mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Recover kernel log during emergencies.
This commit is contained in:
parent
eb831479fb
commit
a0e2934c8c
12 changed files with 503 additions and 111 deletions
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<TextBufferHandle> 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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue