Browse Source

Towards a(nother) new real-mode infrastructure, in which we take

advantage of the fact that we have to have a permanently-resident block
in base memory.
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
9fcded3d23

+ 28
- 50
src/arch/i386/core/relocate.c View File

1
-#include "virtaddr.h"
2
-#include "memsizes.h"
3
-#include "osdep.h"
4
-#include "etherboot.h"
5
-#include <gpxe/init.h>
6
-#include "relocate.h"
7
-
8
-#ifndef KEEP_IT_REAL
9
-
10
-/* by Eric Biederman */
11
-
12
-/* On some platforms etherboot is compiled as a shared library, and we use
13
- * the ELF pic support to make it relocateable.  This works very nicely
14
- * for code, but since no one has implemented PIC data yet pointer
15
- * values in variables are a a problem.  Global variables are a
16
- * pain but the return addresses on the stack are the worst.  On these
17
- * platforms relocate_to will restart etherboot, to ensure the stack
18
- * is reinitialize and hopefully get the global variables
19
- * appropriately reinitialized as well.
20
- * 
21
- */
1
+#include <virtaddr.h>
2
+#include <registers.h>
3
+#include <memsizes.h>
22
 
4
 
23
 /*
5
 /*
24
- * relocate() must be called without any hardware resources pointing
25
- * at the current copy of Etherboot.  The easiest way to achieve this
26
- * is to call relocate() from within arch_initialise(), before the NIC
27
- * gets touched in any way.
6
+ * Originally by Eric Biederman
7
+ *
8
+ * Heavily modified by Michael Brown 
28
  *
9
  *
29
  */
10
  */
30
 
11
 
40
 extern char _text[];
21
 extern char _text[];
41
 extern char _end[];
22
 extern char _end[];
42
 
23
 
43
-/* Post-relocation function table */
44
-static struct post_reloc_fn post_reloc_fns[0] __table_start(post_reloc_fn);
45
-static struct post_reloc_fn post_reloc_fns_end[0] __table_end(post_reloc_fn);
24
+/* within 1MB of 4GB is too close. 
25
+ * MAX_ADDR is the maximum address we can easily do DMA to.
26
+ *
27
+ * Not sure where this constraint comes from, but kept it from Eric's
28
+ * old code - mcb30
29
+ */
30
+#define MAX_ADDR (0xfff00000UL)
46
 
31
 
47
-static void relocate ( void ) {
32
+/**
33
+ * Relocate Etherboot
34
+ *
35
+ * @v ix86		x86 register dump from prefix
36
+ * @ret ix86		x86 registers to return to prefix
37
+ *
38
+ * This copies Etherboot to a suitable location near the top of 32-bit
39
+ * address space, and returns the physical address of the new location
40
+ * to the prefix in %edi.
41
+ */
42
+void relocate ( struct i386_all_regs *ix86 ) {
48
 	unsigned long addr, eaddr, size;
43
 	unsigned long addr, eaddr, size;
49
 	unsigned i;
44
 	unsigned i;
50
-	struct post_reloc_fn *post_reloc_fn;
51
 
45
 
52
 	/* Walk through the memory map and find the highest address
46
 	/* Walk through the memory map and find the highest address
53
 	 * below 4GB that etherboot will fit into.  Ensure etherboot
47
 	 * below 4GB that etherboot will fit into.  Ensure etherboot
183
 		      virt_to_phys ( _text ), virt_to_phys ( _end ),
177
 		      virt_to_phys ( _text ), virt_to_phys ( _end ),
184
 		      addr, addr + _end - _text );
178
 		      addr, addr + _end - _text );
185
 
179
 
186
-		relocate_to ( addr );
187
-		/* Note that we cannot make real-mode calls
188
-		 * (e.g. printf) at this point, because librm has just
189
-		 * been moved to high memory.
190
-		 */
191
-
192
-		/* Call any registered post-relocation functions.
193
-		 * librm has a post-relocation function to install a
194
-		 * new librm into base memory.
195
-		 */
196
-		for ( post_reloc_fn = post_reloc_fns;
197
-		      post_reloc_fn < post_reloc_fns_end ; post_reloc_fn++ ) {
198
-			if ( post_reloc_fn->post_reloc )
199
-				post_reloc_fn->post_reloc ();
200
-		}
201
-		
180
+		memcpy ( phys_to_virt ( addr ), _text, _end - _text );
202
 	}
181
 	}
182
+	
183
+	/* Let prefix know where the new copy is */
184
+	ix86->regs.edi = addr;
203
 }
185
 }
204
-
205
-INIT_FN ( INIT_RELOCATE, relocate, NULL, NULL );
206
-
207
-#endif /* ! KEEP_IT_REAL */

+ 0
- 216
src/arch/i386/core/virtaddr.S View File

7
 #include "virtaddr.h"
7
 #include "virtaddr.h"
8
 		
8
 		
9
 	.arch i386
9
 	.arch i386
10
-
11
-/****************************************************************************
12
- * GDT for initial transition to protected mode
13
- *
14
- * The segment values, PHYSICAL_CS et al, are defined in an external
15
- * header file virtaddr.h, since they need to be shared with librm.
16
- ****************************************************************************
17
- */
18
-	.data
19
-	.align 16
20
-
21
-gdt:
22
-gdt_limit:		.word gdt_length - 1
23
-gdt_addr:		.long 0
24
-			.word 0 /* padding */
25
-	
26
-	.org	gdt + PHYSICAL_CS
27
-physical_cs:
28
-	/* 32 bit protected mode code segment, physical addresses */
29
-	.word	0xffff,0
30
-	.byte	0,0x9f,0xcf,0
31
-	
32
-	.org	gdt + PHYSICAL_DS
33
-physical_ds:
34
-	/* 32 bit protected mode data segment, physical addresses */
35
-	.word	0xffff,0
36
-	.byte	0,0x93,0xcf,0
37
-	
38
-	.org	gdt + VIRTUAL_CS
39
-virtual_cs:
40
-	/* 32 bit protected mode code segment, virtual addresses */
41
-	.word	0xffff,0
42
-	.byte	0,0x9f,0xcf,0
43
-
44
-	.org	gdt + VIRTUAL_DS
45
-virtual_ds:	
46
-	/* 32 bit protected mode data segment, virtual addresses */
47
-	.word	0xffff,0
48
-	.byte	0,0x93,0xcf,0
49
-
50
-#ifdef CONFIG_X86_64
51
-	
52
-	.org	gdt + LONG_CS
53
-long_cs:
54
-	/* 64bit long mode code segment, base 0 */
55
-	.word	0xffff, 0
56
-	.byte	0x00, 0x9f, 0xaf , 0x00
57
-
58
-	.org	gdt + LONG_DS
59
-long_ds:
60
-	/* 64bit long mode data segment, base 0 */
61
-	.word	0xffff, 0
62
-	.byte	0x00, 0x93, 0xcf, 0x00
63
-	
64
-#endif /* CONFIG_X86_64 */
65
-	
66
-gdt_end:		
67
-	.equ	gdt_length, gdt_end - gdt
68
-
69
-	/* The virtual address offset  */	
70
-	.globl virt_offset
71
-virt_offset:	.long  	0
72
-		
73
 	.text
10
 	.text
74
 	.code32
11
 	.code32
75
 	
12
 	
76
-/****************************************************************************
77
- * run_here (flat physical addressing, position-independent)
78
- *
79
- * Set up a GDT to run Etherboot at the current location with virtual
80
- * addressing.  This call does not switch to virtual addresses or move
81
- * the stack pointer.  The GDT will be located within the copy of
82
- * Etherboot.  All registers are preserved.
83
- *
84
- * This gets called at startup and at any subsequent relocation of
85
- * Etherboot.
86
- *
87
- * Parameters: none
88
- ****************************************************************************
89
- */
90
-	.globl	run_here
91
-run_here:
92
-	/* Preserve registers */
93
-	pushl	%eax
94
-	pushl	%ebp
95
-
96
-	/* Find out where we're running */
97
-	call	1f
98
-1:	popl	%ebp
99
-	subl	$1b, %ebp
100
-
101
-	/* Store as virt_offset */
102
-	movl	%ebp, virt_offset(%ebp)
103
-
104
-	/* Set segment base addresses in GDT */
105
-	leal	virtual_cs(%ebp), %eax
106
-	pushl	%eax
107
-	pushl	%ebp
108
-	call	set_seg_base
109
-	popl	%eax /* discard */
110
-	popl	%eax /* discard */
111
-
112
-	/* Set physical location of GDT */
113
-	leal	gdt(%ebp), %eax
114
-	movl	%eax, gdt_addr(%ebp)
115
-
116
-	/* Load the new GDT */
117
-	lgdt	gdt(%ebp)
118
-
119
-	/* Reload new flat physical segment registers */
120
-	movl	$PHYSICAL_DS, %eax
121
-	movl	%eax, %ds
122
-	movl	%eax, %es
123
-	movl	%eax, %fs
124
-	movl	%eax, %gs
125
-	movl	%eax, %ss
126
-
127
-	/* Restore registers, convert return address to far return
128
-	 * address.
129
-	 */
130
-	popl	%ebp
131
-	movl	$PHYSICAL_CS, %eax
132
-	xchgl	%eax, 4(%esp)	/* cs now on stack, ret offset now in eax */
133
-	xchgl	%eax, 0(%esp)	/* ret offset now on stack, eax restored */
134
-	
135
-	/* Return to caller, reloading %cs with new value */
136
-	lret
137
-
138
-/****************************************************************************
139
- * set_seg_base (any addressing, position-independent)
140
- *
141
- * Set the base address of a pair of segments in the GDT.  This relies
142
- * on the layout of the GDT being (CS,DS) pairs.
143
- *
144
- * Parameters:
145
- *   uint32_t base_address
146
- *   struct gdt_entry * code_segment
147
- * Returns:
148
- *   none
149
- ****************************************************************************
150
- */
151
-	.globl set_seg_base
152
-set_seg_base:
153
-	pushl	%eax
154
-	pushl	%ebx
155
-	movl	12(%esp), %eax		/* %eax = base address */
156
-	movl	16(%esp), %ebx		/* %ebx = &code_descriptor */
157
-	movw	%ax, (0+2)(%ebx)	/* CS base bits 0-15 */
158
-	movw	%ax, (8+2)(%ebx)	/* DS base bits 0-15 */
159
-	shrl	$16, %eax
160
-	movb	%al, (0+4)(%ebx)	/* CS base bits 16-23 */
161
-	movb	%al, (8+4)(%ebx)	/* DS base bits 16-23 */
162
-	movb	%ah, (0+7)(%ebx)	/* CS base bits 24-31 */
163
-	movb	%ah, (8+7)(%ebx)	/* DS base bits 24-31 */
164
-	popl	%ebx
165
-	popl	%eax
166
-	ret
167
-	
168
 /****************************************************************************
13
 /****************************************************************************
169
  * _virt_to_phys (virtual addressing)
14
  * _virt_to_phys (virtual addressing)
170
  *
15
  *
254
 	popl	%eax
99
 	popl	%eax
255
 	popfl
100
 	popfl
256
 	ret
101
 	ret
257
-
258
-/****************************************************************************
259
- * relocate_to (virtual addressing)
260
- *
261
- * Relocate Etherboot to the specified address.  The runtime image
262
- * (excluding the prefix, decompressor and compressed image) is copied
263
- * to a new location, and execution continues in the new copy.  This
264
- * routine is designed to be called from C code.
265
- *
266
- * Parameters:
267
- *	uint32_t new_phys_addr
268
- ****************************************************************************
269
- */
270
-	.globl relocate_to
271
-relocate_to:
272
-	/* Save the callee save registers */
273
-	pushl	%ebp
274
-	pushl	%esi
275
-	pushl	%edi
276
-
277
-	/* Compute the physical source address and data length */
278
-	movl	$_text, %esi
279
-	movl	$_end, %ecx
280
-	subl	%esi, %ecx
281
-	addl	virt_offset, %esi
282
-
283
-	/* Compute the physical destination address */
284
-	movl	16(%esp), %edi
285
-
286
-	/* Switch to flat physical addressing */
287
-	call	_virt_to_phys
288
-	
289
-	/* Do the copy */
290
-	cld
291
-	rep movsb
292
-
293
-	/* Calculate offset to new image */
294
-	subl	%esi, %edi
295
-
296
-	/* Switch to executing in new image */
297
-	call	1f
298
-1:	popl	%ebp
299
-	leal	(2f-1b)(%ebp,%edi), %eax
300
-	jmpl	*%eax
301
-2:
302
-	/* Switch to stack in new image */
303
-	addl	%edi, %esp
304
-	
305
-	/* Call run_here() to set up GDT */
306
-	call	run_here
307
-
308
-	/* Switch to virtual addressing */
309
-	call	_phys_to_virt
310
-	
311
-	/* Restore the callee save registers */
312
-	popl	%edi
313
-	popl	%esi
314
-	popl	%ebp
315
-
316
-	/* return */
317
-	ret

