diff options
author | Jordan Hargrave <jordan@cvs.openbsd.org> | 2006-11-27 15:17:38 +0000 |
---|---|---|
committer | Jordan Hargrave <jordan@cvs.openbsd.org> | 2006-11-27 15:17:38 +0000 |
commit | 3c4560151200cd4b978ae3f5fe77cc21f5ad709d (patch) | |
tree | 61e8fb9e9f5fc89b3d3e90ff8f0a4fd8373c0070 /sys/dev | |
parent | 4ae77a80a2c526e96aec6b7969ba7ec0cb0e8a77 (diff) |
Added support for parsing _CRS resources
Post-parsing fixup for forward name references
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpi/dsdt.c | 187 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.h | 108 |
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__ */ |