#OBOS (not vibecoded)

1 messages · Page 21 of 1

real pecan
#

They just spin?

flint idol
#

nope

#

they exit their thread

#

then each driver has a function table

#

kinda like a vtable

#

that the kernel calls to request something from the driver

real pecan
#

Yeah but like

#

Cant u make this struct like an out parameter of the driver entrypoint

#

And have the trampoline call this exit thing

flint idol
#

drivers just store it in their header

#

because it's simple for one

#

and also drivers can request to not have an entry point

real pecan
#

I mean the status struct

flint idol
#

oh the status struct

#

no that'd break compatibility with the test driver I use for fireworks

#

because that's on master, but these changes are going in userspace-work

real pecan
#

Cant u just uhhh... Change it?

flint idol
#

I mean

#

the test driver's fireworks test is only on master

#

as of now

#

these changes are not on master

real pecan
#

F

flint idol
#

and are instead on userspace-work

real pecan
#

Your wip branch is behind master somehow?

flint idol
#

yes

real pecan
#

💀

#

Wtf

flint idol
#

I should maybe bump it sometime soon

#

I fear merge conflicts though

#

because like

real pecan
#

git rebase master

flint idol
#

this

real pecan
#

How does that even happen is beyond me

flint idol
#

2k additions

#

2k deletions

#

this is a lot better than panicking on driver failure KEKW

#

which I unknowingly did

#

or rather I forgot that I did

flint idol
#

yeah something fnuy is goin on with my ahci driver

#

lmao

#

I forgot to remove a forever loop

#

when testing timeouts

#

the exit driver function works

#

it's quite simple

#

simply prints the info if there is an error status

#

it exits the thread if the fatal == false or if status==SUCCESS

#

otherwise

#

it initializes a DPC to unload the driver

#

and exits the thread

#
void Drv_ExitDriver(struct driver_id* id, const driver_init_status* status)
{
    if (!id || !status)
        return;
    if (id->main_thread != Core_GetCurrentThread())
        return;
    irql oldIrql = Core_RaiseIrql(IRQL_DISPATCH);
    if (obos_is_error(status->status))
    {
        if (OBOS_GetLogLevel() <= LOG_LEVEL_WARNING)
        {
            OBOS_Warning("Initialization of driver %d (%s) failed with status %d.\n", 
                id->id, 
                uacpi_strnlen(id->header.driverName, 64) ? id->header.driverName : "Unknown",
                status->status
            );
            if (status->context)
                printf("Note: %s\n", status->context);
            if (status->fatal)
                printf("Note: Fatal error. Unloading the driver.\n");
        }
    }
    if (!status->fatal || obos_is_success(status->status))
        Core_ExitCurrentThread();
    dpc* dpc = CoreH_AllocateDPC(nullptr);
    OBOS_ASSERT(dpc);
    dpc->userdata = id;
    CoreH_InitializeDPC(dpc, unload_driver_dpc, CoreH_CPUIdToAffinity(CoreS_GetCPULocalPtr()->id) /* make sure this runs on this CPU. */);
    Core_ExitCurrentThread();
    OBOS_UNREACHABLE;
    OBOS_UNUSED(oldIrql);
}```
#

only a wall of text

#

if anyone's wondering why I only allow the dpc to run on the current CPU it's because there can be a race condition where the dpc runs before the thread is exitted

#

causing unload to fail saying the main thread didn't exit

#

and I raise the irql to make sure I run the dpc on a separate thread stack

flint idol
#

ok time to get back

#

to torture

#

mirror mirror on the wall

#

who has the buggiest code of them all

#

♫ 99 little bugs in the code ♫
♫ 99 little bugs ♫
♫ take one down, patch it around ♫
♫ 137 little bugs in the code ♫

#

klange, 2024

#

excuse me why the fuck does the ahci driver map ~4M of memory

#

hmm what could this bug be

#

region corruption

#

where could that happen

#
if (block->prev)
    block->prev->next = block->next;
if (block->next)
    block->next->prev = block->prev;
if (This->regionHead == block)
    This->regionHead = block->next;
if (This->regionTail == block)
    This->regionTail = block->prev;
#

there's no way this list remove code is wrong, right?

vale nymph
flint idol
#

I don't think it's a problem

#

it acquires a spinlock in the allocator, but that's about it

#

@devout niche is it ok to call into the allocator at IRQL_DISPATCH?

#

fadanoid the wise

flint idol
#

all I can think of is

#

mismatched allocators

#

but that'd have panicked

#

because kasan violation

devout niche
#

if the call would have to wait for memory to become available no

#

if it acquires a sleeping mutex, no

flint idol
#

I see

#

thanks

#

I feel like this is an off-by-one in the vmm free function

#

like it was last time

#

I have written allocator test

#
allocator_info* alloc = OBOS_KernelAllocator;
void* to_free = nullptr;
while (true)
{
    size_t sz = random_number() % 4096 + 256;
    char* ret = alloc->ZeroAllocate(alloc, sz, 1, nullptr);
    ret[0] = random_number8();
    ret[sz-1] = random_number8();
    if (random_number() % 2)
    {
        alloc->Free(alloc, to_free, 0);
        to_free = ret;
    }
}```
#

I made that multithreaded

#

and it caught a bug

#

seemingly

#

well when I make it so freeRegion does nothing

#

it "works"

#

other than the fact that no memory is getting freed

#

which sounds like a bug with munmap

#

perhaps it accidentally frees past the region bounds

#

you know that's it

#

I'm going full verbose log mode

#

it seems to be freeing 0x5000 bytes at the faulting address

#

before it faults

#
derefing physical page 000000003cca0000 representing ffffff0000ed7000
unmapping ffffff0000ed7000
derefing physical page 000000003cbb9000 representing ffffff0000ed8000
unmapping ffffff0000ed8000
derefing physical page 000000003cc2e000 representing ffffff0000ed9000
unmapping ffffff0000ed9000
derefing physical page 000000003cc8e000 representing ffffff0000eda000
unmapping ffffff0000eda000
derefing physical page 000000003cc9f000 representing ffffff0000edb000
unmapping ffffff0000edb000```
#
Page fault at 0xffffffff8001aaa3 in kernel-mode while to write page at 0xffffff0000ed7090, which is unpresent. Error code: 2
#

and it seems to be a different size each size

#

now it's 0x10000 bytes

#

tf

#

it freed that in vma stack free

#

and sometimes its freed in freeRegion

#
if (block->prev)
        OBOS_ASSERT(block->prev->next != block);
    if (block->next)
        OBOS_ASSERT(block->next->prev != block);
    OBOS_ASSERT(This->regionHead != block);
    OBOS_ASSERT(This->regionTail != block);```
#

I added these assertions

#

tf

#
blk->prev ffff80003ccdd000
blk->next 0000000000000000
linked ffffff0000ed7000```
#

0xffff80003ccdd000 is an address in the vmm allocator

#

yet this crash happens in the non paged pool allocator

#

and that block was allocated in the non paged-pool allocator

#

sometimes it's not

#

printf my beloved

#

HOLD ON

#

printf > gdb

#
freeing 20480 at ffffff0000913000. called from ffffffff8001c0f7```
#

then later in my log file

#
blk->prev ffffff0000913000
blk->next 0000000000000000
linked ffffff000050a000```
#

without allocation of that address in between

flint idol
#

aaand it's an allocator mismatch

#
mapped 65536 bytes at ffffff0000ec8000
mapped 65536 bytes at ffffff0000ed8000
mapped 20480 bytes at ffffff0000ee8000
linked ffffff0000ee8000
blk->prev ffffff0000d6e000
blk->next 0000000000000000
This ffffffff800dc840```
#
alloc: freeing blk ffffff0000ee8000
This: ffffffff805032e0
blk->This ffffffff800dc840```
#

I have no idea why this isn't failing

if ((allocator_info*)r->This != This_)
    OBOS_ASANReport((uintptr_t)__builtin_return_address(0), (uintptr_t)base, nBytes, ASAN_AllocatorMismatch, false);```
#

FUCK

#

I forgot to handle allocator mismatch

#

in asan_report

flint idol
#

rather my vmm committed memory counter is broken

#

or something is terribly wrong

#

since there is ~20M of committed memory

#

yet the allocators report a lot less in use

#

only 5M + 82K

flint idol
#

well ~8M is the framebuffer+backbuffer

#

and for some reason

#

the fat driver is using 3M

#

I wonder if I can optimize the fat driver

#

to directly use the page cache

#

instead of using the VFS to read/write from a volume

#

iirc microsoft's fat driver does something like that?

#

idk if it does

flint idol
#

I just pushed the code

flint idol
flint idol
#
FATAllocator = OBOS_KernelAllocator;
#

my FAT manipulation code now uses the page cache

#

directly

#

the goal is to make anything that uses Vfs_FdRead in the FAT driver use the pagecache manipulation functions instead

#
for (size_t i = 0; i < szClusters; i++)
{
    Vfs_FdSeek(cache->volume, ClusterToSector(cache, cluster+i)*cache->blkSize, SEEK_SET);
    Vfs_FdRead(cache->volume, buf, bytesPerCluster, nullptr);
    Vfs_FdSeek(cache->volume, ClusterToSector(cache, newCluster+i)*cache->blkSize, SEEK_SET);
    Vfs_FdWrite(cache->volume, buf, bytesPerCluster, nullptr);
}
if (cluster)
    FreeClusters(cache, cluster, szClusters);```
#

I wish I had commented this code

#

I think it is supposed to be copying sectors?

#

it is

#

and in looking at that code I remembered that I need to mark the pc regions dirty

flint idol
#

I hate my fat driver

#

the code is so dirty

#

and unpleasant

#

but it kinda works

#

which is good enough

#
if (inRoot && cache->fatType != FAT32_VOLUME)
{
    Vfs_FdSeek(cache->volume, fileoff, SEEK_SET);
    Vfs_FdWrite(cache->volume, buf, blkSize, nullptr);
}
else
{
    Vfs_FdSeek(cache->volume, fileoff, SEEK_SET);
    Vfs_FdWrite(cache->volume, buf, blkSize, nullptr);
}```
#

what is teh point of this if statement

#

lol

#
while (!wroteback)
{
    if (inRoot && cache->fatType != FAT32_VOLUME)
    {
        Vfs_FdSeek(cache->volume, fileoff, SEEK_SET);
        Vfs_FdWrite(cache->volume, buf, blkSize, nullptr);
    }
    else
    {
        Vfs_FdSeek(cache->volume, fileoff, SEEK_SET);
        Vfs_FdWrite(cache->volume, buf, blkSize, nullptr);
    }
    wroteback = true;
}```
#

tf is the point of the loop

#

something tells me I was really tired writing that code..

#

suspiciously the fat driver still works

#

when I changed it to use pagecache

flint idol
#

wow my ahci driver does not know how to scatter gather properly does it...

#
ahci_dma_prepare_buf ahci(0x5567b57622b0)[1]: prepare buf limit=16384 prepared=12288
inland radish
#

this is incredibly irresponsible tbh

flint idol
#

I removed that code

inland radish
#

if the driver hangs it's a problem in the driver

flint idol
#

I think I'm rewriting my scatter gather algorithm

#

to not be shit

inland radish
#

the only use i know of so far for scatter gathering is for readv/writev support

flint idol
#

AHCI uses it

#

it's called the PRDT iirc

inland radish
#

perhaps i should add support for it in my NVME driver

#

for now I only support the PRP method

flint idol
#

I assume it you just give it a physical address and size

#

and it DMAs from there

inland radish
#

You give it several physical page addresses

#

Not just one

#

The first physical page in the PRP list may have an offset in the page

#

This allows for zero copy IO up until the file system layer

flint idol
#
qemu-system-x86_64: hw/ide/core.c:934: ide_dma_cb: Assertion `prep_size >= 0 && prep_size <= n * 512' failed.```
#

bruh

flint idol
#

ok the prdt population code is rewritten

#

and works with this current test

flint idol
#

after a small break

#

I will now utilize the page cache within read/write

#

but I'll optimize that further

#

actually

#

nvm, my 2nd optimization strategy was dumb

#

I was going to see if the clusters within the FAT were contiguous then do the IO in chunks

#

maybe that's a good idea...

#

but that makes this two-pass for what gains...

#

well I guess the io would be done in less fragments

#

instead of reading sector n then sector n+1 then sector n+2

real pecan
#

congrats btw

flint idol
#

this is an honour

flint idol
#

I would read them all in one command

#

or write

#

I also want to implement extending of cluster chains

#

and allocating uncontiguous clusters

flint idol
#

Damn it my computer died on me

lean glen
flint idol
#

ok my computer is back

#

it just quite literally died

real pecan
#

because i follow fadanoid

flint idol
#

it started spamming 4

#

and the ctrl+alt+delete screen was up on only one display

real pecan
flint idol
#

well vscodium died on me

#

guess I'm using nano now

lean glen
#

or use a proper text editor

#

like

#

emacs

flint idol
#

kate meme

#

(the kde text editor)

lean glen
#

I'm aware of it

#

never tried it

#

heard its pretty good tho

flint idol
#

it seems to support LSP (language server protocol I think?)

#

and git

#

ngl kate is actually kinda good....

flint idol
#

the fuck is this allocator bug

#

in Reallocate

#

it's giving me a region starting in the shadow space

#

meh whatever

#

I think I'm going to add colours to my logs

#
enum colour
{
         COLOR_BLACK = 0,
    COLOR_BLUE = 1,
    COLOR_GREEN = 2,
    COLOR_CYAN = 3,
    COLOR_RED = 4,
    COLOR_MAGENTA = 5,
    COLOR_BROWN = 6,
    COLOR_LIGHT_GREY = 7,
    COLOR_DARK_GREY = 8,
    COLOR_LIGHT_BLUE = 9,
    COLOR_LIGHT_GREEN = 10,
    COLOR_LIGHT_CYAN = 11,
    COLOR_LIGHT_RED = 12,
    COLOR_LIGHT_MAGENTA = 13,
    COLOR_LIGHT_BROWN = 14,
    COLOR_WHITE = 15,
};
struct log_backend
{
        void(*write)(char* buf, size_t sz);
// Can be nullptr.
        void(*set_colour)(colour c);
// Can be nullptr.
        void(*reset_colour)();
};```
lean glen
#

COLOR_COLOR

#

why

#

😭

flint idol
#

I was copy pasting from somewhere

#
typedef enum {
    COLOR_BLACK = 0,
    COLOR_BLUE = 1,
    COLOR_GREEN = 2,
    COLOR_CYAN = 3,
    COLOR_RED = 4,
    COLOR_MAGENTA = 5,
    COLOR_BROWN = 6,
    COLOR_LIGHT_GREY = 7,
    COLOR_DARK_GREY = 8,
    COLOR_LIGHT_BLUE = 9,
    COLOR_LIGHT_GREEN = 10,
    COLOR_LIGHT_CYAN = 11,
    COLOR_LIGHT_RED = 12,
    COLOR_LIGHT_MAGENTA = 13,
    COLOR_LIGHT_BROWN = 14,
    COLOR_WHITE = 15,
} color;
typedef struct log_backend {
    void* userdata;
    void(*write)(const char* buf, size_t sz, void* userdata);
    void(*set_color)(color c, void* userdata);
    void(*reset_color)(void* userdata);
} log_backend;```
#

my final thingy

vale nymph
#

vga ass colors

#

did you copy it from the barebones thing in the wiki lmao

flint idol
#

I copied them from my 1st kernel

#

lmao

#

I just need simple colours ok

#

and I also need to fix an allocator mismatch

#

before smp init?

#

weird

#

it's while parsing the kernel command line

#

ofc only in release mode

#

it was because I was checking for that in Free regardless of kasan being enabled

#

but in the allocate region function it was only setting the region's owner pointer if kasan is enabled

#

causing r->This to be nullptr

#

I now have pretty logs

#

:-)

#

infy can you not change the uacpi log levels any time soon

#
OBOS_SetColor(OBOS_LogLevelToColor[level-1]);
printf("[uACPI][%s]: ", prefix);
vprintf(format, list);
OBOS_ResetColor();```
#

in my kernel's uacpi_kernel_vlog

#

ty

ornate ginkgo
#

use a switch and a default case?

flint idol
#

too much work

#

yk what I mean

#

if they change that's when I do that

#

speaking of uacpi...

#

I need to update my kernel api

flint idol
#

which was as soon as I updated uacpi...

#

since ttys are stupid

#

I will implement the next thing on the list

#

which is...

#

pipes

#

there's no way they're that complicated...

#

isn't it just a fifo buffer?

#

that's a named pipe

#

I think anon pipes are the same

#

i.e., pipes made with pipe.2

#

except they aren't named

#

but no, one fd is wrote to

#

and the other is read from

#

so fifo pipes are basically just temporary files in ram?

#

seems like it

flint idol
#

I'll be starting with fifo pipes

#

since they're more intuitive

#

for me

#

ahhhhhhhhhh

#

vnode initialization

vale nymph
#

they have some annoying rules but theyre ok

flint idol
#

to man fifo I go...

#

oh yeah the atomic thing

#

and to man 7 pipe I go...

flint idol
#

@vale nymph is this the pipe atomic funniness you were talking about before?

#

The only difference between pipes and FIFOs is the manner in which they are created and opened. Once these tasks have been accomplished, I/O on pipes and FIFOs has exactly the same seman‐
tics.

#

just a note to self

vale nymph
#

yeah

flint idol
#

ok

#
// !O_NONBLOCK, n <= PIPE_BUF: Atomic writes, block if no room
//  O_NONBLOCK, n <= PIPE_BUF: Atomic writes, return OBOS_STATUS_TRY_AGAIN if no room.
// !O_NONBLOCK,  n > PIPE_BUF: Unatomic writes, blocks until data is written (which includes blocking until the pipe is full).
//  O_NONBLOCK,  n > PIPE_BUF: Unatomic writes, return OBOS_STATUS_TRY_AGAIN if no room. Note: Partial writes are possible (check nWritten).```
#

I think I understood that correctly

#

what does it mean by atomic write?

#

take a rw lock until the write is done?

#

sometime tomorrow I will continue implementing pipes

#

and hopefully will be done pipes tomorrow or the day after

#

and can start syscalls after

#

pipes are at least ez pz

#

I'll implement TTYs in the near future™️

vale nymph
#

So if its above pipe_buf the pipe data might have shit from other processes inbetween

flint idol
#

ah

#

so something like (when n <= PIPE_BUF)

PushlockAcquire(&pipe->lock, WRITER);
memcpy(pipe->buffer+pipe->out_off, buf, szWrite);
PushlockRelease(&pipe->lock, WRITER);```
#

assuming you have room in the pipe

#

and unatomic would mean I just copy into the thing?

#

but what if

#

there is an atomic write going on

ornate ginkgo
#

then you wait lol

#

its atomic

flint idol
#

so like

ornate ginkgo
#

or you dont wait, depending on flags

flint idol
#

I'll just figure this out tomorrow

#

even though this isn't complicated or anything

#

I'm just gonna say fuck unix

real pecan
flint idol
#

ok thanks

vale nymph
#

So if you write less than pipe buf itll be guaranteed to arrive in an entire contiguous chunk in the pipe but if its above you can have some other data in the middle

#

If, say, theres no space in the pipe to complete the whole write at once

flint idol
#

Ohhhh that makes sense

flint idol
#

ok pipes time

#

probably

#

so I think I can set PIPE_BUF to some random number

#
#define PIPE_BUF (512 /* minimum specified by POSIX */)
#

idk what it's supposed to define

#

seems like it's only the limit to change atomic thingies or not

flint idol
#

idk what's up with my kernel rn

#

but

#

when there is a partition that is not FAT

#

it just hangs while probing it

#

I also need to make my pagecache faster

flint idol
#

I'm gonna use clang-format for my os

#

now

flint idol
#

I have settled on using the ms style

#

from clang-formating this

#

I don't think it's a good idea to commit a 17k commit

vale nymph
#

coward

flint idol
#

especially with another commit in the works

#

I'll finish the other one

#

then format

#

now I would continue what I was doing before

#

but I have no idea

#

what I was actually doing

#

yeah what

#

why is it hanging

#

bro wtf

flint idol
#

wait what

#

I need to fix a bug

#

slightly related to this

torpid wigeon
#

like c#?

thick jolt
flint idol
#

it's microsoft's code style

#

or at least how clang-format sees the ms code style

#

let's see what did I do today for the kernel

#

nothing

#

actually

#

I made it so that

#

I meant

#

I fixed the git history

#

since my commits had their name as Linus Torvalds

#

luckily for me no one but me has a local copy of obos' repo

ornate ginkgo
#

As far as you know

opaque pulsar
flint idol
flint idol
#

Lol

flint idol
#

instead of having its own

#

it did make a bug

#

when I did that

#

as a wise klange said

#

#1141057599584878645 message

flint idol
#

there it is

#
reading pc entry at ffffff0020b95000 for vn ffffff0000537e50```
#

and right after that

#
Page fault at 0xffffffff80007f65 in kernel-mode while to read page at 0xffffff0020b96000, which is unpresent. Error code: 0```
#

and a rebuild causes a hang

#

beautiful

#

after a bit

#

it crashes

#

why is it trying to read 9 sectors

#

page_size / sector_size != 9

#

page_size is 4096
sector_size is 512

#
obos_status status = driver->ftable.read_sync(vn->desc, (void*)addr, OBOS_PAGE_SIZE/blkSize, current_offset, nullptr);
#

the most stupid thing I have done in my kernel

#

is definitely not adding a vnode* owner to the pagecache

#

I made it have that

#

because otherwise I do questionable stuff

#

a jinn is playin' around with my computer

#
uhhh, what? (1050624 + 8) > port->nSectors```
#
printf("uhhh, what? (%d + %d) > port->nSectors", blkOffset, blkCount);
#
blkCount = (blkOffset + blkCount) - port->nSectors;
#

I might be delulu

#
if ((blkOffset + blkCount) > port->nSectors)
{
    printf("uhhh, what? (%d + %d) > port->nSectors\n", blkOffset, blkCount);
    blkCount = (blkOffset + blkCount) - port->nSectors;
}```
#

well I almost fixed that

flint idol
#

I add some range checks

#

for block and file offsets

#

in the pagecache, vfs, and ahci driver

#

and now, file mapping has mysteriously stopped working

#

fixed

#

now time to wait

#

to see if the previous bug was fixed

#

it isn't

#

because a disk was being accessed out of range

#

and now the pc get entry function returns nullptr when that happens

#

fixed

flint idol
#

I will finish almost everything else I need for pipes today

#

wait

#

a pipe can have multiple readers and writers, right?

#
typedef struct pipe_desc
{
    struct waitable_header wait_hdr;
    vnode *vn;
    void* buf;
    size_t pipe_size;
    uoff_t write_offset;
    uoff_t read_offset;
} pipe_desc;```
#

wouldn't that mean that *_offset need to be

#

per-each reader/writer

#

actually

#

I don't know

#

I think that

#

it's supposed to be global to the pipe

#

once read_offset == write_offset, the read would return EPIPE I think?

#

or some sorta error status saying the pipe is empty

#

and once write_offset becomes equal to the pipe size, the pipe is full?

#

I suck at ipc don't I

flint idol
#

that gets increased on write

#

and decreased on read

#
typedef struct pipe_desc
{
    struct waitable_header wait_hdr;
    vnode *vn;
    void* buf;
    size_t pipe_size;
    uoff_t offset; // on read, subtract from offset, on write, add to offset
} pipe_desc;```
#

@vale nymph if I guarantee atomic writes no matter the size of the write in my pipe implementation, will it come back to bite me?

vale nymph
#

and it'll be that fun type of bug where you dont know why its happening :')

flint idol
#

bruh ok

#

I hate u posix

#

I'll just make PIPE_BUF be UINT64_MAX

#

I need to fix a bug with pushlocks

#

it is currently possible for there to be a reader while there is a writer

#

I think I fixed that

#

before there was a race condition

#

where when a reader lock could be acquried on the pushlock

#

while there is a writer

#

now, acquire contains this:

if (reader)
    {
        if (lock->currWriter)
        {
            lock->nWaitingReaders++;
            while(lock->currWriter);
            lock->nWaitingReaders--;
        }
        lock->nReaders++;
        return OBOS_STATUS_SUCCESS;
    }``` (forgive the formatting, copy paste is funny)
#

and if you release a writer lock:

lock->currWriter = nullptr;
return lock->nWaitingReaders ? OBOS_STATUS_SUCCESS : CoreH_SignalWaitingThreads(&lock->hdr, false, true);```
#

if there are waiting readers, then it simply continues

#

otherwise it wakes a thread that wants to be a writer

#

I will use a pushlock for 'atomic' writes

#
typedef struct pipe_desc
{
    struct waitable_header wait_hdr;
    vnode *vn;
    void* buf;
    size_t pipe_size;
    uoff_t offset;
    pushlock lock;
} pipe_desc;```
#

current structure of a

#

pipe descriptor

#

something tells me that only having one offset for each opened pipe sounds wrong

#

well

#

one way to find out is to see whether this comes back to bite me

#
static obos_status read_sync(dev_desc desc, void* buf, size_t blkCount, size_t blkOffset, size_t* nBlkRead)
{
    if (!desc)
        return OBOS_STATUS_INVALID_ARGUMENT;
    pipe_desc *pipe = (void*)desc;
    if (!pipe->offset)
        return OBOS_STATUS_EOF; // nothing to read...
    if (blkCount > pipe->pipe_size)
        blkCount = pipe->pipe_size - pipe->offset;
    Core_PushlockAcquire(&pipe->lock, true);
    memcpy(buf, (char*)pipe->buf + pipe->offset, blkCount);
    Core_PushlockRelease(&pipe->lock, true);
    pipe->offset -= blkCount;
    if (nBlkRead)
        *nBlkRead = blkCount;
    return OBOS_STATUS_SUCCESS;
}```
#

what happens

#

if a write has

#

a size that is greater than the pipe size

#

shit

#

I'm dumb

#

I think I'd need to split the writes

#

into smaller writes

#

so something like:

#
while bytes_left_to_write
  write(...)
  bytes_left_to_write - bytes_written```
#

since I made it so pipe_size has to be >= PIPE_BUF

#

writes greater than pipe size should be able to be done unatomically

#

without consequence

#
static obos_status write_sync(dev_desc desc, const void* buf, size_t blkCount, size_t blkOffset, size_t* nBlkWritten)
{
    OBOS_UNUSED(blkOffset);
    if (!desc)
        return OBOS_STATUS_INVALID_ARGUMENT;
    pipe_desc *pipe = (void*)desc;
    if (blkCount > pipe->pipe_size)
    {
        size_t written_count = 0;
        size_t curr_written_count = 0;
        off_t current_offset = 0;
        long bytes_left = blkCount;
        while (bytes_left > 0)
        {
            obos_status status = write_sync(desc, buf + current_offset, bytes_left > pipe->pipe_size ? pipe->pipe_size : bytes_left, 0, &curr_written_count);
            if (obos_is_error(status))
                return status;
            written_count += curr_written_count;
            bytes_left -= curr_written_count;
            current_offset += curr_written_count;
        }
        if (nBlkWritten)
            *nBlkWritten = written_count;
        return OBOS_STATUS_SUCCESS;
    }
    bool atomic = blkCount <= PIPE_BUF;
    Core_PushlockAcquire(&pipe->lock, !atomic /* if we want to do an unatomic write, then we can be a reader, otherwise, we must be a writer */);
    memcpy((char*)pipe->buf + pipe->offset, buf, blkCount);
    pipe->offset += blkCount;
    Core_PushlockRelease(&pipe->lock, !atomic);
    if (nBlkWritten)
        *nBlkWritten = blkCount;
    return OBOS_STATUS_SUCCESS;
}```
#

write should be done

#

I do not plan on testing this.

ornate ginkgo
real pecan
#

wait

#

this shit recurses into itself?

flint idol
#

If it needs to do big writes

#

It splits it into smaller writes

flint idol
#

I just need to implement create pipe (equivalent to pipe.2, but it takes an optional pipe size)

flint idol
#

done

#

probably

#

OBOS_ASSERT(!"untested") in my pipe impl

#

for educational purposes

flint idol
#

I will commit this code

#

and then run clang-format

#

on everything

#

just pushed pipes

#

now time to clang-format this shit

#
 215 files changed, 17962 insertions(+), 17093 deletions(-)```
#

perfect

#

still boots

#

time to commit

#
Misc: Small changes```
#

lol

sharp pike
#

nothing biggie

flint idol
#

it even formatted r4's m68k loader thing

#

the limine stub

#

but I think I will undo that

#

I don't know why, but my m68k entry code

#

is 100x cleaner than the x86_64 entry code

#

350 lines vs 1000 lines

#

I will actually undo that commit

#

and format everything once I merge this branch with master

#

that way I don't get as much merge conflicts

flint idol
#

before I start making syscalls

#

I want to make some final changes to the mm

#

to make entering user space possible

#

or rather, starting user programs possible

#

basicalyl all it is

#

is create_context

#
void Mm_ConstructContext(context* ctx); // userspace-only
// Allocates a page table. Must have enough of the kernel mapped for a userspace -> kernel mode switch to work.
page_table MmS_AllocatePageTable();
#
void Mm_ConstructContext(context* ctx)
{
    OBOS_ASSERT(ctx);
    memzero(ctx, sizeof(*ctx));
    ctx->pt = MmS_AllocatePageTable();
    ctx->lock = Core_SpinlockCreate();
}```
#

simple enough

#

the hard part lies in allocate pt

#

I only need two symbols to be there to allow a user->kernel transition to happen

#

so those two symbols will be the onyl ones allocated

#

actually

#

it's more like an entire file

#

which is isr.asm

#

MmS_AllocatePageTable turned out to be pretty simple

#

I do need to map the kernel stacks in the tss tho

#

my syscalls will run at IRQL_DISPATCH

#

ok, I have implemented that

#

time to see if I can start a userspace-thread

#

that just jmp $s

#

three things can happen:

  • it triple faults
  • it page faults
  • it hangs as intended
#
    context* new_ctx = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(context), nullptr);
    Mm_ConstructContext(new_ctx);
    void* mem = Mm_VirtualMemoryAlloc(new_ctx, nullptr, 0x1000, OBOS_PROTECTION_EXECUTABLE, VMA_FLAGS_NON_PAGED, nullptr, nullptr);
    uintptr_t mem_phys = 0;
    MmS_QueryPageInfo(new_ctx->pt, (uintptr_t)mem, nullptr, &mem_phys);
    char* mem_kern = MmS_MapVirtFromPhys(mem_phys);
    // jmp $
    mem_kern[0] = 0xeb;
    mem_kern[1] = 0xfe;
    thread* thr = CoreH_ThreadAllocate(nullptr);
    thread_ctx thr_ctx = {};
    void* stack =  Mm_VirtualMemoryAlloc(new_ctx, nullptr, 0x4000, OBOS_PROTECTION_EXECUTABLE, VMA_FLAGS_NON_PAGED|VMA_FLAGS_GUARD_PAGE, nullptr, nullptr);
    CoreS_SetupThreadContext(&thr_ctx, (uintptr_t)mem, 0, true, stack, 0x4000);
    CoreH_ThreadInitialize(thr, THREAD_PRIORITY_NORMAL, Core_DefaultThreadAffinity, &thr_ctx);
    process* new = Core_ProcessAllocate(nullptr);
    new->ctx = new_ctx;
    Core_ProcessStart(new, thr);```
flint idol
#

amazing

#

it triple faulted

flint idol
#

oops

#

I forgor to put switch to thread context in the user cr3

#

now I only have one teensy weensy problem (it's a big problem)

#

how do I access a thread's context

#

in CoreS_SwitchToThreadContext

#

after switching to the user's cr3

#

what I could do is copy the context to the stack which is an ist stack (and therefore, mapped)

#

then use that

#

what I'll do is

#

before switching cr3

#

I'll copy whatever is left of the thread_ctx struct to the stack

#

then switch rdi to rsp

#

mov rdi, rsp

#

since it switches to the context pointed to by rdi

flint idol
#

to speed stuff up

flint idol
#

it almost gets to user mode execution

#

in fact, it triple faults in user-code

#

I have a 1.8M qemu log lmfao

flint idol
#

@steep ravine why do you triple fault?

#
 82968: v=0e e=0000 i=0 cpl=0 IP=0008:ffffffff8000dab3 pc=ffffffff8000dab3 SP=0010:ffffffff802a6f28 CR2=ffffffff80262f18
RAX=0000000000000000 RBX=0000000000000000 RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000000000 RBP=0000000000000000 RSP=ffffffff802a6f28
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff8000dab3 RFL=00200086 [--S--P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 0000000000000000 ffffffff 00af9b00 DPL=0 CS64 [-RA]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 ffffffff80262b20 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0028 ffffffff80262f30 00000070 00408900 DPL=0 TSS64-avl
GDT=     ffffffff80262ef8 00000037
IDT=     ffffffff8025d900 00000fff
CR0=80010011 CR2=ffffffff80262f18 CR3=000000003d090000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000018 CCD=ffffffff802a6f28 CCO=ADDQ
EFER=0000000000000d00```
#

