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
|
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <console/console.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/mtrr.h>
#include <cpu/amd/car.h>
#include <cpu/amd/mtrr.h>
#include <cpu/x86/cache.h>
#include <cbmem.h>
#include <string.h>
#include <halt.h>
#include "s3_resume.h"
static void *backup_resume(void)
{
void *resume_backup_memory;
printk(BIOS_DEBUG, "Find resume memory location\n");
if (cbmem_recovery(1)) {
printk(BIOS_EMERG, "Unable to recover CBMEM\n");
halt();
}
resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
if (resume_backup_memory == NULL) {
printk(BIOS_EMERG, "No storage for low-memory backup\n");
halt();
}
return resume_backup_memory;
}
static void move_stack_high_mem(void)
{
void *high_stack = cbmem_find(CBMEM_ID_ROMSTAGE_RAM_STACK);
/* TODO: Make the switch with empty stack instead. */
memcpy(high_stack, (void *)BSP_STACK_BASE_ADDR, HIGH_ROMSTAGE_STACK_SIZE);
/* TODO: We only switch stack on BSP. */
#ifdef __x86_64__
__asm__
volatile ("add %0, %%rsp; add %0, %%rbp; invd"::"g"
(high_stack - BSP_STACK_BASE_ADDR)
:);
#else
__asm__
volatile ("add %0, %%esp; add %0, %%ebp; invd"::"g"
(high_stack - BSP_STACK_BASE_ADDR)
:);
#endif
}
static void set_resume_cache(void)
{
msr_t msr;
/* disable fixed mtrr for now, it will be enabled by mtrr restore */
msr = rdmsr(SYSCFG_MSR);
msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrFixDramModEn);
wrmsr(SYSCFG_MSR, msr);
/* Enable caching for 0 - coreboot ram using variable mtrr */
msr.lo = 0 | MTRR_TYPE_WRBACK;
msr.hi = 0;
wrmsr(MTRR_PHYS_BASE(0), msr);
msr.lo = ~(CONFIG_RAMTOP - 1) | MTRR_PHYS_MASK_VALID;
msr.hi = (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1;
wrmsr(MTRR_PHYS_MASK(0), msr);
/* Set the default memory type and disable fixed and enable variable MTRRs */
msr.hi = 0;
msr.lo = (1 << 11);
wrmsr(MTRR_DEF_TYPE_MSR, msr);
enable_cache();
}
void prepare_for_resume(void)
{
void *resume_backup_memory = backup_resume();
post_code(0x62);
printk(BIOS_DEBUG, "Move CAR stack.\n");
move_stack_high_mem();
post_code(0x63);
disable_cache_as_ram();
printk(BIOS_DEBUG, "CAR disabled.\n");
set_resume_cache();
/*
* Copy the system memory that is in the ramstage area to the
* reserved area.
*/
if (resume_backup_memory)
memcpy(resume_backup_memory, (void *)(CONFIG_RAMBASE), HIGH_MEMORY_SAVE);
printk(BIOS_DEBUG, "System memory saved. OK to load ramstage.\n");
}
|