commit 86eeeaadbb2bf02bbf0095e1e915e69bea6db6e0 from: Murilo Ijanc date: Sun Feb 8 00:58:44 2026 UTC split port, serial and vga into modules, add gdt with tss commit - 650c79ed1d1a5f16ff3ad46e4a32c1a75d608124 commit + 86eeeaadbb2bf02bbf0095e1e915e69bea6db6e0 blob - /dev/null blob + d9319cf663549a05056320f2c6b8a9c2f3a1eb7a (mode 644) --- /dev/null +++ src/gdt.rs @@ -0,0 +1,169 @@ +// vim: set tw=79 cc=80 ts=4 sw=4 sts=4 et : +// +// Copyright (c) 2025-2026 Murilo Ijanc' +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +use core::arch::asm; + +// Segment selectors: index * 8 + RPL +pub const KERNEL_CODE: u16 = 0x08; // index 1, RPL 0 +pub const KERNEL_DATA: u16 = 0x10; // index 2, RPL 0 +pub const USER_DATA: u16 = 0x1B; // index 3, RPL 3 +pub const USER_CODE: u16 = 0x23; // index 4, RPL 3 +pub const TSS_SEL: u16 = 0x28; // index 5 + +// GDT with 7 entries (TSS uses 2 entries = 16 bytes): +// [0] null +// [1] kernel code 64-bit +// [2] kernel data +// [3] user data (DPL=3) +// [4] user code (DPL=3, 64-bit) +// [5-6] TSS (16-byte system descriptor) +// +// Order of user data before user code is required by +// sysret which computes: SS = STAR[63:48]+8, CS = STAR[63:48]+16 +#[repr(C, align(16))] +struct Gdt { + entries: [u64; 7], +} + +static mut GDT: Gdt = Gdt { + entries: [ + // [0] null + 0x0000000000000000, + // [1] kernel code: P=1 DPL=0 S=1 Type=1010 L=1 + 0x00AF9A000000FFFF, + // [2] kernel data: P=1 DPL=0 S=1 Type=0010 + 0x00CF92000000FFFF, + // [3] user data: P=1 DPL=3 S=1 Type=0010 + 0x00CFF2000000FFFF, + // [4] user code: P=1 DPL=3 S=1 Type=1010 L=1 + 0x00AFFA000000FFFF, + // [5-6] TSS: filled at runtime + 0, + 0, + ], +}; + +// TSS: only rsp0 matters for Ring3→Ring0 transition +#[repr(C, packed)] +pub struct Tss { + reserved0: u32, + pub rsp0: u64, + rsp1: u64, + rsp2: u64, + reserved1: u64, + ist: [u64; 7], + reserved2: u64, + reserved3: u16, + iopb_offset: u16, +} + +pub static mut TSS: Tss = Tss { + reserved0: 0, + rsp0: 0, + rsp1: 0, + rsp2: 0, + reserved1: 0, + ist: [0; 7], + reserved2: 0, + reserved3: 0, + iopb_offset: size_of::() as u16, +}; + +#[repr(C, packed)] +struct GdtPointer { + limit: u16, + base: u64, +} + +pub fn init() { + // Install TSS descriptor into GDT entries [5] and [6] + let tss_addr = unsafe { (&raw const TSS) as u64 }; + let tss_size = (size_of::() - 1) as u64; + + // TSS descriptor is 16 bytes (2 GDT entries): + // Low 8 bytes: + // bits 15:0 = limit 15:0 + // bits 31:16 = base 15:0 + // bits 39:32 = base 23:16 + // bits 43:40 = type (0x9 = available 64-bit TSS) + // bit 44 = 0 (system segment) + // bits 46:45 = DPL (0) + // bit 47 = P (1) + // bits 51:48 = limit 19:16 + // bits 55:52 = flags (0) + // bits 63:56 = base 31:24 + // High 8 bytes: + // bits 31:0 = base 63:32 + // bits 63:32 = reserved + let low: u64 = (tss_size & 0xFFFF) + | ((tss_addr & 0xFFFF) << 16) + | (((tss_addr >> 16) & 0xFF) << 32) + | (0x89u64 << 40) // P=1, DPL=0, type=9 + | (((tss_size >> 16) & 0xF) << 48) + | (((tss_addr >> 24) & 0xFF) << 56); + let high: u64 = tss_addr >> 32; + + unsafe { + GDT.entries[5] = low; + GDT.entries[6] = high; + } + + let ptr = GdtPointer { + limit: (size_of::() - 1) as u16, + base: (&raw const GDT) as u64, + }; + + unsafe { + asm!("lgdt [{}]", + in(reg) &ptr, + options(readonly, nostack)); + + // Reload data segments + asm!( + "mov ds, {0:x}", + "mov ss, {0:x}", + "mov es, {0:x}", + in(reg) KERNEL_DATA, + options(nostack), + ); + + // Reload CS via far return + asm!( + "push {sel}", + "lea {tmp}, [rip + 2f]", + "push {tmp}", + "retfq", + "2:", + sel = in(reg) KERNEL_CODE as u64, + tmp = lateout(reg) _, + ); + + // Load TSS + asm!("ltr {0:x}", + in(reg) TSS_SEL, + options(nostack)); + } +} + +/// Set the kernel stack pointer in the TSS. +/// Called during task switch to point to the current +/// task's kernel stack. +pub fn set_kernel_stack(rsp0: u64) { + unsafe { + TSS.rsp0 = rsp0; + } +} blob - /dev/null blob + 364527ea744f608b52cc96e7384d7d509a5500af (mode 644) --- /dev/null +++ src/port.rs @@ -0,0 +1,32 @@ +// vim: set tw=79 cc=80 ts=4 sw=4 sts=4 et : +// +// Copyright (c) 2025-2026 Murilo Ijanc' +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +use core::arch::asm; + +pub unsafe fn outb(port: u16, val: u8) { + unsafe { + asm!("out dx, al", in("dx") port, in("al") val); + } +} + +pub unsafe fn inb(port: u16) -> u8 { + let val: u8; + unsafe { + asm!("in al, dx", out("al") val, in("dx") port); + } + val +} blob - /dev/null blob + f15253162f4b2a0f2023ae7849abc638d09d38ef (mode 644) --- /dev/null +++ src/serial.rs @@ -0,0 +1,48 @@ +// vim: set tw=79 cc=80 ts=4 sw=4 sts=4 et : +// +// Copyright (c) 2025-2026 Murilo Ijanc' +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +use crate::port::{inb, outb}; + +const COM1: u16 = 0x3F8; + +pub fn init() { + unsafe { + outb(COM1 + 1, 0x00); + outb(COM1 + 3, 0x80); + outb(COM1 + 0, 0x03); + outb(COM1 + 1, 0x00); + outb(COM1 + 3, 0x03); + outb(COM1 + 2, 0xC7); + outb(COM1 + 4, 0x0B); + } +} + +pub fn putc(c: u8) { + while unsafe { inb(COM1 + 5) } & 0x20 == 0 {} + unsafe { + outb(COM1, c); + } +} + +pub fn print(s: &str) { + for b in s.bytes() { + if b == b'\n' { + putc(b'\r'); + } + putc(b); + } +} blob - /dev/null blob + 550361f9f9a0cb7faa313f49466386561a8bc713 (mode 644) --- /dev/null +++ src/vga.rs @@ -0,0 +1,28 @@ +// vim: set tw=79 cc=80 ts=4 sw=4 sts=4 et : +// +// Copyright (c) 2025-2026 Murilo Ijanc' +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +const VGA_BUFFER: usize = 0xb8000; + +pub fn write(s: &str, color: u8) { + let vga = VGA_BUFFER as *mut u16; + for (i, b) in s.bytes().enumerate() { + unsafe { + vga.add(i) + .write_volatile((color as u16) << 8 | b as u16); + } + } +}