#uACPI - a portable and easy-to-integrate ACPI implementation

1 messages · Page 8 of 1

north holly
#

Make some sort of compatibility layer between acpica and uacpi

#

To make it easier to throw into the linux kernel

fiery turtle
#

maybe not thousands but hundreds definitely

vale isle
#

tbh if uACPI proves itself worthy (for hobby osdev it already has) i don't see why they wouldn't consider it

fiery turtle
#

yeah, maybe something simpler like reactos or some of the bsds could be a cool start

vale isle
#

yea exactly

#

reactos would be awesome

#

haiku is also a good target

fiery turtle
#

yeah

#

i've talked to the person from the reactos team before and they're interested in doing that

vale isle
fiery turtle
#

atm yes

vale isle
#

they probably have weird machines it would be beneficial for uacpi as well

#

getting tested on xp-era real hardware

fiery turtle
#

yeah

#

although just aml wise uacpi is tested against all publically available aml blobs atm

#

~350 machines

vale isle
#

anyhow uACPI is so cool I will definitely consider contributing after I use it in my OS

fiery turtle
#

well thank you

vale isle
leaden fox
fiery turtle
vale isle
#

would it help if I share my own devices AML

fiery turtle
#

so like 350 * ~15 tables

vale isle
#

ah

fiery turtle
#

sure, acpidump > dump.txt

vale isle
fiery turtle
vale isle
fiery turtle
vale isle
#

oki

fiery turtle
#

all of these blobs are fed to uacpi on every commit to the repo, so u will be part of the history forever

fiery turtle
#

yeah, the source repo is dead unfortunately so i had to fork it

vale isle
#

ah

fiery turtle
#

if they do revive it i will pr my downstream changes

median crest
#

Just slap a fat mutex around it and youre good to go

north holly
#

the beauty of the

🎉 *** U N I X P H I L O S O P H Y *** 🎉

sterile egret
north holly
#

I looked at the hw list and I found one of my test subjects on it

#

which is cool ig

#

how do I add my thing

fiery turtle
trim siren
vale isle
#

and how would i name the files?

fiery turtle
vale isle
fiery turtle
vale isle
#

it gives a url no?

fiery turtle
#

Hmm maybe

vale isle
#

ccp

#

omg my laptop has the chinese communist party

#

no i can't find that

#

this is the probe

#

there is no hwid anywhere

#

WAIT

#

there's this hwid

#

F7FA2

#

but that's much shorter

trim siren
#

maybe that probe= part of the url

#

nvm lol hwid is so short on the site

vale isle
#

i think their hwid stuff changed between the latest version of the acpidump repo

#

and the latest hw-probe

#

i wonder if it's some kind of hash

fiery turtle
#

Honestly if it's impossible to tell what it is, u can just put whatever random hash u want

vale isle
#

that F7FA2 seems legit

#

i'm putting that in

fiery turtle
#

Sounds good to me

vale isle
#

tho linux-hardware.org says it's generated from a hash that includes devices and a salt and mine isn't stock

#

i have a adata nvme ssd instead of whatever the default is

#

so literally only mine will generate this hwid

#

so it's absolutely useless

#

but anyhow

trim siren
vale isle
#

ping me when you review the PR

#

i'm not sure i did it correctly

#

biggest PR i ever did 😳

#

now i wonder if it's possible to easily dump these from windows

#

or I can use a live usb ig

fiery turtle
fiery turtle
sterile egret
fiery turtle
#

Well they're generated at runtime soo

fiery turtle
#

just <hash> is the disassembled dump

hollow elm
sterile egret
#

I’ve done a little work, which I’ve been meaning to continue at some point, to figure out the first machines/motherboards that shipped with ACPI

#

I figure those are likely to have eldritch horrors and would stress test uACPI nicely ultrameme

fiery turtle
#

damn yeah that would be cool to know

rustic compass
#

it would be cool if uacpi supports a table dump to heap function

fiery turtle
#

why do u want that?

rustic compass
#

it would aleviate the need to expose acpi data to other programms and could help in debugging if you can get the acpi data "early" in the boot process

#

just a idea

fiery turtle
#

But u can just do that yourself, get the table, allocate a heap buffer, memcpy it?

rustic compass
#

does a acpi dump contain personal information of some kind?
yea, is the dump format specified somewhere?

fiery turtle
#

Other than that no

fiery turtle
rustic compass
#

i was thinking about once my os gets somewhere to auto dump acpi on a new install and push it to the repo

fiery turtle
#

Sure sounds cool if the user is okay with sharing that sort of data

rustic compass
#

does acpi contain hardware ids or other indentifications that can be used to reliably identify the origin?

fiery turtle
#

Nah

sterile egret
#

Some kind of bootable image that dumped the tables would be nice, though you’d have to decide how/where to store the dump.

#

QR codes obviously meme

fiery turtle
#

I mean

#

Modern hw has megabytes of aml

#

How many qr codes would that take

sterile egret
#

Well…max QR code size is apparently 3kb

#

lol

fiery turtle
#

Yea...

sterile egret
#

Serial might be doable for older machines

median crest
rustic compass
#

If it's a live usb dump to a folder there

rustic compass
#

Does a efi exe has access to acpi data?

#

Then making a live usb would be relatively easy

fiery turtle
#

Ofc

north holly
#

(whoops)

zenith crescent
#

Also me, but I quickly realised

vale isle
#

that might be me too idk

#

if the pr i sent has that it's yours idc

#

i will pirate windows if i ever install it on this machine

vale isle
mortal yoke
#

the table that contains the oem key is actually pretty funny, the public ms spec for it says that it contains proprietary data after the standard acpi header yet its documented in an old non-accepted patent (well they did change some fields to 64-bit but other than that its still the same as far as I could tell)

fiery turtle
vale isle
#

how do I get the disassembled dump then?

#

i think there are other acpi* tools one of them should be it

fiery turtle
#

Just rename the current file

vale isle
#

ok but are you sure this is a binary file

#

it looks like a regular text file

fiery turtle
#

Look at other examples named .bin in this repo and compare contents yours

vale isle
#

ah

fiery turtle
#

Its not a binary file yeah

#

But they name it that for some reason

vale isle
#

done

fiery turtle
trim siren
#

I created a pr for my laptop too

fiery turtle
trim siren
#

nice!

keen marsh
#

You talked about working together with some guy (from apica?) for developing acpi tests. What happened?

