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 @@
-
-
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 @@
+
+
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 {};
};