summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Hargrave <jordan@cvs.openbsd.org>2006-11-27 15:17:38 +0000
committerJordan Hargrave <jordan@cvs.openbsd.org>2006-11-27 15:17:38 +0000
commit3c4560151200cd4b978ae3f5fe77cc21f5ad709d (patch)
tree61e8fb9e9f5fc89b3d3e90ff8f0a4fd8373c0070
parent4ae77a80a2c526e96aec6b7969ba7ec0cb0e8a77 (diff)
Added support for parsing _CRS resources
Post-parsing fixup for forward name references
-rw-r--r--sys/dev/acpi/dsdt.c187
-rw-r--r--sys/dev/acpi/dsdt.h108
2 files changed, 260 insertions, 35 deletions
diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c
index 732d7cbe415..c10cfc0faa2 100644
--- a/sys/dev/acpi/dsdt.c
+++ b/sys/dev/acpi/dsdt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsdt.c,v 1.64 2006/11/25 18:24:54 marco Exp $ */
+/* $OpenBSD: dsdt.c,v 1.65 2006/11/27 15:17:37 jordan Exp $ */
/*
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
*
@@ -32,11 +32,6 @@
#include <dev/acpi/amltypes.h>
#include <dev/acpi/dsdt.h>
-/* XXX: endian macros */
-#define aml_letohost16(x) x
-#define aml_letohost32(x) x
-#define aml_letohost64(x) x
-
#define opsize(opcode) (((opcode) & 0xFF00) ? 2 : 1)
#define AML_CHECKSTACK()
@@ -92,12 +87,10 @@ struct aml_value *aml_parseterm(struct aml_scope *, struct aml_value *);
struct aml_value *aml_evaltarget(struct aml_scope *scope, struct aml_value *res);
int aml_evalterm(struct aml_scope *scope, struct aml_value *raw, struct aml_value *dst);
-const char *aml_nodename(struct aml_node *);
void aml_gasio(struct acpi_softc *, int, uint64_t, uint64_t,
int, int, int, void *, int);
-
struct aml_opcode *aml_findopcode(int);
void *_acpi_os_malloc(size_t, const char *, int);
@@ -523,7 +516,7 @@ void
aml_gasio(struct acpi_softc *sc, int type, uint64_t base, uint64_t length,
int bitpos, int bitlen, int size, void *buf, int mode)
{
- dnprintf(15,"-- aml_gasio: %.2x base:%llx len:%llx bitpos:%.4x bitlen:%.4x sz:%.2x mode=%s\n",
+ dnprintf(10,"-- aml_gasio: %.2x base:%llx len:%llx bitpos:%.4x bitlen:%.4x sz:%.2x mode=%s\n",
type, base, length, bitpos, bitlen, size, mode==ACPI_IOREAD?"read":"write");
acpi_gasio(sc, mode, type, base+(bitpos>>3),
(size>>3), (bitlen>>3), buf);
@@ -621,8 +614,9 @@ aml_nodename(struct aml_node *node)
if (node->parent != &aml_root)
strlcat(namebuf, ".", sizeof(namebuf));
strlcat(namebuf, node->name, sizeof(namebuf));
+ return namebuf+1;
}
- return namebuf+1;
+ return namebuf;
}
const char *
@@ -933,12 +927,18 @@ aml_getbufint(struct aml_value *src, int bitpos, int bitlen,
aml_die("wrong getbufint type\n");
switch (src->type) {
case AML_OBJTYPE_INTEGER:
+ if (bitlen >= aml_intlen)
+ bitlen = aml_intlen;
aml_bufcpy(dst->v_buffer, bitpos, &src->v_integer, 0, bitlen);
break;
case AML_OBJTYPE_BUFFER:
+ if (bitlen >= 8*src->length)
+ bitlen = 8*src->length;
aml_bufcpy(dst->v_buffer, bitpos, src->v_buffer, 0, bitlen);
break;
case AML_OBJTYPE_STRING:
+ if (bitlen >= 8*src->length)
+ bitlen = 8*src->length;
aml_bufcpy(dst->v_buffer, bitpos, src->v_string, 0, bitlen);
break;
}
@@ -969,6 +969,7 @@ aml_fieldio(struct aml_scope *scope, struct aml_value *field,
{
struct aml_value *pop, *tmp;
int bpos, blen, aligned, mask;
+ uint64_t iobase;
pop = field->v_field.ref1;
bpos = field->v_field.bitpos;
@@ -1013,6 +1014,7 @@ aml_fieldio(struct aml_scope *scope, struct aml_value *field,
bpos = bpos & ~mask;
aligned = (bpos == field->v_field.bitpos &&
blen == field->v_field.bitlen);
+ iobase = pop->v_opregion.iobase;
/* Verify that I/O is in range */
#if 0
@@ -1035,8 +1037,7 @@ aml_fieldio(struct aml_scope *scope, struct aml_value *field,
if (mode == ACPI_IOREAD) {
/* Read from GAS space */
aml_gasio(scope->sc, pop->v_opregion.iospace,
- pop->v_opregion.iobase,
- pop->v_opregion.iolen,
+ iobase, pop->v_opregion.iolen,
bpos, blen, mask+1,
tmp->v_buffer,
ACPI_IOREAD);
@@ -1057,7 +1058,7 @@ aml_fieldio(struct aml_scope *scope, struct aml_value *field,
/* XXX: only need to read 1st/last mask chunk */
dnprintf(50,"fpr:Preserve\n");
aml_gasio(scope->sc, pop->v_opregion.iospace,
- pop->v_opregion.iobase,
+ iobase,
pop->v_opregion.iolen,
bpos, blen, mask+1,
tmp->v_buffer,
@@ -1070,7 +1071,7 @@ aml_fieldio(struct aml_scope *scope, struct aml_value *field,
field->v_field.bitlen,
tmp);
aml_gasio(scope->sc, pop->v_opregion.iospace,
- pop->v_opregion.iobase,
+ iobase,
pop->v_opregion.iolen,
bpos, blen, mask+1,
tmp->v_buffer,
@@ -1101,11 +1102,6 @@ aml_showvalue(struct aml_value *val, int lvl)
{
int idx;
-#if ACPI_DEBUG
- if (lvl < acpi_debug)
- return;
-#endif
-
if (val == NULL)
return;
@@ -1294,7 +1290,7 @@ aml_val2int(struct aml_value *rval)
break;
case AML_OBJTYPE_BUFFER:
aml_bufcpy(&ival, 0, rval->v_buffer, 0,
- min(aml_intlen*8, rval->length*8));
+ min(aml_intlen, rval->length*8));
break;
case AML_OBJTYPE_STRING:
ival = (strncmp(rval->v_string, "0x", 2) == 0) ?
@@ -1412,7 +1408,6 @@ aml_setvalue(struct aml_scope *scope, struct aml_value *lhs,
/* ACPI: Overwrite writing to LocalX */
aml_freevalue(lhs);
}
-
switch (lhs->type) {
case AML_OBJTYPE_UNINITIALIZED:
aml_copyvalue(lhs, rhs);
@@ -1422,7 +1417,8 @@ aml_setvalue(struct aml_scope *scope, struct aml_value *lhs,
aml_fieldio(scope, lhs, rhs, ACPI_IOWRITE);
break;
case AML_OBJTYPE_DEBUGOBJ:
- aml_showvalue(rhs, 50);
+ printf("-- debug --\n");
+ aml_showvalue(rhs, 50);
break;
case AML_OBJTYPE_INTEGER+AML_STATIC:
break;
@@ -1862,6 +1858,23 @@ aml_evalinteger(struct acpi_softc *sc, struct aml_node *parent, const char *name
}
void
+aml_walknodes(struct aml_node *node, int mode,
+ int (*nodecb)(struct aml_node *, void *),
+ void *arg)
+{
+ struct aml_node *child;
+
+ if (node == NULL)
+ return;
+ if (mode == AML_WALK_PRE)
+ nodecb(node, arg);
+ for (child=node->child; child; child=child->sibling)
+ aml_walknodes(child, mode, nodecb, arg);
+ if (mode == AML_WALK_POST)
+ nodecb(node, arg);
+}
+
+void
aml_walktree(struct aml_node *node)
{
while(node) {
@@ -2058,6 +2071,8 @@ aml_match(int op, int64_t mv1, struct aml_value *mv2)
return (1);
}
+int amlop_delay;
+
u_int64_t
aml_getpciaddr(struct acpi_softc *sc, struct aml_node *root)
{
@@ -2073,6 +2088,7 @@ aml_getpciaddr(struct acpi_softc *sc, struct aml_node *root)
dnprintf(20,"got _adr [%s]\n",
aml_nodename(root));
}
+
if (!aml_evalname(dsdt_softc, root, "_BBN", 0, NULL, &tmpres)) {
/* PCI bus is in bits 48-63 */
pciaddr += (aml_val2int(&tmpres) << 48L);
@@ -2080,7 +2096,7 @@ aml_getpciaddr(struct acpi_softc *sc, struct aml_node *root)
dnprintf(20,"got _bbn [%s]\n",
aml_nodename(root));
}
- dnprintf(20,"got pciaddr: %llx\n", pciaddr);
+ dnprintf(20,"got pciaddr: %s:%llx\n", aml_nodename(root), pciaddr);
return pciaddr;
}
@@ -2181,7 +2197,6 @@ struct aml_value *
aml_parsenamed(struct aml_scope *scope, int opcode, struct aml_value *res)
{
uint8_t *name;
- u_int64_t pci_addr;
int s, offs = 0;
AML_CHECKSTACK();
@@ -2218,10 +2233,8 @@ aml_parsenamed(struct aml_scope *scope, int opcode, struct aml_value *res)
res->v_opregion.iobase = aml_parseint(scope, AML_ANYINT);
res->v_opregion.iolen = aml_parseint(scope, AML_ANYINT);
if (res->v_opregion.iospace == GAS_PCI_CFG_SPACE) {
- pci_addr = aml_getpciaddr(dsdt_softc,
- scope->node);
-
- res->v_opregion.iobase += pci_addr;
+ res->v_opregion.iobase += aml_getpciaddr(dsdt_softc,
+ scope->node);
}
break;
}
@@ -2943,12 +2956,18 @@ aml_parsetarget(struct aml_scope *scope, struct aml_value *res, struct aml_value
return res;
}
+int odp;
+
/* Main Opcode Parser/Evaluator */
struct aml_value *
aml_parseop(struct aml_scope *scope, struct aml_value *res)
{
int opcode;
struct aml_opcode *htab;
+ struct aml_value *rv = NULL;
+
+ if (odp++ > 25)
+ panic("depth");
aml_freevalue(res);
opcode = aml_parseopcode(scope);
@@ -2957,13 +2976,19 @@ aml_parseop(struct aml_scope *scope, struct aml_value *res)
aml_nodename(scope->node),
aml_mnem(opcode));
- htab = aml_findopcode(opcode);
- if (htab && htab->handler)
- return htab->handler(scope, opcode, res);
+ delay(amlop_delay);
- /* No opcode handler */
- aml_die("Unknown opcode: %.4x @ %.4x", opcode, aml_pc(scope->pos - opsize(opcode)));
- return NULL;
+ htab = aml_findopcode(opcode);
+ if (htab && htab->handler) {
+ rv = htab->handler(scope, opcode, res);
+ }
+ else {
+ /* No opcode handler */
+ aml_die("Unknown opcode: %.4x @ %.4x", opcode,
+ aml_pc(scope->pos - opsize(opcode)));
+ }
+ odp--;
+ return rv;
}
const char hext[] = "0123456789ABCDEF";
@@ -3071,6 +3096,66 @@ aml_create_defaultobjects()
}
int
+aml_print_resource(union acpi_resource *crs, void *arg)
+{
+ int typ = AML_CRSTYPE(crs);
+
+ switch (typ) {
+ case LR_EXTIRQ:
+ printf("extirq: flags:%x len:%x irq:%x\n",
+ crs->lr_extirq.flags,
+ crs->lr_extirq.irq_count,
+ aml_letohost32(crs->lr_extirq.irq[0]));
+ break;
+ case SR_IRQ:
+ printf("irq %.4x %.2x",
+ aml_letohost16(crs->sr_irq.irq_mask),
+ crs->sr_irq.irq_info);
+ break;
+ case SR_DMA:
+ printf("dma %.2x %.2x", crs->sr_dma.dma_chan, crs->sr_dma.dma_info);
+ break;
+ case SR_IOPORT:
+ printf("io %.2x _min:%.4x _max:%.4x _aln:%.2x _len:%.2x\n",
+ crs->sr_ioport.io_info,
+ crs->sr_ioport.io_min,
+ crs->sr_ioport.io_max,
+ crs->sr_ioport.io_aln,
+ crs->sr_ioport.io_len);
+ break;
+ case SR_STARTDEP:
+ printf("startdep");
+ break;
+ case SR_ENDDEP:
+ printf("enddep");
+ break;
+ default:
+ printf("unknown type: %x\n", typ);
+ break;
+ }
+ return (0);
+}
+
+int
+aml_parse_resource(int length, uint8_t *buffer,
+ int (*crs_enum)(union acpi_resource *, void *),
+ void *arg)
+{
+ int off, rlen;
+ union acpi_resource *crs;
+
+ for (off=0; off<length; off += rlen+1) {
+ crs = (union acpi_resource *)(buffer+off);
+ rlen = AML_CRSLEN(crs);
+ if (rlen == 0)
+ break;
+ //aml_print_resource(crs, NULL);
+ crs_enum(crs, arg);
+ }
+ return 0;
+}
+
+int
acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length)
{
u_int8_t *end;
@@ -3089,3 +3174,37 @@ acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length)
return (0);
}
+/*
+ * Walk nodes and perform fixups for nameref
+ */
+int aml_fixup_node(struct aml_node *, void *);
+
+int aml_fixup_node(struct aml_node *node, void *arg)
+{
+ struct aml_value *val = arg;
+ int i;
+
+ if (node->value == NULL)
+ return (0);
+ if (arg == NULL)
+ aml_fixup_node(node, node->value);
+ else if (val->type == AML_OBJTYPE_NAMEREF) {
+ node = aml_searchname(node, val->v_nameref);
+ if (node && node->value) {
+ _aml_setvalue(val, AML_OBJTYPE_OBJREF, -1,
+ node->value);
+ }
+ }
+ else if (val->type == AML_OBJTYPE_PACKAGE) {
+ for (i=0; i<val->length; i++)
+ aml_fixup_node(node, val->v_package[i]);
+ }
+ return (0);
+}
+
+void
+aml_postparse()
+{
+ aml_walknodes(&aml_root, AML_WALK_PRE, aml_fixup_node, NULL);
+}
+
diff --git a/sys/dev/acpi/dsdt.h b/sys/dev/acpi/dsdt.h
index b679476d45b..2ffb1f6eae3 100644
--- a/sys/dev/acpi/dsdt.h
+++ b/sys/dev/acpi/dsdt.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsdt.h,v 1.19 2006/11/25 18:24:54 marco Exp $ */
+/* $OpenBSD: dsdt.h,v 1.20 2006/11/27 15:17:37 jordan Exp $ */
/*
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
*
@@ -89,10 +89,116 @@ void aml_create_defaultobjects(void);
int acpi_mutex_acquire(struct aml_value *, int);
void acpi_mutex_release(struct aml_value *);
+const char *aml_nodename(struct aml_node *);
+
+#define SR_IRQ 0x04
+#define SR_DMA 0x05
+#define SR_STARTDEP 0x06
+#define SR_ENDDEP 0x07
+#define SR_IOPORT 0x08
+#define SR_FIXEDPORT 0x09
+#define SR_ENDTAG 0x0F
+
+#define LR_24BIT 0x81
+#define LR_GENREGISTER 0x82
+#define LR_32BIT 0x85
+#define LR_32BITFIXED 0x86
+#define LR_DWORD 0x87
+#define LR_WORD 0x88
+#define LR_EXTIRQ 0x89
+#define LR_QWORD 0x8A
+
+union acpi_resource
+{
+ struct {
+ uint8_t typecode;
+ uint16_t length;
+ } __packed hdr;
+
+ /* Small resource structures
+ * format of typecode is: tttttlll, t = type, l = length
+ */
+ struct {
+ uint8_t typecode;
+ uint16_t irq_mask;
+ uint8_t irq_info;
+ } __packed sr_irq;
+ struct {
+ uint8_t typecode;
+ uint8_t dma_chan;
+ uint8_t dma_info;
+ } __packed sr_dma;
+ struct {
+ uint8_t typecode;
+ uint8_t io_info;
+ uint16_t io_min;
+ uint16_t io_max;
+ uint8_t io_aln;
+ uint8_t io_len;
+ } __packed sr_ioport;
+ struct {
+ uint8_t typecode;
+ uint16_t fio_bas;
+ uint8_t fio_len;
+ } __packed sr_fioport;
+
+ /* Large resource structures */
+ struct {
+ uint8_t typecode;
+ uint16_t length;
+ uint8_t m24_info;
+ uint16_t m24_min;
+ uint16_t m24_max;
+ uint16_t m24_aln;
+ uint16_t m24_len;
+ } __packed lr_m24;
+ struct {
+ uint8_t typecode;
+ uint16_t length;
+ uint8_t m32_info;
+ uint32_t m32_min;
+ uint32_t m32_max;
+ uint32_t m32_aln;
+ uint32_t m32_len;
+ } __packed lr_m32;
+ struct {
+ uint8_t typecode;
+ uint16_t length;
+ uint8_t flags;
+ uint8_t irq_count;
+ uint32_t irq[1];
+ } __packed lr_extirq;
+} __packed;
+
+#define AML_CRSTYPE(x) ((x)->hdr.typecode & 0x80 ? \
+ (x)->hdr.typecode : \
+(x)->hdr.typecode >> 3)
+#define AML_CRSLEN(x) ((x)->hdr.typecode & 0x80 ? \
+ (x)->hdr.length+2 : \
+(x)->hdr.length & 0x7)
+
+int aml_print_resource(union acpi_resource *, void *);
+int aml_parse_resource(int, uint8_t *, int (*)(union acpi_resource *, void *),
+ void *);
+
#define ACPI_E_NOERROR 0x00
#define ACPI_E_BADVALUE 0x01
#define AML_MAX_ARG 7
#define AML_MAX_LOCAL 8
+/* XXX: endian macros */
+#define aml_letohost16(x) letoh16(x)
+#define aml_letohost32(x) letoh32(x)
+#define aml_letohost64(x) letoh64(x)
+
+#define AML_WALK_PRE 0x00
+#define AML_WALK_POST 0x01
+void
+aml_walknodes(struct aml_node *, int,
+ int (*)(struct aml_node *, void *),
+ void *);
+
+void aml_postparse(void);
+
#endif /* __DEV_ACPI_DSDT_H__ */