1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
/* SPDX-License-Identifier: GPL-2.0-only */
#include <boot_device.h>
#include <bootstate.h>
#include <commonlib/bsd/ipchksum.h>
#include <stdlib.h>
#include <commonlib/region.h>
#include <console/console.h>
#include <fmap.h>
#include <lib.h>
#include <spi-generic.h>
#include <spi_flash.h>
#include <string.h>
#include "fsp_hob.h"
#include "kti_cache.h"
struct kti_metadata {
uint16_t data_size;
uint16_t data_checksum;
} __packed;
void *kti_cache_load(size_t *size)
{
struct region region;
struct region_device read_rdev;
struct kti_metadata md;
void *data;
uint16_t checksum;
if (fmap_locate_area(CONFIG_KTI_CACHE_FMAP_NAME, ®ion) != 0) {
printk(BIOS_ERR, "Region %s doesn't exist!\n", CONFIG_KTI_CACHE_FMAP_NAME);
return NULL;
}
if (boot_device_ro_subregion(®ion, &read_rdev) < 0)
return NULL;
if (rdev_readat(&read_rdev, &md, 0, sizeof(struct kti_metadata)) < 0) {
printk(BIOS_ERR, "Couldn't read KTI metadata\n");
return NULL;
}
if (md.data_size == 0xFFFF) {
printk(BIOS_INFO, "KTI cache not found!\n");
return NULL;
}
data = rdev_mmap(&read_rdev, sizeof(struct kti_metadata), md.data_size);
if (data == NULL) {
printk(BIOS_ERR, "Map KTI cache failed.\n");
return NULL;
}
checksum = ipchksum(data, md.data_size);
rdev_munmap(&read_rdev, data);
if (checksum != md.data_checksum) {
printk(BIOS_ERR, "KTI cache checksum mismatch: %x vs %x\n", md.data_checksum,
checksum);
return NULL;
}
if (size)
*size = md.data_size;
return data;
}
static void kti_cache_protect(void)
{
struct region region;
if (fmap_locate_area(CONFIG_KTI_CACHE_FMAP_NAME, ®ion) < 0) {
return;
}
if (spi_flash_ctrlr_protect_region(boot_device_spi_flash(), ®ion, WRITE_PROTECT) <
0) {
printk(BIOS_ERR, "Set Flash Protected Range for %s failed.\n",
CONFIG_KTI_CACHE_FMAP_NAME);
return;
}
printk(BIOS_INFO, "Enable Flash Protected Range on %s.\n", CONFIG_KTI_CACHE_FMAP_NAME);
}
static void kti_cache_save(void *unused)
{
size_t kti_data_size;
const void *kti_data;
struct kti_metadata *md;
struct region region;
struct region_device write_rdev;
printk(BIOS_INFO, "Save KTI starts...\n");
kti_data = fsp_hob_get_kti_cache(&kti_data_size);
if (!kti_data) {
printk(BIOS_WARNING, "Couldn't find KTI cache hob!\n");
return;
}
hexdump(kti_data, kti_data_size);
md = malloc(sizeof(struct kti_metadata) + kti_data_size);
if (md == NULL) {
printk(BIOS_ERR, "Allocate KTI metadata failed!\n");
return;
}
memset(md, 0, sizeof(struct kti_metadata));
md->data_size = kti_data_size;
md->data_checksum = ipchksum(kti_data, kti_data_size);
memcpy(md + 1, kti_data, kti_data_size);
if (fmap_locate_area(CONFIG_KTI_CACHE_FMAP_NAME, ®ion) != 0)
goto ret;
if (boot_device_rw_subregion(®ion, &write_rdev) < 0)
goto ret;
if (rdev_eraseat(&write_rdev, 0, region_device_sz(&write_rdev)) < 0) {
printk(BIOS_ERR, "Erase stale KTI cache failed.\n");
goto ret;
}
if (rdev_writeat(&write_rdev, md, 0, sizeof(struct kti_metadata) + kti_data_size) < 0) {
printk(BIOS_ERR, "Write KTI cache failed.\n");
goto ret;
}
kti_cache_protect();
printk(BIOS_INFO, "Save KTI ends.\n");
ret:
free(md);
}
/**
* Ensures kti data is stored into SPI after PCI enumeration is done during
* BS_DEV_ENUMERATE-BS_ON_EXIT and lock down SPI protected ranges during
* BS_DEV_RESOURCES-BS_ON_EXIT.
*/
BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_EXIT, kti_cache_save, NULL);
|