17 Commits

Author SHA1 Message Date
e850dabc8b feat: small code optimisations 2022-05-14 16:59:04 +02:00
6d898c07e8 feat: added not implemented function 2021-10-07 19:29:49 +02:00
03f0ec6f88 feat: Vfs and Ext2 support. Code style/attribute improvements
Added VFS and Ext2 support.
Optimized attributes of methods to improve code highlighting.
Printf attribute, malloc attribute, etc.
2021-10-06 21:45:15 +02:00
073051c99e feat: cleanup init code, small other refactors 2021-09-01 21:43:21 +02:00
e693b12915 feat: added missing lapic code 2021-08-30 19:58:50 +02:00
e37222c346 feat: added basic ACPI support using LAI 2021-08-30 19:56:36 +02:00
462dd90890 feat: removed unused cmake directory 2021-08-30 19:50:28 +02:00
a7bd154c32 feat: made string.h and string.c more compliant 2021-08-30 19:47:39 +02:00
ad023a8119 Updated pic init 2021-08-22 19:59:55 +02:00
6b0f6ddfb7 feat added init function 2021-08-13 21:07:40 +02:00
8187265735 feat: free the name of the task when it is ended 2021-08-13 08:18:35 +02:00
f047e692c9 feat: moved file system code around 2021-08-12 21:44:10 +02:00
c172a5cb8a feat: added state to ps output 2021-08-12 20:42:06 +02:00
3034a5d417 feat: added ps command 2021-08-12 20:31:11 +02:00
94c6332e27 feat: added task names 2021-08-12 20:22:00 +02:00
be71f9a7e9 feat: added reaper and suicide support 2021-08-06 22:00:00 +02:00
ee4338fedd feat: added some comments to command.c 2021-08-06 20:50:38 +02:00
82 changed files with 2655 additions and 595 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "lai"]
path = lai
url = https://github.com/managarm/lai.git

View File

