Initial commit - full kernel with IRQ, shell and UART

This commit is contained in:
uie99917 2025-04-07 11:16:01 +00:00
commit 549b86adef
14 changed files with 303 additions and 0 deletions

24
Makefile Normal file
View file

@ -0,0 +1,24 @@
CROSS_COMPILE = arm-none-eabi-
AS = $(CROSS_COMPILE)as
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS = -Wall -mcpu=arm926ej-s -nostdlib -ffreestanding
all: kernel.bin
kernel.elf: boot.o kernel.o
$(LD) -T boot.ld -o $@ $^
kernel.bin: kernel.elf
$(OBJCOPY) -O binary $< $@
boot.o: boot.s
$(AS) -mcpu=arm926ej-s $< -o $@
kernel.o: kernel.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o *.elf *.bin

63
README.md Normal file
View file

@ -0,0 +1,63 @@
# MiniOS Kernel (ARMv7)
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.
---
## Features
- 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
```
Once running, you'll see:
```
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
View file

@ -0,0 +1,20 @@
ENTRY(_start)
SECTIONS {
. = 0x8000;
.text : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss COMMON)
}
. = ALIGN(8);
stack_top = . + 0x1000;
}

12
boot.s Normal file
View file

@ -0,0 +1,12 @@
.global _start
.section .text
_start:
// Set up stack pointer
LDR sp, =stack_top
// Jump to kernel main entry point
BL kernel_main
// Infinite loop if kernel_main returns
halt:
B halt

7
irq.s Normal file
View file

@ -0,0 +1,7 @@
.global irq_handler
.type irq_handler, %function
irq_handler:
PUSH {r0-r12, lr}
BL task_schedule
POP {r0-r12, pc}

32
kernel.c Normal file
View file

@ -0,0 +1,32 @@
#include "uart.h"
#include "task.h"
#include "shell.h"
#define TIMER_BASE 0x101E2000
#define TIMER_LOAD (*(volatile unsigned int *)(TIMER_BASE + 0x00))
#define TIMER_CTRL (*(volatile unsigned int *)(TIMER_BASE + 0x08))
void timer_init() {
TIMER_LOAD = 0x10000;
TIMER_CTRL = (1 << 7) | (1 << 6) | (1 << 5) | 1;
}
void enable_interrupts() {
__asm__ volatile (
"mrs r0, cpsr\n"
"bic r0, r0, #0x80\n"
"msr cpsr_c, r0\n"
);
}
void kernel_main(void) {
uart_init();
uart_write("MiniOS Kernel Booted\n");
timer_init();
enable_interrupts();
task_init();
shell_run();
}

36
shell.c Normal file
View file

@ -0,0 +1,36 @@
#include "uart.h"
#include "task.h"
#include "shell.h"
#include <string.h>
void shell_run() {
char input[64];
int pos = 0;
uart_write("MiniOS Shell> ");
while (1) {
char c = uart_getchar();
uart_putchar(c); // Echo
if (c == '\r' || c == '\n') {
input[pos] = '\0';
uart_write("\n");
if (strcmp(input, "echo") == 0) {
uart_write("Echo test\n");
} else if (strcmp(input, "ps") == 0) {
uart_write("Task list: [0] task1, [1] task2\n");
} else if (strcmp(input, "halt") == 0) {
uart_write("System halted.\n");
while (1);
} else {
uart_write("Unknown command\n");
}
pos = 0;
uart_write("MiniOS Shell> ");
} else {
input[pos++] = c;
}
}
}

6
shell.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef SHELL_H
#define SHELL_H
void shell_run(void);
#endif

9
startup.s Normal file
View file

@ -0,0 +1,9 @@
.global _start
.section .text
_start:
LDR sp, =stack_top
BL kernel_main
B .
.org 0x18
B irq_handler

18
switch.s Normal file
View file

@ -0,0 +1,18 @@
.global context_switch
.type context_switch, %function
context_switch:
// r0 = current task context
// r1 = next task context
// Save r4-r12
STMIA r0!, {r4-r12}
STR sp, [r0]
STR lr, [r0, #4]
// Restore r4-r12
LDMIA r1!, {r4-r12}
LDR sp, [r1]
LDR lr, [r1, #4]
BX lr

26
task.c Normal file
View file

@ -0,0 +1,26 @@
#include "task.h"
task_t tasks[MAX_TASKS];
int current_task = 0;
void task1() {
while (1);
}
void task2() {
while (1);
}
void task_init() {
tasks[0].context.sp = (unsigned int)&tasks[0].stack[255];
tasks[0].context.lr = (unsigned int)task1;
tasks[1].context.sp = (unsigned int)&tasks[1].stack[255];
tasks[1].context.lr = (unsigned int)task2;
current_task = 0;
}
void task_schedule() {
current_task = (current_task + 1) % MAX_TASKS;
}

22
task.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef TASK_H
#define TASK_H
#define MAX_TASKS 2
typedef struct {
unsigned int regs[13]; // r0-r12
unsigned int sp;
unsigned int lr;
} context_t;
typedef struct {
context_t context;
unsigned int stack[256];
} task_t;
void task_init(void);
void task_schedule(void);
extern task_t tasks[MAX_TASKS];
extern int current_task;
#endif

19
uart.c Normal file
View 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
uart.h Normal file
View 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