Browse Source

Use full protected mode for access to high memory within prefix, to

work around limitations in real-mode virtualisation support on Intel
VT-capable chips.
tags/v0.9.3
Michael Brown 16 years ago
parent
commit
dec325fe43
1 changed files with 237 additions and 169 deletions
  1. 237
    169
      src/arch/i386/prefix/libprefix.S

+ 237
- 169
src/arch/i386/prefix/libprefix.S View File

@@ -47,17 +47,181 @@
47 47
 	.section ".data16", "aw", @progbits
48 48
 
49 49
 /****************************************************************************
50
- * install_block (real-mode near call)
50
+ * pm_call (real-mode near call)
51
+ *
52
+ * Call routine in 16-bit protected mode for access to extended memory
53
+ *
54
+ * Parameters:
55
+ *   %ax : address of routine to call in 16-bit protected mode
56
+ * Returns:
57
+ *   none
58
+ * Corrupts:
59
+ *   %ax
60
+ *
61
+ * The specified routine is called in 16-bit protected mode, with:
62
+ *
63
+ *   %cs : 16-bit code segment with base matching real-mode %cs
64
+ *   %ss : 16-bit data segment with base matching real-mode %ss
65
+ *   %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit
66
+ *
67
+ ****************************************************************************
68
+ */
69
+
70
+#ifndef KEEP_IT_REAL
71
+
72
+	/* GDT for protected-mode calls */
73
+	.section ".data16"
74
+	.align 16
75
+gdt:
76
+gdt_limit:		.word gdt_length - 1
77
+gdt_base:		.long 0
78
+			.word 0 /* padding */
79
+pm_cs:		/* 16-bit protected-mode code segment */
80
+	.equ    PM_CS, pm_cs - gdt
81
+	.word   0xffff, 0
82
+	.byte   0, 0x9b, 0x00, 0
83
+pm_ss:		/* 16-bit protected-mode stack segment */
84
+	.equ    PM_SS, pm_ss - gdt
85
+	.word   0xffff, 0
86
+	.byte   0, 0x93, 0x00, 0
87
+pm_ds:		/* 32-bit protected-mode flat data segment */
88
+	.equ    PM_DS, pm_ds - gdt
89
+	.word   0xffff, 0
90
+	.byte   0, 0x93, 0xcf, 0
91
+gdt_end:
92
+	.equ	gdt_length, . - gdt
93
+	.size	gdt, . - gdt
94
+
95
+	.section ".data16"
96
+	.align 16
97
+pm_saved_gdt:	
98
+	.long	0, 0
99
+	.size	pm_saved_gdt, . - pm_saved_gdt
100
+
101
+	.section ".prefix.lib"
102
+	.code16
103
+pm_call:
104
+	/* Preserve registers, flags, GDT, and RM return point */
105
+	pushfl
106
+	sgdt	pm_saved_gdt
107
+	pushw	%gs
108
+	pushw	%fs
109
+	pushw	%es
110
+	pushw	%ds
111
+	pushw	%ss
112
+	pushw	%cs
113
+	pushw	$99f
114
+
115
+	/* Set up GDT bases */
116
+	pushl	%eax
117
+	pushw	%bx
118
+	xorl	%eax, %eax
119
+	movw	%ds, %ax
120
+	shll	$4, %eax
121
+	addl	$gdt, %eax
122
+	movl	%eax, gdt_base
123
+	movw	%cs, %ax
124
+	movw	$pm_cs, %bx
125
+	call	set_seg_base
126
+	movw	%ss, %ax
127
+	movw	$pm_ss, %bx
128
+	call	set_seg_base
129
+	popw	%bx
130
+	popl	%eax
131
+
132
+	/* Switch CPU to protected mode and load up segment registers */
133
+	pushl	%eax
134
+	cli
135
+	lgdt	gdt
136
+	movl	%cr0, %eax
137
+	orb	$CR0_PE, %al
138
+	movl	%eax, %cr0
139
+	ljmp	$PM_CS, $1f
140
+1:	movw	$PM_SS, %ax
141
+	movw	%ax, %ss
142
+	movw	$PM_DS, %ax
143
+	movw	%ax, %ds
144
+	movw	%ax, %es
145
+	movw	%ax, %fs
146
+	movw	%ax, %gs
147
+	popl	%eax
148
+
149
+	/* Call PM routine */
150
+	call	*%ax
151
+
152
+	/* Set real-mode segment limits on %ds, %es, %fs and %gs */
153
+	movw	%ss, %ax
154
+	movw	%ax, %ds
155
+	movw	%ax, %es
156
+	movw	%ax, %fs
157
+	movw	%ax, %gs
158
+
159
+	/* Return CPU to real mode */
160
+	movl	%cr0, %eax
161
+	andb	$0!CR0_PE, %al
162
+	movl	%eax, %cr0
163
+
164
+	/* Restore registers and flags */
165
+	lret
166
+99:	popw	%ss
167
+	popw	%ds
168
+	popw	%es
169
+	popw	%fs
170
+	popw	%gs
171
+	lgdt	pm_saved_gdt
172
+	popfl
173
+
174
+	ret
175
+	.size pm_call, . - pm_call
176
+
177
+set_seg_base:
178
+	rolw	$4, %ax
179
+	movw	%ax, 2(%bx)
180
+	andw	$0xfff0, 2(%bx)
181
+	movb	%al, 4(%bx)
182
+	andb	$0x0f, 4(%bx)
183
+	ret
184
+	.size set_seg_base, . - set_seg_base
185
+
186
+#endif /* KEEP_IT_REAL */
187
+
188
+/****************************************************************************
189
+ * copy_bytes (real-mode or 16-bit protected-mode near call)
190
+ *
191
+ * Copy bytes
192
+ *
193
+ * Parameters:
194
+ *   %ds:esi : source address
195
+ *   %es:edi : destination address
196
+ *   %ecx : length
197
+ * Returns:
198
+ *   %ds:esi : next source address
199
+ *   %ds:esi : next destination address
200
+ * Corrupts:
201
+ *   None
202
+ ****************************************************************************
203
+ */
204
+	.section ".prefix.lib"
205
+	.code16
206
+copy_bytes:
207
+	pushl %ecx
208
+	rep addr32 movsb
209
+	popl %ecx
210
+	ret
211
+	.size copy_bytes, . - copy_bytes
212
+
213
+/****************************************************************************
214
+ * install_block (real-mode or 16-bit protected-mode near call)
51 215
  *
52 216
  * Install block to specified address
53 217
  *
54 218
  * Parameters:
55
- *   %esi : start offset within loaded image (must be a multiple of 16)
219
+ *   %ds:esi : source address (must be a multiple of 16)
56 220
  *   %es:edi : destination address
57 221
  *   %ecx : length of (decompressed) data
58 222
  *   %edx : total length of block (including any uninitialised data portion)
59 223
  * Returns:
60
- *   %esi : end offset within image (rounded up to next multiple of 16)
224
+ *   %ds:esi : next source address (will be a multiple of 16)
61 225
  * Corrupts:
62 226
  *   %edi, %ecx, %edx
63 227
  ****************************************************************************
@@ -65,46 +229,26 @@
65 229
 	.section ".prefix.lib"
66 230
 	.code16
67 231
 install_block:
68
-	/* Preserve registers */
69
-	pushw	%ds
70
-	pushl	%eax
71
-	pushl	%ebx
72
-	movl	%esi, %ebx
73
-	
74
-	/* Starting segment => %ds */
75
-	movw	%cs, %ax
76
-	shrl	$4, %esi
77
-	addw	%si, %ax
78
-	movw	%ax, %ds
79
-	xorl	%esi, %esi
80
-
81
-	/* Calculate start and length of uninitialised data portion */
82
-	addr32 leal	(%edi,%ecx), %eax
83
-	subl	%ecx, %edx
84
-	
85
-	/* Do the copy */
86
-	cld
87 232
 #if COMPRESS
