@@ -91,9 +91,11 @@ impl Command {
9191 }
9292
9393 pub fn output ( & mut self ) -> io:: Result < ( ExitStatus , Vec < u8 > , Vec < u8 > ) > {
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 ( ) ?;
9596 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 ( ) ) )
9799 }
98100}
99101
@@ -246,20 +248,30 @@ impl<'a> fmt::Debug for CommandArgs<'a> {
246248}
247249
248250mod uefi_command_internal {
251+ use r_efi:: protocols:: { loaded_image, simple_text_output} ;
252+
249253 use super :: super :: helpers;
250- use crate :: ffi:: OsStr ;
254+ use crate :: ffi:: { OsStr , OsString } ;
251255 use crate :: io:: { self , const_io_error} ;
252256 use crate :: mem:: MaybeUninit ;
253257 use crate :: os:: uefi:: env:: { boot_services, image_handle} ;
258+ use crate :: os:: uefi:: ffi:: OsStringExt ;
254259 use crate :: ptr:: NonNull ;
260+ use crate :: slice;
261+ use crate :: sys_common:: wstr:: WStrUnits ;
255262
256263 pub struct Command {
257264 handle : NonNull < crate :: ffi:: c_void > ,
265+ stdout : Option < helpers:: Protocol < PipeProtocol > > ,
266+ st : Box < r_efi:: efi:: SystemTable > ,
258267 }
259268
260269 impl Command {
261- const fn new ( handle : NonNull < crate :: ffi:: c_void > ) -> Self {
262- Self { handle }
270+ const fn new (
271+ handle : NonNull < crate :: ffi:: c_void > ,
272+ st : Box < r_efi:: efi:: SystemTable > ,
273+ ) -> Self {
274+ Self { handle, stdout : None , st }
263275 }
264276
265277 pub fn load_image ( p : & OsStr ) -> io:: Result < Self > {
@@ -286,7 +298,17 @@ mod uefi_command_internal {
286298 } else {
287299 let child_handle = unsafe { child_handle. assume_init ( ) } ;
288300 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) )
290312 }
291313 }
292314
@@ -313,6 +335,32 @@ mod uefi_command_internal {
313335
314336 Ok ( r)
315337 }
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 < u8 > > {
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+ }
316364 }
317365
318366 impl Drop for Command {
@@ -325,4 +373,134 @@ mod uefi_command_internal {
325373 }
326374 }
327375 }
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 < u16 > ,
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+ }
328506}
0 commit comments