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 size_t (*device_height)(void*);
|
||||||
extern bool (*device_sync)(void*);
|
extern bool (*device_sync)(void*);
|
||||||
extern void* device_pointer;
|
extern void* device_pointer;
|
||||||
|
extern bool (*emergency_device_is_impaired)(void*);
|
||||||
void Init(size_t (*callback)(void*, const char*, size_t),
|
extern bool (*emergency_device_recoup)(void*);
|
||||||
size_t (*widthfunc)(void*),
|
extern void (*emergency_device_reset)(void*);
|
||||||
size_t (*heightfunc)(void*),
|
extern size_t (*emergency_device_callback)(void*, const char*, size_t);
|
||||||
bool (*syncfunc)(void*),
|
extern size_t (*emergency_device_width)(void*);
|
||||||
void* user);
|
extern size_t (*emergency_device_height)(void*);
|
||||||
|
extern bool (*emergency_device_sync)(void*);
|
||||||
|
extern void* emergency_device_pointer;
|
||||||
|
|
||||||
inline void Flush()
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -74,6 +74,9 @@ public:
|
||||||
virtual void SetCursorEnabled(bool enablecursor) = 0;
|
virtual void SetCursorEnabled(bool enablecursor) = 0;
|
||||||
virtual TextPos GetCursorPos() const = 0;
|
virtual TextPos GetCursorPos() const = 0;
|
||||||
virtual void SetCursorPos(TextPos cursorpos) = 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();
|
TextBuffer* Acquire();
|
||||||
void Release(TextBuffer* textbuf);
|
void Release(TextBuffer* textbuf);
|
||||||
void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
|
void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
|
||||||
|
bool EmergencyIsImpaired();
|
||||||
|
bool EmergencyRecoup();
|
||||||
|
void EmergencyReset();
|
||||||
|
TextBuffer* EmergencyAcquire();
|
||||||
|
void EmergencyRelease(TextBuffer* textbuf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
kthread_mutex_t mutex;
|
kthread_mutex_t mutex;
|
||||||
|
|
|
@ -135,6 +135,42 @@ static bool TextTermSync(void* user)
|
||||||
return ((TextTerminal*) user)->Sync();
|
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;
|
addr_t initrd;
|
||||||
size_t initrdsize;
|
size_t initrdsize;
|
||||||
Ref<TextBufferHandle> textbufhandle;
|
Ref<TextBufferHandle> textbufhandle;
|
||||||
|
@ -167,9 +203,22 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
// Setup a text terminal instance.
|
// Setup a text terminal instance.
|
||||||
TextTerminal textterm(textbufhandle);
|
TextTerminal textterm(textbufhandle);
|
||||||
|
|
||||||
// Register the text terminal as the kernel log and initialize it.
|
// Register the text terminal as the kernel log.
|
||||||
Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, TextTermSync,
|
Log::device_callback = PrintToTextTerminal;
|
||||||
&textterm);
|
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.
|
// Display the boot welcome screen.
|
||||||
DoWelcome();
|
DoWelcome();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -83,6 +83,7 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
||||||
goto cleanup_queue;
|
goto cleanup_queue;
|
||||||
|
|
||||||
memcpy(font, VGA::GetFont(), fontsize);
|
memcpy(font, VGA::GetFont(), fontsize);
|
||||||
|
ret->execute_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
ret->queue_lock = KTHREAD_MUTEX_INITIALIZER;
|
ret->queue_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
ret->queue_not_full = KTHREAD_COND_INITIALIZER;
|
ret->queue_not_full = KTHREAD_COND_INITIALIZER;
|
||||||
ret->queue_not_empty = 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);
|
ret->cursorpos = TextPos(0, 0);
|
||||||
for ( size_t y = 0; y < yres; y++ )
|
for ( size_t y = 0; y < yres; y++ )
|
||||||
memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
|
memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
|
||||||
|
ret->emergency_state = false;
|
||||||
|
|
||||||
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) )
|
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) )
|
||||||
{
|
{
|
||||||
|
@ -304,6 +306,18 @@ void LFBTextBuffer::RenderRange(TextPos from, TextPos to)
|
||||||
|
|
||||||
void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
|
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);
|
ScopedLock lock(&queue_lock);
|
||||||
while ( queue_used == queue_length )
|
while ( queue_used == queue_length )
|
||||||
kthread_cond_wait(&queue_not_full, &queue_lock);
|
kthread_cond_wait(&queue_not_full, &queue_lock);
|
||||||
|
@ -314,6 +328,8 @@ void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
|
||||||
|
|
||||||
void LFBTextBuffer::StopRendering()
|
void LFBTextBuffer::StopRendering()
|
||||||
{
|
{
|
||||||
|
if ( emergency_state )
|
||||||
|
return;
|
||||||
TextBufferCmd cmd;
|
TextBufferCmd cmd;
|
||||||
cmd.type = TEXTBUFCMD_PAUSE;
|
cmd.type = TEXTBUFCMD_PAUSE;
|
||||||
IssueCommand(&cmd);
|
IssueCommand(&cmd);
|
||||||
|
@ -324,6 +340,8 @@ void LFBTextBuffer::StopRendering()
|
||||||
|
|
||||||
void LFBTextBuffer::ResumeRendering()
|
void LFBTextBuffer::ResumeRendering()
|
||||||
{
|
{
|
||||||
|
if ( emergency_state )
|
||||||
|
return;
|
||||||
ScopedLock lock(&queue_lock);
|
ScopedLock lock(&queue_lock);
|
||||||
queue_is_paused = false;
|
queue_is_paused = false;
|
||||||
kthread_cond_signal(&queue_resume);
|
kthread_cond_signal(&queue_resume);
|
||||||
|
@ -496,65 +514,31 @@ void LFBTextBuffer::DoFill(TextPos from, TextPos to, uint16_t fillwith,
|
||||||
attrs[i] = fillattr;
|
attrs[i] = fillattr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFBTextBuffer::RenderThread()
|
bool LFBTextBuffer::IsCommandIdempotent(const TextBufferCmd* cmd) const
|
||||||
{
|
{
|
||||||
queue_is_paused = false;
|
switch ( cmd->type )
|
||||||
size_t offset = 0;
|
|
||||||
size_t amount = 0;
|
|
||||||
bool exit_requested = false;
|
|
||||||
bool sync_requested = false;
|
|
||||||
bool pause_requested = false;
|
|
||||||
|
|
||||||
while ( true )
|
|
||||||
{
|
{
|
||||||
kthread_mutex_lock(&queue_lock);
|
case TEXTBUFCMD_EXIT: return true;
|
||||||
|
case TEXTBUFCMD_SYNC: return true;
|
||||||
if ( queue_used == queue_length && amount )
|
case TEXTBUFCMD_PAUSE: return true;
|
||||||
kthread_cond_signal(&queue_not_full);
|
case TEXTBUFCMD_CHAR: return true;
|
||||||
|
case TEXTBUFCMD_ATTR: return true;
|
||||||
queue_used -= amount;
|
case TEXTBUFCMD_CURSOR_SET_ENABLED: return true;
|
||||||
queue_offset = (queue_offset + amount) % queue_length;
|
case TEXTBUFCMD_CURSOR_MOVE: return true;
|
||||||
|
case TEXTBUFCMD_MOVE: return false;
|
||||||
if ( !queue_used )
|
case TEXTBUFCMD_FILL: return true;
|
||||||
{
|
case TEXTBUFCMD_SCROLL: return false;
|
||||||
if ( exit_requested )
|
default: return false;
|
||||||
{
|
|
||||||
queue_thread = false;
|
|
||||||
kthread_cond_signal(&queue_exit);
|
|
||||||
kthread_mutex_unlock(&queue_lock);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( sync_requested )
|
void LFBTextBuffer::ExecuteCommand(TextBufferCmd* cmd,
|
||||||
{
|
bool& exit_requested,
|
||||||
kthread_cond_signal(&queue_sync);
|
bool& sync_requested,
|
||||||
sync_requested = false;
|
bool& pause_requested,
|
||||||
}
|
TextPos& render_from,
|
||||||
|
TextPos& render_to)
|
||||||
if ( pause_requested )
|
{
|
||||||
{
|
|
||||||
queue_is_paused = true;
|
|
||||||
kthread_cond_signal(&queue_paused);
|
|
||||||
while ( queue_is_paused )
|
|
||||||
kthread_cond_wait(&queue_resume, &queue_lock);
|
|
||||||
pause_requested = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( !queue_used )
|
|
||||||
kthread_cond_wait(&queue_not_empty, &queue_lock);
|
|
||||||
|
|
||||||
amount = queue_used;
|
|
||||||
offset = queue_offset;
|
|
||||||
|
|
||||||
kthread_mutex_unlock(&queue_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 )
|
switch ( cmd->type )
|
||||||
{
|
{
|
||||||
case TEXTBUFCMD_EXIT:
|
case TEXTBUFCMD_EXIT:
|
||||||
|
@ -636,11 +620,134 @@ void LFBTextBuffer::RenderThread()
|
||||||
render_to = {columns-1, rows-1};
|
render_to = {columns-1, rows-1};
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::RenderThread()
|
||||||
|
{
|
||||||
|
queue_is_paused = false;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t amount = 0;
|
||||||
|
bool exit_requested = false;
|
||||||
|
bool sync_requested = false;
|
||||||
|
bool pause_requested = false;
|
||||||
|
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
kthread_mutex_lock(&queue_lock);
|
||||||
|
|
||||||
|
if ( queue_used == queue_length && amount )
|
||||||
|
kthread_cond_signal(&queue_not_full);
|
||||||
|
|
||||||
|
queue_used -= amount;
|
||||||
|
queue_offset = (queue_offset + amount) % queue_length;
|
||||||
|
|
||||||
|
if ( !queue_used )
|
||||||
|
{
|
||||||
|
if ( exit_requested )
|
||||||
|
{
|
||||||
|
queue_thread = false;
|
||||||
|
kthread_cond_signal(&queue_exit);
|
||||||
|
kthread_mutex_unlock(&queue_lock);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( sync_requested )
|
||||||
|
{
|
||||||
|
kthread_cond_signal(&queue_sync);
|
||||||
|
sync_requested = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pause_requested )
|
||||||
|
{
|
||||||
|
queue_is_paused = true;
|
||||||
|
kthread_cond_signal(&queue_paused);
|
||||||
|
while ( queue_is_paused )
|
||||||
|
kthread_cond_wait(&queue_resume, &queue_lock);
|
||||||
|
pause_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( !queue_used )
|
||||||
|
kthread_cond_wait(&queue_not_empty, &queue_lock);
|
||||||
|
|
||||||
|
amount = queue_used;
|
||||||
|
offset = queue_offset;
|
||||||
|
|
||||||
|
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];
|
||||||
|
ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested, render_from, render_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
kthread_mutex_unlock(&execute_lock);
|
||||||
|
|
||||||
if ( !IsTextPosBeforeTextPos(render_to, render_from) )
|
if ( !IsTextPosBeforeTextPos(render_to, render_from) )
|
||||||
RenderRange(render_from, render_to);
|
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
|
} // 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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -83,6 +83,9 @@ public:
|
||||||
virtual void SetCursorEnabled(bool enablecursor);
|
virtual void SetCursorEnabled(bool enablecursor);
|
||||||
virtual TextPos GetCursorPos() const;
|
virtual TextPos GetCursorPos() const;
|
||||||
virtual void SetCursorPos(TextPos newcursorpos);
|
virtual void SetCursorPos(TextPos newcursorpos);
|
||||||
|
virtual bool EmergencyIsImpaired();
|
||||||
|
virtual bool EmergencyRecoup();
|
||||||
|
virtual void EmergencyReset();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void RenderThread();
|
virtual void RenderThread();
|
||||||
|
@ -102,8 +105,16 @@ private:
|
||||||
void IssueCommand(TextBufferCmd* cmd);
|
void IssueCommand(TextBufferCmd* cmd);
|
||||||
void StopRendering();
|
void StopRendering();
|
||||||
void ResumeRendering();
|
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:
|
private:
|
||||||
|
kthread_mutex_t execute_lock;
|
||||||
kthread_mutex_t queue_lock;
|
kthread_mutex_t queue_lock;
|
||||||
kthread_cond_t queue_not_full;
|
kthread_cond_t queue_not_full;
|
||||||
kthread_cond_t queue_not_empty;
|
kthread_cond_t queue_not_empty;
|
||||||
|
@ -131,6 +142,8 @@ private:
|
||||||
uint32_t lfbformat;
|
uint32_t lfbformat;
|
||||||
bool cursorenabled;
|
bool cursorenabled;
|
||||||
TextPos cursorpos;
|
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;
|
size_t (*device_height)(void*) = NULL;
|
||||||
bool (*device_sync)(void*) = NULL;
|
bool (*device_sync)(void*) = NULL;
|
||||||
void* device_pointer = NULL;
|
void* device_pointer = NULL;
|
||||||
|
bool (*emergency_device_is_impaired)(void*) = NULL;
|
||||||
void Init(size_t (*callback)(void*, const char*, size_t),
|
bool (*emergency_device_recoup)(void*) = NULL;
|
||||||
size_t (*widthfunc)(void*),
|
void (*emergency_device_reset)(void*) = NULL;
|
||||||
size_t (*heightfunc)(void*),
|
size_t (*emergency_device_callback)(void*, const char*, size_t) = NULL;
|
||||||
bool (*syncfunc)(void*),
|
size_t (*emergency_device_width)(void*) = NULL;
|
||||||
void* user)
|
size_t (*emergency_device_height)(void*) = NULL;
|
||||||
{
|
bool (*emergency_device_sync)(void*) = NULL;
|
||||||
device_callback = callback;
|
void* emergency_device_pointer = NULL;
|
||||||
device_width = widthfunc;
|
|
||||||
device_height = heightfunc;
|
|
||||||
device_sync = syncfunc;
|
|
||||||
device_pointer = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Log
|
} // namespace Log
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -41,6 +41,7 @@ const bool longpanic = true;
|
||||||
|
|
||||||
static bool panicing = false;
|
static bool panicing = false;
|
||||||
static bool doublepanic = false;
|
static bool doublepanic = false;
|
||||||
|
static bool logrecovering = false;
|
||||||
|
|
||||||
static void PanicLogoLong()
|
static void PanicLogoLong()
|
||||||
{
|
{
|
||||||
|
@ -54,8 +55,53 @@ static void PanicLogoShort()
|
||||||
|
|
||||||
void PanicInit()
|
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();
|
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.
|
// Handle the case where the panic code caused another system crash.
|
||||||
if ( panicing )
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -71,6 +71,41 @@ void TextBufferHandle::Release(TextBuffer* textbuf)
|
||||||
kthread_cond_signal(&unusedcond);
|
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)
|
void TextBufferHandle::Replace(TextBuffer* newtextbuf, bool deletebuf)
|
||||||
{
|
{
|
||||||
ScopedLock lock(&mutex);
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -102,6 +102,116 @@ bool TextTerminal::Sync()
|
||||||
return true;
|
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)
|
void TextTerminal::PutChar(TextBuffer* textbuf, char c)
|
||||||
{
|
{
|
||||||
if ( ansimode )
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -41,6 +41,13 @@ public:
|
||||||
size_t Width() const;
|
size_t Width() const;
|
||||||
size_t Height() const;
|
size_t Height() const;
|
||||||
bool Sync();
|
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:
|
private:
|
||||||
void PutChar(TextBuffer* textbuf, char c);
|
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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -192,4 +192,21 @@ void VGATextBuffer::UpdateCursor()
|
||||||
VGA::SetCursor(width, height-1);
|
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
|
} // 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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -48,6 +48,9 @@ public:
|
||||||
virtual void SetCursorEnabled(bool enablecursor);
|
virtual void SetCursorEnabled(bool enablecursor);
|
||||||
virtual TextPos GetCursorPos() const;
|
virtual TextPos GetCursorPos() const;
|
||||||
virtual void SetCursorPos(TextPos cursorpos);
|
virtual void SetCursorPos(TextPos cursorpos);
|
||||||
|
virtual bool EmergencyIsImpaired();
|
||||||
|
virtual bool EmergencyRecoup();
|
||||||
|
virtual void EmergencyReset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool UsablePosition(TextPos pos) const;
|
bool UsablePosition(TextPos pos) const;
|
||||||
|
|
Loading…
Reference in a new issue