weidongwd has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/74830 )
Change subject: ACPI,SMBIOS : Provide ACPI and SMBIOS support for RISC-V ......................................................................
ACPI,SMBIOS : Provide ACPI and SMBIOS support for RISC-V
Adapt ACPI and SMBIOS related codes for RISC-V arch, and then pass their addresses to the OS via device tree. Due to the limitation of device tree, coreboot cannot transfer hardware configurations flexibly at present, so add ACPI and SMBIOS support to RISC-V arch to support complex computer systems.
TEST=Builds
Change-Id: Ia2cba642a22532b18adf918a4befaf274e1f0e65 Signed-off-by: weidongwd weidong.wd@bytedance.com --- M src/Kconfig M src/acpi/Kconfig M src/acpi/acpi.c M src/arch/riscv/Makefile.inc A src/arch/riscv/smbios.c A src/arch/riscv/smbios_defaults.c M src/arch/riscv/tables.c M src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h M src/include/acpi/acpi.h M src/soc/ucb/riscv/cbmem.c 10 files changed, 1,608 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/30/74830/1
diff --git a/src/Kconfig b/src/Kconfig index e35df43..a47c430 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -856,7 +856,7 @@ If unsure, say Y.
config GENERATE_SMBIOS_TABLES - depends on ARCH_X86 + #depends on ARCH_X86 bool "Generate SMBIOS tables" default y help diff --git a/src/acpi/Kconfig b/src/acpi/Kconfig index 3b02070..7e28a34 100644 --- a/src/acpi/Kconfig +++ b/src/acpi/Kconfig @@ -70,3 +70,13 @@ depends on HAVE_ACPI_TABLES help Selected by platforms that support and fill Intel Low Power Idle Table. + +config ACPI_PPTT + bool + help + Build an ACPI Processor Properties Topology Table. + +config ACPI_RTDT + bool + help + Build an ACPI RISC-V Timer Description Table. diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index e06ac47..7408f23 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -16,8 +16,10 @@ #include <acpi/acpi.h> #include <acpi/acpi_ivrs.h> #include <acpi/acpigen.h> +#if ENV_X86 #include <arch/hpet.h> #include <arch/smp/mpspec.h> +#endif #include <cbfs.h> #include <cbmem.h> #include <commonlib/helpers.h> @@ -26,10 +28,13 @@ #include <cpu/cpu.h> #include <device/mmio.h> #include <device/pci.h> +#if CONFIG(DRIVERS_MC146818) #include <pc80/mc146818rtc.h> +#endif #include <string.h> #include <types.h> #include <version.h> +#include <device/pci_def.h>
#if ENV_X86 #include <arch/ioapic.h> @@ -123,6 +128,7 @@ return sizeof(acpi_mcfg_mmconfig_t); }
+#if ENV_X86 static int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic) { lapic->type = LOCAL_APIC; /* Local APIC structure */ @@ -210,7 +216,6 @@ return ioapic->length; }
-#if ENV_X86 /* For a system with multiple I/O APICs it's required that the one potentially routing i8259 via ExtNMI delivery calls this first to get GSI #0. */ int acpi_create_madt_ioapic_from_hw(acpi_madt_ioapic_t *ioapic, u32 addr) @@ -244,6 +249,7 @@ #endif }
+#if ENV_X86 int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride, u8 bus, u8 source, u32 gsirq, u16 flags) { @@ -337,6 +343,7 @@ current = acpi_create_madt_lapic_nmis(current); return current; } +#endif
static void acpi_create_madt(acpi_madt_t *madt) { @@ -358,6 +365,7 @@ header->length = sizeof(acpi_madt_t); header->revision = get_acpi_table_revision(MADT);
+ #if ENV_X86 madt->lapic_addr = cpu_get_lapic_addr(); if (CONFIG(ACPI_HAVE_PCAT_8259)) madt->flags |= 1; @@ -367,6 +375,7 @@
if (CONFIG(ACPI_COMMON_MADT_IOAPIC)) current = acpi_create_madt_ioapic_gsi0_default(current); + #endif
if (CONFIG(ACPI_CUSTOM_MADT)) current = acpi_fill_madt(current); @@ -377,6 +386,66 @@ header->checksum = acpi_checksum((void *)madt, header->length); }
+#if CONFIG(ACPI_PPTT) +static void acpi_create_pptt(acpi_header_t *pptt) +{ + acpi_header_t *header = pptt; + unsigned long current; + + memset((void *)pptt, 0, sizeof(acpi_header_t)); + + if (!header) + return; + + /* Fill out header fields. */ + memcpy(header->signature, "PPTT", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->asl_compiler_revision = asl_revision; + header->length = sizeof(acpi_header_t); + header->revision = get_acpi_table_revision(PPTT); + + current = acpi_fill_pptt((unsigned long)pptt); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)pptt; + + header->checksum = acpi_checksum((void *)pptt, header->length); +} +#endif + +#if CONFIG(ACPI_RTDT) +static void acpi_create_rtdt(acpi_rtdt_t *rtdt) +{ + acpi_header_t *header = &(rtdt->header); + unsigned long current; + + memset((void *)rtdt, 0, sizeof(acpi_rtdt_t)); + + if (!header) + return; + + /* Fill out header fields. */ + memcpy(header->signature, "RTDT", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->asl_compiler_revision = asl_revision; + header->length = sizeof(acpi_madt_t); + header->revision = get_acpi_table_revision(RTDT); + + current = acpi_fill_rtdt((unsigned long)rtdt); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)rtdt; + + header->checksum = acpi_checksum((void *)rtdt, header->length); +} +#endif + static unsigned long acpi_fill_mcfg(unsigned long current) { current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current, @@ -997,6 +1066,7 @@ SCOPE_IOAPIC, enumeration_id, bus, dev, fn); }
+#if ENV_X86 unsigned long acpi_create_dmar_ds_ioapic_from_hw(unsigned long current, u32 addr, u8 bus, u8 dev, u8 fn) { @@ -1004,6 +1074,7 @@ return acpi_create_dmar_ds(current, SCOPE_IOAPIC, enumeration_id, bus, dev, fn); } +#endif
unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current, u8 enumeration_id, u8 bus, u8 dev, u8 fn) @@ -1041,6 +1112,7 @@ header->checksum = acpi_checksum((void *)slit, header->length); }
+#if ENV_X86 /* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */ static void acpi_create_hpet(acpi_hpet_t *hpet) { @@ -1075,6 +1147,7 @@
header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t)); } +#endif
/* * This method adds the ACPI error injection capability. It fills the default information. @@ -1364,6 +1437,7 @@ header->checksum = acpi_checksum((void *)crat, header->length); }
+#if ENV_X86 unsigned long acpi_write_hpet(const struct device *device, unsigned long current, acpi_rsdp_t *rsdp) { @@ -1382,6 +1456,7 @@
return current; } +#endif
static void acpi_create_dbg2(acpi_dbg2_header_t *dbg2, int port_type, int port_subtype, @@ -1748,8 +1823,9 @@
fadt->preferred_pm_profile = acpi_get_preferred_pm_profile();
- if (CONFIG(USE_PC_CMOS_ALTCENTURY)) - fadt->century = RTC_CLK_ALTCENTURY; + #if CONFIG(USE_PC_CMOS_ALTCENTURY) + fadt->century = RTC_CLK_ALTCENTURY; + #endif
fadt->sci_int = acpi_sci_int();
@@ -1840,6 +1916,12 @@ acpi_tcpa_t *tcpa; acpi_tpm2_t *tpm2; acpi_madt_t *madt; + #if CONFIG(ACPI_RTDT) + acpi_rtdt_t *rtdt; + #endif + #if CONFIG(ACPI_PPTT) + acpi_header_t *pptt; + #endif acpi_lpit_t *lpit; acpi_bert_t *bert; struct device *dev; @@ -2066,6 +2148,28 @@
current = acpi_align_current(current);
+ #if CONFIG(ACPI_PPTT) + pptt = (acpi_header_t *) current; + acpi_create_pptt(pptt); + if (pptt->length > sizeof(acpi_header_t)) { + current += pptt->length; + acpi_add_table(rsdp, pptt); + } + + current = acpi_align_current(current); + #endif + + #if CONFIG(ACPI_RTDT) + rtdt = (acpi_rtdt_t *) current; + acpi_create_rtdt(rtdt); + if (rtdt->header.length > sizeof(acpi_rtdt_t)) { + current += rtdt->header.length; + acpi_add_table(rsdp, rtdt); + } + + current = acpi_align_current(current); + #endif + if (CONFIG(ACPI_BERT)) { void *region; size_t size; @@ -2242,6 +2346,10 @@ return 1; case LPIT: /* ACPI 5.1 up to 6.3: 0 */ return 0; + case PPTT: /* ACPI 5.1 up to 6.3: 0 */ + return 2; + case RTDT: /* ACPI 5.1 up to 6.3: 0 */ + return 2; default: return -1; } diff --git a/src/arch/riscv/Makefile.inc b/src/arch/riscv/Makefile.inc index cc553c9..b4fd416 100644 --- a/src/arch/riscv/Makefile.inc +++ b/src/arch/riscv/Makefile.inc @@ -152,6 +152,9 @@
ramstage-$(CONFIG_RISCV_USE_ARCH_TIMER) += arch_timer.c
+ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c +ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios_defaults.c + $(eval $(call create_class_compiler,rmodules,riscv))
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/mainboard.c diff --git a/src/arch/riscv/smbios.c b/src/arch/riscv/smbios.c new file mode 100644 index 0000000..77a0516 --- /dev/null +++ b/src/arch/riscv/smbios.c @@ -0,0 +1,1034 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <string.h> +#include <smbios.h> +#include <console/console.h> +#include <version.h> +#include <device/device.h> +#include <device/dram/spd.h> +#include <arch/cpu.h> +#include <cpu/x86/name.h> +#include <elog.h> +#include <endian.h> +#include <memory_info.h> +#include <spd.h> +#include <cbmem.h> +#include <commonlib/helpers.h> +#include <device/pci_ids.h> +#include <device/pci.h> +#include <drivers/vpd/vpd.h> +#include <stdlib.h> + +#define update_max(len, max_len, stmt) \ + do { \ + int tmp = stmt; \ + \ + max_len = MAX(max_len, tmp); \ + len += tmp; \ + } while (0) + +int smbios_cpu_vendor(u8 *start); +int smbios_processor_name(u8 *start); + +static u8 smbios_checksum(u8 *p, u32 length) +{ + u8 ret = 0; + while (length--) + ret += *p++; + return -ret; +} + +int smbios_add_string(u8 *start, const char *str) +{ + int i = 1; + char *p = (char *)start; + + /* + * Return 0 as required for empty strings. + * See Section 6.1.3 "Text Strings" of the SMBIOS specification. + */ + if (str == NULL || *str == '\0') + return 0; + + for (;;) { + if (!*p) { + strcpy(p, str); + p += strlen(str); + *p++ = '\0'; + *p++ = '\0'; + return i; + } + + if (!strcmp(p, str)) + return i; + + p += strlen(p)+1; + i++; + } +} + +int smbios_string_table_len(u8 *start) +{ + char *p = (char *)start; + int i, len = 0; + + while (*p) { + i = strlen(p) + 1; + p += i; + len += i; + } + + if (!len) + return 2; + + return len + 1; +} + +int smbios_full_table_len(struct smbios_header *header, u8 *str_table_start) +{ + return header->length + smbios_string_table_len(str_table_start); +} + +void *smbios_carve_table(unsigned long start, u8 type, u8 length, u16 handle) +{ + struct smbios_header *t = (struct smbios_header *)start; + + assert(length >= sizeof(*t)); + memset(t, 0, length); + t->type = type; + t->length = length - 2; + t->handle = handle; + return t; +} + +/* this function will fill the corresponding manufacturer */ +void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t) +{ + const char *const manufacturer = spd_manufacturer_name(mod_id); + + if (manufacturer) { + t->manufacturer = smbios_add_string(t->eos, manufacturer); + } else { + char string_buffer[256]; + + snprintf(string_buffer, sizeof(string_buffer), "Unknown (%x)", mod_id); + t->manufacturer = smbios_add_string(t->eos, string_buffer); + } +} + +static void trim_trailing_whitespace(char *buffer, size_t buffer_size) +{ + size_t len = strnlen(buffer, buffer_size); + + if (len == 0) + return; + + for (char *p = buffer + len - 1; p >= buffer; --p) { + if (*p == ' ') + *p = 0; + else + break; + } +} + +/** This function will fill the corresponding part number */ +static void smbios_fill_dimm_part_number(const char *part_number, struct smbios_type17 *t) +{ + int invalid; + size_t i, len; + char trimmed_part_number[DIMM_INFO_PART_NUMBER_SIZE]; + + strncpy(trimmed_part_number, part_number, sizeof(trimmed_part_number)); + trimmed_part_number[sizeof(trimmed_part_number) - 1] = '\0'; + + /* + * SPD mandates that unused characters be represented with a ' '. + * We don't want to publish the whitespace in the SMBIOS tables. + */ + trim_trailing_whitespace(trimmed_part_number, sizeof(trimmed_part_number)); + + len = strlen(trimmed_part_number); + + invalid = 0; /* assume valid */ + for (i = 0; i < len; i++) { + if (trimmed_part_number[i] < ' ') { + invalid = 1; + trimmed_part_number[i] = '*'; + } + } + + if (len == 0) { + /* Null String in Part Number will have "None" instead. */ + t->part_number = smbios_add_string(t->eos, "None"); + } else if (invalid) { + char string_buffer[sizeof(trimmed_part_number) + 10]; + + snprintf(string_buffer, sizeof(string_buffer), "Invalid (%s)", + trimmed_part_number); + t->part_number = smbios_add_string(t->eos, string_buffer); + } else { + t->part_number = smbios_add_string(t->eos, trimmed_part_number); + } +} + +/* Encodes the SPD serial number into hex */ +static void smbios_fill_dimm_serial_number(const struct dimm_info *dimm, + struct smbios_type17 *t) +{ + char serial[9]; + + snprintf(serial, sizeof(serial), "%02hhx%02hhx%02hhx%02hhx", + dimm->serial[0], dimm->serial[1], dimm->serial[2], dimm->serial[3]); + + t->serial_number = smbios_add_string(t->eos, serial); +} + +static int create_smbios_type17_for_dimm(struct dimm_info *dimm, + unsigned long *current, int *handle, + int type16_handle) +{ + struct spd_info info; + get_spd_info(dimm->ddr_type, dimm->mod_type, &info); + + struct smbios_type17 *t = smbios_carve_table(*current, SMBIOS_MEMORY_DEVICE, + sizeof(*t), *handle); + + t->memory_type = dimm->ddr_type; + if (dimm->configured_speed_mts != 0) + t->clock_speed = dimm->configured_speed_mts; + else + t->clock_speed = dimm->ddr_frequency; + if (dimm->max_speed_mts != 0) + t->speed = dimm->max_speed_mts; + else + t->speed = dimm->ddr_frequency; + if (dimm->dimm_size < 0x7fff) { + t->size = dimm->dimm_size; + } else { + t->size = 0x7fff; + t->extended_size = dimm->dimm_size & 0x7fffffff; + } + t->data_width = 8 * (1 << (dimm->bus_width & 0x7)); + t->total_width = t->data_width + 8 * ((dimm->bus_width & 0x18) >> 3); + t->form_factor = info.form_factor; + + smbios_fill_dimm_manufacturer_from_id(dimm->mod_id, t); + smbios_fill_dimm_serial_number(dimm, t); + smbios_fill_dimm_asset_tag(dimm, t); + smbios_fill_dimm_locator(dimm, t); + + /* put '\0' in the end of data */ + dimm->module_part_number[DIMM_INFO_PART_NUMBER_SIZE - 1] = '\0'; + smbios_fill_dimm_part_number((char *)dimm->module_part_number, t); + + /* Voltage Levels */ + t->configured_voltage = dimm->vdd_voltage; + t->minimum_voltage = dimm->vdd_voltage; + t->maximum_voltage = dimm->vdd_voltage; + + /* Fill in type detail */ + t->type_detail = info.type_detail; + + /* Synchronous = 1 */ + t->type_detail |= MEMORY_TYPE_DETAIL_SYNCHRONOUS; + /* no handle for error information */ + t->memory_error_information_handle = 0xFFFE; + t->attributes = dimm->rank_per_dimm; + t->phys_memory_array_handle = type16_handle; + + *handle += 1; + return smbios_full_table_len(&t->header, t->eos); +} + +static int create_smbios_type17_for_empty_slot(struct dimm_info *dimm, + unsigned long *current, int *handle, + int type16_handle) +{ + struct smbios_type17 *t = smbios_carve_table(*current, SMBIOS_MEMORY_DEVICE, + sizeof(*t), *handle); + t->phys_memory_array_handle = type16_handle; + /* no handle for error information */ + t->memory_error_information_handle = 0xfffe; + t->total_width = 0xffff; /* Unknown */ + t->data_width = 0xffff; /* Unknown */ + t->form_factor = 0x2; /* Unknown */ + smbios_fill_dimm_locator(dimm, t); /* Device and Bank */ + t->memory_type = 0x2; /* Unknown */ + t->type_detail = 0x2; /* Unknown */ + + *handle += 1; + return smbios_full_table_len(&t->header, t->eos); +} + +#define VERSION_VPD "firmware_version" +static const char *vpd_get_bios_version(void) +{ + int size; + const char *s; + char *version; + + s = vpd_find(VERSION_VPD, &size, VPD_RO); + if (!s) { + printk(BIOS_ERR, "Find version from VPD %s failed\n", VERSION_VPD); + return NULL; + } + + version = malloc(size + 1); + if (!version) { + printk(BIOS_ERR, "Failed to malloc %d bytes for VPD version\n", size + 1); + return NULL; + } + memcpy(version, s, size); + version[size] = '\0'; + printk(BIOS_DEBUG, "Firmware version %s from VPD %s\n", version, VERSION_VPD); + return version; +} + +static const char *get_bios_version(void) +{ + const char *s; + +#define SPACES \ + " " + + if (CONFIG(CHROMEOS)) + return SPACES; + + if (CONFIG(VPD_SMBIOS_VERSION)) { + s = vpd_get_bios_version(); + if (s != NULL) + return s; + } + + s = smbios_mainboard_bios_version(); + if (s != NULL) + return s; + + if (strlen(CONFIG_LOCALVERSION) != 0) { + printk(BIOS_DEBUG, "BIOS version set to CONFIG_LOCALVERSION: '%s'\n", + CONFIG_LOCALVERSION); + return CONFIG_LOCALVERSION; + } + + printk(BIOS_DEBUG, "SMBIOS firmware version is set to coreboot_version: '%s'\n", + coreboot_version); + return coreboot_version; +} + +static int smbios_write_type0(unsigned long *current, int handle) +{ + struct smbios_type0 *t = smbios_carve_table(*current, SMBIOS_BIOS_INFORMATION, + sizeof(*t), handle); + + t->vendor = smbios_add_string(t->eos, "coreboot"); + t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date); + + if (CONFIG(CHROMEOS_NVS)) { + uintptr_t version_address = (uintptr_t)t->eos; + /* SMBIOS offsets start at 1 rather than 0 */ + version_address += (u32)smbios_string_table_len(t->eos) - 1; + smbios_type0_bios_version(version_address); + } + t->bios_version = smbios_add_string(t->eos, get_bios_version()); + uint32_t rom_size = CONFIG_ROM_SIZE; + rom_size = MIN(CONFIG_ROM_SIZE, 16 * MiB); + t->bios_rom_size = (rom_size / 65535) - 1; + + if (CONFIG_ROM_SIZE >= 1 * GiB) + t->extended_bios_rom_size = DIV_ROUND_UP(CONFIG_ROM_SIZE, GiB) | (1 << 14); + else + t->extended_bios_rom_size = DIV_ROUND_UP(CONFIG_ROM_SIZE, MiB); + + t->system_bios_major_release = coreboot_major_revision; + t->system_bios_minor_release = coreboot_minor_revision; + + smbios_ec_revision(&t->ec_major_release, &t->ec_minor_release); + + t->bios_characteristics = + BIOS_CHARACTERISTICS_PCI_SUPPORTED | + BIOS_CHARACTERISTICS_SELECTABLE_BOOT | + BIOS_CHARACTERISTICS_UPGRADEABLE; + + if (CONFIG(CARDBUS_PLUGIN_SUPPORT)) + t->bios_characteristics |= BIOS_CHARACTERISTICS_PC_CARD; + + if (CONFIG(HAVE_ACPI_TABLES)) + t->bios_characteristics_ext1 = BIOS_EXT1_CHARACTERISTICS_ACPI; + + t->bios_characteristics_ext2 = BIOS_EXT2_CHARACTERISTICS_TARGET; + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + return len; +} + +unsigned int __weak smbios_processor_external_clock(void) +{ + return 0; /* Unknown */ +} + +unsigned int __weak smbios_processor_characteristics(void) +{ + return 0; +} + + +unsigned int __weak smbios_cache_error_correction_type(u8 level) +{ + return SMBIOS_CACHE_ERROR_CORRECTION_UNKNOWN; +} + +unsigned int __weak smbios_cache_sram_type(void) +{ + return SMBIOS_CACHE_SRAM_TYPE_UNKNOWN; +} + +unsigned int __weak smbios_cache_conf_operation_mode(u8 level) +{ + return SMBIOS_CACHE_OP_MODE_UNKNOWN; /* Unknown */ +} + +/* Returns the processor voltage in 100mV units */ +unsigned int __weak smbios_cpu_get_voltage(void) +{ + return 0; /* Unknown */ +} + +static int smbios_write_type1(unsigned long *current, int handle) +{ + struct smbios_type1 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_INFORMATION, + sizeof(*t), handle); + + t->manufacturer = smbios_add_string(t->eos, smbios_system_manufacturer()); + t->product_name = smbios_add_string(t->eos, smbios_system_product_name()); + t->serial_number = smbios_add_string(t->eos, smbios_system_serial_number()); + t->wakeup_type = smbios_system_wakeup_type(); + t->sku = smbios_add_string(t->eos, smbios_system_sku()); + t->version = smbios_add_string(t->eos, smbios_system_version()); +#ifdef CONFIG_MAINBOARD_FAMILY + t->family = smbios_add_string(t->eos, CONFIG_MAINBOARD_FAMILY); +#endif + smbios_system_set_uuid(t->uuid); + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + return len; +} + +static int smbios_write_type2(unsigned long *current, int handle, const int chassis_handle) +{ + struct smbios_type2 *t = smbios_carve_table(*current, SMBIOS_BOARD_INFORMATION, + sizeof(*t), handle); + + t->manufacturer = smbios_add_string(t->eos, smbios_mainboard_manufacturer()); + t->product_name = smbios_add_string(t->eos, smbios_mainboard_product_name()); + t->serial_number = smbios_add_string(t->eos, smbios_mainboard_serial_number()); + t->version = smbios_add_string(t->eos, smbios_mainboard_version()); + t->asset_tag = smbios_add_string(t->eos, smbios_mainboard_asset_tag()); + t->feature_flags = smbios_mainboard_feature_flags(); + t->location_in_chassis = smbios_add_string(t->eos, + smbios_mainboard_location_in_chassis()); + t->board_type = smbios_mainboard_board_type(); + t->chassis_handle = chassis_handle; + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + return len; +} + +static int smbios_write_type3(unsigned long *current, int handle) +{ + struct smbios_type3 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_ENCLOSURE, + sizeof(*t), handle); + + t->manufacturer = smbios_add_string(t->eos, smbios_system_manufacturer()); + t->bootup_state = SMBIOS_STATE_SAFE; + t->power_supply_state = SMBIOS_STATE_SAFE; + t->thermal_state = SMBIOS_STATE_SAFE; + t->_type = smbios_mainboard_enclosure_type(); + t->security_status = SMBIOS_STATE_SAFE; + t->number_of_power_cords = smbios_chassis_power_cords(); + t->asset_tag_number = smbios_add_string(t->eos, smbios_mainboard_asset_tag()); + t->version = smbios_add_string(t->eos, smbios_chassis_version()); + t->serial_number = smbios_add_string(t->eos, smbios_chassis_serial_number()); + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + return len; +} + +#define MAX_CPUS_ENABLED (CONFIG_MAX_CPUS > 0xff ? 0xff : CONFIG_MAX_CPUS) + +static int smbios_write_type4(unsigned long *current, int handle) +{ + //TODO + return 0; +} + +/* + * Parse the "Deterministic Cache Parameters". + * + * @param current Pointer to memory address to write the tables to + * @param handle Pointer to handle for the tables + * @param max_struct_size Pointer to maximum struct size + * @param type4 Pointer to SMBIOS type 4 structure + */ +static int smbios_write_type7_cache_parameters(unsigned long *current, + int *handle, + int *max_struct_size, + struct smbios_type4 *type4) +{ + //TODO + return 0; +} + +int smbios_write_type8(unsigned long *current, int *handle, + const struct port_information *port, + size_t num_ports) +{ + unsigned int totallen = 0, i; + + for (i = 0; i < num_ports; i++, port++) { + struct smbios_type8 *t = smbios_carve_table(*current, + SMBIOS_PORT_CONNECTOR_INFORMATION, + sizeof(*t), *handle); + t->internal_reference_designator = + smbios_add_string(t->eos, port->internal_reference_designator); + t->internal_connector_type = port->internal_connector_type; + t->external_reference_designator = + smbios_add_string(t->eos, port->external_reference_designator); + t->external_connector_type = port->external_connector_type; + t->port_type = port->port_type; + *handle += 1; + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + totallen += len; + } + return totallen; +} + +int smbios_write_type9(unsigned long *current, int *handle, + const char *name, const enum misc_slot_type type, + const enum slot_data_bus_bandwidth bandwidth, + const enum misc_slot_usage usage, + const enum misc_slot_length length, + const u16 id, u8 slot_char1, u8 slot_char2, u8 bus, u8 dev_func) +{ + struct smbios_type9 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_SLOTS, + sizeof(*t), *handle); + + t->slot_designation = smbios_add_string(t->eos, name ? name : "SLOT"); + t->slot_type = type; + /* TODO add slot_id supoort, will be "_SUN" for ACPI devices */ + t->slot_id = id; + t->slot_data_bus_width = bandwidth; + t->current_usage = usage; + t->slot_length = length; + t->slot_characteristics_1 = slot_char1; + t->slot_characteristics_2 = slot_char2; + t->segment_group_number = 0; + t->bus_number = bus; + t->device_function_number = dev_func; + t->data_bus_width = SlotDataBusWidthOther; + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + *handle += 1; + return len; +} + +static int smbios_write_type11(unsigned long *current, int *handle) +{ + struct device *dev; + struct smbios_type11 *t = smbios_carve_table(*current, SMBIOS_OEM_STRINGS, + sizeof(*t), *handle); + + for (dev = all_devices; dev; dev = dev->next) { + if (dev->ops && dev->ops->get_smbios_strings) + dev->ops->get_smbios_strings(dev, t); + } + + if (t->count == 0) { + memset(t, 0, sizeof(*t)); + return 0; + } + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + (*handle)++; + return len; +} + +static int smbios_write_type16(unsigned long *current, int *handle) +{ + int i; + uint64_t max_capacity; + + struct memory_info *meminfo; + meminfo = cbmem_find(CBMEM_ID_MEMINFO); + if (meminfo == NULL) + return 0; /* can't find mem info in cbmem */ + + printk(BIOS_INFO, "Create SMBIOS type 16\n"); + + if (meminfo->max_capacity_mib == 0 || meminfo->number_of_devices == 0) { + /* Fill in defaults if not provided */ + meminfo->number_of_devices = 0; + meminfo->max_capacity_mib = 0; + for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) { + meminfo->max_capacity_mib += meminfo->dimm[i].dimm_size; + meminfo->number_of_devices += !!meminfo->dimm[i].dimm_size; + } + } + + struct smbios_type16 *t = smbios_carve_table(*current, SMBIOS_PHYS_MEMORY_ARRAY, + sizeof(*t), *handle); + + t->location = MEMORY_ARRAY_LOCATION_SYSTEM_BOARD; + t->use = MEMORY_ARRAY_USE_SYSTEM; + t->memory_error_correction = meminfo->ecc_type; + + /* no error information handle available */ + t->memory_error_information_handle = 0xFFFE; + max_capacity = meminfo->max_capacity_mib; + if (max_capacity * (MiB / KiB) < SMBIOS_USE_EXTENDED_MAX_CAPACITY) + t->maximum_capacity = max_capacity * (MiB / KiB); + else { + t->maximum_capacity = SMBIOS_USE_EXTENDED_MAX_CAPACITY; + t->extended_maximum_capacity = max_capacity * MiB; + } + t->number_of_memory_devices = meminfo->number_of_devices; + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + (*handle)++; + return len; +} + +static int smbios_write_type17(unsigned long *current, int *handle, int type16) +{ + int totallen = 0; + int i; + + struct memory_info *meminfo; + meminfo = cbmem_find(CBMEM_ID_MEMINFO); + if (meminfo == NULL) + return 0; /* can't find mem info in cbmem */ + + printk(BIOS_INFO, "Create SMBIOS type 17\n"); + for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) { + struct dimm_info *d = &meminfo->dimm[i]; + /* + * Windows 10 GetPhysicallyInstalledSystemMemory functions reads SMBIOS tables + * type 16 and type 17. The type 17 tables need to point to a type 16 table. + * Otherwise, the physical installed memory size is guessed from the system + * memory map, which results in a slightly smaller value than the actual size. + */ + int len; + if (d->dimm_size > 0) + len = create_smbios_type17_for_dimm(d, current, handle, type16); + else + len = create_smbios_type17_for_empty_slot(d, current, handle, type16); + + *current += len; + totallen += len; + } + return totallen; +} + +static int smbios_write_type19(unsigned long *current, int *handle, int type16) +{ + int i; + + struct memory_info *meminfo; + meminfo = cbmem_find(CBMEM_ID_MEMINFO); + if (meminfo == NULL) + return 0; /* can't find mem info in cbmem */ + + struct smbios_type19 *t = smbios_carve_table(*current, + SMBIOS_MEMORY_ARRAY_MAPPED_ADDRESS, + sizeof(*t), *handle); + + t->memory_array_handle = type16; + + for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) { + if (meminfo->dimm[i].dimm_size > 0) { + t->extended_ending_address += meminfo->dimm[i].dimm_size; + t->partition_width++; + } + } + t->extended_ending_address *= MiB; + + /* Check if it fits into regular address */ + if (t->extended_ending_address >= KiB && + t->extended_ending_address < 0x40000000000ULL) { + /* + * FIXME: The starting address is SoC specific, but SMBIOS tables are only + * exported on x86 where it's always 0. + */ + + t->starting_address = 0; + t->ending_address = t->extended_ending_address / KiB - 1; + t->extended_starting_address = ~0; + t->extended_ending_address = ~0; + } else { + t->starting_address = ~0; + t->ending_address = ~0; + t->extended_starting_address = 0; + t->extended_ending_address--; + } + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + *handle += 1; + return len; +} + +static int smbios_write_type20_table(unsigned long *current, int *handle, u32 addr_start, + u32 addr_end, int type17_handle, int type19_handle) +{ + struct smbios_type20 *t = smbios_carve_table(*current, SMBIOS_MEMORY_DEVICE_MAPPED_ADDRESS, + sizeof(*t), *handle); + + t->memory_device_handle = type17_handle; + t->memory_array_mapped_address_handle = type19_handle; + t->addr_start = addr_start; + t->addr_end = addr_end; + t->partition_row_pos = 0xff; + t->interleave_pos = 0xff; + t->interleave_depth = 0xff; + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + *handle += 1; + return len; +} + +static int smbios_write_type20(unsigned long *current, int *handle, + int type17_handle, int type19_handle) +{ + u32 start_addr = 0; + int totallen = 0; + int i; + + struct memory_info *meminfo; + meminfo = cbmem_find(CBMEM_ID_MEMINFO); + if (meminfo == NULL) + return 0; /* can't find mem info in cbmem */ + + printk(BIOS_INFO, "Create SMBIOS type 20\n"); + for (i = 0; i < meminfo->dimm_cnt && i < ARRAY_SIZE(meminfo->dimm); i++) { + struct dimm_info *dimm; + dimm = &meminfo->dimm[i]; + if (dimm->dimm_size == 0) + continue; + + u32 end_addr = start_addr + (dimm->dimm_size << 10) - 1; + totallen += smbios_write_type20_table(current, handle, start_addr, end_addr, + type17_handle, type19_handle); + start_addr = end_addr + 1; + } + return totallen; +} + +int smbios_write_type28(unsigned long *current, int *handle, + const char *name, + const enum smbios_temp_location location, + const enum smbios_temp_status status, + u16 max_value, u16 min_value, + u16 resolution, u16 tolerance, + u16 accuracy, + u32 oem, + u16 nominal_value) +{ + struct smbios_type28 *t = smbios_carve_table(*current, SMBIOS_TEMPERATURE_PROBE, + sizeof(*t), *handle); + + t->description = smbios_add_string(t->eos, name ? name : "Temperature"); + t->location_and_status = location | (status << 5); + t->maximum_value = max_value; + t->minimum_value = min_value; + t->resolution = resolution; + t->tolerance = tolerance; + t->accuracy = accuracy; + t->oem_defined = oem; + t->nominal_value = nominal_value; + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + *handle += 1; + return len; +} + +static int smbios_write_type32(unsigned long *current, int handle) +{ + struct smbios_type32 *t = smbios_carve_table(*current, SMBIOS_SYSTEM_BOOT_INFORMATION, + sizeof(*t), handle); + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + return len; +} + +int smbios_write_type38(unsigned long *current, int *handle, + const enum smbios_bmc_interface_type interface_type, + const u8 ipmi_rev, const u8 i2c_addr, const u8 nv_addr, + const u64 base_addr, const u8 base_modifier, + const u8 irq) +{ + struct smbios_type38 *t = smbios_carve_table(*current, SMBIOS_IPMI_DEVICE_INFORMATION, + sizeof(*t), *handle); + + t->interface_type = interface_type; + t->ipmi_rev = ipmi_rev; + t->i2c_slave_addr = i2c_addr; + t->nv_storage_addr = nv_addr; + t->base_address = base_addr; + t->base_address_modifier = base_modifier; + t->irq = irq; + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + *handle += 1; + return len; +} + +int smbios_write_type39(unsigned long *current, int *handle, + u8 unit_group, const char *loc, const char *dev_name, + const char *man, const char *serial_num, + const char *tag_num, const char *part_num, + const char *rev_lvl, u16 max_pow_cap, + const struct power_supply_ch *ps_ch) +{ + struct smbios_type39 *t = smbios_carve_table(*current, + SMBIOS_SYSTEM_POWER_SUPPLY, + sizeof(*t), *handle); + + uint16_t val = 0; + uint16_t ps_type, ps_status, vol_switch, ps_unplug, ps_present, hot_rep; + + t->power_unit_group = unit_group; + t->location = smbios_add_string(t->eos, loc); + t->device_name = smbios_add_string(t->eos, dev_name); + t->manufacturer = smbios_add_string(t->eos, man); + t->serial_number = smbios_add_string(t->eos, serial_num); + t->asset_tag_number = smbios_add_string(t->eos, tag_num); + t->model_part_number = smbios_add_string(t->eos, part_num); + t->revision_level = smbios_add_string(t->eos, rev_lvl); + t->max_power_capacity = max_pow_cap; + + ps_type = ps_ch->power_supply_type & 0xF; + ps_status = ps_ch->power_supply_status & 0x7; + vol_switch = ps_ch->input_voltage_range_switch & 0xF; + ps_unplug = ps_ch->power_supply_unplugged & 0x1; + ps_present = ps_ch->power_supply_present & 0x1; + hot_rep = ps_ch->power_supply_hot_replaceble & 0x1; + + val |= (ps_type << 10); + val |= (ps_status << 7); + val |= (vol_switch << 3); + val |= (ps_unplug << 2); + val |= (ps_present << 1); + val |= hot_rep; + t->power_supply_characteristics = val; + + t->input_voltage_probe_handle = 0xFFFF; + t->cooling_device_handle = 0xFFFF; + t->input_current_probe_handle = 0xFFFF; + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + *handle += 1; + return len; +} + +int smbios_write_type43(unsigned long *current, int *handle, const u32 vendor_id, + const u8 major_spec_ver, const u8 minor_spec_ver, + const u32 fw_ver1, const u32 fw_ver2, const char *description, + const u64 characteristics, const u32 oem_defined) +{ + struct smbios_type43 *t = smbios_carve_table(*current, SMBIOS_TPM_DEVICE, + sizeof(*t), *handle); + + t->vendor_id = vendor_id; + t->major_spec_ver = major_spec_ver; + t->minor_spec_ver = minor_spec_ver; + t->fw_ver1 = fw_ver1; + t->fw_ver2 = fw_ver2; + t->characteristics = characteristics; + t->oem_defined = oem_defined; + t->description = smbios_add_string(t->eos, description); + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + *handle += 1; + return len; +} + +static int smbios_write_type127(unsigned long *current, int handle) +{ + struct smbios_type127 *t = smbios_carve_table(*current, SMBIOS_END_OF_TABLE, + sizeof(*t), handle); + + const int len = smbios_full_table_len(&t->header, t->eos); + *current += len; + return len; +} + +static int smbios_generate_type9_from_devtree(struct device *dev, int *handle, + unsigned long *current) +{ + enum misc_slot_usage usage; + enum slot_data_bus_bandwidth bandwidth; + enum misc_slot_type type; + enum misc_slot_length length; + + if (dev->path.type != DEVICE_PATH_PCI) + return 0; + + if (!dev->smbios_slot_type && !dev->smbios_slot_data_width && + !dev->smbios_slot_designation && !dev->smbios_slot_length) + return 0; + + if (dev_is_active_bridge(dev)) + usage = SlotUsageInUse; + else if (dev->enabled) + usage = SlotUsageAvailable; + else + usage = SlotUsageUnknown; + + if (dev->smbios_slot_data_width) + bandwidth = dev->smbios_slot_data_width; + else + bandwidth = SlotDataBusWidthUnknown; + + if (dev->smbios_slot_type) + type = dev->smbios_slot_type; + else + type = SlotTypeUnknown; + + if (dev->smbios_slot_length) + length = dev->smbios_slot_length; + else + length = SlotLengthUnknown; + + return smbios_write_type9(current, handle, + dev->smbios_slot_designation, + type, + bandwidth, + usage, + length, + 0, + 1, + 0, + dev->bus->secondary, + dev->path.pci.devfn); +} + +int get_smbios_data(struct device *dev, int *handle, unsigned long *current) +{ + int len = 0; + + len += smbios_generate_type9_from_devtree(dev, handle, current); + + return len; +} + +static int smbios_walk_device_tree(struct device *tree, int *handle, unsigned long *current) +{ + struct device *dev; + int len = 0; + + for (dev = tree; dev; dev = dev->next) { + if (!dev->enabled) + continue; + + if (dev->ops && dev->ops->get_smbios_data) { + printk(BIOS_INFO, "%s (%s)\n", dev_path(dev), dev_name(dev)); + len += dev->ops->get_smbios_data(dev, handle, current); + } else { + len += get_smbios_data(dev, handle, current); + } + } + return len; +} + +unsigned long smbios_write_tables(unsigned long current) +{ + struct smbios_entry *se; + struct smbios_entry30 *se3; + unsigned long tables; + int len = 0; + int max_struct_size = 0; + int handle = 0; + + current = ALIGN_UP(current, 16); + printk(BIOS_DEBUG, "%s: %08lx\n", __func__, current); + + se = (struct smbios_entry *)current; + current += sizeof(*se); + current = ALIGN_UP(current, 16); + + se3 = (struct smbios_entry30 *)current; + current += sizeof(*se3); + current = ALIGN_UP(current, 16); + + tables = current; + update_max(len, max_struct_size, smbios_write_type0(¤t, handle++)); + update_max(len, max_struct_size, smbios_write_type1(¤t, handle++)); + + /* The chassis handle is the next one */ + update_max(len, max_struct_size, smbios_write_type2(¤t, handle, handle + 1)); + handle++; + update_max(len, max_struct_size, smbios_write_type3(¤t, handle++)); + + struct smbios_type4 *type4 = (struct smbios_type4 *)current; + update_max(len, max_struct_size, smbios_write_type4(¤t, handle++)); + len += smbios_write_type7_cache_parameters(¤t, &handle, &max_struct_size, type4); + update_max(len, max_struct_size, smbios_write_type11(¤t, &handle)); + if (CONFIG(ELOG)) + update_max(len, max_struct_size, + elog_smbios_write_type15(¤t, handle++)); + + const int type16 = handle; + update_max(len, max_struct_size, smbios_write_type16(¤t, &handle)); + const int type17 = handle; + update_max(len, max_struct_size, smbios_write_type17(¤t, &handle, type16)); + const int type19 = handle; + update_max(len, max_struct_size, smbios_write_type19(¤t, &handle, type16)); + update_max(len, max_struct_size, + smbios_write_type20(¤t, &handle, type17, type19)); + update_max(len, max_struct_size, smbios_write_type32(¤t, handle++)); + + update_max(len, max_struct_size, smbios_walk_device_tree(all_devices, + &handle, ¤t)); + + update_max(len, max_struct_size, smbios_write_type127(¤t, handle++)); + + /* Install SMBIOS 2.1 entry point */ + memset(se, 0, sizeof(*se)); + memcpy(se->anchor, "_SM_", 4); + se->length = sizeof(*se); + se->major_version = 3; + se->minor_version = 0; + se->max_struct_size = max_struct_size; + se->struct_count = handle; + memcpy(se->intermediate_anchor_string, "_DMI_", 5); + + se->struct_table_address = (u32)tables; + se->struct_table_length = len; + + se->intermediate_checksum = smbios_checksum((u8 *)se + 0x10, sizeof(*se) - 0x10); + se->checksum = smbios_checksum((u8 *)se, sizeof(*se)); + + /* Install SMBIOS 3.0 entry point */ + memset(se3, 0, sizeof(*se3)); + memcpy(se3->anchor, "_SM3_", 5); + se3->length = sizeof(*se3); + se3->major_version = 3; + se3->minor_version = 0; + + se3->struct_table_address = (u64)tables; + se3->struct_table_length = len; + + se3->checksum = smbios_checksum((u8 *)se3, sizeof(*se3)); + + return current; +} diff --git a/src/arch/riscv/smbios_defaults.c b/src/arch/riscv/smbios_defaults.c new file mode 100644 index 0000000..8b62ebb --- /dev/null +++ b/src/arch/riscv/smbios_defaults.c @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <memory_info.h> +#include <smbios.h> +#include <stdint.h> +#include <string.h> + +/* this function will fill the corresponding locator */ +__weak void smbios_fill_dimm_locator(const struct dimm_info *dimm, struct smbios_type17 *t) +{ + char locator[40]; + + snprintf(locator, sizeof(locator), "Channel-%d-DIMM-%d", + dimm->channel_num, dimm->dimm_num); + t->device_locator = smbios_add_string(t->eos, locator); + + snprintf(locator, sizeof(locator), "BANK %d", dimm->bank_locator); + t->bank_locator = smbios_add_string(t->eos, locator); +} + +__weak void smbios_fill_dimm_asset_tag(const struct dimm_info *dimm, struct smbios_type17 *t) +{ + char buf[40]; + + snprintf(buf, sizeof(buf), "Channel-%d-DIMM-%d-AssetTag", + dimm->channel_num, dimm->dimm_num); + t->asset_tag = smbios_add_string(t->eos, buf); +} + +__weak smbios_wakeup_type smbios_system_wakeup_type(void) +{ + return SMBIOS_WAKEUP_TYPE_RESERVED; +} + +__weak const char *smbios_mainboard_bios_version(void) +{ + return NULL; +} + +__weak const char *smbios_mainboard_serial_number(void) +{ + return CONFIG_MAINBOARD_SERIAL_NUMBER; +} + +__weak const char *smbios_mainboard_version(void) +{ + return CONFIG_MAINBOARD_VERSION; +} + +__weak const char *smbios_mainboard_manufacturer(void) +{ + return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER; +} + +__weak const char *smbios_mainboard_product_name(void) +{ + return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME; +} + +__weak const char *smbios_mainboard_asset_tag(void) +{ + return ""; +} + +__weak u8 smbios_mainboard_feature_flags(void) +{ + return 0; +} + +__weak const char *smbios_mainboard_location_in_chassis(void) +{ + return ""; +} + +__weak smbios_board_type smbios_mainboard_board_type(void) +{ + return SMBIOS_BOARD_TYPE_MOTHERBOARD; +} + +__weak void smbios_ec_revision(uint8_t *ec_major_revision, uint8_t *ec_minor_revision) +{ + *ec_major_revision = 0x0; + *ec_minor_revision = 0x0; +} + +/* + * System Enclosure or Chassis Types as defined in SMBIOS specification. + * The default value is SMBIOS_ENCLOSURE_DESKTOP (0x03) but laptop, + * convertible, or tablet enclosure will be used if the appropriate + * system type is selected. + */ +__weak smbios_enclosure_type smbios_mainboard_enclosure_type(void) +{ + if (CONFIG(SYSTEM_TYPE_LAPTOP)) + return SMBIOS_ENCLOSURE_LAPTOP; + else if (CONFIG(SYSTEM_TYPE_TABLET)) + return SMBIOS_ENCLOSURE_TABLET; + else if (CONFIG(SYSTEM_TYPE_CONVERTIBLE)) + return SMBIOS_ENCLOSURE_CONVERTIBLE; + else if (CONFIG(SYSTEM_TYPE_DETACHABLE)) + return SMBIOS_ENCLOSURE_DETACHABLE; + else + return SMBIOS_ENCLOSURE_DESKTOP; +} + +__weak const char *smbios_system_serial_number(void) +{ + return smbios_mainboard_serial_number(); +} + +__weak const char *smbios_system_version(void) +{ + return smbios_mainboard_version(); +} + +__weak const char *smbios_system_manufacturer(void) +{ + return smbios_mainboard_manufacturer(); +} + +__weak const char *smbios_system_product_name(void) +{ + return smbios_mainboard_product_name(); +} + +__weak void smbios_system_set_uuid(u8 *uuid) +{ + /* leave all zero */ +} + +__weak unsigned int smbios_cpu_get_max_speed_mhz(void) +{ + return 0; /* Unknown */ +} + +__weak unsigned int smbios_cpu_get_current_speed_mhz(void) +{ + return 0; /* Unknown */ +} + +__weak const char *smbios_system_sku(void) +{ + return ""; +} + +__weak const char *smbios_chassis_version(void) +{ + return ""; +} + +__weak const char *smbios_chassis_serial_number(void) +{ + return ""; +} + +__weak const char *smbios_processor_serial_number(void) +{ + return ""; +} + +__weak u8 smbios_chassis_power_cords(void) +{ + return 1; +} diff --git a/src/arch/riscv/tables.c b/src/arch/riscv/tables.c index 9fc75f4..2fbebf0 100644 --- a/src/arch/riscv/tables.c +++ b/src/arch/riscv/tables.c @@ -4,9 +4,129 @@ #include <boot/tables.h> #include <boot/coreboot_tables.h> #include <symbols.h> +#include <cbmem.h> +#include <mcall.h> +#include <acpi/acpi.h> +#include <console/console.h> +#include <device_tree.h> +#include <endian.h> +#include <stdint.h> +#include <string.h> +#include <stddef.h> +#include <stdlib.h> +#include <smbios.h> + + +#define MAX_SMBIOS_SIZE (10 * KiB) + +#if CONFIG(FLATTENED_DEVICE_TREE) + +static unsigned long write_smbios_table(void) +{ +#if CONFIG(GENERATE_SMBIOS_TABLES) + unsigned long high_table_pointer, new_high_table_pointer; + + + high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_SMBIOS, + MAX_SMBIOS_SIZE); + high_table_pointer = ALIGN_UP(high_table_pointer, 16); + if (high_table_pointer) { + memset((void *)high_table_pointer, 0, MAX_SMBIOS_SIZE); + new_high_table_pointer = + smbios_write_tables(high_table_pointer); + + if (new_high_table_pointer > (high_table_pointer + + MAX_SMBIOS_SIZE)) + printk(BIOS_ERR, "ERROR: Increase SMBIOS size\n"); + printk(BIOS_DEBUG, "SMBIOS tables: %ld bytes.\n", + new_high_table_pointer - high_table_pointer); + } + + return high_table_pointer; +#else + return 0; +#endif +} + + +static unsigned long write_acpi_table(void) +{ +#if CONFIG(HAVE_ACPI_TABLES) + unsigned long high_table_pointer, new_high_table_pointer; + const size_t max_acpi_size = CONFIG_MAX_ACPI_TABLE_SIZE_KB * KiB; + + high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_ACPI, + max_acpi_size); + high_table_pointer = ALIGN_UP(high_table_pointer, 16); + printk(BIOS_INFO, "high_table_pointer: 0x%lx bytes.\n", high_table_pointer); + if (high_table_pointer) { + + memset((void *)high_table_pointer, 0, max_acpi_size); + //rom_table_end = ALIGN_UP(rom_table_end, 16); + new_high_table_pointer = write_acpi_tables(high_table_pointer); + if (new_high_table_pointer > (high_table_pointer + + max_acpi_size)) + printk(BIOS_ERR, "ERROR: Increase ACPI size\n"); + printk(BIOS_DEBUG, "ACPI tables: %ld bytes.\n", + new_high_table_pointer - high_table_pointer); + + } + + return high_table_pointer; +#else + return 0; +#endif +} + +#endif
void arch_write_tables(uintptr_t coreboot_table) { +#if CONFIG(FLATTENED_DEVICE_TREE) + void *fdt = HLS()->fdt; + struct device_tree *tree; + const char * config_path[] = { "cfgtables" }; + struct device_tree_node *node; + void *dt; + #if CONFIG(GENERATE_SMBIOS_TABLES) + unsigned long smbios_entry; + #endif + #if CONFIG(HAVE_ACPI_TABLES) + unsigned long acpi_rsdp; + #endif + + acpi_rsdp = write_acpi_table(); + smbios_entry = write_smbios_table(); + + if (acpi_rsdp || smbios_entry) { + tree = fdt_unflatten(fdt); + node = dt_find_node(tree->root, config_path, NULL, NULL, 1); + + if (acpi_rsdp) + dt_add_u64_prop(node, "acpi_phy_ptr", acpi_rsdp); + + if (smbios_entry) { + dt_add_u64_prop(node, "smbios_phy_ptr", smbios_entry); + + smbios_entry += sizeof(struct smbios_entry); + smbios_entry = ALIGN_UP(smbios_entry, 16); + dt_add_u64_prop(node, "smbios3_phy_ptr", smbios_entry); + } + + /* convert the tree to a flat dt */ + dt = cbmem_add(CBMEM_ID_FDT, dt_flat_size(tree)); + printk(BIOS_INFO, "fdt_phy_ptr: 0x%p.\n", dt); + + if (dt) { + dt_flatten(tree, dt); + + /* update HLS */ + for (int i = 0; i < CONFIG_MAX_CPUS; i++) + OTHER_HLS(i)->fdt = dt; + } + } + +#endif }
void bootmem_arch_add_ranges(void) diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h b/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h index 4162d84..7ad1b88 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h @@ -15,6 +15,7 @@ #define CBMEM_ID_AMDMCT_MEMINFO 0x494D454E #define CBMEM_ID_CAR_GLOBALS 0xcac4e6a3 #define CBMEM_ID_CBTABLE 0x43425442 +#define CBMEM_ID_FDT 0x4c474455 #define CBMEM_ID_CBTABLE_FWD 0x43425443 #define CBMEM_ID_CB_EARLY_DRAM 0x4544524D #define CBMEM_ID_CONSOLE 0x434f4e53 @@ -100,6 +101,7 @@ { CBMEM_ID_AMDMCT_MEMINFO, "AMDMEM INFO" }, \ { CBMEM_ID_CAR_GLOBALS, "CAR GLOBALS" }, \ { CBMEM_ID_CBTABLE, "COREBOOT " }, \ + { CBMEM_ID_FDT, "FDT " }, \ { CBMEM_ID_CBTABLE_FWD, "COREBOOTFWD" }, \ { CBMEM_ID_CB_EARLY_DRAM, "EARLY DRAM USAGE" }, \ { CBMEM_ID_CONSOLE, "CONSOLE " }, \ diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h index 78a6005..e0024f1 100644 --- a/src/include/acpi/acpi.h +++ b/src/include/acpi/acpi.h @@ -76,7 +76,7 @@ BERT, CEDT, DBG2, DMAR, DSDT, EINJ, FACS, FADT, HEST, HMAT, HPET, IVRS, MADT, MCFG, RSDP, RSDT, SLIT, SRAT, SSDT, TCPA, TPM2, XSDT, ECDT, LPIT, /* Additional proprietary tables used by coreboot */ - VFCT, NHLT, SPMI, CRAT + VFCT, NHLT, SPMI, CRAT, PPTT, RTDT };
/* RSDP (Root System Description Pointer) */ @@ -237,6 +237,143 @@ #define ACPI_CEDT_CHBS_CXL_VER_1_1 0x00 #define ACPI_CEDT_CHBS_CXL_VER_2_0 0x01
+//PPTT +struct Acpi128 { + u64 lo; + u64 hi; +} __packed; +typedef struct Acpi128 Acpi128; + +union AcpiImsicHartIndex { + struct { + u32 lhxw : 4; + u32 hhxw : 3; + u32 lhxs : 3; + u32 hhxs : 5; + u32 reserved : 17; + }; + u32 hart_index; +}; +typedef union AcpiImsicHartIndex AcpiImsicHartIndex; + +union AcpiPpttHartCap { + struct { + u64 mmu_type : 4; + u64 aia_enabled : 1; + u64 reserved : 59; + }; + u64 hart_cap; +}; +typedef union AcpiPpttHartCap AcpiPpttHartCap; + +typedef struct acpi_pptt_type0 { + u8 type; + u8 length; + u16 reserved; + u32 flags; + u32 parent; + u32 acpi_processor_id; + u32 num_private_resources; + u32 private_resources[]; +} __packed acpi_pptt_type0_n; + +typedef struct acpi_pptt_type1 { + u8 type; + u8 length; + u16 reserved; + u32 flags; + u32 next_level_cache; + u32 size; + u32 num_sets; + u8 associativity; + u8 attributes; + u16 line_size; +} __packed acpi_pptt_type1_n; + +typedef struct acpi_pptt_type2 { + u8 type; + u8 length; + u16 version; + u32 isa; + u64 cap; +} __packed acpi_pptt_type2_n; + + +struct AcpiImsicSocket { + u64 imsic_addr; + u32 imsic_size; + u32 num_harts; + u8 cpuId[]; +} __packed; + +typedef struct AcpiImsicSocket AcpiImsicSocket; + +struct AcpiMadtImsic { + u8 type; \ + u8 length; + u8 id; + u8 version; + u8 mode; + u8 num_sockets; + u16 total_num_harts; + u16 num_interrupt_id; + u16 ext_irq_num; + u16 ipi_base; + u16 ipi_count; + u32 hart_index; + u32 reserved2; + AcpiImsicSocket socket_imsic[]; +} __packed; + +typedef struct AcpiMadtImsic AcpiMadtImsic; + +struct AcpiAplicImsicInfo { + u64 imsic_addr; + u32 hart_index; + u16 imsic_size; + u16 num_harts; + u8 cpuId[]; +} __packed; +typedef struct AcpiAplicImsicInfo AcpiAplicImsicInfo; + +struct AcpiMadtAplic { + u8 type; \ + u8 length; + u16 global_irq_base; + u16 mode; + u16 id; + u16 num_interrupts; + u16 target_imsic; + u16 reserved; + u16 aplic_size; + u64 aplic_addr; + AcpiAplicImsicInfo imsic_info; +} __packed; +typedef struct AcpiMadtAplic AcpiMadtAplic; + +struct AcpiMadtRintc { + u8 type; \ + u8 length; + u8 version; + u8 aia_csr_enabled; + u32 acpi_proc_id; + struct Acpi128 hartId; +} __packed; +typedef struct AcpiMadtRintc AcpiMadtRintc; + +/* RTDT (RISC-V Timer Description Table) */ +typedef struct acpi_rtdt { + acpi_header_t header; + u16 reserved; + u16 num_mtimer; + u16 num_harts; + u32 reserved1; + u32 size; + u64 base_addr; + u64 time_base_frequency; + struct Acpi128 hartId[]; +} __packed acpi_rtdt_t; + /* CHBS: CXL Host Bridge Structure */ typedef struct acpi_cedt_chbs { u8 type; /* Always 0, other values reserved */ @@ -1319,6 +1456,10 @@
unsigned long acpi_fill_lpit(unsigned long current);
+unsigned long acpi_fill_pptt(unsigned long current); + +unsigned long acpi_fill_rtdt(unsigned long current); + /* These can be used by the target port. */ u8 acpi_checksum(u8 *table, u32 length);
diff --git a/src/soc/ucb/riscv/cbmem.c b/src/soc/ucb/riscv/cbmem.c index 5c423a0..3be7008 100644 --- a/src/soc/ucb/riscv/cbmem.c +++ b/src/soc/ucb/riscv/cbmem.c @@ -6,5 +6,6 @@
uintptr_t cbmem_top_chipset(void) { - return (uintptr_t)_dram + (probe_ramsize((uintptr_t)_dram, CONFIG_DRAM_SIZE_MB) * MiB); + uintptr_t top = (uintptr_t)_dram + (probe_ramsize((uintptr_t)_dram, CONFIG_DRAM_SIZE_MB) * MiB); + return top > 0xffffffffUL ? 0xffffffffUL : top; }