233
+	/* Decompress source to destination */
88 234
 	call	decompress16
89 235
 #else
90
-	rep addr32 movsb
236
+	/* Copy source to destination */
237
+	call	copy_bytes
91 238
 #endif
92 239
 
93
-	/* Zero remaining space */
94
-	movl	%eax, %edi
95
-	movl	%edx, %ecx
96
-	xorb	%al, %al
240
+	/* Zero .bss portion */
241
+	negl	%ecx
242
+	addl	%edx, %ecx
243
+	pushw	%ax
244
+	xorw	%ax, %ax
97 245
 	rep addr32 stosb
246
+	popw	%ax
98 247
 
99
-	/* Adjust %esi */
100
-	addl	%ebx, %esi
248
+	/* Round up %esi to start of next source block */
101 249
 	addl	$0xf, %esi
102 250
 	andl	$~0xf, %esi
103 251
 
104
-	/* Restore registers */
105
-	popl	%ebx
106
-	popl	%eax
107
-	popw	%ds
108 252
 	ret
109 253
 	.size install_block, . - install_block
110 254
 	
@@ -159,9 +303,9 @@ alloc_basemem:
159 303
  * Parameters: 
160 304
  *   %ax : .text16 segment address
161 305
  *   %bx : .data16 segment address
162
- *   %esi : start offset within loaded image (must be a multiple of 16)
306
+ *   %esi : source physical address (must be a multiple of 16)
163 307
  * Returns:
