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
25 #define BX_APPNAME "Bochs"
27 #define ACPI_DATA_SIZE 0x00010000L
28 #define PM_IO_BASE 0xb000
29 #define SMB_IO_BASE 0xb100
30 #define CPU_COUNT_ADDR 0xf000
32 typedef signed char int8_t;
33 typedef short int16_t;
35 typedef long long int64_t;
36 typedef unsigned char uint8_t;
37 typedef unsigned short uint16_t;
38 typedef unsigned int uint32_t;
39 typedef unsigned long long uint64_t;
41 /* if true, put the MP float table and ACPI RSDT in EBDA and the MP
42 table in RAM. Unfortunately, Linux has bugs with that, so we prefer
43 to modify the BIOS in shadow RAM */
44 //#define BX_USE_EBDA_TABLES
46 /* define it if the (emulated) hardware supports SMM mode */
49 #define cpuid(index, eax, ebx, ecx, edx) \
50 asm volatile ("cpuid" \
51 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
54 #define wbinvd() asm volatile("wbinvd")
56 #define CPUID_APIC (1 << 9)
58 #define APIC_BASE ((uint8_t *)0xfee00000)
59 #define APIC_ICR_LOW 0x300
60 #define APIC_SVR 0x0F0
62 #define APIC_LVT3 0x370
64 #define APIC_ENABLED 0x0100
66 #define AP_BOOT_ADDR 0x10000
68 #define MPTABLE_MAX_SIZE 0x00002000
69 #define SMI_CMD_IO_ADDR 0xb2
71 #define BIOS_TMP_STORAGE 0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */
73 static inline void writel(void *addr, uint32_t val)
75 *(volatile uint32_t *)addr = val;
78 static inline void writew(void *addr, uint16_t val)
80 *(volatile uint16_t *)addr = val;
83 static inline void writeb(void *addr, uint8_t val)
85 *(volatile uint8_t *)addr = val;
88 static inline uint32_t readl(const void *addr)
90 return *(volatile const uint32_t *)addr;
93 static inline uint16_t readw(const void *addr)
95 return *(volatile const uint16_t *)addr;
98 static inline uint8_t readb(const void *addr)
100 return *(volatile const uint8_t *)addr;
104 uint32_t cpuid_signature;
105 uint32_t cpuid_features;
106 uint32_t cpuid_ext_features;
107 unsigned long ram_size;
108 uint8_t bios_uuid[16];
109 #ifdef BX_USE_EBDA_TABLES
110 unsigned long ebda_cur_addr;
113 uint32_t pm_io_base, smb_io_base;
115 unsigned long bios_table_cur_addr;
116 unsigned long bios_table_end_addr;
118 void uuid_probe(void)
121 uint32_t eax, ebx, ecx, edx;
123 // check if backdoor port exists
124 asm volatile ("outl %%eax, %%dx"
125 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
126 : "a" (0x564d5868), "c" (0xa), "d" (0x5658));
127 if (ebx == 0x564d5868) {
128 uint32_t *uuid_ptr = (uint32_t *)bios_uuid;
130 asm volatile ("outl %%eax, %%dx"
131 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
132 : "a" (0x564d5868), "c" (0x13), "d" (0x5658));
141 memset(bios_uuid, 0, 16);
147 uint32_t eax, ebx, ecx, edx;
148 cpuid(1, eax, ebx, ecx, edx);
149 cpuid_signature = eax;
150 cpuid_features = edx;
151 cpuid_ext_features = ecx;
156 if (inb_cmos(0x34) | inb_cmos(0x35))
157 ram_size = (inb_cmos(0x34) | (inb_cmos(0x35) << 8)) * 65536 +
160 ram_size = (inb_cmos(0x17) | (inb_cmos(0x18) << 8)) * 1024;
161 #ifdef BX_USE_EBDA_TABLES
162 ebda_cur_addr = ((*(uint16_t *)(0x40e)) << 4) + 0x380;
164 BX_INFO("ram_size=0x%08lx\n", ram_size);
167 /****************************************************/
170 extern uint8_t smp_ap_boot_code_start;
171 extern uint8_t smp_ap_boot_code_end;
173 /* find the number of CPUs by launching a SIPI to them */
176 uint32_t val, sipi_vector;
179 if (cpuid_features & CPUID_APIC) {
181 /* enable local APIC */
182 val = readl(APIC_BASE + APIC_SVR);
184 writel(APIC_BASE + APIC_SVR, val);
186 writew((void *)CPU_COUNT_ADDR, 1);
187 /* copy AP boot code */
188 memcpy((void *)AP_BOOT_ADDR, &smp_ap_boot_code_start,
189 &smp_ap_boot_code_end - &smp_ap_boot_code_start);
192 writel(APIC_BASE + APIC_ICR_LOW, 0x000C4500);
193 sipi_vector = AP_BOOT_ADDR >> 12;
194 writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector);
198 smp_cpus = readw((void *)CPU_COUNT_ADDR);
200 BX_INFO("Found %d cpu(s)\n", smp_cpus);
203 /****************************************************/
206 #define PCI_ADDRESS_SPACE_MEM 0x00
207 #define PCI_ADDRESS_SPACE_IO 0x01
208 #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08
210 #define PCI_ROM_SLOT 6
211 #define PCI_NUM_REGIONS 7
213 #define PCI_DEVICES_MAX 64
215 #define PCI_VENDOR_ID 0x00 /* 16 bits */
216 #define PCI_DEVICE_ID 0x02 /* 16 bits */
217 #define PCI_COMMAND 0x04 /* 16 bits */
218 #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
219 #define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
220 #define PCI_CLASS_DEVICE 0x0a /* Device class */
221 #define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
222 #define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
223 #define PCI_MIN_GNT 0x3e /* 8 bits */
224 #define PCI_MAX_LAT 0x3f /* 8 bits */
226 typedef struct PCIDevice {
231 static uint32_t pci_bios_io_addr;
232 static uint32_t pci_bios_mem_addr;
233 static uint32_t pci_bios_bigmem_addr;
234 /* host irqs corresponding to PCI irqs A-D */
235 static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
236 static PCIDevice i440_pcidev;
238 static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
240 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
244 static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
246 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
247 outw(val, 0xcfc + (addr & 2));
250 static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
252 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
253 outb(val, 0xcfc + (addr & 3));
256 static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
258 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
262 static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
264 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
265 return inw(0xcfc + (addr & 2));
268 static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
270 outl(0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc), 0xcf8);
271 return inb(0xcfc + (addr & 3));
274 static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
277 uint32_t ofs, old_addr;
279 if ( region_num == PCI_ROM_SLOT ) {
282 ofs = 0x10 + region_num * 4;
285 old_addr = pci_config_readl(d, ofs);
287 pci_config_writel(d, ofs, addr);
288 BX_INFO("region %d: 0x%08x\n", region_num, addr);
290 /* enable memory mappings */
291 cmd = pci_config_readw(d, PCI_COMMAND);
292 if ( region_num == PCI_ROM_SLOT )
294 else if (old_addr & PCI_ADDRESS_SPACE_IO)
298 pci_config_writew(d, PCI_COMMAND, cmd);
301 /* return the global irq number corresponding to a given device irq
302 pin. We could also use the bus number to have a more precise
304 static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
307 slot_addend = (pci_dev->devfn >> 3) - 1;
308 return (irq_num + slot_addend) & 3;
312 copy_bios(PCIDevice *d, int v)
314 pci_config_writeb(d, 0x59, v);
315 memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000);
318 // Test if 'addr' is in the range from 'start'..'start+size'
319 #define IN_RANGE(addr, start, size) ({ \
320 u32 __addr = (addr); \
321 u32 __start = (start); \
322 u32 __size = (size); \
323 (__addr - __start < __size); \
326 static void bios_shadow_init(PCIDevice *d)
328 bios_table_cur_addr = 0xf0000 | OFFSET_freespace2_start;
329 bios_table_end_addr = 0xf0000 | OFFSET_freespace2_end;
330 BX_INFO("bios_table_addr: 0x%08lx end=0x%08lx\n",
331 bios_table_cur_addr, bios_table_end_addr);
333 /* remap the BIOS to shadow RAM an keep it read/write while we
334 are writing tables */
335 int v = pci_config_readb(d, 0x59);
337 pci_config_writeb(d, 0x59, v);
338 memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000);
341 if (IN_RANGE((u32)copy_bios, 0xf0000, 0x10000)) {
342 // Current code is in shadowed area. Perform the copy from
343 // the code that is in the temporary location.
344 u32 pos = (u32)copy_bios - 0xf0000 + BIOS_TMP_STORAGE;
345 void (*func)(PCIDevice *, int) = (void*)pos;
351 // Clear the area just copied.
352 memcpy((void *)BIOS_TMP_STORAGE, 0, 0x10000);
357 static void bios_lock_shadow_ram(void)
359 PCIDevice *d = &i440_pcidev;
363 v = pci_config_readb(d, 0x59);
364 v = (v & 0x0f) | (0x10);
365 pci_config_writeb(d, 0x59, v);
368 static void pci_bios_init_bridges(PCIDevice *d)
370 uint16_t vendor_id, device_id;
372 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
373 device_id = pci_config_readw(d, PCI_DEVICE_ID);
375 if (vendor_id == 0x8086 && device_id == 0x7000) {
383 for(i = 0; i < 4; i++) {
385 /* set to trigger level */
386 elcr[irq >> 3] |= (1 << (irq & 7));
387 /* activate irq remapping in PIIX */
388 pci_config_writeb(d, 0x60 + i, irq);
390 outb(elcr[0], 0x4d0);
391 outb(elcr[1], 0x4d1);
392 BX_INFO("PIIX3 init: elcr=%02x %02x\n",
394 } else if (vendor_id == 0x8086 && device_id == 0x1237) {
395 /* i440 PCI bridge */
401 ".globl smp_ap_boot_code_start\n"
402 ".globl smp_ap_boot_code_end\n"
403 ".global smm_relocation_start\n"
404 ".global smm_relocation_end\n"
405 ".global smm_code_start\n"
406 ".global smm_code_end\n"
409 "smp_ap_boot_code_start:\n"
412 " incw " __stringify(CPU_COUNT_ADDR) "\n"
416 "smp_ap_boot_code_end:\n"
418 /* code to relocate SMBASE to 0xa0000 */
419 "smm_relocation_start:\n"
420 " mov $0x38000 + 0x7efc, %ebx\n"
421 " addr32 mov (%ebx), %al\n" /* revision ID to see if x86_64 or x86 */
424 " mov $0x38000 + 0x7ef8, %ebx\n"
427 " mov $0x38000 + 0x7f00, %ebx\n"
429 " movl $0xa0000, %eax\n"
430 " addr32 movl %eax, (%ebx)\n"
431 /* indicate to the BIOS that the SMM code was executed */
436 "smm_relocation_end:\n"
438 /* minimal SMM code to enable or disable ACPI */
446 " mov $" __stringify(PM_IO_BASE) " + 0x04, %dx\n" /* PMCNTRL */
458 " mov $" __stringify(PM_IO_BASE) " + 0x04, %dx\n" /* PMCNTRL */
469 extern uint8_t smm_relocation_start, smm_relocation_end;
470 extern uint8_t smm_code_start, smm_code_end;
473 static void smm_init(PCIDevice *d)
477 /* check if SMM init is already done */
478 value = pci_config_readl(d, 0x58);
479 if ((value & (1 << 25)) == 0) {
481 /* copy the SMM relocation code */
482 memcpy((void *)0x38000, &smm_relocation_start,
483 &smm_relocation_end - &smm_relocation_start);
485 /* enable SMI generation when writing to the APMC register */
486 pci_config_writel(d, 0x58, value | (1 << 25));
488 /* init APM status port */
491 /* raise an SMI interrupt */
494 /* wait until SMM code executed */
495 while (inb(0xb3) != 0x00);
497 /* enable the SMM memory window */
498 pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x48);
500 /* copy the SMM code */
501 memcpy((void *)0xa8000, &smm_code_start,
502 &smm_code_end - &smm_code_start);
505 /* close the SMM memory window and enable normal SMM */
506 pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08);
511 static void pci_bios_init_device(PCIDevice *d)
515 int i, pin, pic_irq, vendor_id, device_id;
517 class = pci_config_readw(d, PCI_CLASS_DEVICE);
518 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
519 device_id = pci_config_readw(d, PCI_DEVICE_ID);
520 BX_INFO("PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n",
521 d->bus, d->devfn, vendor_id, device_id);
524 if (vendor_id == 0x8086 && device_id == 0x7010) {
526 pci_config_writew(d, 0x40, 0x8000); // enable IDE0
527 pci_config_writew(d, 0x42, 0x8000); // enable IDE1
530 /* IDE: we map it as in ISA mode */
531 pci_set_io_region_addr(d, 0, 0x1f0);
532 pci_set_io_region_addr(d, 1, 0x3f4);
533 pci_set_io_region_addr(d, 2, 0x170);
534 pci_set_io_region_addr(d, 3, 0x374);
538 if (vendor_id != 0x1234)
540 /* VGA: map frame buffer to default Bochs VBE address */
541 pci_set_io_region_addr(d, 0, 0xE0000000);
545 if (vendor_id == 0x1014) {
547 if (device_id == 0x0046 || device_id == 0xFFFF) {
549 pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
554 if (vendor_id == 0x0106b &&
555 (device_id == 0x0017 || device_id == 0x0022)) {
557 pci_set_io_region_addr(d, 0, 0x80800000);
562 /* default memory mappings */
563 for(i = 0; i < PCI_NUM_REGIONS; i++) {
567 if (i == PCI_ROM_SLOT)
571 pci_config_writel(d, ofs, 0xffffffff);
572 val = pci_config_readl(d, ofs);
574 size = (~(val & ~0xf)) + 1;
575 if (val & PCI_ADDRESS_SPACE_IO)
576 paddr = &pci_bios_io_addr;
577 else if (size >= 0x04000000)
578 paddr = &pci_bios_bigmem_addr;
580 paddr = &pci_bios_mem_addr;
581 *paddr = (*paddr + size - 1) & ~(size - 1);
582 pci_set_io_region_addr(d, i, *paddr);
589 /* map the interrupt */
590 pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
592 pin = pci_slot_get_pirq(d, pin - 1);
593 pic_irq = pci_irqs[pin];
594 pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
597 if (vendor_id == 0x8086 && device_id == 0x7113) {
598 /* PIIX4 Power Management device (for ACPI) */
599 pm_io_base = PM_IO_BASE;
600 pci_config_writel(d, 0x40, pm_io_base | 1);
601 pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */
602 smb_io_base = SMB_IO_BASE;
603 pci_config_writel(d, 0x90, smb_io_base | 1);
604 pci_config_writeb(d, 0xd2, 0x09); /* enable SMBus io space */
605 pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE);
613 void pci_for_each_device(void (*init_func)(PCIDevice *d))
615 PCIDevice d1, *d = &d1;
617 uint16_t vendor_id, device_id;
619 for(bus = 0; bus < 1; bus++) {
620 for(devfn = 0; devfn < 256; devfn++) {
623 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
624 device_id = pci_config_readw(d, PCI_DEVICE_ID);
625 if (vendor_id != 0xffff || device_id != 0xffff) {
632 void pci_bios_init(void)
634 pci_bios_io_addr = 0xc000;
635 pci_bios_mem_addr = 0xf0000000;
636 pci_bios_bigmem_addr = ram_size;
637 if (pci_bios_bigmem_addr < 0x90000000)
638 pci_bios_bigmem_addr = 0x90000000;
640 pci_for_each_device(pci_bios_init_bridges);
642 pci_for_each_device(pci_bios_init_device);
645 /****************************************************/
646 /* Multi Processor table init */
648 static void putb(uint8_t **pp, int val)
656 static void putstr(uint8_t **pp, const char *str)
665 static void putle16(uint8_t **pp, int val)
674 static void putle32(uint8_t **pp, int val)
685 static int mpf_checksum(const uint8_t *data, int len)
689 for(i = 0; i < len; i++)
694 static unsigned long align(unsigned long addr, unsigned long v)
696 return (addr + v - 1) & ~(v - 1);
699 static void mptable_init(void)
701 uint8_t *mp_config_table, *q, *float_pointer_struct;
702 int ioapic_id, i, len;
703 int mp_config_table_size;
710 #ifdef BX_USE_EBDA_TABLES
711 mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE);
713 bios_table_cur_addr = align(bios_table_cur_addr, 16);
714 mp_config_table = (uint8_t *)bios_table_cur_addr;
717 putstr(&q, "PCMP"); /* "PCMP signature */
718 putle16(&q, 0); /* table length (patched later) */
719 putb(&q, 4); /* spec rev */
720 putb(&q, 0); /* checksum (patched later) */
722 putstr(&q, "QEMUCPU "); /* OEM id */
724 putstr(&q, "BOCHSCPU");
726 putstr(&q, "0.1 "); /* vendor id */
727 putle32(&q, 0); /* OEM table ptr */
728 putle16(&q, 0); /* OEM table size */
729 putle16(&q, smp_cpus + 18); /* entry count */
730 putle32(&q, 0xfee00000); /* local APIC addr */
731 putle16(&q, 0); /* ext table length */
732 putb(&q, 0); /* ext table checksum */
733 putb(&q, 0); /* reserved */
735 for(i = 0; i < smp_cpus; i++) {
736 putb(&q, 0); /* entry type = processor */
737 putb(&q, i); /* APIC id */
738 putb(&q, 0x11); /* local APIC version number */
740 putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
742 putb(&q, 1); /* cpu flags: enabled */
743 putb(&q, 0); /* cpu signature */
747 putle16(&q, 0x201); /* feature flags */
750 putle16(&q, 0); /* reserved */
757 putb(&q, 1); /* entry type = bus */
758 putb(&q, 0); /* bus ID */
762 ioapic_id = smp_cpus;
763 putb(&q, 2); /* entry type = I/O APIC */
764 putb(&q, ioapic_id); /* apic ID */
765 putb(&q, 0x11); /* I/O APIC version number */
766 putb(&q, 1); /* enable */
767 putle32(&q, 0xfec00000); /* I/O APIC addr */
770 for(i = 0; i < 16; i++) {
771 putb(&q, 3); /* entry type = I/O interrupt */
772 putb(&q, 0); /* interrupt type = vectored interrupt */
773 putb(&q, 0); /* flags: po=0, el=0 */
775 putb(&q, 0); /* source bus ID = ISA */
776 putb(&q, i); /* source bus IRQ */
777 putb(&q, ioapic_id); /* dest I/O APIC ID */
778 putb(&q, i); /* dest I/O APIC interrupt in */
781 len = q - mp_config_table;
782 mp_config_table[4] = len;
783 mp_config_table[5] = len >> 8;
785 mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
787 mp_config_table_size = q - mp_config_table;
789 #ifndef BX_USE_EBDA_TABLES
790 bios_table_cur_addr += mp_config_table_size;
793 /* floating pointer structure */
794 #ifdef BX_USE_EBDA_TABLES
795 ebda_cur_addr = align(ebda_cur_addr, 16);
796 float_pointer_struct = (uint8_t *)ebda_cur_addr;
798 bios_table_cur_addr = align(bios_table_cur_addr, 16);
799 float_pointer_struct = (uint8_t *)bios_table_cur_addr;
801 q = float_pointer_struct;
803 /* pointer to MP config table */
804 putle32(&q, (unsigned long)mp_config_table);
806 putb(&q, 1); /* length in 16 byte units */
807 putb(&q, 4); /* MP spec revision */
808 putb(&q, 0); /* checksum (patched later) */
809 putb(&q, 0); /* MP feature byte 1 */
815 float_pointer_struct[10] =
816 -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
817 #ifdef BX_USE_EBDA_TABLES
818 ebda_cur_addr += (q - float_pointer_struct);
820 bios_table_cur_addr += (q - float_pointer_struct);
822 BX_INFO("MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n",
823 (unsigned long)float_pointer_struct,
824 (unsigned long)mp_config_table,
825 mp_config_table_size);
828 /****************************************************/
829 /* ACPI tables init */
831 /* Table structure from Linux kernel (the ACPI tables are under the
834 #define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
835 uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\
836 uint32_t length; /* Length of table, in bytes, including header */\
837 uint8_t revision; /* ACPI Specification minor version # */\
838 uint8_t checksum; /* To make sum of entire table == 0 */\
839 uint8_t oem_id [6]; /* OEM identification */\
840 uint8_t oem_table_id [8]; /* OEM table identification */\
841 uint32_t oem_revision; /* OEM revision number */\
842 uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\
843 uint32_t asl_compiler_revision; /* ASL compiler revision number */
846 struct acpi_table_header /* ACPI common table header */
848 ACPI_TABLE_HEADER_DEF
851 struct rsdp_descriptor /* Root System Descriptor Pointer */
853 uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */
854 uint8_t checksum; /* To make sum of struct == 0 */
855 uint8_t oem_id [6]; /* OEM identification */
856 uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
857 uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
858 uint32_t length; /* XSDT Length in bytes including hdr */
859 uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
860 uint8_t extended_checksum; /* Checksum of entire table */
861 uint8_t reserved [3]; /* Reserved field must be 0 */
865 * ACPI 1.0 Root System Description Table (RSDT)
867 struct rsdt_descriptor_rev1
869 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
870 uint32_t table_offset_entry [3]; /* Array of pointers to other */
875 * ACPI 1.0 Firmware ACPI Control Structure (FACS)
877 struct facs_descriptor_rev1
879 uint8_t signature[4]; /* ACPI Signature */
880 uint32_t length; /* Length of structure, in bytes */
881 uint32_t hardware_signature; /* Hardware configuration signature */
882 uint32_t firmware_waking_vector; /* ACPI OS waking vector */
883 uint32_t global_lock; /* Global Lock */
884 uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */
885 uint32_t reserved1 : 31; /* Must be 0 */
886 uint8_t resverved3 [40]; /* Reserved - must be zero */
891 * ACPI 1.0 Fixed ACPI Description Table (FADT)
893 struct fadt_descriptor_rev1
895 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
896 uint32_t firmware_ctrl; /* Physical address of FACS */
897 uint32_t dsdt; /* Physical address of DSDT */
898 uint8_t model; /* System Interrupt Model */
899 uint8_t reserved1; /* Reserved */
900 uint16_t sci_int; /* System vector of SCI interrupt */
901 uint32_t smi_cmd; /* Port address of SMI command port */
902 uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */
903 uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */
904 uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
905 uint8_t reserved2; /* Reserved - must be zero */
906 uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
907 uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
908 uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
909 uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
910 uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
911 uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
912 uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
913 uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
914 uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
915 uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
916 uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
917 uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
918 uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
919 uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
920 uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */
921 uint8_t reserved3; /* Reserved */
922 uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
923 uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
924 uint16_t flush_size; /* Size of area read to flush caches */
925 uint16_t flush_stride; /* Stride used in flushing caches */
926 uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */
927 uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */
928 uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
929 uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
930 uint8_t century; /* Index to century in RTC CMOS RAM */
931 uint8_t reserved4; /* Reserved */
932 uint8_t reserved4a; /* Reserved */
933 uint8_t reserved4b; /* Reserved */
935 uint32_t wb_invd : 1; /* The wbinvd instruction works properly */
936 uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
937 uint32_t proc_c1 : 1; /* All processors support C1 state */
938 uint32_t plvl2_up : 1; /* C2 state works on MP system */
939 uint32_t pwr_button : 1; /* Power button is handled as a generic feature */
940 uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
941 uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
942 uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
943 uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
944 uint32_t reserved5 : 23; /* Reserved - must be zero */
951 * MADT values and structures
954 /* Values for MADT PCATCompat */
957 #define MULTIPLE_APIC 1
962 struct multiple_apic_table
964 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
965 uint32_t local_apic_address; /* Physical address of local APIC */
967 uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */
968 uint32_t reserved1 : 31;
975 /* Values for Type in APIC_HEADER_DEF */
977 #define APIC_PROCESSOR 0
979 #define APIC_XRUPT_OVERRIDE 2
981 #define APIC_LOCAL_NMI 4
982 #define APIC_ADDRESS_OVERRIDE 5
983 #define APIC_IO_SAPIC 6
984 #define APIC_LOCAL_SAPIC 7
985 #define APIC_XRUPT_SOURCE 8
986 #define APIC_RESERVED 9 /* 9 and greater are reserved */
989 * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
991 #define APIC_HEADER_DEF /* Common APIC sub-structure header */\
995 /* Sub-structures for MADT */
997 struct madt_processor_apic
1000 uint8_t processor_id; /* ACPI processor id */
1001 uint8_t local_apic_id; /* Processor's local APIC id */
1003 uint32_t processor_enabled: 1; /* Processor is usable if set */
1004 uint32_t reserved2 : 31; /* Reserved, must be zero */
1013 uint8_t io_apic_id; /* I/O APIC ID */
1014 uint8_t reserved; /* Reserved - must be zero */
1015 uint32_t address; /* APIC physical address */
1016 uint32_t interrupt; /* Global system interrupt where INTI
1020 #include "acpi-dsdt.hex"
1022 static inline uint16_t cpu_to_le16(uint16_t x)
1027 static inline uint32_t cpu_to_le32(uint32_t x)
1032 static int acpi_checksum(const uint8_t *data, int len)
1036 for(i = 0; i < len; i++)
1038 return (-sum) & 0xff;
1041 static void acpi_build_table_header(struct acpi_table_header *h,
1042 char *sig, int len, uint8_t rev)
1044 memcpy(h->signature, sig, 4);
1045 h->length = cpu_to_le32(len);
1048 memcpy(h->oem_id, "QEMU ", 6);
1049 memcpy(h->oem_table_id, "QEMU", 4);
1051 memcpy(h->oem_id, "BOCHS ", 6);
1052 memcpy(h->oem_table_id, "BXPC", 4);
1054 memcpy(h->oem_table_id + 4, sig, 4);
1055 h->oem_revision = cpu_to_le32(1);
1057 memcpy(h->asl_compiler_id, "QEMU", 4);
1059 memcpy(h->asl_compiler_id, "BXPC", 4);
1061 h->asl_compiler_revision = cpu_to_le32(1);
1062 h->checksum = acpi_checksum((void *)h, len);
1065 int acpi_build_processor_ssdt(uint8_t *ssdt)
1067 uint8_t *ssdt_ptr = ssdt;
1069 int acpi_cpus = smp_cpus > 0xff ? 0xff : smp_cpus;
1071 ssdt_ptr[9] = 0; // checksum;
1072 ssdt_ptr += sizeof(struct acpi_table_header);
1074 // caluculate the length of processor block and scope block excluding PkgLength
1075 length = 0x0d * acpi_cpus + 4;
1077 // build processor scope header
1078 *(ssdt_ptr++) = 0x10; // ScopeOp
1079 if (length <= 0x3e) {
1080 *(ssdt_ptr++) = length + 1;
1082 *(ssdt_ptr++) = 0x7F;
1083 *(ssdt_ptr++) = (length + 2) >> 6;
1085 *(ssdt_ptr++) = '_'; // Name
1086 *(ssdt_ptr++) = 'P';
1087 *(ssdt_ptr++) = 'R';
1088 *(ssdt_ptr++) = '_';
1090 // build object for each processor
1091 for(i=0;i<acpi_cpus;i++) {
1092 *(ssdt_ptr++) = 0x5B; // ProcessorOp
1093 *(ssdt_ptr++) = 0x83;
1094 *(ssdt_ptr++) = 0x0B; // Length
1095 *(ssdt_ptr++) = 'C'; // Name (CPUxx)
1096 *(ssdt_ptr++) = 'P';
1097 if ((i & 0xf0) != 0)
1098 *(ssdt_ptr++) = (i >> 4) < 0xa ? (i >> 4) + '0' : (i >> 4) + 'A' - 0xa;
1100 *(ssdt_ptr++) = 'U';
1101 *(ssdt_ptr++) = (i & 0xf) < 0xa ? (i & 0xf) + '0' : (i & 0xf) + 'A' - 0xa;
1103 *(ssdt_ptr++) = 0x10; // Processor block address
1104 *(ssdt_ptr++) = 0xb0;
1107 *(ssdt_ptr++) = 6; // Processor block length
1110 acpi_build_table_header((struct acpi_table_header *)ssdt,
1111 "SSDT", ssdt_ptr - ssdt, 1);
1113 return ssdt_ptr - ssdt;
1116 /* base_addr must be a multiple of 4KB */
1117 void acpi_bios_init(void)
1119 struct rsdp_descriptor *rsdp;
1120 struct rsdt_descriptor_rev1 *rsdt;
1121 struct fadt_descriptor_rev1 *fadt;
1122 struct facs_descriptor_rev1 *facs;
1123 struct multiple_apic_table *madt;
1124 uint8_t *dsdt, *ssdt;
1125 uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
1126 uint32_t acpi_tables_size, madt_addr, madt_size;
1129 /* reserve memory space for tables */
1130 #ifdef BX_USE_EBDA_TABLES
1131 ebda_cur_addr = align(ebda_cur_addr, 16);
1132 rsdp = (void *)(ebda_cur_addr);
1133 ebda_cur_addr += sizeof(*rsdp);
1135 bios_table_cur_addr = align(bios_table_cur_addr, 16);
1136 rsdp = (void *)(bios_table_cur_addr);
1137 bios_table_cur_addr += sizeof(*rsdp);
1140 addr = base_addr = ram_size - ACPI_DATA_SIZE;
1142 rsdt = (void *)(addr);
1143 addr += sizeof(*rsdt);
1146 fadt = (void *)(addr);
1147 addr += sizeof(*fadt);
1149 /* XXX: FACS should be in RAM */
1150 addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
1152 facs = (void *)(addr);
1153 addr += sizeof(*facs);
1156 dsdt = (void *)(addr);
1157 addr += sizeof(AmlCode);
1160 ssdt = (void *)(addr);
1161 addr += acpi_build_processor_ssdt(ssdt);
1163 addr = (addr + 7) & ~7;
1165 madt_size = sizeof(*madt) +
1166 sizeof(struct madt_processor_apic) * smp_cpus +
1167 sizeof(struct madt_io_apic);
1168 madt = (void *)(addr);
1171 acpi_tables_size = addr - base_addr;
1173 BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n",
1174 (unsigned long)rsdp,
1175 (unsigned long)rsdt, acpi_tables_size);
1178 memset(rsdp, 0, sizeof(*rsdp));
1179 memcpy(rsdp->signature, "RSD PTR ", 8);
1181 memcpy(rsdp->oem_id, "QEMU ", 6);
1183 memcpy(rsdp->oem_id, "BOCHS ", 6);
1185 rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
1186 rsdp->checksum = acpi_checksum((void *)rsdp, 20);
1189 memset(rsdt, 0, sizeof(*rsdt));
1190 rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
1191 rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
1192 rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
1193 acpi_build_table_header((struct acpi_table_header *)rsdt,
1194 "RSDT", sizeof(*rsdt), 1);
1197 memset(fadt, 0, sizeof(*fadt));
1198 fadt->firmware_ctrl = cpu_to_le32(facs_addr);
1199 fadt->dsdt = cpu_to_le32(dsdt_addr);
1201 fadt->reserved1 = 0;
1202 fadt->sci_int = cpu_to_le16(pm_sci_int);
1203 fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
1204 fadt->acpi_enable = 0xf1;
1205 fadt->acpi_disable = 0xf0;
1206 fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
1207 fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
1208 fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
1209 fadt->pm1_evt_len = 4;
1210 fadt->pm1_cnt_len = 2;
1211 fadt->pm_tmr_len = 4;
1212 fadt->plvl2_lat = cpu_to_le16(50);
1213 fadt->plvl3_lat = cpu_to_le16(50);
1214 fadt->plvl3_lat = cpu_to_le16(50);
1215 /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
1216 fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
1217 acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
1221 memset(facs, 0, sizeof(*facs));
1222 memcpy(facs->signature, "FACS", 4);
1223 facs->length = cpu_to_le32(sizeof(*facs));
1226 memcpy(dsdt, AmlCode, sizeof(AmlCode));
1230 struct madt_processor_apic *apic;
1231 struct madt_io_apic *io_apic;
1233 memset(madt, 0, madt_size);
1234 madt->local_apic_address = cpu_to_le32(0xfee00000);
1235 madt->flags = cpu_to_le32(1);
1236 apic = (void *)(madt + 1);
1237 for(i=0;i<smp_cpus;i++) {
1238 apic->type = APIC_PROCESSOR;
1239 apic->length = sizeof(*apic);
1240 apic->processor_id = i;
1241 apic->local_apic_id = i;
1242 apic->flags = cpu_to_le32(1);
1245 io_apic = (void *)apic;
1246 io_apic->type = APIC_IO;
1247 io_apic->length = sizeof(*io_apic);
1248 io_apic->io_apic_id = smp_cpus;
1249 io_apic->address = cpu_to_le32(0xfec00000);
1250 io_apic->interrupt = cpu_to_le32(0);
1252 acpi_build_table_header((struct acpi_table_header *)madt,
1253 "APIC", madt_size, 1);
1257 /* SMBIOS entry point -- must be written to a 16-bit aligned address
1258 between 0xf0000 and 0xfffff.
1260 struct smbios_entry_point {
1261 char anchor_string[4];
1264 uint8_t smbios_major_version;
1265 uint8_t smbios_minor_version;
1266 uint16_t max_structure_size;
1267 uint8_t entry_point_revision;
1268 uint8_t formatted_area[5];
1269 char intermediate_anchor_string[5];
1270 uint8_t intermediate_checksum;
1271 uint16_t structure_table_length;
1272 uint32_t structure_table_address;
1273 uint16_t number_of_structures;
1274 uint8_t smbios_bcd_revision;
1275 } __attribute__((__packed__));
1277 /* This goes at the beginning of every SMBIOS structure. */
1278 struct smbios_structure_header {
1282 } __attribute__((__packed__));
1284 /* SMBIOS type 0 - BIOS Information */
1285 struct smbios_type_0 {
1286 struct smbios_structure_header header;
1288 uint8_t bios_version_str;
1289 uint16_t bios_starting_address_segment;
1290 uint8_t bios_release_date_str;
1291 uint8_t bios_rom_size;
1292 uint8_t bios_characteristics[8];
1293 uint8_t bios_characteristics_extension_bytes[2];
1294 uint8_t system_bios_major_release;
1295 uint8_t system_bios_minor_release;
1296 uint8_t embedded_controller_major_release;
1297 uint8_t embedded_controller_minor_release;
1298 } __attribute__((__packed__));
1300 /* SMBIOS type 1 - System Information */
1301 struct smbios_type_1 {
1302 struct smbios_structure_header header;
1303 uint8_t manufacturer_str;
1304 uint8_t product_name_str;
1305 uint8_t version_str;
1306 uint8_t serial_number_str;
1308 uint8_t wake_up_type;
1309 uint8_t sku_number_str;
1311 } __attribute__((__packed__));
1313 /* SMBIOS type 3 - System Enclosure (v2.3) */
1314 struct smbios_type_3 {
1315 struct smbios_structure_header header;
1316 uint8_t manufacturer_str;
1318 uint8_t version_str;
1319 uint8_t serial_number_str;
1320 uint8_t asset_tag_number_str;
1321 uint8_t boot_up_state;
1322 uint8_t power_supply_state;
1323 uint8_t thermal_state;
1324 uint8_t security_status;
1325 uint32_t oem_defined;
1327 uint8_t number_of_power_cords;
1328 uint8_t contained_element_count;
1329 // contained elements follow
1330 } __attribute__((__packed__));
1332 /* SMBIOS type 4 - Processor Information (v2.0) */
1333 struct smbios_type_4 {
1334 struct smbios_structure_header header;
1335 uint8_t socket_designation_str;
1336 uint8_t processor_type;
1337 uint8_t processor_family;
1338 uint8_t processor_manufacturer_str;
1339 uint32_t processor_id[2];
1340 uint8_t processor_version_str;
1342 uint16_t external_clock;
1344 uint16_t current_speed;
1346 uint8_t processor_upgrade;
1347 } __attribute__((__packed__));
1349 /* SMBIOS type 16 - Physical Memory Array
1350 * Associated with one type 17 (Memory Device).
1352 struct smbios_type_16 {
1353 struct smbios_structure_header header;
1356 uint8_t error_correction;
1357 uint32_t maximum_capacity;
1358 uint16_t memory_error_information_handle;
1359 uint16_t number_of_memory_devices;
1360 } __attribute__((__packed__));
1362 /* SMBIOS type 17 - Memory Device
1363 * Associated with one type 19
1365 struct smbios_type_17 {
1366 struct smbios_structure_header header;
1367 uint16_t physical_memory_array_handle;
1368 uint16_t memory_error_information_handle;
1369 uint16_t total_width;
1370 uint16_t data_width;
1372 uint8_t form_factor;
1374 uint8_t device_locator_str;
1375 uint8_t bank_locator_str;
1376 uint8_t memory_type;
1377 uint16_t type_detail;
1378 } __attribute__((__packed__));
1380 /* SMBIOS type 19 - Memory Array Mapped Address */
1381 struct smbios_type_19 {
1382 struct smbios_structure_header header;
1383 uint32_t starting_address;
1384 uint32_t ending_address;
1385 uint16_t memory_array_handle;
1386 uint8_t partition_width;
1387 } __attribute__((__packed__));
1389 /* SMBIOS type 20 - Memory Device Mapped Address */
1390 struct smbios_type_20 {
1391 struct smbios_structure_header header;
1392 uint32_t starting_address;
1393 uint32_t ending_address;
1394 uint16_t memory_device_handle;
1395 uint16_t memory_array_mapped_address_handle;
1396 uint8_t partition_row_position;
1397 uint8_t interleave_position;
1398 uint8_t interleaved_data_depth;
1399 } __attribute__((__packed__));
1401 /* SMBIOS type 32 - System Boot Information */
1402 struct smbios_type_32 {
1403 struct smbios_structure_header header;
1404 uint8_t reserved[6];
1405 uint8_t boot_status;
1406 } __attribute__((__packed__));
1408 /* SMBIOS type 127 -- End-of-table */
1409 struct smbios_type_127 {
1410 struct smbios_structure_header header;
1411 } __attribute__((__packed__));
1414 smbios_entry_point_init(void *start,
1415 uint16_t max_structure_size,
1416 uint16_t structure_table_length,
1417 uint32_t structure_table_address,
1418 uint16_t number_of_structures)
1422 struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
1424 memcpy(ep->anchor_string, "_SM_", 4);
1426 ep->smbios_major_version = 2;
1427 ep->smbios_minor_version = 4;
1428 ep->max_structure_size = max_structure_size;
1429 ep->entry_point_revision = 0;
1430 memset(ep->formatted_area, 0, 5);
1431 memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
1433 ep->structure_table_length = structure_table_length;
1434 ep->structure_table_address = structure_table_address;
1435 ep->number_of_structures = number_of_structures;
1436 ep->smbios_bcd_revision = 0x24;
1439 ep->intermediate_checksum = 0;
1442 for (i = 0; i < 0x10; i++)
1443 sum += ((int8_t *)start)[i];
1444 ep->checksum = -sum;
1447 for (i = 0x10; i < ep->length; i++)
1448 sum += ((int8_t *)start)[i];
1449 ep->intermediate_checksum = -sum;
1452 /* Type 0 -- BIOS Information */
1453 #define RELEASE_DATE_STR "01/01/2007"
1455 smbios_type_0_init(void *start)
1457 struct smbios_type_0 *p = (struct smbios_type_0 *)start;
1460 p->header.length = sizeof(struct smbios_type_0);
1461 p->header.handle = 0;
1464 p->bios_version_str = 1;
1465 p->bios_starting_address_segment = 0xe800;
1466 p->bios_release_date_str = 2;
1467 p->bios_rom_size = 0; /* FIXME */
1469 memset(p->bios_characteristics, 0, 7);
1470 p->bios_characteristics[7] = 0x08; /* BIOS characteristics not supported */
1471 p->bios_characteristics_extension_bytes[0] = 0;
1472 p->bios_characteristics_extension_bytes[1] = 0;
1474 p->system_bios_major_release = 1;
1475 p->system_bios_minor_release = 0;
1476 p->embedded_controller_major_release = 0xff;
1477 p->embedded_controller_minor_release = 0xff;
1479 start += sizeof(struct smbios_type_0);
1480 memcpy((char *)start, BX_APPNAME, sizeof(BX_APPNAME));
1481 start += sizeof(BX_APPNAME);
1482 memcpy((char *)start, RELEASE_DATE_STR, sizeof(RELEASE_DATE_STR));
1483 start += sizeof(RELEASE_DATE_STR);
1484 *((uint8_t *)start) = 0;
1489 /* Type 1 -- System Information */
1491 smbios_type_1_init(void *start)
1493 struct smbios_type_1 *p = (struct smbios_type_1 *)start;
1495 p->header.length = sizeof(struct smbios_type_1);
1496 p->header.handle = 0x100;
1498 p->manufacturer_str = 0;
1499 p->product_name_str = 0;
1501 p->serial_number_str = 0;
1503 memcpy(p->uuid, bios_uuid, 16);
1505 p->wake_up_type = 0x06; /* power switch */
1506 p->sku_number_str = 0;
1509 start += sizeof(struct smbios_type_1);
1510 *((uint16_t *)start) = 0;
1515 /* Type 3 -- System Enclosure */
1517 smbios_type_3_init(void *start)
1519 struct smbios_type_3 *p = (struct smbios_type_3 *)start;
1522 p->header.length = sizeof(struct smbios_type_3);
1523 p->header.handle = 0x300;
1525 p->manufacturer_str = 0;
1526 p->type = 0x01; /* other */
1528 p->serial_number_str = 0;
1529 p->asset_tag_number_str = 0;
1530 p->boot_up_state = 0x03; /* safe */
1531 p->power_supply_state = 0x03; /* safe */
1532 p->thermal_state = 0x03; /* safe */
1533 p->security_status = 0x02; /* unknown */
1536 p->number_of_power_cords = 0;
1537 p->contained_element_count = 0;
1539 start += sizeof(struct smbios_type_3);
1540 *((uint16_t *)start) = 0;
1545 /* Type 4 -- Processor Information */
1547 smbios_type_4_init(void *start, unsigned int cpu_number)
1549 struct smbios_type_4 *p = (struct smbios_type_4 *)start;
1552 p->header.length = sizeof(struct smbios_type_4);
1553 p->header.handle = 0x400 + cpu_number;
1555 p->socket_designation_str = 1;
1556 p->processor_type = 0x03; /* CPU */
1557 p->processor_family = 0x01; /* other */
1558 p->processor_manufacturer_str = 0;
1560 p->processor_id[0] = cpuid_signature;
1561 p->processor_id[1] = cpuid_features;
1563 p->processor_version_str = 0;
1565 p->external_clock = 0;
1567 p->max_speed = 0; /* unknown */
1568 p->current_speed = 0; /* unknown */
1570 p->status = 0x41; /* socket populated, CPU enabled */
1571 p->processor_upgrade = 0x01; /* other */
1573 start += sizeof(struct smbios_type_4);
1575 memcpy((char *)start, "CPU " "\0" "" "\0" "", 7);
1576 ((char *)start)[4] = cpu_number + '0';
1581 /* Type 16 -- Physical Memory Array */
1583 smbios_type_16_init(void *start, uint32_t memsize)
1585 struct smbios_type_16 *p = (struct smbios_type_16*)start;
1587 p->header.type = 16;
1588 p->header.length = sizeof(struct smbios_type_16);
1589 p->header.handle = 0x1000;
1591 p->location = 0x01; /* other */
1592 p->use = 0x03; /* system memory */
1593 p->error_correction = 0x01; /* other */
1594 p->maximum_capacity = memsize * 1024;
1595 p->memory_error_information_handle = 0xfffe; /* none provided */
1596 p->number_of_memory_devices = 1;
1598 start += sizeof(struct smbios_type_16);
1599 *((uint16_t *)start) = 0;
1604 /* Type 17 -- Memory Device */
1606 smbios_type_17_init(void *start, uint32_t memory_size_mb)
1608 struct smbios_type_17 *p = (struct smbios_type_17 *)start;
1610 p->header.type = 17;
1611 p->header.length = sizeof(struct smbios_type_17);
1612 p->header.handle = 0x1100;
1614 p->physical_memory_array_handle = 0x1000;
1615 p->total_width = 64;
1617 /* truncate memory_size_mb to 16 bits and clear most significant
1618 bit [indicates size in MB] */
1619 p->size = (uint16_t) memory_size_mb & 0x7fff;
1620 p->form_factor = 0x09; /* DIMM */
1622 p->device_locator_str = 1;
1623 p->bank_locator_str = 0;
1624 p->memory_type = 0x07; /* RAM */
1627 start += sizeof(struct smbios_type_17);
1628 memcpy((char *)start, "DIMM 1", 7);
1630 *((uint8_t *)start) = 0;
1635 /* Type 19 -- Memory Array Mapped Address */
1637 smbios_type_19_init(void *start, uint32_t memory_size_mb)
1639 struct smbios_type_19 *p = (struct smbios_type_19 *)start;
1641 p->header.type = 19;
1642 p->header.length = sizeof(struct smbios_type_19);
1643 p->header.handle = 0x1300;
1645 p->starting_address = 0;
1646 p->ending_address = (memory_size_mb-1) * 1024;
1647 p->memory_array_handle = 0x1000;
1648 p->partition_width = 1;
1650 start += sizeof(struct smbios_type_19);
1651 *((uint16_t *)start) = 0;
1656 /* Type 20 -- Memory Device Mapped Address */
1658 smbios_type_20_init(void *start, uint32_t memory_size_mb)
1660 struct smbios_type_20 *p = (struct smbios_type_20 *)start;
1662 p->header.type = 20;
1663 p->header.length = sizeof(struct smbios_type_20);
1664 p->header.handle = 0x1400;
1666 p->starting_address = 0;
1667 p->ending_address = (memory_size_mb-1)*1024;
1668 p->memory_device_handle = 0x1100;
1669 p->memory_array_mapped_address_handle = 0x1300;
1670 p->partition_row_position = 1;
1671 p->interleave_position = 0;
1672 p->interleaved_data_depth = 0;
1674 start += sizeof(struct smbios_type_20);
1676 *((uint16_t *)start) = 0;
1680 /* Type 32 -- System Boot Information */
1682 smbios_type_32_init(void *start)
1684 struct smbios_type_32 *p = (struct smbios_type_32 *)start;
1686 p->header.type = 32;
1687 p->header.length = sizeof(struct smbios_type_32);
1688 p->header.handle = 0x2000;
1689 memset(p->reserved, 0, 6);
1690 p->boot_status = 0; /* no errors detected */
1692 start += sizeof(struct smbios_type_32);
1693 *((uint16_t *)start) = 0;
1698 /* Type 127 -- End of Table */
1700 smbios_type_127_init(void *start)
1702 struct smbios_type_127 *p = (struct smbios_type_127 *)start;
1704 p->header.type = 127;
1705 p->header.length = sizeof(struct smbios_type_127);
1706 p->header.handle = 0x7f00;
1708 start += sizeof(struct smbios_type_127);
1709 *((uint16_t *)start) = 0;
1714 void smbios_init(void)
1716 unsigned cpu_num, nr_structs = 0, max_struct_size = 0;
1717 char *start, *p, *q;
1718 int memsize = ram_size / (1024 * 1024);
1720 #ifdef BX_USE_EBDA_TABLES
1721 ebda_cur_addr = align(ebda_cur_addr, 16);
1722 start = (void *)(ebda_cur_addr);
1724 bios_table_cur_addr = align(bios_table_cur_addr, 16);
1725 start = (void *)(bios_table_cur_addr);
1728 p = (char *)start + sizeof(struct smbios_entry_point);
1730 #define add_struct(fn) { \
1733 if ((q - p) > max_struct_size) \
1734 max_struct_size = q - p; \
1738 add_struct(smbios_type_0_init(p));
1739 add_struct(smbios_type_1_init(p));
1740 add_struct(smbios_type_3_init(p));
1741 for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++)
1742 add_struct(smbios_type_4_init(p, cpu_num));
1743 add_struct(smbios_type_16_init(p, memsize));
1744 add_struct(smbios_type_17_init(p, memsize));
1745 add_struct(smbios_type_19_init(p, memsize));
1746 add_struct(smbios_type_20_init(p, memsize));
1747 add_struct(smbios_type_32_init(p));
1748 add_struct(smbios_type_127_init(p));
1752 smbios_entry_point_init(
1753 start, max_struct_size,
1754 (p - (char *)start) - sizeof(struct smbios_entry_point),
1755 (uint32_t)(start + sizeof(struct smbios_entry_point)),
1758 #ifdef BX_USE_EBDA_TABLES
1759 ebda_cur_addr += (p - (char *)start);
1761 bios_table_cur_addr += (p - (char *)start);
1764 BX_INFO("SMBIOS table addr=0x%08lx\n", (unsigned long)start);
1767 void rombios32_init(void)
1769 BX_INFO("Starting rombios32\n");
1781 if (bios_table_cur_addr != 0) {
1790 bios_lock_shadow_ram();
1792 BX_INFO("bios_table_cur_addr: 0x%08lx\n", bios_table_cur_addr);
1793 if (bios_table_cur_addr > bios_table_end_addr)
1794 BX_PANIC("bios_table_end_addr overflow!\n");