@@ -7,20 +7,21 @@ SET(CMAKE_C_COMPILER ${COMPILER_RT}/i686-elf-gcc)
SET(CMAKE_ASM_COMPILER ${COMPILER_RT}/i686-elf-gcc) SET(CMAKE_ASM_COMPILER ${COMPILER_RT}/i686-elf-gcc)
# Optionally enable cmake debugging # Optionally enable cmake debugging
#SET(CMAKE_VERBOSE_MAKEFILE ON) SET(CMAKE_VERBOSE_MAKEFILE ON)
# Set compile flags # Set compile flags
SET(CMAKE_C_FLAGS "-g -ffreestanding -Wall -Wextra -fno-exceptions -fstack-protector -fno-pie -m32") SET(CMAKE_C_FLAGS "-g -ffreestanding -Wall -Wextra -fno-exceptions -fstack-protector -fno-pie -m32")
SET(CMAKE_ASM_FLAGS "${CFLAGS} -m32 -x assembler-with-cpp") SET(CMAKE_ASM_FLAGS "${CFLAGS} -m32 -x assembler-with-cpp")
SET(CMAKE_EXE_LINKER_FLAGS "-T${CMAKE_CURRENT_LIST_DIR}/linker.ld -lgcc -ffreestanding -nostdlib -no-pie") SET(CMAKE_EXE_LINKER_FLAGS "-T${CMAKE_CURRENT_LIST_DIR}/linker.ld -nostdlib -lgcc")
include_directories(AFTER include) include_directories(AFTER include lai/include)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
FILE(GLOB lai lai/core/*.c lai/helpers/*.c lai/driver/*.c)
FILE(GLOB_RECURSE kernel_src kernel/**.c) FILE(GLOB_RECURSE kernel_src kernel/**.c)
FILE(GLOB_RECURSE kernel_asm kernel/**.S) FILE(GLOB_RECURSE kernel_asm kernel/**.S)
FILE(GLOB_RECURSE boot_asm boot/boot.S boot/bootpaging.S) FILE(GLOB_RECURSE boot_asm boot/boot.S)
add_compile_definitions(__kernel__) add_compile_definitions(__kernel__)
@@ -31,9 +32,11 @@ add_compile_definitions(ENABLE_SELF_TEST) # Support for pretty printing pci cla
add_compile_definitions(ENABLE_PCIPP) # Support for pretty printing pci class/subclass/interface add_compile_definitions(ENABLE_PCIPP) # Support for pretty printing pci class/subclass/interface
add_compile_definitions(K_SHELL) add_compile_definitions(K_SHELL)
add_executable(my-kernel.bin ${kernel_src} ${kernel_asm} ${boot_asm}) # find libgcc.a
add_library(libgcc STATIC IMPORTED)
set_target_properties(libgcc PROPERTIES IMPORTED_LOCATION ${COMPILER_RT}/../lib/gcc/i686-elf/10.2.0/libgcc.a)
add_executable(my-kernel.bin ${kernel_src} ${kernel_asm} ${boot_asm} ${lai})
target_link_libraries(my-kernel.bin libgcc)
set_source_files_properties(${kernel_src} PROPERTIES LANGUAGE C COMPILE_FLAGS "") set_source_files_properties(${kernel_src} PROPERTIES LANGUAGE C COMPILE_FLAGS "")
set_target_properties(my-kernel.bin PROPERTIES LINKER_LANGUAGE C PREFIX "" SUFFIX "" LINK_FLAGS "") set_target_properties(my-kernel.bin PROPERTIES LINKER_LANGUAGE C PREFIX "" SUFFIX "" LINK_FLAGS "")

View File

@@ -19,7 +19,7 @@ forced to be within the first 8 KiB of the kernel file.
.long CHECKSUM .long CHECKSUM
#.include "gdt.S" #.include "gdt.S"
.section .boot.data, "aw", @progbits .section .data
gdt: gdt:
.quad 0x0000000000000000 .quad 0x0000000000000000
.quad 0x00CF9A000000FFFF .quad 0x00CF9A000000FFFF
@@ -42,7 +42,7 @@ System V ABI standard and de-facto extensions. The compiler will assume the
stack is properly aligned and failure to align the stack will result in stack is properly aligned and failure to align the stack will result in
undefined behavior. undefined behavior.
*/ */
.section .boot.bss, "aw", @nobits .section .bss
.align 16 .align 16
stack_bottom: stack_bottom:
.skip 16384 # 16 KiB .skip 16384 # 16 KiB
@@ -53,10 +53,7 @@ The linker script specifies _start as the entry point to the kernel and the
bootloader will jump to this position once the kernel has been loaded. It bootloader will jump to this position once the kernel has been loaded. It
doesn't make sense to return from this function as the bootloader is gone. doesn't make sense to return from this function as the bootloader is gone.
*/ */
.section .boot.text, "ax", @progbits .section .text
.extern _boot_paging
.global _start .global _start
.type _start, @function .type _start, @function
_start: _start:
@@ -80,8 +77,6 @@ _start:
*/ */
mov $stack_top, %esp mov $stack_top, %esp
call _boot_paging
// store multiboot on stack // store multiboot on stack
pushl 0 pushl 0
pushl %eax // MB code pushl %eax // MB code
@@ -106,13 +101,6 @@ _start:
movw %ax,%gs movw %ax,%gs
ljmp $0x8, $continue_boot ljmp $0x8, $continue_boot
/*
Set the size of the _start symbol to the current location '.' minus its start.
This is useful when debugging or when you implement call tracing.
*/
.size _start, . - _start
.section .text
continue_boot: continue_boot:
sti sti
/* /*
@@ -141,3 +129,9 @@ continue_boot:
cli cli
1: #hlt 1: #hlt
jmp 1b jmp 1b
/*
Set the size of the _start symbol to the current location '.' minus its start.
This is useful when debugging or when you implement call tracing.
*/
.size _start, . - _start

View File

@@ -1,51 +0,0 @@
.code32
.extern boot_paging_directory
.extern boot_primary_table
.section .boot.text, "ax", @progbits
.global _boot_paging
.type _boot_paging, @function
_boot_paging:
push %ebp
mov %esp, %ebp
pusha
# Physical address of paging table 1
# movl $(boot_primary_table - 0xC0000000), %edi
movl $(boot_primary_table - 0xC0000000), %edi
movl $0, %esi
movl $1024, %ecx
cmpl %esi, %ecx
_boot_paging_loop:
# stop when after kernel's last address
# cmpl $(_kernel_end -0xC0000000), %esi
cmpl $(_kernel_end), %esi
jge _boot_paging_after_kernel
# make address present and writable
movl %esi, %edx
orl $0x003, %edx
movl %edx, (%edi)
# next address
addl $4096, %esi
addl $4, %edi
loop _boot_paging_loop
_boot_paging_after_kernel:
# write to directory
movl $(boot_primary_table - 0xC0000000 + 0x003), boot_paging_directory - 0xC0000000 + 0
movl $(boot_primary_table - 0xC0000000 + 0x003), boot_paging_directory - 0xC0000000 + 768 * 4
# write paging directory to cr3
movl $(boot_paging_directory - 0xC0000000), %ecx
movl %ecx, %cr3
# enable paging and write protect in cr0
movl %cr0, %ecx
orl $0x80010000, %ecx
movl %ecx, %cr0
_boot_pagin_end:
popa
pop %ebp
ret

View File

@@ -1,10 +0,0 @@
FIND_PATH(GCC_INCLUDES_INCLUDE_DIR cpuid.h
/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include
)
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set APACHE_FOUND to TRUE if
# all listed variables are TRUE
find_package_handle_standard_args(GCC_INCLUDES DEFAULT_MSG GCC_INCLUDES_INCLUDE_DIR )
MARK_AS_ADVANCED(GCC_INCLUDES_INCLUDE_DIR)

View File

@@ -11,6 +11,7 @@
// function // function
#define att_noreturn __attribute((noreturn)) #define att_noreturn __attribute((noreturn))
#define att_cdecl __attribute((cdecl)) #define att_cdecl __attribute((cdecl))
#define att_unused __attribute((unused))
// structure // structure
#define att_packed __attribute((packed)) #define att_packed __attribute((packed))
// field // field

10
include/myke/acpi/acpi.h Normal file
View File

@@ -0,0 +1,10 @@
//
// Created by rick on 22-08-21.
//
#ifndef NEW_KERNEL_ACPI_H
#define NEW_KERNEL_ACPI_H
void* acpi_find_table_by_name(const char* name, int skip);
#endif //NEW_KERNEL_ACPI_H

View File

@@ -0,0 +1,256 @@
//
// Created by rick on 22-08-21.
//
#ifndef NEW_KERNEL_STRUCTURES_H
#define NEW_KERNEL_STRUCTURES_H
#include <attributes.h>
#include <stdbool.h>
#include <sys/types.h>
#define RDSP_SIGNATURE_LENGTH 8
#define RSDP_SIGNATURE "RSD PTR "
enum generic_address_structure_address_space {
system_memory = 0,
system_io = 1,
pci_config_space = 2,
embedded_controller = 3,
system_management_bus = 4,
system_cmos = 5,
pci_device_bar = 6,
ipmi = 7,
gpio = 8,
gsb = 9,
pmc = 0x0A
};
enum generic_address_structure_access_size {
undefined = 0,
uint8 = 1,
uint16 = 2,
uint32 = 3,
uint64 = 4,
};
struct generic_address_structure {
uint8_t address_space;
uint8_t bit_width;
uint8_t bit_offset;
uint8_t access_size;
uint64_t address;
};
struct acpi_rsdp_descriptor {
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
} att_packed;
struct acpi_rsdp_descriptor_20 {
struct acpi_rsdp_descriptor rsdp;
uint32_t length;
uint64_t xsdt_address;
uint8_t extended_checksum;
uint32_t: 24; // reserved
} att_packed;
struct acpi_sdt_header {
char signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
char oem_id[6];
char oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
} att_packed;
struct acpi_rsdt {
struct acpi_sdt_header header;
uint32_t pointer_to_other_sdt[];
} att_packed;
struct acpi_xsdt {
struct acpi_sdt_header header;
uint64_t pointer_to_other_sdt[];
} att_packed;
struct acpi_fadt {
struct acpi_sdt_header header;
uint32_t firmware_ctrl;
uint32_t dsdt;
// field used in ACPI 1.0; no longer in use, for compatibility only
uint8_t: 8;
uint8_t preferred_power_management_profile;
uint16_t sci_interrupt;
uint32_t smi_command_port;
uint8_t acpi_enable;
uint8_t acpi_disable;
uint8_t s4bios_req;
uint8_t pstate_control;
uint32_t pm1a_event_block;
uint32_t pm1b_event_block;
uint32_t pm1a_control_block;
uint32_t pm1b_control_block;
uint32_t pm2_control_block;
uint32_t pm_timer_block;
uint32_t gpe0_block;
uint32_t gpe1_block;
uint8_t pm1_event_length;
uint8_t pm1_control_length;
uint8_t pm2_control_length;
uint8_t pm_timer_length;
uint8_t gpe0_length;
uint8_t gpe1_length;
uint8_t gpe1_base;
uint8_t cstate_control;
uint16_t worst_c2_latency;
uint16_t worst_c3_latency;
uint16_t flush_size;
uint16_t flush_stride;
uint8_t duty_offset;
uint8_t duty_width;
uint8_t day_alarm;
uint8_t month_alarm;
uint8_t century;
// reserved in ACPI 1.0; used since ACPI 2.0+
uint16_t boot_architecture_flags;
uint8_t: 8;
uint32_t flags;
// 12 byte structure; see below for details
struct generic_address_structure reset_reg;
uint8_t reset_value;
uint16_t arm_boot_arch;
uint8_t fadt_minor_version;
// 64bit pointers - Available on ACPI 2.0+
uint64_t x_firmware_control;
uint64_t x_dsdt;
struct generic_address_structure x_pm1a_event_block;
struct generic_address_structure x_pm1b_event_block;
struct generic_address_structure x_pm1a_control_block;
struct generic_address_structure x_pm1b_control_block;
struct generic_address_structure x_pm2_control_block;
struct generic_address_structure x_pm_timer_block;
struct generic_address_structure x_gpe0_block;
struct generic_address_structure x_gpe1_block;
struct generic_address_structure sleep_control_register;
struct generic_address_structure sleep_status_register;
uint64_t hypervisor_id;
} att_packed;
#define MADT_TYPE_PROCESSOR_LOCAL_APIC 0
#define MADT_TYPE_IO_APIC 1
#define MADT_TYPE_IO_APIC_INTERRUPT_SOURCE_OVERRIDE 2
#define MADT_TYPE_IO_APIC_NON_MASKABLE_INTERRUPT_SOURCE 3
#define MADT_TYPE_LOCAL_APIC_NON_MASKABLE_INTERRUPTS 4
#define MADT_TYPE_LOCAL_APIC_ADDRESS_OVERRIDE 5
#define MADT_TYPE_PROCESSOR_LOCAL_X2_APIC 9
union madt_local_apic_flags {
uint32_t flags_int;
struct {
bool processor_enabled: 1;
bool online_capable: 1;
} flags;
};
union madt_interrupt_flags {
uint16_t flags_int;
struct {
bool: 1; // 1
bool active_low: 1; // 2
bool: 1; // 4
bool level_triggered: 1; // 8
} att_packed;
};
struct acpi_madt {
struct acpi_sdt_header header;
uint32_t local_apic_addr;
union {
uint32_t flags_int;
struct {
bool dual_8259_legacy_pics: 1;
};
};
uint8_t entries[];
} att_packed;
struct acpi_madt_entry_header {
uint8_t type;
uint8_t length;
} att_packed;
struct acpi_madt_local_apic { // type 0
struct acpi_madt_entry_header header;
uint8_t processor_id;
uint8_t apic_id;
union madt_local_apic_flags flags;
} att_packed;
struct acpi_madt_io_apic { // type 1
struct acpi_madt_entry_header header;
uint8_t apic_id;
uint8_t: 8; // reserved
uint32_t io_apic_address;
uint32_t global_system_interrupt_base;
} att_packed;
struct acpi_madt_io_apic_interrupt_source_override { // type 2
struct acpi_madt_entry_header header;
uint8_t bus_source;
uint8_t irq_source;
uint32_t global_system_interrupt;
union madt_interrupt_flags flags;
} att_packed;
struct acpi_madt_io_apic_non_maskable_interrupt { // type 3
struct acpi_madt_entry_header header;
uint8_t nmi_source;
uint8_t: 8; // reserved
union madt_interrupt_flags flags;
uint32_t global_system_interrupt;
} att_packed;
struct acpi_madt_local_apic_non_maskable_interrupts {
struct acpi_madt_entry_header header;
uint8_t acpi_processor_id;
union madt_interrupt_flags flags;
uint8_t lint_no;
} att_packed;
struct acpi_madt_local_apic_address_override {
struct acpi_madt_entry_header header;
uint16_t: 16; // reserved
uint64_t physical_address_local_apic;
} att_packed;
struct acpi_madt_processor_local_x2_apic {
struct acpi_madt_entry_header header;
uint16_t: 16; // reserved
uint32_t processors_local_x2_apic_id;
union madt_local_apic_flags flags;
uint32_t acpi_id;
} att_packed;
struct acpi_type {
char name[4];
char *description;
void (*handle_table)(const struct acpi_sdt_header *addr);
};
#endif //NEW_KERNEL_STRUCTURES_H

View File

@@ -9,6 +9,4 @@
void store_bootloader_info(multiboot_info_t *multiboot_info); void store_bootloader_info(multiboot_info_t *multiboot_info);
void main_loop(void *data);
#endif //NEW_KERNEL_COMMAND_H #endif //NEW_KERNEL_COMMAND_H

View File

@@ -7,74 +7,13 @@
#include <stdbool.h> #include <stdbool.h>
typedef struct { enum {
bool sse3: 1; CPUID_VENDOR_ID = 0x00,
bool pclmul: 1; CPUID_FEATURE_FLAGS = 0x01,
bool dtes64: 1; CPUID_CACHE
bool monitor: 1; };
bool ds_cpl: 1;
bool vmx: 1;
bool smx: 1;
bool est: 1;
bool tm2: 1;
bool ssse3: 1;
bool cid: 1;
bool reserved: 1;
bool fma: 1;
bool cx16: 1;
bool etprd: 1;
bool pdcm: 1;
bool pcide: 1;
bool dca: 1;
bool sse4_1: 1;
bool sse4_2: 1;
bool x2APIC: 1;
bool movbe: 1;
bool popcnt: 1;
bool reserved2: 1;
bool aes: 1;
bool xsave: 1;
bool osxsave: 1;
bool avx: 1;
} cpu_features_ecx;
typedef struct { enum {
bool fpu: 1;
bool vme: 1;
bool de: 1;
bool pse: 1;
bool tsc: 1;
bool msr: 1;
bool pae: 1;
bool mce: 1;
bool cx8: 1;
bool apic: 1;
bool reserved: 1;
bool sep: 1;
bool mtrr: 1;
bool pge: 1;
bool mca: 1;
bool cmov: 1;
bool pat: 1;
bool pse36: 1;
bool psn: 1;
bool clf: 1;
bool reserved2: 1;
bool dtes: 1;
bool acpi: 1;
bool mmx: 1;
bool fxsr: 1;
bool sse: 1;
bool sse2: 1;
bool ss: 1;
bool htt: 1;
bool tm1: 1;
bool ia64: 1;
bool pbe: 1;
} cpu_features_edx;
enum cpu_features {
CPUID_FEAT_ECX_SSE3 = 1 << 0, CPUID_FEAT_ECX_SSE3 = 1 << 0,
CPUID_FEAT_ECX_PCLMUL = 1 << 1, CPUID_FEAT_ECX_PCLMUL = 1 << 1,
CPUID_FEAT_ECX_DTES64 = 1 << 2, CPUID_FEAT_ECX_DTES64 = 1 << 2,
@@ -134,6 +73,8 @@ enum cpu_features {
CPUID_FEAT_EDX_PBE = 1 << 31 CPUID_FEAT_EDX_PBE = 1 << 31
}; };
static bool has_apic();
void cpuidx_print_info(); void cpuidx_print_info();
#endif //NEW_KERNEL_CPUIDX_H #endif //NEW_KERNEL_CPUIDX_H

23
include/myke/cpu/lapic.h Normal file
View File

@@ -0,0 +1,23 @@
//
// Created by rick on 23-08-21.
//
#ifndef NEW_KERNEL_LAPIC_H
#define NEW_KERNEL_LAPIC_H
#include <sys/types.h>
#define LAPIC_REG_ID 0x20
#define LAPIC_REG_VERSION 0x30
void lapic_set_addr(uint32_t addr);
void lapic_write(uint32_t offset, uint32_t value);
uint32_t lapic_read(uint32_t offset);
uint32_t lapic_get_id();
uint32_t lapic_get_version();
#endif //NEW_KERNEL_LAPIC_H

17
include/myke/cpu/pic.h Normal file
View File

@@ -0,0 +1,17 @@
//
// Created by rick on 22-08-21.
//
#ifndef NEW_KERNEL_PIC_H
#define NEW_KERNEL_PIC_H
#include <stdbool.h>
#include <sys/types.h>
void pic_init(uint8_t isr_offset);
void pic_set_mask(uint16_t mask);
void pic_eoi(bool slave);
#endif //NEW_KERNEL_PIC_H

View File

@@ -7,12 +7,12 @@
#include <sys/types.h> #include <sys/types.h>
int init_timer(uint32_t freq); int pit_int_frequency(uint32_t freq);
void print_current_tick(); void print_current_tick();
uint32_t timer_get_tick(); uint32_t pit_get_tick();
void sleep(uint32_t milliseconds); void pit_sleep(uint32_t milliseconds);
#endif //MY_KERNEL_TIMER_H #endif //MY_KERNEL_TIMER_H

View File

@@ -19,8 +19,6 @@ typedef struct KeyEvent_t {
char getc(); char getc();
void init_keyboard();
//const char *key_code_to_string(KeyCode key); //const char *key_code_to_string(KeyCode key);
KeyEvent *get_next_event(); KeyEvent *get_next_event();

View File

@@ -1,12 +0,0 @@
//
// Created by rick on 28-01-21.
//
#ifndef NEW_KERNEL_SERIAL_H
#define NEW_KERNEL_SERIAL_H
int serial_init();
void serial_kprint(const char *msg);
#endif //NEW_KERNEL_SERIAL_H

View File

@@ -27,8 +27,4 @@
#define VGA_COL_MAX 80 #define VGA_COL_MAX 80
#define VGA_ROW_MAX 25 #define VGA_ROW_MAX 25
void vga_clear_screen();
void vga_kprint(const char *msg);
#endif //MY_KERNEL_VGASCREEN_H #endif //MY_KERNEL_VGASCREEN_H

View File

@@ -17,6 +17,4 @@ void kprint(const char *msg);
void kprint_sync(const char *msg); void kprint_sync(const char *msg);
void kprint_init(); void kprint_init();
void kprint_start_task();

View File

@@ -21,4 +21,6 @@ void att_noreturn k_panics(const char *msg);
void att_noreturn k_panic(); void att_noreturn k_panic();
void att_noreturn k_not_implemented();
#endif //NEW_KERNEL_LIBK_H #endif //NEW_KERNEL_LIBK_H

View File

@@ -12,6 +12,7 @@
#define SYSCALL_YIELD_JOB 0x02 #define SYSCALL_YIELD_JOB 0x02
#define SYSCALL_YIELD_IRQ 0x03 #define SYSCALL_YIELD_IRQ 0x03
#define SYSCALL_SUSPEND 0x04 #define SYSCALL_SUSPEND 0x04
#define SYSCALL_KILL_SELF 0x05
void att_noreturn syscall_start_scheduler(); void att_noreturn syscall_start_scheduler();
@@ -21,4 +22,6 @@ void syscall_yield_irq(uint16_t irq);
void syscall_job_suspend(); void syscall_job_suspend();
void syscall_kill_self();
#endif //NEW_KERNEL_SYSCALL_H #endif //NEW_KERNEL_SYSCALL_H

View File

@@ -7,7 +7,7 @@
// retrieved from https://github.com/blanham/liballoc // retrieved from https://github.com/blanham/liballoc
#include <sys/types.h> #include <sys/types.h>
void *malloc(size_t); void __attribute__((assume_aligned (16), alloc_size (1), malloc)) *malloc(size_t);
void *realloc(void *, size_t); void *realloc(void *, size_t);

View File

@@ -0,0 +1,8 @@
//
// Created by rick on 21-02-21.
//
#ifndef NEW_KERNEL_PAGING_H
#define NEW_KERNEL_PAGING_H
#endif //NEW_KERNEL_PAGING_H

View File

@@ -1,19 +0,0 @@
//
// Created by rick on 23-02-21.
//
#ifndef NEW_KERNEL_PM_H
#define NEW_KERNEL_PM_H
#include <sys/types.h>
// 4k blocks
#define PAGE_SIZE 4096
void pm_init(void *start_addr, size_t size);
void *pm_get_pages(uint32_t num_pages);
void pm_free_pages(void *page, uint32_t num_pages);
#endif //NEW_KERNEL_PM_H

19
include/myke/mem/pmm.h Normal file
View File

@@ -0,0 +1,19 @@
//
// Created by rick on 23-02-21.
//
#ifndef NEW_KERNEL_PMM_H
#define NEW_KERNEL_PMM_H
#include <sys/types.h>
// 4k blocks
#define PAGE_SIZE 4096
void pmm_init(void *start_addr, size_t size);
void *pmm_get_pages(uint32_t num_pages);
void pmm_free_pages(void *page, uint32_t num_pages);
#endif //NEW_KERNEL_PMM_H

View File

@@ -1,13 +0,0 @@
//
// Created by rick on 21-02-21.
//
#ifndef NEW_KERNEL_VMM_H
#define NEW_KERNEL_VMM_H
#include <sys/types.h>
void vmm_assign_page(void *paddr, void *vaddr, size_t number_of_pages);
void vmm_unassign_page(void *vaddr, size_t number_of_pages);
#endif //NEW_KERNEL_VMM_H

View File

@@ -19,15 +19,15 @@ void task_start_first();
void task_switch_next(); void task_switch_next();
uint32_t task_spawn(task_entrypoint, void *entry_data); pid_t task_spawn(task_entrypoint, void *entry_data, char *name);
void task_end(uint32_t tid); void task_end(pid_t tid);
void task_suspend(); void task_suspend();
uint32_t task_get_current_tid(); pid_t task_get_current_tid();
void task_signal(uint32_t tid); void task_signal(pid_t tid);
void task_lock_acquire(); void task_lock_acquire();
@@ -35,4 +35,6 @@ void task_ensure_enabled();
void task_lock_free(); void task_lock_free();
void task_print_all();
#endif //NEW_KERNEL_TASK_H #endif //NEW_KERNEL_TASK_H

30
include/myke/util/init.h Normal file
View File

@@ -0,0 +1,30 @@
//
// Created by rick on 13-08-21.
//
#ifndef NEW_KERNEL_INIT_H
#define NEW_KERNEL_INIT_H
#include <sys/types.h>
#include <myke/driver.h>
enum init_stage {
INIT_STAGE_EARLY_BOOT_0, // id mapped, high memory, no malloc
INIT_STAGE_EARLY_BOOT_1, // memory available, no tasking
INIT_STAGE_LATE_BOOT, // time source, memory, most basic hardware available
INIT_STAGE_PRE_TASKING, // just before tasking is ready
INIT_STAGE_AFTER_BOOT_PRE_INIT, // tasking just started
// todo define later stages
};
struct init {
const char *name;
enum init_stage stage;
void (*init)();
};
#define INIT_FUNCTION(order) GENERIC_DRIVER(init, order)
void init_execute_all(enum init_stage stage);
#endif //NEW_KERNEL_INIT_H

View File

@@ -9,6 +9,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <myke/driver.h> #include <myke/driver.h>
#define BLOCK_DEV_LBA_SIZE 512
#define BLOCK_DEV_ACCESS_OK 0 #define BLOCK_DEV_ACCESS_OK 0
#define BLOCK_DEV_ACCESS_ERR 1 #define BLOCK_DEV_ACCESS_ERR 1
@@ -27,21 +29,21 @@
typedef struct block_device block_device_t; typedef struct block_device block_device_t;
typedef uint8_t (*block_device_driver_check_device)(const block_device_t *device, uint8_t *first_sector); typedef uint8_t (*block_device_driver_check_device)(block_device_t *device);
typedef uint8_t (*block_device_driver_free)(const block_device_t *device); typedef uint8_t (*block_device_driver_free)(block_device_t *device);
typedef uint8_t (*block_device_access)(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, typedef uint8_t (*block_device_access)(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors,
void *target); void *target);
struct block_dev_driver { typedef struct block_dev_driver {
char name[16]; char name[16];
struct { struct {
uint8_t partitioning: 1; uint8_t partitioning: 1;
} flags; } flags;
block_device_driver_check_device check_device; block_device_driver_check_device check_device;
block_device_driver_free free_device; block_device_driver_free free_device;
} __attribute__((__aligned__(STRUCT_ALIGNMENT))); } __attribute__((__aligned__(STRUCT_ALIGNMENT))) block_dev_driver_t;
#define BLOCK_DEV_DRIVER(order) GENERIC_DRIVER(block_dev_driver, order) #define BLOCK_DEV_DRIVER(order) GENERIC_DRIVER(block_dev_driver, order)
@@ -59,6 +61,7 @@ struct block_device {
block_device_access access; block_device_access access;
struct block_dev_driver *driver; struct block_dev_driver *driver;
void *device_info; // pointer to driver defined structure void *device_info; // pointer to driver defined structure
void *driver_info; // pointer to driver defined structure
// todo device info // todo device info
}; };
@@ -66,10 +69,8 @@ uint8_t block_dev_register(block_device_t *device);
void block_dev_free(block_device_t *device); void block_dev_free(block_device_t *device);
void block_dev_start_task(); void *block_dev_mount(const char *device, const char *driver_name);
void block_dev_print_info(); void block_dev_print_info();
bool block_dev_mount(char *identifier, char *driver);
#endif //NEW_KERNEL_BLOCKDEV_H #endif //NEW_KERNEL_BLOCKDEV_H

223
include/myke/vfs/lfs/ext2.h Normal file
View File

@@ -0,0 +1,223 @@
//
// Created by rick on 18-09-21.
//
#ifndef NEW_KERNEL_EXT2_H
#define NEW_KERNEL_EXT2_H
#include <sys/types.h>
#include <attributes.h>
#define EXT2_SIGNATURE 0xEF53
#define EXT2_SB_ADDR 1024
#define EXT2_SB_SIZE 1024
#define EXT2_BGD_START_ADDR (EXT2_SB_ADDR + EXT2_SB_SIZE)
#define EXT2_DEFAULT_RESERVED_INODES 11
#define EXT2_DEFAULT_INODE_SIZE 128
#define EXT2_ROOT_INODE 2
typedef struct ext2_sb {
uint32_t total_inodes;
uint32_t total_blocks;
uint32_t num_reserved_su;
uint32_t unallocated_blocks;
uint32_t unallocated_inodes;
uint32_t no_blocks_with_sb;
uint32_t block_size;
uint32_t fragment_size;
uint32_t no_blocks_per_group;
uint32_t no_fragments_per_group;
uint32_t no_inodes_per_group;
uint32_t last_mounted;
uint32_t last_written;
uint16_t no_mounted_since_fschk;
uint16_t max_no_mounted_since_fschk;
uint16_t ext2_signature;
uint16_t fs_state;
uint16_t error_action;
uint16_t minor_version;
uint32_t last_fschk;
uint32_t interval_fschk;
uint32_t os_id;
uint32_t major_version;
uint16_t uid_reserved;
uint16_t gid_reserved;
// below extended fields
uint32_t first_nor_reserved_inode;
uint16_t size_inode;
uint16_t owner_bg;
uint32_t features_optional;
uint32_t features_required;
uint32_t features_ro;
uint8_t fs_id[16];
char fs_name[16];
char last_mounted_path[64];
uint32_t compression_alg;
uint8_t preallocate_files;
uint8_t preallocate_dirs;
uint16_t: 16; // unused
uint8_t journal_id[16];
uint32_t journal_inode;
uint32_t journal_device;
uint32_t head_of_orphan_inode_list;
} att_packed ext2_sb_t;
enum {
EXT2_FS_STATE_CLEAN = 1,
EXT2_FS_STATE_ERROR = 2,
};
enum {
EXT2_ERROR_ACTION_IGNORE = 1,
EXT2_ERROR_ACTION_REMOUNT_RO = 2,
EXT2_ERROR_ACTION_PANIC = 3,
};
enum {
EXT2_OS_ID_LINUX = 0,
EXT2_OS_ID_GNU_HURD = 1,
EXT2_OS_ID_MASIX = 2,
EXT2_OS_ID_FREE_BSD = 3,
EXT2_OS_ID_LITES = 4,
};
enum {
EXT2_FEATURE_OPTIONAL_PREALLOCATE = 0x01,
EXT2_FEATURE_OPTIONAL_AFS_SERVER_INODE = 0x02,
EXT2_FEATURE_OPTIONAL_HAS_JOURNAL = 0x04,
EXT2_FEATURE_OPTIONAL_EXTENDED_ATTRIBUTES = 0x08,
EXT2_FEATURE_OPTIONAL_CAN_RESIZE = 0x10,
EXT2_FEATURE_OPTIONAL_DIR_HASH_INDEX = 0x20,
};
#define EXT2_FEAT_OPT_SUPPORTED ( \
0 \
)
enum {
EXT2_FEATURE_REQUIRED_COMPRESSION = 0x01,
EXT2_FEATURE_REQUIRED_DIR_HAS_TYPE = 0x02,
EXT2_FEATURE_REQUIRED_JOURNAL_REPLAY_REQUIRED = 0x04,
EXT2_FEATURE_REQUIRED_HAS_JOURNAL_DEVICE = 0x08,
};
#define EXT2_FEAT_REQ_SUPPORTED ( \
EXT2_FEATURE_REQUIRED_DIR_HAS_TYPE | \
0 \
)
enum {
EXT2_FEATURE_RO_SPARSE_SUPERBLOCKS_AND_GROUPS_DESCRIPTOR = 0x01,
EXT2_FEATURE_RO_64BIT_SIZE = 0x02,
EXT2_FEATURE_RO_DIR_BTREE = 0X04
};
#define EXT2_FEAT_RO_64BIT_SIZE (SIZE_MAX > UINT32_MAX)
#define EXT2_FEAT_RO_SUPPORTED ( \
(EXT2_FEAT_RO_64BIT_SIZE ? EXT2_FEATURE_RO_64BIT_SIZE : 0) | \
0 \
)
typedef struct ext2_bg_descriptor {
uint32_t block_usage_bm;
uint32_t inode_usage_bm;
uint32_t start_block_inode;
uint16_t no_unallocated_blocks;
uint16_t no_unallocated_inodes;
uint16_t no_dirs;
uint8_t unused[14];
} ext2_bg_descriptor_t;
typedef struct ext2_inode {
union {
uint16_t type_permission;
struct {
uint8_t permission_o: 3;
uint8_t permission_g: 3;
uint8_t permission_u: 3;
bool permission_sticky: 1;
bool permission_setgid: 1;
bool permission_setuid: 1;
uint8_t type: 4;
} att_packed;
};
uint16_t uid;
uint32_t size_l;
uint32_t last_access;
uint32_t created;
uint32_t last_mod;
uint32_t deleted;
uint16_t gid;
uint16_t no_hard_links;
uint32_t no_sectors;
uint32_t flags;
uint32_t os_val1;
uint32_t dbp[12]; // fist 12 direct block pointers
uint32_t sibp;
uint32_t dibp;
uint32_t tibp;
uint32_t generation;
uint32_t extended_attr;
union {
uint32_t size_h;
uint32_t dir_acl;
};
uint32_t fragment_addr;
uint8_t os_val2[12];
} att_packed ext2_inode_t;
enum {
EXT2_INODE_FLAG_SECURE_DELETE = 0x00000001,
EXT2_INODE_FLAG_KEEP_COPY_ON_DELETE = 0x00000002,
EXT2_INODE_FLAG_FILE_COMPRESSION = 0x00000004,
EXT2_INODE_FLAG_SYNC_UPDATE = 0x00000008,
EXT2_INODE_FLAG_IMMUTABLE = 0x00000010,
EXT2_INODE_FLAG_APPEND_ONLY = 0x00000020,
EXT2_INODE_FLAG_NO_DUMP = 0x00000040,
EXT2_INODE_FLAG_LAST_ACCESS_IGNORE = 0x00000080,
EXT2_INODE_FLAG_HASH_INDEXED_DIR = 0x00010000,
EXT2_INODE_FLAG_AFS_DIRECTORY = 0x00020000,
EXT2_INODE_FLAG_JOURNAL_FILE_DATA = 0x00040000,
};
typedef struct ext2_dir_entry {
uint32_t inode;
uint16_t ent_size;
uint8_t name_size;
uint8_t type_or_name_size_h;
char name;
} ext2_dir_entry_t;
enum {
EXT2_INODE_TYPE_FIFO = 0x1,
EXT2_INODE_TYPE_CHAR_DEV = 0x2,
EXT2_INODE_TYPE_DIR = 0x4,
EXT2_INODE_TYPE_BLOCK_DEV = 0x6,
EXT2_INODE_TYPE_FILE = 0x8,
EXT2_INODE_TYPE_SYM_LINK = 0xA,
EXT2_INODE_TYPE_UNIX_SOCK = 0xC,
};
enum {
EXT2_DIR_TYPE_UNKNOWN = 0,
EXT2_DIR_TYPE_FILE = 1,
EXT2_DIR_TYPE_DIR = 2,
EXT2_DIR_TYPE_CHAR_DEV = 3,
EXT2_DIR_TYPE_BLOCK_DEV = 4,
EXT2_DIR_TYPE_FIFO = 5,
EXT2_DIR_TYPE_SOCKET = 6,
EXT2_DIR_TYPE_SOFT_LINK = 7,
};
typedef struct ext2_mount_info {
ext2_sb_t sb;
uint32_t no_block_groups;
uint64_t block_size;
uint64_t fragment_size;
void *block_dev;
} ext2_mount_info_t;
#endif //NEW_KERNEL_EXT2_H

View File

@@ -0,0 +1,36 @@
//
// Created by rick on 19-09-21.
//
#ifndef NEW_KERNEL_VFS_DRIVER_H
#define NEW_KERNEL_VFS_DRIVER_H
#include <myke/driver.h>
#include <myke/vfs/vfs.h>
typedef struct vfs_driver {
char name[16];
struct {
} flags;
// api
int (*vfs_mount)(vfs_mount_t *mount);
int (*open)(vfs_mount_t *mount, vfs_fd_t *dir, const char *path, int mode, vfs_fd_t *out);
int (*close)(vfs_mount_t *mount, vfs_fd_t *fd);
int (*fstat)(vfs_mount_t *mount, vfs_fd_t *fd, stat_t *target, int flags);
int (*fread)(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size);
int (*dgetent)(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size);
} __attribute__((__aligned__(STRUCT_ALIGNMENT))) vfs_driver_t;
void vfs_mk_dirent_record(vfs_dirent_t *ent, uint32_t inode, uint32_t cur_offset, uint8_t type, char *name,
size_t name_length);
#define VFS_DRIVER(order) GENERIC_DRIVER(vfs_driver, order)
#endif //NEW_KERNEL_VFS_DRIVER_H

70
include/myke/vfs/vfs.h Normal file
View File