164
- *   %esi : end offset within image (rounded up to next multiple of 16)
308
+ *   %esi : next source physical address (will be a multiple of 16)
165 309
  * Corrupts:
166 310
  *   none
167 311
  ****************************************************************************
@@ -170,43 +314,57 @@ alloc_basemem:
170 314
 	.code16
171 315
 install_basemem:
172 316
 	/* Preserve registers */
317
+	pushw	%ds
173 318
 	pushw	%es
174 319
 	pushl	%edi
175 320
 	pushl	%ecx
176 321
 	pushl	%edx
177 322
 
178 323
 	/* Install .text16 */
324
+	pushl	%esi
325
+	shrl	$4, %esi
326
+	movw	%si, %ds
327
+	xorw	%si, %si
179 328
 	movw	%ax, %es
180 329
 	xorl	%edi, %edi
181 330
 	movl	$_text16_size, %ecx
182 331
 	movl	%ecx, %edx
183 332
 	call	install_block
333
+	popl	%ecx
334
+	addl	%ecx, %esi
184 335
 
185 336
 	/* Install .data16 */
337
+	pushl	%esi
338
+	shrl	$4, %esi
339
+	movw	%si, %ds
340
+	xorw	%si, %si
186 341
 	movw	%bx, %es
187
-	xorl	%edi, %edi	
342
+	xorl	%edi, %edi
188 343
 	movl	$_data16_progbits_size, %ecx
189 344
 	movl	$_data16_size, %edx
190 345
 	call	install_block
346
+	popl	%ecx
347
+	addl	%ecx, %esi
191 348
 
192 349
 	/* Restore registers */
193 350
 	popl	%edx
194 351
 	popl	%ecx
195 352
 	popl	%edi
196 353
 	popw	%es
354
+	popw	%ds
197 355
 	ret
198 356
 	.size install_basemem, . - install_basemem
199 357
 
200 358
 /****************************************************************************
201
- * install_highmem (flat real-mode near call)
359
+ * install_highmem (real-mode near call)
202 360
  *
203 361
  * Install .text and .data into high memory
204 362
  *
205 363
  * Parameters:
206
- *   %esi : start offset within loaded image (must be a multiple of 16)
207
- *   %es:edi : address in high memory
364
+ *   %esi : source physical address (must be a multiple of 16)
365
+ *   %edi : destination physical address
208 366
  * Returns:
209
- *   %esi : end offset within image (rounded up to next multiple of 16)
367
+ *   %esi : next source physical address (will be a multiple of 16)
210 368
  * Corrupts:
211 369
  *   none
212 370
  ****************************************************************************
@@ -218,115 +376,27 @@ install_basemem:
218 376
 	.code16
219 377
 install_highmem:
220 378
 	/* Preserve registers */
379
+	pushw	%ax
221 380
 	pushl	%edi
