Page 1 of 1

Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 8:04 am
by VladSharp
Hi,

As it's my first post - I should introduce myself. My name is Vladimir, currently in Year 12 at college in the UK. All of my assembler knowledge is 3 days old (and no older) and I am tinkering away at an attempt to run a "Hello, world" example in C++ using my own boot loader and from the hard drive.

I want to keep things simple - the kernel is located at the first sector on the hard drive (LBA mode) and I am guessing that the bootloader can use the int 0x13 to read a couple of sectors from the first "device" and in that way load the kernel. Ok, I'm talking a kernel that prints "hello" from asm in real mode but it will be a start.

However, here is my asm bootloader (512 bytes):

Code: Select all

; Set the "standard" boot loader location to our current one
[ORG 0x7c00]
        jmp start               ;Jump to start, sets CS, the code segment pointer

start:
        xor ax, ax              ;Sets AX to 0 (why can't we load 0 into ax?)
        mov ds, ax              ;Initialises DS with AX
        jmp run                 ;Starts running properly

run:
        ;Clear the screen
        mov ax, 3               ;Moves 3 into AX, sets text mode to 3
        int 0x10                ;Calls the interrupt

        mov si, msg             ;Loads start message into SI
        call print              ;Print the message

        ;Set up stack
        cli                     ;Clear interrupts
        mov ax, 0x9000          ;Stack is at 9000h (9000:0000)
        mov ss, ax              ;Init
        mov sp, 0               ;Clear stack pointer
        sti                     ;Enable interrupts again

   call loadkrnl      ;Calls the kernel loader

loadkrnl:
   mov ah, 0x2      ;Read sectors into memory (arg for int 13h)
   mov al, 0x1      ; number of sectors to read - 1
   mov ch, 0x0      ; cylinder number
   mov cl, 0x1      ; sector number
   mov dh, 0x0      ; head number
   mov dl, 0x0      ; driver number
   mov bx, 0x7000      ; offset to ES -- linear 0x7000

   int 0x13      ;Call the disk interrupt

   mov si, gsf
   call print

hang:
    jmp hang

print:
        ;Load the string
        lodsb                   ;Loads a string (a byte at address DS:(E)SI into AL)
        or al,al                ;Performs a bitwise OR on the contents of AL and stores them in AL
        jz done                 ;Jumps to done: (jump if zero, i.e. if AL is 0)

        ;Prepare for the interrupt sending
        mov ah, 0x0E            ;Set the correct flag
        int 0x10                ;Call the interrupt
        jmp print               ;Jump back
done:
        retn                    ;Return to caller

msg db 'Starting Boot process...', 13, 10, 0
gsf db 'Got so far...', 13, 10, 0

    times 510-($-$$) db 0       ;fill with zeroes the first 512 bytes of boot sector
    db 0x55                     ;End with a (deprecate?) signature that this is a boot loader
    db 0xAA                     ;ibid.

However, what I don't understand - is how to jump to executing what i've just loaded, whether, when protected mode is entered, I'd be able to load more than 1MB.

When I run this with "qemu boot2.bin -hda disk.img" (where disk.img is a file which represents the file system but has only the kernel binary at the start of it) - it doesn't get to finish with ("Got so far") but when the -hda flag is removed it reads(?) successfully...

Is it possible to print the contents of the memory once the segments are loaded?

Many thanks,
Vladimir

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 8:46 am
by Ryu
For the first hard drive start at 80h in drive number of INT 13h, AH=2h, and floppy controllers start at 0. Its also wise to set ES segment before using it. If you want to save the kernel at linear 7000h, make sure ES should be 0 or use ES=700h with a 0 offset (prevents you from crossing segment boundry). Also the boot strap is located at 7C00h linear so if you were to load kernel at 7000h, you have 7000h - 7BFFh (3KB) for kernel.

Another thing worth mentioning, the BIOS does not always set CS=7C0h when entering the bootstrap. Which can be fixed by doing a far jmp 7C0:offset to ensure CS=7C0h to stay correctly with the ORG 0x7c00. Ive actually found some systems that left the CS=F000h which BIOS previously was using and would be wrong if you assume CS=7C0h when you start doing calls.

To run the kernel, you also do a far jump or a retf using appropiate segments that the kernel' base is compiled to run on to keep things organized. If your kernel is compiled as ORG 0 do a far jump 000:7000h, or if the kernel ORG 7000h then do far jump 700:0000h, so getting the riff? :P

edit: sorry I got that backwards, If your kernel is compiled as ORG 0 do a far jump 700:0000h, or if the kernel ORG 7000h then do far jump 000:7000h. ORG 7C00h you should have CS=0.

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 11:31 am
by VladSharp
How would you do a far jump in that case then? Not literally, but since you can't use [ORG ] (the code you put before doesn't get executed) - how do you ensure everything is loaded at 0x7c00h? I mean, the far jump would be of the kind "jmp word 0x0000:0x7c00", wouldn't it?

After the interrupt 0x13 it seems that the code still hangs (i.e. doesn't get around to printing what it should) - even when "mov dl, 0x80"

Thank you

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 12:13 pm
by Ryu
A far jump is not relative to any segement except you tell it what segment:offset. How do you ensure everything is loaded at 7C00h? Its by standard that if your bootloader is running its going to be at the linear address 7C00h but the CS segment can be differnt as I found it. I suppose you can check the signature AA55h at 7C00h + 510 bytes but I don't think its necessary. Basically if you have gone pass the first print call which is displaying "'Starting Boot process..." then your CS segment is up right. BUT as I mention it may but be CS=0. To enforce a CS=0 you can do this after jmping to start: (I dont use nasm and not sure this is the correct syntax)


jmp start
start:
jmp word 0x0000:offset set_cs_jmp
set_cs_jmp:
....


I've also noticed that you set ss=900h sp=0, after your first call to print, theres couple things very bad about this. SP is your stack pointer and subtracts when you push or call. A call will push the ip onto stack for return pointer. SP will wrap around to 0FFFEh and I dont think its attentional using the stack space 9000h-18FFFh (odd?). I'm not even sure if the processor will generate an exception on those cases. Normally you would do something like a 900:800h so your stack is 9000h-97FFh. After my example above you should right away set your DS,ES,SS,SP.

I've also noticed that you didnt set SS=900h but SS=9000h which will most likely corrupt some reserved areas:

mov ax, 0x9000 ;Stack is at 9000h (9000:0000)
mov ss, ax ;Init
mov sp, 0 ;Clear stack pointer


If SP is wrapped around the first push or call would end up at 9FFFEh, and 9FC00h-9FFFFh is usually reserved for extended BIOS data.

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 12:58 pm
by VladSharp
Thanks. So I assume you mean

A) something like

Code: Select all

   jmp start
start:
   
   jmp 0x0000:set_cs_jmp

set_cs_jmp:
after the ORG

B) For the stack - does that mean I should set my stack segment to 9000h and the stack pointer to 07FF? Then, I assume, (if memory goes from high to low ;) ) that would be 34817 bytes - i.e. a 34K stack?

Correct me if I'm blatantly wrong... :-\

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 1:14 pm
by Ryu
Hehe. A) I suppose if that assembles okay, and B) if the area 9000h-97FFh your after for stack you should set SS to 900h and SP to 800h, sorry if I've confused you. To convert a segment like SS=900h to linear you shift left 4 times = 9000h or easier, you just add a zero in heximal. The area from address 9000h to 97FFh = a 2KB stack (800h which happends to be your starting SP value!)

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 1:33 pm
by VladSharp
Yes - it seems I was substracting away in the wrong direction...

But then, if I wanted my stack to be bigger (16 K), I would use SS 0x9000 and SP 0xD000? Or do I still not get it?

(The calculation goes you multiply 16*1024 in decimal, conv to hex 4000h and then add 9000h - right?)

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 1:50 pm
by Ryu
If its subtracting its going the right way. 9000:D000h wouldn't be 16k stack. The last comment with the calculation is right 4000h which should be set to SP if you want a 16KB stack. So you want SS 0x9000 and SP 4000h (using from 90000h to 93FFFh).

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 1:55 pm
by VladSharp
Ah, so the SP is the offset from the SS... Obvious :-X Thank you

Re:Qemu + Disk image + Boot loader (q)

Posted: Sat May 27, 2006 5:53 pm
by Dex4u
The code from bootprog may help as its well commened, and can load a exe or com file from floppy or hdd, come with nasm code.
http://alexfru.chat.ru/epm.html#bootprog