diff options
Diffstat (limited to 'src/arch/i386')
26 files changed, 649 insertions, 142 deletions
diff --git a/src/arch/i386/Config b/src/arch/i386/Config index db80b38e..03836c8b 100644 --- a/src/arch/i386/Config +++ b/src/arch/i386/Config @@ -133,7 +133,7 @@ CFLAGS+= -falign-jumps=1 -falign-loops=1 -falign-functions=1 endif GCC_MINORVERSION = $(word 2, $(GCC_VERSION)) ifneq ($(GCC_MINORVERSION),4) -CFLAGS+= -mcpu=i386 +CFLAGS+= -march=i386 endif LDFLAGS+= -N diff --git a/src/arch/i386/Makefile b/src/arch/i386/Makefile index 9f207ea0..94b85c80 100644 --- a/src/arch/i386/Makefile +++ b/src/arch/i386/Makefile @@ -1,7 +1,7 @@ # i386-specific directories containing source files # SRCDIRS += arch/i386/core arch/i386/transitions arch/i386/prefix -SRCDIRS += arch/i386/firmware/pcbios arch/i386/firmware/linuxbios +SRCDIRS += arch/i386/firmware/pcbios SRCDIRS += arch/i386/image SRCDIRS += arch/i386/drivers/bus SRCDIRS += arch/i386/drivers/net @@ -82,6 +82,10 @@ MEDIA += dsk OBJS_dskprefix = dskprefix zdskprefix CFLAGS_zdskprefix = $(CFLAGS_ZPREFIX) +MEDIA += hd +OBJS_hdprefix = hdprefix zhdprefix +CFLAGS_zhdprefix = $(CFLAGS_ZPREFIX) + MEDIA += raw OBJS_rawprefix = rawprefix zrawprefix CFLAGS_zrawprefix = $(CFLAGS_ZPREFIX) diff --git a/src/arch/i386/core/freebsd_loader.c b/src/arch/i386/core/freebsd_loader.c index 4e820e8e..464f6d93 100644 --- a/src/arch/i386/core/freebsd_loader.c +++ b/src/arch/i386/core/freebsd_loader.c @@ -216,7 +216,7 @@ static int elf_freebsd_debug_loader(unsigned int offset) estate.toread, estate.curaddr); #endif /* Save where we are loading this... */ - symtab_load = phys_to_virt(estate.curaddr); + symtab_load = estate.curaddr; *((long *)phys_to_virt(estate.curaddr)) = estate.toread; estate.curaddr += sizeof(long); @@ -244,7 +244,7 @@ static int elf_freebsd_debug_loader(unsigned int offset) estate.toread, estate.curaddr); #endif /* Save where we are loading this... */ - symstr_load = phys_to_virt(estate.curaddr); + symstr_load = estate.curaddr; *((long *)phys_to_virt(estate.curaddr)) = estate.toread; estate.curaddr += sizeof(long); @@ -290,7 +290,7 @@ static void elf_freebsd_boot(unsigned long entry) /* Assumes size of long is a power of 2... */ bsdinfo.bi_esymtab = (symstr_load + sizeof(long) + - *((long *)symstr_load) + + *((long *)phys_to_virt(symstr_load)) + sizeof(long) - 1) & ~(sizeof(long) - 1); /* Where we will build the meta data... */ diff --git a/src/arch/i386/core/hooks.c b/src/arch/i386/core/hooks.c index b2c82a1e..313dc618 100644 --- a/src/arch/i386/core/hooks.c +++ b/src/arch/i386/core/hooks.c @@ -13,20 +13,20 @@ * the prefix requested. * */ -void arch_main ( struct i386_all_regs *regs ) { - void (*exit_path) ( struct i386_all_regs *regs ); +void arch_main ( struct i386_all_regs *ix86 ) { + void (*exit_path) ( struct i386_all_regs *ix86 ); /* Determine exit path requested by prefix */ - exit_path = ( typeof ( exit_path ) ) regs->eax; + exit_path = ( typeof ( exit_path ) ) ix86->regs.eax; /* Call to main() */ - regs->eax = main(); + ix86->regs.eax = main(); if ( exit_path ) { /* Prefix requested that we use a particular function * as the exit path, so we call this function, which * must not return. */ - exit_path ( regs ); + exit_path ( ix86 ); } } diff --git a/src/arch/i386/firmware/pcbios/basemem.c b/src/arch/i386/firmware/pcbios/basemem.c index 0bc9ca98..7dad640e 100644 --- a/src/arch/i386/firmware/pcbios/basemem.c +++ b/src/arch/i386/firmware/pcbios/basemem.c @@ -130,8 +130,8 @@ void free_base_memory ( void *ptr, size_t size ) { */ for ( ; size_kb > 0 ; free_block++, size_kb-- ) { /* Mark this block as unused */ - free_block->magic = FREE_BLOCK_MAGIC; - free_block->size_kb = size_kb; + free_block->header.magic = FREE_BLOCK_MAGIC; + free_block->header.size_kb = size_kb; } /* Free up unused base memory */ @@ -161,12 +161,12 @@ static void free_unused_base_memory ( void ) { * if this is not a free block */ if ( ( fbms == FBMS_MAX ) || - ( free_block->magic != FREE_BLOCK_MAGIC ) ) { + ( free_block->header.magic != FREE_BLOCK_MAGIC ) ) { break; } /* Return memory to BIOS */ - fbms += free_block->size_kb; + fbms += free_block->header.size_kb; DBG ( "Freed %d kB of base memory at [%hx:0000,%hx:0000), " "%d kB now free\n", diff --git a/src/arch/i386/image/nbi.c b/src/arch/i386/image/nbi.c index f361aa94..f5d9e382 100644 --- a/src/arch/i386/image/nbi.c +++ b/src/arch/i386/image/nbi.c @@ -4,22 +4,44 @@ #include "gateA20.h" #include "osloader.h" #include "etherboot.h" +#include "errno.h" -/* An NBI image header */ +/** @file + * + * NBI image format. + * + * The Net Boot Image format is defined by the "Draft Net Boot Image + * Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap. It is now + * considered to be a legacy format, but it still included because a + * large amount of software (e.g. nymph, LTSP) makes use of NBI files. + * + * Etherboot does not implement the INT 78 callback interface + * described by the NBI specification. For a callback interface on + * x86 architecture, use PXE. + * + */ + +/** + * An NBI image header + * + * Note that the length field uses a peculiar encoding; use the + * NBI_LENGTH() macro to decode the actual header length. + * + */ struct imgheader { - unsigned long magic; + unsigned long magic; /**< Magic number (NBI_MAGIC) */ union { - unsigned char length; - unsigned long flags; + unsigned char length; /**< Nibble-coded header length */ + unsigned long flags; /**< Image flags */ }; - segoff_t location; + segoff_t location; /**< 16-bit seg:off header location */ union { - segoff_t segoff; - unsigned long linear; + segoff_t segoff; /**< 16-bit seg:off entry point */ + unsigned long linear; /**< 32-bit entry point */ } execaddr; } __attribute__ (( packed )); -/* NBI magic number */ +/** NBI magic number */ #define NBI_MAGIC 0x1B031336UL /* Interpretation of the "length" fields */ @@ -31,18 +53,24 @@ struct imgheader { #define NBI_PROGRAM_RETURNS(flags) ( (flags) & ( 1 << 8 ) ) #define NBI_LINEAR_EXEC_ADDR(flags) ( (flags) & ( 1 << 31 ) ) -/* NBI header length */ +/** NBI header length */ #define NBI_HEADER_LENGTH 512 -/* An NBI segment header */ +/** + * An NBI segment header + * + * Note that the length field uses a peculiar encoding; use the + * NBI_LENGTH() macro to decode the actual header length. + * + */ struct segheader { - unsigned char length; - unsigned char vendortag; + unsigned char length; /**< Nibble-coded header length */ + unsigned char vendortag; /**< Vendor-defined private tag */ unsigned char reserved; - unsigned char flags; - unsigned long loadaddr; - unsigned long imglength; - unsigned long memlength; + unsigned char flags; /**< Segment flags */ + unsigned long loadaddr; /**< Load address */ + unsigned long imglength; /**< Segment length in NBI file */ + unsigned long memlength; /**< Segment length in memory */ }; /* Interpretation of the "flags" fields */ @@ -53,28 +81,41 @@ struct segheader { #define NBI_LOADADDR_BEFORE 0x03 #define NBI_LAST_SEGHEADER(flags) ( (flags) & ( 1 << 2 ) ) -/* Info passed to NBI image */ +/** Info passed to NBI image */ static struct ebinfo loaderinfo = { VERSION_MAJOR, VERSION_MINOR, 0 }; -/* +/** * Determine whether or not this is a valid NBI image * + * @v start Address of the image + * @v len Length of the image + * @v context NBI image context + * @ret True Image is a valid NBI image + * @ret False Image is not a valid NBI image + * @err EBADIMG Image is not a valid NBI image + * + * "context" is filled in with a context pointer suitable for passing to + * nbi_load() and nbi_boot(). + * */ static int nbi_probe ( physaddr_t start, off_t len, void **context ) { static struct imgheader imgheader; if ( (unsigned)len < sizeof ( imgheader ) ) { DBG ( "NBI image too small\n" ); + errno = EBADIMG; return 0; } copy_from_phys ( &imgheader, start, sizeof ( imgheader ) ); - if ( imgheader.magic != NBI_MAGIC ) + if ( imgheader.magic != NBI_MAGIC ) { + errno = EBADIMG; return 0; + } /* Record image context */ DBG ( "NBI found valid image\n" ); @@ -82,9 +123,17 @@ static int nbi_probe ( physaddr_t start, off_t len, void **context ) { return 1; } -/* +/** * Prepare a segment for an NBI image * + * @v dest Address of segment + * @v imglen Length of initialised-data portion of the segment + * @v memlen Total length of the segment + * @v src Source for initialised data + * @ret True Segment can be used + * @ret False Segment cannot be used + * @err other As returned by prep_segment() + * */ static int nbi_prepare_segment ( physaddr_t dest, off_t imglen, off_t memlen, physaddr_t src __unused ) { @@ -93,9 +142,15 @@ static int nbi_prepare_segment ( physaddr_t dest, off_t imglen, off_t memlen, return prep_segment ( dest, dest + imglen, dest + memlen ); } -/* +/** * Load a segment for an NBI image * + * @v dest Address of segment + * @v imglen Length of initialised-data portion of the segment + * @v memlen Total length of the segment + * @v src Source for initialised data + * @ret True Always + * */ static int nbi_load_segment ( physaddr_t dest, off_t imglen, off_t memlen __unused, physaddr_t src ) { @@ -104,9 +159,18 @@ static int nbi_load_segment ( physaddr_t dest, off_t imglen, return 1; } -/* +/** * Process segments of an NBI image * + * @v start Address of the image + * @v len Length of the image + * @v imgheader Image header information + * @v process Function to call for each segment + * @ret True All segments were processed successfully + * @ret False An error occurred processing a segment + * @err EBADIMG Image is not a valid NBI image + * @err other As returned by the "process" function + * */ static int nbi_process_segments ( physaddr_t start, off_t len, struct imgheader *imgheader, @@ -136,6 +200,7 @@ static int nbi_process_segments ( physaddr_t start, off_t len, if ( sh.length == 0 ) { /* Avoid infinite loop? */ DBG ( "NBI invalid segheader length 0\n" ); + errno = EBADIMG; return 0; } @@ -159,8 +224,8 @@ static int nbi_process_segments ( physaddr_t start, off_t len, - sh.loadaddr; break; default: - DBG ( "NBI can't count up to three\n" ); - return 0; + /* Cannot be reached */ + DBG ( "NBI can't count up to three!\n" ); } /* Process this segment */ @@ -175,6 +240,7 @@ static int nbi_process_segments ( physaddr_t start, off_t len, sh_off += NBI_LENGTH ( sh.length ); if ( sh_off >= NBI_HEADER_LENGTH ) { DBG ( "NBI header overflow\n" ); + errno = EBADIMG; return 0; } @@ -183,22 +249,35 @@ static int nbi_process_segments ( physaddr_t start, off_t len, if ( offset != len ) { DBG ( "NBI length mismatch (file %d, metadata %d)\n", len, offset ); + errno = EBADIMG; return 0; } return 1; } -/* +/** * Load an NBI image into memory * + * @v start Address of image + * @v len Length of image + * @v context NBI context (as returned by nbi_probe()) + * @ret True Image loaded into memory + * @ret False Image not loaded into memory + * @err EBADIMG Image is not a valid NBI image + * @err other As returned by nbi_process_segments() + * @err other As returned by nbi_prepare_segment() + * @err other As returned by nbi_load_segment() + * */ static int nbi_load ( physaddr_t start, off_t len, void *context ) { struct imgheader *imgheader = context; /* If we don't have enough data give up */ - if ( len < NBI_HEADER_LENGTH ) + if ( len < NBI_HEADER_LENGTH ) { + errno = EBADIMG; return 0; + } DBG ( "NBI placing header at %hx:%hx\n", imgheader->location.segment, imgheader->location.offset ); @@ -220,9 +299,14 @@ static int nbi_load ( physaddr_t start, off_t len, void *context ) { return 1; } -/* +/** * Boot a 16-bit NBI image * + * @v imgheader Image header information + * @ret Never NBI program booted successfully + * @ret False NBI program returned + * @err EIMGRET NBI program returned + * */ static int nbi_boot16 ( struct imgheader *imgheader ) { uint16_t basemem_bootp; @@ -256,12 +340,23 @@ static int nbi_boot16 ( struct imgheader *imgheader ) { CLOBBER ( "eax", "ecx", "edx", "ebp" ) ); BASEMEM_PARAMETER_DONE ( bootp_data ); + errno = EIMGRET; return 0; } -/* +/** * Boot a 32-bit NBI image * + * @v imgheader Image header information + * @ret False NBI program should not have returned + * @ret other As returned by NBI program + * @err EIMGRET NBI program should not have returned + * + * To distinguish between the case of an NBI program returning false, + * and an NBI program that should not have returned, check errno. + * errno will be set to EIMGRET only if the NBI program should not + * have returned. + * */ static int nbi_boot32 ( struct imgheader *imgheader ) { int rc = 0; @@ -270,6 +365,7 @@ static int nbi_boot32 ( struct imgheader *imgheader ) { imgheader->execaddr.linear ); /* no gateA20_unset for PM call */ + errno = ENOERR; rc = xstart32 ( imgheader->execaddr.linear, virt_to_phys ( &loaderinfo ), ( ( imgheader->location.segment << 4 ) + @@ -278,15 +374,24 @@ static int nbi_boot32 ( struct imgheader *imgheader ) { printf ( "Secondary program returned %d\n", rc ); if ( ! NBI_PROGRAM_RETURNS ( imgheader->flags ) ) { /* We shouldn't have returned */ + errno = EIMGRET; rc = 0; } return rc; } -/* +/** * Boot a loaded NBI image * + * @v context NBI context (as returned by nbi_probe()) + * @ret Never NBI program booted successfully + * @ret False NBI program should not have returned + * @ret other As returned by NBI program + * @err EIMGRET NBI program should not have returned + * + * See also nbi_boot16() and nbi_boot32(). + * */ static int nbi_boot ( void *context ) { struct imgheader *imgheader = context; @@ -298,6 +403,7 @@ static int nbi_boot ( void *context ) { } } +/** Declaration of the NBI image format */ static struct image nbi_image __image = { .name = "NBI", .probe = nbi_probe, diff --git a/src/arch/i386/core/pxe_loader.c b/src/arch/i386/image/pxe_image.c index 1b611891..bd1bad35 100644 --- a/src/arch/i386/core/pxe_loader.c +++ b/src/arch/i386/image/pxe_image.c @@ -13,7 +13,6 @@ #include "etherboot.h" #include "pxe_callbacks.h" -#include "pxe_export.h" #include "pxe.h" unsigned long pxe_load_offset; diff --git a/src/arch/i386/include/basemem.h b/src/arch/i386/include/basemem.h index 6e7c22dd..289824eb 100644 --- a/src/arch/i386/include/basemem.h +++ b/src/arch/i386/include/basemem.h @@ -19,7 +19,7 @@ struct free_base_memory_header { }; union free_base_memory_block { - struct free_base_memory_header; + struct free_base_memory_header header; char bytes[1024]; }; diff --git a/src/arch/i386/include/bochs.h b/src/arch/i386/include/bochs.h index 73f43c36..9d090fc1 100644 --- a/src/arch/i386/include/bochs.h +++ b/src/arch/i386/include/bochs.h @@ -1,9 +1,16 @@ #ifndef BOCHS_H #define BOCHS_H -/* - * This file defines "bochsbp", the magic breakpoint instruction that - * is incredibly useful when debugging under bochs. +/** @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. * */ @@ -15,7 +22,7 @@ #else /* ASSEMBLY */ -/* Breakpoint for when debugging under bochs */ +/** Breakpoint for when debugging under bochs */ static inline void bochsbp ( void ) { __asm__ __volatile__ ( "xchgw %bx, %bx" ); } diff --git a/src/arch/i386/include/hooks.h b/src/arch/i386/include/hooks.h index 95b9aaa3..3cef262f 100644 --- a/src/arch/i386/include/hooks.h +++ b/src/arch/i386/include/hooks.h @@ -1,6 +1,6 @@ #ifndef HOOKS_H #define HOOKS_H -extern void arch_main ( struct i386_all_regs *regs ); +extern void arch_main ( struct i386_all_regs *ix86 ); #endif /* HOOKS_H */ diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h index 2edc1096..1b82a982 100644 --- a/src/arch/i386/include/librm.h +++ b/src/arch/i386/include/librm.h @@ -17,8 +17,8 @@ /* Real-mode call parameter block, as passed to real_call */ struct real_call_params { - struct i386_seg_regs; - struct i386_regs; + struct i386_seg_regs segs; + struct i386_regs regs; segoff_t rm_code; segoff_t reserved; } PACKED; diff --git a/src/arch/i386/include/pxe_addr.h b/src/arch/i386/include/pxe_addr.h new file mode 100644 index 00000000..954551e8 --- /dev/null +++ b/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/src/arch/i386/include/pxe_callbacks.h b/src/arch/i386/include/pxe_callbacks.h index cf5a7a87..974a3c30 100644 --- a/src/arch/i386/include/pxe_callbacks.h +++ b/src/arch/i386/include/pxe_callbacks.h @@ -5,12 +5,12 @@ #define PXE_CALLBACKS_H #include "etherboot.h" -#include "pxe.h" +#include "pxe_types.h" typedef struct { - segoff_t orig_retaddr; - uint16_t opcode; - segoff_t segoff; + SEGOFF16_t orig_retaddr; + UINT16_t opcode; + SEGOFF16_t segoff; } PACKED pxe_call_params_t; /* @@ -22,7 +22,7 @@ typedef struct { /* Function prototypes */ -extern pxe_stack_t * install_pxe_stack ( void *base ); +extern struct pxe_stack * install_pxe_stack ( void *base ); extern void use_undi_ds_for_rm_stack ( uint16_t ds ); extern int hook_pxe_stack ( void ); extern int unhook_pxe_stack ( void ); diff --git a/src/arch/i386/include/pxe_types.h b/src/arch/i386/include/pxe_types.h deleted file mode 100644 index 45736a2b..00000000 --- a/src/arch/i386/include/pxe_types.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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_TYPES_H -#define PXE_TYPES_H - -/* SEGOFF16_t defined in separate header - */ -#include "realmode.h" -typedef segoff_t I386_SEGOFF16_t; -#define SEGOFF16_t I386_SEGOFF16_t - -#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); - -typedef struct { - uint16_t Seg_Addr; - uint32_t Phy_Addr; - uint16_t Seg_Size; -} PACKED I386_SEGDESC_t; /* PACKED is required, otherwise gcc pads - * this out to 12 bytes - - * mbrown@fensystems.co.uk (mcb30) 17/5/03 */ -#define SEGDESC_t I386_SEGDESC_t - -typedef uint16_t I386_SEGSEL_t; -#define SEGSEL_t I386_SEGSEL_t - -#endif /* PXE_TYPES_H */ diff --git a/src/arch/i386/include/realmode.h b/src/arch/i386/include/realmode.h index cd6fcfc7..fe011184 100644 --- a/src/arch/i386/include/realmode.h +++ b/src/arch/i386/include/realmode.h @@ -12,11 +12,6 @@ * */ -/* All i386 registers, as passed in by prot_call or kir_call */ -struct real_mode_regs { - struct i386_all_regs; -} PACKED; - /* Segment:offset structure. Note that the order within the structure * is offset:segment. */ diff --git a/src/arch/i386/include/registers.h b/src/arch/i386/include/registers.h index 155fffbd..66653238 100644 --- a/src/arch/i386/include/registers.h +++ b/src/arch/i386/include/registers.h @@ -1,9 +1,25 @@ #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" -/* Basic 16-bit and 32-bit register types */ +/** + * 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 { @@ -15,12 +31,33 @@ typedef union { 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 { - reg16_t; + struct { + union { + uint8_t l; + uint8_t byte; + }; + uint8_t h; + } PACKED; + uint16_t word; uint32_t dword; } PACKED reg32_t; -/* As created by pushal / read by popal */ +/** + * 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; @@ -72,7 +109,31 @@ struct i386_regs { }; } PACKED; -/* Our pushal/popal equivalent for segment registers */ +/** + * 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; @@ -82,11 +143,37 @@ struct i386_seg_regs { uint16_t gs; } PACKED; -/* All i386 registers, as passed in by prot_call or kir_call */ +/** + * 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; - struct i386_regs; - uint32_t i386_flags; + struct i386_seg_regs segs; + struct i386_regs regs; + uint32_t flags; } PACKED; #endif /* REGISTERS_H */ diff --git a/src/arch/i386/include/stdint.h b/src/arch/i386/include/stdint.h index b9ade4e0..c801cf6f 100644 --- a/src/arch/i386/include/stdint.h +++ b/src/arch/i386/include/stdint.h @@ -16,4 +16,16 @@ typedef signed long long int64_t; typedef unsigned long physaddr_t; +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + #endif /* STDINT_H */ diff --git a/src/arch/i386/include/virtaddr.h b/src/arch/i386/include/virtaddr.h index d48b6c6c..4d248b0a 100644 --- a/src/arch/i386/include/virtaddr.h +++ b/src/arch/i386/include/virtaddr.h @@ -46,7 +46,8 @@ 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, void *src, size_t len ) { +static inline void copy_to_phys ( physaddr_t dest, const void *src, + size_t len ) { memcpy ( phys_to_virt ( dest ), src, len ); } diff --git a/src/arch/i386/prefix/hdprefix.S b/src/arch/i386/prefix/hdprefix.S new file mode 100644 index 00000000..38e62bc3 --- /dev/null +++ b/src/arch/i386/prefix/hdprefix.S @@ -0,0 +1,296 @@ +/****************************************************************\ + +hdprefix.S Copyright (C) 2005 Per Dalgas Jakobsen + +This code has been inspired/derived by the OSLoader by Vladislav Aleksandrov. +http://www.programmersheaven.com/zone5/cat469/40546.htm. + +This software may be used and distributed according to the terms +of the GNU Public License (GPL), incorporated herein by reference. + +hdprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines. + +Actions performed by hdprefix: +1) Load the MBR to LOADSEG:0 +2) Check which partition is active (or try first partition if none active) +3) Check wether LBA is supported. +3a) LBA +3a1) Load PAYLOAD_SECTS sectors from chosen partition to LOADSEG:0 +3b) CHS (standard) +3b1) Load PAYLOAD_SECTS sectors from chosen partition to LOADSEG:0 +4) Check loaded bootsector for BOOTMAGIC code. +5) Jump to payload LOADSEG:ENTRYPOINT. + +Output with failure points (!#): +--- +Loading (!1)partition # +Std. BIOS(!2) | Ext. BIOS(!3) +Booting...(!4) +(!5) +--- + +!1: Failed to load MBR with Int13,ah=2. +!2: Failed to load bootrecord+payload with Int13,ah=2. +!3: Failed to load bootrecord+payload with Int13,ah=42. +!4: Invalid BOOTMAGIC in loaded bootrecord. +!5: Jumping to payload. + +\*****************************************************************/ + +.equ BOOTSEG, 0x07c0 +.equ LOADSEG, 0x1000 +.equ ENTRYPOINT, _start + +.equ BOOTMAGIC, 0x0aa55 + +.equ partition_table, 0x1be +.equ partition_rec_size, 0x10 + +.equ boot_ind, 0 /* 80h=active */ +.equ start_head, 1 +.equ start_sector, 2 /* bits 0-5 */ +.equ start_cyl, 3 /* bits 8,9 in bits 6,7 of sector */ +.equ os_ind, 4 /* os indicator */ +.equ end_head, 5 +.equ end_sector, 6 /* bits 0-5 */ +.equ end_track, 7 /* bits 8,9 in bits 6,7 of sector */ +.equ nsect, 8 /* sectors preceding partition */ +.equ lenght, 0x0c /* length of partition in sectors */ + +/------------------------------------------------------------- + + .arch i386 + .text + .section ".prefix", "ax", @progbits + .code16 + +bootstart: + jmp $BOOTSEG,$_go /* reload cs:ip */ + + +/****************************************************************/ +/* support routines. */ +/*--------------------------------------------------------------*/ +_failed: + movw $BOOTSEG,%ax + movw %ax,%ds + movw $_failed_msg_end-_failed_msg,%cx + movw $_failed_msg,%si + call _print_str + + /* stop execution - should probably have option to auto-reboot after delay. */ +_failed_loop: + jmp _failed_loop + +/*--------------------------------------------------------------*/ +_print_str: + /* cx = count, ds:si = string. */ + movw $0x0007,%bx + movb $0x0e,%ah +_print_loop: + lodsb + int $0x10 + loop _print_loop + ret + +/*--------------------------------------------------------------*/ +_print_char: + /* al = char. */ + movw $0x0007,%bx + movb $0x0e,%ah + int $0x10 + ret + +/*--------------------------------------------------------------*/ +_print_nl: + /* - */ + movb $0x0d,%al + call _print_char + movb $0x0a,%al + call _print_char + ret + +/*--------------------------------------------------------------*/ +_print_hex: + /* dx = value */ + movb $0x0e,%ah /* write char, tty mode */ + movw $0x0007,%bx /* page 0, attribute 7 (normal) */ + call _print_digit + call _print_digit + call _print_digit + /* fall through */ +_print_digit: + rolw $4,%dx /* rotate so that lowest 4 bits are used */ + movb $0x0f,%al /* mask for nibble */ + andb %dl,%al + addb $0x90,%al /* convert al to ascii hex (four instructions) */ + daa + adcb $0x40,%al + daa + int $0x10 + ret + +/****************************************************************/ + + +_go: + cli + movw $BOOTSEG,%ax + movw %ax,%ds + movw %ax,%ss + movw $0x2000,%sp /* good large stack. */ + sti + cld + movw $LOADSEG,%ax + movw %ax,%es + + movw $_load_msg_end-_load_msg,%cx + movw $_load_msg,%si + call _print_str + +/*--- load MBR so we can use its partition table. ---*/ + xorw %bx,%bx + movw $0x0001,%cx /* chs: 0,0,1 */ + movb %bh,%dh /* - */ + movb $0x80,%dl + movw $0x0201,%ax /* read one sector (MBR) */ + int $0x13 + jc _failed + +/*--- find the active partition ---*/ + movw $_part_msg_end-_part_msg,%cx + movw $_part_msg,%si + call _print_str + + movw $partition_table,%di + movw $4,%cx +_partition_loop: + cmpb $0x80,%es:(%di) /* active? */ + je _partition_found + addw $partition_rec_size,%di + loop _partition_loop + + /*- no partitions marked active - use 1. partition. */ + movw $partition_table,%di + movw $4,%cx + +_partition_found: + movb $'5',%al /* convert to ascii */ + subb %cl,%al + call _print_char + call _print_nl + +/*--- check for lba support ---*/ + movw $0x55aa,%bx + movb $0x80,%dl + movb $0x41,%ah + int $0x13 + jc __bios + cmpw $0x0aa55,%bx + jnz __bios + testb $1,%cl + jz __bios + +/*--- use lba bios calls to read sectors ---*/ +_lba: + movw $_extbios_msg_end-_extbios_msg,%cx + movw $_extbios_msg,%si + call _print_str + + movw %es:nsect(%di),%ax + movw %ax,_bios_lba_low + movw %es:nsect+2(%di),%ax + movw %ax,_bios_lba_high + movb $0x80,%dl + movw $_disk_address_packet,%si + movw $0x4200,%ax /* read */ + int $0x13 + jc _failed + jmp __loaded + +/*--- use standard bios calls to read sectors ---*/ +__bios: + movw $_stdbios_msg_end-_stdbios_msg,%cx + movw $_stdbios_msg,%si + call _print_str + + movw _disk_address_packet+2(,1),%ax /* only low byte is used. */ + xorw %bx,%bx + movw %es:start_sector(%di),%cx + movb %es:start_head(%di),%dh + movb $0x80,%dl + movb $0x02,%ah + int $0x13 + jc _failed + +__loaded: + movw $_boot_msg_end-_boot_msg,%cx + movw $_boot_msg,%si + call _print_str + + /* check if it has a valid bootrecord. */ + cmpw $BOOTMAGIC,%es:510(,1) + jne _failed + call _print_nl + + /* call the payload. */ + pushl $0 /* No parameters to preserve for exit path */ + pushw $0 /* Use prefix exit path mechanism */ + jmp $LOADSEG,$ENTRYPOINT + + .section ".text16", "ax", @progbits + .globl prefix_exit +prefix_exit: + int $0x19 /* should try to boot machine */ + .globl prefix_exit_end +prefix_exit_end: + .previous + + +/*--------------------------------------------------------------*/ + +_load_msg: .ascii "Loading " +_load_msg_end: +_part_msg: .ascii "partition " +_part_msg_end: +_boot_msg: .ascii "Booting..." +_boot_msg_end: +_stdbios_msg: .ascii "Std. BIOS\r\n" +_stdbios_msg_end: +_extbios_msg: .ascii "Ext. BIOS\r\n" +_extbios_msg_end: +_failed_msg: .ascii "FAILED!!!\r\n" +_failed_msg_end: + + +/*--------------------------------------------------------------*/ + +_disk_address_packet: + .byte 0x10 /* size of the packet */ + .byte 0 /* reserved */ + .word _verbatim_size_sct /* number of sectors to read */ + .word 0x0000 /* offset */ + .word LOADSEG /* segment of buffer */ +_bios_lba_low: .word 0 +_bios_lba_high: .word 0 + .word 0 + .word 0 + + .rept 32 + .byte 0 + .endr + + +/*--- Partition table ------------------------------------------*/ + + .org 446, 0 + .rept 64 + .byte 0 + .endr + + +/*--- Magic code -----------------------------------------------*/ + .org 510, 0 + .word BOOTMAGIC + +/*** END ********************************************************/ diff --git a/src/arch/i386/prefix/int19exit.c b/src/arch/i386/prefix/int19exit.c index e7be0624..e1333926 100644 --- a/src/arch/i386/prefix/int19exit.c +++ b/src/arch/i386/prefix/int19exit.c @@ -1,13 +1,31 @@ #include "bochs.h" #include "realmode.h" -/* - * The "exit via INT 19" exit path. INT 19 is the old (pre-BBS) "boot - * system" interrupt. +/** @file + * + * The "exit via INT 19" exit path. + * + * INT 19 is the old (pre-BBS) "boot system" interrupt. It is + * conventionally used now to return from a failed boot from floppy + * disk. * */ -void exit_via_int19 ( struct real_mode_regs *rm_regs ) { +/** + * Exit via INT19 + * + * @v ix86 i386 register values to be loaded on exit + * @ret Never - + * @err None - + * + * Exit back to the BIOS by switching to real mode, reloading the + * registers as they were before Etherboot started, and executing INT + * 19. + * + * @bug Not yet implemented + * + */ +void exit_via_int19 ( struct i386_all_regs *ix86 ) { bochsbp(); /* Placeholder */ } diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S index 9bdc4a02..4a5bd2e6 100644 --- a/src/arch/i386/prefix/romprefix.S +++ b/src/arch/i386/prefix/romprefix.S @@ -110,9 +110,9 @@ UNDIROMID: .byte 0 /* Structure revision */ .byte 0,1,2 /* PXE version 2.1.0 */ .word UNDILoader - _prefix /* Offset to loader routine */ - .word UNDIStackSize /* Stack segment size */ - .word UNDIDataSize /* Data segment size */ - .word UNDICodeSize /* Code segment size */ + .word _real_mode_stack_size /* Stack segment size */ + .word _real_mode_stack_size /* Data segment size */ + .word _pxe_stack_size /* Code segment size */ .ascii "PCIR" /* The code segment contains our pxe_stack_t plus the PXE and diff --git a/src/arch/i386/prefix/select_isapnp.c b/src/arch/i386/prefix/select_isapnp.c index 54ac1c9a..6a539eb5 100644 --- a/src/arch/i386/prefix/select_isapnp.c +++ b/src/arch/i386/prefix/select_isapnp.c @@ -11,7 +11,7 @@ * would cause linker symbol pollution. * */ -void i386_select_isapnp_device ( struct i386_all_regs *regs ) { +void i386_select_isapnp_device ( struct i386_all_regs *ix86 ) { /* * PnP BIOS passes card select number in %bx and read port * address in %dx. @@ -23,10 +23,10 @@ void i386_select_isapnp_device ( struct i386_all_regs *regs ) { } u; /* Set ISAPnP read port */ - isapnp_read_port = regs->dx; + isapnp_read_port = ix86->regs.dx; /* Select ISAPnP bus and specified CSN as first boot device */ memset ( &u, 0, sizeof ( u ) ); - u.isapnp_loc.csn = regs->bx; + u.isapnp_loc.csn = ix86->regs.bx; select_device ( &dev, &isapnp_driver, &u.bus_loc ); } diff --git a/src/arch/i386/prefix/select_pci.c b/src/arch/i386/prefix/select_pci.c index c9a62d52..e143b992 100644 --- a/src/arch/i386/prefix/select_pci.c +++ b/src/arch/i386/prefix/select_pci.c @@ -11,7 +11,7 @@ * that would cause linker symbol pollution. * */ -void i386_select_pci_device ( struct i386_all_regs *regs ) { +void i386_select_pci_device ( struct i386_all_regs *ix86 ) { /* * PCI BIOS passes busdevfn in %ax * @@ -23,6 +23,6 @@ void i386_select_pci_device ( struct i386_all_regs *regs ) { /* Select PCI bus and specified busdevfn as first boot device */ memset ( &u, 0, sizeof ( u ) ); - u.pci_loc.busdevfn = regs->ax; + u.pci_loc.busdevfn = ix86->regs.ax; select_device ( &dev, &pci_driver, &u.bus_loc ); } diff --git a/src/arch/i386/transitions/libkir.S b/src/arch/i386/transitions/libkir.S index 79a0aa00..e0d6c57c 100644 --- a/src/arch/i386/transitions/libkir.S +++ b/src/arch/i386/transitions/libkir.S @@ -135,12 +135,12 @@ kir_to_ext: * * Call a specific C function in the internal code. The prototype of * the C function must be - * void function ( struct real_mode_regs *rm_regs ); - * rm_regs will point to a struct containing the real-mode registers + * void function ( struct i386_all_resg *ix86 ); + * ix86 will point to a struct containing the real-mode registers * at entry to kir_call. * * All registers will be preserved across kir_call(), unless the C - * function explicitly overwrites values in rm_regs. Interrupt status + * function explicitly overwrites values in ix86. Interrupt status * will also be preserved. * * Parameters: @@ -151,7 +151,7 @@ kir_to_ext: * lcall $UNDI_CS, $kir_call * addw $2, %sp * to call in to the C function - * void pxe_api_call ( struct real_mode_regs *rm_regs ); + * void pxe_api_call ( struct i386_all_regs *ix86 ); **************************************************************************** */ @@ -190,7 +190,7 @@ kir_call: pushl %cs:ext_ds_and_es pushl %cs:ext_cs_and_ss - /* Push &rm_regs on stack and call function */ + /* Push &ix86 on stack and call function */ pushl %esp data32 call *%cs:save_function popl %eax /* discard */ diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S index 6e2f1229..2e6ac47b 100644 --- a/src/arch/i386/transitions/librm.S +++ b/src/arch/i386/transitions/librm.S @@ -106,11 +106,11 @@ /* Size of various C data structures */ #define SIZEOF_I386_SEG_REGS 12 #define SIZEOF_I386_REGS 32 -#define SIZEOF_I386_ALL_REGS ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS ) +#define SIZEOF_REAL_MODE_REGS ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS ) #define SIZEOF_I386_FLAGS 4 -#define SIZEOF_REAL_MODE_REGS ( SIZEOF_I386_ALL_REGS + SIZEOF_I386_FLAGS ) +#define SIZEOF_I386_ALL_REGS ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS ) #define SIZEOF_SEGOFF_T 4 -#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_I386_ALL_REGS + 2 * SIZEOF_SEGOFF_T ) +#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_REAL_MODE_REGS + 2 * SIZEOF_SEGOFF_T ) .text .arch i386 @@ -461,12 +461,12 @@ p2r_ljmp: * * Call a specific C function in the protected-mode code. The * prototype of the C function must be - * void function ( struct real_mode_regs *rm_regs ); - * rm_regs will point to a struct containing the real-mode registers + * void function ( struct i386_all_regs *ix86 ); + * ix86 will point to a struct containing the real-mode registers * at entry to prot_call. * * All registers will be preserved across prot_call(), unless the C - * function explicitly overwrites values in rm_regs. Interrupt status + * function explicitly overwrites values in ix86. Interrupt status * will also be preserved. Gate A20 will be enabled. * * The protected-mode code may install librm to a new location. If it @@ -495,12 +495,12 @@ p2r_ljmp: * lcall $LIBRM_SEGMENT, $prot_call * addw $4, %sp * to call in to the C function - * void pxe_api_call ( struct real_mode_regs *rm_regs ); + * void pxe_api_call ( struct i386_all_regs *ix86 ); **************************************************************************** */ -#define PC_OFFSET_RM_REGS ( 0 ) -#define PC_OFFSET_RETADDR ( PC_OFFSET_RM_REGS + SIZEOF_REAL_MODE_REGS ) +#define PC_OFFSET_IX86 ( 0 ) +#define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS ) #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 ) .code16 @@ -534,14 +534,14 @@ EXPORT(prot_call): call real_to_prot .code32 - /* Copy rm_regs from RM stack to PM stack */ - movl $SIZEOF_REAL_MODE_REGS, %ecx + /* Copy ix86 from RM stack to PM stack */ + movl $SIZEOF_I386_ALL_REGS, %ecx subl %ecx, %esp movl %esp, %edi pushl %esi cld rep movsb - popl %edi /* %edi = phys addr of RM copy of rm_regs */ + popl %edi /* %edi = phys addr of RM copy of ix86 */ /* Switch to virtual addresses. */ call 1f @@ -555,7 +555,7 @@ EXPORT(prot_call): popl %eax /* discard */ popal - /* Push &rm_regs on the stack, and call function */ + /* Push &ix86 on the stack, and call function */ pushl %esp call *%ebx popl %eax /* discard */ @@ -564,16 +564,16 @@ EXPORT(prot_call): lcall $VIRTUAL_CS, $_virt_to_phys popl %eax /* discard */ - /* Copy rm_regs from PM stack to RM stack, and remove rm_regs + /* Copy ix86 from PM stack to RM stack, and remove ix86 * from PM stack. (%edi still contains physical address of - * rm_regs on RM stack from earlier, since C code preserves + * ix86 on RM stack from earlier, since C code preserves * %edi). */ movl %esp, %esi - movl $SIZEOF_REAL_MODE_REGS, %ecx + movl $SIZEOF_I386_ALL_REGS, %ecx cld rep movsb - movl %esi, %esp /* remove rm_regs from PM stack */ + movl %esi, %esp /* remove ix86 from PM stack */ /* Obtain physical base address of installed copy of librm in * %ebx. (It's possible that this *isn't* the physical base diff --git a/src/arch/i386/transitions/librm_mgmt.c b/src/arch/i386/transitions/librm_mgmt.c index ffd55ff6..956408f5 100644 --- a/src/arch/i386/transitions/librm_mgmt.c +++ b/src/arch/i386/transitions/librm_mgmt.c @@ -139,7 +139,7 @@ POST_RELOC_FN ( POST_RELOC_LIBRM, librm_post_reloc ); * pointer to this new librm's entry point via es:di. * */ -void initialise_via_librm ( struct i386_all_regs *regs ) { +void initialise_via_librm ( struct i386_all_regs *ix86 ) { /* Hand off to initialise() */ initialise (); @@ -147,7 +147,7 @@ void initialise_via_librm ( struct i386_all_regs *regs ) { * already set up by setup16, so all we need to do is point * es:0000 to the start of the new librm. */ - regs->es = librm_base >> 4; + ix86->segs.es = librm_base >> 4; } /* |