222 381
 	pushl	%ecx
223 382
 	pushl	%edx
224
-		
383
+
225 384
 	/* Install .text and .data to specified address */
226 385
 	movl	$_textdata_progbits_size, %ecx
227 386
 	movl	$_textdata_size, %edx
228
-	call	install_block
387
+	movw	$install_block, %ax
388
+	call	pm_call
229 389
 
230
-	/* Restore registers and interrupt status */
390
+	/* Restore registers */
231 391
 	popl	%edx
232 392
 	popl	%ecx
233 393
 	popl	%edi
394
+	popw	%ax
234 395
 	ret
235 396
 	.size install_highmem, . - install_highmem
236 397
 	
237 398
 #endif /* KEEP_IT_REAL */
238 399
 	
239
-/****************************************************************************
240
- * GDT for flat real mode
241
- *
242
- * We only ever use this GDT to set segment limits; the bases are
243
- * unused.  Also, we only change data segments, so we don't need to
244
- * worry about the code or stack segments.  This makes everything much
245
- * simpler.
246
- ****************************************************************************
247
- */
248
-	
249
-#ifndef KEEP_IT_REAL
250
-	
251
-	.section ".prefix.lib"
252
-	.align 16
253
-gdt:
254
-gdt_limit:		.word gdt_length - 1
255
-gdt_base:		.long 0
256
-			.word 0 /* padding */
257
-
258
-flat_ds:	/* Flat real mode data segment */
259
-	.equ	FLAT_DS, flat_ds - gdt
260
-	.word	0xffff, 0
261
-	.byte	0, 0x93, 0xcf, 0
262
-
263
-real_ds:	/* Normal real mode data segment */
264
-	.equ	REAL_DS, real_ds - gdt
265
-	.word	0xffff, 0
266
-	.byte	0, 0x93, 0x00, 0
267
-
268
-gdt_end:
269
-	.equ	gdt_length, gdt_end - gdt
270
-	.size gdt, . - gdt
271
-	
272
-#endif /* KEEP_IT_REAL */
273
-
274
-/****************************************************************************
275
- * set_real_mode_limits (real-mode near call)
276
- *
277
- * Sets limits on the data segments %ds and %es.
278
- *
279
- * Parameters:
280
- *   %dx : segment type (FLAT_DS for 4GB or REAL_DS for 64kB)
281
- ****************************************************************************
282
- */
283
-
284
-#ifndef KEEP_IT_REAL
285
-	
286
-	.section ".prefix.lib"
287
-	.code16
288
-set_real_mode_limits:
289
-	/* Preserve real-mode segment values and temporary registers */
290
-	pushw	%es
291
-	pushw	%ds
292
-	pushw	%bp
293
-	pushl	%eax
294
-
295
-	/* Set GDT base and load GDT */
296
-	xorl	%eax, %eax
297
-	movw	%cs, %ax
298
-	shll	$4, %eax
299
-	addl	$gdt, %eax
300
-	pushl	%eax
301
-	pushw	%cs:gdt_limit
302
-	movw	%sp, %bp
303
-	lgdt	(%bp)
304
-	addw	$6, %sp
305
-
306
-	/* Switch to protected mode */
307
-	movl	%cr0, %eax
308
-	orb	$CR0_PE, %al
309
-	movl	%eax, %cr0
310
-
311
-	/* Set flat segment limits */
312
-	movw	%dx, %ds
313
-	movw	%dx, %es
314
-
315
-	/* Switch back to real mode */
316
-	movl	%cr0, %eax
317
-	andb	$0!CR0_PE, %al
318
-	movl	%eax, %cr0
319
-
320
-	/* Restore real-mode segment values and temporary registers */
321
-	popl	%eax
322
-	popw	%bp
323
-	popw	%ds
324
-	popw	%es
325
-	ret
326
-	.size set_real_mode_limits, . - set_real_mode_limits
327
-	
328
-#endif /* KEEP_IT_REAL */
329
-	
330 400
 /****************************************************************************
331 401
  * install (real-mode near call)
332 402
  * install_prealloc (real-mode near call)
@@ -354,72 +424,70 @@ install:
354 424
 	.globl install_prealloc
355 425
 install_prealloc:
356 426
 	/* Save registers */
