diff options
Diffstat (limited to 'src/cpu/x86/smm/smmrelocate.S')
-rw-r--r-- | src/cpu/x86/smm/smmrelocate.S | 168 |
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: + |