Merge pull request #29 from SamTebbs33/feature/create-gdt-idt-irq-isr
Added GDT, IDT, IRQ, updated build.zig
This commit is contained in:
		
						commit
						144dffe628
					
				
					 12 changed files with 1009 additions and 11 deletions
				
			
		
							
								
								
									
										39
									
								
								build.zig
									
										
									
									
									
								
							
							
						
						
									
										39
									
								
								build.zig
									
										
									
									
									
								
							|  | @ -4,11 +4,13 @@ const Builder = @import("std").build.Builder; | |||
| const Step = @import("std").build.Step; | ||||
| const builtin = @import("builtin"); | ||||
| const std = @import("std"); | ||||
| const os = std.os; | ||||
| const ArrayList = std.ArrayList; | ||||
| const warn = std.debug.warn; | ||||
| const mem = std.mem; | ||||
| 
 | ||||
| var src_files: ArrayList([]const u8) = undefined; | ||||
| var src_files_asm: ArrayList([]const u8) = undefined; | ||||
| 
 | ||||
| fn concat(allocator: *std.mem.Allocator, str: []const u8, str2: []const u8) !std.Buffer { | ||||
|     var b = try std.Buffer.init(allocator, str); | ||||
|  | @ -18,21 +20,38 @@ fn concat(allocator: *std.mem.Allocator, str: []const u8, str2: []const u8) !std | |||
| 
 | ||||
| pub fn build(b: *Builder) void { | ||||
|     src_files = ArrayList([]const u8).init(b.allocator); | ||||
|     src_files_asm = ArrayList([]const u8).init(b.allocator); | ||||
|     const debug = b.option(bool, "debug", "build with debug symbols / make qemu wait for a debug connection") orelse false; | ||||
|     var build_path = b.option([]const u8, "build-path", "path to build to") orelse "bin"; | ||||
|     var src_path = b.option([]const u8, "source-path", "path to source") orelse "src"; | ||||
|     var target = b.option([]const u8, "target", "target to build/run for") orelse "x86"; | ||||
|     const builtin_target = if (mem.eql(u8, target, "x86")) builtin.Arch.i386 else unreachable; | ||||
| 
 | ||||
|     const iso_path = concat(b.allocator, build_path, "/pluto.iso") catch unreachable; | ||||
|     b.makePath(build_path) catch unreachable; | ||||
|     var grub_path = concat(b.allocator, build_path, "/iso/boot/grub") catch unreachable; | ||||
|     var kern_path = concat(b.allocator, build_path, "/kernel") catch unreachable; | ||||
|     var a_path = concat(b.allocator, build_path, "/kernel/arch/") catch unreachable; | ||||
|     a_path = concat(b.allocator, a_path.toSlice(), target) catch unreachable; | ||||
|     b.makePath(grub_path.toSlice()) catch unreachable; | ||||
|     b.makePath(kern_path.toSlice()) catch unreachable; | ||||
|     b.makePath(a_path.toSlice()) catch unreachable; | ||||
| 
 | ||||
|     src_files.append("kernel/kmain") catch unreachable; | ||||
| 
 | ||||
|     // Add the architecture init file to the source files | ||||
|     // Add the assemblies | ||||
|     switch (builtin_target) { | ||||
|         builtin.Arch.i386 => { | ||||
|             src_files_asm.append("kernel/arch/x86/irq_asm") catch unreachable; | ||||
|             src_files_asm.append("kernel/arch/x86/isr_asm") catch unreachable; | ||||
|         }, | ||||
|         else => {}, | ||||
|     } | ||||
| 
 | ||||
|     var arch_boot = concat(b.allocator, "kernel/arch/", target) catch unreachable; | ||||
|     arch_boot.append("/boot") catch unreachable; | ||||
|     src_files.append(arch_boot.toSlice()) catch unreachable; | ||||
| 
 | ||||
|     const iso_path = concat(b.allocator, build_path, "/pluto.iso") catch unreachable; | ||||
|     var objects_steps = buildObjects(b, builtin_target, build_path, src_path); | ||||
|     var link_step = buildLink(b, builtin_target, build_path); | ||||
|     const iso_step = buildISO(b, build_path, iso_path.toSlice()); | ||||
|  | @ -114,6 +133,13 @@ fn buildLink(b: *Builder, target: builtin.Arch, build_path: []const u8) *Step { | |||
|         file_obj.append(file) catch unreachable; | ||||
|         file_obj.append(".o") catch unreachable; | ||||
|         exec.addObjectFile(file_obj.toSlice()); | ||||
|         exec.setMainPkgPath("."); | ||||
|     } | ||||
|     for (src_files_asm.toSlice()) |file| { | ||||
|         var file_obj = concat(b.allocator, build_path, "/") catch unreachable; | ||||
|         file_obj.append(file) catch unreachable; | ||||
|         file_obj.append(".o") catch unreachable; | ||||
|         exec.addObjectFile(file_obj.toSlice()); | ||||
|     } | ||||
|     return &exec.step; | ||||
| } | ||||
|  | @ -125,6 +151,15 @@ fn buildObjects(b: *Builder, target: builtin.Arch, build_path: []const u8, src_p | |||
|         var file_src = concat(b.allocator, src_path2.toSlice(), file) catch unreachable; | ||||
|         file_src.append(".zig") catch unreachable; | ||||
|         const obj = b.addObject(file, file_src.toSlice()); | ||||
|         obj.setMainPkgPath("."); | ||||
|         obj.setOutputDir(build_path); | ||||
|         obj.setTarget(target, builtin.Os.freestanding, builtin.Abi.gnu); | ||||
|         objects.append(&obj.step) catch unreachable; | ||||
|     } | ||||
|     for (src_files_asm.toSlice()) |file| { | ||||
|         var file_src = concat(b.allocator, src_path2.toSlice(), file) catch unreachable; | ||||
|         file_src.append(".s") catch unreachable; | ||||
|         const obj = b.addAssemble(file, file_src.toSlice()); | ||||
|         obj.setOutputDir(build_path); | ||||
|         obj.setTarget(target, builtin.Os.freestanding, builtin.Abi.gnu); | ||||
|         objects.append(&obj.step) catch unreachable; | ||||
|  |  | |||
|  | @ -1,11 +1,54 @@ | |||
| // Zig version: 0.4.0 | ||||
| 
 | ||||
| const is_test = @import("builtin").is_test; | ||||
| const builtin = @import("builtin"); | ||||
| const gdt = @import("gdt.zig"); | ||||
| const idt = @import("idt.zig"); | ||||
| const irq = @import("irq.zig"); | ||||
| const isr = @import("isr.zig"); | ||||
| 
 | ||||
| pub const InterruptContext = struct { | ||||
|     // Extra segments | ||||
|     gs: u32, | ||||
|     fs: u32, | ||||
|     es: u32, | ||||
|     ds: u32, | ||||
| 
 | ||||
|     // Destination, source, base pointer | ||||
|     edi: u32, | ||||
|     esi: u32, | ||||
|     ebp: u32, | ||||
|     esp: u32, | ||||
| 
 | ||||
|     // General registers | ||||
|     ebx: u32, | ||||
|     edx: u32, | ||||
|     ecx: u32, | ||||
|     eax: u32, | ||||
| 
 | ||||
|     // Interrupt number and error code | ||||
|     int_num: u32, | ||||
|     error_code: u32, | ||||
| 
 | ||||
|     // Instruction pointer, code segment and flags | ||||
|     eip: u32, | ||||
|     cs: u32, | ||||
|     eflags: u32, | ||||
|     user_esp: u32, | ||||
|     ss: u32, | ||||
| }; | ||||
| 
 | ||||
| /// | ||||
| /// Initialise the architecture | ||||
| /// | ||||
| pub fn init() void {} | ||||
| pub fn init() void { | ||||
|     disableInterrupts(); | ||||
| 
 | ||||
|     gdt.init(); | ||||
|     idt.init(); | ||||
| 
 | ||||
|     isr.init(); | ||||
|     irq.init(); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Inline assembly to write to a given port with a byte of data. | ||||
|  | @ -45,3 +88,81 @@ pub fn inb(port: u16) u8 { | |||
| pub fn ioWait() void { | ||||
|     outb(0x80, 0); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Load the GDT and refreshing the code segment with the code segment offset of the kernel as we | ||||
| /// are still in kernel land. Also loads the kernel data segment into all the other segment | ||||
| /// registers. | ||||
| /// | ||||
| /// Arguments: | ||||
| ///     IN gdt_ptr: *gdt.GdtPtr - The address to the GDT. | ||||
| /// | ||||
| pub fn lgdt(gdt_ptr: *const gdt.GdtPtr) void { | ||||
|     // Load the GDT into the CPU | ||||
|     asm volatile ("lgdt (%%eax)" : : [gdt_ptr] "{eax}" (gdt_ptr)); | ||||
|     // Load the kernel data segment, index into the GDT | ||||
|     asm volatile ("mov %%bx, %%ds" : : [KERNEL_DATA_OFFSET] "{bx}" (gdt.KERNEL_DATA_OFFSET)); | ||||
|     asm volatile ("mov %%bx, %%es"); | ||||
|     asm volatile ("mov %%bx, %%fs"); | ||||
|     asm volatile ("mov %%bx, %%gs"); | ||||
|     asm volatile ("mov %%bx, %%ss"); | ||||
|     // Load the kernel code segment into the CS register | ||||
|     asm volatile ( | ||||
|         \\ljmp $0x08, $1f | ||||
|         \\1: | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Load the TSS into the CPU. | ||||
| /// | ||||
| pub fn ltr() void { | ||||
|     asm volatile ("ltr %%ax" : : [TSS_OFFSET] "{ax}" (gdt.TSS_OFFSET)); | ||||
| } | ||||
| 
 | ||||
| /// Load the IDT into the CPU. | ||||
| pub fn lidt(idt_ptr: *const idt.IdtPtr) void { | ||||
|     asm volatile ("lidt (%%eax)" : : [idt_ptr] "{eax}" (idt_ptr)); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Enable interrupts | ||||
| /// | ||||
| pub fn enableInterrupts() void { | ||||
|     asm volatile ("sti"); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Disable interrupts | ||||
| /// | ||||
| pub fn disableInterrupts() void { | ||||
|     asm volatile ("cli"); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Halt the CPU, but interrupts will still be called | ||||
| /// | ||||
| pub fn halt() void { | ||||
|     asm volatile ("hlt"); | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Wait the kernel but still can handle interrupts. | ||||
| /// | ||||
| pub fn spinWait() noreturn { | ||||
|     while (true) { | ||||
|         enableInterrupts(); | ||||
|         halt(); | ||||
|         disableInterrupts(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// | ||||
| /// Halt the kernel. | ||||
| /// | ||||
| pub fn haltNoInterrupts() noreturn { | ||||
|     while (true) { | ||||
|         disableInterrupts(); | ||||
|         halt(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										293
									
								
								src/kernel/arch/x86/gdt.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								src/kernel/arch/x86/gdt.zig
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,293 @@ | |||
| // Zig version: 0.4.0 | ||||
| 
 | ||||
| const arch = @import("arch.zig"); | ||||
| 
 | ||||
| const NUMBER_OF_ENTRIES: u16 = 0x06; | ||||
| const TABLE_SIZE: u16 = @sizeOf(GdtEntry) * NUMBER_OF_ENTRIES - 1; | ||||
| 
 | ||||
| // The indexes into the GDT where each segment resides. | ||||
| 
 | ||||
| /// The index of the NULL GDT entry. | ||||
| const NULL_INDEX: u16           = 0x00; | ||||
| 
 | ||||
| /// The index of the kernel code GDT entry. | ||||
| const KERNEL_CODE_INDEX: u16    = 0x01; | ||||
| 
 | ||||
| /// The index of the kernel data GDT entry. | ||||
| const KERNEL_DATA_INDEX: u16    = 0x02; | ||||
| 
 | ||||
| /// The index of the user code GDT entry. | ||||
| const USER_CODE_INDEX: u16      = 0x03; | ||||
| 
 | ||||
| /// The index of the user data GDT entry. | ||||
| const USER_DATA_INDEX: u16      = 0x04; | ||||
| 
 | ||||
| /// The index of the task state segment GDT entry. | ||||
| const TSS_INDEX: u16            = 0x05; | ||||
| 
 | ||||
| 
 | ||||
| // The offsets into the GDT where each segment resides. | ||||
| 
 | ||||
| /// The offset of the NULL GDT entry. | ||||
| pub const NULL_OFFSET: u16          = 0x00; | ||||
| 
 | ||||
| /// The offset of the kernel code GDT entry. | ||||
| pub const KERNEL_CODE_OFFSET: u16   = 0x08; | ||||
| 
 | ||||
| /// The offset of the kernel data GDT entry. | ||||
| pub const KERNEL_DATA_OFFSET: u16   = 0x10; | ||||
| 
 | ||||
| /// The offset of the user code GDT entry. | ||||
| pub const USER_CODE_OFFSET: u16     = 0x18; | ||||
| 
 | ||||
| /// The offset of the user data GDT entry. | ||||
| pub const USER_DATA_OFFSET: u16     = 0x20; | ||||
| 
 | ||||
| /// The offset of the TTS GDT entry. | ||||
| pub const TSS_OFFSET: u16           = 0x28; | ||||
| 
 | ||||
| // The access bits | ||||
| const ACCESSED_BIT              = 0x01; // 00000001 | ||||
| const WRITABLE_BIT              = 0x02; // 00000010 | ||||
| const DIRECTION_CONFORMING_BIT  = 0x04; // 00000100 | ||||
| const EXECUTABLE_BIT            =  0x08; // 00001000 | ||||
| const DESCRIPTOR_BIT            =  0x10; // 00010000 | ||||
| 
 | ||||
| const PRIVILEGE_RING_0          = 0x00; // 00000000 | ||||
| const PRIVILEGE_RING_1          = 0x20; // 00100000 | ||||
| const PRIVILEGE_RING_2          = 0x40; // 01000000 | ||||
| const PRIVILEGE_RING_3          = 0x60; // 01100000 | ||||
| 
 | ||||
| const PRESENT_BIT               = 0x80; // 10000000 | ||||
| 
 | ||||
| 
 | ||||
| const KERNEL_SEGMENT = PRESENT_BIT | PRIVILEGE_RING_0 | DESCRIPTOR_BIT; | ||||
| const USER_SEGMENT = PRESENT_BIT | PRIVILEGE_RING_3 | DESCRIPTOR_BIT; | ||||
| 
 | ||||
| const CODE_SEGMENT = EXECUTABLE_BIT | WRITABLE_BIT; | ||||
| const DATA_SEGMENT = WRITABLE_BIT; | ||||
| 
 | ||||
| const TSS_SEGMENT = PRESENT_BIT | EXECUTABLE_BIT | ACCESSED_BIT; | ||||
| 
 | ||||
| 
 | ||||
| // The flag bits | ||||
| const IS_64_BIT         = 0x02; // 0010 | ||||
| const IS_32_BIT         = 0x04; // 0100 | ||||
| const IS_LIMIT_4K_BIT   = 0x08; // 1000 | ||||
| 
 | ||||
| /// The structure that contains all the information that each GDT entry needs. | ||||
| const GdtEntry = packed struct { | ||||
|     /// The lower 16 bits of the limit address. Describes the size of memory that can be addressed. | ||||
|     limit_low: u16, | ||||
| 
 | ||||
|     /// The lower 24 bits of the base address. Describes the start of memory for the entry. | ||||
|     base_low: u24, | ||||
| 
 | ||||
|     /// Bit 0   : accessed             - The CPU will set this when the GDT entry is accessed. | ||||
|     /// Bit 1   : writable             - The writable bit to say if the memory region is writable. If set, then memory region is readable and writable. If not set, then the memory region is just readable. | ||||
|     /// Bit 2   : direction_conforming - For a code segment: if set (1), then the code segment can be executed from a lower ring level. If unset (0), then the code segment can only be executed from the same ring level in the privilege flag. For the data segment: if set (1), then the data segment grows downwards. If unset (0), then the data segment grows upwards. | ||||
|     /// Bit 3   : executable           - The execution bit to say that the memory region is executable. | ||||
|     /// Bit 4   : descriptor_bit       - The descriptor bit. | ||||
|     /// Bit 5-6 : privilege            - The ring level of the memory region. | ||||
|     /// Bit 7   : present              - The present bit to tell that this GDT entry is present. | ||||
|     access: u8, | ||||
| 
 | ||||
|     /// The upper 4 bits of the limit address. Describes the size of memory that can be addressed. | ||||
|     limit_high: u4, | ||||
| 
 | ||||
|     /// Bit 0 : reserved_zero - This must always be zero. | ||||
|     /// Bit 1 : is_64bits     - Whether this is a 64 bit system. | ||||
|     /// Bit 2 : is_32bits     - Whether this is a 32 bit system. | ||||
|     /// Bit 3 : is_limit_4K   - Whether paging is turned on, and each address is addressed as if it is a page number not physical/logical linear address. | ||||
|     flags: u4, | ||||
| 
 | ||||
|     /// The upper 8 bits of the base address. Describes the start of memory for the entry. | ||||
|     base_high: u8, | ||||
| }; | ||||
| 
 | ||||
| /// The GDT pointer structure that contains the pointer to the beginning of the GDT and the number | ||||
| /// of the table (minus 1). Used to load the GDT with LGDT instruction. | ||||
| pub const GdtPtr = packed struct { | ||||
|     /// 16bit entry for the number of entries (minus 1). | ||||
|     limit: u16, | ||||
| 
 | ||||
|     /// 32bit entry for the base address for the GDT. | ||||
|     base: *GdtEntry, | ||||
| }; | ||||
| 
 | ||||
| const TtsEntry = packed struct { | ||||
|     /// Pointer to the previous TSS entry | ||||
|     prev_tss: u32, | ||||
| 
 | ||||
|     /// Ring 0 32 bit stack pointer. | ||||
|     esp0: u32, | ||||
| 
 | ||||
|     /// Ring 0 32 bit stack pointer. | ||||
|     ss0: u32, | ||||
| 
 | ||||
|     /// Ring 1 32 bit stack pointer. | ||||
|     esp1: u32, | ||||
| 
 | ||||
|     /// Ring 1 32 bit stack pointer. | ||||
|     ss1: u32, | ||||
| 
 | ||||
|     /// Ring 2 32 bit stack pointer. | ||||
|     esp2: u32, | ||||
| 
 | ||||
|     /// Ring 2 32 bit stack pointer. | ||||
|     ss2: u32, | ||||
| 
 | ||||
|     /// The CR3 control register 3. | ||||
|     cr3: u32, | ||||
| 
 | ||||
|     /// 32 bit instruction pointer. | ||||
|     eip: u32, | ||||
| 
 | ||||
|     /// 32 bit flags register. | ||||
|     eflags: u32, | ||||
| 
 | ||||
|     /// 32 bit accumulator register. | ||||
|     eax: u32, | ||||
| 
 | ||||
|     /// 32 bit counter register. | ||||
|     ecx: u32, | ||||
| 
 | ||||
|     /// 32 bit data register. | ||||
|     edx: u32, | ||||
| 
 | ||||
|     /// 32 bit base register. | ||||
|     ebx: u32, | ||||
| 
 | ||||
|     /// 32 bit stack pointer register. | ||||
|     esp: u32, | ||||
| 
 | ||||
|     /// 32 bit base pointer register. | ||||
|     ebp: u32, | ||||
| 
 | ||||
|     /// 32 bit source register. | ||||
|     esi: u32, | ||||
| 
 | ||||
|     /// 32 bit destination register. | ||||
|     edi: u32, | ||||
| 
 | ||||
|     /// The extra segment. | ||||
|     es: u32, | ||||
| 
 | ||||
|     /// The code segment. | ||||
|     cs: u32, | ||||
| 
 | ||||
|     /// The stack segment. | ||||
|     ss: u32, | ||||
| 
 | ||||
|     /// The data segment. | ||||
|     ds: u32, | ||||
| 
 | ||||
|     /// A extra segment FS. | ||||
|     fs: u32, | ||||
| 
 | ||||
|     /// A extra segment GS. | ||||
|     gs: u32, | ||||
| 
 | ||||
|     /// The local descriptor table register. | ||||
|     ldtr: u32, | ||||
| 
 | ||||
|     /// ? | ||||
|     trap: u16, | ||||
| 
 | ||||
|     /// A pointer to a I/O port bitmap for the current task which specifies individual ports the program should have access to. | ||||
|     io_permissions_base_offset: u16, | ||||
| }; | ||||
| 
 | ||||
| /// | ||||
| /// Make a GDT entry. | ||||
| /// | ||||
| /// Arguments: | ||||
| ///     IN access: u8 - The access bits for the descriptor. | ||||
| ///     IN flags: u4  - The flag bits for the descriptor. | ||||
| /// | ||||
| /// Return: | ||||
| ///     A new GDT entry with the give access and flag bits set with the base at 0x00000000 and limit at 0xFFFFF. | ||||
| /// | ||||
| fn makeEntry(base: u32, limit: u20, access: u8, flags: u4) GdtEntry { | ||||
|     return GdtEntry { | ||||
|         .limit_low = @truncate(u16, limit), | ||||
|         .base_low = @truncate(u24, base), | ||||
|         .access = access, | ||||
|         .limit_high = @truncate(u4, limit >> 16), | ||||
|         .flags = flags, | ||||
|         .base_high = @truncate(u8, base >> 24), | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| /// The GDT entry table of NUMBER_OF_ENTRIES entries. | ||||
| var gdt_entries: [NUMBER_OF_ENTRIES]GdtEntry = []GdtEntry { | ||||
|     // Null descriptor | ||||
|     makeEntry(0, 0, 0, 0), | ||||
| 
 | ||||
|     // Kernel Code | ||||
|     makeEntry(0, 0xFFFFF, KERNEL_SEGMENT | CODE_SEGMENT, IS_32_BIT | IS_LIMIT_4K_BIT), | ||||
| 
 | ||||
|     // Kernel Data | ||||
|     makeEntry(0, 0xFFFFF, KERNEL_SEGMENT | DATA_SEGMENT, IS_32_BIT | IS_LIMIT_4K_BIT), | ||||
| 
 | ||||
|     // User Code | ||||
|     makeEntry(0, 0xFFFFF, USER_SEGMENT | CODE_SEGMENT, IS_32_BIT | IS_LIMIT_4K_BIT), | ||||
| 
 | ||||
|     // User Data | ||||
|     makeEntry(0, 0xFFFFF, USER_SEGMENT | DATA_SEGMENT, IS_32_BIT | IS_LIMIT_4K_BIT), | ||||
| 
 | ||||
|     // Fill in TSS at runtime | ||||
|     makeEntry(0, 0, 0, 0), | ||||
| }; | ||||
| 
 | ||||
| /// The GDT pointer that the CPU is loaded with that contains the base address of the GDT and the size. | ||||
| const gdt_ptr: GdtPtr = GdtPtr { | ||||
|     .limit = TABLE_SIZE, | ||||
|     .base = &gdt_entries[0], | ||||
| }; | ||||
| 
 | ||||
| /// The task state segment entry. | ||||
| var tss: TtsEntry = TtsEntry { | ||||
|     .prev_tss = 0, | ||||
|     .esp0 = undefined, | ||||
|     .ss0 = KERNEL_DATA_OFFSET, | ||||
|     .esp1 = 0, | ||||
|     .ss1 = 0, | ||||
|     .esp2 = 0, | ||||
|     .ss2 = 0, | ||||
|     .cr3 = 0, | ||||
|     .eip = 0, | ||||
|     .eflags = 0, | ||||
|     .eax = 0, | ||||
|     .ecx = 0, | ||||
|     .edx = 0, | ||||
|     .ebx = 0, | ||||
|     .esp = 0, | ||||
|     .ebp = 0, | ||||
|     .esi = 0, | ||||
|     .edi = 0, | ||||
|     .es = 0, | ||||
|     .cs = 0, | ||||
|     .ss = 0, | ||||
|     .ds = 0, | ||||
|     .fs = 0, | ||||
|     .gs = 0, | ||||
|     .ldtr = 0, | ||||
|     .trap = 0, | ||||
|     .io_permissions_base_offset = @sizeOf(TtsEntry), | ||||
| }; | ||||
| 
 | ||||
| pub fn setTssStack(esp0: u32) void { | ||||
|     tss.esp0 = esp0; | ||||
| } | ||||
| 
 | ||||
| pub fn init() void { | ||||
|     // Initiate TSS | ||||
|     gdt_entries[TSS_INDEX] = makeEntry(@ptrToInt(&tss), @sizeOf(TtsEntry) - 1, TSS_SEGMENT, 0); | ||||
| 
 | ||||
|     // Load the GDT | ||||
|     arch.lgdt(&gdt_ptr); | ||||
| 
 | ||||
|     // Load the TSS | ||||
|     arch.ltr(); | ||||
| } | ||||
							
								
								
									
										85
									
								
								src/kernel/arch/x86/idt.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/kernel/arch/x86/idt.zig
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | |||
| // Zig version: 0.4.0 | ||||
| 
 | ||||
| const gdt = @import("gdt.zig"); | ||||
| const arch = @import("arch.zig"); | ||||
| 
 | ||||
| const NUMBER_OF_ENTRIES: u16 = 256; | ||||
| const TABLE_SIZE: u16 = @sizeOf(IdtEntry) * NUMBER_OF_ENTRIES - 1; | ||||
| 
 | ||||
| // The different gate types | ||||
| const TASK_GATE_32BIT: u4 = 0x5; | ||||
| const INTERRUPT_GATE_16BIT: u4 = 0x6; | ||||
| const TRAP_GATE_16BIT: u4 = 0x7; | ||||
| const INTERRUPT_GATE_32BIT: u4 = 0xE; | ||||
| const TRAP_GATE_32BIT: u4 = 0xF; | ||||
| 
 | ||||
| const PRIVILEGE_RING_0: u2 = 0x0; | ||||
| const PRIVILEGE_RING_1: u2 = 0x1; | ||||
| const PRIVILEGE_RING_2: u2 = 0x2; | ||||
| const PRIVILEGE_RING_3: u2 = 0x3; | ||||
| 
 | ||||
| const IdtEntry = packed struct { | ||||
|     /// The lower 16 bits of the base address of the interrupt handler offset. | ||||
|     base_low: u16, | ||||
| 
 | ||||
|     /// The code segment in the GDT which the handlers will be held. | ||||
|     selector: u16, | ||||
| 
 | ||||
|     /// Must be zero, unused. | ||||
|     zero: u8, | ||||
| 
 | ||||
|     /// The IDT gate type. | ||||
|     gate_type: u4, | ||||
| 
 | ||||
|     /// Must be 0 for interrupt and trap gates. | ||||
|     storage_segment: u1, | ||||
| 
 | ||||
|     /// The minimum ring level that the calling code must have to run the handler. So user code may not be able to run some interrupts. | ||||
|     privilege: u2, | ||||
| 
 | ||||
|     /// Whether the IDT entry is present. | ||||
|     present: u1, | ||||
| 
 | ||||
|     /// The upper 16 bits of the base address of the interrupt handler offset. | ||||
|     base_high: u16, | ||||
| }; | ||||
| 
 | ||||
| pub const IdtPtr = packed struct { | ||||
|     /// The total size of the IDT (minus 1) in bytes. | ||||
|     limit: u16, | ||||
| 
 | ||||
|     /// The base address where the IDT is located. | ||||
|     base: *IdtEntry, | ||||
| }; | ||||
| 
 | ||||
| var idt: [NUMBER_OF_ENTRIES]IdtEntry = []IdtEntry{makeEntry(0, 0, 0, 0, 0)} ** NUMBER_OF_ENTRIES; | ||||
| 
 | ||||
| const idt_ptr: IdtPtr = IdtPtr { | ||||
|     .limit = TABLE_SIZE, | ||||
|     .base = &idt[0], | ||||
| }; | ||||
| 
 | ||||
| fn makeEntry(base: u32, selector: u16, gate_type: u4, privilege: u2, present: u1) IdtEntry { | ||||
|     return IdtEntry { | ||||
|         .base_low = @truncate(u16, base), | ||||
|         .selector = selector, | ||||
|         .zero = 0, | ||||
|         .gate_type = gate_type, | ||||
|         .storage_segment = 0, | ||||
|         .privilege = privilege, | ||||
|         .present = present, | ||||
|         .base_high = @truncate(u16, base >> 16), | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| pub fn openInterruptGate(index: u8, base: extern fn()void) void { | ||||
|     idt[index] = makeEntry(@ptrToInt(base), gdt.KERNEL_CODE_OFFSET, INTERRUPT_GATE_32BIT, PRIVILEGE_RING_0, 1); | ||||
| } | ||||
| 
 | ||||
| pub fn closeInterruptGate(index: u8) void { | ||||
|     idt[index] = makeEntry(0, 0, 0, 0, 0); | ||||
| } | ||||
| 
 | ||||
| pub fn init() void { | ||||
|     arch.lidt(&idt_ptr); | ||||
| } | ||||
							
								
								
									
										155
									
								
								src/kernel/arch/x86/irq.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/kernel/arch/x86/irq.zig
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,155 @@ | |||
| // Zig version: 0.4.0 | ||||
| 
 | ||||
| const panic = @import("../../panic.zig"); | ||||
| const tty = @import("../../tty.zig"); | ||||
| const idt = @import("idt.zig"); | ||||
| const arch = @import("arch.zig"); | ||||
| 
 | ||||
| const NUMBER_OF_ENTRIES: u16 = 16; | ||||
| 
 | ||||
| const IRQ_OFFSET: u16 = 32; | ||||
| 
 | ||||
| extern fn irq0() void; | ||||
| extern fn irq1() void; | ||||
| extern fn irq2() void; | ||||
| extern fn irq3() void; | ||||
| extern fn irq4() void; | ||||
| extern fn irq5() void; | ||||
| extern fn irq6() void; | ||||
| extern fn irq7() void; | ||||
| extern fn irq8() void; | ||||
| extern fn irq9() void; | ||||
| extern fn irq10() void; | ||||
| extern fn irq11() void; | ||||
| extern fn irq12() void; | ||||
| extern fn irq13() void; | ||||
| extern fn irq14() void; | ||||
| extern fn irq15() void; | ||||
| 
 | ||||
| // Keep track of the number of spurious irq's | ||||
| var spurious_irq_counter: u32 = 0; | ||||
| 
 | ||||
| var irq_handlers: [NUMBER_OF_ENTRIES]fn(*arch.InterruptContext)void = []fn(*arch.InterruptContext)void {unhandled} ** NUMBER_OF_ENTRIES; | ||||
| 
 | ||||
| fn unhandled(context: *arch.InterruptContext) void { | ||||
|     const interrupt_num: u8 = @truncate(u8, context.int_num - IRQ_OFFSET); | ||||
|     panic.panicFmt(null, "Unhandled IRQ number {}", interrupt_num); | ||||
| } | ||||
| 
 | ||||
| // TODO Move to PIC | ||||
| fn sendEndOfInterrupt(irq_num: u8) void { | ||||
|     if (irq_num >= 8) { | ||||
|         arch.outb(0xA0, 0x20); | ||||
|     } | ||||
| 
 | ||||
|     arch.outb(0x20, 0x20); | ||||
| } | ||||
| 
 | ||||
| // TODO Move to PIC | ||||
| fn spuriousIrq(irq_num: u8) bool { | ||||
|     // Only for IRQ 7 and 15 | ||||
|     if(irq_num == 7) { | ||||
|         // Read master ISR | ||||
|         arch.outb(0x20, 0x0B); | ||||
|         const in_service = arch.inb(0x21); | ||||
|         // Check the MSB is zero, if so, then is a spurious irq | ||||
|         if ((in_service & 0x80) == 0) { | ||||
|             spurious_irq_counter += 1; | ||||
|             return true; | ||||
|         } | ||||
|     } else if (irq_num == 15) { | ||||
|         // Read slave ISR | ||||
|         arch.outb(0xA0, 0x0B); | ||||
|         const in_service = arch.inb(0xA1); | ||||
|         // Check the MSB is zero, if so, then is a spurious irq | ||||
|         if ((in_service & 0x80) == 0) { | ||||
|             // Need to send EOI to the master | ||||
|             arch.outb(0x20, 0x20); | ||||
|             spurious_irq_counter += 1; | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| export fn irqHandler(context: *arch.InterruptContext) void { | ||||
|     const irq_num: u8 = @truncate(u8, context.int_num - IRQ_OFFSET); | ||||
|     // Make sure it isn't a spurious irq | ||||
|     if (!spuriousIrq(irq_num)) { | ||||
|         irq_handlers[irq_num](context); | ||||
|         // Send the end of interrupt command | ||||
|         sendEndOfInterrupt(irq_num); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn registerIrq(irq_num: u16, handler: fn(*arch.InterruptContext)void) void { | ||||
|     irq_handlers[irq_num] = handler; | ||||
|     clearMask(irq_num); | ||||
| } | ||||
| 
 | ||||
| pub fn unregisterIrq(irq_num: u16) void { | ||||
|     irq_handlers[irq_num] = unhandled; | ||||
|     setMask(irq_num); | ||||
| } | ||||
| 
 | ||||
| pub fn setMask(irq_num: u16) void { | ||||
|     // TODO Change to PIC constants | ||||
|     const port: u16 = if (irq_num < 8) 0x20 else 0xA0; | ||||
|     const value = arch.inb(port) | (1 << irq_num); | ||||
|     arch.outb(port, value); | ||||
| } | ||||
| 
 | ||||
| pub fn clearMask(irq_num: u16) void { | ||||
|     // TODO Change to PIC constants | ||||
|     const port: u16 = if (irq_num < 8) 0x20 else 0xA0; | ||||
|     const value = arch.inb(port) & ~(1 << irq_num); | ||||
|     arch.outb(port, value); | ||||
| } | ||||
| 
 | ||||
| // TODO Move this to the PIC once got one | ||||
| fn remapIrq() void { | ||||
|     // Initiate | ||||
|     arch.outb(0x20, 0x11); | ||||
|     arch.outb(0xA0, 0x11); | ||||
| 
 | ||||
|     // Offsets | ||||
|     arch.outb(0x21, IRQ_OFFSET); | ||||
|     arch.outb(0xA1, IRQ_OFFSET + 8); | ||||
| 
 | ||||
|     // IRQ lines | ||||
|     arch.outb(0x21, 0x04); | ||||
|     arch.outb(0xA1, 0x02); | ||||
| 
 | ||||
|     // 80x86 mode | ||||
|     arch.outb(0x21, 0x01); | ||||
|     arch.outb(0xA1, 0x01); | ||||
| 
 | ||||
|     // Mask | ||||
|     arch.outb(0x21, 0xFF); | ||||
|     arch.outb(0xA1, 0xFF); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| pub fn init() void { | ||||
|     // Remap the PIC IRQ so not to overlap with other exceptions | ||||
|     remapIrq(); | ||||
| 
 | ||||
|     // Open all the IRQ's | ||||
|     idt.openInterruptGate(32, irq0); | ||||
|     idt.openInterruptGate(33, irq1); | ||||
|     idt.openInterruptGate(34, irq2); | ||||
|     idt.openInterruptGate(35, irq3); | ||||
|     idt.openInterruptGate(36, irq4); | ||||
|     idt.openInterruptGate(37, irq5); | ||||
|     idt.openInterruptGate(38, irq6); | ||||
|     idt.openInterruptGate(39, irq7); | ||||
|     idt.openInterruptGate(40, irq8); | ||||
|     idt.openInterruptGate(41, irq9); | ||||
|     idt.openInterruptGate(42, irq10); | ||||
|     idt.openInterruptGate(43, irq11); | ||||
|     idt.openInterruptGate(44, irq12); | ||||
|     idt.openInterruptGate(45, irq13); | ||||
|     idt.openInterruptGate(46, irq14); | ||||
|     idt.openInterruptGate(47, irq15); | ||||
| } | ||||
							
								
								
									
										70
									
								
								src/kernel/arch/x86/irq_asm.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/kernel/arch/x86/irq_asm.s
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| .macro irqGenerator n | ||||
|     .align 4
 | ||||
|     .type irq\n, @function
 | ||||
|     .global irq\n | ||||
|     irq\n: | ||||
|         cli | ||||
|         push $0 | ||||
|         push $\n+32 | ||||
|         jmp irqCommonStub | ||||
| .endmacro | ||||
| 
 | ||||
| irqCommonStub: | ||||
|     // Push all the registers | ||||
|     pusha | ||||
| 
 | ||||
|     // Push the additional segment regiters | ||||
|     push    %ds | ||||
|     push    %es | ||||
|     push    %fs | ||||
|     push    %gs | ||||
| 
 | ||||
|     // Set the kernel data segment | ||||
|     mov     $0x10, %ax | ||||
|     mov     %ax, %ds | ||||
|     mov     %ax, %es | ||||
|     mov     %ax, %fs | ||||
|     mov     %ax, %gs | ||||
| 
 | ||||
|     // Push the stack, this is where all the registers are sported, points the interuptContect | ||||
|     mov     %esp, %eax | ||||
|     push    %eax | ||||
| 
 | ||||
|     // Call the handler | ||||
|     call irqHandler | ||||
| 
 | ||||
|     // Pop stack pointer to point to the registers pushed | ||||
|     pop     %eax | ||||
| 
 | ||||
|     // Pop segment regiters inorder | ||||
|     pop     %gs | ||||
|     pop     %fs | ||||
|     pop     %es | ||||
|     pop     %ds | ||||
| 
 | ||||
|     // Pop all general registers | ||||
|     popa | ||||
| 
 | ||||
|     // Pop the error code and interrupt number | ||||
|     add     $0x8, %esp | ||||
| 
 | ||||
|     // Pops 5 things at once: cs, eip, eflags, ss, and esp | ||||
|     iret | ||||
| .type irqCommonStub, @function
 | ||||
| 
 | ||||
| irqGenerator 0 | ||||
| irqGenerator 1 | ||||
| irqGenerator 2 | ||||
| irqGenerator 3 | ||||
| irqGenerator 4 | ||||
| irqGenerator 5 | ||||
| irqGenerator 6 | ||||
| irqGenerator 7 | ||||
| irqGenerator 8 | ||||
| irqGenerator 9 | ||||
| irqGenerator 10 | ||||
| irqGenerator 11 | ||||
| irqGenerator 12 | ||||
| irqGenerator 13 | ||||
| irqGenerator 14 | ||||
| irqGenerator 15 | ||||
							
								
								
									
										131
									
								
								src/kernel/arch/x86/isr.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/kernel/arch/x86/isr.zig
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,131 @@ | |||
| // Zig version: 0.4.0 | ||||
| 
 | ||||
| const panic = @import("../../panic.zig"); | ||||
| const tty = @import("../../tty.zig"); | ||||
| const idt = @import("idt.zig"); | ||||
| const arch = @import("arch.zig"); | ||||
| 
 | ||||
| const NUMBER_OF_ENTRIES: u16 = 32; | ||||
| 
 | ||||
| extern fn isr0() void; | ||||
| extern fn isr1() void; | ||||
| extern fn isr2() void; | ||||
| extern fn isr3() void; | ||||
| extern fn isr4() void; | ||||
| extern fn isr5() void; | ||||
| extern fn isr6() void; | ||||
| extern fn isr7() void; | ||||
| extern fn isr8() void; | ||||
| extern fn isr9() void; | ||||
| extern fn isr10() void; | ||||
| extern fn isr11() void; | ||||
| extern fn isr12() void; | ||||
| extern fn isr13() void; | ||||
| extern fn isr14() void; | ||||
| extern fn isr15() void; | ||||
| extern fn isr16() void; | ||||
| extern fn isr17() void; | ||||
| extern fn isr18() void; | ||||
| extern fn isr19() void; | ||||
| extern fn isr20() void; | ||||
| extern fn isr21() void; | ||||
| extern fn isr22() void; | ||||
| extern fn isr23() void; | ||||
| extern fn isr24() void; | ||||
| extern fn isr25() void; | ||||
| extern fn isr26() void; | ||||
| extern fn isr27() void; | ||||
| extern fn isr28() void; | ||||
| extern fn isr29() void; | ||||
| extern fn isr30() void; | ||||
| extern fn isr31() void; | ||||
| 
 | ||||
| const exception_msg: [NUMBER_OF_ENTRIES][]const u8 = [NUMBER_OF_ENTRIES][]const u8 { | ||||
|     "Divide By Zero", | ||||
|     "Single Step (Debugger)", | ||||
|     "Non Maskable Interrupt", | ||||
|     "Breakpoint (Debugger)", | ||||
|     "Overflow", | ||||
|     "Bound Range Exceeded", | ||||
|     "Invalid Opcode", | ||||
|     "No Coprocessor, Device Not Available", | ||||
|     "Double Fault", | ||||
|     "Coprocessor Segment Overrun", | ||||
|     "Invalid Task State Segment (TSS)", | ||||
|     "Segment Not Present", | ||||
|     "Stack Segment Overrun", | ||||
|     "General Protection Fault", | ||||
|     "Page Fault", | ||||
|     "Unknown Interrupt", | ||||
|     "x87 FPU Floating Point Error", | ||||
|     "Alignment Check", | ||||
|     "Machine Check", | ||||
|     "SIMD Floating Point", | ||||
|     "Virtualization", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Reserved", | ||||
|     "Security", | ||||
|     "Reserved" | ||||
| }; | ||||
| 
 | ||||
| var isr_handlers: [NUMBER_OF_ENTRIES]fn(*arch.InterruptContext)void = []fn(*arch.InterruptContext)void{unhandled} ** NUMBER_OF_ENTRIES; | ||||
| 
 | ||||
| fn unhandled(context: *arch.InterruptContext) void { | ||||
|     const interrupt_num = context.int_num; | ||||
|     panic.panicFmt(null, "Unhandled exception: {}, number {}", exception_msg[interrupt_num], interrupt_num); | ||||
| } | ||||
| 
 | ||||
| export fn isrHandler(context: *arch.InterruptContext) void { | ||||
|     const isr_num = context.int_num; | ||||
|     isr_handlers[isr_num](context); | ||||
| } | ||||
| 
 | ||||
| pub fn registerIsr(isr_num: u16, handler: fn(*arch.InterruptContext)void) void { | ||||
|     isr_handlers[isr_num] = handler; | ||||
| } | ||||
| 
 | ||||
| pub fn unregisterIsr(isr_num: u16) void { | ||||
|     isr_handlers[isr_num] = unhandled; | ||||
| } | ||||
| 
 | ||||
| pub fn init() void { | ||||
|     idt.openInterruptGate(0, isr0); | ||||
|     idt.openInterruptGate(1, isr1); | ||||
|     idt.openInterruptGate(2, isr2); | ||||
|     idt.openInterruptGate(3, isr3); | ||||
|     idt.openInterruptGate(4, isr4); | ||||
|     idt.openInterruptGate(5, isr5); | ||||
|     idt.openInterruptGate(6, isr6); | ||||
|     idt.openInterruptGate(7, isr7); | ||||
|     idt.openInterruptGate(8, isr8); | ||||
|     idt.openInterruptGate(9, isr9); | ||||
|     idt.openInterruptGate(10, isr10); | ||||
|     idt.openInterruptGate(11, isr11); | ||||
|     idt.openInterruptGate(12, isr12); | ||||
|     idt.openInterruptGate(13, isr13); | ||||
|     idt.openInterruptGate(14, isr14); | ||||
|     idt.openInterruptGate(15, isr15); | ||||
|     idt.openInterruptGate(16, isr16); | ||||
|     idt.openInterruptGate(17, isr17); | ||||
|     idt.openInterruptGate(18, isr18); | ||||
|     idt.openInterruptGate(19, isr19); | ||||
|     idt.openInterruptGate(20, isr20); | ||||
|     idt.openInterruptGate(21, isr21); | ||||
|     idt.openInterruptGate(22, isr22); | ||||
|     idt.openInterruptGate(23, isr23); | ||||
|     idt.openInterruptGate(24, isr24); | ||||
|     idt.openInterruptGate(25, isr25); | ||||
|     idt.openInterruptGate(26, isr26); | ||||
|     idt.openInterruptGate(27, isr27); | ||||
|     idt.openInterruptGate(28, isr28); | ||||
|     idt.openInterruptGate(29, isr29); | ||||
|     idt.openInterruptGate(30, isr30); | ||||
|     idt.openInterruptGate(31, isr31); | ||||
| } | ||||
							
								
								
									
										89
									
								
								src/kernel/arch/x86/isr_asm.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/kernel/arch/x86/isr_asm.s
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,89 @@ | |||
| .macro isrGenerator n | ||||
|     .align 4
 | ||||
|     .type isr\n, @function
 | ||||
|     .global isr\n | ||||
|     isr\n: | ||||
|         cli | ||||
|         // Push 0 if there is no interrupt error code | ||||
|         .if (\n != 8 && !(\n >= 10 && \n <= 14) && \n != 17) | ||||
|             push $0 | ||||
|         .endif | ||||
|         push $\n | ||||
|         jmp isrCommonStub | ||||
| .endmacro | ||||
| 
 | ||||
| isrCommonStub: | ||||
|     // Push all the registers | ||||
|     pusha | ||||
| 
 | ||||
|     // Push the additional segment regiters | ||||
|     push    %ds | ||||
|     push    %es | ||||
|     push    %fs | ||||
|     push    %gs | ||||
| 
 | ||||
|     // Set the kernel data segment | ||||
|     mov     $0x10, %ax | ||||
|     mov     %ax, %ds | ||||
|     mov     %ax, %es | ||||
|     mov     %ax, %fs | ||||
|     mov     %ax, %gs | ||||
| 
 | ||||
|     // Push the stack, this is where all the registers are sported, points the interuptContect | ||||
|     mov     %esp, %eax | ||||
|     push    %eax | ||||
| 
 | ||||
|     // Call the handler | ||||
|     call isrHandler | ||||
| 
 | ||||
|     // Pop stack pointer to point to the registers pushed | ||||
|     pop     %eax | ||||
| 
 | ||||
|     // Pop segment regiters inorder | ||||
|     pop     %gs | ||||
|     pop     %fs | ||||
|     pop     %es | ||||
|     pop     %ds | ||||
| 
 | ||||
|     // Pop all general registers | ||||
|     popa | ||||
| 
 | ||||
|     // Pop the error code and interrupt number | ||||
|     add     $0x8, %esp | ||||
| 
 | ||||
|     // Pops 5 things at once: cs, eip, eflags, ss, and esp | ||||
|     iret | ||||
| .type isrCommonStub, @function
 | ||||
| 
 | ||||
| isrGenerator 0 | ||||
| isrGenerator 1 | ||||
| isrGenerator 2 | ||||
| isrGenerator 3 | ||||
| isrGenerator 4 | ||||
| isrGenerator 5 | ||||
| isrGenerator 6 | ||||
| isrGenerator 7 | ||||
| isrGenerator 8 | ||||
| isrGenerator 9 | ||||
| isrGenerator 10 | ||||
| isrGenerator 11 | ||||
| isrGenerator 12 | ||||
| isrGenerator 13 | ||||
| isrGenerator 14 | ||||
| isrGenerator 15 | ||||
| isrGenerator 16 | ||||
| isrGenerator 17 | ||||
| isrGenerator 18 | ||||
| isrGenerator 19 | ||||
| isrGenerator 20 | ||||
| isrGenerator 21 | ||||
| isrGenerator 22 | ||||
| isrGenerator 23 | ||||
| isrGenerator 24 | ||||
| isrGenerator 25 | ||||
| isrGenerator 26 | ||||
| isrGenerator 27 | ||||
| isrGenerator 28 | ||||
| isrGenerator 29 | ||||
| isrGenerator 30 | ||||
| isrGenerator 31 | ||||
|  | @ -6,10 +6,15 @@ const multiboot = @import("multiboot.zig"); | |||
| const tty = @import("tty.zig"); | ||||
| const vga = @import("vga.zig"); | ||||
| 
 | ||||
| // Need to import this as we need the panic to be in the root source file, or zig will just use the | ||||
| // builtin panic and just loop, which is what we don't want | ||||
| const panic_root = @import("panic.zig"); | ||||
| 
 | ||||
| // Just call the panic function, as this need to be in the root source file | ||||
| pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { | ||||
|     @setCold(true); | ||||
|     tty.print("\nKERNEL PANIC: {}\n", msg); | ||||
|     while (true) {} | ||||
|     arch.disableInterrupts(); | ||||
|     panic_root.panicFmt(error_return_trace, "{}", msg); | ||||
| } | ||||
| 
 | ||||
| pub export fn kmain(mb_info: *multiboot.multiboot_info_t, mb_magic: u32) void { | ||||
|  | @ -18,6 +23,9 @@ pub export fn kmain(mb_info: *multiboot.multiboot_info_t, mb_magic: u32) void { | |||
|         arch.init(); | ||||
|         vga.init(); | ||||
|         tty.init(); | ||||
|         tty.print("\nHello Pluto from kernel :)\n"); | ||||
|         tty.print("Hello Pluto from kernel :)\n"); | ||||
| 
 | ||||
|         // Enable interrupts | ||||
|         arch.enableInterrupts(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										13
									
								
								src/kernel/panic.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/kernel/panic.zig
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| // Zig version: 0.4.0 | ||||
| 
 | ||||
| const builtin = @import("builtin"); | ||||
| const tty = @import("tty.zig"); | ||||
| const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") else @import("arch.zig").internals; | ||||
| 
 | ||||
| pub fn panicFmt(trace: ?*builtin.StackTrace, comptime format: []const u8, args: ...) noreturn { | ||||
|     @setCold(true); | ||||
|     tty.print("KERNEL PANIC\n"); | ||||
|     tty.print(format, args); | ||||
|     tty.print("\nHALTING\n"); | ||||
|     arch.haltNoInterrupts(); | ||||
| } | ||||
|  | @ -641,6 +641,7 @@ pub fn init() void { | |||
| 
 | ||||
|     printLogo(); | ||||
|     displayPageNumber(); | ||||
|     updateCursor(); | ||||
| } | ||||
| 
 | ||||
| fn resetGlobals() void { | ||||
|  |  | |||
|  | @ -14,7 +14,6 @@ const PORT_DATA: u16 = 0x03D5; | |||
| 
 | ||||
| // The indexes that is passed to the address port to select the register for the data to be | ||||
| // read or written to. | ||||
| 
 | ||||
| const REG_HORIZONTAL_TOTAL: u8                = 0x00; | ||||
| const REG_HORIZONTAL_DISPLAY_ENABLE_END: u8   = 0x01; | ||||
| const REG_START_HORIZONTAL_BLINKING: u8       = 0x02; | ||||
|  | @ -144,7 +143,7 @@ pub fn updateCursor(x: u16, y: u16) void { | |||
|     var pos_lower: u16 = undefined; | ||||
| 
 | ||||
|     // Make sure new cursor position is within the screen | ||||
|     if (x < HEIGHT and y < WIDTH) { | ||||
|     if (x < WIDTH and y < HEIGHT) { | ||||
|         pos = y * WIDTH + x; | ||||
|     } else { | ||||
|         // If not within the screen, then just put the cursor at the very end | ||||
|  | @ -240,8 +239,6 @@ pub fn init() void { | |||
| 
 | ||||
|     // Set by default the underline cursor | ||||
|     setCursorShape(CursorShape.UNDERLINE); | ||||
|     cursor_scanline_start = CURSOR_SCANLINE_MIDDLE; | ||||
|     cursor_scanline_end = CURSOR_SCANLINE_END; | ||||
| } | ||||
| 
 | ||||
| test "entryColour" { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Edward Dean
						Edward Dean