Compare commits
No commits in common. "master" and "main" have entirely different histories.
36 changed files with 129 additions and 595 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
build/
|
||||
*.o
|
||||
*.elf
|
||||
40
Makefile
40
Makefile
|
|
@ -1,20 +1,36 @@
|
|||
CROSS_COMPILE = arm-none-eabi-
|
||||
AS = $(CROSS_COMPILE)as
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
LD = $(CROSS_COMPILE)ld
|
||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
|
||||
CC=aarch64-linux-gnu-gcc
|
||||
LD=aarch64-linux-gnu-ld
|
||||
OBJCOPY=aarch64-linux-gnu-objcopy
|
||||
CFLAGS = -Wall -mcpu=arm926ej-s -nostdlib -ffreestanding -I.
|
||||
|
||||
CFLAGS=-ffreestanding -O2 -nostdlib -Wall
|
||||
LDFLAGS=-T link.ld
|
||||
|
||||
OBJS=startup.o kernel_main.o uart.o scheduler.o smp.o vfs.o shell.o emmc.o mmc_cmds.o profiler.o proc.o virtio_net_dma.o
|
||||
|
||||
all: kernel.elf
|
||||
.SUFFIXES: .s .o .c
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
kernel.elf: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -o $@ $(OBJS)
|
||||
%.o: %.s
|
||||
$(AS) -mcpu=arm926ej-s $< -o $@
|
||||
|
||||
ASM_S_FILES = $(wildcard system/asm/*.s)
|
||||
ASM_O_FILES = $(ASM_S_FILES:.s=.o)
|
||||
|
||||
CFILES = $(wildcard devices/*.c) $(wildcard devices/*/*.c) $(wildcard system/*.c) $(wildcard system/*/*.c)
|
||||
COFILES = $(CFILES:.c=.o)
|
||||
OFILES = $(ASM_O_FILES) $(COFILES)
|
||||
|
||||
all: kernel.bin
|
||||
|
||||
kernel.elf: ${OFILES}
|
||||
$(LD) -T boot.ld -o $@ $^
|
||||
|
||||
kernel.bin: kernel.elf
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
|
||||
clean:
|
||||
rm -f *.o kernel.elf
|
||||
rm -f *.o */*.o */*/*.o *.elf *.bin
|
||||
|
||||
run: kernel.bin
|
||||
qemu-system-arm -M versatilepb -m 128M -nographic -kernel kernel.bin
|
||||
BIN
MiniOS.7z
Normal file
BIN
MiniOS.7z
Normal file
Binary file not shown.
68
README.md
68
README.md
|
|
@ -1,27 +1,63 @@
|
|||
# MiniOS Kernel (ARMv7)
|
||||
|
||||
# MiniOS
|
||||
This is a minimal bare-metal ARM kernel project built for educational and prototyping purposes.
|
||||
It includes multitasking, a UART shell, a simple task scheduler, and IRQ handling.
|
||||
Tested and compatible with **Windows 10** using `arm-none-eabi-gcc` and QEMU.
|
||||
|
||||
MiniOS is a simple educational operating system designed for ARM64 (QEMU and Luckfox Lyra B M).
|
||||
It includes:
|
||||
---
|
||||
|
||||
- Preemptive multitasking with SMP
|
||||
- UART console with shell
|
||||
- MMU and memory protection
|
||||
- IPC and basic VFS with /proc
|
||||
- Profiler and task inspector
|
||||
- Networking (VirtIO + UDP)
|
||||
- eMMC boot support
|
||||
- ELF loader
|
||||
## Features
|
||||
|
||||
## Build
|
||||
- ARMv7 Bootloader (`boot.s`, `boot.ld`)
|
||||
- UART driver (`uart.c`, `uart.h`)
|
||||
- Task manager with real context switching (`task.c`, `switch.s`)
|
||||
- Round-robin scheduler triggered by timer IRQ (`irq.s`)
|
||||
- Interactive shell via UART (`shell.c`)
|
||||
- Supported commands:
|
||||
- `ps` – list tasks
|
||||
- `echo` – simple message
|
||||
- `halt` – stop execution
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Windows 10**
|
||||
- [Git Bash](https://git-scm.com/download/win)
|
||||
- [GCC ARM Embedded Toolchain](https://developer.arm.com/downloads/-/gnu-rm)
|
||||
- [QEMU for Windows 64-bit](https://qemu.weilnetz.de/w64/)
|
||||
|
||||
---
|
||||
|
||||
## How to Build and Run
|
||||
|
||||
```bash
|
||||
make
|
||||
qemu-system-arm -M versatilepb -m 128M -nographic -kernel kernel.bin
|
||||
```
|
||||
|
||||
## Boot on Luckfox
|
||||
Once running, you'll see:
|
||||
|
||||
```bash
|
||||
load mmc 0:1 0x40200000 kernel.elf
|
||||
bootelf 0x40200000
|
||||
```
|
||||
MiniOS Kernel Booted
|
||||
MiniOS Shell>
|
||||
```
|
||||
|
||||
Type one of the supported commands (`ps`, `echo`, `halt`).
|
||||
|
||||
---
|
||||
|
||||
## Next Steps (Optional)
|
||||
|
||||
- Virtual File System (VFS)
|
||||
- `ls`, `cat`, `cd` shell commands
|
||||
- ELF binary loader
|
||||
- FAT32 filesystem support
|
||||
- Advanced multitasking with priorities
|
||||
|
||||
---
|
||||
|
||||
## Author
|
||||
|
||||
Built by Georgiana using ARM bare-metal architecture.
|
||||
Powered by QEMU and the GNU ARM Toolchain.
|
||||
20
boot.ld
Normal file
20
boot.ld
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x8000;
|
||||
|
||||
.text : {
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss : {
|
||||
*(.bss COMMON)
|
||||
}
|
||||
|
||||
. = ALIGN(8);
|
||||
stack_top = . + 0x1000;
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
#!/bin/sh
|
||||
echo "Loading kernel to 0x40200000..."
|
||||
load mmc 0:1 0x40200000 kernel.elf
|
||||
bootelf 0x40200000
|
||||
19
devices/uart.c
Normal file
19
devices/uart.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "uart.h"
|
||||
|
||||
#define UART_BASE ((volatile char *)0x101f1000)
|
||||
|
||||
void uart_init(void) {}
|
||||
|
||||
void uart_write(const char *msg) {
|
||||
while (*msg) {
|
||||
*UART_BASE = *msg++;
|
||||
}
|
||||
}
|
||||
|
||||
void uart_putchar(char c) {
|
||||
*UART_BASE = c;
|
||||
}
|
||||
|
||||
char uart_getchar(void) {
|
||||
return *UART_BASE;
|
||||
}
|
||||
9
devices/uart.h
Normal file
9
devices/uart.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef UART_H
|
||||
#define UART_H
|
||||
|
||||
void uart_init(void);
|
||||
void uart_write(const char *msg);
|
||||
void uart_putchar(char c);
|
||||
char uart_getchar(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#include "elf.h"
|
||||
#include "uart.h"
|
||||
|
||||
int elf_load(const void *elf_data) {
|
||||
uart_puts("[ELF] Loading ELF...\n");
|
||||
// Stub - parse headers, map segments
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef ELF_H
|
||||
#define ELF_H
|
||||
|
||||
int elf_load(const void *elf_data);
|
||||
|
||||
#endif
|
||||
43
src/emmc.c
43
src/emmc.c
|
|
@ -1,43 +0,0 @@
|
|||
|
||||
#include "emmc.h"
|
||||
#include "uart.h"
|
||||
#include "mmio.h"
|
||||
#include "delay.h"
|
||||
|
||||
#define EMMC_BASE 0x10005000
|
||||
#define EMMC_ARG2 (EMMC_BASE + 0x00)
|
||||
#define EMMC_BLKSZCNT (EMMC_BASE + 0x04)
|
||||
#define EMMC_CMDTM (EMMC_BASE + 0x08)
|
||||
#define EMMC_RESP0 (EMMC_BASE + 0x0C)
|
||||
#define EMMC_DATA (EMMC_BASE + 0x20)
|
||||
#define EMMC_STATUS (EMMC_BASE + 0x24)
|
||||
|
||||
void emmc_init(void) {
|
||||
uart_print("[emmc] Init sequence...\n");
|
||||
mmio_write(EMMC_CMDTM, 0x00000000); // Reset command
|
||||
delay(1000);
|
||||
uart_print("[emmc] Init done\n");
|
||||
}
|
||||
|
||||
int emmc_read_block(uint32_t lba, uint8_t *buffer) {
|
||||
mmio_write(EMMC_ARG2, lba);
|
||||
mmio_write(EMMC_BLKSZCNT, (1 << 16) | 512); // 1 block
|
||||
mmio_write(EMMC_CMDTM, 0x11200010); // CMD17 read single
|
||||
|
||||
while (mmio_read(EMMC_STATUS) & 0x2); // wait for ready
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
((uint32_t*)buffer)[i] = mmio_read(EMMC_DATA);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emmc_boot(void) {
|
||||
uart_print("[emmc] Booting...\n");
|
||||
uint8_t *image = (uint8_t *)0x8000000;
|
||||
emmc_read_block(2048, image); // Read first boot block
|
||||
void (*entry)(void) = (void (*)(void))(image);
|
||||
entry();
|
||||
return 0;
|
||||
}
|
||||
11
src/emmc.h
11
src/emmc.h
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
#ifndef EMMC_H
|
||||
#define EMMC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void emmc_init(void);
|
||||
int emmc_read_block(uint32_t lba, uint8_t *buffer);
|
||||
int emmc_boot(void);
|
||||
|
||||
#endif
|
||||
38
src/ipc.c
38
src/ipc.c
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
#include "ipc.h"
|
||||
#include "scheduler.h"
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_MSGS 8
|
||||
#define MAX_TASKS 16
|
||||
|
||||
typedef struct {
|
||||
ipc_msg_t queue[MAX_MSGS];
|
||||
int head, tail, count;
|
||||
} ipc_queue_t;
|
||||
|
||||
static ipc_queue_t ipc_queues[MAX_TASKS];
|
||||
|
||||
void ipc_init(void) {
|
||||
memset(ipc_queues, 0, sizeof(ipc_queues));
|
||||
}
|
||||
|
||||
int ipc_send(uint64_t to_id, ipc_msg_t msg) {
|
||||
if (to_id >= MAX_TASKS) return -1;
|
||||
ipc_queue_t *q = &ipc_queues[to_id];
|
||||
if (q->count >= MAX_MSGS) return -2;
|
||||
q->queue[q->tail] = msg;
|
||||
q->tail = (q->tail + 1) % MAX_MSGS;
|
||||
q->count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_recv(ipc_msg_t *msg_out) {
|
||||
uint64_t id = scheduler_get_current()->id;
|
||||
ipc_queue_t *q = &ipc_queues[id];
|
||||
if (q->count == 0) return -3;
|
||||
*msg_out = q->queue[q->head];
|
||||
q->head = (q->head + 1) % MAX_MSGS;
|
||||
q->count--;
|
||||
return 0;
|
||||
}
|
||||
16
src/ipc.h
16
src/ipc.h
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#ifndef IPC_H
|
||||
#define IPC_H
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint64_t from;
|
||||
uint32_t type;
|
||||
uint64_t data;
|
||||
} ipc_msg_t;
|
||||
|
||||
int ipc_send(uint64_t to_task_id, ipc_msg_t msg);
|
||||
int ipc_recv(ipc_msg_t *msg_out);
|
||||
void ipc_init(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
#include "uart.h"
|
||||
#include "smp.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
void kernel_main(void) {
|
||||
uart_init();
|
||||
smp_init();
|
||||
scheduler_init();
|
||||
while (1) {
|
||||
scheduler_schedule();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
// Placeholder for MMC commands implementation
|
||||
// To be implemented depending on hardware or simulation platform
|
||||
|
||||
int mmc_send_cmd(uint32_t cmd, uint32_t arg) {
|
||||
return 0;
|
||||
}
|
||||
24
src/mmu.c
24
src/mmu.c
|
|
@ -1,24 +0,0 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_TABLE_SIZE 4096
|
||||
#define MAIR_VALUE 0xFF
|
||||
|
||||
static uint64_t __attribute__((aligned(PAGE_SIZE))) l1_table[512];
|
||||
|
||||
void mmu_init(void) {
|
||||
for (int i = 0; i < 512; i++) {
|
||||
l1_table[i] = (i << 30) | (0b11 << 0) | (0b01 << 2);
|
||||
}
|
||||
|
||||
asm volatile("msr mair_el1, %0" :: "r"(MAIR_VALUE));
|
||||
uint64_t tcr = (16ULL << 0) | (16ULL << 16);
|
||||
asm volatile("msr tcr_el1, %0" :: "r"(tcr));
|
||||
uint64_t ttbr = (uint64_t)l1_table;
|
||||
asm volatile("msr ttbr0_el1, %0" :: "r"(ttbr));
|
||||
uint64_t sctlr;
|
||||
asm volatile("mrs %0, sctlr_el1" : "=r"(sctlr));
|
||||
sctlr |= (1 << 0) | (1 << 2) | (1 << 12);
|
||||
asm volatile("msr sctlr_el1, %0" :: "r"(sctlr));
|
||||
asm volatile("isb");
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef MMU_H
|
||||
#define MMU_H
|
||||
|
||||
void mmu_init(void);
|
||||
|
||||
#endif
|
||||
18
src/proc.c
18
src/proc.c
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
#include "uart.h"
|
||||
#include "scheduler.h"
|
||||
#include "profiler.h"
|
||||
|
||||
void proc_uptime(void) {
|
||||
extern int global_ticks;
|
||||
uart_print("Uptime: ");
|
||||
uart_print_int(global_ticks / 100);
|
||||
uart_print(" seconds\n");
|
||||
}
|
||||
|
||||
void proc_meminfo(void) {
|
||||
extern int free_pages;
|
||||
uart_print("Free memory pages: ");
|
||||
uart_print_int(free_pages);
|
||||
uart_print("\n");
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
#include "profiler.h"
|
||||
#include "uart.h"
|
||||
|
||||
#define MAX_TASKS 16
|
||||
static int task_ticks[MAX_TASKS];
|
||||
|
||||
void profiler_init(void) {
|
||||
for (int i = 0; i < MAX_TASKS; i++) task_ticks[i] = 0;
|
||||
}
|
||||
|
||||
void profiler_tick(void) {
|
||||
extern int current_task_id;
|
||||
task_ticks[current_task_id]++;
|
||||
}
|
||||
|
||||
void profiler_report(void) {
|
||||
uart_print("CPU Time per Task:\n");
|
||||
for (int i = 0; i < MAX_TASKS; i++) {
|
||||
if (task_ticks[i]) {
|
||||
uart_print("Task ");
|
||||
uart_print_int(i);
|
||||
uart_print(": ");
|
||||
uart_print_int(task_ticks[i]);
|
||||
uart_print(" ticks\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
|
||||
#ifndef PROFILER_H
|
||||
#define PROFILER_H
|
||||
|
||||
void profiler_init(void);
|
||||
void profiler_tick(void);
|
||||
void profiler_report(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
#include "scheduler.h"
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_TASKS 16
|
||||
static task_t tasks[MAX_TASKS];
|
||||
static int task_count = 0;
|
||||
static task_t *current = NULL;
|
||||
|
||||
void scheduler_init(void) {
|
||||
memset(tasks, 0, sizeof(tasks));
|
||||
task_count = 0;
|
||||
current = NULL;
|
||||
}
|
||||
|
||||
void scheduler_add(task_t *t) {
|
||||
if (task_count < MAX_TASKS) {
|
||||
tasks[task_count++] = *t;
|
||||
}
|
||||
}
|
||||
|
||||
task_t *scheduler_get_current(void) {
|
||||
return current;
|
||||
}
|
||||
|
||||
void scheduler_schedule(void) {
|
||||
static int i = 0;
|
||||
current = &tasks[i];
|
||||
i = (i + 1) % task_count;
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
#ifndef SCHEDULER_H
|
||||
#define SCHEDULER_H
|
||||
|
||||
typedef struct task {
|
||||
int id;
|
||||
int state;
|
||||
void *stack;
|
||||
void *stack_top;
|
||||
} task_t;
|
||||
|
||||
void scheduler_init(void);
|
||||
void scheduler_add(task_t *t);
|
||||
void scheduler_schedule(void);
|
||||
task_t *scheduler_get_current(void);
|
||||
|
||||
#endif
|
||||
38
src/shell.c
38
src/shell.c
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
#include "uart.h"
|
||||
#include "vfs.h"
|
||||
#include "scheduler.h"
|
||||
#include "proc.h"
|
||||
|
||||
void shell_loop(void) {
|
||||
char buf[128];
|
||||
while (1) {
|
||||
uart_print("> ");
|
||||
int i = 0;
|
||||
while (1) {
|
||||
char c = uart_getc();
|
||||
if (c == '\r' || c == '\n') break;
|
||||
if (i < 127) buf[i++] = c;
|
||||
uart_putc(c);
|
||||
}
|
||||
buf[i] = 0;
|
||||
uart_print("\n");
|
||||
|
||||
if (strcmp(buf, "ps") == 0) {
|
||||
extern void scheduler_list_tasks(void);
|
||||
scheduler_list_tasks();
|
||||
} else if (strcmp(buf, "uptime") == 0) {
|
||||
proc_uptime();
|
||||
} else if (strcmp(buf, "meminfo") == 0) {
|
||||
proc_meminfo();
|
||||
} else if (strncmp(buf, "cat ", 4) == 0) {
|
||||
const char *data = vfs_read(buf + 4);
|
||||
if (data)
|
||||
uart_print(data);
|
||||
else
|
||||
uart_print("File not found\n");
|
||||
} else {
|
||||
uart_print("Unknown command\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/smp.c
26
src/smp.c
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
#include "uart.h"
|
||||
|
||||
volatile int core_ready[4];
|
||||
|
||||
int get_core_id(void) {
|
||||
uint64_t mpidr;
|
||||
asm volatile("mrs %0, mpidr_el1" : "=r"(mpidr));
|
||||
return mpidr & 0b11;
|
||||
}
|
||||
|
||||
void core_entry(void) {
|
||||
int cid = get_core_id();
|
||||
uart_puts("Core ");
|
||||
uart_putc('0' + cid);
|
||||
uart_puts(" ready\n");
|
||||
core_ready[cid] = 1;
|
||||
while (1);
|
||||
}
|
||||
|
||||
void smp_init(void) {
|
||||
for (int i = 1; i < 4; i++) {
|
||||
*(volatile uint64_t *)(0x4000008 + i * 8) = (uint64_t)core_entry;
|
||||
asm volatile("sev");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
bl kernel_main
|
||||
b .
|
||||
26
src/switch.S
26
src/switch.S
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
.global context_switch
|
||||
.type context_switch, %function
|
||||
|
||||
context_switch:
|
||||
// Save callee-saved registers
|
||||
stp x19, x20, [x0]
|
||||
stp x21, x22, [x0, #16]
|
||||
stp x23, x24, [x0, #32]
|
||||
stp x25, x26, [x0, #48]
|
||||
stp x27, x28, [x0, #64]
|
||||
str x29, [x0, #80]
|
||||
str x30, [x0, #88]
|
||||
str sp, [x0, #96]
|
||||
|
||||
// Load new task context
|
||||
ldp x19, x20, [x1]
|
||||
ldp x21, x22, [x1, #16]
|
||||
ldp x23, x24, [x1, #32]
|
||||
ldp x25, x26, [x1, #48]
|
||||
ldp x27, x28, [x1, #64]
|
||||
ldr x29, [x1, #80]
|
||||
ldr x30, [x1, #88]
|
||||
ldr sp, [x1, #96]
|
||||
|
||||
ret
|
||||
32
src/task.c
32
src/task.c
|
|
@ -1,32 +0,0 @@
|
|||
|
||||
#include "scheduler.h"
|
||||
#include "uart.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_TASKS 16
|
||||
static task_t tasks[MAX_TASKS];
|
||||
static int task_count = 0;
|
||||
static task_t *current = NULL;
|
||||
|
||||
void scheduler_init(void) {
|
||||
memset(tasks, 0, sizeof(tasks));
|
||||
task_count = 0;
|
||||
current = NULL;
|
||||
}
|
||||
|
||||
void scheduler_add(task_t *t) {
|
||||
if (task_count < MAX_TASKS) {
|
||||
tasks[task_count++] = *t;
|
||||
}
|
||||
}
|
||||
|
||||
task_t *scheduler_get_current(void) {
|
||||
return current;
|
||||
}
|
||||
|
||||
void scheduler_schedule(void) {
|
||||
static int i = 0;
|
||||
current = &tasks[i];
|
||||
i = (i + 1) % task_count;
|
||||
}
|
||||
35
src/uart.c
35
src/uart.c
|
|
@ -1,35 +0,0 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define UART0_BASE 0x09000000
|
||||
#define UARTFR (*(volatile uint32_t *)(UART0_BASE + 0x18))
|
||||
#define UARTDR (*(volatile uint32_t *)(UART0_BASE + 0x00))
|
||||
|
||||
void uart_init(void) {}
|
||||
|
||||
void uart_putc(char c) {
|
||||
while (UARTFR & (1 << 5));
|
||||
UARTDR = c;
|
||||
}
|
||||
|
||||
void uart_puts(const char *s) {
|
||||
while (*s) uart_putc(*s++);
|
||||
}
|
||||
|
||||
void uart_print(const char *s) {
|
||||
uart_puts(s);
|
||||
}
|
||||
|
||||
void uart_print_int(int x) {
|
||||
char buf[16];
|
||||
int i = 0;
|
||||
if (x == 0) {
|
||||
uart_putc('0');
|
||||
return;
|
||||
}
|
||||
while (x > 0) {
|
||||
buf[i++] = '0' + (x % 10);
|
||||
x /= 10;
|
||||
}
|
||||
while (i--) uart_putc(buf[i]);
|
||||
}
|
||||
11
src/uart.h
11
src/uart.h
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
#ifndef UART_H
|
||||
#define UART_H
|
||||
|
||||
void uart_init(void);
|
||||
void uart_putc(char c);
|
||||
void uart_puts(const char *s);
|
||||
void uart_print(const char *s);
|
||||
void uart_print_int(int x);
|
||||
|
||||
#endif
|
||||
12
src/usb.c
12
src/usb.c
|
|
@ -1,12 +0,0 @@
|
|||
#include "usb.h"
|
||||
#include "uart.h"
|
||||
|
||||
void usb_init(void) {
|
||||
uart_puts("[USB] Initializing USB Host...\n");
|
||||
// Placeholder logic - real implementation would probe EHCI/OHCI/XHCI
|
||||
}
|
||||
|
||||
int usb_read_bulk(int device, void *buffer, int length) {
|
||||
uart_puts("[USB] Reading bulk data...\n");
|
||||
return -1; // Not implemented
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef USB_H
|
||||
#define USB_H
|
||||
|
||||
void usb_init(void);
|
||||
int usb_read_bulk(int device, void *buffer, int length);
|
||||
|
||||
#endif
|
||||
29
src/vfs.c
29
src/vfs.c
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
#include "vfs.h"
|
||||
#include "uart.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static vfs_file_t files[] = {
|
||||
{ "/dev/info.txt", "MiniOS v1.0 - Built July 2025\n" },
|
||||
{ "/proc/version", "MiniOS kernel 1.0\n" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
void vfs_init(void) {}
|
||||
|
||||
const char *vfs_read(const char *path) {
|
||||
for (int i = 0; files[i].path; i++) {
|
||||
if (strcmp(files[i].path, path) == 0)
|
||||
return files[i].content;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vfs_list(const char *prefix) {
|
||||
size_t len = strlen(prefix);
|
||||
for (int i = 0; files[i].path; i++) {
|
||||
if (strncmp(files[i].path, prefix, len) == 0)
|
||||
uart_puts(files[i].path + len + 1), uart_puts("\n");
|
||||
}
|
||||
}
|
||||
14
src/vfs.h
14
src/vfs.h
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
#ifndef VFS_H
|
||||
#define VFS_H
|
||||
|
||||
typedef struct vfs_file {
|
||||
const char *path;
|
||||
const char *content;
|
||||
} vfs_file_t;
|
||||
|
||||
const char *vfs_read(const char *path);
|
||||
void vfs_list(const char *prefix);
|
||||
void vfs_init(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
#include "uart.h"
|
||||
#include "pmm.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define VIRTIO_MMIO_BASE 0x10001000
|
||||
#define VIRTIO_NET_Q_TX 1
|
||||
|
||||
typedef struct {
|
||||
uint64_t addr;
|
||||
uint32_t len;
|
||||
uint16_t flags;
|
||||
uint16_t next;
|
||||
} __attribute__((packed)) virtq_desc_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t flags;
|
||||
uint16_t idx;
|
||||
struct {
|
||||
uint16_t id;
|
||||
uint16_t len;
|
||||
} ring[8];
|
||||
} __attribute__((packed)) virtq_used_t;
|
||||
|
||||
static void *desc_area;
|
||||
|
||||
void virtio_net_dma_send(const void *data, int len) {
|
||||
volatile uint32_t *mmio = (volatile uint32_t *)VIRTIO_MMIO_BASE;
|
||||
virtq_desc_t *desc = (virtq_desc_t *)desc_area;
|
||||
|
||||
void *packet = pmm_alloc_page();
|
||||
memcpy(packet, data, len);
|
||||
|
||||
desc[0].addr = (uint64_t)(uintptr_t)packet;
|
||||
desc[0].len = len;
|
||||
desc[0].flags = 0;
|
||||
desc[0].next = 0;
|
||||
|
||||
virtq_used_t *used = (virtq_used_t *)((uint8_t *)desc_area + 4096);
|
||||
used->ring[0].id = 0;
|
||||
used->ring[0].len = len;
|
||||
used->idx++;
|
||||
|
||||
mmio[0x070 / 4] |= 0x4; // notify
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue