Skip to content

Commit addd6e1

Browse files
authored
Merge pull request #1031 from nicholasbishop/bishop-fix-output-again
Fix logger connection after opening serial protocol
2 parents 0ebf422 + 18a01a3 commit addd6e1

File tree

6 files changed

+76
-4
lines changed

6 files changed

+76
-4
lines changed

uefi-test-runner/src/main.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ extern crate log;
77
extern crate alloc;
88

99
use alloc::string::ToString;
10+
use alloc::vec::Vec;
1011
use uefi::prelude::*;
1112
use uefi::proto::console::serial::Serial;
13+
use uefi::proto::device_path::build::{self, DevicePathBuilder};
14+
use uefi::proto::device_path::messaging::Vendor;
1215
use uefi::table::boot::MemoryType;
1316
use uefi::Result;
1417
use uefi_services::{print, println};
@@ -112,6 +115,33 @@ fn send_request_helper(serial: &mut Serial, request: HostRequest) -> Result {
112115
}
113116
}
114117

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+
115145
/// Send the `request` string to the host via the `serial` device, then
116146
/// wait up to 10 seconds to receive a reply. Returns an error if the
117147
/// reply is not `"OK\n"`.
@@ -145,7 +175,7 @@ fn send_request_to_host(bt: &BootServices, request: HostRequest) {
145175
// device, which was broken when we opened the protocol in exclusive
146176
// mode above.
147177
drop(serial);
148-
let _ = bt.connect_controller(serial_handle, None, None, true);
178+
reconnect_serial_to_console(bt, serial_handle);
149179

150180
if let Err(err) = res {
151181
panic!("request failed: \"{request:?}\": {:?}", err.status());
@@ -156,13 +186,18 @@ fn shutdown(mut st: SystemTable<Boot>) -> ! {
156186
// Get our text output back.
157187
st.stdout().reset(false).unwrap();
158188

159-
info!("Testing complete, shutting down...");
160-
161189
// Tell the host that tests are done. We are about to exit boot
162190
// services, so we can't easily communicate with the host any later
163191
// than this.
164192
send_request_to_host(st.boot_services(), HostRequest::TestsComplete);
165193

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+
166201
// Exit boot services as a proof that it works :)
167202
let (st, _iter) = st.exit_boot_services(MemoryType::LOADER_DATA);
168203

uefi-test-runner/src/proto/console/serial.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::reconnect_serial_to_console;
12
use uefi::proto::console::serial::{ControlBits, Serial};
23
use uefi::table::boot::BootServices;
34
use uefi::{Result, ResultExt, Status};
@@ -66,7 +67,7 @@ pub unsafe fn test(bt: &BootServices) {
6667
// device, which was broken when we opened the protocol in exclusive
6768
// mode above.
6869
drop(serial);
69-
let _ = bt.connect_controller(handle, None, None, true);
70+
reconnect_serial_to_console(bt, handle);
7071

7172
if let Err(err) = res {
7273
panic!("serial test failed: {:?}", err.status());

uefi/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Added
44
- Implemented `PartialEq<char>` for `Char8` and `Char16`.
55
- Added `CStr16::from_char16_with_nul` and `Char16::from_char16_with_nul_unchecked`.
6+
- Added terminal GUID constants to `device_path::messaging::Vendor`.
67

78
## Changed
89
- `DevicePath::to_string` and `DevicePathNode::to_string` now return

uefi/src/proto/device_path/device_path_gen.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,6 +2413,17 @@ pub mod messaging {
24132413

24142414
}
24152415

2416+
impl Vendor {
2417+
/// PC-ANSI terminal GUID.
2418+
pub const PC_ANSI: Guid = guid!("e0c14753-f9be-11d2-9a0c-0090273fc14d");
2419+
/// VT-100 terminal GUID.
2420+
pub const VT_100: Guid = guid!("dfa66065-b419-11d3-9a2d-0090273fc14d");
2421+
/// VT-100+ terminal GUID.
2422+
pub const VT_100_PLUS: Guid = guid!("7baec70b-57e0-4c76-8e87-2f9e28088343");
2423+
/// VT-UTF8 terminal GUID.
2424+
pub const VT_UTF8: Guid = guid!("ad15a0d6-8bec-4acf-a073-d01de77e2d88");
2425+
}
2426+
24162427
newtype_enum! { # [doc = " iSCSI network protocol."] pub enum IscsiProtocol : u16 => { # [doc = " TCP."] TCP = 0x0000 , }
24172428

24182429
}

xtask/src/device_path/spec.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,20 @@ mod messaging {
686686
vendor_defined_data: [u8],
687687
}
688688

689+
impl Vendor {
690+
/// PC-ANSI terminal GUID.
691+
pub const PC_ANSI: Guid = guid!("e0c14753-f9be-11d2-9a0c-0090273fc14d");
692+
693+
/// VT-100 terminal GUID.
694+
pub const VT_100: Guid = guid!("dfa66065-b419-11d3-9a2d-0090273fc14d");
695+
696+
/// VT-100+ terminal GUID.
697+
pub const VT_100_PLUS: Guid = guid!("7baec70b-57e0-4c76-8e87-2f9e28088343");
698+
699+
/// VT-UTF8 terminal GUID.
700+
pub const VT_UTF8: Guid = guid!("ad15a0d6-8bec-4acf-a073-d01de77e2d88");
701+
}
702+
689703
// The spec defines a couple specific messaging-vendor types here,
690704
// one for UART and one for SAS. These are sort of subclasses of
691705
// `messaging::Vendor` so they don't quite fit the usual pattern of

xtask/src/qemu.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ impl Io {
311311

312312
fn process_qemu_io(mut monitor_io: Io, mut serial_io: Io, tmp_dir: &Path) -> Result<()> {
313313
let mut tests_complete = false;
314+
let mut logging_still_working_right_before_ebs = false;
314315

315316
// This regex is used to detect and strip ANSI escape codes. These
316317
// escapes are added by the console output protocol when writing to
@@ -371,6 +372,11 @@ fn process_qemu_io(mut monitor_io: Io, mut serial_io: Io, tmp_dir: &Path) -> Res
371372
tests_complete = true;
372373

373374
reply_ok()?;
375+
} else if line.ends_with("LOGGING_STILL_WORKING_RIGHT_BEFORE_EBS") {
376+
// The app sends this right before calling
377+
// `exit_boot_services`. This serves as a test that we didn't break
378+
// logging by opening the serial device in exclusive mode.
379+
logging_still_working_right_before_ebs = true;
374380
} else {
375381
println!("{line}");
376382
}
@@ -380,6 +386,10 @@ fn process_qemu_io(mut monitor_io: Io, mut serial_io: Io, tmp_dir: &Path) -> Res
380386
bail!("tests did not complete successfully");
381387
}
382388

389+
if !logging_still_working_right_before_ebs {
390+
bail!("logging stopped working sometime before exiting boot services");
391+
}
392+
383393
Ok(())
384394
}
385395

0 commit comments

Comments
 (0)