Max OS 0.3
Loading...
Searching...
No Matches
framebuffer.cpp
Go to the documentation of this file.
1
11#include <console/framebuffer.h>
12#include <common/logger.h>
13
14using namespace MaxOS;
15using namespace MaxOS::common;
16using namespace MaxOS::memory;
17using namespace MaxOS::console;
18using namespace MaxOS::system;
19
26{
27
28 // Save the framebuffer info
29 s_framebuffer_info = framebuffer_info;
30 m_framebuffer_bpp = s_framebuffer_info->common.framebuffer_bpp;
31 m_framebuffer_pitch = s_framebuffer_info->common.framebuffer_pitch;
32 m_framebuffer_size = s_framebuffer_info->common.framebuffer_height * m_framebuffer_pitch;
33 Logger::DEBUG() << "Framebuffer: bpp=" << m_framebuffer_bpp << ", pitch=" << m_framebuffer_pitch << ", size=" << m_framebuffer_size << "\n";
34
35 // Map the frame buffer into the higher half
36 auto physical_address = (uint64_t) s_framebuffer_info->common.framebuffer_addr;
37 m_framebuffer_address = (uint64_t *) PhysicalMemoryManager::to_dm_region(physical_address);
38 PhysicalMemoryManager::s_current_manager->map_area((physical_address_t *) physical_address, m_framebuffer_address, m_framebuffer_size, WRITE | PRESENT);
39
40 // Reserve the physical memory
41 size_t pages = PhysicalMemoryManager::size_to_frames(m_framebuffer_size);
42 PhysicalMemoryManager::s_current_manager->reserve(s_framebuffer_info->common.framebuffer_addr, pages, "Framebuffer");
43
44 // Log info
45 Logger::DEBUG() << "Framebuffer address: physical=0x" << (uint64_t) physical_address << ", virtual=0x" << (uint64_t) m_framebuffer_address << "\n";
46 Logger::DEBUG() << "Framebuffer mapped: 0x" << (uint64_t) m_framebuffer_address << " - 0x" << (uint64_t) (m_framebuffer_address + m_framebuffer_size) << " (pages: " << pages << ")\n";
47
48 // Prepare the console
49 m_video_memory_meta = (uint16_t*) MemoryManager::kmalloc(width() * height() * sizeof(uint16_t));
51 print_logo();
52
53 // Set up the output area
54 m_console_area = new ConsoleArea(this, 0, 0, width() / 2 - 25, height(), ConsoleColour::DarkGrey, ConsoleColour::Black);
55 cout = new ConsoleStream(m_console_area);
56
57 // Only log to the screen when debugging
58#ifndef NDEBUG
60 Logger::INFO() << "Console Stream set up \n";
61#endif
62}
63
64FramebufferConsole::~FramebufferConsole() = default;
65
72 return s_framebuffer_info->common.framebuffer_width / FONT_WIDTH; // 8 pixels per character
73}
74
81 return s_framebuffer_info->common.framebuffer_height / FONT_HEIGHT;
82}
83
91void FramebufferConsole::put_character(uint16_t x, uint16_t y, char c) {
92
93 // Parse any ansi codes
94 if(c == '\033') {
95
96 // Store the character
97 ansi_code_length = 0;
98 ansi_code[ansi_code_length++] = c;
99
100 // Do not draw the escape character
101 return;
102 }
103
104 if(ansi_code_length < 8) {
105
106 // Add the character to the ANSI code
107 ansi_code[ansi_code_length++] = c;
108
109 // If the ANSI code is complete
110 if(c == 'm') {
111 ansi_code[ansi_code_length] = '\0';
112 ansi_code_length = -1;
113
114 if(strcmp("\033[0m", ansi_code) == 0) {
115 m_foreground_color = ConsoleColour::Uninitialised;
116 m_background_color = ConsoleColour::Uninitialised;
117 return;
118 }
119
120 // Get the colour from the ANSI code
121 const Colour colour(ansi_code);
122
123 // Set the colour
124 bool foreground = ansi_code[4] == '3';
125 if(foreground)
126 m_foreground_color = colour.to_console_colour();
127 else
128 m_background_color = colour.to_console_colour();
129
130 }
131
132 // Do not draw the escape character
133 return;
134 }
135
136 // If the coordinates are out of bounds, return
137 if(x >= width() || y >= height())
138 return;
139
140 // Set the character at the offset, by masking the character with the current character (last 8 bits)
141 int offset = (y * width() + x);
142 m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0xFF00) | (uint16_t) c;
143
144 // Convert the char into a string
145 char s[] = " ";
146 s[0] = c;
147
148 // Get the colour as a number
149 Colour foreground = m_foreground_color == ConsoleColour::Uninitialised ? Colour(get_foreground_color(x, y)) : Colour(m_foreground_color);
150 Colour background = m_background_color == ConsoleColour::Uninitialised ? Colour(get_background_color(x, y)) : Colour(m_background_color);
151 auto fg = GraphicsContext::colour_to_int(foreground, m_framebuffer_bpp);
152 auto bg = GraphicsContext::colour_to_int(background, m_framebuffer_bpp);
153
154 // Draw the text from top to bottom
155 for(int y_bit_map_offset = 0; y_bit_map_offset < FONT_WIDTH; y_bit_map_offset++) {
156 for(int x_bit_map_offset = 0; x_bit_map_offset < FONT_HEIGHT - (2 * FONT_PADDING); ++x_bit_map_offset) {
157
158 // Get the character
159 uint8_t character = c;
160
161 // Draw the pixel
162 bool set = AMIGA_FONT[(uint16_t) character * 8 + y_bit_map_offset] & (128 >> (x_bit_map_offset % 8));
163 put_pixel(x * 8 + x_bit_map_offset, y * FONT_HEIGHT + y_bit_map_offset, set ? fg : bg);
164
165 }
166 }
167}
168
176void FramebufferConsole::set_foreground_color(uint16_t x, uint16_t y, common::ConsoleColour foreground) {
177
178 // If the coordinates are out of bounds, return
179 if(x >= width() || y >= height())
180 return;
181
182 // Calculate the offset
183 int offset = (y * width() + x);
184
185 // Set the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
186 m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0xF0FF) | ((uint16_t) foreground << 8);
187}
188
196void FramebufferConsole::set_background_color(uint16_t x, uint16_t y, common::ConsoleColour background) {
197
198 // If the coordinates are out of bounds, return
199 if(x >= width() || y >= height())
200 return;
201
202 // Calculate the offset
203 int offset = (y * width() + x);
204
205 // Set the background color at the offset, by masking the background color with the current background color (bits 12-15)
206 m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0x0FFF) | ((uint16_t) background << 12);
207}
208
216char FramebufferConsole::get_character(uint16_t x, uint16_t y) {
217
218 // If the coordinates are out of bounds, return
219 if(x >= width() || y >= height())
220 return ' ';
221
222 // Calculate the offset
223 int offset = (y * width() + x);
224
225 // Return the character at the offset, by masking the character with the current character (last 8 bits)
226 return (char) (m_video_memory_meta[offset] & 0x00FF);
227}
228
236ConsoleColour FramebufferConsole::get_foreground_color(uint16_t x, uint16_t y) {
237
238 if(CPU::panic_lock.is_locked())
239 return ConsoleColour::White;
240
241 // If the coordinates are out of bounds, return
242 if(x >= width() || y >= height())
243 return ConsoleColour::White;
244
245 // Calculate the offset
246 int offset = (y * width() + x);
247
248 // Return the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
249 return (ConsoleColour) ((m_video_memory_meta[offset] & 0x0F00) >> 8);
250}
251
259ConsoleColour FramebufferConsole::get_background_color(uint16_t x, uint16_t y) {
260
261 if(CPU::panic_lock.is_locked())
262 return ConsoleColour::Red;
263
264 // If the coordinates are out of bounds, return
265 if(x >= width() || y >= height())
266 return ConsoleColour::Black;
267
268 // Calculate the offset
269 int offset = (y * width() + x);
270
271 // Return the background color at the offset, by masking the background color with the current background color (bits 12-15)
272 return (ConsoleColour) ((m_video_memory_meta[offset] & 0xF000) >> 12);
273}
274
281
282 // Load the logo
283 const char* logo = is_panic ? header_data_kp : header_data;
284 auto address = PhysicalMemoryManager::to_dm_region(s_framebuffer_info->common.framebuffer_addr);
285 auto bpp = s_framebuffer_info->common.framebuffer_bpp;
286
287 // Find the center of the screen
288 uint32_t screen_width = s_framebuffer_info->common.framebuffer_width;
289 uint32_t screen_height = s_framebuffer_info->common.framebuffer_height;
290 uint32_t center_x = screen_width / 2;
291 uint32_t center_y = screen_height / 2 - 80;
292
293 // Fill the screen with the logo colour
294 auto col = GraphicsContext::colour_to_int(Colour(is_panic ? ConsoleColour::Red : ConsoleColour::Black), bpp);
295 memset(address, col, screen_width * screen_height * (bpp / 8));
296
297 // Draw the logo
298 for(uint32_t logo_y = 0; logo_y < LOGO_HEIGHT; ++logo_y) {
299 for(uint32_t logo_x = 0; logo_x < LOGO_WIDTH; ++logo_x) {
300
301 // Get the pixel from the logo
302 uint8_t pixel[3] = { 0 };
303 LOGO_HEADER_PIXEL(logo, pixel)
304
305 // Draw the pixel
306 auto col = GraphicsContext::colour_to_int(common::Colour(pixel[0], pixel[1], pixel[2]), bpp);
307 put_pixel(center_x - LOGO_WIDTH / 2 + logo_x, center_y - LOGO_HEIGHT / 2 + logo_y, col);
308 }
309 }
310
312}
313
314
326void FramebufferConsole::scroll_up(uint16_t left, uint16_t top, uint16_t width,
327 uint16_t height,
328 common::ConsoleColour foreground,
329 common::ConsoleColour background, char fill) {
330
331
332 // Get the framebuffer info
333 uint64_t framebuffer_width = s_framebuffer_info->common.framebuffer_width;
334 uint64_t framebuffer_bpp = m_framebuffer_bpp; // in bits per pixel
335 uint64_t bytes_per_pixel = framebuffer_bpp / 8;
336 uint64_t framebuffer_pitch = framebuffer_width * bytes_per_pixel;
337
338 uint16_t line_height = FONT_HEIGHT;
339
340 // Region conversions
341 uint16_t region_pixel_y = top * line_height;
342 uint16_t region_pixel_height = height * line_height;
343 uint16_t region_pixel_left = left * FONT_WIDTH;
344 uint16_t region_pixel_width = width * FONT_WIDTH;
345 size_t row_bytes = region_pixel_width * bytes_per_pixel;
346
347 // Decide the colour of the pixel
348 ConsoleColour to_set_foreground = get_foreground_color(left, top + height - 1);
349 ConsoleColour to_set_background = get_background_color(left, top + height - 1);
350 uint32_t fill_value = GraphicsContext::colour_to_int(Colour(to_set_background), m_framebuffer_bpp);
351
352 // Scroll the region upward by one text line
353 for(uint16_t row = 0; row < region_pixel_height - line_height; row++) {
354 uint8_t* src = (uint8_t*)m_framebuffer_address + (region_pixel_y + row + line_height) * framebuffer_pitch + region_pixel_left * bytes_per_pixel;
355 uint8_t* dest = (uint8_t*)m_framebuffer_address + (region_pixel_y + row) * framebuffer_pitch + region_pixel_left * bytes_per_pixel;
356 memmove(dest, src, row_bytes);
357 }
358
359 // Clear the last line of the region
360 uint16_t clear_start_y = region_pixel_y + region_pixel_height - line_height;
361 for(uint16_t row = 0; row < line_height; row++) {
362 auto row_add = (uint32_t*) ((uint8_t*)m_framebuffer_address + (clear_start_y + row) * framebuffer_pitch + region_pixel_left * 4);
363 for(uint16_t col = 0; col < region_pixel_width; col++) {
364 row_add[col] = fill_value;
365 }
366 }
367
368 //Update any per-pixel colour metadata
369 uint16_t text_row = top + height - 1;
370 for(uint16_t x = left; x < left + width; x++) {
371 set_foreground_color(x, text_row, to_set_foreground);
372 set_background_color(x, text_row, to_set_background);
373 }
374}
375
380
381 // Done
382 Logger::HEADER() << "MaxOS Kernel Successfully Booted\n" << ANSI_COLOURS[ANSIColour::Reset];
383 cout->set_cursor(0, 0);
385}
386
393
394 // Not ready
395 if(!s_framebuffer_info)
396 return;
397
398 // Check bounds
399 if(percentage > 100)
400 percentage = 100;
401
402 uint8_t progress_height = 15;
403 uint8_t progress_spacing = 20;
404 uint8_t progress_width_cull = 40;
405
406 // Find the center of the screen
407 uint32_t right_x = (s_framebuffer_info->common.framebuffer_width / 2) - LOGO_WIDTH / 2;
408 uint32_t bottom_y = (s_framebuffer_info->common.framebuffer_height / 2 - 80) - LOGO_HEIGHT / 2;
409
410 // Find the bounds
411 uint32_t start_x = progress_width_cull;
412 uint32_t start_y = LOGO_HEIGHT + progress_spacing;
413 uint32_t end_x = LOGO_WIDTH - progress_width_cull;
414 uint32_t end_y = LOGO_HEIGHT + progress_height + progress_spacing;
415
416 // Draw the progress bar
417 for(uint32_t progress_y = start_y; progress_y < end_y; ++progress_y) {
418 for(uint32_t progress_x = start_x; progress_x < end_x; ++progress_x) {
419
420 // Check if drawing border
421 bool is_border = (progress_y == start_y) || (progress_y == end_y - 1) ||
422 (progress_x == start_x) || (progress_x == end_x - 1);
423
424 // Only draw the border if it is the first time drawing it
425 is_border = is_border && percentage == 0;
426
427 // If it is not within the percentage, skip it
428 uint32_t logo_progress_width = LOGO_WIDTH * percentage / 100;
429 if(progress_x > logo_progress_width && !is_border)
430 continue;
431
432 // Draw the pixel
433 auto col = GraphicsContext::colour_to_int(Colour(0xFF, 0xFF, 0xFF), s_framebuffer_info->common.framebuffer_bpp);
434 put_pixel(right_x + progress_x, bottom_y + progress_y, col);
435
436 }
437 }
438}
439
446void FramebufferConsole::put_pixel(uint32_t x, uint32_t y, uint32_t colour) {
447
448 auto address = PhysicalMemoryManager::to_dm_region(s_framebuffer_info->common.framebuffer_addr);
449 auto *pixel_address = (uint32_t *) ((uint8_t *) address + (s_framebuffer_info->common.framebuffer_pitch * y) + (s_framebuffer_info->common.framebuffer_bpp * x) / 8);
450 *pixel_address = colour;
451
452}
static Logger * active_logger()
Gets the active logger (to be used to modify the logger)
Definition logger.cpp:240
static LogRecord DEBUG()
Gets the active logger for debug logs.
Definition logger.cpp:204
void disable_log_writer(OutputStream *log_writer)
Prevents an output stream from being used.
Definition logger.cpp:66
static LogRecord HEADER()
Gets the active logger for headers.
Definition logger.cpp:231
void add_log_writer(OutputStream *log_writer)
Adds an output stream to the logger.
Definition logger.cpp:44
static LogRecord INFO()
Gets the active logger for info logs.
Definition logger.cpp:195
static uint32_t colour_to_int(const Colour &colour, uint32_t color_depth)
Converts a colour to an integer value based on the current color depth.
A console that is a subsection of another console, limited by a width and height.
Definition console.h:60
A stream that can be used to write to a console.
Definition console.h:92
void set_cursor(uint16_t x, uint16_t y)
Set the m_position of the cursor.
Definition console.cpp:509
virtual void scroll_up()
Scroll the entire console up by 1 line.
Definition console.cpp:141
virtual void clear()
Definition console.cpp:174
static void update_progress_bar(uint8_t percentage)
Updates the progress bar.
void set_background_color(uint16_t x, uint16_t y, common::ConsoleColour) final
Sets the background color at the specified location.
void put_character(uint16_t x, uint16_t y, char) final
Places a character at the specified location.
common::ConsoleColour get_foreground_color(uint16_t x, uint16_t y) final
Gets the foreground color at the specified location.
void set_foreground_color(uint16_t x, uint16_t y, common::ConsoleColour) final
Sets the foreground color at the specified location.
uint16_t height() final
Gets the height of the console.
common::ConsoleColour get_background_color(uint16_t x, uint16_t y) final
Gets the background color at the specified location.
void finish() const
Cleans up the boot console.
uint16_t width() final
Gets the width of the console.
FramebufferConsole(multiboot_tag_framebuffer *framebuffer_info)
Constructs a new VESA Boot Console object, initializing the console area for text output.
char get_character(uint16_t x, uint16_t y) final
Gets the character at the specified location.
static void print_logo(bool is_panic=false)
Prints the logo to the center of the screen.
ConsoleStream * cout
The boot console output stream.
static void * kmalloc(size_t size)
Allocates a block of memory in the KERNEL space.
static void * to_dm_region(uintptr_t physical_address)
Converts a physical address to a direct map region address if it is in the lower region using the hig...
Definition physical.cpp:929
void reserve(uint64_t address)
Reserves a physical address.
Definition physical.cpp:774
void map_area(virtual_address_t *virtual_address_start, size_t length, size_t flags)
Allocates a new area physical memory to a area virtual address.
Definition physical.cpp:549
static PhysicalMemoryManager * s_current_manager
The current physical memory manager in use.
Definition physical.h:183
static size_t size_to_frames(size_t size)
Converts a size to the number of frames.
Definition physical.cpp:144
static common::Spinlock panic_lock
Lock to prevent multiple panics at once.
Definition cpu.h:267
Defines the VESABootConsole driver for handling console output during boot using an VESA framebuffer.
constexpr uint8_t FONT_PADDING
How many vertical pixels to add to the top and bottom of the font to prevent squishing.
constexpr uint8_t FONT_HEIGHT
How many pixels tall the font is.
constexpr uint8_t FONT_WIDTH
How many pixels wide the font is.
Defines a Logger class for logging messages with different severity levels to multiple output streams...
#define LOGO_HEADER_PIXEL(data, pixel)
Call this macro repeatedly. After each use, the pixel data can be extracted.
Definition logo.h:23
constexpr int LOGO_WIDTH
Width of the logo in pixels.
Definition logo.h:19
constexpr int LOGO_HEIGHT
Height of the logo in pixels.
Definition logo.h:20
void physical_address_t
A type representing a physical address (used for readability)
Definition physical.h:31
@ PRESENT
The page is present in memory.
Definition physical.h:44
@ WRITE
Memory in this page is writable.
Definition physical.h:45
multiboot_uint32_t framebuffer_width
The width of the framebuffer in pixels.
Definition multiboot.h:343
multiboot_uint8_t framebuffer_bpp
The number of bits per pixel.
Definition multiboot.h:345
multiboot_uint32_t framebuffer_height
The height of the framebuffer in pixels.
Definition multiboot.h:344
multiboot_uint64_t framebuffer_addr
The physical address of the framebuffer.
Definition multiboot.h:341
multiboot_uint32_t framebuffer_pitch
The number of bytes per horizontal line.
Definition multiboot.h:342
A tag containing information about the framebuffer.
Definition multiboot.h:356
struct multiboot_tag_framebuffer_common common
*copydoc multiboot_tag_framebuffer_common
Definition multiboot.h:357