Add console, klog, and writef modules.

They are not complete, but adding to checkpoint progress.
This commit is contained in:
Josh Holtrop 2022-03-24 17:52:39 -04:00
parent e214a9c3de
commit 06242a0c9f
5 changed files with 373 additions and 0 deletions

72
src/hulk/console.d Normal file
View File

@ -0,0 +1,72 @@
/**
* HULK Console functionality.
*/
module hulk.console;
import hulk.framebuffer;
import hulk.kfont;
struct Console
{
Framebuffer * m_fb;
size_t m_width;
size_t m_height;
size_t m_x;
size_t m_y;
public void initialize(Framebuffer * fb)
{
m_fb = fb;
m_width = fb.width / kfont.advance;
m_height = fb.height / kfont.line_height;
}
public void clear()
{
m_fb.clear();
m_x = 0u;
m_y = 0u;
}
public void write(char ch)
{
if (ch == '\n')
{
m_x = 0u;
m_y++;
}
else
{
render_char(m_x, m_y, ch);
m_x++;
if (m_x == m_width)
{
m_x = 0u;
m_y++;
}
}
if (m_y == m_height)
{
m_y--;
m_fb.copy_rows_up(fb_y(m_height - 1u),
(m_height - 1u) * kfont.line_height,
kfont.line_height);
}
}
private void render_char(size_t x, size_t y, char ch)
{
const(CharInfo) * ci = &kfont.chars[ch];
m_fb.blit_alpha_bitmap(fb_x(x) + ci.left, fb_y(y) + ci.top - ci.height, ci.bitmap, ci.width, ci.height);
}
private size_t fb_x(size_t x)
{
return x * kfont.advance;
}
private size_t fb_y(size_t y)
{
return m_fb.height - ((y + 1u) * kfont.line_height);
}
}

View File

@ -28,6 +28,22 @@ struct Framebuffer
/** Number of pixels in the frame buffer (whether visible or not). */
private uint m_buffer_size;
/**
* Get the framebuffer width.
*/
public @property uint width()
{
return m_width;
}
/**
* Get the framebuffer height.
*/
public @property uint height()
{
return m_height;
}
/**
* Initialize a frame buffer.
*
@ -168,6 +184,52 @@ struct Framebuffer
blend_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height, color);
}
/**
* Blit an 8-bit alpha bitmap to the framebuffer.
* The foreground will be white (based on the alpha value), and the
* background black.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
*/
void blit_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap,
size_t width, size_t height)
{
y += height - 1u;
size_t bitmap_index;
for (size_t iy = 0u; iy < height; iy++)
{
for (size_t ix = 0u; ix < width; ix++)
{
size_t buffer_index = buffer_index(x + ix, y);
ubyte alpha = alpha_bitmap[bitmap_index];
m_buffer[buffer_index] = (alpha << 16u) | (alpha << 8u) | alpha;
bitmap_index++;
}
y--;
}
}
/**
* Blit an 8-bit alpha bitmap to the framebuffer.
* The foreground will be white (based on the alpha value), and the
* background black.
*
* @param x X coordinate of left side of target location.
* @param y Y coordinate of bottom side of target location.
* @param alpha_bitmap 8-bit alpha-channel bitmap.
* @param width Bitmap width.
* @param height Bitmap height.
*/
void blit_alpha_bitmap(size_t x, size_t y, const(ubyte)[] alpha_bitmap,
size_t width, size_t height)
{
blit_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height);
}
/**
* Copy framebuffer rows up in the framebuffer.
*

View File

@ -6,11 +6,14 @@ module hulk.hulk;
import hulk.header;
import hulk.bootinfo;
import hulk.framebuffer;
import hulk.console;
import hos.memory;
import ldc.attributes;
import hulk.kfont;
static import hulk.klog;
private __gshared Framebuffer fb;
private __gshared Console console;
extern extern(C) __gshared ubyte _hulk_total_size;
@ -44,6 +47,15 @@ extern(C) void hulk_start(ulong rdi, ulong rsi, ulong rdx, BootInfo * bootinfo)
x += kfont.advance;
}
console.initialize(&fb);
console.clear();
hulk.klog.initialize(&console);
for (size_t i = 1u; i != 0u; i++)
{
hulk.klog.writef("Hello! i = %010u\n", i);
}
for (;;)
{
}

76
src/hulk/klog.d Normal file
View File

@ -0,0 +1,76 @@
/**
* HULK Kernel Log buffer.
*/
module hulk.klog;
import core.stdc.stdarg;
import hulk.console;
static import hulk.writef;
/**
* Kernel buffer size log.
* 16 gives a kernel buffer size of 64KB.
*/
enum size_t KLOG_SIZE_LOG = 16u;
/** Kernel buffer size. */
enum size_t KLOG_SIZE = 1u << KLOG_SIZE_LOG;
/** Kernel log buffer. */
private __gshared align(4096) char[KLOG_SIZE] klog_buffer;
/** Write index in the kernel log buffer. */
private __gshared size_t klog_index;
/** Pointer to the console to use for kernel log output. */
private __gshared Console * console;
/**
* Initialize the klog module.
*
* @param console Pointer to the Console to use for kernel output.
*/
void initialize(Console * console)
{
.console = console;
}
/**
* Write a formatted string to the kernel log.
*
* @param s Format string.
* @param args Variable arguments structure.
*/
void writef(string s, va_list args)
{
hulk.writef.writef(s, args, function void(ubyte ch) {
console.write(ch);
});
}
/**
* Write a formatted string to the kernel log.
*
* @param s Format string.
*/
extern (C) void writef(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
va_end(args);
}
/**
* Write a formatted string and newline to the console.
*
* @param s Format string.
*/
extern (C) void writefln(string s, ...)
{
va_list args;
va_start(args, s);
writef(s, args);
writef("\n", args);
va_end(args);
}

151
src/hulk/writef.d Normal file
View File

@ -0,0 +1,151 @@
/**
* HULK Formatted stream writing support.
*/
module hulk.writef;
import core.stdc.stdarg;
alias ch_out_fn = void function(ubyte);
/**
* Format a string and write characters to the given output function.
*
* @param s Format string.
* @param args Variable arguments structure.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
size_t writef(string s, va_list args, ch_out_fn ch_out)
{
size_t length_written;
bool escape = false;
char pad = ' ';
size_t width;
foreach (char c; s)
{
if (escape)
{
if (c == 'x')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, false, pad, width, ch_out);
escape = false;
}
else if (c == 'X')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, true, pad, width, ch_out);
escape = false;
}
else if (c == 'u')
{
ulong v;
va_arg(args, v);
length_written += write_udec(v, pad, width, ch_out);
escape = false;
}
else if ((c == '0') && (width == 0u))
{
pad = '0';
}
else if (('0' <= c) && (c <= '9'))
{
width = (width * 10u) + (c - '0');
}
else
{
ch_out(c);
escape = false;
}
}
else if (c == '%')
{
escape = true;
pad = ' ';
width = 0u;
}
else
{
ch_out(c);
}
}
return length_written;
}
/**
* Format a value in hexadecimal to the given output function.
*
* @param v Value to format.
* @param upper Whether to use uppercase letters.
* @param pad Pad character to use.
* @param width Field width.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
private size_t write_hex(ulong v, bool upper, char pad, size_t width, ch_out_fn ch_out)
{
string hex_chars_lower = "0123456789abcdef";
string hex_chars_upper = "0123456789ABCDEF";
char[16] buf;
size_t i;
do
{
ulong n = v & 0xFu;
buf[i] = upper ? hex_chars_upper[n] : hex_chars_lower[n];
v >>= 4u;
i++;
} while (v != 0u);
size_t length_written = i;
while (width > i)
{
ch_out(pad);
width--;
length_written++;
}
do
{
i--;
ch_out(buf[i]);
} while (i != 0u);
return length_written;
}
/**
* Format a value in decimal to the given output function.
*
* @param v Value to format.
* @param pad Pad character to use.
* @param width Field width.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
private size_t write_udec(ulong v, char pad, size_t width, ch_out_fn ch_out)
{
char[20] buf;
size_t i;
do
{
ulong d = v % 10u;
buf[i] = cast(char)(d + '0');
v /= 10u;
i++;
} while (v != 0u);
size_t length_written = i;
while (width > i)
{
ch_out(pad);
width--;
length_written++;
}
do
{
i--;
ch_out(buf[i]);
} while (i != 0u);
return length_written;
}