compiles!

This commit is contained in:
fekhesk 2022-11-03 03:42:51 -07:00
parent 7319725700
commit 6405017b88
No known key found for this signature in database
GPG Key ID: 6B3D8CB511646891
24 changed files with 764 additions and 629 deletions

View File

@ -1,6 +1,10 @@
[target.ppc32-custom.json]
[target.powerpc-unknown-linux-gnu]
linker = "powerpc-unknown-linux-gnu-gcc"
ar = "powerpc-unknown-linux-gnu-ar"
#rustflags = [ "-C", "link-args=-nostdlib -ffreestanding -fPIC -Ttext 100000 -mbig-endian", "-C", "target-feature=+crt-static"]
# for some reason it wants a string
rustflags = "-C link-args='-nostdlib -ffreestanding -fPIC -Ttext 100000 -mbig-endian' -C target-feature=+crt-static"
rustflags = [
"-C", "link-args=-nostdlib -ffreestanding -fPIC -Ttext 100000 -mbig-endian",
"-C", "target-feature=+crt-static",
]
[build]
target = "powerpc-unknown-linux-gnu"

View File

@ -5,16 +5,16 @@ edition = "2021"
[dependencies]
spin = "0.9.1"
rlibc = "1.0"
pc-keyboard = "0.6.1"
cstr_core = { version = "0.2.6", features = ["alloc"] }
libfar = { git = "https://github.com/realmicrosoft/libfar_nostd" }
linked_list_allocator = { version = "0.9.0", optional = true }
rlibc = { version = "1.0" }
[dependencies.lazy_static]
version = "1.4.0"
features = ["spin_no_std"]
# x86_64 specific dependencies
# apic specific dependencies
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = "0.14.10"
x2apic = "0.4.1"
@ -23,10 +23,18 @@ limine = { version = "0.1.9", optional = true }
# powerpc (32) specific dependencies
[target.'cfg(target_arch = "powerpc")'.dependencies]
openfirmware-sys = { git = "https://github.com/realmicrosoft/openfirmware-sys.git" }
ieee1275 = { git = "https://github.com/rust-osdev/ieee1275-rs", features = ["no_panic_handler"] }
[features]
default = ["f_limine", "f_ll_alloc", "f_debug_verbose"]
default = ["f_ll_alloc", "f_debug_verbose"]
f_debug_verbose = []
f_limine = ["dep:limine", "dep:acpi"]
f_ll_alloc = ["dep:linked_list_allocator"]
f_ll_alloc = ["dep:linked_list_allocator"]
[profile.dev]
panic = "abort"
strip = true
[profile.release]
panic = "abort"
strip = true

View File

@ -1,12 +1,12 @@
arch ?= x86_64
kernel := target/$(arch)-custom/debug/wukkOS
iso := build/arch/$(arch)/wukkOS.iso
target ?= $(arch)-custom
kernel := target/$(target)/release/wukkOS
final := build/arch/$(arch)/wukkOS.bin
initwukko := byob/initwukko.far
initwukko_from := initwukko
efi_bios := build/arch/$(arch)/OVMF-pure-efi.fd
kernel_flags :=
KERNEL_FLAGS := -Zbuild-std=core,alloc
RUST_FLAGS :=
gcc ?= gcc
ld ?= ld
@ -20,9 +20,12 @@ assembly_object_files := $(patsubst arch/$(arch)/%.asm, \
ifeq "$(arch)" "x86_64"
kernel_flags += --features "f_limine"
KERNEL_FLAGS += --features "f_limine" --features "rlibc"
endif
ifeq "$(arch)" "ppc32"
target := powerpc-unknown-linux-gnu
kernel := target/$(target)/release/wukkOS
KERNEL_FLAGS :=
endif
.PHONY: all clean run iso quick_invalidate build_no_iso
@ -32,7 +35,7 @@ all: $(final) $(iso)
build_no_iso: $(final)
clean:
@xargo clean
@cargo clean
@rm -rf build
run: $(final) $(iso)
@ -68,7 +71,7 @@ $(final): $(kernel) $(linker_script) $(initwukko)
# --gc-sections
$(kernel):
@RUSTFLAGS="$(RUST_FLAGS)" RUST_TARGET_PATH="$(shell pwd)" cargo +nightly build --target $(target) -Zbuild-std=core,alloc $(kernel_flags)
@RUST_TARGET_PATH="$(shell pwd)" cargo +nightly build --release --target $(target) $(KERNEL_FLAGS)
$(initwukko):
@mkdir -p $(shell dirname $@)

View File

@ -9,8 +9,7 @@
"panic-strategy": "abort",
"pre-link-args": {
"ld.lld": [
"--gc-sections",
"--script=arch/ppc32/linker.ld"
"--gc-sections"
]
}
}

View File

@ -28,7 +28,7 @@ fn main() {
return;
}
let mut run_cmd = Command::new("qemu-system-x86_64");
let mut run_cmd = Command::new("qemu-system-apic");
run_cmd
.arg("-drive")
.arg(format!("format=raw,file={}", bios.display()));

View File

