morpheus_bootloader/tui/storage_manager/
gpt_ops_ui.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use super::StorageManager;
use crate::tui::input::Keyboard;
use crate::tui::renderer::{Screen, EFI_BLACK, EFI_DARKGREEN, EFI_GREEN, EFI_LIGHTGREEN};
use crate::uefi::gpt_adapter::UefiBlockIoAdapter;
use crate::BootServices;
use morpheus_core::disk::gpt_ops;

impl StorageManager {
    pub(super) fn scan_disk(&mut self, disk_index: usize, bs: &BootServices) -> Result<(), usize> {
        let block_io_ptr = crate::uefi::disk::get_disk_protocol(bs, disk_index)?;
        let block_io = unsafe { &mut *block_io_ptr };

        let media = unsafe { &*block_io.media };
        let block_size = media.block_size as usize;

        let adapter = UefiBlockIoAdapter::new(block_io).map_err(|_| 1usize)?;

        // Use core module to scan partitions
        gpt_ops::scan_partitions(adapter, &mut self.partition_table, block_size).map_err(|e| {
            match e {
                gpt_ops::GptError::IoError => 2usize,
                gpt_ops::GptError::InvalidHeader => 3usize,
                gpt_ops::GptError::NoSpace => 4usize,
                gpt_ops::GptError::PartitionNotFound => 5usize,
                gpt_ops::GptError::OverlappingPartitions => 6usize,
                gpt_ops::GptError::InvalidSize => 7usize,
                gpt_ops::GptError::AlignmentError => 8usize,
            }
        })?;

        // Calculate free space if GPT is present
        if self.partition_table.has_gpt {
            let block_io = unsafe { &mut *block_io_ptr };
            let adapter = UefiBlockIoAdapter::new(block_io).map_err(|_| 1usize)?;
            self.free_space_mb =
                gpt_ops::calculate_total_free_space(adapter, block_size).unwrap_or(0);
        } else {
            self.free_space_mb = 0;
        }

        Ok(())
    }

    pub(super) fn create_gpt_interactive(
        &mut self,
        screen: &mut Screen,
        keyboard: &mut Keyboard,
        bs: &BootServices,
    ) {
        screen.clear();
        screen.put_str_at(
            5,
            5,
            "=== CREATE GPT PARTITION TABLE ===",
            EFI_LIGHTGREEN,
            EFI_BLACK,
        );
        screen.put_str_at(
            5,
            7,
            "WARNING: This will erase all data on the disk!",
            EFI_LIGHTGREEN,
            EFI_BLACK,
        );
        screen.put_str_at(
            5,
            9,
            "Press Y to confirm, any other key to cancel",
            EFI_GREEN,
            EFI_BLACK,
        );

        let key = keyboard.wait_for_key();
        if key.unicode_char != b'y' as u16 && key.unicode_char != b'Y' as u16 {
            screen.clear();
            screen.put_str_at(5, 5, "GPT creation cancelled", EFI_GREEN, EFI_BLACK);
            screen.put_str_at(5, 7, "Press any key...", EFI_DARKGREEN, EFI_BLACK);
            keyboard.wait_for_key();
            return;
        }

        screen.clear();
        screen.put_str_at(5, 5, "Creating GPT table...", EFI_LIGHTGREEN, EFI_BLACK);

        // Get the block IO protocol for current disk
        let block_io_ptr = match crate::uefi::disk::get_disk_protocol(bs, self.current_disk_index) {
            Ok(ptr) => ptr,
            Err(_) => {
                screen.put_str_at(
                    5,
                    7,
                    "ERROR: Failed to get BlockIO protocol",
                    EFI_LIGHTGREEN,
                    EFI_BLACK,
                );
                screen.put_str_at(5, 9, "Press any key...", EFI_DARKGREEN, EFI_BLACK);
                keyboard.wait_for_key();
                return;
            }
        };

        let block_io = unsafe { &mut *block_io_ptr };
        let media = unsafe { &*block_io.media };
        let disk_size_lba = media.last_block + 1;

        let adapter = match UefiBlockIoAdapter::new(block_io) {
            Ok(a) => a,
            Err(_) => {
                screen.put_str_at(
                    5,
                    7,
                    "ERROR: Failed to create adapter",
                    EFI_LIGHTGREEN,
                    EFI_BLACK,
                );
                screen.put_str_at(5, 9, "Press any key...", EFI_DARKGREEN, EFI_BLACK);
                keyboard.wait_for_key();
                return;
            }
        };

        // Use core module to create GPT
        match gpt_ops::create_gpt(adapter, disk_size_lba) {
            Ok(()) => {
                self.partition_table.clear();
                self.partition_table.has_gpt = true;

                screen.put_str_at(
                    5,
                    7,
                    "GPT table created successfully!",
                    EFI_GREEN,
                    EFI_BLACK,
                );
                screen.put_str_at(
                    5,
                    9,
                    "Press any key to continue...",
                    EFI_DARKGREEN,
                    EFI_BLACK,
                );
                keyboard.wait_for_key();
            }
            Err(e) => {
                let err_msg = match e {
                    gpt_ops::GptError::IoError => "I/O Error writing to disk",
                    gpt_ops::GptError::InvalidHeader => "Invalid header generated",
                    _ => "Unknown error",
                };
                screen.put_str_at(
                    5,
                    7,
                    "ERROR: Failed to create GPT",
                    EFI_LIGHTGREEN,
                    EFI_BLACK,
                );
                screen.put_str_at(5, 9, err_msg, EFI_GREEN, EFI_BLACK);
                screen.put_str_at(5, 11, "Press any key...", EFI_DARKGREEN, EFI_BLACK);
                keyboard.wait_for_key();
            }
        }
    }
}