fiery turtle
keen marsh
#

And did you guys start the test suite?

fiery turtle
#

no

#

this person never came back

torpid ferry
#

given intel right now they probably got laid off or demoted

winter orbit
#

oof after a long time of trying to understand how the link between PCI <-> ACPI <-> hal works in Windows 2003, vista and 10 and trying to fix some of the core issues there locally so i can even start this.

Time has begun to start this lol

left orbit
#

damn that is cool

wind fiber
#

Nice!

vale isle
#

nice 👍

fiery turtle
#

i agree!

fiery turtle
#

alright, thats enough time wasted on minecraft and cs2

#

time to get back to the thread safety pr

#

i just had an insanely annoying week at work so no mental capacity to do anything

torpid root
fiery turtle
#

lol

#

i play the gtnh pack, which is a huge time sink

zenith crescent
fiery turtle
#

true

#
uacpi_status uacpi_rw_lock_read(struct uacpi_rw_lock *lock)
{
    uacpi_status ret;

    ret = uacpi_acquire_native_mutex(lock->read_mutex);
    if (uacpi_unlikely_error(ret))
        return ret;

    if (lock->num_readers++ == 0) {
        ret = uacpi_acquire_native_mutex(lock->write_mutex);
        if (uacpi_unlikely_error(ret))
            lock->num_readers = 0;
    }

    uacpi_kernel_release_mutex(lock->read_mutex);
    return ret;
}

I think this should work

fiery turtle
#
uacpi_status uacpi_eval(
    uacpi_namespace_node *parent, const uacpi_char *path,
    const uacpi_args *args, uacpi_object **out_obj
)
{
    struct uacpi_namespace_node *node;
    uacpi_object *obj;
    uacpi_status ret = UACPI_STATUS_INVALID_ARGUMENT;

    if (uacpi_unlikely(parent == UACPI_NULL && path == UACPI_NULL))
        return ret;

    ret = uacpi_namespace_read_lock();
    if (uacpi_unlikely_error(ret))
        return ret;

    if (path != UACPI_NULL) {
        ret = uacpi_namespace_node_find_permanent(parent, path, &node);
        if (uacpi_unlikely_error(ret))
            goto out;
    } else {
        node = parent;
    }

    obj = uacpi_namespace_node_get_object(node);
    if (obj->type != UACPI_OBJECT_METHOD) {
        if (uacpi_unlikely(out_obj == UACPI_NULL))
            goto out;

        *out_obj = uacpi_create_object(UACPI_OBJECT_UNINITIALIZED);
        if (uacpi_unlikely(*out_obj == UACPI_NULL)) {
            ret = UACPI_STATUS_OUT_OF_MEMORY;
            goto out;
        }

        ret = uacpi_object_assign(
            *out_obj, obj, UACPI_ASSIGN_BEHAVIOR_DEEP_COPY
        );
    } else {
        uacpi_namespace_read_unlock();

        uacpi_namespace_write_lock();
        ret = uacpi_execute_control_method(node, obj->method, args, out_obj);
        uacpi_namespace_write_unlock();
        return ret;
    }

out:
    uacpi_namespace_read_unlock();
    return ret;
}

Finally, fully thread safe uacpi_eval

#

actually there's still a race here between read_unlock and write_lock, if some other AML code manages to CopyObject to this node in between these two calls

#

so i guess eval has to take the write lock always

dusky glade
kindred beacon
#

nah you get less interested with age, trust me bro™️

torpid root
#

it's the opposite for me

kindred beacon
#

new PR dropped

#

I didn't know that uacpi_find_devices_at also checks against _CID, which is nice

#

and it wasn't immediately obvious without looking into the impl

fiery turtle
#

yeah thanks for the changes

#

your pr died on this LULW

#

fucking ubuntu got upgraded i guess

#

ill merge without it

kindred beacon
#

lmfao

#

in the README under the Why would I use this over ACPICA? section

fiery turtle
#

do uwanna fix it meme

kindred beacon
#

sure, can do

fiery turtle
#

thanks!

#

i already had this for macos lol

#

i guess now its needed for ubuntu as well

north holly
fiery turtle
#

this is github CI

north holly
#

oh

#

yeah break their packages

#

make sure they cannot fix them at all

fiery turtle
#

it creates a new vm for each run so i would only break my own packages in this case

kindred beacon
#

alright new commit on the PR

fiery turtle
#

leo the readme fixer

#

jkjk thanks a lot

#

aight merged

kindred beacon
#

based

fiery turtle
#

daamn you made the 800th commit @kindred beacon

#

you get a medal now

#

🏅 ig this one

north holly
fiery turtle
#

you should

#

its trivial to do

hasty plinth
#

Yeah it is, well worth it too

fiery turtle
#

okay uhh im back

#

i accidentally regressed ACPICA so gotta fix that first

#

wtf happened to my clion

fiery turtle
#

#polls message

#

pls vote because idk

torpid root
#

this is useful

#

nice

fiery turtle
#

yeah ikr, i noticed its really lacking in acpica so linux kernel has to make very awkward workarounds with global booleans

winter orbit
fiery turtle
#

Since ACPI spec introduced CopyObject real AML thread safety is now insanely difficult

#

if u have a pointer to a namespace node and u want to have an object at it u must do

#
namespace_write_lock();
obj = namespace_node_get_object(node);
uacpi_object_ref(obj);
uacpi_namespace_write_unlock();
#

otherwise someone can do CopyObject to this node, which would overwrite the object stored at the node, and you're left with a dangling pointer

#

thats why public uACPI API will not expose get_object and force the host to obtain a deep copy via uacpi_eval

#

If CopyObject didnt exist namespace nodes become immutable

#

And any stores to them only implicit cast store to an already existing object

#

so its safe to just node->obj

#

and the funniest thing is basically very few aml blobs use CopyObject

#

but since it exists u must guard against this

#

Imagine if someone could CopyObject in python and transform a method into an integer, or transform a class into a method

#

seems insane doesnt it?

#

well aml doesnt think so

#

and a method can CopyObject into itself while its executing too

#
Method (FOO) {
    CopyObject(123, FOO)
}
deft canopy
fiery turtle
#

FOO is now an integer 123 but its still being executed

fiery turtle
fiery turtle
#

they had an Unload opcode

#

u can unload arbtirary shit form the namespace

#

it was removed because of complete insanity of that idea

