The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    └── workflows
    │   └── check.yml
├── COPYING
├── README.md
├── doc
    ├── .gitignore
    ├── book.toml
    ├── license-header.txt
    └── src
    │   ├── SUMMARY.md
    │   ├── booting.md
    │   ├── build.md
    │   ├── debug.md
    │   ├── device.md
    │   ├── external_doc.md
    │   ├── file
    │       ├── fs.md
    │       ├── procfs.md
    │       ├── sysfs.md
    │       └── tmpfs.md
    │   ├── installer.md
    │   ├── intro.md
    │   ├── memory
    │       ├── alloc.md
    │       ├── mem_map.md
    │       ├── mem_space.md
    │       └── tracing.md
    │   ├── module.md
    │   ├── process.md
    │   ├── tty.md
    │   └── userspace
    │       ├── elf.md
    │       ├── exec.md
    │       └── script.md
├── inttest
    ├── .gitignore
    ├── Cargo.lock
    ├── Cargo.toml
    ├── README.md
    ├── build.sh
    └── src
    │   ├── boot.rs
    │   ├── filesystem.rs
    │   ├── main.rs
    │   ├── mount.rs
    │   ├── procfs.rs
    │   ├── signal.rs
    │   └── util.rs
├── kernel
    ├── .cargo
    │   └── config.toml
    ├── .gitignore
    ├── Cargo.lock
    ├── Cargo.toml
    ├── README.md
    ├── arch
    │   ├── x86
    │   │   ├── linker.ld
    │   │   ├── src
    │   │   │   ├── context.s
    │   │   │   ├── memcpy.s
    │   │   │   ├── memmove.s
    │   │   │   ├── memset.s
    │   │   │   └── raw_copy.s
    │   │   └── x86.json
    │   └── x86_64
    │   │   ├── linker.ld
    │   │   ├── src
    │   │       ├── context.s
    │   │       ├── memcpy.s
    │   │       ├── memmove.s
    │   │       ├── memset.s
    │   │       └── raw_copy.s
    │   │   └── x86_64.json
    ├── build
    │   ├── compile.rs
    │   ├── config.rs
    │   ├── main.rs
    │   ├── target.rs
    │   └── util.rs
    ├── ci
    │   └── test.sh
    ├── default.build-config.toml
    ├── grub.cfg
    ├── scripts
    │   ├── gdb.sh
    │   ├── link_partitions.sh
    │   └── qemu.sh
    ├── src
    │   ├── acpi
    │   │   ├── aml
    │   │   │   ├── mod.rs
    │   │   │   ├── named_obj.rs
    │   │   │   ├── namespace_modifier.rs
    │   │   │   ├── term_obj.rs
    │   │   │   ├── type1_opcode.rs
    │   │   │   └── type2_opcode.rs
    │   │   ├── dsdt.rs
    │   │   ├── fadt.rs
    │   │   ├── madt.rs
    │   │   ├── mod.rs
    │   │   └── rsdt.rs
    │   ├── arch
    │   │   ├── mod.rs
    │   │   └── x86
    │   │   │   ├── gdt.rs
    │   │   │   ├── idt.rs
    │   │   │   ├── io.rs
    │   │   │   ├── mod.rs
    │   │   │   ├── paging.rs
    │   │   │   ├── pic.rs
    │   │   │   └── tss.rs
    │   ├── bin.rs
    │   ├── boot.rs
    │   ├── cmdline.rs
    │   ├── crypto
    │   │   ├── chacha20.rs
    │   │   ├── checksum.rs
    │   │   ├── mod.rs
    │   │   └── rand.rs
    │   ├── debug.rs
    │   ├── device
    │   │   ├── bar.rs
    │   │   ├── bus
    │   │   │   ├── mod.rs
    │   │   │   └── pci.rs
    │   │   ├── default.rs
    │   │   ├── id.rs
    │   │   ├── keyboard.rs
    │   │   ├── manager.rs
    │   │   ├── mod.rs
    │   │   ├── serial.rs
    │   │   ├── storage
    │   │   │   ├── ide.rs
    │   │   │   ├── mod.rs
    │   │   │   ├── partition
    │   │   │   │   ├── gpt.rs
    │   │   │   │   ├── mbr.rs
    │   │   │   │   └── mod.rs
    │   │   │   └── pata.rs
    │   │   └── tty.rs
    │   ├── elf
    │   │   ├── kernel.rs
    │   │   ├── mod.rs
    │   │   └── parser.rs
    │   ├── event.rs
    │   ├── file
    │   │   ├── fd.rs
    │   │   ├── fs
    │   │   │   ├── ext2
    │   │   │   │   ├── bgd.rs
    │   │   │   │   ├── dirent.rs
    │   │   │   │   ├── inode.rs
    │   │   │   │   └── mod.rs
    │   │   │   ├── initramfs.rs
    │   │   │   ├── kernfs.rs
    │   │   │   ├── mod.rs
    │   │   │   ├── proc
    │   │   │   │   ├── mem_info.rs
    │   │   │   │   ├── mod.rs
    │   │   │   │   ├── proc_dir
    │   │   │   │   │   ├── cmdline.rs
    │   │   │   │   │   ├── cwd.rs
    │   │   │   │   │   ├── environ.rs
    │   │   │   │   │   ├── exe.rs
    │   │   │   │   │   ├── mod.rs
    │   │   │   │   │   ├── mounts.rs
    │   │   │   │   │   ├── stat.rs
    │   │   │   │   │   └── status.rs
    │   │   │   │   ├── self_link.rs
    │   │   │   │   ├── sys_dir
    │   │   │   │   │   └── mod.rs
    │   │   │   │   ├── uptime.rs
    │   │   │   │   └── version.rs
    │   │   │   └── tmp
    │   │   │   │   └── mod.rs
    │   │   ├── mod.rs
    │   │   ├── perm.rs
    │   │   ├── pipe.rs
    │   │   ├── socket.rs
    │   │   ├── util.rs
    │   │   ├── vfs
    │   │   │   ├── mod.rs
    │   │   │   ├── mountpoint.rs
    │   │   │   └── node.rs
    │   │   └── wait_queue.rs
    │   ├── kernel.rs
    │   ├── libc
    │   │   ├── memcmp.c
    │   │   └── strlen.c
    │   ├── logger.rs
    │   ├── memory
    │   │   ├── alloc.rs
    │   │   ├── buddy.rs
    │   │   ├── cache.rs
    │   │   ├── malloc
    │   │   │   ├── block.rs
    │   │   │   ├── chunk.rs
    │   │   │   └── mod.rs
    │   │   ├── memmap.rs
    │   │   ├── mmio.rs
    │   │   ├── mod.rs
    │   │   ├── oom.rs
    │   │   ├── ring_buffer.rs
    │   │   ├── stats.rs
    │   │   ├── trace.rs
    │   │   ├── user.rs
    │   │   └── vmem.rs
    │   ├── module
    │   │   ├── mod.rs
    │   │   ├── relocation.rs
    │   │   └── version.rs
    │   ├── multiboot.rs
    │   ├── net
    │   │   ├── buff.rs
    │   │   ├── icmp.rs
    │   │   ├── ip.rs
    │   │   ├── lo.rs
    │   │   ├── mod.rs
    │   │   ├── osi.rs
    │   │   ├── sockaddr.rs
    │   │   └── tcp.rs
    │   ├── panic.rs
    │   ├── power.rs
    │   ├── print.rs
    │   ├── process
    │   │   ├── exec
    │   │   │   ├── elf.rs
    │   │   │   ├── mod.rs
    │   │   │   └── vdso.rs
    │   │   ├── mem_space
    │   │   │   ├── gap.rs
    │   │   │   ├── mapping.rs
    │   │   │   ├── mod.rs
    │   │   │   └── transaction.rs
    │   │   ├── mod.rs
    │   │   ├── pid.rs
    │   │   ├── rusage.rs
    │   │   ├── scheduler
    │   │   │   ├── mod.rs
    │   │   │   └── switch.rs
    │   │   ├── signal
    │   │   │   ├── mod.rs
    │   │   │   └── ucontext.rs
    │   │   └── user_desc.rs
    │   ├── selftest.rs
    │   ├── sync
    │   │   ├── atomic.rs
    │   │   ├── mod.rs
    │   │   ├── mutex.rs
    │   │   ├── once.rs
    │   │   ├── rcu.rs
    │   │   ├── rwlock.rs
    │   │   └── spinlock.rs
    │   ├── syscall
    │   │   ├── dirent.rs
    │   │   ├── execve.rs
    │   │   ├── fcntl.rs
    │   │   ├── fd.rs
    │   │   ├── fs.rs
    │   │   ├── getrandom.rs
    │   │   ├── host.rs
    │   │   ├── ioctl.rs
    │   │   ├── mem.rs
    │   │   ├── mod.rs
    │   │   ├── module.rs
    │   │   ├── mount.rs
    │   │   ├── pipe.rs
    │   │   ├── process.rs
    │   │   ├── select.rs
    │   │   ├── signal.rs
    │   │   ├── socket.rs
    │   │   ├── stat.rs
    │   │   ├── sync.rs
    │   │   ├── time.rs
    │   │   ├── user.rs
    │   │   ├── util
    │   │   │   ├── at.rs
    │   │   │   └── mod.rs
    │   │   └── wait.rs
    │   ├── time
    │   │   ├── clock.rs
    │   │   ├── hw
    │   │   │   ├── mod.rs
    │   │   │   ├── pit.rs
    │   │   │   └── rtc.rs
    │   │   ├── mod.rs
    │   │   ├── timer.rs
    │   │   └── unit.rs
    │   └── tty
    │   │   ├── ansi.rs
    │   │   ├── mod.rs
    │   │   ├── termios.rs
    │   │   └── vga.rs
    └── vdso
    │   ├── linker.ld
    │   ├── x86.s
    │   └── x86_64.s
├── macros
    ├── .gitignore
    ├── Cargo.lock
    ├── Cargo.toml
    ├── rustfmt.toml
    └── src
    │   ├── aml.rs
    │   ├── lib.rs
    │   └── util.rs
├── mod
    ├── build
    └── template
    │   ├── Cargo.toml
    │   ├── rust-toolchain.toml
    │   └── src
    │       └── mod.rs
├── rust-toolchain.toml
├── rustfmt.toml
└── utils
    ├── .gitignore
    ├── Cargo.lock
    ├── Cargo.toml
    ├── README.md
    └── src
        ├── boxed.rs
        ├── bytes.rs
        ├── collections
            ├── bitfield.rs
            ├── btreemap.rs
            ├── hashmap
            │   ├── hash.rs
            │   ├── mod.rs
            │   └── raw.rs
            ├── hashset.rs
            ├── id_allocator.rs
            ├── list.rs
            ├── mod.rs
            ├── path.rs
            ├── string.rs
            └── vec.rs
        ├── cpio.rs
        ├── errno.rs
        ├── lib.rs
        ├── limits.rs
        ├── math.rs
        ├── ptr
            ├── arc.rs
            ├── cow.rs
            └── mod.rs
        └── unsafe_mut.rs


/doc/.gitignore:
--------------------------------------------------------------------------------
1 | book
2 | mermaid.min.js
3 | mermaid-init.js
4 | 


--------------------------------------------------------------------------------
/doc/book.toml:
--------------------------------------------------------------------------------
 1 | [book]
 2 | authors = ["llenotre"]
 3 | language = "en"
 4 | multilingual = false
 5 | src = "src"
 6 | title = "Maestro Kernel"
 7 | 
 8 | [preprocessor.mermaid]
 9 | command = "mdbook-mermaid"
10 | 
11 | [output.html]
12 | additional-js = ["mermaid.min.js", "mermaid-init.js"]
13 | mathjax-support = true
14 | 


--------------------------------------------------------------------------------
/doc/license-header.txt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | 


--------------------------------------------------------------------------------
/doc/src/SUMMARY.md:
--------------------------------------------------------------------------------
 1 | # Summary
 2 | 
 3 | - [Introduction](./intro.md)
 4 | - [External Documentation](./external_doc.md)
 5 | 
 6 | # Getting started
 7 | 
 8 | - [Installer](./installer.md)
 9 | - [Build a system from scratch](./build.md)
10 | - [Debug](./debug.md)
11 | 
12 | # Booting
13 | 
14 | - [Booting](./booting.md)
15 | 
16 | # Display
17 | 
18 | - [TTY](./tty.md)
19 | 
20 | # Memory
21 | 
22 | - [Allocators](./memory/alloc.md)
23 | - [Memory map](./memory/mem_map.md)
24 | - [Memory space](./memory/mem_space.md)
25 | - [Tracing](./memory/tracing.md)
26 | 
27 | # Process
28 | 
29 | - [Process](./process.md)
30 | 
31 | # Device
32 | 
33 | - [Devices](./device.md)
34 | 
35 | # File
36 | 
37 | - [Filesystem](./file/fs.md)
38 |     - [tmpfs](./file/tmpfs.md)
39 |     - [procfs](./file/procfs.md)
40 |     - [sysfs](./file/sysfs.md)
41 | 
42 | # Userspace
43 | 
44 | - [Userspace](./userspace/exec.md)
45 | 	- [ELF](./userspace/elf.md)
46 | 	- [Script](./userspace/script.md)
47 | 
48 | # Modules
49 | 
50 | - [Module](./module.md)
51 | 


--------------------------------------------------------------------------------
/doc/src/booting.md:
--------------------------------------------------------------------------------
 1 | # Booting
 2 | 
 3 | The kernel booting sequence is supervised by the **Multiboot2** standard.
 4 | 
 5 | ### Command line arguments
 6 | 
 7 | Multiboot allows passing command line arguments to the kernel at boot. The following arguments are supported:
 8 | 
 9 | - `-root <major> <minor>` (required): Tells the major/minor version numbers of the VFS's root device
10 | - `-init <path>`: Tells the path of the binary to be run as the first process instead of the default path
11 | - `-silent`: Tells the kernel not to show logs on screen while booting
12 | 
13 | ## Memory remapping
14 | 
15 | The kernel is divided into two parts:
16 | - Booting stub, located at `0x100000` on virtual memory
17 | - Main kernel code, located at different positions depending on the architecture in virtual memory:
18 |   - **x86**: `0xc0200000`
19 |   - **x86_64**: `0xffff800000200000`
20 | 
21 | Because GRUB loads the whole kernel at `0x100000`, it is required to remap the memory to use the main code of the kernel. This is done through paging.
22 | 
23 | TODO: Add schematics of memory mapping
24 | 
25 | The mapping of memory at `0x100000` is removed later because it is not required anymore.
26 | 
27 | ## Init process
28 | 
29 | The init process is the first program to be run by the kernel, which is in charge of initializing the system.
30 | 
31 | The program must be located at `/sbin/init`, or another path if specified as a command line argument.
32 | 
33 | The init process has PID `1` and is running as the superuser (uid: `0`, gid: `0`). If this process is killed, the kernel panics.
34 | 


--------------------------------------------------------------------------------
/doc/src/debug.md:
--------------------------------------------------------------------------------
 1 | # Debug
 2 | 
 3 | This section describes debugging features integrated to the kernel.
 4 | 
 5 | 
 6 | 
 7 | ## Selftesting
 8 | 
 9 | Unit tests and integration tests are present in the kernel.
10 | 
11 | To run them, use the command:
12 | 
13 | ```sh
14 | cargo test
15 | ```
16 | 
17 | 
18 | 
19 | ## GDB
20 | 
21 | GDB can be attached to the kernel in order to debug it. To do so, run the script located at `scripts/gdb.sh`.
22 | 
23 | The script runs the kernel with QEMU, using the disk present in the file `qemu_disk` and automatically attaches GDB to it. To begin execution, just type the `continue` command on GDB.
24 | 
25 | 
26 | 
27 | ## Logging
28 | 
29 | The kernel can transmit logs to another machine (the host machine if running in a virtual machine) using the serial port.
30 | 
31 | On QEMU, logs can be saved to the `serial.log` file by setting the `QEMUFLAGS` environment variable:
32 | 
33 | ```
34 | QEMUFLAGS="-serial file:serial.log" cargo run
35 | ```
36 | 


--------------------------------------------------------------------------------
/doc/src/device.md:
--------------------------------------------------------------------------------
 1 | # Devices
 2 | 
 3 | Devices are represented by two types of files: Block Devices and Char Devices.
 4 | 
 5 | Each device file is also associated with a major and minor number, allowing to identify it.
 6 | 
 7 | Those files are usually present in the `/dev` directory.
 8 | 
 9 | Device type abbreviations:
10 | - C = Char Device
11 | - B = Block Device
12 | 
13 | The following sections describe devices that may be present on the system. This list may be extended by kernel modules and as such, doesn't include every possible devices.
14 | 
15 | 
16 | 
17 | ## Default devices list
18 | 
19 | The following devices are present on the system by default.
20 | 
21 | | Path           | Type | Major | Minor | Description                                                                                                                             |
22 | |----------------|------|-------|-------|-----------------------------------------------------------------------------------------------------------------------------------------|
23 | | `/dev/null`    | C    | `1`   | `3`   | This device does nothing. Reading from it returns EOF and writing to it discards the data                                               |
24 | | `/dev/zero`    | C    | `1`   | `5`   | Reading returns an infinite amount of zeros bytes and writing to it discards the data                                                   |
25 | | `/dev/random`  | C    | `1`   | `8`   | Reading returns random bytes and writing to it feeds the kernel's entropy pool. If not enough entropy is available, reading is blocking |
26 | | `/dev/urandom` | C    | `1`   | `9`   | Reading returns random bytes and writing to it feeds the kernel's entropy pool. Contrary to `/dev/random`, reading is never blocking    |
27 | | `/dev/kmsg`    | C    | `1`   | `11`  | Reading returns kernel logs and writing appends kernel logs                                                                             |
28 | | `/dev/tty`     | C    | `5`   | `0`   | Device representing the TTY of the current process                                                                                      |
29 | 
30 | 
31 | 
32 | ## Dynamic devices
33 | 
34 | This section describes devices that may or may not be present depending on the system's peripherals.
35 | 
36 | | Path        | Type | Major | Minor            | Description                                                                                                                                                                 |
37 | |-------------|------|-------|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
38 | | `/dev/sdX`  | B    | `8`   | `n * 16`         | A SCSI drive. `X` has to be replaced by a single letter. Each disk has its own unique letter. `n` is the number associated with the letter (`a` -> `0`, `b` -> `1`, etc...) |
39 | | `/dev/sdXN` | B    | `8`   | `n * 16 + N + 1` | A partition on a SCSI drive. This device works the same as the previous, except `N` is the partition number                                                                 |
40 | 


--------------------------------------------------------------------------------
/doc/src/external_doc.md:
--------------------------------------------------------------------------------
 1 | # External Documentation
 2 | 
 3 | This page lists the external documentation that is used for the development of the kernel.
 4 | 
 5 | # Hardware technical references
 6 | 
 7 | - [Intel® 64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html)
 8 | - [UEFI specification documents](https://uefi.org/uefi)
 9 | - [PCI Local Bus Specification](https://www.ics.uci.edu/~harris/ics216/pci/PCI_22.pdf)
10 | 
11 | # Software interfaces references
12 | 
13 | - [Multiboot2 Specification](https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html)
14 | - [POSIX Technical Standard Base Specifications](https://pubs.opengroup.org/onlinepubs/9799919799/)
15 | 
16 | ## ELF
17 | 
18 | - [Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification](https://refspecs.linuxfoundation.org/elf/elf.pdf)
19 | - [ELF-64 Object File Format](https://uclibc.org/docs/elf-64-gen.pdf)
20 | 
21 | ## System V
22 | 
23 | - [System V Application Binary Interface - Intel386 Architecture Processor Supplement](https://www.uclibc.org/docs/psABI-i386.pdf)
24 | - [System V Application Binary Interface AMD64 Architecture Processor Supplement](https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.95.pdf)
25 | 
26 | # Miscellaneous
27 | 
28 | - [OSDev](https://wiki.osdev.org/)
29 | 


--------------------------------------------------------------------------------
/doc/src/file/fs.md:
--------------------------------------------------------------------------------
 1 | # Filesystem
 2 | 
 3 | A filesystem is a representation of a files hierarchy on a storage device.
 4 | 
 5 | The following filesystems are natively supported:
 6 | - **ext2**: a common filesystem in UNIX environments. Now obsolete (to be replaced by **ext4**)
 7 | 
 8 | ## kernfs
 9 | 
10 | A **kernfs** is a special kind of filesystem that do not store any information on any storage device. Its purpose is to provide a file interface to easily transmit information to the userspace.
11 | 
12 | Native kernfs kinds include:
13 | - [tmpfs](tmpfs.md): storage for temporary files on RAM
14 | - [procfs](procfs.md): provides information about processes
15 | - [sysfs](sysfs.md): provides information about the system
16 | 
17 | ## Virtual FileSystem
18 | 
19 | The **VFS** is a filesystem that has no representation on any storage device. Rather, it is built from other filesystems that are assembled together to form the system's files hierarchy.
20 | 
21 | **Mounting** a filesystem is the action of adding a filesystem to the VFS so that it becomes accessible to users.
22 | 
23 | The directory on which a filesystem is mounted is called a **mountpoint**.
24 | 


--------------------------------------------------------------------------------
/doc/src/file/procfs.md:
--------------------------------------------------------------------------------
 1 | # procfs
 2 | 
 3 | The `procfs` is a filesystem providing information for each running processes. Its structure is based on the one from Linux.
 4 | 
 5 | Each process has its own directory at the root of the filesystem. The name of the directory is the PID of the process in decimal.
 6 | 
 7 | A process's directory contains files with information about the process.
 8 | 
 9 | TODO: list files
10 | 


--------------------------------------------------------------------------------
/doc/src/file/sysfs.md:
--------------------------------------------------------------------------------
1 | # sysfs
2 | 
3 | TODO
4 | 


--------------------------------------------------------------------------------
/doc/src/file/tmpfs.md:
--------------------------------------------------------------------------------
1 | # tmpfs
2 | 
3 | The **tmpfs** provides temporary storage on RAM for any file. It is usually mounted at the path `/tmp`.
4 | 
5 | Since files are stored in RAM, they are all removed when the system is shutdown on reboot.
6 | 
7 | The main goal is to provide fast access to files that do not require persistence.
8 | 


--------------------------------------------------------------------------------
/doc/src/installer.md:
--------------------------------------------------------------------------------
1 | # Installer
2 | 
3 | Since the kernel cannot run by itself, the [installer](https://github.com/maestro-os/maestro-install) can be used to build it.
4 | 
5 | The utility on the installer's repository produces an ISO file which can be run on a virtual or physical machine to install the operating system on it.
6 | 
7 | For more information, check the documentation of the installer on its repository.
8 | 


--------------------------------------------------------------------------------
/doc/src/intro.md:
--------------------------------------------------------------------------------
 1 | # Introduction
 2 | 
 3 | ## Overview
 4 | 
 5 | Maestro is a Unix-like kernel written in Rust. It follows the **POSIX** specifications.
 6 | 
 7 | This documentation is a global overview on the way the Maestro kernel and its interfaces work. It is not intended to be an exhaustive documentation.
 8 | 
 9 | ## License
10 | 
11 | The kernel and this documentation are distributed under the [AGPL-3.0 license](https://www.gnu.org/licenses/agpl-3.0.en.html).
12 | 


--------------------------------------------------------------------------------
/doc/src/memory/alloc.md:
--------------------------------------------------------------------------------
 1 | # Allocators
 2 | 
 3 | This page describes memory allocators that are implemented inside the kernel.
 4 | 
 5 | ## Buddy allocator
 6 | 
 7 | The buddy allocator is the primary allocator which provides memory pages to all other allocators.
 8 | 
 9 | This allocator takes most of the memory on the system and works by recursively dividing them in two until a block of the required size is available.
10 | 
11 | Freeing memory works the other way around, by merging adjacent free blocks.
12 | 
13 | More details are available on [Wikipedia](https://en.wikipedia.org/wiki/Buddy_memory_allocation).
14 | 
15 | Since this allocator provides at least one page of memory per allocation, smaller objects need another allocator to subdivide pages into usable chunks. This is the role of **malloc**.
16 | 
17 | ## malloc
18 | 
19 | The kernel has its own version of the `malloc` function to allow memory allocations internal to the kernel.
20 | 
21 | The implementation is a located in `kernel::memory::malloc`.
22 | 
23 | Functions:
24 | - `alloc`: Allocates the given amount of bytes and returns a pointer to the chunk
25 | - `realloc`: Changes the size of an allocation
26 | - `free`: Frees a previously allocated chunk
27 | 
28 | The allocator works using memory pages provided by the buddy allocator.
29 | 
30 | Allocated chunks are guaranteed to:
31 | - Be accessible from kernelspace
32 | - Not overlap with other chunks
33 | - Be aligned in memory
34 | 
35 | ### Safe interface
36 | 
37 | It is recommended to use the safe interface through the `Alloc` structure instead of the low-level functions described above.
38 | 
39 | ## vmem
40 | 
41 | Virtual memory allows the kernel to provide each process with its own memory space, independent of other processes.
42 | 
43 | Refer to the documentation of the target CPU architecture for details on the way virtual memory works.
44 | 


--------------------------------------------------------------------------------
/doc/src/memory/mem_map.md:
--------------------------------------------------------------------------------
 1 | # Memory map
 2 | 
 3 | The memory space of each process is divided into several chunks. Those chunks are described for each architecture in the following sections.
 4 | 
 5 | ## x86 (32-bit)
 6 | 
 7 | | Begin        | End          | Description                            |
 8 | |--------------|--------------|----------------------------------------|
 9 | | `0x00000000` | `0x00001000` | Not mapped, for the `NULL` pointer     |
10 | | `0x00001000` | `0xc0000000` | Userspace (program image, stack, heap) |
11 | | `0xc0000000` | end          | Kernel space                           |
12 | 
13 | ## x86_64
14 | 
15 | | Begin                | End                  | Description                            |
16 | |----------------------|----------------------|----------------------------------------|
17 | | `0x0000000000000000` | `0x0000000000001000` | Not mapped, for the `NULL` pointer     |
18 | | `0x0000000000001000` | `0x0000800000000000` | Userspace (program image, stack, heap) |
19 | | `0x0000800000000000` | `0xffff800000000000` | Canonical hole, cannot be used         |
20 | | `0xffff800000000000` | end                  | Kernel space                           |
21 | 


--------------------------------------------------------------------------------
/doc/src/memory/mem_space.md:
--------------------------------------------------------------------------------
 1 | # Memory space
 2 | 
 3 | A memory space is a virtual memory context on which reside one or more process. It allows isolation of processes from each others.
 4 | 
 5 | Some processes may share the same memory space, for example using the `clone` system call.
 6 | 
 7 | A memory space contains the following components:
 8 | - Memory mapping: a region of virtual memory in use
 9 | - Memory gap: a region of virtual memory which is free, ready for allocations
10 | 
11 | A process can interact with its memory space using system calls such as `mmap`, `munmap`, `mlock`, `munlock` and `mprotect`.
12 | 
13 | ## Lazy allocations
14 | 
15 | A memory mapping is supposed to point to a physical memory in order to work properly. However, allocating physical memory directly when the memory mapping is created or cloned takes significant resources that might not be used.
16 | 
17 | For example, when using the `fork` system call, the whole memory space has to be duplicated, often to be quickly followed by a call to `execve`, which removes the whole memory space.
18 | 
19 | To prevent this problem, physical memory is allocated lazily.
20 | 
21 | To do so, the kernel maps the virtual memory in read-only. Then, when an attempt to modify the memory (write) occurs, the CPU triggers a page fault, which can then be handled by the kernel to make the actual allocation
22 | 
23 | The following cases can occur:
24 | - simple allocation (example: `mmap`): The virtual memory is mapped to a default page which contains only zeros. When the kernel receives a page fault for this mapping, it allocates a new physical page and maps it at the appropriate location
25 | - duplication (example: `fork`): The virtual memory of the new memory space is mapped to the same physical memory as the original. Then writing is disabled on both. When a page fault is received, the kernel performs the same operation as the previous point, except the data present on the page is also copied.
26 | 
27 | Once the allocation has been made, the kernel enables writing permission on the mapping, then resume the execution. This procedure is totally transparent from the process's point of view.
28 | 


--------------------------------------------------------------------------------
/doc/src/memory/tracing.md:
--------------------------------------------------------------------------------
 1 | # Tracing
 2 | 
 3 | The `memtrace` feature allows to trace usage of memory allocators. This is a debug feature, so it is not meant to be used in production.
 4 | 
 5 | To use it, compile the kernel with the `memtrace` feature:
 6 | 
 7 | ```shell
 8 | cargo build --features memtrace
 9 | ```
10 | 
11 | When run, the kernel will then write tracing data to the **COM2** serial port.
12 | 
13 | This data can then be fed to [kern-profile](https://github.com/maestro-os/kern-profile) to generate a FlameGraph.
14 | 
15 | ## Data format
16 | 
17 | The output data is a series of samples. A sample represents an operation on the allocator.
18 | 
19 | The following operations exist:
20 | 
21 | | ID | Name    | Description                                    |
22 | |----|---------|------------------------------------------------|
23 | | 0  | alloc   | Allocate memory                                |
24 | | 1  | realloc | Resize a previously allocated region of memory |
25 | | 2  | free    | Frees a previously allocated region of memory  |
26 | 
27 | Each sample is written one after the other and has the following layout in memory:
28 | 
29 | | Offset      | Size         | Name   | Description                                          |
30 | |-------------|--------------|--------|------------------------------------------------------|
31 | | `0`         | `1`          | nlen   | The length of the name of the allocator              |
32 | | `1`         | `nlen`       | name   | The name of the allocator                            |
33 | | `nlen + 1`  | `1`          | op     | The ID of the operation (see table above)            |
34 | | `nlen + 2`  | `8`          | ptr    | The address of the region affected by the operation  |
35 | | `nlen + 10` | `8`          | size   | The new size of the region affected by the operation |
36 | | `nlen + 18` | `1`          | nframe | The number of frames in the callstack                |
37 | | `nlen + 19` | `nframe * 8` | frames | The pointers of the frames in the callstack          |
38 | 


--------------------------------------------------------------------------------
/doc/src/module.md:
--------------------------------------------------------------------------------
 1 | # Module
 2 | 
 3 | A kernel module allows to add a feature to the kernel at runtime.
 4 | 
 5 | This chapter describes how to write a kernel module.
 6 | 
 7 | ## Template
 8 | 
 9 | A basic kernel module contains the following files:
10 | 
11 | ```
12 | |- Cargo.toml
13 | |- Cargo.lock
14 | |- rust-toolchain.toml
15 | |- src/
16 |  |- mod.rs
17 | ```
18 | 
19 | These files are located in the `mod/template/` directory of the kernel's sources.
20 | 
21 | `Cargo.toml`:
22 | 
23 | ```toml
24 | {{#include ../../mod/template/Cargo.toml}}
25 | ```
26 | 
27 | `mod.rs`:
28 | 
29 | ```rust
30 | {{#include ../../mod/template/src/mod.rs}}
31 | ```
32 | 
33 | The `kernel` crate gives access to the kernel's functions.
34 | 
35 | The `kernel::module` macro allows to define the kernel module with its dependencies.
36 | 
37 | > **NOTE**: if the `kernel::module` declaration is not present, the module will not work
38 | 
39 | The following properties have to be taken into account when writing a module:
40 | - `init` is called once each times the module is loaded. The execution must be not block since it would freeze the system
41 | - `fini` can be called at all times and must free every resource allocated by the module
42 | 
43 | On success, `init` returns `true`. On failure, it returns `false`.
44 | 
45 | ## Versioning
46 | 
47 | Kernel module versioning is a small subset of the [SemVer](https://semver.org/) specification.
48 | 
49 | Versions MUST have the following format: `X.Y.Z` where:
50 | - `X` is a positive number (including zero) representing the *major version*
51 | - `Y` is a positive number (including zero) representing the *minor version*
52 | - `Z` is a positive number (including zero) representing the *patch version*
53 | 
54 | The same rules as the SemVer specification apply for those numbers.
55 | 
56 | ### Backus-Naur Form
57 | 
58 | ```
59 | <version> ::= <major> "." <minor> "." <patch>
60 | ```
61 | 
62 | ## Interface references
63 | 
64 | The references to the kernel's internals and module interfaces can be found [here](references/kernel/index.html).
65 | 
66 | ## Building
67 | 
68 | The procedure to build a kernel module is the following:
69 | - Build the kernel in debug or release mode (`--release`), depending on which profile you want
70 | - `cd` into the root of the module's source directory
71 | - Set environment variables:
72 |     - `PROFILE`: profile to build for (either `debug` or `release`). Default value: `debug`
73 |     - `ARCH`: architecture to build for (example: `x86`). Default value: `x86`
74 | - Build the module
75 | 
76 | Example:
77 | ```sh
78 | PROFILE="debug" ARCH="x86" ../maestro/mod/build
79 | ```
80 | 
81 | Then, the built module can be found at `target/<arch>/<profile>/lib<name>.so`
82 | 
83 | > **NOTE**: It is important that the specified profile and architecture match the compilation of the kernel, otherwise compilation will not work
84 | 


--------------------------------------------------------------------------------
/doc/src/process.md:
--------------------------------------------------------------------------------
 1 | # Process
 2 | 
 3 | A process is a program being executed by the kernel. Each process has a unique PID which is allocated at creation.
 4 | 
 5 | ## State
 6 | 
 7 | A process can have the following states:
 8 | 
 9 | | Name       | Associated character | Description                                                                              |
10 | |------------|----------------------|------------------------------------------------------------------------------------------|
11 | | `Running`  | R                    | The process is currently running or is ready to be resumed by the scheduler              |
12 | | `Sleeping` | S                    | The process is waiting on a resource to become available (usualy I/O or another process) |
13 | | `Stopped`  | T                    | The process is paused                                                                    |
14 | | `Zombie`   | Z                    | The process has been terminated and cannot resume, ever                                  |
15 | 
16 | The `Running` state is the only state in which a process can be executed.
17 | 
18 | The following state transitions are valid:
19 | 
20 | ```mermaid
21 | stateDiagram-v2
22 |     [*] --> Running
23 | 
24 |     Sleeping --> Running
25 |     Stopped --> Running
26 | 
27 |     Running --> Sleeping
28 |  
29 |     Running --> Stopped
30 |     Sleeping --> Stopped
31 |  
32 |     Stopped --> Zombie
33 |     Sleeping --> Zombie
34 |     Running --> Zombie
35 |     
36 |     Zombie --> [*]
37 | ```
38 | 
39 | ## Scheduler
40 | 
41 | The scheduler is a component that decide which process is running, and when.
42 | 
43 | The system triggers interruptions periodically in order to interrupt the current process, then the scheduler determines the next process to be run, and switches context to that process.
44 | 
45 | The frequency of interruption is determined by the number of processes in running state.
46 | 
47 | To determine the next process to be run, the scheduler uses different information such as state and priority of the process.
48 | 


--------------------------------------------------------------------------------
/doc/src/tty.md:
--------------------------------------------------------------------------------
 1 | # TTY
 2 | 
 3 | The TTY (TeleTypeWriter) is the main interface with the kernel.
 4 | 
 5 | The TTY (partially) supports:
 6 | - POSIX terminal interface ([Wikipedia](https://en.wikipedia.org/wiki/POSIX_terminal_interface))
 7 | - ANSI escape codes ([Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code))
 8 | 
 9 | If running with the VGA text mode, the TTY can only display the following characters:
10 | 
11 | ![VGA text mode characters](https://upload.wikimedia.org/wikipedia/commons/6/6d/Codepage-737.png)
12 | 


--------------------------------------------------------------------------------
/doc/src/userspace/elf.md:
--------------------------------------------------------------------------------
1 | # ELF
2 | 
3 | ELF (Executable and Linkable Format) is an executable format supported by the kernel, which can be used to represent programs.
4 | 
5 | The specification of this format can be found on the page [External Documentation](../external_doc.md).
6 | 


--------------------------------------------------------------------------------
/doc/src/userspace/exec.md:
--------------------------------------------------------------------------------
 1 | # Userspace
 2 | 
 3 | The userspace is the place where user programs run. It is meant to have an interface close to Linux.
 4 | 
 5 | A program running in userspace is initialized using the **System V ABI** specification (see [external documentation](../external_doc.md)).
 6 | 
 7 | ## System call
 8 | 
 9 | System calls are the main way for programs to communicate with the kernel.
10 | 
11 | The system call table can be found at the root of the module `kernel::syscall`.
12 | 
13 | ### ABI by architecture
14 | 
15 | **Note**: the **end** bound of errno ranges are exclusive
16 | 
17 | #### x86 (32 bits)
18 | 
19 | |              |                                          |
20 | |--------------|------------------------------------------|
21 | | Instruction  | `int 0x80`                               |
22 | | Syscall ID   | `eax`                                    |
23 | | Arguments    | `ebx`, `ecx`, `edx`, `esi`, `edi`, `ebp` |
24 | | Return value | `eax`                                    |
25 | | Errno range  | `-4095..0`                               |
26 | 
27 | #### x86_64
28 | 
29 | |              |                                        |
30 | |--------------|----------------------------------------|
31 | | Instruction  | `int 0x80`, `syscall`                  |
32 | | Syscall ID   | `rax`                                  |
33 | | Arguments    | `rdi`, `rsi`, `rdx`, `r10`, `r8`, `r9` |
34 | | Return value | `rax`                                  |
35 | | Errno range  | `-4095..0`                             |
36 | 
37 | ## Compatibility mode
38 | 
39 | The kernel supports running 32-bit programs on 64-bit kernels. The ABI is the same as kernels compiled for 32-bit.
40 | 


--------------------------------------------------------------------------------
/doc/src/userspace/script.md:
--------------------------------------------------------------------------------
 1 | # Script
 2 | 
 3 | A script can be run directly by the kernel by specifying its interpreter use a **shebang**.
 4 | 
 5 | The syntax of a shebang is the following:
 6 | 
 7 | ```
 8 | #!interpreter-path [optional-arg]
 9 | ```
10 | 
11 | The shebang is placed at the top of the script file.
12 | 
13 | Description:
14 | - `interpreter-path` is the path to the interpreter program. The interpreter can itself be a script, up to 4 recursions
15 | - `optional-arg` is an optional argument to be appended to the interpreter
16 | 


--------------------------------------------------------------------------------
/inttest/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | disk


--------------------------------------------------------------------------------
/inttest/Cargo.lock:
--------------------------------------------------------------------------------
 1 | # This file is automatically @generated by Cargo.
 2 | # It is not intended for manual editing.
 3 | version = 4
 4 | 
 5 | [[package]]
 6 | name = "inttest"
 7 | version = "0.1.0"
 8 | dependencies = [
 9 |  "libc",
10 |  "memmap2",
11 | ]
12 | 
13 | [[package]]
14 | name = "libc"
15 | version = "0.2.172"
16 | source = "registry+https://github.com/rust-lang/crates.io-index"
17 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
18 | 
19 | [[package]]
20 | name = "memmap2"
21 | version = "0.9.5"
22 | source = "registry+https://github.com/rust-lang/crates.io-index"
23 | checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
24 | dependencies = [
25 |  "libc",
26 | ]
27 | 


--------------------------------------------------------------------------------
/inttest/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "inttest"
 3 | version = "0.1.0"
 4 | edition = "2024"
 5 | 
 6 | [[bin]]
 7 | name = "inttest"
 8 | path = "src/main.rs"
 9 | 
10 | [[bin]]
11 | name = "init"
12 | path = "src/boot.rs"
13 | 
14 | [dependencies]
15 | libc = "0.2.172"
16 | memmap2 = "0.9.5"
17 | 


--------------------------------------------------------------------------------
/inttest/README.md:
--------------------------------------------------------------------------------
 1 | # Integration tests
 2 | 
 3 | Test suite for the kernel, made to be run by continuous integration.
 4 | 
 5 | The test suite reports its results through the serial port.
 6 | 
 7 | 
 8 | 
 9 | ## Build an image
10 | 
11 | To use the test suite, one must first build a disk image.
12 | 
13 | > **Note**: Building the image requires the command `debugfs`
14 | 
15 | This can be done with the `build.sh` script:
16 | ```sh
17 | ./build.sh
18 | ```
19 | 
20 | This script produces the `disk` file, which can then be used by QEMU with the following option:
21 | ```
22 | -drive file=disk,format=raw
23 | ```
24 | 


--------------------------------------------------------------------------------
/inttest/build.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | set -e
 4 | 
 5 | if [ -z "$TARGET" ]; then
 6 | 	export TARGET=x86_64-unknown-linux-musl
 7 | fi
 8 | 
 9 | # Build
10 | cargo build -Zbuild-std --target "$TARGET"
11 | 
12 | # Create disk and filesystem
13 | dd if=/dev/zero of=disk bs=1M count=1024
14 | mkfs.ext2 disk
15 | 
16 | # Fill filesystem
17 | debugfs -wf - disk <<EOF
18 | mkdir /dev
19 | mkdir /sbin
20 | write target/$TARGET/debug/init /sbin/init
21 | write target/$TARGET/debug/inttest /inttest
22 | EOF
23 | 


--------------------------------------------------------------------------------
/inttest/src/boot.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Boot stub for integration tests.
20 | //!
21 | //! This file exists to run the tests as a second process in order to retrieve the exit code, then
22 | //! shutdown the machine.
23 | 
24 | use std::{os::unix::process::ExitStatusExt, process::Command};
25 | 
26 | pub fn main() {
27 | 	let status = Command::new("/inttest").status().unwrap();
28 | 	if let Some(sig) = status.signal() {
29 | 		eprintln!("[KILLED] {sig}");
30 | 	}
31 | 	let cmd = if status.success() { -1 } else { -2 };
32 | 	unsafe {
33 | 		// Sync to disk
34 | 		libc::sync();
35 | 		// Shutdown
36 | 		libc::syscall(libc::SYS_reboot, 0xde145e83u32, 0x40367d6eu32, cmd, 0);
37 | 	}
38 | 	panic!("Shutdown failed!");
39 | }
40 | 


--------------------------------------------------------------------------------
/inttest/src/mount.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Filesystem mounting tests.
20 | 
21 | use crate::{log, util, util::TestResult};
22 | use std::{ffi::CString, fs, ptr::null};
23 | 
24 | pub fn mount(src: &str, target: &str, fstype: &str) -> TestResult {
25 | 	log!("Create directory");
26 | 	fs::create_dir_all(target)?;
27 | 	log!("Mount");
28 | 	let src = CString::new(src)?;
29 | 	let target = CString::new(target)?;
30 | 	let fstype = CString::new(fstype)?;
31 | 	util::mount(
32 | 		src.as_c_str(),
33 | 		target.as_c_str(),
34 | 		fstype.as_c_str(),
35 | 		0,
36 | 		null(),
37 | 	)?;
38 | 	Ok(())
39 | }
40 | 
41 | pub fn umount(target: &str) -> TestResult {
42 | 	let target = CString::new(target)?;
43 | 	util::umount(target.as_c_str())?;
44 | 	Ok(())
45 | }
46 | 


--------------------------------------------------------------------------------
/inttest/src/procfs.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! procfs filesystem testing.
20 | 
21 | use crate::{
22 | 	test_assert_eq,
23 | 	util::{TestError, TestResult},
24 | };
25 | use std::{collections::HashMap, env, env::current_dir, fs, os::unix::ffi::OsStrExt};
26 | 
27 | pub fn cwd() -> TestResult {
28 | 	let cwd = fs::read_link("/proc/self/cwd")?;
29 | 	test_assert_eq!(cwd, current_dir()?);
30 | 	Ok(())
31 | }
32 | 
33 | pub fn exe() -> TestResult {
34 | 	let exe = fs::read_link("/proc/self/exe")?;
35 | 	test_assert_eq!(exe.as_os_str().as_bytes(), b"/inttest");
36 | 	Ok(())
37 | }
38 | 
39 | pub fn cmdline() -> TestResult {
40 | 	let args0 = fs::read("/proc/self/cmdline")?;
41 | 	let args1 = env::args_os();
42 | 	for (a0, a1) in args0.split(|b| *b == b'\0').zip(args1) {
43 | 		test_assert_eq!(a0, a1.as_bytes());
44 | 	}
45 | 	Ok(())
46 | }
47 | 
48 | pub fn environ() -> TestResult {
49 | 	let environ = fs::read("/proc/self/environ")?;
50 | 	let args0 = environ
51 | 		.split(|b| *b == b'\0')
52 | 		.filter(|var| !var.is_empty())
53 | 		.map(|var| {
54 | 			let off = var
55 | 				.iter()
56 | 				.enumerate()
57 | 				.find(|(_, b)| **b == b'=')
58 | 				.map(|(i, _)| i)
59 | 				.ok_or_else(|| TestError("missing `=` for environment variable".to_owned()))?;
60 | 			let (name, value) = var.split_at(off);
61 | 			Ok((name, &value[1..]))
62 | 		})
63 | 		.collect::<Result<HashMap<_, _>, TestError>>()?;
64 | 	let args1: Vec<_> = env::vars_os().collect();
65 | 	let args1 = args1
66 | 		.iter()
67 | 		.map(|(name, val)| (name.as_bytes(), val.as_bytes()))
68 | 		.collect::<HashMap<_, _>>();
69 | 	test_assert_eq!(args0, args1);
70 | 	Ok(())
71 | }
72 | 


--------------------------------------------------------------------------------
/inttest/src/signal.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Signals testing.
20 | 
21 | use crate::{
22 | 	log,
23 | 	util::{TestResult, kill, signal},
24 | };
25 | use libc::{SIG_DFL, SIGINT, getpid};
26 | use std::{
27 | 	ffi::c_int,
28 | 	sync::atomic::{
29 | 		AtomicBool,
30 | 		Ordering::{Acquire, Release},
31 | 	},
32 | };
33 | 
34 | static HIT: AtomicBool = AtomicBool::new(false);
35 | 
36 | extern "C" fn signal_handler(_: c_int) {
37 | 	HIT.store(true, Release);
38 | }
39 | 
40 | pub fn handler() -> TestResult {
41 | 	log!("Register signal handler");
42 | 	signal(SIGINT, signal_handler as usize)?;
43 | 
44 | 	log!("Kill self");
45 | 	assert!(!HIT.load(Acquire));
46 | 	unsafe {
47 | 		kill(getpid(), SIGINT)?;
48 | 	}
49 | 	assert!(HIT.load(Acquire));
50 | 
51 | 	log!("Cleanup");
52 | 	HIT.store(false, Release);
53 | 	signal(SIGINT, SIG_DFL)?;
54 | 
55 | 	Ok(())
56 | }
57 | 


--------------------------------------------------------------------------------
/kernel/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [unstable]
 2 | build-std = ["core"]
 3 | 
 4 | [target.x86]
 5 | runner = "scripts/qemu.sh"
 6 | 
 7 | [target.x86_64]
 8 | runner = "scripts/qemu.sh"
 9 | 
10 | [build]
11 | # Set default target
12 | target = "arch/x86_64/x86_64.json"
13 | rustflags = [
14 |     "-Zexport-executable-symbols"
15 | ]
16 | 


--------------------------------------------------------------------------------
/kernel/.gitignore:
--------------------------------------------------------------------------------
 1 | # Configuration file
 2 | build-config.toml
 3 | 
 4 | # Compiled files
 5 | *.o
 6 | *.a
 7 | *.so
 8 | iso/
 9 | *.iso
10 | 
11 | # Random garbage
12 | *.gch
13 | *.swp
14 | 
15 | # Rust compilation files
16 | target/
17 | 
18 | # Log files
19 | *.log
20 | 
21 | # Disk files
22 | qemu_disk
23 | mnt/
24 | 


--------------------------------------------------------------------------------
/kernel/Cargo.toml:
--------------------------------------------------------------------------------
 1 | cargo-features = ["profile-rustflags"]
 2 | 
 3 | [package]
 4 | name = "maestro"
 5 | version = "0.1.0"
 6 | authors = ["llenotre <llenotre@student.42.fr>"]
 7 | edition = "2024"
 8 | build = "build/main.rs"
 9 | 
10 | [lib]
11 | name = "kernel"
12 | path = "src/kernel.rs"
13 | 
14 | # Export the kernel as executable
15 | [[bin]]
16 | name = "maestro"
17 | path = "src/bin.rs"
18 | 
19 | [dependencies]
20 | macros = { path = "../macros" }
21 | utils = { path = "../utils" }
22 | 
23 | [build-dependencies]
24 | cc = { version = "1.2.6", features = ["parallel"] }
25 | serde = { version = "1.0.217", features = ["derive"] }
26 | serde_json = "1.0.134"
27 | toml = "0.8.19"
28 | 
29 | [features]
30 | default = []
31 | memtrace = []
32 | strace = ["macros/strace"]
33 | 
34 | [lints.rust]
35 | unexpected_cfgs = { level = "warn", check-cfg = [
36 | 	"cfg(config_debug_storage_test)",
37 | 	"cfg(config_debug_qemu)",
38 | 	"cfg(config_debug_malloc_magic)",
39 | 	"cfg(config_debug_malloc_check)"
40 | ] }
41 | 
42 | [profile.release]
43 | panic = "abort"
44 | 
45 | [profile.dev]
46 | rustflags = [
47 | 	"-Cforce-frame-pointers=yes"
48 | ]
49 | 


--------------------------------------------------------------------------------
/kernel/README.md:
--------------------------------------------------------------------------------
 1 | # Kernel
 2 | 
 3 | ## Build
 4 | 
 5 | The configuration file located at `build-config.toml` allows to specify which features have to be enabled in the kernel.
 6 | 
 7 | A default configuration is available in the file `default.build-config.toml`.
 8 | If `build-config.toml` does not exist, the default configuration is used instead.
 9 | 
10 | The kernel can be built using the following commands:
11 | 
12 | ```sh
13 | cargo build               # Debug mode
14 | cargo build --release     # Release mode
15 | ```
16 | 
17 | The default architecture is `x86_64`. To specify another architecture, add the following parameter to the build command: `--target arch/<arch>/<arch>.json`, where `<arch>` is the selected architecture.
18 | 
19 | The list of available architectures can be retrieved by typing the command:
20 | 
21 | ```sh
22 | ls -1 arch/
23 | ```
24 | 
25 | 
26 | 
27 | ## Run
28 | 
29 | ### With QEMU
30 | 
31 | QEMU is the preferred virtual machine to test the kernel.
32 | 
33 | To install QEMU, type the following command:
34 | 
35 | Ubuntu/Debian:
36 | 
37 | ```sh
38 | apt install qemu
39 | ```
40 | 
41 | Arch Linux:
42 | 
43 | ```sh
44 | pacman -S qemu
45 | ```
46 | 
47 | A fully built operating system is required to run the system. This system must be present on a raw disk in the file `qemu_disk` at the root of the repository. The option `-drive file=qemu_disk,format=raw` is used on QEMU to reference the disk.
48 | 
49 | The kernel can be run using:
50 | 
51 | ```sh
52 | cargo run               # Debug mode
53 | cargo run --release     # Release mode
54 | ```
55 | 
56 | 
57 | #### Run unit tests
58 | 
59 | The following command runs unit tests in QEMU:
60 | 
61 | ```sh
62 | cargo test --lib
63 | ```
64 | 
65 | 
66 | 
67 | ## Documentation
68 | 
69 | The documentation of the kernel's interface for modules can be built using:
70 | 
71 | ```sh
72 | cargo doc
73 | ```
74 | 
75 | Then, it can be accessed at `target/<arch>/doc/kernel/index.html`, where `<arch>` is the architecture the kernel has been compiled for.
76 | 


--------------------------------------------------------------------------------
/kernel/arch/x86/linker.ld:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | /*
20 |  * The linker script for the x86 architecture.
21 |  *
22 |  * The kernel image is split into two parts:
23 |  * - The boot part, in lower memory (sections with the `.boot` prefix)
24 |  * - The kernel part, in higher memory, starting at 0xc0000000
25 |  *
26 |  * In the first boot stage of the kernel, the memory must be remapped so that
27 |  * the kernel image is relocated to higher memory.
28 |  * After running the kernel code, the booting code isn't useful anymore.
29 |  *
30 |  * Sections need to be aligned on the page boundary to be protected against
31 |  * writing (for those where it applies).
32 |  *
33 |  * BSS sections are located right after read-only sections to limit damages if
34 |  * the stack(s) they contain overflows.
35 |  */
36 | 
37 | ENTRY(multiboot_entry)
38 | 
39 | SECTIONS
40 | {
41 |     /* Boot stub sections */
42 | 	. = 0x100000;
43 | 
44 | 	.boot.text : ALIGN(4K)
45 | 	{
46 | 		*(.boot.text)
47 | 	}
48 | 
49 | 	.boot.data : ALIGN(4K)
50 | 	{
51 | 		*(.boot.data)
52 | 	}
53 | 
54 | 	.boot.stack : ALIGN(4K)
55 | 	{
56 | 		*(.boot.stack)
57 | 	}
58 | 
59 |     /* Kernel sections */
60 | 	. = 0xc0200000;
61 | 
62 | 	.text : AT (ADDR (.text) - 0xc0000000) ALIGN(4K)
63 | 	{
64 | 		*(.text*)
65 | 	}
66 | 
67 | 	.rodata : AT (ADDR (.rodata) - 0xc0000000) ALIGN(4K)
68 | 	{
69 | 		*(.rodata*)
70 | 	}
71 | 
72 |     /* Accessible to the userspace (readonly) */
73 | 	.user : AT (ADDR (.user) - 0xc0000000) ALIGN(4K)
74 | 	{
75 | 	    *(.user*)
76 | 	}
77 | 
78 | 	.bss : AT (ADDR (.bss) - 0xc0000000) ALIGN(4K)
79 | 	{
80 | 		*(COMMON)
81 | 		*(.bss*)
82 | 	}
83 | 
84 | 	.data : AT (ADDR (.data) - 0xc0000000) ALIGN(4K)
85 | 	{
86 | 		*(.data*)
87 | 	}
88 | }
89 | 


--------------------------------------------------------------------------------
/kernel/arch/x86/src/memcpy.s:
--------------------------------------------------------------------------------
 1 | # Code taken from musl. License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
 2 | 
 3 | .intel_syntax noprefix
 4 | 
 5 | .section .text
 6 | 
 7 | .global memcpy
 8 | .global __memcpy_fwd
 9 | .hidden __memcpy_fwd
10 | .type memcpy, @function
11 | 
12 | memcpy:
13 | __memcpy_fwd:
14 | 	push esi
15 | 	push edi
16 | 	mov edi, [esp + 12]
17 | 	mov esi, [esp + 16]
18 | 	mov ecx, [esp + 20]
19 | 	mov eax, edi
20 | 	cmp ecx, 4
21 | 	jc 1f
22 | 	test edi, 3
23 | 	jz 1f
24 | 2:
25 | 	movsb
26 | 	dec ecx
27 | 	test edi, 3
28 | 	jnz 2b
29 | 1:
30 | 	mov edx, ecx
31 | 	shr ecx, 2
32 | 	rep movsd
33 | 	and edx, 3
34 | 	jz 1f
35 | 2:
36 | 	movsb
37 | 	dec edx
38 | 	jnz 2b
39 | 1:
40 | 	pop edi
41 | 	pop esi
42 | 	ret
43 | 


--------------------------------------------------------------------------------
/kernel/arch/x86/src/memmove.s:
--------------------------------------------------------------------------------
 1 | # Code taken from musl. License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
 2 | 
 3 | .intel_syntax noprefix
 4 | 
 5 | .section .text
 6 | 
 7 | .global memmove
 8 | .type memmove, @function
 9 | 
10 | memmove:
11 |     mov eax, [esp + 4]
12 |     sub eax, [esp + 8]
13 |     cmp eax, [esp + 12]
14 | .hidden __memcpy_fwd
15 |     jae __memcpy_fwd
16 |     push esi
17 |     push edi
18 |     mov edi, [esp + 12]
19 |     mov esi, [esp + 16]
20 |     mov ecx, [esp + 20]
21 |     lea edi, [edi + ecx - 1]
22 |     lea esi, [esi + ecx - 1]
23 |     std
24 |     rep movsb
25 |     cld
26 |     lea eax, [edi + 1]
27 |     pop edi
28 |     pop esi
29 |     ret
30 | 


--------------------------------------------------------------------------------
/kernel/arch/x86/src/memset.s:
--------------------------------------------------------------------------------
 1 | # Code taken from musl. License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
 2 | 
 3 | .intel_syntax noprefix
 4 | 
 5 | .section .text
 6 | 
 7 | .global memset
 8 | .type memset, @function
 9 | 
10 | memset:
11 | 	mov ecx, [esp + 12]
12 | 	cmp ecx, 62
13 | 	ja 2f
14 | 
15 | 	mov dl, [esp + 8]
16 | 	mov eax, [esp + 4]
17 | 	test ecx, ecx
18 | 	jz 1f
19 | 
20 | 	mov dh, dl
21 | 
22 | 	mov [eax], dl
23 | 	mov [eax + ecx - 1], dl
24 | 	cmp ecx, 2
25 | 	jbe 1f
26 | 
27 | 	mov [eax + 1], dx
28 | 	mov [eax + ecx + -1-2], %dx
29 | 	cmp ecx, 6
30 | 	jbe 1f
31 | 
32 | 	shl edx, 16
33 | 	mov dl, [esp + 8]
34 | 	mov dh, [esp + 8]
35 | 
36 | 	mov [eax + 1+2], %edx
37 | 	mov [eax + ecx + -1-2-4], edx
38 | 	cmp ecx, 14
39 | 	jbe 1f
40 | 
41 | 	mov [eax + 1+2+4], edx
42 | 	mov [eax + 1+2+4+4], edx
43 | 	mov [eax + ecx + -1-2-4-8], edx
44 | 	mov [eax + ecx + -1-2-4-4], edx
45 | 	cmp ecx, 30
46 | 	jbe 1f
47 | 
48 | 	mov [eax + 1+2+4+8], edx
49 | 	mov [eax + 1+2+4+8+4], edx
50 | 	mov [eax + 1+2+4+8+8], edx
51 | 	mov [eax + 1+2+4+8+12], edx
52 | 	mov [eax + ecx + -1-2-4-8-16], edx
53 | 	mov [eax + ecx + -1-2-4-8-12], edx
54 | 	mov [eax + ecx + -1-2-4-8-8], edx
55 | 	mov [eax + ecx + -1-2-4-8-4], edx
56 | 
57 | 1:
58 |     ret
59 | 
60 | 2:
61 | 	movzb eax, [esp + 8]
62 | 	mov [esp + 12], edi
63 | 	imul eax, 0x1010101
64 | 	mov edi, [esp + 4]
65 | 	test edi, 15
66 | 	mov [edi + ecx - 4], eax
67 | 	jnz 2f
68 | 
69 | 1:
70 |     shr ecx, 2
71 | 	rep
72 | 	stosd
73 | 	mov eax, [esp + 4]
74 | 	mov edi, [esp + 12]
75 | 	ret
76 | 	
77 | 2:
78 |     xor edx, edx
79 | 	sub edx, edi
80 | 	and edx, 15
81 | 	mov [edi], eax
82 | 	mov [edi + 4], eax
83 | 	mov [edi + 8], eax
84 | 	mov [edi + 12], eax
85 | 	sub ecx, edx
86 | 	add edi, edx
87 | 	jmp 1b
88 | 


--------------------------------------------------------------------------------
/kernel/arch/x86/src/raw_copy.s:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | // Copy from/to userspace
20 | 
21 | .intel_syntax noprefix
22 | 
23 | .section .text
24 | 
25 | .global raw_copy
26 | .global copy_fault
27 | 
28 | // TODO can be optimized
29 | raw_copy:
30 | 	push esi
31 | 	push edi
32 | 
33 | 	mov edi, 12[esp]
34 | 	mov esi, 16[esp]
35 | 	mov ecx, 20[esp]
36 | 
37 | 	rep movsb
38 | 
39 | 	pop edi
40 | 	pop esi
41 | 	mov eax, 1
42 | 	ret
43 | 
44 | copy_fault:
45 | 	pop edi
46 | 	pop esi
47 | 	xor eax, eax
48 | 	ret
49 | 


--------------------------------------------------------------------------------
/kernel/arch/x86/x86.json:
--------------------------------------------------------------------------------
 1 | {
 2 | 	"arch": "x86",
 3 | 	"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
 4 | 	"disable-redzone": true,
 5 | 	"dynamic-linking": true,
 6 | 	"executables": true,
 7 | 	"features": "-mmx,-sse,-sse2,+soft-float",
 8 | 	"linker": "i686-elf-ld",
 9 | 	"linker-flavor": "ld",
10 | 	"llvm-target": "i686-unknown-none",
11 | 	"os": "none",
12 | 	"panic-strategy": "abort",
13 | 	"target-c-int-width": "32",
14 | 	"target-endian": "little",
15 | 	"target-pointer-width": "32",
16 | 	"rustc-abi": "x86-softfloat"
17 | }
18 | 


--------------------------------------------------------------------------------
/kernel/arch/x86_64/linker.ld:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | /*
20 |  * The linker script for the x86_64 architecture.
21 |  *
22 |  * For more information about the organization of this particular file, check
23 |  * the documentation in the linker script for the x86 architecture.
24 |  */
25 | 
26 | ENTRY(multiboot_entry)
27 | 
28 | SECTIONS
29 | {
30 | 	. = 0x100000;
31 | 
32 | 	.boot.text : ALIGN(4K)
33 | 	{
34 | 		*(.boot.text)
35 | 	}
36 | 
37 | 	.boot.data : ALIGN(4K)
38 | 	{
39 | 		*(.boot.data)
40 | 	}
41 | 
42 | 	.boot.stack : ALIGN(4K)
43 | 	{
44 | 		*(.boot.stack)
45 | 	}
46 | 
47 | 	. = 0xffff800000200000;
48 | 
49 | 	.text : AT (ADDR (.text) - 0xffff800000000000) ALIGN(4K)
50 | 	{
51 | 		*(.text*)
52 | 	}
53 | 
54 | 	.rodata : AT (ADDR (.rodata) - 0xffff800000000000) ALIGN(4K)
55 | 	{
56 | 		*(.rodata*)
57 | 	}
58 | 
59 | 	.user : AT (ADDR (.user) - 0xffff800000000000) ALIGN(4K)
60 | 	{
61 | 	    *(.user*)
62 | 	}
63 | 
64 | 	.bss : AT (ADDR (.bss) - 0xffff800000000000) ALIGN(4K)
65 | 	{
66 | 		*(COMMON)
67 | 		*(.bss*)
68 | 	}
69 | 
70 | 	.data : AT (ADDR (.data) - 0xffff800000000000) ALIGN(4K)
71 | 	{
72 | 		*(.data*)
73 | 	}
74 | }
75 | 


--------------------------------------------------------------------------------
/kernel/arch/x86_64/src/memcpy.s:
--------------------------------------------------------------------------------
 1 | # Code taken from musl. License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
 2 | 
 3 | .intel_syntax noprefix
 4 | 
 5 | .section .text
 6 | 
 7 | .global memcpy
 8 | .global __memcpy_fwd
 9 | .hidden __memcpy_fwd
10 | .type memcpy, @function
11 | 
12 | memcpy:
13 | __memcpy_fwd:
14 |     mov rax, rdi
15 |     cmp rdx, 8
16 |     jc 1f
17 |     test edi, 7
18 |     jz 1f
19 | 2:
20 |     movsb
21 |     dec rdx
22 |     test edi, 7
23 |     jnz 2b
24 | 1:
25 |     mov rcx, rdx
26 |     shr rcx, 3
27 |     rep movsq
28 |     and edx, 7
29 |     jz 1f
30 | 2:
31 |     movsb
32 |     dec edx
33 |     jnz 2b
34 | 1:
35 |     ret
36 | 


--------------------------------------------------------------------------------
/kernel/arch/x86_64/src/memmove.s:
--------------------------------------------------------------------------------
 1 | # Code taken from musl. License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
 2 | 
 3 | .intel_syntax noprefix
 4 | 
 5 | .section .text
 6 | 
 7 | .global memmove
 8 | .type memmove, @function
 9 | 
10 | memmove:
11 |     mov rax, rdi
12 |     sub rax, rsi
13 |     cmp rax, rdx
14 | .hidden __memcpy_fwd
15 |     jae __memcpy_fwd
16 |     mov rcx, rdx
17 |     lea rdi, [rdi + rdx - 1]
18 |     lea rsi, [rsi + rdx - 1]
19 |     std
20 |     rep movsb
21 |     cld
22 |     lea rax, [rdi + 1]
23 |     ret
24 | 


--------------------------------------------------------------------------------
/kernel/arch/x86_64/src/memset.s:
--------------------------------------------------------------------------------
 1 | # Code taken from musl. License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
 2 | 
 3 | .intel_syntax noprefix
 4 | 
 5 | .global memset
 6 | .type memset, @function
 7 | 
 8 | memset:
 9 |     movzb rax, sil
10 |     mov r8, 0x101010101010101
11 |     imul rax, r8
12 | 
13 |     cmp rdx, 126
14 |     ja 2f
15 | 
16 |     test edx, edx
17 |     jz 1f
18 | 
19 |     mov [rdi], sil
20 |     mov [rdi + rdx -1], sil
21 |     cmp edx, 2
22 |     jbe 1f
23 | 
24 |     mov [rdi + 1], ax
25 |     mov [rdi + rdx -1-2], ax
26 |     cmp edx, 6
27 |     jbe 1f
28 | 
29 |     mov [rdi + 1+2], eax
30 |     mov [rdi + rdx -1-2-4], eax
31 |     cmp edx, 14
32 |     jbe 1f
33 | 
34 |     mov [rdi + 1+2+4], rax
35 |     mov [rdi + rdx -1-2-4-8], rax
36 |     cmp edx, 30
37 |     jbe 1f
38 | 
39 |     mov [rdi + 1+2+4+8], rax
40 |     mov [rdi + 1+2+4+8+8], rax
41 |     mov [rdi + rdx -1-2-4-8-16], rax
42 |     mov [rdi + rdx -1-2-4-8-8], rax
43 |     cmp edx, 62
44 |     jbe 1f
45 | 
46 |     mov [rdi + 1+2+4+8+16], rax
47 |     mov [rdi + 1+2+4+8+16+8], rax
48 |     mov [rdi + 1+2+4+8+16+16], rax
49 |     mov [rdi + 1+2+4+8+16+24], rax
50 |     mov [rdi + rdx -1-2-4-8-16-32], rax
51 |     mov [rdi + rdx -1-2-4-8-16-24], rax
52 |     mov [rdi + rdx -1-2-4-8-16-16], rax
53 |     mov [rdi + rdx -1-2-4-8-16-8], rax
54 | 
55 | 1:
56 |     mov rax, rdi
57 |     ret
58 | 
59 | 2:
60 |     test edi, 15
61 |     mov r8, rdi
62 |     mov [rdi + rdx - 8], rax
63 |     mov rcx, rdx
64 |     jnz 2f
65 | 
66 | 1:
67 |     shr rcx, 3
68 |     rep
69 |     stosq
70 |     mov rax, r8
71 |     ret
72 | 
73 | 2:
74 |     xor edx, edx
75 |     sub edx, edi
76 |     and edx, 15
77 |     mov [rdi], rax
78 |     mov [rdi + 8], rax
79 |     sub rcx, rdx
80 |     add rdi, rdx
81 |     jmp 1b
82 | 


--------------------------------------------------------------------------------
/kernel/arch/x86_64/src/raw_copy.s:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | // Copy from/to userspace
20 | 
21 | .intel_syntax noprefix
22 | 
23 | .section .text
24 | 
25 | .global raw_copy
26 | .global copy_fault
27 | 
28 | // TODO can be optimized
29 | raw_copy:
30 |     mov rcx, rdx
31 | 	rep movsb
32 | 	mov rax, 1
33 | 	ret
34 | 
35 | copy_fault:
36 | 	xor rax, rax
37 | 	ret
38 | 


--------------------------------------------------------------------------------
/kernel/arch/x86_64/x86_64.json:
--------------------------------------------------------------------------------
 1 | {
 2 | 	"arch": "x86_64",
 3 | 	"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
 4 | 	"disable-redzone": true,
 5 | 	"dynamic-linking": true,
 6 | 	"executables": true,
 7 | 	"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
 8 | 	"linker": "x86_64-elf-ld",
 9 | 	"linker-flavor": "ld",
10 | 	"llvm-target": "x86_64-unknown-none",
11 | 	"os": "none",
12 | 	"panic-strategy": "abort",
13 | 	"target-c-int-width": "32",
14 | 	"target-endian": "little",
15 | 	"target-pointer-width": "64",
16 | 	"rustc-abi": "x86-softfloat"
17 | }
18 | 


--------------------------------------------------------------------------------
/kernel/build/config.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This file implements the configuration file for compilation.
20 | 
21 | use serde::Deserialize;
22 | use std::{fs, io};
23 | 
24 | /// The debug section of the configuration file.
25 | #[derive(Deserialize)]
26 | struct ConfigDebug {
27 | 	/// If enabled, the kernel tests storage.
28 | 	///
29 | 	/// **Warning**: this option is destructive for any data present on disks connected to the
30 | 	/// host.
31 | 	storage_test: bool,
32 | 
33 | 	/// If enabled, the kernel is compiled for QEMU. This feature is not *required* for QEMU but
34 | 	/// it can provide additional features.
35 | 	qemu: bool,
36 | 
37 | 	/// If enabled, the kernel places a magic number in malloc chunks to allow checking integrity.
38 | 	malloc_magic: bool,
39 | 	/// If enabled, the kernel checks integrity of memory allocations.
40 | 	///
41 | 	/// **Warning**: this options slows down the system significantly.
42 | 	malloc_check: bool,
43 | }
44 | 
45 | /// The compilation configuration.
46 | #[derive(Deserialize)]
47 | pub struct Config {
48 | 	/// Debug section.
49 | 	debug: ConfigDebug,
50 | }
51 | 
52 | impl Config {
53 | 	/// Reads the configuration file.
54 | 	pub fn read() -> io::Result<Self> {
55 | 		const FILE_DEFAULT: &str = "default.build-config.toml";
56 | 		const FILE: &str = "build-config.toml";
57 | 
58 | 		println!("cargo:rerun-if-changed={FILE_DEFAULT}");
59 | 		println!("cargo:rerun-if-changed={FILE}");
60 | 
61 | 		let config_str = match fs::read_to_string(FILE) {
62 | 			Ok(s) => s,
63 | 			// Fallback to default configuration file
64 | 			Err(e) if e.kind() == io::ErrorKind::NotFound => fs::read_to_string(FILE_DEFAULT)?,
65 | 			Err(e) => return Err(e),
66 | 		};
67 | 		toml::from_str(&config_str).map_err(|e| io::Error::other(e.to_string()))
68 | 	}
69 | 
70 | 	/// Sets the crate's cfg flags according to the configuration.
71 | 	pub fn set_cfg(&self, debug: bool) {
72 | 		if debug {
73 | 			if self.debug.storage_test {
74 | 				println!("cargo:rustc-cfg=config_debug_storage_test");
75 | 			}
76 | 			if self.debug.qemu {
77 | 				println!("cargo:rustc-cfg=config_debug_qemu");
78 | 			}
79 | 			if self.debug.malloc_magic {
80 | 				println!("cargo:rustc-cfg=config_debug_malloc_magic");
81 | 			}
82 | 			if self.debug.malloc_check {
83 | 				println!("cargo:rustc-cfg=config_debug_malloc_check");
84 | 			}
85 | 		}
86 | 	}
87 | }
88 | 


--------------------------------------------------------------------------------
/kernel/build/main.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The build script reads the configuration file, compiles required libraries and prepares for the
20 | //! compilation of the kernel.
21 | 
22 | pub mod compile;
23 | pub mod config;
24 | pub mod target;
25 | pub mod util;
26 | 
27 | use crate::{config::Config, target::Target};
28 | use std::{env, path::PathBuf, process::exit};
29 | 
30 | /// The environment passed to the build script.
31 | pub struct Env {
32 | 	/// The path to the root of the workspace.
33 | 	pub manifest_dir: PathBuf,
34 | 	/// The name of the profile used to compile the crate.
35 | 	pub profile: String,
36 | 	/// The optimization level, between `0` and `3` included.
37 | 	pub opt_level: u32,
38 | 	/// The name of the target architecture.
39 | 	pub arch: String,
40 | 	/// The path to the target file.
41 | 	pub target_path: PathBuf,
42 | }
43 | 
44 | impl Env {
45 | 	/// Reads the current environment.
46 | 	pub fn get() -> Self {
47 | 		let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
48 | 		let profile = env::var("PROFILE").unwrap();
49 | 		let opt_level = env::var("OPT_LEVEL").unwrap().parse().unwrap();
50 | 		// Unwrapping is safe because a default target is specified in `.cargo/config.toml`
51 | 		let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
52 | 		let target_path = manifest_dir.join(format!("arch/{arch}/{arch}.json"));
53 | 		Self {
54 | 			manifest_dir,
55 | 			profile,
56 | 			opt_level,
57 | 			arch,
58 | 			target_path,
59 | 		}
60 | 	}
61 | 
62 | 	/// Tells whether compiling in debug mode.
63 | 	pub fn is_debug(&self) -> bool {
64 | 		self.profile == "debug"
65 | 	}
66 | }
67 | 
68 | fn main() {
69 | 	// Read config
70 | 	let env = Env::get();
71 | 	let target = Target::from_env(&env).unwrap_or_else(|e| {
72 | 		eprintln!("Cannot retrieve target: {e}");
73 | 		exit(1);
74 | 	});
75 | 	let config = Config::read().unwrap_or_else(|e| {
76 | 		eprintln!("Failed to read build configuration file: {e}");
77 | 		exit(1);
78 | 	});
79 | 	config.set_cfg(env.is_debug());
80 | 	// Compile
81 | 	compile::compile_c(&env, &target).unwrap_or_else(|e| {
82 | 		eprintln!("Compilation failed: {e}");
83 | 		exit(1);
84 | 	});
85 | 	compile::compile_vdso(&env, &target).unwrap_or_else(|e| {
86 | 		eprintln!("vDSO compilation failed: {e}");
87 | 		exit(1);
88 | 	});
89 | 	// Add the linker script
90 | 	println!(
91 | 		"cargo:rerun-if-changed={}",
92 | 		target.get_linker_script_path().display()
93 | 	);
94 | 	println!(
95 | 		"cargo:rustc-link-arg=-T{}",
96 | 		target.get_linker_script_path().display()
97 | 	);
98 | }
99 | 


--------------------------------------------------------------------------------
/kernel/build/target.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Compilation target information.
20 | 
21 | use crate::Env;
22 | use serde::Deserialize;
23 | use std::{fs, io, path::PathBuf};
24 | 
25 | /// The content of the target JSON file.
26 | ///
27 | /// This structure contains only the fields that are of interest.
28 | #[derive(Deserialize)]
29 | struct TargetFile {
30 | 	/// The LLVM target triplet.
31 | 	#[serde(rename = "llvm-target")]
32 | 	llvm_target: String,
33 | }
34 | 
35 | /// A build target.
36 | pub struct Target<'s> {
37 | 	/// The name of the target.
38 | 	pub name: &'s str,
39 | 	/// The target triplet.
40 | 	pub triplet: String,
41 | }
42 | 
43 | impl<'s> Target<'s> {
44 | 	/// Returns the selected triplet according to the environment.
45 | 	pub fn from_env(env: &'s Env) -> io::Result<Self> {
46 | 		// Read and parse target file
47 | 		let content = fs::read_to_string(&env.target_path)?;
48 | 		let content: TargetFile = serde_json::from_str(&content).map_err(io::Error::from)?;
49 | 		Ok(Self {
50 | 			name: &env.arch,
51 | 			triplet: content.llvm_target,
52 | 		})
53 | 	}
54 | 
55 | 	/// Returns the path to the linker script of the target.
56 | 	pub fn get_linker_script_path(&self) -> PathBuf {
57 | 		PathBuf::from(format!("arch/{}/linker.ld", self.name))
58 | 	}
59 | 
60 | 	/// Returns the path to the directory containing target-specific sources.
61 | 	pub fn src(&self) -> PathBuf {
62 | 		PathBuf::from(format!("arch/{}/src/", self.name))
63 | 	}
64 | 
65 | 	/// Returns the name of the architecture for the compatibility vDSO, if any.
66 | 	pub fn compat_vdso(&self) -> Option<&str> {
67 | 		(self.name == "x86_64").then_some("x86")
68 | 	}
69 | }
70 | 


--------------------------------------------------------------------------------
/kernel/build/util.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Build script utilities
20 | 
21 | use std::{
22 | 	ffi::OsStr,
23 | 	fs, io,
24 | 	path::{Path, PathBuf},
25 | };
26 | 
27 | fn list_c_files_impl(dir: &Path, paths: &mut Vec<PathBuf>) -> io::Result<()> {
28 | 	let dir = match fs::read_dir(dir) {
29 | 		Ok(dir) => dir,
30 | 		Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(()),
31 | 		Err(e) => return Err(e),
32 | 	};
33 | 	for e in dir {
34 | 		let e = e?;
35 | 		let e_path = e.path();
36 | 		let e_type = e.file_type()?;
37 | 		if e_type.is_file() {
38 | 			let ext = e_path.extension().and_then(OsStr::to_str);
39 | 			if !matches!(ext, Some("c" | "s")) {
40 | 				continue;
41 | 			}
42 | 			paths.push(e_path);
43 | 		} else if e_type.is_dir() {
44 | 			list_c_files_impl(&e_path, paths)?;
45 | 		}
46 | 	}
47 | 	Ok(())
48 | }
49 | 
50 | /// Lists paths to C and assembly files.
51 | pub fn list_c_files(dir: &Path) -> io::Result<Vec<PathBuf>> {
52 | 	let mut paths = vec![];
53 | 	list_c_files_impl(dir, &mut paths)?;
54 | 	Ok(paths)
55 | }
56 | 


--------------------------------------------------------------------------------
/kernel/ci/test.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | set -e
 4 | 
 5 | export QEMUFLAGS="-nographic -monitor none -serial stdio"
 6 | 
 7 | cp default.build-config.toml build-config.toml
 8 | sed -i 's/^qemu = false$/qemu = true/' build-config.toml
 9 | 
10 | case $1 in
11 | 	self)
12 | 		cargo test --lib $CARGOFLAGS
13 | 		;;
14 | 	int)
15 | 		cargo run $CARGOFLAGS
16 | 
17 | 		# Check filesystem integrity
18 | 		# FIXME: the clock currently starts at the timestamp zero, which causes fsck to detect errors due to the low value for dtime
19 | 		#fsck.ext2 -fnv qemu_disk
20 | 		# Check persistence
21 | 		echo 'Check `/persistent` exists'
22 | 		echo 'cat /persistent' | debugfs -f - qemu_disk 2>&1 | grep 'persistence OK'
23 | 		;;
24 | 	*)
25 | 		>&2 echo "Invalid tests kind"
26 | 		exit 1
27 | 		;;
28 | esac
29 | 


--------------------------------------------------------------------------------
/kernel/default.build-config.toml:
--------------------------------------------------------------------------------
 1 | # This is the default configuration for the kernel compilation.
 2 | # To setup a configuration, copy this file under the name `build-config.toml`, then modify it
 3 | 
 4 | 
 5 | 
 6 | # These options are only enabled when compiling in debug mode
 7 | [debug]
 8 | # If enabled, the kernel tests storage.
 9 | #
10 | # **Warning**: this option is destructive for any data present on disks connected to the
11 | # host.
12 | storage_test = false
13 | 
14 | # If enabled, the kernel is compiled for QEMU. This feature is not *required* for QEMU but
15 | # it can provide additional features. On panic, the kernel will shut down the virtual machine.
16 | qemu = false
17 | 
18 | # If enabled, the kernel places a magic number in malloc chunks to allow checking integrity.
19 | malloc_magic = false
20 | # If enabled, the kernel checks integrity of memory allocations.
21 | #
22 | # **Warning**: this options slows down the system significantly.
23 | malloc_check = false
24 | 


--------------------------------------------------------------------------------
/kernel/grub.cfg:
--------------------------------------------------------------------------------
1 | menuentry "Maestro" {
2 | 	multiboot2 /boot/maestro -root 8 0
3 | }
4 | 
5 | set default=0
6 | set timeout=0
7 | 


--------------------------------------------------------------------------------
/kernel/scripts/gdb.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | # This script allows to run gdb to debug the kernel using QEMU.
 4 | 
 5 | # Environment variables:
 6 | # - ARCH: specifies the architecture to build for
 7 | # - AUX_ELF: specifies the path to an auxiliary ELF file whose symbols will be added to gdb
 8 | 
 9 | if [ -z "$ARCH" ]; then
10 |   ARCH="x86_64"
11 | fi
12 | 
13 | cargo build $CARGOFLAGS --target arch/$ARCH/$ARCH.json
14 | 
15 | export QEMUFLAGS="$QEMUFLAGS -s -S -d int"
16 | setsid cargo run $CARGOFLAGS --target arch/$ARCH/$ARCH.json >qemu.log 2>&1 &
17 | QEMU_PID=$!
18 | 
19 | KERN_PATH="target/$ARCH/debug/maestro"
20 | 
21 | if ! [ -z "$AUX_ELF" ]; then
22 | 	gdb $KERN_PATH -ex 'target remote :1234' -ex 'set confirm off' -ex 'add-symbol-file -o $AUX_ELF' -ex 'set confirm on'
23 | else
24 | 	gdb $KERN_PATH -ex 'target remote :1234'
25 | fi
26 | 
27 | kill -- -$QEMU_PID
28 | 


--------------------------------------------------------------------------------
/kernel/scripts/link_partitions.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | 
 3 | # This script links partitions from the partitions table on the disk `qemu_disk` to device files in order to mount them
 4 | 
 5 | export IFS='
 6 | '
 7 | 
 8 | SECTOR_SIZE=512
 9 | 
10 | for p in $(fdisk -l qemu_disk | grep '^qemu_disk'); do
11 | 	NAME=$(echo $p | awk '{print $1}')
12 | 	START=$(echo $p | awk '{print $2}')
13 | 	END=$(echo $p | awk '{print $3}')
14 | 	SIZE=$(($END - $START))
15 | 
16 | 	DEV=$(losetup -o $(($START * $SECTOR_SIZE)) --sizelimit $(($SIZE * $SECTOR_SIZE)) --sector-size $SECTOR_SIZE --show -f qemu_disk)
17 | 	echo "$NAME linked as $DEV (offset: $(($START * $SECTOR_SIZE)); size: $(($SIZE * $SECTOR_SIZE)))"
18 | done
19 | 


--------------------------------------------------------------------------------
/kernel/scripts/qemu.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | # Runs the kernel in QEMU. This script is meant to be used through `cargo`
 4 | 
 5 | if [ -z "$ARCH" ]; then
 6 |   ARCH="x86_64"
 7 | fi
 8 | 
 9 | case $ARCH in
10 | 	"x86")
11 | 		QEMU=qemu-system-i386
12 | 		;;
13 | 	"x86_64")
14 | 		QEMU=qemu-system-x86_64
15 | 		;;
16 | 	*)
17 | 		>&2 echo "Invalid architecture '$ARCH'"
18 | 		exit 1
19 | 		;;
20 | esac
21 | 
22 | # Build ISO
23 | 
24 | mkdir -p iso/boot/grub
25 | cp $1 iso/boot/maestro
26 | cp grub.cfg iso/boot/grub
27 | grub-mkrescue -o kernel.iso iso
28 | 
29 | # Run the kernel
30 | 
31 | export QEMUDISK=qemu_disk
32 | export QEMUFLAGS="-device isa-debug-exit,iobase=0xf4,iosize=0x04 $QEMUFLAGS"
33 | if [ -f $QEMUDISK ]; then
34 |   QEMUFLAGS="-drive file=$QEMUDISK,format=raw $QEMUFLAGS"
35 | fi
36 | 
37 | $QEMU -cdrom kernel.iso $QEMUFLAGS
38 | EXIT=$?
39 | 
40 | if [ "$EXIT" -ne 33 ]; then
41 | 	exit 1
42 | fi
43 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/aml/named_obj.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! TODO doc
20 | 
21 | use super::{AMLParseable, Error};
22 | use macros::Parseable;
23 | 
24 | /// TODO doc
25 | #[derive(Parseable)]
26 | pub enum NamedObj {
27 | 	// TODO
28 | }
29 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/aml/namespace_modifier.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! TODO doc
20 | 
21 | use super::{AMLParseable, Error};
22 | use macros::Parseable;
23 | 
24 | /// TODO doc
25 | #[derive(Parseable)]
26 | pub struct DefAlias {
27 | 	// TODO
28 | }
29 | 
30 | /// TODO doc
31 | #[derive(Parseable)]
32 | pub struct DefName {
33 | 	// TODO
34 | }
35 | 
36 | /// TODO doc
37 | #[derive(Parseable)]
38 | pub struct DefScope {
39 | 	// TODO
40 | }
41 | 
42 | /// TODO doc
43 | #[allow(clippy::enum_variant_names)]
44 | #[derive(Parseable)]
45 | pub enum NameSpaceModifierObj {
46 | 	DefAlias(DefAlias),
47 | 	DefName(DefAlias),
48 | 	DefScope(DefAlias),
49 | }
50 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/aml/term_obj.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! TODO doc
20 | 
21 | use super::{
22 | 	AMLParseable, Error, named_obj::NamedObj, namespace_modifier::NameSpaceModifierObj,
23 | 	type1_opcode::Type1Opcode, type2_opcode::Type2Opcode,
24 | };
25 | use macros::Parseable;
26 | 
27 | /// TODO doc
28 | #[derive(Parseable)]
29 | pub enum Object {
30 | 	NameSpaceModifierObj(NameSpaceModifierObj),
31 | 	NamedObj(NamedObj),
32 | }
33 | 
34 | /// TODO doc
35 | #[derive(Parseable)]
36 | pub enum TermObject {
37 | 	Object(Object),
38 | 	Type1Opcode(Type1Opcode),
39 | 	Type2Opcode(Type2Opcode),
40 | }
41 | 
42 | /// TODO doc
43 | #[derive(Parseable)]
44 | pub struct TermList {
45 | 	// TODO objects: Vec<TermObject>,
46 | }
47 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/aml/type1_opcode.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! TODO doc
20 | 
21 | use super::{AMLParseable, Error};
22 | use macros::Parseable;
23 | 
24 | /// TODO doc
25 | #[derive(Parseable)]
26 | pub enum Type1Opcode {
27 | 	// TODO
28 | }
29 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/aml/type2_opcode.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! TODO doc
20 | 
21 | use super::{AMLParseable, Error};
22 | use macros::Parseable;
23 | 
24 | /// TODO doc
25 | #[derive(Parseable)]
26 | pub enum Type2Opcode {
27 | 	// TODO
28 | }
29 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/dsdt.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The DSDT (Differentiated System Description Table) provides information about supported power
20 | //! events.
21 | //!
22 | //! This table contains AML code which has to be parsed and executed to retrieve the required
23 | //! information.
24 | 
25 | use super::{Table, TableHdr};
26 | use core::mem::size_of;
27 | 
28 | /// The Differentiated System Description Table.
29 | #[repr(C)]
30 | #[derive(Debug)]
31 | pub struct Dsdt {
32 | 	/// The table's header.
33 | 	pub header: TableHdr,
34 | 	/// The definition of the AML code.
35 | 	definition_block: [u8],
36 | }
37 | 
38 | impl Dsdt {
39 | 	/// Returns a slice to the AML code.
40 | 	pub fn get_aml(&self) -> &[u8] {
41 | 		let code_len = self.header.length as usize - size_of::<TableHdr>();
42 | 		&self.definition_block[..code_len]
43 | 	}
44 | }
45 | 
46 | impl Table for Dsdt {
47 | 	const SIGNATURE: &'static [u8; 4] = b"DSDT";
48 | }
49 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/madt.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! ACPI's Multiple APIC Description Table (MADT) handling.
20 | 
21 | use super::{Table, TableHdr};
22 | use core::{ffi::c_void, hint::likely};
23 | 
24 | /// The offset of the entries in the MADT.
25 | const ENTRIES_OFF: usize = 0x2c;
26 | 
27 | /// Indicates that the system also has a PC-AT-compatible dual-8259 setup (which
28 | /// must be disabled when enabling ACPI APIC).
29 | const PCAT_COMPAT: u32 = 0b1;
30 | 
31 | /// The Multiple APIC Description Table.
32 | #[repr(C)]
33 | #[derive(Debug)]
34 | pub struct Madt {
35 | 	/// The table's header.
36 | 	pub header: TableHdr,
37 | 
38 | 	/// The physical address at which each process can access its local
39 | 	/// interrupt controller.
40 | 	local_apic_addr: u32,
41 | 	/// APIC flags.
42 | 	flags: u32,
43 | }
44 | 
45 | impl Madt {
46 | 	/// Returns an iterator over each entry of the MADT.
47 | 	pub fn entries(&self) -> EntriesIterator {
48 | 		EntriesIterator {
49 | 			madt: self,
50 | 			cursor: 0,
51 | 		}
52 | 	}
53 | }
54 | 
55 | impl Table for Madt {
56 | 	const SIGNATURE: &'static [u8; 4] = b"APIC";
57 | }
58 | 
59 | /// Represents an MADT entry header.
60 | #[repr(C)]
61 | #[derive(Debug)]
62 | pub struct EntryHeader {
63 | 	/// The entry type.
64 | 	pub entry_type: u8,
65 | 	/// The entry length.
66 | 	pub length: u8,
67 | }
68 | 
69 | /// Iterator over MADT entries.
70 | pub struct EntriesIterator<'m> {
71 | 	madt: &'m Madt,
72 | 	/// Cursor.
73 | 	cursor: usize,
74 | }
75 | 
76 | impl<'m> Iterator for EntriesIterator<'m> {
77 | 	type Item = &'m EntryHeader;
78 | 
79 | 	fn next(&mut self) -> Option<Self::Item> {
80 | 		let entries_len = self.madt.header.length as usize - ENTRIES_OFF;
81 | 		if likely(self.cursor < entries_len) {
82 | 			let entry = unsafe {
83 | 				let ptr = (self as *const _ as *const c_void).add(ENTRIES_OFF + self.cursor)
84 | 					as *const EntryHeader;
85 | 				&*ptr
86 | 			};
87 | 			self.cursor += entry.length as usize;
88 | 			Some(entry)
89 | 		} else {
90 | 			None
91 | 		}
92 | 	}
93 | }
94 | 


--------------------------------------------------------------------------------
/kernel/src/acpi/rsdt.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module handles ACPI's Root System Description Table (RSDT).
20 | 
21 | use super::{Table, TableHdr};
22 | use core::{mem::size_of, ptr, ptr::Pointee, slice};
23 | 
24 | /// The Root System Description Table.
25 | #[repr(C)]
26 | #[derive(Debug)]
27 | pub struct Rsdt {
28 | 	/// The table's header.
29 | 	pub header: TableHdr,
30 | }
31 | 
32 | // TODO XSDT
33 | 
34 | impl Rsdt {
35 | 	/// Iterates over every ACPI tables.
36 | 	pub fn tables(&self) -> impl Iterator<Item = &TableHdr> {
37 | 		let entries_len = self.header.length as usize - size_of::<Rsdt>();
38 | 		let entries_count = entries_len / size_of::<u32>();
39 | 		unsafe {
40 | 			let entries_start = (self as *const Self).add(1) as *const u32;
41 | 			slice::from_raw_parts(entries_start, entries_count)
42 | 				.iter()
43 | 				.map(|p| &*ptr::with_exposed_provenance(*p as usize))
44 | 		}
45 | 	}
46 | 
47 | 	/// Returns a reference to the ACPI table with type `T`.
48 | 	///
49 | 	/// If the table does not exist, the function returns `None`.
50 | 	///
51 | 	/// If the table is invalid, the function panics.
52 | 	pub fn get_table<T: Table>(&self) -> Option<&T> {
53 | 		let hdr = self.tables().find(|hdr| hdr.signature == *T::SIGNATURE)?;
54 | 		if !hdr.check::<T>() {
55 | 			panic!("APCI: invalid table for signature {:?}", hdr.signature)
56 | 		}
57 | 		Some(unsafe { &*(hdr as *const _ as *const T) })
58 | 	}
59 | 
60 | 	/// Returns a reference to the ACPI table with type `T`.
61 | 	///
62 | 	/// The table must be `Unsized`.
63 | 	///
64 | 	/// If the table doesn't exist, the function returns `None`.
65 | 	pub fn get_table_unsized<T: Table + ?Sized + Pointee<Metadata = usize>>(&self) -> Option<&T> {
66 | 		let hdr = self.tables().find(|hdr| hdr.signature == *T::SIGNATURE)?;
67 | 		if !hdr.check::<T>() {
68 | 			panic!("APCI: invalid table for signature {:?}", hdr.signature)
69 | 		}
70 | 		Some(unsafe {
71 | 			let ptr = ptr::from_raw_parts::<T>(hdr as *const _ as *const (), hdr.length as usize);
72 | 			&*ptr
73 | 		})
74 | 	}
75 | }
76 | 
77 | impl Table for Rsdt {
78 | 	const SIGNATURE: &'static [u8; 4] = b"RSDT";
79 | }
80 | 


--------------------------------------------------------------------------------
/kernel/src/arch/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Architecture-specific **Hardware Abstraction Layers** (HAL).
20 | 
21 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
22 | pub mod x86;
23 | 
24 | /// The name of the current CPU architecture.
25 | pub const ARCH: &str = {
26 | 	#[cfg(target_arch = "x86")]
27 | 	{
28 | 		"x86"
29 | 	}
30 | 	#[cfg(target_arch = "x86_64")]
31 | 	{
32 | 		"x86_64"
33 | 	}
34 | };
35 | 


--------------------------------------------------------------------------------
/kernel/src/arch/x86/io.rs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright 2024 Luc Lenôtre
  3 |  *
  4 |  * This file is part of Maestro.
  5 |  *
  6 |  * Maestro is free software: you can redistribute it and/or modify it under the
  7 |  * terms of the GNU General Public License as published by the Free Software
  8 |  * Foundation, either version 3 of the License, or (at your option) any later
  9 |  * version.
 10 |  *
 11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
 12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 14 |  *
 15 |  * You should have received a copy of the GNU General Public License along with
 16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
 17 |  */
 18 | 
 19 | //! The I/O functions allow to communicate with the other components on the
 20 | //! system.
 21 | 
 22 | use core::arch::asm;
 23 | 
 24 | /// Inputs a byte from the specified port.
 25 | ///
 26 | /// # Safety
 27 | ///
 28 | /// Reading from an invalid port has an undefined behaviour.
 29 | ///
 30 | /// This function is not thread safe.
 31 | #[inline(always)]
 32 | pub unsafe fn inb(port: u16) -> u8 {
 33 | 	let ret: i8;
 34 | 	asm!("in al, dx", out("al") ret, in("dx") port);
 35 | 
 36 | 	ret as _
 37 | }
 38 | 
 39 | /// Inputs a word from the specified port.
 40 | ///
 41 | /// # Safety
 42 | ///
 43 | /// Reading from an invalid port has an undefined behaviour.
 44 | ///
 45 | /// This function is not thread safe.
 46 | #[inline(always)]
 47 | pub unsafe fn inw(port: u16) -> u16 {
 48 | 	let ret: i16;
 49 | 	asm!("in ax, dx", out("ax") ret, in("dx") port);
 50 | 
 51 | 	ret as _
 52 | }
 53 | 
 54 | /// Inputs a long from the specified port.
 55 | ///
 56 | /// # Safety
 57 | ///
 58 | /// Reading from an invalid port has an undefined behaviour.
 59 | ///
 60 | /// This function is not thread safe.
 61 | #[inline(always)]
 62 | pub unsafe fn inl(port: u16) -> u32 {
 63 | 	let ret: i32;
 64 | 	asm!("in eax, dx", out("eax") ret, in("dx") port);
 65 | 
 66 | 	ret as _
 67 | }
 68 | 
 69 | /// Outputs a byte to the specified port.
 70 | ///
 71 | /// # Safety
 72 | ///
 73 | /// Writing to an invalid port has an undefined behaviour.
 74 | ///
 75 | /// This function is not thread safe.
 76 | #[inline(always)]
 77 | pub unsafe fn outb(port: u16, value: u8) {
 78 | 	asm!("out dx, al", in("al") value, in("dx") port);
 79 | }
 80 | 
 81 | /// Outputs a word to the specified port.
 82 | ///
 83 | /// # Safety
 84 | ///
 85 | /// Writing to an invalid port has an undefined behaviour.
 86 | ///
 87 | /// This function is not thread safe.
 88 | #[inline(always)]
 89 | pub unsafe fn outw(port: u16, value: u16) {
 90 | 	asm!("out dx, ax", in("ax") value, in("dx") port);
 91 | }
 92 | 
 93 | /// Outputs a long to the specified port.
 94 | ///
 95 | /// # Safety
 96 | ///
 97 | /// Writing to an invalid port has an undefined behaviour.
 98 | ///
 99 | /// This function is not thread safe.
100 | #[inline(always)]
101 | pub unsafe fn outl(port: u16, value: u32) {
102 | 	asm!("out dx, eax", in("eax") value, in("dx") port);
103 | }
104 | 


--------------------------------------------------------------------------------
/kernel/src/arch/x86/pic.rs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright 2024 Luc Lenôtre
  3 |  *
  4 |  * This file is part of Maestro.
  5 |  *
  6 |  * Maestro is free software: you can redistribute it and/or modify it under the
  7 |  * terms of the GNU General Public License as published by the Free Software
  8 |  * Foundation, either version 3 of the License, or (at your option) any later
  9 |  * version.
 10 |  *
 11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
 12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 14 |  *
 15 |  * You should have received a copy of the GNU General Public License along with
 16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
 17 |  */
 18 | 
 19 | //! The PIC is a component handling external interruptions, which allows to
 20 | //! block interruptions until the CPU tells that it's ready to handle another
 21 | //! one.
 22 | 
 23 | use crate::arch::x86::io::{inb, outb};
 24 | 
 25 | /// The master PIC's command port.
 26 | const MASTER_COMMAND: u16 = 0x20;
 27 | /// The master PIC's data port.
 28 | const MASTER_DATA: u16 = 0x21;
 29 | /// The slave PIC's command port.
 30 | const SLAVE_COMMAND: u16 = 0xa0;
 31 | /// The slave PIC's data port.
 32 | const SLAVE_DATA: u16 = 0xa1;
 33 | 
 34 | /// Indicates that ICW4 will be present
 35 | const ICW1_ICW4: u8 = 0x01;
 36 | /// Initialization
 37 | const ICW1_INIT: u8 = 0x10;
 38 | /// TODO doc
 39 | const ICW3_SLAVE_PIC: u8 = 0x04;
 40 | /// TODO doc
 41 | const ICW3_CASCADE: u8 = 0x02;
 42 | /// 8086/88 (MCS-80/85) mode
 43 | const ICW4_8086: u8 = 0x01;
 44 | 
 45 | /// The end-of-interrupt command.
 46 | const COMMAND_EOI: u8 = 0x20;
 47 | 
 48 | /// Initializes the PIC.
 49 | pub fn init(offset1: u8, offset2: u8) {
 50 | 	unsafe {
 51 | 		let mask1 = inb(MASTER_DATA);
 52 | 		let mask2 = inb(SLAVE_DATA);
 53 | 
 54 | 		outb(MASTER_COMMAND, ICW1_INIT | ICW1_ICW4);
 55 | 		outb(SLAVE_COMMAND, ICW1_INIT | ICW1_ICW4);
 56 | 
 57 | 		outb(MASTER_DATA, offset1);
 58 | 		outb(SLAVE_DATA, offset2);
 59 | 
 60 | 		outb(MASTER_DATA, ICW3_SLAVE_PIC);
 61 | 		outb(SLAVE_DATA, ICW3_CASCADE);
 62 | 
 63 | 		outb(MASTER_DATA, ICW4_8086);
 64 | 		outb(SLAVE_DATA, ICW4_8086);
 65 | 
 66 | 		outb(MASTER_DATA, mask1);
 67 | 		outb(SLAVE_DATA, mask2);
 68 | 	}
 69 | }
 70 | 
 71 | /// Enable interruptions on the given IRQ.
 72 | pub fn enable_irq(mut n: u8) {
 73 | 	let port = if n < 8 {
 74 | 		MASTER_DATA
 75 | 	} else {
 76 | 		n -= 8;
 77 | 		SLAVE_DATA
 78 | 	};
 79 | 
 80 | 	unsafe {
 81 | 		let value = inb(port) & !(1 << n);
 82 | 		outb(port, value);
 83 | 	}
 84 | }
 85 | 
 86 | /// Disable interruptions on the given IRQ.
 87 | pub fn disable_irq(mut n: u8) {
 88 | 	let port = if n < 8 {
 89 | 		MASTER_DATA
 90 | 	} else {
 91 | 		n -= 8;
 92 | 		SLAVE_DATA
 93 | 	};
 94 | 
 95 | 	unsafe {
 96 | 		let value = inb(port) | (1 << n);
 97 | 		outb(port, value);
 98 | 	}
 99 | }
100 | 
101 | /// Sends an End-Of-Interrupt message to the PIC for the given interrupt `irq`.
102 | #[unsafe(no_mangle)]
103 | pub extern "C" fn end_of_interrupt(irq: u8) {
104 | 	unsafe {
105 | 		if irq >= 0x8 {
106 | 			outb(SLAVE_COMMAND, COMMAND_EOI);
107 | 		}
108 | 		outb(MASTER_COMMAND, COMMAND_EOI);
109 | 	}
110 | }
111 | 


--------------------------------------------------------------------------------
/kernel/src/bin.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module exists only to import symbols from the kernel that has been compiled as a library.
20 | 
21 | #![no_std]
22 | #![no_main]
23 | // Force presence of the test code for both `cargo test` and `cargo clippy --tests`
24 | #![feature(custom_test_frameworks)]
25 | #![test_runner(kernel::selftest::runner)]
26 | 
27 | extern crate kernel;
28 | 


--------------------------------------------------------------------------------
/kernel/src/crypto/chacha20.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the ChaCha20 algorithm.
20 | 
21 | use core::ptr;
22 | 
23 | /// Performs a left rotation of `b` bits on the value `a`.
24 | macro_rules! rotl {
25 | 	($a:expr, $b:expr) => {
26 | 		($a << $b) | ($a >> (32 - $b))
27 | 	};
28 | }
29 | 
30 | /// Performs a quarter round on the given values.
31 | macro_rules! quarter_round {
32 | 	($a:expr, $b:expr, $c:expr, $d:expr) => {
33 | 		#[allow(clippy::manual_rotate)]
34 | 		{
35 | 			$a = $a.wrapping_add($b);
36 | 			$d ^= $a;
37 | 			$d = rotl!($d, 16);
38 | 
39 | 			$c = $c.wrapping_add($d);
40 | 			$b ^= $c;
41 | 			$b = rotl!($b, 12);
42 | 
43 | 			$a = $a.wrapping_add($b);
44 | 			$d ^= $a;
45 | 			$d = rotl!($d, 8);
46 | 
47 | 			$c = $c.wrapping_add($d);
48 | 			$b ^= $c;
49 | 			$b = rotl!($b, 7);
50 | 		}
51 | 	};
52 | }
53 | 
54 | /// Computes a ChaCha20 block.
55 | pub fn block(inout: &mut [u8; 64]) {
56 | 	let mut buff: [u32; 16] = [0; 16];
57 | 
58 | 	unsafe {
59 | 		ptr::copy_nonoverlapping(inout.as_ptr(), buff.as_mut_ptr() as *mut u8, 64);
60 | 	}
61 | 
62 | 	for _ in (0..20).step_by(2) {
63 | 		// Odd round
64 | 		quarter_round!(buff[0], buff[4], buff[8], buff[12]);
65 | 		quarter_round!(buff[1], buff[5], buff[9], buff[13]);
66 | 		quarter_round!(buff[2], buff[6], buff[10], buff[14]);
67 | 		quarter_round!(buff[3], buff[7], buff[11], buff[15]);
68 | 
69 | 		// Even round
70 | 		quarter_round!(buff[0], buff[5], buff[10], buff[15]);
71 | 		quarter_round!(buff[1], buff[6], buff[11], buff[12]);
72 | 		quarter_round!(buff[2], buff[7], buff[8], buff[13]);
73 | 		quarter_round!(buff[3], buff[4], buff[9], buff[14]);
74 | 	}
75 | 
76 | 	unsafe {
77 | 		ptr::copy_nonoverlapping(buff.as_ptr() as *mut u8, inout.as_mut_ptr(), 64);
78 | 	}
79 | }
80 | 
81 | // TODO unit tests
82 | 


--------------------------------------------------------------------------------
/kernel/src/crypto/checksum.rs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright 2024 Luc Lenôtre
  3 |  *
  4 |  * This file is part of Maestro.
  5 |  *
  6 |  * Maestro is free software: you can redistribute it and/or modify it under the
  7 |  * terms of the GNU General Public License as published by the Free Software
  8 |  * Foundation, either version 3 of the License, or (at your option) any later
  9 |  * version.
 10 |  *
 11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
 12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 14 |  *
 15 |  * You should have received a copy of the GNU General Public License along with
 16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
 17 |  */
 18 | 
 19 | //! This module implements checksum algorithms. A checksum is a value allowing
 20 | //! to verify the integrity of a structure.
 21 | 
 22 | /// Computes a checksum on `data` according to RFC1071.
 23 | pub fn compute_rfc1071(data: &[u8]) -> u16 {
 24 | 	let mut sum: u32 = 0;
 25 | 	let mut i = 0;
 26 | 
 27 | 	// Main loop
 28 | 	while i < (data.len() & !1) {
 29 | 		sum += ((data[i + 1] as u32) << 8) | (data[i] as u32);
 30 | 		i += 2;
 31 | 	}
 32 | 
 33 | 	// Add remaining byte
 34 | 	if i < data.len() {
 35 | 		sum += data[i] as u32;
 36 | 	}
 37 | 
 38 | 	// Folding 32-bits value into 16-bits
 39 | 	while (sum >> 16) != 0 {
 40 | 		sum = (sum & 0xffff) + (sum >> 16);
 41 | 	}
 42 | 
 43 | 	(!sum) as u16
 44 | }
 45 | 
 46 | /// Computes the lookup table for the given generator polynomial.
 47 | ///
 48 | /// Arguments:
 49 | /// - `table` is filled with the table's values.
 50 | /// - `polynom` is the polynom.
 51 | pub fn compute_crc32_lookuptable(table: &mut [u32; 256], polynom: u32) {
 52 | 	// Little endian
 53 | 	let mut i = table.len() / 2;
 54 | 	let mut crc = 1;
 55 | 
 56 | 	while i > 0 {
 57 | 		if crc & 1 != 0 {
 58 | 			crc = (crc >> 1) ^ polynom;
 59 | 		} else {
 60 | 			crc >>= 1;
 61 | 		}
 62 | 
 63 | 		for j in (0..table.len()).step_by(2 * i) {
 64 | 			table[i ^ j] = crc ^ table[j];
 65 | 		}
 66 | 
 67 | 		i >>= 1;
 68 | 	}
 69 | }
 70 | 
 71 | /// Computes the CRC32 checksum on the given data `data` with the given table
 72 | /// `table` for the wanted generator polynomial.
 73 | pub fn compute_crc32(data: &[u8], table: &[u32; 256]) -> u32 {
 74 | 	// Sarwate algorithm
 75 | 	let mut crc = !0u32;
 76 | 
 77 | 	for b in data {
 78 | 		let i = ((crc as usize) ^ (*b as usize)) & 0xff;
 79 | 		crc = table[i] ^ (crc >> 8);
 80 | 	}
 81 | 
 82 | 	!crc
 83 | }
 84 | 
 85 | #[cfg(test)]
 86 | mod test {
 87 | 	use super::*;
 88 | 
 89 | 	#[test_case]
 90 | 	fn rfc1071_0() {
 91 | 		for i in 0..=u16::MAX {
 92 | 			let data = [(i & 0xff) as _, (i >> 8) as _];
 93 | 			assert_eq!(compute_rfc1071(&data), !i);
 94 | 		}
 95 | 	}
 96 | 
 97 | 	// TODO More tests on RFC1071
 98 | 	// TODO Test CRC32
 99 | }
100 | 


--------------------------------------------------------------------------------
/kernel/src/crypto/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Cryptographic algorithms and tools.
20 | 
21 | use utils::errno::AllocResult;
22 | 
23 | pub mod chacha20;
24 | pub mod checksum;
25 | pub mod rand;
26 | 
27 | /// Initializes cryptographic features.
28 | pub(crate) fn init() -> AllocResult<()> {
29 | 	rand::init()
30 | }
31 | 


--------------------------------------------------------------------------------
/kernel/src/debug.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Debugging tools for the kernel.
20 | 
21 | use crate::{elf, memory, memory::VirtAddr};
22 | use core::ptr;
23 | use utils::DisplayableStr;
24 | 
25 | /// Fills the slice `stack` with the callstack starting at `frame`.
26 | ///
27 | /// The first element is the last called function and the last element is the first called
28 | /// function.
29 | ///
30 | /// When the stack ends, the function fills the rest of the slice with `None`.
31 | ///
32 | /// # Safety
33 | ///
34 | /// The caller must ensure the `frame` parameter points ta a valid stack frame.
35 | pub unsafe fn get_callstack(mut frame: *const usize, stack: &mut [VirtAddr]) {
36 | 	stack.fill(VirtAddr::default());
37 | 	for f in stack.iter_mut() {
38 | 		if frame.is_null() {
39 | 			break;
40 | 		}
41 | 		let pc = ptr::read_unaligned(frame.add(1) as _);
42 | 		if pc < memory::PROCESS_END {
43 | 			break;
44 | 		}
45 | 		*f = pc;
46 | 		frame = ptr::read_unaligned(frame as *const *const usize);
47 | 	}
48 | }
49 | 
50 | /// Prints a callstack, including symbols' names and addresses.
51 | ///
52 | /// `stack` is the callstack to print.
53 | ///
54 | /// If the callstack is empty, the function just prints `Empty`.
55 | pub fn print_callstack(stack: &[VirtAddr]) {
56 | 	if !matches!(stack.first(), Some(p) if !p.is_null()) {
57 | 		crate::println!("Empty");
58 | 		return;
59 | 	}
60 | 	for (i, pc) in stack.iter().enumerate() {
61 | 		if pc.is_null() {
62 | 			break;
63 | 		}
64 | 		let name = elf::kernel::get_function_name(*pc).unwrap_or(b"???");
65 | 		crate::println!("{i}: {pc:p} -> {}", DisplayableStr(name));
66 | 	}
67 | }
68 | 
69 | /// Utilities to manipulate QEMU.
70 | #[cfg(config_debug_qemu)]
71 | pub mod qemu {
72 | 	use crate::{arch::x86::io::outl, power};
73 | 
74 | 	/// The port used to trigger QEMU emulator exit with the given exit code.
75 | 	const EXIT_PORT: u16 = 0xf4;
76 | 
77 | 	/// QEMU exit code for success.
78 | 	pub const SUCCESS: u32 = 0x10;
79 | 	/// QEMU exit code for failure.
80 | 	pub const FAILURE: u32 = 0x11;
81 | 
82 | 	/// Exits QEMU with the given status.
83 | 	pub fn exit(status: u32) {
84 | 		unsafe {
85 | 			outl(EXIT_PORT, status);
86 | 		}
87 | 		// halt in case exiting did not succeed for some reason
88 | 		power::halt();
89 | 	}
90 | }
91 | 


--------------------------------------------------------------------------------
/kernel/src/device/bus/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements internal buses, including PCI and USB.
20 | 
21 | pub mod pci;
22 | 
23 | use crate::device::manager;
24 | use utils::errno::EResult;
25 | 
26 | /// Detects internal buses and registers them.
27 | pub fn detect() -> EResult<()> {
28 | 	// PCI
29 | 	let mut pci_manager = pci::PCIManager::new();
30 | 	pci_manager.scan()?;
31 | 	manager::register(pci_manager)?;
32 | 
33 | 	// TODO USB
34 | 
35 | 	Ok(())
36 | }
37 | 


--------------------------------------------------------------------------------
/kernel/src/device/storage/partition/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! A storage device can be divided into several blocks called partitions,
20 | //! allowing for instance to install several systems on the same machine.
21 | 
22 | mod gpt;
23 | mod mbr;
24 | 
25 | use crate::device::BlkDev;
26 | use gpt::Gpt;
27 | use mbr::MbrTable;
28 | use utils::{boxed::Box, collections::vec::Vec, errno::EResult, ptr::arc::Arc};
29 | 
30 | /// A disk partition bounds.
31 | #[derive(Debug)]
32 | pub struct Partition {
33 | 	/// The offset to the first sector of the partition.
34 | 	pub offset: u64,
35 | 	/// The number of sectors in the partition.
36 | 	pub size: u64,
37 | }
38 | 
39 | /// Trait representing a partition table.
40 | pub trait Table {
41 | 	/// Reads the partition table from the given storage device `dev`.
42 | 	///
43 | 	/// If the partition table isn't present on the storage interface, the
44 | 	/// function returns `None`.
45 | 	fn read(dev: &Arc<BlkDev>) -> EResult<Option<Self>>
46 | 	where
47 | 		Self: Sized;
48 | 
49 | 	/// Returns the type of the partition table.
50 | 	fn get_type(&self) -> &'static str;
51 | 
52 | 	/// Reads the partitions list.
53 | 	///
54 | 	/// `dev` is the storage device on which the partitions are to be read.
55 | 	fn read_partitions(&self, dev: &Arc<BlkDev>) -> EResult<Vec<Partition>>;
56 | }
57 | 
58 | /// Reads the list of partitions from the block device.
59 | ///
60 | /// If no partitions table is present, the function returns `None`.
61 | pub fn read(dev: &Arc<BlkDev>) -> EResult<Option<Box<dyn Table>>> {
62 | 	// Try GPT
63 | 	if let Some(table) = Gpt::read(dev)? {
64 | 		return Ok(Some(Box::new(table)?));
65 | 	}
66 | 	// Try MBR
67 | 	if let Some(table) = MbrTable::read(dev)? {
68 | 		return Ok(Some(Box::new(table)?));
69 | 	}
70 | 	Ok(None)
71 | }
72 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/ext2/bgd.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! A Block Group Descriptor is a structure stored in the Block Group Descriptor
20 | //! Table which represents a block group, which is a subdivision of the
21 | //! filesystem.
22 | 
23 | use super::{Ext2Fs, read_block};
24 | use crate::memory::cache::RcFrameVal;
25 | use core::{mem::size_of, sync::atomic::AtomicU16};
26 | use macros::AnyRepr;
27 | use utils::errno::EResult;
28 | 
29 | /// Start block of the block group descriptor table
30 | const BGDT_START_BLK: u32 = 1;
31 | 
32 | /// A block group descriptor.
33 | #[repr(C)]
34 | #[derive(AnyRepr)]
35 | pub struct BlockGroupDescriptor {
36 | 	/// The block address of the block usage bitmap.
37 | 	pub bg_block_bitmap: u32,
38 | 	/// The block address of the inode usage bitmap.
39 | 	pub bg_inode_bitmap: u32,
40 | 	/// Starting block address of inode table.
41 | 	pub bg_inode_table: u32,
42 | 	/// Number of unallocated blocks in group.
43 | 	pub bg_free_blocks_count: AtomicU16,
44 | 	/// Number of unallocated inodes in group.
45 | 	pub bg_free_inodes_count: AtomicU16,
46 | 	/// Number of directories in group.
47 | 	pub bg_used_dirs_count: AtomicU16,
48 | 
49 | 	pub bg_pad: [u8; 14],
50 | }
51 | 
52 | impl BlockGroupDescriptor {
53 | 	/// Returns the `i`th block group descriptor
54 | 	pub fn get(i: u32, fs: &Ext2Fs) -> EResult<RcFrameVal<Self>> {
55 | 		let blk_size = fs.sp.get_block_size() as usize;
56 | 		let bgd_per_blk = blk_size / size_of::<Self>();
57 | 		// Read block
58 | 		let blk_off = BGDT_START_BLK + (i / bgd_per_blk as u32);
59 | 		let blk = read_block(fs, blk_off as _)?;
60 | 		// Get entry
61 | 		let off = i as usize % bgd_per_blk;
62 | 		Ok(RcFrameVal::new(blk, off))
63 | 	}
64 | }
65 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/mem_info.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the `meminfo` file, allows to retrieve information about memory usage of the
20 | //! system.
21 | 
22 | use crate::{
23 | 	file::{File, fs::FileOps},
24 | 	format_content, memory,
25 | 	memory::user::UserSlice,
26 | };
27 | use utils::errno::EResult;
28 | 
29 | /// The `meminfo` file.
30 | #[derive(Debug, Default)]
31 | pub struct MemInfo;
32 | 
33 | impl FileOps for MemInfo {
34 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
35 | 		let mem_info = memory::stats::MEM_INFO.lock().clone();
36 | 		format_content!(off, buf, "{}", mem_info)
37 | 	}
38 | }
39 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/proc_dir/cmdline.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The `cmdline` node allows to retrieve the list of command line arguments of
20 | //! the process.
21 | 
22 | use super::read_memory;
23 | use crate::{
24 | 	file::{File, fs::FileOps},
25 | 	format_content,
26 | 	memory::user::UserSlice,
27 | 	process::{Process, pid::Pid},
28 | };
29 | use utils::{DisplayableStr, errno, errno::EResult};
30 | 
31 | /// The cmdline node of the proc.
32 | #[derive(Clone, Debug)]
33 | pub struct Cmdline(pub Pid);
34 | 
35 | impl FileOps for Cmdline {
36 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
37 | 		let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
38 | 		let Some(mem_space) = proc.mem_space.as_ref() else {
39 | 			return Ok(0);
40 | 		};
41 | 		let cmdline = read_memory(
42 | 			mem_space,
43 | 			mem_space.exe_info.argv_begin,
44 | 			mem_space.exe_info.argv_end,
45 | 		)?;
46 | 		format_content!(off, buf, "{}", DisplayableStr(&cmdline))
47 | 	}
48 | }
49 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/proc_dir/cwd.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the `cwd` node, which is a link to the current
20 | //! working directory of the process.
21 | 
22 | use crate::{
23 | 	file::{fs::NodeOps, vfs, vfs::node::Node},
24 | 	format_content,
25 | 	memory::user::UserSlice,
26 | 	process::{Process, pid::Pid},
27 | };
28 | use utils::{errno, errno::EResult};
29 | 
30 | /// The `cwd` node.
31 | #[derive(Debug)]
32 | pub struct Cwd(pub Pid);
33 | 
34 | impl NodeOps for Cwd {
35 | 	fn readlink(&self, _node: &Node, buf: UserSlice<u8>) -> EResult<usize> {
36 | 		let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
37 | 		let fs = proc.fs.lock();
38 | 		let cwd = vfs::Entry::get_path(&fs.cwd)?;
39 | 		format_content!(0, buf, "{cwd}")
40 | 	}
41 | }
42 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/proc_dir/environ.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The `environ` node allows to retrieve the environment variables of the process.
20 | 
21 | use crate::{
22 | 	file::{
23 | 		File,
24 | 		fs::{FileOps, proc::proc_dir::read_memory},
25 | 	},
26 | 	format_content,
27 | 	memory::user::UserSlice,
28 | 	process::{Process, pid::Pid},
29 | };
30 | use utils::{DisplayableStr, errno, errno::EResult};
31 | 
32 | /// The `environ` node of the proc.
33 | #[derive(Clone, Debug)]
34 | pub struct Environ(pub Pid);
35 | 
36 | impl FileOps for Environ {
37 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
38 | 		let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
39 | 		let Some(mem_space) = proc.mem_space.as_ref() else {
40 | 			return Ok(0);
41 | 		};
42 | 		let environ = read_memory(
43 | 			mem_space,
44 | 			mem_space.exe_info.envp_begin,
45 | 			mem_space.exe_info.envp_end,
46 | 		)?;
47 | 		format_content!(off, buf, "{}", DisplayableStr(&environ))
48 | 	}
49 | }
50 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/proc_dir/exe.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the `exe` node, which is a link to the executable
20 | //! file of the process.
21 | 
22 | use crate::{
23 | 	file::{fs::NodeOps, vfs, vfs::node::Node},
24 | 	format_content,
25 | 	memory::user::UserSlice,
26 | 	process::{Process, pid::Pid},
27 | };
28 | use utils::{errno, errno::EResult};
29 | 
30 | /// The `exe` node.
31 | #[derive(Debug)]
32 | pub struct Exe(pub Pid);
33 | 
34 | impl NodeOps for Exe {
35 | 	fn readlink(&self, _node: &Node, buf: UserSlice<u8>) -> EResult<usize> {
36 | 		let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
37 | 		let path = proc
38 | 			.mem_space
39 | 			.as_ref()
40 | 			.map(|mem_space| vfs::Entry::get_path(&mem_space.exe_info.exe))
41 | 			.transpose()?
42 | 			.unwrap_or_default();
43 | 		format_content!(0, buf, "{path}")
44 | 	}
45 | }
46 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/proc_dir/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the directory of a process in the proc.
20 | 
21 | use crate::{
22 | 	memory::{VirtAddr, user::UserSlice},
23 | 	process::mem_space::MemSpace,
24 | };
25 | use utils::{collections::vec::Vec, errno::AllocResult, ptr::arc::Arc, vec};
26 | 
27 | pub mod cmdline;
28 | pub mod cwd;
29 | pub mod environ;
30 | pub mod exe;
31 | pub mod mounts;
32 | pub mod stat;
33 | pub mod status;
34 | 
35 | /// Reads a range of memory from `mem_space` and writes it to `f`.
36 | ///
37 | /// `begin` and `end` represent the range of memory to read.
38 | pub fn read_memory(
39 | 	mem_space: &Arc<MemSpace>,
40 | 	begin: VirtAddr,
41 | 	end: VirtAddr,
42 | ) -> AllocResult<Vec<u8>> {
43 | 	let len = end.0.saturating_sub(begin.0);
44 | 	let mut buf = vec![0; len]?;
45 | 	let Ok(slice) = UserSlice::from_user(begin.as_ptr(), len) else {
46 | 		// Slice is out of range: return zeros
47 | 		return Ok(buf);
48 | 	};
49 | 	unsafe {
50 | 		MemSpace::switch(mem_space, |_| {
51 | 			let mut i = 0;
52 | 			while i < len {
53 | 				let Ok(len) = slice.copy_from_user(i, &mut buf[i..]) else {
54 | 					break;
55 | 				};
56 | 				i += len;
57 | 			}
58 | 		});
59 | 	}
60 | 	Ok(buf)
61 | }
62 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/proc_dir/mounts.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the `mounts` node which allows to get the list of mountpoint.
20 | 
21 | use crate::{
22 | 	file::{File, fs::FileOps, vfs, vfs::mountpoint},
23 | 	format_content,
24 | 	memory::user::UserSlice,
25 | 	process::pid::Pid,
26 | };
27 | use core::{fmt, fmt::Formatter};
28 | use utils::{DisplayableStr, errno::EResult};
29 | 
30 | /// The `mounts` node.
31 | #[derive(Debug)]
32 | pub struct Mounts(pub Pid);
33 | 
34 | impl FileOps for Mounts {
35 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
36 | 		format_content!(off, buf, "{self}")
37 | 	}
38 | }
39 | 
40 | impl fmt::Display for Mounts {
41 | 	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
42 | 		let mps = mountpoint::MOUNT_POINTS.lock();
43 | 		for (_, mp) in mps.iter() {
44 | 			let Ok(target) = vfs::Entry::get_path(&mp.root_entry) else {
45 | 				continue;
46 | 			};
47 | 			let fs_type = mp.fs.ops.get_name();
48 | 			let flags = "TODO"; // TODO
49 | 			writeln!(
50 | 				f,
51 | 				"{source} {target} {fs_type} {flags} 0 0",
52 | 				source = mp.source,
53 | 				target = target,
54 | 				fs_type = DisplayableStr(fs_type)
55 | 			)?;
56 | 		}
57 | 		Ok(())
58 | 	}
59 | }
60 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/proc_dir/stat.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the `stat` file, which allows to retrieve the current
20 | //! status of the process.
21 | 
22 | use crate::{
23 | 	file::{File, fs::FileOps},
24 | 	format_content,
25 | 	memory::{VirtAddr, user::UserSlice},
26 | 	process::{Process, pid::Pid},
27 | };
28 | use core::fmt;
29 | use utils::{DisplayableStr, errno, errno::EResult};
30 | 
31 | /// The `stat` node of the proc.
32 | #[derive(Debug)]
33 | pub struct StatNode(pub Pid);
34 | 
35 | impl FileOps for StatNode {
36 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
37 | 		let proc = Process::get_by_pid(self.0).ok_or_else(|| errno!(ENOENT))?;
38 | 		let disp = fmt::from_fn(|f| {
39 | 			let (name, vmem_usage) = proc
40 | 				.mem_space
41 | 				.as_ref()
42 | 				.map(|m| (m.exe_info.exe.name.as_bytes(), m.get_vmem_usage()))
43 | 				.unwrap_or_default();
44 | 			let user_regs = proc.user_regs();
45 | 			// TODO Fill every fields with process's data
46 | 			write!(
47 | 				f,
48 | 				"{pid} ({name}) {state_char} {ppid} {pgid} {sid} TODO TODO 0 \
49 | 0 0 0 0 {user_jiffies} {kernel_jiffies} TODO TODO {priority} {nice} {num_threads} 0 {vmem_usage} \
50 | TODO TODO TODO TODO {sp:?} {pc:?} TODO TODO TODO TODO 0 0 0 TODO TODO TODO TODO TODO TODO TODO TODO \
51 | TODO TODO TODO TODO TODO TODO TODO TODO TODO",
52 | 				pid = self.0,
53 | 				name = DisplayableStr(name),
54 | 				state_char = proc.get_state().as_char(),
55 | 				ppid = proc.get_parent_pid(),
56 | 				pgid = proc.get_pgid(),
57 | 				sid = 0,            // TODO
58 | 				user_jiffies = 0,   // TODO
59 | 				kernel_jiffies = 0, // TODO
60 | 				priority = 0,       // TODO
61 | 				nice = 0,           // TODO
62 | 				num_threads = 1,    // TODO
63 | 				sp = VirtAddr(user_regs.get_stack_address() as _),
64 | 				pc = VirtAddr(user_regs.get_program_counter() as _),
65 | 			)
66 | 		});
67 | 		format_content!(off, buf, "{disp}")
68 | 	}
69 | }
70 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/self_link.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of the `self` symlink, which points to the current process's directory.
20 | 
21 | use crate::{
22 | 	file::{fs::NodeOps, vfs::node::Node},
23 | 	format_content,
24 | 	memory::user::UserSlice,
25 | 	process::Process,
26 | };
27 | use utils::errno::EResult;
28 | 
29 | /// The `self` symlink.
30 | #[derive(Debug, Default)]
31 | pub struct SelfNode;
32 | 
33 | impl NodeOps for SelfNode {
34 | 	fn readlink(&self, _node: &Node, buf: UserSlice<u8>) -> EResult<usize> {
35 | 		let pid = Process::current().get_pid();
36 | 		format_content!(0, buf, "{pid}")
37 | 	}
38 | }
39 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/sys_dir/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! TODO doc
20 | 
21 | use crate::{
22 | 	file::{File, FileType, Stat, fs::FileOps},
23 | 	format_content,
24 | 	memory::user::UserSlice,
25 | };
26 | use utils::errno::EResult;
27 | 
28 | /// The `osrelease` file.
29 | #[derive(Debug, Default)]
30 | pub struct OsRelease;
31 | 
32 | impl FileOps for OsRelease {
33 | 	fn get_stat(&self, _file: &File) -> EResult<Stat> {
34 | 		Ok(Stat {
35 | 			mode: FileType::Regular.to_mode() | 0o444,
36 | 			..Default::default()
37 | 		})
38 | 	}
39 | 
40 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
41 | 		format_content!(off, buf, "{}\n", crate::VERSION)
42 | 	}
43 | }
44 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/uptime.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The uptime file returns the amount of time elapsed since the system started up.
20 | 
21 | use crate::{
22 | 	file::{File, fs::FileOps},
23 | 	format_content,
24 | 	memory::user::UserSlice,
25 | 	time::clock::{Clock, current_time_ns},
26 | };
27 | use utils::errno::EResult;
28 | 
29 | /// The `uptime` file.
30 | #[derive(Debug, Default)]
31 | pub struct Uptime;
32 | 
33 | impl FileOps for Uptime {
34 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
35 | 		let uptime = current_time_ns(Clock::Boottime) / 10_000_000;
36 | 		let uptime_upper = uptime / 100;
37 | 		let uptime_lower = uptime % 100;
38 | 		// TODO second value is the total amount of time each core has spent idle
39 | 		format_content!(off, buf, "{uptime_upper}.{uptime_lower:02} 0.00\n")
40 | 	}
41 | }
42 | 


