Hello,

Here is a brief description of a proposal to add support for Structured PCDs.
The concept is to associate a standard C data structure with a VOID* PCD and
use C language syntax to reference fields in the C data structure to override
values in a DSC file and access fields in extensions to the PcdLib macros.

I am looking for general feedback on the concepts in this proposal before
generating the detailed EDK II specification changes to support this proposal.

I have done some prototype work to prove that this proposal is technically 
feasible.  The details of the auto gen required to support Structured PCDs
are not included in this brief description.  Those details will be provided 
in the EDK II Specification updates.

## Why Structured PCDs?
  * Alignment between Module/Library sources and PCDs by using same C structure
    definition from both C code and PCD database simplifies use of VOID* PCDs.
  * Adding support for C structures associated with VOID* PCD simplifies DEC
    default value and DSC file override value assignment.
    - Changes default value from array of hex bytes to being able to specify a
      values based on structure field names
  * Adding support for more default value syntax simplifies DEC default value 
and
    DSC file override value assignment.
    - Support hexadecimal, decimal, TRUE, FALSE, ASCII String, Unicode String,
      Character Constants.
    - See RFC http://article.gmane.org/gmane.comp.bios.edk2.devel/12442
  * Modules/Libraries directly access fields in Structured PCDs using new
    PcdLib macros
  * Structured PCD fields can be designed to exactly match register layouts
  * Allows for removal of FW code that does translations between PCD data layout
    and HW/FW data layouts.
  * Using same C structure for both a Structured PCD and VFR NV Storage 
structure
    eliminates manual maintenance of HII hex byte offsets in DSC file
    - Manual maintenance of offsets has been shown to be error prone and 
difficult
      to debug when they are incorrect.
  * Combining configuration settings into Structured PCDs reduces the number of
    PCDs in DEC files and the overhead of managing token number assignments
    - EDK II build tools assign token numbers to fields within Structured PCDs
  * Adding support for bit fields in a C structure reduces the size overhead for
    storing configuration information

## General Requirements
  * Backwards compatible extensions to EDK II meta-data files and build tools.
  * Declare a VOID* PCD as a collection of fields
  * Provide method for C code to perform Get/Set operation on individual fields
    in the VOID* PCD.
  * Provide a method for a platform developer to set/override the build time
    values for a VOID* PCD by allowing the platform developer to specify the
    value for individual fields in a VOID* PCD in the DSC file.

## C Structure Syntax Proposal
  * Use C typedef syntax to describe complex C structures
  * Use a C language parser with support for struct/union/array/bit fields/pack
  * Recommend use of libclang C language parser into Abstract Syntax Tree (AST)
    - Included with LLVM release
    - http://llvm.org/releases/download.html
    - http://clang.llvm.org/doxygen/group__CINDEX.html
  * Recommend use of Python bindings for CLANG for EDK II Python based BaseTools
    - pip install clang

## DEC File Extensions
  * Declare link between PCD and C data structure and token range for fields
  * @Include path to include file with C typedef [Required]
  * Replace |VOID*| with name of C typedef
  * @TokenMap path to file with token number assignments [Optional]
  * Range of token numbers to assign to fields in C typedef [Required]
  * Example:

```
# @Include  Include/Pcd/AcpiLowerPowerIdleTable.h
# @TokenMap Include/Pcd/AcpiLowerPowerIdleTable.map
gPlatformTokenSpaceGuid.AcpiLowPowerIdleTable|{}|ACPI_LOW_POWER_IDLE_TABLE|0x00010080|0x0E000200-0x0E0002FF
```

  * Recommended File Paths
    - <PackageName>/Include/Pcd/<StructuredPcdName>.h
    - <PackageName>/Include/Pcd/<StructuredPcdName>.map  [Optional]
    - <PackageName>/Include/Pcd/<StructuredPcdName>.uni  [Optional]
  * C Pre-Processor Support
    - Use of #include, #define, #if supported
    - #include limited to files in same package
    - Including files from other packages being evaluated

## C Structure Syntax
  * Support struct/union/array with nesting
  * Support bit fields
  * Support #pragma pack
  * Support flexible array member
  * Leaf field data types: BOOLEAN, UINT8, UINT16, UINT32, UINT64
  * Additional leaf field data types supported to share structure between PCD
    and VFR NV storage structure: CHAR16, EFI_HII_TIME, EFI_HII_DATE, EFI_GUID,
    EFI_HII_REF, EFI_QUESTION_ID, EFI_STRING_ID, and EFI_FORM_ID
  * Field comment block syntax

```
// <Detailed Description>
// @Prompt <One line prompt for a Structured PCD field>
// @DefaultValue <Default Value for a Structured PCD field>
// @ValidRange <Range of valid values for a Structured PCD field>
// @ValidList <Comma separated list of valid values for a Structured PCD field>
// @Expression <Expression to check if a for a Structured PCD field value is 
valid>
// @TokenNumber <Hex Value>
```

  * Re-use same syntax as DEC file for same tags
  * Default Value Syntax Extensions
    - Support hexidecimal, decimal, TRUE, FALSE, ASCII String, Unicode String,
      Character Constants.
    - See RFC http://article.gmane.org/gmane.comp.bios.edk2.devel/12442
  * Field Property
    - RESERVED - A field with no comments.  Init to 0.  No Get/Set.
    - HIDDEN - A field with @TokenNumber of 0.  Init to @DefaultValue.  No 
Get/Set.
    - NORMAL - Supports Get/Set
  * Example C Structure

```
typedef {
  //
  // Nested structure field Bit0.
  // Multiple line description.
  // @DefaultValue 0
  //
  UINT8  Bit0:1;
  //
  // Nested structure field Bit1
  // @DefaultValue 1
  //
  UINT8  Bit1:1;
  //
  // @DefaultValue 2
  //
  UINT8  Bit2_3:2;
  UINT8  Reserved:1;
  //
  // @DefaultValue 6
  //
  UINT8  BitRest:3;
} ANOTHER;

typedef struct {
  //
  // My first BOOLEAN PCD description
  // @Prompt Enter BOOLEAN Value
  //
  BOOLEAN  Bool;
  //
  // My first PCD description
  // @Prompt Enter Value
  // @DefaultValue 9
  //
  UINT8  A:4;
  /*
  My old style comment PCD description
  @Prompt Enter Value
  @DefaultValue 4
  */
  UINT8  B:4;
 
  //
  // If this structure is packed, then this field is unaligned
  //
  // @DefaultValue 0xDEADBEEF
  UINT32  Unaligned32;

  ///
  /// New style Doxygen PCD description
  /// @DefaultValue 0x6789
  ///
  UINT16  C;

  /**
  My old style doxygen PCD description
  @Prompt Enter Value
  @DefaultValue 0xABCD
  **/
  UINT16  D;
  UINT32  E;              // @DefaultValue 9999999
  UINT32  F;              // @DefaultValue 1234567
  ///
  /// My new style comment block PCD description
  /// @Prompt Enter Second Value
  /// @DefaultValue 0xaaaabbbbccccdddd
  ///
  UINT64     G;
  // @DefaultValue 0
  UINT64     H;

  UINT8    Reserved;
  UINT8    Hidden;        // @TokenNumber   0x00000000
  UINT8    OneLine8;      // @DefaultValue  'J'
  UINT16   OneLine16;     // @DefaultValue  "K"
  UINT32   OneLine32;     // @DefaultValue  L"L"
  UINT64   OneLine64;     // @DefaultValue  {0, 0xa, 'M', TRUE}
  BOOLEAN  OneLineBoolA;  // @DefaultValue  TRUE
  BOOLEAN  OneLineBoolB;  // @DefaultValue  FALSE
  BOOLEAN  OneLineBoolC;  // @DefaultValue  1
  BOOLEAN  OneLineBoolD;  // @DefaultValue  0

  ///
  /// Comment Block for nested type
  ///
  ANOTHER     Another;

  //
  // Fixed array of nested type
  //
  ANOTHER     AnotherArray[2];

  union {
    // Nested union array field comment block
    UINT8  Foo[8];
    // Nested union comment block
    // @DefaultValue 0x1234567812345678
    UINT64  Bar;
  } Array[0x8];

  struct {
    struct {
      struct {
        struct {
          UINT16 Filler1;         //  @DefaultValue 0xaa55
          UINT8  Message[10];     //  @DefaultValue "Hello"
          UINT16 Filler2;         //  @DefaultValue 1234
        } NestedArrayLevel4[2];
      } NestedArrayLevel3[2];
    } NestedArrayLevel2[2];
  } NestedArrayLevel1[2];

  // Flexible Array of nested type
  ANOTHER     VariableArray[0];
} TEST;
```

## PCD Library Extensions
  * Add new macros to PcdLib to support access to fields in a Structured PCD
  * Adds keyword 'Field' to macro names
  * Fixed get macros not support for fields in a Structured PCD
  * Only safe set operations supported for fields in a Structured PCD
  * New macros


