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?
loading the kernel....
Re:loading the kernel....
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.
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....
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?
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....
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.
And the interface with the C code has additional perils. Stick to assembly until you get this worked out.
Re:loading the kernel....
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)
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....
---
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)
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....
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...
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...