summaryrefslogtreecommitdiff
path: root/gpxe/src/arch/i386/include
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/arch/i386/include')
-rw-r--r--gpxe/src/arch/i386/include/basemem.h33
-rw-r--r--gpxe/src/arch/i386/include/basemem_packet.h13
-rw-r--r--gpxe/src/arch/i386/include/bios.h11
-rw-r--r--gpxe/src/arch/i386/include/bios_disks.h69
-rw-r--r--gpxe/src/arch/i386/include/biosint.h18
-rw-r--r--gpxe/src/arch/i386/include/bits/byteswap.h76
-rw-r--r--gpxe/src/arch/i386/include/bits/cpu.h86
-rw-r--r--gpxe/src/arch/i386/include/bits/elf.h91
-rw-r--r--gpxe/src/arch/i386/include/bits/elf_x.h5
-rw-r--r--gpxe/src/arch/i386/include/bits/eltorito.h3
-rw-r--r--gpxe/src/arch/i386/include/bits/endian.h9
-rw-r--r--gpxe/src/arch/i386/include/bits/errfile.h34
-rw-r--r--gpxe/src/arch/i386/include/bits/stdint.h21
-rw-r--r--gpxe/src/arch/i386/include/bits/string.h252
-rw-r--r--gpxe/src/arch/i386/include/bits/timer2.h8
-rw-r--r--gpxe/src/arch/i386/include/bits/uaccess.h6
-rw-r--r--gpxe/src/arch/i386/include/bits/uuid.h10
-rw-r--r--gpxe/src/arch/i386/include/bochs.h34
-rw-r--r--gpxe/src/arch/i386/include/bootsector.h12
-rw-r--r--gpxe/src/arch/i386/include/bzimage.h129
-rw-r--r--gpxe/src/arch/i386/include/callbacks_arch.h243
-rw-r--r--gpxe/src/arch/i386/include/gateA20.h7
-rw-r--r--gpxe/src/arch/i386/include/int13.h277
-rw-r--r--gpxe/src/arch/i386/include/io.h265
-rw-r--r--gpxe/src/arch/i386/include/kir.h18
-rw-r--r--gpxe/src/arch/i386/include/libkir.h233
-rw-r--r--gpxe/src/arch/i386/include/librm.h289
-rw-r--r--gpxe/src/arch/i386/include/limits.h59
-rw-r--r--gpxe/src/arch/i386/include/memsizes.h17
-rw-r--r--gpxe/src/arch/i386/include/multiboot.h147
-rw-r--r--gpxe/src/arch/i386/include/pci_io.h35
-rw-r--r--gpxe/src/arch/i386/include/pcibios.h122
-rw-r--r--gpxe/src/arch/i386/include/pcidirect.h126
-rw-r--r--gpxe/src/arch/i386/include/pic8259.h69
-rw-r--r--gpxe/src/arch/i386/include/pnpbios.h15
-rw-r--r--gpxe/src/arch/i386/include/pxe_addr.h17
-rw-r--r--gpxe/src/arch/i386/include/pxe_call.h34
-rw-r--r--gpxe/src/arch/i386/include/realmode.h128
-rw-r--r--gpxe/src/arch/i386/include/registers.h187
-rw-r--r--gpxe/src/arch/i386/include/setjmp.h12
-rw-r--r--gpxe/src/arch/i386/include/smbios.h51
-rw-r--r--gpxe/src/arch/i386/include/undi.h102
-rw-r--r--gpxe/src/arch/i386/include/undiload.h33
-rw-r--r--gpxe/src/arch/i386/include/undinet.h15
-rw-r--r--gpxe/src/arch/i386/include/undipreload.h16
-rw-r--r--gpxe/src/arch/i386/include/undirom.h51
-rw-r--r--gpxe/src/arch/i386/include/vga.h228
-rw-r--r--gpxe/src/arch/i386/include/virtaddr.h105
48 files changed, 3821 insertions, 0 deletions
diff --git a/gpxe/src/arch/i386/include/basemem.h b/gpxe/src/arch/i386/include/basemem.h
new file mode 100644
index 00000000..cd5668e0
--- /dev/null
+++ b/gpxe/src/arch/i386/include/basemem.h
@@ -0,0 +1,33 @@
+#ifndef _BASEMEM_H
+#define _BASEMEM_H
+
+/** @file
+ *
+ * Base memory allocation
+ *
+ */
+
+#include <stdint.h>
+#include <realmode.h>
+#include <bios.h>
+
+/**
+ * Read the BIOS free base memory counter
+ *
+ * @ret fbms Free base memory counter (in kB)
+ */
+static inline unsigned int get_fbms ( void ) {
+ uint16_t fbms;
+
+ get_real ( fbms, BDA_SEG, BDA_FBMS );
+ return fbms;
+}
+
+extern void set_fbms ( unsigned int new_fbms );
+
+/* Actually in hidemem.c, but putting it here avoids polluting the
+ * architecture-independent include/hidemem.h.
+ */
+extern void hide_basemem ( void );
+
+#endif /* _BASEMEM_H */
diff --git a/gpxe/src/arch/i386/include/basemem_packet.h b/gpxe/src/arch/i386/include/basemem_packet.h
new file mode 100644
index 00000000..e4d4f49c
--- /dev/null
+++ b/gpxe/src/arch/i386/include/basemem_packet.h
@@ -0,0 +1,13 @@
+#ifndef BASEMEM_PACKET_H
+#define BASEMEM_PACKET_H
+
+#include <realmode.h>
+
+/** Maximum length of base memory packet buffer */
+#define BASEMEM_PACKET_LEN 1514
+
+/** Base memory packet buffer */
+extern char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] );
+#define basemem_packet __use_data16 ( basemem_packet )
+
+#endif /* BASEMEM_PACKET_H */
diff --git a/gpxe/src/arch/i386/include/bios.h b/gpxe/src/arch/i386/include/bios.h
new file mode 100644
index 00000000..630a898b
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bios.h
@@ -0,0 +1,11 @@
+#ifndef BIOS_H
+#define BIOS_H
+
+#define BDA_SEG 0x0040
+#define BDA_FBMS 0x0013
+#define BDA_NUM_DRIVES 0x0075
+
+extern unsigned long currticks ( void );
+extern void cpu_nap ( void );
+
+#endif /* BIOS_H */
diff --git a/gpxe/src/arch/i386/include/bios_disks.h b/gpxe/src/arch/i386/include/bios_disks.h
new file mode 100644
index 00000000..0dd7c4eb
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bios_disks.h
@@ -0,0 +1,69 @@
+#ifndef BIOS_DISKS_H
+#define BIOS_DISKS_H
+
+#include "dev.h"
+
+/*
+ * Constants
+ *
+ */
+
+#define BIOS_DISK_MAX_NAME_LEN 6
+
+struct bios_disk_sector {
+ char data[512];
+};
+
+/*
+ * The location of a BIOS disk
+ *
+ */
+struct bios_disk_loc {
+ uint8_t drive;
+};
+
+/*
+ * A physical BIOS disk device
+ *
+ */
+struct bios_disk_device {
+ char name[BIOS_DISK_MAX_NAME_LEN];
+ uint8_t drive;
+ uint8_t type;
+};
+
+/*
+ * A BIOS disk driver, with a valid device ID range and naming
+ * function.
+ *
+ */
+struct bios_disk_driver {
+ void ( *fill_drive_name ) ( char *buf, uint8_t drive );
+ uint8_t min_drive;
+ uint8_t max_drive;
+};
+
+/*
+ * Define a BIOS disk driver
+ *
+ */
+#define BIOS_DISK_DRIVER( _name, _fill_drive_name, _min_drive, _max_drive ) \
+ static struct bios_disk_driver _name = { \
+ .fill_drive_name = _fill_drive_name, \
+ .min_drive = _min_drive, \
+ .max_drive = _max_drive, \
+ }
+
+/*
+ * Functions in bios_disks.c
+ *
+ */
+
+
+/*
+ * bios_disk bus global definition
+ *
+ */
+extern struct bus_driver bios_disk_driver;
+
+#endif /* BIOS_DISKS_H */
diff --git a/gpxe/src/arch/i386/include/biosint.h b/gpxe/src/arch/i386/include/biosint.h
new file mode 100644
index 00000000..d4e34963
--- /dev/null
+++ b/gpxe/src/arch/i386/include/biosint.h
@@ -0,0 +1,18 @@
+#ifndef BIOSINT_H
+#define BIOSINT_H
+
+/**
+ * @file BIOS interrupts
+ *
+ */
+
+struct segoff;
+
+extern int hooked_bios_interrupts;
+extern void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
+ struct segoff *chain_vector );
+extern int unhook_bios_interrupt ( unsigned int interrupt,
+ unsigned int handler,
+ struct segoff *chain_vector );
+
+#endif /* BIOSINT_H */
diff --git a/gpxe/src/arch/i386/include/bits/byteswap.h b/gpxe/src/arch/i386/include/bits/byteswap.h
new file mode 100644
index 00000000..54b93ab9
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/byteswap.h
@@ -0,0 +1,76 @@
+#ifndef ETHERBOOT_BITS_BYTESWAP_H
+#define ETHERBOOT_BITS_BYTESWAP_H
+
+static inline __attribute__ ((always_inline, const)) uint16_t
+__i386_bswap_16(uint16_t x)
+{
+ __asm__("xchgb %b0,%h0\n\t"
+ : "=q" (x)
+ : "0" (x));
+ return x;
+}
+
+static inline __attribute__ ((always_inline, const)) uint32_t
+__i386_bswap_32(uint32_t x)
+{
+ __asm__("xchgb %b0,%h0\n\t"
+ "rorl $16,%0\n\t"
+ "xchgb %b0,%h0"
+ : "=q" (x)
+ : "0" (x));
+ return x;
+}
+
+static inline __attribute__ ((always_inline, const)) uint64_t
+__i386_bswap_64(uint64_t x)
+{
+ union {
+ uint64_t qword;
+ uint32_t dword[2];
+ } u;
+
+ u.qword = x;
+ u.dword[0] = __i386_bswap_32(u.dword[0]);
+ u.dword[1] = __i386_bswap_32(u.dword[1]);
+ __asm__("xchgl %0,%1"
+ : "=r" ( u.dword[0] ), "=r" ( u.dword[1] )
+ : "0" ( u.dword[0] ), "1" ( u.dword[1] ) );
+ return u.qword;
+}
+
+#define __bswap_constant_16(x) \
+ ((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
+ (((uint16_t)(x) & 0xff00) >> 8)))
+
+#define __bswap_constant_32(x) \
+ ((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
+ (((uint32_t)(x) & 0x0000ff00U) << 8) | \
+ (((uint32_t)(x) & 0x00ff0000U) >> 8) | \
+ (((uint32_t)(x) & 0xff000000U) >> 24)))
+
+#define __bswap_constant_64(x) \
+ ((uint64_t)((((uint64_t)(x) & 0x00000000000000ffULL) << 56) | \
+ (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & 0xff00000000000000ULL) >> 56)))
+
+#define __bswap_16(x) \
+ ((uint16_t)(__builtin_constant_p(x) ? \
+ __bswap_constant_16(x) : \
+ __i386_bswap_16(x)))
+
+#define __bswap_32(x) \
+ ((uint32_t)(__builtin_constant_p(x) ? \
+ __bswap_constant_32(x) : \
+ __i386_bswap_32(x)))
+
+#define __bswap_64(x) \
+ ((uint64_t)(__builtin_constant_p(x) ? \
+ __bswap_constant_64(x) : \
+ __i386_bswap_64(x)))
+
+#endif /* ETHERBOOT_BITS_BYTESWAP_H */
diff --git a/gpxe/src/arch/i386/include/bits/cpu.h b/gpxe/src/arch/i386/include/bits/cpu.h
new file mode 100644
index 00000000..83339ddd
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/cpu.h
@@ -0,0 +1,86 @@
+#ifndef I386_BITS_CPU_H
+#define I386_BITS_CPU_H
+
+/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
+#define X86_FEATURE_FPU 0 /* Onboard FPU */
+#define X86_FEATURE_VME 1 /* Virtual Mode Extensions */
+#define X86_FEATURE_DE 2 /* Debugging Extensions */
+#define X86_FEATURE_PSE 3 /* Page Size Extensions */
+#define X86_FEATURE_TSC 4 /* Time Stamp Counter */
+#define X86_FEATURE_MSR 5 /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_PAE 6 /* Physical Address Extensions */
+#define X86_FEATURE_MCE 7 /* Machine Check Architecture */
+#define X86_FEATURE_CX8 8 /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC 9 /* Onboard APIC */
+#define X86_FEATURE_SEP 11 /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR 12 /* Memory Type Range Registers */
+#define X86_FEATURE_PGE 13 /* Page Global Enable */
+#define X86_FEATURE_MCA 14 /* Machine Check Architecture */
+#define X86_FEATURE_CMOV 15 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_PAT 16 /* Page Attribute Table */
+#define X86_FEATURE_PSE36 17 /* 36-bit PSEs */
+#define X86_FEATURE_PN 18 /* Processor serial number */
+#define X86_FEATURE_CLFLSH 19 /* Supports the CLFLUSH instruction */
+#define X86_FEATURE_DTES 21 /* Debug Trace Store */
+#define X86_FEATURE_ACPI 22 /* ACPI via MSR */
+#define X86_FEATURE_MMX 23 /* Multimedia Extensions */
+#define X86_FEATURE_FXSR 24 /* FXSAVE and FXRSTOR instructions (fast save and restore */
+ /* of FPU context), and CR4.OSFXSR available */
+#define X86_FEATURE_XMM 25 /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2 26 /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_SELFSNOOP 27 /* CPU self snoop */
+#define X86_FEATURE_HT 28 /* Hyper-Threading */
+#define X86_FEATURE_ACC 29 /* Automatic clock control */
+#define X86_FEATURE_IA64 30 /* IA-64 processor */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL 11 /* SYSCALL/SYSRET */
+#define X86_FEATURE_MMXEXT 22 /* AMD MMX extensions */
+#define X86_FEATURE_LM 29 /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT 30 /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW 31 /* 3DNow! */
+
+/** x86 CPU information */
+struct cpuinfo_x86 {
+ /** CPU features */
+ unsigned int features;
+ /** 64-bit CPU features */
+ unsigned int amd_features;
+};
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
+/*
+ * Generic CPUID function
+ */
+static inline __attribute__ (( always_inline )) void
+cpuid ( int op, unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx ) {
+ __asm__ ( "cpuid" :
+ "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
+ : "0" ( op ) );
+}
+
+extern void get_cpuinfo ( struct cpuinfo_x86 *cpu );
+
+#endif /* I386_BITS_CPU_H */
diff --git a/gpxe/src/arch/i386/include/bits/elf.h b/gpxe/src/arch/i386/include/bits/elf.h
new file mode 100644
index 00000000..dad9c7b8
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/elf.h
@@ -0,0 +1,91 @@
+#ifndef I386_BITS_ELF_H
+#define I386_BITS_ELF_H
+
+#include "cpu.h"
+
+#ifdef CONFIG_X86_64
+/* ELF Defines for the 64bit version of the current architecture */
+#define EM_CURRENT_64 EM_X86_64
+#define EM_CURRENT_64_PRESENT ( \
+ CPU_FEATURE_P(cpu_info.x86_capability, LM) && \
+ CPU_FEATURE_P(cpu_info.x86_capability, PAE) && \
+ CPU_FEATURE_P(cpu_info.x86_capability, PSE))
+
+#define ELF_CHECK_X86_64_ARCH(x) \
+ (EM_CURRENT_64_PRESENT && ((x).e_machine == EM_X86_64))
+#define __unused_i386
+#else
+#define ELF_CHECK_X86_64_ARCH(x) 0
+#define __unused_i386 __unused
+#endif
+
+
+/* ELF Defines for the current architecture */
+#define EM_CURRENT EM_386
+#define ELFDATA_CURRENT ELFDATA2LSB
+
+#define ELF_CHECK_I386_ARCH(x) \
+ (((x).e_machine == EM_386) || ((x).e_machine == EM_486))
+
+#define ELF_CHECK_ARCH(x) \
+ ((ELF_CHECK_I386_ARCH(x) || ELF_CHECK_X86_64_ARCH(x)) && \
+ ((x).e_entry <= 0xffffffffUL))
+
+#ifdef IMAGE_FREEBSD
+/*
+ * FreeBSD has this rather strange "feature" of its design.
+ * At some point in its evolution, FreeBSD started to rely
+ * externally on private/static/debug internal symbol information.
+ * That is, some of the interfaces that software uses to access
+ * and work with the FreeBSD kernel are made available not
+ * via the shared library symbol information (the .DYNAMIC section)
+ * but rather the debug symbols. This means that any symbol, not
+ * just publicly defined symbols can be (and are) used by system
+ * tools to make the system work. (such as top, swapinfo, swapon,
+ * etc)
+ *
+ * Even worse, however, is the fact that standard ELF loaders do
+ * not know how to load the symbols since they are not within
+ * an ELF PT_LOAD section. The kernel needs these symbols to
+ * operate so the following changes/additions to the boot
+ * loading of EtherBoot have been made to get the kernel to load.
+ * All of the changes are within IMAGE_FREEBSD such that the
+ * extra/changed code only compiles when FREEBSD support is
+ * enabled.
+ */
+
+/*
+ * Section header for FreeBSD (debug symbol kludge!) support
+ */
+typedef struct {
+ Elf32_Word sh_name; /* Section name (index into the
+ section header string table). */
+ Elf32_Word sh_type; /* Section type. */
+ Elf32_Word sh_flags; /* Section flags. */
+ Elf32_Addr sh_addr; /* Address in memory image. */
+ Elf32_Off sh_offset; /* Offset in file. */
+ Elf32_Size sh_size; /* Size in bytes. */
+ Elf32_Word sh_link; /* Index of a related section. */
+ Elf32_Word sh_info; /* Depends on section type. */
+ Elf32_Size sh_addralign; /* Alignment in bytes. */
+ Elf32_Size sh_entsize; /* Size of each entry in section. */
+} Elf32_Shdr;
+
+/* sh_type */
+#define SHT_SYMTAB 2 /* symbol table section */
+#define SHT_STRTAB 3 /* string table section */
+
+/*
+ * Module information subtypes (for the metadata that we need to build)
+ */
+#define MODINFO_END 0x0000 /* End of list */
+#define MODINFO_NAME 0x0001 /* Name of module (string) */
+#define MODINFO_TYPE 0x0002 /* Type of module (string) */
+#define MODINFO_METADATA 0x8000 /* Module-specfic */
+
+#define MODINFOMD_SSYM 0x0003 /* start of symbols */
+#define MODINFOMD_ESYM 0x0004 /* end of symbols */
+
+#endif /* IMAGE_FREEBSD */
+
+#endif /* I386_BITS_ELF_H */
diff --git a/gpxe/src/arch/i386/include/bits/elf_x.h b/gpxe/src/arch/i386/include/bits/elf_x.h
new file mode 100644
index 00000000..86c67250
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/elf_x.h
@@ -0,0 +1,5 @@
+#define ARCH_ELF_CLASS ELFCLASS32
+#define ARCH_ELF_DATA ELFDATA2LSB
+#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486)
+typedef Elf32_Ehdr Elf_ehdr;
+typedef Elf32_Phdr Elf_phdr;
diff --git a/gpxe/src/arch/i386/include/bits/eltorito.h b/gpxe/src/arch/i386/include/bits/eltorito.h
new file mode 100644
index 00000000..d43e9aac
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/eltorito.h
@@ -0,0 +1,3 @@
+#ifndef ELTORITO_PLATFORM
+#define ELTORITO_PLATFORM ELTORITO_PLATFORM_X86
+#endif /* ELTORITO_PLATFORM */
diff --git a/gpxe/src/arch/i386/include/bits/endian.h b/gpxe/src/arch/i386/include/bits/endian.h
new file mode 100644
index 00000000..b23b233a
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/endian.h
@@ -0,0 +1,9 @@
+#ifndef ETHERBOOT_BITS_ENDIAN_H
+#define ETHERBOOT_BITS_ENDIAN_H
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#define le32_to_cpup(x) (*(uint32_t *)(x))
+#define cpu_to_le16p(x) (*(uint16_t*)(x))
+
+#endif /* ETHERBOOT_BITS_ENDIAN_H */
diff --git a/gpxe/src/arch/i386/include/bits/errfile.h b/gpxe/src/arch/i386/include/bits/errfile.h
new file mode 100644
index 00000000..0f140214
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/errfile.h
@@ -0,0 +1,34 @@
+#ifndef _BITS_ERRFILE_H
+#define _BITS_ERRFILE_H
+
+/**
+ * @addtogroup errfile Error file identifiers
+ * @{
+ */
+
+#define ERRFILE_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
+#define ERRFILE_memmap ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 )
+#define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 )
+#define ERRFILE_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
+#define ERRFILE_biosint ( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 )
+#define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
+
+#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
+#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
+#define ERRFILE_eltorito ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00020000 )
+#define ERRFILE_multiboot ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00030000 )
+#define ERRFILE_nbi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00040000 )
+#define ERRFILE_pxe_image ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00050000 )
+
+#define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
+#define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
+#define ERRFILE_undinet ( ERRFILE_ARCH | ERRFILE_NET | 0x00020000 )
+#define ERRFILE_undionly ( ERRFILE_ARCH | ERRFILE_NET | 0x00030000 )
+#define ERRFILE_undirom ( ERRFILE_ARCH | ERRFILE_NET | 0x00040000 )
+
+#define ERRFILE_timer_rdtsc ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
+#define ERRFILE_timer_bios ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
+
+/** @} */
+
+#endif /* _BITS_ERRFILE_H */
diff --git a/gpxe/src/arch/i386/include/bits/stdint.h b/gpxe/src/arch/i386/include/bits/stdint.h
new file mode 100644
index 00000000..a2947cda
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/stdint.h
@@ -0,0 +1,21 @@
+#ifndef _BITS_STDINT_H
+#define _BITS_STDINT_H
+
+typedef typeof(sizeof(int)) size_t;
+typedef signed long ssize_t;
+typedef signed long off_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed long int32_t;
+typedef signed long long int64_t;
+
+typedef unsigned long physaddr_t;
+typedef unsigned long intptr_t;
+
+#endif /* _BITS_STDINT_H */
diff --git a/gpxe/src/arch/i386/include/bits/string.h b/gpxe/src/arch/i386/include/bits/string.h
new file mode 100644
index 00000000..c05a7df8
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/string.h
@@ -0,0 +1,252 @@
+#ifndef ETHERBOOT_BITS_STRING_H
+#define ETHERBOOT_BITS_STRING_H
+/*
+ * Taken from Linux /usr/include/asm/string.h
+ * All except memcpy, memmove, memset and memcmp removed.
+ *
+ * Non-standard memswap() function added because it saves quite a bit
+ * of code (mbrown@fensystems.co.uk).
+ */
+
+/*
+ * This string-include defines all string functions as inline
+ * functions. Use gcc. It also assumes ds=es=data space, this should be
+ * normal. Most of the string-functions are rather heavily hand-optimized,
+ * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ * NO Copyright (C) 1991, 1992 Linus Torvalds,
+ * consider these trivial functions to be PD.
+ */
+
+#define __HAVE_ARCH_MEMCPY
+
+extern __attribute__ (( regparm ( 3 ) )) void * __memcpy ( void *dest,
+ const void *src,
+ size_t len );
+
+#if 0
+static inline __attribute__ (( always_inline )) void *
+__memcpy ( void *dest, const void *src, size_t len ) {
+ int d0, d1, d2;
+ __asm__ __volatile__ ( "rep ; movsb"
+ : "=&c" ( d0 ), "=&S" ( d1 ), "=&D" ( d2 )
+ : "0" ( len ), "1" ( src ), "2" ( dest )
+ : "memory" );
+ return dest;
+}
+#endif
+
+static inline __attribute__ (( always_inline )) void *
+__constant_memcpy ( void *dest, const void *src, size_t len ) {
+ union {
+ uint32_t u32[2];
+ uint16_t u16[4];
+ uint8_t u8[8];
+ } __attribute__ (( __may_alias__ )) *dest_u = dest;
+ const union {
+ uint32_t u32[2];
+ uint16_t u16[4];
+ uint8_t u8[8];
+ } __attribute__ (( __may_alias__ )) *src_u = src;
+ const void *esi;
+ void *edi;
+
+ switch ( len ) {
+ case 0 : /* 0 bytes */
+ return dest;
+ /*
+ * Single-register moves; these are always better than a
+ * string operation. We can clobber an arbitrary two
+ * registers (data, source, dest can re-use source register)
+ * instead of being restricted to esi and edi. There's also a
+ * much greater potential for optimising with nearby code.
+ *
+ */
+ case 1 : /* 4 bytes */
+ dest_u->u8[0] = src_u->u8[0];
+ return dest;
+ case 2 : /* 6 bytes */
+ dest_u->u16[0] = src_u->u16[0];
+ return dest;
+ case 4 : /* 4 bytes */
+ dest_u->u32[0] = src_u->u32[0];
+ return dest;
+ /*
+ * Double-register moves; these are probably still a win.
+ *
+ */
+ case 3 : /* 12 bytes */
+ dest_u->u16[0] = src_u->u16[0];
+ dest_u->u8[2] = src_u->u8[2];
+ return dest;
+ case 5 : /* 10 bytes */
+ dest_u->u32[0] = src_u->u32[0];
+ dest_u->u8[4] = src_u->u8[4];
+ return dest;
+ case 6 : /* 12 bytes */
+ dest_u->u32[0] = src_u->u32[0];
+ dest_u->u16[2] = src_u->u16[2];
+ return dest;
+ case 8 : /* 10 bytes */
+ dest_u->u32[0] = src_u->u32[0];
+ dest_u->u32[1] = src_u->u32[1];
+ return dest;
+ }
+
+ /* Even if we have to load up esi and edi ready for a string
+ * operation, we can sometimes save space by using multiple
+ * single-byte "movs" operations instead of loading up ecx and
+ * using "rep movsb".
+ *
+ * "load ecx, rep movsb" is 7 bytes, plus an average of 1 byte
+ * to allow for saving/restoring ecx 50% of the time.
+ *
+ * "movsl" and "movsb" are 1 byte each, "movsw" is two bytes.
+ * (In 16-bit mode, "movsl" is 2 bytes and "movsw" is 1 byte,
+ * but "movsl" moves twice as much data, so it balances out).
+ *
+ * The cutoff point therefore occurs around 26 bytes; the byte
+ * requirements for each method are:
+ *
+ * len 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ * #bytes (ecx) 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
+ * #bytes (no ecx) 4 5 6 7 5 6 7 8 6 7 8 9 7 8 9 10
+ */
+
+ esi = src;
+ edi = dest;
+
+ if ( len >= 26 )
+ return __memcpy ( dest, src, len );
+
+ if ( len >= 6*4 )
+ __asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+ if ( len >= 5*4 )
+ __asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+ if ( len >= 4*4 )
+ __asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+ if ( len >= 3*4 )
+ __asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+ if ( len >= 2*4 )
+ __asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+ if ( len >= 1*4 )
+ __asm__ __volatile__ ( "movsl" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+ if ( ( len % 4 ) >= 2 )
+ __asm__ __volatile__ ( "movsw" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+ if ( ( len % 2 ) >= 1 )
+ __asm__ __volatile__ ( "movsb" : "=&D" ( edi ), "=&S" ( esi )
+ : "0" ( edi ), "1" ( esi ) : "memory" );
+
+ return dest;
+}
+
+#define memcpy( dest, src, len ) \
+ ( __builtin_constant_p ( (len) ) ? \
+ __constant_memcpy ( (dest), (src), (len) ) : \
+ __memcpy ( (dest), (src), (len) ) )
+
+#define __HAVE_ARCH_MEMMOVE
+static inline void * memmove(void * dest,const void * src, size_t n)
+{
+int d0, d1, d2;
+if (dest<src)
+__asm__ __volatile__(
+ "cld\n\t"
+ "rep\n\t"
+ "movsb"
+ : "=&c" (d0), "=&S" (d1), "=&D" (d2)
+ :"0" (n),"1" (src),"2" (dest)
+ : "memory");
+else
+__asm__ __volatile__(
+ "std\n\t"
+ "rep\n\t"
+ "movsb\n\t"
+ "cld"
+ : "=&c" (d0), "=&S" (d1), "=&D" (d2)
+ :"0" (n),
+ "1" (n-1+(const char *)src),
+ "2" (n-1+(char *)dest)
+ :"memory");
+return dest;
+}
+
+#define __HAVE_ARCH_MEMSET
+static inline void * memset(void *s, int c,size_t count)
+{
+int d0, d1;
+__asm__ __volatile__(
+ "cld\n\t"
+ "rep\n\t"
+ "stosb"
+ : "=&c" (d0), "=&D" (d1)
+ :"a" (c),"1" (s),"0" (count)
+ :"memory");
+return s;
+}
+
+#define __HAVE_ARCH_MEMSWAP
+static inline void * memswap(void *dest, void *src, size_t n)
+{
+int d0, d1, d2, d3;
+__asm__ __volatile__(
+ "\n1:\t"
+ "movb (%%edi),%%al\n\t"
+ "xchgb (%%esi),%%al\n\t"
+ "incl %%esi\n\t"
+ "stosb\n\t"
+ "loop 1b"
+ : "=&c" (d0), "=&S" (d1), "=&D" (d2), "=&a" (d3)
+ : "0" (n), "1" (src), "2" (dest)
+ : "memory" );
+return dest;
+}
+
+#define __HAVE_ARCH_STRNCMP
+static inline int strncmp(const char * cs,const char * ct,size_t count)
+{
+register int __res;
+int d0, d1, d2;
+__asm__ __volatile__(
+ "1:\tdecl %3\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "scasb\n\t"
+ "jne 3f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n"
+ "2:\txorl %%eax,%%eax\n\t"
+ "jmp 4f\n"
+ "3:\tsbbl %%eax,%%eax\n\t"
+ "orb $1,%%al\n"
+ "4:"
+ :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+ :"1" (cs),"2" (ct),"3" (count));
+return __res;
+}
+
+#define __HAVE_ARCH_STRLEN
+static inline size_t strlen(const char * s)
+{
+int d0;
+register int __res;
+__asm__ __volatile__(
+ "repne\n\t"
+ "scasb\n\t"
+ "notl %0\n\t"
+ "decl %0"
+ :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
+return __res;
+}
+
+#endif /* ETHERBOOT_BITS_STRING_H */
diff --git a/gpxe/src/arch/i386/include/bits/timer2.h b/gpxe/src/arch/i386/include/bits/timer2.h
new file mode 100644
index 00000000..83923b29
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/timer2.h
@@ -0,0 +1,8 @@
+#ifndef BITS_TIMER2_H
+#define BITS_TIMER2_H
+
+#include <stddef.h>
+
+void i386_timer2_udelay(unsigned int usecs);
+
+#endif
diff --git a/gpxe/src/arch/i386/include/bits/uaccess.h b/gpxe/src/arch/i386/include/bits/uaccess.h
new file mode 100644
index 00000000..9c6d0c21
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/uaccess.h
@@ -0,0 +1,6 @@
+#ifndef _BITS_UACCESS_H
+#define _BITS_UACCESS_H
+
+#include <realmode.h>
+
+#endif /* _BITS_UACCESS_H */
diff --git a/gpxe/src/arch/i386/include/bits/uuid.h b/gpxe/src/arch/i386/include/bits/uuid.h
new file mode 100644
index 00000000..0cbd320a
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/uuid.h
@@ -0,0 +1,10 @@
+#ifndef _I386_UUID_H
+#define _I386_UUID_H
+
+#include <smbios.h>
+
+static inline int get_uuid ( union uuid *uuid ) {
+ return smbios_get_uuid ( uuid );
+}
+
+#endif /* _I386_UUID_H */
diff --git a/gpxe/src/arch/i386/include/bochs.h b/gpxe/src/arch/i386/include/bochs.h
new file mode 100644
index 00000000..9d090fc1
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bochs.h
@@ -0,0 +1,34 @@
+#ifndef BOCHS_H
+#define BOCHS_H
+
+/** @file
+ *
+ * bochs breakpoints
+ *
+ * This file defines @c bochsbp, the magic breakpoint instruction that
+ * is incredibly useful when debugging under bochs. This file should
+ * never be included in production code.
+ *
+ * Use the pseudo-instruction @c bochsbp in assembly code, or the
+ * bochsbp() function in C code.
+ *
+ */
+
+#ifdef ASSEMBLY
+
+/* Breakpoint for when debugging under bochs */
+#define bochsbp xchgw %bx, %bx
+#define BOCHSBP bochsbp
+
+#else /* ASSEMBLY */
+
+/** Breakpoint for when debugging under bochs */
+static inline void bochsbp ( void ) {
+ __asm__ __volatile__ ( "xchgw %bx, %bx" );
+}
+
+#endif /* ASSEMBLY */
+
+#warning "bochs.h should not be included into production code"
+
+#endif /* BOCHS_H */
diff --git a/gpxe/src/arch/i386/include/bootsector.h b/gpxe/src/arch/i386/include/bootsector.h
new file mode 100644
index 00000000..e9071052
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bootsector.h
@@ -0,0 +1,12 @@
+#ifndef _BOOTSECTOR_H
+#define _BOOTSECTOR_H
+
+/** @file
+ *
+ * x86 bootsector image format
+ */
+
+extern int call_bootsector ( unsigned int segment, unsigned int offset,
+ unsigned int drive );
+
+#endif /* _BOOTSECTOR_H */
diff --git a/gpxe/src/arch/i386/include/bzimage.h b/gpxe/src/arch/i386/include/bzimage.h
new file mode 100644
index 00000000..609e8362
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bzimage.h
@@ -0,0 +1,129 @@
+#ifndef _BZIMAGE_H
+#define _BZIMAGE_H
+
+#include <stdint.h>
+
+/**
+ * A bzImage header
+ *
+ * As documented in Documentation/i386/boot.txt
+ */
+struct bzimage_header {
+ /** The size of the setup in sectors
+ *
+ * If this field contains 0, assume it contains 4.
+ */
+ uint8_t setup_sects;
+ /** If set, the root is mounted readonly */
+ uint16_t root_flags;
+ /** DO NOT USE - for bootsect.S use only */
+ uint16_t syssize;
+ /** DO NOT USE - obsolete */
+ uint16_t swap_dev;
+ /** DO NOT USE - for bootsect.S use only */
+ uint16_t ram_size;
+ /** Video mode control */
+ uint16_t vid_mode;
+ /** Default root device number */
+ uint16_t root_dev;
+ /** 0xAA55 magic number */
+ uint16_t boot_flag;
+ /** Jump instruction */
+ uint16_t jump;
+ /** Magic signature "HdrS" */
+ uint32_t header;
+ /** Boot protocol version supported */
+ uint16_t version;
+ /** Boot loader hook (see below) */
+ uint32_t realmode_swtch;
+ /** The load-low segment (0x1000) (obsolete) */
+ uint16_t start_sys;
+ /** Pointer to kernel version string */
+ uint16_t kernel_version;
+ /** Boot loader identifier */
+ uint8_t type_of_loader;
+ /** Boot protocol option flags */
+ uint8_t loadflags;
+ /** Move to high memory size (used with hooks) */
+ uint16_t setup_move_size;
+ /** Boot loader hook (see below) */
+ uint32_t code32_start;
+ /** initrd load address (set by boot loader) */
+ uint32_t ramdisk_image;
+ /** initrd size (set by boot loader) */
+ uint32_t ramdisk_size;
+ /** DO NOT USE - for bootsect.S use only */
+ uint32_t bootsect_kludge;
+ /** Free memory after setup end */
+ uint16_t heap_end_ptr;
+ /** Unused */
+ uint16_t pad1;
+ /** 32-bit pointer to the kernel command line */
+ uint32_t cmd_line_ptr;
+ /** Highest legal initrd address */
+ uint32_t initrd_addr_max;
+} __attribute__ (( packed ));
+
+/** Offset of bzImage header within kernel image */
+#define BZI_HDR_OFFSET 0x1f1
+
+/** bzImage magic signature value */
+#define BZI_SIGNATURE 0x53726448
+
+/** bzImage boot loader identifier for Etherboot */
+#define BZI_LOADER_TYPE_ETHERBOOT 0x40
+
+/** bzImage boot loader identifier for gPXE
+ *
+ * We advertise ourselves as Etherboot version 6.
+ */
+#define BZI_LOADER_TYPE_GPXE ( BZI_LOADER_TYPE_ETHERBOOT | 0x06 )
+
+/** bzImage "load high" flag */
+#define BZI_LOAD_HIGH 0x01
+
+/** Load address for high-loaded kernels */
+#define BZI_LOAD_HIGH_ADDR 0x100000
+
+/** Load address for low-loaded kernels */
+#define BZI_LOAD_LOW_ADDR 0x10000
+
+/** bzImage "kernel can use heap" flag */
+#define BZI_CAN_USE_HEAP 0x80
+
+/** bzImage special video mode "normal" */
+#define BZI_VID_MODE_NORMAL 0xffff
+
+/** bzImage special video mode "ext" */
+#define BZI_VID_MODE_EXT 0xfffe
+
+/** bzImage special video mode "ask" */
+#define BZI_VID_MODE_ASK 0xfffd
+
+/** bzImage maximum initrd address for versions < 2.03 */
+#define BZI_INITRD_MAX 0x37ffffff
+
+/** bzImage command-line structure used by older kernels */
+struct bzimage_cmdline {
+ /** Magic signature */
+ uint16_t magic;
+ /** Offset to command line */
+ uint16_t offset;
+} __attribute__ (( packed ));
+
+/** Offset of bzImage command-line structure within kernel image */
+#define BZI_CMDLINE_OFFSET 0x20
+
+/** bzImage command line present magic marker value */
+#define BZI_CMDLINE_MAGIC 0xa33f
+
+/** Assumed size of real-mode portion (including .bss) */
+#define BZI_ASSUMED_RM_SIZE 0x8000
+
+/** Amount of stack space to provide */
+#define BZI_STACK_SIZE 0x1000
+
+/** Maximum size of command line */
+#define BZI_CMDLINE_SIZE 0x100
+
+#endif /* _BZIMAGE_H */
diff --git a/gpxe/src/arch/i386/include/callbacks_arch.h b/gpxe/src/arch/i386/include/callbacks_arch.h
new file mode 100644
index 00000000..f9cba488
--- /dev/null
+++ b/gpxe/src/arch/i386/include/callbacks_arch.h
@@ -0,0 +1,243 @@
+/* Callout/callback interface for Etherboot
+ *
+ * This file provides the mechanisms for making calls from Etherboot
+ * to external programs and vice-versa.
+ *
+ * Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004.
+ *
+ * $Id$
+ */
+
+#ifndef CALLBACKS_ARCH_H
+#define CALLBACKS_ARCH_H
+
+/* Skip the definitions that won't make sense to the assembler */
+#ifndef ASSEMBLY
+
+/* Struct to hold general-purpose register values. PUSHAL and POPAL
+ * can work directly with this structure; do not change the order of
+ * registers.
+ */
+typedef struct {
+ union {
+ uint16_t di;
+ uint32_t edi;
+ };
+ union {
+ uint16_t si;
+ uint32_t esi;
+ };
+ union {
+ uint16_t bp;
+ uint32_t ebp;
+ };
+ union {
+ uint16_t sp;
+ uint32_t esp;
+ };
+ union {
+ struct {
+ uint8_t bl;
+ uint8_t bh;
+ } PACKED;
+ uint16_t bx;
+ uint32_t ebx;
+ };
+ union {
+ struct {
+ uint8_t dl;
+ uint8_t dh;
+ } PACKED;
+ uint16_t dx;
+ uint32_t edx;
+ };
+ union {
+ struct {
+ uint8_t cl;
+ uint8_t ch;
+ } PACKED;
+ uint16_t cx;
+ uint32_t ecx;
+ };
+ union {
+ struct {
+ uint8_t al;
+ uint8_t ah;
+ } PACKED;
+ uint16_t ax;
+ uint32_t eax;
+ };
+} regs_t;
+
+/* Struct to hold segment register values. Don't change the order;
+ * many bits of assembly code rely on it.
+ */
+typedef struct {
+ uint16_t cs;
+ uint16_t ss;
+ uint16_t ds;
+ uint16_t es;
+ uint16_t fs;
+ uint16_t gs;
+} PACKED seg_regs_t;
+
+/* Struct for a GDT descriptor */
+typedef struct {
+ uint16_t limit;
+ uint32_t address;
+ uint16_t padding;
+} PACKED gdt_descriptor_t;
+
+/* Struct for a GDT entry. Use GDT_SEGMENT() to fill it in.
+ */
+typedef struct {
+ uint16_t limit_0_15;
+ uint16_t base_0_15;
+ uint8_t base_16_23;
+ uint8_t accessed__type__sflag__dpl__present;
+ uint8_t limit_16_19__avl__size__granularity;
+ uint8_t base_24_31;
+} PACKED gdt_segment_t;
+
+#define GDT_SEGMENT(base,limit,type,sflag,dpl,avl,size,granularity) \
+ ( (gdt_segment_t) { \
+ ( (limit) & 0xffff ), \
+ ( (base) & 0xffff ), \
+ ( ( (base) >> 16 ) & 0xff ), \
+ ( ( 1 << 0 ) | ( (type) << 1 ) | \
+ ( (sflag) << 4 ) | ( (dpl) << 5 ) | ( 1 << 7 ) ), \
+ ( ( (limit) >> 16 ) | \
+ ( (avl) << 4 ) | ( (size) << 5 ) | ( (granularity) << 7 ) ),\
+ ( (base) >> 24 ) \
+ } )
+#define GDT_SEGMENT_BASE(gdt_segment) \
+ ( (gdt_segment)->base_0_15 | \
+ (gdt_segment)->base_16_23 << 16 | \
+ (gdt_segment)->base_24_31 << 24 )
+#define GDT_SEGMENT_LIMIT(gdt_segment) \
+ ( (gdt_segment)->limit_0_15 | \
+ ( ( (gdt_segment)->limit_16_19__avl__size__granularity \
+ & 0xf ) << 16 ) )
+#define GDT_SEGMENT_GRANULARITY(gdt_segment) \
+ ( ( (gdt_segment)->limit_16_19__avl__size__granularity \
+ & 0x80 ) >> 7 )
+#define GDT_SEGMENT_TYPE(gdt_segment) \
+ ( ( (gdt_segment)->accessed__type__sflag__dpl__present & 0x0e ) >> 1 )
+#define GDT_SEGMENT_SIZE(gdt_segment) \
+ ( ( (gdt_segment)->limit_16_19__avl__size__granularity \
+ & 0x60 ) >> 5 )
+
+#define GDT_TYPE_DATA (0x0)
+#define GDT_TYPE_STACK (0x2)
+#define GDT_TYPE_WRITEABLE (0x1)
+#define GDT_TYPE_CODE (0x6)
+#define GDT_TYPE_EXEC_ONLY_CODE (0x4)
+#define GDT_TYPE_CONFORMING (0x1)
+#define GDT_SFLAG_SYSTEM (0)
+#define GDT_SFLAG_NORMAL (1)
+#define GDT_AVL_NORMAL (0)
+#define GDT_SIZE_16BIT (0x0)
+#define GDT_SIZE_32BIT (0x2)
+#define GDT_SIZE_64BIT (0x1)
+#define GDT_SIZE_UNKNOWN (0x3)
+#define GDT_GRANULARITY_SMALL (0)
+#define GDT_GRANULARITY_LARGE (1)
+#define GDT_SEGMENT_NORMAL(base,limit,type,size,granularity) \
+ GDT_SEGMENT ( base, limit, type, \
+ GDT_SFLAG_NORMAL, 0, GDT_AVL_NORMAL, \
+ size, granularity )
+
+/* Protected mode code segment */
+#define GDT_SEGMENT_PMCS(base) GDT_SEGMENT_NORMAL ( \
+ base, 0xfffff, GDT_TYPE_CODE | GDT_TYPE_CONFORMING, \
+ GDT_SIZE_32BIT, GDT_GRANULARITY_LARGE )
+#define GDT_SEGMENT_PMCS_PHYS GDT_SEGMENT_PMCS(0)
+/* Protected mode data segment */
+#define GDT_SEGMENT_PMDS(base) GDT_SEGMENT_NORMAL ( \
+ base, 0xfffff, GDT_TYPE_DATA | GDT_TYPE_WRITEABLE, \
+ GDT_SIZE_32BIT, GDT_GRANULARITY_LARGE )
+#define GDT_SEGMENT_PMDS_PHYS GDT_SEGMENT_PMDS(0)
+/* Real mode code segment */
+/* Not sure if there's any reason to use GDT_TYPE_EXEC_ONLY_CODE
+ * instead of just GDT_TYPE_CODE, but that's what our old GDT did and
+ * it worked, so I'm not changing it.
+ */
+#define GDT_SEGMENT_RMCS(base) GDT_SEGMENT_NORMAL ( \
+ base, 0xffff, GDT_TYPE_EXEC_ONLY_CODE | GDT_TYPE_CONFORMING, \
+ GDT_SIZE_16BIT, GDT_GRANULARITY_SMALL )
+/* Real mode data segment */
+#define GDT_SEGMENT_RMDS(base) GDT_SEGMENT_NORMAL ( \
+ base, 0xffff, GDT_TYPE_DATA | GDT_TYPE_WRITEABLE, \
+ GDT_SIZE_16BIT, GDT_GRANULARITY_SMALL )
+/* Long mode code segment */
+#define GDT_SEGMENT_LMCS(base) GDT_SEGMENT_NORMAL ( \
+ base, 0xfffff, GDT_TYPE_CODE | GDT_TYPE_CONFORMING, \
+ GDT_SIZE_64BIT, GDT_GRANULARITY_LARGE )
+#define GDT_SEGMENT_LMCS_PHYS GDT_SEGMENT_LMCS(0)
+/* Long mode data segment */
+/* AFIACT, GDT_SIZE_64BIT applies only to code segments */
+#define GDT_SEGMENT_LMDS(base) GDT_SEGMENT_NORMAL ( \
+ base, 0xfffff, GDT_TYPE_DATA | GDT_TYPE_WRITEABLE, \
+ GDT_SIZE_32BIT, GDT_GRANULARITY_LARGE )
+#define GDT_SEGMENT_LMDS_PHYS GDT_SEGMENT_LMDS(0)
+
+/* Template for creating GDT structures (including segment register
+ * lists), suitable for passing as parameters to external_call().
+ */
+#define GDT_STRUCT_t(num_segments) \
+ struct { \
+ gdt_descriptor_t descriptor; \
+ gdt_segment_t segments[num_segments]; \
+ } PACKED
+/* And utility function for filling it in */
+#define GDT_ADJUST(structure) { \
+ (structure)->descriptor.address = \
+ virt_to_phys(&((structure)->descriptor.limit)); \
+ (structure)->descriptor.limit = \
+ sizeof((structure)->segments) + 8 - 1; \
+ (structure)->descriptor.padding = 0; \
+}
+
+/* Data passed in to in_call() by assembly wrapper.
+ */
+typedef struct {
+ regs_t regs;
+ seg_regs_t seg_regs;
+ gdt_descriptor_t gdt_desc;
+ uint32_t flags;
+ struct {
+ uint32_t offset;
+ uint32_t segment;
+ } ret_addr;
+} PACKED i386_pm_in_call_data_t;
+
+typedef struct {
+ seg_regs_t seg_regs;
+ union {
+ uint16_t pad;
+ uint16_t prefix_sp;
+ };
+ uint16_t flags;
+ struct {
+ uint16_t offset;
+ uint16_t segment;
+ } ret_addr;
+ uint32_t orig_opcode;
+} PACKED i386_rm_in_call_data_t;
+
+typedef struct {
+ i386_pm_in_call_data_t *pm;
+ i386_rm_in_call_data_t *rm;
+} i386_in_call_data_t;
+#define in_call_data_t i386_in_call_data_t
+
+/* Function prototypes
+ */
+extern int install_rm_callback_interface ( void *address, size_t available );
+
+#endif /* ASSEMBLY */
+
+#define RM_IN_CALL (0)
+#define RM_IN_CALL_FAR (2)
+
+#endif /* CALLBACKS_ARCH_H */
diff --git a/gpxe/src/arch/i386/include/gateA20.h b/gpxe/src/arch/i386/include/gateA20.h
new file mode 100644
index 00000000..297ad6f2
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gateA20.h
@@ -0,0 +1,7 @@
+#ifndef GATEA20_H
+#define GATEA20_H
+
+extern void gateA20_set ( void );
+extern void gateA20_unset ( void );
+
+#endif /* GATEA20_H */
diff --git a/gpxe/src/arch/i386/include/int13.h b/gpxe/src/arch/i386/include/int13.h
new file mode 100644
index 00000000..2a193831
--- /dev/null
+++ b/gpxe/src/arch/i386/include/int13.h
@@ -0,0 +1,277 @@
+#ifndef INT13_H
+#define INT13_H
+
+/** @file
+ *
+ * INT 13 emulation
+ *
+ */
+
+#include <stdint.h>
+#include <gpxe/list.h>
+
+struct block_device;
+
+/**
+ * @defgroup int13ops INT 13 operation codes
+ * @{
+ */
+
+/** Reset disk system */
+#define INT13_RESET 0x00
+/** Get status of last operation */
+#define INT13_GET_LAST_STATUS 0x01
+/** Read sectors */
+#define INT13_READ_SECTORS 0x02
+/** Write sectors */
+#define INT13_WRITE_SECTORS 0x03
+/** Get drive parameters */
+#define INT13_GET_PARAMETERS 0x08
+/** Get disk type */
+#define INT13_GET_DISK_TYPE 0x15
+/** Extensions installation check */
+#define INT13_EXTENSION_CHECK 0x41
+/** Extended read */
+#define INT13_EXTENDED_READ 0x42
+/** Extended write */
+#define INT13_EXTENDED_WRITE 0x43
+/** Get extended drive parameters */
+#define INT13_GET_EXTENDED_PARAMETERS 0x48
+/** Get CD-ROM status / terminate emulation */
+#define INT13_CDROM_STATUS_TERMINATE 0x4b
+
+/** @} */
+
+/**
+ * @defgroup int13status INT 13 status codes
+ * @{
+ */
+
+/** Operation completed successfully */
+#define INT13_STATUS_SUCCESS 0x00
+/** Invalid function or parameter */
+#define INT13_STATUS_INVALID 0x01
+/** Read error */
+#define INT13_STATUS_READ_ERROR 0x04
+/** Write error */
+#define INT13_STATUS_WRITE_ERROR 0xcc
+
+/** @} */
+
+/** Block size for non-extended INT 13 calls */
+#define INT13_BLKSIZE 512
+
+/** An INT 13 emulated drive */
+struct int13_drive {
+ /** List of all registered drives */
+ struct list_head list;
+
+ /** Underlying block device */
+ struct block_device *blockdev;
+
+ /** BIOS drive number (0x80-0xff) */
+ unsigned int drive;
+ /** Number of cylinders
+ *
+ * The cylinder number field in an INT 13 call is ten bits
+ * wide, giving a maximum of 1024 cylinders. Conventionally,
+ * when the 7.8GB limit of a CHS address is exceeded, it is
+ * the number of cylinders that is increased beyond the
+ * addressable limit.
+ */
+ unsigned int cylinders;
+ /** Number of heads
+ *
+ * The head number field in an INT 13 call is eight bits wide,
+ * giving a maximum of 256 heads. However, apparently all
+ * versions of MS-DOS up to and including Win95 fail with 256
+ * heads, so the maximum encountered in practice is 255.
+ */
+ unsigned int heads;
+ /** Number of sectors per track
+ *
+ * The sector number field in an INT 13 call is six bits wide,
+ * giving a maximum of 63 sectors, since sector numbering
+ * (unlike head and cylinder numbering) starts at 1, not 0.
+ */
+ unsigned int sectors_per_track;
+
+ /** Status of last operation */
+ int last_status;
+};
+
+/** An INT 13 disk address packet */
+struct int13_disk_address {
+ /** Size of the packet, in bytes */
+ uint8_t bufsize;
+ /** Reserved, must be zero */
+ uint8_t reserved;
+ /** Block count */
+ uint16_t count;
+ /** Data buffer */
+ struct segoff buffer;
+ /** Starting block number */
+ uint64_t lba;
+ /** Data buffer (EDD-3.0 only) */
+ uint64_t buffer_phys;
+} __attribute__ (( packed ));
+
+/** INT 13 disk parameters */
+struct int13_disk_parameters {
+ /** Size of this structure */
+ uint16_t bufsize;
+ /** Flags */
+ uint16_t flags;
+ /** Number of cylinders */
+ uint32_t cylinders;
+ /** Number of heads */
+ uint32_t heads;
+ /** Number of sectors per track */
+ uint32_t sectors_per_track;
+ /** Total number of sectors on drive */
+ uint64_t sectors;
+ /** Bytes per sector */
+ uint16_t sector_size;
+
+} __attribute__ (( packed ));
+
+/**
+ * @defgroup int13types INT 13 disk types
+ * @{
+ */
+
+/** No such drive */
+#define INT13_DISK_TYPE_NONE 0x00
+/** Floppy without change-line support */
+#define INT13_DISK_TYPE_FDD 0x01
+/** Floppy with change-line support */
+#define INT13_DISK_TYPE_FDD_CL 0x02
+/** Hard disk */
+#define INT13_DISK_TYPE_HDD 0x03
+
+/** @} */
+
+/**
+ * @defgroup int13flags INT 13 disk parameter flags
+ * @{
+ */
+
+/** DMA boundary errors handled transparently */
+#define INT13_FL_DMA_TRANSPARENT 0x01
+/** CHS information is valid */
+#define INT13_FL_CHS_VALID 0x02
+/** Removable drive */
+#define INT13_FL_REMOVABLE 0x04
+/** Write with verify supported */
+#define INT13_FL_VERIFIABLE 0x08
+/** Has change-line supported (valid only for removable drives) */
+#define INT13_FL_CHANGE_LINE 0x10
+/** Drive can be locked (valid only for removable drives) */
+#define INT13_FL_LOCKABLE 0x20
+/** CHS is max possible, not current media (valid only for removable drives) */
+#define INT13_FL_CHS_MAX 0x40
+
+/** @} */
+
+/**
+ * @defgroup int13exts INT 13 extension flags
+ * @{
+ */
+
+/** Extended disk access functions supported */
+#define INT13_EXTENSION_LINEAR 0x01
+/** Removable drive functions supported */
+#define INT13_EXTENSION_REMOVABLE 0x02
+/** EDD functions supported */
+#define INT13_EXTENSION_EDD 0x04
+
+/** @} */
+
+/**
+ * @defgroup int13vers INT 13 extension versions
+ * @{
+ */
+
+/** INT13 extensions version 1.x */
+#define INT13_EXTENSION_VER_1_X 0x01
+/** INT13 extensions version 2.0 (EDD-1.0) */
+#define INT13_EXTENSION_VER_2_0 0x20
+/** INT13 extensions version 2.1 (EDD-1.1) */
+#define INT13_EXTENSION_VER_2_1 0x21
+/** INT13 extensions version 3.0 (EDD-3.0) */
+#define INT13_EXTENSION_VER_3_0 0x30
+
+/** @} */
+
+/** Bootable CD-ROM specification packet */
+struct int13_cdrom_specification {
+ /** Size of packet in bytes */
+ uint8_t size;
+ /** Boot media type */
+ uint8_t media_type;
+ /** Drive number */
+ uint8_t drive;
+ /** CD-ROM controller number */
+ uint8_t controller;
+ /** LBA of disk image to emulate */
+ uint32_t lba;
+ /** Device specification */
+ uint16_t device;
+ /** Segment of 3K buffer for caching CD-ROM reads */
+ uint16_t cache_segment;
+ /** Load segment for initial boot image */
+ uint16_t load_segment;
+ /** Number of 512-byte sectors to load */
+ uint16_t load_sectors;
+ /** Low 8 bits of cylinder number */
+ uint8_t cyl;
+ /** Sector number, plus high 2 bits of cylinder number */
+ uint8_t cyl_sector;
+ /** Head number */
+ uint8_t head;
+} __attribute__ (( packed ));
+
+/** A C/H/S address within a partition table entry */
+struct partition_chs {
+ /** Head number */
+ uint8_t head;
+ /** Sector number, plus high 2 bits of cylinder number */
+ uint8_t cyl_sector;
+ /** Low 8 bits of cylinder number */
+ uint8_t cyl;
+} __attribute__ (( packed ));
+
+#define PART_HEAD(chs) ( (chs).head )
+#define PART_SECTOR(chs) ( (chs).cyl_sector & 0x3f )
+#define PART_CYLINDER(chs) ( (chs).cyl | ( ( (chs).cyl_sector & 0xc0 ) << 2 ) )
+
+/** A partition table entry within the MBR */
+struct partition_table_entry {
+ /** Bootable flag */
+ uint8_t bootable;
+ /** C/H/S start address */
+ struct partition_chs chs_start;
+ /** System indicator (partition type) */
+ uint8_t type;
+ /** C/H/S end address */
+ struct partition_chs chs_end;
+ /** Linear start address */
+ uint32_t start;
+ /** Linear length */
+ uint32_t length;
+} __attribute__ (( packed ));
+
+/** A Master Boot Record */
+struct master_boot_record {
+ uint8_t pad[446];
+ /** Partition table */
+ struct partition_table_entry partitions[4];
+ /** 0x55aa MBR signature */
+ uint16_t signature;
+} __attribute__ (( packed ));
+
+extern void register_int13_drive ( struct int13_drive *drive );
+extern void unregister_int13_drive ( struct int13_drive *drive );
+extern int int13_boot ( unsigned int drive );
+
+#endif /* INT13_H */
diff --git a/gpxe/src/arch/i386/include/io.h b/gpxe/src/arch/i386/include/io.h
new file mode 100644
index 00000000..c26fdf7e
--- /dev/null
+++ b/gpxe/src/arch/i386/include/io.h
@@ -0,0 +1,265 @@
+#ifndef ETHERBOOT_IO_H
+#define ETHERBOOT_IO_H
+
+#include <stdint.h>
+#include "virtaddr.h"
+
+/* virt_to_bus converts an addresss inside of etherboot [_start, _end]
+ * into a memory access cards can use.
+ */
+#define virt_to_bus virt_to_phys
+
+
+/* bus_to_virt reverses virt_to_bus, the address must be output
+ * from virt_to_bus to be valid. This function does not work on
+ * all bus addresses.
+ */
+#define bus_to_virt phys_to_virt
+
+/* ioremap converts a random 32bit bus address into something
+ * etherboot can access.
+ */
+static inline void *ioremap(unsigned long bus_addr, unsigned long length __unused)
+{
+ return bus_to_virt(bus_addr);
+}
+
+/* iounmap cleans up anything ioremap had to setup */
+static inline void iounmap(void *virt_addr __unused)
+{
+ return;
+}
+
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+/*
+ * Thanks to James van Artsdalen for a better timing-fix than
+ * the two short jumps: using outb's to a nonexistent port seems
+ * to guarantee better timings even on fast machines.
+ *
+ * On the other hand, I'd like to be sure of a non-existent port:
+ * I feel a bit unsafe about using 0x80 (should be safe, though)
+ *
+ * Linus
+ */
+
+#ifdef SLOW_IO_BY_JUMPING
+#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
+#else
+#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
+#endif
+
+#ifdef REALLY_SLOW_IO
+#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
+#else
+#define SLOW_DOWN_IO __SLOW_DOWN_IO
+#endif
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+static inline __attribute__ (( always_inline )) unsigned long
+_readb ( volatile uint8_t *addr ) {
+ unsigned long data = *addr;
+ DBGIO ( "[%08lx] => %02lx\n", virt_to_phys ( addr ), data );
+ return data;
+}
+static inline __attribute__ (( always_inline )) unsigned long
+_readw ( volatile uint16_t *addr ) {
+ unsigned long data = *addr;
+ DBGIO ( "[%08lx] => %04lx\n", virt_to_phys ( addr ), data );
+ return data;
+}
+static inline __attribute__ (( always_inline )) unsigned long
+_readl ( volatile uint32_t *addr ) {
+ unsigned long data = *addr;
+ DBGIO ( "[%08lx] => %08lx\n", virt_to_phys ( addr ), data );
+ return data;
+}
+#define readb( addr ) _readb ( ( volatile uint8_t * ) (addr) )
+#define readw( addr ) _readw ( ( volatile uint16_t * ) (addr) )
+#define readl( addr ) _readl ( ( volatile uint32_t * ) (addr) )
+
+static inline __attribute__ (( always_inline )) void
+_writeb ( unsigned long data, volatile uint8_t *addr ) {
+ DBGIO ( "[%08lx] <= %02lx\n", virt_to_phys ( addr ), data );
+ *addr = data;
+}
+static inline __attribute__ (( always_inline )) void
+_writew ( unsigned long data, volatile uint16_t *addr ) {
+ DBGIO ( "[%08lx] <= %04lx\n", virt_to_phys ( addr ), data );
+ *addr = data;
+}
+static inline __attribute__ (( always_inline )) void
+_writel ( unsigned long data, volatile uint32_t *addr ) {
+ DBGIO ( "[%08lx] <= %08lx\n", virt_to_phys ( addr ), data );
+ *addr = data;
+}
+#define writeb( b, addr ) _writeb ( (b), ( volatile uint8_t * ) (addr) )
+#define writew( b, addr ) _writew ( (b), ( volatile uint16_t * ) (addr) )
+#define writel( b, addr ) _writel ( (b), ( volatile uint32_t * ) (addr) )
+
+#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
+
+/*
+ * Force strict CPU ordering.
+ * And yes, this is required on UP too when we're talking
+ * to devices.
+ *
+ * For now, "wmb()" doesn't actually do anything, as all
+ * Intel CPU's follow what Intel calls a *Processor Order*,
+ * in which all writes are seen in the program order even
+ * outside the CPU.
+ *
+ * I expect future Intel CPU's to have a weaker ordering,
+ * but I'd also expect them to finally get their act together
+ * and add some real memory barriers if so.
+ *
+ * Some non intel clones support out of order store. wmb() ceases to be a
+ * nop for these.
+ */
+
+#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#define rmb() mb()
+#define wmb() mb();
+
+
+/*
+ * Talk about misusing macros..
+ */
+
+#define __OUT1(s,x) \
+extern void __out##s(unsigned x value, unsigned short port); \
+extern inline void __out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
+__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
+__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
+
+#define __IN1(s,x) \
+extern unsigned x __in##s(unsigned short port); \
+extern inline unsigned x __in##s(unsigned short port) { unsigned x _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,x,i...) \
+__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
+__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
+__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
+__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
+
+#define __INS(s) \
+extern void ins##s(unsigned short port, void * addr, unsigned long count); \
+extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+extern void outs##s(unsigned short port, const void * addr, unsigned long count); \
+extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+__IN(b,"", char)
+__IN(w,"",short)
+__IN(l,"", long)
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+/*
+ * Note that due to the way __builtin_constant_p() works, you
+ * - can't use it inside a inline function (it will never be true)
+ * - you don't have to worry about side effects within the __builtin..
+ */
+#define outb(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc((val),(port)) : \
+ __outb((val),(port)))
+
+#define inb(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc(port) : \
+ __inb(port))
+
+#define outb_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outbc_p((val),(port)) : \
+ __outb_p((val),(port)))
+
+#define inb_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inbc_p(port) : \
+ __inb_p(port))
+
+#define outw(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outwc((val),(port)) : \
+ __outw((val),(port)))
+
+#define inw(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inwc(port) : \
+ __inw(port))
+
+#define outw_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outwc_p((val),(port)) : \
+ __outw_p((val),(port)))
+
+#define inw_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inwc_p(port) : \
+ __inw_p(port))
+
+#define outl(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outlc((val),(port)) : \
+ __outl((val),(port)))
+
+#define inl(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inlc(port) : \
+ __inl(port))
+
+#define outl_p(val,port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __outlc_p((val),(port)) : \
+ __outl_p((val),(port)))
+
+#define inl_p(port) \
+((__builtin_constant_p((port)) && (port) < 256) ? \
+ __inlc_p(port) : \
+ __inl_p(port))
+
+#endif /* ETHERBOOT_IO_H */
diff --git a/gpxe/src/arch/i386/include/kir.h b/gpxe/src/arch/i386/include/kir.h
new file mode 100644
index 00000000..84633d26
--- /dev/null
+++ b/gpxe/src/arch/i386/include/kir.h
@@ -0,0 +1,18 @@
+#ifndef KIR_H
+#define KIR_H
+
+#ifndef KEEP_IT_REAL
+#error "kir.h can be used only with -DKEEP_IT_REAL"
+#endif
+
+#ifdef ASSEMBLY
+
+#define code32 code16gcc
+
+#else /* ASSEMBLY */
+
+__asm__ ( ".code16gcc" );
+
+#endif /* ASSEMBLY */
+
+#endif /* KIR_H */
diff --git a/gpxe/src/arch/i386/include/libkir.h b/gpxe/src/arch/i386/include/libkir.h
new file mode 100644
index 00000000..5f67a56d
--- /dev/null
+++ b/gpxe/src/arch/i386/include/libkir.h
@@ -0,0 +1,233 @@
+#ifndef LIBKIR_H
+#define LIBKIR_H
+
+#include "realmode.h"
+
+#ifndef ASSEMBLY
+
+/*
+ * Full API documentation for these functions is in realmode.h.
+ *
+ */
+
+/* Access to variables in .data16 and .text16 in a way compatible with librm */
+#define __data16( variable ) variable
+#define __data16_array( variable, array ) variable array
+#define __bss16( variable ) variable
+#define __bss16_array( variable, array ) variable array
+#define __text16( variable ) variable
+#define __text16_array( variable,array ) variable array
+#define __use_data16( variable ) variable
+#define __use_text16( variable ) variable
+#define __from_data16( variable ) variable
+#define __from_text16( variable ) variable
+
+/* Real-mode data and code segments */
+static inline __attribute__ (( always_inline )) unsigned int _rm_cs ( void ) {
+ uint16_t cs;
+ __asm__ __volatile__ ( "movw %%cs, %w0" : "=r" ( cs ) );
+ return cs;
+}
+
+static inline __attribute__ (( always_inline )) unsigned int _rm_ds ( void ) {
+ uint16_t ds;
+ __asm__ __volatile__ ( "movw %%ds, %w0" : "=r" ( ds ) );
+ return ds;
+}
+
+#define rm_cs ( _rm_cs() )
+#define rm_ds ( _rm_ds() )
+
+/* Copy to/from base memory */
+
+static inline void copy_to_real_libkir ( unsigned int dest_seg,
+ unsigned int dest_off,
+ const void *src, size_t n ) {
+ unsigned int discard_D, discard_S, discard_c;
+
+ __asm__ __volatile__ ( "pushw %%es\n\t"
+ "movw %3, %%es\n\t"
+ "rep movsb\n\t"
+ "popw %%es\n\t"
+ : "=D" ( discard_D ), "=S" ( discard_S ),
+ "=c" ( discard_c )
+ : "r" ( dest_seg ), "D" ( dest_off ),
+ "S" ( src ),
+ "c" ( n )
+ : "memory" );
+}
+
+static inline void copy_from_real_libkir ( void *dest,
+ unsigned int src_seg,
+ unsigned int src_off,
+ size_t n ) {
+ unsigned int discard_D, discard_S, discard_c;
+
+ __asm__ __volatile__ ( "pushw %%ds\n\t"
+ "movw %4, %%ds\n\t"
+ "rep movsb\n\t"
+ "popw %%ds\n\t"
+ : "=D" ( discard_D ), "=S" ( discard_S ),
+ "=c" ( discard_c )
+ : "D" ( dest ),
+ "r" ( src_seg ), "S" ( src_off ),
+ "c" ( n )
+ : "memory" );
+}
+
+#define copy_to_real copy_to_real_libkir
+#define copy_from_real copy_from_real_libkir
+
+/*
+ * Transfer individual values to/from base memory. There may well be
+ * a neater way to do this. We have two versions: one for constant
+ * offsets (where the mov instruction must be of the form "mov
+ * %es:123, %xx") and one for non-constant offsets (where the mov
+ * instruction must be of the form "mov %es:(%xx), %yx". If it's
+ * possible to incorporate both forms into one __asm__ instruction, I
+ * don't know how to do it.
+ *
+ * Ideally, the mov instruction should be "mov%z0"; the "%z0" is meant
+ * to expand to either "b", "w" or "l" depending on the size of
+ * operand 0. This would remove the (minor) ambiguity in the mov
+ * instruction. However, gcc on at least my system barfs with an
+ * "internal compiler error" when confronted with %z0.
+ *
+ */
+
+#define put_real_kir_const_off( var, seg, off ) \
+ __asm__ ( "movw %w1, %%es\n\t" \
+ "mov %0, %%es:%c2\n\t" \
+ "pushw %%ds\n\t" /* restore %es */ \
+ "popw %%es\n\t" \
+ : \
+ : "r,r" ( var ), "rm,rm" ( seg ), "i,!r" ( off ) \
+ )
+
+#define put_real_kir_nonconst_off( var, seg, off ) \
+ __asm__ ( "movw %w1, %%es\n\t" \
+ "mov %0, %%es:(%2)\n\t" \
+ "pushw %%ds\n\t" /* restore %es */ \
+ "popw %%es\n\t" \
+ : \
+ : "r" ( var ), "rm" ( seg ), "r" ( off ) \
+ )
+
+#define put_real_kir( var, seg, off ) \
+ do { \
+ if ( __builtin_constant_p ( off ) ) \
+ put_real_kir_const_off ( var, seg, off ); \
+ else \
+ put_real_kir_nonconst_off ( var, seg, off ); \
+ } while ( 0 )
+
+#define get_real_kir_const_off( var, seg, off ) \
+ __asm__ ( "movw %w1, %%es\n\t" \
+ "mov %%es:%c2, %0\n\t" \
+ "pushw %%ds\n\t" /* restore %es */ \
+ "popw %%es\n\t" \
+ : "=r,r" ( var ) \
+ : "rm,rm" ( seg ), "i,!r" ( off ) \
+ )
+
+#define get_real_kir_nonconst_off( var, seg, off ) \
+ __asm__ ( "movw %w1, %%es\n\t" \
+ "mov %%es:(%2), %0\n\t" \
+ "pushw %%ds\n\t" /* restore %es */ \
+ "popw %%es\n\t" \
+ : "=r" ( var ) \
+ : "rm" ( seg ), "r" ( off ) \
+ )
+
+#define get_real_kir( var, seg, off ) \
+ do { \
+ if ( __builtin_constant_p ( off ) ) \
+ get_real_kir_const_off ( var, seg, off ); \
+ else \
+ get_real_kir_nonconst_off ( var, seg, off ); \
+ } while ( 0 )
+
+#define put_real put_real_kir
+#define get_real get_real_kir
+
+/**
+ * A pointer to a user buffer
+ *
+ * This is actually a struct segoff, but encoded as a uint32_t to
+ * ensure that gcc passes it around efficiently.
+ */
+typedef uint32_t userptr_t;
+
+/**
+ * Copy data to user buffer
+ *
+ * @v buffer User buffer
+ * @v offset Offset within user buffer
+ * @v src Source
+ * @v len Length
+ */
+static inline __attribute__ (( always_inline )) void
+copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
+ copy_to_real ( ( buffer >> 16 ), ( ( buffer & 0xffff ) + offset ),
+ src, len );
+}
+
+/**
+ * Copy data from user buffer
+ *
+ * @v dest Destination
+ * @v buffer User buffer
+ * @v offset Offset within user buffer
+ * @v len Length
+ */
+static inline __attribute__ (( always_inline )) void
+copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
+ copy_from_real ( dest, ( buffer >> 16 ),
+ ( ( buffer & 0xffff ) + offset ), len );
+}
+
+/**
+ * Convert segment:offset address to user buffer
+ *
+ * @v segment Real-mode segment
+ * @v offset Real-mode offset
+ * @ret buffer User buffer
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+real_to_user ( unsigned int segment, unsigned int offset ) {
+ return ( ( segment << 16 ) | offset );
+}
+
+/**
+ * Convert virtual address to user buffer
+ *
+ * @v virtual Virtual address
+ * @ret buffer User buffer
+ *
+ * This constructs a user buffer from an ordinary pointer. Use it
+ * when you need to pass a pointer to an internal buffer to a function
+ * that expects a @c userptr_t.
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+virt_to_user ( void * virtual ) {
+ return real_to_user ( rm_ds, ( intptr_t ) virtual );
+}
+
+/* TEXT16_CODE: declare a fragment of code that resides in .text16 */
+#define TEXT16_CODE( asm_code_str ) \
+ ".section \".text16\", \"ax\", @progbits\n\t" \
+ ".code16\n\t" \
+ ".arch i386\n\t" \
+ asm_code_str "\n\t" \
+ ".code16gcc\n\t" \
+ ".previous\n\t"
+
+/* REAL_CODE: declare a fragment of code that executes in real mode */
+#define REAL_CODE( asm_code_str ) \
+ ".code16\n\t" \
+ asm_code_str "\n\t" \
+ ".code16gcc\n\t"
+
+#endif /* ASSEMBLY */
+
+#endif /* LIBKIR_H */
diff --git a/gpxe/src/arch/i386/include/librm.h b/gpxe/src/arch/i386/include/librm.h
new file mode 100644
index 00000000..32dceed6
--- /dev/null
+++ b/gpxe/src/arch/i386/include/librm.h
@@ -0,0 +1,289 @@
+#ifndef LIBRM_H
+#define LIBRM_H
+
+/* Drag in protected-mode segment selector values */
+#include "virtaddr.h"
+#include "realmode.h"
+
+#ifndef ASSEMBLY
+
+#include "stddef.h"
+#include "string.h"
+
+/*
+ * Data structures and type definitions
+ *
+ */
+
+/* Access to variables in .data16 and .text16 */
+extern char *data16;
+extern char *text16;
+
+#define __data16( variable ) \
+ __attribute__ (( section ( ".data16" ) )) \
+ _data16_ ## variable __asm__ ( #variable )
+
+#define __data16_array( variable, array ) \
+ __attribute__ (( section ( ".data16" ) )) \
+ _data16_ ## variable array __asm__ ( #variable )
+
+#define __bss16( variable ) \
+ __attribute__ (( section ( ".bss16" ) )) \
+ _data16_ ## variable __asm__ ( #variable )
+
+#define __bss16_array( variable, array ) \
+ __attribute__ (( section ( ".bss16" ) )) \
+ _data16_ ## variable array __asm__ ( #variable )
+
+#define __text16( variable ) \
+ __attribute__ (( section ( ".text16.data" ) )) \
+ _text16_ ## variable __asm__ ( #variable )
+
+#define __text16_array( variable, array ) \
+ __attribute__ (( section ( ".text16.data" ) )) \
+ _text16_ ## variable array __asm__ ( #variable )
+
+#define __use_data16( variable ) \
+ ( * ( ( typeof ( _data16_ ## variable ) * ) \
+ & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
+
+#define __use_text16( variable ) \
+ ( * ( ( typeof ( _text16_ ## variable ) * ) \
+ & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
+
+#define __from_data16( variable ) \
+ ( * ( ( typeof ( variable ) * ) \
+ ( ( ( void * ) &(variable) ) - ( ( void * ) data16 ) ) ) )
+
+#define __from_text16( variable ) \
+ ( * ( ( typeof ( variable ) * ) \
+ ( ( ( void * ) &(variable) ) - ( ( void * ) text16 ) ) ) )
+
+/* Variables in librm.S, present in the normal data segment */
+extern uint16_t __data16 ( rm_cs );
+#define rm_cs __use_data16 ( rm_cs )
+extern uint16_t __text16 ( rm_ds );
+#define rm_ds __use_text16 ( rm_ds )
+
+/* Functions that librm expects to be able to link to. Included here
+ * so that the compiler will catch prototype mismatches.
+ */
+extern void gateA20_set ( void );
+
+/*
+ * librm_mgmt: functions for manipulating base memory and executing
+ * real-mode code.
+ *
+ * Full API documentation for these functions is in realmode.h.
+ *
+ */
+
+/* Macro for obtaining a physical address from a segment:offset pair. */
+#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
+
+/* Copy to/from base memory */
+static inline __attribute__ (( always_inline )) void
+copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off,
+ void *src, size_t n ) {
+ memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
+}
+static inline __attribute__ (( always_inline )) void
+copy_from_real_librm ( void *dest, unsigned int src_seg,
+ unsigned int src_off, size_t n ) {
+ memcpy ( dest, VIRTUAL ( src_seg, src_off ), n );
+}
+#define put_real_librm( var, dest_seg, dest_off ) \
+ do { \
+ * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \
+ } while ( 0 )
+#define get_real_librm( var, src_seg, src_off ) \
+ do { \
+ var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \
+ } while ( 0 )
+#define copy_to_real copy_to_real_librm
+#define copy_from_real copy_from_real_librm
+#define put_real put_real_librm
+#define get_real get_real_librm
+
+/**
+ * A pointer to a user buffer
+ *
+ * Even though we could just use a void *, we use an intptr_t so that
+ * attempts to use normal pointers show up as compiler warnings. Such
+ * code is actually valid for librm, but not for libkir (i.e. under
+ * KEEP_IT_REAL), so it's good to have the warnings even under librm.
+ */
+typedef intptr_t userptr_t;
+
+/**
+ * Add offset to user pointer
+ *
+ * @v ptr User pointer
+ * @v offset Offset
+ * @ret new_ptr New pointer value
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+userptr_add ( userptr_t ptr, off_t offset ) {
+ return ( ptr + offset );
+}
+
+/**
+ * Copy data to user buffer
+ *
+ * @v buffer User buffer
+ * @v offset Offset within user buffer
+ * @v src Source
+ * @v len Length
+ */
+static inline __attribute__ (( always_inline )) void
+copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
+ memcpy ( ( ( void * ) buffer + offset ), src, len );
+}
+
+/**
+ * Copy data from user buffer
+ *
+ * @v dest Destination
+ * @v buffer User buffer
+ * @v offset Offset within user buffer
+ * @v len Length
+ */
+static inline __attribute__ (( always_inline )) void
+copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
+ memcpy ( dest, ( ( void * ) buffer + offset ), len );
+}
+
+/**
+ * Copy data between user buffers
+ *
+ * @v dest Destination user buffer
+ * @v dest_off Offset within destination buffer
+ * @v src Source user buffer
+ * @v src_off Offset within source buffer
+ * @v len Length
+ */
+static inline __attribute__ (( always_inline )) void
+memcpy_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
+ size_t len ) {
+ memcpy ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
+ len );
+}
+
+/**
+ * Copy data between user buffers, allowing for overlap
+ *
+ * @v dest Destination user buffer
+ * @v dest_off Offset within destination buffer
+ * @v src Source user buffer
+ * @v src_off Offset within source buffer
+ * @v len Length
+ */
+static inline __attribute__ (( always_inline )) void
+memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
+ size_t len ) {
+ memmove ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
+ len );
+}
+
+/**
+ * Fill user buffer with a constant byte
+ *
+ * @v buffer User buffer
+ * @v offset Offset within buffer
+ * @v c Constant byte with which to fill
+ * @v len Length
+ */
+static inline __attribute__ (( always_inline )) void
+memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
+ memset ( ( ( void * ) buffer + offset ), c, len );
+}
+
+/**
+ * Find length of NUL-terminated string in user buffer
+ *
+ * @v buffer User buffer
+ * @v offset Offset within buffer
+ * @ret len Length of string (excluding NUL)
+ */
+static inline __attribute__ (( always_inline )) size_t
+strlen_user ( userptr_t buffer, off_t offset ) {
+ return strlen ( ( void * ) buffer + offset );
+}
+
+/**
+ * Convert virtual address to user buffer
+ *
+ * @v virtual Virtual address
+ * @ret buffer User buffer
+ *
+ * This constructs a user buffer from an ordinary pointer. Use it
+ * when you need to pass a pointer to an internal buffer to a function
+ * that expects a @c userptr_t.
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+virt_to_user ( void * virtual ) {
+ return ( ( intptr_t ) virtual );
+}
+
+/**
+ * Convert segment:offset address to user buffer
+ *
+ * @v segment Real-mode segment
+ * @v offset Real-mode offset
+ * @ret buffer User buffer
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+real_to_user ( unsigned int segment, unsigned int offset ) {
+ return virt_to_user ( VIRTUAL ( segment, offset ) );
+}
+
+/**
+ * Convert physical address to user buffer
+ *
+ * @v physical Physical address
+ * @ret buffer User buffer
+ */
+static inline __attribute__ (( always_inline )) userptr_t
+phys_to_user ( physaddr_t physical ) {
+ return virt_to_user ( phys_to_virt ( physical ) );
+}
+
+/**
+ * Convert user buffer to physical address
+ *
+ * @v buffer User buffer
+ * @v offset Offset within user buffer
+ * @ret physical Physical address
+ */
+static inline __attribute__ (( always_inline )) physaddr_t
+user_to_phys ( userptr_t buffer, off_t offset ) {
+ return virt_to_phys ( ( void * ) buffer + offset );
+}
+
+/* TEXT16_CODE: declare a fragment of code that resides in .text16 */
+#define TEXT16_CODE( asm_code_str ) \
+ ".section \".text16\", \"ax\", @progbits\n\t" \
+ ".code16\n\t" \
+ asm_code_str "\n\t" \
+ ".code32\n\t" \
+ ".previous\n\t"
+
+/* REAL_CODE: declare a fragment of code that executes in real mode */
+#define REAL_CODE( asm_code_str ) \
+ "pushl $1f\n\t" \
+ "call real_call\n\t" \
+ "addl $4, %%esp\n\t" \
+ TEXT16_CODE ( "\n1:\n\t" \
+ asm_code_str \
+ "\n\t" \
+ "ret\n\t" )
+
+/* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
+#define PHYS_CODE( asm_code_str ) \
+ "call _virt_to_phys\n\t" \
+ asm_code_str \
+ "call _phys_to_virt\n\t"
+
+#endif /* ASSEMBLY */
+
+#endif /* LIBRM_H */
diff --git a/gpxe/src/arch/i386/include/limits.h b/gpxe/src/arch/i386/include/limits.h
new file mode 100644
index 00000000..f13db267
--- /dev/null
+++ b/gpxe/src/arch/i386/include/limits.h
@@ -0,0 +1,59 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MAX 2147483647
+#define INT_MIN (-INT_MAX - 1)
+
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 2147483647
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 4294967295UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/gpxe/src/arch/i386/include/memsizes.h b/gpxe/src/arch/i386/include/memsizes.h
new file mode 100644
index 00000000..6222fd66
--- /dev/null
+++ b/gpxe/src/arch/i386/include/memsizes.h
@@ -0,0 +1,17 @@
+#ifndef _MEMSIZES_H
+#define _MEMSIZES_H
+
+#include <basemem.h>
+
+/**
+ * Get size of base memory from BIOS free base memory counter
+ *
+ * @ret basemem Base memory size, in kB
+ */
+static inline unsigned int basememsize ( void ) {
+ return get_fbms();
+}
+
+extern unsigned int extmemsize ( void );
+
+#endif /* _MEMSIZES_H */
diff --git a/gpxe/src/arch/i386/include/multiboot.h b/gpxe/src/arch/i386/include/multiboot.h
new file mode 100644
index 00000000..4ca7089b
--- /dev/null
+++ b/gpxe/src/arch/i386/include/multiboot.h
@@ -0,0 +1,147 @@
+#ifndef _MULTIBOOT_H
+#define _MULTIBOOT_H
+
+/**
+ * @file
+ *
+ * Multiboot operating systems
+ *
+ */
+
+#include <stdint.h>
+
+/** The magic number for the Multiboot header */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/** Boot modules must be page aligned */
+#define MB_FLAG_PGALIGN 0x00000001
+
+/** Memory map must be provided */
+#define MB_FLAG_MEMMAP 0x00000002
+
+/** Video mode information must be provided */
+#define MB_FLAG_VIDMODE 0x00000004
+
+/** Image is a raw multiboot image (not ELF) */
+#define MB_FLAG_RAW 0x00010000
+
+/**
+ * The magic number passed by a Multiboot-compliant boot loader
+ *
+ * Must be passed in register %eax when jumping to the Multiboot OS
+ * image.
+ */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+/** Multiboot information structure mem_* fields are valid */
+#define MBI_FLAG_MEM 0x00000001
+
+/** Multiboot information structure boot_device field is valid */
+#define MBI_FLAG_BOOTDEV 0x00000002
+
+/** Multiboot information structure cmdline field is valid */
+#define MBI_FLAG_CMDLINE 0x00000004
+
+/** Multiboot information structure module fields are valid */
+#define MBI_FLAG_MODS 0x00000008
+
+/** Multiboot information structure a.out symbol table is valid */
+#define MBI_FLAG_AOUT 0x00000010
+
+/** Multiboot information struture ELF section header table is valid */
+#define MBI_FLAG_ELF 0x00000020
+
+/** Multiboot information structure memory map is valid */
+#define MBI_FLAG_MMAP 0x00000040
+
+/** Multiboot information structure drive list is valid */
+#define MBI_FLAG_DRIVES 0x00000080
+
+/** Multiboot information structure ROM configuration field is valid */
+#define MBI_FLAG_CFGTBL 0x00000100
+
+/** Multiboot information structure boot loader name field is valid */
+#define MBI_FLAG_LOADER 0x00000200
+
+/** Multiboot information structure APM table is valid */
+#define MBI_FLAG_APM 0x00000400
+
+/** Multiboot information structure video information is valid */
+#define MBI_FLAG_VBE 0x00000800
+
+/** A multiboot header */
+struct multiboot_header {
+ uint32_t magic;
+ uint32_t flags;
+ uint32_t checksum;
+ uint32_t header_addr;
+ uint32_t load_addr;
+ uint32_t load_end_addr;
+ uint32_t bss_end_addr;
+ uint32_t entry_addr;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot a.out symbol table */
+struct multiboot_aout_symbol_table {
+ uint32_t tabsize;
+ uint32_t strsize;
+ uint32_t addr;
+ uint32_t reserved;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot ELF section header table */
+struct multiboot_elf_section_header_table {
+ uint32_t num;
+ uint32_t size;
+ uint32_t addr;
+ uint32_t shndx;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot information structure */
+struct multiboot_info {
+ uint32_t flags;
+ uint32_t mem_lower;
+ uint32_t mem_upper;
+ uint32_t boot_device;
+ uint32_t cmdline;
+ uint32_t mods_count;
+ uint32_t mods_addr;
+ union {
+ struct multiboot_aout_symbol_table aout_syms;
+ struct multiboot_elf_section_header_table elf_sections;
+ } syms;
+ uint32_t mmap_length;
+ uint32_t mmap_addr;
+ uint32_t drives_length;
+ uint32_t drives_addr;
+ uint32_t config_table;
+ uint32_t boot_loader_name;
+ uint32_t apm_table;
+ uint32_t vbe_control_info;
+ uint32_t vbe_mode_info;
+ uint16_t vbe_mode;
+ uint16_t vbe_interface_seg;
+ uint16_t vbe_interface_off;
+ uint16_t vbe_interface_len;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot module structure */
+struct multiboot_module {
+ uint32_t mod_start;
+ uint32_t mod_end;
+ uint32_t string;
+ uint32_t reserved;
+} __attribute__ (( packed, may_alias ));
+
+/** A multiboot memory map entry */
+struct multiboot_memory_map {
+ uint32_t size;
+ uint64_t base_addr;
+ uint64_t length;
+ uint32_t type;
+} __attribute__ (( packed, may_alias ));
+
+/** Usable RAM */
+#define MBMEM_RAM 1
+
+#endif /* _MULTIBOOT_H */
diff --git a/gpxe/src/arch/i386/include/pci_io.h b/gpxe/src/arch/i386/include/pci_io.h
new file mode 100644
index 00000000..4888d557
--- /dev/null
+++ b/gpxe/src/arch/i386/include/pci_io.h
@@ -0,0 +1,35 @@
+#ifndef _PCI_IO_H
+#define _PCI_IO_H
+
+#include <pcibios.h>
+#include <pcidirect.h>
+
+/** @file
+ *
+ * i386 PCI configuration space access
+ *
+ * We have two methods of PCI configuration space access: the PCI BIOS
+ * and direct Type 1 accesses. Selecting between them is via the
+ * compile-time switch -DCONFIG_PCI_DIRECT.
+ *
+ */
+
+#if CONFIG_PCI_DIRECT
+#define pci_max_bus pcidirect_max_bus
+#define pci_read_config_byte pcidirect_read_config_byte
+#define pci_read_config_word pcidirect_read_config_word
+#define pci_read_config_dword pcidirect_read_config_dword
+#define pci_write_config_byte pcidirect_write_config_byte
+#define pci_write_config_word pcidirect_write_config_word
+#define pci_write_config_dword pcidirect_write_config_dword
+#else /* CONFIG_PCI_DIRECT */
+#define pci_max_bus pcibios_max_bus
+#define pci_read_config_byte pcibios_read_config_byte
+#define pci_read_config_word pcibios_read_config_word
+#define pci_read_config_dword pcibios_read_config_dword
+#define pci_write_config_byte pcibios_write_config_byte
+#define pci_write_config_word pcibios_write_config_word
+#define pci_write_config_dword pcibios_write_config_dword
+#endif /* CONFIG_PCI_DIRECT */
+
+#endif /* _PCI_IO_H */
diff --git a/gpxe/src/arch/i386/include/pcibios.h b/gpxe/src/arch/i386/include/pcibios.h
new file mode 100644
index 00000000..3d08d135
--- /dev/null
+++ b/gpxe/src/arch/i386/include/pcibios.h
@@ -0,0 +1,122 @@
+#ifndef _PCIBIOS_H
+#define _PCIBIOS_H
+
+#include <stdint.h>
+
+/** @file
+ *
+ * PCI configuration space access via PCI BIOS
+ *
+ */
+
+struct pci_device;
+
+#define PCIBIOS_INSTALLATION_CHECK 0xb1010000
+#define PCIBIOS_READ_CONFIG_BYTE 0xb1080000
+#define PCIBIOS_READ_CONFIG_WORD 0xb1090000
+#define PCIBIOS_READ_CONFIG_DWORD 0xb10a0000
+#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b0000
+#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c0000
+#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d0000
+
+extern int pcibios_max_bus ( void );
+extern int pcibios_read ( struct pci_device *pci, uint32_t command,
+ uint32_t *value );
+extern int pcibios_write ( struct pci_device *pci, uint32_t command,
+ uint32_t value );
+
+/**
+ * Read byte from PCI configuration space via PCI BIOS
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcibios_read_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t *value ) {
+ uint32_t tmp;
+ int rc;
+
+ rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_BYTE | where, &tmp );
+ *value = tmp;
+ return rc;
+}
+
+/**
+ * Read word from PCI configuration space via PCI BIOS
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcibios_read_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t *value ) {
+ uint32_t tmp;
+ int rc;
+
+ rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_WORD | where, &tmp );
+ *value = tmp;
+ return rc;
+}
+
+/**
+ * Read dword from PCI configuration space via PCI BIOS
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcibios_read_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t *value ) {
+ return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value );
+}
+
+/**
+ * Write byte to PCI configuration space via PCI BIOS
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcibios_write_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t value ) {
+ return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value );
+}
+
+/**
+ * Write word to PCI configuration space via PCI BIOS
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcibios_write_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t value ) {
+ return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_WORD | where, value );
+}
+
+/**
+ * Write dword to PCI configuration space via PCI BIOS
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcibios_write_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t value ) {
+ return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value);
+}
+
+#endif /* _PCIBIOS_H */
diff --git a/gpxe/src/arch/i386/include/pcidirect.h b/gpxe/src/arch/i386/include/pcidirect.h
new file mode 100644
index 00000000..4e2e9d12
--- /dev/null
+++ b/gpxe/src/arch/i386/include/pcidirect.h
@@ -0,0 +1,126 @@
+#ifndef _PCIDIRECT_H
+#define _PCIDIRECT_H
+
+#include <stdint.h>
+#include <io.h>
+
+/** @file
+ *
+ * PCI configuration space access via Type 1 accesses
+ *
+ */
+
+#define PCIDIRECT_CONFIG_ADDRESS 0xcf8
+#define PCIDIRECT_CONFIG_DATA 0xcfc
+
+struct pci_device;
+
+extern void pcidirect_prepare ( struct pci_device *pci, int where );
+
+/**
+ * Determine maximum PCI bus number within system
+ *
+ * @ret max_bus Maximum bus number
+ */
+static inline int pcidirect_max_bus ( void ) {
+ /* No way to work this out via Type 1 accesses */
+ return 0xff;
+}
+
+/**
+ * Read byte from PCI configuration space via Type 1 access
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t *value ) {
+ pcidirect_prepare ( pci, where );
+ *value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
+ return 0;
+}
+
+/**
+ * Read word from PCI configuration space via Type 1 access
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcidirect_read_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t *value ) {
+ pcidirect_prepare ( pci, where );
+ *value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
+ return 0;
+}
+
+/**
+ * Read dword from PCI configuration space via Type 1 access
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t *value ) {
+ pcidirect_prepare ( pci, where );
+ *value = inl ( PCIDIRECT_CONFIG_DATA );
+ return 0;
+}
+
+/**
+ * Write byte to PCI configuration space via Type 1 access
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t value ) {
+ pcidirect_prepare ( pci, where );
+ outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
+ return 0;
+}
+
+/**
+ * Write word to PCI configuration space via Type 1 access
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcidirect_write_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t value ) {
+ pcidirect_prepare ( pci, where );
+ outw ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
+ return 0;
+}
+
+/**
+ * Write dword to PCI configuration space via Type 1 access
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+pcidirect_write_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t value ) {
+ pcidirect_prepare ( pci, where );
+ outl ( value, PCIDIRECT_CONFIG_DATA );
+ return 0;
+}
+
+#endif /* _PCIDIRECT_H */
diff --git a/gpxe/src/arch/i386/include/pic8259.h b/gpxe/src/arch/i386/include/pic8259.h
new file mode 100644
index 00000000..0c501a9c
--- /dev/null
+++ b/gpxe/src/arch/i386/include/pic8259.h
@@ -0,0 +1,69 @@
+/*
+ * Basic support for controlling the 8259 Programmable Interrupt Controllers.
+ *
+ * Initially written by Michael Brown (mcb30).
+ */
+
+#ifndef PIC8259_H
+#define PIC8259_H
+
+/* For segoff_t */
+#include "realmode.h"
+
+#define IRQ_PIC_CUTOFF 8
+
+/* 8259 register locations */
+#define PIC1_ICW1 0x20
+#define PIC1_OCW2 0x20
+#define PIC1_OCW3 0x20
+#define PIC1_ICR 0x20
+#define PIC1_IRR 0x20
+#define PIC1_ISR 0x20
+#define PIC1_ICW2 0x21
+#define PIC1_ICW3 0x21
+#define PIC1_ICW4 0x21
+#define PIC1_IMR 0x21
+#define PIC2_ICW1 0xa0
+#define PIC2_OCW2 0xa0
+#define PIC2_OCW3 0xa0
+#define PIC2_ICR 0xa0
+#define PIC2_IRR 0xa0
+#define PIC2_ISR 0xa0
+#define PIC2_ICW2 0xa1
+#define PIC2_ICW3 0xa1
+#define PIC2_ICW4 0xa1
+#define PIC2_IMR 0xa1
+
+/* Register command values */
+#define OCW3_ID 0x08
+#define OCW3_READ_IRR 0x03
+#define OCW3_READ_ISR 0x02
+#define ICR_EOI_NON_SPECIFIC 0x20
+#define ICR_EOI_NOP 0x40
+#define ICR_EOI_SPECIFIC 0x60
+#define ICR_EOI_SET_PRIORITY 0xc0
+
+/* Macros to enable/disable IRQs */
+#define IMR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_IMR : PIC2_IMR )
+#define IMR_BIT(x) ( 1 << ( (x) % IRQ_PIC_CUTOFF ) )
+#define irq_enabled(x) ( ( inb ( IMR_REG(x) ) & IMR_BIT(x) ) == 0 )
+#define enable_irq(x) outb ( inb( IMR_REG(x) ) & ~IMR_BIT(x), IMR_REG(x) )
+#define disable_irq(x) outb ( inb( IMR_REG(x) ) | IMR_BIT(x), IMR_REG(x) )
+
+/* Macros for acknowledging IRQs */
+#define ICR_REG( irq ) ( (irq) < IRQ_PIC_CUTOFF ? PIC1_ICR : PIC2_ICR )
+#define ICR_VALUE( irq ) ( (irq) % IRQ_PIC_CUTOFF )
+#define CHAINED_IRQ 2
+
+/* Utility macros to convert IRQ numbers to INT numbers and INT vectors */
+#define IRQ_INT( irq ) ( ( ( (irq) - IRQ_PIC_CUTOFF ) ^ 0x70 ) & 0x7f )
+
+/* Other constants */
+#define IRQ_MAX 15
+#define IRQ_NONE -1U
+
+/* Function prototypes
+ */
+void send_eoi ( unsigned int irq );
+
+#endif /* PIC8259_H */
diff --git a/gpxe/src/arch/i386/include/pnpbios.h b/gpxe/src/arch/i386/include/pnpbios.h
new file mode 100644
index 00000000..ab31c699
--- /dev/null
+++ b/gpxe/src/arch/i386/include/pnpbios.h
@@ -0,0 +1,15 @@
+#ifndef _PNPBIOS_H
+#define _PNPBIOS_H
+
+/** @file
+ *
+ * PnP BIOS
+ *
+ */
+
+/* BIOS segment address */
+#define BIOS_SEG 0xf000
+
+extern int find_pnp_bios ( void );
+
+#endif /* _PNPBIOS_H */
diff --git a/gpxe/src/arch/i386/include/pxe_addr.h b/gpxe/src/arch/i386/include/pxe_addr.h
new file mode 100644
index 00000000..954551e8
--- /dev/null
+++ b/gpxe/src/arch/i386/include/pxe_addr.h
@@ -0,0 +1,17 @@
+/*
+ * Architecture-specific portion of pxe.h for Etherboot
+ *
+ * This file has to define the types SEGOFF16_t, SEGDESC_t and
+ * SEGSEL_t for use in other PXE structures. See pxe.h for details.
+ */
+
+#ifndef PXE_ADDR_H
+#define PXE_ADDR_H
+
+#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) )
+#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) )
+#define PTR_TO_SEGOFF16(ptr,segoff16) \
+ (segoff16).segment = SEGMENT(ptr); \
+ (segoff16).offset = OFFSET(ptr);
+
+#endif /* PXE_ADDR_H */
diff --git a/gpxe/src/arch/i386/include/pxe_call.h b/gpxe/src/arch/i386/include/pxe_call.h
new file mode 100644
index 00000000..dc585310
--- /dev/null
+++ b/gpxe/src/arch/i386/include/pxe_call.h
@@ -0,0 +1,34 @@
+#ifndef _PXE_CALL_H
+#define _PXE_CALL_H
+
+/** @file
+ *
+ * PXE API entry point
+ */
+
+#include <pxe_api.h>
+#include <realmode.h>
+
+/** PXE load address segment */
+#define PXE_LOAD_SEGMENT 0
+
+/** PXE load address offset */
+#define PXE_LOAD_OFFSET 0x7c00
+
+/** PXE physical load address */
+#define PXE_LOAD_PHYS ( ( PXE_LOAD_SEGMENT << 4 ) + PXE_LOAD_OFFSET )
+
+/** !PXE structure */
+extern struct s_PXE __text16 ( ppxe );
+#define ppxe __use_text16 ( ppxe )
+
+/** PXENV+ structure */
+extern struct s_PXENV __text16 ( pxenv );
+#define pxenv __use_text16 ( pxenv )
+
+extern void pxe_hook_int1a ( void );
+extern int pxe_unhook_int1a ( void );
+extern void pxe_init_structures ( void );
+extern int pxe_start_nbp ( void );
+
+#endif /* _PXE_CALL_H */
diff --git a/gpxe/src/arch/i386/include/realmode.h b/gpxe/src/arch/i386/include/realmode.h
new file mode 100644
index 00000000..5d3ddf50
--- /dev/null
+++ b/gpxe/src/arch/i386/include/realmode.h
@@ -0,0 +1,128 @@
+#ifndef REALMODE_H
+#define REALMODE_H
+
+#ifndef ASSEMBLY
+
+#include "stdint.h"
+#include "registers.h"
+#include "io.h"
+
+/*
+ * Data structures and type definitions
+ *
+ */
+
+/* Segment:offset structure. Note that the order within the structure
+ * is offset:segment.
+ */
+struct segoff {
+ uint16_t offset;
+ uint16_t segment;
+} __attribute__ (( packed ));
+
+typedef struct segoff segoff_t;
+
+/* Macro hackery needed to stringify bits of inline assembly */
+#define RM_XSTR(x) #x
+#define RM_STR(x) RM_XSTR(x)
+
+/* Drag in the selected real-mode transition library header */
+#ifdef KEEP_IT_REAL
+#include "libkir.h"
+#else
+#include "librm.h"
+#endif
+
+/*
+ * The API to some functions is identical between librm and libkir, so
+ * they are documented here, even though the prototypes are in librm.h
+ * and libkir.h.
+ *
+ */
+
+/*
+ * Declaration of variables in .data16
+ *
+ * To place a variable in the .data16 segment, declare it using the
+ * pattern:
+ *
+ * int __data16 ( foo );
+ * #define foo __use_data16 ( foo );
+ *
+ * extern uint32_t __data16 ( bar );
+ * #define bar __use_data16 ( bar );
+ *
+ * static long __data16 ( baz ) = 0xff000000UL;
+ * #define baz __use_data16 ( baz );
+ *
+ * i.e. take a normal declaration, add __data16() around the variable
+ * name, and add a line saying "#define <name> __use_data16 ( <name> )
+ *
+ * You can then access them just like any other variable, for example
+ *
+ * int x = foo + bar;
+ *
+ * This magic is achieved at a cost of only around 7 extra bytes per
+ * group of accesses to .data16 variables. When using KEEP_IT_REAL,
+ * there is no extra cost.
+ *
+ * You should place variables in .data16 when they need to be accessed
+ * by real-mode code. Real-mode assembly (e.g. as created by
+ * REAL_CODE()) can access these variables via the usual data segment.
+ * You can therefore write something like
+ *
+ * static uint16_t __data16 ( foo );
+ * #define foo __use_data16 ( foo )
+ *
+ * int bar ( void ) {
+ * __asm__ __volatile__ ( REAL_CODE ( "int $0xff\n\t"
+ * "movw %ax, foo" )
+ * : : );
+ * return foo;
+ * }
+ *
+ * Variables may also be placed in .text16 using __text16 and
+ * __use_text16. Some variables (e.g. chained interrupt vectors) fit
+ * most naturally in .text16; most should be in .data16.
+ *
+ * If you have only a pointer to a magic symbol within .data16 or
+ * .text16, rather than the symbol itself, you can attempt to extract
+ * the underlying symbol name using __from_data16() or
+ * __from_text16(). This is not for the faint-hearted; check the
+ * assembler output to make sure that it's doing the right thing.
+ */
+
+/*
+ * void copy_to_real ( uint16_t dest_seg, uint16_t dest_off,
+ * void *src, size_t n )
+ * void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off,
+ * size_t n )
+ *
+ * These functions can be used to copy data to and from arbitrary
+ * locations in base memory.
+ */
+
+/*
+ * put_real ( variable, uint16_t dest_seg, uint16_t dest_off )
+ * get_real ( variable, uint16_t src_seg, uint16_t src_off )
+ *
+ * These macros can be used to read or write single variables to and
+ * from arbitrary locations in base memory. "variable" must be a
+ * variable of either 1, 2 or 4 bytes in length.
+ */
+
+/*
+ * REAL_CODE ( asm_code_str )
+ *
+ * This can be used in inline assembly to create a fragment of code
+ * that will execute in real mode. For example: to write a character
+ * to the BIOS console using INT 10, you would do something like:
+ *
+ * __asm__ __volatile__ ( REAL_CODE ( "int $0x16" )
+ * : "=a" ( character ) : "a" ( 0x0000 ) );
+ *
+ */
+
+#endif /* ASSEMBLY */
+
+#endif /* REALMODE_H */
diff --git a/gpxe/src/arch/i386/include/registers.h b/gpxe/src/arch/i386/include/registers.h
new file mode 100644
index 00000000..2b9b2b43
--- /dev/null
+++ b/gpxe/src/arch/i386/include/registers.h
@@ -0,0 +1,187 @@
+#ifndef REGISTERS_H
+#define REGISTERS_H
+
+/** @file
+ *
+ * i386 registers.
+ *
+ * This file defines data structures that allow easy access to i386
+ * register dumps.
+ *
+ */
+
+#include "compiler.h" /* for doxygen */
+#include "stdint.h"
+
+/**
+ * A 16-bit general register.
+ *
+ * This type encapsulates a 16-bit register such as %ax, %bx, %cx,
+ * %dx, %si, %di, %bp or %sp.
+ *
+ */
+typedef union {
+ struct {
+ union {
+ uint8_t l;
+ uint8_t byte;
+ };
+ uint8_t h;
+ } PACKED;
+ uint16_t word;
+} PACKED reg16_t;
+
+/**
+ * A 32-bit general register.
+ *
+ * This type encapsulates a 32-bit register such as %eax, %ebx, %ecx,
+ * %edx, %esi, %edi, %ebp or %esp.
+ *
+ */
+typedef union {
+ struct {
+ union {
+ uint8_t l;
+ uint8_t byte;
+ };
+ uint8_t h;
+ } PACKED;
+ uint16_t word;
+ uint32_t dword;
+} PACKED reg32_t;
+
+/**
+ * A 32-bit general register dump.
+ *
+ * This is the data structure that is created on the stack by the @c
+ * pushal instruction, and can be read back using the @c popal
+ * instruction.
+ *
+ */
+struct i386_regs {
+ union {
+ uint16_t di;
+ uint32_t edi;
+ };
+ union {
+ uint16_t si;
+ uint32_t esi;
+ };
+ union {
+ uint16_t bp;
+ uint32_t ebp;
+ };
+ union {
+ uint16_t sp;
+ uint32_t esp;
+ };
+ union {
+ struct {
+ uint8_t bl;
+ uint8_t bh;
+ } PACKED;
+ uint16_t bx;
+ uint32_t ebx;
+ };
+ union {
+ struct {
+ uint8_t dl;
+ uint8_t dh;
+ } PACKED;
+ uint16_t dx;
+ uint32_t edx;
+ };
+ union {
+ struct {
+ uint8_t cl;
+ uint8_t ch;
+ } PACKED;
+ uint16_t cx;
+ uint32_t ecx;
+ };
+ union {
+ struct {
+ uint8_t al;
+ uint8_t ah;
+ } PACKED;
+ uint16_t ax;
+ uint32_t eax;
+ };
+} PACKED;
+
+/**
+ * A segment register dump.
+ *
+ * The i386 has no equivalent of the @c pushal or @c popal
+ * instructions for the segment registers. We adopt the convention of
+ * always using the sequences
+ *
+ * @code
+ *
+ * pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and
+ *
+ * @code
+ *
+ * addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ *
+ * @endcode
+ *
+ * This is the data structure that is created and read back by these
+ * instruction sequences.
+ *
+ */
+struct i386_seg_regs {
+ uint16_t cs;
+ uint16_t ss;
+ uint16_t ds;
+ uint16_t es;
+ uint16_t fs;
+ uint16_t gs;
+} PACKED;
+
+/**
+ * A full register dump.
+ *
+ * This data structure is created by the instructions
+ *
+ * @code
+ *
+ * pushfl
+ * pushal
+ * pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and can be read back using the instructions
+ *
+ * @code
+ *
+ * addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ * popal
+ * popfl
+ *
+ * @endcode
+ *
+ * prot_call() and kir_call() create this data structure on the stack
+ * and pass in a pointer to this structure.
+ *
+ */
+struct i386_all_regs {
+ struct i386_seg_regs segs;
+ struct i386_regs regs;
+ uint32_t flags;
+} PACKED;
+
+/* Flags */
+#define CF ( 1 << 0 )
+#define PF ( 1 << 2 )
+#define AF ( 1 << 4 )
+#define ZF ( 1 << 6 )
+#define SF ( 1 << 7 )
+#define OF ( 1 << 11 )
+
+#endif /* REGISTERS_H */
diff --git a/gpxe/src/arch/i386/include/setjmp.h b/gpxe/src/arch/i386/include/setjmp.h
new file mode 100644
index 00000000..ed2be270
--- /dev/null
+++ b/gpxe/src/arch/i386/include/setjmp.h
@@ -0,0 +1,12 @@
+#ifndef ETHERBOOT_SETJMP_H
+#define ETHERBOOT_SETJMP_H
+
+
+/* Define a type for use by setjmp and longjmp */
+#define JBLEN 6
+typedef unsigned long jmp_buf[JBLEN];
+
+extern int setjmp (jmp_buf env);
+extern void longjmp (jmp_buf env, int val);
+
+#endif /* ETHERBOOT_SETJMP_H */
diff --git a/gpxe/src/arch/i386/include/smbios.h b/gpxe/src/arch/i386/include/smbios.h
new file mode 100644
index 00000000..821eda17
--- /dev/null
+++ b/gpxe/src/arch/i386/include/smbios.h
@@ -0,0 +1,51 @@
+#ifndef _SMBIOS_H
+#define _SMBIOS_H
+
+/** @file
+ *
+ * System Management BIOS
+ */
+
+#include <stdint.h>
+
+/** An SMBIOS structure header */
+struct smbios_header {
+ /** Type */
+ uint8_t type;
+ /** Length */
+ uint8_t length;
+ /** Handle */
+ uint16_t handle;
+} __attribute__ (( packed ));
+
+/** SMBIOS system information structure */
+struct smbios_system_information {
+ /** SMBIOS structure header */
+ struct smbios_header header;
+ /** Manufacturer string */
+ uint8_t manufacturer;
+ /** Product string */
+ uint8_t product;
+ /** Version string */
+ uint8_t version;
+ /** Serial number string */
+ uint8_t serial;
+ /** UUID */
+ uint8_t uuid[16];
+ /** Wake-up type */
+ uint8_t wakeup;
+} __attribute__ (( packed ));
+
+/** SMBIOS system information structure type */
+#define SMBIOS_TYPE_SYSTEM_INFORMATION 1
+
+struct smbios_strings;
+extern int find_smbios_structure ( unsigned int type,
+ void *structure, size_t length,
+ struct smbios_strings *strings );
+extern int find_smbios_string ( struct smbios_strings *strings,
+ unsigned int index,
+ char *buffer, size_t length );
+extern int smbios_get_uuid ( union uuid *uuid );
+
+#endif /* _SMBIOS_H */
diff --git a/gpxe/src/arch/i386/include/undi.h b/gpxe/src/arch/i386/include/undi.h
new file mode 100644
index 00000000..9936e17f
--- /dev/null
+++ b/gpxe/src/arch/i386/include/undi.h
@@ -0,0 +1,102 @@
+#ifndef _UNDI_H
+#define _UNDI_H
+
+/** @file
+ *
+ * UNDI driver
+ *
+ */
+
+#ifndef ASSEMBLY
+
+#include <gpxe/device.h>
+#include <pxe_types.h>
+
+/** An UNDI device
+ *
+ * This structure is used by assembly code as well as C; do not alter
+ * this structure without editing pxeprefix.S to match.
+ */
+struct undi_device {
+ /** PXENV+ structure address */
+ SEGOFF16_t pxenv;
+ /** !PXE structure address */
+ SEGOFF16_t ppxe;
+ /** Entry point */
+ SEGOFF16_t entry;
+ /** Return stack */
+ UINT16_t return_stack[3];
+ /** Return type */
+ UINT16_t return_type;
+ /** Free base memory after load */
+ UINT16_t fbms;
+ /** Free base memory prior to load */
+ UINT16_t restore_fbms;
+ /** PCI bus:dev.fn, or @c UNDI_NO_PCI_BUSDEVFN */
+ UINT16_t pci_busdevfn;
+ /** ISAPnP card select number, or @c UNDI_NO_ISAPNP_CSN */
+ UINT16_t isapnp_csn;
+ /** ISAPnP read port, or @c UNDI_NO_ISAPNP_READ_PORT */
+ UINT16_t isapnp_read_port;
+ /** PCI vendor ID
+ *
+ * Filled in only for the preloaded UNDI device by pxeprefix.S
+ */
+ UINT16_t pci_vendor;
+ /** PCI device ID
+ *
+ * Filled in only for the preloaded UNDI device by pxeprefix.S
+ */
+ UINT16_t pci_device;
+ /** Flags
+ *
+ * This is the bitwise OR of zero or more UNDI_FL_XXX
+ * constants.
+ */
+ UINT16_t flags;
+
+ /** Generic device */
+ struct device dev;
+ /** Driver-private data
+ *
+ * Use undi_set_drvdata() and undi_get_drvdata() to access this
+ * field.
+ */
+ void *priv;
+} __attribute__ (( packed ));
+
+/**
+ * Set UNDI driver-private data
+ *
+ * @v undi UNDI device
+ * @v priv Private data
+ */
+static inline void undi_set_drvdata ( struct undi_device *undi, void *priv ) {
+ undi->priv = priv;
+}
+
+/**
+ * Get UNDI driver-private data
+ *
+ * @v undi UNDI device
+ * @ret priv Private data
+ */
+static inline void * undi_get_drvdata ( struct undi_device *undi ) {
+ return undi->priv;
+}
+
+#endif /* ASSEMBLY */
+
+/** PCI bus:dev.fn field is invalid */
+#define UNDI_NO_PCI_BUSDEVFN 0xffff
+
+/** ISAPnP card select number field is invalid */
+#define UNDI_NO_ISAPNP_CSN 0xffff
+
+/** ISAPnP read port field is invalid */
+#define UNDI_NO_ISAPNP_READ_PORT 0xffff
+
+/** UNDI flag: START_UNDI has been called */
+#define UNDI_FL_STARTED 0x0001
+
+#endif /* _UNDI_H */
diff --git a/gpxe/src/arch/i386/include/undiload.h b/gpxe/src/arch/i386/include/undiload.h
new file mode 100644
index 00000000..bfc11874
--- /dev/null
+++ b/gpxe/src/arch/i386/include/undiload.h
@@ -0,0 +1,33 @@
+#ifndef _UNDILOAD_H
+#define _UNDILOAD_H
+
+/** @file
+ *
+ * UNDI load/unload
+ *
+ */
+
+struct undi_device;
+struct undi_rom;
+
+extern int undi_load ( struct undi_device *undi, struct undi_rom *undirom );
+extern int undi_unload ( struct undi_device *undi );
+
+/**
+ * Call UNDI loader to create a pixie
+ *
+ * @v undi UNDI device
+ * @v undirom UNDI ROM
+ * @v pci_busdevfn PCI bus:dev.fn
+ * @ret rc Return status code
+ */
+static inline int undi_load_pci ( struct undi_device *undi,
+ struct undi_rom *undirom,
+ unsigned int pci_busdevfn ) {
+ undi->pci_busdevfn = pci_busdevfn;
+ undi->isapnp_csn = UNDI_NO_ISAPNP_CSN;
+ undi->isapnp_read_port = UNDI_NO_ISAPNP_READ_PORT;
+ return undi_load ( undi, undirom );
+}
+
+#endif /* _UNDILOAD_H */
diff --git a/gpxe/src/arch/i386/include/undinet.h b/gpxe/src/arch/i386/include/undinet.h
new file mode 100644
index 00000000..1a4a385e
--- /dev/null
+++ b/gpxe/src/arch/i386/include/undinet.h
@@ -0,0 +1,15 @@
+#ifndef _UNDINET_H
+#define _UNDINET_H
+
+/** @file
+ *
+ * UNDI network device driver
+ *
+ */
+
+struct undi_device;
+
+extern int undinet_probe ( struct undi_device *undi );
+extern void undinet_remove ( struct undi_device *undi );
+
+#endif /* _UNDINET_H */
diff --git a/gpxe/src/arch/i386/include/undipreload.h b/gpxe/src/arch/i386/include/undipreload.h
new file mode 100644
index 00000000..d9bc8cb9
--- /dev/null
+++ b/gpxe/src/arch/i386/include/undipreload.h
@@ -0,0 +1,16 @@
+#ifndef _UNDIPRELOAD_H
+#define _UNDIPRELOAD_H
+
+/** @file
+ *
+ * Preloaded UNDI stack
+ *
+ */
+
+#include <realmode.h>
+#include <undi.h>
+
+extern struct undi_device __data16 ( preloaded_undi );
+#define preloaded_undi __use_data16 ( preloaded_undi )
+
+#endif /* _UNDIPRELOAD_H */
diff --git a/gpxe/src/arch/i386/include/undirom.h b/gpxe/src/arch/i386/include/undirom.h
new file mode 100644
index 00000000..a2636007
--- /dev/null
+++ b/gpxe/src/arch/i386/include/undirom.h
@@ -0,0 +1,51 @@
+#ifndef _UNDIROM_H
+#define _UNDIROM_H
+
+/** @file
+ *
+ * UNDI expansion ROMs
+ *
+ */
+
+#include <pxe_types.h>
+
+/** An UNDI PCI device ID */
+struct undi_pci_device_id {
+ /** PCI vendor ID */
+ unsigned int vendor_id;
+ /** PCI device ID */
+ unsigned int device_id;
+};
+
+/** An UNDI device ID */
+union undi_device_id {
+ /** PCI device ID */
+ struct undi_pci_device_id pci;
+};
+
+/** An UNDI ROM */
+struct undi_rom {
+ /** List of UNDI ROMs */
+ struct list_head list;
+ /** ROM segment address */
+ unsigned int rom_segment;
+ /** UNDI loader entry point */
+ SEGOFF16_t loader_entry;
+ /** Code segment size */
+ size_t code_size;
+ /** Data segment size */
+ size_t data_size;
+ /** Bus type
+ *
+ * Values are as used by @c PXENV_UNDI_GET_NIC_TYPE
+ */
+ unsigned int bus_type;
+ /** Device ID */
+ union undi_device_id bus_id;
+};
+
+extern struct undi_rom * undirom_find_pci ( unsigned int vendor_id,
+ unsigned int device_id,
+ unsigned int rombase );
+
+#endif /* _UNDIROM_H */
diff --git a/gpxe/src/arch/i386/include/vga.h b/gpxe/src/arch/i386/include/vga.h
new file mode 100644
index 00000000..01fc39d8
--- /dev/null
+++ b/gpxe/src/arch/i386/include/vga.h
@@ -0,0 +1,228 @@
+/*
+ *
+ * modified
+ * by Steve M. Gehlbach <steve@kesa.com>
+ *
+ * Originally from linux/drivers/video/vga16.c by
+ * Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
+ * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#ifndef VGA_H_INCL
+#define VGA_H_INCL 1
+
+//#include <cpu/p5/io.h>
+
+#define u8 unsigned char
+#define u16 unsigned short
+#define u32 unsigned int
+#define __u32 u32
+
+#define VERROR -1
+#define CHAR_HEIGHT 16
+#define LINES 25
+#define COLS 80
+
+// macros for writing to vga regs
+#define write_crtc(data,addr) outb(addr,CRT_IC); outb(data,CRT_DC)
+#define write_att(data,addr) inb(IS1_RC); inb(0x80); outb(addr,ATT_IW); inb(0x80); outb(data,ATT_IW); inb(0x80)
+#define write_seq(data,addr) outb(addr,SEQ_I); outb(data,SEQ_D)
+#define write_gra(data,addr) outb(addr,GRA_I); outb(data,GRA_D)
+u8 read_seq_b(u16 addr);
+u8 read_gra_b(u16 addr);
+u8 read_crtc_b(u16 addr);
+u8 read_att_b(u16 addr);
+
+
+#ifdef VGA_HARDWARE_FIXUP
+void vga_hardware_fixup(void);
+#else
+#define vga_hardware_fixup() do{} while(0)
+#endif
+
+#define SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */
+#define SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */
+#define SYNC_EXT 4 /* external sync */
+#define SYNC_COMP_HIGH_ACT 8 /* composite sync high active */
+#define SYNC_BROADCAST 16 /* broadcast video timings */
+ /* vtotal = 144d/288n/576i => PAL */
+ /* vtotal = 121d/242n/484i => NTSC */
+
+#define SYNC_ON_GREEN 32 /* sync on green */
+
+#define VMODE_NONINTERLACED 0 /* non interlaced */
+#define VMODE_INTERLACED 1 /* interlaced */
+#define VMODE_DOUBLE 2 /* double scan */
+#define VMODE_MASK 255
+
+#define VMODE_YWRAP 256 /* ywrap instead of panning */
+#define VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
+#define VMODE_CONUPDATE 512 /* don't update x/yoffset */
+
+/* VGA data register ports */
+#define CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
+#define CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */
+#define ATT_R 0x3C1 /* Attribute Controller Data Read Register */
+#define GRA_D 0x3CF /* Graphics Controller Data Register */
+#define SEQ_D 0x3C5 /* Sequencer Data Register */
+
+#define MIS_R 0x3CC // Misc Output Read Register
+#define MIS_W 0x3C2 // Misc Output Write Register
+
+#define IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
+#define IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
+#define PEL_D 0x3C9 /* PEL Data Register */
+#define PEL_MSK 0x3C6 /* PEL mask register */
+
+/* EGA-specific registers */
+#define GRA_E0 0x3CC /* Graphics enable processor 0 */
+#define GRA_E1 0x3CA /* Graphics enable processor 1 */
+
+
+/* VGA index register ports */
+#define CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
+#define CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */
+#define ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
+#define GRA_I 0x3CE /* Graphics Controller Index */
+#define SEQ_I 0x3C4 /* Sequencer Index */
+#define PEL_IW 0x3C8 /* PEL Write Index */
+#define PEL_IR 0x3C7 /* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define CRTC_C 25 /* 25 CRT Controller Registers sequentially set*/
+ // the remainder are not in the par array
+#define ATT_C 21 /* 21 Attribute Controller Registers */
+#define GRA_C 9 /* 9 Graphics Controller Registers */
+#define SEQ_C 5 /* 5 Sequencer Registers */
+#define MIS_C 1 /* 1 Misc Output Register */
+
+#define CRTC_H_TOTAL 0
+#define CRTC_H_DISP 1
+#define CRTC_H_BLANK_START 2
+#define CRTC_H_BLANK_END 3
+#define CRTC_H_SYNC_START 4
+#define CRTC_H_SYNC_END 5
+#define CRTC_V_TOTAL 6
+#define CRTC_OVERFLOW 7
+#define CRTC_PRESET_ROW 8
+#define CRTC_MAX_SCAN 9
+#define CRTC_CURSOR_START 0x0A
+#define CRTC_CURSOR_END 0x0B
+#define CRTC_START_HI 0x0C
+#define CRTC_START_LO 0x0D
+#define CRTC_CURSOR_HI 0x0E
+#define CRTC_CURSOR_LO 0x0F
+#define CRTC_V_SYNC_START 0x10
+#define CRTC_V_SYNC_END 0x11
+#define CRTC_V_DISP_END 0x12
+#define CRTC_OFFSET 0x13
+#define CRTC_UNDERLINE 0x14
+#define CRTC_V_BLANK_START 0x15
+#define CRTC_V_BLANK_END 0x16
+#define CRTC_MODE 0x17
+#define CRTC_LINE_COMPARE 0x18
+
+#define ATC_MODE 0x10
+#define ATC_OVERSCAN 0x11
+#define ATC_PLANE_ENABLE 0x12
+#define ATC_PEL 0x13
+#define ATC_COLOR_PAGE 0x14
+
+#define SEQ_CLOCK_MODE 0x01
+#define SEQ_PLANE_WRITE 0x02
+#define SEQ_CHARACTER_MAP 0x03
+#define SEQ_MEMORY_MODE 0x04
+
+#define GDC_SR_VALUE 0x00
+#define GDC_SR_ENABLE 0x01
+#define GDC_COMPARE_VALUE 0x02
+#define GDC_DATA_ROTATE 0x03
+#define GDC_PLANE_READ 0x04
+#define GDC_MODE 0x05
+#define GDC_MISC 0x06
+#define GDC_COMPARE_MASK 0x07
+#define GDC_BIT_MASK 0x08
+
+// text attributes
+#define VGA_ATTR_CLR_RED 0x4
+#define VGA_ATTR_CLR_GRN 0x2
+#define VGA_ATTR_CLR_BLU 0x1
+#define VGA_ATTR_CLR_YEL (VGA_ATTR_CLR_RED | VGA_ATTR_CLR_GRN)
+#define VGA_ATTR_CLR_CYN (VGA_ATTR_CLR_GRN | VGA_ATTR_CLR_BLU)
+#define VGA_ATTR_CLR_MAG (VGA_ATTR_CLR_BLU | VGA_ATTR_CLR_RED)
+#define VGA_ATTR_CLR_BLK 0
+#define VGA_ATTR_CLR_WHT (VGA_ATTR_CLR_RED | VGA_ATTR_CLR_GRN | VGA_ATTR_CLR_BLU)
+#define VGA_ATTR_BNK 0x80
+#define VGA_ATTR_ITN 0x08
+
+/*
+ * vga register parameters
+ * these are copied to the
+ * registers.
+ *
+ */
+struct vga_par {
+ u8 crtc[CRTC_C];
+ u8 atc[ATT_C];
+ u8 gdc[GRA_C];
+ u8 seq[SEQ_C];
+ u8 misc; // the misc register, MIS_W
+ u8 vss;
+};
+
+
+/* Interpretation of offset for color fields: All offsets are from the right,
+ * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
+ * can use the offset as right argument to <<). A pixel afterwards is a bit
+ * stream and is written to video memory as that unmodified. This implies
+ * big-endian byte order if bits_per_pixel is greater than 8.
+ */
+struct fb_bitfield {
+ __u32 offset; /* beginning of bitfield */
+ __u32 length; /* length of bitfield */
+ __u32 msb_right; /* != 0 : Most significant bit is */
+ /* right */
+};
+
+struct screeninfo {
+ __u32 xres; /* visible resolution */
+ __u32 yres;
+ __u32 xres_virtual; /* virtual resolution */
+ __u32 yres_virtual;
+ __u32 xoffset; /* offset from virtual to visible */
+ __u32 yoffset; /* resolution */
+
+ __u32 bits_per_pixel; /* guess what */
+ __u32 grayscale; /* != 0 Graylevels instead of colors */
+
+ struct fb_bitfield red; /* bitfield in fb mem if true color, */
+ struct fb_bitfield green; /* else only length is significant */
+ struct fb_bitfield blue;
+ struct fb_bitfield transp; /* transparency */
+
+ __u32 nonstd; /* != 0 Non standard pixel format */
+
+ __u32 activate; /* see FB_ACTIVATE_* */
+
+ __u32 height; /* height of picture in mm */
+ __u32 width; /* width of picture in mm */
+
+ __u32 accel_flags; /* acceleration flags (hints) */
+
+ /* Timing: All values in pixclocks, except pixclock (of course) */
+ __u32 pixclock; /* pixel clock in ps (pico seconds) */
+ __u32 left_margin; /* time from sync to picture */
+ __u32 right_margin; /* time from picture to sync */
+ __u32 upper_margin; /* time from sync to picture */
+ __u32 lower_margin;
+ __u32 hsync_len; /* length of horizontal sync */
+ __u32 vsync_len; /* length of vertical sync */
+ __u32 sync; /* sync polarity */
+ __u32 vmode; /* interlaced etc */
+ __u32 reserved[6]; /* Reserved for future compatibility */
+};
+
+#endif
diff --git a/gpxe/src/arch/i386/include/virtaddr.h b/gpxe/src/arch/i386/include/virtaddr.h
new file mode 100644
index 00000000..f2ffa2a1
--- /dev/null
+++ b/gpxe/src/arch/i386/include/virtaddr.h
@@ -0,0 +1,105 @@
+#ifndef VIRTADDR_H
+#define VIRTADDR_H
+
+/* Segment selectors as used in our protected-mode GDTs.
+ *
+ * Don't change these unless you really know what you're doing.
+ */
+
+#define VIRTUAL_CS 0x08
+#define VIRTUAL_DS 0x10
+#define PHYSICAL_CS 0x18
+#define PHYSICAL_DS 0x20
+#define REAL_CS 0x28
+#define REAL_DS 0x30
+#if 0
+#define LONG_CS 0x38
+#define LONG_DS 0x40
+#endif
+
+#ifndef ASSEMBLY
+
+#include "stdint.h"
+#include "string.h"
+
+#ifndef KEEP_IT_REAL
+
+/*
+ * Without -DKEEP_IT_REAL, we are in 32-bit protected mode with a
+ * fixed link address but an unknown physical start address. Our GDT
+ * sets up code and data segments with an offset of virt_offset, so
+ * that link-time addresses can still work.
+ *
+ */
+
+/* C-callable function prototypes */
+
+extern void relocate_to ( uint32_t new_phys_addr );
+
+/* Variables in virtaddr.S */
+extern unsigned long virt_offset;
+
+/*
+ * Convert between virtual and physical addresses
+ *
+ */
+static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
+ return ( ( unsigned long ) virt_addr ) + virt_offset;
+}
+
+static inline void * phys_to_virt ( unsigned long phys_addr ) {
+ return ( void * ) ( phys_addr - virt_offset );
+}
+
+static inline void copy_to_phys ( physaddr_t dest, const void *src,
+ size_t len ) {
+ memcpy ( phys_to_virt ( dest ), src, len );
+}
+
+static inline void copy_from_phys ( void *dest, physaddr_t src, size_t len ) {
+ memcpy ( dest, phys_to_virt ( src ), len );
+}
+
+static inline void copy_phys_to_phys ( physaddr_t dest, physaddr_t src,
+ size_t len ) {
+ memcpy ( phys_to_virt ( dest ), phys_to_virt ( src ), len );
+}
+
+#else /* KEEP_IT_REAL */
+
+/*
+ * With -DKEEP_IT_REAL, we are in 16-bit real mode with fixed link
+ * addresses and a segmented memory model. We have separate code and
+ * data segments.
+ *
+ * Because we may be called in 16-bit protected mode (damn PXE spec),
+ * we cannot simply assume that physical = segment * 16 + offset.
+ * Instead, we have to look up the physical start address of the
+ * segment in the !PXE structure. We have to assume that
+ * virt_to_phys() is called only on pointers within the data segment,
+ * because nothing passes segment information to us.
+ *
+ * We don't implement phys_to_virt at all, because there will be many
+ * addresses that simply cannot be reached via a virtual address when
+ * the virtual address space is limited to 64kB!
+ */
+
+static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
+ /* Cheat: just for now, do the segment*16+offset calculation */
+ uint16_t ds;
+
+ __asm__ ( "movw %%ds, %%ax" : "=a" ( ds ) : );
+ return ( 16 * ds + ( ( unsigned long ) virt_addr ) );
+}
+
+/* Define it as a deprecated function so that we get compile-time
+ * warnings, rather than just the link-time errors.
+ */
+extern void * phys_to_virt ( unsigned long phys_addr )
+ __attribute__ ((deprecated));
+
+#endif /* KEEP_IT_REAL */
+
+#endif /* ASSEMBLY */
+
+#endif /* VIRTADDR_H */