commit - 7b1f1314a4618908b79db56b86bae5c9306dc65f
commit + 4d7c062fbfa6373e41c75637079dd1a72c57f150
blob - 328bcaa3fc244f7ebb9b149b20ea0db74ae89291
blob + 47b91394c55e97eb3f122110d63b1915f8c86dcc
--- README
+++ README
runtime. Hence, memory allocation is based on that memory
chunk and not a syscall to request pages from the kernel.
This will force you to tell how much RAM your program
-really needs instead of pretending to be lightweight. Hence,
-when a program does a `malloc` it takes a seat with the
-allocation server which reads the FDM and returns either the
-part needed or and error to say that there is no memory left.
+really needs instead of pretending to be lightweight. The
+memory block is handed at the entry point and the programs,
+thread has to manage it. There is no malloc, there is no
+free, you are on your own.
The layout of the operating system image is :
The Root Task (alpha) goal is to strip away the header and load
executable in memory. Essentialy the root task is the loader.
+Opening a file: A text editor reserves a set amount of memory in
+its contract for viewport. A policy is made so he can request
+a driver to read the part needed from file and another file is
+opened to save history at a maximum amount of bytes.
+
+Tasks spawning other task is not done like unix fork. The way
+a task spawns another is is by cutting a part of its memory and
+requesting the root task to use it to create another one. For
+example, a windom manager could request a memory chunk of 512MB
+and use that 512 MB to spawn other tasks. This way resource
+exhaustion is impossible as the only resources used by the a
+task are his own.
+
+Filesystem: The filesystem is tag based, meaning that there are
+no directories, sub-directories, etc. Files are layout through
+tags and adding a file adds it to the tag. Doing something like
+tags in chell will give you a list. i.e:
+
+> #
+#home
+#games
+#system
+
+Accessing a file is done with for instance home:record.mkv
+
+Files can also have multiple tags. For instance
+
+> ::record.mkv
+
+#home
+#system
+
+Permissions are managed via groups and users just like in Unix.
+That was actually a good design so we keep it. You can do something
+like.
+
+> #home useradd nanga rwx
+> #home groupadd mygroup rwx
+
+When doing this it adds these to all objects with this tag. There
+are no directories, only tags and files.
+
+Basically
+
+#[Tags]:[Group/User]:[File]
+
+The file system server when started is fed by the root task the
+offset before reading the boot drive files.
+
Features:
- Buggy
blob - 2f9e39b4b18e87434300955e12d385bf415864ec
blob + f1b07c8fdf60905a2aaecad352ca1ff7f0c9d782
--- TODO
+++ TODO
-- kalloc and ualloc which checks if memory P_USER is set before
- giving frames.
+- File System (tag based)
-- Add bss to module size for real binary sizes
-
-- Syscalls
-
-- IPC
-
-- File System
-
- a.out executable format
- PIC
- Lua C449 compiler, assembler and linker
- Rewrite in C449
-
-- Create ring buffer to allow asynchronous requests but drop on
- full (no blocking or overwritting)
blob - 6574b6b771e87848e935b310dd24595b5227bcd1
blob + 2de5594659a2333bdff30deac6500e8780a602e7
--- alpha/libc.c
+++ alpha/libc.c
sysc.echo.number = i;
sys_send(&sysc);
}
+
+void
+yield()
+{
+ struct sysc sysc;
+ sysc.type = SYSC_YIELD;
+ sys_send(&sysc);
+}
+
+u8*
+listen(u8 *block)
+{
+ struct sysc sysc;
+ sysc.type = SYSC_LISTEN;
+ sysc.listen.shared_block = block;
+ sys_send(&sysc);
+ return nil;
+}
+
+u8*
+seat(u64 threadid)
+{
+ struct sysc sysc;
+ sysc.type = SYSC_SEAT;
+ sysc.seat.threadid = threadid;
+ sysc.seat.ret_block = nil;
+ sys_send(&sysc);
+ return sysc.seat.ret_block;
+}
blob - e3c44299d8e2701bebb331312b659d8ccf0b5a63
blob + 84979facb56c87769474f78b410905a831d50d5b
--- alpha/libc.h
+++ alpha/libc.h
#include "types.h"
-// Resources given to a thread on initialization
+#define MAX_SHARED_BUFFERS 24
+
+// Resources given to a thread on initialization. Dynamic memory allocation
+// does not exist hence don't expect malloc/calloc/realloc/free/etc. The
+// kernel hands your memory and you're on your own.
struct contract {
u8 *memBlock; // This is guaranteed to be zero'd at entry point
u64 memSize;
- u8 *sharedBlock; // Guaranteed to be zero'd at entry point as well
u64 sharedCount;
+ u8 *sharedBlocks[MAX_SHARED_BUFFERS];
};
// If you come from Unix-like this is kinda
void outputh(u64);
-// Memory allocation
+void yield(void); // Tells the OS to pause the thread until something wakes it up
+
+// Shared Blocks syscalls
+//
+// This sets of functions including yield() allows for communication between threads.
+// doing listen opens a seat for a sender and using yield after tells the kernel to
+// pause the thread and wakes it up if its buffer was written to. This allows for
+// non-blocking and blocking to be implemented without flags.
+
+u8 *seat(u64 thread_id);
+
+void getup(u64 seat_id);
+
+u64 speak(u8 *msg);
+
+u8 *listen(u8 *block); // Tells the OS to open the seat for a sender.
blob - 1a2e9694bafd83253434326ace1ffd76de2b7ae1
blob + d4a5bc809b1263c230055cff194d0832934ecd6b
--- alpha/main.c
+++ alpha/main.c
alpha_main(struct mmap *km)
{
struct task *t;
+ u8 *block = nil;
pci_init();
t = task_new((void *)XHCI_ENTRY);
output("alpha: failed to create task!\n");
output("alpha: running\n");
+ while ((block = seat(t->thread)) == nil);
+ output("alpha: found a seat\n");
+ block[0] = 0x55;
for (;;);
}
sysc.type = SYSC_NEW_THREAD;
sysc.new_thread.entry = entry;
sysc.new_thread.memsize = PAGE_SIZE;
- sysc.new_thread.seats = 0;
+ sysc.new_thread.nseats = 1;
for (int i = 0; i < MAX_TASKS; i++) {
if (tasks[i].assigned == 0) {
blob - 4bbea456c1fc5e1c47816117ea97cf496fac0d68
blob + b1f53ded69a92ac0773586058d6d5b0783e71569
--- c449
+++ c449
properly:
thread 0;
+core 0;
static u8 *name="First";
}
thread 1;
+core 0;
void
main()
blob - 15ee22e44c08b1d58a85ee5ed5ae33d5294522ee
blob + 42b61e061e1a2e50515816aba016e6ecc8b18f25
--- kernel/idt.c
+++ kernel/idt.c
#include "types.h"
#include "kpic.h"
#include "kthreads.h"
+#include "syscalls.h"
#define APIC_EOI_REG ((volatile u32*)0xFEE000B0)
{
struct thread *next;
+ syscall_check_seats();
+
next = thread_next();
if (next != nil) {
blob - 5b711f5a26c269a6ec68fd7615236c460ef62d09
blob + 47337eab319ec3977f8806b72a51a4c7508e41f1
--- kernel/kpic.c
+++ kernel/kpic.c
apic_setup_timer()
{
// Clock divider
- *APIC_TIMER_DIV = 0x03;
+ *APIC_TIMER_DIV = 0x01;
// Setup register
*APIC_TIMER_LVT = APIC_LVT_PERIODIC | TIMER_VECTOR;
blob - f6fa1af4a7b0b7ba0d65afb136dece90e87f1654
blob + b6ffdf4fe737cc85c7e1aa463b2b93a93f7081fd
--- kernel/kthreads.c
+++ kernel/kthreads.c
#include "kmmap.h"
#include "kdebug.h"
#include "kthreads.h"
+#include "syscalls.h"
#include "libc.h"
#define MAX_USER_THREADS 64
{
struct thread *thread = nil;
u64 *sp, usp;
+ u64 tid;
for (int i = 0; i < MAX_USER_THREADS; i++) {
struct thread *th = &uthreads[i];
if (th->assigned == 0) {
th->assigned = 1;
thread = th;
+ tid = i;
break;
}
}
thread->base = allocate_memory(PAGE_SIZE * 2);
thread->con->memBlock = nil;
+ thread->con->sharedCount = 0;
thread->con->memSize = 0;
+ for (int i = 0; i < MAX_SHARED_BUFFERS; i++)
+ thread->con->sharedBlocks[i] = nil;
+
if (thread->base == nil) {
thread->assigned = 0;
return nil;
thread->con->memBlock = (u8 *)allocate_memory(nthread->memsize);
thread->con->memSize = nthread->memsize;
- for (int i = 0; i < thread->con->memSize; i++)
- thread->con->memBlock[i] = 0;
+ // Zero everything
+ if (nthread->memsize > 0) {
+ for (int i = 0; i < thread->con->memSize; i++)
+ thread->con->memBlock[i] = 0;
+ }
+
+ if (nthread->nseats > 0) {
+ for (int i = 0; i < nthread->nseats; i++)
+ seat_new(tid);
+ }
}
sp = (u64 *)((u8*)thread->base + PAGE_SIZE * 2);
blob - 19fbabd1b9e9124fcbbe564306ffed98b5414247
blob + 237e566703ea9144a6cec990175303c4f4c6641f
--- kernel/kthreads.h
+++ kernel/kthreads.h
enum thread_state {
THREAD_READY,
THREAD_RUNNING,
+ THREAD_YIELDING,
};
struct thread {
blob - af6e2abed99462469afc6841fd8300cd54b9c97c
blob + 1aee040fdee868f814c9300a4f6431f44d9c08ad
--- kernel/syscalls.c
+++ kernel/syscalls.c
#include "kthreads.h"
#include "syscalls/syscalls.h"
-#define MAX_SEATS 256
+#define MAX_SEATS 24
#define MAX_SYSC_QUEUE 64
#define THREADID_NONE -1
struct seatmap {
s64 send; // Sender Thread
s64 recv; // Receiver Thread
+ u8 *buff;
+ u8 open;
};
static struct seatmap seatmaps[MAX_SEATS];
s8
seat_new(u64 threadid)
{
+ struct thread *thread = thread_get_uthread(threadid);
+
for (int i = 0; i < MAX_SEATS; i++) {
if (seatmaps[i].recv == THREADID_NONE) {
+ thread->con->sharedBlocks[thread->con->sharedCount++] = seatmaps[i].buff;
seatmaps[i].recv = threadid;
+
+ // Zero'd
+ for (int j = 0; j < PAGE_SIZE; j++)
+ seatmaps[i].buff[j] = 0;
+
+ kprint("Shared block mapped to thread(id="); kprinti(threadid); kprint(")\n");
return 0;
}
}
for (int i = 0; i < MAX_SEATS; i++) {
seatmaps[i].send = THREADID_NONE;
seatmaps[i].recv = THREADID_NONE;
+ seatmaps[i].buff = sbuffers + (i * PAGE_SIZE);
}
// movabs rax, addr
if (th == nil)
kprint("failed to create thread from syscall!\n");
- /*
- if (seat_new(threadid) == -1) {
- kprint("Failed to create new seat\n");
- repeat:
- goto repeat;
- }
- */
-
threadid = thread_getuid(th);
nthread->ret_id = threadid;
th->state = THREAD_RUNNING;
}
void
+sysc_listen_h(struct sysc_listen *listen)
+{
+ for (int i = 0; i < MAX_SEATS; i++) {
+ if (listen->shared_block == seatmaps[i].buff) {
+ seatmaps[i].open = 1;
+ return;
+ }
+ }
+}
+
+void
+sysc_seat_h(struct sysc_seat *sysc_seat)
+{
+ for (int i = 0; i < MAX_SEATS; i++) {
+ if (sysc_seat->threadid == seatmaps[i].recv && seatmaps[i].open == 1) {
+ sysc_seat->ret_block = seatmaps[i].buff;
+ seatmaps[i].send = thread_getuid(cthread);
+ break;
+ }
+ }
+}
+
+void
syscall_handler(struct sysc *call)
{
switch (call->type) {
case SYSC_NEW_THREAD:
syscall_new_thread_h(call);
break;
+ case SYSC_YIELD:
+ cthread->state = THREAD_YIELDING;
+ while (cthread->state != THREAD_RUNNING);
+ break;
+ case SYSC_LISTEN:
+ sysc_listen_h(&call->listen);
+ break;
+ case SYSC_SEAT:
+ sysc_seat_h(&call->seat);
+ break;
default:
break;
}
}
+
+
+void
+syscall_check_seats()
+{
+ for (int i = 0; i < MAX_SEATS; i++) {
+ struct seatmap *map = &seatmaps[i];
+
+ if (map->open == 1 && map->recv != THREADID_NONE && map->send != THREADID_NONE) {
+ struct thread *th = thread_get_uthread(map->recv);
+
+ if (map->buff[0] != 0) th->state = THREAD_RUNNING;
+ }
+ }
+}
blob - 95ffef1019aeafa48a48857106ea098ee698ec70
blob + 79963268d0622d014efb9531ad3f6aaee5af8213
--- kernel/syscalls.h
+++ kernel/syscalls.h
#pragma once
void syscall_init(void);
+s8 seat_new(u64 threadid);
+void syscall_check_seats(void);
blob - 355b272393886987af96ba873b5cab4a4589205e
blob + 9b5e3be626986c9a9b0d22f5a4d9aaeaebfb8046
--- servers/xhci/main.c
+++ servers/xhci/main.c
{
output("xhci: running\n");
- output("xhci: memory size is "); outputi(con->memSize);
- output(" bytes\n");
+ output("xhci: listening\n");
+ listen(con->sharedBlocks[0]);
+ yield();
- output("Memory block location is : "); outputh((u64)con->memBlock[0]); output("\n");
+ output("xhci: listen stop\n");
+ output("xhci: first byte of shared block is "); outputh(con->sharedBlocks[0][0]); output("\n");
for (;;);
}
blob - 4814d52593d770131e8ced32171fbab5cca710de
blob + e8ba6f6be4b57f7df4b5a9b831a5e2d68e19acd0
--- syscalls/syscalls.h
+++ syscalls/syscalls.h
enum sysc_type {
SYSC_ECHO,
+ SYSC_SEAT,
+ SYSC_YIELD,
+ SYSC_LISTEN,
SYSC_NEW_THREAD,
SYSC_FREE_THREAD,
};
struct sysc_new_thread {
void *entry; // Entry point
u64 memsize;
- u64 seats;
+ u64 nseats;
s64 ret_id;
};
+struct sysc_listen {
+ u8 *shared_block;
+};
+
+struct sysc_seat {
+ u64 threadid;
+
+ u8 *ret_block;
+};
+
struct sysc {
enum sysc_type type;
union {
struct sysc_echo echo;
struct sysc_new_thread new_thread;
+ struct sysc_listen listen;
+ struct sysc_seat seat;
};
};