1use ffi::{
2 console::{
3 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL,
4 EFI_SIMPLE_TEXT_INPUT_PROTOCOL,
5 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL,
6 EFI_KEY_DATA,
7 EFI_INPUT_KEY,
8 EFI_SHIFT_STATE_VALID,
9 EFI_LEFT_CONTROL_PRESSED,
10 EFI_RIGHT_CONTROL_PRESSED,
11 EFI_BLACK,
12 EFI_BLUE,
13 EFI_GREEN,
14 EFI_CYAN,
15 EFI_RED,
16 EFI_MAGENTA,
17 EFI_BROWN,
18 EFI_LIGHTGRAY,
19 EFI_DARKGRAY,
20 EFI_LIGHTBLUE,
21 EFI_LIGHTGREEN,
22 EFI_LIGHTCYAN,
23 EFI_LIGHTRED,
24 EFI_LIGHTMAGENTA,
25 EFI_YELLOW,
26 EFI_WHITE,
27 EFI_BACKGROUND_BLACK,
28 EFI_BACKGROUND_BLUE,
29 EFI_BACKGROUND_GREEN,
30 EFI_BACKGROUND_CYAN,
31 EFI_BACKGROUND_RED,
32 EFI_BACKGROUND_MAGENTA,
33 EFI_BACKGROUND_BROWN,
34 EFI_BACKGROUND_LIGHTGRAY,
35 },
36 IsSuccess,
37 UINTN,
38 TRUE,
39 FALSE,
40};
41use core::{cmp, mem::transmute};
42use crate::{SystemTable, io::{self, Write, Cursor, BufRead, BufReader, LineWriter}};
43use crate::Result;
44use crate::system_table;
45use crate::TextInputProcolPtr;
46use alloc::{vec::Vec, string::String, str, fmt};
47
48#[derive(Debug, Copy, Clone)]
52#[repr(usize)]
53pub enum ForeColor {
54 Black = EFI_BLACK,
55 Blue = EFI_BLUE,
56 Green = EFI_GREEN,
57 Cyan = EFI_CYAN,
58 Red = EFI_RED,
59 Magenta = EFI_MAGENTA,
60 Brown = EFI_BROWN,
61 LightGray = EFI_LIGHTGRAY,
62 DarkGray = EFI_DARKGRAY,
63 LightBlue = EFI_LIGHTBLUE,
64 LightGreen = EFI_LIGHTGREEN,
65 LightCyan = EFI_LIGHTCYAN,
66 LightRed = EFI_LIGHTRED,
67 LightMagenta = EFI_LIGHTMAGENTA,
68 Yellow = EFI_YELLOW,
69 White = EFI_WHITE,
70}
71
72impl From<UINTN> for ForeColor {
73 fn from(color_num: UINTN) -> Self {
74 match color_num {
75 EFI_BLACK..=EFI_WHITE => unsafe { transmute(color_num) },
76 _ => panic!("Attempt to convert an out-of-range number to ForeColor")
77 }
78 }
79}
80
81impl From<ForeColor> for UINTN {
82 fn from(fore_color: ForeColor) -> UINTN {
83 fore_color as UINTN
84 }
85}
86
87#[derive(Debug, Copy, Clone)]
88#[repr(usize)]
89pub enum BackColor {
90 Black = EFI_BACKGROUND_BLACK,
91 Blue = EFI_BACKGROUND_BLUE,
92 Green = EFI_BACKGROUND_GREEN,
93 Cyan = EFI_BACKGROUND_CYAN,
94 Red = EFI_BACKGROUND_RED,
95 Magenta = EFI_BACKGROUND_MAGENTA,
96 Brown = EFI_BACKGROUND_BROWN,
97 LightGray = EFI_BACKGROUND_LIGHTGRAY,
98}
99
100impl From<UINTN> for BackColor {
101 fn from(color_num: UINTN) -> Self {
102 match color_num {
103 EFI_BACKGROUND_BLACK..=EFI_BACKGROUND_LIGHTGRAY => unsafe { transmute(color_num) },
104 _ => panic!("Attempt to convert an out-of-range number to BackColor")
105 }
106 }
107}
108
109impl From<BackColor> for UINTN {
110 fn from(back_color: BackColor) -> UINTN {
111 back_color as UINTN
112 }
113}
114
115pub struct Console {
116 pub input: TextInputProcolPtr,
117 pub output: *const EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL,
118 utf8_buf: io::Cursor<Vec<u8>>
119}
120
121const LF: u16 = 10;
122const CR: u16 = 13;
123const BS: u16 = 8;
124
125impl Console {
126 pub fn new(input: TextInputProcolPtr, output: *const EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL) -> Self {
127 Self { input, output, utf8_buf: Cursor::new(Vec::new()) }
128 }
129
130 pub fn cursor_pos(&self) -> Position {
131 let mode = unsafe { (*(*self).output).Mode };
132 Position { row: unsafe { (*mode).CursorRow } as u32, col: unsafe { (*mode).CursorColumn } as u32 } }
134
135 pub fn set_cursor_pos(&self, pos: Position) -> Result<()> {
136 unsafe {
137 ret_on_err!(((*(*self).output).SetCursorPosition)(self.output, pos.col as usize, pos.row as usize));
138 }
139
140 Ok(())
141 }
142
143 pub fn enable_cursor(&mut self) -> Result<()> {
144 unsafe {
145 ret_on_err!(((*(*self).output).EnableCursor)(self.output, TRUE));
146 }
147
148 Ok(())
149 }
150
151 pub fn disable_cursor(&mut self) -> Result<()> {
152 unsafe {
153 ret_on_err!(((*(*self).output).EnableCursor)(self.output, FALSE));
154 }
155
156 Ok(())
157 }
158
159 pub fn clear_screen(&mut self) -> Result<()> {
160 unsafe {
161 ret_on_err!(((*(*self).output).ClearScreen)(self.output));
162 }
163
164 Ok(())
165 }
166
167 pub fn max_supported_mode(&mut self) -> u32 {
171 unsafe { (*(*(*self).output).Mode).MaxMode as u32 } }
173
174 pub fn set_mode(&mut self, mode_number: u32) -> Result<()> {
175 unsafe {
176 ret_on_err!(((*(*self).output).SetMode)(self.output, mode_number as usize)); }
178
179 Ok(())
180 }
181
182 pub fn fore_color(&mut self) -> ForeColor {
183 let attribute = unsafe { (*(*(*self).output).Mode).Attribute } as UINTN; let fore_color_num = attribute & 0b1111; fore_color_num.into()
187 }
188
189 pub fn set_fore_color(&mut self, fore_color: ForeColor) -> Result<()> {
190 let curr_attribute = unsafe { (*(*(*self).output).Mode).Attribute } as UINTN; let curr_back_color = curr_attribute & 0b1111_0000; let new_attribute = usize::from(fore_color) | curr_back_color;
193
194 unsafe {
195 ret_on_err!(((*(*self).output).SetAttribute)(self.output, new_attribute));
196 }
197
198 Ok(())
199 }
200
201 pub fn back_color(&mut self) -> BackColor {
202 let attribute = unsafe { (*(*(*self).output).Mode).Attribute } as UINTN; let back_color_num = attribute & 0b1111_0000; back_color_num.into()
206 }
207
208 pub fn set_back_color(&mut self, back_color: BackColor) -> Result<()> {
209 let curr_attribute = unsafe { (*(*(*self).output).Mode).Attribute } as UINTN; let curr_fore_color = curr_attribute & 0b1111; let new_attribute = curr_fore_color | usize::from(back_color);
212
213 unsafe {
214 ret_on_err!(((*(*self).output).SetAttribute)(self.output, new_attribute));
215 }
216
217 Ok(())
218 }
219
220 pub fn reset(&mut self, extended_verification: bool) -> Result<()> {
221 unsafe {
222 ret_on_err!(((*(*self).output).Reset)(self.output, if extended_verification { TRUE } else { FALSE }));
223 }
224
225 Ok(())
226 }
227
228 fn write_to_efi(&self, buf: &[u16]) -> Result<()> {
229 unsafe {
230 let (ptr, _) = to_ptr(buf);
231 ret_on_err!(((*(*self).output).OutputString)(self.output, ptr));
232 Ok(())
233 }
234 }
235
236 fn read_from_efi(&self, buf: &mut [u16]) -> Result<usize> {
237 match self.input {
238 TextInputProcolPtr::Input(input) => self.read_from_efi_input(buf, input),
239 TextInputProcolPtr::InputEx(input_ex) => self.read_from_efi_input_ex(buf, input_ex),
240 }
241 }
242
243 fn read_from_efi_input_ex(&self, buf: &mut [u16], input_ex: *mut EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL) -> Result<usize> {
245 let mut bytes_read = 0;
246
247 let mut evt_index: UINTN = 0;
248 let mut key_data = EFI_KEY_DATA::default();
249 let mut evt_list = unsafe { [(*input_ex).WaitForKeyEx; 1] };
250
251 while bytes_read < buf.len() {
252 let status = unsafe { ((*system_table().BootServices).WaitForEvent)(evt_list.len(), evt_list.as_mut_ptr(), &mut evt_index) };
254 if !IsSuccess(status) {
255 return Err(status.into()); }
257
258 let status = unsafe { ((*input_ex).ReadKeyStrokeEx)(input_ex, &mut key_data) };
260 if !IsSuccess(status) {
261 return Err(status.into()); }
263
264 fn is_ctr_z(key_data: &EFI_KEY_DATA) -> bool {
265 (key_data.Key.UnicodeChar == 'z' as u16 || key_data.Key.UnicodeChar == 'Z' as u16) &&
266 (key_data.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0 &&
267 ((key_data.KeyState.KeyShiftState & EFI_LEFT_CONTROL_PRESSED) != 0 || (key_data.KeyState.KeyShiftState & EFI_RIGHT_CONTROL_PRESSED) != 0)
268 }
269
270 if key_data.Key.UnicodeChar != 0 { if key_data.Key.UnicodeChar == CR { key_data.Key.UnicodeChar = LF; }
274
275 match key_data.Key.UnicodeChar {
276 BS => {
277 if bytes_read > 0 {
278 bytes_read -= 1;
279 self.write_to_efi(&[BS, 0])?; }
281 },
282 c => {
283 if is_ctr_z(&key_data) {
284 break;
285 } else {
286 buf[bytes_read] = c;
287 bytes_read += 1;
288
289 if c == LF {
290 self.write_to_efi(&[CR, LF, 0])?; break;
292 } else {
293 self.write_to_efi(&[c, 0])?;
294 }
295 }
296 }
297 };
298 } else {
299 }
301
302 }
304
305 Ok(bytes_read)
306 }
307
308 fn read_from_efi_input(&self, buf: &mut [u16], input: *mut EFI_SIMPLE_TEXT_INPUT_PROTOCOL) -> Result<usize> {
309 let mut bytes_read = 0;
310
311 let mut evt_index: UINTN = 0;
312 let mut key_data = EFI_INPUT_KEY::default();
313 let mut evt_list = unsafe { [(*input).WaitForKey; 1] };
314
315 while bytes_read < buf.len() {
316 let status = unsafe { ((*system_table().BootServices).WaitForEvent)(evt_list.len(), evt_list.as_mut_ptr(), &mut evt_index) };
318 if !IsSuccess(status) {
319 return Err(status.into()); }
321
322 let status = unsafe { ((*input).ReadKeyStroke)(input, &mut key_data) };
324 if !IsSuccess(status) {
325 return Err(status.into()); }
327
328 if key_data.UnicodeChar != 0 { if key_data.UnicodeChar == CR { key_data.UnicodeChar = LF; }
332
333 match key_data.UnicodeChar {
334 BS => {
335 if bytes_read > 0 {
336 bytes_read -= 1;
337 self.write_to_efi(&[BS, 0])?; }
339 },
340 c => {
341 buf[bytes_read] = c;
342 bytes_read += 1;
343
344 if c == LF {
345 self.write_to_efi(&[CR, LF, 0])?; break;
347 } else {
348 self.write_to_efi(&[c, 0])?;
349 }
350 }
351 };
352 } else {
353 }
355
356 }
358
359 Ok(bytes_read)
360 }
361
362}
363
364impl io::Write for Console {
366 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
370 const WRITE_BUFSIZE: usize = 8192;
371 let bytes_to_write = cmp::min(buf.len(), WRITE_BUFSIZE);
372 let utf8_buf = match str::from_utf8(&buf[..bytes_to_write]) {
373 Ok(str_) => str_,
374 Err(ref e) if e.valid_up_to() == 0 => return Err(invalid_encoding()),
375 Err(e) => str::from_utf8(&buf[..e.valid_up_to()]).unwrap(), };
377
378 let utf16_iter = utf8_buf.encode_utf16();
381 let mut expected_utf16_buf_size = utf16_iter.size_hint().1.unwrap_or(utf8_buf.len()); let five_percent = (expected_utf16_buf_size as f32 * 0.05) as usize;
383 let extra_size_for_line_endings = cmp::max(5, five_percent); expected_utf16_buf_size += extra_size_for_line_endings; let mut utf16_buf = Vec::with_capacity(expected_utf16_buf_size);
386
387 let mut last_c = 0_u16;
388 for (i, c) in utf16_iter.enumerate() {
389 if c == LF && (i == 0 || last_c != CR) { utf16_buf.push(CR);
391 }
392 utf16_buf.push(c);
393 last_c = c;
394 }
395
396 utf16_buf.push(0); self.write_to_efi(&utf16_buf)
399 .map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to write to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL"))?; Ok(utf8_buf.len())
402 }
403
404 fn flush(&mut self) -> io::Result<()> {
405 Ok(()) }
407}
408
409
410impl io::Read for Console {
411 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
412 if self.utf8_buf.position() as usize == self.utf8_buf.get_ref().len() {
414 let mut utf16_buf = vec![0u16; 0x1000];
415 let bytes_read = self.read_from_efi(&mut utf16_buf).map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to read from EFI_SIMPLE_TEXT_INPUT_PROTOCOL"))?; utf16_buf.truncate(bytes_read as usize);
417 let data = match String::from_utf16(&utf16_buf) {
419 Ok(utf8_buf) => utf8_buf.into_bytes(),
420 Err(..) => return Err(invalid_encoding()),
421 };
422
423 self.utf8_buf = Cursor::new(data);
424 }
425
426 self.utf8_buf.read(buf)
428 }
429}
430
431pub struct StdIn(BufReader<Console>);
433
434impl StdIn {
435 fn new(c: Console) -> Self {
436 StdIn(BufReader::new(c))
437 }
438}
439
440impl io::Read for StdIn {
441 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
442 self.0.read(buf)
443 }
444}
445
446impl BufRead for StdIn {
447 fn fill_buf(&mut self) -> io::Result<&[u8]> { self.0.fill_buf() }
448 fn consume(&mut self, n: usize) { self.0.consume(n) }
449}
450
451pub struct StdOut(LineWriter<Console>);
452
453impl StdOut {
454 fn new(c: Console) -> Self {
455 StdOut(LineWriter::new(c))
456 }
457}
458
459impl io::Write for StdOut {
460 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
461 self.0.write(buf)
462 }
463
464 fn flush(&mut self) -> io::Result<()> {
465 self.0.flush()
466 }
467}
468
469#[derive(Debug, Copy, Clone)]
470pub struct Position {
471 pub row: u32,
472 pub col: u32
473}
474
475pub fn console() -> Console {
476 SystemTable::new(system_table())
477 .expect("failed to create system table").console()
478}
479
480pub fn stdin() -> StdIn {
483 StdIn::new(console())
484}
485
486pub fn stdout() -> StdOut {
487 StdOut::new(console())
488}
489
490#[macro_export]
491macro_rules! println {
492 ($fmt:expr) => (print!(concat!($fmt, "\n")));
493 ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
494}
495
496#[macro_export]
497macro_rules! print {
498 ($($arg:tt)*) => ($crate::console::print_args(format_args!($($arg)*)));
499}
500
501pub fn print_args(args: fmt::Arguments) {
503 return stdout().write_fmt(args).expect("Failed to write to stdout")
504}
505
506
507fn invalid_encoding() -> io::Error {
508 io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
509}
510
511fn to_ptr<T>(slice: &[T]) -> (*const T, usize) {
512 unsafe {
513 transmute(slice)
514 }
515}