On boot, we start executing code from the **Boot Sector**. This contains the assembly instructions, which then jump to the `kernel` code in the **Kernel Sector**.
The `kernel` then reads in bytes from the first partition *(as the sectors are fixed-size, we know when this starts)* into memory, serializing it into a `PartitionHeader` struct via [bincode](https://lib.rs/crates/bincode).
From here, as we have a fixed `CHUNK_SIZE`, and know how many chunks are in our first partition, we can read from any chunk on any partition now.
On startup, an *Actor* can request to read data from the disk. If it has the right [capabilities](/development/design/actor.md#ocap), we find the chunk it's looking for[^find_chunk], parse the data (using `bincode` again), and send it back.
If it does, we simply pass it along like normal. If not, we refuse, and send an error [message](/development/design/actor.md#messages).
### Writing
Writing uses a similar process. An *Actor* can request to write data. If it has proper capabilties, we serialize the data, allocate a free chunk[^free_chunk], and write to it.
Created in-memory on startup, modified directly whenever the filesystem is modified.
It's saved in the *Index Sector* (which is at a known offset & size), allowing it to be read in easily on boot.
It again simply uses `bincode` and compression.
While the index is not necessarily a fixed size, we read until we have enough data from the fixed sector size.
```rust
use hashbrown::HashMap;
let mut index = HashMap::new(); // Create the index
struct Location {
partition: Uuid, // Partition identified via Uuid
chunks: Vec<u64>, // Which chunk(s) in the partition it is
}
let new_data = (Uuid::new(), b"data"); // Test data w/ an actor Uuid & bytes
let new_data_location = Location {
partition_offset: Uuid::new(),
chunks: vec![5, 8], // 5th & 8th chunk in that partition
};
index.insert(&new_data.0, new_data_location); // Insert a new entry mapping a data Uuid to a location
let uuid_location = index.get(&new_data.0).unwrap(); // Get the location of a Uuid
```
This then allows the index to be searched easily to find the data location of a specific `Uuid`.
Whenever an actor makes a request to save data to it's `Uuid` location, this can be easily found.
It also allows us to tell if an actor *hasn't* been saved yet, allowing us to know whether we need to allocate new space for writing, or if there's actually something to read.
Programs written in userspace will need to follow a specific format.
First, users will write a program in **Rust**, using the **Mercury** libraries, and with `no-std`.
They'll use [Actors](/development/design/actor.md) to communicate with the `kernel`.
Then, they'll compile it for the proper platform and get a pure binary.
This will be ran through an *executable packer* program, and the output of which can be downloaded by the package manager, put on disk, etc.
It'll then parsed in via `bincode`, then the core is ran by the `kernel` in userspace.
Additionally, the raw bytes will be compressed.
Then, whether reading from [chunks](#chunk) from memory or disk, we can know whether it will run on the current system, how long to read for, and when the compressed bytes start (due to the fixed length header).
It is then simple to decompress the raw bytes and run them from the `kernel`.
[^find_chunk]: On startup, the `kernel` builds an index of the filesystem in-memory. This is then modified whenever chunks are modified, and saved on disk on shutdown, and read again on startup.