Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright 2016 Google Inc. |
| 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. |
| 14 | */ |
| 15 | |
| 16 | #include <arch/cpu.h> |
| 17 | #include <cbmem.h> |
| 18 | #include <console/console.h> |
Kyösti Mälkki | 140087f | 2016-12-06 14:00:05 +0200 | [diff] [blame] | 19 | #include <cpu/cpu.h> |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 20 | #include <cpu/x86/msr.h> |
| 21 | #include <cpu/x86/mtrr.h> |
| 22 | #include <program_loading.h> |
| 23 | #include <rmodule.h> |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 24 | #include <romstage_handoff.h> |
| 25 | #include <stage_cache.h> |
Subrata Banik | 2847e1e | 2019-02-25 20:31:22 +0530 | [diff] [blame] | 26 | #include <timestamp.h> |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 27 | |
| 28 | static inline void stack_push(struct postcar_frame *pcf, uint32_t val) |
| 29 | { |
| 30 | uint32_t *ptr; |
| 31 | |
| 32 | pcf->stack -= sizeof(val); |
| 33 | ptr = (void *)pcf->stack; |
| 34 | *ptr = val; |
| 35 | } |
| 36 | |
Kyösti Mälkki | 029cebc | 2016-12-02 19:47:07 +0200 | [diff] [blame] | 37 | static void postcar_frame_prepare(struct postcar_frame *pcf) |
| 38 | { |
| 39 | msr_t msr; |
| 40 | msr = rdmsr(MTRR_CAP_MSR); |
| 41 | |
| 42 | pcf->upper_mask = (1 << (cpu_phys_address_size() - 32)) - 1; |
Kyösti Mälkki | a097fb8 | 2017-09-12 10:36:49 +0300 | [diff] [blame] | 43 | pcf->max_var_mtrrs = msr.lo & MTRR_CAP_VCNT; |
| 44 | pcf->num_var_mtrrs = 0; |
Kyösti Mälkki | 029cebc | 2016-12-02 19:47:07 +0200 | [diff] [blame] | 45 | } |
| 46 | |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 47 | int postcar_frame_init(struct postcar_frame *pcf, size_t stack_size) |
| 48 | { |
| 49 | void *stack; |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 50 | |
Kyösti Mälkki | 6e2d0c1 | 2019-06-28 10:08:51 +0300 | [diff] [blame] | 51 | /* |
| 52 | * Use default postcar stack size of 4 KiB. This value should |
| 53 | * not be decreased, because if mainboards use vboot, 1 KiB will |
| 54 | * not be enough anymore. |
| 55 | */ |
| 56 | |
| 57 | if (stack_size == 0) |
| 58 | stack_size = 4 * KiB; |
| 59 | |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 60 | stack = cbmem_add(CBMEM_ID_ROMSTAGE_RAM_STACK, stack_size); |
| 61 | if (stack == NULL) { |
| 62 | printk(BIOS_ERR, "Couldn't add %zd byte stack in cbmem.\n", |
| 63 | stack_size); |
| 64 | return -1; |
| 65 | } |
| 66 | |
Kyösti Mälkki | 029cebc | 2016-12-02 19:47:07 +0200 | [diff] [blame] | 67 | postcar_frame_prepare(pcf); |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 68 | pcf->stack = (uintptr_t)stack; |
| 69 | pcf->stack += stack_size; |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 70 | return 0; |
| 71 | } |
| 72 | |
| 73 | void postcar_frame_add_mtrr(struct postcar_frame *pcf, |
| 74 | uintptr_t addr, size_t size, int type) |
| 75 | { |
Rizwan Qureshi | e8c2e83 | 2016-09-07 20:18:17 +0530 | [diff] [blame] | 76 | /* |
| 77 | * Utilize additional MTRRs if the specified size is greater than the |
| 78 | * base address alignment. |
| 79 | */ |
| 80 | while (size != 0) { |
| 81 | uint32_t addr_lsb; |
| 82 | uint32_t size_msb; |
| 83 | uint32_t mtrr_size; |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 84 | |
Kyösti Mälkki | a097fb8 | 2017-09-12 10:36:49 +0300 | [diff] [blame] | 85 | if (pcf->num_var_mtrrs >= pcf->max_var_mtrrs) { |
Rizwan Qureshi | e8c2e83 | 2016-09-07 20:18:17 +0530 | [diff] [blame] | 86 | printk(BIOS_ERR, "No more variable MTRRs: %d\n", |
Kyösti Mälkki | a097fb8 | 2017-09-12 10:36:49 +0300 | [diff] [blame] | 87 | pcf->max_var_mtrrs); |
Rizwan Qureshi | e8c2e83 | 2016-09-07 20:18:17 +0530 | [diff] [blame] | 88 | return; |
| 89 | } |
| 90 | |
| 91 | addr_lsb = fls(addr); |
| 92 | size_msb = fms(size); |
| 93 | |
| 94 | /* All MTRR entries need to have their base aligned to the mask |
| 95 | * size. The maximum size is calculated by a function of the |
| 96 | * min base bit set and maximum size bit set. */ |
| 97 | if (addr_lsb > size_msb) |
| 98 | mtrr_size = 1 << size_msb; |
| 99 | else |
| 100 | mtrr_size = 1 << addr_lsb; |
| 101 | |
| 102 | printk(BIOS_DEBUG, "MTRR Range: Start=%lx End=%lx (Size %x)\n", |
| 103 | addr, addr + mtrr_size, mtrr_size); |
| 104 | |
| 105 | stack_push(pcf, pcf->upper_mask); |
| 106 | stack_push(pcf, ~(mtrr_size - 1) | MTRR_PHYS_MASK_VALID); |
| 107 | stack_push(pcf, 0); |
| 108 | stack_push(pcf, addr | type); |
Kyösti Mälkki | a097fb8 | 2017-09-12 10:36:49 +0300 | [diff] [blame] | 109 | pcf->num_var_mtrrs++; |
Rizwan Qureshi | e8c2e83 | 2016-09-07 20:18:17 +0530 | [diff] [blame] | 110 | |
| 111 | size -= mtrr_size; |
| 112 | addr += mtrr_size; |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 113 | } |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 114 | } |
| 115 | |
Nico Huber | 36ec3e9 | 2018-05-27 14:32:27 +0200 | [diff] [blame] | 116 | void postcar_frame_add_romcache(struct postcar_frame *pcf, int type) |
| 117 | { |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 118 | if (!CONFIG(BOOT_DEVICE_MEMORY_MAPPED)) |
Nico Huber | 36ec3e9 | 2018-05-27 14:32:27 +0200 | [diff] [blame] | 119 | return; |
| 120 | postcar_frame_add_mtrr(pcf, CACHE_ROM_BASE, CACHE_ROM_SIZE, type); |
| 121 | } |
| 122 | |
Kyösti Mälkki | 544878b | 2019-08-09 11:41:15 +0300 | [diff] [blame] | 123 | void postcar_frame_common_mtrrs(struct postcar_frame *pcf) |
| 124 | { |
| 125 | if (pcf->skip_common_mtrr) |
| 126 | return; |
| 127 | |
| 128 | /* Cache RAM as WB from 0 -> CACHE_TMP_RAMTOP. */ |
| 129 | postcar_frame_add_mtrr(pcf, 0, CACHE_TMP_RAMTOP, MTRR_TYPE_WRBACK); |
| 130 | |
| 131 | /* Cache the ROM as WP just below 4GiB. */ |
| 132 | postcar_frame_add_romcache(pcf, MTRR_TYPE_WRPROT); |
| 133 | } |
| 134 | |
Rizwan Qureshi | b1b44d3 | 2016-08-26 21:08:50 +0530 | [diff] [blame] | 135 | void *postcar_commit_mtrrs(struct postcar_frame *pcf) |
| 136 | { |
| 137 | /* |
| 138 | * Place the number of used variable MTRRs on stack then max number |
| 139 | * of variable MTRRs supported in the system. |
| 140 | */ |
Kyösti Mälkki | a097fb8 | 2017-09-12 10:36:49 +0300 | [diff] [blame] | 141 | stack_push(pcf, pcf->num_var_mtrrs); |
| 142 | stack_push(pcf, pcf->max_var_mtrrs); |
Rizwan Qureshi | b1b44d3 | 2016-08-26 21:08:50 +0530 | [diff] [blame] | 143 | return (void *) pcf->stack; |
| 144 | } |
| 145 | |
Kyösti Mälkki | a7421fb | 2017-09-05 22:43:05 +0300 | [diff] [blame] | 146 | static void finalize_load(uintptr_t *stack_top_ptr, uintptr_t stack_top) |
| 147 | { |
| 148 | *stack_top_ptr = stack_top; |
| 149 | /* |
| 150 | * Signal to rest of system that another update was made to the |
| 151 | * postcar program prior to running it. |
| 152 | */ |
| 153 | prog_segment_loaded((uintptr_t)stack_top_ptr, sizeof(uintptr_t), |
| 154 | SEG_FINAL); |
| 155 | } |
| 156 | |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 157 | static void load_postcar_cbfs(struct prog *prog, struct postcar_frame *pcf) |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 158 | { |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 159 | struct rmod_stage_load rsl = { |
| 160 | .cbmem_id = CBMEM_ID_AFTER_CAR, |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 161 | .prog = prog, |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 162 | }; |
| 163 | |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 164 | if (prog_locate(prog)) |
Keith Short | 7006458 | 2019-05-06 16:12:57 -0600 | [diff] [blame] | 165 | die_with_post_code(POST_INVALID_ROM, |
| 166 | "Failed to locate after CAR program.\n"); |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 167 | if (rmodule_stage_load(&rsl)) |
Keith Short | 7006458 | 2019-05-06 16:12:57 -0600 | [diff] [blame] | 168 | die_with_post_code(POST_INVALID_ROM, |
| 169 | "Failed to load after CAR program.\n"); |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 170 | |
| 171 | /* Set the stack pointer within parameters of the program loaded. */ |
| 172 | if (rsl.params == NULL) |
Keith Short | 7006458 | 2019-05-06 16:12:57 -0600 | [diff] [blame] | 173 | die_with_post_code(POST_INVALID_ROM, |
| 174 | "No parameters found in after CAR program.\n"); |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 175 | |
Kyösti Mälkki | a7421fb | 2017-09-05 22:43:05 +0300 | [diff] [blame] | 176 | finalize_load(rsl.params, pcf->stack); |
Aaron Durbin | dd95e00 | 2016-03-31 13:36:33 -0500 | [diff] [blame] | 177 | |
Subrata Banik | 90f750b | 2019-06-11 17:52:06 +0530 | [diff] [blame] | 178 | stage_cache_add(STAGE_POSTCAR, prog); |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | void run_postcar_phase(struct postcar_frame *pcf) |
| 182 | { |
| 183 | struct prog prog = |
Philipp Deppenwiese | 01797b1 | 2018-11-08 10:39:39 +0100 | [diff] [blame] | 184 | PROG_INIT(PROG_POSTCAR, CONFIG_CBFS_PREFIX "/postcar"); |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 185 | |
| 186 | postcar_commit_mtrrs(pcf); |
| 187 | |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 188 | if (!CONFIG(NO_STAGE_CACHE) && |
Kyösti Mälkki | a7421fb | 2017-09-05 22:43:05 +0300 | [diff] [blame] | 189 | romstage_handoff_is_resume()) { |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 190 | stage_cache_load_stage(STAGE_POSTCAR, &prog); |
Aaron Durbin | c546c76 | 2018-04-23 14:55:09 -0600 | [diff] [blame] | 191 | /* This is here to allow platforms to pass different stack |
| 192 | parameters between S3 resume and normal boot. On the |
| 193 | platforms where the values are the same it's a nop. */ |
Kyösti Mälkki | a7421fb | 2017-09-05 22:43:05 +0300 | [diff] [blame] | 194 | finalize_load(prog.arg, pcf->stack); |
| 195 | } else |
Aaron Durbin | d008413 | 2016-11-29 15:52:08 -0600 | [diff] [blame] | 196 | load_postcar_cbfs(&prog, pcf); |
| 197 | |
Subrata Banik | 2847e1e | 2019-02-25 20:31:22 +0530 | [diff] [blame] | 198 | /* As postcar exist, it's end of romstage here */ |
| 199 | timestamp_add_now(TS_END_ROMSTAGE); |
| 200 | |
Aaron Durbin | 7f8afe0 | 2016-03-18 12:21:23 -0500 | [diff] [blame] | 201 | prog_run(&prog); |
| 202 | } |