morpheus_network/boot/
init.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
//! Post-ExitBootServices initialization.
//!
//! This module handles the transition from UEFI boot services to bare-metal
//! operation. After ExitBootServices(), no UEFI services are available.
//!
//! # Initialization Sequence
//! 1. Validate BootHandoff structure
//! 2. Initialize DMA region layout
//! 3. Initialize NIC driver (VirtIO/Intel/Realtek)
//! 4. Initialize block device driver (if present)
//! 5. Return control to caller for main loop entry
//!
//! # Reference
//! NETWORK_IMPL_GUIDE.md §7.6

use super::handoff::{BootHandoff, HandoffError, BLK_TYPE_VIRTIO, NIC_TYPE_VIRTIO};
use crate::dma::DmaRegion;
use crate::driver::virtio::VirtioConfig;
use crate::types::VirtqueueState;

// ═══════════════════════════════════════════════════════════════════════════
// INITIALIZATION ERROR
// ═══════════════════════════════════════════════════════════════════════════

/// Post-EBS initialization error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InitError {
    /// Handoff validation failed
    HandoffInvalid(HandoffError),
    /// Unsupported NIC type
    UnsupportedNic(u8),
    /// NIC initialization failed
    NicInitFailed,
    /// Unsupported block device type
    UnsupportedBlockDevice(u8),
    /// Block device initialization failed
    BlockDeviceInitFailed,
    /// DMA region setup failed
    DmaSetupFailed,
}

impl From<HandoffError> for InitError {
    fn from(e: HandoffError) -> Self {
        InitError::HandoffInvalid(e)
    }
}

// ═══════════════════════════════════════════════════════════════════════════
// INITIALIZATION RESULT
// ═══════════════════════════════════════════════════════════════════════════

/// Result of post-EBS initialization.
///
/// Contains all the initialized components ready for the main loop.
pub struct InitResult {
    /// Validated handoff reference
    pub handoff: &'static BootHandoff,
    /// DMA region layout
    pub dma: DmaRegion,
    /// VirtIO NIC configuration (if NIC is VirtIO)
    pub nic_config: Option<VirtioConfig>,
    /// RX queue state (initialized)
    pub rx_queue: Option<VirtqueueState>,
    /// TX queue state (initialized)
    pub tx_queue: Option<VirtqueueState>,
    /// MAC address
    pub mac_address: [u8; 6],
    /// Block device config (if present and VirtIO)
    pub blk_config: Option<VirtioConfig>,
}

// ═══════════════════════════════════════════════════════════════════════════
// TIMEOUT CONFIGURATION
// ═══════════════════════════════════════════════════════════════════════════

/// Timeout configuration derived from TSC frequency.
#[derive(Debug, Clone, Copy)]
pub struct TimeoutConfig {
    /// TSC ticks per millisecond
    ticks_per_ms: u64,
}

impl TimeoutConfig {
    /// Create from TSC frequency.
    pub fn new(tsc_freq: u64) -> Self {
        Self {
            ticks_per_ms: tsc_freq / 1_000,
        }
    }

    /// DHCP timeout (30 seconds)
    #[inline]
    pub fn dhcp(&self) -> u64 {
        30_000 * self.ticks_per_ms
    }

    /// DNS query timeout (5 seconds)
    #[inline]
    pub fn dns(&self) -> u64 {
        5_000 * self.ticks_per_ms
    }

    /// TCP connect timeout (30 seconds)
    #[inline]
    pub fn tcp_connect(&self) -> u64 {
        30_000 * self.ticks_per_ms
    }

    /// TCP close timeout (10 seconds)
    #[inline]
    pub fn tcp_close(&self) -> u64 {
        10_000 * self.ticks_per_ms
    }

    /// HTTP send timeout (30 seconds)
    #[inline]
    pub fn http_send(&self) -> u64 {
        30_000 * self.ticks_per_ms
    }

    /// HTTP receive timeout (60 seconds for slow connections)
    #[inline]
    pub fn http_receive(&self) -> u64 {
        60_000 * self.ticks_per_ms
    }

    /// HTTP idle timeout between chunks (30 seconds)
    #[inline]
    pub fn http_idle(&self) -> u64 {
        30_000 * self.ticks_per_ms
    }

    /// Main loop iteration warning threshold (5ms)
    #[inline]
    pub fn loop_warning(&self) -> u64 {
        5 * self.ticks_per_ms
    }

    /// Device reset timeout (100ms)
    #[inline]
    pub fn device_reset(&self) -> u64 {
        100 * self.ticks_per_ms
    }

    /// Convert milliseconds to ticks
    #[inline]
    pub fn ms_to_ticks(&self, ms: u64) -> u64 {
        ms * self.ticks_per_ms
    }

    /// Convert ticks to milliseconds
    #[inline]
    pub fn ticks_to_ms(&self, ticks: u64) -> u64 {
        ticks / self.ticks_per_ms
    }
}

// ═══════════════════════════════════════════════════════════════════════════
// POST-EBS INITIALIZATION
// ═══════════════════════════════════════════════════════════════════════════

