aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/amd/car/post_cache_as_ram.c
blob: 61874a907a8e0e170f237a4da9d2ecfdaf3b0b58 (plain)
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
/* 2005.6 by yhlu
 * 2006.3 yhlu add copy data from CAR to ram
 */
#include <string.h>
#include <arch/stages.h>
#include <cpu/x86/mtrr.h>
#include <cpu/amd/mtrr.h>
#include <cpu/amd/car.h>
#include <arch/acpi.h>
#include "cbmem.h"
#include "cpu/amd/car/disable_cache_as_ram.c"

#if CONFIG_RAMTOP <= 0x100000
	#error "You need to set CONFIG_RAMTOP greater than 1M"
#endif

#define PRINTK_IN_CAR	1

#if PRINTK_IN_CAR
#define print_car_debug(x) print_debug(x)
#else
#define print_car_debug(x)
#endif

extern char _car_data_start[];
extern char _car_data_end[];

static size_t car_data_size(void)
{
	size_t car_size = &_car_data_end[0] - &_car_data_start[0];
	return ALIGN(car_size, 64);
}

static size_t backup_size(void)
{
	size_t car_size = &_car_data_end[0] - &_car_data_start[0];
	return ALIGN(car_size + 1024, 1024);
}

static void memcpy_(void *d, const void *s, size_t len)
{
#if PRINTK_IN_CAR
	printk(BIOS_SPEW, " Copy [%08x-%08x] to [%08x - %08x] ... ",
		(u32) s, (u32) (s + len - 1), (u32) d, (u32) (d + len - 1));
#endif
	memcpy(d, s, len);
}

static void memset_(void *d, int val, size_t len)
{
#if PRINTK_IN_CAR
	printk(BIOS_SPEW, " Fill [%08x-%08x] ... ", (u32) d, (u32) (d + len - 1));
#endif
	memset(d, val, len);
}

static void prepare_romstage_ramstack(void *resume_backup_memory)
{
	size_t backup_top = backup_size();
	print_car_debug("Prepare CAR migration and stack regions...");

	if (resume_backup_memory) {
		memcpy_(resume_backup_memory + HIGH_MEMORY_SAVE - backup_top,
			(void *)(CONFIG_RAMTOP - backup_top), backup_top);
	}
	memset_((void *)(CONFIG_RAMTOP - backup_top), 0, backup_top);

	print_car_debug("Done\n");
}

static void prepare_ramstage_region(void *resume_backup_memory)
{
	size_t backup_top = backup_size();
	print_car_debug("Prepare ramstage memory region... ");

	if (resume_backup_memory) {
		memcpy_(resume_backup_memory, (void *) CONFIG_RAMBASE, HIGH_MEMORY_SAVE - backup_top);
		memset_((void*) CONFIG_RAMBASE, 0, HIGH_MEMORY_SAVE - backup_top);
	} else {
		memset_((void*)0, 0, CONFIG_RAMTOP - backup_top);
	}

	print_car_debug("Done\n");
}

/* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */

static void vErrata343(void)
{
#ifdef BU_CFG2_MSR
    msr_t msr;
    unsigned int uiMask = 0xFFFFFFF7;

    msr = rdmsr(BU_CFG2_MSR);
    msr.hi &= uiMask; // set bit 35 to 0
    wrmsr(BU_CFG2_MSR, msr);
#endif
}

void post_cache_as_ram(void)
{
	void *resume_backup_memory = NULL;

	int s3resume = acpi_s3_resume_allowed() && acpi_is_wakeup_early();
	if (s3resume) {
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
		cbmem_recovery(s3resume);
		resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
#endif
	}
	prepare_romstage_ramstack(resume_backup_memory);

	/* from here don't store more data in CAR */
	vErrata343();

	size_t car_size = car_data_size();
	void *migrated_car = (void *)(CONFIG_RAMTOP - car_size);

	print_car_debug("Copying data from cache to RAM... ");
	memcpy_(migrated_car, &_car_data_start[0], car_size);
	print_car_debug("Done\n");

	/* New stack grows right below migrated_car. */
	print_car_debug("Switching to use RAM as stack... ");
	cache_as_ram_switch_stack(migrated_car);

	/* We do not come back. */
}

void cache_as_ram_new_stack (void)
{
	void *resume_backup_memory = NULL;

#if PRINTK_IN_CAR
	printk(BIOS_DEBUG, "Top about %08x ... Done\n", (u32) &resume_backup_memory);
#endif
	print_car_debug("Disabling cache as ram now\n");
	disable_cache_as_ram_bsp();

	disable_cache();
	set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
	enable_cache();

	if (acpi_s3_resume_allowed() && acpi_is_wakeup_early()) {
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
		resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
#endif
	}
	prepare_ramstage_region(resume_backup_memory);

	set_sysinfo_in_ram(1); // So other core0 could start to train mem

	/*copy and execute ramstage */
	copy_and_run();
	/* We will not return */

	print_car_debug("should not be here -\n");
}