commit 8fab4e2015ce80ff2899f6b69f6f0da1178143d3 Author: uie99917 Date: Fri Jul 4 12:52:28 2025 +0300 Initial commit with Complet_Project contents diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..08e0db7 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ + +CC=aarch64-linux-gnu-gcc +LD=aarch64-linux-gnu-ld +OBJCOPY=aarch64-linux-gnu-objcopy + +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 + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +kernel.elf: $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) + +clean: + rm -f *.o kernel.elf diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a77fa3 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ + +# MiniOS + +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 + +## Build + +```bash +make +``` + +## Boot on Luckfox + +```bash +load mmc 0:1 0x40200000 kernel.elf +bootelf 0x40200000 +``` diff --git a/boot/boot.its b/boot/boot.its new file mode 100644 index 0000000..e69de29 diff --git a/boot/load_boot.sh b/boot/load_boot.sh new file mode 100644 index 0000000..d9fffa7 --- /dev/null +++ b/boot/load_boot.sh @@ -0,0 +1,5 @@ + +#!/bin/sh +echo "Loading kernel to 0x40200000..." +load mmc 0:1 0x40200000 kernel.elf +bootelf 0x40200000 diff --git a/src/elf.c b/src/elf.c new file mode 100644 index 0000000..dd56577 --- /dev/null +++ b/src/elf.c @@ -0,0 +1,8 @@ +#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; +} \ No newline at end of file diff --git a/src/elf.h b/src/elf.h new file mode 100644 index 0000000..aae35ce --- /dev/null +++ b/src/elf.h @@ -0,0 +1,6 @@ +#ifndef ELF_H +#define ELF_H + +int elf_load(const void *elf_data); + +#endif \ No newline at end of file diff --git a/src/emmc.c b/src/emmc.c new file mode 100644 index 0000000..5b806b3 --- /dev/null +++ b/src/emmc.c @@ -0,0 +1,43 @@ + +#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; +} diff --git a/src/emmc.h b/src/emmc.h new file mode 100644 index 0000000..a35edfa --- /dev/null +++ b/src/emmc.h @@ -0,0 +1,11 @@ + +#ifndef EMMC_H +#define EMMC_H + +#include + +void emmc_init(void); +int emmc_read_block(uint32_t lba, uint8_t *buffer); +int emmc_boot(void); + +#endif diff --git a/src/ipc.c b/src/ipc.c new file mode 100644 index 0000000..ce2b0ab --- /dev/null +++ b/src/ipc.c @@ -0,0 +1,38 @@ + +#include "ipc.h" +#include "scheduler.h" +#include + +#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; +} diff --git a/src/ipc.h b/src/ipc.h new file mode 100644 index 0000000..0c8213e --- /dev/null +++ b/src/ipc.h @@ -0,0 +1,16 @@ + +#ifndef IPC_H +#define IPC_H +#include + +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 diff --git a/src/kernel_main.c b/src/kernel_main.c new file mode 100644 index 0000000..85d6e8f --- /dev/null +++ b/src/kernel_main.c @@ -0,0 +1,13 @@ + +#include "uart.h" +#include "smp.h" +#include "scheduler.h" + +void kernel_main(void) { + uart_init(); + smp_init(); + scheduler_init(); + while (1) { + scheduler_schedule(); + } +} diff --git a/src/mmc_cmds.c b/src/mmc_cmds.c new file mode 100644 index 0000000..ff4720a --- /dev/null +++ b/src/mmc_cmds.c @@ -0,0 +1,9 @@ + +#include + +// 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; +} diff --git a/src/mmu.c b/src/mmu.c new file mode 100644 index 0000000..9d1dd51 --- /dev/null +++ b/src/mmu.c @@ -0,0 +1,24 @@ +#include + +#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"); +} \ No newline at end of file diff --git a/src/mmu.h b/src/mmu.h new file mode 100644 index 0000000..eb2bc3c --- /dev/null +++ b/src/mmu.h @@ -0,0 +1,6 @@ +#ifndef MMU_H +#define MMU_H + +void mmu_init(void); + +#endif \ No newline at end of file diff --git a/src/proc.c b/src/proc.c new file mode 100644 index 0000000..b3f6b7f --- /dev/null +++ b/src/proc.c @@ -0,0 +1,18 @@ + +#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"); +} diff --git a/src/profiler.c b/src/profiler.c new file mode 100644 index 0000000..25fbde7 --- /dev/null +++ b/src/profiler.c @@ -0,0 +1,28 @@ + +#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"); + } + } +} diff --git a/src/profiler.h b/src/profiler.h new file mode 100644 index 0000000..544c801 --- /dev/null +++ b/src/profiler.h @@ -0,0 +1,9 @@ + +#ifndef PROFILER_H +#define PROFILER_H + +void profiler_init(void); +void profiler_tick(void); +void profiler_report(void); + +#endif diff --git a/src/scheduler.c b/src/scheduler.c new file mode 100644 index 0000000..58e8cf0 --- /dev/null +++ b/src/scheduler.c @@ -0,0 +1,30 @@ + +#include "scheduler.h" +#include + +#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; +} diff --git a/src/scheduler.h b/src/scheduler.h new file mode 100644 index 0000000..ac56658 --- /dev/null +++ b/src/scheduler.h @@ -0,0 +1,17 @@ + +#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 diff --git a/src/shell.c b/src/shell.c new file mode 100644 index 0000000..0d4c844 --- /dev/null +++ b/src/shell.c @@ -0,0 +1,38 @@ + +#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"); + } + } +} diff --git a/src/smp.c b/src/smp.c new file mode 100644 index 0000000..7685fcc --- /dev/null +++ b/src/smp.c @@ -0,0 +1,26 @@ + +#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"); + } +} diff --git a/src/startup.s b/src/startup.s new file mode 100644 index 0000000..2c338e7 --- /dev/null +++ b/src/startup.s @@ -0,0 +1,6 @@ + +.section .text +.global _start +_start: + bl kernel_main + b . diff --git a/src/switch.S b/src/switch.S new file mode 100644 index 0000000..bc71eb3 --- /dev/null +++ b/src/switch.S @@ -0,0 +1,26 @@ + +.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 diff --git a/src/task.c b/src/task.c new file mode 100644 index 0000000..1157259 --- /dev/null +++ b/src/task.c @@ -0,0 +1,32 @@ + +#include "scheduler.h" +#include "uart.h" +#include +#include + +#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; +} diff --git a/src/uart.c b/src/uart.c new file mode 100644 index 0000000..875d8a5 --- /dev/null +++ b/src/uart.c @@ -0,0 +1,35 @@ + +#include + +#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]); +} diff --git a/src/uart.h b/src/uart.h new file mode 100644 index 0000000..ff25d21 --- /dev/null +++ b/src/uart.h @@ -0,0 +1,11 @@ + +#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 diff --git a/src/usb.c b/src/usb.c new file mode 100644 index 0000000..3174f11 --- /dev/null +++ b/src/usb.c @@ -0,0 +1,12 @@ +#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 +} \ No newline at end of file diff --git a/src/usb.h b/src/usb.h new file mode 100644 index 0000000..80c3848 --- /dev/null +++ b/src/usb.h @@ -0,0 +1,7 @@ +#ifndef USB_H +#define USB_H + +void usb_init(void); +int usb_read_bulk(int device, void *buffer, int length); + +#endif \ No newline at end of file diff --git a/src/vfs.c b/src/vfs.c new file mode 100644 index 0000000..c029ea7 --- /dev/null +++ b/src/vfs.c @@ -0,0 +1,29 @@ + +#include "vfs.h" +#include "uart.h" +#include +#include + +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"); + } +} diff --git a/src/vfs.h b/src/vfs.h new file mode 100644 index 0000000..1b203c9 --- /dev/null +++ b/src/vfs.h @@ -0,0 +1,14 @@ + +#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 diff --git a/src/virtio_net_dma.c b/src/virtio_net_dma.c new file mode 100644 index 0000000..e758d57 --- /dev/null +++ b/src/virtio_net_dma.c @@ -0,0 +1,46 @@ + +#include "uart.h" +#include "pmm.h" +#include +#include + +#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 +}