@@ -0,0 +1,70 @@
//
// Created by rick on 19-09-21.
//
#ifndef NEW_KERNEL_VFS_H
#define NEW_KERNEL_VFS_H
#include <stdbool.h>
#include <sys/stat.h>
#define VFS_MOUNT_OK 0
#define VFS_MOUNT_ERROR 1
#define VFS_OPEN_ERROR 1
#define VFS_OPEN_OK 0
#define VFS_CLOSE_OK 1
#define VFS_READ_ERROR (-1)
#define VFS_DGETENTS_ERR 1
struct vfs_mount;
typedef struct vfs_mount {
struct {
} flags;
const char *prefix;
const char *device;
void *driver; // vfs_mount_driver_t
void *global_driver_data;
struct vfs_mount *next;
} vfs_mount_t;
typedef struct vfs_fd {
struct {
} flags;
vfs_mount_t *mount;
void *driver_data;
} vfs_fd_t;
#define VFS_DIRENT_BASE_SIZE (4 + 4 + 2 + 1)
#define VFS_DIRENT_SIZE(name_length) ((VFS_DIRENT_BASE_SIZE + (name_length) + 1 + 15) & (~0xF))
#define VFS_DIRENT_MAX_SIZE (VFS_DIRENT_BASE_SIZE + 256 + 1)
typedef struct vfs_dirent {
uint32_t inode;
uint32_t offset_next;
uint16_t reclen;
uint8_t type;
char name[];
} vfs_dirent_t;
int vfs_mount(const char *path, const char *device, const char *driver);
// https://man7.org/linux/man-pages/man2/open.2.html
vfs_fd_t *vfs_open(const char *path, int flags, int mode);
void vfs_close(vfs_fd_t *fd);
// https://man7.org/linux/man-pages/man2/stat.2.html
int vfs_fstat(vfs_fd_t *fd, stat_t *target, int flags);
// https://man7.org/linux/man-pages/man2/read.2.html
int vfs_read(vfs_fd_t *fd, void *target, size_t size);
// inspiration https://man7.org/linux/man-pages/man2/getdents.2.html
int vfs_getdents(vfs_fd_t *fd, void *target, int count);
#endif //NEW_KERNEL_VFS_H

View File

@@ -24,7 +24,7 @@ void fflush(FILE *);
FILE *fopen(const char *, const char *); FILE *fopen(const char *, const char *);
void fprintf(FILE *, const char *, ...); void __attribute__((format (printf, 2, 3))) fprintf(FILE *, const char *, ...);
size_t fread(void *, size_t, size_t, FILE *); size_t fread(void *, size_t, size_t, FILE *);
@@ -38,11 +38,11 @@ void setbuf(FILE *, char *);
int vfprintf(FILE *, const char *, va_list); int vfprintf(FILE *, const char *, va_list);
int vprintf(const char* fmt, va_list args); int vprintf(const char *fmt, va_list args);
int printf(const char *fmt, ...); int __attribute__((format (printf, 1, 2))) printf(const char *fmt, ...);
int sprintf(char *target, const char *fmt, ...); int __attribute__((format (printf, 2, 3))) sprintf(char *target, const char *fmt, ...);
#endif //NEW_KERNEL_STDIO_H #endif //NEW_KERNEL_STDIO_H

View File

@@ -21,7 +21,7 @@ int atexit(void (*)(void));
int atoi(const char *); int atoi(const char *);
char *itoa(int value, char *buffer, int base); char *itoa(uint32_t value, char *buffer, int base);
char *getenv(const char *); char *getenv(const char *);

View File

@@ -7,25 +7,31 @@
#include <stddef.h> #include <stddef.h>
int memcpy(void *dst, const void *src, size_t amount); void *memcpy(void *dst, const void *src, size_t amount);
int memset(void *dst, int data, size_t amount); void *memset(void *dst, int data, size_t amount);
int strcpy(char *dst, const char *src); void *memmove(void *dst, const void *src, size_t amount);
int strncpy(char *dst, const char *src, size_t n); void *strcpy(char *dst, const char *src);
void *strncpy(char *dst, const char *src, size_t n);
size_t strlen(const char *str); size_t strlen(const char *str);
const char *strchr(const char *s, char c); char *strchr(const char *s, char c);
const char *strrchr(const char *s, char c); char *strrchr(const char *s, char c);
int memcmp(const void *s1, const void *s2, size_t n); int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2); int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, int n); int strncmp(const char *s1, const char *s2, size_t n);
char *strdup(const char *s);
char *strndup(const char *s, size_t n);
char *strcat(char *dest, const char *src); char *strcat(char *dest, const char *src);

View File

@@ -7,5 +7,6 @@
#define MIN(a, b) (((a)<(b))?(a):(b)) #define MIN(a, b) (((a)<(b))?(a):(b))
#define MAX(a, b) (((a)>(b))?(a):(b)) #define MAX(a, b) (((a)>(b))?(a):(b))
#define DIV_ROUND_UP(a, b) (((a) + ((b) - 1)) / (b))
#endif //NEW_KERNEL_PARAM_H #endif //NEW_KERNEL_PARAM_H

50
include/sys/stat.h Normal file
View File

@@ -0,0 +1,50 @@
//
// Created by rick on 06-10-21.
//
#ifndef NEW_KERNEL_STAT_H
#define NEW_KERNEL_STAT_H
#include <time.h>
// https://man7.org/linux/man-pages/man2/stat.2.html
typedef uint32_t dev_t;
typedef uint32_t ino_t;
typedef uint32_t mode_t;
typedef uint32_t nlink_t;
typedef uint32_t uid_t;
typedef uint32_t gid_t;
typedef size_t off_t;
typedef size_t blksize_t;
typedef uint32_t blkcnt_t;
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
typedef struct stat stat_t;
#endif //NEW_KERNEL_STAT_H

View File

@@ -5,4 +5,10 @@
#ifndef NEW_KERNEL_TIME_H #ifndef NEW_KERNEL_TIME_H
#define NEW_KERNEL_TIME_H #define NEW_KERNEL_TIME_H
typedef uint32_t time_t;
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#endif //NEW_KERNEL_TIME_H #endif //NEW_KERNEL_TIME_H

284
kernel/acpi/acpi.c Normal file
View File

@@ -0,0 +1,284 @@
//
// Created by rick on 22-08-21.
//
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <lai/core.h>
#include <lai/helpers/pc-bios.h>
#include <myke/acpi/acpi.h>
#include <myke/acpi/structures.h>
#include <myke/cpu/lapic.h>
#include <myke/libk/libk.h>
#include <myke/util/init.h>
void acpi_handle_facp(const struct acpi_sdt_header *addr);
void acpi_handle_apic(const struct acpi_sdt_header *addr);
struct acpi_type acpi_types[] = {
{"APIC", "Multiple APIC Description Table (MADT)", acpi_handle_apic},
{"BGRT", "Boot Graphics Resource Table (BGRT; only supported on UEFI systems)", NULL},
{"BERT", "Boot Error Record Table (BERT)", NULL},
{"CPEP", "Corrected Platform Error Polling Table (CPEP)", NULL},
{"DSDT", "Differentiated System Description Table (DSDT)", NULL},
{"ECDT", "Embedded Controller Boot Resources Table (ECDT)", NULL},
{"EINJ", "Error Injection Table (EINJ)", NULL},
{"ERST", "Error Record Serialization Table (ERST)", NULL},
{"FACP", "Fixed ACPI Description Table (FADT)", acpi_handle_facp},
{"FACS", "Firmware ACPPI Control Structure (FACS)", NULL},
{"HEST", "Hardware Error Source Table (HEST)", NULL},
{"MSCT", "Maximum System Characteristics Table (MSCT)", NULL},
{"MPST", "Memory Power State Table (MPST)", NULL},
// {"OEMx", "OEM Specific Information Tables (Any table with a signature beginning with \"OEM\" falls into this definition)", NULL},
{"PMTT", "latform Memory Topology Table (PMTT)", NULL},
{"PSDT", "Persistent System Description Table (PSDT)", NULL},
{"RASF", "ACPI RAS FeatureTable (RASF)", NULL},
{"RSDT", "Root System Description Table (RSDT; 32-bit version of the XSDT)", NULL},
{"SBST", "Smart Battery Specification Table (SBST)", NULL},
{"SLIT", "System Locality System Information Table (SLIT)", NULL},
{"SRAT", "System Resource Affinity Table (SRAT)", NULL},
{"SSDT", "Secondary System Description Table (SSDT)", NULL},
{"XSDT", "Extended System Description Table (This wiki page; included for completeness)", NULL},
{"\0\0\0\0", NULL, NULL},
};
bool acpi_checksum(const void *table_addr, const size_t table_size) {
if (table_size < 1) {
return false; // invalid input
}
const uint8_t *table = table_addr;
uint8_t val = 0;
for (size_t i = 0; i < table_size; ++i) {
val += table[i];
}
return val == 0;
}
const struct acpi_rsdt *rsdt_table = NULL;
const struct acpi_xsdt *xsdt_table = NULL;
const struct acpi_fadt_t *fadt;
const struct acpi_sdt_header *dsdt;
void acpi_handle_facp(const struct acpi_sdt_header *addr) {
// parse the FACP/FADT
fadt = (const struct acpi_fadt_t *) addr;
if (fadt->header.revision > 5) {
// minor since 5.1
printf("ACPI Revision: %i.%i %.6s\n", fadt->header.revision, fadt->minor_version, fadt->header.oem);
} else {
printf("ACPI Revision: %i.0 %.6s\n", fadt->header.revision, fadt->header.oem);
}
if (fadt->x_dsdt != 0 && fadt->x_dsdt < UINT32_MAX) {
dsdt = (struct acpi_sdt_header *) fadt->x_dsdt;
} else if (fadt->dsdt != 0) {
dsdt = (struct acpi_sdt_header *) fadt->dsdt;
} else {
k_panics("No DSDT");
}
if (!acpi_checksum(dsdt, dsdt->length)) {
k_panics("DSDT is not valid");
}
}
void acpi_handle_apic(const struct acpi_sdt_header *addr) {
const struct acpi_madt *madt = (const struct acpi_madt *) addr;
printf("Local apic: %p %i\n", madt->local_apic_addr, madt->flags_int);
lapic_set_addr(madt->local_apic_addr);
const uint8_t *current = madt->entries;
const uint8_t *end = (const uint8_t *) (madt) + madt->header.length;
while (current < end) {
struct acpi_madt_entry_header *current_header = (struct acpi_madt_entry_header *) current;
switch (current_header->type) {
case MADT_TYPE_PROCESSOR_LOCAL_APIC: {
const struct acpi_madt_local_apic *la = (const struct acpi_madt_local_apic *) current_header;
printf("Local APIC %x for %x %x\n", la->apic_id, la->processor_id, la->flags);
break;
}
case MADT_TYPE_IO_APIC: {
const struct acpi_madt_io_apic *ia = (const struct acpi_madt_io_apic *) current_header;
printf("IO APIC %x at %x with %x\n", ia->apic_id, ia->io_apic_address,
ia->global_system_interrupt_base);
break;
}
case MADT_TYPE_IO_APIC_INTERRUPT_SOURCE_OVERRIDE: {
const struct acpi_madt_io_apic_interrupt_source_override *override = (const struct acpi_madt_io_apic_interrupt_source_override *) current_header;
printf("IO APIC Interrupt source override %x:%x -> %x %x\n", override->bus_source, override->irq_source,
override->global_system_interrupt, override->flags);
break;
}
case MADT_TYPE_IO_APIC_NON_MASKABLE_INTERRUPT_SOURCE: {
const struct acpi_madt_io_apic_non_maskable_interrupt *nmi = (const struct acpi_madt_io_apic_non_maskable_interrupt *) current_header;
printf("IO APIC NMI source %x %x %x\n", nmi->nmi_source, nmi->flags, nmi->global_system_interrupt);
break;
}
case MADT_TYPE_LOCAL_APIC_NON_MASKABLE_INTERRUPTS: {
const struct acpi_madt_local_apic_non_maskable_interrupts *nmi = (const struct acpi_madt_local_apic_non_maskable_interrupts *) current_header;
printf("Local APIC NMI CPU %x %x %x\n", nmi->acpi_processor_id, nmi->flags, nmi->lint_no);
break;
}
case MADT_TYPE_LOCAL_APIC_ADDRESS_OVERRIDE: {
const struct acpi_madt_local_apic_address_override *ao = (const struct acpi_madt_local_apic_address_override *) current_header;
printf("Local APIC addr override %x%x\n", ao->physical_address_local_apic >> 32,
ao->physical_address_local_apic & UINT32_MAX);
if (ao->physical_address_local_apic > UINT32_MAX) {
printf("Override above 4GB!");
} else {
lapic_set_addr(ao->physical_address_local_apic & UINT32_MAX);
}
break;
}
case MADT_TYPE_PROCESSOR_LOCAL_X2_APIC: {
const struct acpi_madt_processor_local_x2_apic *x2 = (const struct acpi_madt_processor_local_x2_apic *) current_header;
printf("Local x2APIC %x %x %x\n", x2->processors_local_x2_apic_id, x2->flags, x2->acpi_id);
break;
}
default:
printf("Unknown MADT entry %x", current_header->type);
break;
}
current += current_header->length;
}
printf("Lapic id %x v%x\n", lapic_get_id(), lapic_get_version());
}
void acpi_parse_table(uint32_t table_addr, uint32_t index) {
struct acpi_sdt_header *s_header = (struct acpi_sdt_header *) table_addr;
if (!acpi_checksum(s_header, s_header->length)) {
printf("%i: invalid acpi entry\n", index);
return;
}
struct acpi_type *c = &acpi_types[0];
while (c->name[0] != '\0') {
if (strncmp(s_header->signature, c->name, 4) == 0) {
printf("%i: %.4s %s\n", index, c->name, c->description);
if (c->handle_table != NULL) {
c->handle_table(s_header);
}
break;
}
c += 1;
}
if (c->name[0] == '\0') {
printf("%i: %.4s unknown\n", index, s_header->signature);
}
}
void acpi_parse_rsdt(uint32_t address) {
printf("Parsing RSDT\n");
rsdt_table = (const struct acpi_rsdt *) address;
if (!acpi_checksum(rsdt_table, rsdt_table->header.length)) {
k_panics("Malformed RSDT");
}
if (strncmp(rsdt_table->header.signature, "RSDT", 4) != 0) {
k_panics("RSDT pointer is not RSDT");
}
uint32_t entries = (rsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint32_t);
for (uint32_t i = 0; i < entries; ++i) {
acpi_parse_table(rsdt_table->pointer_to_other_sdt[i], i);
}
}
void acpi_parse_xsdt(uint64_t address) {
printf("Parsing XSDT\n");
if (address > UINT32_MAX) {
k_panics("acpi table above 4GB");
}
xsdt_table = (const struct acpi_xsdt *) (uint32_t) address;
if (!acpi_checksum(xsdt_table, xsdt_table->header.length)) {
k_panics("Malformed XSDT");
}
if (strncmp(xsdt_table->header.signature, "XSDT", 4) != 0) {
k_panics("XSDT pointer is not XSDT");
}
uint32_t entries = (xsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint64_t);
for (uint32_t i = 0; i < entries; ++i) {
const uint64_t entry_addr = xsdt_table->pointer_to_other_sdt[i];
if (entry_addr > UINT32_MAX) {
printf("%i: Above 4GB\n", i);
continue;
}
acpi_parse_table(xsdt_table->pointer_to_other_sdt[i], i);
}
}
void *acpi_find_table_by_name(const char *name, int skip) {
if (xsdt_table != NULL) {
uint32_t entries = (xsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint64_t);
for (uint32_t i = 0; i < entries; ++i) {
const uint64_t entry_addr = xsdt_table->pointer_to_other_sdt[i];
if (entry_addr > UINT32_MAX) {
printf("%i: Above 4GB\n", i);
continue;
}
struct acpi_sdt_header *header = (struct acpi_sdt_header *) xsdt_table->pointer_to_other_sdt[i];
if (!acpi_checksum(header, header->length)) {
printf("Invalid header %d", i);
continue;
}
if (strncmp(header->signature, name, 4) == 0) {
if (skip > 0) {
skip--;
continue;
}
return header;
}
}
}
if (rsdt_table != NULL) {
uint32_t entries = (rsdt_table->header.length - sizeof(struct acpi_sdt_header)) / sizeof(uint32_t);
for (uint32_t i = 0; i < entries; ++i) {
struct acpi_sdt_header *header = (struct acpi_sdt_header *) rsdt_table->pointer_to_other_sdt[i];
if (!acpi_checksum(header, header->length)) {
printf("Invalid header %d", i);
continue;
}
if (strncmp(header->signature, name, 4) == 0) {
if (skip > 0) {
skip--;
continue;
}
return header;
}
}
}
// check if DSDT is requested, but was not present as normal table
if (strncmp(name, "DSDT", 4) == 0) {
return (void *) dsdt;
}
return NULL;
}
void acpi_parse() {
struct lai_rsdp_info lai_rsdp_info;
lai_api_error_t result = lai_bios_detect_rsdp(&lai_rsdp_info);
if (result != LAI_ERROR_NONE) {
printf("LAI: could not find rsdp: %s\n", lai_api_error_to_string(result));
k_panics("Could not init ACPI");
}
lai_set_acpi_revision(lai_rsdp_info.acpi_version);
if (lai_rsdp_info.xsdt_address != 0) {
acpi_parse_xsdt(lai_rsdp_info.xsdt_address);
} else if (lai_rsdp_info.rsdt_address != 0) {
acpi_parse_rsdt(lai_rsdp_info.rsdt_address);
} else {
k_panics("No rsdt nor xsdt");
}
}
void acpi_init() {
acpi_parse();
lai_create_namespace();
}
INIT_FUNCTION(100) = {
.name = "acpi",
.stage = INIT_STAGE_EARLY_BOOT_1,
.init = acpi_init,
};

80
kernel/acpi/lailayer.c Normal file
View File

@@ -0,0 +1,80 @@
//
// Created by rick on 26-08-21.
//
#include <stdio.h>
#include <stdlib.h>
#include <lai/host.h>
#include <myke/acpi/acpi.h>
#include <myke/drivers/ports.h>
#include <myke/libk/libk.h>
const char *lai_loglevel_str(int level) {
switch (level) {
case LAI_DEBUG_LOG:
return "debug ";
case LAI_WARN_LOG:
return "warn ";
default:
return "unknown";
}
}
void laihost_log(int level, const char *msg) {
printf("lai [%s]: %s\n", lai_loglevel_str(level), msg);
}
void laihost_panic(const char *msg) {
k_panics(msg);
}
void *laihost_malloc(size_t size) {
return malloc(size);
}
void *laihost_realloc(void *data, size_t size, size_t old_size) {
return realloc(data, size);
}
void laihost_free(void *data, size_t size) {
free(data);
}
void *laihost_map(size_t address, size_t size) {
return (void *) address;
}
void laihost_unmap(void *pointer, size_t count) {
}
void *laihost_scan(const char *sig, size_t index) {
return acpi_find_table_by_name(sig, (int)index);
}
void laihost_outb(uint16_t port, uint8_t val) {
port_byte_out(port, val);
}
void laihost_outw(uint16_t port, uint16_t val) {
port_word_out(port, val);
}
void laihost_outd(uint16_t port, uint32_t val) {
port_double_word_out(port, val);
}
uint8_t laihost_inb(uint16_t port) {
return port_byte_in(port);
}
uint16_t laihost_inw(uint16_t port) {
return port_word_in(port);
}
uint32_t laihost_ind(uint16_t port) {
return port_double_word_in(port);
}
void laihost_sleep(uint64_t ms) {
return; // todo implement for real system
}

View File

@@ -9,20 +9,24 @@
#include <readline/readline.h> #include <readline/readline.h>
#include <myke/command.h> #include <myke/command.h>
#include <myke/cpu/timer.h> #include <myke/cpu/pit.h>
#include <myke/drivers/pci/ide.h> #include <myke/drivers/pci/ide.h>
#include <myke/drivers/pci/pci.h> #include <myke/drivers/pci/pci.h>
#include <myke/fs/blockdev.h> #include <myke/vfs/blockdev.h>
#include <myke/fs/mbr.h> #include <myke/vfs/part/mbr.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/mem/malloc.h> #include <myke/mem/malloc.h>
#include <myke/mem/mem.h> #include <myke/mem/mem.h>
#include <myke/tasks/task.h>
#include <myke/util/power.h> #include <myke/util/power.h>
#include <myke/vfs/vfs.h>
#ifdef ENABLE_SELF_TEST #ifdef ENABLE_SELF_TEST
#include <myke/debug/debug.h> #include <myke/debug/debug.h>
#include <myke/util/slingurl.h> #include <myke/util/slingurl.h>
#include <myke/libk/syscall.h>
#include <myke/util/init.h>
#endif #endif
@@ -49,15 +53,25 @@ void help(const char *args);
void shutdown(const char *args); void shutdown(const char *args);
void explode(const char *args); void ps(const char *args);
void mount(const char *args);
void ls(const char *args);
void cat(const char *args);
#ifdef ENABLE_SELF_TEST #ifdef ENABLE_SELF_TEST
void explode(const char *args);
void kill_self(const char *args);
void exec_self_test(const char *args); void exec_self_test(const char *args);
void smash(const char *args); void smash(const char *args);
void slingurl(const char* args); void slingurl(const char *args);
#endif #endif
@@ -67,40 +81,59 @@ cmd_handler cmd_handlers[] = {
{"print", print}, {"print", print},
{"ide", ide}, {"ide", ide},
{"shutdown", shutdown}, {"shutdown", shutdown},
{"explode", explode}, {"ps", ps},
{"slingurl", slingurl}, {"mount", mount},
{"ls", ls},
{"cat", cat},
#ifdef ENABLE_SELF_TEST #ifdef ENABLE_SELF_TEST
{"slingurl", slingurl},
{"kill-self", kill_self},
{"self-test", exec_self_test}, {"self-test", exec_self_test},
{"smash", smash}, {"smash", smash},
{"explode", explode},
#endif #endif
{NULL, NULL}, {NULL, NULL},
}; };
void slingurl(const char* args) { #ifdef ENABLE_SELF_TEST
void slingurl(const char *args) {
slingurl_decompose(args); slingurl_decompose(args);
} }
void smash(const char *args) { void smash(const char *args) {
// smash the stack, should trigger the stack protector
char data[16]; char data[16];
memset(data, 'A', 32); memset(data, 'A', 32);
} }
void kill_self(const char *args) {
syscall_kill_self();
}
void exec_self_test(const char *args) { void exec_self_test(const char *args) {
// unit tests
self_test(); self_test();
} }
void explode(const char *args) { void explode(const char *args) {
// trigger a divide by zero exception
uint32_t x = 0; uint32_t x = 0;
uint32_t y = 0; uint32_t y = 0;
__asm__("div %%ebx" : __asm__("div %%ebx" :
"=a" (x), "=b" (y)); "=a" (x), "=b" (y));
} }
#endif
void shutdown(const char *args) { void shutdown(const char *args) {
power_shutdown(); power_shutdown();
} }
void ps(const char *args) {
task_print_all();
}
void print_bootinfo() { void print_bootinfo() {
printf("Bootloader name: %s\n" printf("Bootloader name: %s\n"
"cmdline: %s\n", "cmdline: %s\n",
@@ -162,17 +195,74 @@ void ide(const char *arg) {
} }
} }
void mount(const char *arg) {
vfs_mount("/", "ide0p0", "ext2");
}
void ls(const char *arg) {
vfs_fd_t *fd = vfs_open("/", 0, 0);
if (fd == NULL) {
printf("could not open /\n");
return;
}
void *data = malloc(1024);
if (data == NULL) {
printf("malloc fail\n");
vfs_close(fd);
return;
}
uint32_t num = 0;
while ((num = vfs_getdents(fd, data, 1024)) > 0) {
vfs_dirent_t *ent = data;
while (true) {
printf("%s\n", ent->name);
if (ent->offset_next >= 1024) {
break;
}
ent = &data[ent->offset_next];
}
}
free(data);
vfs_close(fd);
}
void cat(const char *arg) {
vfs_fd_t *fd = vfs_open("/sda1", 0, 0);
vfs_close(fd);
fd = vfs_open("/test.txt", 0, 0);
if (fd == NULL) {
printf("could not open /test.txt\n");
return;
}
char *data = malloc(1024);
if (data == NULL) {
printf("no mem\n");
vfs_close(fd);
return;
}
int read = vfs_read(fd, data, 1024);
if (read < 0) {
printf("Failed to read\n");
} else if (read == 0) {
printf("emtpy file\n");
} else {
printf("first 10 chars %10s\n", data);
}
free(data);
vfs_close(fd);
}
void store_bootloader_info(multiboot_info_t *multiboot_info) { void store_bootloader_info(multiboot_info_t *multiboot_info) {
// get bootloader and cmdline // get bootloader and cmdline
if (multiboot_info->flags & MULTIBOOT_INFO_CMDLINE) { if (multiboot_info->flags & MULTIBOOT_INFO_CMDLINE) {
int cmdline_length = strlen((const char *) multiboot_info->cmdline); size_t cmdline_length = strlen((const char *) multiboot_info->cmdline);
if (cmdline_length > CMDLINE_MAX_LENGTH) { if (cmdline_length > CMDLINE_MAX_LENGTH) {
k_panics("cmdline to long!\n"); k_panics("cmdline to long!\n");
} }
memcpy(cmdline, (char *) multiboot_info->cmdline, cmdline_length); memcpy(cmdline, (char *) multiboot_info->cmdline, cmdline_length);
} }
if (multiboot_info->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) { if (multiboot_info->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
int bootloader_length = strlen((const char *) multiboot_info->boot_loader_name); size_t bootloader_length = strlen((const char *) multiboot_info->boot_loader_name);
if (bootloader_length > BOOTLOADER_NAME_MAX_LENGTH) { if (bootloader_length > BOOTLOADER_NAME_MAX_LENGTH) {
k_panics("bootloader name to long!\n"); k_panics("bootloader name to long!\n");
} }
@@ -201,3 +291,16 @@ void att_noreturn main_loop(void *data) {
free(msg); free(msg);
} }
} }
#ifdef K_SHELL
void main_loop_start() {
task_spawn(main_loop, NULL, "main");
}
INIT_FUNCTION(100) = {
.name = "main-task",
.stage = INIT_STAGE_PRE_TASKING,
.init = main_loop_start,
};
#endif

View File

@@ -16,18 +16,16 @@ union cpu_name {
}; };
}; };
static bool has_apic() {
uint32_t eax, unused, edx;
__get_cpuid(CPUID_FEATURE_FLAGS, &eax, &unused, &unused, &edx);
return edx & CPUID_FEAT_EDX_APIC;
}
void cpuidx_print_info() { void cpuidx_print_info() {
union cpu_name name; union cpu_name name;
__get_cpuid(0, NULL, &name.parts[0], &name.parts[2], &name.parts[1]); __get_cpuid(CPUID_VENDOR_ID, NULL, &name.parts[0], &name.parts[2], &name.parts[1]);
name.end = 0; name.end = 0;
printf("CPU: %s\n", &name.name); printf("CPU: %s\n", &name.name);
cpu_features_ecx features_ecx;
cpu_features_edx features_edx;
__get_cpuid(1, NULL, NULL, (uint32_t *) &features_ecx, (uint32_t *) &features_edx);
printf("");
} }

View File