--------------------------------------------------------------------------------
/kernel/src/file/fs/proc/version.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The `version` file returns the version of the kernel.
20 | 
21 | use crate::{
22 | 	file::{File, fs::FileOps},
23 | 	format_content,
24 | 	memory::user::UserSlice,
25 | };
26 | use utils::errno::EResult;
27 | 
28 | /// Kernel version file.
29 | #[derive(Debug, Default)]
30 | pub struct Version;
31 | 
32 | impl FileOps for Version {
33 | 	fn read(&self, _file: &File, off: u64, buf: UserSlice<u8>) -> EResult<usize> {
34 | 		format_content!(off, buf, "{} version {}\n", crate::NAME, crate::VERSION)
35 | 	}
36 | }
37 | 


--------------------------------------------------------------------------------
/kernel/src/file/util.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements utility functions for files manipulations.
20 | 
21 | use crate::file::{FileType, Stat, perm::AccessProfile, vfs, vfs::ResolutionSettings};
22 | use utils::{
23 | 	collections::path::{Component, Path, PathBuf},
24 | 	errno,
25 | 	errno::EResult,
26 | };
27 | 
28 | /// Creates the directories necessary to reach path `path`.
29 | ///
30 | /// If relative, the path is taken from the root.
31 | pub fn create_dirs(path: &Path) -> EResult<()> {
32 | 	// Path of the parent directory
33 | 	let mut p = PathBuf::root()?;
34 | 	for comp in path.components() {
35 | 		let Component::Normal(name) = &comp else {
36 | 			continue;
37 | 		};
38 | 		if let Ok(parent) = vfs::get_file_from_path(&p, &ResolutionSettings::kernel_follow()) {
39 | 			let res = vfs::create_file(
40 | 				parent,
41 | 				name,
42 | 				&AccessProfile::KERNEL,
43 | 				Stat {
44 | 					mode: FileType::Directory.to_mode() | 0o755,
45 | 					..Default::default()
46 | 				},
47 | 			);
48 | 			match res {
49 | 				Err(e) if e.as_int() != errno::EEXIST => return Err(e),
50 | 				_ => {}
51 | 			}
52 | 		}
53 | 		p = p.join(comp)?;
54 | 	}
55 | 	Ok(())
56 | }
57 | 


