lib: debug: Introduce loglevels + many minor changes

Implement 8 loglevels to use with printk:

While at it, separate the font in a new "video" directory, which
also makes space for a proper video probing implementation. Fill
in the font from 32 to 256. Scale the font to render twice as big.
Implement dynamic line length detection. Change a few things here
and there to follow the linux kernel code style. Add a nice logo.

Signed-off-by: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
This commit is contained in:
Ivaylo Ivanov 2024-10-10 16:24:20 +03:00
parent be0ad76a97
commit 3b517ba95a
11 changed files with 4648 additions and 1893 deletions

View File

@ -13,6 +13,10 @@ menu "Building options"
need to set this unless you want the configured kernel build need to set this unless you want the configured kernel build
directory to select the cross-compiler automatically. directory to select the cross-compiler automatically.
config LOGLEVEL
int "Verbosity of logs"
default 7
config EMBED_LINUX config EMBED_LINUX
bool "Embed linux kernel and device tree" bool "Embed linux kernel and device tree"
default y default y

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */ // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> * Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
*/ */
@ -6,7 +6,16 @@
#ifndef DEBUG_H_ /* Include guard */ #ifndef DEBUG_H_ /* Include guard */
#define DEBUG_H_ #define DEBUG_H_
extern void draw_text(volatile char *fb, char *text, int textX, int textY, int width, int stride); // Sorted by importance
long int debug_linecount = 0; #define KERN_EMERG 0
#define KERN_ALERT 1
#define KERN_CRIT 2
#define KERN_ERR 3
#define KERN_WARNING 4
#define KERN_NOTICE 5
#define KERN_INFO 6
#define KERN_DEBUG 7
#endif extern void printk(int loglevel, char *text);
#endif // DEBUG_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */ // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> * Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
* Copyright (c) 2022, Markuss Broks <markuss.broks@gmail.com> * Copyright (c) 2022, Markuss Broks <markuss.broks@gmail.com>
@ -10,6 +10,8 @@
#include <stdint.h> #include <stdint.h>
extern void __simplefb_raw_print(volatile char *fb, char *text, int text_x,
int text_y, int width, int stride);
extern void simplefb_probe(void *data); extern void simplefb_probe(void *data);
extern struct video *video_info; extern struct video *video_info;
@ -34,4 +36,4 @@ typedef struct _font_params {
font_params get_font_params(void); font_params get_font_params(void);
#endif #endif // SIMPLEFB_H_

20
include/lib/video/font.h Normal file
View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Based on https://github.com/torvalds/linux/blob/master/lib/fonts/font_8x16.c
*/
#ifndef FONT_H_ /* Include guard */
#define FONT_H_
#define FONTW 8
#define FONTH 16
// Define scaled font dimensions --> 8x16 becomes 16x32
#define SCALE_FACTOR 2
#define SCALED_FONTW (FONTW * SCALE_FACTOR)
#define SCALED_FONTH (FONTH * SCALE_FACTOR)
extern const unsigned char letters[256][16];
extern int font_index(char a);
#endif // FONT_H_

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */ // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> * Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
*/ */
@ -12,9 +12,6 @@ extern unsigned long kernel_size;
extern void load_kernel(void* dtb, void* x1, void* x2, void* x3, void* kernel); extern void load_kernel(void* dtb, void* x1, void* x2, void* x3, void* kernel);
extern void soc_init(void); extern void soc_init(void);
extern void clean_fb(volatile char *fb, int width, int height, int stride);
extern void printk(char *text);
extern void writel(unsigned int value, void* address); extern void writel(unsigned int value, void* address);
#endif // MAIN_H_ #endif // MAIN_H_

View File

@ -1,7 +1,10 @@
# SIMPLEFB # simplefb
lib-$(CONFIG_SIMPLE_FB) += simplefb/simplefb.o lib-$(CONFIG_SIMPLE_FB) += simplefb/simplefb.o
# DEBUG # video
lib-$(CONFIG_SIMPLE_FB) += video/font.o
# debug
lib-y += debug/debug.o lib-y += debug/debug.o
# unic (neatlibc still temporarily resides) # unic (neatlibc still temporarily resides)

View File

@ -1,20 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0 */ // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> * Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
*/ */
#include <stddef.h>
#include <string.h>
#include <lib/debug.h> #include <lib/debug.h>
#include <lib/simplefb.h> #include <lib/simplefb.h>
#include <stddef.h> #include <lib/video/font.h>
long int debug_linecount = 0;
// Global log level that controls the verbosity
static int global_loglevel = CONFIG_LOGLEVEL;
void printk(int log_level, char *text)
{
if (log_level > global_loglevel)
return;
char *prefix;
switch (log_level) {
case KERN_EMERG:
prefix = "[EMERG] ";
break;
case KERN_ALERT:
prefix = "[ALERT] ";
break;
case KERN_CRIT:
prefix = "[CRIT] ";
break;
case KERN_ERR:
prefix = "[ERROR] ";
break;
case KERN_WARNING:
prefix = "[WARN] ";
break;
case KERN_NOTICE:
prefix = "[NOTICE] ";
break;
case KERN_INFO:
prefix = "[INFO] ";
break;
case KERN_DEBUG:
prefix = "[DEBUG] ";
break;
default:
prefix = "[LOG] ";
break;
}
void printk(char *text) {
#ifdef CONFIG_SIMPLE_FB #ifdef CONFIG_SIMPLE_FB
/* IMPORTANT: Limit the linecount */ // Actually the first line's Y pos. Scales in __simplefb_raw_print
if(debug_linecount > 100 || debug_linecount < 0) int y_pos = 5;
debug_linecount = 0; int prefix_width = strlen(prefix) * SCALED_FONTW;
draw_text((char*)CONFIG_FRAMEBUFFER_BASE, "[uniLoader] ", 0, (20 + (debug_linecount * 30)), CONFIG_FRAMEBUFFER_WIDTH, CONFIG_FRAMEBUFFER_STRIDE); __simplefb_raw_print((char*)CONFIG_FRAMEBUFFER_BASE, prefix, 0, y_pos,
draw_text((char*)CONFIG_FRAMEBUFFER_BASE, text, 0 + (12 * 8), (20 + (debug_linecount * 30)), CONFIG_FRAMEBUFFER_WIDTH, CONFIG_FRAMEBUFFER_STRIDE); CONFIG_FRAMEBUFFER_WIDTH, CONFIG_FRAMEBUFFER_STRIDE);
__simplefb_raw_print((char*)CONFIG_FRAMEBUFFER_BASE, text, prefix_width, y_pos,
debug_linecount++; CONFIG_FRAMEBUFFER_WIDTH, CONFIG_FRAMEBUFFER_STRIDE);
#endif #endif
} }

View File

@ -1,16 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */ // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> * Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
* Copyright (c) 2022, Markuss Broks <markuss.broks@gmail.com> * Copyright (c) 2022, Markuss Broks <markuss.broks@gmail.com>
* Copyright (c) 2022, Michael Srba <Michael.Srba@seznam.cz> * Copyright (c) 2022, Michael Srba <Michael.Srba@seznam.cz>
*/ */
#include <drivers/framework.h>
#include <lib/font.h>
#include <lib/simplefb.h>
#include <string.h>
/* volatile char */ #include <string.h>
static void clean_fb(void *fb, int width, int height, int stride) { #include <drivers/framework.h>
#include <lib/video/font.h>
#include <lib/simplefb.h>
static void clean_fbmem(void *fb, int width, int height, int stride)
{
memset(fb, 0x0, (width * height * stride)); memset(fb, 0x0, (width * height * stride));
} }
@ -19,7 +20,8 @@ static void clean_fb(void *fb, int width, int height, int stride) {
* Unlike ARGB8888, we explicitly use 3 bytes to represent each pixel, making sure * Unlike ARGB8888, we explicitly use 3 bytes to represent each pixel, making sure
* no extra padding byte is added. * no extra padding byte is added.
*/ */
static void draw_pixel(volatile char *fb, int x, int y, int width, int stride, color c) static void draw_pixel(volatile char *fb, int x, int y, int width, int stride,
color c)
{ {
long int location = (x * stride) + (y * width * stride); long int location = (x * stride) + (y * width * stride);
#ifdef CONFIG_FRAMEBUFFER_BGRA #ifdef CONFIG_FRAMEBUFFER_BGRA
@ -35,48 +37,54 @@ static void draw_pixel(volatile char *fb, int x, int y, int width, int stride, c
#endif #endif
} }
static void draw_horizontal_line(volatile char *fb, int x1, int x2, int y, color c, static int current_y = 0;
int width, int stride) void __simplefb_raw_print(volatile char *fb, char *text, int text_x, int text_y,
int width, int stride)
{ {
for (int i = x1; i < x2; i++)
draw_pixel(fb, i, y, width, stride, c);
}
static void draw_vertical_line(volatile char *fb, int x, int y1, int y2, color c,
int width, int stride)
{
for (int i = y1; i < y2; i++)
draw_pixel(fb, x, i, width, stride, c);
}
static void draw_filled_rectangle(volatile char *fb, int x1, int y1, int w, int h,
color c, int width, int stride)
{
for (int i = y1; i < (y1 + h); i++)
draw_horizontal_line(fb, x1, (x1 + w), i, c, width, stride);
}
void draw_text(volatile char *fb, char *text, int textX, int textY, int width, int stride)
{
// loop through all characters in the text string
int l = strlen(text); int l = strlen(text);
int current_x = text_x;
current_y = current_y == 0 ? text_y : current_y;
int max_x = width - SCALED_FONTW;
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
// Special characters handling
switch (text[i]) {
case '\n':
current_x = text_x;
current_y += SCALED_FONTH;
break;
}
// Non-printable chars
if (text[i] < 32) if (text[i] < 32)
continue; continue;
int ix = font_index(text[i]); if (current_x > max_x) {
unsigned char *img = letters[ix]; current_x = text_x;
current_y += SCALED_FONTH;
}
int ix = font_index(text[i]);
const unsigned char *img = letters[ix];
// Draw the character as a scaled bitmap
for (int y = 0; y < FONTH; y++) { for (int y = 0; y < FONTH; y++) {
unsigned char b = img[y]; unsigned char b = img[y];
for (int x = 0; x < FONTW; x++) { for (int x = 0; x < FONTW; x++) {
if (((b << x) & 0b10000000) > 0) if (((b << x) & 0b10000000) > 0) {
draw_pixel(fb, textX + i * FONTW + x, textY + y, width, for (int dy = 0; dy < SCALE_FACTOR; dy++) {
stride, (color){255, 255, 255}); for (int dx = 0; dx < SCALE_FACTOR; dx++) {
draw_pixel(fb, current_x + x * SCALE_FACTOR + dx,
current_y + y * SCALE_FACTOR + dy,
width, stride, (color){255, 255, 255});
}
}
}
} }
} }
current_x += SCALED_FONTW;
} }
} }
@ -84,7 +92,7 @@ void simplefb_probe(void *data)
{ {
struct video *fb_info = data; struct video *fb_info = data;
clean_fb((char*)fb_info->address, fb_info->width, fb_info->height, clean_fbmem((char*)fb_info->address, fb_info->width, fb_info->height,
fb_info->stride); fb_info->stride);
/* TODO: Introduce a full drivers framework that allows proper exiting */ /* TODO: Introduce a full drivers framework that allows proper exiting */

4490
lib/video/font.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */ // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> * Copyright (c) 2022, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
*/ */
@ -6,6 +6,7 @@
#include <board.h> #include <board.h>
#include <main.h> #include <main.h>
#include <string.h> #include <string.h>
#include <lib/debug.h>
/* /*
* Provide an empty board config that has * Provide an empty board config that has
@ -31,15 +32,23 @@ void main(void* dt, void* kernel)
EXECUTE_BOARD_OP(board.ops[BOARD_OP_DRIVER_SETUP]); EXECUTE_BOARD_OP(board.ops[BOARD_OP_DRIVER_SETUP]);
EXECUTE_BOARD_OP(board.ops[BOARD_OP_LATE_INIT]); EXECUTE_BOARD_OP(board.ops[BOARD_OP_LATE_INIT]);
printk("Passed board initialization!"); printk(-1, " .__.____ .___\n");
printk("Welcome to uniLoader!"); printk(-1, " __ __ ____ |__| | _________ __| _/___________\n");
printk(-1, "| | \\/ \\| | | / _ \\__ \\ / __ |/ __ \\_ __\\\n");
printk(-1, "| | / | \\ | |__( <_> ) __ \\_/ /_/ \\ ___/| |\\/\n");
printk(-1, "|____/|___| /__|_______ \\____(____ /\\____ |\\___ >__|\n");
printk(-1, " \\/ \\/ \\/ \\/ \\/\n");
printk(-1, "Passed board initialization!\n");
printk(-1, "Welcome to uniLoader!\n");
/* Copy kernel to memory and boot */ /* Copy kernel to memory and boot */
printk("Booting linux..."); printk(-1, "Booting linux...\n");
memcpy((void*)CONFIG_PAYLOAD_ENTRY, kernel, (unsigned long) &kernel_size); memcpy((void*)CONFIG_PAYLOAD_ENTRY, kernel, (unsigned long) &kernel_size);
load_kernel(dt, 0, 0, 0, (void*)CONFIG_PAYLOAD_ENTRY); load_kernel(dt, 0, 0, 0, (void*)CONFIG_PAYLOAD_ENTRY);
/* We shouldn't get there */ /* We shouldn't get there */
printk(KERN_WARNING, "Something wrong happened, we shouldn't be here. Hanging....\n");
while(1) {} while(1) {}
} }