https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0d6631c2da3eb593623af…
commit 0d6631c2da3eb593623af9cff8fef86530aecd55
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Wed Oct 2 03:20:10 2019 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue Oct 8 01:30:15 2019 +0200
[FREELDR] Fix an inconsistency bug when switching the CPU state back to 16-bit real
mode.
Basically it appeared that without this fix, the CPU was somehow residing
in an inconsistent state, that made it crash when a full 16-bit real-mode
to 32-bit protected mode transition occurred. (Encountered when trying
to load Linux, see problem description below.)
In that situation, Bochs reports that the CPU is in "compatibility mode".
The fix is based from information from Fig.1-6 "Operating Modes of the
AMD64 Architecture" (page 12) and Chapter 14 (pages 429-446) of the
"AMD64 Architecture Programmer’s Manual Volume 2: System Programming"
https://www.amd.com/system/files/TechDocs/24593.pdf
*** THE PROBLEM ***
When booting Linux using x86 FreeLdr everything goes well.
When trying to do the same using x64 FreeLdr, the Linux code (both the
boot sector, the setup sector and the main kernel contents) is all
correctly loaded and relocated in memory as in the x86 case. We then pass
control to the decompressing code that appears to succeed. However, once
it has finished and "Parsing ELF file..." step has been run, the next
step "Booting the kernel..." crashes with a CPU Triple-Fault.
This problem **DOES NOT HAPPEN** when booting from GRUB.
Log excerpt from Bochs:
<snip>
00089459736i[BIOS ] Booting from 07c0:0000
00089782775i[SER ] com1: FIFO enabled
00095994535i[BIOS ] int13_harddisk: function 41, unmapped device for ELDL=81
00095998517i[BIOS ] int13_harddisk: function 08, unmapped device for ELDL=81
00397139785i[BIOS ] KBD: unsupported int 16h function 03
00397143625i[BIOS ] *** int 15h function AX=e980, BX=0000 not yet supported!
00523008104e[CPU0 ] interrupt(long mode): vector must be within IDT table limits,
IDT.limit = 0x0
00523008104e[CPU0 ] interrupt(long mode): vector must be within IDT table limits,
IDT.limit = 0x0
00523008104i[CPU0 ] CPU is in compatibility mode (active)
00523008104i[CPU0 ] CS.mode = 32 bit
00523008104i[CPU0 ] SS.mode = 32 bit
00523008104i[CPU0 ] EFER = 0x00000500
00523008104i[CPU0 ] | RAX=00000000e0000011 RBX=0000000000000000
00523008104i[CPU0 ] | RCX=0000000000000000 RDX=0000000000000000
00523008104i[CPU0 ] | RSP=00000000004f8000 RBP=000000000082e003
00523008104i[CPU0 ] | RSI=0000000000099800 RDI=00000000c0611000
00523008104i[CPU0 ] | R8=0000000000109000 R9=0000000000009020
00523008104i[CPU0 ] | R10=00000000000007e3 R11=000000000000e958
00523008104i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00523008104i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00523008104i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00523008104i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00523008104i[CPU0 ] | CS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | DS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | SS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | ES:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | FS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | GS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00523008104i[CPU0 ] | MSR_FS_BASE:0000000000000000
00523008104i[CPU0 ] | MSR_GS_BASE:0000000000000000
00523008104i[CPU0 ] | RIP=0000000000409327 (0000000000409327)
00523008104i[CPU0 ] | CR0=0xe0000011 CR2=0x0000000000409327
00523008104i[CPU0 ] | CR3=0x005b5000 CR4=0x000000a0
00523008104i[CPU0 ] 0x0000000000409327: (instruction unavailable) page not present
00523008104p[CPU0 ] >>PANIC<< exception(): 3rd (13) exception with no
resolution
<snip>
---
boot/freeldr/freeldr/arch/realmode/amd64.S | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/boot/freeldr/freeldr/arch/realmode/amd64.S
b/boot/freeldr/freeldr/arch/realmode/amd64.S
index 0a97afd402d..ea1494f6b80 100644
--- a/boot/freeldr/freeldr/arch/realmode/amd64.S
+++ b/boot/freeldr/freeldr/arch/realmode/amd64.S
@@ -160,6 +160,12 @@ CheckFor64BitSupport:
.ascii "PAE or PGE not set.", CR, LF, NUL
.CheckForLongMode:
+ /* Check whether extended functions are supported */
+ mov eax, HEX(80000000)
+ cpuid
+ cmp eax, HEX(80000000) // Any function > 0x80000000 ?
+ jbe .NoLongMode // If not, no long mode.
+ /* Check whether the CPU supports Long Mode */
xor edx, edx
mov eax, HEX(80000001)
cpuid
@@ -167,6 +173,7 @@ CheckFor64BitSupport:
test edx, edx
jnz .Success
+.NoLongMode:
mov si, offset .Msg_NoLongMode
call writestr
popad
@@ -240,6 +247,18 @@ BuildPageTables:
/* This is the entry point from long mode */
RealModeEntryPoint:
+
+ /* Disable long mode */
+ mov ecx, MSR_EFER
+ rdmsr
+ and eax, HEX(0FFFFFEFF) // ~0100
+ wrmsr
+
+ /* Mask PAE and PGE out */
+ mov eax, cr4
+ and eax, HEX(0FFFFFF5F) // ~00A0
+ mov cr4, eax
+
/* Disable Protected Mode */
mov eax, cr0
and eax, HEX(0FFFFFFFE) // ~0x00000001
@@ -295,6 +314,8 @@ ExitToLongMode:
mov word ptr ds:[stack16], sp
/* Set PAE and PGE: 10100000b */
+ // mov eax, cr4
+ // or eax, HEX(00A0)
mov eax, HEX(00A0)
mov cr4, eax