Skip to content

Commit c458cb6

Browse files
authoredApr 18, 2025··
Merge pull request #1614 from kraxel/http
add ip4config2 + http protocols support
2 parents 16f248f + e782459 commit c458cb6

File tree

8 files changed

+672
-0
lines changed

8 files changed

+672
-0
lines changed
 

‎uefi-test-runner/https/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
https ca cert database in efi signature list format
2+
3+
Copied over from centos stream 9 where this is available as
4+
/etc/pki/ca-trust/extracted/edk2/cacerts.bin
5+
6+
It's the Mozilla Foundation CA certificate list, shipped in
7+
ca-certificates.rpm, licensed as "MIT AND GPL-2.0-or-later".

‎uefi-test-runner/https/cacerts.bin

160 KB
Binary file not shown.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
use alloc::vec::Vec;
4+
5+
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
6+
use uefi::proto::device_path::DevicePath;
7+
use uefi::proto::network::http::{HttpBinding, HttpHelper};
8+
use uefi::proto::network::ip4config2::Ip4Config2;
9+
use uefi::{boot, Handle};
10+
11+
use uefi_raw::protocol::network::http::HttpStatusCode;
12+
13+
pub fn print_handle_devpath(prefix: &str, handle: &Handle) {
14+
let Ok(dp) = boot::open_protocol_exclusive::<DevicePath>(*handle) else {
15+
info!("{}no device path for handle", prefix);
16+
return;
17+
};
18+
if let Ok(string) = dp.to_string(DisplayOnly(true), AllowShortcuts(true)) {
19+
info!("{}{}", prefix, string);
20+
}
21+
}
22+
23+
fn fetch_http(handle: Handle, url: &str) -> Option<Vec<u8>> {
24+
info!("http: fetching {} ...", url);
25+
26+
let http_res = HttpHelper::new(handle);
27+
if let Err(e) = http_res {
28+
error!("http new: {}", e);
29+
return None;
30+
}
31+
let mut http = http_res.unwrap();
32+
33+
let res = http.configure();
34+
if let Err(e) = res {
35+
error!("http configure: {}", e);
36+
return None;
37+
}
38+
39+
let res = http.request_get(url);
40+
if let Err(e) = res {
41+
error!("http request: {}", e);
42+
return None;
43+
}
44+
45+
let res = http.response_first(true);
46+
if let Err(e) = res {
47+
error!("http response: {}", e);
48+
return None;
49+
}
50+
51+
let rsp = res.unwrap();
52+
if rsp.status != HttpStatusCode::STATUS_200_OK {
53+
error!("http server error: {:?}", rsp.status);
54+
return None;
55+
}
56+
let Some(cl_hdr) = rsp.headers.iter().find(|h| h.0 == "content-length") else {
57+
// The only way to figure when your transfer is complete is to
58+
// get the content length header and count the bytes you got.
59+
// So missing header -> fatal error.
60+
error!("no content length");
61+
return None;
62+
};
63+
let Ok(cl) = cl_hdr.1.parse::<usize>() else {
64+
error!("parse content length ({})", cl_hdr.1);
65+
return None;
66+
};
67+
info!("http: size is {} bytes", cl);
68+
69+
let mut data = rsp.body;
70+
loop {
71+
if data.len() >= cl {
72+
break;
73+
}
74+
75+
let res = http.response_more();
76+
if let Err(e) = res {
77+
error!("read response: {}", e);
78+
return None;
79+
}
80+
81+
let mut buf = res.unwrap();
82+
data.append(&mut buf);
83+
}
84+
85+
Some(data)
86+
}
87+
88+
pub fn test() {
89+
info!("Testing ip4 config2 + http protocols");
90+
91+
let handles = boot::locate_handle_buffer(boot::SearchType::from_proto::<HttpBinding>())
92+
.expect("get nic handles");
93+
94+
for h in handles.as_ref() {
95+
print_handle_devpath("nic: ", h);
96+
97+
info!("Bring up interface (ip4 config2 protocol)");
98+
let mut ip4 = Ip4Config2::new(*h).expect("open ip4 config2 protocol");
99+
ip4.ifup(true).expect("acquire ipv4 address");
100+
101+
// hard to find web sites which still allow plain http these days ...
102+
info!("Testing HTTP");
103+
fetch_http(*h, "http://example.com/").expect("http request failed");
104+
105+
// FYI: not all firmware builds support modern tls versions.
106+
// request() -> ABORTED typically is a tls handshake error.
107+
// check the firmware log for details.
108+
info!("Testing HTTPS");
109+
fetch_http(
110+
*h,
111+
"https://raw.githubusercontent.com/rust-osdev/uefi-rs/refs/heads/main/Cargo.toml",
112+
)
113+
.expect("https request failed");
114+
115+
info!("PASSED");
116+
}
117+
}

