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
78 .pm: mov ax, 20h ; tmp data selector
80 mov ax, 10h ; dest data selector
83 ; copy main program high
85 mov esi, _ldr_main_start
87 mov ecx, _main_size + 3
92 mov eax, [mem_map_size]
93 mov [es:boot_mem_map_size], eax
96 mov ecx, 32 ; 128 bytes
107 ; return to real mode
115 jmp 42h:.loadcs16 ; 42 seg is modifed at the start
122 ; restore real-mode IVT
131 str_errvm86 db 'Error: memory manager detected! Stop it and try again (e.g. emm386 off)',10,0
132 str_enterpm db 'Entering 32bit protected mode ...',10,0
136 ; warns the user about the experimental and buggy state of this
137 ; protected mode system, and allows aborting if having to reboot later
148 db 'WARNING: this program uses an experimental protected mode kernel, which is ',10
149 db 'still in a very early stage of development, and will probably not be able to ',10
150 db 'return cleanly to DOS on exit. You might be forced to reboot after quitting!',10
151 db 'If this is not acceptable, press ESC now to abort.',10,10
152 db 'Press ESC to abort and return to DOS, any other key to continue...',10,0
156 ; ---------------------- A20 address line enable -----------------------
163 call printstr ; print "Enable A20 line ... "
175 .done: mov si, .okstr
179 .infomsg db 'Enable A20 line:',0
180 .failstr db ' failed.',10,0
181 .okstr db ' success.',10,0
183 ; CF = 1 if A20 test fails (not enabled)
202 .done: mov [ds:si], dl
215 .info db ' fast ...',0
217 KBC_DATA_PORT equ 0x60
218 KBC_CMD_PORT equ 0x64
219 KBC_STATUS_PORT equ 0x64
220 KBC_CMD_WR_OUTPORT equ 0xd1
222 KBC_STAT_IN_FULL equ 2
228 mov al, KBC_CMD_WR_OUTPORT
232 out KBC_DATA_PORT, al
234 .info db ' kbd ...',0
237 in al, KBC_STATUS_PORT
238 and al, KBC_STAT_IN_FULL
243 ; ---------------------- memory detection -----------------------
246 mov si, memdet_detram
248 mov si, memdet_e820_msg
255 mov si, memdet_detram
257 mov si, memdet_e801_msg
264 mov si, memdet_detram
266 mov esi, memdet_88_msg
273 mov si, memdet_detram
275 mov esi, memdet_cmos_msg
282 mov si, memdet_fail_msg
291 str_fail db 'failed',10,0
292 memdet_fail_msg db 'Failed to detect available memory!',10,0
293 memdet_detram db 'Detecting RAM '
294 memdet_e820_msg db '(BIOS 15h/0xe820)... ',0
295 memdet_e801_msg db '(BIOS 15h/0xe801)... ',0
296 memdet_88_msg db '(BIOS 15h/0x88, max 64mb)... ',0
297 memdet_cmos_msg db '(CMOS)...',0
299 ; detect extended memory using BIOS call 15h/e820
301 mov dword [mem_map_size], 0
315 ; skip areas starting above 4GB as we won't be able to use them
316 cmp dword [di + 4], 0
319 ; only care for type 1 (usable ram), otherwise ignore
320 cmp dword [di + 16], 1
325 mov ebp, [mem_map_size]
326 mov [ebp * 8 + esi], eax
328 ; skip areas with 0 size (also clamp size to 4gb)
330 cmp dword [edi + 12], 0
332 ; high part is non-zero, make low part ffffffff
338 ; if both high and low parts are zero, ignore
343 .skiph0:mov [ebp * 8 + esi + 4], eax
344 inc dword [mem_map_size]
347 ; terminate the loop if ebx was reset to 0
355 .fail: ; if size > 0, then it's not a failure, just the end
356 cmp dword [mem_map_size], 0
361 .buffer times 32 db 0
363 ; detect extended memory using BIOS call 15h/e801
366 mov ebp, [mem_map_size]
382 .foo1: mov dword [si], 100000h
384 ; first size is in KB, convert to bytes
387 ; overflow means it's >4GB, clamp to 4GB
389 .foo2: mov [si + 4], eax
390 inc dword [mem_map_size]
393 mov dword [si + 8], 1000000h
395 ; second size is in 64kb blocks, convert to bytes
398 ; overflow means it's >4GB, clamp to 4GB
400 .foo3: mov [si + 12], eax
401 inc dword [mem_map_size]
410 ; reportedly some BIOS implementations fail to clear CF on success
419 ; ax has size in KB, convert to bytes in eax
424 mov dword [si], 100000h
427 mov dword [mem_map_size], 1
445 ; ax has size in KB, convert to bytes in eax
450 mov dword [si], 100000h
452 mov dword [mem_map_size], 1
461 mem_map times 128 db 0
464 ; ----------------------- serial console ------------------------
469 mov dx, UART_BASE + 3 ; LCTL
472 mov dx, UART_BASE ; DIVLO
473 mov al, UART_DIVISOR & 0xff
476 mov al, UART_DIVISOR >> 8
478 mov dx, UART_BASE + 3 ; LCTL
482 mov al, 0xb ; DTR/RTS/OUT2
500 .nolf: call ser_putchar
504 %endif ; def CON_SERIAL
511 cmp al, 10 ; check for line-feed and insert CR before it
534 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
535 enterpm_sel dw 8 ; selector for far jump to protected mode
537 gdt_lim dw 47 ; GDT limit
538 gdt_base dd 0xbadf00d ; space for GDT linear address
541 gdt: ; 0: null segment
544 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
547 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
550 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
553 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
556 ; 5: return to real-mode 16bit code segment (sel: 28h)
560 ; pseudo IDTR descriptor for real-mode IVT at address 0
563 rmidt: dw 3ffh ; IVT limit (1kb / 256 entries)
566 ; vi:set ts=8 sts=8 sw=8 ft=nasm: