Utilize libflate crate to compress and decompress payload

This commit is contained in:
azongchang
2024-07-20 12:12:46 +00:00
committed by Tate, Hongliang Tian
parent 930b0d208d
commit 6752baf166
15 changed files with 321 additions and 37 deletions

View File

@ -11,5 +11,6 @@ repository = "https://github.com/asterinas/asterinas"
[dependencies]
bytemuck = { version = "1.14.0", features = ["derive"] }
bitflags = "1.3"
libflate = "2.1.0"
serde = { version = "1.0.192", features = ["derive"] }
xmas-elf = "0.9.1"

View File

@ -0,0 +1,65 @@
// SPDX-License-Identifier: MPL-2.0
//! This module is used to compress kernel ELF.
use std::{
ffi::{OsStr, OsString},
io::Write,
str::FromStr,
};
use libflate::{gzip, zlib};
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PayloadEncoding {
#[default]
#[serde(rename = "raw")]
Raw,
#[serde(rename = "gzip")]
Gzip,
#[serde(rename = "zlib")]
Zlib,
}
impl FromStr for PayloadEncoding {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"raw" => Ok(Self::Raw),
"gzip" => Ok(Self::Gzip),
"zlib" => Ok(Self::Zlib),
_ => Err(format!("Invalid encoding format: {}", s)),
}
}
}
impl From<OsString> for PayloadEncoding {
fn from(os_string: OsString) -> Self {
PayloadEncoding::from_str(&os_string.to_string_lossy()).unwrap()
}
}
impl From<&OsStr> for PayloadEncoding {
fn from(os_str: &OsStr) -> Self {
PayloadEncoding::from_str(&os_str.to_string_lossy()).unwrap()
}
}
/// Encoding the kernel ELF using the provided format.
pub fn encode_kernel(kernel: Vec<u8>, encoding: PayloadEncoding) -> Vec<u8> {
match encoding {
PayloadEncoding::Raw => kernel,
PayloadEncoding::Gzip => {
let mut encoder = gzip::Encoder::new(Vec::new()).unwrap();
encoder.write_all(&kernel).unwrap();
encoder.finish().into_result().unwrap()
}
PayloadEncoding::Zlib => {
let mut encoder = zlib::Encoder::new(Vec::new()).unwrap();
encoder.write_all(&kernel).unwrap();
encoder.finish().into_result().unwrap()
}
}
}

View File

@ -13,6 +13,7 @@
//! The setup code should be built into the ELF target and we convert it to a flat binary
//! in the builder.
pub mod encoder;
mod mapping;
mod pe_header;
@ -22,6 +23,8 @@ use std::{
path::Path,
};
use encoder::encode_kernel;
pub use encoder::PayloadEncoding;
use mapping::{SetupFileOffset, SetupVA};
use xmas_elf::program::SegmentData;
@ -39,13 +42,15 @@ pub enum BzImageType {
/// - `target_image_path`: The path to the target bzImage;
/// - `image_type`: The type of the bzImage that we are building;
/// - `kernel_path`: The path to the kernel ELF;
/// - `setup_elf_path`: The path to the setup ELF.
/// - `setup_elf_path`: The path to the setup ELF;
/// - `encoding`: The encoding format for compressing the kernel ELF.
///
pub fn make_bzimage(
target_image_path: &Path,
image_type: BzImageType,
kernel_path: &Path,
setup_elf_path: &Path,
encoding: PayloadEncoding,
) {
let mut setup_elf = Vec::new();
File::open(setup_elf_path)
@ -61,7 +66,10 @@ pub fn make_bzimage(
.unwrap()
.read_to_end(&mut kernel)
.unwrap();
let payload = kernel;
let payload = match image_type {
BzImageType::Legacy32 => kernel,
BzImageType::Efi64 => encode_kernel(kernel, encoding),
};
let setup_len = setup.len();
let payload_len = payload.len();

View File

@ -14,6 +14,8 @@ path = "src/main.rs"
[dependencies]
cfg-if = "1.0.0"
core2 = { version = "0.4.0", default-features = false, features = ["nightly"] }
libflate = { version = "2.1.0", default-features = false }
linux-boot-params = { path = "../boot-params", version = "0.1.0" }
uart_16550 = "0.3.0"
xmas-elf = "0.8.0"

View File

@ -0,0 +1,50 @@
// SPDX-License-Identifier: MPL-2.0
//! This module is used to decompress payload.
extern crate alloc;
pub use alloc::vec::Vec;
use core::convert::TryFrom;
use core2::io::Read;
use libflate::{gzip, zlib};
enum MagicNumber {
Elf,
Gzip,
Zlib,
}
impl TryFrom<&[u8]> for MagicNumber {
type Error = &'static str;
fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
match *slice {
[0x7F, 0x45, 0x4C, 0x46, ..] => Ok(Self::Elf),
[0x1F, 0x8B, ..] => Ok(Self::Gzip),
[0x78, 0x9C, ..] => Ok(Self::Zlib),
_ => Err("Unsupported payload type"),
}
}
}
/// Checking the encoding format and matching decoding methods to decode payload.
pub fn decode_payload(payload: &[u8]) -> Vec<u8> {
let mut kernel = Vec::new();
let magic = MagicNumber::try_from(payload).unwrap();
match magic {
MagicNumber::Elf => {
kernel = payload.to_vec();
}
MagicNumber::Gzip => {
let mut decoder = gzip::Decoder::new(payload).unwrap();
decoder.read_to_end(&mut kernel).unwrap();
}
MagicNumber::Zlib => {
let mut decoder = zlib::Decoder::new(payload).unwrap();
decoder.read_to_end(&mut kernel).unwrap();
}
}
kernel
}

View File

@ -8,6 +8,7 @@ use uefi::{
};
use super::{
decoder::decode_payload,
paging::{Ia32eFlags, PageNumber, PageTableCreator},
relocation::apply_rela_dyn_relocations,
};
@ -55,9 +56,11 @@ fn efi_phase_boot(
uefi_services::println!("[EFI stub] Relocations applied.");
uefi_services::println!("[EFI stub] Loading payload.");
let payload = unsafe { crate::get_payload(&*boot_params_ptr) };
crate::loader::load_elf(payload);
let kernel = decode_payload(payload);
uefi_services::println!("[EFI stub] Loading payload.");
crate::loader::load_elf(&kernel);
uefi_services::println!("[EFI stub] Exiting EFI boot services.");
let memory_type = {

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
mod decoder;
mod efi;
mod paging;
mod relocation;