Unit testing framework and devicetree framework refactoring (#50)
authorLunaixsky <lunaixsky@qq.com>
Thu, 28 Nov 2024 01:08:29 +0000 (01:08 +0000)
committerGitHub <noreply@github.com>
Thu, 28 Nov 2024 01:08:29 +0000 (01:08 +0000)
* 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

52 files changed:
lunaix-os/.gitignore
lunaix-os/arch/generic/includes/asm-generic/isrm.h
lunaix-os/arch/x86/exceptions/isrm.c
lunaix-os/hal/devtree/LBuild
lunaix-os/hal/devtree/devtree.h
lunaix-os/hal/devtree/dt.c
lunaix-os/hal/devtree/dt_interrupt.c
lunaix-os/hal/devtree/dtm.c
lunaix-os/hal/devtree/dtspec.c [new file with mode: 0644]
lunaix-os/includes/hal/devtree.h
lunaix-os/includes/hal/devtreem.h
lunaix-os/includes/listings/changeling.lst
lunaix-os/includes/lunaix/changeling.h
lunaix-os/includes/lunaix/compiler.h
lunaix-os/includes/lunaix/ds/hstr.h
lunaix-os/makefile
lunaix-os/tests/.gitignore [new file with mode: 0644]
lunaix-os/tests/includes/testing/basic.h [new file with mode: 0644]
lunaix-os/tests/includes/testing/strutils.h [new file with mode: 0644]
lunaix-os/tests/shared/framework.c [new file with mode: 0644]
lunaix-os/tests/shared/makefile [new file with mode: 0644]
lunaix-os/tests/units/device-tree/.gitignore [new file with mode: 0644]
lunaix-os/tests/units/device-tree/common.h [new file with mode: 0644]
lunaix-os/tests/units/device-tree/dut/changeling.c [new symlink]
lunaix-os/tests/units/device-tree/dut/devtree.h [new symlink]
lunaix-os/tests/units/device-tree/dut/dt.c [new symlink]
lunaix-os/tests/units/device-tree/dut/dt_interrupt.c [new symlink]
lunaix-os/tests/units/device-tree/dut/dtspec.c [new symlink]
lunaix-os/tests/units/device-tree/load.c [new file with mode: 0644]
lunaix-os/tests/units/device-tree/makefile [new file with mode: 0644]
lunaix-os/tests/units/device-tree/samples/basic.dts [new file with mode: 0644]
lunaix-os/tests/units/device-tree/samples/fdt-iter.dts [new file with mode: 0644]
lunaix-os/tests/units/device-tree/samples/fdt-mem.dts [new file with mode: 0644]
lunaix-os/tests/units/device-tree/samples/inheritence.dts [new file with mode: 0644]
lunaix-os/tests/units/device-tree/samples/interrupts.dts [new file with mode: 0644]
lunaix-os/tests/units/device-tree/samples/intrmap.dts [new file with mode: 0644]
lunaix-os/tests/units/device-tree/test-basic.c [new file with mode: 0644]
lunaix-os/tests/units/device-tree/test-fdt-iter.c [new file with mode: 0644]
lunaix-os/tests/units/device-tree/test-fdt-mem.c [new file with mode: 0644]
lunaix-os/tests/units/device-tree/test-inheritence.c [new file with mode: 0644]
lunaix-os/tests/units/device-tree/test-interrupts.c [new file with mode: 0644]
lunaix-os/tests/units/device-tree/test-intrmap.c [new file with mode: 0644]
lunaix-os/tests/units/device-tree/tests.txt [new file with mode: 0644]
lunaix-os/tests/units/makefile [new file with mode: 0644]
lunaix-os/tests/units/stubs/includes/klibc/string.h [new file with mode: 0644]
lunaix-os/tests/units/stubs/includes/lunaix/owloysius.h [new file with mode: 0644]
lunaix-os/tests/units/stubs/klibc/hash.c [new symlink]
lunaix-os/tests/units/stubs/makefile [new file with mode: 0644]
lunaix-os/tests/units/stubs/spike.c [new file with mode: 0644]
lunaix-os/tests/units/stubs/syslog.c [new file with mode: 0644]
lunaix-os/tests/units/stubs/valloc.c [new file with mode: 0644]
lunaix-os/tests/units/test_build.mkinc [new file with mode: 0644]

index ea16967ff3e01503e6c4b7a8ae3efdbf254ca73f..9a6b6a87ca5499c131b731a1928866ae267e6895 100644 (file)
@@ -9,6 +9,7 @@
 !scripts
 !usr
 !link
 !scripts
 !usr
 !link
+!tests
 
 !.gitignore
 !*.md
 
 !.gitignore
 !*.md
index 0bd4dda3f601c1df146f6a5d7b067b7931e7fbb6..0d4a15a5ed11e824807f0faec1be4996e8482557 100644 (file)
@@ -94,7 +94,7 @@ isrm_msi_alloc_simple(struct device* dev, cpu_t cpu, isr_cb handler)
  * @param node
  */
 int
  * @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
 
 /**
  * @brief Get the handler associated with the given iv
index fefc33e2dcfba4a0f074d4c0f6e608767d66873a..86eec04593d45652d8cdae9885e01fe820be80b5 100644 (file)
@@ -211,7 +211,7 @@ isrm_msi_done(msienv_t msienv)
 
 
 int
 
 
 int
-isrm_bind_dtn(struct dt_intr_node* node)
+isrm_bind_dtn(struct dtn_intr* node)
 {
     fail("not supported");
 }
 {
     fail("not supported");
 }
index 4709a35a1b0901e9e0b2e57fe46bec022ecc1ef8..97f3109f78589eaa5b7cc2017f33fd0e349b0395 100644 (file)
@@ -2,4 +2,5 @@ sources([
     "dt_interrupt.c",
     "dt.c",
     "dtm.c"
     "dt_interrupt.c",
     "dt.c",
     "dtm.c"
+    "dtspec.c"
 ])
\ No newline at end of file
 ])
\ No newline at end of file
index c2374c82820d05d2352b28e12d0038d8ab455432..1bfe891b5b2540a3adcb9443bfde5a9560278f52 100644 (file)
@@ -6,42 +6,25 @@
 #include <klibc/string.h>
 
 static inline bool
 #include <klibc/string.h>
 
 static inline bool
-propeq(struct fdt_iter* it, const char* key)
+propeq(struct fdt_blob* fdt, fdt_loc_t loc, const char* key)
 {
 {
-    return streq(fdtit_prop_key(it), key);
+    return streq(fdt_prop_key(fdt, loc), key);
 }
 
 static inline void
 }
 
 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
 }
 
 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
 }
 
 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 */
 
 #endif /* __LUNAIX_DEVTREE_H */
index f1d68608e5d883798aea4cc3c44f0e2a671b9c13..a4265512c5e7effc6d39f7a30821189e33239c4b 100644 (file)
@@ -9,152 +9,317 @@ LOG_MODULE("dtb")
 static morph_t* devtree_obj_root;
 static struct dt_context dtctx;
 
 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
 }
 
 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;
     }
 
         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
     {
     do
     {
-        if (fdt_nope(current)) {
+        if (!fdt_prop(loc.token)) {
             continue;
         }
 
             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;
         }
         
             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
 }
 
 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;
     }
 
         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
 }
 
 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;
         }
         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
 }
 
 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 {
     }
 
     else {
@@ -203,17 +364,17 @@ __parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node)
 }
 
 static bool
 }
 
 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;
     }
 
         node->dma_coherent = true;
     }
 
-    else if (propeq(it, "dma-noncoherent")) {
+    else if (propeq(fdt, loc, "dma-noncoherent")) {
         node->dma_ncoherent = true;
     }
 
         node->dma_ncoherent = true;
     }
 
-    else if (propeq(it, "interrupt-controller")) {
+    else if (propeq(fdt, loc, "interrupt-controller")) {
         node->intr_controll = true;
     }
 
         node->intr_controll = true;
     }
 
@@ -225,18 +386,20 @@ __parse_stdflags(struct fdt_iter* it, struct dt_node_base* node)
 }
 
 static inline void
 }
 
 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
 {
     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);
 
     propt = valloc(sizeof(*propt));
     hashtable_init(propt->_op_bucket);
+
+    node->props = propt;
 }
 
 #define prop_table_add(node, prop)                                             \
 }
 
 #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
                               &(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));
     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));
 
     prop->key = HSTR(key, strlen(key));
-    __mkprop_ptr(it, &prop->val);
+    __mkprop_ptr(loc, &prop->val);
 
     hstr_rehash(&prop->key, HSTR_FULL_HASH);
 
 
     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
 }
 
 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;
     }
 
         return;
     }
 
-    if (__parse_stdbase_prop(it, &node->base)) {
+    if (__parse_stdbase_prop(fdt, loc, &node->base)) {
         return;
     }
 
         return;
     }
 
-    if (__parse_stdnode_prop(it, node)) {
+    if (__parse_stdnode_prop(fdt, loc, node)) {
         return;
     }
 
         return;
     }
 
-    if (parse_stdintr_prop(it, &node->intr)) {
+    if (parse_stdintr_prop(fdt, loc, &node->intr)) {
         return;
     }
 
         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
 }
 
 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
 }
 
 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
     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;
         }
 
             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()
 {
 }
 
 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)
     {
     dt_phnd_t phnd;
     
     llist_for_each(pos, n, &dtctx.nodes, nodes)
     {
-        node = BASE_TO_DTNODE(pos);
+        node = dtn_from(pos);
         intrupt = &node->intr;
 
         intrupt = &node->intr;
 
-        if (!node->base.intr_c) {
+        if (intrupt->parent_hnd == PHND_NULL) {
             continue;
         }
 
         phnd = intrupt->parent_hnd;
             continue;
         }
 
         phnd = intrupt->parent_hnd;
-        default_parent = (struct dt_node*)node->base.parent;
+        default_parent = (struct dtn*)node->base.parent;
         parent = default_parent;
 
         if (phnd != PHND_NULL) {
         parent = default_parent;
 
         if (phnd != PHND_NULL) {
@@ -404,7 +546,7 @@ __resolve_phnd_references()
             parent = default_parent;
         }
 
             parent = default_parent;
         }
 
-        intrupt->parent = &parent->intr;
+        intrupt->parent = parent;
 
         __expand_extended_intr(intrupt);
     }
 
         __expand_extended_intr(intrupt);
     }
@@ -413,100 +555,98 @@ __resolve_phnd_references()
 static void
 __resolve_inter_map()
 {
 static void
 __resolve_inter_map()
 {
-    struct dt_node_base *pos, *n;
+    struct dtn_base *pos, *n;
 
     llist_for_each(pos, n, &dtctx.nodes, nodes)
     {
 
     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)
 {
     }
 }
 
 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);
 
     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;
         }
 
             // 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();
 
 
     __resolve_phnd_references();
     __resolve_inter_map();
 
-    INFO("device tree loaded");
+    INFO("%d nodes loaded.", nr_nodes);
 
     return true;
 }
 
 
     return true;
 }
 
-struct dt_node*
+struct dtn*
 dt_resolve_phandle(dt_phnd_t phandle)
 {
 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) {
     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
 }
 
 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);
 {
     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
 }
 
 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(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_predicate_t pred, void* closure)
 {
-    node = node ? : (struct dt_node*)dtctx.root;
+    node = node ? : (struct dtn*)dtctx.root;
 
     iter->head = &node->base;
     iter->matched = NULL;
 
     iter->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;
     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;
     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
 }
 
 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;
     }
 
 {
     if (!dt_found_any(iter)) {
         return false;
     }
 
-    struct dt_node *node;
+    struct dtn *node;
     morph_t *pos, *head;
 
     head = dt_mobj(iter->head);
     morph_t *pos, *head;
 
     head = dt_mobj(iter->head);
@@ -593,11 +733,11 @@ dt_find_next(struct dt_node_iter* iter,
     return false;
 }
 
     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 hstr hashed_name;
-    struct dt_prop *pos, *n;
+    struct dtp *pos, *n;
     unsigned int hash;
 
     hashed_name = HSTR(name, strlen(name));
     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;
 }
 
     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()
 {
 struct dt_context*
 dt_main_context()
 {
index ab4d8b36dcf58e43f6d569cf30a6c3eea26cfdc9..905eb0243461588c15c4145cb8c1c1a5a7fb05b3 100644 (file)
 #include "devtree.h"
 
 #include <lunaix/mm/valloc.h>
 #include "devtree.h"
 
 #include <lunaix/mm/valloc.h>
-
 #include <klibc/string.h>
 
 #include <klibc/string.h>
 
-static struct dt_intr_map*
-__get_map(struct dt_intr_node* node)
-{
-    if (!node->map) {
-        node->map = valloc(sizeof(struct dt_intr_map));
-        
-        node->map->resolved = false;
-        llist_init_head(&node->map->mapent);
-
-        INTR_TO_DTNODE(node)->base.intr_neuxs = true;
-    }
-
-    return node->map;
-}
-
-static void
-__prepare_key(struct dt_intr_mapkey* key, 
-              dt_enc_t key_raw, unsigned int keylen)
+static int 
+__ispec_sz(struct dtn* node)
 {
 {
-    *key = (struct dt_intr_mapkey) {
-        .val = valloc(keylen * sizeof(int)),
-        .size = keylen
-    };
-
-    memcpy(key->val, key_raw, keylen * sizeof(int));
-}
-
-static inline void
-__destory_key(struct dt_intr_mapkey* key)
-{
-    vfree(key->val);
+    return node->base.intr_c + node->base.addr_c;
 }
 
 }
 
-static inline unsigned int
-__interrupt_keysize(struct dt_node_base* base)
+static struct dtp_val*
+__ispec_mask(struct dtn* node)
 {
 {
-    return dt_size_cells(base) + base->intr_c;
-}
-
-static void
-__mask_key(struct dt_intr_mapkey* k, struct dt_intr_mapkey* mask)
-{
-    for (unsigned int i = 0; i < k->size; i++)
-    {
-        k->val[i] &= mask->val[i];
-    }
-}
-
-static bool
-__compare_key(struct dt_intr_mapkey* k1, struct dt_intr_mapkey* k2)
-{
-    if (k1->size != k2->size) {
-        return false;
-    }
-
-    for (unsigned int i = 0; i < k1->size; i++)
-    {
-        if (k1->val[i] != k2->val[i]) {
-            return false;
-        }    
-    }
-    
-    return true;
-}
-
-static struct dt_node_base*
-__get_connected_nexus(struct dt_node_base* base)
-{
-    struct dt_node_base* current;
-
-    current = base;
-    while (current && !current->intr_neuxs) {
-        current = current->parent;
-    }
-
-    return current;
+    return dt_getprop(&node->base, "interrupt-map-mask");
 }
 
 void
 }
 
 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;
     }
 
         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;
     }
         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
     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;
     }
 
     }
 
     else {
         return false;
     }
 
+    node->valid = true;
     return true;
 }
\ No newline at end of file
     return true;
 }
\ No newline at end of file
index 69ec2e5a66a3b10c197404419faf7df395b9ba0f..7bec48906da51fd336eef05a8ec84c9c38537197 100644 (file)
@@ -104,7 +104,7 @@ __try_match(const char* str, const char* pattern, size_t pat_sz)
 }
 
 static struct device_meta*
 }
 
 static struct device_meta*
