AGESA: Disable CAR with empty stack

Calling disable_cache_as_ram() with valuables in stack is not
a stable solution, as per documentation AMD_DISABLE_STACK
should destroy stack in cache.

Change-Id: I986bb7a88f53f7f7a0b05d4edcd5020f5dbeb4b7
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/18626
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
diff --git a/src/cpu/amd/agesa/cache_as_ram.inc b/src/cpu/amd/agesa/cache_as_ram.inc
index 1258d15..857873a 100644
--- a/src/cpu/amd/agesa/cache_as_ram.inc
+++ b/src/cpu/amd/agesa/cache_as_ram.inc
@@ -26,12 +26,8 @@
 #include "gcccar.inc"
 #include <cpu/x86/cache.h>
 
-/*
- * XMM map:
- */
-
 .code32
-.globl cache_as_ram_setup, disable_cache_as_ram, cache_as_ram_setup_out
+.globl cache_as_ram_setup, cache_as_ram_setup_out
 
 cache_as_ram_setup:
 
@@ -110,17 +106,13 @@
   pushl $0x0
   pushl %ebp
   call  romstage_main
+  movl  %eax, %ebx
 
-  /* Should never see this postcode */
-  post_code(0xaf)
-stop:
-  jmp stop
+/* Register %ebx is new stacktop for remaining of romstage.
+ * It is the only register preserved in AMD_DISABLE_STACK.
+ */
 
 disable_cache_as_ram:
-  /* Save return stack */
-  movd 0(%esp), %xmm1
-  movd %esp, %xmm0
-
   /* Disable cache */
   movl	%cr0, %eax
   orl	$CR0_CacheDisable, %eax
@@ -132,12 +124,13 @@
   movl %cr0, %eax
   andl $0x9fffffff, %eax
   movl %eax, %cr0
-  xorl %eax, %eax
 
-  /* Restore the return stack */
-  wbinvd
-  movd %xmm0, %esp
-  movd %xmm1, (%esp)
-  ret
+  movl  %ebx, %esp
+  call  romstage_after_car
+
+  /* Should never see this postcode */
+  post_code(0xaf)
+stop:
+  jmp stop
 
 cache_as_ram_setup_out:
diff --git a/src/cpu/amd/agesa/family12/romstage.c b/src/cpu/amd/agesa/family12/romstage.c
index 13b9f06..8f4e81a 100644
--- a/src/cpu/amd/agesa/family12/romstage.c
+++ b/src/cpu/amd/agesa/family12/romstage.c
@@ -14,8 +14,6 @@
  * GNU General Public License for more details.
  */
 
-#include <arch/stages.h>
-
 #include <console/console.h>
 #include <cpu/amd/car.h>
 
@@ -49,8 +47,15 @@
 	post_code(0x37);
 	agesawrapper_amdinitearly();
 
+	printk(BIOS_INFO, "Normal boot\n");
+
 	post_code(0x38);
 	agesawrapper_amdinitpost();
+}
+
+void agesa_postcar(struct sysinfo *cb)
+{
+	printk(BIOS_INFO, "Normal boot postcar\n");
 
 	post_code(0x39);
 	printk(BIOS_DEBUG, "sb_before_pci_init ");
@@ -59,7 +64,4 @@
 
 	post_code(0x40);
 	agesawrapper_amdinitenv();
-
-	post_code(0x43);
-	copy_and_run();
 }
diff --git a/src/cpu/amd/agesa/family14/romstage.c b/src/cpu/amd/agesa/family14/romstage.c
index b8c9bd3..e89b2fc 100644
--- a/src/cpu/amd/agesa/family14/romstage.c
+++ b/src/cpu/amd/agesa/family14/romstage.c
@@ -14,9 +14,6 @@
  * GNU General Public License for more details.
  */
 
-#include <arch/stages.h>
-#include <cpu/amd/agesa/s3_resume.h>
-
 #include <console/console.h>
 #include <cpu/amd/car.h>
 
@@ -51,32 +48,31 @@
 
 		post_code(0x40);
 		agesawrapper_amdinitpost();
+	} else {
+		printk(BIOS_INFO, "S3 detected\n");
+
+		post_code(0x60);
+		agesawrapper_amdinitresume();
+	}
+}
+
+void agesa_postcar(struct sysinfo *cb)
+{
+	if (!cb->s3resume) {
+		printk(BIOS_INFO, "Normal boot postcar\n");
 
 		post_code(0x41);
 		agesawrapper_amdinitenv();
 
 		post_code(0x42);
 		amd_initenv();
-
 	} else {
-		printk(BIOS_INFO, "S3 detected\n");
-
-		post_code(0x60);
-
-		agesawrapper_amdinitresume();
+		printk(BIOS_INFO, "S3 resume postcar\n");
 
 		post_code(0x61);
-
 		agesawrapper_amds3laterestore();
 
 		post_code(0x62);
-
-		prepare_for_resume();
 	}
-
-	post_code(0x50);
-	copy_and_run();
-
-	/* Not reached */
 }
 
