Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / net / drivers / efi / efinet.c
blob28f2db27f75c353ba1c4c6230e645e6e8a648a95
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010,2011 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/net/netbuff.h>
20 #include <grub/dl.h>
21 #include <grub/net.h>
22 #include <grub/time.h>
23 #include <grub/efi/api.h>
24 #include <grub/efi/efi.h>
25 #include <grub/i18n.h>
27 GRUB_MOD_LICENSE ("GPLv3+");
29 /* GUID. */
30 static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
31 static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
33 static grub_err_t
34 send_card_buffer (struct grub_net_card *dev,
35 struct grub_net_buff *pack)
37 grub_efi_status_t st;
38 grub_efi_simple_network_t *net = dev->efi_net;
39 grub_uint64_t limit_time = grub_get_time_ms () + 4000;
40 grub_size_t len;
42 if (dev->txbusy)
43 while (1)
45 void *txbuf = NULL;
46 st = efi_call_3 (net->get_status, net, 0, &txbuf);
47 if (st != GRUB_EFI_SUCCESS)
48 return grub_error (GRUB_ERR_IO,
49 N_("couldn't send network packet"));
50 if (txbuf == dev->txbuf)
52 dev->txbusy = 0;
53 break;
55 if (limit_time < grub_get_time_ms ())
56 return grub_error (GRUB_ERR_TIMEOUT, N_("couldn't send network packet"));
59 len = (pack->tail - pack->data);
60 if (len > dev->mtu)
61 len = dev->mtu;
63 grub_memcpy (dev->txbuf, pack->data, len);
65 st = efi_call_7 (net->transmit, net, 0, len,
66 dev->txbuf, NULL, NULL, NULL);
67 if (st != GRUB_EFI_SUCCESS)
68 return grub_error (GRUB_ERR_IO, N_("couldn't send network packet"));
69 dev->txbusy = 1;
70 return GRUB_ERR_NONE;
73 static struct grub_net_buff *
74 get_card_packet (struct grub_net_card *dev)
76 grub_efi_simple_network_t *net = dev->efi_net;
77 grub_err_t err;
78 grub_efi_status_t st;
79 grub_efi_uintn_t bufsize = dev->rcvbufsize;
80 struct grub_net_buff *nb;
81 int i;
83 for (i = 0; i < 2; i++)
85 if (!dev->rcvbuf)
86 dev->rcvbuf = grub_malloc (dev->rcvbufsize);
87 if (!dev->rcvbuf)
88 return NULL;
90 st = efi_call_7 (net->receive, net, NULL, &bufsize,
91 dev->rcvbuf, NULL, NULL, NULL);
92 if (st != GRUB_EFI_BUFFER_TOO_SMALL)
93 break;
94 dev->rcvbufsize = 2 * ALIGN_UP (dev->rcvbufsize > bufsize
95 ? dev->rcvbufsize : bufsize, 64);
96 grub_free (dev->rcvbuf);
97 dev->rcvbuf = 0;
100 if (st != GRUB_EFI_SUCCESS)
101 return NULL;
103 nb = grub_netbuff_alloc (bufsize + 2);
104 if (!nb)
105 return NULL;
107 /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
108 by 4. So that IP header is aligned on 4 bytes. */
109 if (grub_netbuff_reserve (nb, 2))
111 grub_netbuff_free (nb);
112 return NULL;
114 grub_memcpy (nb->data, dev->rcvbuf, bufsize);
115 err = grub_netbuff_put (nb, bufsize);
116 if (err)
118 grub_netbuff_free (nb);
119 return NULL;
122 return nb;
125 static struct grub_net_card_driver efidriver =
127 .name = "efinet",
128 .send = send_card_buffer,
129 .recv = get_card_packet
132 grub_efi_handle_t
133 grub_efinet_get_device_handle (struct grub_net_card *card)
135 if (!card || card->driver != &efidriver)
136 return 0;
137 return card->efi_handle;
140 static void
141 grub_efinet_findcards (void)
143 grub_efi_uintn_t num_handles;
144 grub_efi_handle_t *handles;
145 grub_efi_handle_t *handle;
146 int i = 0;
148 /* Find handles which support the disk io interface. */
149 handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid,
150 0, &num_handles);
151 if (! handles)
152 return;
153 for (handle = handles; num_handles--; handle++)
155 grub_efi_simple_network_t *net;
156 struct grub_net_card *card;
158 net = grub_efi_open_protocol (*handle, &net_io_guid,
159 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
160 if (! net)
161 /* This should not happen... Why? */
162 continue;
164 if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
165 && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
166 continue;
168 if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
169 continue;
171 if (net->mode->state == GRUB_EFI_NETWORK_STARTED
172 && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
173 continue;
175 card = grub_zalloc (sizeof (struct grub_net_card));
176 if (!card)
178 grub_print_error ();
179 grub_free (handles);
180 return;
183 card->mtu = net->mode->max_packet_size;
184 card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
185 card->txbuf = grub_zalloc (card->txbufsize);
186 if (!card->txbuf)
188 grub_print_error ();
189 grub_free (handles);
190 grub_free (card);
191 return;
193 card->txbusy = 0;
195 card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256;
197 card->name = grub_xasprintf ("efinet%d", i++);
198 card->driver = &efidriver;
199 card->flags = 0;
200 card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
201 grub_memcpy (card->default_address.mac,
202 net->mode->current_address,
203 sizeof (card->default_address.mac));
204 card->efi_net = net;
205 card->efi_handle = *handle;
207 grub_net_card_register (card);
209 grub_free (handles);
212 static void
213 grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
214 char **path)
216 struct grub_net_card *card;
217 grub_efi_device_path_t *dp;
219 dp = grub_efi_get_device_path (hnd);
220 if (! dp)
221 return;
223 FOR_NET_CARDS (card)
225 grub_efi_device_path_t *cdp;
226 struct grub_efi_pxe *pxe;
227 struct grub_efi_pxe_mode *pxe_mode;
228 if (card->driver != &efidriver)
229 continue;
230 cdp = grub_efi_get_device_path (card->efi_handle);
231 if (! cdp)
232 continue;
233 if (grub_efi_compare_device_paths (dp, cdp) != 0)
234 continue;
235 pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
236 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
237 if (! pxe)
238 continue;
239 pxe_mode = pxe->mode;
240 grub_net_configure_by_dhcp_ack (card->name, card, 0,
241 (struct grub_net_bootp_packet *)
242 &pxe_mode->dhcp_ack,
243 sizeof (pxe_mode->dhcp_ack),
244 1, device, path);
245 return;
249 GRUB_MOD_INIT(efinet)
251 grub_efinet_findcards ();
252 grub_efi_net_config = grub_efi_net_config_real;
255 GRUB_MOD_FINI(efinet)
257 struct grub_net_card *card, *next;
259 FOR_NET_CARDS_SAFE (card, next)
260 if (card->driver == &efidriver)
261 grub_net_card_unregister (card);