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:
|