Skip to content

Commit

Permalink
Merge branch 'theseus_main' into theseus_main
Browse files Browse the repository at this point in the history
  • Loading branch information
NIMogen authored Aug 28, 2023
2 parents 742528b + 27429e5 commit 3250e0e
Show file tree
Hide file tree
Showing 28 changed files with 1,545 additions and 958 deletions.
19 changes: 16 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ exclude = [

## Exclude application crates used for testing specific Theseus functionality.
## TODO: move these to a specific "tests" folder so we can exclude that entire folder.
"applications/test_aligned_page_allocation",
"applications/test_backtrace",
"applications/test_block_io",
"applications/test_channel",
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,9 @@ else ifeq ($(ARCH),aarch64)
QEMU_FLAGS += -machine virt,gic-version=3
QEMU_FLAGS += -device ramfb
QEMU_FLAGS += -cpu cortex-a72
QEMU_FLAGS += -usb
QEMU_FLAGS += -device usb-ehci,id=ehci
QEMU_FLAGS += -device usb-kbd
else
QEMU_FLAGS += -cpu Broadwell
endif
Expand Down
15 changes: 15 additions & 0 deletions applications/test_aligned_page_allocation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "test_aligned_page_allocation"
version = "0.1.0"
description = "Tests the `AllocationRequest::AlignedTo` variant, which is needed for huge pages"
authors = ["Kevin Boos <kevinaboos@gmail.com>"]
edition = "2021"

[dependencies]
log = "0.4.8"

[dependencies.memory]
path = "../../kernel/memory"

[dependencies.app_io]
path = "../../kernel/app_io"
45 changes: 45 additions & 0 deletions applications/test_aligned_page_allocation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! A set of basic tests for the [`AllocationRequest::AlignedTo`] variant.
#![no_std]

extern crate alloc;

use alloc::{
vec::Vec,
string::String,
};
use app_io::println;
use memory::AllocationRequest;

static TEST_SET: [usize; 9] = [1, 2, 4, 8, 27, 48, 256, 512, 1024];

pub fn main(_args: Vec<String>) -> isize {
match rmain() {
Ok(_) => 0,
Err(e) => {
println!("Error: {}", e);
-1
}
}
}

fn rmain() -> Result<(), &'static str> {
for num_pages in TEST_SET.into_iter() {
for alignment in TEST_SET.into_iter() {
println!("Attempting to allocate {num_pages} pages with alignment of {alignment} 4K pages...");
match memory::allocate_pages_deferred(
AllocationRequest::AlignedTo { alignment_4k_pages: alignment },
num_pages,
) {
Ok((ap, _action)) => {
assert_eq!(ap.start().number() % alignment, 0);
assert_eq!(ap.size_in_pages(), num_pages);
println!(" Success: {ap:?}");
}
Err(e) => println!(" !! FAILURE: {e:?}"),
}
}
}

Ok(())
}
9 changes: 8 additions & 1 deletion kernel/arm_boards/src/boards/qemu_virt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use super::{
InterruptControllerConfig::GicV3, GicV3InterruptControllerConfig,
BoardConfig, mpidr::DefinedMpidrValue,
BoardConfig, mpidr::DefinedMpidrValue, PciEcamConfig,
};
use memory_structs::PhysicalAddress;

Expand Down Expand Up @@ -38,4 +38,11 @@ pub const BOARD_CONFIG: BoardConfig = BoardConfig {
pl011_base_addresses: [ PhysicalAddress::new_canonical(0x09000000) ],
pl011_rx_spi: 33,
cpu_local_timer_ppi: 30,

// obtained via internal qemu debugging
// todo: will this always be correct?
pci_ecam: PciEcamConfig {
base_address: PhysicalAddress::new_canonical(0x4010000000),
size_bytes: 0x10000000,
}
};
10 changes: 10 additions & 0 deletions kernel/arm_boards/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ pub struct GicV3InterruptControllerConfig {
pub redistributor_base_addresses: [PhysicalAddress; NUM_CPUS],
}

#[derive(Debug, Copy, Clone)]
pub struct PciEcamConfig {
pub base_address: PhysicalAddress,
pub size_bytes: usize,
}

