jmping into kernel

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Hamza

jmping into kernel

Post by Hamza »

Hi,
Im a newbie os developer and after long studies I have my hello world printing bootsector and now I want to jump into my kernel. I wrote a simple kernel that just prints "Im in kernel now" and halts. But I couldnt manage to jump into my kernel. Im sure my kernel is working fine.(I tried with another boot sector.). I load my kernel from disk at 0:1000 adress but couldnt find how to jmp there. I examine nearly 10 oses but most of them jmps after switching pmode.

jmp CodeSel:KernelPos

My bootsector is just write "hello world" to video memory and loads kernel.Nothing more. Some oses use raw code of commands.

Code: Select all

db 0edh
dw 0, KernelPos
I couldnt make both working. Ill be glad if some one explain how to jmp kernel at 0:1000h? I need just a line of code.. (No A20 line, no pmode, ...)(Im using Nasm)
slacker

Re:jmping into kernel

Post by slacker »

u dont need to use a long jump...

just:

jmp offset
Hamza

Re:jmping into kernel

Post by Hamza »

Code: Select all

lReadDisk:
    mov ax, 0
    mov es, ax
    mov bx, KERNELPOSITION                  ; es:bx
    mov ah, BIOS_READDISK
    mov al, KERNELLENGTH
    mov ch, 0                               ; Track
    mov cl, 2                               ; Start sector
    mov dh, 0                               ; Head
    int BIOSINTERRUPT

    jmp KERNELPOSITION
Nope... didnt work..
Tim

Re:jmping into kernel

Post by Tim »

You'll still need a far jmp:

Code: Select all

jmp 0:KERNELPOSITION
The Pro from Dover

Re:jmping into kernel

Post by The Pro from Dover »

Given the code below, the problem isn't necessarily in the transition itself; there are some possible problems that could cause the disk read to silently fail. First, the code given does not doesn't set the value of DL, which is the parameter which indicates which drive to read; I am assuming it is set earlier on, but since it isn't shown, I have no way of being sure. Similiarly, the code as shown does not initialize the disk controller, though it presumably is earlier on. The real problem is that this code doesn't check for an error code to make sure that the disk reads properly. This should be a simple test and loop on the value of carry flag, but there's a catch: the FDC shoud be reset before each attempt.

The following code should ensure that it works correctly:

Code: Select all

lResetDisk:
     mov dl, [BootDrive]  ; assumes you saved the Disk ID to BootDrive earlier
     xor ah, ah          ; clear AH  
     mov al, BIOS_RESETDISK
     int BIOSINTERRUPT
     jc short lResetDisk  ; if there is an error, loop and try again

lReadDisk:
    mov ax, 0
    mov es, ax
    mov bx, KERNELPOSITION                  ; es:bx
    mov ah, BIOS_READDISK
    mov al, KERNELLENGTH
    mov ch, 0                              ; Track
    mov cl, 2                              ; Start sector
    mov dh, 0                              ; Head
    int BIOSINTERRUPT
    jc short lResetDisk  ; if there is an error, reset the FDC and try the read again

    jmp KERNELPOSITION
Note that this code, as written, will loop indefinitely until the drive works; this could be a serious problem with a very flakey FDD or disk.

As for the jump itself, it is not technically necessary to use a FAR jump if the kernel offset is in the same segment as that of the boot loader; however, if this is the case, you'll have to make sure that the kernel code itself is [tt][[ORG KERNELPOSITION]][/tt], or else the label offsets for the kernel code will be wrong and the code will fail. I would argue that it wiser to set ES to a convienent segment base, use [tt][[ORG 0x0000]][/tt] in the kernel code, load the kernel at ES:0x0000, and JMP FAR th that location (or, as I do in my code, push ES and then 0x000 and RETF).

If it helps at all, you can see an early version of my own boot loader in this thread. I hope this helps you work out the problem. Note that in this version, rather than repeatedly trying to get it to work, it simply fails and prints an error, which is acceptable but not very fault-tolerant.
Hamza

