MushOS  0.1
A UNIX-like OS prototype, written from scratch
Loading...
Searching...
No Matches
loader.asm
1; This code lies in the first sector of hard disk, the boot sector.
2; BIOS works in 16-bit (real) CPU mode, as soon as it finds boot sector, it calls it.
3
4[bits 16] ; Code also compiled as 16-bit, BIOS-compatible.
5[org 0x7c00] ; Code is loaded at 0x7c00 address in RAM - special booting address.
6
7start:
8 jmp kernel_start ; Jumping to actual code to avoid executing GDT-table.
9
10KERNEL_OFFSET equ 0x8000 ; Offset in RAM, where kernel will be loaded, it is also defined in linker.
11 ; Should be enough since we have micro kernel here.
12CODE_OFFSET equ 0xA000 ;
13
14STACK_OFFSET equ 0x7000 ;
15
16
17gdt_start: ; Beginning of GDT-table. The table itself contains information about RAM segments.
18 ; Each segment has a set of parameters (e.g. readable/writable, data/code, etc.)
19 ; This table is a basic flat model table with no security required to go to 32-bit CPU mode.
20 ; The table contains 2 overlapping 4GB segments (code and data). Since they overlap, they're not protected.
21 ; It maybe will be changed later, from protected mode along with other interesting features.
22
23gdt_null: ; First sector has to be null. For catching segment-register-not-set error catching.
24 dd 0x0 ; Info about one segment takes 4 words (8 bytes) of memory.
25 dd 0x0 ; This null-segment is apparently initialized with all zeroes.
26
27gdt_code: ; The code segment.
28 dw 0xffff ; Segment limit - how long is it. 4GB, as stated.
29 dw 0x0000 ; Segment base - where it begins in memory. In the very beginning.
30 db 0x00 ; Segment base one more time (for some reason it has to be initialized two times).
31 db 10011010b ; Segment flags, these are:
32 ; Present (1) - the segment is present.
33 ; Privilege (00) - highest privilege.
34 ; Descriptor type (1) - 1 for code and data, 0 for traps.
35 ; Type flags:
36 ; Type (1) - 1 for code, 0 for data.
37 ; Conforming (0) - means lower-privileged segments can't call it.
38 ; Readable (1) - readable or executable-only.
39 ; Accessed (0) - CPU sets when accesses the segment.
40 db 11001111b ; Segment flags:
41 ; Granularity (1) - Expands limit from 0xffff to 0xffff000.
42 ; 32 bit (1) - set 0 for 64-bit code.
43 ; 64 bit (0) - we have it unused.
44 ; AVL (0) - flag for custom uses.
45 ; Other 4 bits (1111) contain info about segment limit.
46 db 0x00 ; Segment base (for the third time, yes).
47
48gdt_data: ; The data segment (I will comment differences only).
49 dw 0xffff
50 dw 0x0000
51 db 0x00
52 db 10010010b ; Type (0) - for data.
53 db 11001111b
54 db 0x00
55
56gdt_end: ; Label marks end of GDT table in memory.
57
58gdt_descriptor: ; Special structure - GDT descriptor is used to transfer info about GDT table.
59 dw gdt_end - gdt_start - 1 ; Size of GDT table, one less than actual.
60 dd gdt_start ; Position of table in memory.
61
62
63CODE_SEG equ gdt_code - gdt_start ; These are the values that CS and DS registers must contain in protected mode.
64DATA_SEG equ gdt_data - gdt_start ; They point to beginning of special segments in GDT.
65
66
67read_disk: ; Procedure for reading sectors from disc into memory.
68 ; DH = how many sectors; DL = from what drive; BX = where to load.
69 pusha ; Push all registers.
70 push dx ; For later error checking.
71
72 mov ah, 0x02 ; int 13h : 02 - reading from disk BIOS function.
73 mov al, dh ; Sectors number.
74 mov ch, 0x00 ; Track cylinder.
75 mov dh, 0x00 ; Track number.
76 mov cl, 0x02 ; First sector to read.
77
78 int 13h
79
80 jc .disk_error ; int 13h sets -c flag if reading error occurs.
81
82 pop dx ; int 13h stores number of sectors read into al.
83 cmp dh, al ; Checking how many sectors were read vs. how many must've been read.
84 jne .disk_error ; If not the same number handling error.
85 jmp .done
86
87.disk_error:
88 mov si, ERROR_MSG ; Setting and printing error message.
89 call write_string
90 stc ; Ensuring -c flag was set to check if function finished successfully.
91
92.done:
93 popa ; Pop all registers.
94 ret
95
96
97write_string: ; Procedure for writing string into console.
98 ; SI = pointer to string in ASCIIZ format.
99 pusha
100 mov ah, 0x0e ; int 10h : 0e - writing char into console and setting cursor to next position BIOS function.
101 ; Other parameters (color, mode, etc.) are set by default.
102
103.repeat:
104 lodsb ; Loading char from SI to AL, increasing SI.
105 cmp al, 0x00 ; Checking if the end of string was reached.
106 je .done ; Escaping cycle.
107 int 10h
108 jmp .repeat ; Proceeding to next char.
109
110.done:
111 popa
112 ret
113
114
115kernel_start: ; Start of booting code.
116 mov [BOOT_DRIVE], dl ; BIOS puts number of booting device into DL. Saving it into variable.
117
118 cli ; Clearing interruptions before SP and SP modifying.
119 mov ax, cs ; CS points to 7c00 at the boot time, the current segment. TODO: check!!
120 mov ss, ax ; Placing stack to the same segment. TODO: So stack will be from 0x7c00 to 0x500, check that's enough!
121 mov bp, start ; Stack grows downwards in memory, while the code - upwards. TODO: check!!
122 mov sp, bp ; So stack starts right in the entry point, but grows to another direction.
123 sti ; Setting interruptions back.
124
125 mov ds, ax ; Setting DS and ES to the same segment.
126 mov es, ax ; My boot loader contains code and variables all together.
127
128 ; Setting default output video mode to color VGA 80x25.
129 ;mov ah, 0x00 ; int 10h : 00 - setting video mode BIOS function.
130 ;mov al, 0x03 ; Color, 80x25, text, memory at 0xb8000 preset.
131 ;int 10h
132
133 mov si, BOOT_MSG ; Setting and printing boot message.
134 call write_string
135
136 mov dh, 80 ; Loading 80 sectors from disk into memory. It covers kernel space from 0x8000 to 0x12000
137 mov dl, [BOOT_DRIVE] ; Setting current boot drive.
138 mov bx, KERNEL_OFFSET ; Setting kernel position to one defined above.
139 call read_disk
140
141 jc .loop ; If reading is not successful hanging up system.
142
143 cli ; Clearing interruptions - the interruptions in protected mode differ.
144 lgdt [gdt_descriptor] ; Loading defined above GDB table.
145 mov eax, cr0 ; cr0 CPU register contains information about processor mode in last byte.
146 or eax, 0x01 ; Setting CPU mode to protected.
147 mov cr0, eax ; Loading cr0 register back.
148
149 jmp CODE_SEG:kernel_launch ; Performing long jump to stop all parallel tasks (piping) and force CPU into protected mode.
150
151.loop:
152 jmp $ ; Replace with hlt? Hanging CPU up.
153
154
155[bits 32] ; This segment is compiled in 32-bits mode to be executed in protected CPU mode.
156
157kernel_launch: ; Long jump sets CS to CODE_SEG automatically at this point.
158
159 mov ax, DATA_SEG ; Setting other registers to DATA_SEG.
160 mov ds, ax
161 mov ss, ax
162 mov es, ax
163 mov fs, ax ; Even some strange-looking, protected mode registers.
164 mov gs, ax
165
166 mov ebp, STACK_OFFSET ; Resetting stack back where it was.
167 mov esp, ebp
168
169 call CODE_OFFSET ; Calling pre-loaded C kernel (kernel_gate).
170
171
172variables:
173 BOOT_DRIVE db 0
174 BOOT_MSG db "MUSHOS booted in real mode...", 0x0d, 0x0a, 0
175 ERROR_MSG db "Could not load second boot loader!", 0x0d, 0x0a, 0
176
177magic_numbers: ; $$ - special label in NASM, I'm not 100% sure how it works.
178 times 510-($-$$) db 0 ; Filling least of boot segment with zeroes not to be executed for any reason.
179 dw 0xaa55 ; The last two bytes are special "magic number" allowing BIOS to differ boot sector from regular.