diff --git a/libc/integral/c.inc b/libc/integral/c.inc index c4da8a4c5..5bbb4380b 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -735,6 +735,8 @@ void abort(void) wontreturn; #endif #define __weak_reference(sym, alias) \ + __weak_reference_impl(sym, alias) +#define __weak_reference_impl(sym, alias) \ __asm__(".weak\t" #alias "\n\t" \ ".equ\t" #alias ", " #sym "\n\t" \ ".type\t" #alias ",@notype") diff --git a/libc/intrin/interrupts.S b/libc/intrin/interrupts.S index 933278725..4daabd3c0 100644 --- a/libc/intrin/interrupts.S +++ b/libc/intrin/interrupts.S @@ -26,6 +26,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" #include "libc/macros.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/pc.internal.h" // Code and data structures for bare metal interrupt handling. diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 9248333f4..99580e833 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -385,14 +385,29 @@ privileged long kloghandle(void) { return __klog_handle; } +privileged void _klog_serial(const char *b, size_t n) { + size_t i; + uint16_t dx; + unsigned char al; + for (i = 0; i < n; ++i) { + for (;;) { + dx = 0x3F8 + UART_LSR; + asm("inb\t%1,%0" : "=a"(al) : "dN"(dx)); + if (al & UART_TTYTXR) break; + asm("pause"); + } + dx = 0x3F8; + asm volatile("outb\t%0,%1" + : /* no inputs */ + : "a"(b[i]), "dN"(dx)); + } +} + privileged void klog(const char *b, size_t n) { #ifdef __x86_64__ int e; long h; - size_t i; - uint16_t dx; uint32_t wrote; - unsigned char al; long rax, rdi, rsi, rdx; if ((h = kloghandle()) == -1) { return; @@ -407,18 +422,7 @@ privileged void klog(const char *b, size_t n) { if (_weaken(_klog_vga)) { _weaken(_klog_vga)(b, n); } - for (i = 0; i < n; ++i) { - for (;;) { - dx = 0x3F8 + UART_LSR; - asm("inb\t%1,%0" : "=a"(al) : "dN"(dx)); - if (al & UART_TTYTXR) break; - asm("pause"); - } - dx = 0x3F8; - asm volatile("outb\t%0,%1" - : /* no inputs */ - : "a"(b[i]), "dN"(dx)); - } + _klog_serial(b, n); } else { asm volatile("syscall" : "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx) @@ -1152,3 +1156,6 @@ privileged void kprintf(const char *fmt, ...) { kvprintf(fmt, v); va_end(v); } + +__weak_reference(kprintf, uprintf); +__weak_reference(kvprintf, uvprintf); diff --git a/libc/intrin/kprintf.h b/libc/intrin/kprintf.h index a5f899ec8..0b6b7047e 100644 --- a/libc/intrin/kprintf.h +++ b/libc/intrin/kprintf.h @@ -9,25 +9,49 @@ #define kvsnprintf __kvsnprintf #define kloghandle __kloghandle #define kisdangerous __kisdangerous +#define uprintf __uprintf +#define uvprintf __uvprintf #if !(__ASSEMBLER__ + __LINKER__ + 0) + COSMOPOLITAN_C_START_ -void kprintf(const char *, ...); -size_t ksnprintf(char *, size_t, const char *, ...); -void kvprintf(const char *, va_list); -size_t kvsnprintf(char *, size_t, const char *, va_list); -bool kisdangerous(const void *); - void kprintf(const char *, ...); size_t ksnprintf(char *, size_t, const char *, ...); void kvprintf(const char *, va_list); size_t kvsnprintf(char *, size_t, const char *, va_list); bool kisdangerous(const void *); + void klog(const char *, size_t); +void _klog_serial(const char *, size_t); long kloghandle(void); +void uprintf(const char *, ...); +void uvprintf(const char *, va_list); + +#ifndef TINY +#define KINFOF(FMT, ...) \ + do { \ + uprintf("\r\e[35m%s:%d: " FMT "\e[0m\n", \ + __FILE__, __LINE__, ## __VA_ARGS__); \ + } while (0) +#define KWARNF(FMT, ...) \ + do { \ + uprintf("\r\e[94;49mwarn: %s:%d: " FMT "\e[0m\n", \ + __FILE__, __LINE__, ## __VA_ARGS__); \ + } while (0) +#else +#define KINFOF(FMT, ...) ((void)0) +#define KWARNF(FMT, ...) ((void)0) +#endif +#define KDIEF(FMT, ...) \ + do { \ + kprintf("\r\e[30;101mfatal: %s:%d: " FMT "\e[0m\n", \ + __FILE__, __LINE__, ## __VA_ARGS__); \ + for (;;) asm volatile("cli\n\thlt"); \ + } while (0) + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* _COSMO_SOURCE */ diff --git a/libc/vga/tty-klog.greg.c b/libc/vga/tty-klog.greg.c index 5eafd84b1..2c7f11b9d 100644 --- a/libc/vga/tty-klog.greg.c +++ b/libc/vga/tty-klog.greg.c @@ -33,8 +33,8 @@ #ifdef __x86_64__ /* - * @fileoverview Instantiation of routines for emergency or system console - * output in graphical video modes. + * @fileoverview Instantiation of routines for emergency console output in + * graphical video modes. * * @see libc/vga/tty-graph.inc */ diff --git a/libc/vga/vga-init.greg.c b/libc/vga/vga-init.greg.c index 7cb8b66f7..2560780f4 100644 --- a/libc/vga/vga-init.greg.c +++ b/libc/vga/vga-init.greg.c @@ -25,7 +25,10 @@ │ OTHER DEALINGS IN THE SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/pc.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" #include "libc/str/str.h" #include "libc/vga/vga.internal.h" @@ -72,4 +75,47 @@ textstartup void _vga_init(void) { } } +#if !IsTiny() +/** + * Non-emergency console vprintf(), useful for dumping debugging or + * informational messages at program startup. + * + * @see uprintf() + */ +void uvprintf(const char *fmt, va_list v) { + if (!IsMetal()) { + kvprintf(fmt, v); + } else { + long size = __get_safe_size(8000, 3000); + char *buf = alloca(size); + CheckLargeStackAllocation(buf, size); + size_t count = kvsnprintf(buf, size, fmt, v); + if (count >= size) count = size - 1; + _TtyWrite(&_vga_tty, buf, count); + _klog_serial(buf, count); + } +} + +/** + * Non-emergency console printf(), useful for dumping debugging or + * informational messages at program startup. + * + * uprintf() is similar to kprintf(), but on bare metal with VGA support, it + * uses the normal, fast graphical console, rather than initializing an + * emergency console. This makes uprintf() faster — on bare metal — at the + * expense of being less crash-proof. + * + * (The uprintf() function name comes from the FreeBSD kernel.) + * + * @see kprintf() + * @see https://man.freebsd.org/cgi/man.cgi?query=uprintf&sektion=9&n=1 + */ +void uprintf(const char *fmt, ...) { + va_list v; + va_start(v, fmt); + uvprintf(fmt, v); + va_end(v); +} +#endif /* !IsTiny() */ + #endif /* __x86_64__ */ diff --git a/libc/vga/vga.internal.h b/libc/vga/vga.internal.h index cab78d84b..24098657a 100644 --- a/libc/vga/vga.internal.h +++ b/libc/vga/vga.internal.h @@ -255,8 +255,7 @@ void _TtyGraphMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t, size_t); /* - * Routines that implement emergency or system console output in graphical - * video modes. + * Routines that implement emergency console output in graphical video modes. */ void _TtyKlog16Update(struct Tty *); void _TtyKlog16DrawChar(struct Tty *, size_t, size_t, wchar_t);