diff options
Diffstat (limited to 'gpxe/src/arch/i386/include')
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 */ |