427
+	pushw	%ds
357 428
 	pushl	%esi
358
-	pushw	%dx
429
+
430
+	/* Sanity: clear the direction flag asap */
431
+	cld
432
+
433
+	/* Calculate physical address of payload (i.e. first source) */
434
+	xorl	%esi, %esi
435
+	movw	%cs, %si
436
+	shll	$4, %esi
437
+	addl	$_payload_offset, %esi
438
+
359 439
 	/* Install .text16 and .data16 */
360
-	movl	$_payload_offset, %esi
361 440
 	call	install_basemem
362 441
 
363
-#ifdef KEEP_IT_REAL
364
-	/* Preserve %ds, call init_libkir, restore registers */
365
-	pushw	%ds
442
+	/* Set up %ds for access to .data16 */
366 443
 	movw	%bx, %ds
444
+
445
+#ifdef KEEP_IT_REAL
446
+	/* Initialise libkir */
367 447
 	movw	%ax, (init_libkir_vector+2)
368 448
 	lcall	*init_libkir_vector
369
-	popw	%ds
370 449
 #else
371
-	/* Preserve registers and interrupt status, and disable interrupts */
372
-	pushfw
373
-	pushw	%ds
374
-	pushw	%es
450
+	/* Save registers */
451
+	pushl	%edi
375 452
 	pushl	%ecx
376
-	cli
377 453
 
378
-	/* Load up %ds and %es, and set up vectors for far calls to .text16 */
379
-	movw	%bx, %ds
380
-	xorw	%cx, %cx
381
-	movw	%cx, %es
382
-	movw	%ax, (init_librm_vector+2)
383
-	movw	%ax, (prot_call_vector+2)
384
-	
385 454
 	/* Install .text and .data to temporary area in high memory,
386 455
 	 * prior to reading the E820 memory map and relocating
387 456
 	 * properly.
388 457
 	 */
389
-	movw	$FLAT_DS, %dx
390
-	call	set_real_mode_limits
391 458
 	movl	$HIGHMEM_LOADPOINT, %edi
392 459
 	call	install_highmem
393 460
 
394
-	/* Set up initial protected-mode GDT, call relocate().
461
+	/* Initialise librm at current location */
462
+	movw	%ax, (init_librm_vector+2)
463
+	lcall	*init_librm_vector
464
+
465
+	/* Call relocate() to determine target address for relocation.
395 466
 	 * relocate() will return with %esi, %edi and %ecx set up
396 467
 	 * ready for the copy to the new location.
397 468
 	 */
398
-	lcall	*init_librm_vector
469
+	movw	%ax, (prot_call_vector+2)
399 470
 	pushl	$relocate
400 471
 	lcall	*prot_call_vector
401 472
 	addw	$4, %sp
402 473
 
403
-	/* Move code to new location, set up new protected-mode GDT */
404
-	movw	$FLAT_DS, %dx
405
-	call	set_real_mode_limits
474
+	/* Copy code to new location */
406 475
 	pushl	%edi
407
-	es rep addr32 movsb
476
+	pushw	%ax
477
+	movw	$copy_bytes, %ax
478
+	call	pm_call
479
+	popw	%ax
408 480
 	popl	%edi
409
-	lcall	*init_librm_vector
410 481
 
411
-	/* Restore real-mode segment limits */
412
-	movw	$REAL_DS, %dx
413
-	call	set_real_mode_limits
482
+	/* Initialise librm at new location */
483
+	lcall	*init_librm_vector
414 484
 
415
-	/* Restore registers and interrupt status */
485
+	/* Restore registers */
416 486
 	popl	%ecx
417
-	popw	%es
418
-	popw	%ds
419
-	popfw
487
+	popl	%edi
420 488
 #endif
421
-	popw	%dx
422 489
 	popl	%esi
490
+	popw	%ds
423 491
 	ret
424 492
 	.size install_prealloc, . - install_prealloc
425 493
 

Loading…
Cancel
Save