Search code examples
x86kernelreal-modeprotected-modesmp

Entering Protected Mode: Triple-Fault


I am adding SMP to my kernel, in which the AP should boot. It starts in realmode and faults on entering protected mode. To be clear, it faults on the JMP 0x8:... after loading CR0. I am sure that the AP is getting its code, because looping anywhere in between prevents a fault. The copies the code area APBoot-APBootSequenceEnd to a physical memory location at 9*64KB. I have tried multiple ways to code it, giving it in the comments in the code -

 ;             +============================================================================ =
; File: APBoot.asm
 ; =
; Summary: This file contains the code for initializing APs (application  processors)
; on a SMP system.
;
; The code is copyed to 9*64*1024 before sending INIT-SIPI-SIPI
;
; Copyright (C) 2017 - Shukant Pal
  ;=============================================================================+

global APBoot
 global apSetupInfo
  global APBootSequenceStart


 [bits 16]
   SECTION .TEXT
    ALIGN 4
    APBoot: ; Page-aligned Booting File (copyed and filled by PROCESSOR_SETUP_INFO.BootManager)
    XOR EAX, EAX
    MOV AX, CS                      ; Load CS into AX
    MOV DS, AX                      ; Copy CS into DS
    CLI
    MOV ES, AX                      ; Copy CS into ES
    MOV GS, AX                      ; Copy CS into GS
    MOV FS, AX                      ; Copy CS into FS

    XOR EAX, EAX
    MOV AX, CS
    SHL EAX, 4
    ADD EAX, defaultBootGDTPointer-APBoot

    LGDT [EAX] ; Even LGDT [9*64*1024+defaultBootGDTPointer-APBoot] doesn't work (why?)

    MOV EAX, CR0                        ; Load CR0 into EDX
    OR AL, 0x1                      ; Set PM-bit in EDX
    MOV CR0, EAX                        ; Enable Protected-Mode
    ;[bits 32]; Even if I turn this off, still triple-faults
    JMP 0x8:(9*64*1024+InitSoftwareEnvironment-APBoot) ; Triple Fault

    ALIGN 4
    apSetupInfo:                        ; (ALIGNED) PROCESSOR_SETUP_INFO

    apBootManager:  DD 0x00000000           ; PROCESSOR_SETUP_INFO.BootManager
    apBootAddress:  DD 0x00000000           ; PROCESSOR_SETUP_INFO.BootAddress
    apBootStack:    DD 0x00000000           ; PROCESSOR_SETUP_INFO.BootStack
    apStatus:       DD 0x00000002           ; PROCESSOR_SETUP_INFO.StatusCounter
    apErrorReg: DD 0xE0000000           ; PROCESSOR_SETUP_INFO.ErrorRegister (equ AP_NO_BOOT_ERR)
    apErrorReg1: DD 0
    apErrorReg2: DD 0
    apErrorReg4: DD 0

    defaultBootGDT:                 ; PROCESSOR_SETUP_INFO.DefaultBootGDT
    defaultBootGDTStart:
        DQ 0x0000000000000000           ; NULL GDT_ENTRY

    ; GDT_ENTRY - KernelCode
        DW 0xFFFF                       ; KernelCode.Limit
        DW 0x0000                       ; KernelCode.BaseLow
        DB 0x00                     ; KernelCode.BaseMiddle
        DB 0x9A                     ; KernelCode.Access
        DB 0xCF                     ; KernelCode.Granularity
        DB 0x00                     ; KernelCode.BaseHigh

    ; GDT_ENTRY - KernelData
        DW 0xFFFF                       ; KernelData.Limit
        DW 0x0000                       ; KernelData.BaseLow
        DB 0x00                     ; KernelData.BaseMiddle
        DB 0x92                     ; KernelData.Access
        DB 0xCF                     ; KernelData.Granularity
        DB 0x00                     ; KernelCode.BaseHigh

        DQ 0
        DQ 0

    defaultBootGDTEnd:

    defaultBootGDTPointer:              ; PROCESSOR_SETUP_INFO.DefaultBootGDTPointer
        DW 23                       ; defaultBootGDTPointer.Limit (loaded at Runtime)
        DD (9*64*1024+defaultBootGDT-APBoot)                    ; defaultBootGDTPointer.Base    (loaded at Runtime)

    APBootSequenceStart:

    ALIGN 4
    [bits 32]
    InitSoftwareEnvironment:
        JMP $
        MOV AX, 0x10
        MOV DS, AX
        MOV GS, AX
        MOV ES, AX
        MOV FS, AX
        MOV SS, AX

    ;   MOV EBX, 632 * 1024 + apStatus - APBoot
    ;   MOV DWORD [EBX], 0x1
    ;   MOV DWORD [0xB8000], 0xFFFFFFFF
        JMP $

    global APBootSequenceEnd
    APBootSequenceEnd:

Solution

  • I have found the answer to my question. NASM assembler didn't warn me about the address overriding needed. The address (9*64*1024+InitSoftwareEnvironment) overflows the 16-bit data size. So, I need to use the address overriding option - by changing

    JMP 0x8:(9*64*1024+InitSoftwareEnvironment-APBoot)
    

    to

    JMP DWORD 0x8:(9*64*1024+InitSoftwareEnvironment-APBoot)