-__try_create_categorical(struct dt_node_base *p)
+__try_create_categorical(struct dtn_base *p)
 {
     if (!p) return NULL;
 
 {
     if (!p) return NULL;
 
@@ -130,7 +130,7 @@ __try_create_categorical(struct dt_node_base *p)
 }
 
 static bool
 }
 
 static bool
-compat_matched(struct dtm_driver_record* rec, struct dt_node_base *base)
+compat_matched(struct dtm_driver_record* rec, struct dtn_base *base)
 {
     const char *compat;
     struct dtm_driver_info *p, *n;
 {
     const char *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;
     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();
 
     
     dtctx = dt_main_context();
 
diff --git a/lunaix-os/hal/devtree/dtspec.c b/lunaix-os/hal/devtree/dtspec.c
new file mode 100644 (file)
index 0000000..f70f4d2
--- /dev/null
@@ -0,0 +1,138 @@
+#include "devtree.h"
+#include <lunaix/mm/valloc.h>
+
+#define key_mkwr(key)   \
+            (struct dtspec_key*)(key)
+#define call_op(dtn, ops, name)    \
+            ((ops)->name ? (ops)->name(dtn) : NULL)
+
+struct dtspec_map*
+dtspec_create(struct dtn* node, struct dtp_val* map,
+              const struct dtspec_create_ops* ops)
+{
+    struct dtpropi it;
+    struct dtspec_map* spec;
+    struct dtspec_mapent* ent;
+    struct dtp_val val = {}, *field;
+    int keysz, p_keysz;
+
+    assert(ops->child_keysz);
+    assert(ops->parent_keysz);
+
+    keysz = ops->child_keysz(node);
+    spec = vzalloc(sizeof(*spec));
+
+    field = call_op(node, ops, get_mask);
+    if (field) {
+        dtp_speckey(key_mkwr(&spec->mask), field);
+    }
+
+    field = call_op(node, ops, get_passthru);
+    if (field) {
+        dtp_speckey(key_mkwr(&spec->pass_thru), field);
+    }
+    
+    llist_init_head(&spec->ents);
+
+    dtpi_init(&it, map);
+    while (dtpi_has_next(&it))
+    {
+        ent = vzalloc(sizeof(*ent));
+
+        dtpi_next_val(&it, &val, keysz);
+        dtp_speckey(key_mkwr(&ent->child_spec), &val);
+
+        ent->parent = dtpi_next_hnd(&it);
+        p_keysz = ops->parent_keysz(ent->parent);
+
+        dtpi_next_val(&it, &val, p_keysz);
+        dtp_speckey(key_mkwr(&ent->parent_spec), &val);
+
+        changeling_ref(dt_mobj(ent->parent));
+        llist_append(&spec->ents, &ent->ents);
+    }
+
+    return spec;
+}
+
+static bool
+__try_match(struct dtspec_key* given, struct dtspec_key* against)
+{
+    for (unsigned int i = 0; i < given->size; i++)
+    {
+        if (given->val[i] != against->val[i])
+            return false;
+    }
+    
+    return true;
+}
+
+struct dtspec_mapent*
+dtspec_lookup(struct dtspec_map* map, struct dtspec_key* key)
+{
+    struct dtspec_mapent *pos, *n;
+    struct dtspec_key scratch = {};
+
+    dtspec_cpykey(&scratch, key);
+    dtspec_applymask(map, &scratch);
+
+    llist_for_each(pos, n, &map->ents, ents)
+    {
+        if (__try_match(&scratch, &pos->child_spec))
+        {
+            dtspec_freekey(&scratch);
+            return pos;
+        }
+    }
+
+    dtspec_freekey(&scratch);
+    return NULL;
+}
+
+void
+dtspec_applymask(struct dtspec_map* map, struct dtspec_key* key)
+{
+    for (unsigned int i = 0; i < map->mask.size; i++)
+    {
+        key->val[i] &= map->mask.val[i];
+    }
+}
+
+void
+dtspec_free(struct dtspec_map* map)
+{
+    struct dtspec_mapent *pos, *n;
+    
+    llist_for_each(pos, n, &map->ents, ents)
+    {
+        changeling_unref(dt_mobj(pos->parent));
+        vfree(pos);
+    }
+
+    vfree(map);
+}
+
+void
+dtspec_cpykey(struct dtspec_key* dest, struct dtspec_key* src)
+{    
+    if (dtspec_nullkey(src)) {
+        return;
+    }
+
+    int sz = sizeof(int) * src->size;
+
+    dest->val = valloc(sz);
+    dest->size = src->size;
+    memcpy(dest->val, src->val, sz);
+}
+
+void
+dtspec_freekey(struct dtspec_key* key)
+{
+    if (dtspec_nullkey(key)) {
+        return;
+    }
+
+    vfree(key->val);
+    key->size = 0;
+}
\ No newline at end of file
index 7b02ca5810a026c0942f4366b09c2e51f4ec8063..e7e0cf37ce0a32c36ece6877426e7db109ec8ab2 100644 (file)
@@ -5,45 +5,68 @@
 #include <lunaix/ds/llist.h>
 #include <lunaix/ds/hstr.h>
 #include <lunaix/ds/hashtable.h>
 #include <lunaix/ds/llist.h>
 #include <lunaix/ds/hstr.h>
 #include <lunaix/ds/hashtable.h>
-#include <lunaix/boot_generic.h>
 #include <lunaix/changeling.h>
 
 #include <klibc/string.h>
 
 #include <lunaix/changeling.h>
 
 #include <klibc/string.h>
 
-#define le(v) ((((v) >> 24) & 0x000000ff)  |\
-               (((v) << 8)  & 0x00ff0000)  |\
-               (((v) >> 8)  & 0x0000ff00)  |\
-               (((v) << 24) & 0xff000000))
-
-#define le64(v) (((u64_t)le(v & 0xffffffff) << 32) | le(v >> 32))
-
-#define be(v) ((((v) << 24) & 0x000000ff)  |\
-               (((v) >> 8)  & 0x00ff0000)  |\
-               (((v) << 8)  & 0x0000ff00)  |\
-               (((v) >> 24) & 0xff000000))
-
-#define FDT_MAGIC       be(0xd00dfeed)
-#define FDT_NOD_BEGIN   be(0x00000001)
-#define FDT_NOD_END     be(0x00000002)
-#define FDT_PROP        be(0x00000003)
-#define FDT_NOP         be(0x00000004)
-#define FDT_END         be(0x00000009)
+#define FDT_MAGIC       0xd00dfeedU
+#define FDT_NOD_BEGIN   0x00000001U
+#define FDT_NOD_END     0x00000002U
+#define FDT_PROP        0x00000003U
+#define FDT_NOP         0x00000004U
+#define FDT_END         0x00000009U
 
 #define STATUS_OK       0
 #define STATUS_DISABLE  1
 #define STATUS_RSVD     2
 #define STATUS_FAIL     3
 
 
 #define 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;
 
 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;
     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;
 
 struct fdt_memrsvd_ent 
 {
     u64_t addr;
     u64_t size;
-} align(8);
+} _be align(8);
+
 
 struct fdt_token 
 {
     u32_t token;
 
 struct fdt_token 
 {
     u32_t token;
-} compact align(4);
+} _be compact align(4);
 
 
-struct fdt_node_head
+struct fdt_prop
 {
     struct fdt_token token;
 {
     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 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];
 {
     union {
         struct hbucket    other_props[0];
@@ -121,7 +228,7 @@ struct dt_prop_table
     };
 };
 
     };
 };
 
