]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
efinet support
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 26 Jun 2011 20:42:04 +0000 (22:42 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 26 Jun 2011 20:42:04 +0000 (22:42 +0200)
grub-core/Makefile.core.def
grub-core/kern/x86_64/efi/callwrap.S
grub-core/net/drivers/efi/efinet.c [new file with mode: 0644]
include/grub/efi/api.h

index 5c3ce99be54781aa6839b9324489ea7999a1b453..ac969e09cc434e7126fcee33aea9c7baab1c69b8 100644 (file)
@@ -1588,10 +1588,16 @@ module = {
 
 module = {
   name = ofnet;
-  ieee1275 = net/drivers/ieee1275/ofnet.c;
+  common = net/drivers/ieee1275/ofnet.c;
   enable = ieee1275;
 };
 
+module = {
+  name = efinet;
+  common = net/drivers/efi/efinet.c;
+  enable = efi;
+};
+
 module = {
   name = emunet;
   emu = net/drivers/emu/emunet.c;
index aae267872a6c24f703f6327127c6f83d373aa368..cc2c8aa05881a589dc56d4ed54ec6696cc5ca3e5 100644 (file)
@@ -95,6 +95,20 @@ FUNCTION(efi_wrap_6)
        addq $64, %rsp
        ret
 
+FUNCTION(efi_wrap_7)
+       subq $96, %rsp
+       mov 96+16(%rsp), %rax
+       mov %rax, 48(%rsp)
+       mov 96+8(%rsp), %rax
+       mov %rax, 40(%rsp)
+       mov %r9, 32(%rsp)
+       mov %r8, %r9
+       mov %rcx, %r8
+       mov %rsi, %rcx
+       call *%rdi
+       addq $96, %rsp
+       ret
+
 FUNCTION(efi_wrap_10)
        subq $96, %rsp
        mov 96+40(%rsp), %rax
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
new file mode 100644 (file)
index 0000000..a6e0056
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010,2011  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/net/netbuff.h>
+#include <grub/dl.h>
+#include <grub/net.h>
+#include <grub/time.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* GUID.  */
+static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_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;
+  st = efi_call_7 (net->transmit, net, 0, pack->tail - pack->data,
+                  pack->data, NULL, NULL, NULL);
+  if (st != GRUB_EFI_SUCCESS)
+    return grub_error (GRUB_ERR_IO, "Couldn't send network packet.");
+  return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+get_card_packet (const struct grub_net_card *dev,
+                struct grub_net_buff *nb)
+{
+  grub_efi_simple_network_t *net = dev->data;
+  grub_err_t err;
+  grub_efi_status_t st;
+  grub_efi_uintn_t bufsize = 1500;
+
+  err = grub_netbuff_clear (nb);
+  if (err)
+    return -1;
+
+  err = grub_netbuff_put (nb, 1500);
+  if (err)
+    return -1;
+
+  st = efi_call_7 (net->receive, net, NULL, &bufsize,
+                  nb->data, NULL, NULL, NULL);
+  if (st == GRUB_EFI_BUFFER_TOO_SMALL)
+    {
+      err = grub_netbuff_put (nb, bufsize - 1500);
+      if (err)
+       return -1;
+      st = efi_call_7 (net->receive, net, NULL, &bufsize,
+                      nb->data, NULL, NULL, NULL);
+    }
+  if (st != GRUB_EFI_SUCCESS)
+    {
+      grub_netbuff_clear (nb);
+      return -1;
+    }
+  err = grub_netbuff_unput (nb, (nb->tail - nb->data) - bufsize);
+  if (err)
+    return -1;
+
+  return bufsize;
+}
+
+static struct grub_net_card_driver efidriver =
+  {
+    .name = "efinet",
+    .send = send_card_buffer,
+    .recv = get_card_packet
+  };
+
+
+static void
+grub_efinet_findcards (void)
+{
+  grub_efi_uintn_t num_handles;
+  grub_efi_handle_t *handles;
+  grub_efi_handle_t *handle;
+  int i = 0;
+
+  /* Find handles which support the disk io interface.  */
+  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid,
+                                   0, &num_handles);
+  if (! handles)
+    return;
+  for (handle = handles; num_handles--; handle++)
+    {
+      grub_efi_simple_network_t *net;
+      struct grub_net_card *card;
+
+      net = grub_efi_open_protocol (*handle, &net_io_guid,
+                                   GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+      if (! net)
+       /* This should not happen... Why?  */
+       continue;
+
+      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
+         && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
+       continue;
+
+      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
+       continue;
+
+      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
+         && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
+       continue;
+
+      card = grub_zalloc (sizeof (struct grub_net_card));
+      if (!card)
+       {
+         grub_print_error ();
+         grub_free (handles);
+         return;
+       }
+
+      card->name = grub_xasprintf ("efinet%d", i++);
+      card->driver = &efidriver;
+      card->flags = 0;
+      card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+      grub_memcpy (card->default_address.mac,
+                  net->mode->current_address,
+                  sizeof (card->default_address.mac));
+      card->data = net;
+
+      grub_net_card_register (card);
+    }
+  grub_free (handles);
+}
+
+GRUB_MOD_INIT(efinet)
+{
+  grub_efinet_findcards ();
+}
+
+GRUB_MOD_FINI(ofnet)
+{
+  struct grub_net_card *card;
+  FOR_NET_CARDS (card) 
+    if (card->driver && !grub_strcmp (card->driver->name, "efinet"))
+      {
+       card->driver->fini (card);
+       card->driver = NULL;
+      }
+  grub_net_card_driver_unregister (&efidriver);
+}
+
index ded03a1b39fa57be4a73bf8d577837c1dfac4eaa..a3dde0effbcc7d544eae5d0095b52dbf794ba460 100644 (file)
     { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
   }
 
+#define GRUB_EFI_SIMPLE_NETWORK_GUID   \
+  { 0xa19832b9, 0xac25, 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 } \
@@ -1214,6 +1219,74 @@ struct grub_efi_block_io_media
 };
 typedef struct grub_efi_block_io_media grub_efi_block_io_media_t;
 
+typedef grub_uint8_t grub_efi_mac_t[32];
+
+struct grub_efi_simple_network_mode
+{
+  grub_uint32_t state;
+  grub_uint32_t hwaddr_size;
+  grub_uint32_t media_header_size;
+  grub_uint32_t max_packet_size;
+  grub_uint32_t nvram_size;
+  grub_uint32_t nvram_access_size;
+  grub_uint32_t receive_filter_mask;
+  grub_uint32_t receive_filter_setting;
+  grub_uint32_t max_mcast_filter_count;
+  grub_uint32_t mcast_filter_count;
+  grub_efi_mac_t mcast_filter[16];
+  grub_efi_mac_t current_address;
+  grub_efi_mac_t broadcast_address;
+  grub_efi_mac_t permanent_address;
+  grub_uint8_t if_type;
+  grub_uint8_t mac_changeable;
+  grub_uint8_t multitx_supported;
+  grub_uint8_t media_present_supported;
+  grub_uint8_t media_present;
+};
+
+enum
+  {
+    GRUB_EFI_NETWORK_STOPPED,
+    GRUB_EFI_NETWORK_STARTED,
+    GRUB_EFI_NETWORK_INITIALIZED,
+  };
+
+struct grub_efi_simple_network
+{
+  grub_uint64_t revision;
+  grub_efi_status_t (*start) (struct grub_efi_simple_network *this);
+  void (*stop) (void);
+  grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this,
+                                  grub_efi_uintn_t extra_rx,
+                                  grub_efi_uintn_t extra_tx);
+  void (*reset) (void);
+  void (*shutdown) (void);
+  void (*receive_filters) (void);
+  void (*station_address) (void);
+  void (*statistics) (void);
+  void (*mcastiptomac) (void);
+  void (*nvdata) (void);
+  void (*getstatus) (void);
+  grub_efi_status_t (*transmit) (struct grub_efi_simple_network *this,
+                                grub_efi_uintn_t header_size,
+                                grub_efi_uintn_t buffer_size,
+                                void *buffer,
+                                grub_efi_mac_t *src_addr,
+                                grub_efi_mac_t *dest_addr,
+                                grub_efi_uint16_t *protocol);
+  grub_efi_status_t (*receive) (struct grub_efi_simple_network *this,
+                               grub_efi_uintn_t *header_size,
+                               grub_efi_uintn_t *buffer_size,
+                               void *buffer,
+                               grub_efi_mac_t *src_addr,
+                               grub_efi_mac_t *dest_addr,
+                               grub_uint16_t *protocol);
+  void (*waitforpacket) (void);
+  struct grub_efi_simple_network_mode *mode;
+};
+typedef struct grub_efi_simple_network grub_efi_simple_network_t;
+
+
 struct grub_efi_block_io
 {
   grub_efi_uint64_t revision;
@@ -1243,6 +1316,7 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
 #define efi_call_4(func, a, b, c, d)   func(a, b, c, d)
 #define efi_call_5(func, a, b, c, d, e)        func(a, b, c, d, e)
 #define efi_call_6(func, a, b, c, d, e, f) func(a, b, c, d, e, f)
+#define efi_call_7(func, a, b, c, d, e, f, g) func(a, b, c, d, e, f, g)
 #define efi_call_10(func, a, b, c, d, e, f, g, h, i, j)        func(a, b, c, d, e, f, g, h, i, j)
 
 #else
@@ -1264,6 +1338,9 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
 #define efi_call_6(func, a, b, c, d, e, f) \
   efi_wrap_6(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
   (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f)
+#define efi_call_7(func, a, b, c, d, e, f, g) \
+  efi_wrap_7(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
+  (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f, (grub_uint64_t) g)
 #define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) \
   efi_wrap_10(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
   (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f, (grub_uint64_t) g, \
@@ -1285,6 +1362,10 @@ grub_uint64_t EXPORT_FUNC(efi_wrap_6) (void *func, grub_uint64_t arg1,
                                        grub_uint64_t arg2, grub_uint64_t arg3,
                                        grub_uint64_t arg4, grub_uint64_t arg5,
                                        grub_uint64_t arg6);
+grub_uint64_t EXPORT_FUNC(efi_wrap_7) (void *func, grub_uint64_t arg1,
+                                       grub_uint64_t arg2, grub_uint64_t arg3,
+                                       grub_uint64_t arg4, grub_uint64_t arg5,
+                                       grub_uint64_t arg6, grub_uint64_t arg7);
 grub_uint64_t EXPORT_FUNC(efi_wrap_10) (void *func, grub_uint64_t arg1,
                                         grub_uint64_t arg2, grub_uint64_t arg3,
                                         grub_uint64_t arg4, grub_uint64_t arg5,