33 changes: 33 additions & 0 deletions src/drivers/intel/fsp2_0/debug.c
Expand Up @@ -11,6 +11,27 @@ asmlinkage size_t fsp_write_line(uint8_t *buffer, size_t number_of_bytes)
return number_of_bytes;
}

enum fsp_call_phase {
BEFORE_FSP_CALL,
AFTER_FSP_CALL,
};

static void fsp_gpio_config_check(enum fsp_call_phase phase, const char *call_str)
{
switch (phase) {
case BEFORE_FSP_CALL:
printk(BIOS_SPEW, "Snapshot all GPIOs before %s.\n", call_str);
gpio_snapshot();
break;
case AFTER_FSP_CALL:
printk(BIOS_SPEW, "Verify GPIO snapshot after %s...", call_str);
printk(BIOS_SPEW, "%zd changes detected!\n", gpio_verify_snapshot());
break;
default:
break;
}
}

/*-----------
* MemoryInit
*-----------
Expand Down Expand Up @@ -62,6 +83,9 @@ void fsp_debug_before_silicon_init(fsp_silicon_init_fn silicon_init,
const FSPS_UPD *fsps_old_upd,
const FSPS_UPD *fsps_new_upd)
{
if (CONFIG(CHECK_GPIO_CONFIG_CHANGES))
fsp_gpio_config_check(BEFORE_FSP_CALL, "FSP Silicon Init");

display_mtrrs();

/* Display the UPD values */
Expand All @@ -77,6 +101,9 @@ void fsp_debug_before_silicon_init(fsp_silicon_init_fn silicon_init,

void fsp_debug_after_silicon_init(uint32_t status)
{
if (CONFIG(CHECK_GPIO_CONFIG_CHANGES))
fsp_gpio_config_check(AFTER_FSP_CALL, "FSP Silicon Init");

if (CONFIG(DISPLAY_FSP_CALLS_AND_STATUS))
printk(BIOS_SPEW, "FspSiliconInit returned 0x%08x\n", status);

Expand All @@ -94,6 +121,9 @@ void fsp_debug_after_silicon_init(uint32_t status)
void fsp_before_debug_notify(fsp_notify_fn notify,
const struct fsp_notify_params *notify_params)
{
if (CONFIG(CHECK_GPIO_CONFIG_CHANGES))
fsp_gpio_config_check(BEFORE_FSP_CALL, "FSP Notify");

/* Display the call to FspNotify */
if (!CONFIG(DISPLAY_FSP_CALLS_AND_STATUS))
return;
Expand All @@ -105,6 +135,9 @@ void fsp_before_debug_notify(fsp_notify_fn notify,

void fsp_debug_after_notify(uint32_t status)
{
if (CONFIG(CHECK_GPIO_CONFIG_CHANGES))
fsp_gpio_config_check(AFTER_FSP_CALL, "FSP Notify");

if (CONFIG(DISPLAY_FSP_CALLS_AND_STATUS))
printk(BIOS_SPEW, "FspNotify returned 0x%08x\n", status);

Expand Down
5 changes: 5 additions & 0 deletions src/drivers/intel/fsp2_0/include/fsp/debug.h
Expand Up @@ -57,4 +57,9 @@ void fsp_print_guid_extension_hob(const struct hob_header *hob);
*/
asmlinkage size_t fsp_write_line(uint8_t *buffer, size_t number_of_bytes);

/* Callback to snapshot all GPIO configurations. */
void gpio_snapshot(void);
/* Callback to verify that current GPIO configuration matches the saved snapshot */
size_t gpio_verify_snapshot(void);

#endif /* _FSP2_0_DEBUG_H_ */
13 changes: 5 additions & 8 deletions src/drivers/intel/fsp2_0/include/fsp/util.h
Expand Up @@ -4,6 +4,7 @@
#define _FSP2_0_UTIL_H_

#include <boot/coreboot_tables.h>
#include <cbfs.h>
#include <commonlib/region.h>
#include <arch/cpu.h>
#include <fsp/api.h>
Expand Down Expand Up @@ -103,19 +104,15 @@ void lb_string_platform_blob_version(struct lb_header *header);
void report_fspt_output(void);
void soc_validate_fsp_version(const struct fsp_header *hdr);

/* Fill in header and validate sanity of component within region device. */
enum cb_err fsp_validate_component(struct fsp_header *hdr,
const struct region_device *rdev);
/* Fill in header and validate a loaded FSP component. */
enum cb_err fsp_validate_component(struct fsp_header *hdr, void *fsp_blob, size_t size);

struct fsp_load_descriptor {
/* fsp_prog object will have region_device initialized to final
* load location in memory. */
struct prog fsp_prog;
/* Fill in destination location given final load size. Return 0 on
* success, < 0 on error. */
int (*get_destination)(const struct fsp_load_descriptor *fspld,
void **dest, size_t final_load_size,
const struct region_device *source);
/* CBFS allocator to place loaded FSP. NULL to map flash directly. */
cbfs_allocator_t alloc;
/* Optional argument to be utilized by get_destination() callback. */
void *arg;
};
Expand Down
41 changes: 14 additions & 27 deletions src/drivers/intel/fsp2_0/memory_init.c
Expand Up @@ -339,40 +339,20 @@ static void do_fsp_memory_init(const struct fspm_context *context, bool s3wake)
fsp_debug_after_memory_init(status);
}

static int fspm_get_dest(const struct fsp_load_descriptor *fspld, void **dest,
size_t size, const struct region_device *source)
static void *fspm_allocator(void *arg, size_t size, const union cbfs_mdata *unused)
{
const struct fsp_load_descriptor *fspld = arg;
struct fspm_context *context = fspld->arg;
struct fsp_header *hdr = &context->header;
struct memranges *memmap = &context->memmap;
uintptr_t fspm_begin;
uintptr_t fspm_end;

if (CONFIG(FSP_M_XIP)) {
if (fsp_validate_component(hdr, source) != CB_SUCCESS)
return -1;

*dest = rdev_mmap_full(source);
if ((uintptr_t)*dest != hdr->image_base) {
printk(BIOS_CRIT, "FSPM XIP base does not match: %p vs %p\n",
(void *)(uintptr_t)hdr->image_base, *dest);
return -1;
}
/* Since the component is XIP it's already in the address space.
Thus, there's no need to rdev_munmap(). */
return 0;
}

/* Non XIP FSP-M uses FSP-M address */
fspm_begin = (uintptr_t)CONFIG_FSP_M_ADDR;
fspm_end = fspm_begin + size;
uintptr_t fspm_begin = (uintptr_t)CONFIG_FSP_M_ADDR;
uintptr_t fspm_end = fspm_begin + size;

if (check_region_overlap(memmap, "FSPM", fspm_begin, fspm_end) != CB_SUCCESS)
return -1;

*dest = (void *)fspm_begin;
return NULL;

return 0;
return (void *)fspm_begin;
}

void fsp_memory_init(bool s3wake)
Expand All @@ -381,12 +361,15 @@ void fsp_memory_init(bool s3wake)
struct fspm_context context;
struct fsp_load_descriptor fspld = {
.fsp_prog = PROG_INIT(PROG_REFCODE, CONFIG_FSP_M_CBFS),
.get_destination = fspm_get_dest,
.arg = &context,
};
struct fsp_header *hdr = &context.header;
struct memranges *memmap = &context.memmap;

/* For FSP-M XIP we leave alloc NULL to get a direct mapping to flash. */
if (!CONFIG(FSP_M_XIP))
fspld.alloc = fspm_allocator;

elog_boot_notify(s3wake);

/* Build up memory map of romstage address space including CAR. */
Expand All @@ -399,6 +382,10 @@ void fsp_memory_init(bool s3wake)
if (fsp_load_component(&fspld, hdr) != CB_SUCCESS)
die("FSPM not available or failed to load!\n");

if (CONFIG(FSP_M_XIP) && (uintptr_t)prog_start(&fspld.fsp_prog) != hdr->image_base)
die("FSPM XIP base does not match: %p vs %p\n",
(void *)(uintptr_t)hdr->image_base, prog_start(&fspld.fsp_prog));

timestamp_add_now(TS_BEFORE_INITRAM);

do_fsp_memory_init(&context, s3wake);
Expand Down
2 changes: 1 addition & 1 deletion src/drivers/intel/fsp2_0/mma_core.c
Expand Up @@ -23,7 +23,7 @@ void setup_mma(FSP_M_CONFIG *memory_cfg)
{
struct mma_config_param mma_cfg;

if (mma_locate_param(&mma_cfg)) {
if (mma_map_param(&mma_cfg)) {
printk(BIOS_DEBUG, "MMA: set up failed\n");
return;
}
Expand Down
17 changes: 4 additions & 13 deletions src/drivers/intel/fsp2_0/silicon_init.c
Expand Up @@ -184,22 +184,16 @@ static void do_silicon_init(struct fsp_header *hdr)
post_code(POST_FSP_MULTI_PHASE_SI_INIT_EXIT);
}

static int fsps_get_dest(const struct fsp_load_descriptor *fspld, void **dest,
size_t size, const struct region_device *source)
static void *fsps_allocator(void *arg_unused, size_t size, const union cbfs_mdata *mdata_unused)
{
*dest = cbmem_add(CBMEM_ID_REFCODE, size);

if (*dest == NULL)
return -1;

return 0;
return cbmem_add(CBMEM_ID_REFCODE, size);
}

void fsps_load(void)
{
struct fsp_load_descriptor fspld = {
.fsp_prog = PROG_INIT(PROG_REFCODE, CONFIG_FSP_S_CBFS),
.get_destination = fsps_get_dest,
.alloc = fsps_allocator,
};
struct prog *fsps = &fspld.fsp_prog;
static int load_done;
Expand All @@ -210,10 +204,7 @@ void fsps_load(void)
if (resume_from_stage_cache()) {
printk(BIOS_DEBUG, "Loading FSPS from stage_cache\n");
stage_cache_load_stage(STAGE_REFCODE, fsps);

struct region_device prog_rdev;
prog_chain_rdev(fsps, &prog_rdev);
if (fsp_validate_component(&fsps_hdr, &prog_rdev) != CB_SUCCESS)
if (fsp_validate_component(&fsps_hdr, prog_start(fsps), prog_size(fsps)))
die("On resume fsps header is invalid\n");
load_done = 1;
return;
Expand Down
15 changes: 8 additions & 7 deletions src/drivers/intel/fsp2_0/temp_ram_exit.c
Expand Up @@ -12,18 +12,17 @@ void fsp_temp_ram_exit(void)
struct fsp_header hdr;
uint32_t status;
temp_ram_exit_fn temp_ram_exit;
struct cbfsf file_desc;
struct region_device file_data;
void *mapping;
size_t size;
const char *name = CONFIG_FSP_M_CBFS;

if (cbfs_boot_locate(&file_desc, name, NULL)) {
printk(BIOS_CRIT, "Could not locate %s in CBFS\n", name);
mapping = cbfs_map(name, &size);
if (!mapping) {
printk(BIOS_CRIT, "Could not map %s from CBFS\n", name);
die("FSPM not available for CAR Exit!\n");
}

cbfs_file_data(&file_data, &file_desc);

if (fsp_validate_component(&hdr, &file_data) != CB_SUCCESS)
if (fsp_validate_component(&hdr, mapping, size) != CB_SUCCESS)
die("Invalid FSPM header!\n");

temp_ram_exit = (void *)(hdr.image_base + hdr.temp_ram_exit_entry);
Expand All @@ -34,6 +33,8 @@ void fsp_temp_ram_exit(void)
printk(BIOS_CRIT, "TempRamExit returned 0x%08x\n", status);
die("TempRamExit returned an error!\n");
}

cbfs_unmap(mapping);
}

void late_car_teardown(void)
Expand Down
76 changes: 13 additions & 63 deletions src/drivers/intel/fsp2_0/util.c
Expand Up @@ -55,32 +55,25 @@ enum cb_err fsp_identify(struct fsp_header *hdr, const void *fsp_blob)
return CB_SUCCESS;
}

enum cb_err fsp_validate_component(struct fsp_header *hdr,
const struct region_device *rdev)
enum cb_err fsp_validate_component(struct fsp_header *hdr, void *fsp_file, size_t file_size)
{
void *membase;
void *raw_hdr = fsp_file + FSP_HDR_OFFSET;

/* Map just enough of the file to be able to parse the header. */
membase = rdev_mmap(rdev, FSP_HDR_OFFSET, FSP_HDR_LEN);

if (membase == NULL) {
printk(BIOS_CRIT, "Could not mmap() FSP header.\n");
if (file_size < FSP_HDR_OFFSET + FSP_HDR_LEN) {
printk(BIOS_CRIT, "FSP blob too small.\n");
return CB_ERR;
}

if (fsp_identify(hdr, membase) != CB_SUCCESS) {
rdev_munmap(rdev, membase);
if (fsp_identify(hdr, raw_hdr) != CB_SUCCESS) {
printk(BIOS_CRIT, "No valid FSP header\n");
return CB_ERR;
}

rdev_munmap(rdev, membase);

if (CONFIG(DISPLAY_FSP_HEADER))
fsp_print_header_info(hdr);

/* Check if size specified in the header matches the cbfs file size */
if (region_device_sz(rdev) < hdr->image_size) {
if (file_size < hdr->image_size) {
printk(BIOS_CRIT, "Component size bigger than cbfs file.\n");
return CB_ERR;
}
Expand Down Expand Up @@ -139,70 +132,27 @@ static inline bool fspm_xip(void)
return false;
}

static void *fsp_get_dest_and_load(struct fsp_load_descriptor *fspld, size_t size,
const struct region_device *source_rdev,
uint32_t compression_algo)
{
void *dest;

if (fspld->get_destination(fspld, &dest, size, source_rdev) < 0) {
printk(BIOS_ERR, "FSP Destination not obtained.\n");
return NULL;
}

/* Don't load when executing in place. */
if (fspm_xip())
return dest;

if (cbfs_load_and_decompress(source_rdev, 0, region_device_sz(source_rdev),
dest, size, compression_algo) != size) {
printk(BIOS_ERR, "Failed to load FSP component.\n");
return NULL;
}

/* Don't allow FSP-M relocation. */
if (fspm_env())
return dest;

if (fsp_component_relocate((uintptr_t)dest, dest, size) < 0) {
printk(BIOS_ERR, "Unable to relocate FSP component!\n");
return NULL;
}

return dest;
}

/* Load the FSP component described by fsp_load_descriptor from cbfs. The FSP
* header object will be validated and filled in on successful load. */
enum cb_err fsp_load_component(struct fsp_load_descriptor *fspld, struct fsp_header *hdr)
{
struct cbfsf file_desc;
uint32_t compression_algo;
size_t output_size;
void *dest;
struct region_device source_rdev, prog_rdev;
struct prog *fsp_prog = &fspld->fsp_prog;

if (fspld->get_destination == NULL)
dest = cbfs_alloc(prog_name(fsp_prog), fspld->alloc, fspld, &output_size);
if (!dest)
return CB_ERR;

if (cbfs_boot_locate(&file_desc, prog_name(fsp_prog), &fsp_prog->cbfs_type) < 0)
return CB_ERR;

if (cbfsf_decompression_info(&file_desc, &compression_algo, &output_size) < 0)
return CB_ERR;

cbfs_file_data(&source_rdev, &file_desc);

dest = fsp_get_dest_and_load(fspld, output_size, &source_rdev, compression_algo);

if (dest == NULL)
/* Don't allow FSP-M relocation. */
if (!fspm_env() && fsp_component_relocate((uintptr_t)dest, dest, output_size) < 0) {
printk(BIOS_ERR, "Unable to relocate FSP component!\n");
return CB_ERR;
}

prog_set_area(fsp_prog, dest, output_size);

prog_chain_rdev(fsp_prog, &prog_rdev);
if (fsp_validate_component(hdr, &prog_rdev) != CB_SUCCESS) {
if (fsp_validate_component(hdr, dest, output_size) != CB_SUCCESS) {
printk(BIOS_ERR, "Invalid FSP header after load!\n");
return CB_ERR;
}
Expand Down
9 changes: 3 additions & 6 deletions src/drivers/intel/gma/opregion.c
Expand Up @@ -128,16 +128,14 @@ static enum cb_err locate_vbt_vbios(const u8 *vbios, struct region_device *rdev)
size_t offset;

// FIXME: caller should supply a region_device instead of vbios pointer
if (rdev_chain(&rd, &addrspace_32bit.rdev, (uintptr_t)vbios,
sizeof(*oprom)))
if (rdev_chain_mem(&rd, vbios, sizeof(*oprom)))
return CB_ERR;

if (rdev_readat(&rd, &opromsize, offsetof(optionrom_header_t, size),
sizeof(opromsize)) != sizeof(opromsize) || !opromsize)
return CB_ERR;

if (rdev_chain(&rd, &addrspace_32bit.rdev, (uintptr_t)vbios,
opromsize * 512))
if (rdev_chain_mem(&rd, vbios, opromsize * 512))
return CB_ERR;

oprom = rdev_mmap(&rd, 0, sizeof(*oprom));
Expand Down Expand Up @@ -200,8 +198,7 @@ static enum cb_err locate_vbt_cbfs(struct region_device *rdev)
if (vbt == NULL)
return CB_ERR;

if (rdev_chain(rdev, &addrspace_32bit.rdev, (uintptr_t)vbt,
vbt_data_size))
if (rdev_chain_mem(rdev, vbt, vbt_data_size))
return CB_ERR;

printk(BIOS_INFO, "GMA: Found VBT in CBFS\n");
Expand Down
11 changes: 11 additions & 0 deletions src/drivers/intel/mipi_camera/camera.c
Expand Up @@ -433,6 +433,9 @@ static void camera_fill_sensor(const struct device *dev)
acpi_dp_add_array(dsd, lens_focus);
}

if (config->low_power_probe)
acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);

acpi_dp_add_child(dsd, "port0", prt0);
acpi_dp_write(dsd);

Expand Down Expand Up @@ -480,6 +483,10 @@ static void camera_fill_nvm(const struct device *dev)
acpi_dp_add_integer(dsd, "address-width", config->nvm_width);

acpi_dp_add_string(dsd, "compatible", config->nvm_compat);

if (config->low_power_probe)
acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);

acpi_dp_write(dsd);
}

Expand All @@ -493,6 +500,10 @@ static void camera_fill_vcm(const struct device *dev)

dsd = acpi_dp_new_table("_DSD");
acpi_dp_add_string(dsd, "compatible", config->vcm_compat);

if (config->low_power_probe)
acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);

acpi_dp_write(dsd);
}

Expand Down
2 changes: 2 additions & 0 deletions src/drivers/intel/mipi_camera/chip.h
Expand Up @@ -247,6 +247,8 @@ struct drivers_intel_mipi_camera_config {
const char *vcm_compat;
/* Does the device have a power resource entries */
bool has_power_resource;
/* Perform low power probe */
bool low_power_probe;
};

#endif
12 changes: 8 additions & 4 deletions src/drivers/ipmi/ipmi_kcs.c
Expand Up @@ -29,7 +29,8 @@
static unsigned char ipmi_kcs_status(int port)
{
unsigned char status = inb(IPMI_STAT(port));
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, status);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, status);
return status;
}

Expand Down Expand Up @@ -57,7 +58,8 @@ static int ipmi_kcs_send_data_byte(int port, const unsigned char byte)
{
unsigned char status;

printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);

outb(byte, IPMI_DATA(port));

Expand All @@ -80,7 +82,8 @@ static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)
{
unsigned char status;

printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);

if (wait_ibf_timeout(port))
return 1;
Expand All @@ -101,7 +104,8 @@ static int ipmi_kcs_send_last_data_byte(int port, const unsigned char byte)

static int ipmi_kcs_send_cmd_byte(int port, const unsigned char byte)
{
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);
if (CONFIG(DEBUG_IPMI))
printk(BIOS_SPEW, "%s: 0x%02x\n", __func__, byte);

if (wait_ibf_timeout(port))
return 1;
Expand Down
4 changes: 2 additions & 2 deletions src/drivers/lenovo/hybrid_graphics/hybrid_graphics.c
Expand Up @@ -14,7 +14,7 @@
static void lenovo_hybrid_graphics_enable(struct device *dev)
{
const struct drivers_lenovo_hybrid_graphics_config *config;
enum hybrid_graphics_req mode = HYBRID_GRAPHICS_DEFAULT_GPU;
enum hybrid_graphics_req mode;

/* Don't confuse anyone else and disable the fake device */
dev->enabled = 0;
Expand All @@ -25,7 +25,7 @@ static void lenovo_hybrid_graphics_enable(struct device *dev)
return;
}

get_option(&mode, "hybrid_graphics_mode");
mode = get_int_option("hybrid_graphics_mode", HYBRID_GRAPHICS_DEFAULT_GPU);

if (mode == HYBRID_GRAPHICS_DISCRETE) {
printk(BIOS_DEBUG, "Hybrid graphics:"
Expand Down
4 changes: 2 additions & 2 deletions src/drivers/lenovo/hybrid_graphics/romstage.c
Expand Up @@ -18,7 +18,7 @@ void early_hybrid_graphics(bool *enable_igd, bool *enable_peg)
{
const struct drivers_lenovo_hybrid_graphics_config *config;
const struct device *dev;
enum hybrid_graphics_req mode = HYBRID_GRAPHICS_DEFAULT_GPU;
enum hybrid_graphics_req mode;

/* TODO: Use generic device instead of dummy PNP device */
dev = dev_find_slot_pnp(HYBRID_GRAPHICS_PORT, HYBRID_GRAPHICS_DEVICE);
Expand All @@ -39,7 +39,7 @@ void early_hybrid_graphics(bool *enable_igd, bool *enable_peg)
return;
}

get_option(&mode, "hybrid_graphics_mode");
mode = get_int_option("hybrid_graphics_mode", HYBRID_GRAPHICS_DEFAULT_GPU);

if (mode == HYBRID_GRAPHICS_DISCRETE) {
printk(BIOS_DEBUG, "Hybrid graphics:"
Expand Down
3 changes: 2 additions & 1 deletion src/drivers/mrc_cache/mrc_cache.c
Expand Up @@ -285,7 +285,8 @@ static int mrc_cache_find_current(int type, uint32_t version,
* In recovery mode, force retraining if the memory retrain
* switch is set.
*/
if (vboot_recovery_mode_enabled() && get_recovery_mode_retrain_switch())
if (CONFIG(VBOOT_STARTS_IN_BOOTBLOCK) && vboot_recovery_mode_enabled()
&& get_recovery_mode_retrain_switch())
return -1;

cr = lookup_region(&region, type);
Expand Down
50 changes: 20 additions & 30 deletions src/drivers/pc80/rtc/option.c
Expand Up @@ -68,30 +68,33 @@ static struct cmos_option_table *get_cmos_layout(void)
return ct;
}

static struct cmos_entries *find_cmos_entry(struct cmos_option_table *ct, const char *name)
{
/* Figure out how long name is */
const size_t namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
struct cmos_entries *ce;

/* Find the requested entry record */
ce = (struct cmos_entries *)((unsigned char *)ct + ct->header_length);
for (; ce->tag == LB_TAG_OPTION;
ce = (struct cmos_entries *)((unsigned char *)ce + ce->size)) {
if (memcmp(ce->name, name, namelen) == 0)
return ce;
}
return NULL;
}

enum cb_err cmos_get_option(void *dest, const char *name)
{
struct cmos_option_table *ct;
struct cmos_entries *ce;
size_t namelen;
int found = 0;

/* Figure out how long name is */
namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);

ct = get_cmos_layout();
if (!ct)
return CB_CMOS_LAYOUT_NOT_FOUND;

/* find the requested entry record */
ce = (struct cmos_entries *)((unsigned char *)ct + ct->header_length);
for (; ce->tag == LB_TAG_OPTION;
ce = (struct cmos_entries *)((unsigned char *)ce + ce->size)) {
if (memcmp(ce->name, name, namelen) == 0) {
found = 1;
break;
}
}
if (!found) {
ce = find_cmos_entry(ct, name);
if (!ce) {
printk(BIOS_DEBUG, "No CMOS option '%s'.\n", name);
return CB_CMOS_OPTION_NOT_FOUND;
}
Expand Down Expand Up @@ -151,26 +154,13 @@ enum cb_err cmos_set_option(const char *name, void *value)
struct cmos_option_table *ct;
struct cmos_entries *ce;
unsigned long length;
size_t namelen;
int found = 0;

/* Figure out how long name is */
namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);

ct = get_cmos_layout();
if (!ct)
return CB_CMOS_LAYOUT_NOT_FOUND;

/* find the requested entry record */
ce = (struct cmos_entries *)((unsigned char *)ct + ct->header_length);
for (; ce->tag == LB_TAG_OPTION;
ce = (struct cmos_entries *)((unsigned char *)ce + ce->size)) {
if (memcmp(ce->name, name, namelen) == 0) {
found = 1;
break;
}
}
if (!found) {
ce = find_cmos_entry(ct, name);
if (!ce) {
printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name);
return CB_CMOS_OPTION_NOT_FOUND;
}
Expand Down
6 changes: 3 additions & 3 deletions src/drivers/smmstore/store.c
Expand Up @@ -267,14 +267,14 @@ int smmstore_clear_region(void)
/* Implementation of Version 2 */

static bool store_initialized;
static struct mem_region_device mdev_com_buf;
static struct region_device mdev_com_buf;

static int smmstore_rdev_chain(struct region_device *rdev)
{
if (!store_initialized)
return -1;

return rdev_chain_full(rdev, &mdev_com_buf.rdev);
return rdev_chain_full(rdev, &mdev_com_buf);
}

/**
Expand All @@ -289,7 +289,7 @@ int smmstore_init(void *buf, size_t len)
if (store_initialized)
return -1;

mem_region_device_rw_init(&mdev_com_buf, buf, len);
rdev_chain_mem_rw(&mdev_com_buf, buf, len);

store_initialized = true;

Expand Down
14 changes: 8 additions & 6 deletions src/drivers/spi/spi_flash.c
Expand Up @@ -88,15 +88,17 @@ int spi_flash_cmd(const struct spi_slave *spi, u8 cmd, void *response, size_t le
return ret;
}

/* TODO: This code is quite possibly broken and overflowing stacks. Fix ASAP! */
#pragma GCC diagnostic push
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic ignored "-Wstack-usage="
#endif
#pragma GCC diagnostic ignored "-Wvla"
int spi_flash_cmd_write(const struct spi_slave *spi, const u8 *cmd,
size_t cmd_len, const void *data, size_t data_len)
{
int ret;
u8 buff[4 + MAX_FLASH_CMD_DATA_SIZE];

if (ARRAY_SIZE(buff) < cmd_len + data_len)
return -1;

u8 buff[cmd_len + data_len];
memcpy(buff, cmd, cmd_len);
memcpy(buff + cmd_len, data, data_len);

Expand All @@ -108,6 +110,7 @@ int spi_flash_cmd_write(const struct spi_slave *spi, const u8 *cmd,

return ret;
}
#pragma GCC diagnostic pop

/* Perform the read operation honoring spi controller fifo size, reissuing
* the read command until the full request completed. */
Expand Down Expand Up @@ -256,7 +259,6 @@ int spi_flash_cmd_write_page_program(const struct spi_flash *flash, u32 offset,
byte_addr = offset % page_size;
chunk_len = MIN(len - actual, page_size - byte_addr);
chunk_len = spi_crop_chunk(&flash->spi, sizeof(cmd), chunk_len);
chunk_len = MIN(MAX_FLASH_CMD_DATA_SIZE, chunk_len);

spi_flash_addr(offset, cmd);
if (CONFIG(DEBUG_SPI_FLASH)) {
Expand Down
2 changes: 0 additions & 2 deletions src/drivers/spi/spi_flash_internal.h
Expand Up @@ -24,8 +24,6 @@
/* Common status */
#define STATUS_WIP 0x01

#define MAX_FLASH_CMD_DATA_SIZE 256

/* Send a single-byte command to the device and read the response */
int spi_flash_cmd(const struct spi_slave *spi, u8 cmd, void *response, size_t len);

Expand Down
4 changes: 2 additions & 2 deletions src/drivers/tpm/Kconfig
@@ -1,7 +1,7 @@
config TPM_INIT
config TPM_INIT_RAMSTAGE
bool
default y if TPM1 || TPM2
depends on !VBOOT
depends on !VBOOT && !VENDORCODE_ELTAN_VBOOT && !VENDORCODE_ELTAN_MBOOT
help
This driver automatically initializes the TPM if vboot is not used.
The TPM driver init is done during the ramstage chip init phase.
Expand Down
2 changes: 1 addition & 1 deletion src/drivers/tpm/Makefile.inc
@@ -1,4 +1,4 @@
ramstage-$(CONFIG_TPM_INIT) += tpm.c
ramstage-$(CONFIG_TPM_INIT_RAMSTAGE) += tpm.c

ifeq ($(CONFIG_TPM_PPI),y)
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += ppi.c
Expand Down
6 changes: 2 additions & 4 deletions src/drivers/vpd/vpd.c
Expand Up @@ -101,10 +101,8 @@ static int init_vpd_rdevs_from_cbmem(void)
if (!cbmem)
return -1;

rdev_chain(&ro_vpd, &addrspace_32bit.rdev,
(uintptr_t)cbmem->blob, cbmem->ro_size);
rdev_chain(&rw_vpd, &addrspace_32bit.rdev,
(uintptr_t)cbmem->blob + cbmem->ro_size, cbmem->rw_size);
rdev_chain_mem(&ro_vpd, cbmem->blob, cbmem->ro_size);
rdev_chain_mem(&rw_vpd, cbmem->blob + cbmem->ro_size, cbmem->rw_size);

return 0;
}
Expand Down
6 changes: 2 additions & 4 deletions src/ec/google/chromeec/ec.c
Expand Up @@ -856,10 +856,8 @@ int google_chromeec_cbi_get_fw_config(uint64_t *fw_config)
if (CONFIG(EC_GOOGLE_CHROMEEC_INCLUDE_SSFC_IN_FW_CONFIG)) {
uint32_t ssfc;

if (google_chromeec_cbi_get_ssfc(&ssfc))
return -1;

*fw_config |= (uint64_t)ssfc << 32;
if (!google_chromeec_cbi_get_ssfc(&ssfc))
*fw_config |= (uint64_t)ssfc << 32;
}
return 0;
}
Expand Down
11 changes: 5 additions & 6 deletions src/ec/kontron/it8516e/ec.c
Expand Up @@ -133,13 +133,13 @@ static void it8516e_set_fan_from_options(const config_t *const config,
u8 fan_max = config->default_fan_max[fan_idx];

fanX_mode[3] = '1' + fan_idx;
get_option(&fan_mode, fanX_mode);
fan_mode = get_int_option(fanX_mode, fan_mode);
if (!fan_mode)
fan_mode = IT8516E_MODE_AUTO;
it8516e_set_fan_mode(fan_idx, fan_mode);

fanX_target[3] = '1' + fan_idx;
get_option(&fan_target, fanX_target);
fan_target = get_int_option(fanX_target, fan_target);
switch (fan_mode) {
case IT8516E_MODE_AUTO:
printk(BIOS_DEBUG,
Expand Down Expand Up @@ -173,8 +173,8 @@ static void it8516e_set_fan_from_options(const config_t *const config,

fanX_min[3] = '1' + fan_idx;
fanX_max[3] = '1' + fan_idx;
get_option(&fan_min, fanX_min);
get_option(&fan_max, fanX_max);
fan_min = get_int_option(fanX_min, fan_min);
fan_max = get_int_option(fanX_max, fan_max);

if (!fan_max || fan_max > 100) /* Constrain fan_max to 100% */
fan_max = 100;
Expand Down Expand Up @@ -202,8 +202,7 @@ static void it8516e_pm2_init(struct device *dev)
ec_set_ports(find_resource(dev, PNP_IDX_IO1)->base,
find_resource(dev, PNP_IDX_IO0)->base);

u8 systemp_type = config->default_systemp;
get_option(&systemp_type, "systemp_type");
u8 systemp_type = get_int_option("systemp_type", config->default_systemp);
if (systemp_type >= IT8516E_SYSTEMP_LASTPLUSONE)
systemp_type = IT8516E_SYSTEMP_NONE;
it8516e_set_systemp_type(systemp_type);
Expand Down
2 changes: 1 addition & 1 deletion src/ec/lenovo/h8/acpi/battery.asl
Expand Up @@ -115,7 +115,7 @@ Method(BSTA, 4, NotSerialized)
{
Local0 |= 1
// Negate present rate
Local2 -= 0x10000
Local2 = 0x10000 - Local2
}
Else // Full battery, force to 0
{
Expand Down
7 changes: 1 addition & 6 deletions src/ec/lenovo/h8/bluetooth.c
Expand Up @@ -48,10 +48,5 @@ bool h8_has_bdc(const struct device *dev)
*/
bool h8_bluetooth_nv_enable(void)
{
u8 val;

if (get_option(&val, "bluetooth") != CB_SUCCESS)
return true;

return val;
return get_int_option("bluetooth", true);
}
59 changes: 20 additions & 39 deletions src/ec/lenovo/h8/h8.c
Expand Up @@ -242,9 +242,8 @@ static void h8_enable(struct device *dev)

reg8 = conf->config1;
if (conf->has_keyboard_backlight) {
if (get_option(&val, "backlight") != CB_SUCCESS)
val = 0; /* Both backlights. */
reg8 = (reg8 & 0xf3) | ((val & 0x3) << 2);
/* Default to both backlights */
reg8 = (reg8 & 0xf3) | ((get_int_option("backlight", 0) & 0x3) << 2);
}
ec_write(H8_CONFIG1, reg8);
ec_write(H8_CONFIG2, conf->config2);
Expand All @@ -253,17 +252,15 @@ static void h8_enable(struct device *dev)
beepmask0 = conf->beepmask0;
beepmask1 = conf->beepmask1;

if (conf->has_power_management_beeps
&& get_option(&val, "power_management_beeps") == CB_SUCCESS
&& val == 0) {
beepmask0 = 0x00;
beepmask1 = 0x00;
if (conf->has_power_management_beeps) {
if (get_int_option("power_management_beeps", 1) == 0) {
beepmask0 = 0x00;
beepmask1 = 0x00;
}
}

if (conf->has_power_management_beeps) {
if (get_option(&val, "low_battery_beep") != CB_SUCCESS)
val = 1;
if (val)
if (get_int_option("low_battery_beep", 1))
beepmask0 |= 2;
else
beepmask0 &= ~2;
Expand Down Expand Up @@ -295,19 +292,16 @@ static void h8_enable(struct device *dev)

ec_write(H8_FAN_CONTROL, H8_FAN_CONTROL_AUTO);

if (get_option(&val, "usb_always_on") != CB_SUCCESS)
val = 0;
h8_usb_always_on_enable(val);
h8_usb_always_on_enable(get_int_option("usb_always_on", 0));

if (get_option(&val, "wlan") != CB_SUCCESS)
val = 1;
h8_wlan_enable(val);
h8_wlan_enable(get_int_option("wlan", 1));

h8_trackpoint_enable(1);
h8_usb_power_enable(1);

if (get_option(&val, "volume") == CB_SUCCESS && !acpi_is_wakeup_s3())
ec_write(H8_VOLUME_CONTROL, val);
int volume = get_int_option("volume", -1);
if (volume >= 0 && !acpi_is_wakeup_s3())
ec_write(H8_VOLUME_CONTROL, volume);

val = (CONFIG(H8_SUPPORT_BT_ON_WIFI) || h8_has_bdc(dev)) &&
h8_bluetooth_nv_enable();
Expand All @@ -316,30 +310,17 @@ static void h8_enable(struct device *dev)
val = h8_has_wwan(dev) && h8_wwan_nv_enable();
h8_wwan_enable(val);

if (conf->has_uwb) {
if (get_option(&val, "uwb") != CB_SUCCESS)
val = 1;
if (conf->has_uwb)
h8_uwb_enable(get_int_option("uwb", 1));

h8_uwb_enable(val);
}
h8_fn_ctrl_swap(get_int_option("fn_ctrl_swap", 0));

if (get_option(&val, "fn_ctrl_swap") != CB_SUCCESS)
val = 0;
h8_fn_ctrl_swap(val);
h8_sticky_fn(get_int_option("sticky_fn", 0));

if (get_option(&val, "sticky_fn") != CB_SUCCESS)
val = 0;
h8_sticky_fn(val);

if (CONFIG(H8_HAS_PRIMARY_FN_KEYS)) {
if (get_option(&val, "f1_to_f12_as_primary") != CB_SUCCESS)
val = 1;
f1_to_f12_as_primary(val);
}
if (CONFIG(H8_HAS_PRIMARY_FN_KEYS))
f1_to_f12_as_primary(get_int_option("f1_to_f12_as_primary", 1));

if (get_option(&val, "first_battery") != CB_SUCCESS)
val = PRIMARY_BATTERY;
h8_charge_priority(val);
h8_charge_priority(get_int_option("first_battery", PRIMARY_BATTERY));

h8_set_audio_mute(0);
h8_mb_init();
Expand Down
7 changes: 1 addition & 6 deletions src/ec/lenovo/h8/wwan.c
Expand Up @@ -46,10 +46,5 @@ bool h8_has_wwan(const struct device *dev)
*/
bool h8_wwan_nv_enable(void)
{
u8 val;

if (get_option(&val, "wwan") != CB_SUCCESS)
return true;

return val;
return get_int_option("wwan", true);
}
9 changes: 2 additions & 7 deletions src/ec/lenovo/pmh7/pmh7.c
Expand Up @@ -106,7 +106,6 @@ static void enable_dev(struct device *dev)
{
const struct ec_lenovo_pmh7_config *conf = dev->chip_info;
struct resource *resource;
u8 val;

resource = new_resource(dev, EC_LENOVO_PMH7_INDEX);
resource->flags = IORESOURCE_IO | IORESOURCE_FIXED;
Expand All @@ -118,13 +117,9 @@ static void enable_dev(struct device *dev)
pmh7_backlight_enable(conf->backlight_enable);
pmh7_dock_event_enable(conf->dock_event_enable);

if (get_option(&val, "touchpad") != CB_SUCCESS)
val = 1;
pmh7_touchpad_enable(val);
pmh7_touchpad_enable(get_int_option("touchpad", 1));

if (get_option(&val, "trackpoint") != CB_SUCCESS)
val = 1;
pmh7_trackpoint_enable(val);
pmh7_trackpoint_enable(get_int_option("trackpoint", 1));

printk(BIOS_INFO, "PMH7: ID %02x Revision %02x\n",
pmh7_register_read(EC_LENOVO_PMH7_REG_ID),
Expand Down
4 changes: 4 additions & 0 deletions src/ec/purism/librem-ec/Kconfig
@@ -0,0 +1,4 @@
config EC_LIBREM_EC
bool
help
Purism Librem EC
6 changes: 6 additions & 0 deletions src/ec/purism/librem-ec/Makefile.inc
@@ -0,0 +1,6 @@
ifeq ($(CONFIG_EC_LIBREM_EC),y)

all-y += librem_ec.c
smm-$(CONFIG_DEBUG_SMI) += librem_ec.c

endif
22 changes: 22 additions & 0 deletions src/ec/purism/librem-ec/acpi/ac.asl
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */

Device (AC)
{
Name (_HID, "ACPI0003" /* Power Source Device */) // _HID: Hardware ID
Name (_PCL, Package (0x01) // _PCL: Power Consumer List
{
_SB
})

Name (ACFG, One)

Method (_PSR, 0, NotSerialized) // _PSR: Power Source
{
Return (ACFG)
}

Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
}
172 changes: 172 additions & 0 deletions src/ec/purism/librem-ec/acpi/battery.asl
@@ -0,0 +1,172 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#define BATTERY_DESIGN_VOLTAGE_MV 14800

Device (BAT0)
{
Name (_HID, EisaId ("PNP0C0A") /* Control Method Battery */) // _HID: Hardware ID
Name (_UID, Zero) // _UID: Unique ID
Name (_PCL, Package (0x01) // _PCL: Power Consumer List
{
_SB
})
Name (BFCC, Zero)
Method (_STA, 0, NotSerialized) // _STA: Status
{
If (^^PCI0.LPCB.EC0.ECOK)
{
If (^^PCI0.LPCB.EC0.BAT0)
{
Return (0x1F)
}
Else
{
Return (0x0F)
}
}
Else
{
Return (0x0F)
}
}

Name (PBIF, Package (0x0D)
{
One, // 0 - Power Unit
0xFFFFFFFF, // 1 - Design Capacity
0xFFFFFFFF, // 2 - Last Full Charge Capacity
One, // 3 - Battery Technology
BATTERY_DESIGN_VOLTAGE_MV, // 4 - Design Voltage
Zero, // 5 - Design Capacity of Warning
Zero, // 6 - Design Capacity of Low
0x40, // 7 - Battery Capacity Granularity 1
0x40, // 8 - Battery Capacity Granularity 2
"BAT", // 9 - Model Number
"0001", // 10 - Serial Number
"LION", // 11 - Battery Type
"Notebook" // 12 - OEM Information
})
Method (IVBI, 0, NotSerialized)
{
PBIF [1] = 0xFFFFFFFF
PBIF [2] = 0xFFFFFFFF
PBIF [4] = 0xFFFFFFFF
PBIF [9] = " "
PBIF [10] = " "
PBIF [11] = " "
PBIF [12] = " "
BFCC = Zero
}

Method (UPBI, 0, NotSerialized)
{
If (^^PCI0.LPCB.EC0.BAT0)
{
Local0 = (^^PCI0.LPCB.EC0.BDC0 & 0xFFFF)
PBIF [1] = Local0
Local0 = (^^PCI0.LPCB.EC0.BFC0 & 0xFFFF)
PBIF [2] = Local0
BFCC = Local0
Local0 = (^^PCI0.LPCB.EC0.BDV0 & 0xFFFF)
PBIF [4] = Local0
Local0 = (^^PCI0.LPCB.EC0.BCW0 & 0xFFFF)
PBIF [5] = Local0
Local0 = (^^PCI0.LPCB.EC0.BCL0 & 0xFFFF)
PBIF [6] = Local0
PBIF [9] = "BAT"
PBIF [10] = "0001"
PBIF [11] = "LION"
PBIF [12] = "Notebook"
}
Else
{
IVBI ()
}
}

Method (_BIF, 0, NotSerialized) // _BIF: Battery Information
{
If (^^PCI0.LPCB.EC0.ECOK)
{
UPBI ()
}
Else
{
IVBI ()
}

Return (PBIF) /* \_SB_.BAT0.PBIF */
}

Name (PBST, Package (0x04)
{
Zero, // 0 - Battery state
0xFFFFFFFF, // 1 - Battery present rate
0xFFFFFFFF, // 2 - Battery remaining capacity
BATTERY_DESIGN_VOLTAGE_MV // 3 - Battery present voltage
})
Method (IVBS, 0, NotSerialized)
{
PBST [0] = Zero
PBST [1] = 0xFFFFFFFF
PBST [2] = 0xFFFFFFFF
PBST [3] = 0x2710
}

Method (UPBS, 0, NotSerialized)
{
If (^^PCI0.LPCB.EC0.BAT0)
{
Local0 = Zero
Local1 = Zero
If (^^AC.ACFG)
{
If (((^^PCI0.LPCB.EC0.BST0 & 0x02) == 0x02))
{
Local0 |= 0x02
Local1 = (^^PCI0.LPCB.EC0.BPR0 & 0xFFFF)
}
}
Else
{
Local0 |= One
Local1 = (^^PCI0.LPCB.EC0.BPR0 & 0xFFFF)
}

Local7 = (Local1 & 0x8000)
If ((Local7 == 0x8000))
{
Local1 ^= 0xFFFF
}

Local2 = (^^PCI0.LPCB.EC0.BRC0 & 0xFFFF)
Local3 = (^^PCI0.LPCB.EC0.BPV0 & 0xFFFF)
PBST [0] = Local0
PBST [1] = Local1
PBST [2] = Local2
PBST [3] = Local3
If ((BFCC != ^^PCI0.LPCB.EC0.BFC0))
{
Notify (BAT0, 0x81) // Information Change
}
}
Else
{
IVBS ()
}
}

Method (_BST, 0, NotSerialized) // _BST: Battery Status
{
If (^^PCI0.LPCB.EC0.ECOK)
{
UPBS ()
}
Else
{
IVBS ()
}

Return (PBST) /* \_SB_.BAT0.PBST */
}
}
46 changes: 46 additions & 0 deletions src/ec/purism/librem-ec/acpi/battery_thresholds.asl
@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0-only */

Field (ERAM, ByteAcc, Lock, Preserve)
{
Offset (0xBC),
BTL0, 8, /* BAT0 charging start threshold */
BTH0, 8, /* BAT0 charging end threshold */
}

/*
* Get battery charging threshold
*
* Arg0: 0: Start threshold
* 1: Stop threshold
*/
Method (GBCT, 1, NotSerialized)
{
If (Arg0 == 0) {
Return (BTL0)
}

If (Arg0 == 1) {
Return (BTH0)
}

Return (0xFF)
}

/*
* Set battery charging threshold
*
* Arg0: 0: Start threshold
* 1: Stop threshold
* Arg1: Percentage
*/
Method (SBCT, 2, NotSerialized)
{
If (Arg1 <= 100) {
If (Arg0 == 0) {
BTL0 = Arg1
}
If (Arg0 == 1) {
BTH0 = Arg1
}
}
}
13 changes: 13 additions & 0 deletions src/ec/purism/librem-ec/acpi/buttons.asl
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */

Device (PWRB)
{
Name (_HID, EisaId ("PNP0C0C"))
Name (_PRW, Package () { EC_GPE_SWI, 3 })
}

Device (SLPB)
{
Name (_HID, EisaId ("PNP0C0E"))
Name (_PRW, Package () { EC_GPE_SWI, 3 })
}
232 changes: 232 additions & 0 deletions src/ec/purism/librem-ec/acpi/ec.asl
@@ -0,0 +1,232 @@
/* SPDX-License-Identifier: GPL-2.0-only */

Scope (\_SB) {
#include "ac.asl"
#include "battery.asl"
#include "buttons.asl"
#include "hid.asl"
#include "lid.asl"
#include "librem-ec.asl"
}

Device (\_SB.PCI0.LPCB.EC0)
{
Name (_HID, EisaId ("PNP0C09") /* Embedded Controller Device */) // _HID: Hardware ID
Name (_GPE, EC_GPE_SCI) // _GPE: General Purpose Events
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
IO (Decode16,
0x0062, // Range Minimum
0x0062, // Range Maximum
0x00, // Alignment
0x01, // Length
)
IO (Decode16,
0x0066, // Range Minimum
0x0066, // Range Maximum
0x00, // Alignment
0x01, // Length
)
})

#include "ec_ram.asl"

Name (ECOK, Zero)
Method (_REG, 2, Serialized) // _REG: Region Availability
{
Debug = Concatenate("EC: _REG", Concatenate(ToHexString(Arg0), Concatenate(" ", ToHexString(Arg1))))
If ((Arg0 == 0x03) && (Arg1 == One)) {
// Enable hardware touchpad lock, airplane mode, and keyboard backlight keys
ECOS = 1

// Enable software display brightness keys
WINF = 1

// Set current AC state
^^^^AC.ACFG = ADP
// Update battery information and status
^^^^BAT0.UPBI()
^^^^BAT0.UPBS()

// Notify of changes
Notify(^^^^AC, Zero)
Notify(^^^^BAT0, Zero)

PNOT ()

// EC is now available
ECOK = Arg1

// Reset Librem EC Device
^^^^LIEC.RSET()
}
}

Method (PTS, 1, Serialized) {
Debug = Concatenate("EC: PTS: ", ToHexString(Arg0))
If (ECOK) {
// Clear wake cause
WFNO = Zero
}
}

Method (WAK, 1, Serialized) {
Debug = Concatenate("EC: WAK: ", ToHexString(Arg0))
If (ECOK) {
// Set current AC state
^^^^AC.ACFG = ADP

// Update battery information and status
^^^^BAT0.UPBI()
^^^^BAT0.UPBS()

// Notify of changes
Notify(^^^^AC, Zero)
Notify(^^^^BAT0, Zero)

// Reset Librem EC Device
^^^^LIEC.RSET()
}
}

Method (_Q0A, 0, NotSerialized) // Touchpad Toggle
{
Debug = "EC: Touchpad Toggle"
}

Method (_Q0B, 0, NotSerialized) // Screen Toggle
{
Debug = "EC: Screen Toggle"
}

Method (_Q0C, 0, NotSerialized) // Mute
{
Debug = "EC: Mute"
}

Method (_Q0D, 0, NotSerialized) // Keyboard Backlight
{
Debug = "EC: Keyboard Backlight"
}

Method (_Q0E, 0, NotSerialized) // Volume Down
{
Debug = "EC: Volume Down"
}

Method (_Q0F, 0, NotSerialized) // Volume Up
{
Debug = "EC: Volume Up"
}

Method (_Q10, 0, NotSerialized) // Switch Video Mode
{
Debug = "EC: Switch Video Mode"
}

Method (_Q11, 0, NotSerialized) // Brightness Down
{
Debug = "EC: Brightness Down"
if (^^^^HIDD.HRDY) {
^^^^HIDD.HPEM (20)
}
}

Method (_Q12, 0, NotSerialized) // Brightness Up
{
Debug = "EC: Brightness Up"
if (^^^^HIDD.HRDY) {
^^^^HIDD.HPEM (19)
}
}

Method (_Q13, 0, NotSerialized) // Camera Toggle
{
Debug = "EC: Camera Toggle"
}

Method (_Q14, 0, NotSerialized) // Airplane Mode
{
Debug = "EC: Airplane Mode"
if (^^^^HIDD.HRDY) {
^^^^HIDD.HPEM (8)
}
// TODO: hardware airplane mode
}

Method (_Q15, 0, NotSerialized) // Suspend Button
{
Debug = "EC: Suspend Button"
Notify (SLPB, 0x80)
}

Method (_Q16, 0, NotSerialized) // AC Detect
{
Debug = "EC: AC Detect"
^^^^AC.ACFG = ADP
Notify (AC, 0x80) // Status Change
If (BAT0)
{
Notify (^^^^BAT0, 0x81) // Information Change
Notify (^^^^BAT0, 0x80) // Status Change
}
}

Method (_Q17, 0, NotSerialized) // BAT0 Update
{
Debug = "EC: BAT0 Update (17)"
Notify (^^^^BAT0, 0x81) // Information Change
}

Method (_Q19, 0, NotSerialized) // BAT0 Update
{
Debug = "EC: BAT0 Update (19)"
Notify (^^^^BAT0, 0x81) // Information Change
}

Method (_Q1B, 0, NotSerialized) // Lid Close
{
Debug = "EC: Lid Close"
Notify (LID0, 0x80)
}

Method (_Q1C, 0, NotSerialized) // Thermal Trip
{
Debug = "EC: Thermal Trip"
/* TODO
Notify (\_TZ.TZ0, 0x81) // Thermal Trip Point Change
Notify (\_TZ.TZ0, 0x80) // Thermal Status Change
*/
}

Method (_Q1D, 0, NotSerialized) // Power Button
{
Debug = "EC: Power Button"
Notify (PWRB, 0x80)
}

Method (_Q50, 0, NotSerialized) // Other Events
{
Local0 = OEM4
If (Local0 == 0x8A) {
Debug = "EC: White Keyboard Backlight"
Notify (^^^^LIEC, 0x80)
} ElseIf (Local0 == 0x9F) {
Debug = "EC: Color Keyboard Toggle"
Notify (^^^^LIEC, 0x81)
} ElseIf (Local0 == 0x81) {
Debug = "EC: Color Keyboard Down"
Notify (^^^^LIEC, 0x82)
} ElseIf (Local0 == 0x82) {
Debug = "EC: Color Keyboard Up"
Notify (^^^^LIEC, 0x83)
} ElseIf (Local0 == 0x80) {
Debug = "EC: Color Keyboard Color Change"
Notify (^^^^LIEC, 0x84)
} Else {
Debug = Concatenate("EC: Other: ", ToHexString(Local0))
}
}

#include "battery_thresholds.asl"
}
57 changes: 57 additions & 0 deletions src/ec/purism/librem-ec/acpi/ec_ram.asl
@@ -0,0 +1,57 @@
/* SPDX-License-Identifier: GPL-2.0-only */

OperationRegion (ERAM, EmbeddedControl, Zero, 0xFF)
Field (ERAM, ByteAcc, Lock, Preserve)
{
Offset (0x03),
LSTE, 1, // Lid is open
, 1,
LWKE, 1, // Lid wake
, 5,
Offset (0x07),
TMP1, 8, // CPU temperature
Offset (0x10),
ADP, 1, // AC adapter connected
, 1,
BAT0, 1, // Battery connected
, 5,
WFNO, 8, // Wake cause (not implemented)
Offset (0x16),
BDC0, 32, // Battery design capacity
BFC0, 32, // Battery full capacity
Offset (0x22),
BDV0, 32, // Battery design voltage
BST0, 32, // Battery status
BPR0, 32, // Battery current
BRC0, 32, // Battery remaining capacity
BPV0, 32, // Battery voltage
Offset (0x3A),
BCW0, 32,
BCL0, 32,
Offset (0x68),
ECOS, 8, // Detected OS, 0 = no ACPI, 1 = ACPI but no driver, 2 = ACPI with driver
Offset (0xC8),
OEM1, 8,
OEM2, 8,
OEM3, 16,
OEM4, 8, // Extra SCI data
Offset (0xCD),
TMP2, 8, // GPU temperature
DUT1, 8, // Fan 1 duty
DUT2, 8, // Fan 2 duty
RPM1, 16, // Fan 1 RPM
RPM2, 16, // Fan 2 RPM
Offset (0xD9),
WLED, 8, // WiFi LED
NOTR, 8, // notification LED R
NOTG, 8, // notification LED G
NOTB, 8, // notification LED B
WINF, 8, // Enable ACPI brightness controls
Offset (0xF8),
FCMD, 8,
FDAT, 8,
FBUF, 8,
FBF1, 8,
FBF2, 8,
FBF3, 8,
}
50 changes: 50 additions & 0 deletions src/ec/purism/librem-ec/acpi/hid.asl
@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: GPL-2.0-only */

Device (HIDD)
{
Name (_HID, "INT33D5")
Name (HBSY, Zero)
Name (HIDX, Zero)
Name (HRDY, Zero)

Method (HDEM, 0, Serialized)
{
HBSY = Zero
Return (HIDX)
}

Method (HDMM, 0, Serialized)
{
Return (Zero)
}

Method (HDSM, 1, Serialized)
{
HRDY = Arg0
}

Method (HPEM, 1, Serialized)
{
HBSY = One
HIDX = Arg0

Notify (HIDD, 0xC0)
Local0 = Zero
While ((Local0 < 0xFA) && HBSY)
{
Sleep (0x04)
Local0++
}

If (HBSY == One)
{
HBSY = Zero
HIDX = Zero
Return (One)
}
Else
{
Return (Zero)
}
}
}
176 changes: 176 additions & 0 deletions src/ec/purism/librem-ec/acpi/librem-ec.asl
@@ -0,0 +1,176 @@
/* SPDX-License-Identifier: GPL-2.0-only */

// Notifications:
// 0x80 - hardware backlight toggle
// 0x81 - backlight toggle
// 0x82 - backlight down
// 0x83 - backlight up
// 0x84 - backlight color change
Device (LIEC) {
Name (_HID, "PURI4543")
Name (_UID, 0)

Method (RSET, 0, Serialized) {
Debug = "LIEC: RSET"
SAPL(0)
SKBL(0)
}

Method (INIT, 0, Serialized) {
Debug = "LIEC: INIT"
RSET()
If (^^PCI0.LPCB.EC0.ECOK) {
// Set flags to use software control
^^PCI0.LPCB.EC0.ECOS = 2
Return (0)
} Else {
Return (1)
}
}

Method (FINI, 0, Serialized) {
Debug = "LIEC: FINI"
RSET()
If (^^PCI0.LPCB.EC0.ECOK) {
// Set flags to use hardware control
^^PCI0.LPCB.EC0.ECOS = 1
Return (0)
} Else {
Return (1)
}
}

// Get Airplane LED
Method (GAPL, 0, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
If (^^PCI0.LPCB.EC0.WLED & 0x40) {
Return (1)
}
}
Return (0)
}

// Set Airplane LED
Method (SAPL, 1, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
If (Arg0) {
^^PCI0.LPCB.EC0.WLED |= 0x40
} Else {
^^PCI0.LPCB.EC0.WLED &= 0xBF
}
}
}

// Get notification red LED
Method (GNTR, 0, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
Return (^^PCI0.LPCB.EC0.NOTR)
}
Return (0)
}

// Set notification red LED
Method (SNTR, 1, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
^^PCI0.LPCB.EC0.NOTR = Arg0
}
}

// Get notification green LED
Method (GNTG, 0, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
Return (^^PCI0.LPCB.EC0.NOTG)
}
Return (0)
}

// Set notification green LED
Method (SNTG, 1, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
^^PCI0.LPCB.EC0.NOTG = Arg0
}
}

// Get notification blue LED
Method (GNTB, 0, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
Return (^^PCI0.LPCB.EC0.NOTB)
}
Return (0)
}

// Set notification blue LED
Method (SNTB, 1, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
^^PCI0.LPCB.EC0.NOTB = Arg0
}
}

// Get KB LED
Method (GKBL, 0, Serialized) {
Local0 = 0
If (^^PCI0.LPCB.EC0.ECOK) {
^^PCI0.LPCB.EC0.FDAT = One
^^PCI0.LPCB.EC0.FCMD = 0xCA
Local0 = ^^PCI0.LPCB.EC0.FBUF
^^PCI0.LPCB.EC0.FCMD = Zero
}
Return (Local0)
}

// Set KB Led
Method (SKBL, 1, Serialized) {
If (^^PCI0.LPCB.EC0.ECOK) {
^^PCI0.LPCB.EC0.FDAT = Zero
^^PCI0.LPCB.EC0.FBUF = Arg0
^^PCI0.LPCB.EC0.FCMD = 0xCA
}
}

// Fan names
Method (NFAN, 0, Serialized) {
Return (Package() {
"CPU fan",
})
}

// Get fan duty cycle and RPM as a single value
Method (GFAN, 1, Serialized) {
Local0 = 0
Local1 = 0
If (^^PCI0.LPCB.EC0.ECOK) {
If (Arg0 == 0) {
Local0 = ^^PCI0.LPCB.EC0.DUT1
Local1 = ^^PCI0.LPCB.EC0.RPM1
} ElseIf (Arg0 == 1) {
Local0 = ^^PCI0.LPCB.EC0.DUT2
Local1 = ^^PCI0.LPCB.EC0.RPM2
}
}
If (Local1 != 0) {
// 60 * (EC frequency / 120) / 2
Local1 = 2156250 / Local1
}
Return ((Local1 << 8) | Local0)
}

// Temperature names
Method (NTMP, 0, Serialized) {
Return (Package() {
"CPU temp",
})
}

// Get temperature
Method (GTMP, 1, Serialized) {
Local0 = 0;
If (^^PCI0.LPCB.EC0.ECOK) {
If (Arg0 == 0) {
Local0 = ^^PCI0.LPCB.EC0.TMP1
} ElseIf (Arg0 == 1) {
Local0 = ^^PCI0.LPCB.EC0.TMP2
}
}
Return (Local0)
}
}
23 changes: 23 additions & 0 deletions src/ec/purism/librem-ec/acpi/lid.asl
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-only */

Device (LID0)
{
Name (_HID, EisaId ("PNP0C0D"))
Name (_PRW, Package () { EC_GPE_SWI, 3 })

Method (_LID, 0, NotSerialized) {
DEBUG = "LID: _LID"
If (^^PCI0.LPCB.EC0.ECOK) {
Return (^^PCI0.LPCB.EC0.LSTE)
} Else {
Return (One)
}
}

Method (_PSW, 1, NotSerialized) {
DEBUG = Concatenate("LID: _PSW: ", ToHexString(Arg0))
If (^^PCI0.LPCB.EC0.ECOK) {
^^PCI0.LPCB.EC0.LWKE = Arg0
}
}
}
61 changes: 61 additions & 0 deletions src/ec/purism/librem-ec/librem_ec.c
@@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#include <arch/io.h>
#include <console/system76_ec.h>
#include <timer.h>

// This is the command region for Librem EC firmware. It must be
// enabled for LPC in the mainboard.
#define LIBREM_EC_BASE 0x0E00
#define LIBREM_EC_SIZE 256

#define REG_CMD 0
#define REG_RESULT 1

// When command register is 0, command is complete
#define CMD_FINISHED 0

// Print command. Registers are unique for each command
#define CMD_PRINT 4
#define CMD_PRINT_REG_FLAGS 2
#define CMD_PRINT_REG_LEN 3
#define CMD_PRINT_REG_DATA 4

static inline uint8_t system76_ec_read(uint8_t addr)
{
return inb(LIBREM_EC_BASE + (uint16_t)addr);
}

static inline void system76_ec_write(uint8_t addr, uint8_t data)
{
outb(data, LIBREM_EC_BASE + (uint16_t)addr);
}

void system76_ec_init(void)
{
// Clear entire command region
for (int i = 0; i < LIBREM_EC_SIZE; i++)
system76_ec_write((uint8_t)i, 0);
}

void system76_ec_flush(void)
{
system76_ec_write(REG_CMD, CMD_PRINT);

// Wait for command completion, for up to 10 milliseconds, with a
// test period of 1 microsecond
wait_us(10000, system76_ec_read(REG_CMD) == CMD_FINISHED);

system76_ec_write(CMD_PRINT_REG_LEN, 0);
}

void system76_ec_print(uint8_t byte)
{
uint8_t len = system76_ec_read(CMD_PRINT_REG_LEN);
system76_ec_write(CMD_PRINT_REG_DATA + len, byte);
system76_ec_write(CMD_PRINT_REG_LEN, len + 1);

// If we hit the end of the buffer, or were given a newline, flush
if (byte == '\n' || len >= (LIBREM_EC_SIZE - CMD_PRINT_REG_DATA))
system76_ec_flush();
}
26 changes: 24 additions & 2 deletions src/include/acpi/acpi.h
Expand Up @@ -418,6 +418,10 @@ enum {
DRHD_INCLUDE_PCI_ALL = 1
};

enum {
ATC_REQUIRED = 1
};

enum dmar_flags {
DMAR_INTR_REMAP = 1 << 0,
DMAR_X2APIC_OPT_OUT = 1 << 1,
Expand Down Expand Up @@ -472,7 +476,6 @@ typedef struct dmar_satc_entry {
u8 flags;
u8 reserved;
u16 segment_number;
u8 device_scope[];
} __packed dmar_satc_entry_t;

/* DMAR (DMA Remapping Reporting Structure) */
Expand Down Expand Up @@ -942,6 +945,25 @@ typedef struct acpi_tstate {
u32 status;
} __packed acpi_tstate_t;

enum acpi_lpi_state_flags {
ACPI_LPI_STATE_DISABLED = 0,
ACPI_LPI_STATE_ENABLED
};

/* Low Power Idle State */
struct acpi_lpi_state {
u32 min_residency_us;
u32 worst_case_wakeup_latency_us;
u32 flags;
u32 arch_context_lost_flags;
u32 residency_counter_frequency_hz;
u32 enabled_parent_state;
acpi_addr_t entry_method;
acpi_addr_t residency_counter_register;
acpi_addr_t usage_counter_register;
const char *state_name;
};

/* Port types for ACPI _UPC object */
enum acpi_upc_type {
UPC_TYPE_A,
Expand Down Expand Up @@ -1110,7 +1132,7 @@ unsigned long acpi_create_dmar_rhsa(unsigned long current, u64 base_addr,
unsigned long acpi_create_dmar_andd(unsigned long current, u8 device_number,
const char *device_name);
unsigned long acpi_create_dmar_satc(unsigned long current, u8 flags,
u16 segment, const char *device_scope);
u16 segment);
void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current);
void acpi_dmar_rmrr_fixup(unsigned long base, unsigned long current);
void acpi_dmar_atsr_fixup(unsigned long base, unsigned long current);
Expand Down
16 changes: 16 additions & 0 deletions src/include/acpi/acpi_osc.h
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef __ACPI_ACPI_OSC_H__
#define __ACPI_ACPI_OSC_H__

/* _OSC (Operating System Capabilities) */
#define OSC_CDW1_QUERY (1 << 0)
#define OSC_CDW1_UNKNOWN_FAILURE (1 << 1)
#define OSC_CDW1_UNRECOGNIZED_UUID (1 << 2)
#define OSC_CDW1_UNRECOGNIZED_REVISION (1 << 3)
#define OSC_CDW1_CAPABILITIES_MASKED (1 << 4)

/* Platform-Wide \_SB._OSC */
#define OSC_SB_UUID "0811b06e-4a27-44f9-8d60-3cbbc22e7b48"

#endif /* __ACPI_ACPI_OSC_H__ */
1 change: 1 addition & 0 deletions src/include/acpi/acpigen.h
Expand Up @@ -338,6 +338,7 @@ inline void acpigen_write_device_end(void)
{
acpigen_pop_len();
}
void acpigen_write_LPI_package(u64 level, const struct acpi_lpi_state *states, u16 nentries);
void acpigen_write_PPC(u8 nr);
void acpigen_write_PPC_NVS(void);
void acpigen_write_empty_PCT(void);
Expand Down
14 changes: 14 additions & 0 deletions src/include/assert.h
Expand Up @@ -29,12 +29,24 @@
#define __build_time_assert(x) 0
#endif

/* CMocka function redefinition. */
void mock_assert(const int result, const char *const expression,
const char *const file, const int line);

#if ENV_TEST
#define MOCK_ASSERT(result, expression) \
mock_assert((result), (expression), __ASSERT_FILE__, __ASSERT_LINE__)
#else
#define MOCK_ASSERT(result, expression)
#endif

/* GCC and CAR versions */
#define ASSERT(x) { \
if (!__build_time_assert(x) && !(x)) { \
printk(BIOS_EMERG, \
"ASSERTION ERROR: file '%s', line %d\n", \
__ASSERT_FILE__, __ASSERT_LINE__); \
MOCK_ASSERT(!!(x), #x); \
if (CONFIG(FATAL_ASSERTS)) \
hlt(); \
} \
Expand All @@ -45,6 +57,7 @@
"ASSERTION ERROR: file '%s', line %d\n", \
__ASSERT_FILE__, __ASSERT_LINE__); \
printk(BIOS_EMERG, "%s", msg); \
MOCK_ASSERT(!!(x), (msg)); \
if (CONFIG(FATAL_ASSERTS)) \
hlt(); \
} \
Expand All @@ -53,6 +66,7 @@
printk(BIOS_EMERG, \
"ERROR: BUG ENCOUNTERED at file '%s', line %d\n", \
__ASSERT_FILE__, __ASSERT_LINE__); \
MOCK_ASSERT(0, "BUG ENCOUNTERED"); \
if (CONFIG(FATAL_ASSERTS)) \
hlt(); \
}
Expand Down
1 change: 1 addition & 0 deletions src/include/bootblock_common.h
Expand Up @@ -35,6 +35,7 @@ void bootblock_main_with_timestamp(uint64_t base_timestamp,
/* This is the argument structure passed from decompressor to bootblock. */
struct bootblock_arg {
uint64_t base_timestamp;
void *metadata_hash_anchor;
uint32_t num_timestamps;
struct timestamp_entry timestamps[];
};
Expand Down
13 changes: 3 additions & 10 deletions src/include/cbfs.h
Expand Up @@ -67,7 +67,7 @@
* attributes). Must return a pointer to space of the requested size where the file data should
* be loaded, or NULL to make the operation fail.
*/
typedef void *(*cbfs_allocator_t)(void *arg, size_t size, union cbfs_mdata *mdata);
typedef void *(*cbfs_allocator_t)(void *arg, size_t size, const union cbfs_mdata *mdata);

static inline size_t cbfs_load(const char *name, void *buf, size_t size);
static inline size_t cbfs_ro_load(const char *name, void *buf, size_t size);
Expand Down Expand Up @@ -165,13 +165,6 @@ void *cbfs_boot_map_optionrom(uint16_t vendor, uint16_t device);
/* Return mapping of option ROM with revision number. Returns NULL on error. */
void *cbfs_boot_map_optionrom_revision(uint16_t vendor, uint16_t device, uint8_t rev);

/* Load |in_size| bytes from |rdev| at |offset| to the |buffer_size| bytes large |buffer|,
decompressing it according to |compression| in the process. Returns the decompressed file
size, or 0 on error. LZMA files will be mapped for decompression. LZ4 files will be
decompressed in-place with the buffer size requirements outlined in compression.h. */
size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
size_t in_size, void *buffer, size_t buffer_size, uint32_t compression);


/**********************************************************************************************
* INTERNAL HELPERS FOR INLINES, DO NOT USE. *
Expand All @@ -183,9 +176,9 @@ struct _cbfs_default_allocator_arg {
void *buf;
size_t buf_size;
};
void *_cbfs_default_allocator(void *arg, size_t size, union cbfs_mdata *unused);
void *_cbfs_default_allocator(void *arg, size_t size, const union cbfs_mdata *unused);

void *_cbfs_cbmem_allocator(void *arg, size_t size, union cbfs_mdata *unused);
void *_cbfs_cbmem_allocator(void *arg, size_t size, const union cbfs_mdata *unused);

/**********************************************************************************************
* INLINE IMPLEMENTATIONS *
Expand Down
2 changes: 1 addition & 1 deletion src/include/cbfs_glue.h
Expand Up @@ -20,7 +20,7 @@
(CONFIG(TOCTOU_SAFETY) || ENV_INITIAL_STAGE))

#define ERROR(...) printk(BIOS_ERR, "CBFS ERROR: " __VA_ARGS__)
#define LOG(...) printk(BIOS_ERR, "CBFS: " __VA_ARGS__)
#define LOG(...) printk(BIOS_INFO, "CBFS: " __VA_ARGS__)
#define DEBUG(...) do { \
if (CONFIG(DEBUG_CBFS)) \
printk(BIOS_SPEW, "CBFS DEBUG: " __VA_ARGS__); \
Expand Down
18 changes: 8 additions & 10 deletions src/include/console/console.h
Expand Up @@ -50,30 +50,28 @@ static inline int get_console_loglevel(void)
#if __CONSOLE_ENABLE__
asmlinkage void console_init(void);
int console_log_level(int msg_level);

int printk(int msg_level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
int vprintk(int msg_level, const char *fmt, va_list args);

void do_putchar(unsigned char byte);

/* Return number of microseconds elapsed from start of stage or the previous
get_and_reset() call. */
long console_time_get_and_reset(void);
void console_time_report(void);

#define printk(LEVEL, fmt, args...) do_printk(LEVEL, fmt, ##args)
#define vprintk(LEVEL, fmt, args) do_vprintk(LEVEL, fmt, args)

enum { CONSOLE_LOG_NONE = 0, CONSOLE_LOG_FAST, CONSOLE_LOG_ALL };
#else
static inline void console_init(void) {}
static inline int console_log_level(int msg_level) { return 0; }
static inline void printk(int LEVEL, const char *fmt, ...) {}
static inline void vprintk(int LEVEL, const char *fmt, va_list args) {}
static inline int
__attribute__((format(printf, 2, 3)))
printk(int LEVEL, const char *fmt, ...) { return 0; }
static inline int vprintk(int LEVEL, const char *fmt, va_list args) { return 0; }
static inline void do_putchar(unsigned char byte) {}
static inline long console_time_get_and_reset(void) { return 0; }
static inline void console_time_report(void) {}
#endif

int do_printk(int msg_level, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));

int do_vprintk(int msg_level, const char *fmt, va_list args);

#endif /* CONSOLE_CONSOLE_H_ */
56 changes: 53 additions & 3 deletions src/include/cpu/x86/lapic.h
Expand Up @@ -2,19 +2,54 @@
#define CPU_X86_LAPIC_H

#include <arch/mmio.h>
#include <arch/cpu.h>
#include <cpu/x86/lapic_def.h>
#include <cpu/x86/msr.h>
#include <halt.h>
#include <stdint.h>

static inline bool is_x2apic_mode(void)
{
msr_t msr;
msr = rdmsr(LAPIC_BASE_MSR);
return (msr.lo & LAPIC_BASE_MSR_X2APIC_MODE);
}

static inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
{
msr_t icr;
icr.hi = apicid;
icr.lo = icrlow;
wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
}

static __always_inline uint32_t lapic_read(unsigned int reg)
{
return read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
uint32_t value, index;
msr_t msr;

if (is_x2apic_mode()) {
index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
msr = rdmsr(index);
value = msr.lo;
} else {
value = read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
}
return value;
}

static __always_inline void lapic_write(unsigned int reg, uint32_t v)
{
write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v);
msr_t msr;
uint32_t index;
if (is_x2apic_mode()) {
index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
msr.hi = 0x0;
msr.lo = v;
wrmsr(index, msr);
} else {
write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v);
}
}

