Add correct image loading and network conf
This commit is contained in:
parent
08d6909a74
commit
8216b03026
3 changed files with 139 additions and 33 deletions
|
@ -15,6 +15,7 @@ const HTTP_BOOT_VENDOR: VariableVendor =
|
|||
pub struct Config {
|
||||
pub multicast_group: IpAddress,
|
||||
pub multicast_port: u16,
|
||||
pub source_ip: IpAddress,
|
||||
pub client_uuid: String,
|
||||
}
|
||||
|
||||
|
@ -37,6 +38,10 @@ pub fn read_config(runtime_services: &RuntimeServices) -> Result<Config> {
|
|||
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01,
|
||||
]),
|
||||
source_ip: IpAddress::new_v6([
|
||||
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01,
|
||||
]),
|
||||
multicast_port: 42,
|
||||
client_uuid: String::from("24609104-7ec6-423f-b57f-632b99b7566a"),
|
||||
};
|
||||
|
@ -59,6 +64,11 @@ pub fn read_config(runtime_services: &RuntimeServices) -> Result<Config> {
|
|||
conf.multicast_group = IpAddress::new_v6(group_buf);
|
||||
debug!("Got group {:?}", conf.multicast_group);
|
||||
|
||||
let mut ip_buf: [u8; 16] = [0; 16]; // at most ipv6 is 16 bytes
|
||||
get_var(runtime_services, cstr16!("HTTP_BOOT_IP"), &mut ip_buf)?;
|
||||
conf.source_ip = IpAddress::new_v6(ip_buf);
|
||||
debug!("Got ip address {:?}", conf.source_ip);
|
||||
|
||||
let mut uid_buf: [u8; 36] = [0; 36]; // uuid is 36 bytes
|
||||
get_var(runtime_services, cstr16!("HTTP_BOOT_UUID"), &mut uid_buf)?;
|
||||
conf.client_uuid = match String::from_utf8(uid_buf.to_vec()) {
|
||||
|
|
72
src/main.rs
72
src/main.rs
|
@ -4,23 +4,54 @@
|
|||
pub mod config;
|
||||
pub mod multicast;
|
||||
|
||||
use log::info;
|
||||
use alloc::boxed::Box;
|
||||
use log::{debug, info};
|
||||
use uefi::fs::PathBuf;
|
||||
use uefi::prelude::*;
|
||||
use uefi::proto::debug;
|
||||
use uefi::proto::device_path::{DevicePath, LoadedImageDevicePath};
|
||||
use uefi::table::boot::LoadImageSource;
|
||||
use uefi::{Error, Result, Status};
|
||||
|
||||
fn load_efi_app_from_path(boot_services: &BootServices, app_path: PathBuf) -> Result {
|
||||
let mut fs_handler = boot_services.get_image_file_system(boot_services.image_handle())?;
|
||||
let app_content = match fs_handler.read(app_path) {
|
||||
Err(_e) => return Err(Error::from(Status::PROTOCOL_ERROR)),
|
||||
Ok(x) => x,
|
||||
};
|
||||
let image_source = LoadImageSource::FromBuffer {
|
||||
buffer: &app_content,
|
||||
file_path: None,
|
||||
use uefi::proto::device_path::text::{AllowShortcuts, DevicePathToText, DisplayOnly};
|
||||
use uefi::proto::loaded_image::LoadedImage;
|
||||
use uefi::table::boot::SearchType;
|
||||
use uefi::Identify;
|
||||
extern crate alloc;
|
||||
|
||||
fn load_efi_app_from_path(boot_services: &BootServices, app_path: Box<DevicePath>) -> Result {
|
||||
debug!("checking value for image path");
|
||||
let device_path_to_text_handle = *boot_services
|
||||
.locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))?
|
||||
.first()
|
||||
.expect("DevicePathToText is missing");
|
||||
|
||||
let device_path_to_text =
|
||||
boot_services.open_protocol_exclusive::<DevicePathToText>(device_path_to_text_handle)?;
|
||||
|
||||
let scoped_app_path = &*app_path;
|
||||
|
||||
let image_device_path_text = device_path_to_text
|
||||
.convert_device_path_to_text(
|
||||
boot_services,
|
||||
scoped_app_path,
|
||||
DisplayOnly(true),
|
||||
AllowShortcuts(false),
|
||||
)
|
||||
.expect("convert_device_path_to_text failed");
|
||||
|
||||
info!("Image path: {}", &*image_device_path_text);
|
||||
|
||||
debug!("Loading image source");
|
||||
let image_source = LoadImageSource::FromDevicePath {
|
||||
device_path: scoped_app_path,
|
||||
from_boot_manager: false,
|
||||
};
|
||||
|
||||
debug!("Getting image handler");
|
||||
let img_handler = boot_services.load_image(boot_services.image_handle(), image_source)?;
|
||||
|
||||
debug!("Starting new image");
|
||||
boot_services.start_image(img_handler)
|
||||
}
|
||||
|
||||
|
@ -36,6 +67,27 @@ fn main(_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
info!("init runtime services");
|
||||
let runtime_services = system_table.runtime_services();
|
||||
|
||||
let loaded_image = boot_services
|
||||
.open_protocol_exclusive::<LoadedImageDevicePath>(boot_services.image_handle())
|
||||
.unwrap();
|
||||
|
||||
let device_path_to_text_handle = *boot_services
|
||||
.locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))
|
||||
.unwrap()
|
||||
.first()
|
||||
.expect("DevicePathToText is missing");
|
||||
|
||||
let device_path_to_text = boot_services
|
||||
.open_protocol_exclusive::<DevicePathToText>(device_path_to_text_handle)
|
||||
.unwrap();
|
||||
|
||||
let image_device_path_text = loaded_image
|
||||
.to_string(boot_services, DisplayOnly(false), AllowShortcuts(false))
|
||||
.expect("File path is not set")
|
||||
.expect("File path is not set 2");
|
||||
|
||||
info!("Image path: {}", image_device_path_text);
|
||||
|
||||
let conf = config::read_config(runtime_services).unwrap();
|
||||
let app_path = multicast::send_mcast(boot_services, &conf).unwrap();
|
||||
load_efi_app_from_path(boot_services, app_path).unwrap();
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use log::{debug, error, info};
|
||||
use uefi::prelude::*;
|
||||
use uefi::proto::network::pxe::{BaseCode, UdpOpFlags};
|
||||
use uefi::proto::network::IpAddress;
|
||||
use uefi::table::boot::{ScopedProtocol, SearchType};
|
||||
use uefi::{Error, Identify, Result};
|
||||
extern crate alloc;
|
||||
use crate::config::Config;
|
||||
use uefi::data_types::CStr16;
|
||||
use uefi::fs::{Path, PathBuf};
|
||||
use uefi::proto::device_path::text::DevicePathFromText;
|
||||
use uefi::proto::device_path::DevicePath;
|
||||
use uefi::proto::network::IpAddress;
|
||||
|
||||
fn split_arg(raw_val: &str) -> Option<(&str, &str)> {
|
||||
let mut splitted = raw_val.split("=");
|
||||
|
@ -23,9 +26,35 @@ fn split_arg(raw_val: &str) -> Option<(&str, &str)> {
|
|||
return Some((arg_name, arg_value));
|
||||
}
|
||||
|
||||
fn get_boot_path<'a>(msg: String) -> Result<PathBuf, &'a str> {
|
||||
debug!("Splitting message");
|
||||
fn get_boot_path<'a>(
|
||||
boot_services: &BootServices,
|
||||
msg: String,
|
||||
) -> Result<Box<DevicePath>, &'a str> {
|
||||
debug!("Initializing DevicePathFromTextProtocol");
|
||||
let device_path_from_text_handle = match boot_services
|
||||
.locate_handle_buffer(SearchType::ByProtocol(&DevicePathFromText::GUID))
|
||||
{
|
||||
Err(e) => {
|
||||
return Err(Error::new(e.status(), "failed to locate handle buffer"));
|
||||
}
|
||||
Ok(h) => match h.first() {
|
||||
None => return Err(Error::new(Status::UNSUPPORTED, "no handle buffer")),
|
||||
Some(h) => *h,
|
||||
},
|
||||
};
|
||||
let device_path_from_text = match boot_services
|
||||
.open_protocol_exclusive::<DevicePathFromText>(device_path_from_text_handle)
|
||||
{
|
||||
Err(e) => {
|
||||
return Err(Error::new(
|
||||
e.status(),
|
||||
"failed to open device_path_from_text protocol",
|
||||
))
|
||||
}
|
||||
Ok(d) => d,
|
||||
};
|
||||
|
||||
debug!("Splitting message");
|
||||
// a message has the following format: "ACTION arg1=val1,arg2=val2"
|
||||
let mut splitted_msg_iter = msg.split_ascii_whitespace();
|
||||
|
||||
|
@ -44,20 +73,21 @@ fn get_boot_path<'a>(msg: String) -> Result<PathBuf, &'a str> {
|
|||
None => return Err(Error::new(Status::UNSUPPORTED, "empty list of arguments")),
|
||||
Some(args_list) => {
|
||||
// split all the arguments in a comma separated list
|
||||
for arg in args_list.split(",") {
|
||||
for arg in args_list.split(";") {
|
||||
match split_arg(arg) {
|
||||
None => debug!("unexpected format for argument {}", arg),
|
||||
Some((arg_name, arg_value)) => match arg_name {
|
||||
"id" => debug!("found id {}", arg_value),
|
||||
"efi_app" => {
|
||||
debug!("found efi app {}", arg_value);
|
||||
let mut buf = [0; 128];
|
||||
let mut buf = [0; 2000];
|
||||
let path_raw = CStr16::from_str_with_buf(arg_value, &mut buf)
|
||||
.expect("invalid str format");
|
||||
let p = Path::new(path_raw);
|
||||
let mut res = PathBuf::new();
|
||||
res.push(p);
|
||||
return Ok(res);
|
||||
|
||||
return Ok(device_path_from_text
|
||||
.convert_text_to_device_path(path_raw)
|
||||
.expect("failed to parse device path")
|
||||
.to_boxed());
|
||||
}
|
||||
_ => debug!("unexpected argument {} with value {}", arg_name, arg_value),
|
||||
},
|
||||
|
@ -68,8 +98,11 @@ fn get_boot_path<'a>(msg: String) -> Result<PathBuf, &'a str> {
|
|||
Err(Error::new(Status::UNSUPPORTED, "no efi app defined"))
|
||||
}
|
||||
|
||||
fn read_mcast_response<'a>(base_client: &mut ScopedProtocol<'_, BaseCode>) -> Result<PathBuf> {
|
||||
let mut buf: [u8; 200] = [0; 200];
|
||||
fn read_mcast_response<'a>(
|
||||
boot_services: &BootServices,
|
||||
base_client: &mut ScopedProtocol<'_, BaseCode>,
|
||||
) -> Result<Box<DevicePath>> {
|
||||
let mut buf: [u8; 10000] = [0; 10000];
|
||||
|
||||
let n = base_client
|
||||
.udp_read(
|
||||
|
@ -89,7 +122,7 @@ fn read_mcast_response<'a>(base_client: &mut ScopedProtocol<'_, BaseCode>) -> Re
|
|||
info!("Read {} bytes", n);
|
||||
let received_msg = String::from_utf8(buf[..n].to_vec()).unwrap();
|
||||
info!("Received message {}", received_msg);
|
||||
match get_boot_path(received_msg) {
|
||||
match get_boot_path(boot_services, received_msg) {
|
||||
Ok(r) => Ok(r),
|
||||
Err(e) => {
|
||||
error!("failed to get boot path: {}", e.data());
|
||||
|
@ -98,21 +131,14 @@ fn read_mcast_response<'a>(base_client: &mut ScopedProtocol<'_, BaseCode>) -> Re
|
|||
}
|
||||
}
|
||||
|
||||
pub fn send_mcast<'a>(boot_service: &BootServices, conf: &Config) -> Result<PathBuf> {
|
||||
pub fn send_mcast<'a>(boot_services: &BootServices, conf: &Config) -> Result<Box<DevicePath>> {
|
||||
debug!("Initializing base bootservice client handle");
|
||||
let base_client_handle = *boot_service
|
||||
let base_client_handle = *boot_services
|
||||
.locate_handle_buffer(SearchType::ByProtocol(&BaseCode::GUID))?
|
||||
.first()
|
||||
.expect("DevicePathToText is missing");
|
||||
|
||||
let mut base_client = boot_service.open_protocol_exclusive::<BaseCode>(base_client_handle)?;
|
||||
|
||||
debug!("Initializing source IP address");
|
||||
let src_bytes: [u8; 16] = [
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x02, 0x16, 0x3e, 0xff, 0xfe, 0xc2, 0x16,
|
||||
0xb7,
|
||||
];
|
||||
let src_address: IpAddress = IpAddress::new_v6(src_bytes);
|
||||
let mut base_client = boot_services.open_protocol_exclusive::<BaseCode>(base_client_handle)?;
|
||||
|
||||
let mut req_msg = String::from("BOOT_REQUEST id=");
|
||||
req_msg.push_str(&conf.client_uuid);
|
||||
|
@ -121,8 +147,24 @@ pub fn send_mcast<'a>(boot_service: &BootServices, conf: &Config) -> Result<Path
|
|||
debug!("Starting PXE client");
|
||||
base_client.start(true)?;
|
||||
|
||||
// debug!("Starting DHCP client");
|
||||
// base_client.dhcp(false)?;
|
||||
|
||||
debug!("Setting IP address for PXE client");
|
||||
let mask = IpAddress::new_v6([
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// 2001:abcd:1234:1::2/96
|
||||
let src_bytes: [u8; 16] = [
|
||||
0x20, 0x01, 0xab, 0xcd, 0x12, 0x34, 0x00, 0x01, 0x00, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02,
|
||||
];
|
||||
let src_address: IpAddress = IpAddress::new_v6(src_bytes);
|
||||
// base_client
|
||||
base_client.set_station_ip(Some(&src_address), None)?;
|
||||
// base_client.set_station_ip(Some(&conf.source_ip), None)?;
|
||||
|
||||
info!("Sending UDP multicast message");
|
||||
base_client.udp_write(
|
||||
|
@ -130,12 +172,14 @@ pub fn send_mcast<'a>(boot_service: &BootServices, conf: &Config) -> Result<Path
|
|||
&conf.multicast_group,
|
||||
conf.multicast_port,
|
||||
None,
|
||||
// Some(&conf.source_ip),
|
||||
Some(&src_address),
|
||||
// None,
|
||||
None,
|
||||
None,
|
||||
req_msg.as_bytes(),
|
||||
)?;
|
||||
let res = read_mcast_response(&mut base_client);
|
||||
let res = read_mcast_response(boot_services, &mut base_client);
|
||||
|
||||
info!("Stopping PXE client");
|
||||
base_client.stop()?;
|
||||
|
|
Loading…
Reference in a new issue