@ -1,108 +1,2 @@
use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::marker::PhantomData;
use core::ptr::NonNull;
use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping};
use acpi::platform::interrupt::InterruptSourceOverride;
use cstr_core::CString;
use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest, LimineSmpRequest, LimineModuleRequest};
use crate::{debug, println};
#[cfg(feature = "f_multiboot2")]
use multiboot2::{load, MemoryMapTag, BootInformation};
use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate};
use x86_64::VirtAddr;
use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32, VIRT_MEM_OFFSET};
use crate::serial::terminal::ST;
pub static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0);
pub static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0);
pub static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0);
pub static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0);
pub static KERNEL_ADDRESS: LimineKernelAddressRequest = LimineKernelAddressRequest::new(0);
pub static SMP_REQUEST: LimineSmpRequest = LimineSmpRequest::new(0);
pub static MOD_REQUEST: LimineModuleRequest = LimineModuleRequest::new(0);
#[derive(Clone)]
struct Handler;
impl AcpiHandler for Handler {
unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T> { // todo! check if size is too big
// only get lower 32 bits of physical address
let physical_address = physical_address as u32;
debug!("mapping physical region: {:x} - {:x}", physical_address, physical_address + size as u32);
let _ = read_phys_memory32(physical_address as u32) as usize;
PhysicalMapping::new(
physical_address as usize,
NonNull::new_unchecked(physical_address as *mut T),
size, size,
Self)
}
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
// get page
let page: Page<PageSize> = Page::containing_address(VirtAddr::new(region.physical_start() as u64));
// unmap page
let res = unsafe { MEM_MAPPER.lock().as_mut().unwrap().unmap(page) };
// it isn't *that* important if we don't unmap successfully at the moment, so just write a warning if we fail
if let Err(e) = res {
debug!("(THIS IS NORMAL) failed to unmap physical region: {:?}", e);
}
}
}
pub struct LimineWriter;
impl core::fmt::Write for LimineWriter {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
static mut CACHED: Option<&'static LimineTerminalResponse> = None;
unsafe {
if let Some(writer) = CACHED {
let terminal = &writer.terminals()[0];
writer.write().unwrap()(terminal, s);
} else {
let response = TERMINAL_REQUEST.get_response().get().unwrap();
let terminal = &response.terminals()[0];
let writer = response.write().unwrap();
writer(terminal, s);
CACHED = Some(response);
}
}
Ok(())
}
}
pub fn get_ioapic_info() -> (u32, Vec<InterruptSourceOverride>) {
let rsdp = RSDP_REQUEST.get_response().get().unwrap();
let rsdp_ptr = rsdp.address.get().unwrap() as *const u8;
let tables = unsafe { AcpiTables::from_rsdp(Handler, rsdp_ptr as usize).unwrap() };
let platform_info = tables.platform_info().expect("no platform info");
let interrupt_model = platform_info.interrupt_model;
let apic = match interrupt_model {
InterruptModel::Apic(apic) => apic,
_ => panic!("unsupported interrupt model"),
};
let ioapic = apic.io_apics.first().expect("no ioapic");
let address = ioapic.address;
let overrides = apic.interrupt_source_overrides;
(address, overrides)
}
pub fn get_initwukko() -> Vec<u8> {
let mut response = MOD_REQUEST.get_response().get_mut().unwrap();
let module = &response.modules()[0];
let path_cstr = module.path.as_ptr().unwrap();
let path = unsafe { CString::from_raw(path_cstr as *mut _) };
debug!("initwukko path: {}", path.to_str().unwrap());
let start = module.base.get().unwrap() as *const _ as usize;
let size = module.length as usize;
let end = start + size;
let mut data = Vec::new();
for i in start..end {
let byte = unsafe { *(i as *const u8) };
data.push(byte);
}
data
}
#[cfg(target_arch = "x86_64")]
pub mod x86_64;

106
src/boot/x86_64/mod.rs Normal file
View File

@ -0,0 +1,106 @@
use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::marker::PhantomData;
use core::ptr::NonNull;
use acpi::{AcpiHandler, AcpiTables, InterruptModel, PhysicalMapping};
use acpi::platform::interrupt::InterruptSourceOverride;
use cstr_core::CString;
use limine::{LimineBootInfoRequest, LimineKernelAddressRequest, LimineMemmapRequest, LimineTerminalRequest, LimineTerminalResponse, LimineRsdpRequest, LimineSmpRequest, LimineModuleRequest};
use crate::{debug, println};
use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, Translate};
use x86_64::VirtAddr;
use crate::memory::{BootInfoFrameAllocator, FRAME_ALLOC, MEM_MAPPER, PageSize, read_phys_memory32, VIRT_MEM_OFFSET};
use crate::serial::terminal::ST;
pub static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0);
pub static TERMINAL_REQUEST: LimineTerminalRequest = LimineTerminalRequest::new(0);
pub static MEM_MAP: LimineMemmapRequest = LimineMemmapRequest::new(0);
pub static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0);
pub static KERNEL_ADDRESS: LimineKernelAddressRequest = LimineKernelAddressRequest::new(0);
pub static SMP_REQUEST: LimineSmpRequest = LimineSmpRequest::new(0);
pub static MOD_REQUEST: LimineModuleRequest = LimineModuleRequest::new(0);
#[derive(Clone)]
struct Handler;
impl AcpiHandler for Handler {
unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T> { // todo! check if size is too big
// only get lower 32 bits of physical address
let physical_address = physical_address as u32;
debug!("mapping physical region: {:x} - {:x}", physical_address, physical_address + size as u32);
let _ = read_phys_memory32(physical_address as u32) as usize;
PhysicalMapping::new(
physical_address as usize,
NonNull::new_unchecked(physical_address as *mut T),
size, size,
Self)
}
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>) {
// get page
let page: Page<PageSize> = Page::containing_address(VirtAddr::new(region.physical_start() as u64));
// unmap page
let res = unsafe { MEM_MAPPER.lock().as_mut().unwrap().unmap(page) };
// it isn't *that* important if we don't unmap successfully at the moment, so just write a warning if we fail
if let Err(e) = res {
debug!("(THIS IS NORMAL) failed to unmap physical region: {:?}", e);
}
}
}
pub struct LimineWriter;
impl core::fmt::Write for LimineWriter {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
static mut CACHED: Option<&'static LimineTerminalResponse> = None;
unsafe {
if let Some(writer) = CACHED {
let terminal = &writer.terminals()[0];
writer.write().unwrap()(terminal, s);
} else {
let response = TERMINAL_REQUEST.get_response().get().unwrap();
let terminal = &response.terminals()[0];
let writer = response.write().unwrap();
writer(terminal, s);
CACHED = Some(response);
}
}
Ok(())
}
}
pub fn get_ioapic_info() -> (u32, Vec<InterruptSourceOverride>) {
let rsdp = RSDP_REQUEST.get_response().get().unwrap();
let rsdp_ptr = rsdp.address.get().unwrap() as *const u8;
let tables = unsafe { AcpiTables::from_rsdp(Handler, rsdp_ptr as usize).unwrap() };
let platform_info = tables.platform_info().expect("no platform info");
let interrupt_model = platform_info.interrupt_model;
let apic = match interrupt_model {
InterruptModel::Apic(apic) => apic,
_ => panic!("unsupported interrupt model"),
};
let ioapic = apic.io_apics.first().expect("no ioapic");
let address = ioapic.address;
let overrides = apic.interrupt_source_overrides;
(address, overrides)
}
pub fn get_initwukko() -> Vec<u8> {
let mut response = MOD_REQUEST.get_response().get_mut().unwrap();
let module = &response.modules()[0];
let path_cstr = module.path.as_ptr().unwrap();
let path = unsafe { CString::from_raw(path_cstr as *mut _) };
debug!("initwukko path: {}", path.to_str().unwrap());
let start = module.base.get().unwrap() as *const _ as usize;
let size = module.length as usize;
let end = start + size;
let mut data = Vec::new();
for i in start..end {
let byte = unsafe { *(i as *const u8) };
data.push(byte);
}
data
}