‎uefi-test-runner/src/proto/network/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
pub fn test() {
44
info!("Testing Network protocols");
55

6+
http::test();
67
pxe::test();
78
snp::test();
89
}
910

11+
mod http;
1012
mod pxe;
1113
mod snp;

‎uefi/src/proto/network/http.rs

Lines changed: 383 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,383 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
#![cfg(feature = "alloc")]
4+
5+
//! HTTP Protocol.
6+
//!
7+
//! See [`Http`].
8+
9+
use alloc::string::String;
10+
use alloc::vec;
11+
use alloc::vec::Vec;
12+
use core::ffi::{c_char, c_void, CStr};
13+
use core::ptr;
14+
use log::debug;
15+
16+
use uefi::boot::ScopedProtocol;
17+
use uefi::prelude::*;
18+
use uefi::proto::unsafe_protocol;
19+
use uefi_raw::protocol::driver::ServiceBindingProtocol;
20+
use uefi_raw::protocol::network::http::{
21+
HttpAccessPoint, HttpConfigData, HttpHeader, HttpMessage, HttpMethod, HttpProtocol,
22+
HttpRequestData, HttpResponseData, HttpStatusCode, HttpToken, HttpV4AccessPoint, HttpVersion,
23+
};
24+
25+
/// HTTP [`Protocol`]. Send HTTP Requests.
26+
///
27+
/// [`Protocol`]: uefi::proto::Protocol
28+
#[derive(Debug)]
29+
#[unsafe_protocol(HttpProtocol::GUID)]
30+
pub struct Http(HttpProtocol);
31+
32+
impl Http {
33+
/// Receive HTTP Protocol configuration.
34+
pub fn get_mode_data(&mut self, config_data: &mut HttpConfigData) -> uefi::Result<()> {
35+
let status = unsafe { (self.0.get_mode_data)(&mut self.0, config_data) };
36+
match status {
37+
Status::SUCCESS => Ok(()),
38+
_ => Err(status.into()),
39+
}
40+
}
41+
42+
/// Configure HTTP Protocol. Must be called before sending HTTP requests.
43+
pub fn configure(&mut self, config_data: &HttpConfigData) -> uefi::Result<()> {
44+
let status = unsafe { (self.0.configure)(&mut self.0, config_data) };
45+
match status {
46+
Status::SUCCESS => Ok(()),
47+
_ => Err(status.into()),
48+
}
49+
}
50+
51+
/// Send HTTP request.
52+
pub fn request(&mut self, token: &mut HttpToken) -> uefi::Result<()> {
53+
let status = unsafe { (self.0.request)(&mut self.0, token) };
54+
match status {
55+
Status::SUCCESS => Ok(()),
56+
_ => Err(status.into()),
57+
}
58+
}
59+
60+
/// Cancel HTTP request.
61+
pub fn cancel(&mut self, token: &mut HttpToken) -> uefi::Result<()> {
62+
let status = unsafe { (self.0.cancel)(&mut self.0, token) };
63+
match status {
64+
Status::SUCCESS => Ok(()),
65+
_ => Err(status.into()),
66+
}
67+
}
68+
69+
/// Receive HTTP response.
70+
pub fn response(&mut self, token: &mut HttpToken) -> uefi::Result<()> {
71+
let status = unsafe { (self.0.response)(&mut self.0, token) };
72+
match status {
73+
Status::SUCCESS => Ok(()),
74+
_ => Err(status.into()),
75+
}
76+
}
77+
78+
/// Poll network stack for updates.
79+
pub fn poll(&mut self) -> uefi::Result<()> {
80+
let status = unsafe { (self.0.poll)(&mut self.0) };
81+
match status {
82+
Status::SUCCESS => Ok(()),
83+
_ => Err(status.into()),
84+
}
85+
}
86+
}
87+
88+
/// HTTP Service Binding Protocol.
89+
#[derive(Debug)]
90+
#[unsafe_protocol(HttpProtocol::SERVICE_BINDING_GUID)]
91+
pub struct HttpBinding(ServiceBindingProtocol);
92+
93+
impl HttpBinding {
94+
/// Create HTTP Protocol Handle.
95+
pub fn create_child(&mut self) -> uefi::Result<Handle> {
96+
let mut c_handle = ptr::null_mut();
97+
let status;
98+
let handle;
99+
unsafe {
100+
status = (self.0.create_child)(&mut self.0, &mut c_handle);
101+
handle = Handle::from_ptr(c_handle);
102+
};
103+
match status {
104+
Status::SUCCESS => Ok(handle.unwrap()),
105+
_ => Err(status.into()),
106+
}
107+
}
108+
109+
/// Destroy HTTP Protocol Handle.
110+
pub fn destroy_child(&mut self, handle: Handle) -> uefi::Result<()> {
111+
let status = unsafe { (self.0.destroy_child)(&mut self.0, handle.as_ptr()) };
112+
match status {
113+
Status::SUCCESS => Ok(()),
114+
_ => Err(status.into()),
115+
}
116+
}
117+
}
118+
119+
/// HTTP Response data
120+
#[derive(Debug)]
121+
pub struct HttpHelperResponse {
122+
/// HTTP Status
123+
pub status: HttpStatusCode,
124+
/// HTTP Response Headers
125+
pub headers: Vec<(String, String)>,
126+
/// HTTP Body
127+
pub body: Vec<u8>,
128+
}
129+
130+
/// HTTP Helper, makes using the HTTP protocol more convenient.
131+
#[derive(Debug)]
132+
pub struct HttpHelper {
133+
child_handle: Handle,
134+
binding: ScopedProtocol<HttpBinding>,
135+
protocol: Option<ScopedProtocol<Http>>,
136+
}
137+
138+
impl HttpHelper {
139+
/// Create new HTTP helper instance for the given NIC handle.
140+
pub fn new(nic_handle: Handle) -> uefi::Result<Self> {
141+
let mut binding = unsafe {
142+
boot::open_protocol::<HttpBinding>(
143+
boot::OpenProtocolParams {
144+
handle: nic_handle,
145+
agent: boot::image_handle(),
146+
controller: None,
147+
},
148+
boot::OpenProtocolAttributes::GetProtocol,
149+
)?
150+
};
151+
debug!("http: binding proto ok");
152+
153+
let child_handle = binding.create_child()?;
154+
debug!("http: child handle ok");
155+
156+
let protocol_res = unsafe {
157+
boot::open_protocol::<Http>(
158+
boot::OpenProtocolParams {
159+
handle: child_handle,
160+
agent: boot::image_handle(),
161+
controller: None,
162+
},
163+
boot::OpenProtocolAttributes::GetProtocol,
164+
)
165+
};
166+
if let Err(e) = protocol_res {
167+
let _ = binding.destroy_child(child_handle);
168+
return Err(e);
169+
}
170+
debug!("http: protocol ok");
171+
172+
Ok(Self {
173+
child_handle,
174+
binding,
175+
protocol: Some(protocol_res.unwrap()),
176+
})
177+
}
178+
179+
/// Configure the HTTP Protocol with some sane defaults.
180+
pub fn configure(&mut self) -> uefi::Result<()> {
181+
let ip4 = HttpV4AccessPoint {
182+
use_default_addr: true.into(),
183+
..Default::default()
184+
};
185+
186+
let config = HttpConfigData {
187+
http_version: HttpVersion::HTTP_VERSION_10,
188+
time_out_millisec: 10_000,
189+
local_addr_is_ipv6: false.into(),
190+
access_point: HttpAccessPoint { ipv4_node: &ip4 },
191+
};
192+
193+
self.protocol.as_mut().unwrap().configure(&config)?;
194+
debug!("http: configure ok");
195+
196+
Ok(())
197+
}
198+
199+
/// Send HTTP request
200+
pub fn request(
201+
&mut self,
202+
method: HttpMethod,
203+
url: &str,
204+
body: Option<&mut [u8]>,
205+
) -> uefi::Result<()> {
206+
let url16 = uefi::CString16::try_from(url).unwrap();
207+
208+
let Some(hostname) = url.split('/').nth(2) else {
209+
return Err(Status::INVALID_PARAMETER.into());
210+
};
211+
let mut c_hostname = String::from(hostname);
212+
c_hostname.push('\0');
213+
debug!("http: host: {}", hostname);
214+
215+
let mut tx_req = HttpRequestData {
216+
method,
217+
url: url16.as_ptr().cast::<u16>(),
218+
};
219+
220+
let mut tx_hdr = Vec::new();
221+
tx_hdr.push(HttpHeader {
222+
field_name: c"Host".as_ptr().cast::<u8>(),
223+
field_value: c_hostname.as_ptr(),
224+
});
225+
226+
let mut tx_msg = HttpMessage::default();
227+
tx_msg.data.request = &mut tx_req;
228+
tx_msg.header_count = tx_hdr.len();
229+
tx_msg.header = tx_hdr.as_mut_ptr();
230+
if body.is_some() {
231+
let b = body.unwrap();
232+
tx_msg.body_length = b.len();
233+
tx_msg.body = b.as_mut_ptr().cast::<c_void>();
234+
}
235+
236+
let mut tx_token = HttpToken {
237+
status: Status::NOT_READY,
238+
message: &mut tx_msg,
239+
..Default::default()
240+
};
241+
242+
let p = self.protocol.as_mut().unwrap();
243+
p.request(&mut tx_token)?;
244+
debug!("http: request sent ok");
245+
246+
loop {
247+
if tx_token.status != Status::NOT_READY {
248+
break;
249+
}
250+
p.poll()?;
251+
}
252+
253+
if tx_token.status != Status::SUCCESS {
254+
return Err(tx_token.status.into());
255+
};
256+
257+
debug!("http: request status ok");
258+
259+
Ok(())
260+
}
261+
262+
/// Send HTTP GET request
263+
pub fn request_get(&mut self, url: &str) -> uefi::Result<()> {
264+
self.request(HttpMethod::GET, url, None)?;
265+
Ok(())
266+
}
267+
268+
/// Send HTTP HEAD request
269+
pub fn request_head(&mut self, url: &str) -> uefi::Result<()> {
270+
self.request(HttpMethod::HEAD, url, None)?;
271+
Ok(())
272+
}
273+
274+
/// Receive the start of the http response, the headers and (parts of) the body.
275+
pub fn response_first(&mut self, expect_body: bool) -> uefi::Result<HttpHelperResponse> {
276+
let mut rx_rsp = HttpResponseData {
277+
status_code: HttpStatusCode::STATUS_UNSUPPORTED,
278+
};
279+
280+
let mut body = vec![0; if expect_body { 16 * 1024 } else { 0 }];
281+
let mut rx_msg = HttpMessage::default();
282+
rx_msg.data.response = &mut rx_rsp;
283+
rx_msg.body_length = body.len();
284+
rx_msg.body = if !body.is_empty() {
285+
body.as_mut_ptr()
286+
} else {
287+
ptr::null()
288+
} as *mut c_void;
289+
290+
let mut rx_token = HttpToken {
291+
status: Status::NOT_READY,
292+
message: &mut rx_msg,
293+
..Default::default()
294+
};
295+
296+
let p = self.protocol.as_mut().unwrap();
297+
p.response(&mut rx_token)?;
298+
299+
loop {
300+
if rx_token.status != Status::NOT_READY {
301+
break;
302+
}
303+
p.poll()?;
304+
}
305+
306+
debug!(
307+
"http: response: {} / {:?}",
308+
rx_token.status, rx_rsp.status_code
309+
);
310+
311+
if rx_token.status != Status::SUCCESS && rx_token.status != Status::HTTP_ERROR {
312+
return Err(rx_token.status.into());
313+
};
314+
315+
debug!("http: headers: {}", rx_msg.header_count);
316+
let mut headers: Vec<(String, String)> = Vec::new();
317+
for i in 0..rx_msg.header_count {
318+
let n;
319+
let v;
320+
unsafe {
321+
n = CStr::from_ptr((*rx_msg.header.add(i)).field_name.cast::<c_char>());
322+
v = CStr::from_ptr((*rx_msg.header.add(i)).field_value.cast::<c_char>());
323+
}
324+
headers.push((
325+
n.to_str().unwrap().to_lowercase(),
326+
String::from(v.to_str().unwrap()),
327+
));
328+
}
329+
330+
debug!("http: body: {}/{}", rx_msg.body_length, body.len());
331+
332+
let rsp = HttpHelperResponse {
333+
status: rx_rsp.status_code,
334+
headers,
335+
body: body[0..rx_msg.body_length].to_vec(),
336+
};
337+
Ok(rsp)
338+
}
339+
340+
/// Receive more body data.
341+
pub fn response_more(&mut self) -> uefi::Result<Vec<u8>> {
342+
let mut body = vec![0; 16 * 1024];
343+
let mut rx_msg = HttpMessage {
344+
body_length: body.len(),
345+
body: body.as_mut_ptr().cast::<c_void>(),
346+
..Default::default()
347+
};
348+
349+
let mut rx_token = HttpToken {
350+
status: Status::NOT_READY,
351+
message: &mut rx_msg,
352+
..Default::default()
353+
};
354+
355+
let p = self.protocol.as_mut().unwrap();
356+
p.response(&mut rx_token)?;
357+
358+
loop {
359+
if rx_token.status != Status::NOT_READY {
360+
break;
361+
}
362+
p.poll()?;
363+
}
364+
365+
debug!("http: response: {}", rx_token.status);
366+
367+
if rx_token.status != Status::SUCCESS {
368+
return Err(rx_token.status.into());
369+
};
370+
371+
debug!("http: body: {}/{}", rx_msg.body_length, body.len());
372+
373+
Ok(body[0..rx_msg.body_length].to_vec())
374+
}
375+
}
376+
377+
impl Drop for HttpHelper {
378+
fn drop(&mut self) {
379+
// protocol must go out of scope before calling destroy_child
380+
self.protocol = None;
381+
let _ = self.binding.destroy_child(self.child_handle);
382+
}
383+
}

