Page 1 of 1

UEFI Bootloader - ACPI Problem

Posted: Wed Dec 02, 2015 3:47 pm
by albus95
So following my adventure into making a bootloader using uefi and a karnel I must doing somethingh wrong.
Right now I'm "parsing" ACPI tables to get hardware info.

So I have this code that loop through all the table he could find in the :

Code: Select all


#pragma pack(1)

typedef struct {
	EFI_ACPI_DESCRIPTION_HEADER  Header;
	UINT64                       Entry;
} XSDT_TABLE;

#pragma pack()

VOID ParsingACPITables(EFI_ACPI_6_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Structure, CS_BOOT_INFO *BootInfo)
{
	UINT64  EntryPointer = 0;
	UINT32  EntryCount = 0;
	UINT64   BasePtr;

	XSDT_TABLE *Xsdt = NULL;
	EFI_ACPI_DESCRIPTION_HEADER *CurrentTable = NULL;

	//
	// If XSDT table is find, just install its tables. 
	// Otherwise, try to find and install the RSDT tables.
	//
	if (Structure->XsdtAddress)
	{
		Xsdt = (XSDT_TABLE *)Structure->XsdtAddress;
		if (Xsdt == NULL)
		{
			Print(L"Invalid Xsdt! Parsing ACPi Failed!\n");
			return;
		}

		EntryCount = (Xsdt->Header.Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
		BasePtr = (UINT64)&(Xsdt->Entry);
		Print(L"Got %d Table Entries, BasePtr: 0x%x\n", EntryCount, BasePtr);

		for (UINTN Index = 0; Index < EntryCount; Index++)
		{
			CopyMem(&EntryPointer, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
			CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)EntryPointer);

			if (CurrentTable != NULL)
			{
				//TODO: Compute the cecksum ot the table
				if (IsValidTable(CurrentTable))
					ParseAcpiTable(CurrentTable, BootInfo);
				else
				{
					//TODO: Error Reporting.
				}
			}
			else
			{
				//TODO: Other Table Structs??
				//TODO: Table Above 6 is buggy, what they are??
				Print(L"Invalid Table\n");
				break;
			}
		}
	}
	else if (Structure->RsdtAddress)
	{
		//TODO: Do Other Table Parsing Rsdt for example.
		//TODO: Old Hardware, not supported for now, more important stuff before.
	}
}
Than In the ParseAcpiTable function I identify table by signature:

Code: Select all

#define BEGIN_DECLARE_STRUCT(Type, Name, Address) Type *Name = (Type *) Address; \
												if(Name != NULL) \
												{

#define END_DECLERE_STRUCT(Name) }	\
							else { Print(L"Got invalid table: "); \
								   Print(L#Name);	\
								   Print(L"\n"); }

CHAR8 *Signature = (CHAR8*)&((EFI_ACPI_DESCRIPTION_HEADER *)CurrentTable)->Signature;

//Other table parsing code
	if (AsciiStrnCmp(Signature, "APIC", 4) == 0)
	{
		Print(L"APIC\n");
		BEGIN_DECLARE_STRUCT(EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER, Apic, CurrentTable);
		{
			//Now Query For APIC Interrupts
			if (Apic->Flags & EFI_ACPI_6_0_IO_APIC)
			{
				Print(L"Got IO APCI Interrupt, Falg: 0x0%x\n", Apic->Flags);
				BEGIN_DECLARE_STRUCT(EFI_ACPI_6_0_IO_APIC_STRUCTURE, IoInterrupt, (UINT_PTR)Apic->LocalApicAddress);
				{
					Print(L"Flag: %d, Lenght: %d, Io Apic Address: 0x%X  Global Interrupt Table At: 0x%X\n",
						IoInterrupt->Type,
						IoInterrupt->Length,
						IoInterrupt->IoApicAddress,
						IoInterrupt->GlobalSystemInterruptBase);
				}
				END_DECLERE_STRUCT(EFI_ACPI_6_0_IO_APIC_STRUCTURE);
			}
			if(Apic->Flags & EFI_ACPI_6_0_PLATFORM_INTERRUPT_SOURCES)
			{
				Print(L"Got platform Interrupt Sources Interrupt, Falg: 0x0%x\n", Apic->Flags);
				BEGIN_DECLARE_STRUCT(EFI_ACPI_6_0_PLATFORM_INTERRUPT_APIC_STRUCTURE, PlataformInt, (UINT_PTR)Apic->LocalApicAddress);
				{
					Print(L"Got Cpu With Id 0x%d\n", PlataformInt->ProcessorId);
				}
				END_DECLERE_STRUCT(EFI_ACPI_6_0_PLATFORM_INTERRUPT_APIC_STRUCTURE);
			}
		}
		END_DECLERE_STRUCT(EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
	}
//Other table parsing coe
Bu as it seem the IoInterrupt have all the field set to null for some reason. It happen the same with the facs struct

Code: Select all

if (AsciiStrnCmp(Signature, "FACP", 4) == 0)
	{
		Print(L"FACP\n");
		BEGIN_DECLARE_STRUCT(EFI_ACPI_6_0_FIXED_ACPI_DESCRIPTION_TABLE, Fadt, CurrentTable);
		{
			Print(L"Version: %d, Creator: %d, Hypervisor: 0x%x, Flags: 0x%x\n", Fadt->Header.Revision, Fadt->Header.CreatorRevision, Fadt->HypervisorVendorIdentity, Fadt->Flags);

			if (CalculateTableChesum(Fadt) != 0)
			{
				Print(L"Table Corrupted! %d\n", CalculateTableChesum(Fadt));
				return;
			}

			if (Fadt->XFirmwareCtrl != 0)
			{
				//Now Parse FACS
				BEGIN_DECLARE_STRUCT(EFI_ACPI_6_0_FIRMWARE_ACPI_CONTROL_STRUCTURE, Facs, Fadt->XFirmwareCtrl);
				{		
					Print(
						L"Got FACS, Version: %d, Flag: 0x%x, Vector: 0x%x\n",
						Facs->Version, 
						Facs->HardwareSignature,
						Facs->XFirmwareWakingVector
					);
				}
				END_DECLERE_STRUCT(EFI_ACPI_6_0_FIRMWARE_ACPI_CONTROL_STRUCTURE);
			}
		}
	  END_DECLERE_STRUCT(Fadt);
	}
I have no idea why. Any suggestion? I noticy somethingh have to be wrong in the fadt table as per specification if we have the XFirmwareCtrl pointer we should have FirmwareCtrl set to null but on my case they are both set.

Re: UEFI Bootloader - ACPI Problem

Posted: Thu Dec 03, 2015 12:55 pm
by jnc100
You are parsing the MADT wrong. The flags field has only one purpose - to convey the presence of a dual 8259 PIC setup in bit 0. Immediately following the table are the APIC structures (you seem to be trying to read a table at the physical address of the current LAPIC, which is wrong). What you want to do is something like:

Code: Select all

MADT *madt = phys_addr_of_madt;
uintptr_t cur_ptr = 44;  // offset of APIC structures from base of MADT
while (cur_ptr < madt->length) {
    uintptr_t phys_addr_cur_apic = (uintptr_t)madt + cur_ptr;
    uint8_t apic_structure_type = *(uint8_t *)phys_addr_cur_apic;
    uint8_t apic_structure_length = *(uint8_t *)(phys_addr_cur_apic + 1);

    switch(apic_structure_type) {
        case 0:
            LAPIC_STRUCTURE *lapic = (LAPIC_STRUCTURE *)cur_ptr;
            // handle lapic structure
            break;
        case 1:
            IOAPIC_STRUCTURE *ioapic = (IOAPIC_STRUCTURE *)cur_ptr;
            // handle ioapic structure
            break;
        ...
    }

    cur_ptr += apic_structure_length;
}
Its unclear exactly what is wrong with your FADT. One possibility is that the revision of ACPI in your test system is not high enough to support the X_FIRMWARE_CTRL entry and that you are reading the next table (what is your test system?). Try dumping all the entries of the FADT and seeing if the addresses are reasonable.

Also, your use of the DECLARE_ macros makes the code quite difficult to read. You may wish to simplify it when trying to track down bugs like this.

Regards,
John.

Re: UEFI Bootloader - ACPI Problem

Posted: Thu Dec 03, 2015 3:59 pm
by albus95
jnc100 wrote:You are parsing the MADT wrong. The flags field has only one purpose - to convey the presence of a dual 8259 PIC setup in bit 0. Immediately following the table are the APIC structures (you seem to be trying to read a table at the physical address of the current LAPIC, which is wrong). What you want to do is something like:

Code: Select all

MADT *madt = phys_addr_of_madt;
uintptr_t cur_ptr = 44;  // offset of APIC structures from base of MADT
while (cur_ptr < madt->length) {
    uintptr_t phys_addr_cur_apic = (uintptr_t)madt + cur_ptr;
    uint8_t apic_structure_type = *(uint8_t *)phys_addr_cur_apic;
    uint8_t apic_structure_length = *(uint8_t *)(phys_addr_cur_apic + 1);

    switch(apic_structure_type) {
        case 0:
            LAPIC_STRUCTURE *lapic = (LAPIC_STRUCTURE *)cur_ptr;
            // handle lapic structure
            break;
        case 1:
            IOAPIC_STRUCTURE *ioapic = (IOAPIC_STRUCTURE *)cur_ptr;
            // handle ioapic structure
            break;
        ...
    }

    cur_ptr += apic_structure_length;
}
Its unclear exactly what is wrong with your FADT. One possibility is that the revision of ACPI in your test system is not high enough to support the X_FIRMWARE_CTRL entry and that you are reading the next table (what is your test system?). Try dumping all the entries of the FADT and seeing if the addresses are reasonable.

Also, your use of the DECLARE_ macros makes the code quite difficult to read. You may wish to simplify it when trying to track down bugs like this.

Regards,
John.
Thanks for the help. I will investigate for the fadt

Re: UEFI Bootloader - ACPI Problem

Posted: Sat Dec 05, 2015 2:02 pm
by albus95
So either I have stupid error in my code, or the vm play a rule.
On real hardware I get some value, (of course not sure if they are right).
I gonna post the file in which I parse the tables, so if anyone want try help me see the file.
https://www.dropbox.com/s/n5tm8v0dmzsctre/Acpi.c?dl=0

Re: UEFI Bootloader - ACPI Problem

Posted: Sat Dec 05, 2015 2:35 pm
by jnc100
Of course there was a deliberate error in the code I provided: the code that casted to LAPIC_STRUCTURE*/IOAPIC_STRUCTURE* etc should have casted from phys_addr_cur_apic rather than cur_ptr.

Also, you seem to only handle one of every type of structure. Systems will have one LAPIC per processor and any number (but admittedly typically one) of IOAPICs (each can only handle 24 interrupt sources off the top of my head). There are usually at least two interrupt source overrides too, for ISA IRQs 0 and 9.

It would help if you could provide exactly what the errors are. If the structures have the wrong values in them then dump the addresses of the structures you are reading and the contents they have.

Regards,
John.

Re: UEFI Bootloader - ACPI Problem

Posted: Sat Dec 05, 2015 4:09 pm
by albus95
jnc100 wrote:Of course there was a deliberate error in the code I provided: the code that casted to LAPIC_STRUCTURE*/IOAPIC_STRUCTURE* etc should have casted from phys_addr_cur_apic rather than cur_ptr.

Also, you seem to only handle one of every type of structure. Systems will have one LAPIC per processor and any number (but admittedly typically one) of IOAPICs (each can only handle 24 interrupt sources off the top of my head). There are usually at least two interrupt source overrides too, for ISA IRQs 0 and 9.

It would help if you could provide exactly what the errors are. If the structures have the wrong values in them then dump the addresses of the structures you are reading and the contents they have.

Regards,
John.
Ah interesting, this was why I got multiplke tables.
when i read the code there something not look right to me so that was the error you made.
I really not understand why I not fixed it myself.

Re: UEFI Bootloader - ACPI Problem

Posted: Sat Dec 05, 2015 4:22 pm
by albus95
Work now! Thanks for the help. now i need to investigate why the facs is blank.

Re: UEFI Bootloader - ACPI Problem

Posted: Tue Dec 08, 2015 4:24 am
by albus95
Any one have some idea why facs is not working?