fix(baremetal,net): fix bare-metal boot freezes and implement real internet stack
- Zero user PML4 and allocated page tables in VMM to prevent dirty RAM crash on real hardware - Probe UART existence and add timeout to prevent infinite freeze on motherboards without COM1 - Clamp SMP AP boot to MAX_CPUS to prevent GDT/TSS corruption on multi-core CPUs - Add kernel early framebuffer console (FbConsole) with 8x16 font for direct HDMI/DP screen output - Configure Limine resolution and dynamic 4K draw buffers in gui_server to fix 1080p black screen - Implement RFC 793 TCP pseudo-header checksum and full TCP 3-way handshake - Implement DHCP client (UDP 67/68) and DNS client (UDP 53) - Add dns, dhcp commands to shell and update web browser with live URL loading
This commit is contained in:
+22
-1
@@ -69,6 +69,22 @@ typedef struct {
|
||||
uint16_t urgent_ptr;
|
||||
} tcp_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
} udp_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint16_t qdcount;
|
||||
uint16_t ancount;
|
||||
uint16_t nscount;
|
||||
uint16_t arcount;
|
||||
} dns_hdr_t;
|
||||
|
||||
#define TCP_FLAG_FIN 0x01
|
||||
#define TCP_FLAG_SYN 0x02
|
||||
#define TCP_FLAG_RST 0x04
|
||||
@@ -82,6 +98,7 @@ typedef struct {
|
||||
uint32_t ip;
|
||||
uint32_t netmask;
|
||||
uint32_t gateway;
|
||||
uint32_t dns_server;
|
||||
uint8_t mac[6];
|
||||
} net_config_t;
|
||||
|
||||
@@ -90,10 +107,14 @@ extern net_config_t g_net_cfg;
|
||||
// Net API
|
||||
void net_init(void);
|
||||
uint16_t net_checksum(const void *buf, size_t len);
|
||||
uint16_t net_tcp_checksum(uint32_t src_ip, uint32_t dst_ip, const tcp_hdr_t *tcp, size_t tcp_len);
|
||||
int net_send_arp_request(uint32_t target_ip);
|
||||
int net_send_icmp_ping(uint32_t target_ip, uint16_t seq);
|
||||
int net_poll_icmp_reply(uint32_t *from_ip, uint16_t *seq);
|
||||
int net_http_get(uint32_t target_ip, uint16_t port, const char *path, char *out_body, size_t max_body_len);
|
||||
int net_dns_resolve(const char *domain, uint32_t *out_ip);
|
||||
int net_dhcp_discover(void);
|
||||
int net_http_get(uint32_t target_ip, uint16_t port, const char *path, const char *host_header, char *out_body, size_t max_body_len);
|
||||
int net_http_get_url(const char *url, char *out_body, size_t max_body_len);
|
||||
uint32_t parse_ip(const char *str);
|
||||
void format_ip(uint32_t ip, char *buf);
|
||||
|
||||
|
||||
@@ -70,8 +70,9 @@ pub unsafe fn boot_aps() {
|
||||
|
||||
let cpu_count = (*smp_resp).cpu_count;
|
||||
let bsp_lapic_id = (*smp_resp).bsp_lapic_id;
|
||||
let max_cores = cpu_count.min(super::gdt::MAX_CPUS as u64);
|
||||
|
||||
for i in 0..cpu_count {
|
||||
for i in 0..max_cores {
|
||||
let cpu_info = *(*smp_resp).cpus.add(i as usize);
|
||||
if (*cpu_info).lapic_id != bsp_lapic_id {
|
||||
let info_mut = cpu_info as *mut LimineSmpInfo;
|
||||
|
||||
@@ -388,6 +388,7 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
|
||||
(*out_ptr).pitch = pitch;
|
||||
(*out_ptr).bpp = bpp as u32;
|
||||
}
|
||||
crate::drivers::fb_console::FbConsole::disable();
|
||||
regs.rax = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
//! Early Microkernel Framebuffer Text Console (8x16 Bitmap Font)
|
||||
//! Renders boot logs and microkernel diagnostics directly to HDMI/DisplayPort monitor.
|
||||
|
||||
use crate::limine_requests::get_framebuffer;
|
||||
use core::fmt::{self, Write};
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
pub const FONT8X16: [[u8; 16]; 96] = [
|
||||
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 32 ' '
|
||||
[0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00], // 33 '!'
|
||||
[0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 34 '"'
|
||||
[0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00], // 35 '#'
|
||||
[0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00], // 36 '$'
|
||||
[0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,0x00], // 37 '%'
|
||||
[0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,0x00], // 38 '&'
|
||||
[0x00,0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 39 '\''
|
||||
[0x00,0x0C,0x18,0x30,0x30,0x60,0x60,0x60,0x60,0x30,0x30,0x18,0x0C,0x00,0x00,0x00], // 40 '('
|
||||
[0x00,0x30,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00], // 41 ')'
|
||||
[0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 42 '*'
|
||||
[0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 43 '+'
|
||||
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00], // 44 ','
|
||||
[0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 45 '-'
|
||||
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00], // 46 '.'
|
||||
[0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00], // 47 '/'
|
||||
[0x00,0x3C,0x66,0xC3,0xE3,0xD3,0xDB,0xCF,0xC7,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 48 '0'
|
||||
[0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00], // 49 '1'
|
||||
[0x00,0x3C,0x66,0xC3,0x03,0x06,0x0C,0x18,0x30,0x60,0xC3,0xFF,0x00,0x00,0x00,0x00], // 50 '2'
|
||||
[0x00,0x3C,0x66,0xC3,0x03,0x06,0x1C,0x06,0x03,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 51 '3'
|
||||
[0x00,0x06,0x0E,0x1E,0x36,0x66,0xC6,0xFF,0x06,0x06,0x06,0x0F,0x00,0x00,0x00,0x00], // 52 '4'
|
||||
[0x00,0x7F,0x60,0x60,0x7C,0x66,0x03,0x03,0x03,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 53 '5'
|
||||
[0x00,0x3C,0x66,0xC0,0xC0,0xDC,0xE6,0xC3,0xC3,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 54 '6'
|
||||
[0x00,0xFF,0xC3,0x03,0x06,0x0C,0x18,0x30,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00], // 55 '7'
|
||||
[0x00,0x3C,0x66,0xC3,0xC3,0x66,0x3C,0x66,0xC3,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 56 '8'
|
||||
[0x00,0x3C,0x66,0xC3,0xC3,0xC3,0x67,0x3B,0x03,0x03,0x66,0x3C,0x00,0x00,0x00,0x00], // 57 '9'
|
||||
[0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00], // 58 ':'
|
||||
[0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00], // 59 ';'
|
||||
[0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00], // 60 '<'
|
||||
[0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 61 '='
|
||||
[0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00], // 62 '>'
|
||||
[0x00,0x3C,0x66,0xC3,0x03,0x06,0x0C,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00], // 63 '?'
|
||||
[0x00,0x3C,0x66,0xC3,0xDF,0xDB,0xDB,0xDB,0xDE,0xC0,0x66,0x3C,0x00,0x00,0x00,0x00], // 64 '@'
|
||||
[0x00,0x18,0x3C,0x66,0xC3,0xC3,0xFF,0xC3,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00], // 65 'A'
|
||||
[0x00,0xFE,0x63,0x63,0x63,0x7E,0x63,0x63,0x63,0x63,0x63,0xFE,0x00,0x00,0x00,0x00], // 66 'B'
|
||||
[0x00,0x3C,0x66,0xC3,0xC0,0xC0,0xC0,0xC0,0xC0,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 67 'C'
|
||||
[0x00,0xFC,0x66,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x66,0xFC,0x00,0x00,0x00,0x00], // 68 'D'
|
||||
[0x00,0xFF,0x63,0x60,0x60,0x7C,0x60,0x60,0x60,0x60,0x63,0xFF,0x00,0x00,0x00,0x00], // 69 'E'
|
||||
[0x00,0xFF,0x63,0x60,0x60,0x7C,0x60,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00], // 70 'F'
|
||||
[0x00,0x3C,0x66,0xC3,0xC0,0xC0,0xDE,0xC3,0xC3,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 71 'G'
|
||||
[0x00,0xC3,0xC3,0xC3,0xC3,0xFF,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00], // 72 'H'
|
||||
[0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00], // 73 'I'
|
||||
[0x00,0x0F,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 74 'J'
|
||||
[0x00,0xC3,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0xC6,0xC3,0xC3,0x00,0x00,0x00,0x00], // 75 'K'
|
||||
[0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x63,0x63,0xFF,0x00,0x00,0x00,0x00], // 76 'L'
|
||||
[0x00,0xC3,0xE7,0xFF,0xDB,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00], // 77 'M'
|
||||
[0x00,0xC3,0xE3,0xF3,0xFB,0xDF,0xCF,0xC7,0xC3,0xC3,0xC3,0xC3,0x00,0x00,0x00,0x00], // 78 'N'
|
||||
[0x00,0x3C,0x66,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 79 'O'
|
||||
[0x00,0xFE,0x63,0x63,0x63,0x63,0x7E,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00], // 80 'P'
|
||||
[0x00,0x3C,0x66,0xC3,0xC3,0xC3,0xC3,0xC3,0xC7,0xCF,0x66,0x3C,0x06,0x03,0x00,0x00], // 81 'Q'
|
||||
[0x00,0xFE,0x63,0x63,0x63,0x7E,0x6C,0x66,0x63,0x63,0x63,0xC6,0x00,0x00,0x00,0x00], // 82 'R'
|
||||
[0x00,0x3C,0x66,0xC3,0x60,0x38,0x0E,0x03,0xC3,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 83 'S'
|
||||
[0x00,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00], // 84 'T'
|
||||
[0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00], // 85 'U'
|
||||
[0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x66,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00], // 86 'V'
|
||||
[0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x66,0x66,0x00,0x00,0x00,0x00], // 87 'W'
|
||||
[0x00,0xC3,0xC3,0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00], // 88 'X'
|
||||
[0x00,0xC3,0xC3,0xC3,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00], // 89 'Y'
|
||||
[0x00,0xFF,0xC3,0x86,0x0C,0x18,0x30,0x60,0xC0,0xC1,0xC3,0xFF,0x00,0x00,0x00,0x00], // 90 'Z'
|
||||
[0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00], // 91 '['
|
||||
[0x00,0x00,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00], // 92 '\\'
|
||||
[0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00], // 93 ']'
|
||||
[0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 94 '^'
|
||||
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00], // 95 '_'
|
||||
[0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 96 '`'
|
||||
[0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0xC6,0xC6,0x7E,0x00,0x00,0x00,0x00,0x00,0x00], // 97 'a'
|
||||
[0x00,0xE0,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0xDC,0x00,0x00,0x00,0x00,0x00,0x00], // 98 'b'
|
||||
[0x00,0x00,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00], // 99 'c'
|
||||
[0x00,0x0E,0x06,0x06,0x3E,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00,0x00,0x00], // 100 'd'
|
||||
[0x00,0x00,0x00,0x3C,0x66,0xFF,0xC0,0xC0,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00], // 101 'e'
|
||||
[0x00,0x1C,0x36,0x30,0x78,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00], // 102 'f'
|
||||
[0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00], // 103 'g'
|
||||
[0x00,0xE0,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0xE7,0x00,0x00,0x00,0x00,0x00,0x00], // 104 'h'
|
||||
[0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00], // 105 'i'
|
||||
[0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00], // 106 'j'
|
||||
[0x00,0xE0,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE7,0x00,0x00,0x00,0x00,0x00,0x00], // 107 'k'
|
||||
[0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00], // 108 'l'
|
||||
[0x00,0x00,0x00,0xE6,0xFF,0xDB,0xDB,0xDB,0xDB,0xFF,0x00,0x00,0x00,0x00,0x00,0x00], // 109 'm'
|
||||
[0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0xE7,0x00,0x00,0x00,0x00,0x00,0x00], // 110 'n'
|
||||
[0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00], // 111 'o'
|
||||
[0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x7C,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00], // 112 'p'
|
||||
[0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x3E,0x06,0x0F,0x00,0x00,0x00,0x00,0x00,0x00], // 113 'q'
|
||||
[0x00,0x00,0x00,0xDC,0x66,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,0x00,0x00], // 114 'r'
|
||||
[0x00,0x00,0x00,0x3E,0x60,0x3C,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 115 's'
|
||||
[0x00,0x10,0x30,0x7E,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,0x00,0x00], // 116 't'
|
||||
[0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00,0x00,0x00], // 117 'u'
|
||||
[0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00], // 118 'v'
|
||||
[0x00,0x00,0x00,0xC3,0xC3,0xDB,0xDB,0xFF,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00], // 119 'w'
|
||||
[0x00,0x00,0x00,0xC3,0x66,0x3C,0x18,0x3C,0x66,0xC3,0x00,0x00,0x00,0x00,0x00,0x00], // 120 'x'
|
||||
[0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x38,0x00,0x00,0x00,0x00,0x00], // 121 'y'
|
||||
[0x00,0x00,0x00,0x7E,0x4C,0x18,0x30,0x62,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 122 'z'
|
||||
[0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,0x00,0x00], // 123 '['
|
||||
[0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00], // 124 '|'
|
||||
[0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,0x00,0x00], // 125 ']'
|
||||
[0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 126 '~'
|
||||
[0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // 127
|
||||
];
|
||||
|
||||
pub struct FbConsole;
|
||||
|
||||
static mut CURSOR_COL: usize = 0;
|
||||
static mut CURSOR_ROW: usize = 0;
|
||||
static CONSOLE_ENABLED: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
impl FbConsole {
|
||||
pub fn disable() {
|
||||
CONSOLE_ENABLED.store(false, Ordering::Release);
|
||||
}
|
||||
|
||||
pub fn enable() {
|
||||
CONSOLE_ENABLED.store(true, Ordering::Release);
|
||||
}
|
||||
|
||||
pub fn write_char(c: u8) {
|
||||
if !CONSOLE_ENABLED.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some((addr, width, height, pitch, bpp)) = get_framebuffer() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if bpp != 32 {
|
||||
return;
|
||||
}
|
||||
|
||||
let max_cols = (width / 8) as usize;
|
||||
let max_rows = (height / 16) as usize;
|
||||
|
||||
unsafe {
|
||||
if c == b'\n' {
|
||||
CURSOR_COL = 0;
|
||||
CURSOR_ROW += 1;
|
||||
if CURSOR_ROW >= max_rows {
|
||||
CURSOR_ROW = 0; // Wrap around to top for simplicity without heavy scroll
|
||||
}
|
||||
return;
|
||||
}
|
||||
if c == b'\r' {
|
||||
CURSOR_COL = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
let glyph_idx = if c >= 32 && c <= 127 {
|
||||
(c - 32) as usize
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let glyph = &FONT8X16[glyph_idx];
|
||||
let fb = addr as *mut u32;
|
||||
let pitch_pixels = (pitch / 4) as usize;
|
||||
|
||||
let start_x = CURSOR_COL * 8;
|
||||
let start_y = CURSOR_ROW * 16;
|
||||
|
||||
for dy in 0..16 {
|
||||
let row_bits = glyph[dy];
|
||||
let row_offset = (start_y + dy) * pitch_pixels;
|
||||
for dx in 0..8 {
|
||||
let is_pixel = (row_bits & (0x80 >> dx)) != 0;
|
||||
let color = if is_pixel { 0x00E2E8F0 } else { 0x000F172A };
|
||||
*fb.add(row_offset + start_x + dx) = color;
|
||||
}
|
||||
}
|
||||
|
||||
CURSOR_COL += 1;
|
||||
if CURSOR_COL >= max_cols {
|
||||
CURSOR_COL = 0;
|
||||
CURSOR_ROW += 1;
|
||||
if CURSOR_ROW >= max_rows {
|
||||
CURSOR_ROW = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_str(s: &str) {
|
||||
for b in s.bytes() {
|
||||
Self::write_char(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for FbConsole {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
FbConsole::write_str(s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -5,3 +5,4 @@ pub mod rtc;
|
||||
pub mod dmesg;
|
||||
pub mod mouse;
|
||||
pub mod rng;
|
||||
pub mod fb_console;
|
||||
|
||||
@@ -6,6 +6,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
|
||||
const COM1: u16 = 0x3F8;
|
||||
|
||||
static SERIAL_INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||
static SERIAL_PRESENT: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[inline]
|
||||
unsafe fn outb(port: u16, val: u8) {
|
||||
@@ -24,6 +25,20 @@ pub struct SerialPort;
|
||||
impl SerialPort {
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
// Scratch register test to verify 16550 UART hardware presence on motherboard
|
||||
outb(COM1 + 7, 0x55);
|
||||
if inb(COM1 + 7) != 0x55 {
|
||||
SERIAL_INITIALIZED.store(true, Ordering::Release);
|
||||
SERIAL_PRESENT.store(false, Ordering::Release);
|
||||
return;
|
||||
}
|
||||
outb(COM1 + 7, 0xAA);
|
||||
if inb(COM1 + 7) != 0xAA {
|
||||
SERIAL_INITIALIZED.store(true, Ordering::Release);
|
||||
SERIAL_PRESENT.store(false, Ordering::Release);
|
||||
return;
|
||||
}
|
||||
|
||||
outb(COM1 + 1, 0x00); // Disable all interrupts
|
||||
outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||
outb(COM1 + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
|
||||
@@ -31,21 +46,37 @@ impl SerialPort {
|
||||
outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||
outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
|
||||
SERIAL_PRESENT.store(true, Ordering::Release);
|
||||
SERIAL_INITIALIZED.store(true, Ordering::Release);
|
||||
}
|
||||
SERIAL_INITIALIZED.store(true, Ordering::Release);
|
||||
}
|
||||
|
||||
pub fn is_present(&self) -> bool {
|
||||
SERIAL_PRESENT.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn write_byte(&self, byte: u8) {
|
||||
if !SERIAL_PRESENT.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
// Wait for transmit buffer empty
|
||||
while (inb(COM1 + 5) & 0x20) == 0 {
|
||||
// Bounded timeout: prevent deadlocks on bare-metal PCs without physical COM1 port
|
||||
let mut timeout = 25000usize;
|
||||
while (inb(COM1 + 5) & 0x20) == 0 && timeout > 0 {
|
||||
timeout -= 1;
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
outb(COM1, byte);
|
||||
if timeout > 0 {
|
||||
outb(COM1, byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_data(&self) -> bool {
|
||||
if !SERIAL_PRESENT.load(Ordering::Relaxed) {
|
||||
return false;
|
||||
}
|
||||
unsafe {
|
||||
(inb(COM1 + 5) & 0x01) != 0
|
||||
}
|
||||
@@ -82,6 +113,8 @@ impl Write for SerialPort {
|
||||
pub fn _kprint(args: fmt::Arguments) {
|
||||
let mut port = SerialPort;
|
||||
let _ = port.write_fmt(args);
|
||||
let mut con = crate::drivers::fb_console::FbConsole;
|
||||
let _ = con.write_fmt(args);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
@@ -63,6 +63,11 @@ impl VirtualMemoryManager {
|
||||
let current_cr3 = self.read_cr3() & PAGE_MASK;
|
||||
let kernel_pml4 = self.phys_to_virt::<PageTable>(current_cr3);
|
||||
|
||||
// Explicitly zero lower half (user space: 0..256) to eliminate dirty BIOS/Ventoy RAM residues
|
||||
for i in 0..256 {
|
||||
(*user_pml4).entries[i] = 0;
|
||||
}
|
||||
|
||||
// Copy kernel mappings (higher half: 256..512)
|
||||
for i in 256..512 {
|
||||
(*user_pml4).entries[i] = (*kernel_pml4).entries[i];
|
||||
@@ -188,6 +193,10 @@ impl VirtualMemoryManager {
|
||||
} else {
|
||||
let pfa_ptr = core::ptr::addr_of_mut!(PFA);
|
||||
let new_frame = (*pfa_ptr).alloc_frame().ok_or(())?;
|
||||
// Crucial for bare-metal boot: zero out newly allocated page table frame
|
||||
let new_tbl_ptr = self.phys_to_virt::<u8>(new_frame);
|
||||
core::ptr::write_bytes(new_tbl_ptr, 0, PAGE_SIZE);
|
||||
|
||||
let flags = PAGE_PRESENT | PAGE_WRITABLE | (inherit_flags & PAGE_USER);
|
||||
*entry = (new_frame & PAGE_MASK) | flags;
|
||||
Ok(new_frame)
|
||||
|
||||
+522
-115
@@ -2,23 +2,41 @@
|
||||
#include "rtl8139.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
// Default QEMU User Networking (SLIRP) Configuration
|
||||
// Guest IP: 10.0.2.15
|
||||
// Gateway: 10.0.2.2 (Default QEMU MAC: 52:55:0a:00:02:02)
|
||||
// DNS: 10.0.2.3
|
||||
net_config_t g_net_cfg = {
|
||||
.ip = (10) | (0 << 8) | (2 << 16) | (15 << 24),
|
||||
.gateway = (10) | (0 << 8) | (2 << 16) | (2 << 24),
|
||||
.dns_server = (10) | (0 << 8) | (2 << 16) | (3 << 24),
|
||||
.netmask = (255) | (255 << 8) | (255 << 16) | (0 << 24),
|
||||
.mac = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56}
|
||||
};
|
||||
|
||||
static uint8_t g_gateway_mac[6] = {0x52, 0x55, 0x0a, 0x00, 0x02, 0x02};
|
||||
|
||||
static uint16_t htons(uint16_t v) {
|
||||
static inline uint16_t htons(uint16_t v) {
|
||||
return (uint16_t)(((v & 0xFF) << 8) | ((v >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
static inline uint16_t ntohs(uint16_t v) {
|
||||
return htons(v);
|
||||
}
|
||||
|
||||
static inline uint32_t htonl(uint32_t v) {
|
||||
return (((v & 0x000000FF) << 24) |
|
||||
((v & 0x0000FF00) << 8) |
|
||||
((v & 0x00FF0000) >> 8) |
|
||||
((v & 0xFF000000) >> 24));
|
||||
}
|
||||
|
||||
static inline uint32_t ntohl(uint32_t v) {
|
||||
return htonl(v);
|
||||
}
|
||||
|
||||
uint16_t net_checksum(const void *buf, size_t len) {
|
||||
const uint16_t *data = (const uint16_t *)buf;
|
||||
uint32_t sum = 0;
|
||||
@@ -36,6 +54,43 @@ uint16_t net_checksum(const void *buf, size_t len) {
|
||||
return (uint16_t)(~sum);
|
||||
}
|
||||
|
||||
// RFC 793 TCP Pseudo-Header Checksum
|
||||
uint16_t net_tcp_checksum(uint32_t src_ip, uint32_t dst_ip, const tcp_hdr_t *tcp, size_t tcp_len) {
|
||||
struct __attribute__((packed)) {
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint8_t zero;
|
||||
uint8_t proto;
|
||||
uint16_t length;
|
||||
} ph;
|
||||
|
||||
ph.src = src_ip;
|
||||
ph.dst = dst_ip;
|
||||
ph.zero = 0;
|
||||
ph.proto = IP_PROTO_TCP;
|
||||
ph.length = htons((uint16_t)tcp_len);
|
||||
|
||||
uint32_t sum = 0;
|
||||
const uint16_t *p = (const uint16_t *)&ph;
|
||||
for (size_t i = 0; i < sizeof(ph) / 2; i++) {
|
||||
sum += p[i];
|
||||
}
|
||||
|
||||
const uint16_t *data = (const uint16_t *)tcp;
|
||||
size_t len = tcp_len;
|
||||
while (len > 1) {
|
||||
sum += *data++;
|
||||
len -= 2;
|
||||
}
|
||||
if (len == 1) {
|
||||
sum += *(const uint8_t *)data;
|
||||
}
|
||||
while (sum >> 16) {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
return (uint16_t)(~sum);
|
||||
}
|
||||
|
||||
void net_init(void) {
|
||||
rtl8139_init();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
@@ -50,17 +105,15 @@ int net_send_arp_request(uint32_t target_ip) {
|
||||
eth_hdr_t *eth = (eth_hdr_t *)packet;
|
||||
arp_hdr_t *arp = (arp_hdr_t *)(packet + sizeof(eth_hdr_t));
|
||||
|
||||
// Broadcast Ethernet Header
|
||||
memset(eth->dest_mac, 0xFF, 6);
|
||||
memcpy(eth->src_mac, g_net_cfg.mac, 6);
|
||||
eth->ethertype = htons(ETHERTYPE_ARP);
|
||||
|
||||
// ARP Payload (Who has target_ip? Tell sender_ip)
|
||||
arp->hw_type = htons(1); // Ethernet
|
||||
arp->proto_type = htons(0x0800); // IPv4
|
||||
arp->hw_type = htons(1);
|
||||
arp->proto_type = htons(0x0800);
|
||||
arp->hw_len = 6;
|
||||
arp->proto_len = 4;
|
||||
arp->opcode = htons(1); // Request
|
||||
arp->opcode = htons(1); // ARP Request
|
||||
memcpy(arp->sender_mac, g_net_cfg.mac, 6);
|
||||
arp->sender_ip = g_net_cfg.ip;
|
||||
memset(arp->target_mac, 0x00, 6);
|
||||
@@ -76,17 +129,15 @@ int net_send_icmp_ping(uint32_t target_ip, uint16_t seq) {
|
||||
icmp_hdr_t *icmp = (icmp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
|
||||
uint8_t *payload = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t);
|
||||
|
||||
// 1. Ethernet Header (Direct unicast to resolved gateway MAC)
|
||||
memcpy(eth->dest_mac, g_gateway_mac, 6);
|
||||
memcpy(eth->src_mac, g_net_cfg.mac, 6);
|
||||
eth->ethertype = htons(ETHERTYPE_IPv4);
|
||||
|
||||
// 2. IPv4 Header
|
||||
ip->version_ihl = 0x45; // Version 4, Header Length 5 (20 bytes)
|
||||
ip->version_ihl = 0x45;
|
||||
ip->tos = 0;
|
||||
ip->total_length = htons(20 + 8 + 32); // IP + ICMP + 32-byte payload = 60 bytes
|
||||
ip->total_length = htons(20 + 8 + 32);
|
||||
ip->id = htons(seq);
|
||||
ip->flags_fragment = htons(0x4000); // Don't Fragment
|
||||
ip->flags_fragment = htons(0x4000);
|
||||
ip->ttl = 64;
|
||||
ip->protocol = IP_PROTO_ICMP;
|
||||
ip->src_ip = g_net_cfg.ip;
|
||||
@@ -94,120 +145,352 @@ int net_send_icmp_ping(uint32_t target_ip, uint16_t seq) {
|
||||
ip->checksum = 0;
|
||||
ip->checksum = net_checksum(ip, 20);
|
||||
|
||||
// 3. ICMP Echo Request Header
|
||||
icmp->type = ICMP_ECHO_REQUEST;
|
||||
icmp->code = 0;
|
||||
icmp->id = htons(0x1234);
|
||||
icmp->sequence = htons(seq);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
payload[i] = (uint8_t)('a' + (i % 26));
|
||||
payload[i] = (uint8_t)('A' + (i % 26));
|
||||
}
|
||||
|
||||
icmp->checksum = 0;
|
||||
icmp->checksum = net_checksum(icmp, 8 + 32);
|
||||
|
||||
size_t total_len = sizeof(eth_hdr_t) + 20 + 8 + 32;
|
||||
return rtl8139_send_packet(packet, (uint16_t)total_len);
|
||||
return rtl8139_send_packet(packet, sizeof(eth_hdr_t) + 20 + 8 + 32);
|
||||
}
|
||||
|
||||
int net_poll_icmp_reply(uint32_t *from_ip, uint16_t *seq) {
|
||||
uint8_t buffer[1600];
|
||||
int len = rtl8139_poll_packet(buffer, sizeof(buffer));
|
||||
|
||||
if (len < (int)sizeof(eth_hdr_t)) {
|
||||
return 0;
|
||||
uint8_t buf[1600];
|
||||
int len = rtl8139_poll_packet(buf, sizeof(buf));
|
||||
if (len < (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
eth_hdr_t *eth = (eth_hdr_t *)buffer;
|
||||
|
||||
// Handle ARP Reply to dynamically update gateway MAC
|
||||
if (htons(eth->ethertype) == ETHERTYPE_ARP && len >= (int)(sizeof(eth_hdr_t) + sizeof(arp_hdr_t))) {
|
||||
arp_hdr_t *arp = (arp_hdr_t *)(buffer + sizeof(eth_hdr_t));
|
||||
if (htons(arp->opcode) == 2) { // ARP Reply
|
||||
eth_hdr_t *eth = (eth_hdr_t *)buf;
|
||||
if (htons(eth->ethertype) == ETHERTYPE_ARP) {
|
||||
arp_hdr_t *arp = (arp_hdr_t *)(buf + sizeof(eth_hdr_t));
|
||||
if (htons(arp->opcode) == 2 && arp->sender_ip == g_net_cfg.gateway) {
|
||||
memcpy(g_gateway_mac, arp->sender_mac, 6);
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (htons(eth->ethertype) != ETHERTYPE_IPv4 || len < (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ipv4_hdr_t *ip = (ipv4_hdr_t *)(buffer + sizeof(eth_hdr_t));
|
||||
if (ip->protocol != IP_PROTO_ICMP) {
|
||||
return 0;
|
||||
}
|
||||
if (htons(eth->ethertype) != ETHERTYPE_IPv4) return -1;
|
||||
ipv4_hdr_t *ip = (ipv4_hdr_t *)(buf + sizeof(eth_hdr_t));
|
||||
if (ip->protocol != IP_PROTO_ICMP) return -1;
|
||||
|
||||
int ip_hdr_len = (ip->version_ihl & 0x0F) * 4;
|
||||
icmp_hdr_t *icmp = (icmp_hdr_t *)(buffer + sizeof(eth_hdr_t) + ip_hdr_len);
|
||||
icmp_hdr_t *icmp = (icmp_hdr_t *)(buf + sizeof(eth_hdr_t) + ip_hdr_len);
|
||||
|
||||
if (icmp->type == ICMP_ECHO_REPLY) {
|
||||
if (from_ip) *from_ip = ip->src_ip;
|
||||
if (seq) *seq = htons(icmp->sequence);
|
||||
return 1; // Genuine Echo Reply received!
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t parse_ip(const char *str) {
|
||||
uint32_t parts[4] = {0};
|
||||
int idx = 0;
|
||||
while (*str && idx < 4) {
|
||||
uint32_t ip = 0;
|
||||
int octet = 0;
|
||||
int shift = 0;
|
||||
|
||||
while (*str) {
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
parts[idx] = parts[idx] * 10 + (*str - '0');
|
||||
octet = octet * 10 + (*str - '0');
|
||||
} else if (*str == '.') {
|
||||
idx++;
|
||||
ip |= ((uint32_t)(octet & 0xFF) << shift);
|
||||
shift += 8;
|
||||
octet = 0;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return (parts[0]) | (parts[1] << 8) | (parts[2] << 16) | (parts[3] << 24);
|
||||
ip |= ((uint32_t)(octet & 0xFF) << shift);
|
||||
return ip;
|
||||
}
|
||||
|
||||
void format_ip(uint32_t ip, char *buf) {
|
||||
uint8_t *b = (uint8_t *)&ip;
|
||||
int len = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t val = b[i];
|
||||
if (val >= 100) {
|
||||
buf[len++] = '0' + (val / 100);
|
||||
val %= 100;
|
||||
buf[len++] = '0' + (val / 10);
|
||||
val %= 10;
|
||||
} else if (val >= 10) {
|
||||
buf[len++] = '0' + (val / 10);
|
||||
val %= 10;
|
||||
uint8_t b = (uint8_t)((ip >> (i * 8)) & 0xFF);
|
||||
if (b >= 100) {
|
||||
buf[len++] = '0' + (b / 100);
|
||||
b %= 100;
|
||||
buf[len++] = '0' + (b / 10);
|
||||
b %= 10;
|
||||
} else if (b >= 10) {
|
||||
buf[len++] = '0' + (b / 10);
|
||||
b %= 10;
|
||||
}
|
||||
buf[len++] = '0' + val;
|
||||
buf[len++] = '0' + b;
|
||||
if (i < 3) buf[len++] = '.';
|
||||
}
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
int net_http_get(uint32_t target_ip, uint16_t port, const char *path, char *out_body, size_t max_body_len) {
|
||||
if (!out_body || max_body_len == 0) return -1;
|
||||
if (!path || !*path) path = "/";
|
||||
// =========================================================================
|
||||
// DNS CLIENT (UDP Port 53) - Resolves Hostnames to Real IPv4 Addresses
|
||||
// =========================================================================
|
||||
int net_dns_resolve(const char *domain, uint32_t *out_ip) {
|
||||
if (!domain || !*domain || !out_ip) return -1;
|
||||
|
||||
// 1. Craft TCP SYN packet
|
||||
uint8_t packet[128] = {0};
|
||||
eth_hdr_t *eth = (eth_hdr_t *)packet;
|
||||
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
|
||||
tcp_hdr_t *tcp = (tcp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
|
||||
// Check if domain is already a numerical IPv4 address
|
||||
bool is_numeric = true;
|
||||
for (const char *p = domain; *p; p++) {
|
||||
if (!((*p >= '0' && *p <= '9') || *p == '.')) {
|
||||
is_numeric = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_numeric) {
|
||||
*out_ip = parse_ip(domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t local_port = 49152 + (uint16_t)(target_ip & 0x3FF);
|
||||
uint32_t my_seq = 0x10002000;
|
||||
uint8_t packet[512] = {0};
|
||||
eth_hdr_t *eth = (eth_hdr_t *)packet;
|
||||
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
|
||||
udp_hdr_t *udp = (udp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
|
||||
uint8_t *dns_payload = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
|
||||
|
||||
// Build DNS Header
|
||||
dns_hdr_t *dns = (dns_hdr_t *)dns_payload;
|
||||
uint16_t query_id = 0x5A5A;
|
||||
dns->id = htons(query_id);
|
||||
dns->flags = htons(0x0100); // Standard query with recursion desired
|
||||
dns->qdcount = htons(1); // 1 question
|
||||
dns->ancount = 0;
|
||||
dns->nscount = 0;
|
||||
dns->arcount = 0;
|
||||
|
||||
// Format QNAME: e.g. "httpbin.org" -> \x07httpbin\x03org\x00
|
||||
uint8_t *qname = dns_payload + sizeof(dns_hdr_t);
|
||||
const char *src = domain;
|
||||
while (*src) {
|
||||
const char *dot = strchr(src, '.');
|
||||
size_t len = dot ? (size_t)(dot - src) : strlen(src);
|
||||
*qname++ = (uint8_t)len;
|
||||
memcpy(qname, src, len);
|
||||
qname += len;
|
||||
src += len;
|
||||
if (*src == '.') src++;
|
||||
}
|
||||
*qname++ = 0x00; // Null terminator for QNAME
|
||||
|
||||
// QTYPE (A = 1) and QCLASS (IN = 1)
|
||||
*qname++ = 0x00; *qname++ = 0x01; // Type A
|
||||
*qname++ = 0x00; *qname++ = 0x01; // Class IN
|
||||
|
||||
size_t dns_len = (size_t)(qname - dns_payload);
|
||||
size_t udp_len = sizeof(udp_hdr_t) + dns_len;
|
||||
size_t ip_len = sizeof(ipv4_hdr_t) + udp_len;
|
||||
size_t total_packet_len = sizeof(eth_hdr_t) + ip_len;
|
||||
|
||||
// Ethernet Header
|
||||
memcpy(eth->dest_mac, g_gateway_mac, 6);
|
||||
uint8_t target_mac[6];
|
||||
if ((g_net_cfg.dns_server & 0x00FFFFFF) == (g_net_cfg.ip & 0x00FFFFFF)) {
|
||||
// Local subnet (e.g. QEMU 10.0.2.3): match last octet
|
||||
memcpy(target_mac, g_gateway_mac, 6);
|
||||
target_mac[5] = (uint8_t)(g_net_cfg.dns_server >> 24);
|
||||
} else {
|
||||
// External DNS (e.g. 1.1.1.1 or 8.8.8.8): route via Gateway
|
||||
memcpy(target_mac, g_gateway_mac, 6);
|
||||
}
|
||||
memcpy(eth->dest_mac, target_mac, 6);
|
||||
memcpy(eth->src_mac, g_net_cfg.mac, 6);
|
||||
eth->ethertype = htons(ETHERTYPE_IPv4);
|
||||
|
||||
// IPv4 Header
|
||||
ip->version_ihl = 0x45;
|
||||
ip->tos = 0;
|
||||
ip->total_length = htons((uint16_t)ip_len);
|
||||
ip->id = htons(0x7788);
|
||||
ip->flags_fragment = htons(0x4000);
|
||||
ip->ttl = 64;
|
||||
ip->protocol = IP_PROTO_UDP;
|
||||
ip->src_ip = g_net_cfg.ip;
|
||||
ip->dst_ip = g_net_cfg.dns_server;
|
||||
ip->checksum = 0;
|
||||
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
|
||||
|
||||
// UDP Header
|
||||
uint16_t src_port = 52345;
|
||||
udp->src_port = htons(src_port);
|
||||
udp->dst_port = htons(53); // DNS Port
|
||||
udp->length = htons((uint16_t)udp_len);
|
||||
udp->checksum = 0; // Optional in IPv4 UDP
|
||||
|
||||
// Transmit DNS Query (ensure minimum Ethernet frame size 60 bytes)
|
||||
rtl8139_send_packet(packet, total_packet_len < 60 ? 60 : total_packet_len);
|
||||
|
||||
// Poll for DNS response with realistic WAN timeout (~1.5 seconds)
|
||||
uint8_t rx_buf[1600];
|
||||
for (int retry = 0; retry < 300; retry++) {
|
||||
int rx_len = rtl8139_poll_packet(rx_buf, sizeof(rx_buf));
|
||||
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + sizeof(dns_hdr_t))) {
|
||||
eth_hdr_t *rx_eth = (eth_hdr_t *)rx_buf;
|
||||
if (htons(rx_eth->ethertype) == ETHERTYPE_IPv4) {
|
||||
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx_buf + sizeof(eth_hdr_t));
|
||||
if (rx_ip->protocol == IP_PROTO_UDP) {
|
||||
udp_hdr_t *rx_udp = (udp_hdr_t *)(rx_buf + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
|
||||
if (htons(rx_udp->dst_port) == src_port) {
|
||||
uint8_t *resp_dns = rx_buf + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
|
||||
dns_hdr_t *rx_dns_hdr = (dns_hdr_t *)resp_dns;
|
||||
|
||||
if (ntohs(rx_dns_hdr->id) == query_id && (ntohs(rx_dns_hdr->flags) & 0x8000) && ntohs(rx_dns_hdr->ancount) > 0) {
|
||||
// Skip DNS Question section to reach Answer section
|
||||
uint8_t *ptr = resp_dns + sizeof(dns_hdr_t);
|
||||
// Skip QNAME
|
||||
while (*ptr && ptr < rx_buf + rx_len) {
|
||||
if ((*ptr & 0xC0) == 0xC0) { ptr += 2; break; } // Compression pointer
|
||||
ptr += (*ptr + 1);
|
||||
}
|
||||
if (*ptr == 0) ptr++;
|
||||
ptr += 4; // Skip QTYPE (2) + QCLASS (2)
|
||||
|
||||
// Parse Answers
|
||||
int answers = ntohs(rx_dns_hdr->ancount);
|
||||
for (int a = 0; a < answers && ptr < rx_buf + rx_len - 10; a++) {
|
||||
// Name: either pointer (0xC0XX) or label
|
||||
if ((*ptr & 0xC0) == 0xC0) {
|
||||
ptr += 2;
|
||||
} else {
|
||||
while (*ptr && ptr < rx_buf + rx_len) ptr += (*ptr + 1);
|
||||
if (*ptr == 0) ptr++;
|
||||
}
|
||||
uint16_t a_type = (uint16_t)((ptr[0] << 8) | ptr[1]);
|
||||
uint16_t a_len = (uint16_t)((ptr[8] << 8) | ptr[9]);
|
||||
ptr += 10; // Type(2), Class(2), TTL(4), DataLen(2)
|
||||
|
||||
if (a_type == 1 && a_len == 4) { // IPv4 Address (Type A)
|
||||
uint32_t resolved = 0;
|
||||
memcpy(&resolved, ptr, 4);
|
||||
*out_ip = resolved;
|
||||
return 0; // Success!
|
||||
}
|
||||
ptr += a_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (volatile int d = 0; d < 20000; d++);
|
||||
}
|
||||
|
||||
return -1; // Timeout
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// DHCP AUTO-CONFIGURATION (UDP Port 67/68)
|
||||
// =========================================================================
|
||||
int net_dhcp_discover(void) {
|
||||
// Send DHCP Discover packet broadcast
|
||||
uint8_t packet[350] = {0};
|
||||
eth_hdr_t *eth = (eth_hdr_t *)packet;
|
||||
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
|
||||
udp_hdr_t *udp = (udp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
|
||||
uint8_t *dhcp = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
|
||||
|
||||
memset(eth->dest_mac, 0xFF, 6);
|
||||
memcpy(eth->src_mac, g_net_cfg.mac, 6);
|
||||
eth->ethertype = htons(ETHERTYPE_IPv4);
|
||||
|
||||
ip->version_ihl = 0x45;
|
||||
ip->tos = 0;
|
||||
ip->total_length = htons(sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + 300);
|
||||
ip->id = htons(0x1010);
|
||||
ip->flags_fragment = 0;
|
||||
ip->ttl = 64;
|
||||
ip->protocol = IP_PROTO_UDP;
|
||||
ip->src_ip = 0x00000000;
|
||||
ip->dst_ip = 0xFFFFFFFF; // 255.255.255.255
|
||||
ip->checksum = 0;
|
||||
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
|
||||
|
||||
udp->src_port = htons(68); // DHCP Client
|
||||
udp->dst_port = htons(67); // DHCP Server
|
||||
udp->length = htons(sizeof(udp_hdr_t) + 300);
|
||||
udp->checksum = 0;
|
||||
|
||||
// BOOTP / DHCP Request fields
|
||||
dhcp[0] = 1; // Boot Request
|
||||
dhcp[1] = 1; // 10Mb Ethernet
|
||||
dhcp[2] = 6; // HW Address length
|
||||
dhcp[3] = 0; // Hops
|
||||
dhcp[4] = 0x39; dhcp[5] = 0x03; dhcp[6] = 0xF3; dhcp[7] = 0x26; // Transaction ID
|
||||
memcpy(dhcp + 28, g_net_cfg.mac, 6); // Client MAC
|
||||
// Magic Cookie: 99, 130, 83, 99
|
||||
dhcp[236] = 99; dhcp[237] = 130; dhcp[238] = 83; dhcp[239] = 99;
|
||||
// Option 53: DHCP Discover
|
||||
dhcp[240] = 53; dhcp[241] = 1; dhcp[242] = 1;
|
||||
// Option 55: Parameter Request List (Subnet Mask, Router, DNS)
|
||||
dhcp[243] = 55; dhcp[244] = 3; dhcp[245] = 1; dhcp[246] = 3; dhcp[247] = 6;
|
||||
dhcp[248] = 255; // End
|
||||
|
||||
rtl8139_send_packet(packet, sizeof(packet));
|
||||
|
||||
// Listen for DHCP Offer
|
||||
uint8_t rx[1600];
|
||||
for (int retry = 0; retry < 40; retry++) {
|
||||
int rx_len = rtl8139_poll_packet(rx, sizeof(rx));
|
||||
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + 240)) {
|
||||
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx + sizeof(eth_hdr_t));
|
||||
if (rx_ip->protocol == IP_PROTO_UDP) {
|
||||
udp_hdr_t *rx_udp = (udp_hdr_t *)(rx + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
|
||||
if (htons(rx_udp->dst_port) == 68) {
|
||||
uint8_t *rx_dhcp = rx + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t);
|
||||
uint32_t offered_ip = 0;
|
||||
memcpy(&offered_ip, rx_dhcp + 16, 4); // "Your (client) IP address" (yiaddr)
|
||||
if (offered_ip != 0) {
|
||||
g_net_cfg.ip = offered_ip;
|
||||
// Parse options
|
||||
uint8_t *opt = rx_dhcp + 240;
|
||||
while (*opt != 255 && opt < rx + rx_len) {
|
||||
uint8_t code = *opt++;
|
||||
uint8_t len = *opt++;
|
||||
if (code == 1 && len == 4) memcpy(&g_net_cfg.netmask, opt, 4);
|
||||
if (code == 3 && len == 4) memcpy(&g_net_cfg.gateway, opt, 4);
|
||||
if (code == 6 && len >= 4) memcpy(&g_net_cfg.dns_server, opt, 4);
|
||||
opt += len;
|
||||
}
|
||||
return 0; // Success!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (volatile int d = 0; d < 20000; d++);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// FULL TCP 3-WAY HANDSHAKE & HTTP CLIENT (Live Internet Access)
|
||||
// =========================================================================
|
||||
int net_http_get(uint32_t target_ip, uint16_t port, const char *path, const char *host_header, char *out_body, size_t max_body_len) {
|
||||
if (!out_body || max_body_len == 0) return -1;
|
||||
if (!path || !*path) path = "/";
|
||||
|
||||
uint16_t local_port = 49152 + (uint16_t)(target_ip & 0x1FF) + (uint16_t)(port & 0x1F);
|
||||
uint32_t my_seq = 0x20001000;
|
||||
uint32_t srv_seq = 0;
|
||||
|
||||
uint8_t packet[1500] = {0};
|
||||
eth_hdr_t *eth = (eth_hdr_t *)packet;
|
||||
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t));
|
||||
tcp_hdr_t *tcp = (tcp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t));
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// STEP 1: SEND TCP SYN (with RFC 793 TCP Checksum)
|
||||
// -------------------------------------------------------------
|
||||
memcpy(eth->dest_mac, g_gateway_mac, 6);
|
||||
memcpy(eth->src_mac, g_net_cfg.mac, 6);
|
||||
eth->ethertype = htons(ETHERTYPE_IPv4);
|
||||
|
||||
ip->version_ihl = 0x45;
|
||||
ip->tos = 0;
|
||||
ip->total_length = htons(sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
|
||||
ip->id = htons(0x4321);
|
||||
ip->id = htons(0x1122);
|
||||
ip->flags_fragment = htons(0x4000);
|
||||
ip->ttl = 64;
|
||||
ip->protocol = IP_PROTO_TCP;
|
||||
@@ -216,73 +499,197 @@ int net_http_get(uint32_t target_ip, uint16_t port, const char *path, char *out_
|
||||
ip->checksum = 0;
|
||||
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
|
||||
|
||||
// TCP SYN Header
|
||||
tcp->src_port = htons(local_port);
|
||||
tcp->dst_port = htons(port);
|
||||
tcp->seq_num = (uint32_t)(((my_seq & 0xFF) << 24) | ((my_seq & 0xFF00) << 8) | ((my_seq >> 8) & 0xFF00) | ((my_seq >> 24) & 0xFF));
|
||||
tcp->seq_num = htonl(my_seq);
|
||||
tcp->ack_num = 0;
|
||||
tcp->data_offset_reserved = (5 << 4); // 20 bytes header
|
||||
tcp->data_offset_reserved = (5 << 4);
|
||||
tcp->flags = TCP_FLAG_SYN;
|
||||
tcp->window_size = htons(65535);
|
||||
tcp->checksum = 0;
|
||||
tcp->urgent_ptr = 0;
|
||||
tcp->checksum = net_tcp_checksum(ip->src_ip, ip->dst_ip, tcp, sizeof(tcp_hdr_t));
|
||||
|
||||
// Send SYN
|
||||
rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
|
||||
|
||||
// Poll for packet
|
||||
uint8_t rx_buf[1600];
|
||||
for (int retry = 0; retry < 30; retry++) {
|
||||
int rx_len = rtl8139_poll_packet(rx_buf, sizeof(rx_buf));
|
||||
// -------------------------------------------------------------
|
||||
// STEP 2: WAIT FOR TCP SYN-ACK
|
||||
// -------------------------------------------------------------
|
||||
uint8_t rx[1600];
|
||||
bool got_synack = false;
|
||||
|
||||
for (int retry = 0; retry < 300; retry++) {
|
||||
int rx_len = rtl8139_poll_packet(rx, sizeof(rx));
|
||||
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t))) {
|
||||
eth_hdr_t *rx_eth = (eth_hdr_t *)rx_buf;
|
||||
eth_hdr_t *rx_eth = (eth_hdr_t *)rx;
|
||||
if (htons(rx_eth->ethertype) == ETHERTYPE_IPv4) {
|
||||
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx_buf + sizeof(eth_hdr_t));
|
||||
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx + sizeof(eth_hdr_t));
|
||||
if (rx_ip->protocol == IP_PROTO_TCP) {
|
||||
int ip_hl = (rx_ip->version_ihl & 0x0F) * 4;
|
||||
tcp_hdr_t *rx_tcp = (tcp_hdr_t *)(rx_buf + sizeof(eth_hdr_t) + ip_hl);
|
||||
tcp_hdr_t *rx_tcp = (tcp_hdr_t *)(rx + sizeof(eth_hdr_t) + ip_hl);
|
||||
if (htons(rx_tcp->dst_port) == local_port) {
|
||||
int tcp_hl = (rx_tcp->data_offset_reserved >> 4) * 4;
|
||||
int data_offset = sizeof(eth_hdr_t) + ip_hl + tcp_hl;
|
||||
int payload_len = rx_len - data_offset;
|
||||
if (payload_len > 0) {
|
||||
int copy_bytes = (payload_len < (int)max_body_len - 1) ? payload_len : ((int)max_body_len - 1);
|
||||
memcpy(out_body, rx_buf + data_offset, copy_bytes);
|
||||
out_body[copy_bytes] = '\0';
|
||||
return 200;
|
||||
if ((rx_tcp->flags & (TCP_FLAG_SYN | TCP_FLAG_ACK)) == (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
|
||||
srv_seq = ntohl(rx_tcp->seq_num) + 1;
|
||||
my_seq++;
|
||||
got_synack = true;
|
||||
break;
|
||||
} else if (rx_tcp->flags & TCP_FLAG_RST) {
|
||||
printf("[TCP] Connection refused by remote host (RST received)\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (volatile int d = 0; d < 30000; d++) {}
|
||||
for (volatile int d = 0; d < 60000; d++);
|
||||
}
|
||||
|
||||
// Default Fallback Demo Page
|
||||
const char *demo_html =
|
||||
"<!DOCTYPE html>\n"
|
||||
"<html>\n"
|
||||
"<head>\n"
|
||||
" <title>opencoreC Web Browser</title>\n"
|
||||
"</head>\n"
|
||||
"<body>\n"
|
||||
" <h1>Welcome to opencoreC Web!</h1>\n"
|
||||
" <p>Status: <b>200 OK</b> (Connected via TCP/IPv4)</p>\n"
|
||||
" <p>Local IP: <b>10.0.2.15</b> | Gateway: <b>10.0.2.2</b></p>\n"
|
||||
" <p>Driver: Realtek RTL8139 Fast Ethernet PCI Bus Master</p>\n"
|
||||
" <hr/>\n"
|
||||
" <h3>Available Links & Subsystems:</h3>\n"
|
||||
" <ul>\n"
|
||||
" <li><b>Architecture:</b> 4-Core SMP x86_64 Microkernel</li>\n"
|
||||
" <li><b>IPC:</b> Fast-Path Capability & Synchronous Rendezvous</li>\n"
|
||||
" <li><b>Compositor:</b> LVGL v8.3 with SSE2 SIMD Acceleration</li>\n"
|
||||
" <li><b>Binaries:</b> Native .OPC Binary Format with Sandboxing</li>\n"
|
||||
" <li><b>Hardware:</b> PCI GPU Detection & VRAM Management</li>\n"
|
||||
" </ul>\n"
|
||||
"</body>\n"
|
||||
"</html>\n";
|
||||
if (!got_synack) {
|
||||
// Fallback response for offline environments
|
||||
snprintf(out_body, max_body_len,
|
||||
"<!DOCTYPE html>\n<html>\n<head><title>opencoreC Web</title></head>\n"
|
||||
"<body>\n<h1>opencoreC Web Browser</h1>\n"
|
||||
"<p>Host unreachable via TCP port %u (SYN-ACK timeout).</p>\n"
|
||||
"<p>Target IP: 0x%08x</p>\n</body>\n</html>\n",
|
||||
(unsigned int)port, (unsigned int)target_ip);
|
||||
return 504; // Gateway Timeout
|
||||
}
|
||||
|
||||
strncpy(out_body, demo_html, max_body_len - 1);
|
||||
out_body[max_body_len - 1] = '\0';
|
||||
return 200;
|
||||
// -------------------------------------------------------------
|
||||
// STEP 3: SEND ACK + HTTP GET REQUEST
|
||||
// -------------------------------------------------------------
|
||||
char http_req[512];
|
||||
snprintf(http_req, sizeof(http_req),
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"User-Agent: opencoreC/1.0 (x86_64 SMP)\r\n"
|
||||
"Accept: */*\r\n"
|
||||
"Connection: close\r\n\r\n",
|
||||
path, host_header ? host_header : "10.0.2.2");
|
||||
|
||||
size_t req_len = strlen(http_req);
|
||||
size_t tcp_payload_len = sizeof(tcp_hdr_t) + req_len;
|
||||
|
||||
ip->total_length = htons((uint16_t)(sizeof(ipv4_hdr_t) + tcp_payload_len));
|
||||
ip->id = htons(0x1123);
|
||||
ip->checksum = 0;
|
||||
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
|
||||
|
||||
tcp->seq_num = htonl(my_seq);
|
||||
tcp->ack_num = htonl(srv_seq);
|
||||
tcp->data_offset_reserved = (5 << 4);
|
||||
tcp->flags = TCP_FLAG_ACK | TCP_FLAG_PSH;
|
||||
tcp->checksum = 0;
|
||||
|
||||
uint8_t *payload_ptr = packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t);
|
||||
memcpy(payload_ptr, http_req, req_len);
|
||||
tcp->checksum = net_tcp_checksum(ip->src_ip, ip->dst_ip, tcp, tcp_payload_len);
|
||||
|
||||
rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + tcp_payload_len);
|
||||
my_seq += (uint32_t)req_len;
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// STEP 4: RECEIVE HTTP DATA STREAM
|
||||
// -------------------------------------------------------------
|
||||
size_t total_body_read = 0;
|
||||
out_body[0] = '\0';
|
||||
|
||||
int empty_polls = 0;
|
||||
for (int retry = 0; retry < 400; retry++) {
|
||||
int rx_len = rtl8139_poll_packet(rx, sizeof(rx));
|
||||
if (rx_len > (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t))) {
|
||||
eth_hdr_t *rx_eth = (eth_hdr_t *)rx;
|
||||
if (htons(rx_eth->ethertype) == ETHERTYPE_IPv4) {
|
||||
ipv4_hdr_t *rx_ip = (ipv4_hdr_t *)(rx + sizeof(eth_hdr_t));
|
||||
if (rx_ip->protocol == IP_PROTO_TCP && rx_ip->src_ip == target_ip) {
|
||||
int ip_hl = (rx_ip->version_ihl & 0x0F) * 4;
|
||||
tcp_hdr_t *rx_tcp = (tcp_hdr_t *)(rx + sizeof(eth_hdr_t) + ip_hl);
|
||||
if (htons(rx_tcp->dst_port) == local_port) {
|
||||
int tcp_hl = (rx_tcp->data_offset_reserved >> 4) * 4;
|
||||
int data_offset = sizeof(eth_hdr_t) + ip_hl + tcp_hl;
|
||||
uint16_t ip_total_len = ntohs(rx_ip->total_length);
|
||||
int data_bytes = (int)ip_total_len - (ip_hl + tcp_hl);
|
||||
|
||||
if (data_bytes > 0) {
|
||||
empty_polls = 0;
|
||||
size_t space = max_body_len - 1 - total_body_read;
|
||||
size_t to_copy = (size_t)data_bytes < space ? (size_t)data_bytes : space;
|
||||
memcpy(out_body + total_body_read, rx + data_offset, to_copy);
|
||||
total_body_read += to_copy;
|
||||
out_body[total_body_read] = '\0';
|
||||
|
||||
// Acknowledge received data
|
||||
srv_seq = ntohl(rx_tcp->seq_num) + (uint32_t)data_bytes;
|
||||
tcp->seq_num = htonl(my_seq);
|
||||
tcp->ack_num = htonl(srv_seq);
|
||||
tcp->flags = TCP_FLAG_ACK;
|
||||
tcp->checksum = 0;
|
||||
tcp->checksum = net_tcp_checksum(ip->src_ip, ip->dst_ip, tcp, sizeof(tcp_hdr_t));
|
||||
ip->total_length = htons(sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
|
||||
ip->checksum = 0;
|
||||
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
|
||||
rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
|
||||
}
|
||||
|
||||
if (rx_tcp->flags & TCP_FLAG_FIN) {
|
||||
// Server closed connection cleanly
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (total_body_read > 0) {
|
||||
empty_polls++;
|
||||
if (empty_polls > 25) {
|
||||
break; // Finished receiving body stream
|
||||
}
|
||||
}
|
||||
}
|
||||
for (volatile int d = 0; d < 60000; d++);
|
||||
}
|
||||
|
||||
if (total_body_read > 0) {
|
||||
return 200; // Success HTTP 200 OK
|
||||
}
|
||||
|
||||
// Default response if connected but empty
|
||||
snprintf(out_body, max_body_len,
|
||||
"<!DOCTYPE html>\n<html>\n<head><title>opencoreC Web</title></head>\n"
|
||||
"<body>\n<h1>opencoreC Web Browser</h1>\n"
|
||||
"<p>Connected to %s via TCP/IPv4, but server returned 0 bytes.</p>\n</body>\n</html>\n",
|
||||
host_header ? host_header : "remote host");
|
||||
return 204;
|
||||
}
|
||||
|
||||
int net_http_get_url(const char *url, char *out_body, size_t max_body_len) {
|
||||
if (!url || !*url) return -1;
|
||||
if (strncmp(url, "http://", 7) == 0) url += 7;
|
||||
|
||||
char host[128] = {0};
|
||||
uint16_t port = 80;
|
||||
const char *path = "/";
|
||||
|
||||
int hi = 0;
|
||||
while (*url && *url != '/' && *url != ':' && hi < 127) {
|
||||
host[hi++] = *url++;
|
||||
}
|
||||
if (*url == ':') {
|
||||
url++;
|
||||
port = 0;
|
||||
while (*url >= '0' && *url <= '9') {
|
||||
port = port * 10 + (*url - '0');
|
||||
url++;
|
||||
}
|
||||
}
|
||||
if (*url == '/') {
|
||||
path = url;
|
||||
}
|
||||
|
||||
uint32_t target_ip = 0;
|
||||
if (net_dns_resolve(host, &target_ip) != 0) {
|
||||
target_ip = g_net_cfg.gateway; // Fallback to gateway
|
||||
}
|
||||
|
||||
return net_http_get(target_ip, port, path, host, out_body, max_body_len);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# Limine Bootloader Configuration for opencoreC Microkernel
|
||||
timeout: 0
|
||||
default_entry: 1
|
||||
interface_resolution: 1280x800
|
||||
|
||||
/opencoreC Microkernel (x86_64)
|
||||
protocol: limine
|
||||
resolution: 1280x800x32
|
||||
kernel_path: boot():/boot/opencore_kernel.elf
|
||||
module_path: boot():/boot/init_server.elf
|
||||
module_path: boot():/boot/uart_driver.elf
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# Limine Bootloader Configuration for opencoreC Microkernel
|
||||
timeout: 0
|
||||
default_entry: 1
|
||||
interface_resolution: 1280x800
|
||||
|
||||
/opencoreC Microkernel (x86_64)
|
||||
protocol: limine
|
||||
resolution: 1280x800x32
|
||||
kernel_path: boot():/boot/opencore_kernel.elf
|
||||
module_path: boot():/boot/init_server.elf
|
||||
module_path: boot():/boot/uart_driver.elf
|
||||
|
||||
+23
-32
@@ -46,10 +46,11 @@ static lv_indev_t *g_mouse_indev = NULL;
|
||||
static lv_indev_t *g_kbd_indev = NULL;
|
||||
static lv_group_t *g_input_group = NULL;
|
||||
|
||||
// Double-buffering: 200-row raster bands for high-speed full-band flush (4 sweeps for 1280x800)
|
||||
#define BUF_HEIGHT 200
|
||||
static lv_color_t g_buf1[1280 * BUF_HEIGHT];
|
||||
static lv_color_t g_buf2[1280 * BUF_HEIGHT];
|
||||
// Double-buffering: dynamically scaled raster bands up to 4K (3840x2160)
|
||||
#define MAX_HOR_RES 3840
|
||||
#define BUF_HEIGHT 100
|
||||
static lv_color_t g_buf1[MAX_HOR_RES * BUF_HEIGHT];
|
||||
static lv_color_t g_buf2[MAX_HOR_RES * BUF_HEIGHT];
|
||||
static lv_disp_draw_buf_t g_draw_buf;
|
||||
|
||||
// 16x24 High-Contrast Arrow Cursor Bitmap
|
||||
@@ -275,9 +276,9 @@ static void win_drag_event_cb(lv_event_t *e) {
|
||||
|
||||
// Keep window inside screen bounds
|
||||
if (x < 0) x = 0;
|
||||
if (x > 1280 - 100) x = 1280 - 100;
|
||||
if (x > (lv_coord_t)g_fb.width - 100) x = (lv_coord_t)g_fb.width - 100;
|
||||
if (y < 0) y = 0;
|
||||
if (y > 800 - 80) y = 800 - 80;
|
||||
if (y > (lv_coord_t)g_fb.height - 80) y = (lv_coord_t)g_fb.height - 80;
|
||||
|
||||
lv_obj_set_pos(win, x, y);
|
||||
}
|
||||
@@ -623,37 +624,25 @@ static void ping_btn_event_cb(lv_event_t *e) {
|
||||
static void browser_go_event_cb(lv_event_t *e) {
|
||||
(void)e;
|
||||
const char *url = lv_textarea_get_text(g_ta_browser_url);
|
||||
if (!url || !*url) url = "http://10.0.2.2/index.html";
|
||||
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "Connecting to %s...", url ? url : "10.0.2.2");
|
||||
snprintf(buf, sizeof(buf), "Connecting to %s...", url);
|
||||
lv_label_set_text(g_lbl_browser_status, buf);
|
||||
|
||||
char body[1500];
|
||||
char body[2048];
|
||||
memset(body, 0, sizeof(body));
|
||||
|
||||
uint32_t target_ip = g_net_cfg.gateway;
|
||||
uint16_t port = 80;
|
||||
const char *path = "/";
|
||||
|
||||
if (url && *url) {
|
||||
const char *p = url;
|
||||
if (strncmp(p, "http://", 7) == 0) p += 7;
|
||||
char host[64] = {0};
|
||||
int hi = 0;
|
||||
while (*p && *p != '/' && *p != ':' && hi < 63) {
|
||||
host[hi++] = *p++;
|
||||
}
|
||||
if (*host) target_ip = parse_ip(host);
|
||||
if (*p == '/') path = p;
|
||||
}
|
||||
|
||||
int res = net_http_get(target_ip, port, path, body, sizeof(body));
|
||||
int res = net_http_get_url(url, body, sizeof(body));
|
||||
if (res == 200) {
|
||||
lv_label_set_text(g_lbl_browser_status, "HTTP/1.1 200 OK | TCP Connected (10.0.2.15 -> Gateway:80)");
|
||||
char st[128];
|
||||
snprintf(st, sizeof(st), "HTTP/1.1 200 OK | TCP Connected (%s)", url);
|
||||
lv_label_set_text(g_lbl_browser_status, st);
|
||||
lv_textarea_set_text(g_txt_browser_content, body);
|
||||
show_desktop_toast("Web Browser", "Webpage loaded successfully over TCP/IPv4!");
|
||||
show_desktop_toast("Web Browser", "Live webpage loaded successfully!");
|
||||
} else {
|
||||
lv_label_set_text(g_lbl_browser_status, "Connection Failed");
|
||||
lv_textarea_set_text(g_txt_browser_content, "Error: Could not connect to remote host via TCP.\nCheck network status in Network Center.");
|
||||
lv_label_set_text(g_lbl_browser_status, "Connection Failed / Timeout");
|
||||
lv_textarea_set_text(g_txt_browser_content, body[0] ? body : "Error: Could not connect to remote host via TCP.\nCheck DNS/DHCP network status.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,7 +961,7 @@ static void create_desktop_environment() {
|
||||
// 6. BOTTOM TASKBAR (Windows / KDE Plasma Style)
|
||||
// =========================================================================
|
||||
lv_obj_t *taskbar = lv_obj_create(scr);
|
||||
lv_obj_set_size(taskbar, 1280, 48);
|
||||
lv_obj_set_size(taskbar, g_fb.width, 48);
|
||||
lv_obj_align(taskbar, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_style_bg_color(taskbar, lv_color_hex(0x141824), 0);
|
||||
lv_obj_set_style_border_color(taskbar, lv_color_hex(0x2a3447), 0);
|
||||
@@ -1273,8 +1262,10 @@ int main() {
|
||||
net_init();
|
||||
printf("[GUI-SERVER] net_init() OK.\n");
|
||||
|
||||
// 3. Register Framebuffer Display Driver (Double-buffered with 200 rows)
|
||||
lv_disp_draw_buf_init(&g_draw_buf, g_buf1, g_buf2, 1280 * BUF_HEIGHT);
|
||||
// 3. Register Framebuffer Display Driver (Double-buffered with dynamically scaled rows)
|
||||
uint32_t buf_pixels = (uint32_t)g_fb.width * BUF_HEIGHT;
|
||||
if (buf_pixels > MAX_HOR_RES * BUF_HEIGHT) buf_pixels = MAX_HOR_RES * BUF_HEIGHT;
|
||||
lv_disp_draw_buf_init(&g_draw_buf, g_buf1, g_buf2, buf_pixels);
|
||||
lv_disp_drv_init(&g_disp_drv);
|
||||
g_disp_drv.hor_res = (lv_coord_t)g_fb.width;
|
||||
g_disp_drv.ver_res = (lv_coord_t)g_fb.height;
|
||||
|
||||
+44
-21
@@ -317,32 +317,51 @@ static void cmd_modules() {
|
||||
}
|
||||
|
||||
static void cmd_curl(const char *target) {
|
||||
char body[1024];
|
||||
memset(body, 0, sizeof(body));
|
||||
uint32_t ip = g_net_cfg.gateway;
|
||||
uint16_t port = 80;
|
||||
const char *path = "/";
|
||||
|
||||
if (target && *target) {
|
||||
if (strncmp(target, "http://", 7) == 0) target += 7;
|
||||
char host[64] = {0};
|
||||
int hi = 0;
|
||||
while (*target && *target != '/' && *target != ':' && hi < 63) {
|
||||
host[hi++] = *target++;
|
||||
}
|
||||
if (*host) ip = parse_ip(host);
|
||||
if (*target == '/') path = target;
|
||||
if (!target || !*target) {
|
||||
puts("Usage: curl <http://domain-or-ip/path>");
|
||||
return;
|
||||
}
|
||||
char body[2048];
|
||||
memset(body, 0, sizeof(body));
|
||||
|
||||
char ip_str[32];
|
||||
format_ip(ip, ip_str);
|
||||
printf("[curl] Connecting to %s:%u (Path: %s) via TCP/IPv4...\n", ip_str, port, path);
|
||||
int status = net_http_get(ip, port, path, body, sizeof(body));
|
||||
printf("[curl] Fetching '%s' over TCP/IPv4...\n", target);
|
||||
int status = net_http_get_url(target, body, sizeof(body));
|
||||
if (status == 200) {
|
||||
printf("\033[1;32mHTTP/1.1 200 OK\033[0m (TCP Connected)\n\n");
|
||||
printf("\033[1;32mHTTP/1.1 200 OK\033[0m (Bytes read: %d)\n\n", (int)strlen(body));
|
||||
puts(body);
|
||||
} else {
|
||||
printf("[curl] Connection to %s:%u failed.\n", ip_str, port);
|
||||
printf("[curl] HTTP request returned status %d\n", status);
|
||||
if (*body) puts(body);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_dns(const char *domain) {
|
||||
if (!domain || !*domain) {
|
||||
puts("Usage: dns <hostname> (e.g. dns httpbin.org)");
|
||||
return;
|
||||
}
|
||||
printf("[dns] Querying DNS nameserver for '%s' (UDP port 53)...\n", domain);
|
||||
uint32_t ip = 0;
|
||||
if (net_dns_resolve(domain, &ip) == 0) {
|
||||
char ip_str[32];
|
||||
format_ip(ip, ip_str);
|
||||
printf(" \033[1;32m%s\033[0m has address \033[1;36m%s\033[0m\n", domain, ip_str);
|
||||
} else {
|
||||
printf("[dns] Host '%s' not found (NXDOMAIN / timeout)\n", domain);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_dhcp() {
|
||||
puts("[dhcp] Broadcasting DHCPDISCOVER (UDP 68 -> 67)...");
|
||||
if (net_dhcp_discover() == 0) {
|
||||
char ip[32], gw[32], dns[32];
|
||||
format_ip(g_net_cfg.ip, ip);
|
||||
format_ip(g_net_cfg.gateway, gw);
|
||||
format_ip(g_net_cfg.dns_server, dns);
|
||||
printf("\033[1;32m[dhcp] Lease acquired successfully!\033[0m\n");
|
||||
printf(" IP Address: %s\n Gateway: %s\n DNS Server: %s\n", ip, gw, dns);
|
||||
} else {
|
||||
puts("[dhcp] DHCP request timed out (using static configuration).");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -839,6 +858,10 @@ static void handle_command(char *cmd) {
|
||||
cmd_curl(cmd + 5);
|
||||
} else if (strncmp(cmd, "fetch ", 6) == 0) {
|
||||
cmd_curl(cmd + 6);
|
||||
} else if (strncmp(cmd, "dns ", 4) == 0) {
|
||||
cmd_dns(cmd + 4);
|
||||
} else if (strcmp(cmd, "dhcp") == 0) {
|
||||
cmd_dhcp();
|
||||
} else if (strcmp(cmd, "fastfetch") == 0 || strcmp(cmd, "neofetch") == 0) {
|
||||
print_fastfetch();
|
||||
} else if (strcmp(cmd, "clear") == 0) {
|
||||
|
||||
Reference in New Issue
Block a user