1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rombios32.c,v 1.22 2008/01/27 17:57:26 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // 32 bit Bochs BIOS init code
6 // Copyright (C) 2006 Fabrice Bellard
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "util.h" // BX_INFO
23 #include "cmos.h" // inb_cmos
26 #define BX_APPNAME "Bochs"
28 #define ACPI_DATA_SIZE 0x00010000L
29 #define PM_IO_BASE 0xb000
30 #define SMB_IO_BASE 0xb100
31 #define CPU_COUNT_ADDR 0xf000
33 /* if true, put the MP float table and ACPI RSDT in EBDA and the MP
34 table in RAM. Unfortunately, Linux has bugs with that, so we prefer
35 to modify the BIOS in shadow RAM */
36 //#define BX_USE_EBDA_TABLES
38 /* define it if the (emulated) hardware supports SMM mode */
41 #define cpuid(index, eax, ebx, ecx, edx) \
42 asm volatile ("cpuid" \
43 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
46 #define wbinvd() asm volatile("wbinvd")
48 #define CPUID_APIC (1 << 9)
50 #define APIC_BASE ((u8 *)0xfee00000)
51 #define APIC_ICR_LOW 0x300
52 #define APIC_SVR 0x0F0
54 #define APIC_LVT3 0x370
56 #define APIC_ENABLED 0x0100
58 #define AP_BOOT_ADDR 0x10000
60 #define MPTABLE_MAX_SIZE 0x00002000
61 #define SMI_CMD_IO_ADDR 0xb2
63 #define BIOS_TMP_STORAGE 0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */
65 static inline void writel(void *addr, u32 val)
67 *(volatile u32 *)addr = val;
70 static inline void writew(void *addr, u16 val)
72 *(volatile u16 *)addr = val;
75 static inline void writeb(void *addr, u8 val)
77 *(volatile u8 *)addr = val;
80 static inline u32 readl(const void *addr)
82 return *(volatile const u32 *)addr;
85 static inline u16 readw(const void *addr)
87 return *(volatile const u16 *)addr;
90 static inline u8 readb(const void *addr)
92 return *(volatile const u8 *)addr;
98 u32 cpuid_ext_features;
99 unsigned long ram_size;
101 #ifdef BX_USE_EBDA_TABLES
102 unsigned long ebda_cur_addr;
105 u32 pm_io_base, smb_io_base;
107 unsigned long bios_table_cur_addr;
108 unsigned long bios_table_end_addr;
110 void uuid_probe(void)
113 u32 eax, ebx, ecx, edx;
115 // check if backdoor port exists
116 asm volatile ("outl %%eax, %%dx"
117 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
118 : "a" (0x564d5868), "c" (0xa), "d" (0x5658));
119 if (ebx == 0x564d5868) {
120 u32 *uuid_ptr = (u32 *)bios_uuid;
122 asm volatile ("outl %%eax, %%dx"
123 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
124 : "a" (0x564d5868), "c" (0x13), "d" (0x5658));
133 memset(bios_uuid, 0, 16);
139 u32 eax, ebx, ecx, edx;
140 cpuid(1, eax, ebx, ecx, edx);
141 cpuid_signature = eax;
142 cpuid_features = edx;
143 cpuid_ext_features = ecx;
148 if (inb_cmos(0x34) | inb_cmos(0x35))
149 ram_size = (inb_cmos(0x34) | (inb_cmos(0x35) << 8)) * 65536 +
152 ram_size = (inb_cmos(0x17) | (inb_cmos(0x18) << 8)) * 1024;
153 #ifdef BX_USE_EBDA_TABLES
154 ebda_cur_addr = ((*(u16 *)(0x40e)) << 4) + 0x380;
156 BX_INFO("ram_size=0x%08lx\n", ram_size);
159 /****************************************************/
162 extern u8 smp_ap_boot_code_start;
163 extern u8 smp_ap_boot_code_end;
165 /* find the number of CPUs by launching a SIPI to them */
168 u32 val, sipi_vector;
171 if (cpuid_features & CPUID_APIC) {
173 /* enable local APIC */
174 val = readl(APIC_BASE + APIC_SVR);
176 writel(APIC_BASE + APIC_SVR, val);
178 writew((void *)CPU_COUNT_ADDR, 1);
179 /* copy AP boot code */
180 memcpy((void *)AP_BOOT_ADDR, &smp_ap_boot_code_start,
181 &smp_ap_boot_code_end - &smp_ap_boot_code_start);
184 writel(APIC_BASE + APIC_ICR_LOW, 0x000C4500);
185 sipi_vector = AP_BOOT_ADDR >> 12;
186 writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector);
190 smp_cpus = readw((void *)CPU_COUNT_ADDR);
192 BX_INFO("Found %d cpu(s)\n", smp_cpus);
195 /****************************************************/
198 #define PCI_ADDRESS_SPACE_MEM 0x00
199 #define PCI_ADDRESS_SPACE_IO 0x01
200 #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08
202 #define PCI_ROM_SLOT 6
203 #define PCI_NUM_REGIONS 7
205 #define PCI_DEVICES_MAX 64
207 #define PCI_VENDOR_ID 0x00 /* 16 bits */
208 #define PCI_DEVICE_ID 0x02 /* 16 bits */
209 #define PCI_COMMAND 0x04 /* 16 bits */
210 #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
211 #define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
212 #define PCI_CLASS_DEVICE 0x0a /* Device class */
213 #define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
214 #define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
215 #define PCI_MIN_GNT 0x3e /* 8 bits */
216 #define PCI_MAX_LAT 0x3f /* 8 bits */
218 typedef struct PCIDevice {
223 static u32 pci_bios_io_addr;
224 static u32 pci_bios_mem_addr;
225 static u32 pci_bios_bigmem_addr;
226 /* host irqs corresponding to PCI irqs A-D */
227 static u8 pci_irqs[4] = { 11, 9, 11, 9 };
228 static PCIDevice i440_pcidev;
230 static void pci_config_writel(PCIDevice *d, u32 addr, u32 val)
232 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
236 static void pci_config_writew(PCIDevice *d, u32 addr, u32 val)
238 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
239 outw(val, 0xcfc + (addr & 2));
242 static void pci_config_writeb(PCIDevice *d, u32 addr, u32 val)
244 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
245 outb(val, 0xcfc + (addr & 3));
248 static u32 pci_config_readl(PCIDevice *d, u32 addr)
250 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
254 static u32 pci_config_readw(PCIDevice *d, u32 addr)
256 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
257 return inw(0xcfc + (addr & 2));
260 static u32 pci_config_readb(PCIDevice *d, u32 addr)
262 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
263 return inb(0xcfc + (addr & 3));
266 static void pci_set_io_region_addr(PCIDevice *d, int region_num, u32 addr)
271 if ( region_num == PCI_ROM_SLOT ) {
274 ofs = 0x10 + region_num * 4;
277 old_addr = pci_config_readl(d, ofs);
279 pci_config_writel(d, ofs, addr);
280 BX_INFO("region %d: 0x%08x\n", region_num, addr);
282 /* enable memory mappings */
283 cmd = pci_config_readw(d, PCI_COMMAND);
284 if ( region_num == PCI_ROM_SLOT )
286 else if (old_addr & PCI_ADDRESS_SPACE_IO)
290 pci_config_writew(d, PCI_COMMAND, cmd);
293 /* return the global irq number corresponding to a given device irq
294 pin. We could also use the bus number to have a more precise
296 static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
299 slot_addend = (pci_dev->devfn >> 3) - 1;
300 return (irq_num + slot_addend) & 3;
304 copy_bios(PCIDevice *d, int v)
306 pci_config_writeb(d, 0x59, v);
307 memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000);
310 // Test if 'addr' is in the range from 'start'..'start+size'
311 #define IN_RANGE(addr, start, size) ({ \
312 u32 __addr = (addr); \
313 u32 __start = (start); \
314 u32 __size = (size); \
315 (__addr - __start < __size); \
318 static void bios_shadow_init(PCIDevice *d)
320 bios_table_cur_addr = 0xf0000 | OFFSET_freespace2_start;
321 bios_table_end_addr = 0xf0000 | OFFSET_freespace2_end;
322 BX_INFO("bios_table_addr: 0x%08lx end=0x%08lx\n",
323 bios_table_cur_addr, bios_table_end_addr);
325 /* remap the BIOS to shadow RAM an keep it read/write while we
326 are writing tables */
327 int v = pci_config_readb(d, 0x59);
329 pci_config_writeb(d, 0x59, v);
330 memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000);
333 if (IN_RANGE((u32)copy_bios, 0xf0000, 0x10000)) {
334 // Current code is in shadowed area. Perform the copy from
335 // the code that is in the temporary location.
336 u32 pos = (u32)copy_bios - 0xf0000 + BIOS_TMP_STORAGE;
337 void (*func)(PCIDevice *, int) = (void*)pos;
343 // Clear the area just copied.
344 memcpy((void *)BIOS_TMP_STORAGE, 0, 0x10000);
349 static void bios_lock_shadow_ram(void)
351 PCIDevice *d = &i440_pcidev;
355 v = pci_config_readb(d, 0x59);
356 v = (v & 0x0f) | (0x10);
357 pci_config_writeb(d, 0x59, v);
360 static void pci_bios_init_bridges(PCIDevice *d)
362 u16 vendor_id, device_id;
364 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
365 device_id = pci_config_readw(d, PCI_DEVICE_ID);
367 if (vendor_id == 0x8086 && device_id == 0x7000) {
375 for(i = 0; i < 4; i++) {
377 /* set to trigger level */
378 elcr[irq >> 3] |= (1 << (irq & 7));
379 /* activate irq remapping in PIIX */
380 pci_config_writeb(d, 0x60 + i, irq);
382 outb(elcr[0], 0x4d0);
383 outb(elcr[1], 0x4d1);
384 BX_INFO("PIIX3 init: elcr=%02x %02x\n",
386 } else if (vendor_id == 0x8086 && device_id == 0x1237) {
387 /* i440 PCI bridge */
393 ".globl smp_ap_boot_code_start\n"
394 ".globl smp_ap_boot_code_end\n"
395 ".global smm_relocation_start\n"
396 ".global smm_relocation_end\n"
397 ".global smm_code_start\n"
398 ".global smm_code_end\n"
401 "smp_ap_boot_code_start:\n"
404 " incw " __stringify(CPU_COUNT_ADDR) "\n"
408 "smp_ap_boot_code_end:\n"
410 /* code to relocate SMBASE to 0xa0000 */
411 "smm_relocation_start:\n"
412 " mov $0x38000 + 0x7efc, %ebx\n"
413 " addr32 mov (%ebx), %al\n" /* revision ID to see if x86_64 or x86 */
416 " mov $0x38000 + 0x7ef8, %ebx\n"
419 " mov $0x38000 + 0x7f00, %ebx\n"
421 " movl $0xa0000, %eax\n"
422 " addr32 movl %eax, (%ebx)\n"
423 /* indicate to the BIOS that the SMM code was executed */
428 "smm_relocation_end:\n"
430 /* minimal SMM code to enable or disable ACPI */
438 " mov $" __stringify(PM_IO_BASE) " + 0x04, %dx\n" /* PMCNTRL */
450 " mov $" __stringify(PM_IO_BASE) " + 0x04, %dx\n" /* PMCNTRL */
461 extern u8 smm_relocation_start, smm_relocation_end;
462 extern u8 smm_code_start, smm_code_end;
465 static void smm_init(PCIDevice *d)
469 /* check if SMM init is already done */
470 value = pci_config_readl(d, 0x58);
471 if ((value & (1 << 25)) == 0) {
473 /* copy the SMM relocation code */
474 memcpy((void *)0x38000, &smm_relocation_start,
475 &smm_relocation_end - &smm_relocation_start);
477 /* enable SMI generation when writing to the APMC register */
478 pci_config_writel(d, 0x58, value | (1 << 25));
480 /* init APM status port */
483 /* raise an SMI interrupt */
486 /* wait until SMM code executed */
487 while (inb(0xb3) != 0x00);
489 /* enable the SMM memory window */
490 pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x48);
492 /* copy the SMM code */
493 memcpy((void *)0xa8000, &smm_code_start,
494 &smm_code_end - &smm_code_start);
497 /* close the SMM memory window and enable normal SMM */
498 pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08);
503 static void pci_bios_init_device(PCIDevice *d)
507 int i, pin, pic_irq, vendor_id, device_id;
509 class = pci_config_readw(d, PCI_CLASS_DEVICE);
510 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
511 device_id = pci_config_readw(d, PCI_DEVICE_ID);
512 BX_INFO("PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n",
513 d->bus, d->devfn, vendor_id, device_id);
516 if (vendor_id == 0x8086 && device_id == 0x7010) {
518 pci_config_writew(d, 0x40, 0x8000); // enable IDE0
519 pci_config_writew(d, 0x42, 0x8000); // enable IDE1
522 /* IDE: we map it as in ISA mode */
523 pci_set_io_region_addr(d, 0, 0x1f0);
524 pci_set_io_region_addr(d, 1, 0x3f4);
525 pci_set_io_region_addr(d, 2, 0x170);
526 pci_set_io_region_addr(d, 3, 0x374);
530 if (vendor_id != 0x1234)
532 /* VGA: map frame buffer to default Bochs VBE address */
533 pci_set_io_region_addr(d, 0, 0xE0000000);
537 if (vendor_id == 0x1014) {
539 if (device_id == 0x0046 || device_id == 0xFFFF) {
541 pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
546 if (vendor_id == 0x0106b &&
547 (device_id == 0x0017 || device_id == 0x0022)) {
549 pci_set_io_region_addr(d, 0, 0x80800000);
554 /* default memory mappings */
555 for(i = 0; i < PCI_NUM_REGIONS; i++) {
559 if (i == PCI_ROM_SLOT)
563 pci_config_writel(d, ofs, 0xffffffff);
564 val = pci_config_readl(d, ofs);
566 size = (~(val & ~0xf)) + 1;
567 if (val & PCI_ADDRESS_SPACE_IO)
568 paddr = &pci_bios_io_addr;
569 else if (size >= 0x04000000)
570 paddr = &pci_bios_bigmem_addr;
572 paddr = &pci_bios_mem_addr;
573 *paddr = (*paddr + size - 1) & ~(size - 1);
574 pci_set_io_region_addr(d, i, *paddr);
581 /* map the interrupt */
582 pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
584 pin = pci_slot_get_pirq(d, pin - 1);
585 pic_irq = pci_irqs[pin];
586 pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
589 if (vendor_id == 0x8086 && device_id == 0x7113) {
590 /* PIIX4 Power Management device (for ACPI) */
591 pm_io_base = PM_IO_BASE;
592 pci_config_writel(d, 0x40, pm_io_base | 1);
593 pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */
594 smb_io_base = SMB_IO_BASE;
595 pci_config_writel(d, 0x90, smb_io_base | 1);
596 pci_config_writeb(d, 0xd2, 0x09); /* enable SMBus io space */
597 pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE);
605 void pci_for_each_device(void (*init_func)(PCIDevice *d))
607 PCIDevice d1, *d = &d1;
609 u16 vendor_id, device_id;
611 for(bus = 0; bus < 1; bus++) {
612 for(devfn = 0; devfn < 256; devfn++) {
615 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
616 device_id = pci_config_readw(d, PCI_DEVICE_ID);
617 if (vendor_id != 0xffff || device_id != 0xffff) {
624 void pci_bios_init(void)
626 pci_bios_io_addr = 0xc000;
627 pci_bios_mem_addr = 0xf0000000;
628 pci_bios_bigmem_addr = ram_size;
629 if (pci_bios_bigmem_addr < 0x90000000)
630 pci_bios_bigmem_addr = 0x90000000;
632 pci_for_each_device(pci_bios_init_bridges);
634 pci_for_each_device(pci_bios_init_device);
637 /****************************************************/
638 /* Multi Processor table init */
640 static void putb(u8 **pp, int val)
648 static void putstr(u8 **pp, const char *str)
657 static void putle16(u8 **pp, int val)
666 static void putle32(u8 **pp, int val)
677 static int mpf_checksum(const u8 *data, int len)
681 for(i = 0; i < len; i++)
686 static unsigned long align(unsigned long addr, unsigned long v)
688 return (addr + v - 1) & ~(v - 1);
691 static void mptable_init(void)
693 u8 *mp_config_table, *q, *float_pointer_struct;
694 int ioapic_id, i, len;
695 int mp_config_table_size;
702 #ifdef BX_USE_EBDA_TABLES
703 mp_config_table = (u8 *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE);
705 bios_table_cur_addr = align(bios_table_cur_addr, 16);
706 mp_config_table = (u8 *)bios_table_cur_addr;
709 putstr(&q, "PCMP"); /* "PCMP signature */
710 putle16(&q, 0); /* table length (patched later) */
711 putb(&q, 4); /* spec rev */
712 putb(&q, 0); /* checksum (patched later) */
714 putstr(&q, "QEMUCPU "); /* OEM id */
716 putstr(&q, "BOCHSCPU");
718 putstr(&q, "0.1 "); /* vendor id */
719 putle32(&q, 0); /* OEM table ptr */
720 putle16(&q, 0); /* OEM table size */
721 putle16(&q, smp_cpus + 18); /* entry count */
722 putle32(&q, 0xfee00000); /* local APIC addr */
723 putle16(&q, 0); /* ext table length */
724 putb(&q, 0); /* ext table checksum */
725 putb(&q, 0); /* reserved */
727 for(i = 0; i < smp_cpus; i++) {
728 putb(&q, 0); /* entry type = processor */
729 putb(&q, i); /* APIC id */
730 putb(&q, 0x11); /* local APIC version number */
732 putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
734 putb(&q, 1); /* cpu flags: enabled */
735 putb(&q, 0); /* cpu signature */
739 putle16(&q, 0x201); /* feature flags */
742 putle16(&q, 0); /* reserved */
749 putb(&q, 1); /* entry type = bus */
750 putb(&q, 0); /* bus ID */
754 ioapic_id = smp_cpus;
755 putb(&q, 2); /* entry type = I/O APIC */
756 putb(&q, ioapic_id); /* apic ID */
757 putb(&q, 0x11); /* I/O APIC version number */
758 putb(&q, 1); /* enable */
759 putle32(&q, 0xfec00000); /* I/O APIC addr */
762 for(i = 0; i < 16; i++) {
763 putb(&q, 3); /* entry type = I/O interrupt */
764 putb(&q, 0); /* interrupt type = vectored interrupt */
765 putb(&q, 0); /* flags: po=0, el=0 */
767 putb(&q, 0); /* source bus ID = ISA */
768 putb(&q, i); /* source bus IRQ */
769 putb(&q, ioapic_id); /* dest I/O APIC ID */
770 putb(&q, i); /* dest I/O APIC interrupt in */
773 len = q - mp_config_table;
774 mp_config_table[4] = len;
775 mp_config_table[5] = len >> 8;
777 mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
779 mp_config_table_size = q - mp_config_table;
781 #ifndef BX_USE_EBDA_TABLES
782 bios_table_cur_addr += mp_config_table_size;
785 /* floating pointer structure */
786 #ifdef BX_USE_EBDA_TABLES
787 ebda_cur_addr = align(ebda_cur_addr, 16);
788 float_pointer_struct = (u8 *)ebda_cur_addr;
790 bios_table_cur_addr = align(bios_table_cur_addr, 16);
791 float_pointer_struct = (u8 *)bios_table_cur_addr;
793 q = float_pointer_struct;
795 /* pointer to MP config table */
796 putle32(&q, (unsigned long)mp_config_table);
798 putb(&q, 1); /* length in 16 byte units */
799 putb(&q, 4); /* MP spec revision */
800 putb(&q, 0); /* checksum (patched later) */
801 putb(&q, 0); /* MP feature byte 1 */
807 float_pointer_struct[10] =
808 -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
809 #ifdef BX_USE_EBDA_TABLES
810 ebda_cur_addr += (q - float_pointer_struct);
812 bios_table_cur_addr += (q - float_pointer_struct);
814 BX_INFO("MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n",
815 (unsigned long)float_pointer_struct,
816 (unsigned long)mp_config_table,
817 mp_config_table_size);
820 /****************************************************/
821 /* ACPI tables init */
823 /* Table structure from Linux kernel (the ACPI tables are under the
826 #define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
827 u8 signature [4]; /* ACPI signature (4 ASCII characters) */\
828 u32 length; /* Length of table, in bytes, including header */\
829 u8 revision; /* ACPI Specification minor version # */\
830 u8 checksum; /* To make sum of entire table == 0 */\
831 u8 oem_id [6]; /* OEM identification */\
832 u8 oem_table_id [8]; /* OEM table identification */\
833 u32 oem_revision; /* OEM revision number */\
834 u8 asl_compiler_id [4]; /* ASL compiler vendor ID */\
835 u32 asl_compiler_revision; /* ASL compiler revision number */
838 struct acpi_table_header /* ACPI common table header */
840 ACPI_TABLE_HEADER_DEF
843 struct rsdp_descriptor /* Root System Descriptor Pointer */
845 u8 signature [8]; /* ACPI signature, contains "RSD PTR " */
846 u8 checksum; /* To make sum of struct == 0 */
847 u8 oem_id [6]; /* OEM identification */
848 u8 revision; /* Must be 0 for 1.0, 2 for 2.0 */
849 u32 rsdt_physical_address; /* 32-bit physical address of RSDT */
850 u32 length; /* XSDT Length in bytes including hdr */
851 u64 xsdt_physical_address; /* 64-bit physical address of XSDT */
852 u8 extended_checksum; /* Checksum of entire table */
853 u8 reserved [3]; /* Reserved field must be 0 */
857 * ACPI 1.0 Root System Description Table (RSDT)
859 struct rsdt_descriptor_rev1
861 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
862 u32 table_offset_entry [3]; /* Array of pointers to other */
867 * ACPI 1.0 Firmware ACPI Control Structure (FACS)
869 struct facs_descriptor_rev1
871 u8 signature[4]; /* ACPI Signature */
872 u32 length; /* Length of structure, in bytes */
873 u32 hardware_signature; /* Hardware configuration signature */
874 u32 firmware_waking_vector; /* ACPI OS waking vector */
875 u32 global_lock; /* Global Lock */
876 u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */
877 u32 reserved1 : 31; /* Must be 0 */
878 u8 resverved3 [40]; /* Reserved - must be zero */
883 * ACPI 1.0 Fixed ACPI Description Table (FADT)
885 struct fadt_descriptor_rev1
887 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
888 u32 firmware_ctrl; /* Physical address of FACS */
889 u32 dsdt; /* Physical address of DSDT */
890 u8 model; /* System Interrupt Model */
891 u8 reserved1; /* Reserved */
892 u16 sci_int; /* System vector of SCI interrupt */
893 u32 smi_cmd; /* Port address of SMI command port */
894 u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */
895 u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */
896 u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
897 u8 reserved2; /* Reserved - must be zero */
898 u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
899 u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
900 u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
901 u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
902 u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
903 u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
904 u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
905 u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
906 u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
907 u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
908 u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
909 u8 pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
910 u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
911 u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
912 u8 gpe1_base; /* Offset in gpe model where gpe1 events start */
913 u8 reserved3; /* Reserved */
914 u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
915 u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
916 u16 flush_size; /* Size of area read to flush caches */
917 u16 flush_stride; /* Stride used in flushing caches */
918 u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */
919 u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */
920 u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
921 u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
922 u8 century; /* Index to century in RTC CMOS RAM */
923 u8 reserved4; /* Reserved */
924 u8 reserved4a; /* Reserved */
925 u8 reserved4b; /* Reserved */
927 u32 wb_invd : 1; /* The wbinvd instruction works properly */
928 u32 wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
929 u32 proc_c1 : 1; /* All processors support C1 state */
930 u32 plvl2_up : 1; /* C2 state works on MP system */
931 u32 pwr_button : 1; /* Power button is handled as a generic feature */
932 u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
933 u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
934 u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
935 u32 tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
936 u32 reserved5 : 23; /* Reserved - must be zero */
943 * MADT values and structures
946 /* Values for MADT PCATCompat */
949 #define MULTIPLE_APIC 1
954 struct multiple_apic_table
956 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
957 u32 local_apic_address; /* Physical address of local APIC */
959 u32 PCATcompat : 1; /* A one indicates system also has dual 8259s */
967 /* Values for Type in APIC_HEADER_DEF */
969 #define APIC_PROCESSOR 0
971 #define APIC_XRUPT_OVERRIDE 2
973 #define APIC_LOCAL_NMI 4
974 #define APIC_ADDRESS_OVERRIDE 5
975 #define APIC_IO_SAPIC 6
976 #define APIC_LOCAL_SAPIC 7
977 #define APIC_XRUPT_SOURCE 8
978 #define APIC_RESERVED 9 /* 9 and greater are reserved */
981 * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
983 #define APIC_HEADER_DEF /* Common APIC sub-structure header */\
987 /* Sub-structures for MADT */
989 struct madt_processor_apic
992 u8 processor_id; /* ACPI processor id */
993 u8 local_apic_id; /* Processor's local APIC id */
995 u32 processor_enabled: 1; /* Processor is usable if set */
996 u32 reserved2 : 31; /* Reserved, must be zero */
1005 u8 io_apic_id; /* I/O APIC ID */
1006 u8 reserved; /* Reserved - must be zero */
1007 u32 address; /* APIC physical address */
1008 u32 interrupt; /* Global system interrupt where INTI
1012 #include "acpi-dsdt.hex"
1014 static inline u16 cpu_to_le16(u16 x)
1019 static inline u32 cpu_to_le32(u32 x)
1024 static int acpi_checksum(const u8 *data, int len)
1028 for(i = 0; i < len; i++)
1030 return (-sum) & 0xff;
1033 static void acpi_build_table_header(struct acpi_table_header *h,
1034 char *sig, int len, u8 rev)
1036 memcpy(h->signature, sig, 4);
1037 h->length = cpu_to_le32(len);
1040 memcpy(h->oem_id, "QEMU ", 6);
1041 memcpy(h->oem_table_id, "QEMU", 4);
1043 memcpy(h->oem_id, "BOCHS ", 6);
1044 memcpy(h->oem_table_id, "BXPC", 4);
1046 memcpy(h->oem_table_id + 4, sig, 4);
1047 h->oem_revision = cpu_to_le32(1);
1049 memcpy(h->asl_compiler_id, "QEMU", 4);
1051 memcpy(h->asl_compiler_id, "BXPC", 4);
1053 h->asl_compiler_revision = cpu_to_le32(1);
1054 h->checksum = acpi_checksum((void *)h, len);
1057 int acpi_build_processor_ssdt(u8 *ssdt)
1059 u8 *ssdt_ptr = ssdt;
1061 int acpi_cpus = smp_cpus > 0xff ? 0xff : smp_cpus;
1063 ssdt_ptr[9] = 0; // checksum;
1064 ssdt_ptr += sizeof(struct acpi_table_header);
1066 // caluculate the length of processor block and scope block excluding PkgLength
1067 length = 0x0d * acpi_cpus + 4;
1069 // build processor scope header
1070 *(ssdt_ptr++) = 0x10; // ScopeOp
1071 if (length <= 0x3e) {
1072 *(ssdt_ptr++) = length + 1;
1074 *(ssdt_ptr++) = 0x7F;
1075 *(ssdt_ptr++) = (length + 2) >> 6;
1077 *(ssdt_ptr++) = '_'; // Name
1078 *(ssdt_ptr++) = 'P';
1079 *(ssdt_ptr++) = 'R';
1080 *(ssdt_ptr++) = '_';
1082 // build object for each processor
1083 for(i=0;i<acpi_cpus;i++) {
1084 *(ssdt_ptr++) = 0x5B; // ProcessorOp
1085 *(ssdt_ptr++) = 0x83;
1086 *(ssdt_ptr++) = 0x0B; // Length
1087 *(ssdt_ptr++) = 'C'; // Name (CPUxx)
1088 *(ssdt_ptr++) = 'P';
1089 if ((i & 0xf0) != 0)
1090 *(ssdt_ptr++) = (i >> 4) < 0xa ? (i >> 4) + '0' : (i >> 4) + 'A' - 0xa;
1092 *(ssdt_ptr++) = 'U';
1093 *(ssdt_ptr++) = (i & 0xf) < 0xa ? (i & 0xf) + '0' : (i & 0xf) + 'A' - 0xa;
1095 *(ssdt_ptr++) = 0x10; // Processor block address
1096 *(ssdt_ptr++) = 0xb0;
1099 *(ssdt_ptr++) = 6; // Processor block length
1102 acpi_build_table_header((struct acpi_table_header *)ssdt,
1103 "SSDT", ssdt_ptr - ssdt, 1);
1105 return ssdt_ptr - ssdt;
1108 /* base_addr must be a multiple of 4KB */
1109 void acpi_bios_init(void)
1111 struct rsdp_descriptor *rsdp;
1112 struct rsdt_descriptor_rev1 *rsdt;
1113 struct fadt_descriptor_rev1 *fadt;
1114 struct facs_descriptor_rev1 *facs;
1115 struct multiple_apic_table *madt;
1117 u32 base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
1118 u32 acpi_tables_size, madt_addr, madt_size;
1121 /* reserve memory space for tables */
1122 #ifdef BX_USE_EBDA_TABLES
1123 ebda_cur_addr = align(ebda_cur_addr, 16);
1124 rsdp = (void *)(ebda_cur_addr);
1125 ebda_cur_addr += sizeof(*rsdp);
1127 bios_table_cur_addr = align(bios_table_cur_addr, 16);
1128 rsdp = (void *)(bios_table_cur_addr);
1129 bios_table_cur_addr += sizeof(*rsdp);
1132 addr = base_addr = ram_size - ACPI_DATA_SIZE;
1134 rsdt = (void *)(addr);
1135 addr += sizeof(*rsdt);
1138 fadt = (void *)(addr);
1139 addr += sizeof(*fadt);
1141 /* XXX: FACS should be in RAM */
1142 addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
1144 facs = (void *)(addr);
1145 addr += sizeof(*facs);
1148 dsdt = (void *)(addr);
1149 addr += sizeof(AmlCode);
1152 ssdt = (void *)(addr);
1153 addr += acpi_build_processor_ssdt(ssdt);
1155 addr = (addr + 7) & ~7;
1157 madt_size = sizeof(*madt) +
1158 sizeof(struct madt_processor_apic) * smp_cpus +
1159 sizeof(struct madt_io_apic);
1160 madt = (void *)(addr);
1163 acpi_tables_size = addr - base_addr;
1165 BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n",
1166 (unsigned long)rsdp,
1167 (unsigned long)rsdt, acpi_tables_size);
1170 memset(rsdp, 0, sizeof(*rsdp));
1171 memcpy(rsdp->signature, "RSD PTR ", 8);
1173 memcpy(rsdp->oem_id, "QEMU ", 6);
1175 memcpy(rsdp->oem_id, "BOCHS ", 6);
1177 rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
1178 rsdp->checksum = acpi_checksum((void *)rsdp, 20);
1181 memset(rsdt, 0, sizeof(*rsdt));
1182 rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
1183 rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
1184 rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
1185 acpi_build_table_header((struct acpi_table_header *)rsdt,
1186 "RSDT", sizeof(*rsdt), 1);
1189 memset(fadt, 0, sizeof(*fadt));
1190 fadt->firmware_ctrl = cpu_to_le32(facs_addr);
1191 fadt->dsdt = cpu_to_le32(dsdt_addr);
1193 fadt->reserved1 = 0;
1194 fadt->sci_int = cpu_to_le16(pm_sci_int);
1195 fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
1196 fadt->acpi_enable = 0xf1;
1197 fadt->acpi_disable = 0xf0;
1198 fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
1199 fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
1200 fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
1201 fadt->pm1_evt_len = 4;
1202 fadt->pm1_cnt_len = 2;
1203 fadt->pm_tmr_len = 4;
1204 fadt->plvl2_lat = cpu_to_le16(50);
1205 fadt->plvl3_lat = cpu_to_le16(50);
1206 fadt->plvl3_lat = cpu_to_le16(50);
1207 /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
1208 fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
1209 acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
1213 memset(facs, 0, sizeof(*facs));
1214 memcpy(facs->signature, "FACS", 4);
1215 facs->length = cpu_to_le32(sizeof(*facs));
1218 memcpy(dsdt, AmlCode, sizeof(AmlCode));
1222 struct madt_processor_apic *apic;
1223 struct madt_io_apic *io_apic;
1225 memset(madt, 0, madt_size);
1226 madt->local_apic_address = cpu_to_le32(0xfee00000);
1227 madt->flags = cpu_to_le32(1);
1228 apic = (void *)(madt + 1);
1229 for(i=0;i<smp_cpus;i++) {
1230 apic->type = APIC_PROCESSOR;
1231 apic->length = sizeof(*apic);
1232 apic->processor_id = i;
1233 apic->local_apic_id = i;
1234 apic->flags = cpu_to_le32(1);
1237 io_apic = (void *)apic;
1238 io_apic->type = APIC_IO;
1239 io_apic->length = sizeof(*io_apic);
1240 io_apic->io_apic_id = smp_cpus;
1241 io_apic->address = cpu_to_le32(0xfec00000);
1242 io_apic->interrupt = cpu_to_le32(0);
1244 acpi_build_table_header((struct acpi_table_header *)madt,
1245 "APIC", madt_size, 1);
1249 /* SMBIOS entry point -- must be written to a 16-bit aligned address
1250 between 0xf0000 and 0xfffff.
1252 struct smbios_entry_point {
1253 char anchor_string[4];
1256 u8 smbios_major_version;
1257 u8 smbios_minor_version;
1258 u16 max_structure_size;
1259 u8 entry_point_revision;
1260 u8 formatted_area[5];
1261 char intermediate_anchor_string[5];
1262 u8 intermediate_checksum;
1263 u16 structure_table_length;
1264 u32 structure_table_address;
1265 u16 number_of_structures;
1266 u8 smbios_bcd_revision;
1267 } __attribute__((__packed__));
1269 /* This goes at the beginning of every SMBIOS structure. */
1270 struct smbios_structure_header {
1274 } __attribute__((__packed__));
1276 /* SMBIOS type 0 - BIOS Information */
1277 struct smbios_type_0 {
1278 struct smbios_structure_header header;
1280 u8 bios_version_str;
1281 u16 bios_starting_address_segment;
1282 u8 bios_release_date_str;
1284 u8 bios_characteristics[8];
1285 u8 bios_characteristics_extension_bytes[2];
1286 u8 system_bios_major_release;
1287 u8 system_bios_minor_release;
1288 u8 embedded_controller_major_release;
1289 u8 embedded_controller_minor_release;
1290 } __attribute__((__packed__));
1292 /* SMBIOS type 1 - System Information */
1293 struct smbios_type_1 {
1294 struct smbios_structure_header header;
1295 u8 manufacturer_str;
1296 u8 product_name_str;
1298 u8 serial_number_str;
1303 } __attribute__((__packed__));
1305 /* SMBIOS type 3 - System Enclosure (v2.3) */
1306 struct smbios_type_3 {
1307 struct smbios_structure_header header;
1308 u8 manufacturer_str;
1311 u8 serial_number_str;
1312 u8 asset_tag_number_str;
1314 u8 power_supply_state;
1319 u8 number_of_power_cords;
1320 u8 contained_element_count;
1321 // contained elements follow
1322 } __attribute__((__packed__));
1324 /* SMBIOS type 4 - Processor Information (v2.0) */
1325 struct smbios_type_4 {
1326 struct smbios_structure_header header;
1327 u8 socket_designation_str;
1329 u8 processor_family;
1330 u8 processor_manufacturer_str;
1331 u32 processor_id[2];
1332 u8 processor_version_str;
1338 u8 processor_upgrade;
1339 } __attribute__((__packed__));
1341 /* SMBIOS type 16 - Physical Memory Array
1342 * Associated with one type 17 (Memory Device).
1344 struct smbios_type_16 {
1345 struct smbios_structure_header header;
1348 u8 error_correction;
1349 u32 maximum_capacity;
1350 u16 memory_error_information_handle;
1351 u16 number_of_memory_devices;
1352 } __attribute__((__packed__));
1354 /* SMBIOS type 17 - Memory Device
1355 * Associated with one type 19
1357 struct smbios_type_17 {
1358 struct smbios_structure_header header;
1359 u16 physical_memory_array_handle;
1360 u16 memory_error_information_handle;
1366 u8 device_locator_str;
1367 u8 bank_locator_str;
1370 } __attribute__((__packed__));
1372 /* SMBIOS type 19 - Memory Array Mapped Address */
1373 struct smbios_type_19 {
1374 struct smbios_structure_header header;
1375 u32 starting_address;
1377 u16 memory_array_handle;
1379 } __attribute__((__packed__));
1381 /* SMBIOS type 20 - Memory Device Mapped Address */
1382 struct smbios_type_20 {
1383 struct smbios_structure_header header;
1384 u32 starting_address;
1386 u16 memory_device_handle;
1387 u16 memory_array_mapped_address_handle;
1388 u8 partition_row_position;
1389 u8 interleave_position;
1390 u8 interleaved_data_depth;
1391 } __attribute__((__packed__));
1393 /* SMBIOS type 32 - System Boot Information */
1394 struct smbios_type_32 {
1395 struct smbios_structure_header header;
1398 } __attribute__((__packed__));
1400 /* SMBIOS type 127 -- End-of-table */
1401 struct smbios_type_127 {
1402 struct smbios_structure_header header;
1403 } __attribute__((__packed__));
1406 smbios_entry_point_init(void *start,
1407 u16 max_structure_size,
1408 u16 structure_table_length,
1409 u32 structure_table_address,
1410 u16 number_of_structures)
1414 struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
1416 memcpy(ep->anchor_string, "_SM_", 4);
1418 ep->smbios_major_version = 2;
1419 ep->smbios_minor_version = 4;
1420 ep->max_structure_size = max_structure_size;
1421 ep->entry_point_revision = 0;
1422 memset(ep->formatted_area, 0, 5);
1423 memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
1425 ep->structure_table_length = structure_table_length;
1426 ep->structure_table_address = structure_table_address;
1427 ep->number_of_structures = number_of_structures;
1428 ep->smbios_bcd_revision = 0x24;
1431 ep->intermediate_checksum = 0;
1434 for (i = 0; i < 0x10; i++)
1435 sum += ((s8 *)start)[i];
1436 ep->checksum = -sum;
1439 for (i = 0x10; i < ep->length; i++)
1440 sum += ((s8 *)start)[i];
1441 ep->intermediate_checksum = -sum;
1444 /* Type 0 -- BIOS Information */
1445 #define RELEASE_DATE_STR "01/01/2007"
1447 smbios_type_0_init(void *start)
1449 struct smbios_type_0 *p = (struct smbios_type_0 *)start;
1452 p->header.length = sizeof(struct smbios_type_0);
1453 p->header.handle = 0;
1456 p->bios_version_str = 1;
1457 p->bios_starting_address_segment = 0xe800;
1458 p->bios_release_date_str = 2;
1459 p->bios_rom_size = 0; /* FIXME */
1461 memset(p->bios_characteristics, 0, 7);
1462 p->bios_characteristics[7] = 0x08; /* BIOS characteristics not supported */
1463 p->bios_characteristics_extension_bytes[0] = 0;
1464 p->bios_characteristics_extension_bytes[1] = 0;
1466 p->system_bios_major_release = 1;
1467 p->system_bios_minor_release = 0;
1468 p->embedded_controller_major_release = 0xff;
1469 p->embedded_controller_minor_release = 0xff;
1471 start += sizeof(struct smbios_type_0);
1472 memcpy((char *)start, BX_APPNAME, sizeof(BX_APPNAME));
1473 start += sizeof(BX_APPNAME);
1474 memcpy((char *)start, RELEASE_DATE_STR, sizeof(RELEASE_DATE_STR));
1475 start += sizeof(RELEASE_DATE_STR);
1481 /* Type 1 -- System Information */
1483 smbios_type_1_init(void *start)
1485 struct smbios_type_1 *p = (struct smbios_type_1 *)start;
1487 p->header.length = sizeof(struct smbios_type_1);
1488 p->header.handle = 0x100;
1490 p->manufacturer_str = 0;
1491 p->product_name_str = 0;
1493 p->serial_number_str = 0;
1495 memcpy(p->uuid, bios_uuid, 16);
1497 p->wake_up_type = 0x06; /* power switch */
1498 p->sku_number_str = 0;
1501 start += sizeof(struct smbios_type_1);
1502 *((u16 *)start) = 0;
1507 /* Type 3 -- System Enclosure */
1509 smbios_type_3_init(void *start)
1511 struct smbios_type_3 *p = (struct smbios_type_3 *)start;
1514 p->header.length = sizeof(struct smbios_type_3);
1515 p->header.handle = 0x300;
1517 p->manufacturer_str = 0;
1518 p->type = 0x01; /* other */
1520 p->serial_number_str = 0;
1521 p->asset_tag_number_str = 0;
1522 p->boot_up_state = 0x03; /* safe */
1523 p->power_supply_state = 0x03; /* safe */
1524 p->thermal_state = 0x03; /* safe */
1525 p->security_status = 0x02; /* unknown */
1528 p->number_of_power_cords = 0;
1529 p->contained_element_count = 0;
1531 start += sizeof(struct smbios_type_3);
1532 *((u16 *)start) = 0;
1537 /* Type 4 -- Processor Information */
1539 smbios_type_4_init(void *start, unsigned int cpu_number)
1541 struct smbios_type_4 *p = (struct smbios_type_4 *)start;
1544 p->header.length = sizeof(struct smbios_type_4);
1545 p->header.handle = 0x400 + cpu_number;
1547 p->socket_designation_str = 1;
1548 p->processor_type = 0x03; /* CPU */
1549 p->processor_family = 0x01; /* other */
1550 p->processor_manufacturer_str = 0;
1552 p->processor_id[0] = cpuid_signature;
1553 p->processor_id[1] = cpuid_features;
1555 p->processor_version_str = 0;
1557 p->external_clock = 0;
1559 p->max_speed = 0; /* unknown */
1560 p->current_speed = 0; /* unknown */
1562 p->status = 0x41; /* socket populated, CPU enabled */
1563 p->processor_upgrade = 0x01; /* other */
1565 start += sizeof(struct smbios_type_4);
1567 memcpy((char *)start, "CPU " "\0" "" "\0" "", 7);
1568 ((char *)start)[4] = cpu_number + '0';
1573 /* Type 16 -- Physical Memory Array */
1575 smbios_type_16_init(void *start, u32 memsize)
1577 struct smbios_type_16 *p = (struct smbios_type_16*)start;
1579 p->header.type = 16;
1580 p->header.length = sizeof(struct smbios_type_16);
1581 p->header.handle = 0x1000;
1583 p->location = 0x01; /* other */
1584 p->use = 0x03; /* system memory */
1585 p->error_correction = 0x01; /* other */
1586 p->maximum_capacity = memsize * 1024;
1587 p->memory_error_information_handle = 0xfffe; /* none provided */
1588 p->number_of_memory_devices = 1;
1590 start += sizeof(struct smbios_type_16);
1591 *((u16 *)start) = 0;
1596 /* Type 17 -- Memory Device */
1598 smbios_type_17_init(void *start, u32 memory_size_mb)
1600 struct smbios_type_17 *p = (struct smbios_type_17 *)start;
1602 p->header.type = 17;
1603 p->header.length = sizeof(struct smbios_type_17);
1604 p->header.handle = 0x1100;
1606 p->physical_memory_array_handle = 0x1000;
1607 p->total_width = 64;
1609 /* truncate memory_size_mb to 16 bits and clear most significant
1610 bit [indicates size in MB] */
1611 p->size = (u16) memory_size_mb & 0x7fff;
1612 p->form_factor = 0x09; /* DIMM */
1614 p->device_locator_str = 1;
1615 p->bank_locator_str = 0;
1616 p->memory_type = 0x07; /* RAM */
1619 start += sizeof(struct smbios_type_17);
1620 memcpy((char *)start, "DIMM 1", 7);
1627 /* Type 19 -- Memory Array Mapped Address */
1629 smbios_type_19_init(void *start, u32 memory_size_mb)
1631 struct smbios_type_19 *p = (struct smbios_type_19 *)start;
1633 p->header.type = 19;
1634 p->header.length = sizeof(struct smbios_type_19);
1635 p->header.handle = 0x1300;
1637 p->starting_address = 0;
1638 p->ending_address = (memory_size_mb-1) * 1024;
1639 p->memory_array_handle = 0x1000;
1640 p->partition_width = 1;
1642 start += sizeof(struct smbios_type_19);
1643 *((u16 *)start) = 0;
1648 /* Type 20 -- Memory Device Mapped Address */
1650 smbios_type_20_init(void *start, u32 memory_size_mb)
1652 struct smbios_type_20 *p = (struct smbios_type_20 *)start;
1654 p->header.type = 20;
1655 p->header.length = sizeof(struct smbios_type_20);
1656 p->header.handle = 0x1400;
1658 p->starting_address = 0;
1659 p->ending_address = (memory_size_mb-1)*1024;
1660 p->memory_device_handle = 0x1100;
1661 p->memory_array_mapped_address_handle = 0x1300;
1662 p->partition_row_position = 1;
1663 p->interleave_position = 0;
1664 p->interleaved_data_depth = 0;
1666 start += sizeof(struct smbios_type_20);
1668 *((u16 *)start) = 0;
1672 /* Type 32 -- System Boot Information */
1674 smbios_type_32_init(void *start)
1676 struct smbios_type_32 *p = (struct smbios_type_32 *)start;
1678 p->header.type = 32;
1679 p->header.length = sizeof(struct smbios_type_32);
1680 p->header.handle = 0x2000;
1681 memset(p->reserved, 0, 6);
1682 p->boot_status = 0; /* no errors detected */
1684 start += sizeof(struct smbios_type_32);
1685 *((u16 *)start) = 0;
1690 /* Type 127 -- End of Table */
1692 smbios_type_127_init(void *start)
1694 struct smbios_type_127 *p = (struct smbios_type_127 *)start;
1696 p->header.type = 127;
1697 p->header.length = sizeof(struct smbios_type_127);
1698 p->header.handle = 0x7f00;
1700 start += sizeof(struct smbios_type_127);
1701 *((u16 *)start) = 0;
1706 void smbios_init(void)
1708 unsigned cpu_num, nr_structs = 0, max_struct_size = 0;
1709 char *start, *p, *q;
1710 int memsize = ram_size / (1024 * 1024);
1712 #ifdef BX_USE_EBDA_TABLES
1713 ebda_cur_addr = align(ebda_cur_addr, 16);
1714 start = (void *)(ebda_cur_addr);
1716 bios_table_cur_addr = align(bios_table_cur_addr, 16);
1717 start = (void *)(bios_table_cur_addr);
1720 p = (char *)start + sizeof(struct smbios_entry_point);
1722 #define add_struct(fn) { \
1725 if ((q - p) > max_struct_size) \
1726 max_struct_size = q - p; \
1730 add_struct(smbios_type_0_init(p));
1731 add_struct(smbios_type_1_init(p));
1732 add_struct(smbios_type_3_init(p));
1733 for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++)
1734 add_struct(smbios_type_4_init(p, cpu_num));
1735 add_struct(smbios_type_16_init(p, memsize));
1736 add_struct(smbios_type_17_init(p, memsize));
1737 add_struct(smbios_type_19_init(p, memsize));
1738 add_struct(smbios_type_20_init(p, memsize));
1739 add_struct(smbios_type_32_init(p));
1740 add_struct(smbios_type_127_init(p));
1744 smbios_entry_point_init(
1745 start, max_struct_size,
1746 (p - (char *)start) - sizeof(struct smbios_entry_point),
1747 (u32)(start + sizeof(struct smbios_entry_point)),
1750 #ifdef BX_USE_EBDA_TABLES
1751 ebda_cur_addr += (p - (char *)start);
1753 bios_table_cur_addr += (p - (char *)start);
1756 BX_INFO("SMBIOS table addr=0x%08lx\n", (unsigned long)start);
1759 void rombios32_init(void)
1761 BX_INFO("Starting rombios32\n");
1773 if (bios_table_cur_addr != 0) {
1782 bios_lock_shadow_ram();
1784 BX_INFO("bios_table_cur_addr: 0x%08lx\n", bios_table_cur_addr);
1785 if (bios_table_cur_addr > bios_table_end_addr)
1786 BX_PANIC("bios_table_end_addr overflow!\n");