e8de68a88a6c614c4456653116288e3211d09a91
[coreboot.git] / src / arch / i386 / boot / tables.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) .... others
5  * Copyright (C) 2008-2009 coresystems GmbH
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 /* 2006.1 yhlu add mptable cross 0x467 processing */
22
23 #include <console/console.h>
24 #include <cpu/cpu.h>
25 #include <boot/tables.h>
26 #include <boot/coreboot_tables.h>
27 #include <arch/pirq_routing.h>
28 #include <arch/smp/mpspec.h>
29 #include <arch/acpi.h>
30 #include <string.h>
31 #include <cpu/x86/multiboot.h>
32 #include "coreboot_table.h"
33
34 // Global Descriptor Table, defined in c_start.S
35 extern uint8_t gdt;
36 extern uint8_t gdt_end;
37
38 /* i386 lgdt argument */
39 struct gdtarg {
40         unsigned short limit;
41         unsigned int base;
42 } __attribute__((packed));
43
44 // Copy GDT to new location and reload it
45 // 2003-07 by SONE Takeshi
46 // Ported from Etherboot to coreboot 2005-08 by Steve Magnani
47 void move_gdt(unsigned long newgdt)
48 {
49         uint16_t num_gdt_bytes = &gdt_end - &gdt;
50         struct gdtarg gdtarg;
51
52         printk_debug("Moving GDT to %#lx...", newgdt);
53         memcpy((void*)newgdt, &gdt, num_gdt_bytes);
54         gdtarg.base = newgdt;
55         gdtarg.limit = num_gdt_bytes - 1;
56         __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));
57         printk_debug("ok\n");
58 }
59
60 #if HAVE_HIGH_TABLES == 1
61 uint64_t high_tables_base = 0;
62 uint64_t high_tables_size;
63 #endif
64
65 struct lb_memory *write_tables(void)
66 {
67         unsigned long low_table_start, low_table_end, new_low_table_end;
68         unsigned long rom_table_start, rom_table_end;
69
70 #if HAVE_HIGH_TABLES == 1
71         /* Even if high tables are configured, all tables are copied both to the
72          * low and the high area, so payloads and OSes don't need to know about
73          * the high tables.
74          */
75         unsigned long high_table_start, high_table_end=0;
76
77         if (high_tables_base) {
78                 printk_debug("High Tables Base is %lx.\n", high_tables_base);
79                 high_table_start = high_tables_base;
80                 high_table_end = high_tables_base;
81         } else {
82                 printk_debug("High Tables Base is not set.\n");
83         }
84 #endif
85
86         rom_table_start = 0xf0000; 
87         rom_table_end =   0xf0000;
88         /* Start low addr at 16 bytes instead of 0 because of a buglet
89          * in the generic linux unzip code, as it tests for the a20 line.
90          */
91         low_table_start = 0;
92         low_table_end = 16;
93
94         post_code(0x9a);
95
96 #if HAVE_LOW_TABLES == 1
97         /* This table must be betweeen 0xf0000 & 0x100000 */
98         rom_table_end = write_pirq_routing_table(rom_table_end);
99         rom_table_end = (rom_table_end + 1023) & ~1023;
100 #endif
101 #if HAVE_HIGH_TABLES == 1
102         if (high_tables_base) {
103                 high_table_end = write_pirq_routing_table(high_table_end);
104                 high_table_end = (high_table_end + 1023) & ~1023;
105         }
106 #endif
107
108         /* Write ACPI tables */
109         /* write them in the rom area because DSDT can be large (8K on epia-m) which
110          * pushes coreboot table out of first 4K if set up in low table area 
111          */
112 #if HAVE_LOW_TABLES == 1
113         rom_table_end = write_acpi_tables(rom_table_end);
114         rom_table_end = (rom_table_end+1023) & ~1023;
115 #endif
116 #if HAVE_HIGH_TABLES == 1
117         if (high_tables_base) {
118                 high_table_end = write_acpi_tables(high_table_end);
119                 high_table_end = (high_table_end+1023) & ~1023;
120         }
121 #endif
122         /* copy the smp block to address 0 */
123         post_code(0x96);
124
125         /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
126 #if HAVE_LOW_TABLES == 1
127         new_low_table_end = write_smp_table(low_table_end); // low_table_end is 0x10 at this point
128 #endif
129 #if HAVE_HIGH_TABLES == 1
130         if (high_tables_base) {
131                 high_table_end = write_smp_table(high_table_end);
132                 high_table_end = (high_table_end+1023) & ~1023;
133         }
134 #endif
135
136 #if HAVE_MP_TABLE == 1
137         /* Don't write anything in the traditional x86 BIOS data segment,
138          * for example the linux kernel smp need to use 0x467 to pass reset vector
139          * or use 0x40e/0x413 for EBDA finding...
140          */
141         if(new_low_table_end>0x400){
142                 unsigned mptable_size;
143                 unsigned mpc_start;
144                 low_table_end += SMP_FLOATING_TABLE_LEN; /* keep the mpf in 1k low, so kernel can find it */
145                 mptable_size = new_low_table_end - low_table_end;
146                 /* We can not put mptable low, we need to copy them to somewhere else*/
147                 if((rom_table_end+mptable_size)<0x100000) {
148                         /* We can copy mptable on rom_table  */
149                         mpc_start = rom_table_end;
150                         rom_table_end += mptable_size;
151                         rom_table_end = (rom_table_end+1023) & ~1023;
152                 } else {
153                         /* We can need to put mptable before rom_table */
154                         mpc_start = rom_table_start - mptable_size;
155                         mpc_start &= ~1023;
156                         rom_table_start = mpc_start;
157                 }
158                 printk_debug("move mptable from 0x%0lx to 0x%0x, size 0x%0x\n", low_table_end, mpc_start, mptable_size);
159                 memcpy((unsigned char *)mpc_start, (unsigned char *)low_table_end, mptable_size);
160                 smp_write_floating_table_physaddr(low_table_end - SMP_FLOATING_TABLE_LEN, mpc_start);
161                 memset((unsigned char *)low_table_end, '\0', mptable_size);
162         }
163 #endif
164
165         if (low_table_end < 0x500) {
166                 low_table_end = 0x500;
167         }
168
169         // Relocate the GDT to reserved memory, so it won't get clobbered
170 #if HAVE_HIGH_TABLES == 1
171         if (high_tables_base) {
172                 move_gdt(high_table_end);
173                 high_table_end += &gdt_end - &gdt;
174                 high_table_end = (high_table_end+1023) & ~1023;
175         } else {
176 #endif
177                 move_gdt(low_table_end);
178                 low_table_end += &gdt_end - &gdt;
179 #if HAVE_HIGH_TABLES == 1
180         }
181 #endif
182
183 #if CONFIG_MULTIBOOT
184         /* The Multiboot information structure */
185         mbi = rom_table_end;
186         rom_table_end = write_multiboot_info(
187                                 low_table_start, low_table_end,
188                                 rom_table_start, rom_table_end);
189 #endif
190
191         /* The coreboot table must be in 0-4K or 960K-1M */
192         write_coreboot_table(low_table_start, low_table_end,
193                               rom_table_start, rom_table_end);
194
195 #if 0 && HAVE_HIGH_TABLES == 1
196         /* This is currently broken and should be severely refactored. Ideally
197          * we only have a pointer to the coreboot table in the low memory, so
198          * anyone can find the real position.
199          * write_coreboot_table does a lot more than just writing the coreboot
200          * table. It magically decides where the table should go, and therefore
201          * it consumes two base addresses. If we call write_coreboot_table like
202          * below, we get weird effects.
203          */
204         /* And we want another copy in high area because the low area might be
205          * corrupted
206          */
207         if (high_tables_base) {
208                 write_coreboot_table(high_table_start, high_table_end,
209                                       high_table_start, high_table_end);
210         }
211 #endif
212  
213         return get_lb_mem();
214 }