17 mov fs, ax ; this will store the original real mode segment
19 ; modify the return to real mode jump segment
20 mov [.jmpcs16 + 3], ax
25 ; check for VM86 and abort
38 ; calculate GDT linear address
45 ; set tmp segment bases to match the linear address of our current seg
49 mov word [gdt + 18h + 2], ax ; tmp pm code base
50 mov word [gdt + 20h + 2], ax ; tmp pm data base
51 mov word [gdt + 28h + 2], ax ; ret-to-realmode code
53 mov byte [gdt + 18h + 4], al
54 mov byte [gdt + 20h + 4], al
55 mov byte [gdt + 28h + 4], al
69 .pm: mov ax, 20h ; tmp data selector
71 mov ax, 10h ; dest data selector
74 ; copy main program high
76 mov esi, _ldr_main_start
78 mov ecx, _main_size + 3
105 jmp 42h:.loadcs16 ; 42 seg is modifed at the start
115 dbg_inpm db 'DBG: in pmode',10,0
116 dbg_retrm db 'DBG: returning to real mode...',10,0
118 str_errvm86 db 'Error: memory manager detected! Stop it and try again (e.g. emm386 off)',10,0
119 str_enterpm db 'Entering 32bit protected mode ...',10,0
126 call printstr ; print "Enable A20 line ... "
138 .done: mov si, .okstr
142 .infomsg db 'Enable A20 line:',0
143 .failstr db ' failed.',10,0
144 .okstr db ' success.',10,0
146 ; CF = 1 if A20 test fails (not enabled)
165 .done: mov [ds:si], dl
178 .info db ' fast ...',0
180 KBC_DATA_PORT equ 0x60
181 KBC_CMD_PORT equ 0x64
182 KBC_STATUS_PORT equ 0x64
183 KBC_CMD_WR_OUTPORT equ 0xd1
185 KBC_STAT_IN_FULL equ 2
191 mov al, KBC_CMD_WR_OUTPORT
195 out KBC_DATA_PORT, al
197 .info db ' kbd ...',0
200 in al, KBC_STATUS_PORT
201 and al, KBC_STAT_IN_FULL
205 UART_BASE equ 2f8h ; COM1: 3f8, COM2: 2f8
206 UART_DIVISOR equ 115200 / 9600 ; 9600 baud
209 mov dx, UART_BASE + 3 ; LCTL
212 mov dx, UART_BASE ; DIVLO
213 mov al, UART_DIVISOR & 0xff
216 mov al, UART_DIVISOR >> 8
218 mov dx, UART_BASE + 3 ; LCTL
222 mov al, 0xb ; DTR/RTS/OUT2
240 .nolf: call ser_putchar
248 cmp al, 10 ; check for line-feed and insert CR before it
257 .nolf: call ser_putchar
277 call ser_putchar_pmode
279 .nolf: call ser_putchar_pmode
285 enterpm dd 0xbad00d ; space for linear address for far jump to pmode
286 enterpm_sel dw 8 ; selector for far jump to protected mode
288 gdt_lim dw 47 ; GDT limit
289 gdt_base dd 0xbadf00d ; space for GDT linear address
292 gdt: ; 0: null segment
295 ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd (sel: 8)
298 ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw (sel: 10h)
301 ; 3: tmp code (will set base before entering pmode) (sel: 18h)
304 ; 4: tmp data (will set base before entering pmode) (sel: 20h)
307 ; 5: return to real-mode 16bit code segment (sel: 28h)
312 ; vi:set ts=8 sts=8 sw=8 ft=nasm: