dbg: the boot menu can turn on remote debugging, in a debug build
schdbgd ships Disabled, and its manifest explains why: a debugger that can read
the process table should not run on a machine whose owner never asked for one.
That default is right and has one bad consequence -- **the machines that most
need debugging are the ones you cannot get a shell on to enable it.** A laptop
with no serial port that stops before it can draw has nowhere to say why, and
`schinitd enable` needs a prompt that does not exist.
So `make DEBUG=1` adds a sixth entry to the F8 menu. Picking it toggles;
booting carries the choice through SCHBOOT_DEBUG_FLAG; the kernel publishes
/proc/bootdebug; schinitd starts the one job that flag may un-disable, with
the manifest's Args now naming 0.0.0.0 -- a debugger reachable only from the
machine being debugged is no use when that machine is the one that will not
talk to you.
Four decisions, since this is a network-reachable debugger:
compiled out, not hidden A release build cannot set the flag because the
code that would set it is not in the binary. A
menu item that is present and refuses is an
invitation to make it not refuse.
consent at the machine Somebody standing at the keyboard during boot is
the strongest consent this system can ask for and
the weakest one that is any use on hardware that
will not boot.
one job, named in schinitd Not a manifest key like EnableIfDebug: the general
version of "the boot menu starts things that ship
off" is worse than the specific one, and this way
what the flag can start is one readable line.
the kernel only publishes Nothing in the kernel behaves differently, so a
debug kernel and a release kernel are the same
kernel and a bug cannot be the flag's fault.
/proc/bootdebug is its own file rather than a second line in /proc/bootmode,
because bootmode's whole promise is that reading it is a string compare and
not a parser.
**Also: `tone` stopped lying.** On a machine with no sound card it reported
"the device will not take 16-bit samples", which sends you looking at the
format code instead of at the empty PCI slot -- /dev/dsp exists whether or not
hardware is behind it, and the ioctl is where the absence shows up. ENODEV is
now told apart from a format refusal.
Verified end to end: F8 -> item 6 -> boot -> schinitd says it is starting
schdbgd -> a client outside the VM connected to the forwarded port and ran
`dma`, getting the real arena dump back. The release build has no such entry
in the binary at all, and boots clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9fea18b18b
commit
30a0d0fbed
11 changed files with 204 additions and 20 deletions
|
|
@ -106,6 +106,12 @@ static int SPLASH_UP;
|
|||
* BIOS loader writes, so a verbose boot means the same thing either way. */
|
||||
static int VERBOSE_BOOT;
|
||||
|
||||
// Remote debugging, off unless somebody picks it out of the boot menu -- and
|
||||
// the entry that picks it only exists in a build made with DEBUG=1. See
|
||||
// SCHBOOT_DEBUG_FLAG in include/schboot.h for why the consent is asked for at
|
||||
// this particular moment.
|
||||
static int DEBUG_BOOT;
|
||||
|
||||
static void
|
||||
serial_putc(char c)
|
||||
{
|
||||
|
|
@ -1101,23 +1107,38 @@ boot_menu(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
|
|||
|
||||
res_row(gop, resbuf, sizeof resbuf);
|
||||
|
||||
const char *items[5];
|
||||
// Six entries in a debug build, five in a release one.
|
||||
//
|
||||
// The debugger entry is compiled out rather than hidden, because a
|
||||
// menu item that is present and refuses is an invitation to work out
|
||||
// how to make it not refuse. An ISO built for anybody else has no way
|
||||
// to turn a network debugger on, because the code that would set the
|
||||
// flag is not in it.
|
||||
const char *items[6];
|
||||
int nitems = 5;
|
||||
items[0] = "Boot SchOS";
|
||||
items[1] = "Boot SchOS (verbose)";
|
||||
items[2] = resbuf;
|
||||
items[3] = "System Information";
|
||||
items[4] = "Reboot to firmware";
|
||||
#ifdef SCHOS_DEBUG
|
||||
items[5] = DEBUG_BOOT ? "Remote debugging: on (schdbgd, port 4444)"
|
||||
: "Remote debugging: off";
|
||||
nitems = 6;
|
||||
#endif
|
||||
|
||||
ui_menu("Boot Manager", items, 5, selected,
|
||||
"W/S or 1-5 to choose, Enter to select");
|
||||
ui_menu("Boot Manager", items, nitems, selected,
|
||||
nitems == 6 ? "W/S or 1-6 to choose, Enter to select"
|
||||
: "W/S or 1-5 to choose, Enter to select");
|
||||
|
||||
// The same menu on the serial line: the whole thing once, then one
|
||||
// line per *move*. Reprinting on every keypress would be correct and
|
||||
// unreadable -- a serial terminal has no cursor to paint over, so an
|
||||
// unrecognised key would scroll the selection past again for nothing.
|
||||
if (echoed < 0) {
|
||||
serial_menu("Boot Manager", items, 5, selected,
|
||||
"W/S or 1-5 to choose, Enter to select", 1);
|
||||
serial_menu("Boot Manager", items, nitems, selected,
|
||||
nitems == 6 ? "W/S or 1-6 to choose, Enter to select"
|
||||
: "W/S or 1-5 to choose, Enter to select", 1);
|
||||
} else if (echoed != selected) {
|
||||
serial_item(items, selected, selected, 1);
|
||||
}
|
||||
|
|
@ -1135,17 +1156,23 @@ boot_menu(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
|
|||
BS->Stall(10000);
|
||||
}
|
||||
|
||||
if (scan == 0x01) { selected = (selected + 4) % 5; continue; } /* up */
|
||||
if (scan == 0x02) { selected = (selected + 1) % 5; continue; } /* down */
|
||||
if (c == L'w' || c == L'W') { selected = (selected + 4) % 5; continue; }
|
||||
if (scan == 0x01) { selected = (selected + nitems - 1) % nitems; continue; }
|
||||
if (scan == 0x02) { selected = (selected + 1) % nitems; continue; }
|
||||
if (c == L'w' || c == L'W') { selected = (selected + nitems - 1) % nitems; continue; }
|
||||
if (c == L's' || c == L'S') { selected = (selected + 1) % 5; continue; }
|
||||
if (c >= L'1' && c <= L'5') { selected = (int)(c - L'1'); continue; }
|
||||
if (c >= L'1' && c <= L'0' + nitems) { selected = (int)(c - L'1'); continue; }
|
||||
|
||||
if (c == L'\r' || c == L'\n') {
|
||||
if (selected == 0) return 0;
|
||||
if (selected == 1) return 1;
|
||||
if (selected == 2) { res_choose(gop); continue; }
|
||||
if (selected == 3) { sys_info(gop); continue; }
|
||||
#ifdef SCHOS_DEBUG
|
||||
// A toggle rather than an action: picking it changes what the
|
||||
// entry says and leaves you in the menu, so the state you booted
|
||||
// with is the state you can see before you boot.
|
||||
if (selected == 5) { DEBUG_BOOT = !DEBUG_BOOT; echoed = -1; continue; }
|
||||
#endif
|
||||
if (selected == 4) {
|
||||
ui_clear();
|
||||
ui_text_centered((int)ui_height() / 2, "Halted -- reset to reach firmware setup",
|
||||
|
|
@ -1772,6 +1799,7 @@ EfiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
|||
*(UINT32 *)SCHBOOT_E820_COUNT = nent;
|
||||
*(UINT64 *)SCHBOOT_RSDP_ADDR = rsdp;
|
||||
*(UINT8 *)SCHBOOT_VERBOSE_FLAG = (UINT8)VERBOSE_BOOT;
|
||||
*(UINT8 *)SCHBOOT_DEBUG_FLAG = (UINT8)DEBUG_BOOT;
|
||||
|
||||
// The page tables mboot_entry would have built. entry64low's first act is
|
||||
// a movabs to 0xffff8000...., so the high half must be mapped before the
|
||||
|
|
|
|||
Loading…
Reference in a new issue