IDT-Gates fail in user-mode
Posted: Sun Apr 26, 2009 4:00 am
Hi,
I'm a kernel-dev newbie and experimenting with user-mode at the moment. I'm using the IRET-method to enter user-mode. It seems to work but when I trigger an exception I get
a triple-fault. I tried to change the IDT-Gate attributes but it didn't help.
In kernel mode, I can succesfully raise an exception.
Below, I have slapped together a minimal bootloader to reproduce the problem. It sets up the IDT in protected mode and then goes to user mode to raise an exception. (divide by zero). It then triple-faults instead of calling the "isr" procedure.
I'm really stuck, so maybe somebody here can help me...
Bye,
Zoomby
I'm a kernel-dev newbie and experimenting with user-mode at the moment. I'm using the IRET-method to enter user-mode. It seems to work but when I trigger an exception I get
a triple-fault. I tried to change the IDT-Gate attributes but it didn't help.
In kernel mode, I can succesfully raise an exception.
Below, I have slapped together a minimal bootloader to reproduce the problem. It sets up the IDT in protected mode and then goes to user mode to raise an exception. (divide by zero). It then triple-faults instead of calling the "isr" procedure.
I'm really stuck, so maybe somebody here can help me...
Bye,
Zoomby
Code: Select all
[BITS 16] ;Tells the assembler that its a 16 bit code
[ORG 0x7C00] ;Origin, tell the assembler that where the code will
start:
.read:
mov ax, 0 ; ES:BX = 0000:8000h
mov es, ax ;
mov bx, 8000h ;
mov ah, 2 ; Load data
mov al, 16 ; Read 16 sectors
mov ch, 0 ; Cylinder = 0
mov cl, 2 ; Sector = 2
mov dh, 0 ; Head = 0
;mov dl, 0 ; Drive = A:
int 13h ;
jc .read ; Failed -> Try again
cli
lgdt [gdtr]
mov eax, cr0
or al, 1
mov cr0, eax
jmp SYS_CODE_SEL:protectedMode
[BITS 32] ; All code from now on will be 32-bit
isr:
mov byte [0xB8000],'!'
.hang: jmp $
iret
protectedMode:
mov ax, SYS_DATA_SEL ; Update the segment registers
mov ds, ax ; To complete the transfer to
mov es, ax ; 32-bit mode
mov ss, ax
;Setup IDT
mov word [idt],isr ;set ISR
lidt [idtr]
;Goto user mode
mov ax,USER_DATA_SEL
mov ds,ax
mov es,ax
mov eax,esp
push 0x23
push eax
pushfd
push 0x1B
push userMode
iretd
userMode:
mov eax,0
div eax
mov byte [0xB8000],'U'
jmp userMode
; -----------------------------------------------
; GDT
; -----------------------------------------------
gdtr:
dw gdt_end - gdt - 1 ; GDT limit
dd gdt ; GDT base
gdt:
times 8 db 0 ; NULL Descriptor
SYS_CODE_SEL equ $-gdt
dw 0xFFFF ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0x9A ; type = present, ring 0, code, non-conforming, readable
db 0xCF ; page granular, 32-bit
db 0 ; base 31:24
SYS_DATA_SEL equ $-gdt
dw 0xFFFF ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0x92 ; type = present, ring 0, data, expand-up, writable
db 0xCF ; page granular, 32-bit
db 0 ; base 31:24
USER_CODE_SEL equ $-gdt
dw 0xFFFF ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0xFA ; type = present, ring 3, code
db 0xCF ; page granular, 32-bit
db 0 ; base 31:24
USER_DATA_SEL equ $-gdt
dw 0xFFFF ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0xF2 ; type = present, ring 3, data
db 0xCF ; page granular, 32-bit
db 0 ; base 31:24
gdt_end:
; -----------------------------------------------
; IDT
; -----------------------------------------------
idtr:
dw idt_end - idt - 1 ; IDT limit
dd idt ; IDT base
idt:
IDT_GATE1:
dw 0 ; offset low
dw SYS_CODE_SEL ; selector
db 0 ; zero
db 0x8F ; attributes
dw 0 ; offset hight
idt_end:
TIMES 510-($-$$) DB 0 ;Fill the rest of sector with 0
DW 0xAA55 ;Add boot signature at the end of bootloader