1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /*
4 * This file provides a custom boot media device for the platforms that support additional
5 * window for BIOS regions greater than 16MiB. If the mainboard uses a smaller BIOS region, then
6 * the additional window is unused.
7 */
8
9 #include <boot_device.h>
10 #include <commonlib/region.h>
11 #include <console/console.h>
12 #include <fmap.h>
13 #include <intelblocks/fast_spi.h>
14 #include <spi_flash.h>
15
16 enum window_type {
17 /* Fixed decode window of max 16MiB size just below 4G boundary */
18 FIXED_DECODE_WINDOW,
19 /* Additional decode window for mapping BIOS region greater than 16MiB */
20 EXT_BIOS_DECODE_WINDOW,
21 TOTAL_DECODE_WINDOWS,
22 };
23
24 static struct xlate_region_device real_dev;
25 static struct mem_region_device shadow_devs[TOTAL_DECODE_WINDOWS];
26 static struct xlate_window real_dev_windows[TOTAL_DECODE_WINDOWS];
27
initialize_window(enum window_type type,uintptr_t host_base,uintptr_t flash_base,size_t size)28 static void initialize_window(enum window_type type, uintptr_t host_base,
29 uintptr_t flash_base, size_t size)
30 {
31 mem_region_device_ro_init(&shadow_devs[type], (void *)host_base, size);
32 xlate_window_init(&real_dev_windows[type], &shadow_devs[type].rdev,
33 flash_base, size);
34 printk(BIOS_INFO, "MMAP window: SPI flash base=0x%lx, Host base=0x%lx, Size=0x%zx\n",
35 flash_base, host_base, size);
36 }
37
38 /*
39 *
40 * +--------------+
41 * | |
42 * | |
43 * | |
44 * ^ +------------+--------------------------^--------------------------------+ 0xffffffff
45 * | | | | | |
46 * | | | | | |
47 * | | | + | FIXED |
48 * | | | fixed_win_size | DECODE |
49 * | | BIOS | + | WINDOW |
50 * + | region | | | |
51 * bios_size | (Region 1) | | | |
52 * + | | | | |
53 * | | | | | |
54 * | | | fixed_win_flash_base+----v--------------------------------+ fixed_win_host_base
55 * | | | | | |
56 * | | | | | |
57 * | | | | | Other MMIO |
58 * v | | | | |
59 * bios_start +------------+ ext_win_flash_base | | |
60 * | | + | | |
61 * | | | | | |
62 * | | | | | |
63 * | | | +-----^------------------------------------------------------------^
64 * 0 +------------+ | | | | |
65 * | + | EXT_BIOS | |
66 * SPI flash | ext_win_size | DECODE | |
67 * address | + | WINDOW | +
68 * space | | | | CONFIG_EXT_BIOS_WIN_SIZE
69 * +--------------v-------------------------------+ ext_win_host_base +
70 * | | |
71 * | Unused | |
72 * | | |
73 * +--------------+ CONFIG_EXT_BIOS_WIN_BASE+--v
74 * | |
75 * | |
76 * | |
77 * +--------------+
78 *
79 * Host address
80 * space
81 */
bios_mmap_init(void)82 static void bios_mmap_init(void)
83 {
84 static bool init_done;
85
86 size_t bios_size, bios_start;
87
88 uintptr_t fixed_win_host_base, fixed_win_flash_base;
89 uintptr_t ext_win_host_base, ext_win_flash_base;
90 size_t fixed_win_size, ext_win_size;
91
92 size_t win_count = 0;
93
94 if (init_done)
95 return;
96
97 /* Read the offset and size of BIOS region in the SPI flash address space. */
98 bios_start = fast_spi_get_bios_region(&bios_size);
99
100 /*
101 * By default, fixed decode window (maximum size 16MiB) is mapped just below the 4G
102 * boundary. This window maps the top part of the BIOS region in the SPI flash address
103 * space to the host address space.
104 */
105 fixed_win_size = MIN(16 * MiB, bios_size);
106 fixed_win_host_base = 4ULL * GiB - fixed_win_size;
107 fixed_win_flash_base = bios_start + bios_size - fixed_win_size;
108
109 initialize_window(FIXED_DECODE_WINDOW, fixed_win_host_base, fixed_win_flash_base,
110 fixed_win_size);
111 win_count++;
112
113 _Static_assert(CONFIG_EXT_BIOS_WIN_BASE != 0, "Extended BIOS window base cannot be 0!");
114 _Static_assert(CONFIG_EXT_BIOS_WIN_SIZE != 0, "Extended BIOS window size cannot be 0!");
115
116 /*
117 * Remaining portion of the BIOS region up to a maximum of CONFIG_EXT_BIOS_WIN_SIZE is
118 * mapped at the top of the extended window if the BIOS region is greater than 16MiB.
119 *
120 * If the BIOS region is not greater than 16MiB, then the extended window is not
121 * enabled.
122 */
123 ext_win_size = MIN(CONFIG_EXT_BIOS_WIN_SIZE, bios_size - fixed_win_size);
124
125 if (ext_win_size) {
126 ext_win_host_base = CONFIG_EXT_BIOS_WIN_BASE + CONFIG_EXT_BIOS_WIN_SIZE -
127 ext_win_size;
128 ext_win_flash_base = fixed_win_flash_base - ext_win_size;
129 initialize_window(EXT_BIOS_DECODE_WINDOW, ext_win_host_base,
130 ext_win_flash_base, ext_win_size);
131 win_count++;
132 }
133
134 xlate_region_device_ro_init(&real_dev, win_count, real_dev_windows, CONFIG_ROM_SIZE);
135
136 init_done = true;
137 }
138
boot_device_ro(void)139 const struct region_device *boot_device_ro(void)
140 {
141 bios_mmap_init();
142
143 return &real_dev.rdev;
144 }
145
fast_spi_get_ext_bios_window(uintptr_t * base,size_t * size)146 void fast_spi_get_ext_bios_window(uintptr_t *base, size_t *size)
147 {
148 const struct region_device *rd = &shadow_devs[EXT_BIOS_DECODE_WINDOW].rdev;
149
150 bios_mmap_init();
151
152 *size = region_device_sz(rd);
153
154 if (*size == 0) {
155 *base = 0;
156 } else {
157 /*
158 * This is a memory region device. So, mmap returns the base address of the
159 * device. Also, as this is a memory region device, unmap is a no-op.
160 */
161 *base = (uintptr_t)rdev_mmap_full(rd);
162 }
163 }
164
spi_flash_get_mmap_windows(struct flash_mmap_window * table)165 uint32_t spi_flash_get_mmap_windows(struct flash_mmap_window *table)
166 {
167 int i;
168 uint32_t count = 0;
169
170 bios_mmap_init();
171
172 for (i = 0; i < TOTAL_DECODE_WINDOWS; i++) {
173 if (region_sz(&real_dev_windows[i].sub_region) == 0)
174 continue;
175
176 count++;
177 table->flash_base = region_offset(&real_dev_windows[i].sub_region);
178 table->host_base = (uintptr_t)rdev_mmap_full(&shadow_devs[i].rdev);
179 table->size = region_sz(&real_dev_windows[i].sub_region);
180
181 table++;
182 }
183
184 return count;
185 }
186