summaryrefslogtreecommitdiff
path: root/Kernel/Graphics/Console
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-04-16 22:58:51 +0300
committerAndreas Kling <kling@serenityos.org>2021-05-16 19:58:33 +0200
commit20743e8aede1de46195dd61ad18002cd52db7d3a (patch)
tree49ea710e88949b49c136b0b3b793059c24f6daa1 /Kernel/Graphics/Console
parentdac129e10bdef313dff65b34f1fa17608d3608c2 (diff)
downloadserenity-20743e8aede1de46195dd61ad18002cd52db7d3a.zip
Kernel/Graphics + SystemServer: Support text mode properly
As we removed the support of VBE modesetting that was done by GRUB early on boot, we need to determine if we can modeset the resolution with our drivers, and if not, we should enable text mode and ensure that SystemServer knows about it too. Also, SystemServer should first check if there's a framebuffer device node, which is an indication that text mode was not even if it was requested. Then, if it doesn't find it, it should check what boot_mode argument the user specified (in case it's self-test). This way if we try to use bochs-display device (which is not VGA compatible) and request a text mode, it will not honor the request and will continue with graphical mode. Also try to print critical messages with mininum memory allocations possible. In LibVT, We make the implementation flexible for kernel-specific methods that are implemented in ConsoleImpl class.
Diffstat (limited to 'Kernel/Graphics/Console')
-rw-r--r--Kernel/Graphics/Console/Console.h82
-rw-r--r--Kernel/Graphics/Console/FramebufferConsole.cpp348
-rw-r--r--Kernel/Graphics/Console/FramebufferConsole.h50
-rw-r--r--Kernel/Graphics/Console/TextModeConsole.cpp203
-rw-r--r--Kernel/Graphics/Console/TextModeConsole.h50
-rw-r--r--Kernel/Graphics/Console/VGAConsole.cpp19
-rw-r--r--Kernel/Graphics/Console/VGAConsole.h39
7 files changed, 791 insertions, 0 deletions
diff --git a/Kernel/Graphics/Console/Console.h b/Kernel/Graphics/Console/Console.h
new file mode 100644
index 0000000000..c391dc32fb
--- /dev/null
+++ b/Kernel/Graphics/Console/Console.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RefCounted.h>
+#include <AK/String.h>
+#include <AK/Types.h>
+#include <Kernel/Graphics/GraphicsDevice.h>
+
+namespace Kernel::Graphics {
+
+class Console : public RefCounted<Console> {
+public:
+ // Stanadard VGA text mode colors
+ enum Color : u8 {
+ Black = 0,
+ Blue,
+ Green,
+ Cyan,
+ Red,
+ Magenta,
+ Brown,
+ LightGray,
+ DarkGray,
+ BrightBlue,
+ BrightGreen,
+ BrightCyan,
+ BrightRed,
+ BrightMagenta,
+ Yellow,
+ White,
+ };
+
+public:
+ size_t width() const { return m_width; }
+ size_t height() const { return m_height; }
+ size_t pitch() const { return bytes_per_base_glyph() * width(); }
+ virtual size_t max_column() const { return m_width; }
+ virtual size_t max_row() const { return m_height; }
+ virtual size_t bytes_per_base_glyph() const = 0;
+ virtual size_t chars_per_line() const = 0;
+
+ virtual void enable() = 0;
+ virtual void disable() = 0;
+
+ virtual bool is_hardware_paged_capable() const = 0;
+ virtual bool has_hardware_cursor() const = 0;
+
+ virtual void set_cursor(size_t x, size_t y) = 0;
+ virtual void hide_cursor() = 0;
+ virtual void show_cursor() = 0;
+
+ virtual void clear(size_t x, size_t y, size_t length) const = 0;
+ virtual void write(size_t x, size_t y, char ch, Color background, Color foreground) const = 0;
+ virtual void write(size_t x, size_t y, String, Color background, Color foreground) const = 0;
+ virtual void write(size_t x, size_t y, char ch) const = 0;
+ virtual void write(size_t x, size_t y, String) const = 0;
+ virtual void write(char ch) const = 0;
+
+ virtual ~Console() { }
+
+protected:
+ Console(size_t width, size_t height)
+ : m_width(width)
+ , m_height(height)
+ {
+ m_enabled.store(true);
+ }
+
+ Atomic<bool> m_enabled;
+ Color m_default_foreground_color { Color::White };
+ Color m_default_background_color { Color::Black };
+ const size_t m_width;
+ const size_t m_height;
+ mutable size_t m_x { 0 };
+ mutable size_t m_y { 0 };
+};
+}
diff --git a/Kernel/Graphics/Console/FramebufferConsole.cpp b/Kernel/Graphics/Console/FramebufferConsole.cpp
new file mode 100644
index 0000000000..8ae2e3122e
--- /dev/null
+++ b/Kernel/Graphics/Console/FramebufferConsole.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/Graphics/Console/FramebufferConsole.h>
+
+namespace Kernel::Graphics {
+
+constexpr unsigned char const font8x8_basic[128][8] = {
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0001
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0002
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0003
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0004
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0005
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0006
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0007
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0008
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0009
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000A
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000B
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000C
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000D
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000E
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000F
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0010
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0011
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0012
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0013
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0014
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0015
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0016
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0017
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0018
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0019
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001A
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001B
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001C
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001D
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001E
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001F
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 (space)
+ { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00 }, // U+0021 (!)
+ { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0022 (")
+ { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00 }, // U+0023 (#)
+ { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00 }, // U+0024 ($)
+ { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00 }, // U+0025 (%)
+ { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00 }, // U+0026 (&)
+ { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 (')
+ { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00 }, // U+0028 (()
+ { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00 }, // U+0029 ())
+ { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00 }, // U+002A (*)
+ { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00 }, // U+002B (+)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06 }, // U+002C (,)
+ { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00 }, // U+002D (-)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00 }, // U+002E (.)
+ { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 }, // U+002F (/)
+ { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00 }, // U+0030 (0)
+ { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00 }, // U+0031 (1)
+ { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00 }, // U+0032 (2)
+ { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00 }, // U+0033 (3)
+ { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00 }, // U+0034 (4)
+ { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00 }, // U+0035 (5)
+ { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00 }, // U+0036 (6)
+ { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00 }, // U+0037 (7)
+ { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00 }, // U+0038 (8)
+ { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00 }, // U+0039 (9)
+ { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00 }, // U+003A (:)
+ { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06 }, // U+003B (;)
+ { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00 }, // U+003C (<)
+ { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00 }, // U+003D (=)
+ { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00 }, // U+003E (>)
+ { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00 }, // U+003F (?)
+ { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00 }, // U+0040 (@)
+ { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00 }, // U+0041 (A)
+ { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00 }, // U+0042 (B)
+ { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00 }, // U+0043 (C)
+ { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00 }, // U+0044 (D)
+ { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00 }, // U+0045 (E)
+ { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00 }, // U+0046 (F)
+ { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00 }, // U+0047 (G)
+ { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00 }, // U+0048 (H)
+ { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0049 (I)
+ { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00 }, // U+004A (J)
+ { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00 }, // U+004B (K)
+ { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00 }, // U+004C (L)
+ { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00 }, // U+004D (M)
+ { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00 }, // U+004E (N)
+ { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00 }, // U+004F (O)
+ { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00 }, // U+0050 (P)
+ { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00 }, // U+0051 (Q)
+ { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00 }, // U+0052 (R)
+ { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00 }, // U+0053 (S)
+ { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0054 (T)
+ { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00 }, // U+0055 (U)
+ { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00 }, // U+0056 (V)
+ { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00 }, // U+0057 (W)
+ { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00 }, // U+0058 (X)
+ { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0059 (Y)
+ { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00 }, // U+005A (Z)
+ { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00 }, // U+005B ([)
+ { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00 }, // U+005C (\)
+ { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00 }, // U+005D (])
+ { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00 }, // U+005E (^)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, // U+005F (_)
+ { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0060 (`)
+ { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00 }, // U+0061 (a)
+ { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00 }, // U+0062 (b)
+ { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00 }, // U+0063 (c)
+ { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00 }, // U+0064 (d)
+ { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00 }, // U+0065 (e)
+ { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00 }, // U+0066 (f)
+ { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F }, // U+0067 (g)
+ { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00 }, // U+0068 (h)
+ { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+0069 (i)
+ { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E }, // U+006A (j)
+ { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00 }, // U+006B (k)
+ { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00 }, // U+006C (l)
+ { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00 }, // U+006D (m)
+ { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00 }, // U+006E (n)
+ { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00 }, // U+006F (o)
+ { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F }, // U+0070 (p)
+ { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78 }, // U+0071 (q)
+ { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00 }, // U+0072 (r)
+ { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00 }, // U+0073 (s)
+ { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00 }, // U+0074 (t)
+ { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00 }, // U+0075 (u)
+ { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00 }, // U+0076 (v)
+ { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00 }, // U+0077 (w)
+ { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00 }, // U+0078 (x)
+ { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F }, // U+0079 (y)
+ { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00 }, // U+007A (z)
+ { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00 }, // U+007B ({)
+ { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00 }, // U+007C (|)
+ { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00 }, // U+007D (})
+ { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+007E (~)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // U+007F
+};
+
+// FIXME: This assumes 32 bit BGR (Blue-Green-Red) palette
+enum BGRColor : u32 {
+ Black = 0,
+ Blue = 0x0000FF,
+ Green = 0x00FF00,
+ Cyan = 0x0000FFFF,
+ Red = 0xFF0000,
+ Magenta = 0x00FF00FF,
+ Brown = 0x00964B00,
+ LightGray = 0x00D3D3D3,
+ DarkGray = 0x00A9A9A9,
+ BrightBlue = 0x0ADD8E6,
+ BrightGreen = 0x0090EE90,
+ BrightCyan = 0x00E0FFFF,
+ BrightRed = 0x00D70A53,
+ BrightMagenta = 0x00F984E5,
+ Yellow = 0x00FFE135,
+ White = 0x00FFFFFF,
+};
+
+static inline BGRColor convert_standard_color_to_bgr_color(Console::Color color)
+{
+ switch (color) {
+ case Console::Color::Black:
+ return BGRColor::Black;
+ case Console::Color::Red:
+ return BGRColor::Red;
+ case Console::Color::Brown:
+ return BGRColor::Brown;
+ case Console::Color::Blue:
+ return BGRColor::Blue;
+ case Console::Color::Magenta:
+ return BGRColor::Magenta;
+ case Console::Color::Green:
+ return BGRColor::Green;
+ case Console::Color::Cyan:
+ return BGRColor::Cyan;
+ case Console::Color::LightGray:
+ return BGRColor::LightGray;
+ case Console::Color::DarkGray:
+ return BGRColor::DarkGray;
+ case Console::Color::BrightRed:
+ return BGRColor::BrightRed;
+ case Console::Color::BrightGreen:
+ return BGRColor::BrightGreen;
+ case Console::Color::Yellow:
+ return BGRColor::Yellow;
+ case Console::Color::BrightBlue:
+ return BGRColor::BrightBlue;
+ case Console::Color::BrightMagenta:
+ return BGRColor::BrightMagenta;
+ case Console::Color::BrightCyan:
+ return BGRColor::BrightCyan;
+ case Console::Color::White:
+ return BGRColor::White;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+NonnullRefPtr<FramebufferConsole> FramebufferConsole::initialize(PhysicalAddress framebuffer_address, size_t width, size_t height, size_t pitch)
+{
+ return adopt_ref(*new FramebufferConsole(framebuffer_address, width, height, pitch));
+}
+
+FramebufferConsole::FramebufferConsole(PhysicalAddress framebuffer_address, size_t width, size_t height, size_t pitch)
+ : Console(width, height)
+ , m_framebuffer_address(framebuffer_address)
+ , m_pitch(pitch)
+{
+ dbgln("Framebuffer Console: taking {} bytes", page_round_up(pitch * height));
+ m_framebuffer_region = MM.allocate_kernel_region(m_framebuffer_address, page_round_up(pitch * height), "Framebuffer Console", Region::Access::Read | Region::Access::Write, Region::Cacheable::Yes);
+ VERIFY(m_framebuffer_region);
+
+ // Just to start cleanly, we clean the entire framebuffer
+ memset(m_framebuffer_region->vaddr().as_ptr(), 0, pitch * height);
+}
+
+size_t FramebufferConsole::bytes_per_base_glyph() const
+{
+ // FIXME: We assume we have 32 bit bpp framebuffer.
+ return 8 * 32;
+}
+size_t FramebufferConsole::chars_per_line() const
+{
+ return width() / bytes_per_base_glyph();
+}
+
+void FramebufferConsole::set_cursor(size_t, size_t)
+{
+}
+void FramebufferConsole::hide_cursor()
+{
+}
+void FramebufferConsole::show_cursor()
+{
+}
+
+void FramebufferConsole::clear(size_t x, size_t y, size_t length) const
+{
+ ScopedSpinLock lock(m_lock);
+ if (x == 0 && length == max_column()) {
+ // if we need to clear the entire row, just clean it with quick memset :)
+ auto* offset_in_framebuffer = (u32*)m_framebuffer_region->vaddr().offset(x * sizeof(u32) * 8).offset(y * 8 * sizeof(u32) * width()).as_ptr();
+ for (size_t current_x = 0; current_x < 8; current_x++) {
+ memset(offset_in_framebuffer, 0, width() * sizeof(u32));
+ offset_in_framebuffer = (u32*)((u8*)offset_in_framebuffer + width() * 4);
+ }
+ return;
+ }
+ for (size_t index = 0; index < length; index++) {
+ if (x >= max_column()) {
+ x = 0;
+ y++;
+ if (y >= max_row())
+ y = 0;
+ }
+ clear_glyph(x, y);
+ }
+}
+
+void FramebufferConsole::clear_glyph(size_t x, size_t y) const
+{
+ VERIFY(m_lock.is_locked());
+ auto* offset_in_framebuffer = (u32*)m_framebuffer_region->vaddr().offset(x * sizeof(u32) * 8).offset(y * 8 * sizeof(u32) * width()).as_ptr();
+ for (size_t current_x = 0; current_x < 8; current_x++) {
+ memset(offset_in_framebuffer, 0, 8 * sizeof(u32));
+ offset_in_framebuffer = (u32*)((u8*)offset_in_framebuffer + width() * sizeof(u32));
+ }
+}
+
+void FramebufferConsole::enable()
+{
+ ScopedSpinLock lock(m_lock);
+ memset(m_framebuffer_region->vaddr().as_ptr(), 0, height() * width() * sizeof(u32));
+ m_enabled.store(true);
+}
+void FramebufferConsole::disable()
+{
+ ScopedSpinLock lock(m_lock);
+ m_enabled.store(false);
+}
+
+void FramebufferConsole::write(size_t x, size_t y, char ch, Color background, Color foreground) const
+{
+ ScopedSpinLock lock(m_lock);
+ if (!m_enabled.load())
+ return;
+ if (ch == '\r' || ch == '\n') {
+ m_x = 0;
+ m_y += 1;
+ if (m_y >= max_row())
+ m_y = 0;
+ return;
+ }
+ if ((int)ch < 0x20 || (int)ch == 0x7f) {
+ // FIXME: There's no point in printing empty glyphs...
+ // Maybe try to add these special glyphs and print them.
+ return;
+ }
+ clear_glyph(x, y);
+ auto* offset_in_framebuffer = (u32*)m_framebuffer_region->vaddr().offset(x * sizeof(u32) * 8).offset(y * 8 * sizeof(u32) * width()).as_ptr();
+ int current_bitpixels = 0;
+ int current_bitpixel = 0;
+ auto bitmap = font8x8_basic[(int)ch];
+ bool set;
+ BGRColor foreground_color = convert_standard_color_to_bgr_color(foreground);
+ BGRColor background_color = convert_standard_color_to_bgr_color(background);
+ for (current_bitpixels = 0; current_bitpixels < 8; current_bitpixels++) {
+ for (current_bitpixel = 0; current_bitpixel < 8; current_bitpixel++) {
+ set = bitmap[current_bitpixels] & (1 << current_bitpixel);
+ if (set) {
+ offset_in_framebuffer[current_bitpixel] = foreground_color;
+ } else {
+ offset_in_framebuffer[current_bitpixel] = background_color;
+ }
+ }
+ offset_in_framebuffer = (u32*)((u8*)offset_in_framebuffer + width() * 4);
+ }
+ m_x = x + 1;
+ if (m_x >= max_column()) {
+ m_x = 0;
+ m_y = y + 1;
+ if (m_y >= max_row())
+ m_y = 0;
+ }
+}
+
+void FramebufferConsole::write(size_t, size_t, String, Color, Color) const
+{
+ TODO();
+}
+void FramebufferConsole::write(size_t x, size_t y, char ch) const
+{
+ write(x, y, ch, m_default_background_color, m_default_foreground_color);
+}
+void FramebufferConsole::write(size_t, size_t, String) const
+{
+ TODO();
+}
+
+void FramebufferConsole::write(char ch) const
+{
+ write(m_x, m_y, ch, m_default_background_color, m_default_foreground_color);
+}
+
+}
diff --git a/Kernel/Graphics/Console/FramebufferConsole.h b/Kernel/Graphics/Console/FramebufferConsole.h
new file mode 100644
index 0000000000..336d117367
--- /dev/null
+++ b/Kernel/Graphics/Console/FramebufferConsole.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RefCounted.h>
+#include <AK/Types.h>
+#include <Kernel/Graphics/Console/Console.h>
+#include <Kernel/PhysicalAddress.h>
+
+namespace Kernel::Graphics {
+class FramebufferConsole final : public Console {
+public:
+ static NonnullRefPtr<FramebufferConsole> initialize(PhysicalAddress, size_t width, size_t height, size_t bpp);
+
+ virtual size_t bytes_per_base_glyph() const override;
+ virtual size_t chars_per_line() const override;
+
+ virtual size_t max_column() const { return m_width / 8; }
+ virtual size_t max_row() const { return m_height / 8; }
+
+ virtual bool is_hardware_paged_capable() const override { return false; }
+ virtual bool has_hardware_cursor() const override { return false; }
+
+ virtual void set_cursor(size_t x, size_t y) override;
+ virtual void hide_cursor() override;
+ virtual void show_cursor() override;
+
+ virtual void clear(size_t x, size_t y, size_t length) const override;
+ virtual void write(size_t x, size_t y, char ch, Color background, Color foreground) const override;
+ virtual void write(size_t x, size_t y, String cstring, Color background, Color foreground) const override;
+ virtual void write(size_t x, size_t y, char ch) const override;
+ virtual void write(size_t x, size_t y, String) const override;
+ virtual void write(char ch) const override;
+
+ virtual void enable() override;
+ virtual void disable() override;
+
+protected:
+ void clear_glyph(size_t x, size_t y) const;
+ FramebufferConsole(PhysicalAddress, size_t width, size_t height, size_t bpp);
+ OwnPtr<Region> m_framebuffer_region;
+ PhysicalAddress m_framebuffer_address;
+ size_t m_pitch;
+ mutable SpinLock<u8> m_lock;
+};
+}
diff --git a/Kernel/Graphics/Console/TextModeConsole.cpp b/Kernel/Graphics/Console/TextModeConsole.cpp
new file mode 100644
index 0000000000..847f899ffe
--- /dev/null
+++ b/Kernel/Graphics/Console/TextModeConsole.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/Graphics/Console/TextModeConsole.h>
+#include <Kernel/Graphics/GraphicsManagement.h>
+#include <Kernel/IO.h>
+
+namespace Kernel::Graphics {
+
+UNMAP_AFTER_INIT NonnullRefPtr<TextModeConsole> TextModeConsole::initialize(const VGACompatibleAdapter& adapter)
+{
+ return adopt_ref(*new TextModeConsole(adapter));
+}
+
+UNMAP_AFTER_INIT TextModeConsole::TextModeConsole(const VGACompatibleAdapter& adapter)
+ : VGAConsole(adapter, VGAConsole::Mode::TextMode, 80, 25)
+ , m_current_vga_window(m_vga_region->vaddr().offset(0x18000).as_ptr())
+{
+ for (size_t index = 0; index < height(); index++) {
+ clear_vga_row(index);
+ }
+ dbgln("Text mode console initialized!");
+}
+
+enum VGAColor : u8 {
+ Black = 0,
+ Blue,
+ Green,
+ Cyan,
+ Red,
+ Magenta,
+ Brown,
+ LightGray,
+ DarkGray,
+ BrightBlue,
+ BrightGreen,
+ BrightCyan,
+ BrightRed,
+ BrightMagenta,
+ Yellow,
+ White,
+};
+
+static inline VGAColor convert_standard_color_to_vga_color(Console::Color color)
+{
+ switch (color) {
+ case Console::Color::Black:
+ return VGAColor::Black;
+ case Console::Color::Red:
+ return VGAColor::Red;
+ case Console::Color::Brown:
+ return VGAColor::Brown;
+ case Console::Color::Blue:
+ return VGAColor::Blue;
+ case Console::Color::Magenta:
+ return VGAColor::Magenta;
+ case Console::Color::Green:
+ return VGAColor::Green;
+ case Console::Color::Cyan:
+ return VGAColor::Cyan;
+ case Console::Color::LightGray:
+ return VGAColor::LightGray;
+ case Console::Color::DarkGray:
+ return VGAColor::DarkGray;
+ case Console::Color::BrightRed:
+ return VGAColor::BrightRed;
+ case Console::Color::BrightGreen:
+ return VGAColor::BrightGreen;
+ case Console::Color::Yellow:
+ return VGAColor::Yellow;
+ case Console::Color::BrightBlue:
+ return VGAColor::BrightBlue;
+ case Console::Color::BrightMagenta:
+ return VGAColor::BrightMagenta;
+ case Console::Color::BrightCyan:
+ return VGAColor::BrightCyan;
+ case Console::Color::White:
+ return VGAColor::White;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+void TextModeConsole::set_cursor(size_t x, size_t y)
+{
+ ScopedSpinLock main_lock(GraphicsManagement::the().main_vga_lock());
+ ScopedSpinLock lock(m_vga_lock);
+ m_cursor_x = x;
+ m_cursor_y = y;
+ u16 value = m_current_vga_start_address + (y * width() + x);
+ IO::out8(0x3d4, 0x0e);
+ IO::out8(0x3d5, MSB(value));
+ IO::out8(0x3d4, 0x0f);
+ IO::out8(0x3d5, LSB(value));
+}
+void TextModeConsole::hide_cursor()
+{
+ ScopedSpinLock main_lock(GraphicsManagement::the().main_vga_lock());
+ ScopedSpinLock lock(m_vga_lock);
+ IO::out8(0x3D4, 0xA);
+ IO::out8(0x3D5, 0x20);
+}
+void TextModeConsole::show_cursor()
+{
+ ScopedSpinLock main_lock(GraphicsManagement::the().main_vga_lock());
+ ScopedSpinLock lock(m_vga_lock);
+ IO::out8(0x3D4, 0xA);
+ IO::out8(0x3D5, 0x20);
+}
+
+void TextModeConsole::clear(size_t x, size_t y, size_t length) const
+{
+ ScopedSpinLock lock(m_vga_lock);
+ auto* buf = (u16*)(m_current_vga_window + (x * 2) + (y * width() * 2));
+ for (size_t index = 0; index < length; index++) {
+ buf[index] = 0x0720;
+ }
+}
+void TextModeConsole::write(size_t x, size_t y, char ch) const
+{
+ ScopedSpinLock lock(m_vga_lock);
+ auto* buf = (u16*)(m_current_vga_window + (x * 2) + (y * width() * 2));
+ *buf = (m_default_foreground_color << 8) | (m_default_background_color << 12) | ch;
+ m_x = x + 1;
+ if (m_x >= max_column()) {
+ m_x = 0;
+ m_y = y + 1;
+ if (m_y >= max_row())
+ m_y = 0;
+ }
+}
+void TextModeConsole::write(size_t x, size_t y, String cstring) const
+{
+ ScopedSpinLock lock(m_vga_lock);
+ auto* buf = (u16*)(m_current_vga_window + (x * 2) + (y * width() * 2));
+ u16 color_mask = (m_default_foreground_color << 8) | (m_default_background_color << 12);
+ for (size_t index = 0; index < cstring.length(); index++) {
+ buf[index] = color_mask | cstring[index];
+ }
+ m_x = x + cstring.length();
+ if (m_x >= max_column()) {
+ m_x = 0;
+ m_y = y + 1;
+ if (m_y >= max_row())
+ m_y = 0;
+ }
+}
+void TextModeConsole::write(size_t x, size_t y, char ch, Color background, Color foreground) const
+{
+ ScopedSpinLock lock(m_vga_lock);
+ auto* buf = (u16*)(m_current_vga_window + (x * 2) + (y * width() * 2));
+ *buf = foreground << 8 | background << 12 | ch;
+ m_x = x + 1;
+ if (m_x >= max_column()) {
+ m_x = 0;
+ m_y = y + 1;
+ if (m_y >= max_row())
+ m_y = 0;
+ }
+}
+void TextModeConsole::write(size_t x, size_t y, String cstring, Color background, Color foreground) const
+{
+ ScopedSpinLock lock(m_vga_lock);
+ auto* buf = (u16*)(m_current_vga_window + (x * 2) + (y * width() * 2));
+ u16 color_mask = foreground << 8 | background << 12;
+ for (size_t index = 0; index < cstring.length(); index++) {
+ buf[index] = color_mask | cstring[index];
+ }
+ m_x = x + cstring.length();
+ if (m_x >= max_column()) {
+ m_x = 0;
+ m_y = y + 1;
+ if (m_y >= max_row())
+ m_y = 0;
+ }
+}
+
+void TextModeConsole::clear_vga_row(u16 row)
+{
+ clear(row * width(), width(), width());
+}
+
+void TextModeConsole::set_vga_start_row(u16 row)
+{
+ ScopedSpinLock lock(m_vga_lock);
+ m_vga_start_row = row;
+ m_current_vga_start_address = row * width();
+ m_current_vga_window = m_current_vga_window + row * width() * bytes_per_base_glyph();
+ IO::out8(0x3d4, 0x0c);
+ IO::out8(0x3d5, MSB(m_current_vga_start_address));
+ IO::out8(0x3d4, 0x0d);
+ IO::out8(0x3d5, LSB(m_current_vga_start_address));
+}
+
+void TextModeConsole::write(char ch) const
+{
+ write(m_x, m_y, ch);
+}
+
+}
diff --git a/Kernel/Graphics/Console/TextModeConsole.h b/Kernel/Graphics/Console/TextModeConsole.h
new file mode 100644
index 0000000000..c465b63f39
--- /dev/null
+++ b/Kernel/Graphics/Console/TextModeConsole.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RefCounted.h>
+#include <AK/Types.h>
+#include <Kernel/Graphics/Console/VGAConsole.h>
+#include <Kernel/SpinLock.h>
+
+namespace Kernel::Graphics {
+class TextModeConsole final : public VGAConsole {
+public:
+ static NonnullRefPtr<TextModeConsole> initialize(const VGACompatibleAdapter& adapter);
+ virtual size_t chars_per_line() const override { return width(); };
+
+ virtual bool has_hardware_cursor() const override { return true; }
+ virtual bool is_hardware_paged_capable() const override { return true; }
+
+ virtual size_t bytes_per_base_glyph() const override { return 2; }
+ virtual void set_cursor(size_t x, size_t y) override;
+ virtual void hide_cursor() override;
+ virtual void show_cursor() override;
+ virtual void clear(size_t x, size_t y, size_t length) const override;
+ virtual void write(size_t x, size_t y, char ch) const override;
+ virtual void write(size_t x, size_t y, String cstring) const override;
+ virtual void write(size_t x, size_t y, char ch, Color background, Color foreground) const override;
+ virtual void write(size_t x, size_t y, String, Color background, Color foreground) const override;
+ virtual void write(char ch) const override;
+
+ virtual void enable() override { }
+ virtual void disable() override { VERIFY_NOT_REACHED(); }
+
+private:
+ void clear_vga_row(u16 row);
+ void set_vga_start_row(u16 row);
+
+ explicit TextModeConsole(const VGACompatibleAdapter&);
+
+ mutable SpinLock<u8> m_vga_lock;
+ u16 m_vga_start_row { 0 };
+ u16 m_current_vga_start_address { 0 };
+ u8* m_current_vga_window { nullptr };
+ u16 m_cursor_x { 0 };
+ u16 m_cursor_y { 0 };
+};
+}
diff --git a/Kernel/Graphics/Console/VGAConsole.cpp b/Kernel/Graphics/Console/VGAConsole.cpp
new file mode 100644
index 0000000000..70472b55e7
--- /dev/null
+++ b/Kernel/Graphics/Console/VGAConsole.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/Graphics/Console/VGAConsole.h>
+
+namespace Kernel::Graphics {
+
+UNMAP_AFTER_INIT VGAConsole::VGAConsole(const VGACompatibleAdapter& adapter, Mode mode, size_t width, size_t height)
+ : Console(width, height)
+ , m_vga_region(MM.allocate_kernel_region(PhysicalAddress(0xa0000), page_round_up(0xc0000 - 0xa0000), "VGA Display", Region::Access::Read | Region::Access::Write).release_nonnull())
+ , m_adapter(adapter)
+ , m_mode(mode)
+{
+}
+
+}
diff --git a/Kernel/Graphics/Console/VGAConsole.h b/Kernel/Graphics/Console/VGAConsole.h
new file mode 100644
index 0000000000..e82f1d5e59
--- /dev/null
+++ b/Kernel/Graphics/Console/VGAConsole.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RefCounted.h>
+#include <AK/Types.h>
+#include <Kernel/Graphics/Console/Console.h>
+#include <Kernel/Graphics/VGACompatibleAdapter.h>
+
+namespace Kernel::Graphics {
+class VGAConsole : public Console {
+public:
+ // Note: these are the modes we will support and only these
+ enum class Mode {
+ TextMode = 1, // Text Mode
+ Colored256, // 320x200 256 color mode
+ Colored16, // 640x480 16 color mode
+ };
+
+public:
+ static NonnullRefPtr<VGAConsole> initialize(const VGACompatibleAdapter&, Mode, size_t width, size_t height);
+
+ virtual bool is_hardware_paged_capable() const override { return false; }
+ virtual bool has_hardware_cursor() const override { return false; }
+
+ virtual ~VGAConsole() = default;
+
+protected:
+ VGAConsole(const VGACompatibleAdapter&, Mode, size_t width, size_t height);
+
+ NonnullOwnPtr<Region> m_vga_region;
+ NonnullRefPtr<VGACompatibleAdapter> m_adapter;
+ const Mode m_mode;
+};
+}