Skip to content

Commit 0d77948

Browse files
committed
Simplify MBR code and choose bootable partition
(instead of always using the first one)
1 parent bf1895b commit 0d77948

File tree

3 files changed

+38
-73
lines changed

3 files changed

+38
-73
lines changed

bios/boot_sector/16-bit-linker.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ SECTIONS {
2828
_mbr_end = .;
2929

3030
. = 0x7c00 + 446;
31+
_partition_table = .;
3132
.partition_table :
3233
{
3334
/* partition table entry 0 */

bios/boot_sector/src/main.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use core::{
66
slice,
77
};
88
use fail::{fail, print_char, UnwrapOrFail};
9-
use mbr::MasterBootRecord;
109

1110
global_asm!(include_str!("boot.s"));
1211

@@ -17,32 +16,37 @@ mod mbr;
1716

1817
extern "C" {
1918
static _mbr_start: u8;
19+
static _partition_table: u8;
2020
}
2121

2222
fn mbr_start() -> *const u8 {
2323
unsafe { &_mbr_start }
2424
}
2525

26+
unsafe fn partition_table() -> *const u8 {
27+
unsafe { &_partition_table }
28+
}
29+
2630
#[no_mangle]
2731
pub extern "C" fn first_stage(disk_number: u16) {
2832
print_char(b'1');
29-
let bytes = &unsafe { slice::from_raw_parts(mbr_start(), 512) };
30-
let partition = mbr::get_partition(bytes, 0);
33+
let partition_table = &unsafe { slice::from_raw_parts(partition_table(), 16 * 4) };
34+
let boot_partition = mbr::boot_partition(partition_table).unwrap_or_fail(b'x');
3135

3236
print_char(b'2');
3337
let partition_buf = u16::try_from(mbr_start() as usize).unwrap_or_fail(b'a') + 512;
3438

35-
// load first partition into buffer
39+
// load boot partition into buffer
3640
// TODO: only load headers
3741
let dap = dap::DiskAddressPacket::from_lba(
3842
partition_buf,
39-
partition.logical_block_address.into(),
43+
boot_partition.logical_block_address.into(),
4044
1, // partition.sector_count.try_into().unwrap_or_fail(b'b'),
4145
);
4246
unsafe {
4347
dap.perform_load(disk_number);
4448
}
45-
if partition.sector_count == 0 {
49+
if boot_partition.sector_count == 0 {
4650
fail(b'c');
4751
}
4852

@@ -52,7 +56,7 @@ pub extern "C" fn first_stage(disk_number: u16) {
5256
let fat_slice = unsafe {
5357
slice::from_raw_parts(
5458
partition_buf as *const u8,
55-
usize::try_from(partition.sector_count).unwrap_or_else(|_| fail(b'a')) * 512,
59+
usize::try_from(boot_partition.sector_count).unwrap_or_else(|_| fail(b'a')) * 512,
5660
)
5761
};
5862

bios/boot_sector/src/mbr.rs

Lines changed: 26 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,29 @@
22

33
use super::fail::{fail, UnwrapOrFail};
44

5-
pub fn get_partition(buffer: &[u8], index: usize) -> PartitionTableEntry {
6-
if buffer.len() < BUFFER_SIZE {
5+
/// Returns the first bootable partition in the partition table.
6+
pub fn boot_partition(partitions_raw: &[u8]) -> Option<PartitionTableEntry> {
7+
for index in 0..4 {
8+
let entry = get_partition(partitions_raw, index);
9+
if entry.bootable {
10+
return Some(entry);
11+
}
12+
}
13+
None
14+
}
15+
16+
pub fn get_partition(partitions_raw: &[u8], index: usize) -> PartitionTableEntry {
17+
if partitions_raw.len() < PARTITIONS_AREA_SIZE {
718
fail(b'a');
8-
} else if buffer.get(BUFFER_SIZE - SUFFIX_BYTES.len()..BUFFER_SIZE) != Some(&SUFFIX_BYTES[..]) {
9-
fail(b'b');
1019
}
1120

12-
let offset = TABLE_OFFSET + index * ENTRY_SIZE;
13-
let buffer = buffer.get(offset..).unwrap_or_fail(b'c');
21+
let offset = index * ENTRY_SIZE;
22+
let buffer = partitions_raw.get(offset..).unwrap_or_fail(b'c');
23+
24+
let bootable_raw = *buffer.get(0).unwrap_or_fail(b'd');
25+
let bootable = bootable_raw == 0x80;
1426

15-
let partition_type = *buffer.get(4).unwrap_or_fail(b'd');
27+
let partition_type = *buffer.get(4).unwrap_or_fail(b'e');
1628

1729
let lba = u32::from_le_bytes(
1830
buffer
@@ -28,64 +40,11 @@ pub fn get_partition(buffer: &[u8], index: usize) -> PartitionTableEntry {
2840
.and_then(|s| s.try_into().ok())
2941
.unwrap_or_fail(b'f'),
3042
);
31-
PartitionTableEntry::new(partition_type, lba, len)
43+
PartitionTableEntry::new(bootable, partition_type, lba, len)
3244
}
3345

34-
/// A struct representing an MBR partition table.
35-
pub struct MasterBootRecord {
36-
entries: [PartitionTableEntry; MAX_ENTRIES],
37-
}
38-
39-
const BUFFER_SIZE: usize = 512;
40-
const TABLE_OFFSET: usize = 446;
46+
const PARTITIONS_AREA_SIZE: usize = 16 * 4;
4147
const ENTRY_SIZE: usize = 16;
42-
const SUFFIX_BYTES: [u8; 2] = [0x55, 0xaa];
43-
const MAX_ENTRIES: usize = (BUFFER_SIZE - TABLE_OFFSET - 2) / ENTRY_SIZE;
44-
45-
impl MasterBootRecord {
46-
/// Parses the MBR table from a raw byte buffer.
47-
48-
pub fn from_bytes(buffer: &[u8]) -> MasterBootRecord {
49-
if buffer.len() < BUFFER_SIZE {
50-
fail(b'1');
51-
} else if buffer.get(BUFFER_SIZE - SUFFIX_BYTES.len()..BUFFER_SIZE)
52-
!= Some(&SUFFIX_BYTES[..])
53-
{
54-
fail(b'2');
55-
}
56-
let mut entries = [PartitionTableEntry::empty(); MAX_ENTRIES];
57-
58-
for idx in 0..MAX_ENTRIES {
59-
let offset = TABLE_OFFSET + idx * ENTRY_SIZE;
60-
let buffer = buffer.get(offset..).unwrap_or_fail(b'8');
61-
62-
let partition_type = *buffer.get(4).unwrap_or_fail(b'4');
63-
64-
let lba = u32::from_le_bytes(
65-
buffer
66-
.get(8..)
67-
.and_then(|s| s.get(..4))
68-
.and_then(|s| s.try_into().ok())
69-
.unwrap_or_fail(b'5'),
70-
);
71-
let len = u32::from_le_bytes(
72-
buffer
73-
.get(12..)
74-
.and_then(|s| s.get(..4))
75-
.and_then(|s| s.try_into().ok())
76-
.unwrap_or_fail(b'6'),
77-
);
78-
*entries.get_mut(idx).unwrap_or_fail(b'7') =
79-
PartitionTableEntry::new(partition_type, lba, len);
80-
}
81-
82-
MasterBootRecord { entries }
83-
}
84-
85-
pub fn partition_table_entries(&self) -> &[PartitionTableEntry] {
86-
&self.entries[..]
87-
}
88-
}
8948

9049
/// The type of a particular partition.
9150
#[derive(Copy, Clone, Eq, PartialEq)]
@@ -129,6 +88,9 @@ impl PartitionType {
12988
/// An entry in a partition table.
13089
#[derive(Copy, Clone, Eq, PartialEq)]
13190
pub struct PartitionTableEntry {
91+
/// Whether this partition is a boot partition.
92+
pub bootable: bool,
93+
13294
/// The type of partition in this entry.
13395
pub partition_type: u8,
13496

@@ -141,18 +103,16 @@ pub struct PartitionTableEntry {
141103

142104
impl PartitionTableEntry {
143105
pub fn new(
106+
bootable: bool,
144107
partition_type: u8,
145108
logical_block_address: u32,
146109
sector_count: u32,
147110
) -> PartitionTableEntry {
148111
PartitionTableEntry {
112+
bootable,
149113
partition_type,
150114
logical_block_address,
151115
sector_count,
152116
}
153117
}
154-
155-
pub fn empty() -> PartitionTableEntry {
156-
PartitionTableEntry::new(0, 0, 0)
157-
}
158118
}

0 commit comments

Comments
 (0)