Page 1 of 1

loading the kernel....

Posted: Tue Aug 06, 2002 2:56 pm
by frank
Hi,

I've a program which reads in 1 sector of the disk, then switches to pmode and then should jump to my 32 bit c kernel :)

It works fine with a 16 bit kernel (without the pmode switching then ;))
Pmode switching also works fine...
only the jumping does not work fine..

I first jumped like this:
jmp 0x0000:0x0800
(it's loaded into 0x8000)
But since pmode doesn't support segment adressing I decided to put it in the gdt table

--
jmp kerneladdr
--
kerneladdr equ $-gdt
dw 0ffffh
dw 0h
db 80h
db 09ah
db 0cfh
db 0h
--


But that also doesn't work.
How do I get this working?

Re:loading the kernel....

Posted: Tue Aug 06, 2002 3:24 pm
by crazybuddha
Supposing that you understand what the GDT is, when you switch to pmode, the value in any segment register is a "selector" (i.e. an index) into this table. Say you have three entries in the GDT: null, pmcode, and pmdata. The top 13 bits of the selector are the actual index, so 0x08 is 1000b. That is, this selects the #1 entry in the table (null is entry 0).

so when you try to do a far jmp, CS will be the selector and you specify your offset. Supposing the base address in the descriptor is 0, then for our GDT above, it would look like

jmp dword 0x08:main32

BITS 32
main32:
; you will be here now

But there is one other gotcha. Since this code is somewhere in memory (whereever you put it), you need the offsets to be accurate. The easiest way to do this (in NASM) is with ORG. So if the start of this entire file is 0x600, then you would use ORG 0x600. This will add this amount to each of the offsets, including the 16-bit code that precedes this jmp etc.

Re:loading the kernel....

Posted: Wed Aug 07, 2002 3:26 am
by frank
I tried to jump like this:
jmp dword 0x08:0x08000
(the code is located at 0x0000:0x08000)

The first entry looks like this:
---
codesel equ $-gdt
code_gdt
dw 0ffffh
dw 0h
db 0h
db 0h
db 09ah
db 0cfh
db 0h
---
Which is 0x0000 (I think)

But it reboots, instead of jumping to the memory address.
This is what the kernel looks like:
--
int main()
{
while (1)
{
}
}
--

How do I fix this?

Re:loading the kernel....

Posted: Wed Aug 07, 2002 5:32 am
by crazybuddha
the first entry is always null. Make three entries -- null, code, and data -- and you will save yourself some grief.

And the interface with the C code has additional perils. Stick to assembly until you get this worked out.

Re:loading the kernel....

Posted: Wed Aug 07, 2002 6:03 am
by frank
ok, jumped to the kernel like this (jmp dword 0x08:0x08000)

This is what the gdtr is like
--
gdtr
dw gdt_end-1
dd gdt
gdt
nullsel equ $-gdt
gdt0
dd 0
dd 0
codesel equ $-gdt
dw 0ffffh
dw 0h
db 0h
db 09ah
db 0cfh
db 0h
datasel equ $-gdt
dw 0ffffh
dw 0h
db 0h
db 092h
db 0cfh
db 0h

gdt_end
--

assembly code:
--
org 8000h
jmp main
main: jmp main ; this should hang
--


But it doesn't work... (it stil reboots)

Re:loading the kernel....

Posted: Wed Aug 07, 2002 7:44 am
by frank
---
org 07c00h
mov [drive],dl
jmp readkern

readkern:
bits 16
mov ah,0Eh
mov al,'Q'
int 0x10

mov ah,0x02
mov al,1
mov ch,00000000b
mov cl,00000010b
mov dh,00000000b
mov dl,[drive]
mov bx,0x8000 ; to 0x0000:0x08000
int 13h ; read the kernel

; to pmode
;-------------
cli
lgdt[gdtr]
mov eax,cr0
or al,1
mov cr0,eax
jmp dword codesel:0x8000 ; jump to memory addr (does not work)

; the gdt
;------------
gdtr
dw gdt_end-1
dd gdt

gdt
nullsel equ $-gdt
gdt0
dd 0
dd 0
codesel equ $-gdt
dw 0ffffh
dw 0h
db 0h
db 09ah
db 0cfh
db 0h
datasel equ $-gdt
dw 0ffffh
dw 0h
db 0h
db 092h
db 0cfh
db 0h

gdt_end

drive db 0
times 510-($-$$) db 0
sign dw 0xAA55
---

why doesn't the jump to the memory addr work? (it reboots)

Re:loading the kernel....

Posted: Wed Aug 07, 2002 1:00 pm
by frank
YEEEEHAAAH! ;D
I loaded it into 0x0:0x0 (since the memory starts there)
and like I said, it's working.

The code:
----------------------
org 07c00h
mov [drive],dl
jmp readkern

readkern:
bits 16
mov ah,0Eh
mov al,'Q'
int 0x10

mov ah,0x02
mov al,2
mov ch,00000000b
mov cl,00000010b
mov dh,00000000b
mov dl,[drive]
mov bx,0x0 ; this memory place,please :]
int 13h

cli
lgdt[gdtr]
mov eax,cr0
or al,1
mov cr0,eax
jmp dword codesel:0x0

gdtr
dw gdt_end-1
dd gdt
gdt
nullsel equ $-gdt
gdt0
dd 0
dd 0
codesel equ $-gdt
dw 0ffffh
dw 0h
db 0h
db 09ah
db 0cfh
db 0h
datasel equ $-gdt
dw 0ffffh
dw 0h
db 0h
db 092h
db 0cfh
db 0h

gdt_end

drive db 0
times 510-($-$$) db 0
sign dw 0xAA55
---------------------

(C source is the same, also works with my small assembly source)
Feel free to use, aslong as you change it a bit so that I won't recognize it :)

TNX!

Anyway, I'm still wondering why loading it to 0x8000 did not work...