Patchwork new AMD K8 SMM version

login
register
about
Submitter Stefan Reinauer
Date 2010-12-13 01:25:09
Message ID <4D0575F5.4060000@coresystems.de>
Download mbox | patch
Permalink /patch/2426/
State Superseded
Headers show

Comments

Stefan Reinauer - 2010-12-13 01:25:09
See patch. This adds SMM support for Asus M2V-MX SE.


 cpu/amd/model_fxx/model_fxx_init.c    |    5
 cpu/amd/smm/Makefile.inc              |    2
 cpu/amd/smm/smm_init.c                |  121 +++++++++++++++
 cpu/amd/socket_754/Makefile.inc       |    2
 cpu/amd/socket_939/Makefile.inc       |    2
 cpu/amd/socket_940/Makefile.inc       |    2
 cpu/amd/socket_AM2/Makefile.inc       |    1
 cpu/amd/socket_AM2r2/Makefile.inc     |    3
 cpu/amd/socket_AM3/Makefile.inc       |    3
 cpu/amd/socket_ASB2/Makefile.inc      |    3
 cpu/amd/socket_F/Makefile.inc         |    1
 cpu/amd/socket_F_1207/Makefile.inc    |    1
 cpu/amd/socket_S1G1/Makefile.inc      |    3
 cpu/x86/smm/smihandler.c              |   23 ++
 cpu/x86/smm/smmrelocate.S             |    4
 include/cpu/x86/smm.h                 |    2
 mainboard/asus/m2v-mx_se/Kconfig      |    1
 southbridge/intel/i82801gx/i82801gx.h |   10 -
 southbridge/intel/i82801gx/lpc.c      |    2
 southbridge/intel/i82801gx/smi.c      |    9 +
 southbridge/via/vt8237r/Makefile.inc  |    1
 southbridge/via/vt8237r/lpc.c         |   13 +
 southbridge/via/vt8237r/nvs.h         |   46 +++++
 southbridge/via/vt8237r/smihandler.c  |  265
++++++++++++++++++++++++++++++++++
 southbridge/via/vt8237r/vt8237r.h     |   47 +++++-
 25 files changed, 544 insertions(+), 28 deletions(-)
AMD K8/FAM10 SMM support

Changes to last version:
- integrated Rudolf's suggestions
- use normal IO PCI access (and backup 0xcf8 accordingly)
- separate SMM init and locking
- prevent copying SMM code multiple times

Signed-off-by: Stefan Reinauer <stepan@coreboot.org>
Stefan Reinauer - 2010-12-13 01:35:39
On 12/12/10 5:25 PM, Stefan Reinauer wrote:
> See patch. This adds SMM support for Asus M2V-MX SE.
>
Please, test if you can!
Rudolf Marek - 2010-12-14 22:54:13
Hi,

I will be back on the weekend. Just a comment to this:

> +void smm_init(void)
> +{
> +	msr_t msr;
> +
> +	msr = rdmsr(HWCR_MSR);
> +	if (msr.lo & (1 << 0)) {
> +		// This sounds like a bug... ?
Well the lock survives all resets except power on.

> +		printk(BIOS_DEBUG, "SMM is still locked from last boot, using old handler.\n");
> +		return;
> +	}
> +
> +	/* Only copy SMM handler once, not once per CPU */
> +	if (!smm_handler_copied) {
> +		msr_t syscfg_orig, mtrr_aseg_orig;
> +
> +		smm_handler_copied = 1;
> +
> +		// XXX Really?
Yes if you mess with MTRR you need to do that otherwise it is undefined (check 
system programming manual AMD...)

> +		disable_cache();
> +		syscfg_orig = rdmsr(SYSCFG_MSR);
> +		mtrr_aseg_orig = rdmsr(MTRRfix16K_A0000_MSR);
> +
> +		// XXX Why?
This is because there are AMD extension which tells if MTRR is MMIO or memory 
and we need them ON check AMD programming manual.

> +		msr = syscfg_orig;
> +		msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
Allow changes to MTRR extended attributes

> +		msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;


turn the extended attributes off until we fix them so A0000 is routed to memory.

> +		wrmsr(SYSCFG_MSR, msr);
> +
> +		/* set DRAM access to 0xa0000 */
> +		// XXX but why?

And we tell that on A0000 is memory. This is true until SMM is enabled, then the 
SMM logic is used. We use the extended attributes.

> +		msr.lo = 0x18181818;
> +		msr.hi = 0x18181818;
> +		wrmsr(MTRRfix16K_A0000_MSR, msr);

> +#if 0 // obviously wrong stuff from Rudolf's patch
> +		msr.lo |= SYSCFG_MSR_MtrrFixDramEn;
> +		wrmsr(SYSCFG_MSR, msr);

This need to be fixed  I want to write back the SYSCFG_MSR to disable the 
extended features.

> +#endif

Up to now we enabled the Memory access to A0000 which until now is not used as

> +
> +		/* enable the SMM memory window */
> +		msr = rdmsr(SMM_MASK_MSR);
> +		msr.lo |= (1 << 0); // Enable ASEG SMRAM Range
> +		msr.lo &= ~(1 << 2); // Open ASEG SMRAM Range
> +		wrmsr(SMM_MASK_MSR, msr);

We need to COPY FIRST and then ENABLE SMM because until the enable ASEG is done 
we can write to memory as it is normal memory. (this is kind of equvalent of the 
D_OPEN in intel)

> +
> +		/* copy the real SMM handler */
> +		memcpy((void *)SMM_BASE, &_binary_smm_start, (size_t)&_binary_smm_size);
> +		wbinvd();

This needs to be bit more up.

> +
> +		msr = rdmsr(SMM_MASK_MSR);
> +		msr.lo |= ~(1 << 2); // Close ASEG SMRAM Range
> +		wrmsr(SMM_MASK_MSR, msr);

 From now the SMM restrictions apply no acces to ASEG is possible outside SMM.

> +
> +#if 0 // obviously wrong stuff from Rudolf's patch
> +		msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;
This just disables the extended attribs, but allows the modification of them
> +		wrmsr(SYSCFG_MSR, msr);
> +#endif
> +		// XXX But why?

This turns off the magic extra MTTR access types and we disable them and restore 
what was there.

> +		wrmsr(MTRRfix16K_A0000_MSR, mtrr_aseg_orig);
> +		wrmsr(SYSCFG_MSR, syscfg_orig);
> +		enable_cache();
> +
> +	}
> +
> +	/* But set SMM base address on all CPUs/cores */
> +	msr = rdmsr(SMM_BASE_MSR);
> +	msr.lo = SMM_BASE;
> +	wrmsr(SMM_BASE_MSR, msr);
> +}


And yes we need to call SMM set base addr, together with SMM lock...

More on that later, I think we at least need to solve the settings of smm base 
on another cores and locking them. CHeck my todo list for details.

Hope it is more clear now. Please check following:

BKDG for opteron/athlon 13.2.1.2 SYSCFG Register
And AMD system programming manual for the MTRR extended attributes.

Thanks,
Rudolf
Stefan Reinauer - 2010-12-15 18:38:50
Hi Rudolf,

thanks for your comments... I will try to work them into the code.
But here is some more discussion, maybe I am still confused.

* Rudolf Marek <r.marek@assembler.cz> [101214 23:54]:
> Hi,
> 
> I will be back on the weekend. Just a comment to this:
> 
> >+void smm_init(void)
> >+{
> >+	msr_t msr;
> >+
> >+	msr = rdmsr(HWCR_MSR);
> >+	if (msr.lo & (1 << 0)) {
> >+		// This sounds like a bug... ?
> Well the lock survives all resets except power on.

Yes, and that might be a bug in how we keep state across resets.

Also, we were trying to initialize SMM several times on each boot, once
per CPU and then once in the southbridge code. So you should actually
have seen this message on every boot, with locking enabled. Not just on
reboots.
 
> >+		printk(BIOS_DEBUG, "SMM is still locked from last boot, using old handler.\n");
> >+		return;
> >+	}
> >+
> >+	/* Only copy SMM handler once, not once per CPU */
> >+	if (!smm_handler_copied) {
> >+		msr_t syscfg_orig, mtrr_aseg_orig;
> >+
> >+		smm_handler_copied = 1;
> >+
> >+		// XXX Really?
> Yes if you mess with MTRR you need to do that otherwise it is
> undefined (check system programming manual AMD...)

I know about the cache disable requirement for MTRR changes

The comment was supposed to be about whether it's needed to modify the SYSCFG
and the Fixes ASEG MTRR at all. The changes you are doing should be done
through the SMM_MASK MSR instead. And there is no mention on SYSCFG
changes for SMM in the BKDG. I keep thinking we should not do that at
all.

> 
> >+		disable_cache();
> >+		syscfg_orig = rdmsr(SYSCFG_MSR);
> >+		mtrr_aseg_orig = rdmsr(MTRRfix16K_A0000_MSR);
> >+
> >+		// XXX Why?
> This is because there are AMD extension which tells if MTRR is MMIO
> or memory and we need them ON check AMD programming manual.

Which one, where? I am referring to 32559, and I can't find any such
requirement in the SMM chapter. Check SMM_MASK MSR on page 282/283 in
32559.

> >+		msr = syscfg_orig;
> >+		msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
> Allow changes to MTRR extended attributes
> 
> >+		msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;
> 
> 
> turn the extended attributes off until we fix them so A0000 is routed to memory.
 
> >+		wrmsr(SYSCFG_MSR, msr);
> >+
> >+		/* set DRAM access to 0xa0000 */
> >+		// XXX but why?
> 
> And we tell that on A0000 is memory. This is true until SMM is
> enabled, then the SMM logic is used. We use the extended attributes.

That's what we do with the /* enable the SMM memory window */ chunk
below.


 
> >+		msr.lo = 0x18181818;
> >+		msr.hi = 0x18181818;
> >+		wrmsr(MTRRfix16K_A0000_MSR, msr);
> 
> >+#if 0 // obviously wrong stuff from Rudolf's patch
> >+		msr.lo |= SYSCFG_MSR_MtrrFixDramEn;
> >+		wrmsr(SYSCFG_MSR, msr);
> 
> This need to be fixed  I want to write back the SYSCFG_MSR to
> disable the extended features.
> 
> >+#endif
> 
> Up to now we enabled the Memory access to A0000 which until now is not used as
 
> >+
> >+		/* enable the SMM memory window */
> >+		msr = rdmsr(SMM_MASK_MSR);
> >+		msr.lo |= (1 << 0); // Enable ASEG SMRAM Range
> >+		msr.lo &= ~(1 << 2); // Open ASEG SMRAM Range
> >+		wrmsr(SMM_MASK_MSR, msr);
> 
> We need to COPY FIRST and then ENABLE SMM because until the enable
> ASEG is done we can write to memory as it is normal memory. (this is
> kind of equvalent of the D_OPEN in intel)
 
No, I don't think so. The above does NOT ENABLE SMM but opens the SMM
RAM area to be accessible. This is the equivalent to D_OPEN on Intel.

> >+
> >+		/* copy the real SMM handler */
> >+		memcpy((void *)SMM_BASE, &_binary_smm_start, (size_t)&_binary_smm_size);
> >+		wbinvd();
> 
> This needs to be bit more up.

It needs to be after the SMM_MASK write.

 
> >+
> >+		msr = rdmsr(SMM_MASK_MSR);
> >+		msr.lo |= ~(1 << 2); // Close ASEG SMRAM Range
> >+		wrmsr(SMM_MASK_MSR, msr);
> 
> From now the SMM restrictions apply no acces to ASEG is possible outside SMM.
 
Yes.


> >+
> >+#if 0 // obviously wrong stuff from Rudolf's patch
> >+		msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;
> This just disables the extended attribs, but allows the modification of them

> >+		wrmsr(SYSCFG_MSR, msr);
> >+#endif
> >+		// XXX But why?
> 
> This turns off the magic extra MTTR access types and we disable them
> and restore what was there.
> 
> >+		wrmsr(MTRRfix16K_A0000_MSR, mtrr_aseg_orig);
> >+		wrmsr(SYSCFG_MSR, syscfg_orig);
> >+		enable_cache();
> >+
> >+	}
> >+
> >+	/* But set SMM base address on all CPUs/cores */
> >+	msr = rdmsr(SMM_BASE_MSR);
> >+	msr.lo = SMM_BASE;
> >+	wrmsr(SMM_BASE_MSR, msr);
> >+}
> 


 
> And yes we need to call SMM set base addr, together with SMM lock...

depending on what you mean by SMM lock. The smm_lock() function must be
called after all CPU cores had a chance to set SMBASE to the correct
value. 

, so doing it in the same function is not really an option. It
needs to happen some time later (in lpc.c, while the SMBASE setup
happens in src/cpu/x86/lapic/lapic_cpu_init.c)

> More on that later, I think we at least need to solve the settings
> of smm base on another cores and locking them. 

My patch does exactly that. It does however set the same address on all
cores, which is a bug. Will post an updated patch.

> CHeck my todo list for details.
Ok.. here:

> 0) only enabled board is m2v-mx se (trivial to enable others VIA 8237
>    based)
someone else got to do thi

> 1) PCIe access is hardcoded to 0xe000000
PCIe access removed and PCI register saved in the latest patch

> a) change the SMM handler to save PCIcfg/PCIdata??? regs
> b) make MMCONFIG static to 0xe00000
> c) some clever way to get idea where it is without PCI access

a) implemented as we can not always rely on PCIe being there, and people
will run into the problem later on.

> 2) Dualcore/more cpus
> 
> I hardcoded that for single CPU. You need most likely change
> model_fxx_init.c and call smm_init from there (except that copy can
> done via CPU)

smm_init is called from initialize_cpus(), see above.

> All CPUs needs to set Aseg ENable and SMM_BASE (to different address)

done in the latest patch, with same address though. This needs a fix.

> No smm_relocate.S is used because we dont need it on AMD, we have the
> MSRs...

Done in the latest patch.

> 5) remove HACK_SMM
> The header file dislikes the include someone needs to fix that.

done in latest patch.

> 6) SMM locking

Should be done (correctly) in the latest patch. Needs testing though.

Missing from your TODO is 3 and 4. The intel SMM handler can do that
stuff, so implementing it is hopefully mostly a matter of finding a
dilligent soul grabbing the data sheets and giving it a go:

- poweroff without 4s delay before ACPI is there
- acpi enable/disable
- IO traps

> Hope it is more clear now. Please check following:
> 
> BKDG for opteron/athlon 13.2.1.2 SYSCFG Register
> And AMD system programming manual for the MTRR extended attributes.
 
Stefan
Rudolf Marek - 2010-12-18 11:29:13
Hi again,

>> Well the lock survives all resets except power on.
>
> Yes, and that might be a bug in how we keep state across resets.
>
> Also, we were trying to initialize SMM several times on each boot, once
> per CPU and then once in the southbridge code. So you should actually
> have seen this message on every boot, with locking enabled. Not just on
> reboots.

No, this was intended because I thought it won't go away on INIT - it looks like 
it does, maybe we can kill this code.

>
>>> +		printk(BIOS_DEBUG, "SMM is still locked from last boot, using old handler.\n");
>>> +		return;
>>> +	}
>>> +
>>> +	/* Only copy SMM handler once, not once per CPU */
>>> +	if (!smm_handler_copied) {
>>> +		msr_t syscfg_orig, mtrr_aseg_orig;
>>> +
>>> +		smm_handler_copied = 1;
>>> +
>>> +		// XXX Really?

>> Yes if you mess with MTRR you need to do that otherwise it is
>> undefined (check system programming manual AMD...)
>
> I know about the cache disable requirement for MTRR changes
>
> The comment was supposed to be about whether it's needed to modify the SYSCFG
> and the Fixes ASEG MTRR at all. The changes you are doing should be done
> through the SMM_MASK MSR instead. And there is no mention on SYSCFG
> changes for SMM in the BKDG. I keep thinking we should not do that at
> all.

No check table 62. There is no way if aseg is enabled to write to that memory 
outside SMM. The special SYSCFG gymnastic will enable to write to Aseg because 
the MTRR extensions can route it to memory (completely independent of SMM logic)
And this is what I do. If the SMM logic is on (aseg enable) it wont let you ever 
write to to aseg

>
>>
>>> +		disable_cache();
>>> +		syscfg_orig = rdmsr(SYSCFG_MSR);
>>> +		mtrr_aseg_orig = rdmsr(MTRRfix16K_A0000_MSR);
>>> +
>>> +		// XXX Why?
>> This is because there are AMD extension which tells if MTRR is MMIO
>> or memory and we need them ON check AMD programming manual.
>
> Which one, where? I am referring to 32559, and I can't find any such
> requirement in the SMM chapter. Check SMM_MASK MSR on page 282/283 in
> 32559.

Well this has nothing to do with SMM. If SMM is NOT yet enabled, you can route 
A0000 to memory using the CPU, this is what I do. If SMM gets enabled it started 
to behave way you know it from Intel.

>
> That's what we do with the /* enable the SMM memory window */ chunk
> below.

No. Check table

Table 62.
SMM ASeg-Enabled Memory Types

You see once Aseg is enabled there is no way to copy there something outside the 
SMM.

>> We need to COPY FIRST and then ENABLE SMM because until the enable
>> ASEG is done we can write to memory as it is normal memory. (this is
>> kind of equvalent of the D_OPEN in intel)
>
> No, I don't think so. The above does NOT ENABLE SMM but opens the SMM
> RAM area to be accessible. This is the equivalent to D_OPEN on Intel.

No, enabling Aseg will stop routing to RAM if outside of SMM.




>> And yes we need to call SMM set base addr, together with SMM lock...
>
> depending on what you mean by SMM lock. The smm_lock() function must be
> called after all CPU cores had a chance to set SMBASE to the correct
> value.

I think we can set it per core.

Please check next mail where I fixed your patch.

Thanks,
Rudolf

Patch

Index: src/southbridge/via/vt8237r/vt8237r.h
===================================================================
--- src/southbridge/via/vt8237r/vt8237r.h	(revision 6169)
+++ src/southbridge/via/vt8237r/vt8237r.h	(working copy)
@@ -20,12 +20,11 @@ 
 #ifndef SOUTHBRIDGE_VIA_VT8237R_VT8237R_H
 #define SOUTHBRIDGE_VIA_VT8237R_VT8237R_H
 
-#include <stdint.h>
-
 /* Static resources for the VT8237R southbridge */
 
 #define VT8237R_APIC_ID			0x2
 #define VT8237R_ACPI_IO_BASE		0x500
+#define DEFAULT_PMBASE			VT8237R_ACPI_IO_BASE
 #define VT8237R_SMBUS_IO_BASE		0x400
 /* 0x0 disabled, 0x2 reserved, 0xf = IRQ15 */
 #define VT8237R_ACPI_IRQ		0x9
@@ -36,6 +35,36 @@ 
 #endif
 #define VT8237R_HPET_ADDR		0xfed00000ULL
 
+/* PMBASE FIXME mostly taken from ich7 */
+#define PM1_STS		0x00
+#define   WAK_STS	(1 << 15)
+#define   PCIEXPWAK_STS	(1 << 14)
+#define   PRBTNOR_STS	(1 << 11)
+#define   RTC_STS	(1 << 10)
+#define   PWRBTN_STS	(1 << 8)
+#define   GBL_STS	(1 << 5)
+#define   BM_STS	(1 << 4)
+#define   TMROF_STS	(1 << 0)
+#define PM1_EN		0x02
+#define   PCIEXPWAK_DIS	(1 << 14)
+#define   RTC_EN	(1 << 10)
+#define   PWRBTN_EN	(1 << 8)
+#define   GBL_EN	(1 << 5)
+#define   TMROF_EN	(1 << 0)
+#define PM1_CNT		0x04
+#define   SLP_EN	(1 << 13)
+#define   SLP_TYP	(7 << 10)
+#define   GBL_RLS	(1 << 2)
+#define   BM_RLD	(1 << 1)
+#define   SCI_EN	(1 << 0)
+#define PM1_TMR		0x08
+#define PROC_CNT	0x10
+#define LV2		0x14
+#define LV3		0x15
+#define SMI_STS		0x28
+#define SMI_EN		0x2d
+#define EOS		(1 << 0)
+
 /* IDE */
 #define IDE_CS				0x40
 #define IDE_CONF_I			0x41
@@ -107,6 +136,15 @@ 
 #endif
 ;
 
+#define MAINBOARD_POWER_OFF	0
+#define MAINBOARD_POWER_ON	1
+#define MAINBOARD_POWER_KEEP	2
+
+#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
+#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
+#endif
+
+
 #ifdef __PRE_RAM__
 #ifndef __ROMCC__
 u8 smbus_read_byte(u8 dimm, u8 offset);
@@ -119,10 +157,9 @@ 
 int vt8237_early_network_init(struct vt8237_network_rom *rom);
 #endif
 #else
-#include <device/device.h>
-void writeback(struct device *dev, u16 where, u8 what);
+void writeback(device_t dev, u16 where, u8 what);
 void dump_south(device_t dev);
-u32 vt8237_ide_80pin_detect(struct device *dev);
+u32 vt8237_ide_80pin_detect(device_t dev);
 #endif
 
 #endif
Index: src/southbridge/via/vt8237r/Makefile.inc
===================================================================
--- src/southbridge/via/vt8237r/Makefile.inc	(revision 6169)
+++ src/southbridge/via/vt8237r/Makefile.inc	(working copy)
@@ -25,3 +25,4 @@ 
 driver-y += usb.c
 driver-$(CONFIG_PIRQ_ROUTE) += pirq.c
 ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += fadt.c
+smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
Index: src/southbridge/via/vt8237r/nvs.h
===================================================================
--- src/southbridge/via/vt8237r/nvs.h	(revision 0)
+++ src/southbridge/via/vt8237r/nvs.h	(revision 0)
@@ -0,0 +1,46 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 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
+ */
+
+typedef struct {
+	/* Miscellaneous */
+	u16	osys; /* 0x00 - Operating System */
+	u8	smif; /* 0x02 - SMI function call ("TRAP") */
+	u8	prm0; /* 0x03 - SMI function call parameter */
+	u8	prm1; /* 0x04 - SMI function call parameter */
+	u8	scif; /* 0x05 - SCI function call (via _L00) */
+	u8	prm2; /* 0x06 - SCI function call parameter */
+	u8	prm3; /* 0x07 - SCI function call parameter */
+	u8	lckf; /* 0x08 - Global Lock function for EC */
+	u8	prm4; /* 0x09 - Lock function parameter */
+	u8	prm5; /* 0x0a - Lock function parameter */
+	u32	p80d; /* 0x0b - Debug port (IO 0x80) value */
+	u8	lids; /* 0x0f - LID state (open = 1) */
+	u8	pwrs; /* 0x10 - Power state (AC = 1) */
+	u8	dbgs; /* 0x11 - Debug state */
+	u8	linx; /* 0x12 - Linux OS */
+	u8	dckn; /* 0x13 - PCIe docking state */
+	u8      rsvd[0x28-0x14];
+	/* Processor Identification */
+	u8	apic; /* 0x28 - APIC enabled */
+	u8	mpen; /* 0x29 - MP capable/enabled */
+	u8	pcp0; /* 0x2a - PDC CPU/CORE 0 */
+	u8	pcp1; /* 0x2b - PDC CPU/CORE 1 */
+	u8	ppcm; /* 0x2c - Max. PPC state */
+} __attribute__((packed)) global_nvs_t;
+
Index: src/southbridge/via/vt8237r/lpc.c
===================================================================
--- src/southbridge/via/vt8237r/lpc.c	(revision 6169)
+++ src/southbridge/via/vt8237r/lpc.c	(working copy)
@@ -28,6 +28,7 @@ 
 #include <pc80/mc146818rtc.h>
 #include <arch/ioapic.h>
 #include <cpu/x86/lapic.h>
+#include <cpu/cpu.h>
 #include <pc80/keyboard.h>
 #include <pc80/i8259.h>
 #include <stdlib.h>
@@ -217,12 +218,9 @@ 
 	/* Disable SMI on GPIO. */
 	outw(0x0, VT8237R_ACPI_IO_BASE + 0x24);
 
-	/* Disable all global enable SMIs. */
-	outw(0x0, VT8237R_ACPI_IO_BASE + 0x2a);
+	/* Disable all global enable SMIs, except SW SMI */
+	outw(0x40, VT8237R_ACPI_IO_BASE + 0x2a);
 
-	/* All SMI off, both IDE buses ON, PSON rising edge. */
-	outw(0x0, VT8237R_ACPI_IO_BASE + 0x2c);
-
 	/* Primary activity SMI disable. */
 	outl(0x0, VT8237R_ACPI_IO_BASE + 0x34);
 
@@ -238,6 +236,10 @@ 
 	acpi_slp_type = ((tmp & (7 << 10)) >> 10) == 1 ? 3 : 0 ;
 	printk(BIOS_DEBUG, "SLP_TYP type was %x %x\n", tmp, acpi_slp_type);
 #endif
+
+	/* All SMI on, both IDE buses ON, PSON rising edge. */
+	outw(0x1, VT8237R_ACPI_IO_BASE + 0x2c);
+
 	/* clear sleep */
 	tmp &= ~(7 << 10);
 	tmp |= 1;
@@ -501,6 +503,7 @@ 
 	/* Enable serial IRQ, 6PCI clocks. */
 	pci_write_config8(dev, 0x52, 0x9);
 
+	smm_lock();
 #endif
 
 	/* Power management setup */
Index: src/southbridge/via/vt8237r/smihandler.c
===================================================================
--- src/southbridge/via/vt8237r/smihandler.c	(revision 0)
+++ src/southbridge/via/vt8237r/smihandler.c	(revision 0)
@@ -0,0 +1,265 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright (C) 2010 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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 <types.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <device/pci_def.h>
+#include "vt8237r.h"
+
+#define APM_CNT		0xb2
+#define   CST_CONTROL	0x85
+#define   PST_CONTROL	0x80
+#define   ACPI_DISABLE	0x1e
+#define   ACPI_ENABLE	0xe1
+#define   GNVS_UPDATE   0xea
+#define APM_STS		0xb3
+
+#include "nvs.h"
+
+/* While we read PMBASE dynamically in case it changed, let's
+ * initialize it with a sane value
+ */
+u16 pmbase = DEFAULT_PMBASE;
+u8 smm_initialized = 0;
+
+/* GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located
+ * by coreboot.
+ */
+global_nvs_t *gnvs = (global_nvs_t *)0x0;
+void *tcg = (void *)0x0;
+void *smi1 = (void *)0x0;
+
+#if 0
+/**
+ * @brief read and clear PM1_STS
+ * @return PM1_STS register
+ */
+static u16 reset_pm1_status(void)
+{
+	u16 reg16;
+
+	reg16 = inw(pmbase + PM1_STS);
+	/* set status bits are cleared by writing 1 to them */
+	outw(reg16, pmbase + PM1_STS);
+
+	return reg16;
+}
+
+static void dump_pm1_status(u16 pm1_sts)
+{
+	printk(BIOS_SPEW, "PM1_STS: ");
+	if (pm1_sts & (1 << 15)) printk(BIOS_SPEW, "WAK ");
+	if (pm1_sts & (1 << 14)) printk(BIOS_SPEW, "PCIEXPWAK ");
+	if (pm1_sts & (1 << 11)) printk(BIOS_SPEW, "PRBTNOR ");
+	if (pm1_sts & (1 << 10)) printk(BIOS_SPEW, "RTC ");
+	if (pm1_sts & (1 <<  8)) printk(BIOS_SPEW, "PWRBTN ");
+	if (pm1_sts & (1 <<  5)) printk(BIOS_SPEW, "GBL ");
+	if (pm1_sts & (1 <<  4)) printk(BIOS_SPEW, "BM ");
+	if (pm1_sts & (1 <<  0)) printk(BIOS_SPEW, "TMROF ");
+	printk(BIOS_SPEW, "\n");
+	int reg16 = inw(pmbase + PM1_EN);
+	printk(BIOS_SPEW, "PM1_EN: %x\n", reg16);
+}
+#endif
+
+/**
+ * @brief read and clear SMI_STS
+ * @return SMI_STS register
+ */
+static u16 reset_smi_status(void)
+{
+	u16 reg16;
+
+	reg16 = inw(pmbase + SMI_STS);
+	/* set status bits are cleared by writing 1 to them */
+	outw(reg16, pmbase + SMI_STS);
+
+	return reg16;
+}
+
+static void dump_smi_status(u16 smi_sts)
+{
+	printk(BIOS_DEBUG, "SMI_STS: ");
+	if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "GPIO_RANGE_1 ");
+	if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "GPIO_RANGE_0 ");
+	if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "GP3_TIMEOUT ");
+	if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "GP2_TIMEOUT ");
+	if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "SERR_IRQ ");
+	if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "PMIO_5 ");
+	if (smi_sts & (1 <<  9)) printk(BIOS_DEBUG, "THRMTRIP# ");
+	if (smi_sts & (1 <<  8)) printk(BIOS_DEBUG, "CLKRUN# ");
+	if (smi_sts & (1 <<  7)) printk(BIOS_DEBUG, "PRIMARY_IRQ/NMI/SMI ");
+	if (smi_sts & (1 <<  6)) printk(BIOS_DEBUG, "SWSMI ");
+	if (smi_sts & (1 <<  5)) printk(BIOS_DEBUG, "BIOS_STATUS ");
+	if (smi_sts & (1 <<  4)) printk(BIOS_DEBUG, "LEGACY_USB ");
+	if (smi_sts & (1 <<  3)) printk(BIOS_DEBUG, "GP1_TIMEOUT ");
+	if (smi_sts & (1 <<  2)) printk(BIOS_DEBUG, "GP0_TIMEOUT ");
+	if (smi_sts & (1 <<  1)) printk(BIOS_DEBUG, "SECONDARY_EVENT_TIMEOUT ");
+	if (smi_sts & (1 <<  0)) printk(BIOS_DEBUG, "PRIMARY_ACTIVITY ");
+	printk(BIOS_DEBUG, "\n");
+}
+
+int southbridge_io_trap_handler(int smif)
+{
+	switch (smif) {
+	case 0x32:
+		printk(BIOS_DEBUG, "OS Init\n");
+		/* gnvs->smif:
+		 *  On success, the IO Trap Handler returns 0
+		 *  On failure, the IO Trap Handler returns a value != 0
+		 */
+		gnvs->smif = 0;
+		return 1; /* IO trap handled */
+	}
+
+	/* Not handled */
+	return 0;
+}
+
+/**
+ * @brief Set the EOS bit
+ */
+void southbridge_smi_set_eos(void)
+{
+	u8 reg8;
+
+	reg8 = inb(pmbase + SMI_EN);
+	reg8 |= EOS;
+	outb(reg8, pmbase + SMI_EN);
+}
+
+static void southbridge_smi_cmd(unsigned int node, smm_state_save_area_t *state_save)
+{
+	u16 pmctrl;
+	u8 reg8;
+
+	reg8 = inb(pmbase + 0x2f);
+	switch (reg8) {
+	case CST_CONTROL:
+		/* Calling this function seems to cause
+		 * some kind of race condition in Linux
+		 * and causes a kernel oops
+		 */
+		printk(BIOS_DEBUG, "C-state control\n");
+		break;
+	case PST_CONTROL:
+		/* Calling this function seems to cause
+		 * some kind of race condition in Linux
+		 * and causes a kernel oops
+		 */
+		printk(BIOS_DEBUG, "P-state control\n");
+		break;
+	case ACPI_DISABLE:
+		pmctrl = inw(pmbase + PM1_CNT);
+		pmctrl &= ~SCI_EN;
+		outw(pmctrl, pmbase + PM1_CNT);
+		printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
+		break;
+	case ACPI_ENABLE:
+		pmctrl = inw(pmbase + PM1_CNT);
+		pmctrl |= SCI_EN;
+		outw(pmctrl, pmbase + PM1_CNT);
+		printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n");
+		break;
+	case GNVS_UPDATE:
+		if (smm_initialized) {
+			printk(BIOS_DEBUG, "SMI#: SMM structures already initialized!\n");
+			return;
+		}
+		gnvs = *(global_nvs_t **)0x500;
+		tcg  = *(void **)0x504;
+		smi1 = *(void **)0x508;
+		smm_initialized = 1;
+		printk(BIOS_DEBUG, "SMI#: Setting up structures to %p, %p, %p\n", gnvs, tcg, smi1);
+		break;
+	default:
+		printk(BIOS_DEBUG, "SMI#: Unknown function SMI_CMD=%02x\n", reg8);
+	}
+}
+
+typedef void (*smi_handler_t)(unsigned int node,
+		smm_state_save_area_t *state_save);
+
+smi_handler_t southbridge_smi[32] = {
+	NULL,			  //  [0]
+	NULL,			  //  [1]
+	NULL,			  //  [2]
+	NULL,			  //  [3]
+	southbridge_smi_cmd,	  //  [4]
+	NULL,			  //  [5]
+	NULL,			  //  [6]
+	NULL,			  //  [7]
+	NULL,			  //  [8]
+	NULL,			  //  [9]
+	NULL,			  // [10]
+	NULL,			  // [11]
+	NULL,			  // [12]
+	NULL,			  // [13]
+	NULL,			  // [14]
+	NULL,			  // [15]
+};
+
+/**
+ * @brief Interrupt handler for SMI#
+ *
+ * @param smm_revision revision of the smm state save map
+ */
+
+void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
+{
+	int i, dump = 0;
+	u32 smi_sts;
+
+	/* Update global variable pmbase */
+	pmbase = pci_read_config16(PCI_DEV(0, 0x11, 0), 0x88) & 0xfffc;
+
+	/* We need to clear the SMI status registers, or we won't see what's
+	 * happening in the following calls.
+	 */
+	smi_sts = reset_smi_status();
+
+	/* Filter all non-enabled SMI events */
+	// FIXME Double check, this clears MONITOR
+	// smi_sts &= inl(pmbase + SMI_EN);
+
+	/* Call SMI sub handler for each of the status bits */
+	for (i = 0; i < 16; i++) {
+		if (smi_sts & (1 << i)) {
+			if (southbridge_smi[i])
+				southbridge_smi[i](node, state_save);
+			else {
+				printk(BIOS_DEBUG, "SMI_STS[%d] occured, but no "
+						"handler available.\n", i);
+				dump = 1;
+			}
+		}
+	}
+
+	if(dump) {
+		dump_smi_status(smi_sts);
+	}
+
+}
Index: src/southbridge/intel/i82801gx/i82801gx.h
===================================================================
--- src/southbridge/intel/i82801gx/i82801gx.h	(revision 6169)
+++ src/southbridge/intel/i82801gx/i82801gx.h	(working copy)
@@ -38,19 +38,17 @@ 
 #ifndef __ACPI__
 #define DEBUG_PERIODIC_SMIS 0
 