‎uefi/src/proto/network/ip4config2.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
#![cfg(feature = "alloc")]
4+
5+
//! IP4 Config2 Protocol.
6+
7+
use alloc::vec;
8+
use alloc::vec::Vec;
9+
use core::ffi::c_void;
10+
11+
use uefi::boot::ScopedProtocol;
12+
use uefi::prelude::*;
13+
use uefi::proto::unsafe_protocol;
14+
use uefi::{print, println};
15+
use uefi_raw::protocol::network::ip4_config2::{
16+
Ip4Config2DataType, Ip4Config2InterfaceInfo, Ip4Config2Policy, Ip4Config2Protocol,
17+
};
18+
use uefi_raw::Ipv4Address;
19+
20+
/// IP4 Config2 [`Protocol`]. Configure IPv4 networking.
21+
///
22+
/// [`Protocol`]: uefi::proto::Protocol
23+
#[derive(Debug)]
24+
#[unsafe_protocol(Ip4Config2Protocol::GUID)]
25+
pub struct Ip4Config2(pub Ip4Config2Protocol);
26+
27+
impl Ip4Config2 {
28+
/// Open IP4 Config2 protocol for the given NIC handle.
29+
pub fn new(nic_handle: Handle) -> uefi::Result<ScopedProtocol<Self>> {
30+
let protocol;
31+
unsafe {
32+
protocol = boot::open_protocol::<Self>(
33+
boot::OpenProtocolParams {
34+
handle: nic_handle,
35+
agent: boot::image_handle(),
36+
controller: None,
37+
},
38+
boot::OpenProtocolAttributes::GetProtocol,
39+
)?;
40+
}
41+
Ok(protocol)
42+
}
43+
44+
/// Set configuration data. It is recommended to type-specific set_* helpers instead of calling this directly.
45+
pub fn set_data(&mut self, data_type: Ip4Config2DataType, data: &mut [u8]) -> uefi::Result<()> {
46+
let status = unsafe {
47+
let data_ptr = data.as_mut_ptr().cast::<c_void>();
48+
(self.0.set_data)(&mut self.0, data_type, data.len(), data_ptr)
49+
};
50+
match status {
51+
Status::SUCCESS => Ok(()),
52+
_ => Err(status.into()),
53+
}
54+
}
55+
56+
/// Get configuration data. It is recommended to type-specific get_* helpers instead of calling this directly.
57+
pub fn get_data(&mut self, data_type: Ip4Config2DataType) -> uefi::Result<Vec<u8>> {
58+
let mut data_size = 0;
59+
60+
// call #1: figure return buffer size
61+
let status = unsafe {
62+
let null = core::ptr::null_mut();
63+
(self.0.get_data)(&mut self.0, data_type, &mut data_size, null)
64+
};
65+
if status != Status::BUFFER_TOO_SMALL {
66+
return Err(status.into());
67+
}
68+
69+
// call #2: get data
70+
let mut data = vec![0; data_size];
71+
let status = unsafe {
72+
let data_ptr = data.as_mut_ptr().cast::<c_void>();
73+
(self.0.get_data)(&mut self.0, data_type, &mut data_size, data_ptr)
74+
};
75+
match status {
76+
Status::SUCCESS => Ok(data),
77+
_ => Err(status.into()),
78+
}
79+
}
80+
81+
/// Set config policy (static vs. dhcp).
82+
pub fn set_policy(&mut self, policy: Ip4Config2Policy) -> uefi::Result<()> {
83+
let mut data: [u8; 4] = policy.0.to_ne_bytes();
84+
self.set_data(Ip4Config2DataType::POLICY, &mut data)
85+
}
86+
87+
/// Get current interface configuration.
88+
pub fn get_interface_info(&mut self) -> uefi::Result<Ip4Config2InterfaceInfo> {
89+
let data = self.get_data(Ip4Config2DataType::INTERFACE_INFO)?;
90+
let info: &Ip4Config2InterfaceInfo =
91+
unsafe { &*(data.as_ptr().cast::<Ip4Config2InterfaceInfo>()) };
92+
Ok(Ip4Config2InterfaceInfo {
93+
name: info.name,
94+
if_type: info.if_type,
95+
hw_addr_size: info.hw_addr_size,
96+
hw_addr: info.hw_addr,
97+
station_addr: info.station_addr,
98+
subnet_mask: info.subnet_mask,
99+
route_table_size: 0,
100+
route_table: core::ptr::null_mut(),
101+
})
102+
}
103+
104+
fn print_info(info: &Ip4Config2InterfaceInfo) {
105+
println!(
106+
"addr v4: {}.{}.{}.{}",
107+
info.station_addr.0[0],
108+
info.station_addr.0[1],
109+
info.station_addr.0[2],
110+
info.station_addr.0[3],
111+
);
112+
}
113+
114+
/// Bring up network interface. Does nothing in case the network
115+
/// is already set up. Otherwise turns on DHCP and waits until an
116+
/// IPv4 address has been assigned. Reports progress on the
117+
/// console if verbose is set to true. Returns TIMEOUT error in
118+
/// case DHCP configuration does not finish within 30 seconds.
119+
pub fn ifup(&mut self, verbose: bool) -> uefi::Result<()> {
120+
let no_address = Ipv4Address::default();
121+
122+
let info = self.get_interface_info()?;
123+
if info.station_addr != no_address {
124+
if verbose {
125+
print!("Network is already up: ");
126+
Self::print_info(&info);
127+
}
128+
return Ok(());
129+
}
130+
131+
if verbose {
132+
print!("DHCP ");
133+
}
134+
self.set_policy(Ip4Config2Policy::DHCP)?;
135+
136+
for _ in 0..30 {
137+
if verbose {
138+
print!(".");
139+
}
140+
boot::stall(1_000_000);
141+
let info = self.get_interface_info()?;
142+
if info.station_addr != no_address {
143+
if verbose {
144+
print!(" OK: ");
145+
Self::print_info(&info);
146+
}
147+
return Ok(());
148+
}
149+
}
150+
151+
Err(Status::TIMEOUT.into())
152+
}
153+
}

