#OBOS (not vibecoded)
1 messages · Page 35 of 1
why is linux sending this when I do ping on that address
when I get UDP reception working
I want to see if I can make stdout/stderr/stdin point to a "socket"
and access bash through that
why not shoot for ssh
TODO
Ye
ok so after exactly 1019 ARP packets transmitted through arping
the kernel kinda just disappears
yeah idk where the kernel went
didn't crash
it just hangs after around that many packets
maybe the driver has so many packets backlogged it appears to hang
something similar happens when I make arping run faster
but with much less packets
suspiciously
it stopped at 1024 packets
which is the maximum amount of descriptors in one ring
so maybe I'm running out of descriptors
because I am incorrectly releasing them
I'm testing this once again
but with OBOS_ENSURE(~dev->isr & RxOverflow); in r8169_rx
nope
never gets hit
but I still hang after ~1024 packets sent
I think I remember experiencing a deadlock a long time ago that was caused during high memory usage which I never solved
maybe that has something to do with this
yeah no
no immediate deadlocks found
yeah it's not a deadlock it seems
what if I register a fixed event handler for the power button
and in the handler
I print a stack trace
tomorrow? 
haven't found anything
my stack traces aren't comprehensive enough
because each time it's just in CPU 0's idle thread
I think it's a bug with transmission
because data is indeed received
after exactly 1024 packets transmitted
the r8169 driver gives up
I think I did at least fix the memory leak
since the ping time stays around ~1 ms the entire time
did you try qemu -trace?
unfortunately, real hardware does not have -trace
is there no qemu emulation option for that dev?
I think it was because I was accidentally clearing the EOR bit on the last descriptor 
causing the r8169 to wander off into space
(whoops)
1038 packets transmitted, 1024 packets received, 1% unanswered (0 extra)
rtt min/avg/max/std-dev = 0.222/1.432/4.178/0.614 ms```
OBOS' replies to ARP seem to be pretty fast

yeah so as soon as it rolls back to the first descriptor
in the transmit function
it ceases to work
fixed the bug
- desc->command = tx_frame->sz & TX_PACKET_LEN_MASK;
+ desc->command = (desc->command & EOR) | (tx_frame->sz & TX_PACKET_LEN_MASK);```
8816 packets transmitted, 8803 packets received, 0% unanswered (0 extra)
rtt min/avg/max/std-dev = 0.004/1.828/7.871/0.600 ms```
sudo arping 192.168.100.2 -i enp0s25 -W 0.004```
anyway: obos' stress test is now arping
--- 192.168.100.2 statistics ---
102 packets transmitted, 0 packets received, 100% unanswered (0 extra)```
ah shit it stopped working 
802.11 when?
Nah, no one gets that right
its actually not bad, making a wifi card driver is the harder part lol
i watched the 38c3 talk on esp32 wifi liberation and it seemed like a simple driver is not that hard
they did it in like a year, not as a full time job but as a hobby
and they were reverse engineering
implementing a driver for a well documented one wouldn't be too hard
ig it depends on whether the card has proper specs and whatever yeah, I have only looked at some linux realtek drivers and they don't look fun to implement lol
also I'd imagine esp32's wifi is probably very simple
to bring it up
not to do any packets
just poweron
iirc
I'll pass
yeah same
If I ever do that, it would probably be in a portable library
Because like wifi is cool
But not cool enough to sell my soul to
uWiFi?
u80211
no STA mode works
they're lacking AP and AWDL and mesh networking
and AWDL is an extra it's not actually supported by the proprietary driver in the SDK
Idk what this all means
it's "simple" but needs to be reverse engineered and almost entirely undocumented
as all wifi controllers
they only had function names because expressif didn't strip it
That's like saying fuck you you're not getting this code in a whole other way
STA is station mode, AP is access point mode, mesh networking is mesh networking and AWDL is AirDrop, AirPlay, etc.
I mean apparently they're extremely cool about it and they would release the source if not under NDA
the binaries are apache licensed
oh and they don't have the esp32-specific long range wifi thingy (which is very cool because 1km wifi!!)
intel or someone else wouldn't be this cool about it
wifi and bt are pretty much the only closed source thingies in the esp32 sdk
because they're not espressif's and it's licensed from riviera waves i think
After school, I hope to implement IPv4 reception
And UDP reception
ARP is cool n shit but not quite enough
And also ICMP to go with that, as the two seem related
Also iirc IPv4 also requires packet forwarding
do you have arp?
Yes
icmp is separate from ipv4 iirc
you do not need it
Okay
I want to do that later
ipv6 is pretty simple ime
I will do it, don't worry
cool
I also need to see if a bug fix for my r8169 driver worked
Basically just a deadlock
Also I made a mistake saying the kernel dispatches DPCs when lowering to dispatch IRQL or lower
I meant to say IRQL passive
I need to fix my pagecache soon
It's shitty
None of the pages ever really go on standby/dirty
And speaking of that
I need to fix that too
I'm going to revive the obos m68k port today
Uhh so time to build gcc
For the billionth time this year
astral lore
I will also see if I can get mlibc ported too
It should hopefully be straightforward*
*obos m68k last compiled 5-6 months ago
Waiting for gcc to compile:
should be doable
mlibc/m68k-linux is fully test passing
I only need the crt begin I assume?
And the other crt*.S files
Because my syscalls have the same numbers across architectures
I would just need to implement a syscall trap handler
iirc the trap instruction on m68k is for syscalls
me when trying to build astral
I didn't even know I had "so little" disk space until then
An astral minimal build for me took 16G
and how long did it take?
cause I made a PR for it and I thought to test it before publishing the PR
and I let it build for ~1h and it still wasn't finished and I said aight, let's make the PR anyways
ah damn it
obos m68k crashed first thing
wait not first thing
it got to vfs initialization
bruh what the fuck
Mm_VirtualMemoryAlloc had the brilliant idea of overwriting a kernel code mapping
[ LOG ] Arch_KernelEntry: Done early boot.
[ LOG ] Currently at 8796 KiB of committed memory (36 KiB pageable), 0 KiB paged out, and 8760 KiB non-paged, and 0 KiB uncommitted. Page faulted 47 times (0 hard, 47 soft).```
got the m68k port to boot again
!!
ngl the m68k port is so boring on the qemu virt machine
no devices to support
no PCI
not even ACPI
and the audacity for it to use that much memory
but still do nothing
[ DEBUG ] Arch_KernelEntry: Initializing allocator.
[ DEBUG ] Arch_KernelEntry: Initialize kernel process.
[ DEBUG ] Arch_KernelEntry: Initializing IRQ interface.
[ DEBUG ] Arch_KernelEntry: Initializing VMM.
[ LOG ] Initialized MM.
Working set capacity: 4096 KiB.
4 pageable pages.
2187 committed pages.
Using AGING PRA.
[ DEBUG ] Arch_KernelEntry: Initializing timer interface.
[ DEBUG ] Arch_KernelEntry: Initializing scheduler timer.
[ DEBUG ] Arch_KernelEntry: Loading kernel symbol table.
[ DEBUG ] Arch_KernelEntry: Loading InitRD driver.
[ LOG ] Drv_LoadDriver: Loaded driver 'Initial Ramdisk (InitRD) Driver' at 0xc08ba000.
[ DEBUG ] Arch_KernelEntry: Initializing VFS.
[ LOG ] Arch_KernelEntry: Done early boot.
[ LOG ] Currently at 8796 KiB of committed memory (36 KiB pageable), 0 KiB paged out, and 8760 KiB non-paged, and 0 KiB uncommitted. Page faulted 49 times (0 hard, 49 soft).```
8748 KiB of that memory is used by the kernel binary itself
ok great
with optimizations enabled
/home/oberrow/Code/obos-pkgs-m68k/pkgs/lib/gcc/m68k-obos/14.2.0/../../../../m68k-obos/bin/ld: src/oboskrnl/CMakeFiles/oboskrnl.dir/vfs/pipe.c.obj: in function `read_sync':
pipe.c:(.text+0x7c): undefined reference to `__atomic_load_8'
that happens
maybe it helps to include stdatomic 
nvm it doesn't
ah great
it doesn't even use stdatomic
I decided to change a member of a struct to _Atomic(uoff_t) to _Atomic(uintptr_t)
and it compiles
ok it boots
time to see if x86_64 isn't broken
wait I actually think I know the problem
linking with libatomic doesn't work
I want to implement execve for m68k next
and the hand off to init function
then I will merge the branch
surely that won't be too hard
it's not even that I need execve
I just need to code to hand off to a process after exexce
OBOS_NORETURN OBOS_WEAK void OBOSS_HandControlTo(struct context* ctx, struct exec_aux_values* aux);
OBOS_NORETURN OBOS_WEAK void OBOSS_HandOffToInit(struct exec_aux_values* info);
the latter might as well be implemented in a non-architecture specific way
void OBOSS_HandOffToInit(struct exec_aux_values* aux)
{
OBOS_OpenStandardFDs(OBOS_CurrentHandleTable());
irql oldIrql = Core_RaiseIrql(IRQL_DISPATCH);
OBOS_UNUSED(oldIrql);
context* ctx = CoreS_GetCPULocalPtr()->currentContext;
Core_GetCurrentThread()->context.stackBase = Mm_VirtualMemoryAlloc(ctx, nullptr, 4*1024*1024, OBOS_PROTECTION_USER_PAGE, VMA_FLAGS_GUARD_PAGE, nullptr, nullptr);
Core_GetCurrentThread()->context.stackSize = 4*1024*1024;
CoreS_SetThreadPageTable(&Core_GetCurrentThread()->context, ctx->pt);
OBOSS_HandControlTo(ctx, aux);
}```
x86_64 does this
all of those APIs except for the stack things
are not x86-64 specific
then I will also implement syscall traps
and then I will merge
that branch
and continue on my network stack
ah damn it I also need to add signal support to the m68k port
and a TLS syscall
For the subset of the floating-point instructions that generate exception traps, the FPU
loads the 32-bit FPIAR with the logical address of the instruction before executing the
instruction. Because the IU can execute instructions while the FPU executes floating-point
instructions and, the FPU can concurrently execute two floating-point instructions the PC
value stacked by the MC68040 in response to a floating-point exception handler cannot
point to the offending instruction.
cursed
it seems like I need to manually save FPE registers on the m68040
bruh
I wrote this port 6 months ago
*4 motnhs
*months
because
at one point I broke a bunch of stuff
didn't want to look at m68k docs
fair
move.l (+4,%sp), %a0```
what dose htis does
moves
move source, destination
I think was the syntax
a0 = *(sp+4)
ah yes
I think of src, dest as "put src in dest" and dest, src as "dest = src"
src, dest makes more sense because if I take a mov %rax, %rbx for example, it comes natural to say it means "move rax to rbx"
so src, dest is superior
jk it's just an opinion
I think Intel tried to give that feel of a higher level lang where you do a = b; to put b in a
or
yk
math
you're all brainwashed into thinking that anything related to unix and GNU is good, when i see AT&T assembly i start vomiting and that effects my mental & physical health. Have you ever thought about that, dummy? like dude who thought "ah yes we will put a % before the register name" this is so fucking retarded man. I dont know how you people live with this, I would rather write userland programs for windows than use AT&T syntax for an hour. You can also shove your q,l,w,b suffixes into your asses. Nobody can be more retarded than the guy who thought movq was okay. Also shove your $ up your ass. That thing used to make me vomit, man. Imagine having to put $ for immediates. This is like the most retarded thing ever invented, i dont get why people use this syntax. intel syntax is waaay better. instead of littering the world with your fucked up assembly syntax you should go learn intel syntax assembly. i want to fucking die when i see AT&T assembly man. Like one time i was trying my best to read some AT&T assembly and it took me 4 days to figure out how jmp worked, man. 4 days man. I don't get what's wrong with you people, you keep saying "belwewbewb at&t syntax good barwebqrebrewr" and it's so fucking annoying. When you say that i want to gouge your eyes out and put them in front of the intel assembly so you can stare at it and understand its beauty. Oh btw no one fucking cares about your random .cfi_def_cfa_offset or your fucking section ".note.GNU-stack","",@progbits like dude nobody fucking cares if you want to do shit that nobody understands.
just do it the normal way, will ya? if we were in an arena i would beat the piss out of y'all because of how annoying you all are. the worst part is you fucking got your shitty asssembly syntax into inline assembly like dude wtf the syntax already sucks why make it suck more?? Every time i see inline assembly i cringe because of the fucked up AT&T syntax thing you managed to put there. I dont even know how you read your assembly and actually be able to understand it. You need to win the "person with the strongest stomach" award man. I dont last five minutes when i look at your fucking assembly syntax. Now go use intel assembly or shove your AT&T up your ass. Peace.
Anyway, after these network stack shenanigans and m68k stuff
I might port ncurses
Or curses idk what the difference is
Maybe one makes obos cursed and the other doesn't
at the end of the day it all sucks
I think intel syntax is easier to read and write but its slightly less explicit
I've just been taught AT&T at university, and don't know Intel syntax
So to me people unsing Intel are anoying
I write at&t inline and wanted to drop the extra nasm dependency so just rewrote my asm in at&t
for my bootloader I kept using nasm cuz too much assembly
Note to self: never comment on assembly syntax in your progress thread
You guys can go to uacpi thread aka lounge 2
You've got to compete with Nyaux thread somehow
risc-v is gonna take over
opinion
gcc vs clang vs msvc
Clang
at least I agree on that
Although I am scared of compiling llvm
it's ez
Yeah but I don't care enough
Idk porting gcc and binutils wasn't too hard
Just needed to compile gcc 10+ times
In a day
At some point I gave up and bought 64GB of RAM
I said to myself that I'll take a break from homework to relax, only to come up to this 
lemme actually read it
not sure u wanna read it
I would rather write userland programs for windows than use AT&T syntax for an hour
the syntax already sucks why make it suck more??
comedy gold
nah I got a decent laugh out of it
so is it copypasta
Yes
He can be found in the mintia project server
honestly I agree about $ and % being stupid
I just like src, dest so I tolerate all of the rest 
well yea
nah, you get used to it after a couple of page faults because of movl 0, %eax
I had add %rsp, $16 which is even worse
i think my record is like 16 gcc compiles in a day
including failures tho
and i wasn't even doing proper osdev, i was just working on mlibc in nixpkgs
and yes mlibc in nixpkgs is almost ready it just needs some cleanup and reviewing
and a couple bugs in mlibc to be squashed
my record is like 5 llvm + clang + libc++ compiles yesterday
only two of them would actually have been required but I were trying to compile an aarch64 toolchain + libc++ using the same sysroot folder as what I used for x86_64 and that created weird errors that I tried to resolve in different ways until I realized that
the only benefit of porting llvm is llvm-pipe really
yeah what the fuck is atnt syntax it gives me more cancer than windows
fuck intel but damn
jmp *%rax 
llvm is just another level
once i was compiling llvm under wsl i think
it took around 16 hours or so
yea 20 mins is gcc for me
this is the best machine i ever touched 6 core ryzen laptop
ayymd
what does ayymd mean
?
Do you mean the dumb hexdump clone?
Ah that
It's called speedcrunch if you didn't know 
apt-listchanges: News
---------------------
apt (2.9.24) unstable; urgency=medium
/etc/apt/trusted.gpg is no longer trusted. Setting the Dir::Etc::trusted
option manually continues to work for some more time.
sources.list(5) entries without the Signed-By field are deprecated;
migrate any legacy entries to the deb822 .sources format. See the
apt-secure(7) manual page for best practices for signer configuration.
This deprecates the /etc/apt/trusted.gpg.d directory.
-- Julian Andres Klode <[email protected]> Tue, 21 Jan 2025 12:17:36 +0100
fuck u
W take
tho u sound a big crazy and u sound like ur losing it a little
actually I remember dreamingwarlord from a few years ago
but it seems like they got banned lol
I want to change my vfs mount code
It's quite inefficient
Or maybe the problem is my fat fs code
Either way it's very slow
what is it doing
Slow shit
Also my pagecache is le dogshite
I need to fix that
In a hurry*
*sometime in the next 4 months
I made it when I didn't understand what standby and dirty lists did
L take
I could say the same about Intel syntax, all of the things you're complaining about make it so much more readable and obvious what its actually doing
probably memory corruption 
No
Considering all other fields were correct
The struct was a stack buffer
And stuff
Also 2021 is way to close to 2025
For this to be that
- time->year = read_cmos8(CMOS_REGISTER_YEAR);
+ time->year = read_cmos8(CMOS_REGISTER_YEAR) + 4;```

k just merged that branch

wait u can read the cmos???
HOW
@flint idol I tested obos on the laptop, it looks to at least somewhat work as it gets stuck after it says "Could not make device wake capable" and two uacpi reads
Using port io
There are many ISOs
Here
One of them hangs after uacpi init
Iirc
is there a cmos on every archiecture or just x86
Idk
fair ill just keep it on x86
no there isn't on all architectures
i see
What do you mean by uacpi reads
it just had two uacpi trace lines for some reads after that and nothing more
Did you find this iso in the uacpi thread?
and this iso was some that I downloaded like 10 days ago when I tested it on the other laptop where it triple faulted
I am in the process of fixing a bug with the IOAPIC
When I fix that bug I can send you an iso
Because that is the only thing that I know that could cause obos to hang in uacpi init
The error you got from the wake gpe was just firmware devs being too stoobid for obos to handle
Out of curiosity what was the status it printed
@white mulch
Status mismatch which is interesting
It means the _S3D and _S3W values contradicted each other
if ((snd != UINT64_MAX && snw != UINT64_MAX) && snw >= snd)
{
if (status)
*status = OBOS_STATUS_MISMATCH;
return DSTATE_INVALID;
}```
I'm implementing a gettimeofday syscall for obos
I'm definitely not stealing anything from mlibc
static int days_from_civil(int y, unsigned m, unsigned d) noexcept {
y -= m <= 2;
const int era = (y >= 0 ? y : y - 399) / 400;
const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
const unsigned doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365]
const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
return era * 146097 + static_cast<int>(doe) - 719468;
}```

[23/37] Linking C executable /home/oberrow/Code/obos-patch/out/powerctl
FAILED: /home/oberrow/Code/obos-patch/out/powerctl
: && /home/oberrow/Code/obos-pkgs/pkgs/bin/x86_64-obos-gcc -O2 -g -DNDEBUG -fsanitize=undefined src/user_examples/CMakeFiles/powerctl.dir/powerctl_example.c.obj -o /home/oberrow/Code/obos-patch/out/powerctl && :
/home/oberrow/Code/obos-pkgs/pkgs/lib/gcc/x86_64-obos/14.2.0/../../../../x86_64-obos/bin/ld: cannot find -lubsan: No such file or directory
bruh
bruh the IOAPIC is being stupid
it registers the GSI for GPEs as level triggered and active high
as the MADT entry says GSI9 (the one for the GPE) should be
it hangs as if the opposite was set
the values I set are correct in my ioapic code
as in, I don't set the registers to anything invalid
there isn't a dumb isa irq redirect is there?
or some other thing changing it like that
I print the values after processing the Isa redirect stuff
In the madt
gpe finalize is when it hangs right?
if so maybe that's it
idk when it's supposed to be called
Ye
Wtf
Irq installation happens during early init
By that point you must have configured overrides
Or well, during uacpi_initialize I think
Overrides are configured
The acpl interrupt model thing isn't set until then
yeah but _PIC configures the firmware to actually do the thing
*acpi
try applying different polarity and triggering
just willy nilly
whichever one works
if that works we'll know ur just not parsing it correctly
the log is right before I set the polarity/trigger mdoe
*mode
in the I/O APIC code
// Set vector info.
if (vector)
{
printf("GSI %d is of polarity %s and trigger mode %s\n", gsi, polarity == PolarityActiveHigh ? "active-high" : "active-low", tm == TriggerModeEdgeSensitive ? "edge-sensitive" : "level-sensitive");
entry |= (vector&0xff);
set_bit_to(&entry, 13, polarity);
set_bit_to(&entry, 15, tm);
}```
before that, it sets polarity and tm are set to the proper values in the I/O APIC code
static void set_bit_to(uint64_t* val, uint8_t bit, bool to)
{
if (to)
*val |= BIT(bit);
else
*val &= ~BIT(bit);
}```
no like
the value of the bits
if polarity == PolarityActiveHigh is what it will be seen as by ioapic
typedef enum ioapic_trigger_mode
{
TriggerModeEdgeSensitive = 0,
TriggerModeLevelSensitive = 1,
} ioapic_trigger_mode;
typedef enum ioapic_polarity
{
PolarityActiveHigh,
PolarityActiveLow,
} ioapic_polarity;```
I highly doubt that has anything to do with this but ok I'll try
I mean if clangd says so
OBOS_STATIC_ASSERT(PolarityActiveHigh == 0, "tf?");
this static assertion doesn't fail
and when I check in qemu with info pic
the values match
yeah idk
but u have the same hang on multiple pieces of hw
where e.g. pmos doesnt hang
so that makes me suspicious
maybe my ioapic code is good, but my ISR is somehow bad
maybe but other interrupts work
in qemu?
didnt it hang before u could get even 1
what did you change?
nothing
im confused
same
how do u know u get a gpe irq
logs
so u get a gpe irq
yes
- GPE enabled
- GPE IRQ
- hang
yes
of what
some random ass spinlock idk
bruh
I added some logs related to that
to confirm
it's a spinlock which is allocated on the kernel heap
so probably uacpi's
but it might not be
write_gpe happens under a spinlock
so if you're calling into uacpi with uacpi spinlocks held its your bug
well it's a fucking GPE
spinlocks are supposed to disable interrutps
I need to call into uacpi don't I
well for me, they raise IRQL to IRQL_DISPATCH
which is < IRQL_GPE
what does this mean
you can't get preempted by the scheduler with a spinlock held
your irq handler can call into uacpi even when uacpi locks a spinlock?
thats a bug ofc
but you can get interrupted by GPEs for example
since IRQL_GPE > IRQL_DISPATCH
what did u expect lol
shi idrk
uacpi does
lock_spinlock(idk)
enable_gpe(); < u get a GPE irq here
unlock_spinlock()
ofc this wont work
maybe the reason it worked before for me was because it was before uacpi's thread safety thing
are you reading and writing as uint32_t's?
you kinda have to, so yes
nah nvm we figured it out, his ioapic is correct
GPE should be relatively low priority
(asking just to be sure)
there is no other way lol
write it as u128
funny how modifying one header irq/irql.h causes 107 files to be rebuilt
and modifying int.h causes the entire project to be rebuilt
ok
we should see if obos suspend is superior
ok it boots now
I'm going to test that in a bit
i'm am
a warning log caught my eye
whats the warning
something in the IRQ interface
[ WARN ] register_irq_vector: IRQ object 0xwhatever (IRQ Vector 1) does not have a move callback, and was moved```
what does that even mean
it was moved to a different IRQ vector

there is a callback in the IRQ object that is called when that happens
no but why
idk I wrote this code 7 months ago
under which conditions do u move it
iirc it's when a new IRQ object is made, that disallows the IRQ to be shared, requests a specific vector to be allocated for that IRQ object
if that makes sense
yes
@white mulch could you test this obos iso, it might fix the hang you experienced
also @proper trellis if you could test it, since you were also seeing a crash
does suspend and stuff work now?
this post is sponsored by your daily obos regression
cursor on screen
key press
blank screen
key press
panic cant find /usr/bin/bash
that means it worked
I think
it's definitely supposed to panic at the end because I didn't put bash in this initrd
and I have the init program set to bash 
is this with uacpi 1.0?
yes
won't work because panic

it's accessing nullptr in the acpi nvs saving code
if (entry->type == ULTRA_MEMORY_TYPE_NVS)
{
saved_nvs[nvs_index].region_address = Arch_MapToHHDM(entry->physical_address);
saved_nvs[nvs_index].size = entry->size;
saved_nvs[nvs_index].saved_region = OBOS_NonPagedPoolAllocator->Allocate(OBOS_NonPagedPoolAllocator,
saved_nvs[nvs_index].size,
nullptr);
memcpy(saved_nvs[nvs_index].saved_region, saved_nvs[nvs_index].region_address, saved_nvs[nvs_index].size);
nvs_index++;
}
uh oh
it PFs in that memcpy
noo
and rdi is zero on page fault
allocator bug?
and rdi is the allocated memory...
likely OOM
Bruh
ok it was an allocator bug
very subtle
the allocator can only allocate up to 4G
I accidentally checked nBytes > (4*1024*1024)
instead of nBytes > (4*1024*1024*1024)
ah shit
wake from suspend broke

💀
Time for triple fault debugging
yes
F
let me make sure it still works on the laptop
Inb4 regressed
Is that where it dies
I mean it has been broken for a long time
Long before suspend it hangs
F
Suspend works on the laptop
Ill try
thanks
ok thanks
obos tries to do ecdt init before namespace load apparently
💀
so yeah that explains it, there is nothing in the namespace at that point except the predefined ones
Oberrow what were you thinking
silly me
@white mulch can you try this
it will probably still hang
but it at least will initialize the EC properly with the ECDT
ah shit

ok thanks for testing
I'll be back when I fix the pf
0xffffffff800a7367: Mm_AgingPRA at /home/oberrow/Code/obos/src/oboskrnl/mm/aging.c:89 (discriminator 7)```
fuck this shit
REMOVE_WORKINGSET_PAGE_NODE(ctx->referenced, node);```
meanwhile line 89
which means memory corruption
I got a good idea to speed up testing on this laptop, maybe I can set up my raspi5 in device mode and make it emulate an usb stick out of a folder shared from my main pc or smth
you can do that
@white mulch could you test this
lol
like soundboards but in text
actually I don't think I can
the pi needs power over usbc and I don't have any kind of other power supply that could supply 5v 3A over gpio
sure
thanks
woah dude thats so cool
qwinci is typing...
it doesn't fault anymore but it hangs after the "could not make device wake-capable"
no gpe enable messages or anything
did it log anything like "lock is contended"
no
did u figure it out
Uhh I think I made it worse
anyway where was I last
fixing bugs with obos is getting boring
I'm sure qwinci's bug will end up fixing itself eventually
I couldn't be bothered to do that atm
okay
just let me go to the future when I actually port mesa and take my code from then
so I don't have to do it now
Just become astral
obos will become astral fork
Letsgo
wtf is wrong with u virtualbox
sudo rmmod kvm_intel (or whatever the one for amd is if you have amd)
what if I want kvm back
then you modprobe kvm_intel
sudo modprobe kvm_intel
I am not sure why it suddenly started complaining about that tho, I think it worked just fine in 6.11 even with the kvm module loaded
not at the same time but like if you had no kvm vm's running it would work
--- 192.168.100.2 statistics ---
16699 packets transmitted, 16618 packets received, 0% unanswered (0 extra)
rtt min/avg/max/std-dev = 0.205/1.792/5.565/0.632 ms```
I have fixed a bug with the r8169 driver
that's the result of arping
sudo arping 192.168.100.2 -I enp0s25 -W 0.005```
ok time to do this
ig
oh btw how do I work with the "time to live" field of the ipv4 header
theoretically, IPv4 packet reception should be implemented now
I do some basic size checks on the frame
so at the UDP layer of my net stack
I kinda have no idea what to do with my newly received packet
obos_status Net_UDPReceiveFrame(frame* what, frame* raw_frame)
{
OBOS_UNUSED(raw_frame);
udp_header* hdr = (void*)what->base;
// TODO: Checksum validation
if (be16_to_host(hdr->length) > what->sz)
{
OBOS_Warning("On NIC %02x:%02x:%02x:%02x:%02x:%02x: Received UDP packet has invalid packet size (NOTE: Buffer overflow). Dropping packet.\n",
what->source_mac_address[0], what->source_mac_address[1], what->source_mac_address[2],
what->source_mac_address[3], what->source_mac_address[4], what->source_mac_address[5]
);
return OBOS_STATUS_INVALID_HEADER;
}
return OBOS_STATUS_SUCCESS;
}```
I'm wondering whether I should just put this into some sort of queue
then when someone wants to receive from port n
they look into the packet queue for port n, and pop the first entry
although, a packet isn't actually removed from the queue until it's refcount is zero
there will be a "base refcount" for each queue
this refcount is incremented on each bind() call
if one recvs a packet, the other would miss that packet
I always assumed that only 1 program can be accessing a single port
otherwise
through a simple test with nc
that seems not to be the case
at least with UDP
ah wait
nvm
i think the norm for when you do multiple on one port is to split load among processes, no?
maybe im wrong idk
doesn't seem like it
in fact, in my test with nc
with two instances of nc -u 192.168.100.2 -l -p 32768
and on the other side
I had nc -u 192.168.100.0 32768
when I sent data here
linux would only show those packets to the first instance of this command started
until I closed that instance, then all future packets went to the other instance of nc
the other way around
if I had multiple nc -u 192.168.100.2 32768 opened
any other instances simply died if I tried sending anything
only the first instance worked
so basically, the first to bind a udp port is the one that "owns" it
it seems as if the host in this case sent destination unreachable
the first packet is from a 2nd instance of nc -u 192.168.100.2 32768
idk why but I feel like having:
udp_packet_queue Net_UDPQueues[0x10000];```
for each respective UDP port
sizeof(udp_packet_queue) will probably end up being pretty damn big
yeah that won't work I'm stupid
ah nvm it could
I keep forgetting how UDP works
there will be an RB-tree or hashmap of UDP queues
each udp_queue will have the actual queue in it, as well as an rw-lock, destination port number, and a struct process specifying the owner of the queue
I think it's safe to ignore source port in UDP packets
my kernel doesn't really care where it came from, as long is it was directed toward the kernel
I just wrote a long comment in one of obos' network stack's headers explaining how IP routing works
at least, what my understanding of it is
that's what I have so far
nic_data is just a struct
typedef struct ip_table_entry {
ip_addr address;
uint8_t subnet_mask;
LIST_NODE(ip_table, struct ip_table_entry) node;
} ip_table_entry;
typedef LIST_HEAD(ip_table, ip_table_entry) ip_table;
LIST_PROTOTYPE(ip_table, ip_table_entry, node);
// ...
typedef struct address_table_entry {
ip_addr addr;
mac_address phys;
RB_ENTRY(address_table_entry) node;
} address_table_entry;
typedef RB_HEAD(address_table, address_table_entry) address_table;
RB_PROTOTYPE(address_table, address_table_entry, node, cmp_address_table_entry);
// ...
typedef struct nic_data {
ip_table table;
address_table_entry* gateway_phys;
ip_table_entry* gateway_entry;
address_table address_to_phys;
vnode *interface;
mac_address physical_address;
} nic_data;```
address_table is a map of ip addresses to MAC addresses corresponding to that IP address
so when the kernel makes an ARP request on an interface, it caches the MAC address in the nic_data struct if it gets a reply
I'm going to need a way to remove an entry from that cache
some sort of syscall to do so
hopefully this all isn't overthought
Time to Live: 8 bits
This field indicates the maximum time the datagram is allowed to
remain in the internet system. If this field contains the value
zero, then the datagram must be destroyed. This field is modified
in internet header processing. The time is measured in units of
seconds, but since every module that processes a datagram must
decrease the TTL by at least one even if it process the datagram in
less than a second, the TTL must be thought of only as an upper
bound on the time a datagram may exist. The intention is to cause
undeliverable datagrams to be discarded, and to bound the maximum
datagram lifetime.```
from the IPv4 spec thingy
basically when I receive an IPv4 packet:
- record start timestamp
- if I'm forwarding a packet, the end timestamp is set to right before I remake the IPv4 packet, but after I have resolved the destination MAC address. I do
end-start, then convert that to seconds, and subtract that from time to live, discarding the packet if time to live <= 0. (Do I need to send an ICMP message here?) - otherwise I just process the packet normally because I couldn't be bothered to look at time to live otherwise
I was capturing my wifi interface
and I came across a restarted device
it sent an ARP request on each IP address on the subnet
afaics linux does not care about the time it took to process the packet and always decrements ttl by 1
interesting
netbsd probably does the right thing since it has net in the name y'know /j
the comment in linux also says that you need to send an icmp control message if the ttl reaches 0 ```
/*
* According to the RFC, we must first decrease the TTL field. If
* that reaches zero, we must reply an ICMP control message telling
* that the packet's lifetime expired.
*/
if (ip_hdr(skb)->ttl <= 1)
goto too_many_hops;
good to know
since linux does it, it's probably correct (in a way?)
since linux is used in a lot of routers, afaik
i'd imagine it does this under the assumption that no packet takes >1 second to process
I wonder what "process" even means here
does it just mean to receive the packet, or does it include the time it takes to find out the destination MAC address if forwarding
the latter can technically take more than a second
i don't think finding the destination mac is gonna take >1 second
since that's always done on the local network
true
unless you have an extremely lossy link ig
8 bits/s internet
I just committed these changes
god willing, I will do some of this IP routing stuff tomorrow
and after that, UDP packet reception
which should be as shrimple as:
- finding the proper
ip_table_entryfor the destination address - adding it to the received packet queue for the destination port
which includes changing my ARP code a bit
before, it just assumed the IP address was in interface_vnode->data (data is a uint64_t)
which will become an invalid assumption
after I implement this
I would need to change the code such that it looks for the requested address in each ip_table_entry of the interface
I think I will have my own syscalls and programs to deal with configuring internet routing
which includes my own DHCP implementation, which will go in userland
hopefully DHCP won't be too hard
thankfully I chose the route of making my network stack, this is kinda fun
(until I stop ignoring TCP)
for receiving packets, you can ignore it, since all its use is before it gets to the destination, so you as the receiving part can ignore it, if it's invalid the router will discard it anyways nvm i was wrong
for sending, just pick a default value, linux chose 64 iirc, which seems sane
idk if you did look it up but if not, wikipedia is enough
well nvm it was actually discussed, i just didnt read the other messages
I was exclusively looking at the spec
udp_queue *queue = NetH_GetUDPQueueForPort(ent_, hdr->dest_port, false);
if (!queue)
{
// TODO: Send destination unreachable (port unreachable) on ICMP.
NetH_ReleaseSharedBuffer(what->base);
return OBOS_STATUS_NOT_FOUND;
}
Core_RwLockAcquire(&queue->lock, false);
frame* new_frame = OBOS_KernelAllocator->ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(frame), nullptr);
*new_frame = *what;
new_frame->buff += sizeof(*hdr);
new_frame->sz = hdr->length;
LIST_APPEND(frame_queue, &queue->queue, new_frame);```
it was pretty simple
oops just found a bug there (forgot to release the lock)
udp_queue *queue = NetH_GetUDPQueueForPort(ent_, hdr->dest_port, false);
if (!queue)
{
// TODO: Send destination unreachable (port unreachable) on ICMP.
NetH_ReleaseSharedBuffer(what->base);
return OBOS_STATUS_NOT_FOUND;
}
frame* new_frame = OBOS_KernelAllocator->ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(frame), nullptr);
*new_frame = *what;
new_frame->buff += sizeof(*hdr);
new_frame->sz = hdr->length;
Core_RwLockAcquire(&queue->lock, false);
LIST_APPEND(frame_queue, &queue->queue, new_frame);
Core_RwLockRelease(&queue->lock, false);```
ok so theroetically receiving a UDP packet is as easy as binding yourself to the queue NetH_GetUDPQueueForPort(ip_table_entry, port, true);
then waiting on the event object that is set on each UDP packet's arrival
then you read however many packets you like
by popping from the head of the queue
then you use the frame from the queue and copy it into your buffer
then you call NetH_ReleaseSharedBuffer(frame->base);
and you're done
wtf is happening
the kernel has suddenly started switching IP packets and ARP packets
the host sends my laptop (the client) a UDP packet
it thinks it's ARP
both when I print it
and when it goes to dispatch it
and when I arping the laptop
it thinks it's getting an IPv4 packet
and this only happens sometimes- ah shit
memory corruption

now it seems like it thinks all packets
are ARP

ARPOS
local man forgets to convert UDP header field from big endian to host endian
just run it on a big endian machine and then suddenly these problems go away 
I do have an m68k port 
but no NIC driver for it (yet)
hmm why is my kernel sending packets in the wrong direction
udp packet in question:
it's sending a packet to the current NIC's mac
and saying the source is the destination's source
that makes no sense
wait I'm stupid
bro wtf
my kernel is fucking
idefk
at one point
by some fucking miracle
it does a use after free
Always back to memory bugs
all I know rn is that it's in the network stack
except the stack trace is doing NOTHING
it literally ends at a call to LIST_REMOVE
LIST_REMOVE(frame_queue, ..., ...);
and there are only two calls to that macro in the net stack
both of which
there cannot be a use-after-free
LIST_REMOVE(frame_queue, &frames, data);
OBOS_KernelAllocator->Free(OBOS_KernelAllocator, data, sizeof(*data));```
unless the compiler reorders these two calls 
wtf
LIST_REMOVE(frame_queue, &frames, data);
asm ("" : : :"memory");
OBOS_KernelAllocator->Free(OBOS_KernelAllocator, data, sizeof(*data));```
I put a compiler memory barrier
and it works

lmao
just fixed a bug where you could crash obos by sending it a packet that's 170 bytes long
(170 = 0xaa, I had an assert in free() checking for nBytes==0xaa to make sure no one does a double free of an object, it just backfired)
I made some dumb echo server in kernel-mode
to test UDP reception and transmission
and it works, almost
I have found a pattern
the kernel always echoes back 8 more bytes than there should be
this is false btw
if you're sending a reply to that host, you need to set reply.src_port to received.dest_port and reply.dest_port to received.src_port
the extra 8 bytes in the header are from the sizeof(udp_header)
so that's fine...
the problem is
I was forgetting to subtract that
in the received packet thing
frame* new_frame = OBOS_KernelAllocator->ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(frame), nullptr);
*new_frame = *what;
new_frame->buff += sizeof(*hdr);
- new_frame->sz = be16_to_host(hdr->length);
+ new_frame->sz = be16_to_host(hdr->length) - sizeof(*hdr);```
I decided to test obos' network stack on a real network
to no avail
no packets are received
no packets are transmitted
arping the IP address I assigned it does nothing
perhaps I just need to do something in my router
anyway, I just pushed all the code I've written today
I was able to get a response over the network
but only if I disabled IPv4 packet forwarding
hello
agian
sleep
sleep
cant
go in your bed then
this means that the kernel is stable enough to handle all these packets*
*after enough packets it starts to die
and by die I mean the latency becomes really high
Even worked on my phone
One problem I am observing is use after frees
I think I know why
After a few hundred packets received from the network
It crashes
Which isn't terrible
I mean who needs more than a few hundred packets anyway
the progress is cool though
For reference this is after ~5 minutes
Of packets
And crashing after 5 minutes worth of packets because of memory corruption isn't optimal
however, I suspect this is not an allocator bug, and instead just plain memory corruption
in the network stack
I suspect this is because I was forgetting to reference a buffer in the data_ready callback of the network stack
and sometimes multiple packets are referenced by this buffer
since data_ready can mean multiple packets are ready
or just one
so:
receives two frames, and reports two frames are ready in data_ready
first frame processed, but the buffer's refcount is zero on entry, so when the frame is finally finished processing, and the last call of NetH_ReleaseSharedBuffer happens in Net_IPReceiveFrame, the buffer is freed, even though it is still referenced
next frame: use after free, as we never referenced the shared buffer in 'data_ready'```
just found a bug related to certain page faults
in the network stack
basically, I would use the paged pool allocator for memory that could be used at IRQL > DISPATCH
which is invalid in my kernel, because of demand paging
and demand paging means accessing it the first time means a page fault
which is the specific problem
now my solution is to temporarily lower the irql before doing memcpying into a buffer
feel like the solution is to have a function to "pin" pages to prevent them being paged out when theyre to be used for io
i think windows does that with MDLs?
yes I am going to do that
that is on my todo list
and so is the rewrite of my IO system
mood tbh
huh what is "redirect for host"
never heard of that tbh
the kernel is starting to die
At one point it starts to die because of a bunch of use after frees
It seems
And because of the frame backlog
i.e., there are so many pending frames the kernel starts to vanish
From the network
Until it finally crashes under the load
This time it could withstand a lot more packets, at least
Unplug the life support
kasan 
I broke that in a recent obos update
I plan to do DHCP soon
Should I write my client in userspace
Or kernel space
And just have some syscall to do DHCP and configure the interface's tables
Oh btw how do I know the subnet when I broadcast DHCPDISCOVER
I think linux mostly does DHCP in userspace
why would you need to know it? you only need to set the op/htype/hlen/xid fields of the dhcp header for the discover packet (along with the options to specify the msg type and parameter request list with whatever extra info you want like the subnet mask or dns server)
