boot: one line when it works, all of it when it does not
A boot printed about thirty lines before reaching a prompt. Every one was
useful once, and printed on every boot for ever they train the person in front
of the machine to stop reading their own console -- which is expensive on the
day one of them changes.
SchOS UEFI loader
Press F8 for boot options... booting
Welcome to SchOS! (F8 at boot for the full log, or dmesg once you are in)
root@schos / »
**Nothing was deleted, it was routed.** consputc() already wrote to the klog
ring before anywhere else, so a line can be kept in full while being held back
from the two places a person looks. kinfo() is cprintf() with that routing, and
`dmesg` still has the whole boot with timestamps afterwards. The rule for which
is which is not how interesting a line is -- everything was interesting to
somebody once -- but whether you would want to see it on a machine that is
*working*. `pci: 7 devices` is yes the first time and no every time after;
`e1000: no DMA memory for the rings` is yes for ever and stays a cprintf.
The verbose boot the F8 menu already offered now means something much bigger,
which is the other half of this: it is the only way to see any of it live.
Userspace follows through /proc/bootmode, one word. schinit, schinitd and vgpud
hold back their progress lines and never their failures -- a supervisor that
goes quiet when a job dies is worse than one that chatters.
Two things found by testing rather than by reading:
- schinit read /proc/bootmode *before* bootstrap() mounted /proc, so it got
"quiet" every time and the verbose boot was quiet in the one process that
runs first. It reads after the mount now.
- resolvconf announced "already exists; -f to replace it" on every boot after
the first, which is a line about having done nothing. It is quiet when the
file already says what it would have written, and speaks only when the two
disagree -- which means the nameserver changed and the machine is using the
old one.
Verified both ways: quiet boot is six lines, a forced-verbose build prints all
thirty plus the `verbose boot:` steps, and /proc/kmsg holds every line in both.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
This commit is contained in:
parent
c028561da0
commit
617a4aec0a
24 changed files with 373 additions and 60 deletions
|
|
@ -112,6 +112,16 @@ serial_putc(char c)
|
||||||
__asm__ volatile("outb %0, %1" : : "a"((UINT8)c), "d"((UINT16)0x3F8));
|
__asm__ volatile("outb %0, %1" : : "a"((UINT8)c), "d"((UINT16)0x3F8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Diagnostics: only on a verbose boot.
|
||||||
|
*
|
||||||
|
* These four lines say where the framebuffer is, where the kernel went and
|
||||||
|
* where the ACPI tables are. Worth having when a machine will not boot, and
|
||||||
|
* worth nothing on the thousand boots that work -- and they are the first
|
||||||
|
* thing on the serial line every time, so they set the tone for everything
|
||||||
|
* after. vprint() is print() with that decision built in. */
|
||||||
|
static void vprint(const CHAR16 *s);
|
||||||
|
static void vprint_hex(UINT64 v);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print(const CHAR16 *s)
|
print(const CHAR16 *s)
|
||||||
{
|
{
|
||||||
|
|
@ -139,6 +149,20 @@ print_hex(UINT64 v)
|
||||||
print(buf);
|
print(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vprint(const CHAR16 *s)
|
||||||
|
{
|
||||||
|
if (VERBOSE_BOOT)
|
||||||
|
print(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vprint_hex(UINT64 v)
|
||||||
|
{
|
||||||
|
if (VERBOSE_BOOT)
|
||||||
|
print_hex(v);
|
||||||
|
}
|
||||||
|
|
||||||
// A failure here cannot be recovered from and must not be silent: without this
|
// A failure here cannot be recovered from and must not be silent: without this
|
||||||
// the firmware simply returns to its boot menu and the user is told nothing.
|
// the firmware simply returns to its boot menu and the user is told nothing.
|
||||||
static EFI_STATUS
|
static EFI_STATUS
|
||||||
|
|
@ -948,10 +972,10 @@ setup_framebuffer(void)
|
||||||
// is drawn across the splash.
|
// is drawn across the splash.
|
||||||
SPLASH_UP = ui_active();
|
SPLASH_UP = ui_active();
|
||||||
|
|
||||||
print(L"schos: framebuffer "); print_hex(fb);
|
vprint(L"schos: framebuffer "); vprint_hex(fb);
|
||||||
print(L" "); print_hex(info->HorizontalResolution);
|
vprint(L" "); vprint_hex(info->HorizontalResolution);
|
||||||
print(L"x"); print_hex(info->VerticalResolution);
|
vprint(L"x"); vprint_hex(info->VerticalResolution);
|
||||||
print(L"\r\n");
|
vprint(L"\r\n");
|
||||||
|
|
||||||
return fb;
|
return fb;
|
||||||
}
|
}
|
||||||
|
|
@ -1085,13 +1109,13 @@ EfiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
||||||
ui_progress_end();
|
ui_progress_end();
|
||||||
file->Close(file);
|
file->Close(file);
|
||||||
|
|
||||||
print(L"schos: kernel entry "); print_hex(entry); print(L"\r\n");
|
vprint(L"schos: kernel entry "); vprint_hex(entry); vprint(L"\r\n");
|
||||||
|
|
||||||
// Read while boot services still exist and the system table is guaranteed
|
// Read while boot services still exist and the system table is guaranteed
|
||||||
// valid; written to low memory further down, after the firmware has let go
|
// valid; written to low memory further down, after the firmware has let go
|
||||||
// of it, for the same reason the e820 map is.
|
// of it, for the same reason the e820 map is.
|
||||||
UINT64 rsdp = find_rsdp();
|
UINT64 rsdp = find_rsdp();
|
||||||
print(L"schos: acpi rsdp "); print_hex(rsdp); print(L"\r\n");
|
vprint(L"schos: acpi rsdp "); vprint_hex(rsdp); vprint(L"\r\n");
|
||||||
|
|
||||||
// The memory map, and then out. GetMemoryMap must be the last thing before
|
// The memory map, and then out. GetMemoryMap must be the last thing before
|
||||||
// ExitBootServices: the key it returns is invalidated by any allocation,
|
// ExitBootServices: the key it returns is invalidated by any allocation,
|
||||||
|
|
@ -1120,7 +1144,7 @@ EfiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
||||||
if (nent >= E820_MAXENTRIES)
|
if (nent >= E820_MAXENTRIES)
|
||||||
print(L"schos: WARNING: memory map truncated, some RAM will be unused\r\n");
|
print(L"schos: WARNING: memory map truncated, some RAM will be unused\r\n");
|
||||||
|
|
||||||
print(L"schos: exiting boot services\r\n");
|
vprint(L"schos: exiting boot services\r\n");
|
||||||
|
|
||||||
st = BS->ExitBootServices(image, mapkey);
|
st = BS->ExitBootServices(image, mapkey);
|
||||||
if (EFI_ERROR(st)) {
|
if (EFI_ERROR(st)) {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,15 @@ puts_(const char *s)
|
||||||
write(1, (void *)s, n);
|
write(1, (void *)s, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
same(const char *a, const char *b, int n)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
if (a[i] != b[i])
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
slurp(const char *path, char *buf, int cap)
|
slurp(const char *path, char *buf, int cap)
|
||||||
{
|
{
|
||||||
|
|
@ -110,10 +119,24 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// An existing file is somebody's decision until told otherwise.
|
// An existing file is somebody's decision until told otherwise.
|
||||||
|
//
|
||||||
|
// Saying so every boot is the wrong volume for it. On a machine that has
|
||||||
|
// been up before, /etc/resolv.conf always exists and always says the same
|
||||||
|
// thing, so this printed a line about having done nothing on every single
|
||||||
|
// start -- which is exactly the kind of message that teaches people to
|
||||||
|
// stop reading their own boot.
|
||||||
|
//
|
||||||
|
// Quiet when the file already says what this would have written. It is
|
||||||
|
// still worth a word when the two *disagree*, because then the nameserver
|
||||||
|
// has changed and the machine is using the old one.
|
||||||
if (!force) {
|
if (!force) {
|
||||||
char old[512];
|
char old[512];
|
||||||
if (slurp(DST, old, sizeof(old)) > 0) {
|
int on = slurp(DST, old, sizeof(old));
|
||||||
puts_("resolvconf: " DST " already exists; -f to replace it\n");
|
if (on > 0) {
|
||||||
|
if (on == n && same(old, buf, n))
|
||||||
|
return 0; // already right; nothing to say
|
||||||
|
puts_("resolvconf: " DST " differs from what DHCP gave;"
|
||||||
|
" -f to replace it\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,6 +153,8 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
// Worth one line the first time, because it is the moment names start
|
||||||
|
// working and somebody may be waiting to know it.
|
||||||
puts_("resolvconf: ");
|
puts_("resolvconf: ");
|
||||||
write(1, buf, n);
|
write(1, buf, n);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,23 @@ ends_with(const char *s, const char *suffix)
|
||||||
return seq(s + ls - lf, suffix);
|
return seq(s + ls - lf, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// How the machine was booted; see /proc/bootmode and kinfo() in the kernel.
|
||||||
|
static int verbose_boot;
|
||||||
|
|
||||||
|
static void
|
||||||
|
read_bootmode(void)
|
||||||
|
{
|
||||||
|
char b[16];
|
||||||
|
int fd = open("/proc/bootmode", O_RDONLY);
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
n = read(fd, b, sizeof(b) - 1);
|
||||||
|
close(fd);
|
||||||
|
if (n > 0) { b[n] = 0; verbose_boot = (b[0] == 'v'); }
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
out(const char *s)
|
out(const char *s)
|
||||||
{
|
{
|
||||||
|
|
@ -522,6 +539,11 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|
||||||
|
// Only now: /proc is what bootstrap() mounts, and this reads a file in it.
|
||||||
|
// Before the mount it silently returned "quiet" every time, which made the
|
||||||
|
// verbose boot quiet in exactly the one process that runs first.
|
||||||
|
read_bootmode();
|
||||||
|
|
||||||
// A reincarnated PID 1 has the children but not the table.
|
// A reincarnated PID 1 has the children but not the table.
|
||||||
//
|
//
|
||||||
// exec() replaced this program's memory and kept everything else -- the
|
// exec() replaced this program's memory and kept everything else -- the
|
||||||
|
|
@ -545,6 +567,13 @@ main(int argc, char *argv[])
|
||||||
reclaim();
|
reclaim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quiet unless asked, or unless this is not the first pid 1.
|
||||||
|
//
|
||||||
|
// "SchOS process 1" is a line about the system working exactly as designed,
|
||||||
|
// which is the definition of what a quiet boot leaves out. A *reincarnated*
|
||||||
|
// pid 1 is the opposite -- it means the last one died and was replaced --
|
||||||
|
// so that one prints either way.
|
||||||
|
if (verbose_boot || generation > 1) {
|
||||||
out("schinit: SchOS process 1");
|
out("schinit: SchOS process 1");
|
||||||
if (generation > 1) {
|
if (generation > 1) {
|
||||||
out(", generation ");
|
out(", generation ");
|
||||||
|
|
@ -552,6 +581,7 @@ main(int argc, char *argv[])
|
||||||
out(" (reincarnated)");
|
out(" (reincarnated)");
|
||||||
}
|
}
|
||||||
out("\n");
|
out("\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Generation 4 is the safety net: a manifest that kills init must not kill
|
// Generation 4 is the safety net: a manifest that kills init must not kill
|
||||||
// it for ever, so this generation does not read /etc/schinit at all. One
|
// it for ever, so this generation does not read /etc/schinit at all. One
|
||||||
|
|
@ -590,6 +620,7 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
publish();
|
publish();
|
||||||
|
if (verbose_boot)
|
||||||
out("schinit: ready (pid 1)\n");
|
out("schinit: ready (pid 1)\n");
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,44 @@ out(const char *s)
|
||||||
write(1, (void *)s, slen(s));
|
write(1, (void *)s, slen(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// How the machine was booted, read once.
|
||||||
|
//
|
||||||
|
// The routine progress lines below -- one per job started, plus the summary --
|
||||||
|
// are the userspace half of the same problem the kernel has: worth reading on
|
||||||
|
// a boot you are watching, and noise on the several thousand after it. They
|
||||||
|
// are not deleted, they are held back, and `make qemu` with F8 or any verbose
|
||||||
|
// boot brings all of them back.
|
||||||
|
//
|
||||||
|
// Failures are never held back. A job that could not start, a channel that
|
||||||
|
// closed, a pid 1 that stopped answering: those print either way, because a
|
||||||
|
// silent supervisor is worse than a chatty one.
|
||||||
|
static int verbose_boot;
|
||||||
|
|
||||||
|
static void
|
||||||
|
read_bootmode(void)
|
||||||
|
{
|
||||||
|
char b[16];
|
||||||
|
int fd = open("/proc/bootmode", O_RDONLY);
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return; // no procfs: assume quiet
|
||||||
|
n = read(fd, b, sizeof(b) - 1);
|
||||||
|
close(fd);
|
||||||
|
if (n > 0) {
|
||||||
|
b[n] = 0;
|
||||||
|
verbose_boot = (b[0] == 'v');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Progress, as opposed to news.
|
||||||
|
static void
|
||||||
|
vout(const char *s)
|
||||||
|
{
|
||||||
|
if (verbose_boot)
|
||||||
|
write(1, (void *)s, slen(s));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
outn(int v)
|
outn(int v)
|
||||||
{
|
{
|
||||||
|
|
@ -560,6 +598,8 @@ main(void)
|
||||||
{
|
{
|
||||||
struct schinit_hello h;
|
struct schinit_hello h;
|
||||||
|
|
||||||
|
read_bootmode();
|
||||||
|
|
||||||
// Version handshake before anything else. A mismatch is a refusal rather
|
// Version handshake before anything else. A mismatch is a refusal rather
|
||||||
// than a best-effort interpretation -- see the header for why.
|
// than a best-effort interpretation -- see the header for why.
|
||||||
h.op = SCHINIT_HELLO;
|
h.op = SCHINIT_HELLO;
|
||||||
|
|
@ -580,8 +620,9 @@ main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
load_jobs();
|
load_jobs();
|
||||||
out("schinitd: "); outn(njobs); out(" job(s) loaded, generation ");
|
vout("schinitd: "); if (verbose_boot) outn(njobs);
|
||||||
outn((int)h.generation); out("\n");
|
vout(" job(s) loaded, generation ");
|
||||||
|
if (verbose_boot) { outn((int)h.generation); out("\n"); }
|
||||||
|
|
||||||
// Anything PID 1 is already holding is ours again, not something to start.
|
// Anything PID 1 is already holding is ours again, not something to start.
|
||||||
unsigned int highest = adopt();
|
unsigned int highest = adopt();
|
||||||
|
|
@ -593,11 +634,11 @@ main(void)
|
||||||
continue;
|
continue;
|
||||||
if (j->pid)
|
if (j->pid)
|
||||||
continue; // adopted; it never stopped running
|
continue; // adopted; it never stopped running
|
||||||
out("schinitd: starting "); out(j->label); out("\n");
|
vout("schinitd: starting "); vout(j->label); vout("\n");
|
||||||
ask_spawn(j);
|
ask_spawn(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
out("schinitd: ready\n");
|
vout("schinitd: ready\n");
|
||||||
|
|
||||||
// From here on this program does two things: answer PID 1's heartbeat, and
|
// From here on this program does two things: answer PID 1's heartbeat, and
|
||||||
// act on the exits it reports. There is no wait() in this program and
|
// act on the exits it reports. There is no wait() in this program and
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,26 @@
|
||||||
|
|
||||||
// --- small output, since lib/ has no printf ---------------------------------
|
// --- small output, since lib/ has no printf ---------------------------------
|
||||||
|
|
||||||
|
// How the machine was booted. A driver coming up is progress on a boot you are
|
||||||
|
// watching and noise on every other one; a driver *failing* is neither, and
|
||||||
|
// stays on puts(). See kinfo() in kernel/core/console.c for the same rule one
|
||||||
|
// level down.
|
||||||
|
static int verbose_boot;
|
||||||
|
|
||||||
|
static void
|
||||||
|
read_bootmode(void)
|
||||||
|
{
|
||||||
|
char b[16];
|
||||||
|
int fd = open("/proc/bootmode", O_RDONLY);
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
n = read(fd, b, sizeof(b) - 1);
|
||||||
|
close(fd);
|
||||||
|
if (n > 0) { b[n] = 0; verbose_boot = (b[0] == 'v'); }
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
puts(const char *s)
|
puts(const char *s)
|
||||||
{
|
{
|
||||||
|
|
@ -39,6 +59,23 @@ puts(const char *s)
|
||||||
write(1, (void *)s, n);
|
write(1, (void *)s, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Progress, as opposed to news.
|
||||||
|
static void
|
||||||
|
vputs(const char *s)
|
||||||
|
{
|
||||||
|
if (verbose_boot)
|
||||||
|
puts(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void putn(long long v);
|
||||||
|
|
||||||
|
static void
|
||||||
|
vputn(long long v)
|
||||||
|
{
|
||||||
|
if (verbose_boot)
|
||||||
|
putn(v);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
putn(long long v)
|
putn(long long v)
|
||||||
{
|
{
|
||||||
|
|
@ -375,7 +412,7 @@ bring_up(void)
|
||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
die("the device reports no display");
|
die("the device reports no display");
|
||||||
|
|
||||||
puts("vgpud: display is "); putn(width); puts("x"); putn(height); puts("\n");
|
vputs("vgpud: display is "); vputn(width); vputs("x"); vputn(height); vputs("\n");
|
||||||
|
|
||||||
// A 2D resource the size of the screen.
|
// A 2D resource the size of the screen.
|
||||||
struct virtio_gpu_resource_create_2d *c =
|
struct virtio_gpu_resource_create_2d *c =
|
||||||
|
|
@ -431,8 +468,10 @@ bring_up(void)
|
||||||
if (docmd(sizeof(*so), sizeof(struct virtio_gpu_ctrl_hdr)) < 0 || !resp_ok())
|
if (docmd(sizeof(*so), sizeof(struct virtio_gpu_ctrl_hdr)) < 0 || !resp_ok())
|
||||||
die("SET_SCANOUT refused");
|
die("SET_SCANOUT refused");
|
||||||
|
|
||||||
|
if (verbose_boot) {
|
||||||
puts("vgpud: scanout is ours, framebuffer at physical 0x");
|
puts("vgpud: scanout is ours, framebuffer at physical 0x");
|
||||||
puthex(fb_paddr, 16); puts("\n");
|
puthex(fb_paddr, 16); puts("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push what has been drawn to the host. Two commands, and both are needed:
|
// Push what has been drawn to the host. Two commands, and both are needed:
|
||||||
|
|
@ -735,6 +774,8 @@ control_socket(void)
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
read_bootmode();
|
||||||
|
|
||||||
pcifd = open("/dev/pci", O_RDWR);
|
pcifd = open("/dev/pci", O_RDWR);
|
||||||
if (pcifd < 0)
|
if (pcifd < 0)
|
||||||
die("cannot open /dev/pci");
|
die("cannot open /dev/pci");
|
||||||
|
|
@ -758,17 +799,19 @@ main(int argc, char *argv[])
|
||||||
if (index_ < 0)
|
if (index_ < 0)
|
||||||
nothing_to_do("no virtio-gpu on this machine");
|
nothing_to_do("no virtio-gpu on this machine");
|
||||||
|
|
||||||
|
if (verbose_boot) {
|
||||||
puts("vgpud: virtio-gpu at "); puthex(info.bus, 2); puts(":");
|
puts("vgpud: virtio-gpu at "); puthex(info.bus, 2); puts(":");
|
||||||
puthex(info.slot, 2); puts("."); puthex(info.func, 1);
|
puthex(info.slot, 2); puts("."); puthex(info.func, 1);
|
||||||
if (info.driver[0]) { puts(", currently held by "); puts(info.driver); }
|
if (info.driver[0]) { puts(", currently held by "); puts(info.driver); }
|
||||||
puts("\n");
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
// The kernel driver is asked to let go here. It puts the VBE framebuffer
|
// The kernel driver is asked to let go here. It puts the VBE framebuffer
|
||||||
// back on screen before returning, so there is never a moment with no
|
// back on screen before returning, so there is never a moment with no
|
||||||
// display -- see vgpu_release() and vga_fb_restore().
|
// display -- see vgpu_release() and vga_fb_restore().
|
||||||
if (ioctl(pcifd, PCIIOC_CLAIM, &index_) < 0)
|
if (ioctl(pcifd, PCIIOC_CLAIM, &index_) < 0)
|
||||||
nothing_to_do("claim refused -- the kernel driver would not release it");
|
nothing_to_do("claim refused -- the kernel driver would not release it");
|
||||||
puts("vgpud: claimed\n");
|
vputs("vgpud: claimed\n");
|
||||||
|
|
||||||
// The info is re-read because claiming is what enables memory space and
|
// The info is re-read because claiming is what enables memory space and
|
||||||
// bus mastering, and a BAR read before that can legitimately be zero.
|
// bus mastering, and a BAR read before that can legitimately be zero.
|
||||||
|
|
@ -786,9 +829,9 @@ main(int argc, char *argv[])
|
||||||
draw_test_pattern();
|
draw_test_pattern();
|
||||||
present();
|
present();
|
||||||
|
|
||||||
puts("vgpud: pid ");
|
vputs("vgpud: pid ");
|
||||||
putn(getpid());
|
vputn(getpid());
|
||||||
puts(" drew a test pattern from userspace\n");
|
vputs(" drew a test pattern from userspace\n");
|
||||||
|
|
||||||
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'x') {
|
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'x') {
|
||||||
// Exit without releasing, to show what a crashed driver leaves behind:
|
// Exit without releasing, to show what a crashed driver leaves behind:
|
||||||
|
|
@ -826,7 +869,7 @@ main(int argc, char *argv[])
|
||||||
sleep(100);
|
sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
puts("vgpud: listening on " VGPUD_SOCKET "\n");
|
vputs("vgpud: listening on " VGPUD_SOCKET "\n");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int c = accept(srv, 0, 0);
|
int c = accept(srv, 0, 0);
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
|
|
|
||||||
|
|
@ -207,9 +207,71 @@ framebuffer from the loader. Then everything goes to the UART and
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 7. What the boot says
|
||||||
|
|
||||||
|
A working boot prints one line:
|
||||||
|
|
||||||
|
```
|
||||||
|
SchOS UEFI loader
|
||||||
|
Press F8 for boot options... booting
|
||||||
|
|
||||||
|
Welcome to SchOS! (F8 at boot for the full log, or dmesg once you are in)
|
||||||
|
|
||||||
|
root@schos / »
|
||||||
|
```
|
||||||
|
|
||||||
|
It used to print about thirty — the memory map, the local APIC's calibration,
|
||||||
|
every PCI device, each driver announcing itself, each job starting. All of that
|
||||||
|
is genuinely useful, and all of it is useful *once*. Printed on every boot it
|
||||||
|
trains the person in front of the machine to stop reading their own console,
|
||||||
|
which is expensive on the day one of those lines changes.
|
||||||
|
|
||||||
|
**Nothing was deleted; it was routed.** `consputc()` writes to the klog ring
|
||||||
|
before it writes anywhere else, so a line can be kept in full while being held
|
||||||
|
back from the two places a person is looking. `kinfo()` is `cprintf()` with
|
||||||
|
that routing, and the whole boot is still there afterwards:
|
||||||
|
|
||||||
|
```
|
||||||
|
# dmesg | head -4
|
||||||
|
--- boot 1 ---
|
||||||
|
[ 0.00] e820: 1017 MB usable in 8 regions, top 1006 MB (22 entries)
|
||||||
|
[ 0.00] acpi: 2 cpus, lapic at ffff8000fee00000, ioapic id 0
|
||||||
|
[ 0.00] pci: 7 devices
|
||||||
|
```
|
||||||
|
|
||||||
|
The rule for `kinfo` against `cprintf` is not how interesting a line is —
|
||||||
|
everything was interesting to somebody once. It is: **would you want to see
|
||||||
|
this on a machine that is working?** `pci: 7 devices` is yes the first time and
|
||||||
|
no every time after. `e1000: no DMA memory for the rings` is yes for ever, and
|
||||||
|
stays a `cprintf`.
|
||||||
|
|
||||||
|
Three levels, then, and the middle one is new:
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| quiet (default) | the greeting, plus anything that went wrong |
|
||||||
|
| verbose (F8) | every line above, on the console and the serial line |
|
||||||
|
| the klog | all of it, always, whichever of the two you booted |
|
||||||
|
|
||||||
|
Userspace follows the same rule through `/proc/bootmode`, which holds one word.
|
||||||
|
`schinit`, `schinitd` and `vgpud` read it and hold back their progress lines —
|
||||||
|
but never their failures, because a supervisor that goes quiet when a job dies
|
||||||
|
is worse than one that chatters.
|
||||||
|
|
||||||
|
**`schinit` reads it after `bootstrap()` and not before**, which is the sort of
|
||||||
|
detail that only shows up when tested: `/proc` is what `bootstrap()` mounts, so
|
||||||
|
reading it earlier returned "quiet" every time and made the verbose boot quiet
|
||||||
|
in the one process that runs first.
|
||||||
|
|
||||||
## What it does not do
|
## What it does not do
|
||||||
|
|
||||||
- **No BIOS path.** A machine without UEFI does not boot SchOS.
|
- **No BIOS path.** A machine without UEFI does not boot SchOS.
|
||||||
|
- **The quiet boot hides a slow one.** With nothing printing between the
|
||||||
|
loader and the greeting, a boot that stalls for ten seconds looks the same as
|
||||||
|
one that does not. F8 is the answer and it has to be pressed *before* the
|
||||||
|
stall, which is the wrong order for finding out.
|
||||||
|
- **`/proc/bootmode` is read once, at start.** A program that wants to be
|
||||||
|
quieter or louder later has nowhere to say so, and nothing re-reads it.
|
||||||
- **The root device is compiled in.** Booting from a USB disk needs the root
|
- **The root device is compiled in.** Booting from a USB disk needs the root
|
||||||
device to be selectable, which it is not; the USB mass-storage driver works
|
device to be selectable, which it is not; the USB mass-storage driver works
|
||||||
and a superblock reads back through `bread()`, but nothing can mount it.
|
and a superblock reads back through `bread()`, but nothing can mount it.
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,10 @@ int proc_reincarnate(int status);
|
||||||
void proc_kill_init(void);
|
void proc_kill_init(void);
|
||||||
extern uint init_generation;
|
extern uint init_generation;
|
||||||
void cprintf(char*, ...);
|
void cprintf(char*, ...);
|
||||||
|
// Boot chatter: always in the klog, on the screen only when boot_verbose.
|
||||||
|
// See the note above kinfo() in kernel/core/console.c for which is which.
|
||||||
|
void kinfo(char*, ...);
|
||||||
|
extern int boot_verbose;
|
||||||
|
|
||||||
// A log line: the serial port only, never the display.
|
// A log line: the serial port only, never the display.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ acpi_init(void)
|
||||||
outb(0x23, inb(0x23) | 1);
|
outb(0x23, inb(0x23) | 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cprintf("acpi: %d cpu%s, lapic at %p, ioapic id %d\n",
|
kinfo("acpi: %d cpu%s, lapic at %p, ioapic id %d\n",
|
||||||
ncpu, ncpu == 1 ? "" : "s", lapic, ioapicid);
|
ncpu, ncpu == 1 ? "" : "s", lapic, ioapicid);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ e820_init(void)
|
||||||
for (int i = 0; i < nmem_usable; i++)
|
for (int i = 0; i < nmem_usable; i++)
|
||||||
usable += mem_usable[i].end - mem_usable[i].base;
|
usable += mem_usable[i].end - mem_usable[i].base;
|
||||||
|
|
||||||
cprintf("e820: %d MB usable in %d region%s, top %d MB (%d entries)\n",
|
kinfo("e820: %d MB usable in %d region%s, top %d MB (%d entries)\n",
|
||||||
(int)(usable / (1024 * 1024)), nmem_usable,
|
(int)(usable / (1024 * 1024)), nmem_usable,
|
||||||
nmem_usable == 1 ? "" : "s",
|
nmem_usable == 1 ? "" : "s",
|
||||||
(int)(phystop / (1024 * 1024)), count);
|
(int)(phystop / (1024 * 1024)), count);
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ lapicinit(void)
|
||||||
// see the comment above it for why loading a constant here does not work.
|
// see the comment above it for why loading a constant here does not work.
|
||||||
if (lapic_timer_hz == 0) {
|
if (lapic_timer_hz == 0) {
|
||||||
calibrate_timers();
|
calibrate_timers();
|
||||||
cprintf("cpu0: lapic timer %u Hz, tsc %u MHz, tick = %u counts at %d Hz\n",
|
kinfo("cpu0: lapic timer %u Hz, tsc %u MHz, tick = %u counts at %d Hz\n",
|
||||||
lapic_timer_hz, (uint)(tsc_hz / 1000000),
|
lapic_timer_hz, (uint)(tsc_hz / 1000000),
|
||||||
lapic_timer_hz / HZ, HZ);
|
lapic_timer_hz / HZ, HZ);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,19 +85,30 @@ print_int(int64 xx, int base, int sign)
|
||||||
consputc(buf[i]);
|
consputc(buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
// Everything in the log; only what matters on the screen.
|
||||||
cprintf(char *fmt, ...)
|
//
|
||||||
|
// A boot used to print about thirty lines of diagnostics to the serial line
|
||||||
|
// and the console, and they are genuinely useful -- once. After that they are
|
||||||
|
// the first thing you see every time you start the machine, and the message
|
||||||
|
// that actually matters is buried among them.
|
||||||
|
//
|
||||||
|
// So they are not deleted, they are *routed*. consputc() writes to the klog
|
||||||
|
// ring before anything else, so a line can be kept in full while being held
|
||||||
|
// back from the two places a person is looking. `dmesg`, /proc/kmsg and the
|
||||||
|
// next boot's "carried over from the previous boot" all still have it.
|
||||||
|
//
|
||||||
|
// Set for the duration of one kinfo() and no longer. Not a mode the system
|
||||||
|
// sits in: a panic, a driver failing, anything that is not routine still goes
|
||||||
|
// straight to the screen, because those are lines nobody should have to go
|
||||||
|
// looking for.
|
||||||
|
static int cons_logonly;
|
||||||
|
|
||||||
|
static void
|
||||||
|
vcprintf(char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
va_list ap;
|
int i, c;
|
||||||
int i, c, locking;
|
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
|
|
||||||
locking = cons.locking;
|
|
||||||
if (locking)
|
|
||||||
acquire(&cons.lock);
|
|
||||||
|
|
||||||
if (fmt == 0)
|
if (fmt == 0)
|
||||||
panic("null fmt");
|
panic("null fmt");
|
||||||
|
|
||||||
|
|
@ -143,9 +154,47 @@ cprintf(char *fmt, ...)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cprintf(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int locking = cons.locking;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (locking)
|
||||||
|
acquire(&cons.lock);
|
||||||
|
vcprintf(fmt, ap);
|
||||||
if (locking)
|
if (locking)
|
||||||
release(&cons.lock);
|
release(&cons.lock);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A line for the log, and for the screen only on a verbose boot.
|
||||||
|
//
|
||||||
|
// The rule for choosing between this and cprintf is not "how interesting is
|
||||||
|
// it" -- everything here was interesting to somebody once. It is: **would you
|
||||||
|
// want to see this on a machine that is working?** `pci: 7 devices` is a yes
|
||||||
|
// the first time and a no every time after. `e1000: no memory for its rings`
|
||||||
|
// is a yes for ever, and stays a cprintf.
|
||||||
|
void
|
||||||
|
kinfo(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int locking = cons.locking;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (locking)
|
||||||
|
acquire(&cons.lock);
|
||||||
|
if (!boot_verbose)
|
||||||
|
cons_logonly++;
|
||||||
|
vcprintf(fmt, ap);
|
||||||
|
if (!boot_verbose)
|
||||||
|
cons_logonly--;
|
||||||
|
if (locking)
|
||||||
|
release(&cons.lock);
|
||||||
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hand the console over to panic().
|
// Hand the console over to panic().
|
||||||
|
|
@ -212,6 +261,10 @@ consputc(int c)
|
||||||
// three in the morning. See include/klog.h.
|
// three in the morning. See include/klog.h.
|
||||||
klog_putc(c);
|
klog_putc(c);
|
||||||
|
|
||||||
|
// Held back from the screen and the wire, kept in the log. See kinfo().
|
||||||
|
if (cons_logonly)
|
||||||
|
return;
|
||||||
|
|
||||||
if (c == BACKSPACE) {
|
if (c == BACKSPACE) {
|
||||||
uartputc('\b'); uartputc(' '); uartputc('\b');
|
uartputc('\b'); uartputc(' '); uartputc('\b');
|
||||||
if (!cons_serial_only)
|
if (!cons_serial_only)
|
||||||
|
|
|
||||||
|
|
@ -250,10 +250,10 @@ klog_init(void *base, uint64 bytes)
|
||||||
// silently started over" look identical in a file that begins with a boot
|
// silently started over" look identical in a file that begins with a boot
|
||||||
// divider either way.
|
// divider either way.
|
||||||
if (recovered)
|
if (recovered)
|
||||||
cprintf("klog: %d KB at %p, %d bytes carried over from the previous boot\n",
|
kinfo("klog: %d KB at %p, %d bytes carried over from the previous boot\n",
|
||||||
(int)(bytes / 1024), (uint64)base, (int)prev_bytes);
|
(int)(bytes / 1024), (uint64)base, (int)prev_bytes);
|
||||||
else
|
else
|
||||||
cprintf("klog: %d KB at %p, nothing recoverable was there\n",
|
kinfo("klog: %d KB at %p, nothing recoverable was there\n",
|
||||||
(int)(bytes / 1024), (uint64)base);
|
(int)(bytes / 1024), (uint64)base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,19 @@ kmain(uint32 fb_addr)
|
||||||
netuser_init();
|
netuser_init();
|
||||||
dbg_thread_start();
|
dbg_thread_start();
|
||||||
if (boot_verbose) cprintf("verbose boot: dbg thread started\n");
|
if (boot_verbose) cprintf("verbose boot: dbg thread started\n");
|
||||||
|
|
||||||
|
// The one line a working boot prints.
|
||||||
|
//
|
||||||
|
// Everything above this is a kinfo(), which means it is in the klog and not
|
||||||
|
// on the screen -- the whole boot is still there, it is simply not the first
|
||||||
|
// thing anybody has to read every morning. What is left is the fact that the
|
||||||
|
// machine came up, and where the rest went if it did not.
|
||||||
|
//
|
||||||
|
// A verbose boot has already said thirty other things and does not need a
|
||||||
|
// greeting on top of them.
|
||||||
|
if (!boot_verbose)
|
||||||
|
cprintf("\nWelcome to SchOS! (F8 at boot for the full log, or dmesg once you are in)\n\n");
|
||||||
|
|
||||||
mpmain();
|
mpmain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,7 +269,7 @@ enable_sse(void)
|
||||||
static void
|
static void
|
||||||
mpmain(void)
|
mpmain(void)
|
||||||
{
|
{
|
||||||
cprintf("cpu%d: starting\n", cpunum());
|
kinfo("cpu%d: starting\n", cpunum());
|
||||||
enable_sse(); // allow user XMM/SSE instructions
|
enable_sse(); // allow user XMM/SSE instructions
|
||||||
idtinit(); // load idt register
|
idtinit(); // load idt register
|
||||||
syscallinit(); // syscall set up
|
syscallinit(); // syscall set up
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ time_init(void)
|
||||||
monotonic(&up, &dummy);
|
monotonic(&up, &dummy);
|
||||||
boot_epoch = now > up ? now - up : now;
|
boot_epoch = now > up ? now - up : now;
|
||||||
|
|
||||||
cprintf("time: %d-%d-%d %d:%d:%d UTC from the hardware clock\n",
|
kinfo("time: %d-%d-%d %d:%d:%d UTC from the hardware clock\n",
|
||||||
(int)year, r.month, r.day, r.hour, r.minute, r.second);
|
(int)year, r.month, r.day, r.hour, r.minute, r.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -556,7 +556,7 @@ pci_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_bus(0);
|
scan_bus(0);
|
||||||
cprintf("pci: %d device%s\n", ndevs, ndevs == 1 ? "" : "s");
|
kinfo("pci: %d device%s\n", ndevs, ndevs == 1 ? "" : "s");
|
||||||
|
|
||||||
pci_bind_all();
|
pci_bind_all();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -343,6 +343,7 @@ gen_filesystems(struct sbuf *sb)
|
||||||
#define PROC_NETIF 15
|
#define PROC_NETIF 15
|
||||||
#define PROC_KMSG 17
|
#define PROC_KMSG 17
|
||||||
#define PROC_RESOLV 18
|
#define PROC_RESOLV 18
|
||||||
|
#define PROC_BOOTMODE 19
|
||||||
|
|
||||||
// Render global file `id` (a PROC_* constant) into `buf`. Returns its length.
|
// Render global file `id` (a PROC_* constant) into `buf`. Returns its length.
|
||||||
//
|
//
|
||||||
|
|
@ -378,6 +379,15 @@ proc_gen_global(int id, char *buf, int cap)
|
||||||
// kernel file's include path.
|
// kernel file's include path.
|
||||||
case PROC_NETIF: sb.len = net_info(buf, PROC_BUFSZ); break;
|
case PROC_NETIF: sb.len = net_info(buf, PROC_BUFSZ); break;
|
||||||
case PROC_RESOLV: sb.len = net_resolv(buf, PROC_BUFSZ); break;
|
case PROC_RESOLV: sb.len = net_resolv(buf, PROC_BUFSZ); break;
|
||||||
|
// How this machine was booted, for the programs that start during one.
|
||||||
|
//
|
||||||
|
// schinit and the jobs it runs have the same problem the kernel does -- most
|
||||||
|
// of what they print is interesting once -- and the same answer only works
|
||||||
|
// if they can find out which kind of boot this is. One word, so reading it
|
||||||
|
// is `if (strcmp(buf, "verbose"))` and not a parser.
|
||||||
|
case PROC_BOOTMODE:
|
||||||
|
sb_puts(&sb, boot_verbose ? "verbose\n" : "quiet\n");
|
||||||
|
break;
|
||||||
case PROC_DEVICES: gen_devices(&sb); break;
|
case PROC_DEVICES: gen_devices(&sb); break;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,12 @@ uartearlyinit(void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Announce that we're here.
|
// Announce that we're here -- only when asked for. This is the first thing a serial line ever sees from
|
||||||
|
// SchOS and it says nothing except that the port works -- which is worth a
|
||||||
|
// line on a boot you are watching and not on every boot for ever. It cannot
|
||||||
|
// go through kinfo(): it runs before there is a console to route it to.
|
||||||
|
if (!boot_verbose)
|
||||||
|
return;
|
||||||
for(p="SchOS UART...\n"; *p; p++)
|
for(p="SchOS UART...\n"; *p; p++)
|
||||||
uartputc(*p);
|
uartputc(*p);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ vga_fb_init(uint64 phys_addr)
|
||||||
if (fb_height == 0) fb_height = 600;
|
if (fb_height == 0) fb_height = 600;
|
||||||
if (fb_stride == 0) fb_stride = fb_width * (fb_bpp / 8);
|
if (fb_stride == 0) fb_stride = fb_width * (fb_bpp / 8);
|
||||||
|
|
||||||
cprintf("vga: %dx%d, %d bpp, stride %d, LFB: 0x%x\n",
|
kinfo("vga: %dx%d, %d bpp, stride %d, LFB: 0x%x\n",
|
||||||
fb_width, fb_height, fb_bpp, fb_stride, (uint32)phys_addr);
|
fb_width, fb_height, fb_bpp, fb_stride, (uint32)phys_addr);
|
||||||
|
|
||||||
info.ptr = fb;
|
info.ptr = fb;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ vga_pci_probe(struct pci_dev *d)
|
||||||
pci_enable(d, PCI_CMD_MEMORY);
|
pci_enable(d, PCI_CMD_MEMORY);
|
||||||
|
|
||||||
if (bar == 0) {
|
if (bar == 0) {
|
||||||
cprintf("vga: display controller at %x:%x.%x has no framebuffer aperture\n",
|
kinfo("vga: display controller at %x:%x.%x has no framebuffer aperture\n",
|
||||||
d->bus, d->slot, d->func);
|
d->bus, d->slot, d->func);
|
||||||
return 0; // still ours; nothing more to do
|
return 0; // still ours; nothing more to do
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +73,7 @@ vga_pci_probe(struct pci_dev *d)
|
||||||
(uint32)vbe, (uint32)bar->base);
|
(uint32)vbe, (uint32)bar->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
cprintf("vga: display controller %x:%x, aperture %x (%d MB)\n",
|
kinfo("vga: display controller %x:%x, aperture %x (%d MB)\n",
|
||||||
d->vendor, d->device, (uint32)bar->base,
|
d->vendor, d->device, (uint32)bar->base,
|
||||||
(uint32)(bar->size / (1024 * 1024)));
|
(uint32)(bar->size / (1024 * 1024)));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,7 @@ vgpu_probe(struct pci_dev *d)
|
||||||
cprintf("virtio-gpu: no ISR capability; leaving irq %d unclaimed\n", d->irq);
|
cprintf("virtio-gpu: no ISR capability; leaving irq %d unclaimed\n", d->irq);
|
||||||
|
|
||||||
g->ready = 1;
|
g->ready = 1;
|
||||||
cprintf("virtio-gpu: %dx%d, %d KB framebuffer, queue %d, irq %d\n",
|
kinfo("virtio-gpu: %dx%d, %d KB framebuffer, queue %d, irq %d\n",
|
||||||
g->width, g->height, g->fb_bytes / 1024, g->qsize, d->irq);
|
g->width, g->height, g->fb_bytes / 1024, g->qsize, d->irq);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -578,7 +578,7 @@ vgpu_release(struct pci_dev *d)
|
||||||
|
|
||||||
g->ready = 0;
|
g->ready = 0;
|
||||||
g->pdev = 0;
|
g->pdev = 0;
|
||||||
cprintf("virtio-gpu: released to userspace; screen is the VBE framebuffer\n");
|
kinfo("virtio-gpu: released to userspace; screen is the VBE framebuffer\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -347,7 +347,7 @@ e1000_probe(struct pci_dev *d)
|
||||||
|
|
||||||
e->ready = 1;
|
e->ready = 1;
|
||||||
|
|
||||||
cprintf("e1000: %x:%x:%x:%x:%x:%x, link %s, irq %d\n",
|
kinfo("e1000: %x:%x:%x:%x:%x:%x, link %s, irq %d\n",
|
||||||
e->mac[0], e->mac[1], e->mac[2], e->mac[3], e->mac[4], e->mac[5],
|
e->mac[0], e->mac[1], e->mac[2], e->mac[3], e->mac[4], e->mac[5],
|
||||||
(rd(e, E1000_STATUS) & E1000_STATUS_LU) ? "up" : "down", d->irq);
|
(rd(e, E1000_STATUS) & E1000_STATUS_LU) ? "up" : "down", d->irq);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,8 @@ static const struct global_file globals[] = {
|
||||||
// The nameservers DHCP supplied, in resolv.conf's own syntax. See
|
// The nameservers DHCP supplied, in resolv.conf's own syntax. See
|
||||||
// net_resolv() and cmd/resolvconf.
|
// net_resolv() and cmd/resolvconf.
|
||||||
{ "resolv.conf", 18 },
|
{ "resolv.conf", 18 },
|
||||||
|
// "quiet" or "verbose" -- how this machine was booted. See cmd/schinitd.
|
||||||
|
{ "bootmode", 19 },
|
||||||
{ "kmsg", 17 },
|
{ "kmsg", 17 },
|
||||||
};
|
};
|
||||||
#define NGLOBALS ((int)(sizeof(globals) / sizeof(globals[0])))
|
#define NGLOBALS ((int)(sizeof(globals) / sizeof(globals[0])))
|
||||||
|
|
|
||||||
|
|
@ -533,7 +533,7 @@ kmount_slot(int slot, uint bdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
m->mounted = 1;
|
m->mounted = 1;
|
||||||
cprintf("schfs: mounted '%s' on device %d, %d MB, generation %d\n",
|
kinfo("schfs: mounted '%s' on device %d, %d MB, generation %d\n",
|
||||||
m->vol.label, bdev,
|
m->vol.label, bdev,
|
||||||
(int)(m->vol.total_blocks * SCHFS_BLKSIZE / (1024 * 1024)),
|
(int)(m->vol.total_blocks * SCHFS_BLKSIZE / (1024 * 1024)),
|
||||||
(int)m->vol.generation);
|
(int)m->vol.generation);
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ net_thread(void)
|
||||||
continue;
|
continue;
|
||||||
dhcp_start(net_eth_netif(idx));
|
dhcp_start(net_eth_netif(idx));
|
||||||
attached++;
|
attached++;
|
||||||
cprintf("net: %s attached as interface %d\n", d->name, idx);
|
kinfo("net: %s attached as interface %d\n", d->name, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attached == 0) {
|
if (attached == 0) {
|
||||||
|
|
@ -285,7 +285,7 @@ net_thread(void)
|
||||||
}
|
}
|
||||||
lwip_sys_unlock();
|
lwip_sys_unlock();
|
||||||
|
|
||||||
cprintf("net: lwIP %d.%d.%d up on %d interface%s, requesting an address\n",
|
kinfo("net: lwIP %d.%d.%d up on %d interface%s, requesting an address\n",
|
||||||
LWIP_VERSION_MAJOR, LWIP_VERSION_MINOR, LWIP_VERSION_REVISION,
|
LWIP_VERSION_MAJOR, LWIP_VERSION_MINOR, LWIP_VERSION_REVISION,
|
||||||
attached, attached == 1 ? "" : "s");
|
attached, attached == 1 ? "" : "s");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue