move mptable to 960k to 1M
https://openbios.org/roundup/linuxbios/issue55

This patch is a little bit enhanced, it keeps the ppc table consistent,
which Yinghai's original patch did not.



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2342 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/src/arch/i386/boot/linuxbios_table.c b/src/arch/i386/boot/linuxbios_table.c
index a625fe0..402f7f9 100644
--- a/src/arch/i386/boot/linuxbios_table.c
+++ b/src/arch/i386/boot/linuxbios_table.c
@@ -349,15 +349,22 @@
 }
 
 unsigned long write_linuxbios_table( 
-	unsigned long low_table_start, unsigned long low_table_end,
-	unsigned long rom_table_startk, unsigned long rom_table_endk)
+	unsigned long low_table_start, unsigned long low_table_end, 
+	unsigned long rom_table_start, unsigned long rom_table_end)
 {
 	unsigned long table_size;
 	struct lb_header *head;
 	struct lb_memory *mem;
 
-	head = lb_table_init(low_table_end);
-	low_table_end = (unsigned long)head;
+	if(low_table_end > (0x1000 - sizeof(struct lb_header))) { /* after 4K */
+		/* We need to put lbtable on  to [0xf0000,0x100000) */
+		head = lb_table_init(rom_table_end);
+		rom_table_end = (unsigned long)head;
+	} else {
+		head = lb_table_init(low_table_end);
+		low_table_end = (unsigned long)head;
+	}
+
 	if (HAVE_OPTION_TABLE == 1) {
 		struct lb_record *rec_dest, *rec_src;
 		/* Write the option config table... */
@@ -370,16 +377,13 @@
 	/* Record where RAM is located */
 	mem = build_lb_mem(head);
 	
-	/* Find the current mptable size */
-	table_size = (low_table_end - low_table_start);
-
 	/* Record the mptable and the the lb_table (This will be adjusted later) */
 	lb_add_memory_range(mem, LB_MEM_TABLE, 
-		low_table_start, table_size);
+		low_table_start, low_table_end - low_table_start);
 
-	/* Record the pirq table */
+	/* Record the pirq table, acpi tables, and maybe the mptable */
 	lb_add_memory_range(mem, LB_MEM_TABLE, 
-		rom_table_startk << 10, (rom_table_endk - rom_table_startk) << 10);
+		rom_table_start, rom_table_end - rom_table_start);
 
 	/* Note:
 	 * I assume that there is always memory at immediately after
@@ -393,8 +397,7 @@
 	/* Record our various random string information */
 	lb_strings(head);
 
-	low_table_end = lb_table_fini(head);
-
 	/* Remember where my valid memory ranges are */
-	return low_table_end;
+	return lb_table_fini(head);
+	
 }
diff --git a/src/arch/i386/boot/tables.c b/src/arch/i386/boot/tables.c
index d470abb..8abac2b 100644
--- a/src/arch/i386/boot/tables.c
+++ b/src/arch/i386/boot/tables.c
@@ -1,3 +1,6 @@
+
+/* 2006.1 yhlu add mptable cross 0x467 processing */
+
 #include <console/console.h>
 #include <cpu/cpu.h>
 #include <boot/tables.h>
@@ -13,8 +16,8 @@
 
 /* i386 lgdt argument */
 struct gdtarg {
-    unsigned short limit;
-    unsigned int base;
+	unsigned short limit;
+	unsigned int base;
 } __attribute__((packed));
 
 // Copy GDT to new location and reload it
@@ -23,19 +26,19 @@
 void move_gdt(unsigned long newgdt)
 {
 	uint16_t num_gdt_bytes = &gdt_end - &gdt;
-    struct gdtarg gdtarg;
+	struct gdtarg gdtarg;
 
-    printk_debug("Moving GDT to %#lx...", newgdt);
-    memcpy((void*)newgdt, &gdt, num_gdt_bytes);
-    gdtarg.base = newgdt;
-    gdtarg.limit = num_gdt_bytes - 1;
-    __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));
-    printk_debug("ok\n");
+	printk_debug("Moving GDT to %#lx...", newgdt);
+	memcpy((void*)newgdt, &gdt, num_gdt_bytes);
+	gdtarg.base = newgdt;
+	gdtarg.limit = num_gdt_bytes - 1;
+	__asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));
+	printk_debug("ok\n");
 }
 
 struct lb_memory *write_tables(void)
 {
-	unsigned long low_table_start, low_table_end;
+	unsigned long low_table_start, low_table_end, new_low_table_end;
 	unsigned long rom_table_start, rom_table_end;
 
 	rom_table_start = 0xf0000;
@@ -52,12 +55,6 @@
 	rom_table_end = write_pirq_routing_table(rom_table_end);
 	rom_table_end = (rom_table_end + 1023) & ~1023;
 
-	/* copy the smp block to address 0 */
-	post_code(0x96);
-
-	/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
-	low_table_end = write_smp_table(low_table_end);
-
 	/* Write ACPI tables */
 	/* write them in the rom area because DSDT can be large (8K on epia-m) which
 	 * pushes linuxbios table out of first 4K if set up in low table area 
@@ -66,6 +63,37 @@
 	rom_table_end = write_acpi_tables(rom_table_end);
 	rom_table_end = (rom_table_end+1023) & ~1023;
 
+	/* copy the smp block to address 0 */
+	post_code(0x96);
+
+	/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
+	new_low_table_end = write_smp_table(low_table_end);
+
+        /* Don't write anything in the traditional x86 BIOS data segment,
+         * for example the linux kernel smp need to use 0x467 to pass reset vector
+         */
+        if(new_low_table_end>0x467){
+                unsigned mptable_size = new_low_table_end - low_table_end - SMP_FLOATING_TABLE_LEN;
+                /* We can not put mptable here, we need to copy them to somewhere else*/
+                if((rom_table_end+mptable_size)<0x100000) {
+                        /* We can copy mptable on rom_table, and leave low space for lbtable  */
+                        printk_debug("move mptable to 0x%0x\n", rom_table_end);
+                        memcpy((unsigned char *)rom_table_end, (unsigned char *)(low_table_end+SMP_FLOATING_TABLE_LEN), mptable_size);
+                        memset((unsigned char *)low_table_end, '\0', mptable_size + SMP_FLOATING_TABLE_LEN);
+                        smp_write_floating_table_physaddr(low_table_end, rom_table_end);
+                        low_table_end += SMP_FLOATING_TABLE_LEN;
+                        rom_table_end += mptable_size;
+                        rom_table_end = (rom_table_end+1023) & ~1023;
+                } else {
+                        /* We can need to put mptable low and from 0x500 */
+                        printk_debug("move mptable to 0x%0x\n", 0x500);
+                        memcpy((unsigned char *)0x500, (unsigned char *)(low_table_end+SMP_FLOATING_TABLE_LEN), mptable_size);
+                        memset((unsigned char *)low_table_end, '\0', 0x500-low_table_end);
+                        smp_write_floating_table_physaddr(low_table_end, 0x500);
+                        low_table_end = 0x500 + mptable_size;
+                }
+        }
+
 	/* Don't write anything in the traditional x86 BIOS data segment */
 	if (low_table_end < 0x500) {
 		low_table_end = 0x500;
@@ -78,7 +106,7 @@
 	/* The linuxbios table must be in 0-4K or 960K-1M */
 	write_linuxbios_table(
 			      low_table_start, low_table_end,
-			      rom_table_start >> 10, rom_table_end >> 10);
+			      rom_table_start, rom_table_end);
 
 	return get_lb_mem();
 }
diff --git a/src/arch/i386/smp/mpspec.c b/src/arch/i386/smp/mpspec.c
index daeb784..797dab4 100644
--- a/src/arch/i386/smp/mpspec.c
+++ b/src/arch/i386/smp/mpspec.c
@@ -48,6 +48,30 @@
 	return v;
 }
 
+void *smp_write_floating_table_physaddr(unsigned long addr, unsigned long mpf_physptr)
+{
+        struct intel_mp_floating *mf;
+        void *v;
+
+        v = (void *)addr;
+        mf = v;
+        mf->mpf_signature[0] = '_';
+        mf->mpf_signature[1] = 'M';
+        mf->mpf_signature[2] = 'P';
+        mf->mpf_signature[3] = '_';
+        mf->mpf_physptr = mpf_physptr;
+        mf->mpf_length = 1;
+        mf->mpf_specification = 4;
+        mf->mpf_checksum = 0;
+        mf->mpf_feature1 = 0;
+        mf->mpf_feature2 = 0;
+        mf->mpf_feature3 = 0;
+        mf->mpf_feature4 = 0;
+        mf->mpf_feature5 = 0;
+        mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
+        return v;
+}
+
 void *smp_next_mpc_entry(struct mp_config_table *mc)
 {
 	void *v;
diff --git a/src/arch/ppc/boot/linuxbios_table.c b/src/arch/ppc/boot/linuxbios_table.c
index 10d3b0c..e8eefc6 100644
--- a/src/arch/ppc/boot/linuxbios_table.c
+++ b/src/arch/ppc/boot/linuxbios_table.c
@@ -332,7 +332,7 @@
 
 unsigned long write_linuxbios_table( 
 	unsigned long low_table_start, unsigned long low_table_end,
-	unsigned long rom_table_startk, unsigned long rom_table_endk)
+	unsigned long rom_table_start, unsigned long rom_table_end)
 {
 	unsigned long table_size;
 	struct lb_header *head;
@@ -359,7 +359,7 @@
 
 	/* Record the pirq table */
 	lb_add_memory_range(mem, LB_MEM_TABLE, 
-		rom_table_startk << 10, (rom_table_endk - rom_table_startk) << 10);
+		rom_table_start, (rom_table_end - rom_table_start));
 
 	/* Note:
 	 * I assume that there is always memory at immediately after
diff --git a/src/arch/ppc/boot/tables.c b/src/arch/ppc/boot/tables.c
index 7d8bd31..6fde37d 100644
--- a/src/arch/ppc/boot/tables.c
+++ b/src/arch/ppc/boot/tables.c
@@ -21,7 +21,7 @@
 	/* The linuxbios table must be in 0-4K or 960K-1M */
 	write_linuxbios_table(
 		low_table_start, low_table_end,
-		rom_table_start >> 10, rom_table_end >> 10);
+		rom_table_start, rom_table_end);
 
 	return get_lb_mem();
 }