blob: 7f432dc3624346acf5cd092b16c5457c1d0618f9 [file] [log] [blame]
J-Alves2f86c1e2022-02-23 18:44:19 +00001/*
2 * Copyright 2022 The Hafnium Authors.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
7 */
8
9#include "hf/sp_pkg.h"
10
11#include <stdint.h>
12
13#include "hf/arch/std.h"
14
15#include "hf/addr.h"
16#include "hf/check.h"
17#include "hf/dlog.h"
18#include "hf/std.h"
19
J-Alves60984ce2022-04-27 15:27:29 +010020/**
21 * Function initializes the Secure Partition Package version 0x1:
22 * - Partition manifest is at offset configured in the package header.
23 * - Image offset expected to be 4kb aligned, and to follow the pm manifest.
24 */
25static bool sp_pkg_init_v1(struct mm_stage1_locked stage1_locked,
26 paddr_t pkg_start, struct sp_pkg_header *header,
27 struct mpool *ppool)
28{
29 size_t manifest_size;
30
31 assert(header != NULL);
32
33 /* Expect DTB to immediately follow header */
34 if (header->pm_offset != sizeof(struct sp_pkg_header)) {
35 dlog_error("Invalid package manifest offset.\n");
36 return false;
37 }
38
39 if ((header->img_offset % PAGE_SIZE) != 0U) {
40 dlog_error("Image offset in SP pkg is not page aligned.\n");
41 return false;
42 }
43
44 manifest_size = align_up(header->pm_size + sizeof(struct sp_pkg_header),
45 PAGE_SIZE);
46
47 /* Check that the pm shouldn't override the image. */
48 if (manifest_size > header->img_offset) {
49 dlog_error("Partition manifest bigger than its region.\n");
50 return false;
51 }
52
53 /*
54 * Map remainder of header + manifest. This assumes that PAGE_SIZE has
55 * been mapped already, prior to calling this function.
56 */
57 if (manifest_size > PAGE_SIZE) {
58 CHECK(mm_identity_map(stage1_locked, pkg_start,
59 pa_add(pkg_start, manifest_size),
60 MM_MODE_R, ppool));
61 }
62
63 return true;
64}
65
J-Alves2f86c1e2022-02-23 18:44:19 +000066/*
J-Alves60984ce2022-04-27 15:27:29 +010067 * Function initializes the Secure Partition Package version 0x2:
J-Alves2f86c1e2022-02-23 18:44:19 +000068 * - Maps whole region up to image such that Hafnium can parse the FF-A manifest
69 * and can use the first chunk of memory for booting purposes.
70 */
J-Alves60984ce2022-04-27 15:27:29 +010071static bool sp_pkg_init_v2(struct mm_stage1_locked stage1_locked,
72 paddr_t pkg_start, struct sp_pkg_header *header,
73 struct mpool *ppool)
74{
75 paddr_t pkg_end = pa_add(pkg_start, PAGE_SIZE);
76
77 assert(header != NULL);
78
79 if (header->pm_offset % PAGE_SIZE != 0 ||
80 header->img_offset % PAGE_SIZE != 0) {
81 dlog_error("SP pkg offsets are not page aligned.\n");
82 return false;
83 }
84
85 if (header->pm_offset > header->img_offset) {
86 dlog_error(
87 "SP pkg offsets must be in order: boot info < "
88 "partition manifest < image offset.\n");
89 return false;
90 }
91
92 /*
93 * Check for overflow and then check the pm shouldn't override the
94 * image.
95 */
96 assert(UINT32_MAX - header->pm_offset >= header->pm_size);
97 if (header->pm_offset + header->pm_size > header->img_offset) {
98 dlog_error("Partition manifest bigger than its region.\n");
99 return false;
100 }
101
102 /*
103 * Remap section up to pm as RW, to allow for writing of boot info
104 * descriptors, if the SP specified boot info in its manifest.
105 */
106 if (header->pm_offset > PAGE_SIZE) {
107 pkg_end = pa_add(pkg_start, header->pm_offset);
108 }
109
110 CHECK(mm_identity_map(stage1_locked, pkg_start, pkg_end,
111 MM_MODE_R | MM_MODE_W, ppool) != NULL);
112
113 /* Map partition manifest as read-only. */
114 CHECK(mm_identity_map(stage1_locked, pkg_end,
115 pa_add(pkg_end, header->pm_size), MM_MODE_R,
116 ppool));
117
118 return true;
119}
120
121/**
122 * Initializes the Secure Partition Package. It relies on helper functions
123 * for the respective versions 1 and 2. Returns true if the initialization goes
124 * well, otherwise returns false.
125 */
J-Alves2f86c1e2022-02-23 18:44:19 +0000126bool sp_pkg_init(struct mm_stage1_locked stage1_locked, paddr_t pkg_start,
127 struct sp_pkg_header *header, struct mpool *ppool)
128{
J-Alves2f86c1e2022-02-23 18:44:19 +0000129 paddr_t pkg_end = pa_add(pkg_start, PAGE_SIZE);
130 void *pkg;
131
132 /* Firstly, map a single page of package header. */
J-Alves60984ce2022-04-27 15:27:29 +0100133 pkg = mm_identity_map(stage1_locked, pkg_start, pkg_end, MM_MODE_R,
134 ppool);
J-Alves2f86c1e2022-02-23 18:44:19 +0000135 assert(pkg != NULL);
136
137 memcpy_s(header, sizeof(struct sp_pkg_header), pkg,
138 sizeof(struct sp_pkg_header));
139
140 if (header->magic != SP_PKG_HEADER_MAGIC) {
141 dlog_error("Invalid package magic.\n");
142 goto exit_unmap;
143 }
144
J-Alves60984ce2022-04-27 15:27:29 +0100145 switch (header->version) {
146 case SP_PKG_HEADER_VERSION_1:
147 if (sp_pkg_init_v1(stage1_locked, pkg_start, header, ppool)) {
148 return true;
149 }
150 break;
151 case SP_PKG_HEADER_VERSION_2:
152 if (sp_pkg_init_v2(stage1_locked, pkg_start, header, ppool)) {
153 return true;
154 }
155 break;
156 default:
157 dlog_error("Unrecognized Partition Pkg format.\n");
J-Alves2f86c1e2022-02-23 18:44:19 +0000158 }
159
J-Alves2f86c1e2022-02-23 18:44:19 +0000160exit_unmap:
J-Alves60984ce2022-04-27 15:27:29 +0100161 CHECK(mm_unmap(stage1_locked, pkg_start, pkg_end, ppool));
J-Alves2f86c1e2022-02-23 18:44:19 +0000162
J-Alves60984ce2022-04-27 15:27:29 +0100163 return false;
J-Alves2f86c1e2022-02-23 18:44:19 +0000164}
165
166/**
167 * Unmap SP Pkg from Hafnium's address space.
168 */
169void sp_pkg_deinit(struct mm_stage1_locked stage1_locked, vaddr_t pkg_start,
170 struct sp_pkg_header *header, struct mpool *ppool)
171{
172 paddr_t to_unmap_end;
173
174 to_unmap_end = pa_from_va(
175 va_add(pkg_start, header->pm_offset + header->pm_size));
176
177 CHECK(mm_unmap(stage1_locked, pa_from_va(pkg_start), to_unmap_end,
178 ppool));
179}