summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/include
diff options
context:
space:
mode:
authorMichael Brown2005-04-08 17:01:17 +0200
committerMichael Brown2005-04-08 17:01:17 +0200
commit0ff80b477dcff0726ebdbed95e8a93971e59e82b (patch)
tree860b7150212a07c24a9529ea072f3fb12700974c /src/arch/i386/include
parentMerged this file into HEAD (diff)
downloadipxe-0ff80b477dcff0726ebdbed95e8a93971e59e82b.tar.gz
ipxe-0ff80b477dcff0726ebdbed95e8a93971e59e82b.tar.xz
ipxe-0ff80b477dcff0726ebdbed95e8a93971e59e82b.zip
Merged mcb30-realmode-redesign back to HEAD
Diffstat (limited to 'src/arch/i386/include')
-rw-r--r--src/arch/i386/include/bios.h10
-rw-r--r--src/arch/i386/include/bochs.h27
-rw-r--r--src/arch/i386/include/hidemem.h2
-rw-r--r--src/arch/i386/include/hooks.h19
-rw-r--r--src/arch/i386/include/io.h18
-rw-r--r--src/arch/i386/include/kir.h18
-rw-r--r--src/arch/i386/include/libkir.h184
-rw-r--r--src/arch/i386/include/librm.h186
-rw-r--r--src/arch/i386/include/memsizes.h34
-rw-r--r--src/arch/i386/include/pic8259.h4
-rw-r--r--src/arch/i386/include/pxe_callbacks.h1
-rw-r--r--src/arch/i386/include/pxe_types.h2
-rw-r--r--src/arch/i386/include/realmode.h218
-rw-r--r--src/arch/i386/include/registers.h93
-rw-r--r--src/arch/i386/include/segoff.h41
-rw-r--r--src/arch/i386/include/virtaddr.h85
16 files changed, 764 insertions, 178 deletions
diff --git a/src/arch/i386/include/bios.h b/src/arch/i386/include/bios.h
new file mode 100644
index 00000000..afc648ba
--- /dev/null
+++ b/src/arch/i386/include/bios.h
@@ -0,0 +1,10 @@
+#ifndef BIOS_H
+#define BIOS_H
+
+extern unsigned long currticks ( void );
+extern void cpu_nap ( void );
+extern void disk_init ( void );
+extern unsigned int pcbios_disk_read ( int drive, int cylinder, int head,
+ int sector, char *fixme_buf );
+
+#endif /* BIOS_H */
diff --git a/src/arch/i386/include/bochs.h b/src/arch/i386/include/bochs.h
new file mode 100644
index 00000000..73f43c36
--- /dev/null
+++ b/src/arch/i386/include/bochs.h
@@ -0,0 +1,27 @@
+#ifndef BOCHS_H
+#define BOCHS_H
+
+/*
+ * This file defines "bochsbp", the magic breakpoint instruction that
+ * is incredibly useful when debugging under bochs.
+ *
+ */
+
+#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/src/arch/i386/include/hidemem.h b/src/arch/i386/include/hidemem.h
index 600a8692..71b0905f 100644
--- a/src/arch/i386/include/hidemem.h
+++ b/src/arch/i386/include/hidemem.h
@@ -1,7 +1,7 @@
#ifndef HIDEMEM_H
#define HIDEMEM_H
-#include "segoff.h"
+#include "realmode.h"
extern int install_e820mangler ( void *new_mangler );
extern int hide_etherboot ( void );
diff --git a/src/arch/i386/include/hooks.h b/src/arch/i386/include/hooks.h
index 0764edaf..a4e4b397 100644
--- a/src/arch/i386/include/hooks.h
+++ b/src/arch/i386/include/hooks.h
@@ -1,9 +1,14 @@
-#ifndef ETHERBOOT_I386_HOOKS_H
-#define ETHERBOOT_I386_HOOKS_H
+#ifndef HOOKS_H
+#define HOOKS_H
-void arch_main(in_call_data_t *data, va_list params);
-void arch_on_exit(int status);
-#define arch_relocate_to(addr)
-void arch_relocated_from ( uint32_t old_addr );
+/* in hooks.o */
+extern void arch_initialise ( struct i386_all_regs *regs,
+ void (*retaddr) (void) );
+extern void arch_main ( struct i386_all_regs *regs );
-#endif /* ETHERBOOT_I386_HOOKS_H */
+/* in hooks_rm.o */
+extern void arch_rm_initialise ( struct i386_all_regs *regs,
+ void (*retaddr) (void) );
+extern void arch_rm_main ( struct i386_all_regs *regs );
+
+#endif /* HOOKS_H */
diff --git a/src/arch/i386/include/io.h b/src/arch/i386/include/io.h
index e351a0c1..5b6a6243 100644
--- a/src/arch/i386/include/io.h
+++ b/src/arch/i386/include/io.h
@@ -1,22 +1,8 @@
#ifndef ETHERBOOT_IO_H
#define ETHERBOOT_IO_H
-
-/* Amount of relocation etherboot is experiencing */
-extern unsigned long virt_offset;
-
-/* Don't require identity mapped physical memory,
- * osloader.c is the only valid user at the moment.
- */
-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);
-}
+#include "compiler.h"
+#include "virtaddr.h"
/* virt_to_bus converts an addresss inside of etherboot [_start, _end]
* into a memory access cards can use.
diff --git a/src/arch/i386/include/kir.h b/src/arch/i386/include/kir.h
new file mode 100644
index 00000000..84633d26
--- /dev/null
+++ b/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/src/arch/i386/include/libkir.h b/src/arch/i386/include/libkir.h
new file mode 100644
index 00000000..5bac42d8
--- /dev/null
+++ b/src/arch/i386/include/libkir.h
@@ -0,0 +1,184 @@
+#ifndef LIBKIR_H
+#define LIBKIR_H
+
+#include "realmode.h"
+
+#ifndef ASSEMBLY
+
+/*
+ * Full API documentation for these functions is in realmode.h.
+ *
+ */
+
+/* Copy to/from base memory */
+
+static inline void copy_to_real_libkir ( uint16_t dest_seg, uint16_t dest_off,
+ void *src, size_t n ) {
+ __asm__ ( "movw %4, %%es\n\t"
+ "cld\n\t"
+ "rep movsb\n\t"
+ "pushw %%ds\n\t" /* restore %es */
+ "popw %%es\n\t"
+ : "=S" ( src ), "=D" ( dest_off ), "=c" ( n ) /* clobbered */
+ : "S" ( src ), "r" ( dest_seg ), "D" ( dest_off ), "c" ( n )
+ : "memory"
+ );
+}
+
+static inline void copy_from_real_libkir ( void *dest,
+ uint16_t src_seg, uint16_t src_off,
+ size_t n ) {
+ __asm__ ( "movw %%ax, %%ds\n\t"
+ "cld\n\t"
+ "rep movsb\n\t"
+ "pushw %%es\n\t" /* restore %ds */
+ "popw %%ds\n\t"
+ : "=S" ( src_off ), "=D" ( dest ), "=c" ( n ) /* clobbered */
+ : "a" ( src_seg ), "S" ( src_off ), "D" ( dest ), "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
+
+/* Place/remove parameter on real-mode stack in a way that's
+ * compatible with libkir
+ */
+#define BASEMEM_PARAMETER_INIT_LIBKIR( param ) \
+ ( ( uint16_t ) ( ( uint32_t ) & ( param ) ) )
+#define BASEMEM_PARAMETER_DONE_LIBKIR( param )
+#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBKIR
+#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBKIR
+
+/* REAL_CALL: call an external real-mode routine */
+#define OUT_CONSTRAINTS(...) __VA_ARGS__
+#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
+#define CLOBBER(...) __VA_ARGS__
+#define REAL_CALL( routine, num_out_constraints, out_constraints, \
+ in_constraints, clobber ) \
+ do { \
+ segoff_t __routine = routine; \
+ __asm__ __volatile__ ( \
+ "pushl %" #num_out_constraints "\n\t" \
+ ".code16\n\t" \
+ "pushw %%gs\n\t" /* preserve segs */ \
+ "pushw %%fs\n\t" \
+ "pushw %%es\n\t" \
+ "pushw %%ds\n\t" \
+ "pushw %%cs\n\t" /* lcall to routine */ \
+ "call 1f\n\t" \
+ "jmp 2f\n\t" \
+ "\n1:\n\t" \
+ "addr32 pushl 12(%%esp)\n\t" \
+ "lret\n\t" \
+ "\n2:\n\t" \
+ "popw %%ds\n\t" /* restore segs */ \
+ "popw %%es\n\t" \
+ "popw %%fs\n\t" \
+ "popw %%gs\n\t" \
+ "addw $4, %%sp\n\t" \
+ ".code16gcc\n\t" \
+ : out_constraints : in_constraints : clobber \
+ ); \
+ } while ( 0 )
+
+/* REAL_EXEC: execute some inline assembly code in a way that matches
+ * the interface of librm
+ */
+
+#define IN_CONSTRAINTS_NO_ROUTINE( routine, ... ) __VA_ARGS__
+#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
+ in_constraints, clobber ) \
+ __asm__ __volatile__ ( \
+ ".code16\n\t" \
+ "pushw %%gs\n\t" \
+ "pushw %%fs\n\t" \
+ "pushw %%es\n\t" \
+ "pushw %%ds\n\t" \
+ "\n" #name ":\n\t" \
+ asm_code_str \
+ "popw %%ds\n\t" \
+ "popw %%es\n\t" \
+ "popw %%fs\n\t" \
+ "popw %%gs\n\t" \
+ ".code16gcc\n\t" \
+ : out_constraints \
+ : IN_CONSTRAINTS_NO_ROUTINE ( in_constraints ) \
+ : clobber \
+ );
+
+#endif /* ASSEMBLY */
+
+#endif /* LIBKIR_H */
diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h
new file mode 100644
index 00000000..16bfc089
--- /dev/null
+++ b/src/arch/i386/include/librm.h
@@ -0,0 +1,186 @@
+#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
+ *
+ */
+
+/* Real-mode call parameter block, as passed to real_call */
+struct real_call_params {
+ struct i386_seg_regs;
+ struct i386_regs;
+ segoff_t rm_code;
+ segoff_t reserved;
+} PACKED;
+
+/* Current location of librm in base memory */
+extern char *installed_librm;
+
+/* Start and size of our source copy of librm (i.e. the one that we
+ * can install by copying it to base memory and setting
+ * installed_librm)
+ */
+extern char librm[];
+extern size_t _librm_size[];
+
+/* Linker symbols for offsets within librm. Other symbols should
+ * almost certainly not be referred to from C code.
+ */
+extern void (*_real_to_prot[]) ( void );
+extern void (*_prot_to_real[]) ( void );
+extern void (*_prot_call[]) ( void );
+extern void (*_real_call[]) ( void );
+extern segoff_t _rm_stack[];
+extern uint32_t _pm_stack[];
+extern char _librm_ref_count[];
+
+/* Symbols within current installation of librm */
+#define LIBRM_VAR( sym ) \
+ ( * ( ( typeof ( * _ ## sym ) * ) \
+ & ( installed_librm [ (int) _ ## sym ] ) ) )
+#define LIBRM_FN( sym ) \
+ ( ( typeof ( * _ ## sym ) ) \
+ & ( installed_librm [ (int) _ ## sym ] ) )
+#define LIBRM_CONSTANT( sym ) \
+ ( ( typeof ( * _ ## sym ) ) ( _ ## sym ) )
+#define inst_real_to_prot LIBRM_FN ( real_to_prot )
+#define inst_prot_to_real LIBRM_FN ( prot_to_real )
+#define inst_prot_call LIBRM_FN ( prot_call )
+#define inst_real_call LIBRM_FN ( real_call )
+#define inst_rm_stack LIBRM_VAR ( rm_stack )
+#define inst_pm_stack LIBRM_VAR ( pm_stack )
+#define inst_librm_ref_count LIBRM_VAR ( librm_ref_count )
+#define librm_size LIBRM_CONSTANT ( librm_size )
+
+/* Functions that librm expects to be able to link to. Included here
+ * so that the compiler will catch prototype mismatches.
+ */
+extern void _phys_to_virt ( void );
+extern void _virt_to_phys ( void );
+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 void copy_to_real_librm ( uint16_t dest_seg, uint16_t dest_off,
+ void *src, size_t n ) {
+ memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
+}
+static inline void copy_from_real_librm ( void *dest,
+ uint16_t src_seg, uint16_t 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
+
+/* Copy to/from real-mode stack */
+extern uint16_t copy_to_rm_stack ( void *data, size_t size );
+extern void remove_from_rm_stack ( void *data, size_t size );
+
+/* Place/remove parameter on real-mode stack in a way that's
+ * compatible with libkir
+ */
+#define BASEMEM_PARAMETER_INIT_LIBRM( param ) \
+ copy_to_rm_stack ( & ( param ), sizeof ( param ) )
+#define BASEMEM_PARAMETER_DONE_LIBRM( param ) \
+ remove_from_rm_stack ( & ( param ), sizeof ( param ) )
+#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBRM
+#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBRM
+
+/* REAL_FRAGMENT: Declare and define a real-mode code fragment in .text16 */
+#define REAL_FRAGMENT( name, asm_code_str ) \
+ extern void name ( void ); \
+ extern char name ## _size[]; \
+ __asm__ __volatile__ ( \
+ ".section \".text16\"\n\t" \
+ ".code16\n\t" \
+ ".arch i386\n\t" \
+ #name ":\n\t" \
+ asm_code_str "\n\t" \
+ "lret\n\t" \
+ #name "_end:\n\t" \
+ ".equ " #name "_size, " #name "_end - " #name "\n\t" \
+ ".code32\n\t" \
+ ".previous\n\t" \
+ : : \
+ )
+#define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size )
+
+/* REAL_CALL: call a real-mode routine via librm */
+#define OUT_CONSTRAINTS(...) __VA_ARGS__
+#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
+#define CLOBBER(...) __VA_ARGS__
+#define REAL_CALL( routine, num_out_constraints, out_constraints, \
+ in_constraints, clobber ) \
+ do { \
+ segoff_t __routine = routine; \
+ __asm__ __volatile__ ( \
+ "pushl %" #num_out_constraints "\n\t" \
+ "call 1f\n\t" \
+ "jmp 2f\n\t" \
+ "\n1:\n\t" \
+ "pushl installed_librm\n\t" \
+ "addl $_real_call, 0(%%esp)\n\t" \
+ "ret\n\t" \
+ "\n2:\n\t" \
+ "addl $4, %%esp\n\t" \
+ : out_constraints \
+ : in_constraints \
+ : clobber \
+ ); \
+ } while ( 0 )
+
+/* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
+#define PASSTHRU(...) __VA_ARGS__
+#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
+ in_constraints, clobber ) \
+ do { \
+ segoff_t fragment; \
+ \
+ REAL_FRAGMENT ( name, asm_code_str ); \
+ \
+ fragment.segment = inst_rm_stack.segment; \
+ fragment.offset = \
+ copy_to_rm_stack ( name, FRAGMENT_SIZE ( name ) ); \
+ \
+ REAL_CALL ( fragment, num_out_constraints, \
+ PASSTHRU ( out_constraints ), \
+ PASSTHRU ( in_constraints ), \
+ PASSTHRU ( clobber ) ); \
+ \
+ remove_from_rm_stack ( NULL, FRAGMENT_SIZE ( name ) ); \
+ } while ( 0 )
+
+#endif /* ASSEMBLY */
+
+#endif /* LIBRM_H */
diff --git a/src/arch/i386/include/memsizes.h b/src/arch/i386/include/memsizes.h
new file mode 100644
index 00000000..a5bb3f2d
--- /dev/null
+++ b/src/arch/i386/include/memsizes.h
@@ -0,0 +1,34 @@
+#ifndef MEMSIZES_H
+#define MEMSIZES_H
+
+/*
+ * These structures seem to be very i386 (and, in fact, PCBIOS)
+ * specific, so I've moved them out of etherboot.h.
+ *
+ */
+
+struct e820entry {
+ uint64_t addr;
+ uint64_t size;
+ uint32_t type;
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS 4
+} __attribute__ (( packed ));
+#define E820ENTRY_SIZE 20
+#define E820MAX 32
+
+struct meminfo {
+ uint16_t basememsize;
+ uint16_t pad;
+ uint32_t memsize;
+ uint32_t map_count;
+ struct e820entry map[E820MAX];
+} __attribute__ (( packed ));
+
+extern struct meminfo meminfo;
+
+extern void get_memsizes ( void );
+
+#endif /* MEMSIZES_H */
diff --git a/src/arch/i386/include/pic8259.h b/src/arch/i386/include/pic8259.h
index 694e9d13..d3f9b879 100644
--- a/src/arch/i386/include/pic8259.h
+++ b/src/arch/i386/include/pic8259.h
@@ -8,7 +8,7 @@
#define PIC8259_H
/* For segoff_t */
-#include "segoff.h"
+#include "realmode.h"
#define IRQ_PIC_CUTOFF (8)
@@ -90,7 +90,7 @@ void dump_irq_status ( void );
* handler code, so we put prototypes and the size macro here.
*/
extern void _trivial_irq_handler ( void );
-extern void _trivial_irq_handler_end ( void );
+extern char _trivial_irq_handler_size[];
#define TRIVIAL_IRQ_HANDLER_SIZE FRAGMENT_SIZE(_trivial_irq_handler)
#endif /* PIC8259_H */
diff --git a/src/arch/i386/include/pxe_callbacks.h b/src/arch/i386/include/pxe_callbacks.h
index 9b941931..cf5a7a87 100644
--- a/src/arch/i386/include/pxe_callbacks.h
+++ b/src/arch/i386/include/pxe_callbacks.h
@@ -5,7 +5,6 @@
#define PXE_CALLBACKS_H
#include "etherboot.h"
-#include "segoff.h"
#include "pxe.h"
typedef struct {
diff --git a/src/arch/i386/include/pxe_types.h b/src/arch/i386/include/pxe_types.h
index 7b093e6a..45736a2b 100644
--- a/src/arch/i386/include/pxe_types.h
+++ b/src/arch/i386/include/pxe_types.h
@@ -10,7 +10,7 @@
/* SEGOFF16_t defined in separate header
*/
-#include "segoff.h"
+#include "realmode.h"
typedef segoff_t I386_SEGOFF16_t;
#define SEGOFF16_t I386_SEGOFF16_t
diff --git a/src/arch/i386/include/realmode.h b/src/arch/i386/include/realmode.h
index eca92b9b..d641869f 100644
--- a/src/arch/i386/include/realmode.h
+++ b/src/arch/i386/include/realmode.h
@@ -1,124 +1,124 @@
-/* Real-mode interface
- */
+#ifndef REALMODE_H
+#define REALMODE_H
#ifndef ASSEMBLY
-#include "etherboot.h"
-#include "segoff.h"
-
-typedef union {
- struct {
- union {
- uint8_t l;
- uint8_t byte;
- };
- uint8_t h;
- } PACKED;
- uint16_t word;
-} PACKED reg16_t;
-
-typedef union {
- reg16_t w;
- uint32_t dword;
-} PACKED reg32_t;
-
-/* Macros to help with defining inline real-mode trampoline fragments.
+#include "stdint.h"
+#include "compiler.h"
+#include "registers.h"
+#include "io.h"
+
+/*
+ * Data structures and type definitions
+ *
*/
-#define RM_XSTR(x) #x /* Macro hackery needed to stringify */
-#define RM_STR(x) RM_XSTR(x)
-#define RM_FRAGMENT(name, asm_code_str) \
- extern void name ( void ); \
- extern void name ## _end (void); \
- __asm__( \
- ".section \".text16\"\n\t" \
- ".code16\n\t" \
- ".arch i386\n\t" \
- ".globl " #name " \n\t" \
- #name ":\n\t" \
- asm_code_str "\n\t" \
- ".globl " #name "_end\n\t" \
- #name "_end:\n\t" \
- ".code32\n\t" \
- ".previous\n\t" \
- )
-
-#define FRAGMENT_SIZE(fragment) ( (size_t) ( ( (void*) fragment ## _end )\
- - ( (void*) (fragment) ) ) )
-
-/* Data structures in _prot_to_real and _real_to_prot. These
- * structures are accessed by assembly code as well as C code.
+
+/* 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.
*/
typedef struct {
- uint32_t esp;
- uint16_t cs;
- uint16_t ss;
- uint32_t r2p_params;
-} PACKED prot_to_real_params_t;
+ uint16_t offset;
+ uint16_t segment;
+} segoff_t PACKED;
-typedef struct {
- uint32_t ret_addr;
- uint32_t esp;
- uint32_t ebx;
- uint32_t esi;
- uint32_t edi;
- uint32_t ebp;
- uint32_t out_stack;
- uint32_t out_stack_len;
-} PACKED real_to_prot_params_t;
-
-/* Function prototypes: realmode.c
+/* 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.
+ *
*/
-#define real_call( fragment, in_stack, out_stack ) \
- _real_call ( fragment, FRAGMENT_SIZE(fragment), \
- (void*)(in_stack), \
- ( (in_stack) == NULL ? 0 : sizeof(*(in_stack)) ), \
- (void*)(out_stack), \
- ( (out_stack) == NULL ? 0 : sizeof(*(out_stack)) ) )
-extern uint16_t _real_call ( void *fragment, int fragment_len,
- void *in_stack, int in_stack_len,
- void *out_stack, int out_stack_len );
-/* Function prototypes: realmode_asm.S
+
+/*
+ * 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.
*/
-extern void rm_callback_interface;
-extern uint16_t rm_callback_interface_size;
-extern uint32_t rm_etherboot_location;
-extern void _rm_in_call ( void );
-extern void _rm_in_call_far ( void );
-
-extern void _prot_to_real_prefix ( void );
-extern void _prot_to_real_prefix_end ( void );
-extern uint16_t prot_to_real_prefix_size;
-
-extern void _real_to_prot_suffix ( void );
-extern void _real_to_prot_suffix_end ( void );
-extern uint16_t real_to_prot_suffix_size;
-
-/* PXE assembler bits */
-extern void pxe_callback_interface;
-extern uint16_t pxe_callback_interface_size;
-extern void _pxe_in_call_far ( void );
-extern void _pxenv_in_call_far ( void );
-extern void _pxe_intercept_int1a ( void );
-extern segoff_t _pxe_intercepted_int1a;
-extern segoff_t _pxe_pxenv_location;
-
-/* Global variables
+
+/*
+ * 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.
*/
-extern uint32_t real_mode_stack;
-extern size_t real_mode_stack_size;
+
+/*
+ * REAL_CALL ( routine, num_out_constraints, out_constraints,
+ * in_constraints, clobber )
+ * REAL_EXEC ( name, asm_code_str, num_out_constraints, out_constraints,
+ * in_constraints, clobber )
+ *
+ * If you have a pre-existing real-mode routine that you want to make
+ * a far call to, use REAL_CALL. If you have a code fragment that you
+ * want to copy down to base memory, execute, and then remove, use
+ * REAL_EXEC.
+ *
+ * out_constraints must be of the form OUT_CONSTRAINTS(constraints),
+ * and in_constraints must be of the form IN_CONSTRAINTS(constraints),
+ * where "constraints" is a constraints list as would be used in an
+ * inline __asm__()
+ *
+ * clobber must be of the form CLOBBER ( clobber_list ), where
+ * "clobber_list" is a clobber list as would be used in an inline
+ * __asm__().
+ *
+ * These are best illustrated by example. To write a character to the
+ * console using INT 10, you would do something like:
+ *
+ * REAL_EXEC ( rm_test_librm,
+ * "int $0x10",
+ * 1,
+ * OUT_CONSTRAINTS ( "=a" ( discard ) ),
+ * IN_CONSTRAINTS ( "a" ( 0x0e00 + character ),
+ * "b" ( 1 ) ),
+ * CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
+ *
+ * IMPORTANT: gcc does not automatically assume that input operands
+ * get clobbered. The only way to specify that an input operand may
+ * be modified is to also specify it as an output operand; hence the
+ * "(discard)" in the above code.
+ */
+
+#warning "realmode.h contains placeholders for obsolete macros"
+
+
+/* Just for now */
+#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
+#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
+#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
+
+/* To make basemem.c compile */
extern int lock_real_mode_stack;
+extern char *real_mode_stack;
+extern char real_mode_stack_size[];
+
+#define RM_FRAGMENT(name,asm) \
+ void name ( void ) {} \
+ extern char name ## _size[];
-/* Function prototypes from basemem.c
- */
-#ifdef LINUXBIOS
-/* A silly hard code that let's the code compile and work.
- * When this becomes a problem feel free to implement
- * something better.
- */
-static inline void allot_real_mode_stack(void) { real_mode_stack = 0x7c00; }
-#else
-void allot_real_mode_stack(void);
-#endif
#endif /* ASSEMBLY */
+
+#endif /* REALMODE_H */
diff --git a/src/arch/i386/include/registers.h b/src/arch/i386/include/registers.h
new file mode 100644
index 00000000..2e78d418
--- /dev/null
+++ b/src/arch/i386/include/registers.h
@@ -0,0 +1,93 @@
+#ifndef REGISTERS_H
+#define REGISTERS_H
+
+#include "stdint.h"
+#include "compiler.h"
+
+/* Basic 16-bit and 32-bit register types */
+typedef union {
+ struct {
+ union {
+ uint8_t l;
+ uint8_t byte;
+ };
+ uint8_t h;
+ } PACKED;
+ uint16_t word;
+} PACKED reg16_t;
+
+typedef union {
+ reg16_t;
+ uint32_t dword;
+} PACKED reg32_t;
+
+/* As created by pushal / read by popal */
+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;
+
+/* Our pushal/popal equivalent for segment registers */
+struct i386_seg_regs {
+ uint16_t cs;
+ uint16_t ss;
+ uint16_t ds;
+ uint16_t es;
+ uint16_t fs;
+ uint16_t gs;
+} PACKED;
+
+/* All i386 registers, as passed in by prot_call or kir_call */
+struct i386_all_regs {
+ struct i386_seg_regs;
+ struct i386_regs;
+ uint32_t i386_flags;
+} PACKED;
+
+#endif /* REGISTERS_H */
diff --git a/src/arch/i386/include/segoff.h b/src/arch/i386/include/segoff.h
deleted file mode 100644
index 822ddd33..00000000
--- a/src/arch/i386/include/segoff.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Segment:offset types and macros
- *
- * Initially written by Michael Brown (mcb30).
- */
-
-#ifndef SEGOFF_H
-#define SEGOFF_H
-
-#include <stdint.h>
-#include <osdep.h>
-#include <io.h>
-
-/* Segment:offset structure. Note that the order within the structure
- * is offset:segment.
- */
-typedef struct {
- uint16_t offset;
- uint16_t segment;
-} segoff_t;
-
-/* Macros for converting from virtual to segment:offset addresses,
- * when we don't actually care which of the many isomorphic results we
- * get.
- */
-#ifdef DEBUG_SEGMENT
-uint16_t SEGMENT ( const void * const ptr ) {
- uint32_t phys = virt_to_phys ( ptr );
- if ( phys > 0xfffff ) {
- printf ( "FATAL ERROR: segment address out of range\n" );
- }
- return phys >> 4;
-}
-#else
-#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
-#endif
-#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
-#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
-#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
-
-#endif /* SEGOFF_H */
diff --git a/src/arch/i386/include/virtaddr.h b/src/arch/i386/include/virtaddr.h
new file mode 100644
index 00000000..15fad1cc
--- /dev/null
+++ b/src/arch/i386/include/virtaddr.h
@@ -0,0 +1,85 @@
+#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 PHYSICAL_CS 0x08
+#define PHYSICAL_DS 0x10
+#define VIRTUAL_CS 0x18
+#define VIRTUAL_DS 0x20
+#define LONG_CS 0x28
+#define LONG_DS 0x30
+
+#ifndef ASSEMBLY
+
+#include "stdint.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 );
+}
+
+#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 */