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