lib/prog_loading: introduce prog_segment_loaded()
[coreboot.git] / src / arch / x86 / postcar_loader.c
blobcc1d46058555eaa0f92ae677d4c9305794def916
1 /*
2 * This file is part of the coreboot project.
4 * Copyright 2016 Google Inc.
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.
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.
16 #include <arch/cpu.h>
17 #include <cbmem.h>
18 #include <console/console.h>
19 #include <cpu/x86/msr.h>
20 #include <cpu/x86/mtrr.h>
21 #include <program_loading.h>
22 #include <rmodule.h>
24 static inline void stack_push(struct postcar_frame *pcf, uint32_t val)
26 uint32_t *ptr;
28 pcf->stack -= sizeof(val);
29 ptr = (void *)pcf->stack;
30 *ptr = val;
33 int postcar_frame_init(struct postcar_frame *pcf, size_t stack_size)
35 void *stack;
36 msr_t msr;
38 msr = rdmsr(MTRR_CAP_MSR);
40 stack = cbmem_add(CBMEM_ID_ROMSTAGE_RAM_STACK, stack_size);
41 if (stack == NULL) {
42 printk(BIOS_ERR, "Couldn't add %zd byte stack in cbmem.\n",
43 stack_size);
44 return -1;
47 pcf->stack = (uintptr_t)stack;
48 pcf->stack += stack_size;
50 pcf->upper_mask = (1 << (cpu_phys_address_size() - 32)) - 1;
52 pcf->max_var_mttrs = msr.lo & MTRR_CAP_VCNT;
54 pcf->num_var_mttrs = 0;
56 return 0;
59 void postcar_frame_add_mtrr(struct postcar_frame *pcf,
60 uintptr_t addr, size_t size, int type)
62 size_t align;
64 if (pcf->num_var_mttrs >= pcf->max_var_mttrs) {
65 printk(BIOS_ERR, "No more variable MTRRs: %d\n",
66 pcf->max_var_mttrs);
67 return;
70 /* Determine address alignment by lowest bit set in address. */
71 align = addr & (addr ^ (addr - 1));
73 if (align < size) {
74 printk(BIOS_ERR, "Address (%lx) alignment (%zx) < size (%zx)\n",
75 addr, align, size);
76 size = align;
79 /* Push MTRR mask then base -- upper 32-bits then lower 32-bits. */
80 stack_push(pcf, pcf->upper_mask);
81 stack_push(pcf, ~(size - 1) | MTRR_PHYS_MASK_VALID);
82 stack_push(pcf, 0);
83 stack_push(pcf, addr | type);
84 pcf->num_var_mttrs++;
87 void run_postcar_phase(struct postcar_frame *pcf)
89 struct prog prog =
90 PROG_INIT(PROG_UNKNOWN, CONFIG_CBFS_PREFIX "/postcar");
91 struct rmod_stage_load rsl = {
92 .cbmem_id = CBMEM_ID_AFTER_CAR,
93 .prog = &prog,
97 * Place the number of used variable MTRRs on stack then max number
98 * of variable MTRRs supported in the system.
100 stack_push(pcf, pcf->num_var_mttrs);
101 stack_push(pcf, pcf->max_var_mttrs);
103 if (prog_locate(&prog))
104 die("Failed to locate after CAR program.\n");
105 if (rmodule_stage_load(&rsl))
106 die("Failed to load after CAR program.\n");
108 /* Set the stack pointer within parameters of the program loaded. */
109 if (rsl.params == NULL)
110 die("No parameters found in after CAR program.\n");
112 *(uintptr_t *)rsl.params = pcf->stack;
115 * Signal to rest of system that another update was made to the
116 * postcar program prior to running it.
118 prog_segment_loaded((uintptr_t)rsl.params, sizeof(uintptr_t),
119 SEG_FINAL);
121 prog_run(&prog);