mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-26 17:19:22 +00:00
Merge branch 'master' into next
This commit is contained in:
commit
b4fc7bc2fd
314 files changed
+14321
-4389
No files matched your search
@@ -37,28 +37,29 @@ send_card_buffer (struct grub_net_card *dev,
|
||||
grub_efi_status_t st;
|
||||
grub_efi_simple_network_t *net = dev->efi_net;
|
||||
grub_uint64_t limit_time = grub_get_time_ms () + 4000;
|
||||
void *txbuf;
|
||||
|
||||
if (dev->txbusy)
|
||||
while (1)
|
||||
{
|
||||
void *txbuf = NULL;
|
||||
txbuf = NULL;
|
||||
st = efi_call_3 (net->get_status, net, 0, &txbuf);
|
||||
if (st != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_IO,
|
||||
N_("couldn't send network packet"));
|
||||
if (txbuf == dev->txbuf)
|
||||
/*
|
||||
Some buggy firmware could return an arbitrary address instead of the
|
||||
txbuf address we trasmitted, so just check that txbuf is non NULL
|
||||
for success. This is ok because we open the SNP protocol in
|
||||
exclusive mode so we know we're the only ones transmitting on this
|
||||
box and since we only transmit one packet at a time we know our
|
||||
transmit was successfull.
|
||||
*/
|
||||
if (txbuf)
|
||||
{
|
||||
dev->txbusy = 0;
|
||||
break;
|
||||
}
|
||||
if (txbuf)
|
||||
{
|
||||
st = efi_call_7 (net->transmit, net, 0, dev->last_pkt_size,
|
||||
dev->txbuf, NULL, NULL, NULL);
|
||||
if (st != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_IO,
|
||||
N_("couldn't send network packet"));
|
||||
}
|
||||
if (limit_time < grub_get_time_ms ())
|
||||
return grub_error (GRUB_ERR_TIMEOUT,
|
||||
N_("couldn't send network packet"));
|
||||
@@ -74,7 +75,19 @@ send_card_buffer (struct grub_net_card *dev,
|
||||
dev->txbuf, NULL, NULL, NULL);
|
||||
if (st != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_IO, N_("couldn't send network packet"));
|
||||
dev->txbusy = 1;
|
||||
|
||||
/*
|
||||
The card may have sent out the packet immediately - set txbusy
|
||||
to 0 in this case.
|
||||
Cases were observed where checking txbuf at the next call
|
||||
of send_card_buffer() is too late: 0 is returned in txbuf and
|
||||
we run in the GRUB_ERR_TIMEOUT case above.
|
||||
Perhaps a timeout in the FW has discarded the recycle buffer.
|
||||
*/
|
||||
txbuf = NULL;
|
||||
st = efi_call_3 (net->get_status, net, 0, &txbuf);
|
||||
dev->txbusy = !(st == GRUB_EFI_SUCCESS && txbuf);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
@@ -130,9 +143,80 @@ get_card_packet (struct grub_net_card *dev)
|
||||
return nb;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
open_card (struct grub_net_card *dev)
|
||||
{
|
||||
grub_efi_simple_network_t *net;
|
||||
|
||||
/* Try to reopen SNP exlusively to close any active MNP protocol instance
|
||||
that may compete for packet polling
|
||||
*/
|
||||
net = grub_efi_open_protocol (dev->efi_handle, &net_io_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE);
|
||||
if (net)
|
||||
{
|
||||
if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
|
||||
&& efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net start failed",
|
||||
dev->name);
|
||||
|
||||
if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
|
||||
return grub_error (GRUB_ERR_NET_NO_CARD, "%s: card stopped",
|
||||
dev->name);
|
||||
|
||||
if (net->mode->state == GRUB_EFI_NETWORK_STARTED
|
||||
&& efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed",
|
||||
dev->name);
|
||||
|
||||
/* Enable hardware receive filters if driver declares support for it.
|
||||
We need unicast and broadcast and additionaly all nodes and
|
||||
solicited multicast for IPv6. Solicited multicast is per-IPv6
|
||||
address and we currently do not have API to do it so simply
|
||||
try to enable receive of all multicast packets or evertyhing in
|
||||
the worst case (i386 PXE driver always enables promiscuous too).
|
||||
|
||||
This does trust firmware to do what it claims to do.
|
||||
*/
|
||||
if (net->mode->receive_filter_mask)
|
||||
{
|
||||
grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
|
||||
GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
|
||||
GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
|
||||
|
||||
filters &= net->mode->receive_filter_mask;
|
||||
if (!(filters & GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST))
|
||||
filters |= (net->mode->receive_filter_mask &
|
||||
GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS);
|
||||
|
||||
efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL);
|
||||
}
|
||||
|
||||
efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
|
||||
dev->efi_net, &net_io_guid,
|
||||
grub_efi_image_handle, dev->efi_handle);
|
||||
dev->efi_net = net;
|
||||
}
|
||||
|
||||
/* If it failed we just try to run as best as we can */
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
close_card (struct grub_net_card *dev)
|
||||
{
|
||||
efi_call_1 (dev->efi_net->shutdown, dev->efi_net);
|
||||
efi_call_1 (dev->efi_net->stop, dev->efi_net);
|
||||
efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
|
||||
dev->efi_net, &net_io_guid,
|
||||
grub_efi_image_handle, dev->efi_handle);
|
||||
}
|
||||
|
||||
static struct grub_net_card_driver efidriver =
|
||||
{
|
||||
.name = "efinet",
|
||||
.open = open_card,
|
||||
.close = close_card,
|
||||
.send = send_card_buffer,
|
||||
.recv = get_card_packet
|
||||
};
|
||||
@@ -162,6 +246,29 @@ grub_efinet_findcards (void)
|
||||
{
|
||||
grub_efi_simple_network_t *net;
|
||||
struct grub_net_card *card;
|
||||
grub_efi_device_path_t *dp, *parent = NULL, *child = NULL;
|
||||
|
||||
/* EDK2 UEFI PXE driver creates IPv4 and IPv6 messaging devices as
|
||||
children of main MAC messaging device. We only need one device with
|
||||
bound SNP per physical card, otherwise they compete with each other
|
||||
when polling for incoming packets.
|
||||
*/
|
||||
dp = grub_efi_get_device_path (*handle);
|
||||
if (!dp)
|
||||
continue;
|
||||
for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp); dp = GRUB_EFI_NEXT_DEVICE_PATH (dp))
|
||||
{
|
||||
parent = child;
|
||||
child = dp;
|
||||
}
|
||||
if (child
|
||||
&& GRUB_EFI_DEVICE_PATH_TYPE (child) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|
||||
&& (GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
|
||||
|| GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
|
||||
&& parent
|
||||
&& GRUB_EFI_DEVICE_PATH_TYPE (parent) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|
||||
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
|
||||
continue;
|
||||
|
||||
net = grub_efi_open_protocol (*handle, &net_io_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
@@ -239,7 +346,33 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
|
||||
if (! cdp)
|
||||
continue;
|
||||
if (grub_efi_compare_device_paths (dp, cdp) != 0)
|
||||
continue;
|
||||
{
|
||||
grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp;
|
||||
int match;
|
||||
|
||||
/* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6
|
||||
as children of Ethernet card and binds PXE and Load File protocols
|
||||
to it. Loaded Image Device Path protocol will point to these pseudo
|
||||
devices. We skip them when enumerating cards, so here we need to
|
||||
find matching MAC device.
|
||||
*/
|
||||
ldp = grub_efi_find_last_device_path (dp);
|
||||
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|
||||
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
|
||||
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
|
||||
continue;
|
||||
dup_dp = grub_efi_duplicate_device_path (dp);
|
||||
if (!dup_dp)
|
||||
continue;
|
||||
dup_ldp = grub_efi_find_last_device_path (dup_dp);
|
||||
dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
|
||||
dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
|
||||
dup_ldp->length = sizeof (*dup_ldp);
|
||||
match = grub_efi_compare_device_paths (dup_dp, cdp) == 0;
|
||||
grub_free (dup_dp);
|
||||
if (!match)
|
||||
continue;
|
||||
}
|
||||
pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (! pxe)
|
||||
|
||||
@@ -98,7 +98,7 @@ static int registered = 0;
|
||||
|
||||
GRUB_MOD_INIT(emunet)
|
||||
{
|
||||
if (grub_emunet_create (&emucard.mtu))
|
||||
if (!grub_emunet_create (&emucard.mtu))
|
||||
{
|
||||
grub_net_card_register (&emucard);
|
||||
registered = 1;
|
||||
|
||||
@@ -150,7 +150,7 @@ grub_ieee1275_parse_bootargs (const char *devpath, char *bootpath,
|
||||
grub_net_network_level_address_t client_addr, gateway_addr, subnet_mask;
|
||||
grub_net_link_level_address_t hw_addr;
|
||||
grub_net_interface_flags_t flags = 0;
|
||||
struct grub_net_network_level_interface *inter;
|
||||
struct grub_net_network_level_interface *inter = NULL;
|
||||
grub_uint16_t vlantag = 0;
|
||||
|
||||
hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
@@ -228,7 +228,7 @@ grub_ieee1275_parse_bootargs (const char *devpath, char *bootpath,
|
||||
target.ipv4.masksize = 0;
|
||||
rname = grub_xasprintf ("%s:default", ((*card)->name));
|
||||
if (rname)
|
||||
grub_net_add_route_gw (rname, target, gateway_addr);
|
||||
grub_net_add_route_gw (rname, target, gateway_addr, inter);
|
||||
else
|
||||
return grub_errno;
|
||||
}
|
||||
@@ -312,6 +312,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
|
||||
grub_uint64_t prop;
|
||||
grub_uint8_t *pprop;
|
||||
char *shortname;
|
||||
char need_suffix = 1;
|
||||
|
||||
if (grub_strcmp (alias->type, "network") != 0)
|
||||
return 0;
|
||||
@@ -332,7 +333,43 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
|
||||
|
||||
#define SUFFIX ":speed=auto,duplex=auto,1.1.1.1,dummy,1.1.1.1,1.1.1.1,5,5,1.1.1.1,512"
|
||||
|
||||
if (!grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_OFNET_SUFFIX))
|
||||
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_OFNET_SUFFIX))
|
||||
need_suffix = 0;
|
||||
|
||||
/* sun4v vnet devices do not support setting duplex/speed */
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
grub_ieee1275_finddevice (alias->path, &devhandle);
|
||||
|
||||
grub_ieee1275_get_property_length (devhandle, "compatible", &prop_size);
|
||||
if (prop_size > 0)
|
||||
{
|
||||
pprop = grub_malloc (prop_size);
|
||||
if (!pprop)
|
||||
{
|
||||
grub_free (card);
|
||||
grub_free (ofdata);
|
||||
grub_print_error ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!grub_ieee1275_get_property (devhandle, "compatible",
|
||||
pprop, prop_size, NULL))
|
||||
{
|
||||
for (ptr = (char *) pprop; ptr - (char *) pprop < prop_size;
|
||||
ptr += grub_strlen (ptr) + 1)
|
||||
{
|
||||
if (!grub_strcmp(ptr, "SUNW,sun4v-network"))
|
||||
need_suffix = 0;
|
||||
}
|
||||
}
|
||||
|
||||
grub_free (pprop);
|
||||
}
|
||||
}
|
||||
|
||||
if (need_suffix)
|
||||
ofdata->path = grub_malloc (grub_strlen (alias->path) + sizeof (SUFFIX));
|
||||
else
|
||||
ofdata->path = grub_malloc (grub_strlen (alias->path) + 1);
|
||||
@@ -342,7 +379,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
|
||||
return 0;
|
||||
}
|
||||
ofdata->suffix = grub_stpcpy (ofdata->path, alias->path);
|
||||
if (!grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_OFNET_SUFFIX))
|
||||
if (need_suffix)
|
||||
grub_memcpy (ofdata->suffix, SUFFIX, sizeof (SUFFIX));
|
||||
else
|
||||
*ofdata->suffix = '\0';
|
||||
|
||||
Reference in new issue
Block a user