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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This file provides a custom boot media device for the platforms that support additional
* window for BIOS regions greater than 16MiB. If the mainboard uses a smaller BIOS region, then
* the additional window is unused.
*/
#include <boot_device.h>
#include <commonlib/region.h>
#include <console/console.h>
#include <fmap.h>
#include <intelblocks/fast_spi.h>
#include <spi_flash.h>
enum window_type {
/* Fixed decode window of max 16MiB size just below 4G boundary */
FIXED_DECODE_WINDOW,
/* Additional decode window for mapping BIOS region greater than 16MiB */
EXT_BIOS_DECODE_WINDOW,
TOTAL_DECODE_WINDOWS,
};
static struct xlate_region_device real_dev;
static struct mem_region_device shadow_devs[TOTAL_DECODE_WINDOWS];
static struct xlate_window real_dev_windows[TOTAL_DECODE_WINDOWS];
static void initialize_window(enum window_type type, uintptr_t host_base,
uintptr_t flash_base, size_t size)
{
mem_region_device_ro_init(&shadow_devs[type], (void *)host_base, size);
xlate_window_init(&real_dev_windows[type], &shadow_devs[type].rdev,
flash_base, size);
printk(BIOS_INFO, "MMAP window: SPI flash base=0x%lx, Host base=0x%lx, Size=0x%zx\n",
flash_base, host_base, size);
}
/*
*
* +--------------+
* | |
* | |
* | |
* ^ +------------+--------------------------^--------------------------------+ 0xffffffff
* | | | | | |
* | | | | | |
* | | | + | FIXED |
* | | | fixed_win_size | DECODE |
* | | BIOS | + | WINDOW |
* + | region | | | |
* bios_size | (Region 1) | | | |
* + | | | | |
* | | | | | |
* | | | fixed_win_flash_base+----v--------------------------------+ fixed_win_host_base
* | | | | | |
* | | | | | |
* | | | | | Other MMIO |
* v | | | | |
* bios_start +------------+ ext_win_flash_base | | |
* | | + | | |
* | | | | | |
* | | | | | |
* | | | +-----^------------------------------------------------------------^
* 0 +------------+ | | | | |
* | + | EXT_BIOS | |
* SPI flash | ext_win_size | DECODE | |
* address | + | WINDOW | +
* space | | | | CONFIG_EXT_BIOS_WIN_SIZE
* +--------------v-------------------------------+ ext_win_host_base +
* | | |
* | Unused | |
* | | |
* +--------------+ CONFIG_EXT_BIOS_WIN_BASE+--v
* | |
* | |
* | |
* +--------------+
*
* Host address
* space
*/
static void bios_mmap_init(void)
{
static bool init_done;
size_t bios_size, bios_start;
uintptr_t fixed_win_host_base, fixed_win_flash_base;
uintptr_t ext_win_host_base, ext_win_flash_base;
size_t fixed_win_size, ext_win_size;
size_t win_count = 0;
if (init_done)
return;
/* Read the offset and size of BIOS region in the SPI flash address space. */
bios_start = fast_spi_get_bios_region(&bios_size);
/*
* By default, fixed decode window (maximum size 16MiB) is mapped just below the 4G
* boundary. This window maps the top part of the BIOS region in the SPI flash address
* space to the host address space.
*/
fixed_win_size = MIN(16 * MiB, bios_size);
fixed_win_host_base = 4ULL * GiB - fixed_win_size;
fixed_win_flash_base = bios_start + bios_size - fixed_win_size;
initialize_window(FIXED_DECODE_WINDOW, fixed_win_host_base, fixed_win_flash_base,
fixed_win_size);
win_count++;
_Static_assert(CONFIG_EXT_BIOS_WIN_BASE != 0, "Extended BIOS window base cannot be 0!");
_Static_assert(CONFIG_EXT_BIOS_WIN_SIZE != 0, "Extended BIOS window size cannot be 0!");
/*
* Remaining portion of the BIOS region up to a maximum of CONFIG_EXT_BIOS_WIN_SIZE is
* mapped at the top of the extended window if the BIOS region is greater than 16MiB.
*
* If the BIOS region is not greater than 16MiB, then the extended window is not
* enabled.
*/
ext_win_size = MIN(CONFIG_EXT_BIOS_WIN_SIZE, bios_size - fixed_win_size);
if (ext_win_size) {
ext_win_host_base = CONFIG_EXT_BIOS_WIN_BASE + CONFIG_EXT_BIOS_WIN_SIZE -
ext_win_size;
ext_win_flash_base = fixed_win_flash_base - ext_win_size;
initialize_window(EXT_BIOS_DECODE_WINDOW, ext_win_host_base,
ext_win_flash_base, ext_win_size);
win_count++;
}
xlate_region_device_ro_init(&real_dev, win_count, real_dev_windows, CONFIG_ROM_SIZE);
init_done = true;
}
const struct region_device *boot_device_ro(void)
{
bios_mmap_init();
return &real_dev.rdev;
}
void fast_spi_get_ext_bios_window(uintptr_t *base, size_t *size)
{
const struct region_device *rd = &shadow_devs[EXT_BIOS_DECODE_WINDOW].rdev;
bios_mmap_init();
*size = region_device_sz(rd);
if (*size == 0) {
*base = 0;
} else {
/*
* This is a memory region device. So, mmap returns the base address of the
* device. Also, as this is a memory region device, unmap is a no-op.
*/
*base = (uintptr_t)rdev_mmap_full(rd);
}
}
uint32_t spi_flash_get_mmap_windows(struct flash_mmap_window *table)
{
int i;
uint32_t count = 0;
bios_mmap_init();
for (i = 0; i < TOTAL_DECODE_WINDOWS; i++) {
if (region_sz(&real_dev_windows[i].sub_region) == 0)
continue;
count++;
table->flash_base = region_offset(&real_dev_windows[i].sub_region);
table->host_base = (uintptr_t)rdev_mmap_full(&shadow_devs[i].rdev);
table->size = region_sz(&real_dev_windows[i].sub_region);
table++;
}
return count;
}
|