Skip to content

Commit 0ca5bbe

Browse files
author
T. Andrew Davis
committed
feat(network): enhance DHCP handling and network stack integration
- Added `stack_available` field to `NetObsChamber` to track network stack status. - Improved DHCP request handling in `run_dhcp_request` function, including better error handling for NIC registration. - Refactored DHCP request logic in `activate` and `apply` functions to use the new `run_dhcp_request` function. - Introduced new network activation module in the bootloader, including functions for network configuration, TCP, and UDP operations. - Implemented user-space network activation with probing for NIC drivers and registering network stack operations. - Added functions for managing TCP and UDP sockets, including sending, receiving, and DNS query handling. - Enhanced state management for network operations, including dynamic allocation of socket handles and DNS queries. - Updated mouse input handling in `state.rs` to detect button changes more accurately.
1 parent 9c40619 commit 0ca5bbe

18 files changed

Lines changed: 1289 additions & 340 deletions

File tree

bootloader/src/baremetal.rs

Lines changed: 4 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
use core::sync::atomic::{AtomicBool, Ordering};
77
use morpheus_display::console::TextConsole;
8-
use morpheus_network::device::{NetworkDevice, UnifiedNetDevice};
9-
use morpheus_network::boot::{probe_and_create_driver, ProbeError, ProbeResult};
8+
9+
use crate::baremetal_ops::network;
1010

1111
// TYPES THAT CROSS THE BORDER
1212

@@ -51,199 +51,6 @@ static BAREMETAL_MODE: AtomicBool = AtomicBool::new(false);
5151

5252
static mut LIVE_CONSOLE: Option<TextConsole> = None;
5353

54-
// userspace-activated networking state. offline by default until requested.
55-
static mut USER_NET_DRIVER: Option<UnifiedNetDevice> = None;
56-
static mut USER_NET_DMA: Option<morpheus_network::dma::DmaRegion> = None;
57-
static mut USER_NET_TSC_FREQ: u64 = 0;
58-
59-
unsafe fn log_pci_network_candidates() {
60-
let mut found = 0u32;
61-
for bus in 0..=255u8 {
62-
for dev in 0..32u8 {
63-
for func in 0..8u8 {
64-
let addr = morpheus_hwinit::PciAddr::new(bus, dev, func);
65-
let vendor = morpheus_hwinit::pci_cfg_read16(addr, 0x00);
66-
if vendor == 0xFFFF {
67-
if func == 0 {
68-
break;
69-
}
70-
continue;
71-
}
72-
73-
let class = morpheus_hwinit::pci_cfg_read8(addr, 0x0B);
74-
let subclass = morpheus_hwinit::pci_cfg_read8(addr, 0x0A);
75-
if class != 0x02 {
76-
if func == 0 {
77-
let header = morpheus_hwinit::pci_cfg_read8(addr, 0x0E);
78-
if (header & 0x80) == 0 {
79-
break;
80-
}
81-
}
82-
continue;
83-
}
84-
85-
let device = morpheus_hwinit::pci_cfg_read16(addr, 0x02);
86-
found = found.wrapping_add(1);
87-
morpheus_hwinit::serial::puts("[INFO] [NET] pci net candidate bdf=");
88-
morpheus_hwinit::serial::put_hex64(((bus as u64) << 16) | ((dev as u64) << 8) | func as u64);
89-
morpheus_hwinit::serial::puts(" ven=");
90-
morpheus_hwinit::serial::put_hex64(vendor as u64);
91-
morpheus_hwinit::serial::puts(" dev=");
92-
morpheus_hwinit::serial::put_hex64(device as u64);
93-
morpheus_hwinit::serial::puts(" sub=");
94-
morpheus_hwinit::serial::put_hex64(subclass as u64);
95-
morpheus_hwinit::serial::puts("\n");
96-
97-
if func == 0 {
98-
let header = morpheus_hwinit::pci_cfg_read8(addr, 0x0E);
99-
if (header & 0x80) == 0 {
100-
break;
101-
}
102-
}
103-
}
104-
}
105-
}
106-
107-
if found == 0 {
108-
morpheus_hwinit::serial::log_warn("NET", 953, "pci scan found zero class-0x02 devices");
109-
} else {
110-
morpheus_hwinit::serial::log_info("NET", 954, "pci net candidates logged");
111-
}
112-
}
113-
114-
#[inline]
115-
unsafe fn user_net_driver_mut() -> Option<&'static mut UnifiedNetDevice> {
116-
USER_NET_DRIVER.as_mut()
117-
}
118-
119-
unsafe fn user_net_tx(frame: *const u8, len: usize) -> i64 {
120-
let Some(driver) = user_net_driver_mut() else {
121-
return -1;
122-
};
123-
let frame = core::slice::from_raw_parts(frame, len);
124-
if driver.transmit(frame).is_ok() {
125-
0
126-
} else {
127-
-1
128-
}
129-
}
130-
131-
unsafe fn user_net_rx(buf: *mut u8, buf_len: usize) -> i64 {
132-
let Some(driver) = user_net_driver_mut() else {
133-
return -1;
134-
};
135-
let buf = core::slice::from_raw_parts_mut(buf, buf_len);
136-
match driver.receive(buf) {
137-
Ok(Some(n)) => n as i64,
138-
Ok(None) => 0,
139-
Err(_) => -1,
140-
}
141-
}
142-
143-
unsafe fn user_net_link_up() -> i64 {
144-
let Some(driver) = user_net_driver_mut() else {
145-
return 0;
146-
};
147-
driver.link_up() as i64
148-
}
149-
150-
unsafe fn user_net_mac(out: *mut u8) -> i64 {
151-
let Some(driver) = user_net_driver_mut() else {
152-
return -1;
153-
};
154-
let mac = driver.mac_address();
155-
core::ptr::copy_nonoverlapping(mac.as_ptr(), out, 6);
156-
0
157-
}
158-
159-
unsafe fn user_net_refill() -> i64 {
160-
let Some(driver) = user_net_driver_mut() else {
161-
return -1;
162-
};
163-
driver.refill_rx_queue();
164-
driver.collect_tx_completions();
165-
0
166-
}
167-
168-
unsafe fn user_net_ctrl(_cmd: u32, _arg: u64) -> i64 {
169-
// full NIC control routing can be added later per-driver.
170-
-1
171-
}
172-
173-
unsafe fn activate_network_from_userspace() -> i64 {
174-
morpheus_hwinit::serial::log_info("NET", 940, "userspace activation requested");
175-
176-
if USER_NET_DRIVER.is_some() {
177-
morpheus_hwinit::serial::log_info("NET", 941, "already active");
178-
return 1;
179-
}
180-
181-
let Some(dma) = USER_NET_DMA.as_ref() else {
182-
morpheus_hwinit::serial::log_error("NET", 942, "activation failed: dma unavailable");
183-
return -1;
184-
};
185-
let tsc_freq = USER_NET_TSC_FREQ;
186-
187-
morpheus_hwinit::serial::log_info("NET", 943, "probing NIC via network::probe_and_create_driver");
188-
let driver = match probe_and_create_driver(dma, tsc_freq) {
189-
Ok(ProbeResult::VirtIO(v)) => {
190-
morpheus_hwinit::serial::log_info("NET", 949, "probe selected virtio NIC");
191-
UnifiedNetDevice::VirtIO(v)
192-
}
193-
Ok(ProbeResult::Intel(i)) => {
194-
morpheus_hwinit::serial::log_info("NET", 951, "probe selected intel NIC");
195-
UnifiedNetDevice::Intel(i)
196-
}
197-
Err(ProbeError::NoDevice) => {
198-
morpheus_hwinit::serial::log_error("NET", 944, "probe failed: no supported NIC detected");
199-
log_pci_network_candidates();
200-
return -2;
201-
}
202-
Err(ProbeError::VirtioInitFailed) => {
203-
morpheus_hwinit::serial::log_error("NET", 950, "virtio init failed");
204-
return -3;
205-
}
206-
Err(ProbeError::IntelInitFailed) => {
207-
morpheus_hwinit::serial::log_error("NET", 952, "intel init failed");
208-
return -3;
209-
}
210-
Err(ProbeError::DeviceNotResponding) => {
211-
morpheus_hwinit::serial::log_error("NET", 955, "nic mmio not responding");
212-
return -4;
213-
}
214-
Err(ProbeError::BarMappingFailed) => {
215-
morpheus_hwinit::serial::log_error("NET", 956, "nic bar mapping failure");
216-
return -5;
217-
}
218-
};
219-
220-
morpheus_hwinit::serial::log_ok("NET", 945, "driver initialized");
221-
222-
USER_NET_DRIVER = Some(driver);
223-
224-
morpheus_hwinit::serial::log_info("NET", 946, "registering NIC ops");
225-
morpheus_hwinit::register_nic(morpheus_hwinit::NicOps {
226-
tx: Some(user_net_tx),
227-
rx: Some(user_net_rx),
228-
link_up: Some(user_net_link_up),
229-
mac: Some(user_net_mac),
230-
refill: Some(user_net_refill),
231-
ctrl: Some(user_net_ctrl),
232-
});
233-
234-
// prime descriptor maintenance immediately.
235-
let _ = user_net_refill();
236-
237-
let link_now = user_net_link_up();
238-
if link_now != 0 {
239-
morpheus_hwinit::serial::log_ok("NET", 947, "activation complete: link up");
240-
} else {
241-
morpheus_hwinit::serial::log_info("NET", 948, "activation complete: link down");
242-
}
243-
244-
0
245-
}
246-
24754
/// Called by the hwinit serial hook for every byte emitted via `puts()`.
24855
/// Writes directly to the TextConsole backed by the GOP framebuffer.
24956
pub unsafe fn live_console_putc(b: u8) {
@@ -483,13 +290,11 @@ pub unsafe fn enter_baremetal(config: BaremetalEntryConfig) -> ! {
483290
};
484291

485292
// userspace network activation hook. we stay offline by default.
486-
USER_NET_DMA = Some(morpheus_network::dma::DmaRegion::new(
293+
network::init_userspace_network_activation(morpheus_network::dma::DmaRegion::new(
487294
platform.dma().cpu_base(),
488295
platform.dma().bus_base(),
489296
platform.dma().size(),
490-
));
491-
USER_NET_TSC_FREQ = platform.tsc_freq();
492-
morpheus_hwinit::register_net_activation(activate_network_from_userspace);
297+
), platform.tsc_freq());
493298

494299
// persistent storage — try to mount a real block device
495300
crate::storage::init_persistent_storage(platform.dma(), platform.tsc_freq());
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod network;
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use morpheus_network::boot::{probe_and_create_driver, ProbeError, ProbeResult};
2+
use morpheus_network::device::UnifiedNetDevice;
3+
use morpheus_network::stack::{NetConfig, NetInterface};
4+
5+
use super::{config, nic, state, tcp, udp_dns};
6+
7+
unsafe fn activate_network_from_userspace() -> i64 {
8+
morpheus_hwinit::serial::log_info("NET", 940, "userspace activation requested");
9+
10+
if state::has_driver() {
11+
morpheus_hwinit::serial::log_info("NET", 941, "already active");
12+
return 1;
13+
}
14+
15+
let Some((dma, tsc_freq)) = state::activation_context() else {
16+
morpheus_hwinit::serial::log_error("NET", 942, "activation failed: dma unavailable");
17+
return -1;
18+
};
19+
20+
morpheus_hwinit::serial::log_info("NET", 943, "probing NIC via network::probe_and_create_driver");
21+
let driver = match probe_and_create_driver(dma, tsc_freq) {
22+
Ok(ProbeResult::VirtIO(v)) => {
23+
morpheus_hwinit::serial::log_info("NET", 949, "probe selected virtio NIC");
24+
UnifiedNetDevice::VirtIO(v)
25+
}
26+
Ok(ProbeResult::Intel(i)) => {
27+
morpheus_hwinit::serial::log_info("NET", 951, "probe selected intel NIC");
28+
UnifiedNetDevice::Intel(i)
29+
}
30+
Err(ProbeError::NoDevice) => {
31+
morpheus_hwinit::serial::log_error("NET", 944, "probe failed: no supported NIC detected");
32+
nic::log_pci_network_candidates();
33+
return -2;
34+
}
35+
Err(ProbeError::VirtioInitFailed) => {
36+
morpheus_hwinit::serial::log_error("NET", 950, "virtio init failed");
37+
return -3;
38+
}
39+
Err(ProbeError::IntelInitFailed) => {
40+
morpheus_hwinit::serial::log_error("NET", 952, "intel init failed");
41+
return -3;
42+
}
43+
Err(ProbeError::DeviceNotResponding) => {
44+
morpheus_hwinit::serial::log_error("NET", 955, "nic mmio not responding");
45+
return -4;
46+
}
47+
Err(ProbeError::BarMappingFailed) => {
48+
morpheus_hwinit::serial::log_error("NET", 956, "nic bar mapping failure");
49+
return -5;
50+
}
51+
};
52+
53+
morpheus_hwinit::serial::log_ok("NET", 945, "driver initialized");
54+
55+
let stack = NetInterface::new(driver, NetConfig::dhcp());
56+
state::clear_net_handle_tables();
57+
state::set_stack(stack);
58+
59+
morpheus_hwinit::serial::log_info("NET", 946, "registering NIC ops");
60+
morpheus_hwinit::register_nic(morpheus_hwinit::NicOps {
61+
tx: Some(nic::user_net_tx),
62+
rx: Some(nic::user_net_rx),
63+
link_up: Some(nic::user_net_link_up),
64+
mac: Some(nic::user_net_mac),
65+
refill: Some(nic::user_net_refill),
66+
ctrl: Some(nic::user_net_ctrl),
67+
});
68+
69+
morpheus_hwinit::serial::log_info("NET", 957, "registering net stack ops");
70+
morpheus_hwinit::register_net_stack(morpheus_hwinit::NetStackOps {
71+
tcp_socket: Some(tcp::net_tcp_socket_impl),
72+
tcp_connect: Some(tcp::net_tcp_connect_impl),
73+
tcp_send: Some(tcp::net_tcp_send_impl),
74+
tcp_recv: Some(tcp::net_tcp_recv_impl),
75+
tcp_close: Some(tcp::net_tcp_close_impl),
76+
tcp_state: Some(tcp::net_tcp_state_impl),
77+
tcp_listen: Some(tcp::net_tcp_listen_impl),
78+
tcp_accept: Some(tcp::net_tcp_accept_impl),
79+
tcp_shutdown: Some(tcp::net_tcp_shutdown_impl),
80+
tcp_nodelay: Some(tcp::net_tcp_nodelay_impl),
81+
tcp_keepalive: Some(tcp::net_tcp_keepalive_impl),
82+
udp_socket: Some(udp_dns::net_udp_socket_impl),
83+
udp_send_to: Some(udp_dns::net_udp_send_to_impl),
84+
udp_recv_from: Some(udp_dns::net_udp_recv_from_impl),
85+
udp_close: Some(udp_dns::net_udp_close_impl),
86+
dns_start: Some(udp_dns::net_dns_start_impl),
87+
dns_result: Some(udp_dns::net_dns_result_impl),
88+
dns_set_servers: Some(udp_dns::net_dns_set_servers_impl),
89+
cfg_get: Some(config::net_cfg_get),
90+
cfg_dhcp: Some(config::net_cfg_dhcp),
91+
cfg_static_ip: Some(config::net_cfg_static_ip),
92+
cfg_hostname: Some(config::net_cfg_hostname),
93+
poll_drive: Some(config::net_poll_drive),
94+
poll_stats: Some(config::net_poll_stats),
95+
});
96+
97+
let _ = nic::user_net_refill();
98+
99+
let link_now = nic::user_net_link_up();
100+
if link_now != 0 {
101+
morpheus_hwinit::serial::log_ok("NET", 947, "activation complete: link up");
102+
} else {
103+
morpheus_hwinit::serial::log_info("NET", 948, "activation complete: link down");
104+
}
105+
106+
0
107+
}
108+
109+
pub(super) unsafe fn init_userspace_network_activation(
110+
dma: morpheus_network::dma::DmaRegion,
111+
tsc_freq: u64,
112+
) {
113+
state::set_activation_context(dma, tsc_freq);
114+
morpheus_hwinit::register_net_activation(activate_network_from_userspace);
115+
}

0 commit comments

Comments
 (0)