diff --git a/.asm-lsp.toml b/.asm-lsp.toml deleted file mode 100644 index e34e92b..0000000 --- a/.asm-lsp.toml +++ /dev/null @@ -1,21 +0,0 @@ -[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 0ae2e6a..880cd5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ zig-out .zig-cache -.kate-swp diff --git a/README.md b/README.md deleted file mode 100644 index 7a6beca..0000000 --- a/README.md +++ /dev/null @@ -1,33 +0,0 @@ -an operating system made in nasm assembly and (in the future) zig, using the zig build system. -this project is based on [this video series](https://www.youtube.com/playlist?list=PLFjM7v6KGMpiH2G-kT781ByCNC_0pKpPN) by [nanobyte](https://www.youtube.com/@nanobyte-dev) - -# HOWTO - -## dependencies - -this project requires the nasm assembler, mtools for floppy disk generation and zig to build. -this project uses qemu as the default emulator, but this is optional - -## building - -```bash -git clone https://dario48.site/git/Dario48/zos.git -cd zos -zig build -``` - -## running - -- with the default emulator - -```bash -cd zos -zig build run -``` - -- with a different emulator - -```bash -cd zos -emulator_cmd zig-out/bin/main_floppy.img -``` diff --git a/build.zig b/build.zig index e4051ee..903d6dd 100644 --- a/build.zig +++ b/build.zig @@ -7,56 +7,26 @@ pub fn build(b: *std.Build) void { const initramfs = addNasmFiles(b, AddNasmFilesOptions{ .filename = "src/initramfs.asm", .outputname = "initramfs.bin", - .flags = &.{"-f bin"}, - }); - const kernel = addNasmFiles(b, AddNasmFilesOptions{ - .filename = "src/kernel.asm", - .outputname = "kernel.bin", + .addAsObjFile = false, .flags = &.{"-f bin"}, }); - var floppy = createFloppy(b, "main_floppy.img"); - floppy.run = formatFloppyFat12(b, floppy); + const initramfs_install = b.addInstallBinFile(initramfs.obj, "initramfs.img"); + initramfs_install.step.dependOn(&truncate(b, initramfs).step); - var installToFloppy = installImgToFloppy(b, floppy, initramfs, &.{ - NamedFile{ .file = .{ .runFile = kernel }, .name = "::kernel.bin" }, - NamedFile{ .file = .{ .simpleFile = b.path("src/reference_implementations/test.txt") }, .name = "::test.txt" }, - }); - - const img_install = b.addInstallBinFile(floppy.obj, "main_floppy.img"); - img_install.step.dependOn(&installToFloppy); - - b.getInstallStep().dependOn(&img_install.step); - - const target = b.standardTargetOptions(.{}); - const fat_reference_mod = b.createModule(.{ - .root_source_file = b.path("src/reference_implementations/fat.zig"), - .target = target, - .link_libc = true, - }); + b.getInstallStep().dependOn(&initramfs_install.step); const run = b.addSystemCommand(&.{ "qemu-system-i386", "-fda" }); - run.addFileArg(floppy.obj); + run.addFileArg(b.path("zig-out/bin/initramfs.img")); const run_step = b.step("run", "run the os in qemu"); run_step.dependOn(&run.step); - - const fat_reference = b.addExecutable(.{ - .root_module = fat_reference_mod, - .name = "fat_reference_implementation", - .use_lld = false, - .use_llvm = false, - }); - - const fat_install = b.addInstallArtifact(fat_reference, .{}); - - const build_references = b.step("references", "build the reference implementations"); - build_references.dependOn(&fat_install.step); } const AddNasmFilesOptions = struct { filename: []const u8, outputname: ?[]const u8 = null, + addAsObjFile: bool = true, flags: []const []const u8 = &.{}, }; @@ -65,59 +35,6 @@ const NasmFile = struct { obj: std.Build.LazyPath, }; -const Floppydisk = NasmFile; - -const NamedFile = struct { - file: union(enum) { runFile: NasmFile, simpleFile: std.Build.LazyPath }, - name: []const u8, -}; - -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, additional_files: []const NamedFile) std.Build.Step { - 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); - - var mcopy_step = std.Build.Step.init(.{ .name = "mcopy", .owner = b, .id = .custom }); - mcopy_step.dependOn(&dd.step); - for (additional_files) |f| { - const mcopy = b.addSystemCommand(&.{"mcopy"}); - mcopy.addPrefixedFileArg("-i", floppy.obj); - switch (f.file) { - .runFile => |file| { - mcopy.addFileArg(file.obj); - mcopy_step.dependOn(&file.run.step); - }, - .simpleFile => |file| mcopy.addFileArg(file), - } - mcopy.addArg(f.name); - mcopy_step.dependOn(&mcopy.step); - } - return mcopy_step; -} - // 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)); @@ -135,3 +52,12 @@ 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/build.zig.zon b/build.zig.zon index f29dbdf..365621b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -28,7 +28,7 @@ // Tracks the earliest Zig version that the package considers to be a // supported use case. - .minimum_zig_version = "0.15.0", + .minimum_zig_version = "0.14.1", // This field is optional. // Each dependency must either provide a `url` and `hash`, or a `path`. diff --git a/src/initramfs.asm b/src/initramfs.asm index b2e02b3..6da1603 100644 --- a/src/initramfs.asm +++ b/src/initramfs.asm @@ -2,40 +2,8 @@ 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 @@ -79,139 +47,16 @@ main: mov ss, ax mov sp, 0x7C00 ; stack grows downward from where we are loaded in memory - mov si, msg_startup + ; print the hello world + mov si, msg_hello 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 - -; -; 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 +msg_hello: db 'Hello, world!', ENDL, 0 times 510-($-$$) db 0 dw 0AA55h diff --git a/src/kernel.asm b/src/kernel.asm deleted file mode 100644 index 6da1603..0000000 --- a/src/kernel.asm +++ /dev/null @@ -1,62 +0,0 @@ -; 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 diff --git a/src/reference_implementations/fat.zig b/src/reference_implementations/fat.zig deleted file mode 100644 index 61d7a0f..0000000 --- a/src/reference_implementations/fat.zig +++ /dev/null @@ -1,117 +0,0 @@ -const std = @import("std"); - -const Errors = error{ InvalidSyntax, ReadSectors, FileNotFound }; - -var buffer: [1024]u8 = undefined; - -var g_Fat: []u8 = undefined; - -const BootSector = extern struct { - BootJumpInstruction: [3]u8 align(1), - OemIdentifier: [8]u8 align(1), - BytesPerSector: u16 align(1), - SectorsPerCluster: u8 align(1), - ReservedSectors: u16 align(1), - FatCount: u8 align(1), - DirEntryCount: u16 align(1), - TotalSectors: u16 align(1), - MediaDescriptorType: u8 align(1), - SectorsPerFat: u16 align(1), - SectorsPerTrack: u16 align(1), - Heads: u16 align(1), - HiddenSectors: u32 align(1), - LargeSectorCount: u32 align(1), - - // ebr - DriveNumber: u8 align(1), - _Reserved: u8 align(1), - Signature: u8 align(1), - VolumeId: u32 align(1), - VolumeLaber: [11]u8 align(1), - SystemId: [8]u8 align(1), -}; - -var g_BootSector: BootSector = undefined; - -const DirectoryEntry = extern struct { - Name: [11]u8 align(1), - Attributes: u8 align(1), - _Reserved: u8 align(1), - CreatedTimeTenths: u8 align(1), - CreatedTime: u16 align(1), - CreatedDate: u16 align(1), - AccessedDate: u16 align(1), - FirstClusterHigh: u16 align(1), - ModifiedTime: u16 align(1), - ModifiedDate: u16 align(1), - FirstClusterLow: u16 align(1), - Size: u32 align(1), -}; - -var g_RootDirectory: []DirectoryEntry = undefined; - -fn readStruct(reader: *std.fs.File.Reader, T: type) !T { - var ret: [@sizeOf(T)]u8 = undefined; - _ = try reader.*.read(&ret); - return @bitCast(ret); -} - -fn readBootSector(disk: *std.fs.File) !void { - var reader = disk.*.reader(&buffer); - g_BootSector = try readStruct(&reader, BootSector); -} - -fn readSectors(disk: *std.fs.File, lba: u32, count: u32, bufferOut: *[]anyopaque) !void { - const dest: []u8 = try std.heap.smp_allocator.alloc(u8, g_BootSector.BytesPerSector * count); - defer std.heap.smp_allocator.free(dest); - var stream = disk.readerStreaming(&buffer); - try stream.seekTo(lba * g_BootSector.BytesPerSector); - if (try stream.readStreaming(dest) != g_BootSector.BytesPerSector * count) return Errors.ReadSectors; - @memcpy(@as(*[]u8, @ptrCast(bufferOut)).*, dest); -} - -fn readFat(disk: *std.fs.File) !void { - g_Fat = try std.heap.smp_allocator.alloc(u8, g_BootSector.SectorsPerFat * g_BootSector.BytesPerSector); - errdefer std.heap.smp_allocator.free(g_Fat); - try readSectors(disk, g_BootSector.ReservedSectors, g_BootSector.SectorsPerFat, &g_Fat); -} - -fn readRootDirectory(disk: std.fs.File) !void { - const lba: u32 = g_BootSector.ReservedSectors + g_BootSector.SectorsPerFat + g_BootSector.FatCount; - const size: u32 = @sizeOf(DirectoryEntry) * g_BootSector.DirEntryCount; - const sectors: u32 = (size / g_BootSector.BytesPerSector); - if (@rem(size, g_BootSector.BytesPerSector > 0)) - sectors += 1; - - g_RootDirectory = try std.heap.smp_allocator.alloc(DirectoryEntry, sectors * g_BootSector.BytesPerSector); - errdefer std.heap.smp_allocator.free(g_RootDirectory); - try readSectors(disk, lba, sectors, &g_RootDirectory); -} - -fn findFile(name: []const u8) !*DirectoryEntry { - for (g_RootDirectory, 0..) |Entry, i| - if (std.mem.eql(u8, Entry.Name, name)) - return &g_RootDirectory[i]; - return Errors.FileNotFound; -} - -pub fn main() !void { - if (std.os.argv.len < 3) { - std.log.err("syntax: {s} ", .{std.os.argv[0]}); - return Errors.InvalidSyntax; - } - - var disk = try std.fs.cwd().openFileZ(std.os.argv[1], .{ .mode = .read_only }); - - _ = &disk; - try readBootSector(&disk); - - try readFat(&disk); - defer std.heap.smp_allocator.free(g_Fat); - - try readRootDirectory(disk); - defer std.heap.smp_allocator.free(g_RootDirectory); - - const fileEntry = try findFile(std.os.argv[2]); - _ = fileEntry; -} diff --git a/src/reference_implementations/test.txt b/src/reference_implementations/test.txt deleted file mode 100644 index 20e13f9..0000000 --- a/src/reference_implementations/test.txt +++ /dev/null @@ -1,3 +0,0 @@ -testing file -aabaacaadaaeaafaagaahaaiaajaakaalaamaanaaoaapaaqaaraasaataauaavaawaaxaayaaz -tstngfl