/* * 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 #include #include #include #include #include #include #include #include #include #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