This project is focused on booting an ARMv7 processor using QEMU and GDB, primarily for educational purposes. The implementation combines both assembly language and C, allowing for a deep understanding of low-level programming and system architecture. However, there are small functions written in Rust, which aim to explore the feasibility of replacing C with Rust in certain parts of the project by utilizing the linker. This approach not only highlights the potential of Rust as a systems programming language but also provides an opportunity to compare its performance and safety features against the traditional C components.
Ubuntu/Debian packages:
- gcc-arm-none-eabi
- gdb-arm-none-eabi
- qemu-system
Or
Nix(package manager):
Important
The Makefile contains targets for both the Nix package manager and Ubuntu/Debian packages. The targets starting with nix.
should be fully functional on any machine that supports the nix-shell environment.
- Run
make qemuA8
to execute the project on QEMU. - Open a new terminal and run
make debug
to start debugging the project.- You can also open DDD locally (or any other GUI debugger) and connect to the debug session.
- To launch DDD with the Nix environment, run:
make nix.ddd.debug
.
Project's sructure:
.
├── bin
│ └── image.bin <- Binary image used by 'qemu'
├── core <- Assembly files used to init the processor
├── kernel <- C files
├── linker <- Linker files
│ ├── mmap.ld
│ └── zynq.ld
├── obj <- Object files generated by the Assembler
├── proc <- Assembly functions used as "helpers" to init hw and peripherals
└── sys <- Assembly files used to handle the syscalls
To build the project and assemble/compile files located at core/*.s
/sys/*.s
/proc/*.s
and kernel/*.c
run:
Using nix-shell
:
make nix.build
Locally:
make build
To compile the rust
drivers defined by kernel/rs/drivers.rs
run the make command with the variable RS set to 1:
make build RS=1
The scheduler works on top of the Timer interruptions, utilizing a straightforward algorithm designed for educational purposes. When a task is running, it continuously checks for timer interruptions. Upon receiving a timer interrupt, the system invokes the irq_handler.s, which then calls the c_irq_handler function, passing the current task's context as an argument (a pointer to the stack). The c_scheduler function is then executed to determine whether the current task has exceeded its allocated time slice, indicated by comparing current_task.current_ticks with current_task.task_ticks. If the task has not yet reached its time limit, the system returns to the interrupt handler to continue execution. However, if the time limit is reached, the scheduler performs context switching. This involves saving the current task's interrupt stack pointer (irq_sp) from the assembly context, switching to Supervisor (SVC) mode, and saving the SVC stack pointer of the current task. The scheduler then loads the SVC stack pointer of the next task to be executed, switches back to IRQ mode, and finally loads the interrupt stack pointer of the new task. This cycle repeats, ensuring efficient multitasking and responsive task management on the ARMv7 architecture.
flowchart TD
1["Task x running"] --> 2{"Timer interruption"}
2 -- No --> 1
2 -- Yes --> A
A["irq_handler.s"] --> B["c_irq_handler"]
B -- Pass the task's context as argument (a pointer to the stack)--> C["c_scheduler"]
C --> D{"current_task.current_ticks >= current_task.task_ticks"}
D -- No --> A
D -- Yes --> E["Perform the Context Switching"]
E --> F["save the current task's irq_sp that comes from the assembly ctx"]
F --> G["change to SVC mode"]
G --> H["save the svc_sp of the current task"]
H --> I["load the svc_sp of the new task"]
I --> J["change to IRQ mode"]
J --> K["load the irq_sp of the new task"]
K --> A
Important
There is a bug when printing inside the tasks, which seems to be a stack overflow problem. This issue requires further investigation and debugging to ensure the stability and reliability of the scheduler implementation.
- CPU Scheduling Basics - YouTube
- baremetal-arm/doc/08_scheduling.md at 09-wip · umanovskis/baremetal-arm · GitHub
Nix is a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible. It aims to provide a robust and simple way to handle packages and their dependencies, ensuring that the same package setup can be replicated across multiple environments without any inconsistencies.
The key features of Nix are:
-
Reproducibility: Nix ensures that installing or upgrading one package cannot break other packages. It allows multiple versions of a package to coexist on the same system.
-
Isolation: Nix isolates packages from each other. This means that unlike traditional package managers, it doesn't have global state that can be mutated by packages.
These features make Nix an excellent tool for creating reproducible development environments, reducing the "it works on my machine" problem.
- Nix Tutorial
- A step towards the future of configuration and infrastructure management with Nix
- Is there much difference between using nix-shell and docker for local development? - Help - NixOS Discourse
- What is /usr/bin/env?
- Nix + Make
- ARMV7 - ASM Quick Reference
- ARM - Programmer's Guide
- Machine used by QEMU → RealView Platform Baseboard for Cortex-A8 User Guide
- Genearal ARMv7 guide → baremetal-arm/doc/00_introduction.md at master · umanovskis/baremetal-arm
- ARMv7-A PSRs
- Guide for ARMv7-A | Booting
- ARM bootloader: Interrupt Vector Table Understanding - Stack Overflow
- VectorTable | Allocatable .section
- Stack Pointer Init
- ARMv7-A Processor Modes
Exceptions take into account the interrupts (IRQs
): Guide for ARMv7-A | Types of Exception
- ARM Developer Guide | Handling Exceptions
- Guide for ARMv7-A | Exception Handling
- Guide for ARMv7-A | Return from exception
- Reference Manual | SVC and
- Guide for ARMv7-A | Simplistic Interrupt Handling
- Guide for ARMv7-A | Nested Interrupt Handling
- PrimeCell UART (PL011) Technical Reference Manual r1p5
- ARMs PL011 UART | Welcome to the Mike’s homepage!
- Hello world for bare metal ARM using QEMU | Freedom Embedded
- Emulating ARM PL011 serial ports | Freedom Embedded
- baremetal-arm/doc/07_interrupts.md at master · umanovskis/baremetal-arm · GitHub
- RealView Platform Baseboard for Cortex-A8 User Guide | GIC
- Important: Interrupt Acknowledge → has the irq number
- RealView Platform Baseboard for Cortex-A8 User Guide | IRQs IDs
- TIMER0 ID: 36