Dedup some more code between x86 and x86_64
This commit is contained in:
+2
-5
@@ -1,3 +1,5 @@
|
||||
pub use crate::arch::x86_shared::*;
|
||||
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
|
||||
@@ -37,11 +39,6 @@ pub mod rmm;
|
||||
/// Initialization and start function
|
||||
pub mod start;
|
||||
|
||||
/// Stop function
|
||||
pub mod stop;
|
||||
|
||||
pub mod time;
|
||||
|
||||
use crate::{memory::PAGE_SIZE, Bootstrap};
|
||||
use ::rmm::Arch;
|
||||
pub use ::rmm::X86Arch as CurrentRmmArch;
|
||||
|
||||
@@ -2,6 +2,8 @@ use crate::Bootstrap;
|
||||
|
||||
use self::paging::PAGE_SIZE;
|
||||
|
||||
pub use crate::arch::x86_shared::*;
|
||||
|
||||
pub mod alternative;
|
||||
|
||||
#[macro_use]
|
||||
@@ -46,11 +48,6 @@ pub mod rmm;
|
||||
/// Initialization and start function
|
||||
pub mod start;
|
||||
|
||||
/// Stop function
|
||||
pub mod stop;
|
||||
|
||||
pub mod time;
|
||||
|
||||
use ::rmm::Arch;
|
||||
pub use ::rmm::X8664Arch as CurrentRmmArch;
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::{context, scheme::acpi, time};
|
||||
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn kreset() -> ! {
|
||||
println!("kreset");
|
||||
|
||||
// 8042 reset
|
||||
{
|
||||
println!("Reset with 8042");
|
||||
let mut port = Pio::<u8>::new(0x64);
|
||||
while port.readf(2) {}
|
||||
port.write(0xFE);
|
||||
}
|
||||
|
||||
emergency_reset();
|
||||
}
|
||||
|
||||
pub unsafe fn emergency_reset() -> ! {
|
||||
// Use triple fault to guarantee reset
|
||||
core::arch::asm!(
|
||||
"
|
||||
cli
|
||||
lidt cs:0
|
||||
int $3
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
fn userspace_acpi_shutdown() {
|
||||
log::info!("Notifying any potential ACPI driver");
|
||||
// Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e.
|
||||
// shutdown).
|
||||
if !acpi::register_kstop() {
|
||||
// There was no context to switch to.
|
||||
log::info!("No ACPI driver was alive to handle shutdown.");
|
||||
return;
|
||||
}
|
||||
log::info!("Waiting one second for ACPI driver to run the shutdown sequence.");
|
||||
let initial = time::monotonic();
|
||||
|
||||
// Since this driver is a userspace process, and we do not use any magic like directly
|
||||
// context switching, we have to wait for the userspace driver to complete, with a timeout.
|
||||
//
|
||||
// We switch context, and wait for one second.
|
||||
loop {
|
||||
// TODO: Switch directly to whichever process is handling the kstop pipe. We would add an
|
||||
// event flag like EVENT_DIRECT, which has already been suggested for IRQs.
|
||||
// TODO: Waitpid with timeout? Because, what if the ACPI driver would crash?
|
||||
let _ = unsafe { context::switch() };
|
||||
|
||||
let current = time::monotonic();
|
||||
if current - initial > time::NANOS_PER_SEC {
|
||||
log::info!("Timeout reached, thus falling back to other shutdown methods.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn kstop() -> ! {
|
||||
log::info!("Running kstop()");
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
userspace_acpi_shutdown();
|
||||
|
||||
// Magic shutdown code for bochs and qemu (older versions).
|
||||
for c in "Shutdown".bytes() {
|
||||
let port = 0x8900;
|
||||
println!("Shutdown with outb(0x{:X}, '{}')", port, c as char);
|
||||
Pio::<u8>::new(port).write(c);
|
||||
}
|
||||
|
||||
// Magic shutdown using qemu default ACPI method
|
||||
{
|
||||
let port = 0x604;
|
||||
let data = 0x2000;
|
||||
println!("Shutdown with outb(0x{:X}, 0x{:X})", port, data);
|
||||
Pio::<u16>::new(port).write(data);
|
||||
}
|
||||
|
||||
// Magic code for VMWare. Also a hard lock.
|
||||
println!("Shutdown with cli hlt");
|
||||
loop {
|
||||
core::arch::asm!("cli; hlt");
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#[cfg(feature = "acpi")]
|
||||
use super::device::hpet;
|
||||
use super::device::pit;
|
||||
|
||||
pub fn counter() -> u128 {
|
||||
#[cfg(feature = "acpi")]
|
||||
if let Some(ref hpet) = *crate::acpi::ACPI_TABLE.hpet.read() {
|
||||
//TODO: handle rollover?
|
||||
//TODO: improve performance
|
||||
|
||||
// Current count
|
||||
let counter = unsafe { hpet.base_address.read_u64(hpet::MAIN_COUNTER_OFFSET) };
|
||||
// Comparator holds next interrupt count
|
||||
let comparator = unsafe { hpet.base_address.read_u64(hpet::T0_COMPARATOR_OFFSET) };
|
||||
// Get period in femtoseconds
|
||||
let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };
|
||||
|
||||
// There seems to be a bug in qemu on macos that causes the calculation to produce 0 for
|
||||
// period_fs and hence a divide by zero calculating the divisor - workaround it while we
|
||||
// try and get a fix from qemu: https://gitlab.com/qemu-project/qemu/-/issues/1570
|
||||
let mut period_fs = capability >> 32;
|
||||
if period_fs == 0 {
|
||||
period_fs = 10_000_000;
|
||||
}
|
||||
|
||||
// Calculate divisor
|
||||
let divisor = (pit::RATE as u64 * 1_000_000) / period_fs;
|
||||
// Calculate last interrupt
|
||||
let last_interrupt = comparator.saturating_sub(divisor);
|
||||
// Calculate ticks since last interrupt
|
||||
let elapsed = counter.saturating_sub(last_interrupt);
|
||||
// Calculate nanoseconds since last interrupt
|
||||
return (elapsed as u128 * period_fs as u128) / 1_000_000;
|
||||
}
|
||||
|
||||
// Read ticks since last interrupt
|
||||
let elapsed = unsafe { pit::read() };
|
||||
// Calculate nanoseconds since last interrupt
|
||||
(elapsed as u128 * pit::PERIOD_FS) / 1_000_000
|
||||
}
|
||||
@@ -1 +1,7 @@
|
||||
/// Devices
|
||||
pub mod device;
|
||||
|
||||
/// Stop function
|
||||
pub mod stop;
|
||||
|
||||
pub mod time;
|
||||
|
||||
Reference in New Issue
Block a user