Merge branch 'master' into isa/arm64
[lunaix-os.git] / lunaix-os / hal / devtree / dt.c
1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/syslog.h>
3 #include <lunaix/owloysius.h>
4
5 #include "devtree.h"
6
7 LOG_MODULE("dtb")
8
9 static morph_t* devtree_obj_root;
10 static struct dt_context dtctx;
11
12 void
13 fdt_load(struct fdt_blob* fdt, ptr_t base)
14 {
15     struct fdt_header* hdr;
16
17     fdt->fdt_base = base;
18
19     hdr = fdt->header;
20     if (hdr->magic != FDT_MAGIC) {
21         FATAL("invalid dtb, unexpected magic: 0x%x, expect: 0x%x", 
22                 hdr->magic, FDT_MAGIC);
23     }
24
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;
28 }
29
30 bool
31 fdt_next_boot_rsvdmem(struct fdt_blob* fdt, fdt_loc_t* loc, 
32                       struct dt_memory_node* mem)
33 {
34     fdt_loc_t current;
35
36     current = *loc;
37
38     if (!current.rsvd_ent->addr && !current.rsvd_ent->addr) {
39         return false;
40     }
41
42     mem->base = current.rsvd_ent->addr;
43     mem->size = current.rsvd_ent->size;
44     mem->type = FDT_MEM_RSVD;
45
46     current.rsvd_ent++;
47     *loc = current;
48
49     return true;
50 }
51
52 fdt_loc_t
53 fdt_next_token(fdt_loc_t loc, int* delta_depth)
54 {
55     int d = 0;
56
57     do {
58         if (fdt_node(loc.token)) {
59             d++;
60             loc.ptr += strlen(loc.node->name) + 1;
61             loc.ptr  = ROUNDUP(loc.ptr, sizeof(int));
62         }
63         else if (fdt_node_end(loc.token)) {
64             d--;
65         }
66         else if (fdt_prop(loc.token)) {
67             loc.ptr   += loc.prop->len + 2 * sizeof(int);
68             loc.ptr    = ROUNDUP(loc.ptr, sizeof(int));
69         }
70
71         loc.token++;
72     } while (fdt_nope(loc.token));
73
74     *delta_depth = d;
75     return loc;
76 }
77
78 bool
79 fdt_next_sibling(fdt_loc_t loc, fdt_loc_t* loc_out)
80 {
81     int depth = 0, new_depth = 0;
82
83     do {
84         loc = fdt_next_token(loc, &new_depth);
85         depth += new_depth;
86     } while (depth > 0);
87
88     *loc_out = loc;
89     return !fdt_node_end(loc.token);
90 }
91
92 fdt_loc_t
93 fdt_descend_into(fdt_loc_t loc) 
94 {
95     fdt_loc_t new_loc;
96     int depth = 0;
97
98     new_loc = fdt_next_token(loc, &depth);
99
100     return depth != 1 ? loc : new_loc;
101 }
102
103 bool
104 fdt_find_prop(const struct fdt_blob* fdt, fdt_loc_t loc, 
105               const char* name, struct dtp_val* val)
106 {
107     char* prop_name;
108
109     loc = fdt_descend_into(loc);
110
111     do
112     {
113         if (!fdt_prop(loc.token)) {
114             continue;
115         }
116
117         prop_name = fdt_prop_key(fdt, loc);
118         
119         if (!streq(prop_name, name)) {
120             continue;
121         }
122         
123         if (likely(val)) {
124             val->encoded = (dt_enc_t)loc.prop->val;
125             val->size    = loc.prop->len;
126         }
127         return true;
128         
129     } while (fdt_next_sibling(loc, &loc));
130
131     return false;
132 }
133
134 bool
135 fdt_memscan_begin(struct fdt_memscan* mscan, const struct fdt_blob* fdt)
136 {
137     struct dtp_val val;
138     fdt_loc_t loc;
139
140     loc  = fdt->root;
141     loc  = fdt_descend_into(loc);
142
143     if (fdt_find_prop(fdt, loc, "#address-cells", &val))
144     {
145         mscan->root_addr_c = val.ref->u32_val;
146     }
147
148     if (fdt_find_prop(fdt, loc, "#size-cells", &val))
149     {
150         mscan->root_size_c = val.ref->u32_val;
151     }
152
153     mscan->loc = loc;
154     mscan->node_type = FDT_MEM_FREE;
155 }
156
157 #define get_size(mscan, val)    \
158     (mscan->root_size_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val)
159
160 #define get_addr(mscan, val)    \
161     (mscan->root_addr_c == 1 ? (val)->ref->u32_val : (val)->ref->u64_val)
162
163 bool
164 fdt_memscan_nextnode(struct fdt_memscan* mscan, struct fdt_blob* fdt)
165 {
166     char* prop_name;
167
168     struct dtp_val val, reg_val;
169     fdt_loc_t loc, next;
170     struct dtpropi dtpi;
171     bool has_reg = false, found = false;
172
173     next = mscan->loc;
174
175 restart:
176     do
177     {
178         loc = next;
179         
180         if (!fdt_node(loc.token))
181             continue;
182
183         if (mscan->node_type != FDT_MEM_FREE) {
184             found = true;
185             continue;
186         }
187
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);
192             continue;
193         }
194
195         if (!fdt_find_prop(fdt, loc, "device_type", &val))
196             continue;
197
198         if (!streq(val.str_val, "memory"))
199             continue;
200
201         found = true;
202     } while (fdt_next_sibling(loc, &next) && !found);
203
204     if (found) goto _found;
205
206     // emerged from /reserved-memory, resume walking for /memory
207     if (mscan->node_type != FDT_MEM_FREE) {
208         mscan->node_type = FDT_MEM_FREE;
209         goto restart;
210     }
211
212     return false;
213
214 _found:
215
216     dtpi_init_empty(&mscan->regit);
217     mscan->found = loc;
218     mscan->loc   = next;
219
220     has_reg = fdt_find_prop(fdt, loc, "reg", &val);
221     if (mscan->node_type == FDT_MEM_RSVD) {
222         goto do_rsvd_child;
223     }
224
225     if (!has_reg)
226     {
227         WARN("malformed memory node");
228         goto restart;
229     }
230
231     dtpi_init(&mscan->regit, &val);
232
233     return true;
234
235 do_rsvd_child:
236
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);
239
240     if (has_reg)
241     {
242         dtpi_init(&mscan->regit, &val);
243         mscan->node_type = FDT_MEM_RSVD;
244         return true;
245     }
246     
247     if (!fdt_find_prop(fdt, loc, "size", &val)) 
248     {
249         WARN("malformed reserved memory child node");
250         goto restart;
251     }
252     
253     mscan->node_type = FDT_MEM_RSVD_DYNAMIC;
254     mscan->node_attr.total_size = get_size(mscan, &val);
255
256     if (fdt_find_prop(fdt, loc, "alignment", &val)) {
257         mscan->node_attr.alignment = get_size(mscan, &val);
258     }
259
260     if (fdt_find_prop(fdt, loc, "alloc-ranges", &val)) {
261         dtpi_init(&mscan->regit, &val);
262     }
263
264     return true;
265 }
266
267 bool
268 fdt_memscan_nextrange(struct fdt_memscan* mscan, struct dt_memory_node* mem)
269 {
270     struct dtp_val val;
271
272     if (dtpi_is_empty(&mscan->regit)) {
273         return false;
274     }
275
276     if (!dtpi_has_next(&mscan->regit)) {
277         return false;
278     }
279
280     if (dtpi_next_val(&mscan->regit, &val, mscan->root_addr_c)) {
281         mem->base = get_addr(mscan, &val);
282     }
283
284     if (dtpi_next_val(&mscan->regit, &val, mscan->root_size_c)) {
285         mem->size = get_size(mscan, &val);
286     }
287
288     mem->type = mscan->node_type;
289     
290     if (mem->type == FDT_MEM_RSVD_DYNAMIC) {
291         mem->dyn_alloc_attr = mscan->node_attr;
292     }
293
294     return true;
295 }
296
297 static bool
298 __parse_stdbase_prop(struct fdt_blob* fdt, fdt_loc_t loc, 
299                      struct dtn_base* node)
300 {
301     if (propeq(fdt, loc, "compatible")) {
302         __mkprop_ptr(loc, &node->compat);
303     } 
304
305     else if (propeq(fdt, loc, "phandle")) {
306         node->phandle = __prop_getu32(loc);
307     }
308     
309     else if (propeq(fdt, loc, "#address-cells")) {
310         node->addr_c = (char)__prop_getu32(loc);
311     } 
312     
313     else if (propeq(fdt, loc, "#size-cells")) {
314         node->sz_c = (char)__prop_getu32(loc);
315     } 
316     
317     else if (propeq(fdt, loc, "#interrupt-cells")) {
318         node->intr_c = (char)__prop_getu32(loc);
319     } 
320     
321     else if (propeq(fdt, loc, "status")) {
322         char peek = loc.prop->val_str[0];
323         if (peek == 'o') {
324             node->status = STATUS_OK;
325         }
326         else if (peek == 'r') {
327             node->status = STATUS_RSVD;
328         }
329         else if (peek == 'd') {
330             node->status = STATUS_DISABLE;
331         }
332         else if (peek == 'f') {
333             node->status = STATUS_FAIL;
334         }
335     }
336
337     else {
338         return false;
339     }
340
341     return true;
342 }
343
344 static bool
345 __parse_stdnode_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node)
346 {
347     if (propeq(fdt, loc, "reg")) {
348         __mkprop_ptr(loc, &node->reg);
349     }
350
351     else if (propeq(fdt, loc, "ranges")) {
352         __mkprop_ptr(loc, &node->ranges);
353     }
354
355     else if (propeq(fdt, loc, "dma-ranges")) {
356         __mkprop_ptr(loc, &node->dma_ranges);
357     }
358
359     else {
360         return false;
361     }
362
363     return true;
364 }
365
366 static bool
367 __parse_stdflags(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node)
368 {
369     if (propeq(fdt, loc, "dma-coherent")) {
370         node->dma_coherent = true;
371     }
372
373     else if (propeq(fdt, loc, "dma-noncoherent")) {
374         node->dma_ncoherent = true;
375     }
376
377     else if (propeq(fdt, loc, "interrupt-controller")) {
378         node->intr_controll = true;
379     }
380
381     else {
382         return false;
383     }
384
385     return true;
386 }
387
388 static inline void
389 __dt_node_set_name(struct dtn* node, const char* name)
390 {
391     changeling_setname(&node->mobj, name);
392 }
393
394 static inline void
395 __init_prop_table(struct dtn_base* node)
396 {
397     struct dtp_table* propt;
398
399     propt = valloc(sizeof(*propt));
400     hashtable_init(propt->_op_bucket);
401
402     node->props = propt;
403 }
404
405 #define prop_table_add(node, prop)                                             \
406             hashtable_hash_in( (node)->props->_op_bucket,                      \
407                               &(prop)->ht, (prop)->key.hash);
408
409 static void
410 __parse_other_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node)
411 {
412     struct dtp* prop;
413     const char* key;
414     unsigned int hash;
415
416     prop = valloc(sizeof(*prop));
417     key  = fdt_prop_key(fdt, loc);
418
419     prop->key = HSTR(key, strlen(key));
420     __mkprop_ptr(loc, &prop->val);
421
422     hstr_rehash(&prop->key, HSTR_FULL_HASH);
423
424     prop_table_add(node, prop);
425 }
426
427 static void
428 __fill_node(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node)
429 {
430     if (__parse_stdflags(fdt, loc, &node->base)) {
431         return;
432     }
433
434     if (__parse_stdbase_prop(fdt, loc, &node->base)) {
435         return;
436     }
437
438     if (__parse_stdnode_prop(fdt, loc, node)) {
439         return;
440     }
441
442     if (parse_stdintr_prop(fdt, loc, &node->intr)) {
443         return;
444     }
445
446     __parse_other_prop(fdt, loc, &node->base);
447 }
448
449 static inline void
450 __set_parent(struct dtn_base* parent, struct dtn_base* node)
451 {
452     morph_t* parent_obj;
453     
454     parent_obj   = devtree_obj_root;
455     node->parent = parent;
456     
457     if (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);
462     }
463
464     changeling_attach(parent_obj, dt_mobj(node));
465 }
466
467 static inline void
468 __init_node_regular(struct dtn* node)
469 {
470     __init_prop_table(&node->base);
471     changeling_morph_anon(NULL, node->mobj, dt_morpher);
472  
473     node->intr.parent_hnd = PHND_NULL;
474 }
475
476 static void
477 __expand_extended_intr(struct dtn_intr* intrupt)
478 {
479     struct dtpropi it;
480     struct dtp_val  arr;
481     struct dtn *domain;
482     struct dtspec_intr* ispec;
483     int nr_intrs = 0;
484
485     if (!intrupt->extended) {
486         nr_intrs  = intrupt->raw_ispecs.size / sizeof(u32_t);
487         nr_intrs /= intrupt->parent->base.intr_c; 
488         goto done;
489     }
490
491     arr = intrupt->raw_ispecs;
492
493     llist_init_head(&intrupt->ext_ispecs);
494     
495     dtpi_init(&it, &arr);
496
497     while(dtpi_has_next(&it)) 
498     {
499         domain = dtpi_next_hnd(&it);
500
501         if (!domain) {
502             WARN("(intr_extended) malformed phandle");
503             continue;
504         }
505
506         ispec = valloc(sizeof(*ispec));
507         
508         ispec->domain = domain;
509         dtpi_next_val(&it, &ispec->val, domain->base.intr_c);
510
511         llist_append(&intrupt->ext_ispecs, &ispec->ispecs);
512         nr_intrs++;
513     };
514
515 done:
516     intrupt->nr_intrs = nr_intrs;
517 }
518
519 static void
520 __resolve_phnd_references()
521 {
522     struct dtn_base *pos, *n;
523     struct dtn *node, *parent, *default_parent;
524     struct dtn_intr* intrupt;
525     dt_phnd_t phnd;
526     
527     llist_for_each(pos, n, &dtctx.nodes, nodes)
528     {
529         node = dtn_from(pos);
530         intrupt = &node->intr;
531
532         if (intrupt->parent_hnd == PHND_NULL) {
533             continue;
534         }
535
536         phnd = intrupt->parent_hnd;
537         default_parent = (struct dtn*)node->base.parent;
538         parent = default_parent;
539
540         if (phnd != PHND_NULL) {
541             parent = dt_resolve_phandle(phnd);
542         }
543
544         if (!parent) {
545             WARN("dtb: (phnd_resolve) malformed phandle: %d", phnd);
546             parent = default_parent;
547         }
548
549         intrupt->parent = parent;
550
551         __expand_extended_intr(intrupt);
552     }
553 }
554
555 static void
556 __resolve_inter_map()
557 {
558     struct dtn_base *pos, *n;
559
560     llist_for_each(pos, n, &dtctx.nodes, nodes)
561     {
562         dt_resolve_interrupt_map(dtn_from(pos));
563     }
564 }
565
566 bool
567 dt_load(ptr_t dtb_dropoff)
568 {
569     llist_init_head(&dtctx.nodes);
570     hashtable_init(dtctx.phnds_table);
571
572     struct fdt_blob *fdt;
573     struct dtn      *node,
574                     *stack[16] = { NULL };
575     
576     int depth = 0, delta = 0, nr_nodes = 0;
577     fdt_loc_t  loc, next_loc;
578
579     fdt = &dtctx.fdt;
580     fdt_load(&dtctx.fdt, dtb_dropoff);
581
582     loc = fdt->root;
583     
584     while (!fdt_eof(loc.token)) 
585     {
586         next_loc = fdt_next_token(loc, &delta);
587
588         if (depth >= 16) {
589             // tree too deep
590             ERROR("strange dtb, too deep to dive.");
591             return false;
592         }
593
594         assert(depth >= 0);
595         node = stack[depth];
596
597         if (fdt_node(loc.token))
598         {
599             assert(!node);
600
601             node = vzalloc(sizeof(struct dtn));
602             __init_node_regular(node);
603             llist_append(&dtctx.nodes, &node->base.nodes);
604
605             __dt_node_set_name(node, loc.node->name);
606
607             if (depth) {
608                 __set_parent(&stack[depth - 1]->base, &node->base);
609             }
610
611             nr_nodes++;
612             stack[depth] = node;
613         }
614
615         else if (depth > 1 && fdt_node_end(loc.token))
616         {
617             stack[depth - 1] = NULL;
618         }
619
620         else if (fdt_prop(loc.token))
621         {
622             node = stack[depth - 1];
623
624             assert(depth && node);
625             __fill_node(fdt, loc, node);
626         }
627
628         depth += delta;
629         loc = next_loc;
630     }
631
632     dtctx.root = stack[0];
633
634     __resolve_phnd_references();
635     __resolve_inter_map();
636
637     INFO("%d nodes loaded.", nr_nodes);
638
639     return true;
640 }
641
642 struct dtn*
643 dt_resolve_phandle(dt_phnd_t phandle)
644 {
645     struct dtn_base *pos, *n;
646     llist_for_each(pos, n, &dtctx.nodes, nodes)
647     {
648         if (pos->phandle == phandle) {
649             return (struct dtn*)pos;
650         }
651     }
652
653     return NULL;
654 }
655
656 static bool
657 __byname_predicate(struct dtn_iter* iter, struct dtn_base* node)
658 {
659     int i = 0;
660     const char* be_matched = HSTR_VAL(node->mobj.name);
661     const char* name = (const char*)iter->closure;
662
663     while (be_matched[i] && name[i])
664     {
665         if (be_matched[i] != name[i]) {
666             return false;
667         }
668
669         i++;
670     }
671
672     return true;
673 }
674
675 void
676 dt_begin_find_byname(struct dtn_iter* iter, 
677               struct dtn* node, const char* name)
678 {
679     dt_begin_find(iter, node, __byname_predicate, name);
680 }
681
682 void
683 dt_begin_find(struct dtn_iter* iter, struct dtn* node, 
684               node_predicate_t pred, void* closure)
685 {
686     node = node ? : (struct dtn*)dtctx.root;
687
688     iter->head = &node->base;
689     iter->matched = NULL;
690     iter->closure = closure;
691     iter->pred = pred;
692
693     morph_t *pos, *n;
694     struct dtn_base* base;
695     changeling_for_each(pos, n, &node->mobj)
696     {
697         base = &changeling_reveal(pos, dt_morpher)->base;
698         if (pred(iter, base)) {
699             iter->matched = base;
700             break;
701         }
702     }
703 }
704
705 bool
706 dt_find_next(struct dtn_iter* iter,
707              struct dtn_base** matched)
708 {
709     if (!dt_found_any(iter)) {
710         return false;
711     }
712
713     struct dtn *node;
714     morph_t *pos, *head;
715
716     head = dt_mobj(iter->head);
717     pos  = dt_mobj(iter->matched);
718     *matched = iter->matched;
719
720     while (&pos->sibs != &head->subs)
721     {
722         pos = list_next(pos, morph_t, sibs);
723         node = changeling_reveal(pos, dt_morpher);
724
725         if (!iter->pred(iter, &node->base)) {
726             continue;
727         }
728
729         iter->matched = &node->base;
730         return true;
731     }
732
733     return false;
734 }
735
736 struct dtp_val*
737 dt_getprop(struct dtn_base* base, const char* name)
738 {
739     struct hstr hashed_name;
740     struct dtp *pos, *n;
741     unsigned int hash;
742
743     hashed_name = HSTR(name, strlen(name));
744     hstr_rehash(&hashed_name, HSTR_FULL_HASH);
745     hash = hashed_name.hash;
746
747     hashtable_hash_foreach(base->props->_op_bucket, hash, pos, n, ht)
748     {
749         if (HSTR_EQ(&pos->key, &hashed_name)) {
750             return &pos->val;
751         }
752     }
753
754     return NULL;
755 }
756
757 void
758 dtpx_compile_proplet(struct dtprop_def* proplet)
759 {
760     int i;
761     unsigned int acc = 0;
762     
763     for (i = 0; proplet[i].type && i < 10; ++i)
764     {
765         proplet[i].acc_sz = acc;
766         acc += proplet[i].cell;
767     }
768
769     if (proplet[i - 1].type && i == 10) {
770         FATAL("invalid proplet: no terminator detected");
771     }
772
773     proplet[i].acc_sz = acc;
774 }
775
776 void
777 dtpx_prepare_with(struct dtpropx* propx, struct dtp_val* prop,
778                   struct dtprop_def* proplet)
779 {
780     int i;
781     bool has_str = false;
782     
783     for (i = 0; proplet[i].type; ++i);
784
785     propx->proplet = proplet;
786     propx->proplet_len = i;
787     propx->proplet_sz = proplet[i].acc_sz;
788     propx->raw = prop;
789     propx->row_loc = 0;
790 }
791
792 bool
793 dtpx_goto_row(struct dtpropx* propx, int row)
794 {
795     off_t loc;
796
797     loc  = propx->proplet_sz;
798     loc *= row;
799
800     if (loc * sizeof(u32_t) >= propx->raw->size) {
801         return false;
802     }
803
804     propx->row_loc = loc;
805     return true;
806 }
807
808 bool
809 dtpx_next_row(struct dtpropx* propx)
810 {
811     off_t loc;
812
813     loc  = propx->row_loc;
814     loc += propx->proplet_sz;
815
816     if (loc * sizeof(u32_t) >= propx->raw->size) {
817         return false;
818     }
819
820     propx->row_loc = loc;
821     return true;
822 }
823
824 bool
825 dtpx_extract_at(struct dtpropx* propx, 
826                 struct dtprop_xval* val, int col)
827 {
828     struct dtprop_def* def;
829     union dtp_baseval* raw;
830     dt_enc_t enc;
831
832     if (unlikely(col >= propx->proplet_len)) {
833         return false;
834     }
835
836     def = &propx->proplet[col];
837     enc = &propx->raw->encoded[propx->row_loc + def->acc_sz];
838     raw = (union dtp_baseval*)enc;
839
840     val->archetype = def;
841
842     switch (def->type)
843     {
844         case DTP_U32:
845             val->u32 = raw->u32_val;
846             break;
847
848         case DTP_U64:
849             val->u64 = raw->u64_val;
850             break;
851
852         case DTP_PHANDLE:
853         {
854             ptr_t hnd = raw->phandle;
855             val->phandle = dt_resolve_phandle(hnd);
856         } break;
857
858         case DTP_COMPX:
859             val->composite = enc;
860             break;
861         
862         default:
863             break;
864     }
865
866     return true;
867 }
868
869 bool
870 dtpx_extract_loc(struct dtpropx* propx, 
871                  struct dtprop_xval* val, int row, int col)
872 {
873     ptr_t loc = propx->row_loc;
874
875     if (!dtpx_goto_row(propx, row))
876         return false;
877
878     
879     bool r = dtpx_extract_at(propx, val, col);
880     propx->row_loc = loc;
881     return r;
882 }
883
884 bool
885 dtpx_extract_row(struct dtpropx* propx, struct dtprop_xval* vals, int len)
886 {
887     assert(len == propx->proplet_len);
888
889     for (int i = 0; i < len; i++)
890     {
891         if (!dtpx_extract_at(propx, &vals[i], i)) {
892             return false;
893         }
894     }
895     
896     return true;
897 }
898
899 struct dt_context*
900 dt_main_context()
901 {
902     return &dtctx;
903 }
904
905 static void
906 __init_devtree()
907 {
908     devtree_obj_root = changeling_spawn(NULL, NULL);
909 }
910 owloysius_fetch_init(__init_devtree, on_sysconf);