8 extern boot_mem_map_size
20 mov fs, ax ; this will store the original real mode segment
22 ; modify the return to real mode jump segment
23 mov [.jmpcs16 + 3], ax
28 ; check for VM86 and abort
44 ; calculate GDT linear address
51 ; set tmp segment bases to match the linear address of our current seg
55 mov word [gdt + 18h + 2], ax ; tmp pm code base
56 mov word [gdt + 20h + 2], ax ; tmp pm data base
57 mov word [gdt + 28h + 2], ax ; ret-to-realmode code
59 mov byte [gdt + 18h + 4], al
60 mov byte [gdt + 20h + 4], al
61 mov byte [gdt + 28h + 4], al
75 .pm: mov ax, 20h ; tmp data selector
77 mov ax, 10h ; dest data selector
80 ; copy main program high
82 mov esi, _ldr_main_start
84 mov ecx, _main_size + 3
89 mov eax, [mem_map_size]
90 mov [es:boot_mem_map_size], eax
93 mov ecx, 32 ; 128 bytes
104 ; return to real mode
112 jmp 42h:.loadcs16 ; 42 seg is modifed at the start
119 ; restore real-mode IVT
128 str_errvm86 db 'Error: memory manager detected! Stop it and try again (e.g. emm386 off)',10,0
129 str_enterpm db 'Entering 32bit protected mode ...',10,0
136 call printstr ; print "Enable A20 line ... "
148 .done: mov si, .okstr
152 .infomsg db 'Enable A20 line:',0
153 .failstr db ' failed.',10,0
154 .okstr db ' success.',10,0
156 ; CF = 1 if A20 test fails (not enabled)
175 .done: mov [ds:si], dl
188 .info db ' fast ...',0
190 KBC_DATA_PORT equ 0x60
191 KBC_CMD_PORT equ 0x64
192 KBC_STATUS_PORT equ 0x64
193 KBC_CMD_WR_OUTPORT equ 0xd1
195 KBC_STAT_IN_FULL equ 2
201 mov al, KBC_CMD_WR_OUTPORT
205 out KBC_DATA_PORT, al
207 .info db ' kbd ...',0
210 in al, KBC_STATUS_PORT
211 and al, KBC_STAT_IN_FULL
216 ; ---------------------- memory detection -----------------------
219 mov si, memdet_detram
221 mov si, memdet_e820_msg
228 mov si, memdet_detram
230 mov si, memdet_e801_msg
237 mov si, memdet_detram
239 mov esi, memdet_88_msg
246 mov si, memdet_detram
248 mov esi, memdet_cmos_msg
255 mov si, memdet_fail_msg
264 str_fail db 'failed',10,0
265 memdet_fail_msg db 'Failed to detect available memory!',10,0
266 memdet_detram db 'Detecting RAM '
267 memdet_e820_msg db '(BIOS 15h/0xe820)... ',0
268 memdet_e801_msg db '(BIOS 15h/0xe801)... ',0
269 memdet_88_msg db '(BIOS 15h/0x88, max 64mb)... ',0
270 memdet_cmos_msg db '(CMOS)...',0
272 ; detect extended memory using BIOS call 15h/e820
274 mov dword [mem_map_size], 0
288 ; skip areas starting above 4GB as we won't be able to use them
289 cmp dword [di + 4], 0
292 ; only care for type 1 (usable ram), otherwise ignore
293 cmp dword [di + 16], 1
298 mov ebp, [mem_map_size]
299 mov [ebp * 8 + esi], eax
301 ; skip areas with 0 size (also clamp size to 4gb)
303 cmp dword [edi + 12], 0
305 ; high part is non-zero, make low part ffffffff
311 ; if both high and low parts are zero, ignore
316 .skiph0:mov [ebp * 8 + esi + 4], eax
317 inc dword [mem_map_size]
320 ; terminate the loop if ebx was reset to 0
328 .fail: ; if size > 0, then it's not a failure, just the end
329 cmp dword [mem_map_size], 0
334 .buffer times 32 db 0
336 ; detect extended memory using BIOS call 15h/e801
339 mov ebp, [mem_map_size]
355 .foo1: mov dword [si], 100000h
357 ; first size is in KB, convert to bytes
360 ; overflow means it's >4GB, clamp to 4GB
362 .foo2: mov [si + 4], eax
363 inc dword [mem_map_size]
366 mov dword [si + 8], 1000000h
368 ; second size is in 64kb blocks, convert to bytes
371 ; overflow means it's >4GB, clamp to 4GB
373 .foo3: mov [si + 12], eax
374 inc dword [mem_map_size]
383 ; reportedly some BIOS implementations fail to clear CF on success
392 ; ax has size in KB, convert to bytes in eax
397 mov dword [si], 100000h
400 mov dword [mem_map_size], 1
418 ; ax has size in KB, convert to bytes in eax
423 mov dword [si], 100000h
425 mov dword [mem_map_size], 1
434 mem_map times 128 db 0
437 ; ----------------------- serial console ------------------------
442 mov dx, UART_BASE + 3 ; LCTL
445 mov dx, UART_BASE ; DIVLO
446 mov al, UART_DIVISOR & 0xff
449 mov al, UART_DIVISOR >> 8
451 mov dx, UART_BASE + 3 ; LCTL
455 mov al, 0xb ; DTR/RTS/OUT2
473 .nolf: call ser_putchar
477 %endif ; def CON_SERIAL
484 cmp al, 10 ; check for line-feed and insert CR before it
507 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
508 enterpm_sel dw 8 ; selector for far jump to protected mode
510 gdt_lim dw 47 ; GDT limit
511 gdt_base dd 0xbadf00d ; space for GDT linear address
514 gdt: ; 0: null segment
517 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
520 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
523 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
526 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
529 ; 5: return to real-mode 16bit code segment (sel: 28h)
533 ; pseudo IDTR descriptor for real-mode IVT at address 0
536 rmidt: dw 3ffh ; IVT limit (1kb / 256 entries)
539 ; vi:set ts=8 sts=8 sw=8 ft=nasm: