AllocatePages return EFI_INVALID_PARAMETER for memory type as EfiConventionalMemory? - uefi

Hi I'm using edk2 to write a boot service for a kernel and need to apply AllocatePages service to apply memory with type as EfiConventionalMemory.
However, it returns an error code of EFI_INVALID_PARAMETER.
I looked into the source code from git, the actual function is as follow:
EFI_STATUS
EFIAPI
CoreAllocatePages (
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NumberOfPages,
OUT EFI_PHYSICAL_ADDRESS *Memory
)
{
EFI_STATUS Status;
BOOLEAN NeedGuard;
NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
NeedGuard);
if (!EFI_ERROR (Status)) {
CoreUpdateProfile (
(EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
MemoryProfileActionAllocatePages,
MemoryType,
EFI_PAGES_TO_SIZE (NumberOfPages),
(VOID *) (UINTN) *Memory,
NULL
);
InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);
ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory,
EFI_PAGES_TO_SIZE (NumberOfPages));
}
return Status;
}
It calls the function CoreInternalAllocatePages, which is as follow:
EFI_STATUS
EFIAPI
CoreInternalAllocatePages (
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NumberOfPages,
IN OUT EFI_PHYSICAL_ADDRESS *Memory,
IN BOOLEAN NeedGuard
)
{
EFI_STATUS Status;
UINT64 Start;
UINT64 NumberOfBytes;
UINT64 End;
UINT64 MaxAddress;
UINTN Alignment;
EFI_MEMORY_TYPE CheckType;
if ((UINT32)Type >= MaxAllocateType) {
return EFI_INVALID_PARAMETER;
}
if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
(MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) {
return EFI_INVALID_PARAMETER;
}
So it actually returns EFI_INVALID_PARAMETER if memory type is EfiConventionalMemory.
I also read the UEFI spec which define EfiConventionalMemory as type of "Free (unallocated) memory" before ExitBootServices() is called and "Memory available for general use" after.
So I'm kind of confused if it is normal that I got EFI_INVALID_PARAMETER, if not, what should I do to get the right memory allocation??
Thanks a lot!

The memory type parameter specifies the type the memory should have after allocation. Obviously the memory cannot be free after allocation, so that’s why EfiConventionalMemory is an invalid parameter.
The source of memory for the allocation is always EfiConventionalMemory.
Typically you would use BootServicesData as the requested memory type.

Related

How to access efi executable present in another partition using gnu-efi?

I have to create 2 fat16 partitions in a disk and place one of the efi binary in another fat16 partition.
To begin with, wrote a basic HelloWorld.efi application (second stage) and for the first stage, used below-mentioned 2 apis to execute the HelloWorld.efi (both binaries are present in the same partition)
Currently I am trying to figure out a way to access the HelloWorld.efi present in another partition. Using these apis, I can access any file present in the same partition but don't know what api(s) to use to access another partition? Any suggestions? Thanks.
efi_status = BS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
(void **)&shim_li);
efi_status = BS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
(void **) &drive);
The simplest way would be to check if the file exists inside any filesystem.
The code below uses EDK2 but should work with gnu-efi with minimal modifications.
EFI_STATUS Status;
EFI_HANDLE* Handles;
UINTN HandleCount;
UINTN HandleIndex;
EFI_DEVICE_PATH_PROTOCOL* FilePath;
EFI_HANDLE ImageHandle;
CHAR16* ExitData;
UINTN ExitDataLength;
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
// error handling
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
FilePath = FileDevicePath(Handles[HandleIndex], L"MyFolder\\HelloWorld.efi");
if (FilePath == NULL) {
continue;
}
Status = gBS->LoadImage(TRUE, gImageHandle, FilePath, NULL, 0, &ImageHandle);
gBS->FreePool(FilePath);
if (Status != EFI_SUCCESS) {
continue;
}
// Set LoadOptions and Watchdog if needed
Status = gBS->StartImage(ImageHandle, &ExitDataLength, &ExitData);
// error handling
}
gBS->FreePool(Handles);
If you know the partition id you can parse the device path of the filesystem and search for the correct partition.

Linux Kernel Module dev_get_drvdata Function Always Returns NULL

I have the following kernel module probe function (simplified to show the relevant parts):
static int qnap_ec_probe(struct platform_device* platform_dev)
{
// Allocate memory for the custom data and associate with the device
struct qnap_ec_platform_drv_data* platform_drv_data;
platform_drv_data = devm_kzalloc(&platform_dev->dev, sizeof(struct qnap_ec_platform_drv_data),
GFP_KERNEL);
// Add the custom data to the platform device
platform_set_drvdata(platform_dev, platform_drv_data);
// Register the platform device
devm_hwmon_device_register_with_info(&platform_dev->dev, "qnap_ec", NULL,
&qnap_ec_hwmon_chip_info, NULL);
return 0;
}
and the following hwmon read callback function:
static int qnap_ec_hwmon_read(struct device* dev, enum hwmon_sensor_types type, u32 attribute,
int channel, long* value)
{
struct qnap_ec_platform_drv_data* platform_drv_data;
platform_drv_data = dev_get_drvdata(dev);
if (platform_drv_data == NULL)
{
return -1;
}
return 0;
}
Unfortunately the second function always returns -1 because the dev_get_drvdata function always returns NULL. For some reason the data that's associated with the device in the probe function using platform_set_drvdata doesn't make it into the hwmon read callback function. Am I missing a step in associating this data with the device? What could be causing this issue?

How to change value of module_param parameter in the device driver?

I wrote a simple program for taking a value through command line into my driver. I used module_param() for this and gave permission argument, i.e third arg of module_param(), as S_IWUSR.
This I guess would allow user to modify the value of that parameter once driver is loaded in the kernel. I tried to modify the value of that parameter by:
echo 1 > /sys/module/ghost/parameters/num
But this shows me Permission denied error every time I try to do this, even when I execute the command with sudo. I also tried changing permission in module_param() to 0770 but still was not able to change the parameter value. Is there a way to change the value of parameter passed while inserting the driver ? Why does the above command shows permission denied, even if I run as sudo ?
After the answer of #Ian Abott I am to change the value of the parameter. Now I tried to define a callback function to notify me any changes in the value of that parameter while my driver is loaded. Here is the code
#include"headers.h"
#include"declarations.h"
static int my_set(const char *val, const struct kernel_param *kp)
{
int n = 0, ret;
ret = kstrtoint(val,10,&n); // Kernel function to convert string to integer
if (ret !=0 || n > 10) {
return -EINVAL;
}
printk(KERN_ALERT "my-set function running\n");
return param_set_int(val,kp);
}
static const struct kernel_param_ops param_ops = {
.set = my_set,
.get = param_get_int,
};
module_param(num,int,0600);
static char *name = "hello";
module_param(name,charp,0770);
static int __init init_func(void)
{
int i;
module_param_cb(callBack, &param_ops, &num, 0770);
printk(KERN_INFO "Value of num is %d\n",num);
for( i=0; i<num; i++)
{
printk(KERN_INFO "%s\n", name);
}
return 0;
}
static void __exit exit_func(void)
{
printk(KERN_INFO "Value of num is %d\n",num);
printk(KERN_ALERT "Module removed successfully\n");
}
module_init(init_func);
module_exit(exit_func);
But it doesn't seem to work because my_set function never runs, even if I change the value. My doubt is
1) Is this correct way to implement callback function for the parameter?
2) What is significance of first argument to the function module_param_cb?

UEFI TGC2's sendCommand always returns error 21

I'm developing an UEFI app using the TPM2. getCapabilities works, but everything else is shoved onto this submitCommand() function. everything I try there returns EFI_ABORTED as status.
I tried several commands, like read_PCR and get_random_number, but it appears to occur for all commands (TPM2 spec part 3). I chose the random number command because it's a simple command without authorization or encryption that should always return when executed correctly.
struct TPM2_ {
EFI_HANDLE image;
EFI_BOOT_SERVICES *BS;
EFI_TCG2_PROTOCOL *prot;
UINT32 activePCRbanks;
};
struct TPM2_Rand_Read_Command {
TPMI_ST_COMMAND_TAG tag;
UINT32 commandSize;
TPM_CC commandCode;
UINT16 bytesRequested;
};
struct TPM2_Rand_Read_Response {
TPM_ST tag;
UINT32 responseSize;
TPM_RC responseCode;
TPM2B_DIGEST randomBytes;
};
UINTN tpm_get_random(TPM2 * tpm) {
struct TPM2_Rand_Read_Command cmd;
struct TPM2_Rand_Read_Response resp;
cmd.tag = __builtin_bswap16(TPM_ST_NO_SESSIONS); //x86 is little endian, TPM2 is big-endian, use bswap to convert!)
cmd.commandCode = __builtin_bswap32(TPM_CC_GetRandom);
cmd.commandSize = __builtin_bswap32(sizeof(struct TPM2_Rand_Read_Command));
cmd.bytesRequested = __builtin_bswap16(4);
EFI_STATUS stat = tpm->prot->SubmitCommand(tpm->prot,sizeof(struct TPM2_Rand_Read_Command), (UINT8*)&cmd,sizeof(struct TPM2_Rand_Read_Response),(UINT8*)&resp); //responds 0x15 || 21
Print(L"statreadrand: %x \t %d \r\n", stat, *((UINT32*)resp.randomBytes.buffer));
CHECK_STATUS(stat, L"SubmitReadCommand");
return 0;
}
TPM2* tpm_create(EFI_BOOT_SERVICES *BS, EFI_HANDLE image) {
TPM2* tpm = calloc(1, sizeof(TPM2));
EFI_GUID prot_guid = (EFI_GUID)EFI_TCG2_PROTOCOL_GUID;
tpm->BS = BS;
tpm->image = image;
EFI_STATUS stat = tpm->BS->LocateProtocol(&prot_guid, NULL, (void **)&tpm->prot);
CHECK_STATUS(stat, L"LocateTPMProtocol");
return tpm;
}
I expect the SubmitCommand function to return EFI_SUCCESS (0) and fill the response struct with 4 random bytes. But the function returns EFI_ABORTED (21)
Does anyone know how to solve this?
EDIT: tried different toolchains (GNU-EFI/ plain GCC / EDK2) all give the same behaviour.
The particular PC had this exact problem. probably the TPM was locked.
When using a different PC With a TPM2 the problem didn' t occur and instead, I just got a random number back.

overhead of std::list in C++, what is the solution?

I have this code like this:
uint16_t getNextAvailableTransactionID() throw (RMAPEngineException) {
transactionIDMutex.lock();
if (availableTransactionIDList.size() != 0) {
unsigned int tid = *(availableTransactionIDList.begin());
availableTransactionIDList.pop_front();
transactionIDMutex.unlock();
return tid;
} else {
transactionIDMutex.unlock();
throw RMAPEngineException(RMAPEngineException::TooManyConcurrentTransactions);
}
}
and the availableTransactionIDList is a std::list of C++
Because I use this function as a part in reading out data from hardware. After checking, the overhead coming from the the availableTransactionIDList (I used a clock_gettime() and make a timestamp in the functions to check).
Just wondering, is there anyway to solve the problem with overhead of std::list ?