-struct dt_node_base
+struct dtn_base
 {
     morph_t mobj;
 
 {
     morph_t mobj;
 
@@ -140,254 +247,265 @@ struct dt_node_base
             bool dma_coherent  : 1;
             bool dma_ncoherent : 1;
             bool intr_controll : 1;
             bool dma_coherent  : 1;
             bool dma_ncoherent : 1;
             bool intr_controll : 1;
-            bool intr_neuxs    : 1;
         };
         unsigned int    flags;
     };
 
         };
         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 {
 {
     union {
-        struct dt_intr_node *parent;
+        struct dtn *parent;
         dt_phnd_t parent_hnd;
     };
 
         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;
 {
     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
 {
 };
 
 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
 
 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*
 
 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);
 
 
 bool
 dt_load(ptr_t dtb_dropoff);
 
-struct dt_node*
+struct dtn*
 dt_resolve_phandle(dt_phnd_t phandle);
 
 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
 
 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
 
 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
 
 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
               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
 {
     // 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
 
 static inline bool
-dt_found_any(struct dt_node_iter* iter)
+dt_found_any(struct dtn_iter* iter)
 {
     return !!iter->matched;
 }
 {
     return !!iter->matched;
 }
@@ -395,187 +513,218 @@ dt_found_any(struct dt_node_iter* iter)
 struct dt_context*
 dt_main_context();
 
 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; \
 
 #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])
 
              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 */
 }
 
 #endif /* __LUNAIX_DEVTREE_H */
index c8d10c2f094f644fdd0a06adcf3083d63c1bc060..2b0904d6babf6d257873d3a4eab4773d70032e1b 100644 (file)
@@ -11,7 +11,7 @@ struct device;
 #include <lunaix/ds/list.h>
 #include <klibc/hash.h>
 
 #include <lunaix/ds/list.h>
 #include <klibc/hash.h>
 
-typedef struct dt_node* devtree_link_t;
+typedef struct dtn* devtree_link_t;
 
 #define dt_node_morpher     morphable_attrs(dt_node, mobj)
 
 
 #define dt_node_morpher     morphable_attrs(dt_node, mobj)
 
index 1e26576a42a754843d5a28110c311f942c91c58c..aecd7d4d2446d820d0974b9098427996c7a76506 100644 (file)
@@ -1,4 +1,4 @@
-morphable(dt_node),
+morphable(dtn),
 morphable(pci_probe),
 
 morphable(device_meta),
 morphable(pci_probe),
 
 morphable(device_meta),
index b9188eca8d5522effe2c6536e0915da40f320cef..a8f5c73763c0304e30761da79d36c4bfedbf5114 100644 (file)
@@ -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 morphable_attrs(struct_name, field)     struct_name, field
 #define morphed_ptr(ptr_like)                   ((morph_t*)__ptr(ptr_like))
 #define morpher_uid(mobj)                       ((mobj)->uid)
+#define morpher_name(mobj)                      ((mobj)->name.value)
 
 #define __changeling_morph(parent, chlg, name, struct_name, field)             \
     ({                                                                         \
 
 #define __changeling_morph(parent, chlg, name, struct_name, field)             \
     ({                                                                         \
index ffc73c885e33a7beba59d4a4c43e1be68cbffe1c..a41c741b6dd111d5685e41b4fca3922169cee2e6 100644 (file)
@@ -14,6 +14,9 @@
 #define unreachable             __builtin_unreachable()
 #define no_inline               __attribute__((noinline))
 
 #define unreachable             __builtin_unreachable()
 #define no_inline               __attribute__((noinline))
 
+#define _be                     __attribute__((scalar_storage_order ("big-endian")))
+#define _le                     __attribute__((scalar_storage_order ("little-endian")))
+
 #define _default                _weak
 
 #define msbiti                  (sizeof(int) * 8 - 1)
 #define _default                _weak
 
 #define msbiti                  (sizeof(int) * 8 - 1)
index 169f0b8eccb0de6ad0c795cb4ffe02041f660e4c..77096aa8a845f6c35dbb0d0152bb94f61734dd1c 100644 (file)
@@ -30,7 +30,7 @@ struct hstr
 #define HSTR_LEN(hstr)  ((hstr).len)
 #define HSTR_HASH(hstr) ((hstr).hash)
 
 #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);
 hstr_rehash(struct hstr* hash_str, u32_t truncate_to)
 {
     hash_str->hash = strhash_32(hash_str->value, truncate_to);
index 1fcb3cc2436ae39541363f148e674b75521119ee..9895780868e743be2f6d6d8e3376899706df1a66 100644 (file)
@@ -70,7 +70,12 @@ clean-user:
 clean:
        @$(MAKE) $(MKFLAGS) -C usr clean -I $(mkinc_dir)
        @$(MAKE) $(MKFLAGS) -C scripts clean -I $(mkinc_dir)
 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
        @$(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 (file)
index 0000000..d5a2715
--- /dev/null
@@ -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 (file)
index 0000000..a81dc4f
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef __COMMON_TEST_BASIC_H
+#define __COMMON_TEST_BASIC_H
+
+#include <stdio.h>
+#include "strutils.h"
+
+struct test_context
+{
+    const char* name;
+
+    struct {
+        union {
+            struct {
+                int passed;
+                int failed;
+            };
+            int countings[2];
+        };
+
+        union {
+            struct {
+                int total_passed;
+                int total_failed;
+            };
+            int total_countings[2];
+        };
+    } stats;
+};
+
+#define fmt_passed  "[\x1b[32;49mPASS\x1b[0m]"
+#define fmt_failed  "[\x1b[31;49mFAIL\x1b[0m]"
+
+#define active_context      \
+    ({ extern struct test_context* __test_ctx; __test_ctx; })
+
+#define _expect(expr, act, exp, type_fmt)                                   \
+    do {                                                                    \
+        int failed = !(expr);                                               \
+        printf("  @%s:%03d ....... ", __FILE__, __LINE__);                    \
+        if (failed)                                                         \
+            printf(fmt_failed " (expect: " type_fmt ", got: " type_fmt ")\n",\
+                    exp, act);                                              \
+        else                                                                \
+            printf(fmt_passed "\n");                                       \
+        active_context->stats.countings[failed]++;                          \
+    } while(0)
+
+#define new_aspect(expr, exp, act, typefmt)    expr, exp, act, typefmt
+
+#define expect(aspect)  _expect(aspect)
+
+#define expect_int(a, b)  \
+    _expect(a == b, a, b, "%d")
+
+#define expect_uint(a, b) \
+    _expect(a == b, a, b, "%u")
+
+#define expect_long(a, b) \
+    _expect(a == b, a, b, "%ld")
+
+#define expect_ulong(a, b) \
+    _expect(a == b, a, b, "%lu")
+
+#define expect_str(str_a, str_b)  \
+    _expect(!strcmp(str_a, str_b), str_a, str_b, "'%s'")
+
+#define expect_notnull(ptr)  \
+    _expect(ptr != NULL, "null", "not null", "<%s>")
+
+#define expect_null(ptr)  \
+    _expect(ptr == NULL, "not null", "null", "<%s>")
+
+#define expect_true(val)  \
+    _expect(val, "false", "true", "<%s>")
+
+#define expect_false(val)  \
+    _expect(!val, "true", "false", "<%s>")
+
+#define testcase(name, body)    \
+    do { begin_testcase(name); body; end_testcase(); } while(0)
+
+void
+begin_testcase(const char* name);
+
+void
+end_testcase();
+
+void 
+run_test(int argc, const char* argv[]);
+
+#endif /* __COMMON_TEST_BASIC_H */
diff --git a/lunaix-os/tests/includes/testing/strutils.h b/lunaix-os/tests/includes/testing/strutils.h
new file mode 100644 (file)
index 0000000..978d52a
--- /dev/null
@@ -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 (file)
index 0000000..ad1aebc
--- /dev/null
@@ -0,0 +1,50 @@
+#include <testing/basic.h>
+#include <stdlib.h>
+
+struct test_context* __test_ctx;
+
+void 
+main(int argc, const char* argv[])
+{
+    __test_ctx = calloc(sizeof(*__test_ctx), 1);
+
+    printf("\n");
+
+    run_test(argc, argv);
+
+    printf(
+        "All test done: %d passed, %d failed\n",
+        __test_ctx->stats.total_passed,
+        __test_ctx->stats.total_failed
+    );
+    printf("************\n\n");
+
+    exit(__test_ctx->stats.total_failed > 0);
+}
+
+void
+begin_testcase(const char* name)
+{
+    if (__test_ctx->name) {
+        printf("previous test case: '%s' is still actuive\n", name);
+        exit(1);
+    }
+
+    __test_ctx->name = name;
+    __test_ctx->stats.countings[0] = 0;
+    __test_ctx->stats.countings[1] = 0;
+
+    printf("%s\n", name);
+}
+
+void
+end_testcase()
+{
+    printf("..... passed: %d, failed: %d\n\n", 
+            __test_ctx->stats.passed, __test_ctx->stats.failed);
+
+    __test_ctx->stats.total_passed += __test_ctx->stats.passed;
+    __test_ctx->stats.total_failed += __test_ctx->stats.failed;
+    __test_ctx->name = NULL;
+
+}
\ No newline at end of file
diff --git a/lunaix-os/tests/shared/makefile b/lunaix-os/tests/shared/makefile
new file mode 100644 (file)
index 0000000..0484be2
--- /dev/null
@@ -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 (file)
index 0000000..06e925a
--- /dev/null
@@ -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 (file)
index 0000000..94c2370
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __DTTEST_COMMON_H
+#define __DTTEST_COMMON_H
+
+#define __off_t_defined
+#include "dut/devtree.h"
+
+#include <lunaix/types.h>
+
+bool
+my_load_dtb();
+
+ptr_t
+load_fdt();
+
+#endif /* __DTTEST_COMMON_H */
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 (symlink)
index 0000000..a42dd8d
--- /dev/null
@@ -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 (symlink)
index 0000000..8bb6ea5
--- /dev/null
@@ -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 (symlink)
index 0000000..2fdda30
--- /dev/null
@@ -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 (symlink)
index 0000000..8e3f1ed
--- /dev/null
@@ -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 (symlink)
index 0000000..3f14cce
--- /dev/null
@@ -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 (file)
index 0000000..f97765e
--- /dev/null
@@ -0,0 +1,46 @@
+#include "common.h"
+
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define MAX_DTB_SZ (2 * 1024 * 1024)
+
+#ifndef TEST_DTBFILE
+#warning "no test dtb file given"
+#define TEST_DTBFILE ""
+#endif
+
+extern void init_export___init_devtree();
+
+ptr_t
+load_fdt()
+{
+    int fd = open(TEST_DTBFILE, O_RDONLY);
+    if (fd == -1) {
+        printf("fail to open: %s, %s\n", TEST_DTBFILE, strerror(errno));
+        return false;
+    }
+
+    ptr_t dtb = (ptr_t)mmap(0, 
+                            MAX_DTB_SZ, 
+                            PROT_READ | PROT_WRITE | MAP_POPULATE, 
+                            MAP_PRIVATE, fd, 0);
+    
+    if (dtb == (ptr_t)-1) {
+        printf("fail to map dtb: %s\n", strerror(errno));
+        _exit(1);
+    }
+
+    close(fd);
+    return dtb;
+}
+
+bool
+my_load_dtb()
+{
+    init_export___init_devtree();
+    return dt_load(load_fdt());
+}
\ No newline at end of file
diff --git a/lunaix-os/tests/units/device-tree/makefile b/lunaix-os/tests/units/device-tree/makefile
new file mode 100644 (file)
index 0000000..4d9d530
--- /dev/null
@@ -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 (file)
index 0000000..076e17d
--- /dev/null
@@ -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 (file)
index 0000000..63c9a37
--- /dev/null
@@ -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 (file)
index 0000000..dcc3adb
--- /dev/null
@@ -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 (file)
index 0000000..a7f14f8
--- /dev/null
@@ -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 (file)
index 0000000..7be57b5
--- /dev/null
@@ -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 (file)
index 0000000..d475a0d
--- /dev/null
@@ -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 (file)
index 0000000..b5ea931
--- /dev/null
@@ -0,0 +1,175 @@
+#include "common.h"
+#include <testing/basic.h>
+#include <unistd.h>
+
+static inline struct dtn* 
+validate_node(struct dt_context* ctx, 
+              const char* name, const char* compat)
+{
+    struct dtn_iter it;
+    struct dtn* node = ctx->root;
+
+    
+    dt_begin_find_byname(&it, node, name);
+    
+    node = (struct dtn*)it.matched;
+
+    expect_notnull(node);
+    expect_str(node->base.compat.str_val, compat);
+    expect_int(node->base.addr_c, 1);
+    expect_int(node->base.sz_c, 2);
+
+    return node;
+}
+
+static void
+testcase_rootfield(struct dt_context* ctx)
+{
+    struct dtn* node = ctx->root;
+
+    begin_testcase("root");
+
+    expect_str(node->base.compat.str_val, "root");
+    expect_int(node->base.addr_c, 1);
+    expect_int(node->base.sz_c, 2);
+
+    end_testcase();
+}
+
+static void
+testcase_child1(struct dt_context* ctx)
+{
+    struct dtn* node;
+    struct dtp_val* val;
+
+    begin_testcase("trivial-props");
+    
+    node = validate_node(ctx, "child@1", "child,simple-fields");
+
+    val = dt_getprop(&node->base, "field-str");
+    expect_notnull(val);
+    expect_str(val->str_val, "field");
+
+    val = dt_getprop(&node->base, "field-u32");
+    expect_notnull(val);
+    expect_int(dtp_u32(val), 32);
+
+    val = dt_getprop(&node->base, "field-u64");
+    expect_notnull(val);
+    expect_ulong(dtp_u64(val), (0xfUL << 32 | 0x1));
+
+    val = dt_getprop(&node->base, "field-strlst");
+    expect_notnull(val);
+
+    char* str;
+    int i = 0;
+    const char *expected[] = {"str1", "str2", "str3"};
+    dtprop_strlst_foreach(str, val) {
+        expect_str(str, expected[i]);
+        i++;
+    }
+
+    end_testcase();
+}
+
+static void
+testcase_child2(struct dt_context* ctx)
+{
+    struct dtn* node;
+    struct dtpropx propx;
+    struct dtprop_xval val;
+    struct dtp_val* prop;
+    
+    begin_testcase("dtpx-reg");
+    
+    node = validate_node(ctx, "child@2", "child,encoded-array");
+
+    dt_proplet reg = { dtprop_u32, dtprop_u64, dtprop_end };
+
+    dtpx_compile_proplet(reg);
+    dtpx_prepare_with(&propx, &node->reg, reg);
+    
+    expect_true(dtpx_extract_at(&propx, &val, 0));
+    expect_int(val.u32, 0x12345);
+
+    expect_true(dtpx_extract_at(&propx, &val, 1));
+    expect_ulong(val.u64, (0x1UL << 32) | 0x2UL);
+
+    expect_false(dtpx_extract_at(&propx, &val, 2));
+    expect_false(dtpx_goto_row(&propx, 1));
+
+    end_testcase();
+    
+
+    begin_testcase("dtpx-mixed");
+
+    struct dtprop_xval xvals[5];
+    dt_proplet mixed_array = { 
+        dtprop_handle, dtprop_u32, dtprop_u32, dtprop_u32, dtprop_u32,
+        dtprop_end
+    };
+
+    prop = dt_getprop(&node->base, "mixed_array");
+    expect_notnull(prop);
+
+    dtpx_compile_proplet(mixed_array);
+    dtpx_prepare_with(&propx, prop, mixed_array);
+
+    expect_true(dtpx_extract_row(&propx, xvals, 5));
+    
+    expect_notnull(xvals[0].phandle);
+    expect_str(morpher_name(dt_mobj(xvals[0].phandle)), "child@1");
+    expect_int(xvals[1].u32, 1);
+    expect_int(xvals[2].u32, 3);
+    expect_int(xvals[3].u32, 5);
+    expect_int(xvals[4].u32, 7);
+
+    expect_true(dtpx_next_row(&propx));
+    expect_true(dtpx_extract_row(&propx, xvals, 5));
+
+    expect_notnull(xvals[0].phandle);
+    expect_str(morpher_name(dt_mobj(xvals[0].phandle)), "child@3");
+    expect_int(xvals[1].u32, 2);
+    expect_int(xvals[2].u32, 4);
+    expect_int(xvals[3].u32, 6);
+    expect_int(xvals[4].u32, 8);
+
+    end_testcase();
+}
+
+static void
+testcase_child3(struct dt_context* ctx)
+{
+    struct dtn* node;
+    struct dtpropx propx;
+    struct dtprop_xval val;
+    struct dtp_val* prop;
+    
+    begin_testcase("simple-flags");
+    
+    node = validate_node(ctx, "child@3", "child,flags");
+
+    expect_true(node->base.dma_coherent);
+    expect_true(node->base.intr_controll);
+    expect_int(node->base.status, STATUS_DISABLE);
+
+    end_testcase();
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+
+    if(!my_load_dtb()) {
+        printf("failed to load dtb\n");
+        _exit(1);
+    }
+
+    struct dt_context* ctx;
+    ctx = dt_main_context();
+
+    testcase_rootfield(ctx);
+    testcase_child1(ctx);
+    testcase_child3(ctx);
+    testcase_child2(ctx);
+}
\ No newline at end of file
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 (file)
index 0000000..ac53667
--- /dev/null
@@ -0,0 +1,175 @@
+#include "common.h"
+#include <testing/basic.h>
+
+static void
+test_fdt_basic_iter(ptr_t dtb)
+{
+    struct fdt_blob fdt;
+    fdt_loc_t loc;
+    int depth = 0;
+
+    fdt_load(&fdt, dtb);
+    loc = fdt.root;
+
+    testcase("iter-child1", {
+        loc = fdt_next_token(loc, &depth);
+        
+        expect_int(depth, 1);
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@1");
+    });
+
+    testcase("iter-child1-prop", {
+        loc = fdt_next_token(loc, &depth);
+        
+        expect_int(depth, 1);
+        expect_true(fdt_prop(loc.token));
+        expect_str(fdt_prop_key(&fdt, loc), "prop-child1");
+    });
+
+    testcase("iter-child1-end", {
+        loc = fdt_next_token(loc, &depth);
+        
+        expect_int(depth, 0);
+        expect_true(fdt_node_end(loc.token));
+    });
+
+    testcase("iter-step-out", {
+        loc = fdt_next_token(loc, &depth);
+        
+        expect_int(depth, -1);
+        expect_true(fdt_node(loc.token));
+        expect_str(loc.node->name, "child@2");
+    });
+}
+
+static void
+test_fdt_sibling_iter(ptr_t dtb)
+{
+    struct fdt_blob fdt;
+    fdt_loc_t loc;
+    int depth = 0;
+
+    fdt_load(&fdt, dtb);
+    loc = fdt.root;
+
+    loc = fdt_descend_into(loc);
+
+    testcase("sibling-iter-1", {
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@1");
+    });
+
+    testcase("sibling-iter-2", {
+        expect_true(fdt_next_sibling(loc, &loc));
+
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@2");
+    });
+
+    testcase("sibling-iter-3", {
+        expect_true(fdt_next_sibling(loc, &loc));
+
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@3");
+    });
+
+    testcase("sibling-iter-3", {
+        expect_false(fdt_next_sibling(loc, &loc));
+
+        expect_true(fdt_node_end(loc.token));
+    });
+}
+
+static void
+test_fdt_descend_ascend(ptr_t dtb)
+{
+    struct fdt_blob fdt;
+    fdt_loc_t loc;
+    int depth = 0;
+
+    fdt_load(&fdt, dtb);
+    loc = fdt.root;
+
+    testcase("descend-to-child1", {
+        loc = fdt_descend_into(loc);
+
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@1");
+    });
+
+    testcase("goto-child2", {
+        expect_true(fdt_next_sibling(loc, &loc));
+
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@2");
+
+        loc = fdt_descend_into(loc);
+        
+        expect_int(loc.token->token, FDT_PROP);
+        expect_str(fdt_prop_key(&fdt, loc), "prop-child2");
+    });
+
+    testcase("descend-on-prop", {
+        loc = fdt_descend_into(loc);
+
+        expect_true(loc.ptr == loc.ptr);
+        expect_int(loc.token->token, FDT_PROP);
+        expect_str(fdt_prop_key(&fdt, loc), "prop-child2");
+    });
+
+    testcase("descend-to-child21", {
+        expect_true(fdt_next_sibling(loc, &loc));
+
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@21");
+    });
+
+    testcase("ascend", {
+        loc = fdt_ascend_from(loc);
+
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@3");
+    });
+
+    testcase("ascend-to-root", {
+        loc = fdt_ascend_from(loc);
+
+        expect_true(fdt_node_end(loc.token));
+    });
+}
+
+
+static void
+test_find_prop(ptr_t dtb)
+{
+    struct fdt_blob fdt;
+    fdt_loc_t loc;
+    struct dtp_val val;
+    int depth = 0;
+
+    fdt_load(&fdt, dtb);
+    loc = fdt.root;
+
+    testcase("prop-find-child1", {
+        loc = fdt_descend_into(loc);
+        expect_int(loc.token->token, FDT_NOD_BEGIN);
+        expect_str(loc.node->name, "child@1");
+
+        expect_true(fdt_find_prop(&fdt, loc, "prop-child1", &val));
+        expect_int(val.size, 0);
+
+        expect_false(fdt_find_prop(&fdt, loc, "prop-child2", &val));
+    });
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+    ptr_t dtb = load_fdt();
+
+    test_fdt_basic_iter(dtb);
+    test_fdt_descend_ascend(dtb);
+    test_fdt_sibling_iter(dtb);
+    test_find_prop(dtb);
+}
\ No newline at end of file
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 (file)
index 0000000..1537ab0
--- /dev/null
@@ -0,0 +1,95 @@
+#include "common.h"
+#include <testing/basic.h>
+
+static void
+test_fdt_memory_node(ptr_t dtb)
+{
+    struct fdt_blob fdt;
+    struct fdt_memscan mscan;
+    struct dt_memory_node mnode;
+
+    fdt_load(&fdt, dtb);
+    fdt_memscan_begin(&mscan, &fdt);
+
+    testcase("initial-state", {
+        expect_int(mscan.root_addr_c, 2);
+        expect_int(mscan.root_size_c, 1);
+    });
+
+    testcase("memory-node-1", {
+        expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+        expect_str(mscan.found.node->name, "memory@1000000");
+        expect_true(mscan.node_type == FDT_MEM_FREE);
+
+        expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+        expect_ulong(mnode.base, 0x1000000UL);
+        expect_ulong(mnode.size, 0x10000UL);
+
+        expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+        expect_ulong(mnode.base, 0x8000000UL);
+        expect_ulong(mnode.size, 0x10000UL);
+
+        expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+        expect_ulong(mnode.base, 0x1002000000UL);
+        expect_ulong(mnode.size, 0x200000UL);
+
+        expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+    });
+
+    testcase("memory-node-2", {
+        expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+        expect_str(mscan.found.node->name, "memory@f000000");
+        expect_true(mscan.node_type == FDT_MEM_FREE);
+
+        expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+        expect_ulong(mnode.base, 0xf000000UL);
+        expect_ulong(mnode.size, 0xff000UL);
+
+        expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+    });
+
+    testcase("reserved-node-1", {
+        expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+        expect_str(mscan.found.node->name, "hwrom@0");
+        expect_true(mscan.node_type == FDT_MEM_RSVD);
+        expect_true(mscan.node_attr.nomap);
+
+        expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+        expect_ulong(mnode.base, 0x0);
+        expect_ulong(mnode.size, 0x1000000);
+
+        expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+    });
+
+    testcase("reserved-node-2", {
+        expect_true(fdt_memscan_nextnode(&mscan, &fdt));
+
+        expect_str(mscan.found.node->name, "cma");
+        expect_true(mscan.node_type == FDT_MEM_RSVD_DYNAMIC);
+        expect_true(mscan.node_attr.reusable);
+        expect_false(mscan.node_attr.nomap);
+        expect_ulong(mscan.node_attr.alignment, 0x400000);
+        expect_ulong(mscan.node_attr.total_size, 0x10000000);
+
+        expect_true(fdt_memscan_nextrange(&mscan, &mnode));
+        expect_ulong(mnode.base, 0x10000000);
+        expect_ulong(mnode.size, 0x10000000);
+
+        expect_false(fdt_memscan_nextrange(&mscan, &mnode));
+    });
+
+    testcase("reserved-node-out-of-bound", {
+        expect_false(fdt_memscan_nextnode(&mscan, &fdt));
+    });
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+    ptr_t dtb = load_fdt();
+
+    test_fdt_memory_node(dtb);
+}
\ No newline at end of file
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 (file)
index 0000000..36c299e
--- /dev/null
@@ -0,0 +1,66 @@
+#include "common.h"
+#include <testing/basic.h>
+#include <unistd.h>
+
+static inline struct dtn* 
+get_node(struct dtn* parent, const char* name)
+{
+    struct dtn_iter it;
+    struct dtn* node;
+    
+    dt_begin_find_byname(&it, parent, name);
+    
+    node = (struct dtn*)it.matched;
+    expect_notnull(node);
+
+    return node;
+}
+
+
+void
+run_test(int argc, const char* argv[])
+{
+
+    if(!my_load_dtb()) {
+        printf("failed to load dtb\n");
+        _exit(1);
+    }
+
+    struct dt_context* ctx;
+    struct dtn* node;
+
+    ctx = dt_main_context();
+
+    begin_testcase("root");
+
+    node = ctx->root;
+    expect_int(node->base.addr_c, 1);
+    expect_int(node->base.sz_c, 2);
+    expect_int(node->base.intr_c, 0);
+    end_testcase();
+
+    begin_testcase("level-1 child");
+
+    node = get_node(node, "child@1");
+    expect_int(node->base.addr_c, 1);
+    expect_int(node->base.sz_c, 2);
+    expect_int(node->base.intr_c, 3);
+    end_testcase();
+
+    begin_testcase("level-2 child");
+
+    node = get_node(node, "child@2");
+    expect_int(node->base.addr_c, 4);
+    expect_int(node->base.sz_c, 2);
+    expect_int(node->base.intr_c, 3);
+    end_testcase();
+
+    begin_testcase("level-3 child");
+
+    node = get_node(node, "child@3");
+    expect_int(node->base.addr_c, 4);
+    expect_int(node->base.sz_c, 0);
+    expect_int(node->base.intr_c, 0);
+    end_testcase();
+
+}
\ No newline at end of file
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 (file)
index 0000000..934c4c7
--- /dev/null
@@ -0,0 +1,106 @@
+#include "common.h"
+#include <testing/basic.h>
+
+extern void *calloc(size_t, size_t);
+extern void  free(void *);
+
+void
+run_test(int argc, const char* argv[])
+{
+    struct dt_context* ctx;
+    struct dtn* node, *domain;
+    struct dtn_iter it;
+    struct dtp_val val;
+    
+    my_load_dtb();
+
+    ctx = dt_main_context();
+
+    node = ctx->root;
+    testcase("root", {
+        expect_notnull(node);
+        expect_int(node->base.addr_c, 0);
+        expect_int(node->base.sz_c, 0);
+        expect_int(node->base.intr_c, 0);
+    });
+
+    dt_begin_find_byname(&it, ctx->root, "dev@1");
+    node = (struct dtn*)it.matched;
+    
+    testcase("intr-basic", {
+        expect_notnull(node);
+        expect_notnull(node->intr.parent);
+
+        expect_str(dt_name(node), "dev@1");
+        expect_str(dt_name(node->intr.parent), "pic@11");
+    });
+
+    testcase("intr-single", {
+        expect_int(node->intr.nr_intrs, 1);
+        expect_false(node->intr.extended);
+
+        domain = dt_interrupt_at(node, 0, &val);
+        expect_int(val.ref->raw[0], 1);
+        expect_int(val.ref->raw[1], 2);
+        expect_str(dt_name(domain), "pic@11");
+
+        expect_null(dt_interrupt_at(node, 1, &val));
+    });
+
+    dt_begin_find_byname(&it, ctx->root, "dev@2");
+    node = (struct dtn*)it.matched;
+
+    testcase("intr-multi", {
+        expect_notnull(node);
+        expect_int(node->intr.nr_intrs, 3);
+        expect_false(node->intr.extended);
+
+        domain = dt_interrupt_at(node, 0, &val);
+        expect_int(val.ref->raw[0], 1);
+        expect_int(val.ref->raw[1], 1);
+        expect_str(dt_name(domain), "pic@11");
+
+        domain = dt_interrupt_at(node, 1, &val);
+        expect_int(val.ref->raw[0], 1);
+        expect_int(val.ref->raw[1], 2);
+        expect_str(dt_name(domain), "pic@11");
+
+        domain = dt_interrupt_at(node, 2, &val);
+        expect_int(val.ref->raw[0], 2);
+        expect_int(val.ref->raw[1], 2);
+        expect_str(dt_name(domain), "pic@11");
+
+        expect_null(dt_interrupt_at(node, 3, &val));
+    });
+
+    dt_begin_find_byname(&it, ctx->root, "dev@3");
+    node = (struct dtn*)it.matched;
+
+    testcase("intr-ext-multi", {
+        expect_notnull(node);
+
+        expect_int(node->intr.nr_intrs, 3);
+        expect_true(node->intr.extended);
+
+        domain = dt_interrupt_at(node, 0, &val);
+        expect_int(val.size / sizeof(int), 2);
+        expect_int(val.ref->raw[0], 3);
+        expect_int(val.ref->raw[1], 3);
+        expect_str(dt_name(domain), "pic@11");
+
+        domain = dt_interrupt_at(node, 1, &val);
+        expect_int(val.size / sizeof(int), 1);
+        expect_int(val.ref->raw[0], 1);
+        expect_str(dt_name(domain), "pic@22");
+
+        domain = dt_interrupt_at(node, 2, &val);
+        expect_int(val.size / sizeof(int), 4);
+        expect_int(val.ref->raw[0], 1);
+        expect_int(val.ref->raw[1], 2);
+        expect_int(val.ref->raw[2], 3);
+        expect_int(val.ref->raw[3], 4);
+        expect_str(dt_name(domain), "pic@33");
+
+        expect_null(dt_interrupt_at(node, 3, &val));
+    });
+}
\ No newline at end of file
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 (file)
index 0000000..2a365ff
--- /dev/null
@@ -0,0 +1,115 @@
+#include "common.h"
+#include <testing/basic.h>
+
+extern void *calloc(size_t, size_t);
+extern void  free(void *);
+
+#define be(v) ((((v) & 0x000000ff) << 24)  |\
+               (((v) & 0x00ff0000) >> 8 )  |\
+               (((v) & 0x0000ff00) << 8 )  |\
+               (((v) & 0xff000000) >> 24))
+
+static void
+map_and_mask_test(struct dtn* node)
+{
+    struct dtn_intr* intrn;
+    struct dtspec_map *map;
+    struct dtspec_key *mask, *key, test_key;
+
+    intrn = &node->intr;
+    map = intrn->map;
+    mask = &map->mask;
+
+    test_key.val = calloc(4, sizeof(int));
+    test_key.size = 4;
+    test_key.bval->raw[0] = 0xf200;
+    test_key.bval->raw[1] = 0x22;
+    test_key.bval->raw[2] = 0x0;
+    test_key.bval->raw[3] = 0x16;
+
+    testcase("map", { expect_notnull(map); });
+
+    testcase("mask-value", {
+        expect_int(mask->bval->raw[0], 0xf800);
+        expect_int(mask->bval->raw[1], 0);
+        expect_int(mask->bval->raw[2], 0);
+        expect_int(mask->bval->raw[3], 7);
+    });
+
+    testcase("key-copy", {
+        struct dtspec_key tmp_key;        
+        dtspec_cpykey(&tmp_key, &test_key);
+
+        expect_int(tmp_key.bval->raw[0], 0xf200);
+        expect_int(tmp_key.bval->raw[1], 0x22);
+        expect_int(tmp_key.bval->raw[2], 0);
+        expect_int(tmp_key.bval->raw[3], 0x16);
+        expect_int(tmp_key.size, test_key.size);
+
+        dtspec_freekey(&tmp_key);
+        expect_true(dtspec_nullkey(&tmp_key));
+    });
+
+    testcase("mask-ops", {
+        struct dtspec_key tmp_key;
+        dtspec_cpykey(&tmp_key, &test_key);
+
+        dtspec_applymask(map, &tmp_key);
+
+        expect_int(tmp_key.bval->raw[0], 0xf000);
+        expect_int(tmp_key.bval->raw[1], 0);
+        expect_int(tmp_key.bval->raw[2], 0);
+        expect_int(tmp_key.bval->raw[3], 6);
+
+        dtspec_freekey(&tmp_key);
+    });
+
+    testcase("map-get", {
+        struct dtspec_mapent* ent;
+
+        test_key.bval->raw[0] = 0x8820;
+        test_key.bval->raw[1] = 0x22;
+        test_key.bval->raw[2] = 0x0;
+        test_key.bval->raw[3] = 0x14;
+
+        ent = dtspec_lookup(map, &test_key);
+        expect_notnull(ent);
+
+        expect_int(ent->child_spec.bval->raw[0], 0x8800);
+        expect_int(ent->child_spec.bval->raw[1], 0);
+        expect_int(ent->child_spec.bval->raw[2], 0);
+        expect_int(ent->child_spec.bval->raw[3], 4);
+
+        expect_notnull(ent->parent);
+        expect_str(morpher_name(dt_mobj(ent->parent)), "pic@1");
+
+        expect_int(ent->parent_spec.bval->raw[0], 1);
+        expect_int(ent->parent_spec.bval->raw[1], 1);
+    });
+
+    free(test_key.val);
+}
+
+void
+run_test(int argc, const char* argv[])
+{
+    struct dt_context* ctx;
+    struct dtn* node;
+    struct dtn_iter it;
+    
+    my_load_dtb();
+
+    ctx = dt_main_context();
+
+    dt_begin_find_byname(&it, ctx->root, "pci");
+    node = (struct dtn*)it.matched;
+
+    testcase("root", {
+        expect_notnull(node);
+        expect_int(node->base.addr_c, 3);
+        expect_int(node->base.sz_c, 2);
+        expect_int(node->base.intr_c, 1);
+    });
+
+    map_and_mask_test(node);
+}
\ No newline at end of file
diff --git a/lunaix-os/tests/units/device-tree/tests.txt b/lunaix-os/tests/units/device-tree/tests.txt
new file mode 100644 (file)
index 0000000..d5ae319
--- /dev/null
@@ -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 (file)
index 0000000..66cf8ab
--- /dev/null
@@ -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 (file)
index 0000000..830e248
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __LUNAIX_STRING_H
+#define __LUNAIX_STRING_H
+
+#include <string.h>
+
+static inline int
+streq(const char* a, const char* b)
+{
+    return strcmp(a, b) == 0;
+}
+
+static inline int
+strneq(const char* a, const char* b, unsigned long n)
+{
+    return strcmp(a, b) != 0;
+}
+
+#endif /* __LUNAIX_STRING_H */
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 (file)
index 0000000..a0bef95
--- /dev/null
@@ -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 (symlink)
index 0000000..f99bb20
--- /dev/null
@@ -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 (file)
index 0000000..9d8096b
--- /dev/null
@@ -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 (file)
index 0000000..5a700f5
--- /dev/null
@@ -0,0 +1,11 @@
+#include <lunaix/spike.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void
+__assert_fail(const char* expr, const char* file, unsigned int line)
+{
+    printf("assertion failed: %s (%s:%d)\n", expr, file, line);
+
+    _exit(1);
+}
\ No newline at end of file
diff --git a/lunaix-os/tests/units/stubs/syslog.c b/lunaix-os/tests/units/stubs/syslog.c
new file mode 100644 (file)
index 0000000..0531625
--- /dev/null
@@ -0,0 +1,25 @@
+#include <lunaix/syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+kprintf_m(const char* component, const char* fmt, va_list args)
+{
+    int sz = 0;
+    char buff[1024];
+    
+    sz = vsnprintf(buff, 1024, fmt, args);
+    printf("%s: %s\n", component, buff);
+}
+
+void
+kprintf_v(const char* component, const char* fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+
+    kprintf_m(component, fmt, args);
+
+    va_end(args);
+}
\ No newline at end of file
diff --git a/lunaix-os/tests/units/stubs/valloc.c b/lunaix-os/tests/units/stubs/valloc.c
new file mode 100644 (file)
index 0000000..0d02922
--- /dev/null
@@ -0,0 +1,66 @@
+#include <lunaix/mm/valloc.h>
+#include <stddef.h>
+
+extern void *malloc(size_t);
+extern void *calloc(size_t, size_t);
+extern void free(void*);
+
+void*
+valloc(unsigned int size)
+{
+    return malloc(size);
+}
+
+void*
+vzalloc(unsigned int size)
+{
+    return calloc(size, 1);
+}
+
+void*
+vcalloc(unsigned int size, unsigned int count)
+{
+    return calloc(size, count);
+}
+
+void
+vfree(void* ptr)
+{
+    free(ptr);
+}
+
+void
+vfree_safe(void* ptr)
+{
+    if (ptr) free(ptr);
+}
+
+void*
+valloc_dma(unsigned int size)
+{
+    return malloc(size);
+}
+
+void*
+vzalloc_dma(unsigned int size)
+{
+    return calloc(size, 1);
+}
+
+void
+vfree_dma(void* ptr)
+{
+    free(ptr);
+}
+
+void
+valloc_init()
+{
+    return;
+}
+
+void 
+valloc_ensure_valid(void* ptr)
+{
+    return;
+}
\ No newline at end of file
diff --git a/lunaix-os/tests/units/test_build.mkinc b/lunaix-os/tests/units/test_build.mkinc
new file mode 100644 (file)
index 0000000..1a3fcdb
--- /dev/null
@@ -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