blob: cfdb82aa6aadb98870c08f2de3a5651bd67ed4ab [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>
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070017#include <cbfs.h>
Aaron Durbin0e571fd2015-05-08 17:14:15 -050018#include <cbmem.h>
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070019#include <console/console.h>
20#include <reset.h>
Aaron Durbinb5a20b22015-10-06 17:29:03 -050021#include <string.h>
22#include <vb2_api.h>
Furquan Shaikh2a12e2e2016-07-25 11:48:03 -070023#include <vboot/misc.h>
24#include <vboot/symbols.h>
25#include <vboot/vboot_common.h>
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070026
Aaron Durbinb5933662015-10-07 16:03:41 -050027struct selected_region {
28 uint32_t offset;
29 uint32_t size;
30};
31
Aaron Durbinb5a20b22015-10-06 17:29:03 -050032/*
33 * this is placed at the start of the vboot work buffer. selected_region is used
34 * for the verstage to return the location of the selected slot. buffer is used
Elyes HAOUAS2a600262016-07-30 16:18:46 +020035 * by the vboot2 core. Keep the struct CPU architecture agnostic as it crosses
Aaron Durbinb5a20b22015-10-06 17:29:03 -050036 * stage boundaries.
37 */
38struct vb2_working_data {
Aaron Durbinb5933662015-10-07 16:03:41 -050039 struct selected_region selected_region;
Aaron Durbinb5a20b22015-10-06 17:29:03 -050040 /* offset of the buffer from the start of this struct */
41 uint32_t buffer_offset;
42 uint32_t buffer_size;
43};
44
Aaron Durbin0e571fd2015-05-08 17:14:15 -050045static const size_t vb_work_buf_size = 16 * KiB;
46
Aaron Durbinb5a20b22015-10-06 17:29:03 -050047static struct vb2_working_data * const vboot_get_working_data(void)
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070048{
Aaron Durbin0e571fd2015-05-08 17:14:15 -050049 if (IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER))
50 /* cbmem_add() does a cbmem_find() first. */
51 return cbmem_add(CBMEM_ID_VBOOT_WORKBUF, vb_work_buf_size);
52 else
53 return (struct vb2_working_data *)_vboot2_work;
Daisuke Nojiri742fc8d2014-10-10 10:51:06 -070054}
55
Aaron Durbinb5a20b22015-10-06 17:29:03 -050056static size_t vb2_working_data_size(void)
Aaron Durbin1e8be632015-05-08 17:07:04 -050057{
Aaron Durbin0e571fd2015-05-08 17:14:15 -050058 if (IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER))
59 return vb_work_buf_size;
60 else
61 return _vboot2_work_size;
Aaron Durbin1e8be632015-05-08 17:07:04 -050062}
63
Aaron Durbinb5933662015-10-07 16:03:41 -050064static struct selected_region *vb2_selected_region(void)
65{
66 struct selected_region *sel_reg = NULL;
67
Aaron Durbine6dcafb2016-05-24 14:50:45 -050068 /* Ramstage and postcar always uses cbmem as a source of truth. */
69 if (ENV_RAMSTAGE || ENV_POSTCAR)
Aaron Durbinb5933662015-10-07 16:03:41 -050070 sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG);
71 else if (ENV_ROMSTAGE) {
72 /* Try cbmem first. Fall back on working data if not found. */
73 sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG);
74
75 if (sel_reg == NULL) {
76 struct vb2_working_data *wd = vboot_get_working_data();
77 sel_reg = &wd->selected_region;
78 }
79 } else {
80 /* Stages such as bootblock and verstage use working data. */
81 struct vb2_working_data *wd = vboot_get_working_data();
82 sel_reg = &wd->selected_region;
83 }
84
85 return sel_reg;
86}
87
Aaron Durbinb5a20b22015-10-06 17:29:03 -050088void vb2_init_work_context(struct vb2_context *ctx)
Daisuke Nojirie5d13782014-12-18 11:59:06 -080089{
Aaron Durbinb5a20b22015-10-06 17:29:03 -050090 struct vb2_working_data *wd;
91 size_t work_size;
92
93 /* First initialize the working data region. */
94 work_size = vb2_working_data_size();
95 wd = vboot_get_working_data();
96 memset(wd, 0, work_size);
97
98 /*
99 * vboot prefers 16-byte alignment. This takes away 16 bytes
100 * from the VBOOT2_WORK region, but the vboot devs said that's okay.
101 */
102 wd->buffer_offset = ALIGN_UP(sizeof(*wd), 16);
103 wd->buffer_size = work_size - wd->buffer_offset;
104
105 /* Initialize the vb2_context. */
106 memset(ctx, 0, sizeof(*ctx));
107 ctx->workbuf = (void *)vb2_get_shared_data();
108 ctx->workbuf_size = wd->buffer_size;
109
110}
111
112struct vb2_shared_data *vb2_get_shared_data(void)
113{
114 struct vb2_working_data *wd = vboot_get_working_data();
Daisuke Nojirie5d13782014-12-18 11:59:06 -0800115 return (void *)((uintptr_t)wd + wd->buffer_offset);
116}
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500117
Aaron Durbin6d720f32015-12-08 17:00:23 -0600118int vb2_get_selected_region(struct region *region)
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500119{
Aaron Durbinb5933662015-10-07 16:03:41 -0500120 const struct selected_region *reg = vb2_selected_region();
Aaron Durbin6d720f32015-12-08 17:00:23 -0600121
122 if (reg == NULL)
123 return -1;
124
125 if (reg->offset == 0 && reg->size == 0)
126 return -1;
127
128 region->offset = reg->offset;
129 region->size = reg->size;
130
131 return 0;
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500132}
133
Aaron Durbin6d720f32015-12-08 17:00:23 -0600134void vb2_set_selected_region(const struct region *region)
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500135{
Aaron Durbinb5933662015-10-07 16:03:41 -0500136 struct selected_region *reg = vb2_selected_region();
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700137
138 assert(reg != NULL);
139
Aaron Durbin6d720f32015-12-08 17:00:23 -0600140 reg->offset = region_offset(region);
141 reg->size = region_sz(region);
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500142}
143
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700144int vb2_is_slot_selected(void)
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500145{
Aaron Durbinb5933662015-10-07 16:03:41 -0500146 const struct selected_region *reg = vb2_selected_region();
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500147
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700148 assert(reg != NULL);
149
150 return reg->size > 0;
Aaron Durbinb5a20b22015-10-06 17:29:03 -0500151}
Aaron Durbinb5933662015-10-07 16:03:41 -0500152
153void vb2_store_selected_region(void)
154{
155 const struct vb2_working_data *wd;
156 struct selected_region *sel_reg;
157
158 /* Always use the working data in this path since it's the object
159 * which has the result.. */
160 wd = vboot_get_working_data();
161
162 sel_reg = cbmem_add(CBMEM_ID_VBOOT_SEL_REG, sizeof(*sel_reg));
163
Furquan Shaikha6c5ddd2016-07-22 06:59:40 -0700164 assert(sel_reg != NULL);
165
Aaron Durbinb5933662015-10-07 16:03:41 -0500166 sel_reg->offset = wd->selected_region.offset;
167 sel_reg->size = wd->selected_region.size;
168}
169
170/*
171 * For platforms that employ VBOOT_DYNAMIC_WORK_BUFFER, the vboot
172 * verification doesn't happen until after cbmem is brought online.
173 * Therefore, the selected region contents would not be initialized
174 * so don't automatically add results when cbmem comes online.
175 */
176#if !IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER)
177static void vb2_store_selected_region_cbmem(int unused)
178{
179 vb2_store_selected_region();
180}
181ROMSTAGE_CBMEM_INIT_HOOK(vb2_store_selected_region_cbmem)
182#endif