From: Lunaixsky Date: Thu, 28 Nov 2024 01:08:29 +0000 (+0000) Subject: Unit testing framework and devicetree framework refactoring (#50) X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/9daf4fcdae88f72af60aeb0c7722841af02233d4?ds=sidebyside Unit testing framework and devicetree framework refactoring (#50) * re-write the fdt iterator and parsing procedure * unit test framework and devtree testings * add expect_* assertions, test statistics, more dt test cases * basic.dts : basic dt property testing: trivial, simple prop_encoded, mixed prop_encoded * inheritence.dts : #address-cell, #size-cell and #interrupt-cell parent inheritence test. * regression fix on dt, add dt prop extractor api (dtpx) * tests for interrupt node and rework dtpi api * add tests for interrupt node, exercise interrupt mask and interrupt map * redesign the dtpi api to make it simpler to use * rename dt_node_* and dt_prop_* struct to dtn_* and dtp_* to make it adhere to related functions * struct dtspec: unified specifier-map representation * add correpsond unit test. * fix minor issues, integrate the test into main makefile * api: dt_interrupt_at to query interrupt specifier at given location * add unit test cases for interrupt node related test * rewrite FDT iterator, enable in-place DT lookup * add alloc-less iterator for /memory, /reserved-memory nodes * unit tests for the rewrited iterators * unit test for fdt-memscan * fix detected issues * fix indentations --- diff --git a/lunaix-os/.gitignore b/lunaix-os/.gitignore index ea16967..9a6b6a8 100644 --- a/lunaix-os/.gitignore +++ b/lunaix-os/.gitignore @@ -9,6 +9,7 @@ !scripts !usr !link +!tests !.gitignore !*.md diff --git a/lunaix-os/arch/generic/includes/asm-generic/isrm.h b/lunaix-os/arch/generic/includes/asm-generic/isrm.h index 0bd4dda..0d4a15a 100644 --- a/lunaix-os/arch/generic/includes/asm-generic/isrm.h +++ b/lunaix-os/arch/generic/includes/asm-generic/isrm.h @@ -94,7 +94,7 @@ isrm_msi_alloc_simple(struct device* dev, cpu_t cpu, isr_cb handler) * @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 diff --git a/lunaix-os/arch/x86/exceptions/isrm.c b/lunaix-os/arch/x86/exceptions/isrm.c index fefc33e..86eec04 100644 --- a/lunaix-os/arch/x86/exceptions/isrm.c +++ b/lunaix-os/arch/x86/exceptions/isrm.c @@ -211,7 +211,7 @@ isrm_msi_done(msienv_t msienv) int -isrm_bind_dtn(struct dt_intr_node* node) +isrm_bind_dtn(struct dtn_intr* node) { fail("not supported"); } diff --git a/lunaix-os/hal/devtree/LBuild b/lunaix-os/hal/devtree/LBuild index 4709a35..97f3109 100644 --- a/lunaix-os/hal/devtree/LBuild +++ b/lunaix-os/hal/devtree/LBuild @@ -2,4 +2,5 @@ sources([ "dt_interrupt.c", "dt.c", "dtm.c" + "dtspec.c" ]) \ No newline at end of file diff --git a/lunaix-os/hal/devtree/devtree.h b/lunaix-os/hal/devtree/devtree.h index c2374c8..1bfe891 100644 --- a/lunaix-os/hal/devtree/devtree.h +++ b/lunaix-os/hal/devtree/devtree.h @@ -6,42 +6,25 @@ #include 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 */ diff --git a/lunaix-os/hal/devtree/dt.c b/lunaix-os/hal/devtree/dt.c index f1d6860..a426551 100644 --- a/lunaix-os/hal/devtree/dt.c +++ b/lunaix-os/hal/devtree/dt.c @@ -9,152 +9,317 @@ LOG_MODULE("dtb") static morph_t* devtree_obj_root; static struct dt_context dtctx; -void -fdt_itbegin(struct fdt_iter* fdti, struct fdt_header* fdt_hdr) +void +fdt_load(struct fdt_blob* fdt, ptr_t base) { - unsigned int off_struct, off_str; - struct fdt_token* tok; - const char* str_blk; + struct fdt_header* hdr; - off_str = le(fdt_hdr->off_dt_strings); - off_struct = le(fdt_hdr->off_dt_struct); + fdt->fdt_base = base; - tok = offset_t(fdt_hdr, struct fdt_token, off_struct); - str_blk = offset_t(fdt_hdr, const char, off_str); - - *fdti = (struct fdt_iter) { - .pos = tok, - .str_block = str_blk - }; -} + hdr = fdt->header; + if (hdr->magic != FDT_MAGIC) { + FATAL("invalid dtb, unexpected magic: 0x%x, expect: 0x%x", + hdr->magic, FDT_MAGIC); + } -void -fdt_itend(struct fdt_iter* fdti) -{ - fdti->pos = NULL; + fdt->plat_rsvd_base = base + hdr->off_mem_rsvmap; + fdt->str_block_base = base + hdr->off_dt_strings; + fdt->root.ptr = base + hdr->off_dt_struct; } bool -fdt_itnext(struct fdt_iter* fdti) +fdt_next_boot_rsvdmem(struct fdt_blob* fdt, fdt_loc_t* loc, + struct dt_memory_node* mem) { - struct fdt_token *current; - struct fdt_prop *prop; + fdt_loc_t current; - current = fdti->pos; - if (!current) { + current = *loc; + + if (!current.rsvd_ent->addr && !current.rsvd_ent->addr) { return false; } + mem->base = current.rsvd_ent->addr; + mem->size = current.rsvd_ent->size; + mem->type = FDT_MEM_RSVD; + + current.rsvd_ent++; + *loc = current; + + return true; +} + +fdt_loc_t +fdt_next_token(fdt_loc_t loc, int* delta_depth) +{ + int d = 0; + + do { + if (fdt_node(loc.token)) { + d++; + loc.ptr += strlen(loc.node->name) + 1; + loc.ptr = ROUNDUP(loc.ptr, sizeof(int)); + } + else if (fdt_node_end(loc.token)) { + d--; + } + else if (fdt_prop(loc.token)) { + loc.ptr += loc.prop->len + 2 * sizeof(int); + loc.ptr = ROUNDUP(loc.ptr, sizeof(int)); + } + + loc.token++; + } while (fdt_nope(loc.token)); + + *delta_depth = d; + return loc; +} + +bool +fdt_next_sibling(fdt_loc_t loc, fdt_loc_t* loc_out) +{ + int depth = 0, new_depth = 0; + + do { + loc = fdt_next_token(loc, &new_depth); + depth += new_depth; + } while (depth > 0); + + *loc_out = loc; + return !fdt_node_end(loc.token); +} + +fdt_loc_t +fdt_descend_into(fdt_loc_t loc) +{ + fdt_loc_t new_loc; + int depth = 0; + + new_loc = fdt_next_token(loc, &depth); + + return depth != 1 ? loc : new_loc; +} + +bool +fdt_find_prop(const struct fdt_blob* fdt, fdt_loc_t loc, + const char* name, struct dtp_val* val) +{ + char* prop_name; + + loc = fdt_descend_into(loc); + do { - if (fdt_nope(current)) { + if (!fdt_prop(loc.token)) { continue; } - if (fdt_prop(current)) { - prop = (struct fdt_prop*) current; - current = offset(current, prop->len); - continue; - } + prop_name = fdt_prop_key(fdt, loc); - if (fdt_node_end(current)) { - fdti->depth--; + if (!streq(prop_name, name)) { continue; } - // node begin - - fdti->depth++; - if (fdti->depth == 1) { - // enter root node - break; - } - - while (!fdt_prop(current) && !fdt_node_end(current)) { - current++; - } - - if (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; } @@ -177,22 +342,18 @@ __parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node) } static bool -__parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node) +__parse_stdnode_prop(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn* node) { - if (propeq(it, "reg")) { - __mkprop_ptr(it, &node->reg); - } - - 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 { @@ -203,17 +364,17 @@ __parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node) } static bool -__parse_stdflags(struct fdt_iter* it, struct dt_node_base* node) +__parse_stdflags(struct fdt_blob* fdt, fdt_loc_t loc, struct dtn_base* node) { - if (propeq(it, "dma-coherent")) { + if (propeq(fdt, loc, "dma-coherent")) { node->dma_coherent = true; } - else if (propeq(it, "dma-noncoherent")) { + else if (propeq(fdt, loc, "dma-noncoherent")) { node->dma_ncoherent = true; } - else if (propeq(it, "interrupt-controller")) { + else if (propeq(fdt, loc, "interrupt-controller")) { node->intr_controll = true; } @@ -225,18 +386,20 @@ __parse_stdflags(struct fdt_iter* it, struct dt_node_base* node) } 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) \ @@ -244,17 +407,17 @@ __init_prop_table(struct dt_node_base* node) &(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); @@ -262,137 +425,116 @@ __parse_other_prop(struct fdt_iter* it, struct dt_node_base* node) } 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) { @@ -404,7 +546,7 @@ __resolve_phnd_references() parent = default_parent; } - intrupt->parent = &parent->intr; + intrupt->parent = parent; __expand_extended_intr(intrupt); } @@ -413,100 +555,98 @@ __resolve_phnd_references() static void __resolve_inter_map() { - struct dt_node_base *pos, *n; + struct dtn_base *pos, *n; llist_for_each(pos, n, &dtctx.nodes, nodes) { - dt_resolve_interrupt_map(BASE_TO_DTNODE(pos)); + dt_resolve_interrupt_map(dtn_from(pos)); } } bool dt_load(ptr_t dtb_dropoff) { - dtctx.reloacted_dtb = dtb_dropoff; - - if (dtctx.fdt->magic != FDT_MAGIC) { - ERROR("invalid dtb, unexpected magic: 0x%x", dtctx.fdt->magic); - return false; - } - - size_t str_off = le(dtctx.fdt->size_dt_strings); - dtctx.str_block = offset_t(dtb_dropoff, const char, str_off); - llist_init_head(&dtctx.nodes); hashtable_init(dtctx.phnds_table); - struct fdt_iter it; - struct fdt_token* tok; - struct dt_node_base *node, *prev; + struct fdt_blob *fdt; + struct dtn *node, + *stack[16] = { NULL }; - struct dt_node_base* depth[16]; - bool is_root_level, filled; + int depth = 0, delta = 0, nr_nodes = 0; + fdt_loc_t loc, next_loc; + + fdt = &dtctx.fdt; + fdt_load(&dtctx.fdt, dtb_dropoff); - node = NULL; - depth[0] = NULL; - fdt_itbegin(&it, dtctx.fdt); + loc = fdt->root; - while (fdt_itnext(&it)) { - is_root_level = it.depth == 1; + while (!fdt_eof(loc.token)) + { + next_loc = fdt_next_token(loc, &delta); - if (it.depth >= 16) { + if (depth >= 16) { // tree too deep ERROR("strange dtb, too deep to dive."); return false; } - depth[it.depth] = NULL; - node = depth[it.depth - 1]; + assert(depth >= 0); + node = stack[depth]; - if (!node) { - // need new node - if (unlikely(is_root_level)) { - node = vzalloc(sizeof(struct dt_root)); - __init_node(node); - } - else { - node = vzalloc(sizeof(struct dt_node)); - prev = depth[it.depth - 2]; - node->parent = prev; + if (fdt_node(loc.token)) + { + assert(!node); - __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; } } @@ -514,7 +654,7 @@ dt_resolve_phandle(dt_phnd_t phandle) } static bool -__byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node) +__byname_predicate(struct dtn_iter* iter, struct dtn_base* node) { int i = 0; const char* be_matched = HSTR_VAL(node->mobj.name); @@ -533,17 +673,17 @@ __byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node) } void -dt_begin_find_byname(struct dt_node_iter* iter, - struct dt_node* node, const char* name) +dt_begin_find_byname(struct dtn_iter* iter, + struct dtn* node, const char* name) { dt_begin_find(iter, node, __byname_predicate, name); } void -dt_begin_find(struct dt_node_iter* iter, struct dt_node* node, +dt_begin_find(struct dtn_iter* iter, struct dtn* node, node_predicate_t pred, void* closure) { - node = node ? : (struct dt_node*)dtctx.root; + node = node ? : (struct dtn*)dtctx.root; iter->head = &node->base; iter->matched = NULL; @@ -551,7 +691,7 @@ dt_begin_find(struct dt_node_iter* iter, struct dt_node* node, 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; @@ -563,14 +703,14 @@ dt_begin_find(struct dt_node_iter* iter, struct dt_node* node, } 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); @@ -593,11 +733,11 @@ dt_find_next(struct dt_node_iter* iter, 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)); @@ -614,6 +754,148 @@ dt_getprop(struct dt_node_base* base, const char* 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() { diff --git a/lunaix-os/hal/devtree/dt_interrupt.c b/lunaix-os/hal/devtree/dt_interrupt.c index ab4d8b3..905eb02 100644 --- a/lunaix-os/hal/devtree/dt_interrupt.c +++ b/lunaix-os/hal/devtree/dt_interrupt.c @@ -1,219 +1,93 @@ #include "devtree.h" #include - #include -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 diff --git a/lunaix-os/hal/devtree/dtm.c b/lunaix-os/hal/devtree/dtm.c index 69ec2e5..7bec489 100644 --- a/lunaix-os/hal/devtree/dtm.c +++ b/lunaix-os/hal/devtree/dtm.c @@ -104,7 +104,7 @@ __try_match(const char* str, const char* pattern, size_t pat_sz) } static struct device_meta* -__try_create_categorical(struct dt_node_base *p) +__try_create_categorical(struct dtn_base *p) { if (!p) return NULL; @@ -130,7 +130,7 @@ __try_create_categorical(struct dt_node_base *p) } 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; @@ -156,7 +156,7 @@ dtm_try_create_from(struct device_def* def) 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(); diff --git a/lunaix-os/hal/devtree/dtspec.c b/lunaix-os/hal/devtree/dtspec.c new file mode 100644 index 0000000..f70f4d2 --- /dev/null +++ b/lunaix-os/hal/devtree/dtspec.c @@ -0,0 +1,138 @@ +#include "devtree.h" +#include + +#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 diff --git a/lunaix-os/includes/hal/devtree.h b/lunaix-os/includes/hal/devtree.h index 7b02ca5..e7e0cf3 100644 --- a/lunaix-os/includes/hal/devtree.h +++ b/lunaix-os/includes/hal/devtree.h @@ -5,45 +5,68 @@ #include #include #include -#include #include #include -#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; @@ -56,64 +79,148 @@ struct fdt_header { 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]; @@ -121,7 +228,7 @@ struct dt_prop_table }; }; -struct dt_node_base +struct dtn_base { morph_t mobj; @@ -140,254 +247,265 @@ struct dt_node_base 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; } @@ -395,187 +513,218 @@ dt_found_any(struct dt_node_iter* iter) 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 */ diff --git a/lunaix-os/includes/hal/devtreem.h b/lunaix-os/includes/hal/devtreem.h index c8d10c2..2b0904d 100644 --- a/lunaix-os/includes/hal/devtreem.h +++ b/lunaix-os/includes/hal/devtreem.h @@ -11,7 +11,7 @@ struct device; #include #include -typedef struct dt_node* devtree_link_t; +typedef struct dtn* devtree_link_t; #define dt_node_morpher morphable_attrs(dt_node, mobj) diff --git a/lunaix-os/includes/listings/changeling.lst b/lunaix-os/includes/listings/changeling.lst index 1e26576..aecd7d4 100644 --- a/lunaix-os/includes/listings/changeling.lst +++ b/lunaix-os/includes/listings/changeling.lst @@ -1,4 +1,4 @@ -morphable(dt_node), +morphable(dtn), morphable(pci_probe), morphable(device_meta), diff --git a/lunaix-os/includes/lunaix/changeling.h b/lunaix-os/includes/lunaix/changeling.h index b9188ec..a8f5c73 100644 --- a/lunaix-os/includes/lunaix/changeling.h +++ b/lunaix-os/includes/lunaix/changeling.h @@ -50,6 +50,7 @@ typedef struct changeling morph_t; #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) \ ({ \ diff --git a/lunaix-os/includes/lunaix/compiler.h b/lunaix-os/includes/lunaix/compiler.h index ffc73c8..a41c741 100644 --- a/lunaix-os/includes/lunaix/compiler.h +++ b/lunaix-os/includes/lunaix/compiler.h @@ -14,6 +14,9 @@ #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) diff --git a/lunaix-os/includes/lunaix/ds/hstr.h b/lunaix-os/includes/lunaix/ds/hstr.h index 169f0b8..77096aa 100644 --- a/lunaix-os/includes/lunaix/ds/hstr.h +++ b/lunaix-os/includes/lunaix/ds/hstr.h @@ -30,7 +30,7 @@ struct hstr #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); diff --git a/lunaix-os/makefile b/lunaix-os/makefile index 1fcb3cc..9895780 100644 --- a/lunaix-os/makefile +++ b/lunaix-os/makefile @@ -70,7 +70,12 @@ clean-user: 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 diff --git a/lunaix-os/tests/.gitignore b/lunaix-os/tests/.gitignore new file mode 100644 index 0000000..d5a2715 --- /dev/null +++ b/lunaix-os/tests/.gitignore @@ -0,0 +1 @@ +**/.gdb_history \ No newline at end of file diff --git a/lunaix-os/tests/includes/testing/basic.h b/lunaix-os/tests/includes/testing/basic.h new file mode 100644 index 0000000..a81dc4f --- /dev/null +++ b/lunaix-os/tests/includes/testing/basic.h @@ -0,0 +1,91 @@ +#ifndef __COMMON_TEST_BASIC_H +#define __COMMON_TEST_BASIC_H + +#include +#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 */ diff --git a/lunaix-os/tests/includes/testing/strutils.h b/lunaix-os/tests/includes/testing/strutils.h new file mode 100644 index 0000000..978d52a --- /dev/null +++ b/lunaix-os/tests/includes/testing/strutils.h @@ -0,0 +1,7 @@ +#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 */ diff --git a/lunaix-os/tests/shared/framework.c b/lunaix-os/tests/shared/framework.c new file mode 100644 index 0000000..ad1aebc --- /dev/null +++ b/lunaix-os/tests/shared/framework.c @@ -0,0 +1,50 @@ +#include +#include + +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 diff --git a/lunaix-os/tests/shared/makefile b/lunaix-os/tests/shared/makefile new file mode 100644 index 0000000..0484be2 --- /dev/null +++ b/lunaix-os/tests/shared/makefile @@ -0,0 +1,20 @@ +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 diff --git a/lunaix-os/tests/units/device-tree/.gitignore b/lunaix-os/tests/units/device-tree/.gitignore new file mode 100644 index 0000000..06e925a --- /dev/null +++ b/lunaix-os/tests/units/device-tree/.gitignore @@ -0,0 +1,3 @@ +test +*.dtb +*.test \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/common.h b/lunaix-os/tests/units/device-tree/common.h new file mode 100644 index 0000000..94c2370 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/common.h @@ -0,0 +1,15 @@ +#ifndef __DTTEST_COMMON_H +#define __DTTEST_COMMON_H + +#define __off_t_defined +#include "dut/devtree.h" + +#include + +bool +my_load_dtb(); + +ptr_t +load_fdt(); + +#endif /* __DTTEST_COMMON_H */ diff --git a/lunaix-os/tests/units/device-tree/dut/changeling.c b/lunaix-os/tests/units/device-tree/dut/changeling.c new file mode 120000 index 0000000..a42dd8d --- /dev/null +++ b/lunaix-os/tests/units/device-tree/dut/changeling.c @@ -0,0 +1 @@ +../../../../kernel/changeling.c \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/dut/devtree.h b/lunaix-os/tests/units/device-tree/dut/devtree.h new file mode 120000 index 0000000..8bb6ea5 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/dut/devtree.h @@ -0,0 +1 @@ +../../../../hal/devtree/devtree.h \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/dut/dt.c b/lunaix-os/tests/units/device-tree/dut/dt.c new file mode 120000 index 0000000..2fdda30 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/dut/dt.c @@ -0,0 +1 @@ +../../../../hal/devtree/dt.c \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/dut/dt_interrupt.c b/lunaix-os/tests/units/device-tree/dut/dt_interrupt.c new file mode 120000 index 0000000..8e3f1ed --- /dev/null +++ b/lunaix-os/tests/units/device-tree/dut/dt_interrupt.c @@ -0,0 +1 @@ +../../../../hal/devtree/dt_interrupt.c \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/dut/dtspec.c b/lunaix-os/tests/units/device-tree/dut/dtspec.c new file mode 120000 index 0000000..3f14cce --- /dev/null +++ b/lunaix-os/tests/units/device-tree/dut/dtspec.c @@ -0,0 +1 @@ +../../../../hal/devtree/dtspec.c \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/load.c b/lunaix-os/tests/units/device-tree/load.c new file mode 100644 index 0000000..f97765e --- /dev/null +++ b/lunaix-os/tests/units/device-tree/load.c @@ -0,0 +1,46 @@ +#include "common.h" + +#include +#include +#include +#include +#include + +#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 diff --git a/lunaix-os/tests/units/device-tree/makefile b/lunaix-os/tests/units/device-tree/makefile new file mode 100644 index 0000000..4d9d530 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/makefile @@ -0,0 +1,38 @@ +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 diff --git a/lunaix-os/tests/units/device-tree/samples/basic.dts b/lunaix-os/tests/units/device-tree/samples/basic.dts new file mode 100644 index 0000000..076e17d --- /dev/null +++ b/lunaix-os/tests/units/device-tree/samples/basic.dts @@ -0,0 +1,31 @@ +/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 diff --git a/lunaix-os/tests/units/device-tree/samples/fdt-iter.dts b/lunaix-os/tests/units/device-tree/samples/fdt-iter.dts new file mode 100644 index 0000000..63c9a37 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/samples/fdt-iter.dts @@ -0,0 +1,19 @@ +/dts-v1/; + +/ { + child@1 { + prop-child1; + }; + + child@2 { + prop-child2; + + child@21 { + prop-child21; + }; + }; + + child@3 { + prop-child3; + }; +}; \ No newline at end of file diff --git a/lunaix-os/tests/units/device-tree/samples/fdt-mem.dts b/lunaix-os/tests/units/device-tree/samples/fdt-mem.dts new file mode 100644 index 0000000..dcc3adb --- /dev/null +++ b/lunaix-os/tests/units/device-tree/samples/fdt-mem.dts @@ -0,0 +1,39 @@ +/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 diff --git a/lunaix-os/tests/units/device-tree/samples/inheritence.dts b/lunaix-os/tests/units/device-tree/samples/inheritence.dts new file mode 100644 index 0000000..a7f14f8 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/samples/inheritence.dts @@ -0,0 +1,17 @@ +/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 diff --git a/lunaix-os/tests/units/device-tree/samples/interrupts.dts b/lunaix-os/tests/units/device-tree/samples/interrupts.dts new file mode 100644 index 0000000..7be57b5 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/samples/interrupts.dts @@ -0,0 +1,39 @@ +/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 diff --git a/lunaix-os/tests/units/device-tree/samples/intrmap.dts b/lunaix-os/tests/units/device-tree/samples/intrmap.dts new file mode 100644 index 0000000..d475a0d --- /dev/null +++ b/lunaix-os/tests/units/device-tree/samples/intrmap.dts @@ -0,0 +1,35 @@ +/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 diff --git a/lunaix-os/tests/units/device-tree/test-basic.c b/lunaix-os/tests/units/device-tree/test-basic.c new file mode 100644 index 0000000..b5ea931 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/test-basic.c @@ -0,0 +1,175 @@ +#include "common.h" +#include +#include + +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 diff --git a/lunaix-os/tests/units/device-tree/test-fdt-iter.c b/lunaix-os/tests/units/device-tree/test-fdt-iter.c new file mode 100644 index 0000000..ac53667 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/test-fdt-iter.c @@ -0,0 +1,175 @@ +#include "common.h" +#include + +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 diff --git a/lunaix-os/tests/units/device-tree/test-fdt-mem.c b/lunaix-os/tests/units/device-tree/test-fdt-mem.c new file mode 100644 index 0000000..1537ab0 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/test-fdt-mem.c @@ -0,0 +1,95 @@ +#include "common.h" +#include + +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 diff --git a/lunaix-os/tests/units/device-tree/test-inheritence.c b/lunaix-os/tests/units/device-tree/test-inheritence.c new file mode 100644 index 0000000..36c299e --- /dev/null +++ b/lunaix-os/tests/units/device-tree/test-inheritence.c @@ -0,0 +1,66 @@ +#include "common.h" +#include +#include + +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 diff --git a/lunaix-os/tests/units/device-tree/test-interrupts.c b/lunaix-os/tests/units/device-tree/test-interrupts.c new file mode 100644 index 0000000..934c4c7 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/test-interrupts.c @@ -0,0 +1,106 @@ +#include "common.h" +#include + +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 diff --git a/lunaix-os/tests/units/device-tree/test-intrmap.c b/lunaix-os/tests/units/device-tree/test-intrmap.c new file mode 100644 index 0000000..2a365ff --- /dev/null +++ b/lunaix-os/tests/units/device-tree/test-intrmap.c @@ -0,0 +1,115 @@ +#include "common.h" +#include + +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 diff --git a/lunaix-os/tests/units/device-tree/tests.txt b/lunaix-os/tests/units/device-tree/tests.txt new file mode 100644 index 0000000..d5ae319 --- /dev/null +++ b/lunaix-os/tests/units/device-tree/tests.txt @@ -0,0 +1,6 @@ +basic +inheritence +intrmap +interrupts +fdt-iter +fdt-mem \ No newline at end of file diff --git a/lunaix-os/tests/units/makefile b/lunaix-os/tests/units/makefile new file mode 100644 index 0000000..66cf8ab --- /dev/null +++ b/lunaix-os/tests/units/makefile @@ -0,0 +1,29 @@ +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 diff --git a/lunaix-os/tests/units/stubs/includes/klibc/string.h b/lunaix-os/tests/units/stubs/includes/klibc/string.h new file mode 100644 index 0000000..830e248 --- /dev/null +++ b/lunaix-os/tests/units/stubs/includes/klibc/string.h @@ -0,0 +1,18 @@ +#ifndef __LUNAIX_STRING_H +#define __LUNAIX_STRING_H + +#include + +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 */ diff --git a/lunaix-os/tests/units/stubs/includes/lunaix/owloysius.h b/lunaix-os/tests/units/stubs/includes/lunaix/owloysius.h new file mode 100644 index 0000000..a0bef95 --- /dev/null +++ b/lunaix-os/tests/units/stubs/includes/lunaix/owloysius.h @@ -0,0 +1,35 @@ +#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 */ diff --git a/lunaix-os/tests/units/stubs/klibc/hash.c b/lunaix-os/tests/units/stubs/klibc/hash.c new file mode 120000 index 0000000..f99bb20 --- /dev/null +++ b/lunaix-os/tests/units/stubs/klibc/hash.c @@ -0,0 +1 @@ +../../../../libs/hash.c \ No newline at end of file diff --git a/lunaix-os/tests/units/stubs/makefile b/lunaix-os/tests/units/stubs/makefile new file mode 100644 index 0000000..9d8096b --- /dev/null +++ b/lunaix-os/tests/units/stubs/makefile @@ -0,0 +1,6 @@ +obj-tmp += spike.o +obj-tmp += syslog.o +obj-tmp += valloc.o + +obj-tmp += klibc/hash.o + diff --git a/lunaix-os/tests/units/stubs/spike.c b/lunaix-os/tests/units/stubs/spike.c new file mode 100644 index 0000000..5a700f5 --- /dev/null +++ b/lunaix-os/tests/units/stubs/spike.c @@ -0,0 +1,11 @@ +#include +#include +#include + +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 diff --git a/lunaix-os/tests/units/stubs/syslog.c b/lunaix-os/tests/units/stubs/syslog.c new file mode 100644 index 0000000..0531625 --- /dev/null +++ b/lunaix-os/tests/units/stubs/syslog.c @@ -0,0 +1,25 @@ +#include +#include +#include + +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 diff --git a/lunaix-os/tests/units/stubs/valloc.c b/lunaix-os/tests/units/stubs/valloc.c new file mode 100644 index 0000000..0d02922 --- /dev/null +++ b/lunaix-os/tests/units/stubs/valloc.c @@ -0,0 +1,66 @@ +#include +#include + +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 diff --git a/lunaix-os/tests/units/test_build.mkinc b/lunaix-os/tests/units/test_build.mkinc new file mode 100644 index 0000000..1a3fcdb --- /dev/null +++ b/lunaix-os/tests/units/test_build.mkinc @@ -0,0 +1,5 @@ +MAKEFLAGS += --no-print-directory + +include $(LUNAIX_ROOT)/tests/shared/makefile + +CFLAGS += -isystem $(unit-test-root)/stubs/includes \ No newline at end of file