#lord84
1 messages ยท Page 1 of 1 (latest)
If it ever achieved time travel we would know about it by now
He would've travelled in the past and talked to us

u unconditionally use xsdt if revision is >= 2
u must check that its not null and fall back to rsdt if it is
what if I use xsdt if it's not null
dont u use uacpi
ACPIRSDPHeader* rsdp = (ACPIRSDPHeader*)Arch_MapToHHDM(Arch_LdrPlatformInfo->acpi_rsdp_address);
bool tables32 = rsdp->Revision == 0;
ACPISDTHeader* xsdt = tables32 ? (ACPISDTHeader*)(uintptr_t)rsdp->RsdtAddress : (ACPISDTHeader*)rsdp->XsdtAddress;```
that's what I do
if rev is 1 and u use xsdt it might contain random garbage
np
Yeah re read my message please
xsdt is not guaranteed to be present on any ACPI system, even if its revision is greater than or equal to 2
instead you're expected to do this:
if (rsdp->revision >= 2) {
if (rsdp->xsdt_address != NULL) {
// Use the XSDT
} else {
// Use the RSDT
}
} else {
// Use the RSDT
}```
what if the timeline doesn't work that way
hope this helped ๐
in firmware world nothing is guaranteed
and it needs no special handling
I understand why it may seem useful but it just confuses whoever looks at your codebase
except for whatever the terminal emulator does with \n
I'd assume you have some issue with memcmp, especially if you implemented it yourself
otherwise I'm not sure of why this comparison would fail, other than some other weirdness we can't see
it's not that unclear, it's pretty immediately evident what the intent behind it is, formatting, so you can fairly easily extrapolate what's actually happening
I'm sorry but doing {n} for a newline is quite confusing for me
and that's not really a formatting specifier
ahhh x3
I mean, if you see 'weird' syntax within a printf call it's p safe to assume it's custom formatting
sure, it makes it more confusing to new people coming to the codebase, but there's not much reason to complain unless you're planning on trying to contribute
Idk for me a formatting specifier = 1 argument
wdym
This is why you enable warnings
-Wall -Wextra -pedantic -Werror -pedantic-errors
If there's %n or {n} I expect there to be one parameter that maps to that argument
meh, that's fair enough
too each their own I suppose
You can use gdb to pause on the instruction after the write to cr3, and it'll let you explore the memory mappings before it faults
Info mem and friends are helpful
But also maybe print out what regions youre mapping so sanity checking
How does a write to cr3 fail, did you miss?
Ah I guess there are certain bits than can't be set
What's the value you're trying to write, and the code that does it
the hpet comparators let you select what gsi they fire.
also for the purpose of calibration you dont need interrupts, you can poll the main counter
yeah the first 2(?) comparators tend to only support fixed routing for the legacy compat mode
where it replaces the PIT and something else - rtc timer?
fair, but you also add complexity (and possibly to other parts of your kernel) for stuff you'll never use ๐
you dont need to make use of everything the hardware offers
just take what features you want and get on with what you wanted to do
I say this as someone who used to add support for everything, but it gets exhausting when you get to more complex devices ๐
or maybe that's his first iteration
orrr maye the time period he chose to go back to
is a bit more later than now
I recommend doing PCIe, it's much better
Memory mapped, has a consistent access mechanism
yes
all pci devices should show up
what frosty recommends here is actually called ECAM, not PCIe. Its just a more modern PCI device discovery mechanism
From wikipedia
The second method was created for PCI Express. It is called Enhanced Configuration Access Mechanism (ECAM). It extends device's configuration space to 4 KB, with the bottom 256 bytes overlapping the original (legacy) configuration space in PCI. The section of the addressable space is "stolen" so that the accesses from the CPU don't go to memory but rather reach a given device in the PCI Express fabric. During system initialization, BIOS determines the base address for this "stolen" address region and communicates it to the root complex and to the operating system.
oh yeah. forgot that the access mechanism is named differently from the bus type
regardless, its much better
is each header 4k?
btw not a good idea to read anything memory mapped as a C struct, there's a good reason why READ_ONCE and stuff is a thing in Linux
Nice
what type of heap was it?
how did you implement the old one
I'm genuinely curious how you made it that slow
ah
how big was the heap?
interesting
thats only 1MiB
seems fairly simple. looks more like a PMM that a kernel heap though...
yes
4095/4096 = 0
so you would allocate nothing
you should be aligning up
pages_to_alloc would be 0
so no iterations
just align up
then no confusion
Your math ain't mathin
I just use 2 macros:
#define DIV_ROUNDUP(VALUE, DIV) ((VALUE + (DIV - 1)) / DIV)
#define ALIGN_UP(VALUE, ALIGN) (DIV_ROUNDUP(VALUE, ALIGN) * ALIGN)
I should start doing that
My kernel once had a bug because of a typo while aligning
I think I first stole those macros from limine
this is inefficient for powers of two
GCC will optimise as long as I'm using constants
if not, then I'll have to use some other magic to make it fast
in my old kernel I had a log base 2 function for this purpose
i just do this
#define ALIGN_UP_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define ALIGN_UP(x, val) ALIGN_UP_MASK(x, (typeof(x))(val) - 1)
#define ALIGN_DOWN_MASK(x, mask) ((x) & ~(mask))
#define ALIGN_DOWN(x, val) ALIGN_DOWN_MASK(x, (typeof(x))(val) - 1)
#define IS_ALIGNED_MASK(x, mask) (((x) & (mask)) == 0)
#define IS_ALIGNED(x, val) IS_ALIGNED_MASK(x, (typeof(x))(val) - 1)
#define PAGE_ROUND_UP(size) ALIGN_UP(size, PAGE_SIZE)
#define PAGE_ROUND_DOWN(size) ALIGN_DOWN(size, PAGE_SIZE)
that's probably better
that only works for powers of 2
In compiler optimizations I trust
when was the last time u aligned to something else
it is not the same thing, is all i am saying
thats true ye
Only place I even remember aligning in is in my vma and FdSeek
the "better" version of my version would be to special case powers of 2, but in any case that wasn't the intent of the macros
they are not performance sensitive
in Limine's case
yeah thats how linux does it i think
i'll probably do that anyways
these things just get under my skin in the sense that i have to sort it out after it's pointed out to me lol
size of one bus
btw why not write the code like: ```cpp
void check_function(uint64_t bus, uint64_t slot, uint64_t function) {
if(header_for(bus, slot, function)->vendor == 0xFFFF) return;
// do whatever
}
void check_slot(uint64_t bus, uint64_t slot) {
uint64_t max_functions = 1;
if(header_for(bus, slot, 0)->vendor == 0xFFFF) return;
if(header_for(bus, slot, 0)->type & MULTI) max_functions = 8;
for(uint64_t function = 0; function < max_functions; function++) {
check_function(bus, slot, function);
}
}
void check_bus(uint64_t bus) {
for(uint64_t slot = 0; slot < 32; slot++) {
check_slot(bus, slot);
}
}
functions 1-7 are handled exactly the same as function 0, except for the extra check for multifunction in function 0
anyway base + (bus << 20) + (slot << 15) + (function << 12) should work for computing the address
i don't know why it doesn't work for you
mcfg does not talk about slots at all?
each mcfg entry covers buses N-M and you check all the slots there
or well, there are ways to avoid doing all the extra work of scanning empty slots, but that works too
why require the square brackets around labels?
Lock around any resource that needs it
So if your print functions touch some state in a way that needs to be synchronized, put a lock there
Ideally you would do as much per-core or per-thread as possible and only protect the global state, like the outputs where your logs go
You can even go lock free if youre feeling clever
๐ฆ
Generally you want to hold the lock as little as possible
And yeah you also have to think about what the purpose of the lock is.
Like locking around the framebuffer everytime you write a character is kind of pointless, because what if two cors want to write there
You'd get multiple messages interleaved
You probably want to output a single line of text (or maybe a single message) at a time, I'm assuming we're only thinking about the framebuffer as a way to output logs
Agreed, and that's also super error prone. Now you have to remember that every time.
Possibly, your lock should be around your shared state
Sorry if this isn't making much sense, I'm quite tired
First figure out what you're trying to protect: what parts of the code would cause problems if multiple people executed it.
Yeah nice
Flanterm also has some internal state, so that would also need locking, but it's the same idea. You're already preventing multiple accesses.
NP ๐
Make sure you have caching synced between CPUs
The PAT MSRs might be different
And MTRRs
And make sure cr0.cd is 0
(cache disable)
you really don't need to put (uint64_t*)
The PAT MSRs should be the same on all CPUs
And the APs should not affect the BSP performance if they are doing nothing
Afaik
if you want i can test your os on 2 computers
it emulated as ahci
in firmware setup
and I have sata disk
it's an old pc with amd athlon 2
okay I'll try to test on more modern pc
This is my thread now
