@@ -7,8 +7,11 @@ extern crate log;
7
7
extern crate alloc;
8
8
9
9
use alloc:: string:: ToString ;
10
+ use alloc:: vec:: Vec ;
10
11
use uefi:: prelude:: * ;
11
12
use uefi:: proto:: console:: serial:: Serial ;
13
+ use uefi:: proto:: device_path:: build:: { self , DevicePathBuilder } ;
14
+ use uefi:: proto:: device_path:: messaging:: Vendor ;
12
15
use uefi:: table:: boot:: MemoryType ;
13
16
use uefi:: Result ;
14
17
use uefi_services:: { print, println} ;
@@ -112,6 +115,33 @@ fn send_request_helper(serial: &mut Serial, request: HostRequest) -> Result {
112
115
}
113
116
}
114
117
118
+ /// Reconnect the serial device to the output console.
119
+ ///
120
+ /// This must be called after opening the serial protocol in exclusive mode, as
121
+ /// that breaks the connection to the console, which in turn prevents logs from
122
+ /// getting to the host.
123
+ fn reconnect_serial_to_console ( boot_services : & BootServices , serial_handle : Handle ) {
124
+ let mut storage = Vec :: new ( ) ;
125
+ // Create a device path that specifies the terminal type.
126
+ let terminal_guid = if cfg ! ( target_arch = "aarch64" ) {
127
+ Vendor :: VT_100
128
+ } else {
129
+ Vendor :: VT_UTF8
130
+ } ;
131
+ let terminal_device_path = DevicePathBuilder :: with_vec ( & mut storage)
132
+ . push ( & build:: messaging:: Vendor {
133
+ vendor_guid : terminal_guid,
134
+ vendor_defined_data : & [ ] ,
135
+ } )
136
+ . unwrap ( )
137
+ . finalize ( )
138
+ . unwrap ( ) ;
139
+
140
+ boot_services
141
+ . connect_controller ( serial_handle, None , Some ( terminal_device_path) , true )
142
+ . expect ( "failed to reconnect serial to console" ) ;
143
+ }
144
+
115
145
/// Send the `request` string to the host via the `serial` device, then
116
146
/// wait up to 10 seconds to receive a reply. Returns an error if the
117
147
/// reply is not `"OK\n"`.
@@ -145,7 +175,7 @@ fn send_request_to_host(bt: &BootServices, request: HostRequest) {
145
175
// device, which was broken when we opened the protocol in exclusive
146
176
// mode above.
147
177
drop ( serial) ;
148
- let _ = bt . connect_controller ( serial_handle , None , None , true ) ;
178
+ reconnect_serial_to_console ( bt , serial_handle ) ;
149
179
150
180
if let Err ( err) = res {
151
181
panic ! ( "request failed: \" {request:?}\" : {:?}" , err. status( ) ) ;
@@ -156,13 +186,18 @@ fn shutdown(mut st: SystemTable<Boot>) -> ! {
156
186
// Get our text output back.
157
187
st. stdout ( ) . reset ( false ) . unwrap ( ) ;
158
188
159
- info ! ( "Testing complete, shutting down..." ) ;
160
-
161
189
// Tell the host that tests are done. We are about to exit boot
162
190
// services, so we can't easily communicate with the host any later
163
191
// than this.
164
192
send_request_to_host ( st. boot_services ( ) , HostRequest :: TestsComplete ) ;
165
193
194
+ // Send a special log to the host so that we can verify that logging works
195
+ // up until exiting boot services. See `reconnect_serial_to_console` for the
196
+ // type of regression this prevents.
197
+ info ! ( "LOGGING_STILL_WORKING_RIGHT_BEFORE_EBS" ) ;
198
+
199
+ info ! ( "Testing complete, shutting down..." ) ;
200
+
166
201
// Exit boot services as a proof that it works :)
167
202
let ( st, _iter) = st. exit_boot_services ( MemoryType :: LOADER_DATA ) ;
168
203
0 commit comments