/// This excludes GICv2 because there's no way to send IPIs
/// with GICv2 via the current driver API.
#[derive(Debug, Copy, Clone)]
pub enum InterruptControllerConfig {
GicV3(GicV3InterruptControllerConfig),
Expand Down Expand Up @@ -46,6 +54,8 @@ pub struct BoardConfig {
//
// aarch64 manuals define the default timer IRQ number to be 30.
pub cpu_local_timer_ppi: u8,

pub pci_ecam: PciEcamConfig,
}

// by default & on x86_64, the default.rs file is used
Expand Down
2 changes: 1 addition & 1 deletion kernel/device_manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ event_types = { path = "../event_types" }
serial_port = { path = "../serial_port" }
console = { path = "../console" }
logger = { path = "../logger" }
pci = { path = "../pci" }
derive_more = "0.99.0"
mpmc = "0.1.6"
log = "0.4.8"
Expand All @@ -20,7 +21,6 @@ log = "0.4.8"
memory = { path = "../memory" }
e1000 = { path = "../e1000" }
acpi = { path = "../acpi" }
pci = { path = "../pci" }
ps2 = { path = "../ps2" }
keyboard = { path = "../keyboard" }
mouse = { path = "../mouse" }
Expand Down
15 changes: 8 additions & 7 deletions kernel/device_manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

extern crate alloc;

use log::info;
use log::{info, debug};

#[cfg(target_arch = "x86_64")]
use {
log::{error, debug, warn},
log::{error, warn},
mpmc::Queue,
event_types::Event,
memory::MemoryManagementInfo,
Expand Down Expand Up @@ -86,19 +86,20 @@ pub fn init(
mouse::init(ps2_controller.mouse_ref(), mouse_producer)?;
}

// No PCI support on aarch64 at the moment
#[cfg(target_arch = "x86_64")] {
// Initialize/scan the PCI bus to discover PCI devices
for dev in pci::pci_device_iter() {
debug!("Found pci device: {:X?}", dev);
for dev in pci::pci_device_iter()? {
debug!("Found PCI device: {:X?}", dev);
}

// No NIC support on aarch64 at the moment
#[cfg(target_arch = "x86_64")] {

// store all the initialized ixgbe NICs here to be added to the network interface list
let mut ixgbe_devs = Vec::new();

// Iterate over all PCI devices and initialize the drivers for the devices we support.

for dev in pci::pci_device_iter() {
for dev in pci::pci_device_iter()? {
// Currently we skip Bridge devices, since we have no use for them yet.
if dev.class == 0x06 {
continue;
Expand Down
3 changes: 2 additions & 1 deletion kernel/gic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ edition = "2021"
name = "gic"

[dependencies]
static_assertions = "1.1.0"
zerocopy = "0.5.0"
volatile = "0.2.7"
spin = "0.9.4"
log = "0.4.8"

memory = { path = "../memory" }
Expand Down
119 changes: 74 additions & 45 deletions kernel/gic/src/gic/cpu_interface_gicv2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,39 @@
//! - Acknowledging interrupt requests
//! - Sending End-Of-Interrupts signals
use super::GicRegisters;
use super::Priority;
use super::InterruptNumber;

mod offset {
use crate::Offset32;
pub(crate) const CTLR: Offset32 = Offset32::from_byte_offset(0x00);
pub(crate) const PMR: Offset32 = Offset32::from_byte_offset(0x04);
pub(crate) const IAR: Offset32 = Offset32::from_byte_offset(0x0C);
pub(crate) const RPR: Offset32 = Offset32::from_byte_offset(0x14);
pub(crate) const EOIR: Offset32 = Offset32::from_byte_offset(0x10);
use volatile::{Volatile, ReadOnly, WriteOnly};
use zerocopy::FromBytes;

/// The GICv2 MMIO registers for interfacing with a specific CPU.
///
/// Methods herein apply to the "current" CPU only, i.e., the CPU
/// on which the code that accesses these registers is currently running.
///
/// Note: the physical address for this structure is the same for all CPUs,
/// but the actual backing memory refers to physically separate registers.
#[derive(FromBytes)]
#[repr(C)]
pub struct CpuRegsP1 { // base offset
/// CPU Interface Control Register
ctlr: Volatile<u32>, // 0x00

/// Interrupt Priority Mask Register
prio_mask: Volatile<u32>, // 0x04

/// Binary Point Register
_unused0: u32,

/// Interrupt Acknowledge Register
acknowledge: ReadOnly<u32>, // 0x0C

/// End of Interrupt Register
eoi: WriteOnly<u32>, // 0x10

/// Running Priority Register
running_prio: ReadOnly<u32>, // 0x14
}

// enable group 0
Expand All @@ -25,45 +47,52 @@ mod offset {
// enable group 1
const CTLR_ENGRP1: u32 = 0b10;

/// Enables routing of group 1 interrupts for the current CPU
pub fn init(registers: &mut GicRegisters) {
let mut reg = registers.read_volatile(offset::CTLR);
reg |= CTLR_ENGRP1;
registers.write_volatile(offset::CTLR, reg);
}
impl CpuRegsP1 {
/// Enables routing of group 1 interrupts for the current CPU.
pub fn init(&mut self) {
let mut reg = self.ctlr.read();
reg |= CTLR_ENGRP1;
self.ctlr.write(reg);
}

/// Interrupts have a priority; if their priority
/// is lower or equal to this one, they're queued
/// until this CPU or another one is ready to handle
/// them
pub fn get_minimum_priority(registers: &GicRegisters) -> Priority {
u8::MAX - (registers.read_volatile(offset::PMR) as u8)
}
/// Retrieves the current priority threshold for the current CPU.
///
/// Interrupts have a priority; if their priority is lower or
/// equal to this threshold, they're queued until the current CPU
/// is ready to handle them.
pub fn get_minimum_priority(&self) -> Priority {
u8::MAX - (self.prio_mask.read() as u8)
}

/// Interrupts have a priority; if their priority
/// is lower or equal to this one, they're queued
/// until this CPU or another one is ready to handle
/// them
pub fn set_minimum_priority(registers: &mut GicRegisters, priority: Priority) {
registers.write_volatile(offset::PMR, (u8::MAX - priority) as u32);
}
/// Sets the current priority threshold for the current CPU.
///
/// Interrupts have a priority; if their priority is lower or
/// equal to this threshold, they're queued until the current CPU
/// is ready to handle them.
pub fn set_minimum_priority(&mut self, priority: Priority) {
self.prio_mask.write((u8::MAX - priority) as u32);
}

/// Signals to the controller that the currently processed interrupt has
/// been fully handled, by zeroing the current priority level of this CPU.
/// This implies that the CPU is ready to process interrupts again.
pub fn end_of_interrupt(registers: &mut GicRegisters, int: InterruptNumber) {
registers.write_volatile(offset::EOIR, int);
}
/// Signals to the controller that the currently processed interrupt
/// has been fully handled, by zeroing the current priority level of
/// the current CPU.
///
/// This implies that the CPU is ready to process interrupts again.
pub fn end_of_interrupt(&mut self, int: InterruptNumber) {
self.eoi.write(int);
}

/// Acknowledge the currently serviced interrupt and fetches its
/// number.
///
/// This tells the GIC that the requested interrupt is being
/// handled by this CPU.
pub fn acknowledge_interrupt(&mut self) -> (InterruptNumber, Priority) {
// Reading the interrupt number has the side effect
// of acknowledging the interrupt.
let int_num = self.acknowledge.read() as InterruptNumber;
let priority = self.running_prio.read() as u8;

/// Acknowledge the currently serviced interrupt
/// and fetches its number; this tells the GIC that
/// the requested interrupt is being handled by
/// this CPU.
pub fn acknowledge_interrupt(registers: &mut GicRegisters) -> (InterruptNumber, Priority) {
// Reading the interrupt number has the side effect
// of acknowledging the interrupt.
let int_num = registers.read_volatile(offset::IAR) as InterruptNumber;
let priority = registers.read_volatile(offset::RPR) as u8;

(int_num, priority)
(int_num, priority)
}
}
Loading

0 comments on commit 3250e0e

Please sign in to comment.