1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 18:34:58 +00:00
serenity/Kernel/Graphics/Console/BootFramebufferConsole.cpp
Liav A 37ed1b28fa Kernel: Ensure proper locking when mutating boot console cursor
The BootFramebufferConsole highly depends on using the m_lock spinlock,
therefore setting and changing the cursor state should be done under
that spinlock too to avoid crashing.
2022-09-20 20:51:03 +01:00

106 lines
3.2 KiB
C++

/*
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Graphics/Console/BootFramebufferConsole.h>
#include <Kernel/Locking/Spinlock.h>
// FIXME: Port MemoryManager to aarch64
#if !ARCH(AARCH64)
# include <Kernel/Memory/MemoryManager.h>
#endif
namespace Kernel::Graphics {
// FIXME: Port MemoryManager to aarch64
#if ARCH(AARCH64)
BootFramebufferConsole::BootFramebufferConsole(u8* framebuffer_addr, size_t width, size_t height, size_t pitch)
: GenericFramebufferConsoleImpl(width, height, pitch)
, m_framebuffer(framebuffer_addr)
#else
BootFramebufferConsole::BootFramebufferConsole(PhysicalAddress framebuffer_addr, size_t width, size_t height, size_t pitch)
: GenericFramebufferConsoleImpl(width, height, pitch)
#endif
{
// FIXME: Port MemoryManager to aarch64
#if ARCH(AARCH64)
m_framebuffer_data = framebuffer_addr;
#else
// NOTE: We're very early in the boot process, memory allocations shouldn't really fail
auto framebuffer_end = Memory::page_round_up(framebuffer_addr.offset(height * pitch * sizeof(u32)).get()).release_value();
m_framebuffer = MM.allocate_kernel_region(framebuffer_addr.page_base(), framebuffer_end - framebuffer_addr.page_base().get(), "Boot Framebuffer"sv, Memory::Region::Access::ReadWrite).release_value();
[[maybe_unused]] auto result = m_framebuffer->set_write_combine(true);
m_framebuffer_data = m_framebuffer->vaddr().offset(framebuffer_addr.offset_in_page()).as_ptr();
#endif
memset(m_framebuffer_data, 0, height * pitch * sizeof(u32));
}
void BootFramebufferConsole::clear(size_t x, size_t y, size_t length)
{
SpinlockLocker lock(m_lock);
if (m_framebuffer_data)
GenericFramebufferConsoleImpl::clear(x, y, length);
}
void BootFramebufferConsole::clear_glyph(size_t x, size_t y)
{
VERIFY(m_lock.is_locked());
GenericFramebufferConsoleImpl::clear_glyph(x, y);
}
void BootFramebufferConsole::enable()
{
// Once disabled, ignore requests to re-enable
}
void BootFramebufferConsole::disable()
{
SpinlockLocker lock(m_lock);
GenericFramebufferConsoleImpl::disable();
m_framebuffer = nullptr;
m_framebuffer_data = nullptr;
}
void BootFramebufferConsole::write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical)
{
SpinlockLocker lock(m_lock);
if (m_framebuffer_data)
GenericFramebufferConsoleImpl::write(x, y, ch, background, foreground, critical);
}
void BootFramebufferConsole::set_cursor(size_t x, size_t y)
{
// Note: To ensure we don't trigger a deadlock, let's assert in
// case we already locked the spinlock, so we know there's a bug
// in the call path.
VERIFY(!m_lock.is_locked());
SpinlockLocker lock(m_lock);
hide_cursor();
m_x = x;
m_y = y;
show_cursor();
}
void BootFramebufferConsole::hide_cursor()
{
VERIFY(m_lock.is_locked());
GenericFramebufferConsoleImpl::hide_cursor();
}
void BootFramebufferConsole::show_cursor()
{
VERIFY(m_lock.is_locked());
GenericFramebufferConsoleImpl::show_cursor();
}
u8* BootFramebufferConsole::framebuffer_data()
{
VERIFY(m_lock.is_locked());
VERIFY(m_framebuffer_data);
return m_framebuffer_data;
}
}