deft canopy
#

Lovely

fiery turtle
#

in ACPCIA its impossible to fix because they dont separate the idea of an object and a namespace node

severe swift
fiery turtle
#

it has been fuzzed by qookie quite extensively

#

but i guess the fuzzer is not smart enough to come up with this

#
0x603000000ec8 is located 24 bytes inside of 32-byte region [0x603000000eb0,0x603000000ed0)
freed by thread T0 here:
    #0 0x7f4e4c7ba537 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x55b8c1817293 in uacpi_kernel_free /mnt/d/uACPI/tests/runner/interface_impl.cpp:253
    #2 0x55b8c1896888 in free_method /mnt/d/uACPI/source/types.c:618
    #3 0x55b8c18f5952 in uacpi_shareable_unref_and_delete_if_last /mnt/d/uACPI/source/shareable.c:58
    #4 0x55b8c1896b91 in free_object_storage /mnt/d/uACPI/source/types.c:637
    #5 0x55b8c1897029 in free_object /mnt/d/uACPI/source/types.c:678
    #6 0x55b8c189746e in free_chain /mnt/d/uACPI/source/types.c:724
    #7 0x55b8c18976b2 in uacpi_object_unref /mnt/d/uACPI/source/types.c:762
    #8 0x55b8c189a072 in uacpi_object_detach_child /mnt/d/uACPI/source/types.c:957
    #9 0x55b8c18c4aa9 in object_replace_child /mnt/d/uACPI/source/interpreter.c:2165
    #10 0x55b8c18c4cba in copy_object_to_reference /mnt/d/uACPI/source/interpreter.c:2217
    #11 0x55b8c18dde31 in handle_copy_object_or_store /mnt/d/uACPI/source/interpreter.c:4176
    #12 0x55b8c18e6c70 in exec_op /mnt/d/uACPI/source/interpreter.c:5343
#

its funny u can see it being freed in CopyObject

#

handle_copy_object_or_store

#

and in ACPICA

#

i opened an issue there

#

@mortal yoke btw try this piece of code in your interpreter

#
DefinitionBlock ("", "SSDT", 1, "", "", 0)
{
    Method (FOO) {
        CopyObject(123, FOO)
        Return (1)
    }

    Debug = FOO()
}
fiery turtle
loud ice
#

rcu'd atomic load?

fiery turtle
#

u atomically load a pointer that has been freed

fiery turtle
loud ice
#

put the load behind rcu

#

and the freeing is deferred by rcu

#

so that you can't get a stale pointer there

fiery turtle
#

RCUs is probably not something i want to require from a kernel api

loud ice
#

you can just do like

fiery turtle
#

barely anyone has it

loud ice
#

load or something hmm idk

#

theres definitely a way to do it

loud ice
#

you can play lots of other clever games too

fiery turtle
#

just ignore the issue like acpica caret

loud ice
#

or that lmao

#

or you can run a real managed heap with mark-and-sweep

fiery turtle
#

yeah i guess

loud ice
#

and the load isn't a gc safepoint

fiery turtle
#

if u do a garbage collector

severe swift
#

ACPICA segfaulting doesn't sound good ngl

fiery turtle
#

acpica segfaults from return RefOf(local0)

#

so its not news

vale isle
severe swift
#

I don't know how much of a security implication ACPI can play but rofl would be funny if literally allowed code causes a exploit

fiery turtle
loud ice
#

oh it already does

fiery turtle
#

since it can already do arbitrary writes to any memory

severe swift
#

I'd still treat it as untrusted code on principle halfmemeright

fiery turtle
#

i try to do it for uacpi yeah

#

i dont allow edge cases to break anything

#

this one i discovered today while implementing thread safety

mortal yoke
fiery turtle
#

wdym lol

fiery turtle
#

does it print 1?

mortal yoke
#

no

fiery turtle
#

lmao

#

does it hang somewhere

mortal yoke
#

no it doesn't hang anywhere either

loud ice
#

is it just FOO = 123?

fiery turtle
#

replace the object at the node

vale isle
fiery turtle
loud ice
#

what kind of drugs is aml on?

loud ice
mortal yoke
#

and if I add Debug = whatever before and after the Debug = FOO() both of those are printed but not the FOO

fiery turtle
#

FOO = 123 would implicit cast 123 to whatever the type of FOO is

#

then store it there

#

not replace the object itself but its value

#

CopyObject replaces the object itself

loud ice
#

the word "object" is weird

#

what kind of drugs is aml on?

fiery turtle
#

very hard ones

loud ice
#

guess i'd need to implement an interpreter to understand this crap

fiery turtle
#

FOO becomes an integer 123 if u do CopyObject(123, FOO)

#

even though its a method

vale isle
# loud ice no thats not the thing here clearly

