[coreboot] [PATCH] Add the AML code generator for runtime code generation
Carl-Daniel Hailfinger
c-d.hailfinger.devel.2006 at gmx.net
Mon Feb 2 02:30:24 CET 2009
Hi Rudolf,
that's an impressive piece of code!
On 01.02.2009 17:02, Rudolf Marek wrote:
> Hello,
>
> Following patch adds dynamic ACPI AML code generator which can be used to
> generate run-time ACPI ASL code like this:
>
> Name (XXX, 0xXX)
>
> Or:
>
> Scope (\_SB.PCI0)
> {
> Name (BUSN, Package (0x04)
> {
> 0x11111111,
> 0x22222222,
> 0x33333333,
> 0x44444444
> })
>
> Moreover it demonstrates its use on Asus M2V-MX SE where the SSDT table is
> generated by new function k8acpi_write_vars (technically similar to
> update_ssdt). But lot of nicer ;)
>
> The ACPI binary code generator will be also useful for P-states
> generation,
> without ugly run-time patching of DSDT.
>
> The old SSDT of K8 will be removed and rest of boards converted in
> next patch.
>
> Tested on that board. It generates same table as the static SSDT
> patched by
> amdk8_acpi. Windows still boots too ;)
>
> Signed-off-by: Rudolf Marek <r.marek at assembler.cz>
The following review is rather short and to-the-point. No offense intended.
A few comments about the general design:
The global variable gencurrent is a bit irritating. How do you handle
running on multiple cores?
Same for len_stack. Besides that, both variables are in the global
namespace and could use some acpi_ prefix or suffix.
> Index: coreboot-v2/src/arch/i386/boot/acpi.c
> ===================================================================
> --- coreboot-v2.orig/src/arch/i386/boot/acpi.c 2008-12-23 17:31:37.000000000 +0100
> +++ coreboot-v2/src/arch/i386/boot/acpi.c 2009-02-01 11:05:03.171807310 +0100
> @@ -24,6 +24,7 @@
> #include <console/console.h>
> #include <string.h>
> #include <arch/acpi.h>
> +#include <arch/acpigen.h>
> #include <device/pci.h>
>
> u8 acpi_checksum(u8 *table, u32 length)
> @@ -180,6 +181,34 @@
> header->checksum = acpi_checksum((void *)mcfg, header->length);
> }
>
> +/* this can be overriden by platform ACPI setup code,
> + if it calls acpi_create_ssdt_generator */
> +unsigned long __attribute__((weak)) acpi_fill_ssdt_generator(unsigned long current,
>
I think weak symbols are something that makes code harder to follow.
> + char *oem_table_id) {
>
The { belongs on another line.
> + return current;
> +}
> +
> +void acpi_create_ssdt_generator(acpi_header_t *ssdt, char *oem_table_id)
>
Strange function name.
> +{
> + unsigned long current=(unsigned long)ssdt+sizeof(acpi_header_t);
> + memset((void *)ssdt, 0, sizeof(acpi_header_t));
> + memcpy(&ssdt->signature, SSDT_NAME, 4);
>
Maybe strncpy instead?
> + ssdt->revision = 2;
> + memcpy(&ssdt->oem_id, OEM_ID, 6);
> + memcpy(&ssdt->oem_table_id, oem_table_id, 8);
> + ssdt->oem_revision = 42;
> + memcpy(&ssdt->asl_compiler_id, "GENAML", 4);
> + ssdt->asl_compiler_revision = 42;
>
Heh.
> + ssdt->length = sizeof(acpi_header_t);
> +
> + acpigen_set_current((unsigned char *) current);
> + current = acpi_fill_ssdt_generator(current, oem_table_id);
> +
> + /* recalculate length */
> + ssdt->length = current - (unsigned long)ssdt;
> + ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
> +}
> +
> int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
> {
> lapic->type=0;
> Index: coreboot-v2/src/arch/i386/boot/acpigen.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ coreboot-v2/src/arch/i386/boot/acpigen.c 2009-02-01 11:04:09.927808334 +0100
> @@ -0,0 +1,138 @@
> +/*
> + * This file is part of the coreboot project.
> + *
> + * Copyright (C) 2009 Rudolf Marek <r.marek at assembler.cz>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License v2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/* how many nesting we support */
>
"how many nesting levels do we support"
> +#define ACPIGEN_LENSTACK_SIZE 10
> +
> +/* if you need to change this, change the acpigen_write_f and
> + acpigen_patch_len */
> +
>
Can you remove the empty line above?
> +#define ACPIGEN_MAXLEN 0xfff
> +
> +#include <string.h>
> +#include <arch/acpigen.h>
> +#include <console/console.h>
> +
> +static char *gencurrent;
> +
> +char *len_stack[ACPIGEN_LENSTACK_SIZE];
> +int ltop = 0;
>
These global variables need better names and some comments explaining
what they do.
> +
> +static int acpigen_write_len_f()
>
Needs a doxygen comment.
> +{
> + ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1))
> + len_stack[ltop++] = gencurrent;
> + acpigen_emit_byte(0);
> + acpigen_emit_byte(0);
> + return 2;
> +}
> +
> +void acpigen_patch_len(int len)
>
Needs a doxygen comment.
> +{
> + ASSERT(len <= ACPIGEN_MAXLEN)
> + ASSERT(ltop > 0)
> + char *p = len_stack[--ltop];
> + /* generate store length for 0xfff max */
> + p[0] = (0x40 | (len & 0xf));
> + p[1] = (len >> 4 & 0xff);
> +
> +}
> +
> +void acpigen_set_current(char *curr) {
>
Needs a doxygen comment.
> + gencurrent = curr;
> +}
> +
> +char *acpigen_get_current(void) {
>
Needs a doxygen comment.
> + return gencurrent;
> +}
> +
> +int acpigen_emit_byte(unsigned char b)
> +{
> + (*gencurrent++) = b;
> + return 1;
> +}
> +
> +int acpigen_write_package(int nr_el)
> +{
> + int len;
> + /* package op */
> + acpigen_emit_byte(0x12);
> + len = acpigen_write_len_f();
> + acpigen_emit_byte(nr_el);
> + return len + 2;
> +}
> +
> +int acpigen_write_byte(unsigned int data)
> +{
> + /* byte op */
> + acpigen_emit_byte(0xa);
> + acpigen_emit_byte(data & 0xff);
> + return 2;
> +}
> +
> +int acpigen_write_dword(unsigned int data)
> +{
> + /* dword op */
> + acpigen_emit_byte(0xc);
> + acpigen_emit_byte(data & 0xff);
> + acpigen_emit_byte((data >> 8) & 0xff);
> + acpigen_emit_byte((data >> 16) & 0xff);
> + acpigen_emit_byte((data >> 24) & 0xff);
> + return 5;
> +}
> +
> +int acpigen_write_name_byte(char *name, uint8_t val) {
> + int len;
> + len = acpigen_write_name(name);
> + len += acpigen_write_byte(val);
> + return len;
> +}
> +
> +int acpigen_write_name_dword(char *name, uint32_t val) {
> + int len;
> + len = acpigen_write_name(name);
> + len += acpigen_write_dword(val);
> + return len;
> +}
> +
> +int acpigen_emit_stream(char *data, int size) {
> + int i;
> + for (i = 0; i < size; i++) {
> + acpigen_emit_byte(data[i]);
> + }
> + return size;
> +}
> +
> +int acpigen_write_name(char *name)
> +{
> + int len = strlen(name);
> + /* name op */
> + acpigen_emit_byte(0x8);
> + acpigen_emit_stream(name, len);
> + return len + 1;
> +}
> +
> +int acpigen_write_scope(char *name)
> +{
> + int len;
> + /* scope op */
> + acpigen_emit_byte(0x10);
> + len = acpigen_write_len_f();
> + return len + acpigen_emit_stream(name, strlen(name)) + 1;
> +}
> Index: coreboot-v2/src/arch/i386/boot/Config.lb
> ===================================================================
> --- coreboot-v2.orig/src/arch/i386/boot/Config.lb 2009-02-01 10:25:41.491806925 +0100
> +++ coreboot-v2/src/arch/i386/boot/Config.lb 2009-02-01 10:30:56.756876765 +0100
> @@ -13,5 +13,5 @@
> end
> if HAVE_ACPI_TABLES
> object acpi.o
> +object acpigen.o
> end
> -
> Index: coreboot-v2/src/arch/i386/include/arch/acpigen.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ coreboot-v2/src/arch/i386/include/arch/acpigen.h 2009-02-01 10:30:56.758807179 +0100
> @@ -0,0 +1,37 @@
> +/*
> + * This file is part of the coreboot project.
> + *
> + * Copyright (C) 2009 Rudolf Marek <r.marek at assembler.cz>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License v2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +#ifndef LIBACPI_H
> +#define LIBACPI_H
> +#include <assert.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +
> +void acpigen_patch_len(int len);
> +void acpigen_set_current(char *curr);
> +char *acpigen_get_current(void);
> +int acpigen_write_package(int nr_el);
> +int acpigen_write_byte(unsigned int data);
> +int acpigen_emit_byte(unsigned char data);
> +int acpigen_emit_stream(char *data, int size);
> +int acpigen_write_dword(unsigned int data);
> +int acpigen_write_name(char *name);
> +int acpigen_write_name_dword(char *name, uint32_t val);
> +int acpigen_write_name_byte(char *name, uint8_t val);
> +int acpigen_write_scope(char *name);
> +#endif
> Index: coreboot-v2/src/arch/i386/include/arch/acpi.h
> ===================================================================
> --- coreboot-v2.orig/src/arch/i386/include/arch/acpi.h 2008-12-23 17:38:41.000000000 +0100
> +++ coreboot-v2/src/arch/i386/include/arch/acpi.h 2009-02-01 10:52:25.478808600 +0100
> @@ -29,6 +29,7 @@
> #define MCFG_NAME "MCFG"
> #define SRAT_NAME "SRAT"
> #define SLIT_NAME "SLIT"
> +#define SSDT_NAME "SSDT"
>
> #define RSDT_TABLE "RSDT "
> #define HPET_TABLE "AMD64 "
> @@ -293,6 +294,8 @@
> unsigned long acpi_fill_madt(unsigned long current);
> unsigned long acpi_fill_mcfg(unsigned long current);
> unsigned long acpi_fill_srat(unsigned long current);
> +unsigned long acpi_fill_ssdt_generator(unsigned long current, char *oem_table_id);
> +void acpi_create_ssdt_generator(acpi_header_t *ssdt, char *oem_table_id);
>
The two functions above have rather similar names and it's not
immedately ofvious how they differ.
> void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs,void *dsdt);
>
> /* These can be used by the target port */
> Index: coreboot-v2/src/mainboard/asus/m2v-mx_se/acpi_tables.c
> ===================================================================
> --- coreboot-v2.orig/src/mainboard/asus/m2v-mx_se/acpi_tables.c 2008-12-23 17:46:56.000000000 +0100
> +++ coreboot-v2/src/mainboard/asus/m2v-mx_se/acpi_tables.c 2009-02-01 11:23:05.142807423 +0100
> @@ -30,9 +30,9 @@
> #include <device/pci_ids.h>
> #include <../../../southbridge/via/vt8237r/vt8237r.h>
> #include <../../../southbridge/via/k8t890/k8t890.h>
> +#include <../../../northbridge/amd/amdk8/amdk8_acpi.h>
>
> extern unsigned char AmlCode[];
> -extern unsigned char AmlCode_ssdt[];
>
> unsigned long acpi_fill_mcfg(unsigned long current)
> {
> @@ -81,6 +81,12 @@
> return current;
> }
>
> +unsigned long acpi_fill_ssdt_generator(unsigned long current, char *oem_table_id) {
> + k8acpi_write_vars();
> + /* put PSTATES generator call here */
> + return (unsigned long) (acpigen_get_current());
>
acpigen_get_current is a really confusingly named function.
> +}
> +
> unsigned long write_acpi_tables(unsigned long start)
> {
> unsigned long current;
> @@ -175,13 +181,10 @@
> /* SSDT */
> printk_debug("ACPI: * SSDT\n");
> ssdt = (acpi_header_t *)current;
> - current += ((acpi_header_t *)AmlCode_ssdt)->length;
> - memcpy((void *)ssdt, (void *)AmlCode_ssdt, ((acpi_header_t *)AmlCode_ssdt)->length);
> - update_ssdt((void*)ssdt);
> - /* recalculate checksum */
> - ssdt->checksum = 0;
> - ssdt->checksum = acpi_checksum((unsigned char *)ssdt,ssdt->length);
> - acpi_add_table(rsdt,ssdt);
> +
> + acpi_create_ssdt_generator(ssdt, "DYNADATA");
>
"COREBOOT" please. That way, people can actually find out where the
table came from. The fact that the data are generated dynamically is
already visible from the compiler ID.
> + current += ssdt->length;
> + acpi_add_table(rsdt, ssdt);
>
> printk_info("ACPI: done.\n");
> return current;
> Index: coreboot-v2/src/northbridge/amd/amdk8/amdk8_acpi.c
> ===================================================================
> --- coreboot-v2.orig/src/northbridge/amd/amdk8/amdk8_acpi.c 2008-12-23 17:31:36.000000000 +0100
> +++ coreboot-v2/src/northbridge/amd/amdk8/amdk8_acpi.c 2009-02-01 11:26:00.102959065 +0100
> @@ -259,6 +259,80 @@
> }
> }
>
> +static int k8acpi_write_HT(void) {
> + device_t dev;
> + uint32_t dword;
> + int len, lenp, i;
> +
> + len = acpigen_write_name("HCLK");
> + lenp = acpigen_write_package(HC_POSSIBLE_NUM);
> +
> + for(i=0;i<sysconf.hc_possible_num;i++) {
> + lenp += acpigen_write_dword(sysconf.pci1234[i]);
> + }
> + for(i=sysconf.hc_possible_num; i<HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8
>
Comment on a separate line, please.
> + lenp += acpigen_write_dword(0x0);
> + }
> +
> + acpigen_patch_len(lenp - 1);
>
acpigen_patch_len is a name which does not really reveal function purpose.
> + len += lenp;
> +
> + len += acpigen_write_name("HCDN");
> + lenp = acpigen_write_package(HC_POSSIBLE_NUM);
> +
> + for(i=0;i<sysconf.hc_possible_num;i++) {
> + lenp += acpigen_write_dword(sysconf.hcdn[i]);
> + }
> + for(i=sysconf.hc_possible_num; i<HC_POSSIBLE_NUM; i++) { // in case we set array size to other than 8
> + lenp += acpigen_write_dword(0x20202020);
> + }
> + acpigen_patch_len(lenp - 1);
> + len += lenp;
> +
> + return len;
> +}
> +
> +static int k8acpi_write_pci_data(int dlen, char *name, int offset) {
> + device_t dev;
> + uint32_t dword;
> + int len, lenp, i;
> +
> + dev = dev_find_slot(0, PCI_DEVFN(0x18, 1));
> +
> + len = acpigen_write_name(name);
> + lenp = acpigen_write_package(dlen);
> + for(i=0; i<dlen; i++) {
> + dword = pci_read_config32(dev, offset+i*4);
> + lenp += acpigen_write_dword(dword);
> + }
> + // minus the opcode
> + acpigen_patch_len(lenp - 1);
> + return len + lenp;
> +}
> +
> +
> +int k8acpi_write_vars(void)
> +{
> + int lens;
>
Maybe use len instead of lens?
> + msr_t msr;
> + char pscope[] = "\\._SB_PCI0";
> +
> + lens = acpigen_write_scope(pscope);
> + lens += k8acpi_write_pci_data(4, "BUSN", 0xe0);
> + lens += k8acpi_write_pci_data(8, "PCIO", 0xc0);
> + lens += k8acpi_write_pci_data(16, "MMIO", 0x80);
> + lens += acpigen_write_name_byte("SBLK", sysconf.sblk);
> + lens += acpigen_write_name_byte("CBST",
> + ((sysconf.pci1234[0] >> 12) & 0xff) ? 0xf : 0x0);
> + lens += acpigen_write_name_dword("SBDN", sysconf.sbdn);
> + msr = rdmsr(TOP_MEM);
> + lens += acpigen_write_name_dword("TOM1", msr.lo);
>
I know the original code did not have it, but can you please add TOM2?
> +
> + lens += k8acpi_write_HT();
> + //minus opcode
> + acpigen_patch_len(lens - 1);
> + return lens;
> +}
>
> // used by acpi_tables.h
>
> Index: coreboot-v2/src/northbridge/amd/amdk8/amdk8_acpi.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ coreboot-v2/src/northbridge/amd/amdk8/amdk8_acpi.h 2009-02-01 11:28:13.236202005 +0100
> @@ -0,0 +1,25 @@
> +/*
> + * This file is part of the coreboot project.
> + *
> + * Copyright (C) 2009 Rudolf Marek <r.marek at assembler.cz>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License v2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +#ifndef AMDK8_ACPI_H
> +#define AMDK8_ACPI_H
> +#include <arch/acpigen.h>
> +
> +int k8acpi_write_vars(void);
> +
> +#endif
>
Regards,
Carl-Daniel
--
http://www.hailfinger.org/
More information about the coreboot
mailing list