|
1 | 1 | # MorpheusX Network Stack |
2 | 2 |
|
3 | | -HTTP client for downloading ISOs and other files in the UEFI bootloader environment. |
| 3 | +Bare-metal HTTP client for post-ExitBootServices execution. |
4 | 4 |
|
| 5 | +## Architecture |
5 | 6 |
|
6 | | - |
7 | | -### Design Principles |
8 | | - |
9 | | -1. **Platform Abstraction**: `HttpClient` trait allows multiple implementations |
10 | | -3. **No External Deps**: Everything built on primitives |
11 | | -5. **Error Handling**: Comprehensive error types for network operations |
12 | | - |
13 | | -## Usage |
14 | | - |
15 | | -### Basic Download |
16 | | - |
17 | | -```rust |
18 | | -use morpheus_network::{UefiHttpClient, DownloadManager}; |
19 | | - |
20 | | -// Create UEFI HTTP client |
21 | | -let mut client = UefiHttpClient::new(boot_services)?; |
22 | | - |
23 | | -// Create download manager |
24 | | -let mut downloader = DownloadManager::new(&mut client); |
25 | | - |
26 | | -// Download a file |
27 | | -let data = downloader.download_to_memory("http://example.com/file.iso")?; |
28 | 7 | ``` |
29 | | - |
30 | | -### Download with Progress |
31 | | - |
32 | | -```rust |
33 | | -fn progress_callback(downloaded: usize, total: Option<usize>) { |
34 | | - if let Some(total) = total { |
35 | | - let percent = (downloaded * 100) / total; |
36 | | - println!("Progress: {}%", percent); |
37 | | - } |
38 | | -} |
39 | | - |
40 | | -let data = downloader.download_with_progress( |
41 | | - "http://example.com/large-file.iso", |
42 | | - progress_callback |
43 | | -)?; |
| 8 | +┌──────────────────────────────────────────────────────────────┐ |
| 9 | +│ Entry Point │ |
| 10 | +│ mainloop::download_with_config(&mut driver, config, ...) │ |
| 11 | +└──────────────────────────────────────────────────────────────┘ |
| 12 | + │ |
| 13 | + ▼ |
| 14 | +┌──────────────────────────────────────────────────────────────┐ |
| 15 | +│ State Machine │ |
| 16 | +│ Init → GptPrep → LinkWait → DHCP → DNS → Connect → HTTP │ |
| 17 | +└──────────────────────────────────────────────────────────────┘ |
| 18 | + │ |
| 19 | + ▼ |
| 20 | +┌──────────────────────────────────────────────────────────────┐ |
| 21 | +│ NetworkDriver Trait │ |
| 22 | +│ transmit(), receive(), mac_address(), link_up() │ |
| 23 | +└──────────────────────────────────────────────────────────────┘ |
| 24 | + │ |
| 25 | + ┌──────────────┴──────────────┐ |
| 26 | + ▼ ▼ |
| 27 | +┌─────────────────────────┐ ┌─────────────────────────┐ |
| 28 | +│ VirtioNetDriver │ │ E1000eDriver │ |
| 29 | +│ (QEMU, KVM) │ │ (Real Hardware) │ |
| 30 | +└─────────────────────────┘ └─────────────────────────┘ |
| 31 | + │ │ |
| 32 | + └──────────────┬──────────────┘ |
| 33 | + ▼ |
| 34 | +┌──────────────────────────────────────────────────────────────┐ |
| 35 | +│ ASM Layer (network/asm/) │ |
| 36 | +│ MMIO read/write, TSC, barriers, cache ops │ |
| 37 | +└──────────────────────────────────────────────────────────────┘ |
44 | 38 | ``` |
45 | 39 |
|
46 | | -### Check File Size |
| 40 | +## Usage |
47 | 41 |
|
48 | 42 | ```rust |
49 | | -if let Some(size) = downloader.get_file_size("http://example.com/file.iso")? { |
50 | | - println!("File size: {} bytes", size); |
| 43 | +use morpheus_network::mainloop::{download_with_config, DownloadConfig, DownloadResult}; |
| 44 | +use morpheus_network::boot::probe::{probe_and_create_driver, ProbeResult}; |
| 45 | + |
| 46 | +// 1. Probe PCI and create driver (brutal reset happens during driver::new()) |
| 47 | +let driver = match probe_and_create_driver(&dma, tsc_freq)? { |
| 48 | + ProbeResult::Intel(d) => UnifiedNetworkDriver::Intel(d), |
| 49 | + ProbeResult::VirtIO(d) => UnifiedNetworkDriver::VirtIO(d), |
| 50 | +}; |
| 51 | + |
| 52 | +// 2. Configure download |
| 53 | +let config = DownloadConfig::full( |
| 54 | + "http://example.com/image.iso", |
| 55 | + start_sector, |
| 56 | + 0, // offset |
| 57 | + esp_lba, |
| 58 | + partition_uuid, |
| 59 | + "image.iso", |
| 60 | +); |
| 61 | + |
| 62 | +// 3. Execute download with optional disk write |
| 63 | +let result = download_with_config(&mut driver, config, Some(blk_device), tsc_freq); |
| 64 | + |
| 65 | +match result { |
| 66 | + DownloadResult::Success { bytes_downloaded, bytes_written } => { /* done */ } |
| 67 | + DownloadResult::Failed { reason } => { /* handle error */ } |
51 | 68 | } |
52 | 69 | ``` |
53 | 70 |
|
54 | | -## Implementation |
| 71 | +## Preconditions |
55 | 72 |
|
56 | | -### See /docs/ |
| 73 | +Before calling network functions: |
57 | 74 |
|
58 | | -## Error Handling |
| 75 | +1. **ExitBootServices completed** - No UEFI runtime |
| 76 | +2. **hwinit has run** - Platform normalized (bus mastering, DMA, cache coherency) |
| 77 | +3. **DMA region allocated** - Identity-mapped, cache-coherent |
59 | 78 |
|
60 | | -All operations return `Result<T, NetworkError>`: |
| 79 | +## Driver Reset Contract |
61 | 80 |
|
62 | | -```rust |
63 | | -match downloader.download_to_memory(url) { |
64 | | - Ok(data) => { /* success */ }, |
65 | | - Err(NetworkError::ProtocolNotAvailable) => { |
66 | | - // UEFI firmware doesn't support HTTP |
67 | | - }, |
68 | | - Err(NetworkError::HttpError(404)) => { |
69 | | - // File not found |
70 | | - }, |
71 | | - Err(e) => { |
72 | | - // Other error |
73 | | - } |
74 | | -} |
75 | | -``` |
| 81 | +All drivers perform **brutal reset** on init: |
76 | 82 |
|
77 | | -## Testing |
| 83 | +- Mask and clear all interrupts |
| 84 | +- Disable RX/TX with quiescence polling |
| 85 | +- Full device reset with timeout |
| 86 | +- Wait for EEPROM auto-read |
| 87 | +- Clear all descriptor pointers |
| 88 | +- Disable loopback explicitly |
| 89 | +- Rebuild queues from scratch |
78 | 90 |
|
79 | | -Test in QEMU with OVMF UEFI firmware: |
80 | | -```bash |
81 | | -cd testing |
82 | | -./run.sh |
83 | | -``` |
84 | | - |
85 | | -Ensure QEMU has network configured: |
86 | | -```bash |
87 | | --netdev user,id=net0 \ |
88 | | --device e1000,netdev=net0 |
89 | | -``` |
| 91 | +See `driver/RESET_CONTRACT.md` for details. |
90 | 92 |
|
91 | | -## Future: ARM Support |
| 93 | +## Modules |
92 | 94 |
|
93 | | -When adding ARM64 support: |
94 | | -- Same UEFI protocols work on ARM |
95 | | -- No code changes needed in abstraction layer |
96 | | -- May need arch-specific optimizations for large transfers |
| 95 | +| Module | Purpose | |
| 96 | +|--------|---------| |
| 97 | +| `mainloop` | State machine orchestration, entry point | |
| 98 | +| `driver` | NetworkDriver trait, VirtIO, Intel e1000e | |
| 99 | +| `boot` | Device probing, driver creation helpers | |
| 100 | +| `asm` | Assembly bindings (MMIO, PIO, TSC) | |
| 101 | +| `dma` | DMA buffer management | |
| 102 | +| `time` | TSC-based timing | |
97 | 103 |
|
98 | | -## References |
| 104 | +## State Machine |
99 | 105 |
|
100 | | -- UEFI Specification 2.10, Section 28.7 (EFI HTTP Protocol) |
| 106 | +| State | Description | |
| 107 | +|-------|-------------| |
| 108 | +| Init | Initialize smoltcp interface | |
| 109 | +| GptPrep | Prepare GPT if writing to disk | |
| 110 | +| LinkWait | Wait for link up | |
| 111 | +| DHCP | Obtain IP address | |
| 112 | +| DNS | Resolve hostname | |
| 113 | +| Connect | TCP connection | |
| 114 | +| HTTP | HTTP GET and streaming receive | |
| 115 | +| Manifest | Write manifest to disk | |
| 116 | +| Done | Reboot | |
101 | 117 | - UEFI Specification 2.10, Section 11.1 (EFI Service Binding Protocol) |
0 commit comments