X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/99f2ed669601a61f4f0210e0b481ff877cd9bea7..refs/heads/arm64-irq-premerge:/lunaix-os/hal/devtree/dt.c diff --git a/lunaix-os/hal/devtree/dt.c b/lunaix-os/hal/devtree/dt.c index 72c443c..ee68cf6 100644 --- a/lunaix-os/hal/devtree/dt.c +++ b/lunaix-os/hal/devtree/dt.c @@ -1,199 +1,325 @@ #include #include - -#include +#include #include "devtree.h" LOG_MODULE("dtb") +static morph_t* devtree_obj_root; static struct dt_context dtctx; -void -fdt_itbegin(struct fdt_iter* fdti, struct fdt_header* fdt_hdr) +void +fdt_load(struct fdt_blob* fdt, ptr_t base) { - unsigned int off_struct, off_str; - struct fdt_token* tok; - const char* str_blk; + struct fdt_header* hdr; - off_str = le(fdt_hdr->off_dt_strings); - off_struct = le(fdt_hdr->off_dt_struct); + fdt->fdt_base = base; - tok = offset_t(fdt_hdr, struct fdt_token, off_struct); - str_blk = offset_t(fdt_hdr, const char, off_str); - - *fdti = (struct fdt_iter) { - .pos = tok, - .str_block = str_blk - }; -} + hdr = fdt->header; + if (hdr->magic != FDT_MAGIC) { + FATAL("invalid dtb, unexpected magic: 0x%x, expect: 0x%x", + hdr->magic, FDT_MAGIC); + } -void -fdt_itend(struct fdt_iter* fdti) -{ - fdti->pos = NULL; + fdt->plat_rsvd_base = base + hdr->off_mem_rsvmap; + fdt->str_block_base = base + hdr->off_dt_strings; + fdt->root.ptr = base + hdr->off_dt_struct; } bool -fdt_itnext(struct fdt_iter* fdti) +fdt_next_boot_rsvdmem(struct fdt_blob* fdt, fdt_loc_t* loc, + struct dt_memory_node* mem) { - struct fdt_token *current; - struct fdt_prop *prop; + fdt_loc_t current; - current = fdti->pos; - if (!current) { + current = *loc; + + if (!current.rsvd_ent->addr && !current.rsvd_ent->addr) { return false; } + mem->base = current.rsvd_ent->addr; + mem->size = current.rsvd_ent->size; + mem->type = FDT_MEM_RSVD; + + current.rsvd_ent++; + *loc = current; + + return true; +} + +fdt_loc_t +fdt_next_token(fdt_loc_t loc, int* delta_depth) +{ + int d = 0; + + do { + if (fdt_node(loc.token)) { + d++; + loc.ptr += strlen(loc.node->name) + 1; + loc.ptr = ROUNDUP(loc.ptr, sizeof(int)); + } + else if (fdt_node_end(loc.token)) { + d--; + } + else if (fdt_prop(loc.token)) { + loc.ptr += loc.prop->len + 2 * sizeof(int); + loc.ptr = ROUNDUP(loc.ptr, sizeof(int)); + } + + loc.token++; + } while (fdt_nope(loc.token)); + + *delta_depth = d; + return loc; +} + +bool +fdt_next_sibling(fdt_loc_t loc, fdt_loc_t* loc_out) +{ + int depth = 0, new_depth = 0; + + do { + loc = fdt_next_token(loc, &new_depth); + depth += new_depth; + } while (depth > 0); + + *loc_out = loc; + return !fdt_node_end(loc.token); +} + +fdt_loc_t +fdt_descend_into(fdt_loc_t loc) +{ + fdt_loc_t new_loc; + int depth = 0; + + new_loc = fdt_next_token(loc, &depth); + + return depth != 1 ? loc : new_loc; +} + +bool +fdt_find_prop(const struct fdt_blob* fdt, fdt_loc_t loc, + const char* name, struct dtp_val* val) +{ + char* prop_name; + + loc = fdt_descend_into(loc); + do { - if (fdt_nope(current)) { + if (!fdt_prop(loc.token)) { continue; } - if (fdt_prop(current)) { - prop = (struct fdt_prop*) current; - current = offset(current, prop->len); - continue; - } + prop_name = fdt_prop_key(fdt, loc); - if (fdt_node_end(current)) { - fdti->depth--; + if (!streq(prop_name, name)) { continue; } - // node begin - - fdti->depth++; - if (fdti->depth == 1) { - // enter root node - break; - } - - while (!fdt_prop(current) && !fdt_node_end(current)) { - current++; + if (likely(val)) { + val->encoded = (dt_enc_t)loc.prop->val; + val->size = loc.prop->len; } - - if (fdt_prop(current)) { - break; - } - - current++; + return true; - } while (fdt_nope(current) && fdti->depth > 0); + } while (fdt_next_sibling(loc, &loc)); - return fdti->depth > 0; + return false; } -bool -fdt_itnext_at(struct fdt_iter* fdti, int level) +bool +fdt_memscan_begin(struct fdt_memscan* mscan, const struct fdt_blob* fdt) { - while (fdti->depth != level && fdt_itnext(fdti)); - - return fdti->depth == level; -} + struct dtp_val val; + fdt_loc_t loc; -void -fdt_memrsvd_itbegin(struct fdt_memrsvd_iter* rsvdi, - struct fdt_header* fdt_hdr) -{ - size_t off = le(fdt_hdr->off_mem_rsvmap); - - rsvdi->block = - offset_t(fdt_hdr, typeof(*rsvdi->block), off); - - rsvdi->block = &rsvdi->block[-1]; + loc = fdt->root; + loc = fdt_descend_into(loc); + + if (fdt_find_prop(fdt, loc, "#address-cells", &val)) + { + mscan->root_addr_c = val.ref->u32_val; + } + + if (fdt_find_prop(fdt, loc, "#size-cells", &val)) + { + mscan->root_size_c = val.ref->u32_val; + } + + mscan->loc = loc; + mscan->node_type = FDT_MEM_FREE; } +#define get_size(mscan, val) \ + (mscan->root_size_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val) + +#define get_addr(mscan, val) \ + (mscan->root_addr_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val) + bool -fdt_memrsvd_itnext(struct fdt_memrsvd_iter* rsvdi) +fdt_memscan_nextnode(struct fdt_memscan* mscan, struct fdt_blob* fdt) { - struct fdt_memrsvd_ent* ent; + char* prop_name; - ent = rsvdi->block; - if (!ent) { - return false; + struct dtp_val val, reg_val; + fdt_loc_t loc, next; + struct dtpropi dtpi; + bool has_reg = false, found = false; + + next = mscan->loc; + +restart: + do + { + loc = next; + + if (!fdt_node(loc.token)) + continue; + + if (mscan->node_type != FDT_MEM_FREE) { + found = true; + continue; + } + + if (streq(loc.node->name, "reserved-memory")) { + // dived into /reserved-memory, walking for childrens + mscan->node_type = FDT_MEM_RSVD; + loc = fdt_descend_into(loc); + continue; + } + + if (!fdt_find_prop(fdt, loc, "device_type", &val)) + continue; + + if (!streq(val.str_val, "memory")) + continue; + + found = true; + } while (fdt_next_sibling(loc, &next) && !found); + + if (found) goto _found; + + // emerged from /reserved-memory, resume walking for /memory + if (mscan->node_type != FDT_MEM_FREE) { + mscan->node_type = FDT_MEM_FREE; + goto restart; } - rsvdi->block++; + return false; - return ent->addr || ent->size; -} +_found: -void -fdt_memrsvd_itend(struct fdt_memrsvd_iter* rsvdi) -{ - rsvdi->block = NULL; -} + dtpi_init_empty(&mscan->regit); + mscan->found = loc; + mscan->loc = next; -static inline bool -propeq(struct fdt_iter* it, const char* key) -{ - return streq(fdtit_prop_key(it), key); -} + has_reg = fdt_find_prop(fdt, loc, "reg", &val); + if (mscan->node_type == FDT_MEM_RSVD) { + goto do_rsvd_child; + } -static inline void -__mkprop_val32(struct fdt_iter* it, struct dt_prop_val* val) -{ - val->u32_val = le(*(u32_t*)&it->prop[1]); - val->size = le(it->prop->len); -} + if (!has_reg) + { + WARN("malformed memory node"); + goto restart; + } -static inline void -__mkprop_val64(struct fdt_iter* it, struct dt_prop_val* val) -{ - val->u64_val = le64(*(u64_t*)&it->prop[1]); - val->size = le(it->prop->len); -} + dtpi_init(&mscan->regit, &val); -static inline void -__mkprop_ptr(struct fdt_iter* it, struct dt_prop_val* val) -{ - val->ptr_val = __ptr(&it->prop[1]); - val->size = le(it->prop->len); -} + return true; -static inline u32_t -__prop_getu32(struct fdt_iter* it) -{ - return le(*(u32_t*)&it->prop[1]); +do_rsvd_child: + + mscan->node_attr.nomap = fdt_find_prop(fdt, loc, "no-map", NULL); + mscan->node_attr.reusable = fdt_find_prop(fdt, loc, "reusable", NULL); + + if (has_reg) + { + dtpi_init(&mscan->regit, &val); + mscan->node_type = FDT_MEM_RSVD; + return true; + } + + if (!fdt_find_prop(fdt, loc, "size", &val)) + { + WARN("malformed reserved memory child node"); + goto restart; + } + + mscan->node_type = FDT_MEM_RSVD_DYNAMIC; + mscan->node_attr.total_size = get_size(mscan, &val); + + if (fdt_find_prop(fdt, loc, "alignment", &val)) { + mscan->node_attr.alignment = get_size(mscan, &val); + } + + if (fdt_find_prop(fdt, loc, "alloc-ranges", &val)) { + dtpi_init(&mscan->regit, &val); + } + + return true; } -static bool -__parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node) +bool +fdt_memscan_nextrange(struct fdt_memscan* mscan, struct dt_memory_node* mem) { - struct fdt_prop* prop; + struct dtp_val val; - prop = it->prop; + if (dtpi_is_empty(&mscan->regit)) { + return false; + } - if (propeq(it, "compatible")) { - __mkprop_ptr(it, &node->compat); - } + if (!dtpi_has_next(&mscan->regit)) { + return false; + } + + if (dtpi_next_val(&mscan->regit, &val, mscan->root_addr_c)) { + mem->base = get_addr(mscan, &val); + } + + if (dtpi_next_val(&mscan->regit, &val, mscan->root_size_c)) { + mem->size = get_size(mscan, &val); + } + + mem->type = mscan->node_type; - else if (propeq(it, "model")) { - node->model = (const char*)&prop[1]; + if (mem->type == FDT_MEM_RSVD_DYNAMIC) { + mem->dyn_alloc_attr = mscan->node_attr; + } + + return true; +} + +static bool +__parse_stdbase_prop(struct fdt_blob* fdt, fdt_loc_t loc, + struct dtn_base* node) +{ + if (propeq(fdt, loc, "compatible")) { + __mkprop_ptr(loc, &node->compat); } - else if (propeq(it, "phandle")) { - node->phandle = __prop_getu32(it); - hashtable_hash_in(dtctx.phnds_table, - &node->phnd_link, node->phandle); + else if (propeq(fdt, loc, "phandle")) { + node->phandle = __prop_getu32(loc); } - else if (propeq(it, "#address-cells")) { - node->addr_c = (char)__prop_getu32(it); + else if (propeq(fdt, loc, "#address-cells")) { + node->addr_c = (char)__prop_getu32(loc); } - else if (propeq(it, "#size-cells")) { - node->sz_c = (char)__prop_getu32(it); + else if (propeq(fdt, loc, "#size-cells")) { + node->sz_c = (char)__prop_getu32(loc); } - else if (propeq(it, "#interrupt-cells")) { - node->intr_c = (char)__prop_getu32(it); + else if (propeq(fdt, loc, "#interrupt-cells")) { + node->intr_c = (char)__prop_getu32(loc); } - else if (propeq(it, "status")) { - char peek = *(char*)&it->prop[1]; + else if (propeq(fdt, loc, "status")) { + char peek = loc.prop->val_str[0]; if (peek == 'o') { node->status = STATUS_OK; } @@ -216,22 +342,18 @@ __parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node) } static bool -__parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node) +__parse_stdnode_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node) { - if (propeq(it, "reg")) { - __mkprop_ptr(it, &node->reg); + if (propeq(fdt, loc, "reg")) { + __mkprop_ptr(loc, &node->reg); } - else if (propeq(it, "virtual-reg")) { - __mkprop_ptr(it, &node->vreg); + else if (propeq(fdt, loc, "ranges")) { + __mkprop_ptr(loc, &node->ranges); } - else if (propeq(it, "ranges")) { - __mkprop_ptr(it, &node->ranges); - } - - else if (propeq(it, "dma-ranges")) { - __mkprop_ptr(it, &node->dma_ranges); + else if (propeq(fdt, loc, "dma-ranges")) { + __mkprop_ptr(loc, &node->dma_ranges); } else { @@ -242,17 +364,17 @@ __parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node) } static bool -__parse_stdflags(struct fdt_iter* it, struct dt_node_base* node) +__parse_stdflags(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node) { - if (propeq(it, "dma-coherent")) { + if (propeq(fdt, loc, "dma-coherent")) { node->dma_coherent = true; } - else if (propeq(it, "dma-noncoherent")) { + else if (propeq(fdt, loc, "dma-noncoherent")) { node->dma_ncoherent = true; } - else if (propeq(it, "interrupt-controller")) { + else if (propeq(fdt, loc, "interrupt-controller")) { node->intr_controll = true; } @@ -263,152 +385,156 @@ __parse_stdflags(struct fdt_iter* it, struct dt_node_base* node) return true; } +static inline void +__dt_node_set_name(struct dtn* node, const char* name) +{ + changeling_setname(&node->mobj, name); +} + +static inline void +__init_prop_table(struct dtn_base* node) +{ + struct dtp_table* propt; + + propt = valloc(sizeof(*propt)); + hashtable_init(propt->_op_bucket); + + node->props = propt; +} + +#define prop_table_add(node, prop) \ + hashtable_hash_in( (node)->props->_op_bucket, \ + &(prop)->ht, (prop)->key.hash); + static void -__parse_other_prop(struct fdt_iter* it, struct dt_node_base* node) +__parse_other_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node) { - struct dt_prop* prop; + struct dtp* prop; const char* key; unsigned int hash; prop = valloc(sizeof(*prop)); - key = fdtit_prop_key(it); + key = fdt_prop_key(fdt, loc); prop->key = HSTR(key, strlen(key)); - __mkprop_ptr(it, &prop->val); + __mkprop_ptr(loc, &prop->val); hstr_rehash(&prop->key, HSTR_FULL_HASH); - hash = prop->key.hash; - hashtable_hash_in(node->_op_bucket, &prop->ht, hash); + prop_table_add(node, prop); } static void -__fill_node(struct fdt_iter* it, struct dt_node* node) +__fill_node(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node) { - if (__parse_stdflags(it, &node->base)) { + if (__parse_stdflags(fdt, loc, &node->base)) { return; } - if (__parse_stdbase_prop(it, &node->base)) { + if (__parse_stdbase_prop(fdt, loc, &node->base)) { return; } - if (__parse_stdnode_prop(it, node)) { + if (__parse_stdnode_prop(fdt, loc, node)) { return; } - if (__parse_stdintr_prop(it, &node->intr)) { + if (parse_stdintr_prop(fdt, loc, &node->intr)) { return; } - __parse_other_prop(it, &node->base); + __parse_other_prop(fdt, loc, &node->base); } -static void -__fill_root(struct fdt_iter* it, struct dt_root* node) +static inline void +__set_parent(struct dtn_base* parent, struct dtn_base* node) { - if (__parse_stdflags(it, &node->base)) { - return; - } + morph_t* parent_obj; - if (__parse_stdbase_prop(it, &node->base)) { - return; - } - - struct fdt_prop* prop; - - prop = it->prop; - if (propeq(it, "serial-number")) { - node->serial = (const char*)&prop[1]; - } - - else if (propeq(it, "chassis-type")) { - node->chassis = (const char*)&prop[1]; + parent_obj = devtree_obj_root; + node->parent = parent; + + if (parent) { + node->addr_c = parent->addr_c; + node->sz_c = parent->sz_c; + node->intr_c = parent->intr_c; + parent_obj = dt_mobj(parent); } - __parse_other_prop(it, &node->base); -} - -static inline void -__init_node(struct dt_node_base* node) -{ - hashtable_init(node->_op_bucket); - llist_init_head(&node->children); - - if (node->parent) - node->_std = node->parent->_std; + changeling_attach(parent_obj, dt_mobj(node)); } static inline void -__init_node_regular(struct dt_node* node) +__init_node_regular(struct dtn* node) { - __init_node(&node->base); + __init_prop_table(&node->base); + changeling_morph_anon(NULL, node->mobj, dt_morpher); + node->intr.parent_hnd = PHND_NULL; } static void -__expand_extended_intr(struct dt_intr_node* intrupt) +__expand_extended_intr(struct dtn_intr* intrupt) { - struct dt_prop_iter it; - struct dt_prop_val arr; - struct dt_node *node; - struct dt_node *master; - struct dt_intr_prop* intr_prop; + struct dtpropi it; + struct dtp_val arr; + struct dtn *domain; + struct dtspec_intr* ispec; + int nr_intrs = 0; - if (!intrupt->intr.extended) { - return; + if (!intrupt->extended) { + nr_intrs = intrupt->raw_ispecs.size / sizeof(u32_t); + nr_intrs /= intrupt->parent->base.intr_c; + goto done; } - arr = intrupt->intr.arr; - node = INTR_TO_DTNODE(intrupt); + arr = intrupt->raw_ispecs; - llist_init_head(&intrupt->intr.values); + llist_init_head(&intrupt->ext_ispecs); - dt_decode(&it, &node->base, &arr, 1); - - dt_phnd_t phnd; - do { - phnd = dtprop_to_u32(it.prop_loc); - master = dt_resolve_phandle(phnd); + dtpi_init(&it, &arr); + + while(dtpi_has_next(&it)) + { + domain = dtpi_next_hnd(&it); - if (!master) { - WARN("dtb: (intr_extended) malformed phandle: %d", phnd); + if (!domain) { + WARN("(intr_extended) malformed phandle"); continue; } - intr_prop = valloc(sizeof(*intr_prop)); - - intr_prop->master = &master->intr; - intr_prop->val = (struct dt_prop_val) { - .encoded = it.prop_loc_next, - .size = master->base.intr_c - }; - - llist_append(&intrupt->intr.values, &intr_prop->props); - dtprop_next_n(&it, intr_prop->val.size); + ispec = valloc(sizeof(*ispec)); - } while(dtprop_next(&it)); + ispec->domain = domain; + dtpi_next_val(&it, &ispec->val, domain->base.intr_c); + + llist_append(&intrupt->ext_ispecs, &ispec->ispecs); + nr_intrs++; + }; + +done: + intrupt->nr_intrs = nr_intrs; } static void __resolve_phnd_references() { - struct dt_node_base *pos, *n; - struct dt_node *node, *parent, *default_parent; - struct dt_intr_node* intrupt; + struct dtn_base *pos, *n; + struct dtn *node, *parent, *default_parent; + struct dtn_intr* intrupt; dt_phnd_t phnd; llist_for_each(pos, n, &dtctx.nodes, nodes) { - node = BASE_TO_DTNODE(pos); + node = dtn_from(pos); intrupt = &node->intr; - if (!node->base.intr_c) { + if (intrupt->parent_hnd == PHND_NULL) { continue; } phnd = intrupt->parent_hnd; - default_parent = (struct dt_node*)node->base.parent; + default_parent = (struct dtn*)node->base.parent; parent = default_parent; if (phnd != PHND_NULL) { @@ -420,7 +546,7 @@ __resolve_phnd_references() parent = default_parent; } - intrupt->parent = &parent->intr; + intrupt->parent = parent; __expand_extended_intr(intrupt); } @@ -429,101 +555,98 @@ __resolve_phnd_references() static void __resolve_inter_map() { - struct dt_node_base *pos, *n; + struct dtn_base *pos, *n; llist_for_each(pos, n, &dtctx.nodes, nodes) { - dt_resolve_interrupt_map(BASE_TO_DTNODE(pos)); + dt_resolve_interrupt_map(dtn_from(pos)); } } bool dt_load(ptr_t dtb_dropoff) { - dtctx.reloacted_dtb = dtb_dropoff; - - if (dtctx.fdt->magic != FDT_MAGIC) { - ERROR("invalid dtb, unexpected magic: 0x%x", dtctx.fdt->magic); - return false; - } - - size_t str_off = le(dtctx.fdt->size_dt_strings); - dtctx.str_block = offset_t(dtb_dropoff, const char, str_off); - llist_init_head(&dtctx.nodes); hashtable_init(dtctx.phnds_table); - struct fdt_iter it; - struct fdt_token* tok; - struct dt_node_base *node, *prev; + struct fdt_blob *fdt; + struct dtn *node, + *stack[16] = { NULL }; - struct dt_node_base* depth[16]; - bool is_root_level, filled; + int depth = 0, delta = 0, nr_nodes = 0; + fdt_loc_t loc, next_loc; + + fdt = &dtctx.fdt; + fdt_load(&dtctx.fdt, dtb_dropoff); - node = NULL; - depth[0] = NULL; - fdt_itbegin(&it, dtctx.fdt); + loc = fdt->root; - while (fdt_itnext(&it)) { - is_root_level = it.depth == 1; + while (!fdt_eof(loc.token)) + { + next_loc = fdt_next_token(loc, &delta); - if (it.depth >= 16) { + if (depth >= 16) { // tree too deep ERROR("strange dtb, too deep to dive."); return false; } - depth[it.depth] = NULL; - node = depth[it.depth - 1]; + assert(depth >= 0); + node = stack[depth]; - if (!node) { - // need new node - if (unlikely(is_root_level)) { - node = vzalloc(sizeof(struct dt_root)); - __init_node(node); - } - else { - node = vzalloc(sizeof(struct dt_node)); - prev = depth[it.depth - 2]; - node->parent = prev; + if (fdt_node(loc.token)) + { + assert(!node); + + node = vzalloc(sizeof(struct dtn)); + __init_node_regular(node); + llist_append(&dtctx.nodes, &node->base.nodes); - __init_node_regular((struct dt_node*)node); - llist_append(&prev->children, &node->siblings); + __dt_node_set_name(node, loc.node->name); - llist_append(&dtctx.nodes, &node->nodes); + if (depth) { + __set_parent(&stack[depth - 1]->base, &node->base); } - node->name = (const char*)&it.pos[1]; + nr_nodes++; + stack[depth] = node; } - if (unlikely(is_root_level)) { - __fill_root(&it, (struct dt_root*)node); + else if (depth > 1 && fdt_node_end(loc.token)) + { + stack[depth - 1] = NULL; } - else { - __fill_node(&it, (struct dt_node*)node); + + else if (fdt_prop(loc.token)) + { + node = stack[depth - 1]; + + assert(depth && node); + __fill_node(fdt, loc, node); } - } - fdt_itend(&it); + depth += delta; + loc = next_loc; + } - dtctx.root = (struct dt_root*)depth[0]; + dtctx.root = stack[0]; __resolve_phnd_references(); __resolve_inter_map(); - INFO("device tree loaded"); + INFO("%d nodes loaded.", nr_nodes); return true; } -struct dt_node* +struct dtn* dt_resolve_phandle(dt_phnd_t phandle) { - struct dt_node_base *pos, *n; - hashtable_hash_foreach(dtctx.phnds_table, phandle, pos, n, phnd_link) + struct dtn_base *pos, *n; + llist_for_each(pos, n, &dtctx.nodes, nodes) { if (pos->phandle == phandle) { - return (struct dt_node*)pos; + return (struct dtn*)pos; } } @@ -531,10 +654,10 @@ dt_resolve_phandle(dt_phnd_t phandle) } static bool -__byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node) +__byname_predicate(struct dtn_iter* iter, struct dtn_base* node) { int i = 0; - const char* be_matched = node->name; + const char* be_matched = HSTR_VAL(node->mobj.name); const char* name = (const char*)iter->closure; while (be_matched[i] && name[i]) @@ -550,74 +673,78 @@ __byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node) } void -dt_begin_find_byname(struct dt_node_iter* iter, - struct dt_node* node, const char* name) +dt_begin_find_byname(struct dtn_iter* iter, + struct dtn* node, const char* name) { dt_begin_find(iter, node, __byname_predicate, name); } void -dt_begin_find(struct dt_node_iter* iter, struct dt_node* node, +dt_begin_find(struct dtn_iter* iter, struct dtn* node, node_predicate_t pred, void* closure) { - node = node ? : (struct dt_node*)dtctx.root; + node = node ? : (struct dtn*)dtctx.root; iter->head = &node->base; iter->matched = NULL; iter->closure = closure; iter->pred = pred; - struct dt_node_base *pos, *n; - llist_for_each(pos, n, &node->base.children, siblings) + morph_t *pos, *n; + struct dtn_base* base; + changeling_for_each(pos, n, &node->mobj) { - if (pred(iter, pos)) { - iter->matched = pos; + base = &changeling_reveal(pos, dt_morpher)->base; + if (pred(iter, base)) { + iter->matched = base; break; } } } bool -dt_find_next(struct dt_node_iter* iter, - struct dt_node_base** matched) +dt_find_next(struct dtn_iter* iter, + struct dtn_base** matched) { if (!dt_found_any(iter)) { return false; } - struct dt_node_base *pos, *head; + struct dtn *node; + morph_t *pos, *head; - head = iter->head; - pos = iter->matched; - *matched = pos; + head = dt_mobj(iter->head); + pos = dt_mobj(iter->matched); + *matched = iter->matched; - while (&pos->siblings != &head->children) + while (&pos->sibs != &head->subs) { - pos = list_next(pos, struct dt_node_base, siblings); + pos = list_next(pos, morph_t, sibs); + node = changeling_reveal(pos, dt_morpher); - if (!iter->pred(iter, pos)) { + if (!iter->pred(iter, &node->base)) { continue; } - iter->matched = pos; + iter->matched = &node->base; return true; } return false; } -struct dt_prop_val* -dt_getprop(struct dt_node_base* base, const char* name) +struct dtp_val* +dt_getprop(struct dtn_base* base, const char* name) { struct hstr hashed_name; - struct dt_prop *pos, *n; + struct dtp *pos, *n; unsigned int hash; hashed_name = HSTR(name, strlen(name)); hstr_rehash(&hashed_name, HSTR_FULL_HASH); hash = hashed_name.hash; - hashtable_hash_foreach(base->_op_bucket, hash, pos, n, ht) + hashtable_hash_foreach(base->props->_op_bucket, hash, pos, n, ht) { if (HSTR_EQ(&pos->key, &hashed_name)) { return &pos->val; @@ -625,4 +752,171 @@ dt_getprop(struct dt_node_base* base, const char* name) } return NULL; -} \ No newline at end of file +} + +void +dtpx_compile_proplet(struct dtprop_def* proplet) +{ + int i; + unsigned int acc = 0; + struct dtprop_def* pl; + + for (i = 0; proplet[i].type && i < 10; ++i) + { + pl = &proplet[i]; + + if (pl->type == DTP_COMPX) { + if (pl->cell == 1) + pl->type = DTP_U32; + else if (pl->cell == 2) + pl->type = DTP_U64; + } + + pl->acc_sz = acc; + acc += pl->cell; + } + + if (proplet[i - 1].type && i == 10) { + FATAL("invalid proplet: no terminator detected"); + } + + proplet[i].acc_sz = acc; +} + +void +dtpx_prepare_with(struct dtpropx* propx, struct dtp_val* prop, + struct dtprop_def* proplet) +{ + int i; + bool has_str = false; + + for (i = 0; proplet[i].type; ++i); + + propx->proplet = proplet; + propx->proplet_len = i; + propx->proplet_sz = proplet[i].acc_sz; + propx->raw = prop; + propx->row_loc = 0; +} + +bool +dtpx_goto_row(struct dtpropx* propx, int row) +{ + off_t loc; + + loc = propx->proplet_sz; + loc *= row; + + if (loc * sizeof(u32_t) >= propx->raw->size) { + return false; + } + + propx->row_loc = loc; + return true; +} + +bool +dtpx_next_row(struct dtpropx* propx) +{ + off_t loc; + + loc = propx->row_loc; + loc += propx->proplet_sz; + + if (loc * sizeof(u32_t) >= propx->raw->size) { + return false; + } + + propx->row_loc = loc; + return true; +} + +bool +dtpx_extract_at(struct dtpropx* propx, + struct dtprop_xval* val, int col) +{ + struct dtprop_def* def; + union dtp_baseval* raw; + dt_enc_t enc; + + if (unlikely(col >= propx->proplet_len)) { + return false; + } + + def = &propx->proplet[col]; + enc = &propx->raw->encoded[propx->row_loc + def->acc_sz]; + raw = (union dtp_baseval*)enc; + + val->archetype = def; + + switch (def->type) + { + case DTP_U32: + val->u32 = raw->u32_val; + break; + + case DTP_U64: + val->u64 = raw->u64_val; + break; + + case DTP_PHANDLE: + { + ptr_t hnd = raw->phandle; + val->phandle = dt_resolve_phandle(hnd); + } break; + + case DTP_COMPX: + { + val->composite = enc; + } + break; + + default: + break; + } + + return true; +} + +bool +dtpx_extract_loc(struct dtpropx* propx, + struct dtprop_xval* val, int row, int col) +{ + ptr_t loc = propx->row_loc; + + if (!dtpx_goto_row(propx, row)) + return false; + + + bool r = dtpx_extract_at(propx, val, col); + propx->row_loc = loc; + return r; +} + +bool +dtpx_extract_row(struct dtpropx* propx, struct dtprop_xval* vals, int len) +{ + assert(len == propx->proplet_len); + + for (int i = 0; i < len; i++) + { + if (!dtpx_extract_at(propx, &vals[i], i)) { + return false; + } + } + + return true; +} + +struct dt_context* +dt_main_context() +{ + return &dtctx; +} + +static void +__init_devtree() +{ + devtree_obj_root = changeling_spawn(NULL, NULL); +} +owloysius_fetch_init(__init_devtree, on_sysconf); \ No newline at end of file