static __always_inline void lapic_wait_icr_idle(void)
Expand All @@ -41,9 +76,24 @@ static inline void disable_lapic(void)
wrmsr(LAPIC_BASE_MSR, msr);
}

static __always_inline unsigned int initial_lapicid(void)
{
uint32_t lapicid;
if (is_x2apic_mode())
lapicid = lapic_read(LAPIC_ID);
else
lapicid = cpuid_ebx(1) >> 24;
return lapicid;
}

static __always_inline unsigned int lapicid(void)
{
return lapic_read(LAPIC_ID) >> 24;
uint32_t lapicid = lapic_read(LAPIC_ID);

/* check x2apic mode and return accordingly */
if (!is_x2apic_mode())
lapicid >>= 24;
return lapicid;
}

#if !CONFIG(AP_IN_SIPI_WAIT)
Expand Down
4 changes: 4 additions & 0 deletions src/include/cpu/x86/lapic_def.h
Expand Up @@ -3,6 +3,7 @@

#define LAPIC_BASE_MSR 0x1B
#define LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8)
#define LAPIC_BASE_MSR_X2APIC_MODE (1 << 10)
#define LAPIC_BASE_MSR_ENABLE (1 << 11)
#define LAPIC_BASE_MSR_ADDR_MASK 0xFFFFF000

