summaryrefslogtreecommitdiff
path: root/src/cpu/x86/smm/smmrelocate.S
blob: 3d1d9d26641dffc0263ff14def2f272104bfb2e0 (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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2008 coresystems GmbH
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
 * MA 02110-1301 USA
 */

#include <arch/asm.h>

// Make sure no stage 2 code is included:
#define __ROMCC__

// FIXME: Is this piece of code southbridge specific, or 
// can it be cleaned up so this include is not required?
#include "../../../southbridge/intel/i82801gx/i82801gx.h"

#undef DEBUG_SMM_RELOCATION
//#define DEBUG_SMM_RELOCATION

#define LAPIC_ID 0xfee00020

.global smm_relocation_start
.global smm_relocation_end

/* initially SMM is some sort of real mode. */
.code16

/**
 * This trampoline code relocates SMBASE to 0xa0000 - ( lapicid * 0x400 )
 *
 * Why 0x400? It is a safe value to cover the save state area per CPU. On
 * current AMD CPUs this area is _documented_ to be 0x200 bytes. On Intel
 * Core 2 CPUs the _documented_ parts of the save state area is 48 bytes
 * bigger, effectively sizing our data structures 0x300 bytes.
 *
 * LAPICID	SMBASE		SMM Entry 	SAVE STATE
 *    0		0xa0000		0xa8000		0xafd00
 *    1		0x9fc00		0xa7c00		0xaf900
 *    2		0x9f800		0xa7800		0xaf500
 *    3		0x9f400		0xa7400		0xaf100
 *    4		0x9f000		0xa7000		0xaed00
 *    5		0x9ec00		0xa6c00		0xae900
 *    6		0x9e800		0xa6800		0xae500
 *    7		0x9e400		0xa6400		0xae100
 *    8		0x9e000		0xa6000		0xadd00
 *    9		0x9dc00		0xa5c00		0xad900
 *   10		0x9d800		0xa5800		0xad500
 *   11		0x9d400		0xa5400		0xad100
 *   12		0x9d000		0xa5000		0xacd00
 *   13		0x9cc00		0xa4c00		0xac900
 *   14		0x9c800		0xa4800		0xac500
 *   15		0x9c400		0xa4400		0xac100
 *    .		   .		   .		   .
 *    .		   .		   .		   .
 *    .		   .		   .		   .
 *   31		0x98400		0xa0400		0xa8100
 *
 * With 32 cores, the SMM handler would need to fit between
 * 0xa0000-0xa0400 and the stub plus stack would need to go
 * at 0xa8000-0xa8100 (example for core 0). That is not enough.
 *
 * This means we're basically limited to 16 cpu cores before 
 * we need to use the TSEG/HSEG for the actual SMM handler plus stack.
 * When we exceed 32 cores, we also need to put SMBASE to TSEG/HSEG.
 *
 * If we figure out the documented values above are safe to use,
 * we could pack the structure above even more, so we could use the
 * scheme to pack save state areas for 63 AMD CPUs or 58 Intel CPUs
 * in the ASEG.
 *
 * Note: Some versions of Pentium M need their SMBASE aligned to 32k.
 * On those the above only works for up to 2 cores. But for now we only
 * care fore Core (2) Duo/Solo
 *
 */

smm_relocation_start:
	/* Check revision to see if AMD64 style SMM_BASE
	 *   Intel Core Solo/Duo:  0x30007
	 *   Intel Core2 Solo/Duo: 0x30100
	 *   AMD64:                0x3XX64
	 * This check does not make much sense, unless someone ports
	 * SMI handling to AMD64 CPUs.
	 */

	mov $0x38000 + 0x7efc, %ebx
	addr32 mov (%ebx), %al
	cmp $0x64, %al
	je 1f
 
	mov $0x38000 + 0x7ef8, %ebx
	jmp smm_relocate
1:
	mov $0x38000 + 0x7f00, %ebx

smm_relocate:
	/* Get this CPU's LAPIC ID */
	movl $LAPIC_ID, %esi
	addr32 movl (%esi), %ecx
	shr  $24, %ecx
	
	/* calculate offset by multiplying the 
	 * apic ID by 1024 (0x400)
	 */
	movl %ecx, %edx
	shl $10, %edx

	movl $0xa0000, %eax
	subl %edx, %eax	/* subtract offset, see above */

	addr32 movl %eax, (%ebx)


	/* The next section of code is hardware specific */

	/* Clear SMI status */
	movw $(DEFAULT_PMBASE + 0x34), %dx
	inw %dx, %ax
	outw %ax, %dx

	/* Clear PM1 status */
	movw $(DEFAULT_PMBASE + 0x00), %dx
	inw %dx, %ax
	outw %ax, %dx

	/* Set EOS bit so other SMIs can occur */
	movw $(DEFAULT_PMBASE + 0x30), %dx
	inl %dx, %eax
	orl $(1 << 1), %eax
	outl %eax, %dx

	/* End of hardware specific section. */
#ifdef DEBUG_SMM_RELOCATION
	/* print [SMM-x] so we can determine if CPUx went to SMM */
	movw $CONFIG_TTYS0_BASE, %dx
	mov $'[', %al
	outb %al, %dx
	mov $'S', %al
	outb %al, %dx
	mov $'M', %al
	outb %al, %dx
	outb %al, %dx
	movb $'-', %al
	outb %al, %dx
	/* calculate ascii of cpu number. More than 9 cores? -> FIXME */
	movb %cl, %al
	addb $'0', %al 
	outb %al, %dx
	mov $']', %al
	outb %al, %dx
	mov $'\r', %al
	outb %al, %dx
	mov $'\n', %al
	outb %al, %dx
#endif

	/* That's it. return */
	rsm
smm_relocation_end: