vxBoot - 0.1.0 : First version

@add
<> builtin/loader : add "ld" builtin command
<> loader/entry : add gintrace support to potentially trace an operating system
<> loader/entry : add "image" dump generation in the SMEM

@update
<> builtin/hw : isolate hardware interaction
<> fs/smemfs/pread : change long function name formalism
<> loader/elf/entry : isolate hardware interaction
<> terminal/read : if not cursor time is available, force-display the cursor
<> terminal/util : change complex C semantic abuse

@fix:
<> loader/elf/image : check the available RAM size before load the image
<> loader/elf/image : use non-cacheable area address to load the image
<> loader/elf/image : use cacheable area address for the "entry" address generation
<> loader/elf/entry : display appropriate error string if needed
<> terminal/open : reduce buffer size
<> terminal/open : enable cursor blink only if the device is not an emulator
<> terminal/read : add "mutex" for the display
<> terminal/read : sign comparison
This commit is contained in:
Yann MAGNIN 2021-12-18 13:52:13 +01:00
parent d4d9c68005
commit f90c07132a
17 changed files with 282 additions and 82 deletions

View File

@ -19,11 +19,13 @@ set(SOURCES
src/builtin/ls.c
src/builtin/help.c
src/builtin/hw.c
src/builtin/loader.c
src/loader/scan.c
src/loader/elf/header.c
src/loader/elf/image.c
src/loader/error.c
src/loader/scan.c
src/loader/entry.c
src/hardware/get_info.c
)
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
set(ASSETS
@ -41,12 +43,13 @@ fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
add_executable(vxBoot ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
target_compile_options(vxBoot PRIVATE -Wall -Wextra -Os)
target_include_directories(vxBoot PRIVATE include/)
target_link_libraries(vxBoot Gint::Gint)
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
target_link_libraries(vxBoot -lgintrace-fx Gint::Gint)
generate_g1a(TARGET vxBoot OUTPUT "vxBoot.g1a"
NAME "vxBoot" ICON assets-fx/icon.png)
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
target_link_libraries(vxBoot -lgintrace-cg Gint::Gint)
generate_g3a(TARGET vxBoot OUTPUT "vxBoot.g3a"
NAME "vxBoot" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png)
endif()

View File

@ -7,6 +7,7 @@
extern int ls_main(int argc, char **argv);
extern int os_main(int argc, char **argv);
extern int hw_main(int argc, char **argv);
extern int ld_main(int argc, char **argv);
extern int help_main(int argc, char **argv);
#endif /*__VXBOOT_BUILTIN_H__*/

View File

@ -44,8 +44,12 @@ extern struct smemfs_superblock smemfs_superblock;
//---
extern struct smemfs_inode *smemfs_mount(void);
extern ssize_t smemfs_pread(struct smemfs_inode *inode,
void *buf, size_t count, off_t pos);
extern ssize_t smemfs_pread(
struct smemfs_inode const * restrict const inode,
void *buf,
size_t count,
off_t pos
);
extern struct smemfs_inode *smemfs_alloc_inode(void);

View File

@ -1,6 +1,9 @@
#ifndef __VXBOOT_HARDWARE_H__
# define __VXBOOT_HARDWARE_H__
#include <stdint.h>
#include <stddef.h>
/* define hardware information struct */
struct hwinfo {
struct {
@ -9,6 +12,7 @@ struct hwinfo {
uintptr_t user_addr;
} physical;
size_t size;
size_t available;
} ram;
};
@ -17,7 +21,7 @@ struct hwinfo {
//---
/* hardware_get_info() : get hardware information */
extern void hardware_get_info(struct hwinfo * const hwinfo);
extern int hardware_get_info(struct hwinfo * const hwinfo);
#endif /*__VXBOOT_HARDWARE_H__*/

View File

@ -4,6 +4,7 @@
#include <stddef.h>
#include <stdint.h>
#include "vxBoot/hardware.h"
#include "vxBoot/fs/smemfs.h"
//---
// ELF struct definition
@ -114,7 +115,10 @@ struct ldimg {
extern int loader_scan(void);
/* loader() : try to load a ELF PIE file */
extern int loader(struct smemfs_inode const * restrict const inode);
#define LOADER_DEFAULT 0
#define LOADER_DUMP 1
#define LOADER_TRACE 2
extern int loader(struct smemfs_inode const * restrict const inode, int mode);
//---
@ -146,7 +150,7 @@ enum {
};
/* loader_header_get() : get / check ELF header information */
extern int loader_header_get(
struct smemfs_inode * restrict const inode,
struct smemfs_inode const * restrict const inode,
Elf32_Ehdr *hdr
);
/* loader_header_check() : load and check the file header validity */
@ -160,15 +164,16 @@ extern int loader_header_error(int errnum);
// ELF image ldpers
//---
enum {
ld_image_success = 0,
ld_image_size_error = -1,
ld_image_type_error = -2,
ld_image_mem_error = -3,
ld_image_success = 0,
ld_image_size_error = -1,
ld_image_type_error = -2,
ld_image_mem_error = -3,
ld_image_mem_not_available = -4,
};
/* loader_image_load() : try to load the entier image data */
extern int loader_image_load(
struct smemfs_inode const * restrict const inode,
struct kernel_info * restrict const info,
struct smemfs_inode * restrict const inode,
Elf32_Ehdr *hdr
);
extern int loader_image_error(int const errnum);

View File

@ -7,7 +7,7 @@
/* internal terminal hardcoded information */
#define TERM_PRIVATE_WATERMARK (0xdeadbeef)
#define TERM_RDBUFFER_NBLINE (32)
#define TERM_BUFFER_NB_FRAME (2)
/* hardcoded font size (TODO: dynamic !) */
#ifdef FXCG50

View File

@ -1,42 +1,27 @@
#include "vxBoot/builtin.h"
#include "vxBoot/terminal.h"
#include "vxBoot/hardware.h"
#include <gint/mmu.h>
static ptrdiff_t __ram_get_size(uintptr_t start_ram)
{
volatile uint32_t *ptr = (void*)start_ram;
volatile uint32_t *tst = (void*)start_ram;
uint32_t backup;
//TODO: use UTLB page size information
while (1) {
ptr = &ptr[4096];
backup = ptr[0];
ptr[0] = 0xdeadbeef;
if (ptr[0] == tst[0]) break;
ptr[0] = backup;
}
ptr[0] = backup;
return ((ptrdiff_t)((uintptr_t)ptr - (uintptr_t)tst));
}
/* hw_main() : hw builtin entry */
int hw_main(int argc, char **argv)
{
struct hwinfo hwinfo;
//TODO handle args
(void)argc;
(void)argv;
uintptr_t uram = mmu_translate(0x08100000, NULL);
uintptr_t bram = uram & 0xff000000;
terminal_write("user RAM physical addr: %p\n", uram);
terminal_write("RAM physical addr: %p\n", bram);
terminal_write("RAM size: ");
uintptr_t size = __ram_get_size((uram & 0xff000000) | 0xa0000000);
terminal_write("%d bytes\n", size);
terminal_write("kernel RAM space: %d o\n", size - (uram & 0x00ffffff));
hardware_get_info(&hwinfo);
terminal_write(
"- user RAM physical addr: %p\n"
"- RAM physical addr: %p\n"
"- RAM size: %d\n"
"- Kernel RAM space: %d o\n",
hwinfo.ram.physical.user_addr,
hwinfo.ram.physical.origin_addr,
hwinfo.ram.size,
hwinfo.ram.available
);
return (0);
}

62
src/builtin/loader.c Normal file
View File

@ -0,0 +1,62 @@
#include "vxBoot/builtin.h"
#include "vxBoot/terminal.h"
#include "vxBoot/loader.h"
#include <stdlib.h>
#include <string.h>
int ld_main(int argc, char **argv)
{
extern struct ldimg *kernel_img_list;
char const *path;
struct ldimg *img;
char *endptr;
int counter;
int mode;
int idx;
if (argc >= 4) {
terminal_write(
"too much argument, ony the kernel ID is needed\n"
);
return (84);
}
if (argc == 1) {
if (kernel_img_list == NULL) {
terminal_write(
"no kernel found in you storage memroy :(\n"
);
return (0);
}
counter = 0;
img = kernel_img_list;
while (img != NULL) {
terminal_write("[%d] %s\n", counter, img->inode->name);
img = img->next;
counter += 1;
}
return (0);
}
path = argv[1];
mode = LOADER_DEFAULT;
if (strcmp(argv[1], "dump") == 0) {
path = argv[2];
mode = LOADER_DUMP;
}
if (strcmp(argv[1], "trace") == 0) {
path = argv[2];
mode = LOADER_TRACE;
}
img = kernel_img_list;
idx = strtol(path, &endptr, 10) + 1;
if (endptr == NULL || endptr[0] != '\0') {
terminal_write("kernel ID is not valid\n");
return (84);
}
while (img != NULL && --idx > 0) { img = img->next; }
if (img == NULL) {
terminal_write("kernel ID '%d' does not exist :(\n");
return (84);
}
return (loader(img->inode, mode));
}

View File

@ -17,9 +17,11 @@ struct __file_info {
This function will generate the absolute path of a file because Casio's open
primitive doesn't handle cannonical path */
static void generate_absolute_path(uint16_t *pathname,
struct smemfs_inode *inode, int *pos)
{
static void generate_absolute_path(
uint16_t *pathname,
struct smemfs_inode const * restrict const inode,
int *pos
) {
if (inode == NULL) {
memcpy(pathname, u"\\\\fls0", 12);
*pos = 6;
@ -51,9 +53,12 @@ static void __smemfs_pread(struct __file_info *info, ssize_t *read)
}
/* smemfs_read(): Read primitive */
ssize_t smemfs_pread(struct smemfs_inode *inode,
void *buf, size_t count, off_t pos)
{
ssize_t smemfs_pread(
struct smemfs_inode const * restrict const inode,
void *buf,
size_t count,
off_t pos
) {
struct __file_info file_info = {
.buf = buf,
.count = count,

37
src/hardware/get_info.c Normal file
View File

@ -0,0 +1,37 @@
#include "vxBoot/hardware.h"
#include <gint/mmu.h>
/* __ram_get_size() : try to determine the RAM size */
static ptrdiff_t __ram_get_size(uintptr_t start_ram)
{
volatile uint32_t *ptr = (void*)start_ram;
volatile uint32_t *tst = (void*)start_ram;
uint32_t backup;
//TODO: use UTLB page size information to walk through each pages
while (1) {
ptr = &ptr[4096];
backup = ptr[0];
ptr[0] = 0xdeadbeef;
if (ptr[0] != 0xdeadbeef || ptr[0] == tst[0]) break;
ptr[0] = backup;
}
ptr[0] = backup;
return ((ptrdiff_t)((uintptr_t)ptr - (uintptr_t)tst));
}
/* hardware_get_info() : get hardware information */
int hardware_get_info(struct hwinfo * const hwinfo)
{
if (hwinfo == NULL)
return (-1);
uintptr_t uram = mmu_translate(0x08100000, NULL);
hwinfo->ram.physical.origin_addr = uram & 0xff000000;
hwinfo->ram.physical.user_addr = uram;
hwinfo->ram.size = __ram_get_size(uram | 0xa0000000);
hwinfo->ram.available = hwinfo->ram.size - (uram & 0x00ffffff);
return (0);
}

View File

@ -23,7 +23,7 @@ int loader_header_error(int const errnum)
/* loader_header_get(): Get ELF header and check validity */
int loader_header_get(
struct smemfs_inode * restrict const inode,
struct smemfs_inode const * restrict const inode,
Elf32_Ehdr *header
) {
/* try to read the ELF header */

View File

@ -10,6 +10,7 @@ const struct ld_error_db image_error_db[] = {
{.id = ld_image_size_error, .strerror = "size error"},
{.id = ld_image_type_error, .strerror = "type error"},
{.id = ld_image_mem_error, .strerror = "out of memory error"},
{.id = ld_image_mem_not_available, .strerror = "memory not available"},
{.id = 0xdeb0cad0, .strerror = NULL},
};
@ -21,12 +22,13 @@ int loader_image_error(int const errnum)
/* loader_load_image() - Load the program into Virtual Memory */
int loader_image_load(
struct smemfs_inode const * restrict const inode,
struct kernel_info * restrict const kernel,
struct smemfs_inode * restrict const inode,
Elf32_Ehdr *hdr
) {
Elf32_Phdr program;
uintptr_t paddress;
uintptr_t origin;
uintptr_t vmin;
uintptr_t vmax;
off_t offset;
@ -54,10 +56,14 @@ int loader_image_load(
kernel->memory.program.elf.vmin = vmin;
kernel->memory.program.elf.vmax = vmax;
/* Allocate programe memory */
kernel->memory.program.start = calloc(1, kernel->memory.program.size);
if (kernel->memory.program.start == NULL)
return (ld_image_mem_error);
/* check available space in RAM to load the image */
if (kernel->memory.program.size >= kernel->hardware.ram.available)
return (ld_image_mem_not_available);
/* set the kernel's origin address */
origin = kernel->hardware.ram.physical.user_addr;
origin |= 0xa0000000;
kernel->memory.program.start = (void*)origin;
/* Now, load all program section into physical memory. To do this, we
read each program hdr, generate the "real" physical address of
@ -84,6 +90,7 @@ int loader_image_load(
/* Generate program entry address */
kernel->entry = (uintptr_t)hdr->e_entry - vmin;
kernel->entry += (uintptr_t)kernel->memory.program.start;
kernel->entry += (uintptr_t)kernel->hardware.ram.physical.user_addr;
kernel->entry |= (uintptr_t)0x80000000;
return (ld_image_success);
}

View File

@ -3,10 +3,34 @@
#include "vxBoot/hardware.h"
#include "vxBoot/loader.h"
/* loader_inode: Load a ELF programm (PIE) */
int loader_inode(struct smemfs_inode const * restrict const inode)
#include <gint/gint.h>
#include <gint/bfile.h>
//#include <gintrace/tracer.h>
#include <string.h>
static int dump_reloc(struct kernel_info *kernel)
{
struct hwinfo hwinfo;
int handle;
int size;
size = kernel->memory.program.size + 1;
BFile_Remove(u"\\\\fls0\\reloc_dump.s");
BFile_Create(u"\\\\fls0\\reloc_dump.s", BFile_File, &size);
handle = BFile_Open(u"\\\\fls0\\reloc_dump.s", BFile_WriteOnly);
BFile_Write(
handle,
(void*)kernel->memory.program.start,
kernel->memory.program.size
);
return (0);
}
/* loader_inode: Load a ELF programm (PIE) */
int loader(struct smemfs_inode const * restrict const inode, int mode)
{
struct kernel_info kernel;
Elf32_Ehdr header;
int err;
@ -17,16 +41,53 @@ int loader_inode(struct smemfs_inode const * restrict const inode)
terminal_write("- check header information...\n");
err = loader_header_get(inode, &header);
if (err != 0)
if (err != 0) {
loader_header_error(err);
return (-2);
}
terminal_write("- fetch hardware information...\n");
hardware_get_info(&hwinfo);
terminal_write("- generate kernel geometry...\n");
memset(&kernel, 0x00, sizeof(struct kernel_info));
hardware_get_info(&kernel.hardware);
terminal_write("- load image...\n");
err = loader_image_load(&hwinfo, inode, &header);
if (err != 0)
err = loader_image_load(inode, &kernel, &header);
if (err != 0) {
loader_image_error(err);
return (-3);
}
terminal_write("image successfully loaded !\n");
if (mode == LOADER_DUMP) {
terminal_write(
"kernel information:\n"
"|-- kernel entry: %p\n"
"`-- memory:\n"
" `-- program:\n"
" |-- start: %p\n"
" |-- size: %do\n"
" `-- elf:\n"
" |-- vmin: %p\n"
" `-- vmax: %p\n",
kernel.entry,
kernel.memory.program.start,
kernel.memory.program.size,
kernel.memory.program.elf.vmin,
kernel.memory.program.elf.vmax
);
gint_world_switch(GINT_CALL((void*)&dump_reloc, (void*)&kernel));
return (0);
}
#if 0
if (mode == LOADER_TRACE) {
struct tsession *session;
session = tracer_create_session(
(void*)kernel.entry,
TRACER_DISASM | TRACER_CONTEXT | TRACER_HEXDUMP
);
tracer_set_session(session);
}
#endif
gint_world_switch(GINT_CALL((void*)kernel.entry));
return (0);
}

View File

@ -17,7 +17,7 @@ struct {
int (*f)(int argc, char **argv);
} cmd_list[] = {
{.name = "ls", &ls_main},
{.name = "os", NULL},
{.name = "ld", &ld_main},
{.name = "hw", &hw_main},
{.name = "help", &help_main},
{.name = NULL, NULL}

View File

@ -24,21 +24,24 @@ int terminal_open(void)
terminal.winsize.ws_row = DHEIGHT / terminal.winsize.ft_ypixel;
terminal.buffer.size = terminal.winsize.ws_row
* terminal.winsize.ws_col
* TERM_RDBUFFER_NBLINE
* TERM_BUFFER_NB_FRAME
* sizeof(uint8_t);
terminal.buffer.data = calloc(1, terminal.buffer.size);
if (terminal.buffer.data == NULL) {
terminal_close();
return (-1);
}
terminal.private.timer.id = timer_configure(
TIMER_ANY,
250000,
GINT_CALL(terminal_cursor_handler)
);
if (terminal.private.timer.id < 0) {
terminal_close();
return (-1);
/* workaround to disable cursor blink only in FXCG-Manager (emulator) */
if (*(volatile uint32_t *)0xff000044 != 0x00000000) {
terminal.private.timer.id = timer_configure(
TIMER_ANY,
250000,
GINT_CALL(terminal_cursor_handler)
);
if (terminal.private.timer.id < 0) {
terminal_close();
return (-1);
}
}
terminal.private.color.bg = C_BLACK;
terminal.private.color.fg = C_WHITE;

View File

@ -3,6 +3,7 @@
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/timer.h>
#include <gint/cpu.h>
#include <string.h>
@ -34,6 +35,17 @@ struct {
//---
void term_display_all(void)
{
static int __lock = 0;
/* ugly workaround to avoid race condition with the timer */
cpu_atomic_start();
if (__lock != 0) {
cpu_atomic_end();
return;
}
__lock = 1;
cpu_atomic_end();
/* stop the timer too avoid interrupt-loop */
if (terminal.private.timer.id >= 0)
timer_pause(terminal.private.timer.id);
@ -60,6 +72,9 @@ void term_display_all(void)
/* restart the timer */
if (terminal.private.timer.id >= 0)
timer_start(terminal.private.timer.id);
/* workaround end */
__lock = 0;
}
//---
@ -84,7 +99,7 @@ static void term_buffer_remove(void)
if (term_rdinfo.buffer.cursor == 0)
return;
/* move data if needed */
if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) {
if (term_rdinfo.buffer.cursor < (int)term_rdinfo.buffer.size - 1) {
memcpy(
&term_rdinfo.buffer.data[term_rdinfo.buffer.cursor - 1],
&term_rdinfo.buffer.data[term_rdinfo.buffer.cursor],
@ -103,7 +118,7 @@ static int term_buffer_insert(char n)
if (term_rdinfo.buffer.size + 1 >= term_rdinfo.buffer.max)
return (-1);
/* move data if needed */
if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) {
if (term_rdinfo.buffer.cursor < (int)term_rdinfo.buffer.size - 1) {
off_t i = term_rdinfo.buffer.size + 1;
while (--i >= term_rdinfo.buffer.cursor) {
term_rdinfo.buffer.data[i] =
@ -144,7 +159,7 @@ static int term_key_handle_special(key_event_t key_event)
term_rdinfo.buffer.cursor -= 1;
return (1);
case KEY_RIGHT:
if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1)
if (term_rdinfo.buffer.cursor < (int)term_rdinfo.buffer.size - 1)
term_rdinfo.buffer.cursor += 1;
return (1);
default:
@ -216,6 +231,7 @@ int terminal_read(void *buffer, size_t nb)
memset(buffer, 0x00, nb);
/* save terminal information */
term_rdinfo.cursor.visible = 1;
term_rdinfo.cursor.saved = terminal.buffer.cursor;
term_rdinfo.cursor.x = terminal.cursor.x;
term_rdinfo.cursor.y = terminal.cursor.y;
@ -226,6 +242,8 @@ int terminal_read(void *buffer, size_t nb)
/* start cursor blink timer */
if (terminal.private.timer.id >= 0)
timer_start(terminal.private.timer.id);
else
term_display_all(); // force-display the cursor
/* keyboard handling */
while (term_rdinfo.mode.exit == 0) {

View File

@ -23,7 +23,7 @@ void terminal_buffer_insert(char *buffer, size_t nb)
start = &buffer[nb - dump];
}
/* dump the buffer (be carful with the circular effect) */
/* dump the buffer (be careful with the circular effect) */
if (terminal.buffer.cursor + dump > terminal.buffer.size) {
memcpy(
&terminal.buffer.data[terminal.buffer.cursor],
@ -101,7 +101,7 @@ static int terminal_line_discipline(char n)
void terminal_buffer_display(void)
{
uint8_t *buffer;
uint16_t tmp;
char tmp[2];
int cursor;
int x;
int y;
@ -112,6 +112,8 @@ void terminal_buffer_display(void)
terminal.cursor.x = 0;
terminal.cursor.y = 0;
i = terminal.buffer.cursor - 1;
if (i < 0)
i = terminal.buffer.size - 1;
buffer = &terminal.buffer.data[0];
while (1) {
/* decrease the cursor and avoid circular effect */
@ -136,6 +138,7 @@ void terminal_buffer_display(void)
/* Display character per character because we need to check special
behaviour (like cariege return, line feed, ...) */
tmp[1] = '\0';
terminal.cursor.x = 0;
terminal.cursor.y = 0;
while (1) {
@ -153,16 +156,18 @@ void terminal_buffer_display(void)
x = terminal.cursor.x * terminal.winsize.ft_xpixel;
y = terminal.cursor.y * terminal.winsize.ft_ypixel;
if (terminal_line_discipline(buffer[i]) == 0) {
tmp = buffer[i] << 8;
dtext(x, y, terminal.private.color.fg, (void*)&tmp);
tmp[0] = buffer[i];
dtext(x, y, terminal.private.color.fg, tmp);
terminal_horizontal_update();
}
if (cursor != 0) {
dline(x,
dline(
x,
y + terminal.winsize.ft_ypixel,
x + terminal.winsize.ft_xpixel - 2,
y + terminal.winsize.ft_ypixel,
terminal.private.color.fg);
terminal.private.color.fg
);
}
}
}