/// Perform post-ExitBootServices initialization.
///
/// # Arguments
/// - `handoff`: Pointer to BootHandoff structure (must be valid)
///
/// # Returns
/// - `Ok(InitResult)` with initialized components
/// - `Err(InitError)` if initialization fails
///
/// # Safety
/// - `handoff` must point to a valid, populated BootHandoff structure
/// - Must be called after ExitBootServices()
/// - Must be called on the pre-allocated stack
/// - Must not be called more than once
#[cfg(target_arch = "x86_64")]
pub unsafe fn post_ebs_init(handoff: &'static BootHandoff) -> Result<InitResult, InitError> {
    // ═══════════════════════════════════════════════════════════════════════
    // STEP 1: VALIDATE HANDOFF
    // ═══════════════════════════════════════════════════════════════════════
    handoff.validate()?;

    // ═══════════════════════════════════════════════════════════════════════
    // STEP 2: INITIALIZE DMA REGION LAYOUT
    // ═══════════════════════════════════════════════════════════════════════
    let (dma_cpu, dma_bus, dma_size) = handoff.dma_region();
    let dma = DmaRegion::new(dma_cpu, dma_bus, dma_size as usize);

    // ═══════════════════════════════════════════════════════════════════════
    // STEP 3: INITIALIZE NIC DRIVER
    // ═══════════════════════════════════════════════════════════════════════
    let (nic_config, rx_queue, tx_queue, mac_address) = match handoff.nic_type {
        NIC_TYPE_VIRTIO => init_virtio_nic(handoff, &dma)?,
        other => {
            return Err(InitError::UnsupportedNic(other));
        }
    };

    // ═══════════════════════════════════════════════════════════════════════
    // STEP 4: INITIALIZE BLOCK DEVICE (if present)
    // ═══════════════════════════════════════════════════════════════════════
    let blk_config = if handoff.has_block_device() {
        match handoff.blk_type {
            BLK_TYPE_VIRTIO => {
                // Will be implemented in Chunk 7
                None
            }
            _ => None,
        }
    } else {
        None
    };

    Ok(InitResult {
        handoff,
        dma,
        nic_config: Some(nic_config),
        rx_queue: Some(rx_queue),
        tx_queue: Some(tx_queue),
        mac_address,
        blk_config,
    })
}

#[cfg(not(target_arch = "x86_64"))]
pub unsafe fn post_ebs_init(_handoff: &'static BootHandoff) -> Result<InitResult, InitError> {
    Err(InitError::UnsupportedNic(0))
}

/// Initialize VirtIO NIC.
#[cfg(target_arch = "x86_64")]
unsafe fn init_virtio_nic(
    handoff: &BootHandoff,
    dma: &DmaRegion,
) -> Result<(VirtioConfig, VirtqueueState, VirtqueueState, [u8; 6]), InitError> {
    use crate::driver::virtio::init::virtio_net_init;

    // Create VirtIO config from handoff and DMA region
    let config = VirtioConfig {
        dma_cpu_base: dma.cpu_base(),
        dma_bus_base: dma.bus_base(),
        dma_size: dma.size(),
        queue_size: 32, // Standard queue size
        buffer_size: 2048,
    };

    // Initialize device
    let (features, rx_queue, tx_queue, mac) =
        virtio_net_init(handoff.nic_mmio_base, &config).map_err(|_| InitError::NicInitFailed)?;

    // Update config with negotiated features (for reference)
    let config = VirtioConfig {
        dma_cpu_base: dma.cpu_base(),
        dma_bus_base: dma.bus_base(),
        dma_size: dma.size(),
        queue_size: 32,
        buffer_size: 2048,
    };
    let _ = features; // Used for feature tracking if needed

    Ok((config, rx_queue, tx_queue, mac))
}

// ═══════════════════════════════════════════════════════════════════════════
// ENTRY POINT (called from ASM trampoline)
// ═══════════════════════════════════════════════════════════════════════════

/// Post-EBS entry point for ASM trampoline.
///
/// This is the Rust entry point called after:
/// 1. ExitBootServices() has been called
/// 2. Stack has been switched to pre-allocated stack
/// 3. Interrupts are disabled
///
/// # Arguments
/// - `handoff_ptr`: Pointer to BootHandoff structure
///
/// # Returns
/// Never returns (enters main loop or panics)
///
/// # Safety
/// Must only be called from the ASM trampoline with correct setup.
#[no_mangle]
#[cfg(target_arch = "x86_64")]
pub unsafe extern "C" fn _post_ebs_entry(handoff_ptr: *const BootHandoff) -> ! {
    // Convert to static reference (valid for program lifetime)
    let handoff = &*handoff_ptr;

    // Initialize
    match post_ebs_init(handoff) {
        Ok(_result) => {
            // Main loop entry point will be implemented in Chunk 9
            // For now, halt
            loop {
                core::arch::asm!("hlt", options(nomem, nostack));
            }
        }
        Err(_e) => {
            // Fatal error - halt
            loop {
                core::arch::asm!("hlt", options(nomem, nostack));
            }
        }
    }
}

#[cfg(not(target_arch = "x86_64"))]
pub unsafe extern "C" fn _post_ebs_entry(_handoff_ptr: *const BootHandoff) -> ! {
    loop {}
}