4
src/internals/cpu/mod.rs Normal file
View File

@ -0,0 +1,4 @@
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
#[cfg(target_arch = "powerpc")]
pub mod ppc32;

View File

@ -0,0 +1,25 @@
use ieee1275::PROM;
use spin::Mutex;
use lazy_static::lazy_static;
pub struct PromHandle {
pub prom: Option<PROM>,
}
unsafe impl Send for PromHandle {}
unsafe impl Sync for PromHandle {}
lazy_static!{
pub static ref PROMHNDL: Mutex<PromHandle> = Mutex::new(PromHandle {
prom: None,
});
}
impl PromHandle {
pub fn set_prom(&mut self, prom: PROM) {
self.prom = Some(prom);
}
pub fn get(&mut self) -> &mut PROM {
self.prom.as_mut().unwrap()
}
}

View File

@ -0,0 +1,161 @@
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor};
use x86_64::structures::tss::TaskStateSegment;
use x86_64::{PhysAddr, set_general_handler, VirtAddr};
use x86_64::registers::segmentation::{CS, Segment, SS};
use x86_64::structures::paging::Translate;
use spin::Mutex;
use crate::{internals, println};
use lazy_static::lazy_static;
pub mod apic;
lazy_static! {
static ref GDT: Mutex<GlobalDescriptorTable> = {
let mut gdt = GlobalDescriptorTable::new();
Mutex::new(gdt)
};
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
unsafe {
use internals::errors::unhandled;
set_general_handler!(&mut idt, unhandled);
idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception).set_stack_index(0);
idt.double_fault.set_handler_fn(internals::errors::double_fault).set_stack_index(0);
idt.page_fault.set_handler_fn(internals::errors::page_fault).set_stack_index(0);
idt[internals::cpu::x86_64::apic::TIMER_IRQ].set_handler_fn(internals::cpu::x86_64::apic::timer).set_stack_index(1);
idt[internals::cpu::x86_64::apic::ERROR_IRQ].set_handler_fn(internals::cpu::x86_64::apic::error).set_stack_index(1);
idt[internals::cpu::x86_64::apic::SPURIOUS_IRQ].set_handler_fn(internals::cpu::x86_64::apic::spurious).set_stack_index(1);
idt[internals::cpu::x86_64::apic::FALLBACK_KEYBOARD_IRQ].set_handler_fn(internals::cpu::x86_64::apic::keyboard_irq).set_stack_index(1);
}
idt
};
}
pub fn init() {
// temporarily disable interrupts
x86_64::instructions::interrupts::disable();
println!("debug: setup GDT");
// load TSS
static mut tss: TaskStateSegment = TaskStateSegment::new();
{
unsafe {
{
tss.interrupt_stack_table[0] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[1] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[2] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[3] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[4] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[5] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[6] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
}
{
tss.privilege_stack_table[0] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.privilege_stack_table[1] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.privilege_stack_table[2] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
}
// set word at offset 102 to 0x68 and last two bytes of the tss to 0xffff
// this is a hack to make the tss valid
let tss_ptr = &tss as *const TaskStateSegment as *mut u8;
unsafe {
*tss_ptr.add(102) = 0x68;
*tss_ptr.add(104) = 0xff;
*tss_ptr.add(105) = 0xff;
}
}
let kcs = GDT.lock().add_entry(Descriptor::kernel_code_segment());
let kds = GDT.lock().add_entry(Descriptor::kernel_data_segment());
let tsss = unsafe { GDT.lock().add_entry(Descriptor::tss_segment(&tss)) };
// load GDT
unsafe {
GDT.lock().load_unsafe();
}
println!("debug: GDT loaded");
// set code segment to kernel code segment
unsafe {
CS::set_reg(kcs);
}
println!("debug: CS set");
// set data segment to kernel data segment
unsafe {
SS::set_reg(kds);
}
println!("debug: SS set");
// load TSS
unsafe {
x86_64::instructions::tables::load_tss(tsss);
}
println!("debug: TSS loaded");
// load IDT
IDT.load();
println!("debug: IDT loaded");
// enable interrupts
x86_64::instructions::interrupts::enable();
}
}

View File