```
#define PcdFieldToken(TokenNameDotField)
#define PcdFieldPtrToken(TokenNameDotField)
#define PcdFieldTokenEx(Guid, TokenNameDotField)
#define PcdFieldPtrTokenEx(Guid, TokenNameDotField)

#define PatchPcdGetFieldSize(TokenNameDotField)
#define PatchPcdGetField8/16/32/64/Bool/Ptr(TokenNameDotField)
#define PatchPcdSetField8/16/32/64/Bool(TokenNameDotField, Value)
#define PatchPcdSetFieldPtr(TokenNameDotField, Size, Buffer)

#define PcdGetFieldSizeEx(Guid, TokenNameDotField)
#define PcdGetFieldEx8/16/32/64/Bool/Ptr(Guid, TokenNameDotField)
#define PcdSetFieldEx8/16/32/64/BoolS(Guid, TokenNameDotField, Value)
#define PcdSetFieldExPtrS(Guid, TokenNameDotField, SizeOfBuffer, Buffer)

#define PcdGetFieldSize(TokenNameDotField)
#define PcdGetField8/16/32/64/Bool/Ptr(TokenNameDotField)
#define PcdSetField8/16/32/64/BoolS(TokenNameDotField, Value)
#define PcdSetFieldPtrS(TokenNameDotField, SizeOfBuffer, Buffer)
```

  * Field get examples

```  
Print(L"  Bool             = %d\n",     PcdGetFieldBool (PcdTest.Bool));
Print(L"  A                = %d\n",     PcdGetField8    (PcdTest.A));
Print(L"  B                = %d\n",     PcdGetField8    (PcdTest.B));
Print(L"  D                = %04x\n",   PcdGetField16   (PcdTest.D));
Print(L"  Array[2].Bar     = %016lx\n", PcdGetField64   (PcdTest.Array[2].Bar));
Print(L"  Array            = %p\n",     PcdGetFieldPtr  (PcdTest.Array));
Print(L"  Array[2]         = %p\n",     PcdGetFieldPtr  (PcdTest.Array[2]));
Print(L"  sizeof(Array)    = %d\n",     PcdGetFieldSize (PcdTest.Array));
Print(L"  sizeof(Array[2]) = %d\n",     PcdGetFieldSize (PcdTest.Array[2]));  
```

  * Field set examples

```  
Status = PcdSetFieldBoolS (PcdTest.Bool, TRUE);
Status = PcdSetField8S    (PcdTest.A, 6);
Status = PcdSetField8S    (PcdTest.B, 2);
Status = PcdSetField16S   (PcdTest.D, 0xEF02);
Status = PcdSetField64S   (PcdTest.Array[2].Foo[2], 0x44);
Status = PcdSetField64S   (PcdTest.Array[2].Foo[4], 0x22);
Status = PcdSetField64S   (PcdTest.Array[2].Foo[6], 0x11);
Status = PcdSetField64S   (PcdTest.Array[3].Bar,    0x7654321076543210);
```
  
## DSC File Extensions

  * Structured PCD and all fields must be same type
    - FixedAtBuild, PatchableInModule, Dynamic, DynamicEx
  * If Structured PCD is set to subtype HII
    - Default value in DSC file is ignored.  Recommend setting to {}
    - Offset value is ignored.  Recommend setting to 0.
    - C structure shared between VFR and DEC file
    - All offsets used to access config questions from VFR/IFR match offsets 
      used to perform PCD Get/Set from modules/libs
    - Manual maintenance of HII EFI Variable offset values eliminated
  * Use full C name to override value of a field
    - <TokenSpaceGuidName>.<TokenName>.<Field1>.<Field2>...<Fieldn>|<Value>
  * <Value> supports same @DefaultValue extensions
    - See RFC http://article.gmane.org/gmane.comp.bios.edk2.devel/12442
  * Use highest array index used to determine flexible array size
  * Override values assigned in order listed in DSC files
    - Supports multiple union members in same union to be assigned different 
      values in different SKUs
  * DSC file Structured PCD field value override examples

```  
[PcdsFixedAtBuild]
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Bool|TRUE
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Array[0].Foo|L"ABC"
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Array[1].Foo|"ABC"
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Array[2].Foo|'ABCDE'
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Array[3].Foo|{0x1, 0x2, 0x3}
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Array[4].Foo|{10, 11, 12, 13, 14}
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Array[5].Foo|{'X','Y','Z'}
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.Array[6].Foo|{0x41, 0x42, 67, 68, 
'E', 'F'}
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.C|0xFEDC
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.D|2222
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.E|{'&','*'}
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.F|{35,36}
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.G|"ASCII"
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.H|L"UNI"
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.OneLine16|'MI'
  gStructuredPcdPkgTokenSpaceGuid.PcdTest.OneLine32|{0x21,0x22}
```

  * DSC file Structured PCD flexible array field value override examples

```  
[PcdsPatchableInModule]
  # Override UINT8 flexible array with new ASCII string
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayUint8.VariableArray|"Override
 of ASCII String"
 
  # Override UINT16 flexible array with new Unicode string
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayUint16.VariableArray|L"Override
 of Unicode String"
 
  # Set flexible array of structures to 5 elements (0..4)
  # Overrides default values of bit fields within each array index
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayStructure.VariableArray[0].Bit0|1
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayStructure.VariableArray[1].Bit1|0
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayStructure.VariableArray[2].Bit2_3|3
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayStructure.VariableArray[3].BitRest|0
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayStructure.VariableArray[4].BitRest|1
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayStructure.VariableArray[4].Last|1
 
  # Set flexible array of structures to 9 elements (0..8)
  
gStructuredPcdPkgTokenSpaceGuid.PcdTestFlexibleArrayNestedStructure.VariableArray[8].Z|0x44
```  
  
## PCD Report Format Extensions
  * Add new PCD report subtype for Structured PCDs (Default enabled)
  * Show Structured PCD Token Space Guid Name and Token Name
  * For each field in Structured PCD show
    - Token Number, Byte/Bit offset of the field, Byte/Bit length of the field, 
      Name of the field, value of field
    - List fields that have RESERVED or HIDDEN property
  * Sample Structured PCD report

```
gStructuredPcdPkgTokenSpaceGuid.PcdTest
----------------------------------------------------------
    Number      Offset   Width  Field Name
  ----------    ------  ------  ----------------------------
  0x00002178    373        1    .Another
  0x00002179    373:0       :1  .Another.Bit0
  0x0000217a    373:1       :1  .Another.Bit1
  0x0000217b    373:2       :2  .Another.Bit2_3
                373:4       :1  .Another.Reserved
  0x0000217c    373:5       :3  .Another.BitRest
  0x0000217d    374        2    .AnotherArray
  0x0000217e    374        1    .AnotherArray[0]
```
    
## Structured PCD Token Maps
  * EDK II build assigns token number from range declared in DEC file
    - Token Map file generated in build output directory.  Developer can choose 
      when/if to copy into package 
    - Lock down @TokenMap at milestones or releases
    - Allows backwards compatible changes to C structure
    - Token numbers may not be in numerical order
  * If @TokenNumber is present, then it must be in range
  * If @TokenMap file is declared, the use those token numbers first
  * No duplicate token numbers generated
  * EDK II build generates @TokenMap output file.  Uses C file comment syntax
  
  // @AssignedTokenNumber 
<TokenSpaceGuid>.<TokenName>.<Field1>.<Field2>...<FieldN> <TokenNumber>

  * Example token map comment block

```  
// @AssignedTokenNumber 0x00002000 gStructuredPcdPkgTokenSpaceGuid.PcdTest.Bool
// @AssignedTokenNumber 0x00002001 gStructuredPcdPkgTokenSpaceGuid.PcdTest.A
// @AssignedTokenNumber 0x00002002 gStructuredPcdPkgTokenSpaceGuid.PcdTest.B
// @AssignedTokenNumber 0x00002003 
gStructuredPcdPkgTokenSpaceGuid.PcdTest.Unaligned32
```

## Structured PCD UNI Files
  * Extract @Prompt and Detailed Description from comment blocks
    - Strings are assumed to be en-US language code
    - Replace '.' with '_'
    - Replace array [] with _i_.  All indexes in array have same strings.
  * Generate UNI file with string tokens for Structured PCD Fields
    - Generate in build output directory.  Developer can choose when/if to copy 
into package
    - Can be used as a starting point and cleaned up later
    - Can be used to translate strings to other languages
  * Example UNI output file    

```
#string STR_gStructuredPcdPkgTokenSpaceGuid_PcdTest_Bool_HELP   #language en-US 
"My first BOOLEAN PCD description"
#string STR_gStructuredPcdPkgTokenSpaceGuid_PcdTest_Bool_PROMPT #language en-US 
"Enter BOOLEAN Value"
#string STR_gStructuredPcdPkgTokenSpaceGuid_PcdTest_A_HELP      #language en-US 
"My first PCD description"
#string STR_gStructuredPcdPkgTokenSpaceGuid_PcdTest_A_PROMPT    #language en-US 
"Enter Value"
#string STR_gStructuredPcdPkgTokenSpaceGuid_PcdTest_B_HELP      #language en-US 
"Old style comment PCD description"
#string STR_gStructuredPcdPkgTokenSpaceGuid_PcdTest_B_PROMPT    #language en-US 
"Enter Value"
```  

Best regards,

Mike
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to