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
|
|
||||||
42
Makefile
42
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
|
CFLAGS = -Wall -mcpu=arm926ej-s -nostdlib -ffreestanding -I.
|
||||||
LD=aarch64-linux-gnu-ld
|
|
||||||
OBJCOPY=aarch64-linux-gnu-objcopy
|
|
||||||
|
|
||||||
CFLAGS=-ffreestanding -O2 -nostdlib -Wall
|
.SUFFIXES: .s .o .c
|
||||||
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
|
%.o: %.c
|
||||||
|
|
||||||
all: kernel.elf
|
|
||||||
|
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
kernel.elf: $(OBJS)
|
%.o: %.s
|
||||||
$(LD) $(LDFLAGS) -o $@ $(OBJS)
|
$(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:
|
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
|
## Features
|
||||||
- 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
|
|
||||||
|
|
||||||
## 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
|
```bash
|
||||||
make
|
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