This commit is joint work by Meisaka Yukara <Meisaka.Yukara@gmail.com> and Jonas 'Sortie' Termansen <sortie@maxsi.org>.
267 lines
7.9 KiB
C++
267 lines
7.9 KiB
C++
/*
|
|
* Copyright (c) 2011-2017 Jonas 'Sortie' Termansen.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* log.cpp
|
|
* A system for logging various messages to the kernel log.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include <sortix/kernel/addralloc.h>
|
|
#include <sortix/kernel/kernel.h>
|
|
#include <sortix/kernel/log.h>
|
|
#include <sortix/kernel/memorymanagement.h>
|
|
#include <sortix/kernel/pci.h>
|
|
#include <sortix/kernel/pci-mmio.h>
|
|
#include <sortix/kernel/textbuffer.h>
|
|
|
|
#include "lfbtextbuffer.h"
|
|
#include "multiboot.h"
|
|
#include "textterminal.h"
|
|
#include "vgatextbuffer.h"
|
|
|
|
namespace Sortix {
|
|
namespace Log {
|
|
|
|
uint8_t* fallback_framebuffer = NULL;
|
|
size_t fallback_framebuffer_bpp = 0;
|
|
size_t fallback_framebuffer_pitch = 0;
|
|
size_t fallback_framebuffer_width = 0;
|
|
size_t fallback_framebuffer_height = 0;
|
|
|
|
TextBufferHandle* device_textbufhandle = NULL;
|
|
size_t (*device_callback)(void*, const char*, size_t) = NULL;
|
|
size_t (*device_writeraw)(void*, const char*, size_t) = NULL;
|
|
size_t (*device_width)(void*) = NULL;
|
|
size_t (*device_height)(void*) = NULL;
|
|
void (*device_get_cursor)(void*, size_t*, size_t*) = NULL;
|
|
bool (*device_sync)(void*) = NULL;
|
|
void (*device_invalidate)(void*) = NULL;
|
|
void* device_pointer = NULL;
|
|
bool (*emergency_device_is_impaired)(void*) = NULL;
|
|
bool (*emergency_device_recoup)(void*) = NULL;
|
|
void (*emergency_device_reset)(void*) = NULL;
|
|
size_t (*emergency_device_callback)(void*, const char*, size_t) = NULL;
|
|
size_t (*emergency_device_writeraw)(void*, const char*, size_t) = NULL;
|
|
size_t (*emergency_device_width)(void*) = NULL;
|
|
void (*emergency_device_get_cursor)(void*, size_t*, size_t*) = NULL;
|
|
size_t (*emergency_device_height)(void*) = NULL;
|
|
bool (*emergency_device_sync)(void*) = NULL;
|
|
void* emergency_device_pointer = NULL;
|
|
|
|
static size_t PrintToTextTerminal(void* user, const char* str, size_t len)
|
|
{
|
|
return ((TextTerminal*) user)->Print(str, len);
|
|
}
|
|
|
|
static size_t PrintRawToTextTerminal(void* user, const char* str, size_t len)
|
|
{
|
|
return ((TextTerminal*) user)->PrintRaw(str, len);
|
|
}
|
|
|
|
static size_t TextTermWidth(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->Width();
|
|
}
|
|
|
|
static size_t TextTermHeight(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->Height();
|
|
}
|
|
|
|
static void TextTermGetCursor(void* user, size_t* column, size_t* row)
|
|
{
|
|
((TextTerminal*) user)->GetCursor(column, row);
|
|
}
|
|
|
|
static bool TextTermSync(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->Sync();
|
|
}
|
|
|
|
static void TextTermInvalidate(void* user)
|
|
{
|
|
((TextTerminal*) user)->Invalidate();
|
|
}
|
|
|
|
static bool EmergencyTextTermIsImpaired(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->EmergencyIsImpaired();
|
|
}
|
|
|
|
static bool EmergencyTextTermRecoup(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->EmergencyRecoup();
|
|
}
|
|
|
|
static void EmergencyTextTermReset(void* user)
|
|
{
|
|
((TextTerminal*) user)->EmergencyReset();
|
|
}
|
|
|
|
static
|
|
size_t EmergencyPrintToTextTerminal(void* user, const char* str, size_t len)
|
|
{
|
|
return ((TextTerminal*) user)->EmergencyPrint(str, len);
|
|
}
|
|
|
|
static
|
|
size_t EmergencyPrintRawToTextTerminal(void* user, const char* str, size_t len)
|
|
{
|
|
return ((TextTerminal*) user)->EmergencyPrintRaw(str, len);
|
|
}
|
|
|
|
static size_t EmergencyTextTermWidth(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->EmergencyWidth();
|
|
}
|
|
|
|
static size_t EmergencyTextTermHeight(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->EmergencyHeight();
|
|
}
|
|
|
|
static void EmergencyTextTermGetCursor(void* user, size_t* column, size_t* row)
|
|
{
|
|
((TextTerminal*) user)->EmergencyGetCursor(column, row);
|
|
}
|
|
|
|
static bool EmergencyTextTermSync(void* user)
|
|
{
|
|
return ((TextTerminal*) user)->EmergencySync();
|
|
}
|
|
|
|
void Init(multiboot_info_t* bootinfo)
|
|
{
|
|
(void) bootinfo;
|
|
|
|
const char* oom_msg = "Out of memory setting up kernel log.";
|
|
|
|
// Create the backend text buffer.
|
|
TextBuffer* textbuf;
|
|
if ( (bootinfo->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) &&
|
|
bootinfo->framebuffer_type != MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT )
|
|
{
|
|
assert(bootinfo->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_RGB);
|
|
assert(bootinfo->framebuffer_bpp == 24 ||
|
|
bootinfo->framebuffer_bpp == 32);
|
|
assert(0 < bootinfo->framebuffer_width);
|
|
assert(0 < bootinfo->framebuffer_height);
|
|
pcibar_t fakebar;
|
|
fakebar.addr_raw = bootinfo->framebuffer_addr;
|
|
fakebar.size_raw = (uint64_t) bootinfo->framebuffer_pitch * bootinfo->framebuffer_height;
|
|
fakebar.addr_raw |= PCIBAR_TYPE_64BIT;
|
|
addralloc_t fb_alloc;
|
|
if ( !MapPCIBAR(&fb_alloc, fakebar, Memory::PAT_WC) )
|
|
Panic("Framebuffer setup failure.");
|
|
uint8_t* lfb = (uint8_t*) fb_alloc.from;
|
|
uint32_t lfbformat = bootinfo->framebuffer_bpp;
|
|
size_t scansize = bootinfo->framebuffer_pitch;
|
|
textbuf = CreateLFBTextBuffer(lfb, lfbformat, bootinfo->framebuffer_width,
|
|
bootinfo->framebuffer_height, scansize);
|
|
if ( !textbuf )
|
|
Panic(oom_msg);
|
|
fallback_framebuffer = lfb;
|
|
fallback_framebuffer_bpp = lfbformat;
|
|
fallback_framebuffer_width = bootinfo->framebuffer_width;
|
|
fallback_framebuffer_height = bootinfo->framebuffer_height;
|
|
fallback_framebuffer_pitch = bootinfo->framebuffer_pitch;
|
|
}
|
|
else
|
|
{
|
|
uint16_t* const VGAFB = (uint16_t*) 0xB8000;
|
|
const size_t VGA_WIDTH = 80;
|
|
const size_t VGA_HEIGHT = 25;
|
|
TextChar* vga_chars_buffer = new TextChar[VGA_WIDTH * VGA_HEIGHT];
|
|
if ( !vga_chars_buffer )
|
|
Panic(oom_msg);
|
|
textbuf = new VGATextBuffer(VGAFB, vga_chars_buffer, VGA_WIDTH, VGA_HEIGHT);
|
|
if ( !textbuf )
|
|
Panic(oom_msg);
|
|
}
|
|
|
|
// Create the text buffer handle.
|
|
device_textbufhandle = new TextBufferHandle(textbuf);
|
|
if ( !device_textbufhandle )
|
|
Panic(oom_msg);
|
|
|
|
// Setup a text terminal instance.
|
|
TextTerminal* textterm = new TextTerminal(device_textbufhandle);
|
|
if ( !textterm )
|
|
Panic(oom_msg);
|
|
|
|
// Register the text terminal as the kernel log.
|
|
Log::device_callback = PrintToTextTerminal;
|
|
Log::device_writeraw = PrintRawToTextTerminal;
|
|
Log::device_width = TextTermWidth;
|
|
Log::device_height = TextTermHeight;
|
|
Log::device_get_cursor = TextTermGetCursor;
|
|
Log::device_sync = TextTermSync;
|
|
Log::device_invalidate = TextTermInvalidate;
|
|
Log::device_pointer = textterm;
|
|
|
|
// Register the emergency kernel log.
|
|
Log::emergency_device_is_impaired = EmergencyTextTermIsImpaired;
|
|
Log::emergency_device_recoup = EmergencyTextTermRecoup;
|
|
Log::emergency_device_reset = EmergencyTextTermReset;
|
|
Log::emergency_device_callback = EmergencyPrintToTextTerminal;
|
|
Log::emergency_device_writeraw = EmergencyPrintRawToTextTerminal;
|
|
Log::emergency_device_width = EmergencyTextTermWidth;
|
|
Log::emergency_device_height = EmergencyTextTermHeight;
|
|
Log::emergency_device_get_cursor = EmergencyTextTermGetCursor;
|
|
Log::emergency_device_sync = EmergencyTextTermSync;
|
|
Log::emergency_device_pointer = textterm;
|
|
}
|
|
|
|
void Center(const char* string)
|
|
{
|
|
size_t log_width = Log::Width();
|
|
while ( *string )
|
|
{
|
|
size_t string_width = strcspn(string, "\n");
|
|
size_t leading = string_width <= log_width ?
|
|
(log_width - string_width) / 2 : 0;
|
|
for ( size_t i = 0; i < leading; i++ )
|
|
Log::Print(" ");
|
|
Log::PrintData(string, string_width);
|
|
string += string_width;
|
|
if ( *string == '\n' )
|
|
{
|
|
string++;
|
|
Log::Print("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void BeginReplace()
|
|
{
|
|
((TextTerminal*) Log::device_pointer)->BeginReplace();
|
|
}
|
|
|
|
void CancelReplace()
|
|
{
|
|
((TextTerminal*) Log::device_pointer)->CancelReplace();
|
|
}
|
|
|
|
void FinishReplace(TextBuffer* textbuf)
|
|
{
|
|
((TextTerminal*) Log::device_pointer)->FinishReplace(textbuf);
|
|
}
|
|
|
|
} // namespace Log
|
|
} // namespace Sortix
|