diff --git a/src/cpu/amd/agesa/family15/romstage.c b/src/cpu/amd/agesa/family15/romstage.c
index 1c23308..7b5c0bc 100644
--- a/src/cpu/amd/agesa/family15/romstage.c
+++ b/src/cpu/amd/agesa/family15/romstage.c
@@ -16,8 +16,6 @@
 
 #include <lib.h>
 #include <reset.h>
-#include <arch/stages.h>
-#include <cpu/amd/agesa/s3_resume.h>
 
 #include <console/console.h>
 #include <cpu/amd/car.h>
@@ -73,17 +71,13 @@
 	post_code(0x40);
 	agesawrapper_amdinitpost();
 
+	printk(BIOS_INFO, "Normal boot\n");
+}
+
+void agesa_postcar(struct sysinfo *cb)
+{
+	printk(BIOS_INFO, "Normal boot postcar\n");
+
 	post_code(0x41);
 	agesawrapper_amdinitenv();
-	post_code(0x42);
-
-	post_code(0x50);
-	print_debug("Disabling cache as ram ");
-	disable_cache_as_ram();
-	print_debug("done\n");
-
-	post_code(0x51);
-	copy_and_run();
-
-	/* Not reached */
 }
diff --git a/src/cpu/amd/agesa/family15rl/romstage.c b/src/cpu/amd/agesa/family15rl/romstage.c
index 25cd987..369ae33 100644
--- a/src/cpu/amd/agesa/family15rl/romstage.c
+++ b/src/cpu/amd/agesa/family15rl/romstage.c
@@ -14,9 +14,6 @@
  * GNU General Public License for more details.
  */
 
-#include <arch/stages.h>
-#include <cpu/amd/agesa/s3_resume.h>
-
 #include <console/console.h>
 #include <cpu/amd/car.h>
 
@@ -43,29 +40,32 @@
 	agesawrapper_amdinitearly();
 
 	if (!cb->s3resume) {
+		printk(BIOS_INFO, "Normal boot\n");
+
 		post_code(0x40);
 		agesawrapper_amdinitpost();
-
-		post_code(0x41);
-		agesawrapper_amdinitenv();
-
-		disable_cache_as_ram();
 	} else {
 		printk(BIOS_INFO, "S3 detected\n");
 
 		post_code(0x60);
 		agesawrapper_amdinitresume();
-
-		amd_initcpuio();
-		agesawrapper_amds3laterestore();
-
-		post_code(0x61);
-		prepare_for_resume();
 	}
 
-	post_code(0x50);
-	copy_and_run();
-
-	/* Not reached */
 }
+void agesa_postcar(struct sysinfo *cb)
+{
+	if (!cb->s3resume) {
+		printk(BIOS_INFO, "Normal boot postcar\n");
 
+		post_code(0x41);
+		agesawrapper_amdinitenv();
+	} else {
+		printk(BIOS_INFO, "S3 resume postcar\n");
+
+		post_code(0x61);
+		amd_initcpuio();
+
+		post_code(0x62);
+		agesawrapper_amds3laterestore();
+	}
+}
diff --git a/src/cpu/amd/agesa/family15tn/romstage.c b/src/cpu/amd/agesa/family15tn/romstage.c
index 55bb4b1..fc1aeee 100644
--- a/src/cpu/amd/agesa/family15tn/romstage.c
+++ b/src/cpu/amd/agesa/family15tn/romstage.c
@@ -15,9 +15,6 @@
  * GNU General Public License for more details.
  */
 
-#include <arch/stages.h>
-#include <cpu/amd/agesa/s3_resume.h>
-
 #include <console/console.h>
 #include <cpu/amd/car.h>
 
@@ -45,28 +42,32 @@
 	agesawrapper_amdinitearly();
 
 	if (!cb->s3resume) {
+		printk(BIOS_INFO, "Normal boot\n");
+
 		post_code(0x40);
 		agesawrapper_amdinitpost();
-
-		post_code(0x41);
-		agesawrapper_amdinitenv();
-
-		disable_cache_as_ram();
 	} else {
 		printk(BIOS_INFO, "S3 detected\n");
 
 		post_code(0x60);
 		agesawrapper_amdinitresume();
+	}
+}
 
-		amd_initcpuio();
-		agesawrapper_amds3laterestore();
+void agesa_postcar(struct sysinfo *cb)
+{
+	if (!cb->s3resume) {
+		printk(BIOS_INFO, "Normal boot postcar\n");
+
+		post_code(0x41);
+		agesawrapper_amdinitenv();
+	} else {
+		printk(BIOS_INFO, "S3 resume postcar\n");
 
 		post_code(0x61);
-		prepare_for_resume();
+		amd_initcpuio();
+
+		post_code(0x62);
+		agesawrapper_amds3laterestore();
 	}
-
-	post_code(0x50);
-	copy_and_run();
-
-	/* Not reached */
 }
diff --git a/src/cpu/amd/agesa/family16kb/romstage.c b/src/cpu/amd/agesa/family16kb/romstage.c
index 175ea54..e0fff35 100644
--- a/src/cpu/amd/agesa/family16kb/romstage.c
+++ b/src/cpu/amd/agesa/family16kb/romstage.c
@@ -14,9 +14,6 @@
  * GNU General Public License for more details.
  */
 
-#include <arch/stages.h>
-#include <cpu/amd/agesa/s3_resume.h>
-
 #include <console/console.h>
 #include <cpu/amd/car.h>
 
@@ -43,30 +40,35 @@
 	agesawrapper_amdinitearly();
 
 	if (!cb->s3resume) {
+		printk(BIOS_INFO, "Normal boot\n");
+
 		post_code(0x40);
 		agesawrapper_amdinitpost();
 
-		post_code(0x41);
-		agesawrapper_amdinitenv();
-
-		/* TODO: Disable cache is not ok. */
-		disable_cache_as_ram();
 	} else {
 		printk(BIOS_INFO, "S3 detected\n");
 
 		post_code(0x60);
 		agesawrapper_amdinitresume();
-
-		amd_initcpuio();
-		agesawrapper_amds3laterestore();
-
-		post_code(0x61);
-		prepare_for_resume();
 	}
-
-	post_code(0x50);
-	copy_and_run();
-
-	/* Not reached */
 }
 
+void agesa_postcar(struct sysinfo *cb)
+{
+	if (!cb->s3resume) {
+		printk(BIOS_INFO, "Normal boot postcar\n");
+
+		post_code(0x41);
+		agesawrapper_amdinitenv();
+	} else {
+		printk(BIOS_INFO, "S3 resume postcar\n");
+
+		post_code(0x61);
+		amd_initcpuio();
+
+		post_code(0x62);
+		agesawrapper_amds3laterestore();
+
+		post_code(0x63);
+	}
+}
diff --git a/src/cpu/amd/agesa/romstage.c b/src/cpu/amd/agesa/romstage.c
index f77bab9..11a62ad 100644
--- a/src/cpu/amd/agesa/romstage.c
+++ b/src/cpu/amd/agesa/romstage.c
@@ -15,11 +15,17 @@
 
 #include <arch/acpi.h>
 #include <arch/cpu.h>
+#include <cbmem.h>
 #include <cpu/amd/car.h>
+#include <cpu/amd/agesa/s3_resume.h>
 #include <cpu/x86/bist.h>
+#include <cpu/x86/mtrr.h>
 #include <console/console.h>
+#include <halt.h>
+#include <program_loading.h>
 #include <smp/node.h>
 #include <string.h>
+#include <northbridge/amd/agesa/agesa_helper.h>
 #include <northbridge/amd/agesa/state_machine.h>
 
 static void fill_sysinfo(struct sysinfo *cb)
@@ -51,6 +57,33 @@
 
 	agesa_main(cb);
 
-	/* Not reached */
-	return NULL;
+	uintptr_t stack_top = CACHE_TMP_RAMTOP;
+	if (cb->s3resume) {
+		if (cbmem_recovery(1)) {
+			printk(BIOS_EMERG, "Unable to recover CBMEM\n");
+			halt();
+		}
+		stack_top = romstage_ram_stack_base(HIGH_ROMSTAGE_STACK_SIZE,
+			ROMSTAGE_STACK_CBMEM);
+		stack_top += HIGH_ROMSTAGE_STACK_SIZE;
+	}
+
+	printk(BIOS_DEBUG, "Move CAR stack.\n");
+	return (void*)stack_top;
+}
+
+void asmlinkage romstage_after_car(void)
+{
+	struct sysinfo romstage_state;
+	struct sysinfo *cb = &romstage_state;
+
+	printk(BIOS_DEBUG, "CAR disabled.\n");
+
+	fill_sysinfo(cb);
+	agesa_postcar(cb);
+
+	if (cb->s3resume)
+		set_resume_cache();
+
+	run_ramstage();
 }
diff --git a/src/cpu/amd/agesa/s3_resume.c b/src/cpu/amd/agesa/s3_resume.c
index f45ff3c..8aaa25b 100644
--- a/src/cpu/amd/agesa/s3_resume.c
+++ b/src/cpu/amd/agesa/s3_resume.c
@@ -51,7 +51,7 @@
 #endif
 }
 
-static void set_resume_cache(void)
+void set_resume_cache(void)
 {
 	msr_t msr;
 
diff --git a/src/cpu/amd/agesa/s3_resume.h b/src/cpu/amd/agesa/s3_resume.h
index b10489e..bb65af3 100644
--- a/src/cpu/amd/agesa/s3_resume.h
+++ b/src/cpu/amd/agesa/s3_resume.h
@@ -18,6 +18,7 @@
 
 void restore_mtrr(void);
 void prepare_for_resume(void);
+void set_resume_cache(void);
 
 void backup_mtrr(void *mtrr_store, u32 *mtrr_store_size);
 const void *OemS3Saved_MTRR_Storage(void);