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;
354 static void bios_lock_shadow_ram(void)
356 PCIDevice *d = &i440_pcidev;
360 v = pci_config_readb(d, 0x59);
361 v = (v & 0x0f) | (0x10);
362 pci_config_writeb(d, 0x59, v);
365 static void pci_bios_init_bridges(PCIDevice *d)
367 uint16_t vendor_id, device_id;
369 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
370 device_id = pci_config_readw(d, PCI_DEVICE_ID);
372 if (vendor_id == 0x8086 && device_id == 0x7000) {
380 for(i = 0; i < 4; i++) {
382 /* set to trigger level */
383 elcr[irq >> 3] |= (1 << (irq & 7));
384 /* activate irq remapping in PIIX */
385 pci_config_writeb(d, 0x60 + i, irq);
387 outb(elcr[0], 0x4d0);
388 outb(elcr[1], 0x4d1);
389 BX_INFO("PIIX3 init: elcr=%02x %02x\n",
391 } else if (vendor_id == 0x8086 && device_id == 0x1237) {
392 /* i440 PCI bridge */
398 ".globl smp_ap_boot_code_start\n"
399 ".globl smp_ap_boot_code_end\n"
400 ".global smm_relocation_start\n"
401 ".global smm_relocation_end\n"
402 ".global smm_code_start\n"
403 ".global smm_code_end\n"
406 "smp_ap_boot_code_start:\n"
409 " incw " __stringify(CPU_COUNT_ADDR) "\n"
413 "smp_ap_boot_code_end:\n"
415 /* code to relocate SMBASE to 0xa0000 */
416 "smm_relocation_start:\n"
417 " mov $0x38000 + 0x7efc, %ebx\n"
418 " addr32 mov (%ebx), %al\n" /* revision ID to see if x86_64 or x86 */
421 " mov $0x38000 + 0x7ef8, %ebx\n"
424 " mov $0x38000 + 0x7f00, %ebx\n"
426 " movl $0xa0000, %eax\n"
427 " addr32 movl %eax, (%ebx)\n"
428 /* indicate to the BIOS that the SMM code was executed */
433 "smm_relocation_end:\n"
435 /* minimal SMM code to enable or disable ACPI */
443 " mov $" __stringify(PM_IO_BASE) " + 0x04, %dx\n" /* PMCNTRL */
455 " mov $" __stringify(PM_IO_BASE) " + 0x04, %dx\n" /* PMCNTRL */
466 extern uint8_t smm_relocation_start, smm_relocation_end;
467 extern uint8_t smm_code_start, smm_code_end;
470 static void smm_init(PCIDevice *d)
474 /* check if SMM init is already done */
475 value = pci_config_readl(d, 0x58);
476 if ((value & (1 << 25)) == 0) {
478 /* copy the SMM relocation code */
479 memcpy((void *)0x38000, &smm_relocation_start,
480 &smm_relocation_end - &smm_relocation_start);
482 /* enable SMI generation when writing to the APMC register */
483 pci_config_writel(d, 0x58, value | (1 << 25));
485 /* init APM status port */
488 /* raise an SMI interrupt */
491 /* wait until SMM code executed */
492 while (inb(0xb3) != 0x00);
494 /* enable the SMM memory window */
495 pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x48);
497 /* copy the SMM code */
498 memcpy((void *)0xa8000, &smm_code_start,
499 &smm_code_end - &smm_code_start);
502 /* close the SMM memory window and enable normal SMM */
503 pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08);
508 static void pci_bios_init_device(PCIDevice *d)
512 int i, pin, pic_irq, vendor_id, device_id;
514 class = pci_config_readw(d, PCI_CLASS_DEVICE);
515 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
516 device_id = pci_config_readw(d, PCI_DEVICE_ID);
517 BX_INFO("PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n",
518 d->bus, d->devfn, vendor_id, device_id);
521 if (vendor_id == 0x8086 && device_id == 0x7010) {
523 pci_config_writew(d, 0x40, 0x8000); // enable IDE0
524 pci_config_writew(d, 0x42, 0x8000); // enable IDE1
527 /* IDE: we map it as in ISA mode */
528 pci_set_io_region_addr(d, 0, 0x1f0);
529 pci_set_io_region_addr(d, 1, 0x3f4);
530 pci_set_io_region_addr(d, 2, 0x170);
531 pci_set_io_region_addr(d, 3, 0x374);
535 if (vendor_id != 0x1234)
537 /* VGA: map frame buffer to default Bochs VBE address */
538 pci_set_io_region_addr(d, 0, 0xE0000000);
542 if (vendor_id == 0x1014) {
544 if (device_id == 0x0046 || device_id == 0xFFFF) {
546 pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
551 if (vendor_id == 0x0106b &&
552 (device_id == 0x0017 || device_id == 0x0022)) {
554 pci_set_io_region_addr(d, 0, 0x80800000);
559 /* default memory mappings */
560 for(i = 0; i < PCI_NUM_REGIONS; i++) {
564 if (i == PCI_ROM_SLOT)
568 pci_config_writel(d, ofs, 0xffffffff);
569 val = pci_config_readl(d, ofs);
571 size = (~(val & ~0xf)) + 1;
572 if (val & PCI_ADDRESS_SPACE_IO)
573 paddr = &pci_bios_io_addr;
574 else if (size >= 0x04000000)
575 paddr = &pci_bios_bigmem_addr;
577 paddr = &pci_bios_mem_addr;
578 *paddr = (*paddr + size - 1) & ~(size - 1);
579 pci_set_io_region_addr(d, i, *paddr);
586 /* map the interrupt */
587 pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
589 pin = pci_slot_get_pirq(d, pin - 1);
590 pic_irq = pci_irqs[pin];
591 pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
594 if (vendor_id == 0x8086 && device_id == 0x7113) {
595 /* PIIX4 Power Management device (for ACPI) */
596 pm_io_base = PM_IO_BASE;
597 pci_config_writel(d, 0x40, pm_io_base | 1);
598 pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */
599 smb_io_base = SMB_IO_BASE;
600 pci_config_writel(d, 0x90, smb_io_base | 1);
601 pci_config_writeb(d, 0xd2, 0x09); /* enable SMBus io space */
602 pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE);
610 void pci_for_each_device(void (*init_func)(PCIDevice *d))
612 PCIDevice d1, *d = &d1;
614 uint16_t vendor_id, device_id;
616 for(bus = 0; bus < 1; bus++) {
617 for(devfn = 0; devfn < 256; devfn++) {
620 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
621 device_id = pci_config_readw(d, PCI_DEVICE_ID);
622 if (vendor_id != 0xffff || device_id != 0xffff) {
629 void pci_bios_init(void)
631 pci_bios_io_addr = 0xc000;
632 pci_bios_mem_addr = 0xf0000000;
633 pci_bios_bigmem_addr = ram_size;
634 if (pci_bios_bigmem_addr < 0x90000000)
635 pci_bios_bigmem_addr = 0x90000000;
637 pci_for_each_device(pci_bios_init_bridges);
639 pci_for_each_device(pci_bios_init_device);
642 /****************************************************/
643 /* Multi Processor table init */
645 static void putb(uint8_t **pp, int val)
653 static void putstr(uint8_t **pp, const char *str)
662 static void putle16(uint8_t **pp, int val)
671 static void putle32(uint8_t **pp, int val)
682 static int mpf_checksum(const uint8_t *data, int len)
686 for(i = 0; i < len; i++)
691 static unsigned long align(unsigned long addr, unsigned long v)
693 return (addr + v - 1) & ~(v - 1);
696 static void mptable_init(void)
698 uint8_t *mp_config_table, *q, *float_pointer_struct;
699 int ioapic_id, i, len;
700 int mp_config_table_size;
707 #ifdef BX_USE_EBDA_TABLES
708 mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE);
710 bios_table_cur_addr = align(bios_table_cur_addr, 16);
711 mp_config_table = (uint8_t *)bios_table_cur_addr;
714 putstr(&q, "PCMP"); /* "PCMP signature */
715 putle16(&q, 0); /* table length (patched later) */
716 putb(&q, 4); /* spec rev */
717 putb(&q, 0); /* checksum (patched later) */
719 putstr(&q, "QEMUCPU "); /* OEM id */
721 putstr(&q, "BOCHSCPU");
723 putstr(&q, "0.1 "); /* vendor id */
724 putle32(&q, 0); /* OEM table ptr */
725 putle16(&q, 0); /* OEM table size */
726 putle16(&q, smp_cpus + 18); /* entry count */
727 putle32(&q, 0xfee00000); /* local APIC addr */
728 putle16(&q, 0); /* ext table length */
729 putb(&q, 0); /* ext table checksum */
730 putb(&q, 0); /* reserved */
732 for(i = 0; i < smp_cpus; i++) {
733 putb(&q, 0); /* entry type = processor */
734 putb(&q, i); /* APIC id */
735 putb(&q, 0x11); /* local APIC version number */
737 putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
739 putb(&q, 1); /* cpu flags: enabled */
740 putb(&q, 0); /* cpu signature */
744 putle16(&q, 0x201); /* feature flags */
747 putle16(&q, 0); /* reserved */
754 putb(&q, 1); /* entry type = bus */
755 putb(&q, 0); /* bus ID */
759 ioapic_id = smp_cpus;
760 putb(&q, 2); /* entry type = I/O APIC */
761 putb(&q, ioapic_id); /* apic ID */
762 putb(&q, 0x11); /* I/O APIC version number */
763 putb(&q, 1); /* enable */
764 putle32(&q, 0xfec00000); /* I/O APIC addr */
767 for(i = 0; i < 16; i++) {
768 putb(&q, 3); /* entry type = I/O interrupt */
769 putb(&q, 0); /* interrupt type = vectored interrupt */
770 putb(&q, 0); /* flags: po=0, el=0 */
772 putb(&q, 0); /* source bus ID = ISA */
773 putb(&q, i); /* source bus IRQ */
774 putb(&q, ioapic_id); /* dest I/O APIC ID */
775 putb(&q, i); /* dest I/O APIC interrupt in */
778 len = q - mp_config_table;
779 mp_config_table[4] = len;
780 mp_config_table[5] = len >> 8;
782 mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
784 mp_config_table_size = q - mp_config_table;
786 #ifndef BX_USE_EBDA_TABLES
787 bios_table_cur_addr += mp_config_table_size;
790 /* floating pointer structure */
791 #ifdef BX_USE_EBDA_TABLES
792 ebda_cur_addr = align(ebda_cur_addr, 16);
793 float_pointer_struct = (uint8_t *)ebda_cur_addr;
795 bios_table_cur_addr = align(bios_table_cur_addr, 16);
796 float_pointer_struct = (uint8_t *)bios_table_cur_addr;
798 q = float_pointer_struct;
800 /* pointer to MP config table */
801 putle32(&q, (unsigned long)mp_config_table);
803 putb(&q, 1); /* length in 16 byte units */
804 putb(&q, 4); /* MP spec revision */
805 putb(&q, 0); /* checksum (patched later) */
806 putb(&q, 0); /* MP feature byte 1 */
812 float_pointer_struct[10] =
813 -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
814 #ifdef BX_USE_EBDA_TABLES
815 ebda_cur_addr += (q - float_pointer_struct);
817 bios_table_cur_addr += (q - float_pointer_struct);
819 BX_INFO("MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n",
820 (unsigned long)float_pointer_struct,
821 (unsigned long)mp_config_table,
822 mp_config_table_size);
825 /****************************************************/
826 /* ACPI tables init */
828 /* Table structure from Linux kernel (the ACPI tables are under the
831 #define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
832 uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\
833 uint32_t length; /* Length of table, in bytes, including header */\
834 uint8_t revision; /* ACPI Specification minor version # */\
835 uint8_t checksum; /* To make sum of entire table == 0 */\
836 uint8_t oem_id [6]; /* OEM identification */\
837 uint8_t oem_table_id [8]; /* OEM table identification */\
838 uint32_t oem_revision; /* OEM revision number */\
839 uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\
840 uint32_t asl_compiler_revision; /* ASL compiler revision number */
843 struct acpi_table_header /* ACPI common table header */
845 ACPI_TABLE_HEADER_DEF
848 struct rsdp_descriptor /* Root System Descriptor Pointer */
850 uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */
851 uint8_t checksum; /* To make sum of struct == 0 */
852 uint8_t oem_id [6]; /* OEM identification */
853 uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
854 uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
855 uint32_t length; /* XSDT Length in bytes including hdr */
856 uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
857 uint8_t extended_checksum; /* Checksum of entire table */
858 uint8_t reserved [3]; /* Reserved field must be 0 */
862 * ACPI 1.0 Root System Description Table (RSDT)
864 struct rsdt_descriptor_rev1
866 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
867 uint32_t table_offset_entry [3]; /* Array of pointers to other */
872 * ACPI 1.0 Firmware ACPI Control Structure (FACS)
874 struct facs_descriptor_rev1
876 uint8_t signature[4]; /* ACPI Signature */
877 uint32_t length; /* Length of structure, in bytes */
878 uint32_t hardware_signature; /* Hardware configuration signature */
879 uint32_t firmware_waking_vector; /* ACPI OS waking vector */
880 uint32_t global_lock; /* Global Lock */
881 uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */
882 uint32_t reserved1 : 31; /* Must be 0 */
883 uint8_t resverved3 [40]; /* Reserved - must be zero */
888 * ACPI 1.0 Fixed ACPI Description Table (FADT)
890 struct fadt_descriptor_rev1
892 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
893 uint32_t firmware_ctrl; /* Physical address of FACS */
894 uint32_t dsdt; /* Physical address of DSDT */
895 uint8_t model; /* System Interrupt Model */
896 uint8_t reserved1; /* Reserved */
897 uint16_t sci_int; /* System vector of SCI interrupt */
898 uint32_t smi_cmd; /* Port address of SMI command port */
899 uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */
900 uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */
901 uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
902 uint8_t reserved2; /* Reserved - must be zero */
903 uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
904 uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
905 uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
906 uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
907 uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
908 uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
909 uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
910 uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
911 uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
912 uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
913 uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
914 uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
915 uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
916 uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
917 uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */
918 uint8_t reserved3; /* Reserved */
919 uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
920 uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
921 uint16_t flush_size; /* Size of area read to flush caches */
922 uint16_t flush_stride; /* Stride used in flushing caches */
923 uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */
924 uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */
925 uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
926 uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
927 uint8_t century; /* Index to century in RTC CMOS RAM */
928 uint8_t reserved4; /* Reserved */
929 uint8_t reserved4a; /* Reserved */
930 uint8_t reserved4b; /* Reserved */
932 uint32_t wb_invd : 1; /* The wbinvd instruction works properly */
933 uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
934 uint32_t proc_c1 : 1; /* All processors support C1 state */
935 uint32_t plvl2_up : 1; /* C2 state works on MP system */
936 uint32_t pwr_button : 1; /* Power button is handled as a generic feature */
937 uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
938 uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
939 uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
940 uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
941 uint32_t reserved5 : 23; /* Reserved - must be zero */
948 * MADT values and structures
951 /* Values for MADT PCATCompat */
954 #define MULTIPLE_APIC 1
959 struct multiple_apic_table
961 ACPI_TABLE_HEADER_DEF /* ACPI common table header */
962 uint32_t local_apic_address; /* Physical address of local APIC */
964 uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */
965 uint32_t reserved1 : 31;
972 /* Values for Type in APIC_HEADER_DEF */
974 #define APIC_PROCESSOR 0
976 #define APIC_XRUPT_OVERRIDE 2
978 #define APIC_LOCAL_NMI 4
979 #define APIC_ADDRESS_OVERRIDE 5
980 #define APIC_IO_SAPIC 6
981 #define APIC_LOCAL_SAPIC 7
982 #define APIC_XRUPT_SOURCE 8
983 #define APIC_RESERVED 9 /* 9 and greater are reserved */
986 * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
988 #define APIC_HEADER_DEF /* Common APIC sub-structure header */\
992 /* Sub-structures for MADT */
994 struct madt_processor_apic
997 uint8_t processor_id; /* ACPI processor id */
998 uint8_t local_apic_id; /* Processor's local APIC id */
1000 uint32_t processor_enabled: 1; /* Processor is usable if set */
1001 uint32_t reserved2 : 31; /* Reserved, must be zero */
1010 uint8_t io_apic_id; /* I/O APIC ID */
1011 uint8_t reserved; /* Reserved - must be zero */
1012 uint32_t address; /* APIC physical address */
1013 uint32_t interrupt; /* Global system interrupt where INTI
1017 #include "acpi-dsdt.hex"
1019 static inline uint16_t cpu_to_le16(uint16_t x)
1024 static inline uint32_t cpu_to_le32(uint32_t x)
1029 static int acpi_checksum(const uint8_t *data, int len)
1033 for(i = 0; i < len; i++)
1035 return (-sum) & 0xff;
1038 static void acpi_build_table_header(struct acpi_table_header *h,
1039 char *sig, int len, uint8_t rev)
1041 memcpy(h->signature, sig, 4);
1042 h->length = cpu_to_le32(len);
1045 memcpy(h->oem_id, "QEMU ", 6);
1046 memcpy(h->oem_table_id, "QEMU", 4);
1048 memcpy(h->oem_id, "BOCHS ", 6);
1049 memcpy(h->oem_table_id, "BXPC", 4);
1051 memcpy(h->oem_table_id + 4, sig, 4);
1052 h->oem_revision = cpu_to_le32(1);
1054 memcpy(h->asl_compiler_id, "QEMU", 4);
1056 memcpy(h->asl_compiler_id, "BXPC", 4);
1058 h->asl_compiler_revision = cpu_to_le32(1);
1059 h->checksum = acpi_checksum((void *)h, len);
1062 int acpi_build_processor_ssdt(uint8_t *ssdt)
1064 uint8_t *ssdt_ptr = ssdt;
1066 int acpi_cpus = smp_cpus > 0xff ? 0xff : smp_cpus;
1068 ssdt_ptr[9] = 0; // checksum;
1069 ssdt_ptr += sizeof(struct acpi_table_header);
1071 // caluculate the length of processor block and scope block excluding PkgLength
1072 length = 0x0d * acpi_cpus + 4;
1074 // build processor scope header
1075 *(ssdt_ptr++) = 0x10; // ScopeOp
1076 if (length <= 0x3e) {
1077 *(ssdt_ptr++) = length + 1;
1079 *(ssdt_ptr++) = 0x7F;
1080 *(ssdt_ptr++) = (length + 2) >> 6;
1082 *(ssdt_ptr++) = '_'; // Name
1083 *(ssdt_ptr++) = 'P';
1084 *(ssdt_ptr++) = 'R';
1085 *(ssdt_ptr++) = '_';
1087 // build object for each processor
1088 for(i=0;i<acpi_cpus;i++) {
1089 *(ssdt_ptr++) = 0x5B; // ProcessorOp
1090 *(ssdt_ptr++) = 0x83;
1091 *(ssdt_ptr++) = 0x0B; // Length
1092 *(ssdt_ptr++) = 'C'; // Name (CPUxx)
1093 *(ssdt_ptr++) = 'P';
1094 if ((i & 0xf0) != 0)
1095 *(ssdt_ptr++) = (i >> 4) < 0xa ? (i >> 4) + '0' : (i >> 4) + 'A' - 0xa;
1097 *(ssdt_ptr++) = 'U';
1098 *(ssdt_ptr++) = (i & 0xf) < 0xa ? (i & 0xf) + '0' : (i & 0xf) + 'A' - 0xa;
1100 *(ssdt_ptr++) = 0x10; // Processor block address
1101 *(ssdt_ptr++) = 0xb0;
1104 *(ssdt_ptr++) = 6; // Processor block length
1107 acpi_build_table_header((struct acpi_table_header *)ssdt,
1108 "SSDT", ssdt_ptr - ssdt, 1);
1110 return ssdt_ptr - ssdt;
1113 /* base_addr must be a multiple of 4KB */
1114 void acpi_bios_init(void)
1116 struct rsdp_descriptor *rsdp;
1117 struct rsdt_descriptor_rev1 *rsdt;
1118 struct fadt_descriptor_rev1 *fadt;
1119 struct facs_descriptor_rev1 *facs;
1120 struct multiple_apic_table *madt;
1121 uint8_t *dsdt, *ssdt;
1122 uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
1123 uint32_t acpi_tables_size, madt_addr, madt_size;
1126 /* reserve memory space for tables */
1127 #ifdef BX_USE_EBDA_TABLES
1128 ebda_cur_addr = align(ebda_cur_addr, 16);
1129 rsdp = (void *)(ebda_cur_addr);
1130 ebda_cur_addr += sizeof(*rsdp);
1132 bios_table_cur_addr = align(bios_table_cur_addr, 16);
1133 rsdp = (void *)(bios_table_cur_addr);
1134 bios_table_cur_addr += sizeof(*rsdp);
1137 addr = base_addr = ram_size - ACPI_DATA_SIZE;
1139 rsdt = (void *)(addr);
1140 addr += sizeof(*rsdt);
1143 fadt = (void *)(addr);
1144 addr += sizeof(*fadt);
1146 /* XXX: FACS should be in RAM */
1147 addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
1149 facs = (void *)(addr);
1150 addr += sizeof(*facs);
1153 dsdt = (void *)(addr);
1154 addr += sizeof(AmlCode);
1157 ssdt = (void *)(addr);
1158 addr += acpi_build_processor_ssdt(ssdt);
1160 addr = (addr + 7) & ~7;
1162 madt_size = sizeof(*madt) +
1163 sizeof(struct madt_processor_apic) * smp_cpus +
1164 sizeof(struct madt_io_apic);
1165 madt = (void *)(addr);
1168 acpi_tables_size = addr - base_addr;
1170 BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n",
1171 (unsigned long)rsdp,
1172 (unsigned long)rsdt, acpi_tables_size);
1175 memset(rsdp, 0, sizeof(*rsdp));
1176 memcpy(rsdp->signature, "RSD PTR ", 8);
1178 memcpy(rsdp->oem_id, "QEMU ", 6);
1180 memcpy(rsdp->oem_id, "BOCHS ", 6);
1182 rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
1183 rsdp->checksum = acpi_checksum((void *)rsdp, 20);
1186 memset(rsdt, 0, sizeof(*rsdt));
1187 rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
1188 rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
1189 rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
1190 acpi_build_table_header((struct acpi_table_header *)rsdt,
1191 "RSDT", sizeof(*rsdt), 1);
1194 memset(fadt, 0, sizeof(*fadt));
1195 fadt->firmware_ctrl = cpu_to_le32(facs_addr);
1196 fadt->dsdt = cpu_to_le32(dsdt_addr);
1198 fadt->reserved1 = 0;
1199 fadt->sci_int = cpu_to_le16(pm_sci_int);
1200 fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
1201 fadt->acpi_enable = 0xf1;
1202 fadt->acpi_disable = 0xf0;
1203 fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
1204 fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
1205 fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
1206 fadt->pm1_evt_len = 4;
1207 fadt->pm1_cnt_len = 2;
1208 fadt->pm_tmr_len = 4;
1209 fadt->plvl2_lat = cpu_to_le16(50);
1210 fadt->plvl3_lat = cpu_to_le16(50);
1211 fadt->plvl3_lat = cpu_to_le16(50);
1212 /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
1213 fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
1214 acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
1218 memset(facs, 0, sizeof(*facs));
1219 memcpy(facs->signature, "FACS", 4);
1220 facs->length = cpu_to_le32(sizeof(*facs));
1223 memcpy(dsdt, AmlCode, sizeof(AmlCode));
1227 struct madt_processor_apic *apic;
1228 struct madt_io_apic *io_apic;
1230 memset(madt, 0, madt_size);
1231 madt->local_apic_address = cpu_to_le32(0xfee00000);
1232 madt->flags = cpu_to_le32(1);
1233 apic = (void *)(madt + 1);
1234 for(i=0;i<smp_cpus;i++) {
1235 apic->type = APIC_PROCESSOR;
1236 apic->length = sizeof(*apic);
1237 apic->processor_id = i;
1238 apic->local_apic_id = i;
1239 apic->flags = cpu_to_le32(1);
1242 io_apic = (void *)apic;
1243 io_apic->type = APIC_IO;
1244 io_apic->length = sizeof(*io_apic);
1245 io_apic->io_apic_id = smp_cpus;
1246 io_apic->address = cpu_to_le32(0xfec00000);
1247 io_apic->interrupt = cpu_to_le32(0);
1249 acpi_build_table_header((struct acpi_table_header *)madt,
1250 "APIC", madt_size, 1);
1254 /* SMBIOS entry point -- must be written to a 16-bit aligned address
1255 between 0xf0000 and 0xfffff.
1257 struct smbios_entry_point {
1258 char anchor_string[4];
1261 uint8_t smbios_major_version;
1262 uint8_t smbios_minor_version;
1263 uint16_t max_structure_size;
1264 uint8_t entry_point_revision;
1265 uint8_t formatted_area[5];
1266 char intermediate_anchor_string[5];
1267 uint8_t intermediate_checksum;
1268 uint16_t structure_table_length;
1269 uint32_t structure_table_address;
1270 uint16_t number_of_structures;
1271 uint8_t smbios_bcd_revision;
1272 } __attribute__((__packed__));
1274 /* This goes at the beginning of every SMBIOS structure. */
1275 struct smbios_structure_header {
1279 } __attribute__((__packed__));
1281 /* SMBIOS type 0 - BIOS Information */
1282 struct smbios_type_0 {
1283 struct smbios_structure_header header;
1285 uint8_t bios_version_str;
1286 uint16_t bios_starting_address_segment;
1287 uint8_t bios_release_date_str;
1288 uint8_t bios_rom_size;
1289 uint8_t bios_characteristics[8];
1290 uint8_t bios_characteristics_extension_bytes[2];
1291 uint8_t system_bios_major_release;
1292 uint8_t system_bios_minor_release;
1293 uint8_t embedded_controller_major_release;
1294 uint8_t embedded_controller_minor_release;
1295 } __attribute__((__packed__));
1297 /* SMBIOS type 1 - System Information */
1298 struct smbios_type_1 {
1299 struct smbios_structure_header header;
1300 uint8_t manufacturer_str;
1301 uint8_t product_name_str;
1302 uint8_t version_str;
1303 uint8_t serial_number_str;
1305 uint8_t wake_up_type;
1306 uint8_t sku_number_str;
1308 } __attribute__((__packed__));
1310 /* SMBIOS type 3 - System Enclosure (v2.3) */
1311 struct smbios_type_3 {
1312 struct smbios_structure_header header;
1313 uint8_t manufacturer_str;
1315 uint8_t version_str;
1316 uint8_t serial_number_str;
1317 uint8_t asset_tag_number_str;
1318 uint8_t boot_up_state;
1319 uint8_t power_supply_state;
1320 uint8_t thermal_state;
1321 uint8_t security_status;
1322 uint32_t oem_defined;
1324 uint8_t number_of_power_cords;
1325 uint8_t contained_element_count;
1326 // contained elements follow
1327 } __attribute__((__packed__));
1329 /* SMBIOS type 4 - Processor Information (v2.0) */
1330 struct smbios_type_4 {
1331 struct smbios_structure_header header;
1332 uint8_t socket_designation_str;
1333 uint8_t processor_type;
1334 uint8_t processor_family;
1335 uint8_t processor_manufacturer_str;
1336 uint32_t processor_id[2];
1337 uint8_t processor_version_str;
1339 uint16_t external_clock;
1341 uint16_t current_speed;
1343 uint8_t processor_upgrade;
1344 } __attribute__((__packed__));
1346 /* SMBIOS type 16 - Physical Memory Array
1347 * Associated with one type 17 (Memory Device).
1349 struct smbios_type_16 {
1350 struct smbios_structure_header header;
1353 uint8_t error_correction;
1354 uint32_t maximum_capacity;
1355 uint16_t memory_error_information_handle;
1356 uint16_t number_of_memory_devices;
1357 } __attribute__((__packed__));
1359 /* SMBIOS type 17 - Memory Device
1360 * Associated with one type 19
1362 struct smbios_type_17 {
1363 struct smbios_structure_header header;
1364 uint16_t physical_memory_array_handle;
1365 uint16_t memory_error_information_handle;
1366 uint16_t total_width;
1367 uint16_t data_width;
1369 uint8_t form_factor;
1371 uint8_t device_locator_str;
1372 uint8_t bank_locator_str;
1373 uint8_t memory_type;
1374 uint16_t type_detail;
1375 } __attribute__((__packed__));
1377 /* SMBIOS type 19 - Memory Array Mapped Address */
1378 struct smbios_type_19 {
1379 struct smbios_structure_header header;
1380 uint32_t starting_address;
1381 uint32_t ending_address;
1382 uint16_t memory_array_handle;
1383 uint8_t partition_width;
1384 } __attribute__((__packed__));
1386 /* SMBIOS type 20 - Memory Device Mapped Address */
1387 struct smbios_type_20 {
1388 struct smbios_structure_header header;
1389 uint32_t starting_address;
1390 uint32_t ending_address;
1391 uint16_t memory_device_handle;
1392 uint16_t memory_array_mapped_address_handle;
1393 uint8_t partition_row_position;
1394 uint8_t interleave_position;
1395 uint8_t interleaved_data_depth;
1396 } __attribute__((__packed__));
1398 /* SMBIOS type 32 - System Boot Information */
1399 struct smbios_type_32 {
1400 struct smbios_structure_header header;
1401 uint8_t reserved[6];
1402 uint8_t boot_status;
1403 } __attribute__((__packed__));
1405 /* SMBIOS type 127 -- End-of-table */
1406 struct smbios_type_127 {
1407 struct smbios_structure_header header;
1408 } __attribute__((__packed__));
1411 smbios_entry_point_init(void *start,
1412 uint16_t max_structure_size,
1413 uint16_t structure_table_length,
1414 uint32_t structure_table_address,
1415 uint16_t number_of_structures)
1419 struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
1421 memcpy(ep->anchor_string, "_SM_", 4);
1423 ep->smbios_major_version = 2;
1424 ep->smbios_minor_version = 4;
1425 ep->max_structure_size = max_structure_size;
1426 ep->entry_point_revision = 0;
1427 memset(ep->formatted_area, 0, 5);
1428 memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
1430 ep->structure_table_length = structure_table_length;
1431 ep->structure_table_address = structure_table_address;
1432 ep->number_of_structures = number_of_structures;
1433 ep->smbios_bcd_revision = 0x24;
1436 ep->intermediate_checksum = 0;
1439 for (i = 0; i < 0x10; i++)
1440 sum += ((int8_t *)start)[i];
1441 ep->checksum = -sum;
1444 for (i = 0x10; i < ep->length; i++)
1445 sum += ((int8_t *)start)[i];
1446 ep->intermediate_checksum = -sum;
1449 /* Type 0 -- BIOS Information */
1450 #define RELEASE_DATE_STR "01/01/2007"
1452 smbios_type_0_init(void *start)
1454 struct smbios_type_0 *p = (struct smbios_type_0 *)start;
1457 p->header.length = sizeof(struct smbios_type_0);
1458 p->header.handle = 0;
1461 p->bios_version_str = 1;
1462 p->bios_starting_address_segment = 0xe800;
1463 p->bios_release_date_str = 2;
1464 p->bios_rom_size = 0; /* FIXME */
1466 memset(p->bios_characteristics, 0, 7);
1467 p->bios_characteristics[7] = 0x08; /* BIOS characteristics not supported */
1468 p->bios_characteristics_extension_bytes[0] = 0;
1469 p->bios_characteristics_extension_bytes[1] = 0;
1471 p->system_bios_major_release = 1;
1472 p->system_bios_minor_release = 0;
1473 p->embedded_controller_major_release = 0xff;
1474 p->embedded_controller_minor_release = 0xff;
1476 start += sizeof(struct smbios_type_0);
1477 memcpy((char *)start, BX_APPNAME, sizeof(BX_APPNAME));
1478 start += sizeof(BX_APPNAME);
1479 memcpy((char *)start, RELEASE_DATE_STR, sizeof(RELEASE_DATE_STR));
1480 start += sizeof(RELEASE_DATE_STR);
1481 *((uint8_t *)start) = 0;
1486 /* Type 1 -- System Information */
1488 smbios_type_1_init(void *start)
1490 struct smbios_type_1 *p = (struct smbios_type_1 *)start;
1492 p->header.length = sizeof(struct smbios_type_1);
1493 p->header.handle = 0x100;
1495 p->manufacturer_str = 0;
1496 p->product_name_str = 0;
1498 p->serial_number_str = 0;
1500 memcpy(p->uuid, bios_uuid, 16);
1502 p->wake_up_type = 0x06; /* power switch */
1503 p->sku_number_str = 0;
1506 start += sizeof(struct smbios_type_1);
1507 *((uint16_t *)start) = 0;
1512 /* Type 3 -- System Enclosure */
1514 smbios_type_3_init(void *start)
1516 struct smbios_type_3 *p = (struct smbios_type_3 *)start;
1519 p->header.length = sizeof(struct smbios_type_3);
1520 p->header.handle = 0x300;
1522 p->manufacturer_str = 0;
1523 p->type = 0x01; /* other */
1525 p->serial_number_str = 0;
1526 p->asset_tag_number_str = 0;
1527 p->boot_up_state = 0x03; /* safe */
1528 p->power_supply_state = 0x03; /* safe */
1529 p->thermal_state = 0x03; /* safe */
1530 p->security_status = 0x02; /* unknown */
1533 p->number_of_power_cords = 0;
1534 p->contained_element_count = 0;
1536 start += sizeof(struct smbios_type_3);
1537 *((uint16_t *)start) = 0;
1542 /* Type 4 -- Processor Information */
1544 smbios_type_4_init(void *start, unsigned int cpu_number)
1546 struct smbios_type_4 *p = (struct smbios_type_4 *)start;
1549 p->header.length = sizeof(struct smbios_type_4);
1550 p->header.handle = 0x400 + cpu_number;
1552 p->socket_designation_str = 1;
1553 p->processor_type = 0x03; /* CPU */
1554 p->processor_family = 0x01; /* other */
1555 p->processor_manufacturer_str = 0;
1557 p->processor_id[0] = cpuid_signature;
1558 p->processor_id[1] = cpuid_features;
1560 p->processor_version_str = 0;
1562 p->external_clock = 0;
1564 p->max_speed = 0; /* unknown */
1565 p->current_speed = 0; /* unknown */
1567 p->status = 0x41; /* socket populated, CPU enabled */
1568 p->processor_upgrade = 0x01; /* other */
1570 start += sizeof(struct smbios_type_4);
1572 memcpy((char *)start, "CPU " "\0" "" "\0" "", 7);
1573 ((char *)start)[4] = cpu_number + '0';
1578 /* Type 16 -- Physical Memory Array */
1580 smbios_type_16_init(void *start, uint32_t memsize)
1582 struct smbios_type_16 *p = (struct smbios_type_16*)start;
1584 p->header.type = 16;
1585 p->header.length = sizeof(struct smbios_type_16);
1586 p->header.handle = 0x1000;
1588 p->location = 0x01; /* other */
1589 p->use = 0x03; /* system memory */
1590 p->error_correction = 0x01; /* other */
1591 p->maximum_capacity = memsize * 1024;
1592 p->memory_error_information_handle = 0xfffe; /* none provided */
1593 p->number_of_memory_devices = 1;
1595 start += sizeof(struct smbios_type_16);
1596 *((uint16_t *)start) = 0;
1601 /* Type 17 -- Memory Device */
1603 smbios_type_17_init(void *start, uint32_t memory_size_mb)
1605 struct smbios_type_17 *p = (struct smbios_type_17 *)start;
1607 p->header.type = 17;
1608 p->header.length = sizeof(struct smbios_type_17);
1609 p->header.handle = 0x1100;
1611 p->physical_memory_array_handle = 0x1000;
1612 p->total_width = 64;
1614 /* truncate memory_size_mb to 16 bits and clear most significant
1615 bit [indicates size in MB] */
1616 p->size = (uint16_t) memory_size_mb & 0x7fff;
1617 p->form_factor = 0x09; /* DIMM */
1619 p->device_locator_str = 1;
1620 p->bank_locator_str = 0;
1621 p->memory_type = 0x07; /* RAM */
1624 start += sizeof(struct smbios_type_17);
1625 memcpy((char *)start, "DIMM 1", 7);
1627 *((uint8_t *)start) = 0;
1632 /* Type 19 -- Memory Array Mapped Address */
1634 smbios_type_19_init(void *start, uint32_t memory_size_mb)
1636 struct smbios_type_19 *p = (struct smbios_type_19 *)start;
1638 p->header.type = 19;
1639 p->header.length = sizeof(struct smbios_type_19);
1640 p->header.handle = 0x1300;
1642 p->starting_address = 0;
1643 p->ending_address = (memory_size_mb-1) * 1024;
1644 p->memory_array_handle = 0x1000;
1645 p->partition_width = 1;
1647 start += sizeof(struct smbios_type_19);
1648 *((uint16_t *)start) = 0;
1653 /* Type 20 -- Memory Device Mapped Address */
1655 smbios_type_20_init(void *start, uint32_t memory_size_mb)
1657 struct smbios_type_20 *p = (struct smbios_type_20 *)start;
1659 p->header.type = 20;
1660 p->header.length = sizeof(struct smbios_type_20);
1661 p->header.handle = 0x1400;
1663 p->starting_address = 0;
1664 p->ending_address = (memory_size_mb-1)*1024;
1665 p->memory_device_handle = 0x1100;
1666 p->memory_array_mapped_address_handle = 0x1300;
1667 p->partition_row_position = 1;
1668 p->interleave_position = 0;
1669 p->interleaved_data_depth = 0;
1671 start += sizeof(struct smbios_type_20);
1673 *((uint16_t *)start) = 0;
1677 /* Type 32 -- System Boot Information */
1679 smbios_type_32_init(void *start)
1681 struct smbios_type_32 *p = (struct smbios_type_32 *)start;
1683 p->header.type = 32;
1684 p->header.length = sizeof(struct smbios_type_32);
1685 p->header.handle = 0x2000;
1686 memset(p->reserved, 0, 6);
1687 p->boot_status = 0; /* no errors detected */
1689 start += sizeof(struct smbios_type_32);
1690 *((uint16_t *)start) = 0;
1695 /* Type 127 -- End of Table */
1697 smbios_type_127_init(void *start)
1699 struct smbios_type_127 *p = (struct smbios_type_127 *)start;
1701 p->header.type = 127;
1702 p->header.length = sizeof(struct smbios_type_127);
1703 p->header.handle = 0x7f00;
1705 start += sizeof(struct smbios_type_127);
1706 *((uint16_t *)start) = 0;
1711 void smbios_init(void)
1713 unsigned cpu_num, nr_structs = 0, max_struct_size = 0;
1714 char *start, *p, *q;
1715 int memsize = ram_size / (1024 * 1024);
1717 #ifdef BX_USE_EBDA_TABLES
1718 ebda_cur_addr = align(ebda_cur_addr, 16);
1719 start = (void *)(ebda_cur_addr);
1721 bios_table_cur_addr = align(bios_table_cur_addr, 16);
1722 start = (void *)(bios_table_cur_addr);
1725 p = (char *)start + sizeof(struct smbios_entry_point);
1727 #define add_struct(fn) { \
1730 if ((q - p) > max_struct_size) \
1731 max_struct_size = q - p; \
1735 add_struct(smbios_type_0_init(p));
1736 add_struct(smbios_type_1_init(p));
1737 add_struct(smbios_type_3_init(p));
1738 for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++)
1739 add_struct(smbios_type_4_init(p, cpu_num));
1740 add_struct(smbios_type_16_init(p, memsize));
1741 add_struct(smbios_type_17_init(p, memsize));
1742 add_struct(smbios_type_19_init(p, memsize));
1743 add_struct(smbios_type_20_init(p, memsize));
1744 add_struct(smbios_type_32_init(p));
1745 add_struct(smbios_type_127_init(p));
1749 smbios_entry_point_init(
1750 start, max_struct_size,
1751 (p - (char *)start) - sizeof(struct smbios_entry_point),
1752 (uint32_t)(start + sizeof(struct smbios_entry_point)),
1755 #ifdef BX_USE_EBDA_TABLES
1756 ebda_cur_addr += (p - (char *)start);
1758 bios_table_cur_addr += (p - (char *)start);
1761 BX_INFO("SMBIOS table addr=0x%08lx\n", (unsigned long)start);
1764 void rombios32_init(void)
1766 BX_INFO("Starting rombios32\n");
1778 if (bios_table_cur_addr != 0) {
1787 bios_lock_shadow_ram();
1789 BX_INFO("bios_table_cur_addr: 0x%08lx\n", bios_table_cur_addr);
1790 if (bios_table_cur_addr > bios_table_end_addr)
1791 BX_PANIC("bios_table_end_addr overflow!\n");