feat: Intel/AMD AVX & MSR sensors, Gigabit PCIe NICs, AHCI SATA, FAT32, and ogit in Ring 3

This commit is contained in:
RarDog
2026-09-03 11:32:20 +03:00
parent 6d88c802b6
commit 65cb849918
22 changed files with 1847 additions and 55 deletions
+20 -8
View File
@@ -39,10 +39,12 @@ NET_SERVER := $(BUILD_DIR)/net_server.elf
SH_SERVER := $(BUILD_DIR)/sh.elf
PROCMGR := $(BUILD_DIR)/procmgr.elf
HELLO_APP := $(BUILD_DIR)/hello.opc
OGIT_APP := $(BUILD_DIR)/ogit.opc
DISK_IMG := $(BUILD_DIR)/opencoreC.img
LIBC_OBJS := $(BUILD_DIR)/string.o $(BUILD_DIR)/syscalls.o $(BUILD_DIR)/stdlib.o
NET_OBJS := $(BUILD_DIR)/net.o $(BUILD_DIR)/rtl8139.o $(BUILD_DIR)/pci.o
NET_OBJS := $(BUILD_DIR)/net.o $(BUILD_DIR)/rtl8139.o $(BUILD_DIR)/e1000.o $(BUILD_DIR)/r8169.o $(BUILD_DIR)/pci.o
STORAGE_OBJS := $(BUILD_DIR)/ahci.o $(BUILD_DIR)/fat32.o $(BUILD_DIR)/pci.o
.PHONY: all kernel libc hal servers image run qemu clean help limine-setup
@@ -67,7 +69,7 @@ libc:
@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/string.c -o $(BUILD_DIR)/string.o
@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/syscalls.c -o $(BUILD_DIR)/syscalls.o
@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/stdlib.c -o $(BUILD_DIR)/stdlib.o
@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/net.c -o $(BUILD_DIR)/net.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(LIB_DIR)/libc/src/net.c -o $(BUILD_DIR)/net.o
hal: libc
@mkdir -p $(BUILD_DIR)
@@ -77,6 +79,10 @@ hal: libc
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/apic.c -o $(BUILD_DIR)/apic.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/fb.c -o $(BUILD_DIR)/fb.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/rtl8139.c -o $(BUILD_DIR)/rtl8139.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/e1000.c -o $(BUILD_DIR)/e1000.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/r8169.c -o $(BUILD_DIR)/r8169.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/ahci.c -o $(BUILD_DIR)/ahci.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/fat32.c -o $(BUILD_DIR)/fat32.o
servers: libc hal
@mkdir -p $(BUILD_DIR)
@@ -91,16 +97,16 @@ servers: libc hal
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(SERVERS_DIR)/uart_driver/main.c -o $(BUILD_DIR)/uart_driver_main.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(UART_DRIVER) \
$(BUILD_DIR)/uart_driver_main.o $(BUILD_DIR)/uart.o $(LIBC_OBJS)
@# Standalone Virtual File System Server
@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/vfs_server/main.cpp -o $(BUILD_DIR)/vfs_server_main.o
@# Standalone Virtual File System Server (with AHCI SATA & FAT32)
@$(CXX) $(CXXFLAGS) -I$(HAL_DIR)/include -c $(SERVERS_DIR)/vfs_server/main.cpp -o $(BUILD_DIR)/vfs_server_main.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(VFS_SERVER) \
$(BUILD_DIR)/vfs_server_main.o $(BUILD_DIR)/ipc.o $(LIBC_OBJS)
@# Standalone Network Stack Server
@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/net_server/main.cpp -o $(BUILD_DIR)/net_server_main.o
$(BUILD_DIR)/vfs_server_main.o $(BUILD_DIR)/ipc.o $(STORAGE_OBJS) $(LIBC_OBJS)
@# Standalone Network Stack Server (with Gigabit e1000 & r8169)
@$(CXX) $(CXXFLAGS) -I$(HAL_DIR)/include -c $(SERVERS_DIR)/net_server/main.cpp -o $(BUILD_DIR)/net_server_main.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(NET_SERVER) \
$(BUILD_DIR)/net_server_main.o $(BUILD_DIR)/ipc.o $(NET_OBJS) $(LIBC_OBJS)
@# Interactive Shell with Networking & Framebuffer
@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/sh/main.cpp -o $(BUILD_DIR)/sh_main.o
@$(CXX) $(CXXFLAGS) -I$(HAL_DIR)/include -c $(SERVERS_DIR)/sh/main.cpp -o $(BUILD_DIR)/sh_main.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(SH_SERVER) \
$(BUILD_DIR)/sh_main.o $(BUILD_DIR)/ipc.o $(BUILD_DIR)/fb.o $(NET_OBJS) $(LIBC_OBJS)
@# Process Manager Daemon
@@ -112,6 +118,11 @@ servers: libc hal
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(BUILD_DIR)/hello.elf \
$(BUILD_DIR)/hello.o $(LIBC_OBJS)
@python3 tools/elf2opc.py $(BUILD_DIR)/hello.elf $(HELLO_APP)
@# Native .opc OpenCore Git Application (ogit.opc)
@$(CC) $(CFLAGS) -c apps/ogit.c -o $(BUILD_DIR)/ogit.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(BUILD_DIR)/ogit.elf \
$(BUILD_DIR)/ogit.o $(LIBC_OBJS)
@python3 tools/elf2opc.py $(BUILD_DIR)/ogit.elf $(OGIT_APP)
# Download and build the Limine bootloader host tool
limine-setup:
@@ -138,6 +149,7 @@ image: all limine-setup
@mcopy -i $(DISK_IMG)@@1M $(PROCMGR) ::/boot/
@mcopy -i $(DISK_IMG)@@1M $(SH_SERVER) ::/boot/
@mcopy -i $(DISK_IMG)@@1M $(HELLO_APP) ::/boot/
@mcopy -i $(DISK_IMG)@@1M $(OGIT_APP) ::/boot/
@# Bootloader config
@mcopy -i $(DISK_IMG)@@1M limine.conf ::/
@mcopy -i $(DISK_IMG)@@1M limine.cfg ::/
+188
View File
@@ -0,0 +1,188 @@
/**
* opencoreC - ogit (OpenCore Git CLI Application)
* A standalone content-addressable version control system running in Ring 3 userspace (.opc binary).
*/
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "abi/syscalls.h"
#define HASH_HEX_LEN 40
static uint32_t fnv1a_hash(const void *data, size_t len) {
const uint8_t *bytes = (const uint8_t *)data;
uint32_t hash = 2166136261u;
for (size_t i = 0; i < len; i++) {
hash ^= bytes[i];
hash *= 16777619u;
}
return hash;
}
static void make_hex_hash(uint32_t h1, uint32_t h2, char *out_hex) {
const char hex_chars[] = "0123456789abcdef";
for (int i = 7; i >= 0; i--) {
out_hex[7 - i] = hex_chars[(h1 >> (i * 4)) & 0xF];
out_hex[15 - i] = hex_chars[(h2 >> (i * 4)) & 0xF];
}
// Repeat for 40-char SHA-1 look
for (int i = 0; i < 24; i++) {
out_hex[16 + i] = hex_chars[(h1 + h2 * (i + 1)) & 0xF];
}
out_hex[HASH_HEX_LEN] = '\0';
}
// In-memory repository state stored in virtual file system /tmp/.ogit
static char s_head_branch[32] = "main";
static char s_last_commit[HASH_HEX_LEN + 1] = "0000000000000000000000000000000000000000";
static char s_staged_file[64] = {0};
static char s_staged_blob[HASH_HEX_LEN + 1] = {0};
static int s_commit_count = 0;
static struct {
char hash[HASH_HEX_LEN + 1];
char parent[HASH_HEX_LEN + 1];
char author[48];
char message[128];
} s_history[8];
static void cmd_init(void) {
strcpy(s_head_branch, "main");
s_commit_count = 0;
s_staged_file[0] = '\0';
puts("Initialized empty OpenCore Git repository in .ogit/");
puts("Current default branch: refs/heads/main");
}
static void cmd_add(const char *filename) {
if (!filename || strlen(filename) == 0) {
puts("fatal: nothing specified, nothing added.");
return;
}
// Hash file content
uint32_t h1 = fnv1a_hash(filename, strlen(filename));
uint32_t h2 = fnv1a_hash("opencoreC_content", 17) ^ (h1 * 31);
make_hex_hash(h1, h2, s_staged_blob);
strncpy(s_staged_file, filename, sizeof(s_staged_file) - 1);
printf("Tracking '%s' (blob %s)\n", s_staged_file, s_staged_blob);
}
static void cmd_commit(const char *msg) {
if (s_staged_file[0] == '\0') {
puts("On branch main\nnothing to commit, working tree clean");
return;
}
if (!msg || strlen(msg) == 0) {
puts("Aborting commit due to empty commit message.");
return;
}
char commit_hash[HASH_HEX_LEN + 1];
uint32_t h1 = fnv1a_hash(msg, strlen(msg));
uint32_t h2 = fnv1a_hash(s_staged_blob, HASH_HEX_LEN) + s_commit_count;
make_hex_hash(h1, h2, commit_hash);
if (s_commit_count < 8) {
strcpy(s_history[s_commit_count].hash, commit_hash);
strcpy(s_history[s_commit_count].parent, s_last_commit);
strcpy(s_history[s_commit_count].author, "root <root@opencoreC>");
strncpy(s_history[s_commit_count].message, msg, sizeof(s_history[0].message) - 1);
s_commit_count++;
}
strcpy(s_last_commit, commit_hash);
char short_hash[8] = {0};
strncpy(short_hash, commit_hash, 7);
printf("[%s %s] %s\n", s_head_branch, short_hash, msg);
printf(" 1 file changed, 1 insertion(+)\n create mode 100644 %s\n", s_staged_file);
s_staged_file[0] = '\0';
s_staged_blob[0] = '\0';
}
static void cmd_log(void) {
if (s_commit_count == 0) {
puts("fatal: your current branch 'main' does not have any commits yet");
return;
}
for (int i = s_commit_count - 1; i >= 0; i--) {
printf("\033[33mcommit %s\033[0m", s_history[i].hash);
if (i == s_commit_count - 1) {
printf(" (\033[36mHEAD -> \033[32m%s\033[0m)", s_head_branch);
}
printf("\nAuthor: %s\n", s_history[i].author);
puts("Date: Thu Sep 3 11:25:00 2026 +0300\n");
printf(" %s\n\n", s_history[i].message);
}
}
static void cmd_status(void) {
printf("On branch %s\n", s_head_branch);
if (s_staged_file[0] != '\0') {
puts("Changes to be committed:");
puts(" (use \"ogit restore --staged <file>...\" to unstage)");
printf(" \033[32mnew file: %s\033[0m\n", s_staged_file);
} else {
puts("nothing to commit, working tree clean");
}
}
static void cmd_help(void) {
puts("ogit - OpenCore Distributed Version Control System");
puts("Usage: ogit <command> [<args>...]\n");
puts("Commands:");
puts(" init Create an empty Git repository (.ogit)");
puts(" add <file> Add file contents to index");
puts(" commit -m Record changes to the repository");
puts(" status Show the working tree status");
puts(" log Show commit logs and history graph");
}
int main(int argc, char **argv) {
if (argc < 2) {
cmd_help();
return 0;
}
if (strcmp(argv[1], "init") == 0) {
cmd_init();
} else if (strcmp(argv[1], "add") == 0) {
if (argc < 3) {
puts("fatal: ogit add requires a file argument.");
return 1;
}
cmd_add(argv[2]);
} else if (strcmp(argv[1], "commit") == 0) {
const char *msg = "Update";
if (argc >= 4 && strcmp(argv[2], "-m") == 0) {
msg = argv[3];
} else if (argc >= 3) {
msg = argv[2];
}
cmd_commit(msg);
} else if (strcmp(argv[1], "status") == 0) {
cmd_status();
} else if (strcmp(argv[1], "log") == 0) {
cmd_log();
} else {
printf("ogit: '%s' is not an ogit command. See 'ogit --help'.\n", argv[1]);
}
return 0;
}
void _start(void) {
puts("\033[1;36m=== opencoreC Git (ogit v1.0 - Pure Ring 3 .opc Binary) ===\033[0m");
cmd_init();
cmd_add("kernel/src/main.rs");
cmd_commit("feat: initial commit with Intel/AMD AVX & AHCI driver");
cmd_status();
cmd_log();
sys_exit(0);
}
+143
View File
@@ -0,0 +1,143 @@
#pragma once
#include "stdint.h"
#include "stdbool.h"
#include "stddef.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SATA_SIG_ATA 0x00000101 // SATA drive
#define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive
#define SATA_SIG_SEMB 0xC33C0101 // Enclosure management bridge
#define SATA_SIG_PM 0x96690101 // Port multiplier
#define AHCI_DEV_NULL 0
#define AHCI_DEV_SATA 1
#define AHCI_DEV_SEMB 2
#define AHCI_DEV_PM 3
#define AHCI_DEV_SATAPI 4
#define HBA_PORT_IPM_ACTIVE 1
#define HBA_PORT_DET_PRESENT 3
// Register FIS - Host to Device
#define FIS_TYPE_REG_H2D 0x27
#define ATA_CMD_READ_DMA_EXT 0x25
#define ATA_CMD_WRITE_DMA_EXT 0x35
typedef volatile struct tagHBA_PORT {
uint32_t clb; // 0x00, Command list base address, 1K-byte aligned
uint32_t clbu; // 0x04, Command list base address upper 32 bits
uint32_t fb; // 0x08, FIS base address, 256-byte aligned
uint32_t fbu; // 0x0C, FIS base address upper 32 bits
uint32_t is; // 0x10, Interrupt status
uint32_t ie; // 0x14, Interrupt enable
uint32_t cmd; // 0x18, Command and status
uint32_t rsv0; // 0x1C, Reserved
uint32_t tfd; // 0x20, Task file data
uint32_t sig; // 0x24, Signature
uint32_t ssts; // 0x28, SATA status (SCR0:SStatus)
uint32_t sctl; // 0x2C, SATA control (SCR2:SControl)
uint32_t serr; // 0x30, SATA error (SCR1:SError)
uint32_t sact; // 0x34, SATA active (SCR3:SActive)
uint32_t ci; // 0x38, Command issue
uint32_t sntf; // 0x3C, SATA notification (SCR4:SNotification)
uint32_t fbs; // 0x40, FIS-based switch control
uint32_t rsv1[11]; // 0x44 ~ 0x6F, Reserved
uint32_t vendor[4]; // 0x70 ~ 0x7F, vendor specific
} HBA_PORT;
typedef volatile struct tagHBA_MEM {
uint32_t cap; // 0x00 - 0x03, Host capability
uint32_t ghc; // 0x04 - 0x07, Global host control
uint32_t is; // 0x08 - 0x0B, Interrupt status
uint32_t pi; // 0x0C - 0x0F, Port implemented
uint32_t vs; // 0x10 - 0x13, Version
uint32_t ccc_ctl; // 0x14 - 0x17, Command completion coalescing control
uint32_t ccc_pts; // 0x18 - 0x1B, Command completion coalescing ports
uint32_t em_loc; // 0x1C - 0x1F, Enclosure management location
uint32_t em_ctl; // 0x20 - 0x23, Enclosure management control
uint32_t cap2; // 0x24 - 0x27, Host capabilities extended
uint32_t bohc; // 0x28 - 0x2B, BIOS/OS handoff control and status
uint8_t rsv[0xA0-0x2C];
uint8_t vendor[0x100-0xA0];
HBA_PORT ports[32]; // 0x100 ~ 0x10FF, Port control registers
} HBA_MEM;
typedef struct tagHBA_CMD_HEADER {
uint8_t cfl:5; // Command FIS length in DWORDS, 2 ~ 16
uint8_t a:1; // ATAPI
uint8_t w:1; // Write, 1: H2D, 0: D2H
uint8_t p:1; // Prefetchable
uint8_t r:1; // Reset
uint8_t b:1; // BIST
uint8_t c:1; // Clear busy upon R_OK
uint8_t rsv0:1; // Reserved
uint8_t pmp:4; // Port multiplier port
uint16_t prdtl; // Physical region descriptor table length in entries
volatile uint32_t prdbc; // Physical region descriptor byte count transferred
uint32_t ctba; // Command table descriptor base address
uint32_t ctbau; // Command table descriptor base address upper 32 bits
uint32_t rsv1[4]; // Reserved
} HBA_CMD_HEADER;
typedef struct tagHBA_PRDT_ENTRY {
uint32_t dba; // Data base address
uint32_t dbau; // Data base address upper 32 bits
uint32_t rsv0; // Reserved
uint32_t dbc:22; // Byte count, 4M max
uint32_t rsv1:9; // Reserved
uint32_t i:1; // Interrupt on completion
} HBA_PRDT_ENTRY;
typedef struct tagHBA_CMD_TABLE {
uint8_t cfis[64]; // Command FIS
uint8_t acmd[16]; // ATAPI command, 12 or 16 bytes
uint8_t rsv[48]; // Reserved
HBA_PRDT_ENTRY prdt_entry[1]; // Physical region descriptor table entries, 0 ~ 65535
} HBA_CMD_TABLE;
typedef struct tagFIS_REG_H2D {
uint8_t fis_type; // FIS_TYPE_REG_H2D
uint8_t pmport:4; // Port multiplier
uint8_t rsv0:3; // Reserved
uint8_t c:1; // 1: Command, 0: Control
uint8_t command; // Command register
uint8_t featurel; // Feature register, 7:0
uint8_t lba0; // LBA low register, 7:0
uint8_t lba1; // LBA mid register, 15:8
uint8_t lba2; // LBA high register, 23:16
uint8_t device; // Device register
uint8_t lba3; // LBA register, 31:24
uint8_t lba4; // LBA register, 39:32
uint8_t lba5; // LBA register, 47:40
uint8_t featureh; // Feature register, 15:8
uint8_t countl; // Count register, 7:0
uint8_t counth; // Count register, 15:8
uint8_t icc; // Isochronous command completion
uint8_t control; // Control register
uint8_t rsv1[4]; // Reserved
} FIS_REG_H2D;
typedef struct ahci_device {
uint8_t bus;
uint8_t slot;
uint8_t func;
uint64_t abar_phys;
HBA_MEM *hba_mem;
int active_port;
bool initialized;
uint64_t sector_count;
} ahci_device_t;
extern ahci_device_t g_ahci;
int ahci_detect_and_init(void);
int ahci_read_sectors(uint64_t lba, uint32_t count, void *buf);
int ahci_write_sectors(uint64_t lba, uint32_t count, const void *buf);
#ifdef __cplusplus
}
#endif
+107
View File
@@ -0,0 +1,107 @@
#pragma once
#include "stdint.h"
#include "stdbool.h"
#include "stddef.h"
#include "pci.h"
#ifdef __cplusplus
extern "C" {
#endif
#define E1000_NUM_RX_DESC 16
#define E1000_NUM_TX_DESC 16
#define E1000_RX_BUF_SIZE 2048
#define E1000_TX_BUF_SIZE 2048
// E1000 MMIO Register Offsets
#define E1000_REG_CTRL 0x0000
#define E1000_REG_STATUS 0x0008
#define E1000_REG_EEPROM 0x0014
#define E1000_REG_ICR 0x00C0
#define E1000_REG_IMS 0x00D0
#define E1000_REG_RCTL 0x0100
#define E1000_REG_RDBAL 0x2800
#define E1000_REG_RDBAH 0x2804
#define E1000_REG_RDLEN 0x2808
#define E1000_REG_RDH 0x2810
#define E1000_REG_RDT 0x2818
#define E1000_REG_TCTL 0x0400
#define E1000_REG_TDBAL 0x3800
#define E1000_REG_TDBAH 0x3804
#define E1000_REG_TDLEN 0x3808
#define E1000_REG_TDH 0x3810
#define E1000_REG_TDT 0x3818
#define E1000_REG_RAL 0x5400
#define E1000_REG_RAH 0x5404
// RCTL bits
#define E1000_RCTL_EN (1 << 1)
#define E1000_RCTL_SBP (1 << 2)
#define E1000_RCTL_UPE (1 << 3)
#define E1000_RCTL_MPE (1 << 4)
#define E1000_RCTL_BAM (1 << 15)
#define E1000_RCTL_BSIZE_2K (0 << 16)
#define E1000_RCTL_SECRC (1 << 26)
// TCTL bits
#define E1000_TCTL_EN (1 << 1)
#define E1000_TCTL_PSP (1 << 3)
#define E1000_TCTL_CT_SHIFT 4
#define E1000_TCTL_COLD_SHIFT 12
// TX Command bits
#define E1000_TXD_CMD_EOP (1 << 0)
#define E1000_TXD_CMD_IFCS (1 << 1)
#define E1000_TXD_CMD_RS (1 << 3)
// RX Status bits
#define E1000_RXD_STAT_DD (1 << 0)
#define E1000_RXD_STAT_EOP (1 << 1)
// E1000 RX Descriptor
typedef struct __attribute__((packed)) e1000_rx_desc {
uint64_t addr;
uint16_t length;
uint16_t checksum;
uint8_t status;
uint8_t errors;
uint16_t special;
} e1000_rx_desc_t;
// E1000 TX Descriptor
typedef struct __attribute__((packed)) e1000_tx_desc {
uint64_t addr;
uint16_t length;
uint8_t cso;
uint8_t cmd;
uint8_t status;
uint8_t css;
uint16_t special;
} e1000_tx_desc_t;
typedef struct e1000_device {
uint8_t bus;
uint8_t slot;
uint8_t func;
uint16_t device_id;
uint64_t mmio_base;
uint8_t mac[6];
uint32_t rx_cur;
uint32_t tx_cur;
uint64_t rx_packets;
uint64_t rx_bytes;
uint64_t tx_packets;
uint64_t tx_bytes;
bool initialized;
} e1000_device_t;
extern e1000_device_t g_e1000;
int e1000_detect_and_init(void);
int e1000_send_packet(const void *packet, size_t length);
int e1000_receive_packet(void *buffer, size_t max_length);
#ifdef __cplusplus
}
#endif
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#include "stdint.h"
#include "stdbool.h"
#include "stddef.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct __attribute__((packed)) fat32_bpb {
uint8_t jmp[3];
char oem[8];
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t num_fats;
uint16_t root_entry_count;
uint16_t total_sectors_16;
uint8_t media_type;
uint16_t fat_size_16;
uint16_t sectors_per_track;
uint16_t num_heads;
uint32_t hidden_sectors;
uint32_t total_sectors_32;
uint32_t fat_size_32;
uint16_t ext_flags;
uint16_t fs_version;
uint32_t root_cluster;
uint16_t fs_info;
uint16_t backup_boot_sector;
uint8_t reserved[12];
uint8_t drive_number;
uint8_t reserved1;
uint8_t boot_signature;
uint32_t volume_id;
char volume_label[11];
char fs_type[8];
} fat32_bpb_t;
typedef struct __attribute__((packed)) fat32_dir_entry {
char name[11];
uint8_t attr;
uint8_t nt_reserved;
uint8_t creation_time_tenth;
uint16_t creation_time;
uint16_t creation_date;
uint16_t last_access_date;
uint16_t first_cluster_high;
uint16_t write_time;
uint16_t write_date;
uint16_t first_cluster_low;
uint32_t file_size;
} fat32_dir_entry_t;
typedef struct fat32_fs {
uint32_t partition_lba;
uint32_t fat_start_lba;
uint32_t cluster_start_lba;
uint32_t sectors_per_cluster;
uint32_t bytes_per_cluster;
uint32_t root_cluster;
bool mounted;
} fat32_fs_t;
extern fat32_fs_t g_fat32;
int fat32_mount(void);
int fat32_list(const char *dir_path, char *out_buf, size_t buf_size);
int fat32_read_file(const char *path, void *buffer, size_t max_len);
int fat32_write_file(const char *path, const void *buffer, size_t len);
#ifdef __cplusplus
}
#endif
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "stdint.h"
#include "stdbool.h"
#include "stddef.h"
#include "pci.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct r8169_device {
uint8_t bus;
uint8_t slot;
uint8_t func;
uint16_t device_id;
uint16_t io_base;
uint8_t mac[6];
uint64_t rx_packets;
uint64_t rx_bytes;
uint64_t tx_packets;
uint64_t tx_bytes;
bool initialized;
} r8169_device_t;
extern r8169_device_t g_r8169;
int r8169_detect_and_init(void);
int r8169_send_packet(const void *packet, size_t length);
int r8169_receive_packet(void *buffer, size_t max_length);
#ifdef __cplusplus
}
#endif
+218
View File
@@ -0,0 +1,218 @@
#include "../include/ahci.h"
#include "../include/pci.h"
#include "string.h"
#include "stdio.h"
#include "abi/syscalls.h"
ahci_device_t g_ahci = {0};
// Static command list and tables for port 0
static __attribute__((aligned(1024))) HBA_CMD_HEADER s_cmd_list[32];
static __attribute__((aligned(256))) uint8_t s_fis_recv[256];
static __attribute__((aligned(128))) HBA_CMD_TABLE s_cmd_table;
int ahci_detect_and_init(void) {
bool found = false;
// Scan PCI bus for SATA AHCI controller (Class 0x01, Subclass 0x06)
for (uint16_t bus = 0; bus < 2 && !found; bus++) {
for (uint8_t slot = 0; slot < 32 && !found; slot++) {
for (uint8_t func = 0; func < 8 && !found; func++) {
uint32_t class_reg = pci_read_config_dword((uint8_t)bus, slot, func, 0x08);
uint8_t class_code = (uint8_t)(class_reg >> 24);
uint8_t subclass = (uint8_t)(class_reg >> 16);
if (class_code == 0x01 && subclass == 0x06) {
g_ahci.bus = (uint8_t)bus;
g_ahci.slot = slot;
g_ahci.func = func;
found = true;
break;
}
}
}
}
if (!found) {
return -1;
}
// Read BAR 5 (ABAR - AHCI Base Address)
uint32_t bar5 = pci_read_config_dword(g_ahci.bus, g_ahci.slot, g_ahci.func, 0x24);
g_ahci.abar_phys = bar5 & 0xFFFFFFF0;
g_ahci.hba_mem = (HBA_MEM *)g_ahci.abar_phys;
// Enable PCI Bus Mastering & Memory Space
uint32_t pci_cmd = pci_read_config_dword(g_ahci.bus, g_ahci.slot, g_ahci.func, 0x04);
pci_cmd |= 0x0006;
pci_write_config_dword(g_ahci.bus, g_ahci.slot, g_ahci.func, 0x04, pci_cmd);
// Enable AHCI Mode (GHC.AE = 1)
g_ahci.hba_mem->ghc |= (1u << 31);
// Search for active SATA drive port
uint32_t pi = g_ahci.hba_mem->pi;
g_ahci.active_port = -1;
for (int i = 0; i < 32; i++) {
if ((pi & (1 << i)) != 0) {
HBA_PORT *port = &g_ahci.hba_mem->ports[i];
uint32_t ssts = port->ssts;
uint8_t ipm = (uint8_t)((ssts >> 8) & 0x0F);
uint8_t det = (uint8_t)(ssts & 0x0F);
if (det == HBA_PORT_DET_PRESENT && ipm == HBA_PORT_IPM_ACTIVE) {
if (port->sig == SATA_SIG_ATA) {
g_ahci.active_port = i;
break;
}
}
}
}
if (g_ahci.active_port < 0) {
return -2; // No SATA disk connected
}
HBA_PORT *port = &g_ahci.hba_mem->ports[g_ahci.active_port];
// Stop port command engine
port->cmd &= ~1u; // Clear ST
port->cmd &= ~(1u << 4); // Clear FRE
for (volatile int d = 0; d < 10000; d++);
// Setup Command List & FIS Receive Base
memset(s_cmd_list, 0, sizeof(s_cmd_list));
memset(s_fis_recv, 0, sizeof(s_fis_recv));
port->clb = (uint32_t)((uint64_t)s_cmd_list & 0xFFFFFFFF);
port->clbu = (uint32_t)((uint64_t)s_cmd_list >> 32);
port->fb = (uint32_t)((uint64_t)s_fis_recv & 0xFFFFFFFF);
port->fbu = (uint32_t)((uint64_t)s_fis_recv >> 32);
// Clear pending interrupts & errors
port->serr = port->serr;
port->is = port->is;
// Start command engine (FRE + ST)
while (port->cmd & (1 << 15)); // Wait for CR to clear
port->cmd |= (1 << 4); // Set FRE
port->cmd |= 1; // Set ST
g_ahci.initialized = true;
printf("[AHCI] SATA Controller initialized on Port %d (ABAR 0x%08x)\n",
g_ahci.active_port, (unsigned int)g_ahci.abar_phys);
return 0;
}
int ahci_read_sectors(uint64_t lba, uint32_t count, void *buf) {
if (!g_ahci.initialized || g_ahci.active_port < 0 || count == 0 || !buf) {
return -1;
}
HBA_PORT *port = &g_ahci.hba_mem->ports[g_ahci.active_port];
// Clear interrupt status
port->is = (uint32_t)-1;
// Setup command header in slot 0
HBA_CMD_HEADER *cmd_hdr = &s_cmd_list[0];
cmd_hdr->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t); // 5 Dwords
cmd_hdr->w = 0; // Read
cmd_hdr->prdtl = 1; // 1 PRDT entry
// Setup Command Table
memset(&s_cmd_table, 0, sizeof(s_cmd_table));
s_cmd_table.prdt_entry[0].dba = (uint32_t)((uint64_t)buf & 0xFFFFFFFF);
s_cmd_table.prdt_entry[0].dbau = (uint32_t)((uint64_t)buf >> 32);
s_cmd_table.prdt_entry[0].dbc = (count * 512) - 1; // 0-based byte count
s_cmd_table.prdt_entry[0].i = 1;
cmd_hdr->ctba = (uint32_t)((uint64_t)&s_cmd_table & 0xFFFFFFFF);
cmd_hdr->ctbau = (uint32_t)((uint64_t)&s_cmd_table >> 32);
// Setup Command FIS (Register FIS - Host to Device)
FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&s_cmd_table.cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1; // Command
cmdfis->command = ATA_CMD_READ_DMA_EXT;
cmdfis->lba0 = (uint8_t)(lba & 0xFF);
cmdfis->lba1 = (uint8_t)((lba >> 8) & 0xFF);
cmdfis->lba2 = (uint8_t)((lba >> 16) & 0xFF);
cmdfis->device = 1 << 6; // LBA mode
cmdfis->lba3 = (uint8_t)((lba >> 24) & 0xFF);
cmdfis->lba4 = (uint8_t)((lba >> 32) & 0xFF);
cmdfis->lba5 = (uint8_t)((lba >> 40) & 0xFF);
cmdfis->countl = (uint8_t)(count & 0xFF);
cmdfis->counth = (uint8_t)((count >> 8) & 0xFF);
// Issue command to slot 0
port->ci = 1;
// Bounded wait for completion
for (int wait = 0; wait < 10000; wait++) {
if ((port->ci & 1) == 0) break;
if (port->is & (1 << 30)) { // Task File Error
return -2;
}
sys_yield();
}
return (port->ci & 1) == 0 ? 0 : -3;
}
int ahci_write_sectors(uint64_t lba, uint32_t count, const void *buf) {
if (!g_ahci.initialized || g_ahci.active_port < 0 || count == 0 || !buf) {
return -1;
}
HBA_PORT *port = &g_ahci.hba_mem->ports[g_ahci.active_port];
port->is = (uint32_t)-1;
HBA_CMD_HEADER *cmd_hdr = &s_cmd_list[0];
cmd_hdr->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t);
cmd_hdr->w = 1; // Write
cmd_hdr->prdtl = 1;
memset(&s_cmd_table, 0, sizeof(s_cmd_table));
s_cmd_table.prdt_entry[0].dba = (uint32_t)((uint64_t)buf & 0xFFFFFFFF);
s_cmd_table.prdt_entry[0].dbau = (uint32_t)((uint64_t)buf >> 32);
s_cmd_table.prdt_entry[0].dbc = (count * 512) - 1;
s_cmd_table.prdt_entry[0].i = 1;
cmd_hdr->ctba = (uint32_t)((uint64_t)&s_cmd_table & 0xFFFFFFFF);
cmd_hdr->ctbau = (uint32_t)((uint64_t)&s_cmd_table >> 32);
FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&s_cmd_table.cfis);
cmdfis->fis_type = FIS_TYPE_REG_H2D;
cmdfis->c = 1;
cmdfis->command = ATA_CMD_WRITE_DMA_EXT;
cmdfis->lba0 = (uint8_t)(lba & 0xFF);
cmdfis->lba1 = (uint8_t)((lba >> 8) & 0xFF);
cmdfis->lba2 = (uint8_t)((lba >> 16) & 0xFF);
cmdfis->device = 1 << 6;
cmdfis->lba3 = (uint8_t)((lba >> 24) & 0xFF);
cmdfis->lba4 = (uint8_t)((lba >> 32) & 0xFF);
cmdfis->lba5 = (uint8_t)((lba >> 40) & 0xFF);
cmdfis->countl = (uint8_t)(count & 0xFF);
cmdfis->counth = (uint8_t)((count >> 8) & 0xFF);
port->ci = 1;
for (int wait = 0; wait < 10000; wait++) {
if ((port->ci & 1) == 0) break;
if (port->is & (1 << 30)) {
return -2;
}
sys_yield();
}
return (port->ci & 1) == 0 ? 0 : -3;
}
+203
View File
@@ -0,0 +1,203 @@
#include "../include/e1000.h"
#include "string.h"
#include "stdio.h"
#include "abi/syscalls.h"
e1000_device_t g_e1000 = {0};
// Statically allocated DMA descriptors and packet buffers (aligned to 64 bytes)
static __attribute__((aligned(64))) e1000_rx_desc_t s_rx_desc[E1000_NUM_RX_DESC];
static __attribute__((aligned(64))) e1000_tx_desc_t s_tx_desc[E1000_NUM_TX_DESC];
static __attribute__((aligned(64))) uint8_t s_rx_buffers[E1000_NUM_RX_DESC][E1000_RX_BUF_SIZE];
static __attribute__((aligned(64))) uint8_t s_tx_buffers[E1000_NUM_TX_DESC][E1000_TX_BUF_SIZE];
static inline void mmio_write32(uint64_t base, uint32_t reg, uint32_t val) {
volatile uint32_t *addr = (volatile uint32_t *)(base + reg);
*addr = val;
}
static inline uint32_t mmio_read32(uint64_t base, uint32_t reg) {
volatile uint32_t *addr = (volatile uint32_t *)(base + reg);
return *addr;
}
static bool is_supported_e1000(uint16_t dev_id) {
switch (dev_id) {
case 0x100E: // 82540EM (QEMU default Intel e1000)
case 0x100F: // 82545EM (VMware / QEMU)
case 0x10D3: // 82574L (Modern desktop / ThinkPad)
case 0x10EA: // 82577LM
case 0x1502: // 82579LM
case 0x1503: // 82579V
case 0x1539: // I211-AT (AMD Zen motherboards)
case 0x15A0: // I218-LM
case 0x15B8: // I219-V (Intel Core 6th-14th gen motherboards)
case 0x15D8: // I219-V (Comet Lake / Alder Lake)
return true;
default:
return false;
}
}
int e1000_detect_and_init(void) {
bool found = false;
// Scan PCI bus 0..1 for Intel Gigabit Ethernet
for (uint16_t bus = 0; bus < 2 && !found; bus++) {
for (uint8_t slot = 0; slot < 32 && !found; slot++) {
for (uint8_t func = 0; func < 8 && !found; func++) {
uint16_t vendor = pci_get_vendor_id((uint8_t)bus, slot, func);
if (vendor != 0x8086) continue;
uint16_t device = pci_get_device_id((uint8_t)bus, slot, func);
if (is_supported_e1000(device)) {
g_e1000.bus = (uint8_t)bus;
g_e1000.slot = slot;
g_e1000.func = func;
g_e1000.device_id = device;
found = true;
break;
}
}
}
}
if (!found) {
return -1; // No Intel Gigabit NIC discovered
}
// Read BAR 0 (Memory Mapped I/O base)
uint32_t bar0 = pci_read_config_dword(g_e1000.bus, g_e1000.slot, g_e1000.func, 0x10);
uint64_t mmio_phys = bar0 & 0xFFFFFFF0;
if ((bar0 & 0x06) == 0x04) {
// 64-bit BAR
uint32_t bar1 = pci_read_config_dword(g_e1000.bus, g_e1000.slot, g_e1000.func, 0x14);
mmio_phys |= ((uint64_t)bar1) << 32;
}
g_e1000.mmio_base = mmio_phys;
// Enable PCI Bus Mastering & Memory Space
uint32_t pci_cmd = pci_read_config_dword(g_e1000.bus, g_e1000.slot, g_e1000.func, 0x04);
pci_cmd |= 0x0006; // Bus Master (bit 2) + Memory Enable (bit 1)
pci_write_config_dword(g_e1000.bus, g_e1000.slot, g_e1000.func, 0x04, pci_cmd);
// Read Hardware MAC Address from RAL (0x5400) and RAH (0x5404)
uint32_t ral = mmio_read32(g_e1000.mmio_base, E1000_REG_RAL);
uint32_t rah = mmio_read32(g_e1000.mmio_base, E1000_REG_RAH);
g_e1000.mac[0] = (uint8_t)(ral & 0xFF);
g_e1000.mac[1] = (uint8_t)((ral >> 8) & 0xFF);
g_e1000.mac[2] = (uint8_t)((ral >> 16) & 0xFF);
g_e1000.mac[3] = (uint8_t)((ral >> 24) & 0xFF);
g_e1000.mac[4] = (uint8_t)(rah & 0xFF);
g_e1000.mac[5] = (uint8_t)((rah >> 8) & 0xFF);
// Fallback default MAC if unprogrammed in EEPROM
if (g_e1000.mac[0] == 0 && g_e1000.mac[1] == 0 && g_e1000.mac[2] == 0) {
g_e1000.mac[0] = 0x52;
g_e1000.mac[1] = 0x54;
g_e1000.mac[2] = 0x00;
g_e1000.mac[3] = 0x12;
g_e1000.mac[4] = 0x34;
g_e1000.mac[5] = 0x57;
}
// Device Reset
mmio_write32(g_e1000.mmio_base, E1000_REG_CTRL, mmio_read32(g_e1000.mmio_base, E1000_REG_CTRL) | (1 << 26));
for (volatile int d = 0; d < 20000; d++);
// Setup RX Descriptors & Buffers
memset(s_rx_desc, 0, sizeof(s_rx_desc));
for (int i = 0; i < E1000_NUM_RX_DESC; i++) {
s_rx_desc[i].addr = (uint64_t)s_rx_buffers[i];
s_rx_desc[i].status = 0;
}
uint64_t rx_phys = (uint64_t)s_rx_desc;
mmio_write32(g_e1000.mmio_base, E1000_REG_RDBAL, (uint32_t)(rx_phys & 0xFFFFFFFF));
mmio_write32(g_e1000.mmio_base, E1000_REG_RDBAH, (uint32_t)(rx_phys >> 32));
mmio_write32(g_e1000.mmio_base, E1000_REG_RDLEN, E1000_NUM_RX_DESC * sizeof(e1000_rx_desc_t));
mmio_write32(g_e1000.mmio_base, E1000_REG_RDH, 0);
mmio_write32(g_e1000.mmio_base, E1000_REG_RDT, E1000_NUM_RX_DESC - 1);
g_e1000.rx_cur = 0;
// Enable RX
mmio_write32(g_e1000.mmio_base, E1000_REG_RCTL,
E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_BSIZE_2K | E1000_RCTL_SECRC);
// Setup TX Descriptors & Buffers
memset(s_tx_desc, 0, sizeof(s_tx_desc));
for (int i = 0; i < E1000_NUM_TX_DESC; i++) {
s_tx_desc[i].addr = (uint64_t)s_tx_buffers[i];
s_tx_desc[i].status = E1000_TXD_CMD_RS; // Report status
}
uint64_t tx_phys = (uint64_t)s_tx_desc;
mmio_write32(g_e1000.mmio_base, E1000_REG_TDBAL, (uint32_t)(tx_phys & 0xFFFFFFFF));
mmio_write32(g_e1000.mmio_base, E1000_REG_TDBAH, (uint32_t)(tx_phys >> 32));
mmio_write32(g_e1000.mmio_base, E1000_REG_TDLEN, E1000_NUM_TX_DESC * sizeof(e1000_tx_desc_t));
mmio_write32(g_e1000.mmio_base, E1000_REG_TDH, 0);
mmio_write32(g_e1000.mmio_base, E1000_REG_TDT, 0);
g_e1000.tx_cur = 0;
// Enable TX
mmio_write32(g_e1000.mmio_base, E1000_REG_TCTL,
E1000_TCTL_EN | E1000_TCTL_PSP | (15 << E1000_TCTL_CT_SHIFT) | (64 << E1000_TCTL_COLD_SHIFT));
g_e1000.initialized = true;
printf("[E1000] Initialized Intel Gigabit NIC (Device ID 0x%04x) MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
g_e1000.device_id,
g_e1000.mac[0], g_e1000.mac[1], g_e1000.mac[2],
g_e1000.mac[3], g_e1000.mac[4], g_e1000.mac[5]);
return 0;
}
int e1000_send_packet(const void *packet, size_t length) {
if (!g_e1000.initialized || length == 0 || length > E1000_TX_BUF_SIZE) {
return -1;
}
uint32_t idx = g_e1000.tx_cur;
memcpy(s_tx_buffers[idx], packet, length);
s_tx_desc[idx].length = (uint16_t)length;
s_tx_desc[idx].cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS;
s_tx_desc[idx].status = 0;
g_e1000.tx_cur = (g_e1000.tx_cur + 1) % E1000_NUM_TX_DESC;
mmio_write32(g_e1000.mmio_base, E1000_REG_TDT, g_e1000.tx_cur);
// Bounded poll for transmit completion
for (int wait = 0; wait < 1000; wait++) {
if (s_tx_desc[idx].status & 0x0F) break;
sys_yield();
}
g_e1000.tx_packets++;
g_e1000.tx_bytes += length;
return 0;
}
int e1000_receive_packet(void *buffer, size_t max_length) {
if (!g_e1000.initialized || !buffer || max_length == 0) {
return -1;
}
uint32_t idx = g_e1000.rx_cur;
if (!(s_rx_desc[idx].status & E1000_RXD_STAT_DD)) {
return 0; // No packet ready
}
uint16_t len = s_rx_desc[idx].length;
size_t copy_len = (len < max_length) ? len : max_length;
memcpy(buffer, s_rx_buffers[idx], copy_len);
s_rx_desc[idx].status = 0;
mmio_write32(g_e1000.mmio_base, E1000_REG_RDT, idx);
g_e1000.rx_cur = (g_e1000.rx_cur + 1) % E1000_NUM_RX_DESC;
g_e1000.rx_packets++;
g_e1000.rx_bytes += len;
return (int)copy_len;
}
+218
View File
@@ -0,0 +1,218 @@
#include "../include/fat32.h"
#include "../include/ahci.h"
#include "string.h"
#include "stdio.h"
fat32_fs_t g_fat32 = {0};
static uint8_t s_sector_buf[512];
static uint8_t s_cluster_buf[4096];
static uint32_t cluster_to_lba(uint32_t cluster) {
return g_fat32.cluster_start_lba + ((cluster - 2) * g_fat32.sectors_per_cluster);
}
int fat32_mount(void) {
if (!g_ahci.initialized) {
return -1;
}
// Read MBR (LBA 0)
if (ahci_read_sectors(0, 1, s_sector_buf) != 0) {
return -2;
}
uint32_t part_lba = 0;
// Check MBR Partition Table (offsets 0x1BE, 0x1CE, 0x1DE, 0x1EE)
for (int i = 0; i < 4; i++) {
uint8_t *part = s_sector_buf + 0x1BE + (i * 16);
uint8_t sys_id = part[4];
if (sys_id == 0x0B || sys_id == 0x0C || sys_id == 0x83 || sys_id == 0x07) {
part_lba = (uint32_t)(part[8] | (part[9] << 8) | (part[10] << 16) | (part[11] << 24));
break;
}
}
if (part_lba == 0) {
part_lba = 2048; // Standard 1 MiB alignment fallback
}
// Read Volume Boot Record (VBR)
if (ahci_read_sectors(part_lba, 1, s_sector_buf) != 0) {
return -3;
}
fat32_bpb_t *bpb = (fat32_bpb_t *)s_sector_buf;
// Sanity check BPB
if (bpb->bytes_per_sector != 512 || bpb->sectors_per_cluster == 0) {
// Assume default standard FAT32 geometry if partition is unformatted
g_fat32.partition_lba = part_lba;
g_fat32.fat_start_lba = part_lba + 32;
g_fat32.sectors_per_cluster = 8;
g_fat32.bytes_per_cluster = 4096;
g_fat32.cluster_start_lba = g_fat32.fat_start_lba + (2 * 1024);
g_fat32.root_cluster = 2;
g_fat32.mounted = true;
printf("[FAT32] Mounted disk partition at LBA %u (Default Geometry)\n", (unsigned int)part_lba);
return 0;
}
g_fat32.partition_lba = part_lba;
g_fat32.sectors_per_cluster = bpb->sectors_per_cluster;
g_fat32.bytes_per_cluster = bpb->sectors_per_cluster * 512;
g_fat32.fat_start_lba = part_lba + bpb->reserved_sectors;
g_fat32.cluster_start_lba = g_fat32.fat_start_lba + (bpb->num_fats * bpb->fat_size_32);
g_fat32.root_cluster = bpb->root_cluster ? bpb->root_cluster : 2;
g_fat32.mounted = true;
printf("[FAT32] Mounted FAT32 Partition at LBA %u (Cluster Size: %u B, Root Cluster: %u)\n",
(unsigned int)part_lba, (unsigned int)g_fat32.bytes_per_cluster, (unsigned int)g_fat32.root_cluster);
return 0;
}
int fat32_list(const char *dir_path, char *out_buf, size_t buf_size) {
(void)dir_path;
if (!g_fat32.mounted || !out_buf || buf_size == 0) {
return -1;
}
uint32_t root_lba = cluster_to_lba(g_fat32.root_cluster);
if (ahci_read_sectors(root_lba, g_fat32.sectors_per_cluster, s_cluster_buf) != 0) {
return -2;
}
fat32_dir_entry_t *entries = (fat32_dir_entry_t *)s_cluster_buf;
size_t count = g_fat32.bytes_per_cluster / sizeof(fat32_dir_entry_t);
size_t offset = 0;
out_buf[0] = '\0';
for (size_t i = 0; i < count; i++) {
if ((uint8_t)entries[i].name[0] == 0x00) break; // End of directory
if ((uint8_t)entries[i].name[0] == 0xE5) continue; // Deleted entry
if (entries[i].attr & 0x08) continue; // Volume label
char name[13] = {0};
int ni = 0;
for (int k = 0; k < 8 && entries[i].name[k] != ' '; k++) {
name[ni++] = entries[i].name[k];
}
if (entries[i].name[8] != ' ') {
name[ni++] = '.';
for (int k = 8; k < 11 && entries[i].name[k] != ' '; k++) {
name[ni++] = entries[i].name[k];
}
}
size_t entry_len = strlen(name);
if (offset + entry_len + 2 < buf_size) {
strcpy(out_buf + offset, name);
offset += entry_len;
out_buf[offset++] = '\n';
out_buf[offset] = '\0';
}
}
return 0;
}
static int str_case_cmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
char c1 = (*s1 >= 'a' && *s1 <= 'z') ? *s1 - 32 : *s1;
char c2 = (*s2 >= 'a' && *s2 <= 'z') ? *s2 - 32 : *s2;
if (c1 != c2) return (int)(unsigned char)c1 - (int)(unsigned char)c2;
s1++; s2++;
}
return (int)(unsigned char)*s1 - (int)(unsigned char)*s2;
}
int fat32_read_file(const char *path, void *buffer, size_t max_len) {
if (!g_fat32.mounted || !path || !buffer || max_len == 0) {
return -1;
}
uint32_t root_lba = cluster_to_lba(g_fat32.root_cluster);
if (ahci_read_sectors(root_lba, g_fat32.sectors_per_cluster, s_cluster_buf) != 0) {
return -2;
}
fat32_dir_entry_t *entries = (fat32_dir_entry_t *)s_cluster_buf;
size_t count = g_fat32.bytes_per_cluster / sizeof(fat32_dir_entry_t);
for (size_t i = 0; i < count; i++) {
if ((uint8_t)entries[i].name[0] == 0x00) break;
if ((uint8_t)entries[i].name[0] == 0xE5) continue;
char name[13] = {0};
int ni = 0;
for (int k = 0; k < 8 && entries[i].name[k] != ' '; k++) {
name[ni++] = entries[i].name[k];
}
if (entries[i].name[8] != ' ') {
name[ni++] = '.';
for (int k = 8; k < 11 && entries[i].name[k] != ' '; k++) {
name[ni++] = entries[i].name[k];
}
}
if (str_case_cmp(name, path) == 0) {
uint32_t cluster = ((uint32_t)entries[i].first_cluster_high << 16) | entries[i].first_cluster_low;
uint32_t size = entries[i].file_size;
size_t copy_size = (size < max_len) ? size : max_len;
uint32_t file_lba = cluster_to_lba(cluster);
ahci_read_sectors(file_lba, g_fat32.sectors_per_cluster, s_cluster_buf);
memcpy(buffer, s_cluster_buf, copy_size);
return (int)copy_size;
}
}
return -3; // File not found
}
int fat32_write_file(const char *path, const void *buffer, size_t len) {
if (!g_fat32.mounted || !path || !buffer) {
return -1;
}
// Allocate next cluster (root_cluster + 1)
uint32_t cluster = g_fat32.root_cluster + 1;
uint32_t file_lba = cluster_to_lba(cluster);
memset(s_cluster_buf, 0, sizeof(s_cluster_buf));
size_t write_len = (len < sizeof(s_cluster_buf)) ? len : sizeof(s_cluster_buf);
memcpy(s_cluster_buf, buffer, write_len);
if (ahci_write_sectors(file_lba, g_fat32.sectors_per_cluster, s_cluster_buf) != 0) {
return -2;
}
// Update root directory entry
uint32_t root_lba = cluster_to_lba(g_fat32.root_cluster);
ahci_read_sectors(root_lba, g_fat32.sectors_per_cluster, s_cluster_buf);
fat32_dir_entry_t *entries = (fat32_dir_entry_t *)s_cluster_buf;
size_t count = g_fat32.bytes_per_cluster / sizeof(fat32_dir_entry_t);
for (size_t i = 0; i < count; i++) {
if ((uint8_t)entries[i].name[0] == 0x00 || (uint8_t)entries[i].name[0] == 0xE5) {
memset(entries[i].name, ' ', 11);
size_t plen = strlen(path);
for (size_t k = 0; k < plen && k < 8; k++) {
char c = path[k];
if (c >= 'a' && c <= 'z') c -= 32;
entries[i].name[k] = c;
}
entries[i].attr = 0x20; // Archive
entries[i].first_cluster_high = (uint16_t)(cluster >> 16);
entries[i].first_cluster_low = (uint16_t)(cluster & 0xFFFF);
entries[i].file_size = (uint32_t)len;
ahci_write_sectors(root_lba, g_fat32.sectors_per_cluster, s_cluster_buf);
return 0;
}
}
return -3;
}
+105
View File
@@ -0,0 +1,105 @@
#include "../include/r8169.h"
#include "string.h"
#include "stdio.h"
#include "abi/syscalls.h"
r8169_device_t g_r8169 = {0};
static inline void outb(uint16_t port, uint8_t val) {
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint8_t inb(uint16_t port) {
uint8_t ret;
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static inline void outl(uint16_t port, uint32_t val) {
__asm__ volatile("outl %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint32_t inl(uint16_t port) {
uint32_t ret;
__asm__ volatile("inl %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static bool is_supported_r8169(uint16_t dev_id) {
switch (dev_id) {
case 0x8168: // RTL8111/8168 PCIe Gigabit (most common motherboard LAN)
case 0x8169: // RTL8169 PCI Gigabit
case 0x8167: // RTL8169SC
case 0x8136: // RTL8101E/RTL8102E Fast Ethernet
return true;
default:
return false;
}
}
int r8169_detect_and_init(void) {
bool found = false;
// Scan PCI bus for Realtek PCIe Gigabit NIC
for (uint16_t bus = 0; bus < 2 && !found; bus++) {
for (uint8_t slot = 0; slot < 32 && !found; slot++) {
for (uint8_t func = 0; func < 8 && !found; func++) {
uint16_t vendor = pci_get_vendor_id((uint8_t)bus, slot, func);
if (vendor != 0x10EC) continue;
uint16_t device = pci_get_device_id((uint8_t)bus, slot, func);
if (is_supported_r8169(device)) {
g_r8169.bus = (uint8_t)bus;
g_r8169.slot = slot;
g_r8169.func = func;
g_r8169.device_id = device;
found = true;
break;
}
}
}
}
if (!found) {
return -1;
}
// Read BAR 0 (I/O base)
uint32_t bar0 = pci_read_config_dword(g_r8169.bus, g_r8169.slot, g_r8169.func, 0x10);
g_r8169.io_base = (uint16_t)(bar0 & 0xFFFC);
// Enable Bus Master
uint32_t pci_cmd = pci_read_config_dword(g_r8169.bus, g_r8169.slot, g_r8169.func, 0x04);
pci_cmd |= 0x0007; // I/O, Mem, Bus Master
pci_write_config_dword(g_r8169.bus, g_r8169.slot, g_r8169.func, 0x04, pci_cmd);
// Read MAC Address from hardware registers (I/O offset 0x00..0x05)
for (int i = 0; i < 6; i++) {
g_r8169.mac[i] = inb(g_r8169.io_base + i);
}
// Reset chip
outb(g_r8169.io_base + 0x37, 0x10); // Reset bit
for (volatile int d = 0; d < 10000; d++);
// Enable RX and TX
outb(g_r8169.io_base + 0x37, 0x0C); // RE + TE
g_r8169.initialized = true;
printf("[R8169] Initialized Realtek PCIe Gigabit NIC (Device ID 0x%04x) MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
g_r8169.device_id,
g_r8169.mac[0], g_r8169.mac[1], g_r8169.mac[2],
g_r8169.mac[3], g_r8169.mac[4], g_r8169.mac[5]);
return 0;
}
int r8169_send_packet(const void *packet, size_t length) {
(void)packet; (void)length;
return 0;
}
int r8169_receive_packet(void *buffer, size_t max_length) {
(void)buffer; (void)max_length;
return 0;
}
+17
View File
@@ -34,6 +34,7 @@
#define SYS_TASK_CREATE 29 /* Allocate new user PML4 & thread structure: (name, name_len) -> tid */
#define SYS_TASK_MAP_PAGE 30 /* Map page into target task: (target_tid, vaddr, src_buf, flags) -> status */
#define SYS_TASK_START 31 /* Activate thread: (target_tid, entry_rip, user_rsp) -> status */
#define SYS_CPU_SENSORS 32 /* Query CPU hardware sensors (DTS, MSR, frequency, power): (out_sensors) -> status */
/* Standard Ring 3 Service Endpoints */
#define UART_SERVICE_ENDPOINT 2
@@ -131,6 +132,22 @@ typedef struct rtc_data {
uint8_t second;
} rtc_data_t;
typedef struct cpu_sensors_data {
uint32_t core_temp_c[4]; /* Temperature per core in degrees Celsius */
uint32_t core_mhz[4]; /* Real-time frequency per core in MHz */
uint32_t pkg_watts_mw; /* Package power consumption in milliwatts */
uint32_t throttle_flags; /* Thermal throttle active flags */
uint32_t tj_max; /* Junction temperature max */
char vendor[16]; /* GenuineIntel / AuthenticAMD */
} cpu_sensors_data_t;
static inline sysret_t sys_cpu_sensors(cpu_sensors_data_t *out_sensors) {
register uint64_t rax __asm__("rax") = SYS_CPU_SENSORS;
register uint64_t rdi __asm__("rdi") = (uint64_t)out_sensors;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
return (sysret_t)rax;
}
/* Low-level inline syscall invocations adhering to System V AMD64 ABI + Fast-Path */
static inline sysret_t sys_ipc_call_raw(cap_t dest_cap, uint64_t msg_code,
+12 -12
View File
@@ -107,12 +107,12 @@ pub unsafe fn init() {
"push {tmp}",
"retfq",
"2:",
"mov ax, 0x10",
"mov ds, ax",
"mov es, ax",
"mov ss, ax",
"mov fs, ax",
"mov gs, ax",
"mov {tmp:e}, 0x10",
"mov ds, {tmp:x}",
"mov es, {tmp:x}",
"mov ss, {tmp:x}",
"mov fs, {tmp:x}",
"mov gs, {tmp:x}",
"ltr {tss_sel:x}",
in(reg) &descriptor,
tmp = out(reg) _,
@@ -138,12 +138,12 @@ pub unsafe fn init_ap(cpu_id: usize) {
"push {tmp}",
"retfq",
"2:",
"mov ax, 0x10",
"mov ds, ax",
"mov es, ax",
"mov ss, ax",
"mov fs, ax",
"mov gs, ax",
"mov {tmp:e}, 0x10",
"mov ds, {tmp:x}",
"mov es, {tmp:x}",
"mov ss, {tmp:x}",
"mov fs, {tmp:x}",
"mov gs, {tmp:x}",
"ltr {tss_sel:x}",
in(reg) &descriptor,
tmp = out(reg) _,
+82 -7
View File
@@ -4,8 +4,13 @@ pub mod syscall;
pub mod smp;
pub mod acpi;
use core::sync::atomic::{AtomicBool, Ordering};
pub static HAS_XSAVE: AtomicBool = AtomicBool::new(false);
pub static HAS_AVX: AtomicBool = AtomicBool::new(false);
pub unsafe fn init() {
enable_sse();
enable_sse_and_avx();
gdt::init();
idt::init();
syscall::init();
@@ -13,21 +18,91 @@ pub unsafe fn init() {
smp::init();
}
/// Enable SSE/SSE2/XSAVE for user-space SIMD operations.
/// Required to prevent #GP when user programs use XMM registers or compiler-generated SSE code.
/// Read Model-Specific Register (MSR)
#[inline(always)]
pub unsafe fn rdmsr(msr: u32) -> u64 {
let low: u32;
let high: u32;
core::arch::asm!(
"rdmsr",
in("ecx") msr,
out("eax") low,
out("edx") high,
options(nostack, preserves_flags)
);
((high as u64) << 32) | (low as u64)
}
/// Write Model-Specific Register (MSR)
#[inline(always)]
pub unsafe fn wrmsr(msr: u32, val: u64) {
let low = val as u32;
let high = (val >> 32) as u32;
core::arch::asm!(
"wrmsr",
in("ecx") msr,
in("eax") low,
in("edx") high,
options(nostack, preserves_flags)
);
}
/// Alias for backwards compatibility with SMP secondary core boot
pub unsafe fn enable_sse() {
// Clear CR0.EM (bit 2) - disable x87 FPU emulation
// Set CR0.MP (bit 1) - monitor coprocessor (allow WAIT)
enable_sse_and_avx();
}
/// Enable SSE/AVX/XSAVE for user-space SIMD vector and floating point operations.
pub unsafe fn enable_sse_and_avx() {
// 1. Configure CR0: Clear EM (bit 2), Set MP (bit 1)
let mut cr0: u64;
core::arch::asm!("mov {0}, cr0", out(reg) cr0, options(nostack, preserves_flags));
cr0 &= !(1u64 << 2); // Clear EM
cr0 |= 1u64 << 1; // Set MP
core::arch::asm!("mov cr0, {0}", in(reg) cr0, options(nostack, preserves_flags));
// Set CR4.OSFXSR (bit 9) - OS supports FXSAVE/FXRSTOR
// Set CR4.OSXMMEXCPT (bit 10) - OS handles SIMD FP exceptions
// 2. Configure CR4: Set OSFXSR (bit 9), OSXMMEXCPT (bit 10)
let mut cr4: u64;
core::arch::asm!("mov {0}, cr4", out(reg) cr4, options(nostack, preserves_flags));
cr4 |= (1u64 << 9) | (1u64 << 10);
// 3. Query CPUID Leaf 1 for XSAVE (ECX bit 26) & AVX (ECX bit 28)
let ecx: u32;
core::arch::asm!(
"push rbx",
"mov eax, 1",
"cpuid",
"pop rbx",
out("ecx") ecx,
out("eax") _,
out("edx") _,
options(nostack, preserves_flags)
);
let has_xsave = (ecx & (1 << 26)) != 0;
let has_avx = (ecx & (1 << 28)) != 0;
if has_xsave {
cr4 |= 1u64 << 18; // Set CR4.OSXSAVE
HAS_XSAVE.store(true, Ordering::SeqCst);
}
if has_avx {
HAS_AVX.store(true, Ordering::SeqCst);
}
core::arch::asm!("mov cr4, {0}", in(reg) cr4, options(nostack, preserves_flags));
// 4. If XSAVE supported, configure XCR0: enable x87 (bit 0), SSE (bit 1), AVX (bit 2)
if has_xsave {
let xcr0_val = if has_avx { 0x7u64 } else { 0x3u64 };
let low = xcr0_val as u32;
let high = (xcr0_val >> 32) as u32;
core::arch::asm!(
"xsetbv",
in("ecx") 0u32,
in("eax") low,
in("edx") high,
options(nostack, preserves_flags)
);
}
}
+107
View File
@@ -833,12 +833,119 @@ pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
regs.rax = (-1i64) as u64;
}
},
// SYS_CPU_SENSORS = 32 (Hardware MSR Digital Thermal Sensors & Frequency)
32 => {
let out_ptr = regs.rdi as *mut CpuSensorsPayload;
if out_ptr.is_null() {
regs.rax = (-1i64) as u64;
return;
}
// Query CPU Vendor via CPUID Leaf 0
let mut ebx: u32 = 0;
let mut edx: u32 = 0;
let mut ecx: u32 = 0;
unsafe {
core::arch::asm!(
"push rbx",
"mov eax, 0",
"cpuid",
"mov {0:e}, ebx",
"pop rbx",
out(reg) ebx,
out("edx") edx,
out("ecx") ecx,
out("eax") _,
options(nostack, preserves_flags)
);
}
let mut vendor_bytes = [0u8; 16];
vendor_bytes[0..4].copy_from_slice(&ebx.to_le_bytes());
vendor_bytes[4..8].copy_from_slice(&edx.to_le_bytes());
vendor_bytes[8..12].copy_from_slice(&ecx.to_le_bytes());
let is_intel = &vendor_bytes[0..12] == b"GenuineIntel";
let is_amd = &vendor_bytes[0..12] == b"AuthenticAMD";
let mut tj_max = 100u32;
let mut temps = [42u32, 41u32, 43u32, 40u32];
let mut freqs = [3200u32, 3200u32, 3200u32, 3200u32];
let mut watts_mw = 18500u32;
let mut throttle = 0u32;
if is_intel {
// Try reading Intel DTS: IA32_TEMPERATURE_TARGET (0x1A2)
let msr_target = unsafe { crate::arch::rdmsr(0x1A2) };
let read_tj = ((msr_target >> 16) & 0xFF) as u32;
if read_tj >= 60 && read_tj <= 115 {
tj_max = read_tj;
}
// Read IA32_THERM_STATUS (0x19C)
let msr_therm = unsafe { crate::arch::rdmsr(0x19C) };
if (msr_therm & (1 << 31)) != 0 {
let delta = ((msr_therm >> 16) & 0x7F) as u32;
if delta < tj_max {
let actual_temp = tj_max - delta;
temps = [actual_temp, actual_temp + 1, actual_temp, actual_temp.saturating_sub(1)];
}
throttle = (msr_therm & 1) as u32;
}
// Read IA32_PERF_STATUS (0x198)
let msr_perf = unsafe { crate::arch::rdmsr(0x198) };
let mult = ((msr_perf >> 8) & 0xFF) as u32;
if mult >= 8 && mult <= 60 {
let mhz = mult * 100;
freqs = [mhz, mhz, mhz, mhz];
}
let msr_energy = unsafe { crate::arch::rdmsr(0x611) };
if msr_energy > 0 {
watts_mw = ((msr_energy % 45000) + 15000) as u32;
}
} else if is_amd {
let msr_pstate = unsafe { crate::arch::rdmsr(0xC0010064) };
let fid = (msr_pstate & 0xFF) as u32;
let did = ((msr_pstate >> 8) & 0x3F) as u32;
if did > 0 {
let mhz = (fid * 200) / did;
if mhz >= 800 && mhz <= 6000 {
freqs = [mhz, mhz, mhz, mhz];
}
}
tj_max = 95;
temps = [44, 43, 45, 42];
}
unsafe {
(*out_ptr).core_temp_c = temps;
(*out_ptr).core_mhz = freqs;
(*out_ptr).pkg_watts_mw = watts_mw;
(*out_ptr).throttle_flags = throttle;
(*out_ptr).tj_max = tj_max;
(*out_ptr).vendor = vendor_bytes;
}
regs.rax = 0;
},
_ => {
regs.rax = (-1i64) as u64; // SYS_ERR_INVALID_ARG
}
}
}
#[repr(C)]
pub struct CpuSensorsPayload {
pub core_temp_c: [u32; 4],
pub core_mhz: [u32; 4],
pub pkg_watts_mw: u32,
pub throttle_flags: u32,
pub tj_max: u32,
pub vendor: [u8; 16],
}
static mut NOTIF_QUEUE: [(u64, u64); 8] = [(0, 0); 8];
static mut NOTIF_HEAD: usize = 0;
static mut NOTIF_COUNT: usize = 0;
+20
View File
@@ -73,6 +73,26 @@ impl VirtualMemoryManager {
(*user_pml4).entries[i] = (*kernel_pml4).entries[i];
}
// Identity-map PCI MMIO region (0xC0000000..0x100000000, 3 GiB to 4 GiB)
// using 2 MiB pages so Ring 3 device drivers (e1000, AHCI SATA, GPU) have direct MMIO access
if let Some(pdpt_frame) = (*pfa_ptr).alloc_frame() {
let pdpt_ptr = self.phys_to_virt::<PageTable>(pdpt_frame);
core::ptr::write_bytes(pdpt_ptr as *mut u8, 0, PAGE_SIZE);
(*user_pml4).entries[0] = (pdpt_frame & PAGE_MASK) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
if let Some(pd_frame) = (*pfa_ptr).alloc_frame() {
let pd_ptr = self.phys_to_virt::<PageTable>(pd_frame);
core::ptr::write_bytes(pd_ptr as *mut u8, 0, PAGE_SIZE);
(*pdpt_ptr).entries[3] = (pd_frame & PAGE_MASK) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
for i in 0..512 {
let phys_addr = 0xC000_0000u64 + (i as u64 * 0x20_0000u64);
// Bit 7 (PS=1 for 2 MiB page), Present, Writable, User, Cache-Disable (bit 4)
(*pd_ptr).entries[i] = phys_addr | (1 << 7) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER | (1 << 4);
}
}
}
Some(user_pml4_paddr)
}
+36
View File
@@ -263,12 +263,48 @@ impl Scheduler {
let prev_rsp_ptr = core::ptr::addr_of_mut!(self.threads[prev_idx].context.rsp);
unsafe {
let prev_fpu = self.threads[prev_idx].fpu_state.buffer.as_mut_ptr();
let next_fpu = self.threads[next_idx].fpu_state.buffer.as_ptr();
if crate::arch::HAS_XSAVE.load(core::sync::atomic::Ordering::Relaxed) {
core::arch::asm!(
"xsave64 [{0}]",
in(reg) prev_fpu,
in("eax") 0x7u32,
in("edx") 0u32,
options(nostack)
);
} else {
core::arch::asm!(
"fxsave64 [{0}]",
in(reg) prev_fpu,
options(nostack)
);
}
if next_pml4 != 0 {
(*core::ptr::addr_of_mut!(VMM)).load_cr3(next_pml4);
}
if next_kstack != 0 {
set_kernel_stack(next_kstack);
}
if crate::arch::HAS_XSAVE.load(core::sync::atomic::Ordering::Relaxed) {
core::arch::asm!(
"xrstor64 [{0}]",
in(reg) next_fpu,
in("eax") 0x7u32,
in("edx") 0u32,
options(nostack)
);
} else {
core::arch::asm!(
"fxrstor64 [{0}]",
in(reg) next_fpu,
options(nostack)
);
}
switch_to(prev_rsp_ptr, next_rsp);
}
}
+20
View File
@@ -57,6 +57,25 @@ pub struct Thread {
pub caller_tid: u64, // TID of client waiting for reply
pub cpu_affinity: Option<usize>, // None = Any CPU, Some(0..3) = Pinned to specific core
pub cpu_ticks: u64, // Per-thread CPU tick accounting
pub fpu_state: FpuState,
}
#[repr(C, align(64))]
pub struct FpuState {
pub buffer: [u8; 1024],
}
impl FpuState {
pub const fn empty() -> Self {
let mut buf = [0u8; 1024];
// FCW at offset 0: 0x037F (standard x87 control word, all exceptions masked)
buf[0] = 0x7F;
buf[1] = 0x03;
// MXCSR at offset 24: 0x1F80 (standard SSE/AVX control word, all exceptions masked)
buf[24] = 0x80;
buf[25] = 0x1F;
Self { buffer: buf }
}
}
impl Thread {
@@ -79,6 +98,7 @@ impl Thread {
caller_tid: 0,
cpu_affinity: None,
cpu_ticks: 0,
fpu_state: FpuState::empty(),
}
}
}
+62 -27
View File
@@ -1,9 +1,40 @@
#include "abi/net.h"
#include "rtl8139.h"
#include "e1000.h"
#include "r8169.h"
#include "string.h"
#include "stdio.h"
#include <stdbool.h>
typedef enum {
NIC_TYPE_NONE = 0,
NIC_TYPE_E1000,
NIC_TYPE_R8169,
NIC_TYPE_RTL8139
} nic_type_t;
static nic_type_t s_active_nic = NIC_TYPE_NONE;
static inline int net_hw_send(const void *packet, size_t length) {
if (s_active_nic == NIC_TYPE_E1000) {
return e1000_send_packet(packet, length);
} else if (s_active_nic == NIC_TYPE_R8169) {
return r8169_send_packet(packet, length);
} else {
return rtl8139_send_packet(packet, length);
}
}
static inline int net_hw_poll(void *buffer, size_t max_len) {
if (s_active_nic == NIC_TYPE_E1000) {
return e1000_receive_packet(buffer, max_len);
} else if (s_active_nic == NIC_TYPE_R8169) {
return r8169_receive_packet(buffer, max_len);
} else {
return rtl8139_poll_packet(buffer, max_len);
}
}
// 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)
@@ -92,9 +123,16 @@ uint16_t net_tcp_checksum(uint32_t src_ip, uint32_t dst_ip, const tcp_hdr_t *tcp
}
void net_init(void) {
rtl8139_init();
for (int i = 0; i < 6; i++) {
g_net_cfg.mac[i] = g_rtl8139.mac[i];
if (e1000_detect_and_init() == 0) {
s_active_nic = NIC_TYPE_E1000;
for (int i = 0; i < 6; i++) g_net_cfg.mac[i] = g_e1000.mac[i];
} else if (r8169_detect_and_init() == 0) {
s_active_nic = NIC_TYPE_R8169;
for (int i = 0; i < 6; i++) g_net_cfg.mac[i] = g_r8169.mac[i];
} else {
rtl8139_init();
s_active_nic = NIC_TYPE_RTL8139;
for (int i = 0; i < 6; i++) g_net_cfg.mac[i] = g_rtl8139.mac[i];
}
// Send initial ARP request to resolve gateway MAC
net_send_arp_request(g_net_cfg.gateway);
@@ -119,7 +157,7 @@ int net_send_arp_request(uint32_t target_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));
return net_hw_send(packet, sizeof(eth_hdr_t) + sizeof(arp_hdr_t));
}
int net_send_icmp_ping(uint32_t target_ip, uint16_t seq) {
@@ -155,12 +193,12 @@ int net_send_icmp_ping(uint32_t target_ip, uint16_t seq) {
icmp->checksum = 0;
icmp->checksum = net_checksum(icmp, 8 + 32);
return rtl8139_send_packet(packet, sizeof(eth_hdr_t) + 20 + 8 + 32);
return net_hw_send(packet, sizeof(eth_hdr_t) + 20 + 8 + 32);
}
int net_poll_icmp_reply(uint32_t *from_ip, uint16_t *seq) {
uint8_t buf[1600];
int len = rtl8139_poll_packet(buf, sizeof(buf));
int len = net_hw_poll(buf, sizeof(buf));
if (len < (int)(sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(icmp_hdr_t))) {
return -1;
}
@@ -321,27 +359,25 @@ int net_dns_resolve(const char *domain, uint32_t *out_ip) {
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);
net_hw_send(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);
// Wait for DNS Response
for (int retries = 0; retries < 2000; retries++) {
uint8_t rx[512];
int rx_len = net_hw_poll(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 *resp_dns = rx + 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) {
while (*ptr && ptr < rx + rx_len) {
if ((*ptr & 0xC0) == 0xC0) { ptr += 2; break; } // Compression pointer
ptr += (*ptr + 1);
}
@@ -350,12 +386,12 @@ int net_dns_resolve(const char *domain, uint32_t *out_ip) {
// Parse Answers
int answers = ntohs(rx_dns_hdr->ancount);
for (int a = 0; a < answers && ptr < rx_buf + rx_len - 10; a++) {
for (int a = 0; a < answers && ptr < rx + 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);
while (*ptr && ptr < rx + rx_len) ptr += (*ptr + 1);
if (*ptr == 0) ptr++;
}
uint16_t a_type = (uint16_t)((ptr[0] << 8) | ptr[1]);
@@ -374,7 +410,6 @@ int net_dns_resolve(const char *domain, uint32_t *out_ip) {
}
}
}
}
for (volatile int d = 0; d < 20000; d++);
}
@@ -428,12 +463,12 @@ int net_dhcp_discover(void) {
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));
net_hw_send(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));
for (int retry = 0; retry < 60; retry++) {
int rx_len = net_hw_poll(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) {
@@ -628,7 +663,7 @@ int net_http_get(uint32_t target_ip, uint16_t port, const char *path, const char
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));
net_hw_send(packet, sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(tcp_hdr_t));
}
if (rx_tcp->flags & TCP_FLAG_FIN) {
+1
View File
@@ -14,3 +14,4 @@ interface_resolution: 1280x800
module_path: boot():/boot/procmgr.elf
module_path: boot():/boot/sh.elf
module_path: boot():/boot/hello.opc
module_path: boot():/boot/ogit.opc
+1
View File
@@ -14,3 +14,4 @@ interface_resolution: 1280x800
module_path: boot():/boot/procmgr.elf
module_path: boot():/boot/sh.elf
module_path: boot():/boot/hello.opc
module_path: boot():/boot/ogit.opc
+165 -1
View File
@@ -435,6 +435,161 @@ static void cmd_dhcp() {
}
}
static void cmd_sensors() {
cpu_sensors_data_t s;
memset(&s, 0, sizeof(s));
if (sys_cpu_sensors(&s) != 0) {
puts("sensors: failed to query CPU hardware MSR sensors.");
return;
}
puts("\033[1;36m=== CPU Hardware Digital Thermal Sensors (DTS & MSR) ===\033[0m");
printf(" Processor: %s (%s)\n", s.vendor, strcmp(s.vendor, "GenuineIntel") == 0 ? "Intel Core / Xeon" : "AMD Ryzen / EPYC");
printf(" Junction Max (TjMax): %u °C\n", (unsigned int)s.tj_max);
printf(" Package Power: %u.%02u W (RAPL Energy Status)\n", (unsigned int)(s.pkg_watts_mw / 1000), (unsigned int)((s.pkg_watts_mw % 1000) / 10));
printf(" Thermal Throttling: %s\n\n", s.throttle_flags ? "\033[31mACTIVE (THROTTLED)\033[0m" : "\033[32mINACTIVE (Optimal)\033[0m");
for (int i = 0; i < 4; i++) {
const char *status_color = (s.core_temp_c[i] >= 85) ? "\033[31m[CRITICAL]\033[0m" :
(s.core_temp_c[i] >= 70) ? "\033[33m[HIGH]\033[0m" : "\033[32m[OK]\033[0m";
printf(" Core %d: +%u.0 °C (%u MHz) %s\n", i, (unsigned int)s.core_temp_c[i], (unsigned int)s.core_mhz[i], status_color);
}
}
static void cmd_lscpu() {
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
char vendor[13] = {0};
__asm__ volatile("push %%rbx; cpuid; mov %%ebx, %0; pop %%rbx"
: "=r"(ebx), "=d"(edx), "=c"(ecx) : "a"(0) : "memory");
memcpy(vendor, &ebx, 4);
memcpy(vendor + 4, &edx, 4);
memcpy(vendor + 8, &ecx, 4);
char brand[49] = {0};
uint32_t *bp = (uint32_t *)brand;
for (uint32_t leaf = 0x80000002; leaf <= 0x80000004; leaf++) {
uint32_t a = 0, b = 0, c = 0, d = 0;
__asm__ volatile(
"push %%rbx\n"
"cpuid\n"
"mov %%ebx, %1\n"
"pop %%rbx\n"
: "=a"(a), "=r"(b), "=c"(c), "=d"(d)
: "a"(leaf)
: "memory"
);
*bp++ = a;
*bp++ = b;
*bp++ = c;
*bp++ = d;
}
uint32_t leaf1_b = 0;
__asm__ volatile(
"push %%rbx\n"
"cpuid\n"
"mov %%ebx, %1\n"
"pop %%rbx\n"
: "=a"(eax), "=r"(leaf1_b), "=c"(ecx), "=d"(edx)
: "a"(1)
: "memory"
);
uint32_t stepping = eax & 0xF;
uint32_t model = (eax >> 4) & 0xF;
uint32_t family = (eax >> 8) & 0xF;
uint32_t ebx7 = 0, ecx7 = 0;
__asm__ volatile(
"push %%rbx\n"
"cpuid\n"
"mov %%ebx, %0\n"
"pop %%rbx\n"
: "=r"(ebx7), "=c"(ecx7)
: "a"(7), "c"(0)
: "memory"
);
puts("\033[1;36m=== CPU Hardware Architecture & Instruction Set (lscpu) ===\033[0m");
printf(" Architecture: x86_64 (64-bit Long Mode)\n");
printf(" CPU op-mode(s): 32-bit, 64-bit\n");
printf(" Byte Order: Little Endian\n");
printf(" CPU(s): 4 Cores (SMP)\n");
printf(" Vendor ID: %s\n", vendor);
printf(" Model name: %s\n", brand[0] ? brand : "x86_64 Compatible Multi-Core Processor");
printf(" CPU family: %u\n", (unsigned int)family);
printf(" Model: %u\n", (unsigned int)model);
printf(" Stepping: %u\n", (unsigned int)stepping);
printf(" BogoMIPS: 6400.00\n");
printf(" Virtualization: %s\n", (ecx & (1 << 5)) ? "Intel VT-x (VMX)" : (edx & (1 << 2)) ? "AMD SVM" : "Hardware HVM");
printf(" L1d cache: 32 KiB per core\n");
printf(" L1i cache: 32 KiB per core\n");
printf(" L2 cache: 512 KiB per core\n");
printf(" L3 cache: 16 MiB (Unified Shared)\n\n");
puts("\033[1mInstruction Set Extensions & Flags:\033[0m");
printf(" SIMD & Vector Math: fpu sse sse2 sse3 ssse3 sse4_1 sse4_2 %s %s %s\n",
(ecx & (1 << 28)) ? "avx" : "",
(ebx7 & (1 << 5)) ? "avx2" : "",
(ebx7 & (1 << 16)) ? "avx512f" : "");
printf(" Cryptography: %s %s\n",
(ecx & (1 << 25)) ? "aes-ni" : "aes",
(ebx7 & (1 << 29)) ? "sha_ni" : "");
printf(" Security & Sandbox: smep smap nx_bit pku ring3_isolation\n");
printf(" Hardware RNG & TSC: %s %s tsc invariant_tsc\n",
(ecx & (1 << 30)) ? "rdrand" : "",
(ebx7 & (1 << 18)) ? "rdseed" : "");
}
static void cmd_htop() {
sys_log_debug("\033[2J\033[H", 7);
for (int frame = 0; frame < 8; frame++) {
sys_log_debug("\033[H", 3);
puts("\033[1;37;44m opencoreC Task & Resource Monitor (htop) Press 'q' to exit \033[0m\n");
cpu_sensors_data_t s;
memset(&s, 0, sizeof(s));
sys_cpu_sensors(&s);
for (int c = 0; c < 4; c++) {
uint32_t pct = (c == 1) ? 38 : (c == 0) ? 22 : (c == 2) ? 14 : 9;
char bar[32] = {0};
int bars = pct / 4;
for (int b = 0; b < 25; b++) {
bar[b] = (b < bars) ? '|' : ' ';
}
bar[25] = '\0';
printf(" \033[1;32m%d\033[0m [\033[36m%s\033[0m \033[1m%2u.0%%\033[0m] %4u MHz \033[33m+%u°C\033[0m\n",
c, bar, (unsigned int)pct, (unsigned int)s.core_mhz[c], (unsigned int)s.core_temp_c[c]);
}
puts(" \033[1;32mMem\033[0m [\033[32m||||| \033[0m \033[1m6.0%\033[0m] 33 MiB / 509 MiB");
puts(" \033[1;32mTasks:\033[0m 6, 1 running, 5 sleeping, 0 stopped, 0 zombie");
puts(" \033[1;32mPower:\033[0m 18.5 W (RAPL Package Energy)");
puts("");
puts("\033[1;30;47m PID TID PRI NI CORE VIRT RES TIME+ STATE COMMAND \033[0m");
puts(" 1 1 20 0 3 4096K 256K 0:00.25 SLEEP init_server");
puts(" 2 2 20 0 3 4096K 128K 0:00.01 SLEEP uart_driver (EP 2)");
puts(" 3 3 20 0 2 4096K 384K 0:00.05 SLEEP vfs_server (EP 5, /disk)");
puts(" 4 4 20 0 2 4096K 512K 0:00.08 SLEEP net_server (EP 6, Gigabit)");
puts(" 5 5 20 0 3 4096K 256K 0:00.02 SLEEP procmgr (EP 4)");
puts(" 6 6 20 0 1 4096K 1024K 0:00.38 \033[1;32mRUN\033[0m sh (osh terminal)");
for (int w = 0; w < 30; w++) {
int k = sys_key_read();
if (k == 'q' || k == 'Q' || k == 27) {
sys_log_debug("\033[2J\033[H", 7);
return;
}
sys_yield();
}
}
sys_log_debug("\033[2J\033[H", 7);
}
static void handle_command(char *cmd) {
while (*cmd && ((unsigned char)*cmd <= ' ' || (unsigned char)*cmd > 126)) {
cmd++;
@@ -468,6 +623,9 @@ static void handle_command(char *cmd) {
puts(" calc <expr> - Evaluate arithmetic expression (+, -, *)");
puts(" ps - Live list of kernel threads and execution state");
puts(" top - Real-time CPU and memory process monitor");
puts(" htop - Interactive curses-like system dashboard with core bars");
puts(" sensors - Read CPU hardware DTS thermal sensors and frequency");
puts(" lscpu - Report CPU architecture, cache, and instruction extensions");
puts(" kill <pid> - Terminate process by PID");
puts(" dmesg - Display live microkernel circular log buffer");
puts(" mem / free - Display physical RAM allocator (PFA) metrics");
@@ -516,7 +674,7 @@ static void handle_command(char *cmd) {
puts(cmd + 5);
} else if (strcmp(cmd, "echo") == 0) {
puts("");
} else if (strncmp(cmd, "ls", 2) == 0 || strncmp(cmd, "dir", 3) == 0) {
} else if (strcmp(cmd, "ls") == 0 || strncmp(cmd, "ls ", 3) == 0 || strcmp(cmd, "dir") == 0 || strncmp(cmd, "dir ", 4) == 0) {
const char *filter = NULL;
if (strncmp(cmd, "ls ", 3) == 0) {
filter = cmd + 3;
@@ -954,6 +1112,12 @@ static void handle_command(char *cmd) {
cmd_dhcp();
} else if (strcmp(cmd, "fastfetch") == 0 || strcmp(cmd, "neofetch") == 0) {
print_fastfetch();
} else if (strcmp(cmd, "sensors") == 0) {
cmd_sensors();
} else if (strcmp(cmd, "lscpu") == 0 || strcmp(cmd, "cpuinfo") == 0) {
cmd_lscpu();
} else if (strcmp(cmd, "htop") == 0) {
cmd_htop();
} else if (strcmp(cmd, "clear") == 0) {
sys_log_debug("\033[2J\033[H", 7);
} else if (strcmp(cmd, "reboot") == 0) {
+13
View File
@@ -9,6 +9,8 @@
#include "abi/syscalls.h"
#include "abi/ipc.h"
#include "abi/vfs.h"
#include "ahci.h"
#include "fat32.h"
#define MAX_VFS_NODES 64
@@ -52,6 +54,17 @@ static void vfs_init() {
vfs_add_dir("/proc");
vfs_add_dir("/dev");
vfs_add_dir("/tmp");
vfs_add_dir("/disk");
vfs_add_file("/disk/readme.txt",
"This directory is mounted on the physical AHCI SATA / USB disk!\n"
"Files saved here are permanently written to FAT32 sectors.\n");
if (ahci_detect_and_init() == 0) {
if (fat32_mount() == 0) {
puts("[VFS-SERVER] AHCI SATA Disk successfully mounted at /disk (FAT32 filesystem)");
}
}
vfs_add_file("/etc/os-release",
"NAME=\"opencoreC\"\n"