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
38 call warning ; issue a warning and allow the user to abort
46 ; calculate GDT linear address
53 ; set tmp segment bases to match the linear address of our current seg
57 mov word [gdt + 18h + 2], ax ; tmp pm code base
58 mov word [gdt + 20h + 2], ax ; tmp pm data base
59 mov word [gdt + 28h + 2], ax ; ret-to-realmode code
61 mov byte [gdt + 18h + 4], al
62 mov byte [gdt + 20h + 4], al
63 mov byte [gdt + 28h + 4], al
77 .pm: mov ax, 20h ; tmp data selector
79 mov ax, 10h ; dest data selector
82 ; copy main program high
84 mov esi, _ldr_main_start
86 mov ecx, _main_size + 3
91 mov eax, [mem_map_size]
92 mov [es:boot_mem_map_size], eax
95 mov ecx, 32 ; 128 bytes
106 ; return to real mode
114 jmp 42h:.loadcs16 ; 42 seg is modifed at the start
121 ; restore real-mode IVT
130 str_errvm86 db 'Error: memory manager detected! Stop it and try again (e.g. emm386 off)',10,0
131 str_enterpm db 'Entering 32bit protected mode ...',10,0
134 ; warns the user about the experimental and buggy state of this
135 ; protected mode system, and allows aborting if having to reboot later
146 db 'WARNING: this program uses an experimental protected mode kernel, which is ',10
147 db 'still in a very early stage of development, and will probably not be able to ',10
148 db 'return cleanly to DOS on exit. You might be forced to reboot after quitting!',10
149 db 'If this is not acceptable, press ESC now to abort.',10,10
150 db 'Press ESC to abort and return to DOS, any other key to continue...',10,0
157 call printstr ; print "Enable A20 line ... "
169 .done: mov si, .okstr
173 .infomsg db 'Enable A20 line:',0
174 .failstr db ' failed.',10,0
175 .okstr db ' success.',10,0
177 ; CF = 1 if A20 test fails (not enabled)
196 .done: mov [ds:si], dl
209 .info db ' fast ...',0
211 KBC_DATA_PORT equ 0x60
212 KBC_CMD_PORT equ 0x64
213 KBC_STATUS_PORT equ 0x64
214 KBC_CMD_WR_OUTPORT equ 0xd1
216 KBC_STAT_IN_FULL equ 2
222 mov al, KBC_CMD_WR_OUTPORT
226 out KBC_DATA_PORT, al
228 .info db ' kbd ...',0
231 in al, KBC_STATUS_PORT
232 and al, KBC_STAT_IN_FULL
237 ; ---------------------- memory detection -----------------------
240 mov si, memdet_detram
242 mov si, memdet_e820_msg
249 mov si, memdet_detram
251 mov si, memdet_e801_msg
258 mov si, memdet_detram
260 mov esi, memdet_88_msg
267 mov si, memdet_detram
269 mov esi, memdet_cmos_msg
276 mov si, memdet_fail_msg
285 str_fail db 'failed',10,0
286 memdet_fail_msg db 'Failed to detect available memory!',10,0
287 memdet_detram db 'Detecting RAM '
288 memdet_e820_msg db '(BIOS 15h/0xe820)... ',0
289 memdet_e801_msg db '(BIOS 15h/0xe801)... ',0
290 memdet_88_msg db '(BIOS 15h/0x88, max 64mb)... ',0
291 memdet_cmos_msg db '(CMOS)...',0
293 ; detect extended memory using BIOS call 15h/e820
295 mov dword [mem_map_size], 0
309 ; skip areas starting above 4GB as we won't be able to use them
310 cmp dword [di + 4], 0
313 ; only care for type 1 (usable ram), otherwise ignore
314 cmp dword [di + 16], 1
319 mov ebp, [mem_map_size]
320 mov [ebp * 8 + esi], eax
322 ; skip areas with 0 size (also clamp size to 4gb)
324 cmp dword [edi + 12], 0
326 ; high part is non-zero, make low part ffffffff
332 ; if both high and low parts are zero, ignore
337 .skiph0:mov [ebp * 8 + esi + 4], eax
338 inc dword [mem_map_size]
341 ; terminate the loop if ebx was reset to 0
349 .fail: ; if size > 0, then it's not a failure, just the end
350 cmp dword [mem_map_size], 0
355 .buffer times 32 db 0
357 ; detect extended memory using BIOS call 15h/e801
360 mov ebp, [mem_map_size]
376 .foo1: mov dword [si], 100000h
378 ; first size is in KB, convert to bytes
381 ; overflow means it's >4GB, clamp to 4GB
383 .foo2: mov [si + 4], eax
384 inc dword [mem_map_size]
387 mov dword [si + 8], 1000000h
389 ; second size is in 64kb blocks, convert to bytes
392 ; overflow means it's >4GB, clamp to 4GB
394 .foo3: mov [si + 12], eax
395 inc dword [mem_map_size]
404 ; reportedly some BIOS implementations fail to clear CF on success
413 ; ax has size in KB, convert to bytes in eax
418 mov dword [si], 100000h
421 mov dword [mem_map_size], 1
439 ; ax has size in KB, convert to bytes in eax
444 mov dword [si], 100000h
446 mov dword [mem_map_size], 1
455 mem_map times 128 db 0
458 ; ----------------------- serial console ------------------------
463 mov dx, UART_BASE + 3 ; LCTL
466 mov dx, UART_BASE ; DIVLO
467 mov al, UART_DIVISOR & 0xff
470 mov al, UART_DIVISOR >> 8
472 mov dx, UART_BASE + 3 ; LCTL
476 mov al, 0xb ; DTR/RTS/OUT2
494 .nolf: call ser_putchar
498 %endif ; def CON_SERIAL
505 cmp al, 10 ; check for line-feed and insert CR before it
528 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
529 enterpm_sel dw 8 ; selector for far jump to protected mode
531 gdt_lim dw 47 ; GDT limit
532 gdt_base dd 0xbadf00d ; space for GDT linear address
535 gdt: ; 0: null segment
538 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
541 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
544 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
547 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
550 ; 5: return to real-mode 16bit code segment (sel: 28h)
554 ; pseudo IDTR descriptor for real-mode IVT at address 0
557 rmidt: dw 3ffh ; IVT limit (1kb / 256 entries)
560 ; vi:set ts=8 sts=8 sw=8 ft=nasm: