Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: Split x86_64 specific code #203

Merged
merged 6 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ efi-var = []

[dependencies]
bitflags = "1.3.2"
x86_64 = "0.14.10"
atomic_refcell = "0.1.8"
r-efi = "4.1.0"
uart_16550 = "0.2.18"
linked_list_allocator = "0.10.4"

[target.'cfg(target_arch = "x86_64")'.dependencies]
uart_16550 = "0.2.18"
x86_64 = "0.14.10"

[dev-dependencies]
dirs = "4.0.0"
rand = "0.8.5"
Expand Down
5 changes: 5 additions & 0 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2022 Akira Moroo

#[cfg(target_arch = "x86_64")]
pub mod x86_64;
File renamed without changes.
File renamed without changes.
8 changes: 8 additions & 0 deletions src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2022 Akira Moroo

#[cfg(not(test))]
pub mod asm;
pub mod gdt;
pub mod paging;
pub mod sse;
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions src/arch/x86_64/sse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use x86_64::registers::control::{Cr0, Cr0Flags, Cr4, Cr4Flags};

// Enable SSE2 for XMM registers (needed for EFI calling)
pub fn enable_sse() {
let mut cr0 = Cr0::read();
cr0.remove(Cr0Flags::EMULATE_COPROCESSOR);
cr0.insert(Cr0Flags::MONITOR_COPROCESSOR);
unsafe { Cr0::write(cr0) };
let mut cr4 = Cr4::read();
cr4.insert(Cr4Flags::OSFXSR);
cr4.insert(Cr4Flags::OSXMMEXCPT_ENABLE);
unsafe { Cr4::write(cr4) };
}
93 changes: 93 additions & 0 deletions src/cmos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2021 Akira Moroo

use atomic_refcell::AtomicRefCell;
use x86_64::instructions::port::{Port, PortWriteOnly};

static CMOS: AtomicRefCell<Cmos> = AtomicRefCell::new(Cmos::new());

struct Cmos {
address_port: PortWriteOnly<u8>,
data_port: Port<u8>,
reg_b: Option<u8>,
}

impl Cmos {
const fn new() -> Self {
Self {
address_port: PortWriteOnly::new(0x70),
data_port: Port::new(0x71),
reg_b: None,
}
}

fn read_cmos(&mut self, addr: u8) -> u8 {
assert!(addr < 128);
unsafe {
self.address_port.write(addr);
self.data_port.read()
}
}

fn get_update_status(&mut self) -> bool {
self.read_cmos(0x0a) & 0x80 != 0
}

fn read(&mut self, offset: u8) -> Result<u8, ()> {
if crate::delay::wait_while(1, || self.get_update_status()) {
return Err(());
}
Ok(self.read_cmos(offset))
}

fn get_reg_b(&mut self) -> u8 {
if self.reg_b.is_none() {
self.reg_b = Some(self.read_cmos(0x0b));
}
self.reg_b.unwrap()
}

fn read_date(&mut self) -> Result<(u8, u8, u8), ()> {
let mut year = self.read(0x09)?;
let mut month = self.read(0x08)?;
let mut day = self.read(0x07)?;

if (self.get_reg_b() & 0x04) == 0 {
year = bcd2dec(year);
month = bcd2dec(month);
day = bcd2dec(day);
}

Ok((year, month, day))
}

fn read_time(&mut self) -> Result<(u8, u8, u8), ()> {
let mut hour = self.read(0x04)?;
let mut minute = self.read(0x02)?;
let mut second = self.read(0x00)?;

if (self.get_reg_b() & 0x04) == 0 {
hour = bcd2dec(hour);
minute = bcd2dec(minute);
second = bcd2dec(second);
}

if ((self.get_reg_b() & 0x02) == 0) && ((hour & 0x80) != 0) {
hour = ((hour & 0x7f) + 12) % 24;
}

Ok((hour, minute, second))
}
}

fn bcd2dec(b: u8) -> u8 {
((b >> 4) & 0x0f) * 10 + (b & 0x0f)
}

pub fn read_date() -> Result<(u8, u8, u8), ()> {
CMOS.borrow_mut().read_date()
}

pub fn read_time() -> Result<(u8, u8, u8), ()> {
CMOS.borrow_mut().read_time()
}
20 changes: 16 additions & 4 deletions src/delay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,30 @@ const NSECS_PER_SEC: u64 = 1000000000;
const CPU_KHZ_DEFAULT: u64 = 200;
const PAUSE_THRESHOLD_TICKS: u64 = 150;

#[cfg(target_arch = "x86_64")]
#[inline]
unsafe fn rdtsc() -> u64 {
_rdtsc()
}

#[cfg(target_arch = "x86_64")]
#[inline]
unsafe fn pause() {
asm!("pause");
}

pub fn ndelay(ns: u64) {
let delta = ns * CPU_KHZ_DEFAULT / NSECS_PER_SEC;
let mut pause_delta = 0;
unsafe {
let start = _rdtsc();
let start = rdtsc();
if delta > PAUSE_THRESHOLD_TICKS {
pause_delta = delta - PAUSE_THRESHOLD_TICKS;
}
while _rdtsc() - start < pause_delta {
asm!("pause");
while rdtsc() - start < pause_delta {
pause();
}
while _rdtsc() - start < delta {}
while rdtsc() - start < delta {}
}
}

Expand Down
54 changes: 18 additions & 36 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,34 @@

use core::panic::PanicInfo;

use x86_64::{
instructions::hlt,
registers::control::{Cr0, Cr0Flags, Cr4, Cr4Flags},
};
#[cfg(target_arch = "x86_64")]
use x86_64::instructions::hlt;

#[macro_use]
mod serial;

#[macro_use]
mod common;

#[cfg(not(test))]
mod asm;
mod arch;
mod block;
mod boot;
mod bzimage;
#[cfg(target_arch = "x86_64")]
mod cmos;
mod coreboot;
mod delay;
mod efi;
mod fat;
mod gdt;
#[cfg(all(test, feature = "integration_tests"))]
mod integration;
mod loader;
mod mem;
mod paging;
mod part;
#[cfg(target_arch = "x86_64")]
mod pci;
mod pe;
#[cfg(target_arch = "x86_64")]
mod pvh;
mod rtc;
mod virtio;
Expand All @@ -60,6 +59,7 @@ mod virtio;
fn panic(info: &PanicInfo) -> ! {
log!("PANIC: {}", info);
loop {
#[cfg(target_arch = "x86_64")]
hlt()
}
}
Expand All @@ -70,18 +70,6 @@ fn panic(_: &PanicInfo) -> ! {
loop {}
}

// Enable SSE2 for XMM registers (needed for EFI calling)
fn enable_sse() {
let mut cr0 = Cr0::read();
cr0.remove(Cr0Flags::EMULATE_COPROCESSOR);
cr0.insert(Cr0Flags::MONITOR_COPROCESSOR);
unsafe { Cr0::write(cr0) };
let mut cr4 = Cr4::read();
cr4.insert(Cr4Flags::OSFXSR);
cr4.insert(Cr4Flags::OSXMMEXCPT_ENABLE);
unsafe { Cr4::write(cr4) };
}

const VIRTIO_PCI_VENDOR_ID: u16 = 0x1af4;
const VIRTIO_PCI_BLOCK_DEVICE_ID: u16 = 0x1042;

Expand Down Expand Up @@ -145,30 +133,24 @@ fn boot_from_device(device: &mut block::VirtioBlockDevice, info: &dyn boot::Info
true
}

#[cfg(target_arch = "x86_64")]
#[no_mangle]
#[cfg(not(feature = "coreboot"))]
pub extern "C" fn rust64_start(rdi: &pvh::StartInfo) -> ! {
pub extern "C" fn rust64_start(#[cfg(not(feature = "coreboot"))] pvh_info: &pvh::StartInfo) -> ! {
serial::PORT.borrow_mut().init();

enable_sse();
paging::setup();

main(rdi)
}

#[no_mangle]
#[cfg(feature = "coreboot")]
pub extern "C" fn rust64_start() -> ! {
serial::PORT.borrow_mut().init();
arch::x86_64::sse::enable_sse();
arch::x86_64::paging::setup();

enable_sse();
paging::setup();
#[cfg(feature = "coreboot")]
let info = &coreboot::StartInfo::default();

let info = coreboot::StartInfo::default();
#[cfg(not(feature = "coreboot"))]
let info = pvh_info;

main(&info)
main(info)
}

#[cfg(target_arch = "x86_64")]
fn main(info: &dyn boot::Info) -> ! {
log!("\nBooting with {}", info.name());

Expand Down
31 changes: 22 additions & 9 deletions src/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,31 @@
// limitations under the License.

use atomic_refcell::AtomicRefCell;

#[cfg(target_arch = "x86_64")]
use x86_64::instructions::port::{PortReadOnly, PortWriteOnly};

use crate::{
mem,
virtio::{Error as VirtioError, VirtioTransport},
};

const MAX_BUSES: u8 = 8;
const MAX_DEVICES: u8 = 32;
const MAX_FUNCTIONS: u8 = 8;

const INVALID_VENDOR_ID: u16 = 0xffff;

static PCI_CONFIG: AtomicRefCell<PciConfig> = AtomicRefCell::new(PciConfig::new());

#[cfg(target_arch = "x86_64")]
struct PciConfig {
address_port: PortWriteOnly<u32>,
data_port: PortReadOnly<u32>,
}

impl PciConfig {
#[cfg(target_arch = "x86_64")]
const fn new() -> Self {
// We use the legacy, port-based Configuration Access Mechanism (CAM).
Self {
Expand All @@ -41,15 +46,8 @@ impl PciConfig {
}
}

fn read(&mut self, bus: u8, device: u8, func: u8, offset: u8) -> u32 {
assert_eq!(offset % 4, 0);
assert!(device < MAX_DEVICES);
assert!(func < MAX_FUNCTIONS);

let addr = u32::from(bus) << 16; // bus bits 23-16
let addr = addr | u32::from(device) << 11; // slot/device bits 15-11
let addr = addr | u32::from(func) << 8; // function bits 10-8
let addr = addr | u32::from(offset & 0xfc); // register 7-0
#[cfg(target_arch = "x86_64")]
fn read_at(&mut self, addr: u32) -> u32 {
let addr = addr | 1u32 << 31; // enable bit 31

// SAFETY: We have exclusive access to the ports, so the data read will
Expand All @@ -59,6 +57,21 @@ impl PciConfig {
self.data_port.read()
}
}

fn read(&mut self, bus: u8, device: u8, func: u8, offset: u8) -> u32 {
assert_eq!(offset % 4, 0);
assert!(bus < MAX_BUSES);
assert!(device < MAX_DEVICES);
assert!(func < MAX_FUNCTIONS);

let mut addr = 0;
addr |= u32::from(bus) << 16; // bus bits 23-16
addr |= u32::from(device) << 11; // slot/device bits 15-11
addr |= u32::from(func) << 8; // function bits 10-8
addr |= u32::from(offset & 0xfc); // register 7-0

self.read_at(addr)
}
}

fn get_device_details(bus: u8, device: u8, func: u8) -> (u16, u16) {
Expand Down
Loading