Re:jmping into kernel

Post by Hamza »

yes.. I just skip those parts to make my problem simpler.. But as there could be another problem, I mean perhaps my problem is not just jumping, because Tims advice "jmp 0:KERNELPOSITION also not worked, here is my boot code..:

Code: Select all

BootCode:
    mov [BootDrive], dl                     

    mov ax, cs
    mov ds, ax
    mov es, ax
    mov fs, ax

    cli
    mov ax, 1D0h
    mov ss, ax
    mov sp, 0200h                            

    sti

lLoadKernel:
lResetFloppy:
    mov ah, BIOS_RESETDISK                   
    mov dl, [BootDrive]
    int BIOSINTERRUPT
    jc lResetFloppy

lReadDisk:
    mov ax, 0
    mov es, ax
    mov bx, KERNELPOSITION                  
    mov ah, BIOS_READDISK
    mov al, KERNELLENGTH
    mov ch, 0                               
    mov cl, 2                               
    mov dh, 0                               
    int BIOSINTERRUPT
    jc lResetFloppy

lStopMotor:
    mov dx, FLOPPYCONTROLLER
    mov al, FLOPPY_STOPMOTOR
    out dx, al

    jmp 0:KERNELPOSITION
but still not managed to jmp into my kernel....:(

my kernel entry is:

Code: Select all

[BITS 32]

[extern _main]
[global _kernelmain]

_kernelmain:
    jmp _main
    cli
    hlt
I think the problem is due to the first line of my code. Sould [BITS 32] be [BITS 16]?? but when I change code like that, nasm gives an error:
COFF format doesnt support 16-bit relocations..
I dont know how to handle this..
The Pro from Dover

Re:jmping into kernel

Post by The Pro from Dover »

Hamza wrote:my kernel entry is:

Code: Select all

[BITS 32]

[extern _main]
[global _kernelmain]

_kernelmain:
    jmp _main
    cli
    hlt
I think the problem is due to the first line of my code. Sould [BITS 32] be [BITS 16]?? but when I change code like that, nasm gives an error:
COFF format doesnt support 16-bit relocations...
I dont know how to handle this..
Ah, this explains a great deal. What is happening is that you are trying to run 32-bit protected mode code while the system is still in real mode. What you'll need to do is switch from real mode to p-mode before calling your C code, either in the boot loader or as part of a second stage loader (probably the better option). It is important that this be done before you use any C/C++ code at all, at least using DJGPP, since gcc only generates 32-bit p-mode object code. All the assembly code before the switch must be [tt][[BITS 16]][/tt]; all of the code after the switch must be [tt][[BITS 32]][/tt].

Also, you must remember that you cannot use the standard I/O library functions or objects ([f|s|v|vs]printf(), [f]putc(), cin, cout) , as the DJGPP versions use system calls specific to DPMI; further, you cannot use the real mode BIOS functions when in p-mode. You will have to write the basic I/O routines yourself for when you are running in p-mode. You can use the BIOS in the boot loader, at least prior to switching to p-mode, and using that to print status messages can be a useful debugging tool (as you can see in my own code).

There are several good p-mode tutorials at OSRC. Searching through the archives of this forum should also bring up several threads on the subject. The switch to p-mode itself is not too difficult, but it requires a great deal of setup work both before and after the transition point in order to work correctly.

If you mean to write your own boot loader from scratch, I would recommend trying to get a simple real-mode all-assembly second-stage test working first (take a look at mine for an example), to make sure that your code jumps to it properly, before tackling the p-mode transition. However, you would probably be better off using an existing boot loader like GRUB, which will take care of these messy details for you and let you get on with writing your kernel. Just a suggestion.
Hamza

Re:jmping into kernel

Post by Hamza »

No ı just want to code a real mode kernel...
The Pro from Dover

Re:jmping into kernel

Post by The Pro from Dover »

Ah, I see. While this is probably a lot easier in some regards, it does present some problems, with the most notable being that, as I said earlier, gcc only produces 32-bit protected mode object code. To use C for the kernel, you'll need to find (or write) a compiler that will output real mode binaries. Furthermore, most such compilers use their own approaches towards segment handling that may or may not work with you OS's memory model.

Also, while you'll be able to use the BIOS routines for simple I/O, you'll still need to code the standard functions yourself to work with the system calls for your OS.
Hamza

Re:jmping into kernel

Post by Hamza »

The Pro from Dover wrote: gcc only produces 32-bit protected mode object code.
Ooppss...Is gcc(under DJGPP) generates just 32 bit codes?? Im planning to boot and jump to my kernel (written in C), and change mode in my asm functions called from C Code. If gcc just generates just 32 bit codes, then I can not do that. Indeed what am I looking for is generating 16bit codes, jmping pmode and then generating 32 bit codes.(like in Alex Frounse's pmode tutorials. He jumps to pmode in C code. It means that compile generate 16 bit codes before jmping and 32 bit code after jmping for just one C code. Actually I think he uses tcc and nasm). And also Im planning to go into unreal mode and work at there, so I wonder if unreal mode is 32 bit. So I can not do this by using gcc.Ohh.. what a pity... So I have to code whatever I ll do in real mode by using assembler and then switch pmode and use c, and when I want to switch unreal mode, I have to jump assembler code again. Isnt there an easy way to use c for all these??

And I have a few questions.
1. Looking for a good tutorial for unreal mode. As I understand that unreal mode is just like real mode with capable of whole memory, so I can use bios and video interrupts at there, cant I?

2. If gcc can generate 16 bit codes, after switching to protected mode and after switching to unreal mode, I have to make a far jump, how can I do this?(In alex tutorial, he made this by jumping an asm function and do this in a weird way)

3. I know c and c++. And for boot sector I have read Nasm tutorials, but if gcc not generates 16 bit codes and if my aims to be on eyes, I have to learn assembler well..Or change my c compiler...

4. I can even not jmp my 16 bit nasm coded kernel, is there an example os written in nasm??

and the link you give doesnt work..
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:jmping into kernel

Post by Pype.Clicker »

Hamza wrote:
The Pro from Dover wrote: gcc only produces 32-bit protected mode object code.
Ooppss...Is gcc(under DJGPP) generates just 32 bit codes??
Not exactly. There's an ugly option (like asm __volatile__(".bits 16")) that can be used to force GCC prefixing every operations with db66 and db67 so that its 32bits code can be executed in 16bits segments (including in realmode, afaik).
like in Alexei A. Frounze's pmode tutorials. He jumps to pmode in C code. It means that compile generate 16 bit codes before jmping and 32 bit code after jmping for just one C code. Actually I think he uses tcc and nasm).
Alexei actually do use TCC, which is a 16 bits compiler, and if he enters protected mode, you'll notice his code segment doesn't have the "BIG" bit and has a limit of 64Kb -- therefore it's just a protected 16bits segment and can execute TCC's 16bits code.
And also Im planning to go into unreal mode and work at there, so I wonder if unreal mode is 32 bit.
unreal mode is protected 32bits data segment with real 16bits code segment. virtually no compiler will allow you to do this without the help of pragmas, etc. (maybe watcom C++ could handle it).
And I have a few questions.
1. Looking for a good tutorial for unreal mode. As I understand that unreal mode is just like real mode with capable of whole memory, so I can use bios and video interrupts at there, cant I?
get a look at the "Baby Steps" serie in .:QuickLinkz:. Yes, bios is available in unreal mode, but it cannot access high memory, so for instance, you must write to a buffer under 1MB using INT13 and then rep movsb to upper memory.
3. I know c and c++. And for boot sector I have read Nasm tutorials, but if gcc not generates 16 bit codes and if my aims to be on eyes, I have to learn assembler well..Or change my c compiler...
Go for GRUB. it will handle pmode switch and kernel jumping for you if you feed it with ELF files.
You'll have to learn ASM nonetheless if you want to have interrupts because interrupt handlers must be written in ASM (though they can call C functions)
Post Reply