@ -1,5 +1,3 @@
pub mod errors;
pub mod interrupts;
pub mod cpu;
pub mod WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood {

View File

@ -1,7 +1,10 @@
use core::fmt;
use limine::LimineTerminalResponse;
use crate::boot::LimineWriter;
use crate::serial::terminal::ST;
use core::fmt::Write;
#[cfg(target_arch = "x86_64")]
use crate::boot::x86_64::LimineWriter;
use crate::internals::cpu::ppc32::PROMHNDL;
#[cfg(target_arch = "x86_64")]
use crate::serial::x86_64::terminal::ST;
#[macro_export]
macro_rules! print {
@ -21,25 +24,61 @@ macro_rules! debug {
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
use core::fmt::Write;
ST.writer.lock().write_fmt(args).unwrap();
#[cfg(target_arch = "powerpc")]
{
use core::fmt::Write;
use crate::internals::cpu::ppc32::PROMHNDL;
struct OFPrinter;
impl Write for OFPrinter {
fn write_str(&mut self, s: &str) -> fmt::Result {
unsafe { PROMHNDL.lock().get().write_line(s) };
Ok(())
}
}
OFPrinter.write_fmt(args).unwrap();
}
let mut limine_writer = LimineWriter;
limine_writer.write_fmt(args).unwrap();
#[cfg(target_arch = "apic")]
{
use core::fmt::Write;
ST.writer.lock().write_fmt(args).unwrap();
let mut limine_writer = LimineWriter;
limine_writer.write_fmt(args).unwrap();
}
}
#[doc(hidden)]
pub fn _debug(args: fmt::Arguments) {
use core::fmt::Write;
#[cfg(feature = "f_debug_verbose")]
#[cfg(target_arch = "powerpc")]
{
ST.log("[debug] ");
ST.writer.lock().write_fmt(args).unwrap();
ST.logln("");
use core::fmt::Write;
use crate::internals::cpu::ppc32::PROMHNDL;
struct OFPrinter;
impl Write for OFPrinter {
fn write_str(&mut self, s: &str) -> fmt::Result {
unsafe { PROMHNDL.lock().get().write_line(s) };
Ok(())
}
}
OFPrinter.write_str("[debug] ").unwrap();
OFPrinter.write_fmt(args).unwrap();
OFPrinter.write_str("\n").unwrap();
}
let mut limine_writer = LimineWriter;
limine_writer.write_str("[debug] ").unwrap();
limine_writer.write_fmt(args).unwrap();
limine_writer.write_str("\n").unwrap();
#[cfg(target_arch = "apic")]
{
use core::fmt::Write;
#[cfg(feature = "f_debug_verbose")]
{
ST.log("[debug] ");
ST.writer.lock().write_fmt(args).unwrap();
ST.logln("");
let mut limine_writer = LimineWriter;
limine_writer.write_str("[debug] ").unwrap();
limine_writer.write_fmt(args).unwrap();
limine_writer.write_str("\n").unwrap();
}
}
}

View File

@ -21,18 +21,8 @@ use lazy_static::lazy_static;
use core::panic::PanicInfo;
use libfar::farlib;
use libfar::farlib::{FarArchive, FarFileInfo};
use limine::{LimineBootInfoRequest, LimineMemmapRequest, LimineTerminalRequest};
use spin::Mutex;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor};
use x86_64::structures::tss::TaskStateSegment;
use x86_64::{PhysAddr, set_general_handler, VirtAddr};
use x86_64::registers::segmentation::{CS, Segment, SS};
use x86_64::structures::paging::Translate;
use crate::boot::{get_initwukko, get_ioapic_info, KERNEL_ADDRESS};
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
use crate::memory::{FRAME_ALLOC, MEM_MAPPER};
use crate::serial::terminal::ST;
mod font;
mod serial;
@ -45,27 +35,6 @@ mod macros;
pub type InitWukko = FarArchive;
lazy_static! {
//pub static ref KERN_INFO: Mutex<Option<KernelInfo>> = Mutex::new(None);
static ref GDT: Mutex<GlobalDescriptorTable> = {
let mut gdt = GlobalDescriptorTable::new();
Mutex::new(gdt)
};
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
unsafe {
use internals::errors::unhandled;
set_general_handler!(&mut idt, unhandled);
idt.breakpoint.set_handler_fn(internals::errors::breakpoint_exception).set_stack_index(0);
idt.double_fault.set_handler_fn(internals::errors::double_fault).set_stack_index(0);
idt.page_fault.set_handler_fn(internals::errors::page_fault).set_stack_index(0);
idt[internals::cpu::TIMER_IRQ].set_handler_fn(internals::cpu::timer).set_stack_index(1);
idt[internals::cpu::ERROR_IRQ].set_handler_fn(internals::cpu::error).set_stack_index(1);
idt[internals::cpu::SPURIOUS_IRQ].set_handler_fn(internals::cpu::spurious).set_stack_index(1);
idt[internals::cpu::FALLBACK_KEYBOARD_IRQ].set_handler_fn(internals::cpu::keyboard_irq).set_stack_index(1);
}
idt
};
static ref INITWUKKO: Mutex<Option<InitWukko>> = Mutex::new(None);
}
@ -78,6 +47,10 @@ fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
}
#[panic_handler]
fn panic_wrapper(info: &PanicInfo) -> ! {
panic(info)
}
fn panic(info: &PanicInfo) -> ! {
println!("---KERNEL FUCKY WUKKY UWU (panic)---");
if let Some(s) = info.payload().downcast_ref::<&str>() {
@ -85,7 +58,7 @@ fn panic(info: &PanicInfo) -> ! {
} else {
println!("no panic payload")
};
if let Some(msg) = info.message() {
if let Some(msg) = info.message() {
println!("panic msg: {}", msg)
} else {
println!("no message");
@ -98,144 +71,54 @@ fn panic(info: &PanicInfo) -> ! {
loop {}
}
#[cfg(target_arch = "powerpc")]
use ieee1275::prom_init;
#[cfg(target_arch = "powerpc")]
use ieee1275::services::Args;
#[cfg(target_arch = "powerpc")]
#[no_mangle]
#[link_section = ".text"]
pub extern "C" fn _start(_r3: u32, _r4: u32, entry: extern "C" fn(*mut Args) -> usize) -> isize {
use internals::cpu::ppc32::PROMHNDL;
{
let mut prom = PROMHNDL.lock();
prom.set_prom(prom_init(entry));
}
kernel_main();
PROMHNDL.lock().get().exit()
}
#[no_mangle]
pub extern "C" fn kernel_main() -> ! {
// ppc32 stuff for now
//#[cfg(target_arch = "powerpc")]
{
}
debug!("entry point");
// initialise serial
let mut serial_ports = serial::init_serial();
let mut console_port = None;
for (i, enabled) in serial_ports.ports_enabled.iter().enumerate() {
if *enabled {
console_port = Some(i);
}
}
if let Some(i) = console_port {
let port = &serial_ports.ports[i];
ST.init_from_port(*port);
println!("using serial port {} as console", i);
}
// temporarily disable interrupts
x86_64::instructions::interrupts::disable();
println!("debug: setup GDT");
// load TSS
static mut tss: TaskStateSegment = TaskStateSegment::new();
#[cfg(target_arch = "x86_64")]
{
unsafe {
{
tss.interrupt_stack_table[0] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[1] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[2] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[3] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[4] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[5] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.interrupt_stack_table[6] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
}
{
tss.privilege_stack_table[0] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.privilege_stack_table[1] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
tss.privilege_stack_table[2] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
let stack_end = stack_start + STACK_SIZE;
stack_end
};
}
// set word at offset 102 to 0x68 and last two bytes of the tss to 0xffff
// this is a hack to make the tss valid
let tss_ptr = &tss as *const TaskStateSegment as *mut u8;
unsafe {
*tss_ptr.add(102) = 0x68;
*tss_ptr.add(104) = 0xff;
*tss_ptr.add(105) = 0xff;
// initialise serial
let mut serial_ports = serial::init_serial();
let mut console_port = None;
for (i, enabled) in serial_ports.ports_enabled.iter().enumerate() {
if *enabled {
console_port = Some(i);
}
}
let kcs = GDT.lock().add_entry(Descriptor::kernel_code_segment());
let kds = GDT.lock().add_entry(Descriptor::kernel_data_segment());
let tsss = unsafe { GDT.lock().add_entry(Descriptor::tss_segment(&tss)) };
// load GDT
unsafe {
GDT.lock().load_unsafe();
}
println!("debug: GDT loaded");
// set code segment to kernel code segment
unsafe {
CS::set_reg(kcs);
}
println!("debug: CS set");
// set data segment to kernel data segment
unsafe {
SS::set_reg(kds);
}
println!("debug: SS set");
// load TSS
unsafe {
x86_64::instructions::tables::load_tss(tsss);
}
println!("debug: TSS loaded");
// load IDT
IDT.load();
println!("debug: IDT loaded");
// enable interrupts
x86_64::instructions::interrupts::enable();
if let Some(i) = console_port {
let port = &serial_ports.ports[i];
ST.init_from_port(*port);
println!("using serial port {} as console", i);
}
internals::cpu::x86_64::init();
}
@ -245,6 +128,8 @@ pub extern "C" fn kernel_main() -> ! {
println!("welcome to wukkOS!");
println!("(c) 2022 Real Microsoft, LLC");
/*
// memory stuff
{
print!("initialising mapper...");
@ -296,7 +181,7 @@ pub extern "C" fn kernel_main() -> ! {
unsafe { internals::cpu::setup_ioapic(addr, isos) };
println!("[OK]");
// enable interrupts
//x86_64::instructions::interrupts::enable();
//apic::instructions::interrupts::enable();
}
// initwukko stuff
@ -323,8 +208,12 @@ pub extern "C" fn kernel_main() -> ! {
println!("[OK]");
}
*/
loop {
x86_64::instructions::hlt();
#[cfg(target_arch = "apic")]
{
x86_64::instructions::hlt();
}
}
}

View File

@ -1,148 +1,2 @@
pub mod allocator;
use alloc::boxed::Box;
use alloc::sync::Arc;
use lazy_static::lazy_static;
use limine::LimineMemoryMapEntryType;
use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, Size4KiB, Translate};
use x86_64::{PhysAddr, VirtAddr};
lazy_static!{
pub static ref MEM_MAPPER: Mutex<Option<OffsetPageTable<'static>>> = Mutex::new(None);
pub static ref FRAME_ALLOC: Mutex<Option<BootInfoFrameAllocator>> = Mutex::new(None);
}
pub const VIRT_MEM_OFFSET: u64 = 0xffffffff80000000;
pub type PageSize = Size4KiB;
pub struct Locked<A> {
inner: spin::Mutex<A>,
}
impl<A> Locked<A> {
pub const fn new(inner: A) -> Self {
Locked {
inner: spin::Mutex::new(inner),
}
}
pub fn lock(&self) -> spin::MutexGuard<A> {
self.inner.lock()
}
}
pub unsafe fn init(phys_mem_offset: VirtAddr) -> OffsetPageTable<'static> {
let level_4_table = active_level_4_table(phys_mem_offset);
OffsetPageTable::new(level_4_table, phys_mem_offset)
}
unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTable {
use x86_64::registers::control::Cr3;
let (level_4_table_frame, _) = Cr3::read();
let phys = level_4_table_frame.start_address();
let virt = phys_mem_offset + phys.as_u64();
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
unsafe { &mut *page_table_ptr } // unsafe
}
use spin::Mutex;
use crate::{debug, print, println};
use crate::boot::{KERNEL_ADDRESS, MEM_MAP};
pub struct BootInfoFrameAllocator {
next: usize,
}
impl BootInfoFrameAllocator {
pub unsafe fn init() -> Self {
Self {
next: 0,
}
}
}
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> {
#[cfg(feature = "f_limine")] {
let mmap = MEM_MAP.get_response().get().expect("failed to get memory map")
.memmap();
let mut usable_frames = mmap.iter()
.filter(|entry| entry.typ == LimineMemoryMapEntryType::Usable)
.map(|area| {
let frame_addr = area.base;
let frame_end = area.base + area.len;
let frame_size = frame_end - frame_addr;
let num_frames = frame_size / 4096;
let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr));
(0..num_frames).map(move |i| start_frame + i)
})
.flatten();
let frame = usable_frames.nth(self.next).clone();
self.next += 1;
frame
}
}
}
pub fn read_phys_memory32(addr: u32) -> u32 {
let initaladdr = VirtAddr::new(addr as u64);
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *const u32;
unsafe { *addr }
} else {
debug!("read_phys_memory32: addr {:x} not mapped", initaladdr.as_u64());
// map the page
let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap();
debug!("allocated frame: {:?}", frame);
let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE;
let page = x86_64::structures::paging::Page::containing_address(initaladdr);
debug!("mapped page: {:?}", page);
let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) };
debug!("map_to_result: {:?}", map_to_result);
if map_to_result.is_err() {
panic!("Failed to map page");
}
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *const u32;
unsafe { *addr }
} else {
panic!("Failed to map page");
}
}
}
pub fn write_phys_memory32(addr: u32, value: u32) {
let initaladdr = VirtAddr::new(addr as u64);
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *mut u32;
unsafe { *addr = value };
} else {
debug!("write_phys_memory32: addr {:x} not mapped", initaladdr.as_u64());
// map the page
let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap();
debug!("allocated frame: {:?}", frame);
let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE;
let page = x86_64::structures::paging::Page::containing_address(initaladdr);
debug!("mapped page: {:?}", page);
let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) };
debug!("map_to_result: {:?}", map_to_result);
if map_to_result.is_err() {
panic!("Failed to map page");
}
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *mut u32;
unsafe { *addr = value };
} else {
panic!("Failed to map page");
}
}
}
#[cfg(target_arch = "x86_64")]
pub mod x86_64;

