8 extern boot_mem_map_size
19 mov fs, ax ; this will store the original real mode segment
20 ; modify the return to real mode jump segment
21 mov [.jmpcs16 + 3], ax
23 ; put the stack on the next segment, should be free
30 call warning ; issue a warning and allow the user to abort
33 ; check for VM86 and abort
38 ; try to return to real mode
50 mov di, 30ah ; pretend to be windows 3.1
54 ; we got a function in ds:si
57 pop es ; es <- func seg
59 mov word [vmswitch_seg], es
60 mov word [vmswitch_off], si
61 xor ax, ax ; return to real mode
62 cli ; just make sure nothing enabled intr behind out back
90 ; calculate GDT linear address
97 ; set tmp segment bases to match the linear address of our current seg
101 mov word [gdt + 18h + 2], ax ; tmp pm code base
102 mov word [gdt + 20h + 2], ax ; tmp pm data base
103 mov word [gdt + 28h + 2], ax ; ret-to-realmode code
105 mov byte [gdt + 18h + 4], al
106 mov byte [gdt + 20h + 4], al
107 mov byte [gdt + 28h + 4], al
112 ; change video mode now, to avoid having to bring in all the int86 code
126 .pm: mov ax, 20h ; tmp data selector
128 mov ax, 10h ; dest data selector
131 ; copy main program high
133 mov esi, _ldr_main_start
135 mov ecx, _main_size + 3
140 mov eax, [mem_map_size]
141 mov [es:boot_mem_map_size], eax
143 mov edi, boot_mem_map
144 mov ecx, 32 ; 128 bytes
155 ; return to real mode
163 jmp 42h:.loadcs16 ; 42 seg is modifed at the start
170 ; restore real-mode IVT
173 ; switch back to text mode
177 ; if we used GEMMIS to exit vm86, switch back to it
178 cmp dword [vmswitch], 0
182 ; broadcast windows exit
196 str_gemmis db 'Memory manager detected, trying to take control...',0
197 str_errvm86 db 'Error: memory manager running. Stop it and try again (e.g. emm386 off)',10,0
198 str_enterpm db 'Entering 32bit protected mode ...',10,0
206 ; warns the user about the experimental and buggy state of this
207 ; protected mode system, and allows aborting if having to reboot later
218 db 'WARNING: this program uses an experimental protected mode kernel, which is ',10
219 db 'still in a very early stage of development, and will probably not be able to ',10
220 db 'return cleanly to DOS on exit. You might be forced to reboot after quitting!',10
221 db 'If this is not acceptable, press ESC now to abort.',10,10
222 db 'Press ESC to abort and return to DOS, any other key to continue...',10,10,0
226 ; ---------------------- A20 address line enable -----------------------
233 call printstr ; print "Enable A20 line ... "
245 .done: mov si, msg_okstr
249 .infomsg db 'Enable A20 line:',0
250 msg_failstr db ' failed.',10,0
251 msg_okstr db ' success.',10,0
253 ; CF = 1 if A20 test fails (not enabled)
272 .done: mov [ds:si], dl
285 .info db ' fast ...',0
287 KBC_DATA_PORT equ 0x60
288 KBC_CMD_PORT equ 0x64
289 KBC_STATUS_PORT equ 0x64
290 KBC_CMD_WR_OUTPORT equ 0xd1
292 KBC_STAT_IN_FULL equ 2
298 mov al, KBC_CMD_WR_OUTPORT
302 out KBC_DATA_PORT, al
304 .info db ' kbd ...',0
307 in al, KBC_STATUS_PORT
308 and al, KBC_STAT_IN_FULL
313 ; ---------------------- memory detection -----------------------
316 mov si, memdet_detram
318 mov si, memdet_e820_msg
325 mov si, memdet_detram
327 mov si, memdet_e801_msg
334 mov si, memdet_detram
336 mov esi, memdet_88_msg
343 mov si, memdet_detram
345 mov esi, memdet_cmos_msg
352 mov si, memdet_fail_msg
361 str_fail db 'failed',10,0
362 memdet_fail_msg db 'Failed to detect available memory!',10,0
363 memdet_detram db 'Detecting RAM ',0
364 memdet_e820_msg db '(BIOS 15h/0xe820)... ',0
365 memdet_e801_msg db '(BIOS 15h/0xe801)... ',0
366 memdet_88_msg db '(BIOS 15h/0x88, max 64mb)... ',0
367 memdet_cmos_msg db '(CMOS)...',0
369 ; detect extended memory using BIOS call 15h/e820
371 mov dword [mem_map_size], 0
385 ; skip areas starting above 4GB as we won't be able to use them
386 cmp dword [di + 4], 0
389 ; only care for type 1 (usable ram), otherwise ignore
390 cmp dword [di + 16], 1
395 mov ebp, [mem_map_size]
396 mov [ebp * 8 + esi], eax
398 ; skip areas with 0 size (also clamp size to 4gb)
400 cmp dword [edi + 12], 0
402 ; high part is non-zero, make low part ffffffff
408 ; if both high and low parts are zero, ignore
413 .skiph0:mov [ebp * 8 + esi + 4], eax
414 inc dword [mem_map_size]
417 ; terminate the loop if ebx was reset to 0
425 .fail: ; if size > 0, then it's not a failure, just the end
426 cmp dword [mem_map_size], 0
431 .buffer times 32 db 0
433 ; detect extended memory using BIOS call 15h/e801
436 mov ebp, [mem_map_size]
452 .foo1: mov dword [si], 100000h
454 ; first size is in KB, convert to bytes
457 ; overflow means it's >4GB, clamp to 4GB
459 .foo2: mov [si + 4], eax
460 inc dword [mem_map_size]
463 mov dword [si + 8], 1000000h
465 ; second size is in 64kb blocks, convert to bytes
468 ; overflow means it's >4GB, clamp to 4GB
470 .foo3: mov [si + 12], eax
471 inc dword [mem_map_size]
480 ; reportedly some BIOS implementations fail to clear CF on success
489 ; ax has size in KB, convert to bytes in eax
494 mov dword [si], 100000h
497 mov dword [mem_map_size], 1
515 ; ax has size in KB, convert to bytes in eax
520 mov dword [si], 100000h
522 mov dword [mem_map_size], 1
531 mem_map times 128 db 0
534 ; ----------------------- serial console ------------------------
539 mov dx, UART_BASE + 3 ; LCTL
542 mov dx, UART_BASE ; DIVLO
543 mov al, UART_DIVISOR & 0xff
546 mov al, UART_DIVISOR >> 8
548 mov dx, UART_BASE + 3 ; LCTL
552 mov al, 0xb ; DTR/RTS/OUT2
570 .nolf: call ser_putchar
574 %endif ; def CON_SERIAL
581 cmp al, 10 ; check for line-feed and insert CR before it
604 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
605 enterpm_sel dw 8 ; selector for far jump to protected mode
607 gdt_lim dw 47 ; GDT limit
608 gdt_base dd 0xbadf00d ; space for GDT linear address
611 gdt: ; 0: null segment
614 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
617 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
620 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
623 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
626 ; 5: return to real-mode 16bit code segment (sel: 28h)
630 ; pseudo IDTR descriptor for real-mode IVT at address 0
633 rmidt: dw 3ffh ; IVT limit (1kb / 256 entries)
667 .hexdig:add al, 'a' - 10
672 ; vi:set ts=8 sts=8 sw=8 ft=nasm: