- Enable SD slot on Intel Edison
- Populate CSRT ACPI table for shared DMA controller on Intel Tangier
- Convert Intel ICH-SPI driver to use new spi-mem ops
- Enable config_distro_bootcmd for QEMU x86
- Support U-Boot as a payload for Intel Slim Bootloader
- Avoid writing temporary asl files into the source tree which fixes the
  parallel build issue occasionally seen
This commit is contained in:
Tom Rini 2019-08-09 23:27:15 -04:00
commit 9fd8b2c8c7
53 changed files with 1581 additions and 627 deletions

View File

@ -115,6 +115,7 @@ source "arch/x86/cpu/efi/Kconfig"
source "arch/x86/cpu/qemu/Kconfig"
source "arch/x86/cpu/quark/Kconfig"
source "arch/x86/cpu/queensbay/Kconfig"
source "arch/x86/cpu/slimbootloader/Kconfig"
source "arch/x86/cpu/tangier/Kconfig"
# architecture-specific options below
@ -344,9 +345,17 @@ config INTEL_ME_FILE
The filename of the file to use as Intel Management Engine in the
board directory.
config USE_HOB
bool "Use HOB (Hand-Off Block)"
help
Select this option to access HOB (Hand-Off Block) data structures
and parse HOBs. This HOB infra structure can be reused with
different solutions across different platforms.
config HAVE_FSP
bool "Add an Firmware Support Package binary"
depends on !EFI
select USE_HOB
help
Select this option to add an Firmware Support Package binary to
the resulting U-Boot image. It is a binary blob which U-Boot uses

View File

@ -42,6 +42,7 @@ obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/
obj-$(CONFIG_INTEL_BRASWELL) += braswell/
obj-$(CONFIG_INTEL_BROADWELL) += broadwell/
obj-$(CONFIG_SYS_COREBOOT) += coreboot/
obj-$(CONFIG_SYS_SLIMBOOTLOADER) += slimbootloader/
obj-$(CONFIG_EFI) += efi/
obj-$(CONFIG_QEMU) += qemu/
obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2019 Intel Corporation <www.intel.com>
config SYS_SLIMBOOTLOADER
bool
select USE_HOB
imply SYS_NS16550
imply AHCI_PCI
imply SCSI
imply SCSI_AHCI
imply MMC
imply MMC_PCI
imply MMC_SDHCI
imply MMC_SDHCI_SDMA
imply USB
imply USB_EHCI_HCD
imply USB_XHCI_HCD
imply E1000

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2019 Intel Corporation <www.intel.com>
obj-y += car.o slimbootloader.o sdram.o serial.o

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
#include <generated/asm-offsets.h>
.section .text
.globl car_init
car_init:
/* Get hob pointer parameter from previous stage's stack */
mov 0x4(%esp), %esi
jmp car_init_ret

View File

@ -0,0 +1,151 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
#include <common.h>
#include <linux/sizes.h>
#include <asm/e820.h>
#include <asm/arch/slimbootloader.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* This returns a data pointer of memory map info from the guid hob.
*
* @return: A data pointer of memory map info hob
*/
static struct sbl_memory_map_info *get_memory_map_info(void)
{
struct sbl_memory_map_info *data;
const efi_guid_t guid = SBL_MEMORY_MAP_INFO_GUID;
if (!gd->arch.hob_list)
return NULL;
data = hob_get_guid_hob_data(gd->arch.hob_list, NULL, &guid);
if (!data)
panic("memory map info hob not found\n");
if (!data->count)
panic("invalid number of memory map entries\n");
return data;
}
#define for_each_if(condition) if (!(condition)) {} else
#define for_each_memory_map_entry_reversed(iter, entries) \
for (iter = entries->count - 1; iter >= 0; iter--) \
for_each_if(entries->entry[iter].type == E820_RAM)
/**
* This is to give usable memory region information for u-boot relocation.
* so search usable memory region lower than 4GB.
* The memory map entries from Slim Bootloader hob are already sorted.
*
* @total_size: The memory size that u-boot occupies
* @return : The top available memory address lower than 4GB
*/
ulong board_get_usable_ram_top(ulong total_size)
{
struct sbl_memory_map_info *data;
int i;
u64 addr_start;
u64 addr_end;
ulong ram_top;
data = get_memory_map_info();
/**
* sorted memory map entries from Slim Bootloader based on physical
* start memory address, from low to high. So do reversed search to
* get highest usable, suitable size, 4KB aligned available memory
* under 4GB.
*/
ram_top = 0;
for_each_memory_map_entry_reversed(i, data) {
addr_start = data->entry[i].addr;
addr_end = addr_start + data->entry[i].size;
if (addr_start > SZ_4G)
continue;
if (addr_end > SZ_4G)
addr_end = SZ_4G;
if (addr_end < total_size)
continue;
/* to relocate u-boot at 4K aligned memory */
addr_end = rounddown(addr_end - total_size, SZ_4K);
if (addr_end >= addr_start) {
ram_top = (ulong)addr_end + total_size;
break;
}
}
if (!ram_top)
panic("failed to find available memory for relocation!");
return ram_top;
}
/**
* The memory initialization has already been done in previous Slim Bootloader
* stage thru FSP-M. Instead, this sets the ram_size from the memory map info
* hob.
*/
int dram_init(void)
{
struct sbl_memory_map_info *data;
int i;
u64 ram_size;
data = get_memory_map_info();
/**
* sorted memory map entries from Slim Bootloader based on physical
* start memory address, from low to high. So do reversed search to
* simply get highest usable memory address as RAM size
*/
ram_size = 0;
for_each_memory_map_entry_reversed(i, data) {
/* simply use the highest usable memory address as RAM size */
ram_size = data->entry[i].addr + data->entry[i].size;
break;
}
if (!ram_size)
panic("failed to detect memory size");
gd->ram_size = ram_size;
return 0;
}
int dram_init_banksize(void)
{
if (!CONFIG_NR_DRAM_BANKS)
return 0;
/* simply use a single bank to have whole size for now */
gd->bd->bi_dram[0].start = 0;
gd->bd->bi_dram[0].size = gd->ram_size;
return 0;
}
unsigned int install_e820_map(unsigned int max_entries,
struct e820_entry *entries)
{
struct sbl_memory_map_info *data;
unsigned int i;
data = get_memory_map_info();
for (i = 0; i < data->count; i++) {
entries[i].addr = data->entry[i].addr;
entries[i].size = data->entry[i].size;
entries[i].type = data->entry[i].type;
}
return i;
}

View File

@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
#include <common.h>
#include <dm.h>
#include <ns16550.h>
#include <serial.h>
#include <asm/arch/slimbootloader.h>
/**
* The serial port info hob is generated by Slim Bootloader, so eligible for
* Slim Bootloader based boards only.
*/
static int slimbootloader_serial_ofdata_to_platdata(struct udevice *dev)
{
const efi_guid_t guid = SBL_SERIAL_PORT_INFO_GUID;
struct sbl_serial_port_info *data;
struct ns16550_platdata *plat = dev->platdata;
if (!gd->arch.hob_list)
panic("hob list not found!");
data = hob_get_guid_hob_data(gd->arch.hob_list, NULL, &guid);
if (!data) {
debug("failed to get serial port information\n");
return -ENOENT;
}
debug("type:%d base=0x%08x baudrate=%d stride=%d clk=%d\n",
data->type,
data->base,
data->baud,
data->stride,
data->clk);
/*
* The data->type provides port io or mmio access type info,
* but the access type will be controlled by
* CONFIG_SYS_NS16550_PORT_MAPPED or CONFIG_SYS_NS16550_MEM32.
*
* TBD: ns16550 access type configuration in runtime.
* ex) plat->access_type = data->type
*/
plat->base = data->base;
/* ns16550 uses reg_shift, then covert stride to shift */
plat->reg_shift = data->stride >> 1;
plat->clock = data->clk;
return 0;
}
static const struct udevice_id slimbootloader_serial_ids[] = {
{ .compatible = "intel,slimbootloader-uart" },
{}
};
U_BOOT_DRIVER(serial_slimbootloader) = {
.name = "serial_slimbootloader",
.id = UCLASS_SERIAL,
.of_match = slimbootloader_serial_ids,
.ofdata_to_platdata = slimbootloader_serial_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
.priv_auto_alloc_size = sizeof(struct NS16550),
.probe = ns16550_serial_probe,
.ops = &ns16550_serial_ops,
};

View File

@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
#include <common.h>
#include <asm/arch/slimbootloader.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* This sets tsc_base and clock_rate for early_timer and tsc_timer.
* The performance info guid hob has all performance timestamp data, but
* the only tsc frequency info is used for the timer driver for now.
*
* Slim Bootloader already calibrated TSC and provides it to U-Boot.
* Therefore, U-Boot does not have to re-calibrate TSC.
* Configuring tsc_base and clock_rate here makes x86 tsc_timer driver
* bypass TSC calibration and use the provided TSC frequency.
*/
static void tsc_init(void)
{
struct sbl_performance_info *data;
const efi_guid_t guid = SBL_PERFORMANCE_INFO_GUID;
if (!gd->arch.hob_list)
panic("hob list not found!");
gd->arch.tsc_base = rdtsc();
debug("tsc_base=0x%llx\n", gd->arch.tsc_base);
data = hob_get_guid_hob_data(gd->arch.hob_list, NULL, &guid);
if (!data) {
debug("performance info hob not found\n");
return;
}
/* frequency is in KHz, so to Hz */
gd->arch.clock_rate = data->frequency * 1000;
debug("freq=0x%lx\n", gd->arch.clock_rate);
}
int arch_cpu_init(void)
{
tsc_init();
return x86_cpu_init_f();
}
int checkcpu(void)
{
return 0;
}
int print_cpuinfo(void)
{
return default_print_cpuinfo();
}

View File

@ -97,7 +97,7 @@ early_board_init_ret:
jmp car_init
.globl car_init_ret
car_init_ret:
#ifndef CONFIG_HAVE_FSP
#ifndef CONFIG_USE_HOB
/*
* We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM,
* or fully initialised SDRAM - we really don't care which)
@ -137,12 +137,13 @@ car_init_ret:
/* Get address of global_data */
mov %fs:0, %edx
#ifdef CONFIG_HAVE_FSP
#ifdef CONFIG_USE_HOB
/* Store the HOB list if we have one */
test %esi, %esi
jz skip_hob
movl %esi, GD_HOB_LIST(%edx)
#ifdef CONFIG_HAVE_FSP
/*
* After fsp_init() returns, the stack has already been switched to a
* place within system memory as defined by CONFIG_FSP_TEMP_RAM_ADDR.
@ -151,6 +152,7 @@ car_init_ret:
*/
subl $CONFIG_FSP_SYS_MALLOC_F_LEN, %esp
movl %esp, GD_MALLOC_BASE(%edx)
#endif
skip_hob:
#else
/* Store table pointer */

View File

@ -68,6 +68,44 @@ u32 acpi_fill_mcfg(u32 current)
return current;
}
static u32 acpi_fill_csrt_dma(struct acpi_csrt_group *grp)
{
struct acpi_csrt_shared_info *si = (struct acpi_csrt_shared_info *)&grp[1];
/* Fill the Resource Group with Shared Information attached */
memset(grp, 0, sizeof(*grp));
grp->shared_info_length = sizeof(struct acpi_csrt_shared_info);
grp->length = sizeof(struct acpi_csrt_group) + grp->shared_info_length;
/* TODO: All values below should come from U-Boot DT somehow */
sprintf((char *)&grp->vendor_id, "%04X", 0x8086);
grp->device_id = 0x11a2;
/* Fill the Resource Group Shared Information */
memset(si, 0, sizeof(*si));
si->major_version = 1;
si->minor_version = 0;
/* TODO: All values below should come from U-Boot DT somehow */
si->mmio_base_low = 0xff192000;
si->mmio_base_high = 0;
si->gsi_interrupt = 32;
si->interrupt_polarity = 1;
si->interrupt_mode = 0;
si->num_channels = 8;
si->dma_address_width = 32;
si->base_request_line = 0;
si->num_handshake_signals = 16;
si->max_block_size = 0x20000;
return grp->length;
}
u32 acpi_fill_csrt(u32 current)
{
current += acpi_fill_csrt_dma((struct acpi_csrt_group *)current);
return current;
}
void acpi_create_gnvs(struct acpi_global_nvs *gnvs)
{
struct udevice *dev;

View File

@ -18,6 +18,7 @@ dtb-y += bayleybay.dtb \
qemu-x86_i440fx.dtb \
qemu-x86_q35.dtb \
theadorable-x86-dfi-bt700.dtb \
slimbootloader.dtb \
baytrail_som-db5800-som-6867.dtb
targets += $(dtb-y)

View File

@ -84,15 +84,10 @@
reg = <0xff3fc000 0x1000>;
};
/*
* FIXME: For now U-Boot DM model doesn't allow to power up this controller.
* Enabling it will make U-Boot hang.
*
sdcard: mmc@ff3fa000 {
compatible = "intel,sdhci-tangier";
reg = <0xff3fa000 0x1000>;
};
*/
pmu: power@ff00b000 {
compatible = "intel,pmu-mid";

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
/dts-v1/;
/include/ "skeleton.dtsi"
/include/ "reset.dtsi"
/include/ "tsc_timer.dtsi"
/ {
model = "slimbootloader x86 payload";
compatible = "slimbootloader,x86-payload";
chosen {
stdout-path = &serial;
};
serial: serial {
compatible = "intel,slimbootloader-uart";
};
pci {
compatible = "pci-x86";
};
};

View File

@ -303,6 +303,37 @@ struct acpi_mcfg_mmconfig {
/* ACPI global NVS structure */
struct acpi_global_nvs;
/* CSRT (Core System Resource Table) */
struct acpi_csrt {
struct acpi_table_header header;
};
struct acpi_csrt_group {
u32 length;
u32 vendor_id;
u32 subvendor_id;
u16 device_id;
u16 subdevice_id;
u16 revision;
u16 reserved;
u32 shared_info_length;
};
struct acpi_csrt_shared_info {
u16 major_version;
u16 minor_version;
u32 mmio_base_low;
u32 mmio_base_high;
u32 gsi_interrupt;
u8 interrupt_polarity;
u8 interrupt_mode;
u8 num_channels;
u8 dma_address_width;
u16 base_request_line;
u16 num_handshake_signals;
u32 max_block_size;
};
/* DBG2 definitions are partially used for SPCR interface_type */
/* Types for port_type field */
@ -370,6 +401,7 @@ u32 acpi_fill_madt(u32 current);
int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base,
u16 seg_nr, u8 start, u8 end);
u32 acpi_fill_mcfg(u32 current);
u32 acpi_fill_csrt(u32 current);
void acpi_create_gnvs(struct acpi_global_nvs *gnvs);
ulong write_acpi_tables(ulong start);

View File

@ -0,0 +1,115 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
#ifndef __SLIMBOOTLOADER_ARCH_H__
#define __SLIMBOOTLOADER_ARCH_H__
#include <common.h>
#include <asm/hob.h>
/**
* A GUID to get MemoryMap info hob which is provided by Slim Bootloader
*/
#define SBL_MEMORY_MAP_INFO_GUID \
EFI_GUID(0xa1ff7424, 0x7a1a, 0x478e, \
0xa9, 0xe4, 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32)
/**
* A GUID to get SerialPort info hob which is provided by Slim Bootloader
*/
#define SBL_SERIAL_PORT_INFO_GUID \
EFI_GUID(0x6c6872fe, 0x56a9, 0x4403, \
0xbb, 0x98, 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1)
/**
* A GUID to get boot performance info hob which is provided by Slim Bootloader
*/
#define SBL_PERFORMANCE_INFO_GUID \
EFI_GUID(0x868204be, 0x23d0, 0x4ff9, \
0xac, 0x34, 0xb9, 0x95, 0xac, 0x04, 0xb1, 0xb9)
/**
* A single entry of memory map information
*
* @addr: start address of a memory map entry
* @size: size of a memory map entry
* @type: usable:1, reserved:2, acpi:3, nvs:4, unusable:5
* @flag: only used in Slim Bootloader
* @rsvd: padding for alignment
*/
struct sbl_memory_map_entry {
u64 addr;
u64 size;
u8 type;
u8 flag;
u8 rsvd[6];
};
/**
* This includes all memory map entries which is sorted based on physical start
* address, from low to high, and carved out reserved, acpi nvs, acpi reclaim
* and usable memory.
*
* @rev : revision of memory_map_info structure. currently 1.
* @rsvd : padding for alignment
* @count: the number of memory map entries
* @entry: array of all memory map entries
*/
struct sbl_memory_map_info {
u8 rev;
u8 rsvd[3];
u32 count;
struct sbl_memory_map_entry entry[0];
};
/**
* This includes serial port info which has already been initialized in previous
* Slim Bootloader stage.
* The Slim Bootloader initializes serial port regardless of debug/release build
* modes, and it passes the information to a payload thru hob. So, a payload can
* re-use the serial information without re-initializing serial port.
*
* @rev : revision of serial_port_info structure. currently 1.
* @rsvd : padding for alignment
* @type : port io: 1, mmio: 2
* @base : io base address. ex) 0x3f8, 0x80001000
* @baud : uart baud rate
* @stride: register stride in Bytes
* @clk : uart frequency in Hz
* @rsvd1 : reserved
*/
struct sbl_serial_port_info {
u8 rev;
u8 rsvd[3];
u32 type;
u32 base;
u32 baud;
u32 stride;
u32 clk;
u32 rsvd1;
};
/**
* This includes timestamp data which has been collected in Slim Bootloader
* stages from the reset vector. In addition, this has TSC frequency in KHz to
* calculate each timestamp.
*
* @rev : revision of performance_info structure. currently 1.
* @rsvd : padding for alignment
* @count : the number of collected timestamp data
* @flags : only used in Slim Bootloader
* @frequency: tsc frequency in KHz
* @timestamp: the array of timestamp data which has 64-bit tsc value
*/
struct sbl_performance_info {
u8 rev;
u8 rsvd[3];
u16 count;
u16 flags;
u32 frequency;
u64 timestamp[0];
};
#endif /* __SLIMBOOTLOADER_ARCH_H__ */

View File

@ -421,6 +421,28 @@ Device (PCI0)
}
}
}
Device (GDMA)
{
Name (_ADR, 0x00150000)
Name (_HID, "808611A2")
Name (_UID, Zero)
Method (_STA, 0, NotSerialized)
{
Return (STA_VISIBLE)
}
Method (_CRS, 0, Serialized)
{
Name (RBUF, ResourceTemplate ()
{
Memory32Fixed(ReadWrite, 0xFF192000, 0x00001000)
Interrupt(ResourceConsumer, Level, ActiveHigh, Shared, ,, ) { 32 }
})
Return (RBUF)
}
}
}
Device (FLIS)

View File

@ -45,7 +45,7 @@ struct __packed ffs_file_header {
* This GUID is the file name.
* It is used to uniquely identify the file.
*/
struct efi_guid name;
efi_guid_t name;
/* Used to verify the integrity of the file */
union ffs_integrity integrity;
/* Identifies the type of file */
@ -68,7 +68,7 @@ struct __packed ffs_file_header2 {
* Name in any given firmware volume, except if the file type is
* EFI_FV_FILE_TYPE_FFS_PAD.
*/
struct efi_guid name;
efi_guid_t name;
/* Used to verify the integrity of the file */
union ffs_integrity integrity;
/* Identifies the type of file */

View File

@ -80,7 +80,7 @@ struct fv_header {
* Declares the file system with which the firmware volume
* is formatted.
*/
struct efi_guid fs_guid;
efi_guid_t fs_guid;
/*
* Length in bytes of the complete firmware volume, including
* the header.
@ -128,7 +128,7 @@ struct fv_header {
/* Extension header pointed by ExtHeaderOffset of volume header */
struct fv_ext_header {
/* firmware volume name */
struct efi_guid fv_name;
efi_guid_t fv_name;
/* Size of the rest of the extension header including this structure */
u32 ext_hdr_size;
};

View File

@ -7,124 +7,7 @@
#ifndef __FSP_HOB_H__
#define __FSP_HOB_H__
#include <efi.h>
/* Type of HOB Header */
#define HOB_TYPE_MEM_ALLOC 0x0002
#define HOB_TYPE_RES_DESC 0x0003
#define HOB_TYPE_GUID_EXT 0x0004
#define HOB_TYPE_UNUSED 0xFFFE
#define HOB_TYPE_EOH 0xFFFF
/*
* Describes the format and size of the data inside the HOB.
* All HOBs must contain this generic HOB header.
*/
struct hob_header {
u16 type; /* HOB type */
u16 len; /* HOB length */
u32 reserved; /* always zero */
};
/*
* Describes all memory ranges used during the HOB producer phase that
* exist outside the HOB list. This HOB type describes how memory is used,
* not the physical attributes of memory.
*/
struct hob_mem_alloc {
struct hob_header hdr;
/*
* A GUID that defines the memory allocation region's type and purpose,
* as well as other fields within the memory allocation HOB. This GUID
* is used to define the additional data within the HOB that may be
* present for the memory allocation HOB. Type efi_guid is defined in
* InstallProtocolInterface() in the UEFI 2.0 specification.
*/
struct efi_guid name;
/*
* The base address of memory allocated by this HOB.
* Type phys_addr_t is defined in AllocatePages() in the UEFI 2.0
* specification.
*/
phys_addr_t mem_base;
/* The length in bytes of memory allocated by this HOB */
phys_size_t mem_len;
/*
* Defines the type of memory allocated by this HOB.
* The memory type definition follows the EFI_MEMORY_TYPE definition.
* Type EFI_MEMORY_TYPE is defined in AllocatePages() in the UEFI 2.0
* specification.
*/
enum efi_mem_type mem_type;
/* padding */
u8 reserved[4];
};
/* Value of ResourceType in HOB_RES_DESC */
#define RES_SYS_MEM 0x00000000
#define RES_MMAP_IO 0x00000001
#define RES_IO 0x00000002
#define RES_FW_DEVICE 0x00000003
#define RES_MMAP_IO_PORT 0x00000004
#define RES_MEM_RESERVED 0x00000005
#define RES_IO_RESERVED 0x00000006
#define RES_MAX_MEM_TYPE 0x00000007
/*
* These types can be ORed together as needed.
*
* The first three enumerations describe settings
* The rest of the settings describe capabilities
*/
#define RES_ATTR_PRESENT 0x00000001
#define RES_ATTR_INITIALIZED 0x00000002
#define RES_ATTR_TESTED 0x00000004
#define RES_ATTR_SINGLE_BIT_ECC 0x00000008
#define RES_ATTR_MULTIPLE_BIT_ECC 0x00000010
#define RES_ATTR_ECC_RESERVED_1 0x00000020
#define RES_ATTR_ECC_RESERVED_2 0x00000040
#define RES_ATTR_READ_PROTECTED 0x00000080
#define RES_ATTR_WRITE_PROTECTED 0x00000100
#define RES_ATTR_EXECUTION_PROTECTED 0x00000200
#define RES_ATTR_UNCACHEABLE 0x00000400
#define RES_ATTR_WRITE_COMBINEABLE 0x00000800
#define RES_ATTR_WRITE_THROUGH_CACHEABLE 0x00001000
#define RES_ATTR_WRITE_BACK_CACHEABLE 0x00002000
#define RES_ATTR_16_BIT_IO 0x00004000
#define RES_ATTR_32_BIT_IO 0x00008000
#define RES_ATTR_64_BIT_IO 0x00010000
#define RES_ATTR_UNCACHED_EXPORTED 0x00020000
/*
* Describes the resource properties of all fixed, nonrelocatable resource
* ranges found on the processor host bus during the HOB producer phase.
*/
struct hob_res_desc {
struct hob_header hdr;
/*
* A GUID representing the owner of the resource. This GUID is
* used by HOB consumer phase components to correlate device
* ownership of a resource.
*/
struct efi_guid owner;
u32 type;
u32 attr;
/* The physical start address of the resource region */
phys_addr_t phys_start;
/* The number of bytes of the resource region */
phys_size_t len;
};
/*
* Allows writers of executable content in the HOB producer phase to
* maintain and manage HOBs with specific GUID.
*/
struct hob_guid {
struct hob_header hdr;
/* A GUID that defines the contents of this HOB */
struct efi_guid name;
/* GUID specific data goes here */
};
#include <asm/hob.h>
enum pixel_format {
pixel_rgbx_8bpc, /* RGB 8 bit per color */
@ -146,70 +29,6 @@ struct __packed hob_graphics_info {
u32 pixels_per_scanline;
};
/**
* get_next_hob() - return a pointer to the next HOB in the HOB list
*
* This macro returns a pointer to HOB that follows the HOB specified by hob
* in the HOB List.
*
* @hdr: A pointer to a HOB.
*
* @return: A pointer to the next HOB in the HOB list.
*/
static inline const struct hob_header *get_next_hob(const struct hob_header *hdr)
{
return (const struct hob_header *)((uintptr_t)hdr + hdr->len);
}
/**
* end_of_hob() - determine if a HOB is the last HOB in the HOB list
*
* This macro determine if the HOB specified by hob is the last HOB in the
* HOB list. If hob is last HOB in the HOB list, then true is returned.
* Otherwise, false is returned.
*
* @hdr: A pointer to a HOB.
*
* @retval true: The HOB specified by hdr is the last HOB in the HOB list.
* @retval false: The HOB specified by hdr is not the last HOB in the HOB list.
*/
static inline bool end_of_hob(const struct hob_header *hdr)
{
return hdr->type == HOB_TYPE_EOH;
}
/**
* get_guid_hob_data() - return a pointer to data buffer from a HOB of
* type HOB_TYPE_GUID_EXT
*
* This macro returns a pointer to the data buffer in a HOB specified by hob.
* hob is assumed to be a HOB of type HOB_TYPE_GUID_EXT.
*
* @hdr: A pointer to a HOB.
*
* @return: A pointer to the data buffer in a HOB.
*/
static inline void *get_guid_hob_data(const struct hob_header *hdr)
{
return (void *)((uintptr_t)hdr + sizeof(struct hob_guid));
}
/**
* get_guid_hob_data_size() - return the size of the data buffer from a HOB
* of type HOB_TYPE_GUID_EXT
*
* This macro returns the size, in bytes, of the data buffer in a HOB
* specified by hob. hob is assumed to be a HOB of type HOB_TYPE_GUID_EXT.
*
* @hdr: A pointer to a HOB.
*
* @return: The size of the data buffer.
*/
static inline u16 get_guid_hob_data_size(const struct hob_header *hdr)
{
return hdr->len - sizeof(struct hob_guid);
}
/* FSP specific GUID HOB definitions */
#define FSP_GUID_DATA1 0x912740be
#define FSP_GUID_DATA2 0x2284
@ -223,56 +42,57 @@ static inline u16 get_guid_hob_data_size(const struct hob_header *hdr)
#define FSP_GUID_DATA4_6 0x3f
#define FSP_GUID_DATA4_7 0x0c
#define FSP_GUID_BYTE0 0xbe
#define FSP_GUID_BYTE1 0x40
#define FSP_GUID_BYTE2 0x27
#define FSP_GUID_BYTE3 0x91
#define FSP_GUID_BYTE4 0x84
#define FSP_GUID_BYTE5 0x22
#define FSP_GUID_BYTE6 0x34
#define FSP_GUID_BYTE7 0x47
#define FSP_GUID_BYTE8 FSP_GUID_DATA4_0
#define FSP_GUID_BYTE9 FSP_GUID_DATA4_1
#define FSP_GUID_BYTE10 FSP_GUID_DATA4_2
#define FSP_GUID_BYTE11 FSP_GUID_DATA4_3
#define FSP_GUID_BYTE12 FSP_GUID_DATA4_4
#define FSP_GUID_BYTE13 FSP_GUID_DATA4_5
#define FSP_GUID_BYTE14 FSP_GUID_DATA4_6
#define FSP_GUID_BYTE15 FSP_GUID_DATA4_7
#define FSP_HEADER_GUID \
{ \
FSP_GUID_DATA1, FSP_GUID_DATA2, FSP_GUID_DATA3, \
{ FSP_GUID_DATA4_0, FSP_GUID_DATA4_1, FSP_GUID_DATA4_2, \
FSP_GUID_DATA4_3, FSP_GUID_DATA4_4, FSP_GUID_DATA4_5, \
FSP_GUID_DATA4_6, FSP_GUID_DATA4_7 } \
}
EFI_GUID(FSP_GUID_DATA1, FSP_GUID_DATA2, FSP_GUID_DATA3, \
FSP_GUID_DATA4_0, FSP_GUID_DATA4_1, FSP_GUID_DATA4_2, \
FSP_GUID_DATA4_3, FSP_GUID_DATA4_4, FSP_GUID_DATA4_5, \
FSP_GUID_DATA4_6, FSP_GUID_DATA4_7)
#define FSP_NON_VOLATILE_STORAGE_HOB_GUID \
{ \
0x721acf02, 0x4d77, 0x4c2a, \
{ 0xb3, 0xdc, 0x27, 0xb, 0x7b, 0xa9, 0xe4, 0xb0 } \
}
EFI_GUID(0x721acf02, 0x4d77, 0x4c2a, \
0xb3, 0xdc, 0x27, 0x0b, 0x7b, 0xa9, 0xe4, 0xb0)
#define FSP_BOOTLOADER_TEMP_MEM_HOB_GUID \
{ \
0xbbcff46c, 0xc8d3, 0x4113, \
{ 0x89, 0x85, 0xb9, 0xd4, 0xf3, 0xb3, 0xf6, 0x4e } \
}
EFI_GUID(0xbbcff46c, 0xc8d3, 0x4113, \
0x89, 0x85, 0xb9, 0xd4, 0xf3, 0xb3, 0xf6, 0x4e)
#define FSP_HOB_RESOURCE_OWNER_FSP_GUID \
{ \
0x69a79759, 0x1373, 0x4367, \
{ 0xa6, 0xc4, 0xc7, 0xf5, 0x9e, 0xfd, 0x98, 0x6e } \
}
EFI_GUID(0x69a79759, 0x1373, 0x4367, \
0xa6, 0xc4, 0xc7, 0xf5, 0x9e, 0xfd, 0x98, 0x6e)
#define FSP_HOB_RESOURCE_OWNER_TSEG_GUID \
{ \
0xd038747c, 0xd00c, 0x4980, \
{ 0xb3, 0x19, 0x49, 0x01, 0x99, 0xa4, 0x7d, 0x55 } \
}
EFI_GUID(0xd038747c, 0xd00c, 0x4980, \
0xb3, 0x19, 0x49, 0x01, 0x99, 0xa4, 0x7d, 0x55)
#define FSP_HOB_RESOURCE_OWNER_GRAPHICS_GUID \
{ \
0x9c7c3aa7, 0x5332, 0x4917, \
{ 0x82, 0xb9, 0x56, 0xa5, 0xf3, 0xe6, 0x2a, 0x07 } \
}
EFI_GUID(0x9c7c3aa7, 0x5332, 0x4917, \
0x82, 0xb9, 0x56, 0xa5, 0xf3, 0xe6, 0x2a, 0x07)
/* The following GUIDs are newly introduced in FSP spec 1.1 */
#define FSP_HOB_RESOURCE_OWNER_BOOTLOADER_TOLUM_GUID \
{ \
0x73ff4f56, 0xaa8e, 0x4451, \
{ 0xb3, 0x16, 0x36, 0x35, 0x36, 0x67, 0xad, 0x44 } \
}
EFI_GUID(0x73ff4f56, 0xaa8e, 0x4451, \
0xb3, 0x16, 0x36, 0x35, 0x36, 0x67, 0xad, 0x44)
#define FSP_GRAPHICS_INFO_HOB_GUID \
{ \
0x39f62cce, 0x6825, 0x4669, \
{ 0xbb, 0x56, 0x54, 0x1a, 0xba, 0x75, 0x3a, 0x07 } \
}
EFI_GUID(0x39f62cce, 0x6825, 0x4669, \
0xbb, 0x56, 0x54, 0x1a, 0xba, 0x75, 0x3a, 0x07)
#endif

View File

@ -8,10 +8,10 @@
#define __FSP_SUPPORT_H__
#include "fsp_types.h"
#include "fsp_hob.h"
#include "fsp_fv.h"
#include "fsp_ffs.h"
#include "fsp_api.h"
#include "fsp_hob.h"
#include "fsp_infoheader.h"
#include "fsp_bootmode.h"
#include "fsp_azalia.h"
@ -106,7 +106,7 @@ u64 fsp_get_usable_highmem_top(const void *hob_list);
* 0 if this region does not exist.
*/
u64 fsp_get_reserved_mem_from_guid(const void *hob_list,
u64 *len, struct efi_guid *guid);
u64 *len, const efi_guid_t *guid);
/**
* This function retrieves the FSP reserved normal memory.
@ -131,41 +131,6 @@ u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len);
*/
u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len);
/**
* 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
*
* @retval: A HOB object with matching type; Otherwise NULL.
*/
const struct hob_header *fsp_get_next_hob(uint type, const void *hob_list);
/**
* 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
*
* @retval: A HOB object with matching GUID; Otherwise NULL.
*/
const struct hob_header *fsp_get_next_guid_hob(const struct efi_guid *guid,
const void *hob_list);
/**
* 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.
*
* @retval NULL: Failed to find the GUID HOB.
* @retval others: GUID HOB data buffer pointer.
*/
void *fsp_get_guid_hob_data(const void *hob_list, u32 *len,
struct efi_guid *guid);
/**
* This function retrieves FSP Non-volatile Storage HOB buffer and size.
*

View File

@ -7,14 +7,6 @@
#ifndef __FSP_TYPES_H__
#define __FSP_TYPES_H__
/* 128 bit buffer containing a unique identifier value */
struct efi_guid {
u32 data1;
u16 data2;
u16 data3;
u8 data4[8];
};
/**
* Returns a 16-bit signature built from 2 ASCII characters.
*

View File

@ -83,7 +83,7 @@ struct arch_global_data {
const struct pch_gpio_map *gpio_map; /* board GPIO map */
struct memory_info meminfo; /* Memory information */
struct pei_memory_info pei_meminfo; /* PEI memory information */
#ifdef CONFIG_HAVE_FSP
#ifdef CONFIG_USE_HOB
void *hob_list; /* FSP HOB list */
#endif
struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS];

230
arch/x86/include/asm/hob.h Normal file
View File

@ -0,0 +1,230 @@
/* SPDX-License-Identifier: Intel */
/*
* Copyright (C) 2013, Intel Corporation
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
*/
#ifndef __HOB_H__
#define __HOB_H__
#include <efi.h>
#include <efi_loader.h>
/* Type of HOB Header */
#define HOB_TYPE_MEM_ALLOC 0x0002
#define HOB_TYPE_RES_DESC 0x0003
#define HOB_TYPE_GUID_EXT 0x0004
#define HOB_TYPE_UNUSED 0xFFFE
#define HOB_TYPE_EOH 0xFFFF
/* Value of ResourceType in HOB_RES_DESC */
#define RES_SYS_MEM 0x00000000
#define RES_MMAP_IO 0x00000001
#define RES_IO 0x00000002
#define RES_FW_DEVICE 0x00000003
#define RES_MMAP_IO_PORT 0x00000004
#define RES_MEM_RESERVED 0x00000005
#define RES_IO_RESERVED 0x00000006
#define RES_MAX_MEM_TYPE 0x00000007
/*
* These types can be ORed together as needed.
*
* The first three enumerations describe settings
* The rest of the settings describe capabilities
*/
#define RES_ATTR_PRESENT 0x00000001
#define RES_ATTR_INITIALIZED 0x00000002
#define RES_ATTR_TESTED 0x00000004
#define RES_ATTR_SINGLE_BIT_ECC 0x00000008
#define RES_ATTR_MULTIPLE_BIT_ECC 0x00000010
#define RES_ATTR_ECC_RESERVED_1 0x00000020
#define RES_ATTR_ECC_RESERVED_2 0x00000040
#define RES_ATTR_READ_PROTECTED 0x00000080
#define RES_ATTR_WRITE_PROTECTED 0x00000100
#define RES_ATTR_EXECUTION_PROTECTED 0x00000200
#define RES_ATTR_UNCACHEABLE 0x00000400
#define RES_ATTR_WRITE_COMBINEABLE 0x00000800
#define RES_ATTR_WRITE_THROUGH_CACHEABLE 0x00001000
#define RES_ATTR_WRITE_BACK_CACHEABLE 0x00002000
#define RES_ATTR_16_BIT_IO 0x00004000
#define RES_ATTR_32_BIT_IO 0x00008000
#define RES_ATTR_64_BIT_IO 0x00010000
#define RES_ATTR_UNCACHED_EXPORTED 0x00020000
/*
* Describes the format and size of the data inside the HOB.
* All HOBs must contain this generic HOB header.
*/
struct hob_header {
u16 type; /* HOB type */
u16 len; /* HOB length */
u32 reserved; /* always zero */
};
/*
* Describes all memory ranges used during the HOB producer phase that
* exist outside the HOB list. This HOB type describes how memory is used,
* not the physical attributes of memory.
*/
struct hob_mem_alloc {
struct hob_header hdr;
/*
* A GUID that defines the memory allocation region's type and purpose,
* as well as other fields within the memory allocation HOB. This GUID
* is used to define the additional data within the HOB that may be
* present for the memory allocation HOB. Type efi_guid_t is defined in
* InstallProtocolInterface() in the UEFI 2.0 specification.
*/
efi_guid_t name;
/*
* The base address of memory allocated by this HOB.
* Type phys_addr_t is defined in AllocatePages() in the UEFI 2.0
* specification.
*/
phys_addr_t mem_base;
/* The length in bytes of memory allocated by this HOB */
phys_size_t mem_len;
/*
* Defines the type of memory allocated by this HOB.
* The memory type definition follows the EFI_MEMORY_TYPE definition.
* Type EFI_MEMORY_TYPE is defined in AllocatePages() in the UEFI 2.0
* specification.
*/
enum efi_mem_type mem_type;
/* padding */
u8 reserved[4];
};
/*
* Describes the resource properties of all fixed, nonrelocatable resource
* ranges found on the processor host bus during the HOB producer phase.
*/
struct hob_res_desc {
struct hob_header hdr;
/*
* A GUID representing the owner of the resource. This GUID is
* used by HOB consumer phase components to correlate device
* ownership of a resource.
*/
efi_guid_t owner;
u32 type;
u32 attr;
/* The physical start address of the resource region */
phys_addr_t phys_start;
/* The number of bytes of the resource region */
phys_size_t len;
};
/*
* Allows writers of executable content in the HOB producer phase to
* maintain and manage HOBs with specific GUID.
*/
struct hob_guid {
struct hob_header hdr;
/* A GUID that defines the contents of this HOB */
efi_guid_t name;
/* GUID specific data goes here */
};
/**
* get_next_hob() - return a pointer to the next HOB in the HOB list
*
* This macro returns a pointer to HOB that follows the HOB specified by hob
* in the HOB List.
*
* @hdr: A pointer to a HOB.
*
* @return: A pointer to the next HOB in the HOB list.
*/
static inline const struct hob_header *get_next_hob(const struct hob_header
*hdr)
{
return (const struct hob_header *)((uintptr_t)hdr + hdr->len);
}
/**
* end_of_hob() - determine if a HOB is the last HOB in the HOB list
*
* This macro determine if the HOB specified by hob is the last HOB in the
* HOB list. If hob is last HOB in the HOB list, then true is returned.
* Otherwise, false is returned.
*
* @hdr: A pointer to a HOB.
*
* @retval true: The HOB specified by hdr is the last HOB in the HOB list.
* @retval false: The HOB specified by hdr is not the last HOB in the HOB list.
*/
static inline bool end_of_hob(const struct hob_header *hdr)
{
return hdr->type == HOB_TYPE_EOH;
}
/**
* get_guid_hob_data() - return a pointer to data buffer from a HOB of
* type HOB_TYPE_GUID_EXT
*
* This macro returns a pointer to the data buffer in a HOB specified by hob.
* hob is assumed to be a HOB of type HOB_TYPE_GUID_EXT.
*
* @hdr: A pointer to a HOB.
*
* @return: A pointer to the data buffer in a HOB.
*/
static inline void *get_guid_hob_data(const struct hob_header *hdr)
{
return (void *)((uintptr_t)hdr + sizeof(struct hob_guid));
}
/**
* get_guid_hob_data_size() - return the size of the data buffer from a HOB
* of type HOB_TYPE_GUID_EXT
*
* This macro returns the size, in bytes, of the data buffer in a HOB
* specified by hob. hob is assumed to be a HOB of type HOB_TYPE_GUID_EXT.
*
* @hdr: A pointer to a HOB.
*
* @return: The size of the data buffer.
*/
static inline u16 get_guid_hob_data_size(const struct hob_header *hdr)
{
return hdr->len - sizeof(struct hob_guid);
}
/**
* 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
*
* @retval: A HOB object with matching type; Otherwise NULL.
*/
const struct hob_header *hob_get_next_hob(uint type, const void *hob_list);
/**
* 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
*
* @retval: 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);
/**
* 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.
*
* @retval NULL: Failed to find the GUID HOB.
* @retval others: GUID HOB data buffer pointer.
*/
void *hob_get_guid_hob_data(const void *hob_list, u32 *len,
const efi_guid_t *guid);
#endif /* __HOB_H__ */

View File

@ -42,6 +42,7 @@ obj-y += tables.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_CMD_ZBOOT) += zimage.o
endif
obj-$(CONFIG_USE_HOB) += hob.o
obj-$(CONFIG_HAVE_FSP) += fsp/
ifdef CONFIG_SPL_BUILD

View File

@ -337,6 +337,30 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
header->checksum = table_compute_checksum((void *)mcfg, header->length);
}
__weak u32 acpi_fill_csrt(u32 current)
{
return current;
}
static void acpi_create_csrt(struct acpi_csrt *csrt)
{
struct acpi_table_header *header = &(csrt->header);
u32 current = (u32)csrt + sizeof(struct acpi_csrt);
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;
current = acpi_fill_csrt(current);
/* (Re)calculate length and checksum */
header->length = current - (u32)csrt;
header->checksum = table_compute_checksum((void *)csrt, header->length);
}
static void acpi_create_spcr(struct acpi_spcr *spcr)
{
struct acpi_table_header *header = &(spcr->header);
@ -464,6 +488,7 @@ ulong write_acpi_tables(ulong start)
struct acpi_fadt *fadt;
struct acpi_mcfg *mcfg;
struct acpi_madt *madt;
struct acpi_csrt *csrt;
struct acpi_spcr *spcr;
int i;
@ -553,6 +578,13 @@ ulong write_acpi_tables(ulong start)
acpi_add_table(rsdp, mcfg);
current = ALIGN(current, 16);
debug("ACPI: * CSRT\n");
csrt = (struct acpi_csrt *)current;
acpi_create_csrt(csrt);
current += csrt->header.length;
acpi_add_table(rsdp, csrt);
current = ALIGN(current, 16);
debug("ACPI: * SPCR\n");
spcr = (struct acpi_spcr *)current;
acpi_create_spcr(spcr);

View File

@ -17,7 +17,7 @@
int main(void)
{
DEFINE(GD_BIST, offsetof(gd_t, arch.bist));
#ifdef CONFIG_HAVE_FSP
#ifdef CONFIG_USE_HOB
DEFINE(GD_HOB_LIST, offsetof(gd_t, arch.hob_list));
#endif
DEFINE(GD_TABLE, offsetof(gd_t, arch.table));

View File

@ -8,27 +8,6 @@
#include <asm/fsp/fsp_support.h>
#include <asm/post.h>
/**
* Compares two GUIDs
*
* If the GUIDs are identical then true is returned.
* If there are any bit differences in the two GUIDs, then false is returned.
*
* @guid1: A pointer to a 128 bit GUID.
* @guid2: A pointer to a 128 bit GUID.
*
* @retval true: guid1 and guid2 are identical.
* @retval false: guid1 and guid2 are not identical.
*/
static bool compare_guid(const struct efi_guid *guid1,
const struct efi_guid *guid2)
{
if (memcmp(guid1, guid2, sizeof(struct efi_guid)) == 0)
return true;
else
return false;
}
struct fsp_header *__attribute__((optimize("O0"))) find_fsp_header(void)
{
/*
@ -58,17 +37,22 @@ struct fsp_header *__attribute__((optimize("O0"))) find_fsp_header(void)
/* Check the FFS GUID */
if (fsp &&
((struct ffs_file_header *)fsp)->name.data1 == FSP_GUID_DATA1 &&
((struct ffs_file_header *)fsp)->name.data2 == FSP_GUID_DATA2 &&
((struct ffs_file_header *)fsp)->name.data3 == FSP_GUID_DATA3 &&
((struct ffs_file_header *)fsp)->name.data4[0] == FSP_GUID_DATA4_0 &&
((struct ffs_file_header *)fsp)->name.data4[1] == FSP_GUID_DATA4_1 &&
((struct ffs_file_header *)fsp)->name.data4[2] == FSP_GUID_DATA4_2 &&
((struct ffs_file_header *)fsp)->name.data4[3] == FSP_GUID_DATA4_3 &&
((struct ffs_file_header *)fsp)->name.data4[4] == FSP_GUID_DATA4_4 &&
((struct ffs_file_header *)fsp)->name.data4[5] == FSP_GUID_DATA4_5 &&
((struct ffs_file_header *)fsp)->name.data4[6] == FSP_GUID_DATA4_6 &&
((struct ffs_file_header *)fsp)->name.data4[7] == FSP_GUID_DATA4_7) {
((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 {
@ -305,7 +289,7 @@ u64 fsp_get_usable_highmem_top(const void *hob_list)
}
u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len,
struct efi_guid *guid)
const efi_guid_t *guid)
{
const struct hob_header *hdr;
struct hob_res_desc *res_desc;
@ -318,7 +302,7 @@ u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len,
if (hdr->type == HOB_TYPE_RES_DESC) {
res_desc = (struct hob_res_desc *)hdr;
if (res_desc->type == RES_MEM_RESERVED) {
if (compare_guid(&res_desc->owner, guid)) {
if (!guidcmp(&res_desc->owner, guid)) {
if (len)
*len = (u32)(res_desc->len);
@ -334,12 +318,12 @@ u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len,
u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len)
{
const struct efi_guid guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID;
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, (struct efi_guid *)&guid);
&length, &guid);
if ((len != 0) && (base != 0))
*len = (u32)length;
@ -348,86 +332,35 @@ u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len)
u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len)
{
const struct efi_guid guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID;
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, (struct efi_guid *)&guid);
&length, &guid);
if ((len != 0) && (base != 0))
*len = (u32)length;
return base;
}
const struct hob_header *fsp_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;
}
const struct hob_header *fsp_get_next_guid_hob(const struct efi_guid *guid,
const void *hob_list)
{
const struct hob_header *hdr;
struct hob_guid *guid_hob;
hdr = hob_list;
while ((hdr = fsp_get_next_hob(HOB_TYPE_GUID_EXT,
hdr)) != NULL) {
guid_hob = (struct hob_guid *)hdr;
if (compare_guid(guid, &(guid_hob->name)))
break;
hdr = get_next_hob(hdr);
}
return hdr;
}
void *fsp_get_guid_hob_data(const void *hob_list, u32 *len,
struct efi_guid *guid)
{
const struct hob_header *guid_hob;
guid_hob = fsp_get_next_guid_hob(guid, hob_list);
if (guid_hob == NULL) {
return NULL;
} else {
if (len)
*len = get_guid_hob_data_size(guid_hob);
return get_guid_hob_data(guid_hob);
}
}
void *fsp_get_nvs_data(const void *hob_list, u32 *len)
{
const struct efi_guid guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID;
const efi_guid_t guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID;
return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
return hob_get_guid_hob_data(hob_list, len, &guid);
}
void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len)
{
const struct efi_guid guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID;
const efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID;
return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
return hob_get_guid_hob_data(hob_list, len, &guid);
}
void *fsp_get_graphics_info(const void *hob_list, u32 *len)
{
const struct efi_guid guid = FSP_GRAPHICS_INFO_HOB_GUID;
const efi_guid_t guid = FSP_GRAPHICS_INFO_HOB_GUID;
return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
return hob_get_guid_hob_data(hob_list, len, &guid);
}

84
arch/x86/lib/hob.c Normal file
View File

@ -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
*
* @retval: 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
*
* @retval: 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.
*
* @retval NULL: Failed to find the GUID HOB.
* @retval 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);
}

