| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| # ASRock H77 Pro4-M | ||
|
|
||
| The ASRock H77 Pro4-M is a microATX-sized desktop board for Intel Sandy | ||
| Bridge and Ivy Bridge CPUs. | ||
|
|
||
| ## Technology | ||
|
|
||
| ```eval_rst | ||
| +------------------+--------------------------------------------------+ | ||
| | Northbridge | :doc:`../../northbridge/intel/sandybridge/index` | | ||
| +------------------+--------------------------------------------------+ | ||
| | Southbridge | Intel H77 (bd82x6x) | | ||
| +------------------+--------------------------------------------------+ | ||
| | CPU socket | LGA 1155 | | ||
| +------------------+--------------------------------------------------+ | ||
| | RAM | 4 x DDR3-1600 | | ||
| +------------------+--------------------------------------------------+ | ||
| | Super I/O | Nuvoton NCT6776 | | ||
| +------------------+--------------------------------------------------+ | ||
| | Audio | Realtek ALC892 | | ||
| +------------------+--------------------------------------------------+ | ||
| | Network | Realtek RTL8111E | | ||
| +------------------+--------------------------------------------------+ | ||
| | Serial | Internal header (RS-232) | | ||
| +------------------+--------------------------------------------------+ | ||
| ``` | ||
|
|
||
| ## Status | ||
|
|
||
| Tests were done with SeaBIOS 1.14.0 and slackware64-live from 2019-07-12 | ||
| (linux-4.19.50). | ||
|
|
||
| ### Working | ||
|
|
||
| - Sandy Bridge and Ivy Bridge CPUs (tested: i5-2500, Pentium G2120) | ||
| - Native RAM initialization with four DIMMs | ||
| - PS/2 combined port (mouse or keyboard) | ||
| - Integrated GPU by libgfxinit on all monitor ports (DVI-D, HDMI, D-Sub) | ||
| - PCIe graphics in the PEG slot | ||
| - All three additional PCIe slots | ||
| - All rear and internal USB2 ports | ||
| - All rear and internal USB3 ports | ||
| - All six SATA ports from the PCH (two 6 Gb/s, four 3 Gb/s) | ||
| - All two SATA ports from the ASM1061 PCIe-to-SATA bridge (6 Gb/s) | ||
| - Rear eSATA connector (multiplexed with one ASM1061 port) | ||
| - Gigabit Ethernet | ||
| - Console output on the serial port | ||
| - SeaBIOS 1.14.0 and 1.15.0 to boot Windows 10 (needs VGA BIOS) and Linux via | ||
| extlinux | ||
| - Internal flashing with flashrom-1.2, see | ||
| [Internal Programming](#internal-programming) | ||
| - External flashing with flashrom-1.2 and a Raspberry Pi 1 | ||
| - S3 suspend/resume from either Linux or Windows 10 | ||
| - Poweroff | ||
|
|
||
| ### Not working | ||
|
|
||
| - Booting from the two SATA ports provided by the ASM1061 | ||
| - Automatic fan control with the NCT6776D Super I/O | ||
|
|
||
| ### Untested | ||
|
|
||
| - EHCI debug | ||
| - S/PDIF audio | ||
| - Other audio jacks than the green one, and the front panel header | ||
| - Parallel port | ||
| - Infrared/CIR | ||
| - Wakeup from anything but the power button | ||
|
|
||
| ## Flashing coreboot | ||
|
|
||
| ```eval_rst | ||
| +---------------------+------------+ | ||
| | Type | Value | | ||
| +=====================+============+ | ||
| | Socketed flash | yes | | ||
| +---------------------+------------+ | ||
| | Model | W25Q64.V | | ||
| +---------------------+------------+ | ||
| | Size | 8 MiB | | ||
| +---------------------+------------+ | ||
| | Package | DIP-8 | | ||
| +---------------------+------------+ | ||
| | Write protection | no | | ||
| +---------------------+------------+ | ||
| | Dual BIOS feature | no | | ||
| +---------------------+------------+ | ||
| | Internal flashing | yes | | ||
| +---------------------+------------+ | ||
| ``` | ||
|
|
||
| The flash is divided into the following regions, as obtained with | ||
| `ifdtool -f rom.layout backup.rom`: | ||
| ``` | ||
| 00000000:00000fff fd | ||
| 00200000:007fffff bios | ||
| 00001000:001fffff me | ||
| ``` | ||
|
|
||
| ### Internal programming | ||
|
|
||
| The main SPI flash can be accessed using flashrom. By default, only | ||
| the BIOS region of the flash is writable. If you wish to change any | ||
| other region (Management Engine or flash descriptor), then an external | ||
| programmer is required. | ||
|
|
||
| The following command may be used to flash coreboot: | ||
|
|
||
| ``` | ||
| $ sudo flashrom --noverify-all --ifd -i bios -p internal -w coreboot.rom | ||
| ``` | ||
|
|
||
| The use of `--noverify-all` is required since the Management Engine | ||
| region is not readable even by the host. | ||
|
|
||
| ```eval_rst | ||
| In addition to the information here, please see the | ||
| :doc:`../../flash_tutorial/index`. | ||
| ``` | ||
|
|
||
| ## Hardware monitoring and fan control | ||
|
|
||
| There are two fan headers for the CPU cooler, CPU_FAN1 and CPU_FAN2. They share | ||
| a single fan tachometer input on the Super I/O while some dedicated logic | ||
| selects which one is allowed to reach it. Two GPIO pins on the Super I/O are | ||
| used to control that logic. The firmware has to set them; coreboot selects | ||
| CPU_FAN1 by default, but the user can change that setting if it was built with | ||
| CONFIG_USE_OPTION_TABLE: | ||
|
|
||
| ``` | ||
| $ sudo nvramtool -e cpu_fan_header | ||
| [..] | ||
| $ sudo nvramtool -w cpu_fan_header=CPU_FAN2 | ||
| $ sudo nvramtool -w cpu_fan_header=None | ||
| $ sudo nvramtool -w cpu_fan_header=Both | ||
| ``` | ||
|
|
||
| The setting will take effect after a reboot. Selecting and connecting both fan | ||
| headers is possible but the Super I/O will report wrong fan speeds. | ||
|
|
||
| Currently there is no automatic, OS-independent fan control, but a software | ||
| like `fancontrol` from the lm-sensors package can be used instead. | ||
|
|
||
| ## Serial port header | ||
|
|
||
| Serial port 1, provided by the Super I/O, is exposed on a pin header. The | ||
| RS-232 signals are assigned to the header so that its pin numbers map directly | ||
| to the pin numbers of a DE-9 connector. If your serial port doesn't seem to | ||
| work, check if your bracket expects a different assignment. Also don't try to | ||
| connect it directly to a device that operates at TTL levels - it would need a | ||
| level converter like a MAX232. | ||
|
|
||
| Here is a top view of the serial port header found on this board: | ||
|
|
||
| +---+---+ | ||
| N/C | | 9 | RI -> pin 9 | ||
| +---+---+ | ||
| Pin 8 <- CTS | 8 | 7 | RTS -> pin 7 | ||
| +---+---+ | ||
| Pin 6 <- DSR | 6 | 5 | GND -> pin 5 | ||
| +---+---+ | ||
| Pin 4 <- DTR | 4 | 3 | TxD -> pin 3 | ||
| +---+---+ | ||
| Pin 2 <- RxD | 2 | 1 | DCD -> pin 1 | ||
| +---+---+ | ||
|
|
||
| ## eSATA | ||
|
|
||
| The eSATA port on the rear I/O panel and the internal connector SATA3_A1 share | ||
| the same controller port on the ASM1061. Attaching an eSATA drive causes a | ||
| multiplexer chip to disconnect the internal port from the SATA controller and | ||
| connect the eSATA port instead. This can be seen on GP23 of the Super I/O | ||
| GPIOs: it is '0' when something is connected to the eSATA port and '1' | ||
| otherwise. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Config to build test some optional Kconfigs on an Arm platform | ||
| CONFIG_USE_BLOBS=y | ||
| CONFIG_USE_QC_BLOBS=y | ||
| CONFIG_VENDOR_GOOGLE=y | ||
| CONFIG_BOARD_GOOGLE_TROGDOR=y | ||
| CONFIG_CBFS_VERIFICATION=y | ||
| CONFIG_TPM_MEASURED_BOOT=y | ||
| CONFIG_PAYLOAD_NONE=y |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Settings used by Prodrive to build coreboot for the Hermes | ||
| CONFIG_VENDOR_PRODRIVE=y | ||
| CONFIG_BOARD_PRODRIVE_HERMES=y | ||
| CONFIG_MAINBOARD_SMBIOS_MANUFACTURER="Prodrive Techonologies B.V." | ||
| CONFIG_POST_IO=y | ||
| CONFIG_USE_LEGACY_8254_TIMER=y | ||
| CONFIG_HERMES_USES_SPS_FIRMWARE=y | ||
| CONFIG_GENERIC_LINEAR_FRAMEBUFFER=y | ||
| CONFIG_SMMSTORE=y | ||
| CONFIG_SMMSTORE_V2=y | ||
| CONFIG_DEFAULT_CONSOLE_LOGLEVEL_3=y | ||
| CONFIG_POST_DEVICE_LPC=y | ||
| CONFIG_MAINBOARD_SERIAL_NUMBER="N/A" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,82 +1,146 @@ | ||
| /* SPDX-License-Identifier: BSD-3-Clause */ | ||
|
|
||
| #ifndef _CBFS_H_ | ||
| #define _CBFS_H_ | ||
|
|
||
| #include <commonlib/bsd/cb_err.h> | ||
| #include <commonlib/bsd/cbfs_mdata.h> | ||
| #include <endian.h> | ||
| #include <stdbool.h> | ||
|
|
||
|
|
||
| /********************************************************************************************** | ||
| * CBFS FILE ACCESS APIs * | ||
| **********************************************************************************************/ | ||
|
|
||
| /* For documentation look in src/include/cbfs.h file in the main coreboot source tree. */ | ||
|
|
||
| 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); | ||
| static inline size_t cbfs_unverified_area_load(const char *area, const char *name, void *buf, | ||
| size_t size); | ||
|
|
||
| static inline void *cbfs_map(const char *name, size_t *size_out); | ||
| static inline void *cbfs_ro_map(const char *name, size_t *size_out); | ||
| static inline void *cbfs_unverified_area_map(const char *area, const char *name, | ||
| size_t *size_out); | ||
|
|
||
| void cbfs_unmap(void *mapping); | ||
|
|
||
| static inline size_t cbfs_get_size(const char *name); | ||
| static inline size_t cbfs_ro_get_size(const char *name); | ||
|
|
||
| static inline enum cbfs_type cbfs_get_type(const char *name); | ||
| static inline enum cbfs_type cbfs_ro_get_type(const char *name); | ||
|
|
||
| static inline bool cbfs_file_exists(const char *name); | ||
| static inline bool cbfs_ro_file_exists(const char *name); | ||
|
|
||
| /********************************************************************************************** | ||
| * INTERNAL HELPERS FOR INLINES, DO NOT USE. * | ||
| **********************************************************************************************/ | ||
| ssize_t _cbfs_boot_lookup(const char *name, bool force_ro, union cbfs_mdata *mdata); | ||
|
|
||
| void *_cbfs_load(const char *name, void *buf, size_t *size_inout, bool force_ro); | ||
|
|
||
| void *_cbfs_unverified_area_load(const char *area, const char *name, void *buf, | ||
| size_t *size_inout); | ||
|
|
||
| /********************************************************************************************** | ||
| * INLINE IMPLEMENTATIONS * | ||
| **********************************************************************************************/ | ||
|
|
||
| static inline void *cbfs_map(const char *name, size_t *size_out) | ||
| { | ||
| return _cbfs_load(name, NULL, size_out, false); | ||
| } | ||
|
|
||
| static inline void *cbfs_ro_map(const char *name, size_t *size_out) | ||
| { | ||
| return _cbfs_load(name, NULL, size_out, true); | ||
| } | ||
|
|
||
| static inline void *cbfs_unverified_area_map(const char *area, const char *name, | ||
| size_t *size_out) | ||
| { | ||
| return _cbfs_unverified_area_load(area, name, NULL, size_out); | ||
| } | ||
|
|
||
| static inline size_t cbfs_load(const char *name, void *buf, size_t size) | ||
| { | ||
| if (_cbfs_load(name, buf, &size, false)) | ||
| return size; | ||
| else | ||
| return 0; | ||
| } | ||
|
|
||
| static inline size_t cbfs_ro_load(const char *name, void *buf, size_t size) | ||
| { | ||
| if (_cbfs_load(name, buf, &size, true)) | ||
| return size; | ||
| else | ||
| return 0; | ||
| } | ||
|
|
||
| static inline size_t cbfs_unverified_area_load(const char *area, const char *name, void *buf, | ||
| size_t size) | ||
| { | ||
| if (_cbfs_unverified_area_load(area, name, buf, &size)) | ||
| return size; | ||
| else | ||
| return 0; | ||
| } | ||
|
|
||
| static inline size_t cbfs_get_size(const char *name) | ||
| { | ||
| union cbfs_mdata mdata; | ||
| if (_cbfs_boot_lookup(name, false, &mdata) < 0) | ||
| return 0; | ||
| else | ||
| return be32toh(mdata.h.len); | ||
| } | ||
|
|
||
| static inline size_t cbfs_ro_get_size(const char *name) | ||
| { | ||
| union cbfs_mdata mdata; | ||
| if (_cbfs_boot_lookup(name, true, &mdata) < 0) | ||
| return 0; | ||
| else | ||
| return be32toh(mdata.h.len); | ||
| } | ||
|
|
||
| static inline enum cbfs_type cbfs_get_type(const char *name) | ||
| { | ||
| union cbfs_mdata mdata; | ||
| if (_cbfs_boot_lookup(name, false, &mdata) < 0) | ||
| return CBFS_TYPE_NULL; | ||
| else | ||
| return be32toh(mdata.h.type); | ||
| } | ||
|
|
||
| static inline enum cbfs_type cbfs_ro_get_type(const char *name) | ||
| { | ||
| union cbfs_mdata mdata; | ||
| if (_cbfs_boot_lookup(name, true, &mdata) < 0) | ||
| return CBFS_TYPE_NULL; | ||
| else | ||
| return be32toh(mdata.h.type); | ||
| } | ||
|
|
||
| static inline bool cbfs_file_exists(const char *name) | ||
| { | ||
| union cbfs_mdata mdata; | ||
| return _cbfs_boot_lookup(name, false, &mdata) >= 0; | ||
| } | ||
|
|
||
| static inline bool cbfs_ro_file_exists(const char *name) | ||
| { | ||
| union cbfs_mdata mdata; | ||
| return _cbfs_boot_lookup(name, true, &mdata) >= 0; | ||
| } | ||
|
|
||
|
|
||
| /* Legacy API. Designated for removal in the future. */ | ||
| #include <cbfs_legacy.h> | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /* SPDX-License-Identifier: BSD-3-Clause */ | ||
|
|
||
| #ifndef _CBFS_CBFS_GLUE_H | ||
| #define _CBFS_CBFS_GLUE_H | ||
|
|
||
| #include <libpayload-config.h> | ||
| #include <boot_device.h> | ||
| #include <stdio.h> | ||
|
|
||
| #define CBFS_ENABLE_HASHING CONFIG(LP_CBFS_VERIFICATION) | ||
|
|
||
| #define ERROR(...) printf("CBFS ERROR: " __VA_ARGS__) | ||
| #define LOG(...) printf("CBFS: " __VA_ARGS__) | ||
| #define DEBUG(...) \ | ||
| do { \ | ||
| if (CONFIG(LP_DEBUG_CBFS)) \ | ||
| printf("CBFS DEBUG: " __VA_ARGS__); \ | ||
| } while (0) | ||
|
|
||
| struct cbfs_dev { | ||
| size_t offset; | ||
| size_t size; | ||
| }; | ||
|
|
||
| struct cbfs_boot_device { | ||
| struct cbfs_dev dev; | ||
| void *mcache; | ||
| size_t mcache_size; | ||
| }; | ||
|
|
||
| typedef const struct cbfs_dev *cbfs_dev_t; | ||
|
|
||
| static inline ssize_t cbfs_dev_read(cbfs_dev_t dev, void *buffer, size_t offset, size_t size) | ||
| { | ||
| if (offset + size < offset || offset + size > dev->size) | ||
| return CB_ERR_ARG; | ||
|
|
||
| return boot_device_read(buffer, dev->offset + offset, size); | ||
| } | ||
|
|
||
| static inline size_t cbfs_dev_size(cbfs_dev_t dev) | ||
| { | ||
| return dev->size; | ||
| } | ||
|
|
||
| #endif /* _CBFS_CBFS_GLUE_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /* | ||
| * | ||
| * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net> | ||
| * Copyright (C) 2013 Google, Inc. | ||
| * | ||
| * This file is dual-licensed. You can choose between: | ||
| * - The GNU GPL, version 2, as published by the Free Software Foundation | ||
| * - The revised BSD license (without advertising clause) | ||
| * | ||
| * --------------------------------------------------------------------------- | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation; version 2 of the License. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * --------------------------------------------------------------------------- | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. The name of the author may not be used to endorse or promote products | ||
| * derived from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| * SUCH DAMAGE. | ||
| * --------------------------------------------------------------------------- | ||
| */ | ||
|
|
||
| #ifndef _CBFS_LEGACY_H_ | ||
| #define _CBFS_LEGACY_H_ | ||
|
|
||
| #include <cbfs_core.h> | ||
|
|
||
| /* legacy APIs */ | ||
| const struct cbfs_header *get_cbfs_header(void); | ||
| struct cbfs_file *cbfs_find(const char *name); | ||
| void *cbfs_find_file(const char *name, int type); | ||
|
|
||
| int cbfs_execute_stage(struct cbfs_media *media, const char *name); | ||
| void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, | ||
| uint16_t device); | ||
| void *cbfs_load_payload(struct cbfs_media *media, const char *name); | ||
| void *cbfs_load_stage(struct cbfs_media *media, const char *name); | ||
|
|
||
| /* Simple buffer for streaming media. */ | ||
| struct cbfs_simple_buffer { | ||
| char *buffer; | ||
| size_t allocated; | ||
| size_t size; | ||
| size_t last_allocate; | ||
| }; | ||
|
|
||
| void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer, | ||
| struct cbfs_media *media, | ||
| size_t offset, size_t count); | ||
|
|
||
| void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer, | ||
| const void *address); | ||
|
|
||
| // Utility functions | ||
| int run_address(void *f); | ||
|
|
||
| /* Defined in individual arch / board implementation. */ | ||
| int init_default_cbfs_media(struct cbfs_media *media); | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| /* SPDX_License-Identifier: BSD-3-Clause */ | ||
|
|
||
| #ifndef _FMAP_H | ||
| #define _FMAP_H | ||
|
|
||
| #include <commonlib/bsd/cb_err.h> | ||
| #include <stddef.h> | ||
|
|
||
| /* Looks for area with |name| in FlashMap. Requires lib_sysinfo.fmap_cache. */ | ||
| cb_err_t fmap_locate_area(const char *name, size_t *offset, size_t *size); | ||
|
|
||
| #endif /* _FMAP_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| ## SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later | ||
|
|
||
| config CBFS | ||
| bool "CBFS support" | ||
| default y | ||
| help | ||
| CBFS is the archive format of coreboot | ||
|
|
||
| if CBFS | ||
|
|
||
| config DEBUG_CBFS | ||
| bool "Output verbose CBFS debug messages" | ||
| default n | ||
| help | ||
| This option enables additional CBFS related debug messages. | ||
|
|
||
| config ENABLE_CBFS_FALLBACK | ||
| bool "Fallback to RO (COREBOOT) region" | ||
| default n | ||
| help | ||
| When this option is enabled, the CBFS code will look for a file in the | ||
| RO (COREBOOT) region, if it isn't available in the active RW region. | ||
| This option makes sense only if CONFIG_VBOOT was enabled in the coreboot. | ||
|
|
||
| config CBFS_VERIFICATION | ||
| bool "Enable CBFS verification" | ||
| depends on VBOOT_LIB | ||
| help | ||
| This option enables hash verification of CBFS files in RO (COREBOOT) and RW regions. | ||
|
|
||
| endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,243 @@ | ||
| /* | ||
| * | ||
| * Copyright (C) 2011 secunet Security Networks AG | ||
| * Copyright (C) 2013 Google, Inc. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. The name of the author may not be used to endorse or promote products | ||
| * derived from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| * SUCH DAMAGE. | ||
| */ | ||
| #define LIBPAYLOAD | ||
|
|
||
| #ifdef LIBPAYLOAD | ||
| # include <libpayload-config.h> | ||
| # if CONFIG(LP_LZMA) | ||
| # include <lzma.h> | ||
| # define CBFS_CORE_WITH_LZMA | ||
| # endif | ||
| # if CONFIG(LP_LZ4) | ||
| # include <lz4.h> | ||
| # define CBFS_CORE_WITH_LZ4 | ||
| # endif | ||
| # define CBFS_MINI_BUILD | ||
| #elif defined(__SMM__) | ||
| # define CBFS_MINI_BUILD | ||
| #else | ||
| # define CBFS_CORE_WITH_LZMA | ||
| # define CBFS_CORE_WITH_LZ4 | ||
| # include <lib.h> | ||
| #endif | ||
|
|
||
| #include <cbfs.h> | ||
| #include <string.h> | ||
|
|
||
| #ifdef LIBPAYLOAD | ||
| # include <stdio.h> | ||
| # define DEBUG(x...) | ||
| # define LOG(x...) | ||
| # define ERROR(x...) printf(x) | ||
| #else | ||
| # include <console/console.h> | ||
| # define ERROR(x...) printk(BIOS_ERR, "CBFS: " x) | ||
| # define LOG(x...) printk(BIOS_INFO, "CBFS: " x) | ||
| # if CONFIG_LP_DEBUG_CBFS | ||
| # define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x) | ||
| # else | ||
| # define DEBUG(x...) | ||
| # endif | ||
| #endif | ||
|
|
||
| #include "cbfs_core.c" | ||
|
|
||
| #ifndef __SMM__ | ||
| static inline int tohex4(unsigned int c) | ||
| { | ||
| return (c <= 9) ? (c + '0') : (c - 10 + 'a'); | ||
| } | ||
|
|
||
| static void tohex16(unsigned int val, char* dest) | ||
| { | ||
| dest[0] = tohex4(val>>12); | ||
| dest[1] = tohex4((val>>8) & 0xf); | ||
| dest[2] = tohex4((val>>4) & 0xf); | ||
| dest[3] = tohex4(val & 0xf); | ||
| } | ||
|
|
||
| void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, | ||
| uint16_t device) | ||
| { | ||
| char name[17] = "pciXXXX,XXXX.rom"; | ||
|
|
||
| tohex16(vendor, name+3); | ||
| tohex16(device, name+8); | ||
|
|
||
| return cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL); | ||
| } | ||
|
|
||
| void * cbfs_load_stage(struct cbfs_media *media, const char *name) | ||
| { | ||
| struct cbfs_stage *stage = (struct cbfs_stage *) | ||
| cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL); | ||
| /* this is a mess. There is no ntohll. */ | ||
| /* for now, assume compatible byte order until we solve this. */ | ||
| uintptr_t entry; | ||
| uint32_t final_size; | ||
|
|
||
| if (stage == NULL) | ||
| return (void *) -1; | ||
|
|
||
| LOG("loading stage %s @ %p (%d bytes), entry @ 0x%llx\n", | ||
| name, | ||
| (void*)(uintptr_t) stage->load, stage->memlen, | ||
| stage->entry); | ||
|
|
||
| final_size = cbfs_decompress(stage->compression, | ||
| ((unsigned char *) stage) + | ||
| sizeof(struct cbfs_stage), | ||
| stage->len, | ||
| (void *) (uintptr_t) stage->load, | ||
| stage->memlen); | ||
| if (!final_size) { | ||
| entry = -1; | ||
| goto out; | ||
| } | ||
|
|
||
| memset((void *)((uintptr_t)stage->load + final_size), 0, | ||
| stage->memlen - final_size); | ||
|
|
||
| DEBUG("stage loaded.\n"); | ||
|
|
||
| entry = stage->entry; | ||
| // entry = ntohll(stage->entry); | ||
|
|
||
| out: | ||
| free(stage); | ||
| return (void *) entry; | ||
| } | ||
|
|
||
| int cbfs_execute_stage(struct cbfs_media *media, const char *name) | ||
| { | ||
| struct cbfs_stage *stage = (struct cbfs_stage *) | ||
| cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL); | ||
|
|
||
| if (stage == NULL) | ||
| return 1; | ||
|
|
||
| if (ntohl(stage->compression) != CBFS_COMPRESS_NONE) { | ||
| LOG("Unable to run %s: Compressed file" | ||
| "Not supported for in-place execution\n", name); | ||
| free(stage); | ||
| return 1; | ||
| } | ||
|
|
||
| LOG("run @ %p\n", (void *) (uintptr_t)ntohll(stage->entry)); | ||
| int result = run_address((void *)(uintptr_t)ntohll(stage->entry)); | ||
| free(stage); | ||
| return result; | ||
| } | ||
|
|
||
| void *cbfs_load_payload(struct cbfs_media *media, const char *name) | ||
| { | ||
| return (struct cbfs_payload *)cbfs_get_file_content( | ||
| media, name, CBFS_TYPE_SELF, NULL); | ||
| } | ||
|
|
||
| struct cbfs_file *cbfs_find(const char *name) { | ||
| struct cbfs_handle *handle = cbfs_get_handle(CBFS_DEFAULT_MEDIA, name); | ||
| struct cbfs_media *m = &handle->media; | ||
| void *ret; | ||
|
|
||
| if (!handle) | ||
| return NULL; | ||
|
|
||
| ret = m->map(m, handle->media_offset, | ||
| handle->content_offset + handle->content_size); | ||
| if (ret == CBFS_MEDIA_INVALID_MAP_ADDRESS) { | ||
| free(handle); | ||
| return NULL; | ||
| } | ||
|
|
||
| free(handle); | ||
| return ret; | ||
| } | ||
|
|
||
| void *cbfs_find_file(const char *name, int type) { | ||
| return cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type, NULL); | ||
| } | ||
|
|
||
| const struct cbfs_header *get_cbfs_header(void) { | ||
| return cbfs_get_header(CBFS_DEFAULT_MEDIA); | ||
| } | ||
|
|
||
| /* Simple buffer */ | ||
|
|
||
| void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer, | ||
| struct cbfs_media *media, | ||
| size_t offset, size_t count) { | ||
| void *address = buffer->buffer + buffer->allocated; | ||
| DEBUG("simple_buffer_map(offset=%zu, count=%zu): " | ||
| "allocated=%zu, size=%zu, last_allocate=%zu\n", | ||
| offset, count, buffer->allocated, buffer->size, | ||
| buffer->last_allocate); | ||
| if (buffer->allocated + count >= buffer->size) | ||
| return CBFS_MEDIA_INVALID_MAP_ADDRESS; | ||
| if (media->read(media, address, offset, count) != count) { | ||
| ERROR("simple_buffer: fail to read %zd bytes from 0x%zx\n", | ||
| count, offset); | ||
| return CBFS_MEDIA_INVALID_MAP_ADDRESS; | ||
| } | ||
| buffer->allocated += count; | ||
| buffer->last_allocate = count; | ||
| return address; | ||
| } | ||
|
|
||
| void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer, | ||
| const void *address) { | ||
| // TODO Add simple buffer management so we can free more than last | ||
| // allocated one. | ||
| DEBUG("simple_buffer_unmap(address=%p): " | ||
| "allocated=%zu, size=%zu, last_allocate=%zu\n", | ||
| address, buffer->allocated, buffer->size, | ||
| buffer->last_allocate); | ||
| if ((buffer->buffer + buffer->allocated - buffer->last_allocate) == | ||
| address) { | ||
| buffer->allocated -= buffer->last_allocate; | ||
| buffer->last_allocate = 0; | ||
| } | ||
| return NULL; | ||
| } | ||
|
|
||
| /** | ||
| * run_address is passed the address of a function taking no parameters and | ||
| * jumps to it, returning the result. | ||
| * @param f the address to call as a function. | ||
| * @return value returned by the function. | ||
| */ | ||
|
|
||
| int run_address(void *f) | ||
| { | ||
| int (*v) (void); | ||
| v = f; | ||
| return v(); | ||
| } | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
| #ifndef MOCKS_CBFS_UTIL_H | ||
| #define MOCKS_CBFS_UTIL_H | ||
|
|
||
| #include <cbfs.h> | ||
| #include <stddef.h> | ||
| #include <tests/test.h> | ||
|
|
||
| #define BE32(be32) EMPTY_WRAP(\ | ||
| ((be32) >> 24) & 0xff, ((be32) >> 16) & 0xff, \ | ||
| ((be32) >> 8) & 0xff, ((be32) >> 0) & 0xff) | ||
|
|
||
| #define BE64(be64) EMPTY_WRAP( \ | ||
| BE32(((be64) >> 32) & 0xFFFFFFFF), \ | ||
| BE32(((be64) >> 0) & 0xFFFFFFFF)) | ||
|
|
||
| #define LE32(val32) EMPTY_WRAP(\ | ||
| ((val32) >> 0) & 0xff, ((val32) >> 8) & 0xff, \ | ||
| ((val32) >> 16) & 0xff, ((val32) >> 24) & 0xff) | ||
|
|
||
| #define LE64(val64) EMPTY_WRAP( \ | ||
| BE32(((val64) >> 0) & 0xFFFFFFFF), \ | ||
| BE32(((val64) >> 32) & 0xFFFFFFFF)) | ||
|
|
||
| #define FILENAME_SIZE 16 | ||
|
|
||
| struct cbfs_test_file { | ||
| struct cbfs_file header; | ||
| u8 filename[FILENAME_SIZE]; | ||
| u8 attrs_and_data[200]; | ||
| }; | ||
|
|
||
| #define TEST_MCACHE_SIZE (2 * MiB) | ||
|
|
||
| #define HEADER_INITIALIZER(ftype, attr_len, file_len) { \ | ||
| .magic = CBFS_FILE_MAGIC, \ | ||
| .len = htobe32(file_len), \ | ||
| .type = htobe32(ftype), \ | ||
| .attributes_offset = \ | ||
| htobe32(attr_len ? sizeof(struct cbfs_file) + FILENAME_SIZE : 0), \ | ||
| .offset = htobe32(sizeof(struct cbfs_file) + FILENAME_SIZE + attr_len), \ | ||
| } | ||
|
|
||
| #define HASH_ATTR_SIZE (offsetof(struct cbfs_file_attr_hash, hash.raw) + VB2_SHA256_DIGEST_SIZE) | ||
|
|
||
| /* This macro basically does nothing but suppresses linter messages */ | ||
| #define EMPTY_WRAP(...) __VA_ARGS__ | ||
|
|
||
| #define TEST_DATA_1_FILENAME "test/data/1" | ||
| #define TEST_DATA_1_SIZE sizeof((u8[]){TEST_DATA_1}) | ||
| #define TEST_DATA_1 EMPTY_WRAP( \ | ||
| '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', \ | ||
| '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', \ | ||
| 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', \ | ||
| 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', \ | ||
| '[', '\\', ']', '^', '_', '`', \ | ||
| 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', \ | ||
| 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z') | ||
|
|
||
| #define TEST_DATA_2_FILENAME "test/data/2" | ||
| #define TEST_DATA_2_SIZE sizeof((u8[]){TEST_DATA_2}) | ||
| #define TEST_DATA_2 EMPTY_WRAP( \ | ||
| 0x9d, 0xa9, 0x91, 0xac, 0x5d, 0xb2, 0x70, 0x76, 0x37, 0x94, 0x94, 0xa8, 0x8b, 0x78, \ | ||
| 0xb9, 0xaa, 0x1a, 0x8e, 0x9a, 0x16, 0xbe, 0xdc, 0x29, 0x42, 0x46, 0x58, 0xd4, 0x37, \ | ||
| 0x94, 0xca, 0x05, 0xdb, 0x54, 0xfa, 0xd8, 0x6e, 0x54, 0xd8, 0x30, 0x46, 0x5d, 0x62, \ | ||
| 0xc2, 0xce, 0xd8, 0x74, 0x60, 0xaf, 0x83, 0x8f, 0xfa, 0x97, 0xdd, 0x6e, 0xcb, 0x60, \ | ||
| 0xfa, 0xed, 0x8b, 0x55, 0x9e, 0xc1, 0xc2, 0x18, 0x4f, 0xe2, 0x28, 0x7e, 0xd7, 0x2f, \ | ||
| 0xa2, 0x86, 0xfb, 0x4d, 0x3e, 0x00, 0x5a, 0xf7, 0xc2, 0xad, 0x0e, 0xa7, 0xa2, 0xf7, \ | ||
| 0x38, 0x66, 0xe6, 0x5c, 0x76, 0x98, 0x89, 0x63, 0xeb, 0xc5, 0xf5, 0xb7, 0xa7, 0x58, \ | ||
| 0xe0, 0xf0, 0x2e, 0x2f, 0xb0, 0x95, 0xb7, 0x43, 0x28, 0x19, 0x2d, 0xef, 0x1a, 0xb3, \ | ||
| 0x42, 0x31, 0x55, 0x0f, 0xbc, 0xcd, 0x01, 0xe5, 0x39, 0x18, 0x88, 0x83, 0xb2, 0xc5, \ | ||
| 0x4b, 0x3b, 0x38, 0xe7) | ||
|
|
||
| #define TEST_DATA_INT_1_FILENAME "test-int-1" | ||
| #define TEST_DATA_INT_1_SIZE 8 | ||
| #define TEST_DATA_INT_1 0xFEDCBA9876543210ULL | ||
|
|
||
| #define TEST_DATA_INT_2_FILENAME "test-int-2" | ||
| #define TEST_DATA_INT_2_SIZE 8 | ||
| #define TEST_DATA_INT_2 0x10FE32DC54A97698ULL | ||
|
|
||
| #define TEST_DATA_INT_3_FILENAME "test-int-3" | ||
| #define TEST_DATA_INT_3_SIZE 8 | ||
| #define TEST_DATA_INT_3 0xFA57F003B0036667ULL | ||
|
|
||
| #define TEST_SHA256 \ | ||
| EMPTY_WRAP(0xef, 0xc7, 0xb1, 0x0a, 0xbf, 0x54, 0x2f, 0xaa, 0x12, 0xa6, 0xeb, 0xf, \ | ||
| 0xff, 0xf4, 0x19, 0xc1, 0x63, 0xf4, 0x60, 0x50, 0xc5, 0xb0, 0xbe, 0x37, \ | ||
| 0x32, 0x11, 0x19, 0x63, 0x61, 0xe0, 0x53, 0xe0) | ||
|
|
||
| #define INVALID_SHA256 \ | ||
| EMPTY_WRAP('T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'n', 'o', 't', ' ', 'a', ' ', 'v', \ | ||
| 'a', 'l', 'i', 'd', ' ', 'S', 'H', 'A', '2', '5', '6', '!', '!', '!', '!', \ | ||
| '!', '!') | ||
|
|
||
| extern const u8 test_data_1[TEST_DATA_1_SIZE]; | ||
| extern const u8 test_data_2[TEST_DATA_2_SIZE]; | ||
| extern const u8 test_data_int_1[TEST_DATA_INT_1_SIZE]; | ||
| extern const u8 test_data_int_2[TEST_DATA_INT_2_SIZE]; | ||
| extern const u8 test_data_int_3[TEST_DATA_INT_3_SIZE]; | ||
|
|
||
| extern const u8 good_hash[VB2_SHA256_DIGEST_SIZE]; | ||
| extern const u8 bad_hash[VB2_SHA256_DIGEST_SIZE]; | ||
|
|
||
| extern const struct cbfs_test_file file_no_hash; | ||
| extern const struct cbfs_test_file file_valid_hash; | ||
| extern const struct cbfs_test_file file_broken_hash; | ||
| extern const struct cbfs_test_file test_file_1; | ||
| extern const struct cbfs_test_file test_file_2; | ||
| extern const struct cbfs_test_file test_file_int_1; | ||
| extern const struct cbfs_test_file test_file_int_2; | ||
| extern const struct cbfs_test_file test_file_int_3; | ||
|
|
||
| #endif /* MOCKS_CBFS_UTIL_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| tests-y += fmap_locate_area-test | ||
|
|
||
| fmap_locate_area-test-srcs += tests/libc/fmap_locate_area-test.c |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include "../libc/fmap.c" | ||
|
|
||
| #include <libpayload.h> | ||
| #include <tests/test.h> | ||
|
|
||
|
|
||
| /* Mocks */ | ||
| struct sysinfo_t lib_sysinfo; | ||
| unsigned long virtual_offset = 0; | ||
|
|
||
| static void reset_fmap_cache(void) | ||
| { | ||
| _fmap_cache = NULL; | ||
| } | ||
|
|
||
| static int setup_fmap_test(void **state) | ||
| { | ||
| reset_fmap_cache(); | ||
| lib_sysinfo.fmap_cache = 0; | ||
| return 0; | ||
| } | ||
|
|
||
| static void test_fmap_locate_area_no_fmap_available(void **state) | ||
| { | ||
| size_t offset = 0; | ||
| size_t size = 0; | ||
|
|
||
| assert_int_equal(-1, fmap_locate_area("COREBOOT", &offset, &size)); | ||
| } | ||
|
|
||
| static void test_fmap_locate_area_incorrect_signature(void **state) | ||
| { | ||
| size_t offset = 0; | ||
| size_t size = 0; | ||
| struct fmap mock_fmap = { | ||
| .signature = "NOT_MAP", | ||
| }; | ||
| lib_sysinfo.fmap_cache = (uintptr_t)&mock_fmap; | ||
|
|
||
| assert_int_equal(-1, fmap_locate_area("COREBOOT", &offset, &size)); | ||
| } | ||
|
|
||
| static void test_fmap_locate_area_success(void **state) | ||
| { | ||
| size_t offset = 0; | ||
| size_t size = 0; | ||
| struct fmap mock_fmap = { | ||
| .signature = FMAP_SIGNATURE, | ||
| .ver_major = 1, | ||
| .ver_minor = 1, | ||
| .base = 0xAABB, | ||
| .size = 0x10000, | ||
| .nareas = 3, | ||
| }; | ||
| struct fmap_area area_1 = { | ||
| .size = 0x1100, | ||
| .offset = 0x11, | ||
| .name = {'F', 'I', 'R', 'S', 'T', '_', 'A', 'R', 'E', 'A', 0}, | ||
| .flags = 0, | ||
| }; | ||
| struct fmap_area area_2 = { | ||
| .size = 0x2200, | ||
| .offset = 0x1111, | ||
| .name = {'S', 'E', 'C', 'O', 'N', 'D', '_', 'A', 'R', 'E', 'A', 0}, | ||
| .flags = 0, | ||
| }; | ||
| struct fmap_area area_3 = { | ||
| .size = 0x100, | ||
| .offset = 0x3311, | ||
| .name = {'T', 'H', 'I', 'R', 'D', '_', 'A', 'R', 'E', 'A', 0}, | ||
| .flags = 0, | ||
| }; | ||
| u8 fmap_buffer[sizeof(struct fmap) + 3 * sizeof(struct fmap_area)]; | ||
| memcpy(fmap_buffer, &mock_fmap, sizeof(mock_fmap)); | ||
| memcpy(&fmap_buffer[sizeof(mock_fmap)], &area_1, sizeof(area_1)); | ||
| memcpy(&fmap_buffer[sizeof(mock_fmap) + sizeof(area_1)], &area_2, sizeof(area_2)); | ||
| memcpy(&fmap_buffer[sizeof(mock_fmap) + sizeof(area_1) + sizeof(area_2)], &area_3, | ||
| sizeof(area_3)); | ||
|
|
||
| /* Cache only */ | ||
| reset_fmap_cache(); | ||
| lib_sysinfo.fmap_cache = (uintptr_t)fmap_buffer; | ||
|
|
||
| assert_int_equal(0, fmap_locate_area("FIRST_AREA", &offset, &size)); | ||
| assert_int_equal(area_1.offset, offset); | ||
| assert_int_equal(area_1.size, size); | ||
|
|
||
| assert_int_equal(0, fmap_locate_area("THIRD_AREA", &offset, &size)); | ||
| assert_int_equal(area_3.offset, offset); | ||
| assert_int_equal(area_3.size, size); | ||
|
|
||
| assert_int_equal(0, fmap_locate_area("SECOND_AREA", &offset, &size)); | ||
| assert_int_equal(area_2.offset, offset); | ||
| assert_int_equal(area_2.size, size); | ||
|
|
||
| reset_fmap_cache(); | ||
| } | ||
|
|
||
| #define FMAP_LOCATE_AREA_TEST(fn) cmocka_unit_test_setup(fn, setup_fmap_test) | ||
|
|
||
| int main(void) | ||
| { | ||
| const struct CMUnitTest tests[] = { | ||
| FMAP_LOCATE_AREA_TEST(test_fmap_locate_area_no_fmap_available), | ||
| FMAP_LOCATE_AREA_TEST(test_fmap_locate_area_incorrect_signature), | ||
| FMAP_LOCATE_AREA_TEST(test_fmap_locate_area_success), | ||
| }; | ||
|
|
||
| return lp_run_group_tests(tests, NULL, NULL); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # SPDX-License-Identifier: GPL-2.0-only | ||
|
|
||
| tests-y += cbfs-lookup-no-fallback-test | ||
| tests-y += cbfs-lookup-has-fallback-test | ||
| tests-y += cbfs-verification-no-sha512-test | ||
| tests-y += cbfs-verification-has-sha512-test | ||
| tests-y += cbfs-no-verification-no-sha512-test | ||
| tests-y += cbfs-no-verification-has-sha512-test | ||
|
|
||
|
|
||
| cbfs-lookup-no-fallback-test-srcs += tests/libcbfs/cbfs-lookup-test.c | ||
| cbfs-lookup-no-fallback-test-srcs += tests/mocks/cbfs_file_mock.c | ||
| cbfs-lookup-no-fallback-test-config += CONFIG_LP_ENABLE_CBFS_FALLBACK=0 | ||
| cbfs-lookup-no-fallback-test-config += CONFIG_LP_LZ4=1 | ||
| cbfs-lookup-no-fallback-test-config += CONFIG_LP_LZMA=1 | ||
|
|
||
| $(call copy-test,cbfs-lookup-no-fallback-test,cbfs-lookup-has-fallback-test) | ||
| cbfs-lookup-has-fallback-test-config += CONFIG_LP_ENABLE_CBFS_FALLBACK=1 | ||
|
|
||
| cbfs-verification-no-sha512-test-srcs += tests/libcbfs/cbfs-verification-test.c | ||
| cbfs-verification-no-sha512-test-srcs += tests/mocks/cbfs_file_mock.c | ||
| cbfs-verification-no-sha512-test-config += CONFIG_LP_CBFS_VERIFICATION=1 | ||
| cbfs-verification-no-sha512-test-config += VB2_SUPPORT_SHA512=0 | ||
|
|
||
| $(call copy-test,cbfs-verification-no-sha512-test,cbfs-verification-has-sha512-test) | ||
| cbfs-verification-has-sha512-test-config += VB2_SUPPORT_SHA512=1 | ||
|
|
||
| $(call copy-test,cbfs-verification-no-sha512-test,cbfs-no-verification-no-sha512-test) | ||
| cbfs-verification-has-sha512-test-config += CONFIG_LP_CBFS_VERIFICATION=0 | ||
|
|
||
| $(call copy-test,cbfs-verification-no-sha512-test,cbfs-no-verification-has-sha512-test) | ||
| cbfs-verification-has-sha512-test-config += CONFIG_LP_CBFS_VERIFICATION=0 | ||
| cbfs-verification-has-sha512-test-config += VB2_SUPPORT_SHA512=1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,247 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include <cbfs.h> | ||
| #include <cbfs_glue.h> | ||
| #include <string.h> | ||
| #include <mocks/cbfs_util.h> | ||
| #include <tests/test.h> | ||
|
|
||
| #include "../libcbfs/cbfs.c" | ||
|
|
||
| /* Mocks */ | ||
|
|
||
| unsigned long virtual_offset = 0; | ||
| struct sysinfo_t lib_sysinfo; | ||
|
|
||
| size_t vb2_digest_size(enum vb2_hash_algorithm hash_alg) | ||
| { | ||
| if (hash_alg != VB2_HASH_SHA256) { | ||
| fail_msg("Unsupported hash algorithm: %d\n", hash_alg); | ||
| return 0; | ||
| } | ||
|
|
||
| return VB2_SHA256_DIGEST_SIZE; | ||
| } | ||
|
|
||
| vb2_error_t vb2_hash_verify(const void *buf, uint32_t size, const struct vb2_hash *hash) | ||
| { | ||
| check_expected_ptr(buf); | ||
| check_expected(size); | ||
|
|
||
| assert_int_equal(hash->algo, VB2_HASH_SHA256); | ||
|
|
||
| if (!memcmp(hash->sha256, good_hash, sizeof(good_hash))) | ||
| return VB2_SUCCESS; | ||
|
|
||
| if (!memcmp(hash->sha256, bad_hash, sizeof(bad_hash))) | ||
| return VB2_ERROR_SHA_MISMATCH; | ||
|
|
||
| fail_msg("%s called with bad hash", __func__); | ||
| return VB2_ERROR_SHA_MISMATCH; | ||
| } | ||
|
|
||
| unsigned long ulzman(const unsigned char *src, unsigned long srcn, unsigned char *dst, | ||
| unsigned long dstn) | ||
| { | ||
| fail_msg("Unexpected call to %s", __func__); | ||
| return 0; | ||
| } | ||
|
|
||
| size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn) | ||
| { | ||
| fail_msg("Unexpected call to %s", __func__); | ||
| return 0; | ||
| } | ||
|
|
||
| cb_err_t cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name, | ||
| union cbfs_mdata *mdata_out, size_t *data_offset_out) | ||
| { | ||
| return CB_CBFS_CACHE_FULL; | ||
| } | ||
|
|
||
| cb_err_t cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out, | ||
| size_t *data_offset_out, struct vb2_hash *metadata_hash) | ||
| { | ||
| assert_non_null(dev); | ||
| check_expected(name); | ||
|
|
||
| cb_err_t ret = mock_type(cb_err_t); | ||
| if (ret != CB_SUCCESS) | ||
| return ret; | ||
|
|
||
| memcpy(mdata_out, mock_ptr_type(const union cbfs_mdata *), sizeof(union cbfs_mdata)); | ||
| *data_offset_out = mock_type(size_t); | ||
| return CB_SUCCESS; | ||
| } | ||
|
|
||
| static void expect_cbfs_lookup(const char *name, cb_err_t err, const union cbfs_mdata *mdata, | ||
| size_t data_offset_out) | ||
| { | ||
| expect_string(cbfs_lookup, name, name); | ||
| will_return(cbfs_lookup, err); | ||
|
|
||
| if (err == CB_SUCCESS) { | ||
| will_return(cbfs_lookup, mdata); | ||
| will_return(cbfs_lookup, data_offset_out); | ||
| } | ||
| } | ||
|
|
||
| const void *cbfs_find_attr(const union cbfs_mdata *mdata, uint32_t attr_tag, size_t size_check) | ||
| { | ||
| return mock_ptr_type(void *); | ||
| } | ||
|
|
||
| cb_err_t fmap_locate_area(const char *name, size_t *offset, size_t *size) | ||
| { | ||
| *offset = 0; | ||
| *size = 0; | ||
| return CB_SUCCESS; | ||
| } | ||
|
|
||
| ssize_t boot_device_read(void *buf, size_t offset, size_t size) | ||
| { | ||
| /* Offset should be based on an address from lib_sysinfo.cbfs_offset */ | ||
| memcpy(buf, (void *)offset, size); | ||
|
|
||
| return size; | ||
| } | ||
|
|
||
| const struct vb2_hash *cbfs_file_hash(const union cbfs_mdata *mdata) | ||
| { | ||
| return mock_ptr_type(const struct vb2_hash *); | ||
| } | ||
|
|
||
| /* Utils */ | ||
|
|
||
| static void clear_cbfs_boot_devices(void) | ||
| { | ||
| lib_sysinfo.cbfs_ro_mcache_offset = 0; | ||
| lib_sysinfo.cbfs_ro_mcache_size = 0; | ||
| lib_sysinfo.cbfs_offset = 0; | ||
| lib_sysinfo.cbfs_size = 0; | ||
| lib_sysinfo.cbfs_rw_mcache_offset = 0; | ||
| lib_sysinfo.cbfs_rw_mcache_size = 0; | ||
| memset((void *)cbfs_get_boot_device(true), 0, sizeof(struct cbfs_boot_device)); | ||
| memset((void *)cbfs_get_boot_device(false), 0, sizeof(struct cbfs_boot_device)); | ||
| } | ||
|
|
||
| void set_cbfs(uint64_t offset, size_t size) | ||
| { | ||
| clear_cbfs_boot_devices(); | ||
| lib_sysinfo.cbfs_offset = offset; | ||
| lib_sysinfo.cbfs_size = size; | ||
| } | ||
|
|
||
| /* Tests */ | ||
|
|
||
| static int setup_test_cbfs(void **state) | ||
| { | ||
| clear_cbfs_boot_devices(); | ||
| return 0; | ||
| } | ||
|
|
||
| static void test_cbfs_map_no_hash(void **state) | ||
| { | ||
| void *mapping = NULL; | ||
| size_t size = 0; | ||
|
|
||
| set_cbfs((uint64_t)&file_no_hash, sizeof(file_no_hash)); | ||
|
|
||
| expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS, | ||
| (const union cbfs_mdata *)&file_no_hash, | ||
| be32toh(file_no_hash.header.offset)); | ||
| will_return(cbfs_find_attr, NULL); | ||
|
|
||
| if (CONFIG(LP_CBFS_VERIFICATION)) { | ||
| /* File with no hash. No hash causes hash mismatch by default, | ||
| so mapping will not be completed successfully. */ | ||
| will_return(cbfs_file_hash, NULL); | ||
| mapping = cbfs_map(TEST_DATA_1_FILENAME, NULL); | ||
| assert_null(mapping); | ||
| } else { | ||
| mapping = cbfs_map(TEST_DATA_1_FILENAME, &size); | ||
| assert_non_null(mapping); | ||
| assert_int_equal(TEST_DATA_1_SIZE, size); | ||
| assert_memory_equal(test_data_1, mapping, size); | ||
| cbfs_unmap(mapping); | ||
| } | ||
| } | ||
|
|
||
| static void test_cbfs_map_valid_hash(void **state) | ||
| { | ||
| void *mapping = NULL; | ||
| size_t size = 0; | ||
| struct vb2_hash hash = { | ||
| .algo = VB2_HASH_SHA256, | ||
| }; | ||
| memcpy(&hash.sha256, good_hash, VB2_SHA256_DIGEST_SIZE); | ||
|
|
||
| set_cbfs((uint64_t)&file_valid_hash, sizeof(file_valid_hash)); | ||
|
|
||
| expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS, | ||
| (const union cbfs_mdata *)&file_valid_hash, | ||
| be32toh(file_valid_hash.header.offset)); | ||
| will_return(cbfs_find_attr, NULL); | ||
|
|
||
|
|
||
| if (CONFIG(LP_CBFS_VERIFICATION)) { | ||
| will_return(cbfs_file_hash, &hash); | ||
| expect_memory(vb2_hash_verify, buf, | ||
| &file_valid_hash.attrs_and_data[HASH_ATTR_SIZE], HASH_ATTR_SIZE); | ||
| expect_value(vb2_hash_verify, size, TEST_DATA_1_SIZE); | ||
| mapping = cbfs_map(TEST_DATA_1_FILENAME, &size); | ||
| assert_non_null(mapping); | ||
| assert_int_equal(TEST_DATA_1_SIZE, size); | ||
| assert_memory_equal(mapping, &file_valid_hash.attrs_and_data[HASH_ATTR_SIZE], | ||
| size); | ||
| } else { | ||
| mapping = cbfs_map(TEST_DATA_1_FILENAME, &size); | ||
| assert_non_null(mapping); | ||
| assert_int_equal(TEST_DATA_1_SIZE, size); | ||
| assert_memory_equal(test_data_1, mapping, size); | ||
| cbfs_unmap(mapping); | ||
| } | ||
| } | ||
|
|
||
| static void test_cbfs_map_invalid_hash(void **state) | ||
| { | ||
| void *mapping = NULL; | ||
| size_t size = 0; | ||
| struct vb2_hash hash = { | ||
| .algo = VB2_HASH_SHA256, | ||
| }; | ||
| memcpy(&hash.sha256, bad_hash, VB2_SHA256_DIGEST_SIZE); | ||
|
|
||
| set_cbfs((uint64_t)&file_broken_hash, sizeof(file_broken_hash)); | ||
|
|
||
| expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS, | ||
| (const union cbfs_mdata *)&file_broken_hash, | ||
| be32toh(file_broken_hash.header.offset)); | ||
| will_return(cbfs_find_attr, NULL); | ||
|
|
||
| if (CONFIG(LP_CBFS_VERIFICATION)) { | ||
| will_return(cbfs_file_hash, &hash); | ||
| expect_memory(vb2_hash_verify, buf, | ||
| &file_broken_hash.attrs_and_data[HASH_ATTR_SIZE], HASH_ATTR_SIZE); | ||
| expect_value(vb2_hash_verify, size, TEST_DATA_1_SIZE); | ||
| mapping = cbfs_map(TEST_DATA_1_FILENAME, NULL); | ||
| assert_null(mapping); | ||
| } else { | ||
| mapping = cbfs_map(TEST_DATA_1_FILENAME, &size); | ||
| assert_non_null(mapping); | ||
| assert_int_equal(TEST_DATA_1_SIZE, size); | ||
| assert_memory_equal(test_data_1, mapping, size); | ||
| cbfs_unmap(mapping); | ||
| } | ||
| } | ||
|
|
||
| int main(void) | ||
| { | ||
| const struct CMUnitTest tests[] = { | ||
| cmocka_unit_test_setup(test_cbfs_map_no_hash, setup_test_cbfs), | ||
| cmocka_unit_test_setup(test_cbfs_map_valid_hash, setup_test_cbfs), | ||
| cmocka_unit_test_setup(test_cbfs_map_invalid_hash, setup_test_cbfs), | ||
| }; | ||
|
|
||
| return lp_run_group_tests(tests, NULL, NULL); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include <mocks/cbfs_util.h> | ||
|
|
||
|
|
||
| const u8 test_data_1[TEST_DATA_1_SIZE] = { TEST_DATA_1 }; | ||
| const u8 test_data_2[TEST_DATA_2_SIZE] = { TEST_DATA_2 }; | ||
| const u8 test_data_int_1[TEST_DATA_INT_1_SIZE] = { LE64(TEST_DATA_INT_1) }; | ||
| const u8 test_data_int_2[TEST_DATA_INT_2_SIZE] = { LE64(TEST_DATA_INT_2) }; | ||
| const u8 test_data_int_3[TEST_DATA_INT_3_SIZE] = { LE64(TEST_DATA_INT_3) }; | ||
|
|
||
| const u8 good_hash[VB2_SHA256_DIGEST_SIZE] = { TEST_SHA256 }; | ||
| const u8 bad_hash[VB2_SHA256_DIGEST_SIZE] = { INVALID_SHA256 }; | ||
|
|
||
| const struct cbfs_test_file file_no_hash = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, 0, TEST_DATA_1_SIZE), | ||
| .filename = TEST_DATA_1_FILENAME, | ||
| .attrs_and_data = { | ||
| TEST_DATA_1, | ||
| }, | ||
| }; | ||
|
|
||
| const struct cbfs_test_file file_valid_hash = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, HASH_ATTR_SIZE, TEST_DATA_1_SIZE), | ||
| .filename = TEST_DATA_1_FILENAME, | ||
| .attrs_and_data = { | ||
| BE32(CBFS_FILE_ATTR_TAG_HASH), | ||
| BE32(HASH_ATTR_SIZE), | ||
| BE32(VB2_HASH_SHA256), | ||
| TEST_SHA256, | ||
| TEST_DATA_1, | ||
| }, | ||
| }; | ||
|
|
||
| const struct cbfs_test_file file_broken_hash = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, HASH_ATTR_SIZE, TEST_DATA_1_SIZE), | ||
| .filename = TEST_DATA_1_FILENAME, | ||
| .attrs_and_data = { | ||
| BE32(CBFS_FILE_ATTR_TAG_HASH), | ||
| BE32(HASH_ATTR_SIZE), | ||
| BE32(VB2_HASH_SHA256), | ||
| INVALID_SHA256, | ||
| TEST_DATA_1, | ||
| }, | ||
| }; | ||
|
|
||
| const struct cbfs_test_file test_file_1 = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, 0, TEST_DATA_1_SIZE), | ||
| .filename = TEST_DATA_1_FILENAME, | ||
| .attrs_and_data = { | ||
| TEST_DATA_1, | ||
| }, | ||
| }; | ||
|
|
||
| const struct cbfs_test_file test_file_2 = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, sizeof(struct cbfs_file_attr_compression), | ||
| TEST_DATA_2_SIZE), | ||
| .filename = TEST_DATA_2_FILENAME, | ||
| .attrs_and_data = { | ||
| BE32(CBFS_FILE_ATTR_TAG_COMPRESSION), | ||
| BE32(sizeof(struct cbfs_file_attr_compression)), | ||
| BE32(CBFS_COMPRESS_LZMA), | ||
| BE32(TEST_DATA_2_SIZE), | ||
| TEST_DATA_2, | ||
| }, | ||
| }; | ||
|
|
||
| const struct cbfs_test_file test_file_int_1 = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, 0, TEST_DATA_INT_1_SIZE), | ||
| .filename = TEST_DATA_INT_1_FILENAME, | ||
| .attrs_and_data = { | ||
| LE64(TEST_DATA_INT_1), | ||
| }, | ||
| }; | ||
|
|
||
| const struct cbfs_test_file test_file_int_2 = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, 0, TEST_DATA_INT_2_SIZE), | ||
| .filename = TEST_DATA_INT_2_FILENAME, | ||
| .attrs_and_data = { | ||
| LE64(TEST_DATA_INT_2), | ||
| }, | ||
| }; | ||
|
|
||
| const struct cbfs_test_file test_file_int_3 = { | ||
| .header = HEADER_INITIALIZER(CBFS_TYPE_RAW, sizeof(struct cbfs_file_attr_compression), | ||
| TEST_DATA_INT_3_SIZE), | ||
| .filename = TEST_DATA_INT_3_FILENAME, | ||
| .attrs_and_data = { | ||
| BE32(CBFS_FILE_ATTR_TAG_COMPRESSION), | ||
| BE32(sizeof(struct cbfs_file_attr_compression)), | ||
| BE32(CBFS_COMPRESS_LZ4), | ||
| BE32(TEST_DATA_INT_3_SIZE), | ||
| LE64(TEST_DATA_INT_3), | ||
| }, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include <tests/test.h> | ||
| #include <stdbool.h> | ||
|
|
||
| void die_work(const char *file, const char *func, int line, const char *fmt, ...) | ||
| { | ||
| /* Failing asserts are jumping to the user code (test) if expect_assert_failed() was | ||
| previously called. Otherwise it jumps to the cmocka code and fails the test. */ | ||
| mock_assert(false, "Mock assetion called", file, line); | ||
|
|
||
| /* Should never be reached */ | ||
| print_error("%s() called...\n", __func__); | ||
| while (1) | ||
| ; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| config VBOOT_LIB | ||
| bool "Compile verified boot (vboot) library" | ||
| default n | ||
| help | ||
| This option enables compiling and building vboot libraries vboot_fw and tlcl. | ||
|
|
||
| if VBOOT_LIB | ||
|
|
||
| config VBOOT_TPM2_MODE | ||
| bool "TPM2 Mode" | ||
| default y | ||
| help | ||
| This option enables TPM 2.0 support in vboot. Disabling it allows using TPM 1.2. | ||
|
|
||
| config VBOOT_X86_SHA_EXT | ||
| bool "x86 SHA Extension" | ||
| default n | ||
| depends on ARCH_X86 | ||
| help | ||
| This option enables SHA256 implementation using x86 SHA processor extension | ||
| instructions: sha256msg1, sha256msg2, sha256rnds2. | ||
|
|
||
| endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| VBOOT_BUILD_DIR ?= $(abspath $(obj)/external/vboot) | ||
| VBOOT_FW_LIB = $(VBOOT_BUILD_DIR)/vboot_fw.a | ||
| TLCL_LIB = $(VBOOT_BUILD_DIR)/tlcl.a | ||
|
|
||
| vboot_fw-objs += $(VBOOT_FW_LIB) | ||
| tlcl-objs += $(TLCL_LIB) | ||
|
|
||
| kconfig-to-binary=$(if $(1),1,0) | ||
| vboot-fixup-includes = $(patsubst -I%,-I$(top)/%,\ | ||
| $(patsubst include/%.h,$(top)/include/%.h,\ | ||
| $(filter-out -I$(obj),$(1)))) | ||
|
|
||
| ifeq ($(CONFIG_LP_ARCH_MOCK),) | ||
| VBOOT_CFLAGS += $(call vboot-fixup-includes,$(CFLAGS)) | ||
| VBOOT_CFLAGS += -I$(abspath $(obj)) | ||
| endif | ||
|
|
||
| # Enable vboot debug by default | ||
| VBOOT_CFLAGS += -DVBOOT_DEBUG | ||
|
|
||
| VBOOT_FIRMWARE_ARCH-$(CONFIG_LP_ARCH_ARM) := arm | ||
| VBOOT_FIRMWARE_ARCH-$(CONFIG_LP_ARCH_X86) := x86 | ||
| VBOOT_FIRMWARE_ARCH-$(CONFIG_LP_ARCH_ARM64) := arm64 | ||
|
|
||
| ifeq ($(CONFIG_LP_ARCH_MOCK)$(VBOOT_FIRMWARE_ARCH-y),) | ||
| $(error vboot requires architecture to be set in the configuration) | ||
| endif | ||
|
|
||
| $(VBOOT_FW_LIB): $(obj)/libpayload-config.h | ||
| @printf " MAKE $(subst $(obj)/,,$(@))\n" | ||
| +$(Q) FIRMWARE_ARCH=$(VBOOT_FIRMWARE_ARCH-y) \ | ||
| CC=$(CC) \ | ||
| CFLAGS="$(VBOOT_CFLAGS)" \ | ||
| $(MAKE) -C "$(VBOOT_SOURCE)" \ | ||
| TPM2_MODE=$(call kconfig-to-binary, $(CONFIG_LP_VBOOT_TPM2_MODE)) \ | ||
| X86_SHA_EXT=$(call kconfig-to-binary, $(CONFIG_LP_VBOOT_X86_SHA_EXT)) \ | ||
| UNROLL_LOOPS=1 \ | ||
| BUILD=$(VBOOT_BUILD_DIR) \ | ||
| V=$(V) \ | ||
| $(VBOOT_BUILD_DIR)/vboot_fw.a tlcl | ||
|
|
||
| $(TLCL_LIB): $(VBOOT_FW_LIB) | ||
|
|
||
| .PHONY: $(VBOOT_FW_LIB) $(TLCL_LIB) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,8 +10,6 @@ | |
|
|
||
| #define ACPIGEN_MAXLEN 0xfffff | ||
|
|
||
| #include <lib.h> | ||
| #include <string.h> | ||
| #include <acpi/acpigen.h> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,3 @@ | |
| External (GNVS, OpRegionObj) | ||
| External (DNVS, OpRegionObj) | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include <acpi/acpigen.h> | ||
| #include <acpi/acpi_sata.h> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -153,7 +153,7 @@ Method(DBGO, 1) | |
| return (0) | ||
| } | ||
| OUTC(Local0) | ||
| Local1++ | ||
| } | ||
| } | ||
| return (0) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,6 @@ | |
| #ifndef ARCH_CPU_H | ||
| #define ARCH_CPU_H | ||
|
|
||
| #include <types.h> | ||
|
|
||
| /* | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,23 @@ | ||
| /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */ | ||
| #if defined(__FreeBSD__) | ||
| #include <sys/endian.h> | ||
| #elif defined(__APPLE__) | ||
| #include <libkern/OSByteOrder.h> | ||
|
|
||
| #define htobe16(x) OSSwapHostToBigInt16(x) | ||
| #define htole16(x) OSSwapHostToLittleInt16(x) | ||
| #define be16toh(x) OSSwapBigToHostInt16(x) | ||
| #define le16toh(x) OSSwapLittleToHostInt16(x) | ||
|
|
||
| #define htobe32(x) OSSwapHostToBigInt32(x) | ||
| #define htole32(x) OSSwapHostToLittleInt32(x) | ||
| #define be32toh(x) OSSwapBigToHostInt32(x) | ||
| #define le32toh(x) OSSwapLittleToHostInt32(x) | ||
|
|
||
| #define htobe64(x) OSSwapHostToBigInt64(x) | ||
| #define htole64(x) OSSwapHostToLittleInt64(x) | ||
| #define be64toh(x) OSSwapBigToHostInt64(x) | ||
| #define le64toh(x) OSSwapLittleToHostInt64(x) | ||
| #else | ||
| #include <endian.h> | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,6 @@ | |
| * Authors: Dave Airlie <airlied@redhat.com> | ||
| */ | ||
|
|
||
| #include <device/pci_def.h> | ||
|
|
||
| #include "ast_drv.h" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| config DRIVERS_I2C_SX9360 | ||
| bool | ||
| default n | ||
| depends on HAVE_ACPI_TABLES | ||
| help | ||
| Board has a Semtech SX9360 proximity sensor. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ramstage-$(CONFIG_DRIVERS_I2C_SX9360) += sx9360.c |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #ifndef __DRIVERS_I2C_SX9360_CHIP_H__ | ||
| #define __DRIVERS_I2C_SX9360_CHIP_H__ | ||
|
|
||
| #include <acpi/acpi_device.h> | ||
| #include <device/i2c_simple.h> | ||
|
|
||
| struct drivers_i2c_sx9360_config { | ||
| /* Device Description */ | ||
| const char *desc; | ||
|
|
||
| /* ACPI _UID */ | ||
| unsigned int uid; | ||
|
|
||
| /* Bus speed in Hz, default is I2C_SPEED_FAST */ | ||
| enum i2c_speed speed; | ||
|
|
||
| /* Use GPIO-based interrupt instead of IO-APIC */ | ||
| struct acpi_gpio irq_gpio; | ||
|
|
||
| /* IO-APIC interrupt */ | ||
| struct acpi_irq irq; | ||
|
|
||
| /* | ||
| * Registers definition in the kernel source tree at: | ||
| * Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml | ||
| */ | ||
|
|
||
| /* Raw Proximity filter strength: When not set, disabled. */ | ||
| uint32_t proxraw_strength; | ||
|
|
||
| /* Average Proximity filter strength: When not set, disabled. */ | ||
| uint32_t avg_pos_strength; | ||
|
|
||
| /* Capacitance measure resolution. Driver default: 128. */ | ||
| uint32_t resolution; | ||
| }; | ||
|
|
||
| #endif /* __DRIVERS_I2C_SX9360_CHIP_H__ */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include <acpi/acpi_device.h> | ||
| #include <acpi/acpigen.h> | ||
| #include <console/console.h> | ||
| #include <device/i2c_simple.h> | ||
| #include <device/device.h> | ||
| #include <device/path.h> | ||
| #include <string.h> | ||
| #include "chip.h" | ||
|
|
||
| #define I2C_SX9360_ACPI_ID "STH9360" | ||
| #define I2C_SX9360_CHIP_NAME "Semtech SX9360" | ||
|
|
||
| static void i2c_sx9360_fill_ssdt(const struct device *dev) | ||
| { | ||
| struct drivers_i2c_sx9360_config *config = dev->chip_info; | ||
| const char *scope = acpi_device_scope(dev); | ||
| struct acpi_i2c i2c = { | ||
| .address = dev->path.i2c.device, | ||
| .mode_10bit = dev->path.i2c.mode_10bit, | ||
| .speed = I2C_SPEED_FAST, | ||
| .resource = scope, | ||
| }; | ||
| struct acpi_dp *dsd; | ||
|
|
||
| if (!scope || !config) | ||
| return; | ||
|
|
||
| if (config->speed) | ||
| i2c.speed = config->speed; | ||
|
|
||
| /* Device */ | ||
| acpigen_write_scope(scope); | ||
| acpigen_write_device(acpi_device_name(dev)); | ||
| acpigen_write_name_string("_HID", I2C_SX9360_ACPI_ID); | ||
| acpigen_write_name_integer("_UID", config->uid); | ||
| acpigen_write_name_string("_DDN", config->desc); | ||
| acpigen_write_STA(acpi_device_status(dev)); | ||
|
|
||
| /* Resources */ | ||
| acpigen_write_name("_CRS"); | ||
| acpigen_write_resourcetemplate_header(); | ||
| acpi_device_write_i2c(&i2c); | ||
|
|
||
| if (config->irq_gpio.pin_count) | ||
| acpi_device_write_gpio(&config->irq_gpio); | ||
| else | ||
| acpi_device_write_interrupt(&config->irq); | ||
|
|
||
| acpigen_write_resourcetemplate_footer(); | ||
|
|
||
| /* DSD */ | ||
| dsd = acpi_dp_new_table("_DSD"); | ||
|
|
||
| /* | ||
| * Format described in linux kernel documentation. See | ||
| * https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/proximity/semtech%2Csx9360.yaml | ||
| */ | ||
| acpi_dp_add_integer(dsd, "semtech,proxraw-strength", | ||
| config->proxraw_strength); | ||
| acpi_dp_add_integer(dsd, "semtech,avg-pos-strength", | ||
| config->avg_pos_strength); | ||
| acpi_dp_add_integer(dsd, "semtech,resolution", | ||
| config->resolution); | ||
|
|
||
| acpi_dp_write(dsd); | ||
|
|
||
| acpigen_pop_len(); /* Device */ | ||
| acpigen_pop_len(); /* Scope */ | ||
|
|
||
| printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), | ||
| config->desc ? : dev->chip_ops->name, dev_path(dev)); | ||
| } | ||
|
|
||
| static const char *i2c_sx9360_acpi_name(const struct device *dev) | ||
| { | ||
| static char name[5]; | ||
|
|
||
| snprintf(name, sizeof(name), "SX%02.2X", dev->path.i2c.device); | ||
| return name; | ||
| } | ||
|
|
||
| static struct device_operations i2c_sx9360_ops = { | ||
| .read_resources = noop_read_resources, | ||
| .set_resources = noop_set_resources, | ||
| .acpi_name = i2c_sx9360_acpi_name, | ||
| .acpi_fill_ssdt = i2c_sx9360_fill_ssdt, | ||
| }; | ||
|
|
||
| static void i2c_sx9360_enable(struct device *dev) | ||
| { | ||
| struct drivers_i2c_sx9360_config *config = config_of(dev); | ||
|
|
||
| if (!is_dev_enabled(dev)) | ||
| return; | ||
|
|
||
| dev->ops = &i2c_sx9360_ops; | ||
|
|
||
| if (config->desc) | ||
| dev->name = config->desc; | ||
| } | ||
|
|
||
| struct chip_operations drivers_i2c_sx9360_ops = { | ||
| CHIP_NAME(I2C_SX9360_CHIP_NAME) | ||
| .enable_dev = i2c_sx9360_enable | ||
| }; |