diff --git a/boot/i386/pc/pxeboot.S b/boot/i386/pc/pxeboot.S
index 7f2a143..62a4fb2 100644
--- a/boot/i386/pc/pxeboot.S
+++ b/boot/i386/pc/pxeboot.S
@@ -26,7 +26,8 @@
.globl _start; _start:
/* Root drive will default to boot drive */
- movb $0xFF, %dh
+ movb $0xFF, %dh
+ movb $0x7F, %dl
/* Jump to the real world */
ljmp $0, $0x8200
diff --git a/commands/i386/pc/pxecmd.c b/commands/i386/pc/pxecmd.c
new file mode 100755
index 0000000..6bf3045
--- /dev/null
+++ b/commands/i386/pc/pxecmd.c
@@ -0,0 +1,92 @@
+/* pxe.c - command to control the pxe driver */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static void
+print_ip (grub_uint32_t ip)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ {
+ grub_printf ("%d.", ip & 0xFF);
+ ip >>= 8;
+ }
+ grub_printf ("%d", ip);
+}
+
+static grub_err_t
+grub_cmd_pxe (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc, char **args)
+{
+ if (! grub_pxe_pxenv)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment");
+
+ if ((argc == 0) || (! grub_strcmp (args[0], "info")))
+ {
+ grub_printf ("blksize : %d\n", grub_pxe_blksize);
+ grub_printf ("client ip : ");
+ print_ip (grub_pxe_your_ip);
+ grub_printf ("\nserver ip : ");
+ print_ip (grub_pxe_server_ip);
+ grub_printf ("\ngateway ip : ");
+ print_ip (grub_pxe_gateway_ip);
+ grub_printf ("\n");
+ }
+ else if (! grub_strcmp (args[0], "blksize"))
+ {
+ int size;
+
+ if (argc < 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no blksize specified");
+
+ size = grub_strtoul (args[1], 0, 0);
+ if (size < GRUB_PXE_MIN_BLKSIZE)
+ size = GRUB_PXE_MIN_BLKSIZE;
+ else if (size > GRUB_PXE_MAX_BLKSIZE)
+ size = GRUB_PXE_MAX_BLKSIZE;
+
+ grub_pxe_blksize = size;
+ }
+ else if (! grub_strcmp (args[0], "unload"))
+ {
+ grub_pxe_unload ();
+ }
+
+ return 0;
+}
+
+GRUB_MOD_INIT(pxecmd)
+{
+ (void) mod; /* To stop warning. */
+ grub_register_command ("pxe", grub_cmd_pxe, GRUB_COMMAND_FLAG_BOTH,
+ "pxe info | blksize size | unload",
+ "Show information about PXE.", 0);
+}
+
+GRUB_MOD_FINI(pxecmd)
+{
+ grub_unregister_command ("pxe");
+}
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 8617a92..59fc6a3 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -50,7 +50,8 @@ kernel_img_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \
machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \
- machine/memory.h machine/loader.h machine/vga.h machine/vbe.h machine/kernel.h
+ machine/memory.h machine/loader.h machine/vga.h machine/vbe.h \
+ machine/kernel.h machine/pxe.h
kernel_img_CFLAGS = $(COMMON_CFLAGS)
kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,$(GRUB_MEMORY_MACHINE_LINK_ADDR) $(COMMON_CFLAGS)
@@ -158,7 +159,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \
vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \
ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \
- aout.mod _bsd.mod bsd.mod
+ aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod
# For biosdisk.mod.
biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -325,4 +326,14 @@ bsd_mod_SOURCES = loader/i386/bsd_normal.c
bsd_mod_CFLAGS = $(COMMON_CFLAGS)
bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For pxe.mod
+pxe_mod_SOURCES = disk/i386/pc/pxe.c
+pxe_mod_CFLAGS = $(COMMON_CFLAGS)
+pxe_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For pxecmd.mod
+pxecmd_mod_SOURCES = commands/i386/pc/pxecmd.c
+pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
+pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
include $(srcdir)/conf/common.mk
diff --git a/disk/i386/pc/pxe.c b/disk/i386/pc/pxe.c
new file mode 100644
index 0000000..ced1088
--- /dev/null
+++ b/disk/i386/pc/pxe.c
@@ -0,0 +1,335 @@
+/* pxe.c - Driver to provide access to the pxe filesystem */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#define SEGMENT(x) ((x) >> 4)
+#define OFFSET(x) ((x) & 0xF)
+#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x))
+#define LINEAR(x) (void *) (((x >> 16) <<4) + (x & 0xFFFF))
+
+struct grub_pxenv *grub_pxe_pxenv;
+grub_uint32_t grub_pxe_your_ip;
+grub_uint32_t grub_pxe_server_ip;
+grub_uint32_t grub_pxe_gateway_ip;
+int grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
+
+struct grub_pxe_data
+{
+ grub_uint32_t packet_number;
+ char filename[0];
+};
+
+static int
+grub_pxe_iterate (int (*hook) (const char *name))
+{
+ if (hook ("pxe"))
+ return 1;
+ return 0;
+}
+
+static grub_err_t
+grub_pxe_open (const char *name, grub_disk_t disk)
+{
+ if (grub_strcmp (name, "pxe"))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk");
+
+ disk->total_sectors = 0;
+ disk->id = (unsigned long) "pxe";
+
+ disk->has_partitions = 0;
+ disk->data = 0;
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+grub_pxe_close (grub_disk_t disk __attribute((unused)))
+{
+}
+
+static grub_err_t
+grub_pxe_read (grub_disk_t disk __attribute((unused)),
+ grub_disk_addr_t sector __attribute((unused)),
+ grub_size_t size __attribute((unused)),
+ char *buf __attribute((unused)))
+{
+ return GRUB_ERR_OUT_OF_RANGE;
+}
+
+static grub_err_t
+grub_pxe_write (grub_disk_t disk __attribute((unused)),
+ grub_disk_addr_t sector __attribute((unused)),
+ grub_size_t size __attribute((unused)),
+ const char *buf __attribute((unused)))
+{
+ return GRUB_ERR_OUT_OF_RANGE;
+}
+
+static struct grub_disk_dev grub_pxe_dev =
+ {
+ .name = "pxe",
+ .id = GRUB_DISK_DEVICE_PXE_ID,
+ .iterate = grub_pxe_iterate,
+ .open = grub_pxe_open,
+ .close = grub_pxe_close,
+ .read = grub_pxe_read,
+ .write = grub_pxe_write,
+ .next = 0
+ };
+
+static grub_err_t
+grub_pxefs_dir (grub_device_t device __attribute((unused)),
+ const char *path __attribute((unused)),
+ int (*hook) (const char *filename, int dir) __attribute((unused)))
+{
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_fs grub_pxefs_fs_int;
+
+static grub_err_t
+grub_pxefs_open (struct grub_file *file, const char *name)
+{
+ union
+ {
+ struct grub_pxenv_tftp_get_fsize c1;
+ struct grub_pxenv_tftp_open c2;
+ } c;
+ struct grub_pxe_data *data;
+ grub_file_t file_int, bufio;
+
+ c.c1.server_ip = grub_pxe_server_ip;
+ c.c1.gateway_ip = grub_pxe_gateway_ip;
+ grub_strcpy (c.c1.filename, name);
+ grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1);
+ if (c.c1.status)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
+
+ file->size = c.c1.file_size;
+
+ c.c2.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
+ c.c2.packet_size = grub_pxe_blksize;
+ grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2);
+ if (c.c2.status)
+ return grub_error (GRUB_ERR_BAD_FS, "open fails");
+
+ data = grub_malloc (sizeof (struct grub_pxe_data) + grub_strlen (name) + 1);
+ if (! data)
+ return grub_errno;
+
+ data->packet_number = 0;
+ grub_strcpy (data->filename, name);
+
+ file_int = grub_malloc (sizeof (*file_int));
+ if (! file_int)
+ {
+ grub_free (data);
+ return grub_errno;
+ }
+
+ file_int->data = data;
+ file_int->offset = 0;
+ file_int->device = 0;
+ file_int->size = file->size;
+ file_int->read_hook = 0;
+ file_int->fs = &grub_pxefs_fs_int;
+
+ bufio = grub_bufio_open (file_int, grub_pxe_blksize);
+ if (! bufio)
+ {
+ grub_free (file_int);
+ grub_free (data);
+ return grub_errno;
+ }
+
+ file->data = bufio;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ grub_file_t bufio;
+
+ bufio = file->data;
+ bufio->offset = file->offset;
+
+ return bufio->fs->read (bufio, buf, len);
+}
+
+static grub_ssize_t
+grub_pxefs_close (grub_file_t file)
+{
+ grub_file_close ((grub_file_t) file->data);
+
+ return grub_errno;
+}
+
+static grub_ssize_t
+grub_pxefs_read_int (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_pxenv_tftp_read c;
+ struct grub_pxe_data *data;
+ grub_uint32_t pn, r;
+
+ data = file->data;
+
+ pn = grub_divmod64 (file->offset, grub_pxe_blksize, &r);
+ if (r)
+ return grub_error (GRUB_ERR_BAD_FS,
+ "read access must be aligned to packet size");
+
+ if (data->packet_number > pn)
+ {
+ struct grub_pxenv_tftp_open o;
+
+ grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o);
+
+ o.server_ip = grub_pxe_server_ip;
+ o.gateway_ip = grub_pxe_gateway_ip;
+ grub_strcpy (o.filename, data->filename);
+ o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
+ o.packet_size = grub_pxe_blksize;
+ grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o);
+ if (o.status)
+ return grub_error (GRUB_ERR_BAD_FS, "open fails");
+ data->packet_number = 0;
+ }
+
+ c.buffer = SEGOFS (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
+ while (pn >= data->packet_number)
+ {
+ c.buffer_size = grub_pxe_blksize;
+ grub_pxe_call (GRUB_PXENV_TFTP_READ, &c);
+ if (c.status)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "read fails");
+ return -1;
+ }
+ data->packet_number++;
+ }
+
+ grub_memcpy (buf, (char *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, len);
+
+ return len;
+}
+
+static grub_err_t
+grub_pxefs_close_int (grub_file_t file)
+{
+ struct grub_pxenv_tftp_close c;
+
+ grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c);
+ grub_free (file->data);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_pxefs_label (grub_device_t device __attribute ((unused)),
+ char **label __attribute ((unused)))
+{
+ *label = 0;
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_fs grub_pxefs_fs =
+ {
+ .name = "pxefs",
+ .dir = grub_pxefs_dir,
+ .open = grub_pxefs_open,
+ .read = grub_pxefs_read,
+ .close = grub_pxefs_close,
+ .label = grub_pxefs_label,
+ .next = 0
+ };
+
+static struct grub_fs grub_pxefs_fs_int =
+ {
+ .name = "pxefs",
+ .read = grub_pxefs_read_int,
+ .close = grub_pxefs_close_int,
+ };
+
+static void
+grub_pxe_detect (void)
+{
+ struct grub_pxenv *pxenv;
+ struct grub_pxenv_get_cached_info ci;
+ struct grub_pxenv_boot_player *bp;
+
+ pxenv = grub_pxe_scan ();
+ if (! pxenv)
+ return;
+
+ ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
+ ci.buffer = 0;
+ ci.buffer_size = 0;
+ grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci);
+ if (ci.status)
+ return;
+
+ bp = LINEAR (ci.buffer);
+
+ grub_pxe_your_ip = bp->your_ip;
+ grub_pxe_server_ip = bp->server_ip;
+ grub_pxe_gateway_ip = bp->gateway_ip;
+
+ grub_pxe_pxenv = pxenv;
+}
+
+void
+grub_pxe_unload (void)
+{
+ if (grub_pxe_pxenv)
+ {
+ grub_fs_unregister (&grub_pxefs_fs);
+ grub_disk_dev_unregister (&grub_pxe_dev);
+
+ grub_pxe_pxenv = 0;
+ }
+}
+
+GRUB_MOD_INIT(pxe)
+{
+ (void) mod; /* To stop warning. */
+
+ grub_pxe_detect ();
+ if (grub_pxe_pxenv)
+ {
+ grub_disk_dev_register (&grub_pxe_dev);
+ grub_fs_register (&grub_pxefs_fs);
+ }
+}
+
+GRUB_MOD_FINI(pxe)
+{
+ grub_pxe_unload ();
+}
diff --git a/include/grub/disk.h b/include/grub/disk.h
index 0e27892..16765d0 100644
--- a/include/grub/disk.h
+++ b/include/grub/disk.h
@@ -39,6 +39,7 @@ enum grub_disk_dev_id
GRUB_DISK_DEVICE_MEMDISK_ID,
GRUB_DISK_DEVICE_NAND_ID,
GRUB_DISK_DEVICE_UUID_ID,
+ GRUB_DISK_DEVICE_PXE_ID,
};
struct grub_disk;
diff --git a/include/grub/i386/pc/pxe.h b/include/grub/i386/pc/pxe.h
new file mode 100755
index 0000000..43fec80
--- /dev/null
+++ b/include/grub/i386/pc/pxe.h
@@ -0,0 +1,318 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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 .
+ */
+
+#ifndef GRUB_CPU_PXE_H
+#define GRUB_CPU_PXE_H
+
+#include
+
+#define GRUB_PXENV_TFTP_OPEN 0x0020
+#define GRUB_PXENV_TFTP_CLOSE 0x0021
+#define GRUB_PXENV_TFTP_READ 0x0022
+#define GRUB_PXENV_TFTP_READ_FILE 0x0023
+#define GRUB_PXENV_TFTP_READ_FILE_PMODE 0x0024
+#define GRUB_PXENV_TFTP_GET_FSIZE 0x0025
+
+#define GRUB_PXENV_UDP_OPEN 0x0030
+#define GRUB_PXENV_UDP_CLOSE 0x0031
+#define GRUB_PXENV_UDP_READ 0x0032
+#define GRUB_PXENV_UDP_WRITE 0x0033
+
+#define GRUB_PXENV_START_UNDI 0x0000
+#define GRUB_PXENV_UNDI_STARTUP 0x0001
+#define GRUB_PXENV_UNDI_CLEANUP 0x0002
+#define GRUB_PXENV_UNDI_INITIALIZE 0x0003
+#define GRUB_PXENV_UNDI_RESET_NIC 0x0004
+#define GRUB_PXENV_UNDI_SHUTDOWN 0x0005
+#define GRUB_PXENV_UNDI_OPEN 0x0006
+#define GRUB_PXENV_UNDI_CLOSE 0x0007
+#define GRUB_PXENV_UNDI_TRANSMIT 0x0008
+#define GRUB_PXENV_UNDI_SET_MCAST_ADDR 0x0009
+#define GRUB_PXENV_UNDI_SET_STATION_ADDR 0x000A
+#define GRUB_PXENV_UNDI_SET_PACKET_FILTER 0x000B
+#define GRUB_PXENV_UNDI_GET_INFORMATION 0x000C
+#define GRUB_PXENV_UNDI_GET_STATISTICS 0x000D
+#define GRUB_PXENV_UNDI_CLEAR_STATISTICS 0x000E
+#define GRUB_PXENV_UNDI_INITIATE_DIAGS 0x000F
+#define GRUB_PXENV_UNDI_FORCE_INTERRUPT 0x0010
+#define GRUB_PXENV_UNDI_GET_MCAST_ADDR 0x0011
+#define GRUB_PXENV_UNDI_GET_NIC_TYPE 0x0012
+#define GRUB_PXENV_UNDI_GET_IFACE_INFO 0x0013
+#define GRUB_PXENV_UNDI_ISR 0x0014
+#define GRUB_PXENV_STOP_UNDI 0x0015
+#define GRUB_PXENV_UNDI_GET_STATE 0x0015
+
+#define GRUB_PXENV_UNLOAD_STACK 0x0070
+#define GRUB_PXENV_GET_CACHED_INFO 0x0071
+#define GRUB_PXENV_RESTART_DHCP 0x0072
+#define GRUB_PXENV_RESTART_TFTP 0x0073
+#define GRUB_PXENV_MODE_SWITCH 0x0074
+#define GRUB_PXENV_START_BASE 0x0075
+#define GRUB_PXENV_STOP_BASE 0x0076
+
+#define GRUB_PXENV_EXIT_SUCCESS 0x0000
+#define GRUB_PXENV_EXIT_FAILURE 0x0001
+
+#define GRUB_PXENV_STATUS_SUCCESS 0x00
+#define GRUB_PXENV_STATUS_FAILURE 0x01
+#define GRUB_PXENV_STATUS_BAD_FUNC 0x02
+#define GRUB_PXENV_STATUS_UNSUPPORTED 0x03
+#define GRUB_PXENV_STATUS_KEEP_UNDI 0x04
+#define GRUB_PXENV_STATUS_KEEP_ALL 0x05
+#define GRUB_PXENV_STATUS_OUT_OF_RESOURCES 0x06
+#define GRUB_PXENV_STATUS_ARP_TIMEOUT 0x11
+#define GRUB_PXENV_STATUS_UDP_CLOSED 0x18
+#define GRUB_PXENV_STATUS_UDP_OPEN 0x19
+#define GRUB_PXENV_STATUS_TFTP_CLOSED 0x1A
+#define GRUB_PXENV_STATUS_TFTP_OPEN 0x1B
+#define GRUB_PXENV_STATUS_MCOPY_PROBLEM 0x20
+#define GRUB_PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21
+#define GRUB_PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22
+#define GRUB_PXENV_STATUS_BIS_INIT_FAILURE 0x23
+#define GRUB_PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24
+#define GRUB_PXENV_STATUS_BIS_GBOA_FAILURE 0x25
+#define GRUB_PXENV_STATUS_BIS_FREE_FAILURE 0x26
+#define GRUB_PXENV_STATUS_BIS_GSI_FAILURE 0x27
+#define GRUB_PXENV_STATUS_BIS_BAD_CKSUM 0x28
+#define GRUB_PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30
+#define GRUB_PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32
+
+#define GRUB_PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33
+#define GRUB_PXENV_STATUS_TFTP_READ_TIMEOUT 0x35
+#define GRUB_PXENV_STATUS_TFTP_ERROR_OPCODE 0x36
+#define GRUB_PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38
+#define GRUB_PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39
+#define GRUB_PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3A
+#define GRUB_PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3B
+#define GRUB_PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3C
+#define GRUB_PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3D
+#define GRUB_PXENV_STATUS_TFTP_NO_FILESIZE 0x3E
+#define GRUB_PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3F
+#define GRUB_PXENV_STATUS_DHCP_TIMEOUT 0x51
+#define GRUB_PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52
+#define GRUB_PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53
+#define GRUB_PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54
+#define GRUB_PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
+#define GRUB_PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
+#define GRUB_PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
+#define GRUB_PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
+#define GRUB_PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
+#define GRUB_PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
+#define GRUB_PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
+#define GRUB_PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67
+#define GRUB_PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68
+#define GRUB_PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
+#define GRUB_PXENV_STATUS_UNDI_INVALID_STATE 0x6A
+#define GRUB_PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6B
+#define GRUB_PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6C
+#define GRUB_PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74
+#define GRUB_PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76
+#define GRUB_PXENV_STATUS_BSTRAP_MISSING_LIST 0x77
+#define GRUB_PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78
+#define GRUB_PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79
+#define GRUB_PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xA0
+#define GRUB_PXENV_STATUS_BINL_NO_PXE_SERVER 0xA1
+#define GRUB_PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xA2
+#define GRUB_PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xA3
+#define GRUB_PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xB0
+#define GRUB_PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xC0
+#define GRUB_PXENV_STATUS_LOADER_NO_BC_ROMID 0xC1
+#define GRUB_PXENV_STATUS_LOADER_BAD_BC_ROMID 0xC2
+#define GRUB_PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xC3
+#define GRUB_PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xC4
+#define GRUB_PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xC5
+#define GRUB_PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xC6
+#define GRUB_PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xC8
+#define GRUB_PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xC9
+#define GRUB_PXENV_STATUS_LOADER_UNDI_START 0xCA
+#define GRUB_PXENV_STATUS_LOADER_BC_START 0xCB
+
+#define GRUB_PXENV_PACKET_TYPE_DHCP_DISCOVER 1
+#define GRUB_PXENV_PACKET_TYPE_DHCP_ACK 2
+#define GRUB_PXENV_PACKET_TYPE_CACHED_REPLY 3
+
+#define GRUB_PXE_BOOTP_REQ 1
+#define GRUB_PXE_BOOTP_REP 2
+
+#define GRUB_PXE_BOOTP_BCAST 0x8000
+
+#if 1
+#define GRUB_PXE_BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */
+#else
+#define GRUB_PXE_BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */
+#endif
+
+#define GRUB_PXE_MIN_BLKSIZE 512
+#define GRUB_PXE_MAX_BLKSIZE 1432
+
+#define GRUB_PXE_TFTP_PORT 69
+
+#define GRUB_PXE_VM_RFC1048 0x63825363L
+
+#define GRUB_PXE_ERR_LEN 0xFFFFFFFF
+
+#ifndef ASM_FILE
+
+struct grub_pxenv
+{
+ grub_uint8_t signature[6]; /* 'PXENV+' */
+ grub_uint16_t version; /* MSB = major, LSB = minor */
+ grub_uint8_t length; /* structure length */
+ grub_uint8_t checksum; /* checksum pad */
+ grub_uint32_t rm_entry; /* SEG:OFF to PXE entry point */
+ grub_uint32_t pm_offset; /* Protected mode entry */
+ grub_uint16_t pm_selector; /* Protected mode selector */
+ grub_uint16_t stack_seg; /* Stack segment address */
+ grub_uint16_t stack_size; /* Stack segment size (bytes) */
+ grub_uint16_t bc_code_seg; /* BC Code segment address */
+ grub_uint16_t bc_code_size; /* BC Code segment size (bytes) */
+ grub_uint16_t bc_data_seg; /* BC Data segment address */
+ grub_uint16_t bc_data_size; /* BC Data segment size (bytes) */
+ grub_uint16_t undi_data_seg; /* UNDI Data segment address */
+ grub_uint16_t undi_data_size; /* UNDI Data segment size (bytes) */
+ grub_uint16_t undi_code_seg; /* UNDI Code segment address */
+ grub_uint16_t undi_code_size; /* UNDI Code segment size (bytes) */
+ grub_uint32_t pxe_ptr; /* SEG:OFF to !PXE struct */
+} __attribute__ ((packed));
+
+struct grub_pxenv_get_cached_info
+{
+ grub_uint16_t status;
+ grub_uint16_t packet_type;
+ grub_uint16_t buffer_size;
+ grub_uint32_t buffer;
+ grub_uint16_t buffer_limit;
+} __attribute__ ((packed));
+
+#define GRUB_PXE_MAC_ADDR_LEN 16
+
+typedef grub_uint8_t grub_pxe_mac_addr[GRUB_PXE_MAC_ADDR_LEN];
+
+struct grub_pxenv_boot_player
+{
+ grub_uint8_t opcode;
+ grub_uint8_t hw_type; /* hardware type */
+ grub_uint8_t hw_len; /* hardware addr len */
+ grub_uint8_t gate_hops; /* zero it */
+ grub_uint32_t ident; /* random number chosen by client */
+ grub_uint16_t seconds; /* seconds since did initial bootstrap */
+ grub_uint16_t flags;
+ grub_uint32_t client_ip;
+ grub_uint32_t your_ip;
+ grub_uint32_t server_ip;
+ grub_uint32_t gateway_ip;
+ grub_pxe_mac_addr mac_addr;
+ grub_uint8_t server_name[64];
+ grub_uint8_t boot_file[128];
+ union
+ {
+ grub_uint8_t d[GRUB_PXE_BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options */
+ struct
+ {
+ grub_uint32_t magic; /* DHCP magic cookie */
+ grub_uint32_t flags; /* bootp flags/opcodes */
+ grub_uint8_t padding[56];
+ } v;
+ } vendor;
+} __attribute__ ((packed));
+
+struct grub_pxenv_tftp_open
+{
+ grub_uint16_t status;
+ grub_uint32_t server_ip;
+ grub_uint32_t gateway_ip;
+ grub_uint8_t filename[128];
+ grub_uint16_t tftp_port;
+ grub_uint16_t packet_size;
+} __attribute__ ((packed));
+
+struct grub_pxenv_tftp_close
+{
+ grub_uint16_t status;
+} __attribute__ ((packed));
+
+struct grub_pxenv_tftp_read
+{
+ grub_uint16_t status;
+ grub_uint16_t packet_number;
+ grub_uint16_t buffer_size;
+ grub_uint32_t buffer;
+} __attribute__ ((packed));
+
+struct grub_pxenv_tftp_get_fsize
+{
+ grub_uint16_t status;
+ grub_uint32_t server_ip;
+ grub_uint32_t gateway_ip;
+ grub_uint8_t filename[128];
+ grub_uint32_t file_size;
+} __attribute__ ((packed));
+
+struct grub_pxenv_udp_open
+{
+ grub_uint16_t status;
+ grub_uint32_t src_ip;
+} __attribute__ ((packed));
+
+struct grub_pxenv_udp_close
+{
+ grub_uint16_t status;
+} __attribute__ ((packed));
+
+struct grub_pxenv_udp_write
+{
+ grub_uint16_t status;
+ grub_uint32_t ip;
+ grub_uint32_t gateway;
+ grub_uint16_t src_port;
+ grub_uint16_t dst_port;
+ grub_uint16_t buffer_size;
+ grub_uint32_t buffer;
+} __attribute__ ((packed));
+
+struct grub_pxenv_udp_read
+{
+ grub_uint16_t status;
+ grub_uint32_t src_ip;
+ grub_uint32_t dst_ip;
+ grub_uint16_t src_port;
+ grub_uint16_t dst_port;
+ grub_uint16_t buffer_size;
+ grub_uint32_t buffer;
+} __attribute__ ((packed));
+
+struct grub_pxenv_unload_stack
+{
+ grub_uint16_t status;
+ grub_uint8_t reserved[10];
+} __attribute__ ((packed));
+
+struct grub_pxenv * EXPORT_FUNC(grub_pxe_scan) (void);
+int EXPORT_FUNC(grub_pxe_call) (int func, void * data);
+
+extern struct grub_pxenv *grub_pxe_pxenv;
+extern grub_uint32_t grub_pxe_your_ip;
+extern grub_uint32_t grub_pxe_server_ip;
+extern grub_uint32_t grub_pxe_gateway_ip;
+extern int grub_pxe_blksize;
+
+void grub_pxe_unload (void);
+
+#endif
+
+#endif /* GRUB_CPU_PXE_H */
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index e47cbfd..646545e 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -71,14 +71,19 @@ make_install_device (void)
if (grub_root_drive == 0xFF)
grub_root_drive = grub_boot_drive;
- grub_sprintf (dev, "(%cd%u", (grub_root_drive & 0x80) ? 'h' : 'f',
- grub_root_drive & 0x7f);
+ if (grub_root_drive == 0x7F)
+ grub_strcpy (dev, "(pxe");
+ else
+ {
+ grub_sprintf (dev, "(%cd%u", (grub_root_drive & 0x80) ? 'h' : 'f',
+ grub_root_drive & 0x7f);
- if (grub_install_dos_part >= 0)
- grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
+ if (grub_install_dos_part >= 0)
+ grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
- if (grub_install_bsd_part >= 0)
- grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
+ if (grub_install_bsd_part >= 0)
+ grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
+ }
grub_sprintf (dev + grub_strlen (dev), ")%s", grub_prefix);
grub_strcpy (grub_prefix, dev);
diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S
index 75c46ad..679ad1f 100644
--- a/kern/i386/pc/startup.S
+++ b/kern/i386/pc/startup.S
@@ -2053,3 +2053,102 @@ FUNCTION(grub_vbe_bios_set_palette_data)
popl %ebx
popl %ebp
ret
+
+
+pxe_rm_entry:
+ .long 0
+
+/*
+ * struct grub_pxenv *grub_pxe_scan (void);
+ */
+FUNCTION(grub_pxe_scan)
+ pushl %ebp
+ pushl %ebx
+
+ xorl %ebx, %ebx
+ xorl %ecx, %ecx
+
+ call prot_to_real
+ .code16
+
+ pushw %es
+
+ movw $0x5650, %ax
+ int $0x1A
+ cmpw $0x564E, %ax
+ jnz 1f
+ cmpl $0x4E455850, %es:(%bx) /* PXEN(V+) */
+ jnz 1f
+ cmpw $0x201, %es:6(%bx) /* API version */
+ jb 1f
+ lesw %es:0x28(%bx), %bx /* !PXE structure */
+ cmpl $0x45585021, %es:(%bx) /* !PXE */
+ jnz 1f
+ movw %es, %cx
+ jmp 2f
+1:
+ xorw %bx, %bx
+ xorw %cx, %cx
+2:
+
+ popw %es
+
+ DATA32 call real_to_prot
+ .code32
+
+ xorl %eax, %eax
+ leal (%eax, %ecx, 4), %ecx
+ leal (%ebx, %ecx, 4), %eax /* eax = ecx * 16 + ebx */
+
+ orl %eax, %eax
+ jz 1f
+
+ movl 0x10(%eax), %ecx
+ movl %ecx, pxe_rm_entry
+
+1:
+
+ popl %ebx
+ popl %ebp
+ ret
+
+/*
+ * int grub_pxe_call (int func, void* data);
+ */
+FUNCTION(grub_pxe_call)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl %eax, %ecx
+ movl %edx, %eax
+ andl $0xF, %eax
+ shrl $4, %edx
+ shll $16, %edx
+ addl %eax, %edx
+ movl pxe_rm_entry, %ebx
+
+ call prot_to_real
+ .code16
+
+ pushl %ebx
+ pushl %edx
+ pushw %cx
+ movw %sp, %bx
+ lcall *%ss:6(%bx)
+ cld
+ addw $10, %sp
+ movw %ax, %cx
+
+ DATA32 call real_to_prot
+ .code32
+
+ movzwl %cx, %eax
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret