bunch of work in progress on getting x86_64 bootstrap working.
[newos.git] / boot / x86_64 / bootblock.asm
bloba2750e034f847e34458ff99da90ee7b5d6d85e10
1 ; **
2 ; ** Copyright 1998 Brian J. Swetland
3 ; ** All rights reserved.
4 ; **
5 ; ** Redistribution and use in source and binary forms, with or without
6 ; ** modification, are permitted provided that the following conditions
7 ; ** are met:
8 ; ** 1. Redistributions of source code must retain the above copyright
9 ; ** notice, this list of conditions, and the following disclaimer.
10 ; ** 2. Redistributions in binary form must reproduce the above copyright
11 ; ** notice, this list of conditions, and the following disclaimer in the
12 ; ** documentation and/or other materials provided with the distribution.
13 ; ** 3. The name of the author may not be used to endorse or promote products
14 ; ** derived from this software without specific prior written permission.
15 ; **
16 ; ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 ; ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 ; ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 ; ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 ; ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 ; ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 ; ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 ; ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 ; ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 ; ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 ; /*
28 ; ** Copyright 2001-2004, Travis Geiselbrecht. All rights reserved.
29 ; ** Distributed under the terms of the NewOS License.
30 ; */
32 ; /*
33 ; ** Reviewed, documented and some minor modifications and bug-fixes
34 ; ** applied by Michael Noisternig on 2001-09-02.
35 ; */
37 %define VESA_X_TARGET 640
38 %define VESA_Y_TARGET 480
39 %define VESA_BIT_DEPTH_TARGET 16
41 SECTION
42 CODE16
43 ORG 0x7c00 ; start code at 0x7c00
44 jmp short start
45 sectors dw 800 ; this is interpreted as data (bytes 3 and 4)
46 ; and patched from outside to the size of the bootcode (in sectors)
47 start:
48 cli ; no interrupts please
49 cld
50 xor ax,ax
51 mov ss,ax ; setup stack from 0 - 0x7c00
52 mov sp,0x7c00 ; stack pointer to top of stack
53 call enable_a20 ; enable a20 gate
54 lgdt [ss:gdt] ; load global descriptor table
55 mov eax,cr0 ; switch to protected mode
56 or al,0x1 ; by setting 'protected mode enable' bit
57 mov cr0,eax ; and writing back
58 jmp dword 0x8:unreal32 ; do the actual switch into protected mode
59 ; The switch into protected mode and back is to get the processor into 'unreal' mode
60 ; where it is in 16-bit mode but with segments that are larger than 64k.
61 ; this way, the floppy code can load the image directly into memory >1Mb.
62 unreal32:
63 mov bx,0x10 ; load all of the data segments with large 32-bit segment
64 mov ds,bx
65 mov es,bx
66 mov ss,bx
67 and al,0xfe ; switch back to real mode
68 mov cr0,eax
69 jmp 0x7c0:unreal-0x7c00 ; actually go back to 16-bit
70 unreal:
71 xor ax,ax ; load NULL-descriptor (base 0) into ds, es, ss
72 mov es,ax ; the processor doesn't clear the internal high size bits on these descriptors
73 mov ds,ax ; so the descriptors can now reference 4Gb of memory, with size extensions
74 mov ss,ax
76 ; read in the second half of this stage of the bootloader
77 xor dx,dx ; start at head 0
78 mov bx,0x2 ; start at sector 2 for the second half of this loader
79 mov cx,1 ; one sector
80 mov edi,0x7e00 ; right after this one
81 sti
82 call load_floppy
84 ; read in the rest of the disk
85 mov edi,0x100000 ; destination buffer (at 1 MB) for sector reading in load_floppy
86 mov bx,0x3 ; start at sector 3 (and cylinder 0)
87 mov cx,[sectors] ; read that much sectors
88 xor dx,dx ; start at head 0
89 sti
90 mov si,loadmsg
91 call print
92 call load_floppy ; read remaining sectors at address edi
93 call disable_floppy_motor
94 mov si,okmsg
95 call print
96 cli
98 ; uncomment the next line to enable the VESA mode switch
99 ; call enable_vesa
100 ; mov [in_vesa],al
102 call find_mem_size_real
104 ; mov ebx,[dword 0x100074] ; load dword at rel. address 0x74 from read-destination-buffer
105 ; add ebx,0x101000 ; for stage2 entry
106 mov al,0xcf
107 mov [ds:gdt+14],al ; set desc. 1 and 2
108 mov [ds:gdt+22],al ; to 32-bit segment
109 lgdt [ds:gdt] ; load global descriptor table
111 mov eax,1
112 mov cr0,eax ; enter protected mode
113 jmp dword 0x8:code32 ; flush prefetch queue
114 code32:
115 BITS 32
116 mov ax,0x10 ; load descriptor 2 in all segment selectors (except cs)
117 mov ds,ax
118 mov es,ax
119 mov fs,ax
120 mov gs,ax
121 mov ss,ax
122 mov ebp,0x10000
123 mov esp,ebp
125 mov eax,[vesa_info]
126 push eax
128 xor eax,eax
129 mov al,[in_vesa]
130 push eax
132 xor eax,eax
133 mov al,[ext_mem_count]
134 push eax
136 xor eax,eax
137 mov eax,[ext_mem_info]
138 push eax
140 cmp al, 0x0
141 je probe_mem
143 xor eax,eax
144 push eax ; should be loaded with zero
145 jmp call_stage2
147 probe_mem:
148 call find_mem_size_probe
149 push eax
151 call_stage2:
152 mov ebx,0x100000
153 call ebx ; jump to stage1 entry
154 inf:jmp short inf
156 ; find memory size by testing
157 ; OUT: eax = memory size
158 find_mem_size_probe:
159 mov eax,0x31323738 ; test value
160 mov esi,0x100ff0 ; start above conventional mem + HMA = 1 MB + 1024 Byte
161 _fms_loop:
162 mov edx,[esi] ; read value
163 mov [esi],eax ; write test value
164 mov ecx,[esi] ; read it again
165 mov [esi],edx ; write back old value
166 cmp ecx,eax
167 jnz _fms_loop_out ; read value != test value -> above mem limit
168 add esi,0x1000 ; test next page (4 K)
169 jmp short _fms_loop
170 _fms_loop_out:
171 mov eax,esi
172 sub eax,0x1000
173 add eax,byte +0x10
176 BITS 16
177 ; read sectors into memory
178 ; IN: bx = sector # to start with: should be 2 as sector 1 (bootsector) was read by BIOS
179 ; cx = # of sectors to read
180 ; edi = buffer
181 load_floppy:
182 push bx
183 push cx
184 tryagain:
185 mov al,0x13 ; read a maximum of 18 sectors
186 sub al,bl ; substract first sector (to prevent wrap-around ???)
188 xor ah,ah ; TK: don't read more then required, VMWare doesn't like that
189 cmp ax,cx
190 jl shorten
191 mov ax,cx
192 shorten:
194 mov cx,bx ; -> sector/cylinder # to read from
195 mov bx,0x8000 ; buffer address
196 mov ah,0x2 ; command 'read sectors'
197 push ax
198 int 0x13 ; call BIOS
199 pop ax ; TK: should return number of transferred sectors in al
200 ; but VMWare 3 clobbers it, so we (re-)load al manually
201 jnc okok ; no error -> proceed as usual
202 dec byte [retrycnt]
203 jz fail
204 xor ah,ah ; reset disk controller
205 int 0x13
206 jmp tryagain ; retry
207 okok:
208 mov byte [retrycnt], 3 ; reload retrycnt
209 mov si,dot
210 call print
211 mov esi,0x8000 ; source
212 xor ecx,ecx
213 mov cl,al ; copy # of read sectors (al)
214 shl cx,0x7 ; of size 128*4 bytes
215 rep a32 movsd ; to destination (edi) setup before func3 was called
216 pop cx
217 pop bx
218 xor dh,0x1 ; read: next head
219 jnz bar6
220 inc bh ; read: next cylinder
221 bar6:
222 mov bl,0x1 ; read: sector 1
223 xor ah,ah
224 sub cx,ax ; substract # of read sectors
225 jg load_floppy ; sectors left to read ?
228 disable_floppy_motor:
229 xor al,al
230 mov dx,0x3f2 ; disable floppy motor
231 out dx,al
234 ; prints message in reg. si
235 print:
236 pusha
238 lodsb
239 or al,al
240 jz short _e
241 mov ah,0x0E
242 mov bx,7
243 int 0x10
244 jmp _n
246 popa
249 ; print errormsg, wait for keypress and reboot
250 fail:
251 mov si,errormsg
252 call print
253 xor ax, ax
254 int 0x16
255 int 0x19
257 ; enables the a20 gate
258 ; the usual keyboard-enable-a20-gate-stuff
259 enable_a20:
260 call _a20_loop
261 jnz _enable_a20_done
262 mov al,0xd1
263 out 0x64,al
264 call _a20_loop
265 jnz _enable_a20_done
266 mov al,0xdf
267 out 0x60,al
268 _a20_loop:
269 mov ecx,0x20000
270 _loop2:
271 jmp short _c
273 in al,0x64
274 test al,0x2
275 loopne _loop2
276 _enable_a20_done:
279 loadmsg db "Loading",0
280 errormsg db 0x0a,0x0d,"Error reading disk.",0x0a,0x0d,0
281 okmsg db "OK",0x0a,0x0d,0
282 dot db ".",0
283 gdt:
284 ; the first entry serves 2 purposes: as the GDT header and as the first descriptor
285 ; note that the first descriptor (descriptor 0) is always a NULL-descriptor
286 db 0xFF ; full size of GDT used
287 db 0xff ; which means 8192 descriptors * 8 bytes = 2^16 bytes
288 dw gdt ; address of GDT (dword)
289 dd 0
290 ; descriptor 1:
291 dd 0x0000ffff ; base - limit: 0 - 0xfffff * 4K
292 dd 0x008f9a00 ; type: 16 bit, exec-only conforming, <present>, privilege 0
293 ; descriptor 2:
294 dd 0x0000ffff ; base - limit: 0 - 0xfffff * 4K
295 dd 0x008f9200 ; type: 16 bit, data read/write, <present>, privilege 0
297 retrycnt db 3
298 in_vesa db 0
299 vesa_info dd 0
300 ext_mem_info dd 0
301 ext_mem_count db 0
303 times 510-($-$$) db 0 ; filler for boot sector
304 dw 0xaa55 ; magic number for boot sector
306 ; Starting here is the second sector of the boot code
308 BITS 16
309 find_mem_size_real:
310 ; use int 0x15, EAX=0xe820 to test for memory
311 ; assumes es is null
313 mov ebx,0
314 mov edi,0x7000 ; the extended memory structures will go at 0x7000
315 mov [ext_mem_info],edi
317 find_mem_next:
318 mov eax,0xe820
319 mov edx,'PAMS' ; 'SMAP' in the correct order
320 mov ecx,0x20
322 int 0x15
323 jc done_mem_real ; if carry is set, it wasn't supported
325 inc byte [ext_mem_count] ; increment the count of the number
327 cmp ebx,0x0 ; test if we're done
328 je done_mem_real
330 add edi,0x20 ; increment the buffer by 0x20
331 jmp find_mem_next
333 done_mem_real:
336 ; fool around with vesa mode
337 enable_vesa:
338 ; put the VBEInfo struct at 0x30000
339 mov eax,0x30000
340 mov [vesa_info],eax
341 mov dx,0x3000
342 mov es,dx
343 mov ax,0x4f00
344 mov di,0
345 int 0x10
347 ; check the return code
348 cmp al,0x4f
349 jne done_vesa_bad
350 cmp ah,0x00
351 jne done_vesa_bad
353 ; check the signature on the data structure
354 mov eax,[es:00]
355 cmp eax,0x41534556 ; 'VESA'
356 je vesa_sig_ok
357 cmp eax,0x32454256 ; 'VBE2'
358 jne done_vesa_bad
360 vesa_sig_ok:
361 ; scan through each mode and grab the info on them
362 les bx,[es:14] ; calculate the pointer to the mode list
363 mov di,0x200 ; push the buffer up a little to be past the VBEInfo struct
365 mode_loop:
366 mov cx,[es:bx] ; grab the next mode in the list
367 cmp cx,0xffff
368 je done_vesa_bad
369 and cx,0x01ff
370 mov ax,0x4f01
371 int 0x10
373 ; if it's 1024x768x32, go for it
374 mov ax,[es:di]
375 test ax,0x1 ; test the supported bit
376 jz next_mode
377 test ax,0x08 ; test the linear frame mode bit
378 jz next_mode
379 mov ax,[es:di+18]
380 cmp ax,VESA_X_TARGET ; x
381 jne next_mode
382 mov ax,[es:di+20]
383 cmp ax,VESA_Y_TARGET ; y
384 jne next_mode
385 mov al,[es:di+25]
386 cmp al,VESA_BIT_DEPTH_TARGET ; bit_depth
387 jne next_mode
389 ; looks good, switch into it
390 mov ax,0x4f02
391 mov bx,cx
392 or bx,0x4000 ; add the linear mode bit
393 int 0x10
394 jmp done_vesa_good
396 next_mode:
397 ; get ready to try the next mode
398 inc bx
399 inc bx
400 jmp mode_loop
402 done_vesa_good:
403 mov ax,0x1
406 done_vesa_bad:
407 xor ax,ax
410 times 1024-($-$$) db 0 ; filler for second sector of the loader