From 9f4222e84f5dc35dca9a8f9ff45b3a7a8f9cc147 Mon Sep 17 00:00:00 2001 From: Allen <63997543+aaw3@users.noreply.github.com> Date: Sun, 15 Sep 2024 22:59:06 -0500 Subject: [PATCH] Add changes related to c implementation, printf --- Makefile | 68 ++++++ bochs_config | 7 + debug.sh | 1 + run.sh | 1 + src/bootloader/stage1/Makefile | 14 ++ src/bootloader/stage1/boot.asm | 368 +++++++++++++++++++++++++++++++ src/bootloader/stage2/Makefile | 33 +++ src/bootloader/stage2/linker.lnk | 12 + src/bootloader/stage2/main.asm | 22 ++ src/bootloader/stage2/main.c | 5 + src/bootloader/stage2/main.err | 3 + src/bootloader/stage2/stdint.h | 10 + src/bootloader/stage2/x86.asm | 6 + src/kernel/Makefile | 14 ++ src/kernel/kernel.asm | 43 ++++ test.txt | 1 + 16 files changed, 608 insertions(+) create mode 100644 Makefile create mode 100644 bochs_config create mode 100755 debug.sh create mode 100755 run.sh create mode 100644 src/bootloader/stage1/Makefile create mode 100644 src/bootloader/stage1/boot.asm create mode 100644 src/bootloader/stage2/Makefile create mode 100644 src/bootloader/stage2/linker.lnk create mode 100644 src/bootloader/stage2/main.asm create mode 100644 src/bootloader/stage2/main.c create mode 100644 src/bootloader/stage2/main.err create mode 100644 src/bootloader/stage2/stdint.h create mode 100644 src/bootloader/stage2/x86.asm create mode 100644 src/kernel/Makefile create mode 100644 src/kernel/kernel.asm create mode 100644 test.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e6b0276 --- /dev/null +++ b/Makefile @@ -0,0 +1,68 @@ +ASM=nasm +CC=gcc +CC16=/opt/watcom/binl/wcc +LD16=/opt/watcom/binl/wlink + +BUILD_DIR=build +SRC_DIR=src +TOOLS_DIR=tools + +.PHONY: all floppy_image kernel bootloader clean always tools_fat + +all: floppy_image tools_fat + +# +# Floppy Image +# +floppy_image: $(BUILD_DIR)/main_floppy.img + +$(BUILD_DIR)/main_floppy.img: bootloader kernel + dd if=/dev/zero of=$(BUILD_DIR)/main_floppy.img bs=512 count=2880 + mkfs.fat -F 12 -n "chaOS" $(BUILD_DIR)/main_floppy.img + dd if=${BUILD_DIR}/stage1.bin of=${BUILD_DIR}/main_floppy.img conv=notrunc + mcopy -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/stage2.bin "::stage2.bin" + mcopy -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/kernel.bin "::kernel.bin" + mcopy -i $(BUILD_DIR)/main_floppy.img test.txt "::test.txt" + +# +# Bootloader +# +bootloader: stage1 stage2 + +stage1: $(BUILD_DIR)/stage1.bin + + +$(BUILD_DIR)/stage1.bin: always + $(MAKE) -C $(SRC_DIR)/bootloader/stage1 BUILD_DIR=$(abspath $(BUILD_DIR)) + +stage2: $(BUILD_DIR)/stage2.bin + +$(BUILD_DIR)/stage2.bin: always + $(MAKE) -C $(SRC_DIR)/bootloader/stage2 BUILD_DIR=$(abspath $(BUILD_DIR)) + +# +# Kernel +# +kernel: $(BUILD_DIR)/kernel.bin +$(BUILD_DIR)/kernel.bin: always + $(MAKE) -C $(SRC_DIR)/kernel BUILD_DIR=$(abspath $(BUILD_DIR)) + +# +# Tools +# +tools_fat: $(BUILD_DIR)/tools/fat +$(BUILD_DIR)/tools/fat: always $(TOOLS_DIR)/fat/fat.c + mkdir -p $(BUILD_DIR)/tools + $(CC) $(TOOLS_DIR)/fat/fat.c -g -o $(BUILD_DIR)/tools/fat + +always: + mkdir -p $(BUILD_DIR) + +# +# Clean +# +clean: + $(MAKE) -C $(SRC_DIR)/bootloader/stage1 BUILD_DIR=$(abspath $(BUILD_DIR)) clean + $(MAKE) -C $(SRC_DIR)/bootloader/stage2 BUILD_DIR=$(abspath $(BUILD_DIR)) clean + $(MAKE) -C $(SRC_DIR)/kernel BUILD_DIR=$(abspath $(BUILD_DIR)) clean + rm -rf $(BUILD_DIR)/* \ No newline at end of file diff --git a/bochs_config b/bochs_config new file mode 100644 index 0000000..60ca286 --- /dev/null +++ b/bochs_config @@ -0,0 +1,7 @@ +megs: 128 +romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xfffe0000 +vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest +floppya: 1_44=build/main_floppy.img, status=inserted +boot: floppy +mouse: enabled=0 +display_library: sdl, options="gui_debug" \ No newline at end of file diff --git a/debug.sh b/debug.sh new file mode 100755 index 0000000..eef588c --- /dev/null +++ b/debug.sh @@ -0,0 +1 @@ +bochs -f bochs_config \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..52f414b --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +qemu-system-i386 -fda build/main_floppy.img diff --git a/src/bootloader/stage1/Makefile b/src/bootloader/stage1/Makefile new file mode 100644 index 0000000..e29a05d --- /dev/null +++ b/src/bootloader/stage1/Makefile @@ -0,0 +1,14 @@ +BUILD_DIR?=build/ +ASM?=nasm + +.PHONY: all clean + +all: stage1 + +stage1: $(BUILD_DIR)/stage1.bin + +$(BUILD_DIR)/stage1.bin: + $(ASM) boot.asm -f bin -o $(BUILD_DIR)/stage1.bin + +clean: + rm -f $(BUILD_DIR)/stage1.bin \ No newline at end of file diff --git a/src/bootloader/stage1/boot.asm b/src/bootloader/stage1/boot.asm new file mode 100644 index 0000000..f57f6f6 --- /dev/null +++ b/src/bootloader/stage1/boot.asm @@ -0,0 +1,368 @@ +org 0x7C00 ; BIOS loads at 0x7C00 always - set origin (offset) + +bits 16 ; emit 16-bit code + +%define ENDL 0X0D, 0xA ; CRLF + +; +; FAT-12 Header +; +jmp short start +nop ; 3 byte padding + +bdm_oem: db 'MSWIN4.1' ; OEM string as Windows 4.1 for max compatibility +bdb_bytes_per_sector: dw 512 +bdb_sectors_per_cluster: db 1 +bdb_reserved_sectors: dw 1 +bdb_fat_count: db 2 +bdb_dir_entries_count: dw 0E0h +bdb_total_sectors: dw 2880 ; 2880 * 512 = 1.44MB +bdb_media_descriptor_type: db 0F0h ; 3.5" Floppy +bdb_sectors_per_fat: dw 9 +bdb_sectors_per_track: dw 18 +bdb_heads: dw 2 +bdb_hidden_sectors: dd 0 +bdb_large_sector_count: dd 0 + +; extended boot record +ebr_drive_number: db 0 ; 0x00 for floppy, 0x80 for hard drive + db 0 ; reserved +ebr_signature: db 29h ; extended boot record signature +ebr_volume_id: db 53h, 28h, 14h, 76h ; volume serial number (can be any number) +ebr_volume_label: db 'chaOS ' ; volume label (11 bytes) + db 'FAT12 ' ; file system type (8 bytes) + + +start: + mov ax, 0 ; write to register ax + mov ds, ax ; set data segment to 0 + mov es, ax ; set extra segment to 0 + + ; setup stack + mov ss, ax ; set stack segment to 0 + mov sp, 0x7C00 ; set stack pointer to 0x7C00 + + ; BIOS offset fix + push es + push word .after + retf +.after: + + ; read from floppy disk + ; BIOS should set DL to drive number + mov [ebr_drive_number], dl ; set drive number in ebr + + ; print message + mov si, msg_load + call puts + + ; read drive params on BOOT rather than rely on data from DISK + push es + mov ah, 08h + int 13h + jc floppy_error + pop es + + and cl, 0x3F ; mask out high bits + xor ch, ch + mov [bdb_sectors_per_track], cx ; set sector count + + inc dh + mov [bdb_heads], dh ; set head count + + ; compute LBA of FAT root directory + mov ax, [bdb_sectors_per_fat] ; read FAT sectors + mov bl, [bdb_fat_count] + xor bh, bh + mul bx ; ax = (FAT sectors * FAT count) + add ax, [bdb_reserved_sectors] ; ax = LBA address of FAT root directory + push ax + + ; compute root directory size (number of sectors * 32) / bytes per sector + mov ax, [bdb_dir_entries_count] + shl ax, 5 ; ax = FAT sectors * 32 + xor dx, dx + div word [bdb_bytes_per_sector] ; sectors need to be read + + test dx, dx ; check if dx not 0, add 1 + jz .root_dir_after + inc ax ; add 1 to ax + ; partially full sector + +.root_dir_after: + + ; read root directory + mov cl, al ; number of sectors to read (root directory size) + pop ax + mov dl, [ebr_drive_number] ; drive number + mov bx, buffer ; buffer address + call disk_read + + ; search for kernel file + xor bx, bx + mov di, buffer + +.search_kernel: + mov si, file_stage2_bin ; kernel file name + mov cx, 11 ; compare 11 bytes + push di + repe cmpsb ; compare string + pop di + je .kernel_found + + add di, 32 ; move to next entry + inc bx + cmp bx, [bdb_dir_entries_count] + jl .search_kernel + + ; kernel not found + jmp kernel_not_found_error + + + + +.kernel_found: + ; di points to kernel file entry + mov ax, [di + 26] ; LBA address of kernel file (offset 26) + mov [stage2_cluster], ax + + ; load FAT from disk into memory + mov ax, [bdb_reserved_sectors] ; LBA address of FAT root directory + mov bx, buffer ; buffer address + mov cl, [bdb_sectors_per_fat] ; number of sectors to read + mov dl, [ebr_drive_number] ; drive number + call disk_read + + ; read kernel and process FAT chain + mov bx, KERNEL_LOAD_SEGMENT + mov es, bx + mov bx, KERNEL_LOAD_OFFSET + +.load_kernel_loop: + + ; Read next cluster + mov ax, [stage2_cluster] + add ax, 31 ; first cluster = (stage2_cluster - 2) * sectors per cluster + start sector + ; start sector = rserved + fats + root dir size = 1 + 18 + 134 = 33 + mov cl, 1 + mov dl, [ebr_drive_number] + call disk_read + + add bx, [bdb_bytes_per_sector] + + ; get location of next cluster + mov ax, [stage2_cluster] + mov cx, 3 + mul cx + mov cx, 2 + div cx ; ax = index of FAT entry, dx = cluster % 2 + + mov si, buffer + add si, ax + mov ax, [ds:si] ; read FAT entry at index ax + + or dx, dx + jz .even + +.odd: + shr ax, 4 ; shift right 4 bits + jmp .next_cluster + +.even: + and ax, 0x0FFF ; mask out low 4 bits + +.next_cluster: + cmp ax, 0x0FF8 ; check if last cluster + jae .read_finish + + mov [stage2_cluster], ax + jmp .load_kernel_loop + +.read_finish: + ; jump to kernel + mov dl, [ebr_drive_number] ; boot device in dl + + ; set segment registers + mov ax, KERNEL_LOAD_SEGMENT ; set segment registers + mov ds, ax + mov es, ax + + jmp KERNEL_LOAD_SEGMENT:KERNEL_LOAD_OFFSET + + jmp wait_key_reboot ; should never reach here + + + cli ; disable interrupts + hlt + + +; +; Error handling +; + +floppy_error: +mov si, msg_read_failed + call puts + jmp wait_key_reboot + +kernel_not_found_error: + mov si, msg_stage2_not_found + call puts + jmp wait_key_reboot + +wait_key_reboot: + mov ah, 0 + int 16h ; wait for key press + jmp 0FFFFh:0 ; reboot + +.halt: + cli ; disable interrupts + hlt + +; Prints string to screen +; Params: +; ds:si - pointer to string +puts: + push si + push ax + push bx + +.loop: + lodsb ; load byte from ds:si into al, increment si + or al, al ; set zero flag if al is 0 + jz .done ; jump to done if al is 0 + + mov ah , 0x0E ; enter tty mode + mov bh, 0 ; page number + int 0x10 ; call BIOS interrupt + jmp .loop ; jump back to loop + + +.done: + pop bx + pop ax + pop si + ret + + +; +; Disk routines +; + +; +; Converts LBA addr to CHS addr +; Params: +; - ax: LBA address +; Returns: +; - cx: [0-5]: sector number +; - cx: [6-15]: cylinder +; - dh: head + +lba_to_chs: + + push ax + push dx + + xor dx, dx ; set dx to 0 + div word [bdb_sectors_per_track] ; ax => LBA / SectorsPerTrack + ; dx => LBA % SectorsPerTrack + + inc dx ; dx = (LBA % SectorsPerTrack) + 1 (sector number) + mov cx, dx ; cx = sector number + + xor dx, dx ; dx = 0 + div word [bdb_heads] ; ax => (LBA / SectorsPerTrack) / Heads (cylinder) + ; dx => (LBA / SectorsPerTrack) % Heads (head) + mov dh, dl ; dh = head + mov ch, al ; ch = cylinder lower 8 bits + shl ah, 6 ; shift ah 6 bits to the left + or cl, ah ; cl = cylinder upper 2 bits + + pop ax + mov dl, al ; restore dl and al + pop ax + ret + +; +; Reads sectors from a disk +; Parameters: +; - ax: LBA address +; - cl: number of sectors to read +; - dl: drive number +; - es:bx: buffer to read sectors into + +disk_read: + + push ax ; save registers + push bx + push cx + push dx + push di + + push cx ; temporarily save cl + call lba_to_chs ; convert LBA to CHS + pop ax ; AL = number of sectors to read + + mov ah, 02h ; read sectors + mov di, 3 ; number of retries + +.retry: + pusha ; save registers + stc ; set carry flag + int 13h ; call BIOS interrupt + jnc .done + + ; read failed + popa + call disk_reset + + dec di + test di, di + jnz .retry + +.fail: + ; attempts exhausted + jmp floppy_error + +.done: + popa ; restore registers + + pop di ; save registers + pop dx + pop cx + pop bx + pop ax + ret + +; +; Resets disk controller +; Parameters: +; - dl: drive number + +disk_reset: + pusha + mov ah, 0 + stc + int 13h + jc floppy_error + popa + ret + + +msg_load: db 'Load ~chaOS', ENDL, 0 +msg_read_failed: db 'Read from disk failed!', ENDL, 0 +msg_stage2_not_found: db 'STAGE2.BIN file not found!', ENDL, 0 +file_stage2_bin: db 'STAGE2 BIN' +stage2_cluster: dw 0 + +KERNEL_LOAD_SEGMENT: equ 0x2000 +KERNEL_LOAD_OFFSET: equ 0x0000 + + +times 510-($-$$) db 0 ; pad the rest of the sector with 0s + +dw 0AA55h +; db 0x55, 0xAA ; boot sector signature +; dw 0xAA55 ; boot sector signature (using word) + +buffer: \ No newline at end of file diff --git a/src/bootloader/stage2/Makefile b/src/bootloader/stage2/Makefile new file mode 100644 index 0000000..c8c5706 --- /dev/null +++ b/src/bootloader/stage2/Makefile @@ -0,0 +1,33 @@ +BUILD_DIR?=build/ +ASM?=nasm +ASMFLAGS?=-f obj +CC16?=/opt/watcom/binl/wcc +CFLAGS16?=-4 -d3 -s -wx -ms -zl -zq +LD16?=/opt/watcom/binl/wlink + +SOURCES_C=$(wildcard *.c) +SOURCES_ASM=$(wildcard *.asm) +OBJECTS_C=$(patsubst %.c, $(BUILD_DIR)/stage2/c/%.obj, $(SOURCES_C)) +OBJECTS_ASM=$(patsubst %.asm, $(BUILD_DIR)/stage2/asm/%.obj, $(SOURCES_ASM)) + +.PHONY: all stage2 clean always + +all: stage2 + +stage2: $(BUILD_DIR)/stage2.bin + +$(BUILD_DIR)/stage2.bin: $(OBJECTS_ASM) $(OBJECTS_C) + $(LD16) NAME $(BUILD_DIR)/stage2.bin FILE \{ $(OBJECTS_ASM) $(OBJECTS_C) \} OPTION MAP=$(BUILD_DIR)/stage2.map @linker.lnk + +$(BUILD_DIR)/stage2/c/%.obj: %.c always + $(CC16) $(CFLAGS16) -fo=$@ $< + +$(BUILD_DIR)/stage2/asm/%.obj: %.asm always + $(ASM) $(ASMFLAGS) -o $@ $< + +always: + mkdir -p $(BUILD_DIR)/stage2/c + mkdir -p $(BUILD_DIR)/stage2/asm + +clean: + rm -f $(BUILD_DIR)/stage2.bin \ No newline at end of file diff --git a/src/bootloader/stage2/linker.lnk b/src/bootloader/stage2/linker.lnk new file mode 100644 index 0000000..612fed6 --- /dev/null +++ b/src/bootloader/stage2/linker.lnk @@ -0,0 +1,12 @@ +FORMAT RAW BIN +OPTION QUIET, + NODEFAULTLIBS, + START=entry, + VERBOSE, + OFFSET=0, + STACK=0x200 +ORDER + CLNAME CODE + SEGMENT _ENTRY + SEGMENT _TEXT + CLNAME DATA \ No newline at end of file diff --git a/src/bootloader/stage2/main.asm b/src/bootloader/stage2/main.asm new file mode 100644 index 0000000..f76e725 --- /dev/null +++ b/src/bootloader/stage2/main.asm @@ -0,0 +1,22 @@ +bits 16 + +section _ENTRY class=CODE + +extern _cstart_ +global entry + +entry: + cli + mov ax, ds + mov ss, ax + mov sp, 0 + mov bp, sp + sti + + ; boot drive in dl, send as arg to cstart fn + xor dh, dh + push dx + call _cstart_ + + cli + hlt \ No newline at end of file diff --git a/src/bootloader/stage2/main.c b/src/bootloader/stage2/main.c new file mode 100644 index 0000000..fec5784 --- /dev/null +++ b/src/bootloader/stage2/main.c @@ -0,0 +1,5 @@ +#include "stdint.h" + +void _cdecl cstart_(uint16_t bootDrive) { + +} \ No newline at end of file diff --git a/src/bootloader/stage2/main.err b/src/bootloader/stage2/main.err new file mode 100644 index 0000000..91b3d1d --- /dev/null +++ b/src/bootloader/stage2/main.err @@ -0,0 +1,3 @@ +stdint.h(10): Warning! W138: No newline at end of file +main.c(5): Warning! W138: No newline at end of file +main.c(3): Warning! W303: Parameter 'bootDrive' has been defined, but not referenced diff --git a/src/bootloader/stage2/stdint.h b/src/bootloader/stage2/stdint.h new file mode 100644 index 0000000..822fdf0 --- /dev/null +++ b/src/bootloader/stage2/stdint.h @@ -0,0 +1,10 @@ +#pragma once + +typedef signed char int8_t; +typedef unsigned short uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed long int int32_t; +typedef unsigned long int uint32_t; +typedef signed long long int int64_t; +typedef unsigned long long int uint64_t; \ No newline at end of file diff --git a/src/bootloader/stage2/x86.asm b/src/bootloader/stage2/x86.asm new file mode 100644 index 0000000..5954df6 --- /dev/null +++ b/src/bootloader/stage2/x86.asm @@ -0,0 +1,6 @@ +bits 16 + +section _TEXT class=CODE + +global _x86_Video_WriteCharTeletype +_x86_Video_WriteCharTeletype: diff --git a/src/kernel/Makefile b/src/kernel/Makefile new file mode 100644 index 0000000..79baae8 --- /dev/null +++ b/src/kernel/Makefile @@ -0,0 +1,14 @@ +BUILD_DIR?=build/ +ASM?=nasm + +.PHONY: all kernel clean + +all: kernel + +kernel: $(BUILD_DIR)/kernel.bin + +$(BUILD_DIR)/kernel.bin: + $(ASM) kernel.asm -f bin -o $(BUILD_DIR)/kernel.bin + +clean: + rm -f $(BUILD_DIR)/kernel.bin \ No newline at end of file diff --git a/src/kernel/kernel.asm b/src/kernel/kernel.asm new file mode 100644 index 0000000..6f3c16d --- /dev/null +++ b/src/kernel/kernel.asm @@ -0,0 +1,43 @@ +org 0x0 ; kernel loaded with 0 offset +bits 16 ; emit 16-bit code + +%define ENDL 0X0D, 0xA ; CRLF + + +start: + + ; print message + mov si, msg_hello ; set si to point to msg_hello + call puts ; call puts with si + +.halt: + cli + hlt + + +; Prints string to screen +; Params: +; ds:si - pointer to string +puts: + push si + push ax + push bx + +.loop: + lodsb ; load byte from ds:si into al, increment si + or al, al ; set zero flag if al is 0 + jz .done ; jump to done if al is 0 + + mov ah , 0x0E ; enter tty mode + mov bh, 0 ; page number + int 0x10 ; call BIOS interrupt + + jmp .loop ; jump back to loop + +.done: + pop bx + pop ax + pop si + ret + +msg_hello: db 'Hello from chaOS!', ENDL, 0 \ No newline at end of file diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..e23fc8c --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +Hello from FAT-12 partition! \ No newline at end of file