News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

MASM OS

Started by brodeur235, May 09, 2009, 09:56:54 PM

Previous topic - Next topic

travism

Glad to see you got it all worked out, I was following this thread for a bit. I remember when I first started in os development its a very difficult task to take on and prepare for much MUCH harder complications to overcome. I remember reading the osdev information 20x over and over. Be sure to post results its always fun to see what people come up with. Keep at it!  :U

brodeur235

First I want to say thanks to everyone who posted helpful replies, especially redskull and dedndave. Redskull, that simple bootloader with debug got the ball rolling for me. Now I osdev in ubuntu with nasm (don't worry masm license people :P). I'm keeping a list of the people who help me out and links to the thread in which they helped, so that one day when I've got my kickass os all together, you guys will get help points :). Anyways, this post is for anyone who cares how far I've gotten with my OS. Technically, I haven't really done much of a kernel except print and clear screen functions, but I'm on my 3rd bootloader version. The first bl was just a simple real mode bootloader that loader a fixed size, 1 sector kernel, and jumped to it. The second one added a gdt and protected mode, and the third one added a special kernel loading function that loads a variable size kernel to anywhere in memory.

[EDIT: If you copy and paste the following code into an editor, it looks better; all the comments are lined up neatly.. If you need better readability]

Here's my earliest bootloader, which I sort of went crazy with commenting for my own understanding:

;||======================================================================================||
;||-----------------------------SYNERGY OS BOOTLOADER VERSION 1--------------------------||
;||======================================================================================||


[ORG 0x7C00]                                               ; ORIGIN = 0x0000:0x7C00
                                                           ;
;procedures                                                ; ==Procedures Section==
                                                           ; *NOTE: First data MUST be code: BIOS loads bootloader and jumpts to FIRST byte.
                                                           ; If first byte is data, BIOS jumps to find unexecutable statements.
                                                           ;
main:                                                      ; | MAIN: PROCEDURE (First code executed, because it's located @ 0x0000:0x7C00)
xor ax,ax                                              ; | AX = 0x0000
mov ds,ax                                              ; | DS = AX (mov ds,0 is invalid. immediate value can't be loaded into segment registers)
                                                       ; |
mov si,bl_loaded_msg                                   ; | si = OFFSET of bl_loaded_msg
call print_si                                          ; | calls procedure print_si (jmps there, pushing ret addr onto stack)
                                                       ; |
call load_kernel                                       ; | calls procedure load_kernel (jmps there, pusing ret addr onto stack)
jmp kernel                                             ; V JMPS to kernel (statement could also be JMP 0x7E00)
                                                           ;
print_si:                                                  ; | PRINT_SI: PROCEDURE (Prints a null delimited string to the screen using BIOS call)
mov bh,0x00                                            ; | BH = 0x00 (BH = page #, always 0h for our purposes)
mov bl,0x07                                            ; | BL = 0x07 (BL = text/bg color, 7h for white on black)
mov ah,0x0E                                            ; | AH = 0x0E (AH Determines BIOS function we call, Eh = print single character)
.next_char                                             ; | ".next_char" internal code label (only addressable by this name in this function)
lodsb                                              ; | lodsb is a cool command. (1) loads BYTE [si] into al (2) increments si by 1
cmp al,0x00                                        ; | set flags according to comparison between al and 0
jz .done                                           ; | if al == 0, reached string's null delimiter: (1) stop outputting chars (2) jmp to .done
int 0x10                                           ; | if al != 0, call BIOS function to output character in al
jmp .next_char                                     ; | jmp to ".next_char", outputting chars until null delimiter is reached.
.done                                                  ; | ".done" internal code label (only addressable by this name in this function)
ret                                                ; V return to where function was called (identified by double word on the top of the stack)
                                                           ;
load_kernel:                                               ; | LOAD_KERNEL: PROCEDURE (loads kernel into memory)
mov dh,0x00                                            ; | DH = 0 (DH = drive #. 0 is floppy drive. Can use 0 if booting from floppy .img in emu.)
mov dl,0x00                                            ; | DL = 0 (DL = head #. Head 0 is top of disk, head 1 is bottom of disk. <-- For floppies)
mov ch,0x00                                            ; | CH = 0 (CH = track #. Track 0 is first)
mov cl,0x02                                            ; | CL = 2 (CL = sector #. Sector 1 is where we are -boot loader- 2 is where kernel is)
xor bx,bx                                              ; | BX = 0
mov es,bx                                              ; | ES = BX (Again, segment registers cannot be set with an immediate value)
mov bx,kernel                                          ; | BX = kernel (kernel = 0x0000:0x7E00, because boot loader is 0x7C-0x7DF. kernal after)
mov ah,0x02                                            ; | AH = 2 (AH Determines BIOS function we call, 2h= load data specified by registers)
mov al,0x01                                            ; | AL = 1 (AL = # of sectors to load into memory)
int 0x13                                               ; | call BIOS function to load drive 0, head 0, track 0, sector 2 into mem @ 0000:7E00h
ret                                                    ; V return to where function was called (identified by double word on the top of the stack)
                                                           ;
;data                                                      ; ==Data Section==
                                                           ;
bl_loaded_msg db "Bootloader loaded.",0xA,0xD,0            ; simple string data.
                                                           ;
;padding                                                   ; ==Padding Secion==
                                                           ;
times 512-2-($-$$) db 0x0000                               ; Boot Loader MUST be EXACTLY 512 bytes. We used some with out code and data, pad rest w/ 0.
bootable db 0xAA, 0x55                                     ; Last 2 bytes of bootloader must be AA55h, signaling to BIOS that this drive is bootable.


;||======================================================================================||
;||-----------------------------SYNERGY OS KERNEL VERSION 1------------------------------||
;||======================================================================================||


;procedures

kernel:
mov si,kl_loaded_msg
call print_si

jmp $

;data

kl_loaded_msg db "Kernel loaded.",0xA,0xD,0

;padding

times 512-($-kernel) db 0x0000


Here's the latest bootloader/kernel I have (I compile with: nasm source.asm -f bin -o image.img, and use VBox to test):

;||=====================================================||
;||                      BOOT LOADER                    ||
;||=====================================================||
;general disk info
%define HD_SECTORS_PER_TRACK 0xFF

;kernel disk info
%define KERNEL_DRIVE 0x0000
%define KERNEL_HEAD 0x0000
%define KERNEL_TRACK 0x0000
%define KERNEL_SECTOR 0x0002
%define KERNEL_SIZE (52*1024)

;kernel memory info
%define KERNEL_OFFSET 0xD000

[BITS 16]
[ORG 0x7C00]

;||====||
;||code||
;||====||

bootloader_main:
xor ax,ax
mov ds,ax
mov ss,ax
mov sp,0x100

mov si,bl_loaded_msg
call print_16b

call load_custom_kernel

lgdt [gdt_desc]
mov si,gdt_loaded_msg
call print_16b

mov eax,cr0
or eax,1
mov cr0,eax

jmp 0x8:0xD000

print_16b:
mov bh,0x00
mov bl,0x07
mov ah,0x0E
.p16b_next_char:
lodsb
cmp al,0x00
jz .p16b_done
int 0x10
jmp .p16b_next_char
.p16b_done:
ret

load_custom_kernel:

mov dx,0x0000
mov ax,KERNEL_SIZE
mov bx,0x200 ;512 decimal
div bx
cmp dx,0
jnz .lck_error_kl_size

mov BYTE [hd_sector],KERNEL_SECTOR
mov BYTE [hd_track],KERNEL_TRACK
mov WORD [kern_off],KERNEL_OFFSET
mov cx,ax ; # of sectors to copy
.lck_copy_next_sector:
push cx


cmp BYTE [hd_sector],HD_SECTORS_PER_TRACK ;if 1 greater than 2, adjust
jz .lck_continue_copying
jc .lck_continue_copying

inc BYTE [hd_track]
mov BYTE [hd_sector],0x01

.lck_continue_copying:

mov dh,KERNEL_DRIVE
mov dl,KERNEL_HEAD
mov ch,BYTE [hd_track]
mov cl,BYTE [hd_sector]
xor bx,bx
mov es,bx
mov bx,[kern_off]
mov ah,0x02
mov al,0x01
int 0x13

add WORD [kern_off],0x200
inc BYTE [hd_sector]
pop cx
loop .lck_copy_next_sector
jmp .lck_no_error

.lck_error_kl_size:
mov si,error_kl_size
call print_16b
jmp $
.lck_no_error:
mov si,kl_loaded_msg
call print_16b
jmp .lck_done
.lck_done:
ret

;||===||
;||gdt||
;||===||

gdt_entries:

;null entry
dd 0x0,0x0

;code segment descriptor: OFFESET = 0x8
dw 0xFFFF,0x0000
db 0x00,10011010b
db 11001111b,0x0

;data segment descriptor: OFFSET = 0x10
dw 0xFFFF,0x0000
db 0x00,10010010b
db 11001111b,0x0

;stack segment descriptor: OFFSET = 0x18
db 00000000b
db 11010000b
db 00000000b
db 00000000b     ;Stack is 52 KB (read/writable) growing downwards from 0xD000 to 0x0000
db 00000000b
db 10010110b
db 11000000b
db 00000000b

gdt_desc:
size dw ($-gdt_entries-1)
offset dd gdt_entries

;||====||
;||data||
;||====||

;vars
hd_sector db 0x00
hd_track db 0x00
kern_off dw 0x0000

;regular updates
bl_loaded_msg db "Bootloader loaded.",0XA,0xD,0
gdt_loaded_msg db "Global Descriptor Table loaded.",0xA,0xD,0
kl_loaded_msg db "Kernel loaded.",0xA,0xD,0

;errors
error_kl_size db "Error: Kernel size not an even number of sectors!",0xA,0xD,0

;||=========================||
;||padding (512 BYTES total)||
;||=========================||

times 512-2-($-$$) db 0

;||========||
;||bootable||
;||========||

db 0xAA,0x55
;||=====================================================||
;||                    END BOOT LOADER                  ||
;||=====================================================||

;||=====================================================||
;||                        KERNEL                       ||
;||=====================================================||
[BITS 32]

;code

kernel_main:

mov ax,0x10
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
;mov ax,0x18 ;SS descriptor (offset 0x18 in GDT) doesn't work for some reason...
mov ss,ax
mov esp,0xD000 ; 52 kb stack

mov al,0x1B
call k_set_screen_colors

mov eax,0x03
mov si,((kl_exec_msg-kernel_main)+KERNEL_OFFSET)
call k_print

jmp (($-kernel_main)+KERNEL_OFFSET)

k_print:
mov ebx,0x000B8000
imul eax,160d
add ebx,eax
.kp_next_char:
lodsb
cmp al,0x00
jz .kp_done
mov BYTE [ds:ebx],al
add ebx,0x2
jmp .kp_next_char
.kp_done:
ret

k_clear_screen:
mov ebx,0x00B8000
mov ecx,(80*25)
.kcs_clear_next:
mov BYTE [ds:ebx],' '
add ebx,0x2
loop .kcs_clear_next
ret

k_set_screen_colors:
mov ebx,0x00B8001
mov ecx,(80*25)
.kssc_set_next:
mov BYTE [ds:ebx],al
add ebx,0x2
loop .kssc_set_next
ret

;data

kl_exec_msg db "Kernel Executing.",0

;padding (52 KILOBYTES total)

times (52*1024)-($-kernel_main) db 0
;||=====================================================||
;||                      END KERNEL                     ||
;||=====================================================||

;||=====================================================||
;||                     MEMORY MODEL                    ||
;||=====================================================||

; ______________________________________________________
;|                                                      |
;| { 52 KB stack } { 52 KB Kernel Space }
;|______________________________________________________|


I'm currently working on adding paging. And..., yeah I named the thing already... That was a fun part :P

Brodeur235

redskull

Looking good; you might want to check out the INT 13 extensions (41 and 42), which are a little more flexible than the original ones and could streamline the "load_custom_kernel" function (space is at a premium in the bootloader).  You might also try downloading the source code for ReactOS (a Windows clone), which can give a nice overview of how everything fits together.

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government