Page 1 of 1

help with GDT/ CODE_SEL

Posted: Fri Jan 02, 2004 12:18 pm
by guest
I know you can find many things about GDTs in the web, but I have only a problem to setup a CODE-Selector.

When I try my boot + kernel with bochs I get the message:

write_virtual_checks(): write beyond limit, r/w ED
>>PANIC<< exception(): 3rd (13) exception with no result


The Status is:


protected mode
CS.d_b = 32 bit
SS.d_b = 32 bit
| EAX=00000008 EBX=00000007 ECX=00000002 EDX=00000000
| ESP=00007ffe EBP=00000000 ESI=00007cc5 EDI=0000ffe4
| IOPL=0 NV UP DI PL NZ NA PE NC
| SEG selector base limit G D
| SEG sltr(index|ti|rpl) base limit G D
| DS:0008( 0001| 0| 0) 00000000 0000ffff 1 1
| ES:0008( 0001| 0| 0) 00000000 0000ffff 1 1
| FS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
| GS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
| SS:0008( 0001| 0| 0) 00000000 0000ffff 1 1
| CS:0010( 0002| 0| 0) 00000000 0000ffff 1 1
| EIP=00001000 (00001000)
| CR0=0x60000011 CR1=0x00000000 CR2=0x00000000
| CR3=0x00000000 CR4=0x00000000
restoring default signal behavior
quit_sim called with exit code 1


My GDT is:

Code: Select all

gdt:
; null descriptor
   dw 0         ; limit 15:0
   dw 0         ; base 15:0
   db 0         ; base 23:16
   db 0         ; type
   db 0         ; limit 19:16, flags
   db 0         ; base 31:24

; data descriptor
DATA_SEL equ $-gdt

   dw 0xFFFF      ; limit 15:0
   dw 0x00         ; base  15:0
   db 0x00         ; base  23:16
   db 0x97         ; access byte: present, ring0, code/data segment, non-executable, conforming, writeable, accessed
   db 0xC0         ; flags: Granularity, 32-bit
   db 0x00         ; base 31:24

; code descriptor
CODE_SEL equ $-gdt

   dw 0xFFFF      ; limit 15:0
   dw 0x00         ; base  15:0
   db 0x00         ; base  23:16
   db 0x9B         ; access byte: present, ring0, code/data segment, executable, non-conforming, readable, accessed
   db 0xC0         ; flags: Granularity, 32-bit
   db 0x00         ; base 31:24

gdt_end:

gdt_desc:
   dw gdt_end - gdt - 1   ; GDT limit
   dd gdt         ; linear address of GDT
The Kernel is OK because I try to start it with bootf02 and it works.

my enter_pmode function is:

Code: Select all

enter_pmode:
   cli

   lgdt [gdt_desc]

   mov eax, cr0      ; enable pmode
   or  eax, 1
   mov cr0, eax

   mov eax, DATA_SEL
   mov ds,   eax
   mov es, eax
   mov ss, eax

   jmp CODE_SEL:0x1000    ; 0x1000 is where the kernel is load

Re:help with GDT/ CODE_SEL

Posted: Fri Jan 02, 2004 5:03 pm
by Slasher
The problem might be somewhere else in the code. It you need help its best to post the entire code.
Besides,
mov es,eax
...
...
are all wrong. they should be
mov es,ax
...
...
...

Re:help with GDT/ CODE_SEL

Posted: Fri Jan 02, 2004 6:33 pm
by Tim
Code Slasher wrote:Besides, mov es,eax are all wrong. they should be mov es,ax
No, this is legal. And mov es, eax saves one byte (the O16 previx) in 32-bit mode. :)

Re:help with GDT/ CODE_SEL

Posted: Sat Jan 03, 2004 7:25 am
by guest
boot.asm:

Code: Select all

[BITS 16]
[ORG 0x7C00]

jmp start         ; jump to the code // if any other things a decleared after this

%include 'gdt.inc'

;new_line    db 10,13
msg_ok      db "OK",10,13,0
msg_failed   db "Failed!!!",10,13,"Halt CPU",0
msg_check_cpu   db "Check if CPU is >= 368...",0
msg_need_368   db "Failed",10,13,"Sorry your CPU must be a 368 or better",0
msg_enable_a20   db "Enable the A20 Gate...",0
msg_load_kernel   db "Load the Kernel...",0
msg_enter_pmode db "Enter Protected Mode...",0

bootdrive db 0

kernel_addr dw 0x1000
read_sectors db 0x02

putstr:
   lodsb         ; load the next character
   or al,al      ; if al = 0 (= character)
   jz short putstrd   ; return
   mov ah, 0x0E      ; function 0x0E (display character)
   mov bh, 0x00      ; current page
   mov bl,   0x07      ; color
   int 0x10      ; call display interrupt
   jmp putstr
putstrd:
   ret