149
src/memory/x86_64/mod.rs Normal file
View File

@ -0,0 +1,149 @@
pub mod allocator;
use alloc::boxed::Box;
use alloc::sync::Arc;
use lazy_static::lazy_static;
use limine::LimineMemoryMapEntryType;
use x86_64::structures::paging::{FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, Size4KiB, Translate};
use x86_64::{PhysAddr, VirtAddr};
lazy_static!{
pub static ref MEM_MAPPER: Mutex<Option<OffsetPageTable<'static>>> = Mutex::new(None);
pub static ref FRAME_ALLOC: Mutex<Option<BootInfoFrameAllocator>> = Mutex::new(None);
}
pub const VIRT_MEM_OFFSET: u64 = 0xffffffff80000000;
pub type PageSize = Size4KiB;
pub struct Locked<A> {
inner: spin::Mutex<A>,
}
impl<A> Locked<A> {
pub const fn new(inner: A) -> Self {
Locked {
inner: spin::Mutex::new(inner),
}
}
pub fn lock(&self) -> spin::MutexGuard<A> {
self.inner.lock()
}
}
pub unsafe fn init(phys_mem_offset: VirtAddr) -> OffsetPageTable<'static> {
let level_4_table = active_level_4_table(phys_mem_offset);
OffsetPageTable::new(level_4_table, phys_mem_offset)
}
unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTable {
use x86_64::registers::control::Cr3;
let (level_4_table_frame, _) = Cr3::read();
let phys = level_4_table_frame.start_address();
let virt = phys_mem_offset + phys.as_u64();
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
unsafe { &mut *page_table_ptr } // unsafe
}
use spin::Mutex;
use crate::{debug, print, println};
use crate::boot::{KERNEL_ADDRESS, MEM_MAP};
pub struct BootInfoFrameAllocator {
next: usize,
}
impl BootInfoFrameAllocator {
pub unsafe fn init() -> Self {
Self {
next: 0,
}
}
}
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> {
#[cfg(feature = "f_limine")] {
let mmap = MEM_MAP.get_response().get().expect("failed to get memory map")
.memmap();
let mut usable_frames = mmap.iter()
.filter(|entry| entry.typ == LimineMemoryMapEntryType::Usable)
.map(|area| {
let frame_addr = area.base;
let frame_end = area.base + area.len;
let frame_size = frame_end - frame_addr;
let num_frames = frame_size / 4096;
let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr));
(0..num_frames).map(move |i| start_frame + i)
})
.flatten();
let frame = usable_frames.nth(self.next).clone();
self.next += 1;
frame
}
}
}
pub fn read_phys_memory32(addr: u32) -> u32 {
let initaladdr = VirtAddr::new(addr as u64);
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *const u32;
unsafe { *addr }
} else {
debug!("read_phys_memory32: addr {:x} not mapped", initaladdr.as_u64());
// map the page
let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap();
debug!("allocated frame: {:?}", frame);
let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE;
let page = x86_64::structures::paging::Page::containing_address(initaladdr);
debug!("mapped page: {:?}", page);
let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) };
debug!("map_to_result: {:?}", map_to_result);
if map_to_result.is_err() {
panic!("Failed to map page");
}
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *const u32;
unsafe { *addr }
} else {
panic!("Failed to map page");
}
}
}
pub fn write_phys_memory32(addr: u32, value: u32) {
let initaladdr = VirtAddr::new(addr as u64);
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *mut u32;
unsafe { *addr = value };
} else {
debug!("write_phys_memory32: addr {:x} not mapped", initaladdr.as_u64());
// map the page
let frame = FRAME_ALLOC.lock().as_mut().unwrap().allocate_frame().unwrap();
debug!("allocated frame: {:?}", frame);
let flags = x86_64::structures::paging::PageTableFlags::PRESENT | x86_64::structures::paging::PageTableFlags::WRITABLE;
let page = x86_64::structures::paging::Page::containing_address(initaladdr);
debug!("mapped page: {:?}", page);
let map_to_result = unsafe { MEM_MAPPER.lock().as_mut().unwrap().map_to(page, frame, flags, FRAME_ALLOC.lock().as_mut().unwrap()) };
debug!("map_to_result: {:?}", map_to_result);
if map_to_result.is_err() {
panic!("Failed to map page");
}
let addr = unsafe { MEM_MAPPER.lock().as_mut().unwrap().translate_addr(initaladdr) };
if let Some(addr) = addr {
let addr = addr.as_u64() as *mut u32;
unsafe { *addr = value };
} else {
panic!("Failed to map page");
}
}
}

