Initial commit - full kernel with IRQ, shell and UART
This commit is contained in:
commit
549b86adef
14 changed files with 303 additions and 0 deletions
24
Makefile
Normal file
24
Makefile
Normal 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
63
README.md
Normal 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
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;
|
||||||
|
}
|
||||||
12
boot.s
Normal file
12
boot.s
Normal 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
7
irq.s
Normal 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
32
kernel.c
Normal 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
36
shell.c
Normal 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
6
shell.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef SHELL_H
|
||||||
|
#define SHELL_H
|
||||||
|
|
||||||
|
void shell_run(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
9
startup.s
Normal file
9
startup.s
Normal 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
18
switch.s
Normal 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
26
task.c
Normal 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
22
task.h
Normal 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
19
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
uart.h
Normal file
9
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
|
||||||
Loading…
Add table
Reference in a new issue