Expand Down Expand Up @@ -94,4 +95,7 @@
#define LAPIC_TDR_DIV_64 0x9
#define LAPIC_TDR_DIV_128 0xA

#define X2APIC_MSR_BASE_ADDRESS 0x800
#define X2APIC_LAPIC_ID (X2APIC_MSR_BASE_ADDRESS | (LAPIC_ID >> 4))
#define X2APIC_MSR_ICR_ADDRESS 0x830
#endif /* CPU_X86_LAPIC_DEF_H */
4 changes: 2 additions & 2 deletions src/include/cpu/x86/smm.h
Expand Up @@ -85,7 +85,7 @@ struct smm_stub_params {
* initializes this array with a 1:1 mapping. If the APIC ids are not
* contiguous like the 1:1 mapping it is up to the caller of the stub
* loader to adjust this mapping. */
u8 apic_id_to_cpu[CONFIG_MAX_CPUS];
u16 apic_id_to_cpu[CONFIG_MAX_CPUS];
/* STM's 32bit entry into SMI handler */
u32 start32_offset;
} __packed;
Expand Down Expand Up @@ -148,7 +148,7 @@ struct smm_loader_params {
};

/* Both of these return 0 on success, < 0 on failure. */
int smm_setup_relocation_handler(struct smm_loader_params *params);
int smm_setup_relocation_handler(void * const perm_smram, struct smm_loader_params *params);
int smm_load_module(void *smram, size_t size, struct smm_loader_params *params);

u32 smm_get_cpu_smbase(unsigned int cpu_num);
Expand Down
184 changes: 27 additions & 157 deletions src/include/device/dram/ddr3.h
Expand Up @@ -51,31 +51,31 @@
* Module type (byte 3, bits 3:0) of SPD
* This definition is specific to DDR3. DDR2 SPDs have a different structure.
*/
enum spd_dimm_type {
SPD_DIMM_TYPE_UNDEFINED = 0x00,
SPD_DIMM_TYPE_RDIMM = 0x01,
SPD_DIMM_TYPE_UDIMM = 0x02,
SPD_DIMM_TYPE_SO_DIMM = 0x03,
SPD_DIMM_TYPE_MICRO_DIMM = 0x04,
SPD_DIMM_TYPE_MINI_RDIMM = 0x05,
SPD_DIMM_TYPE_MINI_UDIMM = 0x06,
SPD_DIMM_TYPE_MINI_CDIMM = 0x07,
SPD_DIMM_TYPE_72B_SO_UDIMM = 0x08,
SPD_DIMM_TYPE_72B_SO_RDIMM = 0x09,
SPD_DIMM_TYPE_72B_SO_CDIMM = 0x0a,
SPD_DIMM_TYPE_LRDIMM = 0x0b,
SPD_DIMM_TYPE_16B_SO_DIMM = 0x0c,
SPD_DIMM_TYPE_32B_SO_DIMM = 0x0d,
enum spd_dimm_type_ddr3 {
SPD_DDR3_DIMM_TYPE_UNDEFINED = 0x00,
SPD_DDR3_DIMM_TYPE_RDIMM = 0x01,
SPD_DDR3_DIMM_TYPE_UDIMM = 0x02,
SPD_DDR3_DIMM_TYPE_SO_DIMM = 0x03,
SPD_DDR3_DIMM_TYPE_MICRO_DIMM = 0x04,
SPD_DDR3_DIMM_TYPE_MINI_RDIMM = 0x05,
SPD_DDR3_DIMM_TYPE_MINI_UDIMM = 0x06,
SPD_DDR3_DIMM_TYPE_MINI_CDIMM = 0x07,
SPD_DDR3_DIMM_TYPE_72B_SO_UDIMM = 0x08,
SPD_DDR3_DIMM_TYPE_72B_SO_RDIMM = 0x09,
SPD_DDR3_DIMM_TYPE_72B_SO_CDIMM = 0x0a,
SPD_DDR3_DIMM_TYPE_LRDIMM = 0x0b,
SPD_DDR3_DIMM_TYPE_16B_SO_DIMM = 0x0c,
SPD_DDR3_DIMM_TYPE_32B_SO_DIMM = 0x0d,
/* Masks to bits 3:0 to give the dimm type */
SPD_DIMM_TYPE_MASK = 0x0f,
SPD_DDR3_DIMM_TYPE_MASK = 0x0f,
};

/**
* \brief DIMM flags
*
* Characteristic flags for the DIMM, as presented by the SPD
*/
typedef union dimm_flags_st {
union dimm_flags_ddr3_st {
/* The whole point of the union/struct construct is to allow us to clear
* all the bits with one line: flags.raw = 0.
* We do not care how these bits are ordered */
Expand Down Expand Up @@ -111,19 +111,19 @@ typedef union dimm_flags_st {
unsigned int therm_sensor:1;
};
unsigned int raw;
} dimm_flags_t;
};

/**
* \brief DIMM characteristics
*
* The characteristics of each DIMM, as presented by the SPD
*/
typedef struct dimm_attr_st {
struct dimm_attr_ddr3_st {
enum spd_memory_type dram_type;
enum spd_dimm_type dimm_type;
enum spd_dimm_type_ddr3 dimm_type;
u16 cas_supported;
/* Flags extracted from SPD */
dimm_flags_t flags;
union dimm_flags_ddr3_st flags;
/* SDRAM width */
u8 width;
/* Number of ranks */
Expand Down Expand Up @@ -161,7 +161,7 @@ typedef struct dimm_attr_st {
u8 part_number[17];
/* Serial number */
u8 serial[SPD_DIMM_SERIAL_LEN];
} dimm_attr;
};

enum ddr3_xmp_profile {
DDR3_XMP_PROFILE_1 = 0,
Expand All @@ -172,144 +172,14 @@ typedef u8 spd_raw_data[256];

u16 spd_ddr3_calc_crc(u8 *spd, int len);
u16 spd_ddr3_calc_unique_crc(u8 *spd, int len);
int spd_decode_ddr3(dimm_attr *dimm, spd_raw_data spd_data);
int spd_dimm_is_registered_ddr3(enum spd_dimm_type type);
void dram_print_spd_ddr3(const dimm_attr *dimm);
int spd_xmp_decode_ddr3(dimm_attr *dimm,
int spd_decode_ddr3(struct dimm_attr_ddr3_st *dimm, spd_raw_data spd_data);
int spd_dimm_is_registered_ddr3(enum spd_dimm_type_ddr3 type);
void dram_print_spd_ddr3(const struct dimm_attr_ddr3_st *dimm);
int spd_xmp_decode_ddr3(struct dimm_attr_ddr3_st *dimm,
spd_raw_data spd,
enum ddr3_xmp_profile profile);
enum cb_err spd_add_smbios17(const u8 channel, const u8 slot,
const u16 selected_freq,
const dimm_attr *info);
/**
* \brief Read double word from specified address
*
* Should be useful when doing an MRS to the DIMM
*/
static inline u32 volatile_read(volatile uintptr_t addr)
{
volatile u32 result;
result = *(volatile u32 *)addr;
return result;
}

/**
* \brief Representation of an MRS command
*
* This represents an MRS command as seen by the DIMM. This is not a memory
* address that can be read to generate an MRS command. The mapping of CPU
* to memory pins is hardware-dependent.
* \n
* The idea is to generalize the MRS code, and only need a hardware-specific
* function to map the MRS bits to CPU address bits. An MRS command can be
* sent like:
* @code{.c}
* u32 addr;
* mrs_cmd_t mrs;
* chipset_enable_mrs_command_mode();
* mrs = ddr3_get_mr2(rtt_wr, srt, asr, cwl)
* if (rank_has_mirrorred_pins)
* mrs = ddr3_mrs_mirror_pins(mrs);
* addr = chipset_specific_get_mrs_addr(mrs);
* volatile_read(addr);
* @endcode
*
* The MRS representation has the following structure:
* - cmd[15:0] = Address pins MA[15:0]
* - cmd[18:16] = Bank address BA[2:0]
*/
typedef u32 mrs_cmd_t;

enum ddr3_mr0_precharge {
DDR3_MR0_PRECHARGE_SLOW = 0,
DDR3_MR0_PRECHARGE_FAST = 1,
};
enum ddr3_mr0_mode {
DDR3_MR0_MODE_NORMAL = 0,
DDR3_MR0_MODE_TEST = 1,
};
enum ddr3_mr0_dll_reset {
DDR3_MR0_DLL_RESET_NO = 0,
DDR3_MR0_DLL_RESET_YES = 1,
};
enum ddr3_mr0_burst_type {
DDR3_MR0_BURST_TYPE_SEQUENTIAL = 0,
DDR3_MR0_BURST_TYPE_INTERLEAVED = 1,
};
enum ddr3_mr0_burst_length {
DDR3_MR0_BURST_LENGTH_8 = 0,
DDR3_MR0_BURST_LENGTH_CHOP = 1,
DDR3_MR0_BURST_LENGTH_4 = 2,
};
mrs_cmd_t ddr3_get_mr0(enum ddr3_mr0_precharge precharge_pd,
u8 write_recovery,
enum ddr3_mr0_dll_reset dll_reset,
enum ddr3_mr0_mode mode,
u8 cas,
enum ddr3_mr0_burst_type interleaved_burst,
enum ddr3_mr0_burst_length burst_length);

enum ddr3_mr1_qoff {
DDR3_MR1_QOFF_ENABLE = 0,
DDR3_MR1_QOFF_DISABLE = 1,
};
enum ddr3_mr1_tqds {
DDR3_MR1_TQDS_DISABLE = 0,
DDR3_MR1_TQDS_ENABLE = 1,
};
enum ddr3_mr1_write_leveling {
DDR3_MR1_WRLVL_DISABLE = 0,
DDR3_MR1_WRLVL_ENABLE = 1,
};
enum ddr3_mr1_rtt_nom {
DDR3_MR1_RTT_NOM_OFF = 0,
DDR3_MR1_RTT_NOM_RZQ4 = 1,
DDR3_MR1_RTT_NOM_RZQ2 = 2,
DDR3_MR1_RTT_NOM_RZQ6 = 3,
DDR3_MR1_RTT_NOM_RZQ12 = 4,
DDR3_MR1_RTT_NOM_RZQ8 = 5,
};
enum ddr3_mr1_additive_latency {
DDR3_MR1_AL_DISABLE = 0,
DDR3_MR1_AL_CL_MINUS_1 = 1,
DDR3_MR1_AL_CL_MINUS_2 = 2,
};
enum ddr3_mr1_ods {
DDR3_MR1_ODS_RZQ6 = 0,
DDR3_MR1_ODS_RZQ7 = 1,
};
enum ddr3_mr1_dll {
DDR3_MR1_DLL_ENABLE = 0,
DDR3_MR1_DLL_DISABLE = 1,
};

mrs_cmd_t ddr3_get_mr1(enum ddr3_mr1_qoff qoff,
enum ddr3_mr1_tqds tqds,
enum ddr3_mr1_rtt_nom rtt_nom,
enum ddr3_mr1_write_leveling write_leveling,
enum ddr3_mr1_ods output_drive_strenght,
enum ddr3_mr1_additive_latency additive_latency,
enum ddr3_mr1_dll dll_disable);

enum ddr3_mr2_rttwr {
DDR3_MR2_RTTWR_OFF = 0,
DDR3_MR2_RTTWR_RZQ4 = 1,
DDR3_MR2_RTTWR_RZQ2 = 2,
};
enum ddr3_mr2_srt_range {
DDR3_MR2_SRT_NORMAL = 0,
DDR3_MR2_SRT_EXTENDED = 1,
};
enum ddr3_mr2_asr {
DDR3_MR2_ASR_MANUAL = 0,
DDR3_MR2_ASR_AUTO = 1,
};

mrs_cmd_t ddr3_get_mr2(enum ddr3_mr2_rttwr rtt_wr,
enum ddr3_mr2_srt_range extended_temp,
enum ddr3_mr2_asr self_refresh, u8 cas_cwl);

mrs_cmd_t ddr3_get_mr3(char dataflow_from_mpr);
mrs_cmd_t ddr3_mrs_mirror_pins(mrs_cmd_t cmd);
const struct dimm_attr_ddr3_st *info);

#endif /* DEVICE_DRAM_DDR3L_H */
36 changes: 18 additions & 18 deletions src/include/device/dram/ddr4.h
Expand Up @@ -25,30 +25,30 @@
* Module type (byte 3, bits 3:0) of SPD
* This definition is specific to DDR4. DDR2/3 SPDs have a different structure.
*/
enum spd_dimm_type {
SPD_DIMM_TYPE_EXTENDED = 0x0,
SPD_DIMM_TYPE_RDIMM = 0x1,
SPD_DIMM_TYPE_UDIMM = 0x2,
SPD_DIMM_TYPE_SO_DIMM = 0x3,
SPD_DIMM_TYPE_LRDIMM = 0x4,
SPD_DIMM_TYPE_MINI_RDIMM = 0x5,
SPD_DIMM_TYPE_MINI_UDIMM = 0x6,
SPD_DIMM_TYPE_72B_SO_RDIMM = 0x8,
SPD_DIMM_TYPE_72B_SO_UDIMM = 0x9,
SPD_DIMM_TYPE_16B_SO_DIMM = 0xc,
SPD_DIMM_TYPE_32B_SO_DIMM = 0xd,
enum spd_dimm_type_ddr4 {
SPD_DDR4_DIMM_TYPE_EXTENDED = 0x0,
SPD_DDR4_DIMM_TYPE_RDIMM = 0x1,
SPD_DDR4_DIMM_TYPE_UDIMM = 0x2,
SPD_DDR4_DIMM_TYPE_SO_DIMM = 0x3,
SPD_DDR4_DIMM_TYPE_LRDIMM = 0x4,
SPD_DDR4_DIMM_TYPE_MINI_RDIMM = 0x5,
SPD_DDR4_DIMM_TYPE_MINI_UDIMM = 0x6,
SPD_DDR4_DIMM_TYPE_72B_SO_RDIMM = 0x8,
SPD_DDR4_DIMM_TYPE_72B_SO_UDIMM = 0x9,
SPD_DDR4_DIMM_TYPE_16B_SO_DIMM = 0xc,
SPD_DDR4_DIMM_TYPE_32B_SO_DIMM = 0xd,
/* Masks to bits 3:0 to give the dimm type */
SPD_DIMM_TYPE_MASK = 0xf
SPD_DDR4_DIMM_TYPE_MASK = 0xf
};

/**
* \brief DIMM characteristics
*
* The characteristics of each DIMM, as presented by the SPD
*/
typedef struct dimm_attr_st {
struct dimm_attr_ddr4_st {
enum spd_memory_type dram_type;
enum spd_dimm_type dimm_type;
enum spd_dimm_type_ddr4 dimm_type;
char part_number[SPD_DDR4_PART_LEN + 1];
u8 serial_number[4];
u8 bus_width;
Expand All @@ -59,15 +59,15 @@ typedef struct dimm_attr_st {
u16 manufacturer_id;
u16 vdd_voltage;
bool ecc_extension;
} dimm_attr;
};

typedef u8 spd_raw_data[512];

int spd_decode_ddr4(dimm_attr *dimm, spd_raw_data spd);
int spd_decode_ddr4(struct dimm_attr_ddr4_st *dimm, spd_raw_data spd);

enum cb_err spd_add_smbios17_ddr4(const u8 channel, const u8 slot,
const u16 selected_freq,
const dimm_attr *info);
const struct dimm_attr_ddr4_st *info);

/**
* Converts DDR4 clock speed in MHz to the standard reported speed in MT/s
Expand Down
2 changes: 2 additions & 0 deletions src/include/device/pci_ids.h
Expand Up @@ -3037,6 +3037,7 @@
#define PCI_DEVICE_ID_INTEL_ADP_M_ESPI_29 0x549d
#define PCI_DEVICE_ID_INTEL_ADP_M_ESPI_30 0x549e
#define PCI_DEVICE_ID_INTEL_ADP_M_ESPI_31 0x549f
#define PCI_DEVICE_ID_INTEL_ADP_M_ESPI_32 0x5186
#define PCI_DEVICE_ID_INTEL_SPR_ESPI_1 0x1b80

/* Intel PCIE device ids */
Expand Down Expand Up @@ -3808,6 +3809,7 @@
#define PCI_DEVICE_ID_INTEL_ADL_GT1_9 0x4619
#define PCI_DEVICE_ID_INTEL_ADL_P_GT2 0x46a0
#define PCI_DEVICE_ID_INTEL_ADL_S_GT1 0x4680
#define PCI_DEVICE_ID_INTEL_ADL_M_GT1 0x46c0

/* Intel Northbridge Ids */
#define PCI_DEVICE_ID_INTEL_APL_NB 0x5af0
Expand Down
4 changes: 3 additions & 1 deletion src/include/espi.h
Expand Up @@ -230,8 +230,10 @@

#if CONFIG(ESPI_DEBUG)
void espi_show_slave_general_configuration(uint32_t config);
void espi_show_slave_peripheral_channel_configuration(uint32_t config);
#else
static void espi_show_slave_general_configuration(uint32_t config) {}
static inline void espi_show_slave_general_configuration(uint32_t config) {}
static inline void espi_show_slave_peripheral_channel_configuration(uint32_t config) {}
#endif

static inline bool espi_slave_supports_quad_io(uint32_t gen_caps)
Expand Down
5 changes: 5 additions & 0 deletions src/include/metadata_hash.h
Expand Up @@ -6,6 +6,11 @@

#include <commonlib/bsd/metadata_hash.h>

/* Return a pointer to the whole anchor. Only used for decompressor builds. */
void *metadata_hash_export_anchor(void);
/* Import a pointer that points to the anchor. Only used for decompressor builds. */
void metadata_hash_import_anchor(void *ptr);

/* Verify the an FMAP data structure with the FMAP hash that is stored together with the CBFS
metadata hash in the bootblock's metadata hash anchor (when CBFS verification is enabled). */
vb2_error_t metadata_hash_verify_fmap(const void *fmap_base, size_t fmap_size);
Expand Down
16 changes: 9 additions & 7 deletions src/include/option.h
Expand Up @@ -10,20 +10,22 @@ void sanitize_cmos(void);
enum cb_err cmos_set_option(const char *name, void *val);
enum cb_err cmos_get_option(void *dest, const char *name);

static inline enum cb_err set_option(const char *name, void *val)
static inline enum cb_err set_int_option(const char *name, int value)
{
if (CONFIG(USE_OPTION_TABLE))
return cmos_set_option(name, val);
return cmos_set_option(name, &value);

return CB_CMOS_OTABLE_DISABLED;
}

static inline enum cb_err get_option(void *dest, const char *name)
static inline int get_int_option(const char *name, const int fallback)
{
if (CONFIG(USE_OPTION_TABLE))
return cmos_get_option(dest, name);

return CB_CMOS_OTABLE_DISABLED;
if (CONFIG(USE_OPTION_TABLE)) {
int value = 0;
if (cmos_get_option(&value, name) == CB_SUCCESS)
return value;
}
return fallback;
}

#endif /* _OPTION_H_ */
6 changes: 1 addition & 5 deletions src/include/program_loading.h
Expand Up @@ -91,15 +91,11 @@ static inline void *prog_entry_arg(const struct prog *prog)
return prog->arg;
}

/* region_device representing the 32-bit flat address space. */
extern const struct mem_region_device addrspace_32bit;

/* Can be used to get an rdev representation of program area in memory. */
static inline void prog_chain_rdev(const struct prog *prog,
struct region_device *rdev_out)
{
rdev_chain(rdev_out, &addrspace_32bit.rdev,
(uintptr_t)prog->start, prog->size);
rdev_chain_mem(rdev_out, prog->start, prog->size);
}

static inline void prog_set_area(struct prog *prog, void *start, size_t size)
Expand Down
6 changes: 6 additions & 0 deletions src/include/rules.h
Expand Up @@ -3,6 +3,12 @@
#ifndef _RULES_H
#define _RULES_H

#if defined(__TEST__)
#define ENV_TEST 1
#else
#define ENV_TEST 0
#endif

#if defined(__TIMELESS__)
#define ENV_TIMELESS 1
#else
Expand Down
2 changes: 1 addition & 1 deletion src/include/smbios.h
Expand Up @@ -20,7 +20,7 @@ int smbios_write_type9(unsigned long *current, int *handle,
const enum slot_data_bus_bandwidth bandwidth,
const enum misc_slot_usage usage,
const enum misc_slot_length length,
u8 slot_char1, u8 slot_char2, u8 bus, u8 dev_func);
const u16 id, u8 slot_char1, u8 slot_char2, u8 bus, u8 dev_func);
enum smbios_bmc_interface_type;
int smbios_write_type38(unsigned long *current, int *handle,
const enum smbios_bmc_interface_type interface_type,
Expand Down
76 changes: 0 additions & 76 deletions src/include/spd.h
Expand Up @@ -197,82 +197,6 @@ enum spd_memory_type {
#define MODULE_BUFFERED 1
#define MODULE_REGISTERED 2

/* DIMM SPD addresses */
#define DIMM0 0x50
#define DIMM1 0x51
#define DIMM2 0x52
#define DIMM3 0x53
#define DIMM4 0x54
#define DIMM5 0x55
#define DIMM6 0x56
#define DIMM7 0x57

#define RC00 0
#define RC01 1
#define RC02 2
#define RC03 3
#define RC04 4
#define RC05 5
#define RC06 6
#define RC07 7
#define RC08 8
#define RC09 9
#define RC10 10
#define RC11 11
#define RC12 12
#define RC13 13
#define RC14 14
#define RC15 15
#define RC16 16
#define RC17 17
#define RC18 18
#define RC19 19
#define RC20 20
#define RC21 21
#define RC22 22
#define RC23 23
#define RC24 24
#define RC25 25
#define RC26 26
#define RC27 27
#define RC28 28
#define RC29 29
#define RC30 30
#define RC31 31

#define RC32 32
#define RC33 33
#define RC34 34
#define RC35 35
#define RC36 36
#define RC37 37
#define RC38 38
#define RC39 39
#define RC40 40
#define RC41 41
#define RC42 42
#define RC43 43
#define RC44 44
#define RC45 45
#define RC46 46
#define RC47 47
#define RC48 48
#define RC49 49
#define RC50 50
#define RC51 51
#define RC52 52
#define RC53 53
#define RC54 54
#define RC55 55
#define RC56 56
#define RC57 57
#define RC58 58
#define RC59 59
#define RC60 60
#define RC61 61
#define RC62 62
#define RC63 63

/* Byte 3: Module type information */
#define SPD_UNDEFINED 0x00
#define SPD_RDIMM 0x01
Expand Down
104 changes: 0 additions & 104 deletions src/include/spd_ddr2.h

This file was deleted.

1 change: 1 addition & 0 deletions src/include/stdlib.h
Expand Up @@ -5,6 +5,7 @@

void *memalign(size_t boundary, size_t size);
void *malloc(size_t size);
void *calloc(size_t nitems, size_t size);
void free(void *ptr);

#endif /* STDLIB_H */
1 change: 0 additions & 1 deletion src/lib/Kconfig.cbfs_verification
Expand Up @@ -6,7 +6,6 @@

config CBFS_VERIFICATION
bool # TODO: make user selectable once it works
depends on !COMPRESS_BOOTBLOCK # TODO: figure out decompressor anchor
depends on !VBOOT_STARTS_BEFORE_BOOTBLOCK # this is gonna get tricky...
select VBOOT_LIB
help
Expand Down
1 change: 1 addition & 0 deletions src/lib/Makefile.inc
Expand Up @@ -38,6 +38,7 @@ decompressor-y += delay.c
decompressor-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c
decompressor-y += memchr.c
decompressor-y += memcmp.c
decompressor-$(CONFIG_CBFS_VERIFICATION) += metadata_hash.c
decompressor-y += prog_ops.c
decompressor-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c

Expand Down
3 changes: 3 additions & 0 deletions src/lib/bootblock.c
Expand Up @@ -4,6 +4,7 @@
#include <bootblock_common.h>
#include <console/console.h>
#include <delay.h>
#include <metadata_hash.h>
#include <option.h>
#include <post.h>
#include <program_loading.h>
Expand Down Expand Up @@ -88,6 +89,8 @@ void main(void)
void _start(struct bootblock_arg *arg);
void _start(struct bootblock_arg *arg)
{
if (CONFIG(CBFS_VERIFICATION))
metadata_hash_import_anchor(arg->metadata_hash_anchor);
bootblock_main_with_timestamp(arg->base_timestamp, arg->timestamps,
arg->num_timestamps);
}
Expand Down
118 changes: 68 additions & 50 deletions src/lib/cbfs.c
Expand Up @@ -89,7 +89,7 @@ int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type)
return -1;

size_t msize = be32toh(fh->mdata.h.offset);
if (rdev_chain(&fh->metadata, &addrspace_32bit.rdev, (uintptr_t)&fh->mdata, msize))
if (rdev_chain_mem(&fh->metadata, &fh->mdata, msize))
return -1;

if (type) {
Expand Down Expand Up @@ -186,35 +186,56 @@ static inline bool cbfs_lzma_enabled(void)
return true;
}

size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset, size_t in_size,
void *buffer, size_t buffer_size, uint32_t compression)
static inline bool cbfs_file_hash_mismatch(const void *buffer, size_t size,
const struct vb2_hash *file_hash)
{
size_t out_size;
/* Avoid linking hash functions when verification is disabled. */
if (!CONFIG(CBFS_VERIFICATION))
return false;

/* If there is no file hash, always count that as a mismatch. */
if (file_hash && vb2_hash_verify(buffer, size, file_hash) == VB2_SUCCESS)
return false;

printk(BIOS_CRIT, "CBFS file hash mismatch!\n");
return true;
}

static size_t cbfs_load_and_decompress(const struct region_device *rdev, void *buffer,
size_t buffer_size, uint32_t compression,
const struct vb2_hash *file_hash)
{
size_t in_size = region_device_sz(rdev);
size_t out_size = 0;
void *map;

DEBUG("Decompressing %zu bytes to %p with algo %d\n", buffer_size, buffer, compression);
DEBUG("Decompressing %zu bytes to %p with algo %d\n", in_size, buffer, compression);

switch (compression) {
case CBFS_COMPRESS_NONE:
if (buffer_size < in_size)
return 0;
if (rdev_readat(rdev, buffer, offset, in_size) != in_size)
if (rdev_readat(rdev, buffer, 0, in_size) != in_size)
return 0;
if (cbfs_file_hash_mismatch(buffer, in_size, file_hash))
return 0;
return in_size;

case CBFS_COMPRESS_LZ4:
if (!cbfs_lz4_enabled())
return 0;

/* cbfs_stage_load_and_decompress() takes care of in-place LZ4 decompression by
/* cbfs_prog_stage_load() takes care of in-place LZ4 decompression by
setting up the rdev to be in memory. */
map = rdev_mmap(rdev, offset, in_size);
map = rdev_mmap_full(rdev);
if (map == NULL)
return 0;

timestamp_add_now(TS_START_ULZ4F);
out_size = ulz4fn(map, in_size, buffer, buffer_size);
timestamp_add_now(TS_END_ULZ4F);
if (!cbfs_file_hash_mismatch(map, in_size, file_hash)) {
timestamp_add_now(TS_START_ULZ4F);
out_size = ulz4fn(map, in_size, buffer, buffer_size);
timestamp_add_now(TS_END_ULZ4F);
}

rdev_munmap(rdev, map);

Expand All @@ -223,14 +244,16 @@ size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
case CBFS_COMPRESS_LZMA:
if (!cbfs_lzma_enabled())
return 0;
map = rdev_mmap(rdev, offset, in_size);
map = rdev_mmap_full(rdev);
if (map == NULL)
return 0;

/* Note: timestamp not useful for memory-mapped media (x86) */
timestamp_add_now(TS_START_ULZMA);
out_size = ulzman(map, in_size, buffer, buffer_size);
timestamp_add_now(TS_END_ULZMA);
if (!cbfs_file_hash_mismatch(map, in_size, file_hash)) {
/* Note: timestamp not useful for memory-mapped media (x86) */
timestamp_add_now(TS_START_ULZMA);
out_size = ulzman(map, in_size, buffer, buffer_size);
timestamp_add_now(TS_END_ULZMA);
}

rdev_munmap(rdev, map);

Expand All @@ -241,33 +264,6 @@ size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
}
}

static size_t cbfs_stage_load_and_decompress(const struct region_device *rdev, size_t offset,
size_t in_size, void *buffer, size_t buffer_size, uint32_t compression)
{
struct region_device rdev_src;

if (compression == CBFS_COMPRESS_LZ4) {
if (!cbfs_lz4_enabled())
return 0;
/* Load the compressed image to the end of the available memory area for
in-place decompression. It is the responsibility of the caller to ensure that
buffer_size is large enough (see compression.h, guaranteed by cbfstool for
stages). */
void *compr_start = buffer + buffer_size - in_size;
if (rdev_readat(rdev, compr_start, offset, in_size) != in_size)
return 0;
/* Create a region device backed by memory. */
rdev_chain(&rdev_src, &addrspace_32bit.rdev, (uintptr_t)compr_start, in_size);

return cbfs_load_and_decompress(&rdev_src, 0, in_size, buffer, buffer_size,
compression);
}

/* All other algorithms can use the generic implementation. */
return cbfs_load_and_decompress(rdev, offset, in_size, buffer, buffer_size,
compression);
}

static inline int tohex4(unsigned int c)
{
return (c <= 9) ? (c + '0') : (c - 10 + 'a');
Expand Down Expand Up @@ -344,11 +340,18 @@ void *_cbfs_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
if (size_out)
*size_out = size;

const struct vb2_hash *file_hash = NULL;
if (CONFIG(CBFS_VERIFICATION))
file_hash = cbfs_file_hash(&mdata);

/* allocator == NULL means do a cbfs_map() */
if (allocator) {
loc = allocator(arg, size, &mdata);
} else if (compression == CBFS_COMPRESS_NONE) {
return rdev_mmap_full(&rdev);
void *mapping = rdev_mmap_full(&rdev);
if (!mapping || cbfs_file_hash_mismatch(mapping, size, file_hash))
return NULL;
return mapping;
} else if (!CBFS_CACHE_AVAILABLE) {
ERROR("Cannot map compressed file %s on x86\n", mdata.h.filename);
return NULL;
Expand All @@ -361,23 +364,22 @@ void *_cbfs_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
return NULL;
}

size = cbfs_load_and_decompress(&rdev, 0, region_device_sz(&rdev),
loc, size, compression);
size = cbfs_load_and_decompress(&rdev, loc, size, compression, file_hash);
if (!size)
return NULL;

return loc;
}

void *_cbfs_default_allocator(void *arg, size_t size, union cbfs_mdata *unused)
void *_cbfs_default_allocator(void *arg, size_t size, const union cbfs_mdata *unused)
{
struct _cbfs_default_allocator_arg *darg = arg;
if (size > darg->buf_size)
return NULL;
return darg->buf;
}

void *_cbfs_cbmem_allocator(void *arg, size_t size, union cbfs_mdata *unused)
void *_cbfs_cbmem_allocator(void *arg, size_t size, const union cbfs_mdata *unused)
{
return cbmem_add((uintptr_t)arg, size);
}
Expand Down Expand Up @@ -411,18 +413,34 @@ cb_err_t cbfs_prog_stage_load(struct prog *pstage)
prog_set_entry(pstage, prog_start(pstage) +
be32toh(sattr->entry_offset), NULL);

const struct vb2_hash *file_hash = NULL;
if (CONFIG(CBFS_VERIFICATION))
file_hash = cbfs_file_hash(&mdata);

/* Hacky way to not load programs over read only media. The stages
* that would hit this path initialize themselves. */
if ((ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE) &&
!CONFIG(NO_XIP_EARLY_STAGES) && CONFIG(BOOT_DEVICE_MEMORY_MAPPED)) {
void *mapping = rdev_mmap_full(&rdev);
rdev_munmap(&rdev, mapping);
if (cbfs_file_hash_mismatch(mapping, region_device_sz(&rdev), file_hash))
return CB_CBFS_HASH_MISMATCH;
if (mapping == prog_start(pstage))
return CB_SUCCESS;
}

size_t fsize = cbfs_stage_load_and_decompress(&rdev, 0, region_device_sz(&rdev),
prog_start(pstage), prog_size(pstage), compression);
/* LZ4 stages can be decompressed in-place to save mapping scratch space. Load the
compressed data to the end of the buffer and point &rdev to that memory location. */
if (cbfs_lz4_enabled() && compression == CBFS_COMPRESS_LZ4) {
size_t in_size = region_device_sz(&rdev);
void *compr_start = prog_start(pstage) + prog_size(pstage) - in_size;
if (rdev_readat(&rdev, compr_start, 0, in_size) != in_size)
return CB_ERR;
rdev_chain_mem(&rdev, compr_start, in_size);
}

size_t fsize = cbfs_load_and_decompress(&rdev, prog_start(pstage), prog_size(pstage),
compression, file_hash);
if (!fsize)
return CB_ERR;

Expand Down