rpms/grub/devel grub-0.97-efipxe.patch, NONE, 1.1 grub.spec, 1.88, 1.89
Peter Jones
pjones at fedoraproject.org
Fri Apr 3 18:34:42 UTC 2009
Author: pjones
Update of /cvs/extras/rpms/grub/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv27336
Modified Files:
grub.spec
Added Files:
grub-0.97-efipxe.patch
Log Message:
* Fri Apr 03 2009 Peter Jones <pjones at redhat.com> - 0.97-45
- Add very basic PXE support for EFI.
grub-0.97-efipxe.patch:
--- NEW FILE grub-0.97-efipxe.patch ---
>From 379129c619281449e4c441a932080c68b57f0ab8 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones at redhat.com>
Date: Tue, 31 Mar 2009 14:55:00 +0500
Subject: [PATCH] add basic pxe boot support in efi
---
efi/Makefile.am | 2 +-
efi/byteswap.h | 37 +++++
efi/dhcp.h | 133 +++++++++++++++
efi/eficore.c | 12 ++
efi/efimain.c | 41 ++++--
efi/efimisc.c | 14 +-
efi/efitftp.c | 182 +++++++++++++++++++++
efi/grub/efi/efi.h | 6 +
efi/pxe.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++
efi/pxe.h | 237 +++++++++++++++++++++++++++
grub/Makefile.am | 2 +-
grub/efitftp.c | 29 ++++
stage2/Makefile.am | 4 +-
stage2/disk_io.c | 17 ++-
stage2/efistubs.c | 9 +
stage2/efistubs.h | 8 +
stage2/filesys.h | 13 ++-
17 files changed, 1176 insertions(+), 26 deletions(-)
create mode 100644 efi/byteswap.h
create mode 100644 efi/dhcp.h
create mode 100644 efi/efitftp.c
create mode 100644 efi/pxe.c
create mode 100644 efi/pxe.h
create mode 100644 grub/efitftp.c
create mode 100644 stage2/efistubs.c
create mode 100644 stage2/efistubs.h
diff --git a/efi/Makefile.am b/efi/Makefile.am
index 4d97dbe..129c8d0 100644
--- a/efi/Makefile.am
+++ b/efi/Makefile.am
@@ -72,7 +72,7 @@ noinst_LIBRARIES = libgrubefi.a
libgrubefi_a_SOURCES = $(EFI_ARCH)/callwrap.c eficore.c efimm.c efimisc.c \
$(EFI_ARCH)/setjmp.S eficon.c efidisk.c graphics.c efigraph.c efiuga.c \
font_8x16.c efiserial.c $(EFI_ARCH)/loader/linux.c efichainloader.c \
- xpm.c
+ xpm.c pxe.c efitftp.c
libgrubefi_a_CFLAGS = $(RELOC_FLAGS) -nostdinc
endif
diff --git a/efi/byteswap.h b/efi/byteswap.h
new file mode 100644
index 0000000..5a057c4
--- /dev/null
+++ b/efi/byteswap.h
@@ -0,0 +1,37 @@
+#ifndef BYTESWAP_H
+#define BYTESWAP_H 1
+
+#if defined(__i386__)
+#define LITTLE_ENDIAN 1
+#elif defined(__x86_64__)
+#define LITTLE_ENDIAN 1
+#else
+#error endian not defined
+#endif
+
+#define bswap_16(x) \
+ ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
+
+#define bswap_32(x) \
+ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
+ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
+
+static inline grub_efi_uint16_t htons(grub_efi_uint16_t hostshort)
+{
+#ifdef LITTLE_ENDIAN
+ return bswap_16(hostshort);
+#else
+ return hostshort;
+#endif
+}
+
+static inline grub_efi_uint32_t htonl(grub_efi_uint32_t hostshort)
+{
+#ifdef LITTLE_ENDIAN
+ return bswap_32(hostshort);
+#else
+ return hostshort;
+#endif
+}
+
+#endif /* BYTESWAP_H */
diff --git a/efi/dhcp.h b/efi/dhcp.h
new file mode 100644
index 0000000..a82a522
--- /dev/null
+++ b/efi/dhcp.h
@@ -0,0 +1,133 @@
+#ifndef DHCP_H
+#define DHCP_H 1
+
+#include "pxe.h"
+
+#define EFI_DHCP4_PROTOCOL_GUID \
+{ 0x8a219718, 0x4ef5, 0x4761, {0x91,0xc8,0xc0,0xf0,0x4b,0xda,0x9e,0x56} }
+static grub_efi_guid_t DHCP4Protocol = EFI_DHCP4_PROTOCOL_GUID;
+
+#define EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \
+{ 0x9d9a39d8, 0xbd42, 0x4a73, {0xa4,0xd5,0x8e,0xe9,0x4b,0xe1,0x13,0x80} }
+static grub_efi_guid_t DHCP4SbProtocol = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
+
+#define EFI_PXE_DHCP4_PROTOCOL_GUID \
+{ 0x03c4e624, 0xac28, 0x11d3, {0x9a,0x2d,0x00,0x90,0x29,0x3f,0xc1,0x4d} }
+static grub_efi_guid_t PxeDHCP4Protocol = EFI_PXE_DHCP4_PROTOCOL_GUID;
+
+
+typedef EFI_STATUS (*EFI_DHCP4_GET_MODE_DATA)();
+typedef EFI_STATUS (*EFI_DHCP4_CONFIGURE)();
+typedef EFI_STATUS (*EFI_DHCP4_START)();
+typedef EFI_STATUS (*EFI_DHCP4_RENEW_REBIND)();
+typedef EFI_STATUS (*EFI_DHCP4_RELEASE)();
+typedef EFI_STATUS (*EFI_DHCP4_STOP)();
+typedef EFI_STATUS (*EFI_DHCP4_BUILD)();
+typedef EFI_STATUS (*EFI_DHCP4_TRANSMIT_RECIEVE)();
+typedef EFI_STATUS (*EFI_DHCP4_PARSE)();
+
+typedef struct _EFI_DHCP4_PROTOCOL {
+ EFI_DHCP4_GET_MODE_DATA GetModeData;
+ EFI_DHCP4_CONFIGURE Configure;
+ EFI_DHCP4_START Start;
+ EFI_DHCP4_RENEW_REBIND RenewRebind;
+ EFI_DHCP4_RELEASE Release;
+ EFI_DHCP4_STOP Stop;
+ EFI_DHCP4_BUILD Build;
+ EFI_DHCP4_TRANSMIT_RECIEVE TransmitReceive;
+ EFI_DHCP4_PARSE Parse;
+} EFI_DHCP4_PROTOCOL;
+
+typedef enum {
+ Dhcp4Stopped,
+ Dhcp4Init,
+ Dhcp4Selecting,
+ Dhcp4Requesting,
+ Dhcp4Bound,
+ Dhcp4Renewing,
+ Dhcp4Rebinding,
+ Dhcp4InitReboot,
+ Dhcp4Rebooting,
+} EFI_DHCP4_STATE;
+
+typedef enum {
+ Dhcp4SendDiscover = 0x1,
+ Dhcp4RcvdOffer,
+ Dhcp4SelectOffer,
+ Dhcp4SendRequest,
+ Dhcp4RcvdAck,
+ Dhcp4RcvdNak,
+ Dhcp4SendDecline,
+ Dhcp4BoundCompleted,
+ Dhcp4EnterRenewing,
+ Dhcp4EnterRebinding,
+ Dhcp4AddressLost,
+ Dhcp4Fail,
+} EFI_DHCP4_EVENT;
+
+typedef struct {
+ grub_efi_uint8_t OpCode;
+ grub_efi_uint8_t HwType;
+ grub_efi_uint8_t HwAddrLen;
+ grub_efi_uint8_t Hops;
+ grub_efi_uint32_t xid;
+ grub_efi_uint16_t Seconds;
+ grub_efi_uint16_t reserved;
+ EFI_IPv4_ADDRESS ClientAddr;
+ EFI_IPv4_ADDRESS YourAddr;
+ EFI_IPv4_ADDRESS ServerAddr;
+ EFI_IPv4_ADDRESS GatewayAddr;
+ grub_efi_uint8_t ClientHwAddr[16];
+ char ServerName[64];
+ char BootFileName[128];
+} EFI_DHCP4_HEADER;
+
+typedef struct {
+ grub_efi_uint32_t Size;
+ grub_efi_uint32_t Length;
+ struct {
+ EFI_DHCP4_HEADER Header;
+ grub_efi_uint32_t Magik;
+ grub_efi_uint8_t option[];
+ } Dhcp4;
+} EFI_DHCP4_PACKET;
+
+typedef struct {
+ grub_efi_uint8_t OpCode;
+ grub_efi_uint8_t Length;
+ grub_efi_uint8_t Data[1];
+} EFI_DHCP4_PACKET_OPTION;
+
+typedef EFI_STATUS (*EFI_DHCP4_CALLBACK) (
+ EFI_DHCP4_PROTOCOL *This,
+ void *Context,
+ EFI_DHCP4_STATE CurrentState,
+ EFI_DHCP4_EVENT Dhcp4Event,
+ EFI_DHCP4_PACKET *Packet,
+ EFI_DHCP4_PACKET **NewPacket);
+
+typedef struct {
+ grub_efi_uint32_t DiscoverTryCount;
+ grub_efi_uint32_t *DiscoverTimeout;
+ grub_efi_uint32_t RequestTryCount;
+ grub_efi_uint32_t *RequestTimeout;
+ EFI_IPv4_ADDRESS ClientAddress;
+ EFI_DHCP4_CALLBACK Dhcp4Callback;
+ void *CallbackContext;
+ grub_efi_uint32_t OptionCount;
+ EFI_DHCP4_PACKET_OPTION **OptionList;
+} EFI_DHCP4_CONFIG_DATA;
+
+typedef struct {
+ EFI_DHCP4_STATE State;
+ EFI_DHCP4_CONFIG_DATA ConfigData;
+ EFI_IPv4_ADDRESS ClientAddress;
+ EFI_MAC_ADDRESS ClientMacAddress;
+ EFI_IPv4_ADDRESS ServerAddress;
+ EFI_IPv4_ADDRESS RouterAddress;
+ EFI_IPv4_ADDRESS SubnetMask;
+ grub_efi_uint32_t LeaseTime;
+ EFI_DHCP4_PACKET *ReplyPacket;
+} EFI_DHCP4_MODE_DATA;
+
+#endif /* DHCP_H */
diff --git a/efi/eficore.c b/efi/eficore.c
index 394d82d..8052a14 100644
--- a/efi/eficore.c
+++ b/efi/eficore.c
@@ -38,6 +38,18 @@ static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID;
static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
+grub_efi_status_t
+grub_efi_locate_handle_buffer (grub_efi_locate_search_type_t search_type,
+ grub_efi_guid_t *protocol,
+ void *search_key,
+ grub_efi_uintn_t *no_handles,
+ grub_efi_handle_t **buffer)
+{
+ return Call_Service_5(
+ grub_efi_system_table->boot_services->locate_handle_buffer,
+ search_type, protocol, search_key, no_handles, buffer);
+}
+
void *
grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
{
diff --git a/efi/efimain.c b/efi/efimain.c
index ed73ca2..e1a1e66 100644
--- a/efi/efimain.c
+++ b/efi/efimain.c
@@ -24,6 +24,9 @@
#include <grub/misc.h>
#include <shared.h>
+#include <efistubs.h>
+
+#include "pxe.h"
#define GRUB_SCRATCH_MEM_PAGES (GRUB_SCRATCH_MEM_SIZE >> 12)
@@ -34,25 +37,41 @@ void *grub_scratch_mem = NULL;
#define LOW_STACK_PAGES (LOW_STACK_SIZE >> 12)
static void *low_stack, *real_stack;
+extern int grub_test_pxe(grub_efi_loaded_image_t *loaded_image);
+
static void
real_main (void)
{
grub_efi_loaded_image_t *loaded_image;
- char *path_name;
+ char *path_name = NULL;
loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
- grub_get_drive_partition_from_bdev_handle (loaded_image->device_handle,
- &boot_drive,
- &install_partition);
- path_name = grub_efi_file_path_to_path_name (loaded_image->file_path);
- if (path_name)
- {
- grub_set_config_file (path_name);
- grub_free (path_name);
- }
- grub_load_saved_default (loaded_image->device_handle);
+
+ path_name = grub_efi_pxe_get_config_path(loaded_image);
+
+ if (path_name) {
+ network_ready = 1;
+
+ grub_set_config_file (path_name);
+ grub_free (path_name);
+ } else {
+ grub_get_drive_partition_from_bdev_handle (loaded_image->device_handle,
+ &boot_drive,
+ &install_partition);
+ path_name = grub_efi_file_path_to_path_name (loaded_image->file_path);
+
+ if (path_name)
+ {
+ grub_set_config_file (path_name);
+ grub_free (path_name);
+ }
+
+ grub_load_saved_default (loaded_image->device_handle);
+ }
init_bios_info ();
+ while (console_getkey() < 0)
+ grub_efi_stall(1000);
}
grub_efi_status_t
diff --git a/efi/efimisc.c b/efi/efimisc.c
index 4818617..d508ada 100644
--- a/efi/efimisc.c
+++ b/efi/efimisc.c
@@ -489,11 +489,15 @@ grub_set_config_file (char *path_name)
grub_strcpy (saved_default_file, DEFAULT_SAVED_DEFAULT_FILE_NAME);
return;
}
- path_name_len = dir_end + 1 - path_name;
- if (path_name_len + sizeof (DEFAULT_CONFIG_FILE_NAME) > 128)
- return;
- grub_memmove (config_file, path_name, path_name_len);
- grub_strcpy (config_file + path_name_len, DEFAULT_CONFIG_FILE_NAME);
+ if (strlen(dir_end) == 1) {
+ path_name_len = dir_end + 1 - path_name;
+ if (path_name_len + sizeof (DEFAULT_CONFIG_FILE_NAME) > 128)
+ return;
+ grub_memmove (config_file, path_name, path_name_len);
+ grub_strcpy (config_file + path_name_len, DEFAULT_CONFIG_FILE_NAME);
+ } else {
+ grub_memmove (config_file, path_name, path_name_len);
+ }
if (path_name_len + sizeof (DEFAULT_SAVED_DEFAULT_FILE_NAME) > 128)
return;
path_name_len = dir_end + 1 - path_name;
diff --git a/efi/efitftp.c b/efi/efitftp.c
new file mode 100644
index 0000000..9138165
--- /dev/null
+++ b/efi/efitftp.c
@@ -0,0 +1,182 @@
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#include <grub/efi/misc.h>
+#include <grub/misc.h>
+
+#include <shared.h>
+#include <filesys.h>
+#include "pxe.h"
+
+struct tftp_info tftp_info = {
+ .LoadedImage = NULL,
+ .Pxe = NULL,
+ .ServerIp = NULL,
+ .BasePath = NULL
+};
+
+/*
+ * CLIENT MAC ADDR: 00 15 17 4C E6 74
+ * CLIENT IP: 10.16.52.158 MASK: 255.255.255.0 DHCP IP: 10.16.52.16
+ * GATEWAY IP: 10.16.52.254
+ *
+ * TSize.Running LoadFile()
+ *
+ * TFTP.status: 5
+ * got to grub_efi_pxe_get_config_path
+ * SiAddr: 10.16.52.16
+ * BootpHwAddr: 00:15:17:4c:e6:74:00:00:00:00:00:00:00:00:00:00
+ * BootpSrvName:
+ * BootpBootFile: X86PC/UNDI/pxelinux/bootx64.efi
+ */
+
+grub_efi_status_t tftp_get_file_size(
+ char *Filename,
+ grub_efi_uintn_t *Size)
+{
+ EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;
+ char Buffer[8192];
+ grub_efi_boolean_t Overwrite = 0;
+ grub_efi_boolean_t DontUseBuffer = 0;
+ grub_efi_uint64_t BufferSize = 8192;
+ grub_efi_uintn_t BlockSize = 512;
+ grub_efi_status_t rc;
+ char *FullPath = NULL;
+
+ if (tftp_info.BasePath) {
+ int PathSize = 0;
+ PathSize = strlen(tftp_info.BasePath) + 2 + strlen(Filename);
+ FullPath = grub_malloc(PathSize);
+ grub_sprintf(FullPath, "%s/%s", tftp_info.BasePath, Filename);
+ } else {
+ FullPath = grub_malloc(strlen(Filename));
+ strcpy(FullPath, Filename);
+ }
+
+ rc = Call_Service_10(tftp_info.Pxe->Mtftp, tftp_info.Pxe, OpCode,
+ Buffer, Overwrite, &BufferSize, &BlockSize, tftp_info.ServerIp,
+ FullPath, NULL, DontUseBuffer);
+ if (rc == GRUB_EFI_SUCCESS)
+ *Size = BufferSize;
+ grub_free(FullPath);
+ return rc;
+}
+
+static grub_efi_status_t tftp_read_file(
+ char *Filename,
+ char *Buffer,
+ grub_efi_uintn_t BufferSize)
+{
+ EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
+ grub_efi_boolean_t Overwrite = 0;
+ grub_efi_boolean_t DontUseBuffer = 0;
+ grub_efi_uintn_t BlockSize = 512;
+ grub_efi_status_t rc;
+ char *FullPath = NULL;
+
+ if (tftp_info.BasePath) {
+ int PathSize = 0;
+ PathSize = strlen(tftp_info.BasePath) + 2 + strlen(Filename);
+ FullPath = grub_malloc(PathSize);
+ grub_sprintf(FullPath, "%s/%s", tftp_info.BasePath, Filename);
+ } else {
+ FullPath = grub_malloc(strlen(Filename));
+ strcpy(FullPath, Filename);
+ }
+
+ rc = Call_Service_10(tftp_info.Pxe->Mtftp, tftp_info.Pxe, OpCode,
+ Buffer, Overwrite, &BufferSize, &BlockSize, tftp_info.ServerIp,
+ FullPath, NULL, DontUseBuffer);
+ grub_free(FullPath);
+ return rc;
+}
+
+int
+efi_tftp_mount (void)
+{
+ if (current_drive != NETWORK_DRIVE) {
+ grub_printf("current drive is not network drive.\n");
+
+ return 0;
+ }
+ return 1;
+}
+
+int
+efi_tftp_read (char *addr, int size)
+{
+ int rc;
+
+ if (tftp_info.LastPath == NULL) {
+ grub_printf(" = 0 (no path known)\n");
+ return 0;
+ }
+ if (tftp_info.Buffer == NULL) {
+ grub_printf(" = 0 (no file open)\n");
+ return 0;
+ }
+ if (filemax == -1) {
+ grub_printf(" = 0 (file not found)\n");
+ return 0;
+ }
+ if (filepos == 0) {
+ rc = tftp_read_file(tftp_info.LastPath, tftp_info.Buffer,
+ filemax);
+ }
+
+ grub_memmove(addr, tftp_info.Buffer+filepos, size);
+ filepos += size;
+
+ return size;
+}
+
+int
+efi_tftp_dir (char *dirname)
+{
+ int rc;
+ int ch;
+ grub_efi_uintn_t size;
+ int len;
+ char *name;
+
+ ch = nul_terminate(dirname);
+ len = strlen(dirname);
+
+ name = grub_malloc(len + 1);
+ grub_memmove(name, dirname, len);
+ name[len] = '\0';
+ dirname[len] = ch;
+
+#if 0
+ if (print_possibilities)
+ return 1;
+#endif
+
+ filemax = -1;
+
+ rc = tftp_get_file_size(name, &size);
+ if (rc == 0) {
+ tftp_info.LastPath = grub_malloc(strlen(name) + 1);
+ sprintf(tftp_info.LastPath, "%s", name);
+ filemax = size;
+ filepos = 0;
+
+ tftp_info.Buffer = grub_malloc(filemax);
+
+ printf("rc: %d filemax: %d\n", rc, filemax);
+ return 1;
+ }
+ printf("rc: %d filemax: %d\n", rc, filemax);
+
+ return 0;
+}
+
+void
+efi_tftp_close (void)
+{
+ filepos = 0;
+ filemax = -1;
+ grub_free(tftp_info.LastPath);
+ tftp_info.LastPath = NULL;
+ grub_free(tftp_info.Buffer);
+ tftp_info.Buffer = NULL;
+}
diff --git a/efi/grub/efi/efi.h b/efi/grub/efi/efi.h
index 0424fbb..7078af8 100644
--- a/efi/grub/efi/efi.h
+++ b/efi/grub/efi/efi.h
@@ -25,6 +25,12 @@
#include <grub/efi/api.h>
/* Functions. */
+grub_efi_status_t
+grub_efi_locate_handle_buffer (grub_efi_locate_search_type_t search_type,
+ grub_efi_guid_t *protocol,
+ void *search_key,
+ grub_efi_uintn_t *no_handles,
+ grub_efi_handle_t **buffer);
void *grub_efi_locate_protocol (grub_efi_guid_t * protocol,
void *registration);
grub_efi_handle_t *grub_efi_locate_handle (grub_efi_locate_search_type_t
diff --git a/efi/pxe.c b/efi/pxe.c
new file mode 100644
index 0000000..375f47d
--- /dev/null
+++ b/efi/pxe.c
@@ -0,0 +1,456 @@
+
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#include <grub/efi/misc.h>
+#include <grub/misc.h>
+
+#include <shared.h>
+#include <stddef.h>
+
+#include "pxe.h"
+#include "dhcp.h"
+
+/* Search path is:
+ *
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/1902dcf5-7190-d811-bbd6-6ef21c690030
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/01-00-30-6e-f2-1c-69
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A103437
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A10343
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A1034
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A103
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A10
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A1
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/0
+ * X86PC/UNDI/pxelinux/pxelinux.cfg/default
+ *
+ * The paths we get from uefi are like:
+ * .BootBootFile: X86PC/UNDI/pxelinux/bootx64.efi
+ * .BootCiAddr: 0.0.0.0
+ * .BootYiAddr: 10.16.52.158
+ * .BootSiAddr: 10.16.52.16
+ */
+
+typedef struct {
+ char *options;
+ EFI_DHCP4_PACKET_OPTION *current_option;
+} dhcp_option_parser;
+
+static void dhcp_option_parser_reset(dhcp_option_parser *parser,
+ EFI_PXE_BASE_CODE_PACKET *packet)
+{
+ grub_uint64_t addr = (grub_uint64_t)packet;
+
+ addr += offsetof(EFI_PXE_BASE_CODE_DHCPV4_PACKET, DhcpOptions);
+ parser->current_option = (void *)addr;
+ parser->options = (void *)addr;
+}
+
+static int dhcp_option_parser_next(dhcp_option_parser *parser,
+ EFI_DHCP4_PACKET_OPTION **option)
+{
+ if (parser->current_option->OpCode == 255) {
+ *option = NULL;
+ return 0;
+ }
+ parser->current_option = (void *)((grub_uint64_t)parser->current_option + 2 + parser->current_option->Length);
+ *option = parser->current_option;
+ return 1;
+}
+
+#define DHCPMAGIK "\x63\x82\x53\x63"
+
+static int get_dhcp_client_id(EFI_PXE_BASE_CODE_PACKET *packet, uuid_t *uuid)
+{
+ dhcp_option_parser parser;
+ EFI_DHCP4_PACKET_OPTION *option;
+
+ dhcp_option_parser_reset(&parser, packet);
+
+ if (memcmp((char *)&packet->Dhcpv4.DhcpMagik, DHCPMAGIK, 4))
+ return 0;
+
+ while (dhcp_option_parser_next(&parser, &option)) {
+ int i;
+ char data[option->Length];
+
+ if (option->OpCode != 97)
+ continue;
+
+ if (option->Length != 17)
+ continue;
+
+ memcpy(data, option->Data, option->Length);
+ if (data[0] != 0)
+ continue;
+
+ /* 97[17]: 009cfe245ed0c8bd45a79f54ea5fbd3d97
+ * ^^^^^^^^^^^^ uint8_t[]
+ * ^^ uint8_t
+ * ^^ uint8_t
+ * ^^^^ BE uint16_t
+ * ^^^^ BE uint16_t
+ * ^^^^^^^^ BE uint32_t
+ * ^^ "type". 0 means UUID.
+ */
+ memcpy(uuid, data+1, 16);
+ uuid->time_low = htonl(uuid->time_low);
+ uuid->time_mid = htons(uuid->time_mid);
+ uuid->time_hi_ver = htons(uuid->time_hi_ver);
+
+ return 1;
+ }
+ return 0;
+}
+
+#if 0
+static void grub_dump_dhcp_options(EFI_PXE_BASE_CODE_PACKET *packet)
+{
+ dhcp_option_parser parser;
+ EFI_DHCP4_PACKET_OPTION *option;
+ char hex[] = "0123456789abcdef";
+ int i;
+ int j = 0;
+
+ dhcp_option_parser_reset(&parser, packet);
+
+ if (memcmp((char *)&packet->Dhcpv4.DhcpMagik, DHCPMAGIK, 4))
+ return;
+
+ /* 54[4]: a0014301
+ * 51[4]: 00004506
+ * 1[4]: ffffff00
+ * 3[4]: a00143ef
+ * 6[8]: a001ff20a001ff30
+ * 15[48]: 96e6374716c6c6e226f637e2275646861647e236f6d60226f637e2275646861647e236f6d602275646861647e236f6d6
+ * 28[4]: a00143ff
+ * 40[10]: 275646861647e236f6d6
+ * 41[8]: a001ff20a001ff30
+ * 58[4]: 0000a203
+ * 59[4]: 0000944d
+ * this is the one we want:
+ * 97[17]: 009cfe245ed0c8bd45a79f54ea5fbd3d97
+ * ^^^^^^^^^^^^ in order
+ * ^^
+ * ^^
+ * ^^^^ out of order
+ * ^^^^ out of order
+ * ^^^^^^^^ out of order
+ * ^^ "type". 0 means UUID.
+ * 255[0]:
+ */
+ while (dhcp_option_parser_next(&parser, &option)) {
+ char data[option->Length + 1];
+
+ memcpy(data, option->Data, option->Length);
+ data[option->Length] = '\0';
+
+ grub_printf("%d[%d]: ", option->OpCode, option->Length);
+ for (i = 0; i < option->Length; i++) {
+ grub_printf("%c%c", hex[data[i] & 0xf],
+ hex[(data[i] & 0xf0) >> 4]);
+ }
+ printf("\n");
+ }
+
+}
+
+void grub_print_dhcp_info(grub_efi_loaded_image_t *loaded_image)
+{
+ EFI_PXE_BASE_CODE *pxe = NULL;
+ EFI_PXE_BASE_CODE_PACKET *packet;
+
+ grub_printf("got to %s\n", __func__);
+
+ pxe = grub_efi_locate_protocol(&PxeBaseCodeProtocol, NULL);
+ if (pxe == NULL)
+ return;
+
+ printf("DhcpDiscover options:\n");
+ packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->DhcpDiscover.Dhcpv4;
+ grub_dump_dhcp_options(packet);
+
+ printf("DhcpAck options:\n");
+ packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->DhcpAck.Dhcpv4;
+ grub_dump_dhcp_options(packet);
+
+ printf("PxeDiscover options:\n");
+ packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->PxeDiscover.Dhcpv4;
+ grub_dump_dhcp_options(packet);
+
+ printf("PxeReply options:\n");
+ packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->PxeReply.Dhcpv4;
+ grub_dump_dhcp_options(packet);
+
+#if 0
+ printf("pxe->Mode->DhcpAck.Dhcpv4: \n");
+ printf("\t.BootSrvName: %s\n", pxe->Mode->DhcpAck.Dhcpv4.BootpSrvName);
+ printf("\t.BootBootFile: %s\n", pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile);
+ printf("\t.BootCiAddr: %d.%d.%d.%d\n",
+ pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[0],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[1],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[2],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[3]);
+ printf("\t.BootYiAddr: %d.%d.%d.%d\n",
+ pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[0],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[1],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[2],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[3]);
+ printf("\t.BootSiAddr: %d.%d.%d.%d\n",
+ pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[0],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[1],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[2],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[3]);
+ printf("\t.BootGiAddr: %d.%d.%d.%d\n",
+ pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[0],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[1],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[2],
+ pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[3]);
+ }
+ printf("\n");
+#endif
+
+
+}
+#endif
+
+static void icmp_print_error(EFI_PXE_BASE_CODE *pxe)
+{
+ EFI_PXE_BASE_CODE_ICMP_ERROR *err = &pxe->Mode->IcmpError;
+ int i;
+ //char hex[] = "0123456789abcdef";
+
+ printf("icmp error\n");
+ printf("type: %d code: %d\n", err->Type, err->Code);
+ printf("data: \n");
+ for(i = 0; i < 464; i+=16) {
+ int x;
+ for (x = i; x < i+4; x++)
+ printf("%02x ", err->Data[x]);
+ printf(" ");
+ for (x = i+4; x < i+8; x++)
+ printf("%02x ", err->Data[x]);
+ printf(" ");
+ printf(" ");
+ for (x = i+8; x < i+12; x++)
+ printf("%02x ", err->Data[x]);
+ printf(" ");
+ for (x = i+12; x < i+16; x++)
+ printf("%02x ", err->Data[x]);
+ printf("\n");
+ }
+}
+
+static int grub_efi_pxe_check_for_file(
+ EFI_PXE_BASE_CODE *pxe,
+ EFI_IP_ADDRESS *ServerIp,
+ char *BootpBootFile,
+ char *configname,
+ char **returnpath)
+{
+ size_t bplen = strlen(BootpBootFile);
+ char *Filename = grub_malloc(24 + bplen + 40);
+ char *lastslash = Filename + bplen;
+ grub_efi_uintn_t size;
+ int i;
+ EFI_STATUS rc;
+ char Buffer[8192];
+
+ memcpy(Filename, BootpBootFile, bplen);
+
+ for (i = 0; i < bplen; i++) {
+ if (Filename[i] == '/')
+ lastslash = Filename + i;
+ }
+ if (*lastslash) {
+ *lastslash++ = '/';
+ *lastslash = '\0';
+ }
+
+ sprintf(lastslash, configname);
+
+ printf("tftp://%d.%d.%d.%d/%s\n",
+ ServerIp->v4.Addr[0], ServerIp->v4.Addr[1],
+ ServerIp->v4.Addr[2], ServerIp->v4.Addr[3],
+ Filename);
+
+ rc = tftp_get_file_size(Filename, &size);
+ if (rc == GRUB_EFI_ICMP_ERROR)
+ icmp_print_error(pxe);
+
+ if (rc == GRUB_EFI_SUCCESS) {
+ *returnpath = Filename;
+ return size;
+ }
+ grub_free(Filename);
+ return 0;
+}
+
+extern char *grub_efi_pxe_find_config_file(void);
+char *grub_efi_pxe_find_config_file(void)
+{
+ EFI_PXE_BASE_CODE *pxe = NULL;
+ EFI_PXE_BASE_CODE_DHCPV4_PACKET *packet;
+ EFI_IP_ADDRESS serveraddr;
+ char hex[] = "0123456789ABCDEF";
+ char bootpsrvname[65];
+ char bootpbootfile[129];
+ char hexip[9];
+ char *filepath = NULL;
+ int hexiplen;
+
+ pxe = grub_efi_locate_protocol(&PxeBaseCodeProtocol, NULL);
+ if (pxe == NULL)
+ return NULL;
+
+ packet = &pxe->Mode->DhcpAck.Dhcpv4;
+
+ memcpy(&serveraddr, packet->BootpSiAddr, 4);
+
+ packet = &pxe->Mode->DhcpAck.Dhcpv4;
+#if 0
+ if (!memcmp(packet->BootpHwAddr + 6, "\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00", 10) &&
+ memcmp(packet->BootpHwAddr, "\x00\x00\x00\x00\x00\x00",
+ 6)) {
+ char mac[21];
+ sprintf(mac, "00-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
+ hex[(packet->BootpHwAddr[0] & 0xf0) >> 4],
+ hex[packet->BootpHwAddr[0] & 0xf],
+ hex[(packet->BootpHwAddr[1] & 0xf0) >> 4],
+ hex[packet->BootpHwAddr[1] & 0xf],
+ hex[(packet->BootpHwAddr[2] & 0xf0) >> 4],
+ hex[packet->BootpHwAddr[2] & 0xf],
+ hex[(packet->BootpHwAddr[3] & 0xf0) >> 4],
+ hex[packet->BootpHwAddr[3] & 0xf],
+ hex[(packet->BootpHwAddr[4] & 0xf0) >> 4],
+ hex[packet->BootpHwAddr[4] & 0xf],
+ hex[(packet->BootpHwAddr[5] & 0xf0) >> 4],
+ hex[packet->BootpHwAddr[5] & 0xf]);
+ if (grub_efi_pxe_check_for_file(pxe, &serveraddr,
+ packet->BootpBootFile, mac,
+ &filepath)) {
+
+ return filepath;
+ }
+ }
+
+ sprintf(hexip, "%c%c%c%c%c%c%c%c",
+ hex[(packet->BootpYiAddr[0] & 0xf0) >> 4],
+ hex[packet->BootpYiAddr[0] & 0xf],
+ hex[(packet->BootpYiAddr[1] & 0xf0) >> 4],
+ hex[packet->BootpYiAddr[1] & 0xf],
+ hex[(packet->BootpYiAddr[2] & 0xf0) >> 4],
+ hex[packet->BootpYiAddr[2] & 0xf],
+ hex[(packet->BootpYiAddr[3] & 0xf0) >> 4],
+ hex[packet->BootpYiAddr[3] & 0xf]);
+
+ for (hexiplen = strlen(hexip); hexiplen > 0; hexiplen--)
+ {
+ hexip[hexiplen] = '\0';
+ if (grub_efi_pxe_check_for_file(pxe, &serveraddr,
+ packet->BootpBootFile, hexip,
+ &filepath)) {
+ return filepath;
+ }
+ }
+
+
+ if (grub_efi_pxe_check_for_file(pxe, &serveraddr, packet->BootpBootFile,
+ "efidefault", &filepath)) {
+ return filepath;
+ }
+#endif
+ return NULL;
+}
+
+static void get_pxe_server(EFI_PXE_BASE_CODE *pxe, EFI_IP_ADDRESS **Address)
+{
+ EFI_IP_ADDRESS *tmp = grub_malloc(sizeof *tmp);
+ if (tmp) {
+ memset(tmp, '\0', sizeof (*tmp));
+ memcpy(&tmp->Addr[0], pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, 4);
+ *Address = tmp;
+ }
+}
+
+static char *get_pxe_file_dir(EFI_PXE_BASE_CODE *pxe)
+{
+ char *FileDir = NULL;
+ char *DirEnd = NULL;
+ char *BootpBootFile;
+ size_t bplen;
+
+ BootpBootFile = pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile;
+ bplen = strlen(BootpBootFile);
+ FileDir = grub_malloc(bplen + 1);
+ memcpy(FileDir, BootpBootFile, bplen);
+ FileDir[bplen] = '\0';
+
+ DirEnd = grub_strrchr(FileDir, '/');
+ if (!DirEnd)
+ DirEnd = FileDir;
+
+ *DirEnd = '\0';
+
+ printf("FileDir: \"%s\"\n", FileDir);
+ return FileDir;
+}
+
+static void set_pxe_info(grub_efi_loaded_image_t *LoadedImage,
+ EFI_PXE_BASE_CODE *pxe)
+{
+ tftp_info.LoadedImage = LoadedImage;
+ tftp_info.Pxe = pxe;
+ get_pxe_server(pxe, &tftp_info.ServerIp);
+ tftp_info.BasePath = get_pxe_file_dir(pxe);
+}
+
+char *grub_efi_pxe_get_config_path(grub_efi_loaded_image_t *LoadedImage)
+{
+ EFI_PXE_BASE_CODE *pxe = NULL;
+ EFI_IP_ADDRESS ServerIp;
+ char *FileName = NULL;
+ EFI_PXE_BASE_CODE_DHCPV4_PACKET *packet;
+ uuid_t uuid;
+ size_t FileSize = 0;
+ grub_efi_status_t rc = GRUB_EFI_SUCCESS;
+ char *ConfigPath = NULL;
+
+ pxe = grub_efi_locate_protocol(&PxeBaseCodeProtocol, NULL);
+ if (pxe == NULL)
+ return NULL;
+
+ if (!pxe->Mode->Started)
+ return NULL;
+
+ set_pxe_info(LoadedImage, pxe);
+
+ FileName = grub_malloc(strlen("1902dcf5-7190-d811-bbd6-6ef21c690030"));
+
+ packet = &pxe->Mode->DhcpDiscover.Dhcpv4;
+
+ if (get_dhcp_client_id((EFI_PXE_BASE_CODE_PACKET *)packet, &uuid)) {
+
+ uuid.time_mid = 0x0011;
+ sprintf(FileName,
+ "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ uuid.time_low, uuid.time_mid, uuid.time_hi_ver,
+ uuid.clock_seq_hi, uuid.clock_seq_low,
+ uuid.node[0], uuid.node[1], uuid.node[2],
+ uuid.node[3], uuid.node[4], uuid.node[5]);
+ printf("FileName: \"%s\"\n", FileName);
+
+ rc = tftp_get_file_size(FileName, &FileSize);
+ if (rc == GRUB_EFI_SUCCESS) {
+ char *ReturnFile = grub_malloc(strlen("(nd)/") +
+ strlen(FileName) + 1);
+ sprintf(ReturnFile, "(nd)/%s", FileName);
+ grub_free(FileName);
+ //sprintf(tftp_info.LastPath, FileName);
+ return ReturnFile;
+ }
+ }
+
+ return NULL;
+}
diff --git a/efi/pxe.h b/efi/pxe.h
new file mode 100644
index 0000000..0a68007
--- /dev/null
+++ b/efi/pxe.h
@@ -0,0 +1,237 @@
+#ifndef PXE_H
+#define PXE_H 1
+
+#include "byteswap.h"
+
+extern char *grub_efi_pxe_get_config_path(grub_efi_loaded_image_t *LoadedImage);
+extern void grub_print_dhcp_info(grub_efi_loaded_image_t *loaded_image);
+extern char *grub_efi_pxe_path_to_path_name(void);
+
+
+#define EFI_PXE_BASE_CODE_PROTOCOL \
+ { 0x03c4e603, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }
+static grub_efi_guid_t PxeBaseCodeProtocol = EFI_PXE_BASE_CODE_PROTOCOL;
+
+struct _EFI_PXE_BASE_CODE;
+
+typedef enum {
+ EFI_PXE_BASE_CODE_TFTP_FIRST,
+ EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
+ EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY,
+ EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE,
+ EFI_PXE_BASE_CODE_MTFTP_READ_FILE,
+ EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY,
+ EFI_PXE_BASE_CODE_MTFTP_LAST
+} EFI_PXE_BASE_CODE_TFTP_OPCODE;
+
+typedef struct {
+ grub_efi_uint8_t Addr[4];
+} EFI_IPv4_ADDRESS;
+
+typedef struct {
+ grub_efi_uint8_t Addr[16];
+} EFI_IPv6_ADDRESS;
+
+typedef struct {
+ grub_efi_uint8_t Addr[32];
+} EFI_MAC_ADDRESS;
+
+typedef union {
+ grub_efi_uint32_t Addr[4];
+ EFI_IPv4_ADDRESS v4;
+ EFI_IPv6_ADDRESS v6;
+} EFI_IP_ADDRESS;
+
+typedef grub_efi_uint16_t EFI_PXE_BASE_CODE_UDP_PORT;
+
+typedef struct {
+ EFI_IP_ADDRESS MCastIp;
+ EFI_PXE_BASE_CODE_UDP_PORT CPort;
+ EFI_PXE_BASE_CODE_UDP_PORT SPort;
+ grub_efi_uint16_t ListenTimeout;
+ grub_efi_uint16_t TransmitTimeout;
+} EFI_PXE_BASE_CODE_MTFTP_INFO;
+
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_MTFTP)(
+ struct _EFI_PXE_BASE_CODE *This,
+ EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
+ void *BufferPtr,
+ grub_efi_boolean_t Overwrite,
+ grub_efi_uint64_t *BufferSize,
+ grub_efi_uintn_t *BlockSize,
+ EFI_IP_ADDRESS *ServerIp,
+ grub_efi_uint8_t *Filename,
+ EFI_PXE_BASE_CODE_MTFTP_INFO *Info,
+ grub_efi_boolean_t DontUseBuffer);
+
+typedef struct {
+ grub_efi_uint8_t BootpOpcode;
+ grub_efi_uint8_t BootpHwType;
+ grub_efi_uint8_t BootpHwAddrLen;
+ grub_efi_uint8_t BootpGateHops;
+ grub_efi_uint32_t BootpIdent;
+ grub_efi_uint16_t BootpSeconds;
+ grub_efi_uint16_t BootpFlags;
+ grub_efi_uint8_t BootpCiAddr[4];
+ grub_efi_uint8_t BootpYiAddr[4];
+ grub_efi_uint8_t BootpSiAddr[4];
+ grub_efi_uint8_t BootpGiAddr[4];
+ grub_efi_uint8_t BootpHwAddr[16];
+ grub_efi_uint8_t BootpSrvName[64];
+ grub_efi_uint8_t BootpBootFile[128];
+ grub_efi_uint32_t DhcpMagik;
+ grub_efi_uint8_t DhcpOptions[56];
+} EFI_PXE_BASE_CODE_DHCPV4_PACKET;
+
+// TBD in EFI v1.1
+//typedef struct {
+// grub_efi_uint8_t reserved;
+//} EFI_PXE_BASE_CODE_DHCPV6_PACKET;
+
+typedef union {
+ grub_efi_uint8_t Raw[1472];
+ EFI_PXE_BASE_CODE_DHCPV4_PACKET Dhcpv4;
+// EFI_PXE_BASE_CODE_DHCPV6_PACKET Dhcpv6;
+} EFI_PXE_BASE_CODE_PACKET;
+
+typedef struct {
+ grub_efi_uint8_t Type;
+ grub_efi_uint8_t Code;
+ grub_efi_uint16_t Checksum;
+ union {
+ grub_efi_uint32_t reserved;
+ grub_efi_uint32_t Mtu;
+ grub_efi_uint32_t Pointer;
+ struct {
+ grub_efi_uint16_t Identifier;
+ grub_efi_uint16_t Sequence;
+ } Echo;
+ } u;
+ grub_efi_uint8_t Data[494];
+} EFI_PXE_BASE_CODE_ICMP_ERROR;
+
+typedef struct {
+ grub_efi_uint8_t ErrorCode;
+ grub_efi_char8_t ErrorString[127];
+} EFI_PXE_BASE_CODE_TFTP_ERROR;
+
+
+#define EFI_PXE_BASE_CODE_MAX_IPCNT 8
+typedef struct {
+ grub_efi_uint8_t Filters;
+ grub_efi_uint8_t IpCnt;
+ grub_efi_uint16_t reserved;
+ EFI_IP_ADDRESS IpList[EFI_PXE_BASE_CODE_MAX_IPCNT];
+} EFI_PXE_BASE_CODE_IP_FILTER;
+
+#define EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP 0x0001
+#define EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST 0x0002
+#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS 0x0004
+#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST 0x0008
+
+typedef struct {
+ EFI_IP_ADDRESS IpAddr;
+ EFI_MAC_ADDRESS MacAddr;
+} EFI_PXE_BASE_CODE_ARP_ENTRY;
+
+typedef struct {
+ EFI_IP_ADDRESS IpAddr;
+ EFI_IP_ADDRESS SubnetMask;
+ EFI_IP_ADDRESS GwAddr;
+} EFI_PXE_BASE_CODE_ROUTE_ENTRY;
+
+#define EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8
+#define EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8
+
+typedef struct {
+ grub_efi_boolean_t Started;
+ grub_efi_boolean_t Ipv6Available;
+ grub_efi_boolean_t Ipv6Supported;
+ grub_efi_boolean_t UsingIpv6;
+ grub_efi_boolean_t BisSupported;
+ grub_efi_boolean_t BisDetected;
+ grub_efi_boolean_t AutoArp;
+ grub_efi_boolean_t SendGUID;
+ grub_efi_boolean_t DhcpDiscoverValid;
+ grub_efi_boolean_t DhcpAckReceived;
+ grub_efi_boolean_t ProxyOfferReceived;
+ grub_efi_boolean_t PxeDiscoverValid;
+ grub_efi_boolean_t PxeReplyReceived;
+ grub_efi_boolean_t PxeBisReplyReceived;
+ grub_efi_boolean_t IcmpErrorReceived;
+ grub_efi_boolean_t TftpErrorReceived;
+ grub_efi_boolean_t MakeCallbacks;
+ grub_efi_uint8_t TTL;
+ grub_efi_uint8_t ToS;
+ EFI_IP_ADDRESS StationIp;
+ EFI_IP_ADDRESS SubnetMask;
+ EFI_PXE_BASE_CODE_PACKET DhcpDiscover;
+ EFI_PXE_BASE_CODE_PACKET DhcpAck;
+ EFI_PXE_BASE_CODE_PACKET ProxyOffer;
+ EFI_PXE_BASE_CODE_PACKET PxeDiscover;
+ EFI_PXE_BASE_CODE_PACKET PxeReply;
+ EFI_PXE_BASE_CODE_PACKET PxeBisReply;
+ EFI_PXE_BASE_CODE_IP_FILTER IpFilter;
+ grub_efi_uint32_t ArpCacheEntries;
+ EFI_PXE_BASE_CODE_ARP_ENTRY ArpCache[EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES];
+ grub_efi_uint32_t RouteTableEntries;
+ EFI_PXE_BASE_CODE_ROUTE_ENTRY RouteTable[EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES];
+ EFI_PXE_BASE_CODE_ICMP_ERROR IcmpError;
+ EFI_PXE_BASE_CODE_TFTP_ERROR TftpError;
+} EFI_PXE_BASE_CODE_MODE;
+
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_START)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_STOP)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_DHCP)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_DISCOVER)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_UDP_WRITE)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_UDP_READ)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_IP_FILTER)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_ARP)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_PARAMETERS)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_STATION_IP)();
+typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_PACKETS)();
+
+typedef struct _EFI_PXE_BASE_CODE{
+ grub_efi_uint64_t Revision;
+ EFI_PXE_BASE_CODE_START Start;
+ EFI_PXE_BASE_CODE_STOP Stop;
+ EFI_PXE_BASE_CODE_DHCP Dhcp;
+ EFI_PXE_BASE_CODE_DISCOVER Discover;
+ EFI_PXE_BASE_CODE_MTFTP Mtftp;
+ EFI_PXE_BASE_CODE_UDP_WRITE UdpWrite;
+ EFI_PXE_BASE_CODE_UDP_READ UdpRead;
+ EFI_PXE_BASE_CODE_SET_IP_FILTER SetIpFilter;
+ EFI_PXE_BASE_CODE_ARP Arp;
+ EFI_PXE_BASE_CODE_SET_PARAMETERS SetParameters;
+ EFI_PXE_BASE_CODE_SET_STATION_IP SetStationIp;
+ EFI_PXE_BASE_CODE_SET_PACKETS SetPackets;
+ EFI_PXE_BASE_CODE_MODE *Mode;
+} EFI_PXE_BASE_CODE;
+
+typedef struct {
+ grub_efi_uint32_t time_low;
+ grub_efi_uint16_t time_mid;
+ grub_efi_uint16_t time_hi_ver;
+ grub_efi_uint8_t clock_seq_hi;
+ grub_efi_uint8_t clock_seq_low;
+ grub_efi_uint8_t node[6];
+} uuid_t;
+
+struct tftp_info {
+ grub_efi_loaded_image_t *LoadedImage;
+ EFI_PXE_BASE_CODE *Pxe;
+ EFI_IP_ADDRESS *ServerIp;
+ char *BasePath;
+ char *LastPath;
+ char *Buffer;
+};
+
+extern struct tftp_info tftp_info;
+extern grub_efi_status_t tftp_get_file_size(
+ char *Filename,
+ grub_efi_uintn_t *Size);
+
+#endif /* PXE_H */
diff --git a/grub/Makefile.am b/grub/Makefile.am
index 7eb2eaa..d4353f7 100644
--- a/grub/Makefile.am
+++ b/grub/Makefile.am
@@ -15,5 +15,5 @@ AM_CPPFLAGS = -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
AM_CFLAGS = $(GRUB_CFLAGS)
-grub_SOURCES = main.c asmstub.c
+grub_SOURCES = main.c asmstub.c efitftp.c
grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
diff --git a/grub/efitftp.c b/grub/efitftp.c
new file mode 100644
index 0000000..383c451
--- /dev/null
+++ b/grub/efitftp.c
@@ -0,0 +1,29 @@
+#include <shared.h>
+#include <filesys.h>
+
+int
+efi_tftp_mount (void)
+{
+ grub_printf("non-efi efi_tftp_mount()\n");
+ return 0;
+}
+
+int
+efi_tftp_read (char *addr, int size)
+{
+ grub_printf ("non-efi efi_tftp_read (0x%x, %d)\n", (long) addr, size);
+ return 0;
+}
+
+int
+efi_tftp_dir (char *dirname)
+{
+ grub_printf ("non-efi efi_ftp_dir (%s)\n", dirname);
+ return 0;
+}
+
+void
+efi_tftp_close (void)
+{
+ grub_printf ("non-efi efi_tftp_close ()\n");
+}
diff --git a/stage2/Makefile.am b/stage2/Makefile.am
index e128bc2..06bc8e5 100644
--- a/stage2/Makefile.am
+++ b/stage2/Makefile.am
@@ -23,7 +23,7 @@ libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \
fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \
fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
- terminfo.c tparm.c graphics.c
+ terminfo.c tparm.c graphics.c efistubs.c
libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \
-DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
-DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \
@@ -100,7 +100,7 @@ libstage2_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \
fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \
fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
- terminfo.c tparm.c
+ terminfo.c tparm.c efistubs.c
libstage2_a_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
if !PLATFORM_EFI
diff --git a/stage2/disk_io.c b/stage2/disk_io.c
index 622bdbb..ef34ae4 100644
--- a/stage2/disk_io.c
+++ b/stage2/disk_io.c
@@ -28,6 +28,10 @@
# include <etherboot.h>
#endif
+#ifdef PLATFORM_EFI
+#include "efistubs.h"
+#endif
+
#ifdef GRUB_UTIL
# include <device.h>
#endif
@@ -49,6 +53,9 @@ int fsmax;
struct fsys_entry fsys_table[NUM_FSYS + 1] =
{
/* TFTP should come first because others don't handle net device. */
+# ifdef PLATFORM_EFI
+ {"efitftp", efi_tftp_mount, efi_tftp_read, efi_tftp_dir, efi_tftp_close, 0},
+# endif
# ifdef FSYS_TFTP
{"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close, 0},
# endif
@@ -1067,7 +1074,7 @@ set_device (char *device)
if (*device != ',' && *device != ')')
{
char ch = *device;
-#ifdef SUPPORT_NETBOOT
+#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
if (*device == 'f' || *device == 'h'
|| (*device == 'n' && network_ready)
|| (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
@@ -1091,14 +1098,14 @@ set_device (char *device)
if ((*device == 'f'
|| *device == 'h'
-#ifdef SUPPORT_NETBOOT
+#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
|| (*device == 'n' && network_ready)
#endif
|| (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
&& (device += 2, (*(device - 1) != 'd')))
errnum = ERR_NUMBER_PARSING;
-#ifdef SUPPORT_NETBOOT
+#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
if (ch == 'n' && network_ready)
current_drive = NETWORK_DRIVE;
else
@@ -1465,7 +1472,7 @@ print_completions (int is_filename, int is_completion)
if (!ptr
|| *(ptr-1) != 'd'
-#ifdef SUPPORT_NETBOOT
+#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
|| *(ptr-2) != 'n'
#endif /* SUPPORT_NETBOOT */
|| *(ptr-2) != 'c')
@@ -1496,7 +1503,7 @@ print_completions (int is_filename, int is_completion)
|| (*(ptr-1) == 'd' && *(ptr-2) == 'c')))
print_a_completion ("cd");
-# ifdef SUPPORT_NETBOOT
+# if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
if (network_ready
&& (disk_choice || NETWORK_DRIVE == current_drive)
&& (!ptr
diff --git a/stage2/efistubs.c b/stage2/efistubs.c
new file mode 100644
index 0000000..79db331
--- /dev/null
+++ b/stage2/efistubs.c
@@ -0,0 +1,9 @@
+
+#include "shared.h"
+#include "efistubs.h"
+
+#if defined(PLATFORM_EFI)
+int network_ready = 0;
+#else
+#error wtf
+#endif /* defined(PLATFORM_EFI) */
diff --git a/stage2/efistubs.h b/stage2/efistubs.h
new file mode 100644
index 0000000..97e407d
--- /dev/null
+++ b/stage2/efistubs.h
@@ -0,0 +1,8 @@
+#ifndef EFISTUBS_H
+#define EFISTUBS_H 1
+
+#if defined(PLATFORM_EFI)
+extern int network_ready;
+#endif /* defined(PLATFORM_EFI) */
+
+#endif /* EFISTUBS_H */
diff --git a/stage2/filesys.h b/stage2/filesys.h
index 4ea0728..4295e45 100644
--- a/stage2/filesys.h
+++ b/stage2/filesys.h
@@ -115,6 +115,17 @@ void tftp_close (void);
#define FSYS_TFTP_NUM 0
#endif
+#ifdef PLATFORM_EFI
+#define FSYS_EFI_TFTP_NUM 1
+int efi_tftp_mount (void);
+int efi_tftp_read (char *buf, int len);
+int efi_tftp_dir (char *dirname);
+void efi_tftp_close (void);
+#else
+#define FSYS_EFI_TFTP_NUM 0
+#endif
+
+
#ifdef FSYS_ISO9660
#define FSYS_ISO9660_NUM 1
int iso9660_mount (void);
@@ -128,7 +139,7 @@ int iso9660_dir (char *dirname);
#define NUM_FSYS \
(FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM \
+ FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM \
- + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM)
+ + FSYS_TFTP_NUM + FSYS_EFI_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM)
#endif
/* defines for the block filesystem info area */
--
1.6.2
Index: grub.spec
===================================================================
RCS file: /cvs/extras/rpms/grub/devel/grub.spec,v
retrieving revision 1.88
retrieving revision 1.89
diff -u -r1.88 -r1.89
--- grub.spec 30 Mar 2009 21:22:56 -0000 1.88
+++ grub.spec 3 Apr 2009 18:34:11 -0000 1.89
@@ -1,6 +1,6 @@
Name: grub
Version: 0.97
-Release: 44%{?dist}
+Release: 45%{?dist}
Summary: Grand Unified Boot Loader.
Group: System Environment/Base
License: GPLv2+
@@ -36,6 +36,7 @@
Patch8: grub-0.97-xfs-buildfix.patch
Patch9: grub-0.97-efigraph-use-blt.patch
Patch10: grub-0.97-efislice.patch
+Patch11: grub-0.97-efipxe.patch
%description
GRUB (Grand Unified Boot Loader) is an experimental boot loader
@@ -56,6 +57,7 @@
%patch8 -p1
%patch9 -p1
%patch10 -p1
+%patch11 -p1
%build
autoreconf
@@ -118,6 +120,9 @@
%{_datadir}/grub
%changelog
+* Fri Apr 03 2009 Peter Jones <pjones at redhat.com> - 0.97-45
+- Add very basic PXE support for EFI.
+
* Mon Mar 30 2009 Matthew Garrett <mjg at redhat.com> - 0.97-44
- Recognise the 0xef partition type
More information about the scm-commits
mailing list