ACPI tables for MP identification

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.
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

ACPI tables for MP identification

Post 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...
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

Re: ACPI tables for MP identification

Post 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....
JohnnyTheDon
Member
Member
Posts: 524
Joined: Sun Nov 09, 2008 2:55 am
Location: Pennsylvania, USA

Re: ACPI tables for MP identification

Post 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.
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

Re: ACPI tables for MP identification

Post by worldsapart »

Thanks a lot man... that should answer my doubts for now.. :)
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

Re: ACPI tables for MP identification

Post 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...
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Re: ACPI tables for MP identification

Post 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:

Code: Select all

return (accum == 0);
why not just return (accum)?
JohnnyTheDon
Member
Member
Posts: 524
Joined: Sun Nov 09, 2008 2:55 am
Location: Pennsylvania, USA

Re: ACPI tables for MP identification

Post 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:

Code: Select all

return (accum == 0);
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.
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

Re: ACPI tables for MP identification

Post 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?
JohnnyTheDon
Member
Member
Posts: 524
Joined: Sun Nov 09, 2008 2:55 am
Location: Pennsylvania, USA

Re: ACPI tables for MP identification

Post 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.
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

Re: ACPI tables for MP identification

Post 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??
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

Re: ACPI tables for MP identification

Post 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?
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: ACPI tables for MP identification

Post 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
worldsapart
Member
Member
Posts: 36
Joined: Sat Jan 03, 2009 4:12 am

Re: ACPI tables for MP identification

Post 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!
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Re: ACPI tables for MP identification

Post by jal »

worldsapart wrote:Lesson Learnt!
Glad to hear it, and show of character for admitting it :). Good luck with the ACPI stuff.


JAL
JohnnyTheDon
Member
Member
Posts: 524
Joined: Sun Nov 09, 2008 2:55 am
Location: Pennsylvania, USA

Re: ACPI tables for MP identification

Post 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.
Post Reply