diff --git a/ChangeLog b/ChangeLog index 079429af..1d83e3ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-06-24 Alex Kotov + + * configure.ac: Added packages "arch-*" and "asm" + 2022-06-23 Alex Kotov * configure.ac: Added package "drivers" diff --git a/Makefile.am b/Makefile.am index 6e192c4c..fdf735eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,10 +42,19 @@ if WITH_LIBC libkernaux_la_LIBADD += libc/libc.la endif +####### +# ARCH # +####### + +if WITH_ARCH_I386 +libkernaux_la_SOURCES += src/arch/i386.c +endif + ####### # ASM # ####### +if WITH_ASM if ASM_I386 libkernaux_la_SOURCES += src/asm/i386.S endif @@ -55,6 +64,7 @@ endif if ASM_X86_64 libkernaux_la_SOURCES += src/asm/x86_64.S endif +endif #################### # Default packages # diff --git a/README.md b/README.md index 8e68956c..6d59fb3d 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,11 @@ stable options. All packages are included by default. To exclude all packages except those explicitly included, use `--without-all`. +* `--with[out]-arch-all` - all architectures +* `--with[out]-arch-i386` - architecture i386 +* `--with[out]-arch-riscv64` - architecture riscv64 +* `--with[out]-arch-x86-64` - architecture x86-64 +* `--with[out]-asm` - kernel assembler helpers * `--with[out]-cmdline` - command line parser * `--with[out]-free-list` - free list memory allocator * `--with[out]-io` - input/output diff --git a/configure.ac b/configure.ac index c3741dac..65f97a85 100644 --- a/configure.ac +++ b/configure.ac @@ -44,35 +44,40 @@ AC_CONFIG_FILES([ ############### dnl Features (enabled by default) -AC_ARG_ENABLE([debug], AS_HELP_STRING([--disable-debug], [disable debugging])) -AC_ARG_ENABLE([float], AS_HELP_STRING([--disable-float], [disable floating-point arithmetic])) -AC_ARG_ENABLE([werror], AS_HELP_STRING([--disable-werror], [disable -Werror])) +AC_ARG_ENABLE([debug], AS_HELP_STRING([--disable-debug], [disable debugging])) +AC_ARG_ENABLE([float], AS_HELP_STRING([--disable-float], [disable floating-point arithmetic])) +AC_ARG_ENABLE([werror], AS_HELP_STRING([--disable-werror], [disable -Werror])) dnl Features (disabled by default) -AC_ARG_ENABLE([freestanding], AS_HELP_STRING([--enable-freestanding], [build for freestanding environment])) -AC_ARG_ENABLE([split-libc], AS_HELP_STRING([--enable-split-libc], [split off libc])) -AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [enable usual tests and examples])) -AC_ARG_ENABLE([tests-all], AS_HELP_STRING([--enable-tests-all], [enable all tests])) -AC_ARG_ENABLE([tests-python], AS_HELP_STRING([--enable-tests-python], [enable tests that require Python 3 with YAML and Jinja2])) +AC_ARG_ENABLE([freestanding], AS_HELP_STRING([--enable-freestanding], [build for freestanding environment])) +AC_ARG_ENABLE([split-libc], AS_HELP_STRING([--enable-split-libc], [split off libc])) +AC_ARG_ENABLE([tests], AS_HELP_STRING([--enable-tests], [enable usual tests and examples])) +AC_ARG_ENABLE([tests-all], AS_HELP_STRING([--enable-tests-all], [enable all tests])) +AC_ARG_ENABLE([tests-python], AS_HELP_STRING([--enable-tests-python], [enable tests that require Python 3 with YAML and Jinja2])) dnl Packages (enabled by default) -AC_ARG_WITH( [all], AS_HELP_STRING([--without-all], [without all default packages])) -AC_ARG_WITH( [cmdline], AS_HELP_STRING([--without-cmdline], [without command line parser])) -AC_ARG_WITH( [elf], AS_HELP_STRING([--without-elf], [without ELF utils])) -AC_ARG_WITH( [free-list], AS_HELP_STRING([--without-free-list], [without free list memory allocator])) -AC_ARG_WITH( [io], AS_HELP_STRING([--without-io], [without input/output])) -AC_ARG_WITH( [mbr], AS_HELP_STRING([--without-mbr], [without Master Boot Record])) -AC_ARG_WITH( [memmap], AS_HELP_STRING([--without-memmap], [without memory map])) -AC_ARG_WITH( [multiboot2], AS_HELP_STRING([--without-multiboot2], [without Multiboot 2 information parser])) -AC_ARG_WITH( [ntoa], AS_HELP_STRING([--without-ntoa], [without itoa/ftoa])) -AC_ARG_WITH( [pfa], AS_HELP_STRING([--without-pfa], [without Page Frame Allocator])) -AC_ARG_WITH( [printf], AS_HELP_STRING([--without-printf], [without printf])) -AC_ARG_WITH( [printf-fmt], AS_HELP_STRING([--without-printf-fmt], [without printf format parser])) -AC_ARG_WITH( [units], AS_HELP_STRING([--without-units], [without measurement units utils])) +AC_ARG_WITH( [all], AS_HELP_STRING([--without-all], [without all default packages])) +AC_ARG_WITH( [arch-all], AS_HELP_STRING([--without-arch-all], [without all architectures])) +AC_ARG_WITH( [arch-i386], AS_HELP_STRING([--without-arch-i386], [without architecture i386])) +AC_ARG_WITH( [arch-riscv64], AS_HELP_STRING([--without-arch-riscv64], [without architecture riscv64])) +AC_ARG_WITH( [arch-x86-64], AS_HELP_STRING([--without-arch-x86-64], [without architecture x86-64])) +AC_ARG_WITH( [asm], AS_HELP_STRING([--without-asm], [without kernel assembler helpers])) +AC_ARG_WITH( [cmdline], AS_HELP_STRING([--without-cmdline], [without command line parser])) +AC_ARG_WITH( [elf], AS_HELP_STRING([--without-elf], [without ELF utils])) +AC_ARG_WITH( [free-list], AS_HELP_STRING([--without-free-list], [without free list memory allocator])) +AC_ARG_WITH( [io], AS_HELP_STRING([--without-io], [without input/output])) +AC_ARG_WITH( [mbr], AS_HELP_STRING([--without-mbr], [without Master Boot Record])) +AC_ARG_WITH( [memmap], AS_HELP_STRING([--without-memmap], [without memory map])) +AC_ARG_WITH( [multiboot2], AS_HELP_STRING([--without-multiboot2], [without Multiboot 2 information parser])) +AC_ARG_WITH( [ntoa], AS_HELP_STRING([--without-ntoa], [without itoa/ftoa])) +AC_ARG_WITH( [pfa], AS_HELP_STRING([--without-pfa], [without Page Frame Allocator])) +AC_ARG_WITH( [printf], AS_HELP_STRING([--without-printf], [without printf])) +AC_ARG_WITH( [printf-fmt], AS_HELP_STRING([--without-printf-fmt], [without printf format parser])) +AC_ARG_WITH( [units], AS_HELP_STRING([--without-units], [without measurement units utils])) dnl Packages (disabled by default) -AC_ARG_WITH( [drivers], AS_HELP_STRING([--with-drivers], [with drivers])) -AC_ARG_WITH( [libc], AS_HELP_STRING([--with-libc], [with libc replacement])) +AC_ARG_WITH( [drivers], AS_HELP_STRING([--with-drivers], [with drivers])) +AC_ARG_WITH( [libc], AS_HELP_STRING([--with-libc], [with libc replacement])) @@ -87,20 +92,32 @@ if test -z "$enable_tests_python"; then enable_tests_python=yes; fi ]) AS_IF([test "$enable_tests_all" = yes], do_enable_tests_all) +AC_DEFUN([do_without_arch_all], +[ +if test -z "$with_arch_i386"; then with_arch_i386=no; fi +if test -z "$with_arch_riscv64"; then with_arch_riscv64=no; fi +if test -z "$with_arch_x86_64"; then with_arch_x86_64=no; fi +]) +AS_IF([test "$with_arch_all" = no], do_without_arch_all) + AC_DEFUN([do_without_all], [ -if test -z "$with_cmdline"; then with_cmdline=no; fi -if test -z "$with_elf"; then with_elf=no; fi -if test -z "$with_free_list"; then with_free_list=no; fi -if test -z "$with_io"; then with_io=no; fi -if test -z "$with_mbr"; then with_mbr=no; fi -if test -z "$with_memmap"; then with_memmap=no; fi -if test -z "$with_multiboot2"; then with_multiboot2=no; fi -if test -z "$with_ntoa"; then with_ntoa=no; fi -if test -z "$with_pfa"; then with_pfa=no; fi -if test -z "$with_printf"; then with_printf=no; fi -if test -z "$with_printf_fmt"; then with_printf_fmt=no; fi -if test -z "$with_units"; then with_units=no; fi +if test -z "$with_arch_i386"; then with_arch_i386=no; fi +if test -z "$with_arch_riscv64"; then with_arch_riscv64=no; fi +if test -z "$with_arch_x86_64"; then with_arch_x86_64=no; fi +if test -z "$with_asm"; then with_asm=no; fi +if test -z "$with_cmdline"; then with_cmdline=no; fi +if test -z "$with_elf"; then with_elf=no; fi +if test -z "$with_free_list"; then with_free_list=no; fi +if test -z "$with_io"; then with_io=no; fi +if test -z "$with_mbr"; then with_mbr=no; fi +if test -z "$with_memmap"; then with_memmap=no; fi +if test -z "$with_multiboot2"; then with_multiboot2=no; fi +if test -z "$with_ntoa"; then with_ntoa=no; fi +if test -z "$with_pfa"; then with_pfa=no; fi +if test -z "$with_printf"; then with_printf=no; fi +if test -z "$with_printf_fmt"; then with_printf_fmt=no; fi +if test -z "$with_units"; then with_units=no; fi ]) AS_IF([test "$with_all" = no], do_without_all) @@ -124,6 +141,11 @@ AS_IF([test "$enable_tests_python" = yes], [enable_tests_python=yes], [enable_te dnl Packages (enabled by default) AS_IF([test "$with_all" = no ], [with_all=no], [with_all=yes]) +AS_IF([test "$with_arch_all" = no ], [with_arch_all=no], [with_arch_all=yes]) +AS_IF([test "$with_arch_i386" = no ], [with_arch_i386=no], [with_arch_i386=yes]) +AS_IF([test "$with_arch_riscv64" = no ], [with_arch_riscv64=no], [with_arch_riscv64=yes]) +AS_IF([test "$with_arch_x86_64" = no ], [with_arch_x86_64=no], [with_arch_x86_64=yes]) +AS_IF([test "$with_asm" = no ], [with_asm=no], [with_asm=yes]) AS_IF([test "$with_cmdline" = no ], [with_cmdline=no], [with_cmdline=yes]) AS_IF([test "$with_elf" = no ], [with_elf=no], [with_elf=yes]) AS_IF([test "$with_free_list" = no ], [with_free_list=no], [with_free_list=yes]) @@ -179,6 +201,10 @@ AM_CONDITIONAL([ENABLE_TESTS], [test "$enable_tests" = yes]) AM_CONDITIONAL([ENABLE_TESTS_PYTHON], [test "$enable_tests_python" = yes]) dnl Packages (enabled by default) +AM_CONDITIONAL([WITH_ARCH_I386], [test "$with_arch_i386" = yes]) +AM_CONDITIONAL([WITH_ARCH_RISCV64], [test "$with_arch_riscv64" = yes]) +AM_CONDITIONAL([WITH_ARCH_X86_64], [test "$with_arch_x86_64" = yes]) +AM_CONDITIONAL([WITH_ASM], [test "$with_asm" = yes]) AM_CONDITIONAL([WITH_CMDLINE], [test "$with_cmdline" = yes]) AM_CONDITIONAL([WITH_ELF], [test "$with_elf" = yes]) AM_CONDITIONAL([WITH_FREE_LIST], [test "$with_free_list" = yes]) @@ -219,6 +245,10 @@ AS_IF([test "$enable_tests" = yes], [AC_DEFINE([ENABLE_TESTS], [1] AS_IF([test "$enable_tests_python" = yes], [AC_DEFINE([ENABLE_TESTS_PYTHON], [1], [enabled tests that require Python 3 with YAML and Jinja2])]) dnl Packages (enabled by default) +AS_IF([test "$with_arch_i386" = yes], [AC_DEFINE([WITH_ARCH_I386], [1], [with architecture i386])]) +AS_IF([test "$with_arch_riscv64" = yes], [AC_DEFINE([WITH_ARCH_RISCV64], [1], [with architecture riscv64])]) +AS_IF([test "$with_arch_x86_64" = yes], [AC_DEFINE([WITH_ARCH_X86_64], [1], [with architecture x86_64])]) +AS_IF([test "$with_asm" = yes], [AC_DEFINE([WITH_ASM], [1], [with kernel assembler helpers])]) AS_IF([test "$with_cmdline" = yes], [AC_DEFINE([WITH_CMDLINE], [1], [with command line parser])]) AS_IF([test "$with_elf" = yes], [AC_DEFINE([WITH_ELF], [1], [with ELF utils])]) AS_IF([test "$with_free_list" = yes], [AC_DEFINE([WITH_FREE_LIST], [1], [with free list memory allocator])]) @@ -246,18 +276,21 @@ AS_IF([test "$enable_debug" = yes], [AC_DEFINE([KERNAUX_DEBUG], [1] ########################## dnl Packages (enabled by default) -AS_IF([test "$with_cmdline" = no], [AC_SUBST([comment_line_cmdline], [//])]) -AS_IF([test "$with_elf" = no], [AC_SUBST([comment_line_elf], [//])]) -AS_IF([test "$with_free_list" = no], [AC_SUBST([comment_line_free_list], [//])]) -AS_IF([test "$with_io" = no], [AC_SUBST([comment_line_io], [//])]) -AS_IF([test "$with_mbr" = no], [AC_SUBST([comment_line_mbr], [//])]) -AS_IF([test "$with_memmap" = no], [AC_SUBST([comment_line_memmap], [//])]) -AS_IF([test "$with_multiboot2" = no], [AC_SUBST([comment_line_multiboot2], [//])]) -AS_IF([test "$with_ntoa" = no], [AC_SUBST([comment_line_ntoa], [//])]) -AS_IF([test "$with_pfa" = no], [AC_SUBST([comment_line_pfa], [//])]) -AS_IF([test "$with_printf" = no], [AC_SUBST([comment_line_printf], [//])]) -AS_IF([test "$with_printf_fmt" = no], [AC_SUBST([comment_line_printf_fmt], [//])]) -AS_IF([test "$with_units" = no], [AC_SUBST([comment_line_units], [//])]) +AS_IF([test "$with_arch_i386" = no], [AC_SUBST([comment_line_arch_i386], [//])]) +AS_IF([test "$with_arch_riscv64" = no], [AC_SUBST([comment_line_arch_riscv64], [//])]) +AS_IF([test "$with_arch_x86_64" = no], [AC_SUBST([comment_line_arch_x86_64], [//])]) +AS_IF([test "$with_cmdline" = no], [AC_SUBST([comment_line_cmdline], [//])]) +AS_IF([test "$with_elf" = no], [AC_SUBST([comment_line_elf], [//])]) +AS_IF([test "$with_free_list" = no], [AC_SUBST([comment_line_free_list], [//])]) +AS_IF([test "$with_io" = no], [AC_SUBST([comment_line_io], [//])]) +AS_IF([test "$with_mbr" = no], [AC_SUBST([comment_line_mbr], [//])]) +AS_IF([test "$with_memmap" = no], [AC_SUBST([comment_line_memmap], [//])]) +AS_IF([test "$with_multiboot2" = no], [AC_SUBST([comment_line_multiboot2], [//])]) +AS_IF([test "$with_ntoa" = no], [AC_SUBST([comment_line_ntoa], [//])]) +AS_IF([test "$with_pfa" = no], [AC_SUBST([comment_line_pfa], [//])]) +AS_IF([test "$with_printf" = no], [AC_SUBST([comment_line_printf], [//])]) +AS_IF([test "$with_printf_fmt" = no], [AC_SUBST([comment_line_printf_fmt], [//])]) +AS_IF([test "$with_units" = no], [AC_SUBST([comment_line_units], [//])]) diff --git a/include/Makefile.am b/include/Makefile.am index 8781819f..856b2f39 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,19 +4,31 @@ nobase_include_HEADERS = \ kernaux.h \ - kernaux/arch/i386.h \ - kernaux/arch/riscv64.h \ - kernaux/arch/x86_64.h \ kernaux/assert.h \ kernaux/macro.h \ kernaux/version.h \ kernaux/generic/malloc.h \ kernaux/generic/mutex.h +######## +# ARCH # +######## + +if WITH_ARCH_I386 +nobase_include_HEADERS += kernaux/arch/i386.h +endif +if WITH_ARCH_RISCV64 +nobase_include_HEADERS += kernaux/arch/riscv64.h +endif +if WITH_ARCH_X86_64 +nobase_include_HEADERS += kernaux/arch/x86_64.h +endif + ####### # ASM # ####### +if WITH_ASM if ASM_I386 nobase_include_HEADERS += kernaux/asm/i386.h endif @@ -26,6 +38,7 @@ endif if ASM_X86_64 nobase_include_HEADERS += kernaux/asm/x86_64.h endif +endif #################### # Default packages # diff --git a/include/kernaux.h.in b/include/kernaux.h.in index 47490224..1905fb53 100644 --- a/include/kernaux.h.in +++ b/include/kernaux.h.in @@ -10,6 +10,10 @@ #include #include +@comment_line_arch_i386@#include +@comment_line_arch_riscv64@#include +@comment_line_arch_x86_64@#include + @comment_line_cmdline@#include @comment_line_elf@#include @comment_line_free_list@#include @@ -22,7 +26,3 @@ @comment_line_printf@#include @comment_line_printf_fmt@#include @comment_line_units@#include - -#include -#include -#include diff --git a/include/kernaux/arch/i386.h b/include/kernaux/arch/i386.h index 40280dc1..5cd981f7 100644 --- a/include/kernaux/arch/i386.h +++ b/include/kernaux/arch/i386.h @@ -49,9 +49,9 @@ extern "C" { #define KERNAUX_ARCH_I386_CR4_PGE ((uint32_t)0x00000080) // 7: Page Global Enabled // TODO: bits 8-31 -// Global descriptor table entry +// Global or local descriptor table entry // TODO: validate this according to spec -struct KernAux_Arch_I386_GDTE { +struct KernAux_Arch_I386_DTE { unsigned limit_low : 16; unsigned base_low : 24; unsigned accessed : 1; @@ -70,6 +70,57 @@ struct KernAux_Arch_I386_GDTE { } __attribute__((packed)); +/** + * @brief Task state segment + * @see The manual, page 132, figure 7-1 + */ +struct KernAux_Arch_I386_TSS { + // 0x00 + unsigned prev_tss : 16; + unsigned _zero0 : 16; + // 0x04 + unsigned esp0 : 32; + unsigned ss0 : 16; + unsigned _zero1 : 16; + unsigned esp1 : 32; + unsigned ss1 : 16; + unsigned _zero2 : 16; + unsigned esp2 : 32; + unsigned ss2 : 16; + unsigned _zero3 : 16; + // 0x1c + unsigned cr3 : 32; + unsigned eip : 32; + unsigned eflags : 32; + unsigned eax : 32; + unsigned ecx : 32; + unsigned edx : 32; + unsigned ebx : 32; + unsigned esp : 32; + unsigned ebp : 32; + unsigned esi : 32; + unsigned edi : 32; + // 0x48 + unsigned es : 16; + unsigned _zero4 : 16; + unsigned cs : 16; + unsigned _zero5 : 16; + unsigned ss : 16; + unsigned _zero6 : 16; + unsigned ds : 16; + unsigned _zero7 : 16; + unsigned fs : 16; + unsigned _zero8 : 16; + unsigned gs : 16; + unsigned _zero9 : 16; + unsigned ldt : 16; + unsigned _zero10 : 16; + // 0x64 + unsigned _zero11 : 16; + unsigned io_map_base : 16; +} +__attribute__((packed)); + // Page directory entry // TODO: validate this according to spec struct KernAux_Arch_I386_PDE { diff --git a/include/kernaux/asm/i386.h b/include/kernaux/asm/i386.h index 5656df91..91eaa4a2 100644 --- a/include/kernaux/asm/i386.h +++ b/include/kernaux/asm/i386.h @@ -15,6 +15,14 @@ inline static void kernaux_asm_i386_outportb(uint16_t port, uint8_t value); inline static void kernaux_asm_i386_outportw(uint16_t port, uint16_t value); inline static void kernaux_asm_i386_outportd(uint16_t port, uint32_t value); +void kernaux_asm_i386_flush_gdt( + volatile uint32_t pointer, + volatile uint32_t data_selector, + volatile uint32_t code_selector +); +void kernaux_asm_i386_flush_idt(volatile uint32_t pointer); +void kernaux_asm_i386_flush_tss(volatile uint16_t selector); + uint32_t kernaux_asm_i386_read_cr0(); uint32_t kernaux_asm_i386_read_cr4(); diff --git a/src/arch/i386.c b/src/arch/i386.c new file mode 100644 index 00000000..edb517a5 --- /dev/null +++ b/src/arch/i386.c @@ -0,0 +1,9 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +__attribute__((unused)) +static const int +TSS_validation[sizeof(struct KernAux_Arch_I386_TSS) == 104 ? 1 : -1]; diff --git a/src/asm/i386.S b/src/asm/i386.S index ea61c91e..71fba80a 100644 --- a/src/asm/i386.S +++ b/src/asm/i386.S @@ -2,12 +2,40 @@ #include "config.h" #endif +.global kernaux_asm_i386_flush_gdt +.global kernaux_asm_i386_flush_idt +.global kernaux_asm_i386_flush_tss .global kernaux_asm_i386_read_cr0 .global kernaux_asm_i386_read_cr4 .global kernaux_asm_i386_write_cr0 .global kernaux_asm_i386_write_cr3 .global kernaux_asm_i386_write_cr4 +kernaux_asm_i386_flush_gdt: + mov 4(%esp), %eax + mov 8(%esp), %edx + lgdt (%eax) + mov %edx, %ds + mov %edx, %es + mov %edx, %fs + mov %edx, %gs + mov %edx, %ss + pushl 12(%esp) + push $.flush + ljmp *(%esp) + .flush: + ret + +kernaux_asm_i386_flush_idt: + mov 4(%esp), %eax + lidt (%eax) + ret + +kernaux_asm_i386_flush_tss: + mov 4(%esp), %ax + ltr %ax + ret + kernaux_asm_i386_read_cr0: mov %cr0, %eax ret