UEFI AllocatePages fails wrong parameters

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
Rhodez
Member
Member
Posts: 33
Joined: Tue Jun 30, 2020 2:09 pm
Location: Langeskov, Denmark

UEFI AllocatePages fails wrong parameters

Post by Rhodez »

Hi,

I have problems with AllocatePages when I try to allocate memory in UEFI.
It keeps failing on "EFI_INVALID_PARAMETER", I have tried different options for the parameters, but everything i have tried has failed with invalid parameters.

I have used the AllocatePool to request memory of type "EfiRuntimeServicesCode" with no problem.

Any obvious mistake?

Cheers

Code: Select all

    void* buffer = 0x0; 
    UINTN num_pages = 10;
    Status = BS->AllocatePages(AllocateAnyPages, EfiRuntimeServicesCode, num_pages, (EFI_PHYSICAL_ADDRESS*) buffer); 
    if (EFI_ERROR(Status)) 
    {   
        ST->ConOut->OutputString(ST->ConOut, L"Could not allocate a page \r\n");
        if (EFI_INVALID_PARAMETER == Status) 
        {
            ST->ConOut->OutputString(ST->ConOut, L"Wrong parameters \r\n");
        }
        return;
    }
Octocontrabass
Member
Member
Posts: 5572
Joined: Mon Mar 25, 2013 7:01 pm

Re: UEFI AllocatePages fails wrong parameters

Post by Octocontrabass »

Rhodez wrote:"EfiRuntimeServicesCode"
Are you really writing a UEFI runtime driver?
Rhodez
Member
Member
Posts: 33
Joined: Tue Jun 30, 2020 2:09 pm
Location: Langeskov, Denmark

Re: UEFI AllocatePages fails wrong parameters

Post by Rhodez »

Octocontrabass wrote:
Rhodez wrote:"EfiRuntimeServicesCode"
Are you really writing a UEFI runtime driver?
I guess that must be a no ;)
But I just wanted to make sure that UEFI did not ruin the allocated memory.

And I guess I not totally sure about the difference of EfiBootServicesData/Code and EfiLoaderDate/Code.
The buffer is used to load in the initial code for my kernel.
Whereas I jump to the address of the buffer when I have called ExitBootServices()
Octocontrabass
Member
Member
Posts: 5572
Joined: Mon Mar 25, 2013 7:01 pm

Re: UEFI AllocatePages fails wrong parameters

Post by Octocontrabass »

Rhodez wrote:But I just wanted to make sure that UEFI did not ruin the allocated memory.
UEFI won't touch memory you've allocated unless you free it.
Rhodez wrote:And I guess I not totally sure about the difference of EfiBootServicesData/Code and EfiLoaderDate/Code.
EfiBootServicesData/Code are for UEFI boot service drivers. You're not writing a UEFI boot service driver, are you?

EfiLoaderData/Code are for UEFI loaders. Your UEFI loader should use these.
Rhodez wrote:The buffer is used to load in the initial code for my kernel.
Whereas I jump to the address of the buffer when I have called ExitBootServices()
The page tables set up by the firmware may not allow execution in memory allocated as EfiLoaderData. If you're doing this jump before you've set up your own page tables, you'll need to use EfiLoaderCode.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: UEFI AllocatePages fails wrong parameters

Post by bzt »

Rhodez wrote:Any obvious mistake?
What the others said, I also do believe you should use EfiLoaderCode. Plus in order to return a buffer, you must pass the address of a pointer to the call. Right now you're passing a NULL address (the value of the pointer) instead of the address of the pointer itself.
BS->AllocatePages(AllocateAnyPages, EfiRuntimeServicesCode, num_pages, (EFI_PHYSICAL_ADDRESS*) &buffer);
Also the returned status code is not so important, you should check if the pointer is not NULL after the call. Even if status is EFI_SUCCESS and the pointer is NULL, you'll get problems, so always do a "buffer != NULL" check.

Cheers,
bzt
Rhodez
Member
Member
Posts: 33
Joined: Tue Jun 30, 2020 2:09 pm
Location: Langeskov, Denmark

Re: UEFI AllocatePages fails wrong parameters

Post by Rhodez »

bzt wrote:
Rhodez wrote:Any obvious mistake?
What the others said, I also do believe you should use EfiLoaderCode.
Thank to Octocontrabass for explanation, and to you both for pointing it out.
Nevertheless it not helps on my problem and it was just the last resort I tried before posting it here.
bzt wrote: Plus in order to return a buffer, you must pass the address of a pointer to the call. Right now you're passing a NULL address (the value of the pointer) instead of the address of the pointer itself.
BS->AllocatePages(AllocateAnyPages, EfiRuntimeServicesCode, num_pages, (EFI_PHYSICAL_ADDRESS*) &buffer);
Also the returned status code is not so important, you should check if the pointer is not NULL after the call. Even if status is EFI_SUCCESS and the pointer is NULL, you'll get problems, so always do a "buffer != NULL" check.

Cheers,
bzt
In the UEFI specification the prototype looks like this:

Code: Select all

PrototypetypedefEFI_STATUS(EFIAPI *EFI_ALLOCATE_PAGES) (
IN EFI_ALLOCATE_TYPE        Type,
IN EFI_MEMORY_TYPE          MemoryType,
IN UINTN                    Pages,
IN OUT EFI_PHYSICAL_ADDRESS *Memory);
ref(https://uefi.org/sites/default/files/re ... 202020.pdf)
For me it looks like it wants a pointer, and i would mean that my variable is a pointer?
The specification also says that the value that the pointer holds is ignored when requesting with "AllocateAnyPages"?

I could try to make a variable as EFI_PHYSICAL_ADDRESS, and then parse the address of that, but shouldn't that be the same?

I have also checked against buffer being null, I have just simplified the example given here.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: UEFI AllocatePages fails wrong parameters

Post by bzt »

Rhodez wrote:For me it looks like it wants a pointer, and i would mean that my variable is a pointer?
The specification also says that the value that the pointer holds is ignored when requesting with "AllocateAnyPages"?

I could try to make a variable as EFI_PHYSICAL_ADDRESS, and then parse the address of that, but shouldn't that be the same?
I can understand your confusion, but no, not the same.

I'll try to explain.
EFI_PHYSICAL_ADDRESS - is a memory address
EFI_PHYSICAL_ADDRESS* - is a pointer to a variable that holds a memory address
void* - pointer to a memory (which has a value of an EFI_PHYSICAL_ADDRESS). It doesn't matter what type the pointer points to, it's value always going to be EFI_PHYSICAL_ADDRESS (but the C language hides this from you).

Now the allocate function should return an EFI_PHYSICAL_ADDRESS, a memory address. It cannot do that unless you pass a pointer to a variable. Therefore, assuming you have "EFI_PHYSICAL_ADDRESS P", you should pass &P. Hope this makes sense. Now here comes the problematic part, because you don't have a single memory address variable, but you have a void* pointer. So if you want to make the allocation to return the memory address in that pointer as the pointed address, then you must pass the address of the pointer. The problem is, you have void* type not EFI_PHYSICAL_ADDRESS, so you must cast it to EFI_PHYSICAL_ADDRESS*, without actually dereferencing the pointer (you need the pointer's address and not the pointed address).

For example, let's assume in the memory at address 0x1000 you have a pointer named p, with the value 0x2000. Passing it to a function

Code: Select all

somefunc(p);      // will pass 0x2000 as argument. The function won't be able to change the p pointer, because it doesn't know where it is in the memory, it only knows the pointed value
somefunc(&p);     // will pass 0x1000 as argument, the address of the p pointer. The function therefore can change the pointed address in the pointer
This is a very very (very) simplified description of pointer arithmetic, but I hope clearifies the issue a bit.

As for the ignored part, that means that it doesn't matter what the pointer points to, because that will be overridden by the new address.

Code: Select all

void *p = 0x123; // can be whatever you want, makes the pointer to point to 0x123
alloc(&p); // this function never reads the pointed address from the pointer, just sets it
p == 0x456; // the new value, so the pointer now points to 0x456
Cheers,
bzt
Rhodez
Member
Member
Posts: 33
Joined: Tue Jun 30, 2020 2:09 pm
Location: Langeskov, Denmark

Re: UEFI AllocatePages fails wrong parameters

Post by Rhodez »

Thanks bzt, I totally understand and it also make sense.
It must be the heat which is tricking me, I had not thought to much of the typedef of EFI_PHYSICAL_ADDRESS other than just being a memory pointer.

Also my code works now.! Thanks again.
Post Reply