Added .gitignore
[comos.git] / kernel / start.asm
blob1a52779fab1211a48a21213d1a793050f7c065f2
1 bits 32
2 global _start ; making entry point visible to linker
3 extern kmain ; kmain is defined elsewhere
4 extern _text_start, _edata, _end ; defined in linker script
5 extern _phys_base, _virt_base ; defined in linker script
7 ; setting up the Multiboot header - see GRUB docs for details
8 MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries
9 MEMINFO equ 1<<1 ; provide memory map
10 LOADINFO equ 1<<16 ; load addresses are provided
11 FLAGS equ MODULEALIGN | MEMINFO | LOADINFO ; this is the Multiboot 'flag' field
12 MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
13 CHECKSUM equ -(MAGIC + FLAGS) ; checksum required
15 section multiboot
16 align 4
17 multiboot_header:
18 dd MAGIC
19 dd FLAGS
20 dd CHECKSUM
21 dd multiboot_header ; header_addr
22 dd _text_start ; load_addr
23 dd _edata ; load_end_addr
24 dd _end ; bss_end_addr
25 dd _start ; entry_addr
27 section startup
29 ; reserve initial kernel stack space
30 STACKSIZE equ 0x4000 ; that's 16k.
32 get_freemem_start:
33 ; return the start address of free memory, after kernel image and modules
34 ; mb_info is in ebx
36 ; find the end of the kernel image, rounded up to the next page boundary
37 mov eax,_end
38 test eax,0xFFF ; need to round up?
39 jz .noround
40 add eax,0x1000 ; round up
41 and eax,0xFFFFF000
42 .noround:
43 push eax ; store end of kernel image
45 ; get multiboot flags
46 mov edx,[ebx]
47 test edx,0x08 ; test MBI_MODS_XXX for modules support
48 jz .nomodules
50 ; get mb_info fields
51 mov ecx,[ebx+20] ; mods_count
52 mov edx,[ebx+24] ; mods_addr
54 ; empty modules list?
55 test ecx,ecx
56 jz .finish
57 .loop:
58 ; loop through multiboot modules list
59 mov eax,[edx+4] ; mod_end
60 test eax,0xFFF ; need to round up to nearest page?
61 jz .no_round_mod_end
62 add eax,0x1000 ; round mod_end up to page bourdany
63 and eax,0xFFFFF000
64 .no_round_mod_end:
65 ; find highest mod_end we've found so far
66 cmp [esp],eax
67 ja .nextmod
68 ; this one's the highest
69 mov [esp],eax ; store the rounded mod_end
70 .nextmod:
71 ; move on to next mb_module
72 add edx,byte 16
73 dec ecx
74 jnz .loop
75 .nomodules:
76 .finish:
77 ; return highest address
78 pop eax
79 ret
81 _start:
82 mov esp, stack+STACKSIZE ; set up the stack
83 sub esp,_virt_base ; must use physical address for stack
84 add esp,_phys_base ; until we enable paging!
85 push eax ; pass Multiboot magic number
86 push ebx ; pass Multiboot info structure
87 cld ; make sure direction flag is clear
88 ; (the calling convention is to keep it clear)
90 ; find the start of free memory, after the kernel image and
91 ; modules, in order to allocate space for page directory and
92 ; page tables.
93 call get_freemem_start
94 push eax ; push the address
96 ; allocate a page directory
97 add eax,0x1000
99 ; allocate two page tables
100 push eax
101 add eax,0x1000
102 push eax
103 add eax,0x1000
104 push eax
106 ; clear the page directory
107 mov eax,[esp+12]
108 mov ecx,1024
109 .loop:
110 mov [eax],dword 0
111 add eax,byte 4
112 dec ecx
113 jnz .loop
115 ; NOTE: we set the user bit in the page directory entries.
116 ; This doesn't allow userspace code to read or write from/to
117 ; the memory here, since it requires the user bit in the
118 ; page table entry, too.
120 ; point pagedir[0] -> one of our page tables
121 ; this maps addresses 0x00000000 .. 0x00400000
122 mov eax,[esp+12] ; page directory
123 mov edx,[esp+8] ; page table address
124 or edx,byte 7 ; present, writable, user
125 mov [eax],edx ; put the entry in the table
127 ; point pagedir[768] -> page table
128 ; for addresses 0xC0000000 .. 0xC0400000
129 mov edx,[esp+4]
130 or edx,byte 7 ; present, writable, user
131 mov [eax+(768*4)],edx ; put the entry in the table
133 ; identity map the first page table, so that when we enable
134 ; paging, our kernel can keep on running (and not hit a
135 ; brick wall) - when we enable paging, we can't jump at the
136 ; same time, so if we don't map something to our current eip,
137 ; we'll page-fault (and without an IDT, we'll double-fault and
138 ; triple-fault, and the computer will restart.)
140 xor eax,eax ; count page tables
141 mov ecx,[esp+8] ; page table address
142 .loop2:
143 mov edx,eax
144 shl edx,12 ; (page table entry number) * (page size)
145 or edx,byte 3 ; present, writable, supervisor
146 mov [ecx],edx ; put the entry in the table
147 add ecx,byte 4 ; move on to next entry
148 inc eax
149 cmp eax,1024
150 jb .loop2
152 ; map the second page table:
153 ; point 0xC0000000 .. 0xC0400000 to physical addresses 0x00100000 .. 0x00500000
154 ; this should be enough for our entire kernel image (it's 4 mebibytes)
156 xor eax,eax
157 mov ecx,[esp+4] ; address of our other page table
158 .loop3:
159 mov edx,eax
160 shl edx,12 ; (page table entry number) * (page size)
161 add edx,0x00100000
162 or edx,byte 3 ; present, writable, supervisor
163 mov [ecx],edx ; put the entry in the table
164 add ecx,byte 4 ; move on to the next entry
165 inc eax
166 cmp eax,1024
167 jb .loop3
169 ; now that we've set up our page tables and a page directory, we can tell the CPU
170 ; where to find the page directory
171 mov eax,[esp+12]
172 mov cr3,eax
174 ; and we can turn on paging
175 mov eax,cr0
176 bts eax,byte 31
177 mov cr0,eax
178 ; we're still alive? Good.
180 ; Store the start of free memory after the kernel image and modules,
181 ; and now our page directory and page tables.
182 mov eax,[esp]
183 add esp,byte 16 ; pop our page table addresses - no longer needed
184 push eax ; push the start of free mem
186 ; reload the stack pointer to use virtual addresses > 0xC0000000
187 ; our stuff on the stack will still be there, because it's mapped
188 ; to the same physical address.
189 mov eax,esp
190 sub eax,_phys_base
191 add eax,_virt_base
192 mov esp,eax
194 call kmain ; call kernel proper
195 cli ; halt machine should kernel return
198 section .bss
199 align 32
200 global stack_end
201 stack:
202 resb STACKSIZE ; reserve 16k stack on a quadword boundary
203 stack_end: