audk/CorebootModulePkg/Library/CbParseLib/CbParseLib.c

722 lines
21 KiB
C

/** @file
This library will parse the coreboot table in memory and extract those required
information.
Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi/UefiBaseType.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/IoLib.h>
#include <Library/CbParseLib.h>
#include <IndustryStandard/Acpi.h>
#include "Coreboot.h"
/**
Convert a packed value from cbuint64 to a UINT64 value.
@param val The pointer to packed data.
@return the UNIT64 value after conversion.
**/
UINT64
cb_unpack64 (
IN struct cbuint64 val
)
{
return LShiftU64 (val.hi, 32) | val.lo;
}
/**
Returns the sum of all elements in a buffer of 16-bit values. During
calculation, the carry bits are also been added.
@param Buffer The pointer to the buffer to carry out the sum operation.
@param Length The size, in bytes, of Buffer.
@return Sum The sum of Buffer with carry bits included during additions.
**/
UINT16
CbCheckSum16 (
IN UINT16 *Buffer,
IN UINTN Length
)
{
UINT32 Sum, TmpValue;
UINTN Idx;
UINT8 *TmpPtr;
Sum = 0;
TmpPtr = (UINT8 *)Buffer;
for(Idx = 0; Idx < Length; Idx++) {
TmpValue = TmpPtr[Idx];
if (Idx % 2 == 1) {
TmpValue <<= 8;
}
Sum += TmpValue;
// Wrap
if (Sum >= 0x10000) {
Sum = (Sum + (Sum >> 16)) & 0xFFFF;
}
}
return (UINT16)((~Sum) & 0xFFFF);
}
/**
Find coreboot record with given Tag from the memory Start in 4096
bytes range.
@param Start The start memory to be searched in
@param Tag The tag id to be found
@retval NULL The Tag is not found.
@retval Others The pointer to the record found.
**/
VOID *
EFIAPI
FindCbTag (
IN VOID *Start,
IN UINT32 Tag
)
{
struct cb_header *Header;
struct cb_record *Record;
UINT8 *TmpPtr;
UINT8 *TagPtr;
UINTN Idx;
UINT16 CheckSum;
Header = NULL;
TmpPtr = (UINT8 *)Start;
for (Idx = 0; Idx < 4096; Idx += 16, TmpPtr += 16) {
Header = (struct cb_header *)TmpPtr;
if (Header->signature == CB_HEADER_SIGNATURE) {
break;
}
}
if (Idx >= 4096) {
return NULL;
}
if ((Header == NULL) || (Header->table_bytes == 0)) {
return NULL;
}
//
// Check the checksum of the coreboot table header
//
CheckSum = CbCheckSum16 ((UINT16 *)Header, sizeof (*Header));
if (CheckSum != 0) {
DEBUG ((EFI_D_ERROR, "Invalid coreboot table header checksum\n"));
return NULL;
}
CheckSum = CbCheckSum16 ((UINT16 *)(TmpPtr + sizeof (*Header)), Header->table_bytes);
if (CheckSum != Header->table_checksum) {
DEBUG ((EFI_D_ERROR, "Incorrect checksum of all the coreboot table entries\n"));
return NULL;
}
TagPtr = NULL;
TmpPtr += Header->header_bytes;
for (Idx = 0; Idx < Header->table_entries; Idx++) {
Record = (struct cb_record *)TmpPtr;
if (Record->tag == CB_TAG_FORWARD) {
TmpPtr = (VOID *)(UINTN)((struct cb_forward *)(UINTN)Record)->forward;
if (Tag == CB_TAG_FORWARD) {
return TmpPtr;
} else {
return FindCbTag (TmpPtr, Tag);
}
}
if (Record->tag == Tag) {
TagPtr = TmpPtr;
break;
}
TmpPtr += Record->size;
}
return TagPtr;
}
/**
Find the given table with TableId from the given coreboot memory Root.
@param Root The coreboot memory table to be searched in
@param TableId Table id to be found
@param pMemTable To save the base address of the memory table found
@param pMemTableSize To save the size of memory table found
@retval RETURN_SUCCESS Successfully find out the memory table.
@retval RETURN_INVALID_PARAMETER Invalid input parameters.
@retval RETURN_NOT_FOUND Failed to find the memory table.
**/
RETURN_STATUS
EFIAPI
FindCbMemTable (
IN struct cbmem_root *Root,
IN UINT32 TableId,
OUT VOID **pMemTable,
OUT UINT32 *pMemTableSize
)
{
UINTN Idx;
BOOLEAN IsImdEntry;
struct cbmem_entry *Entries;
if ((Root == NULL) || (pMemTable == NULL)) {
return RETURN_INVALID_PARAMETER;
}
//
// Check if the entry is CBMEM or IMD
// and handle them separately
//
Entries = Root->entries;
if (Entries[0].magic == CBMEM_ENTRY_MAGIC) {
IsImdEntry = FALSE;
} else {
Entries = (struct cbmem_entry *)((struct imd_root *)Root)->entries;
if (Entries[0].magic == IMD_ENTRY_MAGIC) {
IsImdEntry = TRUE;
} else {
return RETURN_NOT_FOUND;
}
}
for (Idx = 0; Idx < Root->num_entries; Idx++) {
if (Entries[Idx].id == TableId) {
if (IsImdEntry) {
*pMemTable = (VOID *) ((UINTN)Entries[Idx].start + (UINTN)Root);
} else {
*pMemTable = (VOID *) (UINTN)Entries[Idx].start;
}
if (pMemTableSize != NULL) {
*pMemTableSize = Entries[Idx].size;
}
DEBUG ((EFI_D_INFO, "Find CbMemTable Id 0x%x, base %p, size 0x%x\n",
TableId, *pMemTable, Entries[Idx].size));
return RETURN_SUCCESS;
}
}
return RETURN_NOT_FOUND;
}
/**
Acquire the memory information from the coreboot table in memory.
@param MemInfoCallback The callback routine
@param pParam Pointer to the callback routine parameter
@retval RETURN_SUCCESS Successfully find out the memory information.
@retval RETURN_NOT_FOUND Failed to find the memory information.
**/
RETURN_STATUS
EFIAPI
CbParseMemoryInfo (
IN CB_MEM_INFO_CALLBACK MemInfoCallback,
IN VOID *pParam
)
{
struct cb_memory *rec;
struct cb_memory_range *Range;
UINT64 Start;
UINT64 Size;
UINTN Index;
//
// Get the coreboot memory table
//
rec = (struct cb_memory *)FindCbTag (0, CB_TAG_MEMORY);
if (rec == NULL) {
rec = (struct cb_memory *)FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_MEMORY);
}
if (rec == NULL) {
return RETURN_NOT_FOUND;
}
for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {
Range = MEM_RANGE_PTR(rec, Index);
Start = cb_unpack64(Range->start);
Size = cb_unpack64(Range->size);
DEBUG ((EFI_D_INFO, "%d. %016lx - %016lx [%02x]\n",
Index, Start, Start + Size - 1, Range->type));
MemInfoCallback (Start, Size, Range->type, pParam);
}
return RETURN_SUCCESS;
}
/**
Acquire the coreboot memory table with the given table id
@param TableId Table id to be searched
@param pMemTable Pointer to the base address of the memory table
@param pMemTableSize Pointer to the size of the memory table
@retval RETURN_SUCCESS Successfully find out the memory table.
@retval RETURN_INVALID_PARAMETER Invalid input parameters.
@retval RETURN_NOT_FOUND Failed to find the memory table.
**/
RETURN_STATUS
EFIAPI
CbParseCbMemTable (
IN UINT32 TableId,
OUT VOID **pMemTable,
OUT UINT32 *pMemTableSize
)
{
struct cb_memory *rec;
struct cb_memory_range *Range;
UINT64 Start;
UINT64 Size;
UINTN Index;
if (pMemTable == NULL) {
return RETURN_INVALID_PARAMETER;
}
*pMemTable = NULL;
//
// Get the coreboot memory table
//
rec = (struct cb_memory *)FindCbTag (0, CB_TAG_MEMORY);
if (rec == NULL) {
rec = (struct cb_memory *)FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_MEMORY);
}
if (rec == NULL) {
return RETURN_NOT_FOUND;
}
for (Index = 0; Index < MEM_RANGE_COUNT(rec); Index++) {
Range = MEM_RANGE_PTR(rec, Index);
Start = cb_unpack64(Range->start);
Size = cb_unpack64(Range->size);
if ((Range->type == CB_MEM_TABLE) && (Start > 0x1000)) {
if (FindCbMemTable ((struct cbmem_root *)(UINTN)(Start + Size - DYN_CBMEM_ALIGN_SIZE), TableId, pMemTable, pMemTableSize) == RETURN_SUCCESS)
return RETURN_SUCCESS;
}
}
return RETURN_NOT_FOUND;
}
/**
Acquire the acpi table from coreboot
@param pMemTable Pointer to the base address of the memory table
@param pMemTableSize Pointer to the size of the memory table
@retval RETURN_SUCCESS Successfully find out the memory table.
@retval RETURN_INVALID_PARAMETER Invalid input parameters.
@retval RETURN_NOT_FOUND Failed to find the memory table.
**/
RETURN_STATUS
EFIAPI
CbParseAcpiTable (
OUT VOID **pMemTable,
OUT UINT32 *pMemTableSize
)
{
return CbParseCbMemTable (SIGNATURE_32 ('I', 'P', 'C', 'A'), pMemTable, pMemTableSize);
}
/**
Acquire the smbios table from coreboot
@param pMemTable Pointer to the base address of the memory table
@param pMemTableSize Pointer to the size of the memory table
@retval RETURN_SUCCESS Successfully find out the memory table.
@retval RETURN_INVALID_PARAMETER Invalid input parameters.
@retval RETURN_NOT_FOUND Failed to find the memory table.
**/
RETURN_STATUS
EFIAPI
CbParseSmbiosTable (
OUT VOID **pMemTable,
OUT UINT32 *pMemTableSize
)
{
return CbParseCbMemTable (SIGNATURE_32 ('T', 'B', 'M', 'S'), pMemTable, pMemTableSize);
}
/**
Find the required fadt information
@param pPmCtrlReg Pointer to the address of power management control register
@param pPmTimerReg Pointer to the address of power management timer register
@param pResetReg Pointer to the address of system reset register
@param pResetValue Pointer to the value to be written to the system reset register
@param pPmEvtReg Pointer to the address of power management event register
@param pPmGpeEnReg Pointer to the address of power management GPE enable register
@retval RETURN_SUCCESS Successfully find out all the required fadt information.
@retval RETURN_NOT_FOUND Failed to find the fadt table.
**/
RETURN_STATUS
EFIAPI
CbParseFadtInfo (
OUT UINTN *pPmCtrlReg,
OUT UINTN *pPmTimerReg,
OUT UINTN *pResetReg,
OUT UINTN *pResetValue,
OUT UINTN *pPmEvtReg,
OUT UINTN *pPmGpeEnReg
)
{
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
UINT32 *Entry32;
UINTN Entry32Num;
EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
UINT64 *Entry64;
UINTN Entry64Num;
UINTN Idx;
RETURN_STATUS Status;
Rsdp = NULL;
Status = RETURN_SUCCESS;
Status = CbParseAcpiTable ((VOID **)&Rsdp, NULL);
if (RETURN_ERROR(Status)) {
return Status;
}
if (Rsdp == NULL) {
return RETURN_NOT_FOUND;
}
DEBUG ((EFI_D_INFO, "Find Rsdp at %p\n", Rsdp));
DEBUG ((EFI_D_INFO, "Find Rsdt 0x%x, Xsdt 0x%lx\n", Rsdp->RsdtAddress, Rsdp->XsdtAddress));
//
// Search Rsdt First
//
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->RsdtAddress);
if (Rsdt != NULL) {
Entry32 = (UINT32 *)(Rsdt + 1);
Entry32Num = (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
for (Idx = 0; Idx < Entry32Num; Idx++) {
if (*(UINT32 *)(UINTN)(Entry32[Idx]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN)(Entry32[Idx]);
if (pPmCtrlReg != NULL) {
*pPmCtrlReg = Fadt->Pm1aCntBlk;
}
DEBUG ((EFI_D_INFO, "PmCtrl Reg 0x%x\n", Fadt->Pm1aCntBlk));
if (pPmTimerReg != NULL) {
*pPmTimerReg = Fadt->PmTmrBlk;
}
DEBUG ((EFI_D_INFO, "PmTimer Reg 0x%x\n", Fadt->PmTmrBlk));
if (pResetReg != NULL) {
*pResetReg = (UINTN)Fadt->ResetReg.Address;
}
DEBUG ((EFI_D_INFO, "Reset Reg 0x%lx\n", Fadt->ResetReg.Address));
if (pResetValue != NULL) {
*pResetValue = Fadt->ResetValue;
}
DEBUG ((EFI_D_INFO, "Reset Value 0x%x\n", Fadt->ResetValue));
if (pPmEvtReg != NULL) {
*pPmEvtReg = Fadt->Pm1aEvtBlk;
DEBUG ((EFI_D_INFO, "PmEvt Reg 0x%x\n", Fadt->Pm1aEvtBlk));
}
if (pPmGpeEnReg != NULL) {
*pPmGpeEnReg = Fadt->Gpe0Blk + Fadt->Gpe0BlkLen / 2;
DEBUG ((EFI_D_INFO, "PmGpeEn Reg 0x%x\n", *pPmGpeEnReg));
}
//
// Verify values for proper operation
//
ASSERT(Fadt->Pm1aCntBlk != 0);
ASSERT(Fadt->PmTmrBlk != 0);
ASSERT(Fadt->ResetReg.Address != 0);
ASSERT(Fadt->Pm1aEvtBlk != 0);
ASSERT(Fadt->Gpe0Blk != 0);
DEBUG_CODE_BEGIN ();
BOOLEAN SciEnabled;
//
// Check the consistency of SCI enabling
//
//
// Get SCI_EN value
//
if (Fadt->Pm1CntLen == 4) {
SciEnabled = (IoRead32 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;
} else {
//
// if (Pm1CntLen == 2), use 16 bit IO read;
// if (Pm1CntLen != 2 && Pm1CntLen != 4), use 16 bit IO read as a fallback
//
SciEnabled = (IoRead16 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;
}
if (!(Fadt->Flags & EFI_ACPI_5_0_HW_REDUCED_ACPI) &&
(Fadt->SmiCmd == 0) &&
!SciEnabled) {
//
// The ACPI enabling status is inconsistent: SCI is not enabled but ACPI
// table does not provide a means to enable it through FADT->SmiCmd
//
DEBUG ((DEBUG_ERROR, "ERROR: The ACPI enabling status is inconsistent: SCI is not"
" enabled but the ACPI table does not provide a means to enable it through FADT->SmiCmd."
" This may cause issues in OS.\n"));
ASSERT (FALSE);
}
DEBUG_CODE_END ();
return RETURN_SUCCESS;
}
}
}
//
// Search Xsdt Second
//
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);
if (Xsdt != NULL) {
Entry64 = (UINT64 *)(Xsdt + 1);
Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3;
for (Idx = 0; Idx < Entry64Num; Idx++) {
if (*(UINT32 *)(UINTN)(Entry64[Idx]) == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN)(Entry64[Idx]);
if (pPmCtrlReg)
*pPmCtrlReg = Fadt->Pm1aCntBlk;
DEBUG ((EFI_D_ERROR, "PmCtrl Reg 0x%x\n", Fadt->Pm1aCntBlk));
if (pPmTimerReg)
*pPmTimerReg = Fadt->PmTmrBlk;
DEBUG ((EFI_D_ERROR, "PmTimer Reg 0x%x\n", Fadt->PmTmrBlk));
if (pResetReg)
*pResetReg = (UINTN)Fadt->ResetReg.Address;
DEBUG ((EFI_D_ERROR, "Reset Reg 0x%lx\n", Fadt->ResetReg.Address));
if (pResetValue)
*pResetValue = Fadt->ResetValue;
DEBUG ((EFI_D_ERROR, "Reset Value 0x%x\n", Fadt->ResetValue));
if (pPmEvtReg != NULL) {
*pPmEvtReg = Fadt->Pm1aEvtBlk;
DEBUG ((EFI_D_INFO, "PmEvt Reg 0x%x\n", Fadt->Pm1aEvtBlk));
}
if (pPmGpeEnReg != NULL) {
*pPmGpeEnReg = Fadt->Gpe0Blk + Fadt->Gpe0BlkLen / 2;
DEBUG ((EFI_D_INFO, "PmGpeEn Reg 0x%x\n", *pPmGpeEnReg));
}
return RETURN_SUCCESS;
}
}
}
return RETURN_NOT_FOUND;
}
/**
Find the serial port information
@param pRegBase Pointer to the base address of serial port registers
@param pRegAccessType Pointer to the access type of serial port registers
@param pRegWidth Pointer to the register width in bytes
@param pBaudrate Pointer to the serial port baudrate
@param pInputHertz Pointer to the input clock frequency
@param pUartPciAddr Pointer to the UART PCI bus, dev and func address
@retval RETURN_SUCCESS Successfully find the serial port information.
@retval RETURN_NOT_FOUND Failed to find the serial port information .
**/
RETURN_STATUS
EFIAPI
CbParseSerialInfo (
OUT UINT32 *pRegBase,
OUT UINT32 *pRegAccessType,
OUT UINT32 *pRegWidth,
OUT UINT32 *pBaudrate,
OUT UINT32 *pInputHertz,
OUT UINT32 *pUartPciAddr
)
{
struct cb_serial *CbSerial;
CbSerial = FindCbTag (0, CB_TAG_SERIAL);
if (CbSerial == NULL) {
CbSerial = FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_SERIAL);
}
if (CbSerial == NULL) {
return RETURN_NOT_FOUND;
}
if (pRegBase != NULL) {
*pRegBase = CbSerial->baseaddr;
}
if (pRegWidth != NULL) {
*pRegWidth = CbSerial->regwidth;
}
if (pRegAccessType != NULL) {
*pRegAccessType = CbSerial->type;
}
if (pBaudrate != NULL) {
*pBaudrate = CbSerial->baud;
}
if (pInputHertz != NULL) {
*pInputHertz = CbSerial->input_hertz;
}
if (pUartPciAddr != NULL) {
*pUartPciAddr = CbSerial->uart_pci_addr;
}
return RETURN_SUCCESS;
}
/**
Search for the coreboot table header
@param Level Level of the search depth
@param HeaderPtr Pointer to the pointer of coreboot table header
@retval RETURN_SUCCESS Successfully find the coreboot table header .
@retval RETURN_NOT_FOUND Failed to find the coreboot table header .
**/
RETURN_STATUS
EFIAPI
CbParseGetCbHeader (
IN UINTN Level,
OUT VOID **HeaderPtr
)
{
UINTN Index;
VOID *TempPtr;
if (HeaderPtr == NULL) {
return RETURN_NOT_FOUND;
}
TempPtr = NULL;
for (Index = 0; Index < Level; Index++) {
TempPtr = FindCbTag (TempPtr, CB_TAG_FORWARD);
if (TempPtr == NULL) {
break;
}
}
if ((Index >= Level) && (TempPtr != NULL)) {
*HeaderPtr = TempPtr;
return RETURN_SUCCESS;
}
return RETURN_NOT_FOUND;
}
/**
Find the video frame buffer information
@param pFbInfo Pointer to the FRAME_BUFFER_INFO structure
@retval RETURN_SUCCESS Successfully find the video frame buffer information.
@retval RETURN_NOT_FOUND Failed to find the video frame buffer information .
**/
RETURN_STATUS
EFIAPI
CbParseFbInfo (
OUT FRAME_BUFFER_INFO *pFbInfo
)
{
struct cb_framebuffer *CbFbRec;
if (pFbInfo == NULL) {
return RETURN_INVALID_PARAMETER;
}
CbFbRec = FindCbTag (0, CB_TAG_FRAMEBUFFER);
if (CbFbRec == NULL) {
CbFbRec = FindCbTag ((VOID *)(UINTN)PcdGet32 (PcdCbHeaderPointer), CB_TAG_FRAMEBUFFER);
}
if (CbFbRec == NULL) {
return RETURN_NOT_FOUND;
}
DEBUG ((EFI_D_INFO, "Found coreboot video frame buffer information\n"));
DEBUG ((EFI_D_INFO, "physical_address: 0x%lx\n", CbFbRec->physical_address));
DEBUG ((EFI_D_INFO, "x_resolution: 0x%x\n", CbFbRec->x_resolution));
DEBUG ((EFI_D_INFO, "y_resolution: 0x%x\n", CbFbRec->y_resolution));
DEBUG ((EFI_D_INFO, "bits_per_pixel: 0x%x\n", CbFbRec->bits_per_pixel));
DEBUG ((EFI_D_INFO, "bytes_per_line: 0x%x\n", CbFbRec->bytes_per_line));
DEBUG ((EFI_D_INFO, "red_mask_size: 0x%x\n", CbFbRec->red_mask_size));
DEBUG ((EFI_D_INFO, "red_mask_pos: 0x%x\n", CbFbRec->red_mask_pos));
DEBUG ((EFI_D_INFO, "green_mask_size: 0x%x\n", CbFbRec->green_mask_size));
DEBUG ((EFI_D_INFO, "green_mask_pos: 0x%x\n", CbFbRec->green_mask_pos));
DEBUG ((EFI_D_INFO, "blue_mask_size: 0x%x\n", CbFbRec->blue_mask_size));
DEBUG ((EFI_D_INFO, "blue_mask_pos: 0x%x\n", CbFbRec->blue_mask_pos));
DEBUG ((EFI_D_INFO, "reserved_mask_size: 0x%x\n", CbFbRec->reserved_mask_size));
DEBUG ((EFI_D_INFO, "reserved_mask_pos: 0x%x\n", CbFbRec->reserved_mask_pos));
pFbInfo->LinearFrameBuffer = CbFbRec->physical_address;
pFbInfo->HorizontalResolution = CbFbRec->x_resolution;
pFbInfo->VerticalResolution = CbFbRec->y_resolution;
pFbInfo->BitsPerPixel = CbFbRec->bits_per_pixel;
pFbInfo->BytesPerScanLine = (UINT16)CbFbRec->bytes_per_line;
pFbInfo->Red.Mask = (1 << CbFbRec->red_mask_size) - 1;
pFbInfo->Red.Position = CbFbRec->red_mask_pos;
pFbInfo->Green.Mask = (1 << CbFbRec->green_mask_size) - 1;
pFbInfo->Green.Position = CbFbRec->green_mask_pos;
pFbInfo->Blue.Mask = (1 << CbFbRec->blue_mask_size) - 1;
pFbInfo->Blue.Position = CbFbRec->blue_mask_pos;
pFbInfo->Reserved.Mask = (1 << CbFbRec->reserved_mask_size) - 1;
pFbInfo->Reserved.Position = CbFbRec->reserved_mask_pos;
return RETURN_SUCCESS;
}