OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 18, 2024 5:26 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: Booting C Kernel with own bootloader
PostPosted: Wed Feb 02, 2011 2:01 pm 
Offline

Joined: Wed Feb 02, 2011 12:30 pm
Posts: 23
Location: Belo Horizonte, Minas Gerais, Brazil
Hello everyone!

I'm developing a small OS that works in protected mode, but executes entirely below 1mb. For acquire this purpose, I've wrote my own bootloader that loads for now, a small kernel of test that print a 'a' on screen.

The main problem is that when I emulate the "OS Project.img" with Virtual box the character 'a' is not printed on screen and nothing happens!
Can anyone give a hand with this?

I'm developing this OS in a Ubuntu system without a floppy drive, using nasm, a i586-elf-gcc compiler and dd command.

bootloader.asm
Code:
;=====================================NASM HEADERS========================================


%define KSEG 0x0800 ; kernel segment
%define KOFF 0x0000 ; kernel offset
%define KSEC 2      ; kernel sector

%define GDT_LOCATION 0x00007E00
%define GDT_SIZE     0x0100

;=========================================================================================

use16

org 0x7C00
jmp 0x0000:start
start:

sti                          ; enable bios interrupts

; read kernel to memory
mov ah, 0x02                 ; interrupt subfunction: read disk
mov dl, 0                    ; drive ( 00h = A: )
mov dh, 0                    ; head
mov ch, 0                    ; cylinder
mov cl, KSEC                 ; sector
mov al, 9                    ; number of sectors to be read
mov bx, KSEG                 ; es:bx points to memory buffer's location
mov es, bx     
mov bx, KOFF                 ; 0x0800:0x0000
int 13h                      ; disk interrupt

use32

cli                          ; disable BIOS interrupt

; initializates GDT
mov  ax, GDT_SIZE         
mov  word[cs:gdtr], ax       ; load GDT size
mov  eax, GDT_LOCATION
mov  dword[cs:gdtr + 2], eax ; load GDT offset
lgdt [gdtr]                  ; load GDT register

; Load GDT entries
mov ebx, dword[cs:gdtr + 2]
mov edx, gdt
mov ecx, 6
fillgdt:
    mov eax, [cs:edx]
    mov [cs:ebx], eax
    add ebx, 4
    add edx, 4
    loop fillgdt

; enter protected mode
mov eax, cr0
or  al, 1
mov cr0, eax

; Load Kernel Code and Data Descriptors
mov ax,0x10
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax

jmp 0x08:0x0000              ; now kernel have control of system

;======================================VARIABLES==========================================


gdtr dw 0x0000     ; GDT size
     dd 0x00000000 ; GDT location

gdt dw 0x0000, 0x0000, 0x0000, 0x0000 ; GDT entry null
    dw 0x004F, 0x9A00, 0x8000, 0xFFFF ; GDT entry kernel code
    dw 0x004F, 0x9200, 0x0500, 0xFFFF ; GDT entry kernel data

;====================================NASM DIRECTIVES======================================

; fill the end of sector with signature's boot
times 510-($-$$) db 0
                 db 0x55
                 db 0xAA


kernel.c
Code:
void kmain ()
{
    unsigned char *videoram = (unsigned char *) 0xb8000;
    videoram[0] = 65;                                     /* character 'A' */
    videoram[1] = 0x07;                                   /* forground, background color. */
   
    for (;;);
}


kernel_linker.ld
Code:
ENTRY (kmain)

SECTIONS
{
    . = 0x00008000;
    .text : { *(.text) }
    . = 0x00000500;
    .data : { *(.data) }
    .bss : { *(.bss) }
}


Compile.sh
Code:
#!/bin/sh
PATH=/usr/local/cross/bin:$PATH

#clean
cd ..
cd Compiled
rm -f "bootloader.bin" "kernel.bin" "kernel.o"
cd ..
cd Image
rm -f "OS Project.img"
cd ..

