I'm fairly sure my structures are OK as I've been doing ring 0 task switching using PIT for about 2 months. TSS structure matches the one on the Wiki.
I can jump into user-mode just fine, it's just when an interrupt occurs during user-mode (PIT, exception etc) the OS crashes.
Bochs reports the following error:
Code: Select all
00072527377e[CPU0 ] interrupt(): SS selector null
00072527377e[CPU0 ] interrupt(): SS selector null
00072527377i[CPU0 ] CPU is in protected mode (active)
00072527377i[CPU0 ] CS.mode = 32 bit
00072527377i[CPU0 ] SS.mode = 32 bit
00072527377i[CPU0 ] EFER = 0x00000000
00072527377i[CPU0 ] | EAX=0062bf80 EBX=00004108 ECX=00015000 EDX=00000000
00072527377i[CPU0 ] | ESP=00004a10 EBP=00004a10 ESI=00e2f000 EDI=00e318ae
00072527377i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf sf ZF af PF cf
00072527377i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00072527377i[CPU0 ] | CS:0023( 0004| 0| 3) 00000000 ffffffff 1 1
00072527377i[CPU0 ] | DS:002b( 0005| 0| 3) 00000000 ffffffff 1 1
00072527377i[CPU0 ] | SS:002b( 0005| 0| 3) 00000000 ffffffff 1 1
00072527377i[CPU0 ] | ES:002b( 0005| 0| 3) 00000000 ffffffff 1 1
00072527377i[CPU0 ] | FS:002b( 0005| 0| 3) 00000000 ffffffff 1 1
00072527377i[CPU0 ] | GS:002b( 0005| 0| 3) 00000000 ffffffff 1 1
00072527377i[CPU0 ] | EIP=0005b196 (0005b196)
00072527377i[CPU0 ] | CR0=0xe0000031 CR2=0x00000000
00072527377i[CPU0 ] | CR3=0x0062d000 CR4=0x00000000
Code: Select all
.startNewUserTask:
mov ax, USER_DATASEG ; USER_DATASEG = 0x28 | 11b
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push USER_DATASEG
push DWORD [esp+StateInfo.esp]
pushf
or DWORD [esp], 0x200 ; Enable interrupts
push USER_CODESEG ; USER_CODESEG = 0x23 | 11b
push DWORD [eax+StateInfo.eip]
mov ebp, DWORD [eax+StateInfo.ebp]
mov eax, 0
iret
Code: Select all
.setupTSS:
mov DWORD [TSS0+X86TSS.ebp], ebp
mov DWORD [TSS0+X86TSS.esp0], esp
mov eax, ss
mov WORD [TSS0+X86TSS.ss0], DATASEG
mov WORD [TSS0+X86TSS.ss], USER_DATASEG
mov eax, cr3
mov DWORD [TSS0+X86TSS.cr3], eax
mov ax, GDT_TSS0_ID | 11b
ltr ax
; Done, go idle and wait for interrupts.
sti
.idle:
hlt
jmp .idle
Code: Select all
GDT_TSS0_ID EQU 0x18
gdt_tss0:
.segLimitLow dw 0
.baseAddrLow dw 0
.baseAddrHiLow db 0
.atts db 11101001b
.segLimitAtts2 db 10010000b ; Must have 0s for OR in setup
.baseAddrHiHi db 0
USER_CODESEG EQU 0x20 | 11b ; RPL of 3 for usermode and higher
gdt_userCodeSegment:
.segLimitLow dw 0xFFFF
.baseAddrLow dw 0x0000
.baseAddrHiLow db 0x00
.atts db 11111010b
.segLimitAtts2 db 11011111b
.baseAddrHiHi db 0x00
USER_DATASEG EQU 0x28 | 11b ; RPL of 3 for usermode and higher
gdt_userDataSegment:
.segLimitLow dw 0xFFFF
.baseAddrLow dw 0x0000
.baseAddrHiLow db 0x00
.atts db 11110010b
.segLimitAtts2 db 11001111b
.baseAddrHiHi db 0x00