View File

@ -1,174 +1,2 @@
use core::arch::asm;
use core::borrow::{Borrow, BorrowMut};
use core::ops::Deref;
pub mod terminal_helpers;
pub mod terminal;
pub mod simplifiers;
#[derive(Clone, Copy, PartialEq)]
pub enum potential_serial_ports {
COM1 = 0x3F8,
COM2 = 0x2F8,
COM3 = 0x3E8,
COM4 = 0x2E8,
COM5 = 0x5F8,
COM6 = 0x4F8,
COM7 = 0x5E8,
COM8 = 0x4E8,
}
impl potential_serial_ports {
pub fn to_string<'a>(&self) -> &'a str {
match self {
potential_serial_ports::COM1 => "COM1",
potential_serial_ports::COM2 => "COM2",
potential_serial_ports::COM3 => "COM3",
potential_serial_ports::COM4 => "COM4",
potential_serial_ports::COM5 => "COM5",
potential_serial_ports::COM6 => "COM6",
potential_serial_ports::COM7 => "COM7",
potential_serial_ports::COM8 => "COM8",
_ => {
panic!("Invalid potential_serial_ports");
}
}
}
}
enum serial_offsets {
DATA = 0,
INTERRUPT_ID = 1,
FIFO_CTRL = 2,
LINE_CTRL = 3,
MODEM_CTRL = 4,
LINE_STATUS = 5,
MODEM_STATUS = 6,
SCRATCH = 7,
}
#[derive(Copy, Clone)]
pub struct Port {
pub base: potential_serial_ports,
}
pub struct SerialPorts {
pub ports_enabled: [bool; 8],
pub ports: [Port; 8],
}
#[cfg(any(target_arch="x86", target_arch="x86_64"))]
pub fn command(port: u16, data: u8) {
unsafe {
asm!("out dx, al", in("al") data, in("dx") port);
}
}
#[cfg(any(target_arch="x86", target_arch="x86_64"))]
pub fn read(port: u16) -> u8 {
let mut data: u8;
unsafe {
asm!("in al, dx", out("al") data, in("dx") port);
}
data
}
// dummy functions for non-x86
#[cfg(not(any(target_arch="x86", target_arch="x86_64")))]
pub fn command(port: u16, data: u8) {
unimplemented!()
}
#[cfg(not(any(target_arch="x86", target_arch="x86_64")))]
pub fn read(port: u16) -> u8 {
unimplemented!()
}
impl Port {
fn is_transmit_empty(&self) -> bool {
let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);
status & 0x20 == 0x20
}
pub fn transmit(&self, data: u8) {
while !self.is_transmit_empty() {}
command(self.base as u16 + serial_offsets::DATA as u16, data);
}
pub fn transmit_string(&self, data: &str) {
for c in data.chars() {
self.transmit(c as u8);
}
}
fn is_recv_full(&self) -> bool {
let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);
status & 0x01 == 0x01
}
pub fn receive(&self, mut timeout: u16) -> u8 {
if timeout != 0 {
while !self.is_recv_full() {
timeout -= 1;
if timeout == 0 {
return 0;
}
}
} else {
while !self.is_recv_full() {}
}
read(self.base as u16 + serial_offsets::DATA as u16)
}
pub fn transrecv(&self, data: u8) -> u8 {
self.transmit(data);
self.receive(0)
}
}
pub fn test_port(port: potential_serial_ports) -> bool {
let mut port: u16 = port as u16;
command(port + serial_offsets::INTERRUPT_ID as u16, 0x00); // disable interrupts
command(port + serial_offsets::LINE_CTRL as u16, 0x80); // enable DLAB
command(port + serial_offsets::DATA as u16, 0x03); // set divisor to 3 (lo byte)
command(port + serial_offsets::LINE_CTRL as u16, 0x03); // set divisor to 3 (hi byte)
command(port + serial_offsets::FIFO_CTRL as u16, 0xC7); // enable FIFO, clear them, with 14-byte threshold
command(port + serial_offsets::MODEM_CTRL as u16, 0x0B); // IRQs enabled, RTS/DSR set
command(port + serial_offsets::MODEM_CTRL as u16, 0x1E); // loopback mode
// test serial
command(port + serial_offsets::DATA as u16, 0xAE);
// check if we received the correct byte
if read(port + serial_offsets::DATA as u16) != 0xAE {
return false;
} else {
// set stuffz idk
command(port + serial_offsets::MODEM_CTRL as u16, 0x0F);
return true;
}
}
pub fn init_serial() -> SerialPorts {
// this is so fucking cursed
let mut ports_tmp : [Port; 8] = [
Port { base: potential_serial_ports::COM1 },
Port { base: potential_serial_ports::COM2 },
Port { base: potential_serial_ports::COM3 },
Port { base: potential_serial_ports::COM4 },
Port { base: potential_serial_ports::COM5 },
Port { base: potential_serial_ports::COM6 },
Port { base: potential_serial_ports::COM7 },
Port { base: potential_serial_ports::COM8 }];
let mut ports_enabled_tmp : [bool; 8] = [false; 8];
for i in 0..8 {
if test_port(ports_tmp[i].base) {
ports_enabled_tmp[i] = true;
}
}
SerialPorts {
ports_enabled: ports_enabled_tmp,
ports: ports_tmp,
}
}
#[cfg(target_arch = "x86_64")]
pub mod x86_64;

174
src/serial/x86_64/mod.rs Normal file
View File

@ -0,0 +1,174 @@
use core::arch::asm;
use core::borrow::{Borrow, BorrowMut};
use core::ops::Deref;
pub mod terminal_helpers;
pub mod terminal;
pub mod simplifiers;
#[derive(Clone, Copy, PartialEq)]
pub enum potential_serial_ports {
COM1 = 0x3F8,
COM2 = 0x2F8,
COM3 = 0x3E8,
COM4 = 0x2E8,
COM5 = 0x5F8,
COM6 = 0x4F8,
COM7 = 0x5E8,
COM8 = 0x4E8,
}
impl potential_serial_ports {
pub fn to_string<'a>(&self) -> &'a str {
match self {
potential_serial_ports::COM1 => "COM1",
potential_serial_ports::COM2 => "COM2",
potential_serial_ports::COM3 => "COM3",
potential_serial_ports::COM4 => "COM4",
potential_serial_ports::COM5 => "COM5",
potential_serial_ports::COM6 => "COM6",
potential_serial_ports::COM7 => "COM7",
potential_serial_ports::COM8 => "COM8",
_ => {
panic!("Invalid potential_serial_ports");
}
}
}
}
enum serial_offsets {
DATA = 0,
INTERRUPT_ID = 1,
FIFO_CTRL = 2,
LINE_CTRL = 3,
MODEM_CTRL = 4,
LINE_STATUS = 5,
MODEM_STATUS = 6,
SCRATCH = 7,
}
#[derive(Copy, Clone)]
pub struct Port {
pub base: potential_serial_ports,
}
pub struct SerialPorts {
pub ports_enabled: [bool; 8],
pub ports: [Port; 8],
}
#[cfg(any(target_arch="x86", target_arch="apic"))]
pub fn command(port: u16, data: u8) {
unsafe {
asm!("out dx, al", in("al") data, in("dx") port);
}
}
#[cfg(any(target_arch="x86", target_arch="apic"))]
pub fn read(port: u16) -> u8 {
let mut data: u8;
unsafe {
asm!("in al, dx", out("al") data, in("dx") port);
}
data
}
// dummy functions for non-x86
#[cfg(not(any(target_arch="x86", target_arch="apic")))]
pub fn command(port: u16, data: u8) {
unimplemented!()
}
#[cfg(not(any(target_arch="x86", target_arch="apic")))]
pub fn read(port: u16) -> u8 {
unimplemented!()
}
impl Port {
fn is_transmit_empty(&self) -> bool {
let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);
status & 0x20 == 0x20
}
pub fn transmit(&self, data: u8) {
while !self.is_transmit_empty() {}
command(self.base as u16 + serial_offsets::DATA as u16, data);
}
pub fn transmit_string(&self, data: &str) {
for c in data.chars() {
self.transmit(c as u8);
}
}
fn is_recv_full(&self) -> bool {
let status = read(self.base as u16 + serial_offsets::LINE_STATUS as u16);
status & 0x01 == 0x01
}
pub fn receive(&self, mut timeout: u16) -> u8 {
if timeout != 0 {
while !self.is_recv_full() {
timeout -= 1;
if timeout == 0 {
return 0;
}
}
} else {
while !self.is_recv_full() {}
}
read(self.base as u16 + serial_offsets::DATA as u16)
}
pub fn transrecv(&self, data: u8) -> u8 {
self.transmit(data);
self.receive(0)
}
}
pub fn test_port(port: potential_serial_ports) -> bool {
let mut port: u16 = port as u16;
command(port + serial_offsets::INTERRUPT_ID as u16, 0x00); // disable interrupts
command(port + serial_offsets::LINE_CTRL as u16, 0x80); // enable DLAB
command(port + serial_offsets::DATA as u16, 0x03); // set divisor to 3 (lo byte)
command(port + serial_offsets::LINE_CTRL as u16, 0x03); // set divisor to 3 (hi byte)
command(port + serial_offsets::FIFO_CTRL as u16, 0xC7); // enable FIFO, clear them, with 14-byte threshold
command(port + serial_offsets::MODEM_CTRL as u16, 0x0B); // IRQs enabled, RTS/DSR set
command(port + serial_offsets::MODEM_CTRL as u16, 0x1E); // loopback mode
// test serial
command(port + serial_offsets::DATA as u16, 0xAE);
// check if we received the correct byte
if read(port + serial_offsets::DATA as u16) != 0xAE {
return false;
} else {
// set stuffz idk
command(port + serial_offsets::MODEM_CTRL as u16, 0x0F);
return true;
}
}
pub fn init_serial() -> SerialPorts {
// this is so fucking cursed
let mut ports_tmp : [Port; 8] = [
Port { base: potential_serial_ports::COM1 },
Port { base: potential_serial_ports::COM2 },
Port { base: potential_serial_ports::COM3 },
Port { base: potential_serial_ports::COM4 },
Port { base: potential_serial_ports::COM5 },
Port { base: potential_serial_ports::COM6 },
Port { base: potential_serial_ports::COM7 },
Port { base: potential_serial_ports::COM8 }];
let mut ports_enabled_tmp : [bool; 8] = [false; 8];
for i in 0..8 {
if test_port(ports_tmp[i].base) {
ports_enabled_tmp[i] = true;
}
}
SerialPorts {
ports_enabled: ports_enabled_tmp,
ports: ports_tmp,
}
}