XSDT struct padding problem

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
interrupt
Posts: 4
Joined: Thu Mar 03, 2016 10:48 am

XSDT struct padding problem

Post by interrupt »

I'm trying to retrieve the IOAPIC address from the ACPI table. I succeeded to get the pointer address to the XSDT. I tried to get the SDTs' addresses from the XSDT structure. Unfortunately, the addresses were incorrect : 0x7ef300000000000, 0x7ef200000000000, 0x7ef100000000000 instead of 0x7ef30000, 0x7ef20000, 0x7ef10000 and 0x7ef40000, i.e. on the example below the address of the SDTs field in my XSDT structure points to 0x4 where it should point to 0x0.

0x0
|
07ef40000 00000000 07ef3000 00000000 07ef2000 00000000 07ef1000 00000000

The SDTheader and XSDT structures :

Code: Select all

struct SDTheader {
	char signature[4];
	uint32_t length;
	uint8_t revision;
	uint8_t sum;
	char OEMid[6];
	char OEMtableId[8];
	uint32_t OEMRevision;
	uint32_t creatorID;
	uint32_t creatorRevision;
} __attribute__((packed));
struct XSDT {
	struct SDTheader header;
	uint64_t sdts[];
} __attribute__((packed));
Furthermore, I realized my XSDT structure was 0x28 bytes wide instead of 0x24 and discovered there was some kind of "padding" between the last field and the first one. The padding was 0x4 bytes wide, which might explain the difference. This seems to be related to the problem mentioned above : if I subtract 0x4 from the address of stds[0], I get the right address.
This is strange as I put __attribute__((packed)) to avoid such a problem.

Has anyone an idea on why is there a padding ?
I'm using UEFI and a cross-compiler targeting x86_64-w64-mingw32 as shown in UEFI Bare Bones.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: XSDT struct padding problem

Post by BrightLight »

I've tried my best to understand your question, and here goes.
The XSDT contains 64-bit pointers to the ACPI tables. On x86(_64), these pointers are in little endian order. The least significant byte is stored first in memory. This also means the least significant DWORD of the QWORD are stored first in memory. There doesn't seem to be anything wrong with your XSDT. So if the first ACPI table was at 0x01010101FFEECCDD, that entry would look like this in a hexdump:

Code: Select all

DD CC EE FF 01 01 01 01
Or if using DWORDs instead of bytes:

Code: Select all

FFEECCDD 01010101
EDIT: Just noticed your first statement.
interrupt wrote:I'm trying to retrieve the IOAPIC address from the ACPI table.
By default, the first I/O APIC is at 0xFEC00000 and the local APIC is at 0xFEE00000.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
interrupt
Posts: 4
Joined: Thu Mar 03, 2016 10:48 am

Re: XSDT struct padding problem

Post by interrupt »

By default, the first I/O APIC is at 0xFEC00000 and the local APIC is at 0xFEE00000.
I'd rather use a safe way to get the I/O APIC address and there's not just the FADT I want from the ACPI.
So if the first ACPI table was at 0x01010101FFEECCDD, that entry would look like this in a hexdump:
Code:

Code: Select all

DD CC EE FF 01 01 01 01
That's exactly my point. I should have :

Code: Select all

00000000 07EF3000
And I've got :

Code: Select all

07EF3000 00000000
And it seems to come from the padding between the two fields of the XSDT (as my sdts field now points to the wrong address and the padding "shifts" the rest to the right).
MDenham
Member
Member
Posts: 62
Joined: Sat Nov 10, 2012 1:16 pm

Re: XSDT struct padding problem

Post by MDenham »

omarrx024 wrote:I've tried my best to understand your question, and here goes.
The XSDT contains 64-bit pointers to the ACPI tables. On x86(_64), these pointers are in little endian order. The least significant byte is stored first in memory. This also means the least significant DWORD of the QWORD are stored first in memory. There doesn't seem to be anything wrong with your XSDT. So if the first ACPI table was at 0x01010101FFEECCDD, that entry would look like this in a hexdump:

Code: Select all

DD CC EE FF 01 01 01 01
Or if using DWORDs instead of bytes:

Code: Select all

FFEECCDD 01010101
The problem he's running into is that the least significant dword is getting written into an area that's apparently turning into padding when there shouldn't be padding between the header and the array of pointers. As a result, everything's shifted over 32 bits. (Specifically, what's happening is the uint64_t array is getting aligned to 8-byte multiples when he doesn't want it aligned.)

I suspect the compiler isn't respecting __attribute__((packed)) correctly with respect to uint64_t; you could try adding __attribute__((aligned (4))) to the sdts[] declaration and see if that fixes things (it should as that ought to override whatever is making the compiler think they need to be 8-byte aligned, but the real question is why it's thinking that in the first place...).
interrupt
Posts: 4
Joined: Thu Mar 03, 2016 10:48 am

Re: XSDT struct padding problem

Post by interrupt »

you could try adding __attribute__((aligned (4))) to the sdts[]
This doesn't change a thing. I still get 0x7EF300000000000.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: XSDT struct padding problem

Post by BrightLight »

interrupt wrote:
you could try adding __attribute__((aligned (4))) to the sdts[]
This doesn't change a thing. I still get 0x7EF300000000000.
Is there any code? Can you try to read the first uint64 from the XSDT? What is the value there?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: XSDT struct padding problem

Post by BrightLight »

interrupt wrote:I'd rather use a safe way to get the I/O APIC address and there's not just the FADT I want from the ACPI.
The I/O APIC and local APIC addresses are in the MADT, not the FADT. All you'd like from the FADT is the DSDT and the PM1a_EVENT/CONTROL blocks.
interrupt wrote:That's exactly my point. I should have :

Code: Select all

00000000 07EF3000
And I've got :

Code: Select all

07EF3000 00000000
And it seems to come from the padding between the two fields of the XSDT (as my sdts field now points to the wrong address and the padding "shifts" the rest to the right).
When you read a QWORD from the XSDT, you get 0x07EF300000000000? I wouldn't think so.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
interrupt
Posts: 4
Joined: Thu Mar 03, 2016 10:48 am

Re: XSDT struct padding problem

Post by interrupt »

omarrx024 wrote:The I/O APIC and local APIC addresses are in the MADT, not the FADT. All you'd like from the FADT is the DSDT and the PM1a_EVENT/CONTROL blocks.
Ah yes, I confused the FADT with the MADT. It's the I/O APIC address field from the MADT I need.
omarrx024 wrote:Is there any code? Can you try to read the first uint64 from the XSDT? What is the value there?
I'm using UEFI, so I've just got to print the value of xsdt->stds.
The signature (the first uint64) is valid ("XSDT", or 0x58 0x53 0x44 0x54).
omarrx024 wrote:When you read a QWORD from the XSDT, you get 0x07EF300000000000?
Actually 0x07EF300000000000 is the first value pointed by the sdts[] field.

EDIT:
I didn't call ExitBootServices yet, so I still can use UEFI protocols.
Post Reply