diff --git a/sortix/include/sortix/kernel/log.h b/sortix/include/sortix/kernel/log.h index 504c6849..532ed43e 100644 --- a/sortix/include/sortix/kernel/log.h +++ b/sortix/include/sortix/kernel/log.h @@ -38,12 +38,14 @@ extern size_t (*device_width)(void*); extern size_t (*device_height)(void*); extern bool (*device_sync)(void*); extern void* device_pointer; - -void Init(size_t (*callback)(void*, const char*, size_t), - size_t (*widthfunc)(void*), - size_t (*heightfunc)(void*), - bool (*syncfunc)(void*), - void* user); +extern bool (*emergency_device_is_impaired)(void*); +extern bool (*emergency_device_recoup)(void*); +extern void (*emergency_device_reset)(void*); +extern size_t (*emergency_device_callback)(void*, const char*, size_t); +extern size_t (*emergency_device_width)(void*); +extern size_t (*emergency_device_height)(void*); +extern bool (*emergency_device_sync)(void*); +extern void* emergency_device_pointer; inline void Flush() { diff --git a/sortix/include/sortix/kernel/textbuffer.h b/sortix/include/sortix/kernel/textbuffer.h index 4a2331bf..ffb0ef67 100644 --- a/sortix/include/sortix/kernel/textbuffer.h +++ b/sortix/include/sortix/kernel/textbuffer.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -74,6 +74,9 @@ public: virtual void SetCursorEnabled(bool enablecursor) = 0; virtual TextPos GetCursorPos() const = 0; virtual void SetCursorPos(TextPos cursorpos) = 0; + virtual bool EmergencyIsImpaired() = 0; + virtual bool EmergencyRecoup() = 0; + virtual void EmergencyReset() = 0; }; @@ -91,6 +94,11 @@ public: TextBuffer* Acquire(); void Release(TextBuffer* textbuf); void Replace(TextBuffer* newtextbuf, bool deletebuf = true); + bool EmergencyIsImpaired(); + bool EmergencyRecoup(); + void EmergencyReset(); + TextBuffer* EmergencyAcquire(); + void EmergencyRelease(TextBuffer* textbuf); private: kthread_mutex_t mutex; diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp index c4fc7075..927e0ecf 100644 --- a/sortix/kernel.cpp +++ b/sortix/kernel.cpp @@ -135,6 +135,42 @@ static bool TextTermSync(void* user) return ((TextTerminal*) user)->Sync(); } +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 EmergencyTextTermWidth(void* user) +{ + return ((TextTerminal*) user)->EmergencyWidth(); +} + +static size_t EmergencyTextTermHeight(void* user) +{ + return ((TextTerminal*) user)->EmergencyHeight(); +} + +static bool EmergencyTextTermSync(void* user) +{ + return ((TextTerminal*) user)->EmergencySync(); +} + addr_t initrd; size_t initrdsize; Ref textbufhandle; @@ -167,9 +203,22 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) // Setup a text terminal instance. TextTerminal textterm(textbufhandle); - // Register the text terminal as the kernel log and initialize it. - Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, TextTermSync, - &textterm); + // Register the text terminal as the kernel log. + Log::device_callback = PrintToTextTerminal; + Log::device_width = TextTermWidth; + Log::device_height = TextTermHeight; + Log::device_sync = TextTermSync; + 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_width = EmergencyTextTermWidth; + Log::emergency_device_height = EmergencyTextTermHeight; + Log::emergency_device_sync = EmergencyTextTermSync; + Log::emergency_device_pointer = &textterm; // Display the boot welcome screen. DoWelcome(); diff --git a/sortix/lfbtextbuffer.cpp b/sortix/lfbtextbuffer.cpp index 27280696..fc24886a 100644 --- a/sortix/lfbtextbuffer.cpp +++ b/sortix/lfbtextbuffer.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -83,6 +83,7 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat, goto cleanup_queue; memcpy(font, VGA::GetFont(), fontsize); + ret->execute_lock = KTHREAD_MUTEX_INITIALIZER; ret->queue_lock = KTHREAD_MUTEX_INITIALIZER; ret->queue_not_full = KTHREAD_COND_INITIALIZER; ret->queue_not_empty = KTHREAD_COND_INITIALIZER; @@ -120,6 +121,7 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat, ret->cursorpos = TextPos(0, 0); for ( size_t y = 0; y < yres; y++ ) memset(lfb + scansize * y, 0, lfbformat/8UL * xres); + ret->emergency_state = false; if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) ) { @@ -304,6 +306,18 @@ void LFBTextBuffer::RenderRange(TextPos from, TextPos to) void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd) { + if ( emergency_state ) + { + bool exit_requested = false; + bool sync_requested = false; + bool pause_requested = false; + TextPos render_from(columns - 1, rows - 1); + TextPos render_to(0, 0); + ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested, render_from, render_to); + if ( !IsTextPosBeforeTextPos(render_to, render_from) ) + RenderRange(render_from, render_to); + return; + } ScopedLock lock(&queue_lock); while ( queue_used == queue_length ) kthread_cond_wait(&queue_not_full, &queue_lock); @@ -314,6 +328,8 @@ void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd) void LFBTextBuffer::StopRendering() { + if ( emergency_state ) + return; TextBufferCmd cmd; cmd.type = TEXTBUFCMD_PAUSE; IssueCommand(&cmd); @@ -324,6 +340,8 @@ void LFBTextBuffer::StopRendering() void LFBTextBuffer::ResumeRendering() { + if ( emergency_state ) + return; ScopedLock lock(&queue_lock); queue_is_paused = false; kthread_cond_signal(&queue_resume); @@ -496,6 +514,114 @@ void LFBTextBuffer::DoFill(TextPos from, TextPos to, uint16_t fillwith, attrs[i] = fillattr; } +bool LFBTextBuffer::IsCommandIdempotent(const TextBufferCmd* cmd) const +{ + switch ( cmd->type ) + { + case TEXTBUFCMD_EXIT: return true; + case TEXTBUFCMD_SYNC: return true; + case TEXTBUFCMD_PAUSE: return true; + case TEXTBUFCMD_CHAR: return true; + case TEXTBUFCMD_ATTR: return true; + case TEXTBUFCMD_CURSOR_SET_ENABLED: return true; + case TEXTBUFCMD_CURSOR_MOVE: return true; + case TEXTBUFCMD_MOVE: return false; + case TEXTBUFCMD_FILL: return true; + case TEXTBUFCMD_SCROLL: return false; + default: return false; + } +} + +void LFBTextBuffer::ExecuteCommand(TextBufferCmd* cmd, + bool& exit_requested, + bool& sync_requested, + bool& pause_requested, + TextPos& render_from, + TextPos& render_to) +{ + switch ( cmd->type ) + { + case TEXTBUFCMD_EXIT: + exit_requested = true; + break; + case TEXTBUFCMD_SYNC: + sync_requested = true; + break; + case TEXTBUFCMD_PAUSE: + pause_requested = true; + break; + case TEXTBUFCMD_CHAR: + { + TextPos pos(cmd->x, cmd->y); + chars[pos.y * columns + pos.x] = cmd->c; + if ( IsTextPosBeforeTextPos(pos, render_from) ) + render_from = pos; + if ( IsTextPosAfterTextPos(pos, render_to) ) + render_to = pos; + } break; + case TEXTBUFCMD_ATTR: + { + TextPos pos(cmd->x, cmd->y); + attrs[pos.y * columns + pos.x] = cmd->attr; + } break; + case TEXTBUFCMD_CURSOR_SET_ENABLED: + if ( cmd->b != cursorenabled ) + { + cursorenabled = cmd->b; + if ( IsTextPosBeforeTextPos(cursorpos, render_from) ) + render_from = cursorpos; + if ( IsTextPosAfterTextPos(cursorpos, render_to) ) + render_to = cursorpos; + } + break; + case TEXTBUFCMD_CURSOR_MOVE: + { + TextPos pos(cmd->x, cmd->y); + if ( cursorpos.x != pos.x || cursorpos.y != pos.y ) + { + if ( IsTextPosBeforeTextPos(cursorpos, render_from) ) + render_from = cursorpos; + if ( IsTextPosAfterTextPos(cursorpos, render_to) ) + render_to = cursorpos; + cursorpos = pos; + if ( IsTextPosBeforeTextPos(cursorpos, render_from) ) + render_from = cursorpos; + if ( IsTextPosAfterTextPos(cursorpos, render_to) ) + render_to = cursorpos; + } + } break; + case TEXTBUFCMD_MOVE: + { + TextPos to(cmd->to_x, cmd->to_y); + TextPos from(cmd->from_x, cmd->from_y); + size_t numchars = cmd->val; + DoMove(to, from, numchars); + TextPos toend = AddToPosition(to, numchars); + if ( IsTextPosBeforeTextPos(to, render_from) ) + render_from = to; + if ( IsTextPosAfterTextPos(toend, render_to) ) + render_to = toend; + } break; + case TEXTBUFCMD_FILL: + { + TextPos from(cmd->from_x, cmd->from_y); + TextPos to(cmd->to_x, cmd->to_y); + DoFill(from, to, cmd->c, cmd->attr); + if ( IsTextPosBeforeTextPos(from, render_from) ) + render_from = from; + if ( IsTextPosAfterTextPos(to, render_to) ) + render_to = to; + } break; + case TEXTBUFCMD_SCROLL: + { + ssize_t off = cmd->scroll_offset; + DoScroll(off, cmd->c); + render_from = {0, 0}; + render_to = {columns-1, rows-1}; + } break; + } +} + void LFBTextBuffer::RenderThread() { queue_is_paused = false; @@ -549,98 +675,79 @@ void LFBTextBuffer::RenderThread() kthread_mutex_unlock(&queue_lock); + execute_amount = amount; + + kthread_mutex_lock(&execute_lock); + TextPos render_from(columns - 1, rows - 1); TextPos render_to(0, 0); for ( size_t i = 0; i < amount; i++ ) { TextBufferCmd* cmd = &queue[(offset + i) % queue_length]; - switch ( cmd->type ) - { - case TEXTBUFCMD_EXIT: - exit_requested = true; - break; - case TEXTBUFCMD_SYNC: - sync_requested = true; - break; - case TEXTBUFCMD_PAUSE: - pause_requested = true; - break; - case TEXTBUFCMD_CHAR: - { - TextPos pos(cmd->x, cmd->y); - chars[pos.y * columns + pos.x] = cmd->c; - if ( IsTextPosBeforeTextPos(pos, render_from) ) - render_from = pos; - if ( IsTextPosAfterTextPos(pos, render_to) ) - render_to = pos; - } break; - case TEXTBUFCMD_ATTR: - { - TextPos pos(cmd->x, cmd->y); - attrs[pos.y * columns + pos.x] = cmd->attr; - } break; - case TEXTBUFCMD_CURSOR_SET_ENABLED: - if ( cmd->b != cursorenabled ) - { - cursorenabled = cmd->b; - if ( IsTextPosBeforeTextPos(cursorpos, render_from) ) - render_from = cursorpos; - if ( IsTextPosAfterTextPos(cursorpos, render_to) ) - render_to = cursorpos; - } - break; - case TEXTBUFCMD_CURSOR_MOVE: - { - TextPos pos(cmd->x, cmd->y); - if ( cursorpos.x != pos.x || cursorpos.y != pos.y ) - { - if ( IsTextPosBeforeTextPos(cursorpos, render_from) ) - render_from = cursorpos; - if ( IsTextPosAfterTextPos(cursorpos, render_to) ) - render_to = cursorpos; - cursorpos = pos; - if ( IsTextPosBeforeTextPos(cursorpos, render_from) ) - render_from = cursorpos; - if ( IsTextPosAfterTextPos(cursorpos, render_to) ) - render_to = cursorpos; - } - } break; - case TEXTBUFCMD_MOVE: - { - TextPos to(cmd->to_x, cmd->to_y); - TextPos from(cmd->from_x, cmd->from_y); - size_t numchars = cmd->val; - DoMove(to, from, numchars); - TextPos toend = AddToPosition(to, numchars); - if ( IsTextPosBeforeTextPos(to, render_from) ) - render_from = to; - if ( IsTextPosAfterTextPos(toend, render_to) ) - render_to = toend; - } break; - case TEXTBUFCMD_FILL: - { - TextPos from(cmd->from_x, cmd->from_y); - TextPos to(cmd->to_x, cmd->to_y); - DoFill(from, to, cmd->c, cmd->attr); - if ( IsTextPosBeforeTextPos(from, render_from) ) - render_from = from; - if ( IsTextPosAfterTextPos(to, render_to) ) - render_to = to; - } break; - case TEXTBUFCMD_SCROLL: - { - ssize_t off = cmd->scroll_offset; - DoScroll(off, cmd->c); - render_from = {0, 0}; - render_to = {columns-1, rows-1}; - } break; - } + ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested, render_from, render_to); } + kthread_mutex_unlock(&execute_lock); + if ( !IsTextPosBeforeTextPos(render_to, render_from) ) RenderRange(render_from, render_to); } } +bool LFBTextBuffer::EmergencyIsImpaired() +{ + return !emergency_state; +} + +bool LFBTextBuffer::EmergencyRecoup() +{ + if ( !emergency_state ) + emergency_state = true; + + if ( !kthread_mutex_trylock(&queue_lock) ) + return false; + kthread_mutex_unlock(&queue_lock); + + if ( !kthread_mutex_trylock(&execute_lock) ) + { + for ( size_t i = 0; i < execute_amount; i++ ) + { + TextBufferCmd* cmd = &queue[(queue_offset + i) % queue_length]; + if ( !IsCommandIdempotent(cmd) ) + return false; + } + } + else + kthread_mutex_unlock(&execute_lock); + + TextPos render_from(0, 0); + TextPos render_to(columns - 1, rows - 1); + + for ( size_t i = 0; i < queue_used; i++ ) + { + bool exit_requested = false; + bool sync_requested = false; + bool pause_requested = false; + TextBufferCmd* cmd = &queue[(queue_offset + i) % queue_length]; + ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested, + render_from, render_to); + } + + queue_used = 0; + queue_offset = 0; + + RenderRange(render_from, render_to); + + return true; +} + +void LFBTextBuffer::EmergencyReset() +{ + // TODO: Reset everything here! + + Fill(TextPos{0, 0}, TextPos{columns-1, rows-1}, TextChar{0, 0}, 0); + SetCursorPos(TextPos{0, 0}); +} + } // namespace Sortix diff --git a/sortix/lfbtextbuffer.h b/sortix/lfbtextbuffer.h index 726ccb38..9fd44404 100644 --- a/sortix/lfbtextbuffer.h +++ b/sortix/lfbtextbuffer.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -83,6 +83,9 @@ public: virtual void SetCursorEnabled(bool enablecursor); virtual TextPos GetCursorPos() const; virtual void SetCursorPos(TextPos newcursorpos); + virtual bool EmergencyIsImpaired(); + virtual bool EmergencyRecoup(); + virtual void EmergencyReset(); public: virtual void RenderThread(); @@ -102,8 +105,16 @@ private: void IssueCommand(TextBufferCmd* cmd); void StopRendering(); void ResumeRendering(); + bool IsCommandIdempotent(const TextBufferCmd* cmd) const; + void ExecuteCommand(TextBufferCmd* cmd, + bool& exit_requested, + bool& sync_requested, + bool& pause_requested, + TextPos& render_from, + TextPos& render_to); private: + kthread_mutex_t execute_lock; kthread_mutex_t queue_lock; kthread_cond_t queue_not_full; kthread_cond_t queue_not_empty; @@ -131,6 +142,8 @@ private: uint32_t lfbformat; bool cursorenabled; TextPos cursorpos; + bool emergency_state; + size_t execute_amount; }; diff --git a/sortix/log.cpp b/sortix/log.cpp index 8adf021e..31d73627 100644 --- a/sortix/log.cpp +++ b/sortix/log.cpp @@ -37,19 +37,14 @@ size_t (*device_width)(void*) = NULL; size_t (*device_height)(void*) = NULL; bool (*device_sync)(void*) = NULL; void* device_pointer = NULL; - -void Init(size_t (*callback)(void*, const char*, size_t), - size_t (*widthfunc)(void*), - size_t (*heightfunc)(void*), - bool (*syncfunc)(void*), - void* user) -{ - device_callback = callback; - device_width = widthfunc; - device_height = heightfunc; - device_sync = syncfunc; - device_pointer = user; -} +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_width)(void*) = NULL; +size_t (*emergency_device_height)(void*) = NULL; +bool (*emergency_device_sync)(void*) = NULL; +void* emergency_device_pointer = NULL; } // namespace Log } // namespace Sortix diff --git a/sortix/panic.cpp b/sortix/panic.cpp index 72b85f88..cb7178b9 100644 --- a/sortix/panic.cpp +++ b/sortix/panic.cpp @@ -41,6 +41,7 @@ const bool longpanic = true; static bool panicing = false; static bool doublepanic = false; +static bool logrecovering = false; static void PanicLogoLong() { @@ -54,8 +55,53 @@ static void PanicLogoShort() void PanicInit() { + // This is a kernel emergency. We will need to disable preemption, such that + // this is the only thread running. This means that we cannot acquire locks + // and the data protected by them may be inconsistent. Interrupt::Disable(); + // Detect whether a panic happened during the log recovery. + if ( logrecovering ) + { + // Oh no! We paniced during the log recovery that we will do momentarily + // - this means that there probably isn't anything we can do but halt. + HaltKernel(); + } + logrecovering = true; + + // The kernel log normally uses locks internally and the console may be + // rendered by a background thread. This means that we cannot use the normal + // kernel log, but that we rather need to switch to the kernel emergency + // log, which is able to cope with the potential inconsistencies. + + Log::device_callback = Log::emergency_device_callback; + Log::device_width = Log::emergency_device_width; + Log::device_height = Log::emergency_device_height; + Log::device_sync = Log::emergency_device_sync; + Log::device_pointer = Log::emergency_device_pointer; + + // Check whether the panic condition left the kernel log unharmed. + if ( !Log::emergency_device_is_impaired(Log::emergency_device_pointer) ) + { + // The kernel log device transitioned ideally to the emergency state. + } + + // Attempt to repair inconsistent state of the emergency log device. + else if ( Log::emergency_device_recoup(Log::emergency_device_pointer) ) + { + // The kernel log was successfully repaired and is ready for use in the + // current emergency state. + } + + // It was not possible to repair the emergency device properly, so instead + // we will need to perform a hard reset of the emergency device. + else + { + Log::emergency_device_reset(Log::emergency_device_pointer); + // The kernel log was successfully repaired and is ready for use in the + // current emergency state. + } + // Handle the case where the panic code caused another system crash. if ( panicing ) { diff --git a/sortix/textbuffer.cpp b/sortix/textbuffer.cpp index 1d668991..2e9443a7 100644 --- a/sortix/textbuffer.cpp +++ b/sortix/textbuffer.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -71,6 +71,41 @@ void TextBufferHandle::Release(TextBuffer* textbuf) kthread_cond_signal(&unusedcond); } +bool TextBufferHandle::EmergencyIsImpaired() +{ + if ( !kthread_mutex_trylock(&mutex) ) + return true; + kthread_mutex_unlock(&mutex); + return false; +} + +bool TextBufferHandle::EmergencyRecoup() +{ + if ( !EmergencyIsImpaired() ) + return true; + mutex = KTHREAD_MUTEX_INITIALIZER; + return true; +} + +void TextBufferHandle::EmergencyReset() +{ +} + +TextBuffer* TextBufferHandle::EmergencyAcquire() +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. + return textbuf ? textbuf : def; +} + +void TextBufferHandle::EmergencyRelease(TextBuffer* textbuf) +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. We don't maintain the reference count + // during this state, so this is a no-operation. + (void) textbuf; +} + void TextBufferHandle::Replace(TextBuffer* newtextbuf, bool deletebuf) { ScopedLock lock(&mutex); diff --git a/sortix/textterminal.cpp b/sortix/textterminal.cpp index 1d94256c..fc59bc8e 100644 --- a/sortix/textterminal.cpp +++ b/sortix/textterminal.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -102,6 +102,116 @@ bool TextTerminal::Sync() return true; } +bool TextTerminal::EmergencyIsImpaired() +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. + + if ( !kthread_mutex_trylock(&termlock) ) + return true; + kthread_mutex_unlock(&termlock); + + if ( textbufhandle->EmergencyIsImpaired() ) + return true; + + TextBuffer* textbuf = textbufhandle->EmergencyAcquire(); + bool textbuf_was_impaired = textbuf->EmergencyIsImpaired(); + textbufhandle->EmergencyRelease(textbuf); + if ( textbuf_was_impaired ) + return true; + + return false; +} + +bool TextTerminal::EmergencyRecoup() +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. + + if ( !kthread_mutex_trylock(&termlock) ) + return false; + kthread_mutex_unlock(&termlock); + + if ( textbufhandle->EmergencyIsImpaired() && + !textbufhandle->EmergencyRecoup() ) + return false; + + TextBuffer* textbuf = textbufhandle->EmergencyAcquire(); + bool textbuf_failure = textbuf->EmergencyIsImpaired() && + !textbuf->EmergencyRecoup(); + textbufhandle->EmergencyRelease(textbuf); + + if ( !textbuf_failure ) + return false; + + return true; +} + +void TextTerminal::EmergencyReset() +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. + + textbufhandle->EmergencyReset(); + + TextBuffer* textbuf = textbufhandle->EmergencyAcquire(); + textbuf->EmergencyReset(); + textbufhandle->EmergencyRelease(textbuf); + + this->termlock = KTHREAD_MUTEX_INITIALIZER; + Reset(); +} + +size_t TextTerminal::EmergencyPrint(const char* string, size_t stringlen) +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. Another thread may have been interrupted + // while it held the terminal lock. The best case is if the terminal lock is + // currently unused, which would mean everything is safe. + + TextBuffer* textbuf = textbufhandle->EmergencyAcquire(); + for ( size_t i = 0; i < stringlen; i++ ) + PutChar(textbuf, string[i]); + UpdateCursor(textbuf); + textbufhandle->EmergencyRelease(textbuf); + return stringlen; +} + +size_t TextTerminal::EmergencyWidth() const +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. Another thread may have been interrupted + // while it held the terminal lock. The best case is if the terminal lock is + // currently unused, which would mean everything is safe. + + TextBuffer* textbuf = textbufhandle->EmergencyAcquire(); + size_t width = textbuf->Width(); + textbufhandle->EmergencyRelease(textbuf); + return width; +} + +size_t TextTerminal::EmergencyHeight() const +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. Another thread may have been interrupted + // while it held the terminal lock. The best case is if the terminal lock is + // currently unused, which would mean everything is safe. + + TextBuffer* textbuf = textbufhandle->EmergencyAcquire(); + size_t height = textbuf->Height(); + textbufhandle->EmergencyRelease(textbuf); + return height; +} + +bool TextTerminal::EmergencySync() +{ + // This is during a kernel emergency where preemption has been disabled and + // this is the only thread running. There is no need to synchronize the + // text buffer here as there is no background thread rendering the console. + + return true; +} + void TextTerminal::PutChar(TextBuffer* textbuf, char c) { if ( ansimode ) diff --git a/sortix/textterminal.h b/sortix/textterminal.h index 2990dadb..f8eabaa5 100644 --- a/sortix/textterminal.h +++ b/sortix/textterminal.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -41,6 +41,13 @@ public: size_t Width() const; size_t Height() const; bool Sync(); + bool EmergencyIsImpaired(); + bool EmergencyRecoup(); + void EmergencyReset(); + size_t EmergencyPrint(const char* string, size_t stringlen); + size_t EmergencyWidth() const; + size_t EmergencyHeight() const; + bool EmergencySync(); private: void PutChar(TextBuffer* textbuf, char c); diff --git a/sortix/vgatextbuffer.cpp b/sortix/vgatextbuffer.cpp index 7f1e83bd..aec4a5bc 100644 --- a/sortix/vgatextbuffer.cpp +++ b/sortix/vgatextbuffer.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -192,4 +192,21 @@ void VGATextBuffer::UpdateCursor() VGA::SetCursor(width, height-1); } +bool VGATextBuffer::EmergencyIsImpaired() +{ + return false; +} + +bool VGATextBuffer::EmergencyRecoup() +{ + return true; +} + +void VGATextBuffer::EmergencyReset() +{ + return; + Fill(TextPos{0, 0}, TextPos{width-1, height-1}, TextChar{0, 0}, 0); + SetCursorPos(TextPos{0, 0}); +} + } // namespace Sortix diff --git a/sortix/vgatextbuffer.h b/sortix/vgatextbuffer.h index 7c0d4ff8..7410b81b 100644 --- a/sortix/vgatextbuffer.h +++ b/sortix/vgatextbuffer.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -48,6 +48,9 @@ public: virtual void SetCursorEnabled(bool enablecursor); virtual TextPos GetCursorPos() const; virtual void SetCursorPos(TextPos cursorpos); + virtual bool EmergencyIsImpaired(); + virtual bool EmergencyRecoup(); + virtual void EmergencyReset(); private: bool UsablePosition(TextPos pos) const;