return p;
}
-/* Compare device paths. */
-static int
-compare_device_paths (const grub_efi_device_path_t *dp1,
- const grub_efi_device_path_t *dp2)
-{
- if (! dp1 || ! dp2)
- /* Return non-zero. */
- return 1;
-
- while (1)
- {
- grub_efi_uint8_t type1, type2;
- grub_efi_uint8_t subtype1, subtype2;
- grub_efi_uint16_t len1, len2;
- int ret;
-
- type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
- type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
-
- if (type1 != type2)
- return (int) type2 - (int) type1;
-
- subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
- subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
-
- if (subtype1 != subtype2)
- return (int) subtype1 - (int) subtype2;
-
- len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
- len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
-
- if (len1 != len2)
- return (int) len1 - (int) len2;
-
- ret = grub_memcmp (dp1, dp2, len1);
- if (ret != 0)
- return ret;
-
- if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
- break;
-
- dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
- dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
- }
-
- return 0;
-}
-
static struct grub_efidisk_data *
make_devices (void)
{
if (parent == d)
continue;
- if (compare_device_paths (parent->device_path, dp) == 0)
+ if (grub_efi_compare_device_paths (parent->device_path, dp) == 0)
{
/* Found. */
if (! parent->last_device_path)
ldp->length[0] = sizeof (*ldp);
ldp->length[1] = 0;
- if (compare_device_paths (dp, d->device_path) == 0)
+ if (grub_efi_compare_device_paths (dp, d->device_path) == 0)
if (hook (p))
{
grub_free (dp);
{
int ret;
- ret = compare_device_paths (find_last_device_path ((*p)->device_path),
- find_last_device_path (d->device_path));
+ ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path),
+ find_last_device_path (d->device_path));
if (ret == 0)
- ret = compare_device_paths ((*p)->device_path,
- d->device_path);
+ ret = grub_efi_compare_device_paths ((*p)->device_path,
+ d->device_path);
if (ret == 0)
return;
else if (ret > 0)
char *
grub_efidisk_get_device_name (grub_efi_handle_t *handle)
{
- grub_efi_device_path_t *dp, *ldp;
+ grub_efi_device_path_t *dp, *ldp, *sdp;
+ /* This is a hard disk partition. */
+ grub_disk_t parent = 0;
+ auto int find_parent_disk (const char *name);
+
+ /* Find the disk which is the parent of a given hard disk partition. */
+ int find_parent_disk (const char *name)
+ {
+ grub_disk_t disk;
+
+ disk = grub_disk_open (name);
+ if (! disk)
+ return 1;
+
+ if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
+ {
+ struct grub_efidisk_data *d;
+
+ d = disk->data;
+ if (grub_efi_compare_device_paths (d->device_path, sdp) == 0)
+ {
+ parent = disk;
+ return 1;
+ }
+ }
+
+ grub_disk_close (disk);
+ return 0;
+ }
dp = grub_efi_get_device_path (handle);
if (! dp)
&& (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
== GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
{
- /* This is a hard disk partition. */
- grub_disk_t parent = 0;
grub_partition_t tpart = NULL;
char *device_name;
grub_efi_device_path_t *dup_dp, *dup_ldp;
grub_efi_hard_drive_device_path_t hd;
- auto int find_parent_disk (const char *name);
auto int find_partition (grub_disk_t disk, const grub_partition_t part);
- /* Find the disk which is the parent of a given hard disk partition. */
- int find_parent_disk (const char *name)
- {
- grub_disk_t disk;
-
- disk = grub_disk_open (name);
- if (! disk)
- return 1;
-
- if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
- {
- struct grub_efidisk_data *d;
-
- d = disk->data;
- if (compare_device_paths (d->device_path, dup_dp) == 0)
- {
- parent = disk;
- return 1;
- }
- }
-
- grub_disk_close (disk);
- return 0;
- }
-
/* Find the identical partition. */
int find_partition (grub_disk_t disk __attribute__ ((unused)),
const grub_partition_t part)
dup_ldp->length[0] = sizeof (*dup_ldp);
dup_ldp->length[1] = 0;
+ sdp = dup_dp;
+
grub_efidisk_iterate (find_parent_disk);
grub_free (dup_dp);
else
{
/* This should be an entire disk. */
- auto int find_disk (const char *name);
char *device_name = 0;
- int find_disk (const char *name)
- {
- grub_disk_t disk;
-
- disk = grub_disk_open (name);
- if (! disk)
- return 1;
-
- if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
- {
- struct grub_efidisk_data *d;
-
- d = disk->data;
- if (compare_device_paths (d->device_path, dp) == 0)
- {
- device_name = grub_strdup (disk->name);
- grub_disk_close (disk);
- return 1;
- }
- }
-
- grub_disk_close (disk);
- return 0;
+ sdp = dp;
- }
-
- grub_efidisk_iterate (find_disk);
+ grub_efidisk_iterate (find_parent_disk);
+ if (!parent)
+ return NULL;
+ device_name = grub_strdup (parent->name);
+ grub_disk_close (parent);
return device_name;
}
dp = (grub_efi_device_path_t *) ((char *) dp + len);
}
}
+
+/* Compare device paths. */
+int
+grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
+ const grub_efi_device_path_t *dp2)
+{
+ if (! dp1 || ! dp2)
+ /* Return non-zero. */
+ return 1;
+
+ while (1)
+ {
+ grub_efi_uint8_t type1, type2;
+ grub_efi_uint8_t subtype1, subtype2;
+ grub_efi_uint16_t len1, len2;
+ int ret;
+
+ type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
+ type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
+
+ if (type1 != type2)
+ return (int) type2 - (int) type1;
+
+ subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
+ subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
+
+ if (subtype1 != subtype2)
+ return (int) subtype1 - (int) subtype2;
+
+ len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
+ len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
+
+ if (len1 != len2)
+ return (int) len1 - (int) len2;
+
+ ret = grub_memcmp (dp1, dp2, len1);
+ if (ret != 0)
+ return ret;
+
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
+ break;
+
+ dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
+ dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
+ }
+
+ return 0;
+}
grub_efidisk_init ();
}
+void (*grub_efi_net_config) (grub_efi_handle_t hnd,
+ char **device,
+ char **path);
+
void
grub_machine_get_bootlocation (char **device, char **path)
{
return;
*device = grub_efidisk_get_device_name (image->device_handle);
*path = grub_efi_get_filename (image->file_path);
+ if (!*device && grub_efi_net_config)
+ grub_efi_net_config (image->device_handle, device, path);
/* Get the directory. */
p = grub_strrchr (*path, '/');
/* GUID. */
static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
-
+static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
static grub_err_t
send_card_buffer (const struct grub_net_card *dev,
struct grub_net_buff *pack)
{
grub_efi_status_t st;
- grub_efi_simple_network_t *net = dev->data;
+ grub_efi_simple_network_t *net = dev->efi_net;
st = efi_call_7 (net->transmit, net, 0, pack->tail - pack->data,
pack->data, NULL, NULL, NULL);
if (st != GRUB_EFI_SUCCESS)
get_card_packet (const struct grub_net_card *dev,
struct grub_net_buff *nb)
{
- grub_efi_simple_network_t *net = dev->data;
+ grub_efi_simple_network_t *net = dev->efi_net;
grub_err_t err;
grub_efi_status_t st;
grub_efi_uintn_t bufsize = 1500;
grub_memcpy (card->default_address.mac,
net->mode->current_address,
sizeof (card->default_address.mac));
- card->data = net;
+ card->efi_net = net;
+ card->efi_handle = *handle;
grub_net_card_register (card);
}
grub_free (handles);
}
+static void
+grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ char **path)
+{
+ struct grub_net_card *card;
+ grub_efi_device_path_t *dp;
+
+ dp = grub_efi_get_device_path (hnd);
+ if (! dp)
+ return;
+
+ FOR_NET_CARDS (card)
+ {
+ grub_efi_device_path_t *cdp;
+ struct grub_efi_pxe *pxe;
+ struct grub_efi_pxe_mode *pxe_mode;
+ if (card->driver != &efidriver)
+ continue;
+ cdp = grub_efi_get_device_path (card->efi_handle);
+ if (! cdp)
+ continue;
+ if (grub_efi_compare_device_paths (dp, cdp) != 0)
+ continue;
+ pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (! pxe)
+ continue;
+ pxe_mode = pxe->mode;
+ grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ (struct grub_net_bootp_packet *)
+ &pxe_mode->dhcp_ack,
+ sizeof (pxe_mode->dhcp_ack),
+ 1, device, path);
+ return;
+ }
+}
+
+
GRUB_MOD_INIT(efinet)
{
grub_efinet_findcards ();
+ grub_efi_net_config = grub_efi_net_config_real;
}
GRUB_MOD_FINI(ofnet)
{
struct grub_net_card *card;
+ grub_efi_net_config = 0;
FOR_NET_CARDS (card)
if (card->driver && !grub_strcmp (card->driver->name, "efinet"))
{
const struct grub_net_card *card,
grub_net_interface_flags_t flags,
const struct grub_net_bootp_packet *bp,
- grub_size_t size)
+ grub_size_t size,
+ int is_def, char **device, char **path)
{
grub_net_network_level_address_t addr;
grub_net_link_level_address_t hwaddr;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = bp->your_ip;
+ if (device)
+ *device = 0;
+ if (path)
+ *path = 0;
+
grub_memcpy (hwaddr.mac, bp->mac_addr,
bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
: sizeof (hwaddr.mac));
if (size > OFFSET_OF (boot_file, bp))
set_env_limn_ro (name, "boot_file", (char *) bp->boot_file,
sizeof (bp->boot_file));
+ if (is_def)
+ default_server = 0;
if (size > OFFSET_OF (server_name, bp)
&& bp->server_name[0])
{
set_env_limn_ro (name, "dhcp_server_name", (char *) bp->server_name,
sizeof (bp->server_name));
- if (!default_server)
+ if (is_def && !default_server)
{
default_server = grub_strdup (bp->server_name);
- grub_errno = GRUB_ERR_NONE;
- }
+ grub_print_error ();
+ }
+ if (device && !*device)
+ {
+ *device = grub_xasprintf ("tftp,%s", bp->server_name);
+ grub_print_error ();
+ }
}
- if (!default_server)
+ if (is_def && !default_server)
{
default_server = grub_xasprintf ("%d.%d.%d.%d",
((grub_uint8_t *) &bp->server_ip)[0],
((grub_uint8_t *) &bp->server_ip)[1],
((grub_uint8_t *) &bp->server_ip)[2],
((grub_uint8_t *) &bp->server_ip)[3]);
- grub_errno = GRUB_ERR_NONE;
- }
+ grub_print_error ();
+ }
+
+ if (device && !*device)
+ {
+ *device = grub_xasprintf ("tftp,%d.%d.%d.%d",
+ ((grub_uint8_t *) &bp->server_ip)[0],
+ ((grub_uint8_t *) &bp->server_ip)[1],
+ ((grub_uint8_t *) &bp->server_ip)[2],
+ ((grub_uint8_t *) &bp->server_ip)[3]);
+ grub_print_error ();
+ }
+ if (size > OFFSET_OF (boot_file, bp) && path)
+ {
+ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
+ grub_print_error ();
+ if (*path)
+ {
+ char *slash;
+ slash = grub_strrchr (*path, '/');
+ if (slash)
+ *slash = 0;
+ else
+ **path = 0;
+ }
+ }
if (size > OFFSET_OF (vendor, bp))
parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp));
}
grub_net_configure_by_dhcp_ack (name, card,
0, (const struct grub_net_bootp_packet *) nb->data,
- (nb->tail - nb->data));
+ (nb->tail - nb->data), 0, 0, 0);
grub_free (name);
if (grub_errno)
grub_print_error ();
{ 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
}
+#define GRUB_EFI_PXE_GUID \
+ { 0x03c4e603, 0xac28, 0x11d3, \
+ { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
#define GRUB_EFI_DEVICE_PATH_GUID \
{ 0x09576e91, 0x6d3f, 0x11d2, \
{ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
};
typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t;
+typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
+
+typedef struct grub_efi_pxe_mode
+{
+ grub_uint8_t unused[52];
+ grub_efi_pxe_packet_t dhcp_discover;
+ grub_efi_pxe_packet_t dhcp_ack;
+ grub_efi_pxe_packet_t proxy_offer;
+ grub_efi_pxe_packet_t pxe_discover;
+ grub_efi_pxe_packet_t pxe_reply;
+} grub_efi_pxe_mode_t;
+
+typedef struct grub_efi_pxe
+{
+ grub_uint64_t rev;
+ void (*start) (void);
+ void (*stop) (void);
+ void (*dhcp) (void);
+ void (*discover) (void);
+ void (*mftp) (void);
+ void (*udpwrite) (void);
+ void (*udpread) (void);
+ void (*setipfilter) (void);
+ void (*arp) (void);
+ void (*setparams) (void);
+ void (*setstationip) (void);
+ void (*setpackets) (void);
+ struct grub_efi_pxe_mode *mode;
+} grub_efi_pxe_t;
+
#define GRUB_EFI_BLACK 0x00
#define GRUB_EFI_BLUE 0x01
#define GRUB_EFI_GREEN 0x02
grub_efi_uint32_t descriptor_version,
grub_efi_memory_descriptor_t *virtual_map);
+int
+EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
+ const grub_efi_device_path_t *dp2);
+
+extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
+ char **device,
+ char **path);
+
void grub_efi_mm_init (void);
void grub_efi_mm_fini (void);
void grub_efi_init (void);
grub_net_card_flags_t flags;
union
{
+ struct
+ {
+ struct grub_efi_simple_network *efi_net;
+ void *efi_handle;
+ };
void *data;
int data_num;
};
const struct grub_net_card *card,
grub_net_interface_flags_t flags,
const struct grub_net_bootp_packet *bp,
- grub_size_t size);
+ grub_size_t size,
+ int is_def, char **device, char **path);
void
grub_net_process_dhcp (struct grub_net_buff *nb,