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