summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rsdos/src/main.rs3
-rw-r--r--rsnix/src/lib.rs1
-rw-r--r--rsnix/src/power.rs48
-rw-r--r--rsnix/src/uefi.rs34
-rw-r--r--shell/src/lib.rs22
5 files changed, 97 insertions, 11 deletions
diff --git a/rsdos/src/main.rs b/rsdos/src/main.rs
index 1169785..d9578e2 100644
--- a/rsdos/src/main.rs
+++ b/rsdos/src/main.rs
@@ -37,6 +37,9 @@ pub extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemT
37 let bs = unsafe { &mut *st.boot_services }; 37 let bs = unsafe { &mut *st.boot_services };
38 let con_out = unsafe { &mut *st.con_out }; 38 let con_out = unsafe { &mut *st.con_out };
39 39
40 // Keep the runtime-services table for later (ResetSystem → poweroff).
41 rsnix::power::init(st.runtime_services);
42
40 // ---- Phase 1: UEFI boot services alive ---- 43 // ---- Phase 1: UEFI boot services alive ----
41 44
42 // Print banner via UEFI console 45 // Print banner via UEFI console
diff --git a/rsnix/src/lib.rs b/rsnix/src/lib.rs
index d2dacf0..8c69b35 100644
--- a/rsnix/src/lib.rs
+++ b/rsnix/src/lib.rs
@@ -7,6 +7,7 @@ pub mod gop;
7pub mod interrupts; 7pub mod interrupts;
8pub mod memory; 8pub mod memory;
9pub mod paging; 9pub mod paging;
10pub mod power;
10pub mod ps2; 11pub mod ps2;
11pub mod serial; 12pub mod serial;
12pub mod uefi; 13pub mod uefi;
diff --git a/rsnix/src/power.rs b/rsnix/src/power.rs
new file mode 100644
index 0000000..cb5d296
--- /dev/null
+++ b/rsnix/src/power.rs
@@ -0,0 +1,48 @@
1// ---------------------------------------------------------------------------
2// Power — halt loop and ACPI shutdown via the UEFI ResetSystem runtime
3// service.
4//
5// The firmware's runtime-services table is stashed before ExitBootServices
6// (`init`). Because we never call SetVirtualAddressMap, the service
7// pointers keep working with physical (identity) addresses after EBS, so
8// poweroff() can ask the firmware to shut the machine down (ACPI S5) — on
9// QEMU this makes the VM exit, on real hardware the power drops.
10// ---------------------------------------------------------------------------
11
12use crate::uefi::{RuntimeServices, EFI_SUCCESS, RESET_SHUTDOWN};
13
14static mut RUNTIME_SERVICES: *mut RuntimeServices = core::ptr::null_mut();
15
16/// Stash the runtime-services table pointer (call in Phase 1, pre-EBS).
17pub fn init(rt: *mut RuntimeServices) {
18 unsafe {
19 RUNTIME_SERVICES = rt;
20 }
21}
22
23/// Halt the CPU forever (interrupts off, hlt loop).
24pub fn halt() -> ! {
25 loop {
26 unsafe {
27 core::arch::asm!("cli; hlt", options(nomem, nostack));
28 }
29 }
30}
31
32/// Shut the machine down through `ResetSystem(EfiResetShutdown)`. Falls
33/// back to `halt()` if no table was saved or the call failed.
34pub fn poweroff() -> ! {
35 unsafe {
36 let rt = RUNTIME_SERVICES;
37 if rt.is_null() {
38 halt();
39 }
40 let reset = (*rt).reset_system;
41 if reset as usize == 0 {
42 halt();
43 }
44 (reset)(RESET_SHUTDOWN, EFI_SUCCESS, 0, core::ptr::null());
45 // ResetSystem only returns on failure.
46 halt()
47 }
48}
diff --git a/rsnix/src/uefi.rs b/rsnix/src/uefi.rs
index 619739e..b1b5e48 100644
--- a/rsnix/src/uefi.rs
+++ b/rsnix/src/uefi.rs
@@ -86,12 +86,42 @@ pub struct SimpleTextInput {
86} 86}
87 87
88// --------------------------------------------------------------------------- 88// ---------------------------------------------------------------------------
89// Runtime services (stub — we don't use them) 89// Runtime services
90// --------------------------------------------------------------------------- 90// ---------------------------------------------------------------------------
91
92/// `EFI_RESET_SYSTEM` — ResetType, ResetStatus, DataSize, ResetData.
93/// ResetType: 0 cold, 1 warm, 2 shutdown, 3 platform-specific.
94pub type EfiResetSystem =
95 unsafe extern "efiapi" fn(u32, u64, usize, *const u16) -> Status;
96
97pub const RESET_COLD: u32 = 0;
98#[allow(dead_code)]
99pub const RESET_WARM: u32 = 1;
100pub const RESET_SHUTDOWN: u32 = 2;
101#[allow(dead_code)]
102pub const RESET_PLATFORM_SPECIFIC: u32 = 3;
103
104/// EFI_RUNTIME_SERVICES — function pointers in spec order after the header.
105/// We only use ResetSystem; the rest stay opaque. The table remains
106/// callable after ExitBootServices because we never call SetVirtualAddressMap,
107/// so the pointers keep working with physical (identity) addresses.
91#[repr(C)] 108#[repr(C)]
92pub struct RuntimeServices { 109pub struct RuntimeServices {
93 _hdr: TableHeader, 110 _hdr: TableHeader,
94 _reserved: [*mut c_void; 30], 111 _get_time: *mut c_void, // 0
112 _set_time: *mut c_void, // 1
113 _get_wakeup_time: *mut c_void, // 2
114 _set_wakeup_time: *mut c_void, // 3
115 _set_virtual_address_map: *mut c_void, // 4
116 _convert_pointer: *mut c_void, // 5
117 _get_variable: *mut c_void, // 6
118 _get_next_variable_name: *mut c_void, // 7
119 _set_variable: *mut c_void, // 8
120 _get_next_high_monotonic_count: *mut c_void, // 9
121 pub reset_system: EfiResetSystem, // 10
122 _update_capsule: *mut c_void, // 11
123 _query_capsule_capabilities: *mut c_void, // 12
124 _query_variable_info: *mut c_void, // 13
95} 125}
96 126
97// --------------------------------------------------------------------------- 127// ---------------------------------------------------------------------------
diff --git a/shell/src/lib.rs b/shell/src/lib.rs
index 4d5ba9c..5cab122 100644
--- a/shell/src/lib.rs
+++ b/shell/src/lib.rs
@@ -40,7 +40,8 @@ pub fn run() -> ! {
40 "help" => cmd_help(), 40 "help" => cmd_help(),
41 "echo" => cmd_echo(args), 41 "echo" => cmd_echo(args),
42 "clear" => cmd_clear(), 42 "clear" => cmd_clear(),
43 "halt" | "poweroff" | "exit" => cmd_halt(), 43 "halt" => cmd_halt(),
44 "poweroff" | "exit" => cmd_poweroff(),
44 "hello" => { 45 "hello" => {
45 gop_println!("World!"); 46 gop_println!("World!");
46 serial_println!("World!"); 47 serial_println!("World!");
@@ -123,10 +124,11 @@ fn cmd_help() {
123 gop_println!(" mem — show memory info"); 124 gop_println!(" mem — show memory info");
124 gop_println!(" mmap — dump the UEFI memory map"); 125 gop_println!(" mmap — dump the UEFI memory map");
125 gop_println!(" stress — stress-test heap/page allocators"); 126 gop_println!(" stress — stress-test heap/page allocators");
126 gop_println!(" halt — halt the system"); 127 gop_println!(" halt — halt the system (hlt loop)");
127 gop_println!(" exit — alias for halt"); 128 gop_println!(" poweroff — shut down via ACPI (ResetSystem)");
129 gop_println!(" exit — alias for poweroff");
128 serial_println!("available commands:"); 130 serial_println!("available commands:");
129 serial_println!(" help, echo, clear, hello, info, mem, mmap, stress, halt, exit"); 131 serial_println!(" help, echo, clear, hello, info, mem, mmap, stress, halt, poweroff, exit");
130} 132}
131 133
132fn cmd_echo(args: &str) { 134fn cmd_echo(args: &str) {
@@ -359,11 +361,13 @@ fn cmd_stress(args: &str) {
359fn cmd_halt() -> ! { 361fn cmd_halt() -> ! {
360 gop_println!("halting..."); 362 gop_println!("halting...");
361 serial_println!("halting..."); 363 serial_println!("halting...");
362 loop { 364 rsnix::power::halt()
363 unsafe { 365}
364 core::arch::asm!("cli; hlt"); 366
365 } 367fn cmd_poweroff() -> ! {
366 } 368 gop_println!("shutting down...");
369 serial_println!("shutting down...");
370 rsnix::power::poweroff()
367} 371}
368 372
369// --------------------------------------------------------------------------- 373// ---------------------------------------------------------------------------