blob: 747644a06288a8488e14f78f601f2a7d85827846 [file] [log] [blame]
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2014 The ChromiumOS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070014 */
15
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -070016#include <assert.h>
Aaron Durbin0e571fd2015-05-08 17:14:15 -050017#include <cbmem.h>
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070018#include <reset.h>
Aaron Durbinb5a20b22015-10-06 17:29:03 -050019#include <string.h>
20#include <vb2_api.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020021#include <security/vboot/misc.h>
22#include <security/vboot/symbols.h>
23#include <security/vboot/vboot_common.h>
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070024
Aaron Durbinb5933662015-10-07 16:03:41 -050025struct selected_region {
26 uint32_t offset;
27 uint32_t size;
28};
29
Aaron Durbinb5a20b22015-10-06 17:29:03 -050030/*
31 * this is placed at the start of the vboot work buffer. selected_region is used
32 * for the verstage to return the location of the selected slot. buffer is used
Elyes HAOUAS2a600262016-07-30 16:18:46 +020033 * by the vboot2 core. Keep the struct CPU architecture agnostic as it crosses
Aaron Durbinb5a20b22015-10-06 17:29:03 -050034 * stage boundaries.
35 */
36struct vb2_working_data {
Aaron Durbinb5933662015-10-07 16:03:41 -050037 struct selected_region selected_region;
Aaron Durbinb5a20b22015-10-06 17:29:03 -050038 /* offset of the buffer from the start of this struct */
39 uint32_t buffer_offset;
40 uint32_t buffer_size;
41};
42
Aaron Durbin0e571fd2015-05-08 17:14:15 -050043static const size_t vb_work_buf_size = 16 * KiB;
44
Aaron Durbinb5a20b22015-10-06 17:29:03 -050045static struct vb2_working_data * const vboot_get_working_data(void)
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070046{
Julius Wernerfa8fa7d2017-03-16 19:32:48 -070047 if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE))
Aaron Durbin0e571fd2015-05-08 17:14:15 -050048 /* cbmem_add() does a cbmem_find() first. */
49 return cbmem_add(CBMEM_ID_VBOOT_WORKBUF, vb_work_buf_size);
50 else
51 return (struct vb2_working_data *)_vboot2_work;
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070052}
53
Aaron Durbinb5a20b22015-10-06 17:29:03 -050054static size_t vb2_working_data_size(void)
Aaron Durbin1e8be632015-05-08 17:07:04 -050055{
Julius Wernerfa8fa7d2017-03-16 19:32:48 -070056 if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE))
Aaron Durbin0e571fd2015-05-08 17:14:15 -050057 return vb_work_buf_size;
58 else
59 return _vboot2_work_size;
Aaron Durbin1e8be632015-05-08 17:07:04 -050060}
61
Aaron Durbinb5933662015-10-07 16:03:41 -050062static struct selected_region *vb2_selected_region(void)
63{
64 struct selected_region *sel_reg = NULL;
65
Aaron Durbine6dcafb2016-05-24 14:50:45 -050066 /* Ramstage and postcar always uses cbmem as a source of truth. */
67 if (ENV_RAMSTAGE || ENV_POSTCAR)
Aaron Durbinb5933662015-10-07 16:03:41 -050068 sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG);
69 else if (ENV_ROMSTAGE) {
70 /* Try cbmem first. Fall back on working data if not found. */
71 sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG);
72
73 if (sel_reg == NULL) {
74 struct vb2_working_data *wd = vboot_get_working_data();
75 sel_reg = &wd->selected_region;
76 }
77 } else {
78 /* Stages such as bootblock and verstage use working data. */
79 struct vb2_working_data *wd = vboot_get_working_data();
80 sel_reg = &wd->selected_region;
81 }
82
83 return sel_reg;
84}
85
Aaron Durbinb5a20b22015-10-06 17:29:03 -050086void vb2_init_work_context(struct vb2_context *ctx)
Daisuke Nojirie5d13782014-12-18 11:59:06 -080087{
Aaron Durbinb5a20b22015-10-06 17:29:03 -050088 struct vb2_working_data *wd;
89 size_t work_size;
90
91 /* First initialize the working data region. */
92 work_size = vb2_working_data_size();
93 wd = vboot_get_working_data();
94 memset(wd, 0, work_size);
95
96 /*
97 * vboot prefers 16-byte alignment. This takes away 16 bytes
98 * from the VBOOT2_WORK region, but the vboot devs said that's okay.
99 */
100 wd->buffer_offset = ALIGN_UP(sizeof(*wd), 16);
101 wd->buffer_size = work_size - wd->buffer_offset;
102
103 /* Initialize the vb2_context. */
104 memset(ctx, 0, sizeof(*ctx));
105 ctx->workbuf = (void *)vb2_get_shared_data();
106 ctx->workbuf_size = wd->buffer_size;
107
108}
109
110struct vb2_shared_data *vb2_get_shared_data(void)
111{
112 struct vb2_working_data *wd = vboot_get_working_data();
Daisuke Nojirie5d13782014-12-18 11:59:06 -0800113 return (void *)((uintptr_t)wd + wd->buffer_offset);
114}
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500115
Aaron Durbin6d720f32015-12-08 17:00:23 -0600116int vb2_get_selected_region(struct region *region)
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500117{
Aaron Durbinb5933662015-10-07 16:03:41 -0500118 const struct selected_region *reg = vb2_selected_region();
Aaron Durbin6d720f32015-12-08 17:00:23 -0600119
120 if (reg == NULL)
121 return -1;
122
123 if (reg->offset == 0 && reg->size == 0)
124 return -1;
125
126 region->offset = reg->offset;
127 region->size = reg->size;
128
129 return 0;
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500130}
131
Aaron Durbin6d720f32015-12-08 17:00:23 -0600132void vb2_set_selected_region(const struct region *region)
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500133{
Aaron Durbinb5933662015-10-07 16:03:41 -0500134 struct selected_region *reg = vb2_selected_region();
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700135
136 assert(reg != NULL);
137
Aaron Durbin6d720f32015-12-08 17:00:23 -0600138 reg->offset = region_offset(region);
139 reg->size = region_sz(region);
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500140}
141
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700142int vb2_is_slot_selected(void)
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500143{
Aaron Durbinb5933662015-10-07 16:03:41 -0500144 const struct selected_region *reg = vb2_selected_region();
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500145
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700146 assert(reg != NULL);
147
148 return reg->size > 0;
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500149}
Aaron Durbinb5933662015-10-07 16:03:41 -0500150
151void vb2_store_selected_region(void)
152{
153 const struct vb2_working_data *wd;
154 struct selected_region *sel_reg;
155
156 /* Always use the working data in this path since it's the object
157 * which has the result.. */
158 wd = vboot_get_working_data();
159
160 sel_reg = cbmem_add(CBMEM_ID_VBOOT_SEL_REG, sizeof(*sel_reg));
161
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700162 assert(sel_reg != NULL);
163
Aaron Durbinb5933662015-10-07 16:03:41 -0500164 sel_reg->offset = wd->selected_region.offset;
165 sel_reg->size = wd->selected_region.size;
166}
167
168/*
Julius Wernerfa8fa7d2017-03-16 19:32:48 -0700169 * For platforms that employ VBOOT_STARTS_IN_ROMSTAGE, the vboot
Aaron Durbinb5933662015-10-07 16:03:41 -0500170 * verification doesn't happen until after cbmem is brought online.
171 * Therefore, the selected region contents would not be initialized
172 * so don't automatically add results when cbmem comes online.
173 */
Julius Wernerfa8fa7d2017-03-16 19:32:48 -0700174#if !IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)
Aaron Durbinb5933662015-10-07 16:03:41 -0500175static void vb2_store_selected_region_cbmem(int unused)
176{
177 vb2_store_selected_region();
178}
179ROMSTAGE_CBMEM_INIT_HOOK(vb2_store_selected_region_cbmem)
180#endif