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
28 call warning ; issue a warning and allow the user to abort
31 ; check for VM86 and abort
36 ; try to return to real mode
48 mov di, 30ah ; pretend to be windows 3.1
52 ; we got a function in ds:si
55 pop es ; es <- func seg
57 mov word [vmswitch_seg], es
58 mov word [vmswitch_off], si
59 xor ax, ax ; return to real mode
60 cli ; just make sure nothing enabled intr behind out back
88 ; calculate GDT linear address
95 ; set tmp segment bases to match the linear address of our current seg
99 mov word [gdt + 18h + 2], ax ; tmp pm code base
100 mov word [gdt + 20h + 2], ax ; tmp pm data base
101 mov word [gdt + 28h + 2], ax ; ret-to-realmode code
103 mov byte [gdt + 18h + 4], al
104 mov byte [gdt + 20h + 4], al
105 mov byte [gdt + 28h + 4], al
110 ; change video mode now, to avoid having to bring in all the int86 code
123 .pm: mov ax, 20h ; tmp data selector
125 mov ax, 10h ; dest data selector
128 ; copy main program high
130 mov esi, _ldr_main_start
132 mov ecx, _main_size + 3
137 mov eax, [mem_map_size]
138 mov [es:boot_mem_map_size], eax
140 mov edi, boot_mem_map
141 mov ecx, 32 ; 128 bytes
152 ; return to real mode
160 jmp 42h:.loadcs16 ; 42 seg is modifed at the start
167 ; restore real-mode IVT
170 ; switch back to text mode
174 ; if we used GEMMIS to exit vm86, switch back to it
175 cmp dword [vmswitch], 0
179 ; broadcast windows exit
193 str_gemmis db 'Memory manager detected, trying to take control...',0
194 str_errvm86 db 'Error: memory manager running. Stop it and try again (e.g. emm386 off)',10,0
195 str_enterpm db 'Entering 32bit protected mode ...',10,0
203 ; warns the user about the experimental and buggy state of this
204 ; protected mode system, and allows aborting if having to reboot later
215 db 'WARNING: this program uses an experimental protected mode kernel, which is ',10
216 db 'still in a very early stage of development, and will probably not be able to ',10
217 db 'return cleanly to DOS on exit. You might be forced to reboot after quitting!',10
218 db 'If this is not acceptable, press ESC now to abort.',10,10
219 db 'Press ESC to abort and return to DOS, any other key to continue...',10,10,0
223 ; ---------------------- A20 address line enable -----------------------
230 call printstr ; print "Enable A20 line ... "
242 .done: mov si, msg_okstr
246 .infomsg db 'Enable A20 line:',0
247 msg_failstr db ' failed.',10,0
248 msg_okstr db ' success.',10,0
250 ; CF = 1 if A20 test fails (not enabled)
269 .done: mov [ds:si], dl
282 .info db ' fast ...',0
284 KBC_DATA_PORT equ 0x60
285 KBC_CMD_PORT equ 0x64
286 KBC_STATUS_PORT equ 0x64
287 KBC_CMD_WR_OUTPORT equ 0xd1
289 KBC_STAT_IN_FULL equ 2
295 mov al, KBC_CMD_WR_OUTPORT
299 out KBC_DATA_PORT, al
301 .info db ' kbd ...',0
304 in al, KBC_STATUS_PORT
305 and al, KBC_STAT_IN_FULL
310 ; ---------------------- memory detection -----------------------
313 mov si, memdet_detram
315 mov si, memdet_e820_msg
322 mov si, memdet_detram
324 mov si, memdet_e801_msg
331 mov si, memdet_detram
333 mov esi, memdet_88_msg
340 mov si, memdet_detram
342 mov esi, memdet_cmos_msg
349 mov si, memdet_fail_msg
358 str_fail db 'failed',10,0
359 memdet_fail_msg db 'Failed to detect available memory!',10,0
360 memdet_detram db 'Detecting RAM '
361 memdet_e820_msg db '(BIOS 15h/0xe820)... ',0
362 memdet_e801_msg db '(BIOS 15h/0xe801)... ',0
363 memdet_88_msg db '(BIOS 15h/0x88, max 64mb)... ',0
364 memdet_cmos_msg db '(CMOS)...',0
366 ; detect extended memory using BIOS call 15h/e820
368 mov dword [mem_map_size], 0
382 ; skip areas starting above 4GB as we won't be able to use them
383 cmp dword [di + 4], 0
386 ; only care for type 1 (usable ram), otherwise ignore
387 cmp dword [di + 16], 1
392 mov ebp, [mem_map_size]
393 mov [ebp * 8 + esi], eax
395 ; skip areas with 0 size (also clamp size to 4gb)
397 cmp dword [edi + 12], 0
399 ; high part is non-zero, make low part ffffffff
405 ; if both high and low parts are zero, ignore
410 .skiph0:mov [ebp * 8 + esi + 4], eax
411 inc dword [mem_map_size]
414 ; terminate the loop if ebx was reset to 0
422 .fail: ; if size > 0, then it's not a failure, just the end
423 cmp dword [mem_map_size], 0
428 .buffer times 32 db 0
430 ; detect extended memory using BIOS call 15h/e801
433 mov ebp, [mem_map_size]
449 .foo1: mov dword [si], 100000h
451 ; first size is in KB, convert to bytes
454 ; overflow means it's >4GB, clamp to 4GB
456 .foo2: mov [si + 4], eax
457 inc dword [mem_map_size]
460 mov dword [si + 8], 1000000h
462 ; second size is in 64kb blocks, convert to bytes
465 ; overflow means it's >4GB, clamp to 4GB
467 .foo3: mov [si + 12], eax
468 inc dword [mem_map_size]
477 ; reportedly some BIOS implementations fail to clear CF on success
486 ; ax has size in KB, convert to bytes in eax
491 mov dword [si], 100000h
494 mov dword [mem_map_size], 1
512 ; ax has size in KB, convert to bytes in eax
517 mov dword [si], 100000h
519 mov dword [mem_map_size], 1
528 mem_map times 128 db 0
531 ; ----------------------- serial console ------------------------
536 mov dx, UART_BASE + 3 ; LCTL
539 mov dx, UART_BASE ; DIVLO
540 mov al, UART_DIVISOR & 0xff
543 mov al, UART_DIVISOR >> 8
545 mov dx, UART_BASE + 3 ; LCTL
549 mov al, 0xb ; DTR/RTS/OUT2
567 .nolf: call ser_putchar
571 %endif ; def CON_SERIAL
578 cmp al, 10 ; check for line-feed and insert CR before it
601 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
602 enterpm_sel dw 8 ; selector for far jump to protected mode
604 gdt_lim dw 47 ; GDT limit
605 gdt_base dd 0xbadf00d ; space for GDT linear address
608 gdt: ; 0: null segment
611 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
614 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
617 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
620 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
623 ; 5: return to real-mode 16bit code segment (sel: 28h)
627 ; pseudo IDTR descriptor for real-mode IVT at address 0
630 rmidt: dw 3ffh ; IVT limit (1kb / 256 entries)
633 ; vi:set ts=8 sts=8 sw=8 ft=nasm: