Page 1 of 2
ACPI tables for MP identification
Posted: Sun Feb 01, 2009 4:16 pm
by worldsapart
Hi,
wel.. I'm trying to parse the ACPI tables to identify the CPUs.. wel.. It's been a while since i coded in C n I'm kinda rusted... It would be great if some1 could help me correct this code.. it tries to look for the RSDP structure... i know it's somethin wrong wit my usage of pointers or my jus my ignorance.. your help will be appreciated..
Code: Select all
struct RSDPDescriptor {
char Signature[8];
char Checksum;
char OEMID[6];
char Revision;
unsigned int RsdtAddress;
unsigned int Length;
double XsdtAddress;
char ExtendedChecksum;
char reserved[3];
};
k_main() // like main in a normal C program
{
int i =0;
char *address = (char *)0x0000040E;
struct RSDPDescriptor *rsdp;
for(i=0;i<1024;i+=16)
{
rsdp = (struct RSDPDescriptor *)(address + i);
if(mystrcmp((*rsdp).Signature,"RSD PTR ") == 0)
{
k_printf("Found RSDP1",8);
}
}
char *address2 = (char *)0x0E0000;
while(address2<=0x0FFFFF)
{
rsdp = (struct RSDPDescriptor *)address2;
if((*rsdp).Signature == "RSD PTR ")
{
k_printf("Found RSDP2",9);
}
address2 += 16;
}
k_printf("Not Found",10);
}
Wel... the prob is.... It doesnt find the RSDP... PLease let me know if u want more details abt my implementation...
Re: ACPI tables for MP identification
Posted: Sun Feb 01, 2009 4:58 pm
by worldsapart
oh yeah.. i know that.. it was corrected.. thanks.. am sorry for posting the wrong code... anythin else that could be possibly wrong?
Does any1 have any code that I could refer to? Would be really helpful....
Re: ACPI tables for MP identification
Posted: Sun Feb 01, 2009 5:54 pm
by JohnnyTheDon
Yep. From my OS:
acpi.h
Code: Select all
#ifndef ACPI_H
#define ACPI_H
#pragma pack(push, 1)
typedef struct _RSDP
{
char Signature[8];
uint8 Checksum;
char OemId[6];
uint8 Revision;
uint32 RsdtAddress;
} RSDP_t;
typedef struct _RSDT
{
char Signature[4];
uint32 Length;
uint8 Revision;
uint8 Checksum;
char OemId[6];
char OemTableId[8];
uint32 OemRevision;
char CreatorId[4];
uint32 CreatorRevision;
} RSDT_t;
typedef struct _MADT
{
char Signature[4];
uint32 Length;
uint8 Revision;
uint8 Checksum;
char OemId[6];
char OemTableId[8];
uint32 OemRevision;
char CreatorId[4];
uint32 CreatorRevision;
uint32 LapicAddress;
uint32 Flags;
} MADT_t;
typedef struct _MADTSubtable
{
uint8 Type;
uint8 Length;
} MADTSubtable_t;
typedef struct _AcpiLapic
{
uint8 Type;
uint8 Length;
uint8 AcpiId;
uint8 LapicId;
uint32 Flags;
} AcpiLapic_t;
typedef struct _AcpiIoApic
{
uint8 Type;
uint8 Length;
uint8 IoApicId;
uint8 Reserved;
uint32 Address;
uint8 IRQBase;
} AcpiIoApic_t;
#pragma pack(pop)
#define MADT_LAPIC 0
#define MADT_IOAPIC 1
bool inline AcpiChecksum(void* ptr, int size)
{
uint8 accum = 0;
for(int i = 0; i < size; i++)
{
accum += ((uint8*)ptr)[i];
}
return (accum == 0);
}
#endif
Excerpt from my SMP header (mp.h):
Code: Select all
#ifndef MP_H
#define MP_H
// Processor Descriptor
typedef struct _Processor
{
PML4 Pml4; // Processor Specific PML4
IDT Idt; // Interupt Descriptor Table
TSS_t* Tss; // System TSS
virt_addr Stack; // Address of stack for this processor
CpuFeatures_t Features; // Features retrieved from CPUID
uint8 LapicId; // Local APIC ID of this processor
int8 Stage; // Processor Initialization Stage
} Processor_t;
EXTERN Processor_t* MpProcessorTable;
EXTERN uint32 MpProcessorCount;
#endif
Excerpt from my SMP code (mp.c):
Code: Select all
static bool MpGetInfo()
{
// Try to find the RSDP in the BIOS
void* i;
for(i = PTOV(0xE0000); i < PTOV(0xFFFFF); i += 16)
{
if(memcmp(i, "RSD PTR", 7) == 0)
{
if(!AcpiChecksum(i, sizeof(RSDP_t)))
continue;
return MpGetInfoAcpi(i);
}
}
// Try to find the RSDP in the EBDA
uint16 ebdaSegment = *((uint16*)PTOV(0x040E));
for(i = PTOV(ebdaSegment<<4); i < PTOV((ebdaSegment<<4)+0x400); i += 16)
{
if(memcmp(i, "RSD PTR", 7) == 0)
{
if(!AcpiChecksum(i, sizeof(RSDP_t)))
continue;
return MpGetInfoAcpi(i);
}
}
return false;
}
static bool MpGetInfoAcpi(RSDP_t* rsdp)
{
// Use the RSDP to find the RSDT
RSDT_t* rsdt = (RSDT_t*)PTOV(rsdp->RsdtAddress);
if(!AcpiChecksum(rsdt, rsdt->Length))
return false;
// Iterate through the tables to find the MADT
MADT_t* madt;
int tableCount = (rsdt->Length-sizeof(RSDT_t))/4;
int i;
for(i = 0; i < tableCount; i++)
{
madt = (MADT_t*)PTOV(*(((uint32*)(rsdt+1))+i));
if(memcmp(madt, "APIC", 4) == 0)
break;
}
if(i == tableCount) // If we didn't find the MADT, something screwed up
return false;
if(!AcpiChecksum(madt, madt->Length)) // Checksum the MADT
return false;
// Get the number of processors and IO APICs
MpProcessorCount = 0;
for(MADTSubtable_t* sub = (MADTSubtable_t*)(madt+1); (void*)sub < ((void*)madt)+madt->Length; sub = (MADTSubtable_t*)(((void*)sub)+sub->Length))
{
if(sub->Type == MADT_LAPIC)
MpProcessorCount++;
}
if(MpProcessorCount < 1) // There needs to be at least one processor and one IO APIC
return false;
// Allocate processor table
MpProcessorTable = (Processor_t*)MemoryAllocPages(ALIGN_SMALL(sizeof(Processor_t)*MpProcessorCount)/PAGE_SIZE_SMALL, VALLOC_MASK_FLAG_WRITABLE);
if((virt_addr)MpProcessorTable == INVALID_VIRTUAL_ADDRESS)
return false;
// Fill the processor and IO APIC tables
i = 0;
for(MADTSubtable_t* sub = (MADTSubtable_t*)(madt+1); (void*)sub < ((void*)madt)+madt->Length; sub = (MADTSubtable_t*)(((void*)sub)+sub->Length))
{
if(sub->Type == MADT_LAPIC)
{
MpProcessorTable[i].LapicId = ((AcpiLapic_t*)sub)->LapicId;
i++;
}
}
return true;
}
PTOV is a macro for converting from virtual to physical addresses, you will probably want to remove it. There is some other stuff in there that is tied to my OS, but most of it should make sense.
Re: ACPI tables for MP identification
Posted: Sun Feb 01, 2009 6:47 pm
by worldsapart
Thanks a lot man... that should answer my doubts for now..
Re: ACPI tables for MP identification
Posted: Mon Feb 02, 2009 3:24 am
by worldsapart
hi Johnnythedon,
your code was really helpful... was able to clean up my code... n correct a few bugs..
wel, I found the RSDP... n checksumd it, n it was fine.. But then I went on to check the RSDT... there was a signature match... but when i did a checksum, it failed!! ... any idea y this could be??? btw... I'm using Qemu to test my code...
If any1 else has had a similar prob and was able to solve it pls do share it wit me... Thanks...
Re: ACPI tables for MP identification
Posted: Mon Feb 02, 2009 5:00 am
by 01000101
I haven't coded for the ACPI tables (only MP) so far.
if it's reporting an incorrect checksum, check it's supposed address and see what the alignment is, if it's not aligned properly, it's an incorrect structure anyways.
I noticed that you're not searching on an alignment offset (i++, and not i+=16 or similar) for the initial structure, this can lead to issues (if it's like the MP tables).
Also, what's the point of this in the checksum function:
why not just return (accum)?
Re: ACPI tables for MP identification
Posted: Mon Feb 02, 2009 9:44 am
by JohnnyTheDon
01000101 wrote:
I noticed that you're not searching on an alignment offset (i++, and not i+=16 or similar) for the initial structure, this can lead to issues (if it's like the MP tables).
Uh, my code does do that:
Code: Select all
for(i = PTOV(0xE0000); i < PTOV(0xFFFFF); [b]i += 16[/b])
01000101 wrote:
Also, what's the point of this in the checksum function:
why not just return (accum)?
Because its a boolean value, and is tested as such. So
Code: Select all
if(!AcpiChecksum(rsdt, rsdt->Length))
return false;
Would need to be
Code: Select all
if(AcpiChecksum(rsdt, rsdt->Length) == 0)
return false;
Its just defering the checking.
wel, I found the RSDP... n checksumd it, n it was fine.. But then I went on to check the RSDT... there was a signature match... but when i did a checksum, it failed!! ... any idea y this could be??? btw... I'm using Qemu to test my code...
Make sure you are using Length when checksumming. IIRC the whole table is checksummed, not just the header. So you would need to write something like:
Code: Select all
if(!AcpiChecksum(rsdt, rsdt->Length))
return false;
If you use sizeof(RSDT_t) instead of rsdt->Length it won't work.
Re: ACPI tables for MP identification
Posted: Mon Feb 02, 2009 12:13 pm
by worldsapart
Hi... yeah I did use Length, cos I know that the Rsdt is bigger than the structure..... wel.. I'll jus post my code so you can see wat mayb wrong..
my RSDT structure
Code: Select all
typedef struct RSDTable
{
char Signature[4];
int Length;
char Revision;
char Checksum;
char OemId[6];
char OemTableId[8];
char OemRevision[4];
char CreatorId[4];
int CreatorRevision;
}RSDT_t;
my code so far:
Code: Select all
RSDP_t *rsdp; // Structure to hold the RSDP table, defined in k_acpi_tables.h
RSDT_t *rsdt; // Structure to hold the RSDT structure
// Searching for RSDP in 16 byte boundaries
if((rsdp = acpi_find_rsdp())==0)
k_printf("No multiple CPUs", 7);
else
{
// So RSDP has been found.. now what? --> checksum!!
if(acpi_checksum(rsdp,rsdp->Length)!=1)
{
k_printf("RSDP checksum failed..",7);
}
else
{
k_printf("RSDP found!",7);
// parse RSDT.. but first checksum!
rsdt = (RSDT_t*)(rsdp->RsdtAddress);
if(mystrcmp((char*)rsdt,"RSDT",4)== 1)
k_printf("Signature Match",8);
if(acpi_checksum(rsdt,rsdt->Length)!=1)
k_printf("RSDT checksum failed",9);
else
{
k_printf("RSDT Found!",9);
}
}
}
the checksum function is the same as yours, except that returns a integer value, cos I dont have a bool type....
Also, I've read a few bug issues related to the Bochs BIOS that Qemu uses, regarding ACPI issues... could that be the prob??? or is there somethin terribly wrong in my code?
Re: ACPI tables for MP identification
Posted: Mon Feb 02, 2009 4:48 pm
by JohnnyTheDon
A few ideas,
1. Change all your chars to unsigned char (including the checksumming function. It should use unsigned char or you may have issues). While you're at it, make everything unsigned.
2. Make sure int is 32-bits in your compiler.
3. Check what length is.
Re: ACPI tables for MP identification
Posted: Mon Feb 02, 2009 5:44 pm
by worldsapart
i changed al the chars to unsigned... still didnt work..
n... in the checksum wher is the char that u were talkin abt??
also, the size of int is 32bits.... and I am workin on the k_printf function to print integers.. wil check the length n let u know.. but meanwhile.. any more ideas??
Re: ACPI tables for MP identification
Posted: Tue Feb 03, 2009 2:31 am
by worldsapart
i did some more testing n debuggin .. but to no avail... wel.. I have some more info..
The rsdp was found at 0x000FBBC0
This was checksummed and was validated..
the rsdt was found at 0x07FF0000
and the length was 52 ...
but the checksum failed.. could it b a prob cos my bochs bios isnt updated wit bug fixes?
Re: ACPI tables for MP identification
Posted: Tue Feb 03, 2009 8:16 am
by jal
worldsapart wrote:but the checksum failed.. could it b a prob cos my bochs bios isnt updated wit bug fixes?
Never blame the emulator, unless you are really, really sure it's at fault. Did you, for example, Google to find out if anyone else has had this problem with Bochs? If not, you can be pretty sure it's not at fault.
JAL
Re: ACPI tables for MP identification
Posted: Tue Feb 03, 2009 12:07 pm
by worldsapart
I am very sorry.. I know that was pretty lame... It was a small bug in my checksum function.
.. corrected that... Am sorry again guys.
Lesson Learnt!
Re: ACPI tables for MP identification
Posted: Tue Feb 03, 2009 1:56 pm
by jal
worldsapart wrote:Lesson Learnt!
Glad to hear it, and show of character for admitting it :). Good luck with the ACPI stuff.
JAL
Re: ACPI tables for MP identification
Posted: Tue Feb 03, 2009 4:40 pm
by JohnnyTheDon
If you want the use ACPI for more than just finding processors, you may want to look at ACPICA (
http://www.acpica.org ). You have to implement around 30 functions for it to use (basic things MemoryAlloc and WritePort) and it will not only find ACPI tables for you, but also do all your power management and give you all the information you need about your devices. Its kind of big (adds something like 200kb to the size of your kernel), but it gets the job done.