Close

Access rights and capabilities

A project log for F-CPU

The Freedom CPU project has a log here too now :-)

yann-guidon-ygdesYann Guidon / YGDES 04/02/2024 at 02:430 Comments

As mentioned before, FC1 is built around a microkernel-like/actor organisation where there is no kernel, driver or user program, only modules.

So how does a module do its job ? Easy answer : its code must have certain rights.

And should the rights be tied to a module or a thread ? Both, in a way.

A "naked" thread (for example your basic "hello world" program) can still perform many functions by having no right by itself, but it calls modules that are endowed with specific rights and vetted by the OS. In the example, the naked thread calls a print function located in a different module, which can access the input/output operation itself, without leaking the "right" back to the caller. It's a sort of delegation.

A debugging program needs extra access rights, which should be preserved through calls to different modules.

But then the processor needs a way to vet each operation, either a specific opcode or access to a specific configuration register.

The processor knows the TID and MID (Thread IDentification number and Module IDentification number) which provide an index into an access right table, which is read again after each thread swap and/or IPC/IPR instruction. This is quite heavy and best done in software, for obvious speed and scalability reasons.

More pragmatically there are two simpler methods:

  1. The thread has a hidden "capabilities" word with a limited number of "rights" that are set by the OS during initialisation and ORed with the capabilities word of the module being executed. This limit in size permits only general/generic rights to be set, such as access to the stack, access to the code space...
  2. More specific rights are handled at the Special Register level, and tied to either a given module or thread : a single bit (MSB) selects whether the field is a TID or MID. This is preferred for scalability (there can be any number of these access right registers) and this tightens the security model, where usually only one thread or module has access to a given resource, limiting the chances of race conditions and abuse.

One exception : Thread #0 has all the rights since it initialises the system and manages all the other modules. It can then choose to endow a given thread with the required rights after some software filtering.

This dual system is flexible, scalable, and granularity can be adjusted.

Both of these methods are easily implemented in HW without microcode or sophisticated circuits. In other words it's "RISC-friendly".

Discussions