summaryrefslogtreecommitdiff
path: root/src/cpu/x86/smm/smmrelocate.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/x86/smm/smmrelocate.S')
-rw-r--r--src/cpu/x86/smm/smmrelocate.S168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/cpu/x86/smm/smmrelocate.S b/src/cpu/x86/smm/smmrelocate.S
new file mode 100644
index 0000000000..2a7bfc23c7
--- /dev/null
+++ b/src/cpu/x86/smm/smmrelocate.S
@@ -0,0 +1,168 @@
+/*
+ * 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>
+#include "../../../../src/northbridge/intel/i945/ich7.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 $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:
+