View File

@ -18,7 +18,8 @@ __weak ulong board_get_usable_ram_top(ulong total_size)
int init_cache_f_r(void)
{
#if CONFIG_IS_ENABLED(X86_32BIT_INIT) && !defined(CONFIG_HAVE_FSP)
#if CONFIG_IS_ENABLED(X86_32BIT_INIT) && !defined(CONFIG_HAVE_FSP) && \
!defined(CONFIG_SYS_SLIMBOOTLOADER)
int ret;
ret = mtrr_commit(false);

View File

@ -73,6 +73,19 @@ config TARGET_MINNOWMAX
Note that PCIE_ECAM_BASE is set up by the FSP so the value used
by U-Boot matches that value.
config TARGET_SLIMBOOTLOADER
bool "slimbootloader"
help
This target is used for running U-Boot on top of Slim Bootloader
boot firmware as a payload. Slim Bootloader does memory initialization
and silicon initialization, and it passes necessary information in
HOB (Hand Off Block) to a payload. The payload consumes HOB data
which is generated by Slim Bootloader for its driver initialization.
Slim Bootloader consumes FSP and its HOB, but FSP HOB is cleared
Before launching a payload. Instead, Slim Bootloader generates its
HOB data such as memory info, serial port info and so on.
Refer to doc/board/intel/slimbootloader.rst for the details.
endchoice
source "board/intel/bayleybay/Kconfig"
@ -82,5 +95,6 @@ source "board/intel/crownbay/Kconfig"
source "board/intel/edison/Kconfig"
source "board/intel/galileo/Kconfig"
source "board/intel/minnowmax/Kconfig"
source "board/intel/slimbootloader/Kconfig"
endif

View File

@ -13,9 +13,19 @@
#include <linux/usb/gadget.h>
#include <asm/cache.h>
#include <asm/pmu.h>
#include <asm/scu.h>
#include <asm/u-boot-x86.h>
/* List of Intel Tangier LSSs */
#define PMU_LSS_TANGIER_SDIO0_01 1
int board_early_init_r(void)
{
pmu_turn_power(PMU_LSS_TANGIER_SDIO0_01, true);
return 0;
}
static struct dwc3_device dwc3_device_data = {
.maximum_speed = USB_SPEED_HIGH,
.base = CONFIG_SYS_USB_OTG_BASE,

View File

@ -0,0 +1,28 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2019 Intel Corporation <www.intel.com>
if TARGET_SLIMBOOTLOADER
config SYS_BOARD
default "slimbootloader"
config SYS_VENDOR
default "intel"
config SYS_SOC
default "slimbootloader"
config SYS_CONFIG_NAME
default "slimbootloader"
config SYS_TEXT_BASE
default 0x00100000
config BOARD_SPECIFIC_OPTIONS
def_bool y
select SYS_SLIMBOOTLOADER
select USB_STORAGE
select USB_KEYBOARD
endif

View File

@ -0,0 +1,6 @@
Intel Slim Bootloader Payload
M: Aiden Park <aiden.park@intel.com>
S: Maintained
F: board/intel/slimbootloader
F: include/configs/slimbootloader.h
F: configs/slimbootloader_defconfig

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2019 Intel Corporation <www.intel.com>
obj-y += start.o slimbootloader.o

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
#include <common.h>
int board_early_init_r(void)
{
/*
* Make sure PCI bus is enumerated so that peripherals on the PCI bus
* can be discovered by their drivers.
*
* Slim Bootloader has already done PCI bus enumeration before loading
* U-Boot, so U-Boot needs to preserve PCI configuration.
* Therefore, '# CONFIG_PCI_PNP is not set' is included in defconfig.
*/
pci_init();
return 0;
}

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
/* board early initialization */
.globl early_board_init
early_board_init:
jmp early_board_init_ret

View File

@ -2,4 +2,5 @@
obj-y += mtrr.o
obj-$(CONFIG_CMD_EXCEPTION) += exception.o
obj-$(CONFIG_USE_HOB) += hob.o
obj-$(CONFIG_HAVE_FSP) += fsp.o

View File

@ -9,21 +9,6 @@
DECLARE_GLOBAL_DATA_PTR;
static char *hob_type[] = {
"reserved",
"Hand-off",
"Mem Alloc",
"Res Desc",
"GUID Ext",
"FV",
"CPU",
"Mem Pool",
"reserved",
"FV2",
"Load PEIM",
"Capsule",
};
static int do_hdr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct fsp_header *hdr = find_fsp_header();
@ -72,57 +57,8 @@ static int do_hdr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return 0;
}
static int do_hob(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
const struct hob_header *hdr;
uint type;
char *desc;
int i = 0;
hdr = gd->arch.hob_list;
printf("HOB list address: 0x%08x\n\n", (unsigned int)hdr);
printf("# | Address | Type | Len | ");
printf("%42s\n", "GUID");
printf("---|----------|-----------|------|-");
printf("------------------------------------------\n");
while (!end_of_hob(hdr)) {
printf("%02x | %08x | ", i, (unsigned int)hdr);
type = hdr->type;
if (type == HOB_TYPE_UNUSED)
desc = "*Unused*";
else if (type == HOB_TYPE_EOH)
desc = "*EOH*";
else if (type >= 0 && type <= ARRAY_SIZE(hob_type))
desc = hob_type[type];
else
desc = "*Invalid*";
printf("%-9s | %04x | ", desc, hdr->len);
if (type == HOB_TYPE_MEM_ALLOC || type == HOB_TYPE_RES_DESC ||
type == HOB_TYPE_GUID_EXT) {
struct efi_guid *guid = (struct efi_guid *)(hdr + 1);
int j;
printf("%08x-%04x-%04x", guid->data1,
guid->data2, guid->data3);
for (j = 0; j < ARRAY_SIZE(guid->data4); j++)
printf("-%02x", guid->data4[j]);
} else {
printf("%42s", "Not Available");
}
printf("\n");
hdr = get_next_hob(hdr);
i++;
}
return 0;
}
static cmd_tbl_t fsp_commands[] = {
U_BOOT_CMD_MKENT(hdr, 0, 1, do_hdr, "", ""),
U_BOOT_CMD_MKENT(hob, 0, 1, do_hob, "", ""),
};
static int do_fsp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
@ -146,6 +82,5 @@ static int do_fsp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
U_BOOT_CMD(
fsp, 2, 1, do_fsp,
"Show Intel Firmware Support Package (FSP) related information",
"hdr - Print FSP header information\n"
"fsp hob - Print FSP Hand-Off Block (HOB) information"
"hdr - Print FSP header information"
);

77
cmd/x86/hob.c Normal file
View File

@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014-2015, Bin Meng <bmeng.cn@gmail.com>
*/
#include <common.h>
#include <command.h>
#include <efi.h>
#include <asm/hob.h>
DECLARE_GLOBAL_DATA_PTR;
static char *hob_type[] = {
"reserved",
"Hand-off",
"Mem Alloc",
"Res Desc",
"GUID Ext",
"FV",
"CPU",
"Mem Pool",
"reserved",
"FV2",
"Load PEIM",
"Capsule",
};
static int do_hob(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
const struct hob_header *hdr;
uint type;
char *desc;
int i = 0;
efi_guid_t *guid;
char uuid[UUID_STR_LEN + 1];
hdr = gd->arch.hob_list;
printf("HOB list address: 0x%08x\n\n", (unsigned int)hdr);
printf("# | Address | Type | Len | ");
printf("%36s\n", "GUID");
printf("---|----------|-----------|------|-");
printf("------------------------------------\n");
while (!end_of_hob(hdr)) {
printf("%02x | %08x | ", i, (unsigned int)hdr);
type = hdr->type;
if (type == HOB_TYPE_UNUSED)
desc = "*Unused*";
else if (type == HOB_TYPE_EOH)
desc = "*EOH*";
else if (type >= 0 && type <= ARRAY_SIZE(hob_type))
desc = hob_type[type];
else
desc = "*Invalid*";
printf("%-9s | %04x | ", desc, hdr->len);
if (type == HOB_TYPE_MEM_ALLOC || type == HOB_TYPE_RES_DESC ||
type == HOB_TYPE_GUID_EXT) {
guid = (efi_guid_t *)(hdr + 1);
uuid_bin_to_str(guid->b, uuid, UUID_STR_FORMAT_GUID);
printf("%s", uuid);
} else {
printf("%36s", "Not Available");
}
printf("\n");
hdr = get_next_hob(hdr);
i++;
}
return 0;
}
U_BOOT_CMD(hob, 1, 1, do_hob,
"Print Hand-Off Block (HOB) information",
""
);

View File

@ -4,6 +4,7 @@ CONFIG_NR_DRAM_BANKS=3
CONFIG_VENDOR_INTEL=y
CONFIG_TARGET_EDISON=y
CONFIG_SMP=y
CONFIG_BOARD_EARLY_INIT_R=y
CONFIG_LAST_STAGE_INIT=y
CONFIG_HUSH_PARSER=y
# CONFIG_CMDLINE_EDITING is not set

View File

@ -12,6 +12,7 @@ CONFIG_SMP=y
CONFIG_GENERATE_PIRQ_TABLE=y
CONFIG_GENERATE_MP_TABLE=y
CONFIG_GENERATE_ACPI_TABLE=y
CONFIG_DISTRO_DEFAULTS=y
CONFIG_BUILD_ROM=y
CONFIG_FIT=y
CONFIG_SPL_LOAD_FIT=y

View File

@ -6,6 +6,7 @@ CONFIG_SMP=y
CONFIG_GENERATE_PIRQ_TABLE=y
CONFIG_GENERATE_MP_TABLE=y
CONFIG_GENERATE_ACPI_TABLE=y
CONFIG_DISTRO_DEFAULTS=y
CONFIG_BUILD_ROM=y
CONFIG_FIT=y
CONFIG_BOOTSTAGE=y

View File

@ -0,0 +1,22 @@
CONFIG_X86=y
CONFIG_VENDOR_INTEL=y
CONFIG_TARGET_SLIMBOOTLOADER=y
CONFIG_DEFAULT_DEVICE_TREE="slimbootloader"
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_SYS_CONSOLE_INFO_QUIET=y
CONFIG_BOARD_EARLY_INIT_R=y
CONFIG_LAST_STAGE_INIT=y
CONFIG_HUSH_PARSER=y
CONFIG_CMD_MMC=y
CONFIG_CMD_EXT2=y
CONFIG_CMD_FAT=y
CONFIG_CMD_USB=y
CONFIG_DOS_PARTITION=y
CONFIG_EFI_PARTITION=y
CONFIG_OF_CONTROL=y
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_BOOTDELAY=10
CONFIG_CONSOLE_SCROLL_LINES=5
# CONFIG_PCI_PNP is not set

View File

@ -54,6 +54,23 @@ If you want to check both consoles, use '-serial stdio'.
Multicore is also supported by QEMU via '-smp n' where n is the number of cores
to instantiate. Note, the maximum supported CPU number in QEMU is 255.
U-Boot uses 'distro_bootcmd' by default when booting on x86 QEMU. This tries to
load a boot script, kernel, and ramdisk from several different interfaces. For
the default boot order, see 'qemu-x86.h'. For more information, see
'README.distro'. Most Linux distros can be booted by writing a uboot script.
For example, Debian (stretch) can be booted by creating a script file named
'boot.txt' with the contents::
setenv bootargs root=/dev/sda1 ro
load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} /vmlinuz
load ${devtype} ${devnum}:${distro_bootpart} ${ramdisk_addr_r} /initrd.img
zboot ${kernel_addr_r} - ${ramdisk_addr_r} ${filesize}
Then compile and install it with::
$ apt install u-boot-tools && \
mkimage -T script -C none -n "Boot script" -d boot.txt /boot/boot.scr
The fw_cfg interface in QEMU also provides information about kernel data,
initrd, command-line arguments and more. U-Boot supports directly accessing
these informtion from fw_cfg interface, which saves the time of loading them

