* Cherry-picks to better handle TFTP timeouts on some arches: (LP: #1521612)
- (7b386b7) efidisk: move device path helpers in core for efinet
- (c52ae40) efinet: skip virtual IP devices when enumerating cards
- (f348aee) efinet: enable hardware filters when opening interface
Mathieu Trudel-Lapierre
8 years ago
0 | 0 | # see git-dpm(1) from git-dpm package |
1 | 99d5df36311e15d60a16f6cba6e3b4ca442b0472 | |
2 | 99d5df36311e15d60a16f6cba6e3b4ca442b0472 | |
1 | 1a8eacd20fdfc9e9d3adf15af0a24a5c025fa071 | |
2 | 1a8eacd20fdfc9e9d3adf15af0a24a5c025fa071 | |
3 | 3 | e8f07821cce1bd0ab6d5622c2a42440f15f4fd71 |
4 | 4 | e8f07821cce1bd0ab6d5622c2a42440f15f4fd71 |
5 | 5 | grub2_2.02~beta2.orig.tar.xz |
0 | grub2 (2.02~beta2-33) UNRELEASED; urgency=medium | |
1 | ||
2 | * Cherry-picks to better handle TFTP timeouts on some arches: (LP: #1521612) | |
3 | - (7b386b7) efidisk: move device path helpers in core for efinet | |
4 | - (c52ae40) efinet: skip virtual IP devices when enumerating cards | |
5 | - (f348aee) efinet: enable hardware filters when opening interface | |
6 | ||
7 | -- Mathieu Trudel-Lapierre <mathieu-tl@ubuntu.com> Thu, 03 Dec 2015 11:01:36 -0500 | |
8 | ||
0 | 9 | grub2 (2.02~beta2-32) unstable; urgency=medium |
1 | 10 | |
2 | 11 | [ Mathieu Trudel-Lapierre ] |
0 | From c603d4c4d477f2592de30410685016e55d3b78c5 Mon Sep 17 00:00:00 2001 | |
1 | From: Andrei Borzenkov <arvidjaar@gmail.com> | |
2 | Date: Thu, 7 May 2015 20:37:16 +0300 | |
3 | Subject: efidisk: move device path helpers in core for efinet | |
4 | ||
5 | Patch-Name: efidisk-device-path-helpers-for-efinet.patch | |
6 | Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1521612 | |
7 | Last-Update: 2015-12-03 | |
8 | --- | |
9 | grub-core/disk/efi/efidisk.c | 61 ++++++++------------------------------------ | |
10 | grub-core/kern/efi/efi.c | 41 +++++++++++++++++++++++++++++ | |
11 | include/grub/efi/efi.h | 4 +++ | |
12 | 3 files changed, 55 insertions(+), 51 deletions(-) | |
13 | ||
14 | diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c | |
15 | index 3b12c34..845c66f 100644 | |
16 | --- a/grub-core/disk/efi/efidisk.c | |
17 | +++ b/grub-core/disk/efi/efidisk.c | |
18 | @@ -43,47 +43,6 @@ static struct grub_efidisk_data *fd_devices; | |
19 | static struct grub_efidisk_data *hd_devices; | |
20 | static struct grub_efidisk_data *cd_devices; | |
21 | ||
22 | -/* Duplicate a device path. */ | |
23 | -static grub_efi_device_path_t * | |
24 | -duplicate_device_path (const grub_efi_device_path_t *dp) | |
25 | -{ | |
26 | - grub_efi_device_path_t *p; | |
27 | - grub_size_t total_size = 0; | |
28 | - | |
29 | - for (p = (grub_efi_device_path_t *) dp; | |
30 | - ; | |
31 | - p = GRUB_EFI_NEXT_DEVICE_PATH (p)) | |
32 | - { | |
33 | - total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); | |
34 | - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) | |
35 | - break; | |
36 | - } | |
37 | - | |
38 | - p = grub_malloc (total_size); | |
39 | - if (! p) | |
40 | - return 0; | |
41 | - | |
42 | - grub_memcpy (p, dp, total_size); | |
43 | - return p; | |
44 | -} | |
45 | - | |
46 | -/* Return the device path node right before the end node. */ | |
47 | -static grub_efi_device_path_t * | |
48 | -find_last_device_path (const grub_efi_device_path_t *dp) | |
49 | -{ | |
50 | - grub_efi_device_path_t *next, *p; | |
51 | - | |
52 | - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) | |
53 | - return 0; | |
54 | - | |
55 | - for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); | |
56 | - ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); | |
57 | - p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) | |
58 | - ; | |
59 | - | |
60 | - return p; | |
61 | -} | |
62 | - | |
63 | static struct grub_efidisk_data * | |
64 | make_devices (void) | |
65 | { | |
66 | @@ -110,7 +69,7 @@ make_devices (void) | |
67 | if (! dp) | |
68 | continue; | |
69 | ||
70 | - ldp = find_last_device_path (dp); | |
71 | + ldp = grub_efi_find_last_device_path (dp); | |
72 | if (! ldp) | |
73 | /* This is empty. Why? */ | |
74 | continue; | |
75 | @@ -150,11 +109,11 @@ find_parent_device (struct grub_efidisk_data *devices, | |
76 | grub_efi_device_path_t *dp, *ldp; | |
77 | struct grub_efidisk_data *parent; | |
78 | ||
79 | - dp = duplicate_device_path (d->device_path); | |
80 | + dp = grub_efi_duplicate_device_path (d->device_path); | |
81 | if (! dp) | |
82 | return 0; | |
83 | ||
84 | - ldp = find_last_device_path (dp); | |
85 | + ldp = grub_efi_find_last_device_path (dp); | |
86 | ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; | |
87 | ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; | |
88 | ldp->length = sizeof (*ldp); | |
89 | @@ -180,11 +139,11 @@ is_child (struct grub_efidisk_data *child, | |
90 | grub_efi_device_path_t *dp, *ldp; | |
91 | int ret; | |
92 | ||
93 | - dp = duplicate_device_path (child->device_path); | |
94 | + dp = grub_efi_duplicate_device_path (child->device_path); | |
95 | if (! dp) | |
96 | return 0; | |
97 | ||
98 | - ldp = find_last_device_path (dp); | |
99 | + ldp = grub_efi_find_last_device_path (dp); | |
100 | ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; | |
101 | ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; | |
102 | ldp->length = sizeof (*ldp); | |
103 | @@ -207,8 +166,8 @@ add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d) | |
104 | { | |
105 | int ret; | |
106 | ||
107 | - ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path), | |
108 | - find_last_device_path (d->device_path)); | |
109 | + ret = grub_efi_compare_device_paths (grub_efi_find_last_device_path ((*p)->device_path), | |
110 | + grub_efi_find_last_device_path (d->device_path)); | |
111 | if (ret == 0) | |
112 | ret = grub_efi_compare_device_paths ((*p)->device_path, | |
113 | d->device_path); | |
114 | @@ -795,7 +754,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) | |
115 | if (! dp) | |
116 | return 0; | |
117 | ||
118 | - ldp = find_last_device_path (dp); | |
119 | + ldp = grub_efi_find_last_device_path (dp); | |
120 | if (! ldp) | |
121 | return 0; | |
122 | ||
123 | @@ -811,14 +770,14 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) | |
124 | ||
125 | /* It is necessary to duplicate the device path so that GRUB | |
126 | can overwrite it. */ | |
127 | - dup_dp = duplicate_device_path (dp); | |
128 | + dup_dp = grub_efi_duplicate_device_path (dp); | |
129 | if (! dup_dp) | |
130 | return 0; | |
131 | ||
132 | while (1) | |
133 | { | |
134 | grub_efi_device_path_t *dup_ldp; | |
135 | - dup_ldp = find_last_device_path (dup_dp); | |
136 | + dup_ldp = grub_efi_find_last_device_path (dup_dp); | |
137 | if (!(GRUB_EFI_DEVICE_PATH_TYPE (dup_ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE | |
138 | && (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE | |
139 | || GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))) | |
140 | diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c | |
141 | index 3b6cf26..12102ef 100644 | |
142 | --- a/grub-core/kern/efi/efi.c | |
143 | +++ b/grub-core/kern/efi/efi.c | |
144 | @@ -422,6 +422,47 @@ grub_efi_get_device_path (grub_efi_handle_t handle) | |
145 | GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); | |
146 | } | |
147 | ||
148 | +/* Return the device path node right before the end node. */ | |
149 | +grub_efi_device_path_t * | |
150 | +grub_efi_find_last_device_path (const grub_efi_device_path_t *dp) | |
151 | +{ | |
152 | + grub_efi_device_path_t *next, *p; | |
153 | + | |
154 | + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) | |
155 | + return 0; | |
156 | + | |
157 | + for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); | |
158 | + ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); | |
159 | + p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) | |
160 | + ; | |
161 | + | |
162 | + return p; | |
163 | +} | |
164 | + | |
165 | +/* Duplicate a device path. */ | |
166 | +grub_efi_device_path_t * | |
167 | +grub_efi_duplicate_device_path (const grub_efi_device_path_t *dp) | |
168 | +{ | |
169 | + grub_efi_device_path_t *p; | |
170 | + grub_size_t total_size = 0; | |
171 | + | |
172 | + for (p = (grub_efi_device_path_t *) dp; | |
173 | + ; | |
174 | + p = GRUB_EFI_NEXT_DEVICE_PATH (p)) | |
175 | + { | |
176 | + total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); | |
177 | + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) | |
178 | + break; | |
179 | + } | |
180 | + | |
181 | + p = grub_malloc (total_size); | |
182 | + if (! p) | |
183 | + return 0; | |
184 | + | |
185 | + grub_memcpy (p, dp, total_size); | |
186 | + return p; | |
187 | +} | |
188 | + | |
189 | static void | |
190 | dump_vendor_path (const char *type, grub_efi_vendor_device_path_t *vendor) | |
191 | { | |
192 | diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h | |
193 | index a000c38..2245632 100644 | |
194 | --- a/include/grub/efi/efi.h | |
195 | +++ b/include/grub/efi/efi.h | |
196 | @@ -56,6 +56,10 @@ void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); | |
197 | char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); | |
198 | grub_efi_device_path_t * | |
199 | EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle); | |
200 | +grub_efi_device_path_t * | |
201 | +EXPORT_FUNC(grub_efi_find_last_device_path) (const grub_efi_device_path_t *dp); | |
202 | +grub_efi_device_path_t * | |
203 | +EXPORT_FUNC(grub_efi_duplicate_device_path) (const grub_efi_device_path_t *dp); | |
204 | grub_err_t EXPORT_FUNC (grub_efi_finish_boot_services) (grub_efi_uintn_t *outbuf_size, void *outbuf, | |
205 | grub_efi_uintn_t *map_key, | |
206 | grub_efi_uintn_t *efi_desc_size, |
0 | From 1a8eacd20fdfc9e9d3adf15af0a24a5c025fa071 Mon Sep 17 00:00:00 2001 | |
1 | From: Andrei Borzenkov <arvidjaar@gmail.com> | |
2 | Date: Tue, 16 Jun 2015 19:52:45 +0300 | |
3 | Subject: efinet: enable hardware filters when opening interface | |
4 | ||
5 | Exclusive open on SNP will close all existing protocol instances which | |
6 | may disable all receive filters on interface. Reinstall them after we | |
7 | opened protocol exclusively. | |
8 | ||
9 | Also follow UEFI specification recommendation and stop interfaces when | |
10 | closing them: | |
11 | ||
12 | Unexpected system errors, reboots and hangs can occur if an OS is loaded | |
13 | and the network devices are not Shutdown() and Stopped(). | |
14 | ||
15 | Also by: Mark Salter <msalter@redhat.com> | |
16 | Closes: 45204 | |
17 | ||
18 | Patch-Name: efinet-enable-hardware-filters-on-interface.patch | |
19 | Bug: http://savannah.gnu.org/bugs/?45204 | |
20 | Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1521612 | |
21 | Last-Update: 2015-12-03 | |
22 | --- | |
23 | grub-core/net/drivers/efi/efinet.c | 25 +++++++++++++++++++++++++ | |
24 | include/grub/efi/api.h | 20 +++++++++++++++++--- | |
25 | 2 files changed, 42 insertions(+), 3 deletions(-) | |
26 | ||
27 | diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c | |
28 | index 775abde..9e0c0ad 100644 | |
29 | --- a/grub-core/net/drivers/efi/efinet.c | |
30 | +++ b/grub-core/net/drivers/efi/efinet.c | |
31 | @@ -156,6 +156,29 @@ open_card (struct grub_net_card *dev) | |
32 | return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed", | |
33 | dev->name); | |
34 | ||
35 | + /* Enable hardware receive filters if driver declares support for it. | |
36 | + We need unicast and broadcast and additionaly all nodes and | |
37 | + solicited multicast for IPv6. Solicited multicast is per-IPv6 | |
38 | + address and we currently do not have API to do it so simply | |
39 | + try to enable receive of all multicast packets or evertyhing in | |
40 | + the worst case (i386 PXE driver always enables promiscuous too). | |
41 | + | |
42 | + This does trust firmware to do what it claims to do. | |
43 | + */ | |
44 | + if (net->mode->receive_filter_mask) | |
45 | + { | |
46 | + grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | | |
47 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | | |
48 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; | |
49 | + | |
50 | + filters &= net->mode->receive_filter_mask; | |
51 | + if (!(filters & GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST)) | |
52 | + filters |= (net->mode->receive_filter_mask & | |
53 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS); | |
54 | + | |
55 | + efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL); | |
56 | + } | |
57 | + | |
58 | efi_call_4 (grub_efi_system_table->boot_services->close_protocol, | |
59 | dev->efi_net, &net_io_guid, | |
60 | grub_efi_image_handle, dev->efi_handle); | |
61 | @@ -169,6 +192,8 @@ open_card (struct grub_net_card *dev) | |
62 | static void | |
63 | close_card (struct grub_net_card *dev) | |
64 | { | |
65 | + efi_call_1 (dev->efi_net->shutdown, dev->efi_net); | |
66 | + efi_call_1 (dev->efi_net->stop, dev->efi_net); | |
67 | efi_call_4 (grub_efi_system_table->boot_services->close_protocol, | |
68 | dev->efi_net, &net_io_guid, | |
69 | grub_efi_image_handle, dev->efi_handle); | |
70 | diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h | |
71 | index e5dd543..1a5e38c 100644 | |
72 | --- a/include/grub/efi/api.h | |
73 | +++ b/include/grub/efi/api.h | |
74 | @@ -1501,17 +1501,31 @@ enum | |
75 | GRUB_EFI_NETWORK_INITIALIZED, | |
76 | }; | |
77 | ||
78 | +enum | |
79 | + { | |
80 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST = 0x01, | |
81 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST = 0x02, | |
82 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST = 0x04, | |
83 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS = 0x08, | |
84 | + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST = 0x10, | |
85 | + }; | |
86 | + | |
87 | struct grub_efi_simple_network | |
88 | { | |
89 | grub_uint64_t revision; | |
90 | grub_efi_status_t (*start) (struct grub_efi_simple_network *this); | |
91 | - void (*stop) (void); | |
92 | + grub_efi_status_t (*stop) (struct grub_efi_simple_network *this); | |
93 | grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this, | |
94 | grub_efi_uintn_t extra_rx, | |
95 | grub_efi_uintn_t extra_tx); | |
96 | void (*reset) (void); | |
97 | - void (*shutdown) (void); | |
98 | - void (*receive_filters) (void); | |
99 | + grub_efi_status_t (*shutdown) (struct grub_efi_simple_network *this); | |
100 | + grub_efi_status_t (*receive_filters) (struct grub_efi_simple_network *this, | |
101 | + grub_uint32_t enable, | |
102 | + grub_uint32_t disable, | |
103 | + grub_efi_boolean_t reset_mcast_filter, | |
104 | + grub_efi_uintn_t mcast_filter_count, | |
105 | + grub_efi_mac_address_t *mcast_filter); | |
106 | void (*station_address) (void); | |
107 | void (*statistics) (void); | |
108 | void (*mcastiptomac) (void); |
0 | From a651971c4597cf8071594bf6a299af511b94ce3d Mon Sep 17 00:00:00 2001 | |
1 | From: Andrei Borzenkov <arvidjaar@gmail.com> | |
2 | Date: Thu, 7 May 2015 20:37:17 +0300 | |
3 | Subject: efinet: skip virtual IPv4 and IPv6 devices when enumerating cards | |
4 | ||
5 | EDK2 PXE driver creates two child devices - IPv4 and IPv6 - with | |
6 | bound SNP instance. This means we get three cards for every physical | |
7 | adapter when enumerating. Not only is this confusing, this may result | |
8 | in grub ignoring packets that come in via the "wrong" card. | |
9 | ||
10 | Example of device hierarchy is | |
11 | ||
12 | Ctrl[91] PciRoot(0x0)/Pci(0x3,0x0) | |
13 | Ctrl[95] PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1) | |
14 | Ctrl[B4] PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0) | |
15 | Ctrl[BC] PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv6(0000:0000:0000:0000:0000:0000:0000:0000) | |
16 | ||
17 | Skip PXE created virtual devices when enumerating cards. Make sure to | |
18 | find real card when applying initial autoconfiguration during PXE boot, | |
19 | this information is associated with one of child devices. | |
20 | ||
21 | Patch-Name: efinet-skip-virtual-devices-on-enumeration.patch | |
22 | Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1521612 | |
23 | Last-Update: 2015-12-03 | |
24 | --- | |
25 | grub-core/net/drivers/efi/efinet.c | 51 +++++++++++++++++++++++++++++++++++++- | |
26 | 1 file changed, 50 insertions(+), 1 deletion(-) | |
27 | ||
28 | diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c | |
29 | index 658b3d1..775abde 100644 | |
30 | --- a/grub-core/net/drivers/efi/efinet.c | |
31 | +++ b/grub-core/net/drivers/efi/efinet.c | |
32 | @@ -208,6 +208,29 @@ grub_efinet_findcards (void) | |
33 | { | |
34 | grub_efi_simple_network_t *net; | |
35 | struct grub_net_card *card; | |
36 | + grub_efi_device_path_t *dp, *parent = NULL, *child = NULL; | |
37 | + | |
38 | + /* EDK2 UEFI PXE driver creates IPv4 and IPv6 messaging devices as | |
39 | + children of main MAC messaging device. We only need one device with | |
40 | + bound SNP per physical card, otherwise they compete with each other | |
41 | + when polling for incoming packets. | |
42 | + */ | |
43 | + dp = grub_efi_get_device_path (*handle); | |
44 | + if (!dp) | |
45 | + continue; | |
46 | + for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp); dp = GRUB_EFI_NEXT_DEVICE_PATH (dp)) | |
47 | + { | |
48 | + parent = child; | |
49 | + child = dp; | |
50 | + } | |
51 | + if (child | |
52 | + && GRUB_EFI_DEVICE_PATH_TYPE (child) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE | |
53 | + && (GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE | |
54 | + || GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) | |
55 | + && parent | |
56 | + && GRUB_EFI_DEVICE_PATH_TYPE (parent) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE | |
57 | + && GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) | |
58 | + continue; | |
59 | ||
60 | net = grub_efi_open_protocol (*handle, &net_io_guid, | |
61 | GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); | |
62 | @@ -285,7 +308,33 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, | |
63 | if (! cdp) | |
64 | continue; | |
65 | if (grub_efi_compare_device_paths (dp, cdp) != 0) | |
66 | - continue; | |
67 | + { | |
68 | + grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp; | |
69 | + int match; | |
70 | + | |
71 | + /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6 | |
72 | + as children of Ethernet card and binds PXE and Load File protocols | |
73 | + to it. Loaded Image Device Path protocol will point to these pseudo | |
74 | + devices. We skip them when enumerating cards, so here we need to | |
75 | + find matching MAC device. | |
76 | + */ | |
77 | + ldp = grub_efi_find_last_device_path (dp); | |
78 | + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE | |
79 | + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE | |
80 | + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) | |
81 | + continue; | |
82 | + dup_dp = grub_efi_duplicate_device_path (dp); | |
83 | + if (!dup_dp) | |
84 | + continue; | |
85 | + dup_ldp = grub_efi_find_last_device_path (dup_dp); | |
86 | + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; | |
87 | + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; | |
88 | + dup_ldp->length = sizeof (*dup_ldp); | |
89 | + match = grub_efi_compare_device_paths (dup_dp, cdp) == 0; | |
90 | + grub_free (dup_dp); | |
91 | + if (!match) | |
92 | + continue; | |
93 | + } | |
94 | pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, | |
95 | GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); | |
96 | if (! pxe) |
82 | 82 | xfs-crc-fix-symlink.patch |
83 | 83 | ofdisk_add_sas_disks.patch |
84 | 84 | efinet-open-Simple-Network-Protocol-exclusively.patch |
85 | efidisk-device-path-helpers-for-efinet.patch | |
86 | efinet-skip-virtual-devices-on-enumeration.patch | |
87 | efinet-enable-hardware-filters-on-interface.patch |
42 | 42 | static struct grub_efidisk_data *hd_devices; |
43 | 43 | static struct grub_efidisk_data *cd_devices; |
44 | 44 | |
45 | /* Duplicate a device path. */ | |
46 | static grub_efi_device_path_t * | |
47 | duplicate_device_path (const grub_efi_device_path_t *dp) | |
48 | { | |
49 | grub_efi_device_path_t *p; | |
50 | grub_size_t total_size = 0; | |
51 | ||
52 | for (p = (grub_efi_device_path_t *) dp; | |
53 | ; | |
54 | p = GRUB_EFI_NEXT_DEVICE_PATH (p)) | |
55 | { | |
56 | total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); | |
57 | if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) | |
58 | break; | |
59 | } | |
60 | ||
61 | p = grub_malloc (total_size); | |
62 | if (! p) | |
63 | return 0; | |
64 | ||
65 | grub_memcpy (p, dp, total_size); | |
66 | return p; | |
67 | } | |
68 | ||
69 | /* Return the device path node right before the end node. */ | |
70 | static grub_efi_device_path_t * | |
71 | find_last_device_path (const grub_efi_device_path_t *dp) | |
72 | { | |
73 | grub_efi_device_path_t *next, *p; | |
74 | ||
75 | if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) | |
76 | return 0; | |
77 | ||
78 | for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); | |
79 | ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); | |
80 | p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) | |
81 | ; | |
82 | ||
83 | return p; | |
84 | } | |
85 | ||
86 | 45 | static struct grub_efidisk_data * |
87 | 46 | make_devices (void) |
88 | 47 | { |
109 | 68 | if (! dp) |
110 | 69 | continue; |
111 | 70 | |
112 | ldp = find_last_device_path (dp); | |
71 | ldp = grub_efi_find_last_device_path (dp); | |
113 | 72 | if (! ldp) |
114 | 73 | /* This is empty. Why? */ |
115 | 74 | continue; |
149 | 108 | grub_efi_device_path_t *dp, *ldp; |
150 | 109 | struct grub_efidisk_data *parent; |
151 | 110 | |
152 | dp = duplicate_device_path (d->device_path); | |
111 | dp = grub_efi_duplicate_device_path (d->device_path); | |
153 | 112 | if (! dp) |
154 | 113 | return 0; |
155 | 114 | |
156 | ldp = find_last_device_path (dp); | |
115 | ldp = grub_efi_find_last_device_path (dp); | |
157 | 116 | ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; |
158 | 117 | ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; |
159 | 118 | ldp->length = sizeof (*ldp); |
179 | 138 | grub_efi_device_path_t *dp, *ldp; |
180 | 139 | int ret; |
181 | 140 | |
182 | dp = duplicate_device_path (child->device_path); | |
141 | dp = grub_efi_duplicate_device_path (child->device_path); | |
183 | 142 | if (! dp) |
184 | 143 | return 0; |
185 | 144 | |
186 | ldp = find_last_device_path (dp); | |
145 | ldp = grub_efi_find_last_device_path (dp); | |
187 | 146 | ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; |
188 | 147 | ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; |
189 | 148 | ldp->length = sizeof (*ldp); |
206 | 165 | { |
207 | 166 | int ret; |
208 | 167 | |
209 | ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path), | |
210 | find_last_device_path (d->device_path)); | |
168 | ret = grub_efi_compare_device_paths (grub_efi_find_last_device_path ((*p)->device_path), | |
169 | grub_efi_find_last_device_path (d->device_path)); | |
211 | 170 | if (ret == 0) |
212 | 171 | ret = grub_efi_compare_device_paths ((*p)->device_path, |
213 | 172 | d->device_path); |
794 | 753 | if (! dp) |
795 | 754 | return 0; |
796 | 755 | |
797 | ldp = find_last_device_path (dp); | |
756 | ldp = grub_efi_find_last_device_path (dp); | |
798 | 757 | if (! ldp) |
799 | 758 | return 0; |
800 | 759 | |
810 | 769 | |
811 | 770 | /* It is necessary to duplicate the device path so that GRUB |
812 | 771 | can overwrite it. */ |
813 | dup_dp = duplicate_device_path (dp); | |
772 | dup_dp = grub_efi_duplicate_device_path (dp); | |
814 | 773 | if (! dup_dp) |
815 | 774 | return 0; |
816 | 775 | |
817 | 776 | while (1) |
818 | 777 | { |
819 | 778 | grub_efi_device_path_t *dup_ldp; |
820 | dup_ldp = find_last_device_path (dup_dp); | |
779 | dup_ldp = grub_efi_find_last_device_path (dup_dp); | |
821 | 780 | if (!(GRUB_EFI_DEVICE_PATH_TYPE (dup_ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE |
822 | 781 | && (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE |
823 | 782 | || GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))) |
419 | 419 | { |
420 | 420 | return grub_efi_open_protocol (handle, &device_path_guid, |
421 | 421 | GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
422 | } | |
423 | ||
424 | /* Return the device path node right before the end node. */ | |
425 | grub_efi_device_path_t * | |
426 | grub_efi_find_last_device_path (const grub_efi_device_path_t *dp) | |
427 | { | |
428 | grub_efi_device_path_t *next, *p; | |
429 | ||
430 | if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) | |
431 | return 0; | |
432 | ||
433 | for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); | |
434 | ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); | |
435 | p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) | |
436 | ; | |
437 | ||
438 | return p; | |
439 | } | |
440 | ||
441 | /* Duplicate a device path. */ | |
442 | grub_efi_device_path_t * | |
443 | grub_efi_duplicate_device_path (const grub_efi_device_path_t *dp) | |
444 | { | |
445 | grub_efi_device_path_t *p; | |
446 | grub_size_t total_size = 0; | |
447 | ||
448 | for (p = (grub_efi_device_path_t *) dp; | |
449 | ; | |
450 | p = GRUB_EFI_NEXT_DEVICE_PATH (p)) | |
451 | { | |
452 | total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); | |
453 | if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) | |
454 | break; | |
455 | } | |
456 | ||
457 | p = grub_malloc (total_size); | |
458 | if (! p) | |
459 | return 0; | |
460 | ||
461 | grub_memcpy (p, dp, total_size); | |
462 | return p; | |
422 | 463 | } |
423 | 464 | |
424 | 465 | static void |
155 | 155 | return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed", |
156 | 156 | dev->name); |
157 | 157 | |
158 | /* Enable hardware receive filters if driver declares support for it. | |
159 | We need unicast and broadcast and additionaly all nodes and | |
160 | solicited multicast for IPv6. Solicited multicast is per-IPv6 | |
161 | address and we currently do not have API to do it so simply | |
162 | try to enable receive of all multicast packets or evertyhing in | |
163 | the worst case (i386 PXE driver always enables promiscuous too). | |
164 | ||
165 | This does trust firmware to do what it claims to do. | |
166 | */ | |
167 | if (net->mode->receive_filter_mask) | |
168 | { | |
169 | grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | | |
170 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | | |
171 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; | |
172 | ||
173 | filters &= net->mode->receive_filter_mask; | |
174 | if (!(filters & GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST)) | |
175 | filters |= (net->mode->receive_filter_mask & | |
176 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS); | |
177 | ||
178 | efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL); | |
179 | } | |
180 | ||
158 | 181 | efi_call_4 (grub_efi_system_table->boot_services->close_protocol, |
159 | 182 | dev->efi_net, &net_io_guid, |
160 | 183 | grub_efi_image_handle, dev->efi_handle); |
168 | 191 | static void |
169 | 192 | close_card (struct grub_net_card *dev) |
170 | 193 | { |
194 | efi_call_1 (dev->efi_net->shutdown, dev->efi_net); | |
195 | efi_call_1 (dev->efi_net->stop, dev->efi_net); | |
171 | 196 | efi_call_4 (grub_efi_system_table->boot_services->close_protocol, |
172 | 197 | dev->efi_net, &net_io_guid, |
173 | 198 | grub_efi_image_handle, dev->efi_handle); |
207 | 232 | { |
208 | 233 | grub_efi_simple_network_t *net; |
209 | 234 | struct grub_net_card *card; |
235 | grub_efi_device_path_t *dp, *parent = NULL, *child = NULL; | |
236 | ||
237 | /* EDK2 UEFI PXE driver creates IPv4 and IPv6 messaging devices as | |
238 | children of main MAC messaging device. We only need one device with | |
239 | bound SNP per physical card, otherwise they compete with each other | |
240 | when polling for incoming packets. | |
241 | */ | |
242 | dp = grub_efi_get_device_path (*handle); | |
243 | if (!dp) | |
244 | continue; | |
245 | for (; ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp); dp = GRUB_EFI_NEXT_DEVICE_PATH (dp)) | |
246 | { | |
247 | parent = child; | |
248 | child = dp; | |
249 | } | |
250 | if (child | |
251 | && GRUB_EFI_DEVICE_PATH_TYPE (child) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE | |
252 | && (GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE | |
253 | || GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) | |
254 | && parent | |
255 | && GRUB_EFI_DEVICE_PATH_TYPE (parent) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE | |
256 | && GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) | |
257 | continue; | |
210 | 258 | |
211 | 259 | net = grub_efi_open_protocol (*handle, &net_io_guid, |
212 | 260 | GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
284 | 332 | if (! cdp) |
285 | 333 | continue; |
286 | 334 | if (grub_efi_compare_device_paths (dp, cdp) != 0) |
287 | continue; | |
335 | { | |
336 | grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp; | |
337 | int match; | |
338 | ||
339 | /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6 | |
340 | as children of Ethernet card and binds PXE and Load File protocols | |
341 | to it. Loaded Image Device Path protocol will point to these pseudo | |
342 | devices. We skip them when enumerating cards, so here we need to | |
343 | find matching MAC device. | |
344 | */ | |
345 | ldp = grub_efi_find_last_device_path (dp); | |
346 | if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE | |
347 | || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE | |
348 | && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) | |
349 | continue; | |
350 | dup_dp = grub_efi_duplicate_device_path (dp); | |
351 | if (!dup_dp) | |
352 | continue; | |
353 | dup_ldp = grub_efi_find_last_device_path (dup_dp); | |
354 | dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; | |
355 | dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; | |
356 | dup_ldp->length = sizeof (*dup_ldp); | |
357 | match = grub_efi_compare_device_paths (dup_dp, cdp) == 0; | |
358 | grub_free (dup_dp); | |
359 | if (!match) | |
360 | continue; | |
361 | } | |
288 | 362 | pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, |
289 | 363 | GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
290 | 364 | if (! pxe) |
1500 | 1500 | GRUB_EFI_NETWORK_INITIALIZED, |
1501 | 1501 | }; |
1502 | 1502 | |
1503 | enum | |
1504 | { | |
1505 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST = 0x01, | |
1506 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST = 0x02, | |
1507 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST = 0x04, | |
1508 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS = 0x08, | |
1509 | GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST = 0x10, | |
1510 | }; | |
1511 | ||
1503 | 1512 | struct grub_efi_simple_network |
1504 | 1513 | { |
1505 | 1514 | grub_uint64_t revision; |
1506 | 1515 | grub_efi_status_t (*start) (struct grub_efi_simple_network *this); |
1507 | void (*stop) (void); | |
1516 | grub_efi_status_t (*stop) (struct grub_efi_simple_network *this); | |
1508 | 1517 | grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this, |
1509 | 1518 | grub_efi_uintn_t extra_rx, |
1510 | 1519 | grub_efi_uintn_t extra_tx); |
1511 | 1520 | void (*reset) (void); |
1512 | void (*shutdown) (void); | |
1513 | void (*receive_filters) (void); | |
1521 | grub_efi_status_t (*shutdown) (struct grub_efi_simple_network *this); | |
1522 | grub_efi_status_t (*receive_filters) (struct grub_efi_simple_network *this, | |
1523 | grub_uint32_t enable, | |
1524 | grub_uint32_t disable, | |
1525 | grub_efi_boolean_t reset_mcast_filter, | |
1526 | grub_efi_uintn_t mcast_filter_count, | |
1527 | grub_efi_mac_address_t *mcast_filter); | |
1514 | 1528 | void (*station_address) (void); |
1515 | 1529 | void (*statistics) (void); |
1516 | 1530 | void (*mcastiptomac) (void); |
55 | 55 | char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); |
56 | 56 | grub_efi_device_path_t * |
57 | 57 | EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle); |
58 | grub_efi_device_path_t * | |
59 | EXPORT_FUNC(grub_efi_find_last_device_path) (const grub_efi_device_path_t *dp); | |
60 | grub_efi_device_path_t * | |
61 | EXPORT_FUNC(grub_efi_duplicate_device_path) (const grub_efi_device_path_t *dp); | |
58 | 62 | grub_err_t EXPORT_FUNC (grub_efi_finish_boot_services) (grub_efi_uintn_t *outbuf_size, void *outbuf, |
59 | 63 | grub_efi_uintn_t *map_key, |
60 | 64 | grub_efi_uintn_t *efi_desc_size, |