blob: 11b461c419f073329d8820741fce24704c25f915 [file] [log] [blame]
Jamie McCrae215345f2023-08-16 07:37:18 +01001/*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2020 Arm Limited
5 * Copyright (c) 2020-2023 Nordic Semiconductor ASA
6 */
7
8#include <assert.h>
9#include <zephyr/kernel.h>
10#include <zephyr/devicetree.h>
11#include <zephyr/drivers/gpio.h>
12#include "bootutil/image.h"
13#include "bootutil_priv.h"
14#include "bootutil/bootutil_log.h"
15#include "bootutil/bootutil_public.h"
16#include "bootutil/fault_injection_hardening.h"
17
18#include "io/io.h"
19#include "mcuboot_config/mcuboot_config.h"
20
21BOOT_LOG_MODULE_DECLARE(mcuboot);
22
23/* Variables passed outside of unit via poiters. */
24static const struct flash_area *_fa_p;
25static struct image_header _hdr = { 0 };
26
27#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) || defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
28/**
29 * Validate hash of a primary boot image.
30 *
31 * @param[in] fa_p flash area pointer
32 * @param[in] hdr boot image header pointer
33 *
34 * @return FIH_SUCCESS on success, error code otherwise
35 */
36fih_ret
37boot_image_validate(const struct flash_area *fa_p,
38 struct image_header *hdr)
39{
40 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
41 FIH_DECLARE(fih_rc, FIH_FAILURE);
42
43 /* NOTE: The first argument to boot_image_validate, for enc_state pointer,
44 * is allowed to be NULL only because the single image loader compiles
45 * with BOOT_IMAGE_NUMBER == 1, which excludes the code that uses
46 * the pointer from compilation.
47 */
48 /* Validate hash */
49 if (IS_ENCRYPTED(hdr))
50 {
51 /* Clear the encrypted flag we didn't supply a key
52 * This flag could be set if there was a decryption in place
53 * was performed. We will try to validate the image, and if still
54 * encrypted the validation will fail, and go in panic mode
55 */
56 hdr->ih_flags &= ~(ENCRYPTIONFLAGS);
57 }
58 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, hdr, fa_p, tmpbuf,
59 BOOT_TMPBUF_SZ, NULL, 0, NULL);
60
61 FIH_RET(fih_rc);
62}
63#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT || MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE*/
64
Jamie McCrae21299732023-12-07 09:41:55 +000065#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
Jamie McCrae215345f2023-08-16 07:37:18 +010066inline static fih_ret
67boot_image_validate_once(const struct flash_area *fa_p,
68 struct image_header *hdr)
69{
70 static struct boot_swap_state state;
71 int rc;
72 FIH_DECLARE(fih_rc, FIH_FAILURE);
73
74 memset(&state, 0, sizeof(struct boot_swap_state));
75 rc = boot_read_swap_state(fa_p, &state);
76 if (rc != 0)
77 FIH_RET(FIH_FAILURE);
78 if (state.magic != BOOT_MAGIC_GOOD
79 || state.image_ok != BOOT_FLAG_SET) {
80 /* At least validate the image once */
81 FIH_CALL(boot_image_validate, fih_rc, fa_p, hdr);
82 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
83 FIH_RET(FIH_FAILURE);
84 }
85 if (state.magic != BOOT_MAGIC_GOOD) {
86 rc = boot_write_magic(fa_p);
87 if (rc != 0)
88 FIH_RET(FIH_FAILURE);
89 }
90 rc = boot_write_image_ok(fa_p);
91 if (rc != 0)
92 FIH_RET(FIH_FAILURE);
93 }
94 FIH_RET(FIH_SUCCESS);
95}
Jamie McCrae21299732023-12-07 09:41:55 +000096#endif
Jamie McCrae215345f2023-08-16 07:37:18 +010097
98/**
99 * Validates that an image in a slot is OK to boot.
100 *
101 * @param[in] slot Slot number to check
102 * @param[out] rsp Parameters for booting image, on success
103 *
104 * @return FIH_SUCCESS on success; non-zero on failure.
105 */
106static fih_ret validate_image_slot(int slot, struct boot_rsp *rsp)
107{
108 int rc = -1;
109 FIH_DECLARE(fih_rc, FIH_FAILURE);
110
111 rc = flash_area_open(slot, &_fa_p);
112 assert(rc == 0);
113
114 rc = boot_image_load_header(_fa_p, &_hdr);
115 if (rc != 0) {
116 goto other;
117 }
118
119#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
120 FIH_CALL(boot_image_validate, fih_rc, _fa_p, &_hdr);
121 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
122 goto other;
123 }
124#elif defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
125 FIH_CALL(boot_image_validate_once, fih_rc, _fa_p, &_hdr);
126 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
127 goto other;
128 }
129#else
130 fih_rc = FIH_SUCCESS;
131#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
132
133 rsp->br_flash_dev_id = flash_area_get_device_id(_fa_p);
134 rsp->br_image_off = flash_area_get_off(_fa_p);
135 rsp->br_hdr = &_hdr;
136
137other:
138 flash_area_close(_fa_p);
139
140 FIH_RET(fih_rc);
141}
142
143/**
144 * Gather information on image and prepare for booting. Will boot from main
145 * image if none of the enabled entrance modes for the firmware loader are set,
146 * otherwise will boot the firmware loader. Note: firmware loader must be a
147 * valid signed image with the same signing key as the application image.
148 *
149 * @param[out] rsp Parameters for booting image, on success
150 *
151 * @return FIH_SUCCESS on success; non-zero on failure.
152 */
153fih_ret
154boot_go(struct boot_rsp *rsp)
155{
156 bool boot_firmware_loader = false;
157 FIH_DECLARE(fih_rc, FIH_FAILURE);
158
159#ifdef CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO
160 if (io_detect_pin() &&
161 !io_boot_skip_serial_recovery()) {
162 boot_firmware_loader = true;
163 }
164#endif
165
166#ifdef CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET
167 if (io_detect_pin_reset()) {
168 boot_firmware_loader = true;
169 }
170#endif
171
172#ifdef CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE
173 if (io_detect_boot_mode()) {
174 boot_firmware_loader = true;
175 }
176#endif
177
178 /* Check if firmware loader button is pressed. TODO: check all entrance methods */
179 if (boot_firmware_loader == true) {
180 FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp);
181
182 if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
183 FIH_RET(fih_rc);
184 }
185 }
186
187 FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_PRIMARY(0), rsp);
188
189#ifdef CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION
190 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
191 FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp);
192 }
193#endif
194
195 FIH_RET(fih_rc);
196}