within lua it wouldn't be a huge issue but if you're interacting with it through the C api and you get a pointer to an object and the lua code sets it to something else and then the pointer would be dangling (if the GC triggers

loud ice
#

acpi is gc'ed as well

#

well, refcounted

#

also its not how any of it works lol

fiery turtle
#

uacpi uses reference counting atm yeah

#

which so far has allowed to sovle all edge cases

loud ice
#

imo you should just do tracing gc

#

its not that bad

#

and it solves 100% of issues

fiery turtle
#

id need to look into it

vale isle
#

GC is not that hard yeah

fiery turtle
#

no idea how it works

loud ice
#

you just do DFS over objects

vale isle
loud ice
#

and any object you touch you dont remove

#

everything else you free

#

ez

fiery turtle
#

the thing is acpica has existed for 20 years with this issue and no one complained

#

even though it segfaults if u blow on it

#

so idk if its worth investing that much into that

#

but probably

loud ice
#

does acpi.sys handle this?

fiery turtle
#

good question

#

ive segfaulted acpi.sys with uacpi test suite before

loud ice
#

lmao

vale isle
#

does code that does this exist in the wild?

fiery turtle
#

well i only have access to 500 blobs

#

but id hope not

#

but its kinda silly to say well this turing complete language can segfault me but surely no one will write code like that

#

at least i want to try and solve most issues like that

mortal yoke
#

yeah it just prints 1

fiery turtle
#

qacpi superiority confirmed

#

this is with asan compiled in right

loud ice
#

im so confused what is an object in AML then?

#

and what is a method????

#

what is anything anymore

fiery turtle
#

u can think of it like assembly labels

loud ice
#

thats not very helpful

fiery turtle
#

a method is just an object type

mortal yoke
fiery turtle
#

nice

fiery turtle
#

AML is similar to python in that u execute top-down and have a collection of named things, e.g. in python u would have

# printed right away
print("hello world")

# not printed right away
def foo():
    print("foo")
#

this much u understand right?

loud ice
#

yes

fiery turtle
#

in aml the idea of a name and an object is slightly detached, an object can exist standalone and also a labeled thing:

// prints 123
Debug = 123

// Create a name FOO and attach an integer 123 to it
Name (FOO, 123)

// Prints 123
Debug = FOO
loud ice
#

that's like any programming language i guess?

#

(also the syntax with Debug = FOO is cursed wtf)

mortal yoke
#

you can also do Printf and the compiler will expand it to a series of stores to Debug

fiery turtle
#

if i do

FOO = "hello"

this will do memcpy(&FOO.object.integer, "hello", min(FOO.sizeofstorage(), strlen("hello"))

#

so only the underlying contents of the integer stored at FOO change

#

in that sense objects in AML are immutable

#

e.g. strings and buffers stay the same length etc

#

but then they add CopyObject

#

Which breaks this paradigm and now u can replace the object stored at FOO entirely

fiery turtle
#

yup

loud ice
#

doesnt this mean that if you do Name(FOO, "Text") FOO = 123 Debug = FOO you print the string at address 123?

#

which is definitely garbage

fiery turtle
#

that will memcpy a qword 123 to Text

loud ice
#

ah okay

fiery turtle
#

the first 4 bytes of it

loud ice
#

stupid

fiery turtle
#

yup

#

i have an example on my README

#

ACPICA does an even stupider thing that literally no one expects

#

they allow buffer size mutation

#

a pitust aml interpreter would be interesting to see meme

#

with garbage collection and stuff

mortal yoke
#

yeah it's an interesting idea

fiery turtle
#

it would probably allow for proper JIT

#

and getting rid of the GIL

#

not that anyone needs that

vale isle
#

ok i took a look at lua and mlua (rust bindings to lua, luajit and luau)
basically it forces you to store stuff in lua's ffi State, so the lua GC is still aware of it and the ""dangling"" thing will not be freed. in C i guess if you don't store it in the ffi State, then you can still cause a dangling pointer, but in rust mlua doesn't let you keep a strong reference to objects unless you store it in the ffi State

#

you can still keep a &Value weak reference

#

this also enables handles to scoped values to be trivially leaked from the given callback. This is not dangerous, though! After the callback returns, all scoped values are invalidated, which means that though references may exist, the Rust types backing them have dropped. Function types will error when called, and AnyUserData will be typeless. It would be impossible to prevent handles to scoped values from escaping anyway, since you would always be able to smuggle them through Lua state

#

so everything is either a Weak reference or a strong reference stored in the lua State

fiery turtle
#

fuck, most of these are not thread safe

north holly
#

goddamn is AML delulu

#

what were they on while making this?

vast kestrel
#

Say thank you it doesn't use the JVM

mortal yoke
#

jvm is actually pretty nice except for some of the weird stuff like invokedynamic

vast kestrel
#

I don't want jvm in my kernel

severe swift
#

jvm in kernel is cursed but also has been done before iirc

vast kestrel
#

Tbf idk anything about jvm only java

#

And about every decision they did was stupid

#

At least up to java 8 I stopped following after that :^)

median crest
#

aml shouldve been lua smh

vale isle
#

yayy

leaden fox
#

aml should've been Fallout's papyrus

vale isle
#

if i ever design hardware and decide to do smth other than ACPI

#

or just regular DTBs

#

i will consider lua

north holly
vast kestrel
#

Tbh lua doesn't really fit with only having number and no builtin bitwise operations

#

Like AML is not that bad

#

It has a few retarded encoding and opcodes decisions

hollow elm
vagrant hull
#

just ship an x86 interpreter instead of an AML one :^)

loud ice
#

they arguably have ints

#

and they have bitops

#

and strings

#

and its a standard

hollow elm
#

wasm :^)

torpid root
#

<insert any language>

north holly
torpid root
#

++

deft canopy
jaunty fox
#

about to try out the new early table access api

fiery turtle
#

lemme know how it goes!

jaunty fox
fiery turtle
#

nice

#

i take it keyronex numa support is underway?

jaunty fox
#

yes, a new structure's beginning to emerge

#

principle is per-numa-loaclity-domain page queues/freelist, page writeback daemon, etc

fiery turtle
#

first hobby os with numa support

median crest
#

Big

jaunty fox
fiery turtle
#

never heard of it

dusky glade
#

infy i love u

dusky glade
#

congrats for fadanoid !!!

torpid root
#

@fiery turtle mr uacpi is this fixable?

#

or just buggy firmware

jaunty fox
torpid root
#

the acpi part lol

#

the stop job is my fault

fiery turtle
#

Although acpica probably aborts the entire namespace in that case, which would skip all other named objects that might be there, which might create even more problems

#

uACPI just skips the opcode in this case

torpid root
#

yeah it doesn't affect anything other than my annoyance

fiery turtle
#

Its probably somewhere closer to the end of the blob so ur lucky

#

Or your firmware has two identical ssdts with different names

#

I've already seen that before

#

Truly fucked firmware out there

vale isle
#

my firmware has that on boot too

#

hp 255 g9

#

this shit is so truly fucked

#

like on display lid close, it sends hp-specific keycodes through the keyboard

#

one keycode for no wifi and one keycode for no bluetooth

#

but no such keycode on display lid open

#

so every time i closed the lid my laptop would be in airplane mode

#

i setkeycode'd it to nil

fiery turtle
#

Cleaning up some table reference leaks, I think im going to go ahead and just store method aml in heap allocated buffers instead of having to keep all of the aml tables mapped at all times

#

This also protects the aml from insane firmware that might try to modify aml currently being executed via smm

north holly
#

W h a t

#

T h e

#

F u c k

vast kestrel
#

how about aml trying to modify its own methods :^)

kind mantle
#

Ah yes, the well-known good practice called "self-modifying code"

fiery turtle
fiery turtle
vast kestrel
#

I wonder how far you can get with aml, like could you make an operating system with it

#

You have dynamic table loading for programs

hollow elm
#

x86 -> aml jit for running user programs

vast kestrel
#

Ohgod

fiery turtle
#

id say u can get very very far

#

u can even route interrupts as scis

vast kestrel
#

True

#

Could you do co-op scheduling?

fiery turtle
#

yeah

vast kestrel
#

You probably could

fiery turtle
#

u can implement a cooperative scheduler based on events

vast kestrel
#

Can you store a method inside of a package?

#

And then execute it

fiery turtle
#

well as a buffer that u could Load and then call

vast kestrel
#

Ohgod

fiery turtle
#

lmao

vast kestrel
#

No easy indirect call would get annoying fast

fiery turtle
#

yeah thats the annoying part

#

no call opcode

vast kestrel
#

I was just about to say let's modify the aml for the indirect call

#

But that won't work given you copy the aml

fiery turtle
#

u could easily extend it to add a CallOp which could operate on anything

#

and then u could do stuff like Call PKG[123]

vast kestrel
#

Yeah but that's no fun

fiery turtle
#

at that point u can do anything

fiery turtle
fiery turtle
vast kestrel
#

Yeah that's what I meant, but given you copy it, it won't work anymore lol

fiery turtle
#

u need a trampoline for calling into a method

#

that would just do XXXX()

#

in table data region u would overwrite XXXX with whtaever u want

#

then call into the trampoline

#

but u still can't do stuff like call-by-address etc

#

but with this approach u could have a function table at least

vast kestrel
#

Maybe you can dynamically generate a switch case

#

So when you add another option for the abstraction, dynamically add to the method another case which does a call

fiery turtle
#

well switch and case are macros

#

which just expand into while (0) { if if if }

vast kestrel
#

Yeah you can do that

#

If id == <const> name(<params>)

fiery turtle
#

true yeah

vast kestrel
#

I'm really tempted to try lol

#

Aml itself doesn't have a way to iterate the namespace right?

fiery turtle
#

that would be funny

fiery turtle
#

best thing u get is CondRefOf

mortal yoke
# fiery turtle and then u could do stuff like `Call PKG[123]`
DefinitionBlock ("", "SSDT", 1, "", "", 0)
{
    Method (FOO) {
        Return (1)
    }

    Method (BAR, 1) {
        CopyObject (DerefOf (Arg0[0]), FOO)
    }

    Method (TST) {
        Debug = "TST"
    }

    Method (ANOT) {
        Debug = "ANOT"
    }

    Name (PKG, Package (1) {})

    PKG[0] = RefOf (TST)
    BAR (PKG)
    Debug = "calling TST"
    Debug = FOO ()
    PKG[0] = RefOf (ANOT)
    BAR (PKG)
    Debug = "calling ANOT"
    Debug = FOO ()
}
vast kestrel
#

The only thing we can't do is isolation :^)

fiery turtle
#

oh yeah u can just abuse CopyObject to execute arbitrary shit lmao

vast kestrel
#

That's genius

fiery turtle
#

u cant modify cpu regs

vast kestrel
#

You would want to synchronize the method cause namespace memes but yeah

#

I mean, bigger problem is anyone has access to physical memory lol

fiery turtle
#

wdym?

mortal yoke
#

its pretty funny

fiery turtle
#

i even do this in one of the test cases iirc

#
// Name: Copy a local method and execute it
// Expect: int => 3735928559

DefinitionBlock ("x.aml", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
{
    Name (TEST, "Hello world!")

    Method (GETX) {
        Return (1)
    }

    Method (COPY) {
        Method (GETX, 1, Serialized) {
            Name (Y, 0xDEAD0000)
            Y += Arg0
            Return (Y)
        }

        Return (RefOf(GETX))
    }

    Method (COP1) {
        Local0 = COPY()
        Return (DerefOf(Local0))
    }

    Method (MAIN, 0, NotSerialized)
    {
        Local0 = COP1()
        CopyObject(Local0, TEST)

        Return (TEST(0xBEEF))
    }
}
vast kestrel
#

I guess you can generate new namespace objects on each indirect call, some kind of a macro

vast kestrel
#

I might want to create a preprocessor anyways to allow me to have names bigger than 4 letters

#

And reg-alloc with the locals

fiery turtle
#
Name (CALL, 0)
Mutex (LK, 0)

Acquire(LK, 0xFFFF)
CopyObject(PKG[X], CALL)
Release(LK)
CALL()
#

this is how u could dispatch arbitrary stuff

vast kestrel
#

Yeah

#

Can't you mark the method as synchronized?

#

Instead of manually creating locks

fiery turtle
#

then it would be locked for the duration of the call

#

which u dont need

vast kestrel
#

Wait, won't this race possibly

fiery turtle
#

CALL getting overwritten by a different thread is no different from CopyObject into yourself

#

an interpreter should support this

vast kestrel
#

I mean, it could happen before the CALL is resolved no?

fiery turtle
#

well

vast kestrel
#

The Name is part of the namespace while executing the method

fiery turtle
#

there's a race window here i guess

#

so yeah i guess u could just

#

wrap this in a serialized function

vast kestrel
#

That is pretty sad tho

fiery turtle
#

well

#

u can create a separate instance of the dispatch function

#

by doing a copyobject of it

vast kestrel
#

Hmmm

fiery turtle
#

or wait

#

yeah

#

that should work

#

we're doing some cursed shit here ngl LULW

vast kestrel
#

oh yeah

#

You can have like 8 versions

fiery turtle
#

i think acpi.sys BSODs if u CopyObject a serialized method

vast kestrel
#

And each time you use one you copyobject

fiery turtle
#

non serialized works tho

fiery turtle
vast kestrel
#

I'll just use the correct interpreter (uacpi)

fiery turtle
#

well not like u could use acpi.sys for this tbh

#

and acpica would just segfault instantly on anything cursed like this

vast kestrel
#

Yeah lmao

fiery turtle
#

would be a funny progress thread lmao

#

X11 ported to AML

vast kestrel
#

Is there some simple image that just runs uacpi? Like the old lai image?

#

Nononono

#

Ok

mortal yoke
#

you could even run it in userspace

vast kestrel
#

Yeah but real hardware is more fun

#

I want an nvme driver

fiery turtle
#

u can even use fw_cfg to retrieve the memory map and stuff

#

if you're on qemu

#

entirely in aml

vast kestrel
#

I think the plan would be to run uacpi, and add another ssdt which is the kernel itself

#

Or well

fiery turtle
#

as for simple image, probably the simplest to build is astral or obos maybe

vast kestrel
#

Kernel is a big word

vast kestrel
#

So you have both the dsdt and firmware stuff, and your own stuff to play with that

fiery turtle
#

yeah u can do that

#

uacpi_table_install

vast kestrel
#

Hmmmm even tho there is no easy way to find objects by their cid/hid from aml

fiery turtle
#

yeah but u can still use ecam for example

vast kestrel
#

Yeah that would work

fiery turtle
#

for other stuff u can cheat and make a syscall into C land layer

vast kestrel
#

Use _OSI to find if the interface exists :^)

fiery turtle
#

lol

#

_OSI("PNPXXXX")

vast kestrel
#

That might actually work lol

#

Wait, does uacpi expose a way to install a native aml method?

#

Like _OSI is technically a method no?

fiery turtle
#

if u make the kernel call uacpi_install_interface for all of those pnp ids then yes

fiery turtle
#

its a native method in uacpi

vast kestrel
#

I could maybe make one for exposing the uacpi namespace search

fiery turtle
#

there's osi.h to manipulate what it reports as supported

fiery turtle
#

the only issue is it takes in the interpreter context, which is defined in interpreter.c aka its sort of private to that

vast kestrel
#

Hmmm

#

Later, I think id first want some preprocessor to make it easier to write asl

fiery turtle
#

true true

#

asl is missing shit that the dtb compiler has

#

like long aliases

vast kestrel
#

Yeah long aliases are first

fiery turtle
#

would be funny if u actually manage to extend the iasl compiler to support compile time alises and upstream it

vast kestrel
#

Oh god

#

I am not sure if I want to touch that lol

#

I might just actually write some python script to preprocess it

fiery turtle
#

true well probably easier to treat it as a C file that can be run through a preprocessor before being fed to iasl

vast kestrel
#

Yeah running cpp would also work well

fiery turtle
#

but a python script sounds nicer

#

u could have custom syntax

vast kestrel
#

I want 3 things to write code sanely, long names, locals dynamically allocated among the LocalX and if it runs out maybe a package to spill or something alike

#

And named arguments

fiery turtle
#

damn

vast kestrel
#

That would already make asl like 100x easier to write

fiery turtle
#

if u actually implement that stuff that might even be unironically used internally by firmware writers

#

hell i might even use it for the uacpi test suite

vast kestrel
#

:^)

fiery turtle
#

i want a progress thread for that stuff shinycaret

vast kestrel
#

I'll write something when I get home and open a progress thread :^)

fiery turtle
#

thats big

#

ngl it sounds very interesting, even to get like a framebuffer logger working via aml

#

E9 is trivial too

vast kestrel
#

Yeah serial/e9

#

Wait

#

Isn't there a Debug thing in acpi

#

Like in aml

fiery turtle
#

yeah but thats kinda cheating

vast kestrel
#

True

fiery turtle
#

but yeah uacpi does log calls via Debug

#

there's even a Printf macro in asl

#

u can do stuff like Printf("Hello %o", "world") etc

vast kestrel
#

Yeah that's nice

#

Use BCD to print numbers :^)

fiery turtle
#

lol

#

ToHexString to be cool

#

i think %x does it automatically but not sure

vast kestrel
#

I wonder, if you ipi the sci vector on another core, would that work?

fiery turtle
#

sure

#

but u would also have to set the respective GPE status bit as 1

#

so that the aml handler is run

vast kestrel
#

wait, can you even set a GPE bit

#

isn't that hardware regs

fiery turtle
#

it depends as per usual

vast kestrel
#

hmmm that might not work well then

fiery turtle
#

well its write 1 to clear soo

vast kestrel
#

yeah

#

ok how about, from the kernel, I call eval on some entry method from each of the cores

#

uacpi is thread safe right :^)

fiery turtle
#

there's a WIP PR shinycaret

#

its like the last bit of uacpi left to make it production ready

north holly
fiery turtle
#

uhhh

north holly
vast kestrel
#

can aml allocate physical memory?

fiery turtle
vast kestrel
#

hmmmm so if we want anything to do dma we would need that

#

but I guess we can start with simple ide pio

fiery turtle
#

Read e820 from fw_cfg

#

Allocate yourself

vast kestrel
#

ohgod

fiery turtle
vast kestrel
#

I mean, there is a kernel running under you, you can't just access physical memory as you want :^)

#

unless you wanna corrupt uacpi itself

fiery turtle
#

Well as long as you have some sort of an Abi where the host kernel lives

#

E.g. 1..10MiB phys

vast kestrel
#

ISA DMA time :^)

fiery turtle
#

Or ask the host kernel via some interface or whatever

fiery turtle
#

This is basically like a vm at this point

#

But honestly a bounce buffer of a few pages sounds fine

#

Just agree with the host kernel on some location, dma to that, then memcpy from aml

#

Or the cursed address of syscall

#

Or, manually probe memory until you locate yourself, then have some Noop area that you will be using as the bounce buffer

north holly
#

I wonder if one could exploit a vulnerability within a kernel's acpi interpreter

#

Actually no

#

Someone could probably just make a malicious aml blob

#

As a virus payload

#

Then since aml is trusted code

vast kestrel
#

I mean, trusted is a big word

north holly
#

Iirc windows has an extra list of aml blobs to load in the register

#

Brain faet

vast kestrel
#

if you have the privs to register aml blobs you can probably make a better rootkit

#

or if you patch the bios, you already have a better rootkit

north holly
#

Couldn't you leverage that to get that aml running

vast kestrel
#

I mean, running what I wanna make and running windows at the same time wouldn't really work

#

I want to make actual drivers in aml

#

I want the kernel to only have the bare minimum required to run uacpi

#

ok I can do something really cursed

#

I can use port io to syscall into the kernel

#

given x86 only has 16bit, and acpi allows for port io of 64bit

#

I can have some custom port ios to communicate with the host

#

worst case if I can't find it some features won't be available

vast kestrel
#

ok I got a tiny kernel that can just load uacpi and load all the limine modules given as aml blobs, now I just need to make a nice acpi buildsystem

#

(the 8 errors is because I was too lazy to implement pci read)

fiery turtle
#

and use some other unused address space type for this

#

e.g. IPMI

#

and then hook that up from the kernel via uacpi_install_address_space_handler

vast kestrel
#

True

vast kestrel
#

so I started writing python to parse asl, and I think this is not what I wanna do tbh

#

like, I have something basic working, but the grammar has soooo many random stuff in it

#

I think maybe I should use some parser generator and try to convert their grammar into that

loud ice
#

i'd think you want to parse a custom language then generate ASL out of that

#

so you dont have to deal with whatever the fuck asl is

vast kestrel
#

I want to just add some small extensions

#

like long names and something to handle locals

#

it should just do minor transformations

loud ice
#

just write your own lang

#

asl/aml is truly cursed afaik

vast kestrel
#

I mean, the problem is that I will need to do cursed stuff to get some of this working, so I am not sure how better whatever I will do is going to be

#

And alot of stuff don't really fit into other Langs, unless it will look essentially like asl

#

Ok I can do something simpler maybe, I can just tokenize the asl, and heuristically replace long names with short ones

#

If it's a keyword don't replace it, otherwise assume it's a long name and replace it

fiery turtle
#

I guess

#

Although reg spilling and local alloc is more complex

vast kestrel
#

Not that much, simple linear scan and if there are too many store it in package instead

fiery turtle
vast kestrel
#

Don't even need a real spill because accessing a package is not that much more expensive

loud ice
fiery turtle
loud ice
#

which is the literal thing you'd want to debug

fiery turtle
#

Lol ig

vast kestrel
#

Whatever broken thing I create is just another test case for uacpi :^)

loud ice
#

lmao

#

your compiler tests double as uacpi tests

fiery turtle
#

Indeed

#

Fuzzing via broken compiler

vast kestrel
#

is there a way to compare references?

#

I have two locals, and I want to check if they both have the same package

#

by same I mean same ref

#

btw it seems your ConcatOp doesn't handle correctly non-integer/string/buffer types

#
Op 0x0073 ('ConcatOp'): invalid argument type: Package, expected a ComputationalData := ByteConst | WordConst | DWordConst ...
#

while the spec says

fiery turtle
fiery turtle
vast kestrel
#

fuck

fiery turtle
#

Aka my concat is the same as acpi.sys

vast kestrel
#

:(

#

anyways I was gonna implement a linked list

#

but I can't really iterate it

fiery turtle
#

Lool

vast kestrel
#

like a cyclic one

fiery turtle
#

Interesting

vast kestrel
#

wait, I can't iterate it at all

#

cause I can't check when I am done even

fiery turtle
#

U cant have a null ref yeah

vast kestrel
#

is there a try-catch :^)

fiery turtle
#

I wish

vast kestrel
#

I can add an entry that has some unique id for every object I create

#

and I can compare that

fiery turtle
#

If u store them as packages yeah u can store like a tuple

loud ice
#

why do you want null?

#

ah nvm

fiery turtle
#

U could say that tuple with ID 0 is null

#

And have like a NULL tuple object

loud ice
#

could you just use number 0

#

and then check the type

fiery turtle
#

Oh yeah

#

Just ObjectType it

loud ice
#

lol

fiery turtle
#

I forget the crap they have in the spec

vast kestrel
#

packages are passed by ref right

fiery turtle
#

You can think of it that way yeah

#

Modifying it from a dif place will be visible everywhere

vast kestrel
#

ok I am really confused then

fiery turtle
#

Same goes for buffers and strings

vast kestrel
#

I have this code, next == 0, value == 3, Local0 is initialized to Package(3) and Local1 is initialized to Package(4)

#

