Page 1 of 1

IDT-Gates fail in user-mode

Posted: Sun Apr 26, 2009 4:00 am
by Zoomby
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

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


Re: IDT-Gates fail in user-mode

Posted: Sun Apr 26, 2009 5:54 am
by neonek
Hi!
As far as I know you need at least one TSS to do context switch between kernel and userspace. Without it you will get faults. Look at JamesM kernel tutorial for more info.

Regards,
Mark

Re: IDT-Gates fail in user-mode

Posted: Sun Apr 26, 2009 8:12 am
by Zoomby
Thanks Mark! :D

Setting up a TSS solved the problem!

What I find a bit strange about James' tutorial:

Code: Select all

   u32int base = (u32int) &tss_entry;
   u32int limit = base + sizeof(tss_entry);
Isn't the limit of the GDT entry just the size of the TSS Structure? What does he want to achieve with by the base address to the limit?

Re: IDT-Gates fail in user-mode

Posted: Sun Apr 26, 2009 8:41 am
by JamesM
Zoomby wrote:Thanks Mark! :D

Setting up a TSS solved the problem!

What I find a bit strange about James' tutorial:

Code: Select all

   u32int base = (u32int) &tss_entry;
   u32int limit = base + sizeof(tss_entry);
Isn't the limit of the GDT entry just the size of the TSS Structure? What does he want to achieve with by the base address to the limit?
No, the limit is the maximum address that is a member of the TSS structure, which is the base address plus the structure size.

Re: IDT-Gates fail in user-mode

Posted: Mon Apr 27, 2009 12:39 am
by xyzzy
Incorrect, the Intel manuals say that the Limit field specifies the size of the segment, not the base of the segment plus its size.

Re: IDT-Gates fail in user-mode

Posted: Mon Apr 27, 2009 5:16 am
by JamesM
AlexExtreme wrote:Incorrect, the Intel manuals say that the Limit field specifies the size of the segment, not the base of the segment plus its size.
After reading them again, it certainly seems that they agree with you.

Re: IDT-Gates fail in user-mode

Posted: Mon Apr 27, 2009 10:23 am
by Zoomby
Thanks for checking that!