Tools for creating MBR
This commit is contained in:
parent
7829f898fb
commit
5449543501
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "crmbr"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
|
@ -0,0 +1,235 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::env;
|
||||||
|
use std::vec::*;
|
||||||
|
use std::string::*;
|
||||||
|
|
||||||
|
struct MBRPartTableEntry {
|
||||||
|
part_type: u8,
|
||||||
|
first_sector: u64,
|
||||||
|
last_sector: u64,
|
||||||
|
bootable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_mbr_partition_table_entry(info: MBRPartTableEntry) -> Vec<u8> {
|
||||||
|
|
||||||
|
let mut buffer = Vec::<u8>::new();
|
||||||
|
buffer.resize(16, 0x00);
|
||||||
|
|
||||||
|
if info.bootable {
|
||||||
|
buffer[0] = 0x80;
|
||||||
|
}
|
||||||
|
buffer[5] = info.part_type;
|
||||||
|
|
||||||
|
buffer[8] = ((info.first_sector & 0xff000000) >> 24) as u8;
|
||||||
|
buffer[9] = ((info.first_sector & 0x00ff0000) >> 16) as u8;
|
||||||
|
buffer[10] = ((info.first_sector & 0x0000ff00) >> 8) as u8;
|
||||||
|
buffer[11] = (info.first_sector & 0x000000ff) as u8;
|
||||||
|
|
||||||
|
buffer[12] = ((info.last_sector & 0xff000000) >> 24) as u8;
|
||||||
|
buffer[13] = ((info.last_sector & 0x00ff0000) >> 16) as u8;
|
||||||
|
buffer[14] = ((info.last_sector & 0x0000ff00) >> 8) as u8;
|
||||||
|
buffer[15] = (info.last_sector & 0x000000ff) as u8;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_command_line_partition_table_entry(input: Vec<String>) -> MBRPartTableEntry {
|
||||||
|
if input.len() != 4 {
|
||||||
|
panic!("Wrong number of fields in partition table entry");
|
||||||
|
}
|
||||||
|
let part_type = resolve_text_to_partition_type(&input[0]);
|
||||||
|
let first_sector: u64 = match input[1].parse() {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => {
|
||||||
|
panic!("Invalid partition start sector in '-p1'!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let last_sector: u64 = match input[2].parse() {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => {
|
||||||
|
panic!("Invalid partition end sector in '-p1'!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut is_bootable: bool = false;
|
||||||
|
if input[3] == "true" {
|
||||||
|
is_bootable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MBRPartTableEntry {
|
||||||
|
part_type: part_type,
|
||||||
|
first_sector: first_sector,
|
||||||
|
last_sector: last_sector,
|
||||||
|
bootable: is_bootable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_text_to_partition_type(text: &String) -> u8 {
|
||||||
|
return match text.as_str() {
|
||||||
|
"empty" => 0x00,
|
||||||
|
"fat12" => 0x01,
|
||||||
|
"fat16" => 0x04,
|
||||||
|
"ext" => 0x05,
|
||||||
|
"fat16_big" => 0x06,
|
||||||
|
"ntfs" => 0x07,
|
||||||
|
"fat32_chs" => 0x0b,
|
||||||
|
"fat32_lba" => 0x0c,
|
||||||
|
"fat16_big_lba" => 0x0e,
|
||||||
|
"ext_lba" => 0x0f,
|
||||||
|
"win_lvm" => 0x42,
|
||||||
|
"gpfs" => 0x75,
|
||||||
|
"swap" => 0x82,
|
||||||
|
"linux" => 0x83,
|
||||||
|
"linux_lvm" => 0x8e,
|
||||||
|
"freebsd" => 0xa5,
|
||||||
|
"openbsd" => 0xa6,
|
||||||
|
"netbsd" => 0xa9,
|
||||||
|
"macos" => 0xaf,
|
||||||
|
&_ => 0xff
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
let mut buffer = Vec::<u8>::new();
|
||||||
|
buffer.resize(512, 0x00);
|
||||||
|
buffer[510] = 0x55;
|
||||||
|
buffer[511] = 0xAA;
|
||||||
|
|
||||||
|
let mut has_bootcode = false;
|
||||||
|
let mut bootcode: [u8; 440] = [0x00; 440];
|
||||||
|
|
||||||
|
let mut has_output_path = false;
|
||||||
|
let mut output_path: String = "".to_string();
|
||||||
|
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
let mut index: usize = 0;
|
||||||
|
while index < args.len() {
|
||||||
|
|
||||||
|
let arg = &args[index];
|
||||||
|
|
||||||
|
if arg == "-h" {
|
||||||
|
|
||||||
|
}
|
||||||
|
if arg == "-mbc" {
|
||||||
|
index += 1;
|
||||||
|
if index >= args.len() {
|
||||||
|
panic!("Failed reading stage 1 bootloader: No path provided!");
|
||||||
|
}
|
||||||
|
let mut file = match File::open(args[index].as_str()) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(err) => {
|
||||||
|
panic!("Failed reading Master Boot Code from file: {}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let file_len = match file.read(&mut bootcode) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(err) => {
|
||||||
|
panic!("Failed reading stage 1 bootloader from '{}': {}", args[index], err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if file_len > 440 {
|
||||||
|
panic!("The stage 1 bootloader can be at most 440 bytes in size!");
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
has_bootcode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if arg == "-out" {
|
||||||
|
index += 1;
|
||||||
|
output_path = args[index].clone();
|
||||||
|
has_output_path = true;
|
||||||
|
index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if arg == "-p1" {
|
||||||
|
if args.len() <= (index + 4) {
|
||||||
|
println!("Too short input near '-p1': This argument has 4 fields!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
let entry = serialize_mbr_partition_table_entry(
|
||||||
|
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
|
||||||
|
);
|
||||||
|
buffer[446..446+16].clone_from_slice(entry.as_slice());
|
||||||
|
|
||||||
|
index += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if arg == "-p2" {
|
||||||
|
if args.len() <= (index + 4) {
|
||||||
|
println!("Too short input near '-p2': This argument has 4 fields!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
let entry = serialize_mbr_partition_table_entry(
|
||||||
|
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
|
||||||
|
);
|
||||||
|
buffer[462..462+16].clone_from_slice(entry.as_slice());
|
||||||
|
|
||||||
|
index += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if arg == "-p3" {
|
||||||
|
if args.len() <= (index + 4) {
|
||||||
|
println!("Too short input near '-p3': This argument has 4 fields!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
let entry = serialize_mbr_partition_table_entry(
|
||||||
|
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
|
||||||
|
);
|
||||||
|
buffer[478..478+16].clone_from_slice(entry.as_slice());
|
||||||
|
|
||||||
|
index += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if arg == "-p4" {
|
||||||
|
if args.len() <= (index + 4) {
|
||||||
|
println!("Too short input near '-p4': This argument has 4 fields!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
let entry = serialize_mbr_partition_table_entry(
|
||||||
|
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
|
||||||
|
);
|
||||||
|
buffer[494..494+16].clone_from_slice(entry.as_slice());
|
||||||
|
|
||||||
|
index += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !has_output_path {
|
||||||
|
panic!("No output path defined!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !has_bootcode {
|
||||||
|
panic!("No bootcode defined!");
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[0..440].clone_from_slice(bootcode.as_slice());
|
||||||
|
|
||||||
|
let mut output_file = match File::create(output_path) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(err) => {
|
||||||
|
panic!("Failed opening output file: {}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match output_file.write_all(&buffer) {
|
||||||
|
Ok(len) => len,
|
||||||
|
Err(err) => {
|
||||||
|
panic!("Failed writing output: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Reference in New Issue