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
187 str_gemmis db 'Memory manager detected, trying to take control...',0
188 str_errvm86 db 'Error: memory manager running. Stop it and try again (e.g. emm386 off)',10,0
189 str_enterpm db 'Entering 32bit protected mode ...',10,0
196 ; warns the user about the experimental and buggy state of this
197 ; protected mode system, and allows aborting if having to reboot later
208 db 'WARNING: this program uses an experimental protected mode kernel, which is ',10
209 db 'still in a very early stage of development, and will probably not be able to ',10
210 db 'return cleanly to DOS on exit. You might be forced to reboot after quitting!',10
211 db 'If this is not acceptable, press ESC now to abort.',10,10
212 db 'Press ESC to abort and return to DOS, any other key to continue...',10,10,0
216 ; ---------------------- A20 address line enable -----------------------
223 call printstr ; print "Enable A20 line ... "
235 .done: mov si, msg_okstr
239 .infomsg db 'Enable A20 line:',0
240 msg_failstr db ' failed.',10,0
241 msg_okstr db ' success.',10,0
243 ; CF = 1 if A20 test fails (not enabled)
262 .done: mov [ds:si], dl
275 .info db ' fast ...',0
277 KBC_DATA_PORT equ 0x60
278 KBC_CMD_PORT equ 0x64
279 KBC_STATUS_PORT equ 0x64
280 KBC_CMD_WR_OUTPORT equ 0xd1
282 KBC_STAT_IN_FULL equ 2
288 mov al, KBC_CMD_WR_OUTPORT
292 out KBC_DATA_PORT, al
294 .info db ' kbd ...',0
297 in al, KBC_STATUS_PORT
298 and al, KBC_STAT_IN_FULL
303 ; ---------------------- memory detection -----------------------
306 mov si, memdet_detram
308 mov si, memdet_e820_msg
315 mov si, memdet_detram
317 mov si, memdet_e801_msg
324 mov si, memdet_detram
326 mov esi, memdet_88_msg
333 mov si, memdet_detram
335 mov esi, memdet_cmos_msg
342 mov si, memdet_fail_msg
351 str_fail db 'failed',10,0
352 memdet_fail_msg db 'Failed to detect available memory!',10,0
353 memdet_detram db 'Detecting RAM '
354 memdet_e820_msg db '(BIOS 15h/0xe820)... ',0
355 memdet_e801_msg db '(BIOS 15h/0xe801)... ',0
356 memdet_88_msg db '(BIOS 15h/0x88, max 64mb)... ',0
357 memdet_cmos_msg db '(CMOS)...',0
359 ; detect extended memory using BIOS call 15h/e820
361 mov dword [mem_map_size], 0
375 ; skip areas starting above 4GB as we won't be able to use them
376 cmp dword [di + 4], 0
379 ; only care for type 1 (usable ram), otherwise ignore
380 cmp dword [di + 16], 1
385 mov ebp, [mem_map_size]
386 mov [ebp * 8 + esi], eax
388 ; skip areas with 0 size (also clamp size to 4gb)
390 cmp dword [edi + 12], 0
392 ; high part is non-zero, make low part ffffffff
398 ; if both high and low parts are zero, ignore
403 .skiph0:mov [ebp * 8 + esi + 4], eax
404 inc dword [mem_map_size]
407 ; terminate the loop if ebx was reset to 0
415 .fail: ; if size > 0, then it's not a failure, just the end
416 cmp dword [mem_map_size], 0
421 .buffer times 32 db 0
423 ; detect extended memory using BIOS call 15h/e801
426 mov ebp, [mem_map_size]
442 .foo1: mov dword [si], 100000h
444 ; first size is in KB, convert to bytes
447 ; overflow means it's >4GB, clamp to 4GB
449 .foo2: mov [si + 4], eax
450 inc dword [mem_map_size]
453 mov dword [si + 8], 1000000h
455 ; second size is in 64kb blocks, convert to bytes
458 ; overflow means it's >4GB, clamp to 4GB
460 .foo3: mov [si + 12], eax
461 inc dword [mem_map_size]
470 ; reportedly some BIOS implementations fail to clear CF on success
479 ; ax has size in KB, convert to bytes in eax
484 mov dword [si], 100000h
487 mov dword [mem_map_size], 1
505 ; ax has size in KB, convert to bytes in eax
510 mov dword [si], 100000h
512 mov dword [mem_map_size], 1
521 mem_map times 128 db 0
524 ; ----------------------- serial console ------------------------
529 mov dx, UART_BASE + 3 ; LCTL
532 mov dx, UART_BASE ; DIVLO
533 mov al, UART_DIVISOR & 0xff
536 mov al, UART_DIVISOR >> 8
538 mov dx, UART_BASE + 3 ; LCTL
542 mov al, 0xb ; DTR/RTS/OUT2
560 .nolf: call ser_putchar
564 %endif ; def CON_SERIAL
571 cmp al, 10 ; check for line-feed and insert CR before it
594 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
595 enterpm_sel dw 8 ; selector for far jump to protected mode
597 gdt_lim dw 47 ; GDT limit
598 gdt_base dd 0xbadf00d ; space for GDT linear address
601 gdt: ; 0: null segment
604 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
607 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
610 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
613 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
616 ; 5: return to real-mode 16bit code segment (sel: 28h)
620 ; pseudo IDTR descriptor for real-mode IVT at address 0
623 rmidt: dw 3ffh ; IVT limit (1kb / 256 entries)
626 ; vi:set ts=8 sts=8 sw=8 ft=nasm: