|
@@ -180,17 +180,49 @@ gdt_end:
|
180
|
180
|
* to us.
|
181
|
181
|
****************************************************************************
|
182
|
182
|
*/
|
183
|
|
- .section ".bss.rm_sp", "aw", @nobits
|
|
183
|
+ .section ".bss.rm_ss_sp", "aw", @nobits
|
184
|
184
|
.globl rm_sp
|
185
|
185
|
rm_sp: .word 0
|
186
|
|
-
|
187
|
|
- .section ".bss.rm_ss", "aw", @nobits
|
188
|
186
|
.globl rm_ss
|
189
|
187
|
rm_ss: .word 0
|
190
|
188
|
|
191
|
189
|
.section ".data.pm_esp", "aw", @progbits
|
192
|
190
|
pm_esp: .long VIRTUAL(_estack)
|
193
|
191
|
|
|
192
|
+/****************************************************************************
|
|
193
|
+ * Temporary static data buffer
|
|
194
|
+ *
|
|
195
|
+ * This is used to reduce the amount of real-mode stack space consumed
|
|
196
|
+ * during mode transitions, since we are sometimes called with very
|
|
197
|
+ * little real-mode stack space available.
|
|
198
|
+ ****************************************************************************
|
|
199
|
+ */
|
|
200
|
+ /* Temporary static buffer usage by virt_call */
|
|
201
|
+ .struct 0
|
|
202
|
+VC_TMP_GDT: .space 6
|
|
203
|
+VC_TMP_IDT: .space 6
|
|
204
|
+VC_TMP_PAD: .space 4 /* for alignment */
|
|
205
|
+.if64
|
|
206
|
+VC_TMP_CR3: .space 4
|
|
207
|
+VC_TMP_CR4: .space 4
|
|
208
|
+VC_TMP_EMER: .space 8
|
|
209
|
+.endif
|
|
210
|
+VC_TMP_END:
|
|
211
|
+ .previous
|
|
212
|
+
|
|
213
|
+ /* Temporary static buffer usage by real_call */
|
|
214
|
+ .struct 0
|
|
215
|
+RC_TMP_FUNCTION: .space 4
|
|
216
|
+RC_TMP_END:
|
|
217
|
+ .previous
|
|
218
|
+
|
|
219
|
+ /* Shared temporary static buffer */
|
|
220
|
+ .section ".bss16.rm_tmpbuf", "aw", @nobits
|
|
221
|
+ .align 16
|
|
222
|
+rm_tmpbuf:
|
|
223
|
+ .space VC_TMP_END
|
|
224
|
+ .size rm_tmpbuf, . - rm_tmpbuf
|
|
225
|
+
|
194
|
226
|
/****************************************************************************
|
195
|
227
|
* Virtual address offsets
|
196
|
228
|
*
|
|
@@ -341,6 +373,7 @@ set_seg_base:
|
341
|
373
|
*
|
342
|
374
|
* Parameters:
|
343
|
375
|
* %ecx : number of bytes to move from RM stack to PM stack
|
|
376
|
+ * %edx : number of bytes to copy from RM temporary buffer to PM stack
|
344
|
377
|
*
|
345
|
378
|
****************************************************************************
|
346
|
379
|
*/
|
|
@@ -361,14 +394,19 @@ real_to_prot:
|
361
|
394
|
/* Add protected-mode return address to length of data to be copied */
|
362
|
395
|
addw $4, %cx /* %ecx must be less than 64kB anyway */
|
363
|
396
|
|
364
|
|
- /* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
|
365
|
|
- xorl %ebp, %ebp
|
366
|
|
- movw %ss, %bp
|
367
|
|
- movzwl %sp, %edx
|
368
|
|
- movl %ebp, %eax
|
|
397
|
+ /* Real-mode %ss:%sp => %ebp and virtual address => %esi */
|
|
398
|
+ xorl %eax, %eax
|
|
399
|
+ movw %ss, %ax
|
369
|
400
|
shll $4, %eax
|
370
|
|
- addr32 leal (%eax,%edx), %esi
|
|
401
|
+ movzwl %sp, %ebp
|
|
402
|
+ addr32 leal (%eax,%ebp), %esi
|
371
|
403
|
subl rm_virt_offset, %esi
|
|
404
|
+ shll $12, %eax
|
|
405
|
+ orl %eax, %ebp
|
|
406
|
+
|
|
407
|
+ /* Real-mode data segment virtual address => %ebx */
|
|
408
|
+ movl rm_data16, %ebx
|
|
409
|
+.if64 ; subl rm_virt_offset, %ebx ; .endif
|
372
|
410
|
|
373
|
411
|
/* Load protected-mode global descriptor table */
|
374
|
412
|
data32 lgdt gdtr
|
|
@@ -407,15 +445,20 @@ r2p_pmode:
|
407
|
445
|
lidt VIRTUAL(idtr32)
|
408
|
446
|
|
409
|
447
|
/* Record real-mode %ss:sp (after removal of data) */
|
410
|
|
- movw %bp, VIRTUAL(rm_ss)
|
411
|
|
- addl %ecx, %edx
|
412
|
|
- movw %dx, VIRTUAL(rm_sp)
|
|
448
|
+ addl %ecx, %ebp
|
|
449
|
+ movl %ebp, VIRTUAL(rm_sp)
|
413
|
450
|
|
414
|
451
|
/* Move data from RM stack to PM stack */
|
|
452
|
+ subl %edx, %esp
|
415
|
453
|
subl %ecx, %esp
|
416
|
454
|
movl %esp, %edi
|
417
|
455
|
rep movsb
|
418
|
456
|
|
|
457
|
+ /* Copy data from RM temporary buffer to PM stack */
|
|
458
|
+ leal rm_tmpbuf(%ebx), %esi
|
|
459
|
+ movl %edx, %ecx
|
|
460
|
+ rep movsb
|
|
461
|
+
|
419
|
462
|
/* Return to virtual address */
|
420
|
463
|
ret
|
421
|
464
|
|
|
@@ -435,6 +478,7 @@ r2p_pmode:
|
435
|
478
|
*
|
436
|
479
|
* Parameters:
|
437
|
480
|
* %ecx : number of bytes to move from PM stack to RM stack
|
|
481
|
+ * %edx : number of bytes to move from PM stack to RM temporary buffer
|
438
|
482
|
* %esi : real-mode global and interrupt descriptor table registers
|
439
|
483
|
*
|
440
|
484
|
****************************************************************************
|
|
@@ -455,19 +499,26 @@ prot_to_real:
|
455
|
499
|
/* Add return address to data to be moved to RM stack */
|
456
|
500
|
addl $4, %ecx
|
457
|
501
|
|
458
|
|
- /* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */
|
459
|
|
- movzwl VIRTUAL(rm_ss), %ebp
|
460
|
|
- movzwl VIRTUAL(rm_sp), %edx
|
461
|
|
- subl %ecx, %edx
|
462
|
|
- movl %ebp, %eax
|
|
502
|
+ /* Real-mode %ss:sp => %ebp and virtual address => %edi */
|
|
503
|
+ movl VIRTUAL(rm_sp), %ebp
|
|
504
|
+ subl %ecx, %ebp
|
|
505
|
+ movzwl VIRTUAL(rm_ss), %eax
|
463
|
506
|
shll $4, %eax
|
464
|
|
- leal (%eax,%edx), %edi
|
|
507
|
+ movzwl %bp, %edi
|
|
508
|
+ addl %eax, %edi
|
465
|
509
|
subl VIRTUAL(virt_offset), %edi
|
466
|
510
|
|
467
|
511
|
/* Move data from PM stack to RM stack */
|
468
|
512
|
movl %esp, %esi
|
469
|
513
|
rep movsb
|
470
|
514
|
|
|
515
|
+ /* Move data from PM stack to RM temporary buffer */
|
|
516
|
+ movl VIRTUAL(data16), %edi
|
|
517
|
+.if64 ; subl VIRTUAL(virt_offset), %edi ; .endif
|
|
518
|
+ addl $rm_tmpbuf, %edi
|
|
519
|
+ movl %edx, %ecx
|
|
520
|
+ rep movsb
|
|
521
|
+
|
471
|
522
|
/* Record protected-mode %esp (after removal of data) */
|
472
|
523
|
movl %esi, VIRTUAL(pm_esp)
|
473
|
524
|
|
|
@@ -497,8 +548,10 @@ p2r_ljmp_rm_cs:
|
497
|
548
|
movw %ax, %es
|
498
|
549
|
movw %ax, %fs
|
499
|
550
|
movw %ax, %gs
|
500
|
|
- movw %bp, %ss
|
501
|
|
- movl %edx, %esp
|
|
551
|
+ movl %ebp, %eax
|
|
552
|
+ shrl $16, %eax
|
|
553
|
+ movw %ax, %ss
|
|
554
|
+ movzwl %bp, %esp
|
502
|
555
|
|
503
|
556
|
/* Return to real-mode address */
|
504
|
557
|
data32 ret
|
|
@@ -921,14 +974,6 @@ long_restore_regs:
|
921
|
974
|
****************************************************************************
|
922
|
975
|
*/
|
923
|
976
|
.struct 0
|
924
|
|
-VC_OFFSET_GDT: .space 6
|
925
|
|
-VC_OFFSET_IDT: .space 6
|
926
|
|
-.if64
|
927
|
|
-VC_OFFSET_PADDING64: .space 4 /* for alignment */
|
928
|
|
-VC_OFFSET_CR3: .space 4
|
929
|
|
-VC_OFFSET_CR4: .space 4
|
930
|
|
-VC_OFFSET_EMER: .space 8
|
931
|
|
-.endif
|
932
|
977
|
VC_OFFSET_IX86: .space SIZEOF_I386_ALL_REGS
|
933
|
978
|
VC_OFFSET_PADDING: .space 2 /* for alignment */
|
934
|
979
|
VC_OFFSET_RETADDR: .space 2
|
|
@@ -941,7 +986,7 @@ VC_OFFSET_END:
|
941
|
986
|
.code16
|
942
|
987
|
.globl virt_call
|
943
|
988
|
virt_call:
|
944
|
|
- /* Preserve registers, flags and GDT on external RM stack */
|
|
989
|
+ /* Preserve registers and flags on external RM stack */
|
945
|
990
|
pushw %ss /* padding */
|
946
|
991
|
pushfl
|
947
|
992
|
pushal
|
|
@@ -951,34 +996,38 @@ virt_call:
|
951
|
996
|
pushw %ds
|
952
|
997
|
pushw %ss
|
953
|
998
|
pushw %cs
|
954
|
|
- subw $VC_OFFSET_IX86, %sp
|
955
|
|
- movw %sp, %bp
|
956
|
|
- sidt VC_OFFSET_IDT(%bp)
|
957
|
|
- sgdt VC_OFFSET_GDT(%bp)
|
|
999
|
+
|
|
1000
|
+ /* Claim ownership of temporary static buffer */
|
|
1001
|
+ cli
|
|
1002
|
+
|
|
1003
|
+ /* Preserve GDT and IDT in temporary static buffer */
|
|
1004
|
+ movw %cs:rm_ds, %ds
|
|
1005
|
+ sidt ( rm_tmpbuf + VC_TMP_IDT )
|
|
1006
|
+ sgdt ( rm_tmpbuf + VC_TMP_GDT )
|
958
|
1007
|
|
959
|
1008
|
.if64 ; /* Preserve control registers, if applicable */
|
960
|
1009
|
movl $MSR_EFER, %ecx
|
961
|
1010
|
rdmsr
|
962
|
|
- movl %eax, (VC_OFFSET_EMER+0)(%bp)
|
963
|
|
- movl %edx, (VC_OFFSET_EMER+4)(%bp)
|
|
1011
|
+ movl %eax, ( rm_tmpbuf + VC_TMP_EMER + 0 )
|
|
1012
|
+ movl %edx, ( rm_tmpbuf + VC_TMP_EMER + 4 )
|
964
|
1013
|
movl %cr4, %eax
|
965
|
|
- movl %eax, VC_OFFSET_CR4(%bp)
|
|
1014
|
+ movl %eax, ( rm_tmpbuf + VC_TMP_CR4 )
|
966
|
1015
|
movl %cr3, %eax
|
967
|
|
- movl %eax, VC_OFFSET_CR3(%bp)
|
|
1016
|
+ movl %eax, ( rm_tmpbuf + VC_TMP_CR3 )
|
968
|
1017
|
.endif
|
969
|
1018
|
/* For sanity's sake, clear the direction flag as soon as possible */
|
970
|
1019
|
cld
|
971
|
1020
|
|
972
|
1021
|
/* Switch to protected mode and move register dump to PM stack */
|
973
|
1022
|
movl $VC_OFFSET_END, %ecx
|
|
1023
|
+ movl $VC_TMP_END, %edx
|
974
|
1024
|
pushl $VIRTUAL(vc_pmode)
|
975
|
1025
|
vc_jmp: jmp real_to_prot
|
976
|
1026
|
.section ".text.virt_call", "ax", @progbits
|
977
|
1027
|
.code32
|
978
|
1028
|
vc_pmode:
|
979
|
1029
|
/* Call function (in protected mode) */
|
980
|
|
- leal VC_OFFSET_IX86(%esp), %eax
|
981
|
|
- pushl %eax
|
|
1030
|
+ pushl %esp
|
982
|
1031
|
call *(VC_OFFSET_FUNCTION+4)(%esp)
|
983
|
1032
|
popl %eax /* discard */
|
984
|
1033
|
|
|
@@ -989,11 +1038,9 @@ vc_lmode:
|
989
|
1038
|
.code64
|
990
|
1039
|
|
991
|
1040
|
/* Call function (in long mode) */
|
992
|
|
- leaq VC_OFFSET_IX86(%rsp), %rdi
|
993
|
|
- pushq %rdi
|
994
|
|
- movslq (VC_OFFSET_FUNCTION+8)(%rsp), %rax
|
|
1041
|
+ movq %rsp, %rdi
|
|
1042
|
+ movslq VC_OFFSET_FUNCTION(%rsp), %rax
|
995
|
1043
|
callq *%rax
|
996
|
|
- popq %rdi /* discard */
|
997
|
1044
|
|
998
|
1045
|
/* Switch to protected mode */
|
999
|
1046
|
call long_to_prot
|
|
@@ -1001,7 +1048,8 @@ vc_lmode:
|
1001
|
1048
|
.endif
|
1002
|
1049
|
/* Switch to real mode and move register dump back to RM stack */
|
1003
|
1050
|
movl $VC_OFFSET_END, %ecx
|
1004
|
|
- movl %esp, %esi
|
|
1051
|
+ movl $VC_TMP_END, %edx
|
|
1052
|
+ leal VC_TMP_GDT(%esp, %ecx), %esi
|
1005
|
1053
|
pushl $vc_rmode
|
1006
|
1054
|
jmp prot_to_real
|
1007
|
1055
|
.section ".text16.virt_call", "ax", @progbits
|
|
@@ -1009,17 +1057,17 @@ vc_lmode:
|
1009
|
1057
|
vc_rmode:
|
1010
|
1058
|
.if64 ; /* Restore control registers, if applicable */
|
1011
|
1059
|
movw %sp, %bp
|
1012
|
|
- movl VC_OFFSET_CR3(%bp), %eax
|
|
1060
|
+ movl ( rm_tmpbuf + VC_TMP_CR3 ), %eax
|
1013
|
1061
|
movl %eax, %cr3
|
1014
|
|
- movl VC_OFFSET_CR4(%bp), %eax
|
|
1062
|
+ movl ( rm_tmpbuf + VC_TMP_CR4 ), %eax
|
1015
|
1063
|
movl %eax, %cr4
|
1016
|
|
- movl (VC_OFFSET_EMER+0)(%bp), %eax
|
1017
|
|
- movl (VC_OFFSET_EMER+4)(%bp), %edx
|
|
1064
|
+ movl ( rm_tmpbuf + VC_TMP_EMER + 0 ), %eax
|
|
1065
|
+ movl ( rm_tmpbuf + VC_TMP_EMER + 4 ), %edx
|
1018
|
1066
|
movl $MSR_EFER, %ecx
|
1019
|
1067
|
wrmsr
|
1020
|
1068
|
.endif
|
1021
|
1069
|
/* Restore registers and flags and return */
|
1022
|
|
- addw $( VC_OFFSET_IX86 + 4 /* also skip %cs and %ss */ ), %sp
|
|
1070
|
+ popl %eax /* skip %cs and %ss */
|
1023
|
1071
|
popw %ds
|
1024
|
1072
|
popw %es
|
1025
|
1073
|
popw %fs
|
|
@@ -1067,6 +1115,7 @@ vc_rmode:
|
1067
|
1115
|
.struct 0
|
1068
|
1116
|
RC_OFFSET_REGS: .space SIZEOF_I386_REGS
|
1069
|
1117
|
RC_OFFSET_REGS_END:
|
|
1118
|
+RC_OFFSET_FUNCTION_COPY:.space 4
|
1070
|
1119
|
.if64
|
1071
|
1120
|
RC_OFFSET_LREGS: .space SIZEOF_X86_64_REGS
|
1072
|
1121
|
RC_OFFSET_LREG_RETADDR: .space SIZEOF_ADDR
|
|
@@ -1087,11 +1136,12 @@ real_call:
|
1087
|
1136
|
.code32
|
1088
|
1137
|
.endif
|
1089
|
1138
|
/* Create register dump and function pointer copy on PM stack */
|
|
1139
|
+ pushl ( RC_OFFSET_FUNCTION - RC_OFFSET_FUNCTION_COPY - 4 )(%esp)
|
1090
|
1140
|
pushal
|
1091
|
|
- pushl RC_OFFSET_FUNCTION(%esp)
|
1092
|
1141
|
|
1093
|
1142
|
/* Switch to real mode and move register dump to RM stack */
|
1094
|
|
- movl $( RC_OFFSET_REGS_END + 4 /* function pointer copy */ ), %ecx
|
|
1143
|
+ movl $RC_OFFSET_REGS_END, %ecx
|
|
1144
|
+ movl $RC_TMP_END, %edx
|
1095
|
1145
|
pushl $rc_rmode
|
1096
|
1146
|
movl $VIRTUAL(rm_default_gdtr_idtr), %esi
|
1097
|
1147
|
jmp prot_to_real
|
|
@@ -1099,9 +1149,8 @@ real_call:
|
1099
|
1149
|
.code16
|
1100
|
1150
|
rc_rmode:
|
1101
|
1151
|
/* Call real-mode function */
|
1102
|
|
- popl rc_function
|
1103
|
1152
|
popal
|
1104
|
|
- call *rc_function
|
|
1153
|
+ call *( rm_tmpbuf + RC_TMP_FUNCTION )
|
1105
|
1154
|
pushal
|
1106
|
1155
|
|
1107
|
1156
|
/* For sanity's sake, clear the direction flag as soon as possible */
|
|
@@ -1109,6 +1158,7 @@ rc_rmode:
|
1109
|
1158
|
|
1110
|
1159
|
/* Switch to protected mode and move register dump back to PM stack */
|
1111
|
1160
|
movl $RC_OFFSET_REGS_END, %ecx
|
|
1161
|
+ xorl %edx, %edx
|
1112
|
1162
|
pushl $VIRTUAL(rc_pmode)
|
1113
|
1163
|
jmp real_to_prot
|
1114
|
1164
|
.section ".text.real_call", "ax", @progbits
|
|
@@ -1126,12 +1176,6 @@ rc_pmode:
|
1126
|
1176
|
ret $( RC_OFFSET_END - RC_OFFSET_PARAMS )
|
1127
|
1177
|
|
1128
|
1178
|
|
1129
|
|
- /* Function vector, used because "call xx(%sp)" is not a valid
|
1130
|
|
- * 16-bit expression.
|
1131
|
|
- */
|
1132
|
|
- .section ".bss16.rc_function", "aw", @nobits
|
1133
|
|
-rc_function: .word 0, 0
|
1134
|
|
-
|
1135
|
1179
|
/* Default real-mode global and interrupt descriptor table registers */
|
1136
|
1180
|
.section ".data.rm_default_gdtr_idtr", "aw", @progbits
|
1137
|
1181
|
rm_default_gdtr_idtr:
|