8 extern boot_mem_map_size
19 mov fs, ax ; this will store the original real mode segment
21 ; modify the return to real mode jump segment
22 mov [.jmpcs16 + 3], ax
27 ; check for VM86 and abort
38 call warning ; issue a warning and allow the user to abort
47 ; calculate GDT linear address
54 ; set tmp segment bases to match the linear address of our current seg
58 mov word [gdt + 18h + 2], ax ; tmp pm code base
59 mov word [gdt + 20h + 2], ax ; tmp pm data base
60 mov word [gdt + 28h + 2], ax ; ret-to-realmode code
62 mov byte [gdt + 18h + 4], al
63 mov byte [gdt + 20h + 4], al
64 mov byte [gdt + 28h + 4], al
69 ; change video mode now, to avoid having to bring in all the int86 code
82 .pm: mov ax, 20h ; tmp data selector
84 mov ax, 10h ; dest data selector
87 ; copy main program high
89 mov esi, _ldr_main_start
91 mov ecx, _main_size + 3
96 mov eax, [mem_map_size]
97 mov [es:boot_mem_map_size], eax
100 mov ecx, 32 ; 128 bytes
111 ; return to real mode
119 jmp 42h:.loadcs16 ; 42 seg is modifed at the start
126 ; restore real-mode IVT
135 str_errvm86 db 'Error: memory manager detected! Stop it and try again (e.g. emm386 off)',10,0
136 str_enterpm db 'Entering 32bit protected mode ...',10,0
140 ; warns the user about the experimental and buggy state of this
141 ; protected mode system, and allows aborting if having to reboot later
152 db 'WARNING: this program uses an experimental protected mode kernel, which is ',10
153 db 'still in a very early stage of development, and will probably not be able to ',10
154 db 'return cleanly to DOS on exit. You might be forced to reboot after quitting!',10
155 db 'If this is not acceptable, press ESC now to abort.',10,10
156 db 'Press ESC to abort and return to DOS, any other key to continue...',10,0
160 ; ---------------------- A20 address line enable -----------------------
167 call printstr ; print "Enable A20 line ... "
179 .done: mov si, .okstr
183 .infomsg db 'Enable A20 line:',0
184 .failstr db ' failed.',10,0
185 .okstr db ' success.',10,0
187 ; CF = 1 if A20 test fails (not enabled)
206 .done: mov [ds:si], dl
219 .info db ' fast ...',0
221 KBC_DATA_PORT equ 0x60
222 KBC_CMD_PORT equ 0x64
223 KBC_STATUS_PORT equ 0x64
224 KBC_CMD_WR_OUTPORT equ 0xd1
226 KBC_STAT_IN_FULL equ 2
232 mov al, KBC_CMD_WR_OUTPORT
236 out KBC_DATA_PORT, al
238 .info db ' kbd ...',0
241 in al, KBC_STATUS_PORT
242 and al, KBC_STAT_IN_FULL
247 ; ---------------------- memory detection -----------------------
250 mov si, memdet_detram
252 mov si, memdet_e820_msg
259 mov si, memdet_detram
261 mov si, memdet_e801_msg
268 mov si, memdet_detram
270 mov esi, memdet_88_msg
277 mov si, memdet_detram
279 mov esi, memdet_cmos_msg
286 mov si, memdet_fail_msg
295 str_fail db 'failed',10,0
296 memdet_fail_msg db 'Failed to detect available memory!',10,0
297 memdet_detram db 'Detecting RAM '
298 memdet_e820_msg db '(BIOS 15h/0xe820)... ',0
299 memdet_e801_msg db '(BIOS 15h/0xe801)... ',0
300 memdet_88_msg db '(BIOS 15h/0x88, max 64mb)... ',0
301 memdet_cmos_msg db '(CMOS)...',0
303 ; detect extended memory using BIOS call 15h/e820
305 mov dword [mem_map_size], 0
319 ; skip areas starting above 4GB as we won't be able to use them
320 cmp dword [di + 4], 0
323 ; only care for type 1 (usable ram), otherwise ignore
324 cmp dword [di + 16], 1
329 mov ebp, [mem_map_size]
330 mov [ebp * 8 + esi], eax
332 ; skip areas with 0 size (also clamp size to 4gb)
334 cmp dword [edi + 12], 0
336 ; high part is non-zero, make low part ffffffff
342 ; if both high and low parts are zero, ignore
347 .skiph0:mov [ebp * 8 + esi + 4], eax
348 inc dword [mem_map_size]
351 ; terminate the loop if ebx was reset to 0
359 .fail: ; if size > 0, then it's not a failure, just the end
360 cmp dword [mem_map_size], 0
365 .buffer times 32 db 0
367 ; detect extended memory using BIOS call 15h/e801
370 mov ebp, [mem_map_size]
386 .foo1: mov dword [si], 100000h
388 ; first size is in KB, convert to bytes
391 ; overflow means it's >4GB, clamp to 4GB
393 .foo2: mov [si + 4], eax
394 inc dword [mem_map_size]
397 mov dword [si + 8], 1000000h
399 ; second size is in 64kb blocks, convert to bytes
402 ; overflow means it's >4GB, clamp to 4GB
404 .foo3: mov [si + 12], eax
405 inc dword [mem_map_size]
414 ; reportedly some BIOS implementations fail to clear CF on success
423 ; ax has size in KB, convert to bytes in eax
428 mov dword [si], 100000h
431 mov dword [mem_map_size], 1
449 ; ax has size in KB, convert to bytes in eax
454 mov dword [si], 100000h
456 mov dword [mem_map_size], 1
465 mem_map times 128 db 0
468 ; ----------------------- serial console ------------------------
473 mov dx, UART_BASE + 3 ; LCTL
476 mov dx, UART_BASE ; DIVLO
477 mov al, UART_DIVISOR & 0xff
480 mov al, UART_DIVISOR >> 8
482 mov dx, UART_BASE + 3 ; LCTL
486 mov al, 0xb ; DTR/RTS/OUT2
504 .nolf: call ser_putchar
508 %endif ; def CON_SERIAL
515 cmp al, 10 ; check for line-feed and insert CR before it
538 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
539 enterpm_sel dw 8 ; selector for far jump to protected mode
541 gdt_lim dw 47 ; GDT limit
542 gdt_base dd 0xbadf00d ; space for GDT linear address
545 gdt: ; 0: null segment
548 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
551 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
554 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
557 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
560 ; 5: return to real-mode 16bit code segment (sel: 28h)
564 ; pseudo IDTR descriptor for real-mode IVT at address 0
567 rmidt: dw 3ffh ; IVT limit (1kb / 256 entries)
570 ; vi:set ts=8 sts=8 sw=8 ft=nasm: