From 909220d3f4b870009592bb5512f3fce0d5d748b4 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 20 Nov 2023 23:03:50 +0200 Subject: [PATCH] initial commit --- .gitignore | 9 +++ README.md | 16 +++++ bootbios/Makefile | 17 +++++ bootbios/bootbios.ld | 15 +++++ bootbios/src/boot.asm | 36 ++++++++++ bootefi/Makefile | 39 +++++++++++ bootefi/src/bootefi.asm | 172 +++++++++++++++++++++++++++++++++++++++++++++++ bootefi/src/hdr.asm | 64 ++++++++++++++++++ bootefi/src/serial.inc | 15 +++++ kern/Makefile | 59 ++++++++++++++++ kern/kern.ld | 25 +++++++ 11 files changed, 467 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 bootbios/Makefile create mode 100644 bootbios/bootbios.ld create mode 100644 bootbios/src/boot.asm create mode 100644 bootefi/Makefile create mode 100644 bootefi/src/bootefi.asm create mode 100644 bootefi/src/hdr.asm create mode 100644 bootefi/src/serial.inc create mode 100644 kern/Makefile create mode 100644 kern/kern.ld diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..326ca30 --- /dev/null +++ b/.gitignore @@ -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 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 index 0000000..d2f6bb1 --- /dev/null +++ b/bootbios/Makefile @@ -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 index 0000000..269d757 --- /dev/null +++ b/bootbios/bootbios.ld @@ -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 index 0000000..0bbbea7 --- /dev/null +++ b/bootbios/src/boot.asm @@ -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 index 0000000..a1f03db --- /dev/null +++ b/bootefi/Makefile @@ -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 index 0000000..f5a52b4 --- /dev/null +++ b/bootefi/src/bootefi.asm @@ -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 index 0000000..bed494d --- /dev/null +++ b/bootefi/src/hdr.asm @@ -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 index 0000000..74fcf0b --- /dev/null +++ b/bootefi/src/serial.inc @@ -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 index 0000000..3da938c --- /dev/null +++ b/kern/Makefile @@ -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 index 0000000..5647bc4 --- /dev/null +++ b/kern/kern.ld @@ -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 = .; +} -- 1.7.10.4