diff --git a/.asm-lsp.toml b/.asm-lsp.toml new file mode 100644 index 0000000..e34e92b --- /dev/null +++ b/.asm-lsp.toml @@ -0,0 +1,21 @@ +[default_config] +version = "0.10.0" +assembler = "nasm" +instruction_set = "x86/x86-64" + +[default_config.opts] +compiler = "zig" +compile_flags_txt = [ + "cc", + "-x", + "assembler-with-cpp", + "-g", + "-Wall", + "-Wextra", + "-pedantic", + "-pedantic-errors", + "-std=c2y", + "-mllvm --x86-asm-syntax=intel", +] +diagnostics = true +default_diagnostics = false diff --git a/.gitignore b/.gitignore index 880cd5d..0ae2e6a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ zig-out .zig-cache +.kate-swp diff --git a/build.zig b/build.zig index 903d6dd..712b389 100644 --- a/build.zig +++ b/build.zig @@ -7,17 +7,24 @@ pub fn build(b: *std.Build) void { const initramfs = addNasmFiles(b, AddNasmFilesOptions{ .filename = "src/initramfs.asm", .outputname = "initramfs.bin", - .addAsObjFile = false, + .flags = &.{"-f bin"}, + }); + const kernel = addNasmFiles(b, AddNasmFilesOptions{ + .filename = "src/kernel.asm", + .outputname = "kernel.bin", .flags = &.{"-f bin"}, }); - const initramfs_install = b.addInstallBinFile(initramfs.obj, "initramfs.img"); - initramfs_install.step.dependOn(&truncate(b, initramfs).step); + var floppy = createFloppy(b, "main_floppy.img"); + floppy.run = formatFloppyFat12(b, floppy); - b.getInstallStep().dependOn(&initramfs_install.step); + const img_install = b.addInstallBinFile(floppy.obj, "main_floppy.img"); + img_install.step.dependOn(&installImgToFloppy(b, floppy, initramfs, kernel).step); + + b.getInstallStep().dependOn(&img_install.step); const run = b.addSystemCommand(&.{ "qemu-system-i386", "-fda" }); - run.addFileArg(b.path("zig-out/bin/initramfs.img")); + run.addFileArg(floppy.obj); const run_step = b.step("run", "run the os in qemu"); run_step.dependOn(&run.step); @@ -26,7 +33,6 @@ pub fn build(b: *std.Build) void { const AddNasmFilesOptions = struct { filename: []const u8, outputname: ?[]const u8 = null, - addAsObjFile: bool = true, flags: []const []const u8 = &.{}, }; @@ -35,6 +41,46 @@ const NasmFile = struct { obj: std.Build.LazyPath, }; +const Floppydisk = NasmFile; + +fn createFloppy(b: *std.Build, name: []const u8) Floppydisk { + const dd = b.addSystemCommand(&.{ "dd", "if=/dev/zero" }); + const Floppy = dd.addPrefixedOutputFileArg("of=", name); + dd.addArgs(&.{ "bs=512", "count=2880" }); + + return Floppydisk{ + .run = dd, + .obj = Floppy, + }; +} + +fn formatFloppyFat12(b: *std.Build, floppy: Floppydisk) *std.Build.Step.Run { + const mkfs = b.addSystemCommand(&.{ "mkfs.fat", "-F12", "-nNBOS" }); + mkfs.addFileArg(floppy.obj); + + mkfs.step.dependOn(&floppy.run.step); + + return mkfs; +} + +fn installImgToFloppy(b: *std.Build, floppy: Floppydisk, bootloader: NasmFile, kernel: NasmFile) *std.Build.Step.Run { + const dd = b.addSystemCommand(&.{"dd"}); + dd.addPrefixedFileArg("if=", bootloader.obj); + dd.addPrefixedFileArg("of=", floppy.obj); + dd.addArg("conv=notrunc"); + dd.step.dependOn(&floppy.run.step); + dd.step.dependOn(&bootloader.run.step); + + const mcopy = b.addSystemCommand(&.{"mcopy"}); + mcopy.addPrefixedFileArg("-i", floppy.obj); + mcopy.addFileArg(kernel.obj); + mcopy.addArg("::kernel.bin"); + mcopy.step.dependOn(&dd.step); + mcopy.step.dependOn(&kernel.run.step); + + return mcopy; +} + // adapted from https://codeberg.org/raddari/zig-nasm-lib.git fn addNasmFiles(b: *std.Build, options: AddNasmFilesOptions) NasmFile { std.debug.assert(!std.fs.path.isAbsolute(options.filename)); @@ -52,12 +98,3 @@ fn addNasmFiles(b: *std.Build, options: AddNasmFilesOptions) NasmFile { .obj = obj, }; } - -fn truncate(b: *std.Build, bin: NasmFile) *std.Build.Step.Run { - const exec = b.addSystemCommand(&.{"truncate"}); - exec.addArgs(&.{ "-s", "1440k" }); - exec.addFileArg(bin.obj); - exec.step.dependOn(&bin.run.step); - - return exec; -} diff --git a/src/initramfs.asm b/src/initramfs.asm index 6da1603..b2e02b3 100644 --- a/src/initramfs.asm +++ b/src/initramfs.asm @@ -2,8 +2,40 @@ org 0x7C00 bits 16 + %define ENDL 0x0D, 0x0A +; +; FAT12 Header +; +jmp short start +nop + +bdb_oem: db "mkfs.fat" +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 +bdb_media_descriptor_type: db 0F0h +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 + db 0 +ebr_signature: db 29h +ebr_volume_id: db 68h, 6Fh, 6Dh, 6Fh +ebr_volume_laber: db 'zos disk ' +ebr_system_id: db 'FAT12 ' + + + + start: jmp main @@ -47,16 +79,139 @@ main: mov ss, ax mov sp, 0x7C00 ; stack grows downward from where we are loaded in memory - ; print the hello world - mov si, msg_hello + mov si, msg_startup call echo + mov si, msg_reading_from_disk + call echo + mov [ebr_drive_number], dl + + mov ax, 1 ; second sector from disk + mov cl, 1 ; 1 sector to read + mov bx, 0x7E00 ; data should be after the bootloader + call disk_read + + cli + hlt + +; errors + +floppy_error: + mov si, msg_read_failed + call echo + jmp .wait_and_reboot + +.wait_and_reboot: + mov ah, 0 + int 16h + + jmp 0FFFFh:0 ; jump to start of bios, should reboot + hlt .halt: + cli ; disable interrupts, this way we shouldn't be able to get out of halt + hlt jmp .halt -msg_hello: db 'Hello, world!', ENDL, 0 + +; +; args: +; ax = lba adress +; return: +; cx[0..5] = sector number +; cx[6-15] = cilinder number +; dh: head +; +lba_to_chs: + push ax + push dx + + xor dx, dx ; clear dw + div word [bdb_sectors_per_track] ; ax = LBA / SectorsPerTrack + ; dx = LBA % SectorsPerTrack + + inc dx + mov cx, dx ; cx = sector + + xor dx, dx ; clear dx + div word [bdb_heads] ; ax = (LBA / SectorsPerTrack) / Heads = cylinder + ; dx = (LBA / SectorsPerTrack) % Heads = head + mov dh, dl + mov ch, al + shl ah, 6 + or cl, ah ; put upper 2 bits of cylinder in CL + + pop ax + mov dl, al + pop ax + + ret + + +; +; args: +; ax = LBA adress +; cl = number of sectors to read +; dl = drive number +; es:bx = pointer to where to store the data +; + +disk_read: + push ax + push bx + push cx + push dx + push di + + push cx ; cx will be overridden + call lba_to_chs + pop ax ; al = number of sectors to read + mov ah, 02h + mov di, 3 ; hoe many times to try + +.retry: + pusha + stc ; set carry flag + int 13h ; if no carry flag => it work + + jnc .done + + ; read fail + popa + call disk_reset + dec di + + test di, di + jnz .retry + +.fail: + jmp floppy_error + +.done: + popa + + pop di + pop dx + pop cx + pop bx + pop ax + ret + +; arg: dl = drive number + +disk_reset: + pusha + mov ah, 0 + stc ; set carry + int 13h + jc floppy_error + popa + ret + +msg_startup: db 'starting zos, please hold while we check for any problems', ENDL, 0 +msg_reading_from_disk: db 'testing reading from disk', ENDL, 0 +msg_read_failed: db 'error when trying to read from floppy', ENDL, 0 times 510-($-$$) db 0 dw 0AA55h diff --git a/src/kernel.asm b/src/kernel.asm new file mode 100644 index 0000000..6da1603 --- /dev/null +++ b/src/kernel.asm @@ -0,0 +1,62 @@ +; vim: ft=nasm +org 0x7C00 +bits 16 + +%define ENDL 0x0D, 0x0A + +start: + jmp main + +; +; echo: +; print something to the screen +; - ds:si points to string +; +echo: + ; save the registers we want to modify + push si + push ax + push bx + + mov ah, 0xe + mov bh, 0 + +.loop: + lodsb ; load byte from ds:si to al + or al, al ; check if next char is null + jz .done + + int 0x10 + jmp .loop + +.done: + pop bx + pop ax + pop si + ret + +main: + + ; setup data segments + ; use ax as and intermediary as we can't write to es/ds directly + mov ax, 0 + mov ds, ax + mov es, ax + + ; setup stack + mov ss, ax + mov sp, 0x7C00 ; stack grows downward from where we are loaded in memory + + ; print the hello world + mov si, msg_hello + call echo + + hlt + +.halt: + jmp .halt + +msg_hello: db 'Hello, world!', ENDL, 0 + +times 510-($-$$) db 0 +dw 0AA55h