Page 1 of 1

RSDP of ACPI is missing.

Posted: Sun Nov 16, 2014 7:20 am
by donggas90
I wrote code for power management from this thread.
but first step, RSDP could not found.

Here is my implementation.

Code: Select all

struct SRootSystemDescriptionPointer
{
	achar_t mSignature[8];
	uint8_t mChecksum;
	achar_t mOemId[6];
	uint8_t mRevision;
	uint32_t mRsdtAddress;

	SRootSystemDescriptionTableHeader* GetRsdt() const
	{
		return reinterpret_cast<SRootSystemDescriptionTableHeader*>(mRsdtAddress);
	}
	bool IsValid() const
	{
		if (CMemory::Equals(mSignature, "RSD PTR ", 8))
		{
			const int8_t* lBytes = reinterpret_cast<const int8_t*>(this);
			int32_t lCheck(0);
			for (size_t i = 0; i < sizeof(SRootSystemDescriptionPointer); i++)
			{
				lCheck += lBytes[i];
			}
			if (0 == lCheck)
			{
				return true;
				//return GetRsdt()->CheckSignature("RSDT");
			}
		}
		return false;
	}
};

static void Initialize()
{
	if (nullptr == msRsdp)
	{
		for (uint32_t i = 0x000E0000; i < 0x000FFFFF; i += 16)
		{
			SRootSystemDescriptionPointer* lRsdp = reinterpret_cast<SRootSystemDescriptionPointer*>(i);
			if (lRsdp->IsValid())
			{
				msRsdp = lRsdp;
				break;
			}
		}

		if (nullptr == msRsdp)
		{
			// word[0x40:0x0E]
			uint32_t lEbda = *(reinterpret_cast<uint16_t*>(0x40E));
			lEbda = (lEbda * 16) & 0x000FFFFF;
			for (size_t i = 0; i < 4096; i += 16)
			{
				SRootSystemDescriptionPointer* lRsdp = reinterpret_cast<SRootSystemDescriptionPointer*>(lEbda + i);
				if (lRsdp->IsValid())
				{
					msRsdp = lRsdp;
					break;
				}
			}
		}
	}
}
Logic is almost same with code of above that thread.
I think, searching range is not correct.
or
My machine do not support ACPI.

My machine is VMware.
If it do not support, what do I use instead of that?

Thanks!

Re: RSDP of ACPI is missing.

Posted: Sun Nov 16, 2014 8:30 am
by Brendan
Hi,
donggas90 wrote:I wrote code for power management from this thread.
but first step, RSDP could not found.
Note: The method shown on that topic is so broken that it's potentially dangerous. Do not use it.
donggas90 wrote:I think, searching range is not correct.
or
My machine do not support ACPI.
For your code; the only problem I can see is that the structure is not "packed" and the compiler probably inserts padding (that would make the size of the structure more than 20 bytes and therefore cause the checksum calculation to fail).
donggas90 wrote:If it do not support, what do I use instead of that?
If the computer doesn't support ACPI (or if the OS doesn't support ACPI, which is a massive amount of work if you don't port ACPICA); then there's only really 3 options:
  • Use the older APM BIOS interface instead
  • Have motherboard specific device drivers (one for each motherboard)
  • Tell the user it's safe for them to turn the power off, and go into an "infinite HLT" waiting loop.
Note: For the last case; if the OS supports it; you'd also tell any hardware (excluding monitor) to move to their "lowest power" state (typically using some sort of device tree in a "depth first" manner, to ensure you don't (e.g.) tell a USB device to go to sleep after its USB controller has).


Cheers,

Brendan

Re: RSDP of ACPI is missing.

Posted: Sun Nov 16, 2014 8:58 am
by donggas90
Thanks Brendan!

My compiler is VC++ 2013 and using /Zp1 option that to align structure member in 1bytes.

Code: Select all

static_assert(sizeof(SRootSystemDescriptionPointer) == 20, "");
and I have above assertion to make correct.

Hmm, it's much harder to shut down the machine I thought.
I should think about plan B.

Re: RSDP of ACPI is missing.

Posted: Sun Nov 16, 2014 9:23 am
by KemyLand
First, you are using a int32_t for cheking for a valid RDSP inside SRootSystemDescriptionPointer::IsValid.

Code: Select all

int32_t lCheck(0);
It must be uint8_t.

Code: Select all

uint8_t lCheck(0);
Both signedness and integer size are affecting you here. Repair this and check your results :wink:
As Brendan said, its a good idea to port ACPICA. But some arch-specific testing doesn't harms anyone :P

As a side note; I'm not really sure if you should find the RSDP by iterating through predefined addresses... The wiki says so, but it's an inefficient algorithm [-X

Re: RSDP of ACPI is missing.

Posted: Sun Nov 16, 2014 9:28 am
by Brendan
Hi,

Just a minor note: APM isn't horrible.

It can be used in real mode or virtual8086 mode, but also has both a 16-bit protected mode interface and a 32-bit protected mode interface. For the protected mode interfaces, you establish a connection (e.g. during boot in real mode) and it gives you details for the segment descriptors it wants and the offset for its entry point in its code segment.

The interface itself is relatively simple. You do need to poll for events, where the events are things like standby/suspend requests, low battery notification, etc; but the polling isn't likely to be a performance problem (it only has to be done once per second). You also get control over power management for various devices; including the ability to turn the computer off.

The sad part is that APM has become obsolete (replaced by ACPI on modern systems, and not supported by UEFI). The nice part is that it's more likely to exist on old computers (e.g. before 2000) where ACPI doesn't exist and/or is buggy; which means that APM support is nice to have (even if the OS does support ACPI).


Cheers,

Brendan

Re: RSDP of ACPI is missing.

Posted: Sun Nov 16, 2014 9:35 am
by Brendan
Hi,
KemyLand wrote:Also, I'm not really sure if you should find the RSDP that way... The wiki says so, but it's an inefficient algorithm [-X
There are minor improvements that could be made (e.g. comparing dwords instead of characters for checking the signature, etc); but the main problem is that the search is a "cache miss disaster" and can't be avoided for BIOS systems. Note: For UEFI the search isn't needed - the firmware simply tells you where ACPI's RSDP is).

The only way I've found to reduce the "cache miss disaster" searching (for BIOS systems) is to combine it with similar searches for SMBIOS and Multi-Processor specification tables. That way, because the areas you need to search for the 3 different things do overlap, you can pay for cache misses once instead of multiple times.


Cheers,

Brendan

Re: RSDP of ACPI is missing.

Posted: Sun Nov 16, 2014 12:09 pm
by donggas90
Thanks for regard, KemyLand.
KemyLand wrote:

Code: Select all

uint8_t lCheck(0);

Code: Select all

bool IsValid() const
{
	if (CMemory::Equals(mSignature, "RSD PTR ", 8))
	{
		const int8_t* lBytes = reinterpret_cast<const int8_t*>(this);
		uint8_t lCheck(0);
		for (size_t i = 0; i < sizeof(SRootSystemDescriptionPointer); i++)
		{
			lCheck += lBytes[i];
		}
		if (0 == lCheck)
		{
			//return true;
			return GetRsdt()->CheckSignature("RSDT");
		}
	}
	return false;
}
Yeah, finally it finds a RSDP.
but just occur page fault when I check the signature of it.
I already identity mapped whole of physical memory.
Thus it means RSDT is invalid.

Code: Select all

struct SRootSystemDescriptionTableHeader 
{
	achar_t mSignature[4];
	uint32_t mLength;
	uint8_t mRevision;
	uint8_t mChecksum;
	achar_t mOemId[6];
	achar_t mOemTableId[8];
	uint32_t mOemRevision;
	uint32_t mCreatorId;
	uint32_t mCreatorRevision;

	inline bool CheckSignature(const void* pCheck) const
	{
		return CMemory::Equals(mSignature, pCheck, 4);
	}
}
and Thanks for additional answer, Brendan.

but I'll try something next time.
In my region, now is about 3AM.
I need to sleep. :lol:

Re: RSDP of ACPI is missing.

Posted: Wed Nov 19, 2014 10:12 am
by donggas90
In detailed diagnostics, I found the problem.

First, my machine's installed physical memory size is 512MB.
but INT15 0xE801 was returned about 510MB.
So last of 1~2MB do not mapped by my Virtual Memory manager that operate paging.
BTW, RSDP is pointing unmapped that location as RSDT, so page fault was occured.

In memory map, I confirmed that the space is ACPI reclaimable.
but wonder that, why INT15 did not return that space included size.

If it's normal situation, how can I specify ACPI space.
I don't trust memory map because it mapped do not exists space such as 4G.
so trustable value is only INT15 returned size but it do not include ACPI space.
If I didn't know real installed size of memory, could not figure out that ACPI space is there in end of memory.

Is there additional step for this problem?

Re: RSDP of ACPI is missing.

Posted: Wed Nov 19, 2014 10:46 am
by JAAman
yes, the missing step is you are using the untrustworthy E801 function instead of the E820 function...

i would guess that this will always be the case (sort of) because the only thing E801 can give you is a number... which is unreliable anyway, because it will always either leave out part of the usable memory, or lead you to think there is memory where there isn't

basically, the only reliable way to get memory information is from E820, using anything else is an unreliable hack on systems that support E820, and a necessary evil which must be expected to be wrong on systems that do not support E820

Re: RSDP of ACPI is missing.

Posted: Wed Nov 19, 2014 12:19 pm
by donggas90
Thanks for regard, JAAman.
JAAman wrote:yes, the missing step is you are using the untrustworthy E801 function instead of the E820 function...
In my post, the memory map mean E820 returned tables.
Yes, it is the best way, but not perfect.
I wrote that, it maps even not exists area.
so I used E801 to support it.

Then, I need to just setup paging for ACPI space forcibly.

Re: RSDP of ACPI is missing.

Posted: Wed Nov 19, 2014 1:36 pm
by donggas90
Finally, made the job.
Thanks for regards!