--------------------------------------------------------------------------------
/kernel/src/libc/memcmp.c:
--------------------------------------------------------------------------------
 1 | // Code taken from musl. License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
 2 | 
 3 | #include <stddef.h>
 4 | 
 5 | int memcmp(const void *vl, const void *vr, size_t n)
 6 | {
 7 |     const unsigned char *l = vl, *r = vr;
 8 |     for (; n && *l == *r; n--, l++, r++);
 9 |     return n ? *l - *r : 0;
10 | }
11 | 


--------------------------------------------------------------------------------
/kernel/src/libc/strlen.c:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | #include <stdint.h>
20 | #include <stddef.h>
21 | 
22 | #define LOW ((size_t) -1 / 0xff)
23 | #define HIGH (LOW * 0x80)
24 | #define ZERO(w) (((w) - LOW) & (~(w) & HIGH))
25 | 
26 | size_t strlen(const char *s)
27 | {
28 | 	const char *n = s;
29 | 
30 |     // Align
31 |     for (; (uintptr_t) n % sizeof(size_t); ++n) if (!*n) return n - s;
32 |     // Check word-by-word
33 |     const size_t *word = (size_t *) n;
34 |     for (; !ZERO(*word); ++word);
35 |     n = (const char *) word;
36 |     // Count remaining
37 |     for (; *n; ++n)
38 |         ;
39 |     return n - s;
40 | }
41 | 


--------------------------------------------------------------------------------
/kernel/src/memory/malloc/block.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! In the malloc allocator, a block is a memory allocation performed from
20 | //! another allocator, which is too big to be used directly for allocation, so
21 | //! it has to be divided into chunks.
22 | 
23 | use super::chunk::{Chunk, FreeChunk};
24 | use crate::memory::buddy;
25 | use core::{
26 | 	mem::{offset_of, size_of},
27 | 	num::NonZeroUsize,
28 | 	ptr,
29 | };
30 | use utils::{errno::AllocResult, limits::PAGE_SIZE};
31 | 
32 | /// A frame of memory allocated using the buddy allocator, storing memory chunks.
33 | #[repr(C, align(8))]
34 | pub struct Block {
35 | 	/// The order of the frame for the buddy allocator
36 | 	order: buddy::FrameOrder,
37 | 	/// The first chunk of the block
38 | 	pub first_chunk: Chunk,
39 | }
40 | 
41 | impl Block {
42 | 	/// Allocates a new block of memory with the minimum available size
43 | 	/// `min_size` in bytes.
44 | 	///
45 | 	/// The buddy allocator must be initialized before using this function.
46 | 	///
47 | 	/// The underlying chunk created by this function is **not** inserted into the free list.
48 | 	pub fn new(min_size: NonZeroUsize) -> AllocResult<&'static mut Self> {
49 | 		let min_total_size = size_of::<Block>() + min_size.get();
50 | 		let block_order = buddy::get_order(min_total_size.div_ceil(PAGE_SIZE));
51 | 		// The size of the first chunk
52 | 		let first_chunk_size = buddy::get_frame_size(block_order) - size_of::<Block>();
53 | 		debug_assert!(first_chunk_size >= min_size.get());
54 | 		// Allocate the block
55 | 		let block = unsafe {
56 | 			let mut ptr = buddy::alloc_kernel(block_order, 0)?.cast();
57 | 			ptr::write_volatile(
58 | 				ptr.as_mut(),
59 | 				Self {
60 | 					order: block_order,
61 | 					first_chunk: Chunk::new(),
62 | 				},
63 | 			);
64 | 			ptr.as_mut()
65 | 		};
66 | 		*block.first_chunk.as_free_chunk().unwrap() = FreeChunk::new(first_chunk_size);
67 | 		Ok(block)
68 | 	}
69 | 
70 | 	/// Returns a mutable reference to the block whose first chunk's reference
71 | 	/// is passed as argument.
72 | 	pub unsafe fn from_first_chunk(chunk: *mut Chunk) -> &'static mut Block {
73 | 		let first_chunk_off = offset_of!(Block, first_chunk);
74 | 		let ptr = chunk.byte_sub(first_chunk_off) as *mut Self;
75 | 		debug_assert!(ptr.is_aligned_to(PAGE_SIZE));
76 | 		&mut *ptr
77 | 	}
78 | }
79 | 
80 | impl Drop for Block {
81 | 	fn drop(&mut self) {
82 | 		unsafe {
83 | 			buddy::free_kernel(self as *mut _ as _, self.order);
84 | 		}
85 | 	}
86 | }
87 | 


--------------------------------------------------------------------------------
/kernel/src/memory/oom.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! OOM killing is a procedure which is invoked when the kernel runs out of
20 | //! memory.
21 | //!
22 | //! The OOM killer terminates one or more processes according to a score computed for
23 | //! each of them.
24 | //!
25 | //! This is an emergency procedure which is not supposed to be used under normal conditions.
26 | 
27 | use crate::{file::vfs, memory::cache};
28 | use utils::errno::AllocResult;
29 | 
30 | /// Attempts to reclaim memory from different places, or panics on failure.
31 | pub fn reclaim() {
32 | 	// Attempt to shrink the page cache
33 | 	if cache::shrink() {
34 | 		return;
35 | 	}
36 | 	// Attempt to shrink the directory entries cache
37 | 	if vfs::shrink_entries() {
38 | 		return;
39 | 	}
40 | 	// TODO Attempt to:
41 | 	// - swap memory to disk
42 | 	// - if the kernel is configured for it, prompt the user to select processes to kill
43 | 	// - if the kernel is configured for it, kill the process with the highest OOM score (ignore
44 | 	//   init process)
45 | 	// - else, panic:
46 | 	panic!("Out of memory");
47 | }
48 | 
49 | /// Executes the given function. On failure due to a lack of memory, the function runs the OOM
50 | /// killer, then tries again.
51 | ///
52 | /// If the OOM killer is unable to free enough memory, the kernel may panic.
53 | pub fn wrap<T, F: FnMut() -> AllocResult<T>>(mut f: F) -> T {
54 | 	loop {
55 | 		if let Ok(r) = f() {
56 | 			return r;
57 | 		}
58 | 		reclaim();
59 | 		// TODO Check if current process has been killed
60 | 	}
61 | }
62 | 


--------------------------------------------------------------------------------
/kernel/src/memory/stats.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Statistics about memory usage.
20 | 
21 | use crate::sync::mutex::Mutex;
22 | use core::{
23 | 	fmt,
24 | 	fmt::{Display, Formatter},
25 | };
26 | 
27 | /// Stores memory usage information. Each field is in KiB.
28 | #[derive(Clone)]
29 | pub struct MemInfo {
30 | 	/// The total amount of memory on the system.
31 | 	pub mem_total: usize,
32 | 	/// The total amount of free physical memory.
33 | 	pub mem_free: usize,
34 | 	/// The total amount of free + reclaimable memory.
35 | 	pub mem_available: usize,
36 | 	/// The total amount of active (mapped) memory.
37 | 	pub active: usize,
38 | 	/// The total amount of inactive (not mapped but cached) memory.
39 | 	pub inactive: usize,
40 | }
41 | 
42 | impl Display for MemInfo {
43 | 	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
44 | 		writeln!(
45 | 			f,
46 | 			"MemTotal: {} kB
47 | MemFree: {} kB
48 | MemAvailable: {} kB
49 | Active: {} kB
50 | Inactive: {} kB",
51 | 			self.mem_total, self.mem_free, self.mem_available, self.active, self.inactive
52 | 		)
53 | 	}
54 | }
55 | 
56 | /// Memory usage statistics.
57 | pub static MEM_INFO: Mutex<MemInfo> = Mutex::new(MemInfo {
58 | 	mem_total: 0,
59 | 	mem_free: 0,
60 | 	mem_available: 0,
61 | 	active: 0,
62 | 	inactive: 0,
63 | });
64 | 


--------------------------------------------------------------------------------
/kernel/src/memory/trace.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Memory usage tracing utility functions.
20 | 
21 | use crate::{debug, device::serial, memory::VirtAddr, register_get};
22 | use core::ptr;
23 | 
24 | /// The operation being sampled.
25 | #[repr(u8)]
26 | pub enum SampleOp {
27 | 	Alloc = 0,
28 | 	Realloc = 1,
29 | 	Free = 2,
30 | }
31 | 
32 | /// Writes a memory tracing sample to the **COM2** serial port.
33 | ///
34 | /// Arguments:
35 | /// - `allocator` is the name of the allocator.
36 | /// - `op` is the operation number.
37 | /// - `ptr` is the affected pointer.
38 | /// - `size` is the new size of the allocation. The unit is dependent on the allocator.
39 | pub fn sample(allocator: &str, op: SampleOp, addr: usize, size: usize) {
40 | 	// Dump callstack
41 | 	#[cfg(target_arch = "x86")]
42 | 	let frame = register_get!("ebp");
43 | 	#[cfg(target_arch = "x86_64")]
44 | 	let frame = register_get!("rbp");
45 | 	let frame = ptr::with_exposed_provenance::<usize>(frame);
46 | 	let mut callstack: [VirtAddr; 64] = [VirtAddr::default(); 64];
47 | 	unsafe {
48 | 		debug::get_callstack(frame, &mut callstack);
49 | 	}
50 | 	// COM2
51 | 	let mut serial = serial::PORTS[1].lock();
52 | 	// Write name of allocator
53 | 	serial.write(&[allocator.len() as u8]);
54 | 	serial.write(allocator.as_bytes());
55 | 	// Write op
56 | 	serial.write(&[op as u8]);
57 | 	// Write ptr and size
58 | 	serial.write(&(addr as u64).to_le_bytes());
59 | 	serial.write(&(size as u64).to_le_bytes());
60 | 	// Write callstack
61 | 	let len = callstack
62 | 		.iter()
63 | 		.enumerate()
64 | 		.find(|(_, p)| p.is_null())
65 | 		.map(|(i, _)| i)
66 | 		.unwrap_or(callstack.len());
67 | 	serial.write(&[len as u8]);
68 | 	for f in &callstack[..len] {
69 | 		serial.write(&(f.0 as u64).to_le_bytes());
70 | 	}
71 | }
72 | 


--------------------------------------------------------------------------------
/kernel/src/net/buff.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! TODO doc
20 | 
21 | use core::ptr::NonNull;
22 | 
23 | /// A linked-list of buffers representing a packet being built.
24 | ///
25 | /// This structure works without any memory allocations and relies entirely on lifetimes.
26 | pub struct BuffList<'b> {
27 | 	/// The buffer.
28 | 	b: &'b [u8],
29 | 
30 | 	/// The next buffer in the list.
31 | 	next: Option<NonNull<BuffList<'b>>>,
32 | 	/// The length of following buffers combined.
33 | 	next_len: usize,
34 | }
35 | 
36 | impl<'b> From<&'b [u8]> for BuffList<'b> {
37 | 	fn from(b: &'b [u8]) -> Self {
38 | 		Self {
39 | 			b,
40 | 
41 | 			next: None,
42 | 			next_len: 0,
43 | 		}
44 | 	}
45 | }
46 | 
47 | impl<'b> BuffList<'b> {
48 | 	/// Returns the length of the buffer, plus following buffers.
49 | 	#[allow(clippy::len_without_is_empty)]
50 | 	pub fn len(&self) -> usize {
51 | 		self.b.len() + self.next_len
52 | 	}
53 | 
54 | 	/// Pushes another buffer at the front of the current list.
55 | 	///
56 | 	/// The function returns the new head of the list (which is the given `front`).
57 | 	pub fn push_front<'o>(&mut self, mut front: BuffList<'o>) -> BuffList<'o>
58 | 	where
59 | 		'b: 'o,
60 | 	{
61 | 		front.next = NonNull::new(self);
62 | 		front.next_len = self.b.len() + self.next_len;
63 | 
64 | 		front
65 | 	}
66 | }
67 | 


--------------------------------------------------------------------------------
/kernel/src/net/icmp.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements the Internet Control Message Protocol.
20 | //!
21 | //! This procotol is defined by the following RFCs:
22 | //! - With IPv4: RFC 792
23 | //! - With IPv6 (ICMPv6): RFC 4443
24 | 
25 | /// An enumeration of ICMP packet types.
26 | pub enum ICMPType {
27 | 	/// Used by ping to reply to an echo request.
28 | 	EchoReply,
29 | 	/// TODO doc
30 | 	DestinationUnreachable,
31 | 	/// TODO doc
32 | 	SourceQuench,
33 | 	/// TODO doc
34 | 	RedirectMessage,
35 | 	/// Used by ping to request an echo.
36 | 	EchoRequest,
37 | 	/// TODO doc
38 | 	RouterAdvertisement,
39 | 	/// TODO doc
40 | 	RouterSolicitation,
41 | 	/// TODO doc
42 | 	TimeExceeded,
43 | 	/// TODO doc
44 | 	ParameterProblem,
45 | 	/// TODO doc
46 | 	Timestamp,
47 | 	/// TODO doc
48 | 	TimestampReply,
49 | 	/// TODO doc
50 | 	InformationRequest,
51 | 	/// TODO doc
52 | 	InformationReply,
53 | 	/// TODO doc
54 | 	AddressMaskRequest,
55 | 	/// TODO doc
56 | 	AddressMaskReply,
57 | 	/// TODO doc
58 | 	Traceroute,
59 | 	/// TODO doc
60 | 	ExtendedEchoRequest,
61 | 	/// TODO doc
62 | 	ExtendedEchoReply,
63 | }
64 | 
65 | impl ICMPType {
66 | 	/// Returns a type from its ID.
67 | 	///
68 | 	/// If no type match, the function returns None.
69 | 	pub fn from_type(id: u8) -> Option<Self> {
70 | 		match id {
71 | 			0 => Some(Self::EchoReply),
72 | 			3 => Some(Self::DestinationUnreachable),
73 | 			4 => Some(Self::SourceQuench),
74 | 			5 => Some(Self::RedirectMessage),
75 | 			8 => Some(Self::EchoRequest),
76 | 			9 => Some(Self::RouterAdvertisement),
77 | 			10 => Some(Self::RouterSolicitation),
78 | 			11 => Some(Self::TimeExceeded),
79 | 			12 => Some(Self::ParameterProblem),
80 | 			13 => Some(Self::Timestamp),
81 | 			14 => Some(Self::TimestampReply),
82 | 			15 => Some(Self::InformationRequest),
83 | 			16 => Some(Self::InformationReply),
84 | 			17 => Some(Self::AddressMaskRequest),
85 | 			18 => Some(Self::AddressMaskReply),
86 | 			30 => Some(Self::Traceroute),
87 | 			42 => Some(Self::ExtendedEchoRequest),
88 | 			43 => Some(Self::ExtendedEchoReply),
89 | 
90 | 			_ => None,
91 | 		}
92 | 	}
93 | }
94 | 


--------------------------------------------------------------------------------
/kernel/src/net/lo.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements the local loopback.
20 | 
21 | use super::{Address, BindAddress, Interface, MAC, buff::BuffList};
22 | use utils::errno::EResult;
23 | 
24 | /// Local loopback interfaces allows the system to write data to itself.
25 | pub struct LocalLoopback {}
26 | 
27 | impl Interface for LocalLoopback {
28 | 	fn get_name(&self) -> &[u8] {
29 | 		b"lo"
30 | 	}
31 | 
32 | 	fn is_up(&self) -> bool {
33 | 		true
34 | 	}
35 | 
36 | 	fn get_mac(&self) -> &MAC {
37 | 		&[0x00; 6]
38 | 	}
39 | 
40 | 	fn get_addresses(&self) -> &[BindAddress] {
41 | 		&[
42 | 			BindAddress {
43 | 				addr: Address::IPv4([127, 0, 0, 1]),
44 | 				subnet_mask: 8,
45 | 			},
46 | 			BindAddress {
47 | 				addr: Address::IPv6([
48 | 					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 | 					0x00, 0x00, 0x01,
50 | 				]),
51 | 				subnet_mask: 128,
52 | 			},
53 | 		]
54 | 	}
55 | 
56 | 	fn read(&mut self, _buff: &mut [u8]) -> EResult<u64> {
57 | 		// TODO Write to ring buffer
58 | 		todo!();
59 | 	}
60 | 
61 | 	fn write(&mut self, _buff: &BuffList<'_>) -> EResult<u64> {
62 | 		// TODO Read from ring buffer
63 | 		todo!();
64 | 	}
65 | }
66 | 


--------------------------------------------------------------------------------
/kernel/src/net/sockaddr.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module defines sockaddr structures used by system calls to define connection informations
20 | //! on sockets.
21 | 
22 | use super::Address;
23 | use core::ffi::c_short;
24 | 
25 | /// Structure providing connection informations for sockets with IPv4.
26 | #[repr(C)]
27 | #[derive(Clone)]
28 | pub struct SockAddrIn {
29 | 	/// The family of the socket.
30 | 	sin_family: c_short,
31 | 	/// The port on which the connection is to be opened.
32 | 	sin_port: c_short,
33 | 	/// The destination address of the connection.
34 | 	sin_addr: u32,
35 | 	/// Padding.
36 | 	sin_zero: [u8; 8],
37 | }
38 | 
39 | /// Structure representing an IPv6 address.
40 | #[repr(C)]
41 | #[derive(Clone, Copy)]
42 | pub union In6Addr {
43 | 	__s6_addr: [u8; 16],
44 | 	__s6_addr16: [u16; 8],
45 | 	__s6_addr32: [u32; 4],
46 | }
47 | 
48 | /// Structure providing connection informations for sockets with IPv6.
49 | #[repr(C)]
50 | #[derive(Clone)]
51 | pub struct SockAddrIn6 {
52 | 	/// The family of the socket.
53 | 	sin6_family: c_short,
54 | 	/// The port on which the connection is to be opened.
55 | 	sin6_port: c_short,
56 | 	/// TODO doc
57 | 	sin6_flowinfo: u32,
58 | 	/// The destination address of the connection.
59 | 	sin6_addr: In6Addr,
60 | 	/// TODO doc
61 | 	sin6_scope_id: u32,
62 | }
63 | 
64 | /// A unified structure which contains data passed from userspace.
65 | #[derive(Debug)]
66 | pub struct SockAddr {
67 | 	/// The port used by the socket.
68 | 	pub port: u16,
69 | 	/// The destination address of the socket.
70 | 	pub addr: Address,
71 | }
72 | 
73 | impl From<SockAddrIn> for SockAddr {
74 | 	fn from(val: SockAddrIn) -> Self {
75 | 		let addr: [u8; 4] = [
76 | 			((val.sin_addr >> 24) & 0xff) as u8,
77 | 			((val.sin_addr >> 16) & 0xff) as u8,
78 | 			((val.sin_addr >> 8) & 0xff) as u8,
79 | 			(val.sin_addr & 0xff) as u8,
80 | 		];
81 | 
82 | 		Self {
83 | 			port: val.sin_port as _,
84 | 			addr: Address::IPv4(addr),
85 | 		}
86 | 	}
87 | }
88 | 
89 | impl From<SockAddrIn6> for SockAddr {
90 | 	fn from(val: SockAddrIn6) -> Self {
91 | 		let addr = unsafe { val.sin6_addr.__s6_addr };
92 | 
93 | 		Self {
94 | 			port: val.sin6_port as _,
95 | 			addr: Address::IPv6(addr),
96 | 		}
97 | 	}
98 | }
99 | 


--------------------------------------------------------------------------------
/kernel/src/net/tcp.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The Transmission Control Protocol (TCP) is a protocol transmitting sequenced, reliable,
20 | //! two-way, connection-based byte streams.
21 | 
22 | use super::{buff::BuffList, osi::Layer};
23 | use crate::file::socket::Socket;
24 | use utils::errno::EResult;
25 | 
26 | /// The TCP segment header.
27 | #[repr(C, packed)]
28 | pub struct TCPHdr {
29 | 	/// Source port.
30 | 	src_port: u16,
31 | 	/// Destination port.
32 | 	dst_port: u16,
33 | 
34 | 	/// Sequence number.
35 | 	seq_nbr: u32,
36 | 
37 | 	/// TODO doc
38 | 	ack_nbr: u32,
39 | 
40 | 	/// The size of the header in units of 4 bytes.
41 | 	///
42 | 	/// Since the first 4 bits are reserved, the value must be shifted by 4 bits.
43 | 	data_offset: u8,
44 | 	/// The segment's flags.
45 | 	flags: u8,
46 | 	/// TODO doc
47 | 	win_size: u16,
48 | 
49 | 	/// TODO doc
50 | 	checksum: u16,
51 | 	/// TODO doc
52 | 	urg_ptr: u16,
53 | }
54 | 
55 | /// The network layer for the TCP protocol.
56 | #[derive(Debug)]
57 | pub struct TCPLayer {}
58 | 
59 | impl Layer for TCPLayer {
60 | 	fn transmit<'c, F>(&self, _buff: BuffList<'c>, _next: F) -> EResult<()>
61 | 	where
62 | 		F: Fn(BuffList<'c>) -> EResult<()>,
63 | 	{
64 | 		// TODO
65 | 		todo!();
66 | 	}
67 | }
68 | 
69 | /// Initiates a TCP connection on the given socket `sock`.
70 | pub fn init_connection(_sock: &mut Socket) -> EResult<()> {
71 | 	// TODO
72 | 	todo!();
73 | }
74 | 


--------------------------------------------------------------------------------
/kernel/src/panic.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements kernel panics handling.
20 | //!
21 | //! A kernel panic occurs when an error is raised that the kernel cannot recover
22 | //! from. This is an undesirable state which requires to reboot the host
23 | //! machine.
24 | 
25 | #[cfg(config_debug_qemu)]
26 | use crate::debug::qemu;
27 | use crate::{arch::x86::cli, logger, memory::VirtAddr, power, register_get};
28 | use core::panic::PanicInfo;
29 | 
30 | /// Called on Rust panic.
31 | #[panic_handler]
32 | fn panic(panic_info: &PanicInfo) -> ! {
33 | 	cli();
34 | 	logger::LOGGER.lock().silent = false;
35 | 
36 | 	#[cfg(test)]
37 | 	{
38 | 		use crate::selftest;
39 | 		if selftest::is_running() {
40 | 			crate::println!("FAILED\n");
41 | 			crate::println!("Error: {panic_info}\n");
42 | 			#[cfg(config_debug_qemu)]
43 | 			qemu::exit(qemu::FAILURE);
44 | 			power::halt();
45 | 		}
46 | 	}
47 | 
48 | 	crate::println!("--- KERNEL PANIC ---\n");
49 | 	crate::println!("Kernel has been forced to halt due to internal problem, sorry :/");
50 | 	crate::print!("Reason: {}", panic_info.message());
51 | 	if let Some(loc) = panic_info.location() {
52 | 		crate::println!(" (location: {loc})");
53 | 	} else {
54 | 		crate::println!();
55 | 	}
56 | 	crate::println!(
57 | 		"If you believe this is a bug on the kernel side, please feel free to report it."
58 | 	);
59 | 
60 | 	crate::println!("cr2: {:?}\n", VirtAddr(register_get!("cr2")));
61 | 
62 | 	#[cfg(debug_assertions)]
63 | 	{
64 | 		use crate::debug;
65 | 		use core::ptr;
66 | 
67 | 		crate::println!("--- Callstack ---");
68 | 		#[cfg(target_arch = "x86")]
69 | 		let frame = register_get!("ebp");
70 | 		#[cfg(target_arch = "x86_64")]
71 | 		let frame = register_get!("rbp");
72 | 		let ebp = ptr::with_exposed_provenance(frame);
73 | 		let mut callstack: [VirtAddr; 8] = [VirtAddr::default(); 8];
74 | 		unsafe {
75 | 			debug::get_callstack(ebp, &mut callstack);
76 | 		}
77 | 		debug::print_callstack(&callstack);
78 | 	}
79 | 	#[cfg(config_debug_qemu)]
80 | 	qemu::exit(qemu::FAILURE);
81 | 	power::halt();
82 | }
83 | 
84 | // TODO check whether this can be removed since the kernel uses panic=abort
85 | /// Function that is required to be implemented by the Rust compiler and is used
86 | /// only when panicking.
87 | #[lang = "eh_personality"]
88 | fn eh_personality() {}
89 | 


--------------------------------------------------------------------------------
/kernel/src/power.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module handles system power.
20 | 
21 | use crate::arch::x86::{
22 | 	cli, hlt,
23 | 	io::{inb, outb},
24 | };
25 | use core::arch::asm;
26 | 
27 | /// Halts the kernel until reboot.
28 | pub fn halt() -> ! {
29 | 	// TODO Send a signal to all other cores to stop them
30 | 	loop {
31 | 		cli();
32 | 		hlt();
33 | 	}
34 | }
35 | 
36 | /// Powers the system down.
37 | pub fn shutdown() -> ! {
38 | 	// TODO Use ACPI to power off the system
39 | 	todo!()
40 | }
41 | 
42 | /// Reboots the system.
43 | pub fn reboot() -> ! {
44 | 	cli();
45 | 	// First try: ACPI
46 | 	// TODO Use ACPI reset to ensure everything reboots
47 | 	// Second try: PS/2
48 | 	loop {
49 | 		let tmp = unsafe { inb(0x64) };
50 | 		// Empty keyboard buffer
51 | 		if tmp & 0b1 != 0 {
52 | 			unsafe {
53 | 				inb(0x60);
54 | 			}
55 | 		}
56 | 		// If buffer is empty, break
57 | 		if tmp & 0b10 == 0 {
58 | 			break;
59 | 		}
60 | 	}
61 | 	// PS/2 CPU reset command
62 | 	unsafe {
63 | 		outb(0x64, 0xfe);
64 | 	}
65 | 	// Third try: triple fault
66 | 	unsafe {
67 | 		asm!("push 0xffff", "push 0", "retf");
68 | 	}
69 | 	unreachable!();
70 | }
71 | 


--------------------------------------------------------------------------------
/kernel/src/print.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of printing/logging macros.
20 | //!
21 | //! Unlike the print macros from Rust's standard library, these are used to log informations
22 | //! instead of only printing.
23 | //!
24 | //! Printing can be silenced at boot using the `-silent` command line argument, but logs remain in
25 | //! memory.
26 | 
27 | use crate::logger::LOGGER;
28 | use core::fmt;
29 | 
30 | /// Prints/logs the given message.
31 | ///
32 | /// This function is meant to be used through [`print!`] and [`println!`] macros only.
33 | #[doc(hidden)]
34 | pub fn _print(args: fmt::Arguments) {
35 | 	let mut logger = LOGGER.lock();
36 | 	fmt::write(&mut *logger, args).ok();
37 | }
38 | 
39 | /// Prints the given formatted string with the given values.
40 | #[allow_internal_unstable(print_internals)]
41 | #[macro_export]
42 | macro_rules! print {
43 | 	($($arg:tt)*) => {{
44 | 		$crate::print::_print(format_args!($($arg)*));
45 | 	}};
46 | }
47 | 
48 | /// Same as [`crate::print!`], except it appends a newline at the end.
49 | #[allow_internal_unstable(print_internals, format_args_nl)]
50 | #[macro_export]
51 | macro_rules! println {
52 | 	() => ($crate::print!("\n"));
53 | 	($($arg:tt)*) => {{
54 | 		$crate::print::_print(format_args_nl!($($arg)*));
55 | 	}};
56 | }
57 | 


--------------------------------------------------------------------------------
/kernel/src/process/pid.rs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright 2024 Luc Lenôtre
  3 |  *
  4 |  * This file is part of Maestro.
  5 |  *
  6 |  * Maestro is free software: you can redistribute it and/or modify it under the
  7 |  * terms of the GNU General Public License as published by the Free Software
  8 |  * Foundation, either version 3 of the License, or (at your option) any later
  9 |  * version.
 10 |  *
 11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
 12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 14 |  *
 15 |  * You should have received a copy of the GNU General Public License along with
 16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
 17 |  */
 18 | 
 19 | //! PIDs handling.
 20 | //!
 21 | //! Each process must have a unique PID, thus they have to be allocated.
 22 | //! A bitfield is used to store the used PIDs.
 23 | 
 24 | use crate::sync::mutex::Mutex;
 25 | use core::{alloc::AllocError, ops::Deref};
 26 | use utils::{collections::id_allocator::IDAllocator, errno::AllocResult};
 27 | 
 28 | /// Type representing a Process ID. This ID is unique for every running
 29 | /// processes.
 30 | pub type Pid = u16;
 31 | 
 32 | /// The maximum possible PID.
 33 | const MAX_PID: Pid = 32768;
 34 | /// Special PID for the idle task.
 35 | pub const IDLE_PID: Pid = 0;
 36 | /// PID of the init process.
 37 | pub const INIT_PID: Pid = 1;
 38 | 
 39 | /// The PID allocator.
 40 | static ALLOCATOR: Mutex<Option<IDAllocator>> = Mutex::new(None);
 41 | 
 42 | /// Perform an operation with the allocator.
 43 | fn allocator_do<F: Fn(&mut IDAllocator) -> AllocResult<T>, T>(f: F) -> AllocResult<T> {
 44 | 	let mut allocator = ALLOCATOR.lock();
 45 | 	let allocator = match &mut *allocator {
 46 | 		Some(a) => a,
 47 | 		None => allocator.insert(IDAllocator::new(MAX_PID as _)?),
 48 | 	};
 49 | 	f(allocator)
 50 | }
 51 | 
 52 | /// Wrapper for a PID, freeing it on drop.
 53 | #[derive(Debug)]
 54 | pub struct PidHandle(Pid);
 55 | 
 56 | impl PidHandle {
 57 | 	/// Allocates the given `pid`.
 58 | 	///
 59 | 	/// If already allocated, the function returns an error.
 60 | 	pub(super) fn mark_used(pid: Pid) -> AllocResult<Self> {
 61 | 		let Some(id) = pid.checked_sub(1) else {
 62 | 			// Pid `0` is not allocated, just return a handle
 63 | 			return Ok(Self(pid));
 64 | 		};
 65 | 		allocator_do(|a| {
 66 | 			if !a.is_used(id as _) {
 67 | 				a.set_used(id as _);
 68 | 				Ok(Self(pid))
 69 | 			} else {
 70 | 				Err(AllocError)
 71 | 			}
 72 | 		})
 73 | 	}
 74 | 
 75 | 	/// Returns an unused PID and marks it as used.
 76 | 	pub fn unique() -> AllocResult<PidHandle> {
 77 | 		allocator_do(|allocator| allocator.alloc(None)).map(|i| PidHandle((i + 1) as _))
 78 | 	}
 79 | }
 80 | 
 81 | impl Deref for PidHandle {
 82 | 	type Target = Pid;
 83 | 
 84 | 	fn deref(&self) -> &Self::Target {
 85 | 		&self.0
 86 | 	}
 87 | }
 88 | 
 89 | impl Drop for PidHandle {
 90 | 	fn drop(&mut self) {
 91 | 		// Cannot free PID `0`
 92 | 		let Some(i) = self.0.checked_sub(1) else {
 93 | 			return;
 94 | 		};
 95 | 		// Cannot fail
 96 | 		let _ = allocator_do(|a| {
 97 | 			a.free(i as _);
 98 | 			Ok(())
 99 | 		});
100 | 	}
101 | }
102 | 


--------------------------------------------------------------------------------
/kernel/src/process/rusage.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Monitoring of the resource usage of processes.
20 | 
21 | use crate::time::unit::Timeval;
22 | 
23 | // TODO Place calls in kernel's code to update usage
24 | 
25 | /// Usage of each resource by a process.
26 | #[derive(Clone, Debug, Default)]
27 | pub struct Rusage {
28 | 	/// User CPU time used.
29 | 	pub ru_utime: Timeval,
30 | 	/// System CPU time used.
31 | 	pub ru_stime: Timeval,
32 | 	/// Maximum resident set size.
33 | 	pub ru_maxrss: i64,
34 | 	/// Integral shared memory size.
35 | 	pub ru_ixrss: i64,
36 | 	/// Integral unshared data size.
37 | 	pub ru_idrss: i64,
38 | 	/// Integral unshared stack size.
39 | 	pub ru_isrss: i64,
40 | 	/// Page reclaims (soft page faults).
41 | 	pub ru_minflt: i64,
42 | 	/// Page faults (hard page faults).
43 | 	pub ru_majflt: i64,
44 | 	/// Swaps.
45 | 	pub ru_nswap: i64,
46 | 	/// Block input operations.
47 | 	pub ru_inblock: i64,
48 | 	/// Block output operations.
49 | 	pub ru_oublock: i64,
50 | 	/// IPC messages sent.
51 | 	pub ru_msgsnd: i64,
52 | 	/// IPC messages received.
53 | 	pub ru_msgrcv: i64,
54 | 	/// Signals received.
55 | 	pub ru_nsignals: i64,
56 | 	/// Voluntary context switches.
57 | 	pub ru_nvcsw: i64,
58 | 	/// Involuntary context switches.
59 | 	pub ru_nivcsw: i64,
60 | }
61 | 


--------------------------------------------------------------------------------
/kernel/src/selftest.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Selftesting are unit tests or integration tests that run on the kernel itself.
20 | //!
21 | //! # Issues
22 | //!
23 | //! Since the kernel cannot reset itself between each test, this method of testing might not be
24 | //! entirely trustable because a test might corrupt the environment for the next tests, which might
25 | //! make them pass even though they should not. Even if this scenario is unlikely, this remains a
26 | //! concern since the kernel has to be as reliable as possible.
27 | 
28 | #[cfg(config_debug_qemu)]
29 | use crate::debug::qemu;
30 | use crate::power;
31 | use core::{
32 | 	any::type_name,
33 | 	sync::{atomic, atomic::AtomicBool},
34 | };
35 | 
36 | /// Boolean value telling whether selftesting is running.
37 | static RUNNING: AtomicBool = AtomicBool::new(false);
38 | 
39 | /// Trait for any testable feature.
40 | pub trait Testable {
41 | 	/// Function called to run the corresponding test.
42 | 	fn run(&self);
43 | }
44 | 
45 | impl<T> Testable for T
46 | where
47 | 	T: Fn(),
48 | {
49 | 	fn run(&self) {
50 | 		let name = type_name::<T>();
51 | 		crate::print!("test {name} ... ");
52 | 		self();
53 | 		crate::println!("ok");
54 | 	}
55 | }
56 | 
57 | /// The test runner for the kernel.
58 | ///
59 | /// This function runs every tests for the kernel and halts the kernel or exits the emulator if
60 | /// possible.
61 | pub fn runner(tests: &[&dyn Testable]) {
62 | 	crate::println!("Running {} tests", tests.len());
63 | 	RUNNING.store(true, atomic::Ordering::Relaxed);
64 | 	for test in tests {
65 | 		test.run();
66 | 	}
67 | 	RUNNING.store(false, atomic::Ordering::Relaxed);
68 | 	crate::println!("No more tests to run");
69 | 	#[cfg(config_debug_qemu)]
70 | 	qemu::exit(qemu::SUCCESS);
71 | 	power::halt();
72 | }
73 | 
74 | /// Tells whether selftesting is running.
75 | pub fn is_running() -> bool {
76 | 	RUNNING.load(atomic::Ordering::Relaxed)
77 | }
78 | 


--------------------------------------------------------------------------------
/kernel/src/sync/atomic.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Implementation of [`AtomicU64`].
20 | 
21 | #[cfg(not(target_has_atomic = "64"))]
22 | use super::mutex::IntMutex;
23 | use core::{fmt, fmt::Formatter, sync::atomic};
24 | 
25 | /// Fulfills the role of `AtomicU64`, while being available on 32 bits platforms.
26 | #[cfg(target_has_atomic = "64")]
27 | #[derive(Default)]
28 | pub struct AtomicU64(core::sync::atomic::AtomicU64);
29 | 
30 | /// Fulfills the role of `AtomicU64`, while being available on 32 bits platforms.
31 | #[cfg(not(target_has_atomic = "64"))]
32 | #[derive(Default)]
33 | pub struct AtomicU64(IntMutex<u64>);
34 | 
35 | impl AtomicU64 {
36 | 	/// Creates a new instance with the given value.
37 | 	pub const fn new(val: u64) -> Self {
38 | 		#[cfg(target_has_atomic = "64")]
39 | 		{
40 | 			Self(core::sync::atomic::AtomicU64::new(val))
41 | 		}
42 | 		#[cfg(not(target_has_atomic = "64"))]
43 | 		{
44 | 			Self(IntMutex::new(val))
45 | 		}
46 | 	}
47 | 
48 | 	/// Loads a value from the atomic integer.
49 | 	#[allow(unused_variables)]
50 | 	pub fn load(&self, order: atomic::Ordering) -> u64 {
51 | 		#[cfg(target_has_atomic = "64")]
52 | 		{
53 | 			self.0.load(order)
54 | 		}
55 | 		#[cfg(not(target_has_atomic = "64"))]
56 | 		{
57 | 			*self.0.lock()
58 | 		}
59 | 	}
60 | 
61 | 	/// Stores a value into the atomic integer.
62 | 	#[allow(unused_variables)]
63 | 	pub fn store(&self, val: u64, order: atomic::Ordering) {
64 | 		#[cfg(target_has_atomic = "64")]
65 | 		{
66 | 			self.0.store(val, order)
67 | 		}
68 | 		#[cfg(not(target_has_atomic = "64"))]
69 | 		{
70 | 			*self.0.lock() = val;
71 | 		}
72 | 	}
73 | 
74 | 	/// Adds to the current value, returning the previous value.
75 | 	#[allow(unused_variables)]
76 | 	pub fn fetch_add(&self, val: u64, order: atomic::Ordering) -> u64 {
77 | 		#[cfg(target_has_atomic = "64")]
78 | 		{
79 | 			self.0.fetch_add(val, order)
80 | 		}
81 | 		#[cfg(not(target_has_atomic = "64"))]
82 | 		{
83 | 			let mut guard = self.0.lock();
84 | 			let prev = *guard;
85 | 			*guard = guard.wrapping_add(val);
86 | 			prev
87 | 		}
88 | 	}
89 | }
90 | 
91 | impl fmt::Debug for AtomicU64 {
92 | 	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
93 | 		fmt::Debug::fmt(&self.0, f)
94 | 	}
95 | }
96 | 


--------------------------------------------------------------------------------
/kernel/src/sync/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Kernel synchronization primitives.
20 | 
21 | pub mod atomic;
22 | pub mod mutex;
23 | pub mod once;
24 | pub mod rcu;
25 | pub mod rwlock;
26 | pub mod spinlock;
27 | 


--------------------------------------------------------------------------------
/kernel/src/sync/once.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Once-initialized objects.
20 | 
21 | use core::{cell::UnsafeCell, mem::MaybeUninit, ops::Deref};
22 | 
23 | /// An object that is meant to be initialized once at boot, then accessed in read-only.
24 | ///
25 | /// The value **must** be initialized with `init` before calling `get`. Failure to do so results in
26 | /// an undefined behavior.
27 | pub struct OnceInit<T>(UnsafeCell<MaybeUninit<T>>);
28 | 
29 | impl<T> OnceInit<T> {
30 | 	/// Creates a new instance waiting to be initialized.
31 | 	///
32 | 	/// # Safety
33 | 	///
34 | 	/// The value **must** be initialized with before calling `get`.
35 | 	pub const unsafe fn new() -> Self {
36 | 		Self(UnsafeCell::new(MaybeUninit::uninit()))
37 | 	}
38 | 
39 | 	/// Initializes with the given value.
40 | 	///
41 | 	/// If already initialized, the previous value is **not** dropped.
42 | 	///
43 | 	/// # Safety
44 | 	///
45 | 	/// It is the caller's responsibility to enforce concurrency rules.
46 | 	pub unsafe fn init(this: &Self, val: T) -> &T {
47 | 		unsafe {
48 | 			let inner = &mut *this.0.get();
49 | 			inner.write(val);
50 | 			inner.assume_init_ref()
51 | 		}
52 | 	}
53 | }
54 | 
55 | impl<T> Deref for OnceInit<T> {
56 | 	type Target = T;
57 | 
58 | 	fn deref(&self) -> &Self::Target {
59 | 		unsafe { (*self.0.get()).assume_init_ref() }
60 | 	}
61 | }
62 | 
63 | unsafe impl<T> Sync for OnceInit<T> {}
64 | 


--------------------------------------------------------------------------------
/kernel/src/sync/spinlock.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Spinlock implementation.
20 | 
21 | use core::{
22 | 	hint,
23 | 	sync::{atomic, atomic::AtomicBool},
24 | };
25 | 
26 | /// Locking primitive spinning until the resource can be acquired.
27 | ///
28 | /// It works by storing a value telling whether a thread is already in that piece of code.
29 | ///
30 | /// To avoid race conditions, the implementation uses an atomic exchange instruction. If a threads
31 | /// tries to acquire the lock while already in use, the thread shall wait in a loop (spin) until
32 | /// the lock is released.
33 | pub struct Spinlock(AtomicBool);
34 | 
35 | impl Spinlock {
36 | 	/// Creates a new spinlock.
37 | 	#[allow(clippy::new_without_default)]
38 | 	pub const fn new() -> Self {
39 | 		Self(AtomicBool::new(false))
40 | 	}
41 | 
42 | 	/// Locks the spinlock.
43 | 	#[inline(always)]
44 | 	pub fn lock(&mut self) {
45 | 		while self.0.swap(true, atomic::Ordering::Acquire) {
46 | 			hint::spin_loop();
47 | 		}
48 | 	}
49 | 
50 | 	/// Unlocks the spinlock.
51 | 	#[inline(always)]
52 | 	pub fn unlock(&mut self) {
53 | 		self.0.store(false, atomic::Ordering::Release);
54 | 	}
55 | }
56 | 


--------------------------------------------------------------------------------
/kernel/src/syscall/getrandom.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The `getrandom` system call allows to get random bytes.
20 | 
21 | use crate::{crypto::rand, memory::user::UserSlice, syscall::Args};
22 | use core::ffi::c_uint;
23 | use utils::errno::EResult;
24 | 
25 | pub fn getrandom(Args((buf, buflen, flags)): Args<(*mut u8, usize, c_uint)>) -> EResult<usize> {
26 | 	let buf = UserSlice::from_user(buf, buflen)?;
27 | 	rand::getrandom(buf, flags)
28 | }
29 | 


--------------------------------------------------------------------------------
/kernel/src/syscall/module.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Kernel module system calls.
20 | 
21 | use crate::{
22 | 	file::{fd::FileDescriptorTable, perm::AccessProfile},
23 | 	memory::user::{UserSlice, UserString},
24 | 	module,
25 | 	module::Module,
26 | 	sync::mutex::Mutex,
27 | 	syscall::Args,
28 | };
29 | use core::{
30 | 	ffi::{c_int, c_uint, c_ulong},
31 | 	hint::unlikely,
32 | };
33 | use utils::{errno, errno::EResult, ptr::arc::Arc};
34 | 
35 | pub fn init_module(
36 | 	Args((module_image, len, _param_values)): Args<(*mut u8, c_ulong, UserString)>,
37 | 	ap: AccessProfile,
38 | ) -> EResult<usize> {
39 | 	let module_image = UserSlice::from_user(module_image, len as _)?;
40 | 	if unlikely(!ap.is_privileged()) {
41 | 		return Err(errno!(EPERM));
42 | 	}
43 | 	let image = module_image
44 | 		.copy_from_user_vec(0)?
45 | 		.ok_or_else(|| errno!(EFAULT))?;
46 | 	let module = Module::load(&image)?;
47 | 	module::add(module)?;
48 | 	Ok(0)
49 | }
50 | 
51 | pub fn finit_module(
52 | 	Args((fd, _param_values, _flags)): Args<(c_int, UserString, c_int)>,
53 | 	ap: AccessProfile,
54 | 	fds: Arc<Mutex<FileDescriptorTable>>,
55 | ) -> EResult<usize> {
56 | 	if !ap.is_privileged() {
57 | 		return Err(errno!(EPERM));
58 | 	}
59 | 	// Read file
60 | 	let image = fds.lock().get_fd(fd)?.get_file().read_all()?;
61 | 	let module = Module::load(&image)?;
62 | 	module::add(module)?;
63 | 	Ok(0)
64 | }
65 | 
66 | // TODO handle flags
67 | pub fn delete_module(
68 | 	Args((name, _flags)): Args<(UserString, c_uint)>,
69 | 	ap: AccessProfile,
70 | ) -> EResult<usize> {
71 | 	if !ap.is_privileged() {
72 | 		return Err(errno!(EPERM));
73 | 	}
74 | 	let name = name.copy_from_user()?.ok_or_else(|| errno!(EFAULT))?;
75 | 	// TODO handle dependency (don't unload a module that is required by another)
76 | 	module::remove(&name)?;
77 | 	Ok(0)
78 | }
79 | 


--------------------------------------------------------------------------------
/kernel/src/syscall/mount.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Mountpoint system calls.
20 | 
21 | use crate::{
22 | 	file::{
23 | 		FileType, fs, vfs,
24 | 		vfs::{ResolutionSettings, mountpoint, mountpoint::MountSource},
25 | 	},
26 | 	memory::user::{UserPtr, UserString},
27 | 	syscall::Args,
28 | };
29 | use core::ffi::{c_int, c_ulong, c_void};
30 | use utils::{collections::path::PathBuf, errno, errno::EResult};
31 | 
32 | pub fn mount(
33 | 	Args((source, target, filesystemtype, mountflags, _data)): Args<(
34 | 		UserString,
35 | 		UserString,
36 | 		UserString,
37 | 		c_ulong,
38 | 		UserPtr<c_void>,
39 | 	)>,
40 | 	rs: ResolutionSettings,
41 | ) -> EResult<usize> {
42 | 	if !rs.access_profile.is_privileged() {
43 | 		return Err(errno!(EPERM));
44 | 	}
45 | 	// Read arguments
46 | 	let source_slice = source.copy_from_user()?.ok_or(errno!(EFAULT))?;
47 | 	let mount_source = MountSource::new(&source_slice)?;
48 | 	let target_slice = target.copy_from_user()?.ok_or(errno!(EFAULT))?;
49 | 	let target_path = PathBuf::try_from(target_slice)?;
50 | 	let filesystemtype_slice = filesystemtype.copy_from_user()?.ok_or(errno!(EFAULT))?;
51 | 	let fs_type = fs::get_type(&filesystemtype_slice).ok_or(errno!(ENODEV))?;
52 | 	// Get target file
53 | 	let target = vfs::get_file_from_path(&target_path, &rs)?;
54 | 	// Check the target is a directory
55 | 	if target.get_type()? != FileType::Directory {
56 | 		return Err(errno!(ENOTDIR));
57 | 	}
58 | 	// TODO Use `data`
59 | 	// Create mountpoint
60 | 	mountpoint::create(mount_source, Some(fs_type), mountflags as _, Some(target))?;
61 | 	Ok(0)
62 | }
63 | 
64 | pub fn umount(Args(target): Args<UserString>, rs: ResolutionSettings) -> EResult<usize> {
65 | 	umount2(Args((target, 0)), rs)
66 | }
67 | 
68 | pub fn umount2(
69 | 	Args((target, _flags)): Args<(UserString, c_int)>,
70 | 	rs: ResolutionSettings,
71 | ) -> EResult<usize> {
72 | 	// TODO handle flags
73 | 	// Check permission
74 | 	if !rs.access_profile.is_privileged() {
75 | 		return Err(errno!(EPERM));
76 | 	}
77 | 	// Get target directory
78 | 	let target_slice = target.copy_from_user()?.ok_or(errno!(EFAULT))?;
79 | 	let target_path = PathBuf::try_from(target_slice)?;
80 | 	let target = vfs::get_file_from_path(&target_path, &rs)?;
81 | 	// Remove mountpoint
82 | 	mountpoint::remove(target)?;
83 | 	Ok(0)
84 | }
85 | 


--------------------------------------------------------------------------------
/kernel/src/syscall/pipe.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The `pipe` system call allows to create a pipe.
20 | 
21 | use crate::{
22 | 	file,
23 | 	file::{File, fd::FileDescriptorTable, pipe::PipeBuffer},
24 | 	memory::user::UserPtr,
25 | 	sync::mutex::Mutex,
26 | 	syscall::Args,
27 | };
28 | use core::ffi::c_int;
29 | use utils::{errno, errno::EResult, ptr::arc::Arc};
30 | 
31 | pub fn pipe(
32 | 	Args(pipefd): Args<UserPtr<[c_int; 2]>>,
33 | 	fds: Arc<Mutex<FileDescriptorTable>>,
34 | ) -> EResult<usize> {
35 | 	let ops = Arc::new(PipeBuffer::new()?)?;
36 | 	let file0 = File::open_floating(ops.clone(), file::O_RDONLY)?;
37 | 	let file1 = File::open_floating(ops, file::O_WRONLY)?;
38 | 	let (fd0_id, fd1_id) = fds.lock().create_fd_pair(file0, file1)?;
39 | 	pipefd.copy_to_user(&[fd0_id as _, fd1_id as _])?;
40 | 	Ok(0)
41 | }
42 | 
43 | pub fn pipe2(
44 | 	Args((pipefd, flags)): Args<(UserPtr<[c_int; 2]>, c_int)>,
45 | 	fds: Arc<Mutex<FileDescriptorTable>>,
46 | ) -> EResult<usize> {
47 | 	// Validation
48 | 	let accepted_flags = file::O_CLOEXEC | file::O_DIRECT | file::O_NONBLOCK;
49 | 	if flags & !accepted_flags != 0 {
50 | 		return Err(errno!(EINVAL));
51 | 	}
52 | 	let ops = Arc::new(PipeBuffer::new()?)?;
53 | 	let file0 = File::open_floating(ops.clone(), flags | file::O_RDONLY)?;
54 | 	let file1 = File::open_floating(ops, flags | file::O_WRONLY)?;
55 | 	let (fd0_id, fd1_id) = fds.lock().create_fd_pair(file0, file1)?;
56 | 	pipefd.copy_to_user(&[fd0_id as _, fd1_id as _])?;
57 | 	Ok(0)
58 | }
59 | 


--------------------------------------------------------------------------------
/kernel/src/syscall/util/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Utility functions for system calls.
20 | 
21 | pub mod at;
22 | 


--------------------------------------------------------------------------------
/kernel/src/time/hw/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements hardware clocks.
20 | 
21 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
22 | pub mod pit;
23 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
24 | pub mod rtc;
25 | 
26 | use crate::{sync::mutex::Mutex, time::unit::Timestamp};
27 | use utils::{
28 | 	boxed::Box,
29 | 	collections::{hashmap::HashMap, string::String},
30 | };
31 | 
32 | /// Trait representing a hardware clock.
33 | pub trait HwClock {
34 | 	/// Enables or disable the clock.
35 | 	fn set_enabled(&mut self, enable: bool);
36 | 	/// Sets the clock's frequency in hertz.
37 | 	///
38 | 	/// The actual frequency is the closest possible rounded down according to the clock's
39 | 	/// resolution.
40 | 	fn set_frequency(&mut self, freq: u32);
41 | 
42 | 	/// Returns the value of the clock, if applicable.
43 | 	fn get_value(&self) -> Option<Timestamp> {
44 | 		None
45 | 	}
46 | 
47 | 	/// Returns the interrupt vector of the timer.
48 | 	fn get_interrupt_vector(&self) -> u32;
49 | }
50 | 
51 | /// The list of hardware clock sources.
52 | ///
53 | /// The key is the name of the clock.
54 | pub static CLOCKS: Mutex<HashMap<String, Box<dyn HwClock>>> = Mutex::new(HashMap::new());
55 | 


--------------------------------------------------------------------------------
/kernel/src/time/hw/pit.rs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright 2024 Luc Lenôtre
  3 |  *
  4 |  * This file is part of Maestro.
  5 |  *
  6 |  * Maestro is free software: you can redistribute it and/or modify it under the
  7 |  * terms of the GNU General Public License as published by the Free Software
  8 |  * Foundation, either version 3 of the License, or (at your option) any later
  9 |  * version.
 10 |  *
 11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
 12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 14 |  *
 15 |  * You should have received a copy of the GNU General Public License along with
 16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
 17 |  */
 18 | 
 19 | //! This module handles the PIT (Programmable Interrupt Timer) which allows to
 20 | //! trigger interruptions at a fixed interval.
 21 | 
 22 | use super::HwClock;
 23 | use crate::arch::x86::{idt, io::outb, pic};
 24 | 
 25 | /// PIT channel number 0.
 26 | const CHANNEL_0: u16 = 0x40;
 27 | /// PIT channel number 2.
 28 | const CHANNEL_2: u16 = 0x42;
 29 | /// The port to send a command to the PIT.
 30 | const PIT_COMMAND: u16 = 0x43;
 31 | 
 32 | /// The command to enable the PC speaker.
 33 | const BEEPER_ENABLE_COMMAND: u8 = 0x61;
 34 | 
 35 | /// Select PIT channel 0.
 36 | const SELECT_CHANNEL_0: u8 = 0b00 << 6;
 37 | /// Select PIT channel 2.
 38 | const SELECT_CHANNEL_2: u8 = 0b10 << 6;
 39 | 
 40 | /// Tells the PIT to read the whole counter value.
 41 | const ACCESS_LOBYTE_HIBYTE: u8 = 0b11 << 4;
 42 | 
 43 | /// Square wave generator.
 44 | const MODE_3: u8 = 0b011 << 1;
 45 | 
 46 | /// The base frequency of the PIT.
 47 | const BASE_FREQUENCY: u32 = 1193182;
 48 | 
 49 | // FIXME prevent having several instances at the same time
 50 | 
 51 | /// The PIT.
 52 | pub struct PIT {}
 53 | 
 54 | impl PIT {
 55 | 	/// Creates a new instance.
 56 | 	///
 57 | 	/// By default, the timer is disabled and its frequency is undefined.
 58 | 	#[allow(clippy::new_without_default)]
 59 | 	pub fn new() -> Self {
 60 | 		let mut s = Self {};
 61 | 		s.set_enabled(false);
 62 | 		idt::wrap_disable_interrupts(|| unsafe {
 63 | 			outb(
 64 | 				PIT_COMMAND,
 65 | 				SELECT_CHANNEL_0 | ACCESS_LOBYTE_HIBYTE | MODE_3,
 66 | 			);
 67 | 			s.set_frequency(1);
 68 | 		});
 69 | 		s
 70 | 	}
 71 | }
 72 | 
 73 | impl HwClock for PIT {
 74 | 	fn set_enabled(&mut self, enable: bool) {
 75 | 		if enable {
 76 | 			pic::enable_irq(0x0);
 77 | 		} else {
 78 | 			pic::disable_irq(0x0);
 79 | 		}
 80 | 	}
 81 | 
 82 | 	fn set_frequency(&mut self, frequency: u32) {
 83 | 		let mut count = if frequency != 0 {
 84 | 			(BASE_FREQUENCY / frequency) as u16
 85 | 		} else {
 86 | 			0
 87 | 		};
 88 | 		if count == 0xffff {
 89 | 			count = 0;
 90 | 		}
 91 | 
 92 | 		// Update frequency divider's value
 93 | 		idt::wrap_disable_interrupts(|| unsafe {
 94 | 			outb(CHANNEL_0, (count & 0xff) as u8);
 95 | 			outb(CHANNEL_0, ((count >> 8) & 0xff) as u8);
 96 | 		});
 97 | 	}
 98 | 
 99 | 	fn get_interrupt_vector(&self) -> u32 {
100 | 		0x20
101 | 	}
102 | }
103 | 
104 | impl Drop for PIT {
105 | 	fn drop(&mut self) {
106 | 		self.set_enabled(false);
107 | 	}
108 | }
109 | 


