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:
RarDog
2026-09-03 10:40:23 +03:00
parent ca75e961f9
commit de772a2de0
12 changed files with 863 additions and 174 deletions
+22 -1
View File
@@ -69,6 +69,22 @@ typedef struct {
uint16_t urgent_ptr; uint16_t urgent_ptr;
} tcp_hdr_t; } 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_FIN 0x01
#define TCP_FLAG_SYN 0x02 #define TCP_FLAG_SYN 0x02
#define TCP_FLAG_RST 0x04 #define TCP_FLAG_RST 0x04
@@ -82,6 +98,7 @@ typedef struct {
uint32_t ip; uint32_t ip;
uint32_t netmask; uint32_t netmask;
uint32_t gateway; uint32_t gateway;
uint32_t dns_server;
uint8_t mac[6]; uint8_t mac[6];
} net_config_t; } net_config_t;
@@ -90,10 +107,14 @@ extern net_config_t g_net_cfg;
// Net API // Net API
void net_init(void); void net_init(void);
uint16_t net_checksum(const void *buf, size_t len); 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_arp_request(uint32_t target_ip);
int net_send_icmp_ping(uint32_t target_ip, uint16_t seq); 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_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); uint32_t parse_ip(const char *str);
void format_ip(uint32_t ip, char *buf); void format_ip(uint32_t ip, char *buf);
+2 -1
View File
@@ -70,8 +70,9 @@ pub unsafe fn boot_aps() {
let cpu_count = (*smp_resp).cpu_count; let cpu_count = (*smp_resp).cpu_count;
let bsp_lapic_id = (*smp_resp).bsp_lapic_id; 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); let cpu_info = *(*smp_resp).cpus.add(i as usize);
if (*cpu_info).lapic_id != bsp_lapic_id { if (*cpu_info).lapic_id != bsp_lapic_id {
let info_mut = cpu_info as *mut LimineSmpInfo; let info_mut = cpu_info as *mut LimineSmpInfo;
+1
View File
@@ -388,6 +388,7 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
(*out_ptr).pitch = pitch; (*out_ptr).pitch = pitch;
(*out_ptr).bpp = bpp as u32; (*out_ptr).bpp = bpp as u32;
} }
crate::drivers::fb_console::FbConsole::disable();
regs.rax = 0; regs.rax = 0;
return; return;
} }
+198
View File
@@ -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(())
}
}
+1
View File
@@ -5,3 +5,4 @@ pub mod rtc;
pub mod dmesg; pub mod dmesg;
pub mod mouse; pub mod mouse;
pub mod rng; pub mod rng;
pub mod fb_console;
+37 -4
View File
@@ -6,6 +6,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
const COM1: u16 = 0x3F8; const COM1: u16 = 0x3F8;
static SERIAL_INITIALIZED: AtomicBool = AtomicBool::new(false); static SERIAL_INITIALIZED: AtomicBool = AtomicBool::new(false);
static SERIAL_PRESENT: AtomicBool = AtomicBool::new(false);
#[inline] #[inline]
unsafe fn outb(port: u16, val: u8) { unsafe fn outb(port: u16, val: u8) {
@@ -24,6 +25,20 @@ pub struct SerialPort;
impl SerialPort { impl SerialPort {
pub fn init() { pub fn init() {
unsafe { 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 + 1, 0x00); // Disable all interrupts
outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor) outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(COM1 + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud 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 + 3, 0x03); // 8 bits, no parity, one stop bit
outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set 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) { pub fn write_byte(&self, byte: u8) {
if !SERIAL_PRESENT.load(Ordering::Relaxed) {
return;
}
unsafe { unsafe {
// Wait for transmit buffer empty // Bounded timeout: prevent deadlocks on bare-metal PCs without physical COM1 port
while (inb(COM1 + 5) & 0x20) == 0 { let mut timeout = 25000usize;
while (inb(COM1 + 5) & 0x20) == 0 && timeout > 0 {
timeout -= 1;
core::hint::spin_loop(); core::hint::spin_loop();
} }
outb(COM1, byte); if timeout > 0 {
outb(COM1, byte);
}
} }
} }
pub fn has_data(&self) -> bool { pub fn has_data(&self) -> bool {
if !SERIAL_PRESENT.load(Ordering::Relaxed) {
return false;
}
unsafe { unsafe {
(inb(COM1 + 5) & 0x01) != 0 (inb(COM1 + 5) & 0x01) != 0
} }
@@ -82,6 +113,8 @@ impl Write for SerialPort {
pub fn _kprint(args: fmt::Arguments) { pub fn _kprint(args: fmt::Arguments) {
let mut port = SerialPort; let mut port = SerialPort;
let _ = port.write_fmt(args); let _ = port.write_fmt(args);
let mut con = crate::drivers::fb_console::FbConsole;
let _ = con.write_fmt(args);
} }
#[macro_export] #[macro_export]
+9
View File
@@ -63,6 +63,11 @@ impl VirtualMemoryManager {
let current_cr3 = self.read_cr3() & PAGE_MASK; let current_cr3 = self.read_cr3() & PAGE_MASK;
let kernel_pml4 = self.phys_to_virt::<PageTable>(current_cr3); 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) // Copy kernel mappings (higher half: 256..512)
for i in 256..512 { for i in 256..512 {
(*user_pml4).entries[i] = (*kernel_pml4).entries[i]; (*user_pml4).entries[i] = (*kernel_pml4).entries[i];
@@ -188,6 +193,10 @@ impl VirtualMemoryManager {
} else { } else {
let pfa_ptr = core::ptr::addr_of_mut!(PFA); let pfa_ptr = core::ptr::addr_of_mut!(PFA);
let new_frame = (*pfa_ptr).alloc_frame().ok_or(())?; 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); let flags = PAGE_PRESENT | PAGE_WRITABLE | (inherit_flags & PAGE_USER);
*entry = (new_frame & PAGE_MASK) | flags; *entry = (new_frame & PAGE_MASK) | flags;
Ok(new_frame) Ok(new_frame)
+522 -115
View File
@@ -2,23 +2,41 @@
#include "rtl8139.h" #include "rtl8139.h"
#include "string.h" #include "string.h"
#include "stdio.h" #include "stdio.h"
#include <stdbool.h>
// Default QEMU User Networking (SLIRP) Configuration // Default QEMU User Networking (SLIRP) Configuration
// Guest IP: 10.0.2.15 // Guest IP: 10.0.2.15
// Gateway: 10.0.2.2 (Default QEMU MAC: 52:55:0a:00:02:02) // 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 = { net_config_t g_net_cfg = {
.ip = (10) | (0 << 8) | (2 << 16) | (15 << 24), .ip = (10) | (0 << 8) | (2 << 16) | (15 << 24),
.gateway = (10) | (0 << 8) | (2 << 16) | (2 << 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), .netmask = (255) | (255 << 8) | (255 << 16) | (0 << 24),
.mac = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56} .mac = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56}
}; };
static uint8_t g_gateway_mac[6] = {0x52, 0x55, 0x0a, 0x00, 0x02, 0x02}; 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)); 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) { uint16_t net_checksum(const void *buf, size_t len) {
const uint16_t *data = (const uint16_t *)buf; const uint16_t *data = (const uint16_t *)buf;
uint32_t sum = 0; uint32_t sum = 0;
@@ -36,6 +54,43 @@ uint16_t net_checksum(const void *buf, size_t len) {
return (uint16_t)(~sum); 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) { void net_init(void) {
rtl8139_init(); rtl8139_init();
for (int i = 0; i < 6; i++) { 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; eth_hdr_t *eth = (eth_hdr_t *)packet;
arp_hdr_t *arp = (arp_hdr_t *)(packet + sizeof(eth_hdr_t)); arp_hdr_t *arp = (arp_hdr_t *)(packet + sizeof(eth_hdr_t));
// Broadcast Ethernet Header
memset(eth->dest_mac, 0xFF, 6); memset(eth->dest_mac, 0xFF, 6);
memcpy(eth->src_mac, g_net_cfg.mac, 6); memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_ARP); eth->ethertype = htons(ETHERTYPE_ARP);
// ARP Payload (Who has target_ip? Tell sender_ip) arp->hw_type = htons(1);
arp->hw_type = htons(1); // Ethernet arp->proto_type = htons(0x0800);
arp->proto_type = htons(0x0800); // IPv4
arp->hw_len = 6; arp->hw_len = 6;
arp->proto_len = 4; arp->proto_len = 4;
arp->opcode = htons(1); // Request arp->opcode = htons(1); // ARP Request
memcpy(arp->sender_mac, g_net_cfg.mac, 6); memcpy(arp->sender_mac, g_net_cfg.mac, 6);
arp->sender_ip = g_net_cfg.ip; arp->sender_ip = g_net_cfg.ip;
memset(arp->target_mac, 0x00, 6); 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)); 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); 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->dest_mac, g_gateway_mac, 6);
memcpy(eth->src_mac, g_net_cfg.mac, 6); memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_IPv4); eth->ethertype = htons(ETHERTYPE_IPv4);
// 2. IPv4 Header ip->version_ihl = 0x45;
ip->version_ihl = 0x45; // Version 4, Header Length 5 (20 bytes)
ip->tos = 0; 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->id = htons(seq);
ip->flags_fragment = htons(0x4000); // Don't Fragment ip->flags_fragment = htons(0x4000);
ip->ttl = 64; ip->ttl = 64;
ip->protocol = IP_PROTO_ICMP; ip->protocol = IP_PROTO_ICMP;
ip->src_ip = g_net_cfg.ip; 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 = 0;
ip->checksum = net_checksum(ip, 20); ip->checksum = net_checksum(ip, 20);
// 3. ICMP Echo Request Header
icmp->type = ICMP_ECHO_REQUEST; icmp->type = ICMP_ECHO_REQUEST;
icmp->code = 0; icmp->code = 0;
icmp->id = htons(0x1234); icmp->id = htons(0x1234);
icmp->sequence = htons(seq); icmp->sequence = htons(seq);
for (int i = 0; i < 32; i++) { 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 = 0;
icmp->checksum = net_checksum(icmp, 8 + 32); icmp->checksum = net_checksum(icmp, 8 + 32);
size_t total_len = sizeof(eth_hdr_t) + 20 + 8 + 32; return rtl8139_send_packet(packet, sizeof(eth_hdr_t) + 20 + 8 + 32);
return rtl8139_send_packet(packet, (uint16_t)total_len);
} }
int net_poll_icmp_reply(uint32_t *from_ip, uint16_t *seq) { int net_poll_icmp_reply(uint32_t *from_ip, uint16_t *seq) {
uint8_t buffer[1600]; uint8_t buf[1600];
int len = rtl8139_poll_packet(buffer, sizeof(buffer)); int len = rtl8139_poll_packet(buf, sizeof(buf));
if (len < (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t))) {
if (len < (int)sizeof(eth_hdr_t)) { return -1;
return 0;
} }
eth_hdr_t *eth = (eth_hdr_t *)buffer; eth_hdr_t *eth = (eth_hdr_t *)buf;
if (htons(eth->ethertype) == ETHERTYPE_ARP) {
// Handle ARP Reply to dynamically update gateway MAC arp_hdr_t *arp = (arp_hdr_t *)(buf + sizeof(eth_hdr_t));
if (htons(eth->ethertype) == ETHERTYPE_ARP && len >= (int)(sizeof(eth_hdr_t) + sizeof(arp_hdr_t))) { if (htons(arp->opcode) == 2 && arp->sender_ip == g_net_cfg.gateway) {
arp_hdr_t *arp = (arp_hdr_t *)(buffer + sizeof(eth_hdr_t));
if (htons(arp->opcode) == 2) { // ARP Reply
memcpy(g_gateway_mac, arp->sender_mac, 6); 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))) { if (htons(eth->ethertype) != ETHERTYPE_IPv4) return -1;
return 0; ipv4_hdr_t *ip = (ipv4_hdr_t *)(buf + sizeof(eth_hdr_t));
} if (ip->protocol != IP_PROTO_ICMP) return -1;
ipv4_hdr_t *ip = (ipv4_hdr_t *)(buffer + sizeof(eth_hdr_t));
if (ip->protocol != IP_PROTO_ICMP) {
return 0;
}
int ip_hdr_len = (ip->version_ihl & 0x0F) * 4; 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 (icmp->type == ICMP_ECHO_REPLY) {
if (from_ip) *from_ip = ip->src_ip; if (from_ip) *from_ip = ip->src_ip;
if (seq) *seq = htons(icmp->sequence); 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 parse_ip(const char *str) {
uint32_t parts[4] = {0}; uint32_t ip = 0;
int idx = 0; int octet = 0;
while (*str && idx < 4) { int shift = 0;
while (*str) {
if (*str >= '0' && *str <= '9') { if (*str >= '0' && *str <= '9') {
parts[idx] = parts[idx] * 10 + (*str - '0'); octet = octet * 10 + (*str - '0');
} else if (*str == '.') { } else if (*str == '.') {
idx++; ip |= ((uint32_t)(octet & 0xFF) << shift);
shift += 8;
octet = 0;
} }
str++; 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) { void format_ip(uint32_t ip, char *buf) {
uint8_t *b = (uint8_t *)&ip;
int len = 0; int len = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
uint8_t val = b[i]; uint8_t b = (uint8_t)((ip >> (i * 8)) & 0xFF);
if (val >= 100) { if (b >= 100) {
buf[len++] = '0' + (val / 100); buf[len++] = '0' + (b / 100);
val %= 100; b %= 100;
buf[len++] = '0' + (val / 10); buf[len++] = '0' + (b / 10);
val %= 10; b %= 10;
} else if (val >= 10) { } else if (b >= 10) {
buf[len++] = '0' + (val / 10); buf[len++] = '0' + (b / 10);
val %= 10; b %= 10;
} }
buf[len++] = '0' + val; buf[len++] = '0' + b;
if (i < 3) buf[len++] = '.'; if (i < 3) buf[len++] = '.';
} }
buf[len] = '\0'; 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; // DNS CLIENT (UDP Port 53) - Resolves Hostnames to Real IPv4 Addresses
if (!path || !*path) path = "/"; // =========================================================================
int net_dns_resolve(const char *domain, uint32_t *out_ip) {
if (!domain || !*domain || !out_ip) return -1;
// 1. Craft TCP SYN packet // Check if domain is already a numerical IPv4 address
uint8_t packet[128] = {0}; bool is_numeric = true;
eth_hdr_t *eth = (eth_hdr_t *)packet; for (const char *p = domain; *p; p++) {
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_hdr_t)); if (!((*p >= '0' && *p <= '9') || *p == '.')) {
tcp_hdr_t *tcp = (tcp_hdr_t *)(packet + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t)); is_numeric = false;
break;
}
}
if (is_numeric) {
*out_ip = parse_ip(domain);
return 0;
}
uint16_t local_port = 49152 + (uint16_t)(target_ip & 0x3FF); uint8_t packet[512] = {0};
uint32_t my_seq = 0x10002000; 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 // 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); memcpy(eth->src_mac, g_net_cfg.mac, 6);
eth->ethertype = htons(ETHERTYPE_IPv4); eth->ethertype = htons(ETHERTYPE_IPv4);
// IPv4 Header // 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->version_ihl = 0x45;
ip->tos = 0; ip->tos = 0;
ip->total_length = htons(sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t)); 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->flags_fragment = htons(0x4000);
ip->ttl = 64; ip->ttl = 64;
ip->protocol = IP_PROTO_TCP; 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 = 0;
ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t)); ip->checksum = net_checksum(ip, sizeof(ipv4_hdr_t));
// TCP SYN Header
tcp->src_port = htons(local_port); tcp->src_port = htons(local_port);
tcp->dst_port = htons(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->ack_num = 0;
tcp->data_offset_reserved = (5 << 4); // 20 bytes header tcp->data_offset_reserved = (5 << 4);
tcp->flags = TCP_FLAG_SYN; tcp->flags = TCP_FLAG_SYN;
tcp->window_size = htons(65535); tcp->window_size = htons(65535);
tcp->checksum = 0; tcp->checksum = 0;
tcp->urgent_ptr = 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)); rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
// Poll for packet // -------------------------------------------------------------
uint8_t rx_buf[1600]; // STEP 2: WAIT FOR TCP SYN-ACK
for (int retry = 0; retry < 30; retry++) { // -------------------------------------------------------------
int rx_len = rtl8139_poll_packet(rx_buf, sizeof(rx_buf)); 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))) { 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) { 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) { if (rx_ip->protocol == IP_PROTO_TCP) {
int ip_hl = (rx_ip->version_ihl & 0x0F) * 4; 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) { if (htons(rx_tcp->dst_port) == local_port) {
int tcp_hl = (rx_tcp->data_offset_reserved >> 4) * 4; if ((rx_tcp->flags & (TCP_FLAG_SYN | TCP_FLAG_ACK)) == (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
int data_offset = sizeof(eth_hdr_t) + ip_hl + tcp_hl; srv_seq = ntohl(rx_tcp->seq_num) + 1;
int payload_len = rx_len - data_offset; my_seq++;
if (payload_len > 0) { got_synack = true;
int copy_bytes = (payload_len < (int)max_body_len - 1) ? payload_len : ((int)max_body_len - 1); break;
memcpy(out_body, rx_buf + data_offset, copy_bytes); } else if (rx_tcp->flags & TCP_FLAG_RST) {
out_body[copy_bytes] = '\0'; printf("[TCP] Connection refused by remote host (RST received)\n");
return 200; break;
} }
} }
} }
} }
} }
for (volatile int d = 0; d < 30000; d++) {} for (volatile int d = 0; d < 60000; d++);
} }
// Default Fallback Demo Page if (!got_synack) {
const char *demo_html = // Fallback response for offline environments
"<!DOCTYPE html>\n" snprintf(out_body, max_body_len,
"<html>\n" "<!DOCTYPE html>\n<html>\n<head><title>opencoreC Web</title></head>\n"
"<head>\n" "<body>\n<h1>opencoreC Web Browser</h1>\n"
" <title>opencoreC Web Browser</title>\n" "<p>Host unreachable via TCP port %u (SYN-ACK timeout).</p>\n"
"</head>\n" "<p>Target IP: 0x%08x</p>\n</body>\n</html>\n",
"<body>\n" (unsigned int)port, (unsigned int)target_ip);
" <h1>Welcome to opencoreC Web!</h1>\n" return 504; // Gateway Timeout
" <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";
strncpy(out_body, demo_html, max_body_len - 1); // -------------------------------------------------------------
out_body[max_body_len - 1] = '\0'; // STEP 3: SEND ACK + HTTP GET REQUEST
return 200; // -------------------------------------------------------------
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);
} }
+2
View File
@@ -1,9 +1,11 @@
# Limine Bootloader Configuration for opencoreC Microkernel # Limine Bootloader Configuration for opencoreC Microkernel
timeout: 0 timeout: 0
default_entry: 1 default_entry: 1
interface_resolution: 1280x800
/opencoreC Microkernel (x86_64) /opencoreC Microkernel (x86_64)
protocol: limine protocol: limine
resolution: 1280x800x32
kernel_path: boot():/boot/opencore_kernel.elf kernel_path: boot():/boot/opencore_kernel.elf
module_path: boot():/boot/init_server.elf module_path: boot():/boot/init_server.elf
module_path: boot():/boot/uart_driver.elf module_path: boot():/boot/uart_driver.elf
+2
View File
@@ -1,9 +1,11 @@
# Limine Bootloader Configuration for opencoreC Microkernel # Limine Bootloader Configuration for opencoreC Microkernel
timeout: 0 timeout: 0
default_entry: 1 default_entry: 1
interface_resolution: 1280x800
/opencoreC Microkernel (x86_64) /opencoreC Microkernel (x86_64)
protocol: limine protocol: limine
resolution: 1280x800x32
kernel_path: boot():/boot/opencore_kernel.elf kernel_path: boot():/boot/opencore_kernel.elf
module_path: boot():/boot/init_server.elf module_path: boot():/boot/init_server.elf
module_path: boot():/boot/uart_driver.elf module_path: boot():/boot/uart_driver.elf
+23 -32
View File
@@ -46,10 +46,11 @@ static lv_indev_t *g_mouse_indev = NULL;
static lv_indev_t *g_kbd_indev = NULL; static lv_indev_t *g_kbd_indev = NULL;
static lv_group_t *g_input_group = 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) // Double-buffering: dynamically scaled raster bands up to 4K (3840x2160)
#define BUF_HEIGHT 200 #define MAX_HOR_RES 3840
static lv_color_t g_buf1[1280 * BUF_HEIGHT]; #define BUF_HEIGHT 100
static lv_color_t g_buf2[1280 * BUF_HEIGHT]; 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; static lv_disp_draw_buf_t g_draw_buf;
// 16x24 High-Contrast Arrow Cursor Bitmap // 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 // Keep window inside screen bounds
if (x < 0) x = 0; 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 < 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); 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) { static void browser_go_event_cb(lv_event_t *e) {
(void)e; (void)e;
const char *url = lv_textarea_get_text(g_ta_browser_url); 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]; 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); lv_label_set_text(g_lbl_browser_status, buf);
char body[1500]; char body[2048];
memset(body, 0, sizeof(body)); memset(body, 0, sizeof(body));
uint32_t target_ip = g_net_cfg.gateway; int res = net_http_get_url(url, body, sizeof(body));
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));
if (res == 200) { 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); 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 { } else {
lv_label_set_text(g_lbl_browser_status, "Connection Failed"); lv_label_set_text(g_lbl_browser_status, "Connection Failed / Timeout");
lv_textarea_set_text(g_txt_browser_content, "Error: Could not connect to remote host via TCP.\nCheck network status in Network Center."); 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) // 6. BOTTOM TASKBAR (Windows / KDE Plasma Style)
// ========================================================================= // =========================================================================
lv_obj_t *taskbar = lv_obj_create(scr); 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_align(taskbar, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_set_style_bg_color(taskbar, lv_color_hex(0x141824), 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); lv_obj_set_style_border_color(taskbar, lv_color_hex(0x2a3447), 0);
@@ -1273,8 +1262,10 @@ int main() {
net_init(); net_init();
printf("[GUI-SERVER] net_init() OK.\n"); printf("[GUI-SERVER] net_init() OK.\n");
// 3. Register Framebuffer Display Driver (Double-buffered with 200 rows) // 3. Register Framebuffer Display Driver (Double-buffered with dynamically scaled rows)
lv_disp_draw_buf_init(&g_draw_buf, g_buf1, g_buf2, 1280 * BUF_HEIGHT); 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); lv_disp_drv_init(&g_disp_drv);
g_disp_drv.hor_res = (lv_coord_t)g_fb.width; g_disp_drv.hor_res = (lv_coord_t)g_fb.width;
g_disp_drv.ver_res = (lv_coord_t)g_fb.height; g_disp_drv.ver_res = (lv_coord_t)g_fb.height;
+44 -21
View File
@@ -317,32 +317,51 @@ static void cmd_modules() {
} }
static void cmd_curl(const char *target) { static void cmd_curl(const char *target) {
char body[1024]; if (!target || !*target) {
memset(body, 0, sizeof(body)); puts("Usage: curl <http://domain-or-ip/path>");
uint32_t ip = g_net_cfg.gateway; return;
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;
} }
char body[2048];
memset(body, 0, sizeof(body));
char ip_str[32]; printf("[curl] Fetching '%s' over TCP/IPv4...\n", target);
format_ip(ip, ip_str); int status = net_http_get_url(target, body, sizeof(body));
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));
if (status == 200) { 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); puts(body);
} else { } 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); cmd_curl(cmd + 5);
} else if (strncmp(cmd, "fetch ", 6) == 0) { } else if (strncmp(cmd, "fetch ", 6) == 0) {
cmd_curl(cmd + 6); 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) { } else if (strcmp(cmd, "fastfetch") == 0 || strcmp(cmd, "neofetch") == 0) {
print_fastfetch(); print_fastfetch();
} else if (strcmp(cmd, "clear") == 0) { } else if (strcmp(cmd, "clear") == 0) {