!scripts
!usr
!link
+!tests
!.gitignore
!*.md
* @param node
*/
int
-isrm_bind_dtn(struct dt_intr_node* node);
+isrm_bind_dtn(struct dtn_intr* node);
/**
* @brief Get the handler associated with the given iv
int
-isrm_bind_dtn(struct dt_intr_node* node)
+isrm_bind_dtn(struct dtn_intr* node)
{
fail("not supported");
}
"dt_interrupt.c",
"dt.c",
"dtm.c"
+ "dtspec.c"
])
\ No newline at end of file
#include <klibc/string.h>
static inline bool
-propeq(struct fdt_iter* it, const char* key)
+propeq(struct fdt_blob* fdt, fdt_loc_t loc, const char* key)
{
- return streq(fdtit_prop_key(it), key);
+ return streq(fdt_prop_key(fdt, loc), key);
}
static inline void
-__mkprop_val32(struct fdt_iter* it, struct dt_prop_val* val)
+__mkprop_ptr(fdt_loc_t loc, struct dtp_val* val)
{
- val->u32_val = le(*(u32_t*)&it->prop[1]);
- val->size = le(it->prop->len);
-}
-
-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);
-}
-
-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);
+ val->ptr_val = __ptr(loc.prop->val);
+ val->size = loc.prop->len;
}
static inline u32_t
-__prop_getu32(struct fdt_iter* it)
+__prop_getu32(fdt_loc_t loc)
{
- return le(*(u32_t*)&it->prop[1]);
+ return loc.prop->val[0];
}
bool
-parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node);
-
-bool
-parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node);
+parse_stdintr_prop(struct fdt_blob*, fdt_loc_t, struct dtn_intr*);
#endif /* __LUNAIX_DEVTREE_H */
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 (fdt_prop(current)) {
- break;
+ if (likely(val)) {
+ val->encoded = (dt_enc_t)loc.prop->val;
+ val->size = loc.prop->len;
}
+ return true;
- current++;
-
- } 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;
+
+ 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;
}
-void
-fdt_memrsvd_itbegin(struct fdt_memrsvd_iter* rsvdi,
- struct fdt_header* fdt_hdr)
+#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_memscan_nextnode(struct fdt_memscan* mscan, struct fdt_blob* fdt)
{
- size_t off = le(fdt_hdr->off_mem_rsvmap);
+ char* prop_name;
+
+ 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;
+ }
+
+ return false;
+
+_found:
+
+ dtpi_init_empty(&mscan->regit);
+ mscan->found = loc;
+ mscan->loc = next;
+
+ has_reg = fdt_find_prop(fdt, loc, "reg", &val);
+ if (mscan->node_type == FDT_MEM_RSVD) {
+ goto do_rsvd_child;
+ }
+
+ if (!has_reg)
+ {
+ WARN("malformed memory node");
+ goto restart;
+ }
+
+ dtpi_init(&mscan->regit, &val);
+
+ return true;
+
+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;
+ }
- rsvdi->block =
- offset_t(fdt_hdr, typeof(*rsvdi->block), off);
+ if (!fdt_find_prop(fdt, loc, "size", &val))
+ {
+ WARN("malformed reserved memory child node");
+ goto restart;
+ }
- rsvdi->block = &rsvdi->block[-1];
+ 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;
}
bool
-fdt_memrsvd_itnext(struct fdt_memrsvd_iter* rsvdi)
+fdt_memscan_nextrange(struct fdt_memscan* mscan, struct dt_memory_node* mem)
{
- struct fdt_memrsvd_ent* ent;
+ struct dtp_val val;
- ent = rsvdi->block;
- if (!ent) {
+ if (dtpi_is_empty(&mscan->regit)) {
return false;
}
- rsvdi->block++;
+ if (!dtpi_has_next(&mscan->regit)) {
+ return false;
+ }
- return ent->addr || ent->size;
-}
+ if (dtpi_next_val(&mscan->regit, &val, mscan->root_addr_c)) {
+ mem->base = get_addr(mscan, &val);
+ }
-void
-fdt_memrsvd_itend(struct fdt_memrsvd_iter* rsvdi)
-{
- rsvdi->block = NULL;
+ if (dtpi_next_val(&mscan->regit, &val, mscan->root_size_c)) {
+ mem->size = get_size(mscan, &val);
+ }
+
+ mem->type = mscan->node_type;
+
+ if (mem->type == FDT_MEM_RSVD_DYNAMIC) {
+ mem->dyn_alloc_attr = mscan->node_attr;
+ }
+
+ return true;
}
static bool
-__parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node)
+__parse_stdbase_prop(struct fdt_blob* fdt, fdt_loc_t loc,
+ struct dtn_base* node)
{
- struct fdt_prop* prop;
-
- prop = it->prop;
-
- if (propeq(it, "compatible")) {
- __mkprop_ptr(it, &node->compat);
+ if (propeq(fdt, loc, "compatible")) {
+ __mkprop_ptr(loc, &node->compat);
}
- else if (propeq(it, "phandle")) {
- node->phandle = __prop_getu32(it);
+ 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;
}
}
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);
- }
-
- else if (propeq(it, "virtual-reg")) {
- __mkprop_ptr(it, &node->vreg);
+ if (propeq(fdt, loc, "reg")) {
+ __mkprop_ptr(loc, &node->reg);
}
- else if (propeq(it, "ranges")) {
- __mkprop_ptr(it, &node->ranges);
+ else if (propeq(fdt, loc, "ranges")) {
+ __mkprop_ptr(loc, &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 {
}
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;
}
}
static inline void
-__dt_node_set_name(struct dt_node_base* node, const char* name)
+__dt_node_set_name(struct dtn* node, const char* name)
{
changeling_setname(&node->mobj, name);
}
static inline void
-__init_prop_table(struct dt_node_base* node)
+__init_prop_table(struct dtn_base* node)
{
- struct dt_prop_table* propt;
+ struct dtp_table* propt;
propt = valloc(sizeof(*propt));
hashtable_init(propt->_op_bucket);
+
+ node->props = propt;
}
#define prop_table_add(node, prop) \
&(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);
}
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);
-}
-
-static void
-__fill_root(struct fdt_iter* it, struct dt_root* node)
-{
- if (__parse_stdflags(it, &node->base)) {
- return;
- }
-
- 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];
- }
-
- __parse_other_prop(it, &node->base);
+ __parse_other_prop(fdt, loc, &node->base);
}
static inline void
-__init_node(struct dt_node_base* node)
+__set_parent(struct dtn_base* parent, struct dtn_base* node)
{
- morph_t* parent;
-
- parent = devtree_obj_root;
- if (node->parent) {
- parent = node->mobj.parent;
- node->_std = node->parent->_std;
+ morph_t* parent_obj;
+
+ 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);
}
- __init_prop_table(node);
- changeling_morph_anon(parent, node->mobj, dt_morpher);
+ 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);
- if (!master) {
- WARN("dtb: (intr_extended) malformed phandle: %d", phnd);
+ while(dtpi_has_next(&it))
+ {
+ domain = dtpi_next_hnd(&it);
+
+ 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) {
parent = default_parent;
}
- intrupt->parent = &parent->intr;
+ intrupt->parent = parent;
__expand_extended_intr(intrupt);
}
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);
- __init_node_regular((struct dt_node*)node);
+ node = vzalloc(sizeof(struct dtn));
+ __init_node_regular(node);
+ llist_append(&dtctx.nodes, &node->base.nodes);
- llist_append(&dtctx.nodes, &node->nodes);
+ __dt_node_set_name(node, loc.node->name);
+
+ if (depth) {
+ __set_parent(&stack[depth - 1]->base, &node->base);
}
- __dt_node_set_name(node, (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;
+ 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;
}
}
}
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 = HSTR_VAL(node->mobj.name);
}
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->pred = pred;
morph_t *pos, *n;
- struct dt_node_base* base;
+ struct dtn_base* base;
changeling_for_each(pos, n, &node->mobj)
{
base = &changeling_reveal(pos, dt_morpher)->base;
}
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 *node;
+ struct dtn *node;
morph_t *pos, *head;
head = dt_mobj(iter->head);
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));
return NULL;
}
+void
+dtpx_compile_proplet(struct dtprop_def* proplet)
+{
+ int i;
+ unsigned int acc = 0;
+
+ for (i = 0; proplet[i].type && i < 10; ++i)
+ {
+ proplet[i].acc_sz = acc;
+ acc += proplet[i].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()
{
#include "devtree.h"
#include <lunaix/mm/valloc.h>
-
#include <klibc/string.h>
-static struct dt_intr_map*
-__get_map(struct dt_intr_node* node)
-{
- if (!node->map) {
- node->map = valloc(sizeof(struct dt_intr_map));
-
- node->map->resolved = false;
- llist_init_head(&node->map->mapent);
-
- INTR_TO_DTNODE(node)->base.intr_neuxs = true;
- }
-
- return node->map;
-}
-
-static void
-__prepare_key(struct dt_intr_mapkey* key,
- dt_enc_t key_raw, unsigned int keylen)
+static int
+__ispec_sz(struct dtn* node)
{
- *key = (struct dt_intr_mapkey) {
- .val = valloc(keylen * sizeof(int)),
- .size = keylen
- };
-
- memcpy(key->val, key_raw, keylen * sizeof(int));
-}
-
-static inline void
-__destory_key(struct dt_intr_mapkey* key)
-{
- vfree(key->val);
+ return node->base.intr_c + node->base.addr_c;
}
-static inline unsigned int
-__interrupt_keysize(struct dt_node_base* base)
+static struct dtp_val*
+__ispec_mask(struct dtn* node)
{
- return dt_size_cells(base) + base->intr_c;
-}
-
-static void
-__mask_key(struct dt_intr_mapkey* k, struct dt_intr_mapkey* mask)
-{
- for (unsigned int i = 0; i < k->size; i++)
- {
- k->val[i] &= mask->val[i];
- }
-}
-
-static bool
-__compare_key(struct dt_intr_mapkey* k1, struct dt_intr_mapkey* k2)
-{
- if (k1->size != k2->size) {
- return false;
- }
-
- for (unsigned int i = 0; i < k1->size; i++)
- {
- if (k1->val[i] != k2->val[i]) {
- return false;
- }
- }
-
- return true;
-}
-
-static struct dt_node_base*
-__get_connected_nexus(struct dt_node_base* base)
-{
- struct dt_node_base* current;
-
- current = base;
- while (current && !current->intr_neuxs) {
- current = current->parent;
- }
-
- return current;
+ return dt_getprop(&node->base, "interrupt-map-mask");
}
void
-dt_resolve_interrupt_map(struct dt_node* node)
+dt_resolve_interrupt_map(struct dtn* node)
{
- struct dt_intr_node* inode;
- struct dt_intr_map* imap;
- struct dt_prop_iter iter;
-
- struct dt_intr_mapent *ent;
-
- unsigned int keysize, parent_keysize;
- unsigned int advance;
- dt_phnd_t parent_hnd;
+ struct dtp_val* map;
+ struct dtspec_create_ops ops = {};
- inode = &node->intr;
- if (likely(!inode->map)) {
+ ops.child_keysz = __ispec_sz;
+ ops.parent_keysz = __ispec_sz;
+ ops.get_mask = __ispec_mask;
+
+ map = dt_getprop(&node->base, "interrupt-map");
+ if (likely(!map)) {
return;
}
- imap = inode->map;
- keysize = __interrupt_keysize(&node->base);
-
- __prepare_key(&imap->key_mask, imap->raw_mask.encoded, keysize);
-
- dt_decode(&iter, &node->base, &imap->raw, 1);
-
- advance = 0;
- do
- {
- advance = keysize;
- ent = valloc(sizeof(*ent));
-
- __prepare_key(&ent->key, iter.prop_loc, advance);
- __mask_key(&ent->key, &imap->key_mask);
-
- parent_hnd = dtprop_to_phnd(dtprop_extract(&iter, advance));
- ent->parent = &dt_resolve_phandle(parent_hnd)->base;
-
- advance++;
- parent_keysize = __interrupt_keysize(ent->parent);
-
- ent->parent_props.encoded = dtprop_extract(&iter, advance);
- ent->parent_props.size = parent_keysize;
-
- advance += parent_keysize;
-
- llist_append(&imap->mapent, &ent->ents);
-
- } while (dtprop_next_n(&iter, advance));
-
- imap->resolved = true;
+ node->intr.map = dtspec_create(node, map, &ops);
}
-struct dt_prop_val*
-dt_resolve_interrupt(struct dt_node* node)
+struct dtn*
+dt_interrupt_at(struct dtn* node, int idx, struct dtp_val* int_spec)
{
- struct dt_node_base* nexus;
- struct dt_intr_node* i_nexus, *i_node;
- struct dt_intr_mapkey key;
- unsigned int keylen;
+ int int_cells;
+ dt_enc_t raw_specs;
+ struct dtn_intr* intr;
+ struct dtn* intr_domain;
- if (!node->intr.intr.valid) {
+ intr = &node->intr;
+ if (!intr->valid || idx >= intr->nr_intrs) {
return NULL;
}
-
- nexus = __get_connected_nexus(&node->base);
- i_nexus = &BASE_TO_DTNODE(nexus)->intr;
- i_node = &node->intr;
-
- if (!nexus) {
- return &i_node->intr.arr;
- }
-
- keylen = __interrupt_keysize(nexus);
- key = (struct dt_intr_mapkey) {
- .val = valloc(keylen * sizeof(int)),
- .size = keylen
- };
-
- memcpy( key.val,
- node->reg.encoded, dt_addr_cells(nexus) * sizeof(int));
- memcpy(&key.val[dt_addr_cells(nexus)],
- i_node->intr.arr.encoded, nexus->intr_c * sizeof(int));
-
- __mask_key(&key, &i_nexus->map->key_mask);
+ if (!intr->extended) {
+ intr_domain = intr->parent;
+ int_cells = intr_domain->base.intr_c;
+
+ raw_specs = &intr->raw_ispecs.encoded[int_cells * idx];
+ dtp_val_set(int_spec, raw_specs, int_cells);
- struct dt_intr_mapent *pos, *n;
+ return intr_domain;
+ }
- llist_for_each(pos, n, &i_nexus->map->mapent, ents) {
- if (__compare_key(&pos->key, &key))
- {
- __destory_key(&key);
- return &pos->parent_props;
+ struct dtspec_intr *p, *n;
+ llist_for_each(p, n, &intr->ext_ispecs, ispecs)
+ {
+ if (!(idx--)) {
+ *int_spec = p->val;
+ return p->domain;
}
}
- __destory_key(&key);
return NULL;
}
bool
-parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node)
+parse_stdintr_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_intr* node)
{
- struct dt_intr_map* map;
-
- if (propeq(it, "interrupt-map")) {
- map = __get_map(node);
- __mkprop_ptr(it, &map->raw);
- }
-
- else if (propeq(it, "interrupt-map-mask")) {
- map = __get_map(node);
- __mkprop_ptr(it, &map->raw_mask);
- }
-
- else if (propeq(it, "interrupt-parent")) {
- node->parent_hnd = __prop_getu32(it);
+ if (propeq(fdt, loc, "interrupt-parent")) {
+ node->parent_hnd = __prop_getu32(loc);
}
- else if (propeq(it, "interrupt-extended")) {
- node->intr.extended = true;
- __mkprop_ptr(it, &node->intr.arr);
+ else if (propeq(fdt, loc, "interrupts-extended")) {
+ node->extended = true;
+ __mkprop_ptr(loc, &node->raw_ispecs);
}
- else if (!node->intr.extended && propeq(it, "interrupts")) {
- node->intr.valid = true;
- __mkprop_ptr(it, &node->intr.arr);
+ else if (!node->extended && propeq(fdt, loc, "interrupts")) {
+ __mkprop_ptr(loc, &node->raw_ispecs);
}
else {
return false;
}
+ node->valid = true;
return true;
}
\ No newline at end of file
}
static struct device_meta*
-__try_create_categorical(struct dt_node_base *p)
+__try_create_categorical(struct dtn_base *p)
{
if (!p) return NULL;
}
static bool
-compat_matched(struct dtm_driver_record* rec, struct dt_node_base *base)
+compat_matched(struct dtm_driver_record* rec, struct dtn_base *base)
{
const char *compat;
struct dtm_driver_info *p, *n;
const char *name;
struct dt_context* dtctx;
struct dtm_driver_record* rec;
- struct dt_node_base *p, *n;
+ struct dtn_base *p, *n;
dtctx = dt_main_context();
--- /dev/null
+#include "devtree.h"
+#include <lunaix/mm/valloc.h>
+
+#define key_mkwr(key) \
+ (struct dtspec_key*)(key)
+#define call_op(dtn, ops, name) \
+ ((ops)->name ? (ops)->name(dtn) : NULL)
+
+struct dtspec_map*
+dtspec_create(struct dtn* node, struct dtp_val* map,
+ const struct dtspec_create_ops* ops)
+{
+ struct dtpropi it;
+ struct dtspec_map* spec;
+ struct dtspec_mapent* ent;
+ struct dtp_val val = {}, *field;
+ int keysz, p_keysz;
+
+ assert(ops->child_keysz);
+ assert(ops->parent_keysz);
+
+ keysz = ops->child_keysz(node);
+ spec = vzalloc(sizeof(*spec));
+
+ field = call_op(node, ops, get_mask);
+ if (field) {
+ dtp_speckey(key_mkwr(&spec->mask), field);
+ }
+
+ field = call_op(node, ops, get_passthru);
+ if (field) {
+ dtp_speckey(key_mkwr(&spec->pass_thru), field);
+ }
+
+ llist_init_head(&spec->ents);
+
+ dtpi_init(&it, map);
+ while (dtpi_has_next(&it))
+ {
+ ent = vzalloc(sizeof(*ent));
+
+ dtpi_next_val(&it, &val, keysz);
+ dtp_speckey(key_mkwr(&ent->child_spec), &val);
+
+ ent->parent = dtpi_next_hnd(&it);
+ p_keysz = ops->parent_keysz(ent->parent);
+
+ dtpi_next_val(&it, &val, p_keysz);
+ dtp_speckey(key_mkwr(&ent->parent_spec), &val);
+
+ changeling_ref(dt_mobj(ent->parent));
+ llist_append(&spec->ents, &ent->ents);
+ }
+
+ return spec;
+}
+
+static bool
+__try_match(struct dtspec_key* given, struct dtspec_key* against)
+{
+ for (unsigned int i = 0; i < given->size; i++)
+ {
+ if (given->val[i] != against->val[i])
+ return false;
+ }
+
+ return true;
+}
+
+struct dtspec_mapent*
+dtspec_lookup(struct dtspec_map* map, struct dtspec_key* key)
+{
+ struct dtspec_mapent *pos, *n;
+ struct dtspec_key scratch = {};
+
+ dtspec_cpykey(&scratch, key);
+ dtspec_applymask(map, &scratch);
+
+ llist_for_each(pos, n, &map->ents, ents)
+ {
+ if (__try_match(&scratch, &pos->child_spec))
+ {
+ dtspec_freekey(&scratch);
+ return pos;
+ }
+ }
+
+ dtspec_freekey(&scratch);
+ return NULL;
+}
+
+void
+dtspec_applymask(struct dtspec_map* map, struct dtspec_key* key)
+{
+ for (unsigned int i = 0; i < map->mask.size; i++)
+ {
+ key->val[i] &= map->mask.val[i];
+ }
+}
+
+void
+dtspec_free(struct dtspec_map* map)
+{
+ struct dtspec_mapent *pos, *n;
+
+ llist_for_each(pos, n, &map->ents, ents)
+ {
+ changeling_unref(dt_mobj(pos->parent));
+ vfree(pos);
+ }
+
+ vfree(map);
+}
+
+void
+dtspec_cpykey(struct dtspec_key* dest, struct dtspec_key* src)
+{
+ if (dtspec_nullkey(src)) {
+ return;
+ }
+
+ int sz = sizeof(int) * src->size;
+
+ dest->val = valloc(sz);
+ dest->size = src->size;
+ memcpy(dest->val, src->val, sz);
+}
+
+void
+dtspec_freekey(struct dtspec_key* key)
+{
+ if (dtspec_nullkey(key)) {
+ return;
+ }
+
+ vfree(key->val);
+ key->size = 0;
+}
\ No newline at end of file
#include <lunaix/ds/llist.h>
#include <lunaix/ds/hstr.h>
#include <lunaix/ds/hashtable.h>
-#include <lunaix/boot_generic.h>
#include <lunaix/changeling.h>
#include <klibc/string.h>
-#define le(v) ((((v) >> 24) & 0x000000ff) |\
- (((v) << 8) & 0x00ff0000) |\
- (((v) >> 8) & 0x0000ff00) |\
- (((v) << 24) & 0xff000000))
-
-#define le64(v) (((u64_t)le(v & 0xffffffff) << 32) | le(v >> 32))
-
-#define be(v) ((((v) << 24) & 0x000000ff) |\
- (((v) >> 8) & 0x00ff0000) |\
- (((v) << 8) & 0x0000ff00) |\
- (((v) >> 24) & 0xff000000))
-
-#define FDT_MAGIC be(0xd00dfeed)
-#define FDT_NOD_BEGIN be(0x00000001)
-#define FDT_NOD_END be(0x00000002)
-#define FDT_PROP be(0x00000003)
-#define FDT_NOP be(0x00000004)
-#define FDT_END be(0x00000009)
+#define FDT_MAGIC 0xd00dfeedU
+#define FDT_NOD_BEGIN 0x00000001U
+#define FDT_NOD_END 0x00000002U
+#define FDT_PROP 0x00000003U
+#define FDT_NOP 0x00000004U
+#define FDT_END 0x00000009U
#define STATUS_OK 0
#define STATUS_DISABLE 1
#define STATUS_RSVD 2
#define STATUS_FAIL 3
+#define PHND_NULL ((dt_phnd_t)-1)
-typedef unsigned int* dt_enc_t;
-typedef unsigned int dt_phnd_t;
+/////////////////////////////////
+/// DT Primitives
+/////////////////////////////////
-struct dt_node_base;
-struct dt_node_iter;
-typedef bool (*node_predicate_t)(struct dt_node_iter*, struct dt_node_base*);
+typedef unsigned int* dt_enc_t;
+typedef unsigned int dt_phnd_t;
+struct dtn_base;
+struct dtn_iter;
+typedef bool (*node_predicate_t)(struct dtn_iter*, struct dtn_base*);
-#define PHND_NULL ((dt_phnd_t)-1)
+union dtp_baseval
+{
+ u32_t u32_val;
+ u64_t u64_val;
+ dt_phnd_t phandle;
+ u32_t raw[0];
+} _be;
+
+struct dtp_val
+{
+ union
+ {
+ union {
+ const char* str_val;
+ const char* str_lst;
+ };
+ ptr_t ptr_val;
+ dt_enc_t encoded;
+
+ union dtp_baseval* ref;
+ };
+ unsigned int size;
+};
+
+struct dtpropi
+{
+ struct dtp_val prop;
+ off_t loc;
+};
+
+/////////////////////////////////
+/// FDT Constructs
+/////////////////////////////////
struct fdt_header {
u32_t magic;
u32_t boot_cpuid_phys;
u32_t size_dt_strings;
u32_t size_dt_struct;
-};
+} _be;
struct fdt_memrsvd_ent
{
u64_t addr;
u64_t size;
-} align(8);
+} _be align(8);
+
struct fdt_token
{
u32_t token;
-} compact align(4);
+} _be compact align(4);
-struct fdt_node_head
+struct fdt_prop
{
struct fdt_token token;
- char name[0];
+ u32_t len;
+ u32_t nameoff;
+
+ union {
+ u32_t val[0];
+ char val_str[0];
+ } _be;
+} _be compact align(4);
+
+struct fdt_loc
+{
+ union {
+ struct fdt_token *token;
+ struct fdt_prop *prop;
+ struct fdt_memrsvd_ent *rsvd_ent;
+ ptr_t ptr;
+ struct {
+ struct fdt_token token;
+ char name[0];
+ } *node;
+ };
};
+typedef struct fdt_loc fdt_loc_t;
+
-struct fdt_prop
+enum fdt_state {
+ FDT_STATE_START,
+ FDT_STATE_NODE,
+ FDT_STATE_NODE_EXIT,
+ FDT_STATE_PROP,
+ FDT_STATE_END,
+};
+
+enum fdtit_mode {
+ FDT_RSVDMEM,
+ FDT_STRUCT,
+};
+
+enum fdt_mem_type {
+ FDT_MEM_RSVD,
+ FDT_MEM_RSVD_DYNAMIC,
+ FDT_MEM_FREE
+};
+
+struct fdt_rsvdmem_attrs
{
- struct fdt_token token;
- u32_t len;
- u32_t nameoff;
-} compact align(4);
-
-struct dt_prop_val
-{
- struct {
- union
- {
- union {
- const char* str_val;
- const char* str_lst;
- };
- ptr_t ptr_val;
-
- union {
- dt_enc_t encoded;
- dt_phnd_t phandle;
- };
- u32_t u32_val;
-
- u64_t u64_val;
+ size_t total_size;
+ ptr_t alignment;
+
+ union {
+ struct {
+ bool nomap : 1;
+ bool reusable : 1;
};
- unsigned int size;
+ int flags;
+ };
+};
+
+struct dt_memory_node
+{
+ ptr_t base;
+ ptr_t size;
+ enum fdt_mem_type type;
+
+ struct fdt_rsvdmem_attrs dyn_alloc_attr;
+};
+
+struct fdt_rsvd_mem
+{
+ u64_t base;
+ u64_t size;
+} _be align(8);
+
+struct fdt_blob
+{
+ union {
+ struct fdt_header* header;
+ ptr_t fdt_base;
+ };
+
+ fdt_loc_t root;
+ union {
+ const char* str_block;
+ ptr_t str_block_base;
};
+
+
+ union {
+ struct fdt_rsvd_mem* plat_rsvd;
+ ptr_t plat_rsvd_base;
+ };
+};
+
+struct fdt_memscan
+{
+ fdt_loc_t loc;
+ fdt_loc_t found;
+
+ struct dtpropi regit;
+
+ u32_t root_addr_c;
+ u32_t root_size_c;
+ enum fdt_mem_type node_type;
+
+ struct fdt_rsvdmem_attrs node_attr;
+};
+
+struct fdt_memrsvd_iter
+{
+ struct fdt_memrsvd_ent *block;
};
-struct dt_prop
+/////////////////////////////////
+/// DT Construct
+/////////////////////////////////
+
+struct dtp
{
struct hlist_node ht;
struct hstr key;
- struct dt_prop_val val;
+ struct dtp_val val;
};
-struct dt_prop_table
+struct dtp_table
{
union {
struct hbucket other_props[0];
};
};
-struct dt_node_base
+struct dtn_base
{
morph_t mobj;
bool dma_coherent : 1;
bool dma_ncoherent : 1;
bool intr_controll : 1;
- bool intr_neuxs : 1;
};
unsigned int flags;
};
- struct dt_node_base *parent;
- struct llist_header nodes;
+ struct dtn_base *parent;
+ struct llist_header nodes;
- struct dt_prop_val compat;
- dt_phnd_t phandle;
+ struct dtp_val compat;
+ dt_phnd_t phandle;
- struct dt_prop_table* props;
+ struct dtp_table *props;
- void* obj;
- morph_t* binded_dev;
+ morph_t *binded_dev;
};
-struct dt_root
+struct dtspec_key
{
- struct dt_node_base base;
-
- const char* serial;
- const char* chassis;
+ union {
+ union dtp_baseval *bval;
+ unsigned int* val;
+ };
+ unsigned int size;
};
-struct dt_intr_prop;
-
-struct dt_intr_mapkey
+struct dtspec_mapent
{
- unsigned int* val;
- unsigned int size;
+ struct llist_header ents;
+ const struct dtspec_key child_spec;
+
+ struct dtn* parent;
+ const struct dtspec_key parent_spec;
};
-struct dt_intr_mapent
+struct dtspec_map
{
- struct llist_header ents;
+ const struct dtspec_key mask;
+ const struct dtspec_key pass_thru;
- struct dt_intr_mapkey key;
-
- struct dt_node_base* parent;
- struct dt_prop_val parent_props;
+ struct llist_header ents;
};
-struct dt_intr_map
+struct dtspec_intr
{
- struct dt_prop_val raw;
- struct dt_prop_val raw_mask;
+ struct dtn *domain;
- struct dt_intr_mapkey key_mask;
- struct llist_header mapent;
-
- bool resolved;
+ struct llist_header ispecs;
+ struct dtp_val val;
};
-struct dt_intr_node
+struct dtn_intr
{
union {
- struct dt_intr_node *parent;
+ struct dtn *parent;
dt_phnd_t parent_hnd;
};
- struct {
- bool extended;
- bool valid;
- union {
- struct dt_prop_val arr;
- struct llist_header values;
+ union {
+ struct {
+ bool extended : 1;
+ bool valid : 1;
};
- } intr;
+ int flags;
+ };
- struct dt_intr_map* map;
-};
-#define INTR_TO_DTNODE(intr_node) \
- (container_of(intr_node, struct dt_node, intr))
+ union {
+ struct dtp_val raw_ispecs;
+ struct llist_header ext_ispecs;
+ };
+
+ int nr_intrs;
-#define BASE_TO_DTNODE(base_node) \
- (container_of(base_node, struct dt_node, base))
+ struct dtspec_map* map;
+};
-struct dt_node
+struct dtn
{
union {
morph_t mobj;
- struct dt_node_base base;
+ struct dtn_base base;
};
- struct dt_intr_node intr;
+ struct dtn_intr intr;
- struct dt_prop_val reg;
- struct dt_prop_val vreg;
+ struct dtp_val reg;
- struct dt_prop_val ranges;
- struct dt_prop_val dma_ranges;
+ struct dtp_val ranges;
+ struct dtp_val dma_ranges;
};
-#define dt_parent(node) ((node)->base.parent)
-#define dt_morpher morphable_attrs(dt_node, mobj)
-#define dt_mobj(node) (&(node)->mobj)
+#define dt_parent(node) ((node)->base.parent)
+#define dt_morpher morphable_attrs(dtn, mobj)
+#define dt_mobj(node) (&(node)->mobj)
+#define dt_name(node) morpher_name(dt_mobj(node))
+#define dtn_from(base_node) \
+ (container_of(base_node, struct dtn, base))
-struct dt_intr_prop
+struct dtn_iter
{
- struct dt_intr_node *master;
-
- struct llist_header props;
- struct dt_prop_val val;
-};
-
-struct dt_prop_iter
-{
- struct dt_prop_val *prop;
- struct dt_node_base *node;
- dt_enc_t prop_loc;
- dt_enc_t prop_loc_next;
- unsigned int ent_sz;
+ struct dtn_base* head;
+ struct dtn_base* matched;
+ void* closure;
+ node_predicate_t pred;
};
struct dt_context
{
- union {
- ptr_t reloacted_dtb;
- struct fdt_header* fdt;
- };
+ struct fdt_blob fdt;
- struct llist_header nodes;
- struct dt_root *root;
- struct hbucket phnds_table[16];
- const char *str_block;
+ struct llist_header nodes;
+ struct dtn *root;
+ struct hbucket phnds_table[16];
+ const char *str_block;
};
-struct fdt_iter
-{
- union {
- struct fdt_token *pos;
- struct fdt_prop *prop;
- struct fdt_node_head *node_head;
- };
- const char* str_block;
- int depth;
-};
+/////////////////////////////////
+/// FDT Methods
+/////////////////////////////////
-struct fdt_memrsvd_iter
-{
- struct fdt_memrsvd_ent *block;
-};
-
-struct dt_node_iter
-{
- struct dt_node_base* head;
- struct dt_node_base* matched;
- void* closure;
- node_predicate_t pred;
-};
+#define fdt_prop(tok) ((tok)->token == FDT_PROP)
+#define fdt_node(tok) ((tok)->token == FDT_NOD_BEGIN)
+#define fdt_nope(tok) ((tok)->token == FDT_NOP)
+#define fdt_eof(tok) ((tok)->token == FDT_END)
+#define fdt_node_end(tok) \
+ ((tok)->token == FDT_NOD_END || (tok)->token == FDT_END)
+void
+fdt_load(struct fdt_blob* fdt, ptr_t base);
+fdt_loc_t
+fdt_next_token(fdt_loc_t loc, int* depth);
-/****
- * FDT Related
- ****/
+bool
+fdt_next_sibling(fdt_loc_t loc, fdt_loc_t* loc_out);
-#define fdt_prop(tok) ((tok)->token == FDT_PROP)
-#define fdt_node(tok) ((tok)->token == FDT_NOD_BEGIN)
-#define fdt_node_end(tok) ((tok)->token == FDT_NOD_END)
-#define fdt_nope(tok) ((tok)->token == FDT_NOP)
+bool
+fdt_next_boot_rsvdmem(struct fdt_blob*, fdt_loc_t*, struct dt_memory_node*);
-void
-fdt_itbegin(struct fdt_iter* fdti, struct fdt_header* fdt_hdr);
+fdt_loc_t
+fdt_descend_into(fdt_loc_t loc);
-void
-fdt_itend(struct fdt_iter* fdti);
+static inline fdt_loc_t
+fdt_ascend_from(fdt_loc_t loc)
+{
+ while (fdt_next_sibling(loc, &loc));
-bool
-fdt_itnext(struct fdt_iter* fdti);
+ loc.token++;
+ return loc;
+}
-bool
-fdt_itnext_at(struct fdt_iter* fdti, int level);
+bool
+fdt_memscan_begin(struct fdt_memscan*, const struct fdt_blob*);
-void
-fdt_memrsvd_itbegin(struct fdt_memrsvd_iter* rsvdi,
- struct fdt_header* fdt_hdr);
+bool
+fdt_memscan_nextnode(struct fdt_memscan*, struct fdt_blob*);
bool
-fdt_memrsvd_itnext(struct fdt_memrsvd_iter* rsvdi);
+fdt_memscan_nextrange(struct fdt_memscan*, struct dt_memory_node*);
-void
-fdt_memrsvd_itend(struct fdt_memrsvd_iter* rsvdi);
+bool
+fdt_find_prop(const struct fdt_blob*, fdt_loc_t,
+ const char*, struct dtp_val*);
static inline char*
-fdtit_prop_key(struct fdt_iter* fdti)
+fdt_prop_key(struct fdt_blob* fdt, fdt_loc_t loc)
{
- return &fdti->str_block[fdti->prop->nameoff];
+ return &fdt->str_block[loc.prop->nameoff];
}
-/****
- * DT Main Functions: General
- ****/
+/////////////////////////////////
+/// DT General Methods
+/////////////////////////////////
bool
dt_load(ptr_t dtb_dropoff);
-struct dt_node*
+struct dtn*
dt_resolve_phandle(dt_phnd_t phandle);
-struct dt_prop_val*
-dt_getprop(struct dt_node_base* base, const char* name);
-
-struct dt_prop_val*
-dt_resolve_interrupt(struct dt_node* node);
+struct dtp_val*
+dt_getprop(struct dtn_base* base, const char* name);
void
-dt_resolve_interrupt_map(struct dt_node* node);
+dt_resolve_interrupt_map(struct dtn* node);
-static inline unsigned int
-dt_addr_cells(struct dt_node_base* base)
+struct dtn*
+dt_interrupt_at(struct dtn* node, int idx, struct dtp_val* int_spec);
+
+static inline void
+dtp_val_set(struct dtp_val* val, dt_enc_t raw, unsigned cells)
{
- return base->parent ? base->parent->addr_c : base->addr_c;
+ val->encoded = raw;
+ val->size = cells * sizeof(u32_t);
}
-static inline unsigned int
-dt_size_cells(struct dt_node_base* base)
+
+//////////////////////////////////////
+/// DT Methods: Specifier Map
+//////////////////////////////////////
+
+
+struct dtspec_create_ops
{
- return base->parent ? base->parent->sz_c : base->sz_c;
+ int (*child_keysz)(struct dtn*);
+ int (*parent_keysz)(struct dtn*);
+ struct dtp_val* (*get_mask)(struct dtn*);
+ struct dtp_val* (*get_passthru)(struct dtn*);
+};
+
+struct dtspec_map*
+dtspec_create(struct dtn* node, struct dtp_val* map,
+ const struct dtspec_create_ops* ops);
+
+struct dtspec_mapent*
+dtspec_lookup(struct dtspec_map*, struct dtspec_key*);
+
+void
+dtspec_applymask(struct dtspec_map*, struct dtspec_key*);
+
+void
+dtspec_free(struct dtspec_map*);
+
+void
+dtspec_cpykey(struct dtspec_key* dest, struct dtspec_key* src);
+
+void
+dtspec_freekey(struct dtspec_key* key);
+
+static inline bool
+dtspec_nullkey(struct dtspec_key* key)
+{
+ return !key || !key->size;
}
-/****
- * DT Main Functions: Node-finder
- ****/
+//////////////////////////////////////
+/// DT Methods: Node query
+//////////////////////////////////////
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);
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);
static inline void
-dt_end_find(struct dt_node_iter* iter)
+dt_end_find(struct dtn_iter* iter)
{
// currently do nothing, keep only for semantic
}
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);
static inline bool
-dt_found_any(struct dt_node_iter* iter)
+dt_found_any(struct dtn_iter* iter)
{
return !!iter->matched;
}
struct dt_context*
dt_main_context();
+static inline u32_t
+dtp_u32(struct dtp_val* val)
+{
+ return val->ref->u32_val;
+}
-/****
- * DT Main Functions: Node-binding
- ****/
-
-static inline void
-dt_bind_object(struct dt_node_base* base, void* obj)
+static inline u64_t
+dtp_u64(struct dtp_val* val)
{
- base->obj = obj;
+ return val->ref->u64_val;
}
-static inline bool
-dt_has_binding(struct dt_node_base* base)
+static inline void
+dtp_speckey(struct dtspec_key* key, struct dtp_val* prop)
{
- return base->obj != NULL;
+ key->size = prop->size / sizeof(u32_t);
+ key->val = prop->encoded;
}
-#define dt_binding_of(node_base, type) \
- ((type)(node_base)->obj)
+//////////////////////////////////////
+/// DT Prop Extractor
+//////////////////////////////////////
-/****
- * DT Main Functions: Prop decoders
- ****/
+enum dtprop_types
+{
+ DTP_END = 0,
+ DTP_U32,
+ DTP_U64,
+ DTP_PHANDLE,
+ DTP_COMPX,
+};
-static inline void
-dt_decode(struct dt_prop_iter* dtpi, struct dt_node_base* node,
- struct dt_prop_val* val, unsigned int ent_sz)
-{
- *dtpi = (struct dt_prop_iter) {
- .prop = val,
- .node = node,
- .prop_loc = val->encoded,
- .prop_loc_next = val->encoded,
- .ent_sz = ent_sz
- };
-}
+struct dtprop_def
+{
+ unsigned int cell;
+ unsigned int acc_sz;
+ enum dtprop_types type;
+};
-#define dt_decode_reg(dtpi, node, field) \
- dt_decode(dtpi, &(node)->base, &(node)->field, \
- dt_size_cells(&(node)->base) \
- + dt_addr_cells(&(node)->base))
+typedef struct dtprop_def dt_proplet[];
-#define dt_decode_range(dtpi, node, field) \
- dt_decode(dtpi, &(node)->base, &(node)->field, \
- dt_size_cells(&(node)->base) * 2 \
- + dt_addr_cells(&(node)->base))
+struct dtprop_xval
+{
+ union {
+ u32_t u32;
+ ptr_t u64;
+ struct dtn* phandle;
+ union {
+ dt_enc_t composite;
+ union dtp_baseval* cval;
+ };
+ };
+ struct dtprop_def* archetype;
+};
-#define dt_decode_simple(dtpi, prop) \
- dt_decode(dtpi, NULL, prop, 1);
+struct dtpropx
+{
+ const struct dtprop_def* proplet;
+ int proplet_len;
+ int proplet_sz;
-#define dtprop_off(dtpi) \
- (unsigned int)(\
- __ptr(dtpi->prop_loc_next) - __ptr(dtpi->prop->encoded) \
- )
+ struct dtp_val* raw;
+ off_t row_loc;
+};
-#define dtprop_extract(dtpi, off) \
- ( (dt_enc_t) (&(dtpi)->prop_loc[(off)]) )
+#define dtprop_u32 (struct dtprop_def){ 1, 0, DTP_U32 }
+#define dtprop_u64 (struct dtprop_def){ 2, 0, DTP_U64 }
+#define dtprop_handle (struct dtprop_def){ 1, 0, DTP_PHANDLE }
+#define dtprop_compx(cell) (struct dtprop_def){ cell, 0, DTP_COMPX }
+#define dtprop_end (struct dtprop_def){ 0, 0, DTP_END }
+#define dtprop_(type, cell) (struct dtprop_def){ cell, 0, type }
+
+#define dtprop_reglike(base) \
+ ({ \
+ dt_proplet p = { \
+ dtprop_compx(base->addr_c), \
+ dtprop_compx(base->sz_c), \
+ dtprop_end \
+ }; \
+ dt_proplet; \
+ })
+
+#define dtprop_rangelike(node) \
+ ({ \
+ dt_proplet p = { \
+ dtprop_compx(base->addr_c), \
+ dtprop_compx(base->parent->addr_c), \
+ dtprop_compx(base->sz_c), \
+ dtprop_end \
+ }; \
+ dt_proplet; \
+ })
#define dtprop_strlst_foreach(pos, prop) \
for (pos = (prop)->str_lst; \
- pos <= &(prop)->str_lst[(prop)->size]; \
+ pos <= &(prop)->str_lst[(prop)->size - 1]; \
pos = &pos[strlen(pos) + 1])
-static inline bool
-dtprop_next_n(struct dt_prop_iter* dtpi, int n)
-{
- unsigned int off;
+void
+dtpx_compile_proplet(struct dtprop_def* proplet);
- dtpi->prop_loc = dtpi->prop_loc_next;
- dtpi->prop_loc_next += n;
+void
+dtpx_prepare_with(struct dtpropx* propx, struct dtp_val* prop,
+ struct dtprop_def* proplet);
- off = dtprop_off(dtpi);
- return off >= dtpi->prop->size;
-}
+#define dtproplet_compile(proplet) \
+ dtpx_compile_proplet(proplet, \
+ sizeof(proplet) / sizeof(struct dtprop_def))
-static inline bool
-dtprop_prev_n(struct dt_prop_iter* dtpi, int n)
-{
- unsigned int off;
+bool
+dtpx_goto_row(struct dtpropx*, int row);
- off = dtprop_off(dtpi);
- if (!off || off > dtpi->prop->size) {
- return false;
- }
+bool
+dtpx_next_row(struct dtpropx*);
- dtpi->prop_loc = dtpi->prop_loc_next;
- dtpi->prop_loc_next -= n;
+bool
+dtpx_extract_at(struct dtpropx*, struct dtprop_xval*, int col);
- return true;
-}
+bool
+dtpx_extract_loc(struct dtpropx*, struct dtprop_xval*,
+ int row, int col);
-static inline bool
-dtprop_next(struct dt_prop_iter* dtpi)
-{
- return dtprop_next_n(dtpi, dtpi->ent_sz);
-}
+bool
+dtpx_extract_row(struct dtpropx*, struct dtprop_xval*, int len);
-static inline bool
-dtprop_prev(struct dt_prop_iter* dtpi)
-{
- return dtprop_prev_n(dtpi, dtpi->ent_sz);
+static inline u32_t
+dtpx_xvalu32(struct dtprop_xval* val){
+ return val->archetype->type == DTP_COMPX ?
+ val->cval->u32_val : val->u32;
}
-static inline unsigned int
-dtprop_to_u32(dt_enc_t enc_val)
-{
- return le(*enc_val);
+static inline u64_t
+dtpx_xvalu64(struct dtprop_xval* val){
+ return val->archetype->type == DTP_COMPX ?
+ val->cval->u64_val : val->u64;
}
-#define dtprop_to_phnd(enc_val) \
- (dt_phnd_t)dtprop_to_u32(enc_val)
-static inline u64_t
-dtprop_to_u64(dt_enc_t enc_val)
-{
- return le64(*(u64_t*)enc_val);
-}
+//////////////////////////////////////
+/// DT Prop Iterator
+//////////////////////////////////////
-static inline u32_t
-dtprop_u32_at(struct dt_prop_iter* dtpi, int index)
+static inline void
+dtpi_init(struct dtpropi* dtpi, struct dtp_val* val)
{
- return dtprop_to_u32(dtprop_extract(dtpi, index));
+ *dtpi = (struct dtpropi) {
+ .prop = *val,
+ .loc = 0
+ };
}
-static inline u32_t
-dtprop_u64_at(struct dt_prop_iter* dtpi, int index)
+static inline void
+dtpi_init_empty(struct dtpropi* dtpi)
{
- return dtprop_to_u64(dtprop_extract(dtpi, index));
+ *dtpi = (struct dtpropi) {
+ .prop = { 0, 0 },
+ .loc = 0
+ };
}
-static inline dt_enc_t
-dtprop_reg_addr(struct dt_prop_iter* dtpi)
+static inline bool
+dtpi_is_empty(struct dtpropi* dtpi)
{
- return dtprop_extract(dtpi, 0);
+ return !dtpi->prop.size;
}
-static inline ptr_t
-dtprop_reg_nextaddr(struct dt_prop_iter* dtpi)
+static inline bool
+dtpi_has_next(struct dtpropi* dtpi)
{
- ptr_t t;
-
- t = (ptr_t)dtprop_to_u64(dtprop_reg_addr(dtpi));
- dtprop_next_n(dtpi, dt_addr_cells(dtpi->node));
-
- return t;
+ return dtpi->loc < dtpi->prop.size / sizeof(u32_t);
}
-static inline dt_enc_t
-dtprop_reg_len(struct dt_prop_iter* dtpi)
+static inline u32_t
+dtpi_next_u32(struct dtpropi* dtpi)
{
- return dtprop_extract(dtpi, dtpi->node->addr_c);
+ union dtp_baseval* val;
+ val = (union dtp_baseval*)&dtpi->prop.encoded[dtpi->loc++];
+ return val->u32_val;
}
-static inline size_t
-dtprop_reg_nextlen(struct dt_prop_iter* dtpi)
+static inline u64_t
+dtpi_next_u64(struct dtpropi* dtpi)
{
- size_t t;
-
- t = (size_t)dtprop_to_u64(dtprop_reg_len(dtpi));
- dtprop_next_n(dtpi, dt_size_cells(dtpi->node));
-
- return t;
+ union dtp_baseval* val;
+ off_t loc = dtpi->loc;
+ dtpi->loc += 2;
+ val = (union dtp_baseval*)&dtpi->prop.encoded[loc];
+
+ return val->u64_val;
}
-static inline dt_enc_t
-dtprop_range_childbus(struct dt_prop_iter* dtpi)
+static inline struct dtn*
+dtpi_next_hnd(struct dtpropi* dtpi)
{
- return dtprop_extract(dtpi, 0);
+ u32_t phandle;
+ phandle = dtpi_next_u32(dtpi);
+ return dt_resolve_phandle(phandle);
}
-static inline dt_enc_t
-dtprop_range_parentbus(struct dt_prop_iter* dtpi)
+static inline bool
+dtpi_next_val(struct dtpropi* dtpi, struct dtp_val* val, int cells)
{
- return dtprop_extract(dtpi, dt_addr_cells(dtpi->node));
-}
+ if (!dtpi_has_next(dtpi)) {
+ return false;
+ }
-static inline dt_enc_t
-dtprop_range_len(struct dt_prop_iter* dtpi)
-{
- return dtprop_extract(dtpi, dt_addr_cells(dtpi->node) * 2);
+ off_t loc = dtpi->loc;
+ dtp_val_set(val, &dtpi->prop.encoded[loc], cells);
+
+ dtpi->loc += cells;
+ return true;
}
#endif /* __LUNAIX_DEVTREE_H */
#include <lunaix/ds/list.h>
#include <klibc/hash.h>
-typedef struct dt_node* devtree_link_t;
+typedef struct dtn* devtree_link_t;
#define dt_node_morpher morphable_attrs(dt_node, mobj)
-morphable(dt_node),
+morphable(dtn),
morphable(pci_probe),
morphable(device_meta),
#define morphable_attrs(struct_name, field) struct_name, field
#define morphed_ptr(ptr_like) ((morph_t*)__ptr(ptr_like))
#define morpher_uid(mobj) ((mobj)->uid)
+#define morpher_name(mobj) ((mobj)->name.value)
#define __changeling_morph(parent, chlg, name, struct_name, field) \
({ \
#define unreachable __builtin_unreachable()
#define no_inline __attribute__((noinline))
+#define _be __attribute__((scalar_storage_order ("big-endian")))
+#define _le __attribute__((scalar_storage_order ("little-endian")))
+
#define _default _weak
#define msbiti (sizeof(int) * 8 - 1)
#define HSTR_LEN(hstr) ((hstr).len)
#define HSTR_HASH(hstr) ((hstr).hash)
-inline void
+static inline void
hstr_rehash(struct hstr* hash_str, u32_t truncate_to)
{
hash_str->hash = strhash_32(hash_str->value, truncate_to);
clean:
@$(MAKE) $(MKFLAGS) -C usr clean -I $(mkinc_dir)
@$(MAKE) $(MKFLAGS) -C scripts clean -I $(mkinc_dir)
+ @$(MAKE) $(MKFLAGS) -C tests/units clean
@$(MAKE) -f kernel.mk clean -I $(mkinc_dir)
@rm -rf $(kbuild_dir) || exit 1
@rm -rf .builder || exit 1
+
+export CFLAGS=-include $(lbuild_config_h)
+unit-test: $(lbuild_config_h)
+ @$(MAKE) $(MKFLAGS) -C tests/units run
\ No newline at end of file
--- /dev/null
+**/.gdb_history
\ No newline at end of file
--- /dev/null
+#ifndef __COMMON_TEST_BASIC_H
+#define __COMMON_TEST_BASIC_H
+
+#include <stdio.h>
+#include "strutils.h"
+
+struct test_context
+{
+ const char* name;
+
+ struct {
+ union {
+ struct {
+ int passed;
+ int failed;
+ };
+ int countings[2];
+ };
+
+ union {
+ struct {
+ int total_passed;
+ int total_failed;
+ };
+ int total_countings[2];
+ };
+ } stats;
+};
+
+#define fmt_passed "[\x1b[32;49mPASS\x1b[0m]"
+#define fmt_failed "[\x1b[31;49mFAIL\x1b[0m]"
+
+#define active_context \
+ ({ extern struct test_context* __test_ctx; __test_ctx; })
+
+#define _expect(expr, act, exp, type_fmt) \
+ do { \
+ int failed = !(expr); \
+ printf(" @%s:%03d ....... ", __FILE__, __LINE__); \
+ if (failed) \
+ printf(fmt_failed " (expect: " type_fmt ", got: " type_fmt ")\n",\
+ exp, act); \
+ else \
+ printf(fmt_passed "\n"); \
+ active_context->stats.countings[failed]++; \
+ } while(0)
+
+#define new_aspect(expr, exp, act, typefmt) expr, exp, act, typefmt
+
+#define expect(aspect) _expect(aspect)
+
+#define expect_int(a, b) \
+ _expect(a == b, a, b, "%d")
+
+#define expect_uint(a, b) \
+ _expect(a == b, a, b, "%u")
+
+#define expect_long(a, b) \
+ _expect(a == b, a, b, "%ld")
+
+#define expect_ulong(a, b) \
+ _expect(a == b, a, b, "%lu")
+
+#define expect_str(str_a, str_b) \
+ _expect(!strcmp(str_a, str_b), str_a, str_b, "'%s'")
+
+#define expect_notnull(ptr) \
+ _expect(ptr != NULL, "null", "not null", "<%s>")
+
+#define expect_null(ptr) \
+ _expect(ptr == NULL, "not null", "null", "<%s>")
+
+#define expect_true(val) \
+ _expect(val, "false", "true", "<%s>")
+
+#define expect_false(val) \
+ _expect(!val, "true", "false", "<%s>")
+
+#define testcase(name, body) \
+ do { begin_testcase(name); body; end_testcase(); } while(0)
+
+void
+begin_testcase(const char* name);
+
+void
+end_testcase();
+
+void
+run_test(int argc, const char* argv[]);
+
+#endif /* __COMMON_TEST_BASIC_H */
--- /dev/null
+#ifndef __TESTING_STRUTILS_H
+#define __TESTING_STRUTILS_H
+
+extern unsigned long strlen(const char *s);
+extern int strcmp(const char *s1, const char *s2);
+
+#endif /* __LUNAIX_STRUTILS_H */
--- /dev/null
+#include <testing/basic.h>
+#include <stdlib.h>
+
+struct test_context* __test_ctx;
+
+void
+main(int argc, const char* argv[])
+{
+ __test_ctx = calloc(sizeof(*__test_ctx), 1);
+
+ printf("\n");
+
+ run_test(argc, argv);
+
+ printf(
+ "All test done: %d passed, %d failed\n",
+ __test_ctx->stats.total_passed,
+ __test_ctx->stats.total_failed
+ );
+ printf("************\n\n");
+
+ exit(__test_ctx->stats.total_failed > 0);
+}
+
+void
+begin_testcase(const char* name)
+{
+ if (__test_ctx->name) {
+ printf("previous test case: '%s' is still actuive\n", name);
+ exit(1);
+ }
+
+ __test_ctx->name = name;
+ __test_ctx->stats.countings[0] = 0;
+ __test_ctx->stats.countings[1] = 0;
+
+ printf("%s\n", name);
+}
+
+void
+end_testcase()
+{
+ printf("..... passed: %d, failed: %d\n\n",
+ __test_ctx->stats.passed, __test_ctx->stats.failed);
+
+ __test_ctx->stats.total_passed += __test_ctx->stats.passed;
+ __test_ctx->stats.total_failed += __test_ctx->stats.failed;
+ __test_ctx->name = NULL;
+
+}
\ No newline at end of file
--- /dev/null
+include $(LUNAIX_ROOT)/makeinc/utils.mkinc
+
+lunaix-root := $(LUNAIX_ROOT)
+unit-test-root := $(lunaix-root)/tests/units
+test-root := $(lunaix-root)/tests
+test-shared-root := $(test-root)/shared
+
+CFLAGS += -idirafter $(lunaix-root)/includes \
+ -I $(test-root)/includes \
+ -Wno-discarded-qualifiers \
+ -Wno-scalar-storage-order \
+ -g
+
+
+%.o: %.c
+ $(call status,CC,$(@F))
+ @$(CC) $(CFLAGS) -c $< -o $@
+
+
+obj-shared := $(test-shared-root)/framework.o
--- /dev/null
+test
+*.dtb
+*.test
\ No newline at end of file
--- /dev/null
+#ifndef __DTTEST_COMMON_H
+#define __DTTEST_COMMON_H
+
+#define __off_t_defined
+#include "dut/devtree.h"
+
+#include <lunaix/types.h>
+
+bool
+my_load_dtb();
+
+ptr_t
+load_fdt();
+
+#endif /* __DTTEST_COMMON_H */
--- /dev/null
+../../../../kernel/changeling.c
\ No newline at end of file
--- /dev/null
+../../../../hal/devtree/devtree.h
\ No newline at end of file
--- /dev/null
+../../../../hal/devtree/dt.c
\ No newline at end of file
--- /dev/null
+../../../../hal/devtree/dt_interrupt.c
\ No newline at end of file
--- /dev/null
+../../../../hal/devtree/dtspec.c
\ No newline at end of file
--- /dev/null
+#include "common.h"
+
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define MAX_DTB_SZ (2 * 1024 * 1024)
+
+#ifndef TEST_DTBFILE
+#warning "no test dtb file given"
+#define TEST_DTBFILE ""
+#endif
+
+extern void init_export___init_devtree();
+
+ptr_t
+load_fdt()
+{
+ int fd = open(TEST_DTBFILE, O_RDONLY);
+ if (fd == -1) {
+ printf("fail to open: %s, %s\n", TEST_DTBFILE, strerror(errno));
+ return false;
+ }
+
+ ptr_t dtb = (ptr_t)mmap(0,
+ MAX_DTB_SZ,
+ PROT_READ | PROT_WRITE | MAP_POPULATE,
+ MAP_PRIVATE, fd, 0);
+
+ if (dtb == (ptr_t)-1) {
+ printf("fail to map dtb: %s\n", strerror(errno));
+ _exit(1);
+ }
+
+ close(fd);
+ return dtb;
+}
+
+bool
+my_load_dtb()
+{
+ init_export___init_devtree();
+ return dt_load(load_fdt());
+}
\ No newline at end of file
--- /dev/null
+include test_build.mkinc
+
+tests := $(shell cat tests.txt)
+
+obj = dut/dt_interrupt.o \
+ dut/dt.o \
+ dut/dtspec.o \
+ dut/changeling.o \
+
+dtbs := $(addprefix samples/,$(addsuffix .dtb,$(tests)))
+
+tests := $(addsuffix .test,$(tests))
+run_tests := $(addprefix run.,$(tests))
+
+%.dtb: %.dts
+ $(call status,DTC,$^)
+ @dtc -q -I dts -O dtb $^ -o $@
+
+.PHONY: all run clean
+
+load.%.o:: load.c
+ $(call status,CC,$@)
+ @$(CC) $(CFLAGS) -DTEST_DTBFILE=\"samples/$*.dtb\" -c $^ -o $@
+
+%.test: $(obj-shared) $(obj-stubs) $(obj) test-%.o load.%.o
+ $(call status,LD,$@)
+ @$(CC) $^ -o $@
+
+run.%.test: %.test
+ $(call status,RUN,$^)
+ @./$^
+
+all: $(dtbs) $(tests)
+
+run: $(dtbs) $(tests) $(run_tests)
+
+clean:
+ @rm -f *.o $(obj) $(test) $(dtbs)
\ No newline at end of file
--- /dev/null
+/dts-v1/;
+
+/ {
+ compatible = "root";
+ #address-cells = <1>;
+ #size-cells = <2>;
+
+ C1: child@1 {
+ compatible = "child,simple-fields";
+
+ field-str = "field";
+ field-u32 = <32>;
+ field-u64 = <0xf 0x1>;
+ field-strlst = "str1", "str2", "str3";
+ };
+
+ C2: child@2 {
+ compatible = "child,encoded-array";
+ reg = <0x12345 0x1 0x2>;
+
+ mixed_array = <&C1 1 3 5 7>, <&C3 2 4 6 8>;
+ };
+
+ C3: child@3 {
+ compatible = "child,flags";
+ dma-coherent;
+
+ status = "disabled";
+ interrupt-controller;
+ };
+};
\ No newline at end of file
--- /dev/null
+/dts-v1/;
+
+/ {
+ child@1 {
+ prop-child1;
+ };
+
+ child@2 {
+ prop-child2;
+
+ child@21 {
+ prop-child21;
+ };
+ };
+
+ child@3 {
+ prop-child3;
+ };
+};
\ No newline at end of file
--- /dev/null
+/dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ memory@1000000 {
+ device_type = "memory";
+
+ reg = <0x00 0x1000000 0x10000 >,
+ <0x00 0x8000000 0x10000 >,
+ <0x10 0x2000000 0x200000 >;
+ };
+
+ memory@f000000 {
+ device_type = "memory";
+
+ reg = <0x00 0xf000000 0xff000 >;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+
+ hwrom_reserved: hwrom@0 {
+ reg = <0x0 0x0 0x1000000>;
+ no-map;
+ };
+
+ cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0x10000000>;
+ alignment = <0x400000>;
+ alloc-ranges = <0x0 0x10000000 0x10000000>;
+ };
+ };
+};
\ No newline at end of file
--- /dev/null
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <2>;
+
+ C1: child@1 {
+ #interrupt-cells = <3>;
+ C2: child@2 {
+ #address-cells = <4>;
+ C3: child@3 {
+ #size-cells = <0>;
+ #interrupt-cells = <0>;
+ };
+ };
+ };
+};
\ No newline at end of file
--- /dev/null
+/dts-v1/;
+
+/ {
+ #address-cells = <0>;
+ #size-cells = <0>;
+
+ pic: pic@11 {
+ interrupt-controller;
+
+ #interrupt-cells = <2>;
+ };
+
+ pic2: pic@22 {
+ interrupt-controller;
+
+ #interrupt-cells = <1>;
+ };
+
+ pic3: pic@33 {
+ interrupt-controller;
+
+ #interrupt-cells = <4>;
+ };
+
+ dev@1 {
+ interrupt-parent = <&pic>;
+ interrupts = <1 2>;
+ };
+
+ dev@2 {
+ interrupt-parent = <&pic>;
+ interrupts = <1 1>, <1 2>, <2 2>;
+ };
+
+ dev@3 {
+ interrupt-parent = <&pic>;
+ interrupts-extended = <&pic 3 3>, <&pic2 1>, <&pic3 1 2 3 4>;
+ };
+};
\ No newline at end of file
--- /dev/null
+/dts-v1/;
+
+/ {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pic: pic@1 {
+ clock-frequency = <0>;
+ interrupt-controller;
+
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+ pci {
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x11 - PCI slot 1 */
+ 0x8800 0 0 1 &pic 2 1 /* INTA */
+ 0x8800 0 0 2 &pic 3 1 /* INTB */
+ 0x8800 0 0 3 &pic 4 1 /* INTC */
+ 0x8800 0 0 4 &pic 1 1 /* INTD */
+ /* IDSEL 0x12 - PCI slot 2 */
+ 0x9000 0 0 1 &pic 3 1 /* INTA */
+ 0x9000 0 0 2 &pic 4 1 /* INTB */
+ 0x9000 0 0 3 &pic 1 1 /* INTC */
+ 0x9000 0 0 4 &pic 2 1 /* INTD */
+ >;
+ };
+};
\ No newline at end of file
--- /dev/null
+#include "common.h"
+#include <testing/basic.h>
+#include <unistd.h>
+
+static inline struct dtn*
+validate_node(struct dt_context* ctx,
+ const char* name, const char* compat)
+{
+ struct dtn_iter it;
+ struct dtn* node = ctx->root;
+
+
+ dt_begin_find_byname(&it, node, name);
+
+ node = (struct dtn*)it.matched;
+
+ expect_notnull(node);
+ expect_str(node->base.compat.str_val, compat);
+ expect_int(node->base.addr_c, 1);
+ expect_int(node->base.sz_c, 2);
+
+ return node;
+}
+
+static void
+testcase_rootfield(struct dt_context* ctx)
+{
+ struct dtn* node = ctx->root;
+
+ begin_testcase("root");
+
+ expect_str(node->base.compat.str_val, "root");
+ expect_int(node->base.addr_c, 1);
+ expect_int(node->base.sz_c, 2);
+
+ end_testcase();
+}
+
+static void
+testcase_child1(struct dt_context* ctx)
+{
+ struct dtn* node;
+ struct dtp_val* val;
+
+ begin_testcase("trivial-props");
+
+ node = validate_node(ctx, "child@1", "child,simple-fields");
+
+ val = dt_getprop(&node->base, "field-str");
+ expect_notnull(val);
+ expect_str(val->str_val, "field");
+
+ val = dt_getprop(&node->base, "field-u32");
+ expect_notnull(val);
+ expect_int(dtp_u32(val), 32);
+
+ val = dt_getprop(&node->base, "field-u64");
+ expect_notnull(val);
+ expect_ulong(dtp_u64(val), (0xfUL << 32 | 0x1));
+
+ val = dt_getprop(&node->base, "field-strlst");
+ expect_notnull(val);
+
+ char* str;
+ int i = 0;
+ const char *expected[] = {"str1", "str2", "str3"};
+ dtprop_strlst_foreach(str, val) {
+ expect_str(str, expected[i]);
+ i++;
+ }
+
+ end_testcase();
+}
+
+static void
+testcase_child2(struct dt_context* ctx)
+{
+ struct dtn* node;
+ struct dtpropx propx;
+ struct dtprop_xval val;
+ struct dtp_val* prop;
+
+ begin_testcase("dtpx-reg");
+
+ node = validate_node(ctx, "child@2", "child,encoded-array");
+
+ dt_proplet reg = { dtprop_u32, dtprop_u64, dtprop_end };
+
+ dtpx_compile_proplet(reg);
+ dtpx_prepare_with(&propx, &node->reg, reg);
+
+ expect_true(dtpx_extract_at(&propx, &val, 0));
+ expect_int(val.u32, 0x12345);
+
+ expect_true(dtpx_extract_at(&propx, &val, 1));
+ expect_ulong(val.u64, (0x1UL << 32) | 0x2UL);
+
+ expect_false(dtpx_extract_at(&propx, &val, 2));
+ expect_false(dtpx_goto_row(&propx, 1));
+
+ end_testcase();
+
+
+ begin_testcase("dtpx-mixed");
+
+ struct dtprop_xval xvals[5];
+ dt_proplet mixed_array = {
+ dtprop_handle, dtprop_u32, dtprop_u32, dtprop_u32, dtprop_u32,
+ dtprop_end
+ };
+
+ prop = dt_getprop(&node->base, "mixed_array");
+ expect_notnull(prop);
+
+ dtpx_compile_proplet(mixed_array);
+ dtpx_prepare_with(&propx, prop, mixed_array);
+
+ expect_true(dtpx_extract_row(&propx, xvals, 5));
+
+ expect_notnull(xvals[0].phandle);
+ expect_str(morpher_name(dt_mobj(xvals[0].phandle)), "child@1");
+ expect_int(xvals[1].u32, 1);
+ expect_int(xvals[2].u32, 3);
+ expect_int(xvals[3].u32, 5);
+ expect_int(xvals[4].u32, 7);
+
+ expect_true(dtpx_next_row(&propx));
+ expect_true(dtpx_extract_row(&propx, xvals, 5));
+
+ expect_notnull(xvals[0].phandle);
+ expect_str(morpher_name(dt_mobj(xvals[0].phandle)), "child@3");
+ expect_int(xvals[1].u32, 2);
+ expect_int(xvals[2].u32, 4);
+ expect_int(xvals[3].u32, 6);
+ expect_int(xvals[4].u32, 8);
+
+ end_testcase();
+}
+
+static void
+testcase_child3(struct dt_context* ctx)
+{
+ struct dtn* node;
+ struct dtpropx propx;
+ struct dtprop_xval val;
+ struct dtp_val* prop;
+
+ begin_testcase("simple-flags");
+
+ node = validate_node(ctx, "child@3", "child,flags");
+
+ expect_true(node->base.dma_coherent);
+ expect_true(node->base.intr_controll);
+ expect_int(node->base.status, STATUS_DISABLE);
+
+ end_testcase();
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+
+ if(!my_load_dtb()) {
+ printf("failed to load dtb\n");
+ _exit(1);
+ }
+
+ struct dt_context* ctx;
+ ctx = dt_main_context();
+
+ testcase_rootfield(ctx);
+ testcase_child1(ctx);
+ testcase_child3(ctx);
+ testcase_child2(ctx);
+}
\ No newline at end of file
--- /dev/null
+#include "common.h"
+#include <testing/basic.h>
+
+static void
+test_fdt_basic_iter(ptr_t dtb)
+{
+ struct fdt_blob fdt;
+ fdt_loc_t loc;
+ int depth = 0;
+
+ fdt_load(&fdt, dtb);
+ loc = fdt.root;
+
+ testcase("iter-child1", {
+ loc = fdt_next_token(loc, &depth);
+
+ expect_int(depth, 1);
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@1");
+ });
+
+ testcase("iter-child1-prop", {
+ loc = fdt_next_token(loc, &depth);
+
+ expect_int(depth, 1);
+ expect_true(fdt_prop(loc.token));
+ expect_str(fdt_prop_key(&fdt, loc), "prop-child1");
+ });
+
+ testcase("iter-child1-end", {
+ loc = fdt_next_token(loc, &depth);
+
+ expect_int(depth, 0);
+ expect_true(fdt_node_end(loc.token));
+ });
+
+ testcase("iter-step-out", {
+ loc = fdt_next_token(loc, &depth);
+
+ expect_int(depth, -1);
+ expect_true(fdt_node(loc.token));
+ expect_str(loc.node->name, "child@2");
+ });
+}
+
+static void
+test_fdt_sibling_iter(ptr_t dtb)
+{
+ struct fdt_blob fdt;
+ fdt_loc_t loc;
+ int depth = 0;
+
+ fdt_load(&fdt, dtb);
+ loc = fdt.root;
+
+ loc = fdt_descend_into(loc);
+
+ testcase("sibling-iter-1", {
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@1");
+ });
+
+ testcase("sibling-iter-2", {
+ expect_true(fdt_next_sibling(loc, &loc));
+
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@2");
+ });
+
+ testcase("sibling-iter-3", {
+ expect_true(fdt_next_sibling(loc, &loc));
+
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@3");
+ });
+
+ testcase("sibling-iter-3", {
+ expect_false(fdt_next_sibling(loc, &loc));
+
+ expect_true(fdt_node_end(loc.token));
+ });
+}
+
+static void
+test_fdt_descend_ascend(ptr_t dtb)
+{
+ struct fdt_blob fdt;
+ fdt_loc_t loc;
+ int depth = 0;
+
+ fdt_load(&fdt, dtb);
+ loc = fdt.root;
+
+ testcase("descend-to-child1", {
+ loc = fdt_descend_into(loc);
+
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@1");
+ });
+
+ testcase("goto-child2", {
+ expect_true(fdt_next_sibling(loc, &loc));
+
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@2");
+
+ loc = fdt_descend_into(loc);
+
+ expect_int(loc.token->token, FDT_PROP);
+ expect_str(fdt_prop_key(&fdt, loc), "prop-child2");
+ });
+
+ testcase("descend-on-prop", {
+ loc = fdt_descend_into(loc);
+
+ expect_true(loc.ptr == loc.ptr);
+ expect_int(loc.token->token, FDT_PROP);
+ expect_str(fdt_prop_key(&fdt, loc), "prop-child2");
+ });
+
+ testcase("descend-to-child21", {
+ expect_true(fdt_next_sibling(loc, &loc));
+
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@21");
+ });
+
+ testcase("ascend", {
+ loc = fdt_ascend_from(loc);
+
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@3");
+ });
+
+ testcase("ascend-to-root", {
+ loc = fdt_ascend_from(loc);
+
+ expect_true(fdt_node_end(loc.token));
+ });
+}
+
+
+static void
+test_find_prop(ptr_t dtb)
+{
+ struct fdt_blob fdt;
+ fdt_loc_t loc;
+ struct dtp_val val;
+ int depth = 0;
+
+ fdt_load(&fdt, dtb);
+ loc = fdt.root;
+
+ testcase("prop-find-child1", {
+ loc = fdt_descend_into(loc);
+ expect_int(loc.token->token, FDT_NOD_BEGIN);
+ expect_str(loc.node->name, "child@1");
+
+ expect_true(fdt_find_prop(&fdt, loc, "prop-child1", &val));
+ expect_int(val.size, 0);
+
+ expect_false(fdt_find_prop(&fdt, loc, "prop-child2", &val));
+ });
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+ ptr_t dtb = load_fdt();
+
+ test_fdt_basic_iter(dtb);
+ test_fdt_descend_ascend(dtb);
+ test_fdt_sibling_iter(dtb);
+ test_find_prop(dtb);
+}
\ No newline at end of file
--- /dev/null
+#include "common.h"
+#include <testing/basic.h>
+
+static void
+test_fdt_memory_node(ptr_t dtb)
+{
+ struct fdt_blob fdt;
+ struct fdt_memscan mscan;
+ struct dt_memory_node mnode;
+
+ fdt_load(&fdt, dtb);
+ fdt_memscan_begin(&mscan, &fdt);
+
+ testcase("initial-state", {
+ expect_int(mscan.root_addr_c, 2);
+ expect_int(mscan.root_size_c, 1);
+ });
+
+ testcase("memory-node-1", {
+ expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+ expect_str(mscan.found.node->name, "memory@1000000");
+ expect_true(mscan.node_type == FDT_MEM_FREE);
+
+ expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+ expect_ulong(mnode.base, 0x1000000UL);
+ expect_ulong(mnode.size, 0x10000UL);
+
+ expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+ expect_ulong(mnode.base, 0x8000000UL);
+ expect_ulong(mnode.size, 0x10000UL);
+
+ expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+ expect_ulong(mnode.base, 0x1002000000UL);
+ expect_ulong(mnode.size, 0x200000UL);
+
+ expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+ });
+
+ testcase("memory-node-2", {
+ expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+ expect_str(mscan.found.node->name, "memory@f000000");
+ expect_true(mscan.node_type == FDT_MEM_FREE);
+
+ expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+ expect_ulong(mnode.base, 0xf000000UL);
+ expect_ulong(mnode.size, 0xff000UL);
+
+ expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+ });
+
+ testcase("reserved-node-1", {
+ expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+ expect_str(mscan.found.node->name, "hwrom@0");
+ expect_true(mscan.node_type == FDT_MEM_RSVD);
+ expect_true(mscan.node_attr.nomap);
+
+ expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+ expect_ulong(mnode.base, 0x0);
+ expect_ulong(mnode.size, 0x1000000);
+
+ expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+ });
+
+ testcase("reserved-node-2", {
+ expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+ expect_str(mscan.found.node->name, "cma");
+ expect_true(mscan.node_type == FDT_MEM_RSVD_DYNAMIC);
+ expect_true(mscan.node_attr.reusable);
+ expect_false(mscan.node_attr.nomap);
+ expect_ulong(mscan.node_attr.alignment, 0x400000);
+ expect_ulong(mscan.node_attr.total_size, 0x10000000);
+
+ expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+ expect_ulong(mnode.base, 0x10000000);
+ expect_ulong(mnode.size, 0x10000000);
+
+ expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+ });
+
+ testcase("reserved-node-out-of-bound", {
+ expect_false(fdt_memscan_nextnode(&mscan, &fdt));
+ });
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+ ptr_t dtb = load_fdt();
+
+ test_fdt_memory_node(dtb);
+}
\ No newline at end of file
--- /dev/null
+#include "common.h"
+#include <testing/basic.h>
+#include <unistd.h>
+
+static inline struct dtn*
+get_node(struct dtn* parent, const char* name)
+{
+ struct dtn_iter it;
+ struct dtn* node;
+
+ dt_begin_find_byname(&it, parent, name);
+
+ node = (struct dtn*)it.matched;
+ expect_notnull(node);
+
+ return node;
+}
+
+
+void
+run_test(int argc, const char* argv[])
+{
+
+ if(!my_load_dtb()) {
+ printf("failed to load dtb\n");
+ _exit(1);
+ }
+
+ struct dt_context* ctx;
+ struct dtn* node;
+
+ ctx = dt_main_context();
+
+ begin_testcase("root");
+
+ node = ctx->root;
+ expect_int(node->base.addr_c, 1);
+ expect_int(node->base.sz_c, 2);
+ expect_int(node->base.intr_c, 0);
+ end_testcase();
+
+ begin_testcase("level-1 child");
+
+ node = get_node(node, "child@1");
+ expect_int(node->base.addr_c, 1);
+ expect_int(node->base.sz_c, 2);
+ expect_int(node->base.intr_c, 3);
+ end_testcase();
+
+ begin_testcase("level-2 child");
+
+ node = get_node(node, "child@2");
+ expect_int(node->base.addr_c, 4);
+ expect_int(node->base.sz_c, 2);
+ expect_int(node->base.intr_c, 3);
+ end_testcase();
+
+ begin_testcase("level-3 child");
+
+ node = get_node(node, "child@3");
+ expect_int(node->base.addr_c, 4);
+ expect_int(node->base.sz_c, 0);
+ expect_int(node->base.intr_c, 0);
+ end_testcase();
+
+}
\ No newline at end of file
--- /dev/null
+#include "common.h"
+#include <testing/basic.h>
+
+extern void *calloc(size_t, size_t);
+extern void free(void *);
+
+void
+run_test(int argc, const char* argv[])
+{
+ struct dt_context* ctx;
+ struct dtn* node, *domain;
+ struct dtn_iter it;
+ struct dtp_val val;
+
+ my_load_dtb();
+
+ ctx = dt_main_context();
+
+ node = ctx->root;
+ testcase("root", {
+ expect_notnull(node);
+ expect_int(node->base.addr_c, 0);
+ expect_int(node->base.sz_c, 0);
+ expect_int(node->base.intr_c, 0);
+ });
+
+ dt_begin_find_byname(&it, ctx->root, "dev@1");
+ node = (struct dtn*)it.matched;
+
+ testcase("intr-basic", {
+ expect_notnull(node);
+ expect_notnull(node->intr.parent);
+
+ expect_str(dt_name(node), "dev@1");
+ expect_str(dt_name(node->intr.parent), "pic@11");
+ });
+
+ testcase("intr-single", {
+ expect_int(node->intr.nr_intrs, 1);
+ expect_false(node->intr.extended);
+
+ domain = dt_interrupt_at(node, 0, &val);
+ expect_int(val.ref->raw[0], 1);
+ expect_int(val.ref->raw[1], 2);
+ expect_str(dt_name(domain), "pic@11");
+
+ expect_null(dt_interrupt_at(node, 1, &val));
+ });
+
+ dt_begin_find_byname(&it, ctx->root, "dev@2");
+ node = (struct dtn*)it.matched;
+
+ testcase("intr-multi", {
+ expect_notnull(node);
+ expect_int(node->intr.nr_intrs, 3);
+ expect_false(node->intr.extended);
+
+ domain = dt_interrupt_at(node, 0, &val);
+ expect_int(val.ref->raw[0], 1);
+ expect_int(val.ref->raw[1], 1);
+ expect_str(dt_name(domain), "pic@11");
+
+ domain = dt_interrupt_at(node, 1, &val);
+ expect_int(val.ref->raw[0], 1);
+ expect_int(val.ref->raw[1], 2);
+ expect_str(dt_name(domain), "pic@11");
+
+ domain = dt_interrupt_at(node, 2, &val);
+ expect_int(val.ref->raw[0], 2);
+ expect_int(val.ref->raw[1], 2);
+ expect_str(dt_name(domain), "pic@11");
+
+ expect_null(dt_interrupt_at(node, 3, &val));
+ });
+
+ dt_begin_find_byname(&it, ctx->root, "dev@3");
+ node = (struct dtn*)it.matched;
+
+ testcase("intr-ext-multi", {
+ expect_notnull(node);
+
+ expect_int(node->intr.nr_intrs, 3);
+ expect_true(node->intr.extended);
+
+ domain = dt_interrupt_at(node, 0, &val);
+ expect_int(val.size / sizeof(int), 2);
+ expect_int(val.ref->raw[0], 3);
+ expect_int(val.ref->raw[1], 3);
+ expect_str(dt_name(domain), "pic@11");
+
+ domain = dt_interrupt_at(node, 1, &val);
+ expect_int(val.size / sizeof(int), 1);
+ expect_int(val.ref->raw[0], 1);
+ expect_str(dt_name(domain), "pic@22");
+
+ domain = dt_interrupt_at(node, 2, &val);
+ expect_int(val.size / sizeof(int), 4);
+ expect_int(val.ref->raw[0], 1);
+ expect_int(val.ref->raw[1], 2);
+ expect_int(val.ref->raw[2], 3);
+ expect_int(val.ref->raw[3], 4);
+ expect_str(dt_name(domain), "pic@33");
+
+ expect_null(dt_interrupt_at(node, 3, &val));
+ });
+}
\ No newline at end of file
--- /dev/null
+#include "common.h"
+#include <testing/basic.h>
+
+extern void *calloc(size_t, size_t);
+extern void free(void *);
+
+#define be(v) ((((v) & 0x000000ff) << 24) |\
+ (((v) & 0x00ff0000) >> 8 ) |\
+ (((v) & 0x0000ff00) << 8 ) |\
+ (((v) & 0xff000000) >> 24))
+
+static void
+map_and_mask_test(struct dtn* node)
+{
+ struct dtn_intr* intrn;
+ struct dtspec_map *map;
+ struct dtspec_key *mask, *key, test_key;
+
+ intrn = &node->intr;
+ map = intrn->map;
+ mask = &map->mask;
+
+ test_key.val = calloc(4, sizeof(int));
+ test_key.size = 4;
+ test_key.bval->raw[0] = 0xf200;
+ test_key.bval->raw[1] = 0x22;
+ test_key.bval->raw[2] = 0x0;
+ test_key.bval->raw[3] = 0x16;
+
+ testcase("map", { expect_notnull(map); });
+
+ testcase("mask-value", {
+ expect_int(mask->bval->raw[0], 0xf800);
+ expect_int(mask->bval->raw[1], 0);
+ expect_int(mask->bval->raw[2], 0);
+ expect_int(mask->bval->raw[3], 7);
+ });
+
+ testcase("key-copy", {
+ struct dtspec_key tmp_key;
+ dtspec_cpykey(&tmp_key, &test_key);
+
+ expect_int(tmp_key.bval->raw[0], 0xf200);
+ expect_int(tmp_key.bval->raw[1], 0x22);
+ expect_int(tmp_key.bval->raw[2], 0);
+ expect_int(tmp_key.bval->raw[3], 0x16);
+ expect_int(tmp_key.size, test_key.size);
+
+ dtspec_freekey(&tmp_key);
+ expect_true(dtspec_nullkey(&tmp_key));
+ });
+
+ testcase("mask-ops", {
+ struct dtspec_key tmp_key;
+ dtspec_cpykey(&tmp_key, &test_key);
+
+ dtspec_applymask(map, &tmp_key);
+
+ expect_int(tmp_key.bval->raw[0], 0xf000);
+ expect_int(tmp_key.bval->raw[1], 0);
+ expect_int(tmp_key.bval->raw[2], 0);
+ expect_int(tmp_key.bval->raw[3], 6);
+
+ dtspec_freekey(&tmp_key);
+ });
+
+ testcase("map-get", {
+ struct dtspec_mapent* ent;
+
+ test_key.bval->raw[0] = 0x8820;
+ test_key.bval->raw[1] = 0x22;
+ test_key.bval->raw[2] = 0x0;
+ test_key.bval->raw[3] = 0x14;
+
+ ent = dtspec_lookup(map, &test_key);
+ expect_notnull(ent);
+
+ expect_int(ent->child_spec.bval->raw[0], 0x8800);
+ expect_int(ent->child_spec.bval->raw[1], 0);
+ expect_int(ent->child_spec.bval->raw[2], 0);
+ expect_int(ent->child_spec.bval->raw[3], 4);
+
+ expect_notnull(ent->parent);
+ expect_str(morpher_name(dt_mobj(ent->parent)), "pic@1");
+
+ expect_int(ent->parent_spec.bval->raw[0], 1);
+ expect_int(ent->parent_spec.bval->raw[1], 1);
+ });
+
+ free(test_key.val);
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+ struct dt_context* ctx;
+ struct dtn* node;
+ struct dtn_iter it;
+
+ my_load_dtb();
+
+ ctx = dt_main_context();
+
+ dt_begin_find_byname(&it, ctx->root, "pci");
+ node = (struct dtn*)it.matched;
+
+ testcase("root", {
+ expect_notnull(node);
+ expect_int(node->base.addr_c, 3);
+ expect_int(node->base.sz_c, 2);
+ expect_int(node->base.intr_c, 1);
+ });
+
+ map_and_mask_test(node);
+}
\ No newline at end of file
--- /dev/null
+basic
+inheritence
+intrmap
+interrupts
+fdt-iter
+fdt-mem
\ No newline at end of file
--- /dev/null
+LUNAIX_ROOT ?= $(shell realpath ../../)
+
+include test_build.mkinc
+
+__test-dir := device-tree
+test-dir := $(addprefix test-,$(__test-dir))
+
+obj-stubs :=
+
+obj-tmp :=
+include stubs/makefile
+obj-stubs += $(addprefix $(unit-test-root)/stubs/,$(obj-tmp))
+
+export obj-stubs LUNAIX_ROOT
+test-%:
+ $(call status,MK,$*)
+ @$(MAKE) $(MKFLAGS) -C $* $(_ACT) -I $(CURDIR)
+
+.PHONY: all clean
+
+all: _ACT := all
+all: $(obj-stubs) $(test-dir)
+
+run: _ACT := run
+run: $(obj-stubs) $(test-dir)
+
+clean: _ACT := clean
+clean: $(test-dir)
+ @rm -f $(obj-stubs) $(obj-shared)
\ No newline at end of file
--- /dev/null
+#ifndef __LUNAIX_STRING_H
+#define __LUNAIX_STRING_H
+
+#include <string.h>
+
+static inline int
+streq(const char* a, const char* b)
+{
+ return strcmp(a, b) == 0;
+}
+
+static inline int
+strneq(const char* a, const char* b, unsigned long n)
+{
+ return strcmp(a, b) != 0;
+}
+
+#endif /* __LUNAIX_STRING_H */
--- /dev/null
+#ifndef __STUB_LUNAIX_OWLOYSIUS_H
+#define __STUB_LUNAIX_OWLOYSIUS_H
+
+
+#define owloysius_fetch_init(func, call_stage) \
+ void init_export_##func() { func(); }
+
+#define invoke_init_function(stage)
+
+static inline void
+initfn_invoke_sysconf()
+{
+ return;
+}
+
+static inline void
+initfn_invoke_earlyboot()
+{
+ return;
+}
+
+static inline void
+initfn_invoke_boot()
+{
+ return;
+}
+
+static inline void
+initfn_invoke_postboot()
+{
+ return;
+}
+
+
+#endif /* __STUB_LUNAIX_OWLOYSIUS_H */
--- /dev/null
+../../../../libs/hash.c
\ No newline at end of file
--- /dev/null
+obj-tmp += spike.o
+obj-tmp += syslog.o
+obj-tmp += valloc.o
+
+obj-tmp += klibc/hash.o
+
--- /dev/null
+#include <lunaix/spike.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void
+__assert_fail(const char* expr, const char* file, unsigned int line)
+{
+ printf("assertion failed: %s (%s:%d)\n", expr, file, line);
+
+ _exit(1);
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+kprintf_m(const char* component, const char* fmt, va_list args)
+{
+ int sz = 0;
+ char buff[1024];
+
+ sz = vsnprintf(buff, 1024, fmt, args);
+ printf("%s: %s\n", component, buff);
+}
+
+void
+kprintf_v(const char* component, const char* fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+
+ kprintf_m(component, fmt, args);
+
+ va_end(args);
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/mm/valloc.h>
+#include <stddef.h>
+
+extern void *malloc(size_t);
+extern void *calloc(size_t, size_t);
+extern void free(void*);
+
+void*
+valloc(unsigned int size)
+{
+ return malloc(size);
+}
+
+void*
+vzalloc(unsigned int size)
+{
+ return calloc(size, 1);
+}
+
+void*
+vcalloc(unsigned int size, unsigned int count)
+{
+ return calloc(size, count);
+}
+
+void
+vfree(void* ptr)
+{
+ free(ptr);
+}
+
+void
+vfree_safe(void* ptr)
+{
+ if (ptr) free(ptr);
+}
+
+void*
+valloc_dma(unsigned int size)
+{
+ return malloc(size);
+}
+
+void*
+vzalloc_dma(unsigned int size)
+{
+ return calloc(size, 1);
+}
+
+void
+vfree_dma(void* ptr)
+{
+ free(ptr);
+}
+
+void
+valloc_init()
+{
+ return;
+}
+
+void
+valloc_ensure_valid(void* ptr)
+{
+ return;
+}
\ No newline at end of file
--- /dev/null
+MAKEFLAGS += --no-print-directory
+
+include $(LUNAIX_ROOT)/tests/shared/makefile
+
+CFLAGS += -isystem $(unit-test-root)/stubs/includes
\ No newline at end of file