Here's the problem. When I call the BIOS function, it will correctly identify and load my GDT and IDT, however, when it attempts to jump to protected mode, it triple-faults. I pulled up the Bochs source code for rombios.c and found the assembly, and mentally traced it to the faulting line. I honestly have no idea where to go from here in terms of debugging because the error from the log doesn't make sense to me. I do know that DS/ES/SS are not set after the BIOS function call, and they should be, but I don't know what's failing here.
I appreciate any help or direction you all can give me.
stage2 code:
Code: Select all
org 0x7E00
bits 16
; --- Snip ---
pmode_switch_table:
; Null descriptor
dq 0
; GDT pointer
dw 0x3F
dw gdt
dd 0
; IDT pointer
dw 0x100
dw idt
db 0
db 0xF2
dw 0
; DS
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10010010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
; ES
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10010010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
; SS
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10010010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
; CS
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10011010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
; Scratch CS
dq 0
gdt:
; Null descriptor
dq 0
; Kernel code descriptor
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10011010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
; Kernel data descriptor
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10010010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
; User code descriptor
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 11111010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
; User data descriptor
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 11110010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10010010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10010010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
dw 0xFFFF ; Limit (low)
dw 0 ; Base (low)
db 0 ; Base (middle)
db 10011010b ; Access
db 11001111b ; Granularity
db 0 ; Base (hi)
idt:
times 32 dq 0
; --- Snip ---
; Enable protected mode
mov bh,32
mov bl,40
mov si,WORD pmode_switch_table
mov ah,0x89
cli
int 15h
xchg bx,bx ; ----- Never reaches here -----
Code: Select all
4007 case 0x89:
4008 // Switch to Protected Mode.
4009 // ES:DI points to user-supplied GDT
4010 // BH/BL contains starting interrupt numbers for PIC0/PIC1
4011 // This subfunction does not return!
4012
4013 // turn off interrupts
4014 ASM_START
4015 cli
4016 ASM_END
4017
4018 set_enable_a20(1); // enable A20 line; we're supposed to fail if that fails
4019
4020 // Initialize CS descriptor for BIOS
4021 write_word(ES, regs.u.r16.si+0x38+0, 0xffff);// limit 15:00 = normal 64K limit
4022 write_word(ES, regs.u.r16.si+0x38+2, 0x0000);// base 15:00
4023 write_byte(ES, regs.u.r16.si+0x38+4, 0x000f);// base 23:16 (hardcoded to f000:0000)
4024 write_byte(ES, regs.u.r16.si+0x38+5, 0x9b); // access
4025 write_word(ES, regs.u.r16.si+0x38+6, 0x0000);// base 31:24/reserved/limit 19:16
4026
4027 BX = regs.u.r16.bx;
4028 ASM_START
4029 // Compiler generates locals offset info relative to SP.
4030 // Get BX (PIC offsets) from stack.
4031 mov bx, sp
4032 SEG SS
4033 mov bx, _int15_function.BX [bx]
4034
4035 // Program PICs
4036 mov al, #0x11 ; send initialisation commands
4037 out 0x20, al
4038 out 0xa0, al
4039 mov al, bh
4040 out 0x21, al
4041 mov al, bl
4042 out 0xa1, al
4043 mov al, #0x04
4044 out 0x21, al
4045 mov al, #0x02
4046 out 0xa1, al
4047 mov al, #0x01
4048 out 0x21, al
4049 out 0xa1, al
4050 mov al, #0xff ; mask all IRQs, user must re-enable
4051 out 0x21, al
4052 out 0xa1, al
4053
4054 // Load GDT and IDT from supplied data
4055 SEG ES
4056 lgdt [si + 0x08]
4057 SEG ES
4058 lidt [si + 0x10]
4059
4060 // set PE bit in CR0
4061 mov eax, cr0
4062 or al, #0x01
4063 mov cr0, eax
4064 // far jump to flush CPU queue after transition to protected mode
4065 JMP_AP(0x0038, protmode_switch)
4066
4067 protmode_switch:
4068 ;; GDT points to valid descriptor table, now load SS, DS, ES
4069 mov ax, #0x28
4070 mov ss, ax
4071 mov ax, #0x18
4072 mov ds, ax
4073 mov ax, #0x20
4074 mov es, ax
4075
4076 // unwind the stack - this will break if calling sequence changes!
4077 mov sp,bp
4078 add sp,#4 ; skip return address
4079 popa ; restore regs
4080 pop ax ; skip saved es
4081 pop ax ; skip saved ds
4082 pop ax ; skip saved flags
4083
4084 // return to caller - note that we do not use IRET because
4085 // we cannot enable interrupts
4086 pop cx ; get return offset
4087 pop ax ; skip return segment
4088 pop ax ; skip flags
4089 mov ax, #0x30 ; ah must be 0 on successful exit
4090 push ax
4091 push cx ; re-create modified ret address on stack
4092 retf
Code: Select all
00016497081i[BIOS ] Booting from 0000:7c00
00016514660e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
00016514660e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00016514660e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00016514660i[CPU0 ] CPU is in protected mode (active)
00016514660i[CPU0 ] CS.d_b = 32 bit
00016514660i[CPU0 ] SS.d_b = 16 bit
00016514660i[CPU0 ] EFER = 0x00000000
00016514660i[CPU0 ] | RAX=0000000060000011 RBX=0000000000002028
00016514660i[CPU0 ] | RCX=0000000000000003 RDX=0000000000000000
00016514660i[CPU0 ] | RSP=0000000000007bcb RBP=0000000000007bdf
00016514660i[CPU0 ] | RSI=00000000000e7e1c RDI=000000000000ffac
00016514660i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00016514660i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00016514660i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00016514660i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00016514660i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00016514660i[CPU0 ] | SEG selector base limit G D
00016514660i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00016514660i[CPU0 ] | CS:0038( 0007| 0| 0) 00000000 ffffffff 1 1
00016514660i[CPU0 ] | DS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00016514660i[CPU0 ] | SS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00016514660i[CPU0 ] | ES:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00016514660i[CPU0 ] | FS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00016514660i[CPU0 ] | GS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00016514660i[CPU0 ] | MSR_FS_BASE:0000000000000000
00016514660i[CPU0 ] | MSR_GS_BASE:0000000000000000
00016514660i[CPU0 ] | RIP=0000000000004e22 (0000000000004e22)
00016514660i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00016514660i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00016514660p[CPU0 ] >>PANIC<< exception(): 3rd (13) exception with no resolution
00016514660e[CPU0 ] WARNING: Any simulation after this point is completely bogus !
00016514660p[CPU0 ] >>PANIC<< Entering to shutdown state still not implemented
Code: Select all
Global Descriptor Table (base=0x0000000000007e5c, limit=63):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, 32-bit
GDT[0x02]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
GDT[0x03]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, 32-bit
GDT[0x04]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
GDT[0x05]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
GDT[0x06]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
GDT[0x07]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Accessed, 32-bit
Code: Select all
Interrupt Descriptor Table (base=0x0000000000007e9c, limit=256):
IDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
IDT[0x01]=??? descriptor hi=0x00000000, lo=0x00000000
...
IDT[0x1e]=??? descriptor hi=0x00000000, lo=0x00000000
IDT[0x1f]=??? descriptor hi=0x00000000, lo=0x00000000
Edit: I found the pmode_switch_table layout both in RB's Interrupt List, and a PDF found here: http://www.frontiernet.net/~fys/docs/FrstStps.pdf (pg. 329)