--------------------------------------------------------------------------------
/kernel/src/time/hw/rtc.rs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * Copyright 2024 Luc Lenôtre
  3 |  *
  4 |  * This file is part of Maestro.
  5 |  *
  6 |  * Maestro is free software: you can redistribute it and/or modify it under the
  7 |  * terms of the GNU General Public License as published by the Free Software
  8 |  * Foundation, either version 3 of the License, or (at your option) any later
  9 |  * version.
 10 |  *
 11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
 12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 14 |  *
 15 |  * You should have received a copy of the GNU General Public License along with
 16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
 17 |  */
 18 | 
 19 | //! The Real Time Clock (RTC) is the clock used by the CMOS to maintain system time.
 20 | 
 21 | use super::HwClock;
 22 | use crate::arch::x86::{
 23 | 	idt,
 24 | 	io::{inb, outb},
 25 | };
 26 | 
 27 | /// The ID of the port used to select the CMOS register to read.
 28 | const SELECT_PORT: u16 = 0x70;
 29 | /// The ID of the port to read or write a CMOS port previously selected.
 30 | const VALUE_PORT: u16 = 0x71;
 31 | 
 32 | /// The ID of the status register A.
 33 | const STATUS_A_REGISTER: u8 = 0x0a;
 34 | /// The ID of the status register B.
 35 | const STATUS_B_REGISTER: u8 = 0x0b;
 36 | /// The ID of the status register C.
 37 | const STATUS_C_REGISTER: u8 = 0x0c;
 38 | 
 39 | // FIXME prevent having several instances at the same time
 40 | 
 41 | /// The RTC.
 42 | ///
 43 | /// **Note**: the RTC needs a call to `reset` to allow the next tick to be fired.
 44 | pub struct RTC {}
 45 | 
 46 | impl RTC {
 47 | 	/// Creates a new instance.
 48 | 	///
 49 | 	/// By default, the timer is disabled and its frequency is undefined.
 50 | 	#[allow(clippy::new_without_default)]
 51 | 	pub fn new() -> Self {
 52 | 		let mut s = Self {};
 53 | 		s.set_enabled(false);
 54 | 		s
 55 | 	}
 56 | 
 57 | 	/// Resets the timer to make it ready for the next tick.
 58 | 	#[inline]
 59 | 	pub fn reset() {
 60 | 		unsafe {
 61 | 			outb(SELECT_PORT, STATUS_C_REGISTER);
 62 | 			inb(VALUE_PORT);
 63 | 		}
 64 | 	}
 65 | }
 66 | 
 67 | impl HwClock for RTC {
 68 | 	fn set_enabled(&mut self, enable: bool) {
 69 | 		idt::wrap_disable_interrupts(|| unsafe {
 70 | 			outb(SELECT_PORT, STATUS_B_REGISTER | 0x80);
 71 | 			let prev = inb(VALUE_PORT);
 72 | 			outb(SELECT_PORT, STATUS_B_REGISTER | 0x80);
 73 | 			if enable {
 74 | 				outb(VALUE_PORT, prev | 0x40);
 75 | 			} else {
 76 | 				outb(VALUE_PORT, prev & !0x40);
 77 | 			}
 78 | 		});
 79 | 	}
 80 | 
 81 | 	fn set_frequency(&mut self, freq: u32) {
 82 | 		let rate = (32768u32 / freq).trailing_zeros() as u8 + 1;
 83 | 		idt::wrap_disable_interrupts(|| unsafe {
 84 | 			outb(SELECT_PORT, STATUS_A_REGISTER | 0x80);
 85 | 			let prev = inb(VALUE_PORT);
 86 | 			outb(SELECT_PORT, STATUS_A_REGISTER | 0x80);
 87 | 			outb(VALUE_PORT, (prev & 0xf0) | (rate & 0x0f));
 88 | 		});
 89 | 	}
 90 | 
 91 | 	fn get_interrupt_vector(&self) -> u32 {
 92 | 		0x28
 93 | 	}
 94 | }
 95 | 
 96 | impl Drop for RTC {
 97 | 	fn drop(&mut self) {
 98 | 		self.set_enabled(false);
 99 | 	}
100 | }
101 | 


--------------------------------------------------------------------------------
/kernel/vdso/linker.ld:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | SECTIONS
20 | {
21 | 	ENTRY(__kernel_vsyscall)
22 | 
23 | 	. = 0x1000;
24 | 
25 | 	.text BLOCK(4K) : ALIGN(4K)
26 | 	{
27 | 		*(.text)
28 | 	}
29 | }
30 | 


--------------------------------------------------------------------------------
/kernel/vdso/x86.s:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | .section .text
20 | 
21 | .global __kernel_vsyscall
22 | .global __kernel_rt_sigreturn
23 | .global __kernel_sigreturn
24 | .global __vdso_clock_gettime
25 | .global __vdso_gettimeofday
26 | .global __vdso_time
27 | 
28 | __kernel_vsyscall:
29 | 	int $0x80
30 | 	ret
31 | 
32 | __kernel_rt_sigreturn:
33 | 	# TODO
34 | 	ud2
35 | 
36 | __kernel_sigreturn:
37 | 	# TODO
38 | 	ud2
39 | 
40 | __vdso_clock_gettime:
41 | 	# TODO
42 | 	ud2
43 | 
44 | __vdso_gettimeofday:
45 | 	# TODO
46 | 	ud2
47 | 
48 | __vdso_time:
49 | 	# TODO
50 | 	ud2
51 | 


--------------------------------------------------------------------------------
/kernel/vdso/x86_64.s:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | .section .text
20 | 
21 | .global __vdso_clock_gettime
22 | .global __vdso_getcpu
23 | .global __vdso_gettimeofday
24 | .global __vdso_time
25 | 
26 | __vdso_clock_gettime:
27 | 	# TODO
28 | 	ud2
29 | 
30 | __vdso_getcpu:
31 |     # TODO
32 |     ud2
33 | 
34 | __vdso_gettimeofday:
35 | 	# TODO
36 | 	ud2
37 | 
38 | __vdso_time:
39 | 	# TODO
40 | 	ud2
41 | 


--------------------------------------------------------------------------------
/macros/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | 


--------------------------------------------------------------------------------
/macros/Cargo.lock:
--------------------------------------------------------------------------------
 1 | # This file is automatically @generated by Cargo.
 2 | # It is not intended for manual editing.
 3 | version = 4
 4 | 
 5 | [[package]]
 6 | name = "macros"
 7 | version = "0.1.0"
 8 | dependencies = [
 9 |  "proc-macro2",
10 |  "quote",
11 |  "syn",
12 | ]
13 | 
14 | [[package]]
15 | name = "proc-macro2"
16 | version = "1.0.95"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
19 | dependencies = [
20 |  "unicode-ident",
21 | ]
22 | 
23 | [[package]]
24 | name = "quote"
25 | version = "1.0.40"
26 | source = "registry+https://github.com/rust-lang/crates.io-index"
27 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
28 | dependencies = [
29 |  "proc-macro2",
30 | ]
31 | 
32 | [[package]]
33 | name = "syn"
34 | version = "2.0.101"
35 | source = "registry+https://github.com/rust-lang/crates.io-index"
36 | checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
37 | dependencies = [
38 |  "proc-macro2",
39 |  "quote",
40 |  "unicode-ident",
41 | ]
42 | 
43 | [[package]]
44 | name = "unicode-ident"
45 | version = "1.0.18"
46 | source = "registry+https://github.com/rust-lang/crates.io-index"
47 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
48 | 


--------------------------------------------------------------------------------
/macros/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "macros"
 3 | version = "0.1.0"
 4 | edition = "2024"
 5 | 
 6 | [lib]
 7 | proc-macro = true
 8 | 
 9 | [dependencies]
10 | proc-macro2 = "1.0.95"
11 | quote = "1.0.40"
12 | syn = { version = "2.0.101", features = ["full", "extra-traits"] }
13 | 
14 | [features]
15 | default = []
16 | strace = []
17 | 


--------------------------------------------------------------------------------
/macros/rustfmt.toml:
--------------------------------------------------------------------------------
1 | ../rustfmt.toml


--------------------------------------------------------------------------------
/macros/src/lib.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This crate implements derive macros for the Maestro kernel.
20 | 
21 | #![feature(iter_intersperse)]
22 | 
23 | extern crate proc_macro;
24 | 
25 | mod aml;
26 | mod util;
27 | 
28 | use crate::util::has_repr_c;
29 | use proc_macro::TokenStream;
30 | use quote::quote;
31 | use syn::{DeriveInput, parse_macro_input};
32 | 
33 | /// Implements `AnyRepr`, making necessary safety checks.
34 | #[proc_macro_derive(AnyRepr)]
35 | pub fn any_repr(input: TokenStream) -> TokenStream {
36 | 	let input = parse_macro_input!(input as DeriveInput);
37 | 	let ident = input.ident;
38 | 	if !has_repr_c(&input.attrs) {
39 | 		panic!("{ident} is not suitable for the trait `AnyRepr`");
40 | 	}
41 | 	let toks = quote! {
42 | 		unsafe impl utils::bytes::AnyRepr for #ident {}
43 | 	};
44 | 	TokenStream::from(toks)
45 | }
46 | 
47 | /// Definition of a derive macro used to turn a structure into a parsable object for the AML
48 | /// bytecode.
49 | ///
50 | /// TODO further document
51 | #[proc_macro_derive(Parseable)]
52 | pub fn aml_parseable(input: TokenStream) -> TokenStream {
53 | 	aml::derive_parseable(input)
54 | }
55 | 


--------------------------------------------------------------------------------
/macros/src/util.rs:
--------------------------------------------------------------------------------
 1 | //! Utility functions.
 2 | 
 3 | use proc_macro2::TokenTree;
 4 | use syn::{AttrStyle, Attribute, Meta, MetaList, Path};
 5 | 
 6 | /// Tells whether the list of attributes contains `repr(C)`.
 7 | pub fn has_repr_c(attrs: &[Attribute]) -> bool {
 8 | 	attrs
 9 | 		.iter()
10 | 		.filter_map(|attr| {
11 | 			if !matches!(attr.style, AttrStyle::Outer) {
12 | 				return None;
13 | 			}
14 | 			let Path {
15 | 				leading_colon: None,
16 | 				segments,
17 | 				..
18 | 			} = attr.path()
19 | 			else {
20 | 				return None;
21 | 			};
22 | 			if segments.len() != 1 {
23 | 				return None;
24 | 			}
25 | 			let seg = segments.first().unwrap();
26 | 			if !seg.arguments.is_empty() {
27 | 				return None;
28 | 			}
29 | 			if seg.ident != "repr" {
30 | 				return None;
31 | 			}
32 | 			let Meta::List(MetaList {
33 | 				ref tokens, ..
34 | 			}) = attr.meta
35 | 			else {
36 | 				return None;
37 | 			};
38 | 			Some(tokens.clone())
39 | 		})
40 | 		.flat_map(|tokens| tokens.into_iter())
41 | 		.filter_map(|tok| {
42 | 			if let TokenTree::Ident(ident) = tok {
43 | 				Some(ident)
44 | 			} else {
45 | 				None
46 | 			}
47 | 		})
48 | 		.any(|ident| ident == "C")
49 | }
50 | 


--------------------------------------------------------------------------------
/mod/build:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | # This script builds kernel modules.
 4 | 
 5 | KERN_SRC=$(realpath $(dirname $0)/..)
 6 | if [ -z "$ARCH" ]; then
 7 | 	ARCH="x86_64"
 8 | fi
 9 | export CARGOFLAGS="--target $KERN_SRC/kernel/arch/$ARCH/$ARCH.json $CARGOFLAGS"
10 | 
11 | if [ ! -z "$PROFILE" ] && [ "$PROFILE" != "debug" ]; then
12 | 	CARGOFLAGS="$CARGOFLAGS --profile $PROFILE"
13 | else
14 | 	export PROFILE="debug"
15 | fi
16 | export RUSTFLAGS="--extern kernel=$KERN_SRC/kernel/target/$ARCH/$PROFILE/libkernel.rlib -L $KERN_SRC/kernel/target/$ARCH/$PROFILE/deps -L $KERN_SRC/kernel/target/$PROFILE/deps $RUSTFLAGS"
17 | 
18 | cargo build $CARGOFLAGS $@
19 | 


--------------------------------------------------------------------------------
/mod/template/Cargo.toml:
--------------------------------------------------------------------------------
 1 | cargo-features = ["profile-rustflags"]
 2 | 
 3 | [package]
 4 | name = "hello"
 5 | version = "0.1.0"
 6 | edition = "2024"
 7 | 
 8 | [lib]
 9 | path = "src/mod.rs"
10 | crate-type = ["dylib"]
11 | 
12 | [dependencies]
13 | 
14 | [profile.release]
15 | panic = "abort"
16 | 
17 | [profile.dev]
18 | rustflags = [
19 | 	"-Cforce-frame-pointers=yes"
20 | ]
21 | 


--------------------------------------------------------------------------------
/mod/template/rust-toolchain.toml:
--------------------------------------------------------------------------------
1 | ../../rust-toolchain.toml


--------------------------------------------------------------------------------
/mod/template/src/mod.rs:
--------------------------------------------------------------------------------
 1 | //! <Add documentation for your module here>
 2 | 
 3 | #![no_std]
 4 | #![no_main]
 5 | 
 6 | // Do not include kernel symbols in the module
 7 | #[no_link]
 8 | extern crate kernel;
 9 | 
10 | // Declare the module, with its dependencies
11 | kernel::module!([]);
12 | 
13 | /// Called on module load
14 | #[unsafe(no_mangle)]
15 | pub extern "C" fn init() -> bool {
16 | 	kernel::println!("Hello world!");
17 | 	true
18 | }
19 | 
20 | /// Called on module unload
21 | #[unsafe(no_mangle)]
22 | pub extern "C" fn fini() {
23 | 	kernel::println!("Goodbye!");
24 | }
25 | 


--------------------------------------------------------------------------------
/rust-toolchain.toml:
--------------------------------------------------------------------------------
1 | [toolchain]
2 | channel = "nightly-2025-05-10"
3 | components = ["rustfmt", "rustc-dev", "rust-src", "clippy", "miri"]
4 | targets = ["i686-unknown-linux-musl", "x86_64-unknown-linux-musl"]
5 | profile = "minimal"
6 | 


--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
 1 | blank_lines_upper_bound = 1
 2 | comment_width = 99
 3 | condense_wildcard_suffixes = true
 4 | format_code_in_doc_comments = true
 5 | group_imports = "One"
 6 | hard_tabs = true
 7 | hex_literal_case = "Lower"
 8 | imports_granularity = "Crate"
 9 | imports_indent = "Block"
10 | max_width = 99
11 | newline_style = "Unix"
12 | reorder_impl_items = true
13 | struct_lit_single_line = false
14 | use_field_init_shorthand = true
15 | wrap_comments = true


--------------------------------------------------------------------------------
/utils/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | 


--------------------------------------------------------------------------------
/utils/Cargo.lock:
--------------------------------------------------------------------------------
 1 | # This file is automatically @generated by Cargo.
 2 | # It is not intended for manual editing.
 3 | version = 4
 4 | 
 5 | [[package]]
 6 | name = "macros"
 7 | version = "0.1.0"
 8 | dependencies = [
 9 |  "proc-macro2",
10 |  "quote",
11 |  "syn",
12 | ]
13 | 
14 | [[package]]
15 | name = "proc-macro2"
16 | version = "1.0.95"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
19 | dependencies = [
20 |  "unicode-ident",
21 | ]
22 | 
23 | [[package]]
24 | name = "quote"
25 | version = "1.0.40"
26 | source = "registry+https://github.com/rust-lang/crates.io-index"
27 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
28 | dependencies = [
29 |  "proc-macro2",
30 | ]
31 | 
32 | [[package]]
33 | name = "syn"
34 | version = "2.0.101"
35 | source = "registry+https://github.com/rust-lang/crates.io-index"
36 | checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
37 | dependencies = [
38 |  "proc-macro2",
39 |  "quote",
40 |  "unicode-ident",
41 | ]
42 | 
43 | [[package]]
44 | name = "unicode-ident"
45 | version = "1.0.18"
46 | source = "registry+https://github.com/rust-lang/crates.io-index"
47 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
48 | 
49 | [[package]]
50 | name = "utils"
51 | version = "0.1.0"
52 | dependencies = [
53 |  "macros",
54 | ]
55 | 


--------------------------------------------------------------------------------
/utils/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "utils"
 3 | version = "0.1.0"
 4 | edition = "2024"
 5 | 
 6 | [dependencies]
 7 | macros = { path = "../macros" }
 8 | 
 9 | [features]
10 | default = []
11 | std = []
12 | healthcheck = []
13 | 


--------------------------------------------------------------------------------
/utils/README.md:
--------------------------------------------------------------------------------
 1 | # util
 2 | 
 3 | Utilities are implemented in a separate library to allow easier debugging, by running tests in userspace.
 4 | 
 5 | 
 6 | 
 7 | ## Run tests
 8 | 
 9 | You can use the command:
10 | 
11 | ```sh
12 | cargo test
13 | ```
14 | 
15 | to run unit tests in userspace.
16 | 
17 | Tests can also be run with [Miri](https://github.com/rust-lang/miri) using:
18 | 
19 | ```sh
20 | cargo miri test
21 | ```


--------------------------------------------------------------------------------
/utils/src/collections/id_allocator.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements an identifier allocator, allowing to allocate and
20 | //! free indexes in range `0..=max`, where `max` is given.
21 | 
22 | use crate::{collections::bitfield::Bitfield, errno::AllocResult};
23 | use core::alloc::AllocError;
24 | 
25 | /// Structure representing an identifier allocator.
26 | pub struct IDAllocator {
27 | 	/// The bitfield keeping track of used identifiers.
28 | 	used: Bitfield,
29 | }
30 | 
31 | impl IDAllocator {
32 | 	/// Creates a new instance.
33 | 	///
34 | 	/// `max` is the maximum ID.
35 | 	pub fn new(max: u32) -> AllocResult<Self> {
36 | 		Ok(Self {
37 | 			used: Bitfield::new((max + 1) as _)?,
38 | 		})
39 | 	}
40 | 
41 | 	/// Tells whether `id` is marked as used.
42 | 	///
43 | 	/// If out of bounds, the function returns `true`.
44 | 	pub fn is_used(&self, id: u32) -> bool {
45 | 		if id <= self.used.len() as _ {
46 | 			self.used.is_set(id as _)
47 | 		} else {
48 | 			true
49 | 		}
50 | 	}
51 | 
52 | 	/// Sets `id` as used.
53 | 	pub fn set_used(&mut self, id: u32) {
54 | 		if id <= self.used.len() as _ {
55 | 			self.used.set(id as _);
56 | 		}
57 | 	}
58 | 
59 | 	/// Allocates an identifier.
60 | 	///
61 | 	/// If `id` is not `None`, the function shall allocate the given id.
62 | 	///
63 | 	/// If the allocation fails, the function returns `None`.
64 | 	#[must_use = "not freeing a PID shall cause a leak"]
65 | 	pub fn alloc(&mut self, id: Option<u32>) -> AllocResult<u32> {
66 | 		if let Some(i) = id {
67 | 			if !self.used.is_set(i as _) {
68 | 				self.used.set(i as _);
69 | 				Ok(i)
70 | 			} else {
71 | 				Err(AllocError)
72 | 			}
73 | 		} else if let Some(i) = self.used.find_clear() {
74 | 			self.used.set(i);
75 | 			Ok(i as _)
76 | 		} else {
77 | 			Err(AllocError)
78 | 		}
79 | 	}
80 | 
81 | 	/// Frees the given identifier `id`.
82 | 	pub fn free(&mut self, id: u32) {
83 | 		if id <= self.used.len() as _ {
84 | 			self.used.clear(id as _);
85 | 		}
86 | 	}
87 | }
88 | 


--------------------------------------------------------------------------------
/utils/src/collections/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements collections.
20 | 
21 | pub mod bitfield;
22 | pub mod btreemap;
23 | pub mod hashmap;
24 | pub mod hashset;
25 | pub mod id_allocator;
26 | pub mod list;
27 | pub mod path;
28 | pub mod string;
29 | pub mod vec;
30 | 


--------------------------------------------------------------------------------
/utils/src/math.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! The functions in this module implement utilities for integer mathematics.
20 | //!
21 | //! Since floating point numbers are slow, imprecise and may even be disabled by
22 | //! default, the kernel uses only integers.
23 | 
24 | use core::ops::{Rem, Shl};
25 | 
26 | /// Computes `pow(2, n)` where `n` is unsigned.
27 | ///
28 | /// The behaviour is undefined for n < 0.
29 | #[inline(always)]
30 | pub fn pow2<T>(n: T) -> T
31 | where
32 | 	T: From<u8> + Shl<Output = T>,
33 | {
34 | 	T::from(1) << n
35 | }
36 | 
37 | /// Pseudo random number generation based on linear congruential generator.
38 | ///
39 | /// Arguments:
40 | /// - `x` is the value to compute the next number from. It should either be a seed, or the previous
41 | ///   value returned from this function.
42 | /// - `a`, `c` and `m` are hyperparameters use as follows: (a * x + c) % m.
43 | pub fn pseudo_rand(x: u32, a: u32, c: u32, m: u32) -> u32 {
44 | 	a.wrapping_mul(x).wrapping_add(c) % m
45 | }
46 | 
47 | /// Returns the Greatest Common Divider of the two given numbers.
48 | pub fn gcd<T>(mut a: T, mut b: T) -> T
49 | where
50 | 	T: Clone + From<u8> + PartialEq + Rem<Output = T>,
51 | {
52 | 	while b != T::from(0) {
53 | 		let r = a % b.clone();
54 | 		a = b;
55 | 		b = r;
56 | 	}
57 | 	a
58 | }
59 | 
60 | #[cfg(test)]
61 | mod test {
62 | 	use super::*;
63 | 
64 | 	#[test]
65 | 	fn gcd0() {
66 | 		assert_eq!(gcd(2, 2), 2);
67 | 		assert_eq!(gcd(4, 2), 2);
68 | 		assert_eq!(gcd(4, 4), 4);
69 | 		assert_eq!(gcd(8, 12), 4);
70 | 		assert_eq!(gcd(48, 18), 6);
71 | 	}
72 | }
73 | 


--------------------------------------------------------------------------------
/utils/src/ptr/mod.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! This module implements smart pointers.
20 | 
21 | pub mod arc;
22 | pub mod cow;
23 | 


--------------------------------------------------------------------------------
/utils/src/unsafe_mut.rs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2024 Luc Lenôtre
 3 |  *
 4 |  * This file is part of Maestro.
 5 |  *
 6 |  * Maestro is free software: you can redistribute it and/or modify it under the
 7 |  * terms of the GNU General Public License as published by the Free Software
 8 |  * Foundation, either version 3 of the License, or (at your option) any later
 9 |  * version.
10 |  *
11 |  * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
12 |  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 |  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 |  *
15 |  * You should have received a copy of the GNU General Public License along with
16 |  * Maestro. If not, see <https://www.gnu.org/licenses/>.
17 |  */
18 | 
19 | //! Unsafe mutable wrapper.
20 | 
21 | use core::{cell::UnsafeCell, ops::Deref};
22 | 
23 | /// Wrapper allowing safe immutable accesses, or unsafe mutable accesses at the same time.
24 | #[derive(Default)]
25 | pub struct UnsafeMut<T>(UnsafeCell<T>);
26 | 
27 | impl<T> UnsafeMut<T> {
28 | 	/// Creates a new instance.
29 | 	pub fn new(val: T) -> Self {
30 | 		Self(UnsafeCell::new(val))
31 | 	}
32 | 
33 | 	/// Returns an immutable reference.
34 | 	pub fn get(&self) -> &T {
35 | 		unsafe { &*self.0.get() }
36 | 	}
37 | 
38 | 	/// Returns a mutable reference.
39 | 	///
40 | 	/// # Safety
41 | 	///
42 | 	/// The caller must ensure no other thread is accessing the value at the same time.
43 | 	#[allow(clippy::mut_from_ref)]
44 | 	pub unsafe fn get_mut(&self) -> &mut T {
45 | 		unsafe { &mut *self.0.get() }
46 | 	}
47 | }
48 | 
49 | impl<T> Deref for UnsafeMut<T> {
50 | 	type Target = T;
51 | 
52 | 	fn deref(&self) -> &Self::Target {
53 | 		self.get()
54 | 	}
55 | }
56 | 
57 | impl<T: Clone> Clone for UnsafeMut<T> {
58 | 	fn clone(&self) -> Self {
59 | 		let inner = unsafe { &*self.0.get() };
60 | 		Self(UnsafeCell::new(inner.clone()))
61 | 	}
62 | }
63 | 


--------------------------------------------------------------------------------