-#if !defined(ASSEMBLY)
+#if !defined(ASSEMBLY) && !defined(__ROMCC__)
 #if !defined(__PRE_RAM__)
 #include "chip.h"
 extern void i82801gx_enable(device_t dev);
+#else
+void enable_smbus(void);
+int smbus_read_byte(unsigned device, unsigned address);
 #endif
 void i82801gx_enable_usbdebug(unsigned int port);
 #endif
 
-#if defined(__PRE_RAM__) && !defined(__ROMCC__) && !defined(ASSEMBLY)
-void enable_smbus(void);
-int smbus_read_byte(unsigned device, unsigned address);
-#endif
-
 #define MAINBOARD_POWER_OFF	0
 #define MAINBOARD_POWER_ON	1
 #define MAINBOARD_POWER_KEEP	2
Index: src/southbridge/intel/i82801gx/lpc.c
===================================================================
--- src/southbridge/intel/i82801gx/lpc.c	(revision 6169)
+++ src/southbridge/intel/i82801gx/lpc.c	(working copy)
@@ -27,6 +27,7 @@ 
 #include <pc80/i8259.h>
 #include <arch/io.h>
 #include <arch/ioapic.h>
+#include <cpu/cpu.h>
 #include "i82801gx.h"
 
 #define NMI_OFF	0
@@ -335,7 +336,6 @@ 
 #if CONFIG_HAVE_SMI_HANDLER
 static void i82801gx_lock_smm(struct device *dev)
 {
-	void smm_lock(void);
 #if TEST_SMM_FLASH_LOCKDOWN
 	u8 reg8;
 #endif
Index: src/southbridge/intel/i82801gx/smi.c
===================================================================
--- src/southbridge/intel/i82801gx/smi.c	(revision 6169)
+++ src/southbridge/intel/i82801gx/smi.c	(working copy)
@@ -318,8 +318,17 @@ 
 	outb(0x00, 0xb2);
 }
 
+static int smm_handler_copied = 0;
+
 static void smm_install(void)
 {
+	/* The first CPU running this gets to copy the SMM handler. But not all
+	 * of them.
+	 */
+	if (smm_handler_copied)
+		return;
+	smm_handler_copied = 1;
+
 	/* enable the SMM memory window */
 	pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
 				D_OPEN | G_SMRAME | C_BASE_SEG);
Index: src/include/cpu/x86/smm.h
===================================================================
--- src/include/cpu/x86/smm.h	(revision 6169)
+++ src/include/cpu/x86/smm.h	(working copy)
@@ -254,7 +254,7 @@ 
 
 void io_trap_handler(int smif);
 int southbridge_io_trap_handler(int smif);
-int mainboard_io_trap_handler(int smif);
+int __attribute__((weak)) mainboard_io_trap_handler(int smif);
 
 void southbridge_smi_set_eos(void);
 
Index: src/cpu/amd/socket_S1G1/Makefile.inc
===================================================================
--- src/cpu/amd/socket_S1G1/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_S1G1/Makefile.inc	(working copy)
@@ -7,7 +7,8 @@ 
 subdirs-y += ../../x86/lapic
 subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/pae
+subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/smm
-subdirs-y += ../../x86/mtrr
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/socket_940/Makefile.inc
===================================================================
--- src/cpu/amd/socket_940/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_940/Makefile.inc	(working copy)
@@ -8,5 +8,7 @@ 
 subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/pae
+subdirs-y += ../../x86/smm
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/model_fxx/model_fxx_init.c
===================================================================
--- src/cpu/amd/model_fxx/model_fxx_init.c	(revision 6169)
+++ src/cpu/amd/model_fxx/model_fxx_init.c	(working copy)
@@ -499,11 +499,6 @@ 
 
 	k8_errata();
 
-	/* Set SMMLOCK to avoid exploits messing with SMM */
-	msr = rdmsr(HWCR_MSR);
-	msr.lo |= (1 << 0);
-	wrmsr(HWCR_MSR, msr);
-
 	enable_cache();
 
 	/* Set the processor name string */
Index: src/cpu/amd/socket_754/Makefile.inc
===================================================================
--- src/cpu/amd/socket_754/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_754/Makefile.inc	(working copy)
@@ -8,5 +8,7 @@ 
 subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/pae
+subdirs-y += ../../x86/smm
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/socket_AM2/Makefile.inc
===================================================================
--- src/cpu/amd/socket_AM2/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_AM2/Makefile.inc	(working copy)
@@ -9,5 +9,6 @@ 
 subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/pae
 subdirs-y += ../../x86/smm
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/socket_AM3/Makefile.inc
===================================================================
--- src/cpu/amd/socket_AM3/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_AM3/Makefile.inc	(working copy)
@@ -7,7 +7,8 @@ 
 subdirs-y += ../../x86/lapic
 subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/pae
+subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/smm
-subdirs-y += ../../x86/mtrr
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/socket_AM2r2/Makefile.inc
===================================================================
--- src/cpu/amd/socket_AM2r2/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_AM2r2/Makefile.inc	(working copy)
@@ -7,7 +7,8 @@ 
 subdirs-y += ../../x86/lapic
 subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/pae
+subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/smm
-subdirs-y += ../../x86/mtrr
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/socket_939/Makefile.inc
===================================================================
--- src/cpu/amd/socket_939/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_939/Makefile.inc	(working copy)
@@ -8,5 +8,7 @@ 
 subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/pae
+subdirs-y += ../../x86/smm
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/smm/smm_init.c
===================================================================
--- src/cpu/amd/smm/smm_init.c	(revision 0)
+++ src/cpu/amd/smm/smm_init.c	(revision 0)
@@ -0,0 +1,121 @@ 
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 coresystems GmbH
+ * Copyright (C) 2010 Rudolf Marek
+ *
+ * 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 <console/console.h>
+#include <arch/io.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/amd/mtrr.h>
+#include <cpu/amd/model_fxx_msr.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <string.h>
+
+#define SMM_BASE_MSR 0xc0010111
+#define SMM_ADDR_MSR 0xc0010112
+#define SMM_MASK_MSR 0xc0010113
+#define SMM_BASE 0xa0000
+
+extern unsigned char _binary_smm_start;
+extern unsigned char _binary_smm_size;
+
+static int smm_handler_copied = 0;
+
+void smm_init(void)
+{
+	msr_t msr;
+
+	msr = rdmsr(HWCR_MSR);
+	if (msr.lo & (1 << 0)) {
+		// This sounds like a bug... ? 
+		printk(BIOS_DEBUG, "SMM is still locked from last boot, using old handler.\n");
+		return;
+	}
+
+	/* Only copy SMM handler once, not once per CPU */
+	if (!smm_handler_copied) {
+		msr_t syscfg_orig, mtrr_aseg_orig;
+
+		smm_handler_copied = 1;
+
+		// XXX Really?
+		disable_cache();
+		syscfg_orig = rdmsr(SYSCFG_MSR);
+		mtrr_aseg_orig = rdmsr(MTRRfix16K_A0000_MSR);
+
+		// XXX Why?
+		msr = syscfg_orig;
+		msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;
+		msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;
+		wrmsr(SYSCFG_MSR, msr);
+
+		/* set DRAM access to 0xa0000 */
+		// XXX but why?
+		msr.lo = 0x18181818;
+		msr.hi = 0x18181818;
+		wrmsr(MTRRfix16K_A0000_MSR, msr);
+#if 0 // obviously wrong stuff from Rudolf's patch
+		msr.lo |= SYSCFG_MSR_MtrrFixDramEn;
+		wrmsr(SYSCFG_MSR, msr);
+#endif
+
+		/* enable the SMM memory window */
+		msr = rdmsr(SMM_MASK_MSR);
+		msr.lo |= (1 << 0); // Enable ASEG SMRAM Range
+		msr.lo &= ~(1 << 2); // Open ASEG SMRAM Range
+		wrmsr(SMM_MASK_MSR, msr);
+
+		/* copy the real SMM handler */
+		memcpy((void *)SMM_BASE, &_binary_smm_start, (size_t)&_binary_smm_size);
+		wbinvd();
+
+		msr = rdmsr(SMM_MASK_MSR);
+		msr.lo |= ~(1 << 2); // Close ASEG SMRAM Range
+		wrmsr(SMM_MASK_MSR, msr);
+
+#if 0 // obviously wrong stuff from Rudolf's patch
+		msr.lo &= ~SYSCFG_MSR_MtrrFixDramEn;
+		wrmsr(SYSCFG_MSR, msr);
+#endif
+		// XXX But why?
+		wrmsr(MTRRfix16K_A0000_MSR, mtrr_aseg_orig);
+		wrmsr(SYSCFG_MSR, syscfg_orig);
+		enable_cache();
+
+	}
+
+	/* But set SMM base address on all CPUs/cores */
+	msr = rdmsr(SMM_BASE_MSR);
+	msr.lo = SMM_BASE;
+	wrmsr(SMM_BASE_MSR, msr);
+}
+
+void smm_lock(void)
+{
+	msr_t msr;
+
+	printk(BIOS_DEBUG, "Locking SMM.\n");
+
+	/* Set SMMLOCK to avoid exploits messing with SMM */
+	msr = rdmsr(HWCR_MSR);
+	msr.lo |= (1 << 0);
+	wrmsr(HWCR_MSR, msr);
+}
Index: src/cpu/amd/smm/Makefile.inc
===================================================================
--- src/cpu/amd/smm/Makefile.inc	(revision 0)
+++ src/cpu/amd/smm/Makefile.inc	(revision 0)
@@ -0,0 +1,2 @@ 
+
+ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smm_init.c
Index: src/cpu/amd/socket_F/Makefile.inc
===================================================================
--- src/cpu/amd/socket_F/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_F/Makefile.inc	(working copy)
@@ -9,5 +9,6 @@ 
 subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/pae
 subdirs-y += ../../x86/smm
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/socket_ASB2/Makefile.inc
===================================================================
--- src/cpu/amd/socket_ASB2/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_ASB2/Makefile.inc	(working copy)
@@ -7,7 +7,8 @@ 
 subdirs-y += ../../x86/lapic
 subdirs-y += ../../x86/cache
 subdirs-y += ../../x86/pae
+subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/smm
-subdirs-y += ../../x86/mtrr
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/amd/socket_F_1207/Makefile.inc
===================================================================
--- src/cpu/amd/socket_F_1207/Makefile.inc	(revision 6169)
+++ src/cpu/amd/socket_F_1207/Makefile.inc	(working copy)
@@ -9,5 +9,6 @@ 
 subdirs-y += ../../x86/mtrr
 subdirs-y += ../../x86/pae
 subdirs-y += ../../x86/smm
+subdirs-y += ../smm
 
 cpu_incs += $(src)/cpu/amd/car/cache_as_ram.inc
Index: src/cpu/x86/smm/smihandler.c
===================================================================
--- src/cpu/x86/smm/smihandler.c	(revision 6169)
+++ src/cpu/x86/smm/smihandler.c	(working copy)
@@ -87,7 +87,26 @@ 
 	southbridge_smi_set_eos();
 }
 
+static u32 pci_orig;
+
 /**
+ * @brief Backup PCI address to make sure we do not mess up the OS
+ */
+static void smi_backup_pci_address(void)
+{
+	pci_orig = inl(0xcf8);
+}
+
+/**
+ * @brief Restore PCI address previously backed up
+ */
+static void smi_restore_pci_address(void)
+{
+	outl(pci_orig, 0xcf8);
+}
+
+
+/**
  * @brief Interrupt handler for SMI#
  *
  * @param smm_revision revision of the smm state save map
@@ -107,6 +126,8 @@ 
 		return;
 	}
 
+	smi_backup_pci_address();
+
 	node=nodeid();
 
 	console_init();
@@ -147,6 +168,8 @@ 
 	if (southbridge_smi_handler)
 		southbridge_smi_handler(node, &state_save);
 
+	smi_restore_pci_address();
+
 	smi_release_lock();
 
 	/* De-assert SMI# signal to allow another SMI */
Index: src/cpu/x86/smm/smmrelocate.S
===================================================================
--- src/cpu/x86/smm/smmrelocate.S	(revision 6169)
+++ src/cpu/x86/smm/smmrelocate.S	(working copy)
@@ -22,6 +22,8 @@ 
 // Make sure no stage 2 code is included:
 #define __PRE_RAM__
 
+#if !defined(CONFIG_NORTHBRIDGE_AMD_AMDK8) && !defined(CONFIG_NORTHBRIDGE_AMD_FAM10)
+
 // FIXME: Is this piece of code southbridge specific, or
 // can it be cleaned up so this include is not required?
 // It's needed right now because we get our DEFAULT_PMBASE from
@@ -175,4 +177,4 @@ 
 	/* That's it. return */
 	rsm
 smm_relocation_end:
-
+#endif
Index: src/mainboard/asus/m2v-mx_se/Kconfig
===================================================================
--- src/mainboard/asus/m2v-mx_se/Kconfig	(revision 6169)
+++ src/mainboard/asus/m2v-mx_se/Kconfig	(working copy)
@@ -37,6 +37,7 @@ 
 	select HAVE_ACPI_RESUME
 	select HAVE_MAINBOARD_RESOURCES
 	select QRANK_DIMM_SUPPORT
+	select HAVE_SMI_HANDLER
 	select SET_FIDVID
 
 config MAINBOARD_DIR