Skip to content

Commit 9f38058

Browse files
committed
Split off UI from OS and redesign it.
This gets rid of the last parts of the OS struct.
1 parent c2ea82d commit 9f38058

15 files changed

Lines changed: 689 additions & 441 deletions

File tree

pixie-shared/src/util.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,42 @@ pub struct BytesFmt(pub u64);
22

33
impl core::fmt::Display for BytesFmt {
44
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5+
let w = f.width().unwrap_or(0);
6+
let prc = f.precision().unwrap_or(2);
57
if self.0 < 1 << 10 {
6-
write!(f, "{} B", self.0)
8+
write!(f, "{:1$} B", self.0, w.saturating_sub(2))
79
} else if self.0 < 1 << 20 {
8-
write!(f, "{:.2} KiB", self.0 as f64 / (1i64 << 10) as f64)
10+
write!(
11+
f,
12+
"{:1$.2$} KiB",
13+
self.0 as f64 / (1i64 << 10) as f64,
14+
w.saturating_sub(4),
15+
prc
16+
)
917
} else if self.0 < 1 << 30 {
10-
write!(f, "{:.2} MiB", self.0 as f64 / (1i64 << 20) as f64)
18+
write!(
19+
f,
20+
"{:1$.2$} MiB",
21+
self.0 as f64 / (1i64 << 20) as f64,
22+
w.saturating_sub(4),
23+
prc
24+
)
1125
} else if self.0 < 1 << 40 {
12-
write!(f, "{:.2} GiB", self.0 as f64 / (1i64 << 30) as f64)
26+
write!(
27+
f,
28+
"{:1$.2$} GiB",
29+
self.0 as f64 / (1i64 << 30) as f64,
30+
w.saturating_sub(4),
31+
prc
32+
)
1333
} else {
14-
write!(f, "{:.2} TiB", self.0 as f64 / (1i64 << 40) as f64)
34+
write!(
35+
f,
36+
"{:1$.2$} TiB",
37+
self.0 as f64 / (1i64 << 40) as f64,
38+
w.saturating_sub(4),
39+
prc
40+
)
1541
}
1642
}
1743
}

pixie-uefi/src/flash.rs

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use alloc::collections::BTreeMap;
33
use alloc::rc::Rc;
44
use alloc::vec::Vec;
55
use core::cell::RefCell;
6+
use core::fmt::Write;
67
use core::mem;
78
use core::net::SocketAddrV4;
89

@@ -12,13 +13,12 @@ use lz4_flex::decompress;
1213
use pixie_shared::chunk_codec::Decoder;
1314
use pixie_shared::util::BytesFmt;
1415
use pixie_shared::{ChunkHash, Image, TcpRequest, UdpRequest, CHUNKS_PORT, MAX_CHUNK_SIZE};
15-
use uefi::proto::console::text::Color;
1616

1717
use crate::os::boot_options::BootOptions;
1818
use crate::os::error::{Error, Result};
1919
use crate::os::executor::Executor;
2020
use crate::os::net::{TcpStream, UdpSocket, ETH_PACKET_SIZE};
21-
use crate::os::{disk, memory, UefiOS};
21+
use crate::os::{disk, memory};
2222
use crate::MIN_MEMORY;
2323

2424
async fn fetch_image(stream: &TcpStream) -> Result<Image> {
@@ -75,7 +75,7 @@ fn handle_packet(
7575
Ok(Some((pos, data)))
7676
}
7777

78-
pub async fn flash(os: UefiOS, server_addr: SocketAddrV4) -> Result<()> {
78+
pub async fn flash(server_addr: SocketAddrV4) -> Result<()> {
7979
let stream = TcpStream::connect(server_addr).await?;
8080
let image = fetch_image(&stream).await?;
8181
stream.shutdown().await;
@@ -103,37 +103,14 @@ pub async fn flash(os: UefiOS, server_addr: SocketAddrV4) -> Result<()> {
103103
}));
104104

105105
let stats2 = stats.clone();
106-
os.set_ui_drawer(move |os| {
107-
os.write_with_color(
108-
&format!("{} total chunks\n", stats2.borrow().chunks),
109-
Color::White,
110-
Color::Black,
111-
);
112-
os.write_with_color(
113-
&format!("{} unique chunks\n", stats2.borrow().unique),
114-
Color::White,
115-
Color::Black,
116-
);
117-
os.write_with_color(
118-
&format!("{} chunks to fetch\n", stats2.borrow().fetch),
119-
Color::White,
120-
Color::Black,
121-
);
122-
os.write_with_color(
123-
&format!("{} chunks received\n", stats2.borrow().recv),
124-
Color::White,
125-
Color::Black,
126-
);
127-
os.write_with_color(
128-
&format!("{} packets received\n", stats2.borrow().pack_recv),
129-
Color::White,
130-
Color::Black,
131-
);
132-
os.write_with_color(
133-
&format!("{} chunks requested\n", stats2.borrow().requested),
134-
Color::White,
135-
Color::Black,
136-
);
106+
crate::os::ui::set_content_drawer(move |draw_area| {
107+
draw_area.clear();
108+
writeln!(draw_area, "{} total chunks", stats2.borrow().chunks).unwrap();
109+
writeln!(draw_area, "{} unique chunks", stats2.borrow().unique).unwrap();
110+
writeln!(draw_area, "{} chunks to fetch", stats2.borrow().fetch).unwrap();
111+
writeln!(draw_area, "{} chunks received", stats2.borrow().recv).unwrap();
112+
writeln!(draw_area, "{} packets received", stats2.borrow().pack_recv).unwrap();
113+
writeln!(draw_area, "{} chunks requested", stats2.borrow().requested).unwrap();
137114
});
138115

139116
let mut disk = disk::Disk::largest();

pixie-uefi/src/main.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use crate::flash::flash;
1616
use crate::os::error::{Error, Result};
1717
use crate::os::executor::Executor;
1818
use crate::os::net::{TcpStream, UdpSocket, ETH_PACKET_SIZE};
19-
use crate::os::UefiOS;
2019
use crate::register::register;
2120
use crate::store::store;
2221

@@ -96,7 +95,7 @@ async fn complete_action(stream: &TcpStream) -> Result<()> {
9695
Ok(())
9796
}
9897

99-
async fn run(os: UefiOS) -> Result<()> {
98+
async fn run() -> Result<()> {
10099
let server = server_discover().await?;
101100

102101
let mut last_was_wait = false;
@@ -114,7 +113,7 @@ async fn run(os: UefiOS) -> Result<()> {
114113

115114
loop {
116115
// Clear any UI drawer.
117-
os.set_ui_drawer(|_| {});
116+
os::ui::set_content_drawer(|_| {});
118117

119118
if !last_was_wait {
120119
log::debug!("Sending request for command");
@@ -147,9 +146,9 @@ async fn run(os: UefiOS) -> Result<()> {
147146
Action::Boot => power_control::reboot_to_os().await,
148147
Action::Restart => {}
149148
Action::Shutdown => shutdown().await,
150-
Action::Register => register(os, server).await?,
151-
Action::Store => store(os, server).await?,
152-
Action::Flash => flash(os, server).await?,
149+
Action::Register => register(server).await?,
150+
Action::Store => store(server).await?,
151+
Action::Flash => flash(server).await?,
153152
}
154153

155154
let tcp = TcpStream::connect(server).await?;
@@ -167,5 +166,5 @@ async fn run(os: UefiOS) -> Result<()> {
167166

168167
#[entry]
169168
fn main() -> Status {
170-
UefiOS::start(run)
169+
os::start(run)
171170
}

pixie-uefi/src/os/disk.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ use uefi::boot::{OpenProtocolParams, ScopedProtocol};
77
use uefi::proto::media::block::BlockIO;
88
use uefi::Handle;
99

10-
use crate::os::executor::Executor;
11-
1210
use super::error::Result;
11+
use crate::os::executor::Executor;
1312

1413
fn open_disk(handle: Handle) -> Result<ScopedProtocol<BlockIO>> {
1514
let image_handle = uefi::boot::image_handle();

pixie-uefi/src/os/executor.rs

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,28 @@ use alloc::collections::VecDeque;
33
use alloc::sync::Arc;
44
use alloc::task::Wake;
55
use alloc::vec::Vec;
6+
use core::fmt::Write;
67
use core::future::{poll_fn, Future};
78
use core::pin::Pin;
89
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
910
use core::task::{Context, Poll, Waker};
11+
1012
use spin::Mutex;
1113
use uefi::boot::{EventType, TimerTrigger, Tpl};
14+
use uefi::proto::console::text::Color;
1215

16+
use crate::os::send_wrapper::SendWrapper;
1317
use crate::os::timer::Timer;
18+
use crate::os::ui::DrawArea;
1419

15-
struct BoxFuture(Pin<Box<dyn Future<Output = ()> + 'static>>);
16-
17-
// SAFETY: there are no threads.
18-
unsafe impl Send for BoxFuture {}
20+
struct BoxFuture(SendWrapper<Pin<Box<dyn Future<Output = ()> + 'static>>>);
1921

2022
struct Task {
2123
name: &'static str,
2224
in_queue: AtomicBool,
2325
future: Mutex<BoxFuture>,
2426
micros: AtomicU64,
27+
last_micros: AtomicU64,
2528
}
2629

2730
impl Task {
@@ -31,8 +34,9 @@ impl Task {
3134
{
3235
Arc::new(Task {
3336
name,
34-
future: Mutex::new(BoxFuture(Box::pin(future))),
37+
future: Mutex::new(BoxFuture(SendWrapper(Box::pin(future)))),
3538
micros: AtomicU64::new(0),
39+
last_micros: AtomicU64::new(0),
3640
in_queue: AtomicBool::new(false),
3741
})
3842
}
@@ -57,8 +61,98 @@ pub struct Executor {
5761
tasks: Vec<Arc<Task>>,
5862
}
5963

64+
pub(super) const TASK_LEN: usize = 34;
65+
6066
impl Executor {
67+
async fn draw_tasks() {
68+
let mut draw_area = DrawArea::tasks();
69+
let (w, h) = draw_area.size();
70+
assert!((w - 1).is_multiple_of(TASK_LEN + 1));
71+
let num_w = (w - 1) / (TASK_LEN + 1);
72+
let mut last = Timer::micros() as u64;
73+
Self::sleep_us(100_000).await;
74+
loop {
75+
draw_area.clear();
76+
let cur = Timer::micros() as u64;
77+
let elapsed = cur.saturating_sub(last).max(1) as f64;
78+
{
79+
let mut executor = EXECUTOR.lock();
80+
let tasks = &mut executor.tasks;
81+
// Sort by *descending* time used since last draw.
82+
tasks.sort_unstable_by_key(|f| {
83+
f.last_micros.load(Ordering::Relaxed) as i64
84+
- f.micros.load(Ordering::Relaxed) as i64
85+
});
86+
87+
write!(draw_area, "\u{250C}").unwrap();
88+
for x in 0..num_w {
89+
for _ in 0..TASK_LEN {
90+
write!(draw_area, "\u{2500}").unwrap();
91+
}
92+
if x + 1 == num_w {
93+
write!(draw_area, "\u{2510}").unwrap();
94+
} else {
95+
write!(draw_area, "\u{252C}").unwrap();
96+
}
97+
}
98+
draw_area.newline();
99+
for y in 0..(h - 2) {
100+
write!(draw_area, "\u{2502}").unwrap();
101+
for x in 0..num_w {
102+
let idx = x * h + y;
103+
if idx >= tasks.len() {
104+
draw_area.advance(TASK_LEN);
105+
} else {
106+
let task = &tasks[idx];
107+
let total_cpu = task.micros.load(Ordering::Relaxed);
108+
let last_cpu = task.last_micros.load(Ordering::Relaxed);
109+
let frac = ((total_cpu - last_cpu) as f64 / elapsed).min(1.0);
110+
draw_area.write_with_color(
111+
&format!(
112+
" {:15}{:5.1}%{:10.3}s ",
113+
&task.name[..task.name.len().min(15)],
114+
frac * 100.0,
115+
total_cpu as f64 * 0.000_001,
116+
),
117+
if frac >= 0.5 {
118+
Color::Red
119+
} else if frac >= 0.1 {
120+
Color::Yellow
121+
} else {
122+
Color::White
123+
},
124+
Color::Black,
125+
);
126+
}
127+
write!(draw_area, "\u{2502}").unwrap();
128+
}
129+
draw_area.newline();
130+
}
131+
write!(draw_area, "\u{2514}").unwrap();
132+
for x in 0..num_w {
133+
for _ in 0..TASK_LEN {
134+
write!(draw_area, "\u{2500}").unwrap();
135+
}
136+
if x + 1 == num_w {
137+
write!(draw_area, "\u{2518}").unwrap();
138+
} else {
139+
write!(draw_area, "\u{2534}").unwrap();
140+
}
141+
}
142+
draw_area.newline();
143+
144+
for t in tasks.iter() {
145+
t.last_micros
146+
.store(t.micros.load(Ordering::Relaxed), Ordering::Relaxed);
147+
}
148+
}
149+
last = Timer::micros() as u64;
150+
Self::sleep_us(1_000_000).await;
151+
}
152+
}
153+
61154
pub fn run() -> ! {
155+
Self::spawn("[show_tasks]", Self::draw_tasks());
62156
loop {
63157
let task = EXECUTOR
64158
.lock()
@@ -126,16 +220,4 @@ impl Executor {
126220
executor.tasks.push(task.clone());
127221
executor.ready_tasks.push_back(task);
128222
}
129-
130-
pub fn top_tasks(n: usize) -> Vec<(u64, &'static str)> {
131-
let mut tasks: Vec<_> = EXECUTOR
132-
.lock()
133-
.tasks
134-
.iter()
135-
.map(|x| (x.micros.load(Ordering::Relaxed), x.name))
136-
.collect();
137-
tasks.sort_by_key(|t| -(t.0 as i64));
138-
tasks.truncate(n);
139-
tasks
140-
}
141223
}

pixie-uefi/src/os/input.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use core::future::{poll_fn, Future};
2+
use core::task::Poll;
3+
4+
use spin::lazy::Lazy;
5+
use spin::Mutex;
6+
use uefi::boot::ScopedProtocol;
7+
use uefi::proto::console::text::{Input, Key};
8+
9+
use crate::os::error::Result;
10+
use crate::os::send_wrapper::SendWrapper;
11+
12+
static INPUT: Lazy<Mutex<SendWrapper<ScopedProtocol<Input>>>> = Lazy::new(|| {
13+
let input_handles = uefi::boot::find_handles::<Input>().unwrap();
14+
let input = uefi::boot::open_protocol_exclusive::<Input>(input_handles[0]).unwrap();
15+
Mutex::new(SendWrapper(input))
16+
});
17+
18+
pub fn read_key() -> impl Future<Output = Result<Key>> {
19+
poll_fn(move |cx| {
20+
let key = INPUT.lock().read_key();
21+
match key {
22+
Err(e) => Poll::Ready(Err(e.into())),
23+
Ok(Some(key)) => Poll::Ready(Ok(key)),
24+
Ok(None) => {
25+
cx.waker().wake_by_ref();
26+
Poll::Pending
27+
}
28+
}
29+
})
30+
}

0 commit comments

Comments
 (0)