├── .envrc ├── .gitignore ├── README.md ├── assets └── recording.gif ├── build.zig ├── build.zig.zon ├── justfile ├── limine ├── limine ├── limine-bios-cd.bin ├── limine-bios.sys ├── limine.cfg └── limine.exe └── src ├── acpi.zig ├── art.zig ├── asm ├── entry.s └── helpers.s ├── console.zig ├── gdt.zig ├── idt.zig ├── kernel.zig ├── keycodes.zig ├── keys.zig ├── linker.ld ├── main.zig ├── malloc.zig ├── mem.zig ├── multiboot.zig ├── pic.zig ├── pit.zig ├── port.zig ├── ps2.zig ├── rand.zig ├── shell.zig ├── sync.zig └── utils.zig /.envrc: -------------------------------------------------------------------------------- 1 | export PATH="$HOME/.local/share/szm/bin":$PATH 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore files in build output directory 2 | zig-out/**/* 3 | # ignore the zig build cache directory 4 | /.zig-cache/**/* 5 | # ignore the iso build directory 6 | /iso/**/* 7 | # ignore iso files at the top level 8 | /*.iso 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AsukaOS 2 | 3 | ![example](assets/recording.gif) 4 | 5 | AsukaOS is a simple x86 operating system written in Zig 0.14.0-dev 6 | 7 | # Building + Running 8 | 9 | if you have `just` you can just run: 10 | 11 | ```bash 12 | # build and run the OS in qemu (and clean up the iso and build dir) 13 | just 14 | # it also includes a helper task to download the correct version of Zig into a sub-folder 15 | just download-zig 16 | # and each step individually 17 | # build the iso; 18 | just mkiso 19 | # build the iso and run qemu; 20 | just qemu 21 | # just build the Zig executable: 22 | just build 23 | # you can also run the equivalent in Zig directly: 24 | zig build 25 | zig build run 26 | zig build make-iso 27 | ``` 28 | 29 | # Credits 30 | 31 | - ![AnErrupTion/EeeOS](https://github.com/AnErrupTion/EeeOS) 32 | 33 | - ![osdev](https://wiki.osdev.org) 34 | -------------------------------------------------------------------------------- /assets/recording.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetbbak/asukaOS/20d2ff8689ef4ad7a998b5af41bf6c32baea6609/assets/recording.gif -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn run_executable(alloc: std.mem.Allocator, args: [][]const u8) void { 4 | // the command to run 5 | const proc = try std.process.Child.run(.{ 6 | .allocator = alloc, 7 | .argv = &args, 8 | }); 9 | 10 | // on success, we own the output streams 11 | defer alloc.free(proc.stdout); 12 | defer alloc.free(proc.stderr); 13 | 14 | const term = proc.term; 15 | 16 | try std.testing.expectEqual(term, std.ChildProcess.Term{ .Exited = 0 }); 17 | } 18 | 19 | // Although this function looks imperative, note that its job is to 20 | // declaratively construct a build graph that will be executed by an external 21 | // runner. 22 | pub fn build(b: *std.Build) void { 23 | var disabled_features = std.Target.Cpu.Feature.Set.empty; 24 | var enabled_features = std.Target.Cpu.Feature.Set.empty; 25 | 26 | disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.mmx)); 27 | disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.sse)); 28 | disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.sse2)); 29 | disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.avx)); 30 | disabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.avx2)); 31 | enabled_features.addFeature(@intFromEnum(std.Target.x86.Feature.soft_float)); 32 | 33 | const target_query = std.Target.Query{ 34 | .cpu_arch = std.Target.Cpu.Arch.x86, 35 | .os_tag = std.Target.Os.Tag.freestanding, 36 | .abi = std.Target.Abi.none, 37 | .cpu_features_sub = disabled_features, 38 | .cpu_features_add = enabled_features, 39 | }; 40 | 41 | // Standard target options allows the person running `zig build` to choose 42 | // what target to build for. Here we do not override the defaults, which 43 | // means any target is allowed, and the default is native. Other options 44 | // for restricting supported target set are available. 45 | // const target = b.standardTargetOptions(.{}); 46 | 47 | // Standard optimization options allow the person running `zig build` to select 48 | // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not 49 | // set a preferred release mode, allowing the user to decide how to optimize. 50 | const optimize = b.standardOptimizeOption(.{}); 51 | 52 | const exe = b.addExecutable(.{ 53 | .name = "asuka-os", 54 | .root_source_file = b.path("src/main.zig"), 55 | .target = b.resolveTargetQuery(target_query), 56 | .optimize = optimize, 57 | .code_model = .kernel, 58 | }); 59 | 60 | exe.setLinkerScript(b.path("src/linker.ld")); 61 | exe.addAssemblyFile(b.path("src/asm/entry.s")); 62 | exe.addAssemblyFile(b.path("src/asm/helpers.s")); 63 | 64 | // This declares intent for the executable to be installed into the 65 | // standard location when the user invokes the "install" step (the default 66 | // step when running `zig build`). 67 | b.installArtifact(exe); 68 | 69 | // add step to check if our executables header is correct 70 | // const grub = b.addSystemCommand(&.{ "grub-file", "--is-x86-multiboot" }); 71 | // const exe_path = b.path("zig-out/bin/asuka-os"); 72 | // grub.addFileArg(exe_path); 73 | // grub.expectExitCode(0); 74 | 75 | // b.getInstallStep().dependOn(&grub.step); 76 | 77 | // This *creates* a Run step in the build graph, to be executed when another 78 | // step is evaluated that depends on it. The next line below will establish 79 | // such a dependency. 80 | const run_cmd = b.addRunArtifact(exe); 81 | run_cmd.step.dependOn(b.getInstallStep()); 82 | 83 | // This allows the user to pass arguments to the application in the build 84 | // command itself, like this: `zig build run -- arg1 arg2 etc` 85 | if (b.args) |args| { 86 | run_cmd.addArgs(args); 87 | } 88 | 89 | // This creates a build step. It will be visible in the `zig build --help` menu, 90 | // and can be selected like this: `zig build run` 91 | // This will evaluate the `run` step rather than the default, which is "install". 92 | const run_step = b.step("run", "Run the app"); 93 | // run_step.dependOn(&grub.step); 94 | 95 | const make_iso_step = b.step("make-iso", "Create a bootable ISO image"); 96 | make_iso_step.makeFn = make_iso; 97 | make_iso_step.dependOn(b.getInstallStep()); 98 | 99 | run_step.makeFn = run; 100 | run_step.dependOn(make_iso_step); 101 | } 102 | 103 | // fn make_iso(self: *std.Build.Step, progress: std.Progress.Node) !void { 104 | fn make_iso(self: *std.Build.Step, opts: std.Build.Step.MakeOptions) anyerror!void { 105 | _ = self; 106 | _ = opts; 107 | 108 | const current_dir = std.fs.cwd(); 109 | current_dir.makeDir("iso") catch {}; 110 | 111 | var isoDirectory = current_dir.openDir("iso", std.fs.Dir.OpenDirOptions{}) catch unreachable; 112 | defer isoDirectory.close(); 113 | 114 | current_dir.copyFile("limine/limine-bios-cd.bin", isoDirectory, "limine-bios-cd.bin", .{}) catch unreachable; 115 | current_dir.copyFile("limine/limine-bios.sys", isoDirectory, "limine-bios.sys", .{}) catch unreachable; 116 | current_dir.copyFile("limine/limine.cfg", isoDirectory, "limine.cfg", .{}) catch unreachable; 117 | current_dir.copyFile("zig-out/bin/asuka-os", isoDirectory, "asuka.elf", .{ .override_mode = 0o777 }) catch unreachable; 118 | 119 | const xorriso_argv = [_][]const u8{ 120 | "xorriso", 121 | "-as", 122 | "mkisofs", 123 | "-b", 124 | "limine-bios-cd.bin", 125 | "-no-emul-boot", 126 | "-boot-load-size", 127 | "4", 128 | "-boot-info-table", 129 | "iso", 130 | "-o", 131 | "asuka-os.iso", 132 | }; 133 | 134 | var xor = std.process.Child.init(&xorriso_argv, std.heap.page_allocator); 135 | try xor.spawn(); 136 | const term = try xor.wait(); 137 | 138 | try std.testing.expectEqual(term, std.process.Child.Term{ .Exited = 0 }); 139 | 140 | // const limine_deploy_argv = [_][]const u8{ 141 | // "limine/limine", 142 | // "bios-install", 143 | // "asuka-os.iso", 144 | // }; 145 | // 146 | // var proc = std.process.Child.init(&limine_deploy_argv, std.heap.page_allocator); 147 | // try proc.spawn(); 148 | // const res = try proc.wait(); 149 | // try std.testing.expectEqual(res, std.process.Child.Term{ .Exited = 0 }); 150 | } 151 | 152 | fn run(self: *std.Build.Step, opts: std.Build.Step.MakeOptions) anyerror!void { 153 | // fn run(self: *std.Build.Step, progress: std.Progress.Node) !void { 154 | _ = self; 155 | _ = opts; 156 | 157 | const qemu_argv = [_][]const u8{ 158 | "qemu-system-i386", 159 | "-cpu", 160 | "pentium2", 161 | "-m", 162 | "256M", // or 128M 163 | "-cdrom", 164 | "asuka-os.iso", 165 | }; 166 | 167 | var qemu = std.process.Child.init(&qemu_argv, std.heap.page_allocator); 168 | try qemu.spawn(); 169 | _ = try qemu.wait(); 170 | } 171 | -------------------------------------------------------------------------------- /build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | // This is the default name used by packages depending on this one. For 3 | // example, when a user runs `zig fetch --save `, this field is used 4 | // as the key in the `dependencies` table. Although the user can choose a 5 | // different name, most users will stick with this provided value. 6 | // 7 | // It is redundant to include "zig" in this name because it is already 8 | // within the Zig package namespace. 9 | .name = "asukaOS", 10 | 11 | // This is a [Semantic Version](https://semver.org/). 12 | // In a future version of Zig it will be used for package deduplication. 13 | .version = "0.0.0", 14 | 15 | // This field is optional. 16 | // This is currently advisory only; Zig does not yet do anything 17 | // with this value. 18 | //.minimum_zig_version = "0.11.0", 19 | 20 | // This field is optional. 21 | // Each dependency must either provide a `url` and `hash`, or a `path`. 22 | // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. 23 | // Once all dependencies are fetched, `zig build` no longer requires 24 | // internet connectivity. 25 | .dependencies = .{ 26 | // See `zig fetch --save ` for a command-line interface for adding dependencies. 27 | //.example = .{ 28 | // // When updating this field to a new URL, be sure to delete the corresponding 29 | // // `hash`, otherwise you are communicating that you expect to find the old hash at 30 | // // the new URL. 31 | // .url = "https://example.com/foo.tar.gz", 32 | // 33 | // // This is computed from the file contents of the directory of files that is 34 | // // obtained after fetching `url` and applying the inclusion rules given by 35 | // // `paths`. 36 | // // 37 | // // This field is the source of truth; packages do not come from a `url`; they 38 | // // come from a `hash`. `url` is just one of many possible mirrors for how to 39 | // // obtain a package matching this `hash`. 40 | // // 41 | // // Uses the [multihash](https://multiformats.io/multihash/) format. 42 | // .hash = "...", 43 | // 44 | // // When this is provided, the package is found in a directory relative to the 45 | // // build root. In this case the package's hash is irrelevant and therefore not 46 | // // computed. This field and `url` are mutually exclusive. 47 | // .path = "foo", 48 | 49 | // // When this is set to `true`, a package is declared to be lazily 50 | // // fetched. This makes the dependency only get fetched if it is 51 | // // actually used. 52 | // .lazy = false, 53 | //}, 54 | }, 55 | 56 | // Specifies the set of files and directories that are included in this package. 57 | // Only files and directories listed here are included in the `hash` that 58 | // is computed for this package. Only files listed here will remain on disk 59 | // when using the zig package manager. As a rule of thumb, one should list 60 | // files required for compilation plus any license(s). 61 | // Paths are relative to the build root. Use the empty string (`""`) to refer to 62 | // the build root itself. 63 | // A directory listed here means that all files within, recursively, are included. 64 | .paths = .{ 65 | "build.zig", 66 | "build.zig.zon", 67 | "src", 68 | // For example... 69 | //"LICENSE", 70 | //"README.md", 71 | }, 72 | } 73 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | default: 2 | just run && just clean 3 | 4 | build: 5 | zig build 6 | 7 | run: 8 | zig build run 9 | 10 | mkiso: 11 | zig build make-iso 12 | 13 | download-zig: 14 | #!/usr/bin/env bash 15 | printf "\e[32m%s\e[0m\n" "[ DOWNLOADING ZIG 14.0 ]" 16 | curl -fsSl https://ziglang.org/builds/zig-linux-$(uname -m)-0.14.0-dev.1860+2e2927735.tar.xz | tar xvfJ - 17 | mkdir -p bin 18 | ln -sf `pwd`/zig-linux-x86_64-0.14.0-dev.1860+2e2927735/zig bin/zig 19 | printf "\e[32m%s\e[0m\n" "[ DONE ] Add $(pwd)/bin to PATH" 20 | # [ -d zig-linux-x86_64-0.14.0-dev.1860+2e2927735 ] && rm -r zig-linux-x86_64-0.14.0-dev.1860+2e2927735 21 | 22 | clean: 23 | #!/usr/bin/env bash 24 | [ -d ./iso ] && rm -r ./iso 25 | [ -f ./asuka-os.iso ] && rm ./asuka-os.iso 26 | # [ -d zig-linux-x86_64-0.14.0-dev.1860+2e2927735 ] && rm -r zig-linux-x86_64-0.14.0-dev.1860+2e2927735 27 | 28 | qemu: 29 | qemu-system-i386 -cpu pentium2 -m 256M -cdrom asuka-os.iso 30 | 31 | # outdated from grub to limine switch 32 | __all: 33 | just 34 | just grub-config 35 | just iso 36 | just qemu 37 | 38 | __iso: 39 | mkdir -p iso/boot/grub 40 | cp zig-out/bin/asuka-os iso/boot/kernel.elf 41 | cp grub.cfg iso/boot/grub/grub.cfg 42 | grub-mkrescue -o asuka-os.iso iso 43 | 44 | __grub-config: 45 | #!/usr/bin/env bash 46 | cat< grub.cfg 47 | menuentry "Zig Bare Bones" { 48 | multiboot /boot/kernel.elf 49 | } 50 | EOF 51 | -------------------------------------------------------------------------------- /limine/limine: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetbbak/asukaOS/20d2ff8689ef4ad7a998b5af41bf6c32baea6609/limine/limine -------------------------------------------------------------------------------- /limine/limine-bios-cd.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetbbak/asukaOS/20d2ff8689ef4ad7a998b5af41bf6c32baea6609/limine/limine-bios-cd.bin -------------------------------------------------------------------------------- /limine/limine-bios.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetbbak/asukaOS/20d2ff8689ef4ad7a998b5af41bf6c32baea6609/limine/limine-bios.sys -------------------------------------------------------------------------------- /limine/limine.cfg: -------------------------------------------------------------------------------- 1 | TIMEOUT=0 2 | :asukaOS 3 | PROTOCOL=multiboot2 4 | KERNEL_PATH=boot:///asuka.elf 5 | -------------------------------------------------------------------------------- /limine/limine.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweetbbak/asukaOS/20d2ff8689ef4ad7a998b5af41bf6c32baea6609/limine/limine.exe -------------------------------------------------------------------------------- /src/acpi.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const multiboot = @import("./multiboot.zig"); 3 | const console = @import("./console.zig"); 4 | const port = @import("./port.zig"); 5 | 6 | pub const rsdp = extern struct { 7 | signature: [8]u8 align(1), 8 | checksum: u8 align(1), 9 | oem_id: [6]u8 align(1), 10 | revision: u8 align(1), 11 | rsdt_address: u32 align(1), 12 | }; 13 | 14 | pub const rsdp_20 = extern struct { 15 | base: rsdp align(1), 16 | 17 | length: u32 align(1), 18 | xsdt_address: u64 align(1), 19 | extended_checksum: u8 align(1), 20 | reserved: [3]u8 align(1), 21 | }; 22 | 23 | const std_header = extern struct { 24 | signature: [4]u8 align(1), 25 | length: u32 align(1), 26 | revision: u8 align(1), 27 | checksum: u8 align(1), 28 | oem_id: [6]u8 align(1), 29 | oem_table_id: [8]u8 align(1), 30 | oem_revision: u32 align(1), 31 | creator_id: u32 align(1), 32 | creator_revision: u32 align(1), 33 | }; 34 | 35 | const rsdt = extern struct { 36 | header: std_header align(1), 37 | 38 | other_sdt_headers: [64]u32 align(1), 39 | }; 40 | 41 | const xsdt = extern struct { 42 | header: std_header align(1), 43 | 44 | other_sdt_headers: [64]u64 align(1), 45 | }; 46 | 47 | const generic_addr_struct = extern struct { 48 | address_space: u8 align(1), 49 | bit_width: u8 align(1), 50 | bit_offset: u8 align(1), 51 | access_size: u8 align(1), 52 | address: u64 align(1), 53 | }; 54 | 55 | const fadt = extern struct { 56 | header: std_header align(1), 57 | 58 | firmware_ctrl: u32 align(1), 59 | dsdt: u32 align(1), 60 | 61 | // Field used in ACPI 1.0 only, no longer in use 62 | reserved: u8 align(1), 63 | 64 | preferred_power_management_profile: u8 align(1), 65 | sci_interrupt: u16 align(1), 66 | smi_command_port: u32 align(1), 67 | acpi_enable: u8 align(1), 68 | acpi_disable: u8 align(1), 69 | s4bios_req: u8 align(1), 70 | pstate_control: u8 align(1), 71 | pm1a_event_block: u32 align(1), 72 | pm1b_event_block: u32 align(1), 73 | pm1a_control_block: u32 align(1), 74 | pm1b_control_block: u32 align(1), 75 | pm2_control_block: u32 align(1), 76 | pm_timer_block: u32 align(1), 77 | gpe0_block: u32 align(1), 78 | gpe1_block: u32 align(1), 79 | pm1_event_length: u8 align(1), 80 | pm1_control_length: u8 align(1), 81 | pm2_control_length: u8 align(1), 82 | pm_timer_length: u8 align(1), 83 | gpe0_length: u8 align(1), 84 | gpe1_length: u8 align(1), 85 | gpe1_base: u8 align(1), 86 | cstate_control: u8 align(1), 87 | worst_c2_latency: u16 align(1), 88 | worst_c3_latency: u16 align(1), 89 | flush_size: u16 align(1), 90 | flush_stride: u16 align(1), 91 | duty_offset: u8 align(1), 92 | duty_width: u8 align(1), 93 | day_alarm: u8 align(1), 94 | month_alarm: u8 align(1), 95 | century: u8 align(1), 96 | 97 | // Reserved in ACPI 1.0, used in ACPI 2.0+ 98 | boot_architecture_flags: u16 align(1), 99 | 100 | reserved2: u8 align(1), 101 | 102 | flags: u32 align(1), 103 | 104 | // Works only in ACPI 2.0+ (in theory) 105 | reset_reg: generic_addr_struct align(1), 106 | reset_value: u8 align(1), 107 | 108 | reserved3: [3]u8 align(1), 109 | 110 | // 64-bit pointers available on ACPI 2.0+ 111 | 112 | x_firmware_control: u64 align(1), 113 | x_dsdt: u64 align(1), 114 | 115 | x_pm1a_event_block: generic_addr_struct align(1), 116 | x_pm1b_event_block: generic_addr_struct align(1), 117 | x_pm1a_control_block: generic_addr_struct align(1), 118 | x_pm1b_control_block: generic_addr_struct align(1), 119 | x_pm2_control_block: generic_addr_struct align(1), 120 | x_pm_timer_block: generic_addr_struct align(1), 121 | x_gpe0_block: generic_addr_struct align(1), 122 | x_gpe1_block: generic_addr_struct align(1), 123 | }; 124 | 125 | var fadt_struct: *fadt = undefined; 126 | var initialized = false; 127 | 128 | pub fn init() void { 129 | if (multiboot.acpiVersion2) { 130 | console.writeln("[acpi] detected version 2.0+"); 131 | 132 | const xsdt_address: usize = @intCast(multiboot.acpiNewRsdp.xsdt_address); 133 | const xsdt_struct: *xsdt = @ptrFromInt(xsdt_address); 134 | const length: usize = @intCast((xsdt_struct.header.length - @sizeOf(std_header)) / 8); 135 | 136 | for (0..length) |i| { 137 | const address: usize = @intCast(xsdt_struct.other_sdt_headers[i]); 138 | const header: *std_header = @ptrFromInt(address); 139 | 140 | if (std.mem.eql(u8, header.signature[0..4], "FACP")) { 141 | console.writeln("[acpi] found fadt"); 142 | 143 | fadt_struct = @ptrFromInt(address); 144 | initialized = true; 145 | 146 | break; 147 | } 148 | } 149 | } else { 150 | console.writeln("[acpi] detected version 1.0"); 151 | 152 | const rsdt_struct: *rsdt = @ptrFromInt(multiboot.acpiOldRsdp.rsdt_address); 153 | const length: usize = @intCast((rsdt_struct.header.length - @sizeOf(std_header)) / 4); 154 | 155 | for (0..length) |i| { 156 | const address = rsdt_struct.other_sdt_headers[i]; 157 | const header: *std_header = @ptrFromInt(address); 158 | 159 | if (std.mem.eql(u8, header.signature[0..4], "FACP")) { 160 | console.writeln("[acpi] found fadt"); 161 | 162 | fadt_struct = @ptrFromInt(address); 163 | initialized = true; 164 | 165 | break; 166 | } 167 | } 168 | } 169 | } 170 | 171 | pub fn enable() void { 172 | if (!initialized) { 173 | console.writeln("[acpi] enable not supported"); 174 | return; 175 | } 176 | 177 | port.outb(@truncate(fadt_struct.smi_command_port), fadt_struct.acpi_enable); 178 | while ((port.inw(@truncate(fadt_struct.pm1a_control_block)) & 1) == 0) {} // Wait for ACPI to be enabled 179 | } 180 | 181 | pub fn disable() void { 182 | if (!initialized) { 183 | console.writeln("[acpi] disable not supported"); 184 | return; 185 | } 186 | 187 | port.outb(@truncate(fadt_struct.smi_command_port), fadt_struct.acpi_disable); 188 | while ((port.inw(@truncate(fadt_struct.pm1a_control_block)) & 1) != 0) {} // Wait for ACPI to be disabled 189 | } 190 | 191 | pub fn shutdown() void { 192 | if (!initialized) { 193 | console.writeln("[acpi] shutdown not supported"); 194 | return; 195 | } 196 | 197 | // TODO: implement acpi shutdown 198 | } 199 | 200 | pub fn reset() void { 201 | if (!initialized) { 202 | console.writeln("[acpi] reset not supported"); 203 | return; 204 | } 205 | 206 | if (fadt_struct.header.revision < 2) { 207 | console.writeln("[acpi] reset not supported due to old version"); 208 | return; 209 | } 210 | 211 | if ((fadt_struct.flags & (1 << 10)) == 0) { 212 | console.writeln("[acpi] reset not supported due to feature not supported"); 213 | return; 214 | } 215 | 216 | port.outb(@truncate(fadt_struct.reset_reg.address), fadt_struct.reset_value); 217 | } 218 | -------------------------------------------------------------------------------- /src/art.zig: -------------------------------------------------------------------------------- 1 | pub const ASUKA_LOGO = [_][]const u8{ 2 | " _ _ ___ ____ ", 3 | " / \\ ___ _ _| | ____ _ / _ \\/ ___| ", 4 | " / _ \\ / __| | | | |/ / _` | | | \\___ \\ ", 5 | " / ___ \\__ \\ |_| | < (_| | |_| |___) |", 6 | " /_/ \\_\\___/\\__,_|_|\\_\\__,_|\\___/|____/ ", 7 | }; 8 | 9 | // this used to not work lmao 10 | pub const ASUKA_LOGO2: []const u8 = 11 | \\ _ _ ___ ____ 12 | \\ / \ ___ _ _| | ____ _ / _ \/ ___| 13 | \\ / _ \ / __| | | | |/ / _` | | | \___ \ 14 | \\ / ___ \__ \ |_| | < (_| | |_| |___) | 15 | \\ /_/ \_\___/\__,_|_|\_\__,_|\___/|____/ 16 | ; 17 | 18 | pub const LKA: []const u8 = 19 | \\ /* (c) Don Yang (8/27/1998) */#include/*DOS only - MSC 6.0 / TC 3.0*/ 20 | \\ int _far*_=(int _far*)0xb8000000L;int z[]={0,2271,2015,4063,2268,2267,30940,0, 21 | \\ 2012,30943,2011,32735,4060,0,32732,4059};int s[]={2,-214,67,-205,-6,-61,-28,-2 22 | \\ ,-1,17,71,3,169,-3,199,206,287,9,319,6-0,333,19,340,3,416,1,485,17,501,-2,523, 23 | \\ 549,4,577,-3,595,654,736,20,740,18,790,1,815,9,825,15,871,1,923,7,977,3,999,0, 24 | \\ 1,-215,66,-204,60,-121,1,-7,10,7,-2,50,120,6,123,1-0,171,21,178,1,205,3,392,7, 25 | \\ 400,3,482,12,583,1,653,8,658,1,681,25,684,1,728,4,828,1,884,7,916,1,982,0,64,- 26 | \\ 203,1,-78,15,-76,1,128,4,335,1,393,11,584,1,652,18,741,12,872,4,978,0,14,-136, 27 | \\ 28,-106,1,-41,5,1,1,40,9,159,-3,174,175,203,21,289,24,367,2,397,26,445,7,473,1 28 | \\ ,495,25,604,1-0,665,9,672,5,731,3,761,1,822,7,837,8,887,23,953,1,997,0,-2,150, 29 | \\ 237,9,239,4 ,360,1,438,4,440,1,628,22,630,-2,708,843,25,845,0,11,-39,8,+ 30 | \\ 42,-5,+157, 317,327,443,470,3,497,1,602,18,710,1,904,0 ,0,18,-59,3 31 | \\ ,2,21,+19, 5,73,-4,201,202,414,479,8, 487-0,25, 551,1,580,4 32 | \\ ,598,1,664 ,7,+674,4, 732,+6,809-0, 5,817,5, 838,1,869,7 33 | \\ ,907-0,1, 952,13,+ 963,12-0,985 , 419,1004, 34 | \\ 0,46 ,0- 185,7,80,+5, 152,-7 35 | \\ ,0- 0+ 167,283,286 ,338, 36 | \\ 499 ,+ 575,788,27 ,0+ 37 | \\ 925, 0,- 5, 247,250,+ 278 -0,+ 358 38 | \\ ,363,24 ,525, 23, 765,0, 75, -290 ,+ 39 | \\ 17,+0- 202,1 ,0- 140, 0+13,+ 0- 40 | \\ 120,6, -84,13 ,-75 ,-2, -29,-8, 9 41 | \\ ,8,7, 89,+4, 124, 20 , 179,+18-0 , 42 | \\ 260,5 ,312,1, 406,+ 17 ,+ 421,-2,517 , 43 | \\ 548, 9,585,- 3,650,651,680, 16, 742,1,806, + 44 | \\ 10, 873,+1, 894,6,917,2,979 ,0, 12,-135,2, 3, 45 | \\ 5,+ 474 ,13 ,562,0+1,663,+3 , 733,0-2, 0+ 46 | \\ 0- 0+ 762,820,4,839,-2 ,+913,+ 951 47 | \\ , + 11,964,1,1057,361, 1062, 0,+0, 48 | \\ 10 ,0- 134,17,-58,18,-26,20 ,20,18,53 ,4,74,1 49 | \\ ,86, 22,98, 18,132,1,202,19,211,5,+ 232,1,257,20, 290,22,0+ 50 | \\ 368,5,409,24,446,4,475,7,488,3,520,10,552,10,565,3,599,1,662,5,675,2,734,8,748 51 | \\ ,1,819,3,840,6,888,5,908,1,950,+10,965,10,986,1,1056,360,1063,0,287,-577,70,0- 52 | \\ 287,15,-201,44,-184,5,-131,12,-119,21,-105,3,-83,11,-73,15,-57,9,-38,17,-25,7, 53 | \\ 9,18,21,7,43,17,54,2,75,5,81,3,90,21,99,2,125,17,133,4,153,7,160,1,170,19,180, 54 | \\ 18,212,4,233,7,240,4,253,17,261,2,281,19,291,3,313,7,320,2,336,17,341,2,361,21 55 | \\ ,369,5,401,2,417,16,422,2,441,23,447,3,476,6,489,1,498,+15,502,2,521,22,526,8, 56 | \\ 553,8,567,2,578,4-0,587,2,600,23,605,19,631,3,659,3,677,23,685,17,711,4,744,6, 57 | \\ 750,22,766,15,791,5,810,-3,818,841,842,23,846,5,889,7,897,5,918,24,926,8,967,8 58 | \\ ,987,51,1005,13,1065,340,1083,0};void main(void){int k=0,a=0,m=1,e=657;for(a=0 59 | \\ ;a<50;a++)printf("\n");while(m<16){if(s[k]){if(s[k]<0){for(a=-s[k++];a;a--)_[s 60 | \\ [k++]+e]=z[m];k--;}else{a=s[k++];while(a)_[--a+s[k]+e]=z[m];}}else{m++;}k++;}} 61 | ; 62 | 63 | pub const KA: []const u8 = 64 | \\ /* (c) Don Yang (8/27/1998) */#include/*DOS only - MSC 6.0 / TC 3.0*/ 65 | \\ int _far*_=(int _far*)0xb8000000L;int z[]={0,2271,2015,4063,2268,2267,30940,0, 66 | \\ ,495,25,604,1-0,665,9,672,5,731,3,761,1,822,7,837,8,887,23,953,1,997,0,-2,150, 67 | \\ 237,9,239,4 ,360,1,438,4,440,1,628,22,630,-2,708,843,25,845,0,11,-39,8,+ 68 | \\ 42,-5,+157, 317,327,443,470,3,497,1,602,18,710,1,904,0 ,0,18,-59,3 69 | \\ ,2,21,+19, 5,73,-4,201,202,414,479,8, 487-0,25, 551,1,580,4 70 | \\ ,598,1,664 ,7,+674,4, 732,+6,809-0, 5,817,5, 838,1,869,7 71 | \\ ,907-0,1, 952,13,+ 963,12-0,985 , 419,1004, 72 | \\ 0,46 ,0- 185,7,80,+5, 152,-7 73 | \\ ,0- 0+ 167,283,286 ,338, 74 | \\ 499 ,+ 575,788,27 ,0+ 75 | \\ 925, 0,- 5, 247,250,+ 278 -0,+ 358 76 | \\ ,363,24 ,525, 23, 765,0, 75, -290 ,+ 77 | \\ 17,+0- 202,1 ,0- 140, 0+13,+ 0- 78 | \\ 120,6, -84,13 ,-75 ,-2, -29,-8, 9 79 | \\ ,8,7, 89,+4, 124, 20 , 179,+18-0 , 80 | \\ 260,5 ,312,1, 406,+ 17 ,+ 421,-2,517 , 81 | \\ 548, 9,585,- 3,650,651,680, 16, 742,1,806, + 82 | \\ 10, 873,+1, 894,6,917,2,979 ,0, 12,-135,2, 3, 83 | \\ 5,+ 474 ,13 ,562,0+1,663,+3 , 733,0-2, 0+ 84 | \\ 0- 0+ 762,820,4,839,-2 ,+913,+ 951 85 | \\ , + 11,964,1,1057,361, 1062, 0,+0, 86 | \\ 10 ,0- 134,17,-58,18,-26,20 ,20,18,53 ,4,74,1 87 | \\ ,86, 22,98, 18,132,1,202,19,211,5,+ 232,1,257,20, 290,22,0+ 88 | \\ 368,5,409,24,446,4,475,7,488,3,520,10,552,10,565,3,599,1,662,5,675,2,734,8,748 89 | \\ [k++]+e]=z[m];k--;}else{a=s[k++];while(a)_[--a+s[k]+e]=z[m];}}else{m++;}k++;}} 90 | ; 91 | -------------------------------------------------------------------------------- /src/asm/entry.s: -------------------------------------------------------------------------------- 1 | .global _start 2 | .type _start, @function 3 | .align 8 4 | 5 | _start: 6 | mov $0x80000, %esp 7 | 8 | push %ebx 9 | 10 | call kmain 11 | 12 | cli 13 | hlt 14 | 15 | -------------------------------------------------------------------------------- /src/asm/helpers.s: -------------------------------------------------------------------------------- 1 | .global load_gdt 2 | .type load_gdt, @function 3 | .align 4 4 | 5 | load_gdt: 6 | mov 4(%esp), %eax 7 | lgdt (%eax) 8 | ljmp $0x08, $jmp_done 9 | jmp_done: 10 | mov $0x10, %ax 11 | mov %ax, %ds 12 | mov %ax, %es 13 | mov %ax, %fs 14 | mov %ax, %gs 15 | mov %ax, %ss 16 | ret 17 | 18 | .global load_idt 19 | .type load_idt, @function 20 | .align 4 21 | 22 | load_idt: 23 | mov 4(%esp), %eax 24 | lidt (%eax) 25 | ret 26 | 27 | .global load_page_directory 28 | .type load_page_directory, @function 29 | .align 4 30 | 31 | load_page_directory: 32 | mov 4(%esp), %eax 33 | mov %eax, %cr3 34 | ret 35 | 36 | .global enable_paging 37 | .type enable_paging, @function 38 | .align 4 39 | 40 | enable_paging: 41 | mov %cr0, %eax 42 | or $0x80000000, %eax 43 | mov %eax, %cr0 44 | ret 45 | 46 | -------------------------------------------------------------------------------- /src/console.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const fmt = @import("std").fmt; 3 | const port = @import("port.zig"); 4 | 5 | const VGA_WIDTH = 80; 6 | const VGA_HEIGHT = 25; 7 | const VGA_SIZE = VGA_WIDTH * VGA_HEIGHT; 8 | 9 | // console colors 10 | pub const Colors = enum(u8) { 11 | Black = 0, 12 | Blue = 1, 13 | Green = 2, 14 | Cyan = 3, 15 | Red = 4, 16 | Magenta = 5, 17 | Brown = 6, 18 | LightGray = 7, 19 | DarkGray = 8, 20 | LightBlue = 9, 21 | LightGreen = 10, 22 | LightCyan = 11, 23 | LightRed = 12, 24 | LightMagenta = 13, 25 | LightBrown = 14, 26 | White = 15, 27 | }; 28 | 29 | var row: usize = 0; 30 | var column: usize = 0; 31 | 32 | // default console colors 33 | var color = vgaEntryColor(Colors.Green, Colors.Black); 34 | 35 | // init screen buffer, many item pointer (volatile means it will change, tell compiler not to cache) 0xB8000 is the VGA buffer location 36 | // in the BIOS (as far as I know) 37 | var buffer = @as([*]volatile u16, @ptrFromInt(0xB8000)); 38 | // var buffer = @as([*]volatile u16, @ptrFromInt(0xA0000)); // framebuffer 39 | 40 | // color is an 8bit int with the first 4 bytes being the fg and last 4 bytes being the bg 41 | // BBBBFFFF 42 | fn vgaEntryColor(fg: Colors, bg: Colors) u8 { 43 | return @intFromEnum(fg) | (@intFromEnum(bg) << 4); 44 | } 45 | 46 | fn vgaEntry(uc: u8, new_color: u8) u16 { 47 | const c: u16 = new_color; 48 | 49 | return uc | (c << 8); 50 | } 51 | 52 | pub fn initialize() void { 53 | clear(); 54 | } 55 | 56 | pub fn setColor(new_color: u8) void { 57 | color = new_color; 58 | } 59 | 60 | pub fn setColor2(new_color: Colors) void { 61 | color = @intFromEnum(new_color); 62 | } 63 | 64 | // get the fg and bg color 65 | pub fn get_colors() u8 { 66 | return color; 67 | } 68 | 69 | // set the fg and bg 70 | pub fn set_colors(fg: Colors, bg: Colors) void { 71 | color = @intFromEnum(fg) | (@intFromEnum(bg) << 4); 72 | } 73 | 74 | // set the fg and bg 75 | pub fn set_bg(bg: u8) void { 76 | // clear the first 4 bits (bg) shift the new bg over 4 bits and bitwise or them 77 | color = (bg << 4) | (color & 0x0F); 78 | } 79 | 80 | // set the fg and bg 81 | pub fn set_fg(fg: u8) void { 82 | // clear the last 4 bits (fg) and bitwise or them 83 | color = fg | (color & 0xF0); 84 | } 85 | 86 | // set the fg and bg 87 | pub fn set_bgc(bg: Colors) void { 88 | // clear the first 4 bits (bg) shift the new bg over 4 bits and bitwise or them 89 | color = (@intFromEnum(bg) << 4) | (color & 0x0F); 90 | } 91 | 92 | // set the fg and bg 93 | pub fn set_fgc(fg: Colors) void { 94 | // clear the last 4 bits (fg) and bitwise or them 95 | color = @intFromEnum(fg) | (color & 0xF0); 96 | } 97 | 98 | pub fn clear_line() void { 99 | var c: usize = column; // column plus the prompt size 100 | while (c > 0) : (c -= 1) { 101 | column -= 1; 102 | putCharAt(' ', color, column, row); 103 | setCursor(column, row); 104 | } 105 | // set cursor to home position 106 | setCursor(c, row); 107 | } 108 | 109 | pub fn clear() void { 110 | // clear the screen buffer with the set colors 111 | @memset(buffer[0..VGA_SIZE], vgaEntry(' ', color)); 112 | 113 | // set cursor to home position 114 | setCursor(0, 0); 115 | 116 | // reset position 117 | column = 0; 118 | row = 0; 119 | } 120 | 121 | pub fn putCharAt(c: u8, new_color: u8, x: usize, y: usize) void { 122 | const index = y * VGA_WIDTH + x; 123 | buffer[index] = vgaEntry(c, new_color); 124 | } 125 | 126 | pub fn putChar(c: u8) void { 127 | if (row == VGA_HEIGHT - 1) { 128 | scrollUp(); 129 | row -= 1; 130 | } 131 | 132 | // handle control sequences 133 | switch (c) { 134 | '\n' => { 135 | column = 0; 136 | row += 1; 137 | }, 138 | '\r' => { 139 | column = 0; 140 | }, 141 | '\t' => { 142 | column += 4; 143 | }, 144 | else => { 145 | putCharAt(c, color, column, row); 146 | column += 1; 147 | setCursor(column, row); 148 | }, 149 | } 150 | 151 | // wrap back around when we reach the right side 152 | if (column >= VGA_WIDTH) { 153 | column = 0; 154 | row += 1; 155 | 156 | if (row >= VGA_HEIGHT) row = 0; 157 | } 158 | } 159 | 160 | // write the given bytes to output - alias for write 161 | pub fn puts(data: []const u8) void { 162 | for (data) |c| putChar(c); 163 | } 164 | 165 | // write the given bytes to output 166 | pub fn write(data: []const u8) void { 167 | for (data) |c| putChar(c); 168 | } 169 | 170 | // same as write and puts but adds a newline to the given string 171 | pub fn writeln(data: []const u8) void { 172 | for (data) |c| putChar(c); 173 | newLine(); 174 | } 175 | 176 | // standard printf function 177 | pub fn printf(comptime format: []const u8, args: anytype) void { 178 | console_writer.print(format, args) catch {}; 179 | } 180 | 181 | pub fn print_err(comptime format: []const u8, args: anytype) void { 182 | printf("[ERR] " ++ format ++ "\n", args); 183 | } 184 | 185 | pub fn print_ok(comptime format: []const u8, args: anytype) void { 186 | printf("[OK] " ++ format ++ "\n", args); 187 | } 188 | 189 | const console_writer = Console.writer(); 190 | 191 | // TODO: check for errors with the port inbound and outbound and handle them 192 | pub const Console = struct { 193 | pub fn println(comptime format: []const u8, args: anytype) void { 194 | print(format ++ "\n", args); 195 | } 196 | 197 | pub fn print(comptime format: []const u8, args: anytype) void { 198 | if (@import("builtin").is_test) { 199 | @import("std").debug.print(format, args); 200 | return; 201 | } 202 | 203 | writer.print(format, args) catch {}; 204 | } 205 | 206 | pub fn write(data: []const u8) void { 207 | for (data) |c| putChar(c); 208 | } 209 | 210 | pub fn write_array(values: []const u8) usize { 211 | var written: usize = 0; 212 | for (values) |value| { 213 | written += 1; 214 | putChar(value); 215 | } 216 | 217 | return written; 218 | } 219 | 220 | pub fn writeWithContext(self: Console, values: []const u8) WriteError!usize { 221 | _ = self; 222 | return write_array(values); 223 | } 224 | 225 | const WriteError = error{CannotWrite}; 226 | const SerialWriter = std.io.Writer(Console, WriteError, writeWithContext); 227 | 228 | pub fn writer() SerialWriter { 229 | return .{ .context = Console{} }; 230 | } 231 | }; 232 | 233 | pub fn newLine() void { 234 | column = 0; 235 | row += 1; 236 | } 237 | 238 | pub fn backspace() void { 239 | column -= 1; 240 | putCharAt(' ', color, column, row); 241 | setCursor(column, row); 242 | } 243 | 244 | pub fn enableCursor() void { 245 | // start pos 246 | port.outb(0x3D4, 0x0A); 247 | port.outb(0x3D5, (port.inb(0x3D5) & 0xC0) | 0); // 0 for the cursor_start position 248 | 249 | // end pos 250 | port.outb(0x3D4, 0x0B); 251 | port.outb(0x3D5, (port.inb(0x3D5) & 0xE0) | VGA_HEIGHT); // 0 for the cursor_start position 252 | } 253 | 254 | pub fn disableCursor() void { 255 | port.outb(0x3D4, 0x0A); 256 | port.outb(0x3D5, 0x20); 257 | } 258 | 259 | pub fn setCursor(x: usize, y: usize) void { 260 | const position = y * VGA_WIDTH + x; 261 | 262 | port.outb(0x3D4, 0x0F); 263 | port.outb(0x3D5, @as(u8, @intCast(position & 0xFF))); 264 | 265 | port.outb(0x3D4, 0x0E); 266 | port.outb(0x3D5, @as(u8, @intCast((position >> 8) & 0xFF))); 267 | } 268 | 269 | pub fn scrollUp() void { 270 | for (1..VGA_HEIGHT) |y| { 271 | for (0..VGA_WIDTH) |x| { 272 | buffer[(y - 1) * VGA_WIDTH + x] = buffer[y * VGA_WIDTH + x]; 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/gdt.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const pmm = @import("mem.zig"); 3 | 4 | const GDT_ENTRIES = 3; 5 | 6 | const gdt_entry = packed struct { 7 | limit_low: u16, 8 | base_low: u16, 9 | base_middle: u8, 10 | access: u8, 11 | granularity: u8, 12 | base_high: u8, 13 | }; 14 | 15 | const gdtr = packed struct { size: u16, offset: u32 }; 16 | 17 | extern fn load_gdt(gdt: usize) void; 18 | 19 | fn create_entry(address: u32, limit: u32, access: u8, granularity: u8) gdt_entry { 20 | return gdt_entry{ 21 | .base_low = @as(u16, @intCast(address & 0xFFFF)), 22 | .base_middle = @as(u8, @intCast((address >> 16) & 0xFF)), 23 | .base_high = @as(u8, @intCast((address >> 24) & 0xFF)), 24 | .limit_low = @as(u16, @intCast(limit & 0xFFFF)), 25 | .granularity = @as(u8, @intCast(@as(u8, @intCast((limit >> 16) & 0x0F)) | (granularity & 0xF0))), 26 | .access = access, 27 | }; 28 | } 29 | 30 | pub fn init() void { 31 | // Initialize buffer and add all segments 32 | const gdt_entries_size = @sizeOf(gdt_entry) * GDT_ENTRIES; 33 | 34 | const gdt_entries_address = pmm.allocate(gdt_entries_size); 35 | const gdt_entries = @as([*]gdt_entry, @ptrFromInt(gdt_entries_address)); 36 | 37 | gdt_entries[0] = create_entry(0, 0, 0, 0); // Null segment 38 | gdt_entries[1] = create_entry(0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment 39 | gdt_entries[2] = create_entry(0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment 40 | 41 | // Load GDT 42 | const gdt_address = pmm.allocate(@sizeOf(gdtr)); 43 | const gdt = @as(*gdtr, @ptrFromInt(gdt_address)); 44 | 45 | gdt.size = gdt_entries_size - 1; 46 | gdt.offset = @as(u32, gdt_entries_address); 47 | 48 | load_gdt(@as(u32, gdt_address)); 49 | } 50 | -------------------------------------------------------------------------------- /src/idt.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const pmm = @import("./mem.zig"); 3 | const pic = @import("./pic.zig"); 4 | const ps2 = @import("./ps2.zig"); 5 | const pit = @import("pit.zig"); 6 | // interrupt descriptor table 7 | 8 | const IDT_ENTRIES = 256; 9 | 10 | const segment_select = packed struct { rpl: u2, ti: u1, index: u13 }; 11 | const type_attrib = packed struct { gate_type: u4, zero: u1, dpl: u2, p: u1 }; 12 | const idt_entry = packed struct { 13 | offset1: u16, 14 | selector: segment_select, 15 | zero: u8, 16 | type_attributes: type_attrib, 17 | offset2: u16, 18 | }; 19 | 20 | const idtr = packed struct { size: u16, offset: u32 }; 21 | 22 | fn create_entry(offset: u32) idt_entry { 23 | const type_attr = type_attrib{ 24 | .gate_type = 0b1110, 25 | .zero = 0b0, 26 | .dpl = 0b00, 27 | .p = 0b1, 28 | }; 29 | 30 | const segment_sel = segment_select{ 31 | .rpl = 0b00, 32 | .ti = 0b0, 33 | .index = 0b0000000000001, 34 | }; 35 | 36 | return idt_entry{ 37 | .offset1 = @as(u16, @intCast(offset & 0xFFFF)), 38 | .selector = segment_sel, 39 | .zero = 0, 40 | .type_attributes = type_attr, 41 | .offset2 = @as(u16, @intCast((offset >> 16) & 0xFFFF)), 42 | }; 43 | } 44 | 45 | fn interrupt_handler(irq: u8, code: u32) void { 46 | switch (irq) { 47 | 0 => { 48 | std.debug.panic("Division Error", .{}); 49 | return; 50 | }, 51 | 1 => { 52 | std.debug.panic("Debug", .{}); 53 | return; 54 | }, 55 | 2 => { 56 | std.debug.panic("Non-maskable Interrupt", .{}); 57 | return; 58 | }, 59 | 3 => { 60 | std.debug.panic("Breakpoint", .{}); 61 | return; 62 | }, 63 | 4 => { 64 | std.debug.panic("Overflow", .{}); 65 | return; 66 | }, 67 | 5 => { 68 | std.debug.panic("Bound Range Exceeded", .{}); 69 | return; 70 | }, 71 | 6 => { 72 | std.debug.panic("Invalid Opcode", .{}); 73 | return; 74 | }, 75 | 7 => { 76 | std.debug.panic("Device Not Available", .{}); 77 | return; 78 | }, 79 | 8 => { 80 | std.debug.panic("Double Fault: {d}", .{code}); 81 | return; 82 | }, 83 | 10 => { 84 | std.debug.panic("Invalid TSS: {d}", .{code}); 85 | return; 86 | }, 87 | 11 => { 88 | std.debug.panic("Segment Not Present: {d}", .{code}); 89 | return; 90 | }, 91 | 12 => { 92 | std.debug.panic("Stack-Segment Fault: {d}", .{code}); 93 | return; 94 | }, 95 | 13 => { 96 | std.debug.panic("General Protection Fault: {d}", .{code}); 97 | return; 98 | }, 99 | 14 => { 100 | std.debug.panic("Page Fault: {d}", .{code}); 101 | return; 102 | }, 103 | 16 => { 104 | std.debug.panic("x87 Floating-Point Exception", .{}); 105 | return; 106 | }, 107 | 17 => { 108 | std.debug.panic("Alignment Check: {d}", .{code}); 109 | return; 110 | }, 111 | 18 => { 112 | std.debug.panic("Machine Check", .{}); 113 | return; 114 | }, 115 | 19 => { 116 | std.debug.panic("SIMD Floating-Point Exception", .{}); 117 | return; 118 | }, 119 | 20 => { 120 | std.debug.panic("Virtualization Exception", .{}); 121 | return; 122 | }, 123 | 21 => { 124 | std.debug.panic("Control Protection Exception: {d}", .{code}); 125 | return; 126 | }, 127 | 28 => { 128 | std.debug.panic("Hypervisor Injection Exception", .{}); 129 | return; 130 | }, 131 | 29 => { 132 | std.debug.panic("VMM Communication Exception: {d}", .{code}); 133 | return; 134 | }, 135 | 30 => { 136 | std.debug.panic("Security Exception: {d}", .{code}); 137 | return; 138 | }, 139 | // 31 => { // reserved 140 | // std.debug.panic("Security Exception: {d}", .{code}); 141 | // return; 142 | // }, 143 | 32 => { 144 | pit.tick(); 145 | pic.pic_end_master(); 146 | // pic.sendEOI(@as(u8, @intCast(irq))); 147 | }, 148 | 149 | else => { 150 | // register our keyboard handler 151 | // https://alamot.github.io/os_isr/ 152 | if (irq >= 0x20 and irq < 0x30) { // between 32-48 -- 33 is keyboard, 44 is ps2 mouse -- switch on 1-16 153 | switch (irq - 0x20) { 154 | 1 => { 155 | ps2.onInterrupt(); 156 | }, 157 | // 2 => { //pic cascade 158 | // }, 159 | else => {}, 160 | } 161 | } 162 | 163 | pic.sendEOI(@as(u8, @intCast(irq))); 164 | return; 165 | }, 166 | } 167 | } 168 | 169 | extern fn load_idt(idt: usize) void; 170 | 171 | fn irq0() callconv(.Interrupt) void { 172 | interrupt_handler(0, 0); 173 | } 174 | fn irq1() callconv(.Interrupt) void { 175 | interrupt_handler(1, 0); 176 | } 177 | fn irq2() callconv(.Interrupt) void { 178 | interrupt_handler(2, 0); 179 | } 180 | fn irq3() callconv(.Interrupt) void { 181 | interrupt_handler(3, 0); 182 | } 183 | fn irq4() callconv(.Interrupt) void { 184 | interrupt_handler(4, 0); 185 | } 186 | fn irq5() callconv(.Interrupt) void { 187 | interrupt_handler(5, 0); 188 | } 189 | fn irq6() callconv(.Interrupt) void { 190 | interrupt_handler(6, 0); 191 | } 192 | fn irq7() callconv(.Interrupt) void { 193 | interrupt_handler(7, 0); 194 | } 195 | // fn irq8(code: u32) callconv(.Interrupt) void { 196 | // interrupt_handler(8, code); 197 | // } 198 | 199 | fn irq8(code: *u32) callconv(.Interrupt) void { 200 | interrupt_handler(8, code.*); 201 | } 202 | 203 | fn irq9() callconv(.Interrupt) void { 204 | interrupt_handler(9, 0); 205 | } 206 | fn irq10(code: *u32) callconv(.Interrupt) void { 207 | interrupt_handler(10, code.*); 208 | } 209 | fn irq11(code: *u32) callconv(.Interrupt) void { 210 | interrupt_handler(11, code.*); 211 | } 212 | fn irq12(code: *u32) callconv(.Interrupt) void { 213 | interrupt_handler(12, code.*); 214 | } 215 | fn irq13(code: *u32) callconv(.Interrupt) void { 216 | interrupt_handler(13, code.*); 217 | } 218 | fn irq14(code: *u32) callconv(.Interrupt) void { 219 | interrupt_handler(14, code.*); 220 | } 221 | fn irq15() callconv(.Interrupt) void { 222 | interrupt_handler(15, 0); 223 | } 224 | fn irq16() callconv(.Interrupt) void { 225 | interrupt_handler(16, 0); 226 | } 227 | fn irq17(code: *u32) callconv(.Interrupt) void { 228 | interrupt_handler(17, code.*); 229 | } 230 | fn irq18() callconv(.Interrupt) void { 231 | interrupt_handler(18, 0); 232 | } 233 | fn irq19() callconv(.Interrupt) void { 234 | interrupt_handler(19, 0); 235 | } 236 | fn irq20() callconv(.Interrupt) void { 237 | interrupt_handler(20, 0); 238 | } 239 | fn irq21(code: *u32) callconv(.Interrupt) void { 240 | interrupt_handler(21, code.*); 241 | } 242 | fn irq22() callconv(.Interrupt) void { 243 | interrupt_handler(22, 0); 244 | } 245 | fn irq23() callconv(.Interrupt) void { 246 | interrupt_handler(23, 0); 247 | } 248 | fn irq24() callconv(.Interrupt) void { 249 | interrupt_handler(24, 0); 250 | } 251 | fn irq25() callconv(.Interrupt) void { 252 | interrupt_handler(25, 0); 253 | } 254 | fn irq26() callconv(.Interrupt) void { 255 | interrupt_handler(26, 0); 256 | } 257 | fn irq27() callconv(.Interrupt) void { 258 | interrupt_handler(27, 0); 259 | } 260 | fn irq28() callconv(.Interrupt) void { 261 | interrupt_handler(28, 0); 262 | } 263 | fn irq29(code: *u32) callconv(.Interrupt) void { 264 | interrupt_handler(29, code.*); 265 | } 266 | fn irq30(code: *u32) callconv(.Interrupt) void { 267 | interrupt_handler(30, code.*); 268 | } 269 | fn irq31() callconv(.Interrupt) void { 270 | interrupt_handler(31, 0); 271 | } 272 | fn irq32() callconv(.Interrupt) void { 273 | interrupt_handler(32, 0); 274 | } 275 | fn irq33() callconv(.Interrupt) void { 276 | interrupt_handler(33, 0); 277 | } 278 | fn irq34() callconv(.Interrupt) void { 279 | interrupt_handler(34, 0); 280 | } 281 | fn irq35() callconv(.Interrupt) void { 282 | interrupt_handler(35, 0); 283 | } 284 | fn irq36() callconv(.Interrupt) void { 285 | interrupt_handler(36, 0); 286 | } 287 | fn irq37() callconv(.Interrupt) void { 288 | interrupt_handler(37, 0); 289 | } 290 | fn irq38() callconv(.Interrupt) void { 291 | interrupt_handler(38, 0); 292 | } 293 | fn irq39() callconv(.Interrupt) void { 294 | interrupt_handler(39, 0); 295 | } 296 | fn irq40() callconv(.Interrupt) void { 297 | interrupt_handler(40, 0); 298 | } 299 | fn irq41() callconv(.Interrupt) void { 300 | interrupt_handler(41, 0); 301 | } 302 | fn irq42() callconv(.Interrupt) void { 303 | interrupt_handler(42, 0); 304 | } 305 | fn irq43() callconv(.Interrupt) void { 306 | interrupt_handler(43, 0); 307 | } 308 | fn irq44() callconv(.Interrupt) void { 309 | interrupt_handler(44, 0); 310 | } 311 | fn irq45() callconv(.Interrupt) void { 312 | interrupt_handler(45, 0); 313 | } 314 | fn irq46() callconv(.Interrupt) void { 315 | interrupt_handler(46, 0); 316 | } 317 | fn irq47() callconv(.Interrupt) void { 318 | interrupt_handler(47, 0); 319 | } 320 | fn irq48() callconv(.Interrupt) void { 321 | interrupt_handler(48, 0); 322 | } 323 | fn irq49() callconv(.Interrupt) void { 324 | interrupt_handler(49, 0); 325 | } 326 | fn irq50() callconv(.Interrupt) void { 327 | interrupt_handler(50, 0); 328 | } 329 | fn irq51() callconv(.Interrupt) void { 330 | interrupt_handler(51, 0); 331 | } 332 | fn irq52() callconv(.Interrupt) void { 333 | interrupt_handler(52, 0); 334 | } 335 | fn irq53() callconv(.Interrupt) void { 336 | interrupt_handler(53, 0); 337 | } 338 | fn irq54() callconv(.Interrupt) void { 339 | interrupt_handler(54, 0); 340 | } 341 | fn irq55() callconv(.Interrupt) void { 342 | interrupt_handler(55, 0); 343 | } 344 | fn irq56() callconv(.Interrupt) void { 345 | interrupt_handler(56, 0); 346 | } 347 | fn irq57() callconv(.Interrupt) void { 348 | interrupt_handler(57, 0); 349 | } 350 | fn irq58() callconv(.Interrupt) void { 351 | interrupt_handler(58, 0); 352 | } 353 | fn irq59() callconv(.Interrupt) void { 354 | interrupt_handler(59, 0); 355 | } 356 | fn irq60() callconv(.Interrupt) void { 357 | interrupt_handler(60, 0); 358 | } 359 | fn irq61() callconv(.Interrupt) void { 360 | interrupt_handler(61, 0); 361 | } 362 | fn irq62() callconv(.Interrupt) void { 363 | interrupt_handler(62, 0); 364 | } 365 | fn irq63() callconv(.Interrupt) void { 366 | interrupt_handler(63, 0); 367 | } 368 | fn irq64() callconv(.Interrupt) void { 369 | interrupt_handler(64, 0); 370 | } 371 | fn irq65() callconv(.Interrupt) void { 372 | interrupt_handler(65, 0); 373 | } 374 | fn irq66() callconv(.Interrupt) void { 375 | interrupt_handler(66, 0); 376 | } 377 | fn irq67() callconv(.Interrupt) void { 378 | interrupt_handler(67, 0); 379 | } 380 | fn irq68() callconv(.Interrupt) void { 381 | interrupt_handler(68, 0); 382 | } 383 | fn irq69() callconv(.Interrupt) void { 384 | interrupt_handler(69, 0); 385 | } 386 | fn irq70() callconv(.Interrupt) void { 387 | interrupt_handler(70, 0); 388 | } 389 | fn irq71() callconv(.Interrupt) void { 390 | interrupt_handler(71, 0); 391 | } 392 | fn irq72() callconv(.Interrupt) void { 393 | interrupt_handler(72, 0); 394 | } 395 | fn irq73() callconv(.Interrupt) void { 396 | interrupt_handler(73, 0); 397 | } 398 | fn irq74() callconv(.Interrupt) void { 399 | interrupt_handler(74, 0); 400 | } 401 | fn irq75() callconv(.Interrupt) void { 402 | interrupt_handler(75, 0); 403 | } 404 | fn irq76() callconv(.Interrupt) void { 405 | interrupt_handler(76, 0); 406 | } 407 | fn irq77() callconv(.Interrupt) void { 408 | interrupt_handler(77, 0); 409 | } 410 | fn irq78() callconv(.Interrupt) void { 411 | interrupt_handler(78, 0); 412 | } 413 | fn irq79() callconv(.Interrupt) void { 414 | interrupt_handler(79, 0); 415 | } 416 | fn irq80() callconv(.Interrupt) void { 417 | interrupt_handler(80, 0); 418 | } 419 | fn irq81() callconv(.Interrupt) void { 420 | interrupt_handler(81, 0); 421 | } 422 | fn irq82() callconv(.Interrupt) void { 423 | interrupt_handler(82, 0); 424 | } 425 | fn irq83() callconv(.Interrupt) void { 426 | interrupt_handler(83, 0); 427 | } 428 | fn irq84() callconv(.Interrupt) void { 429 | interrupt_handler(84, 0); 430 | } 431 | fn irq85() callconv(.Interrupt) void { 432 | interrupt_handler(85, 0); 433 | } 434 | fn irq86() callconv(.Interrupt) void { 435 | interrupt_handler(86, 0); 436 | } 437 | fn irq87() callconv(.Interrupt) void { 438 | interrupt_handler(87, 0); 439 | } 440 | fn irq88() callconv(.Interrupt) void { 441 | interrupt_handler(88, 0); 442 | } 443 | fn irq89() callconv(.Interrupt) void { 444 | interrupt_handler(89, 0); 445 | } 446 | fn irq90() callconv(.Interrupt) void { 447 | interrupt_handler(90, 0); 448 | } 449 | fn irq91() callconv(.Interrupt) void { 450 | interrupt_handler(91, 0); 451 | } 452 | fn irq92() callconv(.Interrupt) void { 453 | interrupt_handler(92, 0); 454 | } 455 | fn irq93() callconv(.Interrupt) void { 456 | interrupt_handler(93, 0); 457 | } 458 | fn irq94() callconv(.Interrupt) void { 459 | interrupt_handler(94, 0); 460 | } 461 | fn irq95() callconv(.Interrupt) void { 462 | interrupt_handler(95, 0); 463 | } 464 | fn irq96() callconv(.Interrupt) void { 465 | interrupt_handler(96, 0); 466 | } 467 | fn irq97() callconv(.Interrupt) void { 468 | interrupt_handler(97, 0); 469 | } 470 | fn irq98() callconv(.Interrupt) void { 471 | interrupt_handler(98, 0); 472 | } 473 | fn irq99() callconv(.Interrupt) void { 474 | interrupt_handler(99, 0); 475 | } 476 | fn irq100() callconv(.Interrupt) void { 477 | interrupt_handler(100, 0); 478 | } 479 | fn irq101() callconv(.Interrupt) void { 480 | interrupt_handler(101, 0); 481 | } 482 | fn irq102() callconv(.Interrupt) void { 483 | interrupt_handler(102, 0); 484 | } 485 | fn irq103() callconv(.Interrupt) void { 486 | interrupt_handler(103, 0); 487 | } 488 | fn irq104() callconv(.Interrupt) void { 489 | interrupt_handler(104, 0); 490 | } 491 | fn irq105() callconv(.Interrupt) void { 492 | interrupt_handler(105, 0); 493 | } 494 | fn irq106() callconv(.Interrupt) void { 495 | interrupt_handler(106, 0); 496 | } 497 | fn irq107() callconv(.Interrupt) void { 498 | interrupt_handler(107, 0); 499 | } 500 | fn irq108() callconv(.Interrupt) void { 501 | interrupt_handler(108, 0); 502 | } 503 | fn irq109() callconv(.Interrupt) void { 504 | interrupt_handler(109, 0); 505 | } 506 | fn irq110() callconv(.Interrupt) void { 507 | interrupt_handler(110, 0); 508 | } 509 | fn irq111() callconv(.Interrupt) void { 510 | interrupt_handler(111, 0); 511 | } 512 | fn irq112() callconv(.Interrupt) void { 513 | interrupt_handler(112, 0); 514 | } 515 | fn irq113() callconv(.Interrupt) void { 516 | interrupt_handler(113, 0); 517 | } 518 | fn irq114() callconv(.Interrupt) void { 519 | interrupt_handler(114, 0); 520 | } 521 | fn irq115() callconv(.Interrupt) void { 522 | interrupt_handler(115, 0); 523 | } 524 | fn irq116() callconv(.Interrupt) void { 525 | interrupt_handler(116, 0); 526 | } 527 | fn irq117() callconv(.Interrupt) void { 528 | interrupt_handler(117, 0); 529 | } 530 | fn irq118() callconv(.Interrupt) void { 531 | interrupt_handler(118, 0); 532 | } 533 | fn irq119() callconv(.Interrupt) void { 534 | interrupt_handler(119, 0); 535 | } 536 | fn irq120() callconv(.Interrupt) void { 537 | interrupt_handler(120, 0); 538 | } 539 | fn irq121() callconv(.Interrupt) void { 540 | interrupt_handler(121, 0); 541 | } 542 | fn irq122() callconv(.Interrupt) void { 543 | interrupt_handler(122, 0); 544 | } 545 | fn irq123() callconv(.Interrupt) void { 546 | interrupt_handler(123, 0); 547 | } 548 | fn irq124() callconv(.Interrupt) void { 549 | interrupt_handler(124, 0); 550 | } 551 | fn irq125() callconv(.Interrupt) void { 552 | interrupt_handler(125, 0); 553 | } 554 | fn irq126() callconv(.Interrupt) void { 555 | interrupt_handler(126, 0); 556 | } 557 | fn irq127() callconv(.Interrupt) void { 558 | interrupt_handler(127, 0); 559 | } 560 | fn irq128() callconv(.Interrupt) void { 561 | interrupt_handler(128, 0); 562 | } 563 | fn irq129() callconv(.Interrupt) void { 564 | interrupt_handler(129, 0); 565 | } 566 | fn irq130() callconv(.Interrupt) void { 567 | interrupt_handler(130, 0); 568 | } 569 | fn irq131() callconv(.Interrupt) void { 570 | interrupt_handler(131, 0); 571 | } 572 | fn irq132() callconv(.Interrupt) void { 573 | interrupt_handler(132, 0); 574 | } 575 | fn irq133() callconv(.Interrupt) void { 576 | interrupt_handler(133, 0); 577 | } 578 | fn irq134() callconv(.Interrupt) void { 579 | interrupt_handler(134, 0); 580 | } 581 | fn irq135() callconv(.Interrupt) void { 582 | interrupt_handler(135, 0); 583 | } 584 | fn irq136() callconv(.Interrupt) void { 585 | interrupt_handler(136, 0); 586 | } 587 | fn irq137() callconv(.Interrupt) void { 588 | interrupt_handler(137, 0); 589 | } 590 | fn irq138() callconv(.Interrupt) void { 591 | interrupt_handler(138, 0); 592 | } 593 | fn irq139() callconv(.Interrupt) void { 594 | interrupt_handler(139, 0); 595 | } 596 | fn irq140() callconv(.Interrupt) void { 597 | interrupt_handler(140, 0); 598 | } 599 | fn irq141() callconv(.Interrupt) void { 600 | interrupt_handler(141, 0); 601 | } 602 | fn irq142() callconv(.Interrupt) void { 603 | interrupt_handler(142, 0); 604 | } 605 | fn irq143() callconv(.Interrupt) void { 606 | interrupt_handler(143, 0); 607 | } 608 | fn irq144() callconv(.Interrupt) void { 609 | interrupt_handler(144, 0); 610 | } 611 | fn irq145() callconv(.Interrupt) void { 612 | interrupt_handler(145, 0); 613 | } 614 | fn irq146() callconv(.Interrupt) void { 615 | interrupt_handler(146, 0); 616 | } 617 | fn irq147() callconv(.Interrupt) void { 618 | interrupt_handler(147, 0); 619 | } 620 | fn irq148() callconv(.Interrupt) void { 621 | interrupt_handler(148, 0); 622 | } 623 | fn irq149() callconv(.Interrupt) void { 624 | interrupt_handler(149, 0); 625 | } 626 | fn irq150() callconv(.Interrupt) void { 627 | interrupt_handler(150, 0); 628 | } 629 | fn irq151() callconv(.Interrupt) void { 630 | interrupt_handler(151, 0); 631 | } 632 | fn irq152() callconv(.Interrupt) void { 633 | interrupt_handler(152, 0); 634 | } 635 | fn irq153() callconv(.Interrupt) void { 636 | interrupt_handler(153, 0); 637 | } 638 | fn irq154() callconv(.Interrupt) void { 639 | interrupt_handler(154, 0); 640 | } 641 | fn irq155() callconv(.Interrupt) void { 642 | interrupt_handler(155, 0); 643 | } 644 | fn irq156() callconv(.Interrupt) void { 645 | interrupt_handler(156, 0); 646 | } 647 | fn irq157() callconv(.Interrupt) void { 648 | interrupt_handler(157, 0); 649 | } 650 | fn irq158() callconv(.Interrupt) void { 651 | interrupt_handler(158, 0); 652 | } 653 | fn irq159() callconv(.Interrupt) void { 654 | interrupt_handler(159, 0); 655 | } 656 | fn irq160() callconv(.Interrupt) void { 657 | interrupt_handler(160, 0); 658 | } 659 | fn irq161() callconv(.Interrupt) void { 660 | interrupt_handler(161, 0); 661 | } 662 | fn irq162() callconv(.Interrupt) void { 663 | interrupt_handler(162, 0); 664 | } 665 | fn irq163() callconv(.Interrupt) void { 666 | interrupt_handler(163, 0); 667 | } 668 | fn irq164() callconv(.Interrupt) void { 669 | interrupt_handler(164, 0); 670 | } 671 | fn irq165() callconv(.Interrupt) void { 672 | interrupt_handler(165, 0); 673 | } 674 | fn irq166() callconv(.Interrupt) void { 675 | interrupt_handler(166, 0); 676 | } 677 | fn irq167() callconv(.Interrupt) void { 678 | interrupt_handler(167, 0); 679 | } 680 | fn irq168() callconv(.Interrupt) void { 681 | interrupt_handler(168, 0); 682 | } 683 | fn irq169() callconv(.Interrupt) void { 684 | interrupt_handler(169, 0); 685 | } 686 | fn irq170() callconv(.Interrupt) void { 687 | interrupt_handler(170, 0); 688 | } 689 | fn irq171() callconv(.Interrupt) void { 690 | interrupt_handler(171, 0); 691 | } 692 | fn irq172() callconv(.Interrupt) void { 693 | interrupt_handler(172, 0); 694 | } 695 | fn irq173() callconv(.Interrupt) void { 696 | interrupt_handler(173, 0); 697 | } 698 | fn irq174() callconv(.Interrupt) void { 699 | interrupt_handler(174, 0); 700 | } 701 | fn irq175() callconv(.Interrupt) void { 702 | interrupt_handler(175, 0); 703 | } 704 | fn irq176() callconv(.Interrupt) void { 705 | interrupt_handler(176, 0); 706 | } 707 | fn irq177() callconv(.Interrupt) void { 708 | interrupt_handler(177, 0); 709 | } 710 | fn irq178() callconv(.Interrupt) void { 711 | interrupt_handler(178, 0); 712 | } 713 | fn irq179() callconv(.Interrupt) void { 714 | interrupt_handler(179, 0); 715 | } 716 | fn irq180() callconv(.Interrupt) void { 717 | interrupt_handler(180, 0); 718 | } 719 | fn irq181() callconv(.Interrupt) void { 720 | interrupt_handler(181, 0); 721 | } 722 | fn irq182() callconv(.Interrupt) void { 723 | interrupt_handler(182, 0); 724 | } 725 | fn irq183() callconv(.Interrupt) void { 726 | interrupt_handler(183, 0); 727 | } 728 | fn irq184() callconv(.Interrupt) void { 729 | interrupt_handler(184, 0); 730 | } 731 | fn irq185() callconv(.Interrupt) void { 732 | interrupt_handler(185, 0); 733 | } 734 | fn irq186() callconv(.Interrupt) void { 735 | interrupt_handler(186, 0); 736 | } 737 | fn irq187() callconv(.Interrupt) void { 738 | interrupt_handler(187, 0); 739 | } 740 | fn irq188() callconv(.Interrupt) void { 741 | interrupt_handler(188, 0); 742 | } 743 | fn irq189() callconv(.Interrupt) void { 744 | interrupt_handler(189, 0); 745 | } 746 | fn irq190() callconv(.Interrupt) void { 747 | interrupt_handler(190, 0); 748 | } 749 | fn irq191() callconv(.Interrupt) void { 750 | interrupt_handler(191, 0); 751 | } 752 | fn irq192() callconv(.Interrupt) void { 753 | interrupt_handler(192, 0); 754 | } 755 | fn irq193() callconv(.Interrupt) void { 756 | interrupt_handler(193, 0); 757 | } 758 | fn irq194() callconv(.Interrupt) void { 759 | interrupt_handler(194, 0); 760 | } 761 | fn irq195() callconv(.Interrupt) void { 762 | interrupt_handler(195, 0); 763 | } 764 | fn irq196() callconv(.Interrupt) void { 765 | interrupt_handler(196, 0); 766 | } 767 | fn irq197() callconv(.Interrupt) void { 768 | interrupt_handler(197, 0); 769 | } 770 | fn irq198() callconv(.Interrupt) void { 771 | interrupt_handler(198, 0); 772 | } 773 | fn irq199() callconv(.Interrupt) void { 774 | interrupt_handler(199, 0); 775 | } 776 | fn irq200() callconv(.Interrupt) void { 777 | interrupt_handler(200, 0); 778 | } 779 | fn irq201() callconv(.Interrupt) void { 780 | interrupt_handler(201, 0); 781 | } 782 | fn irq202() callconv(.Interrupt) void { 783 | interrupt_handler(202, 0); 784 | } 785 | fn irq203() callconv(.Interrupt) void { 786 | interrupt_handler(203, 0); 787 | } 788 | fn irq204() callconv(.Interrupt) void { 789 | interrupt_handler(204, 0); 790 | } 791 | fn irq205() callconv(.Interrupt) void { 792 | interrupt_handler(205, 0); 793 | } 794 | fn irq206() callconv(.Interrupt) void { 795 | interrupt_handler(206, 0); 796 | } 797 | fn irq207() callconv(.Interrupt) void { 798 | interrupt_handler(207, 0); 799 | } 800 | fn irq208() callconv(.Interrupt) void { 801 | interrupt_handler(208, 0); 802 | } 803 | fn irq209() callconv(.Interrupt) void { 804 | interrupt_handler(209, 0); 805 | } 806 | fn irq210() callconv(.Interrupt) void { 807 | interrupt_handler(210, 0); 808 | } 809 | fn irq211() callconv(.Interrupt) void { 810 | interrupt_handler(211, 0); 811 | } 812 | fn irq212() callconv(.Interrupt) void { 813 | interrupt_handler(212, 0); 814 | } 815 | fn irq213() callconv(.Interrupt) void { 816 | interrupt_handler(213, 0); 817 | } 818 | fn irq214() callconv(.Interrupt) void { 819 | interrupt_handler(214, 0); 820 | } 821 | fn irq215() callconv(.Interrupt) void { 822 | interrupt_handler(215, 0); 823 | } 824 | fn irq216() callconv(.Interrupt) void { 825 | interrupt_handler(216, 0); 826 | } 827 | fn irq217() callconv(.Interrupt) void { 828 | interrupt_handler(217, 0); 829 | } 830 | fn irq218() callconv(.Interrupt) void { 831 | interrupt_handler(218, 0); 832 | } 833 | fn irq219() callconv(.Interrupt) void { 834 | interrupt_handler(219, 0); 835 | } 836 | fn irq220() callconv(.Interrupt) void { 837 | interrupt_handler(220, 0); 838 | } 839 | fn irq221() callconv(.Interrupt) void { 840 | interrupt_handler(221, 0); 841 | } 842 | fn irq222() callconv(.Interrupt) void { 843 | interrupt_handler(222, 0); 844 | } 845 | fn irq223() callconv(.Interrupt) void { 846 | interrupt_handler(223, 0); 847 | } 848 | fn irq224() callconv(.Interrupt) void { 849 | interrupt_handler(224, 0); 850 | } 851 | fn irq225() callconv(.Interrupt) void { 852 | interrupt_handler(225, 0); 853 | } 854 | fn irq226() callconv(.Interrupt) void { 855 | interrupt_handler(226, 0); 856 | } 857 | fn irq227() callconv(.Interrupt) void { 858 | interrupt_handler(227, 0); 859 | } 860 | fn irq228() callconv(.Interrupt) void { 861 | interrupt_handler(228, 0); 862 | } 863 | fn irq229() callconv(.Interrupt) void { 864 | interrupt_handler(229, 0); 865 | } 866 | fn irq230() callconv(.Interrupt) void { 867 | interrupt_handler(230, 0); 868 | } 869 | fn irq231() callconv(.Interrupt) void { 870 | interrupt_handler(231, 0); 871 | } 872 | fn irq232() callconv(.Interrupt) void { 873 | interrupt_handler(232, 0); 874 | } 875 | fn irq233() callconv(.Interrupt) void { 876 | interrupt_handler(233, 0); 877 | } 878 | fn irq234() callconv(.Interrupt) void { 879 | interrupt_handler(234, 0); 880 | } 881 | fn irq235() callconv(.Interrupt) void { 882 | interrupt_handler(235, 0); 883 | } 884 | fn irq236() callconv(.Interrupt) void { 885 | interrupt_handler(236, 0); 886 | } 887 | fn irq237() callconv(.Interrupt) void { 888 | interrupt_handler(237, 0); 889 | } 890 | fn irq238() callconv(.Interrupt) void { 891 | interrupt_handler(238, 0); 892 | } 893 | fn irq239() callconv(.Interrupt) void { 894 | interrupt_handler(239, 0); 895 | } 896 | fn irq240() callconv(.Interrupt) void { 897 | interrupt_handler(240, 0); 898 | } 899 | fn irq241() callconv(.Interrupt) void { 900 | interrupt_handler(241, 0); 901 | } 902 | fn irq242() callconv(.Interrupt) void { 903 | interrupt_handler(242, 0); 904 | } 905 | fn irq243() callconv(.Interrupt) void { 906 | interrupt_handler(243, 0); 907 | } 908 | fn irq244() callconv(.Interrupt) void { 909 | interrupt_handler(244, 0); 910 | } 911 | fn irq245() callconv(.Interrupt) void { 912 | interrupt_handler(245, 0); 913 | } 914 | fn irq246() callconv(.Interrupt) void { 915 | interrupt_handler(246, 0); 916 | } 917 | fn irq247() callconv(.Interrupt) void { 918 | interrupt_handler(247, 0); 919 | } 920 | fn irq248() callconv(.Interrupt) void { 921 | interrupt_handler(248, 0); 922 | } 923 | fn irq249() callconv(.Interrupt) void { 924 | interrupt_handler(249, 0); 925 | } 926 | fn irq250() callconv(.Interrupt) void { 927 | interrupt_handler(250, 0); 928 | } 929 | fn irq251() callconv(.Interrupt) void { 930 | interrupt_handler(251, 0); 931 | } 932 | fn irq252() callconv(.Interrupt) void { 933 | interrupt_handler(252, 0); 934 | } 935 | fn irq253() callconv(.Interrupt) void { 936 | interrupt_handler(253, 0); 937 | } 938 | fn irq254() callconv(.Interrupt) void { 939 | interrupt_handler(254, 0); 940 | } 941 | fn irq255() callconv(.Interrupt) void { 942 | interrupt_handler(255, 0); 943 | } 944 | 945 | pub fn init() void { 946 | // Initialize buffer and add all entries 947 | const idt_entries_size = @sizeOf(idt_entry) * IDT_ENTRIES; 948 | 949 | const idt_entries_address = pmm.allocate(idt_entries_size); 950 | const idt_entries = @as([*]idt_entry, @ptrFromInt(idt_entries_address)); 951 | 952 | idt_entries[0] = create_entry(@as(u32, @intFromPtr(&irq0))); 953 | idt_entries[1] = create_entry(@as(u32, @intFromPtr(&irq1))); 954 | idt_entries[2] = create_entry(@as(u32, @intFromPtr(&irq2))); 955 | idt_entries[3] = create_entry(@as(u32, @intFromPtr(&irq3))); 956 | idt_entries[4] = create_entry(@as(u32, @intFromPtr(&irq4))); 957 | idt_entries[5] = create_entry(@as(u32, @intFromPtr(&irq5))); 958 | idt_entries[6] = create_entry(@as(u32, @intFromPtr(&irq6))); 959 | idt_entries[7] = create_entry(@as(u32, @intFromPtr(&irq7))); 960 | idt_entries[8] = create_entry(@as(u32, @intFromPtr(&irq8))); 961 | idt_entries[9] = create_entry(@as(u32, @intFromPtr(&irq9))); 962 | idt_entries[10] = create_entry(@as(u32, @intFromPtr(&irq10))); 963 | idt_entries[11] = create_entry(@as(u32, @intFromPtr(&irq11))); 964 | idt_entries[12] = create_entry(@as(u32, @intFromPtr(&irq12))); 965 | idt_entries[13] = create_entry(@as(u32, @intFromPtr(&irq13))); 966 | idt_entries[14] = create_entry(@as(u32, @intFromPtr(&irq14))); 967 | idt_entries[15] = create_entry(@as(u32, @intFromPtr(&irq15))); 968 | idt_entries[16] = create_entry(@as(u32, @intFromPtr(&irq16))); 969 | idt_entries[17] = create_entry(@as(u32, @intFromPtr(&irq17))); 970 | idt_entries[18] = create_entry(@as(u32, @intFromPtr(&irq18))); 971 | idt_entries[19] = create_entry(@as(u32, @intFromPtr(&irq19))); 972 | idt_entries[20] = create_entry(@as(u32, @intFromPtr(&irq20))); 973 | idt_entries[21] = create_entry(@as(u32, @intFromPtr(&irq21))); 974 | idt_entries[22] = create_entry(@as(u32, @intFromPtr(&irq22))); 975 | idt_entries[23] = create_entry(@as(u32, @intFromPtr(&irq23))); 976 | idt_entries[24] = create_entry(@as(u32, @intFromPtr(&irq24))); 977 | idt_entries[25] = create_entry(@as(u32, @intFromPtr(&irq25))); 978 | idt_entries[26] = create_entry(@as(u32, @intFromPtr(&irq26))); 979 | idt_entries[27] = create_entry(@as(u32, @intFromPtr(&irq27))); 980 | idt_entries[28] = create_entry(@as(u32, @intFromPtr(&irq28))); 981 | idt_entries[29] = create_entry(@as(u32, @intFromPtr(&irq29))); 982 | idt_entries[30] = create_entry(@as(u32, @intFromPtr(&irq30))); 983 | idt_entries[31] = create_entry(@as(u32, @intFromPtr(&irq31))); 984 | idt_entries[32] = create_entry(@as(u32, @intFromPtr(&irq32))); 985 | idt_entries[33] = create_entry(@as(u32, @intFromPtr(&irq33))); 986 | idt_entries[34] = create_entry(@as(u32, @intFromPtr(&irq34))); 987 | idt_entries[35] = create_entry(@as(u32, @intFromPtr(&irq35))); 988 | idt_entries[36] = create_entry(@as(u32, @intFromPtr(&irq36))); 989 | idt_entries[37] = create_entry(@as(u32, @intFromPtr(&irq37))); 990 | idt_entries[38] = create_entry(@as(u32, @intFromPtr(&irq38))); 991 | idt_entries[39] = create_entry(@as(u32, @intFromPtr(&irq39))); 992 | idt_entries[40] = create_entry(@as(u32, @intFromPtr(&irq40))); 993 | idt_entries[41] = create_entry(@as(u32, @intFromPtr(&irq41))); 994 | idt_entries[42] = create_entry(@as(u32, @intFromPtr(&irq42))); 995 | idt_entries[43] = create_entry(@as(u32, @intFromPtr(&irq43))); 996 | idt_entries[44] = create_entry(@as(u32, @intFromPtr(&irq44))); 997 | idt_entries[45] = create_entry(@as(u32, @intFromPtr(&irq45))); 998 | idt_entries[46] = create_entry(@as(u32, @intFromPtr(&irq46))); 999 | idt_entries[47] = create_entry(@as(u32, @intFromPtr(&irq47))); 1000 | idt_entries[48] = create_entry(@as(u32, @intFromPtr(&irq48))); 1001 | idt_entries[49] = create_entry(@as(u32, @intFromPtr(&irq49))); 1002 | idt_entries[50] = create_entry(@as(u32, @intFromPtr(&irq50))); 1003 | idt_entries[51] = create_entry(@as(u32, @intFromPtr(&irq51))); 1004 | idt_entries[52] = create_entry(@as(u32, @intFromPtr(&irq52))); 1005 | idt_entries[53] = create_entry(@as(u32, @intFromPtr(&irq53))); 1006 | idt_entries[54] = create_entry(@as(u32, @intFromPtr(&irq54))); 1007 | idt_entries[55] = create_entry(@as(u32, @intFromPtr(&irq55))); 1008 | idt_entries[56] = create_entry(@as(u32, @intFromPtr(&irq56))); 1009 | idt_entries[57] = create_entry(@as(u32, @intFromPtr(&irq57))); 1010 | idt_entries[58] = create_entry(@as(u32, @intFromPtr(&irq58))); 1011 | idt_entries[59] = create_entry(@as(u32, @intFromPtr(&irq59))); 1012 | idt_entries[60] = create_entry(@as(u32, @intFromPtr(&irq60))); 1013 | idt_entries[61] = create_entry(@as(u32, @intFromPtr(&irq61))); 1014 | idt_entries[62] = create_entry(@as(u32, @intFromPtr(&irq62))); 1015 | idt_entries[63] = create_entry(@as(u32, @intFromPtr(&irq63))); 1016 | idt_entries[64] = create_entry(@as(u32, @intFromPtr(&irq64))); 1017 | idt_entries[65] = create_entry(@as(u32, @intFromPtr(&irq65))); 1018 | idt_entries[66] = create_entry(@as(u32, @intFromPtr(&irq66))); 1019 | idt_entries[67] = create_entry(@as(u32, @intFromPtr(&irq67))); 1020 | idt_entries[68] = create_entry(@as(u32, @intFromPtr(&irq68))); 1021 | idt_entries[69] = create_entry(@as(u32, @intFromPtr(&irq69))); 1022 | idt_entries[70] = create_entry(@as(u32, @intFromPtr(&irq70))); 1023 | idt_entries[71] = create_entry(@as(u32, @intFromPtr(&irq71))); 1024 | idt_entries[72] = create_entry(@as(u32, @intFromPtr(&irq72))); 1025 | idt_entries[73] = create_entry(@as(u32, @intFromPtr(&irq73))); 1026 | idt_entries[74] = create_entry(@as(u32, @intFromPtr(&irq74))); 1027 | idt_entries[75] = create_entry(@as(u32, @intFromPtr(&irq75))); 1028 | idt_entries[76] = create_entry(@as(u32, @intFromPtr(&irq76))); 1029 | idt_entries[77] = create_entry(@as(u32, @intFromPtr(&irq77))); 1030 | idt_entries[78] = create_entry(@as(u32, @intFromPtr(&irq78))); 1031 | idt_entries[79] = create_entry(@as(u32, @intFromPtr(&irq79))); 1032 | idt_entries[80] = create_entry(@as(u32, @intFromPtr(&irq80))); 1033 | idt_entries[81] = create_entry(@as(u32, @intFromPtr(&irq81))); 1034 | idt_entries[82] = create_entry(@as(u32, @intFromPtr(&irq82))); 1035 | idt_entries[83] = create_entry(@as(u32, @intFromPtr(&irq83))); 1036 | idt_entries[84] = create_entry(@as(u32, @intFromPtr(&irq84))); 1037 | idt_entries[85] = create_entry(@as(u32, @intFromPtr(&irq85))); 1038 | idt_entries[86] = create_entry(@as(u32, @intFromPtr(&irq86))); 1039 | idt_entries[87] = create_entry(@as(u32, @intFromPtr(&irq87))); 1040 | idt_entries[88] = create_entry(@as(u32, @intFromPtr(&irq88))); 1041 | idt_entries[89] = create_entry(@as(u32, @intFromPtr(&irq89))); 1042 | idt_entries[90] = create_entry(@as(u32, @intFromPtr(&irq90))); 1043 | idt_entries[91] = create_entry(@as(u32, @intFromPtr(&irq91))); 1044 | idt_entries[92] = create_entry(@as(u32, @intFromPtr(&irq92))); 1045 | idt_entries[93] = create_entry(@as(u32, @intFromPtr(&irq93))); 1046 | idt_entries[94] = create_entry(@as(u32, @intFromPtr(&irq94))); 1047 | idt_entries[95] = create_entry(@as(u32, @intFromPtr(&irq95))); 1048 | idt_entries[96] = create_entry(@as(u32, @intFromPtr(&irq96))); 1049 | idt_entries[97] = create_entry(@as(u32, @intFromPtr(&irq97))); 1050 | idt_entries[98] = create_entry(@as(u32, @intFromPtr(&irq98))); 1051 | idt_entries[99] = create_entry(@as(u32, @intFromPtr(&irq99))); 1052 | idt_entries[100] = create_entry(@as(u32, @intFromPtr(&irq100))); 1053 | idt_entries[101] = create_entry(@as(u32, @intFromPtr(&irq101))); 1054 | idt_entries[102] = create_entry(@as(u32, @intFromPtr(&irq102))); 1055 | idt_entries[103] = create_entry(@as(u32, @intFromPtr(&irq103))); 1056 | idt_entries[104] = create_entry(@as(u32, @intFromPtr(&irq104))); 1057 | idt_entries[105] = create_entry(@as(u32, @intFromPtr(&irq105))); 1058 | idt_entries[106] = create_entry(@as(u32, @intFromPtr(&irq106))); 1059 | idt_entries[107] = create_entry(@as(u32, @intFromPtr(&irq107))); 1060 | idt_entries[108] = create_entry(@as(u32, @intFromPtr(&irq108))); 1061 | idt_entries[109] = create_entry(@as(u32, @intFromPtr(&irq109))); 1062 | idt_entries[110] = create_entry(@as(u32, @intFromPtr(&irq110))); 1063 | idt_entries[111] = create_entry(@as(u32, @intFromPtr(&irq111))); 1064 | idt_entries[112] = create_entry(@as(u32, @intFromPtr(&irq112))); 1065 | idt_entries[113] = create_entry(@as(u32, @intFromPtr(&irq113))); 1066 | idt_entries[114] = create_entry(@as(u32, @intFromPtr(&irq114))); 1067 | idt_entries[115] = create_entry(@as(u32, @intFromPtr(&irq115))); 1068 | idt_entries[116] = create_entry(@as(u32, @intFromPtr(&irq116))); 1069 | idt_entries[117] = create_entry(@as(u32, @intFromPtr(&irq117))); 1070 | idt_entries[118] = create_entry(@as(u32, @intFromPtr(&irq118))); 1071 | idt_entries[119] = create_entry(@as(u32, @intFromPtr(&irq119))); 1072 | idt_entries[120] = create_entry(@as(u32, @intFromPtr(&irq120))); 1073 | idt_entries[121] = create_entry(@as(u32, @intFromPtr(&irq121))); 1074 | idt_entries[122] = create_entry(@as(u32, @intFromPtr(&irq122))); 1075 | idt_entries[123] = create_entry(@as(u32, @intFromPtr(&irq123))); 1076 | idt_entries[124] = create_entry(@as(u32, @intFromPtr(&irq124))); 1077 | idt_entries[125] = create_entry(@as(u32, @intFromPtr(&irq125))); 1078 | idt_entries[126] = create_entry(@as(u32, @intFromPtr(&irq126))); 1079 | idt_entries[127] = create_entry(@as(u32, @intFromPtr(&irq127))); 1080 | idt_entries[128] = create_entry(@as(u32, @intFromPtr(&irq128))); 1081 | idt_entries[129] = create_entry(@as(u32, @intFromPtr(&irq129))); 1082 | idt_entries[130] = create_entry(@as(u32, @intFromPtr(&irq130))); 1083 | idt_entries[131] = create_entry(@as(u32, @intFromPtr(&irq131))); 1084 | idt_entries[132] = create_entry(@as(u32, @intFromPtr(&irq132))); 1085 | idt_entries[133] = create_entry(@as(u32, @intFromPtr(&irq133))); 1086 | idt_entries[134] = create_entry(@as(u32, @intFromPtr(&irq134))); 1087 | idt_entries[135] = create_entry(@as(u32, @intFromPtr(&irq135))); 1088 | idt_entries[136] = create_entry(@as(u32, @intFromPtr(&irq136))); 1089 | idt_entries[137] = create_entry(@as(u32, @intFromPtr(&irq137))); 1090 | idt_entries[138] = create_entry(@as(u32, @intFromPtr(&irq138))); 1091 | idt_entries[139] = create_entry(@as(u32, @intFromPtr(&irq139))); 1092 | idt_entries[140] = create_entry(@as(u32, @intFromPtr(&irq140))); 1093 | idt_entries[141] = create_entry(@as(u32, @intFromPtr(&irq141))); 1094 | idt_entries[142] = create_entry(@as(u32, @intFromPtr(&irq142))); 1095 | idt_entries[143] = create_entry(@as(u32, @intFromPtr(&irq143))); 1096 | idt_entries[144] = create_entry(@as(u32, @intFromPtr(&irq144))); 1097 | idt_entries[145] = create_entry(@as(u32, @intFromPtr(&irq145))); 1098 | idt_entries[146] = create_entry(@as(u32, @intFromPtr(&irq146))); 1099 | idt_entries[147] = create_entry(@as(u32, @intFromPtr(&irq147))); 1100 | idt_entries[148] = create_entry(@as(u32, @intFromPtr(&irq148))); 1101 | idt_entries[149] = create_entry(@as(u32, @intFromPtr(&irq149))); 1102 | idt_entries[150] = create_entry(@as(u32, @intFromPtr(&irq150))); 1103 | idt_entries[151] = create_entry(@as(u32, @intFromPtr(&irq151))); 1104 | idt_entries[152] = create_entry(@as(u32, @intFromPtr(&irq152))); 1105 | idt_entries[153] = create_entry(@as(u32, @intFromPtr(&irq153))); 1106 | idt_entries[154] = create_entry(@as(u32, @intFromPtr(&irq154))); 1107 | idt_entries[155] = create_entry(@as(u32, @intFromPtr(&irq155))); 1108 | idt_entries[156] = create_entry(@as(u32, @intFromPtr(&irq156))); 1109 | idt_entries[157] = create_entry(@as(u32, @intFromPtr(&irq157))); 1110 | idt_entries[158] = create_entry(@as(u32, @intFromPtr(&irq158))); 1111 | idt_entries[159] = create_entry(@as(u32, @intFromPtr(&irq159))); 1112 | idt_entries[160] = create_entry(@as(u32, @intFromPtr(&irq160))); 1113 | idt_entries[161] = create_entry(@as(u32, @intFromPtr(&irq161))); 1114 | idt_entries[162] = create_entry(@as(u32, @intFromPtr(&irq162))); 1115 | idt_entries[163] = create_entry(@as(u32, @intFromPtr(&irq163))); 1116 | idt_entries[164] = create_entry(@as(u32, @intFromPtr(&irq164))); 1117 | idt_entries[165] = create_entry(@as(u32, @intFromPtr(&irq165))); 1118 | idt_entries[166] = create_entry(@as(u32, @intFromPtr(&irq166))); 1119 | idt_entries[167] = create_entry(@as(u32, @intFromPtr(&irq167))); 1120 | idt_entries[168] = create_entry(@as(u32, @intFromPtr(&irq168))); 1121 | idt_entries[169] = create_entry(@as(u32, @intFromPtr(&irq169))); 1122 | idt_entries[170] = create_entry(@as(u32, @intFromPtr(&irq170))); 1123 | idt_entries[171] = create_entry(@as(u32, @intFromPtr(&irq171))); 1124 | idt_entries[172] = create_entry(@as(u32, @intFromPtr(&irq172))); 1125 | idt_entries[173] = create_entry(@as(u32, @intFromPtr(&irq173))); 1126 | idt_entries[174] = create_entry(@as(u32, @intFromPtr(&irq174))); 1127 | idt_entries[175] = create_entry(@as(u32, @intFromPtr(&irq175))); 1128 | idt_entries[176] = create_entry(@as(u32, @intFromPtr(&irq176))); 1129 | idt_entries[177] = create_entry(@as(u32, @intFromPtr(&irq177))); 1130 | idt_entries[178] = create_entry(@as(u32, @intFromPtr(&irq178))); 1131 | idt_entries[179] = create_entry(@as(u32, @intFromPtr(&irq179))); 1132 | idt_entries[180] = create_entry(@as(u32, @intFromPtr(&irq180))); 1133 | idt_entries[181] = create_entry(@as(u32, @intFromPtr(&irq181))); 1134 | idt_entries[182] = create_entry(@as(u32, @intFromPtr(&irq182))); 1135 | idt_entries[183] = create_entry(@as(u32, @intFromPtr(&irq183))); 1136 | idt_entries[184] = create_entry(@as(u32, @intFromPtr(&irq184))); 1137 | idt_entries[185] = create_entry(@as(u32, @intFromPtr(&irq185))); 1138 | idt_entries[186] = create_entry(@as(u32, @intFromPtr(&irq186))); 1139 | idt_entries[187] = create_entry(@as(u32, @intFromPtr(&irq187))); 1140 | idt_entries[188] = create_entry(@as(u32, @intFromPtr(&irq188))); 1141 | idt_entries[189] = create_entry(@as(u32, @intFromPtr(&irq189))); 1142 | idt_entries[190] = create_entry(@as(u32, @intFromPtr(&irq190))); 1143 | idt_entries[191] = create_entry(@as(u32, @intFromPtr(&irq191))); 1144 | idt_entries[192] = create_entry(@as(u32, @intFromPtr(&irq192))); 1145 | idt_entries[193] = create_entry(@as(u32, @intFromPtr(&irq193))); 1146 | idt_entries[194] = create_entry(@as(u32, @intFromPtr(&irq194))); 1147 | idt_entries[195] = create_entry(@as(u32, @intFromPtr(&irq195))); 1148 | idt_entries[196] = create_entry(@as(u32, @intFromPtr(&irq196))); 1149 | idt_entries[197] = create_entry(@as(u32, @intFromPtr(&irq197))); 1150 | idt_entries[198] = create_entry(@as(u32, @intFromPtr(&irq198))); 1151 | idt_entries[199] = create_entry(@as(u32, @intFromPtr(&irq199))); 1152 | idt_entries[200] = create_entry(@as(u32, @intFromPtr(&irq200))); 1153 | idt_entries[201] = create_entry(@as(u32, @intFromPtr(&irq201))); 1154 | idt_entries[202] = create_entry(@as(u32, @intFromPtr(&irq202))); 1155 | idt_entries[203] = create_entry(@as(u32, @intFromPtr(&irq203))); 1156 | idt_entries[204] = create_entry(@as(u32, @intFromPtr(&irq204))); 1157 | idt_entries[205] = create_entry(@as(u32, @intFromPtr(&irq205))); 1158 | idt_entries[206] = create_entry(@as(u32, @intFromPtr(&irq206))); 1159 | idt_entries[207] = create_entry(@as(u32, @intFromPtr(&irq207))); 1160 | idt_entries[208] = create_entry(@as(u32, @intFromPtr(&irq208))); 1161 | idt_entries[209] = create_entry(@as(u32, @intFromPtr(&irq209))); 1162 | idt_entries[210] = create_entry(@as(u32, @intFromPtr(&irq210))); 1163 | idt_entries[211] = create_entry(@as(u32, @intFromPtr(&irq211))); 1164 | idt_entries[212] = create_entry(@as(u32, @intFromPtr(&irq212))); 1165 | idt_entries[213] = create_entry(@as(u32, @intFromPtr(&irq213))); 1166 | idt_entries[214] = create_entry(@as(u32, @intFromPtr(&irq214))); 1167 | idt_entries[215] = create_entry(@as(u32, @intFromPtr(&irq215))); 1168 | idt_entries[216] = create_entry(@as(u32, @intFromPtr(&irq216))); 1169 | idt_entries[217] = create_entry(@as(u32, @intFromPtr(&irq217))); 1170 | idt_entries[218] = create_entry(@as(u32, @intFromPtr(&irq218))); 1171 | idt_entries[219] = create_entry(@as(u32, @intFromPtr(&irq219))); 1172 | idt_entries[220] = create_entry(@as(u32, @intFromPtr(&irq220))); 1173 | idt_entries[221] = create_entry(@as(u32, @intFromPtr(&irq221))); 1174 | idt_entries[222] = create_entry(@as(u32, @intFromPtr(&irq222))); 1175 | idt_entries[223] = create_entry(@as(u32, @intFromPtr(&irq223))); 1176 | idt_entries[224] = create_entry(@as(u32, @intFromPtr(&irq224))); 1177 | idt_entries[225] = create_entry(@as(u32, @intFromPtr(&irq225))); 1178 | idt_entries[226] = create_entry(@as(u32, @intFromPtr(&irq226))); 1179 | idt_entries[227] = create_entry(@as(u32, @intFromPtr(&irq227))); 1180 | idt_entries[228] = create_entry(@as(u32, @intFromPtr(&irq228))); 1181 | idt_entries[229] = create_entry(@as(u32, @intFromPtr(&irq229))); 1182 | idt_entries[230] = create_entry(@as(u32, @intFromPtr(&irq230))); 1183 | idt_entries[231] = create_entry(@as(u32, @intFromPtr(&irq231))); 1184 | idt_entries[232] = create_entry(@as(u32, @intFromPtr(&irq232))); 1185 | idt_entries[233] = create_entry(@as(u32, @intFromPtr(&irq233))); 1186 | idt_entries[234] = create_entry(@as(u32, @intFromPtr(&irq234))); 1187 | idt_entries[235] = create_entry(@as(u32, @intFromPtr(&irq235))); 1188 | idt_entries[236] = create_entry(@as(u32, @intFromPtr(&irq236))); 1189 | idt_entries[237] = create_entry(@as(u32, @intFromPtr(&irq237))); 1190 | idt_entries[238] = create_entry(@as(u32, @intFromPtr(&irq238))); 1191 | idt_entries[239] = create_entry(@as(u32, @intFromPtr(&irq239))); 1192 | idt_entries[240] = create_entry(@as(u32, @intFromPtr(&irq240))); 1193 | idt_entries[241] = create_entry(@as(u32, @intFromPtr(&irq241))); 1194 | idt_entries[242] = create_entry(@as(u32, @intFromPtr(&irq242))); 1195 | idt_entries[243] = create_entry(@as(u32, @intFromPtr(&irq243))); 1196 | idt_entries[244] = create_entry(@as(u32, @intFromPtr(&irq244))); 1197 | idt_entries[245] = create_entry(@as(u32, @intFromPtr(&irq245))); 1198 | idt_entries[246] = create_entry(@as(u32, @intFromPtr(&irq246))); 1199 | idt_entries[247] = create_entry(@as(u32, @intFromPtr(&irq247))); 1200 | idt_entries[248] = create_entry(@as(u32, @intFromPtr(&irq248))); 1201 | idt_entries[249] = create_entry(@as(u32, @intFromPtr(&irq249))); 1202 | idt_entries[250] = create_entry(@as(u32, @intFromPtr(&irq250))); 1203 | idt_entries[251] = create_entry(@as(u32, @intFromPtr(&irq251))); 1204 | idt_entries[252] = create_entry(@as(u32, @intFromPtr(&irq252))); 1205 | idt_entries[253] = create_entry(@as(u32, @intFromPtr(&irq253))); 1206 | idt_entries[254] = create_entry(@as(u32, @intFromPtr(&irq254))); 1207 | idt_entries[255] = create_entry(@as(u32, @intFromPtr(&irq255))); 1208 | 1209 | // Load IDT 1210 | const idt_address = pmm.allocate(@sizeOf(idtr)); 1211 | const idt = @as(*idtr, @ptrFromInt(idt_address)); 1212 | 1213 | idt.size = idt_entries_size - 1; 1214 | idt.offset = @as(u32, idt_entries_address); 1215 | 1216 | load_idt(@as(u32, idt_address)); 1217 | } 1218 | -------------------------------------------------------------------------------- /src/kernel.zig: -------------------------------------------------------------------------------- 1 | // idk about this file, I just needed somewhere to put 'sleep' lol 2 | const std = @import("std"); 3 | const pit = @import("pit.zig"); 4 | 5 | pub fn sleep(ms: u32) void { 6 | for (0..ms) |value| { 7 | _ = value; 8 | pit.set_count(1193182 / 1000); 9 | const start = pit.read_count(); 10 | 11 | while ((start - pit.read_count()) < 1000) {} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/keycodes.zig: -------------------------------------------------------------------------------- 1 | // const InputKey = @import("scanmap.zig").InputKey; 2 | // const ft = @import("../../ft/ft.zig"); 3 | // const keymaps = @import("keymap_index.zig"); 4 | // const keyboard = @import("../keyboard.zig"); 5 | 6 | // var current_map: *const [232][6]u16 = &keymaps.@"us-std"; 7 | 8 | pub const MAP_COLS: u8 = 6; 9 | // pub const NB_SCANCODES: u8 = @typeInfo(InputKey).Enum.fields.len; 10 | 11 | pub const EXT: u16 = 0x0100; 12 | pub const CTRLKEY: u16 = 0x0200; 13 | pub const SHIFT: u16 = 0x0400; 14 | pub const ALT: u16 = 0x0800; 15 | pub const HASNUM: u16 = 0x4000; 16 | pub const HASCAPS: u16 = 0x8000; 17 | 18 | pub const escape_map: [12][]const u8 = [_][]const u8{ 19 | "\x1b[H", 20 | "\x1b[Y", 21 | "\x1b[A", 22 | "\x1b[B", 23 | "\x1b[D", 24 | "\x1b[C", 25 | "\x1bD", 26 | "\x1bM", 27 | "\x1b[G", 28 | "\x1b[S", 29 | "\x1b[T", 30 | "\x1b[@", 31 | }; 32 | 33 | /// Map to control code 34 | pub inline fn C(comptime scancode: u16) u16 { 35 | return scancode & 0x1F; 36 | } 37 | 38 | /// Set eight bit (ALT) 39 | pub inline fn A(comptime scancode: u16) u16 { 40 | return scancode | 0x80; 41 | } 42 | 43 | /// Control + Alt 44 | pub inline fn CA(comptime scancode: u16) u16 { 45 | return A(C(scancode)); 46 | } 47 | 48 | /// Add "Num lock has effect" attribute 49 | pub inline fn N(comptime scancode: u16) u16 { 50 | return scancode | HASNUM; 51 | } 52 | 53 | /// Add "Caps lock has effect" attribute 54 | pub inline fn L(comptime scancode: u16) u16 { 55 | return scancode | HASCAPS; 56 | } 57 | 58 | /// set the keymap to use 59 | // pub fn set_keymap(name: []const u8) error{KeymapNotFound}!void { 60 | // inline for (@typeInfo(keymaps).Struct.decls) |decl| { 61 | // if (ft.mem.eql(u8, decl.name, name)) { 62 | // current_map = &@field(keymaps, decl.name); 63 | // return; 64 | // } 65 | // } 66 | // return error.KeymapNotFound; 67 | // } 68 | 69 | // fn get_keymap_list() [@typeInfo(keymaps).Struct.decls.len][]const u8 { 70 | // comptime { 71 | // var ret: [@typeInfo(keymaps).Struct.decls.len][]const u8 = undefined; 72 | // for (@typeInfo(keymaps).Struct.decls, 0..) |decl, i| { 73 | // ret[i] = decl.name; 74 | // } 75 | // return ret; 76 | // } 77 | // } 78 | 79 | /// list of all the existing keymaps 80 | // pub const keymap_list = get_keymap_list(); 81 | 82 | // pub fn map_key(index: u16) u16 { 83 | // var caps: bool = false; 84 | // var col: u8 = 0; 85 | // const row: [6]u16 = current_map[index]; 86 | // 87 | // if (row[0] & HASNUM != 0) { 88 | // if (keyboard.locks.num_lock) caps = true; 89 | // } else { 90 | // caps = keyboard.keyState.shift; 91 | // if ((keyboard.locks.caps_lock) and (row[0] & HASCAPS) != 0) 92 | // caps = !caps; 93 | // } 94 | // 95 | // if (keyboard.keyState.alt) { 96 | // col = 2; 97 | // if (keyboard.keyState.ctrl or keyboard.keyState.alt_right) col = 3; 98 | // if (caps) col = 4; 99 | // } else { 100 | // col = 0; 101 | // if (caps) col = 1; 102 | // if (keyboard.keyState.ctrl) col = 5; 103 | // } 104 | // 105 | // return row[col] & ~(HASCAPS | HASNUM); 106 | // } 107 | 108 | // Lock Keys 109 | pub const CALOCK = 0x0D + EXT; 110 | pub const NLOCK = 0x0E + EXT; 111 | pub const SLOCK = 0x0F + EXT; 112 | 113 | // Function Keys 114 | pub const F1 = 0x10 + EXT; 115 | pub const F2 = 0x11 + EXT; 116 | pub const F3 = 0x12 + EXT; 117 | pub const F4 = 0x13 + EXT; 118 | pub const F5 = 0x14 + EXT; 119 | pub const F6 = 0x15 + EXT; 120 | pub const F7 = 0x16 + EXT; 121 | pub const F8 = 0x17 + EXT; 122 | pub const F9 = 0x18 + EXT; 123 | pub const F10 = 0x19 + EXT; 124 | pub const F11 = 0x1A + EXT; 125 | pub const F12 = 0x1B + EXT; 126 | 127 | pub const DEL = 0x7f; 128 | 129 | // Alt + Numeric keypad 130 | pub const AHOME = 0x01 + ALT; 131 | pub const AEND = 0x02 + ALT; 132 | pub const AUP = 0x03 + ALT; 133 | pub const ADOWN = 0x04 + ALT; 134 | pub const ALEFT = 0x05 + ALT; 135 | pub const ARIGHT = 0x06 + ALT; 136 | pub const APGUP = 0x07 + ALT; 137 | pub const APGDN = 0x08 + ALT; 138 | pub const AMID = 0x09 + ALT; 139 | pub const AMIN = 0x0A + ALT; 140 | pub const APLUS = 0x0B + ALT; 141 | pub const AINSRT = 0x0C + ALT; 142 | 143 | // Shift+Fn 144 | pub const SF1 = 0x10 + SHIFT; 145 | pub const SF2 = 0x11 + SHIFT; 146 | pub const SF3 = 0x12 + SHIFT; 147 | pub const SF4 = 0x13 + SHIFT; 148 | pub const SF5 = 0x14 + SHIFT; 149 | pub const SF6 = 0x15 + SHIFT; 150 | pub const SF7 = 0x16 + SHIFT; 151 | pub const SF8 = 0x17 + SHIFT; 152 | pub const SF9 = 0x18 + SHIFT; 153 | pub const SF10 = 0x19 + SHIFT; 154 | pub const SF11 = 0x1A + SHIFT; 155 | pub const SF12 = 0x1B + SHIFT; 156 | 157 | // Alt + Fn 158 | pub const AF1 = 0x10 + ALT; 159 | pub const AF2 = 0x11 + ALT; 160 | pub const AF3 = 0x12 + ALT; 161 | pub const AF4 = 0x13 + ALT; 162 | pub const AF5 = 0x14 + ALT; 163 | pub const AF6 = 0x15 + ALT; 164 | pub const AF7 = 0x16 + ALT; 165 | pub const AF8 = 0x17 + ALT; 166 | pub const AF9 = 0x18 + ALT; 167 | pub const AF10 = 0x19 + ALT; 168 | pub const AF11 = 0x1A + ALT; 169 | pub const AF12 = 0x1B + ALT; 170 | 171 | // Alt + Shift + Fn 172 | pub const ASF1 = 0x10 + ALT + SHIFT; 173 | pub const ASF2 = 0x11 + ALT + SHIFT; 174 | pub const ASF3 = 0x12 + ALT + SHIFT; 175 | pub const ASF4 = 0x13 + ALT + SHIFT; 176 | pub const ASF5 = 0x14 + ALT + SHIFT; 177 | pub const ASF6 = 0x15 + ALT + SHIFT; 178 | pub const ASF7 = 0x16 + ALT + SHIFT; 179 | pub const ASF8 = 0x17 + ALT + SHIFT; 180 | pub const ASF9 = 0x18 + ALT + SHIFT; 181 | pub const ASF10 = 0x19 + ALT + SHIFT; 182 | pub const ASF11 = 0x1A + ALT + SHIFT; 183 | pub const ASF12 = 0x1B + ALT + SHIFT; 184 | 185 | // Ctrl + Fn 186 | pub const CF1 = 0x10 + CTRLKEY; 187 | pub const CF2 = 0x11 + CTRLKEY; 188 | pub const CF3 = 0x12 + CTRLKEY; 189 | pub const CF4 = 0x13 + CTRLKEY; 190 | pub const CF5 = 0x14 + CTRLKEY; 191 | pub const CF6 = 0x15 + CTRLKEY; 192 | pub const CF7 = 0x16 + CTRLKEY; 193 | pub const CF8 = 0x17 + CTRLKEY; 194 | pub const CF9 = 0x18 + CTRLKEY; 195 | pub const CF10 = 0x19 + CTRLKEY; 196 | pub const CF11 = 0x1A + CTRLKEY; 197 | pub const CF12 = 0x1B + CTRLKEY; 198 | 199 | // Numeric keypad 200 | pub const HOME = 0x01 + EXT; 201 | pub const END = 0x02 + EXT; 202 | pub const UP = 0x03 + EXT; 203 | pub const DOWN = 0x04 + EXT; 204 | pub const LEFT = 0x05 + EXT; 205 | pub const RIGHT = 0x06 + EXT; 206 | pub const PGUP = 0x07 + EXT; 207 | pub const PGDN = 0x08 + EXT; 208 | pub const MID = 0x09 + EXT; 209 | pub const INSRT = 0x0C + EXT; 210 | 211 | // Ctrl + Numeric keypad 212 | pub const CHOME = 0x01 + CTRLKEY; 213 | pub const CEND = 0x02 + CTRLKEY; 214 | pub const CUP = 0x03 + CTRLKEY; 215 | pub const CDOWN = 0x04 + CTRLKEY; 216 | pub const CLEFT = 0x05 + CTRLKEY; 217 | pub const CRIGHT = 0x06 + CTRLKEY; 218 | pub const CPGUP = 0x07 + CTRLKEY; 219 | pub const CPGDN = 0x08 + CTRLKEY; 220 | pub const CMID = 0x09 + CTRLKEY; 221 | pub const CNMIN = 0x0A + CTRLKEY; 222 | pub const CPLUS = 0x0B + CTRLKEY; 223 | pub const CINSRT = 0x0C + CTRLKEY; 224 | 225 | // Keys affected by Num Lock 226 | pub const NHOME = N(HOME); 227 | pub const NEND = N(END); 228 | pub const NUP = N(UP); 229 | pub const NDOWN = N(DOWN); 230 | pub const NLEFT = N(LEFT); 231 | pub const NRIGHT = N(RIGHT); 232 | pub const NPGUP = N(PGUP); 233 | pub const NPGDN = N(PGDN); 234 | pub const NMID = N(MID); 235 | pub const NINSRT = N(INSRT); 236 | pub const NDEL = N(DEL); 237 | 238 | // The left and right versions for the actual keys in the keymap. 239 | pub const LCTRL = CTRLKEY; 240 | pub const RCTRL = (CTRLKEY | EXT); 241 | pub const LSHIFT = SHIFT; 242 | pub const RSHIFT = (SHIFT | EXT); 243 | pub const LALT = ALT; 244 | pub const RALT = (ALT | EXT); 245 | -------------------------------------------------------------------------------- /src/keys.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const console = @import("./console.zig"); 3 | const ps2 = @import("./ps2.zig"); 4 | const scanmap = @import("./keys.zig"); 5 | const key = @import("keycodes.zig"); 6 | 7 | pub const unshiftedMap = [128]u8{ 8 | 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, '\t', 9 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 10 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 11 | 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 | '\\', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 | }; 17 | 18 | pub const shiftedMap = [128]u8{ 19 | 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 8, '\t', 20 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 0, 'A', 'S', 21 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0, '|', 'Z', 'X', 'C', 'V', 22 | 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 23 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24 | '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27 | }; 28 | 29 | pub const KeyType = enum { unknown, normal, enter, backspace, shift, arrow_up, ctrl }; 30 | pub const Key = struct { type: KeyType, value: u8 }; 31 | 32 | // const BUFFER_SIZE = 4096; 33 | // var buffer: [BUFFER_SIZE]u8 = undefined; 34 | 35 | pub fn key_isrelease(scancode: u8) bool { 36 | return scancode & (1 << 7) != 0; 37 | } 38 | 39 | pub var isLeftShift: bool = false; 40 | pub var isRightShift: bool = false; 41 | pub var isCtrl: bool = false; 42 | 43 | const LEFT_SHIFT = 0x2A; 44 | const RIGHT_SHIFT = 0x36; 45 | const ENTER = 0x1C; 46 | const BACKSPACE = 0x0E; 47 | // prefix 0xE0 - 0x48 UP ? 48 | 49 | pub fn HandleKeyboard(scancode: u8) Key { 50 | switch (scancode) { 51 | LEFT_SHIFT => { 52 | isLeftShift = true; 53 | return .{ .type = .shift, .value = 0 }; 54 | }, 55 | LEFT_SHIFT + 0x80 => { 56 | isLeftShift = false; 57 | return .{ .type = .shift, .value = 0 }; 58 | }, 59 | RIGHT_SHIFT => { 60 | isRightShift = true; 61 | return .{ .type = .shift, .value = 0 }; 62 | }, 63 | RIGHT_SHIFT + 0x80 => { 64 | isRightShift = false; 65 | return .{ .type = .shift, .value = 0 }; 66 | }, 67 | ENTER => return .{ .type = .enter, .value = 0 }, 68 | BACKSPACE => return .{ .type = .backspace, .value = 0 }, 69 | 0x48 => return .{ .type = .arrow_up, .value = 0 }, 70 | 0x1D => { 71 | isCtrl = true; 72 | return .{ .type = .ctrl, .value = 0 }; 73 | }, 74 | else => { 75 | const value = translate(scancode, isLeftShift or isRightShift); 76 | if (value == 0) { 77 | return .{ .type = .unknown, .value = value }; 78 | } 79 | return .{ .type = .normal, .value = value }; 80 | }, 81 | } 82 | } 83 | 84 | // this function isn't needed outside of this file but may be useful for debugging idk 85 | pub inline fn translate(scancode: u8, uppercase: bool) u8 { 86 | if (scancode > 58) return 0; 87 | 88 | if (uppercase) { 89 | return shiftedMap[scancode]; 90 | } 91 | return unshiftedMap[scancode]; 92 | } 93 | 94 | // maybe use an atomic bool? 95 | // var xxx = std.atomic.Value(bool); 96 | 97 | pub fn readkey() Key { 98 | const scan_code = ps2.getScanCode(); 99 | if (scan_code == 0) { 100 | return .{ .type = .unknown, .value = 0 }; 101 | } 102 | 103 | return HandleKeyboard(scan_code); 104 | } 105 | 106 | // no longer in use 107 | pub fn getKey(scan_code: u8) Key { 108 | return switch (scan_code) { 109 | 2 => .{ .type = .normal, .value = '1' }, 110 | 3 => .{ .type = .normal, .value = '2' }, 111 | 4 => .{ .type = .normal, .value = '3' }, 112 | 5 => .{ .type = .normal, .value = '4' }, 113 | 6 => .{ .type = .normal, .value = '5' }, 114 | 7 => .{ .type = .normal, .value = '6' }, 115 | 8 => .{ .type = .normal, .value = '7' }, 116 | 9 => .{ .type = .normal, .value = '8' }, 117 | 10 => .{ .type = .normal, .value = '9' }, 118 | 11 => .{ .type = .normal, .value = '0' }, 119 | 12 => .{ .type = .normal, .value = '-' }, 120 | 13 => .{ .type = .normal, .value = '=' }, 121 | 14 => .{ .type = .backspace, .value = 0 }, 122 | 16 => .{ .type = .normal, .value = 'q' }, 123 | 17 => .{ .type = .normal, .value = 'w' }, 124 | 18 => .{ .type = .normal, .value = 'e' }, 125 | 19 => .{ .type = .normal, .value = 'r' }, 126 | 20 => .{ .type = .normal, .value = 't' }, 127 | 21 => .{ .type = .normal, .value = 'y' }, 128 | 22 => .{ .type = .normal, .value = 'u' }, 129 | 23 => .{ .type = .normal, .value = 'i' }, 130 | 24 => .{ .type = .normal, .value = 'o' }, 131 | 25 => .{ .type = .normal, .value = 'p' }, 132 | 28 => .{ .type = .enter, .value = 0 }, 133 | 30 => .{ .type = .normal, .value = 'a' }, 134 | 31 => .{ .type = .normal, .value = 's' }, 135 | 32 => .{ .type = .normal, .value = 'd' }, 136 | 33 => .{ .type = .normal, .value = 'f' }, 137 | 34 => .{ .type = .normal, .value = 'g' }, 138 | 35 => .{ .type = .normal, .value = 'h' }, 139 | 36 => .{ .type = .normal, .value = 'j' }, 140 | 37 => .{ .type = .normal, .value = 'k' }, 141 | 38 => .{ .type = .normal, .value = 'l' }, 142 | 44 => .{ .type = .normal, .value = 'z' }, 143 | 45 => .{ .type = .normal, .value = 'x' }, 144 | 46 => .{ .type = .normal, .value = 'c' }, 145 | 47 => .{ .type = .normal, .value = 'v' }, 146 | 48 => .{ .type = .normal, .value = 'b' }, 147 | 49 => .{ .type = .normal, .value = 'n' }, 148 | 50 => .{ .type = .normal, .value = 'm' }, 149 | 57 => .{ .type = .normal, .value = ' ' }, 150 | 58 => .{ .type = .normal, .value = ' ' }, 151 | else => .{ .type = .unknown, .value = 0 }, 152 | }; 153 | } 154 | -------------------------------------------------------------------------------- /src/linker.ld: -------------------------------------------------------------------------------- 1 | /* ENTRY(_start) */ 2 | /* */ 3 | /* SECTIONS { */ 4 | /* . = 2M; */ 5 | /**/ 6 | /* .text : ALIGN(4K) { */ 7 | /* *(.multiboot) */ 8 | /* *(.text) */ 9 | /* } */ 10 | /* */ 11 | /* .rodata : ALIGN(4K) { */ 12 | /* *(.rodata) */ 13 | /* } */ 14 | /* */ 15 | /* .data : ALIGN(4K) { */ 16 | /* *(.data) */ 17 | /* } */ 18 | /* */ 19 | /* .bss : ALIGN(4K) { */ 20 | /* *(COMMON) */ 21 | /* *(.bss) */ 22 | /* } */ 23 | /* } */ 24 | 25 | /* the name of the entry label */ 26 | ENTRY(_start) 27 | 28 | SECTIONS { 29 | . = 1M; /* the code should be loaded at 1MB (bios, bootloader, mmap IO lives in the first 1MB) */ 30 | 31 | .text : ALIGN(8K) { /* align at 8KB */ 32 | *(.multiboot) 33 | *(.text) /* all text sections from all files */ 34 | } 35 | 36 | .rodata : ALIGN(8K) { 37 | *(.rodata) /* all read-only data sections */ 38 | } 39 | 40 | .data : ALIGN(8K) { 41 | *(.data) /* all data sections */ 42 | } 43 | 44 | .bss : ALIGN(8K) { 45 | *(COMMON) /* all COMMON sections */ 46 | *(.bss) /* all bss sections */ 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const console = @import("console.zig"); 3 | const multiboot = @import("multiboot.zig"); 4 | const pmm = @import("mem.zig"); 5 | const mmu = @import("malloc.zig"); 6 | const gdt = @import("gdt.zig"); 7 | const idt = @import("idt.zig"); 8 | const pic = @import("pic.zig"); 9 | const ps2 = @import("ps2.zig"); 10 | const acpi = @import("acpi.zig"); 11 | const shell = @import("shell.zig"); 12 | const pit = @import("pit.zig"); 13 | const art = @import("art.zig"); 14 | 15 | const ALIGN = 1 << 0; 16 | const MEMINFO = 1 << 1; 17 | const MAGIC = 0x1BADB002; 18 | const FLAGS = ALIGN | MEMINFO; 19 | 20 | pub fn panic(msg: []const u8, trace: ?*std.builtin.StackTrace, siz: ?usize) noreturn { 21 | @branchHint(.cold); 22 | _ = trace; 23 | _ = siz; 24 | 25 | console.write("PANIC: "); 26 | console.write(msg); 27 | while (true) {} 28 | } 29 | 30 | export fn kmain(multiboot_info_address: usize) noreturn { 31 | asm volatile ("cli"); 32 | console.initialize(); 33 | 34 | console.setColor(1); 35 | console.writeln("Welcome!"); 36 | 37 | console.setColor(12); 38 | 39 | for (art.ASUKA_LOGO) |line| { 40 | console.writeln(line); 41 | } 42 | 43 | console.setColor2(console.Colors.Green); 44 | 45 | console.writeln("[multiboot] init"); 46 | multiboot.init(multiboot_info_address); 47 | 48 | console.writeln("[memory] init"); 49 | pmm.init(multiboot.memoryUpper * 1024, multiboot.entries, multiboot.entryCount); 50 | 51 | console.writeln("[malloc] init"); 52 | mmu.init(); 53 | 54 | console.writeln("[gdt] init"); 55 | gdt.init(); 56 | 57 | console.writeln("[idt] init"); 58 | idt.init(); 59 | 60 | console.writeln("[pic] init"); 61 | pic.init(); 62 | 63 | console.writeln("[ps2] init"); 64 | ps2.init(); 65 | 66 | console.writeln("[acpi] init"); 67 | acpi.init(); 68 | 69 | console.writeln("[acpi] enable"); 70 | acpi.enable(); 71 | 72 | // set interrupt (hlt = halt interrupt | cli = clear interrupt) 73 | asm volatile ("sti"); 74 | 75 | console.clear(); 76 | console.writeln(art.KA); 77 | console.printf("{s}\n", .{art.ASUKA_LOGO2}); 78 | 79 | console.writeln("[pit] init"); 80 | // pit.init_pit(); 81 | // pit.init((1 << 16) - 1); 82 | // pit.init(((1 << 16) - 1) / 2); 83 | pit.init(100); 84 | 85 | var i: u8 = 1; 86 | while (ps2.getScanCode() == 0) : (i += 1) { 87 | console.clear(); 88 | console.printf("{s}\n", .{art.ASUKA_LOGO2}); 89 | console.writeln("press any key to continue..."); 90 | // console.printf("color: {X}\n", .{console.get_colors()}); 91 | console.setColor(@intCast(i)); 92 | if (i > 14) i = 0; 93 | pit.sleep_ns(1000); 94 | } 95 | 96 | console.setColor(10); 97 | console.clear(); 98 | 99 | console.printf("pit freq: {d}\n", .{pit.get_frequency()}); 100 | console.writeln("[shell] exec"); 101 | shell.exec(); 102 | 103 | while (true) {} 104 | } 105 | -------------------------------------------------------------------------------- /src/malloc.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const pmm = @import("./mem.zig"); 3 | // mmu 4 | 5 | const PAGE_DIRECTORY_SIZE = 1024; 6 | const PAGE_TABLE_SIZE = 1024; 7 | 8 | extern fn load_page_directory(address: usize) void; 9 | extern fn enable_paging() void; 10 | 11 | pub fn init() void { 12 | const page_directory_address = pmm.allocate(PAGE_DIRECTORY_SIZE * @sizeOf(u32)); 13 | const page_directory_pointer = @as([*]u32, @ptrFromInt(page_directory_address)); 14 | 15 | // Start address, here it's 0 16 | var address: usize = 0; 17 | 18 | // Align the number of total pages to a 4096-byte boundary 19 | var total_pages = pmm.total_pages; 20 | while (total_pages % 4096 != 0) total_pages += 1; 21 | 22 | // The page directory has 1024 possible entries 23 | const page_directory_pages = total_pages / PAGE_DIRECTORY_SIZE; 24 | 25 | // Map each available page table entry 26 | for (0..page_directory_pages) |i| { 27 | // One page table maps 4 MiB of RAM 28 | const page_table_address = pmm.allocate(PAGE_TABLE_SIZE * @sizeOf(u32)); 29 | const page_table_pointer = @as([*]u32, @ptrFromInt(page_table_address)); 30 | 31 | for (0..PAGE_TABLE_SIZE) |j| { 32 | // The "3" here means "Supervisor level, Read/Write and Present" 33 | page_table_pointer[j] = (@as(u32, address) * 0x1000) | 3; 34 | address += 1; 35 | } 36 | 37 | // Set the first page table entry in the page directory 38 | page_directory_pointer[i] = @as(u32, page_table_address) | 3; 39 | } 40 | 41 | // Mark every other entry as "not present" 42 | for (page_directory_pages..PAGE_DIRECTORY_SIZE) |i| page_directory_pointer[i] = 2; 43 | 44 | // Load the page directory address and enable paging 45 | load_page_directory(page_directory_address); 46 | enable_paging(); 47 | } 48 | -------------------------------------------------------------------------------- /src/mem.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const multiboot = @import("./multiboot.zig"); 3 | const console = @import("./console.zig"); 4 | // pmm 5 | 6 | // Currently, we take 4 KiB from the stack (our program's stack space when it's loaded into memory) 7 | // This is to ensure we have plenty of space for what we want to do 8 | // linksection adds this variable to the '.bss' section of the executable which is where uninitialized 9 | // variables live 10 | export var buffer: [4 * 1024]u8 align(16) linksection(".bss") = undefined; 11 | 12 | pub const PAGE_SIZE = 4096; 13 | const BITMAP_UNIT_SIZE = 8; 14 | const BitmapUnit = u8; 15 | 16 | const Map = struct { address: usize, size: usize }; 17 | const AddressRange = struct { from: usize, to: usize }; 18 | 19 | // allow zero addressed pointers 20 | var bitmap: [*]allowzero volatile BitmapUnit = undefined; 21 | 22 | pub var total_pages: usize = 0; 23 | var bitmap_size: usize = 0; 24 | var number_of_pages: usize = 0; 25 | pub var pages_in_use: usize = 0; 26 | pub var total_size: usize = 0; 27 | 28 | fn initialize_bitmap(best_map_address: usize, memory_maps: []Map, number_of_maps: usize) void { 29 | bitmap = @ptrFromInt(best_map_address); 30 | 31 | // Initialize bitmap by marking unavailable pages as "allocated", else setting them free 32 | var address: usize = 0; 33 | 34 | for (0..bitmap_size) |i| { 35 | var unit: BitmapUnit = 0; 36 | 37 | for (0..BITMAP_UNIT_SIZE) |j| { 38 | const mask: u8 = @intCast(@as(u16, 1) << @as(u4, @intCast(j))); 39 | var address_free = false; 40 | 41 | for (0..number_of_maps) |k| { 42 | if (address_free) break; 43 | 44 | const range = memory_maps[k]; 45 | if (address >= range.address and address <= range.address + range.size) address_free = true; 46 | } 47 | 48 | // The address is in an unavailable range, mark it as "allocated" 49 | if (!address_free) unit |= mask; 50 | 51 | address += PAGE_SIZE; 52 | } 53 | 54 | bitmap[i] = unit; 55 | } 56 | 57 | // Reserve number_of_pages pages for bitmap, in the bitmap itself 58 | var satisfied_pages: usize = 0; 59 | var index: usize = 0; 60 | 61 | while (true) : (index += 1) { 62 | var unit = bitmap[index]; 63 | 64 | for (0..BITMAP_UNIT_SIZE) |j| { 65 | // We have allocated the required number of pages, we can safely return the buffer now. 66 | if (satisfied_pages == number_of_pages) return; 67 | 68 | const mask: u8 = @intCast(@as(u16, 1) << @as(u4, @intCast(j))); 69 | 70 | if ((unit & mask) == 0) { 71 | // We found a free page! 72 | satisfied_pages += 1; 73 | unit |= mask; 74 | bitmap[index] = unit; 75 | } else { 76 | // This should never happen 77 | std.debug.panic("[pmm] found allocated page while trying to allocate bitmap", .{}); 78 | return; 79 | } 80 | } 81 | } 82 | } 83 | 84 | //https://github.com/limine-bootloader/limine/blob/886523359c85aa10691e6b82229c91f31f21a04f/common/lib/misc.h#L66 85 | fn div_round_up(a: usize, b: usize) usize { 86 | return (a + (b - 1)) / b; 87 | } 88 | 89 | pub fn init(max_memory_address: usize, entries: [*]multiboot.MultibootMemoryMapEntry, entry_count: usize) void { 90 | // Get a temporary fixed buffer allocator for our stack space 91 | var fba = std.heap.FixedBufferAllocator.init(&buffer); 92 | 93 | const allocator = fba.allocator(); 94 | 95 | const memory_maps = allocator.alloc(Map, entry_count) catch unreachable; 96 | defer allocator.free(memory_maps); 97 | 98 | var number_of_maps: usize = 0; 99 | var best_map: Map = undefined; 100 | var found_map = false; 101 | 102 | // Find all available memory map entries 103 | for (0..entry_count) |i| { 104 | const entry = entries[i]; 105 | 106 | // See https://en.wikipedia.org/wiki/PCI_hole 107 | if (entry.type == 1 and entry.address <= max_memory_address) { // Available && writable 108 | const size: usize = @intCast(entry.length); 109 | const map = Map{ .address = @intCast(entry.address), .size = size }; 110 | 111 | memory_maps[number_of_maps] = map; 112 | number_of_maps += 1; 113 | total_size += size; 114 | 115 | // Calculate the required values 116 | total_pages = total_size / PAGE_SIZE; 117 | bitmap_size = div_round_up(total_pages, BITMAP_UNIT_SIZE); 118 | 119 | // Check if the current memory map is the best suited for the bitmap 120 | if (!found_map and bitmap_size <= size) { 121 | best_map = map; 122 | found_map = true; 123 | } 124 | } 125 | } 126 | 127 | // Calculate the rest of the values 128 | number_of_pages = div_round_up(bitmap_size, PAGE_SIZE); 129 | 130 | if (!found_map) { 131 | std.debug.panic("[pmm] not enough memory to initialize", .{}); 132 | return; 133 | } 134 | 135 | // Initialize the bitmap with the memory map we found 136 | initialize_bitmap(best_map.address, memory_maps, number_of_maps); 137 | 138 | // At this point, we are using number_of_pages pages 139 | pages_in_use = number_of_pages; 140 | } 141 | 142 | pub fn allocate(size: usize) usize { 143 | // Calculate the required values 144 | var sz = size; 145 | while (sz % PAGE_SIZE != 0) sz += 1; 146 | 147 | const required_pages = sz / PAGE_SIZE; 148 | var satisfied_pages: usize = 0; 149 | var index: usize = 0; 150 | var address: usize = 0; 151 | 152 | while (true) : (index += 1) { 153 | var unit = bitmap[index]; 154 | 155 | for (0..BITMAP_UNIT_SIZE) |j| { 156 | // We have allocated the required number of pages, we can safely return the buffer now. 157 | if (satisfied_pages == required_pages) { 158 | pages_in_use += satisfied_pages; 159 | return address; 160 | } 161 | 162 | const mask = @as(u8, @intCast(@as(u16, 1) << @as(u4, @intCast(j)))); 163 | 164 | if ((unit & mask) == 0) { 165 | // We found a free page! 166 | satisfied_pages += 1; 167 | unit |= mask; 168 | bitmap[index] = unit; 169 | } else { 170 | // Either we still didn't find a free page, or the next page is allocated. 171 | address += PAGE_SIZE; 172 | satisfied_pages = 0; 173 | } 174 | } 175 | } 176 | } 177 | 178 | pub fn free(buffer_address: usize, size: usize) void { 179 | // Calculate the required values 180 | var sz = size; 181 | while (sz % PAGE_SIZE != 0) sz += 1; 182 | 183 | const required_pages = sz / PAGE_SIZE; 184 | var satisfied_pages: usize = 0; 185 | var index: usize = 0; 186 | var address: usize = 0; 187 | 188 | while (true) : (index += 1) { 189 | var unit = bitmap[index]; 190 | 191 | for (0..BITMAP_UNIT_SIZE) |j| { 192 | // We have freed the required number of pages, we can safely return now. 193 | if (satisfied_pages == required_pages) { 194 | pages_in_use -= satisfied_pages; 195 | return; 196 | } 197 | 198 | if (address == buffer_address) { 199 | satisfied_pages += 1; 200 | unit &= ~(@as(u8, @intCast(@as(u16, 1) << @as(u4, @intCast(j))))); 201 | bitmap[index] = unit; 202 | } else address += PAGE_SIZE; 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/multiboot.zig: -------------------------------------------------------------------------------- 1 | const acpi = @import("./acpi.zig"); 2 | const vga = @import("./console.zig"); 3 | 4 | const MultibootHeaderTag = extern struct { 5 | type: u16 align(1), 6 | flags: u16 align(1), 7 | size: u32 align(1), 8 | }; 9 | 10 | const Multiboot = extern struct { 11 | magic: u32 align(8), 12 | architecture: u32 align(1), 13 | header_length: u32 align(1), 14 | checksum: u32 align(1), 15 | end_tag: MultibootHeaderTag align(8), 16 | }; 17 | 18 | const MAGIC = 0xE85250D6; 19 | const ARCHITECTURE = 0; // i386 (protected mode) 20 | const HEADER_LENGTH = @sizeOf(Multiboot); 21 | 22 | export const multiboot align(8) linksection(".multiboot") = Multiboot{ 23 | .magic = MAGIC, 24 | .architecture = ARCHITECTURE, 25 | .header_length = HEADER_LENGTH, 26 | .checksum = 0x100000000 - (MAGIC + ARCHITECTURE + HEADER_LENGTH), 27 | .end_tag = .{ .type = 0, .flags = 0, .size = @sizeOf(MultibootHeaderTag) }, 28 | }; 29 | 30 | pub const MultibootTag = extern struct { 31 | type: u32 align(8), 32 | size: u32 align(1), 33 | }; 34 | 35 | const TAG_SIZE = @sizeOf(MultibootTag); 36 | 37 | pub const MultibootMemoryMapEntry = extern struct { 38 | address: u64 align(1), 39 | length: u64 align(1), 40 | type: u32 align(1), 41 | reserved: u32 align(1), 42 | }; 43 | 44 | pub var commandLine: [*]u8 = undefined; 45 | pub var bootloaderName: [*]u8 = undefined; 46 | pub var memoryLower: u32 = undefined; 47 | pub var memoryUpper: u32 = undefined; 48 | pub var entrySize: u32 = undefined; 49 | pub var entryVersion: u32 = undefined; 50 | pub var entries: [*]MultibootMemoryMapEntry = undefined; 51 | pub var entryCount: u32 = undefined; 52 | pub var acpiVersion2: bool = undefined; 53 | pub var acpiOldRsdp: acpi.rsdp = undefined; 54 | pub var acpiNewRsdp: acpi.rsdp_20 = undefined; 55 | 56 | pub fn init(multiboot_info_address: usize) void { 57 | var entry_address = multiboot_info_address + 8; 58 | 59 | while (true) { 60 | const entry: *MultibootTag = @ptrFromInt(entry_address); 61 | if (entry.type == 0) break; 62 | 63 | switch (entry.type) { 64 | 1 => commandLine = @ptrFromInt(entry_address + TAG_SIZE), 65 | 2 => bootloaderName = @ptrFromInt(entry_address + TAG_SIZE), 66 | 4 => { 67 | const basic_memory: [*]u32 = @ptrFromInt(entry_address + TAG_SIZE); 68 | memoryLower = basic_memory[0]; 69 | memoryUpper = basic_memory[1]; 70 | }, 71 | 6 => { 72 | const memory_map: [*]u32 = @ptrFromInt(entry_address + TAG_SIZE); 73 | entrySize = memory_map[0]; 74 | entryVersion = memory_map[1]; 75 | 76 | const entries_offset = TAG_SIZE + @sizeOf(u32) * 2; 77 | entries = @ptrFromInt(entry_address + entries_offset); 78 | entryCount = (entry.size - entries_offset) / entrySize; 79 | }, 80 | 14 => { 81 | acpiVersion2 = false; 82 | 83 | const rsdp: *acpi.rsdp = @ptrFromInt(entry_address + TAG_SIZE); 84 | acpiOldRsdp = rsdp.*; 85 | }, 86 | 15 => { 87 | acpiVersion2 = true; 88 | 89 | const rsdp: *acpi.rsdp_20 = @ptrFromInt(entry_address + TAG_SIZE); 90 | acpiNewRsdp = rsdp.*; 91 | }, 92 | else => {}, 93 | } 94 | 95 | entry_address += (entry.size + 7) & ~@as(usize, 7); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/pic.zig: -------------------------------------------------------------------------------- 1 | //The 8259 Programmable Interrupt Controller (PIC) is one of the most important chips making up the x86 architecture. 2 | //Without it, the x86 architecture would not be an interrupt driven architecture. 3 | //The function of the 8259A is to manage hardware interrupts and send them to the appropriate system interrupt. 4 | //This allows the system to respond to devices needs without loss of time (from polling the device, for instance). 5 | // It is important to note that APIC has replaced the 8259 PIC in more modern systems, especially those with multiple cores/processors. 6 | // https://wiki.osdev.org/8259_PIC 7 | // 8 | // The 8259 PIC controls the CPU's interrupt mechanism, by accepting several interrupt requests and feeding them to the processor in order. 9 | // For instance, when a keyboard registers a keyhit, it sends a pulse along its interrupt line (IRQ 1) to the PIC chip, which then translates 10 | // the IRQ into a system interrupt 11 | // and sends a message to interrupt the CPU from whatever it is doing. Part of the kernel's job is to either handle these IRQs 12 | // and perform the necessary procedures (poll the keyboard for the scancode) or alert a userspace program to the interrupt 13 | // (send a message to the keyboard driver). 14 | // Without a PIC, you would have to poll all the devices in the system to see if they want to do anything (signal an event) 15 | // but with a PIC, your system can run along nicely until such time that a device wants to signal an event 16 | // which means you don't waste time going to the devices, you let the devices come to you when they are ready. 17 | const port = @import("./port.zig"); 18 | 19 | // PIC = programmable interrupt controller 20 | // IRQ = interrupt request 21 | 22 | // IO base address for master (PIC1) and slave (PIC2) 23 | const PIC1 = 0x20; 24 | const PIC2 = 0xA0; 25 | 26 | // master PIC 27 | const PIC1_COMMAND = PIC1; 28 | const PIC1_DATA = PIC1 + 1; 29 | 30 | // slave PIC 31 | const PIC2_COMMAND = PIC2; 32 | const PIC2_DATA = PIC2 + 1; 33 | 34 | // end of interrupt command code 35 | const PIC_EOI = 0x20; 36 | 37 | // initialization commands 38 | const ICW1_ICW4 = 0x01; 39 | const ICW1_SINGLE = 0x02; 40 | const ICW1_INTERVAL4 = 0x04; 41 | const ICW1_LEVEL = 0x08; 42 | const ICW1_INIT = 0x10; 43 | 44 | // When you enter protected mode (or even before hand, if you're not using GRUB) 45 | // the first command you will need to give the two PICs is the initialise command (code 0x11). 46 | // This command makes the PIC wait for 3 extra "initialisation words" on the data port. These bytes give the PIC: 47 | // - Its vector offset. (ICW2) 48 | // - Tell it how it is wired to master/slaves. (ICW3) 49 | // - Gives additional information about the environment. (ICW4) 50 | const ICW4_8086 = 0x01; 51 | const ICW4_AUTO = 0x02; 52 | const ICW4_BUF_SLAVE = 0x08; 53 | const ICW4_BUF_MASTER = 0x0C; 54 | const ICW4_SFNM = 0x10; 55 | 56 | pub fn init() void { 57 | remap(0x20, 0x20); 58 | } 59 | 60 | // Perhaps the most common command issued to the PIC chips is the end of interrupt (EOI) command (code 0x20). 61 | // This is issued to the PIC chips at the end of an IRQ-based interrupt routine. If the IRQ came from the Master PIC, 62 | // it is sufficient to issue this command only to the Master PIC; however if the IRQ came from the Slave PIC, 63 | // it is necessary to issue the command to both PIC chips. 64 | pub fn sendEOI(irq: u8) void { 65 | if (irq >= 8) { 66 | port.outb(PIC2_COMMAND, PIC_EOI); 67 | } 68 | 69 | port.outb(PIC1_COMMAND, PIC_EOI); 70 | } 71 | 72 | // similar to sendEOI but explicit for testing 73 | pub fn pic_end_master() void { 74 | port.outb(PIC1_COMMAND, PIC_EOI); 75 | } 76 | 77 | // similar to sendEOI but explicit for testing 78 | pub fn pic_end_slave() void { 79 | port.outb(PIC2_COMMAND, PIC_EOI); 80 | port.outb(PIC1_COMMAND, PIC_EOI); 81 | } 82 | 83 | // arguments: 84 | // - offset1 - vector offset for master PIC 85 | // vectors on the master become offset1..offset1+7 86 | // - offset2 - same for slave PIC: offset2..offset2+7 87 | // 88 | // io_wait gives the PIC sometime to react to commands 89 | pub fn remap(offset1: u8, offset2: u8) void { 90 | // save masks 91 | const a = port.inb(PIC1_DATA); 92 | const b = port.inb(PIC2_DATA); 93 | 94 | port.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // start init sequence in cascade mode 95 | port.io_wait(); 96 | port.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); // start init sequence in cascade mode 97 | port.io_wait(); 98 | port.outb(PIC1_DATA, offset1); 99 | port.io_wait(); 100 | port.outb(PIC2_DATA, offset2); 101 | port.io_wait(); 102 | port.outb(PIC1_DATA, 4); 103 | port.io_wait(); 104 | port.outb(PIC2_DATA, 2); 105 | port.io_wait(); 106 | 107 | // restore saved masks 108 | port.outb(PIC1_DATA, a); 109 | port.outb(PIC2_DATA, b); 110 | } 111 | 112 | // If you are going to use the processor local APIC and the IOAPIC, you must first disable the PIC. 113 | // This is done by masking every single interrupt. 114 | pub fn disable() void { 115 | port.outb(PIC1_DATA, 0xFF); 116 | port.outb(PIC2_DATA, 0xFF); 117 | } 118 | 119 | // The PIC has an internal register called the IMR, or the Interrupt Mask Register. 120 | // It is 8 bits wide. This register is a bitmap of the request lines going into the PIC. 121 | // When a bit is set, the PIC ignores the request and continues normal operation. 122 | // Note that setting the mask on a higher request line will not affect a lower line. 123 | // Masking IRQ2 will cause the Slave PIC to stop raising IRQs. 124 | // Here is an example of how to mask an IRQ: 125 | pub fn irq_set_mask(irq: u8) void { 126 | var portq: u16 = 0; 127 | var intr = irq; 128 | 129 | if (intr < 8) { 130 | portq = PIC1_DATA; 131 | } else { 132 | portq = PIC2_DATA; 133 | intr -= 8; 134 | } 135 | 136 | const value = port.inb(portq) | @as(u8, @intCast(@as(u16, 1) << @as(u4, @intCast(intr)))); 137 | port.outb(portq, value); 138 | } 139 | 140 | pub fn irq_clear_mask(irq: u8) void { 141 | var portq: u16 = 0; 142 | var intr = irq; 143 | 144 | if (intr < 8) { 145 | portq = PIC1_DATA; 146 | } else { 147 | portq = PIC2_DATA; 148 | intr -= 8; 149 | } 150 | 151 | const value = port.inb(portq) & ~@as(u8, @intCast(@as(u16, 1) << @as(u4, @intCast(intr)))); 152 | port.outb(portq, value); 153 | } 154 | -------------------------------------------------------------------------------- /src/pit.zig: -------------------------------------------------------------------------------- 1 | const port = @import("port.zig"); 2 | const pic = @import("pic.zig"); 3 | // the most rudimentary form of a timer 4 | // TODO: switch to HPET, APIC and IOAPIC 5 | 6 | // the base frequency - we can set a divisor from 0-65535 7 | // to modify the frequency 8 | const MAX_FREQ = 1193182; 9 | var TIME_SINCE_BOOT: f64 = 0.0; 10 | 11 | // Registers or Channels 12 | const Channel0 = 0x40; 13 | const Channel1 = 0x41; 14 | const Channel2 = 0x42; 15 | const Control = 0x43; 16 | 17 | const Mode = enum(u3) { 18 | Interrupt = 0b000, 19 | HwOneShot = 0b001, 20 | RateGen = 0b010, 21 | SquareWave = 0b011, 22 | SwStrobe = 0b100, 23 | HwStrobe = 0b101, 24 | // RateGen = 0b110, 25 | // SquareWave = 0b111 26 | }; 27 | 28 | const Access = enum(u2) { 29 | Count = 0, 30 | ReloadLsb = 1, 31 | ReloadMsb = 2, 32 | /// Reload value (first LSB, then MSB) 33 | Reload = 3, 34 | }; 35 | 36 | pub fn set_count(count: u16) void { 37 | // disable interrupts 38 | asm volatile ("cli"); 39 | // set low byte 40 | // port.outw(Channel0, (count & 0xFF)); // Low byte 41 | // port.outb(Channel0, count); // Low byte 42 | // port.outb(Channel0, count >> 8); // High byte 43 | 44 | port.outb(Channel0, @as(u8, @truncate(count))); // Low byte 45 | port.outb(Channel0, @as(u8, @truncate((count >> 8)))); // High byte 46 | asm volatile ("sti"); 47 | } 48 | 49 | // max is 16bit 50 | pub var DIVISOR: u16 = 65535; 51 | 52 | // set the PITs divisor 53 | pub fn set_divisor(div: u16) void { 54 | var divisor = div; 55 | if (divisor < 100) divisor = 100; 56 | 57 | // set self.DIVISOR 58 | DIVISOR = divisor; 59 | 60 | // example: 0xABCD outputs... 61 | const low_byte: u8 = @truncate(divisor); // 0xCD 62 | const high_byte: u8 = @truncate(divisor >> 8); // 0xAB 63 | // 64 | port.outb(Channel0, low_byte); 65 | port.io_wait(); 66 | port.outb(Channel0, high_byte); 67 | } 68 | 69 | // get the PITs current frequency (u64) 70 | pub fn get_frequency() u64 { 71 | return MAX_FREQ / @as(u64, DIVISOR); 72 | // const div: u64 = @intCast(DIVISOR); 73 | // return (MAX_FREQ / div); 74 | } 75 | 76 | // set the PITs frequency 77 | pub fn set_frequency(freq: u64) void { 78 | // set_divisor(@as(u16, MAX_FREQ / freq)); 79 | // set_divisor(@intCast(MAX_FREQ / freq)); 80 | set_divisor(@truncate(MAX_FREQ / freq)); 81 | } 82 | 83 | // TODO: why is TIME_SINCE_BOOT and PIT frequency the same? 84 | // 85 | // counting each tick from the PIT on interrupt 86 | pub fn tick() void { 87 | TIME_SINCE_BOOT += @floatFromInt(get_frequency()); 88 | } 89 | 90 | pub fn init(freq: u16) void { 91 | pic.irq_clear_mask(0); 92 | set_frequency(freq); 93 | } 94 | 95 | // counting each tick from the PIT on interrupt 96 | pub fn uptime() f64 { 97 | return TIME_SINCE_BOOT; 98 | } 99 | 100 | // Sleep for specified nanoseconds 101 | pub fn sleep_ns(ns: f64) void { 102 | const start_time: f64 = TIME_SINCE_BOOT; 103 | while (TIME_SINCE_BOOT < start_time + ns) { 104 | asm volatile ("hlt"); // halt 105 | } 106 | } 107 | 108 | // sleep in milliseconds 109 | pub fn sleep_ms(ns: f64) void { 110 | sleep_ms(ns * 1000); 111 | } 112 | 113 | // sleep in seconds 114 | pub fn sleep(sec: f64) void { 115 | sleep_ns(sec * 10000); 116 | } 117 | 118 | // https://wiki.osdev.org/Programmable_Interval_Timer 119 | pub fn read_count() u16 { 120 | var count: u16 = 0; 121 | // disable interrupts 122 | asm volatile ("cli"); 123 | 124 | // al = channel in bits 6 and 7, remaining bits clear 125 | port.outb(Control, 0b0000000); 126 | // count = port.inb(Channel0); // Low byte 127 | // count = port.inb(Channel0); 128 | // count |= @truncate(port.inb(Channel0) << 8); // High byte 129 | 130 | const low: u8 = port.inb(Channel0); // Low byte 131 | const high: u8 = port.inb(Channel0); // High byte 132 | // 133 | asm volatile ("sti"); 134 | 135 | count = ((@as(u16, high)) | @as(u16, low)); 136 | 137 | // return port.inb(Channel0) | (port.inb(Channel0) << 8); 138 | // count = port.inb(Channel0); 139 | // count |= (@truncate(port.inb(Channel0) << 8)); 140 | return count; 141 | // return count; 142 | } 143 | 144 | // Version 3 - Full PIT initialization 145 | pub fn set_count2(count: u16) void { 146 | asm volatile ("cli"); 147 | defer asm volatile ("sti"); 148 | 149 | // Common initialization for channel 0, mode 3 150 | const command: u8 = (0 << 6) // Channel 0 151 | | (3 << 4) // Access mode: lobyte/hibyte 152 | | (3 << 1) // Mode 3 (square wave) 153 | | (0 << 0); // 16-bit binary 154 | 155 | port.outb(0x43, command); // Command port 156 | 157 | // LSB then MSB 158 | port.outb(0x40, @as(u8, @truncate(count))); 159 | port.outb(0x40, @as(u8, @truncate(count >> 8))); 160 | } 161 | 162 | // configures the chan0 with a rate generator, which will trigger irq0 163 | pub const divisor1 = 2685; 164 | // pub const tick = 2251; // f = 1.193182 MHz, TODO: turn into a function 165 | 166 | pub fn configPIT() void { 167 | const chanNum = 0; 168 | // const chan = PIT_CHAN0; 169 | const LOHI = 0b11; // bit4 | bit5 170 | const PITMODE_RATE_GEN = 0x2; 171 | 172 | port.outb(Control, chanNum << 6 | LOHI << 4 | PITMODE_RATE_GEN << 1); 173 | port.outb(Channel0, divisor1 & 0xff); 174 | port.outb(Channel0, divisor1 >> 8); 175 | } 176 | 177 | pub fn init2(freq: u32) void { 178 | // const reloadVal: u16 = @truncate(@divTrunc(MAX_FREQ + @divTrunc(freq, 2), freq)); 179 | const div: u32 = MAX_FREQ / freq; 180 | port.outb(Control, (div & 0xFF)); 181 | port.outb(Channel0, @truncate(div)); 182 | port.outb(Channel0, @truncate(div >> 8)); 183 | } 184 | 185 | pub fn init_freq(freq: u32) void { 186 | const reloadVal: u16 = @truncate(@divTrunc(MAX_FREQ + @divTrunc(freq, 2), freq)); 187 | port.outb(Control, .{ .counter = 0, .access = .Reload, .mode = .SquareWave }); 188 | 189 | port.outb(Channel0, @truncate(reloadVal)); 190 | port.outb(Channel0, @truncate(reloadVal >> 8)); 191 | } 192 | 193 | // ---------------- 194 | const PitFrequency = 1193182; // PIT's base frequency in Hz 195 | 196 | // Initialize PIT in one-shot mode for sleep 197 | pub fn init_pit_one_shot() void { 198 | const command: u8 = (0 << 6) // Channel 0 199 | | (3 << 4) // Access mode: lobyte/hibyte 200 | | (0 << 1); // Mode 0 (interrupt on terminal count) 201 | // One-shot mode is better for sleep 202 | 203 | asm volatile ("cli"); 204 | port.outb(Control, command); 205 | asm volatile ("sti"); 206 | } 207 | 208 | // Convert milliseconds to PIT ticks 209 | pub fn ms_to_ticks(ms: u32) u16 { 210 | const ticks = (ms * PitFrequency) / 1000; 211 | return @truncate(if (ticks > 65535) 65535 else ticks); 212 | } 213 | 214 | // Sleep for specified milliseconds 215 | pub fn sleep_old(ms: u32) void { 216 | const ticks = ms_to_ticks(ms); 217 | 218 | asm volatile ("cli"); 219 | // Load count 220 | port.outb(Channel0, @as(u8, @truncate(ticks))); 221 | port.outb(Channel0, @as(u8, @truncate(ticks >> 8))); 222 | asm volatile ("sti"); 223 | 224 | // Wait for the count to finish 225 | while (true) { 226 | port.outb(Control, 0xE2); // Latch count value for channel 0 227 | const status = port.inb(Channel0); 228 | if ((status & 0x80) != 0) { // Check if we've reached terminal count 229 | break; 230 | } 231 | asm volatile ("pause"); // Don't burn CPU while waiting 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/port.zig: -------------------------------------------------------------------------------- 1 | // https://wiki.osdev.org/Inline_Assembly/Examples#I.2FO_access 2 | // https://github.com/AnErrupTion/EeeOS/blob/master/src/utils/port.zig 3 | pub inline fn outb(port: u16, value: u8) void { 4 | asm volatile ("outb %[value],%[port]" 5 | : 6 | : [value] "{al}" (value), 7 | [port] "N{dx}" (port), 8 | ); 9 | } 10 | 11 | pub inline fn outw(port: u16, value: u16) void { 12 | asm volatile ("outw %[value],%[port]" 13 | : 14 | : [value] "{ax}" (value), 15 | [port] "N{dx}" (port), 16 | ); 17 | } 18 | 19 | pub inline fn inb(port: u16) u8 { 20 | return asm volatile ("inb %[port], %[ret]" 21 | : [ret] "={al}" (-> u8), 22 | : [port] "N{dx}" (port), 23 | ); 24 | } 25 | 26 | pub inline fn inw(port: u16) u16 { 27 | return asm volatile ("inw %[port], %[ret]" 28 | : [ret] "={ax}" (-> u16), 29 | : [port] "N{dx}" (port), 30 | ); 31 | } 32 | 33 | pub fn io_wait() void { 34 | outb(0x80, 0); 35 | } 36 | -------------------------------------------------------------------------------- /src/ps2.zig: -------------------------------------------------------------------------------- 1 | const port = @import("./port.zig"); 2 | const pic = @import("./pic.zig"); 3 | 4 | // https://wiki.osdev.org/%228042%22_PS/2_Controller 5 | // contains all PS2 definitions for reading and writing to the keyboard controller 6 | const DATA_PORT = 0x60; 7 | const STATUS_PORT = 0x64; 8 | const COMMAND_PORT = 0x64; 9 | 10 | const FIFO_SIZE = 256; 11 | var fifo_buffer: [FIFO_SIZE]u8 = undefined; 12 | var fifo_start: usize = 0; 13 | var fifo_end: usize = 0; 14 | 15 | pub fn onInterrupt() void { 16 | const status = port.inb(STATUS_PORT) & 0x01; 17 | 18 | if (status == 0x01) { 19 | const data = port.inb(DATA_PORT); 20 | 21 | var next = fifo_end + 1; 22 | if (next == FIFO_SIZE) next = 0; // Wrap around 23 | if (next == fifo_start) return; // We're out of room 24 | 25 | fifo_buffer[next] = data; 26 | fifo_end = next; 27 | } 28 | } 29 | 30 | pub fn init() void { 31 | // Enable keyboard handler in PIC (IRQ 1) 32 | pic.irq_clear_mask(1); 33 | // flush the output buffer 34 | // _ = port.inb(DATA_PORT); 35 | } 36 | 37 | pub fn getScanCode() u8 { 38 | if (fifo_start == fifo_end) return 0; 39 | 40 | const value = fifo_buffer[fifo_start]; 41 | fifo_start += 1; 42 | if (fifo_start == FIFO_SIZE) fifo_start = 0; // Wrap around 43 | 44 | return value; 45 | } 46 | -------------------------------------------------------------------------------- /src/rand.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const nasm = @import("asm.zig"); 3 | const pmm = @import("mem.zig"); 4 | const pit = @import("pit.zig"); 5 | 6 | // mersenne twister 7 | 8 | const STATE_VECTOR_L = 624; 9 | const STATE_VECTOR_M = 397; 10 | 11 | const UPPER_MASK = 0x80000000; 12 | const LOWER_MASK = 0x7fffffff; 13 | 14 | const MAX_U32 = std.math.maxInt(u32); 15 | 16 | // Holds generated seeds and current index: 17 | const Rand = struct { mt: [STATE_VECTOR_L]u32, index: usize }; 18 | 19 | // Sets initial seeds of MTRand.mt using the generator in input: 20 | inline fn init_seeds(r: *Rand, seed: u32) void { 21 | r.index = 1; 22 | r.mt[0] = seed & 0xffffffff; 23 | 24 | while (r.index < STATE_VECTOR_L) { 25 | r.mt[r.index] = (r.mt[r.index - 1] *% 6069) & 0xffffffff; 26 | r.index += 1; 27 | } 28 | } 29 | 30 | // Returns a pseudo-randomly generated u32: 31 | fn rand_u32() u32 { 32 | var y: u32 = undefined; 33 | 34 | const Static = struct { 35 | var mag: [2]u32 = .{ 0x0, 0x9908b0df }; 36 | }; 37 | 38 | if (rand.index < 0 or rand.index >= STATE_VECTOR_L) { 39 | var kk: u32 = 0; 40 | 41 | const L_1 = STATE_VECTOR_L - 1; 42 | const L_M = STATE_VECTOR_L - STATE_VECTOR_M; 43 | const M_L = STATE_VECTOR_M - STATE_VECTOR_L; 44 | 45 | if (rand.index < 0 or rand.index >= STATE_VECTOR_L + 1) 46 | init_seeds(&rand, 4357); 47 | 48 | while (kk < L_M) { 49 | y = (rand.mt[kk] & UPPER_MASK) | (rand.mt[kk + 1] & LOWER_MASK); 50 | rand.mt[kk] = rand.mt[kk + STATE_VECTOR_M] ^ (y >> 1) ^ Static.mag[y & 0x1]; 51 | kk += 1; 52 | } 53 | 54 | while (kk < L_1) { 55 | const ml: u32 = @bitCast(@as(i32, M_L)); 56 | y = (rand.mt[kk] & UPPER_MASK) | (rand.mt[kk + 1] & LOWER_MASK); 57 | rand.mt[kk] = rand.mt[kk +% ml] ^ (y >> 1) ^ Static.mag[y & 0x1]; 58 | 59 | kk += 1; 60 | } 61 | 62 | y = (rand.mt[L_1] & UPPER_MASK) | (rand.mt[0] & LOWER_MASK); 63 | 64 | rand.mt[L_1] = rand.mt[STATE_VECTOR_M - 1] ^ (y >> 1) ^ Static.mag[y & 0x1]; 65 | 66 | rand.index = 0; 67 | } 68 | 69 | y = rand.mt[rand.index]; 70 | rand.index += 1; 71 | 72 | y ^= (y >> 11); 73 | y ^= (y << 7) & 0x9d2c5680; 74 | y ^= (y << 15) & 0xefc60000; 75 | y ^= (y >> 18); 76 | 77 | return y; 78 | } 79 | 80 | // Creates a new random number generator from a given seed: 81 | pub fn init(seed: ?u32) Rand { 82 | var r: Rand = undefined; 83 | 84 | // const def_seed: u32 = @bitCast(nasm.rdtsc()); 85 | const def_seed: u32 = @intCast(pit.get_frequency()); 86 | 87 | // const s = seed orelse 1337; 88 | const s = seed orelse def_seed; 89 | 90 | init_seeds(&r, s); 91 | return r; 92 | } 93 | 94 | pub fn compinit(seed: ?u32) Rand { 95 | var r: Rand = undefined; 96 | 97 | // const def_seed: u32 = @bitCast(nasm.rdtsc()); 98 | // const def_seed: u32 = @intCast(pit.get_frequency()); 99 | 100 | const s = seed orelse 1337; 101 | // const s = seed orelse def_seed; 102 | 103 | init_seeds(&r, s); 104 | return r; 105 | } 106 | 107 | // Returns a pseudo-randomly generated f64 (in range 0 - 1): 108 | pub fn random() f64 { 109 | return @as(f64, @floatFromInt(rand_u32())) / MAX_U32; 110 | } 111 | 112 | pub fn randint() u32 { 113 | return @as(u32, rand_u32()) / MAX_U32; 114 | } 115 | 116 | // Returns a pseudo-randomly generated i64 (in range min - max): 117 | pub fn randomInt(min: i64, max: i64) i64 { 118 | const range: f64 = @floatFromInt(max - min + 1); 119 | const r: i64 = @intFromFloat(random() * range); 120 | 121 | return min + r; 122 | } 123 | 124 | // Returns a pseudo-randomly generated f64 (in range min - max): 125 | pub fn randomFloat(min: f64, max: f64) f64 { 126 | return random() * (max - min) + min; 127 | } 128 | 129 | // var rand = init(1233123); 130 | var rand = compinit(333); 131 | 132 | test "rand" { 133 | rand = init(3); 134 | 135 | std.debug.print("float {d}\n", .{random()}); 136 | std.debug.print("int {d}\n", .{random()}); 137 | std.debug.print("rand float range 1-10000 {d}\n", .{randomFloat(1, 10000)}); 138 | } 139 | -------------------------------------------------------------------------------- /src/shell.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const console = @import("./console.zig"); 3 | const scanmap = @import("./keys.zig"); 4 | const ps2 = @import("./ps2.zig"); 5 | const acpi = @import("./acpi.zig"); 6 | const port = @import("port.zig"); 7 | const pmm = @import("./mem.zig"); 8 | const kernel = @import("kernel.zig"); 9 | const art = @import("art.zig"); 10 | const utils = @import("utils.zig"); 11 | const rand = @import("rand.zig"); 12 | 13 | const pit = @import("pit.zig"); 14 | const history = @import("history.zig"); 15 | 16 | const eql = @import("std").mem.eql; 17 | 18 | const BUFFER_SIZE = 4096; 19 | var buffer: [BUFFER_SIZE]u8 = undefined; 20 | 21 | fn read_line() usize { 22 | var index: usize = 0; 23 | while (true) { 24 | const scan_code = ps2.getScanCode(); 25 | if (scan_code == 0) { 26 | continue; 27 | } 28 | 29 | // read the scan code and translate it into a key 30 | const key = scanmap.HandleKeyboard(scan_code); 31 | 32 | if (key.type == .unknown or key.type == .shift or key.type == .ctrl) { 33 | continue; 34 | } 35 | 36 | if (key.type == .backspace) { 37 | if (index > 0) { 38 | index -= 1; 39 | buffer[index] = ' '; 40 | console.backspace(); 41 | } 42 | 43 | continue; 44 | } 45 | 46 | if (key.type == .enter) { 47 | console.newLine(); 48 | return index; 49 | } 50 | 51 | if (key.type == .arrow_up) { 52 | console.clear_line(); 53 | // const line = hist.last().?; 54 | // @memcpy(&buffer[0..lastcmd.len], lastcmd); 55 | // buffer = lastcmd; 56 | // for (lastcmd, 0..lastcmd.len) |value, i| { 57 | // buffer[i] = value; 58 | // } 59 | 60 | // @memcpy(&buffer, &lastcmd); 61 | // console.write(buffer[0..lastlen]); 62 | // return lastcmd.len; 63 | // return line.len; 64 | // continue; 65 | // return lastlen; 66 | } 67 | 68 | // debug printf - uncomment "continue" above for .unknown 69 | // if (key.type == .unknown) { 70 | // const out = std.fmt.hex(key.value, .upper); 71 | // const sc = utils.uitoa(scan_code, utils.PrintStyle.hex).arr; 72 | // console.write(&sc); 73 | // continue; 74 | // }; 75 | 76 | buffer[index] = key.value; 77 | console.putChar(key.value); 78 | index += 1; 79 | } 80 | } 81 | 82 | // var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 83 | // const alloc = std.heap.page_allocator; 84 | // const alloc = gpa.allocator(); 85 | // var hist = history.init(); 86 | 87 | var lastcmd: [BUFFER_SIZE]u8 = undefined; 88 | var lastlen: usize = undefined; 89 | 90 | pub fn exec() void { 91 | const format_buffer_size = 1024; 92 | var format_buffer: [format_buffer_size]u8 = undefined; 93 | 94 | // var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 95 | // defer { 96 | // const deinit_status = gpa.deinit(); 97 | //fail test; can't try in defer as defer is executed after we return 98 | // if (deinit_status == .leak) { 99 | // @panic("deinit failed"); 100 | // } 101 | // } 102 | 103 | // const alloc = gpa.allocator(); 104 | // const hist = history.init(alloc); 105 | // defer hist.deinit(); 106 | 107 | while (true) { 108 | console.write("> "); 109 | // var histor_cursor: usize = 0; 110 | 111 | const size = read_line(); 112 | const command = buffer[0..size]; 113 | @memcpy(&lastcmd, &buffer); 114 | lastlen = size; 115 | 116 | if (std.mem.eql(u8, command, "help")) { 117 | console.writeln( 118 | \\help - Shows all commands. 119 | \\usedmem - (mem) Shows the amount of used RAM, in KiB. 120 | \\totalmem - (tmem) Shows the total amount of usable RAM, in MiB. 121 | \\shutdown - Shuts down the computer via ACPI. 122 | \\reset - Resets the computer via ACPI. 123 | \\ascii - Print the ascii OS logo 124 | \\echo - Echo the given text 125 | \\color - (c) change console colors fg (0-15) fg+bg(16-255) (green|red) 126 | \\fg - (c) change console colors fg (0-15) fg+bg(16-255) (green|red) 127 | \\bg - (c) change console colors fg (0-15) fg+bg(16-255) (green|red) 128 | ); 129 | } else if (std.mem.eql(u8, command, "clear")) { 130 | console.clear(); 131 | } else if (std.mem.eql(u8, command, "usedmem") or eql(u8, command, "mem")) { 132 | const format = std.fmt.bufPrint(&format_buffer, "RAM in use: {d} kiB", .{pmm.pages_in_use * pmm.PAGE_SIZE / 1024}) catch unreachable; 133 | console.writeln(format); 134 | } else if (eql(u8, command, "totalmem") or eql(u8, command, "tmem")) { 135 | const format = std.fmt.bufPrint(&format_buffer, "Total usable RAM: {d} MiB", .{pmm.total_size / 1024 / 1024}) catch unreachable; 136 | console.writeln(format); 137 | } else if (std.mem.eql(u8, command, "shutdown")) { 138 | console.writeln("Shutting down..."); 139 | acpi.shutdown(); 140 | // qemu -> qemu 2.0 -> virtualbox -> cloud hypervisor 141 | console.writeln("qemu new versions..."); 142 | port.outw(0x604, 0x2000); 143 | console.writeln("qemu old 2.0..."); 144 | port.outw(0xB004, 0x2000); 145 | console.writeln("virtualbox..."); 146 | port.outw(0x4004, 0x3400); 147 | console.writeln("cloud hypervisor..."); 148 | port.outw(0x600, 0x34); 149 | } else if (std.mem.eql(u8, command, "reset")) { 150 | console.writeln("Resetting..."); 151 | acpi.reset(); 152 | } else if (std.mem.eql(u8, command, "ascii")) { 153 | for (art.ASUKA_LOGO) |line| { 154 | console.writeln(line); 155 | } 156 | } else if (std.mem.eql(u8, command, "")) { 157 | continue; 158 | } else if (std.mem.eql(u8, command, "uptime")) { 159 | console.printf("uptime {d}\n", .{pit.uptime()}); 160 | continue; 161 | } else if (std.mem.eql(u8, command, "neofetch")) { 162 | for (art.ASUKA_LOGO) |line| { 163 | console.writeln(line); 164 | } 165 | console.printf("uptime: {d}\n", .{pit.uptime()}); 166 | console.printf("pit freq: {d}\n", .{pit.uptime()}); 167 | const color = console.get_colors(); 168 | console.set_bg(@intFromEnum(console.Colors.Green)); 169 | console.write(" "); 170 | console.set_bg(@intFromEnum(console.Colors.Blue)); 171 | console.write(" "); 172 | console.set_bg(@intFromEnum(console.Colors.Red)); 173 | console.write(" "); 174 | console.set_bg(@intFromEnum(console.Colors.Magenta)); 175 | console.write(" "); 176 | console.set_bg(@intFromEnum(console.Colors.Cyan)); 177 | console.write(" "); 178 | console.set_bg(@intFromEnum(console.Colors.LightBlue)); 179 | console.writeln(" "); 180 | console.setColor(color); 181 | continue; 182 | } else if (std.mem.eql(u8, command, "alloc")) { 183 | const addy = pmm.allocate(100); 184 | console.write("allocated 100bytes for funsies uwu "); 185 | const x = utils.uitoa(addy, utils.PrintStyle.hex).arr; 186 | console.write("at address: 0x"); 187 | console.writeln(&x); 188 | continue; 189 | } else if (std.mem.eql(u8, command, "trans")) { 190 | const color = console.get_colors(); 191 | console.set_bg(@intFromEnum(console.Colors.Cyan)); 192 | console.writeln(" "); 193 | console.set_bg(@intFromEnum(console.Colors.LightMagenta)); 194 | console.writeln(" "); 195 | console.set_bg(@intFromEnum(console.Colors.White)); 196 | console.writeln(" "); 197 | console.set_bg(@intFromEnum(console.Colors.LightMagenta)); 198 | console.writeln(" "); 199 | console.set_bg(@intFromEnum(console.Colors.Cyan)); 200 | console.writeln(" "); 201 | console.setColor(color); 202 | } else if (std.mem.eql(u8, command, "rand")) { 203 | _ = rand.init(@intCast(pit.get_frequency())); 204 | const i = rand.randomInt(0, 10000); 205 | console.printf("{d}\n", .{i}); 206 | continue; 207 | } else { 208 | var line = std.mem.splitSequence(u8, command, " "); 209 | const first = line.first(); 210 | 211 | if (first.len == 0) { 212 | console.write("error reading command..."); 213 | continue; 214 | } 215 | 216 | if (eql(u8, first, "color") or eql(u8, first, "c")) { 217 | if (line.peek() == null) { 218 | console.setColor2(console.Colors.Red); 219 | console.write("error: "); 220 | console.setColor2(console.Colors.Green); 221 | console.writeln("must provide a value between 0-15"); 222 | continue; 223 | } 224 | 225 | while (line.next()) |value| { 226 | if (value.len < 1) { 227 | console.setColor2(console.Colors.Red); 228 | console.write("error: "); 229 | console.setColor2(console.Colors.Green); 230 | console.writeln("must provide a value between 0-15"); 231 | continue; 232 | } 233 | 234 | if (eql(u8, value, "green")) { 235 | console.setColor2(console.Colors.Green); 236 | continue; 237 | } 238 | 239 | if (eql(u8, value, "red")) { 240 | console.setColor2(console.Colors.Red); 241 | continue; 242 | } 243 | 244 | const col = std.fmt.parseInt(u8, value, 10) catch |e| { 245 | switch (e) { 246 | error.InvalidCharacter => { 247 | console.writeln("uh uh uh >-< bad char"); 248 | continue; 249 | }, 250 | error.Overflow => { 251 | console.writeln("uh uh uh >-< buffaw ovofwow"); 252 | continue; 253 | }, 254 | } 255 | }; 256 | 257 | console.setColor(col); 258 | continue; 259 | } 260 | } 261 | 262 | if (eql(u8, first, "fg") or eql(u8, first, "bg")) { 263 | while (line.next()) |value| { 264 | const col = std.fmt.parseInt(u8, value, 10) catch |e| { 265 | switch (e) { 266 | error.InvalidCharacter => { 267 | console.writeln("uh uh uh >-< bad char"); 268 | continue; 269 | }, 270 | error.Overflow => { 271 | console.writeln("uh uh uh >-< buffaw ovofwow"); 272 | continue; 273 | }, 274 | } 275 | }; 276 | 277 | if (eql(u8, first, "fg")) { 278 | console.set_fg(col); 279 | } else { 280 | console.set_bg(col); 281 | } 282 | } 283 | continue; 284 | } 285 | 286 | if (eql(u8, first, "echo")) { 287 | while (line.next()) |value| { 288 | console.write(value); 289 | console.write(" "); 290 | } 291 | console.writeln(""); 292 | continue; 293 | } 294 | 295 | if (eql(u8, first, "sleep")) { 296 | while (line.next()) |value| { 297 | const time = std.fmt.parseFloat(f64, value) catch |e| { 298 | switch (e) { 299 | error.InvalidCharacter => { 300 | console.writeln("uh uh uh >-< bad char"); 301 | continue; 302 | }, 303 | } 304 | }; 305 | 306 | console.printf("sleeping for {d}\n", .{time}); 307 | // pit.sleep(time * 100_000); 308 | pit.sleep(time); 309 | } 310 | 311 | continue; 312 | } 313 | 314 | // console.write("Unknown command: "); 315 | // console.writeln(command); 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /src/sync.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | // Thanks to: https://github.com/Rheydskey/zros 3 | 4 | pub fn TicketLock(comptime value_type: type) type { 5 | return struct { 6 | last_ticket: std.atomic.Value(u32), 7 | current_ticket: std.atomic.Value(u32), 8 | value: value_type, 9 | 10 | pub fn init(value: value_type) @This() { 11 | return .{ 12 | .last_ticket = std.atomic.Value(u32).init(0), 13 | .current_ticket = std.atomic.Value(u32).init(0), 14 | .value = value, 15 | }; 16 | } 17 | 18 | pub fn lock(self: *@This()) *value_type { 19 | const a = self.last_ticket.fetchAdd(1, .acquire); 20 | 21 | while (self.current_ticket.load(.acquire) != a) { 22 | asm volatile ("pause" ::: "memory"); 23 | } 24 | 25 | return &self.value; 26 | } 27 | 28 | pub fn unlock(self: *@This()) void { 29 | _ = self.current_ticket.fetchAdd(1, .acquire); 30 | } 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/utils.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const console = @import("console.zig"); 3 | 4 | fn splitLineBySpaces(line: []const u8) ![][]const u8 { 5 | var result = std.ArrayList([]const u8).init(std.heap.page_allocator); 6 | defer result.deinit(); 7 | 8 | var it = std.mem.splitSequence(u8, line, " "); 9 | while (it.next()) |item| { 10 | try result.append(item); 11 | } 12 | 13 | return result.toOwnedSlice(); 14 | } 15 | 16 | pub const PrintStyle = enum(u8) { 17 | string = 10, 18 | hex = 16, 19 | binary = 2, 20 | }; 21 | 22 | // from zig std 23 | /// Compares two slices and returns whether they are equal. 24 | pub fn eql(a: [][]const u8, b: [][]const u8) bool { 25 | if (a.len != b.len) return false; 26 | if (a.ptr == b.ptr) return true; 27 | 28 | for (a, 0..) |item, index| { 29 | if (!std.mem.eql(u8, b[index], item)) return false; 30 | } 31 | return true; 32 | } 33 | 34 | pub fn assert(ok: bool) void { 35 | if (!ok) unreachable; // assertion failure 36 | } 37 | 38 | pub fn reverseString(str: [*]u8, len: usize) void { 39 | var start: usize = 0; 40 | var end: usize = len - 1; 41 | var temp: u8 = 0; 42 | 43 | while (end > start) { 44 | temp = str[start]; 45 | str[start] = str[end]; 46 | str[end] = temp; 47 | 48 | start += 1; 49 | end -= 1; 50 | } 51 | } 52 | 53 | // 20 is u64 max len in u8 54 | pub fn uitoa(num: u64, print_style: PrintStyle) struct { arr: [20]u8, len: u8 } { 55 | var str = [_]u8{0} ** 20; 56 | 57 | if (num == 0) { 58 | str[0] = 0; 59 | return .{ .arr = str, .len = 0 }; 60 | } 61 | 62 | var rem: u64 = 0; 63 | var i: u8 = 0; 64 | var num_i = num; 65 | while (num_i != 0) { 66 | rem = @mod(num_i, @intFromEnum(print_style)); 67 | if (rem > 9) { 68 | str[i] = @truncate((rem - 10) + 'a'); 69 | } else { 70 | str[i] = @truncate(rem + '0'); 71 | } 72 | i += 1; 73 | 74 | num_i = num_i / @intFromEnum(print_style); 75 | } 76 | reverseString(&str, i); 77 | return .{ .arr = str, .len = i }; 78 | } 79 | 80 | test "itoa test" { 81 | const res = uitoa(32, PrintStyle.string).arr; 82 | assert(res[0] == '3'); 83 | assert(res[1] == '2'); 84 | 85 | const res2 = uitoa(89367549, PrintStyle.string).arr; 86 | assert(res2[0] == '8'); 87 | assert(res2[1] == '9'); 88 | assert(res2[2] == '3'); 89 | assert(res2[3] == '6'); 90 | assert(res2[4] == '7'); 91 | assert(res2[5] == '5'); 92 | assert(res2[6] == '4'); 93 | assert(res2[7] == '9'); 94 | } 95 | 96 | test "reverse_string test" { 97 | var res = "abvc".*; 98 | reverseString(@as([*]u8, &res), 4); 99 | assert(res[0] == 'c'); 100 | assert(res[1] == 'v'); 101 | assert(res[2] == 'b'); 102 | assert(res[3] == 'a'); 103 | } 104 | 105 | // test "split line by spaces" { 106 | // const input = "Hello World This is a test"; 107 | // const expected = [_][]const u8{ "Hello", "World", "This", "is", "a", "test" }; 108 | // 109 | // const actual = try splitLineBySpaces(input); 110 | // TODO fix I guess? 111 | // i guess this doesn't work unless they are literally the same pointer lmao 112 | // whats the point then? 113 | // try std.testing.expectEqualSlices([]const u8, expected[0..], actual[0..]); 114 | // eql(&expected, actual); 115 | // } 116 | --------------------------------------------------------------------------------