mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-09 03:10:27 +00:00
Quick prototype for VGA console output in bare metal mode
This commit is contained in:
parent
e1590e1e38
commit
c42c607c80
10 changed files with 228 additions and 5 deletions
5
Makefile
5
Makefile
|
@ -111,6 +111,7 @@ include libc/linux/linux.mk # │ You can manipulate arrays
|
|||
include libc/tinymath/tinymath.mk # │ You can issue raw system calls
|
||||
include third_party/compiler_rt/compiler_rt.mk # │
|
||||
include libc/str/str.mk # │
|
||||
include libc/vga/vga.mk # │
|
||||
include third_party/xed/xed.mk # │
|
||||
include third_party/zlib/zlib.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
|
@ -316,7 +317,8 @@ COSMOPOLITAN_OBJECTS = \
|
|||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NEXGEN32E
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_VGA
|
||||
|
||||
COSMOPOLITAN_HEADERS = \
|
||||
APE \
|
||||
|
@ -341,6 +343,7 @@ COSMOPOLITAN_HEADERS = \
|
|||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
LIBC_VGA \
|
||||
NET_HTTP \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA \
|
||||
|
|
|
@ -66,6 +66,7 @@ EXAMPLES_DIRECTDEPS = \
|
|||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_VGA \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "libc/math.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile long double x = -.5;
|
||||
volatile long double y = 1.5;
|
||||
|
|
|
@ -51,7 +51,8 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_SYSV
|
||||
LIBC_SYSV \
|
||||
LIBC_VGA
|
||||
|
||||
LIBC_CALLS_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -19,10 +19,16 @@
|
|||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/vga/vga.h"
|
||||
|
||||
ssize_t sys_writev_metal(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
switch (fd->kind) {
|
||||
case kFdConsole:
|
||||
if (weaken(sys_writev_vga))
|
||||
weaken(sys_writev_vga)(fd, iov, iovlen);
|
||||
/* fallthrough */
|
||||
case kFdSerial:
|
||||
return sys_writev_serial(fd, iov, iovlen);
|
||||
default:
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/pushpop.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
|
@ -55,10 +56,17 @@ textstartup void InitializeFileDescriptors(void) {
|
|||
fds->f = 3;
|
||||
fds->p = fds->__init_p;
|
||||
if (IsMetal()) {
|
||||
extern const char vga_console[];
|
||||
pushmov(&fds->f, 3ull);
|
||||
fds->__init_p[0].kind = pushpop(kFdSerial);
|
||||
fds->__init_p[1].kind = pushpop(kFdSerial);
|
||||
fds->__init_p[2].kind = pushpop(kFdSerial);
|
||||
if (weaken(vga_console)) {
|
||||
fds->__init_p[0].kind = pushpop(kFdConsole);
|
||||
fds->__init_p[1].kind = pushpop(kFdConsole);
|
||||
fds->__init_p[2].kind = pushpop(kFdConsole);
|
||||
} else {
|
||||
fds->__init_p[0].kind = pushpop(kFdSerial);
|
||||
fds->__init_p[1].kind = pushpop(kFdSerial);
|
||||
fds->__init_p[2].kind = pushpop(kFdSerial);
|
||||
}
|
||||
fds->__init_p[0].handle = VEIL("r", 0x3F8ull);
|
||||
fds->__init_p[1].handle = VEIL("r", 0x3F8ull);
|
||||
fds->__init_p[2].handle = VEIL("r", 0x3F8ull);
|
||||
|
|
|
@ -30,6 +30,7 @@ o/$(MODE)/libc: o/$(MODE)/libc/calls \
|
|||
o/$(MODE)/libc/thread \
|
||||
o/$(MODE)/libc/time \
|
||||
o/$(MODE)/libc/tinymath \
|
||||
o/$(MODE)/libc/vga \
|
||||
o/$(MODE)/libc/x \
|
||||
o/$(MODE)/libc/zipos \
|
||||
$(LIBC_CHECKS)
|
||||
|
|
15
libc/vga/vga.h
Normal file
15
libc/vga/vga.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_VGA_VGA_H_
|
||||
#define COSMOPOLITAN_LIBC_VGA_VGA_H_
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
ssize_t sys_writev_vga(struct Fd *, const struct iovec *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_VGA_VGA_H_ */
|
57
libc/vga/vga.mk
Normal file
57
libc/vga/vga.mk
Normal file
|
@ -0,0 +1,57 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += LIBC_VGA
|
||||
|
||||
LIBC_VGA_ARTIFACTS += LIBC_VGA_A
|
||||
LIBC_VGA_A = o/$(MODE)/libc/vga/vga.a
|
||||
LIBC_VGA_A_FILES := $(wildcard libc/vga/*)
|
||||
LIBC_VGA_A_HDRS = $(filter %.h,$(LIBC_VGA_A_FILES))
|
||||
LIBC_VGA_A_SRCS_S = $(filter %.S,$(LIBC_VGA_A_FILES))
|
||||
LIBC_VGA_A_SRCS_C = $(filter %.c,$(LIBC_VGA_A_FILES))
|
||||
|
||||
LIBC_VGA = \
|
||||
$(LIBC_VGA_A_DEPS) \
|
||||
$(LIBC_VGA_A)
|
||||
|
||||
LIBC_VGA_A_SRCS = \
|
||||
$(LIBC_VGA_A_SRCS_S) \
|
||||
$(LIBC_VGA_A_SRCS_C)
|
||||
|
||||
LIBC_VGA_A_OBJS = \
|
||||
$(LIBC_VGA_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(LIBC_VGA_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
LIBC_VGA_A_CHECKS = \
|
||||
$(LIBC_VGA_A).pkg \
|
||||
$(LIBC_VGA_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
LIBC_VGA_A_DIRECTDEPS = \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_SYSV \
|
||||
LIBC_STR \
|
||||
LIBC_INTRIN \
|
||||
LIBC_STUBS
|
||||
|
||||
LIBC_VGA_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_VGA_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(LIBC_VGA_A):libc/vga/ \
|
||||
$(LIBC_VGA_A).pkg \
|
||||
$(LIBC_VGA_A_OBJS)
|
||||
|
||||
$(LIBC_VGA_A).pkg: \
|
||||
$(LIBC_VGA_A_OBJS) \
|
||||
$(foreach x,$(LIBC_VGA_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
LIBC_VGA_LIBS = $(foreach x,$(LIBC_VGA_ARTIFACTS),$($(x)))
|
||||
LIBC_VGA_SRCS = $(foreach x,$(LIBC_VGA_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_VGA_HDRS = $(foreach x,$(LIBC_VGA_ARTIFACTS),$($(x)_HDRS))
|
||||
LIBC_VGA_BINS = $(foreach x,$(LIBC_VGA_ARTIFACTS),$($(x)_BINS))
|
||||
LIBC_VGA_CHECKS = $(foreach x,$(LIBC_VGA_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_VGA_OBJS = $(foreach x,$(LIBC_VGA_ARTIFACTS),$($(x)_OBJS))
|
||||
LIBC_VGA_TESTS = $(foreach x,$(LIBC_VGA_ARTIFACTS),$($(x)_TESTS))
|
||||
$(LIBC_VGA_OBJS): $(BUILD_FILES) libc/vga/vga.mk
|
||||
|
||||
.PHONY: o/$(MODE)/libc/vga
|
||||
o/$(MODE)/libc/vga: $(LIBC_VGA_CHECKS)
|
129
libc/vga/writev-vga.c
Normal file
129
libc/vga/writev-vga.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ This is free and unencumbered software released into the public domain. │
|
||||
│ │
|
||||
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||
│ distribute this software, either in source code form or as a compiled │
|
||||
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||
│ means. │
|
||||
│ │
|
||||
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||
│ of this software dedicate any and all copyright interest in the │
|
||||
│ software to the public domain. We make this dedication for the benefit │
|
||||
│ of the public at large and to the detriment of our heirs and │
|
||||
│ successors. We intend this dedication to be an overt act of │
|
||||
│ relinquishment in perpetuity of all present and future rights to this │
|
||||
│ software under copyright law. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/vga/vga.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define CRTPORT 0x3d4
|
||||
#define WIDTH 80
|
||||
|
||||
typedef struct {
|
||||
char ch;
|
||||
uint8_t attr;
|
||||
} char_cell_t;
|
||||
|
||||
typedef char_cell_t char_row_t[WIDTH];
|
||||
|
||||
const char vga_console[0];
|
||||
|
||||
static unsigned short height = 25, curr_row = 12, curr_col = 0;
|
||||
static uint8_t curr_attr = 0x07;
|
||||
|
||||
static void scroll(void) {
|
||||
unsigned j;
|
||||
uint8_t attr = curr_attr;
|
||||
char_row_t * const vid_buf = (char_row_t *)(BANE + 0xb8000ull);
|
||||
memmove(vid_buf, vid_buf + 1, (height - 1) * sizeof(char_row_t));
|
||||
for (j = 0; j < WIDTH; ++j)
|
||||
vid_buf[height - 1][j] = (char_cell_t){ ' ', attr };
|
||||
}
|
||||
|
||||
static void may_scroll(void) {
|
||||
if (curr_col >= WIDTH) {
|
||||
curr_col = 0;
|
||||
scroll();
|
||||
}
|
||||
}
|
||||
|
||||
static void updatexy_vga(void) {
|
||||
unsigned short pos = curr_row * WIDTH + curr_col;
|
||||
outb(CRTPORT, 0x0e);
|
||||
outb(CRTPORT + 1, (unsigned char)(pos >> 8));
|
||||
outb(CRTPORT, 0x0f);
|
||||
outb(CRTPORT + 1, (unsigned char)pos);
|
||||
}
|
||||
|
||||
static void writec_vga(char c) {
|
||||
/* TODO: ensure screen in a known mode (text or graphics), at rlinit time */
|
||||
/* TODO: use our own font, rather than rely on BIOS's CP437 font */
|
||||
/* TODO: handle UTF-8 multi-bytes */
|
||||
/* TODO: handle VT102 escape sequences */
|
||||
/* TODO: maybe make BEL (\a) character code emit an alarm of some sort */
|
||||
char_row_t * const vid_buf = (char_row_t *)(BANE + 0xb8000ull);
|
||||
uint8_t attr = curr_attr;
|
||||
unsigned short col;
|
||||
switch (c) {
|
||||
case '\b':
|
||||
if (curr_col) {
|
||||
col = curr_col - 1;
|
||||
vid_buf[curr_row][col] = (char_cell_t){ ' ', attr };
|
||||
curr_col = col;
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
col = curr_col;
|
||||
do {
|
||||
vid_buf[curr_row][col] = (char_cell_t){ ' ', attr };
|
||||
++col;
|
||||
} while (col % 8 != 0);
|
||||
curr_col = col;
|
||||
may_scroll();
|
||||
break;
|
||||
case '\r':
|
||||
curr_col = 0;
|
||||
break;
|
||||
case '\n':
|
||||
curr_col = 0;
|
||||
if (curr_row < height - 1)
|
||||
++curr_row;
|
||||
else
|
||||
scroll();
|
||||
break;
|
||||
default:
|
||||
col = curr_col;
|
||||
vid_buf[curr_row][col] = (char_cell_t){ c, attr };
|
||||
curr_col = col + 1;
|
||||
may_scroll();
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
char_row_t * const vid_buf = (char_row_t *)(BANE + 0xb8000ull);
|
||||
size_t i, j, wrote = 0;
|
||||
for (i = 0; i < iovlen; ++i) {
|
||||
const char *input = (const char *)iov[i].iov_base;
|
||||
for (j = 0; j < iov[i].iov_len; ++j) {
|
||||
writec_vga(input[j]);
|
||||
++wrote;
|
||||
}
|
||||
}
|
||||
updatexy_vga();
|
||||
return wrote;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue