Memory Layout

Memory in KnightOS is seperated into four sections - kernel code, Flash paging, kernel memory, and userspace memory.

It is laid out as follows:

AddressLengthDescription
0x00000x4000Kernel
0x40000x4000Flash paging
0x80000x100Thread table
0x81000x40Library table
0x81400x40Signal table
0x81800x20File stream table
0x82000x100Kernel state
0x83000x200Kernel garbage
0x85000x7C00Userspace memory

The actual address and length of these portions of memory may change depending on your kernel configuration - the defaults are shown here. Userspace programs should not have to depend on any of this, but should instead use kernel-provided routines for manipulating data here. Any correctly built userspace program should be able to run on any kernel configuration tuned to any particular situation (more threads and less userspace memory, less libraries and more userspace memory, etc).

Kernel state is not entirely used, but is reserved for future use. It currently holds a few dozen kernel state variables and isn’t structured in any special fashion. See kernelmem.inc for details.

Kernel garbage is only used while interrupts are disabled, and no guarantee is made about its contents. It is used, for example, to hold kernel Flash code that must run from RAM. It is also used to keep track of state when performing a garbage collection.

Userspace memory is allocated with malloc and is available for userspace use. Programs run from here and the memory they allocate is assigned here.

Data Structures

Information about kernel memory tables follows.

Thread Table

The thread table contains state information about all currently executing threads. Each entry is 8 bytes long.

OffsetLengthDescription
00001Thread ID
00012Executable address
00032Stack pointer
00051Flags
00062Reserved for future use

Flags is a bitfield:

BitDescription
1May be suspended
2Is suspended
3Color mode

Library Table

The library table stores information about all libraries currently loaded in the system. Each entry is 4 bytes long.

NOTE: This table will likely be revised to track which threads are using which libraries, and for 16 bit library IDs.

OffsetLengthDescription
00001Library ID
00012Library address
00031Number of dependent threads

Signal Table

All pending signals are stored in the signal table. Each entry is 4 bytes long.

OffsetLengthDescription
00001Target thread
00011Message type
00022Payload

File Stream Table

All active file streams are stored in this table.

OffsetLengthDescription
00001Flags/Owner
00012Buffer address
00031Stream pointer
00042Section identifier
00061Length of final block
00071File entry page
00082File entry address
000A3Working file size
000D1Writable stream flags
000E2Reserved for future use

Flags/owner is the following 8 bit format: FTExxxxx, where xxxxx is the thread ID of the owner. F is set if the stream is currently on the final block of the file. T is set if thread is writable. E is set if the stream pointer is past the end of the file.

Writable stream flags are xxxxxxF, where F is if the stream has been flushed to disk.

The buffer address is the location of the buffer in memory (the first byte). This 256-byte buffer contains the contents of the current DAT block. The stream pointer is the offset within this buffer that the stream is currently poitned to. When this offset overflows or underflows, the system copies the next or prior block (respectively) into the buffer. For writable streams, the stream is first flushed.

The section identifer refers to the current DAT block, and is a section identifier as described by the filesystem specification.

The length of the final block is used in read-only streams to determine when the end of the stream has been reached.