feat: expand user mode, add DOOM game, add manpages
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
.TH FILE 2
|
||||
.SH NAME
|
||||
open, read, getsize, close, readdir - file I/O system calls
|
||||
|
||||
.SH SYNOPSIS
|
||||
.BI int zenith::open(const char* path);
|
||||
.BI int zenith::read(int handle, uint8_t* buf, uint64_t offset, uint64_t size);
|
||||
.BI uint64_t zenith::getsize(int handle);
|
||||
.BI void zenith::close(int handle);
|
||||
.BI int zenith::readdir(const char* path, const char** names, int max);
|
||||
|
||||
.SH DESCRIPTION
|
||||
ZenithOS provides a simple read-only Virtual File System (VFS)
|
||||
backed by the boot ramdisk. Files are accessed via paths in the
|
||||
format "<drive>:/<name>", where drive 0 is the ramdisk.
|
||||
|
||||
.SS open
|
||||
Opens a file and returns a non-negative handle on success, or a
|
||||
negative value on error (file not found, no free handles).
|
||||
|
||||
int h = zenith::open("0:/shell.elf");
|
||||
|
||||
.SS read
|
||||
Reads up to 'size' bytes starting at 'offset' into 'buf'.
|
||||
Returns the number of bytes actually read, or negative on error.
|
||||
There is no implicit file position -- the offset is explicit on
|
||||
every call.
|
||||
|
||||
uint8_t buf[512];
|
||||
int n = zenith::read(h, buf, 0, 512);
|
||||
|
||||
.SS getsize
|
||||
Returns the total size in bytes of the file.
|
||||
|
||||
uint64_t sz = zenith::getsize(h);
|
||||
|
||||
.SS close
|
||||
Closes the file handle and frees kernel resources.
|
||||
|
||||
zenith::close(h);
|
||||
|
||||
.SS readdir
|
||||
Lists entries in a directory. Up to 'max' entry names (max 64)
|
||||
are written to the 'names' array. The kernel allocates a user-
|
||||
accessible page for the string data automatically.
|
||||
|
||||
const char* entries[64];
|
||||
int count = zenith::readdir("0:/", entries, 64);
|
||||
|
||||
.SH READING PATTERN
|
||||
The standard pattern for reading a file:
|
||||
|
||||
int h = zenith::open("0:/myfile.txt");
|
||||
uint64_t size = zenith::getsize(h);
|
||||
uint8_t buf[512];
|
||||
uint64_t off = 0;
|
||||
while (off < size) {
|
||||
uint64_t chunk = size - off;
|
||||
if (chunk > 511) chunk = 511;
|
||||
int n = zenith::read(h, buf, off, chunk);
|
||||
if (n <= 0) break;
|
||||
buf[n] = '\0';
|
||||
zenith::print((const char*)buf);
|
||||
off += n;
|
||||
}
|
||||
zenith::close(h);
|
||||
|
||||
.SH NOTES
|
||||
The filesystem is read-only. There are no write or create calls.
|
||||
All files live on the ramdisk which is loaded at boot from a
|
||||
USTAR tar archive.
|
||||
|
||||
.SH SEE ALSO
|
||||
syscalls(2), spawn(2), malloc(3)
|
||||
@@ -0,0 +1,62 @@
|
||||
.TH FRAMEBUFFER 2
|
||||
.SH NAME
|
||||
fb_info, fb_map - direct framebuffer access
|
||||
|
||||
.SH SYNOPSIS
|
||||
.BI void zenith::fb_info(Zenith::FbInfo* info);
|
||||
.BI void* zenith::fb_map();
|
||||
|
||||
.SH DESCRIPTION
|
||||
These syscalls allow userspace programs to access the linear
|
||||
framebuffer directly for graphical output.
|
||||
|
||||
.SS fb_info
|
||||
Fills in an FbInfo structure with the framebuffer geometry:
|
||||
|
||||
Zenith::FbInfo fb;
|
||||
zenith::fb_info(&fb);
|
||||
// fb.width, fb.height, fb.pitch, fb.bpp
|
||||
|
||||
The pitch is the number of bytes per scanline (may be larger
|
||||
than width * 4 due to alignment). bpp is always 32.
|
||||
|
||||
.SS fb_map
|
||||
Maps the physical framebuffer into the process address space at
|
||||
a fixed virtual address (0x50000000) and returns that address.
|
||||
|
||||
uint32_t* pixels = (uint32_t*)zenith::fb_map();
|
||||
|
||||
Each pixel is a 32-bit value in 0xAARRGGBB format (blue in the
|
||||
low byte). Writing to this memory directly updates the screen.
|
||||
|
||||
.SH PIXEL FORMAT
|
||||
Bits 31-24: Alpha (unused, typically 0xFF)
|
||||
Bits 23-16: Red
|
||||
Bits 15-8: Green
|
||||
Bits 7-0: Blue
|
||||
|
||||
Example: red = 0x00FF0000, green = 0x0000FF00, blue = 0x000000FF
|
||||
|
||||
.SH EXAMPLE
|
||||
Fill the screen with blue:
|
||||
|
||||
Zenith::FbInfo fb;
|
||||
zenith::fb_info(&fb);
|
||||
uint32_t* pixels = (uint32_t*)zenith::fb_map();
|
||||
|
||||
for (uint64_t y = 0; y < fb.height; y++) {
|
||||
uint32_t* row = (uint32_t*)((uint8_t*)pixels + y * fb.pitch);
|
||||
for (uint64_t x = 0; x < fb.width; x++) {
|
||||
row[x] = 0x000000FF;
|
||||
}
|
||||
}
|
||||
|
||||
.SH NOTES
|
||||
After mapping, the cursor overlay is not composited. Programs
|
||||
that use the framebuffer take full control of screen output.
|
||||
|
||||
Only one mapping per process is supported. Calling fb_map()
|
||||
multiple times returns the same address.
|
||||
|
||||
.SH SEE ALSO
|
||||
syscalls(2), malloc(3)
|
||||
@@ -0,0 +1,49 @@
|
||||
.TH INTRO 1
|
||||
.SH NAME
|
||||
intro - introduction to ZenithOS userspace
|
||||
|
||||
.SH DESCRIPTION
|
||||
ZenithOS is a hobbyist 64-bit operating system written in C++20.
|
||||
Userspace programs run in Ring 3, are loaded as static ELF64
|
||||
binaries, and communicate with the kernel through the x86-64
|
||||
SYSCALL/SYSRET mechanism.
|
||||
|
||||
Programs are compiled with a freestanding cross-compiler and
|
||||
linked at virtual address 0x400000. There is no standard C
|
||||
library for C++ programs -- all system interaction goes through
|
||||
the zenith:: syscall wrappers.
|
||||
|
||||
.SH GETTING STARTED
|
||||
To write a new program, create a directory under programs/src/
|
||||
with a main.cpp file. The entry point is:
|
||||
|
||||
extern "C" void _start() { ... }
|
||||
|
||||
There is no argc/argv. Include <zenith/syscall.h> for the full
|
||||
typed syscall API. Include <zenith/heap.h> for malloc/mfree.
|
||||
|
||||
Build with:
|
||||
|
||||
cd programs && make
|
||||
|
||||
The resulting ELF binary appears in programs/bin/.
|
||||
|
||||
.SH SHELL
|
||||
The built-in shell is the primary way to interact with ZenithOS.
|
||||
Type 'help' at the shell prompt for a list of commands. Use
|
||||
'man shell' for detailed shell documentation.
|
||||
|
||||
.SH MAN PAGES
|
||||
The following man pages are available:
|
||||
|
||||
intro(1) This page
|
||||
shell(1) Shell commands reference
|
||||
man(1) The man command itself
|
||||
syscalls(2) Overview of all syscalls
|
||||
spawn(2) Process spawning
|
||||
file(2) File I/O syscalls
|
||||
framebuffer(2) Framebuffer access
|
||||
malloc(3) Memory allocation
|
||||
|
||||
.SH SEE ALSO
|
||||
shell(1), syscalls(2), malloc(3)
|
||||
@@ -0,0 +1,57 @@
|
||||
.TH MALLOC 3
|
||||
.SH NAME
|
||||
malloc, mfree, realloc - userspace heap allocation
|
||||
|
||||
.SH SYNOPSIS
|
||||
.BI void* zenith::malloc(uint64_t size);
|
||||
.BI void zenith::mfree(void* ptr);
|
||||
.BI void* zenith::realloc(void* ptr, uint64_t size);
|
||||
|
||||
.SH DESCRIPTION
|
||||
The userspace heap provides dynamic memory allocation on top of
|
||||
the kernel's page-mapping syscall (SYS_ALLOC). Include the
|
||||
header <zenith/heap.h> to use these functions.
|
||||
|
||||
.SS malloc
|
||||
Allocates 'size' bytes from the free list. Returns a 16-byte
|
||||
aligned pointer, or nullptr on failure. When the free list is
|
||||
empty, it requests more pages from the kernel via SYS_ALLOC
|
||||
(minimum 16 KiB growth, initial seed of 64 KiB).
|
||||
|
||||
char* buf = (char*)zenith::malloc(1024);
|
||||
|
||||
.SS mfree
|
||||
Returns the block to the userspace free list. No syscall is
|
||||
made -- the memory stays mapped and is immediately reusable.
|
||||
Passing nullptr is a safe no-op.
|
||||
|
||||
zenith::mfree(buf);
|
||||
|
||||
.SS realloc
|
||||
Resizes the allocation to 'size' bytes. Allocates a new block,
|
||||
copies the smaller of old/new sizes, and frees the old block.
|
||||
If ptr is nullptr, behaves like malloc.
|
||||
|
||||
buf = (char*)zenith::realloc(buf, 2048);
|
||||
|
||||
.SH IMPLEMENTATION
|
||||
The allocator uses a linked free-list with first-fit search.
|
||||
Blocks larger than needed are split. The allocation header is
|
||||
16 bytes (magic + size). All allocations are 16-byte aligned.
|
||||
|
||||
The heap grows by requesting pages from the kernel via
|
||||
SYS_ALLOC. These pages are never returned to the kernel (since
|
||||
SYS_FREE is currently a no-op), but mfree makes them available
|
||||
for future malloc calls within the process.
|
||||
|
||||
.SH LOW-LEVEL PAGE API
|
||||
For large allocations or when direct page control is needed:
|
||||
|
||||
void* zenith::alloc(uint64_t size); // SYS_ALLOC
|
||||
void zenith::free(void* ptr); // SYS_FREE (no-op)
|
||||
|
||||
alloc() maps zeroed pages starting at 0x40000000 and growing
|
||||
upward. Size is rounded up to 4 KiB page boundaries.
|
||||
|
||||
.SH SEE ALSO
|
||||
syscalls(2), file(2)
|
||||
@@ -0,0 +1,47 @@
|
||||
.TH MAN 1
|
||||
.SH NAME
|
||||
man - display manual pages
|
||||
|
||||
.SH SYNOPSIS
|
||||
.BI man topic
|
||||
.BI man section topic
|
||||
|
||||
.SH DESCRIPTION
|
||||
The man command displays manual pages from the ramdisk in a
|
||||
fullscreen pager. Pages are stored as plain text files with
|
||||
simple formatting directives.
|
||||
|
||||
If no section is specified, sections 1, 2, and 3 are searched
|
||||
in order. If a section number is given, only that section is
|
||||
checked.
|
||||
|
||||
.SH KEY BINDINGS
|
||||
|
||||
.B Navigation
|
||||
j, Down Arrow Scroll down one line
|
||||
k, Up Arrow Scroll up one line
|
||||
Space, Page Down Scroll down one page
|
||||
b, Page Up Scroll up one page
|
||||
g, Home Go to top
|
||||
G, End Go to bottom
|
||||
q Quit
|
||||
|
||||
.SH SECTIONS
|
||||
1 User commands (shell built-ins)
|
||||
2 System calls (kernel interface)
|
||||
3 Library functions (userspace libraries)
|
||||
|
||||
.SH FILES
|
||||
Man pages are stored on the ramdisk at:
|
||||
|
||||
0:/man/<topic>.<section>
|
||||
|
||||
For example, man intro reads 0:/man/intro.1
|
||||
|
||||
.SH EXAMPLES
|
||||
man intro View the introduction
|
||||
man 2 syscalls View syscall overview (section 2)
|
||||
man malloc View malloc documentation
|
||||
|
||||
.SH SEE ALSO
|
||||
intro(1), shell(1), syscalls(2)
|
||||
@@ -0,0 +1,54 @@
|
||||
.TH SHELL 1
|
||||
.SH NAME
|
||||
shell - ZenithOS interactive command shell
|
||||
|
||||
.SH DESCRIPTION
|
||||
The ZenithOS shell is a simple command interpreter that runs as
|
||||
the first userspace process. It provides basic file inspection,
|
||||
process management, networking, and documentation access.
|
||||
|
||||
.SH COMMANDS
|
||||
|
||||
.SS help
|
||||
Display a list of available commands.
|
||||
|
||||
.SS info
|
||||
Show the OS name, version, and syscall API version number.
|
||||
|
||||
.SS man <topic>
|
||||
Open a manual page in the fullscreen pager. See man(1).
|
||||
|
||||
.SS ls
|
||||
List all files on the ramdisk (drive 0:/).
|
||||
|
||||
.SS cat <file>
|
||||
Print the contents of a ramdisk file to the terminal.
|
||||
Example: cat hello.elf
|
||||
|
||||
.SS run <file>
|
||||
Spawn a new process from an ELF binary on the ramdisk and wait
|
||||
for it to exit. The shell blocks until the child process
|
||||
terminates.
|
||||
Example: run hello.elf
|
||||
|
||||
.SS ping <ip>
|
||||
Send 4 ICMP echo requests to the given IP address and display
|
||||
round-trip times. Timeout is 3 seconds per request.
|
||||
Example: ping 10.0.2.2
|
||||
|
||||
.SS uptime
|
||||
Display the system uptime in minutes, seconds, and milliseconds.
|
||||
|
||||
.SS clear
|
||||
Clear the terminal screen.
|
||||
|
||||
.SS exit
|
||||
Terminate the shell process.
|
||||
|
||||
.SH INPUT
|
||||
The shell reads input character by character using SYS_GETCHAR.
|
||||
Backspace is supported. Lines are limited to 255 characters.
|
||||
There is no command history or tab completion.
|
||||
|
||||
.SH SEE ALSO
|
||||
man(1), intro(1), syscalls(2)
|
||||
@@ -0,0 +1,69 @@
|
||||
.TH SPAWN 2
|
||||
.SH NAME
|
||||
spawn, waitpid - create and wait for processes
|
||||
|
||||
.SH SYNOPSIS
|
||||
.BI int zenith::spawn(const char* path, const char* args = nullptr);
|
||||
.BI void zenith::waitpid(int pid);
|
||||
.BI int zenith::getargs(char* buf, uint64_t maxLen);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
.SS spawn
|
||||
Loads the ELF64 binary at the given VFS path and creates a new
|
||||
process. The path must include the drive prefix, for example:
|
||||
|
||||
int pid = zenith::spawn("0:/hello.elf");
|
||||
|
||||
An optional second argument passes a string to the child:
|
||||
|
||||
int pid = zenith::spawn("0:/man.elf", "intro");
|
||||
|
||||
The new process gets its own PML4 page table, a 16 KiB stack
|
||||
(at 0x7FFFFEF000-0x7FFFFFF000), and begins executing at the
|
||||
ELF entry point (_start).
|
||||
|
||||
Returns the new process's PID on success, or -1 on failure.
|
||||
Failure occurs when there are no free process slots (max 16),
|
||||
the file cannot be found, or the ELF is invalid.
|
||||
|
||||
.SS waitpid
|
||||
Blocks the calling process until the process with the given PID
|
||||
has exited. Internally, this yields the CPU in a loop:
|
||||
|
||||
zenith::waitpid(pid);
|
||||
|
||||
This is how the shell implements foreground process execution --
|
||||
it spawns a child and waits for it to complete before showing
|
||||
the next prompt.
|
||||
|
||||
.SH EXAMPLES
|
||||
Spawn a program and wait for it:
|
||||
|
||||
int pid = zenith::spawn("0:/hello.elf");
|
||||
if (pid < 0) {
|
||||
zenith::print("spawn failed\n");
|
||||
} else {
|
||||
zenith::waitpid(pid);
|
||||
zenith::print("child exited\n");
|
||||
}
|
||||
|
||||
.SS getargs
|
||||
Copies the argument string into buf (up to maxLen bytes, always
|
||||
null-terminated). Returns the number of characters copied, or
|
||||
-1 on error.
|
||||
|
||||
char args[256];
|
||||
zenith::getargs(args, sizeof(args));
|
||||
|
||||
The argument string is set by the parent when calling spawn().
|
||||
If no arguments were provided, the buffer will be empty.
|
||||
|
||||
.SH NOTES
|
||||
The _start() entry point receives no argc/argv. Use getargs()
|
||||
to retrieve the argument string passed by the parent process.
|
||||
|
||||
Process exit codes are not yet collected by waitpid.
|
||||
|
||||
.SH SEE ALSO
|
||||
syscalls(2), file(2)
|
||||
@@ -0,0 +1,137 @@
|
||||
.TH SYSCALLS 2
|
||||
.SH NAME
|
||||
syscalls - overview of ZenithOS system calls
|
||||
|
||||
.SH DESCRIPTION
|
||||
ZenithOS provides 26 system calls (numbers 0-25) for userspace
|
||||
programs. Syscalls use the x86-64 SYSCALL instruction with the
|
||||
following register convention:
|
||||
|
||||
RAX Syscall number (in) / return value (out)
|
||||
RDI Argument 1
|
||||
RSI Argument 2
|
||||
RDX Argument 3
|
||||
R10 Argument 4
|
||||
R8 Argument 5
|
||||
R9 Argument 6
|
||||
|
||||
Include <zenith/syscall.h> for typed wrappers in the zenith::
|
||||
namespace.
|
||||
|
||||
.SH PROCESS MANAGEMENT
|
||||
.B SYS_EXIT (0)
|
||||
Terminate the calling process.
|
||||
void zenith::exit(int code = 0);
|
||||
|
||||
.B SYS_YIELD (1)
|
||||
Yield the remainder of the time slice.
|
||||
void zenith::yield();
|
||||
|
||||
.B SYS_SLEEP_MS (2)
|
||||
Sleep for at least the given number of milliseconds.
|
||||
void zenith::sleep_ms(uint64_t ms);
|
||||
|
||||
.B SYS_GETPID (3)
|
||||
Return the PID of the calling process.
|
||||
int zenith::getpid();
|
||||
|
||||
.B SYS_SPAWN (20)
|
||||
Spawn a new process from an ELF binary on the VFS.
|
||||
int zenith::spawn(const char* path, const char* args = nullptr);
|
||||
|
||||
.B SYS_WAITPID (23)
|
||||
Block until the given process has exited.
|
||||
void zenith::waitpid(int pid);
|
||||
|
||||
.SH CONSOLE I/O
|
||||
.B SYS_PRINT (4)
|
||||
Write a null-terminated string to the terminal.
|
||||
void zenith::print(const char* text);
|
||||
|
||||
.B SYS_PUTCHAR (5)
|
||||
Write a single character to the terminal.
|
||||
void zenith::putchar(char c);
|
||||
|
||||
.SH FILE I/O
|
||||
.B SYS_OPEN (6)
|
||||
Open a file. Returns a handle or negative on error.
|
||||
int zenith::open(const char* path);
|
||||
|
||||
.B SYS_READ (7)
|
||||
Read bytes from a file at a given offset.
|
||||
int zenith::read(int h, uint8_t* buf, uint64_t off, uint64_t sz);
|
||||
|
||||
.B SYS_GETSIZE (8)
|
||||
Get the size of an open file in bytes.
|
||||
uint64_t zenith::getsize(int handle);
|
||||
|
||||
.B SYS_CLOSE (9)
|
||||
Close a file handle.
|
||||
void zenith::close(int handle);
|
||||
|
||||
.B SYS_READDIR (10)
|
||||
List directory entries (max 64 per call).
|
||||
int zenith::readdir(const char* path, const char** names, int max);
|
||||
|
||||
.SH MEMORY
|
||||
.B SYS_ALLOC (11)
|
||||
Map zeroed pages into the process address space.
|
||||
void* zenith::alloc(uint64_t size);
|
||||
|
||||
.B SYS_FREE (12)
|
||||
Reserved (currently a no-op).
|
||||
void zenith::free(void* ptr);
|
||||
|
||||
.SH TIMEKEEPING
|
||||
.B SYS_GETTICKS (13)
|
||||
Get APIC timer ticks since boot.
|
||||
uint64_t zenith::get_ticks();
|
||||
|
||||
.B SYS_GETMILLISECONDS (14)
|
||||
Get milliseconds elapsed since boot.
|
||||
uint64_t zenith::get_milliseconds();
|
||||
|
||||
.SH SYSTEM
|
||||
.B SYS_GETINFO (15)
|
||||
Get OS name, version, and configuration.
|
||||
void zenith::get_info(Zenith::SysInfo* info);
|
||||
|
||||
.SH KEYBOARD
|
||||
.B SYS_ISKEYAVAILABLE (16)
|
||||
Check if a key event is pending (non-blocking).
|
||||
bool zenith::is_key_available();
|
||||
|
||||
.B SYS_GETKEY (17)
|
||||
Get the next key event (press or release).
|
||||
void zenith::getkey(Zenith::KeyEvent* out);
|
||||
|
||||
.B SYS_GETCHAR (18)
|
||||
Block until a printable character is typed.
|
||||
char zenith::getchar();
|
||||
|
||||
.SH NETWORKING
|
||||
.B SYS_PING (19)
|
||||
Send an ICMP echo request and wait for reply.
|
||||
int32_t zenith::ping(uint32_t ip, uint32_t timeoutMs);
|
||||
|
||||
.SH FRAMEBUFFER
|
||||
.B SYS_FBINFO (21)
|
||||
Get framebuffer dimensions and format.
|
||||
void zenith::fb_info(Zenith::FbInfo* info);
|
||||
|
||||
.B SYS_FBMAP (22)
|
||||
Map the framebuffer into process memory at 0x50000000.
|
||||
void* zenith::fb_map();
|
||||
|
||||
.SH TERMINAL
|
||||
.B SYS_TERMSIZE (24)
|
||||
Get terminal dimensions (columns and rows).
|
||||
void zenith::termsize(int* cols, int* rows);
|
||||
|
||||
.SH ARGUMENTS
|
||||
.B SYS_GETARGS (25)
|
||||
Get the argument string passed to this process at spawn time.
|
||||
int zenith::getargs(char* buf, uint64_t maxLen);
|
||||
|
||||
.SH SEE ALSO
|
||||
spawn(2), file(2), framebuffer(2), malloc(3)
|
||||
Reference in New Issue
Block a user