feat: Add Process Manager, Limine Framebuffer GUI, RTL8139 Net stack, and extended UNIX commands
This commit is contained in:
@@ -9,6 +9,8 @@ extern "C" {
|
||||
|
||||
int puts(const char *s);
|
||||
int putchar(int c);
|
||||
int printf(const char *format, ...);
|
||||
int sprintf(char *str, const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ void *realloc(void *ptr, size_t size);
|
||||
|
||||
void abort(void);
|
||||
void exit(int status);
|
||||
int atoi(const char *nptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ int strcmp(const char *s1, const char *s2);
|
||||
int strncmp(const char *s1, const char *s2, size_t n);
|
||||
char *strcpy(char *dest, const char *src);
|
||||
char *strncpy(char *dest, const char *src, size_t n);
|
||||
char *strchr(const char *s, int c);
|
||||
char *strstr(const char *haystack, const char *needle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
#include "abi/net.h"
|
||||
#include "rtl8139.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
|
||||
// Default QEMU User Networking (SLIRP) Configuration
|
||||
// Guest IP: 10.0.2.15 (0x0F02000A)
|
||||
// Gateway: 10.0.2.2 (0x0202000A)
|
||||
// Netmask: 255.255.255.0
|
||||
net_config_t g_net_cfg = {
|
||||
.ip = (10) | (0 << 8) | (2 << 16) | (15 << 24),
|
||||
.gateway = (10) | (0 << 8) | (2 << 16) | (2 << 24),
|
||||
.netmask = (255) | (255 << 8) | (255 << 16) | (0 << 24),
|
||||
.mac = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56}
|
||||
};
|
||||
|
||||
static uint16_t htons(uint16_t v) {
|
||||
return (uint16_t)(((v & 0xFF) << 8) | ((v >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t htonl(uint32_t v) {
|
||||
return (((v & 0xFF) << 24) |
|
||||
(((v >> 8) & 0xFF) << 16) |
|
||||
(((v >> 16) & 0xFF) << 8) |
|
||||
((v >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
uint16_t net_checksum(const void *buf, size_t len) {
|
||||
const uint16_t *data = (const uint16_t *)buf;
|
||||
uint32_t sum = 0;
|
||||
|
||||
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++) {
|
||||
g_net_cfg.mac[i] = g_rtl8139.mac[i];
|
||||
}
|
||||
}
|
||||
|
||||
int net_send_arp_request(uint32_t target_ip) {
|
||||
uint8_t packet[64] = {0};
|
||||
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
|
||||
arp->hw_type = htons(1); // Ethernet
|
||||
arp->proto_type = htons(0x0800); // IPv4
|
||||
arp->hw_len = 6;
|
||||
arp->proto_len = 4;
|
||||
arp->opcode = htons(1); // Request
|
||||
memcpy(arp->sender_mac, g_net_cfg.mac, 6);
|
||||
arp->sender_ip = g_net_cfg.ip;
|
||||
memset(arp->target_mac, 0x00, 6);
|
||||
arp->target_ip = target_ip;
|
||||
|
||||
return rtl8139_send_packet(packet, sizeof(eth_hdr_t) + sizeof(arp_hdr_t));
|
||||
}
|
||||
|
||||
int net_send_icmp_ping(uint32_t target_ip, uint16_t seq) {
|
||||
uint8_t packet[98] = {0};
|
||||
eth_hdr_t *eth = (eth_hdr_t *)packet;
|
||||
ipv4_hdr_t *ip = (ipv4_hdr_t *)(packet + sizeof(eth_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);
|
||||
|
||||
// 1. Ethernet Header (Direct to Gateway or Broadcast MAC in QEMU SLIRP)
|
||||
memset(eth->dest_mac, 0xFF, 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->tos = 0;
|
||||
ip->total_length = htons(20 + 8 + 32); // IP + ICMP + 32-byte payload = 60 bytes
|
||||
ip->id = htons(seq);
|
||||
ip->flags_fragment = htons(0x4000); // Don't Fragment
|
||||
ip->ttl = 64;
|
||||
ip->protocol = IP_PROTO_ICMP;
|
||||
ip->src_ip = g_net_cfg.ip;
|
||||
ip->dst_ip = target_ip;
|
||||
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);
|
||||
|
||||
// 32-byte payload pattern: 'a', 'b', 'c'...
|
||||
for (int i = 0; i < 32; i++) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
eth_hdr_t *eth = (eth_hdr_t *)buffer;
|
||||
if (htons(eth->ethertype) != ETHERTYPE_IPv4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
icmp_hdr_t *icmp = (icmp_hdr_t *)(buffer + 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; // Got Echo Reply!
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t parse_ip(const char *str) {
|
||||
uint32_t parts[4] = {0};
|
||||
int idx = 0;
|
||||
while (*str && idx < 4) {
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
parts[idx] = parts[idx] * 10 + (*str - '0');
|
||||
} else if (*str == '.') {
|
||||
idx++;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return (parts[0]) | (parts[1] << 8) | (parts[2] << 16) | (parts[3] << 24);
|
||||
}
|
||||
|
||||
void format_ip(uint32_t ip, char *buf) {
|
||||
uint8_t *b = (uint8_t *)&ip;
|
||||
// Simple itoa formatting
|
||||
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;
|
||||
}
|
||||
buf[len++] = '0' + val;
|
||||
if (i < 3) buf[len++] = '.';
|
||||
}
|
||||
buf[len] = '\0';
|
||||
}
|
||||
@@ -121,3 +121,22 @@ void abort(void) {
|
||||
void exit(int status) {
|
||||
sys_exit(status);
|
||||
}
|
||||
|
||||
int atoi(const char *nptr) {
|
||||
int res = 0;
|
||||
int sign = 1;
|
||||
while (*nptr == ' ' || *nptr == '\t' || *nptr == '\n' || *nptr == '\r') {
|
||||
nptr++;
|
||||
}
|
||||
if (*nptr == '-') {
|
||||
sign = -1;
|
||||
nptr++;
|
||||
} else if (*nptr == '+') {
|
||||
nptr++;
|
||||
}
|
||||
while (*nptr >= '0' && *nptr <= '9') {
|
||||
res = res * 10 + (*nptr - '0');
|
||||
nptr++;
|
||||
}
|
||||
return sign * res;
|
||||
}
|
||||
|
||||
@@ -90,3 +90,25 @@ char *strncpy(char *dest, const char *src, size_t n) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *strchr(const char *s, int c) {
|
||||
char ch = (char)c;
|
||||
while (*s) {
|
||||
if (*s == ch) return (char *)s;
|
||||
s++;
|
||||
}
|
||||
if (ch == '\0') return (char *)s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strstr(const char *haystack, const char *needle) {
|
||||
if (!*needle) return (char *)haystack;
|
||||
size_t needle_len = strlen(needle);
|
||||
while (*haystack) {
|
||||
if (strncmp(haystack, needle, needle_len) == 0) {
|
||||
return (char *)haystack;
|
||||
}
|
||||
haystack++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "abi/syscalls.h"
|
||||
#include "abi/types.h"
|
||||
|
||||
@@ -15,3 +16,108 @@ int putchar(int c) {
|
||||
sys_log_debug(&ch, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
static int format_uint(char *buf, unsigned long long val, int base, int width, char pad) {
|
||||
char tmp[32];
|
||||
int tpos = 0;
|
||||
const char digits[] = "0123456789abcdef";
|
||||
|
||||
if (val == 0) {
|
||||
tmp[tpos++] = '0';
|
||||
} else {
|
||||
while (val > 0) {
|
||||
tmp[tpos++] = digits[val % base];
|
||||
val /= base;
|
||||
}
|
||||
}
|
||||
|
||||
int written = 0;
|
||||
while (tpos < width) {
|
||||
buf[written++] = pad;
|
||||
width--;
|
||||
}
|
||||
while (tpos > 0) {
|
||||
buf[written++] = tmp[--tpos];
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, __builtin_va_list args) {
|
||||
if (size == 0) return 0;
|
||||
size_t out = 0;
|
||||
|
||||
while (*fmt && out < size - 1) {
|
||||
if (*fmt != '%') {
|
||||
buf[out++] = *fmt++;
|
||||
continue;
|
||||
}
|
||||
fmt++; // skip '%'
|
||||
|
||||
char pad = ' ';
|
||||
int width = 0;
|
||||
if (*fmt == '0') {
|
||||
pad = '0';
|
||||
fmt++;
|
||||
}
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
width = width * 10 + (*fmt - '0');
|
||||
fmt++;
|
||||
}
|
||||
|
||||
if (*fmt == 's') {
|
||||
const char *str = __builtin_va_arg(args, const char *);
|
||||
if (!str) str = "(null)";
|
||||
while (*str && out < size - 1) {
|
||||
buf[out++] = *str++;
|
||||
}
|
||||
} else if (*fmt == 'd' || *fmt == 'i') {
|
||||
long long val = __builtin_va_arg(args, int);
|
||||
if (val < 0) {
|
||||
if (out < size - 1) buf[out++] = '-';
|
||||
val = -val;
|
||||
}
|
||||
out += format_uint(buf + out, (unsigned long long)val, 10, width, pad);
|
||||
} else if (*fmt == 'u') {
|
||||
unsigned long long val = __builtin_va_arg(args, unsigned int);
|
||||
out += format_uint(buf + out, val, 10, width, pad);
|
||||
} else if (*fmt == 'x' || *fmt == 'X') {
|
||||
unsigned long long val = __builtin_va_arg(args, unsigned int);
|
||||
out += format_uint(buf + out, val, 16, width, pad);
|
||||
} else if (*fmt == 'p') {
|
||||
unsigned long long val = (unsigned long long)__builtin_va_arg(args, void *);
|
||||
if (out < size - 2) {
|
||||
buf[out++] = '0';
|
||||
buf[out++] = 'x';
|
||||
}
|
||||
out += format_uint(buf + out, val, 16, 8, '0');
|
||||
} else if (*fmt == 'c') {
|
||||
char c = (char)__builtin_va_arg(args, int);
|
||||
if (out < size - 1) buf[out++] = c;
|
||||
} else if (*fmt == '%') {
|
||||
if (out < size - 1) buf[out++] = '%';
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
buf[out] = '\0';
|
||||
return (int)out;
|
||||
}
|
||||
|
||||
int sprintf(char *buf, const char *fmt, ...) {
|
||||
__builtin_va_list args;
|
||||
__builtin_va_start(args, fmt);
|
||||
int ret = vsnprintf(buf, 2048, fmt, args);
|
||||
__builtin_va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
char buf[1024];
|
||||
__builtin_va_list args;
|
||||
__builtin_va_start(args, fmt);
|
||||
int len = vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
__builtin_va_end(args);
|
||||
if (len > 0) {
|
||||
sys_log_debug(buf, (size_t)len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user