diff --git a/artwork/sad-phone.svg b/artwork/sad-phone.svg deleted file mode 100644 index 7d9af34e..00000000 --- a/artwork/sad-phone.svg +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/artwork/sad.svg b/artwork/sad.svg new file mode 100644 index 00000000..f5ad28b2 --- /dev/null +++ b/artwork/sad.svg @@ -0,0 +1,94 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/boot/error/default.nix b/boot/error/default.nix new file mode 100644 index 00000000..d80d4fa4 --- /dev/null +++ b/boot/error/default.nix @@ -0,0 +1,22 @@ +{ runCommand +, lib +, mruby +}: + +# mkDerivation will append something like -aarch64-unknown-linux-gnu to the +# derivation name with cross, which will break the mruby code loading. +# Since we don't need anything from mkDerivation, really, let's use runCommand. +runCommand "boot-error.mrb" { + src = lib.cleanSource ./.; + lib = lib.cleanSource ../recovery-menu/lib; + + nativeBuildInputs = [ + mruby + ]; +} '' + mrbc \ + -o $out \ + $(find $lib -type f -name '*.rb' | sort) \ + $(find $src/lib -type f -name '*.rb' | sort) \ + $src/main.rb +'' diff --git a/boot/error/lib/shaded_text.rb b/boot/error/lib/shaded_text.rb new file mode 100644 index 00000000..ee7ecd69 --- /dev/null +++ b/boot/error/lib/shaded_text.rb @@ -0,0 +1,39 @@ +# This only works as long as the elements are not in a layout. +class ShadedText + OFFSET = 2 + + def initialize(*args) + @secondary = LVGL::LVLabel.new(*args) + style = @secondary.get_style(LVGL::LABEL_STYLE::MAIN).dup + @secondary.set_style(LVGL::LABEL_STYLE::MAIN, style) + style.text_color = 0xFF000000 + + @main = LVGL::LVLabel.new(*args) + style = @main.get_style(LVGL::LABEL_STYLE::MAIN).dup + @main.set_style(LVGL::LABEL_STYLE::MAIN, style) + style.text_color = 0xFFFFFFFF + + # Ensures the position is reset at least once, to sync-up the shade. + set_pos(0, 0) + end + + def method_missing(*args) + @main.send(*(args.dup)) + @secondary.send(*(args.dup)) + end + + def set_pos(x, y) + @main.set_pos(x, y) + @secondary.set_pos(x+OFFSET, y+OFFSET) + end + + def set_x(value) + @main.set_x(value) + @secondary.set_x(value+OFFSET) + end + + def set_y(value) + @main.set_y(value) + @secondary.set_y(value+OFFSET) + end +end diff --git a/boot/error/main.rb b/boot/error/main.rb index 6f9c223d..352e118a 100644 --- a/boot/error/main.rb +++ b/boot/error/main.rb @@ -1,55 +1,36 @@ -# Get exclusive control of the framebuffer -# By design we will not restore the console at exit. -# We are assuming the target does not necessarily have a console attached to -# the framebuffer, so this program has to be enough by itself. -VTConsole.map_console(0) +begin -# Prepare LVGL -LVGL::Hacks.init() +data = JSON.parse(File.read(ARGV.first)) -$color = ARGV.shift -$code = ARGV.shift -$message = ARGV.shift +$exit = false +$code = data["code"] +$color = data["color"] +$delay = data["delay"] +$message = data["message"] +$status = data["status"] +$title = data["title"] $color = $color.rjust(6, "0").rjust(8, "F").to_i(16) -# This only works as long as the elements are not in a layout. -class ShadedText - def initialize(*args) - @secondary = LVGL::LVLabel.new(*args) - style = @secondary.get_style(LVGL::LABEL_STYLE::MAIN).dup - @secondary.set_style(LVGL::LABEL_STYLE::MAIN, style) - style.text_color = 0xFF000000 - - @main = LVGL::LVLabel.new(*args) - style = @main.get_style(LVGL::LABEL_STYLE::MAIN).dup - @main.set_style(LVGL::LABEL_STYLE::MAIN, style) - style.text_color = 0xFFFFFFFF - - # Ensures the position is reset at least once. - set_pos(0, 0) - end - - def method_missing(*args) - @main.send(*(args.dup)) - @secondary.send(*(args.dup)) - end - - def set_pos(x, y) - @main.set_pos(x, y) - @secondary.set_pos(x+2, y+2) - end -end - class UI + # As this is not using BaseWindow, LVGUI::init isn't handled for us. + LVGUI.init() + def initialize() - screen - sad_phone - code - message + add_screen + + # First add the title bar, other elements will sit under. + add_title_bar + # Then, action pane, so we can get its height + add_actions_pane + # Finally, messages pane, which takes the remainder. + add_messages_pane + + # Re-compute the layout + relayout() end - def screen() + def add_screen() @screen = LVGL::LVContainer.new() # Create a new style @@ -60,54 +41,317 @@ class UI style.body_grad_color = $color end - def sad_phone() - file = nil - file = "/sad-phone.svg" if File.exist?("/sad-phone.svg") - return unless file + def add_title_bar() + @title_bar = LVGL::LVContainer.new(@screen) + @title_bar.set_width(@screen.get_width()) + @title_bar.set_height(16*unit) + @title_bar.set_pos(0, 0) - if @screen.get_height > @screen.get_width - LVGL::Hacks::LVNanoSVG.resize_next_width(@screen.get_width) - else - LVGL::Hacks::LVNanoSVG.resize_next_height(@screen.get_height) + @title_bar.get_style(LVGL::CONT_STYLE::MAIN).dup.tap do |style| + @title_bar.set_style(LVGL::CONT_STYLE::MAIN, style) + style.body_main_color = 0x00000000 + style.body_grad_color = 0x00000000 + style.body_border_width = 0 + style.body_radius = 0 + style.body_opa = (255 * 0.30).to_i end + add_sad_phone + add_title + end + + def add_actions_pane() + @actions_pane = LVGL::LVContainer.new(@screen) + @actions_pane.set_width(get_pane_width()) + + # When horizontal, we know it's placed to the right, full height. + if horizontal? + @actions_pane.set_height(@screen.get_height() - @title_bar.get_height()) + @actions_pane.set_pos(get_pane_width(), @title_bar.get_height()) + end + + @actions_pane.get_style(LVGL::CONT_STYLE::MAIN).dup.tap do |style| + @actions_pane.set_style(LVGL::CONT_STYLE::MAIN, style) + style.body_main_color = 0x00000000 + style.body_grad_color = 0x00000000 + style.body_border_width = 0 + style.body_radius = 0 + style.body_opa = (255 * 0.20).to_i + end + + add_time_left + end + + def add_messages_pane() + @messages_pane = LVGL::LVContainer.new(@screen) + @messages_pane.set_width(get_pane_width()) + @messages_pane.set_pos(0, @title_bar.get_height()) + + # When horizontal, full height + if horizontal? + @messages_pane.set_height(@screen.get_height() - @title_bar.get_height()) + end + + @messages_pane.get_style(LVGL::CONT_STYLE::MAIN).dup.tap do |style| + @messages_pane.set_style(LVGL::CONT_STYLE::MAIN, style) + style.body_main_color = 0x00000000 + style.body_grad_color = 0x00000000 + style.body_border_width = 0 + style.body_radius = 0 + style.body_opa = (255 * 0).to_i + end + + add_message_title + add_message + end + + # Title elements + + def add_sad_phone() + file = nil + file = "/sad.svg" if File.exist?("/sad.svg") + file = "sad.svg" if File.exist?("sad.svg") + return unless file + + LVGL::Hacks::LVNanoSVG.resize_next_height(@title_bar.get_height - 2 * padding) @sad_phone = LVGL::LVImage.new(@screen) @sad_phone.set_src(file) + @sad_phone.set_pos(2 * padding, padding) + end - # Center the image - @sad_phone.set_pos( - @screen.get_width / 2 - @sad_phone.get_width / 2, - @screen.get_height / 2 - @sad_phone.get_height / 2, + def add_title() + @title = new_text($code, parent: @title_bar) + @title.set_align(LVGL::LABEL_ALIGN::LEFT) + @title.set_x(@sad_phone.get_x()*2 + @sad_phone.get_width()) + @title.set_y(@title_bar.get_height / 2 - @title.get_height / 2) + @title.set_width(@title_bar.get_width() - @title.get_x()) + end + + # Messages pane elements + + def add_message_title() + @message_title = new_text($title, parent: @messages_pane) + @message_title.set_align(LVGL::LABEL_ALIGN::LEFT) + @message_title.set_pos( + padding, + padding, ) end - def code() - @code = ShadedText.new(@screen) - @code.set_long_mode(LVGL::LABEL_LONG::BREAK) - @code.set_align(LVGL::LABEL_ALIGN::CENTER) - @code.set_width((@screen.get_width * 0.8).to_i) - @code.set_text($code) - @code.set_pos( - @screen.get_width / 2 - @code.get_width / 2, - (@screen.get_height * 0.05).to_i - ) - end - - def message() - @message = ShadedText.new(@screen) - @message.set_long_mode(LVGL::LABEL_LONG::BREAK) - @message.set_align(LVGL::LABEL_ALIGN::CENTER) - @message.set_width((@screen.get_width * 0.95).to_i) - @message.set_text($message) + def add_message() + @message = new_text($message, parent: @messages_pane) + @message.set_align(LVGL::LABEL_ALIGN::LEFT) @message.set_pos( - @screen.get_width / 2 - @message.get_width / 2, - (@screen.get_height * 0.65).to_i + padding, + @message_title.get_height() + @message_title.get_y() + padding ) end + + # Actions pane elements + + def add_time_left() + @time_left = new_text("", parent: @actions_pane) + set_time_left($delay) + @time_left.set_x(@actions_pane.get_width / 2 - @time_left.get_width / 2) + @time_left.set_y(padding) + end + + def set_actions(actions) + @action_buttons ||= [] + @action_buttons.each do |el| + el.del() + end + + y_position = @time_left.get_y() + @time_left.get_height() + padding() + + @action_buttons = actions.map do |action_pair| + label, action = action_pair + + LVGUI::Button.new(@actions_pane).tap do |btn| + LVGUI.focus_group.add_obj(btn) + btn.glue_obj(true) + btn.set_label(label) + btn.set_y(y_position) + btn.event_handler = ->(event) do + case event + when LVGL::EVENT::CLICKED + action.call() + end + end + + # For the next item + y_position = btn.get_y() + btn.get_height() + padding() + end + end + + relayout() + end + + # Layout helpers + + def relayout() + unless horizontal? + @messages_pane.set_height( + @screen.get_height() - @title_bar.get_height() - @actions_pane.get_height() + ) + + # The actions pane has to be as high as required in vertical mode. + last_element = @actions_pane.get_children.reduce do |a, b| + if b + a_end = a.get_y() + a.get_height() + b_end = b.get_y() + b.get_height() + if a_end > b_end + a + else + b + end + else + a + end + end + + @actions_pane.set_height( + last_element.get_y() + last_element.get_height() + padding + ) + + # Always push it as far down as possible! + @actions_pane.set_pos(0, @screen.get_height() - @actions_pane.get_height()) + end + end + + # Misc. helpers + + # Creates a label with some useful defaults. + def new_text(text, parent: nil) + parent ||= @screen + + el = ShadedText.new(parent) + el.set_long_mode(LVGL::LABEL_LONG::BREAK) + el.set_align(LVGL::LABEL_ALIGN::CENTER) + el.set_width((parent.get_width - 2*padding).to_i) + el.set_text(text) + el + end + + # Updates the UI with the time left. + def set_time_left(value) + if value + @time_left.set_text("#{value} seconds left before crashing.") + else + @time_left.set_text("Select an option:") + end + end + + def hide_actions() + @actions_pane.set_opa_scale_enable(true) + @actions_pane.set_opa_scale(0) + end + + def get_pane_width() + if horizontal? + @screen.get_width() / 2 + else + @screen.get_width() + end + end + + def unit() + (if horizontal? + @screen.get_height() + else + @screen.get_width() + end) / 128 + end + + def padding() + 2 * unit + end + + def horizontal?() + @screen.get_height < @screen.get_width + end end # Create the UI -ui = UI.new +$ui = UI.new # Run tasks once to "realize" the UI. LVGL::Hacks::LVTask.handle_tasks + +def run(*cmd) + $stderr.puts " $ " + cmd.join(" ") + system(*cmd) unless LVGL::Introspection.simulator? +end + +def cleanup_and_exit() + $ui.hide_actions() + + # Ensure the next scheduled handle_tasks will run + LVGL::Hacks::LVTask.handle_tasks + sleep(0.1) + + # Refresh the UI one last time. + LVGL::Hacks::LVTask.handle_tasks + + puts "Exiting error applet!" + puts "exit(#{$status})" + + # Ensures console is flushed entirely. + $stdout.flush() + $stderr.flush() + + # Ensures all kernel work is done before it kernel panics at exit. + sleep(0.1) + + # Exit, which will crash the kernel. + exit $status +end + +$ui.set_actions([[ + "Cancel time-out", ->() do + $delay = nil + $ui.set_time_left(nil) + + $ui.set_actions([ + ["Power off", ->() { run("poweroff") }], + ["Kernel panic", ->() { $exit = true }], + *(RebootModes.options), + ]) + end +]]) + +start = Time.now +LVGUI.main_loop do + if $delay + elapsed = Time.now - start + left = $delay - elapsed + $ui.set_time_left(left.floor) + + if elapsed >= $delay + $exit = true + end + end + + # We're using `$exit` as a flag to ensure we exit after all event handlers + # have been completed. + # This is because we will not be able to force a render of the UI during + # an event handler. + cleanup_and_exit() if $exit +end + +# Handles outputing the error and, more importantly, flushing the output. +# When simply existing, the system might not flush the output due to the +# kernel panic. +rescue => e + $stderr.puts("") + $stderr.puts("Unexpected error in error handler:") + $stderr.puts("") + $stderr.puts(e.inspect) + $stderr.puts("") + + $stdout.flush() + $stderr.flush() + + sleep(1) + exit 128 +end diff --git a/boot/init/init.rb b/boot/init/init.rb index 8df10d4e..c72fad0c 100644 --- a/boot/init/init.rb +++ b/boot/init/init.rb @@ -39,26 +39,15 @@ Tasks::Modules.new(*Configuration["kernel"]["modules"]) Tasks::go() $logger.fatal("Tasks all ran, but we're still here...") -System.failure("did_not_switch", color: "ff0000") +System.failure( + "INIT_FAILED_SWITCH", + "Boot process failed to switch to stage-2", + "The stage-1 init did not detect any failure condition, but failed to switch to stage-2.\n\n" + + "It shouldn't happen, yet here we are.", + color: "ff0000" +) rescue => e - System.sad_phone("765300", "Uncaught Exception", e.inspect) - 3.times do - $logger.fatal("********************") - end - $logger.fatal("Handling exception") - $logger.fatal(e.inspect) - $logger.fatal("`init` will exit and the kernel will crash.") - $logger.fatal("********************") - # Leave some time for the $logger.fatals to flush before the kernel crashes. - sleep(1) - System.shell if System.respond_to?(:shell) - - # Users with access to serial debug may prefer crashing to the bootloader. - # Though, crashing the kernel is *required* for console ramoops to be present. - if Configuration["boot"]["crashToBootloader"] then - System.run("reboot bootloader") - else - exit 99 - end + # Then fail + System.failure("INIT_EXCEPTION", "Uncaught Exception", e.inspect, color: "765300", status: 99) end diff --git a/boot/init/lib/system.rb b/boot/init/lib/system.rb index 2877c866..150c1c86 100644 --- a/boot/init/lib/system.rb +++ b/boot/init/lib/system.rb @@ -169,22 +169,64 @@ module System end end - def self.sad_phone(color, code, message) - begin - System.run(LOADER, "/applets/boot-error.mrb", color, code, message) - rescue CommandError => e - $logger.fatal(e.inspect) + def self.failure(code, title, message="(No details given)", color: "000000", delay: Configuration["boot"]["fail"]["delay"], status: 111) + Progress.kill() + + # First print the error we're handling. + # The added asterisks seve to aid in finding it visually. + 5.times do + $logger.fatal("********************************************") end + $logger.fatal("") + $logger.fatal("********************************************") + $logger.fatal("* Fatal error in Mobile NixOS stage-1 init *") + $logger.fatal("********************************************") + $logger.fatal("") + $logger.fatal("#{code}: #{title}") + $logger.fatal("") + $logger.fatal(message) + $logger.fatal("") + 5.times do + $logger.fatal("********************************************") + end + + _flush_outputs() + + File.write("/.error.json", { + code: code, + title: title, + color: color, + delay: delay, + message: message, + status: status, + }.to_json) + + # Show the error handler applet. + begin + System.exec(LOADER, "/applets/boot-error.mrb", "/.error.json") + rescue => e + $logger.fatal("********************************************") + $logger.fatal("* Error handler failed to start *") + $logger.fatal("********************************************") + $logger.fatal(e.inspect) + $logger.fatal("********************************************") + end + + # If we're here, things are broken beyond belief! + _flush_outputs() + + # Drop down to a shell if possible. + shell if respond_to?(:shell) + + # As in "command not found". + exit 127 end - def self.failure(code, message="(No details given)", color: "000000", delay: Configuration["boot"]["fail"]["delay"]) - Progress.kill() - $logger.fatal("#{code}: #{message}") - sad_phone(color, code, message) - shell if respond_to?(:shell) - sleep(delay) - hard_reboot if Configuration["boot"]["fail"]["reboot"] - exit 111 + # Flushes the outputs. + def self._flush_outputs() + # Flush both output + $stdout.flush + $stderr.flush end def self.hard_reboot() diff --git a/boot/init/lib/task.rb b/boot/init/lib/task.rb index 038f24f9..9a810b73 100644 --- a/boot/init/lib/task.rb +++ b/boot/init/lib/task.rb @@ -92,7 +92,7 @@ module Tasks "\n" # Fail with a black backdrop, and force the message to stay up 60s - System.failure("hung_tasks", msg, color: "000000", delay: 60) + System.failure("TASKS_HANG_TIMEOUT", "Hung Tasks", msg, color: "000000", delay: 60) end # Don't burn the CPU if we're waiting on something... diff --git a/boot/init/tasks/switch_root.rb b/boot/init/tasks/switch_root.rb index 3ee0193d..f1fa8e1e 100644 --- a/boot/init/tasks/switch_root.rb +++ b/boot/init/tasks/switch_root.rb @@ -77,7 +77,7 @@ class Tasks::SwitchRoot < SingletonTask return path if path end - System.failure("init_not_found", "Could not find init path for stage-2", color: "FF00FF") + System.failure("INIT_NOT_FOUND", "Stage-2 init not found", "Could not find init path for stage-2", color: "FF00FF") end # May pause the boot to allow the user to select a generation. diff --git a/boot/recovery-menu/lib/reboot_modes.rb b/boot/recovery-menu/lib/reboot_modes.rb new file mode 100644 index 00000000..46c7eff3 --- /dev/null +++ b/boot/recovery-menu/lib/reboot_modes.rb @@ -0,0 +1,16 @@ +module RebootModes + Android = { + "recovery" => ["Reboot to recovery", ->() { run("reboot recovery") }], + "bootloader" => ["Reboot to bootloader", ->() { run("reboot bootloader") }], + } + + def self.options() + [ + ["Reboot to system", ->() { run("reboot") }], + ] + + Configuration["HAL"]["boot"]["rebootModes"].map do |identifier| + const, key = identifier.split(".", 2) + const_get(const)[key] + end + end +end diff --git a/boot/recovery-menu/main.rb b/boot/recovery-menu/main.rb index eeab5c94..a855d2ab 100644 --- a/boot/recovery-menu/main.rb +++ b/boot/recovery-menu/main.rb @@ -7,23 +7,6 @@ def run(*cmd) system(*cmd) unless LVGL::Introspection.simulator? end -module RebootModes - Android = { - "recovery" => ["Reboot to recovery", ->() { run("reboot recovery") }], - "bootloader" => ["Reboot to bootloader", ->() { run("reboot bootloader") }], - } - - def self.options() - [ - ["Reboot to system", ->() { run("reboot") }], - ] + - Configuration["HAL"]["boot"]["rebootModes"].map do |identifier| - const, key = identifier.split(".", 2) - const_get(const)[key] - end - end -end - module BootGUI class MainWindow < LVGUI::BaseWindow include LVGUI::ButtonPalette diff --git a/devices/asus-dumo/kernel/config.aarch64 b/devices/asus-dumo/kernel/config.aarch64 index 4e26f219..0723eb91 100644 --- a/devices/asus-dumo/kernel/config.aarch64 +++ b/devices/asus-dumo/kernel/config.aarch64 @@ -5818,7 +5818,7 @@ CONFIG_KASAN_STACK=1 # # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=0 +CONFIG_PANIC_TIMEOUT=1 # CONFIG_SOFTLOCKUP_DETECTOR is not set # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_WQ_WATCHDOG is not set diff --git a/devices/asus-flo/kernel/config.armv7 b/devices/asus-flo/kernel/config.armv7 index 55d403f0..720eb5c9 100644 --- a/devices/asus-flo/kernel/config.armv7 +++ b/devices/asus-flo/kernel/config.armv7 @@ -120,7 +120,7 @@ CONFIG_RD_LZMA=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y CONFIG_ANON_INODES=y -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_EXPERT=y CONFIG_UID16=y # CONFIG_SYSCTL_SYSCALL is not set diff --git a/devices/asus-z00t/kernel/config.aarch64 b/devices/asus-z00t/kernel/config.aarch64 index f2002779..80026579 100644 --- a/devices/asus-z00t/kernel/config.aarch64 +++ b/devices/asus-z00t/kernel/config.aarch64 @@ -138,7 +138,7 @@ CONFIG_ANON_INODES=y CONFIG_HAVE_UID16=y CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_HOTPLUG=y -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_EXPERT=y CONFIG_UID16=y # CONFIG_SYSCTL_SYSCALL is not set diff --git a/devices/google-marlin/kernel/config.aarch64 b/devices/google-marlin/kernel/config.aarch64 index ee401476..548db5af 100644 --- a/devices/google-marlin/kernel/config.aarch64 +++ b/devices/google-marlin/kernel/config.aarch64 @@ -4386,7 +4386,7 @@ CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_PANIC_ON_RECURSIVE_FAULT=y CONFIG_SCHED_DEBUG=y # CONFIG_PANIC_ON_RT_THROTTLING is not set diff --git a/devices/motorola-addison/kernel/config.aarch64 b/devices/motorola-addison/kernel/config.aarch64 index 15822f30..2cf91cf3 100644 --- a/devices/motorola-addison/kernel/config.aarch64 +++ b/devices/motorola-addison/kernel/config.aarch64 @@ -4759,7 +4759,7 @@ CONFIG_HAVE_ARCH_KASAN=y # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_PANIC_ON_RECURSIVE_FAULT=y # CONFIG_SCHED_DEBUG is not set # CONFIG_PANIC_ON_SCHED_BUG is not set diff --git a/devices/motorola-addison/kernel/config.armv7l b/devices/motorola-addison/kernel/config.armv7l index 5d99b03a..420022aa 100644 --- a/devices/motorola-addison/kernel/config.armv7l +++ b/devices/motorola-addison/kernel/config.armv7l @@ -4492,7 +4492,7 @@ CONFIG_HAVE_DEBUG_KMEMLEAK=y # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_PANIC_ON_RECURSIVE_FAULT=y # CONFIG_SCHED_DEBUG is not set # CONFIG_PANIC_ON_SCHED_BUG is not set diff --git a/devices/oneplus-oneplus3/kernel/config.aarch64 b/devices/oneplus-oneplus3/kernel/config.aarch64 index edf370e9..23e1f0fe 100644 --- a/devices/oneplus-oneplus3/kernel/config.aarch64 +++ b/devices/oneplus-oneplus3/kernel/config.aarch64 @@ -4207,7 +4207,7 @@ CONFIG_HAVE_ARCH_KASAN=y # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_PANIC_ON_RECURSIVE_FAULT=y # CONFIG_SCHED_DEBUG is not set # CONFIG_PANIC_ON_SCHED_BUG is not set diff --git a/devices/pine64-pinephone/kernel/config.aarch64 b/devices/pine64-pinephone/kernel/config.aarch64 index e0204026..750f0e29 100644 --- a/devices/pine64-pinephone/kernel/config.aarch64 +++ b/devices/pine64-pinephone/kernel/config.aarch64 @@ -7045,7 +7045,7 @@ CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y # # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=0 +CONFIG_PANIC_TIMEOUT=1 # CONFIG_SOFTLOCKUP_DETECTOR is not set # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_WQ_WATCHDOG is not set diff --git a/devices/razer-cheryl2/kernel/config.aarch64 b/devices/razer-cheryl2/kernel/config.aarch64 index 828684c8..81e37e6f 100644 --- a/devices/razer-cheryl2/kernel/config.aarch64 +++ b/devices/razer-cheryl2/kernel/config.aarch64 @@ -5055,7 +5055,7 @@ CONFIG_ARCH_HAS_KCOV=y # CONFIG_WQ_WATCHDOG is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_SCHED_DEBUG=y CONFIG_SCHED_INFO=y # CONFIG_PANIC_ON_SCHED_BUG is not set diff --git a/devices/sony-pioneer/kernel/config.aarch64 b/devices/sony-pioneer/kernel/config.aarch64 index 6068039e..811cb12f 100644 --- a/devices/sony-pioneer/kernel/config.aarch64 +++ b/devices/sony-pioneer/kernel/config.aarch64 @@ -4965,7 +4965,7 @@ CONFIG_HAVE_ARCH_KASAN=y # CONFIG_WQ_WATCHDOG is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_SCHED_DEBUG=y CONFIG_SCHED_INFO=y # CONFIG_PANIC_ON_SCHED_BUG is not set diff --git a/devices/xiaomi-lavender/kernel/config.aarch64 b/devices/xiaomi-lavender/kernel/config.aarch64 index a27bbcff..4c435161 100644 --- a/devices/xiaomi-lavender/kernel/config.aarch64 +++ b/devices/xiaomi-lavender/kernel/config.aarch64 @@ -4905,7 +4905,7 @@ CONFIG_HAVE_ARCH_KASAN=y # CONFIG_WQ_WATCHDOG is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_SCHED_DEBUG=y CONFIG_SCHED_INFO=y # CONFIG_PANIC_ON_SCHED_BUG is not set diff --git a/devices/xiaomi-tissot/kernel/config.aarch64 b/devices/xiaomi-tissot/kernel/config.aarch64 index cbcf77cd..8815246e 100644 --- a/devices/xiaomi-tissot/kernel/config.aarch64 +++ b/devices/xiaomi-tissot/kernel/config.aarch64 @@ -4178,7 +4178,7 @@ CONFIG_HAVE_ARCH_KASAN=y # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_TIMEOUT=1 CONFIG_PANIC_ON_RECURSIVE_FAULT=y # CONFIG_SCHED_DEBUG is not set # CONFIG_PANIC_ON_SCHED_BUG is not set diff --git a/examples/testing/crash-before-switch-root/README.md b/examples/testing/crash-before-switch-root/README.md new file mode 100644 index 00000000..63e92634 --- /dev/null +++ b/examples/testing/crash-before-switch-root/README.md @@ -0,0 +1,38 @@ +`crash-before-switch-root` +========================== + +What does this test? +-------------------- + +A simple known method to crash the system at boot. + +This can be used to check changes to the errors handling. + + +Why is this scary? +------------------ + +Not scary at all. Only pretty useless in daily use! + + +How is success defined? +----------------------- + +The boot process should proceed normally (splash, etc), but be +interrupted before switch root. + +The crashing happens *after* mounting /mnt, but *before* switching root. + + +Running +------- + +Assuming you are `cd`'d into the root of a Mobile NixOS checkout: + +``` +nix-build ./examples/testing/crash-before-switch-root && ./result +``` + +This will build for qemu-x86_64 by default. + +As always, be mindful of your `NIX_PATH`. diff --git a/examples/testing/crash-before-switch-root/configuration.nix b/examples/testing/crash-before-switch-root/configuration.nix new file mode 100644 index 00000000..b3170dd2 --- /dev/null +++ b/examples/testing/crash-before-switch-root/configuration.nix @@ -0,0 +1,9 @@ +{ config, lib, pkgs, ... }: + +{ + mobile.boot.stage-1.tasks = [ ./crash.rb ]; + + mobile.boot.stage-1.bootConfig = { + log.level = lib.mkForce "INFO"; + }; +} diff --git a/examples/testing/crash-before-switch-root/crash.rb b/examples/testing/crash-before-switch-root/crash.rb new file mode 100644 index 00000000..0c6e1f62 --- /dev/null +++ b/examples/testing/crash-before-switch-root/crash.rb @@ -0,0 +1,12 @@ +class Tasks::Crash < SingletonTask + def initialize() + # Runs before SwitchRoot + Targets[:SwitchRoot].add_dependency(:Task, self) + # And after /mnt is available + add_dependency(:Mount, "/mnt") + end + + def run() + raise "This is an exception from init!" + end +end diff --git a/examples/testing/crash-before-switch-root/default.nix b/examples/testing/crash-before-switch-root/default.nix new file mode 100644 index 00000000..00840c78 --- /dev/null +++ b/examples/testing/crash-before-switch-root/default.nix @@ -0,0 +1,11 @@ +{ device ? "qemu-x86_64" }: +let + system-build = import ../../../. { + inherit device; + configuration = [ { imports = [ + ../../hello/configuration.nix + ./configuration.nix + ]; } ]; + }; +in + system-build.build.default diff --git a/modules/initrd-boot-gui.nix b/modules/initrd-boot-gui.nix index b799b185..aa13eb43 100644 --- a/modules/initrd-boot-gui.nix +++ b/modules/initrd-boot-gui.nix @@ -4,9 +4,6 @@ let key-held = pkgs.runCommand "key-held.mrb" {} '' ${pkgs.buildPackages.mruby}/bin/mrbc -o $out ${../boot/applets}/key-held.rb ''; - boot-error = pkgs.runCommand "boot-error.mrb" {} '' - ${pkgs.buildPackages.mruby}/bin/mrbc -o $out ${../boot/recovery-menu}/lib/*.rb ${../boot/error}/main.rb - ''; in { mobile.boot.stage-1.contents = with pkgs; [ @@ -15,7 +12,7 @@ in symlink = "/etc/logo.svg"; } { - object = boot-error; + object = pkgs.mobile-nixos.stage-1.boot-error; symlink = "/applets/boot-error.mrb"; } { diff --git a/modules/initrd-fail.nix b/modules/initrd-fail.nix index 088ac9e1..e917e094 100644 --- a/modules/initrd-fail.nix +++ b/modules/initrd-fail.nix @@ -28,8 +28,8 @@ in config = { mobile.boot.stage-1.contents = [ { - object = (builtins.path { path = ../artwork/sad-phone.svg; }); - symlink = "/sad-phone.svg"; + object = (builtins.path { path = ../artwork/sad.svg; }); + symlink = "/sad.svg"; } ]; }; diff --git a/overlay/mruby-builder/mrbgems/mruby-lvgui/default.nix b/overlay/mruby-builder/mrbgems/mruby-lvgui/default.nix index a549a841..07218ad1 100644 --- a/overlay/mruby-builder/mrbgems/mruby-lvgui/default.nix +++ b/overlay/mruby-builder/mrbgems/mruby-lvgui/default.nix @@ -18,8 +18,8 @@ mrbgems.mkGem { src = fetchFromGitHub { repo = "mruby-lvgui"; owner = "mobile-nixos"; - rev = "f1bb1dd9b2c5aa3d3df4fcc41ca706f426d182a8"; - sha256 = "0ybjkzg743d21rn3q0vi0fa9zwp3ym9zw2q5ym24wc7gxdspjcjs"; + rev = "07f6cce17a9819ec9c6da2adea012e3033cfd7b6"; + sha256 = "0c47vv2slwh2n3996aw219likicpsmlk47ayx8xcl49kpmq674ns"; }; gemBuildInputs = [ diff --git a/overlay/overlay.nix b/overlay/overlay.nix index cce0feb8..f068e57d 100644 --- a/overlay/overlay.nix +++ b/overlay/overlay.nix @@ -101,6 +101,7 @@ in stage-1 = { script-loader = callPackage ../boot/script-loader {}; boot-recovery-menu = callPackage ../boot/recovery-menu {}; + boot-error = callPackage ../boot/error {}; boot-splash = callPackage ../boot/splash {}; };