<div dir="ltr">Here is the documentation: <a href="https://github.com/osresearch/kexec-load/blob/main/README.md">https://github.com/osresearch/kexec-load/blob/main/README.md</a></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jul 22, 2021 at 1:09 AM Marvin Häuser <<a href="mailto:mhaeuser@posteo.de">mhaeuser@posteo.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
<br>
On 21.07.21 15:23, Cheng-Chieh Huang via <a href="http://groups.io" rel="noreferrer" target="_blank">groups.io</a> wrote:<br>
> From: Trammell Hudson <<a href="mailto:hudson@trmm.net" target="_blank">hudson@trmm.net</a>><br>
><br>
> This adds a text command line for the UefiPayloadPkg that uses<br>
> a textual magic number 'LnxBoot1' and a series of white-space<br>
> separated key=value[,value...] pairs for the parameters.<br>
><br>
> The v1 binary configuration structure is used if it is present instead<br>
> for backwards compatability.<br>
><br>
> Currently supported text command line arguments are are:<br>
><br>
> * `serial=baud,base,width,type,hz,pci`<br>
> (only `baud` needs to be specified, the rest have reasonable<br>
> defaults)<br>
><br>
> * `mem=start,end,type`<br>
> Types are based on `/sys/firmware/memmaps/*/types`:<br>
>      1 == "System RAM"<br>
>      3 == "ACPI Tables"<br>
>      4 == "ACPI Non-volatile Storage"<br>
>      5 == "Reserved"<br>
><br>
> * `ACPI20=base` pointer to RDSP (from `/sys/firmware/efi/systab`)<br>
><br>
> * `SMBIOS=base` pointer to the SMBIOS table (also from the EFI table)<br>
><br>
> Signed-off-by: Cheng-Chieh Huang <<a href="mailto:chengchieh@google.com" target="_blank">chengchieh@google.com</a>><br>
> ---<br>
>   UefiPayloadPkg/Include/Linuxboot.h             |  17 +-<br>
>   UefiPayloadPkg/Library/LbParseLib/LbParseLib.c | 252 +++++++++++++++++---<br>
>   2 files changed, 230 insertions(+), 39 deletions(-)<br>
><br>
> diff --git a/UefiPayloadPkg/Include/Linuxboot.h b/UefiPayloadPkg/Include/Linuxboot.h<br>
> index 34ca18069983..56b39b5a09ff 100644<br>
> --- a/UefiPayloadPkg/Include/Linuxboot.h<br>
> +++ b/UefiPayloadPkg/Include/Linuxboot.h<br>
> @@ -24,8 +24,7 @@ typedef struct MemoryMapEntryStruct {<br>
>     UINT32 Type;<br>
>   } MemoryMapEntry;<br>
>   <br>
> -typedef struct UefiPayloadConfigStruct {<br>
> -  UINT64 Version;<br>
> +typedef struct {<br>
>     UINT64 AcpiBase;<br>
>     UINT64 AcpiSize;<br>
>     UINT64 SmbiosBase;<br>
> @@ -33,10 +32,22 @@ typedef struct UefiPayloadConfigStruct {<br>
>     SerialPortConfig SerialConfig;<br>
>     UINT32 NumMemoryMapEntries;<br>
>     MemoryMapEntry MemoryMapEntries[0];<br>
> +} UefiPayloadConfigV1;<br>
> +<br>
> +typedef struct UefiPayloadConfigStruct {<br>
> +  UINT64 Version;<br>
> +  union {<br>
> +    UefiPayloadConfigV1 v1;<br>
> +    struct {<br>
> +      char cmdline[0]; // up to 64 KB<br>
> +    } v2;<br>
> +  } config;<br>
>   } UefiPayloadConfig;<br>
>   #pragma pack()<br>
>   <br>
> -#define UEFI_PAYLOAD_CONFIG_VERSION 1<br>
> +// magic version config is "LnxBoot1"<br>
> +#define UEFI_PAYLOAD_CONFIG_VERSION1 1<br>
> +#define UEFI_PAYLOAD_CONFIG_VERSION2 0x31746f6f42786e4cULL<br>
>   <br>
>   #define LINUXBOOT_MEM_RAM 1<br>
>   #define LINUXBOOT_MEM_DEFAULT 2<br>
> diff --git a/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c b/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c<br>
> index 34bfb6a1073f..5e68091cac91 100644<br>
> --- a/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c<br>
> +++ b/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c<br>
> @@ -1,13 +1,12 @@<br>
>   /** @file<br>
> -  This library will parse the linuxboot table in memory and extract those required<br>
> -  information.<br>
> +  This library will parse the linuxboot table in memory and extract those<br>
> +required information.<br>
>   <br>
>     Copyright (c) 2021, the u-root Authors. All rights reserved.<BR><br>
>     SPDX-License-Identifier: BSD-2-Clause-Patent<br>
>   <br>
>   **/<br>
>   <br>
> -<br>
>   #include <IndustryStandard/Acpi.h><br>
>   #include <IndustryStandard/SmBios.h><br>
>   #include <Library/BaseLib.h><br>
> @@ -18,17 +17,42 @@<br>
>   #include <Library/PcdLib.h><br>
>   #include <Linuxboot.h><br>
>   #include <Uefi/UefiBaseType.h><br>
> +#include <stdint.h><br>
> +#include <stdlib.h><br>
> +//#include <string.h><br>
> +//#include <ctype.h><br>
> +<br>
> +#define strncmp(a, b, n) AsciiStrnCmp((a), (b), (n))<br>
> +<br>
> +static uint64_t parse_int(const char* s, char** end) {<br>
> +  UINT64 x;<br>
> +<br>
> +  if (s[0] == '0' && s[1] == 'x')<br>
> +    AsciiStrHexToUint64S(s, end, &x);<br>
> +  else<br>
> +    AsciiStrDecimalToUint64S(s, end, &x);<br>
> +<br>
> +  return x;<br>
> +}<br>
> +<br>
> +static int isspace(const char c) { return c == ' ' || c == '\t' || c == '\n'; }<br>
>   <br>
>   // Retrieve UefiPayloadConfig from Linuxboot's uefiboot<br>
> -UefiPayloadConfig* GetUefiPayLoadConfig() {<br>
> -  UefiPayloadConfig* config =<br>
> +const UefiPayloadConfig* GetUefiPayLoadConfig() {<br>
> +  const UefiPayloadConfig* config =<br>
>         (UefiPayloadConfig*)(UINTN)(PcdGet32(PcdPayloadFdMemBase) - SIZE_64KB);<br>
> -  if (config->Version != UEFI_PAYLOAD_CONFIG_VERSION) {<br>
> -    DEBUG((DEBUG_ERROR, "Expect payload config version: %d, but get %d\n",<br>
> -           UEFI_PAYLOAD_CONFIG_VERSION, config->Version));<br>
> -    CpuDeadLoop ();<br>
> -  }<br>
> -  return config;<br>
> +<br>
> +  if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1 ||<br>
> +      config->Version == UEFI_PAYLOAD_CONFIG_VERSION2)<br>
> +    return config;<br>
> +<br>
> +  DEBUG((DEBUG_ERROR,<br>
> +         "Expect payload config version %016lx or %016lx, but get %016lx\n",<br>
> +         UEFI_PAYLOAD_CONFIG_VERSION1, UEFI_PAYLOAD_CONFIG_VERSION2,<br>
> +         config->Version));<br>
> +  CpuDeadLoop();<br>
> +  while (1)<br>
> +    ;<br>
>   }<br>
>   <br>
>   // Align the address and add memory rang to MemInfoCallback<br>
> @@ -54,6 +78,57 @@ void AddMemoryRange(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN UINTN start,<br>
>     MemInfoCallback(&MemoryMap, NULL);<br>
>   }<br>
>   <br>
> +const char* cmdline_next(const char* cmdline, const char** option) {<br>
> +  // at the end of the string, we're done<br>
> +  if (!cmdline || *cmdline == '\0') return NULL;<br>
> +<br>
> +  // skip any leading whitespace<br>
> +  while (isspace(*cmdline)) cmdline++;<br>
> +<br>
> +  // if we've hit the end of the string, we're done<br>
> +  if (*cmdline == '\0') return NULL;<br>
> +<br>
> +  *option = cmdline;<br>
> +<br>
> +  // find the end of this option or the string<br>
> +  while (!isspace(*cmdline) && *cmdline != '\0') cmdline++;<br>
> +<br>
> +  // cmdline points to the whitespace or end of string<br>
> +  return cmdline;<br>
> +}<br>
> +<br>
> +int cmdline_ints(const char* option, uint64_t args[], int max) {<br>
> +  // skip any leading text up to an '='<br>
> +  const char* s = option;<br>
> +  while (1) {<br>
> +    const char c = *s++;<br>
> +    if (c == '=') break;<br>
> +<br>
> +    if (c == '\0' || isspace(c)) {<br>
> +      s = option;<br>
> +      break;<br>
> +    }<br>
> +  }<br>
> +<br>
> +  for (int i = 0; i < max; i++) {<br>
> +    char* end;<br>
> +    args[i] = parse_int(s, &end);<br>
> +<br>
> +    // end of string or end of the option?<br>
> +    if (*end == '\0' || isspace(*end)) return i + 1;<br>
> +<br>
> +    // not separator? signal an error if we have consumed any ints,<br>
> +    // otherwise return 0 saying that none were found<br>
> +    if (*end != ',') return i == 0 ? 0 : -1;<br>
> +<br>
> +    // skip the , and get the next value<br>
> +    s = end + 1;<br>
> +  }<br>
> +<br>
> +  // too many values!<br>
> +  return -1;<br>
> +}<br>
> +<br>
>   /**<br>
>     Acquire the memory information from the linuxboot table in memory.<br>
>   <br>
> @@ -67,20 +142,50 @@ void AddMemoryRange(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN UINTN start,<br>
>   RETURN_STATUS<br>
>   EFIAPI<br>
>   ParseMemoryInfo(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN VOID* Params) {<br>
> -  UefiPayloadConfig* config;<br>
> -  int i;<br>
> +  const UefiPayloadConfig* config = GetUefiPayLoadConfig();<br>
> +  if (!config) {<br>
> +    DEBUG(<br>
> +        (DEBUG_ERROR, "ParseMemoryInfo: Could not find UEFI Payload config\n"));<br>
> +    return RETURN_SUCCESS;<br>
> +  }<br>
> +<br>
> +  if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1) {<br>
> +    const UefiPayloadConfigV1* config1 = &config->config.v1;<br>
> +    DEBUG(<br>
> +        (DEBUG_INFO, "MemoryMap #entries: %d\n", config1->NumMemoryMapEntries));<br>
> +<br>
> +    for (int i = 0; i < config1->NumMemoryMapEntries; i++) {<br>
> +      const MemoryMapEntry* entry = &config1->MemoryMapEntries[i];<br>
> +      DEBUG((DEBUG_INFO, "Start: 0x%lx End: 0x%lx Type:%d\n", entry->Start,<br>
> +             entry->End, entry->Type));<br>
> +      AddMemoryRange(MemInfoCallback, entry->Start, entry->End, entry->Type);<br>
> +    }<br>
> +  } else<br>
>   <br>
> -  config = GetUefiPayLoadConfig();<br>
> +      if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION2) {<br>
> +    const char* cmdline = config->config.v2.cmdline;<br>
> +    const char* option;<br>
> +    uint64_t args[3];<br>
>   <br>
> -  DEBUG((DEBUG_INFO, "MemoryMap #entries: %d\n", config->NumMemoryMapEntries));<br>
> +    // look for the mem=start,end,type<br>
> +    while ((cmdline = cmdline_next(cmdline, &option))) {<br>
> +      if (strncmp(option, "mem=", 4) != 0) continue;<br>
>   <br>
> -  MemoryMapEntry* entry = &config->MemoryMapEntries[0];<br>
> -  for (i = 0; i < config->NumMemoryMapEntries; i++) {<br>
> -    DEBUG((DEBUG_INFO, "Start: 0x%lx End: 0x%lx Type:%d\n", entry->Start,<br>
> -           entry->End, entry->Type));<br>
> -    AddMemoryRange(MemInfoCallback, entry->Start, entry->End, entry->Type);<br>
> -    entry++;<br>
> +      if (cmdline_ints(option, args, 3) != 3) {<br>
> +        DEBUG((DEBUG_ERROR, "Parse error: '%a'\n", option));<br>
> +        continue;<br>
> +      }<br>
> +<br>
> +      const uint64_t start = args[0];<br>
> +      const uint64_t end = args[1];<br>
> +      const uint64_t type = args[2];<br>
> +<br>
> +      DEBUG(<br>
> +          (DEBUG_INFO, "Start: 0x%lx End: 0x%lx Type:%d\n", start, end, type));<br>
> +      AddMemoryRange(MemInfoCallback, start, end, type);<br>
> +    }<br>
>     }<br>
> +<br>
>     return RETURN_SUCCESS;<br>
>   }<br>
>   <br>
> @@ -96,14 +201,52 @@ ParseMemoryInfo(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN VOID* Params) {<br>
>   RETURN_STATUS<br>
>   EFIAPI<br>
>   ParseSystemTable(OUT SYSTEM_TABLE_INFO* SystemTableInfo) {<br>
> -  UefiPayloadConfig* config;<br>
> +  const UefiPayloadConfig* config = GetUefiPayLoadConfig();<br>
> +  if (!config) {<br>
> +    DEBUG((DEBUG_ERROR,<br>
> +           "ParseSystemTable: Could not find UEFI Payload config\n"));<br>
> +    return RETURN_SUCCESS;<br>
> +  }<br>
>   <br>
> -  config = GetUefiPayLoadConfig();<br>
> -  SystemTableInfo->AcpiTableBase = config->AcpiBase;<br>
> -  SystemTableInfo->AcpiTableSize = config->AcpiSize;<br>
> +  if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1) {<br>
> +    const UefiPayloadConfigV1* config1 = &config->config.v1;<br>
> +    SystemTableInfo->AcpiTableBase = config1->AcpiBase;<br>
> +    SystemTableInfo->AcpiTableSize = config1->AcpiSize;<br>
>   <br>
> -  SystemTableInfo->SmbiosTableBase = config->SmbiosBase;<br>
> -  SystemTableInfo->SmbiosTableSize = config->SmbiosSize;<br>
> +    SystemTableInfo->SmbiosTableBase = config1->SmbiosBase;<br>
> +    SystemTableInfo->SmbiosTableSize = config1->SmbiosSize;<br>
> +  } else<br>
> +<br>
> +      if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION2) {<br>
> +    const char* cmdline = config->config.v2.cmdline;<br>
> +    const char* option;<br>
> +    uint64_t args[2];<br>
> +<br>
> +    // look for the acpi config<br>
> +    while ((cmdline = cmdline_next(cmdline, &option))) {<br>
> +      if (strncmp(option, "ACPI20=", 7) == 0) {<br>
> +        const int count = cmdline_ints(option, args, 2);<br>
> +        if (count < 0) {<br>
> +          DEBUG((DEBUG_ERROR, "Parse error: '%a'\n", option));<br>
> +          continue;<br>
> +        }<br>
> +<br>
> +        if (count > 0) SystemTableInfo->AcpiTableBase = args[0];<br>
> +        if (count > 1) SystemTableInfo->AcpiTableSize = args[1];<br>
> +      }<br>
> +<br>
> +      if (strncmp(option, "SMBIOS=", 7) == 0) {<br>
> +        const int count = cmdline_ints(option, args, 2);<br>
> +        if (count < 0) {<br>
> +          DEBUG((DEBUG_ERROR, "Parse error: '%a'\n", option));<br>
> +          continue;<br>
> +        }<br>
> +<br>
> +        if (count > 0) SystemTableInfo->SmbiosTableBase = args[0];<br>
> +        if (count > 1) SystemTableInfo->SmbiosTableSize = args[1];<br>
> +      }<br>
<br>
Sorry, from only a quick peak, can this not leave {Acpi,Smbios}TableBase <br>
and {Acpi,Smbios}TableSize undefined entirely, while returning <br>
RETURN_SUCCESS?<br>
Even if not, it looks kind of odd a command-line argument can change the <br>
base address without changing the size, is there a documentation of this <br>
behaviour?<br>
What is the structure supposed to carry if no such arguments are given <br>
at all?<br>
<br>
Thanks for your time!<br>
<br>
Best regards,<br>
Marvin<br>
<br>
> +    }<br>
> +  }<br>
>   <br>
>     return RETURN_SUCCESS;<br>
>   }<br>
> @@ -120,15 +263,52 @@ ParseSystemTable(OUT SYSTEM_TABLE_INFO* SystemTableInfo) {<br>
>   RETURN_STATUS<br>
>   EFIAPI<br>
>   ParseSerialInfo(OUT SERIAL_PORT_INFO* SerialPortInfo) {<br>
> -  UefiPayloadConfig* config;<br>
> -  config = GetUefiPayLoadConfig();<br>
> -<br>
> -  SerialPortInfo->BaseAddr = config->SerialConfig.BaseAddr;<br>
> -  SerialPortInfo->RegWidth = config->SerialConfig.RegWidth;<br>
> -  SerialPortInfo->Type = config->SerialConfig.Type;<br>
> -  SerialPortInfo->Baud = config->SerialConfig.Baud;<br>
> -  SerialPortInfo->InputHertz = config->SerialConfig.InputHertz;<br>
> -  SerialPortInfo->UartPciAddr = config->SerialConfig.UartPciAddr;<br>
> +  // fill in some reasonable defaults<br>
> +  SerialPortInfo->BaseAddr = 0x3f8;<br>
> +  SerialPortInfo->RegWidth = 1;<br>
> +  SerialPortInfo->Type = 1;  // uefi.SerialPortTypeIO<br>
> +  SerialPortInfo->Baud = 115200;<br>
> +  SerialPortInfo->InputHertz = 1843200;<br>
> +  SerialPortInfo->UartPciAddr = 0;<br>
> +<br>
> +  const UefiPayloadConfig* config = GetUefiPayLoadConfig();<br>
> +  if (!config) {<br>
> +    DEBUG((DEBUG_ERROR, "ParseSerialInfo: using default config\n"));<br>
> +    return RETURN_SUCCESS;<br>
> +  }<br>
> +<br>
> +  if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1) {<br>
> +    const UefiPayloadConfigV1* config1 = &config->config.v1;<br>
> +    SerialPortInfo->BaseAddr = config1->SerialConfig.BaseAddr;<br>
> +    SerialPortInfo->RegWidth = config1->SerialConfig.RegWidth;<br>
> +    SerialPortInfo->Type = config1->SerialConfig.Type;<br>
> +    SerialPortInfo->Baud = config1->SerialConfig.Baud;<br>
> +    SerialPortInfo->InputHertz = config1->SerialConfig.InputHertz;<br>
> +    SerialPortInfo->UartPciAddr = config1->SerialConfig.UartPciAddr;<br>
> +  } else<br>
> +<br>
> +      if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION2) {<br>
> +    const char* cmdline = config->config.v2.cmdline;<br>
> +    const char* option;<br>
> +    uint64_t args[6] = {};<br>
> +<br>
> +    while ((cmdline = cmdline_next(cmdline, &option))) {<br>
> +      if (strncmp(option, "serial=", 7) != 0) continue;<br>
> +<br>
> +      const int count = cmdline_ints(option, args, 6);<br>
> +      if (count < 0) {<br>
> +        DEBUG((DEBUG_ERROR, "Parse error: %a\n", option));<br>
> +        continue;<br>
> +      }<br>
> +<br>
> +      if (count > 0) SerialPortInfo->Baud = args[0];<br>
> +      if (count > 1) SerialPortInfo->BaseAddr = args[1];<br>
> +      if (count > 2) SerialPortInfo->RegWidth = args[2];<br>
> +      if (count > 3) SerialPortInfo->Type = args[3];<br>
> +      if (count > 4) SerialPortInfo->InputHertz = args[4];<br>
> +      if (count > 5) SerialPortInfo->UartPciAddr = args[5];<br>
> +    }<br>
> +  }<br>
>   <br>
>     return RETURN_SUCCESS;<br>
>   }<br>
<br>
</blockquote></div>


 <div width="1" style="color:white;clear:both">_._,_._,_</div> <hr>   Groups.io Links:<p>   You receive all messages sent to this group.    <p> <a target="_blank" href="https://edk2.groups.io/g/devel/message/78092">View/Reply Online (#78092)</a> |    |  <a target="_blank" href="https://groups.io/mt/84357538/1813853">Mute This Topic</a>  | <a href="https://edk2.groups.io/g/devel/post">New Topic</a><br>    <a href="https://edk2.groups.io/g/devel/editsub/1813853">Your Subscription</a> | <a href="mailto:devel+owner@edk2.groups.io">Contact Group Owner</a> |  <a href="https://edk2.groups.io/g/devel/unsub">Unsubscribe</a>  [edk2-devel-archive@redhat.com]<br> <div width="1" style="color:white;clear:both">_._,_._,_</div>