tpm fixes for coral

binman fixes support for symbols in sub-sections
 support for additional cros_ec commands
 various minor fixes / tweaks
 -----BEGIN PGP SIGNATURE-----
 
 iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmAV6K8RHHNqZ0BjaHJv
 bWl1bS5vcmcACgkQfxc6PpAIreYERgf/QbwOL87yPbf9SyXBQ0EMTmn1ve9HCiv9
 yeXrijvA0/wtTVoM44d/z7THb+7Zqw6LbsVOXUSicdGqaogy10xIuz5we0CoGJm6
 iwYWV6kaAqjCxDTlSToGnR/TCjiOVgXC6u5QPCZC0LGbAmDbAl4jyCuQxxq2eXYD
 hrLSzZPHDe0s2BeWZKRQJ26qyPfWIribXNJXG78/FsvDrdWPPc5K+/ZEb2IWawWR
 nEZ8GTEYZpik/niEJ3gFozwCwpJQi3PyukjZvzTGn6tBqg12YXE4dbSzcj48Uj4o
 prwUFAGKRR97zFB6c4+NUvd3VBUgPtPdZrtzZ1nNCppiMq1E4BKiDg==
 =kijh
 -----END PGP SIGNATURE-----

Merge tag 'dm-pull-30jan21' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm

tpm fixes for coral
binman fixes support for symbols in sub-sections
support for additional cros_ec commands
various minor fixes / tweaks
This commit is contained in:
Tom Rini 2021-01-31 08:49:53 -05:00
commit 242ef48ea7
62 changed files with 1487 additions and 137 deletions

13
Kconfig
View File

@ -217,22 +217,25 @@ config SYS_MALLOC_LEN
TODO: Use for other architectures
config SPL_SYS_MALLOC_F_LEN
hex "Size of malloc() pool in SPL before relocation"
hex "Size of malloc() pool in SPL"
depends on SYS_MALLOC_F && SPL
default 0x2800 if RCAR_GEN3
default SYS_MALLOC_F_LEN
help
Before relocation, memory is very limited on many platforms. Still,
In SPL memory is very limited on many platforms. Still,
we can provide a small malloc() pool if needed. Driver model in
particular needs this to operate, so that it can allocate the
initial serial device and any others that are needed.
It is possible to enable CONFIG_SYS_SPL_MALLOC_START to start a new
malloc() region in SDRAM once it is inited.
config TPL_SYS_MALLOC_F_LEN
hex "Size of malloc() pool in TPL before relocation"
hex "Size of malloc() pool in TPL"
depends on SYS_MALLOC_F && TPL
default SYS_MALLOC_F_LEN
default SPL_SYS_MALLOC_F_LEN
help
Before relocation, memory is very limited on many platforms. Still,
In TPL memory is very limited on many platforms. Still,
we can provide a small malloc() pool if needed. Driver model in
particular needs this to operate, so that it can allocate the
initial serial device and any others that are needed.

View File

@ -32,6 +32,9 @@
#include <os.h>
#include <rtc_def.h>
/* Environment variable for time offset */
#define ENV_TIME_OFFSET "UBOOT_SB_TIME_OFFSET"
/* Operating System Interface */
struct os_mem_hdr {
@ -798,6 +801,28 @@ int os_spl_to_uboot(const char *fname)
return os_jump_to_file(fname);
}
long os_get_time_offset(void)
{
const char *offset;
offset = getenv(ENV_TIME_OFFSET);
if (offset)
return strtol(offset, NULL, 0);
return 0;
}
void os_set_time_offset(long offset)
{
char buf[21];
int ret;
snprintf(buf, sizeof(buf), "%ld", offset);
ret = setenv(ENV_TIME_OFFSET, buf, true);
if (ret)
printf("Could not set environment variable %s\n",
ENV_TIME_OFFSET);
}
void os_localtime(struct rtc_time *rt)
{
time_t t = time(NULL);

View File

@ -215,7 +215,7 @@ static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state,
if (!p)
p = fname + strlen(fname);
len -= p - fname;
snprintf(p, len, fmt, p);
snprintf(p, len, fmt);
state->fdt_fname = fname;
return 0;

View File

@ -260,10 +260,14 @@
stringarray = "pre-proper";
};
spl-test7 {
test-bus {
compatible = "simple-bus";
u-boot,dm-spl;
compatible = "sandbox,spl-test";
stringarray = "spl";
spl-test7 {
u-boot,dm-spl;
compatible = "sandbox,spl-test";
stringarray = "spl";
};
};
square {

View File

@ -90,6 +90,16 @@
wp-ro {
image-pos = <0xf000>;
size = <0x1000>;
used = <0x884>;
compress = "lz4";
uncomp-size = <0xcf8>;
hash {
algo = "sha256";
value = [00 01 02 03 04 05 06 07
08 09 0a 0b 0c 0d 0e 0f
10 11 12 13 14 15 16 17
18 19 1a 1b 1c 1d 1e 1f];
};
};
rw {
image-pos = <0x10000>;

View File

@ -57,6 +57,13 @@ enum {
SYSCON_COUNT
};
/**
*/
enum cros_ec_test_t {
CROSECT_BREAK_HELLO = BIT(1),
CROSECT_LID_OPEN = BIT(2),
};
/**
* sandbox_i2c_set_test_mode() - set test mode for running unit tests
*
@ -260,4 +267,12 @@ uint sandbox_pci_read_bar(u32 barval, int type, uint size);
*/
void sandbox_set_enable_memio(bool enable);
/**
* sandbox_cros_ec_set_test_flags() - Set behaviour for testing purposes
*
* @dev: Device to check
* @flags: Flags to control behaviour (CROSECT_...)
*/
void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags);
#endif

View File

@ -175,7 +175,7 @@ void arch_setup_gd(gd_t *new_gd)
* Per Intel FSP external architecture specification, before calling any FSP
* APIs, we need make sure the system is in flat 32-bit mode and both the code
* and data selectors should have full 4GB access range. Here we reuse the one
* we used in arch/x86/cpu/start16.S, and reload the segement registers.
* we used in arch/x86/cpu/start16.S, and reload the segment registers.
*/
void setup_fsp_gdt(void)
{

View File

@ -77,7 +77,7 @@ _start:
lgdt gdt_ptr2
#endif
/* Load the segement registers to match the GDT loaded in start16.S */
/* Load the segment registers to match the GDT loaded in start16.S */
movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
movw %ax, %fs
movw %ax, %ds

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/gpio/x86-gpio.h>
/include/ "skeleton.dtsi"
@ -99,6 +100,7 @@
clk: clock {
compatible = "intel,apl-clk";
#clock-cells = <1>;
u-boot,dm-pre-reloc;
};
cpus {
@ -139,6 +141,7 @@
};
acpi_gpe: general-purpose-events {
u-boot,dm-pre-reloc;
reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
compatible = "intel,acpi-gpe";
interrupt-controller;
@ -417,8 +420,10 @@
};
i2c_2: i2c2@16,2 {
compatible = "intel,apl-i2c";
compatible = "intel,apl-i2c", "snps,designware-i2c-pci";
reg = <0x0200b210 0 0 0 0>;
early-regs = <IOMAP_I2C2_BASE 0x1000>;
u-boot,dm-pre-reloc;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
@ -429,6 +434,7 @@
tpm: tpm@50 {
reg = <0x50>;
compatible = "google,cr50";
u-boot,dm-pre-reloc;
u-boot,i2c-offset-len = <0>;
ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>;
interrupts-extended = <&acpi_gpe GPIO_28_IRQ
@ -583,6 +589,7 @@
u-boot,dm-pre-reloc;
cros_ec: cros-ec {
u-boot,dm-pre-proper;
u-boot,dm-vpl;
compatible = "google,cros-ec-lpc";
reg = <0x204 1 0x200 1 0x880 0x80>;
@ -637,6 +644,7 @@
PAD_CFG0_TX_DISABLE | PAD_CFG0_ROUTE_IOAPIC |
PAD_CFG0_TRIG_LEVEL | PAD_CFG0_RX_POL_INVERT)
(PAD_CFG1_PULL_NONE | PAD_CFG1_IOSSTATE_TXD_RXE)
PAD_CFG_GPI(GPIO_25, UP_20K, DEEP) /* unused */
/*
* WLAN_PE_RST - default to deasserted just in case FSP
@ -657,6 +665,11 @@
PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1) /* LPC_AD3 */
PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1) /* LPC_CLKRUN_N */
PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */
PAD_CFG_GPI(GPIO_101, NONE, DEEP) /* FST_IO2 -- MEM_CONFIG0 */
PAD_CFG_GPI(GPIO_102, NONE, DEEP) /* FST_IO3 -- MEM_CONFIG1 */
PAD_CFG_GPI(GPIO_38, NONE, DEEP) /* LPSS_UART0_RXD - MEM_CONFIG2*/
PAD_CFG_GPI(GPIO_45, NONE, DEEP) /* LPSS_UART1_CTS - MEM_CONFIG3 */
>;
};
@ -1210,3 +1223,9 @@
PAD_CFG_GPI(GPIO_73, UP_20K, DEEP) /* GP_CAMERASB11 */
>;
};
&rtc {
#address-cells = <1>;
#size-cells = <0>;
u-boot,dm-pre-reloc;
};

View File

@ -33,6 +33,9 @@
#define SRAM_SIZE_2 (4 * KiB)
#endif
/* Early address for I2C port 2 */
#define IOMAP_I2C2_BASE (0xfe020000 + 2 * 0x1000)
/*
* Use UART2. To use UART1 you need to set '2' to '1', change device tree serial
* node name and 'reg' property, and update CONFIG_DEBUG_UART_BASE.

View File

@ -94,6 +94,169 @@ static int do_read_write(struct udevice *dev, int is_write, int argc,
return 0;
}
static const char *const feat_name[64] = {
"limited",
"flash",
"pwm_fan",
"pwm_keyb",
"lightbar",
"led",
"motion_sense",
"keyb",
"pstore",
"port80",
"thermal",
"bklight_switch",
"wifi_switch",
"host_events",
"gpio",
"i2c",
"charger",
"battery",
"smart_battery",
"hang_detect",
"pmu",
"sub_mcu",
"usb_pd",
"usb_mux",
"motion_sense_fifo",
"vstore",
"usbc_ss_mux_virtual",
"rtc",
"fingerprint",
"touchpad",
"rwsig",
"device_event",
"unified_wake_masks",
"host_event64",
"exec_in_ram",
"cec",
"motion_sense_tight_timestamps",
"refined_tablet_mode_hysteresis",
"efs2",
"scp",
"ish",
"typec_cmd",
"typec_require_ap_mode_entry",
"typec_mux_require_ap_ack",
};
static int do_show_features(struct udevice *dev)
{
u64 feat;
int ret;
uint i;
ret = cros_ec_get_features(dev, &feat);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(feat_name); i++) {
if (feat & (1ULL << i)) {
if (feat_name[i])
printf("%s\n", feat_name[i]);
else
printf("unknown %d\n", i);
}
}
return 0;
}
static const char *const switch_name[8] = {
"lid open",
"power button pressed",
"write-protect disabled",
NULL,
"dedicated recovery",
NULL,
NULL,
NULL,
};
static int do_show_switches(struct udevice *dev)
{
uint switches;
int ret;
uint i;
ret = cros_ec_get_switches(dev);
if (ret < 0)
return log_msg_ret("get", ret);
switches = ret;
for (i = 0; i < ARRAY_SIZE(switch_name); i++) {
uint mask = 1 << i;
if (switches & mask) {
if (switch_name[i])
printf("%s\n", switch_name[i]);
else
printf("unknown %02x\n", mask);
}
}
return 0;
}
static const char *const event_name[] = {
"lid_closed",
"lid_open",
"power_button",
"ac_connected",
"ac_disconnected",
"battery_low",
"battery_critical",
"battery",
"thermal_threshold",
"device",
"thermal",
"usb_charger",
"key_pressed",
"interface_ready",
"keyboard_recovery",
"thermal_shutdown",
"battery_shutdown",
"throttle_start",
"throttle_stop",
"hang_detect",
"hang_reboot",
"pd_mcu",
"battery_status",
"panic",
"keyboard_fastboot",
"rtc",
"mkbp",
"usb_mux",
"mode_change",
"keyboard_recovery_hw_reinit",
"extended",
"invalid",
};
static int do_show_events(struct udevice *dev)
{
u32 events;
int ret;
uint i;
ret = cros_ec_get_host_events(dev, &events);
if (ret)
return ret;
printf("%08x\n", events);
for (i = 0; i < ARRAY_SIZE(event_name); i++) {
enum host_event_code code = i + 1;
u64 mask = EC_HOST_EVENT_MASK(code);
if (events & mask) {
if (event_name[i])
printf("%s\n", event_name[i]);
else
printf("unknown code %#x\n", code);
}
}
return 0;
}
static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@ -140,6 +303,16 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
}
printf("rows = %u\n", info.rows);
printf("cols = %u\n", info.cols);
} else if (!strcmp("features", cmd)) {
ret = do_show_features(dev);
if (ret)
printf("Error: %d\n", ret);
} else if (!strcmp("switches", cmd)) {
ret = do_show_switches(dev);
if (ret)
printf("Error: %d\n", ret);
} else if (0 == strcmp("curimage", cmd)) {
enum ec_current_image image;
@ -190,13 +363,10 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
return 1;
}
} else if (0 == strcmp("events", cmd)) {
uint32_t events;
ret = do_show_events(dev);
if (cros_ec_get_host_events(dev, &events)) {
debug("%s: Could not read host events\n", __func__);
return 1;
}
printf("0x%08x\n", events);
if (ret)
printf("Error: %d\n", ret);
} else if (0 == strcmp("clrevents", cmd)) {
uint32_t events = 0x7fffffff;
@ -352,6 +522,15 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
debug("%s: Could not access LDO%d\n", __func__, index);
return ret;
}
} else if (!strcmp("sku", cmd)) {
ret = cros_ec_get_sku_id(dev);
if (ret >= 0) {
printf("%d\n", ret);
ret = 0;
} else {
printf("Error: %d\n", ret);
}
} else {
return CMD_RET_USAGE;
}
@ -370,10 +549,13 @@ U_BOOT_CMD(
"init Re-init CROS-EC (done on startup automatically)\n"
"crosec id Read CROS-EC ID\n"
"crosec info Read CROS-EC info\n"
"crosec features Read CROS-EC features\n"
"crosec switches Read CROS-EC switches\n"
"crosec curimage Read CROS-EC current image\n"
"crosec hash Read CROS-EC hash\n"
"crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
"crosec events Read CROS-EC host events\n"
"crosec eventsb Read CROS-EC host events_b\n"
"crosec clrevents [mask] Clear CROS-EC host events\n"
"crosec regioninfo <ro|rw> Read image info\n"
"crosec flashinfo Read flash info\n"
@ -382,6 +564,7 @@ U_BOOT_CMD(
"crosec write <ro|rw> <addr> [<size>] Write EC image\n"
"crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
"crosec ldo <idx> [<state>] Switch/Read LDO state\n"
"crosec sku Read board SKU ID\n"
"crosec test run tests on cros_ec\n"
"crosec version Read CROS-EC version"
);

View File

@ -29,6 +29,7 @@ CONFIG_BOOTSTAGE_REPORT=y
CONFIG_SPL_BOOTSTAGE_RECORD_COUNT=10
CONFIG_BOOTSTAGE_STASH=y
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS_SUBST=y
CONFIG_SYS_CONSOLE_INFO_QUIET=y
CONFIG_LOGF_FUNC=y
CONFIG_SPL_LOG=y

View File

@ -101,7 +101,6 @@ CONFIG_SYSCON=y
CONFIG_SPL_SYSCON=y
CONFIG_DEVRES=y
CONFIG_DEBUG_DEVRES=y
# CONFIG_SPL_SIMPLE_BUS is not set
CONFIG_ADC=y
CONFIG_ADC_SANDBOX=y
CONFIG_AXI=y

View File

@ -150,6 +150,7 @@ void dev_print (struct blk_desc *dev_desc)
case IF_TYPE_USB:
case IF_TYPE_NVME:
case IF_TYPE_PVBLOCK:
case IF_TYPE_HOST:
printf ("Vendor: %s Rev: %s Prod: %s\n",
dev_desc->vendor,
dev_desc->revision,

View File

@ -99,37 +99,44 @@ Command-line Options
Various options are available, mostly for test purposes. Use -h to see
available options. Some of these are described below:
* -t, --terminal <arg>
- The terminal is normally in what is called 'raw-with-sigs' mode. This means
-t, --terminal <arg>
The terminal is normally in what is called 'raw-with-sigs' mode. This means
that you can use arrow keys for command editing and history, but if you
press Ctrl-C, U-Boot will exit instead of handling this as a keypress.
Other options are 'raw' (so Ctrl-C is handled within U-Boot) and 'cooked'
(where the terminal is in cooked mode and cursor keys will not work, Ctrl-C
will exit).
* -l
- Show the LCD emulation window.
-l
Show the LCD emulation window.
* -d <device_tree>
- A device tree binary file can be provided with -d. If you edit the source
-d <device_tree>
A device tree binary file can be provided with -d. If you edit the source
(it is stored at arch/sandbox/dts/sandbox.dts) you must rebuild U-Boot to
recreate the binary file.
* -D
- To use the default device tree, use -D.
-D
To use the default device tree, use -D.
* -T
- To use the test device tree, use -T.
-T
To use the test device tree, use -T.
* -c [<cmd>;]<cmd>
- To execute commands directly, use the -c option. You can specify a single
-c [<cmd>;]<cmd>
To execute commands directly, use the -c option. You can specify a single
command, or multiple commands separated by a semicolon, as is normal in
U-Boot. Be careful with quoting as the shell will normally process and
swallow quotes. When -c is used, U-Boot exits after the command is complete,
but you can force it to go to interactive mode instead with -i.
* -i
- Go to interactive mode after executing the commands specified by -c.
-i
Go to interactive mode after executing the commands specified by -c.
Environment Variables
---------------------
UBOOT_SB_TIME_OFFSET
This environment variable stores the offset of the emulated real time clock
to the host's real time clock in seconds. The offset defaults to zero.
Memory Emulation
----------------

View File

@ -92,6 +92,7 @@ int host_dev_bind(int devnum, char *filename)
{
struct host_block_dev *host_dev;
struct udevice *dev;
struct blk_desc *desc;
char dev_name[20], *str, *fname;
int ret, fd;
@ -143,6 +144,12 @@ int host_dev_bind(int devnum, char *filename)
goto err_file;
}
desc = blk_get_devnum_by_type(IF_TYPE_HOST, devnum);
desc->removable = 1;
snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
snprintf(desc->revision, BLK_REV_SIZE, "1.0");
return 0;
err_file:
os_close(fd);
@ -187,6 +194,10 @@ int host_dev_bind(int dev, char *filename)
blk_dev->block_write = host_block_write;
blk_dev->devnum = dev;
blk_dev->part_type = PART_TYPE_UNKNOWN;
blk_dev->removable = 1;
snprintf(blk_dev->vendor, BLK_VEN_SIZE, "U-Boot");
snprintf(blk_dev->product, BLK_PRD_SIZE, "hostfile");
snprintf(blk_dev->revision, BLK_REV_SIZE, "1.0");
part_init(blk_dev);
return 0;

View File

@ -83,7 +83,7 @@ static int clk_get_by_index_tail(int ret, ofnode node,
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
__func__, ret);
return ret;
return log_msg_ret("get", ret);
}
clk->dev = dev_clk;
@ -96,14 +96,15 @@ static int clk_get_by_index_tail(int ret, ofnode node,
ret = clk_of_xlate_default(clk, args);
if (ret) {
debug("of_xlate() failed: %d\n", ret);
return ret;
return log_msg_ret("xlate", ret);
}
return clk_request(dev_clk, clk);
err:
debug("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n",
__func__, ofnode_get_name(node), list_name, index, ret);
return ret;
return log_msg_ret("prop", ret);
}
static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
@ -122,7 +123,7 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
if (ret) {
debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
__func__, ret);
return ret;
return log_ret(ret);
}
@ -470,6 +471,7 @@ int clk_free(struct clk *clk)
ulong clk_get_rate(struct clk *clk)
{
const struct clk_ops *ops;
int ret;
debug("%s(clk=%p)\n", __func__, clk);
if (!clk_valid(clk))
@ -479,7 +481,11 @@ ulong clk_get_rate(struct clk *clk)
if (!ops->get_rate)
return -ENOSYS;
return ops->get_rate(clk);
ret = ops->get_rate(clk);
if (ret)
return log_ret(ret);
return 0;
}
struct clk *clk_get_parent(struct clk *clk)

View File

@ -29,8 +29,8 @@ static const struct udevice_id intel_clk_ids[] = {
{ }
};
U_BOOT_DRIVER(clk_intel) = {
.name = "clk_intel",
U_BOOT_DRIVER(intel_apl_clk) = {
.name = "intel_apl_clk",
.id = UCLASS_CLK,
.of_match = intel_clk_ids,
.ops = &intel_clk_ops,

View File

@ -462,6 +462,15 @@ int device_probe(struct udevice *dev)
* continue regardless of the result of pinctrl. Don't process pinctrl
* settings for pinctrl devices since the device may not yet be
* probed.
*
* This call can produce some non-intuitive results. For example, on an
* x86 device where dev is the main PCI bus, the pinctrl device may be
* child or grandchild of that bus, meaning that the child will be
* probed here. If the child happens to be the P2SB and the pinctrl
* device is a child of that, then both the pinctrl and P2SB will be
* probed by this call. This works because the DM_FLAG_ACTIVATED flag
* is set just above. However, the PCI bus' probe() method and
* associated uclass methods have not yet been called.
*/
if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
pinctrl_select_state(dev, "default");

View File

@ -14,16 +14,17 @@
int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry)
{
const char *prop;
ofnode subnode;
if (ofnode_read_u32(node, "image-pos", &entry->offset)) {
debug("Node '%s' has bad/missing 'image-pos' property\n",
ofnode_get_name(node));
return log_ret(-ENOENT);
return log_msg_ret("image-pos", -ENOENT);
}
if (ofnode_read_u32(node, "size", &entry->length)) {
debug("Node '%s' has bad/missing 'size' property\n",
ofnode_get_name(node));
return log_ret(-ENOENT);
return log_msg_ret("size", -ENOENT);
}
entry->used = ofnode_read_s32_default(node, "used", entry->length);
prop = ofnode_read_string(node, "compress");
@ -31,18 +32,20 @@ int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry)
if (!strcmp(prop, "lz4"))
entry->compress_algo = FMAP_COMPRESS_LZ4;
else
return log_msg_ret("Unknown compression algo",
-EINVAL);
return log_msg_ret("compression algo", -EINVAL);
} else {
entry->compress_algo = FMAP_COMPRESS_NONE;
}
entry->unc_length = ofnode_read_s32_default(node, "uncomp-size",
entry->length);
prop = ofnode_read_string(node, "hash");
if (prop)
entry->hash_size = strlen(prop);
entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
entry->hash = (uint8_t *)prop;
subnode = ofnode_find_subnode(node, "hash");
if (ofnode_valid(subnode)) {
prop = ofnode_read_prop(subnode, "value", &entry->hash_size);
/* Assume it is sha256 */
entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
entry->hash = (uint8_t *)prop;
}
return 0;
}

View File

@ -39,7 +39,9 @@ obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
endif
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o

View File

@ -192,6 +192,8 @@ static const struct udevice_id designware_i2c_pci_ids[] = {
{ }
};
DM_DRIVER_ALIAS(i2c_designware_pci, intel_apl_i2c)
U_BOOT_DRIVER(i2c_designware_pci) = {
.name = "i2c_designware_pci",
.id = UCLASS_I2C,

View File

@ -44,6 +44,10 @@ enum {
CROS_EC_CMD_TIMEOUT_MS = 5000,
/* Timeout waiting for a synchronous hash to be recomputed */
CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
/* Wait 10 ms between attempts to check if EC's hash is ready */
CROS_EC_HASH_CHECK_DELAY_MS = 10,
};
#define INVALID_HCMD 0xFF
@ -400,6 +404,8 @@ static int ec_command(struct udevice *dev, uint cmd, int cmd_version,
*/
if (din && in_buffer) {
assert(len <= din_len);
if (len > din_len)
return -ENOSPC;
memmove(din, in_buffer, len);
}
}
@ -502,9 +508,10 @@ static int cros_ec_wait_on_hash_done(struct udevice *dev,
start = get_timer(0);
while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) {
mdelay(50); /* Insert some reasonable delay */
mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
p->cmd = EC_VBOOT_HASH_GET;
if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, p, sizeof(*p), hash,
sizeof(*hash)) < 0)
return -1;
@ -591,6 +598,25 @@ static int cros_ec_invalidate_hash(struct udevice *dev)
return 0;
}
int cros_ec_hello(struct udevice *dev, uint *handshakep)
{
struct ec_params_hello req;
struct ec_response_hello *resp;
req.in_data = 0x12345678;
if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
(uint8_t **)&resp, sizeof(*resp)) < 0)
return -EIO;
if (resp->out_data != req.in_data + 0x01020304) {
printf("Received invalid handshake %x\n", resp->out_data);
if (handshakep)
*handshakep = req.in_data;
return -ENOTSYNC;
}
return 0;
}
int cros_ec_reboot(struct udevice *dev, enum ec_reboot_cmd cmd, uint8_t flags)
{
struct ec_params_reboot_ec p;
@ -603,18 +629,23 @@ int cros_ec_reboot(struct udevice *dev, enum ec_reboot_cmd cmd, uint8_t flags)
return -1;
if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
ulong start;
/*
* EC reboot will take place immediately so delay to allow it
* to complete. Note that some reboot types (EC_REBOOT_COLD)
* will reboot the AP as well, in which case we won't actually
* get to this point.
*/
/*
* TODO(rspangler@chromium.org): Would be nice if we had a
* better way to determine when the reboot is complete. Could
* we poll a memory-mapped LPC value?
*/
udelay(50000);
mdelay(50);
start = get_timer(0);
while (cros_ec_hello(dev, NULL)) {
if (get_timer(start) > 3000) {
log_err("EC did not return from reboot\n");
return -ETIMEDOUT;
}
mdelay(5);
}
}
return 0;
@ -738,7 +769,6 @@ static int cros_ec_check_version(struct udevice *dev)
{
struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
struct ec_params_hello req;
struct ec_response_hello *resp;
struct dm_cros_ec_ops *ops;
int ret;
@ -767,14 +797,14 @@ static int cros_ec_check_version(struct udevice *dev)
/* Try sending a version 3 packet */
cdev->protocol_version = 3;
req.in_data = 0;
if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
(uint8_t **)&resp, sizeof(*resp)) > 0)
ret = cros_ec_hello(dev, NULL);
if (!ret || ret == -ENOTSYNC)
return 0;
/* Try sending a version 2 packet */
cdev->protocol_version = 2;
if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
(uint8_t **)&resp, sizeof(*resp)) > 0)
ret = cros_ec_hello(dev, NULL);
if (!ret || ret == -ENOTSYNC)
return 0;
/*
@ -790,18 +820,16 @@ static int cros_ec_check_version(struct udevice *dev)
int cros_ec_test(struct udevice *dev)
{
struct ec_params_hello req;
struct ec_response_hello *resp;
uint out_data;
int ret;
req.in_data = 0x12345678;
if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
(uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
ret = cros_ec_hello(dev, &out_data);
if (ret == -ENOTSYNC) {
printf("Received invalid handshake %x\n", out_data);
return ret;
} else if (ret) {
printf("ec_command_inptr() returned error\n");
return -1;
}
if (resp->out_data != req.in_data + 0x01020304) {
printf("Received invalid handshake %x\n", resp->out_data);
return -1;
return ret;
}
return 0;
@ -1077,6 +1105,19 @@ int cros_ec_flash_update_rw(struct udevice *dev, const uint8_t *image,
return 0;
}
int cros_ec_get_sku_id(struct udevice *dev)
{
struct ec_sku_id_info *r;
int ret;
ret = ec_command_inptr(dev, EC_CMD_GET_SKU_ID, 0, NULL, 0,
(uint8_t **)&r, sizeof(*r));
if (ret != sizeof(*r))
return -ret;
return r->sku_id;
}
int cros_ec_read_nvdata(struct udevice *dev, uint8_t *block, int size)
{
struct ec_params_vbnvcontext p;
@ -1303,19 +1344,33 @@ int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in,
return 0;
}
int cros_ec_check_feature(struct udevice *dev, int feature)
int cros_ec_get_features(struct udevice *dev, u64 *featuresp)
{
struct ec_response_get_features r;
int rv;
rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, &r, sizeof(r), NULL, 0);
if (rv)
return rv;
rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r));
if (rv != sizeof(r))
return -EIO;
*featuresp = r.flags[0] | (u64)r.flags[1] << 32;
return 0;
}
int cros_ec_check_feature(struct udevice *dev, uint feature)
{
struct ec_response_get_features r;
int rv;
rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r));
if (rv != sizeof(r))
return -EIO;
if (feature >= 8 * sizeof(r.flags))
return -1;
return -EINVAL;
return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature) ? true :
false;
}
/*
@ -1502,10 +1557,99 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable)
return 0;
}
int cros_ec_vstore_supported(struct udevice *dev)
{
return cros_ec_check_feature(dev, EC_FEATURE_VSTORE);
}
int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp)
{
struct ec_response_vstore_info *resp;
if (ec_command_inptr(dev, EC_CMD_VSTORE_INFO, 0, NULL, 0,
(uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
return -EIO;
if (lockedp)
*lockedp = resp->slot_locked;
return resp->slot_count;
}
/*
* cros_ec_vstore_read - Read data from EC vstore slot
*
* @slot: vstore slot to read from
* @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes
*/
int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data)
{
struct ec_params_vstore_read req;
struct ec_response_vstore_read *resp;
req.slot = slot;
if (ec_command_inptr(dev, EC_CMD_VSTORE_READ, 0, &req, sizeof(req),
(uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
return -EIO;
if (!data || req.slot >= EC_VSTORE_SLOT_MAX)
return -EINVAL;
memcpy(data, resp->data, sizeof(resp->data));
return 0;
}
/*
* cros_ec_vstore_write - Save data into EC vstore slot
*
* @slot: vstore slot to write into
* @data: data to write
* @size: size of data in bytes
*
* Maximum size of data is EC_VSTORE_SLOT_SIZE. It is the callers
* responsibility to check the number of implemented slots by
* querying the vstore info.
*/
int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data,
size_t size)
{
struct ec_params_vstore_write req;
if (slot >= EC_VSTORE_SLOT_MAX || size > EC_VSTORE_SLOT_SIZE)
return -EINVAL;
req.slot = slot;
memcpy(req.data, data, size);
if (ec_command(dev, EC_CMD_VSTORE_WRITE, 0, &req, sizeof(req), NULL, 0))
return -EIO;
return 0;
}
int cros_ec_get_switches(struct udevice *dev)
{
struct dm_cros_ec_ops *ops;
int ret;
ops = dm_cros_ec_get_ops(dev);
if (!ops->get_switches)
return -ENOSYS;
ret = ops->get_switches(dev);
if (ret < 0)
return log_msg_ret("get", ret);
return ret;
}
UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
.name = "cros-ec",
.per_device_auto = sizeof(struct cros_ec_dev),
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.post_bind = dm_scan_fdt_dev,
#endif
.flags = DM_UC_FLAG_ALLOC_PRIV_DMA,
};

View File

@ -207,6 +207,12 @@ int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob)
return 0;
}
/* Return the byte of EC switch states */
static int cros_ec_lpc_get_switches(struct udevice *dev)
{
return inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SWITCHES);
}
/*
* Test if LPC command args are supported.
*
@ -239,6 +245,7 @@ static struct dm_cros_ec_ops cros_ec_ops = {
.packet = cros_ec_lpc_packet,
.command = cros_ec_lpc_command,
.check_version = cros_ec_lpc_check_version,
.get_switches = cros_ec_lpc_get_switches,
};
static const struct udevice_id cros_ec_ids[] = {

View File

@ -18,6 +18,7 @@
#include <asm/malloc.h>
#include <asm/state.h>
#include <asm/sdl.h>
#include <asm/test.h>
#include <linux/input.h>
/*
@ -61,6 +62,15 @@ struct ec_keymatrix_entry {
int keycode; /* corresponding linux key code */
};
enum {
VSTORE_SLOT_COUNT = 4,
};
struct vstore_slot {
bool locked;
u8 data[EC_VSTORE_SLOT_SIZE];
};
/**
* struct ec_state - Information about the EC state
*
@ -73,6 +83,8 @@ struct ec_keymatrix_entry {
* @matrix: Information about keyboard matrix
* @keyscan: Current keyscan information (bit set for each row/column pressed)
* @recovery_req: Keyboard recovery requested
* @test_flags: Flags that control behaviour for tests
* @slot_locked: Locked vstore slots (mask)
*/
struct ec_state {
u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2];
@ -84,6 +96,8 @@ struct ec_state {
struct ec_keymatrix_entry *matrix; /* the key matrix info */
uint8_t keyscan[KEYBOARD_COLS];
bool recovery_req;
uint test_flags;
struct vstore_slot slot[VSTORE_SLOT_COUNT];
} s_state, *g_state;
/**
@ -295,6 +309,8 @@ static int process_cmd(struct ec_state *ec,
struct ec_response_hello *resp = resp_data;
resp->out_data = req->in_data + 0x01020304;
if (ec->test_flags & CROSECT_BREAK_HELLO)
resp->out_data++;
len = sizeof(*resp);
break;
}
@ -358,10 +374,20 @@ static int process_cmd(struct ec_state *ec,
resp->mask |= EC_HOST_EVENT_MASK(
EC_HOST_EVENT_KEYBOARD_RECOVERY);
}
if (ec->test_flags & CROSECT_LID_OPEN)
resp->mask |=
EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN);
len = sizeof(*resp);
break;
}
case EC_CMD_HOST_EVENT_CLEAR_B: {
const struct ec_params_host_event_mask *req = req_data;
if (req->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN))
ec->test_flags &= ~CROSECT_LID_OPEN;
len = 0;
break;
}
case EC_CMD_VBOOT_HASH: {
const struct ec_params_vboot_hash *req = req_data;
struct ec_response_vboot_hash *resp = resp_data;
@ -468,6 +494,62 @@ static int process_cmd(struct ec_state *ec,
len = sizeof(*resp);
break;
}
case EC_CMD_GET_SKU_ID: {
struct ec_sku_id_info *resp = resp_data;
resp->sku_id = 1234;
len = sizeof(*resp);
break;
}
case EC_CMD_GET_FEATURES: {
struct ec_response_get_features *resp = resp_data;
resp->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FLASH) |
EC_FEATURE_MASK_0(EC_FEATURE_I2C) |
EC_FEATURE_MASK_0(EC_FEATURE_VSTORE);
resp->flags[1] =
EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS) |
EC_FEATURE_MASK_1(EC_FEATURE_ISH);
len = sizeof(*resp);
break;
}
case EC_CMD_VSTORE_INFO: {
struct ec_response_vstore_info *resp = resp_data;
int i;
resp->slot_count = VSTORE_SLOT_COUNT;
resp->slot_locked = 0;
for (i = 0; i < VSTORE_SLOT_COUNT; i++) {
if (ec->slot[i].locked)
resp->slot_locked |= 1 << i;
}
len = sizeof(*resp);
break;
};
case EC_CMD_VSTORE_WRITE: {
const struct ec_params_vstore_write *req = req_data;
struct vstore_slot *slot;
if (req->slot >= EC_VSTORE_SLOT_MAX)
return -EINVAL;
slot = &ec->slot[req->slot];
slot->locked = true;
memcpy(slot->data, req->data, EC_VSTORE_SLOT_SIZE);
len = 0;
break;
}
case EC_CMD_VSTORE_READ: {
const struct ec_params_vstore_read *req = req_data;
struct ec_response_vstore_read *resp = resp_data;
struct vstore_slot *slot;
if (req->slot >= EC_VSTORE_SLOT_MAX)
return -EINVAL;
slot = &ec->slot[req->slot];
memcpy(resp->data, slot->data, EC_VSTORE_SLOT_SIZE);
len = sizeof(*resp);
break;
}
default:
printf(" ** Unknown EC command %#02x\n", req_hdr->command);
return -1;
@ -518,6 +600,21 @@ void cros_ec_check_keyboard(struct udevice *dev)
}
}
/* Return the byte of EC switch states */
static int cros_ec_sandbox_get_switches(struct udevice *dev)
{
struct ec_state *ec = dev_get_priv(dev);
return ec->test_flags & CROSECT_LID_OPEN ? EC_SWITCH_LID_OPEN : 0;
}
void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags)
{
struct ec_state *ec = dev_get_priv(dev);
ec->test_flags = flags;
}
int cros_ec_probe(struct udevice *dev)
{
struct ec_state *ec = dev_get_priv(dev);
@ -573,6 +670,7 @@ int cros_ec_probe(struct udevice *dev)
struct dm_cros_ec_ops cros_ec_ops = {
.packet = cros_ec_sandbox_packet,
.get_switches = cros_ec_sandbox_get_switches,
};
static const struct udevice_id cros_ec_ids[] = {

View File

@ -57,6 +57,7 @@ long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
plat->use_system_time = use_system_time;
if (offset != -1)
plat->offset = offset;
os_set_time_offset(plat->offset);
return old_offset;
}
@ -80,7 +81,7 @@ static void reset_time(struct udevice *dev)
os_localtime(&now);
plat->base_time = rtc_mktime(&now);
plat->offset = 0;
plat->offset = os_get_time_offset();
plat->use_system_time = true;
}
@ -115,6 +116,7 @@ static int sandbox_i2c_rtc_set(struct udevice *dev, const struct rtc_time *time)
now = plat->base_time;
}
plat->offset = rtc_mktime(time) - now;
os_set_time_offset(plat->offset);
return 0;
}

View File

@ -183,23 +183,31 @@ static int cr50_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer,
return cr50_i2c_wait_tpm_ready(dev);
}
static inline u8 tpm_access(u8 locality)
static inline u8 tpm_access(int locality)
{
if (locality == -1)
locality = 0;
return 0x0 | (locality << 4);
}
static inline u8 tpm_sts(u8 locality)
static inline u8 tpm_sts(int locality)
{
if (locality == -1)
locality = 0;
return 0x1 | (locality << 4);
}
static inline u8 tpm_data_fifo(u8 locality)
static inline u8 tpm_data_fifo(int locality)
{
if (locality == -1)
locality = 0;
return 0x5 | (locality << 4);
}
static inline u8 tpm_did_vid(u8 locality)
static inline u8 tpm_did_vid(int locality)
{
if (locality == -1)
locality = 0;
return 0x6 | (locality << 4);
}
@ -372,7 +380,6 @@ out_err:
static int cr50_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
{
struct cr50_priv *priv = dev_get_priv(dev);
int status;
size_t burstcnt, limit, sent = 0;
u8 tpm_go[4] = { TPM_STS_GO };
@ -549,9 +556,23 @@ static int cr50_i2c_get_desc(struct udevice *dev, char *buf, int size)
{
struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
struct cr50_priv *priv = dev_get_priv(dev);
int len;
return snprintf(buf, size, "cr50 TPM 2.0 (i2c %02x id %x) irq=%d",
chip->chip_addr, priv->vendor >> 16, priv->use_irq);
len = snprintf(buf, size, "cr50 TPM 2.0 (i2c %02x id %x), ",
chip->chip_addr, priv->vendor >> 16);
if (priv->use_irq) {
len += snprintf(buf + len, size - len, "irq=%s/%ld",
priv->irq.dev->name, priv->irq.id);
} else if (dm_gpio_is_valid(&priv->ready_gpio)) {
len += snprintf(buf + len, size - len, "gpio=%s/%u",
priv->ready_gpio.dev->name,
priv->ready_gpio.offset);
} else {
len += snprintf(buf + len, size - len, "delay=%d",
TIMEOUT_NO_IRQ_US);
}
return len;
}
static int cr50_i2c_open(struct udevice *dev)
@ -694,11 +715,12 @@ static int cr50_i2c_probe(struct udevice *dev)
mdelay(10);
}
if (vendor != CR50_DID_VID) {
log_debug("DID_VID %08x not recognised\n", vendor);
log_warning("DID_VID %08x not recognised\n", vendor);
return log_msg_ret("vendor-id", -EXDEV);
}
priv->vendor = vendor;
priv->locality = -1;
log_debug("Cr50 ready\n");
return 0;
}
@ -720,8 +742,8 @@ static const struct udevice_id cr50_i2c_ids[] = {
{ }
};
U_BOOT_DRIVER(cr50_i2c) = {
.name = "cr50_i2c",
U_BOOT_DRIVER(google_cr50) = {
.name = "google_cr50",
.id = UCLASS_TPM,
.of_match = cr50_i2c_ids,
.ops = &cr50_i2c_ops,

View File

@ -234,11 +234,61 @@ int cros_ec_flash_update_rw(struct udevice *dev, const uint8_t *image,
struct udevice *board_get_cros_ec_dev(void);
struct dm_cros_ec_ops {
/**
* check_version() - Check the protocol version being used (optional)
*
* If provided, this function should check that the EC can be supported
* by the driver. If not provided, HELLO messages will be sent to try
* to determine the protocol version.
*
* @dev: Device to check
* @return 0 if the protocol is valid, -ve if not supported
*/
int (*check_version)(struct udevice *dev);
/**
* command() - Old-style command interface
*
* This sends a command and receives a response (deprecated, use
* packet())
*
* @dev: Device to use
* @cmd: Command to send (only supports 0-0xff)
* @cmd_version: Version of command to send (often 0)
* @dout: Output data (may be NULL If dout_len=0)
* @dout_len: Length of output data excluding 4-byte header
* @dinp: On input, set to point to input data, often struct
* cros_ec_dev->din - typically this is left alone but may be
* updated by the driver
* @din_len: Maximum length of response
* @return number of bytes in response, or -ve on error
*/
int (*command)(struct udevice *dev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len);
/**
* packet() - New-style command interface
*
* This interface is preferred over command(), since it is typically
* easier to implement.
*
* @dev: Device to use
* @out_bytes: Number of bytes to send (from struct cros_ec_dev->dout)
* @in_bytes: Maximum number of bytes to expect in response
* @return number of bytes in response, or -ve on error
*/
int (*packet)(struct udevice *dev, int out_bytes, int in_bytes);
/**
* get_switches() - Get value of EC switches
*
* This is currently supported on the LPC EC.
*
* @dev: Device to use
* @return current switches value, or -ENOSYS if not supported
*/
int (*get_switches)(struct udevice *dev);
};
#define dm_cros_ec_get_ops(dev) \
@ -329,6 +379,14 @@ int cros_ec_flash_write(struct udevice *dev, const uint8_t *data,
int cros_ec_flash_offset(struct udevice *dev, enum ec_flash_region region,
uint32_t *offset, uint32_t *size);
/**
* cros_ec_get_sku_id() - Read the SKU ID
*
* @dev: CROS-EC device
* return SKU ID, or -ve on error
*/
int cros_ec_get_sku_id(struct udevice *dev);
/**
* Read/write non-volatile data from/to a CROS-EC device.
*
@ -497,4 +555,88 @@ int cros_ec_get_lid_shutdown_mask(struct udevice *dev);
*/
int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable);
/**
* cros_ec_hello() - Send a hello message
*
* Sends a message with a fixed input value and checks that the expected output
* value is received
*
* @dev: CROS-EC device
* @handshakep: If non-NULL, returns received handshake value on error
* @return 0 if OK, -ve on error
*/
int cros_ec_hello(struct udevice *dev, uint *handshakep);
/**
* cros_ec_get_features() - Get the set of features provided by the EC
*
* See enum ec_feature_code for the list of available features
*
* @dev: CROS-EC device
* @featuresp: Returns a bitmask of supported features
* @return 0 if OK, -ve on error
*/
int cros_ec_get_features(struct udevice *dev, u64 *featuresp);
/**
* cros_ec_check_feature() - Check if a feature is supported
*
* @dev: CROS-EC device
* @feature: Feature number to check (enum ec_feature_code)
* @return true if supported, false if not, -ve on error
*/
int cros_ec_check_feature(struct udevice *dev, uint feature);
/**
* cros_ec_get_switches() - Get switches value
*
* @dev: CROS-EC device
* @return switches value, or -ENOSYS if not supported, or other -ve value on
* other error
*/
int cros_ec_get_switches(struct udevice *dev);
/**
* cros_ec_vstore_supported() - Check if vstore is supported
*
* @dev: CROS-EC device
* @return false if not supported, true if supported, -ve on error
*/
int cros_ec_vstore_supported(struct udevice *dev);
/**
* cros_ec_vstore_info() - Get vstore information
*
* @dev: CROS-EC device
* @lockedp: mask of locked slots
* @return number of vstore slots supported by the EC,, -ve on error
*/
int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp);
/**
* cros_ec_vstore_read() - Read data from EC vstore slot
*
* @dev: CROS-EC device
* @slot: vstore slot to read from
* @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes
* @return 0 if OK, -ve on error
*/
int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data);
/**
* cros_ec_vstore_write() - Save data into EC vstore slot
*
* The maximum size of data is EC_VSTORE_SLOT_SIZE. It is the caller's
* responsibility to check the number of implemented slots by querying the
* vstore info.
*
* @dev: CROS-EC device
* @slot: vstore slot to write into
* @data: data to write
* @size: size of data in bytes
* @return 0 if OK, -ve on error
*/
int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data,
size_t size);
#endif

1
include/ctype.h Symbolic link
View File

@ -0,0 +1 @@
linux/ctype.h

View File

@ -111,7 +111,7 @@ enum {
* probe method if the device has a device tree node.
*
* All three of plat, priv and uclass_priv can be allocated by the
* driver, or you can use the auto_alloc_size members of struct driver and
* driver, or you can use the auto members of struct driver and
* struct uclass_driver to have driver model do this automatically.
*
* @driver: The driver used by this device

View File

@ -30,8 +30,7 @@ static inline const struct device_node *dev_np(const struct udevice *dev)
}
#endif
#ifndef CONFIG_DM_DEV_READ_INLINE
#if !defined(CONFIG_DM_DEV_READ_INLINE) || CONFIG_IS_ENABLED(OF_PLATDATA)
/**
* dev_read_u32() - read a 32-bit integer from a device's DT property
*
@ -1007,7 +1006,7 @@ static inline u64 dev_translate_dma_address(const struct udevice *dev,
static inline int dev_read_alias_highest_id(const char *stem)
{
if (!CONFIG_IS_ENABLED(OF_LIBFDT))
if (!CONFIG_IS_ENABLED(OF_LIBFDT) || !gd->fdt_blob)
return -1;
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
}

View File

@ -1101,13 +1101,50 @@ enum ec_feature_code {
EC_FEATURE_DEVICE_EVENT = 31,
/* EC supports the unified wake masks for LPC/eSPI systems */
EC_FEATURE_UNIFIED_WAKE_MASKS = 32,
/* EC supports 64-bit host events */
EC_FEATURE_HOST_EVENT64 = 33,
/* EC runs code in RAM (not in place, a.k.a. XIP) */
EC_FEATURE_EXEC_IN_RAM = 34,
/* EC supports CEC commands */
EC_FEATURE_CEC = 35,
/* EC supports tight sensor timestamping. */
EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36,
/*
* EC supports tablet mode detection aligned to Chrome and allows
* setting of threshold by host command using
* MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE.
*/
EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37,
/*
* Early Firmware Selection ver.2. Enabled by CONFIG_VBOOT_EFS2.
* Note this is a RO feature. So, a query (EC_CMD_GET_FEATURES) should
* be sent to RO to be precise.
*/
EC_FEATURE_EFS2 = 38,
/* The MCU is a System Companion Processor (SCP). */
EC_FEATURE_SCP = 39,
/* The MCU is an Integrated Sensor Hub */
EC_FEATURE_ISH = 40,
/* New TCPMv2 TYPEC_ prefaced commands supported */
EC_FEATURE_TYPEC_CMD = 41,
/*
* The EC will wait for direction from the AP to enter Type-C alternate
* modes or USB4.
*/
EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY = 42,
/*
* The EC will wait for an acknowledge from the AP after setting the
* mux.
*/
EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK = 43,
};
#define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32))
#define EC_FEATURE_MASK_1(event_code) (1UL << (event_code - 32))
struct __ec_align4 ec_response_get_features {
#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32)
#define EC_FEATURE_MASK_1(event_code) BIT(event_code - 32)
struct ec_response_get_features {
uint32_t flags[2];
};
} __ec_align4;
/*****************************************************************************/
/* Get the board's SKU ID from EC */

View File

@ -424,4 +424,22 @@ int os_setup_signal_handlers(void);
*/
void os_signal_action(int sig, unsigned long pc);
/**
* os_get_time_offset() - get time offset
*
* Get the time offset from environment variable UBOOT_SB_TIME_OFFSET.
*
* Return: offset in seconds
*/
long os_get_time_offset(void);
/**
* os_set_time_offset() - set time offset
*
* Save the time offset in environment variable UBOOT_SB_TIME_OFFSET.
*
* @offset: offset in seconds
*/
void os_set_time_offset(long offset);
#endif

View File

@ -145,6 +145,8 @@ int binman_init(void)
if (ret)
return log_msg_ret("node", -ENOENT);
binman_set_rom_offset(ROM_OFFSET_NONE);
log_debug("binman: Selected image node '%s'\n",
ofnode_get_name(binman->image));
return 0;
}

View File

@ -24,6 +24,7 @@ obj-$(CONFIG_BLK) += blk.o
obj-$(CONFIG_BUTTON) += button.o
obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
obj-$(CONFIG_CLK) += clk.o clk_ccf.o
obj-$(CONFIG_CROS_EC) += cros_ec.o
obj-$(CONFIG_DEVRES) += devres.o
obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o
obj-$(CONFIG_DM_ETH) += eth.o
@ -41,6 +42,7 @@ obj-y += fdtdec.o
obj-$(CONFIG_UT_DM) += nop.o
obj-y += ofnode.o
obj-y += ofread.o
obj-y += of_extra.o
obj-$(CONFIG_OSD) += osd.o
obj-$(CONFIG_DM_VIDEO) += panel.o
obj-$(CONFIG_DM_PCI) += pci.o

178
test/dm/cros_ec.c Normal file
View File

@ -0,0 +1,178 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2021 Google LLC
*/
#include <common.h>
#include <cros_ec.h>
#include <dm.h>
#include <asm/test.h>
#include <dm/test.h>
#include <test/ut.h>
static int dm_test_cros_ec_hello(struct unit_test_state *uts)
{
struct udevice *dev;
uint val;
ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
ut_assertok(cros_ec_hello(dev, NULL));
val = 0xdead1357;
ut_assertok(cros_ec_hello(dev, &val));
ut_asserteq(0xdead1357, val);
sandbox_cros_ec_set_test_flags(dev, CROSECT_BREAK_HELLO);
ut_asserteq(-ENOTSYNC, cros_ec_hello(dev, &val));
ut_asserteq(0x12345678, val);
return 0;
}
DM_TEST(dm_test_cros_ec_hello, UT_TESTF_SCAN_FDT);
static int dm_test_cros_ec_sku_id(struct unit_test_state *uts)
{
struct udevice *dev;
ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
ut_asserteq(1234, cros_ec_get_sku_id(dev));
/* try the command */
console_record_reset();
ut_assertok(run_command("crosec sku", 0));
ut_assert_nextline("1234");
ut_assert_console_end();
return 0;
}
DM_TEST(dm_test_cros_ec_sku_id, UT_TESTF_SCAN_FDT);
static int dm_test_cros_ec_features(struct unit_test_state *uts)
{
struct udevice *dev;
u64 feat;
ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
ut_assertok(cros_ec_get_features(dev, &feat));
ut_asserteq_64(1U << EC_FEATURE_FLASH | 1U << EC_FEATURE_I2C |
1u << EC_FEATURE_VSTORE |
1ULL << EC_FEATURE_UNIFIED_WAKE_MASKS | 1ULL << EC_FEATURE_ISH,
feat);
ut_asserteq(true, cros_ec_check_feature(dev, EC_FEATURE_I2C));
ut_asserteq(false, cros_ec_check_feature(dev, EC_FEATURE_MOTION_SENSE));
ut_asserteq(true, cros_ec_check_feature(dev, EC_FEATURE_ISH));
/* try the command */
console_record_reset();
ut_assertok(run_command("crosec features", 0));
ut_assert_nextline("flash");
ut_assert_nextline("i2c");
ut_assert_nextline("vstore");
ut_assert_nextline("unified_wake_masks");
ut_assert_nextline("ish");
ut_assert_console_end();
return 0;
}
DM_TEST(dm_test_cros_ec_features, UT_TESTF_SCAN_FDT);
static int dm_test_cros_ec_switches(struct unit_test_state *uts)
{
struct udevice *dev;
ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
ut_asserteq(0, cros_ec_get_switches(dev));
/* try the command */
console_record_reset();
ut_assertok(run_command("crosec switches", 0));
ut_assert_console_end();
/* Open the lid and check the switch changes */
sandbox_cros_ec_set_test_flags(dev, CROSECT_LID_OPEN);
ut_asserteq(EC_SWITCH_LID_OPEN, cros_ec_get_switches(dev));
/* try the command */
console_record_reset();
ut_assertok(run_command("crosec switches", 0));
ut_assert_nextline("lid open");
ut_assert_console_end();
return 0;
}
DM_TEST(dm_test_cros_ec_switches, UT_TESTF_SCAN_FDT);
static int dm_test_cros_ec_events(struct unit_test_state *uts)
{
struct udevice *dev;
u32 events;
ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
ut_assertok(cros_ec_get_host_events(dev, &events));
ut_asserteq(0, events);
/* try the command */
console_record_reset();
ut_assertok(run_command("crosec events", 0));
ut_assert_nextline("00000000");
ut_assert_console_end();
/* Open the lid and check the event appears */
sandbox_cros_ec_set_test_flags(dev, CROSECT_LID_OPEN);
ut_assertok(cros_ec_get_host_events(dev, &events));
ut_asserteq(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN), events);
/* try the command */
console_record_reset();
ut_assertok(run_command("crosec events", 0));
ut_assert_nextline("00000002");
ut_assert_nextline("lid_open");
ut_assert_console_end();
/* Clear the event */
ut_assertok(cros_ec_clear_host_events(dev,
EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN)));
ut_assertok(cros_ec_get_host_events(dev, &events));
ut_asserteq(0, events);
return 0;
}
DM_TEST(dm_test_cros_ec_events, UT_TESTF_SCAN_FDT);
static int dm_test_cros_ec_vstore(struct unit_test_state *uts)
{
const int size = EC_VSTORE_SLOT_SIZE;
u8 test_data[size], data[size];
struct udevice *dev;
u32 locked;
int i;
ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
ut_asserteq(true, cros_ec_vstore_supported(dev));
ut_asserteq(4, cros_ec_vstore_info(dev, &locked));
ut_asserteq(0, locked);
/* Write some data */
for (i = 0; i < size; i++)
test_data[i] = ' ' + i;
ut_assertok(cros_ec_vstore_write(dev, 2, test_data, size));
/* Check it is locked */
ut_asserteq(4, cros_ec_vstore_info(dev, &locked));
ut_asserteq(1 << 2, locked);
/* Read it back and compare */
ut_assertok(cros_ec_vstore_read(dev, 2, data));
ut_asserteq_mem(test_data, data, size);
/* Try another slot to make sure it is empty */
ut_assertok(cros_ec_vstore_read(dev, 0, data));
for (i = 0; i < size; i++)
ut_asserteq(0, data[i]);
return 0;
}
DM_TEST(dm_test_cros_ec_vstore, UT_TESTF_SCAN_FDT);

38
test/dm/of_extra.c Normal file
View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2021 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <dm/of_extra.h>
#include <dm/test.h>
#include <test/ut.h>
#include <u-boot/sha256.h>
static int dm_test_ofnode_read_fmap_entry(struct unit_test_state *uts)
{
const char hash_expect[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
};
struct fmap_entry entry;
ofnode node;
node = ofnode_path("/cros-ec/flash/wp-ro");
ut_assertok(ofnode_read_fmap_entry(node, &entry));
ut_asserteq(0xf000, entry.offset);
ut_asserteq(0x1000, entry.length);
ut_asserteq(0x884, entry.used);
ut_asserteq(FMAP_COMPRESS_LZ4, entry.compress_algo);
ut_asserteq(0xcf8, entry.unc_length);
ut_asserteq(FMAP_HASH_SHA256, entry.hash_algo);
ut_asserteq(SHA256_SUM_LEN, entry.hash_size);
ut_asserteq_mem(hash_expect, entry.hash, SHA256_SUM_LEN);
return 0;
}
DM_TEST(dm_test_ofnode_read_fmap_entry, 0);

View File

@ -210,11 +210,11 @@ DM_TEST(dm_test_of_plat_phandle, UT_TESTF_SCAN_PDATA);
/* Test that device parents are correctly set up */
static int dm_test_of_plat_parent(struct unit_test_state *uts)
{
struct udevice *rtc, *i2c;
struct udevice *dev, *bus;
ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc));
ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c));
ut_asserteq_ptr(i2c, dev_get_parent(rtc));
ut_assertok(uclass_first_device_err(UCLASS_SIMPLE_BUS, &bus));
ut_assertok(device_first_child_err(bus, &dev));
ut_asserteq_ptr(bus, dev_get_parent(dev));
return 0;
}

View File

@ -1050,10 +1050,9 @@ Some ideas:
- Allow easy building of images by specifying just the board name
- Support building an image for a board (-b) more completely, with a
configurable build directory
- Support adding FITs to an image
- Support for ARM Trusted Firmware (ATF)
- Detect invalid properties in nodes
- Sort the fdtmap by offset
- Output temporary files to a different directory
--
Simon Glass <sjg@chromium.org>

View File

@ -244,7 +244,8 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
if not os.path.exists(fname):
os.makedirs(fname)
fname = os.path.join(fname, 'root')
tout.Notice("Write entry '%s' to '%s'" % (entry.GetPath(), fname))
tout.Notice("Write entry '%s' size %x to '%s'" %
(entry.GetPath(), len(data), fname))
tools.WriteFile(fname, data)
return einfos

View File

@ -132,7 +132,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section):
(msg, sym.size))
# Look up the symbol in our entry tables.
value = section.LookupSymbol(name, sym.weak, msg, base.address)
value = section.GetImage().LookupImageSymbol(name, sym.weak, msg,
base.address)
if value is None:
value = -1
pack_string = pack_string.lower()

View File

@ -45,10 +45,12 @@ class FakeSection:
def GetPath(self):
return 'section_path'
def LookupSymbol(self, name, weak, msg, base_addr):
def LookupImageSymbol(self, name, weak, msg, base_addr):
"""Fake implementation which returns the same value for all symbols"""
return self.sym_value
def GetImage(self):
return self
def BuildElfTestFiles(target_dir):
"""Build ELF files used for testing in binman

View File

@ -434,8 +434,7 @@ class Entry(object):
missing.append(prop.name)
values.append(value)
if missing:
self.Raise('Missing required properties/entry args: %s' %
(', '.join(missing)))
self.GetImage().MissingArgs(self, missing)
return values
def GetPath(self):

View File

@ -66,3 +66,7 @@ class Entry_blob(Entry):
def GetDefaultFilename(self):
return self._filename
def ProcessContents(self):
# The blob may have changed due to WriteSymbols()
return self.ProcessContentsUpdate(self.data)

View File

@ -22,6 +22,7 @@ class Entry_files(Entry_section):
- files-compress: Compression algorithm to use:
none: No compression
lz4: Use lz4 compression (via 'lz4' command-line utility)
- files-align: Align each file to the given alignment
This entry reads a number of files and places each in a separate sub-entry
within this entry. To access these you need to enable device-tree updates
@ -38,6 +39,7 @@ class Entry_files(Entry_section):
self.Raise("Missing 'pattern' property")
self._files_compress = fdt_util.GetString(self._node, 'files-compress',
'none')
self._files_align = fdt_util.GetInt(self._node, 'files-align');
self._require_matches = fdt_util.GetBool(self._node,
'require-matches')
@ -55,6 +57,8 @@ class Entry_files(Entry_section):
state.AddString(subnode, 'type', 'blob')
state.AddString(subnode, 'filename', fname)
state.AddString(subnode, 'compress', self._files_compress)
if self._files_align:
state.AddInt(subnode, 'align', self._files_align)
# Read entries again, now that we have some
self._ReadEntries()

View File

@ -385,7 +385,7 @@ class Entry_section(Entry):
return entry.GetData()
source_entry.Raise("Cannot find entry for node '%s'" % node.name)
def LookupSymbol(self, sym_name, optional, msg, base_addr):
def LookupSymbol(self, sym_name, optional, msg, base_addr, entries=None):
"""Look up a symbol in an ELF file
Looks up a symbol in an ELF file. Only entry types which come from an
@ -428,18 +428,20 @@ class Entry_section(Entry):
(msg, sym_name))
entry_name, prop_name = m.groups()
entry_name = entry_name.replace('_', '-')
entry = self._entries.get(entry_name)
if not entries:
entries = self._entries
entry = entries.get(entry_name)
if not entry:
if entry_name.endswith('-any'):
root = entry_name[:-4]
for name in self._entries:
for name in entries:
if name.startswith(root):
rest = name[len(root):]
if rest in ['', '-img', '-nodtb']:
entry = self._entries[name]
entry = entries[name]
if not entry:
err = ("%s: Entry '%s' not found in list (%s)" %
(msg, entry_name, ','.join(self._entries.keys())))
(msg, entry_name, ','.join(entries.keys())))
if optional:
print('Warning: %s' % err, file=sys.stderr)
return None
@ -603,10 +605,12 @@ class Entry_section(Entry):
def ReadData(self, decomp=True):
tout.Info("ReadData path='%s'" % self.GetPath())
parent_data = self.section.ReadData(True)
tout.Info('%s: Reading data from offset %#x-%#x, size %#x' %
(self.GetPath(), self.offset, self.offset + self.size,
self.size))
data = parent_data[self.offset:self.offset + self.size]
offset = self.offset - self.section._skip_at_start
data = parent_data[offset:offset + self.size]
tout.Info(
'%s: Reading data from offset %#x-%#x (real %#x), size %#x, got %#x' %
(self.GetPath(), self.offset, self.offset + self.size, offset,
self.size, len(data)))
return data
def ReadChildData(self, child, decomp=True):
@ -648,3 +652,47 @@ class Entry_section(Entry):
"""
for entry in self._entries.values():
entry.CheckMissing(missing_list)
def _CollectEntries(self, entries, entries_by_name, add_entry):
"""Collect all the entries in an section
This builds up a dict of entries in this section and all subsections.
Entries are indexed by path and by name.
Since all paths are unique, entries will not have any conflicts. However
entries_by_name make have conflicts if two entries have the same name
(e.g. with different parent sections). In this case, an entry at a
higher level in the hierarchy will win over a lower-level entry.
Args:
entries: dict to put entries:
key: entry path
value: Entry object
entries_by_name: dict to put entries
key: entry name
value: Entry object
add_entry: Entry to add
"""
entries[add_entry.GetPath()] = add_entry
to_add = add_entry.GetEntries()
if to_add:
for entry in to_add.values():
entries[entry.GetPath()] = entry
for entry in to_add.values():
self._CollectEntries(entries, entries_by_name, entry)
entries_by_name[add_entry.name] = add_entry
def MissingArgs(self, entry, missing):
"""Report a missing argument, if enabled
For entries which require arguments, this reports an error if some are
missing. If missing entries are being ignored (e.g. because we read the
entry from an image rather than creating it), this function does
nothing.
Args:
missing: List of missing properties / entry args, each a string
"""
if not self._ignore_missing:
entry.Raise('Missing required properties/entry args: %s' %
(', '.join(missing)))

View File

@ -9,7 +9,6 @@
from binman import elf
from binman.entry import Entry
from patman import command
from binman.etype.blob import Entry_blob
from patman import tools

View File

@ -2,7 +2,7 @@
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# Entry-type module for 'u-boot-nodtb.bin'
# Entry-type module for 'u-boot-spl-nodtb.bin'
#
from binman.entry import Entry

View File

@ -49,7 +49,7 @@ class Entry_vblock(Entry):
EntryArg('kernelkey', str),
EntryArg('preamble-flags', int)])
def ObtainContents(self):
def GetVblock(self):
# Join up the data files to be signed
input_data = b''
for entry_phandle in self.content:
@ -76,5 +76,16 @@ class Entry_vblock(Entry):
]
#out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
stdout = tools.Run('futility', *args)
self.SetContents(tools.ReadFile(output_fname))
return tools.ReadFile(output_fname)
def ObtainContents(self):
data = self.GetVblock()
if data is False:
return False
self.SetContents(data)
return True
def ProcessContents(self):
# The blob may have changed due to WriteSymbols()
data = self.GetVblock()
return self.ProcessContentsUpdate(data)

View File

@ -53,8 +53,8 @@ FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
def NameToFmap(name):
if type(name) == bytes and sys.version_info[0] >= 3:
name = name.decode('utf-8') # pragma: no cover (for Python 2)
if type(name) == bytes:
name = name.decode('utf-8')
return name.replace('\0', '').replace('-', '_').upper()
def ConvertName(field_names, fields):

View File

@ -1638,15 +1638,37 @@ class TestFunctional(unittest.TestCase):
str(e.exception))
def _HandleVblockCommand(self, pipe_list):
"""Fake calls to the futility utility"""
"""Fake calls to the futility utility
The expected pipe is:
[('futility', 'vbutil_firmware', '--vblock',
'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
'--signprivate', 'devkeys/firmware_data_key.vbprivk',
'--version', '1', '--fv', 'input.vblock', '--kernelkey',
'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
This writes to the output file (here, 'vblock.vblock'). If
self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
of the input data (here, 'input.vblock').
"""
if pipe_list[0][0] == 'futility':
fname = pipe_list[0][3]
with open(fname, 'wb') as fd:
fd.write(VBLOCK_DATA)
if self._hash_data:
infile = pipe_list[0][11]
m = hashlib.sha256()
data = tools.ReadFile(infile)
m.update(data)
fd.write(m.digest())
else:
fd.write(VBLOCK_DATA)
return command.CommandResult()
def testVblock(self):
"""Test for the Chromium OS Verified Boot Block"""
self._hash_data = False
command.test_result = self._HandleVblockCommand
entry_args = {
'keydir': 'devkeys',
@ -1677,6 +1699,29 @@ class TestFunctional(unittest.TestCase):
self.assertIn("Node '/binman/vblock': Cannot find entry for node "
"'other'", str(e.exception))
def testVblockContent(self):
"""Test that the vblock signs the right data"""
self._hash_data = True
command.test_result = self._HandleVblockCommand
entry_args = {
'keydir': 'devkeys',
}
data = self._DoReadFileDtb(
'189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
entry_args=entry_args)[0]
hashlen = 32 # SHA256 hash is 32 bytes
self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
hashval = data[-hashlen:]
dtb = data[len(U_BOOT_DATA):-hashlen]
expected_data = U_BOOT_DATA + dtb
# The hashval should be a hash of the dtb
m = hashlib.sha256()
m.update(expected_data)
expected_hashval = m.digest()
self.assertEqual(expected_hashval, hashval)
def testTpl(self):
"""Test that an image with TPL and its device tree can be created"""
# ELF file with a '__bss_size' symbol
@ -4139,6 +4184,67 @@ class TestFunctional(unittest.TestCase):
}
self.assertEqual(expected, props)
def testSymbolsSubsection(self):
"""Test binman can assign symbols from a subsection"""
elf_fname = self.ElfTestFile('u_boot_binman_syms')
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
self._SetupSplElf('u_boot_binman_syms')
data = self._DoReadFile('187_symbols_sub.dts')
sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
expected = (sym_values + U_BOOT_SPL_DATA[20:] +
tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
U_BOOT_SPL_DATA[20:])
self.assertEqual(expected, data)
def testReadImageEntryArg(self):
"""Test reading an image that would need an entry arg to generate"""
entry_args = {
'cros-ec-rw-path': 'ecrw.bin',
}
data = self.data = self._DoReadFileDtb(
'188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
entry_args=entry_args)
image_fname = tools.GetOutputFilename('image.bin')
orig_image = control.images['image']
# This should not generate an error about the missing 'cros-ec-rw-path'
# since we are reading the image from a file. Compare with
# testEntryArgsRequired()
image = Image.FromFile(image_fname)
self.assertEqual(orig_image.GetEntries().keys(),
image.GetEntries().keys())
def testFilesAlign(self):
"""Test alignment with files"""
data = self._DoReadFile('190_files_align.dts')
# The first string is 15 bytes so will align to 16
expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
self.assertEqual(expect, data)
def testReadImageSkip(self):
"""Test reading an image and accessing its FDT map"""
data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
image_fname = tools.GetOutputFilename('image.bin')
orig_image = control.images['image']
image = Image.FromFile(image_fname)
self.assertEqual(orig_image.GetEntries().keys(),
image.GetEntries().keys())
orig_entry = orig_image.GetEntries()['fdtmap']
entry = image.GetEntries()['fdtmap']
self.assertEqual(orig_entry.offset, entry.offset)
self.assertEqual(orig_entry.size, entry.size)
self.assertEqual(16, entry.image_pos)
u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
if __name__ == "__main__":
unittest.main()

View File

@ -43,8 +43,13 @@ class Image(section.Entry_section):
test: True if this is being called from a test of Images. This this case
there is no device tree defining the structure of the section, so
we create a section manually.
ignore_missing: Ignore any missing entry arguments (i.e. don't raise an
exception). This should be used if the Image is being loaded from
a file rather than generated. In that case we obviously don't need
the entry arguments since the contents already exists.
"""
def __init__(self, name, node, copy_to_orig=True, test=False):
def __init__(self, name, node, copy_to_orig=True, test=False,
ignore_missing=False):
super().__init__(None, 'section', node, test=test)
self.copy_to_orig = copy_to_orig
self.name = 'main-section'
@ -53,6 +58,7 @@ class Image(section.Entry_section):
self.fdtmap_dtb = None
self.fdtmap_data = None
self.allow_repack = False
self._ignore_missing = ignore_missing
if not test:
self.ReadNode()
@ -100,7 +106,7 @@ class Image(section.Entry_section):
# Return an Image with the associated nodes
root = dtb.GetRoot()
image = Image('image', root, copy_to_orig=False)
image = Image('image', root, copy_to_orig=False, ignore_missing=True)
image.image_node = fdt_util.GetString(root, 'image-node', 'image')
image.fdtmap_dtb = dtb
@ -130,12 +136,7 @@ class Image(section.Entry_section):
Returns:
True if the new data size is OK, False if expansion is needed
"""
sizes_ok = True
for entry in self._entries.values():
if not entry.ProcessContents():
sizes_ok = False
tout.Debug("Entry '%s' size change" % self._node.path)
return sizes_ok
return super().ProcessContents()
def WriteSymbols(self):
"""Write symbol values into binary files for access at run time"""
@ -324,3 +325,48 @@ class Image(section.Entry_section):
_DoLine(lines, _EntryToStrings(entry))
selected_entries.append(entry)
return selected_entries, lines, widths
def LookupImageSymbol(self, sym_name, optional, msg, base_addr):
"""Look up a symbol in an ELF file
Looks up a symbol in an ELF file. Only entry types which come from an
ELF image can be used by this function.
This searches through this image including all of its subsections.
At present the only entry properties supported are:
offset
image_pos - 'base_addr' is added if this is not an end-at-4gb image
size
Args:
sym_name: Symbol name in the ELF file to look up in the format
_binman_<entry>_prop_<property> where <entry> is the name of
the entry and <property> is the property to find (e.g.
_binman_u_boot_prop_offset). As a special case, you can append
_any to <entry> to have it search for any matching entry. E.g.
_binman_u_boot_any_prop_offset will match entries called u-boot,
u-boot-img and u-boot-nodtb)
optional: True if the symbol is optional. If False this function
will raise if the symbol is not found
msg: Message to display if an error occurs
base_addr: Base address of image. This is added to the returned
image_pos in most cases so that the returned position indicates
where the targeted entry/binary has actually been loaded. But
if end-at-4gb is used, this is not done, since the binary is
already assumed to be linked to the ROM position and using
execute-in-place (XIP).
Returns:
Value that should be assigned to that symbol, or None if it was
optional and not found
Raises:
ValueError if the symbol is invalid or not found, or references a
property which is not supported
"""
entries = OrderedDict()
entries_by_name = {}
self._CollectEntries(entries, entries_by_name, self)
return self.LookupSymbol(sym_name, optional, msg, base_addr,
entries_by_name)

View File

@ -314,6 +314,16 @@ def AddString(node, prop, value):
for n in GetUpdateNodes(node):
n.AddString(prop, value)
def AddInt(node, prop, value):
"""Add a new string property to affected device trees
Args:
prop_name: Name of property
val: Integer value of property
"""
for n in GetUpdateNodes(node):
n.AddInt(prop, value)
def SetInt(node, prop, value, for_repack=False):
"""Update an integer property in affected device trees with an integer value

View File

@ -5,7 +5,7 @@
binman {
files {
pattern = "files/*.dat";
compress = "none";
files-compress = "none";
};
};
};

View File

@ -0,0 +1,22 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
section {
pad-byte = <0xff>;
u-boot-spl {
};
u-boot {
offset = <24>;
};
};
u-boot-spl2 {
type = "u-boot-spl";
};
};
};

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
size = <0xc00>;
u-boot {
};
cros-ec-rw {
};
fdtmap {
};
image-header {
location = "end";
};
};
};

View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
u_boot: u-boot {
};
dtb: u-boot-dtb {
};
/*
* Put the vblock after the dtb so that the dtb is updated
* before the vblock reads its data. At present binman does not
* understand dependencies between entries, but simply
* iterates again when it thinks something needs to be
* recalculated.
*/
vblock {
content = <&u_boot &dtb>;
keyblock = "firmware.keyblock";
signprivate = "firmware_data_key.vbprivk";
version = <1>;
kernelkey = "kernel_subkey.vbpubk";
preamble-flags = <1>;
};
};
};

View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
binman {
files {
pattern = "files/*.dat";
files-compress = "none";
files-align = <4>;
};
};
};

View File

@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
end-at-4gb;
size = <0x400>;
section {
size = <0x10>;
u-boot {
};
};
fdtmap {
};
image-header {
location = "end";
};
};
};

View File

@ -460,10 +460,21 @@ class Node:
prop_name: Name of property to add
val: String value of property
"""
if sys.version_info[0] >= 3: # pragma: no cover
val = bytes(val, 'utf-8')
val = bytes(val, 'utf-8')
self.AddData(prop_name, val + b'\0')
def AddInt(self, prop_name, val):
"""Add a new integer property to a node
The device tree is marked dirty so that the value will be written to
the blob on the next sync.
Args:
prop_name: Name of property to add
val: Integer value of property
"""
self.AddData(prop_name, struct.pack('>I', val))
def AddSubnode(self, name):
"""Add a new subnode to the node

View File

@ -397,6 +397,12 @@ class TestProp(unittest.TestCase):
data = self.fdt.getprop(self.node.Offset(), 'one')
self.assertEqual(1, fdt32_to_cpu(data))
val = 1234
self.node.AddInt('integer', val)
self.dtb.Sync(auto_resize=True)
data = self.fdt.getprop(self.node.Offset(), 'integer')
self.assertEqual(val, fdt32_to_cpu(data))
val = '123' + chr(0) + '456'
self.node.AddString('string', val)
self.dtb.Sync(auto_resize=True)

View File

@ -476,7 +476,8 @@ def Compress(indata, algo, with_header=True):
fname = GetOutputFilename('%s.comp.tmp' % algo)
WriteFile(fname, indata)
if algo == 'lz4':
data = Run('lz4', '--no-frame-crc', '-c', fname, binary=True)
data = Run('lz4', '--no-frame-crc', '-B4', '-5', '-c', fname,
binary=True)
# cbfstool uses a very old version of lzma
elif algo == 'lzma':
outfname = GetOutputFilename('%s.comp.otmp' % algo)