@@ -7,13 +7,11 @@
#include <myke/cpu/isr.h> #include <myke/cpu/isr.h>
#include <myke/debug/debug.h> #include <myke/debug/debug.h>
#include <myke/cpu/idt.h> #include <myke/cpu/idt.h>
#include <myke/cpu/pic.h>
#include <myke/cpu/syscall_handler.h> #include <myke/cpu/syscall_handler.h>
#include <myke/drivers/ports.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
#define PIC_END_OF_INTERRUPT 0x20
isr_t interrupt_handlers[256]; isr_t interrupt_handlers[256];
void isr_install() { void isr_install() {
@@ -51,20 +49,10 @@ void isr_install() {
set_idt_gate(31, (uint32_t) isr31); set_idt_gate(31, (uint32_t) isr31);
// Remap the PIC // Remap the PIC
// todo make readable pic_init(IRQ0);
port_byte_out(0x20, 0x11);
port_byte_out(0xA0, 0x11);
port_byte_out(0x21, 0x20);
port_byte_out(0xA1, 0x28);
port_byte_out(0x21, 0x04);
port_byte_out(0xA1, 0x02);
port_byte_out(0x21, 0x01);
port_byte_out(0xA1, 0x01);
port_byte_out(0x21, 0x0);
port_byte_out(0xA1, 0x0);
// Install the IRQs // Install the IRQs
set_idt_gate(32, (uint32_t) irq0); set_idt_gate(32, (uint32_t) irq0); // 0x20
set_idt_gate(33, (uint32_t) irq1); set_idt_gate(33, (uint32_t) irq1);
set_idt_gate(34, (uint32_t) irq2); set_idt_gate(34, (uint32_t) irq2);
set_idt_gate(35, (uint32_t) irq3); set_idt_gate(35, (uint32_t) irq3);
@@ -72,7 +60,7 @@ void isr_install() {
set_idt_gate(37, (uint32_t) irq5); set_idt_gate(37, (uint32_t) irq5);
set_idt_gate(38, (uint32_t) irq6); set_idt_gate(38, (uint32_t) irq6);
set_idt_gate(39, (uint32_t) irq7); set_idt_gate(39, (uint32_t) irq7);
set_idt_gate(40, (uint32_t) irq8); set_idt_gate(40, (uint32_t) irq8); // 0x28
set_idt_gate(41, (uint32_t) irq9); set_idt_gate(41, (uint32_t) irq9);
set_idt_gate(42, (uint32_t) irq10); set_idt_gate(42, (uint32_t) irq10);
set_idt_gate(43, (uint32_t) irq11); set_idt_gate(43, (uint32_t) irq11);
@@ -81,6 +69,7 @@ void isr_install() {
set_idt_gate(46, (uint32_t) irq14); set_idt_gate(46, (uint32_t) irq14);
set_idt_gate(47, (uint32_t) irq15); set_idt_gate(47, (uint32_t) irq15);
// 0x80 SYSCALL
set_idt_gate(128, (uint32_t) isr128); set_idt_gate(128, (uint32_t) isr128);
set_idt(); // Load with ASM set_idt(); // Load with ASM
@@ -124,7 +113,7 @@ char *exception_messages[] = {
"Reserved" "Reserved"
}; };
void isr_handler(isr_registers_t r) { void att_used isr_handler(isr_registers_t r) {
char msg[256]; char msg[256];
if (r.int_no == 128) { if (r.int_no == 128) {
syscall_handle(&r); syscall_handle(&r);
@@ -139,11 +128,10 @@ void register_interrupt_handler(uint8_t n, isr_t handler) {
interrupt_handlers[n] = handler; interrupt_handlers[n] = handler;
} }
void irq_handler(isr_registers_t r) { void att_used irq_handler(isr_registers_t r) {
/* After every interrupt we need to send an EOI to the PICs /* After every interrupt we need to send an EOI to the PICs
* or they will not send another interrupt again */ * or they will not send another interrupt again */
if (r.int_no >= 40) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */ pic_eoi(r.int_no >= IRQ8);
port_byte_out(PORT_PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); /* master */
if (r.int_no >= IRQ0 && r.int_no < IRQ15) { if (r.int_no >= IRQ0 && r.int_no < IRQ15) {
task_notify_irq(r.int_no - IRQ0); task_notify_irq(r.int_no - IRQ0);

30
kernel/cpu/lapic.c Normal file
View File

@@ -0,0 +1,30 @@
//
// Created by rick on 23-08-21.
//
#include <myke/cpu/lapic.h>
void *lapic = NULL;
void lapic_set_addr(uint32_t addr) {
lapic = (void *) addr;
}
void lapic_write(uint32_t offset, uint32_t value) {
*(volatile uint32_t *) ((uintptr_t) lapic + offset) = value;
}
uint32_t lapic_read(uint32_t offset) {
if (lapic == NULL) {
return UINT32_MAX;
}
return *(volatile uint32_t *) ((uintptr_t) lapic + offset);
}
uint32_t lapic_get_id() {
return lapic_read(LAPIC_REG_ID);
}
uint32_t lapic_get_version() {
return lapic_read(LAPIC_REG_VERSION);
}

51
kernel/cpu/pic.c Normal file
View File

@@ -0,0 +1,51 @@
//
// Created by rick on 22-08-21.
//
#include <stdbool.h>
#include <myke/cpu/pic.h>
#include <myke/drivers/ports.h>
// https://wiki.osdev.org/8259_PIC
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
#define ICW1_INIT 0x10 /* Initialization - required! */
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
#define PIC_END_OF_INTERRUPT 0x20
void pic_init(uint8_t isr_offset) {
// init both master and slave pic's
port_byte_out(PORT_PIC_MASTER_COMMAND, ICW1_INIT | ICW1_ICW4);
port_byte_out(PORT_PIC_SLAVE_COMMAND, ICW1_INIT | ICW1_ICW4);
// master with ICW4 offset isr_offset, Slave on IRQ2, 8086 mode,
// ICW2
port_byte_out(PORT_PIC_MASTER_DATA, isr_offset); // offset master
port_byte_out(PORT_PIC_SLAVE_DATA, isr_offset + 8); // offset slave
// ICW3
port_byte_out(PORT_PIC_MASTER_DATA, 0x04); // slave PIC at IRQ2
port_byte_out(PORT_PIC_SLAVE_DATA, 0x02); // cascade identity
// ICW4
port_byte_out(PORT_PIC_MASTER_DATA, ICW4_8086); // 8086 mode
port_byte_out(PORT_PIC_SLAVE_DATA, ICW4_8086);
// empty mask
pic_set_mask(0);
}
void pic_set_mask(uint16_t mask) {
port_byte_out(PORT_PIC_MASTER_DATA, mask & 0xFF);
port_byte_out(PORT_PIC_SLAVE_DATA, mask >> 8);
}
void pic_eoi(bool slave) {
if (slave) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */
port_byte_out(PORT_PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); /* master */
}

View File

@@ -5,7 +5,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <myke/cpu/timer.h> #include <myke/cpu/pit.h>
#include <myke/drivers/ports.h> #include <myke/drivers/ports.h>
#include <myke/cpu/isr.h> #include <myke/cpu/isr.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
@@ -33,19 +33,37 @@
#define PIT_CHANNEL_1 (0b01 << 6) #define PIT_CHANNEL_1 (0b01 << 6)
#define PIT_CHANNEL_2 (0b10 << 6) #define PIT_CHANNEL_2 (0b10 << 6)
#define PIT_CHANNEL_READ_BACK (0b11 << 6) #define PIT_CHANNEL_READ_BACK (0b11 << 6)
#define PIT_RB_LATCH_COUNT (0)
#define PIT_RB_LATCH_NO_COUNT (1 << 5)
#define PIT_RB_LATCH_STATUS (0)
#define PIT_RB_LATCH_NO_STATUS (1 << 4)
#define PIT_RB_CHANNEL_2 (1 << 3)
#define PIT_RB_CHANNEL_1 (1 << 2)
#define PIT_RB_CHANNEL_0 (1 << 1)
#define PIT_STATUS_OUTPUT_STATE (1 << 7)
#define PIT_STATUS_NULL_COUNT (1 << 6)
#define PIT_STATUS_ACCESS_MODE (0b11 >> 4)
#define PIT_STATUS_OPERATING_MODE (0b111 < 1)
#define PIT_STATUS_BCD_BIN (1)
#define PIT_FREQUENCY 1193182 /*Hz*/
uint32_t tick = 0; uint32_t tick = 0;
static void timer_callback(isr_registers_t *regs) { uint32_t pit_ms_to_div(uint32_t ms) {
uint32_t divisor = PIT_FREQUENCY / ms;
return divisor;
}
static void pit_callback(isr_registers_t *regs) {
tick++; tick++;
task_switch_next(); task_switch_next();
} }
uint32_t timer_get_tick() { uint32_t pit_get_tick() {
return tick; return tick;
} }
void sleep(uint32_t milliseconds) { void pit_sleep(uint32_t milliseconds) {
uint32_t done = tick + milliseconds; uint32_t done = tick + milliseconds;
while (tick != done) { while (tick != done) {
k_wait_for_interrupt(); k_wait_for_interrupt();
@@ -60,10 +78,10 @@ void print_current_tick() {
kprint("\n"); kprint("\n");
} }
int init_timer(uint32_t freq) { int pit_int_frequency(uint32_t freq) {
register_interrupt_handler(IRQ0, timer_callback); register_interrupt_handler(IRQ0, pit_callback);
uint32_t divisor = 1193180 / freq; uint32_t divisor = PIT_FREQUENCY / freq;
uint8_t low = (uint8_t) (divisor & 0xFF); uint8_t low = (uint8_t) (divisor & 0xFF);
uint8_t high = (uint8_t) ((divisor >> 8) & 0xFF); uint8_t high = (uint8_t) ((divisor >> 8) & 0xFF);
port_byte_out(PORT_PIT_COMMAND, port_byte_out(PORT_PIT_COMMAND,
@@ -72,3 +90,21 @@ int init_timer(uint32_t freq) {
port_byte_out(PORT_PIT_DATA_0, high); port_byte_out(PORT_PIT_DATA_0, high);
return 0; return 0;
} }
// pit_sleep without interrupts
void pit_sleep_ms(const uint32_t sleep) {
// todo locking
uint32_t divider = pit_ms_to_div(sleep);
if (divider > UINT16_MAX) {
k_panics("Sleep for to long");
}
port_byte_out(PORT_PIT_COMMAND,
PIT_MODE_BIN | PIT_MODE_INTERRUPT_ON_TERMINAL_COUNT | PIT_ACCESS_MODE_LH | PIT_CHANNEL_0);
port_byte_out(PORT_PIT_DATA_0, divider & 0xFF);
port_byte_out(PORT_PIT_DATA_0, divider >> 8);
do {
__builtin_ia32_pause();
port_byte_out(PORT_PIT_COMMAND,
PIT_CHANNEL_READ_BACK | PIT_RB_CHANNEL_0 | PIT_RB_LATCH_NO_COUNT | PIT_RB_LATCH_STATUS);
} while (port_byte_in(PORT_PIT_DATA_0) & PIT_STATUS_OUTPUT_STATE);
}

View File

@@ -23,6 +23,11 @@ void syscall_handle(isr_registers_t *registers) {
task_ensure_enabled(); task_ensure_enabled();
task_suspend(); task_suspend();
break; break;
case SYSCALL_KILL_SELF:
task_ensure_enabled();
task_end(task_get_current_tid());
task_switch_next();
break;
default: default:
break; break;
} }

View File

@@ -24,7 +24,7 @@ static const char *elf_name_strtab = ".strtab";
struct stackframe { struct stackframe {
struct stackframe *ebp; struct stackframe *ebp;
uint32_t eip; uintptr_t eip;
}; };
char *debug_get_shstrtab_entry(uint32_t ndx) { char *debug_get_shstrtab_entry(uint32_t ndx) {
@@ -80,7 +80,7 @@ void debug_store_info(struct multiboot_info *info) {
debug_find_sections(info->u.elf_sec.shndx); debug_find_sections(info->u.elf_sec.shndx);
} }
struct elf32_symtab_entry *debug_get_entry_for_addr(uint32_t addr) { struct elf32_symtab_entry *debug_get_entry_for_addr(uintptr_t addr) {
if (elf_symtab == NULL) { if (elf_symtab == NULL) {
return NULL; return NULL;
} }
@@ -106,9 +106,9 @@ void debug_backtrace(bool do_sync) {
while (frame->ebp != NULL) { while (frame->ebp != NULL) {
struct elf32_symtab_entry *entry = debug_get_entry_for_addr(frame->eip); struct elf32_symtab_entry *entry = debug_get_entry_for_addr(frame->eip);
if (entry == NULL) { if (entry == NULL) {
sprintf(msg, "#unknown (%x)\n", frame->eip); sprintf(msg, "#unknown (%lx)\n", frame->eip);
} else { } else {
sprintf(msg, "%s (%x)\n", debug_get_strtab_entry(entry->st_name), frame->eip); sprintf(msg, "%s (%lx)\n", debug_get_strtab_entry(entry->st_name), frame->eip);
}; };
printer(msg); printer(msg);
frame = frame->ebp; frame = frame->ebp;

View File

@@ -101,7 +101,7 @@ void test_string() {
const char *strcpy_src_test = "abc\0def"; const char *strcpy_src_test = "abc\0def";
char *strcpy_dst_test = "\0\0\0\0\0\0\0"; char *strcpy_dst_test = "\0\0\0\0\0\0\0";
const char *strcpy_expected_test = "abc\0\0\0\0"; const char *strcpy_expected_test = "abc\0\0\0\0";
assert_int(0, strcpy(strcpy_dst_test, strcpy_src_test)); assert_ptr(strcpy_dst_test, strcpy(strcpy_dst_test, strcpy_src_test));
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpointer-sign" #pragma clang diagnostic ignored "-Wpointer-sign"
assert_array_equal(strcpy_dst_test, strcpy_expected_test, 8); assert_array_equal(strcpy_dst_test, strcpy_expected_test, 8);

View File

@@ -8,6 +8,7 @@
#include <myke/libc/ringqueue.h> #include <myke/libc/ringqueue.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/libk/syscall.h> #include <myke/libk/syscall.h>
#include <myke/util/init.h>
const char scancode_map_lowercase[] = { const char scancode_map_lowercase[] = {
@@ -131,7 +132,7 @@ static void keyboard_callback(isr_registers_t *regs) {
publish_key_event(scancode); publish_key_event(scancode);
} }
void init_keyboard() { void keyboard_init() {
register_interrupt_handler(IRQ1, keyboard_callback); register_interrupt_handler(IRQ1, keyboard_callback);
keyboard_state.shift = 0; keyboard_state.shift = 0;
keyboard_state.ctrl = 0; keyboard_state.ctrl = 0;
@@ -139,3 +140,9 @@ void init_keyboard() {
keyboard_state.extended = 0; keyboard_state.extended = 0;
keyboard_event_buffer = create_buffer(256, sizeof(KeyEvent)); keyboard_event_buffer = create_buffer(256, sizeof(KeyEvent));
} }
INIT_FUNCTION(100) = {
.name = "keyboard",
.stage = INIT_STAGE_LATE_BOOT,
.init = keyboard_init,
};

View File

@@ -9,12 +9,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include <myke/cpu/timer.h> #include <myke/cpu/pit.h>
#include <myke/debug/debug.h> #include <myke/debug/debug.h>
#include <myke/drivers/pci/ide.h> #include <myke/drivers/pci/ide.h>
#include <myke/drivers/pci/pci.h> #include <myke/drivers/pci/pci.h>
#include <myke/drivers/ports.h> #include <myke/drivers/ports.h>
#include <myke/fs/blockdev.h> #include <myke/vfs/blockdev.h>
#include <myke/libk/kprint.h> #include <myke/libk/kprint.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/tasks/locking.h> #include <myke/tasks/locking.h>
@@ -395,6 +395,10 @@ void ide_register_block_devices() {
if (!ide_devices[i].reserved) { if (!ide_devices[i].reserved) {
continue; continue;
} }
if (ide_devices[i].type == IDE_ATAPI) {
// skip ATAPI for now
continue;
}
ide_block_device_info *info = malloc(sizeof(ide_block_device_info)); // todo free for this one ide_block_device_info *info = malloc(sizeof(ide_block_device_info)); // todo free for this one
info->device_number = i; info->device_number = i;
@@ -451,11 +455,11 @@ uint8_t att_used ide_pci_initialize(pci_device *device) {
// (I) Select Drive: // (I) Select Drive:
ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4)); // Select Drive. ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4)); // Select Drive.
sleep(1); // Wait 1ms for drive select to work. pit_sleep(1); // Wait 1ms for drive select to work.
// (II) Send ATA Identify Command: // (II) Send ATA Identify Command:
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY); ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
sleep(1); // This function should be implemented in your OS. which waits for 1 ms. pit_sleep(1); // This function should be implemented in your OS. which waits for 1 ms.
// it is based on System Timer Device Driver. // it is based on System Timer Device Driver.
// (III) Polling: // (III) Polling:
@@ -485,7 +489,7 @@ uint8_t att_used ide_pci_initialize(pci_device *device) {
} }
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
sleep(1); pit_sleep(1);
} }
// (V) Read Identification Space of the Device: // (V) Read Identification Space of the Device:

View File

@@ -2,9 +2,10 @@
// Created by rick on 28-01-21. // Created by rick on 28-01-21.
// //
#include <myke/drivers/serial.h>
#include <sys/types.h> #include <sys/types.h>
#include <myke/drivers/ports.h> #include <myke/drivers/ports.h>
#include <myke/libk/kprint.h>
#include <myke/util/init.h>
#define SERIAL_INTERRUPT_DATA_AVAILABLE (1 << 0) #define SERIAL_INTERRUPT_DATA_AVAILABLE (1 << 0)
#define SERIAL_INTERRUPT_TRANSMITTER_EMPTY (1 << 1) #define SERIAL_INTERRUPT_TRANSMITTER_EMPTY (1 << 1)
@@ -51,7 +52,7 @@
#define MODEM_CONTROL_LOOPBACK_MODE (1 << 4) #define MODEM_CONTROL_LOOPBACK_MODE (1 << 4)
#define MODEM_CONTROL_AUTOFLOW_CONTROL_ENABLED (1 << 5) #define MODEM_CONTROL_AUTOFLOW_CONTROL_ENABLED (1 << 5)
int serial_init() { int serial_init_hw() {
port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_INTERRUPT, 0); // Disable all interrupts port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_INTERRUPT, 0); // Disable all interrupts
port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_LINE_CONTROL, port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_LINE_CONTROL,
LINE_CONTROL_DIVISOR); // Enable DLAB (set baud rate divisor) LINE_CONTROL_DIVISOR); // Enable DLAB (set baud rate divisor)
@@ -114,4 +115,17 @@ void serial_kprint(const char *msg) {
write_serial(c); write_serial(c);
i++; i++;
} }
} }
void serial_init() {
if (serial_init_hw() != 0) {
return;
}
kprint_register(serial_kprint);
}
INIT_FUNCTION(100) = {
.name = "serial",
.stage = INIT_STAGE_EARLY_BOOT_0,
.init = serial_init,
};

View File

@@ -3,9 +3,11 @@
// //
#include <string.h> #include <string.h>
#include <myke/drivers/vgascreen.h>
#include <myke/drivers/ports.h> #include <myke/drivers/ports.h>
#include <myke/drivers/vgascreen.h>
#include <myke/libk/kprint.h>
#include <myke/util/init.h>
char *_vga_character_memory = (char *) VGA_CHARACTER_MEMORY_LOCATION; char *_vga_character_memory = (char *) VGA_CHARACTER_MEMORY_LOCATION;
@@ -136,3 +138,14 @@ int get_offset_row(int offset) {
int get_offset_col(int offset) { int get_offset_col(int offset) {
return (offset - (get_offset_row(offset) * 2 * VGA_COL_MAX)) / 2; return (offset - (get_offset_row(offset) * 2 * VGA_COL_MAX)) / 2;
} }
void vga_init() {
vga_clear_screen();
kprint_register(vga_kprint);
}
INIT_FUNCTION(100) = {
.name = "vga",
.stage = INIT_STAGE_EARLY_BOOT_0,
.init = vga_init,
};

View File

@@ -5,20 +5,16 @@
#define DEBUG_INIT #define DEBUG_INIT
#include <myke/command.h> #include <myke/command.h>
#include <myke/cpu/cpuidx.h>
#include <myke/cpu/gdt.h> #include <myke/cpu/gdt.h>
#include <myke/cpu/isr.h> #include <myke/cpu/isr.h>
#include <myke/cpu/timer.h> #include <myke/cpu/pit.h>
#include <myke/debug/debug.h> #include <myke/debug/debug.h>
#include <myke/drivers/keyboard.h>
#include <myke/drivers/pci/pci.h> #include <myke/drivers/pci/pci.h>
#include <myke/drivers/serial.h>
#include <myke/drivers/vgascreen.h>
#include <myke/fs/blockdev.h>
#include <myke/libk/kprint.h> #include <myke/libk/kprint.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/libk/syscall.h> #include <myke/libk/syscall.h>
#include <myke/mem/mem.h> #include <myke/mem/mem.h>
#include <myke/util/init.h>
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
const int version_major = 0, const int version_major = 0,
@@ -42,11 +38,8 @@ void init_pci_system() {
void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_name) { void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_name) {
// early init // early init
isr_install(); isr_install();
vga_clear_screen(); // initialize early modules (kprint etc.)
vga_clear_screen(' ', VGA_WHITE | (VGA_GRAY << VGA_SHIFT_BG)); init_execute_all(INIT_STAGE_EARLY_BOOT_0);
kprint_register(vga_kprint);
serial_init();
kprint_register(serial_kprint);
// parse multiboot // parse multiboot
if (mb_name != MULTIBOOT_BOOTLOADER_MAGIC) { if (mb_name != MULTIBOOT_BOOTLOADER_MAGIC) {
@@ -57,34 +50,33 @@ void att_noreturn att_used kmain(multiboot_info_t *multiboot_info, uint32_t mb_n
// initialize memory management // initialize memory management
init_mmap(multiboot_info); init_mmap(multiboot_info);
// safe multiboot info for later use
debug_store_info(multiboot_info);
gdt_init(); gdt_init();
// initialize kprint functionality // initialize kprint functionality
kprint_init(); kprint_init();
// initialize early driver code (ACPI, etc.)
debug_store_info(multiboot_info); init_execute_all(INIT_STAGE_EARLY_BOOT_1);
// identify cpu
cpuidx_print_info();
// enable interrupts // enable interrupts
__asm__ __volatile__("sti"); __asm__ __volatile__("sti");
// start the timer // start the timer
init_timer(1000); pit_int_frequency(1000);
// initialize devices
init_keyboard(); // initialize drivers that are not discovered in any other way
init_execute_all(INIT_STAGE_LATE_BOOT);
// init PCI
init_pci_system(); init_pci_system();
printf("Booted successfully v%d.%d.%d\n", version_major, version_minor, version_patch); printf("Booted successfully v%d.%d.%d\n", version_major, version_minor, version_patch);
// initialize tasking // initialize tasking
task_init(); task_init();
kprint_start_task(); // let other system provide tasks (command, kprint, blockdev)
block_dev_start_task(); init_execute_all(INIT_STAGE_PRE_TASKING);
#ifdef K_SHELL
task_spawn(main_loop, NULL);
#endif
// switch to tasking // switch to tasking
syscall_start_scheduler(); syscall_start_scheduler();
} }

View File

@@ -68,6 +68,11 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) {
++i; ++i;
} }
} }
int l = 0;
while (fmt[i] == 'l') {
l++;
i++;
}
switch (fmt[i]) { switch (fmt[i]) {
case 's': { // string case 's': { // string
uint32_t j = 0; uint32_t j = 0;
@@ -85,8 +90,14 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) {
buf[ptr++] = (char) va_arg(args, int); buf[ptr++] = (char) va_arg(args, int);
break; break;
case 'x': case 'x':
case 'p':
case 'X': // todo capitalize case 'X': // todo capitalize
print_int((uint32_t) va_arg(args, uint32_t), field_width, buf, &ptr, 16); if (l == 0 || l == 1) {
print_int((uint32_t) va_arg(args, uint32_t), field_width, buf, &ptr, 16);
} else if (l == 2) {
print_int((uint64_t) va_arg(args, uint64_t), field_width, buf, &ptr, 16);
}
// todo error
break; break;
case 'i': case 'i':
case 'd': case 'd':

View File

@@ -43,24 +43,21 @@ char *reverse(char *buffer, int i, int j) {
} }
// Iterative function to implement itoa() function in C // Iterative function to implement itoa() function in C
char *itoa(int value, char *buffer, int base) { char *itoa(uint32_t value, char *buffer, int base) {
// invalid input // invalid input
if (base < 2 || base > 32) if (base < 2 || base > 32)
return buffer; return buffer;
// consider absolute value of number
int n = abs(value);
int i = 0; int i = 0;
while (n) { while (value) {
int r = n % base; uint32_t r = value % base;
if (r >= 10) if (r >= 10)
buffer[i++] = 65 + (r - 10); buffer[i++] = 65 + (r - 10);
else else
buffer[i++] = 48 + r; buffer[i++] = 48 + r;
n = n / base; value = value / base;
} }
// if number is 0 // if number is 0

View File

@@ -5,27 +5,37 @@
#include <string.h> #include <string.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/types.h> #include <sys/types.h>
#include <myke/mem/malloc.h>
int memcpy(void *dst, const void *src, size_t amount) { void *memcpy(void *dst, const void *src, size_t amount) {
for (size_t i = 0; i < amount; i++) { for (size_t i = 0; i < amount; i++) {
((char *) dst)[i] = ((const char *) src)[i]; ((char *) dst)[i] = ((const char *) src)[i];
} }
return 0; return dst;
} }
int memset(void *dst, int data, size_t amount) { void *memset(void *dst, int data, size_t amount) {
for (size_t i = 0; i < amount; ++i) { for (size_t i = 0; i < amount; ++i) {
((char *) dst)[i] = (char) data; ((char *) dst)[i] = (char) data;
} }
return 0; return dst;
} }
void *memmove(void *dst, const void *src, size_t amount) {
void *tmp = malloc(amount);
if (tmp == NULL) {
return NULL;
}
memcpy(dst, memcpy(tmp, src, amount), amount);
free(tmp);
return dst;
}
int strcpy(char *dst, const char *src) { void *strcpy(char *dst, const char *src) {
return memcpy(dst, src, strlen(src) + 1); return memcpy(dst, src, strlen(src) + 1);
} }
int strncpy(char *dst, const char *src, size_t n) { void *strncpy(char *dst, const char *src, size_t n) {
return memcpy(dst, src, MIN(strlen(src), n) + 1); return memcpy(dst, src, MIN(strlen(src), n) + 1);
} }
@@ -38,16 +48,19 @@ size_t strlen(const char *str) {
} }
int strcmp(const char *s1, const char *s2) { int strcmp(const char *s1, const char *s2) {
int len1 = strlen(s1); size_t len1 = strlen(s1);
int len2 = strlen(s2); size_t len2 = strlen(s2);
return strncmp(s1, s2, MAX(len1, len2)); return strncmp(s1, s2, MAX(len1, len2));
} }
const char *strchr(const char *s, char c) { char *strchr(const char *s, char c) {
int index = 0; size_t index = 0;
while (1) { while (1) {
if (s[index] == c) { if (s[index] == c) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
return &s[index]; return &s[index];
#pragma clang diagnostic pop
} }
if (s[index] == 0) { if (s[index] == 0) {
return NULL; return NULL;
@@ -56,11 +69,14 @@ const char *strchr(const char *s, char c) {
} }
} }
const char *strrchr(const char *s, char c) { char *strrchr(const char *s, char c) {
int index = strlen(s); size_t index = strlen(s);
while (1) { while (1) {
if (s[index] == c) { if (s[index] == c) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
return &s[index]; return &s[index];
#pragma clang diagnostic pop
} }
if (index == 0) { if (index == 0) {
return NULL; return NULL;
@@ -75,13 +91,13 @@ int memcmp(const void *s1, const void *s2, size_t n) {
a = ((uint8_t *) s1)[i]; a = ((uint8_t *) s1)[i];
b = ((uint8_t *) s2)[i]; b = ((uint8_t *) s2)[i];
if (a > b) return 1; if (a > b) return 1;
if (b < a) return -1; if (a < b) return -1;
} }
return 0; return 0;
} }
int strncmp(const char *s1, const char *s2, int n) { int strncmp(const char *s1, const char *s2, size_t n) {
for (int i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
if (s1[i] == 0 && s2[i] == 0) { if (s1[i] == 0 && s2[i] == 0) {
return 0; return 0;
} }
@@ -118,3 +134,14 @@ char *strncat(char *dest, const char *src, size_t n) {
} }
return dest; return dest;
} }
char *strdup(const char *s) {
return strndup(s, strlen(s));
}
char *strndup(const char *s, size_t n) {
char *new = malloc(n + 1);
memcpy(new, s, n);
new[n] = 0;
return new;
}

View File

@@ -9,12 +9,13 @@
#include <myke/libk/kprint.h> #include <myke/libk/kprint.h>
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
#include <myke/util/stream.h> #include <myke/util/stream.h>
#include <myke/util/init.h>
#define MAX_HANDLERS 8 #define MAX_HANDLERS 8
#define STREAM_SIZE (32*1024) #define STREAM_SIZE (32*1024)
#define PRINT_BUFFER_SIZE 64 #define PRINT_BUFFER_SIZE 64
stream_t *kprint_stream; stream_t *kprint_stream = NULL;
kprint_handler handlers[MAX_HANDLERS] = {0}; kprint_handler handlers[MAX_HANDLERS] = {0};
@@ -29,7 +30,11 @@ void kprint_register(kprint_handler handler) {
} }
void kprint(const char *msg) { void kprint(const char *msg) {
stream_write(kprint_stream, (const uint8_t *) msg, strlen(msg)); if (kprint_stream == NULL) {
kprint_sync(msg);
} else {
stream_write(kprint_stream, (const uint8_t *) msg, strlen(msg));
}
} }
void kprint_internal(const char *msg) { void kprint_internal(const char *msg) {
@@ -64,5 +69,11 @@ void att_noreturn kprint_task(void *_) {
} }
void kprint_start_task() { void kprint_start_task() {
task_spawn(kprint_task, NULL); task_spawn(kprint_task, NULL, "kprint");
} }
INIT_FUNCTION(100) = {
.name = "kprint-task",
.stage = INIT_STAGE_PRE_TASKING,
.init = kprint_start_task,
};

View File

@@ -21,6 +21,10 @@ void att_noreturn k_panics(const char *msg) {
k_panic(); k_panic();
} }
void att_noreturn k_not_implemented() {
k_panics("Not Implemented");
}
void att_noreturn k_panic() { void att_noreturn k_panic() {
kprint_sync("PANIC!"); kprint_sync("PANIC!");
while (1) { while (1) {

View File

@@ -35,3 +35,7 @@ void syscall_yield_irq(uint16_t irq) {
void syscall_job_suspend() { void syscall_job_suspend() {
syscall1(SYSCALL_SUSPEND); syscall1(SYSCALL_SUSPEND);
} }
void syscall_kill_self() {
syscall1(SYSCALL_KILL_SELF);
}

View File

@@ -6,7 +6,7 @@
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
#include <myke/mem/malloc.h> #include <myke/mem/malloc.h>
#include <myke/mem/pm.h> #include <myke/mem/pmm.h>
// retrieved from https://github.com/blanham/liballoc // retrieved from https://github.com/blanham/liballoc
@@ -41,7 +41,7 @@ int liballoc_unlock() {
* \return A pointer to the allocated memory. * \return A pointer to the allocated memory.
*/ */
void *liballoc_alloc(size_t size) { void *liballoc_alloc(size_t size) {
return pm_get_pages(size); return pmm_get_pages(size);
} }
/** This frees previously allocated memory. The void* parameter passed /** This frees previously allocated memory. The void* parameter passed
@@ -53,7 +53,7 @@ void *liballoc_alloc(size_t size) {
* \return 0 if the memory was successfully freed. * \return 0 if the memory was successfully freed.
*/ */
int liballoc_free(void *addr, size_t size) { int liballoc_free(void *addr, size_t size) {
pm_free_pages(addr, size); pmm_free_pages(addr, size);
return 0; return 0;
} }
@@ -282,7 +282,7 @@ static struct liballoc_major *allocate_new_page(unsigned int size) {
} }
void *malloc(size_t req_size) { void __attribute__((assume_aligned (16), alloc_size (1), malloc)) *malloc(size_t req_size) {
int startedBet = 0; int startedBet = 0;
unsigned long long bestSize = 0; unsigned long long bestSize = 0;
void *p = NULL; void *p = NULL;
@@ -725,7 +725,7 @@ void free(void *ptr) {
void *calloc(size_t nobj, size_t size) { void *calloc(size_t nobj, size_t size) {
int real_size; size_t real_size;
void *p; void *p;
real_size = nobj * size; real_size = nobj * size;

View File

@@ -2,13 +2,12 @@
// Created by rick on 22-04-20. // Created by rick on 22-04-20.
// //
#include <attributes.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/mem/mem.h> #include <myke/mem/mem.h>
#include <myke/mem/pm.h> #include <myke/mem/pmm.h>
#define MEMMAP_ENTRIES 16 #define MEMMAP_ENTRIES 16
@@ -22,10 +21,10 @@
#define MMAP_TYPE_PAGING 7 #define MMAP_TYPE_PAGING 7
typedef struct { typedef struct {
uint32_t address; uintptr_t address;
uint32_t length; uint32_t length;
uint32_t type; uint32_t type;
} att_packed mmap_entry; } mmap_entry;
int last_memmap_entry = 0; int last_memmap_entry = 0;
mmap_entry memmap[MEMMAP_ENTRIES] = { mmap_entry memmap[MEMMAP_ENTRIES] = {
@@ -49,7 +48,7 @@ mmap_entry memmap[MEMMAP_ENTRIES] = {
void use_mmap_entry(struct multiboot_mmap_entry *entry) { void use_mmap_entry(struct multiboot_mmap_entry *entry) {
mmap_entry *mm_entry = &memmap[last_memmap_entry++]; mmap_entry *mm_entry = &memmap[last_memmap_entry++];
mm_entry->address = (void *) entry->addr; mm_entry->address = (uintptr_t) entry->addr;
mm_entry->length = entry->len; mm_entry->length = entry->len;
mm_entry->type = entry->type; mm_entry->type = entry->type;
// check if the entry overlaps with the kernel address space // check if the entry overlaps with the kernel address space
@@ -84,7 +83,7 @@ void mmap_init_multiboot(struct multiboot_mmap_entry *entries, uint32_t count) {
continue; // skip for now continue; // skip for now
} }
pm_init((void *) entry->address, entry->length); pmm_init((void *) entry->address, entry->length);
entry->type = MMAP_TYPE_PAGING; entry->type = MMAP_TYPE_PAGING;
} }
} }

59
kernel/mem/paging.c Normal file
View File

@@ -0,0 +1,59 @@
//
// Created by rick on 21-02-21.
//
#include <attributes.h>
#include <stdbool.h>
#include <sys/types.h>
#include <myke/mem/paging.h>
#define TABLE_ADDR_MASK 0xFFFFF000
#define DIRECTORY_SIZE 1024
const uint32_t x = TABLE_ADDR_MASK;
typedef struct {
union {
struct {
bool present: 1;
bool read_write: 1;
bool user_mode: 1;
bool write_through: 1;
bool cache_disabled: 1;
bool accessed: 1;
char ignored: 1;
bool page_size: 1;
bool global: 1; // ignored
uint8_t avail: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_directory_entry;
typedef struct {
union {
struct {
bool present: 1;
bool read_write: 1;
bool user_supervisor: 1;
bool write_through: 1;
bool cache_disabled: 1;
bool accessed: 1;
bool dirty: 1;
char ignored: 1;
bool global: 1;
uint8_t available: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_table_entry;
page_directory_entry page_directory[DIRECTORY_SIZE] att_aligned(4096);
void page_pre_init() {
for (int i = 0; i < DIRECTORY_SIZE; ++i) {
page_directory[i].read_write = true;
page_directory[i].user_mode = false;
page_directory[i].present = false;
}
}

View File

@@ -6,8 +6,7 @@
#include <string.h> #include <string.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/mem/pm.h> #include <myke/mem/pmm.h>
#include <myke/mem/vmm.h>
#define NUM_PAGING_INFOS 16 #define NUM_PAGING_INFOS 16
@@ -40,7 +39,7 @@ typedef struct {
uint8_t last_paging_info = 0; uint8_t last_paging_info = 0;
paging_info paging_infos[NUM_PAGING_INFOS]; paging_info paging_infos[NUM_PAGING_INFOS];
void pm_init(void *start_addr, size_t size) { void pmm_init(void *start_addr, size_t size) {
uint32_t num_pages = size / PAGE_SIZE; uint32_t num_pages = size / PAGE_SIZE;
uint32_t bitmap_size = num_pages / 8; uint32_t bitmap_size = num_pages / 8;
uint32_t bitmap_pages = bitmap_size / PAGE_SIZE; uint32_t bitmap_pages = bitmap_size / PAGE_SIZE;
@@ -49,10 +48,6 @@ void pm_init(void *start_addr, size_t size) {
paging_infos[last_paging_info].size = size; paging_infos[last_paging_info].size = size;
paging_infos[last_paging_info].flags.present = true; paging_infos[last_paging_info].flags.present = true;
// map into memory
vmm_assign_page(start_addr, start_addr, bitmap_pages);
// set state
memset(start_addr, BLOCK_FREE, bitmap_pages); memset(start_addr, BLOCK_FREE, bitmap_pages);
for (uint32_t i = 0; i < bitmap_pages; ++i) { for (uint32_t i = 0; i < bitmap_pages; ++i) {
bitmap_set((uint8_t *) start_addr, i); bitmap_set((uint8_t *) start_addr, i);
@@ -60,7 +55,7 @@ void pm_init(void *start_addr, size_t size) {
last_paging_info++; last_paging_info++;
} }
void *pm_get_pages(uint32_t num_pages) { void *pmm_get_pages(uint32_t num_pages) {
for (int i = 0; i < last_paging_info; ++i) { for (int i = 0; i < last_paging_info; ++i) {
paging_info *info = &paging_infos[i]; paging_info *info = &paging_infos[i];
if (!info->flags.present) continue; if (!info->flags.present) continue;
@@ -80,9 +75,7 @@ void *pm_get_pages(uint32_t num_pages) {
for (k = j; k < j + num_pages; ++k) { for (k = j; k < j + num_pages; ++k) {
bitmap_set(info->page_bitmap, k); bitmap_set(info->page_bitmap, k);
} }
void *paddr = page_to_addr(info->first_page, j); return page_to_addr(info->first_page, j);
vmm_assign_page(paddr, paddr, num_pages);
return paddr;
} }
} }
} }
@@ -90,7 +83,7 @@ void *pm_get_pages(uint32_t num_pages) {
return NULL; return NULL;
} }
void pm_free_pages(void *page, uint32_t num_pages) { void pmm_free_pages(void *page, uint32_t num_pages) {
for (int i = 0; i < last_paging_info; ++i) { for (int i = 0; i < last_paging_info; ++i) {
paging_info *info = &paging_infos[i]; paging_info *info = &paging_infos[i];
if (!info->flags.present) continue; if (!info->flags.present) continue;
@@ -102,6 +95,5 @@ void pm_free_pages(void *page, uint32_t num_pages) {
for (uint32_t current_page = first_page; current_page < first_page + num_pages; ++current_page) { for (uint32_t current_page = first_page; current_page < first_page + num_pages; ++current_page) {
bitmap_unset(info->page_bitmap, current_page); bitmap_unset(info->page_bitmap, current_page);
} }
vmm_unassign_page(page, num_pages);
} }
} }

View File

@@ -1,6 +0,0 @@
.code32
.section .text
.global vmm_get_current_page_directory
vmm_get_current_page_directory:
movl %cr3, %eax
ret

View File

@@ -1,116 +0,0 @@
//
// Created by rick on 21-02-21.
//
#include <attributes.h>
#include <stdbool.h>
#include <sys/types.h>
#include <myke/mem/vmm.h>
#include <myke/mem/pm.h>
#include <myke/libk/libk.h>
#define TABLE_ADDR_MASK 0xFFFFF000
#define TABLE_ADDR_IMASK ~TABLE_ADDR_MASK
#define DIRECTORY_SIZE 1024
const uint32_t x = TABLE_ADDR_MASK;
typedef struct {
union {
struct {
bool present: 1;
bool read_write: 1;
bool user_mode: 1;
bool write_through: 1;
bool cache_disabled: 1;
bool accessed: 1;
char: 1;
bool page_size: 1;
bool global: 1; // ignored
uint8_t avail: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_directory_entry;
typedef struct {
union {
struct {
bool present: 1;
bool read_write: 1;
bool user_supervisor: 1;
bool write_through: 1;
bool cache_disabled: 1;
bool accessed: 1;
bool dirty: 1;
char: 1;
bool global: 1;
uint8_t available: 3;
} att_packed;
uint32_t addr;
};
} att_packed page_table_entry;
//#define in_dir(dir, vaddr) ((page_table_entry*)(((page_directory_entry*)((dir)[(vaddr)/4096/1024].addr & TABLE_ADDR_MASK))[(vaddr)/4096%1024]))
#define dir_index(vaddr) (((uint32_t)(vaddr)) / PAGE_SIZE / DIRECTORY_SIZE)
#define page_index(vaddr) (((uint32_t)(vaddr)) / PAGE_SIZE % DIRECTORY_SIZE)
page_directory_entry boot_paging_directory[DIRECTORY_SIZE] att_aligned(4096);
page_table_entry boot_primary_table[DIRECTORY_SIZE] att_aligned(4096);
extern page_directory_entry *vmm_get_current_page_directory();
void vmm_assign_page_one(uint32_t paddr, uint32_t vaddr) {
page_directory_entry *curr = vmm_get_current_page_directory();
page_directory_entry *dentry = &curr[dir_index(vaddr)];
if (!dentry->present || (dentry->addr & TABLE_ADDR_MASK) == 0) {
// todo allocate table
k_panics("need to allocate new table");
}
page_table_entry *first_entry = (page_table_entry *) (dentry->addr & TABLE_ADDR_MASK);
page_table_entry *pentry = &first_entry[page_index(vaddr)];
if (pentry->present) {
// todo already present
k_panics("virtual address already in use");
}
pentry->addr = (pentry->addr & TABLE_ADDR_IMASK) | paddr;
pentry->present = true;
pentry->read_write = true;
}
void vmm_unassign_page_one(uint32_t vaddr) {
page_directory_entry *curr = vmm_get_current_page_directory();
page_directory_entry *dentry = &curr[dir_index(vaddr)];
if (!dentry->present || (dentry->addr & TABLE_ADDR_MASK) == 0) {
// todo allocate table
k_panics("need to allocate new table");
}
page_table_entry *first_entry = (page_table_entry *) (dentry->addr & TABLE_ADDR_MASK);
page_table_entry *pentry = &first_entry[page_index(vaddr)];
if (!pentry->present) {
// todo already present
k_panics("virtual address not in use");
}
pentry->present = false;
pentry->read_write = false;
pentry->addr = pentry->addr & TABLE_ADDR_IMASK;
}
void vmm_assign_page(void *paddr, void *vaddr, size_t number_of_pages) {
for (size_t i = 0; i < number_of_pages; ++i) {
vmm_assign_page_one(((uint32_t) paddr) + PAGE_SIZE * i, ((uint32_t) vaddr) + PAGE_SIZE * i);
}
}
void vmm_unassign_page(void *vaddr, size_t number_of_pages) {
for (size_t i = 0; i < number_of_pages; ++i) {
vmm_unassign_page_one(((uint32_t) vaddr) + PAGE_SIZE * i);
}
}

View File

@@ -12,7 +12,7 @@
#include <myke/libk/syscall.h> #include <myke/libk/syscall.h>
typedef struct lock_fifo_entry { typedef struct lock_fifo_entry {
uint32_t tid; pid_t tid;
struct lock_fifo_entry *next; struct lock_fifo_entry *next;
} lock_fifo_entry_t; } lock_fifo_entry_t;

View File

@@ -4,12 +4,14 @@
#include <attributes.h> #include <attributes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <myke/cpu/cpu.h> #include <myke/cpu/cpu.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/mem/pm.h> #include <myke/mem/pmm.h>
#include <myke/libk/syscall.h>
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
#define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE)) #define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE))
@@ -23,22 +25,45 @@
#define TASK_STATE_STOPPED (1 << 6) #define TASK_STATE_STOPPED (1 << 6)
#define TASK_STATE_ERROR (1 << 7) #define TASK_STATE_ERROR (1 << 7)
const char *task_state_str(uint8_t state) {
switch (state) {
case TASK_STATE_RUNNABLE:
return "RUNNABLE ";
case TASK_STATE_RUNNING:
return "RUNNING ";
case TASK_STATE_WAIT_IRQ:
return "WAIT_IRQ ";
case TASK_STATE_WAIT_SIGNAL:
return "WAIT_SIGNAL";
case TASK_STATE_STOPPED:
return "STOPPED ";
case TASK_STATE_ERROR:
return "ERROR ";
case TASK_STATE_UNKNOWN:
default:
return "UNKNOWN ";
}
}
int errno = 0; int errno = 0;
typedef struct task { typedef struct task {
// state
bool present: 1; bool present: 1;
uint8_t state; uint8_t state;
uint16_t wait_irq; uint16_t wait_irq;
uint32_t tid; // identity
pid_t tid;
int errno; char *name;
// linked list
struct task *next; struct task *next;
// persistence/memory
int errno;
void *stack; void *stack;
uint32_t stack_page_count; uint32_t stack_page_count;
task_registers_t *task_registers; task_registers_t *task_registers;
} task_t; } task_t;
@@ -57,19 +82,23 @@ task_t *first_task = NULL;
task_t *last_task = NULL; task_t *last_task = NULL;
task_t *current_task = NULL; task_t *current_task = NULL;
uint32_t last_tid = 0; pid_t last_tid = 0;
extern switch_task(task_registers_t pid_t reaper_pid = 0;
**, task_registers_t*);
extern void switch_task(task_registers_t **, task_registers_t *);
extern att_cdecl att_noreturn void __task_entry_point(); extern att_cdecl att_noreturn void __task_entry_point();
extern att_noreturn void __task_entry_point_inner(); extern att_noreturn void __task_entry_point_inner();
// internal api
void task_free(task_t *task);
// explicit cdecl calling convention // explicit cdecl calling convention
void att_cdecl att_noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) { void att_unused att_cdecl att_noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) {
entrypoint(entry_data); entrypoint(entry_data);
// task_end_self(); syscall_kill_self();
while (true); // halt while (true); // halt
} }
@@ -91,11 +120,11 @@ void task_lock_free() {
} }
} }
uint32_t task_get_current_tid() { pid_t task_get_current_tid() {
return current_task->tid; return current_task->tid;
} }
void task_signal(uint32_t tid) { void task_signal(pid_t tid) {
task_t *t = first_task; task_t *t = first_task;
while (t != NULL) { while (t != NULL) {
if (t->tid == tid) { if (t->tid == tid) {
@@ -114,10 +143,47 @@ void task_suspend() {
task_switch_next(); task_switch_next();
} }
// internal tasks
void att_noreturn task_idle(void *data) { void att_noreturn task_idle(void *data) {
while (true) __asm__("hlt"); while (true) __asm__("hlt");
} }
void att_noreturn task_reaper(void *data) {
while (true) {
bool did_reap = false;
task_lock_acquire();
task_t *t = first_task;
task_t *p = first_task;
task_t *n = NULL;
while (t != NULL) {
n = t->next;
if (t->state == TASK_STATE_STOPPED) {
did_reap = true;
if (t == first_task) {
if (n == NULL) {
k_panics("No more tasks");
}
first_task = n;
task_free(t);
t = NULL;
} else {
p->next = n;
task_free(t);
t = p;
}
}
p = t;
t = n;
}
task_lock_free();
if (did_reap) {
syscall_yield_job();
} else {
syscall_job_suspend();
}
}
}
void task_notify_irq(uint8_t irq_no) { void task_notify_irq(uint8_t irq_no) {
uint16_t irq__bit = 1 << irq_no; uint16_t irq__bit = 1 << irq_no;
task_t *t = first_task; task_t *t = first_task;
@@ -198,13 +264,14 @@ void task_switch_next() {
task_switch_next_inner(task_first_runnable()); task_switch_next_inner(task_first_runnable());
} }
task_t *task_create(task_entrypoint entrypoint, void *entry_data) { task_t *task_create(task_entrypoint entrypoint, void *entry_data, char *name) {
task_t *new_task = malloc(sizeof(task_t)); task_t *new_task = malloc(sizeof(task_t));
memset((uint8_t *) new_task, 0, sizeof(task_t)); memset((uint8_t *) new_task, 0, sizeof(task_t));
new_task->tid = last_tid++; new_task->tid = last_tid++;
new_task->name = strdup(name);
new_task->state = TASK_STATE_RUNNABLE; new_task->state = TASK_STATE_RUNNABLE;
new_task->stack = pm_get_pages(16); new_task->stack = pmm_get_pages(16);
new_task->stack_page_count = 16; new_task->stack_page_count = 16;
// todo check for null // todo check for null
@@ -233,12 +300,19 @@ task_t *task_create(task_entrypoint entrypoint, void *entry_data) {
} }
void task_init() { void task_free(task_t *task) {
idle_task = task_create(task_idle, NULL); pmm_free_pages(task->stack, 16);
free(task->name);
free(task);
} }
uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) { void task_init() {
task_t *new_task = task_create(entrypoint, entry_data); idle_task = task_create(task_idle, NULL, "idle");
reaper_pid = task_spawn(task_reaper, NULL, "reaper");
}
pid_t task_spawn(task_entrypoint entrypoint, void *entry_data, char *name) {
task_t *new_task = task_create(entrypoint, entry_data, name);
if (first_task == NULL) { if (first_task == NULL) {
// first task // first task
first_task = new_task; first_task = new_task;
@@ -249,13 +323,27 @@ uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
return new_task->tid; return new_task->tid;
} }
void task_end(uint32_t tid) { void task_end(pid_t tid) {
task_t *t = first_task; task_t *t = first_task;
while (t != NULL) { while (t != NULL) {
if (t->tid == tid) { if (t->tid == tid) {
t->state = TASK_STATE_STOPPED; t->state = TASK_STATE_STOPPED;
task_signal(reaper_pid);
break; break;
} }
t = t->next; t = t->next;
} }
} }
void task_print_all() {
// acquiring task lock as reference to current task may disappear
// might overrun kprint buffer
task_lock_acquire();
printf("tasks:\n");
task_t *c = first_task;
while (c != NULL) {
printf("%d - %s %s\n", c->tid, task_state_str(c->state), c->name);
c = c->next;
}
task_lock_free();
}

21
kernel/util/init.c Normal file
View File

@@ -0,0 +1,21 @@
//
// Created by rick on 13-08-21.
//
#include <myke/util/init.h>
#include <stdio.h>
extern struct init __start_init[];
extern struct init __stop_init[];
#define NUM_DRIVERS ((size_t)(__stop_init - __start_init))
#define DRIVER(i) ((__start_init) + (i))
void init_execute_all(enum init_stage stage) {
for (size_t i = 0; i < NUM_DRIVERS; ++i) {
if (DRIVER(i)->stage != stage) continue;
if (stage > INIT_STAGE_EARLY_BOOT_0) {
printf("init %s\n", DRIVER(i)->name);
}
DRIVER(i)->init();
}
}

View File

@@ -4,13 +4,12 @@
#include <attributes.h> #include <attributes.h>
#include <myke/drivers/ports.h> #include <lai/helpers/pm.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/util/power.h> #include <myke/util/power.h>
void att_noreturn power_shutdown() { void att_noreturn power_shutdown() {
port_word_out(PORT_ACPI, PORT_ACPI_SHUTDOWN); lai_enter_sleep(5);
port_word_out(PORT_QEMU_COMMAND, PORT_QEMU_COMMAND_SHUTDOWN);
port_word_out(PORT_VBOX, PORT_VBOX_SHUTDOWN);
k_panics("Failed to shut down!\n"); k_panics("Failed to shut down!\n");
} }

View File

@@ -4,13 +4,13 @@
#include <attributes.h> #include <attributes.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <myke/fs/blockdev.h> #include <myke/vfs/blockdev.h>
#include <myke/libk/libk.h> #include <myke/libk/libk.h>
#include <myke/tasks/locking.h> #include <myke/tasks/locking.h>
#include <myke/tasks/task.h> #include <myke/tasks/task.h>
#include <myke/util/init.h>
#define MAX_BLOCK_DEVS 64 #define MAX_BLOCK_DEVS 64
@@ -25,6 +25,25 @@ extern struct block_dev_driver __stop_block_dev_driver[];
semaphore_t *block_semaphore; semaphore_t *block_semaphore;
bool blockdev_task_running = false; bool blockdev_task_running = false;
block_device_t *block_dev_get_by_id(const char *name) {
for (int i = 0; i < last_block_dev; ++i) {
if (block_devices[i].flags.present
&& strcmp(block_devices[i].identifier, name) == 0) {
return &block_devices[i];
}
}
return NULL;
}
block_dev_driver_t *block_dev_driver_by_name(const char *name) {
for (size_t i = 0; i < NUM_DRIVERS; ++i) {
if (strcmp(DRIVER(i)->name, name) == 0) {
return DRIVER(i);
}
}
return NULL;
}
uint8_t block_dev_register(block_device_t *device) { uint8_t block_dev_register(block_device_t *device) {
if (last_block_dev >= MAX_BLOCK_DEVS - 1) { if (last_block_dev >= MAX_BLOCK_DEVS - 1) {
return BLOCK_DEV_REGISTER_FULL; return BLOCK_DEV_REGISTER_FULL;
@@ -38,6 +57,25 @@ uint8_t block_dev_register(block_device_t *device) {
return BLOCK_DEV_REGISTER_OK; return BLOCK_DEV_REGISTER_OK;
} }
void *block_dev_mount(const char *device, const char *driver_name) {
if (device == NULL || driver_name == NULL || strlen(device) == 0 || strlen(driver_name) == 0) {
return NULL; // invalid input
}
block_device_t *dev = block_dev_get_by_id(device);
if (dev == NULL) {
return NULL;
}
block_dev_driver_t *driver = block_dev_driver_by_name(driver_name);
if (driver == NULL) {
return NULL;
}
if (driver->check_device(dev) == BLOCK_DEV_DRIVER_CHECK_OK) {
dev->driver = driver;
return dev->driver_info;
}
return NULL;
}
void block_dev_free(block_device_t *device) { void block_dev_free(block_device_t *device) {
//todo //todo
k_panics("block dev free not supported"); k_panics("block dev free not supported");
@@ -51,53 +89,10 @@ int block_dev_num_not_scanned() {
return not_scanned; return not_scanned;
} }
bool block_dev_mount(char *identifier, char *driver_name) {
bool result = true;
block_device_t *device = NULL;
for (int i = 0; i < last_block_dev; ++i) {
if (strncmp(block_devices[i].identifier, identifier, 16) == 0) {
device = &block_devices[i];
}
}
if (identifier == NULL) {
result = false;
goto _end;
}
struct block_dev_driver *driver = NULL;
for (size_t j = 0; j < NUM_DRIVERS; ++j) {
if (strncmp(DRIVER(j)->name, driver_name, 16) == 0) {
driver = DRIVER(j);
}
}
if (driver == NULL) {
result = false;
goto _end;
}
uint8_t *lba0 = malloc(device->block_size);
uint8_t read_result = device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, lba0);
if (read_result != BLOCK_DEV_ACCESS_OK) {
result = false;
goto _access_fail;
}
if (driver->check_device(device, lba0) != BLOCK_DEV_DRIVER_CHECK_OK) {
result = false;
}
_access_fail:
free(lba0);
_end:
return result;
}
void block_dev_scan() { void block_dev_scan() {
int c_last_block_dev = last_block_dev; int c_last_block_dev = last_block_dev;
for (int i = 0; i < c_last_block_dev; ++i) { for (int i = 0; i < c_last_block_dev; ++i) {
if (block_devices[i].flags.scanned || !block_devices[i].flags.present) continue; if (block_devices[i].flags.scanned || !block_devices[i].flags.present) continue;
uint8_t *lba0 = malloc(block_devices[i].block_size);
uint8_t read_result = block_devices[i].access(&block_devices[i], BLOCK_DEV_DIRECTION_READ, 0, 1, lba0);
if (read_result != BLOCK_DEV_ACCESS_OK) {
block_devices[i].flags.unreadable = 1;
goto _block_dev_scan_free;
}
for (size_t j = 0; j < NUM_DRIVERS; ++j) { for (size_t j = 0; j < NUM_DRIVERS; ++j) {
// only partitioning drivers are automatically assigned // only partitioning drivers are automatically assigned
if (!DRIVER(i)->flags.partitioning) { if (!DRIVER(i)->flags.partitioning) {
@@ -109,15 +104,13 @@ void block_dev_scan() {
} }
// let the driver test the disk // let the driver test the disk
uint8_t driver_result = DRIVER(j)->check_device(&block_devices[i], lba0); uint8_t driver_result = DRIVER(j)->check_device(&block_devices[i]);
if (driver_result == BLOCK_DEV_DRIVER_CHECK_OK) { if (driver_result == BLOCK_DEV_DRIVER_CHECK_OK) {
block_devices[i].driver = DRIVER(j); block_devices[i].driver = DRIVER(j);
block_devices[i].flags.driver_installed = 1; block_devices[i].flags.driver_installed = 1;
break; break;
} }
} }
_block_dev_scan_free:
free(lba0);
block_devices[i].flags.scanned = 1; block_devices[i].flags.scanned = 1;
} }
} }
@@ -132,7 +125,7 @@ void att_noreturn block_dev_task(void *data) {
void block_dev_start_task() { void block_dev_start_task() {
block_semaphore = semaphore_create(1); block_semaphore = semaphore_create(1);
blockdev_task_running = true; blockdev_task_running = true;
task_spawn(block_dev_task, NULL); task_spawn(block_dev_task, NULL, "blockdev");
} }
void block_dev_print_info() { void block_dev_print_info() {
@@ -142,4 +135,10 @@ void block_dev_print_info() {
block_devices[i].identifier, block_devices[i].identifier,
block_devices[i].flags.driver_installed ? block_devices[i].driver->name : "n/a"); block_devices[i].flags.driver_installed ? block_devices[i].driver->name : "n/a");
} }
} }
INIT_FUNCTION(100) = {
.name = "blockdev-task",
.stage = INIT_STAGE_PRE_TASKING,
.init = block_dev_start_task,
};

437
kernel/vfs/lfs/ext2.c Normal file
View File

@@ -0,0 +1,437 @@
//
// Created by rick on 19-09-21.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <myke/vfs/blockdev.h>
#include <myke/vfs/lfs/ext2.h>
#include <myke/vfs/vfs-driver.h>
#include <myke/libk/libk.h>
#include <sys/param.h>
// https://wiki.osdev.org/Ext2
#define EXT2_DRIVER_NAME "ext2"
#define MI(mount) ((ext2_mount_info_t *)(mount)->global_driver_data)
#define FDI(fd) ((ext2_fd_info_t *)(fd)->driver_data)
typedef struct ext2_dgetents_state {
uint32_t bp;
void *current_data;
void *current_data_pos;
void *current_data_end;
uint32_t cur;
bool at_end_of_block;
} ext2_dgetents_state_t;
typedef struct ext2_fd_info {
uint32_t inode_nr;
ext2_inode_t *inode;
size_t seek_position;
ext2_dgetents_state_t *dgetents_state;
size_t size;
bool dgetents_done;
} ext2_fd_info_t;
#define EXT2_READ_OK 0
#define EXT2_READ_ENOMEM 1
#define EXT2_READ_IOERR 2
#define EXT2_READ_EOF 3
int ext2_read_blocks(vfs_mount_t *mount, uint32_t block, uint32_t num, void *target) {
uint32_t lba = (block * MI(mount)->block_size) / BLOCK_DEV_LBA_SIZE;
uint32_t num_lba = DIV_ROUND_UP(num * MI(mount)->block_size, BLOCK_DEV_LBA_SIZE);
void *buffer = malloc(num_lba * BLOCK_DEV_LBA_SIZE);
if (buffer == NULL) {
return EXT2_READ_ENOMEM;
}
if (((block_device_t *) MI(mount)->block_dev)->access(
(block_device_t *) MI(mount)->block_dev,
BLOCK_DEV_DIRECTION_READ, lba, num_lba, buffer)
!= BLOCK_DEV_ACCESS_OK) {
free(buffer);
return EXT2_READ_IOERR; // todo
}
memcpy(target, buffer, MI(mount)->block_size);
free(buffer);
return EXT2_READ_OK;
}
ext2_bg_descriptor_t *ext2_get_bg_descriptor(vfs_mount_t *mount, uint32_t idx) {
uint32_t bg_per_block = MI(mount)->block_size / sizeof(ext2_bg_descriptor_t);
uint32_t block = idx / bg_per_block;
if (MI(mount)->block_size != 1024) {
k_panics("only 1024 supported for now");
}
block += 2;
ext2_bg_descriptor_t *blocks = malloc(MI(mount)->block_size);
if (blocks == NULL) {
return NULL;
}
if (ext2_read_blocks(mount, block, 1, blocks) != EXT2_READ_OK) {
free(blocks);
return NULL;
}
ext2_bg_descriptor_t *res = malloc(sizeof(ext2_bg_descriptor_t));
if (res == NULL) {
free(blocks);
return NULL;
}
uint32_t block_index = idx % bg_per_block;
memcpy(res, &blocks[block_index], sizeof(ext2_bg_descriptor_t));
free(blocks);
return res;
}
ext2_bg_descriptor_t *ext2_get_bg_descriptor_for_inode(vfs_mount_t *mount, uint32_t inode) {
uint32_t group_idx = (inode - 1) / MI(mount)->sb.no_inodes_per_group;
if (group_idx > MI(mount)->no_block_groups) {
return NULL; // todo report
}
ext2_bg_descriptor_t *result = ext2_get_bg_descriptor(mount, group_idx);
if (result == NULL) {
return NULL;
}
return result;
}
ext2_inode_t *ext2_get_inode(vfs_mount_t *mount, uint32_t inode) {
if (inode > MI(mount)->sb.total_inodes) {
return NULL; // todo report
}
ext2_bg_descriptor_t *descriptor = ext2_get_bg_descriptor_for_inode(mount, inode);
if (descriptor == NULL) {
return NULL;
}
uint8_t *inodes_in_group = malloc(MI(mount)->block_size);
if (inodes_in_group == NULL) {
free(descriptor);
return NULL;
}
uint32_t inode_index = (inode - 1) % MI(mount)->sb.no_inodes_per_group;
uint32_t block = (inode_index * MI(mount)->sb.size_inode) / MI(mount)->block_size;
uint32_t inode_offset = (inode_index * MI(mount)->sb.size_inode) % MI(mount)->block_size;
// todo check bitmap?
if (ext2_read_blocks(mount, descriptor->start_block_inode + block, 1, inodes_in_group) != EXT2_READ_OK) {
free(descriptor);
return NULL;
}
free(descriptor);
ext2_inode_t *node = malloc(sizeof(ext2_inode_t));
memcpy(node, &inodes_in_group[inode_offset], sizeof(ext2_inode_t));
free(inodes_in_group);
return node;
}
int ext2_get_block_from_inode(vfs_mount_t *mount, vfs_fd_t *fd, void *target, uint32_t block_idx) {
if (block_idx < 12) {
uint32_t bp = FDI(fd)->inode->dbp[block_idx];
if (bp == 0) {
return EXT2_READ_EOF;
}
return ext2_read_blocks(mount, bp, 1, target);
} else {
k_not_implemented();
}
}
#define EXT2_DGETENT_CONT 1
#define EXT2_DGETENT_FULL 2
#define EXT2_DGETENT_END 3
#define EXT2_DGETENT_ERR 4
int ext2_dgetent_next(vfs_mount_t *mount, vfs_fd_t *fd, ext2_dgetents_state_t *state, void *target, size_t offset,
size_t max_size) {
if (state->bp == UINT32_MAX) {
// new
state->current_data = malloc(MI(mount)->block_size);
state->current_data_pos = state->current_data;
state->current_data_end = state->current_data + MI(mount)->block_size;
state->bp = 0;
state->at_end_of_block = false;
int result = ext2_get_block_from_inode(mount, fd, state->current_data, state->bp);
if (result != EXT2_READ_OK) {
return result == EXT2_READ_EOF ? EXT2_DGETENT_END : EXT2_DGETENT_ERR;
}
}
if (state->at_end_of_block == true) {
state->bp += 1;
int result = ext2_get_block_from_inode(mount, fd, state->current_data, state->bp);
state->current_data_pos = state->current_data;
if (result != EXT2_READ_OK) {
return result == EXT2_READ_EOF ? EXT2_DGETENT_END : EXT2_DGETENT_ERR;
}
}
ext2_dir_entry_t *ent = state->current_data_pos;
if (VFS_DIRENT_SIZE(ent->name_size) > max_size) {
return EXT2_DGETENT_FULL;
}
vfs_mk_dirent_record(&target[offset], ent->inode, offset, 0, &ent->name, ent->name_size);
state->current_data_pos += ent->ent_size;
if (state->current_data_pos >= state->current_data_end) {
state->at_end_of_block = true;
}
return EXT2_DGETENT_CONT;
}
int ext2_vfs_mount(vfs_mount_t *mount) {
ext2_mount_info_t *mount_info = block_dev_mount(mount->device, EXT2_DRIVER_NAME);
if (mount_info == NULL) {
return VFS_MOUNT_ERROR;
}
mount->global_driver_data = mount_info;
return VFS_MOUNT_OK;
}
ext2_fd_info_t *ext2_get_inode_info(vfs_mount_t *mount, uint32_t inode) {
ext2_inode_t *node = ext2_get_inode(mount, inode);
if (node == NULL) {
return NULL;
}
ext2_fd_info_t *driver_data = malloc(sizeof(ext2_fd_info_t));
if (driver_data == NULL) {
return NULL;
}
size_t size = node->size_l;
if (MI(mount)->sb.features_optional & EXT2_FEATURE_RO_64BIT_SIZE && node->type == EXT2_INODE_TYPE_FILE) {
#if EXT2_FEAT_RO_64BIT_SIZE
size += node->size_h << 32;
#else
if (node->size_h != 0) {
printf("WARN: file to large");
free(driver_data);
return NULL;
}
#endif
}
driver_data->inode_nr = inode;
driver_data->inode = node;
driver_data->size = size;
driver_data->seek_position = 0;
driver_data->dgetents_state = NULL;
driver_data->dgetents_done = false;
return driver_data;
}
vfs_dirent_t *ext2_get_dirent_for_filename(vfs_mount_t *mount, vfs_fd_t *dir, const char *path) {
size_t name_length = strlen(path);
vfs_dirent_t *ent = malloc(VFS_DIRENT_MAX_SIZE);
if (ent == NULL) {
return NULL;
}
ext2_dgetents_state_t *state = malloc(sizeof(ext2_dgetents_state_t));
if (state == NULL) {
return NULL;
}
memset(state, 0, sizeof(ext2_dgetents_state_t));
state->bp = UINT32_MAX;
bool found = false;
// todo hash algorithm
while (true) {
const int result = ext2_dgetent_next(mount, dir, state, ent, 0, VFS_DIRENT_MAX_SIZE);
if (result == EXT2_DGETENT_FULL || result == EXT2_DGETENT_ERR) {
break; // whut
}
if (result == EXT2_DGETENT_END) {
// not found
break; // not found
}
if (name_length != strlen(ent->name)) {
continue;
}
if (strncmp(path, ent->name, name_length) != 0) {
// not same name
continue;
}
found = true;
break;
}
free(state);
if (!found) {
free(ent);
return NULL;
}
return ent;
}
int ext2_vfs_open(vfs_mount_t *mount, vfs_fd_t *dir, const char *path, int mode, vfs_fd_t *out) {
if (dir == NULL && path == NULL) {
ext2_fd_info_t *driver_data = ext2_get_inode_info(mount, EXT2_ROOT_INODE);
if (driver_data == NULL) {
return VFS_OPEN_ERROR;
}
out->driver_data = driver_data;
return VFS_OPEN_OK;
}
vfs_dirent_t *dirent = ext2_get_dirent_for_filename(mount, dir, path);
int open_result = VFS_OPEN_ERROR;
if (dirent != NULL) {
ext2_fd_info_t *driver_data = ext2_get_inode_info(mount, dirent->inode);
if (driver_data != NULL) {
out->driver_data = driver_data;
open_result = VFS_OPEN_OK;
}
}
free(dirent);
return open_result;
}
int ext2_vfs_close(vfs_mount_t *mount, vfs_fd_t *fd) {
if (FDI(fd)->dgetents_state != NULL) {
free(FDI(fd)->dgetents_state);
}
free(fd);
return VFS_CLOSE_OK;
}
int ext2_vfs_fstat(vfs_mount_t *mount, vfs_fd_t *fd, stat_t *target, int flags) {
target->st_dev = 0; // todo
target->st_ino = FDI(fd)->inode_nr;
target->st_mode = FDI(fd)->inode->type;
target->st_nlink = FDI(fd)->inode->no_hard_links;
target->st_uid = FDI(fd)->inode->uid;
target->st_gid = FDI(fd)->inode->gid;
target->st_size = FDI(fd)->size;
target->st_blksize = MI(mount)->block_size;
target->st_blocks = FDI(fd)->size / 512; // todo correct?
target->st_atim.tv_sec = FDI(fd)->inode->last_access;
target->st_mtim.tv_sec = FDI(fd)->inode->last_mod;
target->st_ctim.tv_sec = FDI(fd)->inode->created;
if (FDI(fd)->inode->type == EXT2_INODE_TYPE_BLOCK_DEV || FDI(fd)->inode->type == EXT2_INODE_TYPE_CHAR_DEV) {
target->st_rdev = FDI(fd)->inode->dbp[0];
}
return 0;
}
int ext2_vfs_fread(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size) {
size_t target_pos = 0;
void *buffer = malloc(MI(mount)->block_size);
if (buffer == NULL) {
return VFS_READ_ERROR;
}
while (true) {
uint32_t block = FDI(fd)->seek_position / MI(mount)->block_size;
uint32_t bytes_read_in_block = FDI(fd)->seek_position % MI(mount)->block_size;
uint32_t bytes_left_in_block = MI(mount)->block_size - bytes_read_in_block;
size_t toread = MIN(MIN(bytes_left_in_block, size - target_pos), FDI(fd)->size - target_pos);
if (ext2_get_block_from_inode(mount, fd, buffer, block) != EXT2_READ_OK) {
free(buffer);
return VFS_READ_ERROR;
}
memcpy(&target[target_pos], &buffer[block], toread);
target_pos += toread;
FDI(fd)->seek_position += toread;
if (target_pos == size || FDI(fd)->seek_position >= FDI(fd)->size) {
break;
}
}
free(buffer);
return target_pos;
}
int ext2_vfs_dgetent(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size) {
if (FDI(fd)->dgetents_done == true) {
return 0;
}
size_t offset = 0;
size_t prev_offset = 0;
if (FDI(fd)->dgetents_state == NULL) {
FDI(fd)->dgetents_state = malloc(sizeof(ext2_dgetents_state_t));
FDI(fd)->dgetents_state->bp = UINT32_MAX;
FDI(fd)->dgetents_state->cur = 0;
}
while (true) {
int result = ext2_dgetent_next(mount, fd, FDI(fd)->dgetents_state, target, offset, size - offset);
if (result != EXT2_DGETENT_CONT) {
if (result == EXT2_DGETENT_END) {
if (FDI(fd)->dgetents_state->current_data != NULL) {
free(FDI(fd)->dgetents_state->current_data);
FDI(fd)->dgetents_state->current_data = NULL;
}
free(FDI(fd)->dgetents_state);
FDI(fd)->dgetents_state = NULL;
FDI(fd)->dgetents_done = true;
}
if (result == EXT2_DGETENT_FULL || result == EXT2_DGETENT_END) {
((vfs_dirent_t *) &target[prev_offset])->offset_next = size;
}
break;
}
size_t reclen = ((vfs_dirent_t *) &target[offset])->reclen;
prev_offset = offset;
offset += reclen;
}
return offset;
}
uint32_t ext2_get_no_bg(ext2_sb_t *sb) {
uint32_t no_bg_by_blocks = DIV_ROUND_UP(sb->total_blocks, sb->no_blocks_per_group);
uint32_t no_bg_by_inodes = DIV_ROUND_UP(sb->total_inodes, sb->no_inodes_per_group);
if (no_bg_by_blocks != no_bg_by_inodes) {
k_panics("No no match");
}
return no_bg_by_inodes;
}
uint8_t ext2_check_device(block_device_t *device) {
ext2_sb_t *sb = malloc(EXT2_SB_SIZE);
if (device->access(device,
BLOCK_DEV_DIRECTION_READ,
EXT2_SB_ADDR / BLOCK_DEV_LBA_SIZE,
EXT2_SB_SIZE / BLOCK_DEV_LBA_SIZE,
sb) != BLOCK_DEV_ACCESS_OK) {
free(sb);
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
if (sb->ext2_signature != EXT2_SIGNATURE) {
printf("Missing signature\n");
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
printf("Ext2 features:\n\tRequired: %lx\n\tOptional: %lx\n\tRo: %lx\n", sb->features_required,
sb->features_optional, sb->features_ro);
if (sb->features_required ^ EXT2_FEAT_REQ_SUPPORTED) {
printf("Filesystem uses features not supported by implementation, %lx\n", sb->features_required);
free(sb);
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
printf("ext2 valid\n");
ext2_mount_info_t *mount_info = malloc(sizeof(ext2_mount_info_t));
memcpy(&mount_info->sb, sb, sizeof(ext2_sb_t));
mount_info->no_block_groups = ext2_get_no_bg(sb);
mount_info->block_size = 1024 << sb->block_size;
mount_info->fragment_size = 1024 << sb->fragment_size;
mount_info->block_dev = device;
device->driver_info = mount_info;
free(sb);
return BLOCK_DEV_DRIVER_CHECK_OK;
}
BLOCK_DEV_DRIVER(300) = {
.name = EXT2_DRIVER_NAME,
.check_device = ext2_check_device,
.free_device = NULL,
};
VFS_DRIVER(300) = {
.name = EXT2_DRIVER_NAME,
.vfs_mount = ext2_vfs_mount,
.open = ext2_vfs_open,
.close = ext2_vfs_close,
.fstat = ext2_vfs_fstat,
.fread = ext2_vfs_fread,
.dgetent = ext2_vfs_dgetent,
};

View File

@@ -8,7 +8,7 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <myke/fs/blockdev.h> #include <myke/vfs/blockdev.h>
#define FAT_TYPE_12 1 #define FAT_TYPE_12 1
#define FAT_TYPE_16 2 #define FAT_TYPE_16 2
@@ -107,9 +107,26 @@ void print_chars(char *chars, int amount) {
} }
} }
uint8_t att_used fat_check_device(const block_device_t *device, uint8_t *first_sector) { uint8_t att_used fat_check_device(const block_device_t *device) {
uint8_t *first_sector = malloc(512);
if (first_sector == NULL) {
printf("No mem\n");
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
uint8_t result = device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, first_sector);
if (result != BLOCK_DEV_ACCESS_OK) {
printf("Could not access device\n");
free(first_sector);
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
if (first_sector[510] != 0x55 || first_sector[511] != 0xAA) {
printf("No boot signature\n");
free(first_sector);
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
fat_bpb bpb; fat_bpb bpb;
memcpy((uint8_t *) &bpb, first_sector, sizeof(fat_bpb)); memcpy((uint8_t *) &bpb, first_sector, sizeof(fat_bpb));
free(first_sector);
if (bpb.bpb.sectors_per_fat == 0 || bpb.bpb.sectors_per_cluster == 0) { if (bpb.bpb.sectors_per_fat == 0 || bpb.bpb.sectors_per_cluster == 0) {
printf("Definitely not FAT\n"); printf("Definitely not FAT\n");
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;

View File

@@ -7,7 +7,7 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <myke/fs/blockdev.h> #include <myke/vfs/blockdev.h>
typedef struct { typedef struct {
char filename[100]; char filename[100];
@@ -75,15 +75,20 @@ ustar_sector *ustar_next(ustar_sector *current) {
return ustar_sector_valid(next) ? next : NULL; return ustar_sector_valid(next) ? next : NULL;
} }
uint8_t ustar_check_device(const block_device_t *device, uint8_t *first_sector) { uint8_t ustar_check_device(const block_device_t *device) {
ustar_sector *sector = (ustar_sector *) first_sector; ustar_sector *sector = malloc(512); // todo fix leak
if (device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, sector) != BLOCK_DEV_ACCESS_OK) {
free(sector);
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
if (!ustar_sector_valid(sector)) { if (!ustar_sector_valid(sector)) {
free(sector);
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
} }
ustar_fs *fs = malloc(sizeof(ustar_fs)); ustar_fs *fs = malloc(sizeof(ustar_fs));
fs->first_inode = malloc(sizeof(ustar_inode)); fs->first_inode = malloc(sizeof(ustar_inode));
memcpy(&fs->first_inode->sector, first_sector, sizeof(ustar_sector)); memcpy(&fs->first_inode->sector, sector, sizeof(ustar_sector));
fs->first_inode->lba = 0; fs->first_inode->lba = 0;
fs->device = device; fs->device = device;

View File

@@ -9,8 +9,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <myke/drivers/pci/ide.h> #include <myke/drivers/pci/ide.h>
#include <myke/fs/blockdev.h> #include <myke/vfs/blockdev.h>
#include <myke/fs/mbr.h> #include <myke/vfs/part/mbr.h>
typedef struct { typedef struct {
uint8_t bootable; uint8_t bootable;
@@ -33,12 +33,11 @@ typedef struct {
} att_packed mbr_table; } att_packed mbr_table;
typedef struct { typedef struct {
const block_device_t *device; block_device_t *device;
uint32_t start_lba; uint32_t start_lba;
} mbr_block_driver_info; } mbr_block_driver_info;
uint8_t uint8_t mbr_block_dev_access(block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
mbr_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
if (!device->flags.present || lba > device->num_lba) { if (!device->flags.present || lba > device->num_lba) {
return BLOCK_DEV_ACCESS_ERR; return BLOCK_DEV_ACCESS_ERR;
} }
@@ -52,9 +51,15 @@ mbr_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t l
return info->device->access(info->device, direction, actual_lba, sectors, target); return info->device->access(info->device, direction, actual_lba, sectors, target);
} }
uint8_t att_used mbr_check_device(const block_device_t *device, uint8_t *first_sector) { uint8_t mbr_check_device(block_device_t *device) {
uint8_t *first_sector = malloc(512);
if (device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, first_sector) != BLOCK_DEV_ACCESS_OK) {
free(first_sector);
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
}
mbr_table table; mbr_table table;
memcpy((uint8_t *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table)); memcpy((uint8_t *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table));
free(first_sector);
if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
} }

14
kernel/vfs/tmpfs.c Normal file
View File

@@ -0,0 +1,14 @@
//
// Created by rick on 13-08-21.
//
#include <myke/util/init.h>
void tmpfs_init() {
}
INIT_FUNCTION(100) = {
.name = "tmpfs",
.stage = INIT_STAGE_AFTER_BOOT_PRE_INIT,
.init = tmpfs_init,
};

186
kernel/vfs/vfs.c Normal file
View File

@@ -0,0 +1,186 @@
//
// Created by rick on 12-08-21.
//
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <myke/tasks/locking.h>
#include <myke/vfs/vfs.h>
#include <myke/vfs/vfs-driver.h>
#include <myke/util/init.h>
#include <myke/libk/libk.h>
vfs_mount_t *first_mount = NULL;
mutex_t *mount_lock = NULL;
extern vfs_driver_t __start_vfs_driver[];
extern vfs_driver_t __stop_vfs_driver[];
#define NUM_DRIVERS ((size_t)(__stop_vfs_driver - __start_vfs_driver))
#define DRIVER(i) ((__start_vfs_driver) + (i))
vfs_driver_t *vfs_get_driver_by_name(const char *name) {
for (size_t i = 0; i < NUM_DRIVERS; ++i) {
if (strcmp(DRIVER(i)->name, name) == 0) {
return DRIVER(i);
}
}
return NULL;
}
void vfs_register_mount(vfs_mount_t *mount) {
mutex_acquire(mount_lock);
if (first_mount == NULL) {
first_mount = mount;
} else {
vfs_mount_t *last_mount = first_mount;
while (last_mount->next != NULL) last_mount = last_mount->next;
last_mount->next = mount;
}
mutex_release(mount_lock);
}
vfs_mount_t *vfs_get_mount_for_path(const char *path) {
if (first_mount == NULL) {
return NULL;
}
mutex_acquire(mount_lock);
size_t max_length = strlen(path);
vfs_mount_t *longest_match = NULL;
size_t match_length = 0;
vfs_mount_t *last_mount = NULL;
do {
if (last_mount == NULL) {
last_mount = first_mount;
} else if ((last_mount = last_mount->next) == NULL) {
break;
}
size_t mount_length = strlen(last_mount->prefix);
if (mount_length > max_length || mount_length < match_length) {
continue;
}
if (strncmp(last_mount->prefix, path, strlen(last_mount->prefix)) == 0) {
longest_match = last_mount;
match_length = mount_length;
}
} while (true);
mutex_release(mount_lock);
return longest_match;
}
int vfs_mount(const char *path, const char *device, const char *driver) {
vfs_driver_t *driver_impl = vfs_get_driver_by_name(driver);
if (driver_impl == NULL) {
return VFS_MOUNT_ERROR;
}
vfs_mount_t *mount = malloc(sizeof(vfs_mount_t));
mount->driver = driver_impl;
mount->device = device;
mount->prefix = path;
int result = driver_impl->vfs_mount(mount);
if (result != VFS_MOUNT_OK) {
free(mount);
return result;
}
vfs_register_mount(mount);
return VFS_MOUNT_OK;
}
vfs_fd_t *vfs_open_intermediate(vfs_mount_t *mount, const char *path, int flags, int mode) {
vfs_fd_t *intermediate_dir = malloc(sizeof(vfs_fd_t));
vfs_fd_t *out = malloc(sizeof(vfs_fd_t));
out->mount = mount;
intermediate_dir->mount = mount;
char *full_path = strdup(path);
char *current_path = full_path;
while (strlen(current_path) > 0) {
if (current_path[0] == '/') {
// root
if (((vfs_driver_t *) mount->driver)->open(mount, NULL, NULL, flags, out) != VFS_OPEN_OK) {
free(out);
free(intermediate_dir);
free(full_path);
return NULL;
}
current_path = &current_path[1];
} else {
char *next_dir = strchr(current_path, '/');
if (next_dir != NULL) {
next_dir[0] = 0;
}
if (((vfs_driver_t *) mount->driver)->open(mount, intermediate_dir, current_path, flags, out) !=
VFS_OPEN_OK) {
((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir);
free(out);
free(intermediate_dir);
free(full_path);
return NULL;
}
if (next_dir == NULL) {
current_path = &current_path[strlen(current_path)];
} else {
current_path = &next_dir[1];
}
if (((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir) != VFS_CLOSE_OK) {
free(out);
free(intermediate_dir);
free(full_path);
return NULL;
}
}
memcpy(intermediate_dir, out, sizeof(vfs_fd_t));
}
free(full_path);
free(intermediate_dir);
return out;
}
// https://man7.org/linux/man-pages/man2/open.2.html
vfs_fd_t *vfs_open(const char *path, int flags, int mode) {
vfs_mount_t *mount = vfs_get_mount_for_path(path);
if (mount == NULL) {
return NULL;
}
return vfs_open_intermediate(mount, &path[strlen(mount->prefix) - 1], flags, mode);
}
void vfs_close(vfs_fd_t *fd) {
((vfs_driver_t *) (fd->mount->driver))->close(fd->mount, fd);
free(fd);
}
// https://man7.org/linux/man-pages/man2/stat.2.html
int vfs_fstat(vfs_fd_t *dirfd, stat_t *target, int flags) {
return ((vfs_driver_t *) (dirfd->mount->driver))->fstat(dirfd->mount, dirfd, target, flags);
}
// https://man7.org/linux/man-pages/man2/read.2.html
int vfs_read(vfs_fd_t *fd, void *target, size_t size) {
return ((vfs_driver_t *) (fd->mount->driver))->fread(fd->mount, fd, target, size);
}
// inspiration https://man7.org/linux/man-pages/man2/getdents.2.html
int vfs_getdents(vfs_fd_t *fd, void *target, int count) {
return ((vfs_driver_t *) fd->mount->driver)->dgetent(fd->mount, fd, target, count);
}
void vfs_mk_dirent_record(vfs_dirent_t *ent, uint32_t inode, uint32_t cur_offset, uint8_t type, char *name,
size_t name_length) {
ent->inode = inode;
strncpy(ent->name, name, name_length);
ent->name[name_length] = 0;
ent->type = type;
ent->reclen = VFS_DIRENT_SIZE(name_length);
ent->offset_next = cur_offset + ent->reclen;
}
void vfs_init() {
mount_lock = mutex_create();
}
INIT_FUNCTION(100) = {
.name = "vfs-task",
.stage = INIT_STAGE_PRE_TASKING,
.init = vfs_init,
};

1
lai Submodule

Submodule lai added at 432546ee09

View File

@@ -10,53 +10,55 @@ SECTIONS
loaded at by the bootloader. */ loaded at by the bootloader. */
. = 1M; . = 1M;
_kernel_start = .; _kernel_start = .;
.boot.data ALIGN(4K) : {
*(.multiboot)
*(.boot.data)
}
.boot.text ALIGN(4K) : {
*(.boot.text)
}
.boot.bss ALIGN(4K) : {
*(.boot.bss)
}
. += 0xC0000000;
/* First put the multiboot header, as it is required to be put very early /* First put the multiboot header, as it is required to be put very early
early in the image or the bootloader won't recognize the file format. early in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */ Next we'll put the .text section. */
.text ALIGN(4K) : AT(ADDR(.text)-0xC0000000) .text BLOCK(4K) : ALIGN(4K)
{ {
*(.multiboot)
*(.text) *(.text)
} }
/* Read-only data. */ /* Read-only data. */
.rodata ALIGN(4K) : AT(ADDR(.rodata)-0xC0000000) .rodata BLOCK(4K) : ALIGN(4K)
{ {
*(.rodata) *(.rodata)
} }
/* Read-write data (initialized) */ /* Read-write data (initialized) */
.data ALIGN(4K) : AT(ADDR(.data)-0xC0000000) .data BLOCK(4K) : ALIGN(4K)
{ {
*(.data) *(.data)
. = ALIGN(16); . = ALIGN(16);
__start_pci_driver = .; __start_pci_driver = .;
*(SORT(.pci_driver.*)) *(SORT(.pci_driver.*))
__stop_pci_driver = .; __stop_pci_driver = .;
. = ALIGN(16); . = ALIGN(16);
__start_block_dev_driver = .; __start_block_dev_driver = .;
*(SORT(.block_dev_driver.*)) *(SORT(.block_dev_driver.*))
__stop_block_dev_driver = .; __stop_block_dev_driver = .;
. = ALIGN(16);
__start_vfs_driver = .;
*(SORT(.vfs_driver.*))
__stop_vfs_driver = .;
. = ALIGN(16);
__start_init = .;
*(SORT(.init.*))
__stop_init = .;
} }
/* Read-write data (uninitialized) and stack */ /* Read-write data (uninitialized) and stack */
.bss ALIGN(4K) : AT(ADDR(.bss)-0xC0000000) .bss BLOCK(4K) : ALIGN(4K)
{ {
*(COMMON) *(COMMON)
*(.bss) *(.bss)
} }
_kernel_end = . - 0xC0000000; _kernel_end = .;
/DISCARD/ : { /DISCARD/ : {
*(.eh_frame); *(.eh_frame);

3
rootfs/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
mnt/*
!mnt
rootfs.img

52
rootfs/mkrootfs.sh Executable file
View File

@@ -0,0 +1,52 @@
#!/bin/bash
IMG_FILE=rootfs.img
IMG_SIZE=100 # MB
function log() {
echo "$*"
}
function yes_or_no() {
while true; do
read -p "$* [y/n]: " yn
case $yn in
[Yy]*) return 0 ;;
[Nn]*)
echo "Aborted"
return 1
;;
esac
done
}
function setup_lb() {
sudo losetup -fP --show ${IMG_FILE}
}
if [ ! -d mnt ]; then
mkdir mnt
fi
if [ -f "${IMG_FILE}" ]; then
log "${IMG_FILE} already exists"
if ! yes_or_no "Continue?"; then
exit 1
fi
fi
# build img
dd if=/dev/zero of=${IMG_FILE} bs=1M count=${IMG_SIZE}
parted -s ${IMG_FILE} mktable msdos
parted -s ${IMG_FILE} mkpart primary ext2 0 100%
LB_DEV="$(setup_lb)"
if [ -z "${LB_DEV}" ]; then
log "Failed to setup loobback"
exit 1
fi
sudo mkfs.ext2 -L rootfs "${LB_DEV}p1"
sudo mount "${LB_DEV}p1" mnt

39
rootfs/mount_rootfs.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/bash
IMG_FILE=rootfs.img
IMG_SIZE=100 # MB
function log() {
echo "$*"
}
function yes_or_no() {
while true; do
read -p "$* [y/n]: " yn
case $yn in
[Yy]*) return 0 ;;
[Nn]*)
echo "Aborted"
return 1
;;
esac
done
}
function setup_lb() {
sudo losetup -fP --show ${IMG_FILE}
}
if [ ! -f "${IMG_FILE}" ]; then
log "${IMG_FILE} doesn't exist"
exit 1
fi
LB_DEV="$(setup_lb)"
if [ -z "${LB_DEV}" ]; then
log "Failed to setup loobback"
exit 1
fi
sudo mount "${LB_DEV}p1" mnt

15
rootfs/umount_rootfsh.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
function log() {
echo "$*"
}
LB_DEV=$(findmnt -n -o SOURCE mnt)
if [ -z "${LB_DEV}" ]; then
log "Not mounted"
exit 1
fi
sudo umount mnt
sudo losetup -d "${LB_DEV%p1}"