mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 00:48:11 +00:00
Kernel: Set up an initial boot framebuffer console
Instead of seeing a black screen until GraphicsManagement was fully initialized, this allows us to see the console output much earlier. So, if the bootloader provided us with a framebuffer, set up a console as early as possible.
This commit is contained in:
parent
eb446725d5
commit
24f2f3ba4e
5 changed files with 121 additions and 2 deletions
|
@ -73,6 +73,7 @@ set(KERNEL_SOURCES
|
||||||
Devices/HID/VMWareMouseDevice.cpp
|
Devices/HID/VMWareMouseDevice.cpp
|
||||||
GlobalProcessExposed.cpp
|
GlobalProcessExposed.cpp
|
||||||
Graphics/Bochs/GraphicsAdapter.cpp
|
Graphics/Bochs/GraphicsAdapter.cpp
|
||||||
|
Graphics/Console/BootFramebufferConsole.cpp
|
||||||
Graphics/Console/GenericFramebufferConsole.cpp
|
Graphics/Console/GenericFramebufferConsole.cpp
|
||||||
Graphics/Console/ContiguousFramebufferConsole.cpp
|
Graphics/Console/ContiguousFramebufferConsole.cpp
|
||||||
Graphics/Console/TextModeConsole.cpp
|
Graphics/Console/TextModeConsole.cpp
|
||||||
|
|
64
Kernel/Graphics/Console/BootFramebufferConsole.cpp
Normal file
64
Kernel/Graphics/Console/BootFramebufferConsole.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, the SerenityOS developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Kernel/Graphics/Console/BootFramebufferConsole.h>
|
||||||
|
#include <Kernel/Locking/Spinlock.h>
|
||||||
|
#include <Kernel/Memory/MemoryManager.h>
|
||||||
|
|
||||||
|
namespace Kernel::Graphics {
|
||||||
|
|
||||||
|
BootFramebufferConsole::BootFramebufferConsole(PhysicalAddress framebuffer_addr, size_t width, size_t height, size_t pitch)
|
||||||
|
: GenericFramebufferConsoleImpl(width, height, pitch)
|
||||||
|
{
|
||||||
|
// 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();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* BootFramebufferConsole::framebuffer_data()
|
||||||
|
{
|
||||||
|
VERIFY(m_lock.is_locked());
|
||||||
|
VERIFY(m_framebuffer_data);
|
||||||
|
return m_framebuffer_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
38
Kernel/Graphics/Console/BootFramebufferConsole.h
Normal file
38
Kernel/Graphics/Console/BootFramebufferConsole.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, the SerenityOS developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Kernel/Forward.h>
|
||||||
|
#include <Kernel/Graphics/Console/GenericFramebufferConsole.h>
|
||||||
|
|
||||||
|
namespace Kernel::Graphics {
|
||||||
|
|
||||||
|
class BootFramebufferConsole : public GenericFramebufferConsoleImpl {
|
||||||
|
public:
|
||||||
|
virtual void clear(size_t x, size_t y, size_t length) override;
|
||||||
|
virtual void write(size_t x, size_t y, char ch, Color background, Color foreground, bool critical = false) override;
|
||||||
|
using GenericFramebufferConsoleImpl::write;
|
||||||
|
|
||||||
|
virtual void enable() override;
|
||||||
|
virtual void disable() override;
|
||||||
|
|
||||||
|
virtual void flush(size_t, size_t, size_t, size_t) override { }
|
||||||
|
virtual void set_resolution(size_t, size_t, size_t) override { }
|
||||||
|
|
||||||
|
BootFramebufferConsole(PhysicalAddress framebuffer_addr, size_t width, size_t height, size_t pitch);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void clear_glyph(size_t x, size_t y) override;
|
||||||
|
|
||||||
|
virtual u8* framebuffer_data() override;
|
||||||
|
|
||||||
|
OwnPtr<Memory::Region> m_framebuffer;
|
||||||
|
u8* m_framebuffer_data {};
|
||||||
|
mutable Spinlock m_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -33,6 +33,7 @@
|
||||||
#include <Kernel/Firmware/ACPI/Initialize.h>
|
#include <Kernel/Firmware/ACPI/Initialize.h>
|
||||||
#include <Kernel/Firmware/ACPI/Parser.h>
|
#include <Kernel/Firmware/ACPI/Parser.h>
|
||||||
#include <Kernel/Firmware/SysFSFirmware.h>
|
#include <Kernel/Firmware/SysFSFirmware.h>
|
||||||
|
#include <Kernel/Graphics/Console/BootFramebufferConsole.h>
|
||||||
#include <Kernel/Graphics/GraphicsManagement.h>
|
#include <Kernel/Graphics/GraphicsManagement.h>
|
||||||
#include <Kernel/Heap/kmalloc.h>
|
#include <Kernel/Heap/kmalloc.h>
|
||||||
#include <Kernel/Interrupts/APIC.h>
|
#include <Kernel/Interrupts/APIC.h>
|
||||||
|
@ -135,6 +136,8 @@ READONLY_AFTER_INIT u8 multiboot_framebuffer_bpp;
|
||||||
READONLY_AFTER_INIT u8 multiboot_framebuffer_type;
|
READONLY_AFTER_INIT u8 multiboot_framebuffer_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Atomic<Graphics::BootFramebufferConsole*> boot_framebuffer_console;
|
||||||
|
|
||||||
extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info)
|
extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info)
|
||||||
{
|
{
|
||||||
g_in_early_boot = true;
|
g_in_early_boot = true;
|
||||||
|
@ -187,6 +190,12 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info)
|
||||||
CommandLine::initialize();
|
CommandLine::initialize();
|
||||||
Memory::MemoryManager::initialize(0);
|
Memory::MemoryManager::initialize(0);
|
||||||
|
|
||||||
|
if (!multiboot_framebuffer_addr.is_null()) {
|
||||||
|
// NOTE: If the bootloader provided a framebuffer, then set up an initial console so we can see the output on the screen as soon as possible!
|
||||||
|
boot_framebuffer_console = &try_make_ref_counted<Graphics::BootFramebufferConsole>(multiboot_framebuffer_addr, multiboot_framebuffer_width, multiboot_framebuffer_height, multiboot_framebuffer_pitch).value().leak_ref();
|
||||||
|
}
|
||||||
|
dmesgln("Starting SerenityOS...");
|
||||||
|
|
||||||
DeviceManagement::initialize();
|
DeviceManagement::initialize();
|
||||||
SysFSComponentRegistry::initialize();
|
SysFSComponentRegistry::initialize();
|
||||||
DeviceManagement::the().attach_null_device(*NullDevice::must_initialize());
|
DeviceManagement::the().attach_null_device(*NullDevice::must_initialize());
|
||||||
|
@ -224,8 +233,6 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info)
|
||||||
APIC::the().setup_ap_boot_environment();
|
APIC::the().setup_ap_boot_environment();
|
||||||
}
|
}
|
||||||
|
|
||||||
dmesgln("Starting SerenityOS...");
|
|
||||||
|
|
||||||
{
|
{
|
||||||
RefPtr<Thread> init_stage2_thread;
|
RefPtr<Thread> init_stage2_thread;
|
||||||
(void)Process::create_kernel_process(init_stage2_thread, KString::must_create("init_stage2"), init_stage2, nullptr, THREAD_AFFINITY_DEFAULT, Process::RegisterProcess::No);
|
(void)Process::create_kernel_process(init_stage2_thread, KString::must_create("init_stage2"), init_stage2, nullptr, THREAD_AFFINITY_DEFAULT, Process::RegisterProcess::No);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <Kernel/Devices/ConsoleDevice.h>
|
#include <Kernel/Devices/ConsoleDevice.h>
|
||||||
#include <Kernel/Devices/DeviceManagement.h>
|
#include <Kernel/Devices/DeviceManagement.h>
|
||||||
#include <Kernel/Devices/PCISerialDevice.h>
|
#include <Kernel/Devices/PCISerialDevice.h>
|
||||||
|
#include <Kernel/Graphics/Console/BootFramebufferConsole.h>
|
||||||
#include <Kernel/Graphics/GraphicsManagement.h>
|
#include <Kernel/Graphics/GraphicsManagement.h>
|
||||||
#include <Kernel/Locking/Spinlock.h>
|
#include <Kernel/Locking/Spinlock.h>
|
||||||
#include <Kernel/TTY/ConsoleManagement.h>
|
#include <Kernel/TTY/ConsoleManagement.h>
|
||||||
|
@ -18,6 +19,10 @@
|
||||||
|
|
||||||
#include <LibC/stdarg.h>
|
#include <LibC/stdarg.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
extern Atomic<Graphics::BootFramebufferConsole*> boot_framebuffer_console;
|
||||||
|
}
|
||||||
|
|
||||||
static bool serial_debug;
|
static bool serial_debug;
|
||||||
// A recursive spinlock allows us to keep writing in the case where a
|
// A recursive spinlock allows us to keep writing in the case where a
|
||||||
// page fault happens in the middle of a dbgln(), etc
|
// page fault happens in the middle of a dbgln(), etc
|
||||||
|
@ -75,6 +80,8 @@ static void critical_console_out(char ch)
|
||||||
// especially when we want to avoid any memory allocations...
|
// especially when we want to avoid any memory allocations...
|
||||||
if (GraphicsManagement::is_initialized() && GraphicsManagement::the().console()) {
|
if (GraphicsManagement::is_initialized() && GraphicsManagement::the().console()) {
|
||||||
GraphicsManagement::the().console()->write(ch, true);
|
GraphicsManagement::the().console()->write(ch, true);
|
||||||
|
} else if (auto* boot_console = boot_framebuffer_console.load()) {
|
||||||
|
boot_console->write(ch, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +99,8 @@ static void console_out(char ch)
|
||||||
}
|
}
|
||||||
if (ConsoleManagement::is_initialized()) {
|
if (ConsoleManagement::is_initialized()) {
|
||||||
ConsoleManagement::the().debug_tty()->emit_char(ch);
|
ConsoleManagement::the().debug_tty()->emit_char(ch);
|
||||||
|
} else if (auto* boot_console = boot_framebuffer_console.load()) {
|
||||||
|
boot_console->write(ch, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue