uefi: process: Add support to capture stdout · model-checking/verify-rust-std@b712e74 (original) (raw)
`@@ -91,9 +91,11 @@ impl Command {
`
91
91
`}
`
92
92
``
93
93
`pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> {
`
94
``
`-
let cmd = uefi_command_internal::Command::load_image(&self.prog)?;
`
``
94
`+
let mut cmd = uefi_command_internal::Command::load_image(&self.prog)?;
`
``
95
`+
cmd.stdout_init()?;
`
95
96
`let stat = cmd.start_image()?;
`
96
``
`-
Ok((ExitStatus(stat), Vec::new(), Vec::new()))
`
``
97
`+
let stdout = cmd.stdout()?;
`
``
98
`+
Ok((ExitStatus(stat), stdout, Vec::new()))
`
97
99
`}
`
98
100
`}
`
99
101
``
`@@ -246,20 +248,30 @@ impl<'a> fmt::Debug for CommandArgs<'a> {
`
246
248
`}
`
247
249
``
248
250
`mod uefi_command_internal {
`
``
251
`+
use r_efi::protocols::{loaded_image, simple_text_output};
`
``
252
+
249
253
`use super::super::helpers;
`
250
``
`-
use crate::ffi::OsStr;
`
``
254
`+
use crate::ffi::{OsStr, OsString};
`
251
255
`use crate::io::{self, const_io_error};
`
252
256
`use crate::mem::MaybeUninit;
`
253
257
`use crate::os::uefi::env::{boot_services, image_handle};
`
``
258
`+
use crate::os::uefi::ffi::OsStringExt;
`
254
259
`use crate::ptr::NonNull;
`
``
260
`+
use crate::slice;
`
``
261
`+
use crate::sys_common::wstr::WStrUnits;
`
255
262
``
256
263
`pub struct Command {
`
257
264
`handle: NonNullcrate::ffi::c_void,
`
``
265
`+
stdout: Option<helpers::Protocol>,
`
``
266
`+
st: Box<r_efi::efi::SystemTable>,
`
258
267
`}
`
259
268
``
260
269
`impl Command {
`
261
``
`-
const fn new(handle: NonNullcrate::ffi::c_void) -> Self {
`
262
``
`-
Self { handle }
`
``
270
`+
const fn new(
`
``
271
`+
handle: NonNullcrate::ffi::c_void,
`
``
272
`+
st: Box<r_efi::efi::SystemTable>,
`
``
273
`+
) -> Self {
`
``
274
`+
Self { handle, stdout: None, st }
`
263
275
`}
`
264
276
``
265
277
`pub fn load_image(p: &OsStr) -> io::Result {
`
`@@ -286,7 +298,17 @@ mod uefi_command_internal {
`
286
298
`} else {
`
287
299
`let child_handle = unsafe { child_handle.assume_init() };
`
288
300
`let child_handle = NonNull::new(child_handle).unwrap();
`
289
``
`-
Ok(Self::new(child_handle))
`
``
301
+
``
302
`+
let loaded_image: NonNull<loaded_image::Protocol> =
`
``
303
`+
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
`
``
304
`+
let mut st: Box<r_efi::efi::SystemTable> =
`
``
305
`+
Box::new(unsafe { crate::ptr::read((*loaded_image.as_ptr()).system_table) });
`
``
306
+
``
307
`+
unsafe {
`
``
308
`+
(*loaded_image.as_ptr()).system_table = st.as_mut();
`
``
309
`+
}
`
``
310
+
``
311
`+
Ok(Self::new(child_handle, st))
`
290
312
`}
`
291
313
`}
`
292
314
``
`@@ -313,6 +335,32 @@ mod uefi_command_internal {
`
313
335
``
314
336
`Ok(r)
`
315
337
`}
`
``
338
+
``
339
`+
pub fn stdout_init(&mut self) -> io::Result<()> {
`
``
340
`+
let mut protocol =
`
``
341
`+
helpers::Protocol::create(PipeProtocol::new(), simple_text_output::PROTOCOL_GUID)?;
`
``
342
+
``
343
`+
self.st.console_out_handle = protocol.handle().as_ptr();
`
``
344
`+
self.st.con_out =
`
``
345
`+
protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol;
`
``
346
+
``
347
`+
self.stdout = Some(protocol);
`
``
348
+
``
349
`+
Ok(())
`
``
350
`+
}
`
``
351
+
``
352
`+
pub fn stdout(&self) -> io::Result<Vec> {
`
``
353
`+
if let Some(stdout) = &self.stdout {
`
``
354
`+
stdout
`
``
355
`+
.as_ref()
`
``
356
`+
.utf8()
`
``
357
`+
.into_string()
`
``
358
`+
.map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed"))
`
``
359
`+
.map(Into::into)
`
``
360
`+
} else {
`
``
361
`+
Err(const_io_error!(io::ErrorKind::NotFound, "stdout not found"))
`
``
362
`+
}
`
``
363
`+
}
`
316
364
`}
`
317
365
``
318
366
`impl Drop for Command {
`
`@@ -325,4 +373,134 @@ mod uefi_command_internal {
`
325
373
`}
`
326
374
`}
`
327
375
`}
`
``
376
+
``
377
`+
#[repr(C)]
`
``
378
`+
struct PipeProtocol {
`
``
379
`+
reset: simple_text_output::ProtocolReset,
`
``
380
`+
output_string: simple_text_output::ProtocolOutputString,
`
``
381
`+
test_string: simple_text_output::ProtocolTestString,
`
``
382
`+
query_mode: simple_text_output::ProtocolQueryMode,
`
``
383
`+
set_mode: simple_text_output::ProtocolSetMode,
`
``
384
`+
set_attribute: simple_text_output::ProtocolSetAttribute,
`
``
385
`+
clear_screen: simple_text_output::ProtocolClearScreen,
`
``
386
`+
set_cursor_position: simple_text_output::ProtocolSetCursorPosition,
`
``
387
`+
enable_cursor: simple_text_output::ProtocolEnableCursor,
`
``
388
`+
mode: *mut simple_text_output::Mode,
`
``
389
`+
_mode: Box<simple_text_output::Mode>,
`
``
390
`+
_buffer: Vec,
`
``
391
`+
}
`
``
392
+
``
393
`+
impl PipeProtocol {
`
``
394
`+
fn new() -> Self {
`
``
395
`+
let mut mode = Box::new(simple_text_output::Mode {
`
``
396
`+
max_mode: 0,
`
``
397
`+
mode: 0,
`
``
398
`+
attribute: 0,
`
``
399
`+
cursor_column: 0,
`
``
400
`+
cursor_row: 0,
`
``
401
`+
cursor_visible: r_efi::efi::Boolean::FALSE,
`
``
402
`+
});
`
``
403
`+
Self {
`
``
404
`+
reset: Self::reset,
`
``
405
`+
output_string: Self::output_string,
`
``
406
`+
test_string: Self::test_string,
`
``
407
`+
query_mode: Self::query_mode,
`
``
408
`+
set_mode: Self::set_mode,
`
``
409
`+
set_attribute: Self::set_attribute,
`
``
410
`+
clear_screen: Self::clear_screen,
`
``
411
`+
set_cursor_position: Self::set_cursor_position,
`
``
412
`+
enable_cursor: Self::enable_cursor,
`
``
413
`+
mode: mode.as_mut(),
`
``
414
`+
_mode: mode,
`
``
415
`+
_buffer: Vec::new(),
`
``
416
`+
}
`
``
417
`+
}
`
``
418
+
``
419
`+
fn utf8(&self) -> OsString {
`
``
420
`+
OsString::from_wide(&self._buffer)
`
``
421
`+
}
`
``
422
+
``
423
`+
extern "efiapi" fn reset(
`
``
424
`+
proto: *mut simple_text_output::Protocol,
`
``
425
`+
_: r_efi::efi::Boolean,
`
``
426
`+
) -> r_efi::efi::Status {
`
``
427
`+
let proto: *mut PipeProtocol = proto.cast();
`
``
428
`+
unsafe {
`
``
429
`+
(*proto)._buffer.clear();
`
``
430
`+
}
`
``
431
`+
r_efi::efi::Status::SUCCESS
`
``
432
`+
}
`
``
433
+
``
434
`+
extern "efiapi" fn output_string(
`
``
435
`+
proto: *mut simple_text_output::Protocol,
`
``
436
`+
buf: *mut r_efi::efi::Char16,
`
``
437
`+
) -> r_efi::efi::Status {
`
``
438
`+
let proto: *mut PipeProtocol = proto.cast();
`
``
439
`+
let buf_len = unsafe {
`
``
440
`+
if let Some(x) = WStrUnits::new(buf) {
`
``
441
`+
x.count()
`
``
442
`+
} else {
`
``
443
`+
return r_efi::efi::Status::INVALID_PARAMETER;
`
``
444
`+
}
`
``
445
`+
};
`
``
446
`+
let buf_slice = unsafe { slice::from_raw_parts(buf, buf_len) };
`
``
447
+
``
448
`+
unsafe {
`
``
449
`+
(*proto)._buffer.extend_from_slice(buf_slice);
`
``
450
`+
};
`
``
451
+
``
452
`+
r_efi::efi::Status::SUCCESS
`
``
453
`+
}
`
``
454
+
``
455
`+
extern "efiapi" fn test_string(
`
``
456
`+
_: *mut simple_text_output::Protocol,
`
``
457
`+
_: *mut r_efi::efi::Char16,
`
``
458
`+
) -> r_efi::efi::Status {
`
``
459
`+
r_efi::efi::Status::SUCCESS
`
``
460
`+
}
`
``
461
+
``
462
`+
extern "efiapi" fn query_mode(
`
``
463
`+
_: *mut simple_text_output::Protocol,
`
``
464
`+
_: usize,
`
``
465
`+
_: *mut usize,
`
``
466
`+
_: *mut usize,
`
``
467
`+
) -> r_efi::efi::Status {
`
``
468
`+
r_efi::efi::Status::UNSUPPORTED
`
``
469
`+
}
`
``
470
+
``
471
`+
extern "efiapi" fn set_mode(
`
``
472
`+
_: *mut simple_text_output::Protocol,
`
``
473
`+
_: usize,
`
``
474
`+
) -> r_efi::efi::Status {
`
``
475
`+
r_efi::efi::Status::UNSUPPORTED
`
``
476
`+
}
`
``
477
+
``
478
`+
extern "efiapi" fn set_attribute(
`
``
479
`+
_: *mut simple_text_output::Protocol,
`
``
480
`+
_: usize,
`
``
481
`+
) -> r_efi::efi::Status {
`
``
482
`+
r_efi::efi::Status::UNSUPPORTED
`
``
483
`+
}
`
``
484
+
``
485
`+
extern "efiapi" fn clear_screen(
`
``
486
`+
_: *mut simple_text_output::Protocol,
`
``
487
`+
) -> r_efi::efi::Status {
`
``
488
`+
r_efi::efi::Status::UNSUPPORTED
`
``
489
`+
}
`
``
490
+
``
491
`+
extern "efiapi" fn set_cursor_position(
`
``
492
`+
_: *mut simple_text_output::Protocol,
`
``
493
`+
_: usize,
`
``
494
`+
_: usize,
`
``
495
`+
) -> r_efi::efi::Status {
`
``
496
`+
r_efi::efi::Status::UNSUPPORTED
`
``
497
`+
}
`
``
498
+
``
499
`+
extern "efiapi" fn enable_cursor(
`
``
500
`+
_: *mut simple_text_output::Protocol,
`
``
501
`+
_: r_efi::efi::Boolean,
`
``
502
`+
) -> r_efi::efi::Status {
`
``
503
`+
r_efi::efi::Status::UNSUPPORTED
`
``
504
`+
}
`
``
505
`+
}
`
328
506
`}
`