check_cpu:
   mov si, msg_check_cpu   ; tell the user what we're doing
   call putstr
   ; test if 8088/8086 is present (flag bits 12-15 will be set)
   pushf         ; save the flags original value
   xor ah,ah               ; ah = 0
   push ax                 ; copy ax into the flags
   popf                    ; with bits 12-15 clear
   pushf                   ; Read flags back into ax
   pop ax       
   and ah,0f0h             ; check if bits 12-15 are set
   cmp ah,0f0h
   je no386                ; no 386 detected (8088/8086 present)
   ; check for a 286 (bits 12-15 are clear)
   mov ah,0f0h             ; set bits 12-15
   push ax                 ; copy ax onto the flags
   popf
   pushf                   ; copy the flags into ax
   pop ax
   and ah,0f0h             ; check if bits 12-15 are clear
   jz no386                ; no 386 detected (80286 present)
   popf                    ; pop the original flags back
   mov si, msg_ok
   call putstr
   ret                     ; no 8088/8086 or 286, so ateast 386
   no386:
   mov si,msg_need_368     ; tell the user the problem
   call putstr
   cli
   hlt
   jmp $-2
.386

enable_a20:
   cli         ; disable interrupts
   call wait_key_buf   ; wait for kbd buffer to clear
   mov al,0xd1      ; tell it we want to write to output port
   out 0x64,al
   call wait_key_buf   ; wait again for kbd to clear
   mov al,0xdf      ; set desired settings (A20 gate)
   out 0x60,al      ; send value to data reg
   call wait_key_buf   ; wait for kbd to clear
   mov cx,0x10      ; loop count
   kbdwait:
      xor ax,ax   ; do anything
      out 0xe0,ax   ; some mor nonsense
   loop kbdwait            ; loop to waste time

   ;-------------- check if a20 was enabled --------------
   mov al,0xd0
   out 0x64,al      ; tell kbdc we want to read output port
   call wait_key_buf_data   ; wait for data to get in it
   in al,0x60      ; get it
   test al,2      ; test if A20 is on
   jnz a20_on      ; if it is clear, then it is off
   jmp error
   a20_on:
   ret
wait_key_buf:
   xor al,al      ; al = 0
   in  al, 0x64      ; get kbd status
   test al, 2      ; is bit 1 clear?
   jnz wait_key_buf   ; if not wait some more
   ret
wait_key_buf_data:
   xor cx,cx      ; cx = 0
   in al, 0x64      ; get kbd status
   test al, 1      ; is bit 0 clear?
   jz wait_key_buf_data   ; if not wait some more
   ret
load_kernel:
   clc         ; clear the carry flag
   mov ecx, 5      ; try to reset the driver 5 times
   reset_drive:
   xor ax, ax      ; ax = 0
   mov dl, [bootdrive]   ; dl = bootdrive
   int 0x13      ; reset drive
   jnc reset_ok      ; if carry flag = 0
   loop reset_drive   ; else try it again if ecx != 0
   jmp error      ; if ecx = 0 and the reset always failed, halt
reset_ok:
   mov ecx, 5      ; try to read the kernel 5 times
    read_kernel:
   mov ax, [kernel_addr]
   mov es, ax      ; address of the buffer
   mov ah, 0x02      ; function number 2 (read from disk)
   mov al, [read_sectors]   ; number of sectors to read
   mov dl, [bootdrive]   ; set drive
   mov dh, 0x00      ; read/write head number
   mov ch, 0x00      ; number of the track or cylinder (0 = first)
   mov cl, 0x02      ; number of the sector where to start (1 = first)
   xor bx, bx      ; offset of the buffer
   int 0x13
   jnc load_ok      ; if all is ok return
   loop read_kernel   ; try once again if there is an error
   jmp error      ; if ecx = 0 and the read operation always failed, halt
load_ok:   
   ret

enter_pmode:
   cli
   lgdt [gdt_desc]
   mov eax, cr0      ; enable pmode
   or  eax, 1
   mov cr0, eax
   mov eax, DATA_SEL
   mov ds,   eax
   mov es, eax
   mov ss, eax
   jmp CODE_SEL:0x1000
;[BITs 32]   
   cli
   hlt
   jmp $-2
error:
   mov si, msg_failed
   call putstr
   cli
   hlt
   jmp $-2


start:
   cli
   mov [bootdrive], dl   ; save the bootdrive
   mov ax, 0x9000
   mov ss, ax      ; setup the stack at 0x9000
   mov esp, 0x8000      ; set the stack size
   sti
   call check_cpu
.386
   mov si, msg_enable_a20
   call putstr
   call enable_a20
   mov si, msg_ok
   call putstr
   mov si, msg_load_kernel
   call putstr
   call load_kernel   ; load the kernel
   mov si, msg_ok
   call putstr
   mov si, msg_enter_pmode
   call putstr
   call enter_pmode
   cli
   hlt
   jmp $-2
times 510-($-$$) db 0
db 0x55
db 0xAA

Re:help with GDT/ CODE_SEL

Posted: Sat Jan 03, 2004 11:51 am
by Candy
please check up your segment stuff

You load the kernel at 0x1000:0000 and jump to 0x0010:00001000. That doesn't work. Load the kernel to 0x0100:0000 or jump to 0010:00010000.