View File

@ -13,3 +13,4 @@ Intel
edison
galileo
minnowmax
slimbootloader

View File

@ -0,0 +1,174 @@
.. SPDX-License-Identifier: GPL-2.0+
.. sectionauthor:: Aiden Park <aiden.park@intel.com>
Slim Bootloader
===============
Introduction
------------
This target is to enable U-Boot_ as a payload of `Slim Bootloader`_ (a.k.a SBL)
boot firmware which currently supports QEMU, Apollolake, Whiskeylake,
Coffeelake-R platforms.
The `Slim Bootloader`_ is designed with multi-stages (Stage1A/B, Stage2, Payload)
architecture to cover from reset vector to OS booting and it consumes
`Intel FSP`_ for silicon initialization.
* Stage1A: Reset vector, CAR init with FSP-T
* Stage1B: Memory init with FSP-M, CAR teardown, Continue execution in memory
* Stage2 : Rest of Silicon init with FSP-S, Create HOB, Hand-off to Payload
* Payload: Payload init with HOB, Load OS from media, Booting OS
The Slim Bootloader stages (Stage1A/B, Stage2) focus on chipset, hardware and
platform specific initialization, and it provides useful information to a
payload in a HOB (Hand-Off Block) which has serial port, memory map, performance
data info and so on. This is Slim Bootloader architectural design to make a
payload light-weight, platform independent and more generic across different
boot solutions or payloads, and to minimize hardware re-initialization in a
payload.
Build Instruction for U-Boot as a Slim Bootloader payload
---------------------------------------------------------
Build U-Boot and obtain u-boot-dtb.bin::
$ make distclean
$ make slimbootloader_defconfig
$ make all
Prepare Slim Bootloader
-----------------------
1. Setup Build Environment for Slim Bootloader.
Refer to `Getting Started`_ page in `Slim Bootloader`_ document site.
2. Get source code. Let's simply clone the repo::
$ git clone https://github.com/slimbootloader/slimbootloader.git
3. Copy u-boot-dtb.bin to Slim Bootloader.
Slim Bootloader looks for a payload from the specific location.
Copy the build u-boot-dtb.bin to the expected location::
$ mkdir -p <Slim Bootloader Dir>/PayloadPkg/PayloadBins/
$ cp <U-Boot Dir>/u-boot-dtb.bin <Slim Bootloader Dir>/PayloadPkg/PayloadBins/u-boot-dtb.bin
Build Instruction for Slim Bootloader for QEMU target
-----------------------------------------------------
Slim Bootloader supports multiple payloads, and a board of Slim Bootloader
detects its target payload by PayloadId in board configuration.
The PayloadId can be any 4 Bytes value.
1. Update PayloadId. Let's use 'U-BT' as an example::
$ vi Platform/QemuBoardPkg/CfgData/CfgDataExt_Brd1.dlt
-GEN_CFG_DATA.PayloadId | 'AUTO'
+GEN_CFG_DATA.PayloadId | 'U-BT'
2. Update payload text base. PAYLOAD_EXE_BASE must be the same as U-Boot
CONFIG_SYS_TEXT_BASE in board/intel/slimbootloader/Kconfig.
PAYLOAD_LOAD_HIGH must be 0::
$ vi Platform/QemuBoardPkg/BoardConfig.py
+ self.PAYLOAD_LOAD_HIGH = 0
+ self.PAYLOAD_EXE_BASE = 0x00100000
3. Build QEMU target. Make sure u-boot-dtb.bin and U-BT PayloadId
in build command. The output is Outputs/qemu/SlimBootloader.bin::
$ python BuildLoader.py build qemu -p "OsLoader.efi:LLDR:Lz4;u-boot-dtb.bin:U-BT:Lzma"
4. Launch Slim Bootloader on QEMU.
You should reach at U-Boot serial console::
$ qemu-system-x86_64 -machine q35 -nographic -serial mon:stdio -pflash Outputs/qemu/SlimBootloader.bin
Build Instruction for Slim Bootloader for LeafHill (APL) target
--------------------------------------------------------------
LeafHill is using PCI UART2 device as a serial port.
For MEM32 serial port, CONFIG_SYS_NS16550_MEM32 needs to be enabled in U-Boot.
1. Enable CONFIG_SYS_NS16550_MEM32 in U-Boot::
$ vi include/configs/slimbootloader.h
+#define CONFIG_SYS_NS16550_MEM32
#ifdef CONFIG_SYS_NS16550_MEM3
2. Build U-Boot::
$ make disclean
$ make slimbootloader_defconfig
$ make all
3. Copy u-boot-dtb.bin to Slim Bootloader.
Slim Bootloader looks for a payload from the specific location.
Copy the build u-boot-dtb.bin to the expected location::
$ mkdir -p <Slim Bootloader Dir>/PayloadPkg/PayloadBins/
$ cp <U-Boot Dir>/u-boot-dtb.bin <Slim Bootloader Dir>/PayloadPkg/PayloadBins/u-boot-dtb.bin
4. Update PayloadId. Let's use 'U-BT' as an example::
$ vi Platform/ApollolakeBoardPkg/CfgData/CfgData_Int_LeafHill.dlt
-GEN_CFG_DATA.PayloadId | 'AUTO
+GEN_CFG_DATA.PayloadId | 'U-BT'
5. Update payload text base.
* PAYLOAD_EXE_BASE must be the same as U-Boot CONFIG_SYS_TEXT_BASE
in board/intel/slimbootloader/Kconfig.
* PAYLOAD_LOAD_HIGH must be 0::
$ vi Platform/ApollolakeBoardPkg/BoardConfig.py
+ self.PAYLOAD_LOAD_HIGH = 0
+ self.PAYLOAD_EXE_BASE = 0x00100000
6. Build APL target. Make sure u-boot-dtb.bin and U-BT PayloadId
in build command. The output is Outputs/apl/Stitch_Components.zip::
$ python BuildLoader.py build apl -p "OsLoader.efi:LLDR:Lz4;u-boot-dtb.bin:U-BT:Lzma"
7. Stitch IFWI.
Refer to Apollolake_ page in Slim Bootloader document site::
$ python Platform/ApollolakeBoardPkg/Script/StitchLoader.py -i <Existing IFWI> -s Outputs/apl/Stitch_Components.zip -o <Output IFWI>
8. Flash IFWI.
Use DediProg to flash IFWI. You should reach at U-Boot serial console.
Build Instruction to use ELF U-Boot
-----------------------------------
1. Enable CONFIG_OF_EMBED::
$ vi configs/slimbootloader_defconfig
+CONFIG_OF_EMBED=y
2. Build U-Boot::
$ make disclean
$ make slimbootloader_defconfig
$ make all
$ strip u-boot (removing symbol for reduced size)
3. Do same steps as above
* Copy u-boot (ELF) to PayloadBins directory
* Update PayloadId 'U-BT' as above.
* No need to set PAYLOAD_LOAD_HIGH and PAYLOAD_EXE_BASE.
* Build Slim Bootloader. Use u-boot instead of u-boot-dtb.bin::
$ python BuildLoader.py build <qemu or apl> -p "OsLoader.efi:LLDR:Lz4;u-boot:U-BT:Lzma"
.. _U-Boot: https://gitlab.denx.de/
.. _`Slim Bootloader`: https://github.com/slimbootloader/
.. _`Intel FSP`: https://github.com/IntelFsp/
.. _`Getting Started`: https://slimbootloader.github.io/getting-started/
.. _Apollolake: https://slimbootloader.github.io/supported-hardware/apollo-lake-crb.html#stitching

View File

@ -136,7 +136,6 @@ static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
bool linear_ok;
int attr;
break;
debug("Mode %x: ", mode);
memset(buffer, '\0', sizeof(struct vbe_mode_info));
regs->e.eax = VESA_GET_MODE_INFO;

View File

@ -14,6 +14,8 @@
#include <pci_ids.h>
#include <spi.h>
#include <asm/io.h>
#include <spi-mem.h>
#include <div64.h>
#include "ich.h"
@ -171,18 +173,6 @@ static int ich_init_controller(struct udevice *dev,
return 0;
}
static inline void spi_use_out(struct spi_trans *trans, unsigned bytes)
{
trans->out += bytes;
trans->bytesout -= bytes;
}
static inline void spi_use_in(struct spi_trans *trans, unsigned bytes)
{
trans->in += bytes;
trans->bytesin -= bytes;
}
static void spi_lock_down(struct ich_spi_platdata *plat, void *sbase)
{
if (plat->ich_version == ICHV_7) {
@ -213,47 +203,12 @@ static bool spi_lock_status(struct ich_spi_platdata *plat, void *sbase)
return lock != 0;
}
static void spi_setup_type(struct spi_trans *trans, int data_bytes)
{
trans->type = 0xFF;
/* Try to guess spi type from read/write sizes */
if (trans->bytesin == 0) {
if (trans->bytesout + data_bytes > 4)
/*
* If bytesin = 0 and bytesout > 4, we presume this is
* a write data operation, which is accompanied by an
* address.
*/
trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
else
trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
return;
}
if (trans->bytesout == 1) { /* and bytesin is > 0 */
trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
return;
}
if (trans->bytesout == 4) /* and bytesin is > 0 */
trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
/* Fast read command is called with 5 bytes instead of 4 */
if (trans->out[0] == SPI_OPCODE_FAST_READ && trans->bytesout == 5) {
trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
--trans->bytesout;
}
}
static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans,
bool lock)
{
uint16_t optypes;
uint8_t opmenu[ctlr->menubytes];
trans->opcode = trans->out[0];
spi_use_out(trans, 1);
if (!lock) {
/* The lock is off, so just use index 0. */
ich_writeb(ctlr, trans->opcode, ctlr->opmenu);
@ -285,12 +240,7 @@ static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans,
optypes = ich_readw(ctlr, ctlr->optype);
optype = (optypes >> (opcode_index * 2)) & 0x3;
if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
trans->bytesout >= 3) {
/* We guessed wrong earlier. Fix it up. */
trans->type = optype;
}
if (optype != trans->type) {
printf("ICH SPI: Transaction doesn't fit type %d\n",
optype);
@ -300,26 +250,6 @@ static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans,
}
}
static int spi_setup_offset(struct spi_trans *trans)
{
/* Separate the SPI address and data */
switch (trans->type) {
case SPI_OPCODE_TYPE_READ_NO_ADDRESS:
case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS:
return 0;
case SPI_OPCODE_TYPE_READ_WITH_ADDRESS:
case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS:
trans->offset = ((uint32_t)trans->out[0] << 16) |
((uint32_t)trans->out[1] << 8) |
((uint32_t)trans->out[2] << 0);
spi_use_out(trans, 3);
return 1;
default:
printf("Unrecognized SPI transaction type %#x\n", trans->type);
return -EPROTO;
}
}
/*
* Wait for up to 6s til status register bit(s) turn 1 (in case wait_til_set
* below is true) or 0. In case the wait was for the bit(s) to set - write
@ -350,7 +280,7 @@ static int ich_status_poll(struct ich_spi_priv *ctlr, u16 bitmask,
return -ETIMEDOUT;
}
void ich_spi_config_opcode(struct udevice *dev)
static void ich_spi_config_opcode(struct udevice *dev)
{
struct ich_spi_priv *ctlr = dev_get_priv(dev);
@ -365,90 +295,38 @@ void ich_spi_config_opcode(struct udevice *dev)
ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32));
}
static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
{
struct udevice *bus = dev_get_parent(dev);
struct udevice *bus = dev_get_parent(slave->dev);
struct ich_spi_platdata *plat = dev_get_platdata(bus);
struct ich_spi_priv *ctlr = dev_get_priv(bus);
uint16_t control;
int16_t opcode_index;
int with_address;
int status;
int bytes = bitlen / 8;
struct spi_trans *trans = &ctlr->trans;
unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END);
int using_cmd = 0;
bool lock = spi_lock_status(plat, ctlr->base);
int ret;
int ret = 0;
/* We don't support writing partial bytes */
if (bitlen % 8) {
debug("ICH SPI: Accessing partial bytes not supported\n");
return -EPROTONOSUPPORT;
}
trans->in = NULL;
trans->out = NULL;
trans->type = 0xFF;
/* An empty end transaction can be ignored */
if (type == SPI_XFER_END && !dout && !din)
return 0;
if (type & SPI_XFER_BEGIN)
memset(trans, '\0', sizeof(*trans));
/* Dp we need to come back later to finish it? */
if (dout && type == SPI_XFER_BEGIN) {
if (bytes > ICH_MAX_CMD_LEN) {
debug("ICH SPI: Command length limit exceeded\n");
return -ENOSPC;
if (op->data.nbytes) {
if (op->data.dir == SPI_MEM_DATA_IN) {
trans->in = op->data.buf.in;
trans->bytesin = op->data.nbytes;
} else {
trans->out = op->data.buf.out;
trans->bytesout = op->data.nbytes;
}
memcpy(trans->cmd, dout, bytes);
trans->cmd_len = bytes;
debug_trace("ICH SPI: Saved %d bytes\n", bytes);
}
if (trans->opcode != op->cmd.opcode)
trans->opcode = op->cmd.opcode;
if (lock && trans->opcode == SPI_OPCODE_WRDIS)
return 0;
}
/*
* We process a 'middle' spi_xfer() call, which has no
* SPI_XFER_BEGIN/END, as an independent transaction as if it had
* an end. We therefore repeat the command. This is because ICH
* seems to have no support for this, or because interest (in digging
* out the details and creating a special case in the code) is low.
*/
if (trans->cmd_len) {
trans->out = trans->cmd;
trans->bytesout = trans->cmd_len;
using_cmd = 1;
debug_trace("ICH SPI: Using %d bytes\n", trans->cmd_len);
} else {
trans->out = dout;
trans->bytesout = dout ? bytes : 0;
}
trans->in = din;
trans->bytesin = din ? bytes : 0;
/* There has to always at least be an opcode */
if (!trans->bytesout) {
debug("ICH SPI: No opcode for transfer\n");
return -EPROTO;
}
ret = ich_status_poll(ctlr, SPIS_SCIP, 0);
if (ret < 0)
return ret;
if (plat->ich_version == ICHV_7)
ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
else
ich_writeb(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
spi_setup_type(trans, using_cmd ? bytes : 0);
opcode_index = spi_setup_opcode(ctlr, trans, lock);
if (opcode_index < 0)
return -EINVAL;
with_address = spi_setup_offset(trans);
if (with_address < 0)
return -EINVAL;
if (trans->opcode == SPI_OPCODE_WREN) {
/*
@ -461,6 +339,40 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
return 0;
}
ret = ich_status_poll(ctlr, SPIS_SCIP, 0);
if (ret < 0)
return ret;
if (plat->ich_version == ICHV_7)
ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
else
ich_writeb(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
/* Try to guess spi transaction type */
if (op->data.dir == SPI_MEM_DATA_OUT) {
if (op->addr.nbytes)
trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
else
trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
} else {
if (op->addr.nbytes)
trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
else
trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
}
/* Special erase case handling */
if (op->addr.nbytes && !op->data.buswidth)
trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
opcode_index = spi_setup_opcode(ctlr, trans, lock);
if (opcode_index < 0)
return -EINVAL;
if (op->addr.nbytes) {
trans->offset = op->addr.val;
with_address = 1;
}
if (ctlr->speed && ctlr->max_speed >= 33000000) {
int byte;
@ -472,13 +384,6 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
ich_writeb(ctlr, byte, ctlr->speed);
}
/* See if we have used up the command data */
if (using_cmd && dout && bytes) {
trans->out = dout;
trans->bytesout = bytes;
debug_trace("ICH SPI: Moving to data, %d bytes\n", bytes);
}
/* Preset control fields */
control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
@ -513,22 +418,6 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
return 0;
}
/*
* Check if this is a write command atempting to transfer more bytes
* than the controller can handle. Iterations for writes are not
* supported here because each SPI write command needs to be preceded
* and followed by other SPI commands, and this sequence is controlled
* by the SPI chip driver.
*/
if (trans->bytesout > ctlr->databytes) {
debug("ICH SPI: Too much to write. This should be prevented by the driver's max_write_size?\n");
return -EPROTO;
}
/*
* Read or write up to databytes bytes at a time until everything has
* been sent.
*/
while (trans->bytesout || trans->bytesin) {
uint32_t data_length;
@ -543,9 +432,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Program data into FDATA0 to N */
if (trans->bytesout) {
write_reg(ctlr, trans->out, ctlr->data, data_length);
spi_use_out(trans, data_length);
if (with_address)
trans->offset += data_length;
trans->bytesout -= data_length;
}
/* Add proper control fields' values */
@ -568,9 +455,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (trans->bytesin) {
read_reg(ctlr, ctlr->data, trans->in, data_length);
spi_use_in(trans, data_length);
if (with_address)
trans->offset += data_length;
trans->bytesin -= data_length;
}
}
@ -581,6 +466,40 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
return 0;
}
static int ich_spi_adjust_size(struct spi_slave *slave, struct spi_mem_op *op)
{
unsigned int page_offset;
int addr = op->addr.val;
unsigned int byte_count = op->data.nbytes;
if (hweight32(ICH_BOUNDARY) == 1) {
page_offset = addr & (ICH_BOUNDARY - 1);
} else {
u64 aux = addr;
page_offset = do_div(aux, ICH_BOUNDARY);
}
if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size) {
op->data.nbytes = min(ICH_BOUNDARY - page_offset,
slave->max_read_size);
} else if (slave->max_write_size) {
op->data.nbytes = min(ICH_BOUNDARY - page_offset,
slave->max_write_size);
}
op->data.nbytes = min(op->data.nbytes, byte_count);
return 0;
}
static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
printf("ICH SPI: Only supports memory operations\n");
return -1;
}
static int ich_spi_probe(struct udevice *dev)
{
struct ich_spi_platdata *plat = dev_get_platdata(dev);
@ -686,10 +605,17 @@ static int ich_spi_ofdata_to_platdata(struct udevice *dev)
return ret;
}
static const struct spi_controller_mem_ops ich_controller_mem_ops = {
.adjust_op_size = ich_spi_adjust_size,
.supports_op = NULL,
.exec_op = ich_spi_exec_op,
};
static const struct dm_spi_ops ich_spi_ops = {
.xfer = ich_spi_xfer,
.set_speed = ich_spi_set_speed,
.set_mode = ich_spi_set_mode,
.mem_ops = &ich_controller_mem_ops,
/*
* cs_info is not needed, since we require all chip selects to be
* in the device tree explicitly

View File

@ -100,13 +100,8 @@ enum {
HSFC_FSMIE = 0x8000
};
enum {
ICH_MAX_CMD_LEN = 5,
};
struct spi_trans {
uint8_t cmd[ICH_MAX_CMD_LEN];
int cmd_len;
uint8_t cmd;
const uint8_t *out;
uint32_t bytesout;
uint8_t *in;
@ -166,6 +161,8 @@ struct spi_trans {
#define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \
(SPI_OPMENU_1 << 8) | (SPI_OPMENU_0 << 0))
#define ICH_BOUNDARY 0x1000
enum ich_version {
ICHV_7,
ICHV_9,

View File

@ -10,8 +10,23 @@
#ifndef __CONFIG_H
#define __CONFIG_H
#include <linux/sizes.h>
#define BOOT_TARGET_DEVICES(func) \
func(USB, usb, 0) \
func(SCSI, scsi, 0) \
func(VIRTIO, virtio, 0) \
func(IDE, ide, 0) \
func(DHCP, dhcp, na)
#include <config_distro_bootcmd.h>
#include <configs/x86-common.h>
#undef CONFIG_ENV_SIZE
#define CONFIG_ENV_SIZE SZ_256K
#define CONFIG_PREBOOT "pci enum"
#define CONFIG_SYS_MONITOR_LEN (1 << 20)
#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial,i8042-kbd\0" \

View File

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
*/
#ifndef __SLIMBOOTLOADER_CONFIG_H__
#define __SLIMBOOTLOADER_CONFIG_H__
#include <configs/x86-common.h>
/*
* By default, CONFIG_SYS_NS16550_PORT_MAPPED is enabled for port io serial.
* To use mmio base serial, enable CONFIG_SYS_NS16550_MEM32 and disable
* CONFIG_SYS_NS16550_PORT_MAPPED until ns16550 driver supports serial port
* configuration in run-time.
*
* #define CONFIG_SYS_NS16550_MEM32
* #undef CONFIG_SYS_NS16550_PORT_MAPPED
*/
#ifdef CONFIG_SYS_NS16550_MEM32
#undef CONFIG_SYS_NS16550_PORT_MAPPED
#endif
#define CONFIG_STD_DEVICES_SETTINGS \
"stdin=serial,i8042-kbd,usbkbd\0" \
"stdout=serial\0" \
"stderr=serial\0"
/*
* Override CONFIG_EXTRA_ENV_SETTINGS in x86-common.h
*/
#undef CONFIG_EXTRA_ENV_SETTINGS
#define CONFIG_EXTRA_ENV_SETTINGS \
CONFIG_STD_DEVICES_SETTINGS \
"netdev=eth0\0" \
"consoledev=ttyS0\0" \
"ramdiskaddr=0x4000000\0" \
"ramdiskfile=initrd\0" \
"bootdev=usb\0" \
"bootdevnum=0\0" \
"bootdevpart=0\0" \
"bootfsload=fatload\0" \
"bootusb=setenv bootdev usb; boot\0" \
"bootscsi=setenv bootdev scsi; boot\0" \
"bootmmc=setenv bootdev mmc; boot\0" \
"bootargs=console=ttyS0,115200 console=tty0\0"
/*
* Override CONFIG_BOOTCOMMAND in x86-common.h
*/
#undef CONFIG_BOOTCOMMAND
#define CONFIG_BOOTCOMMAND \
"if test ${bootdev} = \"usb\"; then ${bootdev} start; fi; " \
"if test ${bootdev} = \"scsi\"; then ${bootdev} scan; fi; " \
"${bootdev} info; " \
"${bootfsload} ${bootdev} ${bootdevnum}:${bootdevpart} " \
"${loadaddr} ${bootfile}; " \
"${bootfsload} ${bootdev} ${bootdevnum}:${bootdevpart} " \
"${ramdiskaddr} ${ramdiskfile}; " \
"zboot ${loadaddr} 0 ${ramdiskaddr} ${filesize}"
#endif /* __SLIMBOOTLOADER_CONFIG_H__ */

View File

@ -105,30 +105,37 @@
#define CONFIG_OTHBOOTARGS "othbootargs=acpi=off\0"
#endif
#ifndef CONFIG_DISTRO_DEFAULTS
#define BOOTENV
#endif
#define CONFIG_EXTRA_ENV_SETTINGS \
CONFIG_STD_DEVICES_SETTINGS \
"pciconfighost=1\0" \
"netdev=eth0\0" \
"consoledev=ttyS0\0" \
CONFIG_OTHBOOTARGS \
"ramdiskaddr=0x4000000\0" \
"ramdiskfile=initramfs.gz\0"
"scriptaddr=0x7000000\0" \
"kernel_addr_r=0x1000000\0" \
"ramdisk_addr_r=0x4000000\0" \
"ramdiskfile=initramfs.gz\0" \
BOOTENV
#define CONFIG_RAMBOOTCOMMAND \
"setenv bootargs root=/dev/ram rw " \
"ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname:$netdev:off " \
"console=$consoledev,$baudrate $othbootargs;" \
"tftpboot $loadaddr $bootfile;" \
"tftpboot $ramdiskaddr $ramdiskfile;" \
"zboot $loadaddr 0 $ramdiskaddr $filesize"
"tftpboot $kernel_addr_r $bootfile;" \
"tftpboot $ramdisk_addr_r $ramdiskfile;" \
"zboot $kernel_addr_r 0 $ramdisk_addr_r $filesize"
#define CONFIG_NFSBOOTCOMMAND \
"setenv bootargs root=/dev/nfs rw " \
"nfsroot=$serverip:$rootpath " \
"ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname:$netdev:off " \
"console=$consoledev,$baudrate $othbootargs;" \
"tftpboot $loadaddr $bootfile;" \
"zboot $loadaddr"
"tftpboot $kernel_addr_r $bootfile;" \
"zboot $kernel_addr_r"
#endif /* __CONFIG_H */

View File

@ -395,11 +395,22 @@ $(obj)/%_efi.so: $(obj)/%.o $(obj)/efi_crt0.o $(obj)/efi_reloc.o $(obj)/efi_free
# ACPI
# ---------------------------------------------------------------------------
#
# This first sends the file (typically dsdt.asl) through the preprocessor
# resolve includes and any CONFIG options used. This produces dsdt.asl.tmp
# which is pure ASL code. The Intel ASL (ACPI (Advanced Configuration and Power
# Interface) Source Language compiler (iasl) then converts this ASL code into a
# C file containing the hex data to build into U-Boot. This file is called
# dsdt.hex (despite us setting the prefix to .../dsdt.asl.tmp) so must be
# renamed to dsdt.c for consumption by the build system.
ASL_TMP = $(patsubst %.c,%.asl.tmp,$@)
quiet_cmd_acpi_c_asl= ASL $<
cmd_acpi_c_asl= \
$(CPP) -x assembler-with-cpp -D__ASSEMBLY__ -P $(UBOOTINCLUDE) -o $<.tmp $<; \
iasl -p $< -tc $<.tmp $(if $(KBUILD_VERBOSE:1=), >/dev/null) && \
mv $(patsubst %.asl,%.hex,$<) $@
$(CPP) -x assembler-with-cpp -D__ASSEMBLY__ -P $(UBOOTINCLUDE) \
-o $(ASL_TMP) $< && \
iasl -p $@ -tc $(ASL_TMP) $(if $(KBUILD_VERBOSE:1=), >/dev/null) && \
mv $(patsubst %.c,%.hex,$@) $@
$(obj)/dsdt.c: $(src)/dsdt.asl
$(call cmd,acpi_c_asl)