diff options
72 files changed, 3350 insertions, 2270 deletions
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 98e8a4fe14..97c89fc067 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -294,10 +294,6 @@ jobs: ln -s travis-ci /tmp/uboot-test-hooks/py/`hostname` grub-mkimage --prefix=\"\" -o ~/grub_x86.efi -O i386-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd grub-mkimage --prefix=\"\" -o ~/grub_x64.efi -O x86_64-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd - cp /opt/grub/grubriscv64.efi ~/grub_riscv64.efi - cp /opt/grub/grubriscv32.efi ~/grub_riscv32.efi - cp /opt/grub/grubaa64.efi ~/grub_arm64.efi - cp /opt/grub/grubarm.efi ~/grub_arm.efi if [[ "${TEST_PY_BD}" == "qemu-riscv32_spl" ]]; then wget -O - https://github.com/riscv/opensbi/releases/download/v0.6/opensbi-0.6-rv32-bin.tar.xz | tar -C /tmp -xJ; export OPENSBI=/tmp/opensbi-0.6-rv32-bin/platform/qemu/virt/firmware/fw_dynamic.bin; @@ -310,6 +306,12 @@ jobs: cd ${WORK_DIR} export UBOOT_TRAVIS_BUILD_DIR=/tmp/${TEST_PY_BD}; tools/buildman/buildman -o ${UBOOT_TRAVIS_BUILD_DIR} -w -E -W -e --board ${TEST_PY_BD} ${OVERRIDE} + cp ~/grub_x86.efi ${UBOOT_TRAVIS_BUILD_DIR}/ + cp ~/grub_x64.efi ${UBOOT_TRAVIS_BUILD_DIR}/ + cp /opt/grub/grubriscv64.efi ${UBOOT_TRAVIS_BUILD_DIR}/grub_riscv64.efi + cp /opt/grub/grubriscv32.efi ${UBOOT_TRAVIS_BUILD_DIR}/grub_riscv32.efi + cp /opt/grub/grubaa64.efi ${UBOOT_TRAVIS_BUILD_DIR}/grub_arm64.efi + cp /opt/grub/grubarm.efi ${UBOOT_TRAVIS_BUILD_DIR}/grub_arm.efi virtualenv -p /usr/bin/python3 /tmp/venv . /tmp/venv/bin/activate pip install -r test/py/requirements.txt diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 23599b97c0..ae91252a00 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,3 +1,6 @@ Please do not submit a Pull Request via github. Our project makes use of mailing lists for patch submission and review. For more details please see https://www.denx.de/wiki/U-Boot/Patches + +The only exception to this is in order to trigger a CI loop on Azure prior +to posting of patches. diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d0746955b4..d2f864669d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,10 +20,6 @@ stages: - ln -s travis-ci /tmp/uboot-test-hooks/py/`hostname` - grub-mkimage --prefix="" -o ~/grub_x86.efi -O i386-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd - grub-mkimage --prefix="" -o ~/grub_x64.efi -O x86_64-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd - - cp /opt/grub/grubriscv64.efi ~/grub_riscv64.efi - - cp /opt/grub/grubriscv32.efi ~/grub_riscv32.efi - - cp /opt/grub/grubaa64.efi ~/grub_arm64.efi - - cp /opt/grub/grubarm.efi ~/grub_arm.efi - if [[ "${TEST_PY_BD}" == "qemu-riscv32_spl" ]]; then wget -O - https://github.com/riscv/opensbi/releases/download/v0.6/opensbi-0.6-rv32-bin.tar.xz | tar -C /tmp -xJ; export OPENSBI=/tmp/opensbi-0.6-rv32-bin/platform/qemu/virt/firmware/fw_dynamic.bin; @@ -40,6 +36,12 @@ stages: - export UBOOT_TRAVIS_BUILD_DIR=/tmp/${TEST_PY_BD} - tools/buildman/buildman -o ${UBOOT_TRAVIS_BUILD_DIR} -w -E -W -e --board ${TEST_PY_BD} ${OVERRIDE} + - cp ~/grub_x86.efi $UBOOT_TRAVIS_BUILD_DIR/ + - cp ~/grub_x64.efi $UBOOT_TRAVIS_BUILD_DIR/ + - cp /opt/grub/grubriscv64.efi $UBOOT_TRAVIS_BUILD_DIR/grub_riscv64.efi + - cp /opt/grub/grubriscv32.efi $UBOOT_TRAVIS_BUILD_DIR/grub_riscv32.efi + - cp /opt/grub/grubaa64.efi $UBOOT_TRAVIS_BUILD_DIR/grub_arm64.efi + - cp /opt/grub/grubarm.efi $UBOOT_TRAVIS_BUILD_DIR/grub_arm.efi - virtualenv -p /usr/bin/python3 /tmp/venv - . /tmp/venv/bin/activate - pip install -r test/py/requirements.txt diff --git a/arch/arm/dts/k3-am65-mcu.dtsi b/arch/arm/dts/k3-am65-mcu.dtsi index bc9a87210d..1355685839 100644 --- a/arch/arm/dts/k3-am65-mcu.dtsi +++ b/arch/arm/dts/k3-am65-mcu.dtsi @@ -6,6 +6,20 @@ */ &cbass_mcu { + mcu_conf: scm_conf@40f00000 { + compatible = "syscon", "simple-mfd"; + reg = <0x0 0x40f00000 0x0 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x40f00000 0x20000>; + + phy_gmii_sel: phy@4040 { + compatible = "ti,am654-phy-gmii-sel"; + reg = <0x4040 0x4>; + #phy-cells = <1>; + }; + }; + mcu_uart0: serial@40a00000 { compatible = "ti,am654-uart"; reg = <0x00 0x40a00000 0x00 0x100>; @@ -102,4 +116,118 @@ #size-cells = <0>; }; }; + + mcu_navss { + compatible = "simple-mfd"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + dma-coherent; + dma-ranges; + + ti,sci-dev-id = <119>; + + mcu_ringacc: ringacc@2b800000 { + compatible = "ti,am654-navss-ringacc"; + reg = <0x0 0x2b800000 0x0 0x400000>, + <0x0 0x2b000000 0x0 0x400000>, + <0x0 0x28590000 0x0 0x100>, + <0x0 0x2a500000 0x0 0x40000>; + reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target"; + ti,num-rings = <286>; + ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */ + ti,dma-ring-reset-quirk; + ti,sci = <&dmsc>; + ti,sci-dev-id = <195>; + }; + + mcu_udmap: dma-controller@285c0000 { + compatible = "ti,am654-navss-mcu-udmap"; + reg = <0x0 0x285c0000 0x0 0x100>, + <0x0 0x2a800000 0x0 0x40000>, + <0x0 0x2aa00000 0x0 0x40000>; + reg-names = "gcfg", "rchanrt", "tchanrt"; + #dma-cells = <1>; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <194>; + ti,ringacc = <&mcu_ringacc>; + + ti,sci-rm-range-tchan = <0x1>, /* TX_HCHAN */ + <0x2>; /* TX_CHAN */ + ti,sci-rm-range-rchan = <0x3>, /* RX_HCHAN */ + <0x4>; /* RX_CHAN */ + ti,sci-rm-range-rflow = <0x5>; /* GP RFLOW */ + }; + }; + + mcu_cpsw: ethernet@46000000 { + compatible = "ti,am654-cpsw-nuss"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0 0x46000000 0x0 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x0 0x0 0x0 0x46000000 0x0 0x200000>; + dma-coherent; + clocks = <&k3_clks 5 10>; + clock-names = "fck"; + power-domains = <&k3_pds 5 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&mcu_udmap 0xf000>, + <&mcu_udmap 0xf001>, + <&mcu_udmap 0xf002>, + <&mcu_udmap 0xf003>, + <&mcu_udmap 0xf004>, + <&mcu_udmap 0xf005>, + <&mcu_udmap 0xf006>, + <&mcu_udmap 0xf007>, + <&mcu_udmap 0x7000>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + cpsw_port1: port@1 { + reg = <1>; + ti,mac-only; + label = "port1"; + ti,syscon-efuse = <&mcu_conf 0x200>; + phys = <&phy_gmii_sel 1>; + }; + }; + + davinci_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; + reg = <0x0 0xf00 0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 5 10>; + clock-names = "fck"; + bus_freq = <1000000>; + }; + + cpts@3d000 { + compatible = "ti,am65-cpts"; + reg = <0x0 0x3d000 0x0 0x400>; + clocks = <&mcu_cpsw_cpts_mux>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 570 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + + mcu_cpsw_cpts_mux: refclk-mux { + #clock-cells = <0>; + clocks = <&k3_clks 118 5>, <&k3_clks 118 11>, + <&k3_clks 118 6>, <&k3_clks 118 3>, + <&k3_clks 118 8>, <&k3_clks 118 14>, + <&k3_clks 120 3>, <&k3_clks 121 3>; + assigned-clocks = <&mcu_cpsw_cpts_mux>; + assigned-clock-parents = <&k3_clks 118 5>; + }; + }; + }; }; diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index a7e5eb0553..d9ff3ed47b 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -4,7 +4,6 @@ */ #include <dt-bindings/pinctrl/k3.h> -#include <dt-bindings/dma/k3-udma.h> #include <dt-bindings/net/ti-dp83867.h> / { @@ -47,164 +46,17 @@ &cbass_mcu { u-boot,dm-spl; - navss_mcu: navss-mcu { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges; + mcu_navss { u-boot,dm-spl; - ti,sci-dev-id = <119>; - - mcu_ringacc: ringacc@2b800000 { - compatible = "ti,am654-navss-ringacc"; - reg = <0x0 0x2b800000 0x0 0x400000>, - <0x0 0x2b000000 0x0 0x400000>, - <0x0 0x28590000 0x0 0x100>, - <0x0 0x2a500000 0x0 0x40000>; - reg-names = "rt", "fifos", - "proxy_gcfg", "proxy_target"; - ti,num-rings = <286>; - ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */ - ti,dma-ring-reset-quirk; - ti,sci = <&dmsc>; - ti,sci-dev-id = <195>; + ringacc@2b800000 { u-boot,dm-spl; }; - mcu_udmap: udmap@285c0000 { - compatible = "ti,k3-navss-udmap"; - reg = <0x0 0x285c0000 0x0 0x100>, - <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; - #dma-cells = <3>; - - ti,ringacc = <&mcu_ringacc>; - ti,psil-base = <0x6000>; - - ti,sci = <&dmsc>; - ti,sci-dev-id = <194>; - - ti,sci-rm-range-tchan = <0x1>, /* TX_HCHAN */ - <0x2>; /* TX_CHAN */ - ti,sci-rm-range-rchan = <0x3>, /* RX_HCHAN */ - <0x4>; /* RX_CHAN */ - ti,sci-rm-range-rflow = <0x5>; /* GP RFLOW */ - dma-coherent; + dma-controller@285c0000 { u-boot,dm-spl; }; }; - - mcu_conf: scm_conf@40f00000 { - compatible = "syscon"; - reg = <0x0 0x40f00000 0x0 0x20000>; - }; - - mcu_cpsw: cpsw_nuss@046000000 { - compatible = "ti,am654-cpsw-nuss"; - #address-cells = <2>; - #size-cells = <2>; - reg = <0x0 0x46000000 0x0 0x200000>; - reg-names = "cpsw_nuss"; - ranges; - dma-coherent; - clocks = <&k3_clks 5 10>; - clock-names = "fck"; - power-domains = <&k3_pds 5 TI_SCI_PD_EXCLUSIVE>; - ti,psil-base = <0x7000>; - - dmas = <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 1 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 2 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 3 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 4 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 5 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 6 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 7 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_RX>; - dma-names = "tx0", "tx1", "tx2", "tx3", - "tx4", "tx5", "tx6", "tx7", - "rx"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - host: host@0 { - reg = <0>; - ti,label = "host"; - }; - - cpsw_port1: port@1 { - reg = <1>; - ti,mac-only; - ti,label = "port1"; - ti,syscon-efuse = <&mcu_conf 0x200>; - }; - }; - - davinci_mdio: mdio { - #address-cells = <1>; - #size-cells = <0>; - bus_freq = <1000000>; - }; - - ti,psil-config0 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config1 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config2 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config3 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config4 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config5 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config6 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config7 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - }; }; &cbass_wakeup { @@ -366,6 +218,7 @@ reg = <0x0 0x46000000 0x0 0x200000>, <0x0 0x40f00200 0x0 0x2>; reg-names = "cpsw_nuss", "mac_efuse"; + /delete-property/ ranges; cpsw-phy-sel@40f04040 { compatible = "ti,am654-cpsw-phy-sel"; diff --git a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi index 7b01e4204f..6e748bfebb 100644 --- a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi +++ b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi @@ -3,7 +3,6 @@ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ */ -#include <dt-bindings/dma/k3-udma.h> #include <dt-bindings/net/ti-dp83867.h> / { @@ -32,183 +31,17 @@ u-boot,dm-spl; }; - mcu_conf: scm_conf@40f00000 { - compatible = "syscon", "simple-mfd"; - reg = <0x0 0x40f00000 0x0 0x20000>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x0 0x40f00000 0x20000>; - - phy_sel: cpsw-phy-sel@4040 { - compatible = "ti,am654-cpsw-phy-sel"; - reg = <0x4040 0x4>; - reg-names = "gmii-sel"; - }; - }; - - cbass_mcu_navss: mcu_navss { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - dma-coherent; - dma-ranges; - ranges; - - ti,sci-dev-id = <232>; + mcu_navss { u-boot,dm-spl; - mcu_ringacc: ringacc@2b800000 { - compatible = "ti,am654-navss-ringacc"; - reg = <0x0 0x2b800000 0x0 0x400000>, - <0x0 0x2b000000 0x0 0x400000>, - <0x0 0x28590000 0x0 0x100>, - <0x0 0x2a500000 0x0 0x40000>; - reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target"; - ti,num-rings = <286>; - ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */ - ti,sci = <&dmsc>; - ti,sci-dev-id = <235>; + ringacc@2b800000 { u-boot,dm-spl; }; - mcu_udmap: udmap@31150000 { - compatible = "ti,j721e-navss-mcu-udmap"; - reg = <0x0 0x285c0000 0x0 0x100>, - <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; - #dma-cells = <3>; - - ti,ringacc = <&mcu_ringacc>; - ti,psil-base = <0x6000>; - - ti,sci = <&dmsc>; - ti,sci-dev-id = <236>; - - ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ - <0x0f>; /* TX_HCHAN */ - ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ - <0x0b>; /* RX_HCHAN */ - ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ + dma-controller@285c0000 { u-boot,dm-spl; }; }; - - mcu_cpsw: ethernet@046000000 { - compatible = "ti,j721e-cpsw-nuss"; - #address-cells = <2>; - #size-cells = <2>; - reg = <0x0 0x46000000 0x0 0x200000>; - reg-names = "cpsw_nuss"; - ranges; - dma-coherent; - clocks = <&k3_clks 18 22>; - clock-names = "fck"; - power-domains = <&k3_pds 18 TI_SCI_PD_EXCLUSIVE>; - ti,psil-base = <0x7000>; - cpsw-phy-sel = <&phy_sel>; - - dmas = <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 1 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 2 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 3 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 4 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 5 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 6 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 7 UDMA_DIR_TX>, - <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_RX>; - dma-names = "tx0", "tx1", "tx2", "tx3", - "tx4", "tx5", "tx6", "tx7", - "rx"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - host: host@0 { - reg = <0>; - ti,label = "host"; - }; - - cpsw_port1: port@1 { - reg = <1>; - ti,mac-only; - ti,label = "port1"; - ti,syscon-efuse = <&mcu_conf 0x200>; - }; - }; - - davinci_mdio: mdio { - #address-cells = <1>; - #size-cells = <0>; - bus_freq = <1000000>; - }; - - cpts { - clocks = <&k3_clks 18 2>; - clock-names = "cpts"; - interrupts-extended = <&gic500 GIC_SPI 858 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "cpts"; - ti,cpts-ext-ts-inputs = <4>; - ti,cpts-periodic-outputs = <2>; - }; - - ti,psil-config0 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config1 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config2 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config3 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config4 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config5 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config6 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - - ti,psil-config7 { - linux,udma-mode = <UDMA_PKT_MODE>; - statictr-type = <PSIL_STATIC_TR_NONE>; - ti,needs-epib; - ti,psd-size = <16>; - }; - }; }; &secure_proxy_main { @@ -318,6 +151,7 @@ reg = <0x0 0x46000000 0x0 0x200000>, <0x0 0x40f00200 0x0 0x2>; reg-names = "cpsw_nuss", "mac_efuse"; + /delete-property/ ranges; cpsw-phy-sel@40f04040 { compatible = "ti,am654-cpsw-phy-sel"; diff --git a/arch/arm/dts/k3-j721e-mcu-wakeup.dtsi b/arch/arm/dts/k3-j721e-mcu-wakeup.dtsi index 2eed50aa5a..e6c99ab698 100644 --- a/arch/arm/dts/k3-j721e-mcu-wakeup.dtsi +++ b/arch/arm/dts/k3-j721e-mcu-wakeup.dtsi @@ -35,6 +35,20 @@ }; }; + mcu_conf: syscon@40f00000 { + compatible = "syscon", "simple-mfd"; + reg = <0x0 0x40f00000 0x0 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x40f00000 0x20000>; + + phy_gmii_sel: phy@4040 { + compatible = "ti,am654-phy-gmii-sel"; + reg = <0x4040 0x4>; + #phy-cells = <1>; + }; + }; + wkup_pmx0: pinmux@4301c000 { compatible = "pinctrl-single"; /* Proxy 0 addressing */ @@ -199,4 +213,107 @@ clocks = <&k3_clks 195 0>; power-domains = <&k3_pds 195 TI_SCI_PD_EXCLUSIVE>; }; + + mcu_navss { + compatible = "simple-mfd"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + dma-coherent; + dma-ranges; + + ti,sci-dev-id = <232>; + + mcu_ringacc: ringacc@2b800000 { + compatible = "ti,am654-navss-ringacc"; + reg = <0x0 0x2b800000 0x0 0x400000>, + <0x0 0x2b000000 0x0 0x400000>, + <0x0 0x28590000 0x0 0x100>, + <0x0 0x2a500000 0x0 0x40000>; + reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target"; + ti,num-rings = <286>; + ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */ + ti,sci = <&dmsc>; + ti,sci-dev-id = <235>; + }; + + mcu_udmap: dma-controller@285c0000 { + compatible = "ti,j721e-navss-mcu-udmap"; + reg = <0x0 0x285c0000 0x0 0x100>, + <0x0 0x2a800000 0x0 0x40000>, + <0x0 0x2aa00000 0x0 0x40000>; + reg-names = "gcfg", "rchanrt", "tchanrt"; + #dma-cells = <1>; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <236>; + ti,ringacc = <&mcu_ringacc>; + + ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ + <0x0f>; /* TX_HCHAN */ + ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ + <0x0b>; /* RX_HCHAN */ + ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ + }; + }; + + mcu_cpsw: ethernet@46000000 { + compatible = "ti,j721e-cpsw-nuss"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0 0x46000000 0x0 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x0 0x0 0x0 0x46000000 0x0 0x200000>; + dma-coherent; + clocks = <&k3_clks 18 22>; + clock-names = "fck"; + power-domains = <&k3_pds 18 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&mcu_udmap 0xf000>, + <&mcu_udmap 0xf001>, + <&mcu_udmap 0xf002>, + <&mcu_udmap 0xf003>, + <&mcu_udmap 0xf004>, + <&mcu_udmap 0xf005>, + <&mcu_udmap 0xf006>, + <&mcu_udmap 0xf007>, + <&mcu_udmap 0x7000>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + cpsw_port1: port@1 { + reg = <1>; + ti,mac-only; + label = "port1"; + ti,syscon-efuse = <&mcu_conf 0x200>; + phys = <&phy_gmii_sel 1>; + }; + }; + + davinci_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; + reg = <0x0 0xf00 0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 18 22>; + clock-names = "fck"; + bus_freq = <1000000>; + }; + + cpts@3d000 { + compatible = "ti,am65-cpts"; + reg = <0x0 0x3d000 0x0 0x400>; + clocks = <&k3_clks 18 2>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 858 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; }; diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c index 9695b2236e..63bf060616 100644 --- a/arch/arm/mach-k3/common.c +++ b/arch/arm/mach-k3/common.c @@ -440,7 +440,7 @@ void spl_board_prepare_for_boot(void) dcache_disable(); } -void spl_board_prepare_for_boot_linux(void) +void spl_board_prepare_for_linux(void) { dcache_disable(); } diff --git a/arch/arm/mach-k3/config.mk b/arch/arm/mach-k3/config.mk index f6b63db349..f7afef610c 100644 --- a/arch/arm/mach-k3/config.mk +++ b/arch/arm/mach-k3/config.mk @@ -48,22 +48,23 @@ ALL-y += tiboot3.bin endif ifdef CONFIG_ARM64 + ifeq ($(CONFIG_TI_SECURE_DEVICE),y) SPL_ITS := u-boot-spl-k3_HS.its -$(SPL_ITS): FORCE - IS_HS=1 \ - $(srctree)/tools/k3_fit_atf.sh \ - $(patsubst %,$(obj)/dts/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST))) > $@ - +$(SPL_ITS): export IS_HS=1 ALL-y += tispl.bin_HS else SPL_ITS := u-boot-spl-k3.its -$(SPL_ITS): FORCE +ALL-y += tispl.bin +endif + +quiet_cmd_k3_mkits = MKITS $@ +cmd_k3_mkits = \ $(srctree)/tools/k3_fit_atf.sh \ $(patsubst %,$(obj)/dts/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST))) > $@ -ALL-y += tispl.bin -endif +$(SPL_ITS): FORCE + $(call cmd,k3_mkits) endif else diff --git a/board/davinci/da8xxevm/da850evm.c b/board/davinci/da8xxevm/da850evm.c index a3b0f8bf09..c91aeb8dbf 100644 --- a/board/davinci/da8xxevm/da850evm.c +++ b/board/davinci/da8xxevm/da850evm.c @@ -205,7 +205,7 @@ int misc_init_r(void) } static const struct pinmux_config gpio_pins[] = { -#ifdef CONFIG_USE_NOR +#ifdef CONFIG_MTD_NOR_FLASH /* GP0[11] is required for NOR to work on Rev 3 EVMs */ { pinmux(0), 8, 4 }, /* GP0[11] */ #endif @@ -235,7 +235,7 @@ const struct pinmux_resource pinmuxes[] = { PINMUX_ITEM(emifa_pins_cs3), PINMUX_ITEM(emifa_pins_cs4), PINMUX_ITEM(emifa_pins_nand), -#elif defined(CONFIG_USE_NOR) +#elif defined(CONFIG_MTD_NOR_FLASH) PINMUX_ITEM(emifa_pins_cs2), PINMUX_ITEM(emifa_pins_nor), #endif @@ -341,7 +341,7 @@ int board_init(void) DAVINCI_SYSCFG_SUSPSRC_UART2), &davinci_syscfg_regs->suspsrc); -#ifdef CONFIG_USE_NOR +#ifdef CONFIG_MTD_NOR_FLASH /* Set the GPIO direction as output */ clrbits_le32((u32 *)GPIO_BANK0_REG_DIR_ADDR, (0x01 << 11)); diff --git a/board/ti/beagle/beagle.c b/board/ti/beagle/beagle.c index 9139ad87d4..9ccd566da3 100644 --- a/board/ti/beagle/beagle.c +++ b/board/ti/beagle/beagle.c @@ -40,11 +40,6 @@ #include "beagle.h" #include <command.h> -#ifdef CONFIG_USB_EHCI_HCD -#include <usb.h> -#include <asm/ehci-omap.h> -#endif - #define TWL4030_I2C_BUS 0 #define EXPANSION_EEPROM_I2C_BUS 1 #define EXPANSION_EEPROM_I2C_ADDRESS 0x50 @@ -297,33 +292,6 @@ static void beagle_dvi_pup(void) } #endif -#ifdef CONFIG_USB_MUSB_OMAP2PLUS -static struct musb_hdrc_config musb_config = { - .multipoint = 1, - .dyn_fifo = 1, - .num_eps = 16, - .ram_bits = 12, -}; - -static struct omap_musb_board_data musb_board_data = { - .interface_type = MUSB_INTERFACE_ULPI, -}; - -static struct musb_hdrc_platform_data musb_plat = { -#if defined(CONFIG_USB_MUSB_HOST) - .mode = MUSB_HOST, -#elif defined(CONFIG_USB_MUSB_GADGET) - .mode = MUSB_PERIPHERAL, -#else -#error "Please define either CONFIG_USB_MUSB_HOST or CONFIG_USB_MUSB_GADGET" -#endif - .config = &musb_config, - .power = 100, - .platform_ops = &omap2430_ops, - .board_data = &musb_board_data, -}; -#endif - /* * Routine: misc_init_r * Description: Configure board specific parts @@ -506,10 +474,6 @@ int misc_init_r(void) omap3_dss_enable(); #endif -#ifdef CONFIG_USB_MUSB_OMAP2PLUS - musb_register(&musb_plat, &musb_board_data, (void *)MUSB_BASE); -#endif - if (generate_fake_mac) omap_die_id_usbethaddr(); @@ -548,37 +512,3 @@ void board_mmc_power_init(void) twl4030_power_mmc_init(0); } #endif - -#if defined(CONFIG_USB_EHCI_HCD) && !defined(CONFIG_SPL_BUILD) -/* Call usb_stop() before starting the kernel */ -void show_boot_progress(int val) -{ - if (val == BOOTSTAGE_ID_RUN_OS) - usb_stop(); -} - -static struct omap_usbhs_board_data usbhs_bdata = { - .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, - .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, - .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED -}; - -int ehci_hcd_init(int index, enum usb_init_type init, - struct ehci_hccr **hccr, struct ehci_hcor **hcor) -{ - return omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor); -} - -int ehci_hcd_stop(int index) -{ - return omap_ehci_hcd_stop(); -} - -#endif /* CONFIG_USB_EHCI_HCD */ - -#if defined(CONFIG_USB_ETHER) && defined(CONFIG_USB_MUSB_GADGET) -int board_eth_init(bd_t *bis) -{ - return usb_eth_initialize(bis); -} -#endif diff --git a/cmd/Kconfig b/cmd/Kconfig index 846c905c9c..bfe6c163dc 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -378,6 +378,7 @@ config CMD_BOOTEFI_HELLO_COMPILE config CMD_BOOTEFI_HELLO bool "Allow booting a standard EFI hello world for testing" depends on CMD_BOOTEFI_HELLO_COMPILE + default y if CMD_BOOTEFI_SELFTEST help This adds a standard EFI hello world application to U-Boot so that it can be used with the 'bootefi hello' command. This is useful @@ -489,13 +490,6 @@ config CMD_SPL_WRITE_SIZE flash used by Falcon-mode boot. See the documentation until CMD_SPL for detail. -config CMD_FITUPD - bool "fitImage update command" - depends on UPDATE_TFTP - help - Implements the 'fitupd' command, which allows to automatically - store software updates present on a TFTP server in NOR Flash - config CMD_THOR_DOWNLOAD bool "thor - TIZEN 'thor' download" select DFU diff --git a/cmd/Makefile b/cmd/Makefile index dc412d1106..7952138dc2 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -62,7 +62,6 @@ obj-$(CONFIG_CMD_EXT4) += ext4.o obj-$(CONFIG_CMD_EXT2) += ext2.o obj-$(CONFIG_CMD_FAT) += fat.o obj-$(CONFIG_CMD_FDT) += fdt.o -obj-$(CONFIG_CMD_FITUPD) += fitupd.o obj-$(CONFIG_CMD_FLASH) += flash.o obj-$(CONFIG_CMD_FPGA) += fpga.o obj-$(CONFIG_CMD_FPGAD) += fpgad.o diff --git a/cmd/fitupd.c b/cmd/fitupd.c deleted file mode 100644 index 0f490c58fc..0000000000 --- a/cmd/fitupd.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2011 - * Andreas Pretzsch, carpe noctem engineering, apr@cn-eng.de - */ - -#include <common.h> -#include <command.h> -#include <net.h> - -static int do_fitupd(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - ulong addr = 0UL; - - if (argc > 2) - return CMD_RET_USAGE; - - if (argc == 2) - addr = simple_strtoul(argv[1], NULL, 16); - - return update_tftp(addr, NULL, NULL); -} - -U_BOOT_CMD(fitupd, 2, 0, do_fitupd, - "update from FIT image", - "[addr]\n" - "\t- run update from FIT image at addr\n" - "\t or from tftp 'updatefile'" -); diff --git a/cmd/lsblk.c b/cmd/lsblk.c index ece8bbf108..653dffce04 100644 --- a/cmd/lsblk.c +++ b/cmd/lsblk.c @@ -5,6 +5,8 @@ */ #include <common.h> +#include <blk.h> +#include <command.h> #include <dm.h> static int do_lsblk(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 49338b4d36..ca0be92fc3 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1410,7 +1410,7 @@ static char env_help_text[] = #endif "env print [-a | name ...] - print environment\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "env print -e [-guid guid|-all][-n] [name ...] - print UEFI environment\n" + "env print -e [-guid guid] [-n] [name ...] - print UEFI environment\n" #endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" @@ -1452,8 +1452,9 @@ U_BOOT_CMD_COMPLETE( "print environment variables", "[-a]\n - print [all] values of all environment variables\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "printenv -e [-guid guid|-all][-n] [name ...]\n" + "printenv -e [-guid guid][-n] [name ...]\n" " - print UEFI variable 'name' or all the variables\n" + " \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n" " \"-n\": suppress dumping variable's value\n" #endif "printenv name ...\n" @@ -1487,7 +1488,7 @@ U_BOOT_CMD_COMPLETE( "-e [-guid guid][-nv][-bs][-rt][-at][-a][-v]\n" " [-i addr,size name], or [name [value ...]]\n" " - set UEFI variable 'name' to 'value' ...'\n" - " \"-guid\": set vendor guid\n" + " \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n" " \"-nv\": set non-volatile attribute\n" " \"-bs\": set boot-service attribute\n" " \"-rt\": set runtime attribute\n" diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 29cad38e19..8e31f43e1f 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -9,11 +9,13 @@ #include <common.h> #include <command.h> #include <efi_loader.h> +#include <efi_variable.h> #include <env.h> #include <exports.h> #include <hexdump.h> #include <malloc.h> #include <mapmem.h> +#include <rtc.h> #include <uuid.h> #include <linux/kernel.h> @@ -34,6 +36,7 @@ static const struct { {EFI_VARIABLE_RUNTIME_ACCESS, "RT"}, {EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, "AW"}, {EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, "AT"}, + {EFI_VARIABLE_READ_ONLY, "RO"}, }; static const struct { @@ -49,8 +52,7 @@ static const struct { {EFI_CERT_TYPE_PKCS7_GUID, "EFI_CERT_TYPE_PKCS7_GUID"}, }; -/* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ -static char unknown_guid[37]; +static const char unknown_guid[] = ""; /** * efi_guid_to_str() - convert guid to readable name @@ -68,9 +70,6 @@ static const char *efi_guid_to_str(const efi_guid_t *guid) if (!guidcmp(guid, &efi_guid_text[i].guid)) return efi_guid_text[i].text; - uuid_bin_to_str((unsigned char *)guid->b, unknown_guid, - UUID_STR_FORMAT_GUID); - return unknown_guid; } @@ -87,20 +86,22 @@ static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, bool verbose) { u32 attributes; u8 *data; + u64 time; + struct rtc_time tm; efi_uintn_t size; int count, i; efi_status_t ret; data = NULL; size = 0; - ret = EFI_CALL(efi_get_variable(name, guid, &attributes, &size, data)); + ret = efi_get_variable_int(name, guid, &attributes, &size, data, &time); if (ret == EFI_BUFFER_TOO_SMALL) { data = malloc(size); if (!data) goto out; - ret = EFI_CALL(efi_get_variable(name, guid, &attributes, &size, - data)); + ret = efi_get_variable_int(name, guid, &attributes, &size, + data, &time); } if (ret == EFI_NOT_FOUND) { printf("Error: \"%ls\" not defined\n", name); @@ -109,13 +110,16 @@ static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, bool verbose) if (ret != EFI_SUCCESS) goto out; - printf("%ls:\n %s:", name, efi_guid_to_str(guid)); + rtc_to_tm(time, &tm); + printf("%ls:\n %pUl %s\n", name, guid, efi_guid_to_str(guid)); + if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + printf(" %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year, + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + printf(" "); for (count = 0, i = 0; i < ARRAY_SIZE(efi_var_attrs); i++) if (attributes & efi_var_attrs[i].mask) { if (count) putc('|'); - else - putc(' '); count++; puts(efi_var_attrs[i].text); } @@ -128,50 +132,6 @@ out: free(data); } -/** - * efi_dump_vars() - show information about named UEFI variables - * - * @argc: Number of arguments (variables) - * @argv: Argument (variable name) array - * @verbose: if true, dump data - * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE - * - * Show information encoded in named UEFI variables - */ -static int efi_dump_vars(int argc, char *const argv[], - const efi_guid_t *guid, bool verbose) -{ - u16 *var_name16, *p; - efi_uintn_t buf_size, size; - - buf_size = 128; - var_name16 = malloc(buf_size); - if (!var_name16) - return CMD_RET_FAILURE; - - for (; argc > 0; argc--, argv++) { - size = (utf8_utf16_strlen(argv[0]) + 1) * sizeof(u16); - if (buf_size < size) { - buf_size = size; - p = realloc(var_name16, buf_size); - if (!p) { - free(var_name16); - return CMD_RET_FAILURE; - } - var_name16 = p; - } - - p = var_name16; - utf8_utf16_strcpy(&p, argv[0]); - - efi_dump_single_var(var_name16, guid, verbose); - } - - free(var_name16); - - return CMD_RET_SUCCESS; -} - static bool match_name(int argc, char *const argv[], u16 *var_name16) { char *buf, *p; @@ -217,10 +177,7 @@ static int efi_dump_var_all(int argc, char *const argv[], efi_uintn_t buf_size, size; efi_guid_t guid; efi_status_t ret; - - if (argc && guid_p) - /* simplified case */ - return efi_dump_vars(argc, argv, guid_p, verbose); + bool match = false; buf_size = 128; var_name16 = malloc(buf_size); @@ -251,13 +208,18 @@ static int efi_dump_var_all(int argc, char *const argv[], return CMD_RET_FAILURE; } - if ((!guid_p || !guidcmp(guid_p, &guid)) && - (!argc || match_name(argc, argv, var_name16))) + if (guid_p && guidcmp(guid_p, &guid)) + continue; + if (!argc || match_name(argc, argv, var_name16)) { + match = true; efi_dump_single_var(var_name16, &guid, verbose); + } } - free(var_name16); + if (!match && argc == 1) + printf("Error: \"%s\" not defined\n", argv[0]); + return CMD_RET_SUCCESS; } @@ -278,9 +240,8 @@ static int efi_dump_var_all(int argc, char *const argv[], int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - efi_guid_t guid; - const efi_guid_t *guid_p; - bool default_guid, guid_any, verbose; + const efi_guid_t *guid_p = NULL; + bool verbose = true; efi_status_t ret; /* Initialize EFI drivers */ @@ -291,31 +252,18 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; } - default_guid = true; - guid_any = false; - verbose = true; for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-guid")) { - if (argc == 1) - return CMD_RET_USAGE; + efi_guid_t guid; - /* -a already specified */ - if (!default_guid && guid_any) + if (argc == 1) return CMD_RET_USAGE; - argc--; argv++; if (uuid_str_to_bin(argv[0], guid.b, UUID_STR_FORMAT_GUID)) return CMD_RET_USAGE; - default_guid = false; - } else if (!strcmp(argv[0], "-all")) { - /* -guid already specified */ - if (!default_guid && !guid_any) - return CMD_RET_USAGE; - - guid_any = true; - default_guid = false; + guid_p = (const efi_guid_t *)guid.b; } else if (!strcmp(argv[0], "-n")) { verbose = false; } else { @@ -323,13 +271,6 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, } } - if (guid_any) - guid_p = NULL; - else if (default_guid) - guid_p = &efi_global_variable_guid; - else - guid_p = (const efi_guid_t *)guid.b; - /* enumerate and show all UEFI variables */ return efi_dump_var_all(argc, argv, guid_p, verbose); } @@ -510,8 +451,7 @@ int do_env_set_efi(struct cmd_tbl *cmdtp, int flag, int argc, argv++; if (uuid_str_to_bin(argv[0], guid.b, UUID_STR_FORMAT_GUID)) { - printf("## Guid not specified or in XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX format\n"); - return CMD_RET_FAILURE; + return CMD_RET_USAGE; } default_guid = false; } else if (!strcmp(argv[0], "-bs")) { @@ -559,8 +499,8 @@ int do_env_set_efi(struct cmd_tbl *cmdtp, int flag, int argc, } if (verbose) { - printf("GUID: %s\n", efi_guid_to_str((const efi_guid_t *) - &guid)); + printf("GUID: %pUl %s\n", &guid, + efi_guid_to_str((const efi_guid_t *)&guid)); printf("Attributes: 0x%x\n", attributes); } @@ -592,8 +532,8 @@ int do_env_set_efi(struct cmd_tbl *cmdtp, int flag, int argc, p = var_name16; utf8_utf16_strncpy(&p, var_name, len + 1); - ret = EFI_CALL(efi_set_variable(var_name16, &guid, attributes, - size, value)); + ret = efi_set_variable_int(var_name16, &guid, attributes, size, value, + true); unmap_sysmem(value); if (ret == EFI_SUCCESS) { ret = CMD_RET_SUCCESS; diff --git a/configs/da850evm_direct_nor_defconfig b/configs/da850evm_direct_nor_defconfig index 36ef122ba3..3924895204 100644 --- a/configs/da850evm_direct_nor_defconfig +++ b/configs/da850evm_direct_nor_defconfig @@ -10,7 +10,6 @@ CONFIG_ENV_SIZE=0x2800 CONFIG_ENV_SECT_SIZE=0x20000 CONFIG_DM_GPIO=y CONFIG_NR_DRAM_BANKS=1 -CONFIG_SYS_EXTRA_OPTIONS="USE_NOR,DIRECT_NOR_BOOT" CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="mem=32M console=ttyS2,115200n8 root=/dev/mtdblock2 rw noinitrd ip=dhcp" diff --git a/configs/omap3_beagle_defconfig b/configs/omap3_beagle_defconfig index af5b8ea872..b08ffc062d 100644 --- a/configs/omap3_beagle_defconfig +++ b/configs/omap3_beagle_defconfig @@ -73,10 +73,13 @@ CONFIG_SYS_NAND_BUSWIDTH_16BIT=y CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y CONFIG_SYS_NAND_U_BOOT_OFFS=0x80000 CONFIG_SPL_NAND_SIMPLE=y +CONFIG_DM_ETH=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_OMAP3_SPI=y CONFIG_USB=y +CONFIG_DM_USB=y +# CONFIG_SPL_DM_USB is not set CONFIG_USB_EHCI_HCD=y CONFIG_USB_OMAP3=y CONFIG_USB_MUSB_GADGET=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 9b74e404bb..d43d78df6f 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -48,6 +48,7 @@ CONFIG_CMD_GPT=y CONFIG_CMD_GPT_RENAME=y CONFIG_CMD_IDE=y CONFIG_CMD_I2C=y +CONFIG_CMD_LSBLK=y CONFIG_CMD_OSD=y CONFIG_CMD_PCI=y CONFIG_CMD_READ=y diff --git a/doc/README.davinci b/doc/README.davinci index 6522c24eea..607531af2a 100644 --- a/doc/README.davinci +++ b/doc/README.davinci @@ -37,11 +37,15 @@ Bootloaders =============== For DA850 an SPL (secondary program loader, see doc/README.SPL) is provided -to load U-Boot directly from SPI flash. The SPL takes care of the low level +to load U-Boot from SPI flash, MMC or NAND. The SPL takes care of the low level initialization. -The SPL is built as u-boot.ais for all DA850 defconfigs. The resulting -image file can be programmed to the SPI flash of the DA850 EVM/LCDK. +The SPL is built as u-boot.ais for all DA850 defconfigs except those booting +from NOR flash. The resulting image file can be programmed to the SPI flash +of the DA850 EVM/LCDK. + +Devices that support booting from NOR utilize execute in place (XIP) and do +not require SPL to perform low level initialization. Environment Variables ===================== diff --git a/doc/README.dfutftp b/doc/README.dfutftp index 127d2d6abc..a3341bbb61 100644 --- a/doc/README.dfutftp +++ b/doc/README.dfutftp @@ -42,8 +42,6 @@ for USB based DFU (CONFIG_DFU_*) and DFU TFTP update The "dfu" command has been extended to support transfer via TFTP - one needs to type for example "dfu tftp 0 mmc 0" -This feature does not depend on "fitupd" command enabled. - As of this writing (SHA1:8d77576371381ade83de475bb639949b44941e8c v2015.10-rc2) the update.c code is not enabled (CONFIG_UPDATE_TFTP) by any board in the contemporary u-boot tree. diff --git a/doc/README.update b/doc/README.update index d37f2c4d4a..bf4379279e 100644 --- a/doc/README.update +++ b/doc/README.update @@ -51,11 +51,6 @@ the mkimage tool. dtc tool with support for binary includes, e.g. in version to be prepared. Refer to the doc/uImage.FIT/ directory for more details on FIT images. -This mechanism can be also triggered by the command "fitupd". -If an optional, non-zero address is provided as argument, the TFTP transfer -is skipped and the image at this address is used. -The fitupd command is enabled by CONFIG_CMD_FITUPD. - Example .its files ------------------ diff --git a/doc/api/efi.rst b/doc/api/efi.rst index d5114f05b3..cb2a1c897e 100644 --- a/doc/api/efi.rst +++ b/doc/api/efi.rst @@ -93,6 +93,8 @@ Runtime services Variable services ~~~~~~~~~~~~~~~~~ +.. kernel-doc:: include/efi_variable.h + :internal: .. kernel-doc:: lib/efi_loader/efi_variable.c :internal: diff --git a/doc/uefi/uefi.rst b/doc/uefi/uefi.rst index 03d6fd0c6a..a72e729cc8 100644 --- a/doc/uefi/uefi.rst +++ b/doc/uefi/uefi.rst @@ -188,6 +188,15 @@ on the sandbox cd <U-Boot source directory> pytest.py test/py/tests/test_efi_secboot/test_signed.py --bd sandbox +UEFI binaries may be signed by Microsoft using the following certificates: + +* KEK: Microsoft Corporation KEK CA 2011 + http://go.microsoft.com/fwlink/?LinkId=321185. +* db: Microsoft Windows Production PCA 2011 + http://go.microsoft.com/fwlink/p/?linkid=321192. +* db: Microsoft Corporation UEFI CA 2011 + http://go.microsoft.com/fwlink/p/?linkid=321194. + Using OP-TEE for EFI variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/dma/ti/Kconfig b/drivers/dma/ti/Kconfig index 3d5498326c..9cbd5f334d 100644 --- a/drivers/dma/ti/Kconfig +++ b/drivers/dma/ti/Kconfig @@ -8,7 +8,11 @@ config TI_K3_NAVSS_UDMA select DMA select TI_K3_NAVSS_RINGACC select TI_K3_NAVSS_PSILCFG + select TI_K3_PSIL default n help Support for UDMA used in K3 devices. endif + +config TI_K3_PSIL + bool diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile index de2f9ac91a..4ea9c626cc 100644 --- a/drivers/dma/ti/Makefile +++ b/drivers/dma/ti/Makefile @@ -1,3 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ obj-$(CONFIG_TI_K3_NAVSS_UDMA) += k3-udma.o +obj-$(CONFIG_TI_K3_PSIL) += k3-psil-data.o +k3-psil-data-y += k3-psil.o +k3-psil-data-$(CONFIG_SOC_K3_AM6) += k3-psil-am654.o +k3-psil-data-$(CONFIG_SOC_K3_J721E) += k3-psil-j721e.o diff --git a/drivers/dma/ti/k3-psil-am654.c b/drivers/dma/ti/k3-psil-am654.c new file mode 100644 index 0000000000..f95d99cfd3 --- /dev/null +++ b/drivers/dma/ti/k3-psil-am654.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> + */ + +#include <linux/kernel.h> + +#include "k3-psil-priv.h" + +#define PSIL_ETHERNET(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 16, \ + }, \ + } + +/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */ +static struct psil_ep am654_src_ep_map[] = { + /* PRU_ICSSG0 */ + PSIL_ETHERNET(0x4100), + PSIL_ETHERNET(0x4101), + PSIL_ETHERNET(0x4102), + PSIL_ETHERNET(0x4103), + /* PRU_ICSSG1 */ + PSIL_ETHERNET(0x4200), + PSIL_ETHERNET(0x4201), + PSIL_ETHERNET(0x4202), + PSIL_ETHERNET(0x4203), + /* PRU_ICSSG2 */ + PSIL_ETHERNET(0x4300), + PSIL_ETHERNET(0x4301), + PSIL_ETHERNET(0x4302), + PSIL_ETHERNET(0x4303), + /* CPSW0 */ + PSIL_ETHERNET(0x7000), +}; + +/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ +static struct psil_ep am654_dst_ep_map[] = { + /* PRU_ICSSG0 */ + PSIL_ETHERNET(0xc100), + PSIL_ETHERNET(0xc101), + PSIL_ETHERNET(0xc102), + PSIL_ETHERNET(0xc103), + PSIL_ETHERNET(0xc104), + PSIL_ETHERNET(0xc105), + PSIL_ETHERNET(0xc106), + PSIL_ETHERNET(0xc107), + /* PRU_ICSSG1 */ + PSIL_ETHERNET(0xc200), + PSIL_ETHERNET(0xc201), + PSIL_ETHERNET(0xc202), + PSIL_ETHERNET(0xc203), + PSIL_ETHERNET(0xc204), + PSIL_ETHERNET(0xc205), + PSIL_ETHERNET(0xc206), + PSIL_ETHERNET(0xc207), + /* PRU_ICSSG2 */ + PSIL_ETHERNET(0xc300), + PSIL_ETHERNET(0xc301), + PSIL_ETHERNET(0xc302), + PSIL_ETHERNET(0xc303), + PSIL_ETHERNET(0xc304), + PSIL_ETHERNET(0xc305), + PSIL_ETHERNET(0xc306), + PSIL_ETHERNET(0xc307), + /* CPSW0 */ + PSIL_ETHERNET(0xf000), + PSIL_ETHERNET(0xf001), + PSIL_ETHERNET(0xf002), + PSIL_ETHERNET(0xf003), + PSIL_ETHERNET(0xf004), + PSIL_ETHERNET(0xf005), + PSIL_ETHERNET(0xf006), + PSIL_ETHERNET(0xf007), +}; + +struct psil_ep_map am654_ep_map = { + .name = "am654", + .src = am654_src_ep_map, + .src_count = ARRAY_SIZE(am654_src_ep_map), + .dst = am654_dst_ep_map, + .dst_count = ARRAY_SIZE(am654_dst_ep_map), +}; diff --git a/drivers/dma/ti/k3-psil-j721e.c b/drivers/dma/ti/k3-psil-j721e.c new file mode 100644 index 0000000000..105ffd946f --- /dev/null +++ b/drivers/dma/ti/k3-psil-j721e.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> + */ + +#include <linux/kernel.h> + +#include "k3-psil-priv.h" + +#define PSIL_ETHERNET(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 16, \ + }, \ + } + +/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */ +static struct psil_ep j721e_src_ep_map[] = { + /* CPSW0 */ + PSIL_ETHERNET(0x7000), +}; + +/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ +static struct psil_ep j721e_dst_ep_map[] = { + /* CPSW0 */ + PSIL_ETHERNET(0xf000), + PSIL_ETHERNET(0xf001), + PSIL_ETHERNET(0xf002), + PSIL_ETHERNET(0xf003), + PSIL_ETHERNET(0xf004), + PSIL_ETHERNET(0xf005), + PSIL_ETHERNET(0xf006), + PSIL_ETHERNET(0xf007), +}; + +struct psil_ep_map j721e_ep_map = { + .name = "j721e", + .src = j721e_src_ep_map, + .src_count = ARRAY_SIZE(j721e_src_ep_map), + .dst = j721e_dst_ep_map, + .dst_count = ARRAY_SIZE(j721e_dst_ep_map), +}; diff --git a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h new file mode 100644 index 0000000000..d3a38322b1 --- /dev/null +++ b/drivers/dma/ti/k3-psil-priv.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + */ + +#ifndef K3_PSIL_PRIV_H_ +#define K3_PSIL_PRIV_H_ + +#include "k3-psil.h" + +struct psil_ep { + u32 thread_id; + struct psil_endpoint_config ep_config; +}; + +/** + * struct psil_ep_map - PSI-L thread ID configuration maps + * @name: Name of the map, set it to the name of the SoC + * @src: Array of source PSI-L thread configurations + * @src_count: Number of entries in the src array + * @dst: Array of destination PSI-L thread configurations + * @dst_count: Number of entries in the dst array + * + * In case of symmetric configuration for a matching src/dst thread (for example + * 0x4400 and 0xc400) only the src configuration can be present. If no dst + * configuration found the code will look for (dst_thread_id & ~0x8000) to find + * the symmetric match. + */ +struct psil_ep_map { + char *name; + struct psil_ep *src; + int src_count; + struct psil_ep *dst; + int dst_count; +}; + +struct psil_endpoint_config *psil_get_ep_config(u32 thread_id); + +/* SoC PSI-L endpoint maps */ +extern struct psil_ep_map am654_ep_map; +extern struct psil_ep_map j721e_ep_map; + +#endif /* K3_PSIL_PRIV_H_ */ diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c new file mode 100644 index 0000000000..b5c92b2829 --- /dev/null +++ b/drivers/dma/ti/k3-psil.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> + */ + +#include <linux/kernel.h> +#include <linux/err.h> + +#include "k3-psil-priv.h" + +static const struct psil_ep_map *soc_ep_map; + +struct psil_endpoint_config *psil_get_ep_config(u32 thread_id) +{ + int i; + + if (!soc_ep_map) { + if (IS_ENABLED(CONFIG_SOC_K3_AM6)) + soc_ep_map = &am654_ep_map; + else if (IS_ENABLED(CONFIG_SOC_K3_J721E)) + soc_ep_map = &j721e_ep_map; + } + + if (thread_id & K3_PSIL_DST_THREAD_ID_OFFSET && soc_ep_map->dst) { + /* check in destination thread map */ + for (i = 0; i < soc_ep_map->dst_count; i++) { + if (soc_ep_map->dst[i].thread_id == thread_id) + return &soc_ep_map->dst[i].ep_config; + } + } + + thread_id &= ~K3_PSIL_DST_THREAD_ID_OFFSET; + if (soc_ep_map->src) { + for (i = 0; i < soc_ep_map->src_count; i++) { + if (soc_ep_map->src[i].thread_id == thread_id) + return &soc_ep_map->src[i].ep_config; + } + } + + return ERR_PTR(-ENOENT); +} diff --git a/drivers/dma/ti/k3-psil.h b/drivers/dma/ti/k3-psil.h new file mode 100644 index 0000000000..53c61b4595 --- /dev/null +++ b/drivers/dma/ti/k3-psil.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + */ + +#ifndef K3_PSIL_H_ +#define K3_PSIL_H_ + +#include <linux/types.h> + +#define K3_PSIL_DST_THREAD_ID_OFFSET 0x8000 + +struct device; + +/** + * enum udma_tp_level - Channel Throughput Levels + * @UDMA_TP_NORMAL: Normal channel + * @UDMA_TP_HIGH: High Throughput channel + * @UDMA_TP_ULTRAHIGH: Ultra High Throughput channel + */ +enum udma_tp_level { + UDMA_TP_NORMAL = 0, + UDMA_TP_HIGH, + UDMA_TP_ULTRAHIGH, + UDMA_TP_LAST, +}; + +/** + * enum psil_endpoint_type - PSI-L Endpoint type + * @PSIL_EP_NATIVE: Normal channel + * @PSIL_EP_PDMA_XY: XY mode PDMA + * @PSIL_EP_PDMA_MCAN: MCAN mode PDMA + * @PSIL_EP_PDMA_AASRC: AASRC mode PDMA + */ +enum psil_endpoint_type { + PSIL_EP_NATIVE = 0, + PSIL_EP_PDMA_XY, + PSIL_EP_PDMA_MCAN, + PSIL_EP_PDMA_AASRC, +}; + +/** + * struct psil_endpoint_config - PSI-L Endpoint configuration + * @ep_type: PSI-L endpoint type + * @pkt_mode: If set, the channel must be in Packet mode, otherwise in + * TR mode + * @notdpkt: TDCM must be suppressed on the TX channel + * @needs_epib: Endpoint needs EPIB + * @psd_size: If set, PSdata is used by the endpoint + * @channel_tpl: Desired throughput level for the channel + * @pdma_acc32: ACC32 must be enabled on the PDMA side + * @pdma_burst: BURST must be enabled on the PDMA side + */ +struct psil_endpoint_config { + enum psil_endpoint_type ep_type; + + unsigned pkt_mode:1; + unsigned notdpkt:1; + unsigned needs_epib:1; + u32 psd_size; + enum udma_tp_level channel_tpl; + + /* PDMA properties, valid for PSIL_EP_PDMA_* */ + unsigned pdma_acc32:1; + unsigned pdma_burst:1; +}; +#endif /* K3_PSIL_H_ */ diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 2ce16c8e27..57d9fbfabb 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -22,7 +22,6 @@ #include <dma.h> #include <dma-uclass.h> #include <linux/delay.h> -#include <dt-bindings/dma/k3-udma.h> #include <linux/bitmap.h> #include <linux/err.h> #include <linux/soc/ti/k3-navss-ringacc.h> @@ -31,12 +30,7 @@ #include <linux/soc/ti/ti_sci_protocol.h> #include "k3-udma-hwdef.h" - -#if BITS_PER_LONG == 64 -#define RINGACC_RING_USE_PROXY (0) -#else -#define RINGACC_RING_USE_PROXY (1) -#endif +#include "k3-psil-priv.h" #define K3_UDMA_MAX_RFLOWS 1024 @@ -65,12 +59,28 @@ struct udma_rchan { void __iomem *reg_rt; int id; - struct k3_nav_ring *fd_ring; /* Free Descriptor ring */ - struct k3_nav_ring *r_ring; /* Receive ring*/ +}; + +#define UDMA_FLAG_PDMA_ACC32 BIT(0) +#define UDMA_FLAG_PDMA_BURST BIT(1) +#define UDMA_FLAG_TDTYPE BIT(2) + +struct udma_match_data { + u32 psil_base; + bool enable_memcpy_support; + u32 flags; + u32 statictr_z_mask; + u32 rchan_oes_offset; + + u8 tpl_levels; + u32 level_start_idx[]; }; struct udma_rflow { int id; + + struct k3_nav_ring *fd_ring; /* Free Descriptor ring */ + struct k3_nav_ring *r_ring; /* Receive ring*/ }; enum udma_rm_range { @@ -114,12 +124,34 @@ struct udma_dev { struct udma_rchan *rchans; struct udma_rflow *rflows; + struct udma_match_data *match_data; + struct udma_chan *channels; u32 psil_base; u32 ch_count; }; +struct udma_chan_config { + u32 psd_size; /* size of Protocol Specific Data */ + u32 metadata_size; /* (needs_epib ? 16:0) + psd_size */ + u32 hdesc_size; /* Size of a packet descriptor in packet mode */ + int remote_thread_id; + u32 atype; + u32 src_thread; + u32 dst_thread; + enum psil_endpoint_type ep_type; + enum udma_tp_level channel_tpl; /* Channel Throughput Level */ + + enum dma_direction dir; + + unsigned int pkt_mode:1; /* TR or packet */ + unsigned int needs_epib:1; /* EPIB is needed for the communication or not */ + unsigned int enable_acc32:1; + unsigned int enable_burst:1; + unsigned int notdpkt:1; /* Suppress sending TDC packet */ +}; + struct udma_chan { struct udma_dev *ud; char name[20]; @@ -132,20 +164,11 @@ struct udma_chan { u32 bcnt; /* number of bytes completed since the start of the channel */ - bool pkt_mode; /* TR or packet */ - bool needs_epib; /* EPIB is needed for the communication or not */ - u32 psd_size; /* size of Protocol Specific Data */ - u32 metadata_size; /* (needs_epib ? 16:0) + psd_size */ - int slave_thread_id; - u32 src_thread; - u32 dst_thread; - u32 static_tr_type; + struct udma_chan_config config; u32 id; - enum dma_direction dir; struct cppi5_host_desc_t *desc_tx; - u32 hdesc_size; bool in_use; void *desc_rx; u32 num_rx_bufs; @@ -271,7 +294,7 @@ static inline bool udma_is_chan_running(struct udma_chan *uc) u32 trt_ctl = 0; u32 rrt_ctl = 0; - switch (uc->dir) { + switch (uc->config.dir) { case DMA_DEV_TO_MEM: rrt_ctl = udma_rchanrt_read(uc->rchan, UDMA_RCHAN_RT_CTL_REG); pr_debug("%s: rrt_ctl: 0x%08x (peer: 0x%08x)\n", @@ -305,9 +328,9 @@ static int udma_pop_from_ring(struct udma_chan *uc, dma_addr_t *addr) struct k3_nav_ring *ring = NULL; int ret = -ENOENT; - switch (uc->dir) { + switch (uc->config.dir) { case DMA_DEV_TO_MEM: - ring = uc->rchan->r_ring; + ring = uc->rflow->r_ring; break; case DMA_MEM_TO_DEV: ring = uc->tchan->tc_ring; @@ -330,10 +353,10 @@ static void udma_reset_rings(struct udma_chan *uc) struct k3_nav_ring *ring1 = NULL; struct k3_nav_ring *ring2 = NULL; - switch (uc->dir) { + switch (uc->config.dir) { case DMA_DEV_TO_MEM: - ring1 = uc->rchan->fd_ring; - ring2 = uc->rchan->r_ring; + ring1 = uc->rflow->fd_ring; + ring2 = uc->rflow->r_ring; break; case DMA_MEM_TO_DEV: ring1 = uc->tchan->t_ring; @@ -392,7 +415,7 @@ static inline int udma_stop_hard(struct udma_chan *uc) { pr_debug("%s: ENTER (chan%d)\n", __func__, uc->id); - switch (uc->dir) { + switch (uc->config.dir) { case DMA_DEV_TO_MEM: udma_rchanrt_write(uc->rchan, UDMA_RCHAN_RT_PEER_RT_EN_REG, 0); udma_rchanrt_write(uc->rchan, UDMA_RCHAN_RT_CTL_REG, 0); @@ -418,9 +441,8 @@ static int udma_start(struct udma_chan *uc) if (udma_is_chan_running(uc)) goto out; - pr_debug("%s: chan:%d dir:%s (static_tr_type: %d)\n", - __func__, uc->id, udma_get_dir_text(uc->dir), - uc->static_tr_type); + pr_debug("%s: chan:%d dir:%s\n", + __func__, uc->id, udma_get_dir_text(uc->config.dir)); /* Make sure that we clear the teardown bit, if it is set */ udma_stop_hard(uc); @@ -428,7 +450,7 @@ static int udma_start(struct udma_chan *uc) /* Reset all counters */ udma_reset_counters(uc); - switch (uc->dir) { + switch (uc->config.dir) { case DMA_DEV_TO_MEM: udma_rchanrt_write(uc->rchan, UDMA_RCHAN_RT_CTL_REG, UDMA_CHAN_RT_CTL_EN); @@ -530,10 +552,10 @@ static inline void udma_stop_dev2mem(struct udma_chan *uc, bool sync) static inline int udma_stop(struct udma_chan *uc) { pr_debug("%s: chan:%d dir:%s\n", - __func__, uc->id, udma_get_dir_text(uc->dir)); + __func__, uc->id, udma_get_dir_text(uc->config.dir)); udma_reset_counters(uc); - switch (uc->dir) { + switch (uc->config.dir) { case DMA_DEV_TO_MEM: udma_stop_dev2mem(uc, true); break; @@ -768,21 +790,14 @@ static int udma_alloc_tx_resources(struct udma_chan *uc) if (ret) return ret; - uc->tchan->t_ring = k3_nav_ringacc_request_ring( - ud->ringacc, uc->tchan->id, - RINGACC_RING_USE_PROXY); - if (!uc->tchan->t_ring) { + ret = k3_nav_ringacc_request_rings_pair(ud->ringacc, uc->tchan->id, -1, + &uc->tchan->t_ring, + &uc->tchan->tc_ring); + if (ret) { ret = -EBUSY; goto err_tx_ring; } - uc->tchan->tc_ring = k3_nav_ringacc_request_ring( - ud->ringacc, -1, RINGACC_RING_USE_PROXY); - if (!uc->tchan->tc_ring) { - ret = -EBUSY; - goto err_txc_ring; - } - memset(&ring_cfg, 0, sizeof(ring_cfg)); ring_cfg.size = 16; ring_cfg.elm_size = K3_NAV_RINGACC_RING_ELSIZE_8; @@ -799,7 +814,6 @@ static int udma_alloc_tx_resources(struct udma_chan *uc) err_ringcfg: k3_nav_ringacc_ring_free(uc->tchan->tc_ring); uc->tchan->tc_ring = NULL; -err_txc_ring: k3_nav_ringacc_ring_free(uc->tchan->t_ring); uc->tchan->t_ring = NULL; err_tx_ring: @@ -813,12 +827,15 @@ static void udma_free_rx_resources(struct udma_chan *uc) if (!uc->rchan) return; - k3_nav_ringacc_ring_free(uc->rchan->fd_ring); - k3_nav_ringacc_ring_free(uc->rchan->r_ring); - uc->rchan->fd_ring = NULL; - uc->rchan->r_ring = NULL; + if (uc->rflow) { + k3_nav_ringacc_ring_free(uc->rflow->fd_ring); + k3_nav_ringacc_ring_free(uc->rflow->r_ring); + uc->rflow->fd_ring = NULL; + uc->rflow->r_ring = NULL; + + udma_put_rflow(uc); + } - udma_put_rflow(uc); udma_put_rchan(uc); } @@ -826,6 +843,7 @@ static int udma_alloc_rx_resources(struct udma_chan *uc) { struct k3_nav_ring_cfg ring_cfg; struct udma_dev *ud = uc->ud; + struct udma_rflow *rflow; int fd_ring_id; int ret; @@ -834,7 +852,7 @@ static int udma_alloc_rx_resources(struct udma_chan *uc) return ret; /* For MEM_TO_MEM we don't need rflow or rings */ - if (uc->dir == DMA_MEM_TO_MEM) + if (uc->config.dir == DMA_MEM_TO_MEM) return 0; ret = udma_get_rflow(uc, uc->rchan->id); @@ -845,40 +863,31 @@ static int udma_alloc_rx_resources(struct udma_chan *uc) fd_ring_id = ud->tchan_cnt + ud->echan_cnt + uc->rchan->id; - uc->rchan->fd_ring = k3_nav_ringacc_request_ring( - ud->ringacc, fd_ring_id, - RINGACC_RING_USE_PROXY); - if (!uc->rchan->fd_ring) { + rflow = uc->rflow; + ret = k3_nav_ringacc_request_rings_pair(ud->ringacc, fd_ring_id, -1, + &rflow->fd_ring, &rflow->r_ring); + if (ret) { ret = -EBUSY; goto err_rx_ring; } - uc->rchan->r_ring = k3_nav_ringacc_request_ring( - ud->ringacc, -1, RINGACC_RING_USE_PROXY); - if (!uc->rchan->r_ring) { - ret = -EBUSY; - goto err_rxc_ring; - } - memset(&ring_cfg, 0, sizeof(ring_cfg)); ring_cfg.size = 16; ring_cfg.elm_size = K3_NAV_RINGACC_RING_ELSIZE_8; ring_cfg.mode = K3_NAV_RINGACC_RING_MODE_RING; - ret = k3_nav_ringacc_ring_cfg(uc->rchan->fd_ring, &ring_cfg); - ret |= k3_nav_ringacc_ring_cfg(uc->rchan->r_ring, &ring_cfg); - + ret = k3_nav_ringacc_ring_cfg(rflow->fd_ring, &ring_cfg); + ret |= k3_nav_ringacc_ring_cfg(rflow->r_ring, &ring_cfg); if (ret) goto err_ringcfg; return 0; err_ringcfg: - k3_nav_ringacc_ring_free(uc->rchan->r_ring); - uc->rchan->r_ring = NULL; -err_rxc_ring: - k3_nav_ringacc_ring_free(uc->rchan->fd_ring); - uc->rchan->fd_ring = NULL; + k3_nav_ringacc_ring_free(rflow->r_ring); + rflow->r_ring = NULL; + k3_nav_ringacc_ring_free(rflow->fd_ring); + rflow->fd_ring = NULL; err_rx_ring: udma_put_rflow(uc); err_rflow: @@ -896,7 +905,7 @@ static int udma_alloc_tchan_sci_req(struct udma_chan *uc) u32 mode; int ret; - if (uc->pkt_mode) + if (uc->config.pkt_mode) mode = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR; else mode = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR; @@ -907,11 +916,11 @@ static int udma_alloc_tchan_sci_req(struct udma_chan *uc) req.nav_id = tisci_rm->tisci_dev_id; req.index = uc->tchan->id; req.tx_chan_type = mode; - if (uc->dir == DMA_MEM_TO_MEM) + if (uc->config.dir == DMA_MEM_TO_MEM) req.tx_fetch_size = sizeof(struct cppi5_desc_hdr_t) >> 2; else - req.tx_fetch_size = cppi5_hdesc_calc_size(uc->needs_epib, - uc->psd_size, + req.tx_fetch_size = cppi5_hdesc_calc_size(uc->config.needs_epib, + uc->config.psd_size, 0) >> 2; req.txcq_qnum = tc_ring; @@ -925,8 +934,8 @@ static int udma_alloc_tchan_sci_req(struct udma_chan *uc) static int udma_alloc_rchan_sci_req(struct udma_chan *uc) { struct udma_dev *ud = uc->ud; - int fd_ring = k3_nav_ringacc_get_ring_id(uc->rchan->fd_ring); - int rx_ring = k3_nav_ringacc_get_ring_id(uc->rchan->r_ring); + int fd_ring = k3_nav_ringacc_get_ring_id(uc->rflow->fd_ring); + int rx_ring = k3_nav_ringacc_get_ring_id(uc->rflow->r_ring); int tc_ring = k3_nav_ringacc_get_ring_id(uc->tchan->tc_ring); struct ti_sci_msg_rm_udmap_rx_ch_cfg req = { 0 }; struct ti_sci_msg_rm_udmap_flow_cfg flow_req = { 0 }; @@ -934,7 +943,7 @@ static int udma_alloc_rchan_sci_req(struct udma_chan *uc) u32 mode; int ret; - if (uc->pkt_mode) + if (uc->config.pkt_mode) mode = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR; else mode = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR; @@ -947,16 +956,16 @@ static int udma_alloc_rchan_sci_req(struct udma_chan *uc) req.nav_id = tisci_rm->tisci_dev_id; req.index = uc->rchan->id; req.rx_chan_type = mode; - if (uc->dir == DMA_MEM_TO_MEM) { + if (uc->config.dir == DMA_MEM_TO_MEM) { req.rx_fetch_size = sizeof(struct cppi5_desc_hdr_t) >> 2; req.rxcq_qnum = tc_ring; } else { - req.rx_fetch_size = cppi5_hdesc_calc_size(uc->needs_epib, - uc->psd_size, + req.rx_fetch_size = cppi5_hdesc_calc_size(uc->config.needs_epib, + uc->config.psd_size, 0) >> 2; req.rxcq_qnum = rx_ring; } - if (uc->rflow->id != uc->rchan->id && uc->dir != DMA_MEM_TO_MEM) { + if (uc->rflow->id != uc->rchan->id && uc->config.dir != DMA_MEM_TO_MEM) { req.flowid_start = uc->rflow->id; req.flowid_cnt = 1; } @@ -967,7 +976,7 @@ static int udma_alloc_rchan_sci_req(struct udma_chan *uc) uc->rchan->id, ret); return ret; } - if (uc->dir == DMA_MEM_TO_MEM) + if (uc->config.dir == DMA_MEM_TO_MEM) return ret; flow_req.valid_params = @@ -989,12 +998,12 @@ static int udma_alloc_rchan_sci_req(struct udma_chan *uc) flow_req.nav_id = tisci_rm->tisci_dev_id; flow_req.flow_index = uc->rflow->id; - if (uc->needs_epib) + if (uc->config.needs_epib) flow_req.rx_einfo_present = 1; else flow_req.rx_einfo_present = 0; - if (uc->psd_size) + if (uc->config.psd_size) flow_req.rx_psinfo_present = 1; else flow_req.rx_psinfo_present = 0; @@ -1027,11 +1036,12 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) int ret; pr_debug("%s: chan:%d as %s\n", - __func__, uc->id, udma_get_dir_text(uc->dir)); + __func__, uc->id, udma_get_dir_text(uc->config.dir)); - switch (uc->dir) { + switch (uc->config.dir) { case DMA_MEM_TO_MEM: /* Non synchronized - mem to mem type of transfer */ + uc->config.pkt_mode = false; ret = udma_get_chan_pair(uc); if (ret) return ret; @@ -1044,8 +1054,8 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) if (ret) goto err_free_res; - uc->src_thread = ud->psil_base + uc->tchan->id; - uc->dst_thread = (ud->psil_base + uc->rchan->id) | 0x8000; + uc->config.src_thread = ud->psil_base + uc->tchan->id; + uc->config.dst_thread = (ud->psil_base + uc->rchan->id) | 0x8000; break; case DMA_MEM_TO_DEV: /* Slave transfer synchronized - mem to dev (TX) trasnfer */ @@ -1053,10 +1063,9 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) if (ret) goto err_free_res; - uc->src_thread = ud->psil_base + uc->tchan->id; - uc->dst_thread = uc->slave_thread_id; - if (!(uc->dst_thread & 0x8000)) - uc->dst_thread |= 0x8000; + uc->config.src_thread = ud->psil_base + uc->tchan->id; + uc->config.dst_thread = uc->config.remote_thread_id; + uc->config.dst_thread |= 0x8000; break; case DMA_DEV_TO_MEM: @@ -1065,19 +1074,19 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) if (ret) goto err_free_res; - uc->src_thread = uc->slave_thread_id; - uc->dst_thread = (ud->psil_base + uc->rchan->id) | 0x8000; + uc->config.src_thread = uc->config.remote_thread_id; + uc->config.dst_thread = (ud->psil_base + uc->rchan->id) | 0x8000; break; default: /* Can not happen */ pr_debug("%s: chan:%d invalid direction (%u)\n", - __func__, uc->id, uc->dir); + __func__, uc->id, uc->config.dir); return -EINVAL; } /* We have channel indexes and rings */ - if (uc->dir == DMA_MEM_TO_MEM) { + if (uc->config.dir == DMA_MEM_TO_MEM) { ret = udma_alloc_tchan_sci_req(uc); if (ret) goto err_free_res; @@ -1087,7 +1096,7 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) goto err_free_res; } else { /* Slave transfer */ - if (uc->dir == DMA_MEM_TO_DEV) { + if (uc->config.dir == DMA_MEM_TO_DEV) { ret = udma_alloc_tchan_sci_req(uc); if (ret) goto err_free_res; @@ -1108,7 +1117,7 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) } /* PSI-L pairing */ - ret = udma_navss_psil_pair(ud, uc->src_thread, uc->dst_thread); + ret = udma_navss_psil_pair(ud, uc->config.src_thread, uc->config.dst_thread); if (ret) { dev_err(ud->dev, "k3_nav_psil_request_link fail\n"); goto err_free_res; @@ -1119,7 +1128,7 @@ static int udma_alloc_chan_resources(struct udma_chan *uc) err_free_res: udma_free_tx_resources(uc); udma_free_rx_resources(uc); - uc->slave_thread_id = -1; + uc->config.remote_thread_id = -1; return ret; } @@ -1128,15 +1137,15 @@ static void udma_free_chan_resources(struct udma_chan *uc) /* Some configuration to UDMA-P channel: disable, reset, whatever */ /* Release PSI-L pairing */ - udma_navss_psil_unpair(uc->ud, uc->src_thread, uc->dst_thread); + udma_navss_psil_unpair(uc->ud, uc->config.src_thread, uc->config.dst_thread); /* Reset the rings for a new start */ udma_reset_rings(uc); udma_free_tx_resources(uc); udma_free_rx_resources(uc); - uc->slave_thread_id = -1; - uc->dir = DMA_MEM_TO_MEM; + uc->config.remote_thread_id = -1; + uc->config.dir = DMA_MEM_TO_MEM; } static int udma_get_mmrs(struct udevice *dev) @@ -1293,12 +1302,8 @@ static int udma_probe(struct udevice *dev) if (IS_ERR(ud->ringacc)) return PTR_ERR(ud->ringacc); - ud->psil_base = dev_read_u32_default(dev, "ti,psil-base", 0); - if (!ud->psil_base) { - dev_info(dev, - "Missing ti,psil-base property, using %d.\n", ret); - return -EINVAL; - } + ud->match_data = (void *)dev_get_driver_data(dev); + ud->psil_base = ud->match_data->psil_base; ret = uclass_get_device_by_phandle(UCLASS_FIRMWARE, dev, "ti,sci", &tisci_dev); @@ -1364,10 +1369,10 @@ static int udma_probe(struct udevice *dev) uc->ud = ud; uc->id = i; - uc->slave_thread_id = -1; + uc->config.remote_thread_id = -1; uc->tchan = NULL; uc->rchan = NULL; - uc->dir = DMA_MEM_TO_MEM; + uc->config.dir = DMA_MEM_TO_MEM; sprintf(uc->name, "UDMA chan%d\n", i); if (!i) uc->in_use = true; @@ -1514,6 +1519,7 @@ static int udma_transfer(struct udevice *dev, int direction, static int udma_request(struct dma *dma) { struct udma_dev *ud = dev_get_priv(dma->dev); + struct udma_chan_config *ucc; struct udma_chan *uc; unsigned long dummy; int ret; @@ -1524,30 +1530,27 @@ static int udma_request(struct dma *dma) } uc = &ud->channels[dma->id]; + ucc = &uc->config; ret = udma_alloc_chan_resources(uc); if (ret) { dev_err(dma->dev, "alloc dma res failed %d\n", ret); return -EINVAL; } - uc->hdesc_size = cppi5_hdesc_calc_size(uc->needs_epib, - uc->psd_size, 0); - uc->hdesc_size = ALIGN(uc->hdesc_size, ARCH_DMA_MINALIGN); - - if (uc->dir == DMA_MEM_TO_DEV) { - uc->desc_tx = dma_alloc_coherent(uc->hdesc_size, &dummy); - memset(uc->desc_tx, 0, uc->hdesc_size); + if (uc->config.dir == DMA_MEM_TO_DEV) { + uc->desc_tx = dma_alloc_coherent(ucc->hdesc_size, &dummy); + memset(uc->desc_tx, 0, ucc->hdesc_size); } else { uc->desc_rx = dma_alloc_coherent( - uc->hdesc_size * UDMA_RX_DESC_NUM, &dummy); - memset(uc->desc_rx, 0, uc->hdesc_size * UDMA_RX_DESC_NUM); + ucc->hdesc_size * UDMA_RX_DESC_NUM, &dummy); + memset(uc->desc_rx, 0, ucc->hdesc_size * UDMA_RX_DESC_NUM); } uc->in_use = true; uc->desc_rx_cur = 0; uc->num_rx_bufs = 0; - if (uc->dir == DMA_DEV_TO_MEM) { + if (uc->config.dir == DMA_DEV_TO_MEM) { uc->cfg_data.flow_id_base = uc->rflow->id; uc->cfg_data.flow_id_cnt = 1; } @@ -1632,7 +1635,7 @@ static int udma_send(struct dma *dma, void *src, size_t len, void *metadata) } uc = &ud->channels[dma->id]; - if (uc->dir != DMA_MEM_TO_DEV) + if (uc->config.dir != DMA_MEM_TO_DEV) return -EINVAL; tc_ring_id = k3_nav_ringacc_get_ring_id(uc->tchan->tc_ring); @@ -1642,8 +1645,8 @@ static int udma_send(struct dma *dma, void *src, size_t len, void *metadata) cppi5_hdesc_reset_hbdesc(desc_tx); cppi5_hdesc_init(desc_tx, - uc->needs_epib ? CPPI5_INFO0_HDESC_EPIB_PRESENT : 0, - uc->psd_size); + uc->config.needs_epib ? CPPI5_INFO0_HDESC_EPIB_PRESENT : 0, + uc->config.psd_size); cppi5_hdesc_set_pktlen(desc_tx, len); cppi5_hdesc_attach_buf(desc_tx, dma_src, len, dma_src, len); cppi5_desc_set_pktids(&desc_tx->hdr, uc->id, 0x3fff); @@ -1656,7 +1659,7 @@ static int udma_send(struct dma *dma, void *src, size_t len, void *metadata) ALIGN((unsigned long)dma_src + len, ARCH_DMA_MINALIGN)); flush_dcache_range((unsigned long)desc_tx, - ALIGN((unsigned long)desc_tx + uc->hdesc_size, + ALIGN((unsigned long)desc_tx + uc->config.hdesc_size, ARCH_DMA_MINALIGN)); ret = udma_push_to_ring(uc->tchan->t_ring, uc->desc_tx); @@ -1674,6 +1677,7 @@ static int udma_send(struct dma *dma, void *src, size_t len, void *metadata) static int udma_receive(struct dma *dma, void **dst, void *metadata) { struct udma_dev *ud = dev_get_priv(dma->dev); + struct udma_chan_config *ucc; struct cppi5_host_desc_t *desc_rx; dma_addr_t buf_dma; struct udma_chan *uc; @@ -1686,13 +1690,14 @@ static int udma_receive(struct dma *dma, void **dst, void *metadata) return -EINVAL; } uc = &ud->channels[dma->id]; + ucc = &uc->config; - if (uc->dir != DMA_DEV_TO_MEM) + if (uc->config.dir != DMA_DEV_TO_MEM) return -EINVAL; if (!uc->num_rx_bufs) return -EINVAL; - ret = k3_nav_ringacc_ring_pop(uc->rchan->r_ring, &desc_rx); + ret = k3_nav_ringacc_ring_pop(uc->rflow->r_ring, &desc_rx); if (ret && ret != -ENODATA) { dev_err(dma->dev, "rx dma fail ch_id:%lu %d\n", dma->id, ret); return ret; @@ -1702,7 +1707,7 @@ static int udma_receive(struct dma *dma, void **dst, void *metadata) /* invalidate cache data */ invalidate_dcache_range((ulong)desc_rx, - (ulong)(desc_rx + uc->hdesc_size)); + (ulong)(desc_rx + ucc->hdesc_size)); cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); pkt_len = cppi5_hdesc_get_pktlen(desc_rx); @@ -1721,10 +1726,10 @@ static int udma_receive(struct dma *dma, void **dst, void *metadata) static int udma_of_xlate(struct dma *dma, struct ofnode_phandle_args *args) { + struct udma_chan_config *ucc; struct udma_dev *ud = dev_get_priv(dma->dev); struct udma_chan *uc = &ud->channels[0]; - ofnode chconf_node, slave_node; - char prop[50]; + struct psil_endpoint_config *ep_config; u32 val; for (val = 0; val < ud->ch_count; val++) { @@ -1736,48 +1741,40 @@ static int udma_of_xlate(struct dma *dma, struct ofnode_phandle_args *args) if (val == ud->ch_count) return -EBUSY; - uc->dir = DMA_DEV_TO_MEM; - if (args->args[2] == UDMA_DIR_TX) - uc->dir = DMA_MEM_TO_DEV; - - slave_node = ofnode_get_by_phandle(args->args[0]); - if (!ofnode_valid(slave_node)) { - dev_err(ud->dev, "slave node is missing\n"); - return -EINVAL; - } - - snprintf(prop, sizeof(prop), "ti,psil-config%u", args->args[1]); - chconf_node = ofnode_find_subnode(slave_node, prop); - if (!ofnode_valid(chconf_node)) { - dev_err(ud->dev, "Channel configuration node is missing\n"); - return -EINVAL; - } + ucc = &uc->config; + ucc->remote_thread_id = args->args[0]; + if (ucc->remote_thread_id & K3_PSIL_DST_THREAD_ID_OFFSET) + ucc->dir = DMA_MEM_TO_DEV; + else + ucc->dir = DMA_DEV_TO_MEM; - if (!ofnode_read_u32(chconf_node, "linux,udma-mode", &val)) { - if (val == UDMA_PKT_MODE) - uc->pkt_mode = true; + ep_config = psil_get_ep_config(ucc->remote_thread_id); + if (IS_ERR(ep_config)) { + dev_err(ud->dev, "No configuration for psi-l thread 0x%04x\n", + uc->config.remote_thread_id); + ucc->dir = DMA_MEM_TO_MEM; + ucc->remote_thread_id = -1; + return false; } - if (!ofnode_read_u32(chconf_node, "statictr-type", &val)) - uc->static_tr_type = val; + ucc->pkt_mode = ep_config->pkt_mode; + ucc->channel_tpl = ep_config->channel_tpl; + ucc->notdpkt = ep_config->notdpkt; + ucc->ep_type = ep_config->ep_type; - uc->needs_epib = ofnode_read_bool(chconf_node, "ti,needs-epib"); - if (!ofnode_read_u32(chconf_node, "ti,psd-size", &val)) - uc->psd_size = val; - uc->metadata_size = (uc->needs_epib ? 16 : 0) + uc->psd_size; + ucc->needs_epib = ep_config->needs_epib; + ucc->psd_size = ep_config->psd_size; + ucc->metadata_size = (ucc->needs_epib ? CPPI5_INFO0_HDESC_EPIB_SIZE : 0) + ucc->psd_size; - if (ofnode_read_u32(slave_node, "ti,psil-base", &val)) { - dev_err(ud->dev, "ti,psil-base is missing\n"); - return -EINVAL; - } - - uc->slave_thread_id = val + args->args[1]; + ucc->hdesc_size = cppi5_hdesc_calc_size(ucc->needs_epib, + ucc->psd_size, 0); + ucc->hdesc_size = ALIGN(ucc->hdesc_size, ARCH_DMA_MINALIGN); dma->id = uc->id; pr_debug("Allocated dma chn:%lu epib:%d psdata:%u meta:%u thread_id:%x\n", - dma->id, uc->needs_epib, - uc->psd_size, uc->metadata_size, - uc->slave_thread_id); + dma->id, ucc->needs_epib, + ucc->psd_size, ucc->metadata_size, + ucc->remote_thread_id); return 0; } @@ -1796,29 +1793,29 @@ int udma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) } uc = &ud->channels[dma->id]; - if (uc->dir != DMA_DEV_TO_MEM) + if (uc->config.dir != DMA_DEV_TO_MEM) return -EINVAL; if (uc->num_rx_bufs >= UDMA_RX_DESC_NUM) return -EINVAL; desc_num = uc->desc_rx_cur % UDMA_RX_DESC_NUM; - desc_rx = uc->desc_rx + (desc_num * uc->hdesc_size); + desc_rx = uc->desc_rx + (desc_num * uc->config.hdesc_size); dma_dst = (dma_addr_t)dst; cppi5_hdesc_reset_hbdesc(desc_rx); cppi5_hdesc_init(desc_rx, - uc->needs_epib ? CPPI5_INFO0_HDESC_EPIB_PRESENT : 0, - uc->psd_size); + uc->config.needs_epib ? CPPI5_INFO0_HDESC_EPIB_PRESENT : 0, + uc->config.psd_size); cppi5_hdesc_set_pktlen(desc_rx, size); cppi5_hdesc_attach_buf(desc_rx, dma_dst, size, dma_dst, size); flush_dcache_range((unsigned long)desc_rx, - ALIGN((unsigned long)desc_rx + uc->hdesc_size, + ALIGN((unsigned long)desc_rx + uc->config.hdesc_size, ARCH_DMA_MINALIGN)); - udma_push_to_ring(uc->rchan->fd_ring, desc_rx); + udma_push_to_ring(uc->rflow->fd_ring, desc_rx); uc->num_rx_bufs++; uc->desc_rx_cur++; @@ -1859,10 +1856,73 @@ static const struct dma_ops udma_ops = { .get_cfg = udma_get_cfg, }; +static struct udma_match_data am654_main_data = { + .psil_base = 0x1000, + .enable_memcpy_support = true, + .statictr_z_mask = GENMASK(11, 0), + .rchan_oes_offset = 0x200, + .tpl_levels = 2, + .level_start_idx = { + [0] = 8, /* Normal channels */ + [1] = 0, /* High Throughput channels */ + }, +}; + +static struct udma_match_data am654_mcu_data = { + .psil_base = 0x6000, + .enable_memcpy_support = true, + .statictr_z_mask = GENMASK(11, 0), + .rchan_oes_offset = 0x200, + .tpl_levels = 2, + .level_start_idx = { + [0] = 2, /* Normal channels */ + [1] = 0, /* High Throughput channels */ + }, +}; + +static struct udma_match_data j721e_main_data = { + .psil_base = 0x1000, + .enable_memcpy_support = true, + .flags = UDMA_FLAG_PDMA_ACC32 | UDMA_FLAG_PDMA_BURST | UDMA_FLAG_TDTYPE, + .statictr_z_mask = GENMASK(23, 0), + .rchan_oes_offset = 0x400, + .tpl_levels = 3, + .level_start_idx = { + [0] = 16, /* Normal channels */ + [1] = 4, /* High Throughput channels */ + [2] = 0, /* Ultra High Throughput channels */ + }, +}; + +static struct udma_match_data j721e_mcu_data = { + .psil_base = 0x6000, + .enable_memcpy_support = true, + .flags = UDMA_FLAG_PDMA_ACC32 | UDMA_FLAG_PDMA_BURST | UDMA_FLAG_TDTYPE, + .statictr_z_mask = GENMASK(23, 0), + .rchan_oes_offset = 0x400, + .tpl_levels = 2, + .level_start_idx = { + [0] = 2, /* Normal channels */ + [1] = 0, /* High Throughput channels */ + }, +}; + static const struct udevice_id udma_ids[] = { - { .compatible = "ti,k3-navss-udmap" }, - { .compatible = "ti,j721e-navss-mcu-udmap" }, - { } + { + .compatible = "ti,am654-navss-main-udmap", + .data = (ulong)&am654_main_data, + }, + { + .compatible = "ti,am654-navss-mcu-udmap", + .data = (ulong)&am654_mcu_data, + }, { + .compatible = "ti,j721e-navss-main-udmap", + .data = (ulong)&j721e_main_data, + }, { + .compatible = "ti,j721e-navss-mcu-udmap", + .data = (ulong)&j721e_mcu_data, + }, + { /* Sentinel */ }, }; U_BOOT_DRIVER(ti_edma3) = { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 50f47d4ba2..7b5c55be7d 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1753,6 +1753,11 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_set_bus_width(mmc, 1); mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); +#if CONFIG_IS_ENABLED(MMC_WRITE) + err = sd_read_ssr(mmc); + if (err) + pr_warn("unable to read ssr\n"); +#endif return 0; } diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index e76ab54838..50fcd32674 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -59,6 +59,7 @@ #define CMD_TIMEOUT 8 #define READ_TIMEOUT 3000000 /* 1 sec */ #define WRITE_TIMEOUT 3000000 /* 1 sec */ +#define R1B_TIMEOUT 3000000 /* 1 sec */ struct mmc_spi_plat { struct mmc_config cfg; @@ -72,7 +73,7 @@ struct mmc_spi_priv { static int mmc_spi_sendcmd(struct udevice *dev, ushort cmdidx, u32 cmdarg, u32 resp_type, u8 *resp, u32 resp_size, - bool resp_match, u8 resp_match_value) + bool resp_match, u8 resp_match_value, bool r1b) { int i, rpos = 0, ret = 0; u8 cmdo[7], r; @@ -105,12 +106,14 @@ static int mmc_spi_sendcmd(struct udevice *dev, if (resp_match) { r = ~resp_match_value; i = CMD_TIMEOUT; - while (i--) { + while (i) { ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); if (ret) return ret; debug(" resp%d=0x%x", rpos, r); rpos++; + i--; + if (r == resp_match_value) break; } @@ -131,6 +134,24 @@ static int mmc_spi_sendcmd(struct udevice *dev, resp[i] = r; } + if (r1b == true) { + i = R1B_TIMEOUT; + while (i) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + + debug(" resp%d=0x%x", rpos, r); + rpos++; + i--; + + if (r) + break; + } + if (!i) + return -ETIMEDOUT; + } + debug("\n"); return 0; @@ -263,8 +284,8 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, int i, multi, ret = 0; u8 *resp = NULL; u32 resp_size = 0; - bool resp_match = false; - u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0; + bool resp_match = false, r1b = false; + u8 resp8 = 0, resp16[2] = { 0 }, resp40[5] = { 0 }, resp_match_value = 0; dm_spi_claim_bus(dev); @@ -289,20 +310,33 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, resp_size = sizeof(resp40); break; case MMC_CMD_SEND_STATUS: + resp = (u8 *)&resp16[0]; + resp_size = sizeof(resp16); + break; case MMC_CMD_SET_BLOCKLEN: case MMC_CMD_SPI_CRC_ON_OFF: - case MMC_CMD_STOP_TRANSMISSION: resp = &resp8; resp_size = sizeof(resp8); resp_match = true; resp_match_value = 0x0; break; + case MMC_CMD_STOP_TRANSMISSION: + case MMC_CMD_ERASE: + resp = &resp8; + resp_size = sizeof(resp8); + r1b = true; + break; case MMC_CMD_SEND_CSD: case MMC_CMD_SEND_CID: case MMC_CMD_READ_SINGLE_BLOCK: case MMC_CMD_READ_MULTIPLE_BLOCK: case MMC_CMD_WRITE_SINGLE_BLOCK: case MMC_CMD_WRITE_MULTIPLE_BLOCK: + case MMC_CMD_APP_CMD: + case SD_CMD_ERASE_WR_BLK_START: + case SD_CMD_ERASE_WR_BLK_END: + resp = &resp8; + resp_size = sizeof(resp8); break; default: resp = &resp8; @@ -313,7 +347,7 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, }; ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type, - resp, resp_size, resp_match, resp_match_value); + resp, resp_size, resp_match, resp_match_value, r1b); if (ret) goto done; @@ -330,8 +364,10 @@ static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, cmd->response[0] |= (uint)resp40[1] << 24; break; case MMC_CMD_SEND_STATUS: - cmd->response[0] = (resp8 & 0xff) ? - MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; + if (resp16[0] || resp16[1]) + cmd->response[0] = MMC_STATUS_ERROR; + else + cmd->response[0] = MMC_STATUS_RDY_FOR_DATA; break; case MMC_CMD_SEND_CID: case MMC_CMD_SEND_CSD: diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 0e05fe4cfc..db1f85125f 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -843,7 +843,7 @@ static int omap_hsmmc_init_setup(struct mmc *mmc) omap_hsmmc_conf_bus_power(mmc, (reg_val & VS33_3V3SUP) ? MMC_SIGNAL_VOLTAGE_330 : MMC_SIGNAL_VOLTAGE_180); #else - writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl); + writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V3, &mmc_base->hctl); writel(readl(&mmc_base->capa) | VS33_3V3SUP | VS18_1V8SUP, &mmc_base->capa); #endif diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 85f3e49c05..971bdcdfda 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -61,6 +61,9 @@ #define AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD 0x3 #define AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY BIT(11) +#define AM65_CPSW_ALE_THREADMAPDEF_REG 0x134 +#define AM65_CPSW_ALE_DEFTHREAD_EN BIT(15) + #define AM65_CPSW_MACSL_CTL_REG 0x0 #define AM65_CPSW_MACSL_CTL_REG_IFCTL_A BIT(15) #define AM65_CPSW_MACSL_CTL_EXT_EN BIT(18) @@ -364,6 +367,9 @@ static int am65_cpsw_start(struct udevice *dev) writel(AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0)); + writel(AM65_CPSW_ALE_DEFTHREAD_EN, + common->ale_base + AM65_CPSW_ALE_THREADMAPDEF_REG); + /* PORT x configuration */ /* Port x Max length register */ @@ -680,7 +686,7 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev) AM65_CPSW_CPSW_NU_ALE_BASE; cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE; - ports_np = dev_read_subnode(dev, "ports"); + ports_np = dev_read_subnode(dev, "ethernet-ports"); if (!ofnode_valid(ports_np)) { ret = -ENOENT; goto out; @@ -746,13 +752,6 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev) goto out; } - node = dev_read_subnode(dev, "mdio"); - if (!ofnode_valid(node)) { - dev_err(dev, "can't find mdio\n"); - ret = -ENOENT; - goto out; - } - cpsw_common->bus_freq = dev_read_u32_default(dev, "bus_freq", AM65_CPSW_MDIO_BUS_FREQ_DEF); diff --git a/drivers/soc/ti/k3-navss-ringacc.c b/drivers/soc/ti/k3-navss-ringacc.c index ecc4b8b5a0..c48e9befe4 100644 --- a/drivers/soc/ti/k3-navss-ringacc.c +++ b/drivers/soc/ti/k3-navss-ringacc.c @@ -127,6 +127,22 @@ struct k3_nav_ring_ops { }; /** + * struct k3_nav_ring_state - Internal state tracking structure + * + * @free: Number of free entries + * @occ: Occupancy + * @windex: Write index + * @rindex: Read index + */ +struct k3_nav_ring_state { + u32 free; + u32 occ; + u32 windex; + u32 rindex; + u32 tdown_complete:1; +}; + +/** * struct k3_nav_ring - RA Ring descriptor * * @rt - Ring control/status registers @@ -139,10 +155,6 @@ struct k3_nav_ring_ops { * @elm_size - Size of the ring element * @mode - Ring mode * @flags - flags - * @free - Number of free elements - * @occ - Ring occupancy - * @windex - Write index (only for @K3_NAV_RINGACC_RING_MODE_RING) - * @rindex - Read index (only for @K3_NAV_RINGACC_RING_MODE_RING) * @ring_id - Ring Id * @parent - Pointer on struct @k3_nav_ringacc * @use_count - Use count for shared rings @@ -161,16 +173,17 @@ struct k3_nav_ring { u32 flags; #define KNAV_RING_FLAG_BUSY BIT(1) #define K3_NAV_RING_FLAG_SHARED BIT(2) - u32 free; - u32 occ; - u32 windex; - u32 rindex; + struct k3_nav_ring_state state; u32 ring_id; struct k3_nav_ringacc *parent; u32 use_count; int proxy_id; }; +struct k3_nav_ringacc_ops { + int (*init)(struct udevice *dev, struct k3_nav_ringacc *ringacc); +}; + /** * struct k3_nav_ringacc - Rings accelerator descriptor * @@ -186,6 +199,7 @@ struct k3_nav_ring { * @tisci - pointer ti-sci handle * @tisci_ring_ops - ti-sci rings ops * @tisci_dev_id - ti-sci device id + * @ops: SoC specific ringacc operation */ struct k3_nav_ringacc { struct udevice *dev; @@ -204,6 +218,8 @@ struct k3_nav_ringacc { const struct ti_sci_handle *tisci; const struct ti_sci_rm_ringacc_ops *tisci_ring_ops; u32 tisci_dev_id; + + const struct k3_nav_ringacc_ops *ops; }; static long k3_nav_ringacc_ring_get_fifo_pos(struct k3_nav_ring *ring) @@ -312,6 +328,29 @@ error: return NULL; } +int k3_nav_ringacc_request_rings_pair(struct k3_nav_ringacc *ringacc, + int fwd_id, int compl_id, + struct k3_nav_ring **fwd_ring, + struct k3_nav_ring **compl_ring) +{ + int ret = 0; + + if (!fwd_ring || !compl_ring) + return -EINVAL; + + *fwd_ring = k3_nav_ringacc_request_ring(ringacc, fwd_id, 0); + if (!(*fwd_ring)) + return -ENODEV; + + *compl_ring = k3_nav_ringacc_request_ring(ringacc, compl_id, 0); + if (!(*compl_ring)) { + k3_nav_ringacc_ring_free(*fwd_ring); + ret = -ENODEV; + } + + return ret; +} + static void k3_ringacc_ring_reset_sci(struct k3_nav_ring *ring) { struct k3_nav_ringacc *ringacc = ring->parent; @@ -338,10 +377,7 @@ void k3_nav_ringacc_ring_reset(struct k3_nav_ring *ring) if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY)) return; - ring->occ = 0; - ring->free = 0; - ring->rindex = 0; - ring->windex = 0; + memset(&ring->state, 0, sizeof(ring->state)); k3_ringacc_ring_reset_sci(ring); } @@ -546,10 +582,7 @@ int k3_nav_ringacc_ring_cfg(struct k3_nav_ring *ring, ring->size = cfg->size; ring->elm_size = cfg->elm_size; ring->mode = cfg->mode; - ring->occ = 0; - ring->free = 0; - ring->rindex = 0; - ring->windex = 0; + memset(&ring->state, 0, sizeof(ring->state)); if (ring->proxy_id != K3_RINGACC_PROXY_NOT_USED) ring->proxy = ringacc->proxy_target_base + @@ -625,10 +658,10 @@ u32 k3_nav_ringacc_ring_get_free(struct k3_nav_ring *ring) if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY)) return -EINVAL; - if (!ring->free) - ring->free = ring->size - ringacc_readl(&ring->rt->occ); + if (!ring->state.free) + ring->state.free = ring->size - ringacc_readl(&ring->rt->occ); - return ring->free; + return ring->state.free; } u32 k3_nav_ringacc_ring_get_occ(struct k3_nav_ring *ring) @@ -694,21 +727,21 @@ static int k3_nav_ringacc_ring_access_proxy( pr_debug("proxy:memcpy_fromio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_fromio(elem, ptr, (4 << ring->elm_size)); - ring->occ--; + ring->state.occ--; break; case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: pr_debug("proxy:memcpy_toio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_toio(ptr, elem, (4 << ring->elm_size)); - ring->free--; + ring->state.free--; break; default: return -EINVAL; } pr_debug("proxy: free%d occ%d\n", - ring->free, ring->occ); + ring->state.free, ring->state.occ); return 0; } @@ -763,21 +796,21 @@ static int k3_nav_ringacc_ring_access_io( pr_debug("memcpy_fromio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_fromio(elem, ptr, (4 << ring->elm_size)); - ring->occ--; + ring->state.occ--; break; case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: pr_debug("memcpy_toio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_toio(ptr, elem, (4 << ring->elm_size)); - ring->free--; + ring->state.free--; break; default: return -EINVAL; } pr_debug("free%d index%d occ%d index%d\n", - ring->free, ring->windex, ring->occ, ring->rindex); + ring->state.free, ring->state.windex, ring->state.occ, ring->state.rindex); return 0; } @@ -810,7 +843,7 @@ static int k3_nav_ringacc_ring_push_mem(struct k3_nav_ring *ring, void *elem) { void *elem_ptr; - elem_ptr = k3_nav_ringacc_get_elm_addr(ring, ring->windex); + elem_ptr = k3_nav_ringacc_get_elm_addr(ring, ring->state.windex); memcpy(elem_ptr, elem, (4 << ring->elm_size)); @@ -819,12 +852,12 @@ static int k3_nav_ringacc_ring_push_mem(struct k3_nav_ring *ring, void *elem) ring->size * (4 << ring->elm_size), ARCH_DMA_MINALIGN)); - ring->windex = (ring->windex + 1) % ring->size; - ring->free--; + ring->state.windex = (ring->state.windex + 1) % ring->size; + ring->state.free--; ringacc_writel(1, &ring->rt->db); pr_debug("ring_push_mem: free%d index%d\n", - ring->free, ring->windex); + ring->state.free, ring->state.windex); return 0; } @@ -833,7 +866,7 @@ static int k3_nav_ringacc_ring_pop_mem(struct k3_nav_ring *ring, void *elem) { void *elem_ptr; - elem_ptr = k3_nav_ringacc_get_elm_addr(ring, ring->rindex); + elem_ptr = k3_nav_ringacc_get_elm_addr(ring, ring->state.rindex); invalidate_dcache_range((unsigned long)ring->ring_mem_virt, ALIGN((unsigned long)ring->ring_mem_virt + @@ -842,12 +875,12 @@ static int k3_nav_ringacc_ring_pop_mem(struct k3_nav_ring *ring, void *elem) memcpy(elem, elem_ptr, (4 << ring->elm_size)); - ring->rindex = (ring->rindex + 1) % ring->size; - ring->occ--; + ring->state.rindex = (ring->state.rindex + 1) % ring->size; + ring->state.occ--; ringacc_writel(-1, &ring->rt->db); pr_debug("ring_pop_mem: occ%d index%d pos_ptr%p\n", - ring->occ, ring->rindex, elem_ptr); + ring->state.occ, ring->state.rindex, elem_ptr); return 0; } @@ -859,7 +892,7 @@ int k3_nav_ringacc_ring_push(struct k3_nav_ring *ring, void *elem) return -EINVAL; pr_debug("ring_push%d: free%d index%d\n", - ring->ring_id, ring->free, ring->windex); + ring->ring_id, ring->state.free, ring->state.windex); if (k3_nav_ringacc_ring_is_full(ring)) return -ENOMEM; @@ -878,7 +911,7 @@ int k3_nav_ringacc_ring_push_head(struct k3_nav_ring *ring, void *elem) return -EINVAL; pr_debug("ring_push_head: free%d index%d\n", - ring->free, ring->windex); + ring->state.free, ring->state.windex); if (k3_nav_ringacc_ring_is_full(ring)) return -ENOMEM; @@ -896,13 +929,13 @@ int k3_nav_ringacc_ring_pop(struct k3_nav_ring *ring, void *elem) if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY)) return -EINVAL; - if (!ring->occ) - ring->occ = k3_nav_ringacc_ring_get_occ(ring); + if (!ring->state.occ) + ring->state.occ = k3_nav_ringacc_ring_get_occ(ring); pr_debug("ring_pop%d: occ%d index%d\n", - ring->ring_id, ring->occ, ring->rindex); + ring->ring_id, ring->state.occ, ring->state.rindex); - if (!ring->occ) + if (!ring->state.occ && !ring->state.tdown_complete) return -ENODATA; if (ring->ops && ring->ops->pop_head) @@ -918,13 +951,13 @@ int k3_nav_ringacc_ring_pop_tail(struct k3_nav_ring *ring, void *elem) if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY)) return -EINVAL; - if (!ring->occ) - ring->occ = k3_nav_ringacc_ring_get_occ(ring); + if (!ring->state.occ) + ring->state.occ = k3_nav_ringacc_ring_get_occ(ring); pr_debug("ring_pop_tail: occ%d index%d\n", - ring->occ, ring->rindex); + ring->state.occ, ring->state.rindex); - if (!ring->occ) + if (!ring->state.occ) return -ENODATA; if (ring->ops && ring->ops->pop_tail) @@ -982,18 +1015,11 @@ static int k3_nav_ringacc_probe_dt(struct k3_nav_ringacc *ringacc) return 0; } -static int k3_nav_ringacc_probe(struct udevice *dev) +static int k3_nav_ringacc_init(struct udevice *dev, struct k3_nav_ringacc *ringacc) { - struct k3_nav_ringacc *ringacc; void __iomem *base_fifo, *base_rt; int ret, i; - ringacc = dev_get_priv(dev); - if (!ringacc) - return -ENOMEM; - - ringacc->dev = dev; - ret = k3_nav_ringacc_probe_dt(ringacc); if (ret) return ret; @@ -1063,11 +1089,42 @@ static int k3_nav_ringacc_probe(struct udevice *dev) return 0; } +struct ringacc_match_data { + struct k3_nav_ringacc_ops ops; +}; + +static struct ringacc_match_data k3_nav_ringacc_data = { + .ops = { + .init = k3_nav_ringacc_init, + }, +}; + static const struct udevice_id knav_ringacc_ids[] = { - { .compatible = "ti,am654-navss-ringacc" }, + { .compatible = "ti,am654-navss-ringacc", .data = (ulong)&k3_nav_ringacc_data, }, {}, }; +static int k3_nav_ringacc_probe(struct udevice *dev) +{ + struct k3_nav_ringacc *ringacc; + int ret; + const struct ringacc_match_data *match_data; + + match_data = (struct ringacc_match_data *)dev_get_driver_data(dev); + + ringacc = dev_get_priv(dev); + if (!ringacc) + return -ENOMEM; + + ringacc->dev = dev; + ringacc->ops = &match_data->ops; + ret = ringacc->ops->init(dev, ringacc); + if (ret) + return ret; + + return 0; +} + U_BOOT_DRIVER(k3_navss_ringacc) = { .name = "k3-navss-ringacc", .id = UCLASS_MISC, diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index b16a39d3ff..a2682b5f46 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -500,8 +500,6 @@ flush_dir(fat_itr *itr) nsects * mydata->sect_size); } -static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); - /* * Read and modify data on existing and consecutive cluster blocks */ @@ -509,6 +507,7 @@ static int get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer, loff_t size, loff_t *gotsize) { + static u8 *tmpbuf_cluster; unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; __u32 startsect; loff_t wsize; @@ -518,6 +517,12 @@ get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer, if (!size) return 0; + if (!tmpbuf_cluster) { + tmpbuf_cluster = memalign(ARCH_DMA_MINALIGN, MAX_CLUSTSIZE); + if (!tmpbuf_cluster) + return -1; + } + assert(pos < bytesperclust); startsect = clust_to_sect(mydata, clustnum); diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 17a31ec788..0577238d60 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -25,6 +25,8 @@ extern char __initdata_begin[], __initdata_end[]; extern char __start_rodata[], __end_rodata[]; extern char __efi_helloworld_begin[]; extern char __efi_helloworld_end[]; +extern char __efi_var_file_begin[]; +extern char __efi_var_file_end[]; /* Start and end of .ctors section - used for constructor calls. */ extern char __ctors_start[], __ctors_end[]; diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h index 2bb4e47496..11aca4afe1 100644 --- a/include/configs/da850evm.h +++ b/include/configs/da850evm.h @@ -13,10 +13,6 @@ /* * Board */ -/* check if direct NOR boot config is used */ -#ifndef CONFIG_DIRECT_NOR_BOOT -#define CONFIG_USE_SPIFLASH -#endif /* * SoC Configuration @@ -28,7 +24,7 @@ #define CONFIG_SYS_HZ_CLOCK clk_get(DAVINCI_AUXCLK_CLKID) #define CONFIG_SKIP_LOWLEVEL_INIT_ONLY -#ifdef CONFIG_DIRECT_NOR_BOOT +#ifdef CONFIG_MTD_NOR_FLASH #define CONFIG_SYS_DV_NOR_BOOT_CFG (0x11) #endif @@ -107,10 +103,6 @@ #define CONFIG_SYS_SPI_CLK clk_get(DAVINCI_SPI1_CLKID) -#ifdef CONFIG_USE_SPIFLASH -#define CONFIG_SYS_SPI_U_BOOT_SIZE 0x40000 -#endif - /* * I2C Configuration */ @@ -170,7 +162,7 @@ #define CONFIG_NET_RETRY_COUNT 10 #endif -#ifdef CONFIG_USE_NOR +#ifdef CONFIG_MTD_NOR_FLASH #define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of flash banks */ #define CONFIG_SYS_FLASH_SECT_SZ (128 << 10) /* 128KB */ #define CONFIG_SYS_FLASH_BASE DAVINCI_ASYNC_EMIF_DATA_CE2_BASE @@ -223,16 +215,11 @@ #define CONFIG_CLOCKS #endif -#if !defined(CONFIG_MTD_RAW_NAND) && \ - !defined(CONFIG_USE_NOR) && \ - !defined(CONFIG_USE_SPIFLASH) -#endif - /* USB Configs */ #define CONFIG_USB_OHCI_NEW #define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 15 -#ifndef CONFIG_DIRECT_NOR_BOOT +#ifdef CONFIG_SPL_BUILD /* defines for SPL */ #define CONFIG_SYS_SPL_MALLOC_START (CONFIG_SYS_TEXT_BASE - \ CONFIG_SYS_MALLOC_LEN) @@ -247,12 +234,12 @@ /* additions for new relocation code, must added to all boards */ #define CONFIG_SYS_SDRAM_BASE 0xc0000000 -#ifdef CONFIG_DIRECT_NOR_BOOT +#ifdef CONFIG_MTD_NOR_FLASH #define CONFIG_SYS_INIT_SP_ADDR 0x8001ff00 #else #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - /* Fix this */ \ GENERATED_GBL_DATA_SIZE) -#endif /* CONFIG_DIRECT_NOR_BOOT */ +#endif /* CONFIG_MTD_NOR_FLASH */ #include <asm/arch/hardware.h> diff --git a/include/crypto/pkcs7_parser.h b/include/crypto/pkcs7_parser.h index b8234da45a..906033a90e 100644 --- a/include/crypto/pkcs7_parser.h +++ b/include/crypto/pkcs7_parser.h @@ -10,7 +10,7 @@ #include <linux/oid_registry.h> #include <crypto/pkcs7.h> -#include "x509_parser.h" +#include <crypto/x509_parser.h> #define kenter(FMT, ...) \ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) diff --git a/include/dt-bindings/dma/k3-udma.h b/include/dt-bindings/dma/k3-udma.h deleted file mode 100644 index 670e1232b4..0000000000 --- a/include/dt-bindings/dma/k3-udma.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com - */ - -#ifndef __DT_TI_UDMA_H -#define __DT_TI_UDMA_H - -#define UDMA_TR_MODE 0 -#define UDMA_PKT_MODE 1 - -#define UDMA_DIR_TX 0 -#define UDMA_DIR_RX 1 - -#define PSIL_STATIC_TR_NONE 0 -#define PSIL_STATIC_TR_XY 1 -#define PSIL_STATIC_TR_MCAN 2 - -#define UDMA_PDMA_TR_XY(id) \ - ti,psil-config##id { \ - linux,udma-mode = <UDMA_TR_MODE>; \ - statictr-type = <PSIL_STATIC_TR_XY>; \ - } - -#define UDMA_PDMA_PKT_XY(id) \ - ti,psil-config##id { \ - linux,udma-mode = <UDMA_PKT_MODE>; \ - statictr-type = <PSIL_STATIC_TR_XY>; \ - } - -#endif /* __DT_TI_UDMA_H */ diff --git a/include/efi_api.h b/include/efi_api.h index 759d911875..5744f6aed8 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -251,6 +251,8 @@ struct efi_rt_properties_table { u32 runtime_services_supported; }; +#define EFI_OPTIONAL_PTR 0x00000001 + struct efi_runtime_services { struct efi_table_hdr hdr; efi_status_t (EFIAPI *get_time)(struct efi_time *time, diff --git a/include/efi_loader.h b/include/efi_loader.h index fc9344c742..98944640be 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -397,6 +397,9 @@ efi_status_t efi_root_node_register(void); efi_status_t efi_initialize_system_table(void); /* efi_runtime_detach() - detach unimplemented runtime functions */ void efi_runtime_detach(void); +/* efi_convert_pointer() - convert pointer to virtual address */ +efi_status_t EFIAPI efi_convert_pointer(efi_uintn_t debug_disposition, + void **address); /* Called by bootefi to make console interface available */ efi_status_t efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ @@ -765,14 +768,17 @@ struct efi_signature_store { struct x509_certificate; struct pkcs7_message; -bool efi_signature_verify_cert(struct x509_certificate *cert, - struct efi_signature_store *dbx); -bool efi_signature_verify_signers(struct pkcs7_message *msg, - struct efi_signature_store *dbx); +bool efi_signature_lookup_digest(struct efi_image_regions *regs, + struct efi_signature_store *db); +bool efi_signature_verify_one(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db); bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, struct pkcs7_message *msg, - struct efi_signature_store *db, - struct x509_certificate **cert); + struct efi_signature_store *db, + struct efi_signature_store *dbx); +bool efi_signature_check_signers(struct pkcs7_message *msg, + struct efi_signature_store *dbx); efi_status_t efi_image_region_add(struct efi_image_regions *regs, const void *start, const void *end, @@ -786,6 +792,9 @@ bool efi_secure_boot_enabled(void); bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, WIN_CERTIFICATE **auth, size_t *auth_len); +/* runtime implementation of memcpy() */ +void efi_memcpy_runtime(void *dest, const void *src, size_t n); + #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ diff --git a/include/efi_variable.h b/include/efi_variable.h new file mode 100644 index 0000000000..2c629e4dca --- /dev/null +++ b/include/efi_variable.h @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#ifndef _EFI_VARIABLE_H +#define _EFI_VARIABLE_H + +#include <linux/bitops.h> + +#define EFI_VARIABLE_READ_ONLY BIT(31) + +enum efi_auth_var_type { + EFI_AUTH_VAR_NONE = 0, + EFI_AUTH_VAR_PK, + EFI_AUTH_VAR_KEK, + EFI_AUTH_VAR_DB, + EFI_AUTH_VAR_DBX, + EFI_AUTH_VAR_DBT, + EFI_AUTH_VAR_DBR, +}; + +/** + * efi_get_variable() - retrieve value of a UEFI variable + * + * @variable_name: name of the variable + * @vendor: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer to which the variable value is copied + * @data: buffer to which the variable value is copied + * @timep: authentication time (seconds since start of epoch) + * Return: status code + */ +efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 *attributes, efi_uintn_t *data_size, + void *data, u64 *timep); + +/** + * efi_set_variable() - set value of a UEFI variable + * + * @variable_name: name of the variable + * @vendor: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer with the variable value + * @data: buffer with the variable value + * @ro_check: check the read only read only bit in attributes + * Return: status code + */ +efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 attributes, efi_uintn_t data_size, + const void *data, bool ro_check); + +/** + * efi_get_next_variable_name_int() - enumerate the current variable names + * + * @variable_name_size: size of variable_name buffer in byte + * @variable_name: name of uefi variable's name in u16 + * @vendor: vendor's guid + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, + u16 *variable_name, + efi_guid_t *vendor); + +/** + * efi_query_variable_info_int() - get information about EFI variables + * + * This function implements the QueryVariableInfo() runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @attributes: bitmask to select variables to be + * queried + * @maximum_variable_storage_size: maximum size of storage area for the + * selected variable types + * @remaining_variable_storage_size: remaining size of storage are for the + * selected variable types + * @maximum_variable_size: maximum size of a variable of the + * selected type + * Returns: status code + */ +efi_status_t efi_query_variable_info_int(u32 attributes, + u64 *maximum_variable_storage_size, + u64 *remaining_variable_storage_size, + u64 *maximum_variable_size); + +#define EFI_VAR_FILE_NAME "ubootefi.var" + +#define EFI_VAR_BUF_SIZE 0x4000 + +/* + * This constant identifies the file format for storing UEFI variables in + * struct efi_var_file. + */ +#define EFI_VAR_FILE_MAGIC 0x0161566966456255 /* UbEfiVa, version 1 */ + +/** + * struct efi_var_entry - UEFI variable file entry + * + * @length: length of enty, multiple of 8 + * @attr: variable attributes + * @time: authentication time (seconds since start of epoch) + * @guid: vendor GUID + * @name: UTF16 variable name + */ +struct efi_var_entry { + u32 length; + u32 attr; + u64 time; + efi_guid_t guid; + u16 name[]; +}; + +/** + * struct efi_var_file - file for storing UEFI variables + * + * @reserved: unused, may be overwritten by memory probing + * @magic: identifies file format, takes value %EFI_VAR_FILE_MAGIC + * @length: length including header + * @crc32: CRC32 without header + * @var: variables + */ +struct efi_var_file { + u64 reserved; + u64 magic; + u32 length; + u32 crc32; + struct efi_var_entry var[]; +}; + +/** + * efi_var_to_file() - save non-volatile variables as file + * + * File ubootefi.var is created on the EFI system partion. + * + * Return: status code + */ +efi_status_t efi_var_to_file(void); + +/** + * efi_var_restore() - restore EFI variables from buffer + * + * @buf: buffer + * Return: status code + */ +efi_status_t efi_var_restore(struct efi_var_file *buf); + +/** + * efi_var_from_file() - read variables from file + * + * File ubootefi.var is read from the EFI system partitions and the variables + * stored in the file are created. + * + * In case the file does not exist yet or a variable cannot be set EFI_SUCCESS + * is returned. + * + * Return: status code + */ +efi_status_t efi_var_from_file(void); + +/** + * efi_var_mem_init() - set-up variable list + * + * Return: status code + */ +efi_status_t efi_var_mem_init(void); + +/** + * efi_var_mem_find() - find a variable in the list + * + * @guid: GUID of the variable + * @name: name of the variable + * @next: on exit pointer to the next variable after the found one + * Return: found variable + */ +struct efi_var_entry *efi_var_mem_find(const efi_guid_t *guid, const u16 *name, + struct efi_var_entry **next); + +/** + * efi_var_mem_del() - delete a variable from the list of variables + * + * @var: variable to delete + */ +void efi_var_mem_del(struct efi_var_entry *var); + +/** + * efi_var_mem_ins() - append a variable to the list of variables + * + * The variable is appended without checking if a variable of the same name + * already exists. The two data buffers are concatenated. + * + * @variable_name: variable name + * @vendor: GUID + * @attributes: variable attributes + * @size1: size of the first data buffer + * @data1: first data buffer + * @size2: size of the second data field + * @data2: second data buffer + * @time: time of authentication (as seconds since start of epoch) + * Result: status code + */ +efi_status_t efi_var_mem_ins(u16 *variable_name, + const efi_guid_t *vendor, u32 attributes, + const efi_uintn_t size1, const void *data1, + const efi_uintn_t size2, const void *data2, + const u64 time); + +/** + * efi_var_mem_free() - determine free memory for variables + * + * Return: maximum data size plus variable name size + */ +u64 efi_var_mem_free(void); + +/** + * efi_init_secure_state - initialize secure boot state + * + * Return: status code + */ +efi_status_t efi_init_secure_state(void); + +/** + * efi_auth_var_get_type() - convert variable name and guid to enum + * + * @name: name of UEFI variable + * @guid: guid of UEFI variable + * Return: identifier for authentication related variables + */ +enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid); + +#endif diff --git a/include/linux/soc/ti/k3-navss-ringacc.h b/include/linux/soc/ti/k3-navss-ringacc.h index 7b027f8bd4..9176277ff0 100644 --- a/include/linux/soc/ti/k3-navss-ringacc.h +++ b/include/linux/soc/ti/k3-navss-ringacc.h @@ -100,6 +100,10 @@ struct k3_nav_ring_cfg { struct k3_nav_ring *k3_nav_ringacc_request_ring(struct k3_nav_ringacc *ringacc, int id, u32 flags); +int k3_nav_ringacc_request_rings_pair(struct k3_nav_ringacc *ringacc, + int fwd_id, int compl_id, + struct k3_nav_ring **fwd_ring, + struct k3_nav_ring **compl_ring); /** * k3_nav_ringacc_get_dev - get pointer on RA device * @ringacc: pointer on RA diff --git a/include/mm_communication.h b/include/mm_communication.h index 193c4d1578..f9c05bb7f1 100644 --- a/include/mm_communication.h +++ b/include/mm_communication.h @@ -205,4 +205,47 @@ struct smm_variable_query_info { u32 attr; }; +#define VAR_CHECK_VARIABLE_PROPERTY_REVISION 0x0001 +#define VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY BIT(0) +/** + * struct var_check_property - Used to store variable properties in StMM + * + * @revision: magic revision number for variable property checking + * @property: properties mask for the variable used in StMM. + * Currently RO flag is supported + * @attributes: variable attributes used in StMM checking when properties + * for a variable are enabled + * @minsize: minimum allowed size for variable payload checked against + * smm_variable_access->datasize in StMM + * @maxsize: maximum allowed size for variable payload checked against + * smm_variable_access->datasize in StMM + * + * Defined in EDK2 as VAR_CHECK_VARIABLE_PROPERTY. + */ +struct var_check_property { + u16 revision; + u16 property; + u32 attributes; + efi_uintn_t minsize; + efi_uintn_t maxsize; +}; + +/** + * struct smm_variable_var_check_property - Used to communicate variable + * properties with StMM + * + * @guid: vendor GUID + * @name_size: size of EFI name + * @property: variable properties struct + * @name: variable name + * + * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY. + */ +struct smm_variable_var_check_property { + efi_guid_t guid; + efi_uintn_t name_size; + struct var_check_property property; + u16 name[]; +}; + #endif /* _MM_COMMUNICATION_H_ */ diff --git a/include/u-boot/rsa.h b/include/u-boot/rsa.h index a0bae495f0..bed1c097c2 100644 --- a/include/u-boot/rsa.h +++ b/include/u-boot/rsa.h @@ -112,6 +112,9 @@ int rsa_verify(struct image_sign_info *info, const struct image_region region[], int region_count, uint8_t *sig, uint sig_len); +int rsa_verify_with_pkey(struct image_sign_info *info, + const void *hash, uint8_t *sig, uint sig_len); + int padding_pkcs_15_verify(struct image_sign_info *info, uint8_t *msg, int msg_len, const uint8_t *hash, int hash_len); diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 6c9df3a767..6017ffe9a6 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -27,6 +27,52 @@ config EFI_LOADER if EFI_LOADER +choice + prompt "Store for non-volatile UEFI variables" + default EFI_VARIABLE_FILE_STORE + help + Select where non-volatile UEFI variables shall be stored. + +config EFI_VARIABLE_FILE_STORE + bool "Store non-volatile UEFI variables as file" + depends on FAT_WRITE + help + Select this option if you want non-volatile UEFI variables to be + stored as file /ubootefi.var on the EFI system partition. + +config EFI_MM_COMM_TEE + bool "UEFI variables storage service via OP-TEE" + depends on OPTEE + help + If OP-TEE is present and running StandAloneMM, dispatch all UEFI + variable related operations to that. The application will verify, + authenticate and store the variables on an RPMB. + +endchoice + +config EFI_VARIABLES_PRESEED + bool "Initial values for UEFI variables" + depends on EFI_VARIABLE_FILE_STORE + help + Include a file with the initial values for non-volatile UEFI variables + into the U-Boot binary. If this configuration option is set, changes + to authentication related variables (PK, KEK, db, dbx) are not + allowed. + +if EFI_VARIABLES_PRESEED + +config EFI_VAR_SEED_FILE + string "File with initial values of non-volatile UEFI variables" + default ubootefi.var + help + File with initial values of non-volatile UEFI variables. The file must + be in the same format as the storage in the EFI system partition. The + easiest way to create it is by setting the non-volatile variables in + U-Boot. If a relative file path is used, it is relative to the source + directory. + +endif + config EFI_GET_TIME bool "GetTime() runtime service" depends on DM_RTC @@ -166,13 +212,4 @@ config EFI_SECURE_BOOT it is signed with a trusted key. To do that, you need to install, at least, PK, KEK and db. -config EFI_MM_COMM_TEE - bool "UEFI variables storage service via OP-TEE" - depends on OPTEE - default n - help - If OP-TEE is present and running StandAloneMM, dispatch all UEFI variable - related operations to that. The application will verify, authenticate and - store the variables on an RPMB. - endif diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 57c7e66ea0..441ac9432e 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -6,7 +6,7 @@ # This file only gets included with CONFIG_EFI_LOADER set, so all # object inclusion implicitly depends on it -asflags-y += -DHOST_ARCH="$(HOST_ARCH)" +asflags-y += -DHOST_ARCH="$(HOST_ARCH)" -I. ccflags-y += -DHOST_ARCH="$(HOST_ARCH)" CFLAGS_efi_boottime.o += \ @@ -35,10 +35,14 @@ obj-y += efi_root_node.o obj-y += efi_runtime.o obj-y += efi_setup.o obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += efi_unicode_collation.o +obj-y += efi_var_common.o +obj-y += efi_var_mem.o ifeq ($(CONFIG_EFI_MM_COMM_TEE),y) obj-y += efi_variable_tee.o else obj-y += efi_variable.o +obj-y += efi_var_file.o +obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o endif obj-y += efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o @@ -50,3 +54,6 @@ obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o obj-y += efi_signature.o + +EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE)) +$(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index e268e9c4b8..e03198b57a 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -12,6 +12,7 @@ #include <log.h> #include <malloc.h> #include <efi_loader.h> +#include <efi_variable.h> #include <asm/unaligned.h> static const struct efi_boot_services *bs; @@ -147,15 +148,14 @@ unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data) static void *get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size) { - efi_guid_t *v = (efi_guid_t *)vendor; efi_status_t ret; void *buf = NULL; *size = 0; - EFI_CALL(ret = rs->get_variable(name, v, NULL, size, buf)); + ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL); if (ret == EFI_BUFFER_TOO_SMALL) { buf = malloc(*size); - EFI_CALL(ret = rs->get_variable(name, v, NULL, size, buf)); + ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL); } if (ret != EFI_SUCCESS) { @@ -219,10 +219,9 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle) attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; size = sizeof(n); - ret = EFI_CALL(efi_set_variable( - L"BootCurrent", - (efi_guid_t *)&efi_global_variable_guid, - attributes, size, &n)); + ret = efi_set_variable_int(L"BootCurrent", + &efi_global_variable_guid, + attributes, size, &n, false); if (ret != EFI_SUCCESS) { if (EFI_CALL(efi_unload_image(*handle)) != EFI_SUCCESS) @@ -262,22 +261,19 @@ efi_status_t efi_bootmgr_load(efi_handle_t *handle) rs = systab.runtime; /* BootNext */ - bootnext = 0; size = sizeof(bootnext); - ret = EFI_CALL(efi_get_variable(L"BootNext", - (efi_guid_t *)&efi_global_variable_guid, - NULL, &size, &bootnext)); + ret = efi_get_variable_int(L"BootNext", + &efi_global_variable_guid, + NULL, &size, &bootnext, NULL); if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { /* BootNext does exist here */ if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) log_err("BootNext must be 16-bit integer\n"); /* delete BootNext */ - ret = EFI_CALL(efi_set_variable( - L"BootNext", - (efi_guid_t *)&efi_global_variable_guid, - EFI_VARIABLE_NON_VOLATILE, 0, - &bootnext)); + ret = efi_set_variable_int(L"BootNext", + &efi_global_variable_guid, + 0, 0, NULL, false); /* load BootNext */ if (ret == EFI_SUCCESS) { diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1591ad8300..0b16554ba2 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3459,6 +3459,8 @@ static efi_status_t efi_get_child_controllers( * the buffer will be too large. But that does not harm. */ *number_of_children = 0; + if (!count) + return EFI_SUCCESS; *child_handle_buffer = calloc(count, sizeof(efi_handle_t)); if (!*child_handle_buffer) return EFI_OUT_OF_RESOURCES; @@ -3536,10 +3538,12 @@ static efi_status_t EFIAPI efi_disconnect_controller( number_of_children = 1; child_handle_buffer = &child_handle; } else { - efi_get_child_controllers(efiobj, - driver_image_handle, - &number_of_children, - &child_handle_buffer); + r = efi_get_child_controllers(efiobj, + driver_image_handle, + &number_of_children, + &child_handle_buffer); + if (r != EFI_SUCCESS) + return r; } /* Get the driver binding protocol */ diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 06a2ebdb90..fef0bb870c 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -267,6 +267,8 @@ bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, dos = (void *)efi; nt = (void *)(efi + dos->e_lfanew); + authoff = 0; + authsz = 0; /* * Count maximum number of regions to be digested. @@ -305,25 +307,36 @@ bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, efi_image_region_add(regs, &opt->DataDirectory[ctidx] + 1, efi + opt->SizeOfHeaders, 0); + + authoff = opt->DataDirectory[ctidx].VirtualAddress; + authsz = opt->DataDirectory[ctidx].Size; } bytes_hashed = opt->SizeOfHeaders; align = opt->FileAlignment; - authoff = opt->DataDirectory[ctidx].VirtualAddress; - authsz = opt->DataDirectory[ctidx].Size; } else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader; + /* Skip CheckSum */ efi_image_region_add(regs, efi, &opt->CheckSum, 0); - efi_image_region_add(regs, &opt->Subsystem, - &opt->DataDirectory[ctidx], 0); - efi_image_region_add(regs, &opt->DataDirectory[ctidx] + 1, - efi + opt->SizeOfHeaders, 0); + if (nt->OptionalHeader.NumberOfRvaAndSizes <= ctidx) { + efi_image_region_add(regs, + &opt->Subsystem, + efi + opt->SizeOfHeaders, 0); + } else { + /* Skip Certificates Table */ + efi_image_region_add(regs, &opt->Subsystem, + &opt->DataDirectory[ctidx], 0); + efi_image_region_add(regs, + &opt->DataDirectory[ctidx] + 1, + efi + opt->SizeOfHeaders, 0); + + authoff = opt->DataDirectory[ctidx].VirtualAddress; + authsz = opt->DataDirectory[ctidx].Size; + } bytes_hashed = opt->SizeOfHeaders; align = opt->FileAlignment; - authoff = opt->DataDirectory[ctidx].VirtualAddress; - authsz = opt->DataDirectory[ctidx].Size; } else { EFI_PRINT("%s: Invalid optional header magic %x\n", __func__, nt->OptionalHeader.Magic); @@ -369,7 +382,7 @@ bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, /* 3. Extra data excluding Certificates Table */ if (bytes_hashed + authsz < len) { - EFI_PRINT("extra data for hash: %lu\n", + EFI_PRINT("extra data for hash: %zu\n", len - (bytes_hashed + authsz)); efi_image_region_add(regs, efi + bytes_hashed, efi + len - authsz, 0); @@ -435,16 +448,16 @@ static bool efi_image_unsigned_authenticate(struct efi_image_regions *regs) } /* try black-list first */ - if (efi_signature_verify_with_sigdb(regs, NULL, dbx, NULL)) { - EFI_PRINT("Image is not signed and rejected by \"dbx\"\n"); + if (efi_signature_lookup_digest(regs, dbx)) { + EFI_PRINT("Image is not signed and its digest found in \"dbx\"\n"); goto out; } /* try white-list */ - if (efi_signature_verify_with_sigdb(regs, NULL, db, NULL)) + if (efi_signature_lookup_digest(regs, db)) ret = true; else - EFI_PRINT("Image is not signed and not found in \"db\" or \"dbx\"\n"); + EFI_PRINT("Image is not signed and its digest not found in \"db\" or \"dbx\"\n"); out: efi_sigstore_free(db); @@ -481,11 +494,13 @@ static bool efi_image_authenticate(void *efi, size_t efi_size) size_t wincerts_len; struct pkcs7_message *msg = NULL; struct efi_signature_store *db = NULL, *dbx = NULL; - struct x509_certificate *cert = NULL; void *new_efi = NULL; - size_t new_efi_size; + u8 *auth, *wincerts_end; + size_t new_efi_size, auth_size; bool ret = false; + debug("%s: Enter, %d\n", __func__, ret); + if (!efi_secure_boot_enabled()) return true; @@ -531,61 +546,122 @@ static bool efi_image_authenticate(void *efi, size_t efi_size) goto err; } - /* go through WIN_CERTIFICATE list */ - for (wincert = wincerts; - (void *)wincert < (void *)wincerts + wincerts_len; - wincert = (void *)wincert + ALIGN(wincert->dwLength, 8)) { - if (wincert->dwLength < sizeof(*wincert)) { - EFI_PRINT("%s: dwLength too small: %u < %zu\n", - __func__, wincert->dwLength, - sizeof(*wincert)); - goto err; + /* + * go through WIN_CERTIFICATE list + * NOTE: + * We may have multiple signatures either as WIN_CERTIFICATE's + * in PE header, or as pkcs7 SignerInfo's in SignedData. + * So the verification policy here is: + * - Success if, at least, one of signatures is verified + * - unless + * any of signatures is rejected explicitly, or + * none of digest algorithms are supported + */ + for (wincert = wincerts, wincerts_end = (u8 *)wincerts + wincerts_len; + (u8 *)wincert < wincerts_end; + wincert = (WIN_CERTIFICATE *) + ((u8 *)wincert + ALIGN(wincert->dwLength, 8))) { + if ((u8 *)wincert + sizeof(*wincert) >= wincerts_end) + break; + + if (wincert->dwLength <= sizeof(*wincert)) { + EFI_PRINT("dwLength too small: %u < %zu\n", + wincert->dwLength, sizeof(*wincert)); + continue; } - msg = pkcs7_parse_message((void *)wincert + sizeof(*wincert), - wincert->dwLength - sizeof(*wincert)); + + EFI_PRINT("WIN_CERTIFICATE_TYPE: 0x%x\n", + wincert->wCertificateType); + + auth = (u8 *)wincert + sizeof(*wincert); + auth_size = wincert->dwLength - sizeof(*wincert); + if (wincert->wCertificateType == WIN_CERT_TYPE_EFI_GUID) { + if (auth + sizeof(efi_guid_t) >= wincerts_end) + break; + + if (auth_size <= sizeof(efi_guid_t)) { + EFI_PRINT("dwLength too small: %u < %zu\n", + wincert->dwLength, sizeof(*wincert)); + continue; + } + if (guidcmp(auth, &efi_guid_cert_type_pkcs7)) { + EFI_PRINT("Certificate type not supported: %pUl\n", + auth); + continue; + } + + auth += sizeof(efi_guid_t); + auth_size -= sizeof(efi_guid_t); + } else if (wincert->wCertificateType + != WIN_CERT_TYPE_PKCS_SIGNED_DATA) { + EFI_PRINT("Certificate type not supported\n"); + continue; + } + + msg = pkcs7_parse_message(auth, auth_size); if (IS_ERR(msg)) { EFI_PRINT("Parsing image's signature failed\n"); msg = NULL; - goto err; + continue; } + /* + * NOTE: + * UEFI specification defines two signature types possible + * in signature database: + * a. x509 certificate, where a signature in image is + * a message digest encrypted by RSA public key + * (EFI_CERT_X509_GUID) + * b. bare hash value of message digest + * (EFI_CERT_SHAxxx_GUID) + * + * efi_signature_verify() handles case (a), while + * efi_signature_lookup_digest() handles case (b). + * + * There is a third type: + * c. message digest of a certificate + * (EFI_CERT_X509_SHAAxxx_GUID) + * This type of signature is used only in revocation list + * (dbx) and handled as part of efi_signatgure_verify(). + */ /* try black-list first */ - if (efi_signature_verify_with_sigdb(regs, msg, dbx, NULL)) { + if (efi_signature_verify_one(regs, msg, dbx)) { EFI_PRINT("Signature was rejected by \"dbx\"\n"); goto err; } - if (!efi_signature_verify_signers(msg, dbx)) { - EFI_PRINT("Signer was rejected by \"dbx\"\n"); + if (!efi_signature_check_signers(msg, dbx)) { + EFI_PRINT("Signer(s) in \"dbx\"\n"); goto err; - } else { - ret = true; } - /* try white-list */ - if (!efi_signature_verify_with_sigdb(regs, msg, db, &cert)) { - EFI_PRINT("Verifying signature with \"db\" failed\n"); + if (efi_signature_lookup_digest(regs, dbx)) { + EFI_PRINT("Image's digest was found in \"dbx\"\n"); goto err; - } else { - ret = true; } - if (!efi_signature_verify_cert(cert, dbx)) { - EFI_PRINT("Certificate was rejected by \"dbx\"\n"); - goto err; - } else { - ret = true; - } + /* try white-list */ + if (efi_signature_verify_with_sigdb(regs, msg, db, dbx)) + continue; + + debug("Signature was not verified by \"db\"\n"); + + if (efi_signature_lookup_digest(regs, db)) + continue; + + debug("Image's digest was not found in \"db\" or \"dbx\"\n"); + goto err; } + ret = true; err: - x509_free_certificate(cert); efi_sigstore_free(db); efi_sigstore_free(dbx); pkcs7_free_message(msg); free(regs); free(new_efi); + debug("%s: Exit, %d\n", __func__, ret); return ret; } #else diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index c0bd99b867..91a4551448 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -121,6 +121,8 @@ efi_status_t efi_init_runtime_supported(void) rt_table->version = EFI_RT_PROPERTIES_TABLE_VERSION; rt_table->length = sizeof(struct efi_rt_properties_table); rt_table->runtime_services_supported = + EFI_RT_SUPPORTED_GET_VARIABLE | + EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME | EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | EFI_RT_SUPPORTED_CONVERT_POINTER; @@ -138,6 +140,25 @@ efi_status_t efi_init_runtime_supported(void) } /** + * efi_memcpy_runtime() - copy memory area + * + * At runtime memcpy() is not available. + * + * @dest: destination buffer + * @src: source buffer + * @n: number of bytes to copy + * Return: pointer to destination buffer + */ +void __efi_runtime efi_memcpy_runtime(void *dest, const void *src, size_t n) +{ + u8 *d = dest; + const u8 *s = src; + + for (; n; --n) + *d++ = *s++; +} + +/** * efi_update_table_header_crc32() - Update crc32 in table header * * @table: EFI table @@ -496,15 +517,13 @@ static __efi_runtime efi_status_t EFIAPI efi_convert_pointer_runtime( * @address: pointer to be converted * Return: status code */ -static __efi_runtime efi_status_t EFIAPI efi_convert_pointer( - efi_uintn_t debug_disposition, void **address) +__efi_runtime efi_status_t EFIAPI +efi_convert_pointer(efi_uintn_t debug_disposition, void **address) { - efi_physical_addr_t addr = (uintptr_t)*address; + efi_physical_addr_t addr; efi_uintn_t i; efi_status_t ret = EFI_NOT_FOUND; - EFI_ENTRY("%zu %p", debug_disposition, address); - if (!efi_virtmap) { ret = EFI_UNSUPPORTED; goto out; @@ -514,7 +533,14 @@ static __efi_runtime efi_status_t EFIAPI efi_convert_pointer( ret = EFI_INVALID_PARAMETER; goto out; } + if (!*address) { + if (debug_disposition & EFI_OPTIONAL_PTR) + return EFI_SUCCESS; + else + return EFI_INVALID_PARAMETER; + } + addr = (uintptr_t)*address; for (i = 0; i < efi_descriptor_count; i++) { struct efi_mem_desc *map = (void *)efi_virtmap + (efi_descriptor_size * i); @@ -532,7 +558,7 @@ static __efi_runtime efi_status_t EFIAPI efi_convert_pointer( } out: - return EFI_EXIT(ret); + return ret; } static __efi_runtime void efi_relocate_runtime_table(ulong offset) diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index a3b05a4a9b..6196c0a06c 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -8,6 +8,7 @@ #include <common.h> #include <bootm.h> #include <efi_loader.h> +#include <efi_variable.h> #define OBJ_LIST_NOT_INITIALIZED 1 @@ -40,12 +41,13 @@ static efi_status_t efi_init_platform_lang(void) * Variable PlatformLangCodes defines the language codes that the * machine can support. */ - ret = EFI_CALL(efi_set_variable(L"PlatformLangCodes", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - sizeof(CONFIG_EFI_PLATFORM_LANG_CODES), - CONFIG_EFI_PLATFORM_LANG_CODES)); + ret = efi_set_variable_int(L"PlatformLangCodes", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(CONFIG_EFI_PLATFORM_LANG_CODES), + CONFIG_EFI_PLATFORM_LANG_CODES, false); if (ret != EFI_SUCCESS) goto out; @@ -53,9 +55,9 @@ static efi_status_t efi_init_platform_lang(void) * Variable PlatformLang defines the language that the machine has been * configured for. */ - ret = EFI_CALL(efi_get_variable(L"PlatformLang", - &efi_global_variable_guid, - NULL, &data_size, &pos)); + ret = efi_get_variable_int(L"PlatformLang", + &efi_global_variable_guid, + NULL, &data_size, &pos, NULL); if (ret == EFI_BUFFER_TOO_SMALL) { /* The variable is already set. Do not change it. */ ret = EFI_SUCCESS; @@ -70,12 +72,12 @@ static efi_status_t efi_init_platform_lang(void) if (pos) *pos = 0; - ret = EFI_CALL(efi_set_variable(L"PlatformLang", - &efi_global_variable_guid, - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - 1 + strlen(lang), lang)); + ret = efi_set_variable_int(L"PlatformLang", + &efi_global_variable_guid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + 1 + strlen(lang), lang, false); out: if (ret != EFI_SUCCESS) printf("EFI: cannot initialize platform language settings\n"); @@ -96,13 +98,13 @@ static efi_status_t efi_init_secure_boot(void) }; efi_status_t ret; - /* TODO: read-only */ - ret = EFI_CALL(efi_set_variable(L"SignatureSupport", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_RUNTIME_ACCESS, - sizeof(signature_types), - &signature_types)); + ret = efi_set_variable_int(L"SignatureSupport", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(signature_types), + &signature_types, false); if (ret != EFI_SUCCESS) printf("EFI: cannot initialize SignatureSupport variable\n"); @@ -160,12 +162,13 @@ efi_status_t efi_init_obj_list(void) goto out; /* Indicate supported features */ - ret = EFI_CALL(efi_set_variable(L"OsIndicationsSupported", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - sizeof(os_indications_supported), - &os_indications_supported)); + ret = efi_set_variable_int(L"OsIndicationsSupported", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(os_indications_supported), + &os_indications_supported, false); if (ret != EFI_SUCCESS) goto out; diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index e05c471c61..fc0314e6d4 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -28,7 +28,8 @@ const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; /** * efi_hash_regions - calculate a hash value - * @regs: List of regions + * @regs: Array of regions + * @count: Number of regions * @hash: Pointer to a pointer to buffer holding a hash value * @size: Size of buffer to be returned * @@ -36,18 +37,20 @@ const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; * * Return: true on success, false on error */ -static bool efi_hash_regions(struct efi_image_regions *regs, void **hash, - size_t *size) +static bool efi_hash_regions(struct image_region *regs, int count, + void **hash, size_t *size) { - *size = 0; - *hash = calloc(1, SHA256_SUM_LEN); if (!*hash) { - EFI_PRINT("Out of memory\n"); - return false; + *hash = calloc(1, SHA256_SUM_LEN); + if (!*hash) { + EFI_PRINT("Out of memory\n"); + return false; + } } - *size = SHA256_SUM_LEN; + if (size) + *size = SHA256_SUM_LEN; - hash_calculate("sha256", regs->reg, regs->num, *hash); + hash_calculate("sha256", regs, count, *hash); #ifdef DEBUG EFI_PRINT("hash calculated:\n"); print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, @@ -72,26 +75,10 @@ static bool efi_hash_msg_content(struct pkcs7_message *msg, void **hash, { struct image_region regtmp; - *size = 0; - *hash = calloc(1, SHA256_SUM_LEN); - if (!*hash) { - EFI_PRINT("Out of memory\n"); - free(msg); - return false; - } - *size = SHA256_SUM_LEN; - regtmp.data = msg->data; regtmp.size = msg->data_len; - hash_calculate("sha256", ®tmp, 1, *hash); -#ifdef DEBUG - EFI_PRINT("hash calculated based on contentInfo:\n"); - print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, - *hash, SHA256_SUM_LEN, false); -#endif - - return true; + return efi_hash_regions(®tmp, 1, hash, size); } /** @@ -169,9 +156,10 @@ static bool efi_signature_verify(struct efi_image_regions *regs, false); #endif /* against contentInfo first */ + hash = NULL; if ((msg->data && efi_hash_msg_content(msg, &hash, &size)) || /* for signed image */ - efi_hash_regions(regs, &hash, &size)) { + efi_hash_regions(regs->reg, regs->num, &hash, &size)) { /* for authenticated variable */ if (ps_info->msgdigest_len != size || memcmp(hash, ps_info->msgdigest, size)) { @@ -210,55 +198,43 @@ out: } /** - * efi_signature_verify_with_list - verify a signature with signature list - * @regs: List of regions to be authenticated - * @msg: Signature - * @signed_info: Pointer to PKCS7's signed_info - * @siglist: Signature list for certificates - * @valid_cert: x509 certificate that verifies this signature + * efi_signature_lookup_digest - search for an image's digest in sigdb + * @regs: List of regions to be authenticated + * @db: Signature database for trusted certificates * - * Signature pointed to by @signed_info against image pointed to by @regs - * is verified by signature list pointed to by @siglist. - * Signature database is a simple concatenation of one or more - * signature list(s). + * A message digest of image pointed to by @regs is calculated and + * its hash value is compared to entries in signature database pointed + * to by @db. * - * Return: true if signature is verified, false if not + * Return: true if found, false if not */ -static -bool efi_signature_verify_with_list(struct efi_image_regions *regs, - struct pkcs7_message *msg, - struct pkcs7_signed_info *signed_info, - struct efi_signature_store *siglist, - struct x509_certificate **valid_cert) +bool efi_signature_lookup_digest(struct efi_image_regions *regs, + struct efi_signature_store *db) { - struct x509_certificate *cert; + struct efi_signature_store *siglist; struct efi_sig_data *sig_data; - bool verified = false; + void *hash = NULL; + size_t size = 0; + bool found = false; - EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, - regs, signed_info, siglist, valid_cert); + EFI_PRINT("%s: Enter, %p, %p\n", __func__, regs, db); - if (!signed_info) { - void *hash; - size_t size; + if (!regs || !db || !db->sig_data_list) + goto out; - EFI_PRINT("%s: unsigned image\n", __func__); - /* - * verify based on calculated hash value - * TODO: support other hash algorithms - */ + for (siglist = db; siglist; siglist = siglist->next) { + /* TODO: support other hash algorithms */ if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) { EFI_PRINT("Digest algorithm is not supported: %pUl\n", &siglist->sig_type); - goto out; + break; } - if (!efi_hash_regions(regs, &hash, &size)) { - EFI_PRINT("Digesting unsigned image failed\n"); - goto out; + if (!efi_hash_regions(regs->reg, regs->num, &hash, &size)) { + EFI_PRINT("Digesting an image failed\n"); + break; } - /* go through the list */ for (sig_data = siglist->sig_data_list; sig_data; sig_data = sig_data->next) { #ifdef DEBUG @@ -266,18 +242,52 @@ bool efi_signature_verify_with_list(struct efi_image_regions *regs, print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, sig_data->data, sig_data->size, false); #endif - if ((sig_data->size == size) && + if (sig_data->size == size && !memcmp(sig_data->data, hash, size)) { - verified = true; + found = true; free(hash); goto out; } } + free(hash); - goto out; + hash = NULL; } - EFI_PRINT("%s: signed image\n", __func__); +out: + EFI_PRINT("%s: Exit, found: %d\n", __func__, found); + return found; +} + +/** + * efi_signature_verify_with_list - verify a signature with signature list + * @regs: List of regions to be authenticated + * @msg: Signature + * @signed_info: Pointer to PKCS7's signed_info + * @siglist: Signature list for certificates + * @valid_cert: x509 certificate that verifies this signature + * + * Signature pointed to by @signed_info against image pointed to by @regs + * is verified by signature list pointed to by @siglist. + * Signature database is a simple concatenation of one or more + * signature list(s). + * + * Return: true if signature is verified, false if not + */ +static +bool efi_signature_verify_with_list(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct pkcs7_signed_info *signed_info, + struct efi_signature_store *siglist, + struct x509_certificate **valid_cert) +{ + struct x509_certificate *cert; + struct efi_sig_data *sig_data; + bool verified = false; + + EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, + regs, signed_info, siglist, valid_cert); + if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) { EFI_PRINT("Signature type is not supported: %pUl\n", &siglist->sig_type); @@ -313,211 +323,222 @@ out: } /** - * efi_signature_verify_with_sigdb - verify a signature with db - * @regs: List of regions to be authenticated - * @msg: Signature - * @db: Signature database for trusted certificates - * @cert: x509 certificate that verifies this signature + * efi_signature_check_revocation - check revocation with dbx + * @sinfo: Signer's info + * @cert: x509 certificate + * @dbx: Revocation signature database * - * Signature pointed to by @msg against image pointed to by @regs - * is verified by signature database pointed to by @db. + * Search revocation signature database pointed to by @dbx and find + * an entry matching to certificate pointed to by @cert. * - * Return: true if signature is verified, false if not + * While this entry contains revocation time, we don't support timestamp + * protocol at this time and any image will be unconditionally revoked + * when this match occurs. + * + * Return: true if check passed, false otherwise. */ -bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, - struct pkcs7_message *msg, - struct efi_signature_store *db, - struct x509_certificate **cert) +static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo, + struct x509_certificate *cert, + struct efi_signature_store *dbx) { - struct pkcs7_signed_info *info; struct efi_signature_store *siglist; - bool verified = false; - - EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, cert); + struct efi_sig_data *sig_data; + struct image_region reg[1]; + void *hash = NULL; + size_t size = 0; + time64_t revoc_time; + bool revoked = false; - if (!db) - goto out; + EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, sinfo, cert, dbx); - if (!db->sig_data_list) + if (!sinfo || !cert || !dbx || !dbx->sig_data_list) goto out; - /* for unsigned image */ - if (!msg) { - EFI_PRINT("%s: Verify unsigned image with db\n", __func__); - for (siglist = db; siglist; siglist = siglist->next) - if (efi_signature_verify_with_list(regs, NULL, NULL, - siglist, cert)) { - verified = true; - goto out; - } - - goto out; - } + EFI_PRINT("Checking revocation against %s\n", cert->subject); + for (siglist = dbx; siglist; siglist = siglist->next) { + if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509_sha256)) + continue; - /* for signed image or variable */ - EFI_PRINT("%s: Verify signed image with db\n", __func__); - for (info = msg->signed_infos; info; info = info->next) { - EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n", - info->sig->hash_algo, info->sig->pkey_algo); + /* calculate hash of TBSCertificate */ + reg[0].data = cert->tbs; + reg[0].size = cert->tbs_size; + if (!efi_hash_regions(reg, 1, &hash, &size)) + goto out; - for (siglist = db; siglist; siglist = siglist->next) { - if (efi_signature_verify_with_list(regs, msg, info, - siglist, cert)) { - verified = true; - goto out; + for (sig_data = siglist->sig_data_list; sig_data; + sig_data = sig_data->next) { + /* + * struct efi_cert_x509_sha256 { + * u8 tbs_hash[256/8]; + * time64_t revocation_time; + * }; + */ +#ifdef DEBUG + if (sig_data->size >= size) { + EFI_PRINT("hash in db:\n"); + print_hex_dump(" ", DUMP_PREFIX_OFFSET, + 16, 1, + sig_data->data, size, false); } +#endif + if ((sig_data->size < size + sizeof(time64_t)) || + memcmp(sig_data->data, hash, size)) + continue; + + memcpy(&revoc_time, sig_data->data + size, + sizeof(revoc_time)); + EFI_PRINT("revocation time: 0x%llx\n", revoc_time); + /* + * TODO: compare signing timestamp in sinfo + * with revocation time + */ + + revoked = true; + free(hash); + goto out; } + free(hash); + hash = NULL; } - out: - EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified); - return verified; + EFI_PRINT("%s: Exit, revoked: %d\n", __func__, revoked); + return !revoked; } /** - * efi_search_siglist - search signature list for a certificate - * @cert: x509 certificate - * @siglist: Signature list - * @revoc_time: Pointer to buffer for revocation time + * efi_signature_verify_one - verify signatures with database + * @regs: List of regions to be authenticated + * @msg: Signature + * @db: Signature database * - * Search signature list pointed to by @siglist and find a certificate - * pointed to by @cert. - * If found, revocation time that is specified in signature database is - * returned in @revoc_time. + * All the signature pointed to by @msg against image pointed to by @regs + * will be verified by signature database pointed to by @db. * - * Return: true if certificate is found, false if not + * Return: true if verification for one of signatures passed, false + * otherwise */ -static bool efi_search_siglist(struct x509_certificate *cert, - struct efi_signature_store *siglist, - time64_t *revoc_time) +bool efi_signature_verify_one(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db) { - struct image_region reg[1]; - void *hash = NULL, *msg = NULL; - struct efi_sig_data *sig_data; - bool found = false; - - /* can be null */ - if (!siglist->sig_data_list) - return false; + struct pkcs7_signed_info *sinfo; + struct efi_signature_store *siglist; + struct x509_certificate *cert; + bool verified = false; - if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509_sha256)) { - /* TODO: other hash algos */ - EFI_PRINT("Certificate's digest type is not supported: %pUl\n", - &siglist->sig_type); - goto out; - } + EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, regs, msg, db); - /* calculate hash of TBSCertificate */ - msg = calloc(1, SHA256_SUM_LEN); - if (!msg) { - EFI_PRINT("Out of memory\n"); + if (!db) goto out; - } - hash = calloc(1, SHA256_SUM_LEN); - if (!hash) { - EFI_PRINT("Out of memory\n"); + if (!db->sig_data_list) goto out; - } - reg[0].data = cert->tbs; - reg[0].size = cert->tbs_size; - hash_calculate("sha256", reg, 1, msg); + EFI_PRINT("%s: Verify signed image with db\n", __func__); + for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) { + EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n", + sinfo->sig->hash_algo, sinfo->sig->pkey_algo); - /* go through signature list */ - for (sig_data = siglist->sig_data_list; sig_data; - sig_data = sig_data->next) { - /* - * struct efi_cert_x509_sha256 { - * u8 tbs_hash[256/8]; - * time64_t revocation_time; - * }; - */ - if ((sig_data->size == SHA256_SUM_LEN) && - !memcmp(sig_data->data, hash, SHA256_SUM_LEN)) { - memcpy(revoc_time, sig_data->data + SHA256_SUM_LEN, - sizeof(*revoc_time)); - found = true; - goto out; - } + for (siglist = db; siglist; siglist = siglist->next) + if (efi_signature_verify_with_list(regs, msg, sinfo, + siglist, &cert)) { + verified = true; + goto out; + } + EFI_PRINT("Valid certificate not in \"db\"\n"); } out: - free(hash); - free(msg); - - return found; + EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified); + return verified; } /** - * efi_signature_verify_cert - verify a certificate with dbx - * @cert: x509 certificate - * @dbx: Signature database + * efi_signature_verify_with_sigdb - verify signatures with db and dbx + * @regs: List of regions to be authenticated + * @msg: Signature + * @db: Signature database for trusted certificates + * @dbx: Revocation signature database * - * Search signature database pointed to by @dbx and find a certificate - * pointed to by @cert. - * This function is expected to be used against "dbx". + * All the signature pointed to by @msg against image pointed to by @regs + * will be verified by signature database pointed to by @db and @dbx. * - * Return: true if a certificate is not rejected, false otherwise. + * Return: true if verification for all signatures passed, false otherwise */ -bool efi_signature_verify_cert(struct x509_certificate *cert, - struct efi_signature_store *dbx) +bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db, + struct efi_signature_store *dbx) { + struct pkcs7_signed_info *info; struct efi_signature_store *siglist; - time64_t revoc_time; - bool found = false; + struct x509_certificate *cert; + bool verified = false; - EFI_PRINT("%s: Enter, %p, %p\n", __func__, dbx, cert); + EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, dbx); - if (!cert) - return false; + if (!regs || !msg || !db || !db->sig_data_list) + goto out; - for (siglist = dbx; siglist; siglist = siglist->next) { - if (efi_search_siglist(cert, siglist, &revoc_time)) { - /* TODO */ - /* compare signing time with revocation time */ + for (info = msg->signed_infos; info; info = info->next) { + EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n", + info->sig->hash_algo, info->sig->pkey_algo); - found = true; - break; + for (siglist = db; siglist; siglist = siglist->next) { + if (efi_signature_verify_with_list(regs, msg, info, + siglist, &cert)) + break; + } + if (!siglist) { + EFI_PRINT("Valid certificate not in \"db\"\n"); + goto out; } + + if (!dbx || efi_signature_check_revocation(info, cert, dbx)) + continue; + + EFI_PRINT("Certificate in \"dbx\"\n"); + goto out; } + verified = true; - EFI_PRINT("%s: Exit, verified: %d\n", __func__, !found); - return !found; +out: + EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified); + return verified; } /** - * efi_signature_verify_signers - verify signers' certificates with dbx + * efi_signature_check_signers - check revocation against all signers with dbx * @msg: Signature - * @dbx: Signature database + * @dbx: Revocation signature database * - * Determine if any of signers' certificates in @msg may be verified - * by any of certificates in signature database pointed to by @dbx. - * This function is expected to be used against "dbx". + * Determine if none of signers' certificates in @msg are revoked + * by signature database pointed to by @dbx. * - * Return: true if none of certificates is rejected, false otherwise. + * Return: true if all signers passed, false otherwise. */ -bool efi_signature_verify_signers(struct pkcs7_message *msg, - struct efi_signature_store *dbx) +bool efi_signature_check_signers(struct pkcs7_message *msg, + struct efi_signature_store *dbx) { - struct pkcs7_signed_info *info; - bool found = false; + struct pkcs7_signed_info *sinfo; + bool revoked = false; EFI_PRINT("%s: Enter, %p, %p\n", __func__, msg, dbx); - if (!msg) + if (!msg || !dbx) goto out; - for (info = msg->signed_infos; info; info = info->next) { - if (info->signer && - !efi_signature_verify_cert(info->signer, dbx)) { - found = true; - goto out; + for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) { + if (sinfo->signer && + !efi_signature_check_revocation(sinfo, sinfo->signer, + dbx)) { + revoked = true; + break; } } out: - EFI_PRINT("%s: Exit, verified: %d\n", __func__, !found); - return !found; + EFI_PRINT("%s: Exit, revoked: %d\n", __func__, revoked); + return !revoked; } /** diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c new file mode 100644 index 0000000000..ee2e67bc8c --- /dev/null +++ b/lib/efi_loader/efi_var_common.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UEFI runtime variable services + * + * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#include <common.h> +#include <efi_loader.h> +#include <efi_variable.h> + +enum efi_secure_mode { + EFI_MODE_SETUP, + EFI_MODE_USER, + EFI_MODE_AUDIT, + EFI_MODE_DEPLOYED, +}; + +struct efi_auth_var_name_type { + const u16 *name; + const efi_guid_t *guid; + const enum efi_auth_var_type type; +}; + +static const struct efi_auth_var_name_type name_type[] = { + {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK}, + {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK}, + {u"db", &efi_guid_image_security_database, EFI_AUTH_VAR_DB}, + {u"dbx", &efi_guid_image_security_database, EFI_AUTH_VAR_DBX}, + /* not used yet + {u"dbt", &efi_guid_image_security_database, EFI_AUTH_VAR_DBT}, + {u"dbr", &efi_guid_image_security_database, EFI_AUTH_VAR_DBR}, + */ +}; + +static bool efi_secure_boot; +static enum efi_secure_mode efi_secure_mode; + +/** + * efi_efi_get_variable() - retrieve value of a UEFI variable + * + * This function implements the GetVariable runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @variable_name: name of the variable + * @vendor: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer to which the variable value is copied + * @data: buffer to which the variable value is copied + * Return: status code + */ +efi_status_t EFIAPI efi_get_variable(u16 *variable_name, + const efi_guid_t *vendor, u32 *attributes, + efi_uintn_t *data_size, void *data) +{ + efi_status_t ret; + + EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes, + data_size, data); + + ret = efi_get_variable_int(variable_name, vendor, attributes, + data_size, data, NULL); + + /* Remove EFI_VARIABLE_READ_ONLY flag */ + if (attributes) + *attributes &= EFI_VARIABLE_MASK; + + return EFI_EXIT(ret); +} + +/** + * efi_set_variable() - set value of a UEFI variable + * + * This function implements the SetVariable runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @variable_name: name of the variable + * @vendor: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer with the variable value + * @data: buffer with the variable value + * Return: status code + */ +efi_status_t EFIAPI efi_set_variable(u16 *variable_name, + const efi_guid_t *vendor, u32 attributes, + efi_uintn_t data_size, const void *data) +{ + efi_status_t ret; + + EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes, + data_size, data); + + /* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */ + if (attributes & ~(u32)EFI_VARIABLE_MASK) + ret = EFI_INVALID_PARAMETER; + else + ret = efi_set_variable_int(variable_name, vendor, attributes, + data_size, data, true); + + return EFI_EXIT(ret); +} + +/** + * efi_get_next_variable_name() - enumerate the current variable names + * + * @variable_name_size: size of variable_name buffer in byte + * @variable_name: name of uefi variable's name in u16 + * @vendor: vendor's guid + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, + u16 *variable_name, + efi_guid_t *vendor) +{ + efi_status_t ret; + + EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor); + + ret = efi_get_next_variable_name_int(variable_name_size, variable_name, + vendor); + + return EFI_EXIT(ret); +} + +/** + * efi_query_variable_info() - get information about EFI variables + * + * This function implements the QueryVariableInfo() runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @attributes: bitmask to select variables to be + * queried + * @maximum_variable_storage_size: maximum size of storage area for the + * selected variable types + * @remaining_variable_storage_size: remaining size of storage are for the + * selected variable types + * @maximum_variable_size: maximum size of a variable of the + * selected type + * Returns: status code + */ +efi_status_t EFIAPI efi_query_variable_info( + u32 attributes, u64 *maximum_variable_storage_size, + u64 *remaining_variable_storage_size, + u64 *maximum_variable_size) +{ + efi_status_t ret; + + EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size, + remaining_variable_storage_size, maximum_variable_size); + + ret = efi_query_variable_info_int(attributes, + maximum_variable_storage_size, + remaining_variable_storage_size, + maximum_variable_size); + + return EFI_EXIT(ret); +} + +/** + * efi_set_secure_state - modify secure boot state variables + * @secure_boot: value of SecureBoot + * @setup_mode: value of SetupMode + * @audit_mode: value of AuditMode + * @deployed_mode: value of DeployedMode + * + * Modify secure boot status related variables as indicated. + * + * Return: status code + */ +static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode, + u8 audit_mode, u8 deployed_mode) +{ + efi_status_t ret; + const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY; + const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + + efi_secure_boot = secure_boot; + + ret = efi_set_variable_int(L"SecureBoot", &efi_global_variable_guid, + attributes_ro, sizeof(secure_boot), + &secure_boot, false); + if (ret != EFI_SUCCESS) + goto err; + + ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid, + attributes_ro, sizeof(setup_mode), + &setup_mode, false); + if (ret != EFI_SUCCESS) + goto err; + + ret = efi_set_variable_int(L"AuditMode", &efi_global_variable_guid, + audit_mode || setup_mode ? + attributes_ro : attributes_rw, + sizeof(audit_mode), &audit_mode, false); + if (ret != EFI_SUCCESS) + goto err; + + ret = efi_set_variable_int(L"DeployedMode", + &efi_global_variable_guid, + audit_mode || deployed_mode || setup_mode ? + attributes_ro : attributes_rw, + sizeof(deployed_mode), &deployed_mode, + false); +err: + return ret; +} + +/** + * efi_transfer_secure_state - handle a secure boot state transition + * @mode: new state + * + * Depending on @mode, secure boot related variables are updated. + * Those variables are *read-only* for users, efi_set_variable_int() + * is called here. + * + * Return: status code + */ +static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode) +{ + efi_status_t ret; + + EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode, + mode); + + if (mode == EFI_MODE_DEPLOYED) { + ret = efi_set_secure_state(1, 0, 0, 1); + if (ret != EFI_SUCCESS) + goto err; + } else if (mode == EFI_MODE_AUDIT) { + ret = efi_set_variable_int(L"PK", &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + 0, NULL, false); + if (ret != EFI_SUCCESS) + goto err; + + ret = efi_set_secure_state(0, 1, 1, 0); + if (ret != EFI_SUCCESS) + goto err; + } else if (mode == EFI_MODE_USER) { + ret = efi_set_secure_state(1, 0, 0, 0); + if (ret != EFI_SUCCESS) + goto err; + } else if (mode == EFI_MODE_SETUP) { + ret = efi_set_secure_state(0, 1, 0, 0); + if (ret != EFI_SUCCESS) + goto err; + } else { + return EFI_INVALID_PARAMETER; + } + + efi_secure_mode = mode; + + return EFI_SUCCESS; + +err: + /* TODO: What action should be taken here? */ + printf("ERROR: Secure state transition failed\n"); + return ret; +} + +efi_status_t efi_init_secure_state(void) +{ + enum efi_secure_mode mode = EFI_MODE_SETUP; + u8 efi_vendor_keys = 0; + efi_uintn_t size = 0; + efi_status_t ret; + + ret = efi_get_variable_int(L"PK", &efi_global_variable_guid, + NULL, &size, NULL, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) { + if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) + mode = EFI_MODE_USER; + } + + ret = efi_transfer_secure_state(mode); + if (ret != EFI_SUCCESS) + return ret; + + /* As we do not provide vendor keys this variable is always 0. */ + ret = efi_set_variable_int(L"VendorKeys", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(efi_vendor_keys), + &efi_vendor_keys, false); + return ret; +} + +/** + * efi_secure_boot_enabled - return if secure boot is enabled or not + * + * Return: true if enabled, false if disabled + */ +bool efi_secure_boot_enabled(void) +{ + return efi_secure_boot; +} + +enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid) +{ + for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) { + if (!u16_strcmp(name, name_type[i].name) && + !guidcmp(guid, name_type[i].guid)) + return name_type[i].type; + } + return EFI_AUTH_VAR_NONE; +} diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c new file mode 100644 index 0000000000..6f9d76f2a2 --- /dev/null +++ b/lib/efi_loader/efi_var_file.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * File interface for UEFI variables + * + * Copyright (c) 2020, Heinrich Schuchardt + */ + +#define LOG_CATEGORY LOGC_EFI + +#include <common.h> +#include <charset.h> +#include <fs.h> +#include <log.h> +#include <malloc.h> +#include <mapmem.h> +#include <efi_loader.h> +#include <efi_variable.h> +#include <u-boot/crc.h> + +#define PART_STR_LEN 10 + +/** + * efi_set_blk_dev_to_system_partition() - select EFI system partition + * + * Set the EFI system partition as current block device. + * + * Return: status code + */ +static efi_status_t __maybe_unused efi_set_blk_dev_to_system_partition(void) +{ + char part_str[PART_STR_LEN]; + int r; + + if (!efi_system_partition.if_type) { + log_err("No EFI system partition\n"); + return EFI_DEVICE_ERROR; + } + snprintf(part_str, PART_STR_LEN, "%u:%u", + efi_system_partition.devnum, efi_system_partition.part); + r = fs_set_blk_dev(blk_get_if_type_name(efi_system_partition.if_type), + part_str, FS_TYPE_ANY); + if (r) { + log_err("Cannot read EFI system partition\n"); + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +/** + * efi_var_collect() - collect non-volatile variables in buffer + * + * A buffer is allocated and filled with all non-volatile variables in a + * format ready to be written to disk. + * + * @bufp: pointer to pointer of buffer with collected variables + * @lenp: pointer to length of buffer + * Return: status code + */ +static efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, + loff_t *lenp) +{ + size_t len = EFI_VAR_BUF_SIZE; + struct efi_var_file *buf; + struct efi_var_entry *var, *old_var; + size_t old_var_name_length = 2; + + *bufp = NULL; /* Avoid double free() */ + buf = calloc(1, len); + if (!buf) + return EFI_OUT_OF_RESOURCES; + var = buf->var; + old_var = var; + for (;;) { + efi_uintn_t data_length, var_name_length; + u8 *data; + efi_status_t ret; + + if ((uintptr_t)buf + len <= + (uintptr_t)var->name + old_var_name_length) + return EFI_BUFFER_TOO_SMALL; + + var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name; + memcpy(var->name, old_var->name, old_var_name_length); + guidcpy(&var->guid, &old_var->guid); + ret = efi_get_next_variable_name_int( + &var_name_length, var->name, &var->guid); + if (ret == EFI_NOT_FOUND) + break; + if (ret != EFI_SUCCESS) { + free(buf); + return ret; + } + old_var_name_length = var_name_length; + old_var = var; + + data = (u8 *)var->name + old_var_name_length; + data_length = (uintptr_t)buf + len - (uintptr_t)data; + ret = efi_get_variable_int(var->name, &var->guid, + &var->attr, &data_length, data, + &var->time); + if (ret != EFI_SUCCESS) { + free(buf); + return ret; + } + if (!(var->attr & EFI_VARIABLE_NON_VOLATILE)) + continue; + var->length = data_length; + var = (struct efi_var_entry *) + ALIGN((uintptr_t)data + data_length, 8); + } + + buf->reserved = 0; + buf->magic = EFI_VAR_FILE_MAGIC; + len = (uintptr_t)var - (uintptr_t)buf; + buf->crc32 = crc32(0, (u8 *)buf->var, + len - sizeof(struct efi_var_file)); + buf->length = len; + *bufp = buf; + *lenp = len; + + return EFI_SUCCESS; +} + +/** + * efi_var_to_file() - save non-volatile variables as file + * + * File ubootefi.var is created on the EFI system partion. + * + * Return: status code + */ +efi_status_t efi_var_to_file(void) +{ +#ifdef CONFIG_EFI_VARIABLE_FILE_STORE + efi_status_t ret; + struct efi_var_file *buf; + loff_t len; + loff_t actlen; + int r; + + ret = efi_var_collect(&buf, &len); + if (ret != EFI_SUCCESS) + goto error; + + ret = efi_set_blk_dev_to_system_partition(); + if (ret != EFI_SUCCESS) + goto error; + + r = fs_write(EFI_VAR_FILE_NAME, map_to_sysmem(buf), 0, len, &actlen); + if (r || len != actlen) + ret = EFI_DEVICE_ERROR; + +error: + if (ret != EFI_SUCCESS) + log_err("Failed to persist EFI variables\n"); + free(buf); + return ret; +#else + return EFI_SUCCESS; +#endif +} + +efi_status_t efi_var_restore(struct efi_var_file *buf) +{ + struct efi_var_entry *var, *last_var; + efi_status_t ret; + + if (buf->reserved || buf->magic != EFI_VAR_FILE_MAGIC || + buf->crc32 != crc32(0, (u8 *)buf->var, + buf->length - sizeof(struct efi_var_file))) { + log_err("Invalid EFI variables file\n"); + return EFI_INVALID_PARAMETER; + } + + var = buf->var; + last_var = (struct efi_var_entry *)((u8 *)buf + buf->length); + while (var < last_var) { + u16 *data = var->name + u16_strlen(var->name) + 1; + + if (var->attr & EFI_VARIABLE_NON_VOLATILE && var->length) { + ret = efi_var_mem_ins(var->name, &var->guid, var->attr, + var->length, data, 0, NULL, + var->time); + if (ret != EFI_SUCCESS) + log_err("Failed to set EFI variable %ls\n", + var->name); + } + var = (struct efi_var_entry *) + ALIGN((uintptr_t)data + var->length, 8); + } + return EFI_SUCCESS; +} + +/** + * efi_var_from_file() - read variables from file + * + * File ubootefi.var is read from the EFI system partitions and the variables + * stored in the file are created. + * + * In case the file does not exist yet or a variable cannot be set EFI_SUCCESS + * is returned. + * + * Return: status code + */ +efi_status_t efi_var_from_file(void) +{ +#ifdef CONFIG_EFI_VARIABLE_FILE_STORE + struct efi_var_file *buf; + loff_t len; + efi_status_t ret; + int r; + + buf = calloc(1, EFI_VAR_BUF_SIZE); + if (!buf) { + log_err("Out of memory\n"); + return EFI_OUT_OF_RESOURCES; + } + + ret = efi_set_blk_dev_to_system_partition(); + if (ret != EFI_SUCCESS) + goto error; + r = fs_read(EFI_VAR_FILE_NAME, map_to_sysmem(buf), 0, EFI_VAR_BUF_SIZE, + &len); + if (r || len < sizeof(struct efi_var_file)) { + log_err("Failed to load EFI variables\n"); + goto error; + } + if (buf->length != len || efi_var_restore(buf) != EFI_SUCCESS) + log_err("Invalid EFI variables file\n"); +error: + free(buf); +#endif + return EFI_SUCCESS; +} diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c new file mode 100644 index 0000000000..7a2dba7dc2 --- /dev/null +++ b/lib/efi_loader/efi_var_mem.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * File interface for UEFI variables + * + * Copyright (c) 2020, Heinrich Schuchardt + */ + +#include <common.h> +#include <efi_loader.h> +#include <efi_variable.h> +#include <u-boot/crc.h> + +static struct efi_var_file __efi_runtime_data *efi_var_buf; +static struct efi_var_entry __efi_runtime_data *efi_current_var; + +/** + * efi_var_mem_compare() - compare GUID and name with a variable + * + * @var: variable to compare + * @guid: GUID to compare + * @name: variable name to compare + * @next: pointer to next variable + * Return: true if match + */ +static bool __efi_runtime +efi_var_mem_compare(struct efi_var_entry *var, const efi_guid_t *guid, + const u16 *name, struct efi_var_entry **next) +{ + int i; + u8 *guid1, *guid2; + const u16 *data, *var_name; + bool match = true; + + for (guid1 = (u8 *)&var->guid, guid2 = (u8 *)guid, i = 0; + i < sizeof(efi_guid_t) && match; ++i) + match = (guid1[i] == guid2[i]); + + for (data = var->name, var_name = name;; ++data, ++var_name) { + if (match) + match = (*data == *var_name); + if (!*data) + break; + } + + ++data; + + if (next) + *next = (struct efi_var_entry *) + ALIGN((uintptr_t)data + var->length, 8); + + if (match) + efi_current_var = var; + + return match; +} + +struct efi_var_entry __efi_runtime +*efi_var_mem_find(const efi_guid_t *guid, const u16 *name, + struct efi_var_entry **next) +{ + struct efi_var_entry *var, *last; + + last = (struct efi_var_entry *) + ((uintptr_t)efi_var_buf + efi_var_buf->length); + + if (!*name) { + if (next) { + *next = efi_var_buf->var; + if (*next >= last) + *next = NULL; + } + return NULL; + } + if (efi_current_var && + efi_var_mem_compare(efi_current_var, guid, name, next)) { + if (next && *next >= last) + *next = NULL; + return efi_current_var; + } + + var = efi_var_buf->var; + if (var < last) { + for (; var;) { + struct efi_var_entry *pos; + bool match; + + match = efi_var_mem_compare(var, guid, name, &pos); + if (pos >= last) + pos = NULL; + if (match) { + if (next) + *next = pos; + return var; + } + var = pos; + } + } + if (next) + *next = NULL; + return NULL; +} + +void __efi_runtime efi_var_mem_del(struct efi_var_entry *var) +{ + u16 *data; + struct efi_var_entry *next, *last; + + if (!var) + return; + + last = (struct efi_var_entry *) + ((uintptr_t)efi_var_buf + efi_var_buf->length); + if (var <= efi_current_var) + efi_current_var = NULL; + + for (data = var->name; *data; ++data) + ; + ++data; + next = (struct efi_var_entry *) + ALIGN((uintptr_t)data + var->length, 8); + efi_var_buf->length -= (uintptr_t)next - (uintptr_t)var; + + memmove(var, next, (uintptr_t)last - (uintptr_t)next); + efi_var_buf->crc32 = crc32(0, (u8 *)efi_var_buf->var, + efi_var_buf->length - + sizeof(struct efi_var_file)); +} + +efi_status_t __efi_runtime efi_var_mem_ins( + u16 *variable_name, + const efi_guid_t *vendor, u32 attributes, + const efi_uintn_t size1, const void *data1, + const efi_uintn_t size2, const void *data2, + const u64 time) +{ + u16 *data; + struct efi_var_entry *var; + u32 var_name_len; + + var = (struct efi_var_entry *) + ((uintptr_t)efi_var_buf + efi_var_buf->length); + for (var_name_len = 0; variable_name[var_name_len]; ++var_name_len) + ; + ++var_name_len; + data = var->name + var_name_len; + + if ((uintptr_t)data - (uintptr_t)efi_var_buf + size1 + size2 > + EFI_VAR_BUF_SIZE) + return EFI_OUT_OF_RESOURCES; + + var->attr = attributes; + var->length = size1 + size2; + var->time = time; + + efi_memcpy_runtime(&var->guid, vendor, sizeof(efi_guid_t)); + efi_memcpy_runtime(var->name, variable_name, + sizeof(u16) * var_name_len); + efi_memcpy_runtime(data, data1, size1); + efi_memcpy_runtime((u8 *)data + size1, data2, size2); + + var = (struct efi_var_entry *) + ALIGN((uintptr_t)data + var->length, 8); + efi_var_buf->length = (uintptr_t)var - (uintptr_t)efi_var_buf; + efi_var_buf->crc32 = crc32(0, (u8 *)efi_var_buf->var, + efi_var_buf->length - + sizeof(struct efi_var_file)); + + return EFI_SUCCESS; +} + +u64 __efi_runtime efi_var_mem_free(void) +{ + return EFI_VAR_BUF_SIZE - efi_var_buf->length - + sizeof(struct efi_var_entry); +} + +/** + * efi_var_mem_bs_del() - delete boot service only variables + */ +static void efi_var_mem_bs_del(void) +{ + struct efi_var_entry *var = efi_var_buf->var; + + for (;;) { + struct efi_var_entry *last; + + last = (struct efi_var_entry *) + ((uintptr_t)efi_var_buf + efi_var_buf->length); + if (var >= last) + break; + if (var->attr & EFI_VARIABLE_RUNTIME_ACCESS) { + u16 *data; + + /* skip variable */ + for (data = var->name; *data; ++data) + ; + ++data; + var = (struct efi_var_entry *) + ALIGN((uintptr_t)data + var->length, 8); + } else { + /* delete variable */ + efi_var_mem_del(var); + } + } +} + +/** + * efi_var_mem_notify_exit_boot_services() - ExitBootService callback + * + * @event: callback event + * @context: callback context + */ +static void EFIAPI __efi_runtime +efi_var_mem_notify_exit_boot_services(struct efi_event *event, void *context) +{ + EFI_ENTRY("%p, %p", event, context); + + /* Delete boot service only variables */ + efi_var_mem_bs_del(); + + EFI_EXIT(EFI_SUCCESS); +} + +/** + * efi_var_mem_notify_exit_boot_services() - SetVirtualMemoryMap callback + * + * @event: callback event + * @context: callback context + */ +static void EFIAPI __efi_runtime +efi_var_mem_notify_virtual_address_map(struct efi_event *event, void *context) +{ + efi_convert_pointer(0, (void **)&efi_var_buf); +} + +efi_status_t efi_var_mem_init(void) +{ + u64 memory; + efi_status_t ret; + struct efi_event *event; + + ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_DATA, + efi_size_in_pages(EFI_VAR_BUF_SIZE), + &memory); + if (ret != EFI_SUCCESS) + return ret; + efi_var_buf = (struct efi_var_file *)(uintptr_t)memory; + memset(efi_var_buf, 0, EFI_VAR_BUF_SIZE); + efi_var_buf->magic = EFI_VAR_FILE_MAGIC; + efi_var_buf->length = (uintptr_t)efi_var_buf->var - + (uintptr_t)efi_var_buf; + /* crc32 for 0 bytes = 0 */ + + ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, + efi_var_mem_notify_exit_boot_services, NULL, + NULL, &event); + if (ret != EFI_SUCCESS) + return ret; + ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_CALLBACK, + efi_var_mem_notify_virtual_address_map, NULL, + NULL, &event); + if (ret != EFI_SUCCESS) + return ret; + return ret; +} diff --git a/lib/efi_loader/efi_var_seed.S b/lib/efi_loader/efi_var_seed.S new file mode 100644 index 0000000000..e0a40cf46c --- /dev/null +++ b/lib/efi_loader/efi_var_seed.S @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Predefined UEFI variables + * + * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#include <config.h> + +.section .rodata.efi_seed.init,"a" +.balign 16 +.global __efi_var_file_begin +__efi_var_file_begin: +.incbin CONFIG_EFI_VAR_SEED_FILE +.global __efi_var_file_end +__efi_var_file_end: +.balign 16 diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index efaba869ef..39a8482903 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -5,349 +5,23 @@ * Copyright (c) 2017 Rob Clark */ +#define LOG_CATEGORY LOGC_EFI + #include <common.h> #include <efi_loader.h> +#include <efi_variable.h> #include <env.h> #include <env_internal.h> #include <hexdump.h> +#include <log.h> #include <malloc.h> #include <rtc.h> #include <search.h> #include <uuid.h> #include <crypto/pkcs7_parser.h> -#include <linux/bitops.h> #include <linux/compat.h> #include <u-boot/crc.h> - -enum efi_secure_mode { - EFI_MODE_SETUP, - EFI_MODE_USER, - EFI_MODE_AUDIT, - EFI_MODE_DEPLOYED, -}; - -static bool efi_secure_boot; -static enum efi_secure_mode efi_secure_mode; -static u8 efi_vendor_keys; - -#define READ_ONLY BIT(31) - -static efi_status_t efi_get_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 *attributes, - efi_uintn_t *data_size, void *data, - u64 *timep); - -static efi_status_t efi_set_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 attributes, - efi_uintn_t data_size, - const void *data, - bool ro_check); - -/* - * Mapping between EFI variables and u-boot variables: - * - * efi_$guid_$varname = {attributes}(type)value - * - * For example: - * - * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported= - * "{ro,boot,run}(blob)0000000000000000" - * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder= - * "(blob)00010000" - * - * The attributes are a comma separated list of these possible - * attributes: - * - * + ro - read-only - * + boot - boot-services access - * + run - runtime access - * - * NOTE: with current implementation, no variables are available after - * ExitBootServices, and all are persisted (if possible). - * - * If not specified, the attributes default to "{boot}". - * - * The required type is one of: - * - * + utf8 - raw utf8 string - * + blob - arbitrary length hex string - * - * Maybe a utf16 type would be useful to for a string value to be auto - * converted to utf16? - */ - -#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_")) - -/** - * efi_to_native() - convert the UEFI variable name and vendor GUID to U-Boot - * variable name - * - * The U-Boot variable name is a concatenation of prefix 'efi', the hexstring - * encoded vendor GUID, and the UTF-8 encoded UEFI variable name separated by - * underscores, e.g. 'efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder'. - * - * @native: pointer to pointer to U-Boot variable name - * @variable_name: UEFI variable name - * @vendor: vendor GUID - * Return: status code - */ -static efi_status_t efi_to_native(char **native, const u16 *variable_name, - const efi_guid_t *vendor) -{ - size_t len; - char *pos; - - len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1; - *native = malloc(len); - if (!*native) - return EFI_OUT_OF_RESOURCES; - - pos = *native; - pos += sprintf(pos, "efi_%pUl_", vendor); - utf16_utf8_strcpy(&pos, variable_name); - - return EFI_SUCCESS; -} - -/** - * prefix() - skip over prefix - * - * Skip over a prefix string. - * - * @str: string with prefix - * @prefix: prefix string - * Return: string without prefix, or NULL if prefix not found - */ -static const char *prefix(const char *str, const char *prefix) -{ - size_t n = strlen(prefix); - if (!strncmp(prefix, str, n)) - return str + n; - return NULL; -} - -/** - * parse_attr() - decode attributes part of variable value - * - * Convert the string encoded attributes of a UEFI variable to a bit mask. - * TODO: Several attributes are not supported. - * - * @str: value of U-Boot variable - * @attrp: pointer to UEFI attributes - * @timep: pointer to time attribute - * Return: pointer to remainder of U-Boot variable value - */ -static const char *parse_attr(const char *str, u32 *attrp, u64 *timep) -{ - u32 attr = 0; - char sep = '{'; - - if (*str != '{') { - *attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS; - return str; - } - - while (*str == sep) { - const char *s; - - str++; - - if ((s = prefix(str, "ro"))) { - attr |= READ_ONLY; - } else if ((s = prefix(str, "nv"))) { - attr |= EFI_VARIABLE_NON_VOLATILE; - } else if ((s = prefix(str, "boot"))) { - attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; - } else if ((s = prefix(str, "run"))) { - attr |= EFI_VARIABLE_RUNTIME_ACCESS; - } else if ((s = prefix(str, "time="))) { - attr |= EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; - hex2bin((u8 *)timep, s, sizeof(*timep)); - s += sizeof(*timep) * 2; - } else if (*str == '}') { - break; - } else { - printf("invalid attribute: %s\n", str); - break; - } - - str = s; - sep = ','; - } - - str++; - - *attrp = attr; - - return str; -} - -/** - * efi_set_secure_state - modify secure boot state variables - * @secure_boot: value of SecureBoot - * @setup_mode: value of SetupMode - * @audit_mode: value of AuditMode - * @deployed_mode: value of DeployedMode - * - * Modify secure boot status related variables as indicated. - * - * Return: status code - */ -static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode, - u8 audit_mode, u8 deployed_mode) -{ - u32 attributes; - efi_status_t ret; - - attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS | - READ_ONLY; - ret = efi_set_variable_common(L"SecureBoot", &efi_global_variable_guid, - attributes, sizeof(secure_boot), - &secure_boot, false); - if (ret != EFI_SUCCESS) - goto err; - - ret = efi_set_variable_common(L"SetupMode", &efi_global_variable_guid, - attributes, sizeof(setup_mode), - &setup_mode, false); - if (ret != EFI_SUCCESS) - goto err; - - ret = efi_set_variable_common(L"AuditMode", &efi_global_variable_guid, - attributes, sizeof(audit_mode), - &audit_mode, false); - if (ret != EFI_SUCCESS) - goto err; - - ret = efi_set_variable_common(L"DeployedMode", - &efi_global_variable_guid, attributes, - sizeof(deployed_mode), &deployed_mode, - false); -err: - return ret; -} - -/** - * efi_transfer_secure_state - handle a secure boot state transition - * @mode: new state - * - * Depending on @mode, secure boot related variables are updated. - * Those variables are *read-only* for users, efi_set_variable_common() - * is called here. - * - * Return: status code - */ -static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode) -{ - efi_status_t ret; - - EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode, - mode); - - if (mode == EFI_MODE_DEPLOYED) { - ret = efi_set_secure_state(1, 0, 0, 1); - if (ret != EFI_SUCCESS) - goto err; - - efi_secure_boot = true; - } else if (mode == EFI_MODE_AUDIT) { - ret = efi_set_variable_common(L"PK", &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - 0, NULL, false); - if (ret != EFI_SUCCESS) - goto err; - - ret = efi_set_secure_state(0, 1, 1, 0); - if (ret != EFI_SUCCESS) - goto err; - - efi_secure_boot = true; - } else if (mode == EFI_MODE_USER) { - ret = efi_set_secure_state(1, 0, 0, 0); - if (ret != EFI_SUCCESS) - goto err; - - efi_secure_boot = true; - } else if (mode == EFI_MODE_SETUP) { - ret = efi_set_secure_state(0, 1, 0, 0); - if (ret != EFI_SUCCESS) - goto err; - } else { - return EFI_INVALID_PARAMETER; - } - - efi_secure_mode = mode; - - return EFI_SUCCESS; - -err: - /* TODO: What action should be taken here? */ - printf("ERROR: Secure state transition failed\n"); - return ret; -} - -/** - * efi_init_secure_state - initialize secure boot state - * - * Return: status code - */ -static efi_status_t efi_init_secure_state(void) -{ - enum efi_secure_mode mode; - efi_uintn_t size; - efi_status_t ret; - - /* - * TODO: - * Since there is currently no "platform-specific" installation - * method of Platform Key, we can't say if VendorKeys is 0 or 1 - * precisely. - */ - - size = 0; - ret = efi_get_variable_common(L"PK", &efi_global_variable_guid, - NULL, &size, NULL, NULL); - if (ret == EFI_BUFFER_TOO_SMALL) { - if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) - mode = EFI_MODE_USER; - else - mode = EFI_MODE_SETUP; - - efi_vendor_keys = 0; - } else if (ret == EFI_NOT_FOUND) { - mode = EFI_MODE_SETUP; - efi_vendor_keys = 1; - } else { - goto err; - } - - ret = efi_transfer_secure_state(mode); - if (ret == EFI_SUCCESS) - ret = efi_set_variable_common(L"VendorKeys", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS | - READ_ONLY, - sizeof(efi_vendor_keys), - &efi_vendor_keys, false); - -err: - return ret; -} - -/** - * efi_secure_boot_enabled - return if secure boot is enabled or not - * - * Return: true if enabled, false if disabled - */ -bool efi_secure_boot_enabled(void) -{ - return efi_secure_boot; -} +#include <asm/sections.h> #ifdef CONFIG_EFI_SECURE_BOOT static u8 pkcs7_hdr[] = { @@ -462,6 +136,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable, struct efi_time timestamp; struct rtc_time tm; u64 new_time; + enum efi_auth_var_type var_type; efi_status_t ret; var_sig = NULL; @@ -538,18 +213,20 @@ static efi_status_t efi_variable_authenticate(u16 *variable, } /* signature database used for authentication */ - if (u16_strcmp(variable, L"PK") == 0 || - u16_strcmp(variable, L"KEK") == 0) { + var_type = efi_auth_var_get_type(variable, vendor); + switch (var_type) { + case EFI_AUTH_VAR_PK: + case EFI_AUTH_VAR_KEK: /* with PK */ truststore = efi_sigstore_parse_sigdb(L"PK"); if (!truststore) goto err; - } else if (u16_strcmp(variable, L"db") == 0 || - u16_strcmp(variable, L"dbx") == 0) { + break; + case EFI_AUTH_VAR_DB: + case EFI_AUTH_VAR_DBX: /* with PK and KEK */ truststore = efi_sigstore_parse_sigdb(L"KEK"); truststore2 = efi_sigstore_parse_sigdb(L"PK"); - if (!truststore) { if (!truststore2) goto err; @@ -557,7 +234,8 @@ static efi_status_t efi_variable_authenticate(u16 *variable, truststore = truststore2; truststore2 = NULL; } - } else { + break; + default: /* TODO: support private authenticated variables */ goto err; } @@ -599,378 +277,148 @@ static efi_status_t efi_variable_authenticate(u16 *variable, } #endif /* CONFIG_EFI_SECURE_BOOT */ -static efi_status_t efi_get_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 *attributes, - efi_uintn_t *data_size, void *data, - u64 *timep) +efi_status_t __efi_runtime +efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 *attributes, efi_uintn_t *data_size, void *data, + u64 *timep) { - char *native_name; - efi_status_t ret; - unsigned long in_size; - const char *val = NULL, *s; - u64 time = 0; - u32 attr; + efi_uintn_t old_size; + struct efi_var_entry *var; + u16 *pdata; if (!variable_name || !vendor || !data_size) return EFI_INVALID_PARAMETER; - - ret = efi_to_native(&native_name, variable_name, vendor); - if (ret) - return ret; - - EFI_PRINT("get '%s'\n", native_name); - - val = env_get(native_name); - free(native_name); - if (!val) + var = efi_var_mem_find(vendor, variable_name, NULL); + if (!var) return EFI_NOT_FOUND; - val = parse_attr(val, &attr, &time); - + if (attributes) + *attributes = var->attr; if (timep) - *timep = time; - - in_size = *data_size; - - if ((s = prefix(val, "(blob)"))) { - size_t len = strlen(s); - - /* number of hexadecimal digits must be even */ - if (len & 1) - return EFI_DEVICE_ERROR; - - /* two characters per byte: */ - len /= 2; - *data_size = len; - - if (in_size < len) { - ret = EFI_BUFFER_TOO_SMALL; - goto out; - } - - if (!data) { - EFI_PRINT("Variable with no data shouldn't exist.\n"); - return EFI_INVALID_PARAMETER; - } + *timep = var->time; - if (hex2bin(data, s, len)) - return EFI_DEVICE_ERROR; - - EFI_PRINT("got value: \"%s\"\n", s); - } else if ((s = prefix(val, "(utf8)"))) { - unsigned len = strlen(s) + 1; - - *data_size = len; - - if (in_size < len) { - ret = EFI_BUFFER_TOO_SMALL; - goto out; - } - - if (!data) { - EFI_PRINT("Variable with no data shouldn't exist.\n"); - return EFI_INVALID_PARAMETER; - } - - memcpy(data, s, len); - ((char *)data)[len] = '\0'; - - EFI_PRINT("got value: \"%s\"\n", (char *)data); - } else { - EFI_PRINT("invalid value: '%s'\n", val); - return EFI_DEVICE_ERROR; - } - -out: - if (attributes) - *attributes = attr & EFI_VARIABLE_MASK; + old_size = *data_size; + *data_size = var->length; + if (old_size < var->length) + return EFI_BUFFER_TOO_SMALL; - return ret; -} + if (!data) + return EFI_INVALID_PARAMETER; -/** - * efi_efi_get_variable() - retrieve value of a UEFI variable - * - * This function implements the GetVariable runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @variable_name: name of the variable - * @vendor: vendor GUID - * @attributes: attributes of the variable - * @data_size: size of the buffer to which the variable value is copied - * @data: buffer to which the variable value is copied - * Return: status code - */ -efi_status_t EFIAPI efi_get_variable(u16 *variable_name, - const efi_guid_t *vendor, u32 *attributes, - efi_uintn_t *data_size, void *data) -{ - efi_status_t ret; + for (pdata = var->name; *pdata; ++pdata) + ; + ++pdata; - EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes, - data_size, data); + efi_memcpy_runtime(data, pdata, var->length); - ret = efi_get_variable_common(variable_name, vendor, attributes, - data_size, data, NULL); - return EFI_EXIT(ret); + return EFI_SUCCESS; } -static char *efi_variables_list; -static char *efi_cur_variable; - -/** - * parse_uboot_variable() - parse a u-boot variable and get uefi-related - * information - * @variable: whole data of u-boot variable (ie. name=value) - * @variable_name_size: size of variable_name buffer in byte - * @variable_name: name of uefi variable in u16, null-terminated - * @vendor: vendor's guid - * @attributes: attributes - * - * A uefi variable is encoded into a u-boot variable as described above. - * This function parses such a u-boot variable and retrieve uefi-related - * information into respective parameters. In return, variable_name_size - * is the size of variable name including NULL. - * - * Return: EFI_SUCCESS if parsing is OK, EFI_NOT_FOUND when - * the entire variable list has been returned, - * otherwise non-zero status code - */ -static efi_status_t parse_uboot_variable(char *variable, - efi_uintn_t *variable_name_size, - u16 *variable_name, - const efi_guid_t *vendor, - u32 *attributes) +efi_status_t __efi_runtime +efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, + u16 *variable_name, efi_guid_t *vendor) { - char *guid, *name, *end, c; - size_t name_len; - efi_uintn_t old_variable_name_size; - u64 time; - u16 *p; - - guid = strchr(variable, '_'); - if (!guid) - return EFI_INVALID_PARAMETER; - guid++; - name = strchr(guid, '_'); - if (!name) - return EFI_INVALID_PARAMETER; - name++; - end = strchr(name, '='); - if (!end) - return EFI_INVALID_PARAMETER; - - name_len = end - name; - old_variable_name_size = *variable_name_size; - *variable_name_size = sizeof(u16) * (name_len + 1); - if (old_variable_name_size < *variable_name_size) - return EFI_BUFFER_TOO_SMALL; - - end++; /* point to value */ - - /* variable name */ - p = variable_name; - utf8_utf16_strncpy(&p, name, name_len); - variable_name[name_len] = 0; + struct efi_var_entry *var; + efi_uintn_t old_size; + u16 *pdata; - /* guid */ - c = *(name - 1); - *(name - 1) = '\0'; /* guid need be null-terminated here */ - if (uuid_str_to_bin(guid, (unsigned char *)vendor, - UUID_STR_FORMAT_GUID)) - /* The only error would be EINVAL. */ + if (!variable_name_size || !variable_name || !vendor) return EFI_INVALID_PARAMETER; - *(name - 1) = c; - - /* attributes */ - parse_attr(end, attributes, &time); - return EFI_SUCCESS; -} + efi_var_mem_find(vendor, variable_name, &var); -/** - * efi_get_next_variable_name() - enumerate the current variable names - * - * @variable_name_size: size of variable_name buffer in byte - * @variable_name: name of uefi variable's name in u16 - * @vendor: vendor's guid - * - * This function implements the GetNextVariableName service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * Return: status code - */ -efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, - u16 *variable_name, - efi_guid_t *vendor) -{ - char *native_name, *variable; - ssize_t name_len, list_len; - char regex[256]; - char * const regexlist[] = {regex}; - u32 attributes; - int i; - efi_status_t ret; - - EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor); + if (!var) + return EFI_NOT_FOUND; - if (!variable_name_size || !variable_name || !vendor) - return EFI_EXIT(EFI_INVALID_PARAMETER); - - if (variable_name[0]) { - /* check null-terminated string */ - for (i = 0; i < *variable_name_size; i++) - if (!variable_name[i]) - break; - if (i >= *variable_name_size) - return EFI_EXIT(EFI_INVALID_PARAMETER); - - /* search for the last-returned variable */ - ret = efi_to_native(&native_name, variable_name, vendor); - if (ret) - return EFI_EXIT(ret); - - name_len = strlen(native_name); - for (variable = efi_variables_list; variable && *variable;) { - if (!strncmp(variable, native_name, name_len) && - variable[name_len] == '=') - break; - - variable = strchr(variable, '\n'); - if (variable) - variable++; - } + for (pdata = var->name; *pdata; ++pdata) + ; + ++pdata; - free(native_name); - if (!(variable && *variable)) - return EFI_EXIT(EFI_INVALID_PARAMETER); + old_size = *variable_name_size; + *variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name; - /* next variable */ - variable = strchr(variable, '\n'); - if (variable) - variable++; - if (!(variable && *variable)) - return EFI_EXIT(EFI_NOT_FOUND); - } else { - /* - *new search: free a list used in the previous search - */ - free(efi_variables_list); - efi_variables_list = NULL; - efi_cur_variable = NULL; - - snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*"); - list_len = hexport_r(&env_htab, '\n', - H_MATCH_REGEX | H_MATCH_KEY, - &efi_variables_list, 0, 1, regexlist); - - if (list_len <= 1) - return EFI_EXIT(EFI_NOT_FOUND); - - variable = efi_variables_list; - } + if (old_size < *variable_name_size) + return EFI_BUFFER_TOO_SMALL; - ret = parse_uboot_variable(variable, variable_name_size, variable_name, - vendor, &attributes); + efi_memcpy_runtime(variable_name, var->name, *variable_name_size); + efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t)); - return EFI_EXIT(ret); + return EFI_SUCCESS; } -static efi_status_t efi_set_variable_common(u16 *variable_name, - const efi_guid_t *vendor, - u32 attributes, - efi_uintn_t data_size, - const void *data, - bool ro_check) +efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 attributes, efi_uintn_t data_size, + const void *data, bool ro_check) { - char *native_name = NULL, *old_data = NULL, *val = NULL, *s; - efi_uintn_t old_size; + struct efi_var_entry *var; + efi_uintn_t ret; bool append, delete; u64 time = 0; - u32 attr; - efi_status_t ret = EFI_SUCCESS; + enum efi_auth_var_type var_type; if (!variable_name || !*variable_name || !vendor || ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) && - !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) { - ret = EFI_INVALID_PARAMETER; - goto err; - } - - ret = efi_to_native(&native_name, variable_name, vendor); - if (ret) - goto err; + !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) + return EFI_INVALID_PARAMETER; /* check if a variable exists */ - old_size = 0; - attr = 0; - ret = efi_get_variable_common(variable_name, vendor, &attr, - &old_size, NULL, &time); + var = efi_var_mem_find(vendor, variable_name, NULL); append = !!(attributes & EFI_VARIABLE_APPEND_WRITE); attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE; delete = !append && (!data_size || !attributes); /* check attributes */ - if (old_size) { - if (ro_check && (attr & READ_ONLY)) { - ret = EFI_WRITE_PROTECTED; - goto err; + var_type = efi_auth_var_get_type(variable_name, vendor); + if (var) { + if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY)) + return EFI_WRITE_PROTECTED; + + if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) { + if (var_type != EFI_AUTH_VAR_NONE) + return EFI_WRITE_PROTECTED; } /* attributes won't be changed */ if (!delete && - ((ro_check && attr != attributes) || - (!ro_check && ((attr & ~(u32)READ_ONLY) - != (attributes & ~(u32)READ_ONLY))))) { - ret = EFI_INVALID_PARAMETER; - goto err; + ((ro_check && var->attr != attributes) || + (!ro_check && ((var->attr & ~(u32)EFI_VARIABLE_READ_ONLY) + != (attributes & ~(u32)EFI_VARIABLE_READ_ONLY))))) { + return EFI_INVALID_PARAMETER; } + time = var->time; } else { - if (delete || append) { + if (delete || append) /* * Trying to delete or to update a non-existent * variable. */ - ret = EFI_NOT_FOUND; - goto err; - } + return EFI_NOT_FOUND; } - if (((!u16_strcmp(variable_name, L"PK") || - !u16_strcmp(variable_name, L"KEK")) && - !guidcmp(vendor, &efi_global_variable_guid)) || - ((!u16_strcmp(variable_name, L"db") || - !u16_strcmp(variable_name, L"dbx")) && - !guidcmp(vendor, &efi_guid_image_security_database))) { + if (var_type != EFI_AUTH_VAR_NONE) { /* authentication is mandatory */ if (!(attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { - EFI_PRINT("%ls: AUTHENTICATED_WRITE_ACCESS required\n", + EFI_PRINT("%ls: TIME_BASED_AUTHENTICATED_WRITE_ACCESS required\n", variable_name); - ret = EFI_INVALID_PARAMETER; - goto err; + return EFI_INVALID_PARAMETER; } } /* authenticate a variable */ if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) { - if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { - ret = EFI_INVALID_PARAMETER; - goto err; - } + if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) + return EFI_INVALID_PARAMETER; if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { + u32 env_attr; + ret = efi_variable_authenticate(variable_name, vendor, &data_size, &data, - attributes, &attr, + attributes, &env_attr, &time); if (ret != EFI_SUCCESS) - goto err; + return ret; /* last chance to check for delete */ if (!data_size) @@ -981,168 +429,61 @@ static efi_status_t efi_set_variable_common(u16 *variable_name, (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { EFI_PRINT("Secure boot is not configured\n"); - ret = EFI_INVALID_PARAMETER; - goto err; + return EFI_INVALID_PARAMETER; } } - /* delete a variable */ if (delete) { - /* !old_size case has been handled before */ - val = NULL; + /* EFI_NOT_FOUND has been handled before */ ret = EFI_SUCCESS; - goto out; - } - - if (append) { - old_data = malloc(old_size); - if (!old_data) { - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - ret = efi_get_variable_common(variable_name, vendor, - &attr, &old_size, old_data, NULL); - if (ret != EFI_SUCCESS) - goto err; + } else if (append) { + u16 *old_data = var->name; + + for (; *old_data; ++old_data) + ; + ++old_data; + ret = efi_var_mem_ins(variable_name, vendor, attributes, + var->length, old_data, data_size, data, + time); } else { - old_size = 0; - } - - val = malloc(2 * old_size + 2 * data_size - + strlen("{ro,run,boot,nv,time=0123456701234567}(blob)") - + 1); - if (!val) { - ret = EFI_OUT_OF_RESOURCES; - goto err; - } - - s = val; - - /* - * store attributes - */ - attributes &= (READ_ONLY | - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS | - EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS); - s += sprintf(s, "{"); - while (attributes) { - attr = 1 << (ffs(attributes) - 1); - - if (attr == READ_ONLY) { - s += sprintf(s, "ro"); - } else if (attr == EFI_VARIABLE_NON_VOLATILE) { - s += sprintf(s, "nv"); - } else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) { - s += sprintf(s, "boot"); - } else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) { - s += sprintf(s, "run"); - } else if (attr == - EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { - s += sprintf(s, "time="); - s = bin2hex(s, (u8 *)&time, sizeof(time)); - } - - attributes &= ~attr; - if (attributes) - s += sprintf(s, ","); + ret = efi_var_mem_ins(variable_name, vendor, attributes, + data_size, data, 0, NULL, time); } - s += sprintf(s, "}"); - s += sprintf(s, "(blob)"); - - /* store payload: */ - if (append) - s = bin2hex(s, old_data, old_size); - s = bin2hex(s, data, data_size); - *s = '\0'; - - EFI_PRINT("setting: %s=%s\n", native_name, val); + efi_var_mem_del(var); -out: - if (env_set(native_name, val)) { - ret = EFI_DEVICE_ERROR; - } else { - bool vendor_keys_modified = false; - - if ((u16_strcmp(variable_name, L"PK") == 0 && - guidcmp(vendor, &efi_global_variable_guid) == 0)) { - ret = efi_transfer_secure_state( - (delete ? EFI_MODE_SETUP : - EFI_MODE_USER)); - if (ret != EFI_SUCCESS) - goto err; - - if (efi_secure_mode != EFI_MODE_SETUP) - vendor_keys_modified = true; - } else if ((u16_strcmp(variable_name, L"KEK") == 0 && - guidcmp(vendor, &efi_global_variable_guid) == 0)) { - if (efi_secure_mode != EFI_MODE_SETUP) - vendor_keys_modified = true; - } + if (ret != EFI_SUCCESS) + return ret; - /* update VendorKeys */ - if (vendor_keys_modified & efi_vendor_keys) { - efi_vendor_keys = 0; - ret = efi_set_variable_common( - L"VendorKeys", - &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_RUNTIME_ACCESS - | READ_ONLY, - sizeof(efi_vendor_keys), - &efi_vendor_keys, - false); - } else { - ret = EFI_SUCCESS; - } - } + if (var_type == EFI_AUTH_VAR_PK) + ret = efi_init_secure_state(); + else + ret = EFI_SUCCESS; -err: - free(native_name); - free(old_data); - free(val); + /* Write non-volatile EFI variables to file */ + if (attributes & EFI_VARIABLE_NON_VOLATILE && + ret == EFI_SUCCESS && efi_obj_list_initialized == EFI_SUCCESS) + efi_var_to_file(); - return ret; + return EFI_SUCCESS; } -/** - * efi_set_variable() - set value of a UEFI variable - * - * This function implements the SetVariable runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @variable_name: name of the variable - * @vendor: vendor GUID - * @attributes: attributes of the variable - * @data_size: size of the buffer with the variable value - * @data: buffer with the variable value - * Return: status code - */ -efi_status_t EFIAPI efi_set_variable(u16 *variable_name, - const efi_guid_t *vendor, u32 attributes, - efi_uintn_t data_size, const void *data) +efi_status_t efi_query_variable_info_int(u32 attributes, + u64 *maximum_variable_storage_size, + u64 *remaining_variable_storage_size, + u64 *maximum_variable_size) { - EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes, - data_size, data); - - /* READ_ONLY bit is not part of API */ - attributes &= ~(u32)READ_ONLY; - - return EFI_EXIT(efi_set_variable_common(variable_name, vendor, - attributes, data_size, data, - true)); + *maximum_variable_storage_size = EFI_VAR_BUF_SIZE - + sizeof(struct efi_var_file); + *remaining_variable_storage_size = efi_var_mem_free(); + *maximum_variable_size = EFI_VAR_BUF_SIZE - + sizeof(struct efi_var_file) - + sizeof(struct efi_var_entry); + return EFI_SUCCESS; } /** - * efi_query_variable_info() - get information about EFI variables - * - * This function implements the QueryVariableInfo() runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. + * efi_query_variable_info_runtime() - runtime implementation of + * QueryVariableInfo() * * @attributes: bitmask to select variables to be * queried @@ -1154,7 +495,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, * selected type * Returns: status code */ -efi_status_t __efi_runtime EFIAPI efi_query_variable_info( +efi_status_t __efi_runtime EFIAPI efi_query_variable_info_runtime( u32 attributes, u64 *maximum_variable_storage_size, u64 *remaining_variable_storage_size, @@ -1177,7 +518,16 @@ static efi_status_t __efi_runtime EFIAPI efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data) { - return EFI_UNSUPPORTED; + efi_status_t ret; + + ret = efi_get_variable_int(variable_name, vendor, attributes, + data_size, data, NULL); + + /* Remove EFI_VARIABLE_READ_ONLY flag */ + if (attributes) + *attributes &= EFI_VARIABLE_MASK; + + return ret; } /** @@ -1193,7 +543,8 @@ static efi_status_t __efi_runtime EFIAPI efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *vendor) { - return EFI_UNSUPPORTED; + return efi_get_next_variable_name_int(variable_name_size, variable_name, + vendor); } /** @@ -1219,10 +570,13 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor, */ void efi_variables_boot_exit_notify(void) { + /* Switch variable services functions to runtime version */ efi_runtime_services.get_variable = efi_get_variable_runtime; efi_runtime_services.get_next_variable_name = efi_get_next_variable_name_runtime; efi_runtime_services.set_variable = efi_set_variable_runtime; + efi_runtime_services.query_variable_info = + efi_query_variable_info_runtime; efi_update_table_header_crc32(&efi_runtime_services.hdr); } @@ -1235,7 +589,20 @@ efi_status_t efi_init_variables(void) { efi_status_t ret; + ret = efi_var_mem_init(); + if (ret != EFI_SUCCESS) + return ret; + ret = efi_init_secure_state(); + if (ret != EFI_SUCCESS) + return ret; - return ret; + if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) { + ret = efi_var_restore((struct efi_var_file *) + __efi_var_file_begin); + if (ret != EFI_SUCCESS) + log_err("Invalid EFI variable seed\n"); + } + + return efi_var_from_file(); } diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index cacc76e23d..c042348938 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -10,6 +10,7 @@ #include <efi.h> #include <efi_api.h> #include <efi_loader.h> +#include <efi_variable.h> #include <tee.h> #include <malloc.h> #include <mm_communication.h> @@ -243,25 +244,92 @@ out: return ret; } -/** - * efi_get_variable() - retrieve value of a UEFI variable - * - * This function implements the GetVariable runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @name: name of the variable - * @guid: vendor GUID - * @attr: attributes of the variable - * @data_size: size of the buffer to which the variable value is copied - * @data: buffer to which the variable value is copied - * Return: status code +/* + * StMM can store internal attributes and properties for variables, i.e enabling + * R/O variables */ -efi_status_t EFIAPI efi_get_variable(u16 *name, const efi_guid_t *guid, - u32 *attr, efi_uintn_t *data_size, - void *data) +static efi_status_t set_property_int(u16 *variable_name, efi_uintn_t name_size, + const efi_guid_t *vendor, + struct var_check_property *var_property) +{ + struct smm_variable_var_check_property *smm_property; + efi_uintn_t payload_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + payload_size = sizeof(*smm_property) + name_size; + if (payload_size > max_payload_size) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + comm_buf = setup_mm_hdr((void **)&smm_property, payload_size, + SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET, + &ret); + if (!comm_buf) + goto out; + + guidcpy(&smm_property->guid, vendor); + smm_property->name_size = name_size; + memcpy(&smm_property->property, var_property, + sizeof(smm_property->property)); + memcpy(smm_property->name, variable_name, name_size); + + ret = mm_communicate(comm_buf, payload_size); + +out: + free(comm_buf); + return ret; +} + +static efi_status_t get_property_int(u16 *variable_name, efi_uintn_t name_size, + const efi_guid_t *vendor, + struct var_check_property *var_property) +{ + struct smm_variable_var_check_property *smm_property; + efi_uintn_t payload_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + memset(var_property, 0, sizeof(*var_property)); + payload_size = sizeof(*smm_property) + name_size; + if (payload_size > max_payload_size) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + comm_buf = setup_mm_hdr((void **)&smm_property, payload_size, + SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, + &ret); + if (!comm_buf) + goto out; + + guidcpy(&smm_property->guid, vendor); + smm_property->name_size = name_size; + memcpy(smm_property->name, variable_name, name_size); + + ret = mm_communicate(comm_buf, payload_size); + /* + * Currently only R/O property is supported in StMM. + * Variables that are not set to R/O will not set the property in StMM + * and the call will return EFI_NOT_FOUND. We are setting the + * properties to 0x0 so checking against that is enough for the + * EFI_NOT_FOUND case. + */ + if (ret == EFI_NOT_FOUND) + ret = EFI_SUCCESS; + if (ret != EFI_SUCCESS) + goto out; + memcpy(var_property, &smm_property->property, sizeof(*var_property)); + +out: + free(comm_buf); + return ret; +} + +efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 *attributes, efi_uintn_t *data_size, + void *data, u64 *timep) { + struct var_check_property var_property; struct smm_variable_access *var_acc; efi_uintn_t payload_size; efi_uintn_t name_size; @@ -269,15 +337,13 @@ efi_status_t EFIAPI efi_get_variable(u16 *name, const efi_guid_t *guid, u8 *comm_buf = NULL; efi_status_t ret; - EFI_ENTRY("\"%ls\" %pUl %p %p %p", name, guid, attr, data_size, data); - - if (!name || !guid || !data_size) { + if (!variable_name || !vendor || !data_size) { ret = EFI_INVALID_PARAMETER; goto out; } /* Check payload size */ - name_size = u16_strsize(name); + name_size = u16_strsize(variable_name); if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) { ret = EFI_INVALID_PARAMETER; goto out; @@ -300,11 +366,11 @@ efi_status_t EFIAPI efi_get_variable(u16 *name, const efi_guid_t *guid, goto out; /* Fill in contents */ - guidcpy(&var_acc->guid, guid); + guidcpy(&var_acc->guid, vendor); var_acc->data_size = tmp_dsize; var_acc->name_size = name_size; - var_acc->attr = attr ? *attr : 0; - memcpy(var_acc->name, name, name_size); + var_acc->attr = attributes ? *attributes : 0; + memcpy(var_acc->name, variable_name, name_size); /* Communicate */ ret = mm_communicate(comm_buf, payload_size); @@ -315,8 +381,16 @@ efi_status_t EFIAPI efi_get_variable(u16 *name, const efi_guid_t *guid, if (ret != EFI_SUCCESS) goto out; - if (attr) - *attr = var_acc->attr; + ret = get_property_int(variable_name, name_size, vendor, &var_property); + if (ret != EFI_SUCCESS) + goto out; + + if (attributes) { + *attributes = var_acc->attr; + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) + *attributes |= EFI_VARIABLE_READ_ONLY; + } + if (data) memcpy(data, (u8 *)var_acc->name + var_acc->name_size, var_acc->data_size); @@ -325,38 +399,21 @@ efi_status_t EFIAPI efi_get_variable(u16 *name, const efi_guid_t *guid, out: free(comm_buf); - return EFI_EXIT(ret); + return ret; } -/** - * efi_get_next_variable_name() - enumerate the current variable names - * - * @variable_name_size: size of variable_name buffer in bytes - * @variable_name: name of uefi variable's name in u16 - * @guid: vendor's guid - * - * This function implements the GetNextVariableName service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * Return: status code - */ -efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, - u16 *variable_name, - efi_guid_t *guid) +efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, + u16 *variable_name, + efi_guid_t *guid) { struct smm_variable_getnext *var_getnext; efi_uintn_t payload_size; efi_uintn_t out_name_size; efi_uintn_t in_name_size; efi_uintn_t tmp_dsize; - efi_uintn_t name_size; u8 *comm_buf = NULL; efi_status_t ret; - EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, guid); - if (!variable_name_size || !variable_name || !guid) { ret = EFI_INVALID_PARAMETER; goto out; @@ -370,19 +427,18 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, goto out; } - name_size = u16_strsize(variable_name); - if (name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) { + if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) { ret = EFI_INVALID_PARAMETER; goto out; } /* Trim output buffer size */ tmp_dsize = *variable_name_size; - if (name_size + tmp_dsize > + if (in_name_size + tmp_dsize > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) { tmp_dsize = max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE - - name_size; + in_name_size; } payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size; @@ -414,37 +470,22 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, out: free(comm_buf); - return EFI_EXIT(ret); + return ret; } -/** - * efi_set_variable() - set value of a UEFI variable - * - * This function implements the SetVariable runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @name: name of the variable - * @guid: vendor GUID - * @attr: attributes of the variable - * @data_size: size of the buffer with the variable value - * @data: buffer with the variable value - * Return: status code - */ -efi_status_t EFIAPI efi_set_variable(u16 *name, const efi_guid_t *guid, - u32 attr, efi_uintn_t data_size, - const void *data) +efi_status_t efi_set_variable_int(u16 *variable_name, const efi_guid_t *vendor, + u32 attributes, efi_uintn_t data_size, + const void *data, bool ro_check) { + efi_status_t ret, alt_ret = EFI_SUCCESS; + struct var_check_property var_property; struct smm_variable_access *var_acc; efi_uintn_t payload_size; efi_uintn_t name_size; u8 *comm_buf = NULL; - efi_status_t ret; + bool ro; - EFI_ENTRY("\"%ls\" %pUl %x %zu %p", name, guid, attr, data_size, data); - - if (!name || name[0] == 0 || !guid) { + if (!variable_name || variable_name[0] == 0 || !vendor) { ret = EFI_INVALID_PARAMETER; goto out; } @@ -452,68 +493,91 @@ efi_status_t EFIAPI efi_set_variable(u16 *name, const efi_guid_t *guid, ret = EFI_INVALID_PARAMETER; goto out; } - /* Check payload size */ - name_size = u16_strsize(name); + name_size = u16_strsize(variable_name); payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size; if (payload_size > max_payload_size) { ret = EFI_INVALID_PARAMETER; goto out; } - /* Get communication buffer and initialize header */ + /* + * Allocate the buffer early, before switching to RW (if needed) + * so we won't need to account for any failures in reading/setting + * the properties, if the allocation fails + */ comm_buf = setup_mm_hdr((void **)&var_acc, payload_size, SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); if (!comm_buf) goto out; + ro = !!(attributes & EFI_VARIABLE_READ_ONLY); + attributes &= EFI_VARIABLE_MASK; + + /* + * The API has the ability to override RO flags. If no RO check was + * requested switch the variable to RW for the duration of this call + */ + ret = get_property_int(variable_name, name_size, vendor, + &var_property); + if (ret != EFI_SUCCESS) + goto out; + + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) { + /* Bypass r/o check */ + if (!ro_check) { + var_property.property &= ~VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY; + ret = set_property_int(variable_name, name_size, vendor, &var_property); + if (ret != EFI_SUCCESS) + goto out; + } else { + ret = EFI_WRITE_PROTECTED; + goto out; + } + } + /* Fill in contents */ - guidcpy(&var_acc->guid, guid); + guidcpy(&var_acc->guid, vendor); var_acc->data_size = data_size; var_acc->name_size = name_size; - var_acc->attr = attr; - memcpy(var_acc->name, name, name_size); + var_acc->attr = attributes; + memcpy(var_acc->name, variable_name, name_size); memcpy((u8 *)var_acc->name + name_size, data, data_size); /* Communicate */ ret = mm_communicate(comm_buf, payload_size); + if (ret != EFI_SUCCESS) + alt_ret = ret; + + if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) { + var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION; + var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY; + var_property.attributes = attributes; + var_property.minsize = 1; + var_property.maxsize = var_acc->data_size; + ret = set_property_int(variable_name, name_size, vendor, &var_property); + } + if (alt_ret != EFI_SUCCESS) + goto out; + + if (!u16_strcmp(variable_name, L"PK")) + alt_ret = efi_init_secure_state(); out: free(comm_buf); - return EFI_EXIT(ret); + return alt_ret == EFI_SUCCESS ? ret : alt_ret; } -/** - * efi_query_variable_info() - get information about EFI variables - * - * This function implements the QueryVariableInfo() runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @attributes: bitmask to select variables to be - * queried - * @maximum_variable_storage_size: maximum size of storage area for the - * selected variable types - * @remaining_variable_storage_size: remaining size of storage are for the - * selected variable types - * @maximum_variable_size: maximum size of a variable of the - * selected type - * Returns: status code - */ -efi_status_t EFIAPI __efi_runtime -efi_query_variable_info(u32 attributes, u64 *max_variable_storage_size, - u64 *remain_variable_storage_size, - u64 *max_variable_size) +efi_status_t efi_query_variable_info_int(u32 attributes, + u64 *max_variable_storage_size, + u64 *remain_variable_storage_size, + u64 *max_variable_size) { struct smm_variable_query_info *mm_query_info; efi_uintn_t payload_size; efi_status_t ret; u8 *comm_buf; - EFI_ENTRY("%x %p %p %p", attributes, max_variable_storage_size, - remain_variable_storage_size, max_variable_size); - payload_size = sizeof(*mm_query_info); comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, @@ -532,7 +596,7 @@ efi_query_variable_info(u32 attributes, u64 *max_variable_storage_size, out: free(comm_buf); - return EFI_EXIT(ret); + return ret; } /** @@ -658,5 +722,9 @@ efi_status_t efi_init_variables(void) MM_VARIABLE_COMMUNICATE_SIZE + max_payload_size; + ret = efi_init_secure_state(); + if (ret != EFI_SUCCESS) + return ret; + return EFI_SUCCESS; } diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c index b3b40ad2cf..3226069c0b 100644 --- a/lib/efi_selftest/efi_selftest_variables_runtime.c +++ b/lib/efi_selftest/efi_selftest_variables_runtime.c @@ -16,9 +16,7 @@ static struct efi_boot_services *boottime; static struct efi_runtime_services *runtime; -static const efi_guid_t guid_vendor0 = - EFI_GUID(0x67029eb5, 0x0af2, 0xf6b1, - 0xda, 0x53, 0xfc, 0xb5, 0x66, 0xdd, 0x1c, 0xe6); +static const efi_guid_t guid_vendor0 = EFI_GLOBAL_VARIABLE_GUID; /* * Setup unit test. @@ -68,17 +66,18 @@ static int execute(void) efi_st_error("SetVariable failed\n"); return EFI_ST_FAILURE; } - len = 3; - ret = runtime->get_variable(L"efi_st_var0", &guid_vendor0, + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"PlatformLangCodes", &guid_vendor0, &attr, &len, data); - if (ret != EFI_UNSUPPORTED) { + if (ret != EFI_SUCCESS) { efi_st_error("GetVariable failed\n"); return EFI_ST_FAILURE; } memset(&guid, 0, 16); *varname = 0; + len = 2 * EFI_ST_MAX_VARNAME_SIZE; ret = runtime->get_next_variable_name(&len, varname, &guid); - if (ret != EFI_UNSUPPORTED) { + if (ret != EFI_SUCCESS) { efi_st_error("GetNextVariableName failed\n"); return EFI_ST_FAILURE; } diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 6c4bbc4625..2057f6819d 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -387,8 +387,8 @@ static int rsa_verify_key(struct image_sign_info *info, * * Return 0 if verified, -ve on error */ -static int rsa_verify_with_pkey(struct image_sign_info *info, - const void *hash, uint8_t *sig, uint sig_len) +int rsa_verify_with_pkey(struct image_sign_info *info, + const void *hash, uint8_t *sig, uint sig_len) { struct key_prop *prop; int ret; @@ -408,8 +408,8 @@ static int rsa_verify_with_pkey(struct image_sign_info *info, return ret; } #else -static int rsa_verify_with_pkey(struct image_sign_info *info, - const void *hash, uint8_t *sig, uint sig_len) +int rsa_verify_with_pkey(struct image_sign_info *info, + const void *hash, uint8_t *sig, uint sig_len) { return -EACCES; } diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index ca40b9beb0..e3bebe94c4 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -312,7 +312,6 @@ CONFIG_DFU_ENV_SETTINGS CONFIG_DHCP_MIN_EXT_LEN CONFIG_DIALOG_POWER CONFIG_DIMM_SLOTS_PER_CTLR -CONFIG_DIRECT_NOR_BOOT CONFIG_DISCONTIGMEM CONFIG_DISCOVER_PHY CONFIG_DISPLAY_AER_xxxx @@ -4150,7 +4149,6 @@ CONFIG_USB_XHCI_EXYNOS CONFIG_USB_XHCI_OMAP CONFIG_USER_LOWLEVEL_INIT CONFIG_USE_INTERRUPT -CONFIG_USE_NOR CONFIG_USE_ONENAND_BOARD_INIT CONFIG_USE_SPIFLASH CONFIG_UTBIPAR_INIT_TBIPA diff --git a/test/py/tests/test_efi_loader.py b/test/py/tests/test_efi_loader.py index 9465c28fbc..7aa422e764 100644 --- a/test/py/tests/test_efi_loader.py +++ b/test/py/tests/test_efi_loader.py @@ -68,8 +68,8 @@ def test_efi_pre_commands(u_boot_console): u_boot_console.run_command('pci enum') @pytest.mark.buildconfigspec('cmd_dhcp') -def test_efi_dhcp(u_boot_console): - """Test the dhcp command. +def test_efi_setup_dhcp(u_boot_console): + """Set up the network using DHCP. The boardenv_* file may be used to enable/disable this test; see the comment at the beginning of this file. @@ -77,7 +77,10 @@ def test_efi_dhcp(u_boot_console): test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False) if not test_dhcp: - pytest.skip('No DHCP server available') + env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None) + if not env_vars: + pytest.skip('No DHCP server available') + return None u_boot_console.run_command('setenv autoload no') output = u_boot_console.run_command('dhcp') @@ -88,7 +91,7 @@ def test_efi_dhcp(u_boot_console): @pytest.mark.buildconfigspec('net') def test_efi_setup_static(u_boot_console): - """Set up a static IP configuration. + """Set up the network using a static IP configuration. The configuration is provided by the boardenv_* file; see the comment at the beginning of this file. @@ -96,7 +99,10 @@ def test_efi_setup_static(u_boot_console): env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None) if not env_vars: - pytest.skip('No static network configuration is defined') + test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False) + if not test_dhcp: + pytest.skip('No static network configuration is defined') + return None for (var, val) in env_vars: u_boot_console.run_command('setenv %s %s' % (var, val)) diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py index ac5a780fdb..c6709700a8 100644 --- a/test/py/tests/test_efi_secboot/conftest.py +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -4,29 +4,32 @@ import os import os.path -import pytest -import re from subprocess import call, check_call, check_output, CalledProcessError +import pytest from defs import * # from test/py/conftest.py + + def tool_is_in_path(tool): for path in os.environ["PATH"].split(os.pathsep): - fn = os.path.join(path, tool) - if os.path.isfile(fn) and os.access(fn, os.X_OK): + full_path = os.path.join(path, tool) + if os.path.isfile(full_path) and os.access(full_path, os.X_OK): return True return False # # Fixture for UEFI secure boot test # + + @pytest.fixture(scope='session') def efi_boot_env(request, u_boot_config): """Set up a file system to be used in UEFI secure boot test. Args: request: Pytest request object. - u_boot_config: U-boot configuration. + u_boot_config: U-boot configuration. Return: A path to disk image to be used for testing @@ -35,34 +38,15 @@ def efi_boot_env(request, u_boot_config): image_path = u_boot_config.persistent_data_dir image_path = image_path + '/' + EFI_SECBOOT_IMAGE_NAME - image_size = EFI_SECBOOT_IMAGE_SIZE - part_size = EFI_SECBOOT_PART_SIZE - fs_type = EFI_SECBOOT_FS_TYPE if HELLO_PATH == '': HELLO_PATH = u_boot_config.build_dir + '/lib/efi_loader/helloworld.efi' try: - mnt_point = u_boot_config.persistent_data_dir + '/mnt_efisecure' + mnt_point = u_boot_config.build_dir + '/mnt_efisecure' + check_call('rm -rf {}'.format(mnt_point), shell=True) check_call('mkdir -p {}'.format(mnt_point), shell=True) - # create a disk/partition - check_call('dd if=/dev/zero of=%s bs=1MiB count=%d' - % (image_path, image_size), shell=True) - check_call('sgdisk %s -n 1:0:+%dMiB' - % (image_path, part_size), shell=True) - # create a file system - check_call('dd if=/dev/zero of=%s.tmp bs=1MiB count=%d' - % (image_path, part_size), shell=True) - check_call('mkfs -t %s %s.tmp' % (fs_type, image_path), shell=True) - check_call('dd if=%s.tmp of=%s bs=1MiB seek=1 count=%d conv=notrunc' - % (image_path, image_path, 1), shell=True) - check_call('rm %s.tmp' % image_path, shell=True) - loop_dev = check_output('sudo losetup -o 1MiB --sizelimit %dMiB --show -f %s | tr -d "\n"' - % (part_size, image_path), shell=True).decode() - check_output('sudo mount -t %s -o umask=000 %s %s' - % (fs_type, loop_dev, mnt_point), shell=True) - # suffix # *.key: RSA private key in PEM # *.crt: X509 certificate (self-signed) in PEM @@ -73,59 +57,80 @@ def efi_boot_env(request, u_boot_config): # *.efi.signed: signed UEFI image # Create signature database - ## PK + # PK check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ -keyout PK.key -out PK.crt -nodes -days 365' - % mnt_point, shell=True) + % mnt_point, shell=True) check_call('cd %s; %scert-to-efi-sig-list -g %s PK.crt PK.esl; %ssign-efi-sig-list -t "2020-04-01" -c PK.crt -k PK.key PK PK.esl PK.auth' - % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), - shell=True) - ## PK_null for deletion + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # PK_null for deletion check_call('cd %s; touch PK_null.esl; %ssign-efi-sig-list -t "2020-04-02" -c PK.crt -k PK.key PK PK_null.esl PK_null.auth' - % (mnt_point, EFITOOLS_PATH), shell=True) - ## KEK + % (mnt_point, EFITOOLS_PATH), shell=True) + # KEK check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ -keyout KEK.key -out KEK.crt -nodes -days 365' - % mnt_point, shell=True) + % mnt_point, shell=True) check_call('cd %s; %scert-to-efi-sig-list -g %s KEK.crt KEK.esl; %ssign-efi-sig-list -t "2020-04-03" -c PK.crt -k PK.key KEK KEK.esl KEK.auth' - % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), - shell=True) - ## db + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # db check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_db/ -keyout db.key -out db.crt -nodes -days 365' - % mnt_point, shell=True) + % mnt_point, shell=True) check_call('cd %s; %scert-to-efi-sig-list -g %s db.crt db.esl; %ssign-efi-sig-list -t "2020-04-04" -c KEK.crt -k KEK.key db db.esl db.auth' - % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), - shell=True) - ## db1 + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # db1 check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_db1/ -keyout db1.key -out db1.crt -nodes -days 365' - % mnt_point, shell=True) + % mnt_point, shell=True) check_call('cd %s; %scert-to-efi-sig-list -g %s db1.crt db1.esl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key db db1.esl db1.auth' - % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), - shell=True) - ## db1-update + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # db1-update check_call('cd %s; %ssign-efi-sig-list -t "2020-04-06" -a -c KEK.crt -k KEK.key db db1.esl db1-update.auth' - % (mnt_point, EFITOOLS_PATH), shell=True) - ## dbx + % (mnt_point, EFITOOLS_PATH), shell=True) + ## dbx (TEST_dbx certificate) check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_dbx/ -keyout dbx.key -out dbx.crt -nodes -days 365' - % mnt_point, shell=True) + % mnt_point, shell=True) check_call('cd %s; %scert-to-efi-sig-list -g %s dbx.crt dbx.esl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx.esl dbx.auth' - % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), - shell=True) + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## dbx_hash (digest of TEST_db certificate) + check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db.crt dbx_hash.crl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx_hash.crl dbx_hash.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## dbx_hash1 (digest of TEST_db1 certificate) + check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db1.crt dbx_hash1.crl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx_hash1.crl dbx_hash1.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## dbx_db (with TEST_db certificate) + check_call('cd %s; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx db.esl dbx_db.auth' + % (mnt_point, EFITOOLS_PATH), + shell=True) # Copy image check_call('cp %s %s' % (HELLO_PATH, mnt_point), shell=True) - ## Sign image + # Sign image check_call('cd %s; sbsign --key db.key --cert db.crt helloworld.efi' - % mnt_point, shell=True) + % mnt_point, shell=True) + ## Sign already-signed image with another key + check_call('cd %s; sbsign --key db1.key --cert db1.crt --output helloworld.efi.signed_2sigs helloworld.efi.signed' + % mnt_point, shell=True) ## Digest image check_call('cd %s; %shash-to-efi-sig-list helloworld.efi db_hello.hash; %ssign-efi-sig-list -t "2020-04-07" -c KEK.crt -k KEK.key db db_hello.hash db_hello.auth' - % (mnt_point, EFITOOLS_PATH, EFITOOLS_PATH), - shell=True) + % (mnt_point, EFITOOLS_PATH, EFITOOLS_PATH), + shell=True) + check_call('cd %s; %shash-to-efi-sig-list helloworld.efi.signed db_hello_signed.hash; %ssign-efi-sig-list -t "2020-04-03" -c KEK.crt -k KEK.key db db_hello_signed.hash db_hello_signed.auth' + % (mnt_point, EFITOOLS_PATH, EFITOOLS_PATH), + shell=True) + check_call('cd %s; %ssign-efi-sig-list -t "2020-04-07" -c KEK.crt -k KEK.key dbx db_hello_signed.hash dbx_hello_signed.auth' + % (mnt_point, EFITOOLS_PATH), + shell=True) - check_call('sudo umount %s' % loop_dev, shell=True) - check_call('sudo losetup -d %s' % loop_dev, shell=True) + check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat {} {}'.format(mnt_point, image_path), shell=True) + check_call('rm -rf {}'.format(mnt_point), shell=True) - except CalledProcessError as e: - pytest.skip('Setup failed: %s' % e.cmd) + except CalledProcessError as exception: + pytest.skip('Setup failed: %s' % exception.cmd) return else: yield image_path diff --git a/test/py/tests/test_efi_secboot/defs.py b/test/py/tests/test_efi_secboot/defs.py index d6222809c5..ba6b9f391e 100644 --- a/test/py/tests/test_efi_secboot/defs.py +++ b/test/py/tests/test_efi_secboot/defs.py @@ -1,21 +1,14 @@ # SPDX-License-Identifier: GPL-2.0+ # Disk image name -EFI_SECBOOT_IMAGE_NAME='test_efi_secboot.img' - -# Size in MiB -EFI_SECBOOT_IMAGE_SIZE=16 -EFI_SECBOOT_PART_SIZE=8 - -# Partition file system type -EFI_SECBOOT_FS_TYPE='vfat' +EFI_SECBOOT_IMAGE_NAME = 'test_efi_secboot.img' # Owner guid -GUID='11111111-2222-3333-4444-123456789abc' +GUID = '11111111-2222-3333-4444-123456789abc' # v1.5.1 or earlier of efitools has a bug in sha256 calculation, and # you need build a newer version on your own. -EFITOOLS_PATH='' +EFITOOLS_PATH = '' # Hello World application for sandbox -HELLO_PATH='' +HELLO_PATH = '' diff --git a/test/py/tests/test_efi_secboot/test_authvar.py b/test/py/tests/test_efi_secboot/test_authvar.py index 148aa3123e..d0c6b9035b 100644 --- a/test/py/tests/test_efi_secboot/test_authvar.py +++ b/test/py/tests/test_efi_secboot/test_authvar.py @@ -9,7 +9,7 @@ This test verifies variable authentication """ import pytest -from defs import * + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('efi_secure_boot') @@ -28,18 +28,18 @@ class TestEfiAuthVar(object): output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, 'printenv -e SecureBoot']) - assert('00000000: 00' in ''.join(output)) + assert '00000000: 00' in ''.join(output) output = u_boot_console.run_command( 'printenv -e SetupMode') - assert('00000000: 01' in output) + assert '00000000: 01' in output with u_boot_console.log.section('Test Case 1b'): # Test Case 1b, PK without AUTHENTICATED_WRITE_ACCESS output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -i 4000000,$filesize PK']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) with u_boot_console.log.section('Test Case 1c'): # Test Case 1c, install PK @@ -47,79 +47,79 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', 'printenv -e -n PK']) - assert('PK:' in ''.join(output)) + assert 'PK:' in ''.join(output) output = u_boot_console.run_command( 'printenv -e SecureBoot') - assert('00000000: 01' in output) + assert '00000000: 01' in output output = u_boot_console.run_command( 'printenv -e SetupMode') - assert('00000000: 00' in output) + assert '00000000: 00' in output with u_boot_console.log.section('Test Case 1d'): # Test Case 1d, db/dbx without KEK output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) with u_boot_console.log.section('Test Case 1e'): # Test Case 1e, install KEK output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 KEK.auth', 'setenv -e -nv -bs -rt -i 4000000,$filesize KEK']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 KEK.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', 'printenv -e -n KEK']) - assert('KEK:' in ''.join(output)) + assert 'KEK:' in ''.join(output) output = u_boot_console.run_command( 'printenv -e SecureBoot') - assert('00000000: 01' in output) + assert '00000000: 01' in output with u_boot_console.log.section('Test Case 1f'): # Test Case 1f, install db output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -i 4000000,$filesize db']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'db:' in ''.join(output) output = u_boot_console.run_command( 'printenv -e SecureBoot') - assert('00000000: 01' in output) + assert '00000000: 01' in output with u_boot_console.log.section('Test Case 1g'): # Test Case 1g, install dbx output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 dbx.auth', 'setenv -e -nv -bs -rt -i 4000000,$filesize dbx']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 dbx.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f dbx']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('dbx:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'dbx:' in ''.join(output) output = u_boot_console.run_command( 'printenv -e SecureBoot') - assert('00000000: 01' in output) + assert '00000000: 01' in output def test_efi_var_auth2(self, u_boot_console, efi_boot_env): """ @@ -138,20 +138,20 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'db:' in ''.join(output) output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db1.auth', 'setenv -e -nv -bs -rt -i 4000000,$filesize db']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) with u_boot_console.log.section('Test Case 2b'): # Test Case 2b, update without correct signature output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db.esl', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) with u_boot_console.log.section('Test Case 2c'): # Test Case 2c, update with correct signature @@ -159,8 +159,8 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 db1.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'db:' in ''.join(output) def test_efi_var_auth3(self, u_boot_console, efi_boot_env): """ @@ -179,20 +179,20 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'db:' in ''.join(output) output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db1.auth', 'setenv -e -nv -bs -rt -a -i 4000000,$filesize db']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) with u_boot_console.log.section('Test Case 3b'): # Test Case 3b, update without correct signature output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db.esl', 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize db']) - assert('Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) with u_boot_console.log.section('Test Case 3c'): # Test Case 3c, update with correct signature @@ -200,8 +200,8 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 db1.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'db:' in ''.join(output) def test_efi_var_auth4(self, u_boot_console, efi_boot_env): """ @@ -220,22 +220,22 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'db:' in ''.join(output) output = u_boot_console.run_command_list([ 'setenv -e -nv -bs -rt db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert('Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) + assert 'db:' in ''.join(output) with u_boot_console.log.section('Test Case 4b'): # Test Case 4b, update without correct signature/data output = u_boot_console.run_command_list([ 'setenv -e -nv -bs -rt -at db', 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) - assert('Failed to set EFI variable' in ''.join(output)) - assert('db:' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) + assert 'db:' in ''.join(output) def test_efi_var_auth5(self, u_boot_console, efi_boot_env): """ @@ -254,15 +254,15 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', 'printenv -e -n PK']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('PK:' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert 'PK:' in ''.join(output) output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 PK_null.esl', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', 'printenv -e -n PK']) - assert('Failed to set EFI variable' in ''.join(output)) - assert('PK:' in ''.join(output)) + assert 'Failed to set EFI variable' in ''.join(output) + assert 'PK:' in ''.join(output) with u_boot_console.log.section('Test Case 5b'): # Test Case 5b, Uninstall PK with correct signature @@ -270,12 +270,12 @@ class TestEfiAuthVar(object): 'fatload host 0:1 4000000 PK_null.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', 'printenv -e -n PK']) - assert(not 'Failed to set EFI variable' in ''.join(output)) - assert('\"PK\" not defined' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) + assert '\"PK\" not defined' in ''.join(output) output = u_boot_console.run_command( 'printenv -e SecureBoot') - assert('00000000: 00' in output) + assert '00000000: 00' in output output = u_boot_console.run_command( 'printenv -e SetupMode') - assert('00000000: 01' in output) + assert '00000000: 01' in output diff --git a/test/py/tests/test_efi_secboot/test_signed.py b/test/py/tests/test_efi_secboot/test_signed.py index 19d78b1b64..7531bbac6a 100644 --- a/test/py/tests/test_efi_secboot/test_signed.py +++ b/test/py/tests/test_efi_secboot/test_signed.py @@ -9,7 +9,7 @@ This test verifies image authentication for signed images. """ import pytest -from defs import * + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('efi_secure_boot') @@ -20,62 +20,80 @@ from defs import * class TestEfiSignedImage(object): def test_efi_signed_image_auth1(self, u_boot_console, efi_boot_env): """ - Test Case 1 - authenticated by db + Test Case 1 - Secure boot is not in force """ u_boot_console.restart_uboot() disk_img = efi_boot_env with u_boot_console.log.section('Test Case 1a'): - # Test Case 1a, run signed image if no db/dbx + # Test Case 1a, run signed image if no PK output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, 'efidebug boot add 1 HELLO1 host 0:1 /helloworld.efi.signed ""', 'efidebug boot next 1', 'bootefi bootmgr']) - assert('Hello, world!' in ''.join(output)) + assert 'Hello, world!' in ''.join(output) with u_boot_console.log.section('Test Case 1b'): - # Test Case 1b, run unsigned image if no db/dbx + # Test Case 1b, run unsigned image if no PK output = u_boot_console.run_command_list([ 'efidebug boot add 2 HELLO2 host 0:1 /helloworld.efi ""', 'efidebug boot next 2', 'bootefi bootmgr']) - assert('Hello, world!' in ''.join(output)) + assert 'Hello, world!' in ''.join(output) - with u_boot_console.log.section('Test Case 1c'): - # Test Case 1c, not authenticated by db + def test_efi_signed_image_auth2(self, u_boot_console, efi_boot_env): + """ + Test Case 2 - Secure boot is in force, + authenticated by db (TEST_db certificate in db) + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 2a'): + # Test Case 2a, db is not yet installed output = u_boot_console.run_command_list([ - 'fatload host 0:1 4000000 db.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'host bind 0 %s' % disk_img, 'fatload host 0:1 4000000 KEK.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) - assert(not 'Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 2', - 'bootefi bootmgr']) - assert('\'HELLO2\' failed' in ''.join(output)) + 'efidebug boot add 1 HELLO1 host 0:1 /helloworld.efi.signed ""', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert('\'HELLO1\' failed' in ''.join(output)) + assert('efi_start_image() returned: 26' in ''.join(output)) output = u_boot_console.run_command_list([ + 'efidebug boot add 2 HELLO2 host 0:1 /helloworld.efi ""', 'efidebug boot next 2', 'efidebug test bootmgr']) - assert('efi_start_image() returned: 26' in ''.join(output)) - assert(not 'Hello, world!' in ''.join(output)) + assert '\'HELLO2\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) - with u_boot_console.log.section('Test Case 1d'): - # Test Case 1d, authenticated by db + with u_boot_console.log.section('Test Case 2b'): + # Test Case 2b, authenticated by db + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ + 'efidebug boot next 2', + 'efidebug test bootmgr']) + assert '\'HELLO2\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot next 1', 'bootefi bootmgr']) - assert('Hello, world!' in ''.join(output)) + assert 'Hello, world!' in ''.join(output) - def test_efi_signed_image_auth2(self, u_boot_console, efi_boot_env): + def test_efi_signed_image_auth3(self, u_boot_console, efi_boot_env): """ - Test Case 2 - rejected by dbx + Test Case 3 - rejected by dbx (TEST_db certificate in dbx) """ u_boot_console.restart_uboot() disk_img = efi_boot_env - with u_boot_console.log.section('Test Case 2a'): - # Test Case 2a, rejected by dbx + with u_boot_console.log.section('Test Case 3a'): + # Test Case 3a, rejected by dbx output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, 'fatload host 0:1 4000000 db.auth', @@ -84,30 +102,148 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) - assert(not 'Failed to set EFI variable' in ''.join(output)) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""', 'efidebug boot next 1', - 'bootefi bootmgr']) - assert('\'HELLO\' failed' in ''.join(output)) + 'efidebug test bootmgr']) + assert '\'HELLO\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + with u_boot_console.log.section('Test Case 3b'): + # Test Case 3b, rejected by dbx even if db allows + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot next 1', 'efidebug test bootmgr']) - assert('efi_start_image() returned: 26' in ''.join(output)) - assert(not 'Hello, world!' in ''.join(output)) + assert '\'HELLO\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) - with u_boot_console.log.section('Test Case 2b'): - # Test Case 2b, rejected by dbx even if db allows + def test_efi_signed_image_auth4(self, u_boot_console, efi_boot_env): + """ + Test Case 4 - revoked by dbx (digest of TEST_db certificate in dbx) + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 4'): + # Test Case 4, rejected by dbx output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 dbx_hash.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', 'fatload host 0:1 4000000 db.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + def test_efi_signed_image_auth5(self, u_boot_console, efi_boot_env): + """ + Test Case 5 - multiple signatures + one signed with TEST_db, and + one signed with TEST_db1 + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 5a'): + # Test Case 5a, rejected if any of signatures is not verified output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + with u_boot_console.log.section('Test Case 5b'): + # Test Case 5b, authenticated if both signatures are verified + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db1.auth', + 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize db']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""', 'efidebug boot next 1', 'bootefi bootmgr']) - assert('\'HELLO\' failed' in ''.join(output)) + assert 'Hello, world!' in ''.join(output) + + with u_boot_console.log.section('Test Case 5c'): + # Test Case 5c, rejected if any of signatures is revoked + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 dbx_hash1.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx']) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""', 'efidebug boot next 1', 'efidebug test bootmgr']) - assert('efi_start_image() returned: 26' in ''.join(output)) - assert(not 'Hello, world!' in ''.join(output)) + assert '\'HELLO\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + def test_efi_signed_image_auth6(self, u_boot_console, efi_boot_env): + """ + Test Case 6 - using digest of signed image in database + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 6a'): + # Test Case 6a, verified by image's digest in db + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 db_hello_signed.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""', + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert 'Hello, world!' in ''.join(output) + + with u_boot_console.log.section('Test Case 6b'): + # Test Case 6b, rejected by TEST_db certificate in dbx + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 dbx_db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + with u_boot_console.log.section('Test Case 6c'): + # Test Case 6c, rejected by image's digest in dbx + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 dbx_hello_signed.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) diff --git a/test/py/tests/test_efi_secboot/test_unsigned.py b/test/py/tests/test_efi_secboot/test_unsigned.py index c42c5ddc47..c4c3f4c202 100644 --- a/test/py/tests/test_efi_secboot/test_unsigned.py +++ b/test/py/tests/test_efi_secboot/test_unsigned.py @@ -9,7 +9,7 @@ This test verifies image authentication for unsigned images. """ import pytest -from defs import * + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('efi_secure_boot') @@ -28,22 +28,22 @@ class TestEfiUnsignedImage(object): # Test Case 1 output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, - 'fatload host 0:1 4000000 KEK.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', - 'fatload host 0:1 4000000 PK.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) - assert(not 'Failed to set EFI variable' in ''.join(output)) + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', 'efidebug boot next 1', 'bootefi bootmgr']) - assert('\'HELLO\' failed' in ''.join(output)) + assert '\'HELLO\' failed' in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot next 1', 'efidebug test bootmgr']) - assert('efi_start_image() returned: 26' in ''.join(output)) - assert(not 'Hello, world!' in ''.join(output)) + assert 'efi_start_image() returned: 26' in ''.join(output) + assert 'Hello, world!' not in ''.join(output) def test_efi_unsigned_image_auth2(self, u_boot_console, efi_boot_env): """ @@ -55,19 +55,19 @@ class TestEfiUnsignedImage(object): # Test Case 2 output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, - 'fatload host 0:1 4000000 db_hello.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', - 'fatload host 0:1 4000000 KEK.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', - 'fatload host 0:1 4000000 PK.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) - assert(not 'Failed to set EFI variable' in ''.join(output)) + 'fatload host 0:1 4000000 db_hello.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', 'efidebug boot next 1', 'bootefi bootmgr']) - assert('Hello, world!' in ''.join(output)) + assert 'Hello, world!' in ''.join(output) def test_efi_unsigned_image_auth3(self, u_boot_console, efi_boot_env): """ @@ -79,39 +79,39 @@ class TestEfiUnsignedImage(object): # Test Case 3a, rejected by dbx output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, - 'fatload host 0:1 4000000 db_hello.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', - 'fatload host 0:1 4000000 KEK.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', - 'fatload host 0:1 4000000 PK.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) - assert(not 'Failed to set EFI variable' in ''.join(output)) + 'fatload host 0:1 4000000 db_hello.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', 'efidebug boot next 1', 'bootefi bootmgr']) - assert('\'HELLO\' failed' in ''.join(output)) + assert '\'HELLO\' failed' in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot next 1', 'efidebug test bootmgr']) - assert('efi_start_image() returned: 26' in ''.join(output)) - assert(not 'Hello, world!' in ''.join(output)) + assert 'efi_start_image() returned: 26' in ''.join(output) + assert 'Hello, world!' not in ''.join(output) with u_boot_console.log.section('Test Case 3b'): # Test Case 3b, rejected by dbx even if db allows output = u_boot_console.run_command_list([ - 'fatload host 0:1 4000000 db_hello.auth', - 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) - assert(not 'Failed to set EFI variable' in ''.join(output)) + 'fatload host 0:1 4000000 db_hello.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) + assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', 'efidebug boot next 1', 'bootefi bootmgr']) - assert('\'HELLO\' failed' in ''.join(output)) + assert '\'HELLO\' failed' in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot next 1', 'efidebug test bootmgr']) - assert('efi_start_image() returned: 26' in ''.join(output)) - assert(not 'Hello, world!' in ''.join(output)) + assert 'efi_start_image() returned: 26' in ''.join(output) + assert 'Hello, world!' not in ''.join(output) |