From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qt1-f202.google.com (mail-qt1-f202.google.com [209.85.160.202]) by mx.groups.io with SMTP id smtpd.web09.4014.1626873887645655575 for ; Wed, 21 Jul 2021 06:24:47 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@google.com header.s=20161025 header.b=pPn+dLts; spf=pass (domain: flex--chengchieh.bounces.google.com, ip: 209.85.160.202, mailfrom: 3hid4yaokbu0rwt2vrwxtwv33v0t.r31stat0tszh.v63947.x3@flex--chengchieh.bounces.google.com) Received: by mail-qt1-f202.google.com with SMTP id b6-20020a05622a0206b029025eb726dd9bso1619799qtx.8 for ; Wed, 21 Jul 2021 06:24:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=gqglycX4zSNqhfobgg+6rx0w9AndEiV3aGpAW7pmBlk=; b=pPn+dLts+PKLtxIfvYmhF11FPL8r/F9QtvfbGM5A7Kbhqk1F43u7kn2IqMeuVaVn0Y /kSpqkA2CLRDYdlIic+SXpVDPEbsmpwk63kRjGFjcm7br5B+MCk91NgICQ1dVEsQQfP3 wEcY3gy2+MndYoJcLa7Qfzg9DstZYhsqDix/nABRmNXquICPHoOKI6dT8rkJVEomdj7R Ic0kcL+BGnKqZy7Zf7/TwU0AIUzDwpaWKCr3nvHO+GhrbM3dX5LSlOu27Pl6XMIere1h E3vCWONTFa9Q6YfKqc7hexRLti568GAVktzBdViGcw6NViMinxRoOUzOHZ+2S6gBJATz WZ4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=gqglycX4zSNqhfobgg+6rx0w9AndEiV3aGpAW7pmBlk=; b=aJ+/4SHUCX0J3zimgnZtWl68GaklCUiKj7FglwafzMEUlSBkS/ed4d4nKPbwCezmUR AS7OgnypmSv6lDnCTpkCQc27RHqF98yzZo+C7R+NbVhsM4bZPifZq0tMDrB9lFkyS4ja lOWS2OBhmuXxhRUAr3/UgtOa9c4Pb3f1eW87vOWSgXp+4frndRfnPs3MhrQYVX5REJ7e 9lzWk+lU+ci5AByqSvfo7ngI6Awueap4D+SBRWrfGBdXoX4A61hbprLb8h1A1GAUdBnQ oFmYAQwoEiqqDwLuWTnjMEtA8B/DE8uAjmFusERj50NZiZYlGGeHIHkTU8xr2k/JZoUG nIVQ== X-Gm-Message-State: AOAM530cyDChgMxOQyljPxR/bMRcGqzfbl2KQ/+3RXcOxOKRmAZN9g/+ EXBJRUegZ5lJlqHhsBl/Cbr9UBr3dEPAIZSdEuXVuFd+AN3Ud+wuxwowuDwDQwTaDeFi/sL6yhs 2x9F+rp5aDU69mVUM79ts31CXoV9tJT0SOOuvtHCwomw+ECeMCRJC+M717EX9PyNylDzAMg== X-Google-Smtp-Source: ABdhPJyi3UF0mCsJG+kaj06dwa+7GpF035K8TJ15JdVwW6gS6u8W2vNYx2l6rHFf3jj8E6DHwfKQOs0s872ROn44 X-Received: from ratho96.c.googlers.com ([fda3:e722:ac3:cc00:3:22c1:c0a8:aae]) (user=chengchieh job=sendgmr) by 2002:a05:6214:443:: with SMTP id cc3mr35904153qvb.40.1626873886400; Wed, 21 Jul 2021 06:24:46 -0700 (PDT) Date: Wed, 21 Jul 2021 13:23:28 +0000 In-Reply-To: <20210721132328.1415485-1-chengchieh@google.com> Message-Id: <20210721132328.1415485-7-chengchieh@google.com> Mime-Version: 1.0 References: <20210721132328.1415485-1-chengchieh@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v1 6/6] UefiPayloadPkg: LinuxBoot: use a text format for the configuration block. From: Cheng-Chieh Huang To: devel@edk2.groups.io Cc: Trammell Hudson , Cheng-Chieh Huang Content-Type: text/plain; charset="UTF-8" From: Trammell Hudson This adds a text command line for the UefiPayloadPkg that uses a textual magic number 'LnxBoot1' and a series of white-space separated key=value[,value...] pairs for the parameters. The v1 binary configuration structure is used if it is present instead for backwards compatability. Currently supported text command line arguments are are: * `serial=baud,base,width,type,hz,pci` (only `baud` needs to be specified, the rest have reasonable defaults) * `mem=start,end,type` Types are based on `/sys/firmware/memmaps/*/types`: 1 == "System RAM" 3 == "ACPI Tables" 4 == "ACPI Non-volatile Storage" 5 == "Reserved" * `ACPI20=base` pointer to RDSP (from `/sys/firmware/efi/systab`) * `SMBIOS=base` pointer to the SMBIOS table (also from the EFI table) Signed-off-by: Cheng-Chieh Huang --- UefiPayloadPkg/Include/Linuxboot.h | 17 +- UefiPayloadPkg/Library/LbParseLib/LbParseLib.c | 252 +++++++++++++++++--- 2 files changed, 230 insertions(+), 39 deletions(-) diff --git a/UefiPayloadPkg/Include/Linuxboot.h b/UefiPayloadPkg/Include/Linuxboot.h index 34ca18069983..56b39b5a09ff 100644 --- a/UefiPayloadPkg/Include/Linuxboot.h +++ b/UefiPayloadPkg/Include/Linuxboot.h @@ -24,8 +24,7 @@ typedef struct MemoryMapEntryStruct { UINT32 Type; } MemoryMapEntry; -typedef struct UefiPayloadConfigStruct { - UINT64 Version; +typedef struct { UINT64 AcpiBase; UINT64 AcpiSize; UINT64 SmbiosBase; @@ -33,10 +32,22 @@ typedef struct UefiPayloadConfigStruct { SerialPortConfig SerialConfig; UINT32 NumMemoryMapEntries; MemoryMapEntry MemoryMapEntries[0]; +} UefiPayloadConfigV1; + +typedef struct UefiPayloadConfigStruct { + UINT64 Version; + union { + UefiPayloadConfigV1 v1; + struct { + char cmdline[0]; // up to 64 KB + } v2; + } config; } UefiPayloadConfig; #pragma pack() -#define UEFI_PAYLOAD_CONFIG_VERSION 1 +// magic version config is "LnxBoot1" +#define UEFI_PAYLOAD_CONFIG_VERSION1 1 +#define UEFI_PAYLOAD_CONFIG_VERSION2 0x31746f6f42786e4cULL #define LINUXBOOT_MEM_RAM 1 #define LINUXBOOT_MEM_DEFAULT 2 diff --git a/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c b/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c index 34bfb6a1073f..5e68091cac91 100644 --- a/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c +++ b/UefiPayloadPkg/Library/LbParseLib/LbParseLib.c @@ -1,13 +1,12 @@ /** @file - This library will parse the linuxboot table in memory and extract those required - information. + This library will parse the linuxboot table in memory and extract those +required information. Copyright (c) 2021, the u-root Authors. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ - #include #include #include @@ -18,17 +17,42 @@ #include #include #include +#include +#include +//#include +//#include + +#define strncmp(a, b, n) AsciiStrnCmp((a), (b), (n)) + +static uint64_t parse_int(const char* s, char** end) { + UINT64 x; + + if (s[0] == '0' && s[1] == 'x') + AsciiStrHexToUint64S(s, end, &x); + else + AsciiStrDecimalToUint64S(s, end, &x); + + return x; +} + +static int isspace(const char c) { return c == ' ' || c == '\t' || c == '\n'; } // Retrieve UefiPayloadConfig from Linuxboot's uefiboot -UefiPayloadConfig* GetUefiPayLoadConfig() { - UefiPayloadConfig* config = +const UefiPayloadConfig* GetUefiPayLoadConfig() { + const UefiPayloadConfig* config = (UefiPayloadConfig*)(UINTN)(PcdGet32(PcdPayloadFdMemBase) - SIZE_64KB); - if (config->Version != UEFI_PAYLOAD_CONFIG_VERSION) { - DEBUG((DEBUG_ERROR, "Expect payload config version: %d, but get %d\n", - UEFI_PAYLOAD_CONFIG_VERSION, config->Version)); - CpuDeadLoop (); - } - return config; + + if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1 || + config->Version == UEFI_PAYLOAD_CONFIG_VERSION2) + return config; + + DEBUG((DEBUG_ERROR, + "Expect payload config version %016lx or %016lx, but get %016lx\n", + UEFI_PAYLOAD_CONFIG_VERSION1, UEFI_PAYLOAD_CONFIG_VERSION2, + config->Version)); + CpuDeadLoop(); + while (1) + ; } // Align the address and add memory rang to MemInfoCallback @@ -54,6 +78,57 @@ void AddMemoryRange(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN UINTN start, MemInfoCallback(&MemoryMap, NULL); } +const char* cmdline_next(const char* cmdline, const char** option) { + // at the end of the string, we're done + if (!cmdline || *cmdline == '\0') return NULL; + + // skip any leading whitespace + while (isspace(*cmdline)) cmdline++; + + // if we've hit the end of the string, we're done + if (*cmdline == '\0') return NULL; + + *option = cmdline; + + // find the end of this option or the string + while (!isspace(*cmdline) && *cmdline != '\0') cmdline++; + + // cmdline points to the whitespace or end of string + return cmdline; +} + +int cmdline_ints(const char* option, uint64_t args[], int max) { + // skip any leading text up to an '=' + const char* s = option; + while (1) { + const char c = *s++; + if (c == '=') break; + + if (c == '\0' || isspace(c)) { + s = option; + break; + } + } + + for (int i = 0; i < max; i++) { + char* end; + args[i] = parse_int(s, &end); + + // end of string or end of the option? + if (*end == '\0' || isspace(*end)) return i + 1; + + // not separator? signal an error if we have consumed any ints, + // otherwise return 0 saying that none were found + if (*end != ',') return i == 0 ? 0 : -1; + + // skip the , and get the next value + s = end + 1; + } + + // too many values! + return -1; +} + /** Acquire the memory information from the linuxboot table in memory. @@ -67,20 +142,50 @@ void AddMemoryRange(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN UINTN start, RETURN_STATUS EFIAPI ParseMemoryInfo(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN VOID* Params) { - UefiPayloadConfig* config; - int i; + const UefiPayloadConfig* config = GetUefiPayLoadConfig(); + if (!config) { + DEBUG( + (DEBUG_ERROR, "ParseMemoryInfo: Could not find UEFI Payload config\n")); + return RETURN_SUCCESS; + } + + if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1) { + const UefiPayloadConfigV1* config1 = &config->config.v1; + DEBUG( + (DEBUG_INFO, "MemoryMap #entries: %d\n", config1->NumMemoryMapEntries)); + + for (int i = 0; i < config1->NumMemoryMapEntries; i++) { + const MemoryMapEntry* entry = &config1->MemoryMapEntries[i]; + DEBUG((DEBUG_INFO, "Start: 0x%lx End: 0x%lx Type:%d\n", entry->Start, + entry->End, entry->Type)); + AddMemoryRange(MemInfoCallback, entry->Start, entry->End, entry->Type); + } + } else - config = GetUefiPayLoadConfig(); + if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION2) { + const char* cmdline = config->config.v2.cmdline; + const char* option; + uint64_t args[3]; - DEBUG((DEBUG_INFO, "MemoryMap #entries: %d\n", config->NumMemoryMapEntries)); + // look for the mem=start,end,type + while ((cmdline = cmdline_next(cmdline, &option))) { + if (strncmp(option, "mem=", 4) != 0) continue; - MemoryMapEntry* entry = &config->MemoryMapEntries[0]; - for (i = 0; i < config->NumMemoryMapEntries; i++) { - DEBUG((DEBUG_INFO, "Start: 0x%lx End: 0x%lx Type:%d\n", entry->Start, - entry->End, entry->Type)); - AddMemoryRange(MemInfoCallback, entry->Start, entry->End, entry->Type); - entry++; + if (cmdline_ints(option, args, 3) != 3) { + DEBUG((DEBUG_ERROR, "Parse error: '%a'\n", option)); + continue; + } + + const uint64_t start = args[0]; + const uint64_t end = args[1]; + const uint64_t type = args[2]; + + DEBUG( + (DEBUG_INFO, "Start: 0x%lx End: 0x%lx Type:%d\n", start, end, type)); + AddMemoryRange(MemInfoCallback, start, end, type); + } } + return RETURN_SUCCESS; } @@ -96,14 +201,52 @@ ParseMemoryInfo(IN BL_MEM_INFO_CALLBACK MemInfoCallback, IN VOID* Params) { RETURN_STATUS EFIAPI ParseSystemTable(OUT SYSTEM_TABLE_INFO* SystemTableInfo) { - UefiPayloadConfig* config; + const UefiPayloadConfig* config = GetUefiPayLoadConfig(); + if (!config) { + DEBUG((DEBUG_ERROR, + "ParseSystemTable: Could not find UEFI Payload config\n")); + return RETURN_SUCCESS; + } - config = GetUefiPayLoadConfig(); - SystemTableInfo->AcpiTableBase = config->AcpiBase; - SystemTableInfo->AcpiTableSize = config->AcpiSize; + if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1) { + const UefiPayloadConfigV1* config1 = &config->config.v1; + SystemTableInfo->AcpiTableBase = config1->AcpiBase; + SystemTableInfo->AcpiTableSize = config1->AcpiSize; - SystemTableInfo->SmbiosTableBase = config->SmbiosBase; - SystemTableInfo->SmbiosTableSize = config->SmbiosSize; + SystemTableInfo->SmbiosTableBase = config1->SmbiosBase; + SystemTableInfo->SmbiosTableSize = config1->SmbiosSize; + } else + + if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION2) { + const char* cmdline = config->config.v2.cmdline; + const char* option; + uint64_t args[2]; + + // look for the acpi config + while ((cmdline = cmdline_next(cmdline, &option))) { + if (strncmp(option, "ACPI20=", 7) == 0) { + const int count = cmdline_ints(option, args, 2); + if (count < 0) { + DEBUG((DEBUG_ERROR, "Parse error: '%a'\n", option)); + continue; + } + + if (count > 0) SystemTableInfo->AcpiTableBase = args[0]; + if (count > 1) SystemTableInfo->AcpiTableSize = args[1]; + } + + if (strncmp(option, "SMBIOS=", 7) == 0) { + const int count = cmdline_ints(option, args, 2); + if (count < 0) { + DEBUG((DEBUG_ERROR, "Parse error: '%a'\n", option)); + continue; + } + + if (count > 0) SystemTableInfo->SmbiosTableBase = args[0]; + if (count > 1) SystemTableInfo->SmbiosTableSize = args[1]; + } + } + } return RETURN_SUCCESS; } @@ -120,15 +263,52 @@ ParseSystemTable(OUT SYSTEM_TABLE_INFO* SystemTableInfo) { RETURN_STATUS EFIAPI ParseSerialInfo(OUT SERIAL_PORT_INFO* SerialPortInfo) { - UefiPayloadConfig* config; - config = GetUefiPayLoadConfig(); - - SerialPortInfo->BaseAddr = config->SerialConfig.BaseAddr; - SerialPortInfo->RegWidth = config->SerialConfig.RegWidth; - SerialPortInfo->Type = config->SerialConfig.Type; - SerialPortInfo->Baud = config->SerialConfig.Baud; - SerialPortInfo->InputHertz = config->SerialConfig.InputHertz; - SerialPortInfo->UartPciAddr = config->SerialConfig.UartPciAddr; + // fill in some reasonable defaults + SerialPortInfo->BaseAddr = 0x3f8; + SerialPortInfo->RegWidth = 1; + SerialPortInfo->Type = 1; // uefi.SerialPortTypeIO + SerialPortInfo->Baud = 115200; + SerialPortInfo->InputHertz = 1843200; + SerialPortInfo->UartPciAddr = 0; + + const UefiPayloadConfig* config = GetUefiPayLoadConfig(); + if (!config) { + DEBUG((DEBUG_ERROR, "ParseSerialInfo: using default config\n")); + return RETURN_SUCCESS; + } + + if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION1) { + const UefiPayloadConfigV1* config1 = &config->config.v1; + SerialPortInfo->BaseAddr = config1->SerialConfig.BaseAddr; + SerialPortInfo->RegWidth = config1->SerialConfig.RegWidth; + SerialPortInfo->Type = config1->SerialConfig.Type; + SerialPortInfo->Baud = config1->SerialConfig.Baud; + SerialPortInfo->InputHertz = config1->SerialConfig.InputHertz; + SerialPortInfo->UartPciAddr = config1->SerialConfig.UartPciAddr; + } else + + if (config->Version == UEFI_PAYLOAD_CONFIG_VERSION2) { + const char* cmdline = config->config.v2.cmdline; + const char* option; + uint64_t args[6] = {}; + + while ((cmdline = cmdline_next(cmdline, &option))) { + if (strncmp(option, "serial=", 7) != 0) continue; + + const int count = cmdline_ints(option, args, 6); + if (count < 0) { + DEBUG((DEBUG_ERROR, "Parse error: %a\n", option)); + continue; + } + + if (count > 0) SerialPortInfo->Baud = args[0]; + if (count > 1) SerialPortInfo->BaseAddr = args[1]; + if (count > 2) SerialPortInfo->RegWidth = args[2]; + if (count > 3) SerialPortInfo->Type = args[3]; + if (count > 4) SerialPortInfo->InputHertz = args[4]; + if (count > 5) SerialPortInfo->UartPciAddr = args[5]; + } + } return RETURN_SUCCESS; } -- 2.32.0.402.g57bb445576-goog