Separate stivale tty code
This commit is contained in:
parent
dc360b9d95
commit
94e9aced54
4 changed files with 153 additions and 134 deletions
11
Makefile
11
Makefile
|
@ -43,10 +43,12 @@ INTERNALLDFLAGS := \
|
|||
-nostdlib \
|
||||
-zmax-page-size=0x1000 \
|
||||
-static
|
||||
|
||||
CFILES := $(wildcard $(SRC_DIR)/*.c)
|
||||
OBJ := $(BUILD_DIR)/$(notdir $(CFILES:.c=.o))
|
||||
HEADER_DEPS := $(BUILD_DIR)/$(notdir $(CFILES:.c=.d))
|
||||
|
||||
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
|
||||
|
||||
CFILES := $(shell find ./$(SRC_DIR) -type f -name '*.c')
|
||||
OBJ := $(subst $(SRC_DIR),$(BUILD_DIR),$(CFILES:.c=.o))
|
||||
HEADER_DEPS := $(OBJ:.o=.d))
|
||||
|
||||
.PHONY: all
|
||||
all: $(KERNEL)
|
||||
|
@ -56,6 +58,7 @@ $(KERNEL): $(OBJ) | $(BIN_DIR)
|
|||
|
||||
-include $(HEADER_DEPS)
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) $(INTERNALCFLAGS) -c $< -o $@
|
||||
|
||||
# create directories if they don't exist
|
||||
|
|
140
src/boot/stivale/stivale.c
Normal file
140
src/boot/stivale/stivale.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stivale2.h>
|
||||
|
||||
// We need to tell the stivale bootloader where we want our stack to be.
|
||||
// We are going to allocate our stack as an array in .bss.
|
||||
static uint8_t stack[8192];
|
||||
|
||||
// stivale2 uses a linked list of tags for both communicating TO the
|
||||
// bootloader, or receiving info FROM it. More information about these tags
|
||||
// is found in the stivale2 specification.
|
||||
|
||||
// stivale2 offers a runtime terminal service which can be ditched at any
|
||||
// time, but it provides an easy way to print out to graphical terminal,
|
||||
// especially during early boot.
|
||||
// Read the notes about the requirements for using this feature below this
|
||||
// code block.
|
||||
static struct stivale2_header_tag_terminal terminal_hdr_tag = {
|
||||
// All tags need to begin with an identifier and a pointer to the next tag.
|
||||
.tag = {
|
||||
// Identification constant defined in stivale2.h and the specification.
|
||||
.identifier = STIVALE2_HEADER_TAG_TERMINAL_ID,
|
||||
// If next is 0, it marks the end of the linked list of header tags.
|
||||
.next = 0
|
||||
},
|
||||
// The terminal header tag possesses a flags field, leave it as 0 for now
|
||||
// as it is unused.
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
// We are now going to define a framebuffer header tag.
|
||||
// This tag tells the bootloader that we want a graphical framebuffer instead
|
||||
// of a CGA-compatible text mode. Omitting this tag will make the bootloader
|
||||
// default to text mode, if available.
|
||||
static struct stivale2_header_tag_framebuffer framebuffer_hdr_tag = {
|
||||
// Same as above.
|
||||
.tag = {
|
||||
.identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID,
|
||||
// Instead of 0, we now point to the previous header tag. The order in
|
||||
// which header tags are linked does not matter.
|
||||
.next = (uint64_t)&terminal_hdr_tag
|
||||
},
|
||||
// We set all the framebuffer specifics to 0 as we want the bootloader
|
||||
// to pick the best it can.
|
||||
.framebuffer_width = 0,
|
||||
.framebuffer_height = 0,
|
||||
.framebuffer_bpp = 0
|
||||
};
|
||||
|
||||
// The stivale2 specification says we need to define a "header structure".
|
||||
// This structure needs to reside in the .stivale2hdr ELF section in order
|
||||
// for the bootloader to find it. We use this __attribute__ directive to
|
||||
// tell the compiler to put the following structure in said section.
|
||||
__attribute__((section(".stivale2hdr"), used))
|
||||
static struct stivale2_header stivale_hdr = {
|
||||
// The entry_point member is used to specify an alternative entry
|
||||
// point that the bootloader should jump to instead of the executable's
|
||||
// ELF entry point. We do not care about that so we leave it zeroed.
|
||||
.entry_point = 0,
|
||||
// Let's tell the bootloader where our stack is.
|
||||
// We need to add the sizeof(stack) since in x86(_64) the stack grows
|
||||
// downwards.
|
||||
.stack = (uintptr_t)stack + sizeof(stack),
|
||||
// Bit 1, if set, causes the bootloader to return to us pointers in the
|
||||
// higher half, which we likely want since this is a higher half kernel.
|
||||
// Bit 2, if set, tells the bootloader to enable protected memory ranges,
|
||||
// that is, to respect the ELF PHDR mandated permissions for the executable's
|
||||
// segments.
|
||||
// Bit 3, if set, enables fully virtual kernel mappings, which we want as
|
||||
// they allow the bootloader to pick whichever *physical* memory address is
|
||||
// available to load the kernel, rather than relying on us telling it where
|
||||
// to load it.
|
||||
// Bit 4 disables a deprecated feature and should always be set.
|
||||
.flags = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4),
|
||||
// This header structure is the root of the linked list of header tags and
|
||||
// points to the first one in the linked list.
|
||||
.tags = (uintptr_t)&framebuffer_hdr_tag
|
||||
};
|
||||
|
||||
// We will now write a helper function which will allow us to scan for tags
|
||||
// that we want FROM the bootloader (structure tags).
|
||||
void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id) {
|
||||
struct stivale2_tag *current_tag = (void *)stivale2_struct->tags;
|
||||
for (;;) {
|
||||
// If the tag pointer is NULL (end of linked list), we did not find
|
||||
// the tag. Return NULL to signal this.
|
||||
if (current_tag == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check whether the identifier matches. If it does, return a pointer
|
||||
// to the matching tag.
|
||||
if (current_tag->identifier == id) {
|
||||
return current_tag;
|
||||
}
|
||||
|
||||
// Get a pointer to the next tag in the linked list and repeat.
|
||||
current_tag = (void *)current_tag->next;
|
||||
}
|
||||
}
|
||||
|
||||
struct stivale2_struct_tag_terminal *term_str_tag = NULL;
|
||||
void *term_write_ptr = NULL;
|
||||
void (*term_write)(const char *string, size_t length) = NULL;
|
||||
|
||||
// The following will be our kernel's entry point.
|
||||
void _start(struct stivale2_struct *stivale2_struct) {
|
||||
// Let's get the terminal structure tag from the bootloader.
|
||||
term_str_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_TERMINAL_ID);
|
||||
|
||||
// Check if the tag was actually found.
|
||||
if (term_str_tag == NULL) {
|
||||
// It wasn't found, just hang...
|
||||
for (;;) {
|
||||
asm ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
kernel_main();
|
||||
|
||||
// We're done, just hang...
|
||||
for (;;) {
|
||||
asm ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void terminal_initialize() {
|
||||
// stub for stivale
|
||||
// Let's get the address of the terminal write function.
|
||||
term_write_ptr = (void *)term_str_tag->term_write;
|
||||
|
||||
// Now, let's assign this pointer to a function pointer which
|
||||
// matches the prototype described in the stivale2 specification for
|
||||
// the stivale2_term_write function.
|
||||
term_write = term_write_ptr;
|
||||
}
|
||||
|
||||
void tty_print(const char* str, int length) {
|
||||
term_write(str, length);
|
||||
}
|
134
src/kernel.c
134
src/kernel.c
|
@ -1,132 +1,6 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stivale2.h>
|
||||
#include <tty.h>
|
||||
|
||||
// We need to tell the stivale bootloader where we want our stack to be.
|
||||
// We are going to allocate our stack as an array in .bss.
|
||||
static uint8_t stack[8192];
|
||||
|
||||
// stivale2 uses a linked list of tags for both communicating TO the
|
||||
// bootloader, or receiving info FROM it. More information about these tags
|
||||
// is found in the stivale2 specification.
|
||||
|
||||
// stivale2 offers a runtime terminal service which can be ditched at any
|
||||
// time, but it provides an easy way to print out to graphical terminal,
|
||||
// especially during early boot.
|
||||
// Read the notes about the requirements for using this feature below this
|
||||
// code block.
|
||||
static struct stivale2_header_tag_terminal terminal_hdr_tag = {
|
||||
// All tags need to begin with an identifier and a pointer to the next tag.
|
||||
.tag = {
|
||||
// Identification constant defined in stivale2.h and the specification.
|
||||
.identifier = STIVALE2_HEADER_TAG_TERMINAL_ID,
|
||||
// If next is 0, it marks the end of the linked list of header tags.
|
||||
.next = 0
|
||||
},
|
||||
// The terminal header tag possesses a flags field, leave it as 0 for now
|
||||
// as it is unused.
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
// We are now going to define a framebuffer header tag.
|
||||
// This tag tells the bootloader that we want a graphical framebuffer instead
|
||||
// of a CGA-compatible text mode. Omitting this tag will make the bootloader
|
||||
// default to text mode, if available.
|
||||
static struct stivale2_header_tag_framebuffer framebuffer_hdr_tag = {
|
||||
// Same as above.
|
||||
.tag = {
|
||||
.identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID,
|
||||
// Instead of 0, we now point to the previous header tag. The order in
|
||||
// which header tags are linked does not matter.
|
||||
.next = (uint64_t)&terminal_hdr_tag
|
||||
},
|
||||
// We set all the framebuffer specifics to 0 as we want the bootloader
|
||||
// to pick the best it can.
|
||||
.framebuffer_width = 0,
|
||||
.framebuffer_height = 0,
|
||||
.framebuffer_bpp = 0
|
||||
};
|
||||
|
||||
// The stivale2 specification says we need to define a "header structure".
|
||||
// This structure needs to reside in the .stivale2hdr ELF section in order
|
||||
// for the bootloader to find it. We use this __attribute__ directive to
|
||||
// tell the compiler to put the following structure in said section.
|
||||
__attribute__((section(".stivale2hdr"), used))
|
||||
static struct stivale2_header stivale_hdr = {
|
||||
// The entry_point member is used to specify an alternative entry
|
||||
// point that the bootloader should jump to instead of the executable's
|
||||
// ELF entry point. We do not care about that so we leave it zeroed.
|
||||
.entry_point = 0,
|
||||
// Let's tell the bootloader where our stack is.
|
||||
// We need to add the sizeof(stack) since in x86(_64) the stack grows
|
||||
// downwards.
|
||||
.stack = (uintptr_t)stack + sizeof(stack),
|
||||
// Bit 1, if set, causes the bootloader to return to us pointers in the
|
||||
// higher half, which we likely want since this is a higher half kernel.
|
||||
// Bit 2, if set, tells the bootloader to enable protected memory ranges,
|
||||
// that is, to respect the ELF PHDR mandated permissions for the executable's
|
||||
// segments.
|
||||
// Bit 3, if set, enables fully virtual kernel mappings, which we want as
|
||||
// they allow the bootloader to pick whichever *physical* memory address is
|
||||
// available to load the kernel, rather than relying on us telling it where
|
||||
// to load it.
|
||||
// Bit 4 disables a deprecated feature and should always be set.
|
||||
.flags = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4),
|
||||
// This header structure is the root of the linked list of header tags and
|
||||
// points to the first one in the linked list.
|
||||
.tags = (uintptr_t)&framebuffer_hdr_tag
|
||||
};
|
||||
|
||||
// We will now write a helper function which will allow us to scan for tags
|
||||
// that we want FROM the bootloader (structure tags).
|
||||
void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id) {
|
||||
struct stivale2_tag *current_tag = (void *)stivale2_struct->tags;
|
||||
for (;;) {
|
||||
// If the tag pointer is NULL (end of linked list), we did not find
|
||||
// the tag. Return NULL to signal this.
|
||||
if (current_tag == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check whether the identifier matches. If it does, return a pointer
|
||||
// to the matching tag.
|
||||
if (current_tag->identifier == id) {
|
||||
return current_tag;
|
||||
}
|
||||
|
||||
// Get a pointer to the next tag in the linked list and repeat.
|
||||
current_tag = (void *)current_tag->next;
|
||||
}
|
||||
}
|
||||
|
||||
// The following will be our kernel's entry point.
|
||||
void _start(struct stivale2_struct *stivale2_struct) {
|
||||
// Let's get the terminal structure tag from the bootloader.
|
||||
struct stivale2_struct_tag_terminal *term_str_tag;
|
||||
term_str_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_TERMINAL_ID);
|
||||
|
||||
// Check if the tag was actually found.
|
||||
if (term_str_tag == NULL) {
|
||||
// It wasn't found, just hang...
|
||||
for (;;) {
|
||||
asm ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
// Let's get the address of the terminal write function.
|
||||
void *term_write_ptr = (void *)term_str_tag->term_write;
|
||||
|
||||
// Now, let's assign this pointer to a function pointer which
|
||||
// matches the prototype described in the stivale2 specification for
|
||||
// the stivale2_term_write function.
|
||||
void (*term_write)(const char *string, size_t length) = term_write_ptr;
|
||||
|
||||
// We should now be able to call the above function pointer to print out
|
||||
// a simple "Hello World" to screen.
|
||||
term_write("Hello World", 11);
|
||||
|
||||
// We're done, just hang...
|
||||
for (;;) {
|
||||
asm ("hlt");
|
||||
}
|
||||
void kernel_main(void) {
|
||||
terminal_initialize();
|
||||
tty_print("Hello, world!", 12);
|
||||
}
|
||||
|
|
2
src/tty.h
Normal file
2
src/tty.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
void terminal_initialize();
|
||||
void tty_print(const char*, int length);
|
Reference in a new issue