#uACPI - a portable and easy-to-integrate ACPI implementation
1 messages Ā· Page 71 of 1
huge
This looks like the lounge?
what
Atleast the color scheme and layout
Self hostable web client
the lounge
it's a web client
we just need to hire one of those hardcore PR firms
they can mount a smear campaign against ACPICA
as OGs of this thread know there is more than enough fuel for that fire
I mean the fact they have been slopping a ton of shit apparently and breaking things
We don't even need to smear them
Just tell the truth
they broke things real good
Who is that?
just ask the guy with the corvette
ACPICA also killed my parents
the acpica maintainer corvette incident
zircon guy
zircon?
fuschia/magenta
little kernel guy
uacpi first got into react
š„
ah cool
uacpi becomes the new reference
Epstein also used ACPICA 

interesting
š
It's funny how it's saying "please try a different search", as if it really wants you to dig something up
Would of been funny if some random email from Epstein like āthis acpica thing is really coolā came up
I mean If Epstein ever used Linux
He used ACPICA by proxy
Which was the joke I was going for


omg look
there is a bash manual in the files
lol
and i saw some emails of orders for hp linux servers or smth iirc
not sure what that was about
SEE! SEE!
got back in my hands an old laptop with a touchscreen
the madt is fucked
non-sequential APIC ids
this one is subtler, but it specifies NMIs as level triggered
which is prohibited by the intel sdm
and i cant get my os to proceed because i get an apic error
someone is sending me an IPI with vector 0-15
it is not me
do you know how the touch is wired? usb/i2c/something else?
no idea
the laptop is super fucked overall
the quality is bad
the keyboard's up arrow is spammed constantly
you can determine if it's usb by looking at lsusb output
alternatively you can get a nice listing of all input devices with evtest
Thats why linux never even looks at nmi entries
Half of my laptops are this way lol, they're rarely sequential
so how does it wire the nmi handler?
when i type nmi in the qemu monitor it is received by linux
how does it know what parameters and what lints
i see
@kindred beacon ```
Available devices:
/dev/input/event0: Lid Switch
/dev/input/event1: Power Button
/dev/input/event10: HDA Intel PCH Mic
/dev/input/event11: HDA Intel PCH Speaker Front
/dev/input/event12: HDA Intel PCH HDMI/DP,pcm=3
/dev/input/event13: HDA Intel PCH HDMI/DP,pcm=7
/dev/input/event14: HDA Intel PCH HDMI/DP,pcm=8
/dev/input/event2: AT Translated Set 2 keyboard
/dev/input/event3: Video Bus
/dev/input/event4: Intel HID events
/dev/input/event5: Intel HID 5 button array
/dev/input/event6: PC Speaker
/dev/input/event7: FTSC1000:00 2808:50C5
/dev/input/event8: FTSC1000:00 2808:50C5 UNKNOWN
/dev/input/event9: SYNA3602:00 0911:5288 Touchpad
the touchscreen is event7
what the fuck
synaptics touchpad letsgo
so yes, over i2c
that's based actually
who needs csm tbh
fuck that old cruft
back in 2020 i was forced to use tomatboot š
i was surprised to learn none of my laptops support the PXE GET_FILE_SIZE request, which is a fucking pain
havent tried the bios PXE yet, maybe that one is better
let me now debug harder what is the apic error issue and i'll try to see how uacpi goes
only use TFTP for limine +Ā kernel binary + initrd, NVMe-oF for the rest 
i have written a pxe rom 
the apic error in your kernel u mean?
yes
ah
for what card?
actual troll
doesnt that already have one?
yeah ofc
ah
the storage is also unironically an emmc card
I have always wondered why do the cheap laptops/chromebooks use emmc instead of ufs
its literally worse than phones lol
It's cheaper?
UFS is like in the flagship smartphones, and only became a thing recently
I mean everyone uses NVMe now?
Smartphones, SD cards
its not flagships only, mid-range phones in 2020 already had it for an example
like oneplus nord n10 that cost like 250⬠back then
I think it's because emmc works over SD bus that chipsets already have
Meanwhile ufs is a different bus
And nvme is just pcie
how much cheaper even is emmc to skip nvmes? iirc you can get 256gb ones for like 30 bucks wholesale
the nice thing about UFS over emmc is that the controller interface is standardized (though ofc it can also come with quirks like all hardware)
rip, i have to actualy implement the ec region handlers 
no idea why the apic error happens
it happens only once after i sti
the error status register has bit 6 set, which means that someone is sending me an interrupt with a vector from 0 to 15, which is illegal
it happens with the other cpu too when i bring it up
okay, this took me a grand total of 5 seconds
also, during initialization, i get a gpe before they're enabled
okay, there is something worse happening
when uacpi calls the battery's _STA, it accesses a register inside the embedded controller space
and i have no handler for it, because i have to first initialize the namespace, and then iterate over the devices looking for the embedded controller, and after that attach a handler?
Isn't emmc also standardized?
Like it's just the SD card
ECDT table
i dont have that
oh okay
Idr how linux handles it exactly, I did look into it a while ago
the thing itself yes, I guess it depends on the device whether it uses the standardized SD host controller interface or something proprietary
though even on devices that implement the sd host controller interface sometimes they are pretty broken and you have to write values to fields that are marked as RO in the spec (e.g. a register where you are supposed to discover supported voltages from so then the generic driver can properly read them from there) 
is that not legal?
my laptop have 0 and 2 lapic ids
idk otherwise who cares
if it works anyways
we know firmware devs are insane
theres even a cpuid to discover how many bits are used for each field
yes
My old PC starts at 16 and doesn't match CPUID 
Looks like future snapdragon laptops will be acpi only
Thank god
huh
cc @wind fiber
If someone has that Linux kernel with uACPI, I'd be willing to test
@fiery turtle i have some problems with implementing uacpi, somehow the compiler wont see the uacpi functions but the ide sees them perfectly
https://codeberg.org/aiqe/forward/src/branch/main/kernel/src/acpi/acpi_init.c
compiler errors:
src/acpi/acpi_init.c: In function āacpi_initā:
src/acpi/acpi_init.c:9:24: error: implicit declaration of function āuacpi_initializeā [-Wimplicit-function-declaration]
9 | uacpi_status ret = uacpi_initialize(0);
| ^~~~~~~~~~~~~~~~
src/acpi/acpi_init.c:14:11: error: implicit declaration of function āuacpi_namespace_loadā [-Wimplicit-function-declaration]
14 | ret = uacpi_namespace_load();
| ^~~~~~~~~~~~~~~~~~~~
src/acpi/acpi_init.c:19:11: error: implicit declaration of function āuacpi_namespace_initializeā [-Wimplicit-function-declaration]
19 | ret = uacpi_namespace_initialize();
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
src/acpi/acpi_init.c:24:5: error: implicit declaration of function āuacpi_set_interrupt_modelā [-Wimplicit-function-declaration]
24 | uacpi_set_interrupt_model(1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
src/acpi/acpi_init.c:25:11: error: implicit declaration of function āuacpi_finalize_gpe_initializationā [-Wimplicit-function-declaration]
25 | ret = uacpi_finalize_gpe_initialization();
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
What compile options for uacpi
Anyway the most likely reason is you have barebones mode enabled
yes
wait
didnt i say that
oh yeah im stupid
yeah, i use barebones mode
is there smth wrong with it
well those functions dont exist in barebones mode
barebones mode only includes tables.h
uacpi needs pci, pci needs interrupt controller, interrupt controller (apic) needs uacpi
well ig i could bootstrap pci with pic
thats why theres the early_table_access helper
so u can parse static tables before doing aml or allocations or anything
and uacpi doesnt need pci until you start running aml
oh okay thanks
gpfs with error code 0 in at if (uacpi_signatures_match(hdr, ACPI_FACS_SIGNATURE)) somehow, what could this relate to
static void dump_table_header(
uacpi_phys_addr phys_addr, void *hdr
)
{
struct acpi_sdt_hdr *sdt = hdr;
if (uacpi_signatures_match(hdr, ACPI_FACS_SIGNATURE)) {
uacpi_info(
"FACS 0x%016"UACPI_PRIX64" %08X", UACPI_FMT64(phys_addr),
sdt->length
);
return;
}
if (!uacpi_memcmp(hdr, ACPI_RSDP_SIGNATURE, sizeof(ACPI_RSDP_SIGNATURE) - 1)) {
struct acpi_rsdp *rsdp = hdr;
uacpi_info(
"RSDP 0x%016"UACPI_PRIX64" %08X v%02X (%6.6s)",
UACPI_FMT64(phys_addr), rsdp->revision >= 2 ? rsdp->length : 20,
rsdp->revision, rsdp->oemid
);
return;
}
uacpi_info(
"%.4s 0x%016"UACPI_PRIX64" %08X v%02X (%6.6s %8.8s)",
sdt->signature, UACPI_FMT64(phys_addr), sdt->length, sdt->revision,
sdt->oemid, sdt->oem_table_id
);
}
Bad implementation of uacpi_kernel_map
that workaround should work i suppose
void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len)
{
void *AddrVirt = (uint64_t)addr + offset;
return (void *)AddrVirt;
}
i feel like its incredibly stupid but cant prove it because im incredibly stupid 
though it didnt work
š
at least use the hhdm
i mean, if you mapped all of it it should work then
You probably don't want to map everything in the HHDM
i mean, for uacpi you could do that
especially if running in the kernel
Sure, but you don't want to do that
The physical memory could have anything, things that may need different caching modes etc.
You can even get machine checks due to mapping shit improperly
Eg MTRRs not liking huge pages in some cases
Can't work
Not everything that ACPI will want is gonna be in the HHDM
unless you map everything in the HHDM but that will require you to map most stuff UC + 4K or things like Evalyn described will happen
if your kernel cant easily impl this api then u are not ready to impl uacpi
u have other things to worry about
How did you manage to gpf with this tho
At least add logs
To trace what you return
in theory you could map it to the HHDM region on demand if you are very careful when you construt it but in many cases its not worth it
eg mapping the memory map exactly and when using large pages make sure they dont spill over into unknown memory
Loongarch64 would also let you cheat this with DMWs since it's a safe way to have an HHDM of all physical memory and with different caching modes
But again it's much easier to just have a proper virtual memory allocator
You won't be starving for virtual address space especially if you support 5 level paging
And you will need this later regardless
Or atleast grab the QEMU log and addr2line it
Yep
https://github.com/uACPI/uACPI/releases/tag/6.0.0
I've just released uACPI 6.0.0, this one is pretty important as it includes a lot of bug fixes
me (again), still on 3.2.0:
woaw based
thanks for the update, i have blessed my os with version 6.0.0
let's see
Next up I want to add an ability to attach arbitrary user data to a uacpi namespace node (to simplify uacpi-linux), and an optional 64-bit division platform helper
I wonder if uACPI for Linux is ever going to be a real thing
As opposed to a tech demo
Considering it fixed a bunch of stuff for reactos...
That just needs a bunch of work put in
uacpi 33.0.0
Nah the work is mostly on the uacpi linux side
Linux 33.0.0
just updated to latest
have there been any changes to the gpe code, or my kernel is broken?
the power off button does not send any ec gpe
ok nvm, you removed the got gpe message 
february/march i think
Maybe that was your kernel
nice! new NT regression after recent update
am i supposed to migrate my pc to uacpi now 
XD
thought i was going crazy... but actually, uacpi_find_devices ignores devices whose _STA reports they're not active (skrill issue)
yes
Did you run into some issue because of that
nah, it's not for real hw
i am implementing memory hotplugging, and obviously unplugged memory is reported as not present
yes 
are you planning to support CPU hotplugging as well?
that sounds like hell
yes
it's the 2 things i want to do before continuing
i should create a thread tbh once i clean some things up
Actually cpu hotplug shouldn't be that bad now that I think of it
You "just" try migrating everything
yeah
what did you do
Booted my computer
Isn't it basically the same as CPU parking?
yes
actually I'll look into this eventually
implementing hotplug support is not necessary for having in your os support for software disabling cpus during runtime, making them sleep for a long time and whatever
doesn't really seem that hard
i just want to get my hands dirty with acpi
(aka match processors to processor objects and call _ej0)
based?
hmm @fiery turtle what could cause uacpi to hang before saying it loaded all the tables and did tot ops in tot ms?
gdb
if i had to guess it hangs in your allocator
yeah just add a bunch of prints
another strange thing would be the messages for port 0
tho maybe that's another process
and i'm gonna check it now
hmm, no, it's uacpi
i think it's hanging on the pci read or something? since that's where i'm using ports
Create namestring just allocates
ok, i think it 100% is pci stuff
for some reason on kvm it doesn't request pci reads / writes before i call send mcfg
but on real hw yes
the hanging is caused by the pci service not responding bc it's not active yet
ok, it was 100% the pci stuff
it is doing pci operations during namespace load
once debug and once information 
inb4 switch on log type but no break;
small typo in include/uacpi/types.h:37
okay, so, i have written a wrapper for _OST, but i am not sure if it's entirely correct
int
acpi_device_ost(uacpi_namespace_node *node, unsigned int source_event,
unsigned int status_code)
{
uacpi_status status;
uacpi_namespace_node *ost;
uacpi_object_array args;
uacpi_object *arg0, *arg1, *args_ptr[3];
status = uacpi_namespace_node_find(node, "_OST", &ost);
if (status == UACPI_STATUS_NOT_FOUND) {
return 0;
} else if (status != UACPI_STATUS_OK) {
return -1;
}
arg0 = uacpi_object_create_integer(source_event);
if (!arg0) {
return -ERROR_OUT_OF_MEMORY;
}
arg1 = uacpi_object_create_integer(status_code);
if (!arg1) {
free(arg0);
return -ERROR_OUT_OF_MEMORY;
}
args_ptr[0] = arg0;
args_ptr[1] = arg1;
args_ptr[2] = UACPI_NULL;
args.count = 3;
args.objects = args_ptr;
status = uacpi_execute(ost, nullptr, &args);
free(arg0);
free(arg1);
if (uacpi_likely_success(status)) {
return 0;
} else {
return -1;
}
}
is this the right way of passing optional arguments?
specifically, _OST takes three arguments: arg0 (integer), arg1(integer), arg2(optional buffer)
I redirected dbg to screen
when the spec says "may be null" it probably means the buffer may be empty
you cant pass 2 arguments to methods that accept 3
you also cant just free the arguments, you must use uacpi_object_unref
since aml can just arbitrarily grab a reference to it and you wont know
oh okay
so, how do i create an empty buffer? do i use uacpi_object_create_buffer, with view.length = 0, or how?
yeah
perfect then
lmao
_OST for memory hotplug in qemu is just this
tbf, there's not much useful stuff that qemu can do
at most, print a message or trace _OST calls, which is what it does
makes sense lol
I know this is mostly NIH but using a whole ACPI system feels kinda like cheating
Is there a way to trim uACPI down to just an AML interpreter
From the git it seems to also do those:
A fairly advanced event subsystem (GPE/fixed, wake, implicit notify, AML handlers)
Table management API (search, dynamic installation/loading, overrides, etc.)
Operation region subsystem (user handlers, support for BufferAcc opregions, builtins for common types)
Sleep state management (transition to any S state, wake vector programming)
PCI routing table retrieval & interrupt model API
Device search API
Interface & feature management exposed via _OSI
Client-defined Notify() handlers
Firmware global lock management (_GL, locked fields, public API)
GAS read/write API
btw infy, how can i fix those warning during namespace load?
you can use or not use all that stuff
i didn't think it wanted to interact with pci things during namespace load
you cant, its a genuine bug in your firmware
well well well...
least buggy firmware:
this one is relatively harmless at least
at this point I'm convinced firmware devs are paid by microsoft to add bugs to firmware
well, i have a pci write / read before loading now
it is legacy only
but should help a bit XD
u can parse mcfg before namespace load no? lol
no
uacpi wants namespace loaded at least
with my current method i mean
i use uacpi_find_devices_at
table_find("MCFG")?
hmm, i do it on the callback of uacpi_find_devices_at
anyway legacy access works fine
u should see the same warnings under linux btw
with acpica
oh
check your dmsg
š
dw, it's not over for you
https://nasm.org and https://nasm.us -- guess which one is for the assembler we all love
What the fuck š
(because i already knew)
never heard of nasm.org tho, wtf is that
nasm.us for sure
I went to that site way too many times
me writing my own aml parser and shi cuz uacpi is too complex: ._.

im sure there isn't a reason it's so complex and it's just like that because infy likes writing complex code :p
lounge-2
not even
if(firmware_is_bugged()) {
panic("buggy firmware I aint even gonna bother");
}
this always panics
does this check just return true always?
it calls is_computer_on()
yeah it's 100% right about 90% of the time
gcc gonna optimize that into if(1) 
mine is 1000 lines 
if you strip references from AML it could be much simpler
most of the complexity i would say comes from them
and no one really knows how they are supposed to work, especially not the spec
lol
how they are supposed to work
bold of you to assume they're supposed to work in the first place
the entire aml/asl spec is designed around ignoring the existence of edge cases
you would never do multilevel references anyway right 
sureeeee
you would never try to make local references escape the method right 
and if you're the implementor, go figure it out lol
gl
"it worked when we tested it on nt"
"acpica threw errors but it booted so who cares"
the way acpica solves it is by segfaulting
so this whole thing works only becaused firmware engineers made sure to only use the bare minimum of features that never trigger such edge cases
acpica my despised
like its not even anything crazy, e.g.
Method (TEST) {
Return (RefOf(Local0))
}
no one really knows how this is supposed to work
replace aml with jvm bytecode atp š
Like my interpreter.c is 6k loc not counting utility functions, you can probably implement a simple java vm in that many loc
i am now tempted but I must resist
and that's why I'm so tempted š
the worst one jvm has is like invokedynamic or whatever
Also there are better reasons to want to make an AML thing and not use uACPI
even our beloved emulator (qemu) does not implement properly the acpi spec 
for memory devices, The physical address space described by _CRS object must be described using the Extended Address Space Resource Descriptor macro.
what i actually get: a qword memory descriptor
Gg
the q35 machine in qemu is missing an aml field that the spec defines as required for the pci root
there is no consistency or correctness. only what will work under windows
which field?
BBN iirc
i think it can be assumed to 0?
_SEG is defined 0 if missing but _BBN is officially supposed to be required despite being assume 0 if missing in practice
oh yes, you're right
so like it's fine it's just more evidence that the acpi spec is just a suggestion
this is because linux itself only supports this type of descriptor 
im not sure
it uses this macro/function (which is not defined anywhere)
and according to gemini, it converts any memory resource to that
and the qemu aml is capable of creating a dword memory descriptor, if the hp region is in low memory
okay yes, indeed it's happening this
elixir is tweaking for some reason
it's defined in acpica
acpi_resource_to_address64 takes a word, dword or qword descriptor, and converts it to a qword descriptor
drivers/acpi/acpica is excluded from elixir for some reason
and if there is an extended one (the required one by the spec), it fails 
i see
I should add a helper like that
Lmao
I fucking love acpi <3
i hate acpi >:(
fair enough but it works š
It feels like every single company takes spec for almost everything takes it and uses it to wipe their ass after shitting and then proceeding to take a piss on It
yeah pretty much tbh
and then they get mad when other people do that to their specs
Out of curiosity what does AML typically do?
Like does it only contain data, or can it write to ports or memory addresses and crazy stuff like that
find unhandled edge cases in aml interpreters
it does all of them
this is rather annoying
aml allows for some kewl shit like acpi shutdown
and more
so in a sense it does allow memory writes and shit
shutdown would have been good if the s5 slp_type was in the fadt and there were no need of doing whatever _pts garbage
Its a turing complete programming language/byte code
It does everything and anything it wants
Typically programming the chipset, talking to the firmware over SMM and many other things
At that point why donāt hardware developers just write their drivers in AML 
They do ship a lot of power management drivers in aml
Thats how you retrieve the battery percentage for example
Some roll entire i2c drivers
And the nice thing for the kernel is it just runs a method which does this black magic under the hood
Why canāt this apply to more drivers? Like GPU drivers for instance
Imagine AML mode setting
that was called running the rom in v8086 
aml is too much trouble and is not very performant
You get backlight control and even mux control in aml for hybrid laptops
But not modeset yeah
Idk why they never did that
Probably because that wasn't needed and was covered by generic gpu drivers
Whereas backlight and mux is always ad hoc chipset specific stuff
Could also have been too funky across GPU versions to be shipping laptops that may have diff cards?
Well gpus provide the tables themselves
ah true
see, the purpose of AML is pinging an EC that tells a proper microcontroller that runs software written in an actual language to do the actual work

... Do GPUs have AML in them?
yes
Damn
Hm?
which GPUs do that?
for integrated GPUs, the AML is typically embedded in the uefi firmware image
and not in the gpu
Nvidia afaik
Firmware image of what
Where does said image live
Mainboard of the gpu?
no, mainboard
Oh ok no thats not how that works
for integrated gpus? yes, it is
I said Nvidia
for integrated GPUs, the AML is typically embedded in the uefi firmware image
that's what i said
I mean where else would it live for an integrated gpu lol
gpu option rom
but that's not how it's done for integrated
I don't think nvidia has any AML (?)
Definitely does
discrete nvidia gpus?
Yes, ill take a look at a few dumps from desktops later to check
They dont have the Nvidia vendor
But if you grep for a gpu object you will see multiple
One for integrated and one for discrete
which vendor do they have?
Ill get back to you
$ grep -rio 'GFX.' | uniq
DSDT.dsl:GFX0
SSDT2.dsl:GFX0
SSDT2.dsl:Gfx
SSDT2.dsl:GFX0
only has integrated
what gpu do you have
this machine has a 1660
but i also never saw it on other desktops
the bus that the card is on is not even in ACPI
you mean as _BBN? That only exposes root ports
no, i mean as _ADR
_ADR doesnt include the bus
how do you address a device on a non root bus then?
yeah it would have to be under a parent bridge dev, so like the pcie root port device ig
yeah nothing on my amd desktop, i have like 3 tables with gfx, but i think they're all talking about the embedded gpu
yeah okay it has a device there but that's supplied by the firmware
not by the gpu
and it only has generic stuff, nothing nvidia specific
i could've sworn i had a table on my rtx2080 that had nvidia stuff
but this one is 5xxx series
that'd mean that the option rom would need to install it
yeah
which is not impossible but kinda rare
proprietary devices do this sometimes (e.g., to boot from raid) but there's probably no point in doing it for a gpu
since you'll have a driver anyway once you're in the proper OS
so like, in a setup with a desktop motherboard, the cpu is not known at firmware compile time
so someone has to install it dynamically
i mean e.g. the amd integrated gpu tables
you think it has a hardcoded set of supported igpus?
What if i plug in a zen6 cpu that didnt exist when it was made
maybe
the gop driver is also in the bios image on intel
yeah
idk how it works on AMD. AMD has a wider set of CPUs per socket, so maybe they're doing it in a less static way
perhaps
The UEFI ROMs can install tables at runtime
yes, it's clear that they can do it, the question is whether they do it in practice
Is there any way obtain the uacpi_generic_region_info associated with a UACPI_OBJECT_OPERATION_REGION?
I'm figuring out what all needs to be done for the Linux integration. acpi_check_address_range seems to require something like that.
But Linux integration already exists, or are you doing something else?
From what I saw, a decent number of the functions were not implemented such that linux got the full use of them (including acpi_check_address_range and acpi_initialize_subsystem).
Ill have to get back to you because idk what check_address_range does off the top of my head, but iirc most unimplemented functions were either not super useful or something very misc
If the most up to date version is the repository posted online, then it seems to lack at least some of the functionality that Linux uses to protect against buggy firmware.
Yeah its possible
Are you working on improving the port?
If anything, since linux is using uacpi source directly, it can just import the private api from internal/ and access any fields of an object
Unfortunately
quick question, is IVRS something you'd want to have upstream
also, are you taking sloperated imhex patterns for tables 
yeah ofc, any tables are welcome
what is that?
hex editor that has a pattern lang for dissecting stuff
we would probably need a separate "disassembler" project for that like iasl in acpica
have u tried running that table against iasl btw
it can disassemble stuff nicely
its just iasl ivrs.dat
yep
i typically just do iasl *.dat to get the disassembled versions for all tables in a dump
yeah it decodes IVRS as well
ive got a non-slop imhex pattern for table headers and also has a thing for pkglen decoding
its very nice
how is your aml project going btw
i havent done any dev on anything in weeks and im sad about it. might work more tonight if i can get the motivation to cooperate tho
ah damn
oh also theres a massive thunderstorm coming with a tornado watch so i might end up sheltering in the basement instead of doing dev work tonight lmao
its not uncommon here this time of year, and ive never actually been caught in a tornado despite that
but still will play it safe if theres a warning on one
where do you live?


