#OBOS (not vibecoded)
1 messages · Page 23 of 1
E.g. Managarm and astral just shutdown by doing uacp_kernel_schedule_work
but if the registers don't get saved then it might cause issues when you want to resume that thread after the wake?
I can just suspend in a throwaway thread
actually no
I think when I wake up from sleep
Ehh idk
yeah I think I should just do this
I think Linux invokes the actual sleep from an asm stub to preserve the regs?
and I enforce that thread to run on the bsp
then when I wake up from sleep
I can just exit the thread
to continue from somewhere else
ig that would work too
Idk I haven't looked at it in depth
a throwaway thread was just the first idea that I had so I went with that (and its nicer with all the c++ stuff that I have)
Do it on the thread that requested shutdown, preserve regs, do actual enter_sleep
Also
Dont forget to quiesce other CPUs
Its probably ub not to
Just ipi and make it cli hlt in the handler
yeah ok
I do it on panic and shutdown
Oh
and reboot
what does doing it on shutdown or reboot gain tho
if the cpu is going to be reset anyway
void Sys_Reboot()
{
OBOSS_HaltCPUs();
uacpi_reboot();
while(1)
asm volatile("");
}
void Sys_Shutdown()
{
OBOS_Log("oboskrnl: Shutdown requested.\n");
OBOSS_HaltCPUs();
// We're at IRQL_DISPATCH which should probably be enough for prepare for sleep state.
uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5);
UACPI_ARCH_DISABLE_INTERRUPTS();
uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S5);
while(1)
asm volatile("");
}```
the forever loops are because it might take a bit for the shutdown/reboot to actually happen
past whatever uacpi's timeout is
(I have observed that on real hw)
I think some hw might just hang if u don't
interesting....
ah
more than 10 seconds? lol
my computer sometimes hangs on shutdown
And how do u even shutdown if your other CPUs still do interrupts and talk to hw lol
It would explode
I just do that lol
I wonder if it could have anything to do with that
Yes
it would happen on windows and linux
idr if obos had that problem
if not then obos > windows and linux
Well they probably also shutdown individual devices and run other aml
yeah
but anyway
I have made a small change to the smp trampoline
so that the kernel tells it where to jump to after cpu initialization
Inb4 it thinks its a resume from suspend when first booting
Causing obos to shit itself
lol
nah it worked fine
diff --git a/src/oboskrnl/arch/x86_64/smp.asm b/src/oboskrnl/arch/x86_64/smp.asm
index 24cb3e4..0053f09 100644
--- a/src/oboskrnl/arch/x86_64/smp.asm
+++ b/src/oboskrnl/arch/x86_64/smp.asm
@@ -12,6 +12,10 @@ global Arch_SMPTrampolineCPULocalPtr:data hidden
section .pageable.data
+extern Arch_APEntry
+global Arch_SMPTrampolineWakeLocation
+Arch_SMPTrampolineWakeLocation: dq Arch_APEntry
+
Arch_SMPTrampolineStart:
bits 16
real_mode:
@@ -84,12 +88,9 @@ reload_cs_addr: equ $-Arch_SMPTrampolineStart
; Load RSP.
mov rsp, [Arch_SMPTrampolineRSP-Arch_SMPTrampolineStart]
-extern Arch_APEntry
-
; Call AP initialization code.
mov rdi, [Arch_SMPTrampolineCPULocalPtr-Arch_SMPTrampolineStart]
- mov rax, Arch_APEntry
- call rax
+ call [Arch_SMPTrampolineWakeLocation]
Arch_SMPTrampolineEnd:
section .text
; All of these CPUID bits are in CPUID.07H.0H:EBX```
that's all it was
obos_status OBOS_Suspend();
extern uint32_t OBOSS_WakeVector32;
extern uint64_t OBOSS_WakeVector64;
extern OBOS_WEAK obos_status OBOSS_PrepareWakeVector();```
nvm
Will you also supply a 64 bit vector
I changed that
obos_status OBOS_Suspend();
#define NO_WAKEVECTOR UINT32_MAX
extern uint32_t OBOSS_WakeVector;
extern OBOS_WEAK obos_status OBOSS_PrepareWakeVector();```
Why
idk what a protecte mode entry is
* 'addr64' is the protected mode entry-point address
because my smp trampoline sits at 0x0
What the fuck
and I don't feel like changing that and seeing what happens
lmao
I have the barebones for suspend implemented
but no wake related things are called yet
is the wake code called
i mean its obos so i trust u
bool OBOS_WokeFromSuspend;
static void suspend_impl()
{
if (OBOS_WokeFromSuspend)
{
uacpi_prepare_for_wake_from_sleep_state(UACPI_SLEEP_STATE_S3);
UACPI_ARCH_ENABLE_INTERRUPTS();
uacpi_wake_from_sleep_state(UACPI_SLEEP_STATE_S3);
OBOS_WokeFromSuspend = false;
CoreH_ThreadReady(suspended_thread);
Core_ExitCurrentThread();
}
uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S3);
UACPI_ARCH_DISABLE_INTERRUPTS();
// good night computer.
uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S3);
OBOS_UNREACHABLE;
}```
suspend_impl is the entry of the suspend worker thread
it's entered at IRQL 2
(Dispatch)
so it cannot yield
so the idea is that
i mean this aint even cursed
the arch's wake from suspend trampoline
will just switch to that thread
but the scheduler's structs still think that
it is at the entry
with OBOS_WokeFromSuspend set to true
so it wakes from suspend
kinda cursed
nah not cursed
hmm
anyway I'm now gonna implement the arch side of suspend
wake.c under arch/x86_64
maybe its cursed in the sense that this is some other random thread
@real pecan the gpe-related functions in uacpi take in an index, can this be anything unique per gpe device, or do I need to find it some way
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_gpe_enable_for_wake(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_gpe_disable_for_wake(
uacpi_namespace_node *gpe_device, uacpi_u16 idx
))```
idx
what do I pass
oh just null
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_gpe_setup_for_wake(
uacpi_namespace_node *gpe_device, uacpi_u16 idx,
uacpi_namespace_node *wake_device
))```
so would I first call this
either null or just the _GPE node
then uacpi_gpe_enable_for_wake
if I pass null does it assume the latter?
oh wait I get it now
static void set_wake_vectors()
{
uacpi_gpe_setup_for_wake(nullptr, 0, nullptr);
uacpi_gpe_enable_for_wake(nullptr, UACPI_FIXED_EVENT_POWER_BUTTON);
}```
I think I would do that to make the power button wake me
yeah
and is this valid?
no
static void set_wake_vectors()
{
uacpi_gpe_setup_for_wake(nullptr, 0, nullptr);
uacpi_gpe_enable_for_wake(nullptr, 0);
}```
what about this
wtf
well you said idx can be null
* NOTE: 'gpe_device' may be null for GPEs managed by \_GPE
and you also said that
i never said anything about the index
what do I pass to idx
/home/oberrow/Code/obos/src/oboskrnl/power/suspend.c:57:(.text+0x10f): undefined reference to `uacpi_gpe_setup_for_wake'```
uhhhh
Elixir Cross Referencer - source file of Linux (version v6.11.5). Browsed file: /drivers/acpi/scan.c
hmm what do we have here
ur supposed to figure out the gpe index of the device u want to enable for wake
then set it up for wake
thats it pretty much
ok
also what's up with this
lmao
/home/oberrow/x86_64-elf-tools/bin/../lib/gcc/x86_64-elf/13.2.0/../../../../x86_64-elf/bin/ld: src/oboskrnl/CMakeFiles/oboskrnl.dir/power/suspend.c.obj: in function `set_wake_vectors':
/home/oberrow/Code/obos/src/oboskrnl/power/suspend.c:57:(.text+0x10f): undefined reference to `uacpi_gpe_setup_for_wake'
/home/oberrow/x86_64-elf-tools/bin/../lib/gcc/x86_64-elf/13.2.0/../../../../x86_64-elf/bin/ld: /home/oberrow/Code/obos/src/oboskrnl/power/suspend.c:58:(.text+0x118): undefined reference to `uacpi_gpe_enable_for_wake'
oh
nvm not this
it will be enabled automatically when u prepare to sleep
u just tell it u want it enabled via setup_for_wake
yeah ok
// thanks infy
UACPI_ALWAYS_ERROR_FOR_REDUCED_HARDWARE(
uacpi_status uacpi_setup_gpe_for_wake(
uacpi_namespace_node *gpe_device, uacpi_u16 idx,
uacpi_namespace_node *wake_device
))
static void set_wake_vectors()
{
// uacpi_gpe_setup_for_wake
uacpi_setup_gpe_for_wake(/* TODO */);
}```
i have a pr open with fixes anyways ill get that in
@real pecan how do I find if a namespace node has a method in uacpi
linux seems to have acpi_has_method
I want something similar
if (!acpi_has_method(device->handle, "_PRW"))
return;```
yes
the object returned isn't refcounted or anything right
ok
reading linux source to find out the thing I need
instead of pinging infy for the 11th time today
my brain hurts
yes
its generally more useful to consult the source than me since ive never even implemented suspend
it seems to do something like
package = (union acpi_object *)buffer.pointer;```
buffer is an acpi_buffer
so I tried to replicate that in uacpi by evaluating the PRW object as linux did
in uacpi its just obj->package
acpi_buffer is what ACPICA uses to return anything from methods
its just an opaque data buffer
ok if I understood this right
if the first element is an integer
that's the gpe number
and the wakeup device is null
otherwise if it is a package
and that package's first element isn't a local reference
wait nvm
ignore that
if ((element->package.count < 2) ||
(element->package.elements[0].type !=
ACPI_TYPE_LOCAL_REFERENCE)
|| (element->package.elements[1].type != ACPI_TYPE_INTEGER))
goto out;```
otherwise if the first element of this package is also a package
why cant u just read the acpi spec
too much work\
in uacpi ACPI_TYPE_LOCAL_REFERENCE would just be a string that u would uacpi_namespace_node_resolve_from_aml_namepath
if (pkg->objects[0]->type == UACPI_OBJECT_INTEGER)
{
gpe_idx = pkg->objects[0]->integer;
gpe_dev = nullptr;
}
else if (pkg->objects[0]->type == UACPI_OBJECT_PACKAGE)
{
uacpi_package* pkg2 = pkg->objects[0]->package;
gpe_dev = ;
gpe_idx = pkg2->objects[1]->integer;
}```
in the 2nd branch, I must set gpe_dev, which is a namespace node, to the pkg2->objects[0]
but idk how because that is a uacpi_object
what
u mean this case DeviceName // Reference?
yes
did u just ignore what i sent above
uacpi_namespace_node_resolve_from_aml_namepath
np
and I assume a string behind the scenes is a uacpi_buffer
if (pkg->objects[0]->type == UACPI_OBJECT_INTEGER)
{
gpe_idx = pkg->objects[0]->integer;
gpe_dev = nullptr;
}
else if (pkg->objects[0]->type == UACPI_OBJECT_PACKAGE)
{
uacpi_package* pkg2 = pkg->objects[0]->package;
gpe_dev = uacpi_namespace_node_resolve_from_aml_namepath(node, pkg2->objects[0]->buffer->text);
gpe_idx = pkg2->objects[1]->integer;
}
else
{
OBOS_UNREACHABLE;
}```
before that I also make sure that device can wake me in S3
besically yes if u dont do any error checking at all
this is going to be the new interface btw #1217009725711847465 message
you wont be able to access shit like that anymore
well that is in the future
yes
rn I need something down
btw
the second branch is only relevant for non x86
or well
probably some very very niche x86
did u suspend qemu
and it triple faults
yes
probably
how did u wake it up
sendkey a
interesting
lol
yet sendkey triple faults it
does any of the wake code ever get executed?
good question
also did you put the wake vector at a non zero address? because the facs doesn't allow zero as the wake address because it means invalid
uhh no lol
my trampoline is at phys 0
well yeah that's probably why lol
normal exception?
one that is expected
it was a page fault because the kernel needed to page something in
void VISIBLE32FLAT
handle_resume32(int status)
{
ASSERT32FLAT();
dprintf(1, "In 32bit resume\n");
if (status == 0xfe)
s3_resume();
// Must be a soft reboot - invoke a hard reboot.
tryReboot();
}
``` s3_resume returns early if the facs waking vector is zero and then it gets to tryReboot (this is on seabios)
oh cool
placing anything at 0 is a terrible idea ngl
now since it'd be too much work to make my smp trampoline be relocatable
I will just have some temp page
that jumps to address zero
hacky, but whatever
bruh
the smp trampoline assumes addresses off zero in many places
its not that hard to make a relocatable trampoline, you can use cs relative addressing and put the boot info at the end of the trampoline or whatever
doesn't change the fact that
I don't wanna
ok now it triple faults
which is better
lmao
werid stuff
I think the bios uses phys. zero as a scratch space
because when I am actually in the trampoline it's corrupted
but before I go to sleep it's not
phys zero is bios ivt
oh yeahhhhhhh
since I still don't feel like making my smp trampoline relocatable
what I'll do now is
keep a copy of the trampoline after the reset vector
and copy it to phys. 0
this guy will do anything but move his goddamn trampoline
at this point you would have already made it relocatable lol
Arch_ACPIWakeTrampoline:
bits 16
call $
pop ax
mov es, ax
mov si, es:.data-Arch_ACPIWakeTrampoline
mov di, 0
mov cx, Arch_SMPTrampolineEnd-Arch_SMPTrampolineStart
rep movsb
jmp 0x00:0x0000
Arch_ACPIWakeTrampoline_data:
times Arch_SMPTrampolineEnd-Arch_SMPTrampolineStart db 0```
bam
cursed
Yes.
🤢
this code is cursed
but I will not look past at it past today
ok now it crashes in a different way
instead of it triple faulting because of an invalid opcode
nvm
bro wtf is up with the cpu
how is it at
long mode
where is the gdt????
GDT= 0000000000000000 00000000```
did u expect registers to survive
hi nyauxmaster
hi
is your day good
yes indeed
im eta'ing scheduling in maybe 3-5 days depending on what memes ill encounter :)
W
indeed
I'm tryna setup bochs
exactly
bruh how do I use bochs
Message: ROM: couldn't open ROM image file '/usr/share/bochs/BIOS-bochs-latest'.
u need a config
yuh huh
thanks
np
gn
gn
nyaux nap%
wtf
why don't I have any BIOS rom
but I do have a vga bios
it is in the bochsbios package
life without apt-file
would be bad
Bochs build in Debian'/Ubuntu's repos is ... weird
U mean GNU/Linux/Debian/Ubuntu?
bochs debugger time
I just compiled mine from source on Ubuntu
as you should tbh
Fedora's repos were really nice
uacpi_namespace_node* prw = uacpi_namespace_node_find(node, "_PRW");
if (prw)
goto end;
lmao\
I was wondering where all the devices
that could wake the system were
why does qemu have no devices with PRW
and why can't bochs get past "Booting from hard disk"
without triple faulting
on kvm it just dies
KVM internal error. Suberror: 1```
yeah looks like it unconditionally causes a wakeup on ps2 keyboard and mouse press
obos try not to triple fault challenge
ok it stopped triple faulting
I think
now it's doing something different
unless
I think it's just executing zeroes
or the ivt
@real pecan I think I accidentally found a workaround to not being able to set the FACS reset vector to zero
if you set it to 0x800
it seems to actually throw me at address 0x0
implementation details of a specific bios
it's always going to 0x0
well yeah
I wasn't trying to do that
I found out by accident
wtf
at least if gdb isn't lying to me
I have two bps
one at 0x0
and one at the reset vector
the latter never gets hit
i mean print the value in facs
p g_uacpi_rt_ctx.facs->whatever
print in gdb as well
Bah
my compiled seabios no works :(
weird
it doesn't like hyper
@real pecan helppppppppp
seabios no working
idk figure it out

now it's not even building
on the 1.12-stable branch
finally
it booted
In resume (status=254)
In 32bit resume
table(50434146)=0x3ffe21f3 (via rsdt)
Found 4 cpu(s) max supported 4 cpu(s)
PCIe: using q35 mmconfig at 0xb0000000
Running option rom at c000:0003
Start SeaVGABIOS (version 1.16.3-debian-1.16.3-2)
VGABUILD: gcc: (Debian 13.2.0-7) 13.2.0 binutils: (GNU Binutils for Debian) 2.41
enter vga_post:
a=00000000 b=0000ffff c=00000000 d=0000ffff ds=0000 es=f000 ss=0000
si=00000000 di=000060c0 bp=00000000 sp=00000f36 cs=f000 ip=d004 f=0000
Jump to resume vector (1000)
There u go
well 0x1000 is the vector I wanted....
Does it not actually jump there
Sooo how are u not seeing it via grub
grub?
idk, it's quite weird
Probably some skill issue
Maybe its waiting on virtual 0x1000
Wdym yay
I now know I'm not jumping to arbitrary code
Big
now I just need to find out the reason for the triple fault
which I will do after a tiny bit
it's a gpe
bruh
53176: v=0d e=0012 i=0 cpl=0 IP=0008:00000000000fd089 pc=00000000000fd089 SP=0010:0000000000000000 env->regs[R_EAX]=0000000000000000
that ain't my code
i stole it
yeah it's because of my smp trampoline isn't it
indirectly
time to give in and write a relocatable smp trampoline
Wdym
basically
I was triple faulting because I was getting an irq in an AP when it was it was still in bios code
and the IVT was overwritten
lol
actually
I'll just assume it's at 0x1000 instead
@real pecan
IT WORKS
defgdsfudrhesfw\
I woke up from S3
static void on_wake()
{
for (volatile bool b = true; b; );
}```
I was able to get the state to the bare minimum to get something to print
gdb is being stoobid
idk why but my tss is broken
fixed
idk why but I must reinitialize the tss' segment on wake
I do now properly restart the cpu
but it's still not in a preferable state to yield to another thread
I am now gonna wake the other CPUs
bruh

I triple fault
check_exception old: 0xffffffff new 0xd
56719: v=0d e=0012 i=0 cpl=0 IP=0008:00000000000fd089 pc=00000000000fd089 SP=0010:0000000000000000 env->regs[R_EAX]=0000000000000000```
fixed
I now restart all CPUs
what's next is restarting the LAPIC timer
then I can finally switch back to whatever that thread was doing behind
check_exception old: 0xffffffff new 0xd
44433: v=0d e=0012 i=0 cpl=0 IP=0008:00000000000fd089 pc=00000000000fd089 SP=0010:0000000000000000 env->regs[R_EAX]=0000000000000000```
sigh
I tried restarting the lapic timer
for this to happen again
after syncing all CPUs to initialize their timers at the same time
it no longer triple faults
but now it crashes (best word to describe what just happened) when trying to switch to a new thread
@real pecan your wake from sleep state might be broken
I'll see once I actually fix this code
x to doubt

I will debug it after school
debug it at school
suspend school pc
Also a good idea
lol
So what I will do is bring debian livecd
Or just a debian installer
So that I can dd the iso
And I'll just debug at school
I need to push my code first thiugh
*though
win32 imager or fuse
Those need admin access, no?
not sure
Forgot to commit n'stuff
halt all cpus
everything hangs
no but it's unintentional
idk why it's happening
hm
it panics
but where are all the log sources?
oh
wait
it hangs while waiting for all CPUs to stop
which I think I know why
yeah
I also noticed that there is a slight (big) bug
the other CPUs restart fine
but they jump to some previous point of the thread they were running
since the thread contexts are not saved
so I'll need to do that
nah I'll just wait for the PR to be merged
I were thinking about this, one way could be that you save the rsp after the irq frame + current thread to somewhere within eg. the cpu struct and then when the ap wakes up after you have done all the lapic init and whatever you would set rsp to the saved rsp + pop regs + possibly swapgs + iretq (after first setting your current thread to the old thread)
and wait for all the cpus to have done that before actually proceeding with the sleep ofc
@real pecan
I fixed the bug
I can now restart the scheduler
damn it
it doesn't work well when it tries to run the uacpi code (but that's because of me)
why is that
some sorta irql bug
brb though
wait
it might actually have ran the uacpi code
@real pecan your uacpi code actually seemed to have not crashed
who would have thought 
also on an unrelated note would be funny if the acpi global lock would be contended and the wake aml would try to acquire it when the io-apic is reset (so no sci's) 
bro fuck this shit
HOWWWWWWWWWWWw
fixed
@real pecan something interesting is happening
after wake from suspend, the framebuffer stops working
I also observed that though I didn't look into it yet because all of the other annoying bugs that I have
anyway, first log message is before the suspend
and the rest are after I wake from suspend
probably the vga card is also reset or something
that's gonna be hard to tackle...
well on qemu it isn't that bad but on real hw however...
if that happens on real hw that is
yeah S3 leaves like everything dead
yeah that makes sense
ur supposed to reinit everything
when uGPU so I can reinit the GPU
well then what do I do?
linux/seabios code
I don't feel like brain damage
qemu has https://osdev.wiki/wiki/Bochs_VBE_Extensions tho and I have a feeling that configuring it + writing to the enable register might make it work again
though it would make sense to use some more portable mechanism if there is one
anyway yeah idk
I can just put a warning before suspend
its uncharted territory for me
OBOS_Warning("Note: Framebuffer might die\n");```
u should try on real hw
good idea
althought very large chance u will see a blank screen
I'll make it shutdown after wake from suspend
lol
so I can know if it worked
thats my stupid pc when it wakes for no reason
well does your PC use obos?
no way
LET THE SHITTY NT KERNEL DIE!!!!
REPLACE IT ALL WITH NYAYX~!!!!!!!!!!!
ummm
shutdown broke
f
just write a dri driver
this time it might be you
??
well
literally nothing changed
let me log stuff from wake from suspend
oberrow try not to deflect blame challenge
well it gets to uacpi code
oberrow try not to blame uacpi for every bug in his kernel insane challenge
it is
meanwhile I only have myself to blame
if you steal all your code from other projects you can blame the people that wrote it 
well yeah some of the sleep/wake/whatever stuff + looking how reference semantics work + gas read/write helpers, ig I could
though its more likely that its my own fault than the uacpi code's fault
lmao
kinda sounds like the entirety of uacpi
copying inline asm
well his stuff is c++
idk why but when running my kernel
use xfce like a real linux user
when ur kernel is so bad that when in a vm it causes the host system to die
go away

I mean I didn't copy the interpreter itself 
and I didn't ctrl c v any code because it wouldn't work ofc, I rewrote it in c++
#1230349543623757845 message
shit
I forgor to put the license
actually
if the license is in the file
would that count
oh infy!
it hangs in uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S5);
wtf
i mean that doesnt tell me anything
lol
regarding the framebuffer if I understood it right linux has some code that uses vga to set the video mode that it calls on wake https://github.com/torvalds/linux/blob/81983758430957d9a5cb3333fe324fd70cf63e7e/arch/x86/realmode/rm/wakemain.c#L84 (look at the files with this __videocard macro https://github.com/torvalds/linux/blob/81983758430957d9a5cb3333fe324fd70cf63e7e/arch/x86/boot/video.h#L81)
idk if this works on all gpus tho because at least newer intel igpus don't advertise themself as vga compatible
yeah I'll pass
for now at least
who needs a framebuffer
lol
instead of suspend
well luckily (or perhaps unluckily)
it doesn't happen when I don't suspend
omg
uacpi_kernel_stall
yields
well
something is utterly fucked
oh btw
@real pecan uacpi_kernel_stall might not be able to be used in uacpi_enter_sleep_state. if someone ever uses the hpet (or any external timer source for that matter) for stall/sleep, then it probably will break if PTS shutdown the timer source.
also shutdown does not work after waking from S5
it times out
it could be that I am missing something in my wake code
which is weird since I
uacpi_prepare_for_wake_from_sleep_state(UACPI_SLEEP_STATE_S3);
UACPI_ARCH_ENABLE_INTERRUPTS();
uacpi_wake_from_sleep_state(UACPI_SLEEP_STATE_S3);```
could be my skill issue though
since I do not put any devices to sleep
nor wake any devices up
but like
if you wrote the shit needed to the ports needed
then it should shutdown
and like this is qemu seabios
the most basic environment
weird
on ovmf it works
firmware fuckiness
KVM Internal Error 3
bru
how
i didnt even
do anything wrong 😭
i only yelled at my teammates
everyone does that in this game
probs had baby teammates
yea maybe one of my teammates reported me
rip bro
yeah I'm not very good at chess
same
tomorrow I hope on implementing the driver interface part of suspending
as now I shall sleep
and maybe working around this bug with shutdown
but before I sleep
I will test obos on one of my test subjects
suspend works
wake from suspend, not so much
Notify (PWRB, 0x02) // Device Wake
is ignored according to uacpi
twice, actually
Method (SIOH, 0, NotSerialized)
{
If (((WKRS == 0x02) && (WKRS != 0xFF))) {}
Else
{
If ((^SIO1.PMS1 & 0x08))
{
Notify (PS2K, 0x02) // Device Wake
Notify (PWRB, 0x02) // Device Wake
}
If ((^SIO1.PMS1 & 0x10))
{
Notify (PS2M, 0x02) // Device Wake
Notify (PWRB, 0x02) // Device Wake
}
}
}```
Method (PS2K._PRW, 0, NotSerialized) // _PRW: Power Resources for Wake
{
Return (GPRW (0x1B, 0x03))
}```
Name (PRWP, Package (0x02)
{
Zero,
Zero
})
Method (GPRW, 2, NotSerialized)
{
PRWP [Zero] = Arg0
Local0 = (SS1 << One)
Local0 |= (SS2 << 0x02)
Local0 |= (SS3 << 0x03)
Local0 |= (SS4 << 0x04)
If (((One << Arg1) & Local0))
{
PRWP [One] = Arg1
}
Else
{
Local0 >>= One
FindSetLeftBit (Local0, PRWP [One])
}
Return (PRWP) /* \PRWP */
}```
Name (SS1, Zero)
Name (SS2, Zero)
Name (SS3, Zero)
Name (SS4, One)```
wait
_S3 doesn't look like it exists on this PC
If (SS3)
{
Name (_S3, Package (0x04) // _S3_: S3 System State
{
0x05,
Zero,
Zero,
Zero
})
}```
acpi_namespace_node* s3 = uacpi_namespace_node_find(uacpi_namespace_root(), "_S3_");
if (!s3)
{
OBOS_Error("Firmware does not have the _S3 (suspend) sleep state\n");
return OBOS_STATUS_UNIMPLEMENTED; // bios does NOT support suspend.
}```
I will do that
this is quite weird
Acpica does it and it works fine, so no
this just means u dont hook an event listener using uacpi_install_notify_handler
Notify is basically a syscall from aml to kernel
I apparently need to implement D state shit for wake to work properly
#1217009725711847465 message
i might implement this stuff too into my kernel
to be honest
im unsure about much of what it does but
seems interesting
when i fix my page tables being fucked up and when i reach userland and have a bunch of unix programs running
that might be something id look into
ability to put your kernel to sleep and then resume
May be I'll try to implement it as well (after finishing with exams, and implementing working set...)
Since I'm going to be "done" soon enough
You guys will probably able to take my kernel as a reference when you do it
what did you have to do?
At the moment, it is the only kernel using uacpi that has some sort of suspend
Find sleep capable acpi namespace nodes
Put them into the required D state
Mark then as a wake GPE
*them
Then stop all CPUs
Then enter S3
On wake
Also make sure to set the wake vector
When you wake up you get put there
On the wake vector
In real mode
On the bsp
so you have to do all the initialisations again
Yes
Move any device back to the old D state
After entering long mode
Also you probably want to have driver specific wake and sleep functions which you call at respective times
You will need to restart the LAPIC timer
..or any hobby kernel with suspend at all
well given oberrow actually gets it to work properly
Other than framebuffer I should be able to get it working correctly
if u get it right fb should get restored on real hw as well
especially if u disable modern windows support via osi
uacpi_bulk_configure_interfaces(UACPI_INTERFACE_ACTION_DISABLE, UACPI_INTERFACE_KIND_VENDOR)
then re-enable only some shit like very old xp
aml will assume u dont have any drivers and do most stuff for u
or well, try to at least
Uncommon AML W
idk if qemu checks for it, probably not
Would be one of the first times that something in obos worked as intended on real hw but not qemu
also the bochs vbe stuff that I were thinking about didn't work for restoring the fb, idk what exactly qemu wants you to do to it
could just look at qemu source
actually I think I might know at least one possible reason, the pci bars get reset
lool
Oh ye
I could make some sort of hack
That looks for the fb in PCI bars
And just saves all BARS for them
just do info pci after resume
Then replace it later
and see what it says
yup
ideally what u should do in your drivers is when initing a pci bus, walk all devices, and look at their bars: if it'a non-zero bar, try to "claim" it aka allocate it out of unused memory. if that fails, allocate a new addres. Record the allocated/claimed address somewhere in a struct.
Then on resume just walk again and re-assign
thats how linux does it anyway
the irq fields aren't right either, ig you have to restore those too
Elixir Cross Referencer - source file of Linux (version v6.11.5). Browsed file: /drivers/pci/setup-res.c
->resource is an array of BARs
it tries to use whatever the bios put there
if that fails it manually allocates here https://elixir.bootlin.com/linux/v6.11.5/source/drivers/pci/setup-bus.c#L707
Elixir Cross Referencer - source file of Linux (version v6.11.5). Browsed file: /drivers/pci/setup-bus.c
at the very least u need a struct per pci devices where u keep the initial values of their bars
the device doesn't care about the irq field afaik? only the pin matters
and the pin is hardwired in the device iirc
ah yeah
so its basically only the bars + the usual stuff that you do when you setup a device anyway like enabling bus master
also getting bar sizes, but not bars for some reason
before suspend
after wake
so yeah
one of the vga BARs had the framebuffer
which is probably why the framebuffer died
what I'm thinking to do is why was suggested to me yesterday
but own most PCI devices by default
then drivers claim them later
I wonder what the difference between ovmf and seabios is
because with ovmf, qemu shutdowns after suspend
but seabios does not
with seabios it doesn't even log it with -d trace:qemu_system_shutdown_request
before suspend (on ovmf)
are you going to write an osdev.wiki article once you finish it? 
that might not even be a bad idea
I'm mostly interested in what needs to be done for pci devices
I gather everything else is the same
you save BARs and other config registers in teh PCi thing
probably includes MSI config
and other capabilities
you throw the device into some D state
you go onto the next device
on wake you restore everything and move the devices back to D0
also
there probably should be some driver-specific way to suspend a device
and vice versa
wtf
so your resume is broken on seabios?
lol
marker
also about the pci thing I am not sure what else do you need to do because I tried writing the bars back after suspend but it didn't change them at all (and -trace pci*) showed no writes at all
tldr: sleep is a huge pain lol
well you do call the _WAK stuff
and prepare for wake
might be needed
at this point I might as well import seabios
yeah I did that and then back to d0 after suspend for the wake capable devices (idk if you should do it for all devices tho)
also apparently my resume is broken on ovmf but not seabios 
rather the acpi spec is outright wrong here
or my computer's firmware made an oopsie
because _PRW > 3, so I think that just means 3 in this table
_S3D is 2
so I should enter D2
this device has no D2 state
rather that or I misunderstood the spec somewhere else
yeah no
there's no _PS2 method
_PRW is the deepest system state that it supports waking from
ye
that evaluated to
0xD, 0x4```
Method (_PRW, 0, NotSerialized) // _PRW: Power Resources for Wake
{
Return (GPRW (0x0D, 0x04))
}```
does it have a _S3W
nop
Method (GPRW, 2, NotSerialized)
{
PRWP [Zero] = Arg0
Local0 = (SS1 << One)
Local0 |= (SS2 << 0x02)
Local0 |= (SS3 << 0x03)
Local0 |= (SS4 << 0x04)
If (((One << Arg1) & Local0))
{
PRWP [One] = Arg1
}
Else
{
Local0 >>= One
FindSetLeftBit (Local0, PRWP [One])
}
Return (PRWP) /* \PRWP */
}```
then you can enter D2 or D3
it says that is _S3W is N/A, _S3D is 2, and _PRW is 3
then enter D2
unless I missed something
in the spec
oh yeah nvm
fucked firmware
but all other devices are the same
that support wake
and have _S3D
I hate acpi
I hate acpi
I hate acpi
I hate acpi
I hate acpi
Possible spam detected for user: oberrow. Please contact a moderator to be unmuted.
maybe if the D state just doesn't exist
I ignore it and move on to calling _PSW
or DSW
does the device have a _PS0/_PR0 method?
yes
it has _PS0
and _PS3
but not the required _PS2
and I just found another unrelated blob doing the same thing
actually the other blob isn't even for a computer that has S3
is there a _PR2? because there is the thing where if there is no explicit _PSx method then you are supposed to use the power resources to do the transition
guess I gotta do that then
and where do I find said power resources
_PRW?
_PRW contains the resources needed for the device to be able to wake the system
ah yeah ig you can do it using that + _PR0
but isn't PR0 for D state 0
and also I have no PR0 in that object
*device
only for fans

yeah but I were thinking about the fact that it said that you should turn off the resources that are no longer needed by the device
so like if there would be some resources needed in d0 but not in the wake state (or whatever state you explicitly put the device to) you'd turn those off if I understood it correctly
makes sense
but yeah idk what are you supposed to do in the case of your firmware
or add debug prints to linux code
though that would be kinda annoying
I don't feel like compiling the linux kernel
journalctl has nothin for me
thanks infy for making uacpi_object opaque /s
lmao
uacpi_object_get_package
use of undeclared identifier uacpi_package
read
an object array
is what it gives me
ok
bruh
uacpi_object_get_integer returns a status
and takes a pointer to the integer
yes??
safety ™️
what is it supposed to do if u give it a different type or a null pointer
uacpi is built onto the idea that all errors are propagated to the client and it on its own doesnt have the right to decide what to do with them
just made it use the new object api
so it doesnt have bullshit like uacpi_kernel_abort etc
good thing I noticed that you merged the PR before I wrote the D state code
otherwise I would've went to play minecraft for 43 days
and come back
lol
the 2nd value in _PRW is irrelevant for finding out the d state to put the device in when entering a sleep state
only snd/snw matter
with n being the sleep state
that you wanna enter
which basically makes the tables in the acpi spec for each
_SnD object
the same
since some parts of the table say I can enter one of two sleep states
I will by default choose the deepest
if that does not exist
I go a bit shallower
etc.
typedef enum d_state {
DSTATE_INVALID = -1,
DSTATE_0,
DSTATE_1,
DSTATE_2,
DSTATE_3HOT,
DSTATE_3COLD,
DSTATE_MAX = DSTATE_3COLD,
} d_state;
// if dry_run is true, then the function does not actually put the device into the state,
// but only checks if it would be able to and returns an apprioriate status.
obos_status OBOS_DeviceSleep(uacpi_namespace_node* dev, d_state new_state, bool dry_run);
obos_status OBOS_DeviceWake(uacpi_namespace_node* dev, d_state new_state, bool dry_run);
d_state OBOS_DeviceGetDStateForWake(uacpi_namespace_node* dev, uacpi_sleep_state state, obos_status* status);```
if (snw >= snd)
{
if (status)
*status = OBOS_STATUS_MISMATCH;
return DSTATE_INVALID;
}```
I wonder if it makes sense to have a check like this
because surely the deepest D state that the device can wake itself in
in sleep state n
is always deeper or equal than the shallowest state that the device can be in in sleep state n
if (snw <= DSTATE_2 && snd == UINT64_MAX)
{
nStates = 3;
avaliableStates[0] = DSTATE_2;
avaliableStates[1] = DSTATE_1;
avaliableStates[2] = DSTATE_0;
}
if (snd <= DSTATE_2 && snw == UINT64_MAX)
{
nStates = 1;
avaliableStates[0] = DSTATE_2;
}
if (snd == DSTATE_2 && (snw >= DSTATE_3HOT && snw != UINT64_MAX))
{
nStates = 3;
avaliableStates[0] = DSTATE_3COLD;
avaliableStates[1] = DSTATE_3HOT;
avaliableStates[2] = DSTATE_2;
}```
idk if I like this logic
I mean it probably works
but I wanna make it unreadable use less redundant checks
typedef enum d_state {
DSTATE_INVALID = -1,
DSTATE_0,
DSTATE_1,
DSTATE_2,
DSTATE_3HOT,
DSTATE_3COLD,
DSTATE_MAX = DSTATE_3COLD,
} d_state;
// if dry_run is true, then the function does not actually put the device into the state,
// but only checks if it would be able to and returns an apprioriate status.
OBOS_EXPORT obos_status OBOS_DeviceSetDState(uacpi_namespace_node* dev, d_state new_state, bool dry_run);
OBOS_EXPORT obos_status OBOS_DeviceHasDState(uacpi_namespace_node* dev, d_state state);
// Returns DSTATE_INVALID on error, or if the device does not need to be moved in another
// D state to wake us.
// Always check status to make sure.
OBOS_EXPORT d_state OBOS_DeviceGetDStateForWake(uacpi_namespace_node* dev, uacpi_sleep_state state, obos_status* status);```
