Skip to content

fborello-lambda/armv7_nix_env

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ARMv7 Baremetal

Why and What

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.

Table of Contents

Dependencies

Ubuntu/Debian packages:

  • gcc-arm-none-eabi
  • gdb-arm-none-eabi
  • qemu-system

Or

Nix(package manager):

  • nix → installs nix-shell
  • nixfmt (optional)

How

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.

To build and run the project:

  1. Run make qemuA8 to execute the project on QEMU.
  2. 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

Scheduling

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
Loading

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.

Resources

What and Why Nix?

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:

  1. 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.

  2. 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.

References

Extras

Booting

Exception Handling

Exceptions take into account the interrupts (IRQs): Guide for ARMv7-A | Types of Exception

UART PL011

GIC

TIMER

Videos

Online Emulator

GDB extras

About

Baremetal ARMv7 template

Resources

Stars

Watchers

Forks

Packages

No packages published