diff --git a/core/initgraph.c b/core/initgraph.c index 23d4f37..5bba6d6 100644 --- a/core/initgraph.c +++ b/core/initgraph.c @@ -17,6 +17,7 @@ static void initgraph_option(bool value) { CMDLINE_OPTION("initgraph", "Print the init graph in DOT format after running", initgraph_option); static bool edges_linked = false; +static struct init_node* failed_node = nullptr; struct init_queue { struct init_node* head; @@ -96,6 +97,7 @@ static void reach_node(struct init_node* node, struct boot_info* info) { log_status("Skipping stage \"%s\"\n", node->name); } else { log_status("Running stage \"%s\"\n", node->name); + failed_node = node; switch (node->action) { case INIT_EMPTY: break; @@ -103,10 +105,14 @@ static void reach_node(struct init_node* node, struct boot_info* info) { node->callback(info); break; case INIT_GATE: - if (!node->gate(info)) + if (!node->gate(info)) { node->disabled = true; + node->failed = true; + } break; } + failed_node = nullptr; + node->executed = true; } node->done = true; } @@ -115,13 +121,31 @@ static void dump() { kprintf("digraph initgraph {\n"); for (auto cur = __ld_initgraph_nodes_start; cur < __ld_initgraph_nodes_end; cur++) { struct init_node* node = *cur; - kprintf("\tn%p [label=\"%s\"];\n", node, node->name); + const char* style = ""; + if (node->failed || node == failed_node) + style = ", color=red, fontcolor=red"; + else if (!node->executed) + style = ", color=gray, fontcolor=gray"; + kprintf("\tn%p [label=\"%s\"%s];\n", node, node->name, style); for (struct init_edge* edge = node->in_edges; edge; edge = edge->next_in) - kprintf("\tn%p -> n%p;\n", edge->source, edge->target); + kprintf( + "\tn%p -> n%p%s;\n", + edge->source, + edge->target, + edge->source->executed && edge->target->executed ? "" : " [color=gray]" + ); } kprintf("}\n"); } +void initgraph_panic() { + static bool dumping = false; + if (!dump_graph || !failed_node || dumping) + return; + dumping = true; + dump(); +} + void initgraph_run(struct init_node* goal, struct boot_info* info) { if (!edges_linked) link_edges(); @@ -153,6 +177,8 @@ void initgraph_run(struct init_node* goal, struct boot_info* info) { } for (auto cur = __ld_initgraph_nodes_start; cur < __ld_initgraph_nodes_end; cur++) { + if ((*cur)->wanted && !(*cur)->done) + failed_node = *cur; assert( !(*cur)->wanted || (*cur)->done, "The dependencies for stage \"%s\" could not be resolved", diff --git a/core/panic.c b/core/panic.c index 08bedfc..2059b4a 100644 --- a/core/panic.c +++ b/core/panic.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -64,6 +65,8 @@ void panic(const char* msg, ...) { print_backtrace(); panic_log("End of panic message\n"); + initgraph_panic(); + while (true) { irq_wait(); } diff --git a/include/zinnia/initgraph.h b/include/zinnia/initgraph.h index 400ce2f..e39945e 100644 --- a/include/zinnia/initgraph.h +++ b/include/zinnia/initgraph.h @@ -41,6 +41,8 @@ struct init_node { bool wanted; bool done; bool disabled; + bool executed; + bool failed; struct init_edge* in_edges; struct init_edge* out_edges; struct init_node* queue_next; @@ -49,17 +51,17 @@ struct init_node { #define INIT_EXTERN(node) extern struct init_node node[1] #define INIT_TASK(node, display, ...) \ - struct init_node node[1] = {{ \ - .name = (display), \ - __VA_OPT__( \ - .action = _Generic( \ - (__VA_ARGS__), \ - void (*)(struct boot_info*): INIT_CALLBACK, \ - bool (*)(struct boot_info*): INIT_GATE \ - ), \ - .func = (void*)(__VA_ARGS__), \ - ) \ - }}; \ + struct init_node node[1] = { \ + {.name = (display), \ + __VA_OPT__( \ + .action = _Generic( \ + (__VA_ARGS__), \ + void (*)(struct boot_info*): INIT_CALLBACK, \ + bool (*)(struct boot_info*): INIT_GATE \ + ), \ + .func = (void*)(__VA_ARGS__), \ + )} \ + }; \ [[__used, __section(".initgraph.nodes")]] \ static struct init_node* const CONCAT(node, _initgraph_node) = node @@ -80,3 +82,5 @@ struct init_node { #define INIT_ENTAILS(node, ...) _INIT_EDGES(UNIQUE_IDENT(init_edges), node, false, __VA_ARGS__) void initgraph_run(struct init_node* goal, struct boot_info* info); + +void initgraph_panic();