|
@@ -70,14 +70,96 @@ real_cs: /* 16 bit real mode code segment */
|
70
|
70
|
.word 0xffff, 0
|
71
|
71
|
.byte 0, 0x9b, 0x00, 0
|
72
|
72
|
|
73
|
|
- .org gdt + REAL_DS
|
|
73
|
+ .org gdt + REAL_DS, 0
|
74
|
74
|
real_ds: /* 16 bit real mode data segment */
|
75
|
|
- .word 0xffff, ( REAL_DS << 4 )
|
|
75
|
+ .word 0xffff, 0
|
|
76
|
+ .byte 0, 0x93, 0x00, 0
|
|
77
|
+
|
|
78
|
+ .org gdt + P2R_DS, 0
|
|
79
|
+p2r_ds: /* 16 bit real mode data segment for prot_to_real transition */
|
|
80
|
+ .word 0xffff, ( P2R_DS << 4 )
|
76
|
81
|
.byte 0, 0x93, 0x00, 0
|
77
|
82
|
|
78
|
83
|
gdt_end:
|
79
|
84
|
.equ gdt_length, gdt_end - gdt
|
80
|
85
|
|
|
86
|
+/****************************************************************************
|
|
87
|
+ * Stored real-mode and protected-mode stack pointers
|
|
88
|
+ *
|
|
89
|
+ * The real-mode stack pointer is stored here whenever real_to_prot
|
|
90
|
+ * is called and restored whenever prot_to_real is called. The
|
|
91
|
+ * converse happens for the protected-mode stack pointer.
|
|
92
|
+ *
|
|
93
|
+ * Despite initial appearances this scheme is, in fact re-entrant,
|
|
94
|
+ * because program flow dictates that we always return via the point
|
|
95
|
+ * we left by. For example:
|
|
96
|
+ * PXE API call entry
|
|
97
|
+ * 1 real => prot
|
|
98
|
+ * ...
|
|
99
|
+ * Print a text string
|
|
100
|
+ * ...
|
|
101
|
+ * 2 prot => real
|
|
102
|
+ * INT 10
|
|
103
|
+ * 3 real => prot
|
|
104
|
+ * ...
|
|
105
|
+ * ...
|
|
106
|
+ * 4 prot => real
|
|
107
|
+ * PXE API call exit
|
|
108
|
+ *
|
|
109
|
+ * At point 1, the RM mode stack value, say RPXE, is stored in
|
|
110
|
+ * rm_ss,sp. We want this value to still be present in rm_ss,sp when
|
|
111
|
+ * we reach point 4.
|
|
112
|
+ *
|
|
113
|
+ * At point 2, the RM stack value is restored from RPXE. At point 3,
|
|
114
|
+ * the RM stack value is again stored in rm_ss,sp. This *does*
|
|
115
|
+ * overwrite the RPXE that we have stored there, but it's the same
|
|
116
|
+ * value, since the code between points 2 and 3 has managed to return
|
|
117
|
+ * to us.
|
|
118
|
+ ****************************************************************************
|
|
119
|
+ */
|
|
120
|
+ .section ".bss.rm_sp", "aw", @nobits
|
|
121
|
+ .globl rm_sp
|
|
122
|
+rm_sp: .word 0
|
|
123
|
+
|
|
124
|
+ .section ".bss.rm_ss", "aw", @nobits
|
|
125
|
+ .globl rm_ss
|
|
126
|
+rm_ss: .word 0
|
|
127
|
+
|
|
128
|
+ .section ".data.pm_esp", "aw", @progbits
|
|
129
|
+pm_esp: .long _estack
|
|
130
|
+
|
|
131
|
+/****************************************************************************
|
|
132
|
+ * Virtual address offsets
|
|
133
|
+ *
|
|
134
|
+ * These are used by the protected-mode code to map between virtual
|
|
135
|
+ * and physical addresses, and to access variables in the .text16 or
|
|
136
|
+ * .data16 segments.
|
|
137
|
+ ****************************************************************************
|
|
138
|
+ */
|
|
139
|
+ .struct 0
|
|
140
|
+VA_VIRT_OFFSET: .space 4
|
|
141
|
+VA_TEXT16: .space 4
|
|
142
|
+VA_DATA16: .space 4
|
|
143
|
+VA_SIZE:
|
|
144
|
+ .previous
|
|
145
|
+
|
|
146
|
+ /* Internal copies, used only by librm itself */
|
|
147
|
+ .section ".bss16.rm_virt_addrs", "aw", @nobits
|
|
148
|
+rm_virt_addrs: .space VA_SIZE
|
|
149
|
+ .equ rm_virt_offset, ( rm_virt_addrs + VA_VIRT_OFFSET )
|
|
150
|
+ .equ rm_text16, ( rm_virt_addrs + VA_TEXT16 )
|
|
151
|
+ .equ rm_data16, ( rm_virt_addrs + VA_DATA16 )
|
|
152
|
+
|
|
153
|
+ /* Externally visible variables, used by C code */
|
|
154
|
+ .section ".bss.virt_addrs", "aw", @nobits
|
|
155
|
+virt_addrs: .space VA_SIZE
|
|
156
|
+ .globl virt_offset
|
|
157
|
+ .equ virt_offset, ( virt_addrs + VA_VIRT_OFFSET )
|
|
158
|
+ .globl text16
|
|
159
|
+ .equ text16, ( virt_addrs + VA_TEXT16 )
|
|
160
|
+ .globl data16
|
|
161
|
+ .equ data16, ( virt_addrs + VA_DATA16 )
|
|
162
|
+
|
81
|
163
|
/****************************************************************************
|
82
|
164
|
* init_librm (real-mode far call, 16-bit real-mode far return address)
|
83
|
165
|
*
|
|
@@ -96,45 +178,65 @@ init_librm:
|
96
|
178
|
/* Preserve registers */
|
97
|
179
|
pushl %eax
|
98
|
180
|
pushl %ebx
|
|
181
|
+ pushl %edi
|
99
|
182
|
|
100
|
|
- /* Store virt_offset and set up virtual_cs and virtual_ds segments */
|
|
183
|
+ /* Store rm_virt_offset and set up virtual_cs and virtual_ds segments */
|
|
184
|
+ movl %edi, rm_virt_offset
|
101
|
185
|
movl %edi, %eax
|
102
|
186
|
movw $virtual_cs, %bx
|
103
|
187
|
call set_seg_base
|
104
|
188
|
movw $virtual_ds, %bx
|
105
|
|
- call set_seg_base
|
106
|
|
- movl %edi, rm_virt_offset
|
|
189
|
+ call set_seg_base
|
107
|
190
|
|
108
|
|
- /* Negate virt_offset */
|
109
|
|
- negl %edi
|
110
|
|
-
|
111
|
|
- /* Store rm_cs and text16, set up real_cs segment */
|
|
191
|
+ /* Store rm_cs and rm_text16, set up real_cs segment */
|
112
|
192
|
xorl %eax, %eax
|
113
|
193
|
movw %cs, %ax
|
114
|
194
|
movw %ax, %cs:rm_cs
|
115
|
195
|
shll $4, %eax
|
116
|
196
|
movw $real_cs, %bx
|
117
|
197
|
call set_seg_base
|
118
|
|
- addr32 leal (%eax, %edi), %ebx
|
119
|
|
- movl %ebx, rm_text16
|
|
198
|
+ subl %edi, %eax
|
|
199
|
+ movl %eax, rm_text16
|
120
|
200
|
|
121
|
|
- /* Store rm_ds and data16 */
|
|
201
|
+ /* Store rm_ds and rm_data16, set up real_ds segment and GDT base */
|
122
|
202
|
xorl %eax, %eax
|
123
|
203
|
movw %ds, %ax
|
124
|
204
|
movw %ax, %cs:rm_ds
|
125
|
205
|
shll $4, %eax
|
126
|
|
- addr32 leal (%eax, %edi), %ebx
|
127
|
|
- movl %ebx, rm_data16
|
128
|
|
-
|
129
|
|
- /* Set GDT base */
|
|
206
|
+ movw $real_ds, %bx
|
|
207
|
+ call set_seg_base
|
130
|
208
|
movl %eax, gdt_base
|
131
|
209
|
addl $gdt, gdt_base
|
|
210
|
+ subl %edi, %eax
|
|
211
|
+ movl %eax, rm_data16
|
|
212
|
+
|
|
213
|
+ /* Switch to protected mode */
|
|
214
|
+ virtcall init_librm_pmode
|
|
215
|
+ .section ".text.init_librm", "ax", @progbits
|
|
216
|
+ .code32
|
|
217
|
+init_librm_pmode:
|
|
218
|
+
|
|
219
|
+ /* Store virt_offset, text16, and data16 */
|
|
220
|
+ pushw %ds
|
|
221
|
+ movw $REAL_DS, %ax
|
|
222
|
+ movw %ax, %ds
|
|
223
|
+ movl $rm_virt_addrs, %esi
|
|
224
|
+ movl $virt_addrs, %edi
|
|
225
|
+ movl $( VA_SIZE / 4 ), %ecx
|
|
226
|
+ rep movsl
|
|
227
|
+ popw %ds
|
|
228
|
+
|
|
229
|
+ /* Return to real mode */
|
|
230
|
+ ret
|
|
231
|
+ .section ".text16.init_librm", "ax", @progbits
|
|
232
|
+ .code16
|
|
233
|
+init_librm_rmode:
|
132
|
234
|
|
133
|
235
|
/* Initialise IDT */
|
134
|
236
|
virtcall init_idt
|
135
|
237
|
|
136
|
238
|
/* Restore registers */
|
137
|
|
- negl %edi
|
|
239
|
+ popl %edi
|
138
|
240
|
popl %ebx
|
139
|
241
|
popl %eax
|
140
|
242
|
lret
|
|
@@ -177,16 +279,10 @@ real_to_prot:
|
177
|
279
|
1: jc 1b
|
178
|
280
|
|
179
|
281
|
/* Make sure we have our data segment available */
|
180
|
|
- movw %cs:rm_ds, %ax
|
181
|
|
- movw %ax, %ds
|
|
282
|
+ movw %cs:rm_ds, %ds
|
182
|
283
|
|
183
|
|
- /* Add virt_offset, text16 and data16 to stack to be
|
184
|
|
- * copied, and also copy the return address.
|
185
|
|
- */
|
186
|
|
- pushl rm_virt_offset
|
187
|
|
- pushl rm_text16
|
188
|
|
- pushl rm_data16
|
189
|
|
- addw $16, %cx /* %ecx must be less than 64kB anyway */
|
|
284
|
+ /* Add protected-mode return address to length of data to be copied */
|
|
285
|
+ addw $4, %cx /* %ecx must be less than 64kB anyway */
|
190
|
286
|
|
191
|
287
|
/* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
|
192
|
288
|
xorl %ebp, %ebp
|
|
@@ -242,11 +338,6 @@ r2p_pmode:
|
242
|
338
|
movl %esp, %edi
|
243
|
339
|
rep movsb
|
244
|
340
|
|
245
|
|
- /* Publish virt_offset, text16 and data16 for PM code to use */
|
246
|
|
- popl data16
|
247
|
|
- popl text16
|
248
|
|
- popl virt_offset
|
249
|
|
-
|
250
|
341
|
/* Return to virtual address */
|
251
|
342
|
ret
|
252
|
343
|
|
|
@@ -284,7 +375,7 @@ prot_to_real:
|
284
|
375
|
|
285
|
376
|
/* Add return address to data to be moved to RM stack */
|
286
|
377
|
addl $4, %ecx
|
287
|
|
-
|
|
378
|
+
|
288
|
379
|
/* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */
|
289
|
380
|
movzwl rm_ss, %ebp
|
290
|
381
|
movzwl rm_sp, %edx
|
|
@@ -293,16 +384,16 @@ prot_to_real:
|
293
|
384
|
shll $4, %eax
|
294
|
385
|
leal (%eax,%edx), %edi
|
295
|
386
|
subl virt_offset, %edi
|
296
|
|
-
|
|
387
|
+
|
297
|
388
|
/* Move data from PM stack to RM stack */
|
298
|
389
|
movl %esp, %esi
|
299
|
390
|
rep movsb
|
300
|
|
-
|
|
391
|
+
|
301
|
392
|
/* Record protected-mode %esp (after removal of data) */
|
302
|
393
|
movl %esi, pm_esp
|
303
|
394
|
|
304
|
395
|
/* Load real-mode segment limits */
|
305
|
|
- movw $REAL_DS, %ax
|
|
396
|
+ movw $P2R_DS, %ax
|
306
|
397
|
movw %ax, %ds
|
307
|
398
|
movw %ax, %es
|
308
|
399
|
movw %ax, %fs
|
|
@@ -604,71 +695,3 @@ interrupt_wrapper:
|
604
|
695
|
/* Restore registers and return */
|
605
|
696
|
popal
|
606
|
697
|
iret
|
607
|
|
-
|
608
|
|
-/****************************************************************************
|
609
|
|
- * Stored real-mode and protected-mode stack pointers
|
610
|
|
- *
|
611
|
|
- * The real-mode stack pointer is stored here whenever real_to_prot
|
612
|
|
- * is called and restored whenever prot_to_real is called. The
|
613
|
|
- * converse happens for the protected-mode stack pointer.
|
614
|
|
- *
|
615
|
|
- * Despite initial appearances this scheme is, in fact re-entrant,
|
616
|
|
- * because program flow dictates that we always return via the point
|
617
|
|
- * we left by. For example:
|
618
|
|
- * PXE API call entry
|
619
|
|
- * 1 real => prot
|
620
|
|
- * ...
|
621
|
|
- * Print a text string
|
622
|
|
- * ...
|
623
|
|
- * 2 prot => real
|
624
|
|
- * INT 10
|
625
|
|
- * 3 real => prot
|
626
|
|
- * ...
|
627
|
|
- * ...
|
628
|
|
- * 4 prot => real
|
629
|
|
- * PXE API call exit
|
630
|
|
- *
|
631
|
|
- * At point 1, the RM mode stack value, say RPXE, is stored in
|
632
|
|
- * rm_ss,sp. We want this value to still be present in rm_ss,sp when
|
633
|
|
- * we reach point 4.
|
634
|
|
- *
|
635
|
|
- * At point 2, the RM stack value is restored from RPXE. At point 3,
|
636
|
|
- * the RM stack value is again stored in rm_ss,sp. This *does*
|
637
|
|
- * overwrite the RPXE that we have stored there, but it's the same
|
638
|
|
- * value, since the code between points 2 and 3 has managed to return
|
639
|
|
- * to us.
|
640
|
|
- ****************************************************************************
|
641
|
|
- */
|
642
|
|
- .section ".bss.rm_sp", "aw", @nobits
|
643
|
|
- .globl rm_sp
|
644
|
|
-rm_sp: .word 0
|
645
|
|
-
|
646
|
|
- .section ".bss.rm_ss", "aw", @nobits
|
647
|
|
- .globl rm_ss
|
648
|
|
-rm_ss: .word 0
|
649
|
|
-
|
650
|
|
- .section ".data.pm_esp", "aw", @progbits
|
651
|
|
-pm_esp: .long _estack
|
652
|
|
-
|
653
|
|
-/****************************************************************************
|
654
|
|
- * Virtual address offsets
|
655
|
|
- *
|
656
|
|
- * These are used by the protected-mode code to map between virtual
|
657
|
|
- * and physical addresses, and to access variables in the .text16 or
|
658
|
|
- * .data16 segments.
|
659
|
|
- ****************************************************************************
|
660
|
|
- */
|
661
|
|
- /* Internal copies, created by init_librm (which runs in real mode) */
|
662
|
|
- .section ".bss16.rm_virt_offset", "aw", @nobits
|
663
|
|
-rm_virt_offset: .long 0
|
664
|
|
-rm_text16: .long 0
|
665
|
|
-rm_data16: .long 0
|
666
|
|
-
|
667
|
|
- /* Externally-visible copies, created by real_to_prot */
|
668
|
|
- .section ".bss.virt_offset", "aw", @nobits
|
669
|
|
- .globl virt_offset
|
670
|
|
-virt_offset: .long 0
|
671
|
|
- .globl text16
|
672
|
|
-text16: .long 0
|
673
|
|
- .globl data16
|
674
|
|
-data16: .long 0
|