initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 30 Sep 2023 03:49:20 +0000 (06:49 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 30 Sep 2023 03:49:20 +0000 (06:49 +0300)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
com32.ld [new file with mode: 0644]
src/loader.asm [new file with mode: 0644]
src/startup.asm [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..dc5c1f6
--- /dev/null
@@ -0,0 +1,8 @@
+*.o
+*.d
+*.swp
+*.com
+*.map
+RUN
+disasm
+dosbox.conf
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..a3411a3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+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 $< >$@
diff --git a/com32.ld b/com32.ld
new file mode 100644 (file)
index 0000000..04c9f88
--- /dev/null
+++ b/com32.ld
@@ -0,0 +1,31 @@
+OUTPUT_FORMAT(binary)
+ENTRY(_start)
+
+SECTIONS {
+       /* loader starts at <seg>:100h */
+       . = 0x100;
+       .loader : {
+               * (.loader);
+               * (.ldrtext);
+       }
+
+       /* main program will be moved to 2MB by the loader */
+       . = 2M;
+       _main_start = .;
+       .startup : { * (.startup); }
+       .text : { * (.text*); }
+       .rodata : { * (.rodata*); }
+       .data : { * (.data*); }
+
+       .bss ALIGN(4): {
+               _bss_start = .;
+               * (.bss*);
+               * (COMMON);
+               . = ALIGN(4);
+               _bss_end = .;
+       }
+       _bss_size = SIZEOF(.bss);
+
+       _main_size = . - _main_start;
+       _mem_start = .;
+}
diff --git a/src/loader.asm b/src/loader.asm
new file mode 100644 (file)
index 0000000..4f3d99d
--- /dev/null
@@ -0,0 +1,216 @@
+       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:
diff --git a/src/startup.asm b/src/startup.asm
new file mode 100644 (file)
index 0000000..8c2b643
--- /dev/null
@@ -0,0 +1,14 @@
+       bits 32
+       section .ldrtext
+
+       global startup
+startup:
+       mov ebx, 0xb8000
+       sub ebx, [tmpsegbase]
+       mov byte [ebx], '@'
+       ret
+
+       global tmpsegbase
+tmpsegbase dd 0
+
+; vi:set ts=8 sts=8 sw=8 ft=nasm: