1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/syslog.h>
3 #include <lunaix/owloysius.h>
9 static morph_t* devtree_obj_root;
10 static struct dt_context dtctx;
13 fdt_load(struct fdt_blob* fdt, ptr_t base)
15 struct fdt_header* hdr;
20 if (hdr->magic != FDT_MAGIC) {
21 FATAL("invalid dtb, unexpected magic: 0x%x, expect: 0x%x",
22 hdr->magic, FDT_MAGIC);
25 fdt->plat_rsvd_base = base + hdr->off_mem_rsvmap;
26 fdt->str_block_base = base + hdr->off_dt_strings;
27 fdt->root.ptr = base + hdr->off_dt_struct;
31 fdt_next_boot_rsvdmem(struct fdt_blob* fdt, fdt_loc_t* loc,
32 struct dt_memory_node* mem)
38 if (!current.rsvd_ent->addr && !current.rsvd_ent->addr) {
42 mem->base = current.rsvd_ent->addr;
43 mem->size = current.rsvd_ent->size;
44 mem->type = FDT_MEM_RSVD;
53 fdt_next_token(fdt_loc_t loc, int* delta_depth)
58 if (fdt_node(loc.token)) {
60 loc.ptr += strlen(loc.node->name) + 1;
61 loc.ptr = ROUNDUP(loc.ptr, sizeof(int));
63 else if (fdt_node_end(loc.token)) {
66 else if (fdt_prop(loc.token)) {
67 loc.ptr += loc.prop->len + 2 * sizeof(int);
68 loc.ptr = ROUNDUP(loc.ptr, sizeof(int));
72 } while (fdt_nope(loc.token));
79 fdt_next_sibling(fdt_loc_t loc, fdt_loc_t* loc_out)
81 int depth = 0, new_depth = 0;
84 loc = fdt_next_token(loc, &new_depth);
89 return !fdt_node_end(loc.token);
93 fdt_descend_into(fdt_loc_t loc)
98 new_loc = fdt_next_token(loc, &depth);
100 return depth != 1 ? loc : new_loc;
104 fdt_find_prop(const struct fdt_blob* fdt, fdt_loc_t loc,
105 const char* name, struct dtp_val* val)
109 loc = fdt_descend_into(loc);
113 if (!fdt_prop(loc.token)) {
117 prop_name = fdt_prop_key(fdt, loc);
119 if (!streq(prop_name, name)) {
124 val->encoded = (dt_enc_t)loc.prop->val;
125 val->size = loc.prop->len;
129 } while (fdt_next_sibling(loc, &loc));
135 fdt_memscan_begin(struct fdt_memscan* mscan, const struct fdt_blob* fdt)
141 loc = fdt_descend_into(loc);
143 if (fdt_find_prop(fdt, loc, "#address-cells", &val))
145 mscan->root_addr_c = val.ref->u32_val;
148 if (fdt_find_prop(fdt, loc, "#size-cells", &val))
150 mscan->root_size_c = val.ref->u32_val;
154 mscan->node_type = FDT_MEM_FREE;
157 #define get_size(mscan, val) \
158 (mscan->root_size_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val)
160 #define get_addr(mscan, val) \
161 (mscan->root_addr_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val)
164 fdt_memscan_nextnode(struct fdt_memscan* mscan, struct fdt_blob* fdt)
168 struct dtp_val val, reg_val;
171 bool has_reg = false, found = false;
180 if (!fdt_node(loc.token))
183 if (mscan->node_type != FDT_MEM_FREE) {
188 if (streq(loc.node->name, "reserved-memory")) {
189 // dived into /reserved-memory, walking for childrens
190 mscan->node_type = FDT_MEM_RSVD;
191 loc = fdt_descend_into(loc);
195 if (!fdt_find_prop(fdt, loc, "device_type", &val))
198 if (!streq(val.str_val, "memory"))
202 } while (fdt_next_sibling(loc, &next) && !found);
204 if (found) goto _found;
206 // emerged from /reserved-memory, resume walking for /memory
207 if (mscan->node_type != FDT_MEM_FREE) {
208 mscan->node_type = FDT_MEM_FREE;
216 dtpi_init_empty(&mscan->regit);
220 has_reg = fdt_find_prop(fdt, loc, "reg", &val);
221 if (mscan->node_type == FDT_MEM_RSVD) {
227 WARN("malformed memory node");
231 dtpi_init(&mscan->regit, &val);
237 mscan->node_attr.nomap = fdt_find_prop(fdt, loc, "no-map", NULL);
238 mscan->node_attr.reusable = fdt_find_prop(fdt, loc, "reusable", NULL);
242 dtpi_init(&mscan->regit, &val);
243 mscan->node_type = FDT_MEM_RSVD;
247 if (!fdt_find_prop(fdt, loc, "size", &val))
249 WARN("malformed reserved memory child node");
253 mscan->node_type = FDT_MEM_RSVD_DYNAMIC;
254 mscan->node_attr.total_size = get_size(mscan, &val);
256 if (fdt_find_prop(fdt, loc, "alignment", &val)) {
257 mscan->node_attr.alignment = get_size(mscan, &val);
260 if (fdt_find_prop(fdt, loc, "alloc-ranges", &val)) {
261 dtpi_init(&mscan->regit, &val);
268 fdt_memscan_nextrange(struct fdt_memscan* mscan, struct dt_memory_node* mem)
272 if (dtpi_is_empty(&mscan->regit)) {
276 if (!dtpi_has_next(&mscan->regit)) {
280 if (dtpi_next_val(&mscan->regit, &val, mscan->root_addr_c)) {
281 mem->base = get_addr(mscan, &val);
284 if (dtpi_next_val(&mscan->regit, &val, mscan->root_size_c)) {
285 mem->size = get_size(mscan, &val);
288 mem->type = mscan->node_type;
290 if (mem->type == FDT_MEM_RSVD_DYNAMIC) {
291 mem->dyn_alloc_attr = mscan->node_attr;
298 __parse_stdbase_prop(struct fdt_blob* fdt, fdt_loc_t loc,
299 struct dtn_base* node)
301 if (propeq(fdt, loc, "compatible")) {
302 __mkprop_ptr(loc, &node->compat);
305 else if (propeq(fdt, loc, "phandle")) {
306 node->phandle = __prop_getu32(loc);
309 else if (propeq(fdt, loc, "#address-cells")) {
310 node->addr_c = (char)__prop_getu32(loc);
313 else if (propeq(fdt, loc, "#size-cells")) {
314 node->sz_c = (char)__prop_getu32(loc);
317 else if (propeq(fdt, loc, "#interrupt-cells")) {
318 node->intr_c = (char)__prop_getu32(loc);
321 else if (propeq(fdt, loc, "status")) {
322 char peek = loc.prop->val_str[0];
324 node->status = STATUS_OK;
326 else if (peek == 'r') {
327 node->status = STATUS_RSVD;
329 else if (peek == 'd') {
330 node->status = STATUS_DISABLE;
332 else if (peek == 'f') {
333 node->status = STATUS_FAIL;
345 __parse_stdnode_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node)
347 if (propeq(fdt, loc, "reg")) {
348 __mkprop_ptr(loc, &node->reg);
351 else if (propeq(fdt, loc, "ranges")) {
352 __mkprop_ptr(loc, &node->ranges);
355 else if (propeq(fdt, loc, "dma-ranges")) {
356 __mkprop_ptr(loc, &node->dma_ranges);
367 __parse_stdflags(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node)
369 if (propeq(fdt, loc, "dma-coherent")) {
370 node->dma_coherent = true;
373 else if (propeq(fdt, loc, "dma-noncoherent")) {
374 node->dma_ncoherent = true;
377 else if (propeq(fdt, loc, "interrupt-controller")) {
378 node->intr_controll = true;
389 __dt_node_set_name(struct dtn* node, const char* name)
391 changeling_setname(&node->mobj, name);
395 __init_prop_table(struct dtn_base* node)
397 struct dtp_table* propt;
399 propt = valloc(sizeof(*propt));
400 hashtable_init(propt->_op_bucket);
405 #define prop_table_add(node, prop) \
406 hashtable_hash_in( (node)->props->_op_bucket, \
407 &(prop)->ht, (prop)->key.hash);
410 __parse_other_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node)
416 prop = valloc(sizeof(*prop));
417 key = fdt_prop_key(fdt, loc);
419 prop->key = HSTR(key, strlen(key));
420 __mkprop_ptr(loc, &prop->val);
422 hstr_rehash(&prop->key, HSTR_FULL_HASH);
424 prop_table_add(node, prop);
428 __fill_node(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node)
430 if (__parse_stdflags(fdt, loc, &node->base)) {
434 if (__parse_stdbase_prop(fdt, loc, &node->base)) {
438 if (__parse_stdnode_prop(fdt, loc, node)) {
442 if (parse_stdintr_prop(fdt, loc, &node->intr)) {
446 __parse_other_prop(fdt, loc, &node->base);
450 __set_parent(struct dtn_base* parent, struct dtn_base* node)
454 parent_obj = devtree_obj_root;
455 node->parent = parent;
458 node->addr_c = parent->addr_c;
459 node->sz_c = parent->sz_c;
460 node->intr_c = parent->intr_c;
461 parent_obj = dt_mobj(parent);
464 changeling_attach(parent_obj, dt_mobj(node));
468 __init_node_regular(struct dtn* node)
470 __init_prop_table(&node->base);
471 changeling_morph_anon(NULL, node->mobj, dt_morpher);
473 node->intr.parent_hnd = PHND_NULL;
477 __expand_extended_intr(struct dtn_intr* intrupt)
482 struct dtspec_intr* ispec;
485 if (!intrupt->extended) {
486 nr_intrs = intrupt->raw_ispecs.size / sizeof(u32_t);
487 nr_intrs /= intrupt->parent->base.intr_c;
491 arr = intrupt->raw_ispecs;
493 llist_init_head(&intrupt->ext_ispecs);
495 dtpi_init(&it, &arr);
497 while(dtpi_has_next(&it))
499 domain = dtpi_next_hnd(&it);
502 WARN("(intr_extended) malformed phandle");
506 ispec = valloc(sizeof(*ispec));
508 ispec->domain = domain;
509 dtpi_next_val(&it, &ispec->val, domain->base.intr_c);
511 llist_append(&intrupt->ext_ispecs, &ispec->ispecs);
516 intrupt->nr_intrs = nr_intrs;
520 __resolve_phnd_references()
522 struct dtn_base *pos, *n;
523 struct dtn *node, *parent, *default_parent;
524 struct dtn_intr* intrupt;
527 llist_for_each(pos, n, &dtctx.nodes, nodes)
529 node = dtn_from(pos);
530 intrupt = &node->intr;
532 if (intrupt->parent_hnd == PHND_NULL) {
536 phnd = intrupt->parent_hnd;
537 default_parent = (struct dtn*)node->base.parent;
538 parent = default_parent;
540 if (phnd != PHND_NULL) {
541 parent = dt_resolve_phandle(phnd);
545 WARN("dtb: (phnd_resolve) malformed phandle: %d", phnd);
546 parent = default_parent;
549 intrupt->parent = parent;
551 __expand_extended_intr(intrupt);
556 __resolve_inter_map()
558 struct dtn_base *pos, *n;
560 llist_for_each(pos, n, &dtctx.nodes, nodes)
562 dt_resolve_interrupt_map(dtn_from(pos));
567 dt_load(ptr_t dtb_dropoff)
569 llist_init_head(&dtctx.nodes);
570 hashtable_init(dtctx.phnds_table);
572 struct fdt_blob *fdt;
574 *stack[16] = { NULL };
576 int depth = 0, delta = 0, nr_nodes = 0;
577 fdt_loc_t loc, next_loc;
580 fdt_load(&dtctx.fdt, dtb_dropoff);
584 while (!fdt_eof(loc.token))
586 next_loc = fdt_next_token(loc, &delta);
590 ERROR("strange dtb, too deep to dive.");
597 if (fdt_node(loc.token))
601 node = vzalloc(sizeof(struct dtn));
602 __init_node_regular(node);
603 llist_append(&dtctx.nodes, &node->base.nodes);
605 __dt_node_set_name(node, loc.node->name);
608 __set_parent(&stack[depth - 1]->base, &node->base);
615 else if (depth > 1 && fdt_node_end(loc.token))
617 stack[depth - 1] = NULL;
620 else if (fdt_prop(loc.token))
622 node = stack[depth - 1];
624 assert(depth && node);
625 __fill_node(fdt, loc, node);
632 dtctx.root = stack[0];
634 __resolve_phnd_references();
635 __resolve_inter_map();
637 INFO("%d nodes loaded.", nr_nodes);
643 dt_resolve_phandle(dt_phnd_t phandle)
645 struct dtn_base *pos, *n;
646 llist_for_each(pos, n, &dtctx.nodes, nodes)
648 if (pos->phandle == phandle) {
649 return (struct dtn*)pos;
657 __byname_predicate(struct dtn_iter* iter, struct dtn_base* node)
660 const char* be_matched = HSTR_VAL(node->mobj.name);
661 const char* name = (const char*)iter->closure;
663 while (be_matched[i] && name[i])
665 if (be_matched[i] != name[i]) {
676 dt_begin_find_byname(struct dtn_iter* iter,
677 struct dtn* node, const char* name)
679 dt_begin_find(iter, node, __byname_predicate, name);
683 dt_begin_find(struct dtn_iter* iter, struct dtn* node,
684 node_predicate_t pred, void* closure)
686 node = node ? : (struct dtn*)dtctx.root;
688 iter->head = &node->base;
689 iter->matched = NULL;
690 iter->closure = closure;
694 struct dtn_base* base;
695 changeling_for_each(pos, n, &node->mobj)
697 base = &changeling_reveal(pos, dt_morpher)->base;
698 if (pred(iter, base)) {
699 iter->matched = base;
706 dt_find_next(struct dtn_iter* iter,
707 struct dtn_base** matched)
709 if (!dt_found_any(iter)) {
716 head = dt_mobj(iter->head);
717 pos = dt_mobj(iter->matched);
718 *matched = iter->matched;
720 while (&pos->sibs != &head->subs)
722 pos = list_next(pos, morph_t, sibs);
723 node = changeling_reveal(pos, dt_morpher);
725 if (!iter->pred(iter, &node->base)) {
729 iter->matched = &node->base;
737 dt_getprop(struct dtn_base* base, const char* name)
739 struct hstr hashed_name;
743 hashed_name = HSTR(name, strlen(name));
744 hstr_rehash(&hashed_name, HSTR_FULL_HASH);
745 hash = hashed_name.hash;
747 hashtable_hash_foreach(base->props->_op_bucket, hash, pos, n, ht)
749 if (HSTR_EQ(&pos->key, &hashed_name)) {
758 dtpx_compile_proplet(struct dtprop_def* proplet)
761 unsigned int acc = 0;
763 for (i = 0; proplet[i].type && i < 10; ++i)
765 proplet[i].acc_sz = acc;
766 acc += proplet[i].cell;
769 if (proplet[i - 1].type && i == 10) {
770 FATAL("invalid proplet: no terminator detected");
773 proplet[i].acc_sz = acc;
777 dtpx_prepare_with(struct dtpropx* propx, struct dtp_val* prop,
778 struct dtprop_def* proplet)
781 bool has_str = false;
783 for (i = 0; proplet[i].type; ++i);
785 propx->proplet = proplet;
786 propx->proplet_len = i;
787 propx->proplet_sz = proplet[i].acc_sz;
793 dtpx_goto_row(struct dtpropx* propx, int row)
797 loc = propx->proplet_sz;
800 if (loc * sizeof(u32_t) >= propx->raw->size) {
804 propx->row_loc = loc;
809 dtpx_next_row(struct dtpropx* propx)
813 loc = propx->row_loc;
814 loc += propx->proplet_sz;
816 if (loc * sizeof(u32_t) >= propx->raw->size) {
820 propx->row_loc = loc;
825 dtpx_extract_at(struct dtpropx* propx,
826 struct dtprop_xval* val, int col)
828 struct dtprop_def* def;
829 union dtp_baseval* raw;
832 if (unlikely(col >= propx->proplet_len)) {
836 def = &propx->proplet[col];
837 enc = &propx->raw->encoded[propx->row_loc + def->acc_sz];
838 raw = (union dtp_baseval*)enc;
840 val->archetype = def;
845 val->u32 = raw->u32_val;
849 val->u64 = raw->u64_val;
854 ptr_t hnd = raw->phandle;
855 val->phandle = dt_resolve_phandle(hnd);
859 val->composite = enc;
870 dtpx_extract_loc(struct dtpropx* propx,
871 struct dtprop_xval* val, int row, int col)
873 ptr_t loc = propx->row_loc;
875 if (!dtpx_goto_row(propx, row))
879 bool r = dtpx_extract_at(propx, val, col);
880 propx->row_loc = loc;
885 dtpx_extract_row(struct dtpropx* propx, struct dtprop_xval* vals, int len)
887 assert(len == propx->proplet_len);
889 for (int i = 0; i < len; i++)
891 if (!dtpx_extract_at(propx, &vals[i], i)) {
908 devtree_obj_root = changeling_spawn(NULL, NULL);
910 owloysius_fetch_init(__init_devtree, on_sysconf);