[metal] Add a uprintf() routine, for non-emergency boot logging

This commit is contained in:
tkchia 2023-10-07 18:16:00 +00:00
parent ec3275179f
commit e68658501f
7 changed files with 104 additions and 25 deletions

View file

@ -735,6 +735,8 @@ void abort(void) wontreturn;
#endif #endif
#define __weak_reference(sym, alias) \ #define __weak_reference(sym, alias) \
__weak_reference_impl(sym, alias)
#define __weak_reference_impl(sym, alias) \
__asm__(".weak\t" #alias "\n\t" \ __asm__(".weak\t" #alias "\n\t" \
".equ\t" #alias ", " #sym "\n\t" \ ".equ\t" #alias ", " #sym "\n\t" \
".type\t" #alias ",@notype") ".type\t" #alias ",@notype")

View file

@ -26,6 +26,7 @@
*/ */
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/pc.internal.h" #include "libc/runtime/pc.internal.h"
// Code and data structures for bare metal interrupt handling. // Code and data structures for bare metal interrupt handling.

View file

@ -385,14 +385,29 @@ privileged long kloghandle(void) {
return __klog_handle; 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) { privileged void klog(const char *b, size_t n) {
#ifdef __x86_64__ #ifdef __x86_64__
int e; int e;
long h; long h;
size_t i;
uint16_t dx;
uint32_t wrote; uint32_t wrote;
unsigned char al;
long rax, rdi, rsi, rdx; long rax, rdi, rsi, rdx;
if ((h = kloghandle()) == -1) { if ((h = kloghandle()) == -1) {
return; return;
@ -407,18 +422,7 @@ privileged void klog(const char *b, size_t n) {
if (_weaken(_klog_vga)) { if (_weaken(_klog_vga)) {
_weaken(_klog_vga)(b, n); _weaken(_klog_vga)(b, n);
} }
for (i = 0; i < n; ++i) { _klog_serial(b, n);
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));
}
} else { } else {
asm volatile("syscall" asm volatile("syscall"
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx) : "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
@ -1152,3 +1156,6 @@ privileged void kprintf(const char *fmt, ...) {
kvprintf(fmt, v); kvprintf(fmt, v);
va_end(v); va_end(v);
} }
__weak_reference(kprintf, uprintf);
__weak_reference(kvprintf, uvprintf);

View file

@ -9,25 +9,49 @@
#define kvsnprintf __kvsnprintf #define kvsnprintf __kvsnprintf
#define kloghandle __kloghandle #define kloghandle __kloghandle
#define kisdangerous __kisdangerous #define kisdangerous __kisdangerous
#define uprintf __uprintf
#define uvprintf __uvprintf
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ 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 *, ...); void kprintf(const char *, ...);
size_t ksnprintf(char *, size_t, const char *, ...); size_t ksnprintf(char *, size_t, const char *, ...);
void kvprintf(const char *, va_list); void kvprintf(const char *, va_list);
size_t kvsnprintf(char *, size_t, const char *, va_list); size_t kvsnprintf(char *, size_t, const char *, va_list);
bool kisdangerous(const void *); bool kisdangerous(const void *);
void klog(const char *, size_t); void klog(const char *, size_t);
void _klog_serial(const char *, size_t);
long kloghandle(void); 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_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* _COSMO_SOURCE */ #endif /* _COSMO_SOURCE */

View file

@ -33,8 +33,8 @@
#ifdef __x86_64__ #ifdef __x86_64__
/* /*
* @fileoverview Instantiation of routines for emergency or system console * @fileoverview Instantiation of routines for emergency console output in
* output in graphical video modes. * graphical video modes.
* *
* @see libc/vga/tty-graph.inc * @see libc/vga/tty-graph.inc
*/ */

View file

@ -25,7 +25,10 @@
OTHER DEALINGS IN THE SOFTWARE. OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/pc.internal.h" #include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/vga/vga.internal.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__ */ #endif /* __x86_64__ */

View file

@ -255,8 +255,7 @@ void _TtyGraphMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t,
size_t); size_t);
/* /*
* Routines that implement emergency or system console output in graphical * Routines that implement emergency console output in graphical video modes.
* video modes.
*/ */
void _TtyKlog16Update(struct Tty *); void _TtyKlog16Update(struct Tty *);
void _TtyKlog16DrawChar(struct Tty *, size_t, size_t, wchar_t); void _TtyKlog16DrawChar(struct Tty *, size_t, size_t, wchar_t);