w h a t

#

what is this PFing on

#

gdt isn't mapped probably

#

fixed that

#

and now it seems like my gdt is broken

#

as I get a GPF

#
info->arch_specific.gdtEntries[0] = 0;
info->arch_specific.gdtEntries[1] = 0x00af9b000000ffff; // 64-bit code
info->arch_specific.gdtEntries[2] = 0x00cf93000000ffff; // 64-bit data
info->arch_specific.gdtEntries[3] = 0x00aff3000000ffff; // 64-bit user-mode data
info->arch_specific.gdtEntries[4] = 0x00cff3000000ffff; // 64-bit user-mode code```
#

that's my gdt

#

and it gpf's on 0x20 which is user code

#

I seem to have switched around user code and data

#
check_exception old: 0xffffffff new 0xd
 83278: v=0d e=0020 i=0 cpl=0 IP=0008:ffffffff8000dab3 pc=ffffffff8000dab3 SP=0010:ffffffff802a6f28 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=0000000000000000 RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000000000 RBP=0000000000000000 RSP=ffffffff802a6f28
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff8000dab3 RFL=00200086 [--S--P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 0000000000000000 ffffffff 00af9b00 DPL=0 CS64 [-RA]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 ffffffff80262b20 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0028 ffffffff80262f30 00000070 00408900 DPL=0 TSS64-avl
GDT=     ffffffff80262ef8 00000037
IDT=     ffffffff8025d900 00000fff
CR0=80010011 CR2=ffffff00007d4df0 CR3=000000003d095000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000018 CCD=ffffffff802a6f28 CCO=ADDQ
EFER=0000000000000d00```
#

it finally gets into user code

#

well it triple faults immediately

#
check_exception old: 0xffffffff new 0xe
 81919: v=0e e=0000 i=0 cpl=3 IP=0023:0000000000001000 pc=0000000000001000 SP=001b:0000000000007000 CR2=ffffffff8025db00
RAX=0000000000000000 RBX=0000000000000000 RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000000000 RBP=0000000000000000 RSP=0000000000007000
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000001000 RFL=00200202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 ffffffff 00cf1300
CS =0023 0000000000000000 ffffffff 00affb00 DPL=3 CS64 [-RA]
SS =001b 0000000000000000 ffffffff 00cff300 DPL=3 DS   [-WA]
DS =0000 0000000000000000 ffffffff 00cf1300
FS =0000 0000000000000000 ffffffff 00cf1300
GS =0000 ffffffff80262b20 ffffffff 00cf1300
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0028 ffffffff80262f30 00000070 00408900 DPL=0 TSS64-avl
GDT=     ffffffff80262ef8 00000037
IDT=     ffffffff8025d900 00000fff
CR0=80010011 CR2=ffffffff8025db00 CR3=000000003d095000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000000 CCD=ffffffff802a6f28 CCO=EFLAGS
EFER=0000000000000d00```
#

I also need to map the idt

#

forogr about that\

#
check_exception old: 0xffffffff new 0xd
 86482: v=0d e=0008 i=0 cpl=0 IP=0008:ffffffff8000805f pc=ffffffff8000805f SP=0010:ffffffff8035afd0 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=ffffffff80263648 RCX=0000000000000000 RDX=0000000000000001
RSI=000000000000001a RDI=ffffffff802639d2 RBP=ffffffff8035aff8 RSP=ffffffff8035afd0
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff8000805f RFL=00200297 [--S-APC] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 0000000000000000 ffffffff 00af9b00 DPL=0 CS64 [-RA]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 ffffffff80263648 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0028 ffffffff802636a0 00000070 00408900 DPL=0 TSS64-avl
GDT=     ffffffff80263668 00000037
IDT=     ffffffff8025d900 00000fff
CR0=80010011 CR2=0000000000000000 CR3=0000000000006000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000095 CCD=ffffffffffffffff CCO=EFLAGS
EFER=0000000000000d00```
#

mapped the idt

#

and now it GPFs

#

in the idle task

#

uhhh

#

wtf

#

the gdt is fucked

lean glen
#

e=0008

#

it faults on your gdt

flint idol
#

I know

#

gdt is fucked

#

so is the entrie cpu local struct?

#

*entire

real pecan
#

what

vale nymph
#

rust rewrite when

thick jolt
#

^^

#

dont rewrite in rust

#

seriously tho

#

dont.

#

if u dont know rust

#

do not

#

and thats coming from someone who still has a LOT to learn

shy forge
#

Do whatever you want

#

try and fail hard

flint idol
#

it's been in C for like

#

5-6 months

#

also because I'd rather do win32 api dev using assembly than use C++ for a kernel again

lean glen
#

C++ is nice

thick jolt
#

bro

#

go to #1230349543623757845

#

see the past

#

fucking month

#

actually

#

3 months

#

💀

shy forge
#

Brother I'm telling you failing hard ain't a bad thing unless you're like on a time or money budget

#

Life's a learning experience bro

#

I learnt C through osdev

#

My first malloc was literally char arr[size]; return arr;

flint idol
#

broooooooooo

#

where tf is my cpu_local struct corrupted beyond recognition

flint idol
#

I think his message lagged

#

since it's been

#

5

#

months

#

since I started this rewrite

#

so one CPU's gs_base is zero (swapgs memes?)

#

another CPU's cpu local struct might be corrupted

#

*is

#

I see a problem

#

gs base is set to some random cpu's gs_base in the thread context

#

and is restored

#

while on another cpu

#

and kernel gs base is also zero

#

so what I should do on switch to a userspace context

#

is swapgs

#

first

#

then restore the thread's gs_base

#

and now it doesn't crash!

#

who'd have thought it'd take all day to get to usermode

#
[  LOG  ] User thread 10 SIGSEGV```
#

when I add

mov rax, 0xdeadbeef
mov qword ptr [rax], 5```
#

!!!!

#

but then ofc, since signals are completely untested until now

#

it crashes

#

oopsie

vale nymph
#

0xdeadc0fee

#

or coffe

#

i dont speak engrish

flint idol
#

wait

#

what

#

signals

#

worked first try

#

this cannot be

#

now I rather implemented a way to kill arbitrary threads

#

or I did not

#

idr

#

I did not make such a thing

flint idol
#

for signals who's default action is to kill the thread

#

I'll just exit thread in the default signal handler

#

as for SIGKILL

#

I'll always force the default signal handler

#

what's "with additional actions"

#

implementation-defined abnormal termination actions, such as creation of a core file, may also occur.

#

in my case

#

idgaf about core files

vale nymph
#

dont say that about core files you'll make them sad

real pecan
flint idol
#

anyway

#

after charging myself with noodles

#

and burning my tongue in the process

#

I will finalize my signal implementation

real pecan
real pecan
flint idol
#

yes

real pecan
#

Nice

flint idol
#

signal default actions now work

#

which means my signal implementation should be complete

#

uhhh

#

that can't be good

vale nymph
#

I said the same thing months ago

flint idol
#

O_O

vale nymph
#

then I saw I was doing like 5 things wrong and forgot to implement some other things

flint idol
#

until then

#

I will be committing this

flint idol
#

syscall interface

#

how shall I abstract syscalls....

#

since a lot of syscalls are the same across all archs

#

I think I should reserve many syscalls for arch-agnostic stuff

#

and the rest are arch-specific

flint idol
#

and the rest are arch-specific

flint idol
#
uintptr_t syscalls[UINT32_MAX]; // obviously a bad idea```
flint idol
#

make this 0-0x10000

#

nvm

flint idol
# flint idol but, instead of having a table that big

I'll have something like

// increase when needed
#define ARCH_SYSCALL_TABLE_SIZE 0x10000
uintptr_t arch_syscall_table[ARCH_SYSCALL_TABLE_SIZE];
#define SYSCALL_TABLE_SIZE 0x10000
uintptr_t syscall_table[SYSCALL_TABLE_SIZE];
#define get_syscall_from_num(n) \
  (((n) >= 0x80000000) ? \
    arch_syscall_table[n-0x80000000] : \
    syscall_table[n])
#

then the arch's syscall trap handler will convert the syscall abi to the kernel abi (whatever that may be)

#

I think on x86-64, the syscall abi will be equivalent to the systemv abi (in terms of calling convention), except with eax being the syscall number

#

to make it easy to abstract it

#

because speed

#

I will implement the syscall instruction

#

and have no other trap method

#

bro

#

why did I make my syscall init function

#

in ASSEMBLY

#

in my 3rd kernel

flint idol
#

SIGILL thinkong

#

when testing syscalls

#

fixing the SIGILL causes a triple fault

flint idol
#

syscalls almost work

#

returning causes a SIGSEGV

#

idk if that's the syscall's fault

#
[ DEBUG ] hai```
#

syscall zero is currently a test syscall

#

that prints 'hai' and returns

#

I made it take a parameter

#

fixed a bug

#

and now it takes in a string from usermode and prints that

#
ORG 0x1000
mov eax, 0
mov rdi, 0x1100
syscall
jmp $
ORG 0x1100
db "hai from usermode", 0
#

that is the current code

#

tomorrow I will implement syscalls for everything

#

meaning

#

vfs, vmm, scheduler, sync primitives, ipc, and driver interface syscalls

#

then I will implement fork()

#

in the vmm

#

and expose that

#

then I'll make sure to get this all working on the m68k port

#

and finally merge userspace-work

#

then I port stuff

#

I just committed that

#

code

#

that's enough osdev for the day

#

I'm headed to sleep

#

wake up
shit
get out of bed
osdev
sleep (optional)

flint idol
#

time to implement a bunch of syscalls

#

I feel like it would be a good idea to add a context argument to read/write of drivers

#

since usermode reads and writes from drivers are possible

#

I will also implement locking pages into memory

#

I'll start with page locking

flint idol
#

actually, that's unneeded

#

if I just use user memcpy

#

along with currentContext

#

but there is one thing I must do

#

that is, when entering an interrupt from kernel mode

#

I need to switch the current context to the kernel ctx

#

I think I just found the longest single instruction in my kernel

#

of 13 bytes

flint idol
#

my vmm is ~3K loc

#

which ig is cool

#

my kernel is 27k loc

#

without drivers

#

my kernel in total is 33.3K loc

#

including drivers

flint idol
#

anyway, time to start making some syscalls

#

I will start with scheduling related syscalls

#

yield and exitcurrentthread

#

I'll implement a handle system after those two syscalls

#

should I sync pending signals on return from syscall

#

I think so

#

because it is a return from kernel->user

#

I'd need some funny logic

flint idol
#

I think it's sufficient

#

to just sync signals on return to usermode in an irq

flint idol
#

ok there is a bug

#

user stacks cannot be swapped out

#

without it breaking

#

specifically

#

it page faults twice

#

then recursively locks

#

it's a bug in cow

#
memcpy(MmS_MapVirtFromPhys(new->phys), (void*)addr, info->prot.huge_page ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE);
#

specifically here

#

fixed

vale nymph
flint idol
#

arch-specific

vale nymph
#

would that not leak memory then

flint idol
#

but on x86-64 it returns an hhdm address

flint idol
vale nymph
#

sounds leaky to map a virtual address and not unmap it later lol but sure

flint idol
#

well it doesn't

#

in any implementation

#

yet

#

and it's used very rarely

#

meaning 30 times

lean glen
#

Chances are you're going to identity map everything anyway

#

So don't do any allocation in that function

flint idol
#

I need a logo for obos

#

but I don't have any sort of artistic skills or an ai to do it for me

thick jolt
thick jolt
#

@flint idol

#

oberrow use my logo

#

its the best logo

flint idol
#

g

thick jolt
flint idol
#

hold on I just need to crop it a bit

#

amazing

#

bruh fuck gimp

thick jolt
#

amazing indeed

flint idol
#
    mov rax, [rdi]
    mov cr8, rax
    push rdi
    call Core_GetIRQLVar
    pop rdi
    mov rcx, [rdi]
    mov [rax], rcx ; crashes here becuz nullptr
    add rdi, 8```
#

and I have no idea how it crashes

#

for reference

#

this is in CoreS_SwitchToThreadContext

#

hold on wtf

#
Kernel Panic on CPU 1 in thread 10, owned by process 2. Reason: OBOS_PANIC_EXCEPTION. Information on the crash is below:
Page fault at 0xffffffff8000dd88 in kernel-mode while to write page at 0x0000000000000000, which is unpresent. Error code: 2
Register dump:
        RDI: 0xffffff0000023ea0, RSI: 0x0000000000000000, RBP: 0xffffffff80328ff0
        RSP: 0xffffffff80328f68, RBX: 0xffffffff80028a92, RDX: 0x0000000000000000
        RCX: 0x0000000000000000, RAX: 0x0000000000000000, RIP: 0xffffffff8000dd88
         R8: 0x0000000000000000,  R9: 0x0000000000000000, R10: 0x27235311250fd7ed
        R11: 0x0000000400000000, R12: 0x0000000000000000, R13: 0x0000000000000000
        R14: 0x0000000000000000, R15: 0x0000000000000000, RFL: 0x0000000000210282
         SS: 0x0000000000000010,  DS: 0x0000000000000000,  CS: 0x0000000000000008
        CR0: 0x0000000080010011, CR2: 0x0000000000000000, CR3: 0x0000000000006000
        CR4: 0x0000000000000020, CR8: 0x0000000000000000, EFER: 0x0000000000000d01```
#

this function clis at the very beginning

#

and rflags.if=1

#

fuck

#

may god have mercy on me.

#

this is stack corruption at the best

flint idol
#

hmm

#

it seems to have returned from a page fault handler

flint idol
#

looks kinda weird

#

better

flint idol
#

after procrastination through football clips

#

I will continue debugging

flint idol
#

I added the syscalls Sys_Rebootand Sys_Shutdown

#

that reboot and shutdown (surprising right?)

#

and it doesn't break

#

it seems to be a bug with yield

#

since

#

when I replace the yield syscall

#

with one that does nothing

#

it doesn't crash

#
mov rdi, Core_Schedule
xor rsi,rsi
call CoreS_CallFunctionOnStack```
#

in yield

#

it uses the same stack

#

that the syscall handler uses

#

CoreS_CallFunctionOnStack this function

flint idol
#

fixed the bug

#

this PR is at

#

changes

#

I need to merge this soon

real pecan
#

time for real hw tests

flint idol
#

forgot about those

#

will do

#

just need to remove the ahci driver from the initrd, it's problematic

real pecan
#

lol

flint idol
#

It works on test subject 1

real pecan
#

Which one did astral hang on

flint idol
#

#1

real pecan
#

Ah

flint idol
#

Which reminds me to test it on the other one

#

Which does not have native ps2

real pecan
#

Is it emulation

flint idol
#

It's the one with the dumb x component in the video thing

flint idol
#

I will test a laptop I have with native ps2 soon

real pecan
#

Ooh that one

flint idol
#

AMD retarbios

  • infy, 2024
#

AMD ATOMBIOS

#

This is obos running on test subject 1

#

The test program does sys shutdown

real pecan
#

Nice

#

Does that take so long u manage to take a photo of it?

flint idol
#

Before it shutdown

#

It takes like 2 or 3 seconds to shutdown on this hw

#

Quite dumb

real pecan
#

I see

flint idol
#

Test subject 2 seems to hang in the uart driver

#

Bruh

#

Idk how I messed that up

real pecan
#

Lmao

#

Out of all things u fucked up the serial driver

flint idol
#

Will be rebooting without com

flint idol
#

Upon disabling the serial driver

#

It works

#

Credits to @vale nymph for the background color

flint idol
#

ok

#

handle interface

#

basically

#

a handle is an opaque integer

#

user-facing

#

that represents a certain kernel object

#

threads, timers, etc.

#

in the kernel

#

they are keys into a hashmap in the process structure

#
enum handle_type
{
    // ...
};
struct handle_desc
{
    enum handle_type type;
    union {
        // ...
    } un;
};
typedef uint64_t handle;```
#

the actual integer type of handle is undecided

#

rather int to stay compliant-ish with unix FDs

#

or uint64_t to give more handle values (you never know when your handles will go over INT_MAX)

#

I mean it's easily changeable, especially considering nothing in userspace would be using the handle type directly but my mlibc sysdeps

#

however I think I will go with int

#

or unsigned int

#
typedef unsigned int handle; // we use unsigned int instead of uint64_t to stay compliant-ish with unix```
#

allocating handles will be shrimple

handle_freelist freelist;
handle last_handle; // when the free list is empty.```
#

someone had a good idea

#

and I will be taking it since it sounds like a good idea

flint idol
lean glen
#

Hashmap might suck here

#

Just use an array

flint idol
#

but what if the handle value gets really high

#

then the array would have to be that big

#

and like

#

that's bad

lean glen
#

that's why you have a limit

flint idol
#

if I limit handle values to UINT16_MAX it takes 1M of memory

#

for the entire handle table

flint idol
#

I can split that in half if I remove the handle type

#

from handle_desc

lean glen
#

That's a shitton of handles

flint idol
#

well yes

#

idk how many handles are usually in use at a time

#

for like bash for example

lean glen
#

Less than 65535

lean glen
#

And it runs

flint idol
#

but handles are like each kernel object for me which includes mutexes

#

meh whatever

lean glen
#

Why tho

flint idol
#

I'll increase it when I need to

flint idol
#

would I represent a mutex in userspace

#

for example

lean glen
#

Are mutexes even implemented by the kernel

vale nymph
#

no

#

not on linux at least

#

and on mlibc

flint idol
#

well frick you, I implement them in the kernel

lean glen
#

yeah

#

Futexes are tho I think?

flint idol
#

well

#

so I don't need mutex syscalls

#

probably

#

I mean it could be useful for any native programs I make

lean glen
#

I don't think you understand why you want handles

flint idol
#

to represent a kernel object in usermode, no?

#

like a file

#

or thread

#

or any sort of kernel object that the kernel wants to expose to userspace through syscalls

lean glen
#

Yeah I guess

flint idol
#
handle Sys_OpenFile(const char* file, int open_mode);
obos_status Sys_ReadFile(handle file, char* buf, size_t sz, size_t* nRead);
#

for example

lean glen
#

Yeah NT seems to use an array

#

For handles

flint idol
#

how big is it?

#

I'll just search it

#

for some reason chrome takes a minute to start

lean glen
#

This is according to the design workbook btw so it might not be true nowadays

flint idol
#

I have windows internals downloaded

lean glen
#

Yeah use that

flint idol
#

damn

#

only have part 1

#

Objects and handles
(references to instances of an object) are discussed in more detail in Chapter 8 in Part 2.

#

I'll just ask the NT nerds

flint idol
#
typedef struct handle_table {
    handle_desc* arr;
    handle_desc* head;
    handle last_handle;
    size_t size;
    pushlock lock;
} handle_table;```
#

that'll be my handle table

#

a dynamically expanding array

flint idol
#

obos with optimizations is very fast

#

it take <2s to boot

#

1s

#
while (Arch_LAPICAddress->interruptCommand0_31 & (1 << 12))
    pause();
#

my kernel spends many time in here

#
while (invlpg_ipi_packet.active && ++spin <= 10000)
    pause();```
#

as well as here

#

unsurprisingly it spends a lot of time

#

in here

    for (basicalloc_region* r = start; r; )
    {
        if (!r->free.nNodes || !r->biggestFreeNode)
            goto end;
        if (r->biggestFreeNode->size >= size)
        {
            from = r;
            break;
        }

    end:
        r = r->next;
    }```
#

(TODO: Write a better allocator)

flint idol