+ 19
- 82
src/arch/i386/include/librm.h View File

15
  *
15
  *
16
  */
16
  */
17
 
17
 
18
-/* Real-mode call parameter block, as passed to real_call */
19
-struct real_call_params {
20
-	struct i386_seg_regs segs;
21
-	struct i386_regs regs;
22
-	segoff_t rm_code;
23
-	segoff_t reserved;
24
-} PACKED;
25
-
26
-/* Current location of librm in base memory */
27
-extern char *installed_librm;
28
-
29
-/* Start and size of our source copy of librm (i.e. the one that we
30
- * can install by copying it to base memory and setting
31
- * installed_librm)
32
- */
33
-extern char librm[];
34
-extern size_t _librm_size[];
35
-
36
-/* Linker symbols for offsets within librm.  Other symbols should
37
- * almost certainly not be referred to from C code.
38
- */
39
-extern void (*_real_to_prot[]) ( void );
40
-extern void (*_prot_to_real[]) ( void );
41
-extern void (*_prot_call[]) ( void );
42
-extern void (*_real_call[]) ( void );
43
-extern uint32_t _librm_base[];
44
-extern segoff_t _rm_stack[];
45
-extern uint32_t _pm_stack[];
46
-extern char _librm_ref_count[];
47
-
48
-/* Symbols within current installation of librm */
49
-#define LIBRM_VAR( sym ) \
50
-	( * ( ( typeof ( * _ ## sym ) * ) \
51
-	      & ( installed_librm [ (int) _ ## sym ] ) ) )
52
-#define LIBRM_FN( sym ) \
53
-	 ( ( typeof ( * _ ## sym ) ) \
54
-	      & ( installed_librm [ (int) _ ## sym ] ) )
55
-#define LIBRM_CONSTANT( sym ) \
56
-	( ( typeof ( * _ ## sym ) ) ( _ ## sym ) )
57
-#define inst_real_to_prot	LIBRM_FN ( real_to_prot )
58
-#define inst_prot_to_real	LIBRM_FN ( prot_to_real )
59
-#define inst_prot_call		LIBRM_FN ( prot_call )
60
-#define inst_real_call		LIBRM_FN ( real_call )
61
-#define inst_librm_base		LIBRM_VAR ( librm_base )
62
-#define inst_rm_stack		LIBRM_VAR ( rm_stack )
63
-#define inst_pm_stack		LIBRM_VAR ( pm_stack )
64
-#define inst_librm_ref_count	LIBRM_VAR ( librm_ref_count )
65
-#define librm_size		LIBRM_CONSTANT ( librm_size )
66
-
67
-/* Symbols within local (uninstalled) copy of librm */
68
-extern uint32_t librm_base;
18
+/* Variables in librm.S, present in the normal data segment */
19
+extern uint16_t rm_sp;
20
+extern uint16_t rm_ss;
21
+extern uint16_t rm_cs;
22
+extern uint32_t pm_esp;
69
 
23
 
70
 /* Functions that librm expects to be able to link to.  Included here
24
 /* Functions that librm expects to be able to link to.  Included here
71
  * so that the compiler will catch prototype mismatches.
25
  * so that the compiler will catch prototype mismatches.
72
  */
26
  */
73
-extern void _phys_to_virt ( void );
74
-extern void _virt_to_phys ( void );
75
 extern void gateA20_set ( void );
27
 extern void gateA20_set ( void );
76
 
28
 
77
 /*
29
 /*
132
 		".arch i386\n\t"					\
84
 		".arch i386\n\t"					\
133
 		#name ":\n\t"						\
85
 		#name ":\n\t"						\
134
 		asm_code_str "\n\t"					\
86
 		asm_code_str "\n\t"					\
135
-		"lret\n\t"						\
87
+		"ret\n\t"						\
136
 		#name "_end:\n\t"					\
88
 		#name "_end:\n\t"					\
137
 		".equ " #name "_size, " #name "_end - " #name "\n\t"	\
89
 		".equ " #name "_size, " #name "_end - " #name "\n\t"	\
138
 		".code32\n\t"						\
90
 		".code32\n\t"						\
143
 
95
 
144
 /* REAL_CALL: call a real-mode routine via librm */
96
 /* REAL_CALL: call a real-mode routine via librm */
145
 #define OUT_CONSTRAINTS(...) __VA_ARGS__
97
 #define OUT_CONSTRAINTS(...) __VA_ARGS__
146
-#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
98
+#define IN_CONSTRAINTS(...) __VA_ARGS__
147
 #define CLOBBER(...) __VA_ARGS__
99
 #define CLOBBER(...) __VA_ARGS__
148
-#define REAL_CALL( routine, num_out_constraints, out_constraints,	     \
149
-		   in_constraints, clobber )				     \
150
-	do {								     \
151
-		segoff_t __routine = routine;				     \
152
-		__asm__ __volatile__ (					     \
153
-				      "pushl %" #num_out_constraints "\n\t"  \
154
-				      "call 1f\n\t"			     \
155
-				      "jmp 2f\n\t"			     \
156
-				      "\n1:\n\t"			     \
157
-				      "pushl installed_librm\n\t"	     \
158
-				      "addl $_real_call, 0(%%esp)\n\t"	     \
159
-				      "ret\n\t"				     \
160
-				      "\n2:\n\t"			     \
161
-				      "addl $4, %%esp\n\t"		     \
162
-				      : out_constraints			     \
163
-				      : in_constraints			     \
164
-				      : clobber				     \
165
-				      );				     \
100
+#define REAL_CALL( routine, num_out_constraints, out_constraints,	\
101
+		   in_constraints, clobber )				\
102
+	do {								\
103
+		__asm__ __volatile__ (					\
104
+				      "pushl $" #routine "\n\t"		\
105
+				      "call real_call\n\t"		\
106
+				      "addl $4, %%esp\n\t"		\
107
+				      : out_constraints			\
108
+				      : in_constraints			\
109
+				      : clobber				\
110
+				      );				\
166
 	} while ( 0 )
111
 	} while ( 0 )
167
 
112
 
168
 /* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
113
 /* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
170
 #define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
115
 #define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
171
 		   in_constraints, clobber )				     \
116
 		   in_constraints, clobber )				     \
172
 	do {								     \
117
 	do {								     \
173
-		segoff_t fragment;					     \
174
-									     \
175
 		REAL_FRAGMENT ( name, asm_code_str );			     \
118
 		REAL_FRAGMENT ( name, asm_code_str );			     \
176
 									     \
119
 									     \
177
-		fragment.segment = inst_rm_stack.segment;		     \
178
-		fragment.offset =					     \
179
-			copy_to_rm_stack ( name, FRAGMENT_SIZE ( name ) );   \
180
-									     \
181
-		REAL_CALL ( fragment, num_out_constraints,		     \
120
+		REAL_CALL ( name, num_out_constraints,			     \
182
 			    PASSTHRU ( out_constraints ),		     \
121
 			    PASSTHRU ( out_constraints ),		     \
183
 			    PASSTHRU ( in_constraints ),		     \
122
 			    PASSTHRU ( in_constraints ),		     \
184
 			    PASSTHRU ( clobber ) );			     \
123
 			    PASSTHRU ( clobber ) );			     \
185
-									     \
186
-		remove_from_rm_stack ( NULL, FRAGMENT_SIZE ( name ) );	     \
187
 	} while ( 0 )
124
 	} while ( 0 )
188
 
125
 
189
 #endif /* ASSEMBLY */
126
 #endif /* ASSEMBLY */

+ 1
- 1
src/arch/i386/include/realmode.h View File

18
 typedef struct {
18
 typedef struct {
19
 	uint16_t offset;
19
 	uint16_t offset;
20
 	uint16_t segment;
20
 	uint16_t segment;
21
-} segoff_t PACKED;
21
+} __attribute__ (( packed )) segoff_t;
22
 
22
 
23
 /* Macro hackery needed to stringify bits of inline assembly */
23
 /* Macro hackery needed to stringify bits of inline assembly */
24
 #define RM_XSTR(x) #x
24
 #define RM_XSTR(x) #x

+ 11
- 6
src/arch/i386/include/virtaddr.h View File

5
  *
5
  *
6
  * Don't change these unless you really know what you're doing.
6
  * Don't change these unless you really know what you're doing.
7
  */
7
  */
8
-#define PHYSICAL_CS 0x08
9
-#define PHYSICAL_DS 0x10
10
-#define VIRTUAL_CS 0x18
11
-#define VIRTUAL_DS 0x20
12
-#define LONG_CS 0x28
13
-#define LONG_DS 0x30
8
+
9
+#define VIRTUAL_CS 0x08
10
+#define VIRTUAL_DS 0x10
11
+#define PHYSICAL_CS 0x18
12
+#define PHYSICAL_DS 0x20
13
+#define REAL_CS 0x28
14
+#define REAL_DS 0x30
15
+#if 0
16
+#define LONG_CS 0x38
17
+#define LONG_DS 0x40
18
+#endif
14
 
19
 
15
 #ifndef ASSEMBLY
20
 #ifndef ASSEMBLY
16
 
21
 

+ 31
- 32
src/arch/i386/prefix/dskprefix.S View File

3
  *
3
  *
4
  * SYS_SIZE is the number of clicks (16 bytes) to be loaded.
4
  * SYS_SIZE is the number of clicks (16 bytes) to be loaded.
5
  */
5
  */
6
-.equ	SYSSIZE, 8192	# 8192 * 16 bytes = 128kB maximum size of .ROM file
6
+.globl	SYSSIZE
7
+.equ	SYSSIZE, _load_size_pgh
7
 
8
 
8
 /*	floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
9
 /*	floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
9
  *	modified by Drew Eckhardt
10
  *	modified by Drew Eckhardt
143
 	 * start of loaded image.
144
 	 * start of loaded image.
144
 	 */
145
 	 */
145
 
146
 
146
-start_runtime:
147
-
148
-#ifdef	COMPRESS
149
-	/* Decompress runtime image.  %es:0000 points to decompressed
150
-	 * image on exit.
151
-	 */
152
-	lcall	$SYSSEG, $decompress16
153
-#endif
154
-	
155
-	/* Set up internal environment.  Address of entry-point
156
-	 * function is returned in %es:di.
157
-	 */
158
-	pushw	%es		/* setup16 says %ds:0000 must point to image */
159
-	popw	%ds
160
-	movw	$setup16, %di
161
-	pushw	%cs
162
-	call	ljmp_to_es_di
163
-
164
-	/* Call to arch_main.  Register INT19 as an exit path.  This
165
-	 * call will never return.
166
-	 */
167
-	movl	$exit_via_int19, %eax
168
-	pushl	$arch_main
169
-	pushl	%eax		/* Dummy return address */
170
-
171
-	/* Do the equivalent of ljmp *%es:di */
172
-ljmp_to_es_di:	
173
-	pushw	%es
174
-	pushw	%di
175
-	lret
147
+	/* Jump to loaded copy */
148
+	ljmp	$SYSSEG, $start_runtime
176
 
149
 
177
 /* This routine loads the system at address SYSSEG<<4, making sure no 64kB
150
 /* This routine loads the system at address SYSSEG<<4, making sure no 64kB
178
  * boundaries are crossed. We try to load it as fast as possible, loading whole
151
  * boundaries are crossed. We try to load it as fast as possible, loading whole
181
  * in:	es - starting address segment (normally SYSSEG)
154
  * in:	es - starting address segment (normally SYSSEG)
182
  */
155
  */
183
 read_it: 
156
 read_it: 
184
-	movw	$1,sread		/* don't reload the prefix */
157
+	movw	$0,sread		/* load whole image including prefix */
185
 	movw	%es,%ax
158
 	movw	%es,%ax
186
 	testw	$0x0fff, %ax
159
 	testw	$0x0fff, %ax
187
 die:	jne	die			/* es must be at 64kB boundary */
160
 die:	jne	die			/* es must be at 64kB boundary */
374
 	.org 510, 0
347
 	.org 510, 0
375
 	.word 0xAA55
348
 	.word 0xAA55
376
 
349
 
350
+start_runtime:
351
+	/* Install .text16 and .data16 to top of base memory */
352
+	call	alloc_basemem
353
+	call	install_basemem
354
+
355
+	/* Install .text and .data to 2MB mark */
356
+	movl	$(2<<20), %edi
357
+	call	install_highmem
358
+
359
+	/* Jump to .text16 segment */
360
+	pushw	%ax
361
+	pushw	$1f
362
+	lret
363
+	.section ".text16", "awx", @progbits
364
+1:
365
+	call	init_gdt
366
+	pushl	$initialise
367
+	data32 call	prot_call
368
+	popl	%eax /* discard */
369
+	pushl	$main
370
+	data32 call	prot_call
371
+	popl	%eax /* discard */
372
+
373
+	/* Boot next device */
374
+	int $0x18
375
+

+ 79
- 96
src/arch/i386/scripts/i386.lds View File

15
      * addresses, but may have individual link addresses depending on
15
      * addresses, but may have individual link addresses depending on
16
      * the memory model being used.
16
      * the memory model being used.
17
      *
17
      *
18
-     * The linker symbols {prefix,decompress,text,data}_link_addr,
19
-     * load_addr, and _max_align may be specified explicitly.  If not
20
-     * specified, they will default to:
18
+     * The linker symbols {prefix,text}_link_addr, load_addr, and
19
+     * _max_align may be specified explicitly.  If not specified, they
20
+     * will default to:
21
      *
21
      *
22
      *   _prefix_link_addr	= 0
22
      *   _prefix_link_addr	= 0
23
-     *   _decompress_link_addr	= 0
24
      *   _text_link_addr	= 0
23
      *   _text_link_addr	= 0
25
-     *   _data_link_addr	= _text_link_addr + sizeof ( text sections )
26
      *   _load_addr		= 0
24
      *   _load_addr		= 0
27
      *   _max_align		= 16
25
      *   _max_align		= 16
28
      * 
26
      * 
39
      * >16-byte alignment of physical addresses when -DKEEP_IT_REAL is
37
      * >16-byte alignment of physical addresses when -DKEEP_IT_REAL is
40
      * used (though virtual addresses will still be fully aligned).
38
      * used (though virtual addresses will still be fully aligned).
41
      *
39
      *
42
-     * The real-mode prefixes rely on _text_link_addr and
43
-     * _decompress_link_addr being 0, since they issue far calls into
44
-     * those sections, thus requiring that symbol_value ==
45
-     * symbol_offset therein.  Using the linker to calculate
46
-     * e.g. offset_setup16=setup16-_text will not work, since you then
47
-     * cannot use the reference from the prefix to setup16 to drag in
48
-     * setup16.o.  Life is hard.
49
-     *
50
-     * If librm is included, then it must go at offset 0 within the
51
-     * text section.  This is because librm is dual-usage: it is
52
-     * called from setup16 with %cs:0000 pointing to the start of the
53
-     * text section, and later it will be copied to base memory and
54
-     * called with %cs:0000 pointing to the start of librm.
55
-     *
56
-     * The decompressor is designed to decompress in-place.  After
57
-     * calling the decompressor, the image will look exactly the same
58
-     * as the uncompressed image; the compressed data and the
59
-     * decompressor code itself will have been overwritten.
60
      */
40
      */
61
 
41
 
62
     /*
42
     /*
72
 	_entry = .;
52
 	_entry = .;
73
 	*(.prefix)
53
 	*(.prefix)
74
 	*(.prefix.*)
54
 	*(.prefix.*)
55
+	_eprefix_progbits = .;
75
     }
56
     }
76
     
57
     
77
     _eprefix = .;
58
     _eprefix = .;
78
 
59
 
79
     /*
60
     /*
80
-     * The decompressor (may be absent)
61
+     * The 16-bit sections, if present
81
      */
62
      */
82
 
63
 
83
-    _decompress_link_addr = DEFINED ( _decompress_link_addr ) ?
84
-			      _decompress_link_addr : 0;
85
-    . = _decompress_link_addr;
86
-    _decompress = .;
64
+    _text16_link_addr = 0;
65
+    . = _text16_link_addr;
66
+    _text16 = .;
67
+
68
+    .text16 : AT ( _text16_load_offset + __text16 ) {
69
+	__text16 = .;
70
+	*(.text16)
71
+	*(.text16.*)
72
+	_etext16_progbits = .;
73
+    } = 0x9090
74
+
75
+    _etext16 = .;
76
+
77
+    _data16_link_addr = 0;
78
+    . = _data16_link_addr;
79
+    _data16 = .;
87
 
80
 
88
-    .decompress : AT ( _decompress_load_offset + __decompress ) {
89
-	    __decompress = .;
90
-	    *(.decompress)
91
-	    *(.decompress.*)
81
+    .rodata16 : AT ( _data16_load_offset + __rodata16 ) {
82
+	__rodata16 = .;
83
+	*(.rodata16)
84
+	*(.rodata16.*)
85
+    }
86
+    .data16 : AT ( _data16_load_offset + __data16 ) {
87
+	__data16 = .;
88
+	*(.data16)
89
+	*(.data16.*)
90
+	_edata16_progbits = .;
91
+    }
92
+    .bss16 : AT ( _data16_load_offset + __bss16 ) {
93
+	__bss16 = .;
94
+	_bss16 = .;
95
+	*(.bss16)
96
+	*(.bss16.*)
97
+	_ebss16 = .;
98
+    }
99
+    .stack16 : AT ( _data16_load_offset + __stack16 ) {
100
+	__stack16 = .;
101
+	*(.stack16)
102
+	*(.stack16.*)
92
     }
103
     }
93
 
104
 
94
-    _edecompress = .;
105
+    _edata16 = .;
95
 
106
 
96
     /*
107
     /*
97
-     * The text sections
108
+     * The 32-bit sections
98
      */
109
      */
99
 
110
 
100
     _text_link_addr = DEFINED ( _text_link_addr ) ? _text_link_addr : 0;
111
     _text_link_addr = DEFINED ( _text_link_addr ) ? _text_link_addr : 0;
101
     . = _text_link_addr;
112
     . = _text_link_addr;
102
     _text = .;
113
     _text = .;
103
 
114
 
104
-    .text16 : AT ( _text_load_offset + __text16 ) {
105
-	__text16 = .;
106
-
107
-	/* librm is a special case; it must go at the start of the
108
-	 * text section if it is included.
109
-	 */
110
-	_assert = ASSERT ( ( . == _text_link_addr ), "librm cannot go first" );
111
-	*(.librm)
112
-
113
-	*(.text16)
114
-	*(.text16.*)
115
-    } = 0x9090
116
-
117
     .text : AT ( _text_load_offset + __text ) {
115
     .text : AT ( _text_load_offset + __text ) {
118
 	__text = .;
116
 	__text = .;
119
 	*(.text)
117
 	*(.text)
122
 
120
 
123
     _etext = .;
121
     _etext = .;
124
 
122
 
125
-    /*
126
-     * The data sections
127
-     */
128
-
129
-    _data_link_addr = DEFINED ( _data_link_addr ) ? _data_link_addr : .;
130
-    . = _data_link_addr;
131
     _data = .;
123
     _data = .;
132
 
124
 
133
-    .rodata : AT ( _data_load_offset + __rodata ) {
125
+    .rodata : AT ( _text_load_offset + __rodata ) {
134
 	__rodata = .;
126
 	__rodata = .;
135
 	*(.rodata)
127
 	*(.rodata)
136
 	*(.rodata.*)
128
 	*(.rodata.*)
137
     }
129
     }
138
-
139
-    .data : AT ( _data_load_offset + __data ) {
130
+    .data : AT ( _text_load_offset + __data ) {
140
 	__data = .;
131
 	__data = .;
141
 	*(.data)
132
 	*(.data)
142
 	*(.data.*)
133
 	*(.data.*)
143
 	*(SORT(.tbl.*))		/* Various tables.  See include/tables.h */
134
 	*(SORT(.tbl.*))		/* Various tables.  See include/tables.h */
144
-	_progbits_end = .;
135
+	_etext_progbits = .;
145
     }
136
     }
146
-
147
-    .bss : AT ( _data_load_offset + __bss ) {
137
+    .bss : AT ( _text_load_offset + __bss ) {
148
 	__bss = .;
138
 	__bss = .;
149
 	_bss = .;
139
 	_bss = .;
150
 	*(.bss)
140
 	*(.bss)
152
 	*(COMMON)
142
 	*(COMMON)
153
 	_ebss = .;
143
 	_ebss = .;
154
     }
144
     }
155
-
156
-    .stack : AT ( _data_load_offset + __stack ) {
145
+    .stack : AT ( _text_load_offset + __stack ) {
157
 	__stack = .;
146
 	__stack = .;
158
 	*(.stack)
147
 	*(.stack)
159
 	*(.stack.*)
148
 	*(.stack.*)
188
     _prefix_load_offset	    = ALIGN ( _max_align );
177
     _prefix_load_offset	    = ALIGN ( _max_align );
189
     _prefix_load_addr	    = _prefix_link_addr + _prefix_load_offset;
178
     _prefix_load_addr	    = _prefix_link_addr + _prefix_load_offset;
190
     _prefix_size	    = _eprefix - _prefix;
179
     _prefix_size	    = _eprefix - _prefix;
191
-    .			    = _prefix_load_addr + _prefix_size;
192
-
193
-    .			   -= _decompress_link_addr;
194
-    _decompress_load_offset = ALIGN ( _max_align );
195
-    _decompress_load_addr   = _decompress_link_addr + _decompress_load_offset;
196
-    _decompress_size	    = _edecompress - _decompress;
197
-    .			    = _decompress_load_addr + _decompress_size;
180
+    _prefix_progbits_size   = _eprefix_progbits - _prefix;
181
+    .			    = _prefix_load_addr + _prefix_progbits_size;
182
+
183
+    .			   -= _text16_link_addr;
184
+    _text16_load_offset	    = ALIGN ( _max_align );
185
+    _text16_load_addr	    = _text16_link_addr + _text16_load_offset;
186
+    _text16_size	    = _etext16 - _text16;
187
+    _text16_progbits_size   = _etext16_progbits - _text16;
188
+    .			    = _text16_load_addr + _text16_progbits_size;
189
+
190
+    .			   -= _data16_link_addr;
191
+    _data16_load_offset	    = ALIGN ( _max_align );
192
+    _data16_load_addr	    = _data16_link_addr + _data16_load_offset;
193
+    _data16_size	    = _edata16 - _data16;
194
+    _data16_progbits_size   = _edata16_progbits - _data16;
195
+    .			    = _data16_load_addr + _data16_progbits_size;
198
 
196
 
199
     .			   -= _text_link_addr;
197
     .			   -= _text_link_addr;
200
     _text_load_offset	    = ALIGN ( _max_align );
198
     _text_load_offset	    = ALIGN ( _max_align );
201
     _text_load_addr	    = _text_link_addr + _text_load_offset;
199
     _text_load_addr	    = _text_link_addr + _text_load_offset;
202
     _text_size		    = _etext - _text;
200
     _text_size		    = _etext - _text;
203
-    .			    = _text_load_addr + _text_size;
201
+    _text_progbits_size	    = _etext_progbits - _text;
202
+    .			    = _text_load_addr + _text_progbits_size;
203
+
204
+    .			    = ALIGN ( _max_align );
204
 
205
 
205
-    .			   -= _data_link_addr;
206
-    _data_load_offset	    = ALIGN ( _max_align );
207
-    _data_load_addr	    = _data_link_addr + _data_load_offset;
208
-    _data_size		    = _edata - _data;
209
-    .			    = _data_load_addr + _data_size;
206
+    _load_size		    = . - _load_addr;
210
 
207
 
211
     /*
208
     /*
212
      * Alignment checks.  ALIGN() can only operate on the location
209
      * Alignment checks.  ALIGN() can only operate on the location
218
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
215
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
219
 		       "_prefix is badly aligned" );
216
 		       "_prefix is badly aligned" );
220
 
217
 
221
-    . = _decompress_load_addr - _prefix_link_addr;
218
+    . = _text16_load_addr - _text16_link_addr;
222
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
219
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
223
-		       "_decompress is badly aligned" );
220
+		       "_text16 is badly aligned" );
224
 
221
 
225
-    . = _text_load_addr - _text_link_addr;
222
+    . = _data16_load_addr - _data16_link_addr;
226
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
223
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
227
-		       "_text is badly aligned" );
224
+		       "_data16 is badly aligned" );
228
 
225
 
229
-    . = _data_load_addr - _data_link_addr;
226
+    . = _text_load_addr - _text_link_addr;
230
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
227
     _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
231
-		       "_data is badly aligned" );
232
-
233
-    /*
234
-     * setup16 needs to know this when KEEP_IT_REAL is used.  There
235
-     * are no harmful side-effects of calculating it all the time.
236
-     */
237
-    _text_load_size_pgh = ( _data_load_addr - _text_load_addr ) / 16 ;
228
+		       "_text is badly aligned" );
238
 
229
 
239
     /*
230
     /*
240
-     * Useful-to-know values.
231
+     * Values calculated to save code from doing it
241
      */
232
      */
242
-
243
-    /* Size of the decompressed runtime image */
244
-    _runtime_size = _edata - _text;
245
-    /* Size of the initialised-contents portion of the runtime image */
246
-    _runtime_progbits_size = _progbits_end - _text;
247
-    /* Size of the (non-compressed) binary file */
248
-    _file_size = _prefix_size + _runtime_progbits_size;
249
-    /* Size of the non-compressed portion of the compressed binary file */
250
-    _zfile_noncompressed_size = _prefix_size + _decompress_size;
233
+    _load_size_pgh	= ( _load_size / 16 );
251
 }
234
 }

+ 283
- 559
src/arch/i386/transitions/librm.S View File

8
 /* Drag in local definitions */
8
 /* Drag in local definitions */
9
 #include "librm.h"
9
 #include "librm.h"
10
 
10
 
11
-/* Drag in FREE_BASEMEM_HEADER_SIZE */
12
-#include "basemem.h"
13
-
14
-/****************************************************************************
15
- * This file defines librm: a block of code that is designed to reside
16
- * permanently in base memory and provide the interface between
17
- * real-mode code running in base memory and protected-mode code
18
- * running in high memory.  It provides the following functions:
19
- *
20
- *   real_to_prot &	switch between real and protected mode 
21
- *   prot_to_real	while running in base memory, preserving 
22
- *			all non-segment registers
23
- *
24
- *   real_call		issue a call to a real-mode routine from
25
- *			protected-mode code running in high memory
26
- *
27
- *   prot_call		issue a call to a protected-mode routine from
28
- *			real-mode code running in base memory
29
- *
30
- * librm requires the following functions to be present in the
31
- * protected-mode code:
32
- *
33
- *   _phys_to_virt	Switch from physical to virtual addressing.  This
34
- *			routine must be position-independent and must
35
- *			*not* assume that it is genuinely running with
36
- *			flat physical addresses
37
- *
38
- *   _virt_to_phys	Switch from virtual to physical addresses.
39
- *
40
- *   gateA20_set	Enable the A20 line to permit access to the odd
41
- *			megabytes of RAM.  (This function will be called
42
- *			with virtual addresses set up).
43
- *
44
- * librm needs to be linked against the protected-mode binary so that
45
- * it can import the symbols for these functions.
46
- *
47
- * librm requires that the protected-mode code set up the following
48
- * segments:
49
- *
50
- *   PHYSICAL_CS	32-bit pmode code and data segments with flat
51
- *   PHYSICAL_DS	physical addresses.
52
- *
53
- *   VIRTUAL_CS		32-bit pmode code segment with virtual
54
- *			addressing, such that a protected-mode routine
55
- *			can always be found at $VIRTUAL_CS:routine.
56
- *
57
- * These segments must be set as #define constants when compiling
58
- * librm.  Edit librm.h to change the values.
59
- *
60
- * librm does not know the location of the code executing in high
61
- * memory.  It relies on the code running in high memory setting up a
62
- * GDT such that the high-memory code is accessible at virtual
63
- * addresses fixed at compile-time.
64
- *
65
- * librm symbols are exported as absolute values and represent offsets
66
- * into librm.  This is the most useful form of the symbols, since
67
- * librm is basically a binary blob that you place somewhere in base
68
- * memory.
69
- *
70
- * librm.h provides convenient ways to use these symbols: you simply
71
- * set the pointer ( char * ) installed_librm to point to wherever
72
- * librm is installed, and can then use e.g. inst_rm_stack just like
73
- * any other variable and have it automatically refer to the value of
74
- * rm_stack in the installed librm.  Macro trickery makes this
75
- * completely transparent, and the resulting assembler code is
76
- * amazingly efficient.
77
- *
78
- * Note that librm must be called in genuine real mode, not 16:16 or
79
- * 16:32 protected mode.  It makes the assumption that
80
- * physical_address = 16*segment+offset, and also that it can use
81
- * OFFSET(%bp) to access stack variables.  The former assumption will
82
- * break in either protected mode, the latter may break in 16:32
83
- * protected mode.
84
- ****************************************************************************
85
- */
86
-
87
-/*
88
- * Default values for pmode segments if not defined
89
- */
90
-#ifndef PHYSICAL_CS
91
-#warning "Assuming PHYSICAL_CS = 0x08"
92
-#define PHYSICAL_CS 0x08
93
-#endif
94
-#ifndef PHYSICAL_DS
95
-#warning "Assuming PHYSICAL_DS = 0x10"
96
-#define PHYSICAL_DS 0x10
97
-#endif
98
-#ifndef VIRTUAL_CS
99
-#warning "Assuming VIRTUAL_CS = 0x18"
100
-#define VIRTUAL_CS 0x18
101
-#endif
102
-
103
 /* For switches to/from protected mode */
11
 /* For switches to/from protected mode */
104
 #define CR0_PE 1
12
 #define CR0_PE 1
105
 
13
 
109
 #define SIZEOF_REAL_MODE_REGS	( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
17
 #define SIZEOF_REAL_MODE_REGS	( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
110
 #define SIZEOF_I386_FLAGS	4
18
 #define SIZEOF_I386_FLAGS	4
111
 #define SIZEOF_I386_ALL_REGS	( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
19
 #define SIZEOF_I386_ALL_REGS	( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
112
-#define SIZEOF_SEGOFF_T		4
113
-#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_REAL_MODE_REGS + 2 * SIZEOF_SEGOFF_T )
114
 	
20
 	
115
-	.text
116
 	.arch i386
21
 	.arch i386
117
-	.section ".librm", "awx", @progbits
118
-	.align 16
119
-
120
-	.globl	librm
121
-librm:
122
-	
123
-_librm_start:
124
-
125
-#undef OFFSET
126
-#define OFFSET(sym) ( sym - _librm_start )
127
-
128
-#undef EXPORT
129
-#define EXPORT(sym) \
130
-	.globl sym ; \
131
-	.globl _ ## sym ;  \
132
-	.equ _ ## sym, OFFSET(sym) ; \
133
-	sym
22
+	.section ".text16", "awx", @progbits
134
 
23
 
135
 /****************************************************************************
24
 /****************************************************************************
136
- * Note that the first sizeof(struct free_base_memory_header) bytes of
137
- * librm will get vapourised by free_base_memory().  Since we need
138
- * librm to continue working even when this happens, we put some
139
- * padding here.
25
+ * Global descriptor table
140
  *
26
  *
141
- * We must also ensure that the total size of librm is <1kB, otherwise
142
- * free_base_memory() will stomp somewhere in the middle of us as
143
- * well...
144
- ****************************************************************************
145
- */
146
-	.fill FREE_BASEMEM_HEADER_SIZE, 1, 0
147
-
148
-/****************************************************************************
149
- * Record of the current physical location of the installed copy.
150
- * Used by prot_call in order to return via the current installed copy
151
- * even if Etherboot has been relocated during the protected-mode
152
- * call.
153
- ****************************************************************************
154
- */
155
-EXPORT(librm_base):
156
-librm_base:	.long 0
157
-		
158
-/****************************************************************************
159
- * GDT for initial transition to protected mode
27
+ * Call init_gdt to set up the GDT before attempting to use any
28
+ * protected-mode code.
160
  *
29
  *
161
- * PHYSICAL_CS and PHYSICAL_DS are defined in an external header file.
162
- * We use only those selectors, and construct our GDT to match the
163
- * selector values we're asked to use.  Use PHYSICAL_CS=0x08 and
164
- * PHYSICAL_DS=0x10 to minimise the space occupied by this GDT.
165
- *
166
- * Note: pm_gdt is also used to store the location of the
167
- * protected-mode GDT as recorded on entry to prot_to_real.
168
- ****************************************************************************
169
- */
170
-	.align 16
171
-pm_gdt:
172
-pm_gdt_limit:		.word pm_gdt_length - 1
173
-pm_gdt_addr:		.long 0
174
-			.word 0 /* padding */
175
-	
176
-	.org	pm_gdt + PHYSICAL_CS
177
-pm_gdt_pm_cs:
178
-	/* 32 bit protected mode code segment, physical addresses */
179
-	.word	0xffff, 0
180
-	.byte	0, 0x9f, 0xcf, 0
181
-	
182
-	.org	pm_gdt + PHYSICAL_DS
183
-pm_gdt_pm_ds:
184
-	/* 32 bit protected mode data segment, physical addresses */
185
-	.word	0xffff,0
186
-	.byte	0,0x93,0xcf,0
187
-	
188
-pm_gdt_end:		
189
-	.equ	pm_gdt_length, pm_gdt_end - pm_gdt
190
-
191
-/****************************************************************************
192
- * GDT for transition to real mode
193
- *
194
- * This is used primarily to set 64kB segment limits.  Define
195
- * FLATTEN_REAL_MODE if you want to use so-called "flat real mode"
196
- * with 4GB limits instead.  The base address of each of the segments
197
- * will be adjusted at run-time.
30
+ * Define FLATTEN_REAL_MODE if you want to use so-called "flat real
31
+ * mode" with 4GB limits instead.
198
  *
32
  *
199
  * NOTE: This must be located before prot_to_real, otherwise gas
33
  * NOTE: This must be located before prot_to_real, otherwise gas
200
  * throws a "can't handle non absolute segment in `ljmp'" error due to
34
  * throws a "can't handle non absolute segment in `ljmp'" error due to
201
- * not knowing the value of RM_CS when the ljmp is encountered.
35
+ * not knowing the value of REAL_CS when the ljmp is encountered.
202
  *
36
  *
203
- * Note also that putting ".word rm_gdt_end - rm_gdt - 1" directly
204
- * into rm_gdt_limit, rather than going via rm_gdt_length, will also
205
- * produce the "non absolute segment" error.  This is most probably a
206
- * bug in gas.
37
+ * Note also that putting ".word gdt_end - gdt - 1" directly into
38
+ * gdt_limit, rather than going via gdt_length, will also produce the
39
+ * "non absolute segment" error.  This is most probably a bug in gas.
207
  ****************************************************************************
40
  ****************************************************************************
208
  */
41
  */
209
 	
42
 	
212
 #else
45
 #else
213
 #define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00
46
 #define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00
214
 #endif
47
 #endif
48
+	.section ".text16"
215
 	.align 16
49
 	.align 16
216
-rm_gdt:
217
-rm_gdt_limit:		.word rm_gdt_length - 1
218
-rm_gdt_base:		.long 0
50
+gdt:
51
+gdt_limit:		.word gdt_length - 1
52
+gdt_base:		.long 0
219
 			.word 0 /* padding */
53
 			.word 0 /* padding */
54
+
55
+	.org	gdt + VIRTUAL_CS, 0
56
+virtual_cs:	/* 32 bit protected mode code segment, virtual addresses */
57
+	.word	0xffff, 0
58
+	.byte	0, 0x9f, 0xcf, 0
59
+
60
+	.org	gdt + VIRTUAL_DS, 0
61
+virtual_ds:	/* 32 bit protected mode data segment, virtual addresses */
62
+	.word	0xffff, 0
63
+	.byte	0, 0x93, 0xcf, 0
220
 	
64
 	
221
-rm_gdt_rm_cs: 	/* 16 bit real mode code segment */
222
-	.equ	RM_CS, rm_gdt_rm_cs - rm_gdt
223
-	.word	0xffff,(0&0xffff)
224
-	.byte	(0>>16),0x9b,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24)
225
-	
226
-rm_gdt_rm_ds:	/* 16 bit real mode data segment */
227
-	.equ	RM_DS, rm_gdt_rm_ds - rm_gdt
228
-	.word	0xffff,(0&0xffff)
229
-	.byte	(0>>16),0x93,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24)
65
+	.org	gdt + PHYSICAL_CS, 0
66
+physical_cs:	/* 32 bit protected mode code segment, physical addresses */
67
+	.word	0xffff, 0
68
+	.byte	0, 0x9f, 0xcf, 0
69
+
70
+	.org	gdt + PHYSICAL_DS, 0
71
+physical_ds:	/* 32 bit protected mode data segment, physical addresses */
72
+	.word	0xffff, 0
73
+	.byte	0, 0x93, 0xcf, 0	
74
+
75
+	.org	gdt + REAL_CS, 0
76
+real_cs: 	/* 16 bit real mode code segment */
77
+	.word	0xffff, 0
78
+	.byte	0, 0x9b, RM_LIMIT_16_19__AVL__SIZE__GRANULARITY, 0
79
+
80
+	.org	gdt + REAL_DS	
81
+real_ds:	/* 16 bit real mode data segment */
82
+	.word	0xffff, 0
83
+	.byte	0, 0x93, RM_LIMIT_16_19__AVL__SIZE__GRANULARITY, 0
230
 	
84
 	
231
-rm_gdt_end:
232
-	.equ	rm_gdt_length, rm_gdt_end - rm_gdt
85
+gdt_end:
86
+	.equ	gdt_length, gdt_end - gdt
233
 
87
 
234
 /****************************************************************************
88
 /****************************************************************************
235
- * real_to_prot (real-mode far call)
236
- *
237
- * Switch from 16-bit real-mode to 32-bit protected mode with flat
238
- * physical addresses.  %esp is restored from the saved pm_esp.  All
239
- * segment registers are set to flat physical-mode values.  All other
240
- * registers are preserved.  Interrupts are disabled.
89
+ * init_gdt (real-mode near call, 16-bit real-mode return address)
241
  *
90
  *
242
- * Note that this routine can be called *without* having first set up
243
- * a stored pm_esp or stored GDT.  If you do this, real_to_prot will
244
- * return with a temporary stack that is only *FOUR BYTES* in size.
245
- * This is just enough to enable you to do a "call 1f; popl %ebp"
246
- * sequence in order to find out your physical address and then load a
247
- * proper 32-bit protected-mode stack pointer.  Do *NOT* use more than
248
- * four bytes since this will overwrite code in librm!
91
+ * Initialise the GDT ready for transitions to protected mode.
249
  *
92
  *
250
- * Parameters: none
93
+ * Parameters: 
94
+ *   %edi : Physical base of protected-mode code
251
  ****************************************************************************
95
  ****************************************************************************
252
  */
96
  */
97
+	.section ".text16"
98
+	.code16
99
+	.globl init_gdt
100
+init_gdt:
101
+	/* Preserve registers */
102
+	pushl	%eax
103
+	pushw	%bx
253
 
104
 
254
-	.code16		
255
-EXPORT(real_to_prot):
256
-	/* Disable interrupts */
257
-	cli
105
+	/* Record virt_offset */
106
+	movl	%edi, %cs:virt_offset_rm_copy
258
 
107
 
259
-	/* Set %ds = %cs, for easier access to variables */
260
-	pushw	%cs
261
-	popw	%ds
262
-	
263
-	/* Preserve registers */
264
-	movl	%eax, %ds:OFFSET(save_eax)
265
-	movl	%ebx, %ds:OFFSET(save_ebx)
108
+	/* Set virtual_cs and virtual_ds base */
109
+	movl	%edi, %eax
110
+	movw	$virtual_cs, %bx
111
+	call	set_seg_base
266
 
112
 
267
-	/* Extract real-mode far return address from stack */
268
-	popl	%ds:OFFSET(save_retaddr)
113
+	/* Set real_cs and real_ds base, and GDT base */
114
+	movw	$real_cs, %bx
115
+	xorl	%eax, %eax
116
+	movw	%cs, %ax
117
+	shll	$4, %eax
118
+	call	set_seg_base
119
+	addl	$gdt, %eax
120
+	movl	%eax, %cs:gdt_base
269
 
121
 
270
-	/* Record real-mode stack pointer */
271
-	movw	%sp, %ds:OFFSET(rm_sp)
272
-	pushw	%ss
273
-	popw	%ds:OFFSET(rm_ss)
274
-
275
-	/* Physical base address of librm to %ebx */
276
-	xorl	%ebx, %ebx
277
-	movw	%cs, %bx
278
-	shll	$4, %ebx
279
-
280
-	/* Record physical base address of librm */
281
-	movl	%ebx, %ds:OFFSET(librm_base)
282
-		
283
-	/* Check base address of stored protected-mode GDT.  If it's
284
-	 * zero, set it up to use our internal GDT (with physical
285
-	 * segments only).
286
-	 */
287
-	movl	%ds:OFFSET(pm_gdt_addr), %eax
288
-	testl	%eax, %eax
289
-	jnz	1f
290
-	/* Use internal GDT */
291
-	movl	%ebx, %eax
292
-	addl	$OFFSET(pm_gdt), %eax
293
-	movl	%eax, %ds:OFFSET(pm_gdt_addr)
294
-1:	
295
-	
296
-	/* Set up protected-mode continuation address on real-mode stack */
297
-	pushl	$PHYSICAL_CS
298
-	movl	%ebx, %eax
299
-	addl	$OFFSET(1f), %eax
122
+	/* Restore registers */
123
+	popw	%bx
124
+	popl	%eax
125
+	ret
126
+
127
+	.section ".text16"
128
+	.code16
129
+set_seg_base:
300
 	pushl	%eax
130
 	pushl	%eax
131
+	movw	%ax, %cs:(0+2)(%bx)
132
+	movw	%ax, %cs:(8+2)(%bx)
133
+	shrl	$16, %eax
134
+	movb	%al, %cs:(0+4)(%bx)
135
+	movb	%al, %cs:(8+4)(%bx)
136
+	movb	%ah, %cs:(0+7)(%bx)
137
+	movb	%ah, %cs:(8+7)(%bx)
138
+	popl	%eax
139
+	ret
301
 	
140
 	
302
-	/* Restore protected-mode GDT */
303
-	data32 lgdt	%ds:OFFSET(pm_gdt)
141
+/****************************************************************************
142
+ * real_to_prot (real-mode near call, 32-bit virtual return address)
143
+ *
144
+ * Switch from 16-bit real-mode to 32-bit protected mode with virtual
145
+ * addresses.  The real-mode %ss:sp is stored in rm_ss and rm_sp, and
146
+ * the protected-mode %esp is restored from the saved pm_esp.
147
+ * Interrupts are disabled.  All other registers may be destroyed.
148
+ *
149
+ * The return address for this function should be a 32-bit virtual
150
+ * address.
151
+ *
152
+ * Parameters: 
153
+ *   %ecx : number of bytes to move from RM stack to PM stack
154
+ *
155
+ ****************************************************************************
156
+ */
157
+	.section ".text16"
158
+	.code16
159
+real_to_prot:
160
+	/* Protected-mode return address => %ebx */
161
+	popl	%ebx
162
+
163
+	/* Real-mode %cs => %dx, %ss => %bp */
164
+	movw	%cs, %dx
165
+	movw	%ss, %bp
166
+
167
+	/* virt_offset => %edi */
168
+	movl	%cs:virt_offset_rm_copy, %edi
304
 
169
 
305
 	/* Switch to protected mode */
170
 	/* Switch to protected mode */
171
+	cli
172
+	data32 lgdt	%cs:gdt
306
 	movl	%cr0, %eax
173
 	movl	%cr0, %eax
307
 	orb	$CR0_PE, %al
174
 	orb	$CR0_PE, %al
308
 	movl	%eax, %cr0
175
 	movl	%eax, %cr0
309
-
310
-	/* Flush prefetch queue and reload %cs:eip */
311
-	data32 lret
312
-1:	.code32
313
-
314
-	/* Set up protected-mode stack and data segments */
315
-	movw	$PHYSICAL_DS, %ax
176
+	data32 ljmp	$VIRTUAL_CS, $1f
177
+	.section ".text"
178
+	.code32
179
+1:
180
+	/* Set up protected-mode data segments */
181
+	movw	$VIRTUAL_DS, %ax
316
 	movw	%ax, %ds
182
 	movw	%ax, %ds
317
 	movw	%ax, %es
183
 	movw	%ax, %es
318
 	movw	%ax, %fs
184
 	movw	%ax, %fs
319
 	movw	%ax, %gs
185
 	movw	%ax, %gs
186
+
187
+	/* Record virt_offset */
188
+	movl	%edi, virt_offset
189
+
190
+	/* Move data from RM stack to PM stack and set up PM stack */
191
+	movzwl	%sp, %esi
192
+	movl	pm_esp, %esp
193
+	subl	%ecx, %esp
194
+	movl	%esp, %edi
195
+	rep ss movsb
320
 	movw	%ax, %ss
196
 	movw	%ax, %ss
321
 
197
 
322
-	/* Switch to saved protected-mode stack.  Note that there may
323
-	 * not actually *be* a saved protected-mode stack.
324
-	 */
325
-	movl	OFFSET(pm_esp)(%ebx), %esp
326
-	testl	%esp, %esp
327
-	jnz	1f
328
-	/* No stack - use save_retaddr as a 4-byte temporary stack */
329
-	leal	OFFSET(save_retaddr+4)(%ebx), %esp
330
-1:	
331
-	
332
-	/* Convert real-mode far return address to physical address
333
-	 * and place on stack
334
-	 */
335
-	pushl	OFFSET(save_retaddr)(%ebx)
336
-	xorl	%eax, %eax
337
-	xchgw	2(%esp), %ax
338
-	shll	$4, %eax
339
-	addl	%eax, 0(%esp)
198
+	/* Record real-mode %cs and %ss:sp */
199
+	movw	%dx, rm_cs
200
+	movw	%bp, rm_ss
201
+	movw	%si, rm_sp
340
 
202
 
341
-	/* Restore registers and return */
342
-	movl	OFFSET(save_eax)(%ebx), %eax
343
-	movl	OFFSET(save_ebx)(%ebx), %ebx
344
-	ret
203
+	/* Return to virtual address */
204
+	jmp	*%ebx
345
 
205
 
346
 /****************************************************************************
206
 /****************************************************************************
347
- * prot_to_real (protected-mode near call, physical addresses)
207
+ * prot_to_real (protected-mode near call, 32-bit real-mode return address)
348
  *
208
  *
349
- * Switch from 32-bit protected mode with flat physical addresses to
350
- * 16-bit real mode.  %ss:sp is restored from the saved rm_ss and
351
- * rm_sp.  %cs is set such that %cs:0000 is the start of librm.  All
352
- * other segment registers are set to %ss.  All other registers are
353
- * preserved.  Interrupts are *not* enabled, since we want to be able
354
- * to use this routine inside an ISR.
209
+ * Switch from 32-bit protected mode with virtual addresses to 16-bit
210
+ * real mode.  The protected-mode %esp is stored in pm_esp and the
211
+ * real-mode %ss:sp is restored from the saved rm_ss and rm_sp.  All
212
+ * real-mode data segment registers are set equal to %ss.  Interrupts
213
+ * are *not* enabled, since we want to be able to use prot_to_real in
214
+ * an ISR.  All other registers may be destroyed.
355
  *
215
  *
356
- * Note that since %cs:0000 points to the start of librm on exit, it
357
- * follows that the code calling prot_to_real must be located within
358
- * 64kB of the start of librm.
216
+ * The return address for this function should be a 32-bit (sic)
217
+ * real-mode offset within .code16.
218
+ *
219
+ * Parameters: 
220
+ *   %ecx : number of bytes to move from PM stack to RM stack
359
  *
221
  *
360
- * Parameters: none
361
  ****************************************************************************
222
  ****************************************************************************
362
  */
223
  */
363
-
224
+	.section ".text"
364
 	.code32
225
 	.code32
365
-EXPORT(prot_to_real):
366
-	/* Calculate physical base address of librm in %ebx, preserve
367
-	 * original %eax and %ebx in save_eax and save_ebx
368
-	 */
369
-	pushl	%ebx
370
-	call	1f
371
-1:	popl	%ebx
372
-	subl	$OFFSET(1b), %ebx
373
-	popl	OFFSET(save_ebx)(%ebx)
374
-	movl	%eax, OFFSET(save_eax)(%ebx)
375
-
376
-	/* Record physical base address of librm */
377
-	movl	%ebx, OFFSET(librm_base)(%ebx)
378
-
379
-	/* Extract return address from the stack, convert to offset
380
-	 * within librm and save in save_retaddr
381
-	 */
382
-	popl	%eax
383
-	subl	%ebx, %eax
384
-	movl	%eax, OFFSET(save_retaddr)(%ebx)
385
-
386
-	/* Record protected-mode stack pointer */
387
-	movl	%esp, OFFSET(pm_esp)(%ebx)
388
-
389
-	/* Record protected-mode GDT */
390
-	sgdt	OFFSET(pm_gdt)(%ebx)
391
-
392
-	/* Set up real-mode GDT */
393
-	leal	OFFSET(rm_gdt)(%ebx), %eax
394
-	movl	%eax, OFFSET(rm_gdt_base)(%ebx)
395
-	movl	%ebx, %eax
396
-	rorl	$16, %eax
397
-	movw	%bx, OFFSET(rm_gdt_rm_cs+2)(%ebx)
398
-	movb	%al, OFFSET(rm_gdt_rm_cs+4)(%ebx)
399
-	movw	%bx, OFFSET(rm_gdt_rm_ds+2)(%ebx)
400
-	movb	%al, OFFSET(rm_gdt_rm_ds+4)(%ebx)
226
+prot_to_real:
227
+	/* Real-mode return address => %ebx */
228
+	popl	%ebx
401
 	
229
 	
402
-	/* Switch to real-mode GDT and reload segment registers to get
403
-	 * 64kB limits.  Stack is invalidated by this process.
404
-	 */
405
-	lgdt	OFFSET(rm_gdt)(%ebx)
406
-	ljmp	$RM_CS, $1f
407
-1:	.code16
408
-	movw	$RM_DS, %ax
230
+	/* Real-mode %ss:sp => %ebp:edx */
231
+	movzwl	rm_ss, %ebp
232
+	movzwl	rm_sp, %edx
233
+	subl	%ecx, %edx
234
+	
235
+	/* Copy data from PM stack to RM stack */
236
+	movl	%ebp, %eax
237
+	shll	$4, %eax
238
+	leal	(%eax,%edx), %edi
239
+	subl	virt_offset, %edi
240
+	movl	%esp, %esi
241
+	rep movsb
242
+	
243
+	/* Record protected-mode %esp */
244
+	movl	%esi, pm_esp
245
+
246
+	/* Real-mode %cs => %di */
247
+	movw	rm_cs, %di
248
+
249
+	/* Load real-mode segment limits */
250
+	movw	$REAL_DS, %ax
409
 	movw	%ax, %ds
251
 	movw	%ax, %ds
410
 	movw	%ax, %es
252
 	movw	%ax, %es
411
 	movw	%ax, %fs
253
 	movw	%ax, %fs
412
 	movw	%ax, %gs
254
 	movw	%ax, %gs
413
 	movw	%ax, %ss
255
 	movw	%ax, %ss
414
-
415
-	/* Calculate real-mode code segment in %ax and store in ljmp
416
-	 * instruction
417
-	 */
418
-	movl	%ebx, %eax
419
-	shrl	$4, %eax
420
-	movw	%ax, OFFSET(p2r_ljmp) + 3
421
-
256
+	ljmp	$REAL_CS, $1f
257
+	.section ".text16"
258
+	.code16
259
+1:
260
+	/* Set up real-mode ljmp instruction */
261
+	movw	%di, %ds:(p2r_ljmp + 3)
262
+	
422
 	/* Switch to real mode */
263
 	/* Switch to real mode */
423
-	movl	%cr0, %ebx
424
-	andb	$0!CR0_PE, %bl
425
-	movl	%ebx, %cr0
426
-
427
-	/* Intersegment jump to flush prefetch queue and reload
428
-	 * %cs:eip.  The segment gets filled in by the above code.  We
429
-	 * can't just use lret to achieve this, because we have no
430
-	 * stack at the moment.
431
-	 */
432
-p2r_ljmp:
433
-	ljmp	$0, $OFFSET(1f)
434
-1:	
435
-
436
-	/* Set %ds to point to code segment for easier data access */
437
-	movw	%ax, %ds
438
-			
439
-	/* Restore registers */
440
-	movl	OFFSET(save_eax), %eax
441
-	movl	OFFSET(save_ebx), %ebx
442
-
443
-	/* Set up real-mode data segments and stack */
444
-	movw	OFFSET(rm_ss), %ss
445
-	movw	OFFSET(rm_sp), %sp
446
-	pushw	%ss
447
-	pushw	%ss
448
-	pushw	%ss
449
-	pushw	%ss
450
-	popw	%ds
451
-	popw	%es
452
-	popw	%fs
453
-	popw	%gs
454
-
455
-	/* Set up return address on stack and return */
456
-	pushw	%cs:OFFSET(save_retaddr)
457
-	ret
264
+	movl	%cr0, %eax
265
+	andb	$0!CR0_PE, %al
266
+	movl	%eax, %cr0
458
 
267
 
268
+p2r_ljmp:
269
+	ljmp	$0, $1f /* Segment is filled in by above code */
270
+1:
271
+	/* Set up real-mode stack and data segments, and stack pointer */
272
+	movw	%bp, %ds
273
+	movw	%bp, %es
274
+	movw	%bp, %fs
275
+	movw	%bp, %gs
276
+	movw	%bp, %ss
277
+	movw	%dx, %sp
278
+
279
+	/* Return to real-mode address */
280
+	jmp	*%bx
281
+	
459
 /****************************************************************************
282
 /****************************************************************************
460
- * prot_call (real-mode far call)
283
+ * prot_call (real-mode near call, 32-bit real-mode return address)
461
  *
284
  *
462
  * Call a specific C function in the protected-mode code.  The
285
  * Call a specific C function in the protected-mode code.  The
463
  * prototype of the C function must be
286
  * prototype of the C function must be
469
  * function explicitly overwrites values in ix86.  Interrupt status
292
  * function explicitly overwrites values in ix86.  Interrupt status
470
  * will also be preserved.  Gate A20 will be enabled.
293
  * will also be preserved.  Gate A20 will be enabled.
471
  *
294
  *
472
- * The protected-mode code may install librm to a new location.  If it
473
- * does so, it must update librm_base in *this* copy of librm to point
474
- * to the new physical location.  prot_call will then return via the
475
- * newly installed copy.
476
- *
477
- * Note that when Etherboot performs its initial relocation, "*this*"
478
- * copy in the above paragraph will refer to the "master" copy, since
479
- * that is the initial installed copy.  Etherboot will return to
480
- * prot_call using a virtual address, so will return to the master
481
- * copy in high memory (rather than the original copy in base memory).
482
- * The master copy in high memory will have the physical address of
483
- * the newly installed copy in librm_base, since install_librm()
484
- * writes it there.  Thus, Etherboot's initialise() function will
485
- * return to the master copy of prot_call(), which will then jump to
486
- * the installed copy.
487
- *
488
- * It works, trust me.
489
- *
490
  * Parameters:
295
  * Parameters:
491
  *   function : virtual address of protected-mode function to call
296
  *   function : virtual address of protected-mode function to call
492
  *
297
  *
493
  * Example usage:
298
  * Example usage:
494
  *	pushl	$pxe_api_call
299
  *	pushl	$pxe_api_call
495
- *	lcall	$LIBRM_SEGMENT, $prot_call
300
+ *	call	prot_call
496
  *	addw	$4, %sp
301
  *	addw	$4, %sp
497
  * to call in to the C function
302
  * to call in to the C function
498
  *      void pxe_api_call ( struct i386_all_regs *ix86 );
303
  *      void pxe_api_call ( struct i386_all_regs *ix86 );
502
 #define PC_OFFSET_IX86 ( 0 )
307
 #define PC_OFFSET_IX86 ( 0 )
503
 #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
308
 #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
504
 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
309
 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
505
-	
310
+#define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
311
+
312
+	.section ".text16"
506
 	.code16
313
 	.code16
507
-EXPORT(prot_call):
508
-	/* Preserve registers and flags on RM stack */
314
+	.globl prot_call
315
+prot_call:
316
+	/* Preserve registers and flags on external RM stack */
509
 	pushfl
317
 	pushfl
510
 	pushal
318
 	pushal
511
 	pushw	%gs
319
 	pushw	%gs
513
 	pushw	%es
321
 	pushw	%es
514
 	pushw	%ds
322
 	pushw	%ds
515
 	pushw	%ss
323
 	pushw	%ss
516
-	pushw	%cs	
517
-	
518
-	/* Record RM stack pointer */
519
-	xorl	%ebp, %ebp
520
-	movw	%sp, %bp
521
-	
522
-	/* Physical address of RM stack pointer to %esi */
523
-	xorl	%esi, %esi
524
-	pushw	%ss
525
-	popw	%si
526
-	shll	$4, %esi
527
-	addl	%ebp, %esi
528
-
529
-	/* Address of pmode function to %ebx */
530
-	movl	%ss:(PC_OFFSET_FUNCTION)(%bp), %ebx
531
-	
532
-	/* Switch to protected mode */
533
 	pushw	%cs
324
 	pushw	%cs
534
-	call	real_to_prot
535
-	.code32
536
 
325
 
537
-	/* Copy ix86 from RM stack to PM stack */
538
-	movl	$SIZEOF_I386_ALL_REGS, %ecx
539
-	subl	%ecx, %esp
540
-	movl	%esp, %edi
541
-	pushl	%esi
326
+	/* For sanity's sake, clear the direction flag as soon as possible */
542
 	cld
327
 	cld
543
-	rep movsb
544
-	popl	%edi		/* %edi = phys addr of RM copy of ix86 */
545
-	
546
-	/* Switch to virtual addresses. */
547
-	call	1f
548
-	jmp	2f
549
-1:	ljmp	$VIRTUAL_CS, $_phys_to_virt
550
-2:	
551
 
328
 
552
-	/* Enable A20 line */
553
-	pushal
554
-	lcall	$VIRTUAL_CS, $gateA20_set
555
-	popl	%eax	/* discard */
556
-	popal
329
+	/* Switch to protected mode and move register dump to PM stack */
330
+	movl	$PC_OFFSET_END, %ecx
331
+	pushl	$1f
332
+	jmp	real_to_prot
333
+	.section ".text"
334
+	.code32
335
+1:
336
+	/* Set up environment expected by C code */
337
+	call	gateA20_set
557
 
338
 
558
-	/* Push &ix86 on the stack, and call function */
339
+	/* Call function */
559
 	pushl	%esp
340
 	pushl	%esp
560
-	call	*%ebx
341
+	call	*(PC_OFFSET_FUNCTION+4)(%esp)
561
 	popl	%eax /* discard */
342
 	popl	%eax /* discard */
562
 
343
 
563
-	/* Switch to physical addresses, discard PM register store */
564
-	lcall	$VIRTUAL_CS, $_virt_to_phys
565
-	popl	%eax /* discard */
566
-
567
-	/* Copy ix86 from PM stack to RM stack, and remove ix86
568
-	 * from PM stack.  (%edi still contains physical address of
569
-	 * ix86 on RM stack from earlier, since C code preserves
570
-	 * %edi).
571
-	 */
572
-	movl	%esp, %esi
573
-	movl	$SIZEOF_I386_ALL_REGS, %ecx
574
-	cld
575
-	rep movsb
576
-	movl	%esi, %esp	/* remove ix86 from PM stack */
577
-
578
-	/* Obtain physical base address of installed copy of librm in
579
-	 * %ebx.  (It's possible that this *isn't* the physical base
580
-	 * address of the copy we're currently executing in, because
581
-	 * the protected-mode call could have moved librm.  If it does
582
-	 * so, it must update librm_base in our copy to reflect the
583
-	 * new location.
584
-	 */
585
-	call	1f
586
-1:	popl	%ebp
587
-	movl	(librm_base-1b)(%ebp), %ebx
588
-	
589
-	/* Jump to running in installed copy of librm */
590
-	addl	$OFFSET(1f), %ebx
591
-	jmp	*%ebx
592
-1:	
593
-	
594
-	/* Switch to real mode */
595
-	call	prot_to_real
344
+	/* Switch to real mode and move register dump back to RM stack */
345
+	movl	$PC_OFFSET_END, %ecx
346
+	pushl	$1f
347
+	jmp	prot_to_real
348
+	.section ".text16"
596
 	.code16
349
 	.code16
597
-
598
-	/* Restore registers and flags, and return */
599
-	popw	%ax	/* skip %cs */
600
-	popw	%ax	/* skip %ss */
350
+1:	
351
+	/* Restore registers and flags and return */
352
+	popw	%ax	/* skip %cs - it is already set */
353
+	popw	%ax	/* skip %ss - it is already set */
601
 	popw	%ds
354
 	popw	%ds
602
 	popw	%es
355
 	popw	%es
603
 	popw	%fs
356
 	popw	%fs
604
 	popw	%gs
357
 	popw	%gs
605
 	popal
358
 	popal
606
 	popfl
359
 	popfl
607
-	lret
360
+	ret
608
 
361
 
609
 /****************************************************************************
362
 /****************************************************************************
610
- * real_call (protected-mode near call, virtual addresses)
363
+ * real_call (protected-mode near call, 32-bit virtual return address)
611
  *
364
  *
612
  * Call a real-mode function from protected-mode code.
365
  * Call a real-mode function from protected-mode code.
613
  *
366
  *
625
  * and examples.
378
  * and examples.
626
  *
379
  *
627
  * Parameters:
380
  * Parameters:
628
- *   far pointer to real-mode function to call
381
+ *   (32-bit) near pointer to real-mode function to call
629
  *
382
  *
630
  * Returns: none
383
  * Returns: none
631
  ****************************************************************************
384
  ****************************************************************************
632
  */
385
  */
633
 
386
 
634
 #define RC_OFFSET_PRESERVE_REGS ( 0 )
387
 #define RC_OFFSET_PRESERVE_REGS ( 0 )
635
-#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + 8 )
636
-#define RC_OFFSET_RM_FUNCTION ( RC_OFFSET_RETADDR + 4 )
637
-	
638
-	.code32
639
-EXPORT(real_call):
640
-	/* Preserve registers */
641
-	pushl	%ebp
642
-	pushl	%eax
643
-	
644
-	/* Switch to physical addresses */
645
-	lcall	$VIRTUAL_CS, $_virt_to_phys
646
-	addl	$4, %esp
647
-
648
-	/* Extract real-mode function address and store in ljmp instruction */
649
-	call	1f
650
-1:	popl	%ebp
651
-	movl	RC_OFFSET_RM_FUNCTION(%esp), %eax
652
-	movl	%eax, (rc_ljmp + 1 - 1b)(%ebp)
388
+#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + SIZEOF_I386_REGS )
389
+#define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 )
390
+#define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 )
653
 
391
 
654
-	/* Restore registers */
655
-	popl	%eax
656
-	popl	%ebp
392
+	.section ".text"
393
+	.code32
394
+	.globl real_call
395
+real_call:
396
+	/* Create register dump on PM stack */
397
+	pushal
657
 
398
 
658
-	/* Switch to real mode, preserving non-segment registers */
659
-	call	prot_to_real
399
+	/* Switch to real mode and move register dump to RM stack */
400
+	movl	$RC_OFFSET_END, %ecx
401
+	pushl	$1f
402
+	jmp	prot_to_real
403
+	.section ".text16"
660
 	.code16
404
 	.code16
405
+1:
406
+	/* Construct call to real-mode function */
407
+	movw	%sp, %bp
408
+	movw	RC_OFFSET_FUNCTION(%bp), %ax
409
+	movw	%ax, %cs:rc_function
661
 
410
 
662
-	/* Far call to real-mode routine */
663
-	pushw	%cs
664
-	call	rc_ljmp
665
-	jmp	2f
666
-rc_ljmp:	
667
-	ljmp	$0, $0	/* address filled in by above code */
668
-2:	
669
-	
670
-	/* Switch to protected mode */
671
-	pushw	%cs
672
-	call	real_to_prot
673
-	.code32
411
+	/* Call real-mode function */
412
+	popal
413
+	call	*%cs:rc_function
414
+	pushal
674
 
415
 
675
-	/* Switch to virtual addresses */
676
-	call	1f
677
-	jmp	2f
678
-1:	ljmp	$VIRTUAL_CS, $_phys_to_virt
679
-2:	
416
+	/* Switch to protected mode and move register dump back to PM stack */
417
+	movl	$RC_OFFSET_END, %ecx
418
+	pushl	$1f
419
+	jmp	real_to_prot
420
+	.section ".text"
421
+	.code32
422
+1:
423
+	/* Set up environment expected by C code */
424
+	call	gateA20_set
680
 
425
 
681
-	/* Enable A20 line */
682
-	pushal
683
-	lcall	$VIRTUAL_CS, $gateA20_set
684
-	popl	%eax	/* discard */
426
+	/* Restore registers and return */
685
 	popal
427
 	popal
686
-
687
-	/* Return */
688
 	ret
428
 	ret
689
-	
690
-/****************************************************************************
691
- * Relocation lock counter
692
- *
693
- * librm may be moved in base memory only when this counter is zero.
694
- * The counter gets incremented whenever a reference to librm is
695
- * generated (e.g. a real_call is made, resulting in a return address
696
- * pointing to librm being placed on the stack), and decremented when
697
- * the reference goes out of scope (e.g. the real_call returns).
698
- ****************************************************************************
699
- */
700
-EXPORT(librm_ref_count):	.byte 0
701
 
429
 
430
+	.section ".text16"
431
+rc_function:	.word 0
432
+	
702
 /****************************************************************************
433
 /****************************************************************************
703
  * Stored real-mode and protected-mode stack pointers
434
  * Stored real-mode and protected-mode stack pointers
704
  *
435
  *
734
  ****************************************************************************
465
  ****************************************************************************
735
  */
466
  */
736
 
467
 
737
-EXPORT(rm_stack):	/* comprises rm_ss and rm_sp */
738
-rm_sp:		.word 0
739
-rm_ss:		.word 0
740
-
741
-EXPORT(pm_stack):
742
-pm_esp:		.long 0
743
-
744
-/****************************************************************************
745
- * Temporary variables
746
- ****************************************************************************
747
- */
748
-save_eax:	.long 0
749
-save_ebx:	.long 0
750
-save_retaddr:	.long 0
751
-	
752
-/****************************************************************************
753
- * End of librm
754
- ****************************************************************************
755
- */
756
-_librm_end:
757
-	.globl _librm_size
758
-	.equ _librm_size, _librm_end - _librm_start
468
+	.section ".data"
469
+	.globl rm_sp
470
+rm_sp:	.word 0
471
+	.globl rm_ss
472
+rm_ss:	.word 0
473
+	.globl rm_cs
474
+rm_cs:	.word 0
475
+	.globl pm_esp
476
+pm_esp:	.long _estack
477
+
478
+	.section ".text16"
479
+virt_offset_rm_copy:	.long 0
480
+	.section ".data"
481
+	.globl virt_offset
482
+virt_offset:		.long 0	

+ 8
- 135
src/arch/i386/transitions/librm_mgmt.c View File

9
 /* Build a null object under -DKEEP_IT_REAL */
9
 /* Build a null object under -DKEEP_IT_REAL */
10
 #else
10
 #else
11
 
11
 
12
-#include "stdint.h"
13
-#include "stddef.h"
14
-#include "string.h"
15
-#include "basemem.h"
16
-#include "relocate.h"
17
-#include <gpxe/init.h>
18
-#include "librm.h"
12
+#include <stdint.h>
13
+#include <librm.h>
19
 
14
 
20
 /*
15
 /*
21
  * This file provides functions for managing librm.
16
  * This file provides functions for managing librm.
22
  *
17
  *
23
  */
18
  */
24
 
19
 
25
-/* Current location of librm in base memory */
26
-char *installed_librm = librm;
27
-
28
-/* Whether or not we have base memory currently allocated for librm.
29
- * Note that we *can* have a working librm present in unallocated base
30
- * memory; this is the situation at startup for all real-mode
31
- * prefixes.
32
- */
33
-static int allocated_librm = 0;
34
-
35
 /*
20
 /*
36
  * Allocate space on the real-mode stack and copy data there.
21
  * Allocate space on the real-mode stack and copy data there.
37
  *
22
  *
38
  */
23
  */
39
 uint16_t copy_to_rm_stack ( void *data, size_t size ) {
24
 uint16_t copy_to_rm_stack ( void *data, size_t size ) {
40
 #ifdef DEBUG_LIBRM
25
 #ifdef DEBUG_LIBRM
41
-	if ( inst_rm_stack.offset <= size ) {
26
+	if ( rm_sp <= size ) {
42
 		printf ( "librm: out of space in RM stack\n" );
27
 		printf ( "librm: out of space in RM stack\n" );
43
 		lockup();
28
 		lockup();
44
 	}
29
 	}
45
 #endif
30
 #endif
46
-	inst_rm_stack.offset -= size;
47
-	copy_to_real ( inst_rm_stack.segment, inst_rm_stack.offset,
48
-		       data, size );
49
-	return inst_rm_stack.offset;
31
+	rm_sp -= size;
32
+	copy_to_real ( rm_ss, rm_sp, data, size );
33
+	return rm_sp;
50
 };
34
 };
51
 
35
 
52
 /*
36
 /*
56
  */
40
  */
57
 void remove_from_rm_stack ( void *data, size_t size ) {
41
 void remove_from_rm_stack ( void *data, size_t size ) {
58
 	if ( data ) {
42
 	if ( data ) {
59
-		copy_from_real ( data,
60
-				 inst_rm_stack.segment, inst_rm_stack.offset,
61
-				 size );
43
+		copy_from_real ( data, rm_ss, rm_sp, size );
62
 	}
44
 	}
63
-	inst_rm_stack.offset += size;
45
+	rm_sp += size;
64
 };
46
 };
65
 
47
 
66
-/*
67
- * Install librm to base memory
68
- *
69
- */
70
-static void install_librm ( char *addr ) {
71
-	librm_base = virt_to_phys ( addr );
72
-	memcpy ( addr, librm, librm_size );
73
-	installed_librm = addr;
74
-}
75
-
76
-/*
77
- * Uninstall librm from base memory.  This copies librm back to the
78
- * "master" copy, so that it can be reinstalled to a new location,
79
- * preserving the values for rm_ss and rm_sp from the old installed
80
- * copy.
81
- *
82
- * We deliberately leave the old copy intact and effectively installed
83
- * (apart from being in unallocated memory) so that we can use it for
84
- * any real-mode calls required when allocating memory for the new
85
- * copy, or for the real-mode exit path.
86
- */
87
-static void uninstall_librm ( void ) {
88
-
89
-	/* Copy installed librm back to master copy */
90
-	memcpy ( librm, installed_librm, librm_size );
91
-
92
-	/* Free but do not zero the base memory */
93
-	if ( allocated_librm ) {
94
-		free_base_memory ( installed_librm, librm_size );
95
-		allocated_librm = 0;
96
-	}
97
-}
98
-
99
-/*
100
- * If librm isn't installed (i.e. if we have librm, but weren't
101
- * entered via it), then install librm and a real-mode stack to a
102
- * fixed temporary location, just so that we can e.g. issue printf()
103
- *
104
- * [ If we were entered via librm, then the real_to_prot call will
105
- * have filled in librm_base. ]
106
- */
107
-static void librm_init ( void ) {
108
-	if ( ! librm_base ) {
109
-		install_librm ( phys_to_virt ( 0x7c00 ) );
110
-		inst_rm_stack.segment = 0x7c0;
111
-		inst_rm_stack.offset = 0x1000;
112
-	}
113
-}
114
-
115
-/*
116
- * librm_post_reloc gets called immediately after relocation.
117
- *
118
- */
119
-static void librm_post_reloc ( void ) {
120
-	/* Point installed_librm back at last known physical location.
121
-	 */
122
-	installed_librm = phys_to_virt ( librm_base );
123
-
124
-	/* Allocate base memory for librm and place a copy there */
125
-	if ( ! allocated_librm ) {
126
-		char *new_librm = alloc_base_memory ( librm_size );
127
-		uninstall_librm ();
128
-		install_librm ( new_librm );
129
-		allocated_librm = 1;
130
-	}
131
-}
132
-
133
-INIT_FN ( INIT_LIBRM, librm_init, NULL, uninstall_librm );
134
-POST_RELOC_FN ( POST_RELOC_LIBRM, librm_post_reloc );
135
-
136
-/*
137
- * Wrapper for initialise() when librm is being used.  We have to
138
- * install a copy of librm to allocated base memory and return the
139
- * pointer to this new librm's entry point via es:di.
140
- *
141
- */
142
-void initialise_via_librm ( struct i386_all_regs *ix86 ) {
143
-	/* Hand off to initialise() */
144
-	initialise ();
145
-
146
-	/* Point es:di to new librm's entry point.  Fortunately, di is
147
-	 * already set up by setup16, so all we need to do is point
148
-	 * es:0000 to the start of the new librm.
149
-	 */
150
-	ix86->segs.es = librm_base >> 4;
151
-}
152
-
153
-/*
154
- * Increment lock count of librm
155
- *
156
- */
157
-void lock_librm ( void ) {
158
-	inst_librm_ref_count++;
159
-}
160
-
161
-/*
162
- * Decrement lock count of librm
163
- *
164
- */
165
-void unlock_librm ( void ) {
166
-#ifdef DEBUG_LIBRM
167
-	if ( inst_librm_ref_count == 0 ) {
168
-		printf ( "librm: ref count gone negative\n" );
169
-		lockup();
170
-	}
171
-#endif
172
-	inst_librm_ref_count--;
173
-}
174
-
175
 #endif /* KEEP_IT_REAL */
48
 #endif /* KEEP_IT_REAL */

+ 0
- 5
src/include/osdep.h View File

14
 #include "setjmp.h"
14
 #include "setjmp.h"
15
 #include "latch.h"
15
 #include "latch.h"
16
 
16
 
17
-/* within 1MB of 4GB is too close. 
18
- * MAX_ADDR is the maximum address we can easily do DMA to.
19
- */
20
-#define MAX_ADDR (0xfff00000UL)
21
-
22
 typedef	unsigned long Address;
17
 typedef	unsigned long Address;
23
 
18
 
24
 /* ANSI prototyping macro */
19
 /* ANSI prototyping macro */

Loading…
Cancel
Save