initial commit master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 20 Nov 2023 21:03:50 +0000 (23:03 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 20 Nov 2023 21:03:50 +0000 (23:03 +0200)
.gitignore [new file with mode: 0644]
README.md [new file with mode: 0644]
bootbios/Makefile [new file with mode: 0644]
bootbios/bootbios.ld [new file with mode: 0644]
bootbios/src/boot.asm [new file with mode: 0644]
bootefi/Makefile [new file with mode: 0644]
bootefi/src/bootefi.asm [new file with mode: 0644]
bootefi/src/hdr.asm [new file with mode: 0644]
bootefi/src/serial.inc [new file with mode: 0644]
kern/Makefile [new file with mode: 0644]
kern/kern.ld [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..326ca30
--- /dev/null
@@ -0,0 +1,9 @@
+*.o
+*.d
+*.swp
+*.elf
+*.bin
+*.img
+*.map
+bootbios
+*.efi
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..3d61b7b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,16 @@
+New operating system project
+============================
+
+Short term goals:
+  - support booting from BIOS, EFI and multiboot boot loaders.
+  - equally usable from display/keyboard or serial port from early boot.
+  - support GDB debugging over serial port as early as possible.
+
+Long term goals:
+  - VM system with user/kernel priviledge levels.
+  - support for 32bit and 64bit mode operation.
+  - built-in C compiler and assembler (tcc?) like templeOS.
+  - usable on a 386 with 2MB RAM (don't ignore base memory).
+  - support for USB devices (at least HID and ideally also mass storage).
+  - networking (start with the NE2000 on the 486).
+  - graphical desktop (VBE + chip-specific drivers).
diff --git a/bootbios/Makefile b/bootbios/Makefile
new file mode 100644 (file)
index 0000000..d2f6bb1
--- /dev/null
@@ -0,0 +1,17 @@
+src = $(wildcard src/*.asm)
+obj = $(src:.asm=.o)
+bin = bootbios
+
+LDFLAGS = -m elf_i386 -T bootbios.ld -Map bootbios.map
+
+$(bin): $(obj)
+       $(LD) -o $(bin) $(obj) $(LDFLAGS)
+
+.SUFFIXES: .asm
+
+.asm.o:
+       nasm -o $@ -f elf $<
+
+.PHONY: clean
+clean:
+       rm -f $(OBJ)
diff --git a/bootbios/bootbios.ld b/bootbios/bootbios.ld
new file mode 100644 (file)
index 0000000..269d757
--- /dev/null
@@ -0,0 +1,15 @@
+OUTPUT_FORMAT(binary)
+
+SECTIONS {
+       . = 0x7c00;
+
+       .boot : { * (.boot); }
+
+       /* second stage boot loader */
+       .boot2 : {
+               * (.boot2);
+               /* pad to the next sector boundary */
+               . = ALIGN(512);
+       }
+       _boot2_size = SIZEOF(.boot2);
+}
diff --git a/bootbios/src/boot.asm b/bootbios/src/boot.asm
new file mode 100644 (file)
index 0000000..0bbbea7
--- /dev/null
@@ -0,0 +1,36 @@
+       bits 16
+       section .boot
+
+start:
+       cli
+       xor ax, ax
+       mov ds, ax
+       mov es, ax
+       mov ss, ax
+       jmp 0:.setcs
+.setcs:
+       mov sp, ax
+
+       mov si, str_load2
+       call printstr
+
+       sti
+hang:  hlt
+       jmp hang
+
+str_load2 db 'Loading 2nd stage boot loader...',13,10,0
+
+printstr:
+       lodsb
+       test al, al
+       jz .done
+       mov ah, 0eh
+       xor bx, bx
+       int 10h
+       jmp printstr
+.done: ret
+
+
+       times 510-($-$$) db 0
+       dw 0aa55h
+; vi:ft=nasm ts=8 sts=8 sw=8:
diff --git a/bootefi/Makefile b/bootefi/Makefile
new file mode 100644 (file)
index 0000000..a1f03db
--- /dev/null
@@ -0,0 +1,39 @@
+.PHONY: all
+all: disk.img
+
+bootx64.efi: bootefi.bin src/hdr.asm
+       nasm -o $@ -f bin src/hdr.asm
+
+bootefi.bin: src/bootefi.asm
+       nasm -o $@ -f bin $<
+
+part.img: bootx64.efi
+       dd if=/dev/zero of=$@ bs=1024 count=2080
+       mkfs -t vfat $@
+       mmd -i $@ ::/EFI
+       mmd -i $@ ::/EFI/BOOT
+       mcopy -i $@ $< ::/EFI/BOOT
+
+disk.img: part.img
+       dd if=/dev/zero of=$@ bs=1024 count=2048
+       echo start=2048 type=ef | sfdisk $@
+       dd if=$< of=$@ bs=512 seek=2048 conv=notrunc
+
+.PHONY: clean
+clean:
+       rm -f bootx64.efi bootefi.bin
+
+.PHONY: run
+run: disk.img
+       qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -hda $< -net none -serial stdio
+
+.PHONY: debug
+debug: disk.img
+       qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -S -s -hda $< -net none -serial stdio
+
+
+disasm: bootx64.efi
+       ndisasm -b 64 -o 0x1000 -e 4096 $< >$@
+
+disasm16: bootx64.efi
+       ndisasm -b 16 -o 0x1000 -e 4096 $< >$@
diff --git a/bootefi/src/bootefi.asm b/bootefi/src/bootefi.asm
new file mode 100644 (file)
index 0000000..f5a52b4
--- /dev/null
@@ -0,0 +1,172 @@
+       bits 64
+       org 1000h
+
+%include "src/serial.inc"
+
+BOOT_SERVICES          equ 96
+BOOT_GET_MEMORY_MAP    equ 56
+BOOT_EXIT_BOOT_SERVICES        equ 232
+
+start:
+       mov [efihandle], rcx
+       mov [systab], rdx
+
+       ; retrieve memory map
+       ; args: RCX, RDX, R8, and R9.
+       lea rcx, [mmap_size]
+       lea rdx, [mmapbuf]
+       lea r8, [mmap_key]
+       lea r9, [mmap_descsz]
+       lea rax, [mmap_descver]
+       push rax
+       sub rsp, 32
+       mov rax, [systab]
+       mov rbx, [rax + BOOT_SERVICES]
+       call [rbx + BOOT_GET_MEMORY_MAP]
+       add rsp, 40
+       ; exit boot services
+       mov rcx, [efihandle]
+       mov rdx, [mmap_key]
+       mov rax, [systab]
+       mov rbx, [rax + BOOT_SERVICES]
+       call [rbx + BOOT_EXIT_BOOT_SERVICES]
+
+       ; move code to absolute 1000h
+       call get_rip
+.after_call:
+       sub rax, .after_call - start
+       mov rsi, rax    ; source address
+       mov rdi, start  ; destination
+       mov rcx, end - start
+       shr rcx, 2      ; dwords
+       cld
+       rep movsd       ; copy code to make it absolute
+
+       mov rax, .abs
+       jmp rax
+.abs:
+       call setup_serial
+
+       ; switch to 32-bit compatibility long mode
+       lgdt [gdtlim]
+       push word 8
+       push qword start32
+       retfq
+
+get_rip:
+       mov rax, [rsp]
+       ret
+
+       ; serial port setup
+setup_serial:
+       ; set clock divisor
+       mov al, LCTL_DLAB
+       mov dx, UART_LCTL
+       out dx, al
+       mov ax, DIV_9600
+       mov dx, UART_DIVLO
+       out dx, al
+       mov al, ah
+       mov dx, UART_DIVHI
+       out dx, al
+       ; set format 8n1
+       mov al, LCTL_8N1
+       mov dx, UART_LCTL
+       out dx, al
+       ; clear and enable fifo
+       mov al, FIFO_ENABLE_CLEAR
+       mov dx, UART_FIFO
+       out dx, al
+       ; assert RTS and DTR
+       mov al, MCTL_DTR_RTS_OUT2
+       mov dx, UART_MCTL
+       out dx, al
+       ret
+
+
+; ----------- 32bit code ----------
+
+       bits 32
+start32:
+       mov ax, 10h
+       mov ds, ax
+       mov ss, ax
+       mov es, ax
+       mov gs, ax
+       mov fs, ax
+
+       ; disable paging to deactivate long mode
+       mov eax, cr0
+       and eax, 7fffffffh
+       mov cr0, eax
+
+       ; disable long mode (EFER.LME = 0)
+       ; TODO: EFER is MSR c0000080, LME is bit 8
+       mov ecx, 0c0000080h
+       rdmsr
+       and eax, 0fffffeffh
+       wrmsr
+
+       ; halt for ever
+       sti
+halt:  hlt
+       jmp halt
+
+ser_putchar:
+       mov ah, al
+       ; wait until transmit register is empty
+       mov dx, UART_LSTAT
+.wait: in al, dx
+       and al, LST_TREG_EMPTY
+       jz .wait
+       mov dx, UART_DATA
+       mov al, ah
+       out dx, al
+       ret
+
+ser_putstr:
+       mov al, [si]
+       test al, al
+       jz .done
+       call ser_putchar
+       inc si
+       jmp ser_putstr
+.done: ret
+
+
+; ---------- data ------------
+
+       align 8
+efihandle dq 0
+systab dq 0
+; memory map data
+mmap_size dq 4096
+mmap_key dq 0
+mmap_descsz dq 0
+mmap_descver dq 0
+
+       align 4096
+mmapbuf: times 4096 db 0
+
+str_hello db 'hello!',13,10,0
+
+       align 4
+gdtlim dw 31
+gdtbase        dq gdt
+
+       align 8
+gdt:   ; 0: null segment
+       dd 0, 0
+       ; 1: code - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
+       dd 0x0000ffff
+       dd 0x00cf9a00
+       ; 2: data - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
+       dd 0x0000ffff
+       dd 0x00cf9200
+       ; 3: code16
+       dd 0x0000ffff
+       dd 0x00009a00
+
+       align 4
+end:
+; vi:ft=nasm:
diff --git a/bootefi/src/hdr.asm b/bootefi/src/hdr.asm
new file mode 100644 (file)
index 0000000..bed494d
--- /dev/null
@@ -0,0 +1,64 @@
+; vi:ft=nasm:
+       org 0
+
+       ; DOS stub
+       db "MZ"
+       times 3ah db 0
+       dd 40h          ; PE offset
+       ; PE signature
+       db "PE",0,0
+       ; COFF header
+       dw 8664h        ; machine type: x86-64
+       dw 1            ; number of sections
+       dd 0            ; creation time
+       dd 0            ; offset to symbol table
+       dd 0            ; number of symbols
+       dw opthdr_end - opthdr  ; size of optional header
+       dw 2022h        ; characteristics: DLL, exec image, can handle > 2gb addr
+       ; optional header - standard fields
+opthdr:        dw 020bh        ; magic: PE32+
+       dw 0            ; linker version
+       dd prog_end - prog      ; size of code
+       dd 0            ; size of init data
+       dd 0            ; size of uninit data
+       dd prog         ; entry point
+       dd prog         ; base of code
+       ; optional header - windows-specific fields
+       dq 100000h      ; image base
+       dd 4096         ; section alignment
+       dd 4096         ; file alignment
+       dd 0            ; os version
+       dd 0            ; img version
+       dd 0            ; subsys version
+       dd 0
+       dd image_end    ; size of image
+       dd prog         ; size of headers
+       dd 0            ; checksum
+       dw 10           ; subsystem: EFI application
+       dw 0040h        ; DLL characteristics: relocatable at runtime
+       dq 4096         ; size of stack reserve
+       dq 4096         ; size of stack commit
+       dq 4096         ; size of heap reserve
+       dq 0            ; size of heap commit
+       dd 0
+       dd 0            ; number of rva and sizes
+opthdr_end:
+
+       ; sections
+       db ".text",0,0,0
+       dd image_end - prog     ; virtual size
+       dd prog         ; virtual address
+       dd image_end - prog     ; raw data size
+       dd prog         ; raw data
+       dd 0            ; relocations offset
+       dd 0            ; line numbers offset
+       dw 0            ; num reloc
+       dw 0            ; num line numbers
+       dd 60000020h    ; characteristics: exec, readable, code
+
+       align 4096
+prog:
+       incbin "bootefi.bin"
+prog_end:
+       align 4096
+image_end:
diff --git a/bootefi/src/serial.inc b/bootefi/src/serial.inc
new file mode 100644 (file)
index 0000000..74fcf0b
--- /dev/null
@@ -0,0 +1,15 @@
+UART_DATA              equ 0x3f8
+UART_DIVLO             equ 0x3f8
+UART_DIVHI             equ 0x3f9
+UART_FIFO              equ 0x3fa
+UART_LCTL              equ 0x3fb
+UART_MCTL              equ 0x3fc
+UART_LSTAT             equ 0x3fd
+DIV_9600               equ 115200 / 9600
+LCTL_8N1               equ 0x03
+LCTL_DLAB              equ 0x80
+FIFO_ENABLE_CLEAR      equ 0x07
+MCTL_DTR_RTS_OUT2      equ 0x0b
+LST_TREG_EMPTY         equ 0x20
+
+; vi:ft=nasm:
diff --git a/kern/Makefile b/kern/Makefile
new file mode 100644 (file)
index 0000000..3da938c
--- /dev/null
@@ -0,0 +1,59 @@
+csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c)
+ssrc = $(wildcard src/*.s) $(wildcard src/libc/*.s)
+
+obj = $(csrc:.c=.o) $(ssrc:.s=.o)
+dep = $(csrc:.c=.d)
+elf = kern.elf
+
+warn = -pedantic -Wall
+dbg = -g
+inc = -Isrc -Isrc/libc
+gccflags = -fno-pic -ffreestanding -nostdinc -fno-builtin -fcommon
+
+CFLAGS = $(ccarch) -march=i386 $(warn) $(opt) $(dbg) $(gccflags) $(inc) $(def) -MMD
+ASFLAGS = $(asarch) -march=i386 $(dbg) -nostdinc -fno-builtin $(inc)
+LDFLAGS = $(ldarch) -nostdlib -T kern.ld -print-gc-sections
+
+ifneq ($(shell uname -m), i386)
+       ccarch = -m32
+       asarch = --32
+       ldarch = -m elf_i386
+endif
+
+# uncomment to use a specific toolchain
+#TOOLPREFIX = x86_64-elf-
+
+CC = $(TOOLPREFIX)gcc
+AS = $(TOOLPREFIX)as
+LD = $(TOOLPREFIX)ld
+OBJCOPY = $(TOOLPREFIX)objcopy
+OBJDUMP = $(TOOLPREFIX)objdump
+
+
+$(elf): $(obj)
+       $(LD) -o $@ $(obj) -Map link.map $(LDFLAGS)
+
+%.o: %.S
+       $(CC) -o $@ $(CFLAGS) -c $<
+
+-include $(dep)
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(elf)
+
+
+.PHONY: cleandep
+cleandep:
+       rm -f $(dep)
+
+
+QEMUFLAGS = -serial file:serial.log
+
+.PHONY: run
+run: $(elf)
+       qemu-system-i386 -kernel $(elf) $(QEMUFLAGS)
+
+.PHONY: debug
+debug: $(elf)
+       qemu-system-i386 -kernel $(elf) $(QEMUFLAGS) -s -S
diff --git a/kern/kern.ld b/kern/kern.ld
new file mode 100644 (file)
index 0000000..5647bc4
--- /dev/null
@@ -0,0 +1,25 @@
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+       /* kernel loaded at 1MB */
+       . = 1M;
+       _kimg_start = .;
+
+       .startup : { * (.startup); }
+       .multiboot : { * (.multiboot); }
+       .text : { * (.text); }
+       .rodata : { * (.rodata); }
+       .data : { * (.data); }
+
+       .bss ALIGN(4): {
+               _bss_start = .;
+               * (.bss);
+               * (COMMON);
+               . = ALIGN(4);
+               _bss_end = .;
+       }
+       _bss_size = SIZEOF(.bss);
+
+       _kimg_size = . - _kimg_start;
+       _mem_start = .;
+}