#make
nasm "Source/boot/bootloader.asm" -f bin -o "Compiled/bootloader.bin"
i586-elf-gcc -o "Compiled/kernel.o" -c "Source/kernel/kernel.c"
i586-elf-ld -T "Source/kernel/kernel_linker.ld" -o "Compiled/kernel.bin" "Compiled/kernel.o"

dd if="Compiled/bootloader.bin" of="Image/OS Project.img" bs=512 count=1 seek=0
dd if="Compiled/kernel.bin"     of="Image/OS Project.img" bs=512 count=9 seek=1
dd if="/dev/zero"               of="Image/OS Project.img" bs=512 count=2870 seek=10


Thank you for your patience.

_________________
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Wed Feb 02, 2011 3:05 pm 
Offline
Member
Member

Joined: Sun Mar 07, 2010 2:12 am
Posts: 65
Just a quick look:
1st: Your bootloader should setup a proper stack pointer and real mode
segment registers for a start.

Code:
jmp 0x08:0x0000              ; now kernel have control of system

2ndly: I would guess that you try load the kernel to adress 0:8000h.
Basically you are not jumping to your kernel at all.

I have a boot code example here:

http://board.flatassembler.net/topic.php?t=6529

regards
Mac2004


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Wed Feb 02, 2011 5:34 pm 
Offline
Member
Member
User avatar

Joined: Sat Jul 17, 2010 12:45 am
Posts: 487
mac2004 wrote:
Just a quick look:
1st: Your bootloader should setup a proper stack pointer and real mode
segment registers for a start.

Code:
jmp 0x08:0x0000              ; now kernel have control of system

2ndly: I would guess that you try load the kernel to adress 0:8000h.
Basically you are not jumping to your kernel at all.





He was trying
to set the base of the code segment in the GDT to 0x8000. So the jump is Ok.
In fact, I see the following source of errors (listed in descending order of possibility):
1 No far jump before loading the segment registers after entering protected mode.
2. GDT discriptors out of order.
3. Using 32 bit code before actually entering 32 bit protected mode.
4. No drive reset before loading sectors.
5. No provision of saving the Boot Device no. You might be booting from one drive and trying to load sectors from other (1st floppy in your case).

_________________
Programming is not about using a language to solve a problem, it's about using logic to find a solution !


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Wed Feb 02, 2011 6:48 pm 
Offline
Member
Member
User avatar

Joined: Wed Feb 07, 2007 1:45 pm
Posts: 1401
Location: Eugene, OR, US
Well, as Chandra says, your "use32" is definitely in the wrong place. Should be after the "MOV CR0, EAX".
It's very hard to tell if a bunch of GDT bits are correct just by staring at them. So I hope those are right.
The thing that I noticed is that your GDT_SIZE is illegal. You need to subtract 1. This may also cause a failure.


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Thu Feb 03, 2011 4:46 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 3:45 am
Posts: 9301
Location: On the balcony, where I can actually keep 1½m distance
bewing wrote:
Well, as Chandra says, your "use32" is definitely in the wrong place. Should be after the "MOV CR0, EAX".
Even after the jump, because that's the instruction where the processor enters 32-bits mode.

_________________
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Thu Feb 03, 2011 7:52 am 
Offline

Joined: Wed Feb 02, 2011 12:30 pm
Posts: 23
Location: Belo Horizonte, Minas Gerais, Brazil
Thank you for replying me!

Well, I did those modification in bootloader (implement drive reset, far jump, use32 setup correctly, change GDT descriptors order) and also wrote a simple kernel in assembly for testing if this error was in compiling and linking 'kernel.c', but seems it does not, nothing still happening. So, I've tried using a bootloader found at http://www.osdever.net/tutorials/view/mixing-assembly-c, modifying some parametres and, guess what? Still nothing happening.... I think that is an Virtual Box's error emulating. I will try emulate it on Bonch or qemu, because it seems to be more trusty. This is my code with modifications:
Code:
;=====================================NASM HEADERS========================================


%define KSEG 0x0800 ; kernel segment
%define KOFF 0x0000 ; kernel offset
%define KSEC 2      ; kernel sector

%define GDT_LOCATION 0x00007E00
%define GDT_SIZE     0x00FF

;=========================================================================================

use16

org 0x7C00
jmp 0x0000:start
start:

sti                          ; enable bios interrupts

; Set stacks
mov ax, 0x0500
mov ss, ax
mov sp, 0x7BFF             

; Driver reset
mov ah,0x00
mov dl,0x00
int 0x13

; read kernel to memory
mov ah, 0x02                 ; interrupt subfunction: read disk
mov dl, 0                    ; drive ( 00h = A: )
mov dh, 0                    ; head
mov ch, 0                    ; cylinder
mov cl, KSEC                 ; sector
mov al, 1                    ; number of sectors to be read
mov bx, KSEG                 ; es:bx points to memory buffer's location
mov es, bx     
mov bx, KOFF                 ; 0x0800:0x0000
int 13h                      ; disk interrupt

cli                          ; disable BIOS interrupt

push cs
pop  ds

; initializates GDT
mov  ax, GDT_SIZE         
mov  word[gdtr], ax          ; load GDT size
mov  eax, GDT_LOCATION
mov  dword[gdtr + 2], eax    ; load GDT offset

; Load GDT entries
mov ebx, dword[gdtr + 2]
mov edx, gdt
mov ecx, 6
fillgdt:
    mov eax, dword[edx]
    mov dword[ebx], eax
    add ebx, 4
    add edx, 4
    loop fillgdt


xor  ax, ax
mov  ds, ax
lgdt [gdtr]                  ; load GDT register

; enter protected mode
mov eax, cr0
or  al, 1
mov cr0, eax

jmp 0x08:pmode

use32

pmode:

; Load Kernel Code and Data Descriptors
mov ax,0x10
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax

jmp 0x08:0x8000              ; now kernel have control of system

;======================================VARIABLES==========================================


gdtr dw 0x0000     ; GDT size
     dd 0x00000000 ; GDT location

gdt dw 0x0000, 0x0000, 0x0000, 0x0000 ; GDT entry null
    dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; GDT entry kernel code
    dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; GDT entry kernel data

;====================================NASM DIRECTIVES======================================

; fill the end of sector with signature's boot
times 510-($-$$) db 0
                 db 0x55
                 db 0xAA


After all, i have some questions about loading kernel and GDT descriptors:

- Have I need to explicitly load all GDT descriptors, like I did in my code? Because I saw that a lot of people do something like:
Code:
xor ax, ax
mov ds, ax              ; Set DS-register to 0 - used by lgdt

lgdt [gdt_desc]         ; Load the GDT descriptor

...
...

gdt:                    ; Address for the GDT

gdt_null:               ; Null Segment
        dd 0
        dd 0

gdt_code:               ; Code segment, read/execute, nonconforming
        dw 0FFFFh
        dw 0
        db 0
        db 10011010b
        db 11001111b
        db 0

gdt_data:               ; Data segment, read/write, expand down
        dw 0FFFFh
        dw 0
        db 0
        db 10010010b
        db 11001111b
        db 0

gdt_end:                ; Used to calculate the size of the GDT

gdt_desc:                       ; The GDT descriptor
        dw gdt_end - gdt - 1    ; Limit (size)
        dd gdt                  ; Address of the GDT


- When GDT is setup correctly and protected mode was loaded properly, data will be stored in segment that I've specified right? Ok, and if this is true, what is stack pointer function in this story (still the same)?

_________________
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Thu Feb 03, 2011 9:13 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 3:45 am
Posts: 9301
Location: On the balcony, where I can actually keep 1½m distance
Quote:
Have I need to explicitly load all GDT descriptors, like I did in my code? Because I saw that a lot of people do something like:
Did you try to observe the differences?

Quote:
http://www.osdever.net/tutorials/view/mixing-assembly-c
I see you found the tutorial from hell. KEEP OUT - there is just too much broken code and lies around it.

Quote:
I think that is an Virtual Box's error emulating
Learn not to blame your tools but yourself. That said, Bochs will be able to give you much better information about which things go wrong.