and this is what I get ```
[AML DEBUG] Package @ffff80007fc8f0c8 (ffff80007fc8f088) (4 elements)
Element: Uninitialized
Element: Uninitialized
Element: Uninitialized
Element: Integer => 0x0000BABE
[AML DEBUG] Package @ffff80007fc6b008 (ffff80007fc6af08) (3 elements)
Element: Package @ffff80007fc6b0c8 (ffff80007fc8f148) (4 elements)
Element: Package @ffff80007fc8f9c8 (ffff80007fc7bd48) (3 elements)
Element: Integer => 0x00000001
[AML DEBUG] Package @ffff80007fc7bf48 (ffff80007fc7bdc8) (4 elements)
Element: Uninitialized
Element: Uninitialized
Element: Uninitialized
Element: Uninitialized
[AML DEBUG] Package @ffff80007fc6b008 (ffff80007fc6af08) (3 elements)
Element: Package @ffff80007fc6b0c8 (ffff80007fc8f148) (4 elements)
Element: Package @ffff80007fc8f9c8 (ffff80007fc7bd48) (3 elements)
Element: Integer => 0x00000001

#

do I need to keep the ref maybe?

#

and not deref

#

yeah that worked

fiery turtle
#

Store does a deep copy

#

So yes

vast kestrel
#

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

#

but why is it uninitialized

#

like

fiery turtle
#

Wdym

vast kestrel
#

Local1 is completely uninitialized after the deref

#

while it was with stuff beforehand

fiery turtle
#

Can u show a snippet

#

Im not my phone

#

On*

vast kestrel
#

yeah one second

#

the third debug is after doing the derefof on the package

#

you can see from the pointers that the first package is refed by the second one

fiery turtle
#

No like

#

Which code does not what u expect

vast kestrel
#

and then when printing the Local1 after the derefof(local0(next)) it is a package full of uninitialized

#

if it was a copy I would expect it to at least have something

fiery turtle
#

Can you come up with a simplified example KEKW

vast kestrel
#

let me try :^)

#

ok I am really fucking confused

#

I might just wait till you have a computer because I have no idea what is going on lol

fiery turtle
#

Lol

#

Any code examples?

#

Ill be at my pc later today

vast kestrel
#

I have this code

#

this is the result

#

if I comment out the Local1 = Local0[0] it prints

fiery turtle
vast kestrel
#

why is it uninitialized

#

and why can it do dereof index but can't do index

fiery turtle
#

Because u deep copied an empty package

vast kestrel
#

OH I see what you mean by deep copy

fiery turtle
#

And the stored to it

vast kestrel
#

so I need a RefOf?

fiery turtle
#

Yeah

vast kestrel
#

ok that makes sooooo much more sense

fiery turtle
#

Lol

vast kestrel
#

I am still a bit confused on why the Local1 = Local0[0] had the cast error

#

while the dereof worked

fiery turtle
vast kestrel
#

btw it would be nice if when you have an invalid argument for an object it would say which argument

fiery turtle
#

Wdym by that

vast kestrel
#

so for example when it sasys invalid argument for Index, it would say if its the source or index that doesn't match

#

Ig I can infer that from what it expects tho

fiery turtle
#

Oh, yeah ig those debug messages could be improved

#

Are u actually preprocessing it with cpp?

vast kestrel
#

nope

#

using the horrible iasl preprocessor

fiery turtle
#

Oh thats a thing?

vast kestrel
#

yeah it has stuff

#

but

#

it doesn't know how to do things like "[MACRO]"

#

you have to do [ MACRO ]

fiery turtle
#

How does it work?

vast kestrel
#

it is just builtin

#

it even has ifdef and all

fiery turtle
#

Oh interesting

vast kestrel
#

iasl had #embed before c had it :^)

fiery turtle
#

Damn

#

Ngl I didnt know iasl could do that

loud ice
#

can you do uart with acpi?

#

like a uart device

#

in aml

fiery turtle
#

Yeah ofc

vast kestrel
#

ok so now it seems like I can't switch the reference inside of a package

#

wait, do I need to use CopyObject instead

vast kestrel
fiery turtle
vast kestrel
#

AAAAAAAAAAAAAA AML IS SO DUMB

fiery turtle
#

References are not refundable

#

Rebindable sorry

#

Lmao

#

Storing to a ref implicit casts

vast kestrel
#

hmmm what

loud ice
#

may i recommend writing your own aml generator

vast kestrel
#

before that I need to figure the rules lol

loud ice
#

fair

#

thats what the spec is for :^)

vast kestrel
#

I might do something with static types just so I can actually emit things correctly, like that copy object

vast kestrel
loud ice
#

what is a namestring?

fiery turtle
loud ice
#

who comes up with this crap

fiery turtle
#

Use -f

vast kestrel
#

.........................

#

what do you mean technically

fiery turtle
#

Spec says copyobject takes in a SuperName

#

But nt supports copyobject to everything

vast kestrel
#

ill go insane by the end of it

fiery turtle
loud ice
#

wait how would CopyObject(Local2, Local0[0]) work

fiery turtle
#

Literal basically

fiery turtle
loud ice
#

wait is it src, dst

vast kestrel
#

src, dst

fiery turtle
#

Yes

loud ice
#

fucking what

fiery turtle
#

Lol

loud ice
#

may i guess that it is not in fact possible to do it without NT noncompliant magic?

fiery turtle
#

Yes

#

Copyobject only works on paths officially

loud ice
#

does acpica agree with this particular nt misfeature

fiery turtle
#

Yep

#

Iirc

loud ice
#

fucking what

fiery turtle
#

Lol

#

Get used to shit like this

vast kestrel
#

I mean

#

given you don't have any other way to replace an element

#

I can understand

fiery turtle
#

Ye

vast kestrel
#

or well, a reference element

#

ok adding -f doesn't help

fiery turtle
#

Well in acpica u do

#

Acpica allows reference rebind

vast kestrel
#

am I really going to need an actual compiler this quickly

fiery turtle
#

Aka it doesn't perform store to the referenced object

#

But rather to the ref container

#

Which is wrong ofc

fiery turtle
vast kestrel
#

I mean, thats what something sane would do

fiery turtle
#

Yeah

#

Except it doesn't for Arg references

#

So for that it does mimic nt

#

But not for other stuff

vast kestrel
#

.............................................

fiery turtle
#

Lmao

vast kestrel
#

ok a compiler it is ig

fiery turtle
#

Its like walk over tokens and emit the respective aml op

vast kestrel
#

yeah except I will want to support the symbolic expressions

fiery turtle
#

True

vast kestrel
#

and right now I just didn't do long names

#

so I might as well do it

#

ok i need a name for the project

#

right now I called it uacpios

fiery turtle
#

Lmao

#

Like if u implement a syscall layer for stuff like hooking interrupts or context switching u can have a full blown kernel pretty much

vast kestrel
#

I think my first goal is more of a dos like

fiery turtle
#

Makes sense

vast kestrel
#

like, what I was gonna do, is create some framework to patch aml from aml

#

so I can dynamically create Device objects for each PCI device

#

so I can use the AML OperationRegion PCI stuff

fiery turtle
#

Oh interesting

vast kestrel
#

and for that I figured I probably want a way to do dynamic lists

fiery turtle
#

True

vast kestrel
#

so I was gonna make a linked list and here we are

fiery turtle
#

Ill take a look

vast kestrel
fiery turtle
#

Copyobject where possible ftw

vast kestrel
#

anyways any other name or do I keep uacpios

fiery turtle
#

Sounds good to me

#

A progress thread? flnsh

vast kestrel
#

yasss I will make one to stop spamming this channel lel

fiery turtle
#

I dont mind honestly

#

Its acpi related content anyway

median crest
#

Uacpios

#

What is that

fiery turtle
#

An os entirely in aml

loud ice
#

oh god

#

you may want to write an amljit for that

loud ice
#

so that perf doesnt suck

median crest
#

That sound awful I love it

vast kestrel
#

the true universal OS

loud ice
#

can acpi emulate a uart?

fiery turtle
#

You can start with a basic jit that just calls into C

torpid ferry
#

now embed it in firmware, boom you made windows into an usable os :^)

fiery turtle
loud ice
#

if so you can literally just make /dev/ttySn be your custom os

loud ice
#

if so then super based

fiery turtle
#

Wdym exactly lol

vast kestrel
#

I think he means actully defining a uart device that is uart

loud ice
vast kestrel
#

where it calls acpi methods to access it

loud ice
#

and the os makes it look like serial

fiery turtle
#

Yeah ofc

vale isle
vast kestrel
#

like how you can make an rtc in pure aml

loud ice
vast kestrel
vale isle
#

windows subsystem for aml

fiery turtle
#

Well not natively there's no such thing in Linux lol

vast kestrel
#

ok yeah that is what I assumed lol

torpid ferry
#

you can probably do it with weird SMM interactions on some chipsets

fiery turtle
#

But u can define a device with a method that can be hooked up

loud ice
#

but the os wont make it look like hardware uart?

fiery turtle
#

And u can execute aml from Linux userspace via aml debugger

loud ice
#

you can always pretend to be i2c or whatever ig

#

output via fake i2c keyboard :^)

vale isle
#

can WSL run AML?

loud ice
#

input by faking a gop?

#

hmm no thats ugly

torpid ferry