Hello, world! in linear framebuffer
This commit is contained in:
6
Makefile
6
Makefile
@@ -1,6 +1,7 @@
|
|||||||
build:
|
build:
|
||||||
rm -f *.o
|
rm -f *.o
|
||||||
x86_64-elf-gcc -c -I src src/kmain.c -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections
|
x86_64-elf-gcc -c -I src src/term.c src/kmain.c -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel
|
||||||
|
objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o
|
||||||
x86_64-elf-ld -o kernel -T linker.ld *.o
|
x86_64-elf-ld -o kernel -T linker.ld *.o
|
||||||
|
|
||||||
limine/limine:
|
limine/limine:
|
||||||
@@ -25,5 +26,8 @@ build-iso: limine/limine build
|
|||||||
iso_root -o kernel.iso
|
iso_root -o kernel.iso
|
||||||
./limine/limine bios-install kernel.iso
|
./limine/limine bios-install kernel.iso
|
||||||
|
|
||||||
|
run:
|
||||||
|
qemu-system-x86_64 -cdrom kernel.iso
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf *.o kernel iso_root kernel.iso limine
|
rm -rf *.o kernel iso_root kernel.iso limine
|
||||||
|
|||||||
@@ -9,3 +9,10 @@ make build-iso
|
|||||||
```
|
```
|
||||||
|
|
||||||
Then it can be run with `qemu-system-x86_64 kernel.iso`.
|
Then it can be run with `qemu-system-x86_64 kernel.iso`.
|
||||||
|
|
||||||
|
|
||||||
|
### Kernel conventions
|
||||||
|
|
||||||
|
Functions that return an integer as status of success/failure will return:
|
||||||
|
- 0 if everything went correctly
|
||||||
|
- a negative value if something went wrong
|
||||||
|
|||||||
9
src/kernel.h
Normal file
9
src/kernel.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef KERNEL_H
|
||||||
|
#define KERNEL_H
|
||||||
|
|
||||||
|
enum ErrorCodes
|
||||||
|
{
|
||||||
|
ENOMEM
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
13
src/kmain.c
13
src/kmain.c
@@ -1,6 +1,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
|
#include "term.h"
|
||||||
|
|
||||||
// Limine version used
|
// Limine version used
|
||||||
__attribute__((used, section(".limine_requests")))
|
__attribute__((used, section(".limine_requests")))
|
||||||
@@ -19,6 +20,8 @@ static volatile LIMINE_REQUESTS_START_MARKER;
|
|||||||
__attribute__((used, section(".limine_requests_end")))
|
__attribute__((used, section(".limine_requests_end")))
|
||||||
static volatile LIMINE_REQUESTS_END_MARKER;
|
static volatile LIMINE_REQUESTS_END_MARKER;
|
||||||
|
|
||||||
|
struct limine_framebuffer* framebuffer;
|
||||||
|
|
||||||
// We won't be linked to standard library, but still need the basic mem* functions
|
// We won't be linked to standard library, but still need the basic mem* functions
|
||||||
// so everything goes allright with the compiler
|
// so everything goes allright with the compiler
|
||||||
|
|
||||||
@@ -103,14 +106,12 @@ void kmain()
|
|||||||
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) hcf();
|
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) hcf();
|
||||||
|
|
||||||
// Get the first framebuffer from the response
|
// Get the first framebuffer from the response
|
||||||
struct limine_framebuffer* framebuffer = framebuffer_request.response->framebuffers[0];
|
framebuffer = framebuffer_request.response->framebuffers[0];
|
||||||
|
|
||||||
|
if (term_init()) hcf();
|
||||||
|
|
||||||
// Draw something
|
// Draw something
|
||||||
for (size_t i=0; i<100; i++)
|
kputs("Hello, world!");
|
||||||
{
|
|
||||||
volatile uint32_t* fb_ptr = framebuffer->address;
|
|
||||||
fb_ptr[i*(framebuffer->pitch/4) + i] = 0xffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
|
|||||||
99
src/term.c
Normal file
99
src/term.c
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Terminal output
|
||||||
|
|
||||||
|
#include <limine.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "term.h"
|
||||||
|
|
||||||
|
extern struct limine_framebuffer* framebuffer;
|
||||||
|
|
||||||
|
// Importing the PSF object file
|
||||||
|
extern unsigned char _binary_zap_light16_psf_start[];
|
||||||
|
extern unsigned char _binary_zap_light16_psf_end[];
|
||||||
|
|
||||||
|
PSF1_Header* font = (PSF1_Header*)_binary_zap_light16_psf_start;
|
||||||
|
uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header);
|
||||||
|
|
||||||
|
#define FONT_WIDTH 8
|
||||||
|
#define FONT_HEIGHT font->characterSize
|
||||||
|
|
||||||
|
// Character cursor
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int x;
|
||||||
|
unsigned int y;
|
||||||
|
} Cursor;
|
||||||
|
|
||||||
|
Cursor cursor = {0};
|
||||||
|
|
||||||
|
unsigned char* fb;
|
||||||
|
|
||||||
|
int term_init()
|
||||||
|
{
|
||||||
|
// Get framebuffer address from Limine struct
|
||||||
|
|
||||||
|
if (framebuffer)
|
||||||
|
{
|
||||||
|
fb = framebuffer->address;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are marked "static" because we don't wanna expose them all around
|
||||||
|
// AKA they should just be seen here (kind of like private functions in cpp)
|
||||||
|
static void putpixel(int x, int y, int color)
|
||||||
|
{
|
||||||
|
// Depth isn't part of limine_framebuffer attributes so it will be 4
|
||||||
|
unsigned pos = x*4 + y*framebuffer->pitch;
|
||||||
|
fb[pos] = color & 255; // blue channel
|
||||||
|
fb[pos+1] = (color >> 8) & 255; // green
|
||||||
|
fb[pos+2] = (color >> 16) & 255; // blue
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_char(char c, int px, int py, int fg, int bg)
|
||||||
|
{
|
||||||
|
uint8_t* glyph = glyphs + ((unsigned char)c * FONT_HEIGHT);
|
||||||
|
|
||||||
|
for (size_t y=0; y<FONT_HEIGHT; y++)
|
||||||
|
{
|
||||||
|
uint8_t row = glyph[y];
|
||||||
|
for (size_t x=0; x<8; x++)
|
||||||
|
{
|
||||||
|
int color = (row & (0x80 >> x)) ? fg : bg;
|
||||||
|
putpixel(px+x, py+y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void putchar(char c)
|
||||||
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
cursor.x = 0;
|
||||||
|
cursor.y++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cursor.x+1)*FONT_WIDTH >= framebuffer->width)
|
||||||
|
{
|
||||||
|
cursor.x = 0;
|
||||||
|
cursor.y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int px = cursor.x * FONT_WIDTH;
|
||||||
|
int py = cursor.y * FONT_HEIGHT;
|
||||||
|
draw_char(c, px, py, WHITE, BLACK);
|
||||||
|
cursor.x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug-printing
|
||||||
|
void kputs(const char* str)
|
||||||
|
{
|
||||||
|
unsigned int i=0;
|
||||||
|
while (str[i] != 0)
|
||||||
|
{
|
||||||
|
putchar(str[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/term.h
Normal file
22
src/term.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef TERM_H
|
||||||
|
#define TERM_H
|
||||||
|
|
||||||
|
int term_init();
|
||||||
|
void kputs(const char* str);
|
||||||
|
|
||||||
|
enum TermColors
|
||||||
|
{
|
||||||
|
BLACK = 0x000000,
|
||||||
|
WHITE = 0xffffff
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PSF1_FONT_MAGIC 0x0436
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t magic;
|
||||||
|
uint8_t fontMode;
|
||||||
|
uint8_t characterSize; // height
|
||||||
|
} PSF1_Header;
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
zap-light16.psf
Normal file
BIN
zap-light16.psf
Normal file
Binary file not shown.
Reference in New Issue
Block a user