--- /dev/null
+csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c)
+ssrc = $(wildcard src/*.asm) $(wildcard src/libc/*.asm)
+obj = $(csrc:.c=.o) $(ssrc:.asm=.o)
+dep = $(csrc:.c=.d)
+bin = test.com
+
+warn = -pedantic -Wall
+inc = -Isrc -Isrc/libc
+
+CFLAGS = -m32 -march=i386 $(warn) $(opt) $(dbg) -fno-pic -ffreestanding -nostdinc $(inc) $(def)
+LDFLAGS = -m elf_i386 -nostdlib -T com32.ld -Map test.map
+
+$(bin): $(obj)
+ $(LD) -o $@ $(obj) $(LDFLAGS)
+
+-include $(dep)
+
+%.o: %.asm
+ nasm -o $@ -f elf $<
+
+%.s: %.c
+ $(CC) $(CFLAGS) -S $< -o $@
+
+.PHONY: clean
+clean:
+ rm -f $(obj) $(bin)
+
+.PHONY: cleandep
+cleandep:
+ rm -f $(dep)
+
+disasm: $(bin)
+ ndisasm -o 0x100 -b 16 $< >$@
--- /dev/null
+ section .loader
+
+ extern startup
+ extern tmpsegbase
+
+ [bits 16]
+ global _start
+_start:
+ cli
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+ mov fs, ax ; this will store the original real mode segment
+ mov ss, ax
+ ; modify the return to real mode jump segment
+ mov [.jmpcs16 + 3], ax
+
+ xor ax, ax
+ mov sp, ax
+
+
+ call enable_a20
+
+ ; calculate GDT linear address
+ xor eax, eax
+ mov ax, cs
+ shl eax, 4
+ mov [tmpsegbase], eax ; save segment base
+ add eax, gdt
+ mov [gdt_base], eax
+
+ ; set tmp segment bases to match the linear address of our current seg
+ xor eax, eax
+ mov ax, cs
+ shl eax, 4
+ mov word [gdt + 18h + 2], ax ; tmp pm code base
+ mov word [gdt + 20h + 2], ax ; tmp pm data base
+ mov word [gdt + 28h + 2], ax ; ret-to-realmode code
+ shr eax, 16
+ mov byte [gdt + 18h + 4], al
+ mov byte [gdt + 20h + 4], al
+ mov byte [gdt + 28h + 4], al
+
+ mov si, str_enterpm
+ call printstr
+
+ lgdt [gdt_lim]
+
+ mov eax, cr0
+ or eax, 1
+ mov cr0, eax
+
+ jmp 18h:.pm
+
+ [bits 32]
+.pm: mov ax, 20h ; tmp data selector
+ mov ds, ax
+ mov ss, ax
+ mov ax, 10h ; dest data selector
+ mov es, ax
+
+ mov esp, 200000h
+
+ call startup
+
+ ; return to real mode
+ jmp 28h:.rm
+
+ [bits 16]
+.rm: mov eax, cr0
+ and ax, 0xfffe
+ mov cr0, eax
+.jmpcs16:
+ jmp 42h:.loadcs16 ; 42 seg is modifed at the start (TODO)
+.loadcs16:
+ mov ax, fs
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov ax, 4c00h
+ int 21h
+
+str_enterpm db 'Entering 32bit protected mode ...',10,0
+
+enable_a20:
+ call test_a20
+ jnc .ret
+
+ mov si, .infomsg
+ call printstr ; print "Enable A20 line ... "
+
+ call enable_a20_kbd
+ call test_a20
+ jnc .done
+ call enable_a20_fast
+ call test_a20
+ jnc .done
+ mov si, .failstr
+ call printstr
+ mov ax, 4c00h
+ int 21h
+.done: mov si, .okstr
+ call printstr
+.ret: ret
+
+.infomsg db 'Enable A20 line:',0
+.failstr db ' failed.',10,0
+.okstr db ' success.',10,0
+
+ ; CF = 1 if A20 test fails (not enabled)
+test_a20:
+ push ds
+ push es
+ xor ax, ax
+ mov ds, ax
+ not ax
+ mov es, ax
+ mov si, 420h
+ mov di, 430h
+ mov dl, [ds:si]
+ mov dh, [es:di]
+ mov [ds:si], al
+ not ax
+ mov [es:di], al
+ cmp al, [ds:si]
+ clc
+ jnz .done
+ stc
+.done: mov [ds:si], dl
+ mov [es:di], dh
+ pop es
+ pop ds
+ ret
+
+enable_a20_fast:
+ mov si, .info
+ call printstr
+ in al, 92h
+ or al, 2
+ out 92h, al
+ ret
+.info db ' fast ...',0
+
+KBC_DATA_PORT equ 0x60
+KBC_CMD_PORT equ 0x64
+KBC_STATUS_PORT equ 0x64
+KBC_CMD_WR_OUTPORT equ 0xd1
+
+KBC_STAT_IN_FULL equ 2
+
+enable_a20_kbd:
+ mov si, .info
+ call printstr
+ call kbc_wait_write
+ mov al, KBC_CMD_WR_OUTPORT
+ out KBC_CMD_PORT, al
+ call kbc_wait_write
+ mov al, 0xdf
+ out KBC_DATA_PORT, al
+ ret
+.info db ' kbd ...',0
+
+kbc_wait_write:
+ in al, KBC_STATUS_PORT
+ and al, KBC_STAT_IN_FULL
+ jnz kbc_wait_write
+ ret
+
+printstr:
+ lodsb
+ test al, al
+ jz .end
+ cmp al, 10 ; check for line-feed and insert CR before it
+ jnz .nolf
+ push ax
+ mov dl, 13
+ mov ah, 2
+ int 21h
+ pop ax
+.nolf: mov ah, 2
+ mov dl, al
+ int 21h
+ jmp printstr
+.end: ret
+
+
+ align 4
+enterpm dd 0xbad00d ; space for linear address for far jump to pmode
+enterpm_sel dw 8 ; selector for far jump to protected mode
+ align 4
+gdt_lim dw 47 ; GDT limit
+gdt_base dd 0xbadf00d ; space for GDT linear address
+
+ align 8
+gdt: ; 0: null segment
+ dd 0
+ dd 0
+ ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
+ dd 0000ffffh
+ dd 00cf9a00h
+ ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
+ dd 0000ffffh
+ dd 00cf9200h
+ ; 3: tmp code (will set base before entering pmode)
+ dd 0000ffffh
+ dd 00cf9a00h
+ ; 4: tmp data (will set base before entering pmode)
+ dd 0000ffffh
+ dd 00cf9200h
+ ; 5: return to real-mode 16bit code segment
+ dd 0000ffffh
+ dd 00009a00h
+
+
+; vi:set ts=8 sts=8 sw=8 ft=nasm: