diff --git a/README.md b/README.md index cac75f0a..bfbdb43d 100644 --- a/README.md +++ b/README.md @@ -13,19 +13,18 @@ _(1) MCH2025 is a preliminary name, MCH2025 is an event that will be organised b -# Contributing +# [Documentation](./docs/README.md) -We are an open-source project, so we can always use more hands! -If you're looking for things to help with, look for the [issues with the PoC (Proof of Concept) milestone](https://github.com/badgeteam/BadgerOS/issues/33). -**We are currently using the ESP32-C6 for development.** -Make sure to check out the [style guide](docs/styleguide.md) so your code can fit right in. -If you're unsure where to put your code, look into the [project structure](docs/project-structure.md). -If you're not sure what to do but want to help, message us: -- [robotman2412](https://t.me/robotman2412) on telegram +# Contributing +We are an open-source project, so we can always use more hands! +If you're new to this project and want to help, message us: +- [RobotMan2412](https://t.me/robotman2412) on telegram - [Badge.team](https://t.me/+StQpEWyhnb96Y88p) telegram group +After that, see [Project structure](./docs/project_structure.md) for reference about how this project works. + # Prerequisites diff --git a/docs/README.md b/docs/README.md index 009fbae8..3f1c84aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,20 @@ # BadgerOS documentation -- [C code style guide](styleguide.md) -- [Project structure](project-structure.md) \ No newline at end of file + + + +## For contributors +For information about the structure of the project, including building, tools and folder structure, see [Project structure](./project_structure.md). + +## For BadgerOS kernel developers +For information about the internal structure and API of the BadgerOS kernel, see [Kernel documentation](./kernel/README.md). + + +For project plan and requirements, see [Project requirements](./project_requirements.md). diff --git a/docs/kernel/README.md b/docs/kernel/README.md new file mode 100644 index 00000000..a64ec2a2 --- /dev/null +++ b/docs/kernel/README.md @@ -0,0 +1,54 @@ +# Kernel documentation +This page is intended for BadgerOS kernel developers. +It details the internal kernel APIs and structures. + +## Index +- [List of kernel components](#list-of-kernel-components) +- [Component interaction overview](#component-interaction-overview) +- [Components and their purpose](#components-and-their-purpose) + + +# List of kernel components +These links provide more detail on the scope and requirements per component and their APIs (when implemented). +- [Hardware abstraction layer](./hal.md) +- [Scheduler](./scheduler.md) +- [Process management](./process.md) +- [Memory management](./memory.md) +- [Filesystems](./filesystems.md) +- [Traps and interrupts](./isr.md) + + +# Component interaction overview +Components in the rows use APIs from components in the columns. +| | HAL | Sched | Proc | Mem | FS | Trap | +| :---: | :---: | :---: | :---: | :---: | :---: | :---: | +| HAL | | | | | | | +| Sched | | | | | | x | +| Proc | | x | | x | x | | +| Mem | | | | | | | +| FS | x | | | | | | +| Trap | | x | | | | | + + +# Components and their purpose +## Hardware abstraction layer +The hardware abstraction layer, or HAL for short, provides a generic interface to various hardware functions, including GPIO, I²C, SPI, FLASH, etc. +Other components can then use the HAL to perform the same operations on different hardware without the need for porting them. +Take filesystems for example, where one type of filesystem can be stored on almost any kind of media without the need for explicit support from the filesystem driver. + +## Scheduler +The scheduler manages distribution of CPU time between threads running on the same system. BadgerOS implements a [preemptive scheduler](https://en.wikipedia.org/wiki/Preemption_(computing)); the scheduler takes back control after a predetermined time so one process cannot freeze the entire computer. + +## Process management +The process management API manages the creation and termination of processes and assigning resources to processes. All resources given to a process are accounted by the process management API so they can be reclaimed when the process exits. +The process API has tight relationships with the scheduler and memory management because both threads and memory are resources integral to the existance of processes. + +## Memory management +All the memory available to the system is handled centrally by the memory manager. The memory manager is responsible for accounting the available memory and distributing said memory between processes, kernel-side caches, kernel stacks and kernel data structures. +Memory management also includes the configuration of virtual memory or memory protection, whichever is applicable. + +## Filesystems +The filesystem component is reponsible for managing all the mounted filesystems. It abstracts the filesystem details away, leaving only a generic interface that applies to all types of filesystem. + +## Traps and interrupts +Traps and interrupts are low-level mechanisms of the CPU used for error conditions and events respectively. Traps can be illegal instruction, memory access fault, system calls, etc. while interrupts are generated by other hardware like timers, GPIO, SPI, I²C or inter-CPU communication. diff --git a/docs/kernel/filesystems.md b/docs/kernel/filesystems.md new file mode 100644 index 00000000..42a7cc7f --- /dev/null +++ b/docs/kernel/filesystems.md @@ -0,0 +1,78 @@ +# Filesystems +The filesystem component is reponsible for managing all the mounted filesystems. It abstracts the filesystem details away, leaving only a generic interface that applies to all types of filesystem. + +Currently responsible: Joyce (Quantumcatgirl). + +## Index +- [Scope](#scope) +- [Dependents](#dependents) +- [Dependencies](#dependencies) +- [Data types](#data-types) +- [API](#api) + + +# Scope +BadgerOS will initially support both a RAM filesystem, also called RAMFS, and a FAT filesystem. It supports FAT before EXT2/3/4 as a compromise to allow mounting the filesystem from Windows or MacOS without the need for additional software. In the future, EXT2/3/4 *may* be supported, but there are higher priorities than that. + +Most filesystems will be stored on nonvolatile physical media. This physical media is abstracted from the filesystem implementation by the block device API. The block device API is similar to the HAL in purpose, but not dependant on the target platform. + +## API scope +- API support for UNIX permissions +- API support for reading and writing +- API support for sybolic links (TODO) +- API support for hard links (TODO) + +## FAT filesystem scope +- Support for FAT12, FAT16 and FAT32 (TODO) +- Support for [long filename](https://en.wikipedia.org/wiki/Long_filename) entries (TODO) +- Support for reading and writing (TODO) +- Support for formatting (TODO) + +## RAM filesystem scope +- Support for UNIX permissions +- Support for reading and writing +- Support for device special files (TODO) +- Support for symbolic links (TODO) +- Support for hard links + +## Block device scope +- Support for reading, writing and erasing blocks +- Support for block size and total size detection + + +# Dependents +## [Process management](./process.md) +The process management component uses filesystems to load executable files to start programs. + + +# Dependencies +## [Hardware abstraction layer](./hal.md) +The block device part of the filesystems component uses the HAL to abstract the implementation details of communication with the storage media. + + +# Data types +TODO. + + +# API +Because of the multiple abstractions present in the filesystems, the API is split into 5 parts: +- High-level filesystem API: `fs_*` +- Filesystem abstraction layer: `vfs_*` +- Filesystem implementations: `vfs_fat_*`, `vfs_ramfs_*`, etc. +- Block device abstraction layer: `blkdev_*` +- Block device implementations: `blkdev_ram_*`, etc. + +## High-level filesystem API +The high-level filesystem API translates traditional file operations into calls to the filesystem abstraction layer that more directly represent operations on the filesystem. + +The high-level filesystem API also converts multiple file handles per logical file into one single handle so individual filesystem implementations only need to manage one handle per file / directory. + +## Filesystem abstraction layer +The filesystem abstraction layer defines which functions each filesystem needs to implement and forwards every function call directly to the implementation. + +The filesystem abstraction layer and the filesystem implementation only manage one handle per file, so they only need to synchronize accesses between different files not symbolic or hard linked. + +## Block device abstraction layer +The block device abstraction layer implements caches and some common utilities for accessing block devices. It calls the block device implementations for read, write and erase commands, which handle the uncached accesses. + +The block device API does synchronize multiple accesses to the same partition, which is the taks of the filesystem implementation. diff --git a/docs/kernel/hal.md b/docs/kernel/hal.md new file mode 100644 index 00000000..9b032057 --- /dev/null +++ b/docs/kernel/hal.md @@ -0,0 +1,62 @@ +# Hardware abstraction layer +The hardware abstraction layer, or HAL for short, provides a generic interface to various hardware functions, including GPIO, I²C, SPI, FLASH, etc. +Other components can then use the HAL to perform the same operations on different hardware without the need for porting them. +Take filesystems for example, where one type of filesystem can be stored on almost any kind of media without the need for explicit support from the filesystem driver. + +Currently responsible: Julian (RobotMan2412). + +## Index +- [Scope](#scope) +- [Dependents](#dependents) +- [Dependencies](#dependencies) +- [Data types](#data-types) +- [API](#api) + + +# Scope +The HAL needs to provide an abstract interface that can perform all actions that BagderOS needs it to. There will abstractions for: +- GPIO + - Digital I/O + - PWM outputs + - ADC + - DAC +- I²C +- UART +- SPI +- I²S +- FLASH + +## GPIO scope +The GPIOs need to be able to function as digital I/Os and all alternate functions provided by the hardware for which there is a driver (I²C, UART, SPI, etc.). The GPIO API also needs to be able to tell whether a pin is currently in use by one of such alternate functions. At least one GPIO input pin needs to support interrupts. + +## I²C scope +The I²C HAL needs to support master, slave, 10-bit addressing and interrupts. + +## UART scope +The UART HAL needs to support baudrate configuration and interrupts. + +## SPI scope +The SPI HAL needs to support DMA, one-wire SPI, two-wire SPI and interrupts. + +## I²S scope +TODO: Depends on sound architecture + +## FLASH scope +The FLASH HAL needs to support FLASH MMUs (if present), reading, erasing and writing. + + +# Dependents +## [Filesystems](./filesystems.md) +The block device drivers from the filesystems component depend on the HAL to abstract communications with physical storage media. + + +# Dependencies +The HAL does not depend on other components. + + +# Data types +TODO. + + +# API +TODO. diff --git a/docs/kernel/isr.md b/docs/kernel/isr.md new file mode 100644 index 00000000..ef7f5cd6 --- /dev/null +++ b/docs/kernel/isr.md @@ -0,0 +1,72 @@ +# Traps and interrupts +Traps and interrupts are low-level mechanisms of the CPU used for error conditions and events respectively. Traps can be illegal instruction, memory access fault, system calls, etc. while interrupts are generated by other hardware like timers, GPIO, SPI, I²C or inter-CPU communication. + +Currently responsible: Julian (RobotMan2412). + +## Index +- [Scope](#scope) +- [Dependents](#dependents) +- [Dependencies](#dependencies) +- [Data types](#data-types) +- [API](#api) + + +# Scope +The interrupt service routine, or ISR for short, handles these CPU events and converts them into events in the kernel. A limited amount of code can run inside an interrupt, with the exception of system calls, which are run on the kernel thread associated with the process. + + +# Dependents +## [Scheduler](./scheduler.md) +The scheduler calls `isr_ctx_switch_set` to inform the ISR which context to run next. This context can be kernel side (either kernel thread or kernel side of user thread) or user side (user side of user thread). + + +# Dependencies +## [Scheduler](./scheduler.md) +When a trap or interrupt happens, the ISR can call `sched_request_switch_from_isr` to ask the scheduler if a context switch is in order and if so, to which context. +When a system call happens, the ISR calls `sched_raise_from_isr` to "raise" the privileges to kernel mode and run specified kernel code in the thread. + + +# Data types +## isr_ctx_t +The ISR context is a CPU-specific data structure that stores the execution context for a side of a thread; kernel threads have one ISR contexts while user threads have one each for their kernel and user sides. + +Aside from the CPU-specific fields, which should not be accessed by code that is not CPU-specific, there are two general fields: + +### Field: `sched_thread_t *thread` +Pointer to owning `sched_thread_t`. +Used by the ISR itself to call the scheduler with the appropriate thread handle. + +### Field: `bool is_kernel_thread` +Thread is a kernel thread. +If true, the thread is run in M-mode, otherwise it is run in U-mode. + +M-mode (or kernel-mode) contexts are (run as) the kernel, inheriting all the privileges associated. U-mode (or user-mode) contexts are for user code and their privileges are strictly regulated by the kernel. + +The scheduler uses this field to indicate in which privilege mode the context should be run. + + +# API +## `static inline isr_ctx_t *isr_ctx_get();` +Get the current [ISR context](#isr_ctx_t). + +Used by the scheduler and error handling functions as a CPU-specific way to get information about the execution state. + +## `static inline isr_ctx_t *isr_ctx_switch_get();` +Get the outstanding context switch target, if any. + +Can be used to query which ISR context is set to be switched to. If NULL, the current context is kept when the ISR returns. + +## `static inline void isr_ctx_switch_set(isr_ctx_t *switch_to);` +Set the context switch target to switch to before exiting the trap/interrupt handler. + +Used by the scheduler in response to a call to `sched_request_switch_from_isr`. + +## `void isr_ctx_dump(isr_ctx_t const *ctx);` +Print a register dump given isr_ctx_t. + +Used by error handlers to print the execution state when either the kernel panics or a user thread raises an exception. + +## `void kernel_cur_regs_dump();` +Print a register dump of the current registers. + +Used by error handlers when the kernel panics. diff --git a/docs/kernel/memory.md b/docs/kernel/memory.md new file mode 100644 index 00000000..1eb1405f --- /dev/null +++ b/docs/kernel/memory.md @@ -0,0 +1,33 @@ +# Memory management +All the memory available to the system is handled centrally by the memory manager. The memory manager is responsible for accounting the available memory and distributing said memory between processes, kernel-side caches, kernel stacks and kernel data structures. +Memory management also includes the configuration of virtual memory or memory protection, whichever is applicable. + +Currently responsible: Hein-Pieter van Braam (HP). + +## Index +- [Scope](#scope) +- [Dependents](#dependents) +- [Dependencies](#dependencies) +- [Data types](#data-types) +- [API](#api) + + +# Scope +Memory management is in charge of allocating and protecting all the memory available to the system. Various systems in the kernel and applications can request memory for various purposes. The memory allocator decides how much memory at what addresses to assign to applications or the kernel. This information is then relayed to memory protection for the application or kernel respectively. + + +# Dependents +## [Process management](./process.md) +The process management component relays requests for memory from the processes to the memory management component. + + +# Dependencies +The memory allocator does not depend on other components. + + +# Data types +TODO. + + +# API +TODO. diff --git a/docs/kernel/process.md b/docs/kernel/process.md new file mode 100644 index 00000000..8e797125 --- /dev/null +++ b/docs/kernel/process.md @@ -0,0 +1,31 @@ +# Document title +Description + +Currently responsible: Name (Nickname). + +## Index +- [Scope](#scope) +- [Dependents](#dependents) +- [Dependencies](#dependencies) +- [Data types](#data-types) +- [API](#api) + + +# Scope +Scope + + +# Dependents + + + +# Dependencies + + + +# Data types +TODO. + + +# API +TODO. diff --git a/docs/kernel/scheduler.md b/docs/kernel/scheduler.md new file mode 100644 index 00000000..8e797125 --- /dev/null +++ b/docs/kernel/scheduler.md @@ -0,0 +1,31 @@ +# Document title +Description + +Currently responsible: Name (Nickname). + +## Index +- [Scope](#scope) +- [Dependents](#dependents) +- [Dependencies](#dependencies) +- [Data types](#data-types) +- [API](#api) + + +# Scope +Scope + + +# Dependents + + + +# Dependencies + + + +# Data types +TODO. + + +# API +TODO. diff --git a/docs/project-structure.md b/docs/project-structure.md deleted file mode 100644 index 0a8b55da..00000000 --- a/docs/project-structure.md +++ /dev/null @@ -1,44 +0,0 @@ -# BadgerOS project structure - -There are three levels of abstraction: CPU, platform and kernel. -The CPU level contains divers for CPU-specific logic like interrupt handling, -the platform level contains drivers for hardware inside the CPU and -the kernel level contains the business logic that allows applications to run. - -The folder structure reflects this: -| path | purpose -| :------------- | :------ -| src | Kernel-implemented source -| include | Kernel-declared includes -| cpu/*/src | CPU-implemented source -| cpu/*/include | CPU-declared include -| port/*/src | Platform-implemented source -| port/*/include | Platform-declared include - -In the future, there will be more details on the structure these folders will have internally but for now it's flat. - -## The source folders -This applies to `src`, `cpu/*/src` and `port/*/src`. - -The source folders contain exclusively C files and files to embed into the kernel verbatim. -If you're not sure where to put a new function, consider: -- Does the function depend on the target platform? - - If so, it should be in `port/*/src` -- Does the function depend on the CPU, but not the target platform? - - If so, it should be in `cpu/*/src` -- Can the function be described in a platform- and CPU-independent way? - - If so, it should be in `src` - -## The include folders -This applies to `include`, `cpu/*/include` and `port/*/include`. - -The include folders contain exclusively C header files. -If you're not sure where to put a new definition, consider: -- Does the value of a it or signature of a function depend on the target platform? - - If so, it should be in `port/*/include/*` -- Does the value of a it or signature of a function depend on the CPU, but not the target platform? - - If so, it should be in `cpu/*/include/*` -- Can the it be described in a platform- and CPU-independent way? - - If so, it should be in `include` - -_Note: The value of `*` may change, but is always the same in a path: `port/abc/include/abc` is valid, but `port/one/include/another` is not._ diff --git a/docs/project_requirements.md b/docs/project_requirements.md new file mode 100644 index 00000000..c1627938 --- /dev/null +++ b/docs/project_requirements.md @@ -0,0 +1,183 @@ +# Project requirements +## Philosophy +BadgerOS aims to be the new stable target for Badge.Team badges and their applications. +To be a stable target means things like generic interfaces and stable APIs. +It should also have a nice, responsive user interface, which helps with appealing to the users. + +This original philosophy created a set of requirements: +- The application's environment should be as standard as possible + - Applications have access to the C standard library + - Applications running on the same CPU architecture on different badges shouldn't need to be recompiled. + - Applications should have traditional memory protection +- The kernel should not be architecture-specific + - CPU architectures need to be abstracted + - SoCs architectures need to be abstracted +- The user interface should be intuitive + +This document expands on all of these requirements as a part of forming a project plan for BadgerOS. + + +## Index +- [Kernel requirements](#kernel-requirements) + - [CPU low-level](#cpu-low-level) + - [Low-level drivers](#low-level-drivers) + - [High-level drivers](#high-level-drivers) + - [Kernel infrastructure](#kernel-infrastructure) + - [Application binary interface](#application-binary-interface) +- [System application requirements](#system-application-requirements) + - [Application list](#application-list) + - [Settings](#settings) + - [App store](#app-store) + - [Name tag](#name-tag) + - [Text editor](#text-editor) + - [File browser](#file-browser) + - [Simple application IDE](#simple-application-ide) + - [Event schedule / calendar](#event-schedule--calendar) + - [Image viewer](#image-viewer) + + + +# Kernel requirements +These requirements are for the kernel and the services it provides. + +## CPU low-level +The following CPU-related features must be supported: +- ☐ Support for dynamic interrupt allocation +- ☐ Support for 1-8 CPUs +- ☐ Support for heterogeneous CPU systems + + +## Low-level drivers +The ESP32-P4 has GPIOs, which also support a subset of the communications interfaces. +The GPIO driver must support the following: +- ☐ Digital I/O + - ☑ Direction control + - ☑ Pull resistor control + - ☐ Open drain support +- ☐ PWM driver + - ☐ Configurable frequency +The GPIO driver should support the following: +- ☐ ADC driver +- ☐ DAC driver + +The ESP32-P4 has many hardware communications interfaces. +The following interfaces must be supported: +- ☐ I²C master drivers + - ☐ Configurable speed + - ☐ Configurable pins + - ☐ Interrupt capable + - ☐ Low-power I²C + - ☐ High-power I²C + - ☐ I³C +- ☐ SPI master drivers + - ☐ Configurable speed + - ☐ Configurable pins + - ☐ Interrupt capable + - ☐ DMA capable +- ☐ UART drivers + - ☐ Configurable speed + - ☐ Configurable pins + - ☐ Interrupt capable + - ☐ DMA capable +- ☐ I²S drivers + - ☐ Configurable speed + - ☐ Configurable pins + - ☐ Configurable sample type + - ☐ Interrupt capable + - ☐ DMA capable +- ☐ SDIO drivers + - ☐ Configurable speed + - ☐ Configurable pins + - ☐ Interrupt capable + - ☐ DMA capable +- ☐ MIPI DSI drivers + +The following interfaces should be supported: +- ☐ USB host drivers + - ☐ Keyboard + - ☐ Mouse + - ☐ Mass storage device +- ☐ Ethernet drivers + +The ESP32-P4 also has some image processing hardware. +The following image processing should be supported: +- ☐ Pixel Processing Accelerator (rotate / scale unit) +- ☐ JPEG encoder +- ☐ JPEG decoder + + +## High-level drivers +There must be high-level drivers for: +- ☐ I²C CH32V003 comms + - ☐ Keyboard + - ☐ I/O expander +- ☐ SDIO ESP32-C6 comms + - ☐ Networking + - ☐ I/O expander + + +## Kernel infrastructure +TODO: Infrastructure that the kernel itself depends on. + +## Application binary interface +The ABI must support: +- ☑ File I/O +- ☐ Multithreading and thread management +- ☐ Process spawning and management +- ☐ Badge-style interface + - ☐ Keyboard input + - ☐ Gamepad input + - ☐ One or more displays +- ☐ Networking +The ABI should support: +- ☐ Rotate / scale unit, if present +- ☐ Hardware JPEG codec, if present + + + +# System application requirements +These requirements are for the preinstalled applications integral to the operating system, like settings. + +## Application list +The following applications must exist: +- ☐ Settings +- ☐ App store (name TBD) +- ☐ Name tag +- ☐ Text editor +- ☐ File browser + +The following applications should exist +- ☐ Simple application IDE +- ☐ Event schedule / calendar +- ☐ Image viewer + +## Settings +The settings must include: +- ☐ Name tag adjustment +- ☐ Multiple WiFi network management +- ☐ System updates +The settings should include: +- ☐ OTA server address +- ☐ App store server address + +## App store + +## Name tag +The name tag should support: +- ☐ Images +- ☐ Font selection +- ☐ Color selection +- ☐ Border selection + +## Text editor + +## File browser + +## Simple application IDE + +## Event schedule / calendar + +## Image viewer +The image viewer, if present, should support: +- ☐ JPEG images +- ☐ PNG images diff --git a/docs/project_structure.md b/docs/project_structure.md new file mode 100644 index 00000000..1c97e47c --- /dev/null +++ b/docs/project_structure.md @@ -0,0 +1,133 @@ +# Project structure + +## Index +- [How the build system works](#how-the-build-system-works) +- [Code style](#code-style) +- [General folder structure](#general-folder-structure) +- [Kernel folder structure](#project-structure) +- [Custom tools and scripts](#custom-tools-and-scripts) + + +# How the build system works +## Prerequisites +You can get a copy of the build tools **[from our buildroot fork](https://github.com/badgeteam/mch2025-badgeros-buildroot/releases/tag/badgeros-sdk-release-1.1)**. + +If you prefer to install manually, get: +- CMake +- GNU make +- One of: `riscv32-unknown-linux-gnu-gcc`, `riscv32-linux-gnu-gcc`, `riscv64-unknown-linux-gnu-gcc` or `riscv64-linux-gnu-gcc` +- Picocom +- `esptool.py` (from ESP-IDF) +- OpenOCD (for debugging) + +## Recommended software +Not required for build, but might be useful: +- clang-format +- clang-tidy + +## Build process +BadgerOS uses a combination of CMake (for C source code), Makefiles (for issuing build commands) and Python scripts (to generate source code or files). When you go to the root of the project and type `make build`, the following happens: +1. The [system applications](../files/init/) are built +2. The non-application files [are generated](../files/Makefile) +3. The [filesystem image](../kernel/Makefile#L18) is generated from these +4. The [kernel](../kernel/) is built using [CMake](../kernel/CMakeLists.txt) +5. The output files for the kernel are copied to kernel/firmware. + +## Convenience functions +For your convenience, there are a couple other functions than just building the project, including: +- `make flash` (requires esptool.py from [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/#installation)), for flashing the kernel to your hardware +- `make monitor` (requires picocom), for opening the serial monitor with an address to line filter +- `make clang-tidy-check` (requires clang-tidy), for running the clang-tidy pull request check locally +- `make clang-format-check` (requires clang-format), for running the clang-format pull request check locally + + +# Code style +BagderOS uses clang-format 18.0 or later to keep code style consistent. +When you create a pull request, a code formatting check will run. +If it fails, please make sure to run clang-format yourself, format on save in your IDE of choice is recommended. + + +# General folder structure +The BadgerOS repository contains source code for the BadgerOS kernel, all official preinstalled applications (except sponsored ones) and the other files required to create a BadgerOS installation. +It can be broadly divided into four categories: +- [Kernel source code](#kernel-source-code) +- [Application source code](#application-source-code) +- [Shared source code](#shared-source-code) +- [Installation file structure](#installation-file-structure) + +## Kernel source code +All source code unique to the BadgerOS kernel lives in the `kernel` folder. This [is further divided](#kernel-folder-structure) among [CPU-specific](../kernel/cpu), [platform-specific](../kernel/port/) and [generic kernel code](../kernel/). +The `kernel` folder also contains the scripts used to build just the kernel, like the [`kernel/Makefile`](../kernel/Makefile) and [`kernel/CMakeLists.txt`](../kernel/CMakeLists.txt). + +## Application source code +Applications that are part of the operating system are also in this repository. +This includes [`/sbin/init`](../files/init/src/) (the [init program](https://en.wikipedia.org/wiki/Init)), other non-kernel system programs, settings, the application store / installer / hatchery, name tag applications and other utilities. + +The application source code lives in [`files`](../files), then with a folder per system application. + +## Shared source code +A small number of files contains information that is shared between both the kernel and the applications. These files, named "shared source" or "common source", live in the [`common`](../common) directory. Most of this pertains to the interface between the kernel and applications: system calls and APIs. + +## Installation file structure +One of the final products is an image that contains all the files required for a normal BadgerOS installation. These files are generated, currently by [a Makefile](../files/Makefile), and are output into the `files/root` folder. These can, along with the kernel, be used to create an image to be installed onto hardware. + + +# Kernel folder structure +There are three levels of abstraction: CPU, platform and kernel. +The CPU level contains divers for CPU-specific logic like interrupt handling, +the platform level contains drivers for hardware inside the CPU and +the kernel level contains the business logic that allows applications to run. + +The folder structure reflects this: +| path | purpose +| :------------- | :------ +| src | Kernel-implemented source +| include | Kernel-declared includes +| cpu/*/src | CPU-implemented source +| cpu/*/include | CPU-declared include +| port/*/src | Platform-implemented source +| port/*/include | Platform-declared include + +In the future, there will be more details on the structure these folders will have internally but for now it's flat. + +## The source folders +This applies to `src`, `cpu/*/src` and `port/*/src`. + +The source folders contain exclusively C files and files to embed into the kernel verbatim. +If you're not sure where to put a new function, consider: +- Does the function depend on the target platform? + - If so, it should be in `port/*/src` +- Does the function depend on the CPU, but not the target platform? + - If so, it should be in `cpu/*/src` +- Can the function be described in a platform- and CPU-independent way? + - If so, it should be in `src` + +## The include folders +This applies to `include`, `cpu/*/include` and `port/*/include`. + +The include folders contain exclusively C header files. +If you're not sure where to put a new definition, consider: +- Does the value of a it or signature of a function depend on the target platform? + - If so, it should be in `port/*/include/*` +- Does the value of a it or signature of a function depend on the CPU, but not the target platform? + - If so, it should be in `cpu/*/include/*` +- Can the it be described in a platform- and CPU-independent way? + - If so, it should be in `include` + +_Note: The value of `*` may change, but is always the same in a path: `port/abc/include/abc` is valid, but `port/one/include/another` is not._ + + +# Custom tools and scripts +BadgerOS uses a couple custom tools during the build process for converting data. Some of these tools can also be used from the command line. + +## address-filter.py +`address-filter.py` is used to look for addresses in the serial monitor and, if found, prints the linenumber associated with the address. + +## bin2c.py +`bin2c.py` is a simple tool used to convert the contents of a file to a C file containing a `uint8_t` array with the same value. It can be used to load constants from a non-code file without having to store it in the BagderOS installation's filesystem. + +## pack-image.py +`pack-image.py` is a required step of making binaries that can be loaded by Espressif's bootloader. It reads the image header, calculates and appends a checksum, which is checked by the bootloader before it hands over control to BadgerOS. This tool is used in the build process to create the final executable that can be flashed onto an ESP32. + +## ramfs-gen.py +`ramfs-gen.py` generates a C file that represents a folder structure. It is intended to generate the contents of a RAM filesystem, though it can also be used for any other type of media. This tool is used before building the kernel, so a temporary filesystem can be stored in RAM before drivers for nonvolatile media exist. diff --git a/docs/styleguide.md b/docs/styleguide.md deleted file mode 100644 index 60f9aa93..00000000 --- a/docs/styleguide.md +++ /dev/null @@ -1,226 +0,0 @@ -# BadgerOS style guide -- [C code and header style guide](#c-code-style) - - - -# C code style -- [Naming conventions](#naming-conventions) -- [Type definitions](#type-definitions) -- [Variable declarations](#variable-declarations) -- [Function declarations](#function-declarations) -- [Function definitions](#function-definitions) -- [File structure](#file-structure) -- [Spacing](#spacing) -- [Indentation](#indentation) - - -## Naming conventions -All names should be in `snake_case`, some of which are `SNAKE_UPPERCASE`. -Specifically, macros may be either, other most namable things are only `snake_case`. - -The following are always `snake_case`: -- Function names -- Variable names -- Struct/union/enum names -- Typedef names - -Enum values and macro names are mostly `SNAKE_UPPERCASE` except macros that replace functions, types or other lowercase items, in which case the macro name should also be lowercase. - -It is also good to establish the words that make up the name, take the following example: -```c -// Returns the amount of GPIO pins present. -#define io_count() (31) -// Sets the mode of GPIO pin `pin` to `mode`. -void io_mode (badge_err_t *ec, int pin, io_mode_t mode); -``` - -This demonstrates the macro exception as well as the prefix given to the GPIO API. -In general, every API has a prefix, which may be extended if an API is split into multiple sub-APIs. - -In general, names should: -- Have a prefix indicating what API is being referred to. -- Roughly describe their purpose: - - Especially if the type of a variable is something nameless, like `int pin`. - - This may be simplified if the context makes it clear, like `badge_err_t *ec`. -- Not use terms that are too abstract: - - Things like `int *list` are not recommended. - - Exact duplication of the type name like `badge_err_t *badge_err` is not recommended. -- Not start with `_`: - - This is typically a workaround for equal names. - - Names starting with `__` are reserved. - - Names starting with `_` followed by a capital letter are reserved. - -## Type definitions -Type definitions should be simple. If a type is a complex composite, consider using typedefs and structs. Here is a general example of how to define types: -```c -// If you need the longest integer the CPU has. -typedef unsigned long long my_type0; -// Prefer int8_t if possible. -typedef signed char my_type1; -// Prefer uint8_t if possible. -typedef unsigned char my_type2; -// For strings and other things to print. -typedef char my_type3; -// For string constants. -typedef const char *my_type4; - -// Structs, unions and enums should be in a typedef. -typedef struct my_struct my_struct_t; -// Same comment as at the typedef. -struct my_struct { - // Same rules as variable declarations in here. -}; - -// Structs, unions and enums may also be anonymous. -typedef struct { - // Same rules as variable declarations in here. -} my_anonymous_struct_t; - -// Always use typedefs for function pointers. -typedef void (*my_func_1_t)(int some_parameter, char *another_parameter); -// If there are no parameters, write void. -typedef int (*my_func_2_t)(void); -``` - -The following rules apply to types in general: -- The column at which the name starts is constant among a block of declarations / definitions. -- The padding is written with spaces. -- The `*` is at the function name and has at least one space from the type before it. -- The `const` is to the left of the type (unless the pointer is also a constant). -- When a specific resolution is required, use the appropriate (u)int[bits]_t. -- When referring to a length, use `size_t`. - -The following rules apply to structs, unions and enums: -- The content of the definition is indented with four spaces. -- The `{` is on the same line as the `struct`, `union` or `enum` keyword. - -The following rules apply to function pointer types: -- Always use typedefs for function pointers. -- If there are no parameters, write void. - -The following rules apply to integers in types: -- When the integer refers to a `long`, `short`, `char`, etc. the `int` keyword is omitted. -- The `signed` keyword is only permitted before `char`. -- The `signed` and `unsigned` keywords are before the length of the integer. - -The `bool` type is not to be treated as a regular integer: - - `true` and `false` should be used where applicable. - - Multiplication with a constant is allowed. - - Multiplication with a variable or expression is not. - - Bitwise OR, bitwise AND and bitwise complement are not allowed on booleans. - - -## Variable declarations -Variable declarations should be on one line unless that means exceeding 120 columns. -Every variable should have at least a one-line comment explaining the purpose. -Here is a general example of how to declare variables: -```c -// This string will be printed when XYZ happens. -const char *my_string_constant = "Hello, World!"; -// This string will be printed when UVW happens. -const char *the_other_string = "FooBar."; -// How many magic numbers are in `magic_numbers`. -size_t magic_numbers_len; -// A list of carefully selected magic numbers. -const int *magic_numbers; -``` - -The following rules apply: -- [The rules for type definitions](#type-definitions). -- The column at which the name starts is constant among a block of declarations / definitions. -- The column at which the `=` starts is constant among a block of definitions. -- The padding is written with spaces. -- The `=` has at least one space to the left and one space to the right. -- Arrays have a `_len` suffixed length counterpart of type `size_t`. -- The length of an array is declared before the array if that is possible. -- The variable name should approximately describe the purpose. - - -## Function declarations -Function declarations should be on one line unless that means exceeding 120 columns. -Every function should have at least a one-line comment explaining the purpose and functions with return values should explain what is returned on error. -Here is a general example of how to declare functions: -```c -// Computes an approximation of the square root of `x`. -// Does not accept negative inputs for `x`. -// Returns -1 on error. -int fast_square_root(int x) __attribute__((const)); -// Computes the integer square root of `x` (rounded down). -// Does not accept negative inputs for `x`. -// Returns -1 on error. -int square_root (int x) __attribute__((const)); -// Counts the number of times `c` occurs in `str`. -// Returns 0 if `c` is 0 or if `str` is NULL. -size_t count_occurances(const char *str, char c) - __attribute__((pure)); -``` - -The following rules apply: -- [The rules for type definitions](#type-definitions). -- The column at which the name starts is constant among a block of declarations. -- The column at which the `(` starts is constant among a block of definitions. -- The padding is written with spaces. -- The attributes are behind the `)`. - - With exactly one space of padding OR - - On a newline, preceded by exactly eight spaces. -- The function name should approximately describe the purpose. - - -## Function definitions -Function definitions should be on one line unless that means exceeding 120 columns. -Every function should have at least a one-line comment explaining the purpose and functions with return values should explain what is returned on error. -Function definitions should have the same exact comment as their matching declaration. -Here is a general example of how to define functions: -```c -// Counts the number of times `c` occurs in `str`. -// Returns 0 if `c` is 0 or if `str` is NULL. -size_t count_occurances(const char *str, char c) { - // Null checks. - if (!str || !c) return 0; - - // Count the amount of times `c` occurs in `str`. - size_t count = 0; - // A comment here is not required. - while (*str) { - // Compare current character. - // This type of counting would also work but is not recommended: - // count += *str == c; - if (*str == c) count ++; - // Next character. - str ++; - } - - // A comment at such a return is not required. - return count; -} -``` - -The following rules apply: -- [The rules for type definitions](#type-definitions). -- [The rules for functions declarations](#function-declarations), except: - - No horizontal alignment is required or allowed. - - If attributes are required, they must be on the declaration, but not definition. -- The `{` is on the same line as the `)`. - -## File structure -The order of things to write in a C source file is: - -1. The license identifier. -2. Includes. - 1. Project includes. - 2. System libraries. - 3. External libraries. -3. Local types, if any. -4. Functions. - -Things like headers should be sorted alphabetically. - - -## Spacing -In order to make a high-level overview of a file more readable, there should be a certain number of empty lines between different parts of the file. -For any two given things, there should always be at least one empty line between them. - -Things that are unrelated (like functions between two different APIs) should have exactly 3 empty lines between them. This also applies to space between the defines and types, and between the types and functions. - -## Indentation -Indentation is written with size 4 tabs unless the required indent is not aligned to 4, in which case spaces may be added after the tabs. diff --git a/kernel/include/isr_ctx.h b/kernel/include/isr_ctx.h index 4e346134..2330be2c 100644 --- a/kernel/include/isr_ctx.h +++ b/kernel/include/isr_ctx.h @@ -9,14 +9,13 @@ typedef struct isr_ctx_t isr_ctx_t; -// Get the current kernel context. +// Get the current ISR context. static inline isr_ctx_t *isr_ctx_get(); -// Get the outstanding context swap target, if any. +// Get the outstanding context switch target, if any. static inline isr_ctx_t *isr_ctx_switch_get(); -// Set the context swap target to swap to before exiting the trap/interrupt -// handler. +// Set the context switch target to switch to before exiting the trap/interrupt handler. static inline void isr_ctx_switch_set(isr_ctx_t *switch_to); // Print a register dump given isr_ctx_t.