aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/arch/x86/lib
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/arch/x86/lib')
-rw-r--r--roms/u-boot/arch/x86/lib/Makefile102
-rw-r--r--roms/u-boot/arch/x86/lib/acpi.c109
-rw-r--r--roms/u-boot/arch/x86/lib/acpi_nhlt.c491
-rw-r--r--roms/u-boot/arch/x86/lib/acpi_s3.c84
-rw-r--r--roms/u-boot/arch/x86/lib/acpi_table.c900
-rw-r--r--roms/u-boot/arch/x86/lib/acpigen.c96
-rw-r--r--roms/u-boot/arch/x86/lib/asm-offsets.c26
-rw-r--r--roms/u-boot/arch/x86/lib/bios.c357
-rw-r--r--roms/u-boot/arch/x86/lib/bios.h99
-rw-r--r--roms/u-boot/arch/x86/lib/bios_asm.S303
-rw-r--r--roms/u-boot/arch/x86/lib/bios_interrupts.c219
-rw-r--r--roms/u-boot/arch/x86/lib/bootm.c225
-rw-r--r--roms/u-boot/arch/x86/lib/cmd_boot.c50
-rw-r--r--roms/u-boot/arch/x86/lib/coreboot/Makefile7
-rw-r--r--roms/u-boot/arch/x86/lib/coreboot/cb_support.c41
-rw-r--r--roms/u-boot/arch/x86/lib/coreboot/cb_sysinfo.c468
-rw-r--r--roms/u-boot/arch/x86/lib/coreboot_table.c174
-rw-r--r--roms/u-boot/arch/x86/lib/crt0_ia32_efi.S51
-rw-r--r--roms/u-boot/arch/x86/lib/crt0_x86_64_efi.S50
-rw-r--r--roms/u-boot/arch/x86/lib/div64.c112
-rw-r--r--roms/u-boot/arch/x86/lib/e820.c85
-rw-r--r--roms/u-boot/arch/x86/lib/early_cmos.c50
-rw-r--r--roms/u-boot/arch/x86/lib/elf_ia32_efi.lds91
-rw-r--r--roms/u-boot/arch/x86/lib/elf_x86_64_efi.lds80
-rw-r--r--roms/u-boot/arch/x86/lib/fsp/Makefile10
-rw-r--r--roms/u-boot/arch/x86/lib/fsp/fsp_common.c102
-rw-r--r--roms/u-boot/arch/x86/lib/fsp/fsp_dram.c174
-rw-r--r--roms/u-boot/arch/x86/lib/fsp/fsp_graphics.c182
-rw-r--r--roms/u-boot/arch/x86/lib/fsp/fsp_support.c184
-rw-r--r--roms/u-boot/arch/x86/lib/fsp1/Makefile8
-rw-r--r--roms/u-boot/arch/x86/lib/fsp1/fsp_car.S111
-rw-r--r--roms/u-boot/arch/x86/lib/fsp1/fsp_common.c103
-rw-r--r--roms/u-boot/arch/x86/lib/fsp1/fsp_dram.c40
-rw-r--r--roms/u-boot/arch/x86/lib/fsp1/fsp_support.c200
-rw-r--r--roms/u-boot/arch/x86/lib/fsp2/Makefile10
-rw-r--r--roms/u-boot/arch/x86/lib/fsp2/fsp_common.c13
-rw-r--r--roms/u-boot/arch/x86/lib/fsp2/fsp_dram.c94
-rw-r--r--roms/u-boot/arch/x86/lib/fsp2/fsp_init.c193
-rw-r--r--roms/u-boot/arch/x86/lib/fsp2/fsp_meminit.c115
-rw-r--r--roms/u-boot/arch/x86/lib/fsp2/fsp_silicon_init.c60
-rw-r--r--roms/u-boot/arch/x86/lib/fsp2/fsp_support.c143
-rw-r--r--roms/u-boot/arch/x86/lib/hob.c84
-rw-r--r--roms/u-boot/arch/x86/lib/i8254.c67
-rw-r--r--roms/u-boot/arch/x86/lib/i8259.c129
-rw-r--r--roms/u-boot/arch/x86/lib/init_helpers.c39
-rw-r--r--roms/u-boot/arch/x86/lib/interrupts.c158
-rw-r--r--roms/u-boot/arch/x86/lib/lpc-uclass.c16
-rw-r--r--roms/u-boot/arch/x86/lib/mpspec.c410
-rw-r--r--roms/u-boot/arch/x86/lib/mrccache.c357
-rw-r--r--roms/u-boot/arch/x86/lib/northbridge-uclass.c14
-rw-r--r--roms/u-boot/arch/x86/lib/physmem.c205
-rw-r--r--roms/u-boot/arch/x86/lib/pinctrl_ich6.c217
-rw-r--r--roms/u-boot/arch/x86/lib/pirq_routing.c145
-rw-r--r--roms/u-boot/arch/x86/lib/pmu.c117
-rw-r--r--roms/u-boot/arch/x86/lib/ramtest.c78
-rw-r--r--roms/u-boot/arch/x86/lib/reloc_ia32_efi.c69
-rw-r--r--roms/u-boot/arch/x86/lib/reloc_x86_64_efi.c63
-rw-r--r--roms/u-boot/arch/x86/lib/relocate.c175
-rw-r--r--roms/u-boot/arch/x86/lib/scu.c231
-rw-r--r--roms/u-boot/arch/x86/lib/sections.c12
-rw-r--r--roms/u-boot/arch/x86/lib/sfi.c153
-rw-r--r--roms/u-boot/arch/x86/lib/spl.c257
-rw-r--r--roms/u-boot/arch/x86/lib/string.c292
-rw-r--r--roms/u-boot/arch/x86/lib/tables.c155
-rw-r--r--roms/u-boot/arch/x86/lib/tpl.c155
-rw-r--r--roms/u-boot/arch/x86/lib/zimage.c792
66 files changed, 10402 insertions, 0 deletions
diff --git a/roms/u-boot/arch/x86/lib/Makefile b/roms/u-boot/arch/x86/lib/Makefile
new file mode 100644
index 000000000..65d9b3bd6
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/Makefile
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2002-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+ifndef CONFIG_X86_64
+ifndef CONFIG_TPL_BUILD
+obj-y += bios.o
+obj-y += bios_asm.o
+obj-y += bios_interrupts.o
+endif
+obj-y += string.o
+endif
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_CMD_BOOTM) += bootm.o
+endif
+obj-y += cmd_boot.o
+obj-$(CONFIG_$(SPL_)COREBOOT_SYSINFO) += coreboot/
+obj-$(CONFIG_SEABIOS) += coreboot_table.o
+obj-y += early_cmos.o
+obj-y += e820.o
+obj-y += init_helpers.o
+obj-y += interrupts.o
+obj-y += lpc-uclass.o
+obj-y += mpspec.o
+obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi_nhlt.o
+obj-y += northbridge-uclass.o
+obj-$(CONFIG_I8259_PIC) += i8259.o
+obj-$(CONFIG_I8254_TIMER) += i8254.o
+obj-$(CONFIG_PINCTRL_ICH6) += pinctrl_ich6.o
+obj-y += pirq_routing.o
+obj-y += relocate.o
+obj-y += physmem.o
+obj-$(CONFIG_INTEL_MID) += pmu.o
+obj-$(CONFIG_X86_RAMTEST) += ramtest.o
+obj-$(CONFIG_INTEL_MID) += scu.o
+obj-y += sections.o
+obj-y += sfi.o
+obj-y += acpi.o
+obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o
+ifndef CONFIG_QEMU
+obj-y += acpigen.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o
+endif
+obj-y += tables.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_CMD_ZBOOT) += zimage.o
+endif
+obj-$(CONFIG_USE_HOB) += hob.o
+ifndef CONFIG_TPL_BUILD
+obj-$(CONFIG_ENABLE_MRC_CACHE) += mrccache.o
+obj-$(CONFIG_HAVE_FSP) += fsp/
+obj-$(CONFIG_FSP_VERSION1) += fsp1/
+obj-$(CONFIG_FSP_VERSION2) += fsp2/
+endif
+
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_TPL_BUILD
+obj-y += tpl.o
+else
+obj-y += spl.o
+endif
+endif
+
+lib-$(CONFIG_USE_PRIVATE_LIBGCC) += div64.o
+
+ifeq ($(CONFIG_$(SPL_)X86_64),)
+obj-$(CONFIG_EFI_APP) += crt0_ia32_efi.o reloc_ia32_efi.o
+endif
+
+ifneq ($(CONFIG_EFI_STUB),)
+
+CFLAGS_REMOVE_reloc_ia32_efi.o += -mregparm=3
+CFLAGS_reloc_ia32_efi.o += -fpic -fshort-wchar
+
+# When building for 64-bit we must remove the i386-specific flags
+CFLAGS_REMOVE_reloc_x86_64_efi.o += -mregparm=3 -march=i386 -m32
+CFLAGS_reloc_x86_64_efi.o += -fpic -fshort-wchar -m64
+
+AFLAGS_REMOVE_crt0_x86_64_efi.o += -mregparm=3 -march=i386 -m32
+AFLAGS_crt0_x86_64_efi.o += -fpic -fshort-wchar -m64
+
+extra-$(CONFIG_EFI_STUB_32BIT) += crt0_ia32_efi.o reloc_ia32_efi.o
+extra-$(CONFIG_EFI_STUB_64BIT) += crt0_x86_64_efi.o reloc_x86_64_efi.o
+
+endif
+
+ifdef CONFIG_EFI_STUB
+
+ifeq ($(CONFIG_$(SPL_)X86_64),)
+extra-y += $(EFI_CRT0) $(EFI_RELOC)
+endif
+
+else
+
+ifndef CONFIG_SPL_BUILD
+ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),)
+extra-y += $(EFI_CRT0) $(EFI_RELOC)
+endif
+endif
+
+endif
diff --git a/roms/u-boot/arch/x86/lib/acpi.c b/roms/u-boot/arch/x86/lib/acpi.c
new file mode 100644
index 000000000..155fffabf
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/acpi.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <acpi/acpi_table.h>
+#include <asm/io.h>
+#include <asm/tables.h>
+
+static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp)
+{
+ if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
+ return NULL;
+
+ debug("Looking on %p for valid checksum\n", rsdp);
+
+ if (table_compute_checksum((void *)rsdp, 20) != 0)
+ return NULL;
+ debug("acpi rsdp checksum 1 passed\n");
+
+ if ((rsdp->revision > 1) &&
+ (table_compute_checksum((void *)rsdp, rsdp->length) != 0))
+ return NULL;
+ debug("acpi rsdp checksum 2 passed\n");
+
+ return rsdp;
+}
+
+struct acpi_fadt *acpi_find_fadt(void)
+{
+ char *p, *end;
+ struct acpi_rsdp *rsdp = NULL;
+ struct acpi_rsdt *rsdt;
+ struct acpi_fadt *fadt = NULL;
+ int i;
+
+ /* Find RSDP */
+ for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) {
+ rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p);
+ if (rsdp)
+ break;
+ }
+
+ if (!rsdp)
+ return NULL;
+
+ debug("RSDP found at %p\n", rsdp);
+ rsdt = (struct acpi_rsdt *)(uintptr_t)rsdp->rsdt_address;
+
+ end = (char *)rsdt + rsdt->header.length;
+ debug("RSDT found at %p ends at %p\n", rsdt, end);
+
+ for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) {
+ fadt = (struct acpi_fadt *)(uintptr_t)rsdt->entry[i];
+ if (strncmp((char *)fadt, "FACP", 4) == 0)
+ break;
+ fadt = NULL;
+ }
+
+ if (!fadt)
+ return NULL;
+
+ debug("FADT found at %p\n", fadt);
+ return fadt;
+}
+
+void *acpi_find_wakeup_vector(struct acpi_fadt *fadt)
+{
+ struct acpi_facs *facs;
+ void *wake_vec;
+
+ debug("Trying to find the wakeup vector...\n");
+
+ facs = (struct acpi_facs *)(uintptr_t)fadt->firmware_ctrl;
+
+ if (!facs) {
+ debug("No FACS found, wake up from S3 not possible.\n");
+ return NULL;
+ }
+
+ debug("FACS found at %p\n", facs);
+ wake_vec = (void *)(uintptr_t)facs->firmware_waking_vector;
+ debug("OS waking vector is %p\n", wake_vec);
+
+ return wake_vec;
+}
+
+void enter_acpi_mode(int pm1_cnt)
+{
+ u16 val = inw(pm1_cnt);
+
+ /*
+ * PM1_CNT register bit0 selects the power management event to be
+ * either an SCI or SMI interrupt. When this bit is set, then power
+ * management events will generate an SCI interrupt. When this bit
+ * is reset power management events will generate an SMI interrupt.
+ *
+ * Per ACPI spec, it is the responsibility of the hardware to set
+ * or reset this bit. OSPM always preserves this bit position.
+ *
+ * U-Boot does not support SMI. And we don't have plan to support
+ * anything running in SMM within U-Boot. To create a legacy-free
+ * system, and expose ourselves to OSPM as working under ACPI mode
+ * already, turn this bit on.
+ */
+ outw(val | PM1_CNT_SCI_EN, pm1_cnt);
+}
diff --git a/roms/u-boot/arch/x86/lib/acpi_nhlt.c b/roms/u-boot/arch/x86/lib/acpi_nhlt.c
new file mode 100644
index 000000000..6c8cd83e1
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/acpi_nhlt.c
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Modified from coreboot nhlt.c
+ */
+
+#define LOG_CATEGORY LOGC_ACPI
+
+#include <common.h>
+#include <binman.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <tables_csum.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpi_nhlt.h>
+#include <asm/unaligned.h>
+#include <dm/acpi.h>
+
+#define NHLT_RID 1
+#define NHLT_SSID 1
+#define WAVEFORMAT_TAG 0xfffe
+#define DEFAULT_VIRTUAL_BUS_ID 0
+
+static const struct sub_format pcm_subformat = {
+ .data1 = 0x00000001,
+ .data2 = 0x0000,
+ .data3 = 0x0010,
+ .data4 = { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 },
+};
+
+struct nhlt *nhlt_init(void)
+{
+ struct nhlt *nhlt;
+
+ nhlt = malloc(sizeof(*nhlt));
+
+ if (!nhlt)
+ return NULL;
+
+ memset(nhlt, 0, sizeof(*nhlt));
+ nhlt->subsystem_id = NHLT_SSID;
+
+ return nhlt;
+}
+
+struct nhlt_endpoint *nhlt_add_endpoint(struct nhlt *nhlt, int link_type,
+ int device_type, int dir,
+ u16 vid, u16 did)
+{
+ struct nhlt_endpoint *endp;
+
+ if (link_type < NHLT_LINK_HDA || link_type >= NHLT_MAX_LINK_TYPES)
+ return NULL;
+
+ if (nhlt->num_endpoints >= MAX_ENDPOINTS)
+ return NULL;
+
+ endp = &nhlt->endpoints[nhlt->num_endpoints];
+
+ endp->link_type = link_type;
+ endp->instance_id = nhlt->current_instance_id[link_type];
+ endp->vendor_id = vid;
+ endp->device_id = did;
+ endp->revision_id = NHLT_RID;
+ endp->subsystem_id = nhlt->subsystem_id;
+ endp->device_type = device_type;
+ endp->direction = dir;
+ endp->virtual_bus_id = DEFAULT_VIRTUAL_BUS_ID;
+ endp->num_formats = 0;
+
+ nhlt->num_endpoints++;
+
+ return endp;
+}
+
+static int append_specific_config(struct nhlt_specific_config *spec_cfg,
+ const void *config, size_t config_sz)
+{
+ size_t new_sz;
+ void *new_cfg;
+
+ new_sz = spec_cfg->size + config_sz;
+ new_cfg = malloc(new_sz);
+ if (!new_cfg)
+ return -ENOMEM;
+
+ /* Append new config */
+ memcpy(new_cfg, spec_cfg->capabilities, spec_cfg->size);
+ memcpy(new_cfg + spec_cfg->size, config, config_sz);
+
+ free(spec_cfg->capabilities);
+
+ /* Update with new config data */
+ spec_cfg->size = new_sz;
+ spec_cfg->capabilities = new_cfg;
+
+ return 0;
+}
+
+int nhlt_endpoint_append_config(struct nhlt_endpoint *endp, const void *config,
+ size_t config_sz)
+{
+ return append_specific_config(&endp->config, config, config_sz);
+}
+
+struct nhlt_format *nhlt_add_format(struct nhlt_endpoint *endp,
+ int num_channels, int sample_freq_khz,
+ int container_bits_per_sample,
+ int valid_bits_per_sample,
+ uint32_t speaker_mask)
+{
+ struct nhlt_format *fmt;
+ struct nhlt_waveform *wave;
+
+ if (endp->num_formats >= MAX_FORMATS)
+ return NULL;
+
+ fmt = &endp->formats[endp->num_formats];
+ wave = &fmt->waveform;
+
+ wave->tag = WAVEFORMAT_TAG;
+ wave->num_channels = num_channels;
+ wave->samples_per_second = sample_freq_khz * 1000;
+ wave->bits_per_sample = container_bits_per_sample;
+ wave->extra_size = sizeof(wave->valid_bits_per_sample);
+ wave->extra_size += sizeof(wave->channel_mask);
+ wave->extra_size += sizeof(wave->sub_format);
+ wave->valid_bits_per_sample = valid_bits_per_sample;
+ wave->channel_mask = speaker_mask;
+ memcpy(&wave->sub_format, &pcm_subformat, sizeof(wave->sub_format));
+
+ /* Calculate the dervied fields */
+ wave->block_align = wave->num_channels * wave->bits_per_sample / 8;
+ wave->bytes_per_second = wave->block_align * wave->samples_per_second;
+
+ endp->num_formats++;
+
+ return fmt;
+}
+
+int nhlt_format_append_config(struct nhlt_format *fmt, const void *config,
+ size_t config_sz)
+{
+ return append_specific_config(&fmt->config, config, config_sz);
+}
+
+int nhlt_endpoint_add_formats(struct nhlt_endpoint *endp,
+ const struct nhlt_format_config *formats,
+ size_t num_formats)
+{
+ ofnode node;
+ size_t i;
+
+ node = binman_section_find_node("private-files");
+
+ for (i = 0; i < num_formats; i++) {
+ const struct nhlt_format_config *cfg = &formats[i];
+ struct nhlt_format *fmt;
+ void *data;
+ int size;
+ int ret;
+
+ fmt = nhlt_add_format(endp, cfg->num_channels,
+ cfg->sample_freq_khz,
+ cfg->container_bits_per_sample,
+ cfg->valid_bits_per_sample,
+ cfg->speaker_mask);
+ if (!fmt)
+ return -ENOSPC;
+
+ if (!cfg->settings_file)
+ continue;
+
+ ret = binman_entry_map(node, cfg->settings_file, &data, &size);
+ if (ret) {
+ log_warning("Failed to find settings file %s\n",
+ cfg->settings_file);
+ return log_msg_ret("settings", ret);
+ }
+
+ ret = nhlt_format_append_config(fmt, data, size);
+ if (ret)
+ return log_msg_ret("append", ret);
+ }
+
+ return 0;
+}
+
+void nhlt_next_instance(struct nhlt *nhlt, int link_type)
+{
+ if (link_type < NHLT_LINK_HDA || link_type >= NHLT_MAX_LINK_TYPES)
+ return;
+
+ nhlt->current_instance_id[link_type]++;
+}
+
+static size_t calc_specific_config_size(struct nhlt_specific_config *cfg)
+{
+ return sizeof(cfg->size) + cfg->size;
+}
+
+static size_t calc_format_size(struct nhlt_format *fmt)
+{
+ size_t sz = 0;
+
+ /* Wave format first */
+ sz += sizeof(fmt->waveform.tag);
+ sz += sizeof(fmt->waveform.num_channels);
+ sz += sizeof(fmt->waveform.samples_per_second);
+ sz += sizeof(fmt->waveform.bytes_per_second);
+ sz += sizeof(fmt->waveform.block_align);
+ sz += sizeof(fmt->waveform.bits_per_sample);
+ sz += sizeof(fmt->waveform.extra_size);
+ sz += sizeof(fmt->waveform.valid_bits_per_sample);
+ sz += sizeof(fmt->waveform.channel_mask);
+ sz += sizeof(fmt->waveform.sub_format);
+
+ sz += calc_specific_config_size(&fmt->config);
+
+ return sz;
+}
+
+static size_t calc_endpoint_size(struct nhlt_endpoint *endp)
+{
+ int i;
+ size_t sz = 0;
+
+ sz += sizeof(endp->length) + sizeof(endp->link_type);
+ sz += sizeof(endp->instance_id) + sizeof(endp->vendor_id);
+ sz += sizeof(endp->device_id) + sizeof(endp->revision_id);
+ sz += sizeof(endp->subsystem_id) + sizeof(endp->device_type);
+ sz += sizeof(endp->direction) + sizeof(endp->virtual_bus_id);
+ sz += calc_specific_config_size(&endp->config);
+ sz += sizeof(endp->num_formats);
+
+ for (i = 0; i < endp->num_formats; i++)
+ sz += calc_format_size(&endp->formats[i]);
+
+ /* Adjust endpoint length to reflect current configuration */
+ endp->length = sz;
+
+ return sz;
+}
+
+static size_t calc_endpoints_size(struct nhlt *nhlt)
+{
+ size_t sz = 0;
+ int i;
+
+ for (i = 0; i < nhlt->num_endpoints; i++)
+ sz += calc_endpoint_size(&nhlt->endpoints[i]);
+
+ return sz;
+}
+
+static size_t calc_size(struct nhlt *nhlt)
+{
+ return sizeof(nhlt->num_endpoints) + calc_endpoints_size(nhlt);
+}
+
+size_t nhlt_current_size(struct nhlt *nhlt)
+{
+ return calc_size(nhlt) + sizeof(struct acpi_table_header);
+}
+
+static void nhlt_free_resources(struct nhlt *nhlt)
+{
+ int i, j;
+
+ /* Free all specific configs */
+ for (i = 0; i < nhlt->num_endpoints; i++) {
+ struct nhlt_endpoint *endp = &nhlt->endpoints[i];
+
+ free(endp->config.capabilities);
+ for (j = 0; j < endp->num_formats; j++) {
+ struct nhlt_format *fmt = &endp->formats[j];
+
+ free(fmt->config.capabilities);
+ }
+ }
+
+ /* Free nhlt object proper */
+ free(nhlt);
+}
+
+struct cursor {
+ u8 *start;
+ u8 *buf;
+};
+
+static void ser8(struct cursor *cur, uint val)
+{
+ *cur->buf = val;
+ cur->buf += sizeof(u8);
+}
+
+static void ser16(struct cursor *cur, uint val)
+{
+ put_unaligned_le16(val, cur->buf);
+ cur->buf += sizeof(u16);
+}
+
+static void ser32(struct cursor *cur, uint val)
+{
+ put_unaligned_le32(val, cur->buf);
+ cur->buf += sizeof(u32);
+}
+
+static void serblob(struct cursor *cur, void *from, size_t sz)
+{
+ memcpy(cur->buf, from, sz);
+ cur->buf += sz;
+}
+
+static void serialise_specific_config(struct nhlt_specific_config *cfg,
+ struct cursor *cur)
+{
+ log_debug("%zx\n", cur->buf - cur->start);
+ ser32(cur, cfg->size);
+ serblob(cur, cfg->capabilities, cfg->size);
+}
+
+static void serialise_waveform(struct nhlt_waveform *wave, struct cursor *cur)
+{
+ log_debug("%zx\n", cur->buf - cur->start);
+ ser16(cur, wave->tag);
+ ser16(cur, wave->num_channels);
+ ser32(cur, wave->samples_per_second);
+ ser32(cur, wave->bytes_per_second);
+ ser16(cur, wave->block_align);
+ ser16(cur, wave->bits_per_sample);
+ ser16(cur, wave->extra_size);
+ ser16(cur, wave->valid_bits_per_sample);
+ ser32(cur, wave->channel_mask);
+ ser32(cur, wave->sub_format.data1);
+ ser16(cur, wave->sub_format.data2);
+ ser16(cur, wave->sub_format.data3);
+ serblob(cur, wave->sub_format.data4, sizeof(wave->sub_format.data4));
+}
+
+static void serialise_format(struct nhlt_format *fmt, struct cursor *cur)
+{
+ log_debug("%zx\n", cur->buf - cur->start);
+ serialise_waveform(&fmt->waveform, cur);
+ serialise_specific_config(&fmt->config, cur);
+}
+
+static void serialise_endpoint(struct nhlt_endpoint *endp, struct cursor *cur)
+{
+ int i;
+
+ log_debug("%zx\n", cur->buf - cur->start);
+ ser32(cur, endp->length);
+ ser8(cur, endp->link_type);
+ ser8(cur, endp->instance_id);
+ ser16(cur, endp->vendor_id);
+ ser16(cur, endp->device_id);
+ ser16(cur, endp->revision_id);
+ ser32(cur, endp->subsystem_id);
+ ser8(cur, endp->device_type);
+ ser8(cur, endp->direction);
+ ser8(cur, endp->virtual_bus_id);
+ serialise_specific_config(&endp->config, cur);
+ ser8(cur, endp->num_formats);
+
+ for (i = 0; i < endp->num_formats; i++)
+ serialise_format(&endp->formats[i], cur);
+}
+
+static void nhlt_serialise_endpoints(struct nhlt *nhlt, struct cursor *cur)
+{
+ int i;
+
+ ser8(cur, nhlt->num_endpoints);
+
+ for (i = 0; i < nhlt->num_endpoints; i++)
+ serialise_endpoint(&nhlt->endpoints[i], cur);
+}
+
+int nhlt_serialise_oem_overrides(struct acpi_ctx *ctx, struct nhlt *nhlt,
+ const char *oem_id, const char *oem_table_id,
+ uint32_t oem_revision)
+{
+ struct cursor cur;
+ struct acpi_table_header *header;
+ size_t sz;
+ size_t oem_id_len;
+ size_t oem_table_id_len;
+ int ret;
+
+ log_debug("ACPI: * NHLT\n");
+ sz = nhlt_current_size(nhlt);
+
+ /* Create header */
+ header = (void *)ctx->current;
+ memset(header, '\0', sizeof(struct acpi_table_header));
+ memcpy(header->signature, "NHLT", 4);
+ header->length = sz;
+ header->revision = acpi_get_table_revision(ACPITAB_NHLT);
+
+ if (oem_id) {
+ oem_id_len = min((int)strlen(oem_id), 6);
+ memcpy(header->oem_id, oem_id, oem_id_len);
+ }
+ if (oem_table_id) {
+ oem_table_id_len = min((int)strlen(oem_table_id), 8);
+ memcpy(header->oem_table_id, oem_table_id, oem_table_id_len);
+ }
+ header->oem_revision = oem_revision;
+ memcpy(header->aslc_id, ASLC_ID, 4);
+
+ cur.buf = (void *)(header + 1);
+ cur.start = (void *)header;
+ nhlt_serialise_endpoints(nhlt, &cur);
+
+ header->checksum = table_compute_checksum(header, sz);
+ nhlt_free_resources(nhlt);
+ assert(cur.buf - cur.start == sz);
+
+ ret = acpi_add_table(ctx, ctx->current);
+ if (ret)
+ return log_msg_ret("add", ret);
+ acpi_inc_align(ctx, sz);
+
+ return 0;
+}
+
+static int _nhlt_add_single_endpoint(struct nhlt *nhlt, int virtual_bus_id,
+ const struct nhlt_endp_descriptor *epd)
+{
+ struct nhlt_endpoint *endp;
+ int ret;
+
+ endp = nhlt_add_endpoint(nhlt, epd->link, epd->device, epd->direction,
+ epd->vid, epd->did);
+ if (!endp)
+ return -EINVAL;
+
+ endp->virtual_bus_id = virtual_bus_id;
+
+ ret = nhlt_endpoint_append_config(endp, epd->cfg, epd->cfg_size);
+ if (ret)
+ return ret;
+
+ ret = nhlt_endpoint_add_formats(endp, epd->formats, epd->num_formats);
+ if (ret)
+ return log_msg_ret("formats", ret);
+
+ return 0;
+}
+
+static int _nhlt_add_endpoints(struct nhlt *nhlt, int virtual_bus_id,
+ const struct nhlt_endp_descriptor *epds,
+ size_t num_epds)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < num_epds; i++) {
+ ret = _nhlt_add_single_endpoint(nhlt, virtual_bus_id, &epds[i]);
+ if (ret)
+ return log_ret(ret);
+ }
+
+ return 0;
+}
+
+int nhlt_add_endpoints(struct nhlt *nhlt,
+ const struct nhlt_endp_descriptor *epds, size_t num_epds)
+{
+ int ret;
+
+ ret = _nhlt_add_endpoints(nhlt, DEFAULT_VIRTUAL_BUS_ID, epds, num_epds);
+
+ return ret;
+}
+
+int nhlt_add_ssp_endpoints(struct nhlt *nhlt, int virtual_bus_id,
+ const struct nhlt_endp_descriptor *epds,
+ size_t num_epds)
+{
+ int ret;
+
+ ret = _nhlt_add_endpoints(nhlt, virtual_bus_id, epds, num_epds);
+ if (!ret)
+ nhlt_next_instance(nhlt, NHLT_LINK_SSP);
+
+ return ret;
+}
diff --git a/roms/u-boot/arch/x86/lib/acpi_s3.c b/roms/u-boot/arch/x86/lib/acpi_s3.c
new file mode 100644
index 000000000..2c70acbe7
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/acpi_s3.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <acpi/acpi_s3.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpi.h>
+#include <asm/global_data.h>
+#include <asm/post.h>
+#include <linux/linkage.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE;
+
+static void acpi_jump_to_wakeup(void *vector)
+{
+ /* Copy wakeup trampoline in place */
+ memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size);
+
+ printf("Jumping to OS waking vector %p\n", vector);
+ acpi_do_wakeup(vector);
+}
+
+void acpi_resume(struct acpi_fadt *fadt)
+{
+ void *wake_vec;
+
+ /* Turn on ACPI mode for S3 */
+ enter_acpi_mode(fadt->pm1a_cnt_blk);
+
+ wake_vec = acpi_find_wakeup_vector(fadt);
+
+ /*
+ * Restore the memory content starting from address 0x1000 which is
+ * used for the real mode interrupt handler stubs.
+ */
+ memcpy((void *)0x1000, (const void *)gd->arch.backup_mem,
+ S3_RESERVE_SIZE);
+
+ post_code(POST_OS_RESUME);
+ acpi_jump_to_wakeup(wake_vec);
+}
+
+int acpi_s3_reserve(void)
+{
+ /* adjust stack pointer for ACPI S3 resume backup memory */
+ gd->start_addr_sp -= S3_RESERVE_SIZE;
+ gd->arch.backup_mem = gd->start_addr_sp;
+
+ gd->start_addr_sp &= ~0xf;
+
+ /*
+ * U-Boot sets up the real mode interrupt handler stubs starting from
+ * address 0x1000. In most cases, the first 640K (0x00000 - 0x9ffff)
+ * system memory is reported as system RAM in E820 table to the OS.
+ * (see install_e820_map() implementation for each platform). So OS
+ * can use these memories whatever it wants.
+ *
+ * If U-Boot is in an S3 resume path, care must be taken not to corrupt
+ * these memorie otherwise OS data gets lost. Testing shows that, on
+ * Microsoft Windows 10 on Intel Baytrail its wake up vector happens to
+ * be installed at the same address 0x1000. While on Linux its wake up
+ * vector does not overlap this memory range, but after resume kernel
+ * checks low memory range per config option CONFIG_X86_RESERVE_LOW
+ * which is 64K by default to see whether a memory corruption occurs
+ * during the suspend/resume (it's harmless, but warnings are shown
+ * in the kernel dmesg logs).
+ *
+ * We cannot simply mark the these memory as reserved in E820 table
+ * because such configuration makes GRUB complain: unable to allocate
+ * real mode page. Hence we choose to back up these memories to the
+ * place where we reserved on our stack for our S3 resume work.
+ * Before jumping to OS wake up vector, we need restore the original
+ * content there (see acpi_resume() above).
+ */
+ if (gd->arch.prev_sleep_state == ACPI_S3)
+ memcpy((void *)gd->arch.backup_mem, (const void *)0x1000,
+ S3_RESERVE_SIZE);
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/acpi_table.c b/roms/u-boot/arch/x86/lib/acpi_table.c
new file mode 100644
index 000000000..5ec31301d
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/acpi_table.c
@@ -0,0 +1,900 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Based on acpi.c from coreboot
+ *
+ * Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com>
+ * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#define LOG_CATEGORY LOGC_ACPI
+
+#include <common.h>
+#include <bloblist.h>
+#include <cpu.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/uclass-internal.h>
+#include <mapmem.h>
+#include <serial.h>
+#include <version.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpi/global_nvs.h>
+#include <asm/ioapic.h>
+#include <asm/global_data.h>
+#include <asm/lapic.h>
+#include <asm/mpspec.h>
+#include <asm/tables.h>
+#include <asm/arch/global_nvs.h>
+#include <dm/acpi.h>
+#include <linux/err.h>
+
+/*
+ * IASL compiles the dsdt entries and writes the hex values
+ * to a C array AmlCode[] (see dsdt.c).
+ */
+extern const unsigned char AmlCode[];
+
+/* ACPI RSDP address to be used in boot parameters */
+static ulong acpi_rsdp_addr;
+
+static void acpi_create_facs(struct acpi_facs *facs)
+{
+ memset((void *)facs, 0, sizeof(struct acpi_facs));
+
+ memcpy(facs->signature, "FACS", 4);
+ facs->length = sizeof(struct acpi_facs);
+ facs->hardware_signature = 0;
+ facs->firmware_waking_vector = 0;
+ facs->global_lock = 0;
+ facs->flags = 0;
+ facs->x_firmware_waking_vector_l = 0;
+ facs->x_firmware_waking_vector_h = 0;
+ facs->version = 1;
+}
+
+static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic,
+ u8 cpu, u8 apic)
+{
+ lapic->type = ACPI_APIC_LAPIC;
+ lapic->length = sizeof(struct acpi_madt_lapic);
+ lapic->flags = LOCAL_APIC_FLAG_ENABLED;
+ lapic->processor_id = cpu;
+ lapic->apic_id = apic;
+
+ return lapic->length;
+}
+
+int acpi_create_madt_lapics(u32 current)
+{
+ struct udevice *dev;
+ int total_length = 0;
+ int cpu_num = 0;
+
+ for (uclass_find_first_device(UCLASS_CPU, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+ int length;
+
+ length = acpi_create_madt_lapic(
+ (struct acpi_madt_lapic *)current, cpu_num++,
+ plat->cpu_id);
+ current += length;
+ total_length += length;
+ }
+
+ return total_length;
+}
+
+int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id,
+ u32 addr, u32 gsi_base)
+{
+ ioapic->type = ACPI_APIC_IOAPIC;
+ ioapic->length = sizeof(struct acpi_madt_ioapic);
+ ioapic->reserved = 0x00;
+ ioapic->gsi_base = gsi_base;
+ ioapic->ioapic_id = id;
+ ioapic->ioapic_addr = addr;
+
+ return ioapic->length;
+}
+
+int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
+ u8 bus, u8 source, u32 gsirq, u16 flags)
+{
+ irqoverride->type = ACPI_APIC_IRQ_SRC_OVERRIDE;
+ irqoverride->length = sizeof(struct acpi_madt_irqoverride);
+ irqoverride->bus = bus;
+ irqoverride->source = source;
+ irqoverride->gsirq = gsirq;
+ irqoverride->flags = flags;
+
+ return irqoverride->length;
+}
+
+int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
+ u8 cpu, u16 flags, u8 lint)
+{
+ lapic_nmi->type = ACPI_APIC_LAPIC_NMI;
+ lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi);
+ lapic_nmi->flags = flags;
+ lapic_nmi->processor_id = cpu;
+ lapic_nmi->lint = lint;
+
+ return lapic_nmi->length;
+}
+
+static int acpi_create_madt_irq_overrides(u32 current)
+{
+ struct acpi_madt_irqoverride *irqovr;
+ u16 sci_flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_HIGH;
+ int length = 0;
+
+ irqovr = (void *)current;
+ length += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
+
+ irqovr = (void *)(current + length);
+ length += acpi_create_madt_irqoverride(irqovr, 0, 9, 9, sci_flags);
+
+ return length;
+}
+
+__weak u32 acpi_fill_madt(u32 current)
+{
+ current += acpi_create_madt_lapics(current);
+
+ current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current,
+ io_apic_read(IO_APIC_ID) >> 24, IO_APIC_ADDR, 0);
+
+ current += acpi_create_madt_irq_overrides(current);
+
+ return current;
+}
+
+static void acpi_create_madt(struct acpi_madt *madt)
+{
+ struct acpi_table_header *header = &(madt->header);
+ u32 current = (u32)madt + sizeof(struct acpi_madt);
+
+ memset((void *)madt, 0, sizeof(struct acpi_madt));
+
+ /* Fill out header fields */
+ acpi_fill_header(header, "APIC");
+ header->length = sizeof(struct acpi_madt);
+ header->revision = ACPI_MADT_REV_ACPI_3_0;
+
+ madt->lapic_addr = LAPIC_DEFAULT_BASE;
+ madt->flags = ACPI_MADT_PCAT_COMPAT;
+
+ current = acpi_fill_madt(current);
+
+ /* (Re)calculate length and checksum */
+ header->length = current - (u32)madt;
+
+ header->checksum = table_compute_checksum((void *)madt, header->length);
+}
+
+int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base,
+ u16 seg_nr, u8 start, u8 end)
+{
+ memset(mmconfig, 0, sizeof(*mmconfig));
+ mmconfig->base_address_l = base;
+ mmconfig->base_address_h = 0;
+ mmconfig->pci_segment_group_number = seg_nr;
+ mmconfig->start_bus_number = start;
+ mmconfig->end_bus_number = end;
+
+ return sizeof(struct acpi_mcfg_mmconfig);
+}
+
+__weak u32 acpi_fill_mcfg(u32 current)
+{
+ current += acpi_create_mcfg_mmconfig
+ ((struct acpi_mcfg_mmconfig *)current,
+ CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255);
+
+ return current;
+}
+
+/* MCFG is defined in the PCI Firmware Specification 3.0 */
+static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
+{
+ struct acpi_table_header *header = &(mcfg->header);
+ u32 current = (u32)mcfg + sizeof(struct acpi_mcfg);
+
+ memset((void *)mcfg, 0, sizeof(struct acpi_mcfg));
+
+ /* Fill out header fields */
+ acpi_fill_header(header, "MCFG");
+ header->length = sizeof(struct acpi_mcfg);
+ header->revision = 1;
+
+ current = acpi_fill_mcfg(current);
+
+ /* (Re)calculate length and checksum */
+ header->length = current - (u32)mcfg;
+ header->checksum = table_compute_checksum((void *)mcfg, header->length);
+}
+
+/**
+ * acpi_create_tcpa() - Create a TCPA table
+ *
+ * @tcpa: Pointer to place to put table
+ *
+ * Trusted Computing Platform Alliance Capabilities Table
+ * TCPA PC Specific Implementation SpecificationTCPA is defined in the PCI
+ * Firmware Specification 3.0
+ */
+static int acpi_create_tcpa(struct acpi_tcpa *tcpa)
+{
+ struct acpi_table_header *header = &tcpa->header;
+ u32 current = (u32)tcpa + sizeof(struct acpi_tcpa);
+ int size = 0x10000; /* Use this as the default size */
+ void *log;
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(BLOBLIST))
+ return -ENXIO;
+ memset(tcpa, '\0', sizeof(struct acpi_tcpa));
+
+ /* Fill out header fields */
+ acpi_fill_header(header, "TCPA");
+ header->length = sizeof(struct acpi_tcpa);
+ header->revision = 1;
+
+ ret = bloblist_ensure_size_ret(BLOBLISTT_TCPA_LOG, &size, &log);
+ if (ret)
+ return log_msg_ret("blob", ret);
+
+ tcpa->platform_class = 0;
+ tcpa->laml = size;
+ tcpa->lasa = (ulong)log;
+
+ /* (Re)calculate length and checksum */
+ header->length = current - (u32)tcpa;
+ header->checksum = table_compute_checksum((void *)tcpa, header->length);
+
+ return 0;
+}
+
+static int get_tpm2_log(void **ptrp, int *sizep)
+{
+ const int tpm2_default_log_len = 0x10000;
+ int size;
+ int ret;
+
+ *sizep = 0;
+ size = tpm2_default_log_len;
+ ret = bloblist_ensure_size_ret(BLOBLISTT_TPM2_TCG_LOG, &size, ptrp);
+ if (ret)
+ return log_msg_ret("blob", ret);
+ *sizep = size;
+
+ return 0;
+}
+
+static int acpi_create_tpm2(struct acpi_tpm2 *tpm2)
+{
+ struct acpi_table_header *header = &tpm2->header;
+ int tpm2_log_len;
+ void *lasa;
+ int ret;
+
+ memset((void *)tpm2, 0, sizeof(struct acpi_tpm2));
+
+ /*
+ * Some payloads like SeaBIOS depend on log area to use TPM2.
+ * Get the memory size and address of TPM2 log area or initialize it.
+ */
+ ret = get_tpm2_log(&lasa, &tpm2_log_len);
+ if (ret)
+ return ret;
+
+ /* Fill out header fields. */
+ acpi_fill_header(header, "TPM2");
+ memcpy(header->aslc_id, ASLC_ID, 4);
+
+ header->length = sizeof(struct acpi_tpm2);
+ header->revision = acpi_get_table_revision(ACPITAB_TPM2);
+
+ /* Hard to detect for coreboot. Just set it to 0 */
+ tpm2->platform_class = 0;
+
+ /* Must be set to 0 for FIFO-interface support */
+ tpm2->control_area = 0;
+ tpm2->start_method = 6;
+ memset(tpm2->msp, 0, sizeof(tpm2->msp));
+
+ /* Fill the log area size and start address fields. */
+ tpm2->laml = tpm2_log_len;
+ tpm2->lasa = (uintptr_t)lasa;
+
+ /* Calculate checksum. */
+ header->checksum = table_compute_checksum((void *)tpm2, header->length);
+
+ return 0;
+}
+
+__weak u32 acpi_fill_csrt(u32 current)
+{
+ return 0;
+}
+
+static int acpi_create_csrt(struct acpi_csrt *csrt)
+{
+ struct acpi_table_header *header = &(csrt->header);
+ u32 current = (u32)csrt + sizeof(struct acpi_csrt);
+ uint ptr;
+
+ memset((void *)csrt, 0, sizeof(struct acpi_csrt));
+
+ /* Fill out header fields */
+ acpi_fill_header(header, "CSRT");
+ header->length = sizeof(struct acpi_csrt);
+ header->revision = 0;
+
+ ptr = acpi_fill_csrt(current);
+ if (!ptr)
+ return -ENOENT;
+ current = ptr;
+
+ /* (Re)calculate length and checksum */
+ header->length = current - (u32)csrt;
+ header->checksum = table_compute_checksum((void *)csrt, header->length);
+
+ return 0;
+}
+
+static void acpi_create_spcr(struct acpi_spcr *spcr)
+{
+ struct acpi_table_header *header = &(spcr->header);
+ struct serial_device_info serial_info = {0};
+ ulong serial_address, serial_offset;
+ struct udevice *dev;
+ uint serial_config;
+ uint serial_width;
+ int access_size;
+ int space_id;
+ int ret = -ENODEV;
+
+ memset((void *)spcr, 0, sizeof(struct acpi_spcr));
+
+ /* Fill out header fields */
+ acpi_fill_header(header, "SPCR");
+ header->length = sizeof(struct acpi_spcr);
+ header->revision = 2;
+
+ /* Read the device once, here. It is reused below */
+ dev = gd->cur_serial_dev;
+ if (dev)
+ ret = serial_getinfo(dev, &serial_info);
+ if (ret)
+ serial_info.type = SERIAL_CHIP_UNKNOWN;
+
+ /* Encode chip type */
+ switch (serial_info.type) {
+ case SERIAL_CHIP_16550_COMPATIBLE:
+ spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
+ break;
+ case SERIAL_CHIP_UNKNOWN:
+ default:
+ spcr->interface_type = ACPI_DBG2_UNKNOWN;
+ break;
+ }
+
+ /* Encode address space */
+ switch (serial_info.addr_space) {
+ case SERIAL_ADDRESS_SPACE_MEMORY:
+ space_id = ACPI_ADDRESS_SPACE_MEMORY;
+ break;
+ case SERIAL_ADDRESS_SPACE_IO:
+ default:
+ space_id = ACPI_ADDRESS_SPACE_IO;
+ break;
+ }
+
+ serial_width = serial_info.reg_width * 8;
+ serial_offset = serial_info.reg_offset << serial_info.reg_shift;
+ serial_address = serial_info.addr + serial_offset;
+
+ /* Encode register access size */
+ switch (serial_info.reg_shift) {
+ case 0:
+ access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
+ break;
+ case 1:
+ access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
+ break;
+ case 2:
+ access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+ break;
+ case 3:
+ access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
+ break;
+ default:
+ access_size = ACPI_ACCESS_SIZE_UNDEFINED;
+ break;
+ }
+
+ debug("UART type %u @ %lx\n", spcr->interface_type, serial_address);
+
+ /* Fill GAS */
+ spcr->serial_port.space_id = space_id;
+ spcr->serial_port.bit_width = serial_width;
+ spcr->serial_port.bit_offset = 0;
+ spcr->serial_port.access_size = access_size;
+ spcr->serial_port.addrl = lower_32_bits(serial_address);
+ spcr->serial_port.addrh = upper_32_bits(serial_address);
+
+ /* Encode baud rate */
+ switch (serial_info.baudrate) {
+ case 9600:
+ spcr->baud_rate = 3;
+ break;
+ case 19200:
+ spcr->baud_rate = 4;
+ break;
+ case 57600:
+ spcr->baud_rate = 6;
+ break;
+ case 115200:
+ spcr->baud_rate = 7;
+ break;
+ default:
+ spcr->baud_rate = 0;
+ break;
+ }
+
+ serial_config = SERIAL_DEFAULT_CONFIG;
+ if (dev)
+ ret = serial_getconfig(dev, &serial_config);
+
+ spcr->parity = SERIAL_GET_PARITY(serial_config);
+ spcr->stop_bits = SERIAL_GET_STOP(serial_config);
+
+ /* No PCI devices for now */
+ spcr->pci_device_id = 0xffff;
+ spcr->pci_vendor_id = 0xffff;
+
+ /*
+ * SPCR has no clue if the UART base clock speed is different
+ * to the default one. However, the SPCR 1.04 defines baud rate
+ * 0 as a preconfigured state of UART and OS is supposed not
+ * to touch the configuration of the serial device.
+ */
+ if (serial_info.clock != SERIAL_DEFAULT_CLOCK)
+ spcr->baud_rate = 0;
+
+ /* Fix checksum */
+ header->checksum = table_compute_checksum((void *)spcr, header->length);
+}
+
+static int acpi_create_ssdt(struct acpi_ctx *ctx,
+ struct acpi_table_header *ssdt,
+ const char *oem_table_id)
+{
+ memset((void *)ssdt, '\0', sizeof(struct acpi_table_header));
+
+ acpi_fill_header(ssdt, "SSDT");
+ ssdt->revision = acpi_get_table_revision(ACPITAB_SSDT);
+ ssdt->aslc_revision = 1;
+ ssdt->length = sizeof(struct acpi_table_header);
+
+ acpi_inc(ctx, sizeof(struct acpi_table_header));
+
+ acpi_fill_ssdt(ctx);
+
+ /* (Re)calculate length and checksum */
+ ssdt->length = ctx->current - (void *)ssdt;
+ ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length);
+ log_debug("SSDT at %p, length %x\n", ssdt, ssdt->length);
+
+ /* Drop the table if it is empty */
+ if (ssdt->length == sizeof(struct acpi_table_header)) {
+ ctx->current = ssdt;
+ return -ENOENT;
+ }
+ acpi_align(ctx);
+
+ return 0;
+}
+
+/*
+ * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
+ */
+ulong write_acpi_tables(ulong start_addr)
+{
+ const int thl = sizeof(struct acpi_table_header);
+ struct acpi_ctx *ctx;
+ struct acpi_facs *facs;
+ struct acpi_table_header *dsdt;
+ struct acpi_fadt *fadt;
+ struct acpi_table_header *ssdt;
+ struct acpi_mcfg *mcfg;
+ struct acpi_tcpa *tcpa;
+ struct acpi_madt *madt;
+ struct acpi_csrt *csrt;
+ struct acpi_spcr *spcr;
+ void *start;
+ int aml_len;
+ ulong addr;
+ int ret;
+ int i;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (!ctx)
+ return log_msg_ret("mem", -ENOMEM);
+ gd->acpi_ctx = ctx;
+
+ start = map_sysmem(start_addr, 0);
+
+ debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
+
+ acpi_reset_items();
+ acpi_setup_base_tables(ctx, start);
+
+ debug("ACPI: * FACS\n");
+ facs = ctx->current;
+ acpi_inc_align(ctx, sizeof(struct acpi_facs));
+
+ acpi_create_facs(facs);
+
+ debug("ACPI: * DSDT\n");
+ dsdt = ctx->current;
+
+ /* Put the table header first */
+ memcpy(dsdt, &AmlCode, thl);
+ acpi_inc(ctx, thl);
+ log_debug("DSDT starts at %p, hdr ends at %p\n", dsdt, ctx->current);
+
+ /* If the table is not empty, allow devices to inject things */
+ aml_len = dsdt->length - thl;
+ if (aml_len) {
+ void *base = ctx->current;
+
+ acpi_inject_dsdt(ctx);
+ log_debug("Added %x bytes from inject_dsdt, now at %p\n",
+ ctx->current - base, ctx->current);
+ log_debug("Copy AML code size %x to %p\n", aml_len,
+ ctx->current);
+ memcpy(ctx->current, AmlCode + thl, aml_len);
+ acpi_inc(ctx, aml_len);
+ }
+
+ dsdt->length = ctx->current - (void *)dsdt;
+ acpi_align(ctx);
+ log_debug("Updated DSDT length to %x, total %x\n", dsdt->length,
+ ctx->current - (void *)dsdt);
+
+ if (!IS_ENABLED(CONFIG_ACPI_GNVS_EXTERNAL)) {
+ /* Pack GNVS into the ACPI table area */
+ for (i = 0; i < dsdt->length; i++) {
+ u32 *gnvs = (u32 *)((u32)dsdt + i);
+
+ if (*gnvs == ACPI_GNVS_ADDR) {
+ *gnvs = map_to_sysmem(ctx->current);
+ debug("Fix up global NVS in DSDT to %#08x\n",
+ *gnvs);
+ break;
+ }
+ }
+
+ /*
+ * Fill in platform-specific global NVS variables. If this fails
+ * we cannot return the error but this should only happen while
+ * debugging.
+ */
+ addr = acpi_create_gnvs(ctx->current);
+ if (IS_ERR_VALUE(addr))
+ printf("Error: Gailed to create GNVS\n");
+ acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
+ }
+
+ /*
+ * Recalculate the length and update the DSDT checksum since we patched
+ * the GNVS address. Set the checksum to zero since it is part of the
+ * region being checksummed.
+ */
+ dsdt->checksum = 0;
+ dsdt->checksum = table_compute_checksum((void *)dsdt, dsdt->length);
+
+ /*
+ * Fill in platform-specific global NVS variables. If this fails we
+ * cannot return the error but this should only happen while debugging.
+ */
+ addr = acpi_create_gnvs(ctx->current);
+ if (IS_ERR_VALUE(addr))
+ printf("Error: Failed to create GNVS\n");
+
+ acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
+
+ debug("ACPI: * FADT\n");
+ fadt = ctx->current;
+ acpi_inc_align(ctx, sizeof(struct acpi_fadt));
+ acpi_create_fadt(fadt, facs, dsdt);
+ acpi_add_table(ctx, fadt);
+
+ debug("ACPI: * SSDT\n");
+ ssdt = (struct acpi_table_header *)ctx->current;
+ if (!acpi_create_ssdt(ctx, ssdt, OEM_TABLE_ID))
+ acpi_add_table(ctx, ssdt);
+
+ debug("ACPI: * MCFG\n");
+ mcfg = ctx->current;
+ acpi_create_mcfg(mcfg);
+ acpi_inc_align(ctx, mcfg->header.length);
+ acpi_add_table(ctx, mcfg);
+
+ if (IS_ENABLED(CONFIG_TPM_V2)) {
+ struct acpi_tpm2 *tpm2;
+
+ debug("ACPI: * TPM2\n");
+ tpm2 = (struct acpi_tpm2 *)ctx->current;
+ ret = acpi_create_tpm2(tpm2);
+ if (!ret) {
+ acpi_inc_align(ctx, tpm2->header.length);
+ acpi_add_table(ctx, tpm2);
+ } else {
+ log_warning("TPM2 table creation failed\n");
+ }
+ }
+
+ debug("ACPI: * MADT\n");
+ madt = ctx->current;
+ acpi_create_madt(madt);
+ acpi_inc_align(ctx, madt->header.length);
+ acpi_add_table(ctx, madt);
+
+ if (IS_ENABLED(CONFIG_TPM_V1)) {
+ debug("ACPI: * TCPA\n");
+ tcpa = (struct acpi_tcpa *)ctx->current;
+ ret = acpi_create_tcpa(tcpa);
+ if (ret) {
+ log_warning("Failed to create TCPA table (err=%d)\n",
+ ret);
+ } else {
+ acpi_inc_align(ctx, tcpa->header.length);
+ acpi_add_table(ctx, tcpa);
+ }
+ }
+
+ debug("ACPI: * CSRT\n");
+ csrt = ctx->current;
+ if (!acpi_create_csrt(csrt)) {
+ acpi_inc_align(ctx, csrt->header.length);
+ acpi_add_table(ctx, csrt);
+ }
+
+ debug("ACPI: * SPCR\n");
+ spcr = ctx->current;
+ acpi_create_spcr(spcr);
+ acpi_inc_align(ctx, spcr->header.length);
+ acpi_add_table(ctx, spcr);
+
+ acpi_write_dev_tables(ctx);
+
+ addr = map_to_sysmem(ctx->current);
+ debug("current = %lx\n", addr);
+
+ acpi_rsdp_addr = (unsigned long)ctx->rsdp;
+ debug("ACPI: done\n");
+
+ return addr;
+}
+
+ulong acpi_get_rsdp_addr(void)
+{
+ return acpi_rsdp_addr;
+}
+
+/**
+ * acpi_write_hpet() - Write out a HPET table
+ *
+ * Write out the table for High-Precision Event Timers
+ *
+ * @hpet: Place to put HPET table
+ */
+static int acpi_create_hpet(struct acpi_hpet *hpet)
+{
+ struct acpi_table_header *header = &hpet->header;
+ struct acpi_gen_regaddr *addr = &hpet->addr;
+
+ /*
+ * See IA-PC HPET (High Precision Event Timers) Specification v1.0a
+ * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf
+ */
+ memset((void *)hpet, '\0', sizeof(struct acpi_hpet));
+
+ /* Fill out header fields. */
+ acpi_fill_header(header, "HPET");
+
+ header->aslc_revision = ASL_REVISION;
+ header->length = sizeof(struct acpi_hpet);
+ header->revision = acpi_get_table_revision(ACPITAB_HPET);
+
+ /* Fill out HPET address */
+ addr->space_id = 0; /* Memory */
+ addr->bit_width = 64;
+ addr->bit_offset = 0;
+ addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff;
+ addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32;
+
+ hpet->id = *(u32 *)CONFIG_HPET_ADDRESS;
+ hpet->number = 0;
+ hpet->min_tick = 0; /* HPET_MIN_TICKS */
+
+ header->checksum = table_compute_checksum(hpet,
+ sizeof(struct acpi_hpet));
+
+ return 0;
+}
+
+int acpi_write_hpet(struct acpi_ctx *ctx)
+{
+ struct acpi_hpet *hpet;
+ int ret;
+
+ log_debug("ACPI: * HPET\n");
+
+ hpet = ctx->current;
+ acpi_inc_align(ctx, sizeof(struct acpi_hpet));
+ acpi_create_hpet(hpet);
+ ret = acpi_add_table(ctx, hpet);
+ if (ret)
+ return log_msg_ret("add", ret);
+
+ return 0;
+}
+
+int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
+ uint access_size)
+{
+ struct acpi_dbg2_header *dbg2 = ctx->current;
+ char path[ACPI_PATH_MAX];
+ struct acpi_gen_regaddr address;
+ phys_addr_t addr;
+ int ret;
+
+ if (!device_active(dev)) {
+ log_info("Device not enabled\n");
+ return -EACCES;
+ }
+ /*
+ * PCI devices don't remember their resource allocation information in
+ * U-Boot at present. We assume that MMIO is used for the UART and that
+ * the address space is 32 bytes: ns16550 uses 8 registers of up to
+ * 32-bits each. This is only for debugging so it is not a big deal.
+ */
+ addr = dm_pci_read_bar32(dev, 0);
+ log_debug("UART addr %lx\n", (ulong)addr);
+
+ memset(&address, '\0', sizeof(address));
+ address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
+ address.addrl = (uint32_t)addr;
+ address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
+ address.access_size = access_size;
+
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+ acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
+ ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
+
+ acpi_inc_align(ctx, dbg2->header.length);
+ acpi_add_table(ctx, dbg2);
+
+ return 0;
+}
+
+void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs,
+ void *dsdt)
+{
+ struct acpi_table_header *header = &fadt->header;
+
+ memset((void *)fadt, '\0', sizeof(struct acpi_fadt));
+
+ acpi_fill_header(header, "FACP");
+ header->length = sizeof(struct acpi_fadt);
+ header->revision = 4;
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
+ memcpy(header->aslc_id, ASLC_ID, 4);
+ header->aslc_revision = 1;
+
+ fadt->firmware_ctrl = (unsigned long)facs;
+ fadt->dsdt = (unsigned long)dsdt;
+
+ fadt->x_firmware_ctl_l = (unsigned long)facs;
+ fadt->x_firmware_ctl_h = 0;
+ fadt->x_dsdt_l = (unsigned long)dsdt;
+ fadt->x_dsdt_h = 0;
+
+ fadt->preferred_pm_profile = ACPI_PM_MOBILE;
+
+ /* Use ACPI 3.0 revision */
+ fadt->header.revision = 4;
+}
+
+void acpi_create_dmar_drhd(struct acpi_ctx *ctx, uint flags, uint segment,
+ u64 bar)
+{
+ struct dmar_entry *drhd = ctx->current;
+
+ memset(drhd, '\0', sizeof(*drhd));
+ drhd->type = DMAR_DRHD;
+ drhd->length = sizeof(*drhd); /* will be fixed up later */
+ drhd->flags = flags;
+ drhd->segment = segment;
+ drhd->bar = bar;
+ acpi_inc(ctx, drhd->length);
+}
+
+void acpi_create_dmar_rmrr(struct acpi_ctx *ctx, uint segment, u64 bar,
+ u64 limit)
+{
+ struct dmar_rmrr_entry *rmrr = ctx->current;
+
+ memset(rmrr, '\0', sizeof(*rmrr));
+ rmrr->type = DMAR_RMRR;
+ rmrr->length = sizeof(*rmrr); /* will be fixed up later */
+ rmrr->segment = segment;
+ rmrr->bar = bar;
+ rmrr->limit = limit;
+ acpi_inc(ctx, rmrr->length);
+}
+
+void acpi_dmar_drhd_fixup(struct acpi_ctx *ctx, void *base)
+{
+ struct dmar_entry *drhd = base;
+
+ drhd->length = ctx->current - base;
+}
+
+void acpi_dmar_rmrr_fixup(struct acpi_ctx *ctx, void *base)
+{
+ struct dmar_rmrr_entry *rmrr = base;
+
+ rmrr->length = ctx->current - base;
+}
+
+static int acpi_create_dmar_ds(struct acpi_ctx *ctx, enum dev_scope_type type,
+ uint enumeration_id, pci_dev_t bdf)
+{
+ /* we don't support longer paths yet */
+ const size_t dev_scope_length = sizeof(struct dev_scope) + 2;
+ struct dev_scope *ds = ctx->current;
+
+ memset(ds, '\0', dev_scope_length);
+ ds->type = type;
+ ds->length = dev_scope_length;
+ ds->enumeration = enumeration_id;
+ ds->start_bus = PCI_BUS(bdf);
+ ds->path[0].dev = PCI_DEV(bdf);
+ ds->path[0].fn = PCI_FUNC(bdf);
+
+ return ds->length;
+}
+
+int acpi_create_dmar_ds_pci_br(struct acpi_ctx *ctx, pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_PCI_SUB, 0, bdf);
+}
+
+int acpi_create_dmar_ds_pci(struct acpi_ctx *ctx, pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_PCI_ENDPOINT, 0, bdf);
+}
+
+int acpi_create_dmar_ds_ioapic(struct acpi_ctx *ctx, uint enumeration_id,
+ pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_IOAPIC, enumeration_id, bdf);
+}
+
+int acpi_create_dmar_ds_msi_hpet(struct acpi_ctx *ctx, uint enumeration_id,
+ pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_MSI_HPET, enumeration_id, bdf);
+}
diff --git a/roms/u-boot/arch/x86/lib/acpigen.c b/roms/u-boot/arch/x86/lib/acpigen.c
new file mode 100644
index 000000000..ea2ec2a90
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/acpigen.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Google LLC
+ */
+
+#include <common.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpigen.h>
+
+void acpigen_write_empty_pct(struct acpi_ctx *ctx)
+{
+ /*
+ * Name (_PCT, Package (0x02)
+ * {
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00, // Bit Width
+ * 0x00, // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * },
+ *
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00, // Bit Width
+ * 0x00, // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * }
+ * })
+ */
+ static char stream[] = {
+ /* 00000030 "0._PCT.," */
+ 0x08, 0x5f, 0x50, 0x43, 0x54, 0x12, 0x2c,
+ /* 00000038 "........" */
+ 0x02, 0x11, 0x14, 0x0a, 0x11, 0x82, 0x0c, 0x00,
+ /* 00000040 "........" */
+ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000048 "....y..." */
+ 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14,
+ /* 00000050 "........" */
+ 0x0a, 0x11, 0x82, 0x0c, 0x00, 0x7f, 0x00, 0x00,
+ /* 00000058 "........" */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x79, 0x00
+ };
+ acpigen_emit_stream(ctx, stream, ARRAY_SIZE(stream));
+}
+
+void acpigen_write_empty_ptc(struct acpi_ctx *ctx)
+{
+ /*
+ * Name (_PTC, Package (0x02)
+ * {
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00, // Bit Width
+ * 0x00, // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * },
+ *
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00, // Bit Width
+ * 0x00, // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * }
+ * })
+ */
+ struct acpi_gen_regaddr addr = {
+ .space_id = ACPI_ADDRESS_SPACE_FIXED,
+ .bit_width = 0,
+ .bit_offset = 0,
+ .access_size = 0,
+ .addrl = 0,
+ .addrh = 0,
+ };
+
+ acpigen_write_name(ctx, "_PTC");
+ acpigen_write_package(ctx, 2);
+
+ /* ControlRegister */
+ acpigen_write_register_resource(ctx, &addr);
+
+ /* StatusRegister */
+ acpigen_write_register_resource(ctx, &addr);
+
+ acpigen_pop_len(ctx);
+}
diff --git a/roms/u-boot/arch/x86/lib/asm-offsets.c b/roms/u-boot/arch/x86/lib/asm-offsets.c
new file mode 100644
index 000000000..8df67db65
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/asm-offsets.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Adapted from Linux v2.6.36 kernel: arch/powerpc/kernel/asm-offsets.c
+ *
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <common.h>
+#include <asm/global_data.h>
+#include <linux/kbuild.h>
+
+int main(void)
+{
+ DEFINE(GD_BIST, offsetof(gd_t, arch.bist));
+#ifdef CONFIG_USE_HOB
+ DEFINE(GD_HOB_LIST, offsetof(gd_t, arch.hob_list));
+#endif
+ DEFINE(GD_TABLE, offsetof(gd_t, arch.table));
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/bios.c b/roms/u-boot/arch/x86/lib/bios.c
new file mode 100644
index 000000000..fbdc3b04e
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/bios.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * From Coreboot file device/oprom/realmode/x86.c
+ *
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2009-2010 coresystems GmbH
+ */
+#include <common.h>
+#include <compiler.h>
+#include <bios_emul.h>
+#include <irq_func.h>
+#include <log.h>
+#include <vbe.h>
+#include <linux/linkage.h>
+#include <asm/cache.h>
+#include <asm/processor.h>
+#include <asm/i8259.h>
+#include <asm/io.h>
+#include <asm/post.h>
+#include "bios.h"
+
+/* Interrupt handlers for each interrupt the ROM can call */
+static int (*int_handler[256])(void);
+
+/* to have a common register file for interrupt handlers */
+X86EMU_sysEnv _X86EMU_env;
+
+asmlinkage void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx,
+ u32 esi, u32 edi);
+
+asmlinkage void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx,
+ u32 edx, u32 esi, u32 edi);
+
+static void setup_realmode_code(void)
+{
+ memcpy((void *)REALMODE_BASE, &asm_realmode_code,
+ asm_realmode_code_size);
+
+ /* Ensure the global pointers are relocated properly. */
+ realmode_call = PTR_TO_REAL_MODE(asm_realmode_call);
+ realmode_interrupt = PTR_TO_REAL_MODE(__realmode_interrupt);
+
+ debug("Real mode stub @%x: %d bytes\n", REALMODE_BASE,
+ asm_realmode_code_size);
+}
+
+static void setup_rombios(void)
+{
+ const char date[] = "06/11/99";
+ memcpy((void *)0xffff5, &date, 8);
+
+ const char ident[] = "PCI_ISA";
+ memcpy((void *)0xfffd9, &ident, 7);
+
+ /* system model: IBM-AT */
+ writeb(0xfc, 0xffffe);
+}
+
+static int int_exception_handler(void)
+{
+ /* compatibility shim */
+ struct eregs reg_info = {
+ .eax = M.x86.R_EAX,
+ .ecx = M.x86.R_ECX,
+ .edx = M.x86.R_EDX,
+ .ebx = M.x86.R_EBX,
+ .esp = M.x86.R_ESP,
+ .ebp = M.x86.R_EBP,
+ .esi = M.x86.R_ESI,
+ .edi = M.x86.R_EDI,
+ .vector = M.x86.intno,
+ .error_code = 0,
+ .eip = M.x86.R_EIP,
+ .cs = M.x86.R_CS,
+ .eflags = M.x86.R_EFLG
+ };
+ struct eregs *regs = &reg_info;
+
+ debug("Oops, exception %d while executing option rom\n", regs->vector);
+ cpu_hlt();
+
+ return 0;
+}
+
+static int int_unknown_handler(void)
+{
+ debug("Unsupported software interrupt #0x%x eax 0x%x\n",
+ M.x86.intno, M.x86.R_EAX);
+
+ return -1;
+}
+
+/* setup interrupt handlers for mainboard */
+void bios_set_interrupt_handler(int intnum, int (*int_func)(void))
+{
+ int_handler[intnum] = int_func;
+}
+
+static void setup_interrupt_handlers(void)
+{
+ int i;
+
+ /*
+ * The first 16 int_handler functions are not BIOS services,
+ * but the CPU-generated exceptions ("hardware interrupts")
+ */
+ for (i = 0; i < 0x10; i++)
+ int_handler[i] = &int_exception_handler;
+
+ /* Mark all other int_handler calls as unknown first */
+ for (i = 0x10; i < 0x100; i++) {
+ /* Skip if bios_set_interrupt_handler() isn't called first */
+ if (int_handler[i])
+ continue;
+
+ /*
+ * Now set the default functions that are actually needed
+ * to initialize the option roms. The board may override
+ * these with bios_set_interrupt_handler()
+ */
+ switch (i) {
+ case 0x10:
+ int_handler[0x10] = &int10_handler;
+ break;
+ case 0x12:
+ int_handler[0x12] = &int12_handler;
+ break;
+ case 0x16:
+ int_handler[0x16] = &int16_handler;
+ break;
+ case 0x1a:
+ int_handler[0x1a] = &int1a_handler;
+ break;
+ default:
+ int_handler[i] = &int_unknown_handler;
+ break;
+ }
+ }
+}
+
+static void write_idt_stub(void *target, u8 intnum)
+{
+ unsigned char *codeptr;
+
+ codeptr = (unsigned char *)target;
+ memcpy(codeptr, &__idt_handler, __idt_handler_size);
+ codeptr[3] = intnum; /* modify int# in the code stub. */
+}
+
+static void setup_realmode_idt(void)
+{
+ struct realmode_idt *idts = NULL;
+ int i;
+
+ /*
+ * Copy IDT stub code for each interrupt. This might seem wasteful
+ * but it is really simple
+ */
+ for (i = 0; i < 256; i++) {
+ idts[i].cs = 0;
+ idts[i].offset = 0x1000 + (i * __idt_handler_size);
+ write_idt_stub((void *)((ulong)idts[i].offset), i);
+ }
+
+ /*
+ * Many option ROMs use the hard coded interrupt entry points in the
+ * system bios. So install them at the known locations.
+ */
+
+ /* int42 is the relocated int10 */
+ write_idt_stub((void *)0xff065, 0x42);
+ /* BIOS Int 11 Handler F000:F84D */
+ write_idt_stub((void *)0xff84d, 0x11);
+ /* BIOS Int 12 Handler F000:F841 */
+ write_idt_stub((void *)0xff841, 0x12);
+ /* BIOS Int 13 Handler F000:EC59 */
+ write_idt_stub((void *)0xfec59, 0x13);
+ /* BIOS Int 14 Handler F000:E739 */
+ write_idt_stub((void *)0xfe739, 0x14);
+ /* BIOS Int 15 Handler F000:F859 */
+ write_idt_stub((void *)0xff859, 0x15);
+ /* BIOS Int 16 Handler F000:E82E */
+ write_idt_stub((void *)0xfe82e, 0x16);
+ /* BIOS Int 17 Handler F000:EFD2 */
+ write_idt_stub((void *)0xfefd2, 0x17);
+ /* ROM BIOS Int 1A Handler F000:FE6E */
+ write_idt_stub((void *)0xffe6e, 0x1a);
+}
+
+#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE
+static u8 vbe_get_mode_info(struct vbe_mode_info *mi)
+{
+ u16 buffer_seg;
+ u16 buffer_adr;
+ char *buffer;
+
+ debug("VBE: Getting information about VESA mode %04x\n",
+ mi->video_mode);
+ buffer = PTR_TO_REAL_MODE(asm_realmode_buffer);
+ buffer_seg = (((unsigned long)buffer) >> 4) & 0xff00;
+ buffer_adr = ((unsigned long)buffer) & 0xffff;
+
+ realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, mi->video_mode,
+ 0x0000, buffer_seg, buffer_adr);
+ memcpy(mi->mode_info_block, buffer, sizeof(struct vbe_mode_info));
+ mi->valid = true;
+
+ return 0;
+}
+
+static u8 vbe_set_mode(struct vbe_mode_info *mi)
+{
+ int video_mode = mi->video_mode;
+
+ debug("VBE: Setting VESA mode %#04x\n", video_mode);
+ /* request linear framebuffer mode */
+ video_mode |= (1 << 14);
+ /* don't clear the framebuffer, we do that later */
+ video_mode |= (1 << 15);
+ realmode_interrupt(0x10, VESA_SET_MODE, video_mode,
+ 0x0000, 0x0000, 0x0000, 0x0000);
+
+ return 0;
+}
+
+static void vbe_set_graphics(int vesa_mode, struct vbe_mode_info *mode_info)
+{
+ unsigned char *framebuffer;
+
+ mode_info->video_mode = (1 << 14) | vesa_mode;
+ vbe_get_mode_info(mode_info);
+
+ framebuffer = (unsigned char *)(ulong)mode_info->vesa.phys_base_ptr;
+ debug("VBE: resolution: %dx%d@%d\n",
+ le16_to_cpu(mode_info->vesa.x_resolution),
+ le16_to_cpu(mode_info->vesa.y_resolution),
+ mode_info->vesa.bits_per_pixel);
+ debug("VBE: framebuffer: %p\n", framebuffer);
+ if (!framebuffer) {
+ debug("VBE: Mode does not support linear framebuffer\n");
+ return;
+ }
+
+ mode_info->video_mode &= 0x3ff;
+ vbe_set_mode(mode_info);
+}
+#endif /* CONFIG_FRAMEBUFFER_SET_VESA_MODE */
+
+void bios_run_on_x86(struct udevice *dev, unsigned long addr, int vesa_mode,
+ struct vbe_mode_info *mode_info)
+{
+ pci_dev_t pcidev = dm_pci_get_bdf(dev);
+ u32 num_dev;
+
+ num_dev = PCI_BUS(pcidev) << 8 | PCI_DEV(pcidev) << 3 |
+ PCI_FUNC(pcidev);
+
+ /* Needed to avoid exceptions in some ROMs */
+ interrupt_init();
+
+ /* Set up some legacy information in the F segment */
+ setup_rombios();
+
+ /* Set up C interrupt handlers */
+ setup_interrupt_handlers();
+
+ /* Set up real-mode IDT */
+ setup_realmode_idt();
+
+ /* Make sure the code is placed. */
+ setup_realmode_code();
+
+ debug("Calling Option ROM at %lx, pci device %#x...", addr, num_dev);
+
+ /* Option ROM entry point is at OPROM start + 3 */
+ realmode_call(addr + 0x0003, num_dev, 0xffff, 0x0000, 0xffff, 0x0,
+ 0x0);
+ debug("done\n");
+
+#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE
+ if (vesa_mode != -1)
+ vbe_set_graphics(vesa_mode, mode_info);
+#endif
+}
+
+asmlinkage int interrupt_handler(u32 intnumber, u32 gsfs, u32 dses,
+ u32 edi, u32 esi, u32 ebp, u32 esp,
+ u32 ebx, u32 edx, u32 ecx, u32 eax,
+ u32 cs_ip, u16 stackflags)
+{
+ u32 ip;
+ u32 cs;
+ u32 flags;
+ int ret = 0;
+
+ ip = cs_ip & 0xffff;
+ cs = cs_ip >> 16;
+ flags = stackflags;
+
+#ifdef CONFIG_REALMODE_DEBUG
+ debug("oprom: INT# 0x%x\n", intnumber);
+ debug("oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n",
+ eax, ebx, ecx, edx);
+ debug("oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n",
+ ebp, esp, edi, esi);
+ debug("oprom: ip: %04x cs: %04x flags: %08x\n",
+ ip, cs, flags);
+ debug("oprom: stackflags = %04x\n", stackflags);
+#endif
+
+ /*
+ * Fetch arguments from the stack and put them to a place
+ * suitable for the interrupt handlers
+ */
+ M.x86.R_EAX = eax;
+ M.x86.R_ECX = ecx;
+ M.x86.R_EDX = edx;
+ M.x86.R_EBX = ebx;
+ M.x86.R_ESP = esp;
+ M.x86.R_EBP = ebp;
+ M.x86.R_ESI = esi;
+ M.x86.R_EDI = edi;
+ M.x86.intno = intnumber;
+ M.x86.R_EIP = ip;
+ M.x86.R_CS = cs;
+ M.x86.R_EFLG = flags;
+
+ /* Call the interrupt handler for this interrupt number */
+ ret = int_handler[intnumber]();
+
+ /*
+ * This code is quite strange...
+ *
+ * Put registers back on the stack. The assembler code will pop them
+ * later. We force (volatile!) changing the values of the parameters
+ * of this function. We know that they stay alive on the stack after
+ * we leave this function.
+ */
+ *(volatile u32 *)&eax = M.x86.R_EAX;
+ *(volatile u32 *)&ecx = M.x86.R_ECX;
+ *(volatile u32 *)&edx = M.x86.R_EDX;
+ *(volatile u32 *)&ebx = M.x86.R_EBX;
+ *(volatile u32 *)&esi = M.x86.R_ESI;
+ *(volatile u32 *)&edi = M.x86.R_EDI;
+ flags = M.x86.R_EFLG;
+
+ /* Pass success or error back to our caller via the CARRY flag */
+ if (ret) {
+ flags &= ~1; /* no error: clear carry */
+ } else {
+ debug("int%02x call returned error\n", intnumber);
+ flags |= 1; /* error: set carry */
+ }
+ *(volatile u16 *)&stackflags = flags;
+
+ return ret;
+}
diff --git a/roms/u-boot/arch/x86/lib/bios.h b/roms/u-boot/arch/x86/lib/bios.h
new file mode 100644
index 000000000..2e51b9fbf
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/bios.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * From Coreboot file device/oprom/realmode/x86.h
+ *
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2009-2010 coresystems GmbH
+ */
+
+#ifndef _X86_LIB_BIOS_H
+#define _X86_LIB_BIOS_H
+
+#include <linux/linkage.h>
+
+#define REALMODE_BASE 0x600
+
+#ifdef __ASSEMBLY__
+
+#define PTR_TO_REAL_MODE(x) (x - asm_realmode_code + REALMODE_BASE)
+
+#else
+
+/* Convert a symbol address to our real mode area */
+#define PTR_TO_REAL_MODE(sym)\
+ (void *)(REALMODE_BASE + ((char *)&(sym) - (char *)&asm_realmode_code))
+
+/*
+ * The following symbols cannot be used directly. They need to be fixed up
+ * to point to the correct address location after the code has been copied
+ * to REALMODE_BASE. Absolute symbols are not used because those symbols are
+ * relocated by U-Boot.
+ */
+extern unsigned char asm_realmode_call, __realmode_interrupt;
+extern unsigned char asm_realmode_buffer;
+
+#define DOWNTO8(A) \
+ union { \
+ struct { \
+ union { \
+ struct { \
+ uint8_t A##l; \
+ uint8_t A##h; \
+ } __packed; \
+ uint16_t A##x; \
+ } __packed; \
+ uint16_t h##A##x; \
+ } __packed; \
+ uint32_t e##A##x; \
+ } __packed;
+
+#define DOWNTO16(A) \
+ union { \
+ struct { \
+ uint16_t A; \
+ uint16_t h##A; \
+ } __packed; \
+ uint32_t e##A; \
+ } __packed;
+
+struct eregs {
+ DOWNTO8(a);
+ DOWNTO8(c);
+ DOWNTO8(d);
+ DOWNTO8(b);
+ DOWNTO16(sp);
+ DOWNTO16(bp);
+ DOWNTO16(si);
+ DOWNTO16(di);
+ uint32_t vector;
+ uint32_t error_code;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+};
+
+struct realmode_idt {
+ u16 offset, cs;
+};
+
+void x86_exception(struct eregs *info);
+
+/* From x86_asm.S */
+extern unsigned char __idt_handler;
+extern unsigned int __idt_handler_size;
+extern unsigned char asm_realmode_code;
+extern unsigned int asm_realmode_code_size;
+
+asmlinkage void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx,
+ u32 esi, u32 edi);
+
+asmlinkage void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx,
+ u32 edx, u32 esi, u32 edi);
+
+int int10_handler(void);
+int int12_handler(void);
+int int16_handler(void);
+int int1a_handler(void);
+#endif /*__ASSEMBLY__ */
+
+#endif
diff --git a/roms/u-boot/arch/x86/lib/bios_asm.S b/roms/u-boot/arch/x86/lib/bios_asm.S
new file mode 100644
index 000000000..62dc5652d
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/bios_asm.S
@@ -0,0 +1,303 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * From coreboot x86_asm.S, cleaned up substantially
+ *
+ * Copyright (C) 2009-2010 coresystems GmbH
+ */
+
+#include <asm/processor.h>
+#include <asm/processor-flags.h>
+#include "bios.h"
+
+#define SEG(segment) $segment * X86_GDT_ENTRY_SIZE
+
+/*
+ * This is the interrupt handler stub code. It gets copied to the IDT and
+ * to some fixed addresses in the F segment. Before the code can used,
+ * it gets patched up by the C function copying it: byte 3 (the $0 in
+ * movb $0, %al) is overwritten with the interrupt numbers.
+ */
+
+ .code16
+ .globl __idt_handler
+__idt_handler:
+ pushal
+ movb $0, %al /* This instruction gets modified */
+ ljmp $0, $__interrupt_handler_16bit
+ .globl __idt_handler_size
+__idt_handler_size:
+ .long . - __idt_handler
+
+.macro setup_registers
+ /* initial register values */
+ movl 44(%ebp), %eax
+ movl %eax, __registers + 0 /* eax */
+ movl 48(%ebp), %eax
+ movl %eax, __registers + 4 /* ebx */
+ movl 52(%ebp), %eax
+ movl %eax, __registers + 8 /* ecx */
+ movl 56(%ebp), %eax
+ movl %eax, __registers + 12 /* edx */
+ movl 60(%ebp), %eax
+ movl %eax, __registers + 16 /* esi */
+ movl 64(%ebp), %eax
+ movl %eax, __registers + 20 /* edi */
+.endm
+
+.macro enter_real_mode
+ /* Activate the right segment descriptor real mode. */
+ ljmp SEG(X86_GDT_ENTRY_16BIT_CS), $PTR_TO_REAL_MODE(1f)
+1:
+.code16
+ /*
+ * Load the segment registers with properly configured segment
+ * descriptors. They will retain these configurations (limits,
+ * writability, etc.) once protected mode is turned off.
+ */
+ mov SEG(X86_GDT_ENTRY_16BIT_DS), %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+
+ /* Turn off protection */
+ movl %cr0, %eax
+ andl $~X86_CR0_PE, %eax
+ movl %eax, %cr0
+
+ /* Now really going into real mode */
+ ljmp $0, $PTR_TO_REAL_MODE(1f)
+1:
+ /*
+ * Set up a stack: Put the stack at the end of page zero. That way
+ * we can easily share it between real and protected, since the
+ * 16-bit ESP at segment 0 will work for any case.
+ */
+ mov $0x0, %ax
+ mov %ax, %ss
+
+ /* Load 16 bit IDT */
+ xor %ax, %ax
+ mov %ax, %ds
+ lidt __realmode_idt
+
+.endm
+
+.macro prepare_for_irom
+ movl $0x1000, %eax
+ movl %eax, %esp
+
+ /* Initialise registers for option rom lcall */
+ movl __registers + 0, %eax
+ movl __registers + 4, %ebx
+ movl __registers + 8, %ecx
+ movl __registers + 12, %edx
+ movl __registers + 16, %esi
+ movl __registers + 20, %edi
+
+ /* Set all segments to 0x0000, ds to 0x0040 */
+ push %ax
+ xor %ax, %ax
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov SEG(X86_GDT_ENTRY_16BIT_FLAT_DS), %ax
+ mov %ax, %ds
+ pop %ax
+
+.endm
+
+.macro enter_protected_mode
+ /* Go back to protected mode */
+ movl %cr0, %eax
+ orl $X86_CR0_PE, %eax
+ movl %eax, %cr0
+
+ /* Now that we are in protected mode jump to a 32 bit code segment */
+ data32 ljmp SEG(X86_GDT_ENTRY_32BIT_CS), $PTR_TO_REAL_MODE(1f)
+1:
+ .code32
+ mov SEG(X86_GDT_ENTRY_32BIT_DS), %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %gs
+ mov %ax, %ss
+ mov SEG(X86_GDT_ENTRY_32BIT_FS), %ax
+ mov %ax, %fs
+
+ /* restore proper idt */
+ lidt idt_ptr
+.endm
+
+/*
+ * In order to be independent of U-Boot's position in RAM we relocate a part
+ * of the code to the first megabyte of RAM, so the CPU can use it in
+ * real-mode. This code lives at asm_realmode_code.
+ */
+ .globl asm_realmode_code
+asm_realmode_code:
+
+/* Realmode IDT pointer structure. */
+__realmode_idt = PTR_TO_REAL_MODE(.)
+ .word 1023 /* 16 bit limit */
+ .long 0 /* 24 bit base */
+ .word 0
+
+/* Preserve old stack */
+__stack = PTR_TO_REAL_MODE(.)
+ .long 0
+
+/* Register store for realmode_call and realmode_interrupt */
+__registers = PTR_TO_REAL_MODE(.)
+ .long 0 /* 0 - EAX */
+ .long 0 /* 4 - EBX */
+ .long 0 /* 8 - ECX */
+ .long 0 /* 12 - EDX */
+ .long 0 /* 16 - ESI */
+ .long 0 /* 20 - EDI */
+
+/* 256 byte buffer, used by int10 */
+ .globl asm_realmode_buffer
+asm_realmode_buffer:
+ .skip 256
+
+ .code32
+ .globl asm_realmode_call
+asm_realmode_call:
+ /* save all registers to the stack */
+ pusha
+ pushf
+ movl %esp, __stack
+ movl %esp, %ebp
+
+ /*
+ * This function is called with regparm=0 and we have to skip the
+ * 36 bytes from pushf+pusha. Hence start at 40.
+ * Set up our call instruction.
+ */
+ movl 40(%ebp), %eax
+ mov %ax, __lcall_instr + 1
+ andl $0xffff0000, %eax
+ shrl $4, %eax
+ mov %ax, __lcall_instr + 3
+
+ wbinvd
+
+ setup_registers
+ enter_real_mode
+ prepare_for_irom
+
+__lcall_instr = PTR_TO_REAL_MODE(.)
+ .byte 0x9a
+ .word 0x0000, 0x0000
+
+ enter_protected_mode
+
+ /* restore stack pointer, eflags and register values and exit */
+ movl __stack, %esp
+ popf
+ popa
+ ret
+
+ .globl __realmode_interrupt
+__realmode_interrupt:
+ /* save all registers to the stack and store the stack pointer */
+ pusha
+ pushf
+ movl %esp, __stack
+ movl %esp, %ebp
+
+ /*
+ * This function is called with regparm=0 and we have to skip the
+ * 36 bytes from pushf+pusha. Hence start at 40.
+ * Prepare interrupt calling code.
+ */
+ movl 40(%ebp), %eax
+ movb %al, __intXX_instr + 1 /* intno */
+
+ setup_registers
+ enter_real_mode
+ prepare_for_irom
+
+__intXX_instr = PTR_TO_REAL_MODE(.)
+ .byte 0xcd, 0x00 /* This becomes intXX */
+
+ enter_protected_mode
+
+ /* restore stack pointer, eflags and register values and exit */
+ movl __stack, %esp
+ popf
+ popa
+ ret
+
+/*
+ * This is the 16-bit interrupt entry point called by the IDT stub code.
+ *
+ * Before this code code is called, %eax is pushed to the stack, and the
+ * interrupt number is loaded into %al. On return this function cleans up
+ * for its caller.
+ */
+ .code16
+__interrupt_handler_16bit = PTR_TO_REAL_MODE(.)
+ push %ds
+ push %es
+ push %fs
+ push %gs
+
+ /* Save real mode SS */
+ movw %ss, %cs:__realmode_ss
+
+ /* Clear DF to not break ABI assumptions */
+ cld
+
+ /*
+ * Clean up the interrupt number. We could do this in the stub, but
+ * it would cost two more bytes per stub entry.
+ */
+ andl $0xff, %eax
+ pushl %eax /* ... and make it the first parameter */
+
+ enter_protected_mode
+
+ /*
+ * Now we are in protected mode. We need compute the right ESP based
+ * on saved real mode SS otherwise interrupt_handler() won't get
+ * correct parameters from the stack.
+ */
+ movzwl %cs:__realmode_ss, %ecx
+ shll $4, %ecx
+ addl %ecx, %esp
+
+ /* Call the C interrupt handler */
+ movl $interrupt_handler, %eax
+ call *%eax
+
+ /* Restore real mode ESP based on saved SS */
+ movzwl %cs:__realmode_ss, %ecx
+ shll $4, %ecx
+ subl %ecx, %esp
+
+ enter_real_mode
+
+ /* Restore real mode SS */
+ movw %cs:__realmode_ss, %ss
+
+ /*
+ * Restore all registers, including those manipulated by the C
+ * handler
+ */
+ popl %eax
+ pop %gs
+ pop %fs
+ pop %es
+ pop %ds
+ popal
+ iret
+
+__realmode_ss = PTR_TO_REAL_MODE(.)
+ .word 0
+
+ .globl asm_realmode_code_size
+asm_realmode_code_size:
+ .long . - asm_realmode_code
diff --git a/roms/u-boot/arch/x86/lib/bios_interrupts.c b/roms/u-boot/arch/x86/lib/bios_interrupts.c
new file mode 100644
index 000000000..d6b4da7e2
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/bios_interrupts.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * From Coreboot
+ *
+ * Copyright (C) 2001 Ronald G. Minnich
+ * Copyright (C) 2005 Nick.Barker9@btinternet.com
+ * Copyright (C) 2007-2009 coresystems GmbH
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/pci.h>
+#include "bios_emul.h"
+
+/* errors go in AH. Just set these up so that word assigns will work */
+enum {
+ PCIBIOS_SUCCESSFUL = 0x0000,
+ PCIBIOS_UNSUPPORTED = 0x8100,
+ PCIBIOS_BADVENDOR = 0x8300,
+ PCIBIOS_NODEV = 0x8600,
+ PCIBIOS_BADREG = 0x8700
+};
+
+int int10_handler(void)
+{
+ static u8 cursor_row, cursor_col;
+ int res = 0;
+
+ switch ((M.x86.R_EAX & 0xff00) >> 8) {
+ case 0x01: /* Set cursor shape */
+ res = 1;
+ break;
+ case 0x02: /* Set cursor position */
+ if (cursor_row != ((M.x86.R_EDX >> 8) & 0xff) ||
+ cursor_col >= (M.x86.R_EDX & 0xff)) {
+ debug("\n");
+ }
+ cursor_row = (M.x86.R_EDX >> 8) & 0xff;
+ cursor_col = M.x86.R_EDX & 0xff;
+ res = 1;
+ break;
+ case 0x03: /* Get cursor position */
+ M.x86.R_EAX &= 0x00ff;
+ M.x86.R_ECX = 0x0607;
+ M.x86.R_EDX = (cursor_row << 8) | cursor_col;
+ res = 1;
+ break;
+ case 0x06: /* Scroll up */
+ debug("\n");
+ res = 1;
+ break;
+ case 0x08: /* Get Character and Mode at Cursor Position */
+ M.x86.R_EAX = 0x0f00 | 'A'; /* White on black 'A' */
+ res = 1;
+ break;
+ case 0x09: /* Write Character and attribute */
+ case 0x0e: /* Write Character */
+ debug("%c", M.x86.R_EAX & 0xff);
+ res = 1;
+ break;
+ case 0x0f: /* Get video mode */
+ M.x86.R_EAX = 0x5002; /*80 x 25 */
+ M.x86.R_EBX &= 0x00ff;
+ res = 1;
+ break;
+ default:
+ printf("Unknown INT10 function %04x\n", M.x86.R_EAX & 0xffff);
+ break;
+ }
+ return res;
+}
+
+int int12_handler(void)
+{
+ M.x86.R_EAX = 64 * 1024;
+ return 1;
+}
+
+int int16_handler(void)
+{
+ int res = 0;
+
+ switch ((M.x86.R_EAX & 0xff00) >> 8) {
+ case 0x00: /* Check for Keystroke */
+ M.x86.R_EAX = 0x6120; /* Space Bar, Space */
+ res = 1;
+ break;
+ case 0x01: /* Check for Keystroke */
+ M.x86.R_EFLG |= 1 << 6; /* Zero Flag set (no key available) */
+ res = 1;
+ break;
+ default:
+ printf("Unknown INT16 function %04x\n", M.x86.R_EAX & 0xffff);
+
+break;
+ }
+ return res;
+}
+
+#define PCI_CONFIG_SPACE_TYPE1 (1 << 0)
+#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4)
+
+int int1a_handler(void)
+{
+ unsigned short func = (unsigned short)M.x86.R_EAX;
+ int retval = 1;
+ unsigned short devid, vendorid, devfn;
+ struct udevice *dev;
+ /* Use short to get rid of gabage in upper half of 32-bit register */
+ short devindex;
+ unsigned char bus;
+ pci_dev_t bdf;
+ u32 dword;
+ u16 word;
+ u8 byte, reg;
+ int ret;
+
+ switch (func) {
+ case 0xb101: /* PCIBIOS Check */
+ M.x86.R_EDX = 0x20494350; /* ' ICP' */
+ M.x86.R_EAX &= 0xffff0000; /* Clear AH / AL */
+ M.x86.R_EAX |= PCI_CONFIG_SPACE_TYPE1 |
+ PCI_SPECIAL_CYCLE_TYPE1;
+ /*
+ * last bus in the system. Hard code to 255 for now.
+ * dev_enumerate() does not seem to tell us (publically)
+ */
+ M.x86.R_ECX = 0xff;
+ M.x86.R_EDI = 0x00000000; /* protected mode entry */
+ retval = 1;
+ break;
+ case 0xb102: /* Find Device */
+ devid = M.x86.R_ECX;
+ vendorid = M.x86.R_EDX;
+ devindex = M.x86.R_ESI;
+ bdf = -1;
+ ret = dm_pci_find_device(vendorid, devid, devindex, &dev);
+ if (!ret) {
+ unsigned short busdevfn;
+
+ bdf = dm_pci_get_bdf(dev);
+ M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
+ M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
+ /*
+ * busnum is an unsigned char;
+ * devfn is an int, so we mask it off.
+ */
+ busdevfn = (PCI_BUS(bdf) << 8) | PCI_DEV(bdf) << 3 |
+ PCI_FUNC(bdf);
+ debug("0x%x: return 0x%x\n", func, busdevfn);
+ M.x86.R_EBX = busdevfn;
+ retval = 1;
+ } else {
+ M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
+ M.x86.R_EAX |= PCIBIOS_NODEV;
+ retval = 0;
+ }
+ break;
+ case 0xb10a: /* Read Config Dword */
+ case 0xb109: /* Read Config Word */
+ case 0xb108: /* Read Config Byte */
+ case 0xb10d: /* Write Config Dword */
+ case 0xb10c: /* Write Config Word */
+ case 0xb10b: /* Write Config Byte */
+ devfn = M.x86.R_EBX & 0xff;
+ bus = M.x86.R_EBX >> 8;
+ reg = M.x86.R_EDI;
+ bdf = PCI_BDF(bus, devfn >> 3, devfn & 7);
+
+ ret = dm_pci_bus_find_bdf(bdf, &dev);
+ if (ret) {
+ debug("%s: Device %x not found\n", __func__, bdf);
+ break;
+ }
+
+ switch (func) {
+ case 0xb108: /* Read Config Byte */
+ dm_pci_read_config8(dev, reg, &byte);
+ M.x86.R_ECX = byte;
+ break;
+ case 0xb109: /* Read Config Word */
+ dm_pci_read_config16(dev, reg, &word);
+ M.x86.R_ECX = word;
+ break;
+ case 0xb10a: /* Read Config Dword */
+ dm_pci_read_config32(dev, reg, &dword);
+ M.x86.R_ECX = dword;
+ break;
+ case 0xb10b: /* Write Config Byte */
+ byte = M.x86.R_ECX;
+ dm_pci_write_config8(dev, reg, byte);
+ break;
+ case 0xb10c: /* Write Config Word */
+ word = M.x86.R_ECX;
+ dm_pci_write_config16(dev, reg, word);
+ break;
+ case 0xb10d: /* Write Config Dword */
+ dword = M.x86.R_ECX;
+ dm_pci_write_config32(dev, reg, dword);
+ break;
+ }
+#ifdef CONFIG_REALMODE_DEBUG
+ debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func,
+ bus, devfn, reg, M.x86.R_ECX);
+#endif
+ M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
+ M.x86.R_EAX |= PCIBIOS_SUCCESSFUL;
+ retval = 1;
+ break;
+ default:
+ printf("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
+ M.x86.R_EAX &= 0xffff00ff; /* Clear AH */
+ M.x86.R_EAX |= PCIBIOS_UNSUPPORTED;
+ retval = 0;
+ break;
+ }
+
+ return retval;
+}
diff --git a/roms/u-boot/arch/x86/lib/bootm.c b/roms/u-boot/arch/x86/lib/bootm.c
new file mode 100644
index 000000000..733dd7125
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/bootm.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ */
+
+#include <common.h>
+#include <bootstage.h>
+#include <command.h>
+#include <hang.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <fdt_support.h>
+#include <image.h>
+#include <u-boot/zlib.h>
+#include <asm/bootparam.h>
+#include <asm/cpu.h>
+#include <asm/byteorder.h>
+#include <asm/zimage.h>
+#ifdef CONFIG_SYS_COREBOOT
+#include <asm/arch/timestamp.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define COMMAND_LINE_OFFSET 0x9000
+
+void bootm_announce_and_cleanup(void)
+{
+ printf("\nStarting kernel ...\n\n");
+
+#ifdef CONFIG_SYS_COREBOOT
+ timestamp_add_now(TS_START_KERNEL);
+#endif
+ bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
+#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
+ bootstage_report();
+#endif
+
+ /*
+ * Call remove function of all devices with a removal flag set.
+ * This may be useful for last-stage operations, like cancelling
+ * of DMA operation or releasing device internal buffers.
+ */
+ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+}
+
+#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
+int arch_fixup_memory_node(void *blob)
+{
+ struct bd_info *bd = gd->bd;
+ int bank;
+ u64 start[CONFIG_NR_DRAM_BANKS];
+ u64 size[CONFIG_NR_DRAM_BANKS];
+
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ start[bank] = bd->bi_dram[bank].start;
+ size[bank] = bd->bi_dram[bank].size;
+ }
+
+ return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
+}
+#endif
+
+/* Subcommand: PREP */
+static int boot_prep_linux(bootm_headers_t *images)
+{
+ char *cmd_line_dest = NULL;
+ image_header_t *hdr;
+ int is_zimage = 0;
+ void *data = NULL;
+ size_t len;
+ int ret;
+
+#ifdef CONFIG_OF_LIBFDT
+ if (images->ft_len) {
+ debug("using: FDT\n");
+ if (image_setup_linux(images)) {
+ puts("FDT creation failed! hanging...");
+ hang();
+ }
+ }
+#endif
+ if (images->legacy_hdr_valid) {
+ hdr = images->legacy_hdr_os;
+ if (image_check_type(hdr, IH_TYPE_MULTI)) {
+ ulong os_data, os_len;
+
+ /* if multi-part image, we need to get first subimage */
+ image_multi_getimg(hdr, 0, &os_data, &os_len);
+ data = (void *)os_data;
+ len = os_len;
+ } else {
+ /* otherwise get image data */
+ data = (void *)image_get_data(hdr);
+ len = image_get_data_size(hdr);
+ }
+ is_zimage = 1;
+#if defined(CONFIG_FIT)
+ } else if (images->fit_uname_os && is_zimage) {
+ ret = fit_image_get_data(images->fit_hdr_os,
+ images->fit_noffset_os,
+ (const void **)&data, &len);
+ if (ret) {
+ puts("Can't get image data/size!\n");
+ goto error;
+ }
+ is_zimage = 1;
+#endif
+ }
+
+ if (is_zimage) {
+ ulong load_address;
+ char *base_ptr;
+
+ base_ptr = (char *)load_zimage(data, len, &load_address);
+ if (!base_ptr) {
+ puts("## Kernel loading failed ...\n");
+ goto error;
+ }
+ images->os.load = load_address;
+ cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET;
+ images->ep = (ulong)base_ptr;
+ } else if (images->ep) {
+ cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET;
+ } else {
+ printf("## Kernel loading failed (missing x86 kernel setup) ...\n");
+ goto error;
+ }
+
+ printf("Setup at %#08lx\n", images->ep);
+ ret = setup_zimage((void *)images->ep, cmd_line_dest,
+ 0, images->rd_start,
+ images->rd_end - images->rd_start, 0);
+
+ if (ret) {
+ printf("## Setting up boot parameters failed ...\n");
+ return 1;
+ }
+
+ return 0;
+
+error:
+ return 1;
+}
+
+int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit)
+{
+ bootm_announce_and_cleanup();
+
+#ifdef CONFIG_SYS_COREBOOT
+ timestamp_add_now(TS_U_BOOT_START_KERNEL);
+#endif
+ if (image_64bit) {
+ if (!cpu_has_64bit()) {
+ puts("Cannot boot 64-bit kernel on 32-bit machine\n");
+ return -EFAULT;
+ }
+ /* At present 64-bit U-Boot does not support booting a
+ * kernel.
+ * TODO(sjg@chromium.org): Support booting both 32-bit and
+ * 64-bit kernels from 64-bit U-Boot.
+ */
+#if !CONFIG_IS_ENABLED(X86_64)
+ return cpu_jump_to_64bit(setup_base, load_address);
+#endif
+ } else {
+ /*
+ * Set %ebx, %ebp, and %edi to 0, %esi to point to the
+ * boot_params structure, and then jump to the kernel. We
+ * assume that %cs is 0x10, 4GB flat, and read/execute, and
+ * the data segments are 0x18, 4GB flat, and read/write.
+ * U-Boot is setting them up that way for itself in
+ * arch/i386/cpu/cpu.c.
+ *
+ * Note that we cannot currently boot a kernel while running as
+ * an EFI application. Please use the payload option for that.
+ */
+#ifndef CONFIG_EFI_APP
+ __asm__ __volatile__ (
+ "movl $0, %%ebp\n"
+ "cli\n"
+ "jmp *%[kernel_entry]\n"
+ :: [kernel_entry]"a"(load_address),
+ [boot_params] "S"(setup_base),
+ "b"(0), "D"(0)
+ );
+#endif
+ }
+
+ /* We can't get to here */
+ return -EFAULT;
+}
+
+/* Subcommand: GO */
+static int boot_jump_linux(bootm_headers_t *images)
+{
+ debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n",
+ images->ep, images->os.load);
+
+ return boot_linux_kernel(images->ep, images->os.load,
+ images->os.arch == IH_ARCH_X86_64);
+}
+
+int do_bootm_linux(int flag, int argc, char *const argv[],
+ bootm_headers_t *images)
+{
+ /* No need for those on x86 */
+ if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+ return -1;
+
+ if (flag & BOOTM_STATE_OS_PREP)
+ return boot_prep_linux(images);
+
+ if (flag & BOOTM_STATE_OS_GO)
+ return boot_jump_linux(images);
+
+ return boot_jump_linux(images);
+}
diff --git a/roms/u-boot/arch/x86/lib/cmd_boot.c b/roms/u-boot/arch/x86/lib/cmd_boot.c
new file mode 100644
index 000000000..4facbe5f3
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/cmd_boot.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008-2011
+ * Graeme Russ, <graeme.russ@gmail.com>
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <asm/u-boot-x86.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+unsigned long do_go_exec(ulong (*entry)(int, char * const []),
+ int argc, char *const argv[])
+{
+ unsigned long ret = 0;
+ char **argv_tmp;
+
+ /*
+ * x86 does not use a dedicated register to pass the pointer to
+ * the global_data, so it is instead passed as argv[-1]. By using
+ * argv[-1], the called 'Application' can use the contents of
+ * argv natively. However, to safely use argv[-1] a new copy of
+ * argv is needed with the extra element
+ */
+ argv_tmp = malloc(sizeof(char *) * (argc + 1));
+
+ if (argv_tmp) {
+ argv_tmp[0] = (char *)gd;
+
+ memcpy(&argv_tmp[1], argv, (size_t)(sizeof(char *) * argc));
+
+ ret = (entry) (argc, &argv_tmp[1]);
+ free(argv_tmp);
+ }
+
+ return ret;
+}
diff --git a/roms/u-boot/arch/x86/lib/coreboot/Makefile b/roms/u-boot/arch/x86/lib/coreboot/Makefile
new file mode 100644
index 000000000..cb0ae1d01
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/coreboot/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2021 Google LLC
+#
+
+obj-y += cb_sysinfo.o
+obj-y += cb_support.o
diff --git a/roms/u-boot/arch/x86/lib/coreboot/cb_support.c b/roms/u-boot/arch/x86/lib/coreboot/cb_support.c
new file mode 100644
index 000000000..ebb45cdfb
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/coreboot/cb_support.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Support for booting from coreboot
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#include <common.h>
+#include <asm/cb_sysinfo.h>
+#include <asm/e820.h>
+
+unsigned int cb_install_e820_map(unsigned int max_entries,
+ struct e820_entry *entries)
+{
+ unsigned int num_entries;
+ int i;
+
+ num_entries = min((unsigned int)lib_sysinfo.n_memranges, max_entries);
+ if (num_entries < lib_sysinfo.n_memranges) {
+ printf("Warning: Limiting e820 map to %d entries\n",
+ num_entries);
+ }
+ for (i = 0; i < num_entries; i++) {
+ struct memrange *memrange = &lib_sysinfo.memrange[i];
+
+ entries[i].addr = memrange->base;
+ entries[i].size = memrange->size;
+
+ /*
+ * coreboot has some extensions (type 6 & 16) to the E820 types.
+ * When we detect this, mark it as E820_RESERVED.
+ */
+ if (memrange->type == CB_MEM_VENDOR_RSVD ||
+ memrange->type == CB_MEM_TABLE)
+ entries[i].type = E820_RESERVED;
+ else
+ entries[i].type = memrange->type;
+ }
+
+ return num_entries;
+}
diff --git a/roms/u-boot/arch/x86/lib/coreboot/cb_sysinfo.c b/roms/u-boot/arch/x86/lib/coreboot/cb_sysinfo.c
new file mode 100644
index 000000000..748fa4ee5
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/coreboot/cb_sysinfo.c
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * This file is part of the libpayload project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ * Copyright (C) 2009 coresystems GmbH
+ */
+
+#include <common.h>
+#include <asm/cb_sysinfo.h>
+#include <init.h>
+#include <mapmem.h>
+#include <net.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This needs to be in the .data section so that it's copied over during
+ * relocation. By default it's put in the .bss section which is simply filled
+ * with zeroes when transitioning from "ROM", which is really RAM, to other
+ * RAM.
+ */
+struct sysinfo_t lib_sysinfo __section(".data");
+
+/*
+ * Some of this is x86 specific, and the rest of it is generic. Right now,
+ * since we only support x86, we'll avoid trying to make lots of infrastructure
+ * we don't need. If in the future, we want to use coreboot on some other
+ * architecture, then take out the generic parsing code and move it elsewhere.
+ */
+
+/* === Parsing code === */
+/* This is the generic parsing code */
+
+static void cb_parse_memory(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct cb_memory *mem = (struct cb_memory *)ptr;
+ int count = MEM_RANGE_COUNT(mem);
+ int i;
+
+ if (count > SYSINFO_MAX_MEM_RANGES)
+ count = SYSINFO_MAX_MEM_RANGES;
+
+ info->n_memranges = 0;
+
+ for (i = 0; i < count; i++) {
+ struct cb_memory_range *range =
+ (struct cb_memory_range *)MEM_RANGE_PTR(mem, i);
+
+ info->memrange[info->n_memranges].base =
+ UNPACK_CB64(range->start);
+
+ info->memrange[info->n_memranges].size =
+ UNPACK_CB64(range->size);
+
+ info->memrange[info->n_memranges].type = range->type;
+
+ info->n_memranges++;
+ }
+}
+
+static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct cb_serial *ser = (struct cb_serial *)ptr;
+
+ info->serial = ser;
+}
+
+static void cb_parse_vboot_handoff(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct lb_range *vbho = (struct lb_range *)ptr;
+
+ info->vboot_handoff = (void *)(uintptr_t)vbho->range_start;
+ info->vboot_handoff_size = vbho->range_size;
+}
+
+static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct lb_range *vbnv = (struct lb_range *)ptr;
+
+ info->vbnv_start = vbnv->range_start;
+ info->vbnv_size = vbnv->range_size;
+}
+
+static void cb_parse_cbmem_entry(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct cb_cbmem_entry *entry = (struct cb_cbmem_entry *)ptr;
+
+ if (entry->id != CBMEM_ID_SMBIOS)
+ return;
+
+ info->smbios_start = entry->address;
+ info->smbios_size = entry->entry_size;
+}
+
+static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info)
+{
+ int i;
+ struct cb_gpios *gpios = (struct cb_gpios *)ptr;
+
+ info->num_gpios = (gpios->count < SYSINFO_MAX_GPIOS) ?
+ (gpios->count) : SYSINFO_MAX_GPIOS;
+
+ for (i = 0; i < info->num_gpios; i++)
+ info->gpios[i] = gpios->gpios[i];
+}
+
+static void cb_parse_vdat(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct lb_range *vdat = (struct lb_range *)ptr;
+
+ info->vdat_addr = map_sysmem(vdat->range_start, vdat->range_size);
+ info->vdat_size = vdat->range_size;
+}
+
+static void cb_parse_mac_addresses(unsigned char *ptr,
+ struct sysinfo_t *info)
+{
+ struct cb_macs *macs = (struct cb_macs *)ptr;
+ int i;
+
+ info->num_macs = (macs->count < ARRAY_SIZE(info->macs)) ?
+ macs->count : ARRAY_SIZE(info->macs);
+
+ for (i = 0; i < info->num_macs; i++)
+ info->macs[i] = macs->mac_addrs[i];
+}
+
+static void cb_parse_tstamp(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_cbmem_tab *const cbmem = ptr;
+
+ info->tstamp_table = map_sysmem(cbmem->cbmem_tab, 0);
+}
+
+static void cb_parse_cbmem_cons(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_cbmem_tab *const cbmem = ptr;
+
+ info->cbmem_cons = map_sysmem(cbmem->cbmem_tab, 0);
+}
+
+static void cb_parse_acpi_gnvs(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
+
+ info->acpi_gnvs = map_sysmem(cbmem->cbmem_tab, 0);
+}
+
+static void cb_parse_board_id(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct cb_board_id *const cbbid = (struct cb_board_id *)ptr;
+
+ info->board_id = cbbid->board_id;
+}
+
+static void cb_parse_ram_code(unsigned char *ptr, struct sysinfo_t *info)
+{
+ struct cb_ram_code *const ram_code = (struct cb_ram_code *)ptr;
+
+ info->ram_code = ram_code->ram_code;
+}
+
+static void cb_parse_optiontable(void *ptr, struct sysinfo_t *info)
+{
+ /* ptr points to a coreboot table entry and is already virtual */
+ info->option_table = ptr;
+}
+
+static void cb_parse_checksum(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_cmos_checksum *cmos_cksum = ptr;
+
+ info->cmos_range_start = cmos_cksum->range_start;
+ info->cmos_range_end = cmos_cksum->range_end;
+ info->cmos_checksum_location = cmos_cksum->location;
+}
+
+static void cb_parse_framebuffer(void *ptr, struct sysinfo_t *info)
+{
+ /* ptr points to a coreboot table entry and is already virtual */
+ info->framebuffer = ptr;
+}
+
+static void cb_parse_string(unsigned char *ptr, char **info)
+{
+ *info = (char *)((struct cb_string *)ptr)->string;
+}
+
+static void cb_parse_wifi_calibration(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
+
+ info->wifi_calibration = map_sysmem(cbmem->cbmem_tab, 0);
+}
+
+static void cb_parse_ramoops(void *ptr, struct sysinfo_t *info)
+{
+ struct lb_range *ramoops = (struct lb_range *)ptr;
+
+ info->ramoops_buffer = ramoops->range_start;
+ info->ramoops_buffer_size = ramoops->range_size;
+}
+
+static void cb_parse_mtc(void *ptr, struct sysinfo_t *info)
+{
+ struct lb_range *mtc = (struct lb_range *)ptr;
+
+ info->mtc_start = mtc->range_start;
+ info->mtc_size = mtc->range_size;
+}
+
+static void cb_parse_spi_flash(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_spi_flash *flash = (struct cb_spi_flash *)ptr;
+
+ info->spi_flash.size = flash->flash_size;
+ info->spi_flash.sector_size = flash->sector_size;
+ info->spi_flash.erase_cmd = flash->erase_cmd;
+}
+
+static void cb_parse_boot_media_params(unsigned char *ptr,
+ struct sysinfo_t *info)
+{
+ struct cb_boot_media_params *const bmp =
+ (struct cb_boot_media_params *)ptr;
+
+ info->fmap_offset = bmp->fmap_offset;
+ info->cbfs_offset = bmp->cbfs_offset;
+ info->cbfs_size = bmp->cbfs_size;
+ info->boot_media_size = bmp->boot_media_size;
+}
+
+static void cb_parse_vpd(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
+
+ info->chromeos_vpd = map_sysmem(cbmem->cbmem_tab, 0);
+}
+
+static void cb_parse_tsc_info(void *ptr, struct sysinfo_t *info)
+{
+ const struct cb_tsc_info *tsc_info = ptr;
+
+ if (tsc_info->freq_khz == 0)
+ return;
+
+ /* Honor the TSC frequency passed to the payload */
+ info->cpu_khz = tsc_info->freq_khz;
+}
+
+static void cb_parse_x86_rom_var_mtrr(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_x86_rom_mtrr *rom_mtrr = ptr;
+
+ info->x86_rom_var_mtrr_index = rom_mtrr->index;
+}
+
+static void cb_parse_mrc_cache(void *ptr, struct sysinfo_t *info)
+{
+ struct cb_cbmem_tab *const cbmem = (struct cb_cbmem_tab *)ptr;
+
+ info->mrc_cache = map_sysmem(cbmem->cbmem_tab, 0);
+}
+
+__weak void cb_parse_unhandled(u32 tag, unsigned char *ptr)
+{
+}
+
+static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
+{
+ unsigned char *ptr = addr;
+ struct cb_header *header;
+ int i;
+
+ header = (struct cb_header *)ptr;
+ if (!header->table_bytes)
+ return 0;
+
+ /* Make sure the checksums match */
+ if (!ip_checksum_ok(header, sizeof(*header)))
+ return -1;
+
+ if (compute_ip_checksum(ptr + sizeof(*header), header->table_bytes) !=
+ header->table_checksum)
+ return -1;
+
+ info->header = header;
+
+ /*
+ * Board straps represented by numerical values are small numbers.
+ * Preset them to an invalid value in case the firmware does not
+ * supply the info.
+ */
+ info->board_id = ~0;
+ info->ram_code = ~0;
+
+ /* Now, walk the tables */
+ ptr += header->header_bytes;
+
+ /* Inintialize some fields to sentinel values */
+ info->vbnv_start = info->vbnv_size = (uint32_t)(-1);
+
+ for (i = 0; i < header->table_entries; i++) {
+ struct cb_record *rec = (struct cb_record *)ptr;
+
+ /* We only care about a few tags here (maybe more later) */
+ switch (rec->tag) {
+ case CB_TAG_FORWARD:
+ return cb_parse_header(
+ (void *)(unsigned long)
+ ((struct cb_forward *)rec)->forward,
+ len, info);
+ continue;
+ case CB_TAG_MEMORY:
+ cb_parse_memory(ptr, info);
+ break;
+ case CB_TAG_SERIAL:
+ cb_parse_serial(ptr, info);
+ break;
+ case CB_TAG_VERSION:
+ cb_parse_string(ptr, &info->cb_version);
+ break;
+ case CB_TAG_EXTRA_VERSION:
+ cb_parse_string(ptr, &info->extra_version);
+ break;
+ case CB_TAG_BUILD:
+ cb_parse_string(ptr, &info->build);
+ break;
+ case CB_TAG_COMPILE_TIME:
+ cb_parse_string(ptr, &info->compile_time);
+ break;
+ case CB_TAG_COMPILE_BY:
+ cb_parse_string(ptr, &info->compile_by);
+ break;
+ case CB_TAG_COMPILE_HOST:
+ cb_parse_string(ptr, &info->compile_host);
+ break;
+ case CB_TAG_COMPILE_DOMAIN:
+ cb_parse_string(ptr, &info->compile_domain);
+ break;
+ case CB_TAG_COMPILER:
+ cb_parse_string(ptr, &info->compiler);
+ break;
+ case CB_TAG_LINKER:
+ cb_parse_string(ptr, &info->linker);
+ break;
+ case CB_TAG_ASSEMBLER:
+ cb_parse_string(ptr, &info->assembler);
+ break;
+ case CB_TAG_CMOS_OPTION_TABLE:
+ cb_parse_optiontable(ptr, info);
+ break;
+ case CB_TAG_OPTION_CHECKSUM:
+ cb_parse_checksum(ptr, info);
+ break;
+ /*
+ * FIXME we should warn on serial if coreboot set up a
+ * framebuffer buf the payload does not know about it.
+ */
+ case CB_TAG_FRAMEBUFFER:
+ cb_parse_framebuffer(ptr, info);
+ break;
+ case CB_TAG_MAINBOARD:
+ info->mainboard = (struct cb_mainboard *)ptr;
+ break;
+ case CB_TAG_GPIO:
+ cb_parse_gpios(ptr, info);
+ break;
+ case CB_TAG_VDAT:
+ cb_parse_vdat(ptr, info);
+ break;
+ case CB_TAG_VBNV:
+ cb_parse_vbnv(ptr, info);
+ break;
+ case CB_TAG_VBOOT_HANDOFF:
+ cb_parse_vboot_handoff(ptr, info);
+ break;
+ case CB_TAG_MAC_ADDRS:
+ cb_parse_mac_addresses(ptr, info);
+ break;
+ case CB_TAG_SERIALNO:
+ cb_parse_string(ptr, &info->serialno);
+ break;
+ case CB_TAG_TIMESTAMPS:
+ cb_parse_tstamp(ptr, info);
+ break;
+ case CB_TAG_CBMEM_CONSOLE:
+ cb_parse_cbmem_cons(ptr, info);
+ break;
+ case CB_TAG_ACPI_GNVS:
+ cb_parse_acpi_gnvs(ptr, info);
+ break;
+ case CB_TAG_CBMEM_ENTRY:
+ cb_parse_cbmem_entry(ptr, info);
+ break;
+ case CB_TAG_BOARD_ID:
+ cb_parse_board_id(ptr, info);
+ break;
+ case CB_TAG_RAM_CODE:
+ cb_parse_ram_code(ptr, info);
+ break;
+ case CB_TAG_WIFI_CALIBRATION:
+ cb_parse_wifi_calibration(ptr, info);
+ break;
+ case CB_TAG_RAM_OOPS:
+ cb_parse_ramoops(ptr, info);
+ break;
+ case CB_TAG_SPI_FLASH:
+ cb_parse_spi_flash(ptr, info);
+ break;
+ case CB_TAG_MTC:
+ cb_parse_mtc(ptr, info);
+ break;
+ case CB_TAG_BOOT_MEDIA_PARAMS:
+ cb_parse_boot_media_params(ptr, info);
+ break;
+ case CB_TAG_TSC_INFO:
+ cb_parse_tsc_info(ptr, info);
+ break;
+ case CB_TAG_VPD:
+ cb_parse_vpd(ptr, info);
+ break;
+ case CB_TAG_X86_ROM_MTRR:
+ cb_parse_x86_rom_var_mtrr(rec, info);
+ break;
+ case CB_TAG_MRC_CACHE:
+ cb_parse_mrc_cache(rec, info);
+ break;
+ default:
+ cb_parse_unhandled(rec->tag, ptr);
+ break;
+ }
+
+ ptr += rec->size;
+ }
+
+ return 1;
+}
+
+/* == Architecture specific == */
+/* This is the x86 specific stuff */
+
+int get_coreboot_info(struct sysinfo_t *info)
+{
+ long addr;
+ int ret;
+
+ addr = locate_coreboot_table();
+ if (addr < 0)
+ return addr;
+ ret = cb_parse_header((void *)addr, 0x1000, info);
+ if (!ret)
+ return -ENOENT;
+ gd->arch.coreboot_table = addr;
+ gd->flags |= GD_FLG_SKIP_LL_INIT;
+
+ return 0;
+}
+
+const struct sysinfo_t *cb_get_sysinfo(void)
+{
+ if (!ll_boot_init())
+ return &lib_sysinfo;
+
+ return NULL;
+}
diff --git a/roms/u-boot/arch/x86/lib/coreboot_table.c b/roms/u-boot/arch/x86/lib/coreboot_table.c
new file mode 100644
index 000000000..6eab0452f
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/coreboot_table.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <vbe.h>
+#include <acpi/acpi_s3.h>
+#include <asm/coreboot_tables.h>
+#include <asm/e820.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int high_table_reserve(void)
+{
+ /* adjust stack pointer to reserve space for configuration tables */
+ gd->arch.high_table_limit = gd->start_addr_sp;
+ gd->start_addr_sp -= CONFIG_HIGH_TABLE_SIZE;
+ gd->arch.high_table_ptr = gd->start_addr_sp;
+
+ /* clear the memory */
+ if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) &&
+ gd->arch.prev_sleep_state != ACPI_S3) {
+ memset((void *)gd->arch.high_table_ptr, 0,
+ CONFIG_HIGH_TABLE_SIZE);
+ }
+
+ gd->start_addr_sp &= ~0xf;
+
+ return 0;
+}
+
+void *high_table_malloc(size_t bytes)
+{
+ u32 new_ptr;
+ void *ptr;
+
+ new_ptr = gd->arch.high_table_ptr + bytes;
+ if (new_ptr >= gd->arch.high_table_limit)
+ return NULL;
+ ptr = (void *)gd->arch.high_table_ptr;
+ gd->arch.high_table_ptr = new_ptr;
+
+ return ptr;
+}
+
+/**
+ * cb_table_init() - initialize a coreboot table header
+ *
+ * This fills in the coreboot table header signature and the header bytes.
+ * Other fields are set to zero.
+ *
+ * @cbh: coreboot table header address
+ */
+static void cb_table_init(struct cb_header *cbh)
+{
+ memset(cbh, 0, sizeof(struct cb_header));
+ memcpy(cbh->signature, "LBIO", 4);
+ cbh->header_bytes = sizeof(struct cb_header);
+}
+
+/**
+ * cb_table_add_entry() - add a coreboot table entry
+ *
+ * This increases the coreboot table entry size with added table entry length
+ * and increases entry count by 1.
+ *
+ * @cbh: coreboot table header address
+ * @cbr: to be added table entry address
+ * @return: pointer to next table entry address
+ */
+static u32 cb_table_add_entry(struct cb_header *cbh, struct cb_record *cbr)
+{
+ cbh->table_bytes += cbr->size;
+ cbh->table_entries++;
+
+ return (u32)cbr + cbr->size;
+}
+
+/**
+ * cb_table_finalize() - finalize the coreboot table
+ *
+ * This calculates the checksum for all coreboot table entries as well as
+ * the checksum for the coreboot header itself.
+ *
+ * @cbh: coreboot table header address
+ */
+static void cb_table_finalize(struct cb_header *cbh)
+{
+ struct cb_record *cbr = (struct cb_record *)(cbh + 1);
+
+ cbh->table_checksum = compute_ip_checksum(cbr, cbh->table_bytes);
+ cbh->header_checksum = compute_ip_checksum(cbh, cbh->header_bytes);
+}
+
+void write_coreboot_table(u32 addr, struct memory_area *cfg_tables)
+{
+ struct cb_header *cbh = (struct cb_header *)addr;
+ struct cb_record *cbr;
+ struct cb_memory *mem;
+ struct cb_memory_range *map;
+ struct e820_entry e820[32];
+ struct cb_framebuffer *fb;
+ struct vesa_mode_info *vesa;
+ int i, num;
+
+ cb_table_init(cbh);
+ cbr = (struct cb_record *)(cbh + 1);
+
+ /*
+ * Two type of coreboot table entries are generated by us.
+ * They are 'struct cb_memory' and 'struct cb_framebuffer'.
+ */
+
+ /* populate memory map table */
+ mem = (struct cb_memory *)cbr;
+ mem->tag = CB_TAG_MEMORY;
+ map = mem->map;
+
+ /* first install e820 defined memory maps */
+ num = install_e820_map(ARRAY_SIZE(e820), e820);
+ for (i = 0; i < num; i++) {
+ map->start.lo = e820[i].addr & 0xffffffff;
+ map->start.hi = e820[i].addr >> 32;
+ map->size.lo = e820[i].size & 0xffffffff;
+ map->size.hi = e820[i].size >> 32;
+ map->type = e820[i].type;
+ map++;
+ }
+
+ /* then install all configuration tables */
+ while (cfg_tables->size) {
+ map->start.lo = cfg_tables->start & 0xffffffff;
+ map->start.hi = cfg_tables->start >> 32;
+ map->size.lo = cfg_tables->size & 0xffffffff;
+ map->size.hi = cfg_tables->size >> 32;
+ map->type = CB_MEM_TABLE;
+ map++;
+ num++;
+ cfg_tables++;
+ }
+ mem->size = num * sizeof(struct cb_memory_range) +
+ sizeof(struct cb_record);
+ cbr = (struct cb_record *)cb_table_add_entry(cbh, cbr);
+
+ /* populate framebuffer table if we have sane vesa info */
+ vesa = &mode_info.vesa;
+ if (vesa->x_resolution && vesa->y_resolution) {
+ fb = (struct cb_framebuffer *)cbr;
+ fb->tag = CB_TAG_FRAMEBUFFER;
+ fb->size = sizeof(struct cb_framebuffer);
+
+ fb->x_resolution = vesa->x_resolution;
+ fb->y_resolution = vesa->y_resolution;
+ fb->bits_per_pixel = vesa->bits_per_pixel;
+ fb->bytes_per_line = vesa->bytes_per_scanline;
+ fb->physical_address = vesa->phys_base_ptr;
+ fb->red_mask_size = vesa->red_mask_size;
+ fb->red_mask_pos = vesa->red_mask_pos;
+ fb->green_mask_size = vesa->green_mask_size;
+ fb->green_mask_pos = vesa->green_mask_pos;
+ fb->blue_mask_size = vesa->blue_mask_size;
+ fb->blue_mask_pos = vesa->blue_mask_pos;
+ fb->reserved_mask_size = vesa->reserved_mask_size;
+ fb->reserved_mask_pos = vesa->reserved_mask_pos;
+
+ cbr = (struct cb_record *)cb_table_add_entry(cbh, cbr);
+ }
+
+ cb_table_finalize(cbh);
+}
diff --git a/roms/u-boot/arch/x86/lib/crt0_ia32_efi.S b/roms/u-boot/arch/x86/lib/crt0_ia32_efi.S
new file mode 100644
index 000000000..c0a4853ea
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/crt0_ia32_efi.S
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * crt0-efi-ia32.S - x86 EFI startup code.
+ *
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ * All rights reserved.
+ */
+
+ .text
+ .align 4
+
+ .globl _start
+_start:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl 12(%ebp) # copy "image" argument
+ pushl 8(%ebp) # copy "systab" argument
+
+ call 0f
+0: popl %eax
+ movl %eax,%ebx
+
+ addl $image_base-0b,%eax # %eax = ldbase
+ addl $_DYNAMIC-0b,%ebx # %ebx = _DYNAMIC
+
+ pushl %ebx # pass _DYNAMIC as second argument
+ pushl %eax # pass ldbase as first argument
+ call _relocate
+ popl %ebx
+ popl %ebx
+ testl %eax,%eax
+ jne .exit
+ call efi_main # call app with "image" and "systab" argument
+
+.exit: leave
+ ret
+
+ /*
+ * hand-craft a dummy .reloc section so EFI knows it's a relocatable
+ * executable:
+ */
+ .data
+dummy: .long 0
+
+#define IMAGE_REL_ABSOLUTE 0
+ .section .reloc
+ .long dummy /* Page RVA */
+ .long 10 /* Block Size (2*4+2) */
+ .word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */
diff --git a/roms/u-boot/arch/x86/lib/crt0_x86_64_efi.S b/roms/u-boot/arch/x86/lib/crt0_x86_64_efi.S
new file mode 100644
index 000000000..47ed5af97
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/crt0_x86_64_efi.S
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * crt0-efi-x86_64.S - x86_64 EFI startup code.
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ * Copyright (C) 2005 Intel Corporation
+ * Contributed by Fenghua Yu <fenghua.yu@intel.com>.
+ *
+ * All rights reserved.
+ */
+ .text
+ .align 4
+
+ .globl _start
+_start:
+ subq $8, %rsp
+
+ pushq %rcx
+ pushq %rdx
+
+ lea image_base(%rip), %rcx
+ lea _DYNAMIC(%rip), %rdx
+
+ call _relocate
+
+ popq %rdx
+ popq %rcx
+
+ testq %rax, %rax
+ jnz .exit
+
+ call efi_main
+.exit:
+ addq $8, %rsp
+
+ ret
+
+ /*
+ * hand-craft a dummy .reloc section so EFI knows it's a relocatable
+ * executable:
+ */
+ .data
+dummy: .long 0
+
+#define IMAGE_REL_ABSOLUTE 0
+ .section .reloc, "a"
+label1:
+ .long dummy-label1 /* Page RVA */
+ .long 10 /* Block Size (2*4+2) */
+ .word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */
diff --git a/roms/u-boot/arch/x86/lib/div64.c b/roms/u-boot/arch/x86/lib/div64.c
new file mode 100644
index 000000000..2bea205f6
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/div64.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * This file is copied from the coreboot repository as part of
+ * the libpayload project:
+ *
+ * Copyright 2014 Google Inc.
+ */
+
+#include <common.h>
+
+union overlay64 {
+ u64 longw;
+ struct {
+ u32 lower;
+ u32 higher;
+ } words;
+};
+
+u64 __ashldi3(u64 num, unsigned int shift)
+{
+ union overlay64 output;
+
+ output.longw = num;
+ if (shift >= 32) {
+ output.words.higher = output.words.lower << (shift - 32);
+ output.words.lower = 0;
+ } else {
+ if (!shift)
+ return num;
+ output.words.higher = (output.words.higher << shift) |
+ (output.words.lower >> (32 - shift));
+ output.words.lower = output.words.lower << shift;
+ }
+ return output.longw;
+}
+
+u64 __lshrdi3(u64 num, unsigned int shift)
+{
+ union overlay64 output;
+
+ output.longw = num;
+ if (shift >= 32) {
+ output.words.lower = output.words.higher >> (shift - 32);
+ output.words.higher = 0;
+ } else {
+ if (!shift)
+ return num;
+ output.words.lower = output.words.lower >> shift |
+ (output.words.higher << (32 - shift));
+ output.words.higher = output.words.higher >> shift;
+ }
+ return output.longw;
+}
+
+#define MAX_32BIT_UINT ((((u64)1) << 32) - 1)
+
+static u64 _64bit_divide(u64 dividend, u64 divider, u64 *rem_p)
+{
+ u64 result = 0;
+
+ /*
+ * If divider is zero - let the rest of the system care about the
+ * exception.
+ */
+ if (!divider)
+ return 1 / (u32)divider;
+
+ /* As an optimization, let's not use 64 bit division unless we must. */
+ if (dividend <= MAX_32BIT_UINT) {
+ if (divider > MAX_32BIT_UINT) {
+ result = 0;
+ if (rem_p)
+ *rem_p = divider;
+ } else {
+ result = (u32)dividend / (u32)divider;
+ if (rem_p)
+ *rem_p = (u32)dividend % (u32)divider;
+ }
+ return result;
+ }
+
+ while (divider <= dividend) {
+ u64 locald = divider;
+ u64 limit = __lshrdi3(dividend, 1);
+ int shifts = 0;
+
+ while (locald <= limit) {
+ shifts++;
+ locald = locald + locald;
+ }
+ result |= __ashldi3(1, shifts);
+ dividend -= locald;
+ }
+
+ if (rem_p)
+ *rem_p = dividend;
+
+ return result;
+}
+
+u64 __udivdi3(u64 num, u64 den)
+{
+ return _64bit_divide(num, den, NULL);
+}
+
+u64 __umoddi3(u64 num, u64 den)
+{
+ u64 v = 0;
+
+ _64bit_divide(num, den, &v);
+ return v;
+}
diff --git a/roms/u-boot/arch/x86/lib/e820.c b/roms/u-boot/arch/x86/lib/e820.c
new file mode 100644
index 000000000..12fcff123
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/e820.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <asm/e820.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Install a default e820 table with 4 entries as follows:
+ *
+ * 0x000000-0x0a0000 Useable RAM
+ * 0x0a0000-0x100000 Reserved for ISA
+ * 0x100000-gd->ram_size Useable RAM
+ * CONFIG_PCIE_ECAM_BASE PCIe ECAM
+ */
+__weak unsigned int install_e820_map(unsigned int max_entries,
+ struct e820_entry *entries)
+{
+ entries[0].addr = 0;
+ entries[0].size = ISA_START_ADDRESS;
+ entries[0].type = E820_RAM;
+ entries[1].addr = ISA_START_ADDRESS;
+ entries[1].size = ISA_END_ADDRESS - ISA_START_ADDRESS;
+ entries[1].type = E820_RESERVED;
+ entries[2].addr = ISA_END_ADDRESS;
+ entries[2].size = gd->ram_size - ISA_END_ADDRESS;
+ entries[2].type = E820_RAM;
+ entries[3].addr = CONFIG_PCIE_ECAM_BASE;
+ entries[3].size = CONFIG_PCIE_ECAM_SIZE;
+ entries[3].type = E820_RESERVED;
+
+ return 4;
+}
+
+#if CONFIG_IS_ENABLED(EFI_LOADER)
+void efi_add_known_memory(void)
+{
+ struct e820_entry e820[E820MAX];
+ unsigned int i, num;
+ u64 start, ram_top;
+ int type;
+
+ num = install_e820_map(ARRAY_SIZE(e820), e820);
+
+ ram_top = (u64)gd->ram_top & ~EFI_PAGE_MASK;
+ if (!ram_top)
+ ram_top = 0x100000000ULL;
+
+ for (i = 0; i < num; ++i) {
+ start = e820[i].addr;
+
+ switch (e820[i].type) {
+ case E820_RAM:
+ type = EFI_CONVENTIONAL_MEMORY;
+ break;
+ case E820_RESERVED:
+ type = EFI_RESERVED_MEMORY_TYPE;
+ break;
+ case E820_ACPI:
+ type = EFI_ACPI_RECLAIM_MEMORY;
+ break;
+ case E820_NVS:
+ type = EFI_ACPI_MEMORY_NVS;
+ break;
+ case E820_UNUSABLE:
+ default:
+ type = EFI_UNUSABLE_MEMORY;
+ break;
+ }
+
+ if (type == EFI_CONVENTIONAL_MEMORY) {
+ efi_add_conventional_memory_map(start,
+ start + e820[i].size,
+ ram_top);
+ } else {
+ efi_add_memory_map(start, e820[i].size, type);
+ }
+ }
+}
+#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
diff --git a/roms/u-boot/arch/x86/lib/early_cmos.c b/roms/u-boot/arch/x86/lib/early_cmos.c
new file mode 100644
index 000000000..f7b3bb2a8
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/early_cmos.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+/*
+ * This library provides CMOS (inside RTC SRAM) access routines at a very
+ * early stage when driver model is not available yet. Only read access is
+ * provided. The 16-bit/32-bit read are compatible with driver model RTC
+ * uclass write ops, that data is stored in little-endian mode.
+ */
+
+#include <common.h>
+#include <asm/early_cmos.h>
+#include <asm/io.h>
+
+u8 cmos_read8(u8 addr)
+{
+ outb(addr, CMOS_IO_PORT);
+
+ return inb(CMOS_IO_PORT + 1);
+}
+
+u16 cmos_read16(u8 addr)
+{
+ u16 value = 0;
+ u16 data;
+ int i;
+
+ for (i = 0; i < sizeof(value); i++) {
+ data = cmos_read8(addr + i);
+ value |= data << (i << 3);
+ }
+
+ return value;
+}
+
+u32 cmos_read32(u8 addr)
+{
+ u32 value = 0;
+ u32 data;
+ int i;
+
+ for (i = 0; i < sizeof(value); i++) {
+ data = cmos_read8(addr + i);
+ value |= data << (i << 3);
+ }
+
+ return value;
+}
diff --git a/roms/u-boot/arch/x86/lib/elf_ia32_efi.lds b/roms/u-boot/arch/x86/lib/elf_ia32_efi.lds
new file mode 100644
index 000000000..aad61e7f8
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/elf_ia32_efi.lds
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * U-Boot EFI linker script
+ *
+ * Modified from usr/lib32/elf_ia32_efi.lds in gnu-efi
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+ image_base = .;
+ .hash : { *(.hash) } /* this MUST come first, EFI expects it */
+ . = ALIGN(4096);
+ .text :
+ {
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ }
+ . = ALIGN(4096);
+ .sdata :
+ {
+ *(.got.plt)
+ *(.got)
+ *(.srodata)
+ *(.sdata)
+ *(.sbss)
+ *(.scommon)
+ }
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.data)
+ *(.data1)
+ *(.data.*)
+ *(.sdata)
+ *(.got.plt)
+ *(.got)
+ /*
+ * the EFI loader doesn't seem to like a .bss section, so we
+ * stick it all into .data:
+ */
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss*)
+ *(COMMON)
+
+ /* U-Boot lists and device tree */
+ . = ALIGN(8);
+ *(SORT(.u_boot_list*));
+ . = ALIGN(8);
+ *(.dtb*);
+ }
+
+ . = ALIGN(4096);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(4096);
+ .rel :
+ {
+ *(.rel.data)
+ *(.rel.data.*)
+ *(.rel.got)
+ *(.rel.stab)
+ *(.data.rel.ro.local)
+ *(.data.rel.local)
+ *(.data.rel.ro)
+ *(.data.rel*)
+ *(.rel.u_boot_list*)
+ }
+ . = ALIGN(4096);
+ .reloc : /* This is the PECOFF .reloc section! */
+ {
+ *(.reloc)
+ }
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+ . = ALIGN(4096);
+ /DISCARD/ :
+ {
+ *(.rel.reloc)
+ *(.eh_frame)
+ *(.note.GNU-stack)
+ }
+ .comment 0 : { *(.comment) }
+}
diff --git a/roms/u-boot/arch/x86/lib/elf_x86_64_efi.lds b/roms/u-boot/arch/x86/lib/elf_x86_64_efi.lds
new file mode 100644
index 000000000..b436429b3
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/elf_x86_64_efi.lds
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * U-Boot EFI linker script
+ *
+ * Modified from usr/lib32/elf_x86_64_efi.lds in gnu-efi
+ */
+
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+ image_base = .;
+ .hash : { *(.hash) } /* this MUST come first, EFI expects it */
+ . = ALIGN(4096);
+ .eh_frame : {
+ *(.eh_frame)
+ }
+
+ . = ALIGN(4096);
+
+ .text : {
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ }
+
+ . = ALIGN(4096);
+
+ .reloc : {
+ *(.reloc)
+ }
+
+ . = ALIGN(4096);
+
+ .data : {
+ *(.rodata*)
+ *(.got.plt)
+ *(.got)
+ *(.data*)
+ *(.sdata)
+ /* the EFI loader doesn't seem to like a .bss section, so we stick
+ * it all into .data: */
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss*)
+ *(COMMON)
+ *(.rel.local)
+
+ /* U-Boot lists and device tree */
+ . = ALIGN(8);
+ *(SORT(.u_boot_list*));
+ . = ALIGN(8);
+ *(.dtb*);
+ }
+
+ . = ALIGN(4096);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(4096);
+
+ .rela : {
+ *(.rela.data*)
+ *(.rela.got)
+ *(.rela.stab)
+ }
+
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+ . = ALIGN(4096);
+ .ignored.reloc : {
+ *(.rela.reloc)
+ *(.eh_frame)
+ *(.note.GNU-stack)
+ }
+
+ .comment 0 : { *(.comment) }
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp/Makefile b/roms/u-boot/arch/x86/lib/fsp/Makefile
new file mode 100644
index 000000000..da6c0a886
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-y += fsp_common.o
+obj-y += fsp_dram.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_VIDEO_FSP) += fsp_graphics.o
+endif
+obj-y += fsp_support.o
diff --git a/roms/u-boot/arch/x86/lib/fsp/fsp_common.c b/roms/u-boot/arch/x86/lib/fsp/fsp_common.c
new file mode 100644
index 000000000..6365b0a50
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp/fsp_common.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <errno.h>
+#include <init.h>
+#include <log.h>
+#include <rtc.h>
+#include <acpi/acpi_s3.h>
+#include <asm/cmos_layout.h>
+#include <asm/early_cmos.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/mrccache.h>
+#include <asm/post.h>
+#include <asm/processor.h>
+#include <asm/fsp/fsp_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu(void)
+{
+ return 0;
+}
+
+int print_cpuinfo(void)
+{
+ post_code(POST_CPU_INFO);
+ return default_print_cpuinfo();
+}
+
+int fsp_init_phase_pci(void)
+{
+ u32 status;
+
+ /* call into FspNotify */
+ debug("Calling into FSP (notify phase INIT_PHASE_PCI): ");
+ status = fsp_notify(NULL, INIT_PHASE_PCI);
+ if (status)
+ debug("fail, error code %x\n", status);
+ else
+ debug("OK\n");
+
+ return status ? -EPERM : 0;
+}
+
+void board_final_init(void)
+{
+ u32 status;
+
+ /* call into FspNotify */
+ debug("Calling into FSP (notify phase INIT_PHASE_BOOT): ");
+ status = fsp_notify(NULL, INIT_PHASE_BOOT);
+ if (status)
+ debug("fail, error code %x\n", status);
+ else
+ debug("OK\n");
+}
+
+void board_final_cleanup(void)
+{
+ u32 status;
+
+ /* TODO(sjg@chromium.org): This causes Linux to crash */
+ return;
+
+ /* call into FspNotify */
+ debug("Calling into FSP (notify phase INIT_PHASE_END_FIRMWARE): ");
+ status = fsp_notify(NULL, INIT_PHASE_END_FIRMWARE);
+ if (status)
+ debug("fail, error code %x\n", status);
+ else
+ debug("OK\n");
+}
+
+int fsp_save_s3_stack(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ if (gd->arch.prev_sleep_state == ACPI_S3)
+ return 0;
+
+ ret = uclass_get_device(UCLASS_RTC, 0, &dev);
+ if (ret) {
+ debug("Cannot find RTC: err=%d\n", ret);
+ return -ENODEV;
+ }
+
+ /* Save the stack address to CMOS */
+ ret = rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp);
+ if (ret) {
+ debug("Save stack address to CMOS: err=%d\n", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp/fsp_dram.c b/roms/u-boot/arch/x86/lib/fsp/fsp_dram.c
new file mode 100644
index 000000000..8ad9aeeda
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp/fsp_dram.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <handoff.h>
+#include <init.h>
+#include <log.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/e820.h>
+#include <asm/global_data.h>
+#include <asm/mrccache.h>
+#include <asm/mtrr.h>
+#include <asm/post.h>
+#include <dm/ofnode.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int fsp_scan_for_ram_size(void)
+{
+ phys_size_t ram_size = 0;
+ const struct hob_header *hdr;
+ struct hob_res_desc *res_desc;
+
+ hdr = gd->arch.hob_list;
+ while (!end_of_hob(hdr)) {
+ if (hdr->type == HOB_TYPE_RES_DESC) {
+ res_desc = (struct hob_res_desc *)hdr;
+ if (res_desc->type == RES_SYS_MEM ||
+ res_desc->type == RES_MEM_RESERVED)
+ ram_size += res_desc->len;
+ }
+ hdr = get_next_hob(hdr);
+ }
+
+ gd->ram_size = ram_size;
+ post_code(POST_DRAM);
+
+ return 0;
+};
+
+int dram_init_banksize(void)
+{
+ efi_guid_t fsp = FSP_HOB_RESOURCE_OWNER_FSP_GUID;
+ const struct hob_header *hdr;
+ struct hob_res_desc *res_desc;
+ phys_addr_t mtrr_top;
+ phys_addr_t low_end;
+ uint bank;
+
+ if (!ll_boot_init()) {
+ gd->bd->bi_dram[0].start = 0;
+ gd->bd->bi_dram[0].size = gd->ram_size;
+
+ mtrr_add_request(MTRR_TYPE_WRBACK, 0, gd->ram_size);
+ return 0;
+ }
+
+ low_end = 0; /* top of low memory usable by U-Boot */
+ mtrr_top = 0; /* top of low memory (even if reserved) */
+ for (bank = 1, hdr = gd->arch.hob_list;
+ bank < CONFIG_NR_DRAM_BANKS && !end_of_hob(hdr);
+ hdr = get_next_hob(hdr)) {
+ if (hdr->type != HOB_TYPE_RES_DESC)
+ continue;
+ res_desc = (struct hob_res_desc *)hdr;
+ if (!guidcmp(&res_desc->owner, &fsp))
+ low_end = res_desc->phys_start;
+ if (res_desc->type != RES_SYS_MEM &&
+ res_desc->type != RES_MEM_RESERVED)
+ continue;
+ if (res_desc->phys_start < (1ULL << 32)) {
+ mtrr_top = max(mtrr_top,
+ res_desc->phys_start + res_desc->len);
+ } else {
+ gd->bd->bi_dram[bank].start = res_desc->phys_start;
+ gd->bd->bi_dram[bank].size = res_desc->len;
+ mtrr_add_request(MTRR_TYPE_WRBACK, res_desc->phys_start,
+ res_desc->len);
+ log_debug("ram %llx %llx\n",
+ gd->bd->bi_dram[bank].start,
+ gd->bd->bi_dram[bank].size);
+ }
+ }
+
+ /* Add the memory below 4GB */
+ gd->bd->bi_dram[0].start = 0;
+ gd->bd->bi_dram[0].size = low_end;
+
+ /*
+ * Set up an MTRR to the top of low, reserved memory. This is necessary
+ * for graphics to run at full speed in U-Boot.
+ */
+ mtrr_add_request(MTRR_TYPE_WRBACK, 0, mtrr_top);
+
+ return 0;
+}
+
+unsigned int install_e820_map(unsigned int max_entries,
+ struct e820_entry *entries)
+{
+ unsigned int num_entries = 0;
+ const struct hob_header *hdr;
+ struct hob_res_desc *res_desc;
+ const fdt64_t *prop;
+ int size;
+
+ hdr = gd->arch.hob_list;
+
+ while (!end_of_hob(hdr)) {
+ if (hdr->type == HOB_TYPE_RES_DESC) {
+ res_desc = (struct hob_res_desc *)hdr;
+ entries[num_entries].addr = res_desc->phys_start;
+ entries[num_entries].size = res_desc->len;
+
+ if (res_desc->type == RES_SYS_MEM)
+ entries[num_entries].type = E820_RAM;
+ else if (res_desc->type == RES_MEM_RESERVED)
+ entries[num_entries].type = E820_RESERVED;
+
+ num_entries++;
+ }
+ hdr = get_next_hob(hdr);
+ }
+
+ /* Mark PCIe ECAM address range as reserved */
+ entries[num_entries].addr = CONFIG_PCIE_ECAM_BASE;
+ entries[num_entries].size = CONFIG_PCIE_ECAM_SIZE;
+ entries[num_entries].type = E820_RESERVED;
+ num_entries++;
+
+ if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)) {
+ ulong stack_size;
+
+ stack_size = CONFIG_IS_ENABLED(HAVE_ACPI_RESUME,
+ (CONFIG_STACK_SIZE_RESUME), (0));
+ /*
+ * Everything between U-Boot's stack and ram top needs to be
+ * reserved in order for ACPI S3 resume to work.
+ */
+ entries[num_entries].addr = gd->start_addr_sp - stack_size;
+ entries[num_entries].size = gd->ram_top - gd->start_addr_sp +
+ stack_size;
+ entries[num_entries].type = E820_RESERVED;
+ num_entries++;
+ }
+
+ prop = ofnode_read_chosen_prop("e820-entries", &size);
+ if (prop) {
+ int count = size / (sizeof(u64) * 3);
+ int i;
+
+ if (num_entries + count >= max_entries)
+ return -ENOSPC;
+ for (i = 0; i < count; i++, num_entries++, prop += 3) {
+ entries[num_entries].addr = fdt64_to_cpu(prop[0]);
+ entries[num_entries].size = fdt64_to_cpu(prop[1]);
+ entries[num_entries].type = fdt64_to_cpu(prop[2]);
+ }
+ }
+
+ return num_entries;
+}
+
+#if CONFIG_IS_ENABLED(HANDOFF) && IS_ENABLED(CONFIG_USE_HOB)
+int handoff_arch_save(struct spl_handoff *ho)
+{
+ ho->arch.usable_ram_top = gd->bd->bi_dram[0].size;
+ ho->arch.hob_list = gd->arch.hob_list;
+
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/arch/x86/lib/fsp/fsp_graphics.c b/roms/u-boot/arch/x86/lib/fsp/fsp_graphics.c
new file mode 100644
index 000000000..02fd05c9f
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp/fsp_graphics.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_VIDEO
+
+#include <common.h>
+#include <dm.h>
+#include <init.h>
+#include <log.h>
+#include <vbe.h>
+#include <video.h>
+#include <acpi/acpi_table.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/global_data.h>
+#include <asm/intel_opregion.h>
+#include <asm/mtrr.h>
+#include <dm/acpi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pixel {
+ u8 pos;
+ u8 size;
+};
+
+static const struct fsp_framebuffer {
+ struct pixel red;
+ struct pixel green;
+ struct pixel blue;
+ struct pixel rsvd;
+} fsp_framebuffer_format_map[] = {
+ [pixel_rgbx_8bpc] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} },
+ [pixel_bgrx_8bpc] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} },
+};
+
+static int save_vesa_mode(struct vesa_mode_info *vesa)
+{
+ const struct hob_graphics_info *ginfo;
+ const struct fsp_framebuffer *fbinfo;
+
+ ginfo = fsp_get_graphics_info(gd->arch.hob_list, NULL);
+
+ /*
+ * If there is no graphics info structure, bail out and keep
+ * running on the serial console.
+ *
+ * Note: on some platforms (eg: Braswell), the FSP will not produce
+ * the graphics info HOB unless you plug some cables to the display
+ * interface (eg: HDMI) on the board.
+ */
+ if (!ginfo) {
+ debug("FSP graphics hand-off block not found\n");
+ return -ENXIO;
+ }
+
+ vesa->x_resolution = ginfo->width;
+ vesa->y_resolution = ginfo->height;
+ vesa->bits_per_pixel = 32;
+ vesa->bytes_per_scanline = ginfo->pixels_per_scanline * 4;
+ vesa->phys_base_ptr = ginfo->fb_base;
+
+ if (ginfo->pixel_format >= pixel_bitmask) {
+ debug("FSP set unknown framebuffer format: %d\n",
+ ginfo->pixel_format);
+ return -EINVAL;
+ }
+ fbinfo = &fsp_framebuffer_format_map[ginfo->pixel_format];
+ vesa->red_mask_size = fbinfo->red.size;
+ vesa->red_mask_pos = fbinfo->red.pos;
+ vesa->green_mask_size = fbinfo->green.size;
+ vesa->green_mask_pos = fbinfo->green.pos;
+ vesa->blue_mask_size = fbinfo->blue.size;
+ vesa->blue_mask_pos = fbinfo->blue.pos;
+ vesa->reserved_mask_size = fbinfo->rsvd.size;
+ vesa->reserved_mask_pos = fbinfo->rsvd.pos;
+
+ return 0;
+}
+
+static int fsp_video_probe(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct vesa_mode_info *vesa = &mode_info.vesa;
+ int ret;
+
+ if (!ll_boot_init())
+ return -ENODEV;
+
+ printf("Video: ");
+
+ /* Initialize vesa_mode_info structure */
+ ret = save_vesa_mode(vesa);
+ if (ret)
+ goto err;
+
+ /*
+ * The framebuffer base address in the FSP graphics info HOB reflects
+ * the value assigned by the FSP. After PCI enumeration the framebuffer
+ * base address may be relocated. Let's get the updated one from device.
+ *
+ * For IGD, it seems to be always on BAR2.
+ */
+ vesa->phys_base_ptr = dm_pci_read_bar32(dev, 2);
+ gd->fb_base = vesa->phys_base_ptr;
+
+ ret = vbe_setup_video_priv(vesa, uc_priv, plat);
+ if (ret)
+ goto err;
+
+ mtrr_add_request(MTRR_TYPE_WRCOMB, vesa->phys_base_ptr, 256 << 20);
+ mtrr_commit(true);
+
+ printf("%dx%dx%d @ %x\n", uc_priv->xsize, uc_priv->ysize,
+ vesa->bits_per_pixel, vesa->phys_base_ptr);
+
+ return 0;
+
+err:
+ printf("No video mode configured in FSP!\n");
+ return ret;
+}
+
+static int fsp_video_bind(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ /* Set the maximum supported resolution */
+ plat->size = 2560 * 1600 * 4;
+
+ return 0;
+}
+
+#ifdef CONFIG_INTEL_GMA_ACPI
+static int fsp_video_acpi_write_tables(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ struct igd_opregion *opregion;
+ int ret;
+
+ log_debug("ACPI: * IGD OpRegion\n");
+ opregion = (struct igd_opregion *)ctx->current;
+
+ ret = intel_gma_init_igd_opregion((struct udevice *)dev, opregion);
+ if (ret)
+ return ret;
+
+ acpi_inc_align(ctx, sizeof(struct igd_opregion));
+
+ return 0;
+}
+#endif
+
+struct acpi_ops fsp_video_acpi_ops = {
+#ifdef CONFIG_INTEL_GMA_ACPI
+ .write_tables = fsp_video_acpi_write_tables,
+#endif
+};
+
+static const struct udevice_id fsp_video_ids[] = {
+ { .compatible = "fsp-fb" },
+ { }
+};
+
+U_BOOT_DRIVER(fsp_video) = {
+ .name = "fsp_video",
+ .id = UCLASS_VIDEO,
+ .of_match = fsp_video_ids,
+ .bind = fsp_video_bind,
+ .probe = fsp_video_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+ ACPI_OPS_PTR(&fsp_video_acpi_ops)
+};
+
+static struct pci_device_id fsp_video_supported[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_DISPLAY_VGA << 8, 0xffff00) },
+ { },
+};
+
+U_BOOT_PCI_DEVICE(fsp_video, fsp_video_supported);
diff --git a/roms/u-boot/arch/x86/lib/fsp/fsp_support.c b/roms/u-boot/arch/x86/lib/fsp/fsp_support.c
new file mode 100644
index 000000000..fd4d98ef6
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp/fsp_support.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/post.h>
+
+u32 fsp_get_usable_lowmem_top(const void *hob_list)
+{
+ const struct hob_header *hdr;
+ struct hob_res_desc *res_desc;
+ phys_addr_t phys_start;
+ u32 top;
+#ifdef CONFIG_FSP_BROKEN_HOB
+ struct hob_mem_alloc *res_mem;
+ phys_addr_t mem_base = 0;
+#endif
+
+ /* Get the HOB list for processing */
+ hdr = hob_list;
+
+ /* * Collect memory ranges */
+ top = FSP_LOWMEM_BASE;
+ while (!end_of_hob(hdr)) {
+ if (hdr->type == HOB_TYPE_RES_DESC) {
+ res_desc = (struct hob_res_desc *)hdr;
+ if (res_desc->type == RES_SYS_MEM) {
+ phys_start = res_desc->phys_start;
+ /* Need memory above 1MB to be collected here */
+ if (phys_start >= FSP_LOWMEM_BASE &&
+ phys_start < (phys_addr_t)FSP_HIGHMEM_BASE)
+ top += (u32)(res_desc->len);
+ }
+ }
+
+#ifdef CONFIG_FSP_BROKEN_HOB
+ /*
+ * Find out the lowest memory base address allocated by FSP
+ * for the boot service data
+ */
+ if (hdr->type == HOB_TYPE_MEM_ALLOC) {
+ res_mem = (struct hob_mem_alloc *)hdr;
+ if (!mem_base)
+ mem_base = res_mem->mem_base;
+ if (res_mem->mem_base < mem_base)
+ mem_base = res_mem->mem_base;
+ }
+#endif
+
+ hdr = get_next_hob(hdr);
+ }
+
+#ifdef CONFIG_FSP_BROKEN_HOB
+ /*
+ * Check whether the memory top address is below the FSP HOB list.
+ * If not, use the lowest memory base address allocated by FSP as
+ * the memory top address. This is to prevent U-Boot relocation
+ * overwrites the important boot service data which is used by FSP,
+ * otherwise the subsequent call to fsp_notify() will fail.
+ */
+ if (top > (u32)hob_list) {
+ debug("Adjust memory top address due to a buggy FSP\n");
+ top = (u32)mem_base;
+ }
+#endif
+
+ return top;
+}
+
+u64 fsp_get_usable_highmem_top(const void *hob_list)
+{
+ const struct hob_header *hdr;
+ struct hob_res_desc *res_desc;
+ phys_addr_t phys_start;
+ u64 top;
+
+ /* Get the HOB list for processing */
+ hdr = hob_list;
+
+ /* Collect memory ranges */
+ top = FSP_HIGHMEM_BASE;
+ while (!end_of_hob(hdr)) {
+ if (hdr->type == HOB_TYPE_RES_DESC) {
+ res_desc = (struct hob_res_desc *)hdr;
+ if (res_desc->type == RES_SYS_MEM) {
+ phys_start = res_desc->phys_start;
+ /* Need memory above 4GB to be collected here */
+ if (phys_start >= (phys_addr_t)FSP_HIGHMEM_BASE)
+ top += (u32)(res_desc->len);
+ }
+ }
+ hdr = get_next_hob(hdr);
+ }
+
+ return top;
+}
+
+u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len,
+ const efi_guid_t *guid)
+{
+ const struct hob_header *hdr;
+ struct hob_res_desc *res_desc;
+
+ /* Get the HOB list for processing */
+ hdr = hob_list;
+
+ /* Collect memory ranges */
+ while (!end_of_hob(hdr)) {
+ if (hdr->type == HOB_TYPE_RES_DESC) {
+ res_desc = (struct hob_res_desc *)hdr;
+ if (res_desc->type == RES_MEM_RESERVED) {
+ if (!guidcmp(&res_desc->owner, guid)) {
+ if (len)
+ *len = (u32)(res_desc->len);
+
+ return (u64)(res_desc->phys_start);
+ }
+ }
+ }
+ hdr = get_next_hob(hdr);
+ }
+
+ return 0;
+}
+
+u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len)
+{
+ const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID;
+ u64 length;
+ u32 base;
+
+ base = (u32)fsp_get_reserved_mem_from_guid(hob_list,
+ &length, &guid);
+ if (len && base)
+ *len = (u32)length;
+
+ return base;
+}
+
+u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len)
+{
+ const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID;
+ u64 length;
+ u32 base;
+
+ base = (u32)fsp_get_reserved_mem_from_guid(hob_list,
+ &length, &guid);
+ if (len && base)
+ *len = (u32)length;
+
+ return base;
+}
+
+void *fsp_get_nvs_data(const void *hob_list, u32 *len)
+{
+ const efi_guid_t guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID;
+
+ return hob_get_guid_hob_data(hob_list, len, &guid);
+}
+
+void *fsp_get_var_nvs_data(const void *hob_list, u32 *len)
+{
+ const efi_guid_t guid = FSP_VARIABLE_NV_DATA_HOB_GUID;
+
+ return hob_get_guid_hob_data(hob_list, len, &guid);
+}
+
+void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len)
+{
+ const efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID;
+
+ return hob_get_guid_hob_data(hob_list, len, &guid);
+}
+
+void *fsp_get_graphics_info(const void *hob_list, u32 *len)
+{
+ const efi_guid_t guid = FSP_GRAPHICS_INFO_HOB_GUID;
+
+ return hob_get_guid_hob_data(hob_list, len, &guid);
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp1/Makefile b/roms/u-boot/arch/x86/lib/fsp1/Makefile
new file mode 100644
index 000000000..1cf5e5419
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp1/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2015 Google, Inc
+
+obj-y += fsp_car.o
+obj-y += fsp_common.o
+obj-y += fsp_dram.o
+obj-y += fsp_support.o
diff --git a/roms/u-boot/arch/x86/lib/fsp1/fsp_car.S b/roms/u-boot/arch/x86/lib/fsp1/fsp_car.S
new file mode 100644
index 000000000..a64a65343
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp1/fsp_car.S
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <config.h>
+#include <asm/post.h>
+
+.globl car_init
+car_init:
+ /*
+ * Note: ebp holds the BIST value (built-in self test) so far, but ebp
+ * will be destroyed through the FSP call, thus we have to test the
+ * BIST value here before we call into FSP.
+ */
+ test %ebp, %ebp
+ jz car_init_start
+ post_code(POST_BIST_FAILURE)
+ jmp die
+
+car_init_start:
+ post_code(POST_CAR_START)
+ lea fsp_find_header_romstack, %esp
+ jmp fsp_find_header
+
+fsp_find_header_ret:
+ /* EAX points to FSP_INFO_HEADER */
+ mov %eax, %ebp
+
+ /* sanity test */
+ cmp $CONFIG_FSP_ADDR, %eax
+ jb die
+
+ /* calculate TempRamInitEntry address */
+ mov 0x30(%ebp), %eax
+ add 0x1c(%ebp), %eax
+
+ /* call FSP TempRamInitEntry to setup temporary stack */
+ lea temp_ram_init_romstack, %esp
+ jmp *%eax
+
+temp_ram_init_ret:
+ addl $4, %esp
+ cmp $0, %eax
+ jnz car_init_fail
+
+ post_code(POST_CAR_CPU_CACHE)
+
+ /*
+ * The FSP TempRamInit initializes the ecx and edx registers to
+ * point to a temporary but writable memory range (Cache-As-RAM).
+ * ecx: the start of this temporary memory range,
+ * edx: the end of this range.
+ */
+
+ /* stack grows down from top of CAR */
+ movl %edx, %esp
+ subl $4, %esp
+
+ xor %esi, %esi
+ jmp car_init_done
+
+.global fsp_init_done
+fsp_init_done:
+ /*
+ * We come here from fsp_continue() with eax pointing to the HOB list.
+ * Save eax to esi temporarily.
+ */
+ movl %eax, %esi
+
+car_init_done:
+ /*
+ * Re-initialize the ebp (BIST) to zero, as we already reach here
+ * which means we passed BIST testing before.
+ */
+ xorl %ebp, %ebp
+ jmp car_init_ret
+
+car_init_fail:
+ post_code(POST_CAR_FAILURE)
+
+die:
+ hlt
+ jmp die
+ hlt
+
+ /*
+ * The function call before CAR initialization is tricky. It cannot
+ * be called using the 'call' instruction but only the 'jmp' with
+ * the help of a handcrafted stack in the ROM. The stack needs to
+ * contain the function return address as well as the parameters.
+ */
+ .balign 4
+fsp_find_header_romstack:
+ .long fsp_find_header_ret
+
+ .balign 4
+temp_ram_init_romstack:
+ .long temp_ram_init_ret
+ .long temp_ram_init_params
+temp_ram_init_params:
+_dt_ucode_base_size:
+ /* These next two fields are filled in by binman */
+.globl ucode_base
+ucode_base: /* Declared in microcode.h */
+ .long 0 /* microcode base */
+.globl ucode_size
+ucode_size: /* Declared in microcode.h */
+ .long 0 /* microcode size */
+ .long CONFIG_SYS_MONITOR_BASE /* code region base */
+ .long CONFIG_SYS_MONITOR_LEN /* code region size */
diff --git a/roms/u-boot/arch/x86/lib/fsp1/fsp_common.c b/roms/u-boot/arch/x86/lib/fsp1/fsp_common.c
new file mode 100644
index 000000000..209261718
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp1/fsp_common.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <init.h>
+#include <log.h>
+#include <malloc.h>
+#include <rtc.h>
+#include <acpi/acpi_s3.h>
+#include <asm/cmos_layout.h>
+#include <asm/early_cmos.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/mrccache.h>
+#include <asm/post.h>
+#include <asm/processor.h>
+#include <asm/fsp1/fsp_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void *fsp_prepare_mrc_cache(void)
+{
+ struct mrc_data_container *cache;
+ struct mrc_region entry;
+ int ret;
+
+ ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
+ if (ret)
+ return NULL;
+
+ cache = mrccache_find_current(&entry);
+ if (!cache)
+ return NULL;
+
+ debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__,
+ cache->data, cache->data_size, cache->checksum);
+
+ return cache->data;
+}
+
+int arch_fsp_init(void)
+{
+ void *nvs;
+ int stack = CONFIG_FSP_TEMP_RAM_ADDR;
+ int boot_mode = BOOT_FULL_CONFIG;
+ int prev_sleep_state;
+
+ if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)) {
+ prev_sleep_state = chipset_prev_sleep_state();
+ gd->arch.prev_sleep_state = prev_sleep_state;
+ }
+
+ if (!gd->arch.hob_list) {
+ if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
+ nvs = fsp_prepare_mrc_cache();
+ else
+ nvs = NULL;
+
+ if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) &&
+ prev_sleep_state == ACPI_S3) {
+ if (nvs == NULL) {
+ /* If waking from S3 and no cache then */
+ debug("No MRC cache found in S3 resume path\n");
+ post_code(POST_RESUME_FAILURE);
+ /* Clear Sleep Type */
+ chipset_clear_sleep_state();
+ /* Reboot */
+ debug("Rebooting..\n");
+ outb(SYS_RST | RST_CPU, IO_PORT_RESET);
+ /* Should not reach here.. */
+ panic("Reboot System");
+ }
+
+ /*
+ * DM is not available yet at this point, hence call
+ * CMOS access library which does not depend on DM.
+ */
+ stack = cmos_read32(CMOS_FSP_STACK_ADDR);
+ boot_mode = BOOT_ON_S3_RESUME;
+ }
+
+ /*
+ * The first time we enter here, call fsp_init().
+ * Note the execution does not return to this function,
+ * instead it jumps to fsp_continue().
+ */
+ fsp_init(stack, boot_mode, nvs);
+ } else {
+ /*
+ * The second time we enter here, adjust the size of malloc()
+ * pool before relocation. Given gd->malloc_base was adjusted
+ * after the call to board_init_f_init_reserve() in arch/x86/
+ * cpu/start.S, we should fix up gd->malloc_limit here.
+ */
+ gd->malloc_limit += CONFIG_FSP_SYS_MALLOC_F_LEN;
+ }
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp1/fsp_dram.c b/roms/u-boot/arch/x86/lib/fsp1/fsp_dram.c
new file mode 100644
index 000000000..cfd9b9f48
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp1/fsp_dram.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/global_data.h>
+
+int dram_init(void)
+{
+ int ret;
+
+ /* The FSP has already set up DRAM, so grab the info we need */
+ ret = fsp_scan_for_ram_size();
+ if (ret)
+ return ret;
+
+ if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
+ struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
+
+ mrc->buf = fsp_get_nvs_data(gd->arch.hob_list, &mrc->len);
+ }
+
+ return 0;
+}
+
+/*
+ * This function looks for the highest region of memory lower than 4GB which
+ * has enough space for U-Boot where U-Boot is aligned on a page boundary.
+ * It overrides the default implementation found elsewhere which simply
+ * picks the end of ram, wherever that may be. The location of the stack,
+ * the relocation address, and how far U-Boot is moved by relocation are
+ * set in the global data structure.
+ */
+ulong board_get_usable_ram_top(ulong total_size)
+{
+ return fsp_get_usable_lowmem_top(gd->arch.hob_list);
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp1/fsp_support.c b/roms/u-boot/arch/x86/lib/fsp1/fsp_support.c
new file mode 100644
index 000000000..d84c632f1
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp1/fsp_support.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/fsp1/fsp_support.h>
+#include <asm/post.h>
+
+struct fsp_header *__attribute__((optimize("O0"))) fsp_find_header(void)
+{
+ /*
+ * This function may be called before the a stack is established,
+ * so special care must be taken. First, it cannot declare any local
+ * variable using stack. Only register variable can be used here.
+ * Secondly, some compiler version will add prolog or epilog code
+ * for the C function. If so the function call may not work before
+ * stack is ready.
+ *
+ * GCC 4.8.1 has been verified to be working for the following codes.
+ */
+ volatile register u8 *fsp asm("eax");
+
+ /* Initalize the FSP base */
+ fsp = (u8 *)CONFIG_FSP_ADDR;
+
+ /* Check the FV signature, _FVH */
+ if (((struct fv_header *)fsp)->sign == EFI_FVH_SIGNATURE) {
+ /* Go to the end of the FV header and align the address */
+ fsp += ((struct fv_header *)fsp)->ext_hdr_off;
+ fsp += ((struct fv_ext_header *)fsp)->ext_hdr_size;
+ fsp = (u8 *)(((u32)fsp + 7) & 0xFFFFFFF8);
+ } else {
+ fsp = 0;
+ }
+
+ /* Check the FFS GUID */
+ if (fsp &&
+ ((struct ffs_file_header *)fsp)->name.b[0] == FSP_GUID_BYTE0 &&
+ ((struct ffs_file_header *)fsp)->name.b[1] == FSP_GUID_BYTE1 &&
+ ((struct ffs_file_header *)fsp)->name.b[2] == FSP_GUID_BYTE2 &&
+ ((struct ffs_file_header *)fsp)->name.b[3] == FSP_GUID_BYTE3 &&
+ ((struct ffs_file_header *)fsp)->name.b[4] == FSP_GUID_BYTE4 &&
+ ((struct ffs_file_header *)fsp)->name.b[5] == FSP_GUID_BYTE5 &&
+ ((struct ffs_file_header *)fsp)->name.b[6] == FSP_GUID_BYTE6 &&
+ ((struct ffs_file_header *)fsp)->name.b[7] == FSP_GUID_BYTE7 &&
+ ((struct ffs_file_header *)fsp)->name.b[8] == FSP_GUID_BYTE8 &&
+ ((struct ffs_file_header *)fsp)->name.b[9] == FSP_GUID_BYTE9 &&
+ ((struct ffs_file_header *)fsp)->name.b[10] == FSP_GUID_BYTE10 &&
+ ((struct ffs_file_header *)fsp)->name.b[11] == FSP_GUID_BYTE11 &&
+ ((struct ffs_file_header *)fsp)->name.b[12] == FSP_GUID_BYTE12 &&
+ ((struct ffs_file_header *)fsp)->name.b[13] == FSP_GUID_BYTE13 &&
+ ((struct ffs_file_header *)fsp)->name.b[14] == FSP_GUID_BYTE14 &&
+ ((struct ffs_file_header *)fsp)->name.b[15] == FSP_GUID_BYTE15) {
+ /* Add the FFS header size to find the raw section header */
+ fsp += sizeof(struct ffs_file_header);
+ } else {
+ fsp = 0;
+ }
+
+ if (fsp &&
+ ((struct raw_section *)fsp)->type == EFI_SECTION_RAW) {
+ /* Add the raw section header size to find the FSP header */
+ fsp += sizeof(struct raw_section);
+ } else {
+ fsp = 0;
+ }
+
+ return (struct fsp_header *)fsp;
+}
+
+void fsp_continue(u32 status, void *hob_list)
+{
+ post_code(POST_MRC);
+
+ assert(status == 0);
+
+ /* The boot loader main function entry */
+ fsp_init_done(hob_list);
+}
+
+void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf)
+{
+ struct fsp_config_data config_data;
+ fsp_init_f init;
+ struct fsp_init_params params;
+ struct fspinit_rtbuf rt_buf;
+ struct fsp_header *fsp_hdr;
+ struct fsp_init_params *params_ptr;
+#ifdef CONFIG_FSP_USE_UPD
+ struct vpd_region *fsp_vpd;
+ struct upd_region *fsp_upd;
+#endif
+
+ fsp_hdr = fsp_find_header();
+ if (fsp_hdr == NULL) {
+ /* No valid FSP info header was found */
+ panic("Invalid FSP header");
+ }
+
+ config_data.common.fsp_hdr = fsp_hdr;
+ config_data.common.stack_top = stack_top;
+ config_data.common.boot_mode = boot_mode;
+
+#ifdef CONFIG_FSP_USE_UPD
+ /* Get VPD region start */
+ fsp_vpd = (struct vpd_region *)(fsp_hdr->img_base +
+ fsp_hdr->cfg_region_off);
+
+ /* Verify the VPD data region is valid */
+ assert(fsp_vpd->sign == VPD_IMAGE_ID);
+
+ fsp_upd = &config_data.fsp_upd;
+
+ /* Copy default data from Flash */
+ memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset),
+ sizeof(struct upd_region));
+
+ /* Verify the UPD data region is valid */
+ assert(fsp_upd->terminator == UPD_TERMINATOR);
+#endif
+
+ memset(&rt_buf, 0, sizeof(struct fspinit_rtbuf));
+
+ /* Override any configuration if required */
+ fsp_update_configs(&config_data, &rt_buf);
+
+ memset(&params, 0, sizeof(struct fsp_init_params));
+ params.nvs_buf = nvs_buf;
+ params.rt_buf = (struct fspinit_rtbuf *)&rt_buf;
+ params.continuation = (fsp_continuation_f)fsp_asm_continuation;
+
+ init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init);
+ params_ptr = &params;
+
+ post_code(POST_PRE_MRC);
+
+ /* Load GDT for FSP */
+ setup_fsp_gdt();
+
+ /*
+ * Use ASM code to ensure the register value in EAX & EDX
+ * will be passed into fsp_continue
+ */
+ asm volatile (
+ "pushl %0;"
+ "call *%%eax;"
+ ".global fsp_asm_continuation;"
+ "fsp_asm_continuation:;"
+ "movl 4(%%esp), %%eax;" /* status */
+ "movl 8(%%esp), %%edx;" /* hob_list */
+ "jmp fsp_continue;"
+ : : "m"(params_ptr), "a"(init)
+ );
+
+ /*
+ * Should never get here.
+ * Control will continue from fsp_continue.
+ * This line below is to prevent the compiler from optimizing
+ * structure intialization.
+ *
+ * DO NOT REMOVE!
+ */
+ init(&params);
+}
+
+u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
+{
+ fsp_notify_f notify;
+ struct fsp_notify_params params;
+ struct fsp_notify_params *params_ptr;
+ u32 status;
+
+ if (!fsp_hdr)
+ fsp_hdr = (struct fsp_header *)fsp_find_header();
+
+ if (fsp_hdr == NULL) {
+ /* No valid FSP info header */
+ panic("Invalid FSP header");
+ }
+
+ notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
+ params.phase = phase;
+ params_ptr = &params;
+
+ /*
+ * Use ASM code to ensure correct parameter is on the stack for
+ * FspNotify as U-Boot is using different ABI from FSP
+ */
+ asm volatile (
+ "pushl %1;" /* push notify phase */
+ "call *%%eax;" /* call FspNotify */
+ "addl $4, %%esp;" /* clean up the stack */
+ : "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
+ );
+
+ return status;
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp2/Makefile b/roms/u-boot/arch/x86/lib/fsp2/Makefile
new file mode 100644
index 000000000..ddbe2d0db
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp2/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Google LLC
+
+obj-y += fsp_common.o
+obj-y += fsp_dram.o
+obj-y += fsp_init.o
+obj-y += fsp_meminit.o
+obj-y += fsp_silicon_init.o
+obj-y += fsp_support.o
diff --git a/roms/u-boot/arch/x86/lib/fsp2/fsp_common.c b/roms/u-boot/arch/x86/lib/fsp2/fsp_common.c
new file mode 100644
index 000000000..f69456e43
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp2/fsp_common.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <init.h>
+
+int arch_fsp_init(void)
+{
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp2/fsp_dram.c b/roms/u-boot/arch/x86/lib/fsp2/fsp_dram.c
new file mode 100644
index 000000000..42d3892b7
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp2/fsp_dram.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <common.h>
+#include <handoff.h>
+#include <init.h>
+#include <log.h>
+#include <spl.h>
+#include <acpi/acpi_s3.h>
+#include <asm/arch/cpu.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/fsp2/fsp_api.h>
+#include <asm/fsp2/fsp_internal.h>
+#include <asm/global_data.h>
+#include <linux/sizes.h>
+
+int dram_init(void)
+{
+ int ret;
+
+ if (!ll_boot_init()) {
+ /* Use a small and safe amount of 1GB */
+ gd->ram_size = SZ_1G;
+
+ return 0;
+ }
+ if (spl_phase() == PHASE_SPL) {
+ bool s3wake = false;
+
+ s3wake = IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) &&
+ gd->arch.prev_sleep_state == ACPI_S3;
+
+ ret = fsp_memory_init(s3wake,
+ IS_ENABLED(CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH));
+ if (ret) {
+ log_debug("Memory init failed (err=%x)\n", ret);
+ return ret;
+ }
+
+ /* The FSP has already set up DRAM, so grab the info we need */
+ ret = fsp_scan_for_ram_size();
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_ENABLE_MRC_CACHE
+ gd->arch.mrc[MRC_TYPE_NORMAL].buf =
+ fsp_get_nvs_data(gd->arch.hob_list,
+ &gd->arch.mrc[MRC_TYPE_NORMAL].len);
+ gd->arch.mrc[MRC_TYPE_VAR].buf =
+ fsp_get_var_nvs_data(gd->arch.hob_list,
+ &gd->arch.mrc[MRC_TYPE_VAR].len);
+ log_debug("normal %x, var %x\n",
+ gd->arch.mrc[MRC_TYPE_NORMAL].len,
+ gd->arch.mrc[MRC_TYPE_VAR].len);
+#endif
+ } else {
+#if CONFIG_IS_ENABLED(HANDOFF)
+ struct spl_handoff *ho = gd->spl_handoff;
+
+ if (!ho) {
+ log_debug("No SPL handoff found\n");
+ return -ESTRPIPE;
+ }
+ gd->ram_size = ho->ram_size;
+ handoff_load_dram_banks(ho);
+#endif
+ ret = arch_fsps_preinit();
+ if (ret)
+ return log_msg_ret("fsp_s_preinit", ret);
+ }
+
+ return 0;
+}
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+ if (!ll_boot_init())
+ return gd->ram_size;
+
+#if CONFIG_IS_ENABLED(HANDOFF)
+ struct spl_handoff *ho = gd->spl_handoff;
+
+ log_debug("usable_ram_top = %lx\n", ho->arch.usable_ram_top);
+
+ return ho->arch.usable_ram_top;
+#endif
+
+ return gd->ram_top;
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp2/fsp_init.c b/roms/u-boot/arch/x86/lib/fsp2/fsp_init.c
new file mode 100644
index 000000000..5afdce1e0
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp2/fsp_init.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <binman.h>
+#include <binman_sym.h>
+#include <bootstage.h>
+#include <cbfs.h>
+#include <dm.h>
+#include <init.h>
+#include <log.h>
+#include <spi.h>
+#include <spl.h>
+#include <spi_flash.h>
+#include <asm/intel_pinctrl.h>
+#include <dm/uclass-internal.h>
+#include <asm/fsp2/fsp_internal.h>
+
+int arch_cpu_init_dm(void)
+{
+ struct udevice *dev;
+ ofnode node;
+ int ret;
+
+ /* Make sure pads are set up early in U-Boot */
+ if (!ll_boot_init() || spl_phase() != PHASE_BOARD_F)
+ return 0;
+
+ /* Probe all pinctrl devices to set up the pads */
+ ret = uclass_first_device_err(UCLASS_PINCTRL, &dev);
+ if (ret)
+ return log_msg_ret("no fsp pinctrl", ret);
+ node = ofnode_path("fsp");
+ if (!ofnode_valid(node))
+ return log_msg_ret("no fsp params", -EINVAL);
+ ret = pinctrl_config_pads_for_node(dev, node);
+ if (ret)
+ return log_msg_ret("pad config", ret);
+
+ return ret;
+}
+
+#if !defined(CONFIG_TPL_BUILD)
+binman_sym_declare(ulong, intel_fsp_m, image_pos);
+binman_sym_declare(ulong, intel_fsp_m, size);
+
+/**
+ * get_cbfs_fsp() - Obtain the FSP by looking up in CBFS
+ *
+ * This looks up an FSP in a CBFS. It is used mostly for testing, when booting
+ * U-Boot from a hybrid image containing coreboot as the first-stage bootloader.
+ *
+ * The typical use for this feature is when building a Chrome OS image which
+ * includes coreboot in it. By adding U-Boot into the 'COREBOOT' CBFS as well,
+ * it is possible to make coreboot chain-load U-Boot. Thus the initial stages of
+ * the SoC init can be done by coreboot and the later stages by U-Boot. This is
+ * a convenient way to start the porting work. The jump to U-Boot can then be
+ * moved progressively earlier and earlier, until U-Boot takes over all the init
+ * and you have a native port.
+ *
+ * This function looks up a CBFS at a known location and reads the FSP-M from it
+ * so that U-Boot can init the memory.
+ *
+ * This function is not used in the normal boot but is kept here for future
+ * development.
+ *
+ * @type; Type to look up (only FSP_M supported at present)
+ * @map_base: Base memory address for mapped SPI
+ * @entry: Returns an entry containing the position of the FSP image
+ */
+static int get_cbfs_fsp(enum fsp_type_t type, ulong map_base,
+ struct binman_entry *entry)
+{
+ /*
+ * Use a hard-coded position of CBFS in the ROM for now. It would be
+ * possible to read the position using the FMAP in the ROM, but since
+ * this code is only used for development, it doesn't seem worth it.
+ * Use the 'cbfstool <image> layout' command to get these values, e.g.:
+ * 'COREBOOT' (CBFS, size 1814528, offset 2117632).
+ */
+ ulong cbfs_base = 0x205000;
+ struct cbfs_priv *cbfs;
+ int ret;
+
+ ret = cbfs_init_mem(map_base + cbfs_base, CBFS_SIZE_UNKNOWN, true,
+ &cbfs);
+ if (ret)
+ return ret;
+ if (!ret) {
+ const struct cbfs_cachenode *node;
+
+ node = cbfs_find_file(cbfs, "fspm.bin");
+ if (!node)
+ return log_msg_ret("fspm node", -ENOENT);
+
+ entry->image_pos = (ulong)node->data;
+ entry->size = node->data_length;
+ }
+
+ return 0;
+}
+
+int fsp_locate_fsp(enum fsp_type_t type, struct binman_entry *entry,
+ bool use_spi_flash, struct udevice **devp,
+ struct fsp_header **hdrp, ulong *rom_offsetp)
+{
+ ulong mask = CONFIG_ROM_SIZE - 1;
+ struct udevice *dev;
+ ulong rom_offset = 0;
+ uint map_size;
+ ulong map_base;
+ uint offset;
+ int ret;
+
+ /*
+ * Find the devices but don't probe them, since we don't want to
+ * auto-config PCI before silicon init runs
+ */
+ ret = uclass_find_first_device(UCLASS_NORTHBRIDGE, &dev);
+ if (ret)
+ return log_msg_ret("Cannot get northbridge", ret);
+ if (!use_spi_flash) {
+ struct udevice *sf;
+
+ /* Just use the SPI driver to get the memory map */
+ ret = uclass_find_first_device(UCLASS_SPI_FLASH, &sf);
+ if (ret)
+ return log_msg_ret("Cannot get SPI flash", ret);
+ ret = dm_spi_get_mmap(sf, &map_base, &map_size, &offset);
+ if (ret)
+ return log_msg_ret("Could not get flash mmap", ret);
+ }
+
+ if (spl_phase() >= PHASE_BOARD_F) {
+ if (type != FSP_S)
+ return -EPROTONOSUPPORT;
+ ret = binman_entry_find("intel-fsp-s", entry);
+ if (ret)
+ return log_msg_ret("binman entry", ret);
+ if (!use_spi_flash)
+ rom_offset = (map_base & mask) - CONFIG_ROM_SIZE;
+ } else {
+ ret = -ENOENT;
+ if (false)
+ /*
+ * Support using a hybrid image build by coreboot. See
+ * the function comments for details
+ */
+ ret = get_cbfs_fsp(type, map_base, entry);
+ if (ret) {
+ ulong mask = CONFIG_ROM_SIZE - 1;
+
+ if (type != FSP_M)
+ return -EPROTONOSUPPORT;
+ entry->image_pos = binman_sym(ulong, intel_fsp_m,
+ image_pos);
+ entry->size = binman_sym(ulong, intel_fsp_m, size);
+ if (entry->image_pos != BINMAN_SYM_MISSING) {
+ ret = 0;
+ if (use_spi_flash)
+ entry->image_pos &= mask;
+ else
+ entry->image_pos += (map_base & mask);
+ } else {
+ ret = -ENOENT;
+ }
+ }
+ }
+ if (ret)
+ return log_msg_ret("Cannot find FSP", ret);
+ entry->image_pos += rom_offset;
+
+ /*
+ * Account for the time taken to read memory-mapped SPI flash since in
+ * this case we don't use the SPI driver and BOOTSTAGE_ID_ACCUM_SPI.
+ */
+ if (!use_spi_flash)
+ bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi");
+ ret = fsp_get_header(entry->image_pos, entry->size, use_spi_flash,
+ hdrp);
+ if (!use_spi_flash)
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI);
+ if (ret)
+ return log_msg_ret("fsp_get_header", ret);
+ *devp = dev;
+ if (rom_offsetp)
+ *rom_offsetp = rom_offset;
+
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/arch/x86/lib/fsp2/fsp_meminit.c b/roms/u-boot/arch/x86/lib/fsp2/fsp_meminit.c
new file mode 100644
index 000000000..022e2cb64
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp2/fsp_meminit.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright (C) 2015-2016 Intel Corp.
+ * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
+ * Mostly taken from coreboot fsp2_0/memory_init.c
+ */
+
+#include <common.h>
+#include <binman.h>
+#include <bootstage.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/mrccache.h>
+#include <asm/fsp/fsp_infoheader.h>
+#include <asm/fsp2/fsp_api.h>
+#include <asm/fsp2/fsp_internal.h>
+#include <asm/arch/fsp/fsp_configs.h>
+#include <asm/arch/fsp/fsp_m_upd.h>
+
+static int prepare_mrc_cache_type(enum mrc_type_t type,
+ struct mrc_data_container **cachep)
+{
+ struct mrc_data_container *cache;
+ struct mrc_region entry;
+ int ret;
+
+ ret = mrccache_get_region(type, NULL, &entry);
+ if (ret)
+ return ret;
+ cache = mrccache_find_current(&entry);
+ if (!cache)
+ return -ENOENT;
+
+ log_debug("MRC at %x, size %x\n", (uint)cache->data, cache->data_size);
+ *cachep = cache;
+
+ return 0;
+}
+
+int prepare_mrc_cache(struct fspm_upd *upd)
+{
+ struct mrc_data_container *cache;
+ int ret;
+
+ ret = prepare_mrc_cache_type(MRC_TYPE_NORMAL, &cache);
+ if (ret)
+ return log_msg_ret("Cannot get normal cache", ret);
+ upd->arch.nvs_buffer_ptr = cache->data;
+
+ ret = prepare_mrc_cache_type(MRC_TYPE_VAR, &cache);
+ if (ret)
+ return log_msg_ret("Cannot get var cache", ret);
+ upd->config.variable_nvs_buffer_ptr = cache->data;
+
+ return 0;
+}
+
+int fsp_memory_init(bool s3wake, bool use_spi_flash)
+{
+ struct fspm_upd upd, *fsp_upd;
+ fsp_memory_init_func func;
+ struct binman_entry entry;
+ struct fsp_header *hdr;
+ struct hob_header *hob;
+ struct udevice *dev;
+ int delay;
+ int ret;
+
+ log_debug("Locating FSP\n");
+ ret = fsp_locate_fsp(FSP_M, &entry, use_spi_flash, &dev, &hdr, NULL);
+ if (ret)
+ return log_msg_ret("locate FSP", ret);
+ debug("Found FSP_M at %x, size %x\n", hdr->img_base, hdr->img_size);
+
+ /* Copy over the default config */
+ fsp_upd = (struct fspm_upd *)(hdr->img_base + hdr->cfg_region_off);
+ if (fsp_upd->header.signature != FSPM_UPD_SIGNATURE)
+ return log_msg_ret("Bad UPD signature", -EPERM);
+ memcpy(&upd, fsp_upd, sizeof(upd));
+
+ delay = dev_read_u32_default(dev, "fspm,training-delay", 0);
+ ret = fspm_update_config(dev, &upd);
+ if (ret) {
+ if (ret != -ENOENT)
+ return log_msg_ret("Could not setup config", ret);
+ } else {
+ delay = 0;
+ }
+
+ if (delay)
+ printf("SDRAM training (%d seconds)...", delay);
+ else
+ log_debug("SDRAM init...");
+ bootstage_start(BOOTSTAGE_ID_ACCUM_FSP_M, "fsp-m");
+ func = (fsp_memory_init_func)(hdr->img_base + hdr->fsp_mem_init);
+ ret = func(&upd, &hob);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_FSP_M);
+ cpu_reinit_fpu();
+ if (delay)
+ printf("done\n");
+ else
+ log_debug("done\n");
+ if (ret)
+ return log_msg_ret("SDRAM init fail\n", ret);
+
+ gd->arch.hob_list = hob;
+
+ ret = fspm_done(dev);
+ if (ret)
+ return log_msg_ret("fsm_done\n", ret);
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp2/fsp_silicon_init.c b/roms/u-boot/arch/x86/lib/fsp2/fsp_silicon_init.c
new file mode 100644
index 000000000..a96d2b183
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp2/fsp_silicon_init.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright (C) 2015-2016 Intel Corp.
+ * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
+ *
+ * Mostly taken from coreboot fsp2_0/silicon_init.c
+ */
+
+#define LOG_CATEGORY UCLASS_NORTHBRIDGE
+
+#include <common.h>
+#include <binman.h>
+#include <bootstage.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/arch/fsp/fsp_configs.h>
+#include <asm/arch/fsp/fsp_s_upd.h>
+#include <asm/fsp/fsp_infoheader.h>
+#include <asm/fsp2/fsp_internal.h>
+#include <asm/global_data.h>
+
+int fsp_silicon_init(bool s3wake, bool use_spi_flash)
+{
+ struct fsps_upd upd, *fsp_upd;
+ fsp_silicon_init_func func;
+ struct fsp_header *hdr;
+ struct binman_entry entry;
+ struct udevice *dev;
+ ulong rom_offset = 0;
+ u32 init_addr;
+ int ret;
+
+ log_debug("Locating FSP\n");
+ ret = fsp_locate_fsp(FSP_S, &entry, use_spi_flash, &dev, &hdr,
+ &rom_offset);
+ if (ret)
+ return log_msg_ret("locate FSP", ret);
+ binman_set_rom_offset(rom_offset);
+ gd->arch.fsp_s_hdr = hdr;
+
+ /* Copy over the default config */
+ fsp_upd = (struct fsps_upd *)(hdr->img_base + hdr->cfg_region_off);
+ if (fsp_upd->header.signature != FSPS_UPD_SIGNATURE)
+ return log_msg_ret("Bad UPD signature", -EPERM);
+ memcpy(&upd, fsp_upd, sizeof(upd));
+
+ ret = fsps_update_config(dev, rom_offset, &upd);
+ if (ret)
+ return log_msg_ret("Could not setup config", ret);
+ log_debug("Silicon init @ %x...", init_addr);
+ bootstage_start(BOOTSTAGE_ID_ACCUM_FSP_S, "fsp-s");
+ func = (fsp_silicon_init_func)(hdr->img_base + hdr->fsp_silicon_init);
+ ret = func(&upd);
+ bootstage_accum(BOOTSTAGE_ID_ACCUM_FSP_S);
+ if (ret)
+ return log_msg_ret("Silicon init fail\n", ret);
+ log_debug("done\n");
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/fsp2/fsp_support.c b/roms/u-boot/arch/x86/lib/fsp2/fsp_support.c
new file mode 100644
index 000000000..b2c765824
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/fsp2/fsp_support.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <init.h>
+#include <log.h>
+#include <spi_flash.h>
+#include <asm/fsp/fsp_support.h>
+#include <asm/fsp2/fsp_internal.h>
+#include <asm/global_data.h>
+
+/* The amount of the FSP header to probe to obtain what we need */
+#define PROBE_BUF_SIZE 0x180
+
+int fsp_get_header(ulong offset, ulong size, bool use_spi_flash,
+ struct fsp_header **fspp)
+{
+ static efi_guid_t guid = FSP_HEADER_GUID;
+ struct fv_ext_header *exhdr;
+ struct fsp_header *fsp;
+ struct ffs_file_header *file_hdr;
+ struct fv_header *fv;
+ struct raw_section *raw;
+ void *ptr, *base;
+ u8 buf[PROBE_BUF_SIZE];
+ struct udevice *dev;
+ int ret;
+
+ /*
+ * There are quite a very steps to work through all the headers in this
+ * file and the structs have similar names. Turn on debugging if needed
+ * to understand what is going wrong.
+ *
+ * You are in a maze of twisty little headers all alike.
+ */
+ log_debug("offset=%x buf=%x, use_spi_flash=%d\n", (uint)offset,
+ (uint)buf, use_spi_flash);
+ if (use_spi_flash) {
+ ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
+ if (ret)
+ return log_msg_ret("Cannot find flash device", ret);
+ ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf);
+ if (ret)
+ return log_msg_ret("Cannot read flash", ret);
+ } else {
+ memcpy(buf, (void *)offset, PROBE_BUF_SIZE);
+ }
+
+ /* Initalise the FSP base */
+ ptr = buf;
+ fv = ptr;
+
+ /* Check the FV signature, _FVH */
+ log_debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign);
+ if (fv->sign != EFI_FVH_SIGNATURE)
+ return log_msg_ret("Base FV signature", -EINVAL);
+
+ /* Go to the end of the FV header and align the address */
+ log_debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off);
+ ptr += fv->ext_hdr_off;
+ exhdr = ptr;
+ ptr += ALIGN(exhdr->ext_hdr_size, 8);
+ log_debug("ptr=%x\n", ptr - (void *)buf);
+
+ /* Check the FFS GUID */
+ file_hdr = ptr;
+ if (memcmp(&file_hdr->name, &guid, sizeof(guid)))
+ return log_msg_ret("Base FFS GUID", -ENXIO);
+ /* Add the FFS header size to find the raw section header */
+ ptr = file_hdr + 1;
+
+ raw = ptr;
+ log_debug("raw->type = %x\n", raw->type);
+ if (raw->type != EFI_SECTION_RAW)
+ return log_msg_ret("Section type not RAW", -ENOEXEC);
+
+ /* Add the raw section header size to find the FSP header */
+ ptr = raw + 1;
+ fsp = ptr;
+
+ /* Check the FSPH header */
+ log_debug("fsp %x, fsp-buf=%x, si=%x\n", (uint)fsp, ptr - (void *)buf,
+ (void *)&fsp->fsp_silicon_init - (void *)buf);
+ if (fsp->sign != EFI_FSPH_SIGNATURE)
+ return log_msg_ret("Base FSPH signature", -EACCES);
+
+ base = (void *)fsp->img_base;
+ log_debug("image base %x\n", (uint)base);
+ if (fsp->fsp_mem_init)
+ log_debug("mem_init offset %x\n", (uint)fsp->fsp_mem_init);
+ else if (fsp->fsp_silicon_init)
+ log_debug("silicon_init offset %x\n",
+ (uint)fsp->fsp_silicon_init);
+ if (use_spi_flash) {
+ ret = spi_flash_read_dm(dev, offset, size, base);
+ if (ret)
+ return log_msg_ret("Could not read FPS-M", ret);
+ } else {
+ memcpy(base, (void *)offset, size);
+ }
+ ptr = base + (ptr - (void *)buf);
+ *fspp = ptr;
+
+ return 0;
+}
+
+u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
+{
+ fsp_notify_f notify;
+ struct fsp_notify_params params;
+ struct fsp_notify_params *params_ptr;
+ u32 status;
+
+ if (!ll_boot_init())
+ return 0;
+
+ if (!fsp_hdr)
+ fsp_hdr = gd->arch.fsp_s_hdr;
+
+ if (!fsp_hdr)
+ return log_msg_ret("no FSP", -ENOENT);
+
+ notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
+ params.phase = phase;
+ params_ptr = &params;
+
+ /*
+ * Use ASM code to ensure correct parameter is on the stack for
+ * FspNotify as U-Boot is using different ABI from FSP
+ */
+ asm volatile (
+ "pushl %1;" /* push notify phase */
+ "call *%%eax;" /* call FspNotify */
+ "addl $4, %%esp;" /* clean up the stack */
+ : "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
+ );
+
+ return status;
+}
diff --git a/roms/u-boot/arch/x86/lib/hob.c b/roms/u-boot/arch/x86/lib/hob.c
new file mode 100644
index 000000000..f2c47240e
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/hob.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: Intel
+/*
+ * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/hob.h>
+
+/**
+ * Returns the next instance of a HOB type from the starting HOB.
+ *
+ * @type: HOB type to search
+ * @hob_list: A pointer to the HOB list
+ *
+ * @return A HOB object with matching type; Otherwise NULL.
+ */
+const struct hob_header *hob_get_next_hob(uint type, const void *hob_list)
+{
+ const struct hob_header *hdr;
+
+ hdr = hob_list;
+
+ /* Parse the HOB list until end of list or matching type is found */
+ while (!end_of_hob(hdr)) {
+ if (hdr->type == type)
+ return hdr;
+
+ hdr = get_next_hob(hdr);
+ }
+
+ return NULL;
+}
+
+/**
+ * Returns the next instance of the matched GUID HOB from the starting HOB.
+ *
+ * @guid: GUID to search
+ * @hob_list: A pointer to the HOB list
+ *
+ * @return A HOB object with matching GUID; Otherwise NULL.
+ */
+const struct hob_header *hob_get_next_guid_hob(const efi_guid_t *guid,
+ const void *hob_list)
+{
+ const struct hob_header *hdr;
+ struct hob_guid *guid_hob;
+
+ hdr = hob_list;
+ while ((hdr = hob_get_next_hob(HOB_TYPE_GUID_EXT, hdr))) {
+ guid_hob = (struct hob_guid *)hdr;
+ if (!guidcmp(guid, &guid_hob->name))
+ break;
+ hdr = get_next_hob(hdr);
+ }
+
+ return hdr;
+}
+
+/**
+ * This function retrieves a GUID HOB data buffer and size.
+ *
+ * @hob_list: A HOB list pointer.
+ * @len: A pointer to the GUID HOB data buffer length.
+ * If the GUID HOB is located, the length will be updated.
+ * @guid A pointer to HOB GUID.
+ *
+ * @return NULL: Failed to find the GUID HOB.
+ * @return others: GUID HOB data buffer pointer.
+ */
+void *hob_get_guid_hob_data(const void *hob_list, u32 *len,
+ const efi_guid_t *guid)
+{
+ const struct hob_header *guid_hob;
+
+ guid_hob = hob_get_next_guid_hob(guid, hob_list);
+ if (!guid_hob)
+ return NULL;
+
+ if (len)
+ *len = get_guid_hob_data_size(guid_hob);
+
+ return get_guid_hob_data(guid_hob);
+}
diff --git a/roms/u-boot/arch/x86/lib/i8254.c b/roms/u-boot/arch/x86/lib/i8254.c
new file mode 100644
index 000000000..0f9753891
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/i8254.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+
+#define TIMER1_VALUE 18 /* 15.6us */
+#define BEEP_FREQUENCY_HZ 440
+#define SYSCTL_PORTB 0x61
+#define PORTB_BEEP_ENABLE 0x3
+
+static void i8254_set_beep_freq(uint frequency_hz)
+{
+ uint countdown;
+
+ countdown = PIT_TICK_RATE / frequency_hz;
+
+ outb(countdown & 0xff, PIT_BASE + PIT_T2);
+ outb((countdown >> 8) & 0xff, PIT_BASE + PIT_T2);
+}
+
+int i8254_init(void)
+{
+ /*
+ * Initialize counter 1, used to refresh request signal.
+ * This is required for legacy purpose as some codes like
+ * vgabios utilizes counter 1 to provide delay functionality.
+ */
+ outb(PIT_CMD_CTR1 | PIT_CMD_LOW | PIT_CMD_MODE2,
+ PIT_BASE + PIT_COMMAND);
+ outb(TIMER1_VALUE, PIT_BASE + PIT_T1);
+
+ /*
+ * Initialize counter 2, used to drive the speaker.
+ * To start a beep, set both bit0 and bit1 of port 0x61.
+ * To stop it, clear both bit0 and bit1 of port 0x61.
+ */
+ outb(PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
+ PIT_BASE + PIT_COMMAND);
+ i8254_set_beep_freq(BEEP_FREQUENCY_HZ);
+
+ return 0;
+}
+
+int i8254_enable_beep(uint frequency_hz)
+{
+ if (!frequency_hz)
+ return -EINVAL;
+
+ /* make sure i8254 is setup correctly before generating beeps */
+ outb(PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
+ PIT_BASE + PIT_COMMAND);
+
+ i8254_set_beep_freq(frequency_hz);
+ setio_8(SYSCTL_PORTB, PORTB_BEEP_ENABLE);
+
+ return 0;
+}
+
+void i8254_disable_beep(void)
+{
+ clrio_8(SYSCTL_PORTB, PORTB_BEEP_ENABLE);
+}
diff --git a/roms/u-boot/arch/x86/lib/i8259.c b/roms/u-boot/arch/x86/lib/i8259.c
new file mode 100644
index 000000000..a0e3c0925
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/i8259.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Graeme Russ, <graeme.russ@gmail.com>
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
+ */
+
+/*
+ * This file provides the interrupt handling functionality for systems
+ * based on the standard PC/AT architecture using two cascaded i8259
+ * Programmable Interrupt Controllers.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/i8259.h>
+#include <asm/ibmpc.h>
+#include <asm/interrupt.h>
+
+int i8259_init(void)
+{
+ u8 i;
+
+ /* Mask all interrupts */
+ outb(0xff, MASTER_PIC + IMR);
+ outb(0xff, SLAVE_PIC + IMR);
+
+ /*
+ * Master PIC
+ * Place master PIC interrupts at INT20
+ */
+ outb(ICW1_SEL | ICW1_EICW4, MASTER_PIC + ICW1);
+ outb(0x20, MASTER_PIC + ICW2);
+ outb(IR2, MASTER_PIC + ICW3);
+ outb(ICW4_PM, MASTER_PIC + ICW4);
+
+ for (i = 0; i < 8; i++)
+ outb(OCW2_SEOI | i, MASTER_PIC + OCW2);
+
+ /*
+ * Slave PIC
+ * Place slave PIC interrupts at INT28
+ */
+ outb(ICW1_SEL | ICW1_EICW4, SLAVE_PIC + ICW1);
+ outb(0x28, SLAVE_PIC + ICW2);
+ outb(0x02, SLAVE_PIC + ICW3);
+ outb(ICW4_PM, SLAVE_PIC + ICW4);
+
+ for (i = 0; i < 8; i++)
+ outb(OCW2_SEOI | i, SLAVE_PIC + OCW2);
+
+ /*
+ * Enable cascaded interrupts by unmasking the cascade IRQ pin of
+ * the master PIC
+ */
+ unmask_irq(2);
+
+ /* Interrupt 9 should be level triggered (SCI). The OS might do this */
+ configure_irq_trigger(9, true);
+
+ return 0;
+}
+
+void mask_irq(int irq)
+{
+ int imr_port;
+
+ if (irq >= SYS_NUM_IRQS)
+ return;
+
+ if (irq > 7)
+ imr_port = SLAVE_PIC + IMR;
+ else
+ imr_port = MASTER_PIC + IMR;
+
+ outb(inb(imr_port) | (1 << (irq & 7)), imr_port);
+}
+
+void unmask_irq(int irq)
+{
+ int imr_port;
+
+ if (irq >= SYS_NUM_IRQS)
+ return;
+
+ if (irq > 7)
+ imr_port = SLAVE_PIC + IMR;
+ else
+ imr_port = MASTER_PIC + IMR;
+
+ outb(inb(imr_port) & ~(1 << (irq & 7)), imr_port);
+}
+
+void specific_eoi(int irq)
+{
+ if (irq >= SYS_NUM_IRQS)
+ return;
+
+ if (irq > 7) {
+ /*
+ * IRQ is on the slave - Issue a corresponding EOI to the
+ * slave PIC and an EOI for IRQ2 (the cascade interrupt)
+ * on the master PIC
+ */
+ outb(OCW2_SEOI | (irq & 7), SLAVE_PIC + OCW2);
+ irq = SEOI_IR2;
+ }
+
+ outb(OCW2_SEOI | irq, MASTER_PIC + OCW2);
+}
+
+void configure_irq_trigger(int int_num, bool is_level_triggered)
+{
+ u16 int_bits = inb(ELCR1) | (((u16)inb(ELCR2)) << 8);
+
+ debug("%s: current interrupts are 0x%x\n", __func__, int_bits);
+ if (is_level_triggered)
+ int_bits |= (1 << int_num);
+ else
+ int_bits &= ~(1 << int_num);
+
+ /* Write new values */
+ debug("%s: try to set interrupts 0x%x\n", __func__, int_bits);
+ outb((u8)(int_bits & 0xff), ELCR1);
+ outb((u8)(int_bits >> 8), ELCR2);
+}
diff --git a/roms/u-boot/arch/x86/lib/init_helpers.c b/roms/u-boot/arch/x86/lib/init_helpers.c
new file mode 100644
index 000000000..67401b9ba
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/init_helpers.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011
+ * Graeme Russ, <graeme.russ@gmail.com>
+ */
+
+#include <common.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <linux/errno.h>
+#include <asm/mtrr.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int init_cache_f_r(void)
+{
+ bool do_mtrr = CONFIG_IS_ENABLED(X86_32BIT_INIT) ||
+ IS_ENABLED(CONFIG_FSP_VERSION2);
+ int ret;
+
+ if (!ll_boot_init())
+ return 0;
+
+ do_mtrr &= !IS_ENABLED(CONFIG_FSP_VERSION1) &&
+ !IS_ENABLED(CONFIG_SYS_SLIMBOOTLOADER);
+
+ if (do_mtrr) {
+ ret = mtrr_commit(false);
+ /*
+ * If MTRR MSR is not implemented by the processor, just ignore
+ * it
+ */
+ if (ret && ret != -ENOSYS)
+ return ret;
+ }
+
+ /* Initialise the CPU cache(s) */
+ return init_cache();
+}
diff --git a/roms/u-boot/arch/x86/lib/interrupts.c b/roms/u-boot/arch/x86/lib/interrupts.c
new file mode 100644
index 000000000..ff52959ed
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/interrupts.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Graeme Russ, <graeme.russ@gmail.com>
+ *
+ * (C) Copyright 2007
+ * Daniel Hellstrom, Gaisler Research, <daniel@gaisler.com>
+ *
+ * (C) Copyright 2006
+ * Detlev Zundel, DENX Software Engineering, <dzu@denx.de>
+ *
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
+ *
+ * (C) Copyright 2001
+ * Josh Huber, Mission Critical Linux, Inc, <huber@mclx.com>
+ */
+
+/*
+ * This file contains the high-level API for the interrupt sub-system
+ * of the x86 port of U-Boot. Most of the functionality has been
+ * shamelessly stolen from the leon2 / leon3 ports of U-Boot.
+ * Daniel Hellstrom, Detlev Zundel, Wolfgang Denk and Josh Huber are
+ * credited for the corresponding work on those ports. The original
+ * interrupt handling routines for the x86 port were written by
+ * Daniel Engström
+ */
+
+#include <common.h>
+#include <command.h>
+#include <irq_func.h>
+#include <asm/interrupt.h>
+
+#if !CONFIG_IS_ENABLED(X86_64)
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ unsigned int count;
+};
+
+static struct irq_action irq_handlers[SYS_NUM_IRQS] = { {0} };
+static int spurious_irq_cnt;
+static int spurious_irq;
+
+void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
+{
+ int status;
+
+ if (irq < 0 || irq >= SYS_NUM_IRQS) {
+ printf("irq_install_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler != NULL)
+ printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+ (ulong) handler,
+ (ulong) irq_handlers[irq].handler);
+
+ status = disable_interrupts();
+
+ irq_handlers[irq].handler = handler;
+ irq_handlers[irq].arg = arg;
+ irq_handlers[irq].count = 0;
+
+ if (CONFIG_IS_ENABLED(I8259_PIC))
+ unmask_irq(irq);
+
+ if (status)
+ enable_interrupts();
+
+ return;
+}
+
+void irq_free_handler(int irq)
+{
+ int status;
+
+ if (irq < 0 || irq >= SYS_NUM_IRQS) {
+ printf("irq_free_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ status = disable_interrupts();
+
+ if (CONFIG_IS_ENABLED(I8259_PIC))
+ mask_irq(irq);
+
+ irq_handlers[irq].handler = NULL;
+ irq_handlers[irq].arg = NULL;
+
+ if (status)
+ enable_interrupts();
+
+ return;
+}
+
+void do_irq(int hw_irq)
+{
+ int irq = hw_irq - 0x20;
+
+ if (irq < 0 || irq >= SYS_NUM_IRQS) {
+ printf("do_irq: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler) {
+ if (CONFIG_IS_ENABLED(I8259_PIC))
+ mask_irq(irq);
+
+ irq_handlers[irq].handler(irq_handlers[irq].arg);
+ irq_handlers[irq].count++;
+
+ if (CONFIG_IS_ENABLED(I8259_PIC)) {
+ unmask_irq(irq);
+ specific_eoi(irq);
+ }
+ } else {
+ if ((irq & 7) != 7) {
+ spurious_irq_cnt++;
+ spurious_irq = irq;
+ }
+ }
+}
+#endif
+
+#if defined(CONFIG_CMD_IRQ)
+int do_irqinfo(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+#if !CONFIG_IS_ENABLED(X86_64)
+ struct idt_ptr ptr;
+ int irq;
+
+ interrupt_read_idt(&ptr);
+ printf("IDT at %lx, size %x\n", ptr.address, ptr.size);
+ printf("Spurious IRQ: %u, last unknown IRQ: %d\n",
+ spurious_irq_cnt, spurious_irq);
+
+ printf("Interrupt-Information:\n");
+ printf("Nr Routine Arg Count\n");
+
+ for (irq = 0; irq < SYS_NUM_IRQS; irq++) {
+ if (irq_handlers[irq].handler != NULL) {
+ printf("%02d %08lx %08lx %d\n",
+ irq,
+ (ulong)irq_handlers[irq].handler,
+ (ulong)irq_handlers[irq].arg,
+ irq_handlers[irq].count);
+ }
+ }
+#endif
+
+ return 0;
+}
+#endif
diff --git a/roms/u-boot/arch/x86/lib/lpc-uclass.c b/roms/u-boot/arch/x86/lib/lpc-uclass.c
new file mode 100644
index 000000000..1302a6e34
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/lpc-uclass.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+
+UCLASS_DRIVER(lpc) = {
+ .id = UCLASS_LPC,
+ .name = "lpc",
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .post_bind = dm_scan_fdt_dev,
+#endif
+};
diff --git a/roms/u-boot/arch/x86/lib/mpspec.c b/roms/u-boot/arch/x86/lib/mpspec.c
new file mode 100644
index 000000000..8e97d9ff3
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/mpspec.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Adapted from coreboot src/arch/x86/boot/mpspec.c
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/cpu.h>
+#include <asm/global_data.h>
+#include <asm/irq.h>
+#include <asm/ioapic.h>
+#include <asm/lapic.h>
+#include <asm/mpspec.h>
+#include <asm/tables.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static bool isa_irq_occupied[16];
+
+struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf)
+{
+ ulong mc;
+
+ memcpy(mf->mpf_signature, MPF_SIGNATURE, 4);
+ mf->mpf_physptr = (ulong)mf + sizeof(struct mp_floating_table);
+ mf->mpf_length = 1;
+ mf->mpf_spec = MPSPEC_V14;
+ mf->mpf_checksum = 0;
+ /* We don't use the default configuration table */
+ mf->mpf_feature1 = 0;
+ /* Indicate that virtual wire mode is always implemented */
+ mf->mpf_feature2 = 0;
+ mf->mpf_feature3 = 0;
+ mf->mpf_feature4 = 0;
+ mf->mpf_feature5 = 0;
+ mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16);
+
+ mc = (ulong)mf + sizeof(struct mp_floating_table);
+ return (struct mp_config_table *)mc;
+}
+
+void mp_config_table_init(struct mp_config_table *mc)
+{
+ memcpy(mc->mpc_signature, MPC_SIGNATURE, 4);
+ mc->mpc_length = sizeof(struct mp_config_table);
+ mc->mpc_spec = MPSPEC_V14;
+ mc->mpc_checksum = 0;
+ mc->mpc_oemptr = 0;
+ mc->mpc_oemsize = 0;
+ mc->mpc_entry_count = 0;
+ mc->mpc_lapic = LAPIC_DEFAULT_BASE;
+ mc->mpe_length = 0;
+ mc->mpe_checksum = 0;
+ mc->reserved = 0;
+
+ /* The oem/product id fields are exactly 8/12 bytes long */
+ table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' ');
+ table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' ');
+}
+
+void mp_write_processor(struct mp_config_table *mc)
+{
+ struct mpc_config_processor *mpc;
+ struct udevice *dev;
+ u8 boot_apicid, apicver;
+ u32 cpusignature, cpufeature;
+ struct cpuid_result result;
+
+ boot_apicid = lapicid();
+ apicver = lapic_read(LAPIC_LVR) & 0xff;
+ result = cpuid(1);
+ cpusignature = result.eax;
+ cpufeature = result.edx;
+
+ for (uclass_find_first_device(UCLASS_CPU, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+ u8 cpuflag = MPC_CPU_EN;
+
+ if (!device_active(dev))
+ continue;
+
+ mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc);
+ mpc->mpc_type = MP_PROCESSOR;
+ mpc->mpc_apicid = plat->cpu_id;
+ mpc->mpc_apicver = apicver;
+ if (boot_apicid == plat->cpu_id)
+ cpuflag |= MPC_CPU_BP;
+ mpc->mpc_cpuflag = cpuflag;
+ mpc->mpc_cpusignature = cpusignature;
+ mpc->mpc_cpufeature = cpufeature;
+ mpc->mpc_reserved[0] = 0;
+ mpc->mpc_reserved[1] = 0;
+ mp_add_mpc_entry(mc, sizeof(*mpc));
+ }
+}
+
+void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype)
+{
+ struct mpc_config_bus *mpc;
+
+ mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc);
+ mpc->mpc_type = MP_BUS;
+ mpc->mpc_busid = id;
+ memcpy(mpc->mpc_bustype, bustype, 6);
+ mp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr)
+{
+ struct mpc_config_ioapic *mpc;
+
+ mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc);
+ mpc->mpc_type = MP_IOAPIC;
+ mpc->mpc_apicid = id;
+ mpc->mpc_apicver = ver;
+ mpc->mpc_flags = MPC_APIC_USABLE;
+ mpc->mpc_apicaddr = apicaddr;
+ mp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag,
+ int srcbus, int srcbusirq, int dstapic, int dstirq)
+{
+ struct mpc_config_intsrc *mpc;
+
+ mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc);
+ mpc->mpc_type = MP_INTSRC;
+ mpc->mpc_irqtype = irqtype;
+ mpc->mpc_irqflag = irqflag;
+ mpc->mpc_srcbus = srcbus;
+ mpc->mpc_srcbusirq = srcbusirq;
+ mpc->mpc_dstapic = dstapic;
+ mpc->mpc_dstirq = dstirq;
+ mp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype,
+ int srcbus, int dev, int pin, int dstapic, int dstirq)
+{
+ u8 srcbusirq = (dev << 2) | (pin - 1);
+
+ mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW,
+ srcbus, srcbusirq, dstapic, dstirq);
+}
+
+void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag,
+ int srcbus, int srcbusirq, int destapic, int destlint)
+{
+ struct mpc_config_lintsrc *mpc;
+
+ mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc);
+ mpc->mpc_type = MP_LINTSRC;
+ mpc->mpc_irqtype = irqtype;
+ mpc->mpc_irqflag = irqflag;
+ mpc->mpc_srcbusid = srcbus;
+ mpc->mpc_srcbusirq = srcbusirq;
+ mpc->mpc_destapic = destapic;
+ mpc->mpc_destlint = destlint;
+ mp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void mp_write_address_space(struct mp_config_table *mc,
+ int busid, int addr_type,
+ u32 addr_base_low, u32 addr_base_high,
+ u32 addr_length_low, u32 addr_length_high)
+{
+ struct mp_ext_system_address_space *mpe;
+
+ mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc);
+ mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_addr_type = addr_type;
+ mpe->mpe_addr_base_low = addr_base_low;
+ mpe->mpe_addr_base_high = addr_base_high;
+ mpe->mpe_addr_length_low = addr_length_low;
+ mpe->mpe_addr_length_high = addr_length_high;
+ mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe);
+}
+
+void mp_write_bus_hierarchy(struct mp_config_table *mc,
+ int busid, int bus_info, int parent_busid)
+{
+ struct mp_ext_bus_hierarchy *mpe;
+
+ mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc);
+ mpe->mpe_type = MPE_BUS_HIERARCHY;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_bus_info = bus_info;
+ mpe->mpe_parent_busid = parent_busid;
+ mpe->reserved[0] = 0;
+ mpe->reserved[1] = 0;
+ mpe->reserved[2] = 0;
+ mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe);
+}
+
+void mp_write_compat_address_space(struct mp_config_table *mc, int busid,
+ int addr_modifier, u32 range_list)
+{
+ struct mp_ext_compat_address_space *mpe;
+
+ mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc);
+ mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_addr_modifier = addr_modifier;
+ mpe->mpe_range_list = range_list;
+ mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe);
+}
+
+u32 mptable_finalize(struct mp_config_table *mc)
+{
+ ulong end;
+
+ mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc),
+ mc->mpe_length);
+ mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length);
+ end = mp_next_mpe_entry(mc);
+
+ debug("Write the MP table at: %lx - %lx\n", (ulong)mc, end);
+
+ return end;
+}
+
+static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa,
+ int apicid, int external_int2)
+{
+ int i;
+
+ mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT,
+ MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
+ bus_isa, 0, apicid, 0);
+ mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
+ bus_isa, 1, apicid, 1);
+ mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT,
+ MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
+ bus_isa, 0, apicid, 2);
+
+ for (i = 3; i < 16; i++) {
+ /*
+ * Do not write ISA interrupt entry if it is already occupied
+ * by the platform devices.
+ */
+ if (isa_irq_occupied[i])
+ continue;
+
+ mp_write_intsrc(mc, MP_INT,
+ MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
+ bus_isa, i, apicid, i);
+ }
+}
+
+/*
+ * Check duplicated I/O interrupt assignment table entry, to make sure
+ * there is only one entry with the given bus, device and interrupt pin.
+ */
+static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base,
+ int entry_num, int bus, int device, int pin)
+{
+ struct mpc_config_intsrc *intsrc = intsrc_base;
+ int i;
+
+ for (i = 0; i < entry_num; i++) {
+ if (intsrc->mpc_srcbus == bus &&
+ intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1)))
+ break;
+ intsrc++;
+ }
+
+ return (i == entry_num) ? false : true;
+}
+
+/* TODO: move this to driver model */
+__weak int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq)
+{
+ /* PIRQ[A-H] are connected to I/O APIC INTPIN#16-23 */
+ return pirq + 16;
+}
+
+static int mptable_add_intsrc(struct mp_config_table *mc,
+ int bus_isa, int apicid)
+{
+ struct mpc_config_intsrc *intsrc_base;
+ int intsrc_entries = 0;
+ const void *blob = gd->fdt_blob;
+ struct udevice *dev;
+ int len, count;
+ const u32 *cell;
+ int i, ret;
+
+ ret = uclass_first_device_err(UCLASS_IRQ, &dev);
+ if (ret && ret != -ENODEV) {
+ debug("%s: Cannot find irq router node\n", __func__);
+ return ret;
+ }
+
+ /* Get I/O interrupt information from device tree */
+ cell = fdt_getprop(blob, dev_of_offset(dev), "intel,pirq-routing",
+ &len);
+ if (!cell)
+ return -ENOENT;
+
+ if ((len % sizeof(struct pirq_routing)) == 0)
+ count = len / sizeof(struct pirq_routing);
+ else
+ return -EINVAL;
+
+ intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc);
+
+ for (i = 0; i < count; i++) {
+ struct pirq_routing pr;
+ int bus, dev, func;
+ int dstirq;
+
+ pr.bdf = fdt_addr_to_cpu(cell[0]);
+ pr.pin = fdt_addr_to_cpu(cell[1]);
+ pr.pirq = fdt_addr_to_cpu(cell[2]);
+ bus = PCI_BUS(pr.bdf);
+ dev = PCI_DEV(pr.bdf);
+ func = PCI_FUNC(pr.bdf);
+
+ if (check_dup_entry(intsrc_base, intsrc_entries,
+ bus, dev, pr.pin)) {
+ debug("found entry for bus %d device %d INT%c, skipping\n",
+ bus, dev, 'A' + pr.pin - 1);
+ cell += sizeof(struct pirq_routing) / sizeof(u32);
+ continue;
+ }
+
+ dstirq = mp_determine_pci_dstirq(bus, dev, func, pr.pirq);
+ /*
+ * For PIRQ which is connected to I/O APIC interrupt pin#0-15,
+ * mark it as occupied so that we can skip it later.
+ */
+ if (dstirq < 16)
+ isa_irq_occupied[dstirq] = true;
+ mp_write_pci_intsrc(mc, MP_INT, bus, dev, pr.pin,
+ apicid, dstirq);
+ intsrc_entries++;
+ cell += sizeof(struct pirq_routing) / sizeof(u32);
+ }
+
+ /* Legacy Interrupts */
+ debug("Writing ISA IRQs\n");
+ mptable_add_isa_interrupts(mc, bus_isa, apicid, 0);
+
+ return 0;
+}
+
+static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa)
+{
+ mp_write_lintsrc(mc, MP_EXTINT,
+ MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
+ bus_isa, 0, MP_APIC_ALL, 0);
+ mp_write_lintsrc(mc, MP_NMI,
+ MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
+ bus_isa, 0, MP_APIC_ALL, 1);
+}
+
+ulong write_mp_table(ulong addr)
+{
+ struct mp_config_table *mc;
+ int ioapic_id, ioapic_ver;
+ int bus_isa = 0xff;
+ int ret;
+ ulong end;
+
+ /* 16 byte align the table address */
+ addr = ALIGN(addr, 16);
+
+ /* Write floating table */
+ mc = mp_write_floating_table((struct mp_floating_table *)addr);
+
+ /* Write configuration table header */
+ mp_config_table_init(mc);
+
+ /* Write processor entry */
+ mp_write_processor(mc);
+
+ /* Write bus entry */
+ mp_write_bus(mc, bus_isa, BUSTYPE_ISA);
+
+ /* Write I/O APIC entry */
+ ioapic_id = io_apic_read(IO_APIC_ID) >> 24;
+ ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff;
+ mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR);
+
+ /* Write I/O interrupt assignment entry */
+ ret = mptable_add_intsrc(mc, bus_isa, ioapic_id);
+ if (ret)
+ debug("Failed to write I/O interrupt assignment table\n");
+
+ /* Write local interrupt assignment entry */
+ mptable_add_lintsrc(mc, bus_isa);
+
+ /* Finalize the MP table */
+ end = mptable_finalize(mc);
+
+ return end;
+}
diff --git a/roms/u-boot/arch/x86/lib/mrccache.c b/roms/u-boot/arch/x86/lib/mrccache.c
new file mode 100644
index 000000000..b52691568
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/mrccache.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * From coreboot src/southbridge/intel/bd82x6x/mrccache.c
+ *
+ * Copyright (C) 2014 Google Inc.
+ * Copyright (C) 2015 Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <net.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/global_data.h>
+#include <asm/mrccache.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static uint mrc_block_size(uint data_size)
+{
+ uint mrc_size = sizeof(struct mrc_data_container) + data_size;
+
+ return ALIGN(mrc_size, MRC_DATA_ALIGN);
+}
+
+static struct mrc_data_container *next_mrc_block(
+ struct mrc_data_container *cache)
+{
+ /* MRC data blocks are aligned within the region */
+ u8 *region_ptr = (u8 *)cache;
+
+ region_ptr += mrc_block_size(cache->data_size);
+
+ return (struct mrc_data_container *)region_ptr;
+}
+
+static int is_mrc_cache(struct mrc_data_container *cache)
+{
+ return cache && (cache->signature == MRC_DATA_SIGNATURE);
+}
+
+struct mrc_data_container *mrccache_find_current(struct mrc_region *entry)
+{
+ struct mrc_data_container *cache, *next;
+ ulong base_addr, end_addr;
+ uint id;
+
+ base_addr = entry->base + entry->offset;
+ end_addr = base_addr + entry->length;
+ cache = NULL;
+
+ /* Search for the last filled entry in the region */
+ for (id = 0, next = (struct mrc_data_container *)base_addr;
+ is_mrc_cache(next);
+ id++) {
+ cache = next;
+ next = next_mrc_block(next);
+ if ((ulong)next >= end_addr)
+ break;
+ }
+
+ if (id-- == 0) {
+ debug("%s: No valid MRC cache found.\n", __func__);
+ return NULL;
+ }
+
+ /* Verify checksum */
+ if (cache->checksum != compute_ip_checksum(cache->data,
+ cache->data_size)) {
+ printf("%s: MRC cache checksum mismatch\n", __func__);
+ return NULL;
+ }
+
+ debug("%s: picked entry %u from cache block\n", __func__, id);
+
+ return cache;
+}
+
+/**
+ * find_next_mrc_cache() - get next cache entry
+ *
+ * This moves to the next cache entry in the region, making sure it has enough
+ * space to hold data of size @data_size.
+ *
+ * @entry: MRC cache flash area
+ * @cache: Entry to start from
+ * @data_size: Required data size of the new entry. Note that we assume that
+ * all cache entries are the same size
+ *
+ * @return next cache entry if found, NULL if we got to the end
+ */
+static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry,
+ struct mrc_data_container *prev, int data_size)
+{
+ struct mrc_data_container *cache;
+ ulong base_addr, end_addr;
+
+ base_addr = entry->base + entry->offset;
+ end_addr = base_addr + entry->length;
+
+ /*
+ * We assume that all cache entries are the same size, but let's use
+ * data_size here for clarity.
+ */
+ cache = next_mrc_block(prev);
+ if ((ulong)cache + mrc_block_size(data_size) > end_addr) {
+ /* Crossed the boundary */
+ cache = NULL;
+ debug("%s: no available entries found\n", __func__);
+ } else {
+ debug("%s: picked next entry from cache block at %p\n",
+ __func__, cache);
+ }
+
+ return cache;
+}
+
+/**
+ * mrccache_update() - update the MRC cache with a new record
+ *
+ * This writes a new record to the end of the MRC cache region. If the new
+ * record is the same as the latest record then the write is skipped
+ *
+ * @sf: SPI flash to write to
+ * @entry: Position and size of MRC cache in SPI flash
+ * @cur: Record to write
+ * @return 0 if updated, -EEXIST if the record is the same as the latest
+ * record, -EINVAL if the record is not valid, other error if SPI write failed
+ */
+static int mrccache_update(struct udevice *sf, struct mrc_region *entry,
+ struct mrc_data_container *cur)
+{
+ struct mrc_data_container *cache;
+ ulong offset;
+ ulong base_addr;
+ int ret;
+
+ if (!is_mrc_cache(cur)) {
+ debug("%s: Cache data not valid\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Find the last used block */
+ base_addr = entry->base + entry->offset;
+ debug("Updating MRC cache data\n");
+ cache = mrccache_find_current(entry);
+ if (cache && (cache->data_size == cur->data_size) &&
+ (!memcmp(cache, cur, cache->data_size + sizeof(*cur)))) {
+ debug("MRC data in flash is up to date. No update\n");
+ return -EEXIST;
+ }
+
+ /* Move to the next block, which will be the first unused block */
+ if (cache)
+ cache = find_next_mrc_cache(entry, cache, cur->data_size);
+
+ /*
+ * If we have got to the end, erase the entire mrc-cache area and start
+ * again at block 0.
+ */
+ if (!cache) {
+ debug("Erasing the MRC cache region of %x bytes at %x\n",
+ entry->length, entry->offset);
+
+ ret = spi_flash_erase_dm(sf, entry->offset, entry->length);
+ if (ret) {
+ debug("Failed to erase flash region\n");
+ return ret;
+ }
+ cache = (struct mrc_data_container *)base_addr;
+ }
+
+ /* Write the data out */
+ offset = (ulong)cache - base_addr + entry->offset;
+ debug("Write MRC cache update to flash at %lx\n", offset);
+ ret = spi_flash_write_dm(sf, offset, cur->data_size + sizeof(*cur),
+ cur);
+ if (ret) {
+ debug("Failed to write to SPI flash\n");
+ return log_msg_ret("Cannot update mrccache", ret);
+ }
+
+ return 0;
+}
+
+static void mrccache_setup(struct mrc_output *mrc, void *data)
+{
+ struct mrc_data_container *cache = data;
+ u16 checksum;
+
+ cache->signature = MRC_DATA_SIGNATURE;
+ cache->data_size = mrc->len;
+ checksum = compute_ip_checksum(mrc->buf, cache->data_size);
+ debug("Saving %d bytes for MRC output data, checksum %04x\n",
+ cache->data_size, checksum);
+ cache->checksum = checksum;
+ cache->reserved = 0;
+ memcpy(cache->data, mrc->buf, cache->data_size);
+
+ mrc->cache = cache;
+}
+
+int mrccache_reserve(void)
+{
+ int i;
+
+ for (i = 0; i < MRC_TYPE_COUNT; i++) {
+ struct mrc_output *mrc = &gd->arch.mrc[i];
+
+ if (!mrc->len)
+ continue;
+
+ /* adjust stack pointer to store pure cache data plus header */
+ gd->start_addr_sp -= (mrc->len + MRC_DATA_HEADER_SIZE);
+ mrccache_setup(mrc, (void *)gd->start_addr_sp);
+
+ gd->start_addr_sp &= ~0xf;
+ }
+
+ return 0;
+}
+
+int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
+ struct mrc_region *entry)
+{
+ struct udevice *dev;
+ ofnode mrc_node;
+ ulong map_base;
+ uint map_size;
+ uint offset;
+ ofnode node;
+ u32 reg[2];
+ int ret;
+
+ /*
+ * Find the flash chip within the SPI controller node. Avoid probing
+ * the device here since it may put it into a strange state where the
+ * memory map cannot be read.
+ */
+ ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev);
+ if (ret || !dev) {
+ /*
+ * Fall back to searching the device tree since driver model
+ * may not be ready yet (e.g. with FSPv1)
+ */
+ node = ofnode_by_compatible(ofnode_null(), "jedec,spi-nor");
+ if (!ofnode_valid(node))
+ return log_msg_ret("Cannot find SPI flash\n", -ENOENT);
+ ret = -ENODEV;
+ } else {
+ ret = dm_spi_get_mmap(dev, &map_base, &map_size, &offset);
+ if (!ret)
+ entry->base = map_base;
+ node = dev_ofnode(dev);
+ }
+
+ /*
+ * At this point we have entry->base if ret == 0. If not, then we have
+ * the node and can look for memory-map
+ */
+ if (ret) {
+ ret = ofnode_read_u32_array(node, "memory-map", reg, 2);
+ if (ret)
+ return log_msg_ret("Cannot find memory map\n", ret);
+ entry->base = reg[0];
+ }
+
+ /* Find the place where we put the MRC cache */
+ mrc_node = ofnode_find_subnode(node, type == MRC_TYPE_NORMAL ?
+ "rw-mrc-cache" : "rw-var-mrc-cache");
+ if (!ofnode_valid(mrc_node))
+ return log_msg_ret("Cannot find node", -EPERM);
+
+ ret = ofnode_read_u32_array(mrc_node, "reg", reg, 2);
+ if (ret)
+ return log_msg_ret("Cannot find address", ret);
+ entry->offset = reg[0];
+ entry->length = reg[1];
+
+ if (devp)
+ *devp = dev;
+ debug("MRC cache type %d in '%s', offset %x, len %x, base %x\n",
+ type, dev ? dev->name : ofnode_get_name(node), entry->offset,
+ entry->length, entry->base);
+
+ return 0;
+}
+
+static int mrccache_save_type(enum mrc_type_t type)
+{
+ struct mrc_data_container *cache;
+ struct mrc_output *mrc;
+ struct mrc_region entry;
+ struct udevice *sf;
+ int ret;
+
+ mrc = &gd->arch.mrc[type];
+ if (!mrc->len)
+ return 0;
+ log_debug("Saving %#x bytes of MRC output data type %d to SPI flash\n",
+ mrc->len, type);
+ ret = mrccache_get_region(type, &sf, &entry);
+ if (ret)
+ return log_msg_ret("Cannot get region", ret);
+ ret = device_probe(sf);
+ if (ret)
+ return log_msg_ret("Cannot probe device", ret);
+ cache = mrc->cache;
+
+ ret = mrccache_update(sf, &entry, cache);
+ if (!ret)
+ debug("Saved MRC data with checksum %04x\n", cache->checksum);
+ else if (ret == -EEXIST)
+ debug("MRC data is the same as last time, skipping save\n");
+
+ return 0;
+}
+
+int mrccache_save(void)
+{
+ int i;
+
+ for (i = 0; i < MRC_TYPE_COUNT; i++) {
+ int ret;
+
+ ret = mrccache_save_type(i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mrccache_spl_save(void)
+{
+ int i;
+
+ for (i = 0; i < MRC_TYPE_COUNT; i++) {
+ struct mrc_output *mrc = &gd->arch.mrc[i];
+ void *data;
+ int size;
+
+ size = mrc->len + MRC_DATA_HEADER_SIZE;
+ data = malloc(size);
+ if (!data)
+ return log_msg_ret("Allocate MRC cache block", -ENOMEM);
+ mrccache_setup(mrc, data);
+ }
+
+ return mrccache_save();
+}
diff --git a/roms/u-boot/arch/x86/lib/northbridge-uclass.c b/roms/u-boot/arch/x86/lib/northbridge-uclass.c
new file mode 100644
index 000000000..383888724
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/northbridge-uclass.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/root.h>
+
+UCLASS_DRIVER(northbridge) = {
+ .id = UCLASS_NORTHBRIDGE,
+ .name = "northbridge",
+};
diff --git a/roms/u-boot/arch/x86/lib/physmem.c b/roms/u-boot/arch/x86/lib/physmem.c
new file mode 100644
index 000000000..c11101b44
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/physmem.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <physmem.h>
+#include <asm/cpu.h>
+#include <asm/global_data.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Large pages are 2MB. */
+#define LARGE_PAGE_SIZE ((1 << 20) * 2)
+
+/*
+ * Paging data structures.
+ */
+
+struct pdpe {
+ uint64_t p:1;
+ uint64_t mbz_0:2;
+ uint64_t pwt:1;
+ uint64_t pcd:1;
+ uint64_t mbz_1:4;
+ uint64_t avl:3;
+ uint64_t base:40;
+ uint64_t mbz_2:12;
+};
+
+typedef struct pdpe pdpt_t[512];
+
+struct pde {
+ uint64_t p:1; /* present */
+ uint64_t rw:1; /* read/write */
+ uint64_t us:1; /* user/supervisor */
+ uint64_t pwt:1; /* page-level writethrough */
+ uint64_t pcd:1; /* page-level cache disable */
+ uint64_t a:1; /* accessed */
+ uint64_t d:1; /* dirty */
+ uint64_t ps:1; /* page size */
+ uint64_t g:1; /* global page */
+ uint64_t avl:3; /* available to software */
+ uint64_t pat:1; /* page-attribute table */
+ uint64_t mbz_0:8; /* must be zero */
+ uint64_t base:31; /* base address */
+};
+
+typedef struct pde pdt_t[512];
+
+static pdpt_t pdpt __aligned(4096);
+static pdt_t pdts[4] __aligned(4096);
+
+/*
+ * Map a virtual address to a physical address and optionally invalidate any
+ * old mapping.
+ *
+ * @param virt The virtual address to use.
+ * @param phys The physical address to use.
+ * @param invlpg Whether to use invlpg to clear any old mappings.
+ */
+static void x86_phys_map_page(uintptr_t virt, phys_addr_t phys, int invlpg)
+{
+ /* Extract the two bit PDPT index and the 9 bit PDT index. */
+ uintptr_t pdpt_idx = (virt >> 30) & 0x3;
+ uintptr_t pdt_idx = (virt >> 21) & 0x1ff;
+
+ /* Set up a handy pointer to the appropriate PDE. */
+ struct pde *pde = &(pdts[pdpt_idx][pdt_idx]);
+
+ memset(pde, 0, sizeof(struct pde));
+ pde->p = 1;
+ pde->rw = 1;
+ pde->us = 1;
+ pde->ps = 1;
+ pde->base = phys >> 21;
+
+ if (invlpg) {
+ /* Flush any stale mapping out of the TLBs. */
+ __asm__ __volatile__(
+ "invlpg %0\n\t"
+ :
+ : "m" (*(uint8_t *)virt)
+ );
+ }
+}
+
+/* Identity map the lower 4GB and turn on paging with PAE. */
+static void x86_phys_enter_paging(void)
+{
+ phys_addr_t page_addr;
+ unsigned i;
+
+ /* Zero out the page tables. */
+ memset(pdpt, 0, sizeof(pdpt));
+ memset(pdts, 0, sizeof(pdts));
+
+ /* Set up the PDPT. */
+ for (i = 0; i < ARRAY_SIZE(pdts); i++) {
+ pdpt[i].p = 1;
+ pdpt[i].base = ((uintptr_t)&pdts[i]) >> 12;
+ }
+
+ /* Identity map everything up to 4GB. */
+ for (page_addr = 0; page_addr < (1ULL << 32);
+ page_addr += LARGE_PAGE_SIZE) {
+ /* There's no reason to invalidate the TLB with paging off. */
+ x86_phys_map_page(page_addr, page_addr, 0);
+ }
+
+ cpu_enable_paging_pae((ulong)pdpt);
+}
+
+/* Disable paging and PAE mode. */
+static void x86_phys_exit_paging(void)
+{
+ cpu_disable_paging_pae();
+}
+
+/*
+ * Set physical memory to a particular value when the whole region fits on one
+ * page.
+ *
+ * @param map_addr The address that starts the physical page.
+ * @param offset How far into that page to start setting a value.
+ * @param c The value to set memory to.
+ * @param size The size in bytes of the area to set.
+ */
+static void x86_phys_memset_page(phys_addr_t map_addr, uintptr_t offset, int c,
+ unsigned size)
+{
+ /*
+ * U-Boot should be far away from the beginning of memory, so that's a
+ * good place to map our window on top of.
+ */
+ const uintptr_t window = LARGE_PAGE_SIZE;
+
+ /* Make sure the window is below U-Boot. */
+ assert(window + LARGE_PAGE_SIZE <
+ gd->relocaddr - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_STACK_SIZE);
+ /* Map the page into the window and then memset the appropriate part. */
+ x86_phys_map_page(window, map_addr, 1);
+ memset((void *)(window + offset), c, size);
+}
+
+/*
+ * A physical memory anologue to memset with matching parameters and return
+ * value.
+ */
+phys_addr_t arch_phys_memset(phys_addr_t start, int c, phys_size_t size)
+{
+ const phys_addr_t max_addr = (phys_addr_t)~(uintptr_t)0;
+ const phys_addr_t orig_start = start;
+
+ if (!size)
+ return orig_start;
+
+ /* Handle memory below 4GB. */
+ if (start <= max_addr) {
+ phys_size_t low_size = min(max_addr + 1 - start, size);
+ void *start_ptr = (void *)(uintptr_t)start;
+
+ assert(((phys_addr_t)(uintptr_t)start) == start);
+ memset(start_ptr, c, low_size);
+ start += low_size;
+ size -= low_size;
+ }
+
+ /* Use paging and PAE to handle memory above 4GB up to 64GB. */
+ if (size) {
+ phys_addr_t map_addr = start & ~(LARGE_PAGE_SIZE - 1);
+ phys_addr_t offset = start - map_addr;
+
+ x86_phys_enter_paging();
+
+ /* Handle the first partial page. */
+ if (offset) {
+ phys_addr_t end =
+ min(map_addr + LARGE_PAGE_SIZE, start + size);
+ phys_size_t cur_size = end - start;
+ x86_phys_memset_page(map_addr, offset, c, cur_size);
+ size -= cur_size;
+ map_addr += LARGE_PAGE_SIZE;
+ }
+ /* Handle the complete pages. */
+ while (size > LARGE_PAGE_SIZE) {
+ x86_phys_memset_page(map_addr, 0, c, LARGE_PAGE_SIZE);
+ size -= LARGE_PAGE_SIZE;
+ map_addr += LARGE_PAGE_SIZE;
+ }
+ /* Handle the last partial page. */
+ if (size)
+ x86_phys_memset_page(map_addr, 0, c, size);
+
+ x86_phys_exit_paging();
+ }
+ return orig_start;
+}
diff --git a/roms/u-boot/arch/x86/lib/pinctrl_ich6.c b/roms/u-boot/arch/x86/lib/pinctrl_ich6.c
new file mode 100644
index 000000000..fd5e311b2
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/pinctrl_ich6.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <pch.h>
+#include <pci.h>
+#include <asm/cpu.h>
+#include <asm/global_data.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define GPIO_USESEL_OFFSET(x) (x)
+#define GPIO_IOSEL_OFFSET(x) (x + 4)
+#define GPIO_LVL_OFFSET(x) ((x) ? (x) + 8 : 0xc)
+#define GPI_INV 0x2c
+
+#define IOPAD_MODE_MASK 0x7
+#define IOPAD_PULL_ASSIGN_SHIFT 7
+#define IOPAD_PULL_ASSIGN_MASK (0x3 << IOPAD_PULL_ASSIGN_SHIFT)
+#define IOPAD_PULL_STRENGTH_SHIFT 9
+#define IOPAD_PULL_STRENGTH_MASK (0x3 << IOPAD_PULL_STRENGTH_SHIFT)
+
+static int ich6_pinctrl_set_value(uint16_t base, unsigned offset, int value)
+{
+ if (value)
+ setio_32(base, 1UL << offset);
+ else
+ clrio_32(base, 1UL << offset);
+
+ return 0;
+}
+
+static int ich6_pinctrl_set_function(uint16_t base, unsigned offset, int func)
+{
+ if (func)
+ setio_32(base, 1UL << offset);
+ else
+ clrio_32(base, 1UL << offset);
+
+ return 0;
+}
+
+static int ich6_pinctrl_set_direction(uint16_t base, unsigned offset, int dir)
+{
+ if (!dir)
+ setio_32(base, 1UL << offset);
+ else
+ clrio_32(base, 1UL << offset);
+
+ return 0;
+}
+
+static int ich6_pinctrl_cfg_pin(s32 gpiobase, s32 iobase, int pin_node)
+{
+ bool is_gpio, invert;
+ u32 gpio_offset[2];
+ int pad_offset;
+ int dir, val;
+ int ret;
+
+ /*
+ * GPIO node is not mandatory, so we only do the pinmuxing if the
+ * node exists.
+ */
+ ret = fdtdec_get_int_array(gd->fdt_blob, pin_node, "gpio-offset",
+ gpio_offset, 2);
+ if (!ret) {
+ /* Do we want to force the GPIO mode? */
+ is_gpio = fdtdec_get_bool(gd->fdt_blob, pin_node, "mode-gpio");
+ if (is_gpio)
+ ich6_pinctrl_set_function(GPIO_USESEL_OFFSET(gpiobase) +
+ gpio_offset[0], gpio_offset[1],
+ 1);
+
+ dir = fdtdec_get_int(gd->fdt_blob, pin_node, "direction", -1);
+ if (dir != -1)
+ ich6_pinctrl_set_direction(GPIO_IOSEL_OFFSET(gpiobase) +
+ gpio_offset[0], gpio_offset[1],
+ dir);
+
+ val = fdtdec_get_int(gd->fdt_blob, pin_node, "output-value",
+ -1);
+ if (val != -1)
+ ich6_pinctrl_set_value(GPIO_LVL_OFFSET(gpiobase) +
+ gpio_offset[0], gpio_offset[1],
+ val);
+
+ invert = fdtdec_get_bool(gd->fdt_blob, pin_node, "invert");
+ if (invert)
+ setio_32(gpiobase + GPI_INV, 1 << gpio_offset[1]);
+ debug("gpio %#x bit %d, is_gpio %d, dir %d, val %d, invert %d\n",
+ gpio_offset[0], gpio_offset[1], is_gpio, dir, val,
+ invert);
+ }
+
+ /* if iobase is present, let's configure the pad */
+ if (iobase != -1) {
+ ulong iobase_addr;
+
+ /*
+ * The offset for the same pin for the IOBASE and GPIOBASE are
+ * different, so instead of maintaining a lookup table,
+ * the device tree should provide directly the correct
+ * value for both mapping.
+ */
+ pad_offset = fdtdec_get_int(gd->fdt_blob, pin_node,
+ "pad-offset", -1);
+ if (pad_offset == -1)
+ return 0;
+
+ /* compute the absolute pad address */
+ iobase_addr = iobase + pad_offset;
+
+ /*
+ * Do we need to set a specific function mode?
+ * If someone put also 'mode-gpio', this option will
+ * be just ignored by the controller
+ */
+ val = fdtdec_get_int(gd->fdt_blob, pin_node, "mode-func", -1);
+ if (val != -1)
+ clrsetbits_le32(iobase_addr, IOPAD_MODE_MASK, val);
+
+ /* Configure the pull-up/down if needed */
+ val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-assign", -1);
+ if (val != -1)
+ clrsetbits_le32(iobase_addr,
+ IOPAD_PULL_ASSIGN_MASK,
+ val << IOPAD_PULL_ASSIGN_SHIFT);
+
+ val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-strength",
+ -1);
+ if (val != -1)
+ clrsetbits_le32(iobase_addr,
+ IOPAD_PULL_STRENGTH_MASK,
+ val << IOPAD_PULL_STRENGTH_SHIFT);
+
+ debug("%s: pad cfg [0x%x]: %08x\n", __func__, pad_offset,
+ readl(iobase_addr));
+ }
+
+ return 0;
+}
+
+static int ich6_pinctrl_probe(struct udevice *dev)
+{
+ struct udevice *pch;
+ int pin_node;
+ int ret;
+ u32 gpiobase;
+ u32 iobase = -1;
+
+ debug("%s: start\n", __func__);
+ ret = uclass_first_device(UCLASS_PCH, &pch);
+ if (ret)
+ return ret;
+ if (!pch)
+ return -ENODEV;
+
+ /*
+ * Get the memory/io base address to configure every pins.
+ * IOBASE is used to configure the mode/pads
+ * GPIOBASE is used to configure the direction and default value
+ */
+ ret = pch_get_gpio_base(pch, &gpiobase);
+ if (ret) {
+ debug("%s: invalid GPIOBASE address (%08x)\n", __func__,
+ gpiobase);
+ return -EINVAL;
+ }
+
+ /*
+ * Get the IOBASE, this is not mandatory as this is not
+ * supported by all the CPU
+ */
+ ret = pch_get_io_base(pch, &iobase);
+ if (ret && ret != -ENOSYS) {
+ debug("%s: invalid IOBASE address (%08x)\n", __func__, iobase);
+ return -EINVAL;
+ }
+
+ for (pin_node = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev));
+ pin_node > 0;
+ pin_node = fdt_next_subnode(gd->fdt_blob, pin_node)) {
+ /* Configure the pin */
+ ret = ich6_pinctrl_cfg_pin(gpiobase, iobase, pin_node);
+ if (ret != 0) {
+ debug("%s: invalid configuration for the pin %d\n",
+ __func__, pin_node);
+ return ret;
+ }
+ }
+ debug("%s: done\n", __func__);
+
+ return 0;
+}
+
+static const struct udevice_id ich6_pinctrl_match[] = {
+ { .compatible = "intel,x86-pinctrl", .data = X86_SYSCON_PINCONF },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(ich6_pinctrl) = {
+ .name = "ich6_pinctrl",
+ .id = UCLASS_SYSCON,
+ .of_match = ich6_pinctrl_match,
+ .probe = ich6_pinctrl_probe,
+};
diff --git a/roms/u-boot/arch/x86/lib/pirq_routing.c b/roms/u-boot/arch/x86/lib/pirq_routing.c
new file mode 100644
index 000000000..caeaec928
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/pirq_routing.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * Part of this file is ported from coreboot src/arch/x86/boot/pirq_routing.c
+ */
+
+#include <common.h>
+#include <log.h>
+#include <pci.h>
+#include <asm/global_data.h>
+#include <asm/pci.h>
+#include <asm/pirq_routing.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u8 pirq_get_next_free_irq(struct udevice *dev, u8 *pirq, u16 bitmap,
+ bool irq_already_routed[])
+{
+ int i, link;
+ u8 irq = 0;
+
+ /* IRQ sharing starts from IRQ#3 */
+ for (i = 3; i < 16; i++) {
+ /* Can we assign this IRQ? */
+ if (!((bitmap >> i) & 1))
+ continue;
+
+ /* We can, now let's assume we can use this IRQ */
+ irq = i;
+
+ /* Have we already routed it? */
+ if (irq_already_routed[irq])
+ continue;
+
+ for (link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) {
+ if (pirq_check_irq_routed(dev, link, irq)) {
+ irq_already_routed[irq] = true;
+ break;
+ }
+ }
+
+ /* If it's not yet routed, use it */
+ if (!irq_already_routed[irq]) {
+ irq_already_routed[irq] = true;
+ break;
+ }
+
+ /* But if it was already routed, try the next one */
+ }
+
+ /* Now we get our IRQ */
+ return irq;
+}
+
+void pirq_route_irqs(struct udevice *dev, struct irq_info *irq, int num)
+{
+ unsigned char irq_slot[MAX_INTX_ENTRIES];
+ unsigned char pirq[CONFIG_MAX_PIRQ_LINKS];
+ bool irq_already_routed[16];
+ int i, intx;
+
+ memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS);
+ memset(irq_already_routed, '\0', sizeof(irq_already_routed));
+
+ /* Set PCI IRQs */
+ for (i = 0; i < num; i++) {
+ debug("PIRQ Entry %d Dev: %d.%x.%d\n", i,
+ irq->bus, irq->devfn >> 3, irq->devfn & 7);
+
+ for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) {
+ int link = irq->irq[intx].link;
+ int bitmap = irq->irq[intx].bitmap;
+ int irq = 0;
+
+ debug("INT%c link: %x bitmap: %x ",
+ 'A' + intx, link, bitmap);
+
+ if (!bitmap || !link) {
+ debug("not routed\n");
+ irq_slot[intx] = irq;
+ continue;
+ }
+
+ /* translate link value to link number */
+ link = pirq_translate_link(dev, link);
+
+ /* yet not routed */
+ if (!pirq[link]) {
+ irq = pirq_get_next_free_irq(dev, pirq, bitmap,
+ irq_already_routed);
+ pirq[link] = irq;
+ } else {
+ irq = pirq[link];
+ }
+
+ debug("IRQ: %d\n", irq);
+ irq_slot[intx] = irq;
+
+ /* Assign IRQ in the interrupt router */
+ pirq_assign_irq(dev, link, irq);
+ }
+
+ /* Bus, device, slots IRQs for {A,B,C,D} */
+ pci_assign_irqs(irq->bus, irq->devfn >> 3, irq_slot);
+
+ irq++;
+ }
+
+ for (i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++)
+ debug("PIRQ%c: %d\n", 'A' + i, pirq[i]);
+}
+
+u32 copy_pirq_routing_table(u32 addr, struct irq_routing_table *rt)
+{
+ struct irq_routing_table *rom_rt;
+
+ /* Align the table to be 16 byte aligned */
+ addr = ALIGN(addr, 16);
+
+ debug("Copying Interrupt Routing Table to 0x%x\n", addr);
+ memcpy((void *)(uintptr_t)addr, rt, rt->size);
+
+ /*
+ * We do the sanity check here against the copied table after memcpy,
+ * as something might go wrong after the memcpy, which is normally
+ * due to the F segment decode is not turned on to systeam RAM.
+ */
+ rom_rt = (struct irq_routing_table *)(uintptr_t)addr;
+ if (rom_rt->signature != PIRQ_SIGNATURE ||
+ rom_rt->version != PIRQ_VERSION || rom_rt->size % 16) {
+ printf("Interrupt Routing Table not valid\n");
+ return addr;
+ }
+
+ return addr + rt->size;
+}
+
+ulong write_pirq_routing_table(ulong addr)
+{
+ if (!gd->arch.pirq_routing_table)
+ return addr;
+
+ return copy_pirq_routing_table(addr, gd->arch.pirq_routing_table);
+}
diff --git a/roms/u-boot/arch/x86/lib/pmu.c b/roms/u-boot/arch/x86/lib/pmu.c
new file mode 100644
index 000000000..083aec8d8
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/pmu.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Intel Corporation
+ */
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/cpu.h>
+#include <asm/pmu.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+/* Registers */
+struct pmu_regs {
+ u32 sts;
+ u32 cmd;
+ u32 ics;
+ u32 reserved;
+ u32 wkc[4];
+ u32 wks[4];
+ u32 ssc[4];
+ u32 sss[4];
+};
+
+/* Bits in PMU_REGS_STS */
+#define PMU_REGS_STS_BUSY (1 << 8)
+
+struct pmu_mid {
+ struct pmu_regs *regs;
+};
+
+static int pmu_read_status(struct pmu_regs *regs)
+{
+ int retry = 500000;
+ u32 val;
+
+ do {
+ val = readl(&regs->sts);
+ if (!(val & PMU_REGS_STS_BUSY))
+ return 0;
+
+ udelay(1);
+ } while (--retry);
+
+ printf("WARNING: PMU still busy\n");
+ return -EBUSY;
+}
+
+static int pmu_power_lss(struct pmu_regs *regs, unsigned int lss, bool on)
+{
+ unsigned int offset = (lss * 2) / 32;
+ unsigned int shift = (lss * 2) % 32;
+ u32 ssc;
+ int ret;
+
+ /* Check PMU status */
+ ret = pmu_read_status(regs);
+ if (ret)
+ return ret;
+
+ /* Read PMU values */
+ ssc = readl(&regs->sss[offset]);
+
+ /* Modify PMU values */
+ if (on)
+ ssc &= ~(0x3 << shift); /* D0 */
+ else
+ ssc |= 0x3 << shift; /* D3hot */
+
+ /* Write modified PMU values */
+ writel(ssc, &regs->ssc[offset]);
+
+ /* Update modified PMU values */
+ writel(0x00002201, &regs->cmd);
+
+ /* Check PMU status */
+ return pmu_read_status(regs);
+}
+
+int pmu_turn_power(unsigned int lss, bool on)
+{
+ struct pmu_mid *pmu;
+ struct udevice *dev;
+ int ret;
+
+ ret = syscon_get_by_driver_data(X86_SYSCON_PMU, &dev);
+ if (ret)
+ return ret;
+
+ pmu = dev_get_priv(dev);
+
+ return pmu_power_lss(pmu->regs, lss, on);
+}
+
+static int pmu_mid_probe(struct udevice *dev)
+{
+ struct pmu_mid *pmu = dev_get_priv(dev);
+
+ pmu->regs = syscon_get_first_range(X86_SYSCON_PMU);
+
+ return 0;
+}
+
+static const struct udevice_id pmu_mid_match[] = {
+ { .compatible = "intel,pmu-mid", .data = X86_SYSCON_PMU },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(intel_mid_pmu) = {
+ .name = "pmu_mid",
+ .id = UCLASS_SYSCON,
+ .of_match = pmu_mid_match,
+ .probe = pmu_mid_probe,
+ .priv_auto = sizeof(struct pmu_mid),
+};
diff --git a/roms/u-boot/arch/x86/lib/ramtest.c b/roms/u-boot/arch/x86/lib/ramtest.c
new file mode 100644
index 000000000..033853963
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/ramtest.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * From Coreboot src/lib/ramtest.c
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/post.h>
+
+static void write_phys(unsigned long addr, u32 value)
+{
+#if CONFIG_SSE2
+ asm volatile(
+ "movnti %1, (%0)"
+ : /* outputs */
+ : "r" (addr), "r" (value) /* inputs */
+ : /* clobbers */
+ );
+#else
+ writel(value, addr);
+#endif
+}
+
+static u32 read_phys(unsigned long addr)
+{
+ return readl(addr);
+}
+
+static void phys_memory_barrier(void)
+{
+#if CONFIG_SSE2
+ /* Needed for movnti */
+ asm volatile(
+ "sfence"
+ :
+ :
+ : "memory"
+ );
+#else
+ asm volatile(""
+ :
+ :
+ : "memory");
+#endif
+}
+
+void quick_ram_check(void)
+{
+ int fail = 0;
+ u32 backup;
+
+ backup = read_phys(CONFIG_RAMBASE);
+ write_phys(CONFIG_RAMBASE, 0x55555555);
+ phys_memory_barrier();
+ if (read_phys(CONFIG_RAMBASE) != 0x55555555)
+ fail = 1;
+ write_phys(CONFIG_RAMBASE, 0xaaaaaaaa);
+ phys_memory_barrier();
+ if (read_phys(CONFIG_RAMBASE) != 0xaaaaaaaa)
+ fail = 1;
+ write_phys(CONFIG_RAMBASE, 0x00000000);
+ phys_memory_barrier();
+ if (read_phys(CONFIG_RAMBASE) != 0x00000000)
+ fail = 1;
+ write_phys(CONFIG_RAMBASE, 0xffffffff);
+ phys_memory_barrier();
+ if (read_phys(CONFIG_RAMBASE) != 0xffffffff)
+ fail = 1;
+
+ write_phys(CONFIG_RAMBASE, backup);
+ if (fail) {
+ post_code(POST_RAM_FAILURE);
+ panic("RAM INIT FAILURE!\n");
+ }
+ phys_memory_barrier();
+}
diff --git a/roms/u-boot/arch/x86/lib/reloc_ia32_efi.c b/roms/u-boot/arch/x86/lib/reloc_ia32_efi.c
new file mode 100644
index 000000000..d56cd50bd
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/reloc_ia32_efi.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * reloc_ia32.c - position independent x86 ELF shared object relocator
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ *
+ * All rights reserved.
+ */
+
+#include <common.h>
+#include <efi.h>
+#include <elf.h>
+
+efi_status_t EFIAPI _relocate(long ldbase, Elf32_Dyn *dyn)
+{
+ long relsz = 0, relent = 0;
+ Elf32_Rel *rel = 0;
+ unsigned long *addr;
+ int i;
+
+ for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
+ switch (dyn[i].d_tag) {
+ case DT_REL:
+ rel = (Elf32_Rel *)((unsigned long)dyn[i].d_un.d_ptr +
+ ldbase);
+ break;
+
+ case DT_RELSZ:
+ relsz = dyn[i].d_un.d_val;
+ break;
+
+ case DT_RELENT:
+ relent = dyn[i].d_un.d_val;
+ break;
+
+ case DT_RELA:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!rel && relent == 0)
+ return EFI_SUCCESS;
+
+ if (!rel || relent == 0)
+ return EFI_LOAD_ERROR;
+
+ while (relsz > 0) {
+ /* apply the relocs */
+ switch (ELF32_R_TYPE(rel->r_info)) {
+ case R_386_NONE:
+ break;
+
+ case R_386_RELATIVE:
+ addr = (unsigned long *)(ldbase + rel->r_offset);
+ *addr += ldbase;
+ break;
+
+ default:
+ break;
+ }
+ rel = (Elf32_Rel *)((char *)rel + relent);
+ relsz -= relent;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/u-boot/arch/x86/lib/reloc_x86_64_efi.c b/roms/u-boot/arch/x86/lib/reloc_x86_64_efi.c
new file mode 100644
index 000000000..2694de711
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/reloc_x86_64_efi.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * reloc_x86_64.c - position independent x86_64 ELF shared object relocator
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ * Copyright (C) 2005 Intel Co.
+ * Contributed by Fenghua Yu <fenghua.yu@intel.com>.
+ *
+ * All rights reserved.
+ */
+
+#include <common.h>
+#include <efi.h>
+#include <elf.h>
+
+efi_status_t EFIAPI _relocate(long ldbase, Elf64_Dyn *dyn)
+{
+ long relsz = 0, relent = 0;
+ Elf64_Rel *rel = 0;
+ unsigned long *addr;
+ int i;
+
+ for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
+ switch (dyn[i].d_tag) {
+ case DT_RELA:
+ rel = (Elf64_Rel *)
+ ((unsigned long)dyn[i].d_un.d_ptr + ldbase);
+ break;
+ case DT_RELASZ:
+ relsz = dyn[i].d_un.d_val;
+ break;
+ case DT_RELAENT:
+ relent = dyn[i].d_un.d_val;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!rel && relent == 0)
+ return EFI_SUCCESS;
+
+ if (!rel || relent == 0)
+ return EFI_LOAD_ERROR;
+
+ while (relsz > 0) {
+ /* apply the relocs */
+ switch (ELF64_R_TYPE(rel->r_info)) {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_RELATIVE:
+ addr = (unsigned long *)(ldbase + rel->r_offset);
+ *addr += ldbase;
+ break;
+ default:
+ break;
+ }
+ rel = (Elf64_Rel *)((char *)rel + relent);
+ relsz -= relent;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/u-boot/arch/x86/lib/relocate.c b/roms/u-boot/arch/x86/lib/relocate.c
new file mode 100644
index 000000000..6fe515164
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/relocate.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2008-2011
+ * Graeme Russ, <graeme.russ@gmail.com>
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <relocate.h>
+#include <asm/global_data.h>
+#include <asm/u-boot-x86.h>
+#include <asm/sections.h>
+#include <elf.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int copy_uboot_to_ram(void)
+{
+ size_t len = (uintptr_t)&__data_end - (uintptr_t)&__text_start;
+
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ return 0;
+ memcpy((void *)gd->relocaddr, (void *)&__text_start, len);
+
+ return 0;
+}
+
+int clear_bss(void)
+{
+ ulong dst_addr = (ulong)&__bss_start + gd->reloc_off;
+ size_t len = (uintptr_t)&__bss_end - (uintptr_t)&__bss_start;
+
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ return 0;
+ memset((void *)dst_addr, 0x00, len);
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(X86_64)
+static void do_elf_reloc_fixups64(unsigned int text_base, uintptr_t size,
+ Elf64_Rela *re_src, Elf64_Rela *re_end)
+{
+ Elf64_Addr *offset_ptr_rom, *last_offset = NULL;
+ Elf64_Addr *offset_ptr_ram;
+
+ do {
+ unsigned long long type = ELF64_R_TYPE(re_src->r_info);
+
+ if (type != R_X86_64_RELATIVE) {
+ printf("%s: unsupported relocation type 0x%llx "
+ "at %p, ", __func__, type, re_src);
+ printf("offset = 0x%llx\n", re_src->r_offset);
+ continue;
+ }
+
+ /* Get the location from the relocation entry */
+ offset_ptr_rom = (Elf64_Addr *)(uintptr_t)re_src->r_offset;
+
+ /* Check that the location of the relocation is in .text */
+ if (offset_ptr_rom >= (Elf64_Addr *)(uintptr_t)text_base &&
+ offset_ptr_rom > last_offset) {
+ /* Switch to the in-RAM version */
+ offset_ptr_ram = (Elf64_Addr *)((ulong)offset_ptr_rom +
+ gd->reloc_off);
+
+ /* Check that the target points into .text */
+ if (*offset_ptr_ram >= text_base &&
+ *offset_ptr_ram <= text_base + size) {
+ *offset_ptr_ram = gd->reloc_off +
+ re_src->r_addend;
+ } else {
+ debug(" %p: %lx: rom reloc %lx, ram %p, value %lx, limit %lX\n",
+ re_src, (ulong)re_src->r_info,
+ (ulong)re_src->r_offset, offset_ptr_ram,
+ (ulong)*offset_ptr_ram, text_base + size);
+ }
+ } else {
+ debug(" %p: %lx: rom reloc %lx, last %p\n", re_src,
+ (ulong)re_src->r_info, (ulong)re_src->r_offset,
+ last_offset);
+ }
+ last_offset = offset_ptr_rom;
+
+ } while (++re_src < re_end);
+}
+#else
+static void do_elf_reloc_fixups32(unsigned int text_base, uintptr_t size,
+ Elf32_Rel *re_src, Elf32_Rel *re_end)
+{
+ Elf32_Addr *offset_ptr_rom, *last_offset = NULL;
+ Elf32_Addr *offset_ptr_ram;
+
+ do {
+ unsigned int type = ELF32_R_TYPE(re_src->r_info);
+
+ if (type != R_386_RELATIVE) {
+ printf("%s: unsupported relocation type 0x%x "
+ "at %p, ", __func__, type, re_src);
+ printf("offset = 0x%x\n", re_src->r_offset);
+ continue;
+ }
+
+ /* Get the location from the relocation entry */
+ offset_ptr_rom = (Elf32_Addr *)(uintptr_t)re_src->r_offset;
+
+ /* Check that the location of the relocation is in .text */
+ if (offset_ptr_rom >= (Elf32_Addr *)(uintptr_t)text_base &&
+ offset_ptr_rom > last_offset) {
+
+ /* Switch to the in-RAM version */
+ offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom +
+ gd->reloc_off);
+
+ /* Check that the target points into .text */
+ if (*offset_ptr_ram >= text_base &&
+ *offset_ptr_ram <= text_base + size) {
+ *offset_ptr_ram += gd->reloc_off;
+ } else {
+ debug(" %p: rom reloc %x, ram %p, value %x, limit %lX\n",
+ re_src, re_src->r_offset, offset_ptr_ram,
+ *offset_ptr_ram, text_base + size);
+ }
+ } else {
+ debug(" %p: rom reloc %x, last %p\n", re_src,
+ re_src->r_offset, last_offset);
+ }
+ last_offset = offset_ptr_rom;
+
+ } while (++re_src < re_end);
+}
+#endif
+
+/*
+ * This function has more error checking than you might expect. Please see
+ * this commit message for more information:
+ * 62f7970a x86: Add error checking to x86 relocation code
+ */
+int do_elf_reloc_fixups(void)
+{
+ void *re_src = (void *)(&__rel_dyn_start);
+ void *re_end = (void *)(&__rel_dyn_end);
+ uint text_base;
+
+ /* The size of the region of u-boot that runs out of RAM. */
+ uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start;
+
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ return 0;
+ if (re_src == re_end)
+ panic("No relocation data");
+
+#ifdef CONFIG_SYS_TEXT_BASE
+ text_base = CONFIG_SYS_TEXT_BASE;
+#else
+ panic("No CONFIG_SYS_TEXT_BASE");
+#endif
+#if CONFIG_IS_ENABLED(X86_64)
+ do_elf_reloc_fixups64(text_base, size, re_src, re_end);
+#else
+ do_elf_reloc_fixups32(text_base, size, re_src, re_end);
+#endif
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/scu.c b/roms/u-boot/arch/x86/lib/scu.c
new file mode 100644
index 000000000..90ef239bc
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/scu.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Intel Mobile Internet Devices (MID) based on Intel Atom SoCs have few
+ * microcontrollers inside to do some auxiliary tasks. One of such
+ * microcontroller is System Controller Unit (SCU) which, in particular,
+ * is servicing watchdog and controlling system reset function.
+ *
+ * This driver enables IPC channel to SCU.
+ */
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/cpu.h>
+#include <asm/scu.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+/* SCU register map */
+struct ipc_regs {
+ u32 cmd;
+ u32 status;
+ u32 sptr;
+ u32 dptr;
+ u32 reserved[28];
+ u32 wbuf[4];
+ u32 rbuf[4];
+};
+
+struct scu {
+ struct ipc_regs *regs;
+};
+
+/**
+ * scu_ipc_send_command() - send command to SCU
+ * @regs: register map of SCU
+ * @cmd: command
+ *
+ * Command Register (Write Only):
+ * A write to this register results in an interrupt to the SCU core processor
+ * Format:
+ * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
+ */
+static void scu_ipc_send_command(struct ipc_regs *regs, u32 cmd)
+{
+ writel(cmd, &regs->cmd);
+}
+
+/**
+ * scu_ipc_check_status() - check status of last command
+ * @regs: register map of SCU
+ *
+ * Status Register (Read Only):
+ * Driver will read this register to get the ready/busy status of the IPC
+ * block and error status of the IPC command that was just processed by SCU
+ * Format:
+ * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
+ */
+static int scu_ipc_check_status(struct ipc_regs *regs)
+{
+ int loop_count = 100000;
+ int status;
+
+ do {
+ status = readl(&regs->status);
+ if (!(status & BIT(0)))
+ break;
+
+ udelay(1);
+ } while (--loop_count);
+ if (!loop_count)
+ return -ETIMEDOUT;
+
+ if (status & BIT(1)) {
+ printf("%s() status=0x%08x\n", __func__, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int scu_ipc_cmd(struct ipc_regs *regs, u32 cmd, u32 sub,
+ u32 *in, int inlen, u32 *out, int outlen)
+{
+ int i, err;
+
+ for (i = 0; i < inlen; i++)
+ writel(*in++, &regs->wbuf[i]);
+
+ scu_ipc_send_command(regs, (inlen << 16) | (sub << 12) | cmd);
+ err = scu_ipc_check_status(regs);
+
+ if (!err) {
+ for (i = 0; i < outlen; i++)
+ *out++ = readl(&regs->rbuf[i]);
+ }
+
+ return err;
+}
+
+/**
+ * scu_ipc_raw_command() - IPC command with data and pointers
+ * @cmd: IPC command code
+ * @sub: IPC command sub type
+ * @in: input data of this IPC command
+ * @inlen: input data length in dwords
+ * @out: output data of this IPC command
+ * @outlen: output data length in dwords
+ * @dptr: data writing to SPTR register
+ * @sptr: data writing to DPTR register
+ *
+ * Send an IPC command to SCU with input/output data and source/dest pointers.
+ *
+ * Return: an IPC error code or 0 on success.
+ */
+int scu_ipc_raw_command(u32 cmd, u32 sub, u32 *in, int inlen, u32 *out,
+ int outlen, u32 dptr, u32 sptr)
+{
+ int inbuflen = DIV_ROUND_UP(inlen, 4);
+ struct udevice *dev;
+ struct scu *scu;
+ int ret;
+
+ ret = syscon_get_by_driver_data(X86_SYSCON_SCU, &dev);
+ if (ret)
+ return ret;
+
+ scu = dev_get_priv(dev);
+
+ /* Up to 16 bytes */
+ if (inbuflen > 4)
+ return -EINVAL;
+
+ writel(dptr, &scu->regs->dptr);
+ writel(sptr, &scu->regs->sptr);
+
+ /*
+ * SRAM controller doesn't support 8-bit writes, it only
+ * supports 32-bit writes, so we have to copy input data into
+ * the temporary buffer, and SCU FW will use the inlen to
+ * determine the actual input data length in the temporary
+ * buffer.
+ */
+
+ u32 inbuf[4] = {0};
+
+ memcpy(inbuf, in, inlen);
+
+ return scu_ipc_cmd(scu->regs, cmd, sub, inbuf, inlen, out, outlen);
+}
+
+/**
+ * scu_ipc_simple_command() - send a simple command
+ * @cmd: command
+ * @sub: sub type
+ *
+ * Issue a simple command to the SCU. Do not use this interface if
+ * you must then access data as any data values may be overwritten
+ * by another SCU access by the time this function returns.
+ *
+ * This function may sleep. Locking for SCU accesses is handled for
+ * the caller.
+ */
+int scu_ipc_simple_command(u32 cmd, u32 sub)
+{
+ struct scu *scu;
+ struct udevice *dev;
+ int ret;
+
+ ret = syscon_get_by_driver_data(X86_SYSCON_SCU, &dev);
+ if (ret)
+ return ret;
+
+ scu = dev_get_priv(dev);
+
+ scu_ipc_send_command(scu->regs, sub << 12 | cmd);
+ return scu_ipc_check_status(scu->regs);
+}
+
+/**
+ * scu_ipc_command - command with data
+ * @cmd: command
+ * @sub: sub type
+ * @in: input data
+ * @inlen: input length in dwords
+ * @out: output data
+ * @outlen: output length in dwords
+ *
+ * Issue a command to the SCU which involves data transfers.
+ */
+int scu_ipc_command(u32 cmd, u32 sub, u32 *in, int inlen, u32 *out, int outlen)
+{
+ struct scu *scu;
+ struct udevice *dev;
+ int ret;
+
+ ret = syscon_get_by_driver_data(X86_SYSCON_SCU, &dev);
+ if (ret)
+ return ret;
+
+ scu = dev_get_priv(dev);
+
+ return scu_ipc_cmd(scu->regs, cmd, sub, in, inlen, out, outlen);
+}
+
+static int scu_ipc_probe(struct udevice *dev)
+{
+ struct scu *scu = dev_get_priv(dev);
+
+ scu->regs = syscon_get_first_range(X86_SYSCON_SCU);
+
+ return 0;
+}
+
+static const struct udevice_id scu_ipc_match[] = {
+ { .compatible = "intel,scu-ipc", .data = X86_SYSCON_SCU },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(scu_ipc) = {
+ .name = "scu_ipc",
+ .id = UCLASS_SYSCON,
+ .of_match = scu_ipc_match,
+ .probe = scu_ipc_probe,
+ .priv_auto = sizeof(struct scu),
+};
diff --git a/roms/u-boot/arch/x86/lib/sections.c b/roms/u-boot/arch/x86/lib/sections.c
new file mode 100644
index 000000000..375029ead
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/sections.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
+ */
+#include <linux/compiler.h>
+
+char __efi_runtime_start[0] __section(".__efi_runtime_start");
+char __efi_runtime_stop[0] __section(".__efi_runtime_stop");
+char __efi_runtime_rel_start[0]
+ __section(".__efi_runtime_rel_start");
+char __efi_runtime_rel_stop[0]
+ __section(".__efi_runtime_rel_stop");
diff --git a/roms/u-boot/arch/x86/lib/sfi.c b/roms/u-boot/arch/x86/lib/sfi.c
new file mode 100644
index 000000000..85e963b63
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/sfi.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+/*
+ * Intel Simple Firmware Interface (SFI)
+ *
+ * Yet another way to pass information to the Linux kernel.
+ *
+ * See https://simplefirmware.org/ for details
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <asm/cpu.h>
+#include <asm/ioapic.h>
+#include <asm/sfi.h>
+#include <asm/tables.h>
+#include <dm/uclass-internal.h>
+
+struct table_info {
+ u32 base;
+ int ptr;
+ u32 entry_start;
+ u64 table[SFI_TABLE_MAX_ENTRIES];
+ int count;
+};
+
+static void *get_entry_start(struct table_info *tab)
+{
+ if (tab->count == SFI_TABLE_MAX_ENTRIES)
+ return NULL;
+ tab->entry_start = tab->base + tab->ptr;
+ tab->table[tab->count] = tab->entry_start;
+ tab->entry_start += sizeof(struct sfi_table_header);
+
+ return (void *)(uintptr_t)tab->entry_start;
+}
+
+static void finish_table(struct table_info *tab, const char *sig, void *entry)
+{
+ struct sfi_table_header *hdr;
+
+ hdr = (struct sfi_table_header *)(uintptr_t)(tab->base + tab->ptr);
+ strcpy(hdr->sig, sig);
+ hdr->len = sizeof(*hdr) + ((ulong)entry - tab->entry_start);
+ hdr->rev = 1;
+ strncpy(hdr->oem_id, "U-Boot", SFI_OEM_ID_SIZE);
+ strncpy(hdr->oem_table_id, "Table v1", SFI_OEM_TABLE_ID_SIZE);
+ hdr->csum = 0;
+ hdr->csum = table_compute_checksum(hdr, hdr->len);
+ tab->ptr += hdr->len;
+ tab->ptr = ALIGN(tab->ptr, 16);
+ tab->count++;
+}
+
+static int sfi_write_system_header(struct table_info *tab)
+{
+ u64 *entry = get_entry_start(tab);
+ int i;
+
+ if (!entry)
+ return -ENOSPC;
+
+ for (i = 0; i < tab->count; i++)
+ *entry++ = tab->table[i];
+ finish_table(tab, SFI_SIG_SYST, entry);
+
+ return 0;
+}
+
+static int sfi_write_cpus(struct table_info *tab)
+{
+ struct sfi_cpu_table_entry *entry = get_entry_start(tab);
+ struct udevice *dev;
+ int count = 0;
+
+ if (!entry)
+ return -ENOSPC;
+
+ for (uclass_find_first_device(UCLASS_CPU, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+
+ if (!device_active(dev))
+ continue;
+ entry->apic_id = plat->cpu_id;
+ entry++;
+ count++;
+ }
+
+ /* Omit the table if there is only one CPU */
+ if (count > 1)
+ finish_table(tab, SFI_SIG_CPUS, entry);
+
+ return 0;
+}
+
+static int sfi_write_apic(struct table_info *tab)
+{
+ struct sfi_apic_table_entry *entry = get_entry_start(tab);
+
+ if (!entry)
+ return -ENOSPC;
+
+ entry->phys_addr = IO_APIC_ADDR;
+ entry++;
+ finish_table(tab, SFI_SIG_APIC, entry);
+
+ return 0;
+}
+
+static int sfi_write_xsdt(struct table_info *tab)
+{
+ struct sfi_xsdt_header *entry = get_entry_start(tab);
+
+ if (!entry)
+ return -ENOSPC;
+
+ entry->oem_revision = 1;
+ entry->creator_id = 1;
+ entry->creator_revision = 1;
+ entry++;
+ finish_table(tab, SFI_SIG_XSDT, entry);
+
+ return 0;
+}
+
+ulong write_sfi_table(ulong base)
+{
+ struct table_info table;
+
+ table.base = base;
+ table.ptr = 0;
+ table.count = 0;
+ sfi_write_cpus(&table);
+ sfi_write_apic(&table);
+
+ /*
+ * The SFI specification marks the XSDT table as option, but Linux 4.0
+ * crashes on start-up when it is not provided.
+ */
+ sfi_write_xsdt(&table);
+
+ /* Finally, write out the system header which points to the others */
+ sfi_write_system_header(&table);
+
+ return base + table.ptr;
+}
diff --git a/roms/u-boot/arch/x86/lib/spl.c b/roms/u-boot/arch/x86/lib/spl.c
new file mode 100644
index 000000000..b18c1cd60
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/spl.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 Google, Inc
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <hang.h>
+#include <image.h>
+#include <init.h>
+#include <irq_func.h>
+#include <log.h>
+#include <malloc.h>
+#include <spl.h>
+#include <syscon.h>
+#include <asm/cpu.h>
+#include <asm/cpu_common.h>
+#include <asm/global_data.h>
+#include <asm/mrccache.h>
+#include <asm/mtrr.h>
+#include <asm/pci.h>
+#include <asm/processor.h>
+#include <asm/spl.h>
+#include <asm-generic/sections.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+__weak int arch_cpu_init_dm(void)
+{
+ return 0;
+}
+
+#ifdef CONFIG_TPL
+
+static int set_max_freq(void)
+{
+ if (cpu_get_burst_mode_state() == BURST_MODE_UNAVAILABLE) {
+ /*
+ * Burst Mode has been factory-configured as disabled and is not
+ * available in this physical processor package
+ */
+ debug("Burst Mode is factory-disabled\n");
+ return -ENOENT;
+ }
+
+ /* Enable burst mode */
+ cpu_set_burst_mode(true);
+
+ /* Enable speed step */
+ cpu_set_eist(true);
+
+ /* Set P-State ratio */
+ cpu_set_p_state_to_turbo_ratio();
+
+ return 0;
+}
+#endif
+
+static int x86_spl_init(void)
+{
+#ifndef CONFIG_TPL
+ /*
+ * TODO(sjg@chromium.org): We use this area of RAM for the stack
+ * and global_data in SPL. Once U-Boot starts up and releocates it
+ * is not needed. We could make this a CONFIG option or perhaps
+ * place it immediately below CONFIG_SYS_TEXT_BASE.
+ */
+ __maybe_unused char *ptr = (char *)0x110000;
+#else
+ struct udevice *punit;
+#endif
+ int ret;
+
+ debug("%s starting\n", __func__);
+ if (IS_ENABLED(TPL))
+ ret = x86_cpu_reinit_f();
+ else
+ ret = x86_cpu_init_f();
+ ret = spl_init();
+ if (ret) {
+ debug("%s: spl_init() failed\n", __func__);
+ return ret;
+ }
+ ret = arch_cpu_init();
+ if (ret) {
+ debug("%s: arch_cpu_init() failed\n", __func__);
+ return ret;
+ }
+#ifndef CONFIG_TPL
+ ret = arch_cpu_init_dm();
+ if (ret) {
+ debug("%s: arch_cpu_init_dm() failed\n", __func__);
+ return ret;
+ }
+#endif
+ preloader_console_init();
+#if !defined(CONFIG_TPL) && !CONFIG_IS_ENABLED(CPU)
+ ret = print_cpuinfo();
+ if (ret) {
+ debug("%s: print_cpuinfo() failed\n", __func__);
+ return ret;
+ }
+#endif
+ ret = dram_init();
+ if (ret) {
+ debug("%s: dram_init() failed\n", __func__);
+ return ret;
+ }
+ if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
+ ret = mrccache_spl_save();
+ if (ret)
+ debug("%s: Failed to write to mrccache (err=%d)\n",
+ __func__, ret);
+ }
+
+#ifndef CONFIG_SYS_COREBOOT
+ memset(&__bss_start, 0, (ulong)&__bss_end - (ulong)&__bss_start);
+# ifndef CONFIG_TPL
+
+ /* TODO(sjg@chromium.org): Consider calling cpu_init_r() here */
+ ret = interrupt_init();
+ if (ret) {
+ debug("%s: interrupt_init() failed\n", __func__);
+ return ret;
+ }
+
+ /*
+ * The stack grows down from ptr. Put the global data at ptr. This
+ * will only be used for SPL. Once SPL loads U-Boot proper it will
+ * set up its own stack.
+ */
+ gd->new_gd = (struct global_data *)ptr;
+ memcpy(gd->new_gd, gd, sizeof(*gd));
+ arch_setup_gd(gd->new_gd);
+ gd->start_addr_sp = (ulong)ptr;
+
+ /* Cache the SPI flash. Otherwise copying the code to RAM takes ages */
+ ret = mtrr_add_request(MTRR_TYPE_WRBACK,
+ (1ULL << 32) - CONFIG_XIP_ROM_SIZE,
+ CONFIG_XIP_ROM_SIZE);
+ if (ret) {
+ debug("%s: SPI cache setup failed (err=%d)\n", __func__, ret);
+ return ret;
+ }
+ mtrr_commit(true);
+# else
+ ret = syscon_get_by_driver_data(X86_SYSCON_PUNIT, &punit);
+ if (ret)
+ debug("Could not find PUNIT (err=%d)\n", ret);
+
+ ret = set_max_freq();
+ if (ret)
+ debug("Failed to set CPU frequency (err=%d)\n", ret);
+# endif
+#endif
+
+ return 0;
+}
+
+void board_init_f(ulong flags)
+{
+ int ret;
+
+ ret = x86_spl_init();
+ if (ret) {
+ printf("x86_spl_init: error %d\n", ret);
+ hang();
+ }
+#if IS_ENABLED(CONFIG_TPL) || IS_ENABLED(CONFIG_SYS_COREBOOT)
+ gd->bd = malloc(sizeof(*gd->bd));
+ if (!gd->bd) {
+ printf("Out of memory for bd_info size %x\n", sizeof(*gd->bd));
+ hang();
+ }
+ board_init_r(gd, 0);
+#else
+ /* Uninit CAR and jump to board_init_f_r() */
+ board_init_f_r_trampoline(gd->start_addr_sp);
+#endif
+}
+
+void board_init_f_r(void)
+{
+ init_cache_f_r();
+ gd->flags &= ~GD_FLG_SERIAL_READY;
+ debug("cache status %d\n", dcache_status());
+ board_init_r(gd, 0);
+}
+
+u32 spl_boot_device(void)
+{
+ return BOOT_DEVICE_SPI_MMAP;
+}
+
+int spl_start_uboot(void)
+{
+ return 0;
+}
+
+void spl_board_announce_boot_device(void)
+{
+ printf("SPI flash");
+}
+
+static int spl_board_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ spl_image->size = CONFIG_SYS_MONITOR_LEN;
+ spl_image->entry_point = CONFIG_SYS_TEXT_BASE;
+ spl_image->load_addr = CONFIG_SYS_TEXT_BASE;
+ spl_image->os = IH_OS_U_BOOT;
+ spl_image->name = "U-Boot";
+
+ if (!IS_ENABLED(CONFIG_SYS_COREBOOT)) {
+ /*
+ * Copy U-Boot from ROM
+ * TODO(sjg@chromium.org): Figure out a way to get the text base
+ * correctly here, and in the device-tree binman definition.
+ *
+ * Also consider using FIT so we get the correct image length
+ * and parameters.
+ */
+ memcpy((char *)spl_image->load_addr, (char *)0xfff00000,
+ 0x100000);
+ }
+
+ debug("Loading to %lx\n", spl_image->load_addr);
+
+ return 0;
+}
+SPL_LOAD_IMAGE_METHOD("SPI", 5, BOOT_DEVICE_SPI_MMAP, spl_board_load_image);
+
+int spl_spi_load_image(void)
+{
+ return -EPERM;
+}
+
+#ifdef CONFIG_X86_RUN_64BIT
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
+{
+ int ret;
+
+ printf("Jumping to 64-bit U-Boot: Note many features are missing\n");
+ ret = cpu_jump_to_64bit_uboot(spl_image->entry_point);
+ debug("ret=%d\n", ret);
+ hang();
+}
+#endif
+
+void spl_board_init(void)
+{
+#ifndef CONFIG_TPL
+ preloader_console_init();
+#endif
+}
diff --git a/roms/u-boot/arch/x86/lib/string.c b/roms/u-boot/arch/x86/lib/string.c
new file mode 100644
index 000000000..c6263cd2f
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/string.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 1991,1992,1993,1997,1998,2003, 2005 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+/* From glibc-2.14, sysdeps/i386/memset.c */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <asm/string.h>
+
+typedef uint32_t op_t;
+
+void *memset(void *dstpp, int c, size_t len)
+{
+ int d0;
+ unsigned long int dstp = (unsigned long int) dstpp;
+
+ /* This explicit register allocation improves code very much indeed. */
+ register op_t x asm("ax");
+
+ x = (unsigned char) c;
+
+ /* Clear the direction flag, so filling will move forward. */
+ asm volatile("cld");
+
+ /* This threshold value is optimal. */
+ if (len >= 12) {
+ /* Fill X with four copies of the char we want to fill with. */
+ x |= (x << 8);
+ x |= (x << 16);
+
+ /* Adjust LEN for the bytes handled in the first loop. */
+ len -= (-dstp) % sizeof(op_t);
+
+ /*
+ * There are at least some bytes to set. No need to test for
+ * LEN == 0 in this alignment loop.
+ */
+
+ /* Fill bytes until DSTP is aligned on a longword boundary. */
+ asm volatile(
+ "rep\n"
+ "stosb" /* %0, %2, %3 */ :
+ "=D" (dstp), "=c" (d0) :
+ "0" (dstp), "1" ((-dstp) % sizeof(op_t)), "a" (x) :
+ "memory");
+
+ /* Fill longwords. */
+ asm volatile(
+ "rep\n"
+ "stosl" /* %0, %2, %3 */ :
+ "=D" (dstp), "=c" (d0) :
+ "0" (dstp), "1" (len / sizeof(op_t)), "a" (x) :
+ "memory");
+ len %= sizeof(op_t);
+ }
+
+ /* Write the last few bytes. */
+ asm volatile(
+ "rep\n"
+ "stosb" /* %0, %2, %3 */ :
+ "=D" (dstp), "=c" (d0) :
+ "0" (dstp), "1" (len), "a" (x) :
+ "memory");
+
+ return dstpp;
+}
+
+#define OP_T_THRES 8
+#define OPSIZ (sizeof(op_t))
+
+#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \
+do { \
+ int __d0; \
+ asm volatile( \
+ /* Clear the direction flag, so copying goes forward. */ \
+ "cld\n" \
+ /* Copy bytes. */ \
+ "rep\n" \
+ "movsb" : \
+ "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \
+ "0" (dst_bp), "1" (src_bp), "2" (nbytes) : \
+ "memory"); \
+} while (0)
+
+#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \
+do { \
+ int __d0; \
+ asm volatile( \
+ /* Clear the direction flag, so copying goes forward. */ \
+ "cld\n" \
+ /* Copy longwords. */ \
+ "rep\n" \
+ "movsl" : \
+ "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \
+ "0" (dst_bp), "1" (src_bp), "2" ((nbytes) / 4) : \
+ "memory"); \
+ (nbytes_left) = (nbytes) % 4; \
+} while (0)
+
+void *memcpy(void *dstpp, const void *srcpp, size_t len)
+{
+ unsigned long int dstp = (long int)dstpp;
+ unsigned long int srcp = (long int)srcpp;
+
+ /* Copy from the beginning to the end. */
+
+ /* If there not too few bytes to copy, use word copy. */
+ if (len >= OP_T_THRES) {
+ /* Copy just a few bytes to make DSTP aligned. */
+ len -= (-dstp) % OPSIZ;
+ BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ);
+
+ /* Copy from SRCP to DSTP taking advantage of the known
+ * alignment of DSTP. Number of bytes remaining is put
+ * in the third argument, i.e. in LEN. This number may
+ * vary from machine to machine.
+ */
+ WORD_COPY_FWD(dstp, srcp, len, len);
+
+ /* Fall out and copy the tail. */
+ }
+
+ /* There are just a few bytes to copy. Use byte memory operations. */
+ BYTE_COPY_FWD(dstp, srcp, len);
+
+ return dstpp;
+}
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+ int d0, d1, d2, d3, d4, d5;
+ char *ret = dest;
+
+ __asm__ __volatile__(
+ /* Handle more 16 bytes in loop */
+ "cmp $0x10, %0\n\t"
+ "jb 1f\n\t"
+
+ /* Decide forward/backward copy mode */
+ "cmp %2, %1\n\t"
+ "jb 2f\n\t"
+
+ /*
+ * movs instruction have many startup latency
+ * so we handle small size by general register.
+ */
+ "cmp $680, %0\n\t"
+ "jb 3f\n\t"
+ /* movs instruction is only good for aligned case */
+ "mov %1, %3\n\t"
+ "xor %2, %3\n\t"
+ "and $0xff, %3\n\t"
+ "jz 4f\n\t"
+ "3:\n\t"
+ "sub $0x10, %0\n\t"
+
+ /* We gobble 16 bytes forward in each loop */
+ "3:\n\t"
+ "sub $0x10, %0\n\t"
+ "mov 0*4(%1), %3\n\t"
+ "mov 1*4(%1), %4\n\t"
+ "mov %3, 0*4(%2)\n\t"
+ "mov %4, 1*4(%2)\n\t"
+ "mov 2*4(%1), %3\n\t"
+ "mov 3*4(%1), %4\n\t"
+ "mov %3, 2*4(%2)\n\t"
+ "mov %4, 3*4(%2)\n\t"
+ "lea 0x10(%1), %1\n\t"
+ "lea 0x10(%2), %2\n\t"
+ "jae 3b\n\t"
+ "add $0x10, %0\n\t"
+ "jmp 1f\n\t"
+
+ /* Handle data forward by movs */
+ ".p2align 4\n\t"
+ "4:\n\t"
+ "mov -4(%1, %0), %3\n\t"
+ "lea -4(%2, %0), %4\n\t"
+ "shr $2, %0\n\t"
+ "rep movsl\n\t"
+ "mov %3, (%4)\n\t"
+ "jmp 11f\n\t"
+ /* Handle data backward by movs */
+ ".p2align 4\n\t"
+ "6:\n\t"
+ "mov (%1), %3\n\t"
+ "mov %2, %4\n\t"
+ "lea -4(%1, %0), %1\n\t"
+ "lea -4(%2, %0), %2\n\t"
+ "shr $2, %0\n\t"
+ "std\n\t"
+ "rep movsl\n\t"
+ "mov %3,(%4)\n\t"
+ "cld\n\t"
+ "jmp 11f\n\t"
+
+ /* Start to prepare for backward copy */
+ ".p2align 4\n\t"
+ "2:\n\t"
+ "cmp $680, %0\n\t"
+ "jb 5f\n\t"
+ "mov %1, %3\n\t"
+ "xor %2, %3\n\t"
+ "and $0xff, %3\n\t"
+ "jz 6b\n\t"
+
+ /* Calculate copy position to tail */
+ "5:\n\t"
+ "add %0, %1\n\t"
+ "add %0, %2\n\t"
+ "sub $0x10, %0\n\t"
+
+ /* We gobble 16 bytes backward in each loop */
+ "7:\n\t"
+ "sub $0x10, %0\n\t"
+
+ "mov -1*4(%1), %3\n\t"
+ "mov -2*4(%1), %4\n\t"
+ "mov %3, -1*4(%2)\n\t"
+ "mov %4, -2*4(%2)\n\t"
+ "mov -3*4(%1), %3\n\t"
+ "mov -4*4(%1), %4\n\t"
+ "mov %3, -3*4(%2)\n\t"
+ "mov %4, -4*4(%2)\n\t"
+ "lea -0x10(%1), %1\n\t"
+ "lea -0x10(%2), %2\n\t"
+ "jae 7b\n\t"
+ /* Calculate copy position to head */
+ "add $0x10, %0\n\t"
+ "sub %0, %1\n\t"
+ "sub %0, %2\n\t"
+
+ /* Move data from 8 bytes to 15 bytes */
+ ".p2align 4\n\t"
+ "1:\n\t"
+ "cmp $8, %0\n\t"
+ "jb 8f\n\t"
+ "mov 0*4(%1), %3\n\t"
+ "mov 1*4(%1), %4\n\t"
+ "mov -2*4(%1, %0), %5\n\t"
+ "mov -1*4(%1, %0), %1\n\t"
+
+ "mov %3, 0*4(%2)\n\t"
+ "mov %4, 1*4(%2)\n\t"
+ "mov %5, -2*4(%2, %0)\n\t"
+ "mov %1, -1*4(%2, %0)\n\t"
+ "jmp 11f\n\t"
+
+ /* Move data from 4 bytes to 7 bytes */
+ ".p2align 4\n\t"
+ "8:\n\t"
+ "cmp $4, %0\n\t"
+ "jb 9f\n\t"
+ "mov 0*4(%1), %3\n\t"
+ "mov -1*4(%1, %0), %4\n\t"
+ "mov %3, 0*4(%2)\n\t"
+ "mov %4, -1*4(%2, %0)\n\t"
+ "jmp 11f\n\t"
+
+ /* Move data from 2 bytes to 3 bytes */
+ ".p2align 4\n\t"
+ "9:\n\t"
+ "cmp $2, %0\n\t"
+ "jb 10f\n\t"
+ "movw 0*2(%1), %%dx\n\t"
+ "movw -1*2(%1, %0), %%bx\n\t"
+ "movw %%dx, 0*2(%2)\n\t"
+ "movw %%bx, -1*2(%2, %0)\n\t"
+ "jmp 11f\n\t"
+
+ /* Move data for 1 byte */
+ ".p2align 4\n\t"
+ "10:\n\t"
+ "cmp $1, %0\n\t"
+ "jb 11f\n\t"
+ "movb (%1), %%cl\n\t"
+ "movb %%cl, (%2)\n\t"
+ ".p2align 4\n\t"
+ "11:"
+ : "=&c" (d0), "=&S" (d1), "=&D" (d2),
+ "=r" (d3), "=r" (d4), "=r"(d5)
+ : "0" (n),
+ "1" (src),
+ "2" (dest)
+ : "memory");
+
+ return ret;
+}
diff --git a/roms/u-boot/arch/x86/lib/tables.c b/roms/u-boot/arch/x86/lib/tables.c
new file mode 100644
index 000000000..1779bb3e1
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/tables.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <bloblist.h>
+#include <log.h>
+#include <malloc.h>
+#include <smbios.h>
+#include <acpi/acpi_table.h>
+#include <asm/global_data.h>
+#include <asm/sfi.h>
+#include <asm/mpspec.h>
+#include <asm/tables.h>
+#include <asm/coreboot_tables.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * Function prototype to write a specific configuration table
+ *
+ * @addr: start address to write the table
+ * @return: end address of the table
+ */
+typedef ulong (*table_write)(ulong addr);
+
+/**
+ * struct table_info - Information about each table to write
+ *
+ * @name: Name of table (for debugging)
+ * @write: Function to call to write this table
+ * @tag: Bloblist tag if using CONFIG_BLOBLIST_TABLES
+ * @size: Maximum table size
+ * @align: Table alignment in bytes
+ */
+struct table_info {
+ const char *name;
+ table_write write;
+ enum bloblist_tag_t tag;
+ int size;
+ int align;
+};
+
+static struct table_info table_list[] = {
+#ifdef CONFIG_GENERATE_PIRQ_TABLE
+ { "pirq", write_pirq_routing_table },
+#endif
+#ifdef CONFIG_GENERATE_SFI_TABLE
+ { "sfi", write_sfi_table, },
+#endif
+#ifdef CONFIG_GENERATE_MP_TABLE
+ { "mp", write_mp_table, },
+#endif
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+ { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, 0x10000, 0x1000},
+#endif
+#ifdef CONFIG_GENERATE_SMBIOS_TABLE
+ { "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, 0x1000, 0x100},
+#endif
+};
+
+void table_fill_string(char *dest, const char *src, size_t n, char pad)
+{
+ int start, len;
+ int i;
+
+ strncpy(dest, src, n);
+
+ /* Fill the remaining bytes with pad */
+ len = strlen(src);
+ start = len < n ? len : n;
+ for (i = start; i < n; i++)
+ dest[i] = pad;
+}
+
+int write_tables(void)
+{
+ u32 rom_table_start;
+ u32 rom_table_end;
+ u32 high_table, table_size;
+ struct memory_area cfg_tables[ARRAY_SIZE(table_list) + 1];
+ int i;
+
+ rom_table_start = ROM_TABLE_ADDR;
+
+ debug("Writing tables to %x:\n", rom_table_start);
+ for (i = 0; i < ARRAY_SIZE(table_list); i++) {
+ const struct table_info *table = &table_list[i];
+ int size = table->size ? : CONFIG_ROM_TABLE_SIZE;
+
+ if (IS_ENABLED(CONFIG_BLOBLIST_TABLES) && table->tag) {
+ rom_table_start = (ulong)bloblist_add(table->tag, size,
+ table->align);
+ if (!rom_table_start)
+ return log_msg_ret("bloblist", -ENOBUFS);
+ }
+ rom_table_end = table->write(rom_table_start);
+ rom_table_end = ALIGN(rom_table_end, ROM_TABLE_ALIGN);
+
+ if (IS_ENABLED(CONFIG_SEABIOS)) {
+ table_size = rom_table_end - rom_table_start;
+ high_table = (u32)(ulong)high_table_malloc(table_size);
+ if (high_table) {
+ table->write(high_table);
+
+ cfg_tables[i].start = high_table;
+ cfg_tables[i].size = table_size;
+ } else {
+ printf("%d: no memory for configuration tables\n",
+ i);
+ return -ENOSPC;
+ }
+ }
+
+ debug("- wrote '%s' to %x, end %x\n", table->name,
+ rom_table_start, rom_table_end);
+ if (rom_table_end - rom_table_start > size) {
+ log_err("Out of space for configuration tables: need %x, have %x\n",
+ rom_table_end - rom_table_start, size);
+ return log_msg_ret("bloblist", -ENOSPC);
+ }
+ rom_table_start = rom_table_end;
+ }
+
+ if (IS_ENABLED(CONFIG_SEABIOS)) {
+ /* make sure the last item is zero */
+ cfg_tables[i].size = 0;
+ write_coreboot_table(CB_TABLE_ADDR, cfg_tables);
+ }
+
+ if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) {
+ void *ptr = (void *)CONFIG_ROM_TABLE_ADDR;
+
+ /* Write an RSDP pointing to the tables */
+ if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) {
+ struct acpi_ctx *ctx = gd_acpi_ctx();
+
+ acpi_write_rsdp(ptr, ctx->rsdt, ctx->xsdt);
+ ptr += ALIGN(sizeof(struct acpi_rsdp), 16);
+ }
+ if (IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE)) {
+ void *smbios;
+
+ smbios = bloblist_find(BLOBLISTT_SMBIOS_TABLES, 0);
+ if (!smbios)
+ return log_msg_ret("smbios", -ENOENT);
+ memcpy(ptr, smbios, sizeof(struct smbios_entry));
+ }
+ }
+
+ debug("- done writing tables\n");
+
+ return 0;
+}
diff --git a/roms/u-boot/arch/x86/lib/tpl.c b/roms/u-boot/arch/x86/lib/tpl.c
new file mode 100644
index 000000000..b3e5f9c91
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/tpl.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Google, Inc
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <hang.h>
+#include <image.h>
+#include <init.h>
+#include <log.h>
+#include <spl.h>
+#include <asm/cpu.h>
+#include <asm/global_data.h>
+#include <asm/mtrr.h>
+#include <asm/processor.h>
+#include <asm-generic/sections.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+__weak int arch_cpu_init_dm(void)
+{
+ return 0;
+}
+
+static int x86_tpl_init(void)
+{
+ int ret;
+
+ debug("%s starting\n", __func__);
+ ret = x86_cpu_init_tpl();
+ if (ret) {
+ debug("%s: x86_cpu_init_tpl() failed\n", __func__);
+ return ret;
+ }
+ ret = spl_init();
+ if (ret) {
+ debug("%s: spl_init() failed\n", __func__);
+ return ret;
+ }
+ ret = arch_cpu_init();
+ if (ret) {
+ debug("%s: arch_cpu_init() failed\n", __func__);
+ return ret;
+ }
+ ret = arch_cpu_init_dm();
+ if (ret) {
+ debug("%s: arch_cpu_init_dm() failed\n", __func__);
+ return ret;
+ }
+ preloader_console_init();
+
+ return 0;
+}
+
+void board_init_f(ulong flags)
+{
+ int ret;
+
+ ret = x86_tpl_init();
+ if (ret) {
+ debug("Error %d\n", ret);
+ panic("x86_tpl_init fail");
+ }
+
+ /* Uninit CAR and jump to board_init_f_r() */
+ board_init_r(gd, 0);
+}
+
+void board_init_f_r(void)
+{
+ /* Not used since we never call board_init_f_r_trampoline() */
+ while (1);
+}
+
+u32 spl_boot_device(void)
+{
+ return IS_ENABLED(CONFIG_CHROMEOS_VBOOT) ? BOOT_DEVICE_CROS_VBOOT :
+ BOOT_DEVICE_SPI_MMAP;
+}
+
+int spl_start_uboot(void)
+{
+ return 0;
+}
+
+void spl_board_announce_boot_device(void)
+{
+ printf("SPI flash");
+}
+
+static int spl_board_load_image(struct spl_image_info *spl_image,
+ struct spl_boot_device *bootdev)
+{
+ spl_image->size = CONFIG_SYS_MONITOR_LEN; /* We don't know SPL size */
+ spl_image->entry_point = CONFIG_SPL_TEXT_BASE;
+ spl_image->load_addr = CONFIG_SPL_TEXT_BASE;
+ spl_image->os = IH_OS_U_BOOT;
+ spl_image->name = "U-Boot";
+
+ debug("Loading to %lx\n", spl_image->load_addr);
+
+ return 0;
+}
+SPL_LOAD_IMAGE_METHOD("SPI", 5, BOOT_DEVICE_SPI_MMAP, spl_board_load_image);
+
+int spl_spi_load_image(void)
+{
+ return -EPERM;
+}
+
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
+{
+ debug("Jumping to %s at %lx\n", spl_phase_name(spl_next_phase()),
+ (ulong)spl_image->entry_point);
+#ifdef DEBUG
+ print_buffer(spl_image->entry_point, (void *)spl_image->entry_point, 1,
+ 0x20, 0);
+#endif
+ jump_to_spl(spl_image->entry_point);
+ hang();
+}
+
+void spl_board_init(void)
+{
+ preloader_console_init();
+}
+
+#if !CONFIG_IS_ENABLED(PCI)
+/*
+ * This is a fake PCI bus for TPL when it doesn't have proper PCI. It is enough
+ * to bind the devices on the PCI bus, some of which have early-regs properties
+ * providing fixed BARs. Individual drivers program these BARs themselves so
+ * that they can access the devices. The BARs are allocated statically in the
+ * device tree.
+ *
+ * Once SPL is running it enables PCI properly, but does not auto-assign BARs
+ * for devices, so the TPL BARs continue to be used. Once U-Boot starts it does
+ * the auto allocation (after relocation).
+ */
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static const struct udevice_id tpl_fake_pci_ids[] = {
+ { .compatible = "pci-x86" },
+ { }
+};
+#endif
+
+U_BOOT_DRIVER(pci_x86) = {
+ .name = "pci_x86",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = of_match_ptr(tpl_fake_pci_ids),
+ DM_PHASE(tpl)
+};
+#endif
diff --git a/roms/u-boot/arch/x86/lib/zimage.c b/roms/u-boot/arch/x86/lib/zimage.c
new file mode 100644
index 000000000..90fc8a466
--- /dev/null
+++ b/roms/u-boot/arch/x86/lib/zimage.c
@@ -0,0 +1,792 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
+ */
+
+/*
+ * Linux x86 zImage and bzImage loading
+ *
+ * based on the procdure described in
+ * linux/Documentation/i386/boot.txt
+ */
+
+#define LOG_CATEGORY LOGC_BOOT
+
+#include <common.h>
+#include <bootm.h>
+#include <command.h>
+#include <env.h>
+#include <init.h>
+#include <irq_func.h>
+#include <log.h>
+#include <malloc.h>
+#include <acpi/acpi_table.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/zimage.h>
+#include <asm/byteorder.h>
+#include <asm/bootm.h>
+#include <asm/bootparam.h>
+#include <asm/global_data.h>
+#ifdef CONFIG_SYS_COREBOOT
+#include <asm/arch/timestamp.h>
+#endif
+#include <linux/compiler.h>
+#include <linux/ctype.h>
+#include <linux/libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Memory lay-out:
+ *
+ * relative to setup_base (which is 0x90000 currently)
+ *
+ * 0x0000-0x7FFF Real mode kernel
+ * 0x8000-0x8FFF Stack and heap
+ * 0x9000-0x90FF Kernel command line
+ */
+#define DEFAULT_SETUP_BASE 0x90000
+#define COMMAND_LINE_OFFSET 0x9000
+#define HEAP_END_OFFSET 0x8e00
+
+#define COMMAND_LINE_SIZE 2048
+
+/**
+ * struct zboot_state - Current state of the boot
+ *
+ * @bzimage_addr: Address of the bzImage to boot
+ * @bzimage_size: Size of the bzImage, or 0 to detect this
+ * @initrd_addr: Address of the initial ramdisk, or 0 if none
+ * @initrd_size: Size of the initial ramdisk, or 0 if none
+ * @load_address: Address where the bzImage is moved before booting, either
+ * BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR
+ * @base_ptr: Pointer to the boot parameters, typically at address
+ * DEFAULT_SETUP_BASE
+ * @cmdline: Environment variable containing the 'override' command line, or
+ * NULL to use the one in the setup block
+ */
+struct zboot_state {
+ ulong bzimage_addr;
+ ulong bzimage_size;
+ ulong initrd_addr;
+ ulong initrd_size;
+ ulong load_address;
+ struct boot_params *base_ptr;
+ char *cmdline;
+} state;
+
+enum {
+ ZBOOT_STATE_START = BIT(0),
+ ZBOOT_STATE_LOAD = BIT(1),
+ ZBOOT_STATE_SETUP = BIT(2),
+ ZBOOT_STATE_INFO = BIT(3),
+ ZBOOT_STATE_GO = BIT(4),
+
+ /* This one doesn't execute automatically, so stop the count before 5 */
+ ZBOOT_STATE_DUMP = BIT(5),
+ ZBOOT_STATE_COUNT = 5,
+};
+
+static void build_command_line(char *command_line, int auto_boot)
+{
+ char *env_command_line;
+
+ command_line[0] = '\0';
+
+ env_command_line = env_get("bootargs");
+
+ /* set console= argument if we use a serial console */
+ if (!strstr(env_command_line, "console=")) {
+ if (!strcmp(env_get("stdout"), "serial")) {
+
+ /* We seem to use serial console */
+ sprintf(command_line, "console=ttyS0,%s ",
+ env_get("baudrate"));
+ }
+ }
+
+ if (auto_boot)
+ strcat(command_line, "auto ");
+
+ if (env_command_line)
+ strcat(command_line, env_command_line);
+#ifdef DEBUG
+ printf("Kernel command line:");
+ puts(command_line);
+ printf("\n");
+#endif
+}
+
+static int kernel_magic_ok(struct setup_header *hdr)
+{
+ if (KERNEL_MAGIC != hdr->boot_flag) {
+ printf("Error: Invalid Boot Flag "
+ "(found 0x%04x, expected 0x%04x)\n",
+ hdr->boot_flag, KERNEL_MAGIC);
+ return 0;
+ } else {
+ printf("Valid Boot Flag\n");
+ return 1;
+ }
+}
+
+static int get_boot_protocol(struct setup_header *hdr, bool verbose)
+{
+ if (hdr->header == KERNEL_V2_MAGIC) {
+ if (verbose)
+ printf("Magic signature found\n");
+ return hdr->version;
+ } else {
+ /* Very old kernel */
+ if (verbose)
+ printf("Magic signature not found\n");
+ return 0x0100;
+ }
+}
+
+static int setup_device_tree(struct setup_header *hdr, const void *fdt_blob)
+{
+ int bootproto = get_boot_protocol(hdr, false);
+ struct setup_data *sd;
+ int size;
+
+ if (bootproto < 0x0209)
+ return -ENOTSUPP;
+
+ if (!fdt_blob)
+ return 0;
+
+ size = fdt_totalsize(fdt_blob);
+ if (size < 0)
+ return -EINVAL;
+
+ size += sizeof(struct setup_data);
+ sd = (struct setup_data *)malloc(size);
+ if (!sd) {
+ printf("Not enough memory for DTB setup data\n");
+ return -ENOMEM;
+ }
+
+ sd->next = hdr->setup_data;
+ sd->type = SETUP_DTB;
+ sd->len = fdt_totalsize(fdt_blob);
+ memcpy(sd->data, fdt_blob, sd->len);
+ hdr->setup_data = (unsigned long)sd;
+
+ return 0;
+}
+
+static const char *get_kernel_version(struct boot_params *params,
+ void *kernel_base)
+{
+ struct setup_header *hdr = &params->hdr;
+ int bootproto;
+ const char *s, *end;
+
+ bootproto = get_boot_protocol(hdr, false);
+ if (bootproto < 0x0200 || hdr->setup_sects < 15)
+ return NULL;
+
+ /* sanity-check the kernel version in case it is missing */
+ for (s = kernel_base + hdr->kernel_version + 0x200, end = s + 0x100; *s;
+ s++) {
+ if (!isprint(*s))
+ return NULL;
+ }
+
+ return kernel_base + hdr->kernel_version + 0x200;
+}
+
+struct boot_params *load_zimage(char *image, unsigned long kernel_size,
+ ulong *load_addressp)
+{
+ struct boot_params *setup_base;
+ const char *version;
+ int setup_size;
+ int bootproto;
+ int big_image;
+
+ struct boot_params *params = (struct boot_params *)image;
+ struct setup_header *hdr = &params->hdr;
+
+ /* base address for real-mode segment */
+ setup_base = (struct boot_params *)DEFAULT_SETUP_BASE;
+
+ if (!kernel_magic_ok(hdr))
+ return 0;
+
+ /* determine size of setup */
+ if (0 == hdr->setup_sects) {
+ log_warning("Setup Sectors = 0 (defaulting to 4)\n");
+ setup_size = 5 * 512;
+ } else {
+ setup_size = (hdr->setup_sects + 1) * 512;
+ }
+
+ log_debug("Setup Size = 0x%8.8lx\n", (ulong)setup_size);
+
+ if (setup_size > SETUP_MAX_SIZE)
+ printf("Error: Setup is too large (%d bytes)\n", setup_size);
+
+ /* determine boot protocol version */
+ bootproto = get_boot_protocol(hdr, true);
+
+ log_debug("Using boot protocol version %x.%02x\n",
+ (bootproto & 0xff00) >> 8, bootproto & 0xff);
+
+ version = get_kernel_version(params, image);
+ if (version)
+ printf("Linux kernel version %s\n", version);
+ else
+ printf("Setup Sectors < 15 - Cannot print kernel version\n");
+
+ /* Determine image type */
+ big_image = (bootproto >= 0x0200) &&
+ (hdr->loadflags & BIG_KERNEL_FLAG);
+
+ /* Determine load address */
+ if (big_image)
+ *load_addressp = BZIMAGE_LOAD_ADDR;
+ else
+ *load_addressp = ZIMAGE_LOAD_ADDR;
+
+ printf("Building boot_params at 0x%8.8lx\n", (ulong)setup_base);
+ memset(setup_base, 0, sizeof(*setup_base));
+ setup_base->hdr = params->hdr;
+
+ if (bootproto >= 0x0204)
+ kernel_size = hdr->syssize * 16;
+ else
+ kernel_size -= setup_size;
+
+ if (bootproto == 0x0100) {
+ /*
+ * A very old kernel MUST have its real-mode code
+ * loaded at 0x90000
+ */
+ if ((ulong)setup_base != 0x90000) {
+ /* Copy the real-mode kernel */
+ memmove((void *)0x90000, setup_base, setup_size);
+
+ /* Copy the command line */
+ memmove((void *)0x99000,
+ (u8 *)setup_base + COMMAND_LINE_OFFSET,
+ COMMAND_LINE_SIZE);
+
+ /* Relocated */
+ setup_base = (struct boot_params *)0x90000;
+ }
+
+ /* It is recommended to clear memory up to the 32K mark */
+ memset((u8 *)0x90000 + setup_size, 0,
+ SETUP_MAX_SIZE - setup_size);
+ }
+
+ if (big_image) {
+ if (kernel_size > BZIMAGE_MAX_SIZE) {
+ printf("Error: bzImage kernel too big! "
+ "(size: %ld, max: %d)\n",
+ kernel_size, BZIMAGE_MAX_SIZE);
+ return 0;
+ }
+ } else if ((kernel_size) > ZIMAGE_MAX_SIZE) {
+ printf("Error: zImage kernel too big! (size: %ld, max: %d)\n",
+ kernel_size, ZIMAGE_MAX_SIZE);
+ return 0;
+ }
+
+ printf("Loading %s at address %lx (%ld bytes)\n",
+ big_image ? "bzImage" : "zImage", *load_addressp, kernel_size);
+
+ memmove((void *)*load_addressp, image + setup_size, kernel_size);
+
+ return setup_base;
+}
+
+int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
+ ulong initrd_addr, ulong initrd_size, ulong cmdline_force)
+{
+ struct setup_header *hdr = &setup_base->hdr;
+ int bootproto = get_boot_protocol(hdr, false);
+
+ log_debug("Setup E820 entries\n");
+ if (ll_boot_init()) {
+ setup_base->e820_entries = install_e820_map(
+ ARRAY_SIZE(setup_base->e820_map), setup_base->e820_map);
+ } else if (IS_ENABLED(CONFIG_COREBOOT_SYSINFO)) {
+ setup_base->e820_entries = cb_install_e820_map(
+ ARRAY_SIZE(setup_base->e820_map), setup_base->e820_map);
+ }
+
+ if (bootproto == 0x0100) {
+ setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
+ setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET;
+ }
+ if (bootproto >= 0x0200) {
+ hdr->type_of_loader = 0x80; /* U-Boot version 0 */
+ if (initrd_addr) {
+ printf("Initial RAM disk at linear address "
+ "0x%08lx, size %ld bytes\n",
+ initrd_addr, initrd_size);
+
+ hdr->ramdisk_image = initrd_addr;
+ hdr->ramdisk_size = initrd_size;
+ }
+ }
+
+ if (bootproto >= 0x0201) {
+ hdr->heap_end_ptr = HEAP_END_OFFSET;
+ hdr->loadflags |= HEAP_FLAG;
+ }
+
+ if (cmd_line) {
+ int max_size = 0xff;
+ int ret;
+
+ log_debug("Setup cmdline\n");
+ if (bootproto >= 0x0206)
+ max_size = hdr->cmdline_size;
+ if (bootproto >= 0x0202) {
+ hdr->cmd_line_ptr = (uintptr_t)cmd_line;
+ } else if (bootproto >= 0x0200) {
+ setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC;
+ setup_base->screen_info.cl_offset =
+ (uintptr_t)cmd_line - (uintptr_t)setup_base;
+
+ hdr->setup_move_size = 0x9100;
+ }
+
+ /* build command line at COMMAND_LINE_OFFSET */
+ if (cmdline_force)
+ strcpy(cmd_line, (char *)cmdline_force);
+ else
+ build_command_line(cmd_line, auto_boot);
+ ret = bootm_process_cmdline(cmd_line, max_size, BOOTM_CL_ALL);
+ if (ret) {
+ printf("Cmdline setup failed (max_size=%x, bootproto=%x, err=%d)\n",
+ max_size, bootproto, ret);
+ return ret;
+ }
+ printf("Kernel command line: \"");
+ puts(cmd_line);
+ printf("\"\n");
+ }
+
+ if (IS_ENABLED(CONFIG_INTEL_MID) && bootproto >= 0x0207)
+ hdr->hardware_subarch = X86_SUBARCH_INTEL_MID;
+
+ if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE))
+ setup_base->acpi_rsdp_addr = acpi_get_rsdp_addr();
+
+ log_debug("Setup devicetree\n");
+ setup_device_tree(hdr, (const void *)env_get_hex("fdtaddr", 0));
+ setup_video(&setup_base->screen_info);
+
+ if (IS_ENABLED(CONFIG_EFI_STUB))
+ setup_efi_info(&setup_base->efi_info);
+
+ return 0;
+}
+
+static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ const char *s;
+
+ memset(&state, '\0', sizeof(state));
+ if (argc >= 2) {
+ /* argv[1] holds the address of the bzImage */
+ s = argv[1];
+ } else {
+ s = env_get("fileaddr");
+ }
+
+ if (s)
+ state.bzimage_addr = simple_strtoul(s, NULL, 16);
+
+ if (argc >= 3) {
+ /* argv[2] holds the size of the bzImage */
+ state.bzimage_size = simple_strtoul(argv[2], NULL, 16);
+ }
+
+ if (argc >= 4)
+ state.initrd_addr = simple_strtoul(argv[3], NULL, 16);
+ if (argc >= 5)
+ state.initrd_size = simple_strtoul(argv[4], NULL, 16);
+ if (argc >= 6) {
+ /*
+ * When the base_ptr is passed in, we assume that the image is
+ * already loaded at the address given by argv[1] and therefore
+ * the original bzImage is somewhere else, or not accessible.
+ * In any case, we don't need access to the bzImage since all
+ * the processing is assumed to be done.
+ *
+ * So set the base_ptr to the given address, use this arg as the
+ * load address and set bzimage_addr to 0 so we know that it
+ * cannot be proceesed (or processed again).
+ */
+ state.base_ptr = (void *)simple_strtoul(argv[5], NULL, 16);
+ state.load_address = state.bzimage_addr;
+ state.bzimage_addr = 0;
+ }
+ if (argc >= 7)
+ state.cmdline = env_get(argv[6]);
+
+ return 0;
+}
+
+static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct boot_params *base_ptr;
+
+ if (state.base_ptr) {
+ struct boot_params *from = (struct boot_params *)state.base_ptr;
+
+ base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE;
+ log_debug("Building boot_params at 0x%8.8lx\n",
+ (ulong)base_ptr);
+ memset(base_ptr, '\0', sizeof(*base_ptr));
+ base_ptr->hdr = from->hdr;
+ } else {
+ base_ptr = load_zimage((void *)state.bzimage_addr, state.bzimage_size,
+ &state.load_address);
+ if (!base_ptr) {
+ puts("## Kernel loading failed ...\n");
+ return CMD_RET_FAILURE;
+ }
+ }
+ state.base_ptr = base_ptr;
+ if (env_set_hex("zbootbase", (ulong)base_ptr) ||
+ env_set_hex("zbootaddr", state.load_address))
+ return CMD_RET_FAILURE;
+
+ return 0;
+}
+
+static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct boot_params *base_ptr = state.base_ptr;
+ int ret;
+
+ if (!base_ptr) {
+ printf("base is not set: use 'zboot load' first\n");
+ return CMD_RET_FAILURE;
+ }
+ ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
+ 0, state.initrd_addr, state.initrd_size,
+ (ulong)state.cmdline);
+ if (ret) {
+ puts("Setting up boot parameters failed ...\n");
+ return CMD_RET_FAILURE;
+ }
+
+ return 0;
+}
+
+static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ printf("Kernel loaded at %08lx, setup_base=%p\n",
+ state.load_address, state.base_ptr);
+
+ return 0;
+}
+
+static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int ret;
+
+ disable_interrupts();
+
+ /* we assume that the kernel is in place */
+ ret = boot_linux_kernel((ulong)state.base_ptr, state.load_address,
+ false);
+ printf("Kernel returned! (err=%d)\n", ret);
+
+ return CMD_RET_FAILURE;
+}
+
+static void print_num(const char *name, ulong value)
+{
+ printf("%-20s: %lx\n", name, value);
+}
+
+static void print_num64(const char *name, u64 value)
+{
+ printf("%-20s: %llx\n", name, value);
+}
+
+static const char *const e820_type_name[E820_COUNT] = {
+ [E820_RAM] = "RAM",
+ [E820_RESERVED] = "Reserved",
+ [E820_ACPI] = "ACPI",
+ [E820_NVS] = "ACPI NVS",
+ [E820_UNUSABLE] = "Unusable",
+};
+
+static const char *const bootloader_id[] = {
+ "LILO",
+ "Loadlin",
+ "bootsect-loader",
+ "Syslinux",
+ "Etherboot/gPXE/iPXE",
+ "ELILO",
+ "undefined",
+ "GRUB",
+ "U-Boot",
+ "Xen",
+ "Gujin",
+ "Qemu",
+ "Arcturus Networks uCbootloader",
+ "kexec-tools",
+ "Extended",
+ "Special",
+ "Reserved",
+ "Minimal Linux Bootloader",
+ "OVMF UEFI virtualization stack",
+};
+
+struct flag_info {
+ uint bit;
+ const char *name;
+};
+
+static struct flag_info load_flags[] = {
+ { LOADED_HIGH, "loaded-high" },
+ { QUIET_FLAG, "quiet" },
+ { KEEP_SEGMENTS, "keep-segments" },
+ { CAN_USE_HEAP, "can-use-heap" },
+};
+
+static struct flag_info xload_flags[] = {
+ { XLF_KERNEL_64, "64-bit-entry" },
+ { XLF_CAN_BE_LOADED_ABOVE_4G, "can-load-above-4gb" },
+ { XLF_EFI_HANDOVER_32, "32-efi-handoff" },
+ { XLF_EFI_HANDOVER_64, "64-efi-handoff" },
+ { XLF_EFI_KEXEC, "kexec-efi-runtime" },
+};
+
+static void print_flags(struct flag_info *flags, int count, uint value)
+{
+ int i;
+
+ printf("%-20s:", "");
+ for (i = 0; i < count; i++) {
+ uint mask = flags[i].bit;
+
+ if (value & mask)
+ printf(" %s", flags[i].name);
+ }
+ printf("\n");
+}
+
+static void show_loader(struct setup_header *hdr)
+{
+ bool version_valid = false;
+ int type, version;
+ const char *name;
+
+ type = hdr->type_of_loader >> 4;
+ version = hdr->type_of_loader & 0xf;
+ if (type == 0xe)
+ type = 0x10 + hdr->ext_loader_type;
+ version |= hdr->ext_loader_ver << 4;
+ if (!hdr->type_of_loader) {
+ name = "pre-2.00 bootloader";
+ } else if (hdr->type_of_loader == 0xff) {
+ name = "unknown";
+ } else if (type < ARRAY_SIZE(bootloader_id)) {
+ name = bootloader_id[type];
+ version_valid = true;
+ } else {
+ name = "undefined";
+ }
+ printf("%20s %s", "", name);
+ if (version_valid)
+ printf(", version %x", version);
+ printf("\n");
+}
+
+void zimage_dump(struct boot_params *base_ptr)
+{
+ struct setup_header *hdr;
+ const char *version;
+ int i;
+
+ printf("Setup located at %p:\n\n", base_ptr);
+ print_num64("ACPI RSDP addr", base_ptr->acpi_rsdp_addr);
+
+ printf("E820: %d entries\n", base_ptr->e820_entries);
+ if (base_ptr->e820_entries) {
+ printf("%18s %16s %s\n", "Addr", "Size", "Type");
+ for (i = 0; i < base_ptr->e820_entries; i++) {
+ struct e820_entry *entry = &base_ptr->e820_map[i];
+
+ printf("%12llx %10llx %s\n", entry->addr, entry->size,
+ entry->type < E820_COUNT ?
+ e820_type_name[entry->type] :
+ simple_itoa(entry->type));
+ }
+ }
+
+ hdr = &base_ptr->hdr;
+ print_num("Setup sectors", hdr->setup_sects);
+ print_num("Root flags", hdr->root_flags);
+ print_num("Sys size", hdr->syssize);
+ print_num("RAM size", hdr->ram_size);
+ print_num("Video mode", hdr->vid_mode);
+ print_num("Root dev", hdr->root_dev);
+ print_num("Boot flag", hdr->boot_flag);
+ print_num("Jump", hdr->jump);
+ print_num("Header", hdr->header);
+ if (hdr->header == KERNEL_V2_MAGIC)
+ printf("%-20s %s\n", "", "Kernel V2");
+ else
+ printf("%-20s %s\n", "", "Ancient kernel, using version 100");
+ print_num("Version", hdr->version);
+ print_num("Real mode switch", hdr->realmode_swtch);
+ print_num("Start sys", hdr->start_sys);
+ print_num("Kernel version", hdr->kernel_version);
+ version = get_kernel_version(base_ptr, (void *)state.bzimage_addr);
+ if (version)
+ printf(" @%p: %s\n", version, version);
+ print_num("Type of loader", hdr->type_of_loader);
+ show_loader(hdr);
+ print_num("Load flags", hdr->loadflags);
+ print_flags(load_flags, ARRAY_SIZE(load_flags), hdr->loadflags);
+ print_num("Setup move size", hdr->setup_move_size);
+ print_num("Code32 start", hdr->code32_start);
+ print_num("Ramdisk image", hdr->ramdisk_image);
+ print_num("Ramdisk size", hdr->ramdisk_size);
+ print_num("Bootsect kludge", hdr->bootsect_kludge);
+ print_num("Heap end ptr", hdr->heap_end_ptr);
+ print_num("Ext loader ver", hdr->ext_loader_ver);
+ print_num("Ext loader type", hdr->ext_loader_type);
+ print_num("Command line ptr", hdr->cmd_line_ptr);
+ if (hdr->cmd_line_ptr) {
+ printf(" ");
+ /* Use puts() to avoid limits from CONFIG_SYS_PBSIZE */
+ puts((char *)(ulong)hdr->cmd_line_ptr);
+ printf("\n");
+ }
+ print_num("Initrd addr max", hdr->initrd_addr_max);
+ print_num("Kernel alignment", hdr->kernel_alignment);
+ print_num("Relocatable kernel", hdr->relocatable_kernel);
+ print_num("Min alignment", hdr->min_alignment);
+ if (hdr->min_alignment)
+ printf("%-20s: %x\n", "", 1 << hdr->min_alignment);
+ print_num("Xload flags", hdr->xloadflags);
+ print_flags(xload_flags, ARRAY_SIZE(xload_flags), hdr->xloadflags);
+ print_num("Cmdline size", hdr->cmdline_size);
+ print_num("Hardware subarch", hdr->hardware_subarch);
+ print_num64("HW subarch data", hdr->hardware_subarch_data);
+ print_num("Payload offset", hdr->payload_offset);
+ print_num("Payload length", hdr->payload_length);
+ print_num64("Setup data", hdr->setup_data);
+ print_num64("Pref address", hdr->pref_address);
+ print_num("Init size", hdr->init_size);
+ print_num("Handover offset", hdr->handover_offset);
+ if (get_boot_protocol(hdr, false) >= 0x215)
+ print_num("Kernel info offset", hdr->kernel_info_offset);
+}
+
+static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct boot_params *base_ptr = state.base_ptr;
+
+ if (argc > 1)
+ base_ptr = (void *)simple_strtoul(argv[1], NULL, 16);
+ if (!base_ptr) {
+ printf("No zboot setup_base\n");
+ return CMD_RET_FAILURE;
+ }
+ zimage_dump(base_ptr);
+
+ return 0;
+}
+
+/* Note: This defines the complete_zboot() function */
+U_BOOT_SUBCMDS(zboot,
+ U_BOOT_CMD_MKENT(start, 8, 1, do_zboot_start, "", ""),
+ U_BOOT_CMD_MKENT(load, 1, 1, do_zboot_load, "", ""),
+ U_BOOT_CMD_MKENT(setup, 1, 1, do_zboot_setup, "", ""),
+ U_BOOT_CMD_MKENT(info, 1, 1, do_zboot_info, "", ""),
+ U_BOOT_CMD_MKENT(go, 1, 1, do_zboot_go, "", ""),
+ U_BOOT_CMD_MKENT(dump, 2, 1, do_zboot_dump, "", ""),
+)
+
+int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int state_mask)
+{
+ int i;
+
+ for (i = 0; i < ZBOOT_STATE_COUNT; i++) {
+ struct cmd_tbl *cmd = &zboot_subcmds[i];
+ int mask = 1 << i;
+ int ret;
+
+ if (mask & state_mask) {
+ ret = cmd->cmd(cmd, flag, argc, argv);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int do_zboot_parent(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int *repeatable)
+{
+ /* determine if we have a sub command */
+ if (argc > 1) {
+ char *endp;
+
+ simple_strtoul(argv[1], &endp, 16);
+ /*
+ * endp pointing to nul means that argv[1] was just a valid
+ * number, so pass it along to the normal processing
+ */
+ if (*endp)
+ return do_zboot(cmdtp, flag, argc, argv, repeatable);
+ }
+
+ do_zboot_states(cmdtp, flag, argc, argv, ZBOOT_STATE_START |
+ ZBOOT_STATE_LOAD | ZBOOT_STATE_SETUP |
+ ZBOOT_STATE_INFO | ZBOOT_STATE_GO);
+
+ return CMD_RET_FAILURE;
+}
+
+U_BOOT_CMDREP_COMPLETE(
+ zboot, 8, do_zboot_parent, "Boot bzImage",
+ "[addr] [size] [initrd addr] [initrd size] [setup] [cmdline]\n"
+ " addr - The optional starting address of the bzimage.\n"
+ " If not set it defaults to the environment\n"
+ " variable \"fileaddr\".\n"
+ " size - The optional size of the bzimage. Defaults to\n"
+ " zero.\n"
+ " initrd addr - The address of the initrd image to use, if any.\n"
+ " initrd size - The size of the initrd image to use, if any.\n"
+ " setup - The address of the kernel setup region, if this\n"
+ " is not at addr\n"
+ " cmdline - Environment variable containing the kernel\n"
+ " command line, to override U-Boot's normal\n"
+ " cmdline generation\n"
+ "\n"
+ "Sub-commands to do part of the zboot sequence:\n"
+ "\tstart [addr [arg ...]] - specify arguments\n"
+ "\tload - load OS image\n"
+ "\tsetup - set up table\n"
+ "\tinfo - show summary info\n"
+ "\tgo - start OS\n"
+ "\tdump [addr] - dump info (optional address of boot params)",
+ complete_zboot
+);