Browse Source

a bunch of added stuff

master
Mathieu Serandour 1 year ago
parent
commit
9c530a8ebd
  1. 8
      .gitignore
  2. 80
      Makefile
  3. BIN
      disk.hdd
  4. BIN
      disk_root/EFI/BOOT/BOOTX64.EFI
  5. 32
      disk_root/boot/limine.cfg
  6. 97
      kernel/Makefile
  7. 39
      kernel/common.h
  8. 14
      kernel/debug/assert.c
  9. 17
      kernel/debug/assert.h
  10. 25
      kernel/debug/panic.c
  11. 10
      kernel/debug/panic.h
  12. 317
      kernel/entry.c
  13. 4
      kernel/klib/Makefile
  14. 203
      kernel/klib/sprintf.c
  15. 19
      kernel/klib/sprintf.h
  16. 418
      kernel/klib/string.c
  17. 84
      kernel/klib/string.h
  18. 61
      kernel/linker.ld
  19. 88
      kernel/memory/gdt.c
  20. 7
      kernel/memory/gdt.h
  21. 67
      kernel/memory/gdt.s
  22. 16
      kernel/memory/kalloc.c
  23. 6
      kernel/memory/kalloc.h
  24. 17
      kernel/registers.c
  25. 21
      kernel/registers.h
  26. 13
      kernel/regs.h
  27. 41
      kernel/regs.s
  28. 20
      kernel/video/terminal.c
  29. 16
      kernel/video/terminal.h
  30. 213
      kernel/video/video.c
  31. 36
      kernel/video/video.h
  32. BIN
      resources/bmp/charmap.bmp

8
.gitignore

@ -1,5 +1,5 @@
.vscode
img_moint
*.o
include_cp
.vscode
img_moint
*.o
include_cp
*.elf

80
Makefile

@ -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

BIN
disk.hdd

Binary file not shown.

BIN
disk_root/EFI/BOOT/BOOTX64.EFI

Binary file not shown.

32
disk_root/boot/limine.cfg

@ -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

97
kernel/Makefile

@ -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)

39
kernel/common.h

@ -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

14
kernel/debug/assert.c

@ -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);
}

17
kernel/debug/assert.h

@ -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")

25
kernel/debug/panic.c

@ -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();
}

10
kernel/debug/panic.h

@ -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);

317
kernel/entry.c

@ -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");
}
}

4
kernel/klib/Makefile

@ -0,0 +1,4 @@
test:
del -f a.exe
gcc test.c sprintf.c string.c
a.exe

203
kernel/klib/sprintf.c

@ -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;
}

19
kernel/klib/sprintf.h

@ -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

418
kernel/klib/string.c

@ -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;
}

84
kernel/klib/string.h

@ -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

61
kernel/linker.ld

@ -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*)
}
}

88
kernel/memory/gdt.c

@ -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);
}

7
kernel/memory/gdt.h

@ -0,0 +1,7 @@
#ifndef GDT_H
#define GDT_H
void init_gdt_table();
#endif // GDT_H

67
kernel/memory/gdt.s

@ -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

16
kernel/memory/kalloc.c

@ -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) {
}

6
kernel/memory/kalloc.h

@ -0,0 +1,6 @@
#pragma once
#include <stddef.h>
void* kmalloc(size_t size);
void kfree(void* p);

17
kernel/registers.c

<
@ -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);