‎uefi/src/proto/network/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//!
55
//! These protocols can be used to interact with network resources.
66
7+
pub mod http;
8+
pub mod ip4config2;
79
pub mod pxe;
810
pub mod snp;
911

‎xtask/src/qemu.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ pub fn run_qemu(arch: UefiArch, opt: &QemuOpt) -> Result<()> {
359359

360360
if arch == UefiArch::IA32 || arch == UefiArch::X86_64 {
361361
cmd.args(["-debugcon", "file:./integration-test-debugcon.log"]);
362+
cmd.args(["-chardev", "file,id=fw,path=./ovmf-firmware-debugcon.log"]);
363+
cmd.args(["-device", "isa-debugcon,chardev=fw,iobase=0x402"]);
362364
}
363365

364366
// Set the boot menu timeout to zero. On aarch64 in particular this speeds
@@ -529,6 +531,12 @@ pub fn run_qemu(arch: UefiArch, opt: &QemuOpt) -> Result<()> {
529531
None
530532
};
531533

534+
// Pass CA certificate database to the edk2 firmware, for TLS support.
535+
cmd.args([
536+
"-fw_cfg",
537+
"name=etc/edk2/https/cacerts,file=uefi-test-runner/https/cacerts.bin",
538+
]);
539+
532540
// Set up a software TPM if requested.
533541
let _tpm = if let Some(tpm_version) = opt.tpm {
534542
let tpm = Swtpm::spawn(tpm_version)?;

0 commit comments

Comments
 (0)
Please sign in to comment.