_________________
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Fri Feb 04, 2011 3:42 am 
Offline
Member
Member
User avatar

Joined: Thu Nov 16, 2006 12:01 pm
Posts: 7614
Location: Germany
Combuster wrote:
Quote:
I think that is an Virtual Box's error emulating
Learn not to blame your tools but yourself.


Seconding this. The chances of some problem being due to an error in your tools is very, very slim. The chance that you are the first to find a given bug in a mainstream tool is even less.

(You did try to google for any known errors related to your problem, did you?)

Always assume the problem is in your code, unless you have proof that the tool is to blame. Don't waste your time trying to prove the tool incorrect before you have thoroughly and systematically proven your code to be correct.

_________________
Every good solution is obvious once you've found it.


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Fri Feb 04, 2011 10:26 am 
Offline

Joined: Wed Feb 02, 2011 12:30 pm
Posts: 23
Location: Belo Horizonte, Minas Gerais, Brazil
ty guys

_________________
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Fri Feb 04, 2011 3:49 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 06, 2010 10:42 am
Posts: 52
Location: Antwerp (Belgium)
Don't you need Grub to print on screen like you do, and as far as I see I don't see a multiboot-header so you I assume you aren't using it. If I'm not mistaking you're just placing "65" at 0xb8000 the RAM but you graphics card has no idea that you are trying to print something on the screen. If you would use GRUB, it would place it in the VRAM for you and give instructions to the GPU.

My advise: writing you're own bootloader is cool but It'll will get very tricky when you'll try to print stuff, because you will need a gpu-driver or something. So I advise you to use GRUB it's almost the same but you'll have the possibility to easily print on screen.


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Fri Feb 04, 2011 3:58 pm 
Offline
Member
Member

Joined: Tue Jun 15, 2010 9:27 am
Posts: 255
Location: Flyover State, United States
GRUB is a bootloader. It's sole purpose is to load the operating system with the machine in a specified state. It provides no functionality for writing to the screen or other BIOS-like functionality, except providing structures containing important system information to the loaded operating system. On a standard PC, unless you put commands in your multiboot header telling it otherwise, GRUB starts the OS in 80 by 25 text mode with the framebuffer at 0x000B8000. Even without GRUB, the BIOS puts the card in that mode before loading the bootloader any way. If the VGA registers are untouched, you can write to the screen much the same.

_________________
Getting_Started on the wiki
x86 technical information
Interrupt Jump Table
Real Programmers Don't Use Pascal
My open-source projects


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Fri Feb 04, 2011 4:03 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 06, 2010 10:42 am
Posts: 52
Location: Antwerp (Belgium)
Tosi wrote:
GRUB is a bootloader. It's sole purpose is to load the operating system with the machine in a specified state. It provides no functionality for writing to the screen or other BIOS-like functionality, except providing structures containing important system information to the loaded operating system. On a standard PC, unless you put commands in your multiboot header telling it otherwise, GRUB starts the OS in 80 by 25 text mode with the framebuffer at 0x000B8000. Even without GRUB, the BIOS puts the card in that mode before loading the bootloader any way. If the VGA registers are untouched, you can write to the screen much the same.

Offtoppic: Really? People always told me that 0xB8000 was because of GRUB. Have you got some docs about all that for me?

Ontopic: Then I don't directly see what's wrong. But then I do advise you to use Bochs, it's easier for debugging maybe you could find something there?


Top
 Profile  
 
 Post subject: Re: Booting C Kernel with own bootloader
PostPosted: Fri Feb 04, 2011 4:21 pm 
Offline
Member
Member

Joined: Tue Jun 15, 2010 9:27 am
Posts: 255
Location: Flyover State, United States
VGA Graphics register 0x06 - bits 2 and 3 choose how memory is mapped. For 80x25 text mode this is 011b which maps the display memory to the 64 kb region beginning at 0x000B8000. All of this is independent of the bootloader used.

_________________
Getting_Started on the wiki
x86 technical information
Interrupt Jump Table
Real Programmers Don't Use Pascal
My open-source projects


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 123 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group