32 changed files with 1522 additions and 467 deletions
@ -1,5 +1,5 @@ |
|||
.vscode |
|||
img_moint |
|||
*.o |
|||
include_cp |
|||
.vscode |
|||
img_moint |
|||
*.o |
|||
include_cp |
|||
*.elf |
@ -1,39 +1,41 @@ |
|||
|
|||
.PHONY: clean all disk kernel force_look |
|||
|
|||
HDD_ROOT := disc_root |
|||
HDD_FILE := disk.hdd |
|||
|
|||
USED_LOOPBACK := /dev/loop6 |
|||
|
|||
all: disk |
|||
|
|||
|
|||
disk: kernel |
|||
dd if=/dev/zero bs=1M count=0 seek=64 of=$(HDD_FILE) |
|||
sudo /sbin/parted -s $(HDD_FILE) mklabel gpt |
|||
sudo /sbin/parted -s $(HDD_FILE) mkpart ESP fat32 2048s 100% |
|||
sudo /sbin/parted -s $(HDD_FILE) set 1 esp on |
|||
./limine-bootloader/limine-install $(HDD_FILE) |
|||
|
|||
sudo losetup -P $(USED_LOOPBACK) $(HDD_FILE) |
|||
|
|||
sudo mkfs.fat -F 32 $(USED_LOOPBACK)p1 |
|||
mkdir -p img_mount |
|||
sudo mount $(USED_LOOPBACK)p1 img_mount |
|||
|
|||
sudo cp -r disk_root/* img_mount/ |
|||
sync |
|||
sudo umount img_mount |
|||
sudo /sbin/losetup -d $(USED_LOOPBACK) |
|||
|
|||
|
|||
kernel: force_look |
|||
$(MAKE) -C ./kernel/ |
|||
|
|||
clean: |
|||
cd ./kernel/ && make clean |
|||
rm -f $(HDD_FILE) |
|||
|
|||
force_look: |
|||
true |
|||
|
|||
.PHONY: clean all disk kernel force_look threaded_build |
|||
|
|||
HDD_ROOT := disc_root |
|||
HDD_FILE := disk.hdd |
|||
|
|||
USED_LOOPBACK := /dev/loop6 |
|||
|
|||
all: disk |
|||
|
|||
threaded_build: |
|||
make -j all |
|||
|
|||
disk: kernel |
|||
dd if=/dev/zero bs=1M count=0 seek=64 of=$(HDD_FILE) |
|||
sudo /sbin/parted -s $(HDD_FILE) mklabel gpt |
|||
sudo /sbin/parted -s $(HDD_FILE) mkpart ESP fat32 2048s 100% |
|||
sudo /sbin/parted -s $(HDD_FILE) set 1 esp on |
|||
./limine-bootloader/limine-install $(HDD_FILE) |
|||
|
|||
sudo losetup -P $(USED_LOOPBACK) $(HDD_FILE) |
|||
|
|||
sudo mkfs.fat -F 32 $(USED_LOOPBACK)p1 |
|||
mkdir -p img_mount |
|||
sudo mount $(USED_LOOPBACK)p1 img_mount |
|||
|
|||
sudo cp -r disk_root/* img_mount/ |
|||
sync |
|||
sudo umount img_mount |
|||
sudo /sbin/losetup -d $(USED_LOOPBACK) |
|||
|
|||
|
|||
kernel: force_look |
|||
$(MAKE) -C ./kernel/ |
|||
|
|||
clean: |
|||
cd ./kernel/ && make clean |
|||
rm -f $(HDD_FILE) |
|||
|
|||
force_look: |
|||
true |
|||
|
Binary file not shown.
Binary file not shown.
@ -1,17 +1,17 @@ |
|||
DEFAULT_ENTRY=1 |
|||
TIMEOUT=10 |
|||
GRAPHICS=yes |
|||
VERBOSE=yes |
|||
|
|||
THEME_MARGIN=64 |
|||
RESOLUTION=800x600 |
|||
BACKGROUND_PATH=boot:///boot/bg.bmp |
|||
THEME_BACKGROUND=8f000000 |
|||
BACKGROUND_STYLE=centered |
|||
|
|||
:Stivale2 Test |
|||
|
|||
PROTOCOL=stivale2 |
|||
RESOLUTION=800x600 |
|||
KERNEL_PATH=boot:///boot/kernel.elf |
|||
DEFAULT_ENTRY=1 |
|||
TIMEOUT=10 |
|||
GRAPHICS=yes |
|||
VERBOSE=yes |
|||
|
|||
THEME_MARGIN=64 |
|||
#RESOLUTION=800x600 |
|||
#BACKGROUND_PATH=boot:///boot/bg.bmp |
|||
#THEME_BACKGROUND=8f000000 |
|||
BACKGROUND_STYLE=centered |
|||
|
|||
:Stivale2 Test |
|||
|
|||
PROTOCOL=stivale2 |
|||
#RESOLUTION=800x600 |
|||
KERNEL_PATH=boot:///boot/kernel.elf |
|||
BACKGROUND_STYLE=centered |
@ -1,42 +1,57 @@ |
|||
KERNEL := ../disk_root/boot/kernel.elf |
|||
CC = x86_64-elf-gcc |
|||
|
|||
CFLAGS = -Wall -Wextra -O2 -pipe |
|||
|
|||
INTERNALLDFLAGS := \
|
|||
-fno-pic -fpie \
|
|||
-Wl,-static,-pie,--no-dynamic-linker,-ztext \
|
|||
-static-pie \
|
|||
-nostdlib \
|
|||
-Tlinker.ld \
|
|||
-z max-page-size=0x1000 |
|||
|
|||
INTERNALCFLAGS := \
|
|||
-I/opt/cross/include/ \
|
|||
-H \
|
|||
-std=gnu11 \
|
|||
-ffreestanding \
|
|||
-fno-stack-protector \
|
|||
-fno-pic -fpie \
|
|||
-mno-80387 \
|
|||
-mno-mmx \
|
|||
-mno-3dnow \
|
|||
-mno-sse \
|
|||
-mno-sse2 \
|
|||
-mno-red-zone |
|||
|
|||
CFILES := $(shell find ./ -type f -name '*.c') |
|||
OBJ := $(CFILES:.c=.o) |
|||
|
|||
.PHONY: all clean |
|||
|
|||
all: $(KERNEL) |
|||
|
|||
$(KERNEL): $(OBJ) |
|||
$(CC) $(INTERNALLDFLAGS) $(OBJ) -o $@ |
|||
|
|||
%.o: %.c |
|||
$(CC) $(CFLAGS) $(INTERNALCFLAGS) -c $< -o $@ |
|||
|
|||
clean: |
|||
KERNEL := ../disk_root/boot/kernel.elf |
|||
CC := x86_64-elf-gcc |
|||
ASM := nasm |
|||
ASM_FLAGS := -felf64 |
|||
|
|||
CFLAGS = -Wall -Wextra -O2 -pipe |
|||
|
|||
INTERNALLDFLAGS := \
|
|||
-fno-pic \
|
|||
-Wl,-static,--no-dynamic-linker,-ztext \
|
|||
-znocombreloc \
|
|||
-nostdlib \
|
|||
-Tlinker.ld \
|
|||
-z max-page-size=0x1000 |
|||
|
|||
|
|||
INTERNALCFLAGS := \
|
|||
-znocombreloc \
|
|||
-I/opt/cross/include/ \
|
|||
-H \
|
|||
-std=gnu11 \
|
|||
-ffreestanding \
|
|||
-fno-stack-protector \
|
|||
-fno-pic \
|
|||
-mno-80387 \
|
|||
-mno-mmx \
|
|||
-mno-3dnow \
|
|||
-mno-sse \
|
|||
-mno-sse2 \
|
|||
-mno-red-zone \
|
|||
-m64 |
|||
|
|||
CFILES := $(shell find ./ -type f -name '*.c') |
|||
SFILES := $(shell find ./ -type f -name '*.s') |
|||
OBJ := $(SFILES:.s=.s.o) $(CFILES:.c=.c.o) charmap.bmp.o |
|||
.PHONY: all clean |
|||
|
|||
all: $(KERNEL) |
|||
|
|||
|
|||
|
|||
$(KERNEL): $(OBJ) |
|||
echo $(OBJ) |
|||
$(CC) $(INTERNALLDFLAGS) $(OBJ) -o $@ |
|||
|
|||
%.bmp.o: ../resources/bmp/%.bmp |
|||
$(LD) -r -b binary -o $@ $< |
|||
|
|||
%.c.o: %.c |
|||
$(CC) $(CFLAGS) $(INTERNALCFLAGS) -c $< -o $@ |
|||
|
|||
%.s.o: %.s |
|||
echo "$(ASM) $(ASM_FLAGS) $< -o $@" |
|||
$(ASM) $(ASM_FLAGS) $< -o $@ |
|||
|
|||
clean: |
|||
rm -rf $(KERNEL) $(OBJ) |
@ -0,0 +1,39 @@ |
|||
#ifndef COMMON_H |
|||
#define COMMON_H |
|||
|
|||
#include <stdint.h> |
|||
|
|||
typedef uint16_t u64; |
|||
typedef int64_t i64; |
|||
typedef uint32_t u32; |
|||
typedef int32_t i32; |
|||
|
|||
typedef uint16_t u16; |
|||
typedef int16_t i16; |
|||
|
|||
typedef uint8_t u8; |
|||
typedef int8_t i8; |
|||
|
|||
|
|||
#define __packed __attribute__((packed)) |
|||
#define __align(N) __attribute__ ((aligned(N))) |
|||
#define __noreturn __attribute__((noreturn)) |
|||
|
|||
#ifndef NDEBUG |
|||
#define PDEBUG kprintf("'%s':%d - %s()\n", __FILE__, __LINE__,__func__); |
|||
#endif |
|||
|
|||
inline uint64_t allign16(uint64_t p) { |
|||
uint64_t offset = p & 0x0f; |
|||
if(offset) |
|||
p = (p+16) & (~0xf); |
|||
|
|||
return p; |
|||
} |
|||
|
|||
inline void* mallign16(void* ptr) { |
|||
return (void*)allign16((uint64_t)ptr); |
|||
} |
|||
// 8 = ring 0 && id 1
|
|||
|
|||
#endif //COMMON_H
|
@ -0,0 +1,14 @@ |
|||
#include "../klib/sprintf.h" |
|||
#include "assert.h" |
|||
#include "panic.h" |
|||
|
|||
|
|||
void __assert(const char* __restrict__ expression, |
|||
const char* __restrict__ file, |
|||
const int line) { |
|||
char buffer[1024]; |
|||
|
|||
sprintf("assertion '%s' failed at: %s:%d", expression, file, line); |
|||
|
|||
panic(buffer); |
|||
} |
@ -0,0 +1,17 @@ |
|||
#pragma once |
|||
|
|||
|
|||
#ifndef NDEBUG |
|||
void __assert(const char* __restrict__ expression, |
|||
const char* __restrict__ file, |
|||
const int line); |
|||
|
|||
#define assert(EX) (void)((EX) || (__assert (#EX, __FILE__, __LINE__),0)) |
|||
#else |
|||
#define assert(EX) |
|||
#endif |
|||
|
|||
|
|||
#define static_assert(EX) _Static_assert(EX, \ |
|||
"static assert failed") |
|||
|
@ -0,0 +1,25 @@ |
|||
#include "panic.h" |
|||
#include "../video/terminal.h" |
|||
|
|||
|
|||
__attribute__((noreturn)) void panic(const char* panic_string) { |
|||
// checks if video is operationnal
|
|||
if(get_terminal_handler() != NULL) { |
|||
termina_set_colors(0xa0a0a0, 0x0000ff); |
|||
|
|||
if(panic_string == NULL) |
|||
panic_string = ""; |
|||
|
|||
kprintf( |
|||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" |
|||
"!!!!!!!!!!!!! KERNL PANIC !!!!!!!!!!!!!\n" |
|||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" |
|||
"%s\n\n\n" |
|||
"you may manually shutdown the machine.\n" |
|||
|
|||
); |
|||
} |
|||
for(;;) |
|||
asm volatile("hlt"); |
|||
__builtin_unreachable(); |
|||
} |
@ -0,0 +1,10 @@ |
|||
#pragma once |
|||
|
|||
|
|||
/**
|
|||
* panic_string can be NULL |
|||
* |
|||
* doesn't return: freezes |
|||
* dumps the registers and print debug infos |
|||
*/ |
|||
__attribute__((noreturn)) void panic(const char* panic_string); |
@ -1,126 +1,193 @@ |
|||
|
|||
#include <stivale2.h> |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
// We need to tell the stivale bootloader where we want our stack to be.
|
|||
// We are going to allocate our stack as an uninitialised array in .bss.
|
|||
static uint8_t stack[4096]; |
|||
|
|||
// 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, which is mandatory when
|
|||
// using the stivale2 terminal.
|
|||
// 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.
|
|||
.flags = (1 << 1), |
|||
// 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("Bincows beta", 12); |
|||
|
|||
// We're done, just hang...
|
|||
for (;;) { |
|||
asm ("hlt"); |
|||
} |
|||
#include <stivale2.h> |
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#include "memory/gdt.h" |
|||
#include "video/video.h" |
|||
#include "klib/sprintf.h" |
|||
#include "klib/string.h" |
|||
#include "video/terminal.h" |
|||
#include "common.h" |
|||
#include "regs.h" |
|||
|
|||
// 8K stack
|
|||
static uint8_t stack[8192] __align(16); |
|||
|
|||
|
|||
// 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, which is mandatory when
|
|||
// using the stivale2 terminal.
|
|||
// 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.
|
|||
.flags = (1 << 1), |
|||
// 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; |
|||
} |
|||
} |
|||
|
|||
|
|||
#define PRINT_VAL(v) kprintf(#v "=%ld\n", v); |
|||
#define PRINT_HEX(v) kprintf(#v "=%lx\n", v); |
|||
|
|||
extern void _binary____resources_bmp_charmap_bmp_start; |
|||
|
|||
extern uint64_t test(void); |
|||
extern int64_t test_size; |
|||
|
|||
// Registers %rbp, %rbx and %r12 through %r15 โbelongโ to the calling functio
|
|||
// 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; |
|||
|
|||
|
|||
|
|||
set_terminal_handler(term_write_ptr); |
|||
|
|||
struct stivale2_struct_tag_framebuffer fbtag; |
|||
struct stivale2_struct_tag_framebuffer* _fbtag = stivale2_get_tag(stivale2_struct,0x506461d2950408fa); |
|||
|
|||
memcpy(&fbtag, _fbtag, sizeof(fbtag)); |
|||
|
|||
PRINT_VAL(fbtag.memory_model); |
|||
PRINT_VAL(fbtag.framebuffer_pitch); |
|||
PRINT_VAL(fbtag.framebuffer_width); |
|||
PRINT_VAL(fbtag.framebuffer_height); |
|||
PRINT_VAL(fbtag.framebuffer_bpp); |
|||
PRINT_HEX(fbtag.framebuffer_addr); |
|||
PRINT_VAL(fbtag. red_mask_shift); |
|||
PRINT_VAL(fbtag.green_mask_shift); |
|||
PRINT_VAL(fbtag. blue_mask_shift); |
|||
PRINT_VAL(fbtag. red_mask_size); |
|||
PRINT_VAL(fbtag.green_mask_size); |
|||
PRINT_VAL(fbtag. blue_mask_size); |
|||
PRINT_VAL(test_size); |
|||
|
|||
Image sc = {.w = fbtag.framebuffer_width, |
|||
.h = fbtag.framebuffer_height, |
|||
.pitch= fbtag.framebuffer_pitch, |
|||
.bpp = fbtag.framebuffer_bpp, |
|||
.pix = (void*)fbtag.framebuffer_addr}; |
|||
|
|||
|
|||
initVideo(&sc); |
|||
|
|||
Image* image = loadBMP(&_binary____resources_bmp_charmap_bmp_start); |
|||
PRINT_VAL(image); |
|||
|
|||
|
|||
|
|||
// We should now be able to call the above function pointer to print out
|
|||
// a simple "Hello World" to screen.
|
|||
char buf[128]; |
|||
kprintf("ds=0x%x\nss=0x%x\ncs=%x\nes=%x\nfs=%x\ngs=%x\n\n", |
|||
_ds(), _ss(), _cs(),_es(),_fs(),_gs()); |
|||
kprintf("print=0x%lx\n\n", kprintf);//0x00ea60
|
|||
//0x100a60
|
|||
init_gdt_table(); |
|||
|
|||
blit(image, NULL, NULL); |
|||
//*ptr = 0xfffa24821;
|
|||
asm("hlt"); |
|||
|
|||
for(size_t i = 0; i < fbtag.framebuffer_height; i++) { |
|||
uint8_t* base = fbtag.framebuffer_addr + fbtag.framebuffer_pitch*i; |
|||
for(size_t j = 0; j < fbtag.framebuffer_width; j++) { |
|||
uint32_t* px = (uint32_t*)&base[4*j]; |
|||
*px = 0xffffff00; |
|||
|
|||
} |
|||
} |
|||
//*(uint64_t*)(term_write_ptr) = 0xfeac;
|
|||
//print_fun(buf, 2);
|
|||
|
|||
// kprintf("Bincows beta");
|
|||
|
|||
// We're done, just hang...
|
|||
for (;;) { |
|||
asm ("hlt"); |
|||
} |
|||
} |
@ -0,0 +1,4 @@ |
|||
test: |
|||
del -f a.exe |
|||
gcc test.c sprintf.c string.c |
|||
a.exe |
@ -0,0 +1,203 @@ |
|||
#include "sprintf.h" |
|||
#include "string.h" |
|||
|
|||
#define SIGN(X) X > 0 ? 1 : -1 |
|||
#define ARG(TYPE) (TYPE)va_arg(ap, TYPE) |
|||
|
|||
char* utohex(char* str, uint64_t x, size_t min_digits) { |
|||
size_t digits = 1; |
|||
|
|||
uint64_t _x = x; |
|||
|
|||
// _x < 0xf
|
|||
while(_x & ~0xf) { |
|||
_x >>= 4; |
|||
digits++; |
|||
} |
|||
|
|||
if(digits < min_digits) |
|||
digits = min_digits; |
|||
|
|||
char* end = str+digits; |
|||
|
|||
char* ptr = end; |
|||
|
|||
for(int i = digits;i>0;i--) { |
|||
int d = x & 0x0f; |
|||
if(d < 0xa) |
|||
d += '0'; |
|||
else |
|||
d += 'a'-10; |
|||
*(--ptr) = d; |
|||
|
|||
x >>= 4; |
|||
} |
|||
|
|||
|
|||
*end = '\0'; |
|||
return end; |
|||
} |
|||
|
|||
// unsigned to string
|
|||
// return a ptr to the end of the string
|
|||
char* utos(char* str, uint64_t x, size_t min_digits) { |
|||
size_t digits = 1; |
|||
|
|||
uint64_t _x = x; |
|||
while(_x > 9) { |
|||
_x /= 10; |
|||
digits++; |
|||
} |
|||
|
|||
if(digits < min_digits) |
|||
digits = min_digits; |
|||
|
|||
char* end = str+digits; |
|||
|
|||
char* ptr = end; |
|||
for(int i = digits;i>0;i--) { |
|||
*(--ptr) = '0' + x%10; |
|||
|
|||
x /= 10; |
|||
} |
|||
*end = '\0'; |
|||
|
|||
|
|||
return end; |
|||
} |
|||
|
|||
// signed to string
|
|||
char* itos(char* str, int64_t x, size_t min_digits) { |
|||
if(x < 0) { |
|||
*(str++) = '-'; |
|||
x *= -1; |
|||
} |
|||
|
|||
return utos(str, x, min_digits); |
|||
} |
|||
|
|||
|
|||
int vsprintf(char *str, const char *format, va_list ap) { |
|||
char cf; |
|||
int args_put = 0; |
|||
int persent = 0; |
|||
int digits = 0; |
|||
|
|||
// bool value: '%l..'
|
|||
int _long = 0; |
|||
|
|||
while(1) { |
|||
cf = *(format++); |
|||
if(cf == '\0') |
|||
break; |
|||
|
|||
if(persent) { |
|||
if(cf == '.') |
|||
continue; |
|||
else if(cf == 'l') { |
|||
_long = 1; |
|||
continue; |
|||
} |
|||
|
|||
int i = cf - '0'; |
|||
if(i >= 0 && i <= 9) |
|||
digits = 10 * digits + i; |
|||
else { |
|||
switch(cf) { |
|||
default: |
|||
// invalid
|
|||
break; |
|||
case 'u': |
|||
if(!_long) |
|||
str = utos(str, ARG(uint32_t), digits); |
|||
else |
|||
str = utos(str, ARG(uint64_t), digits); |
|||
break; |
|||
case 'd': |
|||
case 'i': |
|||
if(!_long) |
|||
str = itos(str, ARG(int32_t), digits); |
|||
else |
|||
str = itos(str, ARG(int64_t), digits); |
|||
break; |
|||
case 'h': |
|||
case 'x': |
|||
if(!_long) |
|||
str = utohex(str, ARG(uint32_t), digits); |
|||
else |
|||
str = utohex(str, ARG(uint64_t), digits); |
|||
break; |
|||
case 's': |
|||
{ |
|||
const char* arg = ARG(const char*); |
|||
strcpy(str, arg); |
|||
str += strlen(arg); |
|||
} |
|||
break; |
|||
case 'c': |
|||
*(str++) = (char)ARG(int); |
|||
break; |
|||
} |
|||
digits = 0; |
|||
persent = 0; |
|||
_long = 0; |
|||
args_put++; |
|||
} |
|||
} |
|||
|
|||
else if(cf == '%') { |
|||
persent = 1; |
|||
} |
|||
else { |
|||
*(str++) = cf; |
|||
} |
|||
} |
|||
|
|||
*str = '\0'; |
|||
return args_put; |
|||
} |
|||
|
|||
|
|||
int sprintf(char* str, const char* format, ...) { |
|||
va_list ap; |
|||
int res; |
|||
|
|||
va_start(ap, format); |
|||
res = vsprintf(str,format,ap); |
|||
va_end(ap); |
|||
|
|||
return res; |
|||
} |
|||
//
|
|||
//int vsnprintf(char *str, size_t size, const char *format, va_list ap) {
|
|||
//
|
|||
//
|
|||
//}
|
|||
|
|||
static void (*print_fun)(const char *string, size_t length) = NULL; |
|||
|
|||
|
|||
void set_print_fun(void* fun) { |
|||
print_fun = fun; |
|||
} |
|||
int kprintf(const char* format, ...) { |
|||
va_list ap; |
|||
int ret; |
|||
|
|||
va_start(ap, format); |
|||
|
|||
if(!print_fun) |
|||
ret = -1; |
|||
else { |
|||
char buf[1024]; |
|||
|
|||
ret = vsprintf(buf, format, ap); |
|||
|
|||
print_fun(buf, strlen(buf)); |
|||
} |
|||
|
|||
va_end(ap); |
|||
|
|||
return ret; |
|||
} |
|||
|
@ -0,0 +1,19 @@ |
|||
#ifndef SPRINTF_H |
|||
#define SPRINTF_H |
|||
|
|||
|
|||
#include <stdint.h> |
|||
#include <stddef.h> |
|||
#include <stdarg.h> |
|||
|
|||
|
|||
int sprintf(char *str, const char *format, ...); |
|||
int snprintf(char *str, size_t size, const char *format, ...); |
|||
int vsprintf(char *str, const char *format, va_list ap); |
|||
int vsnprintf(char *str, size_t size, const char *format, va_list ap); |
|||
|
|||
|
|||
void set_print_fun(void* fun); |
|||
int kprintf(const char* format, ...); |
|||
|
|||
#endif |
@ -1,167 +1,251 @@ |
|||
#include "string.h" |
|||
|
|||
|
|||
size_t strlen(const char* str) { |
|||
const char* ptr = str; |
|||
|
|||
int len = 0; |
|||
|
|||
while(*(ptr++) != '\0') |
|||
len++; |
|||
|
|||
return len; |
|||
} |
|||
|
|||
|
|||
size_t strnlen(const char* str, size_t n) { |
|||
int len = 0; |
|||
|
|||
while(*(str++) != '\0' && n--) |
|||
len++; |
|||
|
|||
return len; |
|||
} |
|||
|
|||
char* strcpy(char* dst, const char* src) { |
|||
char c; |
|||
char* pdst = dst; |
|||
|
|||
do { |
|||
c = *(src++); |
|||
|
|||
*(pdst++) = c; |
|||
} |
|||
while(c != '\0'); |
|||
|
|||
return dst; |
|||
} |
|||
|
|||
char* strncpy(char* dst, const char* src, size_t n) { |
|||
char c; |
|||
char* pdst = dst; |
|||
|
|||
do { |
|||
c = *(src++); |
|||
|
|||
*(pdst++) = c; |
|||
|
|||
n--; |
|||
} |
|||
while(c != '\0' && n > 0); |
|||
|
|||
*pdst = '\0'; |
|||
|
|||
return dst; |
|||
} |
|||
|
|||
|
|||
int strcmp(const char* str1, const char* str2) { |
|||
int d; |
|||
|
|||
while(1) { |
|||
char c1 = *(str1++); |
|||
char c2 = *(str2++); |
|||
|
|||
d = c1-c2; |
|||
|
|||
if(!c1 || !c2 || d) |
|||
break; |
|||
} |
|||
|
|||
return d; |
|||
} |
|||
|
|||
int strncmp(const char* str1, const char* str2, size_t n) { |
|||
int d; |
|||
|
|||
while(n-- > 0) { |
|||
char c1 = *(str1++); |
|||
char c2 = *(str2++); |
|||
|
|||
d = c1-c2; |
|||
|
|||
if(!c1 || !c2 || d) |
|||
break; |
|||
} |
|||
|
|||
return d; |
|||
} |
|||
|
|||
|
|||
char* strchr (const char *s, int c) { |
|||
char curr; |
|||
|
|||
while(1) { |
|||
curr = *s; |
|||
|
|||
if(curr == c) |
|||
return s; |
|||
else if(curr = '\0') |
|||
break; |
|||
|
|||
s++; |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
char* strrchr(const char *s, int c) { |
|||
char curr; |
|||
|
|||
char* found = NULL; |
|||
|
|||
while(1) { |
|||
curr = *s; |
|||
|
|||
if(curr == c) |
|||
found = s; |
|||
else if(curr = '\0') |
|||
break; |
|||
|
|||
s++; |
|||
} |
|||
|
|||
return found; |
|||
} |
|||
|
|||
|
|||
char *strstr(const char *haystack, const char *needle) { |
|||
char* ptr = haystack; |
|||
|
|||
int i = 0; |
|||
char c, ci; |
|||
|
|||
do { |
|||
|
|||
ci = needle[i]; |
|||
|
|||
if(ci == '\0') |
|||
return haystack - i - 1; |
|||
|
|||
|
|||
c = *(haystack++); |
|||
|
|||
if(c == ci) |
|||
i++; |
|||
else if(c == '\0') |
|||
return NULL; |
|||
else |
|||
i = 0; |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
char* strcat(char *dest, const char *src) { |
|||
while(*(dest++)) ; |
|||
|
|||
return strcpy(dest, src); |
|||
} |
|||
|
|||
char *strncat(char *dest, const char *src, size_t n) { |
|||
while(*(dest++)) ; |
|||
|
|||
return strncpy(dest, src, n); |
|||
} |
|||
#include "string.h" |
|||
|
|||
|
|||
size_t strlen(const char* str) { |
|||
const char* ptr = str; |
|||
|
|||
int len = 0; |
|||
|
|||
while(*(ptr++) != '\0') |
|||
len++; |
|||
|
|||
return len; |
|||
} |
|||
|
|||
|
|||
size_t strnlen(const char* str, size_t n) { |
|||
int len = 0; |
|||
|
|||
while(*(str++) != '\0' && n--) |
|||
len++; |
|||
|
|||
return len; |
|||
} |
|||
|
|||
char* strcpy(char* dst, const char* src) { |
|||
char c; |
|||
char* pdst = dst; |
|||
|
|||
do { |
|||
c = *(src++); |
|||
|
|||
*(pdst++) = c; |
|||
} |
|||
while(c != '\0'); |
|||
|
|||
return dst; |
|||
} |
|||
|
|||
char* strncpy(char* dst, const char* src, size_t n) { |
|||
char c; |
|||
char* pdst = dst; |
|||
|
|||
do { |
|||
c = *(src++); |
|||
|
|||
*(pdst++) = c; |
|||
|
|||
n--; |
|||
} |
|||
while(c != '\0' && n > 0); |
|||
|
|||
if(c != '\0') |
|||
*pdst = '\0'; |
|||
dst = '\0'; |
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
int strcmp(const char* str1, const char* str2) { |
|||
int d; |
|||
|
|||
while(1) { |
|||
char c1 = *(str1++); |
|||
char c2 = *(str2++); |
|||
|
|||
d = c1-c2; |
|||
|
|||
if(!c1 || !c2 || d) |
|||
break; |
|||
} |
|||
|
|||
return d; |
|||
} |
|||
|
|||
int strncmp(const char* str1, const char* str2, size_t n) { |
|||
int d; |
|||
|
|||
while(n-- > 0) { |
|||
char c1 = *(str1++); |
|||
char c2 = *(str2++); |
|||
|
|||
d = c1-c2; |
|||
|
|||
if(!c1 || !c2 || d) |
|||
break; |
|||
} |
|||
|
|||
return d; |
|||
} |
|||
|
|||
|
|||
const char* strchr (const char *_s, int c) { |
|||
const char* s=_s; |
|||
char curr; |
|||
|
|||
while(1) { |
|||
curr = *s; |
|||
|
|||
if(curr == c) |
|||
return s; |
|||
else if(curr == '\0') |
|||
break; |
|||
|
|||
s++; |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
const char* strrchr(const char *s, int c) { |
|||
char curr; |
|||
|
|||
const char* found = NULL; |
|||
|
|||
while(1) { |
|||
curr = *s; |
|||
|
|||
if(curr == c) |
|||
found = s; |
|||
else if(curr == '\0') |
|||
break; |
|||
|
|||
s++; |
|||
} |
|||
|
|||
return found; |
|||
} |
|||
|
|||
|
|||
const char *strstr(const char *haystack, const char *needle) { |
|||
|
|||
int i = 0; |
|||
char c, ci; |
|||
|
|||
while(1) { |
|||
|
|||
ci = needle[i]; |
|||
|
|||
if(ci == '\0') |
|||
return haystack - i - 1; |
|||
|
|||
|
|||
c = *(haystack++); |
|||
|
|||
if(c == ci) |
|||
i++; |
|||
else if(c == '\0') |
|||
return NULL; |
|||
else |
|||
i = 0; |
|||
} |
|||
} |
|||
|
|||
|
|||
char* strcat(char *dest, const char *src) { |
|||
while(*(dest++)) ; |
|||
|
|||
return strcpy(dest, src); |
|||
} |
|||
|
|||
char *strncat(char *dest, const char *src, size_t n) { |
|||
char* ret = dest; |
|||
|
|||
while(*(dest++)) ; |
|||
strncpy(--dest, src, n); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
|
|||
void * memccpy (void* dst, const void *src, int c, size_t n) { |
|||
|
|||
|
|||
for(; n > 0; n--) { |
|||
char d = *(char*)(src++) = *(char*)(dst++); |
|||
|
|||
if(d == c) |
|||
return dst; |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
const void* memchr (const void *_buf, int _ch, size_t n) { |
|||
uint8_t ch = *(uint8_t*)(&_ch); |
|||
const uint8_t* buf=_buf; |
|||
|
|||
for(;n > 0; n--) { |
|||
if(*buf == ch) |
|||
return buf; |
|||
buf++; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
int memcmp (const void* _buf1, const void* _buf2, size_t n) { |
|||
const uint8_t* buf1=_buf1; |
|||
const uint8_t* buf2=_buf2; |
|||
|
|||
for(; n > 0; n--) { |
|||
int d = *(buf1++) - *(buf2++); |
|||
|
|||
if(d != 0) |
|||
return d; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void * memcpy (void * _dest, const void *_src, size_t n) { |
|||
uint8_t* src=_src,*dest=_dest; |
|||
|
|||
for(;n > 0; --n) |
|||
*(dest++) = *(src++); |
|||
|
|||
return dest; |
|||
} |
|||
|
|||
void * memset (void * _buf, int _ch, size_t n) { |
|||
uint8_t ch = *(uint8_t*)(&_ch); |
|||
uint8_t* buf = _buf; |
|||
|
|||
// first unaligned bytes
|
|||
for(;n > 0 && (uint64_t)buf % 8 != 0; --n) |
|||
*(buf++) = ch; |
|||
|
|||
|
|||
if(!n) return buf; |
|||
|
|||
if(n >= 8) { |
|||
uint64_t ch64 = ch | (ch << 8); |
|||
ch64 = ch64 | (ch64 << 16); |
|||
|
|||
for(;n > 0; n -= 8) { |
|||
*(uint64_t*)buf = ch64; |
|||
buf += 8; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
// last unaligned bytes
|
|||
for(;n > 0 && (uint64_t)buf % 8 != 0; --n) |
|||
*(buf++) = ch; |
|||
|
|||
return buf; |
|||
} |
|||
|
@ -1,45 +1,41 @@ |
|||
#ifndef KSTRING_H |
|||
#define KSTRING_H |
|||
|
|||
#include <inttypes.h> |
|||
|
|||
#ifndef size_t |
|||
typedef unsigned long int size_t; |
|||
#endif |
|||
#ifndef NULL |
|||
#define NULL (void *)(0) |
|||
#endif |
|||
#ifndef __ATTR_PURE__ |
|||
#define __ATTR_PURE__ __attribute__((__pure__)) |
|||
#endif |
|||
|
|||
|
|||
void * memccpy (void *, const void *, int, size_t); |
|||
void * memchr (const void *, int, size_t) __ATTR_PURE__; |
|||
int memcmp (const void *, const void *, size_t) __ATTR_PURE__; |
|||
void * memcpy (void *, const void *, size_t); |
|||
void * memmem (const void *, size_t, const void *, size_t) __ATTR_PURE__; |
|||
void * memmove (void *, const void *, size_t); |
|||
void * memrchr (const void *, int, size_t) __ATTR_PURE__; |
|||
void * memset (void *, int, size_t); |
|||
|
|||
|
|||
|
|||
size_t strlen (const char* str) __ATTR_PURE__; |
|||
size_t strnlen(const char* str, size_t n) __ATTR_PURE__; |
|||
int strcmp (const char* str1, const char* str2) __ATTR_PURE__; |
|||
int strncmp(const char* str1, const char* str2, size_t n) __ATTR_PURE__; |
|||
char* strchr (const char *s, int c) __ATTR_PURE__; |
|||
char* strrchr(const char *s, int c) __ATTR_PURE__; |
|||
char* strstr(const char *haystack, const char *needle) __ATTR_PURE__; |
|||
|
|||
|
|||
char* strcpy (char* dst, const char* src); |
|||
char* strncpy(char* dst, const char* src, size_t n); |
|||
char* strcat(char *dest, const char *src); |
|||
char* strncat(char *dest, const char *src, size_t n); |
|||
|
|||
|
|||
|
|||
|
|||
#ifndef KSTRING_H |
|||
#define KSTRING_H |
|||
|
|||
#include <stdint.h> |
|||
#include <stddef.h> |
|||
|
|||
|
|||
#ifndef __ATTR_PURE__ |
|||
#define __ATTR_PURE__ __attribute__((__pure__)) |
|||
#endif |
|||
|
|||
|
|||
void * memccpy (void * __restrict__, const void * __restrict__, int, size_t); |
|||
const void * memchr (const void *, int, size_t) __ATTR_PURE__; |
|||
int memcmp (const void *, const void *, size_t) __ATTR_PURE__; |
|||
void * memcpy (void * __restrict__, const void * __restrict__, size_t); |
|||
void * memset (void *, int, size_t); |
|||
//void * memmem (const void *, size_t, const void *, size_t) __ATTR_PURE__;
|
|||
//void * memmove (void *, const void *, size_t);
|
|||
//void * memrchr (const void *, int, size_t) __ATTR_PURE__;
|
|||
|
|||
|
|||
|
|||
size_t strlen (const char* str) __ATTR_PURE__; |
|||
size_t strnlen(const char* str, size_t n) __ATTR_PURE__; |
|||
int strcmp (const char* str1, const char* str2) __ATTR_PURE__; |
|||
int strncmp(const char* str1, const char* str2, size_t n) __ATTR_PURE__; |
|||
const char* strchr (const char *s, int c) __ATTR_PURE__; |
|||
const char* strrchr(const char *s, int c) __ATTR_PURE__; |
|||
const char* strstr(const char *haystack, const char *needle) __ATTR_PURE__; |
|||
|
|||
|
|||
char* strcpy (char* __restrict__ dst, const char* __restrict__ src); |
|||
char* strncpy(char* __restrict__ dst, const char* __restrict__ src, size_t n); |
|||
char* strcat(char * __restrict__ dest, const char * __restrict__ src); |
|||
char* strncat(char * __restrict__ dest, const char * __restrict__ src, size_t n); |
|||
|
|||
|
|||
|
|||
|
|||
#endif//KSTRING_H
|
@ -1,32 +1,31 @@ |
|||
/* Tell the linker that we want the symbol _start to be our entry point */ |
|||
ENTRY(_start) |
|||
|
|||
SECTIONS |
|||
{ |
|||
/* We wanna be placed in the higher half, 2MiB above 0 in physical memory. */ |
|||
. = 0xffffffff80200000; |
|||
|
|||
/* We place the .stivalehdr section containing the header in its own section, */ |
|||
/* and we use the KEEP directive on it to make sure it doesn't get discarded. */ |
|||
.stivalehdr : { |
|||
KEEP(*(.stivalehdr)) |
|||
} |
|||
|
|||
/* Then let's place all the other traditional executable sections afterwards. */ |
|||
.text : { |
|||
*(.text*) |
|||
} |
|||
|
|||
.rodata : { |
|||
*(.rodata*) |
|||
} |
|||
|
|||
.data : { |
|||
*(.data*) |
|||
} |
|||
|
|||
.bss : { |
|||
*(COMMON) |
|||
*(.bss*) |
|||
} |
|||
/* Tell the linker that we want the symbol _start to be our entry point */ |
|||
ENTRY(_start) |
|||
|
|||
SECTIONS |
|||
{ |
|||
. = 0x00100000; |
|||
|
|||
/* We place the .stivalehdr section containing the header in its own section, */ |
|||
/* and we use the KEEP directive on it to make sure it doesn't get discarded. */ |
|||
.stivalehdr : { |
|||
KEEP(*(.stivalehdr)) |
|||
} |
|||
|
|||
/* Then let's place all the other traditional executable sections afterwards. */ |
|||
.text : ALIGN(0x1000) { |
|||
*(.text*) |
|||
} |
|||
|
|||
.rodata : ALIGN(0x1000) { |
|||
*(.rodata*) |
|||
} |
|||
|
|||
.data : ALIGN(0x1000) { |
|||
*(.data*) |
|||
} |
|||
|
|||
.bss : ALIGN(0x1000) { |
|||
*(COMMON) |
|||
*(.bss*) |
|||
} |
|||
} |
@ -0,0 +1,88 @@ |
|||
#include "gdt.h" |
|||
#include "../common.h" |
|||
#include "../klib/sprintf.h" |
|||
#include "../debug/assert.h" |
|||
|
|||
/*
|
|||
typedef GDTentryAccessByte |
|||
*/ |
|||
|
|||
struct GDTentry { |
|||
u16 limit1; // x86_64: ignrored
|
|||
u16 base1; // x86_64: ignrored
|
|||
u8 base2; // x86_64: ignrored
|
|||
// access byte
|
|||
//union {
|
|||
// struct {
|
|||
u8 accessed: 1; // should be 0 (the CPU sets it to 1 when accessed)
|
|||
u8 read_write: 1; // for code selectors: readable bit
|
|||
// for data selectors: writable bit
|
|||
u8 dir_conforming: 1; // for code selectors: should be 0 in longmode
|
|||
// (code can be executed by lower privilege level)
|
|||
// for data selectors: 0: segment grows upward, downward otherwise
|
|||
u8 executable: 1; // for code selectors
|
|||
u8 descriptor: 1; // should be 1 for data/code segments, 0 for system (tss)
|
|||
u8 ring: 2; // privilege ring
|
|||
u8 present: 1; // should always be 1
|
|||
//} __packed;
|
|||
// u8 access_byte;
|
|||
//} __packed;
|
|||
|
|||
|
|||
u8 limit2: 4; // x86_64: ignrored
|
|||
//union {
|
|||
//struct {
|
|||
u8 nullbits: 1; // must be 0
|
|||
u8 longcode: 1; // x86_64: 1
|
|||
u8 size: 1; // x86_64: must be 0
|
|||
u8 granularity: 1; // x86_64: ignrored
|
|||
//} __packed;
|
|||
// u8 flags: 4;
|
|||
//} __packed;
|
|||
u8 base3; // x86_64: ignrored
|
|||
} __packed; |
|||
|
|||
struct GDTDescriptor { |
|||
uint16_t size; // size of the GDT - 1
|
|||
uint64_t offset; // address of the table
|
|||
} __packed; |
|||
|
|||
|
|||
|
|||
// GDT is in .bss section
|
|||
static struct GDTentry gdt[] = { |
|||
{0},// null descriptor
|
|||
{0,0,0, 0,0,0,1,1,0,1, 0, 0,1,0,1, 0}, // kernel code segment
|
|||
{0,0,0, 0,1,0,0,1,0,1, 0, 0,0,1,1, 0}, // kernel data segment
|
|||
{0,0,0, 0,0,0,1,1,0,1, 0, 0,1,0,1, 0}, // kernel code segment
|
|||
{0,0,0, 0,1,0,0,1,0,1, 0, 0,0,1,1, 0}, // kernel data segment
|
|||
{0,0,0, 0,0,0,1,1,0,1, 0, 0,1,0,1, 0}, // kernel code segment
|
|||
{0,0,0, 0,1,0,0,1,0,1, 0, 0,0,1,1, 0}, // kernel data segment
|
|||
{0,0,0, 0,0,0,1,1,0,1, 0, 0,1,0,1, 0}, // kernel code segment
|
|||
{0,0,0, 0,1,0,0,1,0,1, 0, 0,0,1,1, 0}, // kernel data segment
|
|||
/// 98a0
|
|||
// 92a0
|
|||
}; |
|||
|
|||
static_assert(sizeof(gdt) == 9 * sizeof(struct GDTentry)); |
|||
|
|||
// from gdt.s
|
|||
void _lgdt(void* gdt_desc_ptr); |
|||
|
|||
|
|||
struct GDTDescriptor gdt_descriptor = { |
|||
.size=sizeof(gdt)-1, |
|||
.offset=(uint64_t)gdt |
|||
}; |
|||
|
|||
#define PRINT_STRUCT(TARGET) \ |
|||
kprintf("&" #TARGET "=0x%8lx\tsizeof(" #TARGET ")=%ld (0x%lx)\n", \ |
|||
&TARGET, sizeof(TARGET),sizeof(TARGET)) |
|||
|
|||
volatile int y = 5421; |
|||
|
|||
void init_gdt_table() { |
|||
PRINT_STRUCT(gdt); |
|||
PRINT_STRUCT(gdt[0]); |
|||
_lgdt(&gdt_descriptor); |
|||
} |
@ -0,0 +1,7 @@ |
|||
#ifndef GDT_H |
|||
#define GDT_H |
|||
|
|||
void init_gdt_table(); |
|||
|
|||
|
|||
#endif // GDT_H
|
@ -0,0 +1,67 @@ |
|||
[bits 64] |
|||
|
|||
|
|||
section .text |
|||
global _lgdt |
|||
global _cr3 |
|||
extern gdt_descriptor |
|||
; argument in RDI |
|||
_lgdt: |
|||
call _lgdt2 |
|||
;pop rax |
|||
|
|||
push qword 1234 |
|||
pop rax |
|||
;cmp rax, 1234 |
|||
;a: je a |
|||
ret |
|||
|
|||
_lgdt2: |
|||
cli |
|||
;sgdt [gdt_descriptor] |
|||
|
|||
;sub dword [gdt_descriptor], 4*8 |
|||
;add qword [gdt_descriptor+2], 4*8 |
|||
|
|||
;mov rax, qword [gdt_descriptor+2] |
|||
|
|||
;mov qword [rax], 0 |
|||
|
|||
lgdt [gdt_descriptor] |
|||
;ret |
|||
|
|||
mov rax, rsp |
|||
push qword 0x30 |
|||
;0x30 |
|||
push qword rax |
|||
pushf |
|||
push qword 0x28 |
|||
push qword far_ret |
|||
iretq |
|||
|
|||
far_ret: |
|||
;mov ax, ds |
|||
mov ax, 0x30 |
|||
mov ds, ax |
|||
mov ss, ax |
|||
mov es, ax |
|||
mov fs, ax |
|||
mov gs, ax |
|||
ret |
|||
|
|||
|
|||
_cr3: |
|||
mov rax, rdi |
|||
mov cr3, rax |
|||
ret |
|||
|
|||
global test |
|||
test: |
|||
mov rax, 0xff00ff |
|||
ret |
|||
dq 0 |
|||
endtest: TIMES 64 dq 0 |
|||
|
|||
section .data |
|||
global test_size |
|||
test_size: dq endtest - test |
@ -0,0 +1,16 @@ |
|||
#include <stdint.h> |
|||
#include "kalloc.h" |
|||
#include "../common.h" |
|||
|
|||
static void* brk = (void *) 0x00800000; |
|||
|
|||
|
|||
void* kmalloc(size_t size) { |
|||
void* ptr = brk; |
|||
brk = mallign16(brk+size); |
|||
return ptr; |
|||
} |
|||
|
|||
void kfree(void* ptr) { |
|||
|
|||
} |
@ -0,0 +1,6 @@ |
|||
#pragma once |
|||
|
|||
#include <stddef.h> |
|||
|
|||
void* kmalloc(size_t size); |
|||
void kfree(void* p); |
@ -0,0 +1,17 @@ |
|||
#include "registers.h" |
|||
/*
|
|||
void set_ds(u16 e) { |
|||
__asm__ __volatile__ ("movw %0, %%ds" ::"=r"(e): "ds"); |
|||
} |
|||
|
|||
u16 _ds(void) { |
|||
u16 ret; |
|||
__asm__ __volatile__ ("movw %%cs, %0" :"r"(ret):); |
|||
return ret; |
|||
} |
|||
u16 _ds(void); |
|||