mirror of
https://github.com/realmicrosoft/windows.git
synced 2024-08-14 22:46:44 +00:00
compiles!
This commit is contained in:
parent
7319725700
commit
6405017b88
24 changed files with 764 additions and 629 deletions
|
@ -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"
|
16
Cargo.toml
16
Cargo.toml
|
@ -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"]
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
strip = true
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
strip = true
|
13
Makefile
13
Makefile
|
@ -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 $@)
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
"panic-strategy": "abort",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections",
|
||||
"--script=arch/ppc32/linker.ld"
|
||||
"--gc-sections"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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()));
|
||||
|
|
110
src/boot/mod.rs
110
src/boot/mod.rs
|
@ -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
106
src/boot/x86_64/mod.rs
Normal 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
4
src/internals/cpu/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod x86_64;
|
||||
#[cfg(target_arch = "powerpc")]
|
||||
pub mod ppc32;
|
25
src/internals/cpu/ppc32/mod.rs
Normal file
25
src/internals/cpu/ppc32/mod.rs
Normal 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()
|
||||
}
|
||||
}
|
161
src/internals/cpu/x86_64/mod.rs
Normal file
161
src/internals/cpu/x86_64/mod.rs
Normal 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();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
pub mod errors;
|
||||
pub mod interrupts;
|
||||
pub mod cpu;
|
||||
|
||||
pub mod WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood {
|
||||
|
|
|
@ -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,15 +24,50 @@ macro_rules! debug {
|
|||
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
#[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();
|
||||
}
|
||||
|
||||
#[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) {
|
||||
#[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_str("[debug] ").unwrap();
|
||||
OFPrinter.write_fmt(args).unwrap();
|
||||
OFPrinter.write_str("\n").unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "apic")]
|
||||
{
|
||||
use core::fmt::Write;
|
||||
#[cfg(feature = "f_debug_verbose")]
|
||||
{
|
||||
|
@ -42,4 +80,5 @@ pub fn _debug(args: fmt::Arguments) {
|
|||
limine_writer.write_fmt(args).unwrap();
|
||||
limine_writer.write_str("\n").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
191
src/main.rs
191
src/main.rs
|
@ -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>() {
|
||||
|
@ -98,10 +71,38 @@ 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");
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
// initialise serial
|
||||
let mut serial_ports = serial::init_serial();
|
||||
let mut console_port = None;
|
||||
|
@ -117,125 +118,7 @@ pub extern "C" fn kernel_main() -> ! {
|
|||
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();
|
||||
{
|
||||
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();
|
||||
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 {
|
||||
#[cfg(target_arch = "apic")]
|
||||
{
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
149
src/memory/x86_64/mod.rs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
174
src/serial/x86_64/mod.rs
Normal 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,
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue