diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e4494ed --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "errno.h": "c" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index ced3f65..3d56b2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,77 +1,78 @@ -cmake_minimum_required(VERSION 2.8.4) - -# ------------------------------------------------------------------------------ -# Add the debugging option. -set(DEBUGGING_TYPE "DEBUG_STDIO" CACHE STRING - "Chose the type of debugging: DEBUG_STDIO DEBUG_LOG") -set_property( - CACHE DEBUGGING_TYPE PROPERTY STRINGS - DEBUG_STDIO - DEBUG_LOG) -if ("${DEBUGGING_TYPE}" STREQUAL "DEBUG_STDIO" OR - "${DEBUGGING_TYPE}" STREQUAL "DEBUG_LOG") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D${DEBUGGING_TYPE}") - message(STATUS "Setting debugging type to ${DEBUGGING_TYPE}.") -else () - message(FATAL_ERROR "Debugging type ${DEBUGGING_TYPE} is not valid.") -endif () - -# ------------------------------------------------------------------------------ -# Add the sub-directories. -add_subdirectory(mentos) -add_subdirectory(initscp) - -# ------------------------------------------------------------------------------ -# Generate the initrd filesystem. -add_custom_target( - initfs - COMMAND echo "---------------------------------------------" - COMMAND echo "Initializing 'initfs'..." - COMMAND echo "---------------------------------------------" - COMMAND initfscp -s ${CMAKE_SOURCE_DIR}/files -t ${CMAKE_BINARY_DIR}/initfs -m /dev - COMMAND echo "---------------------------------------------" - COMMAND echo "Done!" - COMMAND echo "---------------------------------------------" - DEPENDS initfscp -) - -# ------------------------------------------------------------------------------ -# Set memory size. -SET(MEMORY_SIZE 1096M) - -# ------------------------------------------------------------------------------ -# Builds the code and runs qemu with the built Os. -SET(EMULATOR qemu-system-i386) -if (${DEBUGGING_TYPE} STREQUAL DEBUG_LOG) - SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -serial file:serial.log) -elseif (${DEBUGGING_TYPE} STREQUAL DEBUG_STDIO) - SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -serial stdio) -endif () -SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -vga std) -SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -k it) -SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -sdl) -SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -m ${MEMORY_SIZE}) -SET(EMULATOR_KERNEL -kernel mentos/kernel.bin) -SET(EMULATOR_FS -initrd initfs) - -add_custom_target( - qemu - COMMAND ${EMULATOR} ${EMULATOR_FLAGS} ${EMULATOR_KERNEL} ${EMULATOR_FS} - DEPENDS MentOs - DEPENDS initfs -) - -# ------------------------------------------------------------------------------ -# Builds the code and runs qemu with the built Os. -SET(EMULATOR_FLAGS_GDB ${EMULATOR_FLAGS} -s -S) -SET(GDB_PROG cgdb) -SET(GDB_ARGS -x ${CMAKE_SOURCE_DIR}/.gdb.debug) - -add_custom_target( - qemu-gdb - COMMAND xterm -geometry 160x30-0-0 -e ${EMULATOR} ${EMULATOR_FLAGS_GDB} ${EMULATOR_KERNEL} ${EMULATOR_FS} & - COMMAND xterm -geometry 160x30-0+0 -e ${GDB_PROG} ${GDB_ARGS} & - DEPENDS MentOs - DEPENDS initfs -) - +cmake_minimum_required(VERSION 2.8.4) + +project(MentOsProject) + +# ------------------------------------------------------------------------------ +# Add the debugging option. +set(DEBUGGING_TYPE "DEBUG_STDIO" CACHE STRING + "Chose the type of debugging: DEBUG_STDIO DEBUG_LOG") +set_property( + CACHE DEBUGGING_TYPE PROPERTY STRINGS + DEBUG_STDIO + DEBUG_LOG) +if ("${DEBUGGING_TYPE}" STREQUAL "DEBUG_STDIO" OR + "${DEBUGGING_TYPE}" STREQUAL "DEBUG_LOG") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D${DEBUGGING_TYPE}") + message(STATUS "Setting debugging type to ${DEBUGGING_TYPE}.") +else () + message(FATAL_ERROR "Debugging type ${DEBUGGING_TYPE} is not valid.") +endif () + +# ------------------------------------------------------------------------------ +# Add the sub-directories. +add_subdirectory(mentos) +add_subdirectory(initscp) + +# ------------------------------------------------------------------------------ +# Generate the initrd filesystem. +add_custom_target( + initfs + COMMAND echo "---------------------------------------------" + COMMAND echo "Initializing 'initfs'..." + COMMAND echo "---------------------------------------------" + COMMAND initfscp -s ${CMAKE_SOURCE_DIR}/files -t ${CMAKE_BINARY_DIR}/initfs -m /dev + COMMAND echo "---------------------------------------------" + COMMAND echo "Done!" + COMMAND echo "---------------------------------------------" + DEPENDS initfscp +) + +# ------------------------------------------------------------------------------ +# Set memory size. +SET(MEMORY_SIZE 1096M) + +# ------------------------------------------------------------------------------ +# Builds the code and runs qemu with the built Os. +SET(EMULATOR qemu-system-i386) +if (${DEBUGGING_TYPE} STREQUAL DEBUG_LOG) + SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -serial file:serial.log) +elseif (${DEBUGGING_TYPE} STREQUAL DEBUG_STDIO) + SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -serial stdio) +endif () +SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -vga std) +SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -k it) +SET(EMULATOR_FLAGS ${EMULATOR_FLAGS} -m ${MEMORY_SIZE}) +SET(EMULATOR_KERNEL -kernel mentos/kernel.bin) +SET(EMULATOR_FS -initrd initfs) + +add_custom_target( + qemu + COMMAND ${EMULATOR} ${EMULATOR_FLAGS} ${EMULATOR_KERNEL} ${EMULATOR_FS} + DEPENDS MentOs + DEPENDS initfs +) + +# ------------------------------------------------------------------------------ +# Builds the code and runs qemu with the built Os. +SET(EMULATOR_FLAGS_GDB ${EMULATOR_FLAGS} -s -S) +SET(GDB_PROG cgdb) +SET(GDB_ARGS -x ${CMAKE_SOURCE_DIR}/.gdb.debug) + +add_custom_target( + qemu-gdb + COMMAND xterm -geometry 160x30-0-0 -e ${EMULATOR} ${EMULATOR_FLAGS_GDB} ${EMULATOR_KERNEL} ${EMULATOR_FS} & + COMMAND xterm -geometry 160x30-0+0 -e ${GDB_PROG} ${GDB_ARGS} & + DEPENDS MentOs + DEPENDS initfs +) + diff --git a/files/README b/files/README index d2c7f2c..2180858 100644 --- a/files/README +++ b/files/README @@ -1,9 +1,9 @@ -MentOS 0.1 - -Welcome to the MentOS, the Mentoring Operating System. - -If you want some help enter the "help" command into the cli. - -Bye, -The Ment(OS) Team - +MentOS 0.1 + +Welcome to the MentOS, the Mentoring Operating System. + +If you want some help enter the "help" command into the cli. + +Bye, +The Ment(OS) Team + diff --git a/files/home/test6.txt b/files/home/test6.txt index 218546c..a04f221 100644 --- a/files/home/test6.txt +++ b/files/home/test6.txt @@ -1 +1 @@ -io ti vi bi! +io ti vi bi! diff --git a/files/home/user/test7.txt b/files/home/user/test7.txt index a49ecf1..57350ba 100644 --- a/files/home/user/test7.txt +++ b/files/home/user/test7.txt @@ -1 +1 @@ -tanto questa e' solo una prova :\ +tanto questa e' solo una prova :\ diff --git a/files/passwd b/files/passwd index 4af77b6..4ec8b0a 100644 --- a/files/passwd +++ b/files/passwd @@ -1,3 +1,3 @@ -root:password -user:computer -asd:asd +root:password +user:computer +asd:asd diff --git a/files/prog/more.c b/files/prog/more.c index fa67ac4..f5f416c 100644 --- a/files/prog/more.c +++ b/files/prog/more.c @@ -1,28 +1,28 @@ -#include -#include - -void main(int argc, char ** argv) -{ - if (argc == 2) - { - // Try to open the file. - int fd = open(argv[1], O_RDONLY, 42); - if (fd > -1) - { - char c; - // Put on the standard output the characters. - while (read(fd, &c, 1)) putchar(c); - putchar('\n'); - putchar('\n'); - close(fd); - } - else - { - printf("%s: cannot find the file.\n\n", argv[1]); - } - } - else - { - printf("Usage: more file\n\n"); - } +#include +#include + +void main(int argc, char ** argv) +{ + if (argc == 2) + { + // Try to open the file. + int fd = open(argv[1], O_RDONLY, 42); + if (fd > -1) + { + char c; + // Put on the standard output the characters. + while (read(fd, &c, 1)) putchar(c); + putchar('\n'); + putchar('\n'); + close(fd); + } + else + { + printf("%s: cannot find the file.\n\n", argv[1]); + } + } + else + { + printf("Usage: more file\n\n"); + } } \ No newline at end of file diff --git a/files/test1.txt b/files/test1.txt index 79484ca..f2bdf33 100644 --- a/files/test1.txt +++ b/files/test1.txt @@ -1 +1 @@ -ciao mondo +ciao mondo diff --git a/files/test2.txt b/files/test2.txt index 111264b..e1ea826 100644 --- a/files/test2.txt +++ b/files/test2.txt @@ -1 +1 @@ -come va ? +come va ? diff --git a/files/test3.txt b/files/test3.txt index 8984e68..90e0d9a 100644 --- a/files/test3.txt +++ b/files/test3.txt @@ -1 +1 @@ -bho, io credo bene eh eh eh +bho, io credo bene eh eh eh diff --git a/files/test4.txt b/files/test4.txt index a49ecf1..57350ba 100644 --- a/files/test4.txt +++ b/files/test4.txt @@ -1 +1 @@ -tanto questa e' solo una prova :\ +tanto questa e' solo una prova :\ diff --git a/files/test5.txt b/files/test5.txt index 218546c..a04f221 100644 --- a/files/test5.txt +++ b/files/test5.txt @@ -1 +1 @@ -io ti vi bi! +io ti vi bi! diff --git a/mentos/CMakeLists.txt b/mentos/CMakeLists.txt index a3657dd..bf778d4 100644 --- a/mentos/CMakeLists.txt +++ b/mentos/CMakeLists.txt @@ -1,336 +1,361 @@ -# ------------------------------------------------------------------------------ -# Initialize the project. -project(MentOs C ASM) - -# ------------------------------------------------------------------------------ -# Set the project name. -set(PROJECT_NAME MentOs) - -# ------------------------------------------------------------------------------ -# Find doxygen -find_package(Doxygen) - -# Add option to generate documentation. -option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) - -if (BUILD_DOCUMENTATION) - if (NOT DOXYGEN_FOUND) - message(FATAL_ERROR "Doxygen is needed to build the documentation.") - endif (NOT DOXYGEN_FOUND) - - set(doxyfile_in ${CMAKE_SOURCE_DIR}/doc/dreamos.doxyfile) - set(doxyfile ${CMAKE_BINARY_DIR}/doxyfile) - - configure_file(${doxyfile_in} ${doxyfile} @ONLY) - - add_custom_target( - doc - COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen" - VERBATIM - ) - install(DIRECTORY ${CMAKE_BINARY_DIR}/html DESTINATION share/doc) -endif (BUILD_DOCUMENTATION) - -# ------------------------------------------------------------------------------ -# Add the scheduling option. -set(SCHEDULER_TYPE - "SCHEDULER_RR" - CACHE STRING - "Chose the type of scheduler: SCHEDULER_RR SCHEDULER_PRIORITY SCHEDULER_CFS") -set_property( - CACHE SCHEDULER_TYPE PROPERTY STRINGS - SCHEDULER_RR - SCHEDULER_PRIORITY - SCHEDULER_CFS) -if ("${SCHEDULER_TYPE}" STREQUAL "SCHEDULER_RR" OR - "${SCHEDULER_TYPE}" STREQUAL "SCHEDULER_PRIORITY" OR - "${SCHEDULER_TYPE}" STREQUAL "SCHEDULER_CFS") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D${SCHEDULER_TYPE}") - message(STATUS "Setting scheduler type to ${SCHEDULER_TYPE}.") -else () - message(FATAL_ERROR "Scheduler type ${SCHEDULER_TYPE} is not valid.") -endif () - -# ------------------------------------------------------------------------------ -# Add the option to enable buddy system. -option(ENABLE_BUDDY_SYSTEM "Enables the buddy system" OFF) -if (ENABLE_BUDDY_SYSTEM) - message(STATUS "Enabling buddy system.") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_BUDDYSYSTEM") -else (ENABLE_BUDDY_SYSTEM) - message(STATUS "Buddy system disabled.") -endif (ENABLE_BUDDY_SYSTEM) - -# ------------------------------------------------------------------------------ -# Set the compiler options (original). -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdlib") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-builtin") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i686") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") - -# ------------------------------------------------------------------------------ -# Set the compiler options (extra). -set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Wall") -#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Wpedantic") -#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -pedantic-errors") -#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Wextra") -#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Werror") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-align") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wdisabled-optimization") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfloat-equal") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfloat-conversion") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-nonliteral") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-security") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-y2k") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wimport") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winit-self") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winline") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winvalid-pch") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-field-initializers") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-include-dirs") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpacked") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wredundant-decls") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstack-protector") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-aliasing=2") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-default") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-enum") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunreachable-code") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-function") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-label") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-parameter") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-value") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-variable") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvariadic-macros") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wwrite-strings") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-conversion") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wuninitialized") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmessage-length=0") - -# ------------------------------------------------------------------------------ - -if (CMAKE_BUILD_TYPE MATCHES "Release") -elseif (CMAKE_BUILD_TYPE MATCHES "Debug") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG") -endif (CMAKE_BUILD_TYPE MATCHES "Release") - -# ------------------------------------------------------------------------------ -# Set the assembly flags. -enable_language(ASM) -set(CMAKE_ASM_COMPILER ${CMAKE_SOURCE_DIR}/third_party/nasm/bin/nasm) -SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -g") -SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -O0") -SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -f elf") -SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -F dwarf") -set(CMAKE_ASM_COMPILE_OBJECT " -o ") - -# ------------------------------------------------------------------------------ -# Add the includes. -include_directories( - inc - inc/descriptor_tables - inc/devices - inc/drivers - inc/drivers/keyboard - inc/fs - inc/hardware - inc/io - inc/kernel - inc/libc - inc/lng - inc/mem - inc/misc - inc/sys - inc/system - inc/process - inc/elf - inc/ui - inc/ui/shell - inc/ui/command - inc/ui/init -) - -# ------------------------------------------------------------------------------ -# Add the source files. -set(SOURCE_FILES - boot.asm - - src/kernel.c - src/multiboot.c - - src/devices/pci.c - src/devices/fpu.c - - src/drivers/ata.c - src/drivers/fdc.c - src/drivers/mouse.c - src/drivers/keyboard/keyboard.c - src/drivers/keyboard/keymap.c - - src/fs/fcntl.c - src/fs/initrd.c - src/fs/vfs.c - src/fs/read_write.c - src/fs/open.c - src/fs/stat.c - src/fs/readdir.c - - src/sys/module.c - src/sys/unistd.c - src/hardware/timer.c - src/hardware/cpuid.c - src/hardware/pic8259.c - src/io/port_io.c - src/io/mm_io.c - src/io/video.c - - src/kernel/sys.c - - src/libc/assert.c - src/libc/ctype.c - src/libc/stdio.c - src/libc/string.c - src/libc/vsprintf.c - src/libc/queue.c - src/libc/stdlib.c - src/libc/spinlock.c - src/libc/list.c - src/libc/ordered_array.c - src/libc/mutex.c - src/libc/libgen.c - src/libc/strerror.c - src/libc/tree.c - src/libc/bitset.c - src/libc/fcvt.c - src/libc/rbtree.c - src/libc/math.c - src/libc/hashmap.c - - src/libc/unistd/getppid.c - src/libc/unistd/getpid.c - src/libc/unistd/exit.c - src/libc/unistd/vfork.c - src/libc/unistd/read.c - src/libc/unistd/write.c - src/libc/unistd/execve.c - src/libc/unistd/nice.c - src/libc/unistd/open.c - src/libc/unistd/reboot.c - src/libc/unistd/waitpid.c - src/libc/unistd/chdir.c - src/libc/unistd/getcwd.c - src/libc/unistd/close.c - src/libc/unistd/stat.c - src/libc/unistd/mkdir.c - - src/mem/kheap.c - src/mem/paging.c - src/mem/zone_allocator.c - - src/misc/bitops.c - src/misc/clock.c - src/misc/debug.c - src/sys/dirent.c - src/sys/utsname.c - src/elf/elf.c - - src/descriptor_tables/gdt.c - src/descriptor_tables/gdt.asm - src/descriptor_tables/interrupt.c - src/descriptor_tables/exception.c - src/descriptor_tables/interrupt.asm - src/descriptor_tables/exception.asm - src/descriptor_tables/idt.c - src/descriptor_tables/idt.asm - src/descriptor_tables/tss.c - src/descriptor_tables/tss.asm - - src/process/scheduler.c - src/process/scheduler_algorithm.c - src/process/process.c - src/process/user.asm - - src/system/errno.c - src/system/panic.c - src/system/syscall.c - src/system/printk.c - - src/ui/command/cmd_cd.c - src/ui/command/cmd_clear.c - src/ui/command/cmd_cpuid.c - src/ui/command/cmd_credits.c - src/ui/command/cmd_date.c - src/ui/command/cmd_drv_load.c - src/ui/command/cmd_echo.c - src/ui/command/cmd_logo.c - src/ui/command/cmd_ls.c - src/ui/command/cmd_mkdir.c - src/ui/command/cmd_more.c - src/ui/command/cmd_newfile.c - src/ui/command/cmd_poweroff.c - src/ui/command/cmd_ps.c - src/ui/command/cmd_pwd.c - src/ui/command/cmd_rm.c - src/ui/command/cmd_rmdir.c - src/ui/command/cmd_showpid.c - src/ui/command/cmd_sleep.c - #src/ui/command/cmd_tester.c - src/ui/command/cmd_touch.c - src/ui/command/cmd_uname.c - src/ui/command/cmd_whoami.c - src/ui/command/cmd_ipcs.c - src/ui/command/cmd_ipcrm.c - src/ui/command/cmd_nice.c - - src/ui/init/init.c - - src/ui/shell/shell.c - src/ui/shell/shell_login.c - ) - -if (ENABLE_BUDDY_SYSTEM MATCHES "ON") - set(SOURCE_FILES - ${SOURCE_FILES} - src/mem/buddysystem.c) -endif (ENABLE_BUDDY_SYSTEM MATCHES "ON") - -# ------------------------------------------------------------------------------ -# Add the executable. -add_library(${PROJECT_NAME} ${SOURCE_FILES}) - -# ------------------------------------------------------------------------------ -# Build the kernel. -add_custom_command( - TARGET MentOs - POST_BUILD - COMMAND $(LD) - -melf_i386 - -static - --oformat elf32-i386 - -Ttext 0x100000 - --output=${CMAKE_CURRENT_BINARY_DIR}/kernel.bin - --script=${CMAKE_CURRENT_SOURCE_DIR}/kernel.lds - ${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.a - -Map ${CMAKE_CURRENT_BINARY_DIR}/kernel.map -) +# ------------------------------------------------------------------------------ +# Initialize the project. +project(MentOs C ASM) + +# ------------------------------------------------------------------------------ +# Set the project name. +set(PROJECT_NAME MentOs) + +# ------------------------------------------------------------------------------ +# Find doxygen +find_package(Doxygen) + +# Add option to generate documentation. +option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) + +if (BUILD_DOCUMENTATION) + if (NOT DOXYGEN_FOUND) + message(FATAL_ERROR "Doxygen is needed to build the documentation.") + endif (NOT DOXYGEN_FOUND) + + set(doxyfile_in ${CMAKE_SOURCE_DIR}/doc/dreamos.doxyfile) + set(doxyfile ${CMAKE_BINARY_DIR}/doxyfile) + + configure_file(${doxyfile_in} ${doxyfile} @ONLY) + + add_custom_target( + doc + COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM + ) + install(DIRECTORY ${CMAKE_BINARY_DIR}/html DESTINATION share/doc) +endif (BUILD_DOCUMENTATION) + +# ------------------------------------------------------------------------------ +# Add the scheduling option. +set(SCHEDULER_TYPE + "SCHEDULER_RR" + CACHE STRING + "Chose the type of scheduler: SCHEDULER_RR SCHEDULER_PRIORITY SCHEDULER_CFS") +set_property( + CACHE SCHEDULER_TYPE PROPERTY STRINGS + SCHEDULER_RR + SCHEDULER_PRIORITY + SCHEDULER_CFS) +if ("${SCHEDULER_TYPE}" STREQUAL "SCHEDULER_RR" OR + "${SCHEDULER_TYPE}" STREQUAL "SCHEDULER_PRIORITY" OR + "${SCHEDULER_TYPE}" STREQUAL "SCHEDULER_CFS") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D${SCHEDULER_TYPE}") + message(STATUS "Setting scheduler type to ${SCHEDULER_TYPE}.") +else () + message(FATAL_ERROR "Scheduler type ${SCHEDULER_TYPE} is not valid.") +endif () + +# ------------------------------------------------------------------------------ +# Add the option to enable buddy system. +option(ENABLE_BUDDY_SYSTEM "Enables the buddy system" OFF) +if (ENABLE_BUDDY_SYSTEM) + message(STATUS "Enabling buddy system.") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_BUDDYSYSTEM") +else (ENABLE_BUDDY_SYSTEM) + message(STATUS "Buddy system disabled.") +endif (ENABLE_BUDDY_SYSTEM) + +# ------------------------------------------------------------------------------ +# Add the option to enable deadlock prevention. +option(ENABLE_DEADLOCK_PREVENTION "Enables the buddy system" OFF) +if (ENABLE_DEADLOCK_PREVENTION) + message(STATUS "Enabling deadlock prevention.") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_DEADLOCK_PREVENTION") +else (ENABLE_DEADLOCK_PREVENTION) + message(STATUS "Deadlock prevention disabled.") +endif (ENABLE_DEADLOCK_PREVENTION) + +# ------------------------------------------------------------------------------ +# Set the compiler options (original). +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdlib") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-builtin") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i686") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") + +# ------------------------------------------------------------------------------ +# Set the compiler options (extra). +set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Wall") +#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Wpedantic") +#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -pedantic-errors") +#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Wextra") +#set(CMAKE_C_FLAGS"${CMAKE_C_FLAGS} -Werror") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-align") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wdisabled-optimization") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfloat-equal") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfloat-conversion") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-nonliteral") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-security") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-y2k") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wimport") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winit-self") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winline") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winvalid-pch") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-field-initializers") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-include-dirs") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpacked") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wredundant-decls") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstack-protector") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-aliasing=2") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-default") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-enum") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunreachable-code") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-function") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-label") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-parameter") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-value") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused-variable") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvariadic-macros") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wwrite-strings") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-conversion") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wuninitialized") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmessage-length=0") + +# ------------------------------------------------------------------------------ + +if (CMAKE_BUILD_TYPE MATCHES "Release") +elseif (CMAKE_BUILD_TYPE MATCHES "Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG") +endif (CMAKE_BUILD_TYPE MATCHES "Release") + +# ------------------------------------------------------------------------------ +# Set the assembly flags. +enable_language(ASM) +set(CMAKE_ASM_COMPILER ${CMAKE_SOURCE_DIR}/third_party/nasm/bin/nasm) +SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -g") +SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -O0") +SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -f elf") +SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -F dwarf") +set(CMAKE_ASM_COMPILE_OBJECT " -o ") + +# ------------------------------------------------------------------------------ +# Add the includes. +include_directories( + inc + inc/descriptor_tables + inc/devices + inc/drivers + inc/drivers/keyboard + inc/fs + inc/hardware + inc/io + inc/kernel + inc/libc + inc/lng + inc/mem + inc/misc + inc/sys + inc/experimental + inc/experimental/math + inc/system + inc/process + inc/elf + inc/ui + inc/ui/shell + inc/ui/command + inc/ui/init +) + +# ------------------------------------------------------------------------------ +# Add the source files. +set(SOURCE_FILES + boot.asm + + src/kernel.c + src/multiboot.c + + src/devices/pci.c + src/devices/fpu.c + + src/drivers/ata.c + src/drivers/fdc.c + src/drivers/mouse.c + src/drivers/keyboard/keyboard.c + src/drivers/keyboard/keymap.c + + src/experimental/smart_sem_kernel.c + src/experimental/smart_sem_user.c + src/experimental/resource.c + src/experimental/math/arr_math.c + + src/fs/fcntl.c + src/fs/initrd.c + src/fs/vfs.c + src/fs/read_write.c + src/fs/open.c + src/fs/stat.c + src/fs/readdir.c + + src/sys/module.c + src/sys/unistd.c + src/hardware/timer.c + src/hardware/cpuid.c + src/hardware/pic8259.c + src/io/port_io.c + src/io/mm_io.c + src/io/video.c + + src/kernel/sys.c + + src/libc/assert.c + src/libc/ctype.c + src/libc/stdio.c + src/libc/string.c + src/libc/vsprintf.c + src/libc/queue.c + src/libc/stdlib.c + src/libc/spinlock.c + src/libc/list.c + src/libc/ordered_array.c + src/libc/mutex.c + src/libc/libgen.c + src/libc/strerror.c + src/libc/tree.c + src/libc/bitset.c + src/libc/fcvt.c + src/libc/rbtree.c + src/libc/math.c + src/libc/hashmap.c + + src/libc/unistd/getppid.c + src/libc/unistd/getpid.c + src/libc/unistd/exit.c + src/libc/unistd/vfork.c + src/libc/unistd/read.c + src/libc/unistd/write.c + src/libc/unistd/execve.c + src/libc/unistd/nice.c + src/libc/unistd/open.c + src/libc/unistd/reboot.c + src/libc/unistd/waitpid.c + src/libc/unistd/chdir.c + src/libc/unistd/getcwd.c + src/libc/unistd/close.c + src/libc/unistd/stat.c + src/libc/unistd/mkdir.c + + src/mem/kheap.c + src/mem/paging.c + src/mem/zone_allocator.c + + src/misc/bitops.c + src/misc/clock.c + src/misc/debug.c + src/sys/dirent.c + src/sys/utsname.c + src/elf/elf.c + + src/descriptor_tables/gdt.c + src/descriptor_tables/gdt.asm + src/descriptor_tables/interrupt.c + src/descriptor_tables/exception.c + src/descriptor_tables/interrupt.asm + src/descriptor_tables/exception.asm + src/descriptor_tables/idt.c + src/descriptor_tables/idt.asm + src/descriptor_tables/tss.c + src/descriptor_tables/tss.asm + + src/process/scheduler.c + src/process/scheduler_algorithm.c + src/process/process.c + src/process/user.asm + + src/system/errno.c + src/system/panic.c + src/system/syscall.c + src/system/printk.c + + src/ui/command/cmd_cd.c + src/ui/command/cmd_clear.c + src/ui/command/cmd_cpuid.c + src/ui/command/cmd_credits.c + src/ui/command/cmd_date.c + src/ui/command/cmd_drv_load.c + src/ui/command/cmd_echo.c + src/ui/command/cmd_logo.c + src/ui/command/cmd_ls.c + src/ui/command/cmd_mkdir.c + src/ui/command/cmd_more.c + src/ui/command/cmd_newfile.c + src/ui/command/cmd_poweroff.c + src/ui/command/cmd_ps.c + src/ui/command/cmd_pwd.c + src/ui/command/cmd_rm.c + src/ui/command/cmd_rmdir.c + src/ui/command/cmd_showpid.c + src/ui/command/cmd_sleep.c + #src/ui/command/cmd_tester.c + src/ui/command/cmd_touch.c + src/ui/command/cmd_uname.c + src/ui/command/cmd_whoami.c + src/ui/command/cmd_ipcs.c + src/ui/command/cmd_ipcrm.c + src/ui/command/cmd_nice.c + src/ui/command/cmd_deadlock.c + + src/ui/init/init.c + + src/ui/shell/shell.c + src/ui/shell/shell_login.c + ) + +if (ENABLE_BUDDY_SYSTEM MATCHES "ON") + set(SOURCE_FILES + ${SOURCE_FILES} + src/mem/buddysystem.c) +endif (ENABLE_BUDDY_SYSTEM MATCHES "ON") + +if (ENABLE_DEADLOCK_PREVENTION MATCHES "ON") + set(SOURCE_FILES + ${SOURCE_FILES} + src/experimental/deadlock_prevention.c + src/experimental/deadlock_simulation.c) +endif (ENABLE_DEADLOCK_PREVENTION MATCHES "ON") + +# ------------------------------------------------------------------------------ +# Add the executable. +add_library(${PROJECT_NAME} ${SOURCE_FILES}) + +# ------------------------------------------------------------------------------ +# Build the kernel. +add_custom_command( + TARGET MentOs + POST_BUILD + COMMAND $(LD) + -melf_i386 + -static + --oformat elf32-i386 + -Ttext 0x100000 + --output=${CMAKE_CURRENT_BINARY_DIR}/kernel.bin + --script=${CMAKE_CURRENT_SOURCE_DIR}/kernel.lds + ${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.a + -Map ${CMAKE_CURRENT_BINARY_DIR}/kernel.map +) diff --git a/mentos/boot.asm b/mentos/boot.asm index 0c26b1f..f9af4b6 100644 --- a/mentos/boot.asm +++ b/mentos/boot.asm @@ -1,97 +1,97 @@ -; MentOS, The Mentoring Operating system project -; @file boot.asm -; @brief Kernel start location, multiboot header -; @copyright (c) 2019 This file is distributed under the MIT License. -; See LICENSE.md for details. - -[BITS 32] ; All instructions should be 32-bit. -[EXTERN kmain] ; The start point of our C code - -; The magic field should contain this. -MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 -; This should be in %eax. -MULTIBOOT_BOOTLOADER_MAGIC equ 0x2BADB002 - -; = Specify what GRUB should PROVIDE ========================================= -; Align the kernel and kernel modules on i386 page (4KB) boundaries. -MULTIBOOT_PAGE_ALIGN equ 0x00000001 -; Provide the kernel with memory information. -MULTIBOOT_MEMORY_INFO equ 0x00000002 -; Must pass video information to OS. -MULTIBOOT_VIDEO_MODE equ 0x00000004 -; ----------------------------------------------------------------------------- - -; This is the flag combination that we prepare for Grub -; to read at kernel load time. -MULTIBOOT_HEADER_FLAGS equ (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE) -; Grub reads this value to make sure it loads a kernel -; and not just garbage. -MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) - -LOAD_MEMORY_ADDRESS equ 0x00000000 -; reserve (1024*1024) for the stack on a doubleword boundary -KERNEL_STACK_SIZE equ 0x100000 - -; ----------------------------------------------------------------------------- -; SECTION (multiboot_header) -; ----------------------------------------------------------------------------- -section .multiboot_header -align 4 -; This is the GRUB Multiboot header. -multiboot_header: - ; magic - dd MULTIBOOT_HEADER_MAGIC - ; flags - dd MULTIBOOT_HEADER_FLAGS - ; checksum - dd MULTIBOOT_CHECKSUM - -; ----------------------------------------------------------------------------- -; SECTION (data) -; ----------------------------------------------------------------------------- -section .data, nobits -align 4096 -[GLOBAL boot_page_dir] -boot_page_dir: - resb 0x1000 -boot_page_tabl: - resb 0x1000 - -; ----------------------------------------------------------------------------- -; SECTION (text) -; ----------------------------------------------------------------------------- -section .text -[GLOBAL kernel_entry] -kernel_entry: - ; Clear interrupt flag [IF = 0]; 0xFA - cli - ; To set up a stack, we simply set the esp register to point to the top of - ; our stack (as it grows downwards). - mov esp, stack_top - ; pass the initial ESP - push esp - ; pass Multiboot info structure - push ebx - ; pass Multiboot magic number - push eax - ; Call the kmain() function inside kernel.c - call kmain - ; Set interrupt flag [IF = 1]; 0xFA - ; Clear interrupts and hang if we return from kmain - cli -hang: - hlt - jmp hang - - -; ----------------------------------------------------------------------------- -; SECTION (bss) -; ----------------------------------------------------------------------------- -section .bss -[GLOBAL stack_bottom] -[GLOBAL stack_top] -align 16 -stack_bottom: - resb KERNEL_STACK_SIZE -stack_top: - ; the top of the stack is the bottom because the stack counts down +; MentOS, The Mentoring Operating system project +; @file boot.asm +; @brief Kernel start location, multiboot header +; @copyright (c) 2019 This file is distributed under the MIT License. +; See LICENSE.md for details. + +[BITS 32] ; All instructions should be 32-bit. +[EXTERN kmain] ; The start point of our C code + +; The magic field should contain this. +MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 +; This should be in %eax. +MULTIBOOT_BOOTLOADER_MAGIC equ 0x2BADB002 + +; = Specify what GRUB should PROVIDE ========================================= +; Align the kernel and kernel modules on i386 page (4KB) boundaries. +MULTIBOOT_PAGE_ALIGN equ 0x00000001 +; Provide the kernel with memory information. +MULTIBOOT_MEMORY_INFO equ 0x00000002 +; Must pass video information to OS. +MULTIBOOT_VIDEO_MODE equ 0x00000004 +; ----------------------------------------------------------------------------- + +; This is the flag combination that we prepare for Grub +; to read at kernel load time. +MULTIBOOT_HEADER_FLAGS equ (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE) +; Grub reads this value to make sure it loads a kernel +; and not just garbage. +MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) + +LOAD_MEMORY_ADDRESS equ 0x00000000 +; reserve (1024*1024) for the stack on a doubleword boundary +KERNEL_STACK_SIZE equ 0x100000 + +; ----------------------------------------------------------------------------- +; SECTION (multiboot_header) +; ----------------------------------------------------------------------------- +section .multiboot_header +align 4 +; This is the GRUB Multiboot header. +multiboot_header: + ; magic + dd MULTIBOOT_HEADER_MAGIC + ; flags + dd MULTIBOOT_HEADER_FLAGS + ; checksum + dd MULTIBOOT_CHECKSUM + +; ----------------------------------------------------------------------------- +; SECTION (data) +; ----------------------------------------------------------------------------- +section .data, nobits +align 4096 +[GLOBAL boot_page_dir] +boot_page_dir: + resb 0x1000 +boot_page_tabl: + resb 0x1000 + +; ----------------------------------------------------------------------------- +; SECTION (text) +; ----------------------------------------------------------------------------- +section .text +[GLOBAL kernel_entry] +kernel_entry: + ; Clear interrupt flag [IF = 0]; 0xFA + cli + ; To set up a stack, we simply set the esp register to point to the top of + ; our stack (as it grows downwards). + mov esp, stack_top + ; pass the initial ESP + push esp + ; pass Multiboot info structure + push ebx + ; pass Multiboot magic number + push eax + ; Call the kmain() function inside kernel.c + call kmain + ; Set interrupt flag [IF = 1]; 0xFA + ; Clear interrupts and hang if we return from kmain + cli +hang: + hlt + jmp hang + + +; ----------------------------------------------------------------------------- +; SECTION (bss) +; ----------------------------------------------------------------------------- +section .bss +[GLOBAL stack_bottom] +[GLOBAL stack_top] +align 16 +stack_bottom: + resb KERNEL_STACK_SIZE +stack_top: + ; the top of the stack is the bottom because the stack counts down diff --git a/mentos/inc/descriptor_tables/gdt.h b/mentos/inc/descriptor_tables/gdt.h index a7728e4..fe2c546 100644 --- a/mentos/inc/descriptor_tables/gdt.h +++ b/mentos/inc/descriptor_tables/gdt.h @@ -1,79 +1,79 @@ -/// MentOS, The Mentoring Operating system project -/// @file gdt.h -/// @brief Data structures concerning the Global Descriptor Table (GDT). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @brief Access flags, determines what ring this segment can be used in. -typedef enum gdt_access_option_t -{ - /// Identifies a kernel segment. - KERNEL = 0x00, - /// Identifies a user segment. - USER = 0x03, - /// Identifies a code segment. - CODE = 0x10, - /// Identifies a data segment. - DATA = 0x10, - /// Segment is present. - PRESENT = 0x80, -} __attribute__ ((__packed__)) gdt_access_option_t; - -/// @brief Options for the second option. -typedef enum gdt_granularity_option_t -{ - /// Granularity. - GRANULARITY = 0x80, - /// Szbits. - SZBITS = 0x40 -} __attribute__ ((__packed__)) gdt_granularity_option_t; - -/// @brief Data structure representing a GDT descriptor. -typedef struct gdt_descriptor_t -{ - /// The lower 16 bits of the limit. - uint16_t limit_low; - /// The lower 16 bits of the base. - uint16_t base_low; - /// The next 8 bits of the base. - uint8_t base_middle; - /// Access flags, determine what ring this segment can be used in. - uint8_t access; - /// SegLimit_hi(4 bit) AVL(1 bit) L(1 bit) D/B(1 bit) G(1bit). - uint8_t granularity; - /// The last 8 bits of the base. - uint8_t base_high; -} __attribute__((packed)) gdt_descriptor_t; - -/// @brief Data structure used to load the GDT into the GDTR. -typedef struct gdt_pointer_t -{ - /// The size of the GDT (entry number). - uint16_t limit; - /// The starting address of the GDT. - uint32_t base; -} __attribute__((packed)) gdt_pointer_t; - -/// @brief Initialise the GDT. -/// @details This will setup the special GDT -/// pointer, set up the first 3 entries in our GDT, and then -/// finally call gdt_flush() in our assembler file in order -/// to tell the processor where the new GDT is and update the -/// new segment registers. -void init_gdt(); - -/// @brief Sets the value of one GDT entry. -/// @param index The index inside the GDT. -/// @param base Memory address where the segment we are defining starts. -/// @param limit The memory address which determines the end of the segnment. -/// @param _access Type (4bit) - S (1) bit -DPL (2 bit) - P(1 bit). -/// @param _granul SegLimit_hi(4 bit) AVL(1 bit) L(1 bit) D/B(1 bit) G(1bit). -void gdt_set_gate(uint8_t index, - uint32_t base, - uint32_t limit, - uint8_t _access, - uint8_t _granul); +/// MentOS, The Mentoring Operating system project +/// @file gdt.h +/// @brief Data structures concerning the Global Descriptor Table (GDT). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @brief Access flags, determines what ring this segment can be used in. +typedef enum gdt_access_option_t +{ + /// Identifies a kernel segment. + KERNEL = 0x00, + /// Identifies a user segment. + USER = 0x03, + /// Identifies a code segment. + CODE = 0x10, + /// Identifies a data segment. + DATA = 0x10, + /// Segment is present. + PRESENT = 0x80, +} __attribute__ ((__packed__)) gdt_access_option_t; + +/// @brief Options for the second option. +typedef enum gdt_granularity_option_t +{ + /// Granularity. + GRANULARITY = 0x80, + /// Szbits. + SZBITS = 0x40 +} __attribute__ ((__packed__)) gdt_granularity_option_t; + +/// @brief Data structure representing a GDT descriptor. +typedef struct gdt_descriptor_t +{ + /// The lower 16 bits of the limit. + uint16_t limit_low; + /// The lower 16 bits of the base. + uint16_t base_low; + /// The next 8 bits of the base. + uint8_t base_middle; + /// Access flags, determine what ring this segment can be used in. + uint8_t access; + /// SegLimit_hi(4 bit) AVL(1 bit) L(1 bit) D/B(1 bit) G(1bit). + uint8_t granularity; + /// The last 8 bits of the base. + uint8_t base_high; +} __attribute__((packed)) gdt_descriptor_t; + +/// @brief Data structure used to load the GDT into the GDTR. +typedef struct gdt_pointer_t +{ + /// The size of the GDT (entry number). + uint16_t limit; + /// The starting address of the GDT. + uint32_t base; +} __attribute__((packed)) gdt_pointer_t; + +/// @brief Initialise the GDT. +/// @details This will setup the special GDT +/// pointer, set up the first 3 entries in our GDT, and then +/// finally call gdt_flush() in our assembler file in order +/// to tell the processor where the new GDT is and update the +/// new segment registers. +void init_gdt(); + +/// @brief Sets the value of one GDT entry. +/// @param index The index inside the GDT. +/// @param base Memory address where the segment we are defining starts. +/// @param limit The memory address which determines the end of the segnment. +/// @param _access Type (4bit) - S (1) bit -DPL (2 bit) - P(1 bit). +/// @param _granul SegLimit_hi(4 bit) AVL(1 bit) L(1 bit) D/B(1 bit) G(1bit). +void gdt_set_gate(uint8_t index, + uint32_t base, + uint32_t limit, + uint8_t _access, + uint8_t _granul); diff --git a/mentos/inc/descriptor_tables/idt.h b/mentos/inc/descriptor_tables/idt.h index ddb388b..abed780 100644 --- a/mentos/inc/descriptor_tables/idt.h +++ b/mentos/inc/descriptor_tables/idt.h @@ -1,169 +1,169 @@ -/// MentOS, The Mentoring Operating system project -/// @file idt.h -/// @brief Data structures concerning the Interrupt Descriptor Table (IDT). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "isr.h" -#include "stdint.h" -#include - -/// The maximum dimension of the IDT. -#define IDT_SIZE 256 - -/// When an exception occurs whose entry is a Task Gate, a task switch results. -#define TASK_GATE 0x5 - -/// Used to specify an interrupt service routine (16-bit). -#define INT16_GATE 0x6 - -/// @brief Similar to an Interrupt gate (16-bit). -#define TRAP16_GATE 0x7 - -/// Used to specify an interrupt service routine (32-bit). -#define INT32_GATE 0xE - -/// @brief Similar to an Interrupt gate (32-bit). -#define TRAP32_GATE 0xF - -/* - * Trap and Interrupt gates are similar, and their descriptors are - * structurally the same, they differ only in the "type" field. The - * difference is that for interrupt gates, interrupts are automatically - * disabled upon entry and reenabled upon IRET which restores the saved EFLAGS. - */ - -/// @brief This structure describes one interrupt gate. -typedef struct idt_descriptor_t { - unsigned short offset_low; - unsigned short seg_selector; - // This will ALWAYS be set to 0. - unsigned char null_par; - // |P|DPL|01110|. - // P present, DPL required Ring (2bits). - unsigned char options; - unsigned short offset_high; -} __attribute__((packed)) idt_descriptor_t; - -/// @brief A pointer structure used for informing the CPU about our IDT. -typedef struct idt_pointer_t { - /// The size of the IDT (entry number). - unsigned short int limit; - /// The start address of the IDT. - unsigned int base; -} __attribute__((packed)) idt_pointer_t; - -/// @brief Initialise the interrupt descriptor table. -void init_idt(); - -/// @brief Use this function to set an entry in the IDT. -/// @param index Indice della IDT. -/// @param handler Puntatore alla funzione che gestira' l'interrupt/Eccezione -/// @param options Le opzioni del descrittore (PRESENT,NOTPRESENT,KERNEL,USER) -/// @param seg_sel Il selettore del segmento della GDT. -void idt_set_gate(uint8_t index, interrupt_handler_t handler, uint16_t options, - uint8_t seg_sel); - -//==== List of exceptions generated internally by the CPU ====================== -extern void INT_0(); - -extern void INT_1(); - -extern void INT_2(); - -extern void INT_3(); - -extern void INT_4(); - -extern void INT_5(); - -extern void INT_6(); - -extern void INT_7(); - -extern void INT_8(); - -extern void INT_9(); - -extern void INT_10(); - -extern void INT_11(); - -extern void INT_12(); - -extern void INT_13(); - -extern void INT_14(); - -extern void INT_15(); - -extern void INT_16(); - -extern void INT_17(); - -extern void INT_18(); - -extern void INT_19(); - -extern void INT_20(); - -extern void INT_21(); - -extern void INT_22(); - -extern void INT_23(); - -extern void INT_24(); - -extern void INT_25(); - -extern void INT_26(); - -extern void INT_27(); - -extern void INT_28(); - -extern void INT_29(); - -extern void INT_30(); - -extern void INT_31(); - -extern void INT_80(); -//============================================================================== - -//==== List of interrupts generated by PIC ===================================== -extern void IRQ_0(); - -extern void IRQ_1(); - -extern void IRQ_2(); - -extern void IRQ_3(); - -extern void IRQ_4(); - -extern void IRQ_5(); - -extern void IRQ_6(); - -extern void IRQ_7(); - -extern void IRQ_8(); - -extern void IRQ_9(); - -extern void IRQ_10(); - -extern void IRQ_11(); - -extern void IRQ_12(); - -extern void IRQ_13(); - -extern void IRQ_14(); - -extern void IRQ_15(); -//============================================================================== +/// MentOS, The Mentoring Operating system project +/// @file idt.h +/// @brief Data structures concerning the Interrupt Descriptor Table (IDT). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "isr.h" +#include "stdint.h" +#include + +/// The maximum dimension of the IDT. +#define IDT_SIZE 256 + +/// When an exception occurs whose entry is a Task Gate, a task switch results. +#define TASK_GATE 0x5 + +/// Used to specify an interrupt service routine (16-bit). +#define INT16_GATE 0x6 + +/// @brief Similar to an Interrupt gate (16-bit). +#define TRAP16_GATE 0x7 + +/// Used to specify an interrupt service routine (32-bit). +#define INT32_GATE 0xE + +/// @brief Similar to an Interrupt gate (32-bit). +#define TRAP32_GATE 0xF + +/* + * Trap and Interrupt gates are similar, and their descriptors are + * structurally the same, they differ only in the "type" field. The + * difference is that for interrupt gates, interrupts are automatically + * disabled upon entry and reenabled upon IRET which restores the saved EFLAGS. + */ + +/// @brief This structure describes one interrupt gate. +typedef struct idt_descriptor_t { + unsigned short offset_low; + unsigned short seg_selector; + // This will ALWAYS be set to 0. + unsigned char null_par; + // |P|DPL|01110|. + // P present, DPL required Ring (2bits). + unsigned char options; + unsigned short offset_high; +} __attribute__((packed)) idt_descriptor_t; + +/// @brief A pointer structure used for informing the CPU about our IDT. +typedef struct idt_pointer_t { + /// The size of the IDT (entry number). + unsigned short int limit; + /// The start address of the IDT. + unsigned int base; +} __attribute__((packed)) idt_pointer_t; + +/// @brief Initialise the interrupt descriptor table. +void init_idt(); + +/// @brief Use this function to set an entry in the IDT. +/// @param index Indice della IDT. +/// @param handler Puntatore alla funzione che gestira' l'interrupt/Eccezione +/// @param options Le opzioni del descrittore (PRESENT,NOTPRESENT,KERNEL,USER) +/// @param seg_sel Il selettore del segmento della GDT. +void idt_set_gate(uint8_t index, interrupt_handler_t handler, uint16_t options, + uint8_t seg_sel); + +//==== List of exceptions generated internally by the CPU ====================== +extern void INT_0(); + +extern void INT_1(); + +extern void INT_2(); + +extern void INT_3(); + +extern void INT_4(); + +extern void INT_5(); + +extern void INT_6(); + +extern void INT_7(); + +extern void INT_8(); + +extern void INT_9(); + +extern void INT_10(); + +extern void INT_11(); + +extern void INT_12(); + +extern void INT_13(); + +extern void INT_14(); + +extern void INT_15(); + +extern void INT_16(); + +extern void INT_17(); + +extern void INT_18(); + +extern void INT_19(); + +extern void INT_20(); + +extern void INT_21(); + +extern void INT_22(); + +extern void INT_23(); + +extern void INT_24(); + +extern void INT_25(); + +extern void INT_26(); + +extern void INT_27(); + +extern void INT_28(); + +extern void INT_29(); + +extern void INT_30(); + +extern void INT_31(); + +extern void INT_80(); +//============================================================================== + +//==== List of interrupts generated by PIC ===================================== +extern void IRQ_0(); + +extern void IRQ_1(); + +extern void IRQ_2(); + +extern void IRQ_3(); + +extern void IRQ_4(); + +extern void IRQ_5(); + +extern void IRQ_6(); + +extern void IRQ_7(); + +extern void IRQ_8(); + +extern void IRQ_9(); + +extern void IRQ_10(); + +extern void IRQ_11(); + +extern void IRQ_12(); + +extern void IRQ_13(); + +extern void IRQ_14(); + +extern void IRQ_15(); +//============================================================================== diff --git a/mentos/inc/descriptor_tables/isr.h b/mentos/inc/descriptor_tables/isr.h index c8c5217..7a71809 100644 --- a/mentos/inc/descriptor_tables/isr.h +++ b/mentos/inc/descriptor_tables/isr.h @@ -1,129 +1,129 @@ -/// MentOS, The Mentoring Operating system project -/// @file isr.h -/// @brief Data structures concerning the Interrupt Service Routines (ISRs). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "kernel.h" - -// TODO: see interrupt_handler_t in Linux, it is quite different. -/// @brief Interrupt handler definition. -/// @details An interrupt handler is an interrupt service routine called -/// to manage interrupt requests, or CPU execptions. -/// @param f An interrupt stack frame. -typedef void (*interrupt_handler_t)(pt_regs *f); - -/// @brief For each exceptions isrs_init sets a default handler which -/// prints the rose exceptions and stops kernel execution. -void isrs_init(); - -/// @brief For each interrupt irqs_init sets a default handler which -/// prints the rose IRQ line and stops kernel execution. -void irqs_init(); - -/* Even if an interrupt service routine is called for exceptions and - * interrupts, we use two distinct methods to logically setup an ISR to - * handle theme. Tecnically speacking, exceptions are synchronous interrupts - * generated by CPU. For an exception we have an ISR. Interrupts are - * asynchronous events generated by PIC. Furthermore, multiple ISRs can be set - * for a same IRQ. - */ - -/// @brief Installs an ISR to handle an exception. -/// @param i Exception identifier. -/// @param handler Exception handler. -/// @return 0 On success, -1 otherwise. -int isr_install_handler(uint32_t i, interrupt_handler_t handler, - char *description); - -/// @brief Installs an ISR to handle an interrupt. -/// @param i Interrupt identifier. -/// @param handler Interrupt handler. -/// @return 0 On success, -1 otherwise. -int irq_install_handler(uint32_t i, interrupt_handler_t handler, - char *description); - -/// @brief Method called by CPU to handle interrupts. -/// @param f The interrupt stack frame. -extern void irq_handler(pt_regs *f); - -/// @brief Method called by CPU to handle exceptions. -/// @param f The interrupt stack frame. -extern void isq_handler(pt_regs *f); - -//==== List of exceptions generated internally by the CPU ====================== -/// @brief DE Divide Error. -#define DIVIDE_ERROR 0 - -/// @brief DB Debug. -#define DEBUG_EXC 1 - -/// @brief Non Mascable Interrupt. -#define NMI_INTERRUPT 2 - -/// @brief BP Breakpoint. -#define BREAKPOINT 3 - -/// @brief OF Overflow. -#define OVERFLOW 4 - -/// @brief BR Bound Range Exception. -#define BOUND_RANGE_EXCEED 5 - -/// @brief UD Invalid OpCode Exception. -#define INVALID_OPCODE 6 - -/// @brief NM Device Not Available. -#define DEV_NOT_AVL 7 - -/// @brief DF Double Fault. -#define DOUBLE_FAULT 8 - -/// @brief Coprocessor Segment Overrun. -#define COPROC_SEG_OVERRUN 9 - -/// @brief TS Invalid TSS. -#define INVALID_TSS 10 - -/// @brief NP Segment Not Present. -#define SEGMENT_NOT_PRESENT 11 - -/// @brief SS Stack Segment Fault. -#define STACK_SEGMENT_FAULT 12 - -/// @brief GP General Protection. -#define GENERAL_PROTECTION 13 - -/// @brief PF Page Fault. -#define PAGE_FAULT 14 - -/// @brief XX Reserverd. -#define INT_RSV 15 - -/// @brief MF Floating Point. -#define FLOATING_POINT_ERR 16 - -/// @brief AC Alignment Check. -#define ALIGNMENT_CHECK 17 - -/// @brief MC Machine Check. -#define MACHINE_CHECK 18 - -/// @brief XF Streaming SIMD Exception. -#define SIMD_FP_EXC 19 - -/// @brief Virtualization Exception. -#define VIRT_EXC 20 - -/// @brief Reserved [21-29]. -/// @brief Security Exception. -#define SECURITY_EXC 30 - -/// @brief Triple Fault -#define TRIPLE_FAULT 31 - -/// @brief System call interrupt. -#define SYSTEM_CALL 80 -//============================================================================== +/// MentOS, The Mentoring Operating system project +/// @file isr.h +/// @brief Data structures concerning the Interrupt Service Routines (ISRs). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "kernel.h" + +// TODO: see interrupt_handler_t in Linux, it is quite different. +/// @brief Interrupt handler definition. +/// @details An interrupt handler is an interrupt service routine called +/// to manage interrupt requests, or CPU execptions. +/// @param f An interrupt stack frame. +typedef void (*interrupt_handler_t)(pt_regs *f); + +/// @brief For each exceptions isrs_init sets a default handler which +/// prints the rose exceptions and stops kernel execution. +void isrs_init(); + +/// @brief For each interrupt irqs_init sets a default handler which +/// prints the rose IRQ line and stops kernel execution. +void irqs_init(); + +/* Even if an interrupt service routine is called for exceptions and + * interrupts, we use two distinct methods to logically setup an ISR to + * handle theme. Tecnically speacking, exceptions are synchronous interrupts + * generated by CPU. For an exception we have an ISR. Interrupts are + * asynchronous events generated by PIC. Furthermore, multiple ISRs can be set + * for a same IRQ. + */ + +/// @brief Installs an ISR to handle an exception. +/// @param i Exception identifier. +/// @param handler Exception handler. +/// @return 0 On success, -1 otherwise. +int isr_install_handler(uint32_t i, interrupt_handler_t handler, + char *description); + +/// @brief Installs an ISR to handle an interrupt. +/// @param i Interrupt identifier. +/// @param handler Interrupt handler. +/// @return 0 On success, -1 otherwise. +int irq_install_handler(uint32_t i, interrupt_handler_t handler, + char *description); + +/// @brief Method called by CPU to handle interrupts. +/// @param f The interrupt stack frame. +extern void irq_handler(pt_regs *f); + +/// @brief Method called by CPU to handle exceptions. +/// @param f The interrupt stack frame. +extern void isq_handler(pt_regs *f); + +//==== List of exceptions generated internally by the CPU ====================== +/// @brief DE Divide Error. +#define DIVIDE_ERROR 0 + +/// @brief DB Debug. +#define DEBUG_EXC 1 + +/// @brief Non Mascable Interrupt. +#define NMI_INTERRUPT 2 + +/// @brief BP Breakpoint. +#define BREAKPOINT 3 + +/// @brief OF Overflow. +#define OVERFLOW 4 + +/// @brief BR Bound Range Exception. +#define BOUND_RANGE_EXCEED 5 + +/// @brief UD Invalid OpCode Exception. +#define INVALID_OPCODE 6 + +/// @brief NM Device Not Available. +#define DEV_NOT_AVL 7 + +/// @brief DF Double Fault. +#define DOUBLE_FAULT 8 + +/// @brief Coprocessor Segment Overrun. +#define COPROC_SEG_OVERRUN 9 + +/// @brief TS Invalid TSS. +#define INVALID_TSS 10 + +/// @brief NP Segment Not Present. +#define SEGMENT_NOT_PRESENT 11 + +/// @brief SS Stack Segment Fault. +#define STACK_SEGMENT_FAULT 12 + +/// @brief GP General Protection. +#define GENERAL_PROTECTION 13 + +/// @brief PF Page Fault. +#define PAGE_FAULT 14 + +/// @brief XX Reserverd. +#define INT_RSV 15 + +/// @brief MF Floating Point. +#define FLOATING_POINT_ERR 16 + +/// @brief AC Alignment Check. +#define ALIGNMENT_CHECK 17 + +/// @brief MC Machine Check. +#define MACHINE_CHECK 18 + +/// @brief XF Streaming SIMD Exception. +#define SIMD_FP_EXC 19 + +/// @brief Virtualization Exception. +#define VIRT_EXC 20 + +/// @brief Reserved [21-29]. +/// @brief Security Exception. +#define SECURITY_EXC 30 + +/// @brief Triple Fault +#define TRIPLE_FAULT 31 + +/// @brief System call interrupt. +#define SYSTEM_CALL 80 +//============================================================================== diff --git a/mentos/inc/descriptor_tables/tss.h b/mentos/inc/descriptor_tables/tss.h index ea5acdb..6549a52 100644 --- a/mentos/inc/descriptor_tables/tss.h +++ b/mentos/inc/descriptor_tables/tss.h @@ -1,61 +1,61 @@ -/// MentOS, The Mentoring Operating system project -/// @file tss.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "gdt.h" -#include "stdio.h" -#include "kernel.h" - -// TODO: doxygen comment. -typedef struct tss_entry { - uint32_t prevTss; - uint32_t esp0; - uint32_t ss0; - uint32_t esp1; - uint32_t ss1; - uint32_t esp2; - uint32_t ss2; - uint32_t cr3; - uint32_t eip; - uint32_t eflags; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t es; - uint32_t cs; - uint32_t ss; - uint32_t ds; - uint32_t fs; - uint32_t gs; - uint32_t ldt; - uint16_t trap; - uint16_t iomap; -} tss_entry_t; - -extern void tss_flush(); - -/// @brief We don't need tss to assist task switching, but it's required to -/// have one tss for switching back to kernel mode(system call for -/// example). -/// @param idx -/// @param kss -/// @param kesp -void tss_init(uint8_t idx, uint32_t kss, uint32_t kesp); - -// esp the kernel should be using. -/// @brief This function is used to set the tss's esp, so that CPU knows what. -/// @param kss -/// @param kesp -void tss_set_stack(uint32_t kss, uint32_t kesp); - -// TODO: doxygen comment. -void print_tss(); +/// MentOS, The Mentoring Operating system project +/// @file tss.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "gdt.h" +#include "stdio.h" +#include "kernel.h" + +// TODO: doxygen comment. +typedef struct tss_entry { + uint32_t prevTss; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap; +} tss_entry_t; + +extern void tss_flush(); + +/// @brief We don't need tss to assist task switching, but it's required to +/// have one tss for switching back to kernel mode(system call for +/// example). +/// @param idx +/// @param kss +/// @param kesp +void tss_init(uint8_t idx, uint32_t kss, uint32_t kesp); + +// esp the kernel should be using. +/// @brief This function is used to set the tss's esp, so that CPU knows what. +/// @param kss +/// @param kesp +void tss_set_stack(uint32_t kss, uint32_t kesp); + +// TODO: doxygen comment. +void print_tss(); diff --git a/mentos/inc/devices/fpu.h b/mentos/inc/devices/fpu.h index 5edd9c5..d82c1dd 100644 --- a/mentos/inc/devices/fpu.h +++ b/mentos/inc/devices/fpu.h @@ -1,21 +1,21 @@ -/// MentOS, The Mentoring Operating system project -/// @file fpu.h -/// @brief Floating Point Unit (FPU). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "stdint.h" -#include "stdbool.h" - -// TODO: doxygen comment. -/// @brief -void switch_fpu(); - -// TODO: doxygen comment. -/// @brief -void unswitch_fpu(); - -// TODO: doxygen comment. -/// @brief -/// @return -bool_t fpu_install(); +/// MentOS, The Mentoring Operating system project +/// @file fpu.h +/// @brief Floating Point Unit (FPU). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "stdint.h" +#include "stdbool.h" + +// TODO: doxygen comment. +/// @brief +void switch_fpu(); + +// TODO: doxygen comment. +/// @brief +void unswitch_fpu(); + +// TODO: doxygen comment. +/// @brief +/// @return +bool_t fpu_install(); diff --git a/mentos/inc/devices/pci.h b/mentos/inc/devices/pci.h index f517fd4..b40d502 100644 --- a/mentos/inc/devices/pci.h +++ b/mentos/inc/devices/pci.h @@ -1,247 +1,247 @@ -/// MentOS, The Mentoring Operating system project -/// @file pci.h -/// @brief Routines for PCI initialization. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @defgroup pci_configuration_space The PCI configuration space. -/// The PCI Specification defines the organization of the 256-byte. -/// Configuration Space registers and imposes a specific template for the -/// space. Figures 2 & 3 show the layout of the 256-byte Configuration space. -/// All PCI compliant devices must support the Vendor ID, Device ID, Command -/// and Status, Revision ID, Class Code and Header Type fields. Implementation -/// of the other registers is optional, depending upon the devices -/// functionality. -/// @{ - -/// 16 bits - Identifies the manufacturer of the device. Where valid IDs are -/// allocated by PCI-SIG (the list is here) to ensure uniqueness and 0xFFFF is -/// an invalid value that will be returned on read accesses to Configuration -/// Space registers of non-existent devices. -#define PCI_VENDOR_ID 0x00 - -/// 16 bits - Identifies the particular device. Where valid IDs are allocated -/// by the vendor. -#define PCI_DEVICE_ID 0x02 - -/// 16 bits - Provides control over a device's ability to generate and -/// respond to PCI cycles. Where the only functionality guaranteed to be -/// supported by all devices is, when a 0 is written to this register, the -/// device is disconnected from the PCI bus for all accesses except -/// Configuration Space access. -#define PCI_COMMAND 0x04 - -/// 16 bits - A register used to record status information for PCI bus -/// related events. -#define PCI_STATUS 0x06 - -/// 8 bits - Specifies a revision identifier for a particular device. Where -/// valid IDs are allocated by the vendor. -#define PCI_REVISION_ID 0x08 - -/// 8 bits - A read-only register that specifies a register-level -/// programming interface the device has, if it has any at all. -#define PCI_PROG_IF 0x09 - -/// 8 bits - A read-only register that specifies the specific function the -/// device performs. -#define PCI_SUBCLASS 0x0a - -/// 8 bits - A read-only register that specifies the type of function the -/// device performs. -#define PCI_CLASS 0x0b - -/// 8 bits - Specifies the system cache line size in 32-bit units. A device -/// can limit the number of cacheline sizes it can support, if a unsupported -/// value is written to this field, the device will behave as if a value of 0 -/// was written. -#define PCI_CACHE_LINE_SIZE 0x0c - -/// 8 bits - Specifies the latency timer in units of PCI bus clocks. -#define PCI_LATENCY_TIMER 0x0d - -/// 8 bits - Identifies the layout of the rest of the header beginning at -/// byte 0x10 of the header and also specifies whether or not the device has -/// multiple functions. Where a value of 0x00 specifies a general device, a -/// value of 0x01 specifies a PCI-to-PCI bridge, and a value of 0x02 specifies -/// a CardBus bridge. If bit 7 of this register is set, the device has -/// multiple functions; otherwise, it is a single function device. -#define PCI_HEADER_TYPE 0x0e - -/// 8 bits - Represents that status and allows control of a devices BIST -/// (built-in self test). -#define PCI_BIST 0x0f - -/// @defgroup pci_base_addresses The PCI base addresses. -/// Base addresses specify locations in memory or I/O space. -/// Decoded size can be determined by writing a value of 0xffffffff to the -/// register, and reading it back. Only 1 bits are decoded. -/// @{ - -#define PCI_BASE_ADDRESS_0 0x10 - -#define PCI_BASE_ADDRESS_1 0x14 - -#define PCI_BASE_ADDRESS_2 0x18 - -#define PCI_BASE_ADDRESS_3 0x1c - -#define PCI_BASE_ADDRESS_4 0x20 - -#define PCI_BASE_ADDRESS_5 0x24 - -/// @} pci_base_addresses - -/// Points to the Card Information Structure and is used by devices that -/// share silicon between CardBus and PCI. -#define PCI_CARDBUS_CIS 0x28 - -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c - -#define PCI_SUBSYSTEM_ID 0x2e - -#define PCI_ROM_ADDRESS 0x30 - -/// Points to a linked list of new capabilities implemented by the device. -/// Used if bit 4 of the status register (Capabilities List bit) is set to 1. -/// The bottom two bits are reserved and should be masked before the Pointer -/// is used to access the Configuration Space. -#define PCI_CAPABILITY_LIST 0x34 - -/// Specifies which input of the system interrupt controllers the device's -/// interrupt pin is connected to and is implemented by any device that makes -/// use of an interrupt pin. For the x86 architecture this register -/// corresponds to the PIC IRQ numbers 0-15 (and not I/O APIC IRQ numbers) and -/// a value of 0xFF defines no connection. -#define PCI_INTERRUPT_LINE 0x3c - -/// Specifies which interrupt pin the device uses. Where a value of 0x01 is -/// INTA#, 0x02 is INTB#, 0x03 is INTC#, 0x04 is INTD#, and 0x00 means the -/// device does not use an interrupt pin. -#define PCI_INTERRUPT_PIN 0x3d - -/// A read-only register that specifies the burst period length, in 1/4 -/// microsecond units, that the device needs (assuming a 33 MHz clock rate). -#define PCI_MIN_GNT 0x3e - -/// A read-only register that specifies how often the device needs access to -/// the PCI bus (in 1/4 microsecond units). -#define PCI_MAX_LAT 0x3f - -/// @} pci_configuration_space - -#define PCI_SECONDARY_BUS 0x19 - -#define PCI_HEADER_TYPE_DEVICE 0 - -#define PCI_HEADER_TYPE_BRIDGE 1 - -#define PCI_HEADER_TYPE_CARDBUS 2 - -#define PCI_TYPE_BRIDGE 0x060400 - -#define PCI_TYPE_SATA 0x010600 - -#define PCI_ADDRESS_PORT 0xCF8 - -#define PCI_VALUE_PORT 0xCFC - -#define PCI_NONE 0xFFFF - -// TODO: doxygen comment. -/// @brief -typedef void (*pci_func_t)(uint32_t device, uint16_t vendor_id, - uint16_t device_id, void *extra); - -// TODO: doxygen comment. -/// @brief -static inline int pci_extract_bus(uint32_t device) -{ - return (uint8_t)((device >> 16)); -} - -// TODO: doxygen comment. -/// @brief -static inline int pci_extract_slot(uint32_t device) -{ - return (uint8_t)((device >> 8)); -} - -// TODO: doxygen comment. -/// @brief -static inline int pci_extract_func(uint32_t device) -{ - return (uint8_t)(device); -} - -// TODO: doxygen comment. -/// @brief -static inline uint32_t pci_get_addr(uint32_t device, int field) -{ - return 0x80000000 | (pci_extract_bus(device) << 16) | - (pci_extract_slot(device) << 11) | (pci_extract_func(device) << 8) | - ((field)&0xFC); -} - -// TODO: doxygen comment. -/// @brief -static inline uint32_t pci_box_device(int bus, int slot, int func) -{ - return (uint32_t)((bus << 16) | (slot << 8) | func); -} - -/// @brief Reads a field from the given PCI device. -uint32_t pci_read_field(uint32_t device, int field, int size); - -// TODO: doxygen comment. -/// @brief -void pci_write_field(uint32_t device, int field, int size, uint32_t value); - -// TODO: doxygen comment. -/// @brief -uint32_t pci_find_type(uint32_t device); - -// TODO: doxygen comment. -/// @brief -const char *pci_vendor_lookup(unsigned short vendor_id); - -// TODO: doxygen comment. -/// @brief -const char *pci_device_lookup(unsigned short vendor_id, - unsigned short device_id); -// TODO: doxygen comment. -/// @brief -void pci_scan_hit(pci_func_t f, uint32_t dev, void *extra); - -// TODO: doxygen comment. -/// @brief -void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, - void *extra); - -// TODO: doxygen comment. -/// @brief -void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void *extra); - -// TODO: doxygen comment. -/// @brief -void pci_scan_bus(pci_func_t f, int type, int bus, void *extra); - -// TODO: doxygen comment. -/// @brief -void pci_scan(pci_func_t f, int type, void *extra); - -// TODO: doxygen comment. -/// @brief -void pci_remap(void); - -// TODO: doxygen comment. -/// @brief -int pci_get_interrupt(uint32_t device); - -// TODO: doxygen comment. -/// @brief -void pci_debug_scan(); +/// MentOS, The Mentoring Operating system project +/// @file pci.h +/// @brief Routines for PCI initialization. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @defgroup pci_configuration_space The PCI configuration space. +/// The PCI Specification defines the organization of the 256-byte. +/// Configuration Space registers and imposes a specific template for the +/// space. Figures 2 & 3 show the layout of the 256-byte Configuration space. +/// All PCI compliant devices must support the Vendor ID, Device ID, Command +/// and Status, Revision ID, Class Code and Header Type fields. Implementation +/// of the other registers is optional, depending upon the devices +/// functionality. +/// @{ + +/// 16 bits - Identifies the manufacturer of the device. Where valid IDs are +/// allocated by PCI-SIG (the list is here) to ensure uniqueness and 0xFFFF is +/// an invalid value that will be returned on read accesses to Configuration +/// Space registers of non-existent devices. +#define PCI_VENDOR_ID 0x00 + +/// 16 bits - Identifies the particular device. Where valid IDs are allocated +/// by the vendor. +#define PCI_DEVICE_ID 0x02 + +/// 16 bits - Provides control over a device's ability to generate and +/// respond to PCI cycles. Where the only functionality guaranteed to be +/// supported by all devices is, when a 0 is written to this register, the +/// device is disconnected from the PCI bus for all accesses except +/// Configuration Space access. +#define PCI_COMMAND 0x04 + +/// 16 bits - A register used to record status information for PCI bus +/// related events. +#define PCI_STATUS 0x06 + +/// 8 bits - Specifies a revision identifier for a particular device. Where +/// valid IDs are allocated by the vendor. +#define PCI_REVISION_ID 0x08 + +/// 8 bits - A read-only register that specifies a register-level +/// programming interface the device has, if it has any at all. +#define PCI_PROG_IF 0x09 + +/// 8 bits - A read-only register that specifies the specific function the +/// device performs. +#define PCI_SUBCLASS 0x0a + +/// 8 bits - A read-only register that specifies the type of function the +/// device performs. +#define PCI_CLASS 0x0b + +/// 8 bits - Specifies the system cache line size in 32-bit units. A device +/// can limit the number of cacheline sizes it can support, if a unsupported +/// value is written to this field, the device will behave as if a value of 0 +/// was written. +#define PCI_CACHE_LINE_SIZE 0x0c + +/// 8 bits - Specifies the latency timer in units of PCI bus clocks. +#define PCI_LATENCY_TIMER 0x0d + +/// 8 bits - Identifies the layout of the rest of the header beginning at +/// byte 0x10 of the header and also specifies whether or not the device has +/// multiple functions. Where a value of 0x00 specifies a general device, a +/// value of 0x01 specifies a PCI-to-PCI bridge, and a value of 0x02 specifies +/// a CardBus bridge. If bit 7 of this register is set, the device has +/// multiple functions; otherwise, it is a single function device. +#define PCI_HEADER_TYPE 0x0e + +/// 8 bits - Represents that status and allows control of a devices BIST +/// (built-in self test). +#define PCI_BIST 0x0f + +/// @defgroup pci_base_addresses The PCI base addresses. +/// Base addresses specify locations in memory or I/O space. +/// Decoded size can be determined by writing a value of 0xffffffff to the +/// register, and reading it back. Only 1 bits are decoded. +/// @{ + +#define PCI_BASE_ADDRESS_0 0x10 + +#define PCI_BASE_ADDRESS_1 0x14 + +#define PCI_BASE_ADDRESS_2 0x18 + +#define PCI_BASE_ADDRESS_3 0x1c + +#define PCI_BASE_ADDRESS_4 0x20 + +#define PCI_BASE_ADDRESS_5 0x24 + +/// @} pci_base_addresses + +/// Points to the Card Information Structure and is used by devices that +/// share silicon between CardBus and PCI. +#define PCI_CARDBUS_CIS 0x28 + +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c + +#define PCI_SUBSYSTEM_ID 0x2e + +#define PCI_ROM_ADDRESS 0x30 + +/// Points to a linked list of new capabilities implemented by the device. +/// Used if bit 4 of the status register (Capabilities List bit) is set to 1. +/// The bottom two bits are reserved and should be masked before the Pointer +/// is used to access the Configuration Space. +#define PCI_CAPABILITY_LIST 0x34 + +/// Specifies which input of the system interrupt controllers the device's +/// interrupt pin is connected to and is implemented by any device that makes +/// use of an interrupt pin. For the x86 architecture this register +/// corresponds to the PIC IRQ numbers 0-15 (and not I/O APIC IRQ numbers) and +/// a value of 0xFF defines no connection. +#define PCI_INTERRUPT_LINE 0x3c + +/// Specifies which interrupt pin the device uses. Where a value of 0x01 is +/// INTA#, 0x02 is INTB#, 0x03 is INTC#, 0x04 is INTD#, and 0x00 means the +/// device does not use an interrupt pin. +#define PCI_INTERRUPT_PIN 0x3d + +/// A read-only register that specifies the burst period length, in 1/4 +/// microsecond units, that the device needs (assuming a 33 MHz clock rate). +#define PCI_MIN_GNT 0x3e + +/// A read-only register that specifies how often the device needs access to +/// the PCI bus (in 1/4 microsecond units). +#define PCI_MAX_LAT 0x3f + +/// @} pci_configuration_space + +#define PCI_SECONDARY_BUS 0x19 + +#define PCI_HEADER_TYPE_DEVICE 0 + +#define PCI_HEADER_TYPE_BRIDGE 1 + +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_TYPE_BRIDGE 0x060400 + +#define PCI_TYPE_SATA 0x010600 + +#define PCI_ADDRESS_PORT 0xCF8 + +#define PCI_VALUE_PORT 0xCFC + +#define PCI_NONE 0xFFFF + +// TODO: doxygen comment. +/// @brief +typedef void (*pci_func_t)(uint32_t device, uint16_t vendor_id, + uint16_t device_id, void *extra); + +// TODO: doxygen comment. +/// @brief +static inline int pci_extract_bus(uint32_t device) +{ + return (uint8_t)((device >> 16)); +} + +// TODO: doxygen comment. +/// @brief +static inline int pci_extract_slot(uint32_t device) +{ + return (uint8_t)((device >> 8)); +} + +// TODO: doxygen comment. +/// @brief +static inline int pci_extract_func(uint32_t device) +{ + return (uint8_t)(device); +} + +// TODO: doxygen comment. +/// @brief +static inline uint32_t pci_get_addr(uint32_t device, int field) +{ + return 0x80000000 | (pci_extract_bus(device) << 16) | + (pci_extract_slot(device) << 11) | (pci_extract_func(device) << 8) | + ((field)&0xFC); +} + +// TODO: doxygen comment. +/// @brief +static inline uint32_t pci_box_device(int bus, int slot, int func) +{ + return (uint32_t)((bus << 16) | (slot << 8) | func); +} + +/// @brief Reads a field from the given PCI device. +uint32_t pci_read_field(uint32_t device, int field, int size); + +// TODO: doxygen comment. +/// @brief +void pci_write_field(uint32_t device, int field, int size, uint32_t value); + +// TODO: doxygen comment. +/// @brief +uint32_t pci_find_type(uint32_t device); + +// TODO: doxygen comment. +/// @brief +const char *pci_vendor_lookup(unsigned short vendor_id); + +// TODO: doxygen comment. +/// @brief +const char *pci_device_lookup(unsigned short vendor_id, + unsigned short device_id); +// TODO: doxygen comment. +/// @brief +void pci_scan_hit(pci_func_t f, uint32_t dev, void *extra); + +// TODO: doxygen comment. +/// @brief +void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, + void *extra); + +// TODO: doxygen comment. +/// @brief +void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void *extra); + +// TODO: doxygen comment. +/// @brief +void pci_scan_bus(pci_func_t f, int type, int bus, void *extra); + +// TODO: doxygen comment. +/// @brief +void pci_scan(pci_func_t f, int type, void *extra); + +// TODO: doxygen comment. +/// @brief +void pci_remap(void); + +// TODO: doxygen comment. +/// @brief +int pci_get_interrupt(uint32_t device); + +// TODO: doxygen comment. +/// @brief +void pci_debug_scan(); diff --git a/mentos/inc/drivers/ata.h b/mentos/inc/drivers/ata.h index 6920636..b66293d 100644 --- a/mentos/inc/drivers/ata.h +++ b/mentos/inc/drivers/ata.h @@ -1,199 +1,199 @@ -/// MentOS, The Mentoring Operating system project -// @file ata.h -/// @brief ATA values and data structures. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @defgroup ata_defines The ATA configuration registers. -/// @{ - -/// @defgroup status_register Status register bits -/// @{ - -/// Device Busy -#define ATA_STAT_BUSY 0x80 -/// Device Ready -#define ATA_STAT_READY 0x40 -/// Device Fault -#define ATA_STAT_FAULT 0x20 -/// Device Seek Complete -#define ATA_STAT_SEEK 0x10 -/// Data Request (ready) -#define ATA_STAT_DRQ 0x08 -/// Corrected Data Error -#define ATA_STAT_CORR 0x04 -/// Vendor specific -#define ATA_STAT_INDEX 0x02 -/// Error -#define ATA_STAT_ERR 0x01 - -/// @} - -/// @defgroup device_registers Device / Head Register Bits -/// @{ - -#define ATA_DEVICE(x) ((x & 1) << 4) -#define ATA_LBA 0xE0 - -/// @} - -/// @defgroup ata_commands ATA Commands -/// @{ - -/// Read Sectors (with retries) -#define ATA_CMD_READ 0x20 -/// Read Sectors (no retries) -#define ATA_CMD_READN 0x21 -/// Write Sectores (with retries) -#define ATA_CMD_WRITE 0x30 -/// Write Sectors (no retries) -#define ATA_CMD_WRITEN 0x31 -/// Read Verify (with retries) -#define ATA_CMD_VRFY 0x40 -/// Read verify (no retries) -#define ATA_CMD_VRFYN 0x41 -/// Seek -#define ATA_CMD_SEEK 0x70 -/// Execute Device Diagnostic -#define ATA_CMD_DIAG 0x90 -/// Initialize Device Parameters -#define ATA_CMD_INIT 0x91 -/// Read Multiple -#define ATA_CMD_RD_MULT 0xC4 -/// Write Multiple -#define ATA_CMD_WR_MULT 0xC5 -/// Set Multiple Mode -#define ATA_CMD_SETMULT 0xC6 -/// Read DMA (with retries) -#define ATA_CMD_RD_DMA 0xC8 -/// Read DMS (no retries) -#define ATA_CMD_RD_DMAN 0xC9 -/// Write DMA (with retries) -#define ATA_CMD_WR_DMA 0xCA -/// Write DMA (no retires) -#define ATA_CMD_WR_DMAN 0xCB -/// Identify Device -#define ATA_CMD_IDENT 0xEC -#define ATA_CMD_CH_FLSH 0xE7 -/// Set Features -#define ATA_CMD_SETF 0xEF -/// Check Power Mode -#define ATA_CMD_CHK_PWR 0xE5 - -/// @} - -/// @defgroup atapi_commands ATAPI Commands -/// @{ - -#define ATAPI_CMD_PACKET 0xA0 -#define ATAPI_CMD_ID_PCKT 0xA1 - -/// @} - -#define ATA_IDENT_DEVICETYPE 0 -#define ATA_IDENT_CYLINDERS 2 -#define ATA_IDENT_HEADS 6 -#define ATA_IDENT_SECTORS 12 -#define ATA_IDENT_SERIAL 20 -#define ATA_IDENT_MODEL 54 -#define ATA_IDENT_CAPABILITIES 98 -#define ATA_IDENT_FIELDVALID 106 -#define ATA_IDENT_MAX_LBA 120 -#define ATA_IDENT_COMMANDSETS 164 -#define ATA_IDENT_MAX_LBA_EXT 200 - -#define IDE_ATA 0x00 -#define IDE_ATAPI 0x01 - -#define ATA_MASTER 0x00 -#define ATA_SLAVE 0x01 - -#define ATA_REG_DATA 0x00 -#define ATA_REG_ERROR 0x01 -#define ATA_REG_FEATURES 0x01 -#define ATA_REG_SECCOUNT0 0x02 -#define ATA_REG_LBA0 0x03 -#define ATA_REG_LBA1 0x04 -#define ATA_REG_LBA2 0x05 -#define ATA_REG_HDDEVSEL 0x06 -#define ATA_REG_COMMAND 0x07 -#define ATA_REG_STATUS 0x07 -#define ATA_REG_SECCOUNT1 0x08 -#define ATA_REG_LBA3 0x09 -#define ATA_REG_LBA4 0x0A -#define ATA_REG_LBA5 0x0B -#define ATA_REG_CONTROL 0x0C -#define ATA_REG_ALTSTATUS 0x0C -#define ATA_REG_DEVADDRESS 0x0D - -// Channels: -#define ATA_PRIMARY 0x00 -#define ATA_SECONDARY 0x01 - -// Directions: -#define ATA_READ 0x00 -#define ATA_WRITE 0x01 - -/// @} - -typedef struct { - uint16_t base; - uint16_t ctrl; - uint16_t bmide; - uint16_t nien; -} ide_channel_regs_t; - -typedef struct { - uint8_t reserved; - uint8_t channel; - uint8_t drive; - uint16_t type; - uint16_t signature; - uint16_t capabilities; - uint32_t command_sets; - uint32_t size; - uint8_t model[41]; -} ide_device_t; - -typedef struct { - uint8_t status; - uint8_t chs_first_sector[3]; - uint8_t type; - uint8_t chs_last_sector[3]; - uint32_t lba_first_sector; - uint32_t sector_count; -} partition_t; - -typedef struct { - uint16_t flags; - uint16_t unused1[9]; - char serial[20]; - uint16_t unused2[3]; - char firmware[8]; - char model[40]; - uint16_t sectors_per_int; - uint16_t unused3; - uint16_t capabilities[2]; - uint16_t unused4[2]; - uint16_t valid_ext_data; - uint16_t unused5[5]; - uint16_t size_of_rw_mult; - uint32_t sectors_28; - uint16_t unused6[38]; - uint64_t sectors_48; - uint16_t unused7[152]; -} __attribute__((packed)) ata_identify_t; - -typedef struct { - uint8_t boostrap[446]; - partition_t partitions[4]; - uint8_t signature[2]; -} __attribute__((packed)) mbr_t; - -int ata_initialize(); - -int ata_finalize(); +/// MentOS, The Mentoring Operating system project +// @file ata.h +/// @brief ATA values and data structures. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @defgroup ata_defines The ATA configuration registers. +/// @{ + +/// @defgroup status_register Status register bits +/// @{ + +/// Device Busy +#define ATA_STAT_BUSY 0x80 +/// Device Ready +#define ATA_STAT_READY 0x40 +/// Device Fault +#define ATA_STAT_FAULT 0x20 +/// Device Seek Complete +#define ATA_STAT_SEEK 0x10 +/// Data Request (ready) +#define ATA_STAT_DRQ 0x08 +/// Corrected Data Error +#define ATA_STAT_CORR 0x04 +/// Vendor specific +#define ATA_STAT_INDEX 0x02 +/// Error +#define ATA_STAT_ERR 0x01 + +/// @} + +/// @defgroup device_registers Device / Head Register Bits +/// @{ + +#define ATA_DEVICE(x) ((x & 1) << 4) +#define ATA_LBA 0xE0 + +/// @} + +/// @defgroup ata_commands ATA Commands +/// @{ + +/// Read Sectors (with retries) +#define ATA_CMD_READ 0x20 +/// Read Sectors (no retries) +#define ATA_CMD_READN 0x21 +/// Write Sectores (with retries) +#define ATA_CMD_WRITE 0x30 +/// Write Sectors (no retries) +#define ATA_CMD_WRITEN 0x31 +/// Read Verify (with retries) +#define ATA_CMD_VRFY 0x40 +/// Read verify (no retries) +#define ATA_CMD_VRFYN 0x41 +/// Seek +#define ATA_CMD_SEEK 0x70 +/// Execute Device Diagnostic +#define ATA_CMD_DIAG 0x90 +/// Initialize Device Parameters +#define ATA_CMD_INIT 0x91 +/// Read Multiple +#define ATA_CMD_RD_MULT 0xC4 +/// Write Multiple +#define ATA_CMD_WR_MULT 0xC5 +/// Set Multiple Mode +#define ATA_CMD_SETMULT 0xC6 +/// Read DMA (with retries) +#define ATA_CMD_RD_DMA 0xC8 +/// Read DMS (no retries) +#define ATA_CMD_RD_DMAN 0xC9 +/// Write DMA (with retries) +#define ATA_CMD_WR_DMA 0xCA +/// Write DMA (no retires) +#define ATA_CMD_WR_DMAN 0xCB +/// Identify Device +#define ATA_CMD_IDENT 0xEC +#define ATA_CMD_CH_FLSH 0xE7 +/// Set Features +#define ATA_CMD_SETF 0xEF +/// Check Power Mode +#define ATA_CMD_CHK_PWR 0xE5 + +/// @} + +/// @defgroup atapi_commands ATAPI Commands +/// @{ + +#define ATAPI_CMD_PACKET 0xA0 +#define ATAPI_CMD_ID_PCKT 0xA1 + +/// @} + +#define ATA_IDENT_DEVICETYPE 0 +#define ATA_IDENT_CYLINDERS 2 +#define ATA_IDENT_HEADS 6 +#define ATA_IDENT_SECTORS 12 +#define ATA_IDENT_SERIAL 20 +#define ATA_IDENT_MODEL 54 +#define ATA_IDENT_CAPABILITIES 98 +#define ATA_IDENT_FIELDVALID 106 +#define ATA_IDENT_MAX_LBA 120 +#define ATA_IDENT_COMMANDSETS 164 +#define ATA_IDENT_MAX_LBA_EXT 200 + +#define IDE_ATA 0x00 +#define IDE_ATAPI 0x01 + +#define ATA_MASTER 0x00 +#define ATA_SLAVE 0x01 + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_FEATURES 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 +#define ATA_REG_SECCOUNT1 0x08 +#define ATA_REG_LBA3 0x09 +#define ATA_REG_LBA4 0x0A +#define ATA_REG_LBA5 0x0B +#define ATA_REG_CONTROL 0x0C +#define ATA_REG_ALTSTATUS 0x0C +#define ATA_REG_DEVADDRESS 0x0D + +// Channels: +#define ATA_PRIMARY 0x00 +#define ATA_SECONDARY 0x01 + +// Directions: +#define ATA_READ 0x00 +#define ATA_WRITE 0x01 + +/// @} + +typedef struct { + uint16_t base; + uint16_t ctrl; + uint16_t bmide; + uint16_t nien; +} ide_channel_regs_t; + +typedef struct { + uint8_t reserved; + uint8_t channel; + uint8_t drive; + uint16_t type; + uint16_t signature; + uint16_t capabilities; + uint32_t command_sets; + uint32_t size; + uint8_t model[41]; +} ide_device_t; + +typedef struct { + uint8_t status; + uint8_t chs_first_sector[3]; + uint8_t type; + uint8_t chs_last_sector[3]; + uint32_t lba_first_sector; + uint32_t sector_count; +} partition_t; + +typedef struct { + uint16_t flags; + uint16_t unused1[9]; + char serial[20]; + uint16_t unused2[3]; + char firmware[8]; + char model[40]; + uint16_t sectors_per_int; + uint16_t unused3; + uint16_t capabilities[2]; + uint16_t unused4[2]; + uint16_t valid_ext_data; + uint16_t unused5[5]; + uint16_t size_of_rw_mult; + uint32_t sectors_28; + uint16_t unused6[38]; + uint64_t sectors_48; + uint16_t unused7[152]; +} __attribute__((packed)) ata_identify_t; + +typedef struct { + uint8_t boostrap[446]; + partition_t partitions[4]; + uint8_t signature[2]; +} __attribute__((packed)) mbr_t; + +int ata_initialize(); + +int ata_finalize(); diff --git a/mentos/inc/drivers/fdc.h b/mentos/inc/drivers/fdc.h index 608ecec..79333a8 100644 --- a/mentos/inc/drivers/fdc.h +++ b/mentos/inc/drivers/fdc.h @@ -1,45 +1,45 @@ -/// MentOS, The Mentoring Operating system project -/// @file fdc.h -/// @brief Definitions about the floppy. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief Floppy Disk Controller (FDC) registers. -typedef enum fdc_registers_t -{ - STATUS_REGISTER_A = 0x3F0, - ///< This register is read-only and monitors the state of the - ///< interrupt pin and several disk interface pins. - STATUS_REGISTER_B = 0x3F1, - ///< This register is read-only and monitors the state of several - ///< isk interface pins. - DOR = 0x3F2, - ///< The Digital Output Register contains the drive select and - ///< motor enable bits, a reset bit and a DMA GATE bit. - TAPE_DRIVE_REGISTER = 0x3F3, - ///< This register allows the user to assign tape support to a - ///< particular drive during initialization. - MAIN_STATUS_REGISTER = 0x3F4, - ///< The Main Status Register is a read-only register and is used - ///< for controlling command input and result output for all commands. - DATARATE_SELECT_REGISTER = 0x3F4, - ///< This register is included for compatibility with the 82072 - ///< floppy controller and is write-only. - DATA_FIFO = 0x3F5, - ///< All command parameter information and disk data transfers go - ///< through the FIFO. - DIGITAL_INPUT_REGISTER = 0x3F7, - ///< This register is read only in all modes. - CONFIGURATION_CONTROL_REGISTER = 0x3F7 - ///< This register sets the datarate and is write only. -} fdc_registers_t; - -/// @brief Allows to enable the motor. -/// @details The motor enable pins are directly controlled via the DOR and -/// are a function of the mapping based on BOOTSEL bits in the TDR. -void fdc_enable_motor(void); - -/// @brief Allows to disable the motor. -void fdc_disable_motor(void); +/// MentOS, The Mentoring Operating system project +/// @file fdc.h +/// @brief Definitions about the floppy. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief Floppy Disk Controller (FDC) registers. +typedef enum fdc_registers_t +{ + STATUS_REGISTER_A = 0x3F0, + ///< This register is read-only and monitors the state of the + ///< interrupt pin and several disk interface pins. + STATUS_REGISTER_B = 0x3F1, + ///< This register is read-only and monitors the state of several + ///< isk interface pins. + DOR = 0x3F2, + ///< The Digital Output Register contains the drive select and + ///< motor enable bits, a reset bit and a DMA GATE bit. + TAPE_DRIVE_REGISTER = 0x3F3, + ///< This register allows the user to assign tape support to a + ///< particular drive during initialization. + MAIN_STATUS_REGISTER = 0x3F4, + ///< The Main Status Register is a read-only register and is used + ///< for controlling command input and result output for all commands. + DATARATE_SELECT_REGISTER = 0x3F4, + ///< This register is included for compatibility with the 82072 + ///< floppy controller and is write-only. + DATA_FIFO = 0x3F5, + ///< All command parameter information and disk data transfers go + ///< through the FIFO. + DIGITAL_INPUT_REGISTER = 0x3F7, + ///< This register is read only in all modes. + CONFIGURATION_CONTROL_REGISTER = 0x3F7 + ///< This register sets the datarate and is write only. +} fdc_registers_t; + +/// @brief Allows to enable the motor. +/// @details The motor enable pins are directly controlled via the DOR and +/// are a function of the mapping based on BOOTSEL bits in the TDR. +void fdc_enable_motor(void); + +/// @brief Allows to disable the motor. +void fdc_disable_motor(void); diff --git a/mentos/inc/drivers/keyboard/keyboard.h b/mentos/inc/drivers/keyboard/keyboard.h index 6436794..a72d1ba 100644 --- a/mentos/inc/drivers/keyboard/keyboard.h +++ b/mentos/inc/drivers/keyboard/keyboard.h @@ -1,51 +1,51 @@ -/// MentOS, The Mentoring Operating system project -/// @file keyboard.h -/// @brief Definitions about the keyboard. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "kernel.h" -#include "stdint.h" -#include "stdbool.h" - -/// @brief The dimension of the circular buffer used to store video history. -#define BUFSIZE 256 - -/// @brief Function used to install the keyboard. -void keyboard_install(); - -/// @brief The keyboard handler. -void keyboard_isr(pt_regs *r); - -/// @brief Enable the keyboard. -void keyboard_enable(); - -/// @brief Disable the keyboard. -void keyboard_disable(); - -/// @brief Leds handler. -void keyboard_update_leds(); - -/// @brief Get a char from the buffer. -/// @details It loops until there is something new to read. -/// @return The read character. -int keyboard_getc(); - -/// @brief Set Keyboard echo Shadow. -/// @param value 1 if you want enable shadow, 0 otherwise. -void keyboard_set_shadow(const bool_t value); - -/// @brief Set Keyboard echo Shadow character. -/// @param value 1 if you want enable shadow, 0 otherwise. -void keyboard_set_shadow_character(const char _shadow_character); - -/// @brief Get Keyboard Shadow information. -bool_t keyboard_get_shadow(); - -/// @brief Get ctrl status. -bool_t keyboard_is_ctrl_pressed(); - -/// @brief Get shift status. -bool_t keyboard_is_shifted(); +/// MentOS, The Mentoring Operating system project +/// @file keyboard.h +/// @brief Definitions about the keyboard. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "kernel.h" +#include "stdint.h" +#include "stdbool.h" + +/// @brief The dimension of the circular buffer used to store video history. +#define BUFSIZE 256 + +/// @brief Function used to install the keyboard. +void keyboard_install(); + +/// @brief The keyboard handler. +void keyboard_isr(pt_regs *r); + +/// @brief Enable the keyboard. +void keyboard_enable(); + +/// @brief Disable the keyboard. +void keyboard_disable(); + +/// @brief Leds handler. +void keyboard_update_leds(); + +/// @brief Get a char from the buffer. +/// @details It loops until there is something new to read. +/// @return The read character. +int keyboard_getc(); + +/// @brief Set Keyboard echo Shadow. +/// @param value 1 if you want enable shadow, 0 otherwise. +void keyboard_set_shadow(const bool_t value); + +/// @brief Set Keyboard echo Shadow character. +/// @param value 1 if you want enable shadow, 0 otherwise. +void keyboard_set_shadow_character(const char _shadow_character); + +/// @brief Get Keyboard Shadow information. +bool_t keyboard_get_shadow(); + +/// @brief Get ctrl status. +bool_t keyboard_is_ctrl_pressed(); + +/// @brief Get shift status. +bool_t keyboard_is_shifted(); diff --git a/mentos/inc/drivers/keyboard/keymap.h b/mentos/inc/drivers/keyboard/keymap.h index 9ce71c7..1c94ed5 100644 --- a/mentos/inc/drivers/keyboard/keymap.h +++ b/mentos/inc/drivers/keyboard/keymap.h @@ -1,242 +1,242 @@ -/// MentOS, The Mentoring Operating system project -/// @file keymap.h -/// @brief Keymap for keyboard. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @defgroup keyboardcodes Keyboard Codes -/// @brief This is the list of keyboard codes. -/// @{ - -/// Escape character. -#define KEY_ESCAPE 0x01 -/// 1. -#define KEY_ONE 0x02 -/// 2. -#define KEY_TWO 0x03 -/// 3. -#define KEY_THREE 0x04 -/// 4. -#define KEY_FOUR 0x05 -/// 5. -#define KEY_FIVE 0x06 -/// 6. -#define KEY_SIX 0x07 -/// 7. -#define KEY_SEVEN 0x08 -/// 8. -#define KEY_EIGHT 0x09 -/// 9. -#define KEY_NINE 0x0A -/// 0. -#define KEY_ZERO 0x0B -/// '. -#define KEY_APOSTROPHE 0x0C -/// i'. -#define KEY_I_ACC 0x0D -/// Backspace. -#define KEY_BACKSPACE 0x0E -/// Tabular. -#define KEY_TAB 0x0F -/// q. -#define KEY_Q 0x10 -/// w. -#define KEY_W 0x11 -/// e. -#define KEY_E 0x12 -/// r. -#define KEY_R 0x13 -/// t. -#define KEY_T 0x14 -/// y. -#define KEY_Y 0x15 -/// u. -#define KEY_U 0x16 -/// i. -#define KEY_I 0x17 -/// o. -#define KEY_O 0x18 -/// p. -#define KEY_P 0x19 -/// (. -#define KEY_LEFT_BRAKET 0x1A -/// ). -#define KEY_RIGHT_BRAKET 0x1B -/// Enter. -#define KEY_ENTER 0x1C -/// Left-ctrl. -#define KEY_LEFT_CONTROL 0x1D -/// a. -#define KEY_A 0x1E -/// s. -#define KEY_S 0x1F -/// d. -#define KEY_D 0x20 -/// f. -#define KEY_F 0x21 -/// g. -#define KEY_G 0x22 -/// h. -#define KEY_H 0x23 -/// j. -#define KEY_J 0x24 -/// k. -#define KEY_K 0x25 -/// l. -#define KEY_L 0x26 -/// '. -#define KEY_SEMICOLON 0x27 -/// ". -#define KEY_DOUBLE_QUOTES 0x28 -///` or ~. -#define KEY_GRAVE 0x29 -/// LShift. -#define KEY_LEFT_SHIFT 0x2A -/// \ or |. -#define KEY_BACKSLASH 0x2B -/// Z. -#define KEY_Z 0x2c -/// X. -#define KEY_X 0x2d -/// C. -#define KEY_C 0x2e -/// V. -#define KEY_V 0x2f -/// B. -#define KEY_B 0x30 -/// N. -#define KEY_N 0x31 -/// M. -#define KEY_M 0x32 -/// , or <. -#define KEY_COMMA 0x33 -/// . or >. -#define KEY_PERIOD 0x34 -/// - or _. -#define KEY_MINUS 0x35 -/// RShift. -#define KEY_RIGHT_SHIFT 0x36 -/// NP - *. -#define KEY_KP_MUL 0x37 -/// LAlt. -#define KEY_LEFT_ALT 0x38 -/// Space. -#define KEY_SPACE 0x39 -/// Caps Lock. -#define KEY_CAPS_LOCK 0x3a -/// Function 1. -#define KEY_F1 0x3B -/// Function 2. -#define KEY_F2 0x3C -/// Function 3. -#define KEY_F3 0x3D -/// Function 4. -#define KEY_F4 0x3E -/// Function 5. -#define KEY_F5 0x3F -/// Function 6. -#define KEY_F6 0x40 -/// Function 7. -#define KEY_F7 0x41 -/// Function 8. -#define KEY_F8 0x42 -/// Function 9. -#define KEY_F9 0x43 -/// Function 10. -#define KEY_F10 0x44 -/// Num Lock. -#define KEY_NUM_LOCK 0x45 -/// Scroll Lock. -#define KEY_SCROLL_LOCK 0x46 -/// NP - Home. -#define KEY_KP7 0x47 -/// NP - UpArrow. -#define KEY_KP8 0x48 -/// NP - Pgup. -#define KEY_KP9 0x49 -/// NP - Grey. -#define KEY_KP_SUB 0x4A -/// NP - LArrow. -#define KEY_KP4 0x4B -/// NP - Center. -#define KEY_KP5 0x4C -/// NP - RArrow. -#define KEY_KP6 0x4D -/// NP - Grey +. -#define KEY_KP_ADD 0x4E -/// NP - End. -#define KEY_KP1 0x4F -/// NP - DArrow. -#define KEY_KP2 0x50 -/// NP - Pgdn. -#define KEY_KP3 0x51 -/// NP - Ins. -#define KEY_KP0 0x52 -/// NP - Del. -#define KEY_KP_DEC 0x53 -/// NP - Del. -#define KEY_KP_LESS 0x56 -/// NP - Enter 57372. -#define KEY_KP_RETURN 0xe01c -/// Right Ctrl 57373. -#define KEY_RIGHT_CONTROL 0xE01D -/// Divide 57397. -#define KEY_KP_DIV 0xE035 -/// Right Alt 57400. -#define KEY_RIGHT_ALT 0xe038 -/// F11 57431. -#define KEY_F11 0xe057 -/// F12 57432. -#define KEY_F12 0xe058 -/// Left Winkey 57435. -#define KEY_LEFT_WIN 0xe05b -/// Right Winkey 57436. -#define KEY_RIGHT_WIN 0xe05c -/// Ins 57426. -#define KEY_INSERT 0xe052 -/// Home 57415. -#define KEY_HOME 0xe047 -/// Up Arrow 57416. -#define KEY_UP_ARROW 0xe048 -/// Pgup 57417. -#define KEY_PAGE_UP 0xe049 -/// Left Arrow 57419. -#define KEY_LEFT_ARROW 0xe04b -/// Del 57427. -#define KEY_DELETE 0xe053 -/// End 57423. -#define KEY_END 0xe04f -/// Pgdn 57425. -#define KEY_PAGE_DOWN 0xe051 -/// Right Arrow 57421. -#define KEY_RIGHT_ARROW 0xe04d -/// Down Arrow 57424. -#define KEY_DOWN_ARROW 0xe050 -///< Code break code. -#define CODE_BREAK 0x80 - -/// @} - -/// Num Pad Led. -#define NUM_LED 0x45 -/// Scroll Lock Led. -#define SCROLL_LED 0x46 -/// Caps Lock Led. -#define CAPS_LED 0x3a - -/// @brief Defines a set of arrays used to map key to characters. -typedef struct keymap_t { - /// The basic mapping. - int32_t base[65536]; - /// The mapping when shifted. - int32_t shift[65536]; - /// The mapping when numlock is active. - uint32_t numlock[65536]; -} keymap_t; - -/// @brief Italian keymap. -extern const keymap_t keymap_it; +/// MentOS, The Mentoring Operating system project +/// @file keymap.h +/// @brief Keymap for keyboard. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @defgroup keyboardcodes Keyboard Codes +/// @brief This is the list of keyboard codes. +/// @{ + +/// Escape character. +#define KEY_ESCAPE 0x01 +/// 1. +#define KEY_ONE 0x02 +/// 2. +#define KEY_TWO 0x03 +/// 3. +#define KEY_THREE 0x04 +/// 4. +#define KEY_FOUR 0x05 +/// 5. +#define KEY_FIVE 0x06 +/// 6. +#define KEY_SIX 0x07 +/// 7. +#define KEY_SEVEN 0x08 +/// 8. +#define KEY_EIGHT 0x09 +/// 9. +#define KEY_NINE 0x0A +/// 0. +#define KEY_ZERO 0x0B +/// '. +#define KEY_APOSTROPHE 0x0C +/// i'. +#define KEY_I_ACC 0x0D +/// Backspace. +#define KEY_BACKSPACE 0x0E +/// Tabular. +#define KEY_TAB 0x0F +/// q. +#define KEY_Q 0x10 +/// w. +#define KEY_W 0x11 +/// e. +#define KEY_E 0x12 +/// r. +#define KEY_R 0x13 +/// t. +#define KEY_T 0x14 +/// y. +#define KEY_Y 0x15 +/// u. +#define KEY_U 0x16 +/// i. +#define KEY_I 0x17 +/// o. +#define KEY_O 0x18 +/// p. +#define KEY_P 0x19 +/// (. +#define KEY_LEFT_BRAKET 0x1A +/// ). +#define KEY_RIGHT_BRAKET 0x1B +/// Enter. +#define KEY_ENTER 0x1C +/// Left-ctrl. +#define KEY_LEFT_CONTROL 0x1D +/// a. +#define KEY_A 0x1E +/// s. +#define KEY_S 0x1F +/// d. +#define KEY_D 0x20 +/// f. +#define KEY_F 0x21 +/// g. +#define KEY_G 0x22 +/// h. +#define KEY_H 0x23 +/// j. +#define KEY_J 0x24 +/// k. +#define KEY_K 0x25 +/// l. +#define KEY_L 0x26 +/// '. +#define KEY_SEMICOLON 0x27 +/// ". +#define KEY_DOUBLE_QUOTES 0x28 +///` or ~. +#define KEY_GRAVE 0x29 +/// LShift. +#define KEY_LEFT_SHIFT 0x2A +/// \ or |. +#define KEY_BACKSLASH 0x2B +/// Z. +#define KEY_Z 0x2c +/// X. +#define KEY_X 0x2d +/// C. +#define KEY_C 0x2e +/// V. +#define KEY_V 0x2f +/// B. +#define KEY_B 0x30 +/// N. +#define KEY_N 0x31 +/// M. +#define KEY_M 0x32 +/// , or <. +#define KEY_COMMA 0x33 +/// . or >. +#define KEY_PERIOD 0x34 +/// - or _. +#define KEY_MINUS 0x35 +/// RShift. +#define KEY_RIGHT_SHIFT 0x36 +/// NP - *. +#define KEY_KP_MUL 0x37 +/// LAlt. +#define KEY_LEFT_ALT 0x38 +/// Space. +#define KEY_SPACE 0x39 +/// Caps Lock. +#define KEY_CAPS_LOCK 0x3a +/// Function 1. +#define KEY_F1 0x3B +/// Function 2. +#define KEY_F2 0x3C +/// Function 3. +#define KEY_F3 0x3D +/// Function 4. +#define KEY_F4 0x3E +/// Function 5. +#define KEY_F5 0x3F +/// Function 6. +#define KEY_F6 0x40 +/// Function 7. +#define KEY_F7 0x41 +/// Function 8. +#define KEY_F8 0x42 +/// Function 9. +#define KEY_F9 0x43 +/// Function 10. +#define KEY_F10 0x44 +/// Num Lock. +#define KEY_NUM_LOCK 0x45 +/// Scroll Lock. +#define KEY_SCROLL_LOCK 0x46 +/// NP - Home. +#define KEY_KP7 0x47 +/// NP - UpArrow. +#define KEY_KP8 0x48 +/// NP - Pgup. +#define KEY_KP9 0x49 +/// NP - Grey. +#define KEY_KP_SUB 0x4A +/// NP - LArrow. +#define KEY_KP4 0x4B +/// NP - Center. +#define KEY_KP5 0x4C +/// NP - RArrow. +#define KEY_KP6 0x4D +/// NP - Grey +. +#define KEY_KP_ADD 0x4E +/// NP - End. +#define KEY_KP1 0x4F +/// NP - DArrow. +#define KEY_KP2 0x50 +/// NP - Pgdn. +#define KEY_KP3 0x51 +/// NP - Ins. +#define KEY_KP0 0x52 +/// NP - Del. +#define KEY_KP_DEC 0x53 +/// NP - Del. +#define KEY_KP_LESS 0x56 +/// NP - Enter 57372. +#define KEY_KP_RETURN 0xe01c +/// Right Ctrl 57373. +#define KEY_RIGHT_CONTROL 0xE01D +/// Divide 57397. +#define KEY_KP_DIV 0xE035 +/// Right Alt 57400. +#define KEY_RIGHT_ALT 0xe038 +/// F11 57431. +#define KEY_F11 0xe057 +/// F12 57432. +#define KEY_F12 0xe058 +/// Left Winkey 57435. +#define KEY_LEFT_WIN 0xe05b +/// Right Winkey 57436. +#define KEY_RIGHT_WIN 0xe05c +/// Ins 57426. +#define KEY_INSERT 0xe052 +/// Home 57415. +#define KEY_HOME 0xe047 +/// Up Arrow 57416. +#define KEY_UP_ARROW 0xe048 +/// Pgup 57417. +#define KEY_PAGE_UP 0xe049 +/// Left Arrow 57419. +#define KEY_LEFT_ARROW 0xe04b +/// Del 57427. +#define KEY_DELETE 0xe053 +/// End 57423. +#define KEY_END 0xe04f +/// Pgdn 57425. +#define KEY_PAGE_DOWN 0xe051 +/// Right Arrow 57421. +#define KEY_RIGHT_ARROW 0xe04d +/// Down Arrow 57424. +#define KEY_DOWN_ARROW 0xe050 +///< Code break code. +#define CODE_BREAK 0x80 + +/// @} + +/// Num Pad Led. +#define NUM_LED 0x45 +/// Scroll Lock Led. +#define SCROLL_LED 0x46 +/// Caps Lock Led. +#define CAPS_LED 0x3a + +/// @brief Defines a set of arrays used to map key to characters. +typedef struct keymap_t { + /// The basic mapping. + int32_t base[65536]; + /// The mapping when shifted. + int32_t shift[65536]; + /// The mapping when numlock is active. + uint32_t numlock[65536]; +} keymap_t; + +/// @brief Italian keymap. +extern const keymap_t keymap_it; diff --git a/mentos/inc/drivers/mouse.h b/mentos/inc/drivers/mouse.h index 0f20a34..b22f615 100644 --- a/mentos/inc/drivers/mouse.h +++ b/mentos/inc/drivers/mouse.h @@ -1,45 +1,45 @@ -/// MentOS, The Mentoring Operating system project -/// @file mouse.h -/// @brief Driver for *PS2* Mouses. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/* The mouse starts sending automatic packets when the mouse moves or is - * clicked. - */ -#include - -#define MOUSE_ENABLE_PACKET 0xF4 - -/// The mouse stops sending automatic packets. -#define MOUSE_DISABLE_PACKET 0xF5 - -/// Disables streaming, sets the packet rate to 100 per second, and -/// resolution to 4 pixels per mm. -#define MOUSE_USE_DEFAULT_SETTINGS 0xF6 - -/// @brief Sets up the mouse by installing the mouse handler into IRQ12. -void mouse_install(); - -/// @brief Enable the mouse driver. -void mouse_enable(); - -/// @brief Disable the mouse driver. -void mouse_disable(); - -/// @brief Mouse wait for a command. -/// @param type 1 for sending - 0 for receiving. -void mouse_waitcmd(unsigned char type); - -/// @brief Send data to mouse. -/// @param data The data to send. -void mouse_write(unsigned char data); - -/// @brief Read data from mouse. -/// @return The data received from mouse. -unsigned char mouse_read(); - -/// @brief The mouse handler. -void mouse_isr(register_t *r); +/// MentOS, The Mentoring Operating system project +/// @file mouse.h +/// @brief Driver for *PS2* Mouses. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/* The mouse starts sending automatic packets when the mouse moves or is + * clicked. + */ +#include + +#define MOUSE_ENABLE_PACKET 0xF4 + +/// The mouse stops sending automatic packets. +#define MOUSE_DISABLE_PACKET 0xF5 + +/// Disables streaming, sets the packet rate to 100 per second, and +/// resolution to 4 pixels per mm. +#define MOUSE_USE_DEFAULT_SETTINGS 0xF6 + +/// @brief Sets up the mouse by installing the mouse handler into IRQ12. +void mouse_install(); + +/// @brief Enable the mouse driver. +void mouse_enable(); + +/// @brief Disable the mouse driver. +void mouse_disable(); + +/// @brief Mouse wait for a command. +/// @param type 1 for sending - 0 for receiving. +void mouse_waitcmd(unsigned char type); + +/// @brief Send data to mouse. +/// @param data The data to send. +void mouse_write(unsigned char data); + +/// @brief Read data from mouse. +/// @return The data received from mouse. +unsigned char mouse_read(); + +/// @brief The mouse handler. +void mouse_isr(register_t *r); diff --git a/mentos/inc/elf/elf.h b/mentos/inc/elf/elf.h index b3bad2e..1caf8a0 100644 --- a/mentos/inc/elf/elf.h +++ b/mentos/inc/elf/elf.h @@ -1,60 +1,60 @@ -/// MentOS, The Mentoring Operating system project -/// @file elf.h -/// @brief Function for multiboot support. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" -#include "multiboot.h" - -// Used to get the symbol type. -#define ELF32_ST_TYPE(i) ((i)&0xf) - -// List of symbol types. -#define ELF32_TYPE_FUNCTION (0x02) - -/// @brief A section header with all kinds of useful information. -typedef struct elf_section_header -{ - uint32_t name_offset_in_shstrtab; - uint32_t type; - uint32_t flags; - uint32_t addr; - uint32_t offset; - uint32_t size; - uint32_t link; - uint32_t info; - uint32_t addralign; - uint32_t entsize; -} __attribute__((packed)) elf_section_header_t; - -/// @brief A symbol itself. -typedef struct elf_symbol -{ - uint32_t name_offset_in_strtab; - uint32_t value; - uint32_t size; - uint8_t info; - uint8_t other; - uint16_t shndx; -} __attribute__((packed)) elf_symbol_t; - -// Will hold the array of symbols and their names for us. -typedef struct elf_symbols -{ - elf_symbol_t *symtab; - uint32_t symtab_size; - const char *strtab; - uint32_t strtab_size; -} elf_symbols_t; - - -/// @brief Builds as the set of elf symbols from a multiboot scructure. -void build_elf_symbols_from_multiboot (multiboot_info_t* mb); - -/* Locate a symbol (only functions) in the following elf symbols - * Note that, for now, we'll only use this for the kernel (no other elf things..) - */ -const char *elf_lookup_symbol (uint32_t addr, elf_symbols_t *elf); +/// MentOS, The Mentoring Operating system project +/// @file elf.h +/// @brief Function for multiboot support. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" +#include "multiboot.h" + +// Used to get the symbol type. +#define ELF32_ST_TYPE(i) ((i)&0xf) + +// List of symbol types. +#define ELF32_TYPE_FUNCTION (0x02) + +/// @brief A section header with all kinds of useful information. +typedef struct elf_section_header +{ + uint32_t name_offset_in_shstrtab; + uint32_t type; + uint32_t flags; + uint32_t addr; + uint32_t offset; + uint32_t size; + uint32_t link; + uint32_t info; + uint32_t addralign; + uint32_t entsize; +} __attribute__((packed)) elf_section_header_t; + +/// @brief A symbol itself. +typedef struct elf_symbol +{ + uint32_t name_offset_in_strtab; + uint32_t value; + uint32_t size; + uint8_t info; + uint8_t other; + uint16_t shndx; +} __attribute__((packed)) elf_symbol_t; + +// Will hold the array of symbols and their names for us. +typedef struct elf_symbols +{ + elf_symbol_t *symtab; + uint32_t symtab_size; + const char *strtab; + uint32_t strtab_size; +} elf_symbols_t; + + +/// @brief Builds as the set of elf symbols from a multiboot scructure. +void build_elf_symbols_from_multiboot (multiboot_info_t* mb); + +/* Locate a symbol (only functions) in the following elf symbols + * Note that, for now, we'll only use this for the kernel (no other elf things..) + */ +const char *elf_lookup_symbol (uint32_t addr, elf_symbols_t *elf); diff --git a/mentos/inc/experimental/deadlock_prevention.h b/mentos/inc/experimental/deadlock_prevention.h new file mode 100644 index 0000000..5b6bae0 --- /dev/null +++ b/mentos/inc/experimental/deadlock_prevention.h @@ -0,0 +1,31 @@ +/** + * @author Mirco De Marchi + * @date 2/02/2021 + * @brief Header file for deadlock prevention algorithms. + * @copyright (c) University of Verona + */ + +#pragma once + +#include "stdio.h" +#include "stdlib.h" +#include "stdio.h" +#include "stdbool.h" +#include "string.h" + +/// @brief Resource allocation request status enumeration. +typedef enum { + SAFE, ///< State safe. + WAIT, ///< State waiting. + WAIT_UNSAFE, ///< State waiting for unsafe detection. + ERROR, ///< State error. +} deadlock_status_t; + +/// @brief Request of resources perfomed by a task. +/// @param req_vec Array pointer of resource request for each task in the +/// system. +/// @param task_i Index of task that perform the request to use as array index. +/// @param n Number of tasks currently in the system. +/// @param m Number of resource types in the system (length of req_vec). +/// @return Status of the request (see status_t enum). +deadlock_status_t request(uint32_t *req_vec, size_t task_i, size_t n, size_t m); diff --git a/mentos/inc/experimental/deadlock_simulation.h b/mentos/inc/experimental/deadlock_simulation.h new file mode 100644 index 0000000..55fcdc0 --- /dev/null +++ b/mentos/inc/experimental/deadlock_simulation.h @@ -0,0 +1,11 @@ +/** + * @author Mirco De Marchi + * @date 2/02/2021 + * @brief Header file for deadlock deterministic simulation. + * @copyright (c) University of Verona + */ + +#pragma once + +/// @brief Deadlock deterministic simulation start function. +void deadlock_simulation(); diff --git a/mentos/inc/experimental/math/arr_math.h b/mentos/inc/experimental/math/arr_math.h new file mode 100644 index 0000000..2c91809 --- /dev/null +++ b/mentos/inc/experimental/math/arr_math.h @@ -0,0 +1,150 @@ +/// MentOS, The Mentoring Operating system project +/// @file arr_math.h +/// @brief Array arithmetic operations source file- +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdio.h" +#include "stdlib.h" +#include "stdio.h" +#include "stdint.h" +#include "stdbool.h" + +/// @brief Initialize all memory cells of destination array with a value. +/// @param dst Pointer of destination array. +/// @param value Value to use for array inizialization. +/// @param length Length of destination array. +/// @return The pointer of the destination array. +uint32_t *all(uint32_t *dst, uint32_t value, size_t length); + +/// @brief Element wise array subtraction. +/// @param left Pointer of left operator and destination array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return The pointer of the destination array. +/// E.g. [4, 5, 6] - [1, 2, 3] = [3, 3, 3] +uint32_t *arr_sub(uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Element wise array addition. +/// @param left Pointer of left operator and destination array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return The pointer of the destination array. +/// E.g. [4, 5, 6] + [1, 2, 3] = [5, 7, 9] +uint32_t *arr_add(uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if at least one element of an array is greater than another +/// array in relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if there is an element of the left array greater than the +/// respective right one, otherwise false. +/// E.g. [1, 1, 6] g_any [1, 2, 3] = true +/// [1, 1, 3] g_any [1, 2, 3] = false +bool_t arr_g_any(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if at least one element of an array is greater or equal than +/// another array in relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if there is an element of the left array greater or equal than +/// the respective right one, otherwise false. +/// E.g. [1, 1, 6] ge_any [1, 2, 3] = true +/// [0, 1, 3] ge_any [1, 2, 3] = true +/// [0, 1, 2] ge_any [1, 2, 3] = false +bool_t arr_ge_any(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if at least one element of an array is less than another +/// array in relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if there is an element of the left array less than the +/// respective right one, otherwise false. +/// E.g. [1, 2, 3] l_any [1, 1, 6] = true +/// [1, 2, 3] l_any [0, 1, 3] = false +bool_t arr_l_any(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if at least one element of an array is less or equal than +/// another array in relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if there is an element of the left array less or equal than +/// the respective right one, otherwise false. +/// E.g. [1, 2, 3] le_any [1, 1, 6] = true +/// [1, 2, 3] le_any [0, 1, 3] = true +/// [1, 2, 3] le_any [0, 1, 2] = false +bool_t arr_le_any(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if each element of an array is greater than another array in +/// relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if all elements of the left array are greater than the +/// respective right one, otherwise false. +/// E.g. [2, 3, 4] g_all [1, 2, 3] = true +/// [2, 3, 3] g_all [1, 2, 3] = false +bool_t arr_g(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if each element of an array is greater or equal than another +/// array in relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if all elements of the left array are greater or equal than the +/// respective right one, otherwise false. +/// E.g. [2, 3, 4] ge_all [1, 2, 3] = true +/// [2, 3, 3] ge_all [1, 2, 3] = true +/// [2, 3, 3] ge_all [1, 2, 4] = false +bool_t arr_ge(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if each element of an array is less than another array in +/// relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if all elements of the left array are less than the +/// respective right one, otherwise false. +/// E.g. [1, 2, 3] l_all [2, 3, 4] = true +/// [1, 2, 3] l_all [2, 3, 3] = false +bool_t arr_l(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if each element of an array is less or equal than another +/// array in relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if all elements of the left array are less or equal than the +/// respective right one, otherwise false. +/// E.g. [1, 2, 3] le_all [2, 3, 4] = true +/// [1, 2, 3] le_all [2, 3, 3] = true +/// [1, 2, 4] le_all [2, 3, 3] = false +bool_t arr_le(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if each element of an array is equal than another array in +/// relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if all elements of the left array are equal than the respective +/// right one, otherwise false. +/// E.g. [1, 2, 3] e_all [1, 2, 3] = true +/// [1, 2, 3] e_all [1, 2, 1] = false +bool_t arr_e(const uint32_t *left, const uint32_t *right, size_t length); + +/// @brief Check if at least one element of an array is not equal than another +/// array in relation to the respective index. +/// @param left Pointer of left operator array. +/// @param right Pointer of right operator array. +/// @param length Length of arrays. +/// @return True if there is an element of the left array not equal than the +/// respective right one, otherwise false. +/// E.g. [1, 2, 3] e_all [1, 2, 1] = true +/// [1, 2, 3] e_all [1, 2, 3] = false +bool_t arr_ne(const uint32_t *left, const uint32_t *right, size_t length); diff --git a/mentos/inc/experimental/resource.h b/mentos/inc/experimental/resource.h new file mode 100644 index 0000000..125f959 --- /dev/null +++ b/mentos/inc/experimental/resource.h @@ -0,0 +1,111 @@ +/// MentOS, The Mentoring Operating system project +/// @file resource.h +/// @brief Resource definition header code. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "process.h" +#include "stdint.h" +#include "types.h" +#include "list_head.h" + +/// @brief Resource descriptor. +typedef struct resource { + /// Resource index. The resources indexes has to be continuous: 0, 1, ... M. + size_t rid; + + /// List head for tasks that share this resource. + list_head resources_list; + + /// Number of instances of this resource. For now, always 1. + size_t n_instances; + + /// The category of the resource (added for debug purpose). + const char *category; + + /// If the resource has been assigned, it points to the task assigned, + /// otherwise NULL. + task_struct *assigned_task; + + /// Number of instances assigned to assigned task. + size_t assigned_instances; + +} resource_t; + +/// @brief Structure that maintains information about resources currently +/// allocated in the system. +typedef struct resource_list { + /// Number of queued resources. + size_t num_active; + + /// Head of resources. + list_head head; +} resource_list_t; + +/// @brief Number of instances of each resources currently available. +extern uint32_t * available; +/// @brief Matrix of maximum resources instances that each task may need. +extern uint32_t ** max; +/// @brief Matrix of current resource allocation for each task. +extern uint32_t ** alloc; +/// @brief Matrix of current resource needs for each task. +/// need[i][j] = max[i][j] - alloc[i][j] +extern uint32_t ** need; + +/// @brief Resource creation. +/// @param category Resource category string, used to group resources. +/// @return The pointer to the resource created. +resource_t *resource_create(const char *category); + +/// @brief Resource initialization. +/// @param r Pointer to a resource created. +void resource_init(resource_t *r); + +/// @brief Resource destruction. +/// @param r Pointer to a resource created. +void resource_destroy(resource_t *r); + +/// @brief Assign the ownership of a resource to the current calling task. +/// @param r Pointer to a resource created. +void resource_assign(resource_t *r); + +/// @brief Remove the ownership of a resource from the current calling task. +/// @param r Pointer to a resource created. +void resource_deassign(resource_t *r); + +/// @brief Initialize deadlock prevention structures. +/// @param available Array of resources instances currently available; +/// @param max Matrix of the maximum resources instances that each +/// task may require; +/// @param alloc Matrix of current resources instances allocation of +/// each task. +/// @param need Matrix of current resources instances need of each task. +/// @param idx_map_task_struct Pointer to the array of index and tasks mapping. +void init_deadlock_structures(uint32_t *available, uint32_t **max, + uint32_t **alloc, uint32_t **need, + task_struct *idx_map_task_struct[]); + +/// @brief Reset to zero deadlock prevention structures. +/// @param available Array of resources instances currently available; +/// @param max Matrix of the maximum resources instances that each +/// task may require; +/// @param alloc Matrix of current resources instances allocation of +/// each task. +/// @param idx_map_task_struct Pointer to the array of index and tasks mapping. +/// There is no need to reset the need matrix because it has to be calculated +/// starting from max matrix, which is clean. +void reset_deadlock_structures(uint32_t *available, uint32_t **max, + uint32_t **alloc, task_struct *idx_map_task_struct[]); + +/// @brief Get the number of total resources allocated in the system. +/// @return The number of resources. +size_t kernel_get_active_resources(); + +/// @brief Return the index of the current task contained in the array of index +/// and processes mapping. +/// @param idx_map_task_struct Pointer to the array of index and tasks mapping. +/// @return The index that maps with the current task in the +/// idx_map_task_struct array, or -1 if not found the mapping task. +int32_t get_current_task_idx_from(task_struct *idx_map_task_struct[]); diff --git a/mentos/inc/experimental/smart_sem_kernel.h b/mentos/inc/experimental/smart_sem_kernel.h new file mode 100644 index 0000000..052e893 --- /dev/null +++ b/mentos/inc/experimental/smart_sem_kernel.h @@ -0,0 +1,37 @@ +/// MentOS, The Mentoring Operating system project +/// @file smart_sem_kernel.h +/// @brief Smart semaphore semaphore kernel-side implementation header code. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. +/// N.B. Header to use only in kernel space. + +#pragma once + +#include "stdatomic.h" + +/// @brief Smart semaphore creation. +/// @return The semaphore id or -1 if creation failed. +int sys_sem_create(); + +/// @brief Destruction of a created smart semaphore. +/// @param id Smart semaphore ID. +/// @return Return -1 if destroy failed, otherwise 0. +int sys_sem_destroy(int id); + +/// @brief Initialization of a created smart semaphore. +/// @param id Smart semaphore ID. +/// @return Return -1 if initialization failed, otherwise 0. +int sys_sem_init(int id); + +/// @brief Tries a safety acquisition of a smart semaphore identified by +/// an ID and, if available, takes the ownership. +/// @param id Smart semaphore ID. +/// @return Return -1 if creation failed, return 0 if semaphore busy or +/// the acquisition is unsafe, otherwise return 1 if semaphore has been +/// acquired. +int sys_sem_try_acquire(int id); + +/// @brief Release the ownership of a smart semaphore. +/// @param id Smart semaphore ID. +/// @return Return -1 if release failed, otherwise 0. +int sys_sem_release(int id); diff --git a/mentos/inc/experimental/smart_sem_user.h b/mentos/inc/experimental/smart_sem_user.h new file mode 100644 index 0000000..8f70af3 --- /dev/null +++ b/mentos/inc/experimental/smart_sem_user.h @@ -0,0 +1,35 @@ +/// MentOS, The Mentoring Operating system project +/// @file smart_sem_user.h +/// @brief Semaphore user-side implementation header code. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. +/// N.B. Header to use only in user space. + +#pragma once + +/// @brief Semaphore creation. +/// @return The semaphore id or -1 if creation failed. +/// Set the errno code if failed. +int sem_create(); + +/// @brief Destruction of a created semaphore. +/// @param id Semaphore ID. +/// @return Return -1 and set errno if destroy failed, otherwise 0. +int sem_destroy(int id); + +/// @brief Initialization of a created semaphore. +/// @param id Semaphore ID. +/// @return Return -1 and set errno if initialization failed, otherwise 0. +int sem_init(int id); + +/// @brief Acquire the semaphore ownership if available, otherwise waits that +/// becomes available. +/// @param id Semaphore ID. +/// @return Return -1 and set errno if creation failed, otherwise 0 if +/// semaphore has been successfully acquired. +int sem_acquire(int id); + +/// @brief Release the ownership of a Semaphore. +/// @param id Semaphore ID. +/// @return Return -1 and set errno if release failed, otherwise 0. +int sem_release(int id); diff --git a/mentos/inc/fs/fcntl.h b/mentos/inc/fs/fcntl.h index 7c8a835..cea8624 100644 --- a/mentos/inc/fs/fcntl.h +++ b/mentos/inc/fs/fcntl.h @@ -1,26 +1,26 @@ -/// MentOS, The Mentoring Operating system project -/// @file fcntl.h -/// @brief Headers of functions fcntl() and open(). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" - -/// Open for reading only. -#define O_RDONLY 0x00 -/// Open for writing only. -#define O_WRONLY 0x01 -/// Open for reading and writing. -#define O_RDWR 0x02 -/// If the file exists, this flag has no effect. Otherwise, the file is created. -#define O_CREAT 0x40 -/// The file offset will be set to the end of the file prior to each write. -#define O_APPEND 0x400 - -/// @brief Deletes the file whose name is specified in filename. -/// @param pathname A path to a file. -/// @return On success, zero is returned. On error, -1 is returned, -/// and errno is set appropriately. -int remove(const char *pathname); +/// MentOS, The Mentoring Operating system project +/// @file fcntl.h +/// @brief Headers of functions fcntl() and open(). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" + +/// Open for reading only. +#define O_RDONLY 0x00 +/// Open for writing only. +#define O_WRONLY 0x01 +/// Open for reading and writing. +#define O_RDWR 0x02 +/// If the file exists, this flag has no effect. Otherwise, the file is created. +#define O_CREAT 0x40 +/// The file offset will be set to the end of the file prior to each write. +#define O_APPEND 0x400 + +/// @brief Deletes the file whose name is specified in filename. +/// @param pathname A path to a file. +/// @return On success, zero is returned. On error, -1 is returned, +/// and errno is set appropriately. +int remove(const char *pathname); diff --git a/mentos/inc/fs/initrd.h b/mentos/inc/fs/initrd.h index e5111d3..bef790f 100644 --- a/mentos/inc/fs/initrd.h +++ b/mentos/inc/fs/initrd.h @@ -1,131 +1,131 @@ -/// MentOS, The Mentoring Operating system project -/// @file initrd.h -/// @brief Headers of functions for initrd filesystem. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stat.h" -#include "dirent.h" -#include "unistd.h" -#include "stdint.h" -#include "kernel.h" - -/// The maximum number of files. -#define MAX_FILES 32 - -/// The maximum number of file descriptors. -#define MAX_INITRD_DESCRIPTORS MAX_OPEN_FD - -/// @brief Contains the number of files inside the initrd filesystem. -typedef struct initrd_t { - /// Number of files. - uint32_t nfiles; -} initrd_t; - -/// @brief Information concerning a file. -typedef struct initrd_file_t { - /// Number used as delimiter, it must be set to 0xBF. - int magic; - /// The name of the file. - char fileName[NAME_MAX]; - /// The type of the file. - short int file_type; - /// The uid of the owner. - int uid; - /// Offset of the starting address. - unsigned int offset; - /// Dimension of the file. - unsigned int length; -} initrd_file_t; - -/// @brief Descriptor linked to open files. -typedef struct initrd_fd { - /// Id of the open file inside the file system. More precisely, its index - /// inside the vector of files. - int file_descriptor; - /// The current position inside the file. Used for writing/reading - /// opeations. - int cur_pos; -} initrd_fd; - -// TODO: doxygen comment. -/// @brief -extern initrd_t *fs_specs; -/// @brief File system headers. -extern initrd_file_t *fs_headers; -// TODO: doxygen comment. -/// @brief -extern unsigned int fs_end; - -/// Initializes the initrd file system. -uint32_t initfs_init(); - -/// @brief Opens a directory at the given path. -/// @param path The path where the directory resides. -/// @return Structure used to access the directory. -DIR *initfs_opendir(const char *path); - -/// @brief Closes the directory stream associated with dirp. -/// @param dirp The directory handler. -/// @return 0 on success. On error, -1 is returned, and errno is set. -int initfs_closedir(DIR *dirp); - -/// @brief Moves the position of the currently readed entry inside the -/// directory. -/// @param dirp The directory handler. -/// @return A pointer to the next entry inside the directory. -dirent_t *initrd_readdir(DIR *dirp); - -/// @brief Creates a new directory. -/// @param path The path to the new directory. -/// @param mode The file mode. -/// @return 0 if success. -int initrd_mkdir(const char *path, mode_t mode); - -/// @brief Removes a directory. -/// @param path The path to the directory. -/// @return 0 if success. -int initrd_rmdir(const char *path); - -/// @brief Open the file at the given path and returns its file descriptor. -/// @param path The path to the file. -/// @param flags The flags used to determine the behavior of the function. -/// @return The file descriptor of the opened file, otherwise returns -1. -int initfs_open(const char *path, int flags, ...); - -/// @brief Deletes the file at the given path. -/// @param path The path to the file. -/// @return On success, zero is returned. On error, -1 is returned. -int initfs_remove(const char *path); - -/// @brief Reads from the file identified by the file descriptor. -/// @param fildes The file descriptor of the file. -/// @param buf Buffer where the read content must be placed. -/// @param nbyte The number of bytes to read. -/// @return T The number of red bytes. -ssize_t initfs_read(int fildes, char *buf, size_t nbyte); - -/// @brief Retrieves information concerning the file at the given position. -/// @param path The path where the file resides. -/// @param stat The structure where the information are stored. -/// @return 0 if success. -int initrd_stat(const char *path, stat_t *stat); - -/// @brief Writes the given content inside the file. -/// @param fildes The file descriptor of the file. -/// @param buf The content to write. -/// @param nbyte The number of bytes to write. -/// @return T The number of written bytes. -ssize_t initrd_write(int fildes, const void *buf, size_t nbyte); - -/// @brief Closes the given file. -/// @param fildes The file descriptor of the file. -int initrd_close(int fildes); - -// TODO: doxygen comment. -size_t initrd_nfiles(); - -// TODO: doxygen comment. -void dump_initrd_fs(); +/// MentOS, The Mentoring Operating system project +/// @file initrd.h +/// @brief Headers of functions for initrd filesystem. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stat.h" +#include "dirent.h" +#include "unistd.h" +#include "stdint.h" +#include "kernel.h" + +/// The maximum number of files. +#define MAX_FILES 32 + +/// The maximum number of file descriptors. +#define MAX_INITRD_DESCRIPTORS MAX_OPEN_FD + +/// @brief Contains the number of files inside the initrd filesystem. +typedef struct initrd_t { + /// Number of files. + uint32_t nfiles; +} initrd_t; + +/// @brief Information concerning a file. +typedef struct initrd_file_t { + /// Number used as delimiter, it must be set to 0xBF. + int magic; + /// The name of the file. + char fileName[NAME_MAX]; + /// The type of the file. + short int file_type; + /// The uid of the owner. + int uid; + /// Offset of the starting address. + unsigned int offset; + /// Dimension of the file. + unsigned int length; +} initrd_file_t; + +/// @brief Descriptor linked to open files. +typedef struct initrd_fd { + /// Id of the open file inside the file system. More precisely, its index + /// inside the vector of files. + int file_descriptor; + /// The current position inside the file. Used for writing/reading + /// opeations. + int cur_pos; +} initrd_fd; + +// TODO: doxygen comment. +/// @brief +extern initrd_t *fs_specs; +/// @brief File system headers. +extern initrd_file_t *fs_headers; +// TODO: doxygen comment. +/// @brief +extern unsigned int fs_end; + +/// Initializes the initrd file system. +uint32_t initfs_init(); + +/// @brief Opens a directory at the given path. +/// @param path The path where the directory resides. +/// @return Structure used to access the directory. +DIR *initfs_opendir(const char *path); + +/// @brief Closes the directory stream associated with dirp. +/// @param dirp The directory handler. +/// @return 0 on success. On error, -1 is returned, and errno is set. +int initfs_closedir(DIR *dirp); + +/// @brief Moves the position of the currently readed entry inside the +/// directory. +/// @param dirp The directory handler. +/// @return A pointer to the next entry inside the directory. +dirent_t *initrd_readdir(DIR *dirp); + +/// @brief Creates a new directory. +/// @param path The path to the new directory. +/// @param mode The file mode. +/// @return 0 if success. +int initrd_mkdir(const char *path, mode_t mode); + +/// @brief Removes a directory. +/// @param path The path to the directory. +/// @return 0 if success. +int initrd_rmdir(const char *path); + +/// @brief Open the file at the given path and returns its file descriptor. +/// @param path The path to the file. +/// @param flags The flags used to determine the behavior of the function. +/// @return The file descriptor of the opened file, otherwise returns -1. +int initfs_open(const char *path, int flags, ...); + +/// @brief Deletes the file at the given path. +/// @param path The path to the file. +/// @return On success, zero is returned. On error, -1 is returned. +int initfs_remove(const char *path); + +/// @brief Reads from the file identified by the file descriptor. +/// @param fildes The file descriptor of the file. +/// @param buf Buffer where the read content must be placed. +/// @param nbyte The number of bytes to read. +/// @return T The number of red bytes. +ssize_t initfs_read(int fildes, char *buf, size_t nbyte); + +/// @brief Retrieves information concerning the file at the given position. +/// @param path The path where the file resides. +/// @param stat The structure where the information are stored. +/// @return 0 if success. +int initrd_stat(const char *path, stat_t *stat); + +/// @brief Writes the given content inside the file. +/// @param fildes The file descriptor of the file. +/// @param buf The content to write. +/// @param nbyte The number of bytes to write. +/// @return T The number of written bytes. +ssize_t initrd_write(int fildes, const void *buf, size_t nbyte); + +/// @brief Closes the given file. +/// @param fildes The file descriptor of the file. +int initrd_close(int fildes); + +// TODO: doxygen comment. +size_t initrd_nfiles(); + +// TODO: doxygen comment. +void dump_initrd_fs(); diff --git a/mentos/inc/fs/vfs.h b/mentos/inc/fs/vfs.h index 360ebec..720b6a0 100644 --- a/mentos/inc/fs/vfs.h +++ b/mentos/inc/fs/vfs.h @@ -1,52 +1,52 @@ -/// MentOS, The Mentoring Operating system project -/// @file vfs.h -/// @brief Headers for Virtual File System (VFS). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "unistd.h" -#include "vfs_types.h" - -/// The maximum number of mount points. -#define MAX_MOUNTPOINT 10 - -/// The currently opened file descriptor. -extern int current_fd; - -/// The list of file descriptors. -extern file_descriptor_t fd_list[MAX_OPEN_FD]; - -/// The list of mount points. -extern mountpoint_t mountpoint_list[MAX_MOUNTPOINT]; - -/// @brief Initialize the Virtual File System (VFS). -void vfs_init(); - -/// @brief Retrieves the id of the mount point where the path resides. -/// @param path The path to the mountpoint. -/// @return The id of the mountpoint. -int32_t get_mountpoint_id(const char *path); - -// TODO: doxigen comment. -mountpoint_t * get_mountpoint(const char *path); - -// TODO: doxigen comment. -mountpoint_t * get_mountpoint_from_id(int32_t mp_id); - -/// @brief A path is extracted from the relative path, excluding the -/// mountpoint. -/// @param mp_id Id of the mountpoint point of the file. -/// @param path Path to the file to be opened. -/// @return Path without the mountpoint part. -int get_relative_path(uint32_t mp_id, char *path); - -/// @brief Given a path, it extracts its absolute path (starting from -/// the current one). -/// @param path Path to the file to be opened. -/// @return Error code. -int get_absolute_path(char *path); - -/// @brief Dumps the list of file descriptors. -void vfs_dump(); +/// MentOS, The Mentoring Operating system project +/// @file vfs.h +/// @brief Headers for Virtual File System (VFS). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "unistd.h" +#include "vfs_types.h" + +/// The maximum number of mount points. +#define MAX_MOUNTPOINT 10 + +/// The currently opened file descriptor. +extern int current_fd; + +/// The list of file descriptors. +extern file_descriptor_t fd_list[MAX_OPEN_FD]; + +/// The list of mount points. +extern mountpoint_t mountpoint_list[MAX_MOUNTPOINT]; + +/// @brief Initialize the Virtual File System (VFS). +void vfs_init(); + +/// @brief Retrieves the id of the mount point where the path resides. +/// @param path The path to the mountpoint. +/// @return The id of the mountpoint. +int32_t get_mountpoint_id(const char *path); + +// TODO: doxigen comment. +mountpoint_t * get_mountpoint(const char *path); + +// TODO: doxigen comment. +mountpoint_t * get_mountpoint_from_id(int32_t mp_id); + +/// @brief A path is extracted from the relative path, excluding the +/// mountpoint. +/// @param mp_id Id of the mountpoint point of the file. +/// @param path Path to the file to be opened. +/// @return Path without the mountpoint part. +int get_relative_path(uint32_t mp_id, char *path); + +/// @brief Given a path, it extracts its absolute path (starting from +/// the current one). +/// @param path Path to the file to be opened. +/// @return Error code. +int get_absolute_path(char *path); + +/// @brief Dumps the list of file descriptors. +void vfs_dump(); diff --git a/mentos/inc/fs/vfs_types.h b/mentos/inc/fs/vfs_types.h index dbbb06e..ab7ac23 100644 --- a/mentos/inc/fs/vfs_types.h +++ b/mentos/inc/fs/vfs_types.h @@ -1,136 +1,136 @@ -/// MentOS, The Mentoring Operating system project -/// @file vfs_types.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stat.h" -#include "kernel.h" -#include "dirent.h" - -#define PATH_SEPARATOR '/' -#define PATH_SEPARATOR_STRING "/" -#define PATH_UP ".." -#define PATH_DOT "." - -/// Identifies a file. -#define FS_FILE 0x01U -/// Identifies a directory. -#define FS_DIRECTORY 0x02U -/// Identifies a character devies. -#define FS_CHARDEVICE 0x04U -/// Identifies a block devies. -#define FS_BLOCKDEVICE 0x08U -/// Identifies a pipe. -#define FS_PIPE 0x10U -/// Identifies a symbolic link. -#define FS_SYMLINK 0x20U -/// Identifies a mount-point. -#define FS_MOUNTPOINT 0x40U - -/// Function used to open a directory. -typedef DIR *(*opendir_callback)(const char *); - -/// Function used to close a directory. -typedef int (*closedir_callback)(DIR *); - -/// Function used to create a directory. -typedef int (*mkdir_callback)(const char *, mode_t); - -/// Function used to remove a directory. -typedef int (*rmdir_callback)(const char *); - -/// Function used to read the next entry of a directory. -typedef dirent_t *(*readdir_callback)(DIR *); - -/// Function used to open a file. -typedef int (*open_callback)(const char *, int, ...); - -/// Function used to remove a file. -typedef int (*remove_callback)(const char *); - -/// Function used to close a file. -typedef int (*close_callback)(int); - -/// Function used to read from a file. -typedef ssize_t (*read_callback)(int, char *, size_t); - -/// Function used to write inside a file. -typedef ssize_t (*write_callback)(int, const void *, size_t); - -/// Function used to stat fs entries. -typedef int (*stat_callback)(const char *, stat_t *); - -/// @brief Set of functions used to perform operations on directories. -typedef struct directory_operations_t { - /// Identifies a mount-point. - opendir_callback opendir_f; - /// Closes a directory. - closedir_callback closedir_f; - /// Creates a directory. - mkdir_callback mkdir_f; - /// Removes a directory. - rmdir_callback rmdir_f; - /// Read next entry inside the directory. - readdir_callback readdir_f; -} directory_operations_t; - -/// @brief Set of functions used to perform operations on files. -typedef struct super_node_operations_t { - /// Open a file. - open_callback open_f; - /// Remove a file. - remove_callback remove_f; - /// Close a file. - close_callback close_f; - /// Read from a file. - read_callback read_f; - /// Write inside a file. - write_callback write_f; -} super_node_operations_t; - -/// @brief Stat operations. -typedef struct stat_operations_t { - /// Stat function. - stat_callback stat_f; -} stat_operations_t; - -/// @brief Data structure that contains information about the mounted filesystems. -typedef struct mountpoint_t { - /// The id of the mountpoint. - int32_t mp_id; - /// Name of the mountpoint. - char mountpoint[NAME_MAX]; - /// Maschera dei permessi. - unsigned int pmask; - /// User ID. - unsigned int uid; - /// Group ID. - unsigned int gid; - /// Starting address of the FileSystem. - unsigned int start_address; - /// Ending address of the FileSystem. - unsigned int end_address; - /// Device ID. - int dev_id; - /// Operations on files. - super_node_operations_t operations; - /// Operations on directories. - directory_operations_t dir_op; - /// Stat operations. - stat_operations_t stat_op; -} mountpoint_t; - -/// @brief Data structure containing information about an open file. -typedef struct file_descriptor_t { - /// The descriptor of the internal file of the FileSystem. - int fs_spec_id; - /// The id of the mountpoint where the. - int mountpoint_id; - /// Offset for file reading, for the next read. - int offset; - /// Flags for file opening modes. - int flags_mask; -} file_descriptor_t; +/// MentOS, The Mentoring Operating system project +/// @file vfs_types.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stat.h" +#include "kernel.h" +#include "dirent.h" + +#define PATH_SEPARATOR '/' +#define PATH_SEPARATOR_STRING "/" +#define PATH_UP ".." +#define PATH_DOT "." + +/// Identifies a file. +#define FS_FILE 0x01U +/// Identifies a directory. +#define FS_DIRECTORY 0x02U +/// Identifies a character devies. +#define FS_CHARDEVICE 0x04U +/// Identifies a block devies. +#define FS_BLOCKDEVICE 0x08U +/// Identifies a pipe. +#define FS_PIPE 0x10U +/// Identifies a symbolic link. +#define FS_SYMLINK 0x20U +/// Identifies a mount-point. +#define FS_MOUNTPOINT 0x40U + +/// Function used to open a directory. +typedef DIR *(*opendir_callback)(const char *); + +/// Function used to close a directory. +typedef int (*closedir_callback)(DIR *); + +/// Function used to create a directory. +typedef int (*mkdir_callback)(const char *, mode_t); + +/// Function used to remove a directory. +typedef int (*rmdir_callback)(const char *); + +/// Function used to read the next entry of a directory. +typedef dirent_t *(*readdir_callback)(DIR *); + +/// Function used to open a file. +typedef int (*open_callback)(const char *, int, ...); + +/// Function used to remove a file. +typedef int (*remove_callback)(const char *); + +/// Function used to close a file. +typedef int (*close_callback)(int); + +/// Function used to read from a file. +typedef ssize_t (*read_callback)(int, char *, size_t); + +/// Function used to write inside a file. +typedef ssize_t (*write_callback)(int, const void *, size_t); + +/// Function used to stat fs entries. +typedef int (*stat_callback)(const char *, stat_t *); + +/// @brief Set of functions used to perform operations on directories. +typedef struct directory_operations_t { + /// Identifies a mount-point. + opendir_callback opendir_f; + /// Closes a directory. + closedir_callback closedir_f; + /// Creates a directory. + mkdir_callback mkdir_f; + /// Removes a directory. + rmdir_callback rmdir_f; + /// Read next entry inside the directory. + readdir_callback readdir_f; +} directory_operations_t; + +/// @brief Set of functions used to perform operations on files. +typedef struct super_node_operations_t { + /// Open a file. + open_callback open_f; + /// Remove a file. + remove_callback remove_f; + /// Close a file. + close_callback close_f; + /// Read from a file. + read_callback read_f; + /// Write inside a file. + write_callback write_f; +} super_node_operations_t; + +/// @brief Stat operations. +typedef struct stat_operations_t { + /// Stat function. + stat_callback stat_f; +} stat_operations_t; + +/// @brief Data structure that contains information about the mounted filesystems. +typedef struct mountpoint_t { + /// The id of the mountpoint. + int32_t mp_id; + /// Name of the mountpoint. + char mountpoint[NAME_MAX]; + /// Maschera dei permessi. + unsigned int pmask; + /// User ID. + unsigned int uid; + /// Group ID. + unsigned int gid; + /// Starting address of the FileSystem. + unsigned int start_address; + /// Ending address of the FileSystem. + unsigned int end_address; + /// Device ID. + int dev_id; + /// Operations on files. + super_node_operations_t operations; + /// Operations on directories. + directory_operations_t dir_op; + /// Stat operations. + stat_operations_t stat_op; +} mountpoint_t; + +/// @brief Data structure containing information about an open file. +typedef struct file_descriptor_t { + /// The descriptor of the internal file of the FileSystem. + int fs_spec_id; + /// The id of the mountpoint where the. + int mountpoint_id; + /// Offset for file reading, for the next read. + int offset; + /// Flags for file opening modes. + int flags_mask; +} file_descriptor_t; diff --git a/mentos/inc/hardware/cmd_cpuid.h b/mentos/inc/hardware/cmd_cpuid.h index 742a698..c2daf9b 100644 --- a/mentos/inc/hardware/cmd_cpuid.h +++ b/mentos/inc/hardware/cmd_cpuid.h @@ -1,86 +1,86 @@ -/// MentOS, The Mentoring Operating system project -/// @file cpuid.h -/// @brief CPUID definitions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" -#include "stdint.h" -#include "kernel.h" - -/// Dimension of the exc flags. -#define ECX_FLAGS_SIZE 24 - -/// Dimension of the edx flags. -#define EDX_FLAGS_SIZE 32 - -/// @brief Contains the information concerning the CPU. -typedef struct cpuinfo_t { - /// The name of the vendor. - char cpu_vendor[13]; - /// The type of the CPU. - char *cpu_type; - /// The family of the CPU. - uint32_t cpu_family; - /// The model of the CPU. - uint32_t cpu_model; - /// Identifier for individual cores when the CPU is interrogated by the - /// CPUID instruction. - uint32_t apic_id; - /// Ecx flags. - uint32_t cpuid_ecx_flags[ECX_FLAGS_SIZE]; - /// Edx flags. - uint32_t cpuid_edx_flags[EDX_FLAGS_SIZE]; - // TODO: doxygen comment. - int is_brand_string; - // TODO: doxygen comment. - char *brand_string; -} cpuinfo_t; - -/// This will be populated with the information concerning the CPU. -cpuinfo_t sinfo; - -/// @brief Main CPUID procedure. -/// @param cpuinfo Structure to fill with CPUID information. -void get_cpuid(cpuinfo_t *cpuinfo); - -/// @brief Actual CPUID call. -/// @param registers The registers to fill with the result of the call. -void call_cpuid(register_t *registers); - -/// @brief Extract vendor string. -/// @param cpuinfo The struct containing the CPUID infos. -/// @param registers The registers. -void cpuid_write_vendor(cpuinfo_t *cpuinfo, register_t *registers); - -// TODO: doxygen documentation. -/// @brief CPUID is called with EAX=1 -/// EAX contains Type, Family, Model and Stepping ID -/// EBX contains the Brand Index if supported, and the APIC ID -/// ECX/EDX contains feature information -/// @param cpuinfo -/// @param registers -void cpuid_write_proctype(cpuinfo_t *cpuinfo, register_t *registers); - -/// @brief EAX=1, ECX contains a list of supported features. -void cpuid_feature_ecx(cpuinfo_t *, uint32_t); - -/// @brief EAX=1, EDX contains a list of supported features. -void cpuid_feature_edx(cpuinfo_t *, uint32_t); - -// TODO: doxygen documentation. -/// @brief Extract single byte from a register. -/// @param reg -/// @param position -/// @param value -/// @return -uint32_t cpuid_get_byte(const uint32_t reg, const uint32_t position, - const uint32_t value); - -/// @brief Index of brand strings. -char *cpuid_brand_index(register_t *); - -/// @brief Brand string is contained in EAX, EBX, ECX and EDX. -char *cpuid_brand_string(register_t *); +/// MentOS, The Mentoring Operating system project +/// @file cpuid.h +/// @brief CPUID definitions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" +#include "stdint.h" +#include "kernel.h" + +/// Dimension of the exc flags. +#define ECX_FLAGS_SIZE 24 + +/// Dimension of the edx flags. +#define EDX_FLAGS_SIZE 32 + +/// @brief Contains the information concerning the CPU. +typedef struct cpuinfo_t { + /// The name of the vendor. + char cpu_vendor[13]; + /// The type of the CPU. + char *cpu_type; + /// The family of the CPU. + uint32_t cpu_family; + /// The model of the CPU. + uint32_t cpu_model; + /// Identifier for individual cores when the CPU is interrogated by the + /// CPUID instruction. + uint32_t apic_id; + /// Ecx flags. + uint32_t cpuid_ecx_flags[ECX_FLAGS_SIZE]; + /// Edx flags. + uint32_t cpuid_edx_flags[EDX_FLAGS_SIZE]; + // TODO: doxygen comment. + int is_brand_string; + // TODO: doxygen comment. + char *brand_string; +} cpuinfo_t; + +/// This will be populated with the information concerning the CPU. +cpuinfo_t sinfo; + +/// @brief Main CPUID procedure. +/// @param cpuinfo Structure to fill with CPUID information. +void get_cpuid(cpuinfo_t *cpuinfo); + +/// @brief Actual CPUID call. +/// @param registers The registers to fill with the result of the call. +void call_cpuid(register_t *registers); + +/// @brief Extract vendor string. +/// @param cpuinfo The struct containing the CPUID infos. +/// @param registers The registers. +void cpuid_write_vendor(cpuinfo_t *cpuinfo, register_t *registers); + +// TODO: doxygen documentation. +/// @brief CPUID is called with EAX=1 +/// EAX contains Type, Family, Model and Stepping ID +/// EBX contains the Brand Index if supported, and the APIC ID +/// ECX/EDX contains feature information +/// @param cpuinfo +/// @param registers +void cpuid_write_proctype(cpuinfo_t *cpuinfo, register_t *registers); + +/// @brief EAX=1, ECX contains a list of supported features. +void cpuid_feature_ecx(cpuinfo_t *, uint32_t); + +/// @brief EAX=1, EDX contains a list of supported features. +void cpuid_feature_edx(cpuinfo_t *, uint32_t); + +// TODO: doxygen documentation. +/// @brief Extract single byte from a register. +/// @param reg +/// @param position +/// @param value +/// @return +uint32_t cpuid_get_byte(const uint32_t reg, const uint32_t position, + const uint32_t value); + +/// @brief Index of brand strings. +char *cpuid_brand_index(register_t *); + +/// @brief Brand string is contained in EAX, EBX, ECX and EDX. +char *cpuid_brand_string(register_t *); diff --git a/mentos/inc/hardware/pic8259.h b/mentos/inc/hardware/pic8259.h index 7d409c8..c73fc2b 100644 --- a/mentos/inc/hardware/pic8259.h +++ b/mentos/inc/hardware/pic8259.h @@ -1,110 +1,110 @@ -/// MentOS, The Mentoring Operating system project -/// @file pic8259.h -/// @brief Pic8259 definitions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "idt.h" -#include "kheap.h" -#include "debug.h" -#include "stddef.h" -#include "kernel.h" -#include "bitops.h" -#include "port_io.h" -#include "irqflags.h" -#include "scheduler.h" - -/// The total number of IRQs. -#define IRQ_NUM 16 - -/// @defgroup irqs Interrupt Requests (IRQs). -/// @brief This is the list of interrupt requests. -/// @{ - -/// @brief System timer. -#define IRQ_TIMER 0 - -/// @brief Keyboard controller. -#define IRQ_KEYBOARD 1 - -/// @brief cascaded signals from IRQs 8–15 (any devices configured to use IRQ -/// 2 will actually be using IRQ 9) -#define IRQ_TO_SLAVE_PIC 2 - -/// @brief Serial port controller for serial port 2 (and 4). -#define IRQ_COM2_4 3 - -/// @brief Serial port controller for serial port 1 (and 3). -#define IRQ_COM1_3 4 - -/// @brief Parallel port 2 and 3 (or sound card). -#define IRQ_LPT2 5 - -/// @brief Floppy disk controller. -#define IRQ_FLOPPY 6 - -/// @brief Parallel port 1. -#define IRQ_LPT1 7 - -/// @brief Real-time clock (RTC). -#define IRQ_REAL_TIME_CLOCK 8 - -/// @brief Advanced Configuration and Power Interface (ACPI) -/// system control interrupt on Intel chipsets.[1] Other chipset -/// manufacturers might use another interrupt for this purpose, or -/// make it available for the use of peripherals (any devices configured -/// to use IRQ 2 will actually be using IRQ 9) -#define IRQ_AVAILABLE_1 9 - -/// @brief The Interrupt is left open for the use of -/// peripherals (open interrupt/available, SCSI or NIC). -#define IRQ_AVAILABLE_2 10 - -/// @brief The Interrupt is left open for the use of -/// peripherals (open interrupt/available, SCSI or NIC). -#define IRQ_AVAILABLE_3 11 - -/// @brief Mouse on PS/2 connector. -#define IRQ_MOUSE 12 - -/// @brief CPU co-processor or integrated floating point unit -/// or inter-processor interrupt (use depends on OS). -#define IRQ_MATH_CPU 13 - -/// @brief Primary ATA channel (ATA interface usually serves -/// hard disk drives and CD drives). -#define IRQ_FIRST_HD 14 - -/// @brief Secondary ATA channel. -#define IRQ_SECOND_HD 15 - -/// @} - -/// @brief Function that initializes the processor pic 8259 that will manage the -/// interruptions. -void pic8259_init_irq(); - -/// @brief This function, enable irqs on the pic. -/// @details This function provide a tool for enabling irq from the pic -/// processor. -/// @param irq Number of irq to enable. -/// @return 0 If all OK, -1 on errors. -int pic8259_irq_enable(uint32_t irq); - -/// @brief This function, disable irqs on the pic. -/// @details This function provide a tool for enabling irq from the pic -/// processor. -/// @param irq Number of irq to enable. -/// @return 0 If all OK, -1 on errors. -int pic8259_irq_disable(uint32_t irq); - -/// @brief This is issued to the PIC chips at the end of an IRQ-based -/// interrupt routine. -/// @param irq The interrupt number. -void pic8259_send_eoi(uint32_t irq); - -/// @brief This Function return the number of current IRQ Request. -/// @return Number of IRQ + 1 currently serving. If 0 there are no IRQ. -//int pic8259_irq_get_current(); +/// MentOS, The Mentoring Operating system project +/// @file pic8259.h +/// @brief Pic8259 definitions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "idt.h" +#include "kheap.h" +#include "debug.h" +#include "stddef.h" +#include "kernel.h" +#include "bitops.h" +#include "port_io.h" +#include "irqflags.h" +#include "scheduler.h" + +/// The total number of IRQs. +#define IRQ_NUM 16 + +/// @defgroup irqs Interrupt Requests (IRQs). +/// @brief This is the list of interrupt requests. +/// @{ + +/// @brief System timer. +#define IRQ_TIMER 0 + +/// @brief Keyboard controller. +#define IRQ_KEYBOARD 1 + +/// @brief cascaded signals from IRQs 8–15 (any devices configured to use IRQ +/// 2 will actually be using IRQ 9) +#define IRQ_TO_SLAVE_PIC 2 + +/// @brief Serial port controller for serial port 2 (and 4). +#define IRQ_COM2_4 3 + +/// @brief Serial port controller for serial port 1 (and 3). +#define IRQ_COM1_3 4 + +/// @brief Parallel port 2 and 3 (or sound card). +#define IRQ_LPT2 5 + +/// @brief Floppy disk controller. +#define IRQ_FLOPPY 6 + +/// @brief Parallel port 1. +#define IRQ_LPT1 7 + +/// @brief Real-time clock (RTC). +#define IRQ_REAL_TIME_CLOCK 8 + +/// @brief Advanced Configuration and Power Interface (ACPI) +/// system control interrupt on Intel chipsets.[1] Other chipset +/// manufacturers might use another interrupt for this purpose, or +/// make it available for the use of peripherals (any devices configured +/// to use IRQ 2 will actually be using IRQ 9) +#define IRQ_AVAILABLE_1 9 + +/// @brief The Interrupt is left open for the use of +/// peripherals (open interrupt/available, SCSI or NIC). +#define IRQ_AVAILABLE_2 10 + +/// @brief The Interrupt is left open for the use of +/// peripherals (open interrupt/available, SCSI or NIC). +#define IRQ_AVAILABLE_3 11 + +/// @brief Mouse on PS/2 connector. +#define IRQ_MOUSE 12 + +/// @brief CPU co-processor or integrated floating point unit +/// or inter-processor interrupt (use depends on OS). +#define IRQ_MATH_CPU 13 + +/// @brief Primary ATA channel (ATA interface usually serves +/// hard disk drives and CD drives). +#define IRQ_FIRST_HD 14 + +/// @brief Secondary ATA channel. +#define IRQ_SECOND_HD 15 + +/// @} + +/// @brief Function that initializes the processor pic 8259 that will manage the +/// interruptions. +void pic8259_init_irq(); + +/// @brief This function, enable irqs on the pic. +/// @details This function provide a tool for enabling irq from the pic +/// processor. +/// @param irq Number of irq to enable. +/// @return 0 If all OK, -1 on errors. +int pic8259_irq_enable(uint32_t irq); + +/// @brief This function, disable irqs on the pic. +/// @details This function provide a tool for enabling irq from the pic +/// processor. +/// @param irq Number of irq to enable. +/// @return 0 If all OK, -1 on errors. +int pic8259_irq_disable(uint32_t irq); + +/// @brief This is issued to the PIC chips at the end of an IRQ-based +/// interrupt routine. +/// @param irq The interrupt number. +void pic8259_send_eoi(uint32_t irq); + +/// @brief This Function return the number of current IRQ Request. +/// @return Number of IRQ + 1 currently serving. If 0 there are no IRQ. +//int pic8259_irq_get_current(); diff --git a/mentos/inc/hardware/timer.h b/mentos/inc/hardware/timer.h index a3a1860..44d5482 100644 --- a/mentos/inc/hardware/timer.h +++ b/mentos/inc/hardware/timer.h @@ -1,85 +1,85 @@ -/// MentOS, The Mentoring Operating system project -/// @file timer.h -/// @brief Programmable Interval Timer (PIT) definitions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "kernel.h" -#include "stdint.h" - -/// @defgroup picregs Programmable Interval Timer Registers -/// @brief The list of registers used to set the PIT. -/// @{ - -/// Channel 0 data port (read/write). -#define PIT_DATAREG0 0x40 - -/// Channel 1 data port (read/write). -#define PIT_DATAREG1 0x41 - -/// Channel 2 data port (read/write). -#define PIT_DATAREG2 0x42 - -/// Mode/Command register (write only, a read is ignored). -#define PIT_COMREG 0x43 - -/// @} - -/// @brief Frequency divider value (1.193182 MHz). -#define PIT_DIVISOR 1193180 - -/// @brief Command used to configure the PIT. -/// @details -/// 0x36 = 00110110B. -/// Channel | 00 | Select Channel 0. -/// Access mode | 11 | lobyte/hibyte. -/// Operating mode | 011 | Mode 3 (square wave generator). -/// BCD/Binary mode | 0 | 16-bit binary. -#define PIT_CONFIGURATION 0x36 - -#define PIT_MASK 0xFF - -/// @brief Pointer to a functionality to wake up. -typedef void (*wakeup_callback_t)(); - -/// @brief Holds the information about a wake-up functionality. -typedef struct wakeup_info { - /// Pointer to the functionality. - wakeup_callback_t func; - /// The tick, in the future, when the functionality must be triggered. - __volatile__ uint32_t wakeup_at_jiffy; - /// The period in seconds. - uint32_t period; -} wakeup_info_t; - -/// @brief Handles the timer. -/// @details In this case, it's very simple: We -/// increment the 'timer_ticks' variable every time the -/// timer fires. By default, the timer fires 18.222 times -/// per second. Why 18.222Hz? Some engineer at IBM must've -/// been smoking something funky -void timer_handler(pt_regs *reg); - -/// @brief Sets up the system clock by installing the timer handler into IRQ0. -void timer_install(); - -/// @brief Returns the number of ticks since the system is running. -uint64_t timer_get_ticks(); - -/// @brief Returns the number of ticks since the system is running. -uint64_t timer_get_subticks(); - -/// @brief Registers a function which will be waken up at each tick. -/// @param func The functionality which must be triggered. -/// @param period The period in second. -void timer_register_wakeup_call(wakeup_callback_t func, uint32_t period); - -/// @brief Makes the process sleep for the given ammount of time. -/// @param seconds The ammount of seconds. -void sleep(unsigned int seconds); - -/// @brief Allows to set the timer phase to the given frequency. -/// @param hz The frequency to set. -void timer_phase(const uint32_t hz); +/// MentOS, The Mentoring Operating system project +/// @file timer.h +/// @brief Programmable Interval Timer (PIT) definitions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "kernel.h" +#include "stdint.h" + +/// @defgroup picregs Programmable Interval Timer Registers +/// @brief The list of registers used to set the PIT. +/// @{ + +/// Channel 0 data port (read/write). +#define PIT_DATAREG0 0x40 + +/// Channel 1 data port (read/write). +#define PIT_DATAREG1 0x41 + +/// Channel 2 data port (read/write). +#define PIT_DATAREG2 0x42 + +/// Mode/Command register (write only, a read is ignored). +#define PIT_COMREG 0x43 + +/// @} + +/// @brief Frequency divider value (1.193182 MHz). +#define PIT_DIVISOR 1193180 + +/// @brief Command used to configure the PIT. +/// @details +/// 0x36 = 00110110B. +/// Channel | 00 | Select Channel 0. +/// Access mode | 11 | lobyte/hibyte. +/// Operating mode | 011 | Mode 3 (square wave generator). +/// BCD/Binary mode | 0 | 16-bit binary. +#define PIT_CONFIGURATION 0x36 + +#define PIT_MASK 0xFF + +/// @brief Pointer to a functionality to wake up. +typedef void (*wakeup_callback_t)(); + +/// @brief Holds the information about a wake-up functionality. +typedef struct wakeup_info { + /// Pointer to the functionality. + wakeup_callback_t func; + /// The tick, in the future, when the functionality must be triggered. + __volatile__ uint32_t wakeup_at_jiffy; + /// The period in seconds. + uint32_t period; +} wakeup_info_t; + +/// @brief Handles the timer. +/// @details In this case, it's very simple: We +/// increment the 'timer_ticks' variable every time the +/// timer fires. By default, the timer fires 18.222 times +/// per second. Why 18.222Hz? Some engineer at IBM must've +/// been smoking something funky +void timer_handler(pt_regs *reg); + +/// @brief Sets up the system clock by installing the timer handler into IRQ0. +void timer_install(); + +/// @brief Returns the number of ticks since the system is running. +uint64_t timer_get_ticks(); + +/// @brief Returns the number of ticks since the system is running. +uint64_t timer_get_subticks(); + +/// @brief Registers a function which will be waken up at each tick. +/// @param func The functionality which must be triggered. +/// @param period The period in second. +void timer_register_wakeup_call(wakeup_callback_t func, uint32_t period); + +/// @brief Makes the process sleep for the given ammount of time. +/// @param seconds The ammount of seconds. +void sleep(unsigned int seconds); + +/// @brief Allows to set the timer phase to the given frequency. +/// @param hz The frequency to set. +void timer_phase(const uint32_t hz); diff --git a/mentos/inc/io/mm_io.h b/mentos/inc/io/mm_io.h index 6f3bc3a..eca1f6b 100644 --- a/mentos/inc/io/mm_io.h +++ b/mentos/inc/io/mm_io.h @@ -1,27 +1,27 @@ -/// MentOS, The Mentoring Operating system project -/// @file mm_io.h -/// @brief Memory Mapped IO functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @brief Reads a 8-bit value from the given address. -uint8_t in_memb(uint32_t addr); - -/// @brief Reads a 16-bit value from the given address. -uint16_t in_mems(uint32_t addr); - -/// @brief Reads a 32-bit value from the given address. -uint32_t in_meml(uint32_t addr); - -/// @brief Writes a 8-bit value at the given address. -void out_memb(uint32_t addr, uint8_t value); - -/// @brief Writes a 16-bit value at the given address. -void out_mems(uint32_t addr, uint16_t value); - -/// @brief Writes a 32-bit value at the given address. -void out_meml(uint32_t addr, uint32_t value); +/// MentOS, The Mentoring Operating system project +/// @file mm_io.h +/// @brief Memory Mapped IO functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @brief Reads a 8-bit value from the given address. +uint8_t in_memb(uint32_t addr); + +/// @brief Reads a 16-bit value from the given address. +uint16_t in_mems(uint32_t addr); + +/// @brief Reads a 32-bit value from the given address. +uint32_t in_meml(uint32_t addr); + +/// @brief Writes a 8-bit value at the given address. +void out_memb(uint32_t addr, uint8_t value); + +/// @brief Writes a 16-bit value at the given address. +void out_mems(uint32_t addr, uint16_t value); + +/// @brief Writes a 32-bit value at the given address. +void out_meml(uint32_t addr, uint32_t value); diff --git a/mentos/inc/io/port_io.h b/mentos/inc/io/port_io.h index 270ad71..bf63320 100644 --- a/mentos/inc/io/port_io.h +++ b/mentos/inc/io/port_io.h @@ -1,43 +1,43 @@ -/// MentOS, The Mentoring Operating system project -/// @file port_io.h -/// @brief Byte I/O on ports prototypes. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @brief Used for reading from the I/O ports. -/// @param port The input port. -/// @return The read value. -uint8_t inportb(uint16_t port); - -/// @brief Used for reading 2 bytes from the I/O ports. -/// @param port The input port. -/// @return The read value. -uint16_t inports(uint16_t port); - -void inportsm(uint16_t port, uint8_t *data, unsigned long size); - -/// @brief Used for reading 4 bytes from the I/O ports. -/// @param port The input port. -/// @return The read value. -uint32_t inportl(uint16_t port); - -/// @brief Use this to write to I/O ports to send bytes to devices. -/// @param port The output port. -/// @param data The data to write. -void outportb(uint16_t port, uint8_t data); - -/// @brief Use this to write to I/O ports to send 2 bytes to devices. -/// @param port The output port. -/// @param data The data to write. -void outports(uint16_t port, uint16_t data); - -void outportsm(uint16_t port, uint8_t *data, uint16_t size); - -/// @brief Use this to write to I/O ports to send 4 bytes to devices. -/// @param port The output port. -/// @param data The data to write. -void outportl(uint16_t port, uint32_t data); +/// MentOS, The Mentoring Operating system project +/// @file port_io.h +/// @brief Byte I/O on ports prototypes. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @brief Used for reading from the I/O ports. +/// @param port The input port. +/// @return The read value. +uint8_t inportb(uint16_t port); + +/// @brief Used for reading 2 bytes from the I/O ports. +/// @param port The input port. +/// @return The read value. +uint16_t inports(uint16_t port); + +void inportsm(uint16_t port, uint8_t *data, unsigned long size); + +/// @brief Used for reading 4 bytes from the I/O ports. +/// @param port The input port. +/// @return The read value. +uint32_t inportl(uint16_t port); + +/// @brief Use this to write to I/O ports to send bytes to devices. +/// @param port The output port. +/// @param data The data to write. +void outportb(uint16_t port, uint8_t data); + +/// @brief Use this to write to I/O ports to send 2 bytes to devices. +/// @param port The output port. +/// @param data The data to write. +void outports(uint16_t port, uint16_t data); + +void outportsm(uint16_t port, uint8_t *data, uint16_t size); + +/// @brief Use this to write to I/O ports to send 4 bytes to devices. +/// @param port The output port. +/// @param data The data to write. +void outportl(uint16_t port, uint32_t data); diff --git a/mentos/inc/io/video.h b/mentos/inc/io/video.h index b619214..c3bb74f 100644 --- a/mentos/inc/io/video.h +++ b/mentos/inc/io/video.h @@ -1,132 +1,132 @@ -/// MentOS, The Mentoring Operating system project -/// @file video.h -/// @brief Video functions and costants. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @brief A set of colors. -typedef enum video_color_t { - ///0 : Black - BLACK, - /// 1 : Blue - BLUE, - /// 2 : Green - GREEN, - /// 3 : Cyan - CYAN, - /// 4 : Red - RED, - /// 5 : Magenta - MAGENTA, - /// 6 : Brown - BROWN, - /// 7 : Grey - GREY, - /// 8 : Dark Grey - DARK_GREY, - /// 9 : Bright Blue - BRIGHT_BLUE, - /// 10 : Bright Green - BRIGHT_GREEN, - /// 11 : Bright Cyan - BRIGHT_CYAN, - /// 12 : Bright Red - BRIGHT_RED, - /// 13 : Bright Magenta - BRIGHT_MAGENTA, - /// 14 : Yellow - YELLOW, - /// 15 : White - WHITE, -} video_color_t; - -/// @brief Initialize the video. -void video_init(); - -/// @brief Print the given character on the screen. -void video_putc(int); - -/// @brief Prints the given string on the screen. -void video_puts(const char *str); - -/// @brief Change foreground colour. -void video_set_color(const video_color_t foreground); - -/// @brief Change background colour. -void video_set_background(const video_color_t background); - -/// @brief Deletes the last inserted character. -void video_delete_last_character(); - -/// @brief Move the cursor to the given position. -void video_set_cursor(const unsigned int x, const unsigned int y); - -/// @brief When something is written in another position, update the cursor. -void video_set_cursor_auto(); - -/// @brief Move the cursor at the position x, y on the screen. -void video_move_cursor(int, int); - -/// @brief Prints a tab on the screen. -void video_put_tab(); - -/// @brief Clears the screen. -void video_clear(); - -/// @brief Move to the following line (the effect of \n character). -void video_new_line(); - -/// @brief Move to the up line (the effect of \n character). -void video_cartridge_return(); - -/// @brief Get the current column number. -uint32_t video_get_column(); - -/// @brief Get the current row number. -uint32_t video_get_line(); - -/// @brief The whole screen is shifted up by one line. Used when the cursor -/// reaches the last position of the screen. -void video_shift_one_line(); - -/// @brief The scrolling buffer is updated to contain the screen up the -/// current one. The oldest line is lost to make space for the new one. -void video_rotate_scroll_buffer(); - -/// @brief Called by the pression of the PAGEUP key. -/// The screen aboce the current one is printed and the current one is -/// saved in downbuffer, ready to be restored in future. -void video_scroll_up(); - -/// @brief Called by the pression of the PAGEDOWN key. -/// The content of downbuffer (that is, the screen present when you -/// pressed PAGEUP) is printed again. -void video_scroll_down(); - -/// Determines the lower-bound on the x axis for the video. -uint32_t lower_bound_x; - -/// Determines the lower-bound on the y axis for the video. -uint32_t lower_bound_y; - -/// Determines the current position of the shell cursor on the x axis. -uint32_t shell_current_x; - -/// Determines the current position of the shell cursor on the y axis. -uint32_t shell_current_y; - -/// Determines the lower-bound on the x axis for the shell. -uint32_t shell_lower_bound_x; - -/// Determines the lower-bound on the y axis for the shell. -uint32_t shell_lower_bound_y; - -/// @brief Prints [OK] at the current row and column 60. -void video_print_ok(); - -/// @brief Prints [FAIL] at the current row and column 60. -void video_print_fail(); +/// MentOS, The Mentoring Operating system project +/// @file video.h +/// @brief Video functions and costants. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @brief A set of colors. +typedef enum video_color_t { + ///0 : Black + BLACK, + /// 1 : Blue + BLUE, + /// 2 : Green + GREEN, + /// 3 : Cyan + CYAN, + /// 4 : Red + RED, + /// 5 : Magenta + MAGENTA, + /// 6 : Brown + BROWN, + /// 7 : Grey + GREY, + /// 8 : Dark Grey + DARK_GREY, + /// 9 : Bright Blue + BRIGHT_BLUE, + /// 10 : Bright Green + BRIGHT_GREEN, + /// 11 : Bright Cyan + BRIGHT_CYAN, + /// 12 : Bright Red + BRIGHT_RED, + /// 13 : Bright Magenta + BRIGHT_MAGENTA, + /// 14 : Yellow + YELLOW, + /// 15 : White + WHITE, +} video_color_t; + +/// @brief Initialize the video. +void video_init(); + +/// @brief Print the given character on the screen. +void video_putc(int); + +/// @brief Prints the given string on the screen. +void video_puts(const char *str); + +/// @brief Change foreground colour. +void video_set_color(const video_color_t foreground); + +/// @brief Change background colour. +void video_set_background(const video_color_t background); + +/// @brief Deletes the last inserted character. +void video_delete_last_character(); + +/// @brief Move the cursor to the given position. +void video_set_cursor(const unsigned int x, const unsigned int y); + +/// @brief When something is written in another position, update the cursor. +void video_set_cursor_auto(); + +/// @brief Move the cursor at the position x, y on the screen. +void video_move_cursor(int, int); + +/// @brief Prints a tab on the screen. +void video_put_tab(); + +/// @brief Clears the screen. +void video_clear(); + +/// @brief Move to the following line (the effect of \n character). +void video_new_line(); + +/// @brief Move to the up line (the effect of \n character). +void video_cartridge_return(); + +/// @brief Get the current column number. +uint32_t video_get_column(); + +/// @brief Get the current row number. +uint32_t video_get_line(); + +/// @brief The whole screen is shifted up by one line. Used when the cursor +/// reaches the last position of the screen. +void video_shift_one_line(); + +/// @brief The scrolling buffer is updated to contain the screen up the +/// current one. The oldest line is lost to make space for the new one. +void video_rotate_scroll_buffer(); + +/// @brief Called by the pression of the PAGEUP key. +/// The screen aboce the current one is printed and the current one is +/// saved in downbuffer, ready to be restored in future. +void video_scroll_up(); + +/// @brief Called by the pression of the PAGEDOWN key. +/// The content of downbuffer (that is, the screen present when you +/// pressed PAGEUP) is printed again. +void video_scroll_down(); + +/// Determines the lower-bound on the x axis for the video. +uint32_t lower_bound_x; + +/// Determines the lower-bound on the y axis for the video. +uint32_t lower_bound_y; + +/// Determines the current position of the shell cursor on the x axis. +uint32_t shell_current_x; + +/// Determines the current position of the shell cursor on the y axis. +uint32_t shell_current_y; + +/// Determines the lower-bound on the x axis for the shell. +uint32_t shell_lower_bound_x; + +/// Determines the lower-bound on the y axis for the shell. +uint32_t shell_lower_bound_y; + +/// @brief Prints [OK] at the current row and column 60. +void video_print_ok(); + +/// @brief Prints [FAIL] at the current row and column 60. +void video_print_fail(); diff --git a/mentos/inc/kernel.h b/mentos/inc/kernel.h index 38fe385..a31858e 100644 --- a/mentos/inc/kernel.h +++ b/mentos/inc/kernel.h @@ -1,278 +1,278 @@ -/// MentOS, The Mentoring Operating system project -/// @file kernel.h -/// @brief Kernel generic data structure and functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "elf.h" -#include "stddef.h" -#include "stdint.h" -#include "stdbool.h" -#include "multiboot.h" - -/// The maximum number of modules. -#define MAX_MODULES 10 - -/// Our kernel now loads at 0xC0000000, so what low memory address such as -/// 0xb800 you used to access, should be LOAD_MEMORY_ADDRESS + 0xb800 -#define LOAD_MEMORY_ADDRESS 0x00000000 - -// TODO: doxygen comment. -extern uintptr_t initial_esp; - -/// @brief Halt. -inline static void halt() -{ - __asm__ __volatile__("hlt" ::: "memory"); -} - -/// @brief Pause. -inline static void pause() -{ - __asm__ __volatile__("pause" ::: "memory"); -} - -#define K 1024 - -#define M (1024 * K) - -#define G (1024 * M) - -/// Pointer the beging of the module. -extern char *module_start[MAX_MODULES]; - -/// Address to the end of the module. -extern char *module_end[MAX_MODULES]; - -/// Elf symbols of the kernel. -extern elf_symbols_t kernel_elf; - -/// @brief Entry point of the kernel. -/// @param boot_informations Information concerning the boot. -/// @return The exit status of the kernel. -int kmain(uint32_t magic, multiboot_info_t *header, uintptr_t esp); - -/// @brief Register structs for interrupt/exception. -typedef struct register_t { - /// FS and GS have no hardware-assigned uses. - uint32_t gs; - /// FS and GS have no hardware-assigned uses. - uint32_t fs; - /// Extra Segment determined by the programmer. - uint32_t es; - /// Data Segment. - uint32_t ds; - /// 32-bit destination register. - uint32_t edi; - /// 32-bit source register. - uint32_t esi; - /// 32-bit base pointer register. - uint32_t ebp; - /// 32-bit stack pointer register. - uint32_t esp; - /// 32-bit base register. - uint32_t ebx; - /// 32-bit data register. - uint32_t edx; - /// 32-bit counter. - uint32_t ecx; - /// 32-bit accumulator register. - uint32_t eax; - /// Interrupt number. - uint32_t int_no; - /// Error code. - uint32_t err_code; - /// Instruction Pointer Register. - uint32_t eip; - /// Code Segment. - uint32_t cs; - /// 32-bit flag register. - uint32_t eflags; - // TODO: Check meaning! - uint32_t useresp; - /// Stack Segment. - uint32_t ss; -} register_t; - -/* - * /// @brief Register structs for bios service. - * typedef struct register16_t - * { - * /// Destination Index. - * uint16_t di; - * /// Source Index. - * uint16_t si; - * /// Base Pointer. - * uint16_t bp; - * /// Stack Pointer. - * uint16_t sp; - * /// Also known as the base register. - * uint16_t bx; - * /// Also known as the data register. - * uint16_t dx; - * /// Also known as the count register. - * uint16_t cx; - * /// Is the primary accumulator. - * uint16_t ax; - * /// Data Segment. - * uint16_t ds; - * /// Extra Segment determined by the programmer. - * uint16_t es; - * /// FS and GS have no hardware-assigned uses. - * uint16_t fs; - * /// FS and GS have no hardware-assigned uses. - * uint16_t gs; - * /// Stack Segment. - * uint16_t ss; - * /// 32-bit flag register. - * uint16_t eflags; - * } register16_t; - */ - -//==== Interrupt stack frame =================================================== -// Interrupt stack frame. When the CPU moves from Ring3 to Ring0 because of -// an interrupt, the following registes/values are moved into the kernel's stack -// TODO: doxygen comment. -typedef struct pt_regs { - /// FS and GS have no hardware-assigned uses. - uint32_t gs; - /// FS and GS have no hardware-assigned uses. - uint32_t fs; - /// Extra Segment determined by the programmer. - uint32_t es; - /// Data Segment. - uint32_t ds; - /// 32-bit destination register. - uint32_t edi; - /// 32-bit source register. - uint32_t esi; - /// 32-bit base pointer register. - uint32_t ebp; - /// 32-bit stack pointer register. - uint32_t esp; - /// 32-bit base register. - uint32_t ebx; - /// 32-bit data register. - uint32_t edx; - /// 32-bit counter. - uint32_t ecx; - /// 32-bit accumulator register. - uint32_t eax; - /// Interrupt number. - uint32_t int_no; - /// Error code. - uint32_t err_code; - /// Instruction Pointer Register. - uint32_t eip; - /// Code Segment. - uint32_t cs; - /// 32-bit flag register. - uint32_t eflags; - // TODO: Check meaning! - uint32_t useresp; - /// Stack Segment. - uint32_t ss; -} pt_regs; -//============================================================================== - -//==== Floating Point Unit (FPU) Register ====================================== -// Data structure used to save FPU registers. -/// @brief Environment information of floating point unit. -typedef struct { - /// Control word (16bits). - long en_cw; - /// Status word (16bits). - long en_sw; - /// Tag word (16bits). - long en_tw; - /// Floating point instruction pointer. - long en_fip; - /// Floating code segment selector. - unsigned short en_fcs; - /// Opcode last executed (11 bits). - unsigned short en_opcode; - /// Floating operand offset. - long en_foo; - /// Floating operand segment selector. - long en_fos; -} env87; - -/// @brief Contents of each floating point accumulator. -typedef struct { - unsigned char fp_bytes[10]; -} fpacc87; - -/// @brief Floating point context. -typedef struct { - /// Floating point control/status. - env87 sv_env; - /// Accumulator contents, 0-7. - fpacc87 sv_ac[8]; - /// Padding for (now unused) saved status word. - unsigned char sv_pad0[4]; - /* - * Bogus padding for emulators. Emulators should use their own - * struct and arrange to store into this struct (ending here) - * before it is inspected for ptracing or for core dumps. Some - * emulators overwrite the whole struct. We have no good way of - * knowing how much padding to leave. Leave just enough for the - * GPL emulator's i387_union (176 bytes total). - */ - unsigned char sv_pad[64]; // Padding; used by emulators -} save87; - -// TODO: doxygen comment. -typedef struct { - /// Control word (16bits). - uint16_t en_cw; - /// Status word (16bits). - uint16_t en_sw; - /// Tag word (16bits). - uint16_t en_tw; - /// Opcode last executed (11 bits). - uint16_t en_opcode; - /// Floating point instruction pointer. - uint32_t en_fip; - /// Floating code segment selector. - uint16_t en_fcs; - /// Padding. - uint16_t en_pad0; - /// Floating operand offset. - uint32_t en_foo; - /// Floating operand segment selector. - uint16_t en_fos; - /// Padding. - uint16_t en_pad1; - /// SSE sontorol/status register. - uint32_t en_mxcsr; - /// Valid bits in mxcsr. - uint32_t en_mxcsr_mask; -} envxmm; - -/// @brief Contents of each SSE extended accumulator. -typedef struct { - unsigned char xmm_bytes[16]; -} xmmacc; - -// TODO: doxygen comment. -typedef struct { - envxmm sv_env; - struct { - fpacc87 fp_acc; - /// Padding. - unsigned char fp_pad[6]; - } sv_fp[8]; - xmmacc sv_xmm[8]; - - /// Padding. - unsigned char sv_pad[224]; -} __attribute__((__aligned__(16))) savexmm; - -// TODO: doxygen comment. -typedef union { - save87 sv_87; - savexmm sv_xmm; -} savefpu; -//============================================================================== +/// MentOS, The Mentoring Operating system project +/// @file kernel.h +/// @brief Kernel generic data structure and functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "elf.h" +#include "stddef.h" +#include "stdint.h" +#include "stdbool.h" +#include "multiboot.h" + +/// The maximum number of modules. +#define MAX_MODULES 10 + +/// Our kernel now loads at 0xC0000000, so what low memory address such as +/// 0xb800 you used to access, should be LOAD_MEMORY_ADDRESS + 0xb800 +#define LOAD_MEMORY_ADDRESS 0x00000000 + +// TODO: doxygen comment. +extern uintptr_t initial_esp; + +/// @brief Halt. +inline static void halt() +{ + __asm__ __volatile__("hlt" ::: "memory"); +} + +/// @brief Pause. +inline static void pause() +{ + __asm__ __volatile__("pause" ::: "memory"); +} + +#define K 1024 + +#define M (1024 * K) + +#define G (1024 * M) + +/// Pointer the beging of the module. +extern char *module_start[MAX_MODULES]; + +/// Address to the end of the module. +extern char *module_end[MAX_MODULES]; + +/// Elf symbols of the kernel. +extern elf_symbols_t kernel_elf; + +/// @brief Entry point of the kernel. +/// @param boot_informations Information concerning the boot. +/// @return The exit status of the kernel. +int kmain(uint32_t magic, multiboot_info_t *header, uintptr_t esp); + +/// @brief Register structs for interrupt/exception. +typedef struct register_t { + /// FS and GS have no hardware-assigned uses. + uint32_t gs; + /// FS and GS have no hardware-assigned uses. + uint32_t fs; + /// Extra Segment determined by the programmer. + uint32_t es; + /// Data Segment. + uint32_t ds; + /// 32-bit destination register. + uint32_t edi; + /// 32-bit source register. + uint32_t esi; + /// 32-bit base pointer register. + uint32_t ebp; + /// 32-bit stack pointer register. + uint32_t esp; + /// 32-bit base register. + uint32_t ebx; + /// 32-bit data register. + uint32_t edx; + /// 32-bit counter. + uint32_t ecx; + /// 32-bit accumulator register. + uint32_t eax; + /// Interrupt number. + uint32_t int_no; + /// Error code. + uint32_t err_code; + /// Instruction Pointer Register. + uint32_t eip; + /// Code Segment. + uint32_t cs; + /// 32-bit flag register. + uint32_t eflags; + // TODO: Check meaning! + uint32_t useresp; + /// Stack Segment. + uint32_t ss; +} register_t; + +/* + * /// @brief Register structs for bios service. + * typedef struct register16_t + * { + * /// Destination Index. + * uint16_t di; + * /// Source Index. + * uint16_t si; + * /// Base Pointer. + * uint16_t bp; + * /// Stack Pointer. + * uint16_t sp; + * /// Also known as the base register. + * uint16_t bx; + * /// Also known as the data register. + * uint16_t dx; + * /// Also known as the count register. + * uint16_t cx; + * /// Is the primary accumulator. + * uint16_t ax; + * /// Data Segment. + * uint16_t ds; + * /// Extra Segment determined by the programmer. + * uint16_t es; + * /// FS and GS have no hardware-assigned uses. + * uint16_t fs; + * /// FS and GS have no hardware-assigned uses. + * uint16_t gs; + * /// Stack Segment. + * uint16_t ss; + * /// 32-bit flag register. + * uint16_t eflags; + * } register16_t; + */ + +//==== Interrupt stack frame =================================================== +// Interrupt stack frame. When the CPU moves from Ring3 to Ring0 because of +// an interrupt, the following registes/values are moved into the kernel's stack +// TODO: doxygen comment. +typedef struct pt_regs { + /// FS and GS have no hardware-assigned uses. + uint32_t gs; + /// FS and GS have no hardware-assigned uses. + uint32_t fs; + /// Extra Segment determined by the programmer. + uint32_t es; + /// Data Segment. + uint32_t ds; + /// 32-bit destination register. + uint32_t edi; + /// 32-bit source register. + uint32_t esi; + /// 32-bit base pointer register. + uint32_t ebp; + /// 32-bit stack pointer register. + uint32_t esp; + /// 32-bit base register. + uint32_t ebx; + /// 32-bit data register. + uint32_t edx; + /// 32-bit counter. + uint32_t ecx; + /// 32-bit accumulator register. + uint32_t eax; + /// Interrupt number. + uint32_t int_no; + /// Error code. + uint32_t err_code; + /// Instruction Pointer Register. + uint32_t eip; + /// Code Segment. + uint32_t cs; + /// 32-bit flag register. + uint32_t eflags; + // TODO: Check meaning! + uint32_t useresp; + /// Stack Segment. + uint32_t ss; +} pt_regs; +//============================================================================== + +//==== Floating Point Unit (FPU) Register ====================================== +// Data structure used to save FPU registers. +/// @brief Environment information of floating point unit. +typedef struct { + /// Control word (16bits). + long en_cw; + /// Status word (16bits). + long en_sw; + /// Tag word (16bits). + long en_tw; + /// Floating point instruction pointer. + long en_fip; + /// Floating code segment selector. + unsigned short en_fcs; + /// Opcode last executed (11 bits). + unsigned short en_opcode; + /// Floating operand offset. + long en_foo; + /// Floating operand segment selector. + long en_fos; +} env87; + +/// @brief Contents of each floating point accumulator. +typedef struct { + unsigned char fp_bytes[10]; +} fpacc87; + +/// @brief Floating point context. +typedef struct { + /// Floating point control/status. + env87 sv_env; + /// Accumulator contents, 0-7. + fpacc87 sv_ac[8]; + /// Padding for (now unused) saved status word. + unsigned char sv_pad0[4]; + /* + * Bogus padding for emulators. Emulators should use their own + * struct and arrange to store into this struct (ending here) + * before it is inspected for ptracing or for core dumps. Some + * emulators overwrite the whole struct. We have no good way of + * knowing how much padding to leave. Leave just enough for the + * GPL emulator's i387_union (176 bytes total). + */ + unsigned char sv_pad[64]; // Padding; used by emulators +} save87; + +// TODO: doxygen comment. +typedef struct { + /// Control word (16bits). + uint16_t en_cw; + /// Status word (16bits). + uint16_t en_sw; + /// Tag word (16bits). + uint16_t en_tw; + /// Opcode last executed (11 bits). + uint16_t en_opcode; + /// Floating point instruction pointer. + uint32_t en_fip; + /// Floating code segment selector. + uint16_t en_fcs; + /// Padding. + uint16_t en_pad0; + /// Floating operand offset. + uint32_t en_foo; + /// Floating operand segment selector. + uint16_t en_fos; + /// Padding. + uint16_t en_pad1; + /// SSE sontorol/status register. + uint32_t en_mxcsr; + /// Valid bits in mxcsr. + uint32_t en_mxcsr_mask; +} envxmm; + +/// @brief Contents of each SSE extended accumulator. +typedef struct { + unsigned char xmm_bytes[16]; +} xmmacc; + +// TODO: doxygen comment. +typedef struct { + envxmm sv_env; + struct { + fpacc87 fp_acc; + /// Padding. + unsigned char fp_pad[6]; + } sv_fp[8]; + xmmacc sv_xmm[8]; + + /// Padding. + unsigned char sv_pad[224]; +} __attribute__((__aligned__(16))) savexmm; + +// TODO: doxygen comment. +typedef union { + save87 sv_87; + savexmm sv_xmm; +} savefpu; +//============================================================================== diff --git a/mentos/inc/libc/assert.h b/mentos/inc/libc/assert.h index 0148391..b6fb60f 100644 --- a/mentos/inc/libc/assert.h +++ b/mentos/inc/libc/assert.h @@ -1,24 +1,24 @@ -/// MentOS, The Mentoring Operating system project -/// @file assert.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdio.h" -#include "panic.h" -#include "stdarg.h" - -/// @brief Function used to log the information of a failed assertion. -/// @param assertion The failed assertion. -/// @param file The file where the assertion is located. -/// @param line The line inside the file. -/// @param function The function where the assertion is. -void __assert_fail(const char *assertion, const char *file, unsigned int line, - const char *function); - -/// @brief Assert function. -#define assert(expression) \ - ((expression) ? (void)0 : \ - __assert_fail(#expression, __FILE__, __LINE__, __func__)) +/// MentOS, The Mentoring Operating system project +/// @file assert.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdio.h" +#include "panic.h" +#include "stdarg.h" + +/// @brief Function used to log the information of a failed assertion. +/// @param assertion The failed assertion. +/// @param file The file where the assertion is located. +/// @param line The line inside the file. +/// @param function The function where the assertion is. +void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function); + +/// @brief Assert function. +#define assert(expression) \ + ((expression) ? (void)0 : \ + __assert_fail(#expression, __FILE__, __LINE__, __func__)) diff --git a/mentos/inc/libc/bitset.h b/mentos/inc/libc/bitset.h index 094150f..b3243b6 100644 --- a/mentos/inc/libc/bitset.h +++ b/mentos/inc/libc/bitset.h @@ -1,42 +1,42 @@ -/// MentOS, The Mentoring Operating system project -/// @file bitset.h -/// @brief Bitset data structure. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" -#include "stdbool.h" - -/// @brief Bitset structure. -typedef struct { - /// The internal data. - unsigned char *data; - /// The size of the bitset. - size_t size; -} bitset_t; - -// TODO: doxygen comment. -/// @brief -void bitset_init(bitset_t *set, size_t size); - -// TODO: doxygen comment. -/// @brief -void bitset_free(bitset_t *set); - -// TODO: doxygen comment. -/// @brief -void bitset_set(bitset_t *set, size_t bit); - -// TODO: doxygen comment. -/// @brief -void bitset_clear(bitset_t *set, size_t bit); - -// TODO: doxygen comment. -/// @brief -bool_t bitset_test(bitset_t *set, size_t bit); - -// TODO: doxygen comment. -/// @brief -signed long bitset_find_first_unset_bit(bitset_t *set); +/// MentOS, The Mentoring Operating system project +/// @file bitset.h +/// @brief Bitset data structure. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" +#include "stdbool.h" + +/// @brief Bitset structure. +typedef struct { + /// The internal data. + unsigned char *data; + /// The size of the bitset. + size_t size; +} bitset_t; + +// TODO: doxygen comment. +/// @brief +void bitset_init(bitset_t *set, size_t size); + +// TODO: doxygen comment. +/// @brief +void bitset_free(bitset_t *set); + +// TODO: doxygen comment. +/// @brief +void bitset_set(bitset_t *set, size_t bit); + +// TODO: doxygen comment. +/// @brief +void bitset_clear(bitset_t *set, size_t bit); + +// TODO: doxygen comment. +/// @brief +bool_t bitset_test(bitset_t *set, size_t bit); + +// TODO: doxygen comment. +/// @brief +signed long bitset_find_first_unset_bit(bitset_t *set); diff --git a/mentos/inc/libc/compiler.h b/mentos/inc/libc/compiler.h index dd661bd..cbc065a 100644 --- a/mentos/inc/libc/compiler.h +++ b/mentos/inc/libc/compiler.h @@ -1,22 +1,22 @@ -/// MentOS, The Mentoring Operating system project -/// @file compiler.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/* - * Prevent the compiler from merging or refetching reads or writes. - * - * Ensuring that the compiler does not fold, spindle, or otherwise - * mutilate accesses that either do not require ordering or that interact - * with an explicit memory barrier or atomic instruction that provides the - * required ordering. - */ - -/// @brief Assign the value to the given variable. -#define WRITE_ONCE(var, val) (*((volatile typeof(val) *)(&(var))) = (val)) - -/// @brief Read the value from the given variable. -#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var)))) +/// MentOS, The Mentoring Operating system project +/// @file compiler.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/* + * Prevent the compiler from merging or refetching reads or writes. + * + * Ensuring that the compiler does not fold, spindle, or otherwise + * mutilate accesses that either do not require ordering or that interact + * with an explicit memory barrier or atomic instruction that provides the + * required ordering. + */ + +/// @brief Assign the value to the given variable. +#define WRITE_ONCE(var, val) (*((volatile typeof(val) *)(&(var))) = (val)) + +/// @brief Read the value from the given variable. +#define READ_ONCE(var) (*((volatile typeof(var) *)(&(var)))) diff --git a/mentos/inc/libc/ctype.h b/mentos/inc/libc/ctype.h index 2e5dccf..7063e80 100644 --- a/mentos/inc/libc/ctype.h +++ b/mentos/inc/libc/ctype.h @@ -1,34 +1,34 @@ -/// MentOS, The Mentoring Operating system project -/// @file ctype.h -/// @brief Functions related to character handling. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief Check if the given value is a digit. -int isdigit(int c); - -/// @brief Check if the given value is a letter. -int isalpha(int c); - -/// @brief Check if the given value is either a letter or a digit. -int isalnum(int c); - -/// @brief Check if the given value is an hexadecimal digit. -int isxdigit(int c); - -/// @brief Check if the given value is a lower case letter. -int islower(int c); - -/// @brief Check if the given value is an upper case letter. -int isupper(int c); - -/// @brief Transforms the given value into a lower case letter. -int tolower(int c); - -/// @brief Transforms the given value into an upper case letter. -int toupper(int c); - -/// @brief Check if the given value is a whitespace. -int isspace(int c); +/// MentOS, The Mentoring Operating system project +/// @file ctype.h +/// @brief Functions related to character handling. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief Check if the given value is a digit. +int isdigit(int c); + +/// @brief Check if the given value is a letter. +int isalpha(int c); + +/// @brief Check if the given value is either a letter or a digit. +int isalnum(int c); + +/// @brief Check if the given value is an hexadecimal digit. +int isxdigit(int c); + +/// @brief Check if the given value is a lower case letter. +int islower(int c); + +/// @brief Check if the given value is an upper case letter. +int isupper(int c); + +/// @brief Transforms the given value into a lower case letter. +int tolower(int c); + +/// @brief Transforms the given value into an upper case letter. +int toupper(int c); + +/// @brief Check if the given value is a whitespace. +int isspace(int c); diff --git a/mentos/inc/libc/fcvt.h b/mentos/inc/libc/fcvt.h index a645dfc..768f761 100644 --- a/mentos/inc/libc/fcvt.h +++ b/mentos/inc/libc/fcvt.h @@ -1,27 +1,27 @@ -/// MentOS, The Mentoring Operating system project -/// @file fcvt.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -// TODO: doxygen comment. -/// @brief -/// @param arg -/// @param ndigits -/// @param decpt -/// @param sign -/// @param buf -/// @result -char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); - -// TODO: doxygen comment. -/// @brief -/// @param arg -/// @param ndigits -/// @param decpt -/// @param sign -/// @param buf -/// @result -char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +/// MentOS, The Mentoring Operating system project +/// @file fcvt.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +// TODO: doxygen comment. +/// @brief +/// @param arg +/// @param ndigits +/// @param decpt +/// @param sign +/// @param buf +/// @result +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); + +// TODO: doxygen comment. +/// @brief +/// @param arg +/// @param ndigits +/// @param decpt +/// @param sign +/// @param buf +/// @result +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); diff --git a/mentos/inc/libc/hashmap.h b/mentos/inc/libc/hashmap.h index 32b94cf..7feb579 100644 --- a/mentos/inc/libc/hashmap.h +++ b/mentos/inc/libc/hashmap.h @@ -1,80 +1,80 @@ -/// MentOS, The Mentoring Operating system project -/// @file hashmap.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "list.h" -#include "stdbool.h" - -//============================================================================== -// Opaque types. -typedef struct hashmap_entry_t hashmap_entry_t; -typedef struct hashmap_t hashmap_t; - -//============================================================================= -// Hashmap functions. - -// TODO: doxygen comment. -typedef size_t (*hashmap_hash_t)(void *key); - -// TODO: doxygen comment. -typedef bool_t (*hashmap_comp_t)(void *a, void *b); - -// TODO: doxygen comment. -typedef void (*hashmap_free_t)(void *); - -// TODO: doxygen comment. -typedef void *(*hashmap_dupe_t)(void *); - -//============================================================================== -// Hashmap creation and destruction. - -// TODO: doxygen comment. -extern hashmap_t *hashmap_create(size_t size); - -// TODO: doxygen comment. -extern hashmap_t *hashmap_create_int(size_t size); - -// TODO: doxygen comment. -extern void hashmap_free(hashmap_t *map); - -//============================================================================== -// Hashmap management. - -// TODO: doxygen comment. -extern void *hashmap_set(hashmap_t *map, void *key, void *value); - -// TODO: doxygen comment. -extern void *hashmap_get(hashmap_t *map, void *key); - -// TODO: doxygen comment. -extern void *hashmap_remove(hashmap_t *map, void *key); - -//============================================================================== -// Hashmap search. - -// TODO: doxygen comment. -extern bool_t hashmap_is_empty(hashmap_t *map); - -// TODO: doxygen comment. -extern bool_t hashmap_has(hashmap_t *map, void *key); - -// TODO: doxygen comment. -extern list_t *hashmap_keys(hashmap_t *map); - -// TODO: doxygen comment. -extern list_t *hashmap_values(hashmap_t *map); - -// TODO: doxygen comment. -extern size_t hashmap_string_hash(void *key); - -// TODO: doxygen comment. -extern bool_t hashmap_string_comp(void *a, void *b); - -// TODO: doxygen comment. -extern void *hashmap_string_dupe(void *key); - -//============================================================================== +/// MentOS, The Mentoring Operating system project +/// @file hashmap.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "list.h" +#include "stdbool.h" + +//============================================================================== +// Opaque types. +typedef struct hashmap_entry_t hashmap_entry_t; +typedef struct hashmap_t hashmap_t; + +//============================================================================= +// Hashmap functions. + +// TODO: doxygen comment. +typedef size_t (*hashmap_hash_t)(void *key); + +// TODO: doxygen comment. +typedef bool_t (*hashmap_comp_t)(void *a, void *b); + +// TODO: doxygen comment. +typedef void (*hashmap_free_t)(void *); + +// TODO: doxygen comment. +typedef void *(*hashmap_dupe_t)(void *); + +//============================================================================== +// Hashmap creation and destruction. + +// TODO: doxygen comment. +extern hashmap_t *hashmap_create(size_t size); + +// TODO: doxygen comment. +extern hashmap_t *hashmap_create_int(size_t size); + +// TODO: doxygen comment. +extern void hashmap_free(hashmap_t *map); + +//============================================================================== +// Hashmap management. + +// TODO: doxygen comment. +extern void *hashmap_set(hashmap_t *map, void *key, void *value); + +// TODO: doxygen comment. +extern void *hashmap_get(hashmap_t *map, void *key); + +// TODO: doxygen comment. +extern void *hashmap_remove(hashmap_t *map, void *key); + +//============================================================================== +// Hashmap search. + +// TODO: doxygen comment. +extern bool_t hashmap_is_empty(hashmap_t *map); + +// TODO: doxygen comment. +extern bool_t hashmap_has(hashmap_t *map, void *key); + +// TODO: doxygen comment. +extern list_t *hashmap_keys(hashmap_t *map); + +// TODO: doxygen comment. +extern list_t *hashmap_values(hashmap_t *map); + +// TODO: doxygen comment. +extern size_t hashmap_string_hash(void *key); + +// TODO: doxygen comment. +extern bool_t hashmap_string_comp(void *a, void *b); + +// TODO: doxygen comment. +extern void *hashmap_string_dupe(void *key); + +//============================================================================== diff --git a/mentos/inc/libc/irqflags.h b/mentos/inc/libc/irqflags.h index b7145db..e76f3e5 100644 --- a/mentos/inc/libc/irqflags.h +++ b/mentos/inc/libc/irqflags.h @@ -1,72 +1,72 @@ -/// MentOS, The Mentoring Operating system project -/// @file irqflags.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" -#include "stdint.h" - -/// @brief Enable IRQs. -inline static void irq_enable() -{ - __asm__ __volatile__("sti" ::: "memory"); -} - -// TODO: doxygen comment. -inline unsigned long get_eflags() -{ - unsigned long eflags; - /* "=rm" is safe here, because "pop" adjusts the stack before - * it evaluates its effective address -- this is part of the - * documented behavior of the "pop" instruction. - */ - __asm__ __volatile__("pushf ; pop %0" - : "=rm"(eflags) - : /* no input */ - : "memory"); - return eflags; -} - -/// @brief Enable IRQs (nested). -/// @details If called after calling irq_nested_disable, this function will -/// not activate IRQs if they were not active before. -inline static void irq_nested_enable(uint8_t flags) -{ - if (flags) { - irq_enable(); - } -} - -/// @brief Disable IRQs. -inline static void irq_disable() -{ - __asm__ __volatile__("cli" ::: "memory"); -} - -/// @brief Disable IRQs (nested). -/// @details Disable IRQs when unsure if IRQs were enabled at all. -/// This function together with irq_nested_enable can be used in -/// situations when interrupts shouldn't be activated if they were not -/// activated before calling this function. -inline static uint8_t irq_nested_disable() -{ - size_t flags; - __asm__ __volatile__("pushf; cli; pop %0" : "=r"(flags) : : "memory"); - if (flags & (1 << 9)) - return 1; - return 0; -} - -/// @brief Determines, if the interrupt flags (IF) is set. -inline static uint8_t is_irq_enabled() -{ - size_t flags; - __asm__ __volatile__("pushf; pop %0" : "=r"(flags) : : "memory"); - if (flags & (1 << 9)) { - return 1; - } - return 0; -} +/// MentOS, The Mentoring Operating system project +/// @file irqflags.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" +#include "stdint.h" + +/// @brief Enable IRQs. +inline static void irq_enable() +{ + __asm__ __volatile__("sti" ::: "memory"); +} + +// TODO: doxygen comment. +inline unsigned long get_eflags() +{ + unsigned long eflags; + /* "=rm" is safe here, because "pop" adjusts the stack before + * it evaluates its effective address -- this is part of the + * documented behavior of the "pop" instruction. + */ + __asm__ __volatile__("pushf ; pop %0" + : "=rm"(eflags) + : /* no input */ + : "memory"); + return eflags; +} + +/// @brief Enable IRQs (nested). +/// @details If called after calling irq_nested_disable, this function will +/// not activate IRQs if they were not active before. +inline static void irq_nested_enable(uint8_t flags) +{ + if (flags) { + irq_enable(); + } +} + +/// @brief Disable IRQs. +inline static void irq_disable() +{ + __asm__ __volatile__("cli" ::: "memory"); +} + +/// @brief Disable IRQs (nested). +/// @details Disable IRQs when unsure if IRQs were enabled at all. +/// This function together with irq_nested_enable can be used in +/// situations when interrupts shouldn't be activated if they were not +/// activated before calling this function. +inline static uint8_t irq_nested_disable() +{ + size_t flags; + __asm__ __volatile__("pushf; cli; pop %0" : "=r"(flags) : : "memory"); + if (flags & (1 << 9)) + return 1; + return 0; +} + +/// @brief Determines, if the interrupt flags (IF) is set. +inline static uint8_t is_irq_enabled() +{ + size_t flags; + __asm__ __volatile__("pushf; pop %0" : "=r"(flags) : : "memory"); + if (flags & (1 << 9)) { + return 1; + } + return 0; +} diff --git a/mentos/inc/libc/libgen.h b/mentos/inc/libc/libgen.h index 5f9bc61..e65b323 100644 --- a/mentos/inc/libc/libgen.h +++ b/mentos/inc/libc/libgen.h @@ -1,28 +1,28 @@ -/// MentOS, The Mentoring Operating system project -/// @file libgen.h -/// @brief String routines. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "stddef.h" - -// TODO: doxygen comment. -/// @brief -/// @param out -/// @param cur -/// @param sep -/// @param max -/// @result -int parse_path(char *out, char **cur, char sep, size_t max); - -// TODO: doxygen comment. -/// @brief -/// @param path -/// @result -char *dirname(const char *path); - -// TODO: doxygen comment. -/// @brief -/// @param path -/// @result -char *basename(const char *path); +/// MentOS, The Mentoring Operating system project +/// @file libgen.h +/// @brief String routines. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "stddef.h" + +// TODO: doxygen comment. +/// @brief +/// @param out +/// @param cur +/// @param sep +/// @param max +/// @result +int parse_path(char *out, char **cur, char sep, size_t max); + +// TODO: doxygen comment. +/// @brief +/// @param path +/// @result +char *dirname(const char *path); + +// TODO: doxygen comment. +/// @brief +/// @param path +/// @result +char *basename(const char *path); diff --git a/mentos/inc/libc/limits.h b/mentos/inc/libc/limits.h index bd5c67f..6e0443a 100644 --- a/mentos/inc/libc/limits.h +++ b/mentos/inc/libc/limits.h @@ -1,47 +1,47 @@ -/// MentOS, The Mentoring Operating system project -/// @file limits.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// Number of bits in a `char'. -#define CHAR_BIT 8 - -/// Minimum value a `signed char' can hold. - -#define SCHAR_MIN (-128) - -/// Maximum value a `signed char' can hold. -#define SCHAR_MAX 127 - -/// Maximum value a `char' can hold. (Minimum is 0.) -#define CHAR_MAX 255 - -/// Minimum value a `signed short int' can hold. -#define SHRT_MIN (-32768) - -/// Maximum value a `signed short int' can hold. -#define SHRT_MAX 32767 - -/// Minimum value a `signed int' can hold. -#define INT_MIN (-INT_MAX - 1) - -/// Maximum values a `signed int' can hold. -#define INT_MAX 2147483647 - -/// Maximum value an `unsigned int' can hold. (Minimum is 0.) -#define UINT_MAX 4294967295U - -/// Minimum value a `signed long int' can hold. -#define LONG_MAX 2147483647L - -/// Maximum value a `signed long int' can hold. -#define LONG_MIN (-LONG_MAX - 1L) - -/// Maximum number of characters in a file name. -#define NAME_MAX 255 - -/// Maximum number of characters in a path name. +/// MentOS, The Mentoring Operating system project +/// @file limits.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// Number of bits in a `char'. +#define CHAR_BIT 8 + +/// Minimum value a `signed char' can hold. + +#define SCHAR_MIN (-128) + +/// Maximum value a `signed char' can hold. +#define SCHAR_MAX 127 + +/// Maximum value a `char' can hold. (Minimum is 0.) +#define CHAR_MAX 255 + +/// Minimum value a `signed short int' can hold. +#define SHRT_MIN (-32768) + +/// Maximum value a `signed short int' can hold. +#define SHRT_MAX 32767 + +/// Minimum value a `signed int' can hold. +#define INT_MIN (-INT_MAX - 1) + +/// Maximum values a `signed int' can hold. +#define INT_MAX 2147483647 + +/// Maximum value an `unsigned int' can hold. (Minimum is 0.) +#define UINT_MAX 4294967295U + +/// Minimum value a `signed long int' can hold. +#define LONG_MAX 2147483647L + +/// Maximum value a `signed long int' can hold. +#define LONG_MIN (-LONG_MAX - 1L) + +/// Maximum number of characters in a file name. +#define NAME_MAX 255 + +/// Maximum number of characters in a path name. #define PATH_MAX 4096 \ No newline at end of file diff --git a/mentos/inc/libc/list.h b/mentos/inc/libc/list.h index c8852ab..c21ee98 100644 --- a/mentos/inc/libc/list.h +++ b/mentos/inc/libc/list.h @@ -1,107 +1,107 @@ -/// MentOS, The Mentoring Operating system project -/// @file list.h -/// @brief An implementation for generic list. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" -#include "stddef.h" -#include "stdbool.h" - -/// @brief Represent the node of a list. -typedef struct listnode_t { - /// A pointer to the value. - void *value; - /// The previous node. - struct listnode_t *prev; - /// The next node. - struct listnode_t *next; -} listnode_t; - -/// @brief Represent the list. -typedef struct list_t { - /// The first element of the list. - listnode_t *head; - /// The last element of the list. - listnode_t *tail; - /// The size of the list. - size_t size; -} list_t; - -/// @brief Macro used to iterate through a list. -#define listnode_foreach(it, list) \ - for (listnode_t * (it) = (list)->head; (it) != NULL; (it) = (it)->next) - -/// @brief Create a list and set head, tail to NULL, and size to 0. -list_t *list_create(); - -/// @brief Get list size. -size_t list_size(list_t *list); - -/// @brief Checks if the list is empty. -bool_t list_empty(list_t *list); - -/// @brief Insert a value at the front of list. -listnode_t *list_insert_front(list_t *list, void *value); - -/// @brief Insert a value at the back of list. -listnode_t *list_insert_back(list_t *list, void *value); - -/// @brief Insert a value at the back of list. -void list_insert_node_back(list_t *list, listnode_t *item); - -/// @brief Given a listnode, remove it from lis. -void *list_remove_node(list_t *list, listnode_t *node); - -/// @brief Remove a value at the front of list. -void *list_remove_front(list_t *list); - -/// @brief Remove a value at the back of list. -void *list_remove_back(list_t *list); - -/// @brief Searches the node of the list which points at the given value. -listnode_t *list_find(list_t *list, void *value); - -/// @brief Insert after tail of list(same as insert back). -void list_push(list_t *list, void *value); - -/// @brief Remove and return the tail of the list. -/// @details User is responsible for freeing the returned node and the value. -listnode_t *list_pop_back(list_t *list); - -/// @brief Remove and return the head of the list. -/// @details User is responsible for freeing the returned node and the value. -listnode_t *list_pop_front(list_t *list); - -/// @brief Insert before head of list(same as insert front). -void list_enqueue(list_t *list, void *value); - -/// @brief Remove and return tail of list(same as list_pop). -listnode_t *list_dequeue(list_t *list); - -/// @brief Get the value of the first element but not remove it. -void *list_peek_front(list_t *list); - -/// @brief Get the value of the last element but not remove it. -void *list_peek_back(list_t *list); - -/// @brief Destory a list. -void list_destroy(list_t *list); - -/// @brief Destroy a node of the list. -void listnode_destroy(listnode_t *node); - -/// @brief Does the list contain a value (Return -1 if list element is not -/// found). -int list_contain(list_t *list, void *value); - -/// @brief Returns the node at the given index. -listnode_t *list_get_node_by_index(list_t *list, size_t index); - -/// @brief Removes a node from the list at the given index. -void *list_remove_by_index(list_t *list, size_t index); - -/// @brief Append source at the end of target and DESTROY source. -void list_merge(list_t *target, list_t *source); +/// MentOS, The Mentoring Operating system project +/// @file list.h +/// @brief An implementation for generic list. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" +#include "stddef.h" +#include "stdbool.h" + +/// @brief Represent the node of a list. +typedef struct listnode_t { + /// A pointer to the value. + void *value; + /// The previous node. + struct listnode_t *prev; + /// The next node. + struct listnode_t *next; +} listnode_t; + +/// @brief Represent the list. +typedef struct list_t { + /// The first element of the list. + listnode_t *head; + /// The last element of the list. + listnode_t *tail; + /// The size of the list. + size_t size; +} list_t; + +/// @brief Macro used to iterate through a list. +#define listnode_foreach(it, list) \ + for (listnode_t * (it) = (list)->head; (it) != NULL; (it) = (it)->next) + +/// @brief Create a list and set head, tail to NULL, and size to 0. +list_t *list_create(); + +/// @brief Get list size. +size_t list_size(list_t *list); + +/// @brief Checks if the list is empty. +bool_t list_empty(list_t *list); + +/// @brief Insert a value at the front of list. +listnode_t *list_insert_front(list_t *list, void *value); + +/// @brief Insert a value at the back of list. +listnode_t *list_insert_back(list_t *list, void *value); + +/// @brief Insert a value at the back of list. +void list_insert_node_back(list_t *list, listnode_t *item); + +/// @brief Given a listnode, remove it from lis. +void *list_remove_node(list_t *list, listnode_t *node); + +/// @brief Remove a value at the front of list. +void *list_remove_front(list_t *list); + +/// @brief Remove a value at the back of list. +void *list_remove_back(list_t *list); + +/// @brief Searches the node of the list which points at the given value. +listnode_t *list_find(list_t *list, void *value); + +/// @brief Insert after tail of list(same as insert back). +void list_push(list_t *list, void *value); + +/// @brief Remove and return the tail of the list. +/// @details User is responsible for freeing the returned node and the value. +listnode_t *list_pop_back(list_t *list); + +/// @brief Remove and return the head of the list. +/// @details User is responsible for freeing the returned node and the value. +listnode_t *list_pop_front(list_t *list); + +/// @brief Insert before head of list(same as insert front). +void list_enqueue(list_t *list, void *value); + +/// @brief Remove and return tail of list(same as list_pop). +listnode_t *list_dequeue(list_t *list); + +/// @brief Get the value of the first element but not remove it. +void *list_peek_front(list_t *list); + +/// @brief Get the value of the last element but not remove it. +void *list_peek_back(list_t *list); + +/// @brief Destory a list. +void list_destroy(list_t *list); + +/// @brief Destroy a node of the list. +void listnode_destroy(listnode_t *node); + +/// @brief Does the list contain a value (Return -1 if list element is not +/// found). +int list_contain(list_t *list, void *value); + +/// @brief Returns the node at the given index. +listnode_t *list_get_node_by_index(list_t *list, size_t index); + +/// @brief Removes a node from the list at the given index. +void *list_remove_by_index(list_t *list, size_t index); + +/// @brief Append source at the end of target and DESTROY source. +void list_merge(list_t *target, list_t *source); diff --git a/mentos/inc/libc/list_head.h b/mentos/inc/libc/list_head.h index 2af28ec..9f2f827 100644 --- a/mentos/inc/libc/list_head.h +++ b/mentos/inc/libc/list_head.h @@ -1,129 +1,129 @@ -/// MentOS, The Mentoring Operating system project -/// @file list_head.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" - -/// @brief Structure used to implement the list_head data structure. -typedef struct list_head { - /// @brief The previous element. - struct list_head *prev; - /// @brief The subsequent element. - struct list_head *next; -} list_head; - -/// @brief Get the struct for this entry. -/// @param ptr The &struct list_head pointer. -/// @param type The type of the struct this is embedded in. -/// @param member The name of the list_head within the struct. -#define list_entry(ptr, type, member) \ - ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) - -/// @brief Iterates over a list. -/// @param pos The &struct list_head to use as a loop cursor. -/// @param head The head for your list. -#define list_for_each(pos, head) \ - for ((pos) = (head)->next; (pos) != (head); (pos) = (pos)->next) - -/// @brief Iterates over a list backwards. -/// @param pos The &struct list_head to use as a loop cursor. -/// @param head The head for your list. -#define list_for_each_prev(pos, head) \ - for ((pos) = (head)->prev; (pos) != (head); (pos) = (pos)->prev) - -/// @brief Iterates over a list safe against removal of list entry. -/// @param pos The &struct list_head to use as a loop cursor. -/// @param store Another &struct list_head to use as temporary storage. -/// @param head The head for your list. -#define list_for_each_safe(pos, store, head) \ - for ((pos) = (head)->next, (store) = (pos)->next; (pos) != (head); \ - (pos) = (store), (store) = (pos)->next) - -/// @brief Initializes the list_head. -/// @param head The head for your list. -#define list_head_init(head) (head)->next = (head)->prev = (head) - -/// @brief Insert element l2 after l1. -static inline void list_head_insert_after(list_head *l1, list_head *l2) -{ - // [La]->l1 La<-[l1]->Lb <-[l2]-> l1<-[Lb] - - list_head *l1_next = l1->next; - // [La]->l1 La<-[l1]->l2 <-[l2]-> l1<-[Lb] - l1->next = l2; - // [La]->l1 La<-[l1]->l2 l1<-[l2]-> l1<-[Lb] - l2->prev = l1; - // [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l1<-[Lb] - l2->next = l1_next; - // [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l2<-[Lb] - l1_next->prev = l2; -} - -/// @brief Insert element l2 before l1. -static inline void list_head_insert_before(list_head *l1, list_head *l2) -{ - // [La]->l1 [l2] La<-[l1]->Lb l1<-[Lb] - - list_head *l1_prev = l1->prev; - // [La]->l2 [l2] La<-[l1]->Lb l1<-[Lb] - l1_prev->next = l2; - // [La]->l2 La<-[l2] La<-[l1]->Lb l1<-[Lb] - l2->prev = l1_prev; - // [La]->l2 La<-[l2]->l1 La<-[l1]->Lb l1<-[Lb] - l2->next = l1; - // [La]->l2 La<-[l2]->l1 l2<-[l1]->Lb l1<-[Lb] - l1->prev = l2; -} - -/// @brief Remove l from the list. -/// @param l The element to remove. -static inline void list_head_del(list_head *l) -{ - // [La]->l La<-[l]->Lb l<-[Lb] - - // [La]->Lb La<-[l]->Lb l<-[Lb] - l->prev->next = l->next; - // [La]->Lb La<-[l]->Lb La<-[Lb] - l->next->prev = l->prev; - // [La]->Lb l<-[l]->l La<-[Lb] - l->next = l->prev = l; -} - -/// @brief Tests whether the given list is empty. -/// @param head The list to check. -/// @return 1 if empty, 0 otherwise. -static inline int list_head_empty(list_head const *head) -{ - return head->next == head; -} - -/// Insert a new entry between two known consecutive entries. -static inline void __list_add(list_head *new, list_head *prev, list_head *next) -{ - // [prev]-> <-[new]-> <-[next] - - // [prev]-> <-[new]-> new<-[next] - next->prev = new; - // [prev]-> <-[new]->next new<-[next] - new->next = next; - // [prev]-> prev<-[new]->next new<-[next] - new->prev = prev; - // [prev]->new prev<-[new]->next new<-[next] - prev->next = new; -} - -/// @brief Insert element l2 before l1. -static inline void list_head_add(list_head *new, list_head *head) -{ - __list_add(new, head, head->next); -} - -/// @brief Insert element l2 before l1. -static inline void list_head_add_tail(list_head *new, list_head *head) -{ - __list_add(new, head->prev, head); -} +/// MentOS, The Mentoring Operating system project +/// @file list_head.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" + +/// @brief Structure used to implement the list_head data structure. +typedef struct list_head { + /// @brief The previous element. + struct list_head *prev; + /// @brief The subsequent element. + struct list_head *next; +} list_head; + +/// @brief Get the struct for this entry. +/// @param ptr The &struct list_head pointer. +/// @param type The type of the struct this is embedded in. +/// @param member The name of the list_head within the struct. +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) + +/// @brief Iterates over a list. +/// @param pos The &struct list_head to use as a loop cursor. +/// @param head The head for your list. +#define list_for_each(pos, head) \ + for ((pos) = (head)->next; (pos) != (head); (pos) = (pos)->next) + +/// @brief Iterates over a list backwards. +/// @param pos The &struct list_head to use as a loop cursor. +/// @param head The head for your list. +#define list_for_each_prev(pos, head) \ + for ((pos) = (head)->prev; (pos) != (head); (pos) = (pos)->prev) + +/// @brief Iterates over a list safe against removal of list entry. +/// @param pos The &struct list_head to use as a loop cursor. +/// @param store Another &struct list_head to use as temporary storage. +/// @param head The head for your list. +#define list_for_each_safe(pos, store, head) \ + for ((pos) = (head)->next, (store) = (pos)->next; (pos) != (head); \ + (pos) = (store), (store) = (pos)->next) + +/// @brief Initializes the list_head. +/// @param head The head for your list. +#define list_head_init(head) (head)->next = (head)->prev = (head) + +/// @brief Insert element l2 after l1. +static inline void list_head_insert_after(list_head *l1, list_head *l2) +{ + // [La]->l1 La<-[l1]->Lb <-[l2]-> l1<-[Lb] + + list_head *l1_next = l1->next; + // [La]->l1 La<-[l1]->l2 <-[l2]-> l1<-[Lb] + l1->next = l2; + // [La]->l1 La<-[l1]->l2 l1<-[l2]-> l1<-[Lb] + l2->prev = l1; + // [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l1<-[Lb] + l2->next = l1_next; + // [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l2<-[Lb] + l1_next->prev = l2; +} + +/// @brief Insert element l2 before l1. +static inline void list_head_insert_before(list_head *l1, list_head *l2) +{ + // [La]->l1 [l2] La<-[l1]->Lb l1<-[Lb] + + list_head *l1_prev = l1->prev; + // [La]->l2 [l2] La<-[l1]->Lb l1<-[Lb] + l1_prev->next = l2; + // [La]->l2 La<-[l2] La<-[l1]->Lb l1<-[Lb] + l2->prev = l1_prev; + // [La]->l2 La<-[l2]->l1 La<-[l1]->Lb l1<-[Lb] + l2->next = l1; + // [La]->l2 La<-[l2]->l1 l2<-[l1]->Lb l1<-[Lb] + l1->prev = l2; +} + +/// @brief Remove l from the list. +/// @param l The element to remove. +static inline void list_head_del(list_head *l) +{ + // [La]->l La<-[l]->Lb l<-[Lb] + + // [La]->Lb La<-[l]->Lb l<-[Lb] + l->prev->next = l->next; + // [La]->Lb La<-[l]->Lb La<-[Lb] + l->next->prev = l->prev; + // [La]->Lb l<-[l]->l La<-[Lb] + l->next = l->prev = l; +} + +/// @brief Tests whether the given list is empty. +/// @param head The list to check. +/// @return 1 if empty, 0 otherwise. +static inline int list_head_empty(list_head const *head) +{ + return head->next == head; +} + +/// Insert a new entry between two known consecutive entries. +static inline void __list_add(list_head *new, list_head *prev, list_head *next) +{ + // [prev]-> <-[new]-> <-[next] + + // [prev]-> <-[new]-> new<-[next] + next->prev = new; + // [prev]-> <-[new]->next new<-[next] + new->next = next; + // [prev]-> prev<-[new]->next new<-[next] + new->prev = prev; + // [prev]->new prev<-[new]->next new<-[next] + prev->next = new; +} + +/// @brief Insert element l2 before l1. +static inline void list_head_add(list_head *new, list_head *head) +{ + __list_add(new, head, head->next); +} + +/// @brief Insert element l2 before l1. +static inline void list_head_add_tail(list_head *new, list_head *head) +{ + __list_add(new, head->prev, head); +} diff --git a/mentos/inc/libc/math.h b/mentos/inc/libc/math.h index e41a9cc..2da9ff7 100644 --- a/mentos/inc/libc/math.h +++ b/mentos/inc/libc/math.h @@ -1,131 +1,131 @@ -/// MentOS, The Mentoring Operating system project -/// @file math.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief The absolute value. -#define abs(a) (((a) < 0) ? -(a) : (a)) - -/// @brief The max of the two values. -#define max(a, b) (((a) > (b)) ? (a) : (b)) - -/// @brief The min of the two values. -#define min(a, b) (((a) < (b)) ? (a) : (b)) - -/// @brief The sign the the passed value. -#define sign(x) ((x < 0) ? -1 : ((x > 0) ? 1 : 0)) - -/// @brief Returns a rounded up, away from zero, to the nearest multiple of b. -#define ceil(NUMBER, BASE) (((NUMBER) + (BASE)-1) & ~((BASE)-1)) - -/// @brief e -#define M_E 2.7182818284590452354 - -/// @brief log_2 e -#define M_LOG2E 1.4426950408889634074 - -/// @brief log_10 e -#define M_LOG10E 0.43429448190325182765 - -/// @brief log_e 2 -#define M_LN2 0.69314718055994530942 - -/// @brief log_e 10 -#define M_LN10 2.30258509299404568402 - -/// @brief pi -#define M_PI 3.14159265358979323846 - -/// @brief pi / 2 -#define M_PI_2 1.57079632679489661923 - -/// @brief pi / 4 -#define M_PI_4 0.78539816339744830962 - -/// @brief 1 / pi -#define M_1_PI 0.31830988618379067154 - -/// @brief 2 / pi -#define M_2_PI 0.63661977236758134308 - -/// @brief 2 / sqrt(pi) -#define M_2_SQRTPI 1.12837916709551257390 - -/// @brief sqrt(2) -#define M_SQRT2 1.41421356237309504880 - -/// @brief 1 / sqrt(2) -#define M_SQRT1_2 0.70710678118654752440 - -// TODO: doxygen comment. -/// @brief -/// @param x -/// @result -double round(double x); - -// TODO: doxygen comment. -/// @brief -/// @param x -/// @result -double floor(double x); - -/// @brief Power function. -/// @param x First number. -/// @param y Second number. -/// @result Power between number x and y. -double pow(double x, double y); - -// TODO: doxygen comment. -/// @brief -/// @param base -/// @param value -/// @result -long find_nearest_pow_greater(double base, double value); - -/// @brief Exponential function. -/// @param x Value of the exponent. -double exp(double x); - -// TODO: doxygen comment. -/// @brief -/// @param x -/// @result -double fabs(double x); - -/// @brief Square root function. -/// @param x Topic of the square root. -double sqrt(double x); - -// TODO: doxygen comment. -/// @brief -/// @param x -/// @result -int isinf(double x); - -// TODO: doxygen comment. -/// @brief -/// @param x -/// @result -int isnan(double x); - -/// @brief Logarithm function in base 10. -/// @param x Topic of the logarithm function. -double log10(double x); - -/// @brief Natural logarithm function. -/// @param x Topic of the logarithm function. -double ln(double x); - -/// @brief Logarithm function in base x. -/// @brief x Base of the logarithm. -/// @param y Topic of the logarithm function. -double logx(double x, double y); - -/// @brief Breaks x into an integral and a fractional part. -/// The integer part is stored in the object pointed by intpart, and the -/// fractional part is returned by the function. Both parts have the same -/// sign as x. -double modf(double x, double *intpart); +/// MentOS, The Mentoring Operating system project +/// @file math.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief The absolute value. +#define abs(a) (((a) < 0) ? -(a) : (a)) + +/// @brief The max of the two values. +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +/// @brief The min of the two values. +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +/// @brief The sign the the passed value. +#define sign(x) ((x < 0) ? -1 : ((x > 0) ? 1 : 0)) + +/// @brief Returns a rounded up, away from zero, to the nearest multiple of b. +#define ceil(NUMBER, BASE) (((NUMBER) + (BASE)-1) & ~((BASE)-1)) + +/// @brief e +#define M_E 2.7182818284590452354 + +/// @brief log_2 e +#define M_LOG2E 1.4426950408889634074 + +/// @brief log_10 e +#define M_LOG10E 0.43429448190325182765 + +/// @brief log_e 2 +#define M_LN2 0.69314718055994530942 + +/// @brief log_e 10 +#define M_LN10 2.30258509299404568402 + +/// @brief pi +#define M_PI 3.14159265358979323846 + +/// @brief pi / 2 +#define M_PI_2 1.57079632679489661923 + +/// @brief pi / 4 +#define M_PI_4 0.78539816339744830962 + +/// @brief 1 / pi +#define M_1_PI 0.31830988618379067154 + +/// @brief 2 / pi +#define M_2_PI 0.63661977236758134308 + +/// @brief 2 / sqrt(pi) +#define M_2_SQRTPI 1.12837916709551257390 + +/// @brief sqrt(2) +#define M_SQRT2 1.41421356237309504880 + +/// @brief 1 / sqrt(2) +#define M_SQRT1_2 0.70710678118654752440 + +// TODO: doxygen comment. +/// @brief +/// @param x +/// @result +double round(double x); + +// TODO: doxygen comment. +/// @brief +/// @param x +/// @result +double floor(double x); + +/// @brief Power function. +/// @param x First number. +/// @param y Second number. +/// @result Power between number x and y. +double pow(double x, double y); + +// TODO: doxygen comment. +/// @brief +/// @param base +/// @param value +/// @result +long find_nearest_pow_greater(double base, double value); + +/// @brief Exponential function. +/// @param x Value of the exponent. +double exp(double x); + +// TODO: doxygen comment. +/// @brief +/// @param x +/// @result +double fabs(double x); + +/// @brief Square root function. +/// @param x Topic of the square root. +double sqrt(double x); + +// TODO: doxygen comment. +/// @brief +/// @param x +/// @result +int isinf(double x); + +// TODO: doxygen comment. +/// @brief +/// @param x +/// @result +int isnan(double x); + +/// @brief Logarithm function in base 10. +/// @param x Topic of the logarithm function. +double log10(double x); + +/// @brief Natural logarithm function. +/// @param x Topic of the logarithm function. +double ln(double x); + +/// @brief Logarithm function in base x. +/// @brief x Base of the logarithm. +/// @param y Topic of the logarithm function. +double logx(double x, double y); + +/// @brief Breaks x into an integral and a fractional part. +/// The integer part is stored in the object pointed by intpart, and the +/// fractional part is returned by the function. Both parts have the same +/// sign as x. +double modf(double x, double *intpart); diff --git a/mentos/inc/libc/mutex.h b/mentos/inc/libc/mutex.h index a32927d..ace98fc 100644 --- a/mentos/inc/libc/mutex.h +++ b/mentos/inc/libc/mutex.h @@ -1,26 +1,26 @@ -/// MentOS, The Mentoring Operating system project -/// @file mutex.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @brief Structure of a mutex. -typedef struct mutex_t { - /// The state of the mutex. - uint8_t state; - /// The owner of the mutex. - uint32_t owner; -} mutex_t; - -/// @brief Allows to lock a mutex. -/// @param mutex The mutex to lock. -/// @param owner The one who request the lock. -void mutex_lock(mutex_t *mutex, uint32_t owner); - -/// @brief Unlocks the mutex. -/// @param mutex The mutex to unlock. -void mutex_unlock(mutex_t *mutex); +/// MentOS, The Mentoring Operating system project +/// @file mutex.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @brief Structure of a mutex. +typedef struct mutex_t { + /// The state of the mutex. + uint8_t state; + /// The owner of the mutex. + uint32_t owner; +} mutex_t; + +/// @brief Allows to lock a mutex. +/// @param mutex The mutex to lock. +/// @param owner The one who request the lock. +void mutex_lock(mutex_t *mutex, uint32_t owner); + +/// @brief Unlocks the mutex. +/// @param mutex The mutex to unlock. +void mutex_unlock(mutex_t *mutex); diff --git a/mentos/inc/libc/ordered_array.h b/mentos/inc/libc/ordered_array.h index b4cf225..630655a 100644 --- a/mentos/inc/libc/ordered_array.h +++ b/mentos/inc/libc/ordered_array.h @@ -1,53 +1,53 @@ -/// MentOS, The Mentoring Operating system project -/// @file ordered_array.h -/// @brief Interface for creating, inserting and deleting from ordered arrays. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" - -/// @brief This array is insertion sorted - it always remains in a sorted -/// state (between calls). It can store anything that can be cast to a -/// void* -- so a uint32_t, or any pointer. -typedef void *array_type_t; - -/// @brief A predicate should return nonzero if the first argument is less -/// than the second. Else it should return zero. -typedef int8_t (*lessthan_predicate_t)(array_type_t, array_type_t); - -/// @brief Structure which holds information concerning an ordered array. -typedef struct ordered_array_t { - /// Pointer to the array. - array_type_t *array; - /// The size of the array. - uint32_t size; - /// The maximum size of the array. - uint32_t max_size; - /// Ordering fucntion. - lessthan_predicate_t less_than; -} ordered_array_t; - -/// @brief A standard less than predicate. -int8_t standard_lessthan_predicate(array_type_t a, array_type_t b); - -/// @brief Create an ordered array. -ordered_array_t create_ordered_array(uint32_t max_size, - lessthan_predicate_t less_than); - -/// @brief Set the ordered array. -ordered_array_t place_ordered_array(void *addr, uint32_t max_size, - lessthan_predicate_t less_than); - -/// @brief Destroy an ordered array. -void destroy_ordered_array(ordered_array_t *array); - -/// @brief Add an item into the array. -void insert_ordered_array(array_type_t item, ordered_array_t *array); - -/// @brief Lookup the item at index i. -array_type_t lookup_ordered_array(uint32_t i, ordered_array_t *array); - -/// @brief Deletes the item at location i from the array. -void remove_ordered_array(uint32_t i, ordered_array_t *array); +/// MentOS, The Mentoring Operating system project +/// @file ordered_array.h +/// @brief Interface for creating, inserting and deleting from ordered arrays. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" + +/// @brief This array is insertion sorted - it always remains in a sorted +/// state (between calls). It can store anything that can be cast to a +/// void* -- so a uint32_t, or any pointer. +typedef void *array_type_t; + +/// @brief A predicate should return nonzero if the first argument is less +/// than the second. Else it should return zero. +typedef int8_t (*lessthan_predicate_t)(array_type_t, array_type_t); + +/// @brief Structure which holds information concerning an ordered array. +typedef struct ordered_array_t { + /// Pointer to the array. + array_type_t *array; + /// The size of the array. + uint32_t size; + /// The maximum size of the array. + uint32_t max_size; + /// Ordering fucntion. + lessthan_predicate_t less_than; +} ordered_array_t; + +/// @brief A standard less than predicate. +int8_t standard_lessthan_predicate(array_type_t a, array_type_t b); + +/// @brief Create an ordered array. +ordered_array_t create_ordered_array(uint32_t max_size, + lessthan_predicate_t less_than); + +/// @brief Set the ordered array. +ordered_array_t place_ordered_array(void *addr, uint32_t max_size, + lessthan_predicate_t less_than); + +/// @brief Destroy an ordered array. +void destroy_ordered_array(ordered_array_t *array); + +/// @brief Add an item into the array. +void insert_ordered_array(array_type_t item, ordered_array_t *array); + +/// @brief Lookup the item at index i. +array_type_t lookup_ordered_array(uint32_t i, ordered_array_t *array); + +/// @brief Deletes the item at location i from the array. +void remove_ordered_array(uint32_t i, ordered_array_t *array); diff --git a/mentos/inc/libc/queue.h b/mentos/inc/libc/queue.h index 599d507..fa5f8ab 100644 --- a/mentos/inc/libc/queue.h +++ b/mentos/inc/libc/queue.h @@ -1,76 +1,76 @@ -/// MentOS, The Mentoring Operating system project -/// @file queue.h -/// @brief Implementation of queue data structure. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" -#include "stdbool.h" - -/// @brief A node of the queue. -typedef struct queue_node_t { - /// The wrapped data. - void *data; - /// The next node of the queue. - struct queue_node_t *next; -} queue_node_t; - -/// @brief The queue. -typedef struct queue_t { - /// The front of the queue. - queue_node_t *front; - /// The back of the queue. - queue_node_t *back; - /// The size of the data contained inside the queue. - size_t data_size; -} * queue_t; - -/// @brief Creates a queue. -/// @param data_size The size of the stored elements. -/// @return The created queue. -queue_t queue_create(size_t data_size); - -/// @brief Destroys the queue. -/// @param queue The queue to be destroyed. -/// @return If the queue is destroyed. -bool_t queue_destroy(queue_t queue); - -/// @brief Returns if the queue is empty. -/// @param queue The queue. -bool_t queue_is_empty(queue_t queue); - -/// @brief Allows to add data to the queue. -/// @param queue The queue. -/// @param data The data to add. -/// @return If the data has been pushed inside the queue. -bool_t queue_enqueue(queue_t queue, void *data); - -/// @brief Removes the first element of the queue. -/// @param queue The queue. -/// @return If the data has been removed. -bool_t queue_dequeue(queue_t queue); - -/// @brief Returns the first element of the queue. -/// @param queue The queue. -/// @param data The data. -/// @return If the data has been correctly retrieved. -bool_t queue_front(queue_t queue, void *data); - -/// @brief Returns the last element of the queue. -/// @param queue The queue. -/// @param data The data. -/// @return If the data has been correctly retrieved. -bool_t queue_back(queue_t queue, void *data); - -/// @brief Returns the first element of the queue and removes it. -/// @param queue The queue. -/// @param data The data. -/// @return If the data has been correctly retrieved. -bool_t queue_front_and_dequeue(queue_t queue, void *data); - -/// @brief Deletes all the elements inside the queue. -/// @param queue The queue. -/// @return If the queue has been cleared. -bool_t queue_clear(queue_t queue); +/// MentOS, The Mentoring Operating system project +/// @file queue.h +/// @brief Implementation of queue data structure. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" +#include "stdbool.h" + +/// @brief A node of the queue. +typedef struct queue_node_t { + /// The wrapped data. + void *data; + /// The next node of the queue. + struct queue_node_t *next; +} queue_node_t; + +/// @brief The queue. +typedef struct queue_t { + /// The front of the queue. + queue_node_t *front; + /// The back of the queue. + queue_node_t *back; + /// The size of the data contained inside the queue. + size_t data_size; +} * queue_t; + +/// @brief Creates a queue. +/// @param data_size The size of the stored elements. +/// @return The created queue. +queue_t queue_create(size_t data_size); + +/// @brief Destroys the queue. +/// @param queue The queue to be destroyed. +/// @return If the queue is destroyed. +bool_t queue_destroy(queue_t queue); + +/// @brief Returns if the queue is empty. +/// @param queue The queue. +bool_t queue_is_empty(queue_t queue); + +/// @brief Allows to add data to the queue. +/// @param queue The queue. +/// @param data The data to add. +/// @return If the data has been pushed inside the queue. +bool_t queue_enqueue(queue_t queue, void *data); + +/// @brief Removes the first element of the queue. +/// @param queue The queue. +/// @return If the data has been removed. +bool_t queue_dequeue(queue_t queue); + +/// @brief Returns the first element of the queue. +/// @param queue The queue. +/// @param data The data. +/// @return If the data has been correctly retrieved. +bool_t queue_front(queue_t queue, void *data); + +/// @brief Returns the last element of the queue. +/// @param queue The queue. +/// @param data The data. +/// @return If the data has been correctly retrieved. +bool_t queue_back(queue_t queue, void *data); + +/// @brief Returns the first element of the queue and removes it. +/// @param queue The queue. +/// @param data The data. +/// @return If the data has been correctly retrieved. +bool_t queue_front_and_dequeue(queue_t queue, void *data); + +/// @brief Deletes all the elements inside the queue. +/// @param queue The queue. +/// @return If the queue has been cleared. +bool_t queue_clear(queue_t queue); diff --git a/mentos/inc/libc/rbtree.h b/mentos/inc/libc/rbtree.h index b2c9806..e8ecf64 100644 --- a/mentos/inc/libc/rbtree.h +++ b/mentos/inc/libc/rbtree.h @@ -1,134 +1,134 @@ -/// MentOS, The Mentoring Operating system project -/// @file rbtree.h -/// @brief Implementation of red black tree data structure. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" - -#ifndef RBTREE_ITER_MAX_HEIGHT - -/// Tallest allowable tree to iterate. -#define RBTREE_ITER_MAX_HEIGHT 64 -#endif - -//============================================================================== -// Opaque types. - -// TODO: doxygen comment. -typedef struct rbtree_t rbtree_t; - -// TODO: doxygen comment. -typedef struct rbtree_node_t rbtree_node_t; - -// TODO: doxygen comment. -typedef struct rbtree_iter_t rbtree_iter_t; - -//============================================================================== -// Comparison functions. - -// TODO: doxygen comment. -typedef int (*rbtree_tree_cmp_f)(rbtree_t *self, rbtree_node_t *a, void *arg); - -// TODO: doxygen comment. -typedef int (*rbtree_tree_node_cmp_f)(rbtree_t *self, rbtree_node_t *a, - rbtree_node_t *b); - -// TODO: doxygen comment. -typedef void (*rbtree_tree_node_f)(rbtree_t *self, rbtree_node_t *node); - -//============================================================================== -// Node management functions. - -// TODO: doxygen comment. -rbtree_node_t *rbtree_node_alloc(); - -// TODO: doxygen comment. -rbtree_node_t *rbtree_node_create(void *value); - -// TODO: doxygen comment. -rbtree_node_t *rbtree_node_init(rbtree_node_t *self, void *value); - -// TODO: doxygen comment. -void *rbtree_node_get_value(rbtree_node_t *self); - -// TODO: doxygen comment. -void rbtree_node_dealloc(rbtree_node_t *self); - -//============================================================================== -// Tree management functions. - -// TODO: doxygen comment. -rbtree_t *rbtree_tree_alloc(); - -// TODO: doxygen comment. -rbtree_t *rbtree_tree_create(rbtree_tree_node_cmp_f cmp); - -// TODO: doxygen comment. -rbtree_t *rbtree_tree_init(rbtree_t *self, rbtree_tree_node_cmp_f cmp); - -// TODO: doxygen comment. -void rbtree_tree_dealloc(rbtree_t *self, rbtree_tree_node_f node_cb); - -// TODO: doxygen comment. -void *rbtree_tree_find(rbtree_t *self, void *value); - -// TODO: doxygen comment. -void *rbtree_tree_find_by_value(rbtree_t *self, rbtree_tree_cmp_f cmp_fun, - void *value); - -// TODO: doxygen comment. -int rbtree_tree_insert(rbtree_t *self, void *value); - -// TODO: doxygen comment. -int rbtree_tree_remove(rbtree_t *self, void *value); - -// TODO: doxygen comment. -size_t rbtree_tree_size(rbtree_t *self); - -// TODO: doxygen comment. -int rbtree_tree_insert_node(rbtree_t *self, rbtree_node_t *node); - -// TODO: doxygen comment. -int rbtree_tree_remove_with_cb(rbtree_t *self, void *value, - rbtree_tree_node_f node_cb); - -//============================================================================== -// Iterators. - -// TODO: doxygen comment. -rbtree_iter_t *rbtree_iter_alloc(); - -// TODO: doxygen comment. -rbtree_iter_t *rbtree_iter_init(rbtree_iter_t *self); - -// TODO: doxygen comment. -rbtree_iter_t *rbtree_iter_create(); - -// TODO: doxygen comment. -void rbtree_iter_dealloc(rbtree_iter_t *self); - -// TODO: doxygen comment. -void *rbtree_iter_first(rbtree_iter_t *self, rbtree_t *tree); - -// TODO: doxygen comment. -void *rbtree_iter_last(rbtree_iter_t *self, rbtree_t *tree); - -// TODO: doxygen comment. -void *rbtree_iter_next(rbtree_iter_t *self); - -// TODO: doxygen comment. -void *rbtree_iter_prev(rbtree_iter_t *self); - -//============================================================================== -// Tree debugging functions. - -// TODO: doxygen comment. -int rbtree_tree_test(rbtree_t *self, rbtree_node_t *root); - -// TODO: doxygen comment. -void rbtree_tree_print(rbtree_t *self, rbtree_tree_node_f fun); - -//============================================================================== +/// MentOS, The Mentoring Operating system project +/// @file rbtree.h +/// @brief Implementation of red black tree data structure. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" + +#ifndef RBTREE_ITER_MAX_HEIGHT + +/// Tallest allowable tree to iterate. +#define RBTREE_ITER_MAX_HEIGHT 64 +#endif + +//============================================================================== +// Opaque types. + +// TODO: doxygen comment. +typedef struct rbtree_t rbtree_t; + +// TODO: doxygen comment. +typedef struct rbtree_node_t rbtree_node_t; + +// TODO: doxygen comment. +typedef struct rbtree_iter_t rbtree_iter_t; + +//============================================================================== +// Comparison functions. + +// TODO: doxygen comment. +typedef int (*rbtree_tree_cmp_f)(rbtree_t *self, rbtree_node_t *a, void *arg); + +// TODO: doxygen comment. +typedef int (*rbtree_tree_node_cmp_f)(rbtree_t *self, rbtree_node_t *a, + rbtree_node_t *b); + +// TODO: doxygen comment. +typedef void (*rbtree_tree_node_f)(rbtree_t *self, rbtree_node_t *node); + +//============================================================================== +// Node management functions. + +// TODO: doxygen comment. +rbtree_node_t *rbtree_node_alloc(); + +// TODO: doxygen comment. +rbtree_node_t *rbtree_node_create(void *value); + +// TODO: doxygen comment. +rbtree_node_t *rbtree_node_init(rbtree_node_t *self, void *value); + +// TODO: doxygen comment. +void *rbtree_node_get_value(rbtree_node_t *self); + +// TODO: doxygen comment. +void rbtree_node_dealloc(rbtree_node_t *self); + +//============================================================================== +// Tree management functions. + +// TODO: doxygen comment. +rbtree_t *rbtree_tree_alloc(); + +// TODO: doxygen comment. +rbtree_t *rbtree_tree_create(rbtree_tree_node_cmp_f cmp); + +// TODO: doxygen comment. +rbtree_t *rbtree_tree_init(rbtree_t *self, rbtree_tree_node_cmp_f cmp); + +// TODO: doxygen comment. +void rbtree_tree_dealloc(rbtree_t *self, rbtree_tree_node_f node_cb); + +// TODO: doxygen comment. +void *rbtree_tree_find(rbtree_t *self, void *value); + +// TODO: doxygen comment. +void *rbtree_tree_find_by_value(rbtree_t *self, rbtree_tree_cmp_f cmp_fun, + void *value); + +// TODO: doxygen comment. +int rbtree_tree_insert(rbtree_t *self, void *value); + +// TODO: doxygen comment. +int rbtree_tree_remove(rbtree_t *self, void *value); + +// TODO: doxygen comment. +size_t rbtree_tree_size(rbtree_t *self); + +// TODO: doxygen comment. +int rbtree_tree_insert_node(rbtree_t *self, rbtree_node_t *node); + +// TODO: doxygen comment. +int rbtree_tree_remove_with_cb(rbtree_t *self, void *value, + rbtree_tree_node_f node_cb); + +//============================================================================== +// Iterators. + +// TODO: doxygen comment. +rbtree_iter_t *rbtree_iter_alloc(); + +// TODO: doxygen comment. +rbtree_iter_t *rbtree_iter_init(rbtree_iter_t *self); + +// TODO: doxygen comment. +rbtree_iter_t *rbtree_iter_create(); + +// TODO: doxygen comment. +void rbtree_iter_dealloc(rbtree_iter_t *self); + +// TODO: doxygen comment. +void *rbtree_iter_first(rbtree_iter_t *self, rbtree_t *tree); + +// TODO: doxygen comment. +void *rbtree_iter_last(rbtree_iter_t *self, rbtree_t *tree); + +// TODO: doxygen comment. +void *rbtree_iter_next(rbtree_iter_t *self); + +// TODO: doxygen comment. +void *rbtree_iter_prev(rbtree_iter_t *self); + +//============================================================================== +// Tree debugging functions. + +// TODO: doxygen comment. +int rbtree_tree_test(rbtree_t *self, rbtree_node_t *root); + +// TODO: doxygen comment. +void rbtree_tree_print(rbtree_t *self, rbtree_tree_node_f fun); + +//============================================================================== diff --git a/mentos/inc/libc/spinlock.h b/mentos/inc/libc/spinlock.h index 5976c70..d4f79b4 100644 --- a/mentos/inc/libc/spinlock.h +++ b/mentos/inc/libc/spinlock.h @@ -1,32 +1,32 @@ -/// MentOS, The Mentoring Operating system project -/// @file spinlock.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "debug.h" -#include "stddef.h" -#include "irqflags.h" -#include "stdatomic.h" -#include "scheduler.h" - -#define SPINLOCK_FREE 0 - -#define SPINLOCK_BUSY 1 - -/// @brief Spinlock structure. -typedef atomic_t spinlock_t; - -/// @brief Initialize the spinlock. -void spinlock_init(spinlock_t *spinlock); - -/// @brief Try to lock the spinlock. -void spinlock_lock(spinlock_t *spinlock); - -/// @brief Try to unlock the spinlock. -void spinlock_unlock(spinlock_t *spinlock); - -/// @brief Try to unlock the spinlock. -bool_t spinlock_trylock(spinlock_t *spinlock); +/// MentOS, The Mentoring Operating system project +/// @file spinlock.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "debug.h" +#include "stddef.h" +#include "irqflags.h" +#include "stdatomic.h" +#include "scheduler.h" + +#define SPINLOCK_FREE 0 + +#define SPINLOCK_BUSY 1 + +/// @brief Spinlock structure. +typedef atomic_t spinlock_t; + +/// @brief Initialize the spinlock. +void spinlock_init(spinlock_t *spinlock); + +/// @brief Try to lock the spinlock. +void spinlock_lock(spinlock_t *spinlock); + +/// @brief Try to unlock the spinlock. +void spinlock_unlock(spinlock_t *spinlock); + +/// @brief Try to unlock the spinlock. +bool_t spinlock_trylock(spinlock_t *spinlock); diff --git a/mentos/inc/libc/stdarg.h b/mentos/inc/libc/stdarg.h index 6890b22..e25c8d0 100644 --- a/mentos/inc/libc/stdarg.h +++ b/mentos/inc/libc/stdarg.h @@ -1,28 +1,28 @@ -/// MentOS, The Mentoring Operating system project -/// @file stdarg.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief The va_list type is an array containing a single element of one -/// structure containing the necessary information to implement the -/// va_arg macro. -typedef char *va_list; - -/// @brief The type of the item on the stack. -#define va_item int - -/// @brief Amount of space required in an argument list (ie. the stack) for an -/// argument of type t. -#define va_size(t) \ - (((sizeof(t) + sizeof(va_item) - 1) / sizeof(va_item)) * sizeof(va_item)) - -/// @brief The start of a variadic list. -#define va_start(ap, last_arg) (ap = ((va_list)(&last_arg) + va_size(last_arg))) -/// @brief The end of a variadic list. -#define va_end(ap) ((void)0) - -/// @brief The argument of a variadic list. -#define va_arg(ap, t) (ap += va_size(t), *((t *)(ap - va_size(t)))) +/// MentOS, The Mentoring Operating system project +/// @file stdarg.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief The va_list type is an array containing a single element of one +/// structure containing the necessary information to implement the +/// va_arg macro. +typedef char *va_list; + +/// @brief The type of the item on the stack. +#define va_item int + +/// @brief Amount of space required in an argument list (ie. the stack) for an +/// argument of type t. +#define va_size(t) \ + (((sizeof(t) + sizeof(va_item) - 1) / sizeof(va_item)) * sizeof(va_item)) + +/// @brief The start of a variadic list. +#define va_start(ap, last_arg) (ap = ((va_list)(&last_arg) + va_size(last_arg))) +/// @brief The end of a variadic list. +#define va_end(ap) ((void)0) + +/// @brief The argument of a variadic list. +#define va_arg(ap, t) (ap += va_size(t), *((t *)(ap - va_size(t)))) diff --git a/mentos/inc/libc/stdatomic.h b/mentos/inc/libc/stdatomic.h index 8ec33ff..93bb31c 100644 --- a/mentos/inc/libc/stdatomic.h +++ b/mentos/inc/libc/stdatomic.h @@ -1,109 +1,109 @@ -/// MentOS, The Mentoring Operating system project -/// @file stdatomic.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" -#include "stdbool.h" -#include "compiler.h" - -/// @brief Standard structure for atomic operations. -typedef volatile unsigned atomic_t; - -/// @brief At declaration, initialize an atomic_t to i. -#define ATOMIC_INIT(i) \ - { \ - (i) \ - } - -/// @brief The prefix used to lock. -#define LOCK_PREFIX "\n\tlock; " - -/// @brief Compile read-write barrier. -#define barrier() asm volatile("" : : : "memory") - -/// @brief Pause instruction to prevent excess processor bus usage. -#define cpu_relax() asm volatile("pause\n" : : : "memory") - -// TODO: doxygen comment. -inline static int32_t atomic_set_and_test(atomic_t const *ptr, int32_t i) -{ - __asm__ __volatile__("xchgl %0,%1" - : "=r"(i) - : "m"(*(volatile unsigned *)ptr), "0"(i) - : "memory"); - // __asm__ __volatile__("xchgl %0, %1" : "=r"(i) : "m"(ptr), "0"(i) : "memory"); - return i; -} - -/// @brief Atomically set ptr equal to i. -inline static void atomic_set(atomic_t *ptr, int32_t i) -{ - atomic_set_and_test(ptr, i); -} - -/// @brief Atomically read the integer value of ptr. -inline static int32_t atomic_read(const atomic_t *ptr) -{ - return READ_ONCE(*ptr); -} - -/// @brief Atomically add i to ptr. -inline static int32_t atomic_add(atomic_t const *ptr, int32_t i) -{ - int result = i; - asm volatile(LOCK_PREFIX "xaddl %0, %1" - : "=r"(i) - : "m"(ptr), "0"(i) - : "memory", "cc"); - return result + i; -} - -/// @brief Atomically subtract i from ptr. -inline static int32_t atomic_sub(atomic_t *ptr, int32_t i) -{ - return atomic_add(ptr, -i); -} - -/// @brief Atomically add one to ptr. -inline static int32_t atomic_inc(atomic_t *ptr) -{ - return atomic_add(ptr, 1); -} - -/// @brief Atomically subtract one from ptr. -inline static int32_t atomic_dec(atomic_t *ptr) -{ - return atomic_add(ptr, -1); -} - -/// @brief Atomically add i to ptr and return true if the result is negative; -/// otherwise false. -inline static bool_t atomic_add_negative(atomic_t *ptr, int32_t i) -{ - return (bool_t)(atomic_add(ptr, i) < 0); -} - -/// @brief Atomically subtract i from ptr and return true if the result is -/// zero; otherwise false. -inline static bool_t atomic_sub_and_test(atomic_t *ptr, int32_t i) -{ - return (bool_t)(atomic_sub(ptr, i) == 0); -} - -/// @brief Atomically increment ptr by one and return true if the result is -/// zero; false otherwise. -inline static int32_t atomic_inc_and_test(atomic_t *ptr) -{ - return (bool_t)(atomic_inc(ptr) == 0); -} - -/// @brief Atomically decrement ptr by one and return true if zero; false -/// otherwise. -inline static int32_t atomic_dec_and_test(atomic_t *ptr) -{ - return (bool_t)(atomic_dec(ptr) == 0); -} +/// MentOS, The Mentoring Operating system project +/// @file stdatomic.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" +#include "stdbool.h" +#include "compiler.h" + +/// @brief Standard structure for atomic operations. +typedef volatile unsigned atomic_t; + +/// @brief At declaration, initialize an atomic_t to i. +#define ATOMIC_INIT(i) \ + { \ + (i) \ + } + +/// @brief The prefix used to lock. +#define LOCK_PREFIX "\n\tlock; " + +/// @brief Compile read-write barrier. +#define barrier() asm volatile("" : : : "memory") + +/// @brief Pause instruction to prevent excess processor bus usage. +#define cpu_relax() asm volatile("pause\n" : : : "memory") + +// TODO: doxygen comment. +inline static int32_t atomic_set_and_test(atomic_t const *ptr, int32_t i) +{ + __asm__ __volatile__("xchgl %0,%1" + : "=r"(i) + : "m"(*(volatile unsigned *)ptr), "0"(i) + : "memory"); + // __asm__ __volatile__("xchgl %0, %1" : "=r"(i) : "m"(ptr), "0"(i) : "memory"); + return i; +} + +/// @brief Atomically set ptr equal to i. +inline static void atomic_set(atomic_t *ptr, int32_t i) +{ + atomic_set_and_test(ptr, i); +} + +/// @brief Atomically read the integer value of ptr. +inline static int32_t atomic_read(const atomic_t *ptr) +{ + return READ_ONCE(*ptr); +} + +/// @brief Atomically add i to ptr. +inline static int32_t atomic_add(atomic_t const *ptr, int32_t i) +{ + int result = i; + asm volatile(LOCK_PREFIX "xaddl %0, %1" + : "=r"(i) + : "m"(ptr), "0"(i) + : "memory", "cc"); + return result + i; +} + +/// @brief Atomically subtract i from ptr. +inline static int32_t atomic_sub(atomic_t *ptr, int32_t i) +{ + return atomic_add(ptr, -i); +} + +/// @brief Atomically add one to ptr. +inline static int32_t atomic_inc(atomic_t *ptr) +{ + return atomic_add(ptr, 1); +} + +/// @brief Atomically subtract one from ptr. +inline static int32_t atomic_dec(atomic_t *ptr) +{ + return atomic_add(ptr, -1); +} + +/// @brief Atomically add i to ptr and return true if the result is negative; +/// otherwise false. +inline static bool_t atomic_add_negative(atomic_t *ptr, int32_t i) +{ + return (bool_t)(atomic_add(ptr, i) < 0); +} + +/// @brief Atomically subtract i from ptr and return true if the result is +/// zero; otherwise false. +inline static bool_t atomic_sub_and_test(atomic_t *ptr, int32_t i) +{ + return (bool_t)(atomic_sub(ptr, i) == 0); +} + +/// @brief Atomically increment ptr by one and return true if the result is +/// zero; false otherwise. +inline static int32_t atomic_inc_and_test(atomic_t *ptr) +{ + return (bool_t)(atomic_inc(ptr) == 0); +} + +/// @brief Atomically decrement ptr by one and return true if zero; false +/// otherwise. +inline static int32_t atomic_dec_and_test(atomic_t *ptr) +{ + return (bool_t)(atomic_dec(ptr) == 0); +} diff --git a/mentos/inc/libc/stdbool.h b/mentos/inc/libc/stdbool.h index 9a52976..5518b26 100644 --- a/mentos/inc/libc/stdbool.h +++ b/mentos/inc/libc/stdbool.h @@ -1,16 +1,16 @@ -/// MentOS, The Mentoring Operating system project -/// @file stdbool.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief Define boolean value. -typedef enum bool_t -{ - /// [0] False. - false, - /// [1] True. - true -} __attribute__ ((__packed__)) bool_t; +/// MentOS, The Mentoring Operating system project +/// @file stdbool.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief Define boolean value. +typedef enum bool_t +{ + /// [0] False. + false, + /// [1] True. + true +} __attribute__ ((__packed__)) bool_t; diff --git a/mentos/inc/libc/stddef.h b/mentos/inc/libc/stddef.h index 9098592..e91c897 100644 --- a/mentos/inc/libc/stddef.h +++ b/mentos/inc/libc/stddef.h @@ -1,87 +1,87 @@ -/// MentOS, The Mentoring Operating system project -/// @file stddef.h -/// @brief Define basic data types. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#ifndef NULL - -/// @brief Define NULL. -#define NULL ((void *)0) - -#endif - -#ifndef EOF - -/// @brief Define End-Of-File. -#define EOF (-1) - -#endif - -/// @brief Define the size of a buffer. -#define BUFSIZ 512 - -/// @brief Define the size of the kernel. -#define KERNEL_SIZE 0x200 - -#ifndef TRUE - -/// @brief Define the value of true. -#define TRUE 1 - -#endif - -#ifndef FALSE - -/// @brief Define the value of false. -#define FALSE 0 - -#endif - -/// @brief Define the byte type. -typedef unsigned char byte_t; - -/// @brief Define the generic size type. -typedef unsigned long size_t; - -/// @brief Define the generic signed size type. -typedef long ssize_t; - -/// @brief Define the type of an inode. -typedef unsigned int ino_t; - -// TODO: doxygen comment. -typedef unsigned int dev_t; - -/// @brief The type of user-id. -typedef unsigned int uid_t; - -/// @brief The type of group-id. -typedef unsigned int gid_t; - -/// @brief The type of offset. -typedef unsigned int off_t; - -/// @brief The type of mode. -typedef unsigned int mode_t; - -// TODO: doxygen comment. -typedef mode_t pgprot_t; - -// TODO: doxygen comment. -typedef unsigned long int ulong; - -// TODO: doxygen comment. -typedef unsigned short int ushort; - -// TODO: doxygen comment. -typedef unsigned int uint; - -// TODO: doxygen comment. -typedef int key_t; - -// TODO: doxygen comment. -// Check with clock.h -typedef long __time_t; +/// MentOS, The Mentoring Operating system project +/// @file stddef.h +/// @brief Define basic data types. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#ifndef NULL + +/// @brief Define NULL. +#define NULL ((void *)0) + +#endif + +#ifndef EOF + +/// @brief Define End-Of-File. +#define EOF (-1) + +#endif + +/// @brief Define the size of a buffer. +#define BUFSIZ 512 + +/// @brief Define the size of the kernel. +#define KERNEL_SIZE 0x200 + +#ifndef TRUE + +/// @brief Define the value of true. +#define TRUE 1 + +#endif + +#ifndef FALSE + +/// @brief Define the value of false. +#define FALSE 0 + +#endif + +/// @brief Define the byte type. +typedef unsigned char byte_t; + +/// @brief Define the generic size type. +typedef unsigned long size_t; + +/// @brief Define the generic signed size type. +typedef long ssize_t; + +/// @brief Define the type of an inode. +typedef unsigned int ino_t; + +// TODO: doxygen comment. +typedef unsigned int dev_t; + +/// @brief The type of user-id. +typedef unsigned int uid_t; + +/// @brief The type of group-id. +typedef unsigned int gid_t; + +/// @brief The type of offset. +typedef unsigned int off_t; + +/// @brief The type of mode. +typedef unsigned int mode_t; + +// TODO: doxygen comment. +typedef mode_t pgprot_t; + +// TODO: doxygen comment. +typedef unsigned long int ulong; + +// TODO: doxygen comment. +typedef unsigned short int ushort; + +// TODO: doxygen comment. +typedef unsigned int uint; + +// TODO: doxygen comment. +typedef int key_t; + +// TODO: doxygen comment. +// Check with clock.h +typedef long __time_t; diff --git a/mentos/inc/libc/stdint.h b/mentos/inc/libc/stdint.h index fa4b624..f53033a 100644 --- a/mentos/inc/libc/stdint.h +++ b/mentos/inc/libc/stdint.h @@ -1,37 +1,37 @@ -/// MentOS, The Mentoring Operating system project -/// @file stdint.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief Define the signed 64-bit integer. -typedef int int64_t; - -/// @brief Define the unsigned 64-bit integer. -typedef unsigned int uint64_t; - -/// @brief Define the signed 32-bit integer. -typedef int int32_t; - -/// @brief Define the unsigned 32-bit integer. -typedef unsigned int uint32_t; - -/// @brief Define the signed 16-bit integer. -typedef short int16_t; - -/// @brief Define the unsigned 16-bit integer. -typedef unsigned short uint16_t; - -/// @brief Define the signed 8-bit integer. -typedef char int8_t; - -/// @brief Define the unsigned 8-bit integer. -typedef unsigned char uint8_t; - -/// @brief Define the signed 32-bit pointer. -typedef signed intptr_t; - -/// @brief Define the unsigned 32-bit pointer. -typedef unsigned uintptr_t; +/// MentOS, The Mentoring Operating system project +/// @file stdint.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief Define the signed 64-bit integer. +typedef int int64_t; + +/// @brief Define the unsigned 64-bit integer. +typedef unsigned int uint64_t; + +/// @brief Define the signed 32-bit integer. +typedef int int32_t; + +/// @brief Define the unsigned 32-bit integer. +typedef unsigned int uint32_t; + +/// @brief Define the signed 16-bit integer. +typedef short int16_t; + +/// @brief Define the unsigned 16-bit integer. +typedef unsigned short uint16_t; + +/// @brief Define the signed 8-bit integer. +typedef char int8_t; + +/// @brief Define the unsigned 8-bit integer. +typedef unsigned char uint8_t; + +/// @brief Define the signed 32-bit pointer. +typedef signed intptr_t; + +/// @brief Define the unsigned 32-bit pointer. +typedef unsigned uintptr_t; diff --git a/mentos/inc/libc/stdio.h b/mentos/inc/libc/stdio.h index 47be959..2eeb835 100644 --- a/mentos/inc/libc/stdio.h +++ b/mentos/inc/libc/stdio.h @@ -1,50 +1,50 @@ -/// MentOS, The Mentoring Operating system project -/// @file stdio.h -/// @brief Standard I/0 functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdarg.h" -#include "stddef.h" - -/// @brief The maximum number of digits of an integer. -#define MAX_DIGITS_IN_INTEGER 11 -/// @brief The size of 'gets' buffer. -#define GETS_BUFFERSIZE 255 - -#ifndef EOF -/// @brief Define the End-Of-File. -#define EOF (-1) -#endif - -/// @brief Writes the given character to the standard output (stdout). -void putchar(int character); - -/// @brief Writes the string pointed by str to the standard output (stdout) -/// and appends a newline character ('\n'). -void puts(char *str); - -/// @brief Returns the next character from the standard input (stdin). -int getchar(void); - -/// @brief Reads characters from the standard input (stdin) and stores them -/// as a C string into str until a newline character or the end-of-file is -/// reached. -char *gets(char *str); - -/// @brief Convert the given string to an integer. -int atoi(const char *str); - -/// @brief Write formatted output to stdout. -int printf(const char *, ...); - -/// @brief Read formatted input from stdin. -size_t scanf(const char *, ...); - -/// @brief Write formatted output to the string str from argument list ARG. -int vsprintf(char *str, const char *fmt, va_list args); - -/// @brief Write formatted output to the string str. -int sprintf(char *str, const char *fmt, ...); +/// MentOS, The Mentoring Operating system project +/// @file stdio.h +/// @brief Standard I/0 functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdarg.h" +#include "stddef.h" + +/// @brief The maximum number of digits of an integer. +#define MAX_DIGITS_IN_INTEGER 11 +/// @brief The size of 'gets' buffer. +#define GETS_BUFFERSIZE 255 + +#ifndef EOF +/// @brief Define the End-Of-File. +#define EOF (-1) +#endif + +/// @brief Writes the given character to the standard output (stdout). +void putchar(int character); + +/// @brief Writes the string pointed by str to the standard output (stdout) +/// and appends a newline character ('\n'). +void puts(char *str); + +/// @brief Returns the next character from the standard input (stdin). +int getchar(void); + +/// @brief Reads characters from the standard input (stdin) and stores them +/// as a C string into str until a newline character or the end-of-file is +/// reached. +char *gets(char *str); + +/// @brief Convert the given string to an integer. +int atoi(const char *str); + +/// @brief Write formatted output to stdout. +int printf(const char *, ...); + +/// @brief Read formatted input from stdin. +size_t scanf(const char *, ...); + +/// @brief Write formatted output to the string str from argument list ARG. +int vsprintf(char *str, const char *fmt, va_list args); + +/// @brief Write formatted output to the string str. +int sprintf(char *str, const char *fmt, ...); diff --git a/mentos/inc/libc/stdlib.h b/mentos/inc/libc/stdlib.h index e508a61..482d737 100644 --- a/mentos/inc/libc/stdlib.h +++ b/mentos/inc/libc/stdlib.h @@ -1,25 +1,36 @@ -/// MentOS, The Mentoring Operating system project -/// @file stdlib.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" - -/// @brief Malloc based on the number of elements. -void *calloc(size_t element_number, size_t element_size); - -void *malloc(unsigned int size); - -void free(void * p); - -/// The maximum value returned by the rand function. -#define RAND_MAX ((1U << 31U) - 1U) - -/// @brief Allows to set the seed of the random value generator. -void srand(int x); - -/// @brief Generates a random value. -int rand(); +/// MentOS, The Mentoring Operating system project +/// @file stdlib.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" + +/// @brief Malloc based on the number of elements. +void *calloc(size_t element_number, size_t element_size); + +void *malloc(unsigned int size); + +void free(void * p); + +/// @brief Allocate a matrix with n rows of a specific size. +/// @param n Number of matrix rows. +/// @param size Size of each matrix row. +/// @return Matrix pointer. +void **mmalloc(size_t n, size_t size); + +/// @brief Free a matrix of n rows. +/// @param src Matrix to free. +/// @param n Number of matrix rows. +void mfree(void **src, size_t n); + +/// The maximum value returned by the rand function. +#define RAND_MAX ((1U << 31U) - 1U) + +/// @brief Allows to set the seed of the random value generator. +void srand(int x); + +/// @brief Generates a random value. +int rand(); diff --git a/mentos/inc/libc/strerror.h b/mentos/inc/libc/strerror.h index 631db12..e5a52a6 100644 --- a/mentos/inc/libc/strerror.h +++ b/mentos/inc/libc/strerror.h @@ -1,12 +1,12 @@ -/// MentOS, The Mentoring Operating system project -/// @file strerror.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "errno.h" - -// TODO: doxygen comment. -char *strerror(int errnum); +/// MentOS, The Mentoring Operating system project +/// @file strerror.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "errno.h" + +// TODO: doxygen comment. +char *strerror(int errnum); diff --git a/mentos/inc/libc/string.h b/mentos/inc/libc/string.h index c3a4fdf..604db33 100644 --- a/mentos/inc/libc/string.h +++ b/mentos/inc/libc/string.h @@ -1,159 +1,159 @@ -/// MentOS, The Mentoring Operating system project -/// @file string.h -/// @brief String routines. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "list.h" -#include "stddef.h" - -/// @brief Copies the first num characters of source to destination. -char *strncpy(char *destination, const char *source, size_t num); - -/// @brief Compares up to n characters of s1 to those of s2. -int strncmp(const char *s1, const char *s2, size_t n); - -/// @brief Case insensitive string compare. -int stricmp(const char *s1, const char *s2); - -/// @brief Case-insensitively compare up to n characters of s1 to those of s2. -int strnicmp(const char *s1, const char *s2, size_t n); - -/// @brief Returns a pointer to the first occurrence of ch in str. -char *strchr(const char *s, int ch); - -/// @brief Returns a pointer to the last occurrence of ch in str. -char *strrchr(const char *s, int ch); - -/// @brief Returns a pointer to the first occurrence of s2 in s1, or NULL if -/// s2 is not part of s1. -char *strstr(const char *s1, const char *s2); - -/// @brief Returns the length of the initial portion of string which consists -/// only of characters that are part of control. -size_t strspn(const char *string, const char *control); - -/// @brief Calculates the length of the initial segment of string which -/// consists entirely of characters not in control. -size_t strcspn(const char *string, const char *control); - -/// @brief Finds the first character in the string string that matches any -/// character specified in control. -char *strpbrk(const char *string, const char *control); - -/// @brief Make a copy of the given string. -char *strdup(const char *s); - -/// @brief Make a copy of the given string. -char *kstrdup(const char *s); - -/// @brief Appends the string pointed to, by s2 to the end of the string -/// pointed to, by s1 up to n characters long. -char *strncat(char *s1, const char *s2, size_t n); - -/// @brief Fill the string s with the character c, to the given length n. -char *strnset(char *s, int c, size_t n); - -/// @brief Fill the string s with the character c. -char *strset(char *s, int c); - -/// @brief Reverse the string s. -char *strrev(char *s); - -// TODO: Check behaviour & doxygen comment. -char *strtok(char *str, const char *delim); - -// TODO: Check behaviour & doxygen comment. -char *strtok_r(char *string, const char *control, char **lasts); - -/// @brief Another function to copy n characters from str2 to str1. -void *memmove(void *dst, const void *src, size_t n); - -/// @brief Searches for the first occurrence of the character c (an unsigned -/// char) in the first n bytes of the string pointed to, by the -/// argument str. -void *memchr(const void *str, int c, size_t n); - -char *strlwr(char *s); - -char *strupr(char *s); - -/// @brief Copies the first n bytes from memory area src to memory area dest, -/// stopping when the character c is found. -void *memccpy(void *dst, const void *src, int c, size_t n); - -/// @brief Copy a block of memory, handling overlap. -/// @param _dst Pointer to the destination. -/// @param _src Pointer to the source. -/// @param num Number of bytes to be copied. -/// @return Pointer to the destination. -void *memcpy(void *_dst, const void *_src, size_t num); - -/// @brief Compares the first n bytes of str1 and str2. -int memcmp(const void *str1, const void *str2, size_t n); - -/// @brief Sets the first num bytes of the block of memory pointed by ptr -/// to the specified value. -/// @param ptr Pointer to the block of memory to set. -/// @param value Value to be set. -/// @param num Number of bytes to be set to the given value. -/// @return The same ptr. -void *memset(void *ptr, int value, size_t num); - -/// @brief Copy the string src into the array dst. -char *strcpy(char *dst, const char *src); - -/// @brief Appends a copy of the string src to the string dst. -char *strcat(char *dst, const char *src); - -/// @brief Checks if the two strings are equal. -int strcmp(const char *s1, const char *s2); - -/// @brief Returns the lenght of the string s. -size_t strlen(const char *s); - -/// @brief Returns the number of characters inside s, excluding the -/// terminating null byte ('\0'), but at most count. -size_t strnlen(const char *s, size_t count); - -/// @brief Separate a string in token according to the delimiter. -/// If str is NULL, the scanning will continue for the previous string. -/// It can be bettered. -char *strtok(char *str, const char *delim); - -/// @brief Compare num characters of s2 and s1. -int _kstrncmp(const char *s1, const char *s2, size_t num); - -/// @brief Removes the whitespaces in from of str. -char *trim(char *str); - -/// @brief Create a copy of str. -char *strdup(const char *src); - -/// @brief Separate stringp based on delim. -char *strsep(char **stringp, const char *delim); - -/// @brief Split a string into list of strings. -list_t *str_split(const char *str, const char *delim, unsigned int *num); - -/// @brief Reconstruct a string from list using delim as delimiter. -char *list2str(list_t *list, const char *delim); - -/// @brief Move the number "num" into a string. -/// @param buffer The string containing the number. -/// @param num The number to convert. -/// @param base The base used to convert. -void int_to_str(char *buffer, unsigned int num, unsigned int base); - -/// @brief Transforms num into a string. -void _knntos(char *buffer, int num, int base); - -/// @brief Replaces the occurences of find with replace inside str. -char *replace_char(char *str, char find, char replace); - -/// @brief Converts a file mode (the type and permission information associated -/// with an inode) into a symbolic string which is stored in the location -/// referenced by p. -void strmode(mode_t mode, char *p); +/// MentOS, The Mentoring Operating system project +/// @file string.h +/// @brief String routines. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "list.h" +#include "stddef.h" + +/// @brief Copies the first num characters of source to destination. +char *strncpy(char *destination, const char *source, size_t num); + +/// @brief Compares up to n characters of s1 to those of s2. +int strncmp(const char *s1, const char *s2, size_t n); + +/// @brief Case insensitive string compare. +int stricmp(const char *s1, const char *s2); + +/// @brief Case-insensitively compare up to n characters of s1 to those of s2. +int strnicmp(const char *s1, const char *s2, size_t n); + +/// @brief Returns a pointer to the first occurrence of ch in str. +char *strchr(const char *s, int ch); + +/// @brief Returns a pointer to the last occurrence of ch in str. +char *strrchr(const char *s, int ch); + +/// @brief Returns a pointer to the first occurrence of s2 in s1, or NULL if +/// s2 is not part of s1. +char *strstr(const char *s1, const char *s2); + +/// @brief Returns the length of the initial portion of string which consists +/// only of characters that are part of control. +size_t strspn(const char *string, const char *control); + +/// @brief Calculates the length of the initial segment of string which +/// consists entirely of characters not in control. +size_t strcspn(const char *string, const char *control); + +/// @brief Finds the first character in the string string that matches any +/// character specified in control. +char *strpbrk(const char *string, const char *control); + +/// @brief Make a copy of the given string. +char *strdup(const char *s); + +/// @brief Make a copy of the given string. +char *kstrdup(const char *s); + +/// @brief Appends the string pointed to, by s2 to the end of the string +/// pointed to, by s1 up to n characters long. +char *strncat(char *s1, const char *s2, size_t n); + +/// @brief Fill the string s with the character c, to the given length n. +char *strnset(char *s, int c, size_t n); + +/// @brief Fill the string s with the character c. +char *strset(char *s, int c); + +/// @brief Reverse the string s. +char *strrev(char *s); + +// TODO: Check behaviour & doxygen comment. +char *strtok(char *str, const char *delim); + +// TODO: Check behaviour & doxygen comment. +char *strtok_r(char *string, const char *control, char **lasts); + +/// @brief Another function to copy n characters from str2 to str1. +void *memmove(void *dst, const void *src, size_t n); + +/// @brief Searches for the first occurrence of the character c (an unsigned +/// char) in the first n bytes of the string pointed to, by the +/// argument str. +void *memchr(const void *str, int c, size_t n); + +char *strlwr(char *s); + +char *strupr(char *s); + +/// @brief Copies the first n bytes from memory area src to memory area dest, +/// stopping when the character c is found. +void *memccpy(void *dst, const void *src, int c, size_t n); + +/// @brief Copy a block of memory, handling overlap. +/// @param _dst Pointer to the destination. +/// @param _src Pointer to the source. +/// @param num Number of bytes to be copied. +/// @return Pointer to the destination. +void *memcpy(void *_dst, const void *_src, size_t num); + +/// @brief Compares the first n bytes of str1 and str2. +int memcmp(const void *str1, const void *str2, size_t n); + +/// @brief Sets the first num bytes of the block of memory pointed by ptr +/// to the specified value. +/// @param ptr Pointer to the block of memory to set. +/// @param value Value to be set. +/// @param num Number of bytes to be set to the given value. +/// @return The same ptr. +void *memset(void *ptr, int value, size_t num); + +/// @brief Copy the string src into the array dst. +char *strcpy(char *dst, const char *src); + +/// @brief Appends a copy of the string src to the string dst. +char *strcat(char *dst, const char *src); + +/// @brief Checks if the two strings are equal. +int strcmp(const char *s1, const char *s2); + +/// @brief Returns the lenght of the string s. +size_t strlen(const char *s); + +/// @brief Returns the number of characters inside s, excluding the +/// terminating null byte ('\0'), but at most count. +size_t strnlen(const char *s, size_t count); + +/// @brief Separate a string in token according to the delimiter. +/// If str is NULL, the scanning will continue for the previous string. +/// It can be bettered. +char *strtok(char *str, const char *delim); + +/// @brief Compare num characters of s2 and s1. +int _kstrncmp(const char *s1, const char *s2, size_t num); + +/// @brief Removes the whitespaces in from of str. +char *trim(char *str); + +/// @brief Create a copy of str. +char *strdup(const char *src); + +/// @brief Separate stringp based on delim. +char *strsep(char **stringp, const char *delim); + +/// @brief Split a string into list of strings. +list_t *str_split(const char *str, const char *delim, unsigned int *num); + +/// @brief Reconstruct a string from list using delim as delimiter. +char *list2str(list_t *list, const char *delim); + +/// @brief Move the number "num" into a string. +/// @param buffer The string containing the number. +/// @param num The number to convert. +/// @param base The base used to convert. +void int_to_str(char *buffer, unsigned int num, unsigned int base); + +/// @brief Transforms num into a string. +void _knntos(char *buffer, int num, int base); + +/// @brief Replaces the occurences of find with replace inside str. +char *replace_char(char *str, char find, char replace); + +/// @brief Converts a file mode (the type and permission information associated +/// with an inode) into a symbolic string which is stored in the location +/// referenced by p. +void strmode(mode_t mode, char *p); diff --git a/mentos/inc/libc/tree.h b/mentos/inc/libc/tree.h index 097a36a..d99a22c 100644 --- a/mentos/inc/libc/tree.h +++ b/mentos/inc/libc/tree.h @@ -1,77 +1,77 @@ -/// MentOS, The Mentoring Operating system project -/// @file tree.h -/// @brief General-purpose tree implementation. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "list.h" - -/// @brief A node of the tree. -typedef struct tree_node_t { - /// The value stored by the node. - void *value; - /// Pointer to the list of childrens. - list_t *children; - /// Pointer to the parent. - struct tree_node_t *parent; -} tree_node_t; - -/// @brief Represents the tree. -typedef struct tree_t { - /// Number of nodes inside the tree. - size_t nodes; - /// Pointer to the root of the tree. - tree_node_t *root; -} tree_t; - -typedef uint8_t (*tree_comparator_t)(void *, void *); - -/// @brief Creates a new tree. -tree_t *tree_create(); - -/// @brief Sets the root node for a new tree. -tree_node_t *tree_set_root(tree_t *tree, void *value); - -/// @brief Free the contents of a node and its children, -/// but not the nodes themselves. -void tree_node_destroy(tree_node_t *node); - -/// @brief Free the contents of a tree, but not the nodes. -void tree_destroy(tree_t *tree); - -/// @brief Free all of the nodes in a tree, but not their contents. -void tree_free(tree_t *tree); - -/// @brief Create a new tree node pointing to the given value. -tree_node_t *tree_node_create(void *value); - -/// @brief Insert a node as a child of parent. -void tree_node_insert_child_node(tree_t *tree, tree_node_t *parent, - tree_node_t *node); - -/// @brief Insert a (fresh) node as a child of parent. -tree_node_t *tree_node_insert_child(tree_t *tree, tree_node_t *parent, - void *value); - -/// @brief Recursive node part of tree_find_parent. -tree_node_t *tree_node_find_parent(tree_node_t *haystack, tree_node_t *needle); - -/// @brief Remove a node when we know its parent; update node counts for the -/// tree. -void tree_node_parent_remove(tree_t *tree, tree_node_t *parent, - tree_node_t *node); - -/// @brief Remove an entire branch given its root. -void tree_node_remove(tree_t *tree, tree_node_t *node); - -/// @brief Remove this node and move its children into its parent's -/// list of children. -void tree_remove(tree_t *tree, tree_node_t *node); - -// TODO: doxygen comment. -void tree_break_off(tree_t *tree, tree_node_t *node); - -/// @brief Searches the given value inside the tree. -tree_node_t *tree_find(tree_t *tree, void *value, tree_comparator_t comparator); +/// MentOS, The Mentoring Operating system project +/// @file tree.h +/// @brief General-purpose tree implementation. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "list.h" + +/// @brief A node of the tree. +typedef struct tree_node_t { + /// The value stored by the node. + void *value; + /// Pointer to the list of childrens. + list_t *children; + /// Pointer to the parent. + struct tree_node_t *parent; +} tree_node_t; + +/// @brief Represents the tree. +typedef struct tree_t { + /// Number of nodes inside the tree. + size_t nodes; + /// Pointer to the root of the tree. + tree_node_t *root; +} tree_t; + +typedef uint8_t (*tree_comparator_t)(void *, void *); + +/// @brief Creates a new tree. +tree_t *tree_create(); + +/// @brief Sets the root node for a new tree. +tree_node_t *tree_set_root(tree_t *tree, void *value); + +/// @brief Free the contents of a node and its children, +/// but not the nodes themselves. +void tree_node_destroy(tree_node_t *node); + +/// @brief Free the contents of a tree, but not the nodes. +void tree_destroy(tree_t *tree); + +/// @brief Free all of the nodes in a tree, but not their contents. +void tree_free(tree_t *tree); + +/// @brief Create a new tree node pointing to the given value. +tree_node_t *tree_node_create(void *value); + +/// @brief Insert a node as a child of parent. +void tree_node_insert_child_node(tree_t *tree, tree_node_t *parent, + tree_node_t *node); + +/// @brief Insert a (fresh) node as a child of parent. +tree_node_t *tree_node_insert_child(tree_t *tree, tree_node_t *parent, + void *value); + +/// @brief Recursive node part of tree_find_parent. +tree_node_t *tree_node_find_parent(tree_node_t *haystack, tree_node_t *needle); + +/// @brief Remove a node when we know its parent; update node counts for the +/// tree. +void tree_node_parent_remove(tree_t *tree, tree_node_t *parent, + tree_node_t *node); + +/// @brief Remove an entire branch given its root. +void tree_node_remove(tree_t *tree, tree_node_t *node); + +/// @brief Remove this node and move its children into its parent's +/// list of children. +void tree_remove(tree_t *tree, tree_node_t *node); + +// TODO: doxygen comment. +void tree_break_off(tree_t *tree, tree_node_t *node); + +/// @brief Searches the given value inside the tree. +tree_node_t *tree_find(tree_t *tree, void *value, tree_comparator_t comparator); diff --git a/mentos/inc/mem/buddysystem.h b/mentos/inc/mem/buddysystem.h index 160d0d1..32b27dd 100644 --- a/mentos/inc/mem/buddysystem.h +++ b/mentos/inc/mem/buddysystem.h @@ -1,25 +1,25 @@ -/// MentOS, The Mentoring Operating system project -/// @file buddysystem.h -/// @brief Buddy System. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "zone_allocator.h" - -/// @brief Allocate a block of page frames in a zone of size 2^{order. -/// @param zone A memory zone. -/// @param order The logarithm of the size of the block. -/// @return The address of the first page descriptor of the block, or NULL. -page_t *bb_alloc_pages(zone_t *zone, unsigned int order); - -/// @brief Free a block of page frames in a zone of size 2^{order. -/// @param zone A memory zone. -/// @param page The address of the first page descriptor of the block. -/// @param order The logarithm of the size of the block. -void bb_free_pages(zone_t *zone, page_t *page, unsigned int order); - -/// @brief Print the size of free_list of each free_area. -/// @param zone A memory zone. -void buddy_system_dump(zone_t *zone); +/// MentOS, The Mentoring Operating system project +/// @file buddysystem.h +/// @brief Buddy System. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "zone_allocator.h" + +/// @brief Allocate a block of page frames in a zone of size 2^{order. +/// @param zone A memory zone. +/// @param order The logarithm of the size of the block. +/// @return The address of the first page descriptor of the block, or NULL. +page_t *bb_alloc_pages(zone_t *zone, unsigned int order); + +/// @brief Free a block of page frames in a zone of size 2^{order. +/// @param zone A memory zone. +/// @param page The address of the first page descriptor of the block. +/// @param order The logarithm of the size of the block. +void bb_free_pages(zone_t *zone, page_t *page, unsigned int order); + +/// @brief Print the size of free_list of each free_area. +/// @param zone A memory zone. +void buddy_system_dump(zone_t *zone); diff --git a/mentos/inc/mem/gfp.h b/mentos/inc/mem/gfp.h index 602745e..5b05c01 100644 --- a/mentos/inc/mem/gfp.h +++ b/mentos/inc/mem/gfp.h @@ -1,167 +1,167 @@ -/// MentOS, The Mentoring Operating system project -/// @file gfp.h -/// @brief List of GFP Flags. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// Type used for GFP_FLAGS. -typedef unsigned int gfp_t; - -// Plain integer GFP bitmasks. Do not use this directly. -#define ___GFP_DMA 0x01u - -#define ___GFP_HIGHMEM 0x02u - -#define ___GFP_DMA32 0x04u - -#define ___GFP_RECLAIMABLE 0x10u - -#define ___GFP_HIGH 0x20u - -#define ___GFP_IO 0x40u - -#define ___GFP_FS 0x80u - -#define ___GFP_ZERO 0x100u - -#define ___GFP_ATOMIC 0x200u - -#define ___GFP_DIRECT_RECLAIM 0x400u - -#define ___GFP_KSWAPD_RECLAIM 0x800u - -/* - * Physical address zone modifiers (see linux/mmzone.h - low four bits) - * - * Do not put any conditional on these. If necessary modify the definitions - * without the underscores and use them consistently. The definitions here may - * be used in bit comparisons. - */ -#define __GFP_DMA ___GFP_DMA - -#define __GFP_HIGHMEM ___GFP_HIGHMEM - -#define __GFP_DMA32 ___GFP_DMA32 - -#define GFP_ZONEMASK (__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32) - -/** - * DOC: Watermark modifiers - * - * Watermark modifiers -- controls access to emergency reserves - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * %__GFP_HIGH indicates that the caller is high-priority and that granting - * the request is necessary before the system can make forward progress. - * For example, creating an IO context to clean pages. - * - * %__GFP_ATOMIC indicates that the caller cannot reclaim or sleep and is - * high priority. Users are typically interrupt handlers. This may be - * used in conjunction with %__GFP_HIGH - */ -#define __GFP_ATOMIC ___GFP_ATOMIC - -#define __GFP_HIGH ___GFP_HIGH - -/** - * DOC: Reclaim modifiers - * - * Reclaim modifiers - * ~~~~~~~~~~~~~~~~~ - * - * %__GFP_IO can start physical IO. - * - * %__GFP_FS can call down to the low-level FS. Clearing the flag avoids the - * allocator recursing into the filesystem which might already be holding - * locks. - * - * %__GFP_DIRECT_RECLAIM indicates that the caller may enter direct reclaim. - * This flag can be cleared to avoid unnecessary delays when a fallback - * option is available. - * - * %__GFP_KSWAPD_RECLAIM indicates that the caller wants to wake kswapd when - * the low watermark is reached and have it reclaim pages until the high - * watermark is reached. A caller may wish to clear this flag when fallback - * options are available and the reclaim is likely to disrupt the system. The - * canonical example is THP allocation where a fallback is cheap but - * reclaim/compaction may cause indirect stalls. - * - * %__GFP_RECLAIM is shorthand to allow/forbid both direct and kswapd reclaim. - */ -#define __GFP_IO ___GFP_IO - -#define __GFP_FS ___GFP_FS -// Caller can reclaim. -#define __GFP_DIRECT_RECLAIM ___GFP_DIRECT_RECLAIM - -// Kswapd can wake. -#define __GFP_KSWAPD_RECLAIM ___GFP_KSWAPD_RECLAIM - -#define __GFP_RECLAIM (___GFP_DIRECT_RECLAIM | ___GFP_KSWAPD_RECLAIM) - -/** - * DOC: Useful GFP flag combinations - * - * Useful GFP flag combinations - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Useful GFP flag combinations that are commonly used. It is recommended - * that subsystems start with one of these combinations and then set/clear - * %__GFP_FOO flags as necessary. - * - * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower - * watermark is applied to allow access to "atomic reserves" - * - * %GFP_KERNEL is typical for kernel-internal allocations. The caller requires - * %ZONE_NORMAL or a lower zone for direct access but can direct reclaim. - * - * %GFP_NOWAIT is for kernel allocations that should not stall for direct - * reclaim, start physical IO or use any filesystem callback. - * - * %GFP_NOIO will use direct reclaim to discard clean pages or slab pages - * that do not require the starting of any physical IO. - * Please try to avoid using this flag directly and instead use - * memalloc_noio_{save,restore} to mark the whole scope which cannot - * perform any IO with a short explanation why. All allocation requests - * will inherit GFP_NOIO implicitly. - * - * %GFP_NOFS will use direct reclaim but will not use any filesystem interfaces. - * Please try to avoid using this flag directly and instead use - * memalloc_nofs_{save,restore} to mark the whole scope which cannot/shouldn't - * recurse into the FS layer with a short explanation why. All allocation - * requests will inherit GFP_NOFS implicitly. - * - * %GFP_USER is for userspace allocations that also need to be directly - * accessibly by the kernel or hardware. It is typically used by hardware - * for buffers that are mapped to userspace (e.g. graphics) that hardware - * still must DMA to. cpuset limits are enforced for these allocations. - * - * %GFP_DMA exists for historical reasons and should be avoided where possible. - * The flags indicates that the caller requires that the lowest zone be - * used (%ZONE_DMA or 16M on x86-64). Ideally, this would be removed but - * it would require careful auditing as some users really require it and - * others use the flag to avoid lowmem reserves in %ZONE_DMA and treat the - * lowest zone as a type of emergency reserve. - * - * %GFP_HIGHUSER is for userspace allocations that may be mapped to userspace, - * do not need to be directly accessible by the kernel but that cannot - * move once in use. An example may be a hardware allocation that maps - * data directly into userspace but has no addressing limitations. - */ -#define GFP_ATOMIC (__GFP_HIGH | __GFP_ATOMIC | __GFP_KSWAPD_RECLAIM) - -#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) - -#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) - -#define GFP_NOIO (__GFP_RECLAIM) - -#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO) - -#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS) - -#define GFP_DMA (__GFP_DMA) - -#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM) +/// MentOS, The Mentoring Operating system project +/// @file gfp.h +/// @brief List of GFP Flags. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// Type used for GFP_FLAGS. +typedef unsigned int gfp_t; + +// Plain integer GFP bitmasks. Do not use this directly. +#define ___GFP_DMA 0x01u + +#define ___GFP_HIGHMEM 0x02u + +#define ___GFP_DMA32 0x04u + +#define ___GFP_RECLAIMABLE 0x10u + +#define ___GFP_HIGH 0x20u + +#define ___GFP_IO 0x40u + +#define ___GFP_FS 0x80u + +#define ___GFP_ZERO 0x100u + +#define ___GFP_ATOMIC 0x200u + +#define ___GFP_DIRECT_RECLAIM 0x400u + +#define ___GFP_KSWAPD_RECLAIM 0x800u + +/* + * Physical address zone modifiers (see linux/mmzone.h - low four bits) + * + * Do not put any conditional on these. If necessary modify the definitions + * without the underscores and use them consistently. The definitions here may + * be used in bit comparisons. + */ +#define __GFP_DMA ___GFP_DMA + +#define __GFP_HIGHMEM ___GFP_HIGHMEM + +#define __GFP_DMA32 ___GFP_DMA32 + +#define GFP_ZONEMASK (__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32) + +/** + * DOC: Watermark modifiers + * + * Watermark modifiers -- controls access to emergency reserves + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * %__GFP_HIGH indicates that the caller is high-priority and that granting + * the request is necessary before the system can make forward progress. + * For example, creating an IO context to clean pages. + * + * %__GFP_ATOMIC indicates that the caller cannot reclaim or sleep and is + * high priority. Users are typically interrupt handlers. This may be + * used in conjunction with %__GFP_HIGH + */ +#define __GFP_ATOMIC ___GFP_ATOMIC + +#define __GFP_HIGH ___GFP_HIGH + +/** + * DOC: Reclaim modifiers + * + * Reclaim modifiers + * ~~~~~~~~~~~~~~~~~ + * + * %__GFP_IO can start physical IO. + * + * %__GFP_FS can call down to the low-level FS. Clearing the flag avoids the + * allocator recursing into the filesystem which might already be holding + * locks. + * + * %__GFP_DIRECT_RECLAIM indicates that the caller may enter direct reclaim. + * This flag can be cleared to avoid unnecessary delays when a fallback + * option is available. + * + * %__GFP_KSWAPD_RECLAIM indicates that the caller wants to wake kswapd when + * the low watermark is reached and have it reclaim pages until the high + * watermark is reached. A caller may wish to clear this flag when fallback + * options are available and the reclaim is likely to disrupt the system. The + * canonical example is THP allocation where a fallback is cheap but + * reclaim/compaction may cause indirect stalls. + * + * %__GFP_RECLAIM is shorthand to allow/forbid both direct and kswapd reclaim. + */ +#define __GFP_IO ___GFP_IO + +#define __GFP_FS ___GFP_FS +// Caller can reclaim. +#define __GFP_DIRECT_RECLAIM ___GFP_DIRECT_RECLAIM + +// Kswapd can wake. +#define __GFP_KSWAPD_RECLAIM ___GFP_KSWAPD_RECLAIM + +#define __GFP_RECLAIM (___GFP_DIRECT_RECLAIM | ___GFP_KSWAPD_RECLAIM) + +/** + * DOC: Useful GFP flag combinations + * + * Useful GFP flag combinations + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Useful GFP flag combinations that are commonly used. It is recommended + * that subsystems start with one of these combinations and then set/clear + * %__GFP_FOO flags as necessary. + * + * %GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower + * watermark is applied to allow access to "atomic reserves" + * + * %GFP_KERNEL is typical for kernel-internal allocations. The caller requires + * %ZONE_NORMAL or a lower zone for direct access but can direct reclaim. + * + * %GFP_NOWAIT is for kernel allocations that should not stall for direct + * reclaim, start physical IO or use any filesystem callback. + * + * %GFP_NOIO will use direct reclaim to discard clean pages or slab pages + * that do not require the starting of any physical IO. + * Please try to avoid using this flag directly and instead use + * memalloc_noio_{save,restore} to mark the whole scope which cannot + * perform any IO with a short explanation why. All allocation requests + * will inherit GFP_NOIO implicitly. + * + * %GFP_NOFS will use direct reclaim but will not use any filesystem interfaces. + * Please try to avoid using this flag directly and instead use + * memalloc_nofs_{save,restore} to mark the whole scope which cannot/shouldn't + * recurse into the FS layer with a short explanation why. All allocation + * requests will inherit GFP_NOFS implicitly. + * + * %GFP_USER is for userspace allocations that also need to be directly + * accessibly by the kernel or hardware. It is typically used by hardware + * for buffers that are mapped to userspace (e.g. graphics) that hardware + * still must DMA to. cpuset limits are enforced for these allocations. + * + * %GFP_DMA exists for historical reasons and should be avoided where possible. + * The flags indicates that the caller requires that the lowest zone be + * used (%ZONE_DMA or 16M on x86-64). Ideally, this would be removed but + * it would require careful auditing as some users really require it and + * others use the flag to avoid lowmem reserves in %ZONE_DMA and treat the + * lowest zone as a type of emergency reserve. + * + * %GFP_HIGHUSER is for userspace allocations that may be mapped to userspace, + * do not need to be directly accessible by the kernel but that cannot + * move once in use. An example may be a hardware allocation that maps + * data directly into userspace but has no addressing limitations. + */ +#define GFP_ATOMIC (__GFP_HIGH | __GFP_ATOMIC | __GFP_KSWAPD_RECLAIM) + +#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) + +#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) + +#define GFP_NOIO (__GFP_RECLAIM) + +#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO) + +#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS) + +#define GFP_DMA (__GFP_DMA) + +#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM) diff --git a/mentos/inc/mem/kheap.h b/mentos/inc/mem/kheap.h index 299904f..89e9bbc 100644 --- a/mentos/inc/mem/kheap.h +++ b/mentos/inc/mem/kheap.h @@ -1,128 +1,139 @@ -/// MentOS, The Mentoring Operating system project -/// @file kheap.h -/// @brief Interface for kernel heap functions, also provides a placement -/// malloc() for use before the heap is initialised. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "kernel.h" -#include "scheduler.h" - -//#define KHEAP_START (void*)(LOAD_MEMORY_ADDRESS + 0x00800000) // 0x00800000 = 8M -//#define KHEAP_MAX_ADDRESS (void*)(LOAD_MEMORY_ADDRESS + 0x0FFFFFFF) // 0x10000000 = 256 M -// M = 1024 * 1024 = 1MB -#define KHEAP_INITIAL_SIZE (4 * M) -#define UHEAP_INITIAL_SIZE (1 * M) - -/** - * @brief Structure of block_t - * size: | 31 bit | 1 bit | - * | first bits of real size | free/alloc | - * To calculate the real size, set to zero the last bit - * prev: -> block_t - * next: -> block_t - **/ -typedef struct block_t { - unsigned int size; - struct block_t *nextfree; - struct block_t *next; -} block_t; - -/// @brief Initialize heap. -/// @param initial_size Starting size. -void kheap_init(size_t initial_size); - -/// @brief Returns if the kheap is enabled. -bool_t kheap_is_enabled(); - -void *ksbrk(int increment); - -#if 0 -/// @brief Kmalloc wrapper. -/// @details When heap is not created, use a placement memory allocator, when -/// heap is created, use malloc(), the dynamic memory allocator. -/// @param size Size of memory to allocate. -/// @param align Return a page-aligned memory block. -/// @param phys Return the physical address of the memory block. -/// @return -uint32_t kmalloc_int(size_t size, bool_t align, uint32_t *phys); - -/// @brief Wrapper for kmalloc, get physical address. -/// @param sz Size of memory to allocate. -/// @param phys Pointer to the variable where to place the physical address. -/// @return -void *kmalloc_p(unsigned int sz, unsigned int *phys); - -/// @brief Wrapper for aligned kmalloc, get physical address. -/// @param sz Size of memory to allocate. -/// @param phys Pointer to the variable where to place the physical address. -/// @return -void *kmalloc_ap(unsigned int sz, unsigned int *phys); -#endif - -/// @brief Dynamically allocates memory of the given size. -/// @param sz Size of memory to allocate. -/// @return -void *kmalloc(unsigned int sz); - -/// @brief Wrapper for aligned kmalloc. -/// @param size Size of memory to allocate. -/// @return -void *kmalloc_align(size_t size); - -/// @brief Dynamically allocates memory for (size * num) and memset it. -/// @param num Multiplier. -/// @param size Size of memory to allocate. -/// @return -void *kcalloc(unsigned int num, unsigned int size); - -/// @brief Wrapper function for realloc. -/// @param ptr -/// @param size -/// @return -void *krealloc(void *ptr, unsigned int size); - -/// @brief Wrapper function for free. -/// @param p -void kfree(void *p); - -/// @brief Allocates size bytes of uninitialized storage. -//void *malloc(unsigned int size); - -// We can't do a user heap brk if we don't enable paging... -void *usbrk(int increment); - -/// @brief User malloc -/// @param size The size requested in byte. -/// @return The address of the allocated space. -void *umalloc(unsigned int size); - -/// @brief User free -/// @param p Pointer to the space to free. -void ufree(void *p); - -/// @brief Allocates size bytes of uninitialized storage with block align. -//void *malloc_align(struct vm_area_struct *heap, unsigned int size); - -/// @brief Deallocates previously allocated space. -//void free(void *ptr); - -/// @brief Reallocates the given area of memory. It must be still allocated -/// and not yet freed with a call to free or realloc. -/// @param ptr -/// @param size -/// @return -//void *realloc(void *ptr, unsigned int size); - -/// @brief Prints the heap visually, for debug. -void kheap_dump(); - -/// @brief Get the pointer to the kernel heap start. -/// @return The kernel heap start pointer. -uint32_t get_kheap_start(); - -/// @brief Get the pointer to the kernel heap curr. -/// @return The kernel heap current pointer. -uint32_t get_kheap_curr(); +/// MentOS, The Mentoring Operating system project +/// @file kheap.h +/// @brief Interface for kernel heap functions, also provides a placement +/// malloc() for use before the heap is initialised. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "kernel.h" +#include "scheduler.h" + +//#define KHEAP_START (void*)(LOAD_MEMORY_ADDRESS + 0x00800000) // 0x00800000 = 8M +//#define KHEAP_MAX_ADDRESS (void*)(LOAD_MEMORY_ADDRESS + 0x0FFFFFFF) // 0x10000000 = 256 M +// M = 1024 * 1024 = 1MB +#define KHEAP_INITIAL_SIZE (4 * M) +#define UHEAP_INITIAL_SIZE (1 * M) + +/** + * @brief Structure of block_t + * size: | 31 bit | 1 bit | + * | first bits of real size | free/alloc | + * To calculate the real size, set to zero the last bit + * prev: -> block_t + * next: -> block_t + **/ +typedef struct block_t { + unsigned int size; + struct block_t *nextfree; + struct block_t *next; +} block_t; + +/// @brief Initialize heap. +/// @param initial_size Starting size. +void kheap_init(size_t initial_size); + +/// @brief Returns if the kheap is enabled. +bool_t kheap_is_enabled(); + +void *ksbrk(int increment); + +#if 0 +/// @brief Kmalloc wrapper. +/// @details When heap is not created, use a placement memory allocator, when +/// heap is created, use malloc(), the dynamic memory allocator. +/// @param size Size of memory to allocate. +/// @param align Return a page-aligned memory block. +/// @param phys Return the physical address of the memory block. +/// @return +uint32_t kmalloc_int(size_t size, bool_t align, uint32_t *phys); + +/// @brief Wrapper for kmalloc, get physical address. +/// @param sz Size of memory to allocate. +/// @param phys Pointer to the variable where to place the physical address. +/// @return +void *kmalloc_p(unsigned int sz, unsigned int *phys); + +/// @brief Wrapper for aligned kmalloc, get physical address. +/// @param sz Size of memory to allocate. +/// @param phys Pointer to the variable where to place the physical address. +/// @return +void *kmalloc_ap(unsigned int sz, unsigned int *phys); +#endif + +/// @brief Dynamically allocates memory of the given size. +/// @param sz Size of memory to allocate. +/// @return +void *kmalloc(unsigned int sz); + +/// @brief Wrapper for aligned kmalloc. +/// @param size Size of memory to allocate. +/// @return +void *kmalloc_align(size_t size); + +/// @brief Dynamically allocates memory for (size * num) and memset it. +/// @param num Multiplier. +/// @param size Size of memory to allocate. +/// @return +void *kcalloc(unsigned int num, unsigned int size); + +/// @brief Wrapper function for realloc. +/// @param ptr +/// @param size +/// @return +void *krealloc(void *ptr, unsigned int size); + +/// @brief Allocate a matrix with n rows of a specific size. +/// @param n Number of matrix rows. +/// @param size Size of each matrix row. +/// @return Matrix pointer. +void **kmmalloc(size_t n, size_t size); + +/// @brief Wrapper function for free. +/// @param p +void kfree(void *p); + +/// @brief Free a matrix of n rows. +/// @param src Matrix to free. +/// @param n Number of matrix rows. +void kmfree(void **src, size_t n); + +/// @brief Allocates size bytes of uninitialized storage. +//void *malloc(unsigned int size); + +// We can't do a user heap brk if we don't enable paging... +void *usbrk(int increment); + +/// @brief User malloc +/// @param size The size requested in byte. +/// @return The address of the allocated space. +void *umalloc(unsigned int size); + +/// @brief User free +/// @param p Pointer to the space to free. +void ufree(void *p); + +/// @brief Allocates size bytes of uninitialized storage with block align. +//void *malloc_align(struct vm_area_struct *heap, unsigned int size); + +/// @brief Deallocates previously allocated space. +//void free(void *ptr); + +/// @brief Reallocates the given area of memory. It must be still allocated +/// and not yet freed with a call to free or realloc. +/// @param ptr +/// @param size +/// @return +//void *realloc(void *ptr, unsigned int size); + +/// @brief Prints the heap visually, for debug. +void kheap_dump(); + +/// @brief Get the pointer to the kernel heap start. +/// @return The kernel heap start pointer. +uint32_t get_kheap_start(); + +/// @brief Get the pointer to the kernel heap curr. +/// @return The kernel heap current pointer. +uint32_t get_kheap_curr(); diff --git a/mentos/inc/mem/paging.h b/mentos/inc/mem/paging.h index d8e12b9..6321a2f 100644 --- a/mentos/inc/mem/paging.h +++ b/mentos/inc/mem/paging.h @@ -1,106 +1,106 @@ -/// MentOS, The Mentoring Operating system project -/// @file paging.h -/// @brief Implementation of a memory paging management. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "zone_allocator.h" -#include "kernel.h" -#include "stddef.h" - -/// Size of a page. -#define PAGE_SIZE 4096 - -/// @brief Virtual Memory Area. -/// Process segments. -struct vm_area_struct { - /// Memory descriptor associated. - struct mm_struct *vm_mm; - - /// Start address of the segment. - uint32_t vm_start; - - /// End address of the segment. - uint32_t vm_end; - - /// Next memory area of the list. - struct vm_area_struct *vm_next; - - /// Permissions. - pgprot_t vm_page_prot; - - /// Flags. - unsigned short vm_flags; - - /// rbtree node. - // struct rb_node vm_rb; -}; - -/// @brief Memory Descriptor. -/// Memory description of user process. -struct mm_struct { - /// List of memory area. - struct vm_area_struct *mmap; - // /// rbtree of memory area. - // struct rb_root mm_rb; - - /// Last memory area used. - struct vm_area_struct *mmap_cache; - - // ///< Process page directory. - // page_directory_t * pgd; - - /// Number of memory area. - int map_count; - - /// List of mm_struct. - list_head mmlist; - - /// CODE. - uint32_t start_code, end_code; - - /// DATA. - uint32_t start_data, end_data; - - /// HEAP. - uint32_t start_brk, brk; - - /// STACK. - uint32_t start_stack; - - /// ARGS. - uint32_t arg_start, arg_end; - - /// ENVIRONMENT. - uint32_t env_start, env_end; - - /// Number of mapped pages. - unsigned int total_vm; -}; - -/// @brief Returns if paging is enabled. -bool_t paging_is_enabled(); - -/// @brief Create a Memory Descriptor. -/// @param stack_size The size of the stack in byte. -/// @return The Memory Descriptor created. -struct mm_struct *create_process_image(size_t stack_size); - -/// @brief Create a virtual memory area. -/// @param mm The memory descriptor which will contain the new segment. -/// @param size The size of the segment. -/// @return The virtual address of the starting point of the segment. -uint32_t create_segment(struct mm_struct *mm, size_t size); - -/// @brief Free Memory Descriptor with all the memory segment contained. -/// @param mm The Memory Descriptor to free. -void destroy_process_image(struct mm_struct *mm); - -/* - * /// @brief Free a virtual memory area. - * /// @param mm The Memory Descriptor that contains the segment. - * /// @param segment The segment to free. - * void destroy_segment(struct mm_struct *mm, struct vm_area_struct *segment); - */ +/// MentOS, The Mentoring Operating system project +/// @file paging.h +/// @brief Implementation of a memory paging management. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "zone_allocator.h" +#include "kernel.h" +#include "stddef.h" + +/// Size of a page. +#define PAGE_SIZE 4096 + +/// @brief Virtual Memory Area. +/// Process segments. +struct vm_area_struct { + /// Memory descriptor associated. + struct mm_struct *vm_mm; + + /// Start address of the segment. + uint32_t vm_start; + + /// End address of the segment. + uint32_t vm_end; + + /// Next memory area of the list. + struct vm_area_struct *vm_next; + + /// Permissions. + pgprot_t vm_page_prot; + + /// Flags. + unsigned short vm_flags; + + /// rbtree node. + // struct rb_node vm_rb; +}; + +/// @brief Memory Descriptor. +/// Memory description of user process. +struct mm_struct { + /// List of memory area. + struct vm_area_struct *mmap; + // /// rbtree of memory area. + // struct rb_root mm_rb; + + /// Last memory area used. + struct vm_area_struct *mmap_cache; + + // ///< Process page directory. + // page_directory_t * pgd; + + /// Number of memory area. + int map_count; + + /// List of mm_struct. + list_head mmlist; + + /// CODE. + uint32_t start_code, end_code; + + /// DATA. + uint32_t start_data, end_data; + + /// HEAP. + uint32_t start_brk, brk; + + /// STACK. + uint32_t start_stack; + + /// ARGS. + uint32_t arg_start, arg_end; + + /// ENVIRONMENT. + uint32_t env_start, env_end; + + /// Number of mapped pages. + unsigned int total_vm; +}; + +/// @brief Returns if paging is enabled. +bool_t paging_is_enabled(); + +/// @brief Create a Memory Descriptor. +/// @param stack_size The size of the stack in byte. +/// @return The Memory Descriptor created. +struct mm_struct *create_process_image(size_t stack_size); + +/// @brief Create a virtual memory area. +/// @param mm The memory descriptor which will contain the new segment. +/// @param size The size of the segment. +/// @return The virtual address of the starting point of the segment. +uint32_t create_segment(struct mm_struct *mm, size_t size); + +/// @brief Free Memory Descriptor with all the memory segment contained. +/// @param mm The Memory Descriptor to free. +void destroy_process_image(struct mm_struct *mm); + +/* + * /// @brief Free a virtual memory area. + * /// @param mm The Memory Descriptor that contains the segment. + * /// @param segment The segment to free. + * void destroy_segment(struct mm_struct *mm, struct vm_area_struct *segment); + */ diff --git a/mentos/inc/mem/zone_allocator.h b/mentos/inc/mem/zone_allocator.h index c2cd4f0..59a3530 100644 --- a/mentos/inc/mem/zone_allocator.h +++ b/mentos/inc/mem/zone_allocator.h @@ -1,163 +1,163 @@ -/// MentOS, The Mentoring Operating system project -/// @file zone_allocator.h -/// @brief Implementation of the Zone Allocator -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "gfp.h" -#include "math.h" -#include "stdint.h" -#include "stdbool.h" -#include "list_head.h" - -/// Max order of buddysystem blocks. -#define MAX_ORDER 11 - -/// @brief Buddy system descriptor: collection of free page blocks. -/// Each block represents 2^k free contiguous page. -typedef struct { - /// free_list collectes the first page descriptors of a blocks of 2^k frames - list_head free_list; - /// nr_free specifies the number of blocks of free pages. - int nr_free; -} free_area_t; - -/// @brief Page descriptor. Use as a bitmap to understand -/// the order of the block and if it is free or allocated. -typedef struct { - /// Array of flags encoding also the zone number to which the page frame belongs. - unsigned long flags; - /// Page frame’s reference counter. -1 free, >= 0 used - int _count; - /// If the page is free, this field is used by the buddy system. - unsigned long private; - /// Contains pointers to the least recently used doubly linked list of pages. - struct list_head lru; -} page_t; - -/// @brief Enumeration for zone_t. -enum zone_type { - /* - * ZONE_DMA is used when there are devices that are not able - * to do DMA to all of addressable memory (ZONE_NORMAL). Then we - * carve out the portion of memory that is needed for these devices. - * The range is arch specific. - * - * Some examples - * - * Architecture Limit - * --------------------------- - * parisc, ia64, sparc <4G - * s390 <2G - * arm Various - * alpha Unlimited or 0-16MB. - * - * i386, x86_64 and multiple other arches - * <16M. - */ - - // ///< Direct memory access. - // ZONE_DMA, - - /* - * Normal addressable memory is in ZONE_NORMAL. DMA operations can be - * performed on pages in ZONE_NORMAL if the DMA devices support - * transfers to all addressable memory. - */ - /// Direct mapping. Used by the kernel. - ZONE_NORMAL, - - /* - * A memory area that is only addressable by the kernel through - * mapping portions into its own address space. This is for example - * used by i386 to allow the kernel to address the memory beyond - * 900MB. The kernel will set up special mappings (page - * table entries on i386) for each page that the kernel needs to - * access. - */ - /// Page tables mapping. Used by user processes. - ZONE_HIGHMEM, - - __MAX_NR_ZONES -}; - -/// @brief Data structure to differentiate memory zone. -typedef struct { - /// Number of free pages in the zone. - unsigned long free_pages; - /// BuddySystem structure for the zone. - free_area_t free_area[MAX_ORDER]; - /// Pointer to first page descriptor of the zone. - page_t *zone_mem_map; - /// Index of the first page frame of the zone. - uint32_t zone_start_pfn; - /// Zone's name. - char *name; - /// Zone's size in number of pages. - unsigned long size; -} zone_t; - -/// @brief Data structure to rapresent a memory node. -/// In UMA Architecture there is only one node called -/// contig_page_data. -typedef struct { - /// Zones of the node. - zone_t node_zones[__MAX_NR_ZONES]; - /// Number of zones in the node. - int nr_zones; - /// Array of pages of the node. - page_t *node_mem_map; - /// Physical address of the first page of the node. - unsigned long node_start_paddr; - /// Index on global mem_map for node_mem_map. - unsigned long node_start_mapnr; - /// Node's size in number of pages. - unsigned long node_size; - /// NID. - int node_id; - /// Pointer to the next node. - struct pglist_data *node_next; -} pg_data_t; - -extern page_t *mem_map; -extern pg_data_t *contig_page_data; - -/// @brief Find the nearest block's order of size greater -/// than the amount of byte. -/// @param amount The amount of byte which we want to calculate order. -/// @return The block's order greater and nearest than amount. -uint32_t find_nearest_order_greater(uint32_t amount); - -/// @brief Physical memory manager initialization (page_t, zones) -/// @param mem_size Size of the memory. -bool_t pmmngr_init(uint32_t mem_size); - -/// @brief Find the first free page frame, set it allocated -/// and return the memory address of the page frame. -/// @param gfp_mask GFP_FLAGS to decide the zone allocation. -/// @return Memory address of the first free block. -uint32_t __alloc_page(gfp_t gfp_mask); - -/// @brief Frees the given page frame address. -/// @param addr The block address. -void free_page(uint32_t addr); - -/// @brief Find the first free 2^order amount of page frames, -/// set it allocated and return the memory address of the first -/// page frame allocated. -/// @param gfp_mask GFP_FLAGS to decide the zone allocation. -/// @param order The logarithm of the size of the page frame. -/// @return Memory address of the first free page frame allocated. -uint32_t __alloc_pages(gfp_t gfp_mask, uint32_t order); - -/// @brief Frees from the given page frame address up to -/// 2^order amount of page frames. -/// @param addr The page frame address. -/// @param order The logarithm of the size of the block. -void free_pages(uint32_t addr, uint32_t order); - -/// @brief Get the pointer of the last byte allocated with pmmngr_init() -/// @return The pointer to the memory. -uint32_t get_memory_start(); +/// MentOS, The Mentoring Operating system project +/// @file zone_allocator.h +/// @brief Implementation of the Zone Allocator +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "gfp.h" +#include "math.h" +#include "stdint.h" +#include "stdbool.h" +#include "list_head.h" + +/// Max order of buddysystem blocks. +#define MAX_ORDER 11 + +/// @brief Buddy system descriptor: collection of free page blocks. +/// Each block represents 2^k free contiguous page. +typedef struct { + /// free_list collectes the first page descriptors of a blocks of 2^k frames + list_head free_list; + /// nr_free specifies the number of blocks of free pages. + int nr_free; +} free_area_t; + +/// @brief Page descriptor. Use as a bitmap to understand +/// the order of the block and if it is free or allocated. +typedef struct { + /// Array of flags encoding also the zone number to which the page frame belongs. + unsigned long flags; + /// Page frame’s reference counter. -1 free, >= 0 used + int _count; + /// If the page is free, this field is used by the buddy system. + unsigned long private; + /// Contains pointers to the least recently used doubly linked list of pages. + struct list_head lru; +} page_t; + +/// @brief Enumeration for zone_t. +enum zone_type { + /* + * ZONE_DMA is used when there are devices that are not able + * to do DMA to all of addressable memory (ZONE_NORMAL). Then we + * carve out the portion of memory that is needed for these devices. + * The range is arch specific. + * + * Some examples + * + * Architecture Limit + * --------------------------- + * parisc, ia64, sparc <4G + * s390 <2G + * arm Various + * alpha Unlimited or 0-16MB. + * + * i386, x86_64 and multiple other arches + * <16M. + */ + + // ///< Direct memory access. + // ZONE_DMA, + + /* + * Normal addressable memory is in ZONE_NORMAL. DMA operations can be + * performed on pages in ZONE_NORMAL if the DMA devices support + * transfers to all addressable memory. + */ + /// Direct mapping. Used by the kernel. + ZONE_NORMAL, + + /* + * A memory area that is only addressable by the kernel through + * mapping portions into its own address space. This is for example + * used by i386 to allow the kernel to address the memory beyond + * 900MB. The kernel will set up special mappings (page + * table entries on i386) for each page that the kernel needs to + * access. + */ + /// Page tables mapping. Used by user processes. + ZONE_HIGHMEM, + + __MAX_NR_ZONES +}; + +/// @brief Data structure to differentiate memory zone. +typedef struct { + /// Number of free pages in the zone. + unsigned long free_pages; + /// BuddySystem structure for the zone. + free_area_t free_area[MAX_ORDER]; + /// Pointer to first page descriptor of the zone. + page_t *zone_mem_map; + /// Index of the first page frame of the zone. + uint32_t zone_start_pfn; + /// Zone's name. + char *name; + /// Zone's size in number of pages. + unsigned long size; +} zone_t; + +/// @brief Data structure to rapresent a memory node. +/// In UMA Architecture there is only one node called +/// contig_page_data. +typedef struct { + /// Zones of the node. + zone_t node_zones[__MAX_NR_ZONES]; + /// Number of zones in the node. + int nr_zones; + /// Array of pages of the node. + page_t *node_mem_map; + /// Physical address of the first page of the node. + unsigned long node_start_paddr; + /// Index on global mem_map for node_mem_map. + unsigned long node_start_mapnr; + /// Node's size in number of pages. + unsigned long node_size; + /// NID. + int node_id; + /// Pointer to the next node. + struct pglist_data *node_next; +} pg_data_t; + +extern page_t *mem_map; +extern pg_data_t *contig_page_data; + +/// @brief Find the nearest block's order of size greater +/// than the amount of byte. +/// @param amount The amount of byte which we want to calculate order. +/// @return The block's order greater and nearest than amount. +uint32_t find_nearest_order_greater(uint32_t amount); + +/// @brief Physical memory manager initialization (page_t, zones) +/// @param mem_size Size of the memory. +bool_t pmmngr_init(uint32_t mem_size); + +/// @brief Find the first free page frame, set it allocated +/// and return the memory address of the page frame. +/// @param gfp_mask GFP_FLAGS to decide the zone allocation. +/// @return Memory address of the first free block. +uint32_t __alloc_page(gfp_t gfp_mask); + +/// @brief Frees the given page frame address. +/// @param addr The block address. +void free_page(uint32_t addr); + +/// @brief Find the first free 2^order amount of page frames, +/// set it allocated and return the memory address of the first +/// page frame allocated. +/// @param gfp_mask GFP_FLAGS to decide the zone allocation. +/// @param order The logarithm of the size of the page frame. +/// @return Memory address of the first free page frame allocated. +uint32_t __alloc_pages(gfp_t gfp_mask, uint32_t order); + +/// @brief Frees from the given page frame address up to +/// 2^order amount of page frames. +/// @param addr The page frame address. +/// @param order The logarithm of the size of the block. +void free_pages(uint32_t addr, uint32_t order); + +/// @brief Get the pointer of the last byte allocated with pmmngr_init() +/// @return The pointer to the memory. +uint32_t get_memory_start(); diff --git a/mentos/inc/misc/bitops.h b/mentos/inc/misc/bitops.h index 3268375..1bff138 100644 --- a/mentos/inc/misc/bitops.h +++ b/mentos/inc/misc/bitops.h @@ -1,30 +1,30 @@ -/// MentOS, The Mentoring Operating system project -/// @file bitops.h -/// @brief Bitmasks functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" -#include "stdbool.h" - -/// @brief Finds the first bit set in the given irq mask. -int find_first_bit(unsigned short int irq_mask); - -/// @brief Check if the passed value has the given flag set. -/// @param flags The value to check. -/// @param flag The flag to search. -/// @return True If the value contain the flag,
-/// False otherwise. -bool_t has_flag(uint32_t flags, uint32_t flag); - -/// @brief Set the passed flag to the value. -/// @param flags The destination value. -/// @param flag The flag to set. -void set_flag(uint32_t *flags, uint32_t flag); - -/// @brief Clear the passed flag to the value. -/// @param flags The destination value. -/// @param flag The flag to clear. -void clear_flag(uint32_t *flags, uint32_t flag); +/// MentOS, The Mentoring Operating system project +/// @file bitops.h +/// @brief Bitmasks functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" +#include "stdbool.h" + +/// @brief Finds the first bit set in the given irq mask. +int find_first_bit(unsigned short int irq_mask); + +/// @brief Check if the passed value has the given flag set. +/// @param flags The value to check. +/// @param flag The flag to search. +/// @return True If the value contain the flag,
+/// False otherwise. +bool_t has_flag(uint32_t flags, uint32_t flag); + +/// @brief Set the passed flag to the value. +/// @param flags The destination value. +/// @param flag The flag to set. +void set_flag(uint32_t *flags, uint32_t flag); + +/// @brief Clear the passed flag to the value. +/// @param flags The destination value. +/// @param flag The flag to clear. +void clear_flag(uint32_t *flags, uint32_t flag); diff --git a/mentos/inc/misc/clock.h b/mentos/inc/misc/clock.h index d7e7b64..e0a5bdc 100644 --- a/mentos/inc/misc/clock.h +++ b/mentos/inc/misc/clock.h @@ -1,98 +1,98 @@ -/// MentOS, The Mentoring Operating system project -/// @file clock.h -/// @brief Clock functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// Used to store time values. -typedef unsigned int time_t; - -/// Used to get information about the current time. -typedef struct tm_t { - /// Seconds [0 to 59] - int tm_sec; - /// Minutes [0 to 59] - int tm_min; - /// Hours [0 to 23] - int tm_hour; - /// Day of the month [1 to 31] - int tm_mday; - /// Month [0 to 11] - int tm_mon; - /// Year [since 1900] - int tm_year; - /// Day of the week [0 to 6] - int tm_wday; - /// Day in the year [0 to 365] - int tm_yday; - /// Is Daylight Saving Time. - int tm_isdst; -} tm_t; - -/// Value used to retrieve the seconds. -#define SECOND_RTC 0x00 - -/// Value used to retrieve the minutes. -#define MINUTE_RTC 0x02 - -/// Value used to retrieve the hours. -#define HOUR_RTC 0x04 - -/// Value used to retrieve the day of the week. -#define DAY_W_RTC 0x06 - -/// Value used to retrieve the day of the month. -#define DAY_M_RTC 0x07 - -/// Value used to retrieve the month. -#define MONTH_RTC 0x08 - -/// Value used to retrieve the year. -#define YEAR_RTC 0x09 - -/// @brief Returns the milliseconds. -time_t get_millisecond(); - -/// @brief Returns the seconds. -time_t get_second(); - -/// @brief Returns the hours. -time_t get_hour(); - -/// @brief Returns the minutes. -time_t get_minute(); - -/// @brief Returns the day of the month. -time_t get_day_m(); - -/// @brief returns the month. -time_t get_month(); - -/// @brief Returns the year. -time_t get_year(); - -/// @brief Returns the day of the week. -time_t get_day_w(); - -/// @brief Returns the name of the month. -char *get_month_lng(); - -/// @brief Returns the name of the day. -char *get_day_lng(); - -/// @brief Returns the current time. -time_t time(time_t *timer); - -// TODO: doxygen comment. -time_t difftime(time_t time1, time_t time2); - -// TODO: doxygen comment. -void strhourminutesecond(char *dst); - -// TODO: doxygen comment. -void strdaymonthyear(char *dst); - -// TODO: doxygen comment. -void strdatehour(char *dst); +/// MentOS, The Mentoring Operating system project +/// @file clock.h +/// @brief Clock functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// Used to store time values. +typedef unsigned int time_t; + +/// Used to get information about the current time. +typedef struct tm_t { + /// Seconds [0 to 59] + int tm_sec; + /// Minutes [0 to 59] + int tm_min; + /// Hours [0 to 23] + int tm_hour; + /// Day of the month [1 to 31] + int tm_mday; + /// Month [0 to 11] + int tm_mon; + /// Year [since 1900] + int tm_year; + /// Day of the week [0 to 6] + int tm_wday; + /// Day in the year [0 to 365] + int tm_yday; + /// Is Daylight Saving Time. + int tm_isdst; +} tm_t; + +/// Value used to retrieve the seconds. +#define SECOND_RTC 0x00 + +/// Value used to retrieve the minutes. +#define MINUTE_RTC 0x02 + +/// Value used to retrieve the hours. +#define HOUR_RTC 0x04 + +/// Value used to retrieve the day of the week. +#define DAY_W_RTC 0x06 + +/// Value used to retrieve the day of the month. +#define DAY_M_RTC 0x07 + +/// Value used to retrieve the month. +#define MONTH_RTC 0x08 + +/// Value used to retrieve the year. +#define YEAR_RTC 0x09 + +/// @brief Returns the milliseconds. +time_t get_millisecond(); + +/// @brief Returns the seconds. +time_t get_second(); + +/// @brief Returns the hours. +time_t get_hour(); + +/// @brief Returns the minutes. +time_t get_minute(); + +/// @brief Returns the day of the month. +time_t get_day_m(); + +/// @brief returns the month. +time_t get_month(); + +/// @brief Returns the year. +time_t get_year(); + +/// @brief Returns the day of the week. +time_t get_day_w(); + +/// @brief Returns the name of the month. +char *get_month_lng(); + +/// @brief Returns the name of the day. +char *get_day_lng(); + +/// @brief Returns the current time. +time_t time(time_t *timer); + +// TODO: doxygen comment. +time_t difftime(time_t time1, time_t time2); + +// TODO: doxygen comment. +void strhourminutesecond(char *dst); + +// TODO: doxygen comment. +void strdaymonthyear(char *dst); + +// TODO: doxygen comment. +void strdatehour(char *dst); diff --git a/mentos/inc/misc/debug.h b/mentos/inc/misc/debug.h index 9bb2505..e1a8baa 100644 --- a/mentos/inc/misc/debug.h +++ b/mentos/inc/misc/debug.h @@ -1,67 +1,67 @@ -/// MentOS, The Mentoring Operating system project -/// @file debug.h -/// @brief Debugging primitives. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "kernel.h" -#include "port_io.h" - -/// @brief Used to enable the device. Any I/O to the debug module before this -/// command is sent will simply be ignored. -#define DBG_ENABLE 0x8A00 - -/// @brief Disable the I/O interface to the debugger and the memory -/// monitoring functions. -#define DBG_DISABLE 0x8AFF - -/// @brief Selects register 0: Memory monitoring range start address -/// (inclusive). -#define SELECTS_REG_0 0x8A01 - -/// @brief Selects register 1: Memory monitoring range end address (exclusive). -#define SELECTS_REG_1 0x8A02 - -/// @brief Enable address range memory monitoring as indicated by register 0 -/// and 1 and clears both registers. -#define ENABLE_ADDR_RANGE_MEM_MONITOR 0x8A80 - -/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE2 -/// to port 0x8A00 after the device has been enabled will enable instruction -/// tracing. -#define INSTRUCTION_TRACE_ENABLE 0x8AE3 - -/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE2 -/// to port 0x8A00 after the device has been enabled will disable instruction -/// tracing. -#define INSTRUCTION_TRACE_DISABLE 0x8AE2 - -/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE5 -/// to port 0x8A00 after the device has been enabled will enable register -/// tracing. This currently output the value of all the registers for each -/// instruction traced. Note: instruction tracing must be enabled to view -/// the register tracing. -#define REGISTER_TRACE_ENABLE 0x8AE5 - -/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE4 -/// to port 0x8A00 after the device has been enabled will disable register -/// tracing. -#define REGISTER_TRACE_DISABLE 0x8AE4 - -/// @brief Prints the given string to the debug output. -void _dbg_print(const char *file, const char *fun, int line, const char *msg, - ...); - -#define __FILENAME__ \ - (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : \ - __FILE__) - -#define dbg_print(...) _dbg_print(__FILENAME__, __func__, __LINE__, __VA_ARGS__) - -/// @brief Prints the given registers to the debug output. -void print_reg(register_t *reg); - -/// @brief Prints the given intrframe to the debug output. -void print_intrframe(pt_regs *frame); +/// MentOS, The Mentoring Operating system project +/// @file debug.h +/// @brief Debugging primitives. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "kernel.h" +#include "port_io.h" + +/// @brief Used to enable the device. Any I/O to the debug module before this +/// command is sent will simply be ignored. +#define DBG_ENABLE 0x8A00 + +/// @brief Disable the I/O interface to the debugger and the memory +/// monitoring functions. +#define DBG_DISABLE 0x8AFF + +/// @brief Selects register 0: Memory monitoring range start address +/// (inclusive). +#define SELECTS_REG_0 0x8A01 + +/// @brief Selects register 1: Memory monitoring range end address (exclusive). +#define SELECTS_REG_1 0x8A02 + +/// @brief Enable address range memory monitoring as indicated by register 0 +/// and 1 and clears both registers. +#define ENABLE_ADDR_RANGE_MEM_MONITOR 0x8A80 + +/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE2 +/// to port 0x8A00 after the device has been enabled will enable instruction +/// tracing. +#define INSTRUCTION_TRACE_ENABLE 0x8AE3 + +/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE2 +/// to port 0x8A00 after the device has been enabled will disable instruction +/// tracing. +#define INSTRUCTION_TRACE_DISABLE 0x8AE2 + +/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE5 +/// to port 0x8A00 after the device has been enabled will enable register +/// tracing. This currently output the value of all the registers for each +/// instruction traced. Note: instruction tracing must be enabled to view +/// the register tracing. +#define REGISTER_TRACE_ENABLE 0x8AE5 + +/// @brief If the debugger is enabled (via --enable-debugger), sending 0x8AE4 +/// to port 0x8A00 after the device has been enabled will disable register +/// tracing. +#define REGISTER_TRACE_DISABLE 0x8AE4 + +/// @brief Prints the given string to the debug output. +void _dbg_print(const char *file, const char *fun, int line, const char *msg, + ...); + +#define __FILENAME__ \ + (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : \ + __FILE__) + +#define dbg_print(...) _dbg_print(__FILENAME__, __func__, __LINE__, __VA_ARGS__) + +/// @brief Prints the given registers to the debug output. +void print_reg(register_t *reg); + +/// @brief Prints the given intrframe to the debug output. +void print_intrframe(pt_regs *frame); diff --git a/mentos/inc/multiboot.h b/mentos/inc/multiboot.h index 458a643..46428ed 100644 --- a/mentos/inc/multiboot.h +++ b/mentos/inc/multiboot.h @@ -1,206 +1,206 @@ -/// MentOS, The Mentoring Operating system project -/// @file multiboot.h -/// @brief Data structures used for multiboot. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -// Do not inc here in boot.s. - -#pragma once - -#include "stdint.h" - -// The magic field should contain this. -#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 -// This should be in %eax. -#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 - -/// Is there basic lower/upper memory information? -#define MULTIBOOT_FLAG_MEM 0x00000001U -/// is there a boot device set? -#define MULTIBOOT_FLAG_DEVICE 0x00000002U -/// is the command-line defined? -#define MULTIBOOT_FLAG_CMDLINE 0x00000004U -/// are there modules to do something with? -#define MULTIBOOT_FLAG_MODS 0x00000008U -/// is there a symbol table loaded? -#define MULTIBOOT_FLAG_AOUT 0x00000010U -/// is there an ELF section header table? -#define MULTIBOOT_FLAG_ELF 0x00000020U -/// is there a full memory map? -#define MULTIBOOT_FLAG_MMAP 0x00000040U -/// Is there drive info? -#define MULTIBOOT_FLAG_DRIVE_INFO 0x00000080U -/// Is there a config table? -#define MULTIBOOT_FLAG_CONFIG_TABLE 0x00000100U -/// Is there a boot loader name? -#define MULTIBOOT_FLAG_BOOT_LOADER_NAME 0x00000200U -/// Is there a APM table? -#define MULTIBOOT_FLAG_APM_TABLE 0x00000400U -/// Is there video information? -#define MULTIBOOT_FLAG_VBE_INFO 0x00000800U -#define MULTIBOOT_FLAG_FRAMEBUFFER_INFO 0x00001000U - -#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 -#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 -#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 - -#define MULTIBOOT_MEMORY_AVAILABLE 1 -#define MULTIBOOT_MEMORY_RESERVED 2 -#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 -#define MULTIBOOT_MEMORY_NVS 4 -#define MULTIBOOT_MEMORY_BADRAM 5 - -// +-------------------+ -// 0 | flags | (required) -// +-------------------+ -// 4 | mem_lower | (present if flags[0] is set) -// 8 | mem_upper | (present if flags[0] is set) -// +-------------------+ -// 12 | boot_device | (present if flags[1] is set) -// +-------------------+ -// 16 | cmdline | (present if flags[2] is set) -// +-------------------+ -// 20 | mods_count | (present if flags[3] is set) -// 24 | mods_addr | (present if flags[3] is set) -// +-------------------+ -// 28 - 40 | syms | (present if flags[4] or -// | | flags[5] is set) -// +-------------------+ -// 44 | mmap_length | (present if flags[6] is set) -// 48 | mmap_addr | (present if flags[6] is set) -// +-------------------+ -// 52 | drives_length | (present if flags[7] is set) -// 56 | drives_addr | (present if flags[7] is set) -// +-------------------+ -// 60 | config_table | (present if flags[8] is set) -// +-------------------+ -// 64 | boot_loader_name | (present if flags[9] is set) -// +-------------------+ -// 68 | apm_table | (present if flags[10] is set) -// +-------------------+ -// 72 | vbe_control_info | (present if flags[11] is set) -// 76 | vbe_mode_info | -// 80 | vbe_mode | -// 82 | vbe_interface_seg | -// 84 | vbe_interface_off | -// 86 | vbe_interface_len | -// +-------------------+ -// 88 | framebuffer_addr | (present if flags[12] is set) -// 96 | framebuffer_pitch | -// 100 | framebuffer_width | -// 104 | framebuffer_height| -// 108 | framebuffer_bpp | -// 109 | framebuffer_type | -// 110-115 | color_info | -// +-------------------+ - -/// The symbol table for a.out. -typedef struct multiboot_aout_symbol_table { - uint32_t tabsize; - uint32_t strsize; - uint32_t addr; - uint32_t reserved; -} multiboot_aout_symbol_table_t; - -/// The section header table for ELF. -typedef struct multiboot_elf_section_header_table { - uint32_t num; - uint32_t size; - uint32_t addr; - uint32_t shndx; -} multiboot_elf_section_header_table_t; - -// TODO: doxygen comment. -typedef struct multiboot_module { - // The memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive. - uint32_t mod_start; - uint32_t mod_end; - // Module command line. - uint32_t cmdline; - // Padding to take it to 16 bytes (must be zero). - uint32_t pad; -} multiboot_module_t; - -typedef struct multiboot_memory_map { - uint32_t size; - uint32_t base_addr_low; - uint32_t base_addr_high; - uint32_t length_low; - uint32_t length_high; - uint32_t type; -} multiboot_memory_map_t; - -// TODO: doxygen comment. -typedef struct multiboot_info { - /// Multiboot info version number. - uint32_t flags; - - /// Available memory from BIOS. - uint32_t mem_lower; - uint32_t mem_upper; - - /// "root" partition. - uint32_t boot_device; - - /// Kernel command line. - uint32_t cmdline; - - /// Boot-Module list. - uint32_t mods_count; - uint32_t mods_addr; - - union { - multiboot_aout_symbol_table_t aout_sym; - multiboot_elf_section_header_table_t elf_sec; - } u; - - /// Memory Mapping buffer. - uint32_t mmap_length; - uint32_t mmap_addr; - - /// Drive Info buffer. - uint32_t drives_length; - uint32_t drives_addr; - - /// ROM configuration table. - uint32_t config_table; - - /// Boot Loader Name. - uint32_t boot_loader_name; - - /// APM table. - uint32_t apm_table; - - /// Video. - uint32_t vbe_control_info; - uint32_t vbe_mode_info; - uint32_t vbe_mode; - uint32_t vbe_interface_seg; - uint32_t vbe_interface_off; - uint32_t vbe_interface_len; - - uint32_t framebuffer_addr; - uint32_t framebuffer_pitch; - uint32_t framebuffer_width; - uint32_t framebuffer_height; - uint32_t framebuffer_bpp; - uint32_t framebuffer_type; - union { - struct { - uint32_t framebuffer_palette_addr; - uint16_t framebuffer_palette_num_colors; - }; - struct { - uint8_t framebuffer_red_field_position; - uint8_t framebuffer_red_mask_size; - uint8_t framebuffer_green_field_position; - uint8_t framebuffer_green_mask_size; - uint8_t framebuffer_blue_field_position; - uint8_t framebuffer_blue_mask_size; - }; - }; -} __attribute__((packed)) multiboot_info_t; - -// TODO: doxygen comment. -void dump_multiboot(multiboot_info_t *mboot_ptr); +/// MentOS, The Mentoring Operating system project +/// @file multiboot.h +/// @brief Data structures used for multiboot. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +// Do not inc here in boot.s. + +#pragma once + +#include "stdint.h" + +// The magic field should contain this. +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 +// This should be in %eax. +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/// Is there basic lower/upper memory information? +#define MULTIBOOT_FLAG_MEM 0x00000001U +/// is there a boot device set? +#define MULTIBOOT_FLAG_DEVICE 0x00000002U +/// is the command-line defined? +#define MULTIBOOT_FLAG_CMDLINE 0x00000004U +/// are there modules to do something with? +#define MULTIBOOT_FLAG_MODS 0x00000008U +/// is there a symbol table loaded? +#define MULTIBOOT_FLAG_AOUT 0x00000010U +/// is there an ELF section header table? +#define MULTIBOOT_FLAG_ELF 0x00000020U +/// is there a full memory map? +#define MULTIBOOT_FLAG_MMAP 0x00000040U +/// Is there drive info? +#define MULTIBOOT_FLAG_DRIVE_INFO 0x00000080U +/// Is there a config table? +#define MULTIBOOT_FLAG_CONFIG_TABLE 0x00000100U +/// Is there a boot loader name? +#define MULTIBOOT_FLAG_BOOT_LOADER_NAME 0x00000200U +/// Is there a APM table? +#define MULTIBOOT_FLAG_APM_TABLE 0x00000400U +/// Is there video information? +#define MULTIBOOT_FLAG_VBE_INFO 0x00000800U +#define MULTIBOOT_FLAG_FRAMEBUFFER_INFO 0x00001000U + +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + +// +-------------------+ +// 0 | flags | (required) +// +-------------------+ +// 4 | mem_lower | (present if flags[0] is set) +// 8 | mem_upper | (present if flags[0] is set) +// +-------------------+ +// 12 | boot_device | (present if flags[1] is set) +// +-------------------+ +// 16 | cmdline | (present if flags[2] is set) +// +-------------------+ +// 20 | mods_count | (present if flags[3] is set) +// 24 | mods_addr | (present if flags[3] is set) +// +-------------------+ +// 28 - 40 | syms | (present if flags[4] or +// | | flags[5] is set) +// +-------------------+ +// 44 | mmap_length | (present if flags[6] is set) +// 48 | mmap_addr | (present if flags[6] is set) +// +-------------------+ +// 52 | drives_length | (present if flags[7] is set) +// 56 | drives_addr | (present if flags[7] is set) +// +-------------------+ +// 60 | config_table | (present if flags[8] is set) +// +-------------------+ +// 64 | boot_loader_name | (present if flags[9] is set) +// +-------------------+ +// 68 | apm_table | (present if flags[10] is set) +// +-------------------+ +// 72 | vbe_control_info | (present if flags[11] is set) +// 76 | vbe_mode_info | +// 80 | vbe_mode | +// 82 | vbe_interface_seg | +// 84 | vbe_interface_off | +// 86 | vbe_interface_len | +// +-------------------+ +// 88 | framebuffer_addr | (present if flags[12] is set) +// 96 | framebuffer_pitch | +// 100 | framebuffer_width | +// 104 | framebuffer_height| +// 108 | framebuffer_bpp | +// 109 | framebuffer_type | +// 110-115 | color_info | +// +-------------------+ + +/// The symbol table for a.out. +typedef struct multiboot_aout_symbol_table { + uint32_t tabsize; + uint32_t strsize; + uint32_t addr; + uint32_t reserved; +} multiboot_aout_symbol_table_t; + +/// The section header table for ELF. +typedef struct multiboot_elf_section_header_table { + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; +} multiboot_elf_section_header_table_t; + +// TODO: doxygen comment. +typedef struct multiboot_module { + // The memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive. + uint32_t mod_start; + uint32_t mod_end; + // Module command line. + uint32_t cmdline; + // Padding to take it to 16 bytes (must be zero). + uint32_t pad; +} multiboot_module_t; + +typedef struct multiboot_memory_map { + uint32_t size; + uint32_t base_addr_low; + uint32_t base_addr_high; + uint32_t length_low; + uint32_t length_high; + uint32_t type; +} multiboot_memory_map_t; + +// TODO: doxygen comment. +typedef struct multiboot_info { + /// Multiboot info version number. + uint32_t flags; + + /// Available memory from BIOS. + uint32_t mem_lower; + uint32_t mem_upper; + + /// "root" partition. + uint32_t boot_device; + + /// Kernel command line. + uint32_t cmdline; + + /// Boot-Module list. + uint32_t mods_count; + uint32_t mods_addr; + + union { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /// Memory Mapping buffer. + uint32_t mmap_length; + uint32_t mmap_addr; + + /// Drive Info buffer. + uint32_t drives_length; + uint32_t drives_addr; + + /// ROM configuration table. + uint32_t config_table; + + /// Boot Loader Name. + uint32_t boot_loader_name; + + /// APM table. + uint32_t apm_table; + + /// Video. + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint32_t vbe_mode; + uint32_t vbe_interface_seg; + uint32_t vbe_interface_off; + uint32_t vbe_interface_len; + + uint32_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint32_t framebuffer_bpp; + uint32_t framebuffer_type; + union { + struct { + uint32_t framebuffer_palette_addr; + uint16_t framebuffer_palette_num_colors; + }; + struct { + uint8_t framebuffer_red_field_position; + uint8_t framebuffer_red_mask_size; + uint8_t framebuffer_green_field_position; + uint8_t framebuffer_green_mask_size; + uint8_t framebuffer_blue_field_position; + uint8_t framebuffer_blue_mask_size; + }; + }; +} __attribute__((packed)) multiboot_info_t; + +// TODO: doxygen comment. +void dump_multiboot(multiboot_info_t *mboot_ptr); diff --git a/mentos/inc/process/prio.h b/mentos/inc/process/prio.h index 82a4a63..6bfad35 100644 --- a/mentos/inc/process/prio.h +++ b/mentos/inc/process/prio.h @@ -1,55 +1,55 @@ -/// MentOS, The Mentoring Operating system project -/// @file prio.h -/// @brief Defines processes priority value. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#define MAX_NICE +19 - -#define MIN_NICE -20 - -#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1) - -// Priority of a process goes from 0..MAX_PRIO-1, valid RT -// priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH -// tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority -// values are inverted: lower p->prio value means higher priority. -// -// The MAX_USER_RT_PRIO value allows the actual maximum -// RT priority to be separate from the value exported to -// user-space. This allows kernel threads to set their -// priority to a value higher than any user task. -// Note: MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO. - -#define MAX_RT_PRIO 100 - -#define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH) - -#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2) - -// Convert user-nice values [ -20 ... 0 ... 19 ] -// to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], -// and back. -#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO) - -#define PRIO_TO_NICE(prio) ((prio)-DEFAULT_PRIO) - -// 'User priority' is the nice value converted to something we -// can work with better when scaling various scheduler parameters, -// it's a [ 0 ... 39 ] range. -#define USER_PRIO(p) ((p)-MAX_RT_PRIO) - -#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio) - -#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) - -static const int prio_to_weight[NICE_WIDTH] = { - /* 100 */ 88761, 71755, 56483, 46273, 36291, - /* 105 */ 29154, 23254, 18705, 14949, 11916, - /* 110 */ 9548, 7620, 6100, 4904, 3906, - /* 115 */ 3121, 2501, 1991, 1586, 1277, - /* 120 */ 1024, 820, 655, 526, 423, - /* 125 */ 335, 272, 215, 172, 137, - /* 130 */ 110, 87, 70, 56, 45, - /* 135 */ 36, 29, 23, 18, 15 -}; +/// MentOS, The Mentoring Operating system project +/// @file prio.h +/// @brief Defines processes priority value. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#define MAX_NICE +19 + +#define MIN_NICE -20 + +#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1) + +// Priority of a process goes from 0..MAX_PRIO-1, valid RT +// priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH +// tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority +// values are inverted: lower p->prio value means higher priority. +// +// The MAX_USER_RT_PRIO value allows the actual maximum +// RT priority to be separate from the value exported to +// user-space. This allows kernel threads to set their +// priority to a value higher than any user task. +// Note: MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO. + +#define MAX_RT_PRIO 100 + +#define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH) + +#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2) + +// Convert user-nice values [ -20 ... 0 ... 19 ] +// to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], +// and back. +#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO) + +#define PRIO_TO_NICE(prio) ((prio)-DEFAULT_PRIO) + +// 'User priority' is the nice value converted to something we +// can work with better when scaling various scheduler parameters, +// it's a [ 0 ... 39 ] range. +#define USER_PRIO(p) ((p)-MAX_RT_PRIO) + +#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio) + +#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) + +static const int prio_to_weight[NICE_WIDTH] = { + /* 100 */ 88761, 71755, 56483, 46273, 36291, + /* 105 */ 29154, 23254, 18705, 14949, 11916, + /* 110 */ 9548, 7620, 6100, 4904, 3906, + /* 115 */ 3121, 2501, 1991, 1586, 1277, + /* 120 */ 1024, 820, 655, 526, 423, + /* 125 */ 335, 272, 215, 172, 137, + /* 130 */ 110, 87, 70, 56, 45, + /* 135 */ 36, 29, 23, 18, 15 +}; diff --git a/mentos/inc/process/process.h b/mentos/inc/process/process.h index aa26b82..c4f3ffa 100644 --- a/mentos/inc/process/process.h +++ b/mentos/inc/process/process.h @@ -1,203 +1,209 @@ -/// MentOS, The Mentoring Operating system project -/// @file process.h -/// @brief Process data structures and functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "list.h" -#include "tree.h" -#include "clock.h" -#include "types.h" -#include "stdint.h" -#include "stddef.h" -#include "paging.h" -#include "kernel.h" -#include "unistd.h" -#include "list_head.h" -#include "signal_defs.h" -#include "limits.h" - -/// The maximum length of a name for a task_struct. -#define TASK_NAME_MAX_LENGTH 100 - -/// The default dimension of the stack of a process (1 MByte). -#define DEFAULT_STACK_SIZE 0x100000 - -//==== Task state ============================================================== -// Used in tsk->state -/// The task is running. -#define TASK_RUNNING 0x0000 - -/// The task is interruptible. -#define TASK_INTERRUPTIBLE 0x0001 - -/// The task is uninterruptible. -#define TASK_UNINTERRUPTIBLE 0x0002 - -// Used in tsk->exit_state -/// The task is dead. -#define EXIT_DEAD 0x0010 - -/// The task is zombie. -#define EXIT_ZOMBIE 0x0020 -//============================================================================== - -/// @brief Every task_struck has a sched_entity. This structure is used to track -/// the statistics of a process. While the other variables also play a role in -/// CFS decisions'algorithm, vruntime is by far the core variable which needs -/// more attention as to understand the scheduling decision process. -/// @details -/// The nice value is a user-space and priority 'prio' is the process's actual -/// priority that use by Linux kernel. In linux system priorities are 0 to 139 -/// in which 0 to 99 for real time and 100 to 139 for users. -/// The nice value range is -20 to +19 where -20 is highest, 0 default and +19 -/// is lowest. relation between nice value and priority is : PR = 20 + NI. -typedef struct sched_entity { - /// Static execution priority. - int prio; - - /// Start execution time. - time_t start_runtime; - - /// Last context switch time. - time_t exec_start; - - /// Overall execution time. - time_t sum_exec_runtime; - - /// weighted execution time. - time_t vruntime; - -} sched_entity; - -// x86 thread (x86 and FPU registers). -typedef struct thread_struct { - /// 32-bit base pointer register. - uint32_t ebp; - - /// 32-bit stack pointer register. - uint32_t useresp; - - /// 32-bit base register. - uint32_t ebx; - - /// 32-bit data register. - uint32_t edx; - - /// 32-bit counter. - uint32_t ecx; - - /// 32-bit accumulator register. - uint32_t eax; - - /// Instruction Pointer Register. - uint32_t eip; - - /// 32-bit flag register. - uint32_t eflags; - - /// FS and GS have no hardware-assigned uses. - uint32_t gs; - - /// FS and GS have no hardware-assigned uses. - uint32_t fs; - - /// Extra Segment determined by the programmer. - uint32_t es; - - /// Data Segment. - uint32_t ds; - - /// 32-bit destination register. - uint32_t edi; - - /// 32-bit source register. - uint32_t esi; - - // ///< Code Segment. - // uint32_t cs; - - // ///< Stack Segment. - // uint32_t ss; - - /// Determines if the FPU is enabled. - bool_t fpu_enabled; - - /// Data structure used to save FPU registers. - savefpu fpu_register; -} thread_struct; - -/// @brief this is our task object. Every process in the system has this, and -/// it holds a lot of information. It’ll hold mm information, it’s name, -/// statistics, etc.. -typedef struct task_struct { - /// The pid of the process. - pid_t pid; - - // -1 unrunnable, 0 runnable, >0 stopped. - /// The current state of the process: - __volatile__ long state; - - /// Pointer to process's parent. - struct task_struct *parent; - - /// List head for scheduling purposes. - list_head run_list; - - /// List of children traced by the process. - list_head children; - - /// List of siblings. - list_head sibling; - - /// The context of the processors. - thread_struct thread; - - /// For scheduling algorithms. - sched_entity se; - - /// Exit code of the process. (parameter of _exit() system call). - int exit_code; - - /// The name of the task (Added for debug purpose). - char name[TASK_NAME_MAX_LENGTH]; - - /// Task's segments. - struct mm_struct *mm; - - /// Task's specific error number. - int error_no; - - /// The current working directory. - char cwd[PATH_MAX]; - - //==== Future work ========================================================= - // - task's attributes: - // struct task_struct __rcu *real_parent; - // int exit_state; - // int exit_signal; - // struct thread_info thread_info; - // List of sibling, namely processes created by parent process - // struct list_head sibling; - - // - task's file descriptor: - // struct files_struct *files; - - // - task's signal handlers: - // struct signal_struct *signal; - // struct sighand_struct *sighand; - // sigset_t blocked; - // sigset_t real_blocked; - // sigset_t saved_sigmask; - // struct sigpending pending; - //========================================================================== - -} task_struct; - -// TODO: doxygen comment. -char *get_current_dir_name(); - -/// @brief Create and spawn the init process. -struct task_struct *create_init_process(); +/// MentOS, The Mentoring Operating system project +/// @file process.h +/// @brief Process data structures and functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "list.h" +#include "tree.h" +#include "clock.h" +#include "types.h" +#include "stdint.h" +#include "stddef.h" +#include "paging.h" +#include "kernel.h" +#include "unistd.h" +#include "list_head.h" +#include "signal_defs.h" +#include "limits.h" + +/// The maximum length of a name for a task_struct. +#define TASK_NAME_MAX_LENGTH 100 + +/// The default dimension of the stack of a process (1 MByte). +#define DEFAULT_STACK_SIZE 0x100000 + +/// The maximum number of resources for a task. +#define TASK_RESOURCE_MAX_AMOUNT 32 + +//==== Task state ============================================================== +// Used in tsk->state +/// The task is running. +#define TASK_RUNNING 0x0000 + +/// The task is interruptible. +#define TASK_INTERRUPTIBLE 0x0001 + +/// The task is uninterruptible. +#define TASK_UNINTERRUPTIBLE 0x0002 + +// Used in tsk->exit_state +/// The task is dead. +#define EXIT_DEAD 0x0010 + +/// The task is zombie. +#define EXIT_ZOMBIE 0x0020 +//============================================================================== + +/// @brief Every task_struck has a sched_entity. This structure is used to track +/// the statistics of a process. While the other variables also play a role in +/// CFS decisions'algorithm, vruntime is by far the core variable which needs +/// more attention as to understand the scheduling decision process. +/// @details +/// The nice value is a user-space and priority 'prio' is the process's actual +/// priority that use by Linux kernel. In linux system priorities are 0 to 139 +/// in which 0 to 99 for real time and 100 to 139 for users. +/// The nice value range is -20 to +19 where -20 is highest, 0 default and +19 +/// is lowest. relation between nice value and priority is : PR = 20 + NI. +typedef struct sched_entity { + /// Static execution priority. + int prio; + + /// Start execution time. + time_t start_runtime; + + /// Last context switch time. + time_t exec_start; + + /// Overall execution time. + time_t sum_exec_runtime; + + /// weighted execution time. + time_t vruntime; + +} sched_entity; + +// x86 thread (x86 and FPU registers). +typedef struct thread_struct { + /// 32-bit base pointer register. + uint32_t ebp; + + /// 32-bit stack pointer register. + uint32_t useresp; + + /// 32-bit base register. + uint32_t ebx; + + /// 32-bit data register. + uint32_t edx; + + /// 32-bit counter. + uint32_t ecx; + + /// 32-bit accumulator register. + uint32_t eax; + + /// Instruction Pointer Register. + uint32_t eip; + + /// 32-bit flag register. + uint32_t eflags; + + /// FS and GS have no hardware-assigned uses. + uint32_t gs; + + /// FS and GS have no hardware-assigned uses. + uint32_t fs; + + /// Extra Segment determined by the programmer. + uint32_t es; + + /// Data Segment. + uint32_t ds; + + /// 32-bit destination register. + uint32_t edi; + + /// 32-bit source register. + uint32_t esi; + + // ///< Code Segment. + // uint32_t cs; + + // ///< Stack Segment. + // uint32_t ss; + + /// Determines if the FPU is enabled. + bool_t fpu_enabled; + + /// Data structure used to save FPU registers. + savefpu fpu_register; +} thread_struct; + +/// @brief this is our task object. Every process in the system has this, and +/// it holds a lot of information. It’ll hold mm information, it’s name, +/// statistics, etc.. +typedef struct task_struct { + /// The pid of the process. + pid_t pid; + + // -1 unrunnable, 0 runnable, >0 stopped. + /// The current state of the process: + __volatile__ long state; + + /// Pointer to process's parent. + struct task_struct *parent; + + /// List head for scheduling purposes. + list_head run_list; + + /// List of children traced by the process. + list_head children; + + /// List of siblings. + list_head sibling; + + /// The context of the processors. + thread_struct thread; + + /// For scheduling algorithms. + sched_entity se; + + /// Exit code of the process. (parameter of _exit() system call). + int exit_code; + + /// The name of the task (Added for debug purpose). + char name[TASK_NAME_MAX_LENGTH]; + + /// Task's segments. + struct mm_struct *mm; + + /// Task's specific error number. + int error_no; + + /// The current working directory. + char cwd[PATH_MAX]; + + /// Array of resource pointers that task need for. + struct resource *resources[TASK_RESOURCE_MAX_AMOUNT]; + + //==== Future work ========================================================= + // - task's attributes: + // struct task_struct __rcu *real_parent; + // int exit_state; + // int exit_signal; + // struct thread_info thread_info; + // List of sibling, namely processes created by parent process + // struct list_head sibling; + + // - task's file descriptor: + // struct files_struct *files; + + // - task's signal handlers: + // struct signal_struct *signal; + // struct sighand_struct *sighand; + // sigset_t blocked; + // sigset_t real_blocked; + // sigset_t saved_sigmask; + // struct sigpending pending; + //========================================================================== + +} task_struct; + +// TODO: doxygen comment. +char *get_current_dir_name(); + +/// @brief Create and spawn the init process. +struct task_struct *create_init_process(); diff --git a/mentos/inc/process/scheduler.h b/mentos/inc/process/scheduler.h index 7aacb1c..d304e45 100644 --- a/mentos/inc/process/scheduler.h +++ b/mentos/inc/process/scheduler.h @@ -1,68 +1,68 @@ -/// MentOS, The Mentoring Operating system project -/// @file scheduler.h -/// @brief Scheduler structures and functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "clock.h" -#include "kernel.h" -#include "stdint.h" -#include "process.h" - -typedef struct { - /// Number of queued processes. - size_t num_active; - - /// Queue of processes. - list_head queue; - - /// The current running process. - task_struct *curr; -} runqueue_t; - -/// @brief Returns a non-decreasing unique process id. -/// @return Process identifier (PID). -uint32_t get_new_pid(); - -/// @brief Initialize the scheduler. -void kernel_initialize_scheduler(); - -/// @brief Activate the given process. -/// @param process Process that has to be activated. -void enqueue_task(task_struct *process); - -/// @brief Removes the given process from the queue. -/// @param process Process that has to be activated. -void dequeue_task(task_struct *process); - -/// @brief Returns the number of active processes. -size_t kernel_get_active_processes(); - -/// @brief Returns the pointer to the current active process. -task_struct *kernel_get_current_process(); - -/// @brief Returns a pointer to the process with the given pid. -task_struct *kernel_get_running_process(pid_t pid); - -task_struct *pick_next_task(runqueue_t *runqueue, time_t delta_exec); - -/// @brief The RR implementation of the scheduler. -/// @param f The context of the process. -void kernel_schedule(pt_regs *f); - -/// @birief Values from pt_regs to task_struct process. -void update_context(pt_regs *f, task_struct *process); - -/// @brief Values from task_struct process to pt_regs. -void do_switch(task_struct *process, pt_regs *f); - -/// @brief Switch CPU to user mode and start running that given process. -/// @param process The process that has to be executed -void enter_user_jmp(uintptr_t location, uintptr_t stack); - -/// @brief Sets the priority value of the given task. -int set_user_nice(task_struct *p, long nice); - - +/// MentOS, The Mentoring Operating system project +/// @file scheduler.h +/// @brief Scheduler structures and functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "clock.h" +#include "kernel.h" +#include "stdint.h" +#include "process.h" + +typedef struct { + /// Number of queued processes. + size_t num_active; + + /// Queue of processes. + list_head queue; + + /// The current running process. + task_struct *curr; +} runqueue_t; + +/// @brief Returns a non-decreasing unique process id. +/// @return Process identifier (PID). +uint32_t get_new_pid(); + +/// @brief Initialize the scheduler. +void kernel_initialize_scheduler(); + +/// @brief Activate the given process. +/// @param process Process that has to be activated. +void enqueue_task(task_struct *process); + +/// @brief Removes the given process from the queue. +/// @param process Process that has to be activated. +void dequeue_task(task_struct *process); + +/// @brief Returns the number of active processes. +size_t kernel_get_active_processes(); + +/// @brief Returns the pointer to the current active process. +task_struct *kernel_get_current_process(); + +/// @brief Returns a pointer to the process with the given pid. +task_struct *kernel_get_running_process(pid_t pid); + +task_struct *pick_next_task(runqueue_t *runqueue, time_t delta_exec); + +/// @brief The RR implementation of the scheduler. +/// @param f The context of the process. +void kernel_schedule(pt_regs *f); + +/// @birief Values from pt_regs to task_struct process. +void update_context(pt_regs *f, task_struct *process); + +/// @brief Values from task_struct process to pt_regs. +void do_switch(task_struct *process, pt_regs *f); + +/// @brief Switch CPU to user mode and start running that given process. +/// @param process The process that has to be executed +void enter_user_jmp(uintptr_t location, uintptr_t stack); + +/// @brief Sets the priority value of the given task. +int set_user_nice(task_struct *p, long nice); + + diff --git a/mentos/inc/sys/dirent.h b/mentos/inc/sys/dirent.h index f81fd7a..51db0d4 100644 --- a/mentos/inc/sys/dirent.h +++ b/mentos/inc/sys/dirent.h @@ -1,48 +1,48 @@ -/// MentOS, The Mentoring Operating system project -/// @file dirent.h -/// @brief Functions used to manage directories. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" -#include "limits.h" - -/// @brief Contains the entries of a directory. -typedef struct dirent_t { - /// The inode of the entry. - ino_t d_ino; - - /// The type of the entry. - int d_type; - - /// The nam of the entry. - char d_name[NAME_MAX + 1]; -} dirent_t; - -/// @brief Contains information concerning a directory. -typedef struct DIR { - /// Filesystem directory handle. - int fd; - /// The currently opened entry. - ino_t cur_entry; - /// Path to the directory. - char path[NAME_MAX + 1]; - /// Next directory item. - dirent_t entry; -} DIR; - -/// @brief Opens a directory and returns a handler to it. -/// @param path The path of the directory. -/// @return Pointer to the directory. Otherwise, NULL. -DIR *opendir(const char *path); - -/// @brief Given a pointer to a directory, it closes it. -int closedir(DIR *dirp); - -/// @brief At each call of this function, it returns a pointer to the next -/// element inside the directory. -/// @return A pointer to the next element. If there are no more elments, it -/// returns NULL. -dirent_t *readdir(DIR *dirp); +/// MentOS, The Mentoring Operating system project +/// @file dirent.h +/// @brief Functions used to manage directories. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" +#include "limits.h" + +/// @brief Contains the entries of a directory. +typedef struct dirent_t { + /// The inode of the entry. + ino_t d_ino; + + /// The type of the entry. + int d_type; + + /// The nam of the entry. + char d_name[NAME_MAX + 1]; +} dirent_t; + +/// @brief Contains information concerning a directory. +typedef struct DIR { + /// Filesystem directory handle. + int fd; + /// The currently opened entry. + ino_t cur_entry; + /// Path to the directory. + char path[NAME_MAX + 1]; + /// Next directory item. + dirent_t entry; +} DIR; + +/// @brief Opens a directory and returns a handler to it. +/// @param path The path of the directory. +/// @return Pointer to the directory. Otherwise, NULL. +DIR *opendir(const char *path); + +/// @brief Given a pointer to a directory, it closes it. +int closedir(DIR *dirp); + +/// @brief At each call of this function, it returns a pointer to the next +/// element inside the directory. +/// @return A pointer to the next element. If there are no more elments, it +/// returns NULL. +dirent_t *readdir(DIR *dirp); diff --git a/mentos/inc/sys/errno.h b/mentos/inc/sys/errno.h index eeff0de..ec83dff 100644 --- a/mentos/inc/sys/errno.h +++ b/mentos/inc/sys/errno.h @@ -1,383 +1,383 @@ -/// MentOS, The Mentoring Operating system project -/// @file process.c -/// @brief System call errors definition. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -extern int *__geterrno(); - -#define errno (*__geterrno()) - -/// Operation not permitted. -#define EPERM 1 - -/// No such file or directory. -#define ENOENT 2 - -/// No such process. -#define ESRCH 3 - -/// Interrupted system call. -#define EINTR 4 - -///I/O error. -#define EIO 5 - -/// No such device or address. -#define ENXIO 6 - -/// Arg list too long. -#define E2BIG 7 - -/// Exec format error. -#define ENOEXEC 8 - -/// Bad file number. -#define EBADF 9 - -/// No child processes. -#define ECHILD 10 - -/// Try again. -#define EAGAIN 11 - -/// Out of memory. -#define ENOMEM 12 - -/// Permission denied. -#define EACCES 13 - -/// Bad address. -#define EFAULT 14 - -/// Block device required. -#define ENOTBLK 15 - -/// Device or resource busy. -#define EBUSY 16 - -/// File exists. -#define EEXIST 17 - -/// Cross-device link. -#define EXDEV 18 - -/// No such device. -#define ENODEV 19 - -/// Not a directory. -#define ENOTDIR 20 - -/// Is a directory. -#define EISDIR 21 - -/// Invalid argument. -#define EINVAL 22 - -/// File table overflow. -#define ENFILE 23 - -/// Too many open files. -#define EMFILE 24 - -/// Not a typewriter. -#define ENOTTY 25 - -/// Text file busy. -#define ETXTBSY 26 - -/// File too large. -#define EFBIG 27 - -/// No space left on device. -#define ENOSPC 28 - -/// Illegal seek. -#define ESPIPE 29 - -/// Read-only file system. -#define EROFS 30 - -/// Too many links. -#define EMLINK 31 - -/// Broken pipe. -#define EPIPE 32 - -/// Math argument out of domain of func. -#define EDOM 33 - -/// Math result not representable. -#define ERANGE 34 - -/// Resource deadlock would occur. -#define EDEADLK 35 - -/// File name too long. -#define ENAMETOOLONG 36 - -/// No record locks available. -#define ENOLCK 37 - -/// Function not implemented. -#define ENOSYS 38 - -/// Directory not empty. -#define ENOTEMPTY 39 - -/// Too many symbolic links encountered. -#define ELOOP 40 - -/// Operation would block. -#define EWOULDBLOCK EAGAIN - -/// No message of desired type. -#define ENOMSG 42 - -/// Identifier removed. -#define EIDRM 43 - -/// Channel number out of range. -#define ECHRNG 44 - -/// Level 2 not synchronized. -#define EL2NSYNC 45 - -/// Level 3 halted. -#define EL3HLT 46 - -/// Level 3 reset. -#define EL3RST 47 - -/// Link number out of range. -#define ELNRNG 48 - -/// Protocol driver not attached. -#define EUNATCH 49 - -/// No CSI structure available. -#define ENOCSI 50 - -/// Level 2 halted. -#define EL2HLT 51 - -/// Invalid exchange. -#define EBADE 52 - -/// Invalid request descriptor. -#define EBADR 53 - -/// Exchange full. -#define EXFULL 54 - -/// No anode. -#define ENOANO 55 - -/// Invalid request code. -#define EBADRQC 56 - -/// Invalid slot. -#define EBADSLT 57 - -// TODO: doxygen comment. -#define EDEADLOCK EDEADLK - -/// Bad font file format. -#define EBFONT 59 - -/// Device not a stream. -#define ENOSTR 60 - -/// No data available. -#define ENODATA 61 - -/// Timer expired. -#define ETIME 62 - -/// Out of streams resources. -#define ENOSR 63 - -/// Machine is not on the network. -#define ENONET 64 - -/// Package not installed. -#define ENOPKG 65 - -/// Object is remote. -#define EREMOTE 66 - -/// Link has been severed. -#define ENOLINK 67 - -/// Advertise error. -#define EADV 68 - -/// Srmount error. -#define ESRMNT 69 - -/// Communication error on send. -#define ECOMM 70 - -/// Protocol error. -#define EPROTO 71 - -/// Multihop attempted. -#define EMULTIHOP 72 - -/// RFS specific error. -#define EDOTDOT 73 - -/// Not a data message. -#define EBADMSG 74 - -/// Value too large for defined data type. -#define EOVERFLOW 75 - -/// Name not unique on network. -#define ENOTUNIQ 76 - -/// File descriptor in bad state. -#define EBADFD 77 - -/// Remote address changed. -#define EREMCHG 78 - -/// Can not access a needed shared library. -#define ELIBACC 79 - -/// Accessing a corrupted shared library. -#define ELIBBAD 80 - -/// .lib section in a.out corrupted. -#define ELIBSCN 81 - -/// Attempting to link in too many shared libraries. -#define ELIBMAX 82 - -/// Cannot exec a shared library directly. -#define ELIBEXEC 83 - -/// Illegal byte sequence. -#define EILSEQ 84 - -/// Interrupted system call should be restarted. -#define ERESTART 85 - -/// Streams pipe error. -#define ESTRPIPE 86 - -/// Too many users. -#define EUSERS 87 - -///Socket operation on non-socket. -#define ENOTSOCK 88 - -/// Destination address required. -#define EDESTADDRREQ 89 - -/// Message too long. -#define EMSGSIZE 90 - -/// Protocol wrong type for socket. -#define EPROTOTYPE 91 - -/// Protocol not available. -#define ENOPROTOOPT 92 - -/// Protocol not supported. -#define EPROTONOSUPPORT 93 - -/// Socket type not supported. -#define ESOCKTNOSUPPORT 94 - -/// Operation not supported on transport endpoint. -#define EOPNOTSUPP 95 - -/// Protocol family not supported. -#define EPFNOSUPPORT 96 - -/// Address family not supported by protocol. -#define EAFNOSUPPORT 97 - -/// Address already in use. -#define EADDRINUSE 98 - -/// Cannot assign requested address. -#define EADDRNOTAVAIL 99 - -/// Network is down. -#define ENETDOWN 100 - -/// Network is unreachable. -#define ENETUNREACH 101 - -/// Network dropped connection because of reset. -#define ENETRESET 102 - -/// Software caused connection abort. -#define ECONNABORTED 103 - -/// Connection reset by peer. -#define ECONNRESET 104 - -/// No buffer space available. -#define ENOBUFS 105 - -/// Transport endpoint is already connected. -#define EISCONN 106 - -/// Transport endpoint is not connected. -#define ENOTCONN 107 - -/// Cannot send after transport endpoint shutdown. -#define ESHUTDOWN 108 - -/// Too many references: cannot splice. -#define ETOOMANYREFS 109 - -/// Connection timed out. -#define ETIMEDOUT 110 - -/// Connection refused. -#define ECONNREFUSED 111 - -/// Host is down. -#define EHOSTDOWN 112 - -/// No route to host. -#define EHOSTUNREACH 113 - -///Operation already in progress. -#define EALREADY 114 - -/// Operation now in progress. -#define EINPROGRESS 115 - -/// Stale NFS file handle. -#define ESTALE 116 - -/// Structure needs cleaning. -#define EUCLEAN 117 - -/// Not a XENIX named type file. -#define ENOTNAM 118 - -/// No XENIX semaphores available. -#define ENAVAIL 119 - -/// Is a named type file. -#define EISNAM 120 - -/// Remote I/O error. -#define EREMOTEIO 121 - -/// Quota exceeded. -#define EDQUOT 122 - -/// No medium found. -#define ENOMEDIUM 123 - -/// Wrong medium type. -#define EMEDIUMTYPE 124 +/// MentOS, The Mentoring Operating system project +/// @file process.c +/// @brief System call errors definition. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +extern int *__geterrno(); + +#define errno (*__geterrno()) + +/// Operation not permitted. +#define EPERM 1 + +/// No such file or directory. +#define ENOENT 2 + +/// No such process. +#define ESRCH 3 + +/// Interrupted system call. +#define EINTR 4 + +///I/O error. +#define EIO 5 + +/// No such device or address. +#define ENXIO 6 + +/// Arg list too long. +#define E2BIG 7 + +/// Exec format error. +#define ENOEXEC 8 + +/// Bad file number. +#define EBADF 9 + +/// No child processes. +#define ECHILD 10 + +/// Try again. +#define EAGAIN 11 + +/// Out of memory. +#define ENOMEM 12 + +/// Permission denied. +#define EACCES 13 + +/// Bad address. +#define EFAULT 14 + +/// Block device required. +#define ENOTBLK 15 + +/// Device or resource busy. +#define EBUSY 16 + +/// File exists. +#define EEXIST 17 + +/// Cross-device link. +#define EXDEV 18 + +/// No such device. +#define ENODEV 19 + +/// Not a directory. +#define ENOTDIR 20 + +/// Is a directory. +#define EISDIR 21 + +/// Invalid argument. +#define EINVAL 22 + +/// File table overflow. +#define ENFILE 23 + +/// Too many open files. +#define EMFILE 24 + +/// Not a typewriter. +#define ENOTTY 25 + +/// Text file busy. +#define ETXTBSY 26 + +/// File too large. +#define EFBIG 27 + +/// No space left on device. +#define ENOSPC 28 + +/// Illegal seek. +#define ESPIPE 29 + +/// Read-only file system. +#define EROFS 30 + +/// Too many links. +#define EMLINK 31 + +/// Broken pipe. +#define EPIPE 32 + +/// Math argument out of domain of func. +#define EDOM 33 + +/// Math result not representable. +#define ERANGE 34 + +/// Resource deadlock would occur. +#define EDEADLK 35 + +/// File name too long. +#define ENAMETOOLONG 36 + +/// No record locks available. +#define ENOLCK 37 + +/// Function not implemented. +#define ENOSYS 38 + +/// Directory not empty. +#define ENOTEMPTY 39 + +/// Too many symbolic links encountered. +#define ELOOP 40 + +/// Operation would block. +#define EWOULDBLOCK EAGAIN + +/// No message of desired type. +#define ENOMSG 42 + +/// Identifier removed. +#define EIDRM 43 + +/// Channel number out of range. +#define ECHRNG 44 + +/// Level 2 not synchronized. +#define EL2NSYNC 45 + +/// Level 3 halted. +#define EL3HLT 46 + +/// Level 3 reset. +#define EL3RST 47 + +/// Link number out of range. +#define ELNRNG 48 + +/// Protocol driver not attached. +#define EUNATCH 49 + +/// No CSI structure available. +#define ENOCSI 50 + +/// Level 2 halted. +#define EL2HLT 51 + +/// Invalid exchange. +#define EBADE 52 + +/// Invalid request descriptor. +#define EBADR 53 + +/// Exchange full. +#define EXFULL 54 + +/// No anode. +#define ENOANO 55 + +/// Invalid request code. +#define EBADRQC 56 + +/// Invalid slot. +#define EBADSLT 57 + +// TODO: doxygen comment. +#define EDEADLOCK EDEADLK + +/// Bad font file format. +#define EBFONT 59 + +/// Device not a stream. +#define ENOSTR 60 + +/// No data available. +#define ENODATA 61 + +/// Timer expired. +#define ETIME 62 + +/// Out of streams resources. +#define ENOSR 63 + +/// Machine is not on the network. +#define ENONET 64 + +/// Package not installed. +#define ENOPKG 65 + +/// Object is remote. +#define EREMOTE 66 + +/// Link has been severed. +#define ENOLINK 67 + +/// Advertise error. +#define EADV 68 + +/// Srmount error. +#define ESRMNT 69 + +/// Communication error on send. +#define ECOMM 70 + +/// Protocol error. +#define EPROTO 71 + +/// Multihop attempted. +#define EMULTIHOP 72 + +/// RFS specific error. +#define EDOTDOT 73 + +/// Not a data message. +#define EBADMSG 74 + +/// Value too large for defined data type. +#define EOVERFLOW 75 + +/// Name not unique on network. +#define ENOTUNIQ 76 + +/// File descriptor in bad state. +#define EBADFD 77 + +/// Remote address changed. +#define EREMCHG 78 + +/// Can not access a needed shared library. +#define ELIBACC 79 + +/// Accessing a corrupted shared library. +#define ELIBBAD 80 + +/// .lib section in a.out corrupted. +#define ELIBSCN 81 + +/// Attempting to link in too many shared libraries. +#define ELIBMAX 82 + +/// Cannot exec a shared library directly. +#define ELIBEXEC 83 + +/// Illegal byte sequence. +#define EILSEQ 84 + +/// Interrupted system call should be restarted. +#define ERESTART 85 + +/// Streams pipe error. +#define ESTRPIPE 86 + +/// Too many users. +#define EUSERS 87 + +///Socket operation on non-socket. +#define ENOTSOCK 88 + +/// Destination address required. +#define EDESTADDRREQ 89 + +/// Message too long. +#define EMSGSIZE 90 + +/// Protocol wrong type for socket. +#define EPROTOTYPE 91 + +/// Protocol not available. +#define ENOPROTOOPT 92 + +/// Protocol not supported. +#define EPROTONOSUPPORT 93 + +/// Socket type not supported. +#define ESOCKTNOSUPPORT 94 + +/// Operation not supported on transport endpoint. +#define EOPNOTSUPP 95 + +/// Protocol family not supported. +#define EPFNOSUPPORT 96 + +/// Address family not supported by protocol. +#define EAFNOSUPPORT 97 + +/// Address already in use. +#define EADDRINUSE 98 + +/// Cannot assign requested address. +#define EADDRNOTAVAIL 99 + +/// Network is down. +#define ENETDOWN 100 + +/// Network is unreachable. +#define ENETUNREACH 101 + +/// Network dropped connection because of reset. +#define ENETRESET 102 + +/// Software caused connection abort. +#define ECONNABORTED 103 + +/// Connection reset by peer. +#define ECONNRESET 104 + +/// No buffer space available. +#define ENOBUFS 105 + +/// Transport endpoint is already connected. +#define EISCONN 106 + +/// Transport endpoint is not connected. +#define ENOTCONN 107 + +/// Cannot send after transport endpoint shutdown. +#define ESHUTDOWN 108 + +/// Too many references: cannot splice. +#define ETOOMANYREFS 109 + +/// Connection timed out. +#define ETIMEDOUT 110 + +/// Connection refused. +#define ECONNREFUSED 111 + +/// Host is down. +#define EHOSTDOWN 112 + +/// No route to host. +#define EHOSTUNREACH 113 + +///Operation already in progress. +#define EALREADY 114 + +/// Operation now in progress. +#define EINPROGRESS 115 + +/// Stale NFS file handle. +#define ESTALE 116 + +/// Structure needs cleaning. +#define EUCLEAN 117 + +/// Not a XENIX named type file. +#define ENOTNAM 118 + +/// No XENIX semaphores available. +#define ENAVAIL 119 + +/// Is a named type file. +#define EISNAM 120 + +/// Remote I/O error. +#define EREMOTEIO 121 + +/// Quota exceeded. +#define EDQUOT 122 + +/// No medium found. +#define ENOMEDIUM 123 + +/// Wrong medium type. +#define EMEDIUMTYPE 124 diff --git a/mentos/inc/sys/ipc.h b/mentos/inc/sys/ipc.h index 4bd6eba..afe2b86 100644 --- a/mentos/inc/sys/ipc.h +++ b/mentos/inc/sys/ipc.h @@ -1,53 +1,53 @@ -/// MentOS, The Mentoring Operating system project -/// @file ipc.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stddef.h" - -/// Create key if key does not exist. -#define IPC_CREAT 01000 - -/// Fail if key exists. -#define IPC_EXCL 02000 - -/// Return error on wait. -#define IPC_NOWAIT 04000 - -/// Remove identifier. -#define IPC_RMID 0 - -/// Set `ipc_perm' options. -#define IPC_SET 1 - -/// Get `ipc_perm' options. -#define IPC_STAT 2 - -/// See ipcs. -#define IPC_INFO 3 - -struct ipc_perm { - /// Creator user id. - uid_t cuid; - - /// Creator group id. - gid_t cgid; - - /// User id. - uid_t uid; - - /// Group id. - gid_t gid; - - /// r/w permission. - ushort mode; - - /// Sequence # (to generate unique msg/sem/shm id). - ushort seq; - - /// User specified msg/sem/shm key. - key_t key; -}; +/// MentOS, The Mentoring Operating system project +/// @file ipc.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stddef.h" + +/// Create key if key does not exist. +#define IPC_CREAT 01000 + +/// Fail if key exists. +#define IPC_EXCL 02000 + +/// Return error on wait. +#define IPC_NOWAIT 04000 + +/// Remove identifier. +#define IPC_RMID 0 + +/// Set `ipc_perm' options. +#define IPC_SET 1 + +/// Get `ipc_perm' options. +#define IPC_STAT 2 + +/// See ipcs. +#define IPC_INFO 3 + +struct ipc_perm { + /// Creator user id. + uid_t cuid; + + /// Creator group id. + gid_t cgid; + + /// User id. + uid_t uid; + + /// Group id. + gid_t gid; + + /// r/w permission. + ushort mode; + + /// Sequence # (to generate unique msg/sem/shm id). + ushort seq; + + /// User specified msg/sem/shm key. + key_t key; +}; diff --git a/mentos/inc/sys/module.h b/mentos/inc/sys/module.h index 02386d7..9cf50d3 100644 --- a/mentos/inc/sys/module.h +++ b/mentos/inc/sys/module.h @@ -1,7 +1,7 @@ -/// MentOS, The Mentoring Operating system project -/// @file module.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once +/// MentOS, The Mentoring Operating system project +/// @file module.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once diff --git a/mentos/inc/sys/reboot.h b/mentos/inc/sys/reboot.h index 8547eff..ace1ba3 100644 --- a/mentos/inc/sys/reboot.h +++ b/mentos/inc/sys/reboot.h @@ -1,43 +1,43 @@ -/// MentOS, The Mentoring Operating system project -/// @file reboot.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -// Magic values required to use _reboot() system call. -#define LINUX_REBOOT_MAGIC1 0xfee1dead - -#define LINUX_REBOOT_MAGIC2 672274793 - -#define LINUX_REBOOT_MAGIC2A 85072278 - -#define LINUX_REBOOT_MAGIC2B 369367448 - -#define LINUX_REBOOT_MAGIC2C 537993216 - -// Commands accepted by the _reboot() system call. -/// Restart system using default command and mode. -#define LINUX_REBOOT_CMD_RESTART 0x01234567 - -/// Stop OS and give system control to ROM monitor, if any. -#define LINUX_REBOOT_CMD_HALT 0xCDEF0123 - -/// Ctrl-Alt-Del sequence causes RESTART command. -#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF - -/// Ctrl-Alt-Del sequence sends SIGINT to init task. -#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 - -/// Stop OS and remove all power from system, if possible. -#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC - -/// Restart system using given command string. -#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 - -/// Suspend system using software suspend if compiled in. -#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 - -/// Restart system using a previously loaded Linux kernel -#define LINUX_REBOOT_CMD_KEXEC 0x45584543 +/// MentOS, The Mentoring Operating system project +/// @file reboot.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +// Magic values required to use _reboot() system call. +#define LINUX_REBOOT_MAGIC1 0xfee1dead + +#define LINUX_REBOOT_MAGIC2 672274793 + +#define LINUX_REBOOT_MAGIC2A 85072278 + +#define LINUX_REBOOT_MAGIC2B 369367448 + +#define LINUX_REBOOT_MAGIC2C 537993216 + +// Commands accepted by the _reboot() system call. +/// Restart system using default command and mode. +#define LINUX_REBOOT_CMD_RESTART 0x01234567 + +/// Stop OS and give system control to ROM monitor, if any. +#define LINUX_REBOOT_CMD_HALT 0xCDEF0123 + +/// Ctrl-Alt-Del sequence causes RESTART command. +#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF + +/// Ctrl-Alt-Del sequence sends SIGINT to init task. +#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 + +/// Stop OS and remove all power from system, if possible. +#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC + +/// Restart system using given command string. +#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 + +/// Suspend system using software suspend if compiled in. +#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 + +/// Restart system using a previously loaded Linux kernel +#define LINUX_REBOOT_CMD_KEXEC 0x45584543 diff --git a/mentos/inc/sys/shm.h b/mentos/inc/sys/shm.h index 8a80360..e3b151e 100644 --- a/mentos/inc/sys/shm.h +++ b/mentos/inc/sys/shm.h @@ -1,132 +1,132 @@ -/// MentOS, The Mentoring Operating system project -/// @file shm.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "ipc.h" -#include "debug.h" -#include "clock.h" -#include "kheap.h" -#include "stddef.h" -#include "paging.h" -#include "syscall.h" -#include "scheduler.h" - -//======== Permission flag for shmget ========================================== -// or S_IRUGO from . -#define SHM_R 0400 - -// or S_IWUGO from . -#define SHM_W 0200 -//============================================================================== - -//======== Flags for shmat ===================================================== -// Attach read-only else read-write. -#define SHM_RDONLY 010000 - -// Round attach address to SHMLBA. -#define SHM_RND 020000 - -// Take-over region on attach. -#define SHM_REMAP 040000 - -// Execution access. -#define SHM_EXEC 0100000 -//============================================================================== - -//======== Commands for shmctl ================================================= -// Lock segment (root only). -#define SHM_LOCK 11 - -// Unlock segment (root only). -#define SHM_UNLOCK 12 -//============================================================================== - -// Ipcs ctl commands. -#define SHM_STAT 13 - -#define SHM_INFO 14 - -#define SHM_STAT_ANY 15 - -//======== shm_mode upper byte flags =========================================== -// segment will be destroyed on last detach. -#define SHM_DEST 01000 - -// Segment will not be swapped. -#define SHM_LOCKED 02000 - -// Segment is mapped via hugetlb. -#define SHM_HUGETLB 04000 - -// Don't check for reservations. -#define SHM_NORESERVE 010000 - -typedef unsigned long shmatt_t; - -struct shmid_ds { - // Operation permission struct. - struct ipc_perm shm_perm; - - // Size of segment in bytes. - size_t shm_segsz; - - // Time of last shmat(). - time_t shm_atime; - - // Time of last shmdt(). - time_t shm_dtime; - - // Time of last change by shmctl(). - time_t shm_ctime; - - // Pid of creator. - pid_t shm_cpid; - - // Pid of last shmop. - pid_t shm_lpid; - - // Number of current attaches. - shmatt_t shm_nattch; - - struct shmid_ds *next; - - // Where shm created is memorized, should be a file. - void *shm_location; -}; - -/// @@brief Syscall Service Routine: Shared memory control operation. -int syscall_shmctl(int *args); - -/// @@brief Syscall Service Routine: Get shared memory segment. -int syscall_shmget(int *args); - -/// @@brief Syscall Service Routine: Attach shared memory segment. -void *syscall_shmat(int *args); - -/// @@brief Syscall Service Routine: Detach shared memory segment. -int syscall_shmdt(int *args); - -/// @@brief User Wrapper: Shared memory control operation. -int shmctl(int shmid, int cmd, struct shmid_ds *buf); - -/// @@brief User Wrapper: Get shared memory segment. -int shmget(key_t key, size_t size, int flags); - -/// @@brief User Wrapper: Attach shared memory segment. -void *shmat(int shmid, void *shmaddr, int flag); - -/// @@brief User Wrapper: Detach shared memory segment. -int shmdt(void *shmaddr); - -/// @@brief Find shmid_ds on list. -struct shmid_ds *find_shm_fromid(int shmid); - -/// @@brief Find shmid_ds on list. -struct shmid_ds *find_shm_fromkey(key_t key); - -/// @@brief shmid_ds on list. -struct shmid_ds *find_shm_fromvaddr(void *shmvaddr); +/// MentOS, The Mentoring Operating system project +/// @file shm.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "ipc.h" +#include "debug.h" +#include "clock.h" +#include "kheap.h" +#include "stddef.h" +#include "paging.h" +#include "syscall.h" +#include "scheduler.h" + +//======== Permission flag for shmget ========================================== +// or S_IRUGO from . +#define SHM_R 0400 + +// or S_IWUGO from . +#define SHM_W 0200 +//============================================================================== + +//======== Flags for shmat ===================================================== +// Attach read-only else read-write. +#define SHM_RDONLY 010000 + +// Round attach address to SHMLBA. +#define SHM_RND 020000 + +// Take-over region on attach. +#define SHM_REMAP 040000 + +// Execution access. +#define SHM_EXEC 0100000 +//============================================================================== + +//======== Commands for shmctl ================================================= +// Lock segment (root only). +#define SHM_LOCK 11 + +// Unlock segment (root only). +#define SHM_UNLOCK 12 +//============================================================================== + +// Ipcs ctl commands. +#define SHM_STAT 13 + +#define SHM_INFO 14 + +#define SHM_STAT_ANY 15 + +//======== shm_mode upper byte flags =========================================== +// segment will be destroyed on last detach. +#define SHM_DEST 01000 + +// Segment will not be swapped. +#define SHM_LOCKED 02000 + +// Segment is mapped via hugetlb. +#define SHM_HUGETLB 04000 + +// Don't check for reservations. +#define SHM_NORESERVE 010000 + +typedef unsigned long shmatt_t; + +struct shmid_ds { + // Operation permission struct. + struct ipc_perm shm_perm; + + // Size of segment in bytes. + size_t shm_segsz; + + // Time of last shmat(). + time_t shm_atime; + + // Time of last shmdt(). + time_t shm_dtime; + + // Time of last change by shmctl(). + time_t shm_ctime; + + // Pid of creator. + pid_t shm_cpid; + + // Pid of last shmop. + pid_t shm_lpid; + + // Number of current attaches. + shmatt_t shm_nattch; + + struct shmid_ds *next; + + // Where shm created is memorized, should be a file. + void *shm_location; +}; + +/// @@brief Syscall Service Routine: Shared memory control operation. +int syscall_shmctl(int *args); + +/// @@brief Syscall Service Routine: Get shared memory segment. +int syscall_shmget(int *args); + +/// @@brief Syscall Service Routine: Attach shared memory segment. +void *syscall_shmat(int *args); + +/// @@brief Syscall Service Routine: Detach shared memory segment. +int syscall_shmdt(int *args); + +/// @@brief User Wrapper: Shared memory control operation. +int shmctl(int shmid, int cmd, struct shmid_ds *buf); + +/// @@brief User Wrapper: Get shared memory segment. +int shmget(key_t key, size_t size, int flags); + +/// @@brief User Wrapper: Attach shared memory segment. +void *shmat(int shmid, void *shmaddr, int flag); + +/// @@brief User Wrapper: Detach shared memory segment. +int shmdt(void *shmaddr); + +/// @@brief Find shmid_ds on list. +struct shmid_ds *find_shm_fromid(int shmid); + +/// @@brief Find shmid_ds on list. +struct shmid_ds *find_shm_fromkey(key_t key); + +/// @@brief shmid_ds on list. +struct shmid_ds *find_shm_fromvaddr(void *shmvaddr); diff --git a/mentos/inc/sys/stat.h b/mentos/inc/sys/stat.h index 05aa9b6..a9c6a66 100644 --- a/mentos/inc/sys/stat.h +++ b/mentos/inc/sys/stat.h @@ -1,41 +1,41 @@ -/// MentOS, The Mentoring Operating system project -/// @file stat.h -/// @brief Stat functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "clock.h" -#include "stddef.h" - -/// @brief Data structure which contains information about a file. -typedef struct stat_t -{ - /// ID of device containing file. - dev_t st_dev; - /// Fle serial number. - ino_t st_ino; - /// Mode of file. - mode_t st_mode; - /// User id del file. - uid_t st_uid; - /// Group id del file. - gid_t st_gid; - /// Dimensione del file. - off_t st_size; - /// Time of last access. - time_t st_atime; - /// Time of last data modification. - time_t st_mtime; - /// Time of last status change. - time_t st_ctime; -} stat_t; - -/// @brief Retrieves information about the file at the given location. -/// @param path The file descriptor of the file that is being inquired. -/// @param buf A structure where data about the file will be stored. -/// @return Returns a negative value on failure. -int stat(const char *path, stat_t *buf); - -int mkdir(const char *path, mode_t mode); +/// MentOS, The Mentoring Operating system project +/// @file stat.h +/// @brief Stat functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "clock.h" +#include "stddef.h" + +/// @brief Data structure which contains information about a file. +typedef struct stat_t +{ + /// ID of device containing file. + dev_t st_dev; + /// Fle serial number. + ino_t st_ino; + /// Mode of file. + mode_t st_mode; + /// User id del file. + uid_t st_uid; + /// Group id del file. + gid_t st_gid; + /// Dimensione del file. + off_t st_size; + /// Time of last access. + time_t st_atime; + /// Time of last data modification. + time_t st_mtime; + /// Time of last status change. + time_t st_ctime; +} stat_t; + +/// @brief Retrieves information about the file at the given location. +/// @param path The file descriptor of the file that is being inquired. +/// @param buf A structure where data about the file will be stored. +/// @return Returns a negative value on failure. +int stat(const char *path, stat_t *buf); + +int mkdir(const char *path, mode_t mode); diff --git a/mentos/inc/sys/types.h b/mentos/inc/sys/types.h index 4457700..166558f 100644 --- a/mentos/inc/sys/types.h +++ b/mentos/inc/sys/types.h @@ -1,67 +1,67 @@ -/// MentOS, The Mentoring Operating system project -/// @file types.h -/// @brief Collection of Kernel datatype -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// The type of process id. -typedef signed int pid_t; - -/// The type of process user variable. -typedef unsigned int user_t; - -/// The type of process status. -typedef unsigned int status_t; - -/// Defines the list of flags of a process. -typedef enum eflags_list { - /// Carry flag. - EFLAG_CF = (1 << 0), - - /// Parity flag. - EFLAG_PF = (1 << 2), - - /// Auxiliary carry flag. - EFLAG_AF = (1 << 4), - - /// Zero flag. - EFLAG_ZF = (1 << 6), - - /// Sign flag. - EFLAG_SF = (1 << 7), - - /// Trap flag. - EFLAG_TF = (1 << 8), - - /// Interrupt enable flag. - EFLAG_IF = (1 << 9), - - /// Direction flag. - EFLAG_DF = (1 << 10), - - /// Overflow flag. - EFLAG_OF = (1 << 11), - - /// Nested task flag. - EFLAG_NT = (1 << 14), - - /// Resume flag. - EFLAG_RF = (1 << 16), - - /// Virtual 8086 mode flag. - EFLAG_VM = (1 << 17), - - /// Alignment check flag (486+). - EFLAG_AC = (1 << 18), - - /// Virutal interrupt flag. - EFLAG_VIF = (1 << 19), - - /// Virtual interrupt pending flag. - EFLAG_VIP = (1 << 20), - - /// ID flag. - EFLAG_ID = (1 << 21), -} eflags_list; +/// MentOS, The Mentoring Operating system project +/// @file types.h +/// @brief Collection of Kernel datatype +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// The type of process id. +typedef signed int pid_t; + +/// The type of process user variable. +typedef unsigned int user_t; + +/// The type of process status. +typedef unsigned int status_t; + +/// Defines the list of flags of a process. +typedef enum eflags_list { + /// Carry flag. + EFLAG_CF = (1 << 0), + + /// Parity flag. + EFLAG_PF = (1 << 2), + + /// Auxiliary carry flag. + EFLAG_AF = (1 << 4), + + /// Zero flag. + EFLAG_ZF = (1 << 6), + + /// Sign flag. + EFLAG_SF = (1 << 7), + + /// Trap flag. + EFLAG_TF = (1 << 8), + + /// Interrupt enable flag. + EFLAG_IF = (1 << 9), + + /// Direction flag. + EFLAG_DF = (1 << 10), + + /// Overflow flag. + EFLAG_OF = (1 << 11), + + /// Nested task flag. + EFLAG_NT = (1 << 14), + + /// Resume flag. + EFLAG_RF = (1 << 16), + + /// Virtual 8086 mode flag. + EFLAG_VM = (1 << 17), + + /// Alignment check flag (486+). + EFLAG_AC = (1 << 18), + + /// Virutal interrupt flag. + EFLAG_VIF = (1 << 19), + + /// Virtual interrupt pending flag. + EFLAG_VIP = (1 << 20), + + /// ID flag. + EFLAG_ID = (1 << 21), +} eflags_list; diff --git a/mentos/inc/sys/unistd.h b/mentos/inc/sys/unistd.h index d49cce1..ef96d4a 100644 --- a/mentos/inc/sys/unistd.h +++ b/mentos/inc/sys/unistd.h @@ -1,95 +1,95 @@ -/// MentOS, The Mentoring Operating system project -/// @file unistd.h -/// @brief Functions used to manage files. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "types.h" -#include "stddef.h" - -//======== Standard file descriptors =========================================== -/// Standard input. -#define STDIN_FILENO -3 - -/// Standard output. -#define STDOUT_FILENO -2 - -/// Standard error output. -#define STDERR_FILENO -1 -//============================================================================== - -/// Maximum number of opened file. -#define MAX_OPEN_FD 4 - -/// @brief Read data from a file descriptor. -/// @param fd The file descriptor. -/// @param buf The buffer. -/// @param nbytes The number of bytes to read. -/// @return The number of read characters. -ssize_t read(int fd, void *buf, size_t nbytes); - -/// @brief Write data into a file descriptor. -/// @param fd The file descriptor. -/// @param buf The buffer collecting data to written. -/// @param nbytes The number of bytes to write. -/// @return The number of written bytes. -ssize_t write(int fd, void *buf, size_t nbytes); - -/// @brief Opens the file specified by pathname. -/// @param pathname A pathname for a file. -/// @param flags Used to set the file status flags and file access modes -/// of the open file description. -/// @param mode Specifies the file mode bits be applied when a new file -/// is created. -/// @return Returns a file descriptor, a small, nonnegative integer for -/// use in subsequent system calls. -int open(const char *pathname, int flags, mode_t mode); - -/// @brief Close a file descriptor. -/// @param fd The file descriptor. -/// @return The result of the operation. -int close(int fd); - -/// @brief Removes the given directory. -/// @param path The path to the directory to remove. -/// @return -int rmdir(const char *path); - -/// @brief Wrapper for exit system call. -extern void exit(int status); - -/// @brief Return the process identifier of the calling process. -/// @return pid_t process identifier. -extern pid_t getpid(); - -/// @brief Clone the calling process, but without copying the whole address space. -/// The calling process is suspended until the new process exits or is -/// replaced by a call to `execve'. Return -1 for errors, 0 to the new -/// process, and the process ID of the new process to the old process. -/// @return -extern pid_t vfork(); - -/// @brief Replaces the current process image with a new process image. -/// @param path The path to the binary file to execute. -/// @param argv The list of arguments. -/// @param envp -/// @return -extern int execve(const char *path, char *const argv[], char *const envp[]); - -/// @brief Adds inc to the nice value for the calling thread. -/// @param inc The value to add to the nice. -/// @return On success, the new nice value is returned. On error, -1 is -/// returned, and errno is set appropriately. -int nice(int inc); - -/// @brief Reboot system call. -/// @param cmd -/// @param arg -/// @return -int reboot(int magic1, int magic2, unsigned int cmd, void *arg); - -void getcwd(char *path, size_t size); - -void chdir(char const *path); +/// MentOS, The Mentoring Operating system project +/// @file unistd.h +/// @brief Functions used to manage files. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "types.h" +#include "stddef.h" + +//======== Standard file descriptors =========================================== +/// Standard input. +#define STDIN_FILENO -3 + +/// Standard output. +#define STDOUT_FILENO -2 + +/// Standard error output. +#define STDERR_FILENO -1 +//============================================================================== + +/// Maximum number of opened file. +#define MAX_OPEN_FD 4 + +/// @brief Read data from a file descriptor. +/// @param fd The file descriptor. +/// @param buf The buffer. +/// @param nbytes The number of bytes to read. +/// @return The number of read characters. +ssize_t read(int fd, void *buf, size_t nbytes); + +/// @brief Write data into a file descriptor. +/// @param fd The file descriptor. +/// @param buf The buffer collecting data to written. +/// @param nbytes The number of bytes to write. +/// @return The number of written bytes. +ssize_t write(int fd, void *buf, size_t nbytes); + +/// @brief Opens the file specified by pathname. +/// @param pathname A pathname for a file. +/// @param flags Used to set the file status flags and file access modes +/// of the open file description. +/// @param mode Specifies the file mode bits be applied when a new file +/// is created. +/// @return Returns a file descriptor, a small, nonnegative integer for +/// use in subsequent system calls. +int open(const char *pathname, int flags, mode_t mode); + +/// @brief Close a file descriptor. +/// @param fd The file descriptor. +/// @return The result of the operation. +int close(int fd); + +/// @brief Removes the given directory. +/// @param path The path to the directory to remove. +/// @return +int rmdir(const char *path); + +/// @brief Wrapper for exit system call. +extern void exit(int status); + +/// @brief Return the process identifier of the calling process. +/// @return pid_t process identifier. +extern pid_t getpid(); + +/// @brief Clone the calling process, but without copying the whole address space. +/// The calling process is suspended until the new process exits or is +/// replaced by a call to `execve'. Return -1 for errors, 0 to the new +/// process, and the process ID of the new process to the old process. +/// @return +extern pid_t vfork(); + +/// @brief Replaces the current process image with a new process image. +/// @param path The path to the binary file to execute. +/// @param argv The list of arguments. +/// @param envp +/// @return +extern int execve(const char *path, char *const argv[], char *const envp[]); + +/// @brief Adds inc to the nice value for the calling thread. +/// @param inc The value to add to the nice. +/// @return On success, the new nice value is returned. On error, -1 is +/// returned, and errno is set appropriately. +int nice(int inc); + +/// @brief Reboot system call. +/// @param cmd +/// @param arg +/// @return +int reboot(int magic1, int magic2, unsigned int cmd, void *arg); + +void getcwd(char *path, size_t size); + +void chdir(char const *path); diff --git a/mentos/inc/sys/utsname.h b/mentos/inc/sys/utsname.h index c79cc74..691442a 100644 --- a/mentos/inc/sys/utsname.h +++ b/mentos/inc/sys/utsname.h @@ -1,28 +1,28 @@ -/// MentOS, The Mentoring Operating system project -/// @file utsname.h -/// @brief Functions used to provide information about the machine & OS. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// Maximum length of the string used by utsname. -#define SYS_LEN 257 - -/// @brief Holds information concerning the machine and the os. -typedef struct utsname_t { - /// The name of the system. - char sysname[SYS_LEN]; - - /// The name of the node. - char nodename[SYS_LEN]; - - /// The version of the OS. - char version[SYS_LEN]; - - /// The name of the machine. - char machine[SYS_LEN]; -} utsname_t; - -/// @brief Sets the values of os_infos. -int uname(utsname_t *os_infos); +/// MentOS, The Mentoring Operating system project +/// @file utsname.h +/// @brief Functions used to provide information about the machine & OS. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// Maximum length of the string used by utsname. +#define SYS_LEN 257 + +/// @brief Holds information concerning the machine and the os. +typedef struct utsname_t { + /// The name of the system. + char sysname[SYS_LEN]; + + /// The name of the node. + char nodename[SYS_LEN]; + + /// The version of the OS. + char version[SYS_LEN]; + + /// The name of the machine. + char machine[SYS_LEN]; +} utsname_t; + +/// @brief Sets the values of os_infos. +int uname(utsname_t *os_infos); diff --git a/mentos/inc/sys/wait.h b/mentos/inc/sys/wait.h index c82ae56..aa6d58e 100644 --- a/mentos/inc/sys/wait.h +++ b/mentos/inc/sys/wait.h @@ -1,60 +1,60 @@ -/// MentOS, The Mentoring Operating system project -/// @file wait.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "types.h" - -/// @brief Return immediately if no child is there to be waited for. -#define WNOHANG 0x00000001 - -/// @brief Return for children that are stopped, and whose status has not -/// been reported. -#define WUNTRACED 0x00000002 - -/// @brief returns true if the child process exited because of a signal that -/// was not caught. -#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status)) - -/// @brief returns true if the child process that caused the return is -/// currently stopped; this is only possible if the call was done using -/// WUNTRACED(). -#define WIFSTOPPED(status) (((status)&0xff) == 0x7f) - -/// @brief evaluates to the least significant eight bits of the return code -/// of the child that terminated, which may have been set as the argument -/// to a call to exit() or as the argument for a return statement in the -/// main program. This macro can only be evaluated if WIFEXITED() -/// returned nonzero. -#define WEXITSTATUS(status) (((status)&0xff00) >> 8) - -/// @brief returns the number of the signal that caused the child process to -/// terminate. This macro can only be evaluated if WIFSIGNALED() returned -/// nonzero. -#define WTERMSIG(status) ((status)&0x7f) - -/// @brief Is nonzero if the child exited normally. -#define WIFEXITED(status) (WTERMSIG(status) == 0) - -/// @brief returns the number of the signal that caused the child to stop. -/// This macro can only be evaluated if WIFSTOPPED() returned nonzero. -#define WSTOPSIG(status) (WEXITSTATUS(status)) - -extern pid_t wait(int *status); - -/// @brief Suspends the execution of the calling thread until a child -/// specified by pid argument has changed state. -/// @details -/// By default, waitpid() waits only for terminated children, but this -/// behavior is modifiable via the options argument, as described below. -/// The value of pid can be: -/// - 1 meaning wait for any child process. -/// 0 meaning wait for any child process whose process group ID is -/// equal to that of the calling process. -/// > 0 meaning wait for the child whose process ID is equal to the -/// value of pid. -/// @return On error, -1 is returned. -extern pid_t waitpid(pid_t pid, int *status, int options); +/// MentOS, The Mentoring Operating system project +/// @file wait.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "types.h" + +/// @brief Return immediately if no child is there to be waited for. +#define WNOHANG 0x00000001 + +/// @brief Return for children that are stopped, and whose status has not +/// been reported. +#define WUNTRACED 0x00000002 + +/// @brief returns true if the child process exited because of a signal that +/// was not caught. +#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status)) + +/// @brief returns true if the child process that caused the return is +/// currently stopped; this is only possible if the call was done using +/// WUNTRACED(). +#define WIFSTOPPED(status) (((status)&0xff) == 0x7f) + +/// @brief evaluates to the least significant eight bits of the return code +/// of the child that terminated, which may have been set as the argument +/// to a call to exit() or as the argument for a return statement in the +/// main program. This macro can only be evaluated if WIFEXITED() +/// returned nonzero. +#define WEXITSTATUS(status) (((status)&0xff00) >> 8) + +/// @brief returns the number of the signal that caused the child process to +/// terminate. This macro can only be evaluated if WIFSIGNALED() returned +/// nonzero. +#define WTERMSIG(status) ((status)&0x7f) + +/// @brief Is nonzero if the child exited normally. +#define WIFEXITED(status) (WTERMSIG(status) == 0) + +/// @brief returns the number of the signal that caused the child to stop. +/// This macro can only be evaluated if WIFSTOPPED() returned nonzero. +#define WSTOPSIG(status) (WEXITSTATUS(status)) + +extern pid_t wait(int *status); + +/// @brief Suspends the execution of the calling thread until a child +/// specified by pid argument has changed state. +/// @details +/// By default, waitpid() waits only for terminated children, but this +/// behavior is modifiable via the options argument, as described below. +/// The value of pid can be: +/// - 1 meaning wait for any child process. +/// 0 meaning wait for any child process whose process group ID is +/// equal to that of the calling process. +/// > 0 meaning wait for the child whose process ID is equal to the +/// value of pid. +/// @return On error, -1 is returned. +extern pid_t waitpid(pid_t pid, int *status, int options); diff --git a/mentos/inc/system/panic.h b/mentos/inc/system/panic.h index eb7b2ce..7ddfaff 100644 --- a/mentos/inc/system/panic.h +++ b/mentos/inc/system/panic.h @@ -1,12 +1,12 @@ -/// MentOS, The Mentoring Operating system project -/// @file panic.h -/// @brief Functions used to manage kernel panic. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief Prints the given message and then safely stop the execution of -/// the kernel. -/// @param msg The message that has to be shown. -void kernel_panic(const char *msg); +/// MentOS, The Mentoring Operating system project +/// @file panic.h +/// @brief Functions used to manage kernel panic. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief Prints the given message and then safely stop the execution of +/// the kernel. +/// @param msg The message that has to be shown. +void kernel_panic(const char *msg); diff --git a/mentos/inc/system/printk.h b/mentos/inc/system/printk.h index c14ed1c..93ae75f 100644 --- a/mentos/inc/system/printk.h +++ b/mentos/inc/system/printk.h @@ -1,10 +1,10 @@ -/// MentOS, The Mentoring Operating system project -/// @file printk.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// @brief Write formatted output to stdout. -void printk(const char *, ...); +/// MentOS, The Mentoring Operating system project +/// @file printk.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief Write formatted output to stdout. +void printk(const char *, ...); diff --git a/mentos/inc/system/signal_defs.h b/mentos/inc/system/signal_defs.h index d06a730..6778d6c 100644 --- a/mentos/inc/system/signal_defs.h +++ b/mentos/inc/system/signal_defs.h @@ -1,121 +1,121 @@ -/// MentOS, The Mentoring Operating system project -/// @file signal_defs.h -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -// Signal names (from the Unix specification on signals) - -/// Hangup. -#define SIGHUP 1 - -/// Interupt. -#define SIGINT 2 - -/// Quit. -#define SIGQUIT 3 - -/// Illegal instruction. -#define SIGILL 4 - -/// A breakpoint or trace instruction has been reached. -#define SIGTRAP 5 - -/// Another process has requested that you abort. -#define SIGABRT 6 - -/// Emulation trap XXX. -#define SIGEMT 7 - -/// Floating-point arithmetic exception. -#define SIGFPE 8 - -/// You have been stabbed repeated with a large knife. -#define SIGKILL 9 - -/// Bus error (device error). -#define SIGBUS 10 - -/// Segmentation fault. -#define SIGSEGV 11 - -/// Bad system call. -#define SIGSYS 12 - -/// Attempted to read or write from a broken pipe. -#define SIGPIPE 13 - -/// This is your wakeup call. -#define SIGALRM 14 - -/// You have been Schwarzenegger'd. -#define SIGTERM 15 - -/// User Defined Signal #1. -#define SIGUSR1 16 - -/// User Defined Signal #2. -#define SIGUSR2 17 - -/// Child status report. -#define SIGCHLD 18 - -/// We need moar powah!. -#define SIGPWR 19 - -/// Your containing terminal has changed size. -#define SIGWINCH 20 - -/// An URGENT! event (On a socket). -#define SIGURG 21 - -/// XXX OBSOLETE; socket i/o possible. -#define SIGPOLL 22 - -/// Stopped (signal). -#define SIGSTOP 23 - -/// ^Z (suspend). -#define SIGTSTP 24 - -/// Unsuspended (please, continue). -#define SIGCONT 25 - -/// TTY input has stopped. -#define SIGTTIN 26 - -/// TTY output has stopped. -#define SIGTTOUT 27 - -/// Virtual timer has expired. -#define SIGVTALRM 28 - -/// Profiling timer expired. -#define SIGPROF 29 - -/// CPU time limit exceeded. -#define SIGXCPU 30 - -/// File size limit exceeded. -#define SIGXFSZ 31 - -/// Herp. -#define SIGWAITING 32 - -/// Die in a fire. -#define SIGDIAF 33 - -/// The sending process does not like you. -#define SIGHATE 34 - -/// Window server event. -#define SIGWINEVENT 35 - -/// Everybody loves cats. -#define SIGCAT 36 - -#define SIGTTOU 37 - -#define NUMSIGNALS 38 - -#define NSIG NUMSIGNALS +/// MentOS, The Mentoring Operating system project +/// @file signal_defs.h +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +// Signal names (from the Unix specification on signals) + +/// Hangup. +#define SIGHUP 1 + +/// Interupt. +#define SIGINT 2 + +/// Quit. +#define SIGQUIT 3 + +/// Illegal instruction. +#define SIGILL 4 + +/// A breakpoint or trace instruction has been reached. +#define SIGTRAP 5 + +/// Another process has requested that you abort. +#define SIGABRT 6 + +/// Emulation trap XXX. +#define SIGEMT 7 + +/// Floating-point arithmetic exception. +#define SIGFPE 8 + +/// You have been stabbed repeated with a large knife. +#define SIGKILL 9 + +/// Bus error (device error). +#define SIGBUS 10 + +/// Segmentation fault. +#define SIGSEGV 11 + +/// Bad system call. +#define SIGSYS 12 + +/// Attempted to read or write from a broken pipe. +#define SIGPIPE 13 + +/// This is your wakeup call. +#define SIGALRM 14 + +/// You have been Schwarzenegger'd. +#define SIGTERM 15 + +/// User Defined Signal #1. +#define SIGUSR1 16 + +/// User Defined Signal #2. +#define SIGUSR2 17 + +/// Child status report. +#define SIGCHLD 18 + +/// We need moar powah!. +#define SIGPWR 19 + +/// Your containing terminal has changed size. +#define SIGWINCH 20 + +/// An URGENT! event (On a socket). +#define SIGURG 21 + +/// XXX OBSOLETE; socket i/o possible. +#define SIGPOLL 22 + +/// Stopped (signal). +#define SIGSTOP 23 + +/// ^Z (suspend). +#define SIGTSTP 24 + +/// Unsuspended (please, continue). +#define SIGCONT 25 + +/// TTY input has stopped. +#define SIGTTIN 26 + +/// TTY output has stopped. +#define SIGTTOUT 27 + +/// Virtual timer has expired. +#define SIGVTALRM 28 + +/// Profiling timer expired. +#define SIGPROF 29 + +/// CPU time limit exceeded. +#define SIGXCPU 30 + +/// File size limit exceeded. +#define SIGXFSZ 31 + +/// Herp. +#define SIGWAITING 32 + +/// Die in a fire. +#define SIGDIAF 33 + +/// The sending process does not like you. +#define SIGHATE 34 + +/// Window server event. +#define SIGWINEVENT 35 + +/// Everybody loves cats. +#define SIGCAT 36 + +#define SIGTTOU 37 + +#define NUMSIGNALS 38 + +#define NSIG NUMSIGNALS diff --git a/mentos/inc/system/syscall.h b/mentos/inc/system/syscall.h index fa37331..581a023 100644 --- a/mentos/inc/system/syscall.h +++ b/mentos/inc/system/syscall.h @@ -1,84 +1,84 @@ -/// MentOS, The Mentoring Operating system project -/// @file syscall.h -/// @brief System Call handler definition. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "syscall_types.h" -#include "kernel.h" -#include "dirent.h" -#include "types.h" -#include "stat.h" - -/// @brief Initialize the system calls. -void syscall_init(); - -/// @brief Handler for the system calls. -void syscall_handler(pt_regs *r); - -/// The exit() function causes normal process termination. -void sys_exit(int exit_code); - -/// @brief Read data from a file descriptor. -/// @param fd The file descriptor. -/// @param buf The buffer. -/// @param nbytes The number of bytes to read. -/// @return The number of read characters. -ssize_t sys_read(int fd, void *buf, size_t nbytes); - -/// @brief Write data into a file descriptor. -/// @param fd The file descriptor. -/// @param buf The buffer collecting data to written. -/// @param nbytes The number of bytes to write. -/// @return The number of written bytes. -ssize_t sys_write(int fd, void *buf, size_t nbytes); - -/// @brief Given a pathname for a file, open() returns a file -/// descriptor, a small, nonnegative integer for use in -/// subsequent system calls. -/// @param pathname A pathname for a file. -/// @param flags Used to set the file status flags and file access modes -/// of the open file description. -/// @param mode Specifies the file mode bits be applied when a new file -/// is created. -/// @return Returns a file descriptor, a small, nonnegative integer -/// for use in subsequent system calls. -int sys_open(const char *pathname, int flags, mode_t mode); - -/// @brief -/// @param fd -/// @return -int sys_close(int fd); - -/// @brief Suspends execution of the calling thread until a child specified -/// by pid argument has changed state. -pid_t sys_waitpid(pid_t pid, int *status, int options); - -/// @brief Replaces the current process image with a new process image. -int sys_execve(pt_regs *r); - -void sys_chdir(char const *path); - -/// Returns the process ID (PID) of the calling process. -pid_t sys_getpid(); - -/// @brief Adds the increment to the priority value of the task. -int sys_nice(int increment); - -/// Returns the parent process ID (PPID) of the calling process. -pid_t sys_getppid(); - -int sys_reboot(int magic1, int magic2, unsigned int cmd, void *arg); - -void sys_getcwd(char *path, size_t size); - -/// @brief Create a child process. -pid_t sys_vfork(pt_regs *r); - -int sys_stat(const char *path, stat_t *buf); - -int sys_mkdir(const char *path, mode_t mode); - +/// MentOS, The Mentoring Operating system project +/// @file syscall.h +/// @brief System Call handler definition. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "syscall_types.h" +#include "kernel.h" +#include "dirent.h" +#include "types.h" +#include "stat.h" + +/// @brief Initialize the system calls. +void syscall_init(); + +/// @brief Handler for the system calls. +void syscall_handler(pt_regs *r); + +/// The exit() function causes normal process termination. +void sys_exit(int exit_code); + +/// @brief Read data from a file descriptor. +/// @param fd The file descriptor. +/// @param buf The buffer. +/// @param nbytes The number of bytes to read. +/// @return The number of read characters. +ssize_t sys_read(int fd, void *buf, size_t nbytes); + +/// @brief Write data into a file descriptor. +/// @param fd The file descriptor. +/// @param buf The buffer collecting data to written. +/// @param nbytes The number of bytes to write. +/// @return The number of written bytes. +ssize_t sys_write(int fd, void *buf, size_t nbytes); + +/// @brief Given a pathname for a file, open() returns a file +/// descriptor, a small, nonnegative integer for use in +/// subsequent system calls. +/// @param pathname A pathname for a file. +/// @param flags Used to set the file status flags and file access modes +/// of the open file description. +/// @param mode Specifies the file mode bits be applied when a new file +/// is created. +/// @return Returns a file descriptor, a small, nonnegative integer +/// for use in subsequent system calls. +int sys_open(const char *pathname, int flags, mode_t mode); + +/// @brief +/// @param fd +/// @return +int sys_close(int fd); + +/// @brief Suspends execution of the calling thread until a child specified +/// by pid argument has changed state. +pid_t sys_waitpid(pid_t pid, int *status, int options); + +/// @brief Replaces the current process image with a new process image. +int sys_execve(pt_regs *r); + +void sys_chdir(char const *path); + +/// Returns the process ID (PID) of the calling process. +pid_t sys_getpid(); + +/// @brief Adds the increment to the priority value of the task. +int sys_nice(int increment); + +/// Returns the parent process ID (PPID) of the calling process. +pid_t sys_getppid(); + +int sys_reboot(int magic1, int magic2, unsigned int cmd, void *arg); + +void sys_getcwd(char *path, size_t size); + +/// @brief Create a child process. +pid_t sys_vfork(pt_regs *r); + +int sys_stat(const char *path, stat_t *buf); + +int sys_mkdir(const char *path, mode_t mode); + dirent_t *sys_readdir(DIR *dirp); \ No newline at end of file diff --git a/mentos/inc/system/syscall_types.h b/mentos/inc/system/syscall_types.h index c964358..82e6f4b 100644 --- a/mentos/inc/system/syscall_types.h +++ b/mentos/inc/system/syscall_types.h @@ -1,220 +1,232 @@ -/// MentOS, The Mentoring Operating system project -/// @file syscall_number.h -/// @brief System Call numbers. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -// Return result in eax ("=a"). -// System call number in eax ("a"). -#define DEFN_SYSCALL0(__res, num) \ - __asm__ __volatile__("INT $0x80" : "=a"(__res) : "a"(num)) - -// Return result in eax ("=a"). -// System call number in eax ("a"). -// p1 in ebx ("+b"). -#define DEFN_SYSCALL1(__res, num, p1) \ - __asm__ __volatile__("INT $0x80" : "=a"(__res), "+b"(p1) : "a"(num)) - -#define DEFN_SYSCALL2(__res, num, p1, p2) \ - __asm__ __volatile__("INT $0x80" \ - : "=a"(__res), "+b"(p1), "+c"(p2) \ - : "a"(num)); - -#define DEFN_SYSCALL3(__res, num, p1, p2, p3) \ - __asm__ __volatile__("INT $0x80" \ - : "=a"(__res), "+b"(p1), "+c"(p2), "+d"(p3) \ - : "a"(num)) - -#define DEFN_SYSCALL4(__res, num, p1, p2, p3, p4) \ - __asm__ __volatile__("INT $0x80" \ - : "=a"(__res), "+b"(p1), "+c"(p2), "+d"(p3), "+S"(p4) \ - : "a"(num)) - -#define DEFN_SYSCALL5(__res, num, p1, p2, p3, p4, p5) \ - __asm__ __volatile__("INT $0x80" \ - : "=a"(__res), "+b"(p1), "+c"(p2), "+d"(p3), \ - "+S"(p4), "+D"(p5) \ - : "a"(num)) - -#define __NR_exit 1 -#define __NR_fork 2 -#define __NR_read 3 -#define __NR_write 4 -#define __NR_open 5 -#define __NR_close 6 -#define __NR_waitpid 7 -#define __NR_creat 8 -#define __NR_link 9 -#define __NR_unlink 10 -#define __NR_execve 11 -#define __NR_chdir 12 -#define __NR_time 13 -#define __NR_mknod 14 -#define __NR_chmod 15 -#define __NR_lchown 16 -#define __NR_stat 18 -#define __NR_lseek 19 -#define __NR_getpid 20 -#define __NR_mount 21 -#define __NR_oldumount 22 -#define __NR_setuid 23 -#define __NR_getuid 24 -#define __NR_stime 25 -#define __NR_ptrace 26 -#define __NR_alarm 27 -#define __NR_fstat 28 -#define __NR_pause 29 -#define __NR_utime 30 -#define __NR_access 33 -#define __NR_nice 34 -#define __NR_sync 36 -#define __NR_kill 37 -#define __NR_rename 38 -#define __NR_mkdir 39 -#define __NR_rmdir 40 -#define __NR_dup 41 -#define __NR_pipe 42 -#define __NR_times 43 -#define __NR_brk 45 -#define __NR_setgid 46 -#define __NR_getgid 47 -#define __NR_signal 48 -#define __NR_geteuid 49 -#define __NR_getegid 50 -#define __NR_acct 51 -#define __NR_umount 52 -#define __NR_ioctl 54 -#define __NR_fcntl 55 -#define __NR_setpgid 57 -#define __NR_olduname 59 -#define __NR_umask 60 -#define __NR_chroot 61 -#define __NR_ustat 62 -#define __NR_dup2 63 -#define __NR_getppid 64 -#define __NR_getpgrp 65 -#define __NR_setsid 66 -#define __NR_sigaction 67 -#define __NR_sgetmask 68 -#define __NR_ssetmask 69 -#define __NR_setreuid 70 -#define __NR_setregid 71 -#define __NR_sigsuspend 72 -#define __NR_sigpending 73 -#define __NR_sethostname 74 -#define __NR_setrlimit 75 -#define __NR_getrlimit 76 -#define __NR_getrusage 77 -#define __NR_gettimeofday 78 -#define __NR_settimeofday 79 -#define __NR_getgroups 80 -#define __NR_setgroups 81 -#define __NR_symlink 83 -#define __NR_lstat 84 -#define __NR_readlink 85 -#define __NR_uselib 86 -#define __NR_swapon 87 -#define __NR_reboot 88 -#define __NR_readdir 89 -#define __NR_mmap 90 -#define __NR_munmap 91 -#define __NR_truncate 92 -#define __NR_ftruncate 93 -#define __NR_fchmod 94 -#define __NR_fchown 95 -#define __NR_getpriority 96 -#define __NR_setpriority 97 -#define __NR_statfs 99 -#define __NR_fstatfs 100 -#define __NR_ioperm 101 -#define __NR_socketcall 102 -#define __NR_syslog 103 -#define __NR_setitimer 104 -#define __NR_getitimer 105 -#define __NR_newstat 106 -#define __NR_newlstat 107 -#define __NR_newfstat 108 -#define __NR_uname 109 -#define __NR_iopl 110 -#define __NR_vhangup 111 -#define __NR_idle 112 -#define __NR_vm86old 113 -#define __NR_wait4 114 -#define __NR_swapoff 115 -#define __NR_sysinfo 116 -#define __NR_ipc 117 -#define __NR_fsync 118 -#define __NR_sigreturn 119 -#define __NR_clone 120 -#define __NR_setdomainname 121 -#define __NR_newuname 122 -#define __NR_modify_ldt 123 -#define __NR_adjtimex 124 -#define __NR_mprotect 125 -#define __NR_sigprocmask 126 -#define __NR_create_module 127 -#define __NR_init_module 128 -#define __NR_delete_module 129 -#define __NR_get_kernel_syms 130 -#define __NR_quotactl 131 -#define __NR_getpgid 132 -#define __NR_fchdir 133 -#define __NR_bdflush 134 -#define __NR_sysfs 135 -#define __NR_personality 136 -#define __NR_setfsuid 138 -#define __NR_setfsgid 139 -#define __NR_llseek 140 -#define __NR_getdents 141 -#define __NR_select 142 -#define __NR_flock 143 -#define __NR_msync 144 -#define __NR_readv 145 -#define __NR_writev 146 -#define __NR_getsid 147 -#define __NR_fdatasync 148 -#define __NR_sysctl 149 -#define __NR_mlock 150 -#define __NR_munlock 151 -#define __NR_mlockall 152 -#define __NR_munlockall 153 -#define __NR_sched_setparam 154 -#define __NR_sched_getparam 155 -#define __NR_sched_setscheduler 156 -#define __NR_sched_getscheduler 157 -#define __NR_sched_yield 158 -#define __NR_sched_get_priority_max 159 -#define __NR_sched_get_priority_min 160 -#define __NR_sched_rr_get_interval 161 -#define __NR_nanosleep 162 -#define __NR_mremap 163 -#define __NR_setresuid 164 -#define __NR_getresuid 165 -#define __NR_vm86 166 -#define __NR_query_module 167 -#define __NR_poll 168 -#define __NR_nfsservctl 169 -#define __NR_setresgid 170 -#define __NR_getresgid 171 -#define __NR_prctl 172 -#define __NR_rt_sigreturn 173 -#define __NR_rt_sigaction 174 -#define __NR_rt_sigprocmask 175 -#define __NR_rt_sigpending 176 -#define __NR_rt_sigtimedwait 177 -#define __NR_rt_sigqueueinfo 178 -#define __NR_rt_sigsuspend 179 -#define __NR_pread 180 -#define __NR_pwrite 181 -#define __NR_chown 182 -#define __NR_getcwd 183 -#define __NR_capget 184 -#define __NR_capset 185 -#define __NR_sigaltstack 186 -#define __NR_sendfile 187 -#define __NR_vfork 188 -#define __NR_free 189 // TODO: remove me! - -#define SYSCALL_NUMBER 190 \ No newline at end of file +/// MentOS, The Mentoring Operating system project +/// @file syscall_number.h +/// @brief System Call numbers. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +// Return result in eax ("=a"). +// System call number in eax ("a"). +#define DEFN_SYSCALL0(__res, num) \ + __asm__ __volatile__("INT $0x80" \ + : "=a"(__res) \ + : "a"(num)) + +// Return result in eax ("=a"). +// System call number in eax ("a"). +// p1 in ebx ("+b"). +#define DEFN_SYSCALL1(__res, num, p1) \ + __asm__ __volatile__("INT $0x80" \ + : "=a"(__res), "+b"(p1) \ + : "a"(num)) + +#define DEFN_SYSCALL2(__res, num, p1, p2) \ + __asm__ __volatile__("INT $0x80" \ + : "=a"(__res), "+b"(p1), "+c"(p2) \ + : "a"(num)); + +#define DEFN_SYSCALL3(__res, num, p1, p2, p3) \ + __asm__ __volatile__("INT $0x80" \ + : "=a"(__res), "+b"(p1), "+c"(p2), "+d"(p3) \ + : "a"(num)) + +#define DEFN_SYSCALL4(__res, num, p1, p2, p3, p4) \ + __asm__ __volatile__("INT $0x80" \ + : "=a"(__res), "+b"(p1), "+c"(p2), "+d"(p3), "+S"(p4) \ + : "a"(num)) + +#define DEFN_SYSCALL5(__res, num, p1, p2, p3, p4, p5) \ + __asm__ __volatile__("INT $0x80" \ + : "=a"(__res), "+b"(p1), "+c"(p2), "+d"(p3), \ + "+S"(p4), "+D"(p5) \ + : "a"(num)) + +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_lchown 16 +#define __NR_stat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_oldumount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_fstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount 52 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_setpgid 57 +#define __NR_olduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_symlink 83 +#define __NR_lstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_newstat 106 +#define __NR_newlstat 107 +#define __NR_newfstat 108 +#define __NR_uname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86old 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_newuname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR_llseek 140 +#define __NR_getdents 141 +#define __NR_select 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR_sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_vm86 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread 180 +#define __NR_pwrite 181 +#define __NR_chown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_vfork 188 +#define __NR_free 189 // TODO: remove me! + +/* +#define __NR_sem_... 190 +#define __NR_sem_... 191 +#define __NR_sem_... 192 +#define __NR_sem_... 193 +#define __NR_sem_... 194 +*/ + +#define SYSCALL_NUMBER 195 \ No newline at end of file diff --git a/mentos/inc/ui/command/commands.h b/mentos/inc/ui/command/commands.h index cbca97a..fe406ca 100644 --- a/mentos/inc/ui/command/commands.h +++ b/mentos/inc/ui/command/commands.h @@ -1,93 +1,96 @@ -/// MentOS, The Mentoring Operating system project -/// @file commands.h -/// @brief Prototypes of functions for the Shell. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "shell.h" - -/// @brief Prints the logo. -void cmd_logo(int argc, char **argv); - -/// @brief Returns the list of commands. -void cmd_help(int argc, char **argv); - -/// @brief Echos the given message. -void cmd_echo(int argc, char **argv); - -/// @brief Power off the machine. -void cmd_poweroff(int argc, char **argv); - -/// @brief Call the uname function. -void cmd_uname(int argc, char **argv); - -/// @brief Prints the credits. -void cmd_credits(int argc, char **argv); - -/// @brief Sleeps the thread of the shell for a given period of time. -void cmd_sleep(int argc, char **argv); - -/// @brief Shows the output of the cpuid function. -void cmd_cpuid(int argc, char **argv); - -/// @brief Lists the directory. -void cmd_ls(int argc, char **argv); - -/// @brief Move to another directory. -void cmd_cd(int argc, char **argv); - -/// @brief Creates a new directory. -void cmd_mkdir(int argc, char **argv); - -/// @brief Removes a file. -void cmd_rm(int argc, char **argv); - -/// @brief Removes a directory. -void cmd_rmdir(int argc, char **argv); - -/// @brief Show the current user name. -void cmd_whoami(int argc, char **argv); - -/// @brief Allows to test some functionalities of the kernel. -void cmd_tester(int argc, char **argv); - -/// @brief Print current working directory. -void cmd_pwd(int argc, char **argv); - -/// @brief Read content of a file. -void cmd_more(int argc, char **argv); - -/// @brief Create a new file. -void cmd_touch(int argc, char **argv); - -/// @brief Create a new file. -void cmd_newfile(int argc, char **argv); - -/// @brief Show task list. -void cmd_ps(int argc, char **argv); - -/// @brief Show date and time. -void cmd_date(int argc, char **argv); - -/// @brief Clears the screen. -void cmd_clear(int argc, char **argv); - -/// @brief Shows the PID of the shell. -void cmd_showpid(int argc, char **argv); - -/// @brief Prints the history. -void cmd_show_history(int argc, char **argv); - -/// @brief Loads the drivers. -void cmd_drv_load(int argc, char **argv); - -/// @brief Show IPC state. -void cmd_ipcs(int argc, char **argv); - -/// @brief Remove IPC resorce from id. -void cmd_ipcrm(int argc, char **argv); - -/// @brief Change the nice value. -void cmd_nice(int argc, char **argv); +/// MentOS, The Mentoring Operating system project +/// @file commands.h +/// @brief Prototypes of functions for the Shell. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "shell.h" + +/// @brief Prints the logo. +void cmd_logo(int argc, char **argv); + +/// @brief Returns the list of commands. +void cmd_help(int argc, char **argv); + +/// @brief Echos the given message. +void cmd_echo(int argc, char **argv); + +/// @brief Power off the machine. +void cmd_poweroff(int argc, char **argv); + +/// @brief Call the uname function. +void cmd_uname(int argc, char **argv); + +/// @brief Prints the credits. +void cmd_credits(int argc, char **argv); + +/// @brief Sleeps the thread of the shell for a given period of time. +void cmd_sleep(int argc, char **argv); + +/// @brief Shows the output of the cpuid function. +void cmd_cpuid(int argc, char **argv); + +/// @brief Lists the directory. +void cmd_ls(int argc, char **argv); + +/// @brief Move to another directory. +void cmd_cd(int argc, char **argv); + +/// @brief Creates a new directory. +void cmd_mkdir(int argc, char **argv); + +/// @brief Removes a file. +void cmd_rm(int argc, char **argv); + +/// @brief Removes a directory. +void cmd_rmdir(int argc, char **argv); + +/// @brief Show the current user name. +void cmd_whoami(int argc, char **argv); + +/// @brief Allows to test some functionalities of the kernel. +void cmd_tester(int argc, char **argv); + +/// @brief Print current working directory. +void cmd_pwd(int argc, char **argv); + +/// @brief Read content of a file. +void cmd_more(int argc, char **argv); + +/// @brief Create a new file. +void cmd_touch(int argc, char **argv); + +/// @brief Create a new file. +void cmd_newfile(int argc, char **argv); + +/// @brief Show task list. +void cmd_ps(int argc, char **argv); + +/// @brief Show date and time. +void cmd_date(int argc, char **argv); + +/// @brief Clears the screen. +void cmd_clear(int argc, char **argv); + +/// @brief Shows the PID of the shell. +void cmd_showpid(int argc, char **argv); + +/// @brief Prints the history. +void cmd_show_history(int argc, char **argv); + +/// @brief Loads the drivers. +void cmd_drv_load(int argc, char **argv); + +/// @brief Show IPC state. +void cmd_ipcs(int argc, char **argv); + +/// @brief Remove IPC resorce from id. +void cmd_ipcrm(int argc, char **argv); + +/// @brief Change the nice value. +void cmd_nice(int argc, char **argv); + +/// @brief Test deadlock behavior with tasks and shared resources. +void cmd_deadlock(int argc, char **argv); diff --git a/mentos/inc/ui/init/init.h b/mentos/inc/ui/init/init.h index 70230d3..491936f 100644 --- a/mentos/inc/ui/init/init.h +++ b/mentos/inc/ui/init/init.h @@ -1,10 +1,10 @@ -/// MentOS, The Mentoring Operating system project -/// @file init.h -/// @brief Scheduler structures and functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -// TODO: doxygen comment. -int main_init(); +/// MentOS, The Mentoring Operating system project +/// @file init.h +/// @brief Scheduler structures and functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +// TODO: doxygen comment. +int main_init(); diff --git a/mentos/inc/ui/shell/shell.h b/mentos/inc/ui/shell/shell.h index e51ff1b..efe8665 100644 --- a/mentos/inc/ui/shell/shell.h +++ b/mentos/inc/ui/shell/shell.h @@ -1,78 +1,78 @@ -/// MentOS, The Mentoring Operating system project -/// @file shell.h -/// @brief Data structure used to implement the Shell. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "stdint.h" -#include "kernel.h" -#include "limits.h" - -/// Maximum length of credentials. -#define CREDENTIALS_LENGTH 50 - -/// Maximum length of commands. -#define CMD_LEN 256 - -/// Maximum length of descriptions. -#define DESC_LEN 256 - -/// Maximum number of saved commands. -#define MAX_NUM_COM 50 - -/// Maximum length of history. -#define HST_LEN 10 - -#define KEY_UP 72 - -#define KEY_DOWN 80 - -#define KEY_LEFT 75 - -#define KEY_RIGHT 77 - -/// Pointer to the function of a commmand. -typedef void (* CommandFunction)(int argc, char **argv); - -/// @brief Holds information about a command. -typedef struct command_t -{ - /// The name of the command. - char cmdname[CMD_LEN]; - - /// The function pointer to the command. - CommandFunction function; - - /// The description of the command. - char cmddesc[DESC_LEN]; -} command_t; - -/// @brief Holds information about the user. -typedef struct userenv_t -{ - /// The username. - char username[CREDENTIALS_LENGTH]; - - /// The current path. - char cur_path[PATH_MAX]; - - /// The user identifier. - unsigned int uid; - - /// The group identifier. - unsigned int gid; -} userenv_t; - -/// Contains the information about the current user. -extern userenv_t current_user; - -/// @brief The shell. -int shell(int argc, char **argv, char **envp); - -/// @brief Moves the cursor left. -void move_cursor_left(void); - -/// @brief Moves the cursor right. -void move_cursor_right(void); +/// MentOS, The Mentoring Operating system project +/// @file shell.h +/// @brief Data structure used to implement the Shell. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "stdint.h" +#include "kernel.h" +#include "limits.h" + +/// Maximum length of credentials. +#define CREDENTIALS_LENGTH 50 + +/// Maximum length of commands. +#define CMD_LEN 256 + +/// Maximum length of descriptions. +#define DESC_LEN 256 + +/// Maximum number of saved commands. +#define MAX_NUM_COM 50 + +/// Maximum length of history. +#define HST_LEN 10 + +#define KEY_UP 72 + +#define KEY_DOWN 80 + +#define KEY_LEFT 75 + +#define KEY_RIGHT 77 + +/// Pointer to the function of a commmand. +typedef void (* CommandFunction)(int argc, char **argv); + +/// @brief Holds information about a command. +typedef struct command_t +{ + /// The name of the command. + char cmdname[CMD_LEN]; + + /// The function pointer to the command. + CommandFunction function; + + /// The description of the command. + char cmddesc[DESC_LEN]; +} command_t; + +/// @brief Holds information about the user. +typedef struct userenv_t +{ + /// The username. + char username[CREDENTIALS_LENGTH]; + + /// The current path. + char cur_path[PATH_MAX]; + + /// The user identifier. + unsigned int uid; + + /// The group identifier. + unsigned int gid; +} userenv_t; + +/// Contains the information about the current user. +extern userenv_t current_user; + +/// @brief The shell. +int shell(int argc, char **argv, char **envp); + +/// @brief Moves the cursor left. +void move_cursor_left(void); + +/// @brief Moves the cursor right. +void move_cursor_right(void); diff --git a/mentos/inc/ui/shell/shell_login.h b/mentos/inc/ui/shell/shell_login.h index 3d0b458..472e666 100644 --- a/mentos/inc/ui/shell/shell_login.h +++ b/mentos/inc/ui/shell/shell_login.h @@ -1,14 +1,14 @@ -/// MentOS, The Mentoring Operating system project -/// @file shell_login.h -/// @brief Functions used to manage login. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -#include "shell.h" -#include "stdbool.h" - -/// @brief Function used to perform login. -void shell_login(); - +/// MentOS, The Mentoring Operating system project +/// @file shell_login.h +/// @brief Functions used to manage login. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +#include "shell.h" +#include "stdbool.h" + +/// @brief Function used to perform login. +void shell_login(); + diff --git a/mentos/inc/version.h b/mentos/inc/version.h index b79875f..888cabe 100644 --- a/mentos/inc/version.h +++ b/mentos/inc/version.h @@ -1,34 +1,34 @@ -/// MentOS, The Mentoring Operating system project -/// @file version.h -/// @brief Version information. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#pragma once - -/// The name of the operating system. -#define OS_NAME "MentOS" - -/// The site of the operating system. -#define OS_SITEURL "..." - -/// Major version of the operating system. -#define OS_MAJOR_VERSION 0 - -/// Minor version of the operating system. -#define OS_MINOR_VERSION 3 - -/// Micro version of the operating system. -#define OS_MICRO_VERSION 0 - -/// Helper to transform the given argument into a string. -#define OS_STR_HELPER(x) #x - -/// Helper to transform the given argument into a string. -#define OS_STR(x) OS_STR_HELPER(x) - -/// Complete version of the operating system. -#define OS_VERSION \ - OS_STR(OS_MAJOR_VERSION) "." \ - OS_STR(OS_MINOR_VERSION) "." \ - OS_STR(OS_MICRO_VERSION) +/// MentOS, The Mentoring Operating system project +/// @file version.h +/// @brief Version information. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// The name of the operating system. +#define OS_NAME "MentOS" + +/// The site of the operating system. +#define OS_SITEURL "..." + +/// Major version of the operating system. +#define OS_MAJOR_VERSION 0 + +/// Minor version of the operating system. +#define OS_MINOR_VERSION 3 + +/// Micro version of the operating system. +#define OS_MICRO_VERSION 0 + +/// Helper to transform the given argument into a string. +#define OS_STR_HELPER(x) #x + +/// Helper to transform the given argument into a string. +#define OS_STR(x) OS_STR_HELPER(x) + +/// Complete version of the operating system. +#define OS_VERSION \ + OS_STR(OS_MAJOR_VERSION) "." \ + OS_STR(OS_MINOR_VERSION) "." \ + OS_STR(OS_MICRO_VERSION) diff --git a/mentos/kernel.lds b/mentos/kernel.lds index db0112d..a37a925 100644 --- a/mentos/kernel.lds +++ b/mentos/kernel.lds @@ -1,52 +1,52 @@ -OUTPUT_FORMAT("elf") -OUTPUT_ARCH(i386) - -ENTRY(kernel_entry) - -KERNEL_PHYSICAL_ADDRESS = 0x00100000; -LOAD_MEMORY_ADDRESS = 0x00000000; - -SECTIONS -{ - . = KERNEL_PHYSICAL_ADDRESS; - - /* Put the .multiboot_header and .text section. */ - .text : AT(ADDR(.text)) - { - _multiboot_header_start = .; - *(.multiboot_header) - _multiboot_header_end = .; - - _text_start = .; - *(.text) - _text_end = .; - } - - /* Read-only data. */ - .rodata ALIGN(4K) : AT(ADDR(.rodata)) - { - _rodata_start = .; - *(.rodata) - _rodata_end = .; - } - - /* Read-write data (initialized) */ - .data ALIGN(4K) : AT(ADDR(.data)) - { - _data_start = .; - *(.data) - _data_end = .; - } - - /* Read-write data (uninitialized) and stack */ - .bss ALIGN(4K) : AT(ADDR(.bss)) - { - _bss_start = .; - *(.bss) - _bss_end = .; - } - - /* Put a symbol end here, it tells us where all the kernel code/data ends, - it means everything after 'end' can be used for something else. */ - end = .; -} +OUTPUT_FORMAT("elf") +OUTPUT_ARCH(i386) + +ENTRY(kernel_entry) + +KERNEL_PHYSICAL_ADDRESS = 0x00100000; +LOAD_MEMORY_ADDRESS = 0x00000000; + +SECTIONS +{ + . = KERNEL_PHYSICAL_ADDRESS; + + /* Put the .multiboot_header and .text section. */ + .text : AT(ADDR(.text)) + { + _multiboot_header_start = .; + *(.multiboot_header) + _multiboot_header_end = .; + + _text_start = .; + *(.text) + _text_end = .; + } + + /* Read-only data. */ + .rodata ALIGN(4K) : AT(ADDR(.rodata)) + { + _rodata_start = .; + *(.rodata) + _rodata_end = .; + } + + /* Read-write data (initialized) */ + .data ALIGN(4K) : AT(ADDR(.data)) + { + _data_start = .; + *(.data) + _data_end = .; + } + + /* Read-write data (uninitialized) and stack */ + .bss ALIGN(4K) : AT(ADDR(.bss)) + { + _bss_start = .; + *(.bss) + _bss_end = .; + } + + /* Put a symbol end here, it tells us where all the kernel code/data ends, + it means everything after 'end' can be used for something else. */ + end = .; +} diff --git a/mentos/src/descriptor_tables/exception.asm b/mentos/src/descriptor_tables/exception.asm index ba386cc..71f0858 100644 --- a/mentos/src/descriptor_tables/exception.asm +++ b/mentos/src/descriptor_tables/exception.asm @@ -1,111 +1,111 @@ -; MentOS, The Mentoring Operating system project -; @file exception.asm -; @brief -; @copyright (c) 2019 This file is distributed under the MIT License. -; See LICENSE.md for details. - -; Macro used to define a ISR which does not push an error code. -%macro ISR_NOERR 1 - [GLOBAL INT_%1] - INT_%1: - cli - ; A normal ISR stub that pops a dummy error code to keep a - ; uniform stack frame - push 0 - push %1 - jmp isr_common -%endmacro - -; Macro used to define a ISR which pushes an error code. -%macro ISR_ERR 1 - [GLOBAL INT_%1] - INT_%1: - cli - push %1 - jmp isr_common -%endmacro - -; Standard X86 interrupt service routines -ISR_NOERR 0 -ISR_NOERR 1 -ISR_NOERR 2 -ISR_NOERR 3 -ISR_NOERR 4 -ISR_NOERR 5 -ISR_NOERR 6 -ISR_NOERR 7 -ISR_ERR 8 -ISR_NOERR 9 -ISR_ERR 10 -ISR_ERR 11 -ISR_ERR 12 -ISR_ERR 13 -ISR_ERR 14 -ISR_NOERR 15 -ISR_NOERR 16 -ISR_NOERR 17 -ISR_NOERR 18 -ISR_NOERR 19 - -ISR_NOERR 20 -ISR_NOERR 21 -ISR_NOERR 22 -ISR_NOERR 23 -ISR_NOERR 24 -ISR_NOERR 25 -ISR_NOERR 26 -ISR_NOERR 27 -ISR_NOERR 28 -ISR_NOERR 29 -ISR_NOERR 30 -ISR_NOERR 31 - -ISR_NOERR 80 - -[EXTERN isr_handler] - -isr_common: - ; Save all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi) - pusha - - ; Save segment registers - push ds - push es - push fs - push gs - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - ; CLD - Azzera la flag di Direzione - ; Questa istruzione forza semplicemente a zero la flag di Direzione. - ; Quando la flag di direzione vale 0 tutte le istruzioni per la - ; manipolazione delle stringhe agiscono in avanti, cioè dagli indirizzi più - ; bassi a quelli più alti. - ; L'istruzione agisce dunque sui puntatori SI e DI producendo su essi un - ; autoincremento proporzionale alla dimensione degli operandi trattati. - ; Le sue caratteristiche sono riassunte nella seguente tabella (leggi le - ; istruzioni Legenda della Tabella): - cld - - ; Call the interrupt handler. - push esp; - call isr_handler - add esp, 0x4 - - ; Restore segment registers. - pop gs - pop fs - pop es - pop ds - - ; Restore all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi). - popa - - ; Cleanup error code and IRQ # - add esp, 0x8 - - iret ; pops 5 things at once: - ; CS, EIP, EFLAGS, SS, and ESP +; MentOS, The Mentoring Operating system project +; @file exception.asm +; @brief +; @copyright (c) 2019 This file is distributed under the MIT License. +; See LICENSE.md for details. + +; Macro used to define a ISR which does not push an error code. +%macro ISR_NOERR 1 + [GLOBAL INT_%1] + INT_%1: + cli + ; A normal ISR stub that pops a dummy error code to keep a + ; uniform stack frame + push 0 + push %1 + jmp isr_common +%endmacro + +; Macro used to define a ISR which pushes an error code. +%macro ISR_ERR 1 + [GLOBAL INT_%1] + INT_%1: + cli + push %1 + jmp isr_common +%endmacro + +; Standard X86 interrupt service routines +ISR_NOERR 0 +ISR_NOERR 1 +ISR_NOERR 2 +ISR_NOERR 3 +ISR_NOERR 4 +ISR_NOERR 5 +ISR_NOERR 6 +ISR_NOERR 7 +ISR_ERR 8 +ISR_NOERR 9 +ISR_ERR 10 +ISR_ERR 11 +ISR_ERR 12 +ISR_ERR 13 +ISR_ERR 14 +ISR_NOERR 15 +ISR_NOERR 16 +ISR_NOERR 17 +ISR_NOERR 18 +ISR_NOERR 19 + +ISR_NOERR 20 +ISR_NOERR 21 +ISR_NOERR 22 +ISR_NOERR 23 +ISR_NOERR 24 +ISR_NOERR 25 +ISR_NOERR 26 +ISR_NOERR 27 +ISR_NOERR 28 +ISR_NOERR 29 +ISR_NOERR 30 +ISR_NOERR 31 + +ISR_NOERR 80 + +[EXTERN isr_handler] + +isr_common: + ; Save all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi) + pusha + + ; Save segment registers + push ds + push es + push fs + push gs + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + ; CLD - Azzera la flag di Direzione + ; Questa istruzione forza semplicemente a zero la flag di Direzione. + ; Quando la flag di direzione vale 0 tutte le istruzioni per la + ; manipolazione delle stringhe agiscono in avanti, cioè dagli indirizzi più + ; bassi a quelli più alti. + ; L'istruzione agisce dunque sui puntatori SI e DI producendo su essi un + ; autoincremento proporzionale alla dimensione degli operandi trattati. + ; Le sue caratteristiche sono riassunte nella seguente tabella (leggi le + ; istruzioni Legenda della Tabella): + cld + + ; Call the interrupt handler. + push esp; + call isr_handler + add esp, 0x4 + + ; Restore segment registers. + pop gs + pop fs + pop es + pop ds + + ; Restore all registers (eax, ecx, edx, ebx, esp, ebp, esi, edi). + popa + + ; Cleanup error code and IRQ # + add esp, 0x8 + + iret ; pops 5 things at once: + ; CS, EIP, EFLAGS, SS, and ESP diff --git a/mentos/src/descriptor_tables/exception.c b/mentos/src/descriptor_tables/exception.c index e346ebc..95a9449 100644 --- a/mentos/src/descriptor_tables/exception.c +++ b/mentos/src/descriptor_tables/exception.c @@ -1,93 +1,93 @@ -/// MentOS, The Mentoring Operating system project -/// @file isr.c -/// @brief Functions which manage the Interrupt Service Routines (ISRs). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "isr.h" -#include "idt.h" -#include "stdio.h" -#include "debug.h" - -// Default error messages for exceptions. -static const char *exception_messages[32] = { "Division by zero", - "Debug", - "Non-maskable interrupt", - "Breakpoint", - "Detected overflow", - "Out-of-bounds", - "Invalid opcode", - "No coprocessor", - "Double fault", - "Coprocessor segment overrun", - "Bad TSS", - "Segment not present", - "Stack fault", - "General protection fault", - "Page fault", - "Unknown interrupt", - "Coprocessor fault", - "Alignment check", - "Machine check", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Security exception", - "Triple fault" }; - -// Array of interrupt service routines for execptions and interrupts. -static interrupt_handler_t isr_routines[IDT_SIZE]; -static char *isr_routines_description[IDT_SIZE]; - -// Default handler for exceptions. -void default_isr_handler(pt_regs *f) -{ - uint32_t irq_line = f->int_no; - - printf("Kernel PANIC!\n no handler for execption [%d]\n", irq_line); - printf("Description: %s\n", (irq_line < 32) ? - exception_messages[irq_line] : - "no description"); - // Stop kernel execution. - while (1) - ; - - // TODO: call the kernel panic method! -} - -void isrs_init() -{ - // Setting the default_isr_handler as default handler. - for (uint32_t i = 0; i < IDT_SIZE; ++i) { - isr_routines[i] = default_isr_handler; - } -} - -int isr_install_handler(uint32_t i, interrupt_handler_t handler, - char *description) -{ - // Sanity check. - if (!(i >= 0 && i <= 31) && i != 80) { - return -1; - } - isr_routines[i] = handler; - isr_routines_description[i] = description; - return 0; -} - -void isr_handler(pt_regs *f) -{ - uint32_t isr_number = f->int_no; - if (isr_number != 80) { - dbg_print("calling ISR %d\n", isr_number); - } - isr_routines[isr_number](f); -} +/// MentOS, The Mentoring Operating system project +/// @file isr.c +/// @brief Functions which manage the Interrupt Service Routines (ISRs). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "isr.h" +#include "idt.h" +#include "stdio.h" +#include "debug.h" + +// Default error messages for exceptions. +static const char *exception_messages[32] = { "Division by zero", + "Debug", + "Non-maskable interrupt", + "Breakpoint", + "Detected overflow", + "Out-of-bounds", + "Invalid opcode", + "No coprocessor", + "Double fault", + "Coprocessor segment overrun", + "Bad TSS", + "Segment not present", + "Stack fault", + "General protection fault", + "Page fault", + "Unknown interrupt", + "Coprocessor fault", + "Alignment check", + "Machine check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Security exception", + "Triple fault" }; + +// Array of interrupt service routines for execptions and interrupts. +static interrupt_handler_t isr_routines[IDT_SIZE]; +static char *isr_routines_description[IDT_SIZE]; + +// Default handler for exceptions. +void default_isr_handler(pt_regs *f) +{ + uint32_t irq_line = f->int_no; + + printf("Kernel PANIC!\n no handler for execption [%d]\n", irq_line); + printf("Description: %s\n", (irq_line < 32) ? + exception_messages[irq_line] : + "no description"); + // Stop kernel execution. + while (1) + ; + + // TODO: call the kernel panic method! +} + +void isrs_init() +{ + // Setting the default_isr_handler as default handler. + for (uint32_t i = 0; i < IDT_SIZE; ++i) { + isr_routines[i] = default_isr_handler; + } +} + +int isr_install_handler(uint32_t i, interrupt_handler_t handler, + char *description) +{ + // Sanity check. + if (!(i >= 0 && i <= 31) && i != 80) { + return -1; + } + isr_routines[i] = handler; + isr_routines_description[i] = description; + return 0; +} + +void isr_handler(pt_regs *f) +{ + uint32_t isr_number = f->int_no; + if (isr_number != 80) { + dbg_print("calling ISR %d\n", isr_number); + } + isr_routines[isr_number](f); +} diff --git a/mentos/src/descriptor_tables/gdt.asm b/mentos/src/descriptor_tables/gdt.asm index df68538..b17c7b2 100644 --- a/mentos/src/descriptor_tables/gdt.asm +++ b/mentos/src/descriptor_tables/gdt.asm @@ -1,23 +1,23 @@ -; MentOS, The Mentoring Operating system project -; @file gdt.asm -; @brief -; @copyright (c) 2019 This file is distributed under the MIT License. -; See LICENSE.md for details. - -[GLOBAL gdt_flush] ; Allows the C code to call gdt_flush(). - -gdt_flush: - mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. - lgdt [eax] ; Load the new GDT pointer - - mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment - mov ds, ax ; Load all data segment selectors - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump! - -.flush: +; MentOS, The Mentoring Operating system project +; @file gdt.asm +; @brief +; @copyright (c) 2019 This file is distributed under the MIT License. +; See LICENSE.md for details. + +[GLOBAL gdt_flush] ; Allows the C code to call gdt_flush(). + +gdt_flush: + mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. + lgdt [eax] ; Load the new GDT pointer + + mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment + mov ds, ax ; Load all data segment selectors + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump! + +.flush: ret \ No newline at end of file diff --git a/mentos/src/descriptor_tables/gdt.c b/mentos/src/descriptor_tables/gdt.c index 16edba2..bf0cebb 100644 --- a/mentos/src/descriptor_tables/gdt.c +++ b/mentos/src/descriptor_tables/gdt.c @@ -1,101 +1,101 @@ -/// MentOS, The Mentoring Operating system project -/// @file gdt.c -/// @brief Functions which manage the Global Descriptor Table (GDT). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "gdt.h" -#include "tss.h" - -/// The maximum dimension of the GDT. -#define GDT_SIZE 10 - -/// @brief This will be a function in gdt.s. We use this to properly -/// reload the new segment registers -/// @param _gdt_pointer addresss of the gdt. -extern void gdt_flush(uint32_t _gdt_pointer); - -/// The GDT itself. -gdt_descriptor_t gdt[GDT_SIZE]; - -/// Pointer structure to give to the CPU. -gdt_pointer_t gdt_pointer; - -void init_gdt() -{ - // Prepare GDT vector. - for (uint32_t it = 0; it < GDT_SIZE; ++it) { - gdt[it].limit_low = 0; - gdt[it].base_low = 0; - gdt[it].base_middle = 0; - gdt[it].access = 0; - gdt[it].granularity = 0; - gdt[it].base_high = 0; - } - - // Setup the GDT pointer and limit. - // We have six entries in the GDT: - // - Two for kernel mode. - // - Two for user mode. - // - The NULL descriptor. - // - And one for the TSS (task state segment). - // The limit is the last valid byte from the start of the GDT. - // i.e. the size of the GDT - 1. - gdt_pointer.limit = sizeof(gdt_descriptor_t) * 6 - 1; - gdt_pointer.base = (uint32_t)&gdt; - - // ------------------------------------------------------------------------ - // NULL - // ------------------------------------------------------------------------ - gdt_set_gate(0, 0, 0, 0, 0); - - // ------------------------------------------------------------------------ - // CODE - // ------------------------------------------------------------------------ - // The base address is 0, the limit is 4GBytes, it uses 4KByte - // granularity, uses 32-bit opcodes, and is a Code Segment descriptor. - gdt_set_gate(1, 0, 0xFFFFFFFF, PRESENT | KERNEL | CODE | 0x0A, - GRANULARITY | SZBITS | 0x0F); - - // ------------------------------------------------------------------------ - // DATA - // ------------------------------------------------------------------------ - // It's EXACTLY the same as our code segment, but the descriptor type in - // this entry's access byte says it's a Data Segment. - gdt_set_gate(2, 0, 0xFFFFFFFF, PRESENT | KERNEL | DATA | 0x02, - GRANULARITY | SZBITS | 0x0F); - - // ------------------------------------------------------------------------ - // USER MODE CODE - // ------------------------------------------------------------------------ - gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, GRANULARITY | SZBITS | 0x0F); - - // ------------------------------------------------------------------------ - // USER MODE DATA - // ------------------------------------------------------------------------ - gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, GRANULARITY | SZBITS | 0x0F); - - // Initialize the TSS - tss_init(5, 0x10, 0x0); - - // Inform the CPU about the changes on the GDT. - gdt_flush((uint32_t)&gdt_pointer); - tss_flush(); -} - -void gdt_set_gate(uint8_t index, uint32_t base, uint32_t limit, uint8_t _access, - uint8_t _granul) -{ - // Setup the descriptor base address. - gdt[index].base_low = (base & 0xFFFF); - gdt[index].base_middle = (base >> 16) & 0xFF; - gdt[index].base_high = (base >> 24) & 0xFF; - - // Setup the descriptor limits. - gdt[index].limit_low = (limit & 0xFFFF); - gdt[index].granularity = (limit >> 16) & 0x0F; - - // Finally, set up the granularity and access flags. - gdt[index].access = _access; - gdt[index].granularity |= _granul & 0xF0; -} +/// MentOS, The Mentoring Operating system project +/// @file gdt.c +/// @brief Functions which manage the Global Descriptor Table (GDT). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "gdt.h" +#include "tss.h" + +/// The maximum dimension of the GDT. +#define GDT_SIZE 10 + +/// @brief This will be a function in gdt.s. We use this to properly +/// reload the new segment registers +/// @param _gdt_pointer addresss of the gdt. +extern void gdt_flush(uint32_t _gdt_pointer); + +/// The GDT itself. +gdt_descriptor_t gdt[GDT_SIZE]; + +/// Pointer structure to give to the CPU. +gdt_pointer_t gdt_pointer; + +void init_gdt() +{ + // Prepare GDT vector. + for (uint32_t it = 0; it < GDT_SIZE; ++it) { + gdt[it].limit_low = 0; + gdt[it].base_low = 0; + gdt[it].base_middle = 0; + gdt[it].access = 0; + gdt[it].granularity = 0; + gdt[it].base_high = 0; + } + + // Setup the GDT pointer and limit. + // We have six entries in the GDT: + // - Two for kernel mode. + // - Two for user mode. + // - The NULL descriptor. + // - And one for the TSS (task state segment). + // The limit is the last valid byte from the start of the GDT. + // i.e. the size of the GDT - 1. + gdt_pointer.limit = sizeof(gdt_descriptor_t) * 6 - 1; + gdt_pointer.base = (uint32_t)&gdt; + + // ------------------------------------------------------------------------ + // NULL + // ------------------------------------------------------------------------ + gdt_set_gate(0, 0, 0, 0, 0); + + // ------------------------------------------------------------------------ + // CODE + // ------------------------------------------------------------------------ + // The base address is 0, the limit is 4GBytes, it uses 4KByte + // granularity, uses 32-bit opcodes, and is a Code Segment descriptor. + gdt_set_gate(1, 0, 0xFFFFFFFF, PRESENT | KERNEL | CODE | 0x0A, + GRANULARITY | SZBITS | 0x0F); + + // ------------------------------------------------------------------------ + // DATA + // ------------------------------------------------------------------------ + // It's EXACTLY the same as our code segment, but the descriptor type in + // this entry's access byte says it's a Data Segment. + gdt_set_gate(2, 0, 0xFFFFFFFF, PRESENT | KERNEL | DATA | 0x02, + GRANULARITY | SZBITS | 0x0F); + + // ------------------------------------------------------------------------ + // USER MODE CODE + // ------------------------------------------------------------------------ + gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, GRANULARITY | SZBITS | 0x0F); + + // ------------------------------------------------------------------------ + // USER MODE DATA + // ------------------------------------------------------------------------ + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, GRANULARITY | SZBITS | 0x0F); + + // Initialize the TSS + tss_init(5, 0x10, 0x0); + + // Inform the CPU about the changes on the GDT. + gdt_flush((uint32_t)&gdt_pointer); + tss_flush(); +} + +void gdt_set_gate(uint8_t index, uint32_t base, uint32_t limit, uint8_t _access, + uint8_t _granul) +{ + // Setup the descriptor base address. + gdt[index].base_low = (base & 0xFFFF); + gdt[index].base_middle = (base >> 16) & 0xFF; + gdt[index].base_high = (base >> 24) & 0xFF; + + // Setup the descriptor limits. + gdt[index].limit_low = (limit & 0xFFFF); + gdt[index].granularity = (limit >> 16) & 0x0F; + + // Finally, set up the granularity and access flags. + gdt[index].access = _access; + gdt[index].granularity |= _granul & 0xF0; +} diff --git a/mentos/src/descriptor_tables/idt.asm b/mentos/src/descriptor_tables/idt.asm index 66cb14c..ed555e0 100644 --- a/mentos/src/descriptor_tables/idt.asm +++ b/mentos/src/descriptor_tables/idt.asm @@ -1,12 +1,12 @@ -; MentOS, The Mentoring Operating system project -; @file idt.asm -; @brief -; @copyright (c) 2019 This file is distributed under the MIT License. -; See LICENSE.md for details. - -[GLOBAL idt_flush] ; Allows the C code to call idt_flush(). - -idt_flush: - mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter. - lidt [eax] ; Load the IDT pointer. +; MentOS, The Mentoring Operating system project +; @file idt.asm +; @brief +; @copyright (c) 2019 This file is distributed under the MIT License. +; See LICENSE.md for details. + +[GLOBAL idt_flush] ; Allows the C code to call idt_flush(). + +idt_flush: + mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter. + lidt [eax] ; Load the IDT pointer. ret \ No newline at end of file diff --git a/mentos/src/descriptor_tables/idt.c b/mentos/src/descriptor_tables/idt.c index ce15413..116e027 100644 --- a/mentos/src/descriptor_tables/idt.c +++ b/mentos/src/descriptor_tables/idt.c @@ -1,129 +1,129 @@ -/// MentOS, The Mentoring Operating system project -/// @file idt.c -/// @brief Functions which manage the Interrupt Descriptor Table (IDT). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "idt.h" -#include "gdt.h" -#include "debug.h" - -/// @brief This function is in idt.asm. -extern void idt_flush(uint32_t idt_pointer); - -/// The IDT itself. -static idt_descriptor_t idt_table[IDT_SIZE]; - -/// Pointer structure to give to the CPU. -idt_pointer_t idt_pointer; - -// 1000 0000 -#define IDT_PRESENT 0x80 -// 0000 0000 -#define IDT_KERNEL 0x00 -// 0110 0000 -#define IDT_USER 0x60 -// 0000 1110 -#define IDT_PADDING 0x0E - -void init_idt() -{ - // Prepare IDT vector. - for (uint32_t it = 0; it < IDT_SIZE; ++it) { - idt_table[it].offset_low = 0; - idt_table[it].seg_selector = 0; - idt_table[it].null_par = 0; - idt_table[it].options = 0; - idt_table[it].offset_high = 0; - } - - // Just like the GDT, the IDT has a "limit" field that is set to the last - // valid byte in the IDT, after adding in the start position (i.e. size-1). - idt_pointer.limit = sizeof(idt_descriptor_t) * IDT_SIZE - 1; - idt_pointer.base = (uint32_t)&idt_table; - - // Initialize ISR for CPU execptions. - isrs_init(); - - // Initialize ISR for PIC interrupts. - irqs_init(); - - // Register ISR [0-31] + 80, interrupts generated by CPU. - // These interrupts will be initially managed by isr_handler. - // The appropriate handler will be called by looking at the vector - // isr_routines. - idt_set_gate(0, INT_0, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(1, INT_1, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(2, INT_2, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(3, INT_3, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(4, INT_4, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(5, INT_5, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(6, INT_6, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(7, INT_7, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(8, INT_8, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(9, INT_9, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(10, INT_10, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(11, INT_11, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(12, INT_12, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(13, INT_13, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(14, INT_14, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(15, INT_15, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(16, INT_16, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(17, INT_17, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(18, INT_18, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(19, INT_19, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(20, INT_20, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(21, INT_21, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(22, INT_22, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(23, INT_23, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(24, INT_24, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(25, INT_25, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(26, INT_26, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(27, INT_27, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(28, INT_28, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(29, INT_29, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(30, INT_30, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(31, INT_31, IDT_PRESENT | IDT_KERNEL, 0x8); - - // Registers ISR [32-47] (irq [0-15]), interrupts generated by PIC. - // These interrupts will be initially managed by irq_handler. - // The appropriate handler will be called by looking at the vector - // isr_routines. - idt_set_gate(32, IRQ_0, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(33, IRQ_1, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(34, IRQ_2, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(35, IRQ_3, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(36, IRQ_4, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(37, IRQ_5, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(38, IRQ_6, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(39, IRQ_7, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(40, IRQ_8, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(41, IRQ_9, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(42, IRQ_10, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(43, IRQ_11, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(44, IRQ_12, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(45, IRQ_13, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(46, IRQ_14, IDT_PRESENT | IDT_KERNEL, 0x8); - idt_set_gate(47, IRQ_15, IDT_PRESENT | IDT_KERNEL, 0x8); - - // System call! - idt_set_gate(128, INT_80, IDT_PRESENT | IDT_USER, 0x8); - - // Points the processor's internal register to the new IDT. - idt_flush((uint32_t)&idt_pointer); -} - -void idt_set_gate(uint8_t index, interrupt_handler_t handler, uint16_t options, - uint8_t seg_sel) -{ - uint32_t base_prt = (uint32_t)handler; - - // Assign the base values. - idt_table[index].offset_low = (base_prt & 0xFFFF); - idt_table[index].offset_high = (base_prt >> 16) & 0xFFFF; - - // Set the other fields. - idt_table[index].null_par = 0x00; - idt_table[index].seg_selector = seg_sel; - idt_table[index].options = options | IDT_PADDING; -} +/// MentOS, The Mentoring Operating system project +/// @file idt.c +/// @brief Functions which manage the Interrupt Descriptor Table (IDT). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "idt.h" +#include "gdt.h" +#include "debug.h" + +/// @brief This function is in idt.asm. +extern void idt_flush(uint32_t idt_pointer); + +/// The IDT itself. +static idt_descriptor_t idt_table[IDT_SIZE]; + +/// Pointer structure to give to the CPU. +idt_pointer_t idt_pointer; + +// 1000 0000 +#define IDT_PRESENT 0x80 +// 0000 0000 +#define IDT_KERNEL 0x00 +// 0110 0000 +#define IDT_USER 0x60 +// 0000 1110 +#define IDT_PADDING 0x0E + +void init_idt() +{ + // Prepare IDT vector. + for (uint32_t it = 0; it < IDT_SIZE; ++it) { + idt_table[it].offset_low = 0; + idt_table[it].seg_selector = 0; + idt_table[it].null_par = 0; + idt_table[it].options = 0; + idt_table[it].offset_high = 0; + } + + // Just like the GDT, the IDT has a "limit" field that is set to the last + // valid byte in the IDT, after adding in the start position (i.e. size-1). + idt_pointer.limit = sizeof(idt_descriptor_t) * IDT_SIZE - 1; + idt_pointer.base = (uint32_t)&idt_table; + + // Initialize ISR for CPU execptions. + isrs_init(); + + // Initialize ISR for PIC interrupts. + irqs_init(); + + // Register ISR [0-31] + 80, interrupts generated by CPU. + // These interrupts will be initially managed by isr_handler. + // The appropriate handler will be called by looking at the vector + // isr_routines. + idt_set_gate(0, INT_0, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(1, INT_1, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(2, INT_2, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(3, INT_3, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(4, INT_4, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(5, INT_5, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(6, INT_6, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(7, INT_7, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(8, INT_8, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(9, INT_9, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(10, INT_10, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(11, INT_11, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(12, INT_12, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(13, INT_13, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(14, INT_14, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(15, INT_15, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(16, INT_16, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(17, INT_17, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(18, INT_18, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(19, INT_19, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(20, INT_20, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(21, INT_21, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(22, INT_22, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(23, INT_23, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(24, INT_24, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(25, INT_25, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(26, INT_26, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(27, INT_27, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(28, INT_28, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(29, INT_29, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(30, INT_30, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(31, INT_31, IDT_PRESENT | IDT_KERNEL, 0x8); + + // Registers ISR [32-47] (irq [0-15]), interrupts generated by PIC. + // These interrupts will be initially managed by irq_handler. + // The appropriate handler will be called by looking at the vector + // isr_routines. + idt_set_gate(32, IRQ_0, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(33, IRQ_1, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(34, IRQ_2, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(35, IRQ_3, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(36, IRQ_4, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(37, IRQ_5, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(38, IRQ_6, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(39, IRQ_7, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(40, IRQ_8, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(41, IRQ_9, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(42, IRQ_10, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(43, IRQ_11, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(44, IRQ_12, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(45, IRQ_13, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(46, IRQ_14, IDT_PRESENT | IDT_KERNEL, 0x8); + idt_set_gate(47, IRQ_15, IDT_PRESENT | IDT_KERNEL, 0x8); + + // System call! + idt_set_gate(128, INT_80, IDT_PRESENT | IDT_USER, 0x8); + + // Points the processor's internal register to the new IDT. + idt_flush((uint32_t)&idt_pointer); +} + +void idt_set_gate(uint8_t index, interrupt_handler_t handler, uint16_t options, + uint8_t seg_sel) +{ + uint32_t base_prt = (uint32_t)handler; + + // Assign the base values. + idt_table[index].offset_low = (base_prt & 0xFFFF); + idt_table[index].offset_high = (base_prt >> 16) & 0xFFFF; + + // Set the other fields. + idt_table[index].null_par = 0x00; + idt_table[index].seg_selector = seg_sel; + idt_table[index].options = options | IDT_PADDING; +} diff --git a/mentos/src/descriptor_tables/interrupt.asm b/mentos/src/descriptor_tables/interrupt.asm index b095447..cf15f98 100644 --- a/mentos/src/descriptor_tables/interrupt.asm +++ b/mentos/src/descriptor_tables/interrupt.asm @@ -1,85 +1,85 @@ -; MentOS, The Mentoring Operating system project -; @file interrupt.asm -; @brief -; @copyright (c) 2019 This file is distributed under the MIT License. -; See LICENSE.md for details. - -%macro IRQ 2 - [GLOBAL IRQ_%1] - IRQ_%1: - cli ; disable interrupt line - ; A normal ISR stub that pops a dummy error code to keep a - ; uniform stack frame - push 0 - push %2 ; irq number - jmp irq_common -%endmacro -; 32 is the first irq, 47 is the last one. DO NOT CHANGE THESE NUMBERS. -IRQ 0, 32 -IRQ 1, 33 -IRQ 2, 34 -IRQ 3, 35 -IRQ 4, 36 -IRQ 5, 37 -IRQ 6, 38 -IRQ 7, 39 -IRQ 8, 40 -IRQ 9, 41 -IRQ 10, 42 -IRQ 11, 43 -IRQ 12, 44 -IRQ 13, 45 -IRQ 14, 46 -IRQ 15, 47 - -[EXTERN irq_handler] - -irq_common: - ;==== Save CPU registers =================================================== - ; when an irq occurs, the following registers are already pushed on stack: - ; eip, cs, eflags, useresp, ss - - ; Save registers: eax, ecx, edx, ebx, esp, ebp, esi, edi - pusha - - ; Save segment registers - push ds - push es - push fs - push gs - ;--------------------------------------------------------------------------- - - ;==== ensure we are using kernel data segment ============================== - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - cld - ;--------------------------------------------------------------------------- - - ;==== Call the interrupt handler =========================================== - ; The argument passed is a pointer to an Interrupt_State struct, - ; which describes the stack layout for all interrupts. - push esp - call irq_handler - add esp, $4 ; remove esp from stack - ;--------------------------------------------------------------------------- - - ;==== Restore registers ==================================================== - ; restore segment registers - pop gs - pop fs - pop es - pop ds - - ; restore registers: eax, ecx, edx, ebx, esp, ebp, esi, edi - popa - ;--------------------------------------------------------------------------- - - ; Cleanup error code and IRQ # - add esp, $8 - - ; return to process - iret ; pops 5 things at once: - ; CS, EIP, EFLAGS, SS, and ESP +; MentOS, The Mentoring Operating system project +; @file interrupt.asm +; @brief +; @copyright (c) 2019 This file is distributed under the MIT License. +; See LICENSE.md for details. + +%macro IRQ 2 + [GLOBAL IRQ_%1] + IRQ_%1: + cli ; disable interrupt line + ; A normal ISR stub that pops a dummy error code to keep a + ; uniform stack frame + push 0 + push %2 ; irq number + jmp irq_common +%endmacro +; 32 is the first irq, 47 is the last one. DO NOT CHANGE THESE NUMBERS. +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +[EXTERN irq_handler] + +irq_common: + ;==== Save CPU registers =================================================== + ; when an irq occurs, the following registers are already pushed on stack: + ; eip, cs, eflags, useresp, ss + + ; Save registers: eax, ecx, edx, ebx, esp, ebp, esi, edi + pusha + + ; Save segment registers + push ds + push es + push fs + push gs + ;--------------------------------------------------------------------------- + + ;==== ensure we are using kernel data segment ============================== + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + cld + ;--------------------------------------------------------------------------- + + ;==== Call the interrupt handler =========================================== + ; The argument passed is a pointer to an Interrupt_State struct, + ; which describes the stack layout for all interrupts. + push esp + call irq_handler + add esp, $4 ; remove esp from stack + ;--------------------------------------------------------------------------- + + ;==== Restore registers ==================================================== + ; restore segment registers + pop gs + pop fs + pop es + pop ds + + ; restore registers: eax, ecx, edx, ebx, esp, ebp, esi, edi + popa + ;--------------------------------------------------------------------------- + + ; Cleanup error code and IRQ # + add esp, $8 + + ; return to process + iret ; pops 5 things at once: + ; CS, EIP, EFLAGS, SS, and ESP diff --git a/mentos/src/descriptor_tables/interrupt.c b/mentos/src/descriptor_tables/interrupt.c index 15f0161..fcc188d 100644 --- a/mentos/src/descriptor_tables/interrupt.c +++ b/mentos/src/descriptor_tables/interrupt.c @@ -1,113 +1,113 @@ -/// MentOS, The Mentoring Operating system project -/// @file isr.c -/// @brief Functions which manage the Interrupt Service Routines (ISRs). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "isr.h" -#include "idt.h" -#include "printk.h" -#include "pic8259.h" -#include "pic8259.h" -#include "scheduler.h" - -// TODO: lists, double-linked lists should be a Kernel data struture! -/// @brief shared interrupt handlers are stored into a linked list. -/// irq_struct_t is a node of the list -typedef struct irq_struct_t { - /// Puntatore alla funzione handler di un IRQ. - interrupt_handler_t handler; - - /// Puntatore alla descrizione dell'handler. - char *description; - - /// Prossimo handler per questo IRQ - struct irq_struct_t *next; -} irq_struct_t; - -// For each IRQ, a chain of handlers. -static irq_struct_t *shared_interrupt_handlers[IRQ_NUM]; - -// Default handler for interrupts and exceptions. -void default_irq_handler(pt_regs *f) -{ - uint32_t irq_line = f->int_no - 32; - - printk("Kernel PANIC!\n no handler for IRQ [%d]\n", irq_line); - - // Stop kernel execution. - while (1) - ; - // TODO: call the kernel panic method! -} - -void irqs_init() -{ - // Setting the default_irq_handler as default handler for each IRQ line. - irq_struct_t *irq_struct = NULL; - for (uint32_t i = 0; i < IRQ_NUM; ++i) { - irq_struct = (irq_struct_t *)kmalloc(sizeof(irq_struct_t)); - irq_struct->handler = default_irq_handler; - irq_struct->next = NULL; - shared_interrupt_handlers[i] = irq_struct; - } -} - -int irq_install_handler(uint32_t i, interrupt_handler_t handler, - char *description) -{ - // We have maximun IRQ_NUM IRQ lines. - if (i > IRQ_NUM) { - return -1; - } - - // The current handler for this IRQ line. - irq_struct_t *current_irq_struct = shared_interrupt_handlers[i]; - - // Is the current handler the default one? - if (current_irq_struct->handler == default_irq_handler) { - // Set the given handler as a new handler for i-th IRQ. - current_irq_struct->handler = handler; - // Return. Nothing else to do. - return 0; - } - - // Move current_irq_struct to get the last handler for this IRQ line. - while (current_irq_struct->next != NULL) { - current_irq_struct = current_irq_struct->next; - } - - // Create a new irq_struct_t to save the given handler. - irq_struct_t *irq_struct = - (irq_struct_t *)kmalloc(sizeof(irq_struct_t)); - irq_struct->next = NULL; - irq_struct->description = description; - irq_struct->handler = handler; - - // Store the given handler. - current_irq_struct->next = irq_struct; - return 0; -} - -void irq_handler(pt_regs *f) -{ - // Keep in mind, - // because of irq mapping, the first PIC's irq line is shifted by 32. - uint32_t irq_line = f->int_no - 32; - - // Actually, we may have several handlers for a same irq line. - // The Kernel should provide the dev_id to each handler in order to - // let it know if its own device generated the interrupt. - // TODO: get dev_id - - irq_struct_t *irq_struct = shared_interrupt_handlers[irq_line]; - do { - // Call the interrupt function. - irq_struct->handler(f); - // Move to the next interrupt function. - irq_struct = irq_struct->next; - } while (irq_struct != NULL); - - // Send the end-of-interrupt to PIC. - pic8259_send_eoi(irq_line); -} +/// MentOS, The Mentoring Operating system project +/// @file isr.c +/// @brief Functions which manage the Interrupt Service Routines (ISRs). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "isr.h" +#include "idt.h" +#include "printk.h" +#include "pic8259.h" +#include "pic8259.h" +#include "scheduler.h" + +// TODO: lists, double-linked lists should be a Kernel data struture! +/// @brief shared interrupt handlers are stored into a linked list. +/// irq_struct_t is a node of the list +typedef struct irq_struct_t { + /// Puntatore alla funzione handler di un IRQ. + interrupt_handler_t handler; + + /// Puntatore alla descrizione dell'handler. + char *description; + + /// Prossimo handler per questo IRQ + struct irq_struct_t *next; +} irq_struct_t; + +// For each IRQ, a chain of handlers. +static irq_struct_t *shared_interrupt_handlers[IRQ_NUM]; + +// Default handler for interrupts and exceptions. +void default_irq_handler(pt_regs *f) +{ + uint32_t irq_line = f->int_no - 32; + + printk("Kernel PANIC!\n no handler for IRQ [%d]\n", irq_line); + + // Stop kernel execution. + while (1) + ; + // TODO: call the kernel panic method! +} + +void irqs_init() +{ + // Setting the default_irq_handler as default handler for each IRQ line. + irq_struct_t *irq_struct = NULL; + for (uint32_t i = 0; i < IRQ_NUM; ++i) { + irq_struct = (irq_struct_t *)kmalloc(sizeof(irq_struct_t)); + irq_struct->handler = default_irq_handler; + irq_struct->next = NULL; + shared_interrupt_handlers[i] = irq_struct; + } +} + +int irq_install_handler(uint32_t i, interrupt_handler_t handler, + char *description) +{ + // We have maximun IRQ_NUM IRQ lines. + if (i > IRQ_NUM) { + return -1; + } + + // The current handler for this IRQ line. + irq_struct_t *current_irq_struct = shared_interrupt_handlers[i]; + + // Is the current handler the default one? + if (current_irq_struct->handler == default_irq_handler) { + // Set the given handler as a new handler for i-th IRQ. + current_irq_struct->handler = handler; + // Return. Nothing else to do. + return 0; + } + + // Move current_irq_struct to get the last handler for this IRQ line. + while (current_irq_struct->next != NULL) { + current_irq_struct = current_irq_struct->next; + } + + // Create a new irq_struct_t to save the given handler. + irq_struct_t *irq_struct = + (irq_struct_t *)kmalloc(sizeof(irq_struct_t)); + irq_struct->next = NULL; + irq_struct->description = description; + irq_struct->handler = handler; + + // Store the given handler. + current_irq_struct->next = irq_struct; + return 0; +} + +void irq_handler(pt_regs *f) +{ + // Keep in mind, + // because of irq mapping, the first PIC's irq line is shifted by 32. + uint32_t irq_line = f->int_no - 32; + + // Actually, we may have several handlers for a same irq line. + // The Kernel should provide the dev_id to each handler in order to + // let it know if its own device generated the interrupt. + // TODO: get dev_id + + irq_struct_t *irq_struct = shared_interrupt_handlers[irq_line]; + do { + // Call the interrupt function. + irq_struct->handler(f); + // Move to the next interrupt function. + irq_struct = irq_struct->next; + } while (irq_struct != NULL); + + // Send the end-of-interrupt to PIC. + pic8259_send_eoi(irq_line); +} diff --git a/mentos/src/descriptor_tables/tss.asm b/mentos/src/descriptor_tables/tss.asm index 84275dc..22b904e 100644 --- a/mentos/src/descriptor_tables/tss.asm +++ b/mentos/src/descriptor_tables/tss.asm @@ -1,12 +1,12 @@ -; MentOS, The Mentoring Operating system project -; @file tss.asm -; @brief -; @copyright (c) 2019 This file is distributed under the MIT License. -; See LICENSE.md for details. - -[GLOBAL tss_flush] - -tss_flush: - mov ax, 0x28 - ltr ax - ret +; MentOS, The Mentoring Operating system project +; @file tss.asm +; @brief +; @copyright (c) 2019 This file is distributed under the MIT License. +; See LICENSE.md for details. + +[GLOBAL tss_flush] + +tss_flush: + mov ax, 0x28 + ltr ax + ret diff --git a/mentos/src/descriptor_tables/tss.c b/mentos/src/descriptor_tables/tss.c index 8cbf775..e4be7f9 100644 --- a/mentos/src/descriptor_tables/tss.c +++ b/mentos/src/descriptor_tables/tss.c @@ -1,59 +1,59 @@ -/// MentOS, The Mentoring Operating system project -/// @file tss.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "tss.h" -#include "debug.h" -#include "string.h" - -static tss_entry_t kernel_tss; - -void tss_init(uint8_t idx, uint32_t kss, uint32_t kesp) -{ - uint32_t base = (uint32_t) &kernel_tss; - uint32_t limit = base + sizeof(tss_entry_t); - - // Add the TSS descriptor to the GDT. - // Kernel tss, access(E9 = 1 11 0 1 0 0 1) - // 1 present - // 11 ring 3 - // 0 should always be 1, why 0? may be this value doesn't matter at all - // 1 code? - // 0 can not be executed by ring lower or equal to DPL, - // 0 not readable - // 1 access bit, always 0, cpu set this to 1 when accessing this - // sector(why 0 now?) - gdt_set_gate(idx, base, limit, 0xE9, 0x0); - - // init. tss entry to zero - memset(&kernel_tss, 0x0, sizeof(tss_entry_t)); - - kernel_tss.ss0 = kss; - // Note that we usually set tss's esp to 0 when booting our os, however, - // we need to set it to the real esp when we've switched to usermode - // because the CPU needs to know what esp to use when usermode app is - // calling a kernel function(aka system call), that's why we have a - // function below called tss_set_stack. - kernel_tss.esp0 = kesp; - kernel_tss.cs = 0x0b; - kernel_tss.ds = 0x13; - kernel_tss.es = 0x13; - kernel_tss.fs = 0x13; - kernel_tss.gs = 0x13; - kernel_tss.ss = 0x13; - kernel_tss.iomap = sizeof(tss_entry_t); -} - -void print_tss() { - printf("TSS: SSO(%p) ESP0(%p)\n", kernel_tss.ss0, kernel_tss.esp0); -} - -void tss_set_stack(uint32_t kss, uint32_t kesp) -{ - // Kernel data segment. - kernel_tss.ss0 = kss; - // Kernel stack address. - kernel_tss.esp0 = kesp; -} +/// MentOS, The Mentoring Operating system project +/// @file tss.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "tss.h" +#include "debug.h" +#include "string.h" + +static tss_entry_t kernel_tss; + +void tss_init(uint8_t idx, uint32_t kss, uint32_t kesp) +{ + uint32_t base = (uint32_t) &kernel_tss; + uint32_t limit = base + sizeof(tss_entry_t); + + // Add the TSS descriptor to the GDT. + // Kernel tss, access(E9 = 1 11 0 1 0 0 1) + // 1 present + // 11 ring 3 + // 0 should always be 1, why 0? may be this value doesn't matter at all + // 1 code? + // 0 can not be executed by ring lower or equal to DPL, + // 0 not readable + // 1 access bit, always 0, cpu set this to 1 when accessing this + // sector(why 0 now?) + gdt_set_gate(idx, base, limit, 0xE9, 0x0); + + // init. tss entry to zero + memset(&kernel_tss, 0x0, sizeof(tss_entry_t)); + + kernel_tss.ss0 = kss; + // Note that we usually set tss's esp to 0 when booting our os, however, + // we need to set it to the real esp when we've switched to usermode + // because the CPU needs to know what esp to use when usermode app is + // calling a kernel function(aka system call), that's why we have a + // function below called tss_set_stack. + kernel_tss.esp0 = kesp; + kernel_tss.cs = 0x0b; + kernel_tss.ds = 0x13; + kernel_tss.es = 0x13; + kernel_tss.fs = 0x13; + kernel_tss.gs = 0x13; + kernel_tss.ss = 0x13; + kernel_tss.iomap = sizeof(tss_entry_t); +} + +void print_tss() { + printf("TSS: SSO(%p) ESP0(%p)\n", kernel_tss.ss0, kernel_tss.esp0); +} + +void tss_set_stack(uint32_t kss, uint32_t kesp) +{ + // Kernel data segment. + kernel_tss.ss0 = kss; + // Kernel stack address. + kernel_tss.esp0 = kesp; +} diff --git a/mentos/src/devices/fpu.c b/mentos/src/devices/fpu.c index c9a0b7d..1393f4d 100644 --- a/mentos/src/devices/fpu.c +++ b/mentos/src/devices/fpu.c @@ -1,177 +1,177 @@ -/// MentOS, The Mentoring Operating system project -/// @file fpu.c -/// @brief Floating Point Unit (FPU). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "fpu.h" -#include "isr.h" -#include "debug.h" -#include "string.h" -#include "assert.h" -#include "process.h" -#include "scheduler.h" - -#define NO_LAZY_FPU - -struct task_struct *fpu_thread = NULL; - -/// @brief Set the FPU control word. -/// @param cw What to set the control word to. -void set_fpu_cw(const uint16_t cw) -{ - asm volatile("fldcw %0" ::"m"(cw)); -} - -/// @brief Enable the FPU and SSE. -void enable_fpu() -{ - asm volatile("clts"); - - size_t t; - - asm volatile("mov %%cr0, %0" : "=r"(t)); - - t &= ~(1 << 2); - - t |= (1 << 1); - - asm volatile("mov %0, %%cr0" ::"r"(t)); - - asm volatile("mov %%cr4, %0" : "=r"(t)); - - t |= 3 << 9; - - asm volatile("mov %0, %%cr4" ::"r"(t)); -} - -/// Disable FPU and SSE so it traps to the kernel. -void disable_fpu() -{ - size_t t; - - asm volatile("mov %%cr0, %0" : "=r"(t)); - - t |= 1 << 3; - - asm volatile("mov %0, %%cr0" ::"r"(t)); -} - -// Temporary aligned buffer for copying around FPU contexts. -uint8_t saves[512] __attribute__((aligned(16))); - -/// @brief Restore the FPU for a process. -void restore_fpu(struct task_struct *proc) -{ - assert(proc && "Trying to restore FPU of NULL process."); - - memcpy(&saves, (uint8_t *)&proc->thread.fpu_register, 512); - - asm volatile("fxrstor (%0)" ::"r"(saves)); -} - -/// Save the FPU for a process. -void save_fpu(struct task_struct *proc) -{ - assert(proc && "Trying to save FPU of NULL process."); - - asm volatile("fxsave (%0)" ::"r"(saves)); - - memcpy((uint8_t *)&proc->thread.fpu_register, &saves, 512); -} - -/// Initialize the FPU. -void init_fpu() -{ - asm volatile("fninit"); -} - -/// Kernel trap for FPU usage when FPU is disabled. -void invalid_op(pt_regs *r) -{ - // First, turn the FPU on. - enable_fpu(); - if (fpu_thread == kernel_get_current_process()) { - // If this is the thread that last used the FPU, do nothing. - return; - } - if (fpu_thread) { - // If there is a thread that was using the FPU, save its state. - save_fpu(fpu_thread); - } - fpu_thread = kernel_get_current_process(); - if (!fpu_thread->thread.fpu_enabled) { - /* - * If the FPU has not been used in this thread previously, - * we need to initialize it. - */ - init_fpu(); - fpu_thread->thread.fpu_enabled = true; - return; - } - // Otherwise we restore the context for this thread. - restore_fpu(fpu_thread); -} - -// Called during a context switch; disable the FPU. -void switch_fpu() -{ -#ifdef NO_LAZY_FPU - save_fpu(kernel_get_current_process()); -#else - disable_fpu(); -#endif -} - -void unswitch_fpu() -{ -#ifdef NO_LAZY_FPU - restore_fpu(kernel_get_current_process()); -#endif -} - -static bool_t fpu_test_1() -{ - double a = M_PI; - for (int i = 0; i < 10000; i++) { - a = a * 1.123 + (a / 3); - a /= 1.111; - while (a > 100.0) { - a /= 3.1234563212; - } - while (a < 2.0) { - a += 1.1232132131; - } - } - return (a == 50.11095685350556294679336133413); -} - -/* - * Ensure basic FPU functionality works. - * - * For processors without a FPU, this tests that maths libraries link - * correctly. - */ -static bool_t fpu_test_2() -{ - double a = M_PI; - for (int i = 0; i < 100; i++) { - a = a * 3 + (a / 3); - } - return (a == 60957114488184560000000000000000000000000000000000000.0); -} - -// Enable the FPU context handling. -bool_t fpu_install() -{ -#ifdef NO_LAZY_FPU - enable_fpu(); - init_fpu(); - save_fpu(kernel_get_current_process()); -#else - enable_fpu(); - disable_fpu(); -#endif - isr_install_handler(7, &invalid_op, "fpu"); - return fpu_test_1() & fpu_test_2(); -} +/// MentOS, The Mentoring Operating system project +/// @file fpu.c +/// @brief Floating Point Unit (FPU). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "fpu.h" +#include "isr.h" +#include "debug.h" +#include "string.h" +#include "assert.h" +#include "process.h" +#include "scheduler.h" + +#define NO_LAZY_FPU + +struct task_struct *fpu_thread = NULL; + +/// @brief Set the FPU control word. +/// @param cw What to set the control word to. +void set_fpu_cw(const uint16_t cw) +{ + asm volatile("fldcw %0" ::"m"(cw)); +} + +/// @brief Enable the FPU and SSE. +void enable_fpu() +{ + asm volatile("clts"); + + size_t t; + + asm volatile("mov %%cr0, %0" : "=r"(t)); + + t &= ~(1 << 2); + + t |= (1 << 1); + + asm volatile("mov %0, %%cr0" ::"r"(t)); + + asm volatile("mov %%cr4, %0" : "=r"(t)); + + t |= 3 << 9; + + asm volatile("mov %0, %%cr4" ::"r"(t)); +} + +/// Disable FPU and SSE so it traps to the kernel. +void disable_fpu() +{ + size_t t; + + asm volatile("mov %%cr0, %0" : "=r"(t)); + + t |= 1 << 3; + + asm volatile("mov %0, %%cr0" ::"r"(t)); +} + +// Temporary aligned buffer for copying around FPU contexts. +uint8_t saves[512] __attribute__((aligned(16))); + +/// @brief Restore the FPU for a process. +void restore_fpu(struct task_struct *proc) +{ + assert(proc && "Trying to restore FPU of NULL process."); + + memcpy(&saves, (uint8_t *)&proc->thread.fpu_register, 512); + + asm volatile("fxrstor (%0)" ::"r"(saves)); +} + +/// Save the FPU for a process. +void save_fpu(struct task_struct *proc) +{ + assert(proc && "Trying to save FPU of NULL process."); + + asm volatile("fxsave (%0)" ::"r"(saves)); + + memcpy((uint8_t *)&proc->thread.fpu_register, &saves, 512); +} + +/// Initialize the FPU. +void init_fpu() +{ + asm volatile("fninit"); +} + +/// Kernel trap for FPU usage when FPU is disabled. +void invalid_op(pt_regs *r) +{ + // First, turn the FPU on. + enable_fpu(); + if (fpu_thread == kernel_get_current_process()) { + // If this is the thread that last used the FPU, do nothing. + return; + } + if (fpu_thread) { + // If there is a thread that was using the FPU, save its state. + save_fpu(fpu_thread); + } + fpu_thread = kernel_get_current_process(); + if (!fpu_thread->thread.fpu_enabled) { + /* + * If the FPU has not been used in this thread previously, + * we need to initialize it. + */ + init_fpu(); + fpu_thread->thread.fpu_enabled = true; + return; + } + // Otherwise we restore the context for this thread. + restore_fpu(fpu_thread); +} + +// Called during a context switch; disable the FPU. +void switch_fpu() +{ +#ifdef NO_LAZY_FPU + save_fpu(kernel_get_current_process()); +#else + disable_fpu(); +#endif +} + +void unswitch_fpu() +{ +#ifdef NO_LAZY_FPU + restore_fpu(kernel_get_current_process()); +#endif +} + +static bool_t fpu_test_1() +{ + double a = M_PI; + for (int i = 0; i < 10000; i++) { + a = a * 1.123 + (a / 3); + a /= 1.111; + while (a > 100.0) { + a /= 3.1234563212; + } + while (a < 2.0) { + a += 1.1232132131; + } + } + return (a == 50.11095685350556294679336133413); +} + +/* + * Ensure basic FPU functionality works. + * + * For processors without a FPU, this tests that maths libraries link + * correctly. + */ +static bool_t fpu_test_2() +{ + double a = M_PI; + for (int i = 0; i < 100; i++) { + a = a * 3 + (a / 3); + } + return (a == 60957114488184560000000000000000000000000000000000000.0); +} + +// Enable the FPU context handling. +bool_t fpu_install() +{ +#ifdef NO_LAZY_FPU + enable_fpu(); + init_fpu(); + save_fpu(kernel_get_current_process()); +#else + enable_fpu(); + disable_fpu(); +#endif + isr_install_handler(7, &invalid_op, "fpu"); + return fpu_test_1() & fpu_test_2(); +} diff --git a/mentos/src/devices/pci.c b/mentos/src/devices/pci.c index 086feb0..c61ff9f 100644 --- a/mentos/src/devices/pci.c +++ b/mentos/src/devices/pci.c @@ -1,515 +1,515 @@ -/// MentOS, The Mentoring Operating system project -/// @file pci.c -/// @brief Routines for PCI initialization. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "pci.h" -#include "debug.h" -#include "stdio.h" -#include "kheap.h" -#include "string.h" -#include "port_io.h" - -void pci_write_field(uint32_t device, int field, int size, uint32_t value) -{ - (void)size; - outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); -#if 0 - if (size == 4) - outportl(PCI_VALUE_PORT, value); - else if (size == 2) - outports(PCI_VALUE_PORT, value); - else if (size == 1) - outportb(PCI_VALUE_PORT, value); -#else - outportl(PCI_VALUE_PORT, value); -#endif -} - -uint32_t pci_read_field(uint32_t device, int field, int size) -{ - outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); - - if (size == 4) { - return inportl(PCI_VALUE_PORT); - } else if (size == 2) { - return inports(PCI_VALUE_PORT + (field & 2)); - } else if (size == 1) { - return inportb(PCI_VALUE_PORT + (field & 3)); - } - return 0xFFFF; -} - -uint32_t pci_find_type(uint32_t device) -{ - return pci_read_field(device, PCI_CLASS, 1) << 16 | - pci_read_field(device, PCI_SUBCLASS, 1) << 8 | - pci_read_field(device, PCI_PROG_IF, 1); -} - -struct { - uint16_t id; - const char *name; -} _pci_vendors[] = { - { 0x1022, "AMD" }, { 0x106b, "Apple, Inc." }, - { 0x1234, "Bochs/QEMU" }, { 0x1274, "Ensoniq" }, - { 0x15ad, "VMWare" }, { 0x8086, "Intel Corporation" }, - { 0x80EE, "VirtualBox" }, -}; - -struct { - uint16_t ven_id; - uint16_t dev_id; - const char *name; -} _pci_devices[] = { - { 0x1022, 0x2000, "PCNet Ethernet Controller (pcnet)" }, - { 0x106b, 0x003f, "OHCI Controller" }, - { 0x1234, 0x1111, "VGA BIOS Graphics Extensions" }, - { 0x1274, 0x1371, "Creative Labs CT2518 (ensoniq audio)" }, - { 0x15ad, 0x0740, "VM Communication Interface" }, - { 0x15ad, 0x0405, "SVGA II Adapter" }, - { 0x15ad, 0x0790, "PCI bridge" }, - { 0x15ad, 0x07a0, "PCI Express Root Port" }, - { 0x8086, 0x100e, "Gigabit Ethernet Controller (e1000)" }, - { 0x8086, 0x100f, "Gigabit Ethernet Controller (e1000)" }, - { 0x8086, 0x1237, "PCI & Memory" }, - { 0x8086, 0x2415, "AC'97 Audio Chipset" }, - { 0x8086, 0x7000, "PCI-to-ISA Bridge" }, - { 0x8086, 0x7010, "IDE Interface" }, - { 0x8086, 0x7110, "PIIX4 ISA" }, - { 0x8086, 0x7111, "PIIX4 IDE" }, - { 0x8086, 0x7113, "Power Management Controller" }, - { 0x8086, 0x7190, "Host Bridge" }, - { 0x8086, 0x7191, "AGP Bridge" }, - { 0x80EE, 0xBEEF, "Bochs/QEMU-compatible Graphics Adapter" }, - { 0x80EE, 0xCAFE, "Guest Additions Device" }, -}; - -struct { - uint32_t id; - const char *name; -} _pci_classes[] = { - { 0x000000, "Legacy Device" }, - { 0x000100, "VGA-Compatible Device" }, - - { 0x010000, "SCSI bus controller" }, - { 0x010100, "ISA Compatibility mode-only controller" }, - { 0x010105, "PCI native mode-only controller" }, - { 0x01010a, "ISA Compatibility mode controller, supports both channels " - "switched to PCI native mode" }, - { 0x01010f, "PCI native mode controller, supports both channels switched " - "to ISA compatibility mode" }, - { 0x010180, - "ISA Compatibility mode-only controller, supports bus mastering" }, - { 0x010185, "PCI native mode-only controller, supports bus mastering" }, - { 0x01018a, "ISA Compatibility mode controller, supports both channels " - "switched to PCI native mode, supports bus mastering" }, - { 0x01018f, "PCI native mode controller, supports both channels switched " - "\to ISA compatibility mode, supports bus mastering" }, - - { 0x010200, "Floppy disk controller" }, - { 0x010300, "IPI bus controller" }, - { 0x010400, "RAID controller" }, - { 0x010520, "ATA controller, single stepping" }, - { 0x010530, "ATA controller, continuous" }, - { 0x010600, "Serial ATA controller - vendor specific interface" }, - { 0x010601, "Serial ATA controller - AHCI 1.0 interface" }, - { 0x010700, "Serial Attached SCSI controller" }, - { 0x018000, "Mass Storage controller" }, - - { 0x020000, "Ethernet controller" }, - { 0x020100, "Token Ring controller" }, - { 0x020200, "FDDI controller" }, - { 0x020300, "ATM controller" }, - { 0x020400, "ISDN controller" }, - { 0x020500, "WorldFip controller" }, - // { 0x0206xx , "PICMG 2.14 Multi Computing" }, - { 0x028000, "Network controller" }, - - { 0x030000, "VGA Display controller" }, - { 0x030001, "8514-compatible Display controller" }, - { 0x030100, "XGA Display controller" }, - { 0x030200, "3D Display controller" }, - { 0x038000, "Display controller" }, - - { 0x040000, "Video device" }, - { 0x040100, "Audio device" }, - { 0x040200, "Computer Telephony device" }, - { 0x048000, "Multimedia device" }, - - { 0x050000, "RAM memory controller" }, - { 0x050100, "Flash memory controller" }, - { 0x058000, "Memory controller" }, - - { 0x060000, "Host bridge" }, - { 0x060100, "ISA bridge" }, - { 0x060200, "EISA bridge" }, - { 0x060300, "MCA bridge" }, - { 0x060400, "PCI-to-PCI bridge" }, - { 0x060401, "PCI-to-PCI bridge (subtractive decoding)" }, - { 0x060500, "PCMCIA bridge" }, - { 0x060600, "NuBus bridge" }, - { 0x060700, "CardBus bridge" }, - // { 0x0608xx , "RACEway bridge" }, - { 0x060940, "PCI-to-PCI bridge, Semi-transparent, primary facing Host" }, - { 0x060980, "PCI-to-PCI bridge, Semi-transparent, secondary facing Host" }, - { 0x060A00, "InfiniBand-to-PCI host bridge" }, - { 0x068000, "Bridge device" }, - - { 0x070000, "Generic XT-compatible serial controller" }, - { 0x070001, "16450-compatible serial controller" }, - { 0x070002, "16550-compatible serial controller" }, - { 0x070003, "16650-compatible serial controller" }, - { 0x070004, "16750-compatible serial controller" }, - { 0x070005, "16850-compatible serial controller" }, - { 0x070006, "16950-compatible serial controller" }, - - { 0x070100, "Parallel port" }, - { 0x070101, "Bi-directional parallel port" }, - { 0x070102, "ECP 1.X compliant parallel port" }, - { 0x070103, "IEEE1284 controller" }, - { 0x0701FE, "IEEE1284 target device" }, - { 0x070200, "Multiport serial controller" }, - - { 0x070300, "Generic modem" }, - { 0x070301, "Hayes 16450-compatible modem" }, - { 0x070302, "Hayes 16550-compatible modem" }, - { 0x070303, "Hayes 16650-compatible modem" }, - { 0x070304, "Hayes 16750-compatible modem" }, - { 0x070400, "GPIB (IEEE 488.1/2) controller" }, - { 0x070500, "Smart Card" }, - { 0x078000, "Communications device" }, - - { 0x080000, "Generic 8259 PIC" }, - { 0x080001, "ISA PIC" }, - { 0x080002, "EISA PIC" }, - { 0x080010, "I/O APIC interrupt controller" }, - { 0x080020, "I/O(x) APIC interrupt controller" }, - - { 0x080100, "Generic 8237 DMA controller" }, - { 0x080101, "ISA DMA controller" }, - { 0x080102, "EISA DMA controller" }, - - { 0x080200, "Generic 8254 system timer" }, - { 0x080201, "ISA system timer" }, - { 0x080202, "EISA system timer-pair" }, - - { 0x080300, "Generic RTC controller" }, - { 0x080301, "ISA RTC controller" }, - - { 0x080400, "Generic PCI Hot-Plug controller" }, - { 0x080500, "SD Host controller" }, - { 0x088000, "System peripheral" }, - - { 0x090000, "Keyboard controller" }, - { 0x090100, "Digitizer (pen)" }, - { 0x090200, "Mouse controller" }, - { 0x090300, "Scanner controller" }, - { 0x090400, "Generic Gameport controller" }, - { 0x090410, "Legacy Gameport controller" }, - { 0x098000, "Input controller" }, - - { 0x0a0000, "Generic docking station" }, - { 0x0a8000, "Docking station" }, - - { 0x0b0000, "386 Processor" }, - { 0x0b0100, "486 Processor" }, - { 0x0b0200, "Pentium Processor" }, - { 0x0b1000, "Alpha Processor" }, - { 0x0b2000, "PowerPC Processor" }, - { 0x0b3000, "MIPS Processor" }, - { 0x0b4000, "Co-processor" }, - - { 0x0c0000, "IEEE 1394 (FireWire)" }, - { 0x0c0010, "IEEE 1394 -- OpenHCI spec" }, - { 0x0c0100, "ACCESS.bus" }, - { 0x0c0200, "SSA" }, - { 0x0c0300, "Universal Serial Bus (UHC spec)" }, - { 0x0c0310, "Universal Serial Bus (Open Host spec)" }, - { 0x0c0320, "USB2 Host controller (Intel Enhanced HCI spec)" }, - { 0x0c0380, "Universal Serial Bus (no PI spec)" }, - { 0x0c03FE, "USB Target Device" }, - { 0x0c0400, "Fibre Channel" }, - { 0x0c0500, "System Management Bus" }, - { 0x0c0600, "InfiniBand" }, - { 0x0c0700, "IPMI SMIC Interface" }, - { 0x0c0701, "IPMI Kybd Controller Style Interface" }, - { 0x0c0702, "IPMI Block Transfer Interface" }, - // { 0x0c08xx , "SERCOS Interface" }, - { 0x0c0900, "CANbus" }, - - { 0x0d100, "iRDA compatible controller" }, - { 0x0d100, "Consumer IR controller" }, - { 0x0d100, "RF controller" }, - { 0x0d100, "Bluetooth controller" }, - { 0x0d100, "Broadband controller" }, - { 0x0d100, "Ethernet (802.11a 5 GHz) controller" }, - { 0x0d100, "Ethernet (802.11b 2.4 GHz) controller" }, - { 0x0d100, "Wireless controller" }, - - // { 0x0e00xx , "I2O Intelligent I/O, spec 1.0" }, - { 0x0e0000, "Message FIFO at offset 040h" }, - - { 0x0f0100, "TV satellite comm. controller" }, - { 0x0f0200, "Audio satellite comm. controller" }, - { 0x0f0300, "Voice satellite comm. controller" }, - { 0x0f0400, "Data satellite comm. controller" }, - - { 0x100000, "Network and computing en/decryption" }, - { 0x101000, "Entertainment en/decryption" }, - { 0x108000, "En/Decryption" }, - - { 0x110000, "DPIO modules" }, - { 0x110100, "Perf. counters" }, - { 0x111000, "Comm. synch., time and freq. test" }, - { 0x112000, "Management card" }, - { 0x118000, "Data acq./Signal proc." }, -}; - -const char *pci_vendor_lookup(unsigned short vendor_id) -{ - for (int i = 0; i < sizeof(_pci_vendors) / sizeof(_pci_vendors[0]); ++i) { - if (_pci_vendors[i].id == vendor_id) { - return _pci_vendors[i].name; - } - } - - return "Unknown"; -} - -const char *pci_device_lookup(unsigned short vendor_id, - unsigned short device_id) -{ - for (int i = 0; i < sizeof(_pci_devices) / sizeof(_pci_devices[0]); ++i) { - if (_pci_devices[i].ven_id == vendor_id && - _pci_devices[i].dev_id == device_id) { - return _pci_devices[i].name; - } - } - - return "Unknown"; -} - -const char *pci_class_lookup(uint32_t class_code) -{ - for (int i = 0; i < sizeof(_pci_classes) / sizeof(_pci_classes[0]); ++i) { - if (_pci_classes[i].id == class_code) { - return _pci_classes[i].name; - } - } - - return "Unknown"; -} - -void pci_scan_hit(pci_func_t f, uint32_t dev, void *extra) -{ - uint16_t dev_vend = (uint16_t)pci_read_field(dev, PCI_VENDOR_ID, 2); - uint16_t dev_dvid = (uint16_t)pci_read_field(dev, PCI_DEVICE_ID, 2); - f(dev, dev_vend, dev_dvid, extra); -} - -void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, - void *extra) -{ - uint32_t dev = pci_box_device(bus, slot, func); - - if ((type == -1) || (type == pci_find_type(dev))) { - pci_scan_hit(f, dev, extra); - } - if (pci_find_type(dev) == PCI_TYPE_BRIDGE) { - pci_scan_bus(f, type, pci_read_field(dev, PCI_SECONDARY_BUS, 1), extra); - } -} - -void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void *extra) -{ - uint32_t dev = pci_box_device(bus, slot, 0); - - if (pci_read_field(dev, PCI_VENDOR_ID, 2) == PCI_NONE) { - return; - } - - pci_scan_func(f, type, bus, slot, 0, extra); - - if (!pci_read_field(dev, PCI_HEADER_TYPE, 1)) { - return; - } - - for (int func = 1; func < 8; func++) { - dev = pci_box_device(bus, slot, func); - - if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) { - pci_scan_func(f, type, bus, slot, func, extra); - } - } -} - -void pci_scan_bus(pci_func_t f, int type, int bus, void *extra) -{ - for (int slot = 0; slot < 32; ++slot) { - pci_scan_slot(f, type, bus, slot, extra); - } -} - -void pci_scan(pci_func_t f, int type, void *extra) -{ - if ((pci_read_field(0, PCI_HEADER_TYPE, 1) & 0x80) == 0) { - pci_scan_bus(f, type, 0, extra); - return; - } - - for (int func = 0; func < 8; ++func) { - uint32_t dev = pci_box_device(0, 0, func); - - if (pci_read_field(dev, PCI_VENDOR_ID, 2) == PCI_NONE) { - break; - } - pci_scan_bus(f, type, func, extra); - } -} - -static void find_isa_bridge(uint32_t device, uint16_t vendorid, - uint16_t deviceid, void *extra) -{ - if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) { - *((uint32_t *)extra) = device; - } -} - -static uint32_t pci_isa = 0; -static uint32_t pci_remaps[4] = { 0 }; - -void pci_remap() -{ - pci_scan(&find_isa_bridge, -1, &pci_isa); - - if (pci_isa) { - dbg_print("PCI-to-ISA interrupt mappings by line:\n"); - - for (int i = 0; i < 4; ++i) { - pci_remaps[i] = pci_read_field(pci_isa, 0x60 + i, 1); - dbg_print("\tLine %d: 0x%2x\n", i + 1, pci_remaps[i]); - } - - uint32_t out = 0; - memcpy(&out, &pci_remaps, 4); - pci_write_field(pci_isa, 0x60, 4, out); - } -} - -int pci_get_interrupt(uint32_t device) -{ - if (pci_isa == 0) { - return pci_read_field(device, PCI_INTERRUPT_LINE, 1); - } - - uint32_t irq_pin = pci_read_field(device, PCI_INTERRUPT_PIN, 1); - - if (irq_pin == 0) { - dbg_print("PCI device does not specific interrupt line\n"); - return pci_read_field(device, PCI_INTERRUPT_LINE, 1); - } - - int pirq = (irq_pin + pci_extract_slot(device) - 2) % 4; - - uint32_t int_line = pci_read_field(device, PCI_INTERRUPT_LINE, 1); - - dbg_print("Slot is %d, irq pin is %d, so pirq is %d and that maps to %d?" - "int_line=%d\n", - pci_extract_slot(device), irq_pin, pirq, pci_remaps[pirq], - int_line); - - if (pci_remaps[pirq] == 0x80) { - dbg_print("Not mapped, remapping?\n"); - pci_remaps[pirq] = int_line; - uint32_t out = 0; - memcpy(&out, &pci_remaps, 4); - pci_write_field(pci_isa, 0x60, 4, out); - return pci_read_field(device, PCI_INTERRUPT_LINE, 1); - } - - return pci_remaps[pirq]; -} - -static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, - void *extra) -{ - (void)device; - (void)vendorid; - (void)deviceid; - size_t *count = extra; - ++(*count); -} - -static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, - void *extra) -{ - (void)extra; - dbg_print("%2x:%2x.%d\n", pci_extract_bus(device), pci_extract_slot(device), - pci_extract_func(device), deviceid); - dbg_print(" Vendor : [0x%06x] %s\n", vendorid, - pci_vendor_lookup(vendorid)); - dbg_print(" Device : [0x%06x] %s\n", deviceid, - pci_device_lookup(vendorid, deviceid)); - dbg_print(" Type : [0x%06x] %s\n", pci_find_type(device), - pci_class_lookup(pci_find_type(device))); - dbg_print(" Status : 0x%4x\n", - pci_read_field(device, PCI_STATUS, 2)); - dbg_print(" Command : 0x%4x\n", - pci_read_field(device, PCI_COMMAND, 2)); - dbg_print(" Revision : %2d\n", - pci_read_field(device, PCI_REVISION_ID, 1)); - dbg_print(" Cache Line Size : %2d\n", - pci_read_field(device, PCI_CACHE_LINE_SIZE, 1)); - dbg_print(" Latency Timer : %2d\n", - pci_read_field(device, PCI_LATENCY_TIMER, 1)); - dbg_print(" Header Type : %2d\n", - pci_read_field(device, PCI_HEADER_TYPE, 1)); - dbg_print(" BIST : %2d\n", pci_read_field(device, PCI_BIST, 1)); - dbg_print(" BAR0 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_0, 4)); - dbg_print(" BAR1 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_1, 4)); - dbg_print(" BAR2 : 0x%08x\n", - pci_read_field(device, PCI_BASE_ADDRESS_2, 4)); - dbg_print(" BAR3 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_3, 4)); - dbg_print(" BAR4 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_4, 4)); - dbg_print(" BAR6 : 0x%08x\n", - pci_read_field(device, PCI_BASE_ADDRESS_5, 4)); - dbg_print(" Cardbus CIS : 0x%08x\n", - pci_read_field(device, PCI_CARDBUS_CIS, 4)); - dbg_print(" Subsystem V. ID : 0x%08x\n", - pci_read_field(device, PCI_SUBSYSTEM_VENDOR_ID, 2)); - dbg_print(" Subsystem ID : 0x%08x\n", - pci_read_field(device, PCI_SUBSYSTEM_ID, 2)); - dbg_print(" ROM Base Address: 0x%08x\n", - pci_read_field(device, PCI_ROM_ADDRESS, 4)); - dbg_print(" PCI Cp. LinkList: 0x%08x\n", - pci_read_field(device, PCI_CAPABILITY_LIST, 1)); - dbg_print(" Max Latency : 0x%08x\n", - pci_read_field(device, PCI_MAX_LAT, 1)); - dbg_print(" Min Grant : 0x%08x\n", - pci_read_field(device, PCI_MIN_GNT, 1)); - dbg_print(" Interrupt Pin : %2d\n", - pci_read_field(device, PCI_INTERRUPT_PIN, 1)); - dbg_print(" Interrupt Line : %2d\n", - pci_read_field(device, PCI_INTERRUPT_LINE, 1)); - dbg_print(" Interrupt Number: %2d\n", pci_get_interrupt(device)); - dbg_print("\n"); -} - -void pci_debug_scan() -{ - dbg_print("\n--------------------------------------------------\n"); - dbg_print("Counting PCI entities...\n"); - size_t count = 0; - pci_scan(&scan_count, -1, &count); - dbg_print("Total PCI entities: %d\n", count); - - dbg_print("Scanning PCI entities...\n"); - pci_scan(&scan_hit_list, -1, NULL); - - dbg_print("Mapping PCI entities...\n"); - pci_remap(); - - dbg_print("--------------------------------------------------\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file pci.c +/// @brief Routines for PCI initialization. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "pci.h" +#include "debug.h" +#include "stdio.h" +#include "kheap.h" +#include "string.h" +#include "port_io.h" + +void pci_write_field(uint32_t device, int field, int size, uint32_t value) +{ + (void)size; + outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); +#if 0 + if (size == 4) + outportl(PCI_VALUE_PORT, value); + else if (size == 2) + outports(PCI_VALUE_PORT, value); + else if (size == 1) + outportb(PCI_VALUE_PORT, value); +#else + outportl(PCI_VALUE_PORT, value); +#endif +} + +uint32_t pci_read_field(uint32_t device, int field, int size) +{ + outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); + + if (size == 4) { + return inportl(PCI_VALUE_PORT); + } else if (size == 2) { + return inports(PCI_VALUE_PORT + (field & 2)); + } else if (size == 1) { + return inportb(PCI_VALUE_PORT + (field & 3)); + } + return 0xFFFF; +} + +uint32_t pci_find_type(uint32_t device) +{ + return pci_read_field(device, PCI_CLASS, 1) << 16 | + pci_read_field(device, PCI_SUBCLASS, 1) << 8 | + pci_read_field(device, PCI_PROG_IF, 1); +} + +struct { + uint16_t id; + const char *name; +} _pci_vendors[] = { + { 0x1022, "AMD" }, { 0x106b, "Apple, Inc." }, + { 0x1234, "Bochs/QEMU" }, { 0x1274, "Ensoniq" }, + { 0x15ad, "VMWare" }, { 0x8086, "Intel Corporation" }, + { 0x80EE, "VirtualBox" }, +}; + +struct { + uint16_t ven_id; + uint16_t dev_id; + const char *name; +} _pci_devices[] = { + { 0x1022, 0x2000, "PCNet Ethernet Controller (pcnet)" }, + { 0x106b, 0x003f, "OHCI Controller" }, + { 0x1234, 0x1111, "VGA BIOS Graphics Extensions" }, + { 0x1274, 0x1371, "Creative Labs CT2518 (ensoniq audio)" }, + { 0x15ad, 0x0740, "VM Communication Interface" }, + { 0x15ad, 0x0405, "SVGA II Adapter" }, + { 0x15ad, 0x0790, "PCI bridge" }, + { 0x15ad, 0x07a0, "PCI Express Root Port" }, + { 0x8086, 0x100e, "Gigabit Ethernet Controller (e1000)" }, + { 0x8086, 0x100f, "Gigabit Ethernet Controller (e1000)" }, + { 0x8086, 0x1237, "PCI & Memory" }, + { 0x8086, 0x2415, "AC'97 Audio Chipset" }, + { 0x8086, 0x7000, "PCI-to-ISA Bridge" }, + { 0x8086, 0x7010, "IDE Interface" }, + { 0x8086, 0x7110, "PIIX4 ISA" }, + { 0x8086, 0x7111, "PIIX4 IDE" }, + { 0x8086, 0x7113, "Power Management Controller" }, + { 0x8086, 0x7190, "Host Bridge" }, + { 0x8086, 0x7191, "AGP Bridge" }, + { 0x80EE, 0xBEEF, "Bochs/QEMU-compatible Graphics Adapter" }, + { 0x80EE, 0xCAFE, "Guest Additions Device" }, +}; + +struct { + uint32_t id; + const char *name; +} _pci_classes[] = { + { 0x000000, "Legacy Device" }, + { 0x000100, "VGA-Compatible Device" }, + + { 0x010000, "SCSI bus controller" }, + { 0x010100, "ISA Compatibility mode-only controller" }, + { 0x010105, "PCI native mode-only controller" }, + { 0x01010a, "ISA Compatibility mode controller, supports both channels " + "switched to PCI native mode" }, + { 0x01010f, "PCI native mode controller, supports both channels switched " + "to ISA compatibility mode" }, + { 0x010180, + "ISA Compatibility mode-only controller, supports bus mastering" }, + { 0x010185, "PCI native mode-only controller, supports bus mastering" }, + { 0x01018a, "ISA Compatibility mode controller, supports both channels " + "switched to PCI native mode, supports bus mastering" }, + { 0x01018f, "PCI native mode controller, supports both channels switched " + "\to ISA compatibility mode, supports bus mastering" }, + + { 0x010200, "Floppy disk controller" }, + { 0x010300, "IPI bus controller" }, + { 0x010400, "RAID controller" }, + { 0x010520, "ATA controller, single stepping" }, + { 0x010530, "ATA controller, continuous" }, + { 0x010600, "Serial ATA controller - vendor specific interface" }, + { 0x010601, "Serial ATA controller - AHCI 1.0 interface" }, + { 0x010700, "Serial Attached SCSI controller" }, + { 0x018000, "Mass Storage controller" }, + + { 0x020000, "Ethernet controller" }, + { 0x020100, "Token Ring controller" }, + { 0x020200, "FDDI controller" }, + { 0x020300, "ATM controller" }, + { 0x020400, "ISDN controller" }, + { 0x020500, "WorldFip controller" }, + // { 0x0206xx , "PICMG 2.14 Multi Computing" }, + { 0x028000, "Network controller" }, + + { 0x030000, "VGA Display controller" }, + { 0x030001, "8514-compatible Display controller" }, + { 0x030100, "XGA Display controller" }, + { 0x030200, "3D Display controller" }, + { 0x038000, "Display controller" }, + + { 0x040000, "Video device" }, + { 0x040100, "Audio device" }, + { 0x040200, "Computer Telephony device" }, + { 0x048000, "Multimedia device" }, + + { 0x050000, "RAM memory controller" }, + { 0x050100, "Flash memory controller" }, + { 0x058000, "Memory controller" }, + + { 0x060000, "Host bridge" }, + { 0x060100, "ISA bridge" }, + { 0x060200, "EISA bridge" }, + { 0x060300, "MCA bridge" }, + { 0x060400, "PCI-to-PCI bridge" }, + { 0x060401, "PCI-to-PCI bridge (subtractive decoding)" }, + { 0x060500, "PCMCIA bridge" }, + { 0x060600, "NuBus bridge" }, + { 0x060700, "CardBus bridge" }, + // { 0x0608xx , "RACEway bridge" }, + { 0x060940, "PCI-to-PCI bridge, Semi-transparent, primary facing Host" }, + { 0x060980, "PCI-to-PCI bridge, Semi-transparent, secondary facing Host" }, + { 0x060A00, "InfiniBand-to-PCI host bridge" }, + { 0x068000, "Bridge device" }, + + { 0x070000, "Generic XT-compatible serial controller" }, + { 0x070001, "16450-compatible serial controller" }, + { 0x070002, "16550-compatible serial controller" }, + { 0x070003, "16650-compatible serial controller" }, + { 0x070004, "16750-compatible serial controller" }, + { 0x070005, "16850-compatible serial controller" }, + { 0x070006, "16950-compatible serial controller" }, + + { 0x070100, "Parallel port" }, + { 0x070101, "Bi-directional parallel port" }, + { 0x070102, "ECP 1.X compliant parallel port" }, + { 0x070103, "IEEE1284 controller" }, + { 0x0701FE, "IEEE1284 target device" }, + { 0x070200, "Multiport serial controller" }, + + { 0x070300, "Generic modem" }, + { 0x070301, "Hayes 16450-compatible modem" }, + { 0x070302, "Hayes 16550-compatible modem" }, + { 0x070303, "Hayes 16650-compatible modem" }, + { 0x070304, "Hayes 16750-compatible modem" }, + { 0x070400, "GPIB (IEEE 488.1/2) controller" }, + { 0x070500, "Smart Card" }, + { 0x078000, "Communications device" }, + + { 0x080000, "Generic 8259 PIC" }, + { 0x080001, "ISA PIC" }, + { 0x080002, "EISA PIC" }, + { 0x080010, "I/O APIC interrupt controller" }, + { 0x080020, "I/O(x) APIC interrupt controller" }, + + { 0x080100, "Generic 8237 DMA controller" }, + { 0x080101, "ISA DMA controller" }, + { 0x080102, "EISA DMA controller" }, + + { 0x080200, "Generic 8254 system timer" }, + { 0x080201, "ISA system timer" }, + { 0x080202, "EISA system timer-pair" }, + + { 0x080300, "Generic RTC controller" }, + { 0x080301, "ISA RTC controller" }, + + { 0x080400, "Generic PCI Hot-Plug controller" }, + { 0x080500, "SD Host controller" }, + { 0x088000, "System peripheral" }, + + { 0x090000, "Keyboard controller" }, + { 0x090100, "Digitizer (pen)" }, + { 0x090200, "Mouse controller" }, + { 0x090300, "Scanner controller" }, + { 0x090400, "Generic Gameport controller" }, + { 0x090410, "Legacy Gameport controller" }, + { 0x098000, "Input controller" }, + + { 0x0a0000, "Generic docking station" }, + { 0x0a8000, "Docking station" }, + + { 0x0b0000, "386 Processor" }, + { 0x0b0100, "486 Processor" }, + { 0x0b0200, "Pentium Processor" }, + { 0x0b1000, "Alpha Processor" }, + { 0x0b2000, "PowerPC Processor" }, + { 0x0b3000, "MIPS Processor" }, + { 0x0b4000, "Co-processor" }, + + { 0x0c0000, "IEEE 1394 (FireWire)" }, + { 0x0c0010, "IEEE 1394 -- OpenHCI spec" }, + { 0x0c0100, "ACCESS.bus" }, + { 0x0c0200, "SSA" }, + { 0x0c0300, "Universal Serial Bus (UHC spec)" }, + { 0x0c0310, "Universal Serial Bus (Open Host spec)" }, + { 0x0c0320, "USB2 Host controller (Intel Enhanced HCI spec)" }, + { 0x0c0380, "Universal Serial Bus (no PI spec)" }, + { 0x0c03FE, "USB Target Device" }, + { 0x0c0400, "Fibre Channel" }, + { 0x0c0500, "System Management Bus" }, + { 0x0c0600, "InfiniBand" }, + { 0x0c0700, "IPMI SMIC Interface" }, + { 0x0c0701, "IPMI Kybd Controller Style Interface" }, + { 0x0c0702, "IPMI Block Transfer Interface" }, + // { 0x0c08xx , "SERCOS Interface" }, + { 0x0c0900, "CANbus" }, + + { 0x0d100, "iRDA compatible controller" }, + { 0x0d100, "Consumer IR controller" }, + { 0x0d100, "RF controller" }, + { 0x0d100, "Bluetooth controller" }, + { 0x0d100, "Broadband controller" }, + { 0x0d100, "Ethernet (802.11a 5 GHz) controller" }, + { 0x0d100, "Ethernet (802.11b 2.4 GHz) controller" }, + { 0x0d100, "Wireless controller" }, + + // { 0x0e00xx , "I2O Intelligent I/O, spec 1.0" }, + { 0x0e0000, "Message FIFO at offset 040h" }, + + { 0x0f0100, "TV satellite comm. controller" }, + { 0x0f0200, "Audio satellite comm. controller" }, + { 0x0f0300, "Voice satellite comm. controller" }, + { 0x0f0400, "Data satellite comm. controller" }, + + { 0x100000, "Network and computing en/decryption" }, + { 0x101000, "Entertainment en/decryption" }, + { 0x108000, "En/Decryption" }, + + { 0x110000, "DPIO modules" }, + { 0x110100, "Perf. counters" }, + { 0x111000, "Comm. synch., time and freq. test" }, + { 0x112000, "Management card" }, + { 0x118000, "Data acq./Signal proc." }, +}; + +const char *pci_vendor_lookup(unsigned short vendor_id) +{ + for (int i = 0; i < sizeof(_pci_vendors) / sizeof(_pci_vendors[0]); ++i) { + if (_pci_vendors[i].id == vendor_id) { + return _pci_vendors[i].name; + } + } + + return "Unknown"; +} + +const char *pci_device_lookup(unsigned short vendor_id, + unsigned short device_id) +{ + for (int i = 0; i < sizeof(_pci_devices) / sizeof(_pci_devices[0]); ++i) { + if (_pci_devices[i].ven_id == vendor_id && + _pci_devices[i].dev_id == device_id) { + return _pci_devices[i].name; + } + } + + return "Unknown"; +} + +const char *pci_class_lookup(uint32_t class_code) +{ + for (int i = 0; i < sizeof(_pci_classes) / sizeof(_pci_classes[0]); ++i) { + if (_pci_classes[i].id == class_code) { + return _pci_classes[i].name; + } + } + + return "Unknown"; +} + +void pci_scan_hit(pci_func_t f, uint32_t dev, void *extra) +{ + uint16_t dev_vend = (uint16_t)pci_read_field(dev, PCI_VENDOR_ID, 2); + uint16_t dev_dvid = (uint16_t)pci_read_field(dev, PCI_DEVICE_ID, 2); + f(dev, dev_vend, dev_dvid, extra); +} + +void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, + void *extra) +{ + uint32_t dev = pci_box_device(bus, slot, func); + + if ((type == -1) || (type == pci_find_type(dev))) { + pci_scan_hit(f, dev, extra); + } + if (pci_find_type(dev) == PCI_TYPE_BRIDGE) { + pci_scan_bus(f, type, pci_read_field(dev, PCI_SECONDARY_BUS, 1), extra); + } +} + +void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void *extra) +{ + uint32_t dev = pci_box_device(bus, slot, 0); + + if (pci_read_field(dev, PCI_VENDOR_ID, 2) == PCI_NONE) { + return; + } + + pci_scan_func(f, type, bus, slot, 0, extra); + + if (!pci_read_field(dev, PCI_HEADER_TYPE, 1)) { + return; + } + + for (int func = 1; func < 8; func++) { + dev = pci_box_device(bus, slot, func); + + if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) { + pci_scan_func(f, type, bus, slot, func, extra); + } + } +} + +void pci_scan_bus(pci_func_t f, int type, int bus, void *extra) +{ + for (int slot = 0; slot < 32; ++slot) { + pci_scan_slot(f, type, bus, slot, extra); + } +} + +void pci_scan(pci_func_t f, int type, void *extra) +{ + if ((pci_read_field(0, PCI_HEADER_TYPE, 1) & 0x80) == 0) { + pci_scan_bus(f, type, 0, extra); + return; + } + + for (int func = 0; func < 8; ++func) { + uint32_t dev = pci_box_device(0, 0, func); + + if (pci_read_field(dev, PCI_VENDOR_ID, 2) == PCI_NONE) { + break; + } + pci_scan_bus(f, type, func, extra); + } +} + +static void find_isa_bridge(uint32_t device, uint16_t vendorid, + uint16_t deviceid, void *extra) +{ + if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) { + *((uint32_t *)extra) = device; + } +} + +static uint32_t pci_isa = 0; +static uint32_t pci_remaps[4] = { 0 }; + +void pci_remap() +{ + pci_scan(&find_isa_bridge, -1, &pci_isa); + + if (pci_isa) { + dbg_print("PCI-to-ISA interrupt mappings by line:\n"); + + for (int i = 0; i < 4; ++i) { + pci_remaps[i] = pci_read_field(pci_isa, 0x60 + i, 1); + dbg_print("\tLine %d: 0x%2x\n", i + 1, pci_remaps[i]); + } + + uint32_t out = 0; + memcpy(&out, &pci_remaps, 4); + pci_write_field(pci_isa, 0x60, 4, out); + } +} + +int pci_get_interrupt(uint32_t device) +{ + if (pci_isa == 0) { + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } + + uint32_t irq_pin = pci_read_field(device, PCI_INTERRUPT_PIN, 1); + + if (irq_pin == 0) { + dbg_print("PCI device does not specific interrupt line\n"); + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } + + int pirq = (irq_pin + pci_extract_slot(device) - 2) % 4; + + uint32_t int_line = pci_read_field(device, PCI_INTERRUPT_LINE, 1); + + dbg_print("Slot is %d, irq pin is %d, so pirq is %d and that maps to %d?" + "int_line=%d\n", + pci_extract_slot(device), irq_pin, pirq, pci_remaps[pirq], + int_line); + + if (pci_remaps[pirq] == 0x80) { + dbg_print("Not mapped, remapping?\n"); + pci_remaps[pirq] = int_line; + uint32_t out = 0; + memcpy(&out, &pci_remaps, 4); + pci_write_field(pci_isa, 0x60, 4, out); + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); + } + + return pci_remaps[pirq]; +} + +static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, + void *extra) +{ + (void)device; + (void)vendorid; + (void)deviceid; + size_t *count = extra; + ++(*count); +} + +static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, + void *extra) +{ + (void)extra; + dbg_print("%2x:%2x.%d\n", pci_extract_bus(device), pci_extract_slot(device), + pci_extract_func(device), deviceid); + dbg_print(" Vendor : [0x%06x] %s\n", vendorid, + pci_vendor_lookup(vendorid)); + dbg_print(" Device : [0x%06x] %s\n", deviceid, + pci_device_lookup(vendorid, deviceid)); + dbg_print(" Type : [0x%06x] %s\n", pci_find_type(device), + pci_class_lookup(pci_find_type(device))); + dbg_print(" Status : 0x%4x\n", + pci_read_field(device, PCI_STATUS, 2)); + dbg_print(" Command : 0x%4x\n", + pci_read_field(device, PCI_COMMAND, 2)); + dbg_print(" Revision : %2d\n", + pci_read_field(device, PCI_REVISION_ID, 1)); + dbg_print(" Cache Line Size : %2d\n", + pci_read_field(device, PCI_CACHE_LINE_SIZE, 1)); + dbg_print(" Latency Timer : %2d\n", + pci_read_field(device, PCI_LATENCY_TIMER, 1)); + dbg_print(" Header Type : %2d\n", + pci_read_field(device, PCI_HEADER_TYPE, 1)); + dbg_print(" BIST : %2d\n", pci_read_field(device, PCI_BIST, 1)); + dbg_print(" BAR0 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_0, 4)); + dbg_print(" BAR1 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_1, 4)); + dbg_print(" BAR2 : 0x%08x\n", + pci_read_field(device, PCI_BASE_ADDRESS_2, 4)); + dbg_print(" BAR3 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_3, 4)); + dbg_print(" BAR4 : 0x%08x", pci_read_field(device, PCI_BASE_ADDRESS_4, 4)); + dbg_print(" BAR6 : 0x%08x\n", + pci_read_field(device, PCI_BASE_ADDRESS_5, 4)); + dbg_print(" Cardbus CIS : 0x%08x\n", + pci_read_field(device, PCI_CARDBUS_CIS, 4)); + dbg_print(" Subsystem V. ID : 0x%08x\n", + pci_read_field(device, PCI_SUBSYSTEM_VENDOR_ID, 2)); + dbg_print(" Subsystem ID : 0x%08x\n", + pci_read_field(device, PCI_SUBSYSTEM_ID, 2)); + dbg_print(" ROM Base Address: 0x%08x\n", + pci_read_field(device, PCI_ROM_ADDRESS, 4)); + dbg_print(" PCI Cp. LinkList: 0x%08x\n", + pci_read_field(device, PCI_CAPABILITY_LIST, 1)); + dbg_print(" Max Latency : 0x%08x\n", + pci_read_field(device, PCI_MAX_LAT, 1)); + dbg_print(" Min Grant : 0x%08x\n", + pci_read_field(device, PCI_MIN_GNT, 1)); + dbg_print(" Interrupt Pin : %2d\n", + pci_read_field(device, PCI_INTERRUPT_PIN, 1)); + dbg_print(" Interrupt Line : %2d\n", + pci_read_field(device, PCI_INTERRUPT_LINE, 1)); + dbg_print(" Interrupt Number: %2d\n", pci_get_interrupt(device)); + dbg_print("\n"); +} + +void pci_debug_scan() +{ + dbg_print("\n--------------------------------------------------\n"); + dbg_print("Counting PCI entities...\n"); + size_t count = 0; + pci_scan(&scan_count, -1, &count); + dbg_print("Total PCI entities: %d\n", count); + + dbg_print("Scanning PCI entities...\n"); + pci_scan(&scan_hit_list, -1, NULL); + + dbg_print("Mapping PCI entities...\n"); + pci_remap(); + + dbg_print("--------------------------------------------------\n"); +} diff --git a/mentos/src/drivers/ata.c b/mentos/src/drivers/ata.c index f59a706..4ac0b46 100644 --- a/mentos/src/drivers/ata.c +++ b/mentos/src/drivers/ata.c @@ -1,1009 +1,1009 @@ -/// MentOS, The Mentoring Operating system project -/// @file ata.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "ata.h" -#include "isr.h" -#include "vfs.h" -#include "pci.h" -#include "list.h" -#include "debug.h" -#include "stdio.h" -#include "kheap.h" -#include "assert.h" -#include "string.h" -#include "kernel.h" -#include "pic8259.h" -#include "spinlock.h" - -// #define COMPLETE_VFS -// #define COMPLETE_SCHEDULER - -uint32_t ata_pci = 0x00000000; - -list_t *atapi_waiter; - -bool_t atapi_in_progress = false; - -typedef union { - uint8_t command_bytes[12]; - uint16_t command_words[6]; -} atapi_command_t; - -typedef struct { - uintptr_t offset; - uint16_t bytes; - uint16_t last; -} prdt_t; - -typedef struct { - char name[256]; - int io_base; - int control; - int slave; - bool_t is_atapi; - ata_identify_t identity; - prdt_t *dma_prdt; - uintptr_t dma_prdt_phys; - uint8_t *dma_start; - uintptr_t dma_start_phys; - uint32_t bar4; - uint32_t atapi_lba; - uint32_t atapi_sector_size; -} ata_device_t; - -ata_device_t ata_primary_master = { .io_base = 0x1F0, - .control = 0x3F6, - .slave = 0 }; -ata_device_t ata_primary_slave = { .io_base = 0x1F0, - .control = 0x3F6, - .slave = 1 }; -ata_device_t ata_secondary_master = { .io_base = 0x170, - .control = 0x376, - .slave = 0 }; -ata_device_t ata_secondary_slave = { .io_base = 0x170, - .control = 0x376, - .slave = 1 }; - -// volatile uint8_t ata_lock = 0; -spinlock_t ata_lock = { 0 }; - -// TODO: support other sector sizes. -#define ATA_SECTOR_SIZE 512 - -/// @brief Waits for the -/// @param dev -void ata_io_wait(ata_device_t *dev) -{ - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); -} - -uint8_t ata_status_wait(ata_device_t *dev, int timeout) -{ - uint8_t status; - if (timeout > 0) { - for (int i = 0; (status = inportb(dev->io_base + ATA_REG_STATUS)) & - ATA_STAT_BUSY && - (i < timeout); - ++i) - ; - } else { - while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & - ATA_STAT_BUSY) - ; - } - - return status; -} - -int ata_wait(ata_device_t *dev, bool_t advanced) -{ - ata_io_wait(dev); - uint8_t status = ata_status_wait(dev, 0); - if (advanced) { - status = inportb(dev->io_base + ATA_REG_STATUS); - if (status & ATA_STAT_ERR) - return 1; - if (status & ATA_STAT_FAULT) - return 1; - if (!(status & ATA_STAT_DRQ)) - return 1; - } - - return 0; -} - -void ata_device_select(ata_device_t *dev) -{ - outportb(dev->io_base + 1, 1); - outportb(dev->control, 0); - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); -} - -void ata_device_read_sector(ata_device_t *dev, uint32_t lba, uint8_t *buf); - -void ata_device_read_sector_atapi(ata_device_t *dev, uint32_t lba, - uint8_t *buf); - -void ata_device_write_sector_retry(ata_device_t *dev, uint32_t lba, - uint8_t *buf); - -#ifdef COMPLETE_VFS -uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, - uint8_t *buffer); -uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, - uint8_t *buffer); -void open_ata(fs_node_t *node, unsigned int flags); -void close_ata(fs_node_t *node); -#endif - -uint64_t ata_max_offset(ata_device_t *dev) -{ - uint64_t sectors = dev->identity.sectors_48; - if (!sectors) { - // Fall back to sectors_28. - sectors = dev->identity.sectors_28; - } - - return sectors * ATA_SECTOR_SIZE; -} - -uint64_t atapi_max_offset(ata_device_t *dev) -{ - uint64_t max_sector = dev->atapi_lba; - - if (!max_sector) { - return 0; - } - - return (max_sector + 1) * dev->atapi_sector_size; -} - -#ifdef COMPLETE_VFS -uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, - uint8_t *buffer) -{ - ata_device_t *dev = (ata_device_t *)node->device; - - unsigned int start_block = offset / ATA_SECTOR_SIZE; - unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; - - unsigned int x_offset = 0; - - if (offset > ata_max_offset(dev)) { - return 0; - } - - if (offset + size > ata_max_offset(dev)) { - unsigned int i = ata_max_offset(dev) - offset; - size = i; - } - - if (offset % ATA_SECTOR_SIZE) { - unsigned int prefix_size = - (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); - char *tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, start_block, (uint8_t *)tmp); - - memcpy(buffer, (void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), - prefix_size); - - free(tmp); - - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { - unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; - char *tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, end_block, (uint8_t *)tmp); - - memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, - postfix_size); - - free(tmp); - - end_block--; - } - - while (start_block <= end_block) { - ata_device_read_sector(dev, start_block, - (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += ATA_SECTOR_SIZE; - start_block++; - } - - return size; -} -#endif - -#ifdef COMPLETE_VFS -uint32_t read_atapi(fs_node_t *node, uint32_t offset, uint32_t size, - uint8_t *buffer) -{ - ata_device_t *dev = (ata_device_t *)node->device; - - unsigned int start_block = offset / dev->atapi_sector_size; - unsigned int end_block = (offset + size - 1) / dev->atapi_sector_size; - - unsigned int x_offset = 0; - - if (offset > atapi_max_offset(dev)) { - return 0; - } - - if (offset + size > atapi_max_offset(dev)) { - unsigned int i = atapi_max_offset(dev) - offset; - size = i; - } - - if (offset % dev->atapi_sector_size) { - unsigned int prefix_size = - (dev->atapi_sector_size - (offset % dev->atapi_sector_size)); - char *tmp = malloc(dev->atapi_sector_size); - ata_device_read_sector_atapi(dev, start_block, (uint8_t *)tmp); - - memcpy(buffer, - (void *)((uintptr_t)tmp + (offset % dev->atapi_sector_size)), - prefix_size); - - free(tmp); - - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % dev->atapi_sector_size && start_block <= end_block) { - unsigned int postfix_size = (offset + size) % dev->atapi_sector_size; - char *tmp = malloc(dev->atapi_sector_size); - ata_device_read_sector_atapi(dev, end_block, (uint8_t *)tmp); - - memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, - postfix_size); - - free(tmp); - - end_block--; - } - - while (start_block <= end_block) { - ata_device_read_sector_atapi(dev, start_block, - (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += dev->atapi_sector_size; - start_block++; - } - - return size; -} -#endif - -#ifdef COMPLETE_VFS -uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, - uint8_t *buffer) -{ - ata_device_t *dev = (ata_device_t *)node->device; - - unsigned int start_block = offset / ATA_SECTOR_SIZE; - unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; - - unsigned int x_offset = 0; - - if (offset > ata_max_offset(dev)) { - return 0; - } - - if (offset + size > ata_max_offset(dev)) { - unsigned int i = ata_max_offset(dev) - offset; - size = i; - } - - if (offset % ATA_SECTOR_SIZE) { - unsigned int prefix_size = - (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); - - char *tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, start_block, (uint8_t *)tmp); - - dbg_print("Writing first block"); - - memcpy((void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), buffer, - prefix_size); - ata_device_write_sector_retry(dev, start_block, (uint8_t *)tmp); - - free(tmp); - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { - unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; - - char *tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, end_block, (uint8_t *)tmp); - - dbg_print("Writing last block"); - - memcpy(tmp, (void *)((uintptr_t)buffer + size - postfix_size), - postfix_size); - - ata_device_write_sector_retry(dev, end_block, (uint8_t *)tmp); - - free(tmp); - end_block--; - } - - while (start_block <= end_block) { - ata_device_write_sector_retry( - dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += ATA_SECTOR_SIZE; - start_block++; - } - - return size; -} -#endif - -#ifdef COMPLETE_VFS -void open_ata(fs_node_t *node, unsigned int flags) -{ - return; -} -#endif - -#ifdef COMPLETE_VFS -void close_ata(fs_node_t *node) -{ - return; -} -#endif - -#ifdef COMPLETE_VFS -fs_node_t *atapi_device_create(ata_device_t *device) -{ - fs_node_t *fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - sprintf(fnode->name, "cdrom%d", cdrom_number); - fnode->device = device; - fnode->uid = 0; - fnode->gid = 0; - fnode->mask = 0660; - fnode->length = atapi_max_offset(device); - fnode->flags = FS_BLOCKDEVICE; - fnode->read = read_atapi; - // No write support. - fnode->write = NULL; - fnode->open = open_ata; - fnode->close = close_ata; - fnode->readdir = NULL; - fnode->finddir = NULL; - // TODO, identify: etc? - fnode->ioctl = NULL; - return fnode; -} -#endif - -#ifdef COMPLETE_VFS -fs_node_t *ata_device_create(ata_device_t *device) -{ - fs_node_t *fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - sprintf(fnode->name, "atadev%d", ata_drive_char - 'a'); - fnode->device = device; - fnode->uid = 0; - fnode->gid = 0; - fnode->mask = 0660; - // TODO - fnode->length = ata_max_offset(device); - fnode->flags = FS_BLOCKDEVICE; - fnode->read = read_ata; - fnode->write = write_ata; - fnode->open = open_ata; - fnode->close = close_ata; - fnode->readdir = NULL; - fnode->finddir = NULL; - // TODO: identify, etc? - fnode->ioctl = NULL; - return fnode; -} -#endif - -void ata_soft_reset(ata_device_t *dev) -{ - outportb(dev->control, 0x04); - ata_io_wait(dev); - outportb(dev->control, 0x00); -} - -void ata_irq_handler(pt_regs *r) -{ - inportb(ata_primary_master.io_base + ATA_REG_STATUS); - - if (atapi_in_progress) { - // wakeup_queue(atapi_waiter); - } - - // irq_ack(14); - pic8259_send_eoi(14); -} - -void ata_irq_handler_s(pt_regs *r) -{ - inportb(ata_secondary_master.io_base + ATA_REG_STATUS); - - if (atapi_in_progress) { - // wakeup_queue(atapi_waiter); - } - - // irq_ack(15); - pic8259_send_eoi(15); -} - -bool_t ata_device_init(ata_device_t *dev) -{ - dbg_print("Detected IDE device on bus 0x%3x\n", dev->io_base); - dbg_print("Device name: %s\n", dev->name); - ata_device_select(dev); - outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENT); - ata_io_wait(dev); - uint8_t status = inportb(dev->io_base + ATA_REG_COMMAND); - dbg_print("Device status: %d\n", status); - - ata_wait(dev, false); - - uint16_t *buf = (uint16_t *)&dev->identity; - for (int i = 0; i < 256; ++i) { - buf[i] = inports(dev->io_base); - } - - uint8_t *ptr = (uint8_t *)&dev->identity.model; - for (int i = 0; i < 39; i += 2) { - char tmp = ptr[i + 1]; - ptr[i + 1] = ptr[i]; - ptr[i] = tmp; - } - ptr[39] = 0; - - dbg_print("Device Model: %s\n", dev->identity.model); - dbg_print("Sectors (48): %d\n", (uint32_t)dev->identity.sectors_48); - dbg_print("Sectors (24): %d\n", dev->identity.sectors_28); - - dbg_print("Setting up DMA...\n"); - // TODO: Ale. - // dev->dma_prdt = kmalloc_p(sizeof(prdt_t) * 1, &dev->dma_prdt_phys); - // dev->dma_start = kmalloc_p(4096, &dev->dma_start_phys); - - dbg_print("Putting prdt at 0x%x (0x%x phys)\n", dev->dma_prdt, - dev->dma_prdt_phys); - dbg_print("Putting prdt[0] at 0x%x (0x%x phys)\n", dev->dma_start, - dev->dma_start_phys); - - dev->dma_prdt[0].offset = dev->dma_start_phys; - dev->dma_prdt[0].bytes = 512; - dev->dma_prdt[0].last = 0x8000; - - dbg_print("ATA PCI device ID: 0x%x\n", ata_pci); - - uint16_t command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); - dbg_print("COMMAND register before: 0x%4x\n", command_reg); - if (command_reg & (1U << 2U)) { - dbg_print("Bus mastering already enabled.\n"); - } else { - // bit 2. - command_reg |= (1U << 2U); - dbg_print("Enabling bus mastering...\n"); - pci_write_field(ata_pci, PCI_COMMAND, 4, command_reg); - command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); - dbg_print("COMMAND register after: 0x%4x\n", command_reg); - } - - dev->bar4 = pci_read_field(ata_pci, PCI_BASE_ADDRESS_4, 4); - dbg_print("BAR4: 0x%x\n", dev->bar4); - - if (dev->bar4 & 0x00000001U) { - dev->bar4 = dev->bar4 & 0xFFFFFFFC; - } else { - dbg_print("? ATA bus master registers are 'usually' I/O ports.\n"); - - // No DMA because we're not sure what to do here- - return false; - } -#if 0 - pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 0xFE); - if (pci_read_field(ata_pci, PCI_INTERRUPT_LINE, 1) == 0xFE) - { - // Needs assignment. - pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 14); - } -#endif - - return true; -} - -int atapi_device_init(ata_device_t *dev) -{ - dbg_print("Detected ATAPI device at io-base 0x%3x, ctrl 0x%3x, slave %d\n", - dev->io_base, dev->control, dev->slave); - dbg_print("Device name: %s\n", dev->name); - ata_device_select(dev); - outportb(dev->io_base + ATA_REG_COMMAND, ATAPI_CMD_ID_PCKT); - ata_io_wait(dev); - uint8_t status = inportb(dev->io_base + ATA_REG_COMMAND); - dbg_print("Device status: %d\n", status); - - ata_wait(dev, false); - - uint16_t *buf = (uint16_t *)&dev->identity; - - for (int i = 0; i < 256; ++i) { - buf[i] = inports(dev->io_base); - } - - uint8_t *ptr = (uint8_t *)&dev->identity.model; - for (int i = 0; i < 39; i += 2) { - char tmp = ptr[i + 1]; - ptr[i + 1] = ptr[i]; - ptr[i] = tmp; - } - ptr[39] = 0; - - dbg_print("Device Model: %s\n", dev->identity.model); - - // Detect medium. - atapi_command_t command; - command.command_bytes[0] = 0x25; - command.command_bytes[1] = 0; - command.command_bytes[2] = 0; - command.command_bytes[3] = 0; - command.command_bytes[4] = 0; - command.command_bytes[5] = 0; - command.command_bytes[6] = 0; - command.command_bytes[7] = 0; - // Bit 0 = PMI (0, last sector). - command.command_bytes[8] = 0; - // Control. - command.command_bytes[9] = 0; - command.command_bytes[10] = 0; - command.command_bytes[11] = 0; - - uint16_t bus = dev->io_base; - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_LBA1, 0x08); - outportb(bus + ATA_REG_LBA2, 0x08); - outportb(bus + ATA_REG_COMMAND, ATAPI_CMD_PACKET); - - // Poll. - while (1) { - status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_STAT_ERR)) { - goto atapi_error; - } - if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { - break; - } - } - - for (int i = 0; i < 6; ++i) - outports(bus, command.command_words[i]); - - // Poll. - while (1) { - status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_STAT_ERR)) { - goto atapi_error_read; - } - if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { - break; - } - if ((status & ATA_STAT_DRQ)) { - break; - } - } - - uint16_t data[4]; - - for (int i = 0; i < 4; ++i) { - data[i] = inports(bus); - } - -#define htonl(l) \ - ((((l)&0xFF) << 24) | (((l)&0xFF00) << 8) | (((l)&0xFF0000) >> 8) | \ - (((l)&0xFF000000) >> 24)) - uint32_t lba, blocks; - ; - - memcpy(&lba, &data[0], sizeof(uint32_t)); - - lba = htonl(lba); - - memcpy(&blocks, &data[2], sizeof(uint32_t)); - - blocks = htonl(blocks); - - dev->atapi_lba = lba; - dev->atapi_sector_size = blocks; - - if (!lba) { - return false; - } - - dbg_print("Finished! LBA = %x; block length = %x\n", lba, blocks); - return true; - -atapi_error_read: - dbg_print("ATAPI error; no medium?\n"); - return false; - -atapi_error: - dbg_print("ATAPI early error; unsure\n"); - return false; -} - -int ata_device_detect(ata_device_t *dev) -{ - static char ata_drive_char = 'a'; - static int cdrom_number = 0; - - ata_soft_reset(dev); - ata_io_wait(dev); - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - ata_status_wait(dev, 10000); - - dbg_print("Probing cylinder registers...\n"); - uint8_t cl = inportb(dev->io_base + ATA_REG_LBA1); - uint8_t ch = inportb(dev->io_base + ATA_REG_LBA2); - if ((cl == 0xFF) && (ch == 0xFF)) { - dbg_print("No drive(s) present\n"); - return false; - } - - dbg_print("Waiting while busy...\n"); - uint8_t status = ata_status_wait(dev, 5000); - if (status & ATA_STAT_BUSY) { - dbg_print("No drive(s) present\n"); - - return false; - } - - dbg_print("Device detected: 0x%2x 0x%2x\n", cl, ch); - if ((cl == 0x00 && ch == 0x00) || (cl == 0x3C && ch == 0xC3)) { - // The device is not an ATAPI. - dev->is_atapi = false; - // Parallel ATA device, or emulated SATA - sprintf(dev->name, "/dev/hd%c", ata_drive_char); - -#ifdef COMPLETE_VFS - fs_node_t *node = ata_device_create(dev); - vfs_mount(devname, node); -#endif - - ++ata_drive_char; - if (!ata_device_init(dev)) { - return 0; - } - - return 1; - } else if ((cl == 0x14 && ch == 0xEB) || (cl == 0x69 && ch == 0x96)) { - // The device is an ATAPI. - dev->is_atapi = true; - sprintf(dev->name, "/dev/cdrom%d", cdrom_number); - -#ifdef COMPLETE_VFS - fs_node_t *node = atapi_device_create(dev); - vfs_mount(devname, node); -#endif - - ++cdrom_number; - if (!atapi_device_init(dev)) { - return 0; - } - return 2; - } - dbg_print("\n"); - - // TODO: ATAPI, SATA, SATAPI. - - return 0; -} - -void ata_device_read_sector(ata_device_t *dev, uint32_t lba, uint8_t *buf) -{ - uint16_t bus = dev->io_base; - - uint8_t slave = dev->slave; - - if (dev->is_atapi) { - return; - } - - spinlock_lock(&ata_lock); - -#if 0 - int errors = 0; - try_again: -#endif - - ata_wait(dev, false); - - // Stop. - outportb(dev->bar4, 0x00); - - // Set the PRDT. - outportl(dev->bar4 + 0x04, dev->dma_prdt_phys); - - // Enable error, irq status. - outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); - - // Set read. - outportb(dev->bar4, 0x08); - - irq_enable(); - - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if (!(status & ATA_STAT_BUSY)) { - break; - } - } - - outportb(bus + ATA_REG_CONTROL, 0x00); - outportb(bus + ATA_REG_HDDEVSEL, - 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); - ata_io_wait(dev); - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_SECCOUNT0, 1); - outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); - outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); - outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); - // outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ); -#if 1 - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { - break; - } - } -#endif - outportb(bus + ATA_REG_COMMAND, ATA_CMD_RD_DMA); - - ata_io_wait(dev); - - outportb(dev->bar4, 0x08 | 0x01); - - while (1) { - int status = inportb(dev->bar4 + 0x02); - int dstatus = inportb(dev->io_base + ATA_REG_STATUS); - if (!(status & 0x04)) { - continue; - } - if (!(dstatus & ATA_STAT_BUSY)) { - break; - } - } - irq_disable(); - -#if 0 - if (ata_wait(dev, true)) { - dbg_print("Error during ATA read of lba block %d\n", lba); - errors++; - if (errors > 4) - { - dbg_print( - "-- Too many errors trying to read this block. Bailing.\n"); - spinlock_unlock(&ata_lock); - return; - } - goto try_again; - } -#endif - - // Copy from DMA buffer to output buffer. - memcpy(buf, dev->dma_start, 512); - - // Inform device we are done. - outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); - -#if 0 - int size = 256; - inportsm(bus,buf,size); - ata_wait(dev, false); - outportb(bus + ATA_REG_CONTROL, 0x02); -#endif - spinlock_unlock(&ata_lock); -} - -void ata_device_read_sector_atapi(ata_device_t *dev, uint32_t lba, uint8_t *buf) -{ - if (!dev->is_atapi) { - return; - } - - uint16_t bus = dev->io_base; - spinlock_lock(&ata_lock); - - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_LBA1, dev->atapi_sector_size & 0xFF); - outportb(bus + ATA_REG_LBA2, dev->atapi_sector_size >> 8); - outportb(bus + ATA_REG_COMMAND, ATAPI_CMD_PACKET); - - // Poll. - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_STAT_ERR)) { - goto atapi_error_on_read_setup; - } - if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_DRQ)) { - break; - } - } - - atapi_in_progress = true; - - atapi_command_t command; - command.command_bytes[0] = 0xA8; - command.command_bytes[1] = 0; - command.command_bytes[2] = (lba >> 0x18) & 0xFF; - command.command_bytes[3] = (lba >> 0x10) & 0xFF; - command.command_bytes[4] = (lba >> 0x08) & 0xFF; - command.command_bytes[5] = (lba >> 0x00) & 0xFF; - command.command_bytes[6] = 0; - command.command_bytes[7] = 0; - // Bit 0 = PMI (0, last sector). - command.command_bytes[8] = 0; - // Control. - command.command_bytes[9] = 1; - command.command_bytes[10] = 0; - command.command_bytes[11] = 0; - - for (int i = 0; i < 6; ++i) { - outports(bus, command.command_words[i]); - } - - // Wait. -#ifdef COMPLETE_SCHEDULER - sleep_on(atapi_waiter); -#endif - - atapi_in_progress = false; - - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_STAT_ERR)) { - goto atapi_error_on_read_setup; - } - if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_DRQ)) { - break; - } - } - - uint16_t size_to_read = inportb(bus + ATA_REG_LBA2) << 8; - size_to_read = size_to_read | inportb(bus + ATA_REG_LBA1); - - inportsm(bus, buf, size_to_read / 2); - - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_STAT_ERR)) { - goto atapi_error_on_read_setup; - } - if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { - break; - } - } - -atapi_error_on_read_setup: - spinlock_unlock(&ata_lock); -} - -void ata_device_write_sector(ata_device_t *dev, uint32_t lba, uint8_t *buf) -{ - uint16_t bus = dev->io_base; - uint8_t slave = dev->slave; - - spinlock_lock(&ata_lock); - - outportb(bus + ATA_REG_CONTROL, 0x02); - - ata_wait(dev, false); - outportb(bus + ATA_REG_HDDEVSEL, - 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); - ata_wait(dev, false); - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_SECCOUNT0, 0x01); - outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); - outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); - outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE); - ata_wait(dev, false); - int size = ATA_SECTOR_SIZE / 2; - outportsm(bus, buf, size); - outportb(bus + 0x07, ATA_CMD_CH_FLSH); - ata_wait(dev, false); - spinlock_unlock(&ata_lock); -} - -int buffer_compare(uint32_t *ptr1, uint32_t *ptr2, size_t size) -{ - assert(!(size % 4)); - - size_t i = 0; - - while (i < size) { - if (*ptr1 != *ptr2) { - return 1; - } - - ptr1++; - ptr2++; - i += sizeof(uint32_t); - } - return 0; -} - -void ata_device_write_sector_retry(ata_device_t *dev, uint32_t lba, - uint8_t *buf) -{ - uint8_t *read_buf = kmalloc(ATA_SECTOR_SIZE); - do { - ata_device_write_sector(dev, lba, buf); - ata_device_read_sector(dev, lba, read_buf); - } while ( - buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)); - kfree(read_buf); -} - -void find_ata_pci(uint32_t dev, uint16_t vid, uint16_t did, void *extra) -{ - if ((vid == 0x8086) && (did == 0x7010 || did == 0x7111)) { - *((uint32_t *)extra) = dev; - } -} - -int ata_initialize() -{ - // Detect drives and mount them. - // Locate ATA device via PCI. - pci_scan(&find_ata_pci, -1, &ata_pci); - - irq_install_handler(14, ata_irq_handler, "ide master"); - irq_install_handler(15, ata_irq_handler_s, "ide slave"); - - atapi_waiter = list_create(); - - dbg_print("Detecteing devices...\n"); - dbg_print("Detecteing Primary Master...\n"); - ata_device_detect(&ata_primary_master); - dbg_print("\n"); - dbg_print("Detecteing Primary Slave...\n"); - ata_device_detect(&ata_primary_slave); - dbg_print("\n"); - dbg_print("Detecteing Secondary Master...\n"); - ata_device_detect(&ata_secondary_master); - dbg_print("\n"); - dbg_print("Detecteing Secondary Slave...\n"); - ata_device_detect(&ata_secondary_slave); - dbg_print("\n"); - dbg_print("Done\n"); - - return 0; -} - -int ata_finalize() -{ - return 0; -} +/// MentOS, The Mentoring Operating system project +/// @file ata.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "ata.h" +#include "isr.h" +#include "vfs.h" +#include "pci.h" +#include "list.h" +#include "debug.h" +#include "stdio.h" +#include "kheap.h" +#include "assert.h" +#include "string.h" +#include "kernel.h" +#include "pic8259.h" +#include "spinlock.h" + +// #define COMPLETE_VFS +// #define COMPLETE_SCHEDULER + +uint32_t ata_pci = 0x00000000; + +list_t *atapi_waiter; + +bool_t atapi_in_progress = false; + +typedef union { + uint8_t command_bytes[12]; + uint16_t command_words[6]; +} atapi_command_t; + +typedef struct { + uintptr_t offset; + uint16_t bytes; + uint16_t last; +} prdt_t; + +typedef struct { + char name[256]; + int io_base; + int control; + int slave; + bool_t is_atapi; + ata_identify_t identity; + prdt_t *dma_prdt; + uintptr_t dma_prdt_phys; + uint8_t *dma_start; + uintptr_t dma_start_phys; + uint32_t bar4; + uint32_t atapi_lba; + uint32_t atapi_sector_size; +} ata_device_t; + +ata_device_t ata_primary_master = { .io_base = 0x1F0, + .control = 0x3F6, + .slave = 0 }; +ata_device_t ata_primary_slave = { .io_base = 0x1F0, + .control = 0x3F6, + .slave = 1 }; +ata_device_t ata_secondary_master = { .io_base = 0x170, + .control = 0x376, + .slave = 0 }; +ata_device_t ata_secondary_slave = { .io_base = 0x170, + .control = 0x376, + .slave = 1 }; + +// volatile uint8_t ata_lock = 0; +spinlock_t ata_lock = { 0 }; + +// TODO: support other sector sizes. +#define ATA_SECTOR_SIZE 512 + +/// @brief Waits for the +/// @param dev +void ata_io_wait(ata_device_t *dev) +{ + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); +} + +uint8_t ata_status_wait(ata_device_t *dev, int timeout) +{ + uint8_t status; + if (timeout > 0) { + for (int i = 0; (status = inportb(dev->io_base + ATA_REG_STATUS)) & + ATA_STAT_BUSY && + (i < timeout); + ++i) + ; + } else { + while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & + ATA_STAT_BUSY) + ; + } + + return status; +} + +int ata_wait(ata_device_t *dev, bool_t advanced) +{ + ata_io_wait(dev); + uint8_t status = ata_status_wait(dev, 0); + if (advanced) { + status = inportb(dev->io_base + ATA_REG_STATUS); + if (status & ATA_STAT_ERR) + return 1; + if (status & ATA_STAT_FAULT) + return 1; + if (!(status & ATA_STAT_DRQ)) + return 1; + } + + return 0; +} + +void ata_device_select(ata_device_t *dev) +{ + outportb(dev->io_base + 1, 1); + outportb(dev->control, 0); + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); +} + +void ata_device_read_sector(ata_device_t *dev, uint32_t lba, uint8_t *buf); + +void ata_device_read_sector_atapi(ata_device_t *dev, uint32_t lba, + uint8_t *buf); + +void ata_device_write_sector_retry(ata_device_t *dev, uint32_t lba, + uint8_t *buf); + +#ifdef COMPLETE_VFS +uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, + uint8_t *buffer); +uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, + uint8_t *buffer); +void open_ata(fs_node_t *node, unsigned int flags); +void close_ata(fs_node_t *node); +#endif + +uint64_t ata_max_offset(ata_device_t *dev) +{ + uint64_t sectors = dev->identity.sectors_48; + if (!sectors) { + // Fall back to sectors_28. + sectors = dev->identity.sectors_28; + } + + return sectors * ATA_SECTOR_SIZE; +} + +uint64_t atapi_max_offset(ata_device_t *dev) +{ + uint64_t max_sector = dev->atapi_lba; + + if (!max_sector) { + return 0; + } + + return (max_sector + 1) * dev->atapi_sector_size; +} + +#ifdef COMPLETE_VFS +uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, + uint8_t *buffer) +{ + ata_device_t *dev = (ata_device_t *)node->device; + + unsigned int start_block = offset / ATA_SECTOR_SIZE; + unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; + + unsigned int x_offset = 0; + + if (offset > ata_max_offset(dev)) { + return 0; + } + + if (offset + size > ata_max_offset(dev)) { + unsigned int i = ata_max_offset(dev) - offset; + size = i; + } + + if (offset % ATA_SECTOR_SIZE) { + unsigned int prefix_size = + (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); + char *tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, start_block, (uint8_t *)tmp); + + memcpy(buffer, (void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), + prefix_size); + + free(tmp); + + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { + unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; + char *tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, end_block, (uint8_t *)tmp); + + memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, + postfix_size); + + free(tmp); + + end_block--; + } + + while (start_block <= end_block) { + ata_device_read_sector(dev, start_block, + (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += ATA_SECTOR_SIZE; + start_block++; + } + + return size; +} +#endif + +#ifdef COMPLETE_VFS +uint32_t read_atapi(fs_node_t *node, uint32_t offset, uint32_t size, + uint8_t *buffer) +{ + ata_device_t *dev = (ata_device_t *)node->device; + + unsigned int start_block = offset / dev->atapi_sector_size; + unsigned int end_block = (offset + size - 1) / dev->atapi_sector_size; + + unsigned int x_offset = 0; + + if (offset > atapi_max_offset(dev)) { + return 0; + } + + if (offset + size > atapi_max_offset(dev)) { + unsigned int i = atapi_max_offset(dev) - offset; + size = i; + } + + if (offset % dev->atapi_sector_size) { + unsigned int prefix_size = + (dev->atapi_sector_size - (offset % dev->atapi_sector_size)); + char *tmp = malloc(dev->atapi_sector_size); + ata_device_read_sector_atapi(dev, start_block, (uint8_t *)tmp); + + memcpy(buffer, + (void *)((uintptr_t)tmp + (offset % dev->atapi_sector_size)), + prefix_size); + + free(tmp); + + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % dev->atapi_sector_size && start_block <= end_block) { + unsigned int postfix_size = (offset + size) % dev->atapi_sector_size; + char *tmp = malloc(dev->atapi_sector_size); + ata_device_read_sector_atapi(dev, end_block, (uint8_t *)tmp); + + memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, + postfix_size); + + free(tmp); + + end_block--; + } + + while (start_block <= end_block) { + ata_device_read_sector_atapi(dev, start_block, + (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += dev->atapi_sector_size; + start_block++; + } + + return size; +} +#endif + +#ifdef COMPLETE_VFS +uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, + uint8_t *buffer) +{ + ata_device_t *dev = (ata_device_t *)node->device; + + unsigned int start_block = offset / ATA_SECTOR_SIZE; + unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; + + unsigned int x_offset = 0; + + if (offset > ata_max_offset(dev)) { + return 0; + } + + if (offset + size > ata_max_offset(dev)) { + unsigned int i = ata_max_offset(dev) - offset; + size = i; + } + + if (offset % ATA_SECTOR_SIZE) { + unsigned int prefix_size = + (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); + + char *tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, start_block, (uint8_t *)tmp); + + dbg_print("Writing first block"); + + memcpy((void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), buffer, + prefix_size); + ata_device_write_sector_retry(dev, start_block, (uint8_t *)tmp); + + free(tmp); + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { + unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; + + char *tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, end_block, (uint8_t *)tmp); + + dbg_print("Writing last block"); + + memcpy(tmp, (void *)((uintptr_t)buffer + size - postfix_size), + postfix_size); + + ata_device_write_sector_retry(dev, end_block, (uint8_t *)tmp); + + free(tmp); + end_block--; + } + + while (start_block <= end_block) { + ata_device_write_sector_retry( + dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += ATA_SECTOR_SIZE; + start_block++; + } + + return size; +} +#endif + +#ifdef COMPLETE_VFS +void open_ata(fs_node_t *node, unsigned int flags) +{ + return; +} +#endif + +#ifdef COMPLETE_VFS +void close_ata(fs_node_t *node) +{ + return; +} +#endif + +#ifdef COMPLETE_VFS +fs_node_t *atapi_device_create(ata_device_t *device) +{ + fs_node_t *fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + sprintf(fnode->name, "cdrom%d", cdrom_number); + fnode->device = device; + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->length = atapi_max_offset(device); + fnode->flags = FS_BLOCKDEVICE; + fnode->read = read_atapi; + // No write support. + fnode->write = NULL; + fnode->open = open_ata; + fnode->close = close_ata; + fnode->readdir = NULL; + fnode->finddir = NULL; + // TODO, identify: etc? + fnode->ioctl = NULL; + return fnode; +} +#endif + +#ifdef COMPLETE_VFS +fs_node_t *ata_device_create(ata_device_t *device) +{ + fs_node_t *fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + sprintf(fnode->name, "atadev%d", ata_drive_char - 'a'); + fnode->device = device; + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + // TODO + fnode->length = ata_max_offset(device); + fnode->flags = FS_BLOCKDEVICE; + fnode->read = read_ata; + fnode->write = write_ata; + fnode->open = open_ata; + fnode->close = close_ata; + fnode->readdir = NULL; + fnode->finddir = NULL; + // TODO: identify, etc? + fnode->ioctl = NULL; + return fnode; +} +#endif + +void ata_soft_reset(ata_device_t *dev) +{ + outportb(dev->control, 0x04); + ata_io_wait(dev); + outportb(dev->control, 0x00); +} + +void ata_irq_handler(pt_regs *r) +{ + inportb(ata_primary_master.io_base + ATA_REG_STATUS); + + if (atapi_in_progress) { + // wakeup_queue(atapi_waiter); + } + + // irq_ack(14); + pic8259_send_eoi(14); +} + +void ata_irq_handler_s(pt_regs *r) +{ + inportb(ata_secondary_master.io_base + ATA_REG_STATUS); + + if (atapi_in_progress) { + // wakeup_queue(atapi_waiter); + } + + // irq_ack(15); + pic8259_send_eoi(15); +} + +bool_t ata_device_init(ata_device_t *dev) +{ + dbg_print("Detected IDE device on bus 0x%3x\n", dev->io_base); + dbg_print("Device name: %s\n", dev->name); + ata_device_select(dev); + outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENT); + ata_io_wait(dev); + uint8_t status = inportb(dev->io_base + ATA_REG_COMMAND); + dbg_print("Device status: %d\n", status); + + ata_wait(dev, false); + + uint16_t *buf = (uint16_t *)&dev->identity; + for (int i = 0; i < 256; ++i) { + buf[i] = inports(dev->io_base); + } + + uint8_t *ptr = (uint8_t *)&dev->identity.model; + for (int i = 0; i < 39; i += 2) { + char tmp = ptr[i + 1]; + ptr[i + 1] = ptr[i]; + ptr[i] = tmp; + } + ptr[39] = 0; + + dbg_print("Device Model: %s\n", dev->identity.model); + dbg_print("Sectors (48): %d\n", (uint32_t)dev->identity.sectors_48); + dbg_print("Sectors (24): %d\n", dev->identity.sectors_28); + + dbg_print("Setting up DMA...\n"); + // TODO: Ale. + // dev->dma_prdt = kmalloc_p(sizeof(prdt_t) * 1, &dev->dma_prdt_phys); + // dev->dma_start = kmalloc_p(4096, &dev->dma_start_phys); + + dbg_print("Putting prdt at 0x%x (0x%x phys)\n", dev->dma_prdt, + dev->dma_prdt_phys); + dbg_print("Putting prdt[0] at 0x%x (0x%x phys)\n", dev->dma_start, + dev->dma_start_phys); + + dev->dma_prdt[0].offset = dev->dma_start_phys; + dev->dma_prdt[0].bytes = 512; + dev->dma_prdt[0].last = 0x8000; + + dbg_print("ATA PCI device ID: 0x%x\n", ata_pci); + + uint16_t command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); + dbg_print("COMMAND register before: 0x%4x\n", command_reg); + if (command_reg & (1U << 2U)) { + dbg_print("Bus mastering already enabled.\n"); + } else { + // bit 2. + command_reg |= (1U << 2U); + dbg_print("Enabling bus mastering...\n"); + pci_write_field(ata_pci, PCI_COMMAND, 4, command_reg); + command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); + dbg_print("COMMAND register after: 0x%4x\n", command_reg); + } + + dev->bar4 = pci_read_field(ata_pci, PCI_BASE_ADDRESS_4, 4); + dbg_print("BAR4: 0x%x\n", dev->bar4); + + if (dev->bar4 & 0x00000001U) { + dev->bar4 = dev->bar4 & 0xFFFFFFFC; + } else { + dbg_print("? ATA bus master registers are 'usually' I/O ports.\n"); + + // No DMA because we're not sure what to do here- + return false; + } +#if 0 + pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 0xFE); + if (pci_read_field(ata_pci, PCI_INTERRUPT_LINE, 1) == 0xFE) + { + // Needs assignment. + pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 14); + } +#endif + + return true; +} + +int atapi_device_init(ata_device_t *dev) +{ + dbg_print("Detected ATAPI device at io-base 0x%3x, ctrl 0x%3x, slave %d\n", + dev->io_base, dev->control, dev->slave); + dbg_print("Device name: %s\n", dev->name); + ata_device_select(dev); + outportb(dev->io_base + ATA_REG_COMMAND, ATAPI_CMD_ID_PCKT); + ata_io_wait(dev); + uint8_t status = inportb(dev->io_base + ATA_REG_COMMAND); + dbg_print("Device status: %d\n", status); + + ata_wait(dev, false); + + uint16_t *buf = (uint16_t *)&dev->identity; + + for (int i = 0; i < 256; ++i) { + buf[i] = inports(dev->io_base); + } + + uint8_t *ptr = (uint8_t *)&dev->identity.model; + for (int i = 0; i < 39; i += 2) { + char tmp = ptr[i + 1]; + ptr[i + 1] = ptr[i]; + ptr[i] = tmp; + } + ptr[39] = 0; + + dbg_print("Device Model: %s\n", dev->identity.model); + + // Detect medium. + atapi_command_t command; + command.command_bytes[0] = 0x25; + command.command_bytes[1] = 0; + command.command_bytes[2] = 0; + command.command_bytes[3] = 0; + command.command_bytes[4] = 0; + command.command_bytes[5] = 0; + command.command_bytes[6] = 0; + command.command_bytes[7] = 0; + // Bit 0 = PMI (0, last sector). + command.command_bytes[8] = 0; + // Control. + command.command_bytes[9] = 0; + command.command_bytes[10] = 0; + command.command_bytes[11] = 0; + + uint16_t bus = dev->io_base; + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_LBA1, 0x08); + outportb(bus + ATA_REG_LBA2, 0x08); + outportb(bus + ATA_REG_COMMAND, ATAPI_CMD_PACKET); + + // Poll. + while (1) { + status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_STAT_ERR)) { + goto atapi_error; + } + if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { + break; + } + } + + for (int i = 0; i < 6; ++i) + outports(bus, command.command_words[i]); + + // Poll. + while (1) { + status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_STAT_ERR)) { + goto atapi_error_read; + } + if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { + break; + } + if ((status & ATA_STAT_DRQ)) { + break; + } + } + + uint16_t data[4]; + + for (int i = 0; i < 4; ++i) { + data[i] = inports(bus); + } + +#define htonl(l) \ + ((((l)&0xFF) << 24) | (((l)&0xFF00) << 8) | (((l)&0xFF0000) >> 8) | \ + (((l)&0xFF000000) >> 24)) + uint32_t lba, blocks; + ; + + memcpy(&lba, &data[0], sizeof(uint32_t)); + + lba = htonl(lba); + + memcpy(&blocks, &data[2], sizeof(uint32_t)); + + blocks = htonl(blocks); + + dev->atapi_lba = lba; + dev->atapi_sector_size = blocks; + + if (!lba) { + return false; + } + + dbg_print("Finished! LBA = %x; block length = %x\n", lba, blocks); + return true; + +atapi_error_read: + dbg_print("ATAPI error; no medium?\n"); + return false; + +atapi_error: + dbg_print("ATAPI early error; unsure\n"); + return false; +} + +int ata_device_detect(ata_device_t *dev) +{ + static char ata_drive_char = 'a'; + static int cdrom_number = 0; + + ata_soft_reset(dev); + ata_io_wait(dev); + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + ata_status_wait(dev, 10000); + + dbg_print("Probing cylinder registers...\n"); + uint8_t cl = inportb(dev->io_base + ATA_REG_LBA1); + uint8_t ch = inportb(dev->io_base + ATA_REG_LBA2); + if ((cl == 0xFF) && (ch == 0xFF)) { + dbg_print("No drive(s) present\n"); + return false; + } + + dbg_print("Waiting while busy...\n"); + uint8_t status = ata_status_wait(dev, 5000); + if (status & ATA_STAT_BUSY) { + dbg_print("No drive(s) present\n"); + + return false; + } + + dbg_print("Device detected: 0x%2x 0x%2x\n", cl, ch); + if ((cl == 0x00 && ch == 0x00) || (cl == 0x3C && ch == 0xC3)) { + // The device is not an ATAPI. + dev->is_atapi = false; + // Parallel ATA device, or emulated SATA + sprintf(dev->name, "/dev/hd%c", ata_drive_char); + +#ifdef COMPLETE_VFS + fs_node_t *node = ata_device_create(dev); + vfs_mount(devname, node); +#endif + + ++ata_drive_char; + if (!ata_device_init(dev)) { + return 0; + } + + return 1; + } else if ((cl == 0x14 && ch == 0xEB) || (cl == 0x69 && ch == 0x96)) { + // The device is an ATAPI. + dev->is_atapi = true; + sprintf(dev->name, "/dev/cdrom%d", cdrom_number); + +#ifdef COMPLETE_VFS + fs_node_t *node = atapi_device_create(dev); + vfs_mount(devname, node); +#endif + + ++cdrom_number; + if (!atapi_device_init(dev)) { + return 0; + } + return 2; + } + dbg_print("\n"); + + // TODO: ATAPI, SATA, SATAPI. + + return 0; +} + +void ata_device_read_sector(ata_device_t *dev, uint32_t lba, uint8_t *buf) +{ + uint16_t bus = dev->io_base; + + uint8_t slave = dev->slave; + + if (dev->is_atapi) { + return; + } + + spinlock_lock(&ata_lock); + +#if 0 + int errors = 0; + try_again: +#endif + + ata_wait(dev, false); + + // Stop. + outportb(dev->bar4, 0x00); + + // Set the PRDT. + outportl(dev->bar4 + 0x04, dev->dma_prdt_phys); + + // Enable error, irq status. + outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); + + // Set read. + outportb(dev->bar4, 0x08); + + irq_enable(); + + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & ATA_STAT_BUSY)) { + break; + } + } + + outportb(bus + ATA_REG_CONTROL, 0x00); + outportb(bus + ATA_REG_HDDEVSEL, + 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); + ata_io_wait(dev); + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_SECCOUNT0, 1); + outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); + outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); + outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); + // outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ); +#if 1 + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { + break; + } + } +#endif + outportb(bus + ATA_REG_COMMAND, ATA_CMD_RD_DMA); + + ata_io_wait(dev); + + outportb(dev->bar4, 0x08 | 0x01); + + while (1) { + int status = inportb(dev->bar4 + 0x02); + int dstatus = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & 0x04)) { + continue; + } + if (!(dstatus & ATA_STAT_BUSY)) { + break; + } + } + irq_disable(); + +#if 0 + if (ata_wait(dev, true)) { + dbg_print("Error during ATA read of lba block %d\n", lba); + errors++; + if (errors > 4) + { + dbg_print( + "-- Too many errors trying to read this block. Bailing.\n"); + spinlock_unlock(&ata_lock); + return; + } + goto try_again; + } +#endif + + // Copy from DMA buffer to output buffer. + memcpy(buf, dev->dma_start, 512); + + // Inform device we are done. + outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); + +#if 0 + int size = 256; + inportsm(bus,buf,size); + ata_wait(dev, false); + outportb(bus + ATA_REG_CONTROL, 0x02); +#endif + spinlock_unlock(&ata_lock); +} + +void ata_device_read_sector_atapi(ata_device_t *dev, uint32_t lba, uint8_t *buf) +{ + if (!dev->is_atapi) { + return; + } + + uint16_t bus = dev->io_base; + spinlock_lock(&ata_lock); + + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_LBA1, dev->atapi_sector_size & 0xFF); + outportb(bus + ATA_REG_LBA2, dev->atapi_sector_size >> 8); + outportb(bus + ATA_REG_COMMAND, ATAPI_CMD_PACKET); + + // Poll. + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_STAT_ERR)) { + goto atapi_error_on_read_setup; + } + if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_DRQ)) { + break; + } + } + + atapi_in_progress = true; + + atapi_command_t command; + command.command_bytes[0] = 0xA8; + command.command_bytes[1] = 0; + command.command_bytes[2] = (lba >> 0x18) & 0xFF; + command.command_bytes[3] = (lba >> 0x10) & 0xFF; + command.command_bytes[4] = (lba >> 0x08) & 0xFF; + command.command_bytes[5] = (lba >> 0x00) & 0xFF; + command.command_bytes[6] = 0; + command.command_bytes[7] = 0; + // Bit 0 = PMI (0, last sector). + command.command_bytes[8] = 0; + // Control. + command.command_bytes[9] = 1; + command.command_bytes[10] = 0; + command.command_bytes[11] = 0; + + for (int i = 0; i < 6; ++i) { + outports(bus, command.command_words[i]); + } + + // Wait. +#ifdef COMPLETE_SCHEDULER + sleep_on(atapi_waiter); +#endif + + atapi_in_progress = false; + + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_STAT_ERR)) { + goto atapi_error_on_read_setup; + } + if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_DRQ)) { + break; + } + } + + uint16_t size_to_read = inportb(bus + ATA_REG_LBA2) << 8; + size_to_read = size_to_read | inportb(bus + ATA_REG_LBA1); + + inportsm(bus, buf, size_to_read / 2); + + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_STAT_ERR)) { + goto atapi_error_on_read_setup; + } + if (!(status & ATA_STAT_BUSY) && (status & ATA_STAT_READY)) { + break; + } + } + +atapi_error_on_read_setup: + spinlock_unlock(&ata_lock); +} + +void ata_device_write_sector(ata_device_t *dev, uint32_t lba, uint8_t *buf) +{ + uint16_t bus = dev->io_base; + uint8_t slave = dev->slave; + + spinlock_lock(&ata_lock); + + outportb(bus + ATA_REG_CONTROL, 0x02); + + ata_wait(dev, false); + outportb(bus + ATA_REG_HDDEVSEL, + 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); + ata_wait(dev, false); + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_SECCOUNT0, 0x01); + outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); + outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); + outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE); + ata_wait(dev, false); + int size = ATA_SECTOR_SIZE / 2; + outportsm(bus, buf, size); + outportb(bus + 0x07, ATA_CMD_CH_FLSH); + ata_wait(dev, false); + spinlock_unlock(&ata_lock); +} + +int buffer_compare(uint32_t *ptr1, uint32_t *ptr2, size_t size) +{ + assert(!(size % 4)); + + size_t i = 0; + + while (i < size) { + if (*ptr1 != *ptr2) { + return 1; + } + + ptr1++; + ptr2++; + i += sizeof(uint32_t); + } + return 0; +} + +void ata_device_write_sector_retry(ata_device_t *dev, uint32_t lba, + uint8_t *buf) +{ + uint8_t *read_buf = kmalloc(ATA_SECTOR_SIZE); + do { + ata_device_write_sector(dev, lba, buf); + ata_device_read_sector(dev, lba, read_buf); + } while ( + buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)); + kfree(read_buf); +} + +void find_ata_pci(uint32_t dev, uint16_t vid, uint16_t did, void *extra) +{ + if ((vid == 0x8086) && (did == 0x7010 || did == 0x7111)) { + *((uint32_t *)extra) = dev; + } +} + +int ata_initialize() +{ + // Detect drives and mount them. + // Locate ATA device via PCI. + pci_scan(&find_ata_pci, -1, &ata_pci); + + irq_install_handler(14, ata_irq_handler, "ide master"); + irq_install_handler(15, ata_irq_handler_s, "ide slave"); + + atapi_waiter = list_create(); + + dbg_print("Detecteing devices...\n"); + dbg_print("Detecteing Primary Master...\n"); + ata_device_detect(&ata_primary_master); + dbg_print("\n"); + dbg_print("Detecteing Primary Slave...\n"); + ata_device_detect(&ata_primary_slave); + dbg_print("\n"); + dbg_print("Detecteing Secondary Master...\n"); + ata_device_detect(&ata_secondary_master); + dbg_print("\n"); + dbg_print("Detecteing Secondary Slave...\n"); + ata_device_detect(&ata_secondary_slave); + dbg_print("\n"); + dbg_print("Done\n"); + + return 0; +} + +int ata_finalize() +{ + return 0; +} diff --git a/mentos/src/drivers/fdc.c b/mentos/src/drivers/fdc.c index 5dbe1a5..8100d5e 100644 --- a/mentos/src/drivers/fdc.c +++ b/mentos/src/drivers/fdc.c @@ -1,27 +1,27 @@ -/// MentOS, The Mentoring Operating system project -/// @file fdc.c -/// @brief Floppy driver controller handling. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "fdc.h" -#include "video.h" -#include "port_io.h" - -void fdc_disable_motor() -{ - /* Setting bits: - * 2: (RESET) - * 3: (IRQ) - */ - outportb(DOR, 0x0c); -} - -void fdc_enable_motor() -{ - /* Setting bits: - * 3: (IRQ) - * 4: (MOTA) - */ - outportb(DOR, 0x18); -} +/// MentOS, The Mentoring Operating system project +/// @file fdc.c +/// @brief Floppy driver controller handling. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "fdc.h" +#include "video.h" +#include "port_io.h" + +void fdc_disable_motor() +{ + /* Setting bits: + * 2: (RESET) + * 3: (IRQ) + */ + outportb(DOR, 0x0c); +} + +void fdc_enable_motor() +{ + /* Setting bits: + * 3: (IRQ) + * 4: (MOTA) + */ + outportb(DOR, 0x18); +} diff --git a/mentos/src/drivers/keyboard/keyboard.c b/mentos/src/drivers/keyboard/keyboard.c index 49452f9..77f5b25 100644 --- a/mentos/src/drivers/keyboard/keyboard.c +++ b/mentos/src/drivers/keyboard/keyboard.c @@ -1,271 +1,271 @@ -/// MentOS, The Mentoring Operating system project -/// @file keyboard.c -/// @brief Keyboard handling. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "keyboard.h" -#include "isr.h" -#include "video.h" -#include "stdio.h" -#include "keymap.h" -#include "bitops.h" -#include "port_io.h" -#include "pic8259.h" - -/// A macro from Ivan to update buffer indexes. -#define STEP(x) (((x) == BUFSIZE - 1) ? 0 : (x + 1)) - -/// Circular Buffer where the pressed keys are stored. -static int circular_buffer[BUFSIZE]; - -/// Index inside the buffer... -static long buf_r = 0; - -/// Index inside the buffer... -static long buf_w = 0; - -/// Tracks the state of the leds. -static uint8_t ledstate = 0; - -/// The shadow option is active. -static bool_t shadow = false; - -/// The shadow character. -static char shadow_character = 0; - -/// The flags concerning the keyboard. -static uint32_t keyboard_flags = 0; - -/// Flag which identifies the left shift. -#define KBD_LEFT_SHIFT 1 - -/// Flag which identifies the right shift. -#define KBD_RIGHT_SHIFT 2 - -/// Flag which identifies the caps lock. -#define KBD_CAPS_LOCK 4 - -/// Flag which identifies the num lock. -#define KBD_NUM_LOCK 8 - -/// Flag which identifies the scroll lock. -#define KBD_SCROLL_LOCK 16 - -/// Flag which identifies the left control. -#define KBD_LEFT_CONTROL 32 - -/// Flag which identifies the right control. -#define KBD_RIGHT_CONTROL 64 - -static inline void push_character(char c) -{ - // Update buffer. - if (STEP(buf_w) == buf_r) { - buf_r = STEP(buf_r); - } - circular_buffer[buf_w] = c; - buf_w = STEP(buf_w); -} - -void keyboard_install() -{ - // Install the IRQ. - irq_install_handler(IRQ_KEYBOARD, keyboard_isr, "keyboard"); - // Enable the IRQ. - pic8259_irq_enable(IRQ_KEYBOARD); -} - -void keyboard_isr(pt_regs *r) -{ - (void)r; - - if (!(inportb(0x64) & 1)) { - return; - } - - // Take scancode from the port. - uint32_t scancode = inportb(0x60); - if (scancode == 0xE0) { - scancode = (scancode << 8) | inportb(0x60); - } - - // If the key has just been released. - if (scancode & 0x80) { - if (scancode == (KEY_LEFT_SHIFT | CODE_BREAK)) { - clear_flag(&keyboard_flags, KBD_LEFT_SHIFT); - } else if (scancode == (KEY_RIGHT_SHIFT | CODE_BREAK)) { - clear_flag(&keyboard_flags, KBD_RIGHT_SHIFT); - } else if (scancode == (KEY_LEFT_CONTROL | CODE_BREAK)) { - clear_flag(&keyboard_flags, KBD_LEFT_CONTROL); - } else if (scancode == (KEY_RIGHT_CONTROL | CODE_BREAK)) { - clear_flag(&keyboard_flags, KBD_RIGHT_CONTROL); - } - } else { - int32_t character = 0; - - // Parse the key. - switch (scancode) { - case KEY_LEFT_SHIFT: - set_flag(&keyboard_flags, KBD_LEFT_SHIFT); - break; - case KEY_RIGHT_SHIFT: - set_flag(&keyboard_flags, KBD_RIGHT_SHIFT); - break; - case KEY_LEFT_CONTROL: - set_flag(&keyboard_flags, KBD_LEFT_CONTROL); - break; - case KEY_RIGHT_CONTROL: - set_flag(&keyboard_flags, KBD_RIGHT_CONTROL); - break; - case KEY_CAPS_LOCK: - keyboard_flags ^= KBD_CAPS_LOCK; - keyboard_update_leds(); - break; - case KEY_NUM_LOCK: - keyboard_flags ^= KBD_NUM_LOCK; - keyboard_update_leds(); - break; - case KEY_SCROLL_LOCK: - keyboard_flags ^= KBD_SCROLL_LOCK; - keyboard_update_leds(); - break; - case KEY_PAGE_UP: - video_scroll_up(); - break; - case KEY_PAGE_DOWN: - video_scroll_down(); - break; - case KEY_ESCAPE: - break; - case KEY_LEFT_ALT: - break; - case KEY_RIGHT_ALT: - break; - case KEY_BACKSPACE: - push_character('\b'); - video_delete_last_character(); - video_set_cursor_auto(); - break; - case KEY_KP_RETURN: - case KEY_ENTER: - push_character('\n'); - video_new_line(); - video_set_cursor_auto(); - pic8259_send_eoi(IRQ_KEYBOARD); - break; - case KEY_UP_ARROW: - push_character('\033'); - push_character('['); - push_character(72); - break; - case KEY_DOWN_ARROW: - push_character('\033'); - push_character('['); - push_character(80); - break; - case KEY_LEFT_ARROW: - push_character('\033'); - push_character('['); - push_character(75); - break; - case KEY_RIGHT_ARROW: - push_character('\033'); - push_character('['); - push_character(77); - break; - default: - if (has_flag(keyboard_flags, KBD_NUM_LOCK)) { - character = keymap_it.numlock[scancode]; - } - if (character <= 0) { - // Apply shift modifier. - if (has_flag(keyboard_flags, - (KBD_LEFT_SHIFT | KBD_RIGHT_SHIFT))) { - character = keymap_it.shift[scancode]; - } else { - character = keymap_it.base[scancode]; - } - } - if (character > 0) { - // Apply caps lock modifier. - if (has_flag(keyboard_flags, KBD_CAPS_LOCK)) { - if (character >= 'a' && character <= 'z') { - character += 'A' - 'a'; - } else if (character >= 'A' && character <= 'Z') { - character += 'a' - 'A'; - } - } - if (!shadow) { - video_putc(character); - } else if (shadow_character != 0) { - video_putc(shadow_character); - } - // Update buffer. - push_character(character); - } - break; - } - } - pic8259_send_eoi(IRQ_KEYBOARD); -} - -void keyboard_update_leds() -{ - // Handle scroll_loc & num_loc & caps_loc. - (keyboard_flags & KBD_SCROLL_LOCK) ? (ledstate |= 1) : (ledstate ^= 1); - (keyboard_flags & KBD_NUM_LOCK) ? (ledstate |= 2) : (ledstate ^= 2); - (keyboard_flags & KBD_CAPS_LOCK) ? (ledstate |= 4) : (ledstate ^= 4); - - // Write on the port. - outportb(0x60, 0xED); - outportb(0x60, ledstate); -} - -void keyboard_enable() -{ - outportb(0x60, 0xF4); -} - -void keyboard_disable() -{ - outportb(0x60, 0xF5); -} - -int keyboard_getc(void) -{ - int c = -1; - if (buf_r != buf_w) { - c = circular_buffer[buf_r]; - buf_r = STEP(buf_r); - } - return c; -} - -void keyboard_set_shadow(const bool_t value) -{ - shadow = value; - if (shadow == false) { - shadow_character = 0; - } -} - -void keyboard_set_shadow_character(const char _shadow_character) -{ - shadow_character = _shadow_character; -} - -bool_t keyboard_get_shadow() -{ - return shadow; -} - -bool_t keyboard_is_ctrl_pressed() -{ - return (bool_t)(keyboard_flags & (KBD_LEFT_CONTROL)); -} - -bool_t keyboard_is_shifted() -{ - return (bool_t)(keyboard_flags & (KBD_LEFT_SHIFT | KBD_RIGHT_SHIFT)); -} +/// MentOS, The Mentoring Operating system project +/// @file keyboard.c +/// @brief Keyboard handling. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "keyboard.h" +#include "isr.h" +#include "video.h" +#include "stdio.h" +#include "keymap.h" +#include "bitops.h" +#include "port_io.h" +#include "pic8259.h" + +/// A macro from Ivan to update buffer indexes. +#define STEP(x) (((x) == BUFSIZE - 1) ? 0 : (x + 1)) + +/// Circular Buffer where the pressed keys are stored. +static int circular_buffer[BUFSIZE]; + +/// Index inside the buffer... +static long buf_r = 0; + +/// Index inside the buffer... +static long buf_w = 0; + +/// Tracks the state of the leds. +static uint8_t ledstate = 0; + +/// The shadow option is active. +static bool_t shadow = false; + +/// The shadow character. +static char shadow_character = 0; + +/// The flags concerning the keyboard. +static uint32_t keyboard_flags = 0; + +/// Flag which identifies the left shift. +#define KBD_LEFT_SHIFT 1 + +/// Flag which identifies the right shift. +#define KBD_RIGHT_SHIFT 2 + +/// Flag which identifies the caps lock. +#define KBD_CAPS_LOCK 4 + +/// Flag which identifies the num lock. +#define KBD_NUM_LOCK 8 + +/// Flag which identifies the scroll lock. +#define KBD_SCROLL_LOCK 16 + +/// Flag which identifies the left control. +#define KBD_LEFT_CONTROL 32 + +/// Flag which identifies the right control. +#define KBD_RIGHT_CONTROL 64 + +static inline void push_character(char c) +{ + // Update buffer. + if (STEP(buf_w) == buf_r) { + buf_r = STEP(buf_r); + } + circular_buffer[buf_w] = c; + buf_w = STEP(buf_w); +} + +void keyboard_install() +{ + // Install the IRQ. + irq_install_handler(IRQ_KEYBOARD, keyboard_isr, "keyboard"); + // Enable the IRQ. + pic8259_irq_enable(IRQ_KEYBOARD); +} + +void keyboard_isr(pt_regs *r) +{ + (void)r; + + if (!(inportb(0x64) & 1)) { + return; + } + + // Take scancode from the port. + uint32_t scancode = inportb(0x60); + if (scancode == 0xE0) { + scancode = (scancode << 8) | inportb(0x60); + } + + // If the key has just been released. + if (scancode & 0x80) { + if (scancode == (KEY_LEFT_SHIFT | CODE_BREAK)) { + clear_flag(&keyboard_flags, KBD_LEFT_SHIFT); + } else if (scancode == (KEY_RIGHT_SHIFT | CODE_BREAK)) { + clear_flag(&keyboard_flags, KBD_RIGHT_SHIFT); + } else if (scancode == (KEY_LEFT_CONTROL | CODE_BREAK)) { + clear_flag(&keyboard_flags, KBD_LEFT_CONTROL); + } else if (scancode == (KEY_RIGHT_CONTROL | CODE_BREAK)) { + clear_flag(&keyboard_flags, KBD_RIGHT_CONTROL); + } + } else { + int32_t character = 0; + + // Parse the key. + switch (scancode) { + case KEY_LEFT_SHIFT: + set_flag(&keyboard_flags, KBD_LEFT_SHIFT); + break; + case KEY_RIGHT_SHIFT: + set_flag(&keyboard_flags, KBD_RIGHT_SHIFT); + break; + case KEY_LEFT_CONTROL: + set_flag(&keyboard_flags, KBD_LEFT_CONTROL); + break; + case KEY_RIGHT_CONTROL: + set_flag(&keyboard_flags, KBD_RIGHT_CONTROL); + break; + case KEY_CAPS_LOCK: + keyboard_flags ^= KBD_CAPS_LOCK; + keyboard_update_leds(); + break; + case KEY_NUM_LOCK: + keyboard_flags ^= KBD_NUM_LOCK; + keyboard_update_leds(); + break; + case KEY_SCROLL_LOCK: + keyboard_flags ^= KBD_SCROLL_LOCK; + keyboard_update_leds(); + break; + case KEY_PAGE_UP: + video_scroll_up(); + break; + case KEY_PAGE_DOWN: + video_scroll_down(); + break; + case KEY_ESCAPE: + break; + case KEY_LEFT_ALT: + break; + case KEY_RIGHT_ALT: + break; + case KEY_BACKSPACE: + push_character('\b'); + video_delete_last_character(); + video_set_cursor_auto(); + break; + case KEY_KP_RETURN: + case KEY_ENTER: + push_character('\n'); + video_new_line(); + video_set_cursor_auto(); + pic8259_send_eoi(IRQ_KEYBOARD); + break; + case KEY_UP_ARROW: + push_character('\033'); + push_character('['); + push_character(72); + break; + case KEY_DOWN_ARROW: + push_character('\033'); + push_character('['); + push_character(80); + break; + case KEY_LEFT_ARROW: + push_character('\033'); + push_character('['); + push_character(75); + break; + case KEY_RIGHT_ARROW: + push_character('\033'); + push_character('['); + push_character(77); + break; + default: + if (has_flag(keyboard_flags, KBD_NUM_LOCK)) { + character = keymap_it.numlock[scancode]; + } + if (character <= 0) { + // Apply shift modifier. + if (has_flag(keyboard_flags, + (KBD_LEFT_SHIFT | KBD_RIGHT_SHIFT))) { + character = keymap_it.shift[scancode]; + } else { + character = keymap_it.base[scancode]; + } + } + if (character > 0) { + // Apply caps lock modifier. + if (has_flag(keyboard_flags, KBD_CAPS_LOCK)) { + if (character >= 'a' && character <= 'z') { + character += 'A' - 'a'; + } else if (character >= 'A' && character <= 'Z') { + character += 'a' - 'A'; + } + } + if (!shadow) { + video_putc(character); + } else if (shadow_character != 0) { + video_putc(shadow_character); + } + // Update buffer. + push_character(character); + } + break; + } + } + pic8259_send_eoi(IRQ_KEYBOARD); +} + +void keyboard_update_leds() +{ + // Handle scroll_loc & num_loc & caps_loc. + (keyboard_flags & KBD_SCROLL_LOCK) ? (ledstate |= 1) : (ledstate ^= 1); + (keyboard_flags & KBD_NUM_LOCK) ? (ledstate |= 2) : (ledstate ^= 2); + (keyboard_flags & KBD_CAPS_LOCK) ? (ledstate |= 4) : (ledstate ^= 4); + + // Write on the port. + outportb(0x60, 0xED); + outportb(0x60, ledstate); +} + +void keyboard_enable() +{ + outportb(0x60, 0xF4); +} + +void keyboard_disable() +{ + outportb(0x60, 0xF5); +} + +int keyboard_getc(void) +{ + int c = -1; + if (buf_r != buf_w) { + c = circular_buffer[buf_r]; + buf_r = STEP(buf_r); + } + return c; +} + +void keyboard_set_shadow(const bool_t value) +{ + shadow = value; + if (shadow == false) { + shadow_character = 0; + } +} + +void keyboard_set_shadow_character(const char _shadow_character) +{ + shadow_character = _shadow_character; +} + +bool_t keyboard_get_shadow() +{ + return shadow; +} + +bool_t keyboard_is_ctrl_pressed() +{ + return (bool_t)(keyboard_flags & (KBD_LEFT_CONTROL)); +} + +bool_t keyboard_is_shifted() +{ + return (bool_t)(keyboard_flags & (KBD_LEFT_SHIFT | KBD_RIGHT_SHIFT)); +} diff --git a/mentos/src/drivers/keyboard/keymap.c b/mentos/src/drivers/keyboard/keymap.c index 79c5c74..b1202eb 100644 --- a/mentos/src/drivers/keyboard/keymap.c +++ b/mentos/src/drivers/keyboard/keymap.c @@ -1,207 +1,207 @@ -/// MentOS, The Mentoring Operating system project -/// @file keymap.c -/// @brief Keymap for keyboard. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "keymap.h" - -const keymap_t keymap_it = { - .base = { - [0] = -1, - [KEY_ESCAPE] = 27, - [KEY_ONE] = '1', - [KEY_TWO] = '2', - [KEY_THREE] = '3', - [KEY_FOUR] = '4', - [KEY_FIVE] = '5', - [KEY_SIX] = '6', - [KEY_SEVEN] = '7', - [KEY_EIGHT] = '8', - [KEY_NINE] = '9', - [KEY_ZERO] = '0', - [KEY_APOSTROPHE] = '\'', - [KEY_I_ACC] = 141, - [KEY_BACKSPACE] = '\b', - [KEY_TAB] = '\t', - [KEY_Q] = 'q', - [KEY_W] = 'w', - [KEY_E] = 'e', - [KEY_R] = 'r', - [KEY_T] = 't', - [KEY_Y] = 'y', - [KEY_U] = 'u', - [KEY_I] = 'i', - [KEY_O] = 'o', - [KEY_P] = 'p', - [KEY_LEFT_BRAKET] = 138, - [KEY_RIGHT_BRAKET] = '+', - [KEY_ENTER] = 13, - [KEY_LEFT_CONTROL] = -1, - [KEY_A] = 'a', - [KEY_S] = 's', - [KEY_D] = 'd', - [KEY_F] = 'f', - [KEY_G] = 'g', - [KEY_H] = 'h', - [KEY_J] = 'j', - [KEY_K] = 'k', - [KEY_L] = 'l', - [KEY_SEMICOLON] = 149, - [KEY_DOUBLE_QUOTES] = 133, - [KEY_GRAVE] = '\\', - [KEY_LEFT_SHIFT] = -1, - [KEY_BACKSLASH] = 151, - [KEY_Z] = 'z', - [KEY_X] = 'x', - [KEY_C] = 'c', - [KEY_V] = 'v', - [KEY_B] = 'b', - [KEY_N] = 'n', - [KEY_M] = 'm', - [KEY_COMMA] = ',', - [KEY_PERIOD] = '.', - [KEY_MINUS] = '-', - [KEY_RIGHT_SHIFT] = -1, - [KEY_KP_MUL] = '*', - [KEY_LEFT_ALT] = -1, - [KEY_SPACE] = ' ', - [KEY_CAPS_LOCK] = -1, - [KEY_F1] = -1, - [KEY_F2] = -1, - [KEY_F3] = -1, - [KEY_F4] = -1, - [KEY_F5] = -1, - [KEY_F6] = -1, - [KEY_F7] = -1, - [KEY_F8] = -1, - [KEY_F9] = -1, - [KEY_F10] = -1, - [KEY_NUM_LOCK] = -1, - [KEY_SCROLL_LOCK] = -1, - [KEY_KP7] = -1, - [KEY_KP8] = -1, - [KEY_KP9] = -1, - [KEY_KP_SUB] = '-', - [KEY_KP4] = -1, - [KEY_KP5] = -1, - [KEY_KP6] = -1, - [KEY_KP_ADD] = '+', - [KEY_KP1] = -1, - [KEY_KP2] = -1, - [KEY_KP3] = -1, - [KEY_KP0] = -1, - [KEY_KP_DEC] = -1, - [84] = -1, - [85] = -1, - [KEY_KP_LESS] = '<', - [87] = -1, - [88] = -1, - [KEY_KP_DIV] = '/' - }, - .shift = { - [0] = -1, - [KEY_ESCAPE] = -1, - [KEY_ONE] = '!', - [KEY_TWO] = '"', - [KEY_THREE] = 156, - [KEY_FOUR] = '$', - [KEY_FIVE] = '%', - [KEY_SIX] = '&', - [KEY_SEVEN] = '/', - [KEY_EIGHT] = '(', - [KEY_NINE] = ')', - [KEY_ZERO] = '=', - [KEY_APOSTROPHE] = '?', - [KEY_I_ACC] = '^', - [KEY_BACKSPACE] = -1, - [KEY_TAB] = -1, - [KEY_Q] = 'Q', - [KEY_W] = 'W', - [KEY_E] = 'E', - [KEY_R] = 'R', - [KEY_T] = 'T', - [KEY_Y] = 'Y', - [KEY_U] = 'U', - [KEY_I] = 'I', - [KEY_O] = 'O', - [KEY_P] = 'P', - [KEY_LEFT_BRAKET] = 130, - [KEY_RIGHT_BRAKET] = '*', - [KEY_ENTER] = -1, - [KEY_LEFT_CONTROL] = -1, - [KEY_A] = 'A', - [KEY_S] = 'S', - [KEY_D] = 'D', - [KEY_F] = 'F', - [KEY_G] = 'G', - [KEY_H] = 'H', - [KEY_J] = 'J', - [KEY_K] = 'K', - [KEY_L] = 'L', - [KEY_SEMICOLON] = 128, - [KEY_DOUBLE_QUOTES] = 167, - [KEY_GRAVE] = '|', - [KEY_LEFT_SHIFT] = -1, - [KEY_BACKSLASH] = -1, - [KEY_Z] = 'Z', - [KEY_X] = 'X', - [KEY_C] = 'C', - [KEY_V] = 'V', - [KEY_B] = 'B', - [KEY_N] = 'N', - [KEY_M] = 'M', - [KEY_COMMA] = ';', - [KEY_PERIOD] = ':', - [KEY_MINUS] = '_', - [KEY_RIGHT_SHIFT] = -1, - [KEY_KP_MUL] = '*', - [KEY_LEFT_ALT] = -1, - [KEY_SPACE] = ' ', - [KEY_CAPS_LOCK] = -1, - [KEY_F1] = -1, - [KEY_F2] = -1, - [KEY_F3] = -1, - [KEY_F4] = -1, - [KEY_F5] = -1, - [KEY_F6] = -1, - [KEY_F7] = -1, - [KEY_F8] = -1, - [KEY_F9] = -1, - [KEY_F10] = -1, - [KEY_NUM_LOCK] = -1, - [KEY_SCROLL_LOCK] = -1, - [KEY_KP7] = -1, - [KEY_KP8] = -1, - [KEY_KP9] = -1, - [KEY_KP_SUB] = '-', - [KEY_KP4] = -1, - [KEY_KP5] = -1, - [KEY_KP6] = -1, - [KEY_KP_ADD] = '+', - [KEY_KP1] = -1, - [KEY_KP2] = -1, - [KEY_KP3] = -1, - [KEY_KP0] = -1, - [KEY_KP_DEC] = -1, - [84] = -1, - [85] = -1, - [KEY_KP_LESS] = '>', - [87] = -1, - [88] = -1, - [KEY_KP_DIV] = '/' - }, - .numlock = { - [KEY_KP_DEC] = '.', - [KEY_KP0] = '0', - [KEY_KP1] = '1', - [KEY_KP2] = '2', - [KEY_KP3] = '3', - [KEY_KP4] = '4', - [KEY_KP5] = '5', - [KEY_KP6] = '6', - [KEY_KP7] = '7', - [KEY_KP8] = '8', - [KEY_KP9] = '9', - }, -}; +/// MentOS, The Mentoring Operating system project +/// @file keymap.c +/// @brief Keymap for keyboard. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "keymap.h" + +const keymap_t keymap_it = { + .base = { + [0] = -1, + [KEY_ESCAPE] = 27, + [KEY_ONE] = '1', + [KEY_TWO] = '2', + [KEY_THREE] = '3', + [KEY_FOUR] = '4', + [KEY_FIVE] = '5', + [KEY_SIX] = '6', + [KEY_SEVEN] = '7', + [KEY_EIGHT] = '8', + [KEY_NINE] = '9', + [KEY_ZERO] = '0', + [KEY_APOSTROPHE] = '\'', + [KEY_I_ACC] = 141, + [KEY_BACKSPACE] = '\b', + [KEY_TAB] = '\t', + [KEY_Q] = 'q', + [KEY_W] = 'w', + [KEY_E] = 'e', + [KEY_R] = 'r', + [KEY_T] = 't', + [KEY_Y] = 'y', + [KEY_U] = 'u', + [KEY_I] = 'i', + [KEY_O] = 'o', + [KEY_P] = 'p', + [KEY_LEFT_BRAKET] = 138, + [KEY_RIGHT_BRAKET] = '+', + [KEY_ENTER] = 13, + [KEY_LEFT_CONTROL] = -1, + [KEY_A] = 'a', + [KEY_S] = 's', + [KEY_D] = 'd', + [KEY_F] = 'f', + [KEY_G] = 'g', + [KEY_H] = 'h', + [KEY_J] = 'j', + [KEY_K] = 'k', + [KEY_L] = 'l', + [KEY_SEMICOLON] = 149, + [KEY_DOUBLE_QUOTES] = 133, + [KEY_GRAVE] = '\\', + [KEY_LEFT_SHIFT] = -1, + [KEY_BACKSLASH] = 151, + [KEY_Z] = 'z', + [KEY_X] = 'x', + [KEY_C] = 'c', + [KEY_V] = 'v', + [KEY_B] = 'b', + [KEY_N] = 'n', + [KEY_M] = 'm', + [KEY_COMMA] = ',', + [KEY_PERIOD] = '.', + [KEY_MINUS] = '-', + [KEY_RIGHT_SHIFT] = -1, + [KEY_KP_MUL] = '*', + [KEY_LEFT_ALT] = -1, + [KEY_SPACE] = ' ', + [KEY_CAPS_LOCK] = -1, + [KEY_F1] = -1, + [KEY_F2] = -1, + [KEY_F3] = -1, + [KEY_F4] = -1, + [KEY_F5] = -1, + [KEY_F6] = -1, + [KEY_F7] = -1, + [KEY_F8] = -1, + [KEY_F9] = -1, + [KEY_F10] = -1, + [KEY_NUM_LOCK] = -1, + [KEY_SCROLL_LOCK] = -1, + [KEY_KP7] = -1, + [KEY_KP8] = -1, + [KEY_KP9] = -1, + [KEY_KP_SUB] = '-', + [KEY_KP4] = -1, + [KEY_KP5] = -1, + [KEY_KP6] = -1, + [KEY_KP_ADD] = '+', + [KEY_KP1] = -1, + [KEY_KP2] = -1, + [KEY_KP3] = -1, + [KEY_KP0] = -1, + [KEY_KP_DEC] = -1, + [84] = -1, + [85] = -1, + [KEY_KP_LESS] = '<', + [87] = -1, + [88] = -1, + [KEY_KP_DIV] = '/' + }, + .shift = { + [0] = -1, + [KEY_ESCAPE] = -1, + [KEY_ONE] = '!', + [KEY_TWO] = '"', + [KEY_THREE] = 156, + [KEY_FOUR] = '$', + [KEY_FIVE] = '%', + [KEY_SIX] = '&', + [KEY_SEVEN] = '/', + [KEY_EIGHT] = '(', + [KEY_NINE] = ')', + [KEY_ZERO] = '=', + [KEY_APOSTROPHE] = '?', + [KEY_I_ACC] = '^', + [KEY_BACKSPACE] = -1, + [KEY_TAB] = -1, + [KEY_Q] = 'Q', + [KEY_W] = 'W', + [KEY_E] = 'E', + [KEY_R] = 'R', + [KEY_T] = 'T', + [KEY_Y] = 'Y', + [KEY_U] = 'U', + [KEY_I] = 'I', + [KEY_O] = 'O', + [KEY_P] = 'P', + [KEY_LEFT_BRAKET] = 130, + [KEY_RIGHT_BRAKET] = '*', + [KEY_ENTER] = -1, + [KEY_LEFT_CONTROL] = -1, + [KEY_A] = 'A', + [KEY_S] = 'S', + [KEY_D] = 'D', + [KEY_F] = 'F', + [KEY_G] = 'G', + [KEY_H] = 'H', + [KEY_J] = 'J', + [KEY_K] = 'K', + [KEY_L] = 'L', + [KEY_SEMICOLON] = 128, + [KEY_DOUBLE_QUOTES] = 167, + [KEY_GRAVE] = '|', + [KEY_LEFT_SHIFT] = -1, + [KEY_BACKSLASH] = -1, + [KEY_Z] = 'Z', + [KEY_X] = 'X', + [KEY_C] = 'C', + [KEY_V] = 'V', + [KEY_B] = 'B', + [KEY_N] = 'N', + [KEY_M] = 'M', + [KEY_COMMA] = ';', + [KEY_PERIOD] = ':', + [KEY_MINUS] = '_', + [KEY_RIGHT_SHIFT] = -1, + [KEY_KP_MUL] = '*', + [KEY_LEFT_ALT] = -1, + [KEY_SPACE] = ' ', + [KEY_CAPS_LOCK] = -1, + [KEY_F1] = -1, + [KEY_F2] = -1, + [KEY_F3] = -1, + [KEY_F4] = -1, + [KEY_F5] = -1, + [KEY_F6] = -1, + [KEY_F7] = -1, + [KEY_F8] = -1, + [KEY_F9] = -1, + [KEY_F10] = -1, + [KEY_NUM_LOCK] = -1, + [KEY_SCROLL_LOCK] = -1, + [KEY_KP7] = -1, + [KEY_KP8] = -1, + [KEY_KP9] = -1, + [KEY_KP_SUB] = '-', + [KEY_KP4] = -1, + [KEY_KP5] = -1, + [KEY_KP6] = -1, + [KEY_KP_ADD] = '+', + [KEY_KP1] = -1, + [KEY_KP2] = -1, + [KEY_KP3] = -1, + [KEY_KP0] = -1, + [KEY_KP_DEC] = -1, + [84] = -1, + [85] = -1, + [KEY_KP_LESS] = '>', + [87] = -1, + [88] = -1, + [KEY_KP_DIV] = '/' + }, + .numlock = { + [KEY_KP_DEC] = '.', + [KEY_KP0] = '0', + [KEY_KP1] = '1', + [KEY_KP2] = '2', + [KEY_KP3] = '3', + [KEY_KP4] = '4', + [KEY_KP5] = '5', + [KEY_KP6] = '6', + [KEY_KP7] = '7', + [KEY_KP8] = '8', + [KEY_KP9] = '9', + }, +}; diff --git a/mentos/src/drivers/mouse.c b/mentos/src/drivers/mouse.c index 1073d79..1e09bfe 100644 --- a/mentos/src/drivers/mouse.c +++ b/mentos/src/drivers/mouse.c @@ -1,175 +1,175 @@ -/// MentOS, The Mentoring Operating system project -/// @file mouse.c -/// @brief Driver for *PS2* Mouses. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "mouse.h" -#include "pic8259.h" - -static uint8_t mouse_cycle = 0; - -static int8_t mouse_bytes[3]; - -static int32_t mouse_x = (800 / 2); - -static int32_t mouse_y = (600 / 2); - -void mouse_install() -{ - // Enable the auxiliary mouse device. - mouse_waitcmd(1); - outportb(0x64, 0xA8); - - // Enable the interrupts. - mouse_waitcmd(1); - outportb(0x64, 0x20); - mouse_waitcmd(0); - uint8_t status_byte = (inportb(0x60) | 2); - mouse_waitcmd(1); - outportb(0x64, 0x60); - mouse_waitcmd(1); - outportb(0x60, status_byte); - - // Tell the mouse to use default settings. - mouse_write(MOUSE_USE_DEFAULT_SETTINGS); - // Acknowledge. - mouse_read(); - - // Setup the mouse handler. - // pic8259_irq_install_handler(IRQ_MOUSE, mouse_isr); - - mouse_enable(); -} - -void mouse_enable() -{ - // Enable the mouse interrupts. - pic8259_irq_enable(IRQ_MOUSE); - // Disable the mouse. - mouse_write(MOUSE_ENABLE_PACKET); - // Acknowledge. - mouse_read(); -} - -void mouse_disable() -{ - // Disable the mouse interrupts. - pic8259_irq_disable(IRQ_MOUSE); - // Disable the mouse. - mouse_write(MOUSE_DISABLE_PACKET); - // Acknowledge. - mouse_read(); -} - -void mouse_waitcmd(unsigned char type) -{ - register unsigned int _time_out = 100000; - if (type == 0) { - // DATA. - while (_time_out--) { - if ((inportb(0x64) & 1) == 1) { - return; - } - } - return; - } else { - while (_time_out--) // SIGNALS - { - if ((inportb(0x64) & 2) == 0) { - return; - } - } - return; - } -} - -void mouse_write(unsigned char data) -{ - mouse_waitcmd(1); - outportb(0x64, 0xD4); - mouse_waitcmd(1); - outportb(0x60, data); -} - -unsigned char mouse_read() -{ - mouse_waitcmd(0); - return inportb(0x60); -} - -void mouse_isr(register_t *r) -{ - (void)r; - // Get the input bytes. - mouse_bytes[mouse_cycle++] = (char)inportb(0x60); - if (mouse_cycle == 3) { - // Reset the mouse cycle. - mouse_cycle = 0; - // ---------------------------- - // Get the X coordinates. - // ---------------------------- - if ((mouse_bytes[0] & 0x40) == 0) { - // Bit number 4 of the first byte (value 0x10) indicates that - // delta X (the 2nd byte) is a negative number, if it is set. - if ((mouse_bytes[0] & 0x10) == 0) { - mouse_x -= mouse_bytes[1]; - } else { - mouse_x += mouse_bytes[1]; - } - } else { - // Overflow. - mouse_x += mouse_bytes[1] / 2; - } - // ---------------------------- - // Get the Y coordinates. - // ---------------------------- - if ((mouse_bytes[0] & 0x80) == 0) { - // Bit number 5 of the first byte (value 0x20) indicates that - // delta Y (the 3rd byte) is a negative number, if it is set. - if ((mouse_bytes[0] & 0x20) == 0) { - mouse_y -= mouse_bytes[2]; - } else { - mouse_y += mouse_bytes[2]; - } - } else { - // Overflow. - mouse_y -= mouse_bytes[2] / 2; - } - // ---------------------------- - // Apply cursor constraint (800x600). - // ---------------------------- - if (mouse_x <= 0) { - mouse_x = 0; - } else if (mouse_x >= (800 - 16)) { - mouse_x = 800 - 16; - } - if (mouse_y <= 0) { - mouse_y = 0; - } else if (mouse_y >= (600 - 24)) { - mouse_y = 600 - 24; - } - // Print the position. - // dbg_print("\rX: %d | Y: %d\n", mouse_x, mouse_y); - - // Move the cursor. - // video_set_cursor(mouse_x, mouse_y); - - // Here a problem is detected, if the mouse moves - // Pressed keys are detected. - // Detecting keystrokes. - // Center pressed. - if ((mouse_bytes[0] & 0x04) == 0) { - // dbg_print(LNG_MOUSE_MID); - } - // Right pressed. - if ((mouse_bytes[0] & 0x02) == 0) { - // dbg_print(LNG_MOUSE_RIGHT); - } - // Left pressed. - if ((mouse_bytes[0] & 0x01) == 0) { - // dbg_print(LNG_MOUSE_LEFT); - } - } - pic8259_send_eoi(IRQ_MOUSE); -} +/// MentOS, The Mentoring Operating system project +/// @file mouse.c +/// @brief Driver for *PS2* Mouses. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "mouse.h" +#include "pic8259.h" + +static uint8_t mouse_cycle = 0; + +static int8_t mouse_bytes[3]; + +static int32_t mouse_x = (800 / 2); + +static int32_t mouse_y = (600 / 2); + +void mouse_install() +{ + // Enable the auxiliary mouse device. + mouse_waitcmd(1); + outportb(0x64, 0xA8); + + // Enable the interrupts. + mouse_waitcmd(1); + outportb(0x64, 0x20); + mouse_waitcmd(0); + uint8_t status_byte = (inportb(0x60) | 2); + mouse_waitcmd(1); + outportb(0x64, 0x60); + mouse_waitcmd(1); + outportb(0x60, status_byte); + + // Tell the mouse to use default settings. + mouse_write(MOUSE_USE_DEFAULT_SETTINGS); + // Acknowledge. + mouse_read(); + + // Setup the mouse handler. + // pic8259_irq_install_handler(IRQ_MOUSE, mouse_isr); + + mouse_enable(); +} + +void mouse_enable() +{ + // Enable the mouse interrupts. + pic8259_irq_enable(IRQ_MOUSE); + // Disable the mouse. + mouse_write(MOUSE_ENABLE_PACKET); + // Acknowledge. + mouse_read(); +} + +void mouse_disable() +{ + // Disable the mouse interrupts. + pic8259_irq_disable(IRQ_MOUSE); + // Disable the mouse. + mouse_write(MOUSE_DISABLE_PACKET); + // Acknowledge. + mouse_read(); +} + +void mouse_waitcmd(unsigned char type) +{ + register unsigned int _time_out = 100000; + if (type == 0) { + // DATA. + while (_time_out--) { + if ((inportb(0x64) & 1) == 1) { + return; + } + } + return; + } else { + while (_time_out--) // SIGNALS + { + if ((inportb(0x64) & 2) == 0) { + return; + } + } + return; + } +} + +void mouse_write(unsigned char data) +{ + mouse_waitcmd(1); + outportb(0x64, 0xD4); + mouse_waitcmd(1); + outportb(0x60, data); +} + +unsigned char mouse_read() +{ + mouse_waitcmd(0); + return inportb(0x60); +} + +void mouse_isr(register_t *r) +{ + (void)r; + // Get the input bytes. + mouse_bytes[mouse_cycle++] = (char)inportb(0x60); + if (mouse_cycle == 3) { + // Reset the mouse cycle. + mouse_cycle = 0; + // ---------------------------- + // Get the X coordinates. + // ---------------------------- + if ((mouse_bytes[0] & 0x40) == 0) { + // Bit number 4 of the first byte (value 0x10) indicates that + // delta X (the 2nd byte) is a negative number, if it is set. + if ((mouse_bytes[0] & 0x10) == 0) { + mouse_x -= mouse_bytes[1]; + } else { + mouse_x += mouse_bytes[1]; + } + } else { + // Overflow. + mouse_x += mouse_bytes[1] / 2; + } + // ---------------------------- + // Get the Y coordinates. + // ---------------------------- + if ((mouse_bytes[0] & 0x80) == 0) { + // Bit number 5 of the first byte (value 0x20) indicates that + // delta Y (the 3rd byte) is a negative number, if it is set. + if ((mouse_bytes[0] & 0x20) == 0) { + mouse_y -= mouse_bytes[2]; + } else { + mouse_y += mouse_bytes[2]; + } + } else { + // Overflow. + mouse_y -= mouse_bytes[2] / 2; + } + // ---------------------------- + // Apply cursor constraint (800x600). + // ---------------------------- + if (mouse_x <= 0) { + mouse_x = 0; + } else if (mouse_x >= (800 - 16)) { + mouse_x = 800 - 16; + } + if (mouse_y <= 0) { + mouse_y = 0; + } else if (mouse_y >= (600 - 24)) { + mouse_y = 600 - 24; + } + // Print the position. + // dbg_print("\rX: %d | Y: %d\n", mouse_x, mouse_y); + + // Move the cursor. + // video_set_cursor(mouse_x, mouse_y); + + // Here a problem is detected, if the mouse moves + // Pressed keys are detected. + // Detecting keystrokes. + // Center pressed. + if ((mouse_bytes[0] & 0x04) == 0) { + // dbg_print(LNG_MOUSE_MID); + } + // Right pressed. + if ((mouse_bytes[0] & 0x02) == 0) { + // dbg_print(LNG_MOUSE_RIGHT); + } + // Left pressed. + if ((mouse_bytes[0] & 0x01) == 0) { + // dbg_print(LNG_MOUSE_LEFT); + } + } + pic8259_send_eoi(IRQ_MOUSE); +} diff --git a/mentos/src/elf/elf.c b/mentos/src/elf/elf.c index 372b0c4..ca306ef 100644 --- a/mentos/src/elf/elf.c +++ b/mentos/src/elf/elf.c @@ -1,74 +1,74 @@ -/// MentOS, The Mentoring Operating system project -/// @file elf.c -/// @brief Function for multiboot support. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "elf.h" -#include "debug.h" -#include "string.h" -#include "multiboot.h" - -/// @brief Data structure containg information about the kernel. -elf_symbols_t kernel_elf; - -/* - * This function grabs a pointer to the array of section headers. - * It then grabs a pointer to the section where all the strings are (.shstrtab) - * (remember that each section header has an offset to this .shstrtab) - * - * Then it's just a matter of iterating sections (checking their names via - * indexing shstrtab) until we find strtab and symtab, which is what we're - * looking for - */ -void build_elf_symbols_from_multiboot(multiboot_info_t *mb) -{ - uint32_t i; - elf_section_header_t *sh = (elf_section_header_t *)mb->u.elf_sec.addr; - - /* - * .shstrtab has the names of the sections, - * and sh is an array of sections, which themselves contain - * an index to .shstrtab (for their names) - */ - uint32_t shstrtab = sh[mb->u.elf_sec.shndx].addr; - for (i = 0; i < mb->u.elf_sec.num; i++) { - const char *name = - (const char *)(shstrtab + sh[i].name_offset_in_shstrtab); - if (!strcmp(name, ".strtab")) { - kernel_elf.strtab = (const char *)sh[i].addr; - kernel_elf.strtab_size = sh[i].size; - } - if (!strcmp(name, ".symtab")) { - kernel_elf.symtab = (elf_symbol_t *)sh[i].addr; - kernel_elf.symtab_size = sh[i].size; - } - } -} - -/* - * Iterate through all the symbols and look for functions... - * Then, as we find functions, check if the symbol is within that - * function's range (given by value and size) - */ -const char *elf_lookup_symbol(uint32_t addr, elf_symbols_t *elf) -{ - int i; - int num_symbols = elf->symtab_size / sizeof(elf_symbol_t); - - for (i = 0; i < num_symbols; i++) { - if (ELF32_ST_TYPE(elf->symtab[i].info) != ELF32_TYPE_FUNCTION) { - continue; - } - - if ((addr >= elf->symtab[i].value) && - (addr < (elf->symtab[i].value + elf->symtab[i].size))) { - const char *name = - (const char *)((uint32_t)elf->strtab + - elf->symtab[i].name_offset_in_strtab); - return name; - } - } - - return NULL; -} +/// MentOS, The Mentoring Operating system project +/// @file elf.c +/// @brief Function for multiboot support. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "elf.h" +#include "debug.h" +#include "string.h" +#include "multiboot.h" + +/// @brief Data structure containg information about the kernel. +elf_symbols_t kernel_elf; + +/* + * This function grabs a pointer to the array of section headers. + * It then grabs a pointer to the section where all the strings are (.shstrtab) + * (remember that each section header has an offset to this .shstrtab) + * + * Then it's just a matter of iterating sections (checking their names via + * indexing shstrtab) until we find strtab and symtab, which is what we're + * looking for + */ +void build_elf_symbols_from_multiboot(multiboot_info_t *mb) +{ + uint32_t i; + elf_section_header_t *sh = (elf_section_header_t *)mb->u.elf_sec.addr; + + /* + * .shstrtab has the names of the sections, + * and sh is an array of sections, which themselves contain + * an index to .shstrtab (for their names) + */ + uint32_t shstrtab = sh[mb->u.elf_sec.shndx].addr; + for (i = 0; i < mb->u.elf_sec.num; i++) { + const char *name = + (const char *)(shstrtab + sh[i].name_offset_in_shstrtab); + if (!strcmp(name, ".strtab")) { + kernel_elf.strtab = (const char *)sh[i].addr; + kernel_elf.strtab_size = sh[i].size; + } + if (!strcmp(name, ".symtab")) { + kernel_elf.symtab = (elf_symbol_t *)sh[i].addr; + kernel_elf.symtab_size = sh[i].size; + } + } +} + +/* + * Iterate through all the symbols and look for functions... + * Then, as we find functions, check if the symbol is within that + * function's range (given by value and size) + */ +const char *elf_lookup_symbol(uint32_t addr, elf_symbols_t *elf) +{ + int i; + int num_symbols = elf->symtab_size / sizeof(elf_symbol_t); + + for (i = 0; i < num_symbols; i++) { + if (ELF32_ST_TYPE(elf->symtab[i].info) != ELF32_TYPE_FUNCTION) { + continue; + } + + if ((addr >= elf->symtab[i].value) && + (addr < (elf->symtab[i].value + elf->symtab[i].size))) { + const char *name = + (const char *)((uint32_t)elf->strtab + + elf->symtab[i].name_offset_in_strtab); + return name; + } + } + + return NULL; +} diff --git a/mentos/src/experimental/deadlock_prevention.c b/mentos/src/experimental/deadlock_prevention.c new file mode 100644 index 0000000..7f824fe --- /dev/null +++ b/mentos/src/experimental/deadlock_prevention.c @@ -0,0 +1,108 @@ +/// MentOS, The Mentoring Operating system project +/// @file deadlock_prevention.c +/// @brief Deadlock prevention algorithms source code. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. +/// +/// Complete request() and state_safe() functions, according to what you learnt +/// in deadlock lectures. +/// +/// In order to complete the functions I prepared for you a library to manage +/// easily arrays. The library is arr_math.h and you can find the documentation +/// in include/util/arr_math.h header file. +/// +/// In addition you will find the same data structures that you have seen in +/// class: +/// - available: number of resources instances currently available; +/// - max: matrix of the maximum number of resources instances that each task +/// may require; +/// - alloc: matrix of current resources instances allocation of each task. +/// - need: matrix of current resources instances needs of each task. +/// Assume that these data structure are already filled with the +/// information described, in other words, you need to use these data structures +/// in read-only. +/// +/// Suggestion! +/// From arr_math.h you may need only: arr_g_any(), arr_add(), arr_sub(), +/// all() and arr_ne(); + +#include "deadlock_prevention.h" + +#include "arr_math.h" +#include "kheap.h" + +/// Array of resources instances currently available; +uint32_t * available; +/// Matrix of the maximum resources instances that each task may require; +uint32_t ** max; +/// Matrix of current resources instances allocation of each task. +uint32_t ** alloc; +/// Matrix of current resources instances need of each task. +uint32_t ** need; + +/// @brief Check if the current system resource allocation maintains the system +/// in a safe state. +/// @param n Number of tasks currently in the system. +/// @param m Number of resource types in the system (length of req_vec). +static bool_t state_safe(size_t n, size_t m) +{ + // Allocate work as a copy of available. + uint32_t *work = memcpy(kmalloc(sizeof(uint32_t) * m), available, + sizeof(uint32_t) * m); + + // Allocate finish initialized with all false (zeros). + uint32_t *finish = all(kmalloc(sizeof(uint32_t) * n), 0UL, n); + uint32_t *all_true = all(kmalloc(sizeof(uint32_t) * n), 1UL, n); + + int i; + // Loop while finish is not equal an array all true (ones). + while (/* ... */) + { + // Find a task that can satisfy all the resources it needs. + for (i = 0; i < n && (/* ... */ || /* ... */); i++); + if (i == n) + { + // Free memory. + kfree(work); + kfree(finish); + kfree(all_true); + return false; + } + else + { + // Assume to make available the resources that the task found needs. + /* ... */ + } + } + + // Free memory. + kfree(work); + kfree(finish); + kfree(all_true); + return true; +} + +deadlock_status_t request(uint32_t *req_vec, size_t task_i, size_t n, size_t m) +{ + if (/* ... */) + { + return ERROR; + } + + if (/* ... */) + { + return WAIT; + } + + // Try to allocate resources. + /* ... */ + + // Check safe state + if (/* ... */) + { + // Restore previous allocation. + /* ... */ + return WAIT_UNSAFE; + } + return SAFE; +} diff --git a/mentos/src/experimental/deadlock_simulation.c b/mentos/src/experimental/deadlock_simulation.c new file mode 100644 index 0000000..e59cf3f --- /dev/null +++ b/mentos/src/experimental/deadlock_simulation.c @@ -0,0 +1,318 @@ +/** + * @author Mirco De Marchi + * @date 2/02/2021 + * @brief Source file for deadlock deterministic simulation. + * @copyright (c) University of Verona + */ + +#include "deadlock_simulation.h" +#include "deadlock_prevention.h" +#include "resource.h" +#include "debug.h" +#include "arr_math.h" +#include "kheap.h" + +#define SIM_N 2 ///< Task amount on simulation. +#define SIM_M 2 ///< Resource type amount on simulation. + +/// @brief Simulation operations types. +typedef enum { + FREE, + LOCK, +} op_t; + +/// @brief Structure type for a task resource request. +typedef struct request { + pid_t req_task; ///< Process id. + op_t op; ///< Operation type. + uint32_t req_vec[SIM_M]; ///< Resource request vector. +} req_t; + +/// @brief Print available resources. +static void simulation_stats_available(); + +/// @brief Print resource request array. +/// @param req_vec Pointer to the resource request array. +/// @param length Length of resource request array. +static void simulation_stats_request(uint32_t *req_vec, size_t length); + +/// @brief Print stats of resources over tasks matrix. +/// @param header_str String name related with the matrix to print. +/// @param m Matrix to print stats. +/// @param r Row number of the matrix. +/// @param c Col number of the matrix. +static void simulation_stats_matrix(const char * header_str, uint32_t **m, + size_t r, size_t c); + +/// @brief Print system stats. +static void simulation_stats(); + +/// @brief Simulate a semaphore try lock. +static deadlock_status_t simulation_try_lock(uint32_t *req_vec, size_t task_i, + size_t n, size_t m); + +/// @brief Simulate a semaphore lock. +static void simulation_lock(uint32_t *req_vec, pid_t pid); + +/// @brief Simulate a semaphore free. +static void simulation_free(uint32_t *req_vec, pid_t pid); + +/// @brief Simulation initialization. +static void simulation_init(); + +/// @brief Simulation core. +static void simulation_start(); + +/// @brief Simulation end. +static void simulation_close(); + +/// @brief Initial number of instances of resource type R_j currently available. +uint32_t initial_available[SIM_M] = {1, 1}; +/// @brief Initial matrix of maximum resource request that each task require. +uint32_t initial_max[SIM_N][SIM_M] = {{1, 1}, {1, 1}}; +/// @brief Initial matrix of current resource allocation of each task. +uint32_t initial_alloc[SIM_N][SIM_M] = {{0, 0}, {0, 0}}; + +/// @brief Simulation requests. +req_t req_vec_test[] = { + {.req_task=0, .op=LOCK, .req_vec={1, 0}}, + {.req_task=1, .op=LOCK, .req_vec={0, 1}}, + {.req_task=0, .op=LOCK, .req_vec={0, 1}}, + {.req_task=1, .op=LOCK, .req_vec={0, 1}}, + {.req_task=0, .op=LOCK, .req_vec={0, 1}}, + {.req_task=0, .op=FREE, .req_vec={0, 1}}, + {.req_task=1, .op=LOCK, .req_vec={0, 1}}, + {.req_task=0, .op=FREE, .req_vec={1, 0}}, + {.req_task=1, .op=LOCK, .req_vec={1, 0}}, + {.req_task=1, .op=FREE, .req_vec={1, 0}}, + {.req_task=1, .op=FREE, .req_vec={0, 1}}, + {.req_task=1, .op=FREE, .req_vec={0, 1}}, +}; + +static void simulation_stats_available() +{ + dbg_print(" { "); + for (size_t j = 0; j < SIM_M-1; j++) + dbg_print("R_%i: %u, ", j, available[j]); + dbg_print("R_%d: %u }", SIM_M-1, available[SIM_M-1]); +} + +static void simulation_stats_request(uint32_t *req_vec, size_t length) +{ + dbg_print(" { "); + for (size_t j = 0; j < length-1; j++) + dbg_print("R_%i: %u, ", j, req_vec[j]); + dbg_print("R_%i: %u }", length-1, req_vec[length-1]); +} + +static void simulation_stats_matrix(const char * header_str, uint32_t **m, + size_t r, size_t c) +{ + const int col_size = 7; + const size_t tot_col = c + 1; + size_t j = 0; + + dbg_print(" "); + for (j = 0; j < (tot_col * col_size) - 1; j++) dbg_print("-"); + dbg_print("\n"); + + dbg_print("|"); + const size_t table_space = (tot_col * col_size) - strlen(header_str) - 1; + for (j = 0; j < table_space / 2; j++) dbg_print(" "); + dbg_print("%s", header_str); + for (; j < table_space; j++) dbg_print(" "); + dbg_print("|\n"); + + dbg_print("| Task |"); + for (j = 0; j < c; j++) dbg_print(" R_%-2i |", j); + dbg_print("\n"); + + for (size_t i = 0; i < r; i++) + { + dbg_print("| %4i |", i); + for (j = 0; j < c; j++) + dbg_print(" %4u |", m[i][j]); + dbg_print("\n"); + } + + dbg_print(" "); + for (j = 0; j < (tot_col * col_size) - 1; j++) dbg_print("-"); + dbg_print("\n"); +} + +static void simulation_stats() +{ + dbg_print("Tasks N: %i\n", SIM_N); + dbg_print("Resources M: %i\n", SIM_M); + + dbg_print("AVAILABLE:"); + simulation_stats_available(); + dbg_print("\n"); + + simulation_stats_matrix("MAX", max, SIM_N, SIM_M); + simulation_stats_matrix("ALLOC", alloc, SIM_N, SIM_M); + simulation_stats_matrix("NEED", need, SIM_N, SIM_M); +} + +static deadlock_status_t simulation_try_lock(uint32_t *req_vec, size_t task_i, + size_t n, size_t m) +{ +#if ENABLE_DEADLOCK_PREVENTION + return request(req_vec, task_i, n, m); +#else + return ERROR; +#endif +} + +static void simulation_lock(uint32_t *req_vec, pid_t pid) +{ + if (!(available && max && alloc && need)) + { + dbg_print("Some task-resource matrices NULL\n"); + return; + } + + switch (simulation_try_lock(req_vec, pid, SIM_N, SIM_M)) { + case SAFE: + dbg_print("LOCK (task: %d; req_vec:", pid); + simulation_stats_request(req_vec, SIM_M); + dbg_print(") SAFE: enjoy your resource\n"); + dbg_print("available:"); + simulation_stats_available(); + dbg_print("\n"); + simulation_stats_matrix("ALLOC", alloc, SIM_N, SIM_M); + break; + case WAIT: + dbg_print("LOCK (task %d; req_vec:", pid); + simulation_stats_request(req_vec, SIM_M); + dbg_print(") WAIT: resource busy\n"); + dbg_print("available:"); + simulation_stats_available(); + dbg_print("\n"); + simulation_stats_matrix("ALLOC", alloc, SIM_N, SIM_M); + break; + case WAIT_UNSAFE: + dbg_print("LOCK (task %d; rec_vec:", pid); + simulation_stats_request(req_vec, SIM_M); + dbg_print(") WAIT UNSAFE: deadlock detected\n"); + dbg_print("available:"); + simulation_stats_available(); + dbg_print("\n"); + simulation_stats_matrix("ALLOC", alloc, SIM_N, SIM_M); + break; + case ERROR: + dbg_print("LOCK (task %d; rec_vec:", pid); + simulation_stats_request(req_vec, SIM_M); + dbg_print(") ERROR: max matrix overflow\n"); + dbg_print("available:"); + simulation_stats_available(); + dbg_print("\n"); + simulation_stats_matrix("ALLOC", alloc, SIM_N, SIM_M); + break; + default: + return; + } +} + +static void simulation_free(uint32_t *req_vec, pid_t pid) +{ + if (arr_l_any(alloc[pid], req_vec, SIM_M)) + { + dbg_print("FREE (task %d; rec_vec:", pid); + simulation_stats_request(req_vec, SIM_M); + dbg_print(") ERROR: try to free a resource not own\n"); + dbg_print("available:"); + simulation_stats_available(); + dbg_print("\n"); + simulation_stats_matrix("ALLOC", alloc, SIM_N, SIM_M); + return; + } + + arr_add(available, req_vec, SIM_M); + arr_sub(alloc[pid], req_vec, SIM_M); + // Check what happen if you uncomment the following line. + // arr_add(need[pid], req_vec, SIM_M); + + dbg_print("FREE (task %d; rec_vec:", pid); + simulation_stats_request(req_vec, SIM_M); + dbg_print(")\n"); + dbg_print("available:"); + simulation_stats_available(); + dbg_print("\n"); + simulation_stats_matrix("ALLOC", alloc, SIM_N, SIM_M); +} + +static void simulation_init() +{ + available = (uint32_t *) kmalloc(SIM_M * sizeof(uint32_t)); + max = (uint32_t **) kmmalloc(SIM_N, SIM_M * sizeof(uint32_t)); + alloc = (uint32_t **) kmmalloc(SIM_N, SIM_M * sizeof(uint32_t)); + need = (uint32_t **) kmmalloc(SIM_N, SIM_M * sizeof(uint32_t)); + + memcpy(available, initial_available, SIM_M * sizeof(uint32_t)); + for (size_t i = 0; i < SIM_N; i++) + { + memcpy(max[i], initial_max[i], SIM_M * sizeof(uint32_t)); + memcpy(alloc[i], initial_alloc[i], SIM_M * sizeof(uint32_t)); + } + + // Calculate need[i][j] = max[i][j] - alloc[i][j]. + for (size_t i = 0; i < SIM_N; i++) + { + memcpy(need[i], max[i], SIM_M * sizeof(uint32_t)); + arr_sub(need[i], alloc[i], SIM_M); + } +} + +static void simulation_start() +{ + dbg_print("Deadlock Prevention: simulation start\n"); + for (size_t test = 0; test < sizeof(req_vec_test) / sizeof(req_t); test++) + { + uint32_t *req_vec = req_vec_test[test].req_vec; + pid_t task_pid = req_vec_test[test].req_task; + + switch (req_vec_test[test].op) + { + case FREE: + { + simulation_free(req_vec, task_pid); + break; + } + case LOCK: + { + simulation_lock(req_vec, task_pid); + break; + } + default: + { + dbg_print("Request vector operation type not recognized\n"); + break; + } + } + } +} + +static void simulation_close() +{ + kfree(available); + kmfree((void **) max, SIM_N); + kmfree((void **) alloc, SIM_N); + kmfree((void **) need, SIM_N); + max = NULL; + alloc = NULL; + need = NULL; +} + +void deadlock_simulation(int argc, char **argv) +{ +#if ENABLE_DEADLOCK_PREVENTION + dbg_print("Deadlock Prevention: enabled\n"); + simulation_init(); + simulation_stats(); + simulation_start(); + simulation_close(); +#else + dbg_print("Deadlock Prevention: disabled\n"); +#endif +} \ No newline at end of file diff --git a/mentos/src/experimental/math/arr_math.c b/mentos/src/experimental/math/arr_math.c new file mode 100644 index 0000000..55333f2 --- /dev/null +++ b/mentos/src/experimental/math/arr_math.c @@ -0,0 +1,106 @@ +/// MentOS, The Mentoring Operating system project +/// @file arr_math.c +/// @brief Array arithmetic operations source file- +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "arr_math.h" + +uint32_t *all(uint32_t *dst, uint32_t value, size_t length) +{ + for (size_t i = 0; i < length; i++) { + *(dst + i) = value; + } + return dst; +} + +uint32_t *arr_sub(uint32_t *left, const uint32_t *right, size_t length) +{ + for (size_t i = 0; i < length; i++) { + *(left + i) -= *(right + i); + } + return left; +} + +uint32_t *arr_add(uint32_t *left, const uint32_t *right, size_t length) +{ + for (size_t i = 0; i < length; i++) { + *(left + i) += *(right + i); + } + return left; +} + +bool_t arr_g_any(const uint32_t *left, const uint32_t *right, size_t length) +{ + for (size_t i = 0; i < length; i++) { + if (*(left + i) > *(right + i)) { + return true; + } + } + return false; +} + +bool_t arr_ge_any(const uint32_t *left, const uint32_t *right, size_t length) +{ + for (size_t i = 0; i < length; i++) { + if (*(left + i) >= *(right + i)) { + return true; + } + } + return false; +} + +bool_t arr_l_any(const uint32_t *left, const uint32_t *right, size_t length) +{ + for (size_t i = 0; i < length; i++) { + if (*(left + i) < *(right + i)) { + return true; + } + } + return false; +} + +bool_t arr_le_any(const uint32_t *left, const uint32_t *right, size_t length) +{ + for (size_t i = 0; i < length; i++) { + if (*(left + i) <= *(right + i)) { + return true; + } + } + return false; +} + +bool_t arr_g(const uint32_t *left, const uint32_t *right, size_t length) +{ + return !arr_le_any(left, right, length); +} + +bool_t arr_ge(const uint32_t *left, const uint32_t *right, size_t length) +{ + return !arr_l_any(left, right, length); +} + +bool_t arr_l(const uint32_t *left, const uint32_t *right, size_t length) +{ + return !arr_ge_any(left, right, length); +} + +bool_t arr_le(const uint32_t *left, const uint32_t *right, size_t length) +{ + return !arr_g_any(left, right, length); +} + +bool_t arr_e(const uint32_t *left, const uint32_t *right, size_t length) +{ + for (size_t i = 0; i < length; i++) { + if (*(left + i) != *(right + i)) { + return false; + } + } + return true; +} + +bool_t arr_ne(const uint32_t *left, const uint32_t *right, size_t length) +{ + return !arr_e(left, right, length); +} diff --git a/mentos/src/experimental/resource.c b/mentos/src/experimental/resource.c new file mode 100644 index 0000000..69b440a --- /dev/null +++ b/mentos/src/experimental/resource.c @@ -0,0 +1,277 @@ +/// MentOS, The Mentoring Operating system project +/// @file resource.c +/// @brief Resource definition source code. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "resource.h" +#include "kheap.h" +#include "string.h" +#include "arr_math.h" + +/// The list of processes. +extern runqueue_t runqueue; +/// The list of resources. +resource_list_t r_list; + +/// Array of resources instances currently available; +uint32_t * available; +/// Matrix of the maximum resources instances that each task may require; +uint32_t ** max; +/// Matrix of current resources instances allocation of each task. +uint32_t ** alloc; +/// Matrix of current resources instances need of each task. +uint32_t ** need; + +/// @brief Remove the resource reference dependency from each task in running +/// state. +/// @param r Resource pointer. +static void clean_resource_reference(resource_t *r) +{ + if (!r) return; + // Loop on running tasks. + list_head *it; + list_for_each (it, &runqueue.queue) { + task_struct *entry = list_entry(it, task_struct, run_list); + if (entry != NULL) { + // Loop on resources that tasks depend on. + for (size_t r_i = 0; r_i < TASK_RESOURCE_MAX_AMOUNT; r_i++) { + // Clean the resource reference in the task resources list. + if (entry->resources[r_i] == r) { + entry->resources[r_i] = NULL; + } + } + } + } +} + +/// @brief Generate the idx_map_task_struct array, that maps an index with a +/// related process. +/// @param idx_map_task_struct Pointer of the array already allocated to fill. +/// @return The same pointer passed as parameter. +static task_struct **compute_index_map_task_struct( + task_struct *idx_map_task_struct[]) +{ + // Loop on running tasks. + list_head *task_it; + size_t t_i = 0; + list_for_each (task_it, &runqueue.queue) { + task_struct *task = list_entry(task_it, task_struct, run_list); + if (task != NULL) { + // Map a task with an index. + idx_map_task_struct[t_i] = task; + t_i++; + } + } + + return idx_map_task_struct; +} + +/// @brief Generate the available array, that contains the resources instances +/// currently available. +/// @param available Pointer of the array already allocated to fill. +/// @return The same pointer passed as parameter. +static uint32_t *fill_available(uint32_t *available) +{ + // Loop on resources created. + list_head *resource_it; + list_for_each (resource_it, &r_list.head) { + resource_t *resource = list_entry(resource_it, resource_t, + resources_list); + available[resource->rid] = + resource->n_instances - resource->assigned_instances; + } + + return available; +} + +/// @brief Generate the max matrix, that contains the maximum number of +/// resources instances that each task may require. +/// @param max Pointer of the matrix already allocated to fill. +/// @param idx_map_task_struct Pointer to the array of index and tasks mapping. +/// @return The same pointer passed as first parameter. +static uint32_t **fill_max(uint32_t **max, task_struct *idx_map_task_struct[]) +{ + // Loop on all tasks. + size_t n = kernel_get_active_processes(); + size_t m = kernel_get_active_resources(); + for (size_t t_i = 0; t_i < n; t_i++) { + task_struct *task = idx_map_task_struct[t_i]; + if (task != NULL) { + // Find resources needed by the task. + for (size_t r_i = 0; r_i < m; r_i++) { + if (task->resources[r_i] != NULL) { + max[t_i][r_i] = task->resources[r_i]->n_instances; + } + } + } + } + + return max; +} + +/// @brief Generate the alloc matrix, that contains the current resources +/// instances allocated for each task. +/// @param alloc Pointer of the matrix already allocated to fill. +/// @param idx_map_task_struct Pointer to the array of index and tasks mapping. +/// @return The same pointer passed as first parameter. +static uint32_t **fill_alloc(uint32_t **alloc, + task_struct *idx_map_task_struct[]) +{ + size_t n = kernel_get_active_processes(); + // Loop on resources created. + list_head *resource_it; + list_for_each (resource_it, &r_list.head) { + resource_t *resource = list_entry(resource_it, resource_t, + resources_list); + // Find the task with this resource assigned and take the instances num. + for (size_t t_i = 0; t_i < n; t_i++) { + if (idx_map_task_struct[t_i] == resource->assigned_task) { + alloc[t_i][resource->rid] = resource->assigned_instances; + } + } + } + + return alloc; +} + +/// @brief Generate the need matrix, that contains the current resources +/// instances need of each task. +/// @param need Pointer of the matrix already allocated to fill. +/// @param max Pointer to the max matrix. +/// @param alloc Pointer to the alloc matrix. +/// @return The same pointer passed as first parameter. +static uint32_t **fill_need(uint32_t **need, uint32_t **max, uint32_t **alloc) +{ + // Calculate need[i][j] = max[i][j] - alloc[i][j]. + size_t n = kernel_get_active_processes(); + size_t m = kernel_get_active_resources(); + for (size_t i = 0; i < n; i++) { + memcpy(need[i], max[i], m * sizeof(uint32_t)); + arr_sub(need[i], alloc[i], m); + } + return need; +} + +resource_t *resource_create(const char *category) +{ + // Check if current task can allocate a new resource. + task_struct *current_task = kernel_get_current_process(); + size_t i = 0; + while(current_task->resources[i] != NULL) { + i++; + + if (i >= TASK_RESOURCE_MAX_AMOUNT) { + return NULL; + } + } + + // Allocate new resource and initialize it. + resource_t *new = kmalloc(sizeof(resource_t)); + memset(new, 0, sizeof(resource_t)); + new->rid = r_list.num_active++; + new->category = category; + + // Current task is one of the tasks that need for this resource allocation. + current_task->resources[i] = new; + // The number of resource instances: for now always 1. + new->n_instances = 1; + + // Initialize the list_head. + list_head_init(&new->resources_list); + list_head_add_tail(&new->resources_list, &r_list.head); + + return new; +} + +void resource_init(resource_t *r) +{ + if (!r) return; + r->assigned_task = NULL; + r->assigned_instances = 0; +} + +void resource_destroy(resource_t *r) +{ + if (!r) return; + // Remove pointer of this resource from running processes. + clean_resource_reference(r); + // Remove this resource from resources list. + list_head_del(&r->resources_list); + kfree(r); + r_list.num_active--; + + // Normalize resource ids. + list_head *resource_it; + size_t rid = 0; + list_for_each (resource_it, &r_list.head) { + resource_t *resource = list_entry(resource_it, resource_t, + resources_list); + if (resource != NULL) { + resource->rid = rid; + } + } +} + +void resource_assign(resource_t *r) +{ + if (!r) return; + // Assign resource to current task. + r->assigned_task = kernel_get_current_process(); + // Number of instances assigned, for now always 1. + r->assigned_instances = 1; +} + +void resource_deassign(resource_t *r) +{ + if (!r) return; + r->assigned_task = NULL; + r->assigned_instances = 0; +} + +void init_deadlock_structures(uint32_t *available, uint32_t **max, + uint32_t **alloc, uint32_t **need, + task_struct *idx_map_task_struct[]) +{ + reset_deadlock_structures(available, max, alloc, idx_map_task_struct); + compute_index_map_task_struct(idx_map_task_struct); + fill_alloc(alloc, idx_map_task_struct); + fill_max(max, idx_map_task_struct); + fill_available(available); + fill_need(need, max, alloc); +} + +void reset_deadlock_structures(uint32_t *available, uint32_t **max, + uint32_t **alloc, task_struct *idx_map_task_struct[]) +{ + size_t n = kernel_get_active_processes(); + size_t m = kernel_get_active_resources(); + + // Clean idx_map_task_struct and rows of max and alloc. + for (size_t t_i = 0; t_i < n; t_i++) { + idx_map_task_struct[t_i] = NULL; + memset(alloc[t_i], 0, m * sizeof(uint32_t)); + memset(max[t_i], 0, m * sizeof(uint32_t)); + } + + // Clean row of resources. + memset(available, 0, m * sizeof(uint32_t)); +} + +size_t kernel_get_active_resources() +{ + return r_list.num_active; +} + +int32_t get_current_task_idx_from(task_struct *idx_map_task_struct[]) +{ + size_t n = kernel_get_active_processes(); + int32_t ret = -1; + for (size_t t_i = 0; t_i < n; t_i++) { + if (idx_map_task_struct[t_i] == kernel_get_current_process()) { + ret = t_i; + break; + } + } + return ret; +} diff --git a/mentos/src/experimental/smart_sem_kernel.c b/mentos/src/experimental/smart_sem_kernel.c new file mode 100644 index 0000000..cbf7373 --- /dev/null +++ b/mentos/src/experimental/smart_sem_kernel.c @@ -0,0 +1,186 @@ +/// MentOS, The Mentoring Operating system project +/// @file smart_sem_kernel.c +/// @brief Smart semaphore kernel-side implementation source code. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "smart_sem_kernel.h" + +#include "errno.h" +#include "resource.h" +#include "kheap.h" +#include "deadlock_prevention.h" +#include "panic.h" +#include "debug.h" + +/// Max number of semaphore that the operating system can manage. +#define SEM_MAX 356 +/// Max value of a semaphore. WIP +#define SEM_VALUE_MAX 32 + +/// @brief Smart semaphore descriptor. +typedef struct { + /// Semaphore value. The initialization value is 0. + volatile atomic_t value; + /// Semaphore mutex value. The initialization value is 0. + volatile atomic_t mutex; + /// Set to true if this semaphore instance is used, otherwise is false. + bool_t used; + /// Reference to the resource related with the semaphore used. If semaphore + /// is not used, this pointer is NULL. + resource_t *sem_resource; +} smart_sem_t; + +/// Global array of all smart semaphores that can be allocated. +smart_sem_t semaphores[SEM_MAX] = { 0 }; + +/// @brief Check if the semaphore is available and if it can be safety taken. If +/// the acquisition is safe, it set the semaphore value. +/// Safety check is done only if ENABLE_DEADLOCK_PREVENTION is true. +/// @param id Smart semaphore id. +/// @return True if semaphore can be safely acquired, otherwise if the +/// semaphore acquisition is unsafe or not available, return false. +static bool_t sys_sem_try(int id) +{ +#if ENABLE_DEADLOCK_PREVENTION + // Init deadlock prevention structures. + size_t n = kernel_get_active_processes(); + size_t m = kernel_get_active_resources(); + available = (uint32_t *) kmalloc(m * sizeof(uint32_t)); + max = (uint32_t **) kmmalloc(n, m * sizeof(uint32_t)); + alloc = (uint32_t **) kmmalloc(n, m * sizeof(uint32_t)); + need = (uint32_t **) kmmalloc(n, m * sizeof(uint32_t)); + task_struct **idx_map_task_struct = (task_struct **) kmalloc( + n * sizeof(task_struct *)); + if (available && max && alloc && need && idx_map_task_struct) { + init_deadlock_structures(available, max, alloc, need, + idx_map_task_struct); + } else { + kernel_panic("not able to perform allocation for deadlock prevention"); + } + + // Init request vector. + uint32_t *req_vec = (uint32_t *) kmalloc(m * sizeof(uint32_t)); + if (req_vec) { + memset(req_vec, 0, m * sizeof(uint32_t)); + req_vec[semaphores[id].sem_resource->rid] = 1; + } else { + kernel_panic("not able to perform allocation for deadlock prevention"); + } + + // Find current task correct index. + int32_t current_task_idx = get_current_task_idx_from(idx_map_task_struct); + if (current_task_idx < 0) { + kernel_panic("did't find current task in idx_map_task_struct array"); + } + + // Perform request. + bool_t ret = false; + switch (request(req_vec, current_task_idx, n, m)) { + case WAIT: + case WAIT_UNSAFE: + break; + case SAFE: + if (atomic_set_and_test(&semaphores[id].value, 1) == 0) { + ret = true; + } else { + kernel_panic("allocation request return bad safe status"); + } + break; + case ERROR: + default: + kernel_panic("deadlock prevention error"); + } + + kfree(available); + kmfree((void **) max, n); + kmfree((void **) alloc, n); + kmfree((void **) need, n); + kfree(idx_map_task_struct); + kfree(req_vec); + max = NULL; + alloc = NULL; + need = NULL; + + return ret; +#else + dbg_print("sys_sem_try(%d)\n", id); + return atomic_set_and_test(&semaphores[id].value, 1) == 0; +#endif +} + +int sys_sem_create() +{ + int id = -1; + for (unsigned i = 0; i < SEM_MAX; ++i) { + if (!semaphores[i].used) { + semaphores[i].sem_resource = resource_create("sem"); + if (!semaphores[i].sem_resource) { + return -1; + } + + semaphores[i].used = true; + id = (int)i; + break; + } + } + dbg_print("sys_sem_create() -> %d\n", id); + return id; +} + +int sys_sem_destroy(int id) +{ + dbg_print("sys_sem_destroy(%d)\n", id); + if ((id < 0) || (id > SEM_MAX)) { + return -1; + } + semaphores[id].used = false; + resource_destroy(semaphores[id].sem_resource); + return 0; +} + +int sys_sem_init(int id) +{ + dbg_print("sys_sem_init(%d)\n", id); + if ((id < 0) || (id > SEM_MAX)) { + return -1; + } + if (!semaphores[id].used) { + return -1; + } + atomic_set(&semaphores[id].value, 0); + resource_init(semaphores[id].sem_resource); + return 0; +} + +int sys_sem_try_acquire(int id) +{ + dbg_print("sys_sem_try_acquire(%d)\n", id); + if ((id < 0) || (id > SEM_MAX)) { + return -1; + } + if (!semaphores[id].used) { + return -1; + } + + if (sys_sem_try(id)) { + resource_assign(semaphores[id].sem_resource); + return 1; + } + + return 0; +} + +int sys_sem_release(int id) +{ + dbg_print("sys_sem_release(%d)\n", id); + if ((id < 0) || (id > SEM_MAX)) { + return -1; + } + if (!semaphores[id].used) { + return -1; + } + atomic_set(&semaphores[id].value, 0); + resource_deassign(semaphores[id].sem_resource); + return 0; +} diff --git a/mentos/src/experimental/smart_sem_user.c b/mentos/src/experimental/smart_sem_user.c new file mode 100644 index 0000000..8bb4e00 --- /dev/null +++ b/mentos/src/experimental/smart_sem_user.c @@ -0,0 +1,69 @@ +/// MentOS, The Mentoring Operating system project +/// @file smart_sem_user.c +/// @brief Semaphore user-side implementation source code. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "smart_sem_user.h" + +#include "syscall.h" +#include "syscall_types.h" +#include "errno.h" +#include "debug.h" + +int sem_create() +{ + int retval = 0; + + /* ... */ + + dbg_print("sem_create() -> %d\n", retval); + + return retval; +} + +int sem_destroy(int id) +{ + int retval = 0; + + dbg_print("sem_destroy(%d)\n", id); + + /* ... */ + + return retval; +} + +int sem_init(int id) +{ + int retval = 0; + + dbg_print("sem_init(%d)\n", id); + + /* ... */ + + return retval; +} + +int sem_acquire(int id) +{ + int retval; + + dbg_print("sem_acquire(%d)\n", id); + + do { + /* ... */ + } while (retval != 1); + + return retval; +} + +int sem_release(int id) +{ + int retval = 0; + + dbg_print("sem_release(%d)\n", id); + + /* ... */ + + return retval; +} \ No newline at end of file diff --git a/mentos/src/fs/fcntl.c b/mentos/src/fs/fcntl.c index 68e3b80..e22ea03 100644 --- a/mentos/src/fs/fcntl.c +++ b/mentos/src/fs/fcntl.c @@ -1,30 +1,30 @@ -/// MentOS, The Mentoring Operating system project -/// @file fcntl.c -/// @brief Implementation of functions fcntl() and open(). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "fcntl.h" -#include "string.h" -#include "vfs.h" -#include "limits.h" - -int remove(const char *pathname) -{ - char absolute_path[PATH_MAX]; - strcpy(absolute_path, pathname); - if (pathname[0] != '/') { - get_absolute_path(absolute_path); - } - - int32_t mp_id = get_mountpoint_id(absolute_path); - if (mp_id < 0) { - return -1; - } - - if (mountpoint_list[mp_id].operations.remove_f == NULL) { - return -1; - } - - return mountpoint_list[mp_id].operations.remove_f(absolute_path); -} +/// MentOS, The Mentoring Operating system project +/// @file fcntl.c +/// @brief Implementation of functions fcntl() and open(). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "fcntl.h" +#include "string.h" +#include "vfs.h" +#include "limits.h" + +int remove(const char *pathname) +{ + char absolute_path[PATH_MAX]; + strcpy(absolute_path, pathname); + if (pathname[0] != '/') { + get_absolute_path(absolute_path); + } + + int32_t mp_id = get_mountpoint_id(absolute_path); + if (mp_id < 0) { + return -1; + } + + if (mountpoint_list[mp_id].operations.remove_f == NULL) { + return -1; + } + + return mountpoint_list[mp_id].operations.remove_f(absolute_path); +} diff --git a/mentos/src/fs/initrd.c b/mentos/src/fs/initrd.c index c80762e..04839f2 100644 --- a/mentos/src/fs/initrd.c +++ b/mentos/src/fs/initrd.c @@ -1,455 +1,455 @@ -/// MentOS, The Mentoring Operating system project -/// @file initrd.c -/// @brief Headers of functions for initrd filesystem. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "stdio.h" -#include "vfs.h" -#include "errno.h" -#include "debug.h" -#include "shell.h" -#include "kheap.h" -#include "fcntl.h" -#include "libgen.h" -#include "bitops.h" -#include "initrd.h" -#include "string.h" - -char *module_start[MAX_MODULES]; - -initrd_t *fs_specs; -initrd_file_t *fs_headers; -unsigned int fs_end; - -/// The list of file descriptors. -initrd_fd ird_descriptors[MAX_INITRD_DESCRIPTORS]; - -/// The currently opened file descriptor. -unsigned int cur_irdfd; - -static inline initrd_file_t *get_initrd_file(const char *path) -{ - for (uint32_t i = 0; i < MAX_FILES; ++i) { - // Discard the headers which has a different name. - if (strcmp(path, fs_headers[i].fileName) == 0) { - return &(fs_headers[i]); - } - } - - return NULL; -} - -static inline size_t get_free_header(initrd_file_t **free_header) -{ - for (size_t i = 0; i < MAX_FILES; ++i) { - // TODO: If the header has type 0, then I suppose it is not used. - if (fs_headers[i].file_type == 0) { - (*free_header) = &(fs_headers[i]); - return i; - } - } - - return 0; -} - -uint32_t initfs_init() -{ - fs_end = 0; - fs_specs = (initrd_t *)module_start[0]; - fs_headers = (initrd_file_t *)(module_start[0] + sizeof(initrd_t)); - - for (int i = 0; i < MAX_INITRD_DESCRIPTORS; ++i) { - ird_descriptors[i].file_descriptor = -1; - ird_descriptors[i].cur_pos = 0; - } - cur_irdfd = 0; - printf(" * Number of Files: %d\n", fs_specs->nfiles); - fs_end = fs_headers[(fs_specs->nfiles) - 1].offset + - fs_headers[(fs_specs->nfiles) - 1].length; - printf(" * Filesystem end : %d\n", fs_end); - //dump_initrd_fs(); - - return fs_specs->nfiles; -} - -DIR *initfs_opendir(const char *path) -{ - initrd_file_t *direntry = get_initrd_file(path); - - if ((direntry == NULL) && (strcmp(path, "/") != 0)) { - dbg_print("Cannot find '%s'\n", path); - - return NULL; - } - - DIR *pdir = kmalloc(sizeof(DIR)); - pdir->fd = -1; - pdir->cur_entry = 0; - strcpy(pdir->path, path); - - return pdir; -} - -int initfs_closedir(DIR *dirp) -{ - if (dirp != NULL) { - kfree(dirp); - } - - return 0; -} - -dirent_t *initrd_readdir(DIR *dirp) -{ - if (dirp->cur_entry >= MAX_FILES) { - return NULL; - } - - for (; dirp->cur_entry < MAX_FILES; ++dirp->cur_entry) { - initrd_file_t *entry = &fs_headers[dirp->cur_entry]; - if (entry->fileName[0] == '\0') { - continue; - } - // Get the directory of the file. - char *filedir = dirname(entry->fileName); - - // Check if directory path and file directory are the same, or if - // the directory is the root and the file directory is dot. - if (strcmp(dirp->path, filedir) == 0) { - dirp->entry.d_ino = dirp->cur_entry; - dirp->entry.d_type = entry->file_type; - strcpy(dirp->entry.d_name, entry->fileName); - ++dirp->cur_entry; - - return &(dirp->entry); - } - } - - return NULL; -} - -int initrd_mkdir(const char *path, mode_t mode) -{ - (void)mode; - initrd_file_t *direntry = NULL; - - // Check if the directory already exists. - direntry = get_initrd_file(path); - if (direntry != NULL) { - printf("initrd_mkdir: cannot create directory '%s': " - "File exists\n\n", - path); - return -1; - } - // Check if the directories before it exist. - if ((strcmp(dirname(path), ".") != 0) && - (strcmp(dirname(path), "/") != 0)) { - dbg_print("initrd_mkdir: %s\n", dirname(path)); - direntry = get_initrd_file(dirname(path)); - if (direntry == NULL) { - printf("initrd_mkdir: cannot create directory '%s': " - "No such file or directory\n\n", - path); - - return -1; - } - if ((direntry->file_type != FS_DIRECTORY) && - (direntry->file_type != FS_MOUNTPOINT)) { - printf("initrd_mkdir: cannot create directory '%s': " - "Not a directory\n\n", - path); - - return -1; - } - } - // Get a free header. - initrd_file_t *free_header = NULL; - get_free_header(&free_header); - if (free_header == NULL) { - printf("initrd_mkdir: cannot create directory '%s': " - "Maximum number of headers reached\n\n", - path); - - return -1; - } - // Create the directory. - free_header->magic = 0xBF; - strcpy(free_header->fileName, path); - free_header->file_type = FS_DIRECTORY; - free_header->uid = current_user.uid; - free_header->offset = ++fs_end; - free_header->length = 0; - // Increase the number of files. - ++fs_specs->nfiles; - - return 1; -} - -int initrd_rmdir(const char *path) -{ - initrd_file_t *direntry = NULL; - - // Check if the directory exists. - direntry = get_initrd_file(path); - if (direntry == NULL) { - //errno = ENOENT; - return -1; - } - - if ((direntry->file_type != FS_DIRECTORY)) { - //errno = ENOTDIR; - return -1; - } - - for (int i = 0; i < MAX_FILES; ++i) { - initrd_file_t *entry = &fs_headers[i]; - if (entry->fileName[0] == '\0') { - continue; - } - // Get the directory of the file. - char *filedir = dirname(entry->fileName); - // Check if directory path and file directory are the same. - if (strcmp(direntry->fileName, filedir) == 0) { - //errno = ENOTEMPTY; - return -1; - } - } - // Remove the directory. - direntry->magic = 0; - memset(direntry->fileName, 0, NAME_MAX); - direntry->file_type = 0; - direntry->uid = 0; - direntry->offset = 0; - direntry->length = 0; - // Decrease the number of files. - --fs_specs->nfiles; - - return 0; -} - -int initfs_open(const char *path, int flags, ...) -{ - // If we have reached the maximum number of descriptors, just try to find - // a non-used one. - if (cur_irdfd >= MAX_INITRD_DESCRIPTORS) { - // Reset the current ird file descriptor. - cur_irdfd = 0; - while ((ird_descriptors[cur_irdfd].file_descriptor != -1) && - (cur_irdfd < MAX_INITRD_DESCRIPTORS)) { - ++cur_irdfd; - } - } - - for (uint32_t it = 0; it < fs_specs->nfiles; ++it) { - // Discard the headers which has a different name. - if (strcmp(path, fs_headers[it].fileName) != 0) { - continue; - } - - // However, if the name is the same, but the file type is different, - // stop the function and return failure value. - if ((fs_headers[it].file_type == FS_DIRECTORY) || - (fs_headers[it].file_type == FS_MOUNTPOINT)) { - //errno = EISDIR; - return -1; - } - - if (has_flag(flags, O_CREAT)) { - //errno = EEXIST; - return -1; - } - - // Otherwise, if the file is correct, update - ird_descriptors[cur_irdfd].file_descriptor = it; - ird_descriptors[cur_irdfd].cur_pos = 0; - if (has_flag(flags, O_APPEND)) { - ird_descriptors[cur_irdfd].cur_pos = fs_headers[it].length; - } - - return cur_irdfd++; - } - if (has_flag(flags, O_CREAT)) { - // Check if the directories before it exist. - if ((strcmp(dirname(path), ".") != 0) && - (strcmp(dirname(path), "/") != 0)) { - initrd_file_t *direntry = get_initrd_file(dirname(path)); - if (direntry == NULL) { - //errno = ENOENT; - return -1; - } - } - // Get a free header. - initrd_file_t *free_header = NULL; - size_t fd = get_free_header(&free_header); - if (free_header == NULL) { - //errno = ENFILE; - return -1; - } - // Create the file. - free_header->magic = 0xBF; - strcpy(free_header->fileName, path); - free_header->file_type = FS_FILE; - free_header->uid = current_user.uid; - free_header->offset = ++fs_end; - free_header->length = 0; - // Set the descriptor. - ird_descriptors[cur_irdfd].file_descriptor = fd; - ird_descriptors[cur_irdfd].cur_pos = 0; - // Increase the number of files. - ++fs_specs->nfiles; - - return cur_irdfd++; - } - - //errno = ENOENT; - return -1; -} - -int initfs_remove(const char *path) -{ - initrd_file_t *file = get_initrd_file(path); - - if (file == NULL) { - return -1; - } - - if (file->file_type != FS_FILE) { - return -1; - } - - // Remove the directory. - file->magic = 0; - memset(file->fileName, 0, NAME_MAX); - file->file_type = 0; - file->uid = 0; - file->offset = 0; - file->length = 0; - // Decrease the number of files. - --fs_specs->nfiles; - - return 0; -} - -ssize_t initfs_read(int fildes, char *buf, size_t nbyte) -{ - // If the number of byte to read is zero, skip. - if (nbyte == 0) { - return 0; - } - - // Get the file descriptor of the file. - int lfd = ird_descriptors[fildes].file_descriptor; - - // Get the current position. - int read_pos = ird_descriptors[fildes].cur_pos; - - // Get the legnth of the file. - int file_size = fs_headers[lfd].length; - - // Get the begin of the file. - char *file_start = (module_start[0] + fs_headers[lfd].offset); - - // Declare an iterator. - size_t it = 0; - - while ((it < nbyte) && (read_pos < file_size)) { - *buf++ = file_start[read_pos]; - ++read_pos; - ++it; - } - - ird_descriptors[fildes].cur_pos = read_pos; - if (read_pos == file_size) { - return EOF; - } - - return nbyte; -} - -int initrd_stat(const char *path, stat_t *stat) -{ - int i; - i = 0; - - while (i < MAX_FILES) { - if (!strcmp(path, fs_headers[i].fileName)) { - stat->st_uid = fs_headers[i].uid; - stat->st_size = fs_headers[i].length; - - break; - } - i++; - } - //dbg_print("Initrd stat function\n"); - //buf->st_uid = 33; - if (i == MAX_FILES) { - return -1; - } else { - return 0; - } -} - -ssize_t initrd_write(int fildes, const void *buf, size_t nbyte) -{ - // If the number of byte to write is zero, skip. - if (nbyte == 0) { - return 0; - } - - // Make a copy of the buffer. - char *tmp = (char *)kmalloc(strlen(buf) * sizeof(char)); - strcpy(tmp, buf); - - // Get the file descriptor of the file. - int lfd = ird_descriptors[fildes].file_descriptor; - - printf("Please wait, im writing the world...\n"); - printf("And the world begun with those words: %s and his mark his: %d\n", - tmp, lfd); - // Get the begin of the file. - char *file_start = (module_start[0] + fs_headers[lfd].offset + - ird_descriptors[fildes].cur_pos); - // Declare an iterator. - size_t it = 0; - while (it <= nbyte) { - file_start[it] = tmp[it]; - ++it; - } - - // Increment the length of the file. - fs_headers[lfd].length = fs_headers[lfd].length + it; - // Free the memory of the temporary file. - kfree(tmp); - // Return the number of written bytes. - - return it; -} - -int initrd_close(int fildes) -{ - ird_descriptors[fildes].file_descriptor = -1; - ird_descriptors[fildes].cur_pos = 0; - - return 0; -} - -size_t initrd_nfiles() -{ - size_t nfiles = 0; - - for (size_t i = 0; i < MAX_FILES; ++i) { - if (fs_headers[i].file_type != 0) { - ++nfiles; - } - } - - return nfiles; -} - -void dump_initrd_fs() -{ - for (uint32_t i = 0; i < MAX_FILES; ++i) { - dbg_print("[%2d] %s\n", i, fs_headers[i].fileName); - } -} +/// MentOS, The Mentoring Operating system project +/// @file initrd.c +/// @brief Headers of functions for initrd filesystem. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "stdio.h" +#include "vfs.h" +#include "errno.h" +#include "debug.h" +#include "shell.h" +#include "kheap.h" +#include "fcntl.h" +#include "libgen.h" +#include "bitops.h" +#include "initrd.h" +#include "string.h" + +char *module_start[MAX_MODULES]; + +initrd_t *fs_specs; +initrd_file_t *fs_headers; +unsigned int fs_end; + +/// The list of file descriptors. +initrd_fd ird_descriptors[MAX_INITRD_DESCRIPTORS]; + +/// The currently opened file descriptor. +unsigned int cur_irdfd; + +static inline initrd_file_t *get_initrd_file(const char *path) +{ + for (uint32_t i = 0; i < MAX_FILES; ++i) { + // Discard the headers which has a different name. + if (strcmp(path, fs_headers[i].fileName) == 0) { + return &(fs_headers[i]); + } + } + + return NULL; +} + +static inline size_t get_free_header(initrd_file_t **free_header) +{ + for (size_t i = 0; i < MAX_FILES; ++i) { + // TODO: If the header has type 0, then I suppose it is not used. + if (fs_headers[i].file_type == 0) { + (*free_header) = &(fs_headers[i]); + return i; + } + } + + return 0; +} + +uint32_t initfs_init() +{ + fs_end = 0; + fs_specs = (initrd_t *)module_start[0]; + fs_headers = (initrd_file_t *)(module_start[0] + sizeof(initrd_t)); + + for (int i = 0; i < MAX_INITRD_DESCRIPTORS; ++i) { + ird_descriptors[i].file_descriptor = -1; + ird_descriptors[i].cur_pos = 0; + } + cur_irdfd = 0; + printf(" * Number of Files: %d\n", fs_specs->nfiles); + fs_end = fs_headers[(fs_specs->nfiles) - 1].offset + + fs_headers[(fs_specs->nfiles) - 1].length; + printf(" * Filesystem end : %d\n", fs_end); + //dump_initrd_fs(); + + return fs_specs->nfiles; +} + +DIR *initfs_opendir(const char *path) +{ + initrd_file_t *direntry = get_initrd_file(path); + + if ((direntry == NULL) && (strcmp(path, "/") != 0)) { + dbg_print("Cannot find '%s'\n", path); + + return NULL; + } + + DIR *pdir = kmalloc(sizeof(DIR)); + pdir->fd = -1; + pdir->cur_entry = 0; + strcpy(pdir->path, path); + + return pdir; +} + +int initfs_closedir(DIR *dirp) +{ + if (dirp != NULL) { + kfree(dirp); + } + + return 0; +} + +dirent_t *initrd_readdir(DIR *dirp) +{ + if (dirp->cur_entry >= MAX_FILES) { + return NULL; + } + + for (; dirp->cur_entry < MAX_FILES; ++dirp->cur_entry) { + initrd_file_t *entry = &fs_headers[dirp->cur_entry]; + if (entry->fileName[0] == '\0') { + continue; + } + // Get the directory of the file. + char *filedir = dirname(entry->fileName); + + // Check if directory path and file directory are the same, or if + // the directory is the root and the file directory is dot. + if (strcmp(dirp->path, filedir) == 0) { + dirp->entry.d_ino = dirp->cur_entry; + dirp->entry.d_type = entry->file_type; + strcpy(dirp->entry.d_name, entry->fileName); + ++dirp->cur_entry; + + return &(dirp->entry); + } + } + + return NULL; +} + +int initrd_mkdir(const char *path, mode_t mode) +{ + (void)mode; + initrd_file_t *direntry = NULL; + + // Check if the directory already exists. + direntry = get_initrd_file(path); + if (direntry != NULL) { + printf("initrd_mkdir: cannot create directory '%s': " + "File exists\n\n", + path); + return -1; + } + // Check if the directories before it exist. + if ((strcmp(dirname(path), ".") != 0) && + (strcmp(dirname(path), "/") != 0)) { + dbg_print("initrd_mkdir: %s\n", dirname(path)); + direntry = get_initrd_file(dirname(path)); + if (direntry == NULL) { + printf("initrd_mkdir: cannot create directory '%s': " + "No such file or directory\n\n", + path); + + return -1; + } + if ((direntry->file_type != FS_DIRECTORY) && + (direntry->file_type != FS_MOUNTPOINT)) { + printf("initrd_mkdir: cannot create directory '%s': " + "Not a directory\n\n", + path); + + return -1; + } + } + // Get a free header. + initrd_file_t *free_header = NULL; + get_free_header(&free_header); + if (free_header == NULL) { + printf("initrd_mkdir: cannot create directory '%s': " + "Maximum number of headers reached\n\n", + path); + + return -1; + } + // Create the directory. + free_header->magic = 0xBF; + strcpy(free_header->fileName, path); + free_header->file_type = FS_DIRECTORY; + free_header->uid = current_user.uid; + free_header->offset = ++fs_end; + free_header->length = 0; + // Increase the number of files. + ++fs_specs->nfiles; + + return 1; +} + +int initrd_rmdir(const char *path) +{ + initrd_file_t *direntry = NULL; + + // Check if the directory exists. + direntry = get_initrd_file(path); + if (direntry == NULL) { + //errno = ENOENT; + return -1; + } + + if ((direntry->file_type != FS_DIRECTORY)) { + //errno = ENOTDIR; + return -1; + } + + for (int i = 0; i < MAX_FILES; ++i) { + initrd_file_t *entry = &fs_headers[i]; + if (entry->fileName[0] == '\0') { + continue; + } + // Get the directory of the file. + char *filedir = dirname(entry->fileName); + // Check if directory path and file directory are the same. + if (strcmp(direntry->fileName, filedir) == 0) { + //errno = ENOTEMPTY; + return -1; + } + } + // Remove the directory. + direntry->magic = 0; + memset(direntry->fileName, 0, NAME_MAX); + direntry->file_type = 0; + direntry->uid = 0; + direntry->offset = 0; + direntry->length = 0; + // Decrease the number of files. + --fs_specs->nfiles; + + return 0; +} + +int initfs_open(const char *path, int flags, ...) +{ + // If we have reached the maximum number of descriptors, just try to find + // a non-used one. + if (cur_irdfd >= MAX_INITRD_DESCRIPTORS) { + // Reset the current ird file descriptor. + cur_irdfd = 0; + while ((ird_descriptors[cur_irdfd].file_descriptor != -1) && + (cur_irdfd < MAX_INITRD_DESCRIPTORS)) { + ++cur_irdfd; + } + } + + for (uint32_t it = 0; it < fs_specs->nfiles; ++it) { + // Discard the headers which has a different name. + if (strcmp(path, fs_headers[it].fileName) != 0) { + continue; + } + + // However, if the name is the same, but the file type is different, + // stop the function and return failure value. + if ((fs_headers[it].file_type == FS_DIRECTORY) || + (fs_headers[it].file_type == FS_MOUNTPOINT)) { + //errno = EISDIR; + return -1; + } + + if (has_flag(flags, O_CREAT)) { + //errno = EEXIST; + return -1; + } + + // Otherwise, if the file is correct, update + ird_descriptors[cur_irdfd].file_descriptor = it; + ird_descriptors[cur_irdfd].cur_pos = 0; + if (has_flag(flags, O_APPEND)) { + ird_descriptors[cur_irdfd].cur_pos = fs_headers[it].length; + } + + return cur_irdfd++; + } + if (has_flag(flags, O_CREAT)) { + // Check if the directories before it exist. + if ((strcmp(dirname(path), ".") != 0) && + (strcmp(dirname(path), "/") != 0)) { + initrd_file_t *direntry = get_initrd_file(dirname(path)); + if (direntry == NULL) { + //errno = ENOENT; + return -1; + } + } + // Get a free header. + initrd_file_t *free_header = NULL; + size_t fd = get_free_header(&free_header); + if (free_header == NULL) { + //errno = ENFILE; + return -1; + } + // Create the file. + free_header->magic = 0xBF; + strcpy(free_header->fileName, path); + free_header->file_type = FS_FILE; + free_header->uid = current_user.uid; + free_header->offset = ++fs_end; + free_header->length = 0; + // Set the descriptor. + ird_descriptors[cur_irdfd].file_descriptor = fd; + ird_descriptors[cur_irdfd].cur_pos = 0; + // Increase the number of files. + ++fs_specs->nfiles; + + return cur_irdfd++; + } + + //errno = ENOENT; + return -1; +} + +int initfs_remove(const char *path) +{ + initrd_file_t *file = get_initrd_file(path); + + if (file == NULL) { + return -1; + } + + if (file->file_type != FS_FILE) { + return -1; + } + + // Remove the directory. + file->magic = 0; + memset(file->fileName, 0, NAME_MAX); + file->file_type = 0; + file->uid = 0; + file->offset = 0; + file->length = 0; + // Decrease the number of files. + --fs_specs->nfiles; + + return 0; +} + +ssize_t initfs_read(int fildes, char *buf, size_t nbyte) +{ + // If the number of byte to read is zero, skip. + if (nbyte == 0) { + return 0; + } + + // Get the file descriptor of the file. + int lfd = ird_descriptors[fildes].file_descriptor; + + // Get the current position. + int read_pos = ird_descriptors[fildes].cur_pos; + + // Get the legnth of the file. + int file_size = fs_headers[lfd].length; + + // Get the begin of the file. + char *file_start = (module_start[0] + fs_headers[lfd].offset); + + // Declare an iterator. + size_t it = 0; + + while ((it < nbyte) && (read_pos < file_size)) { + *buf++ = file_start[read_pos]; + ++read_pos; + ++it; + } + + ird_descriptors[fildes].cur_pos = read_pos; + if (read_pos == file_size) { + return EOF; + } + + return nbyte; +} + +int initrd_stat(const char *path, stat_t *stat) +{ + int i; + i = 0; + + while (i < MAX_FILES) { + if (!strcmp(path, fs_headers[i].fileName)) { + stat->st_uid = fs_headers[i].uid; + stat->st_size = fs_headers[i].length; + + break; + } + i++; + } + //dbg_print("Initrd stat function\n"); + //buf->st_uid = 33; + if (i == MAX_FILES) { + return -1; + } else { + return 0; + } +} + +ssize_t initrd_write(int fildes, const void *buf, size_t nbyte) +{ + // If the number of byte to write is zero, skip. + if (nbyte == 0) { + return 0; + } + + // Make a copy of the buffer. + char *tmp = (char *)kmalloc(strlen(buf) * sizeof(char)); + strcpy(tmp, buf); + + // Get the file descriptor of the file. + int lfd = ird_descriptors[fildes].file_descriptor; + + printf("Please wait, im writing the world...\n"); + printf("And the world begun with those words: %s and his mark his: %d\n", + tmp, lfd); + // Get the begin of the file. + char *file_start = (module_start[0] + fs_headers[lfd].offset + + ird_descriptors[fildes].cur_pos); + // Declare an iterator. + size_t it = 0; + while (it <= nbyte) { + file_start[it] = tmp[it]; + ++it; + } + + // Increment the length of the file. + fs_headers[lfd].length = fs_headers[lfd].length + it; + // Free the memory of the temporary file. + kfree(tmp); + // Return the number of written bytes. + + return it; +} + +int initrd_close(int fildes) +{ + ird_descriptors[fildes].file_descriptor = -1; + ird_descriptors[fildes].cur_pos = 0; + + return 0; +} + +size_t initrd_nfiles() +{ + size_t nfiles = 0; + + for (size_t i = 0; i < MAX_FILES; ++i) { + if (fs_headers[i].file_type != 0) { + ++nfiles; + } + } + + return nfiles; +} + +void dump_initrd_fs() +{ + for (uint32_t i = 0; i < MAX_FILES; ++i) { + dbg_print("[%2d] %s\n", i, fs_headers[i].fileName); + } +} diff --git a/mentos/src/fs/open.c b/mentos/src/fs/open.c index a8cf3d5..c98caab 100644 --- a/mentos/src/fs/open.c +++ b/mentos/src/fs/open.c @@ -1,98 +1,98 @@ -/// MentOS, The Mentoring Operating system project -/// @file open.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "syscall.h" -#include "string.h" -#include "limits.h" -#include "debug.h" -#include "stdio.h" -#include "vfs.h" - -int sys_open(const char *pathname, int flags, mode_t mode) -{ - // Allocate a variable for the path. - char absolute_path[PATH_MAX]; - - // Copy the path to the working variable. - strcpy(absolute_path, pathname); - - // If the first character is not the '/' then get the absolute path. - if (absolute_path[0] != '/') { - if (!get_absolute_path(absolute_path)) { - dbg_print("Cannot get the absolute path.\n"); - return -1; - } - } - - // Search for an unused fd. - for (current_fd = 0; current_fd < MAX_OPEN_FD; ++current_fd) { - if (fd_list[current_fd].mountpoint_id == -1) { - break; - } - } - - // Check if there is not fd available. - if (current_fd == MAX_OPEN_FD) { - //errno = EMFILE; - return -1; - } - - // Get the mountpoint. - mountpoint_t *mp = get_mountpoint(absolute_path); - if (mp == NULL) { - //errno = ENODEV; - return -1; - } - - // Check if the function is implemented. - if (mp->operations.open_f == NULL) { - //errno = ENOSYS; - // Reset the file descriptor. - sys_close(current_fd); - return -1; - } - - int32_t fs_spec_id = mp->operations.open_f(absolute_path, flags, mode); - if (fs_spec_id == -1) { - // Reset the file descriptor. - sys_close(current_fd); - return -1; - } - - // Set the file descriptor id. - fd_list[current_fd].fs_spec_id = fs_spec_id; - - // Set the mount point id. - fd_list[current_fd].mountpoint_id = mp->mp_id; - - // Reset the offset. - fd_list[current_fd].offset = 0; - - // Set the flags. - fd_list[current_fd].flags_mask = flags; - - // Return the file descriptor and increment it. - return (current_fd++); -} - -int sys_close(int fd) -{ - if (fd < 0) { - return -1; - } - if (fd_list[fd].fs_spec_id >= -1) { - int mp_id = fd_list[fd].mountpoint_id; - if (mountpoint_list[mp_id].operations.close_f != NULL) { - int fs_fd = fd_list[fd].fs_spec_id; - mountpoint_list[mp_id].operations.close_f(fs_fd); - } - fd_list[fd].fs_spec_id = -1; - fd_list[fd].mountpoint_id = -1; - } else { - return -1; - } - return 0; -} +/// MentOS, The Mentoring Operating system project +/// @file open.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "syscall.h" +#include "string.h" +#include "limits.h" +#include "debug.h" +#include "stdio.h" +#include "vfs.h" + +int sys_open(const char *pathname, int flags, mode_t mode) +{ + // Allocate a variable for the path. + char absolute_path[PATH_MAX]; + + // Copy the path to the working variable. + strcpy(absolute_path, pathname); + + // If the first character is not the '/' then get the absolute path. + if (absolute_path[0] != '/') { + if (!get_absolute_path(absolute_path)) { + dbg_print("Cannot get the absolute path.\n"); + return -1; + } + } + + // Search for an unused fd. + for (current_fd = 0; current_fd < MAX_OPEN_FD; ++current_fd) { + if (fd_list[current_fd].mountpoint_id == -1) { + break; + } + } + + // Check if there is not fd available. + if (current_fd == MAX_OPEN_FD) { + //errno = EMFILE; + return -1; + } + + // Get the mountpoint. + mountpoint_t *mp = get_mountpoint(absolute_path); + if (mp == NULL) { + //errno = ENODEV; + return -1; + } + + // Check if the function is implemented. + if (mp->operations.open_f == NULL) { + //errno = ENOSYS; + // Reset the file descriptor. + sys_close(current_fd); + return -1; + } + + int32_t fs_spec_id = mp->operations.open_f(absolute_path, flags, mode); + if (fs_spec_id == -1) { + // Reset the file descriptor. + sys_close(current_fd); + return -1; + } + + // Set the file descriptor id. + fd_list[current_fd].fs_spec_id = fs_spec_id; + + // Set the mount point id. + fd_list[current_fd].mountpoint_id = mp->mp_id; + + // Reset the offset. + fd_list[current_fd].offset = 0; + + // Set the flags. + fd_list[current_fd].flags_mask = flags; + + // Return the file descriptor and increment it. + return (current_fd++); +} + +int sys_close(int fd) +{ + if (fd < 0) { + return -1; + } + if (fd_list[fd].fs_spec_id >= -1) { + int mp_id = fd_list[fd].mountpoint_id; + if (mountpoint_list[mp_id].operations.close_f != NULL) { + int fs_fd = fd_list[fd].fs_spec_id; + mountpoint_list[mp_id].operations.close_f(fs_fd); + } + fd_list[fd].fs_spec_id = -1; + fd_list[fd].mountpoint_id = -1; + } else { + return -1; + } + return 0; +} diff --git a/mentos/src/fs/read_write.c b/mentos/src/fs/read_write.c index 9bbfb98..61b5fbb 100644 --- a/mentos/src/fs/read_write.c +++ b/mentos/src/fs/read_write.c @@ -1,63 +1,63 @@ -/// MentOS, The Mentoring Operating system project -/// @file read_write.c -/// @brief Read and write functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include -#include "vfs.h" -#include "stdio.h" -#include "fcntl.h" -#include "unistd.h" -#include "keyboard.h" -#include "video.h" - -ssize_t sys_read(int fd, void *buf, size_t nbytes) -{ - if (fd == STDIN_FILENO) { - *((char *)buf) = keyboard_getc(); - return 1; - } - - int mp_id = fd_list[fd].mountpoint_id; - int fs_fd = fd_list[fd].fs_spec_id; - - if (mountpoint_list[mp_id].operations.read_f != NULL) { - return mountpoint_list[mp_id].operations.read_f(fs_fd, buf, nbytes); - } else { - printf("No READ Found for that file system\n"); - } - - return 0; -} - -ssize_t sys_write(int fd, void *buf, size_t nbytes) -{ - if ((fd == STDOUT_FILENO) || (fd == STDERR_FILENO)) { - for (size_t i = 0; (i < nbytes); ++i) - video_putc(((char *)buf)[i]); - return nbytes; - } - - if (fd > MAX_OPEN_FD) { - //errno = EBADF; - return -1; - } - - if (!(fd_list[fd].flags_mask & O_RDWR)) { - //errno = EROFS; - return -1; - } - - mountpoint_t *mp = &mountpoint_list[fd_list[fd].mountpoint_id]; - if (mp == NULL) { - //errno = ENODEV; - return -1; - } - if (mp->operations.write_f == NULL) { - //errno = ENOSYS; - return -1; - } - - return mp->operations.write_f(fd_list[fd].fs_spec_id, buf, nbytes); -} +/// MentOS, The Mentoring Operating system project +/// @file read_write.c +/// @brief Read and write functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include "vfs.h" +#include "stdio.h" +#include "fcntl.h" +#include "unistd.h" +#include "keyboard.h" +#include "video.h" + +ssize_t sys_read(int fd, void *buf, size_t nbytes) +{ + if (fd == STDIN_FILENO) { + *((char *)buf) = keyboard_getc(); + return 1; + } + + int mp_id = fd_list[fd].mountpoint_id; + int fs_fd = fd_list[fd].fs_spec_id; + + if (mountpoint_list[mp_id].operations.read_f != NULL) { + return mountpoint_list[mp_id].operations.read_f(fs_fd, buf, nbytes); + } else { + printf("No READ Found for that file system\n"); + } + + return 0; +} + +ssize_t sys_write(int fd, void *buf, size_t nbytes) +{ + if ((fd == STDOUT_FILENO) || (fd == STDERR_FILENO)) { + for (size_t i = 0; (i < nbytes); ++i) + video_putc(((char *)buf)[i]); + return nbytes; + } + + if (fd > MAX_OPEN_FD) { + //errno = EBADF; + return -1; + } + + if (!(fd_list[fd].flags_mask & O_RDWR)) { + //errno = EROFS; + return -1; + } + + mountpoint_t *mp = &mountpoint_list[fd_list[fd].mountpoint_id]; + if (mp == NULL) { + //errno = ENODEV; + return -1; + } + if (mp->operations.write_f == NULL) { + //errno = ENOSYS; + return -1; + } + + return mp->operations.write_f(fd_list[fd].fs_spec_id, buf, nbytes); +} diff --git a/mentos/src/fs/readdir.c b/mentos/src/fs/readdir.c index 6ae887f..f123378 100644 --- a/mentos/src/fs/readdir.c +++ b/mentos/src/fs/readdir.c @@ -1,28 +1,28 @@ -/// MentOS, The Mentoring Operating system project -/// @file readdir.c -/// @brief Function for accessing directory entries. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "dirent.h" -#include "syscall.h" -#include "stdio.h" -#include "vfs.h" - -dirent_t *sys_readdir(DIR *dirp) -{ - if (dirp == NULL) { - printf("readdir: cannot read directory :" - "Directory pointer is not valid\n"); - - return NULL; - } - if (mountpoint_list[dirp->fd].dir_op.readdir_f == NULL) { - printf("readdir: cannot read directory '%s':" - "No readdir function\n", - dirp->path); - - return NULL; - } - return mountpoint_list[dirp->fd].dir_op.readdir_f(dirp); -} +/// MentOS, The Mentoring Operating system project +/// @file readdir.c +/// @brief Function for accessing directory entries. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "dirent.h" +#include "syscall.h" +#include "stdio.h" +#include "vfs.h" + +dirent_t *sys_readdir(DIR *dirp) +{ + if (dirp == NULL) { + printf("readdir: cannot read directory :" + "Directory pointer is not valid\n"); + + return NULL; + } + if (mountpoint_list[dirp->fd].dir_op.readdir_f == NULL) { + printf("readdir: cannot read directory '%s':" + "No readdir function\n", + dirp->path); + + return NULL; + } + return mountpoint_list[dirp->fd].dir_op.readdir_f(dirp); +} diff --git a/mentos/src/fs/stat.c b/mentos/src/fs/stat.c index 9365317..0256e77 100644 --- a/mentos/src/fs/stat.c +++ b/mentos/src/fs/stat.c @@ -1,85 +1,85 @@ -/// MentOS, The Mentoring Operating system project -/// @file stat.c -/// @brief Stat functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "vfs.h" -#include "kheap.h" -#include "stdio.h" -#include "string.h" -#include "initrd.h" -#include "limits.h" - -int sys_stat(const char *path, stat_t *buf) -{ - // Reset the structure. - buf->st_dev = 0; - buf->st_ino = 0; - buf->st_mode = 0; - buf->st_uid = 0; - buf->st_gid = 0; - buf->st_size = 0; - buf->st_atime = 0; - buf->st_mtime = 0; - buf->st_ctime = 0; - - char absolute_path[PATH_MAX]; - strcpy(absolute_path, path); - - if (path[0] != '/') - { - get_absolute_path(absolute_path); - } - - int32_t mp_id = get_mountpoint_id(absolute_path); - if (mp_id < 0) - { - printf("stat: cannot execute stat of '%s': Not exists\n", path); - return -1; - } - - buf->st_dev = (uint32_t) mp_id; - if (mountpoint_list[mp_id].stat_op.stat_f == NULL) - { - printf("stat: cannot execute stat of '%s': Not stat function\n", - path); - - return -1; - } - mountpoint_list[mp_id].stat_op.stat_f(absolute_path, buf); - - return 0; -} - -int sys_mkdir(const char *path, mode_t mode) -{ - char absolute_path[PATH_MAX]; - strcpy(absolute_path, path); - int result = -1; - - if (path[0] != '/') - { - get_absolute_path(absolute_path); - } - - int32_t mp_id = get_mountpoint_id(absolute_path); - if (mp_id < 0) - { - printf("mkdir: cannot create directory '%s':" - "Cannot find mount-point\n", path); - - return result; - } - - if (mountpoint_list[mp_id].dir_op.mkdir_f == NULL) - { - printf("mkdir: cannot create directory '%s': " - "No mkdir function\n", path); - - return result; - } - result = mountpoint_list[mp_id].dir_op.mkdir_f(absolute_path, mode); - - return result; -} +/// MentOS, The Mentoring Operating system project +/// @file stat.c +/// @brief Stat functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "vfs.h" +#include "kheap.h" +#include "stdio.h" +#include "string.h" +#include "initrd.h" +#include "limits.h" + +int sys_stat(const char *path, stat_t *buf) +{ + // Reset the structure. + buf->st_dev = 0; + buf->st_ino = 0; + buf->st_mode = 0; + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_size = 0; + buf->st_atime = 0; + buf->st_mtime = 0; + buf->st_ctime = 0; + + char absolute_path[PATH_MAX]; + strcpy(absolute_path, path); + + if (path[0] != '/') + { + get_absolute_path(absolute_path); + } + + int32_t mp_id = get_mountpoint_id(absolute_path); + if (mp_id < 0) + { + printf("stat: cannot execute stat of '%s': Not exists\n", path); + return -1; + } + + buf->st_dev = (uint32_t) mp_id; + if (mountpoint_list[mp_id].stat_op.stat_f == NULL) + { + printf("stat: cannot execute stat of '%s': Not stat function\n", + path); + + return -1; + } + mountpoint_list[mp_id].stat_op.stat_f(absolute_path, buf); + + return 0; +} + +int sys_mkdir(const char *path, mode_t mode) +{ + char absolute_path[PATH_MAX]; + strcpy(absolute_path, path); + int result = -1; + + if (path[0] != '/') + { + get_absolute_path(absolute_path); + } + + int32_t mp_id = get_mountpoint_id(absolute_path); + if (mp_id < 0) + { + printf("mkdir: cannot create directory '%s':" + "Cannot find mount-point\n", path); + + return result; + } + + if (mountpoint_list[mp_id].dir_op.mkdir_f == NULL) + { + printf("mkdir: cannot create directory '%s': " + "No mkdir function\n", path); + + return result; + } + result = mountpoint_list[mp_id].dir_op.mkdir_f(absolute_path, mode); + + return result; +} diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 22e1b0c..babdb11 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -1,169 +1,169 @@ -/// MentOS, The Mentoring Operating system project -/// @file vfs.c -/// @brief Headers for Virtual File System (VFS). -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include -#include -#include "video.h" -#include "vfs.h" -#include "debug.h" -#include "shell.h" -#include "string.h" -#include "initrd.h" -#include "limits.h" - -int current_fd; -char *module_start[MAX_MODULES]; -file_descriptor_t fd_list[MAX_OPEN_FD]; -mountpoint_t mountpoint_list[MAX_MOUNTPOINT]; - -void vfs_init() -{ - current_fd = 0; - - for (int32_t i = 0; i < MAX_MOUNTPOINT; ++i) { - strcpy(mountpoint_list[i].mountpoint, ""); - mountpoint_list[i].mp_id = i; - mountpoint_list[i].uid = 0; - mountpoint_list[i].gid = 0; - mountpoint_list[i].pmask = 0; - mountpoint_list[i].dev_id = 0; - mountpoint_list[i].start_address = 0; - mountpoint_list[i].dir_op.opendir_f = NULL; - mountpoint_list[i].operations.open_f = NULL; - mountpoint_list[i].operations.close_f = NULL; - mountpoint_list[i].operations.read_f = NULL; - mountpoint_list[i].operations.write_f = NULL; - mountpoint_list[i].stat_op.stat_f = NULL; - } - - for (int32_t i = 0; i < MAX_OPEN_FD; ++i) { - fd_list[i].fs_spec_id = -1; - fd_list[i].mountpoint_id = -1; - fd_list[i].offset = 0; - fd_list[i].flags_mask = 0; - } - - strcpy(mountpoint_list[0].mountpoint, "/"); - mountpoint_list[0].uid = 0; - mountpoint_list[0].gid = 0; - mountpoint_list[0].pmask = 0; - mountpoint_list[0].dev_id = 0; - mountpoint_list[0].start_address = (unsigned int)module_start[0]; - mountpoint_list[0].end_address = (unsigned int)module_end[0]; - mountpoint_list[0].dir_op.opendir_f = initfs_opendir; - mountpoint_list[0].dir_op.closedir_f = initfs_closedir; - mountpoint_list[0].dir_op.readdir_f = initrd_readdir; - mountpoint_list[0].dir_op.mkdir_f = initrd_mkdir; - mountpoint_list[0].dir_op.rmdir_f = initrd_rmdir; - mountpoint_list[0].operations.open_f = initfs_open; - mountpoint_list[0].operations.remove_f = initfs_remove; - mountpoint_list[0].operations.close_f = initrd_close; - mountpoint_list[0].operations.read_f = initfs_read; - mountpoint_list[0].operations.write_f = initrd_write; - mountpoint_list[0].stat_op.stat_f = initrd_stat; -} - -int32_t get_mountpoint_id(const char *path) -{ - size_t last_mpl = 0; - int32_t last_mp_id = -1; - - for (uint32_t it = 0; it < MAX_MOUNTPOINT; ++it) { - size_t mpl = strlen(mountpoint_list[it].mountpoint); - - if (!strncmp(path, mountpoint_list[it].mountpoint, mpl)) { - if (((mpl > last_mpl) && it > 0) || (it == 0)) { - last_mpl = mpl; - last_mp_id = it; - } - } - } - - return last_mp_id; -} - -mountpoint_t *get_mountpoint(const char *path) -{ - int32_t mp_id = get_mountpoint_id(path); - - if (mp_id < 0) { - return NULL; - } - - return &mountpoint_list[mp_id]; -} - -mountpoint_t *get_mountpoint_from_id(int32_t mp_id) -{ - if (mp_id >= MAX_MOUNTPOINT) { - return NULL; - } - - return &mountpoint_list[mp_id]; -} - -int get_relative_path(uint32_t mp_id, char *path) -{ - char relative_path[PATH_MAX]; - - // Get the size of the path. - size_t path_size = strlen(path); - - // Get the size of the mount-point. - size_t mnpt_size = strlen(mountpoint_list[mp_id].mountpoint); - - // Get the size of the relative path. - size_t rltv_size = path_size - mnpt_size; - - // Copy the relative path. - if (rltv_size > 0) { - size_t i; - for (i = 0; i < rltv_size; ++i) { - relative_path[i] = path[mnpt_size + i]; - } - relative_path[i] = '\0'; - strcpy(path, relative_path); - } - - return strlen(path); -} - -int get_absolute_path(char *path) -{ - if (path[0] != '/') { - char abspath[PATH_MAX]; - memset(abspath, '\0', PATH_MAX); - getcwd(abspath, PATH_MAX); - int abs_size = strlen(abspath); - if (abspath[abs_size - 1] == '/') { - strncat(abspath, path, strlen(path)); - } else { - strncat(abspath, "/", strlen(path)); - strncat(abspath, path, strlen(path)); - } - strcpy(path, abspath); - - return strlen(path); - } - - return 0; -} - -void vfs_dump() -{ - dbg_print("File Descriptors:\n"); - int i = 0; - - while (i < MAX_OPEN_FD) { - if (fd_list[i].mountpoint_id != -1) { - dbg_print("[%d] %s\n", i, - mountpoint_list[fd_list[i].mountpoint_id].mountpoint); - } else { - dbg_print("[%d] Free\n", i); - } - ++i; - } -} +/// MentOS, The Mentoring Operating system project +/// @file vfs.c +/// @brief Headers for Virtual File System (VFS). +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include "video.h" +#include "vfs.h" +#include "debug.h" +#include "shell.h" +#include "string.h" +#include "initrd.h" +#include "limits.h" + +int current_fd; +char *module_start[MAX_MODULES]; +file_descriptor_t fd_list[MAX_OPEN_FD]; +mountpoint_t mountpoint_list[MAX_MOUNTPOINT]; + +void vfs_init() +{ + current_fd = 0; + + for (int32_t i = 0; i < MAX_MOUNTPOINT; ++i) { + strcpy(mountpoint_list[i].mountpoint, ""); + mountpoint_list[i].mp_id = i; + mountpoint_list[i].uid = 0; + mountpoint_list[i].gid = 0; + mountpoint_list[i].pmask = 0; + mountpoint_list[i].dev_id = 0; + mountpoint_list[i].start_address = 0; + mountpoint_list[i].dir_op.opendir_f = NULL; + mountpoint_list[i].operations.open_f = NULL; + mountpoint_list[i].operations.close_f = NULL; + mountpoint_list[i].operations.read_f = NULL; + mountpoint_list[i].operations.write_f = NULL; + mountpoint_list[i].stat_op.stat_f = NULL; + } + + for (int32_t i = 0; i < MAX_OPEN_FD; ++i) { + fd_list[i].fs_spec_id = -1; + fd_list[i].mountpoint_id = -1; + fd_list[i].offset = 0; + fd_list[i].flags_mask = 0; + } + + strcpy(mountpoint_list[0].mountpoint, "/"); + mountpoint_list[0].uid = 0; + mountpoint_list[0].gid = 0; + mountpoint_list[0].pmask = 0; + mountpoint_list[0].dev_id = 0; + mountpoint_list[0].start_address = (unsigned int)module_start[0]; + mountpoint_list[0].end_address = (unsigned int)module_end[0]; + mountpoint_list[0].dir_op.opendir_f = initfs_opendir; + mountpoint_list[0].dir_op.closedir_f = initfs_closedir; + mountpoint_list[0].dir_op.readdir_f = initrd_readdir; + mountpoint_list[0].dir_op.mkdir_f = initrd_mkdir; + mountpoint_list[0].dir_op.rmdir_f = initrd_rmdir; + mountpoint_list[0].operations.open_f = initfs_open; + mountpoint_list[0].operations.remove_f = initfs_remove; + mountpoint_list[0].operations.close_f = initrd_close; + mountpoint_list[0].operations.read_f = initfs_read; + mountpoint_list[0].operations.write_f = initrd_write; + mountpoint_list[0].stat_op.stat_f = initrd_stat; +} + +int32_t get_mountpoint_id(const char *path) +{ + size_t last_mpl = 0; + int32_t last_mp_id = -1; + + for (uint32_t it = 0; it < MAX_MOUNTPOINT; ++it) { + size_t mpl = strlen(mountpoint_list[it].mountpoint); + + if (!strncmp(path, mountpoint_list[it].mountpoint, mpl)) { + if (((mpl > last_mpl) && it > 0) || (it == 0)) { + last_mpl = mpl; + last_mp_id = it; + } + } + } + + return last_mp_id; +} + +mountpoint_t *get_mountpoint(const char *path) +{ + int32_t mp_id = get_mountpoint_id(path); + + if (mp_id < 0) { + return NULL; + } + + return &mountpoint_list[mp_id]; +} + +mountpoint_t *get_mountpoint_from_id(int32_t mp_id) +{ + if (mp_id >= MAX_MOUNTPOINT) { + return NULL; + } + + return &mountpoint_list[mp_id]; +} + +int get_relative_path(uint32_t mp_id, char *path) +{ + char relative_path[PATH_MAX]; + + // Get the size of the path. + size_t path_size = strlen(path); + + // Get the size of the mount-point. + size_t mnpt_size = strlen(mountpoint_list[mp_id].mountpoint); + + // Get the size of the relative path. + size_t rltv_size = path_size - mnpt_size; + + // Copy the relative path. + if (rltv_size > 0) { + size_t i; + for (i = 0; i < rltv_size; ++i) { + relative_path[i] = path[mnpt_size + i]; + } + relative_path[i] = '\0'; + strcpy(path, relative_path); + } + + return strlen(path); +} + +int get_absolute_path(char *path) +{ + if (path[0] != '/') { + char abspath[PATH_MAX]; + memset(abspath, '\0', PATH_MAX); + getcwd(abspath, PATH_MAX); + int abs_size = strlen(abspath); + if (abspath[abs_size - 1] == '/') { + strncat(abspath, path, strlen(path)); + } else { + strncat(abspath, "/", strlen(path)); + strncat(abspath, path, strlen(path)); + } + strcpy(path, abspath); + + return strlen(path); + } + + return 0; +} + +void vfs_dump() +{ + dbg_print("File Descriptors:\n"); + int i = 0; + + while (i < MAX_OPEN_FD) { + if (fd_list[i].mountpoint_id != -1) { + dbg_print("[%d] %s\n", i, + mountpoint_list[fd_list[i].mountpoint_id].mountpoint); + } else { + dbg_print("[%d] Free\n", i); + } + ++i; + } +} diff --git a/mentos/src/hardware/cpuid.c b/mentos/src/hardware/cpuid.c index 412158e..7a6922a 100644 --- a/mentos/src/hardware/cpuid.c +++ b/mentos/src/hardware/cpuid.c @@ -1,181 +1,181 @@ -/// MentOS, The Mentoring Operating system project -/// @file cpuid.c -/// @brief CPUID-based function to detect CPU type. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "cmd_cpuid.h" -#include "string.h" - -void get_cpuid(cpuinfo_t *cpuinfo) -{ - register_t ereg; - - ereg.eax = ereg.ebx = ereg.ecx = ereg.edx = 0; - cpuid_write_vendor(cpuinfo, &ereg); - - ereg.eax = 1; - ereg.ebx = ereg.ecx = ereg.edx = 0; - cpuid_write_proctype(cpuinfo, &ereg); -} - -void call_cpuid(register_t *registers) -{ - __asm__("cpuid\n\t" - : "=a"(registers->eax), "=b"(registers->ebx), "=c"(registers->ecx), - "=d"(registers->edx) - : "a"(registers->eax)); -} - -void cpuid_write_vendor(cpuinfo_t *cpuinfo, register_t *registers) -{ - call_cpuid(registers); - - cpuinfo->cpu_vendor[0] = (char)((registers->ebx & 0x000000FF)); - cpuinfo->cpu_vendor[1] = (char)((registers->ebx & 0x0000FF00) >> 8); - cpuinfo->cpu_vendor[2] = (char)((registers->ebx & 0x00FF0000) >> 16); - cpuinfo->cpu_vendor[3] = (char)((registers->ebx & 0xFF000000) >> 24); - cpuinfo->cpu_vendor[4] = (char)((registers->edx & 0x000000FF)); - cpuinfo->cpu_vendor[5] = (char)((registers->edx & 0x0000FF00) >> 8); - cpuinfo->cpu_vendor[6] = (char)((registers->edx & 0x00FF0000) >> 16); - cpuinfo->cpu_vendor[7] = (char)((registers->edx & 0xFF000000) >> 24); - cpuinfo->cpu_vendor[8] = (char)((registers->ecx & 0x000000FF)); - cpuinfo->cpu_vendor[9] = (char)((registers->ecx & 0x0000FF00) >> 8); - cpuinfo->cpu_vendor[10] = (char)((registers->ecx & 0x00FF0000) >> 16); - cpuinfo->cpu_vendor[11] = (char)((registers->ecx & 0xFF000000) >> 24); - cpuinfo->cpu_vendor[12] = '\0'; -} - -void cpuid_write_proctype(cpuinfo_t *cpuinfo, register_t *registers) -{ - call_cpuid(registers); - - uint32_t type = cpuid_get_byte(registers->eax, 0xB, 0x3); - - switch (type) { - case 0: - cpuinfo->cpu_type = "Original OEM Processor"; - break; - case 1: - cpuinfo->cpu_type = "Intel Overdrive Processor"; - break; - case 2: - cpuinfo->cpu_type = "Dual processor"; - break; - case 3: - cpuinfo->cpu_type = "(Intel reserved bit)"; - break; - } - - uint32_t familyID = cpuid_get_byte(registers->eax, 0x7, 0xE); - cpuinfo->cpu_family = familyID; - - if (familyID == 0x0F) { - cpuinfo->cpu_family += cpuid_get_byte(registers->eax, 0x13, 0xFF); - } - - uint32_t model = cpuid_get_byte(registers->eax, 0x3, 0xE); - cpuinfo->cpu_model = model; - - if (familyID == 0x06 || familyID == 0x0F) { - uint32_t ext_model = cpuid_get_byte(registers->eax, 0xF, 0xE); - cpuinfo->cpu_model += (ext_model << 4); - } - cpuinfo->apic_id = cpuid_get_byte(registers->ebx, 0x17, 0xFF); - - cpuid_feature_ecx(cpuinfo, registers->ecx); - cpuid_feature_edx(cpuinfo, registers->edx); - - /* Get brand string to identify the processor */ - if (familyID >= 0x0F && model >= 0x03) { - cpuinfo->brand_string = cpuid_brand_string(registers); - } else { - cpuinfo->brand_string = cpuid_brand_index(registers); - } -} - -void cpuid_feature_ecx(cpuinfo_t *cpuinfo, uint32_t ecx) -{ - uint32_t temp = ecx; - uint32_t i; - - for (i = 0; i < ECX_FLAGS_SIZE; ++i) { - temp = cpuid_get_byte(temp, i, 1); - cpuinfo->cpuid_ecx_flags[i] = temp; - temp = ecx; - } -} - -void cpuid_feature_edx(cpuinfo_t *cpuinfo, uint32_t edx) -{ - uint32_t temp = edx; - uint32_t i; - - for (i = 0; i < EDX_FLAGS_SIZE; ++i) { - temp = cpuid_get_byte(temp, i, 1); - cpuinfo->cpuid_edx_flags[i] = temp; - temp = edx; - } -} - -inline uint32_t cpuid_get_byte(const uint32_t reg, const uint32_t position, - const uint32_t value) -{ - return ((reg >> position) & value); -} - -char *cpuid_brand_index(register_t *r) -{ - char *indexes[21] = { "Reserved", - "Intel Celeron", - "Intel Pentium III", - "Intel Pentium III Xeon", - "Mobile Intel Pentium III", - "Mobile Intel Celeron", - "Intel Pentium 4", - "Intel Pentium 4", - "Intel Celeron", - "Intel Xeon MP", - "Intel Xeon MP", - "Mobile Intel Pentium 4", - "Mobile Intel Celeron", - "Mobile Genuine Intel", - "Intel Celeron M", - "Mobile Intel Celeron", - "Intel Celeron", - "Mobile Genuine Intel", - "Intel Pentium M", - "Mobile Intel Celeron", - NULL }; - - int bx = (r->ebx & 0xFF); - - if (bx > 0x17) { - bx = 0; - } - - return indexes[bx]; -} - -/// -/// @param r -/// @return -char *cpuid_brand_string(register_t *r) -{ - char *temp = ""; - - for (r->eax = 0x80000002; r->eax <= 0x80000004; (r->eax)++) { - r->ebx = r->ecx = r->edx = 0; - call_cpuid(r); - temp = - strncat(temp, (const char *)r->eax, strlen((const char *)r->eax)); - temp = - strncat(temp, (const char *)r->ebx, strlen((const char *)r->ebx)); - temp = - strncat(temp, (const char *)r->ecx, strlen((const char *)r->ecx)); - temp = - strncat(temp, (const char *)r->edx, strlen((const char *)r->edx)); - } - - return temp; -} +/// MentOS, The Mentoring Operating system project +/// @file cpuid.c +/// @brief CPUID-based function to detect CPU type. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "cmd_cpuid.h" +#include "string.h" + +void get_cpuid(cpuinfo_t *cpuinfo) +{ + register_t ereg; + + ereg.eax = ereg.ebx = ereg.ecx = ereg.edx = 0; + cpuid_write_vendor(cpuinfo, &ereg); + + ereg.eax = 1; + ereg.ebx = ereg.ecx = ereg.edx = 0; + cpuid_write_proctype(cpuinfo, &ereg); +} + +void call_cpuid(register_t *registers) +{ + __asm__("cpuid\n\t" + : "=a"(registers->eax), "=b"(registers->ebx), "=c"(registers->ecx), + "=d"(registers->edx) + : "a"(registers->eax)); +} + +void cpuid_write_vendor(cpuinfo_t *cpuinfo, register_t *registers) +{ + call_cpuid(registers); + + cpuinfo->cpu_vendor[0] = (char)((registers->ebx & 0x000000FF)); + cpuinfo->cpu_vendor[1] = (char)((registers->ebx & 0x0000FF00) >> 8); + cpuinfo->cpu_vendor[2] = (char)((registers->ebx & 0x00FF0000) >> 16); + cpuinfo->cpu_vendor[3] = (char)((registers->ebx & 0xFF000000) >> 24); + cpuinfo->cpu_vendor[4] = (char)((registers->edx & 0x000000FF)); + cpuinfo->cpu_vendor[5] = (char)((registers->edx & 0x0000FF00) >> 8); + cpuinfo->cpu_vendor[6] = (char)((registers->edx & 0x00FF0000) >> 16); + cpuinfo->cpu_vendor[7] = (char)((registers->edx & 0xFF000000) >> 24); + cpuinfo->cpu_vendor[8] = (char)((registers->ecx & 0x000000FF)); + cpuinfo->cpu_vendor[9] = (char)((registers->ecx & 0x0000FF00) >> 8); + cpuinfo->cpu_vendor[10] = (char)((registers->ecx & 0x00FF0000) >> 16); + cpuinfo->cpu_vendor[11] = (char)((registers->ecx & 0xFF000000) >> 24); + cpuinfo->cpu_vendor[12] = '\0'; +} + +void cpuid_write_proctype(cpuinfo_t *cpuinfo, register_t *registers) +{ + call_cpuid(registers); + + uint32_t type = cpuid_get_byte(registers->eax, 0xB, 0x3); + + switch (type) { + case 0: + cpuinfo->cpu_type = "Original OEM Processor"; + break; + case 1: + cpuinfo->cpu_type = "Intel Overdrive Processor"; + break; + case 2: + cpuinfo->cpu_type = "Dual processor"; + break; + case 3: + cpuinfo->cpu_type = "(Intel reserved bit)"; + break; + } + + uint32_t familyID = cpuid_get_byte(registers->eax, 0x7, 0xE); + cpuinfo->cpu_family = familyID; + + if (familyID == 0x0F) { + cpuinfo->cpu_family += cpuid_get_byte(registers->eax, 0x13, 0xFF); + } + + uint32_t model = cpuid_get_byte(registers->eax, 0x3, 0xE); + cpuinfo->cpu_model = model; + + if (familyID == 0x06 || familyID == 0x0F) { + uint32_t ext_model = cpuid_get_byte(registers->eax, 0xF, 0xE); + cpuinfo->cpu_model += (ext_model << 4); + } + cpuinfo->apic_id = cpuid_get_byte(registers->ebx, 0x17, 0xFF); + + cpuid_feature_ecx(cpuinfo, registers->ecx); + cpuid_feature_edx(cpuinfo, registers->edx); + + /* Get brand string to identify the processor */ + if (familyID >= 0x0F && model >= 0x03) { + cpuinfo->brand_string = cpuid_brand_string(registers); + } else { + cpuinfo->brand_string = cpuid_brand_index(registers); + } +} + +void cpuid_feature_ecx(cpuinfo_t *cpuinfo, uint32_t ecx) +{ + uint32_t temp = ecx; + uint32_t i; + + for (i = 0; i < ECX_FLAGS_SIZE; ++i) { + temp = cpuid_get_byte(temp, i, 1); + cpuinfo->cpuid_ecx_flags[i] = temp; + temp = ecx; + } +} + +void cpuid_feature_edx(cpuinfo_t *cpuinfo, uint32_t edx) +{ + uint32_t temp = edx; + uint32_t i; + + for (i = 0; i < EDX_FLAGS_SIZE; ++i) { + temp = cpuid_get_byte(temp, i, 1); + cpuinfo->cpuid_edx_flags[i] = temp; + temp = edx; + } +} + +inline uint32_t cpuid_get_byte(const uint32_t reg, const uint32_t position, + const uint32_t value) +{ + return ((reg >> position) & value); +} + +char *cpuid_brand_index(register_t *r) +{ + char *indexes[21] = { "Reserved", + "Intel Celeron", + "Intel Pentium III", + "Intel Pentium III Xeon", + "Mobile Intel Pentium III", + "Mobile Intel Celeron", + "Intel Pentium 4", + "Intel Pentium 4", + "Intel Celeron", + "Intel Xeon MP", + "Intel Xeon MP", + "Mobile Intel Pentium 4", + "Mobile Intel Celeron", + "Mobile Genuine Intel", + "Intel Celeron M", + "Mobile Intel Celeron", + "Intel Celeron", + "Mobile Genuine Intel", + "Intel Pentium M", + "Mobile Intel Celeron", + NULL }; + + int bx = (r->ebx & 0xFF); + + if (bx > 0x17) { + bx = 0; + } + + return indexes[bx]; +} + +/// +/// @param r +/// @return +char *cpuid_brand_string(register_t *r) +{ + char *temp = ""; + + for (r->eax = 0x80000002; r->eax <= 0x80000004; (r->eax)++) { + r->ebx = r->ecx = r->edx = 0; + call_cpuid(r); + temp = + strncat(temp, (const char *)r->eax, strlen((const char *)r->eax)); + temp = + strncat(temp, (const char *)r->ebx, strlen((const char *)r->ebx)); + temp = + strncat(temp, (const char *)r->ecx, strlen((const char *)r->ecx)); + temp = + strncat(temp, (const char *)r->edx, strlen((const char *)r->edx)); + } + + return temp; +} diff --git a/mentos/src/hardware/pic8259.c b/mentos/src/hardware/pic8259.c index 11cc46e..a7e6537 100644 --- a/mentos/src/hardware/pic8259.c +++ b/mentos/src/hardware/pic8259.c @@ -1,174 +1,174 @@ -/// MentOS, The Mentoring Operating system project -/// @file pic8259.c -/// @brief pic8259 definitions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "pic8259.h" - -/// End-of-interrupt command code. -#define EOI 0x20 - -/// IO base address for master PIC. -#define MASTER_PORT_COMMAND 0x20 - -/// I/O address for data to master. -#define MASTER_PORT_DATA (MASTER_PORT_COMMAND + 1) - -/// IO base address for slave PIC. -#define SLAVE_PORT_COMMAND 0xA0 - -/// I/O address for data to slave. -#define SLAVE_PORT_DATA (SLAVE_PORT_COMMAND + 1) - -/// ICW4 (not) needed. -#define ICW1_ICW4 0x01 - -/// Single (cascade) mode. -#define ICW1_SINGLE 0x02 - -/// Call address interval 4 (8). -#define ICW1_INTERVAL4 0x04 - -/// Level triggered (edge) mode. -#define ICW1_LEVEL 0x08 - -/// Initialization - required. -#define ICW1_INIT 0x10 - -/// 8086/88 (MCS-80/85) mode -#define ICW4_8086 0x01 - -/// Auto (normal) EOI. -#define ICW4_AUTO 0x02 - -/// Buffered mode/slave. -#define ICW4_BUF_SLAVE 0x08 - -/// Buffered mode/master. -#define ICW4_BUF_MASTER 0x0C - -/// Special fully nested (not). -#define ICW4_SFNM 0x10 - -/// OCW3 irq ready next CMD read. -#define PIC_READ_IRR 0x0A - -/// OCW3 irq service next CMD read. -#define PIC_READ_ISR 0x0B - -/// The current mask of the master. -static byte_t master_cur_mask; - -/// The current mask of the slave. -static byte_t slave_cur_mask; - -void pic8259_init_irq() -{ - // Set the masks for the master and slave. - master_cur_mask = 0xFF; - slave_cur_mask = 0xFF; - - // Starts the initialization sequence (in cascade mode). - outportb(MASTER_PORT_COMMAND, ICW1_INIT + ICW1_ICW4); - outportb(SLAVE_PORT_COMMAND, ICW1_INIT + ICW1_ICW4); - - // ICW2: Master PIC vector offset. - outportb(MASTER_PORT_DATA, 0x20); - // ICW2: Slave PIC vector offset. - outportb(SLAVE_PORT_DATA, 0x28); - - // ICW3: Tell Master PIC that there is a slave PIC at IRQ2 (0000 0100). - outportb(MASTER_PORT_DATA, 4); - // ICW3: Tell Slave PIC its cascade identity (0000 0010). - outportb(SLAVE_PORT_DATA, 2); - - outportb(MASTER_PORT_DATA, ICW4_8086); - outportb(SLAVE_PORT_DATA, ICW4_8086); - - // Restore saved masks. - outportb(MASTER_PORT_DATA, master_cur_mask); - outportb(SLAVE_PORT_DATA, slave_cur_mask); - - pic8259_irq_enable(IRQ_TO_SLAVE_PIC); - - outportb(0xFF, MASTER_PORT_DATA); - outportb(0xFF, SLAVE_PORT_DATA); -} - -int pic8259_irq_enable(uint32_t irq) -{ - if (irq >= IRQ_NUM) { - return -1; - } - - byte_t cur_mask; - byte_t new_mask; - - if (irq < 8) { - new_mask = ~(1 << irq); - cur_mask = inportb(MASTER_PORT_DATA); - outportb(MASTER_PORT_DATA, (new_mask & cur_mask)); - master_cur_mask = (new_mask & cur_mask); - } else { - irq -= 8; - new_mask = ~(1 << irq); - cur_mask = inportb(SLAVE_PORT_DATA); - outportb(SLAVE_PORT_DATA, (new_mask & cur_mask)); - slave_cur_mask = (new_mask & cur_mask); - } - - return 0; -} - -int pic8259_irq_disable(uint32_t irq) -{ - if (irq >= IRQ_NUM) { - return -1; - } - - uint8_t cur_mask; - if (irq < 8) { - cur_mask = inportb(MASTER_PORT_DATA); - cur_mask |= (1 << irq); - outportb(MASTER_PORT_DATA, cur_mask & 0xFF); - } else { - irq = irq - 8; - cur_mask = inportb(SLAVE_PORT_DATA); - cur_mask |= (1 << irq); - outportb(SLAVE_PORT_DATA, cur_mask & 0xFF); - } - return 0; -} - -void pic8259_send_eoi(uint32_t irq) -{ - // Perhaps the most common command issued to the PIC chips is the end of - // interrupt (EOI) command (code 0x20). This is issued to the PIC chips - // at the end of an IRQ-based interrupt routine. If the IRQ came from the - // Master PIC, it is sufficient to issue this command only to the Master - // PIC; however if the IRQ came from the Slave PIC, it is necessary to - // issue the command to both PIC chips. - if (irq >= 8) { - outportb(SLAVE_PORT_COMMAND, EOI); - } - outportb(MASTER_PORT_COMMAND, EOI); -} - -/* - * int pic8259_irq_get_current() - * { - * outportb(MASTER_PORT_COMMAND, PIC_READ_ISR); - * uint8_t cur_irq = inportb(MASTER_PORT_COMMAND); - * - * if (cur_irq == 4) - * { - * outportb(SLAVE_PORT_COMMAND, PIC_READ_ISR); - * cur_irq = inportb(SLAVE_PORT_COMMAND); - * - * return 8 + find_first_bit(cur_irq); - * } - * - * return find_first_bit(cur_irq); - * } - */ +/// MentOS, The Mentoring Operating system project +/// @file pic8259.c +/// @brief pic8259 definitions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "pic8259.h" + +/// End-of-interrupt command code. +#define EOI 0x20 + +/// IO base address for master PIC. +#define MASTER_PORT_COMMAND 0x20 + +/// I/O address for data to master. +#define MASTER_PORT_DATA (MASTER_PORT_COMMAND + 1) + +/// IO base address for slave PIC. +#define SLAVE_PORT_COMMAND 0xA0 + +/// I/O address for data to slave. +#define SLAVE_PORT_DATA (SLAVE_PORT_COMMAND + 1) + +/// ICW4 (not) needed. +#define ICW1_ICW4 0x01 + +/// Single (cascade) mode. +#define ICW1_SINGLE 0x02 + +/// Call address interval 4 (8). +#define ICW1_INTERVAL4 0x04 + +/// Level triggered (edge) mode. +#define ICW1_LEVEL 0x08 + +/// Initialization - required. +#define ICW1_INIT 0x10 + +/// 8086/88 (MCS-80/85) mode +#define ICW4_8086 0x01 + +/// Auto (normal) EOI. +#define ICW4_AUTO 0x02 + +/// Buffered mode/slave. +#define ICW4_BUF_SLAVE 0x08 + +/// Buffered mode/master. +#define ICW4_BUF_MASTER 0x0C + +/// Special fully nested (not). +#define ICW4_SFNM 0x10 + +/// OCW3 irq ready next CMD read. +#define PIC_READ_IRR 0x0A + +/// OCW3 irq service next CMD read. +#define PIC_READ_ISR 0x0B + +/// The current mask of the master. +static byte_t master_cur_mask; + +/// The current mask of the slave. +static byte_t slave_cur_mask; + +void pic8259_init_irq() +{ + // Set the masks for the master and slave. + master_cur_mask = 0xFF; + slave_cur_mask = 0xFF; + + // Starts the initialization sequence (in cascade mode). + outportb(MASTER_PORT_COMMAND, ICW1_INIT + ICW1_ICW4); + outportb(SLAVE_PORT_COMMAND, ICW1_INIT + ICW1_ICW4); + + // ICW2: Master PIC vector offset. + outportb(MASTER_PORT_DATA, 0x20); + // ICW2: Slave PIC vector offset. + outportb(SLAVE_PORT_DATA, 0x28); + + // ICW3: Tell Master PIC that there is a slave PIC at IRQ2 (0000 0100). + outportb(MASTER_PORT_DATA, 4); + // ICW3: Tell Slave PIC its cascade identity (0000 0010). + outportb(SLAVE_PORT_DATA, 2); + + outportb(MASTER_PORT_DATA, ICW4_8086); + outportb(SLAVE_PORT_DATA, ICW4_8086); + + // Restore saved masks. + outportb(MASTER_PORT_DATA, master_cur_mask); + outportb(SLAVE_PORT_DATA, slave_cur_mask); + + pic8259_irq_enable(IRQ_TO_SLAVE_PIC); + + outportb(0xFF, MASTER_PORT_DATA); + outportb(0xFF, SLAVE_PORT_DATA); +} + +int pic8259_irq_enable(uint32_t irq) +{ + if (irq >= IRQ_NUM) { + return -1; + } + + byte_t cur_mask; + byte_t new_mask; + + if (irq < 8) { + new_mask = ~(1 << irq); + cur_mask = inportb(MASTER_PORT_DATA); + outportb(MASTER_PORT_DATA, (new_mask & cur_mask)); + master_cur_mask = (new_mask & cur_mask); + } else { + irq -= 8; + new_mask = ~(1 << irq); + cur_mask = inportb(SLAVE_PORT_DATA); + outportb(SLAVE_PORT_DATA, (new_mask & cur_mask)); + slave_cur_mask = (new_mask & cur_mask); + } + + return 0; +} + +int pic8259_irq_disable(uint32_t irq) +{ + if (irq >= IRQ_NUM) { + return -1; + } + + uint8_t cur_mask; + if (irq < 8) { + cur_mask = inportb(MASTER_PORT_DATA); + cur_mask |= (1 << irq); + outportb(MASTER_PORT_DATA, cur_mask & 0xFF); + } else { + irq = irq - 8; + cur_mask = inportb(SLAVE_PORT_DATA); + cur_mask |= (1 << irq); + outportb(SLAVE_PORT_DATA, cur_mask & 0xFF); + } + return 0; +} + +void pic8259_send_eoi(uint32_t irq) +{ + // Perhaps the most common command issued to the PIC chips is the end of + // interrupt (EOI) command (code 0x20). This is issued to the PIC chips + // at the end of an IRQ-based interrupt routine. If the IRQ came from the + // Master PIC, it is sufficient to issue this command only to the Master + // PIC; however if the IRQ came from the Slave PIC, it is necessary to + // issue the command to both PIC chips. + if (irq >= 8) { + outportb(SLAVE_PORT_COMMAND, EOI); + } + outportb(MASTER_PORT_COMMAND, EOI); +} + +/* + * int pic8259_irq_get_current() + * { + * outportb(MASTER_PORT_COMMAND, PIC_READ_ISR); + * uint8_t cur_irq = inportb(MASTER_PORT_COMMAND); + * + * if (cur_irq == 4) + * { + * outportb(SLAVE_PORT_COMMAND, PIC_READ_ISR); + * cur_irq = inportb(SLAVE_PORT_COMMAND); + * + * return 8 + find_first_bit(cur_irq); + * } + * + * return find_first_bit(cur_irq); + * } + */ diff --git a/mentos/src/hardware/timer.c b/mentos/src/hardware/timer.c index 5a4b795..128296d 100644 --- a/mentos/src/hardware/timer.c +++ b/mentos/src/hardware/timer.c @@ -1,115 +1,115 @@ -/// MentOS, The Mentoring Operating system project -/// @file timer.c -/// @brief Timer implementation. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "timer.h" -#include "list.h" -#include "kheap.h" -#include "debug.h" -#include "stdint.h" -#include "pic8259.h" -#include "port_io.h" -#include "irqflags.h" - -#define SUBTICKS_PER_TICK 1000 - -/// This will keep track of how many ticks the system has been running for. -static __volatile__ uint64_t timer_subticks = 0; -/// This will keep track of how many seconds the system has been running for. -static __volatile__ uint64_t timer_ticks = 0; - -/// The list of wakeup functions. -// static list_t *wakeup_list; - -void timer_phase(const uint32_t hz) -{ - // Calculate our divisor. - uint32_t divisor = PIT_DIVISOR / hz; - // Set our command byte 0x36. - outportb(PIT_COMREG, PIT_CONFIGURATION); - // Set low byte of divisor. - outportb(PIT_DATAREG0, divisor & PIT_MASK); - // Set high byte of divisor. - outportb(PIT_DATAREG0, (divisor >> 8) & PIT_MASK); -} - -void timer_handler(pt_regs *reg) -{ - (void)reg; - // Check if a second has passed. - if ((++timer_subticks % SUBTICKS_PER_TICK) == 0) { - ++timer_ticks; - } - /* - * if (!list_empty(wakeup_list)) - * { - * listnode_foreach(t, wakeup_list) - * { - * wakeup_info_t *wakeupInfo = (wakeup_info_t *) t->value; - * if (timer_subticks >= wakeupInfo->wakeup_at_jiffy) - * { - * // Call the function. - * wakeupInfo->func(); - * // Reset the timer. - * wakeupInfo->wakeup_at_jiffy = - * timer_subticks + wakeupInfo->period * timer_hz; - * } - * { - * } - */ - - kernel_schedule(reg); - // The ack is sent to PIC only when all handlers terminated! - pic8259_send_eoi(IRQ_TIMER); -} - -void timer_install() -{ - // Intialize the wakeup list (before installing the timer). - // wakeup_list = list_create(); - // Set the timer phase. - timer_phase(SUBTICKS_PER_TICK); - // Installs 'timer_handler' to IRQ0. - irq_install_handler(IRQ_TIMER, timer_handler, "timer"); - // Enable the IRQ of the itemer. - pic8259_irq_enable(IRQ_TIMER); -} - -uint64_t timer_get_ticks() -{ - return timer_ticks; -} - -uint64_t timer_get_subticks() -{ - return timer_subticks; -} - -/* - * void timer_register_wakeup_call(wakeup_callback_t func, uint32_t period) - * { - * - * // Save the function sec, and jiffy to a list, when timer hits that - * // func's jiffy it will call the func, and update next jiffies. - * - * wakeup_info_t *wakeupInfo = kmalloc(sizeof(wakeup_info_t)); - * - * wakeupInfo->func = func; - * - * wakeupInfo->wakeup_at_jiffy = timer_subticks + period * timer_hz; - * - * wakeupInfo->period = period; - * - * list_insert_front(wakeup_list, wakeupInfo); - * } - */ - -void sleep(unsigned int seconds) -{ - uint32_t future_time = timer_ticks + seconds; - - while (timer_ticks <= future_time) - ; -} +/// MentOS, The Mentoring Operating system project +/// @file timer.c +/// @brief Timer implementation. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "timer.h" +#include "list.h" +#include "kheap.h" +#include "debug.h" +#include "stdint.h" +#include "pic8259.h" +#include "port_io.h" +#include "irqflags.h" + +#define SUBTICKS_PER_TICK 1000 + +/// This will keep track of how many ticks the system has been running for. +static __volatile__ uint64_t timer_subticks = 0; +/// This will keep track of how many seconds the system has been running for. +static __volatile__ uint64_t timer_ticks = 0; + +/// The list of wakeup functions. +// static list_t *wakeup_list; + +void timer_phase(const uint32_t hz) +{ + // Calculate our divisor. + uint32_t divisor = PIT_DIVISOR / hz; + // Set our command byte 0x36. + outportb(PIT_COMREG, PIT_CONFIGURATION); + // Set low byte of divisor. + outportb(PIT_DATAREG0, divisor & PIT_MASK); + // Set high byte of divisor. + outportb(PIT_DATAREG0, (divisor >> 8) & PIT_MASK); +} + +void timer_handler(pt_regs *reg) +{ + (void)reg; + // Check if a second has passed. + if ((++timer_subticks % SUBTICKS_PER_TICK) == 0) { + ++timer_ticks; + } + /* + * if (!list_empty(wakeup_list)) + * { + * listnode_foreach(t, wakeup_list) + * { + * wakeup_info_t *wakeupInfo = (wakeup_info_t *) t->value; + * if (timer_subticks >= wakeupInfo->wakeup_at_jiffy) + * { + * // Call the function. + * wakeupInfo->func(); + * // Reset the timer. + * wakeupInfo->wakeup_at_jiffy = + * timer_subticks + wakeupInfo->period * timer_hz; + * } + * { + * } + */ + + kernel_schedule(reg); + // The ack is sent to PIC only when all handlers terminated! + pic8259_send_eoi(IRQ_TIMER); +} + +void timer_install() +{ + // Intialize the wakeup list (before installing the timer). + // wakeup_list = list_create(); + // Set the timer phase. + timer_phase(SUBTICKS_PER_TICK); + // Installs 'timer_handler' to IRQ0. + irq_install_handler(IRQ_TIMER, timer_handler, "timer"); + // Enable the IRQ of the itemer. + pic8259_irq_enable(IRQ_TIMER); +} + +uint64_t timer_get_ticks() +{ + return timer_ticks; +} + +uint64_t timer_get_subticks() +{ + return timer_subticks; +} + +/* + * void timer_register_wakeup_call(wakeup_callback_t func, uint32_t period) + * { + * + * // Save the function sec, and jiffy to a list, when timer hits that + * // func's jiffy it will call the func, and update next jiffies. + * + * wakeup_info_t *wakeupInfo = kmalloc(sizeof(wakeup_info_t)); + * + * wakeupInfo->func = func; + * + * wakeupInfo->wakeup_at_jiffy = timer_subticks + period * timer_hz; + * + * wakeupInfo->period = period; + * + * list_insert_front(wakeup_list, wakeupInfo); + * } + */ + +void sleep(unsigned int seconds) +{ + uint32_t future_time = timer_ticks + seconds; + + while (timer_ticks <= future_time) + ; +} diff --git a/mentos/src/io/mm_io.c b/mentos/src/io/mm_io.c index b39caa1..0e26312 100644 --- a/mentos/src/io/mm_io.c +++ b/mentos/src/io/mm_io.c @@ -1,37 +1,37 @@ -/// MentOS, The Mentoring Operating system project -/// @file mm_io.c -/// @brief Memory Mapped IO functions implementation. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "mm_io.h" - -uint8_t in_memb(uint32_t addr) -{ - return *((uint8_t *) (addr)); -} - -uint16_t in_mems(uint32_t addr) -{ - return *((uint16_t *) (addr)); -} - -uint32_t in_meml(uint32_t addr) -{ - return *((uint32_t *) (addr)); -} - -void out_memb(uint32_t addr, uint8_t value) -{ - (*((uint8_t *) (addr))) = (value); -} - -void out_mems(uint32_t addr, uint16_t value) -{ - (*((uint16_t *) (addr))) = (value); -} - -void out_meml(uint32_t addr, uint32_t value) -{ - (*((uint32_t *) (addr))) = (value); -} +/// MentOS, The Mentoring Operating system project +/// @file mm_io.c +/// @brief Memory Mapped IO functions implementation. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "mm_io.h" + +uint8_t in_memb(uint32_t addr) +{ + return *((uint8_t *) (addr)); +} + +uint16_t in_mems(uint32_t addr) +{ + return *((uint16_t *) (addr)); +} + +uint32_t in_meml(uint32_t addr) +{ + return *((uint32_t *) (addr)); +} + +void out_memb(uint32_t addr, uint8_t value) +{ + (*((uint8_t *) (addr))) = (value); +} + +void out_mems(uint32_t addr, uint16_t value) +{ + (*((uint16_t *) (addr))) = (value); +} + +void out_meml(uint32_t addr, uint32_t value) +{ + (*((uint32_t *) (addr))) = (value); +} diff --git a/mentos/src/io/port_io.c b/mentos/src/io/port_io.c index ee85812..2997049 100644 --- a/mentos/src/io/port_io.c +++ b/mentos/src/io/port_io.c @@ -1,59 +1,59 @@ -/// MentOS, The Mentoring Operating system project -/// @file port_io.c -/// @brief Byte I/O on ports prototypes. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "port_io.h" - -inline uint8_t inportb(uint16_t port) -{ - unsigned char data = 0; - __asm__ __volatile__("inb %%dx, %%al" : "=a"(data) : "d"(port)); - - return data; -} - -inline uint16_t inports(uint16_t port) -{ - uint16_t rv; - __asm__ __volatile__("inw %1, %0" : "=a"(rv) : "dN"(port)); - - return rv; -} - -void inportsm(uint16_t port, uint8_t *data, unsigned long size) -{ - __asm__ __volatile__("rep insw" - : "+D"(data), "+c"(size) - : "d"(port) - : "memory"); -} - -inline uint32_t inportl(uint16_t port) -{ - uint32_t rv; - __asm__ __volatile__("inl %%dx, %%eax" : "=a"(rv) : "dN"(port)); - - return rv; -} - -inline void outportb(uint16_t port, uint8_t data) -{ - __asm__ __volatile__("outb %%al, %%dx" ::"a"(data), "d"(port)); -} - -inline void outports(uint16_t port, uint16_t data) -{ - __asm__ __volatile__("outw %1, %0" : : "dN"(port), "a"(data)); -} - -void outportsm(uint16_t port, uint8_t *data, uint16_t size) -{ - asm volatile("rep outsw" : "+S"(data), "+c"(size) : "d"(port)); -} - -inline void outportl(uint16_t port, uint32_t data) -{ - __asm__ __volatile__("outl %%eax, %%dx" : : "dN"(port), "a"(data)); -} +/// MentOS, The Mentoring Operating system project +/// @file port_io.c +/// @brief Byte I/O on ports prototypes. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "port_io.h" + +inline uint8_t inportb(uint16_t port) +{ + unsigned char data = 0; + __asm__ __volatile__("inb %%dx, %%al" : "=a"(data) : "d"(port)); + + return data; +} + +inline uint16_t inports(uint16_t port) +{ + uint16_t rv; + __asm__ __volatile__("inw %1, %0" : "=a"(rv) : "dN"(port)); + + return rv; +} + +void inportsm(uint16_t port, uint8_t *data, unsigned long size) +{ + __asm__ __volatile__("rep insw" + : "+D"(data), "+c"(size) + : "d"(port) + : "memory"); +} + +inline uint32_t inportl(uint16_t port) +{ + uint32_t rv; + __asm__ __volatile__("inl %%dx, %%eax" : "=a"(rv) : "dN"(port)); + + return rv; +} + +inline void outportb(uint16_t port, uint8_t data) +{ + __asm__ __volatile__("outb %%al, %%dx" ::"a"(data), "d"(port)); +} + +inline void outports(uint16_t port, uint16_t data) +{ + __asm__ __volatile__("outw %1, %0" : : "dN"(port), "a"(data)); +} + +void outportsm(uint16_t port, uint8_t *data, uint16_t size) +{ + asm volatile("rep outsw" : "+S"(data), "+c"(size) : "d"(port)); +} + +inline void outportl(uint16_t port, uint32_t data) +{ + __asm__ __volatile__("outl %%eax, %%dx" : : "dN"(port), "a"(data)); +} diff --git a/mentos/src/io/video.c b/mentos/src/io/video.c index 6a8760a..1393a07 100644 --- a/mentos/src/io/video.c +++ b/mentos/src/io/video.c @@ -1,381 +1,381 @@ -/// MentOS, The Mentoring Operating system project -/// @file video.c -/// @brief Video functions and costants. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "video.h" -#include "debug.h" -#include "stdbool.h" - -/// The height of the screen. -#define SCREEN_HEIGHT 25 - -/// The width of the screen. -#define SCREEN_WIDTH 80 - -/// @brief Structure used to hold information about the screen. -typedef struct screen_t { - /// The width of the screen. - uint32_t width; - /// The height of the screen. - uint32_t height; - /// Pointer to the memory of the screen. - char *memory; - /// Pointer to a position of the screen. - char *pointer; - /// The current foreground color. - char foreground_color; - /// The current background color. - char background_color; - /// The buffer used when scrolling upward. - char upbuffer[SCREEN_HEIGHT][SCREEN_WIDTH * 2]; - /// The buffer used when scrolling downward. - char downbuffer[SCREEN_HEIGHT][SCREEN_WIDTH * 2]; - /// The output has been scrolled. - bool_t is_scrolled; - /// If the output has been shifted at least once. - bool_t is_shifted_once; - /// Used to store the last x coordiantes (used when scrolling). - uint32_t stored_x; - /// Used to store the last y coordiantes (used when scrolling). - uint32_t stored_y; -} screen_t; - -/// The information concerning the screen. -screen_t screen; - -void video_init() -{ - // =================================== - screen.height = 25; - screen.width = 80; - screen.memory = (char *)0xb8000; - screen.pointer = (char *)0xb8000; - screen.foreground_color = GREY; - screen.background_color = BLACK; - screen.is_scrolled = false; - screen.is_shifted_once = false; - // =================================== - video_clear(); -} - -static inline void _draw_char(char c) -{ - *(screen.pointer++) = c; - *(screen.pointer++) = - (screen.foreground_color + 16 * screen.background_color); -} - -void video_putc(int c) -{ - // If we have stored the last coordinates, this means that we are - // currently scrolling upwards. Thus, we need to scroll down first. - if (screen.stored_x && screen.stored_y) { - video_scroll_down(); - } - // If the character is '\n' go the new line. - if (c == '\n') { - video_new_line(); - } else if (c == '\033') { - __asm__("nop"); - } else if (c == '\t') { - video_put_tab(); - } else if (c == '\b') { - video_delete_last_character(); - } else if (c == '\r') { - video_cartridge_return(); - } else { - _draw_char(c); - } - video_shift_one_line(); - video_set_cursor_auto(); -} - -void video_puts(const char *str) -{ - while ((*str) != 0) { - if ((*str) == '\n') { - video_new_line(); - } else if ((*str) == '\033') { - video_set_color(*(++str)); - } else if ((*str) == '\t') { - video_put_tab(); - } else if ((*str) == '\b') { - video_delete_last_character(); - } else if ((*str) == '\r') { - video_cartridge_return(); - } else { - video_putc((*str)); - } - ++str; - } -} - -void video_set_color(const video_color_t foreground) -{ - screen.foreground_color = foreground; -} - -void video_set_background(const video_color_t background) -{ - screen.background_color = background; -} - -void video_delete_last_character() -{ - if (lower_bound_y != video_get_line() || - lower_bound_x < video_get_column()) { - video_set_color(WHITE); - video_set_background(BLACK); - // Delete any tabular. - int x = video_get_column(); - if ((*(screen.pointer - 2)) == '\t') { - for (int i = 0; (i < (4 - x % 4)); ++i) { - if ((*(screen.pointer - 2)) != '\t') - break; - // Bring back the pointer. - screen.pointer -= 2; - // Delete the character. - _draw_char(' '); - // Bring back the pointer. - screen.pointer -= 2; - } - } else { - // Bring back the pointer. - screen.pointer -= 2; - // Delete the character. - _draw_char(' '); - // Bring back the pointer. - screen.pointer -= 2; - } - } -} - -void video_set_cursor(const unsigned int x, const unsigned int y) -{ - uint32_t position = (x * 80) + y; - - // Cursor LOW port to vga INDEX register. - outportb(0x3D4, 0x0F); - outportb(0x3D5, (uint8_t)(position & 0xFF)); - - // Cursor HIGH port to vga INDEX register. - outportb(0x3D4, 0x0E); - outportb(0x3D5, (uint8_t)((position >> 8) & 0xFF)); -} - -void video_set_cursor_auto() -{ - long x = ((screen.pointer - screen.memory) / 2) / screen.width; - long y = ((screen.pointer - screen.memory) / 2) % screen.width; - - if (x < 0) { - dbg_print("Negative x while setting auto-cursor.\n"); - x = 0; - } - - if (y < 0) { - dbg_print("Negative x while setting auto-cursor.\n"); - y = 0; - } - - video_set_cursor((uint32_t)x, (uint32_t)y); -} - -void video_move_cursor(int x, int y) -{ - screen.pointer = screen.memory + ((y * screen.width * 2) + (x * 2)); - video_set_cursor_auto(); -} - -void video_put_tab() -{ - int foreground = screen.foreground_color; - video_set_color(screen.background_color); - int x = video_get_column(); - for (int i = 0; i < (4 - x % 4); ++i) - _draw_char('\t'); - video_set_color(foreground); -} - -void video_clear() -{ - screen.pointer = screen.memory; - - for (uint32_t y = 0; y < screen.height; y++) { - for (uint32_t x = 0; x < screen.width; x++) { - *(screen.pointer++) = ' '; - *(screen.pointer++) = 0x7; - } - } - - screen.pointer = screen.memory; -} - -void video_new_line() -{ - screen.pointer = - screen.memory + - ((((screen.pointer - screen.memory) / (screen.width * 2)) + 1) * - (screen.width * 2)); - - video_shift_one_line(); - video_set_cursor_auto(); -} - -void video_cartridge_return() -{ - screen.pointer = - screen.memory + - ((((screen.pointer - screen.memory) / (screen.width * 2)) - 1) * - (screen.width * 2)); - - video_new_line(); - - video_shift_one_line(); - - video_set_cursor_auto(); -} - -uint32_t video_get_column() -{ - if (screen.pointer < screen.memory) { - dbg_print("Get negative value while getting video column.\n"); - - return 0; - } - - return ((screen.pointer - screen.memory) % (screen.width * 2)) / 2; -} - -uint32_t video_get_line() -{ - if (screen.pointer < screen.memory) { - dbg_print("Get negative value while getting video line.\n"); - - return 0; - } - - return ((screen.pointer - screen.memory) / (screen.width * 2)); -} - -void video_shift_one_line(void) -{ - if (screen.pointer >= - screen.memory + ((screen.height) * screen.width * 2)) { - /* We save the line to be lost in a buffer, this will be useful for - * scrolling. - */ - video_rotate_scroll_buffer(); - uint32_t index; - - for (index = 0; index < screen.width * 2; index++) { - screen.upbuffer[screen.height - 1][index] = - *(screen.memory + index); - } - - for (char *i = screen.memory; - i <= (screen.memory + ((screen.height) * screen.width * 2) + - (screen.width * 2)); - ++i) { - *i = i[screen.width * 2]; - } - screen.pointer = - screen.memory + - ((((screen.pointer - screen.memory) / (screen.width * 2)) - 1) * - (screen.width * 2)); - // Set that the scroll has been shifted at least once. - screen.is_shifted_once = true; - } -} - -void video_rotate_scroll_buffer() -{ - for (uint32_t y = 1; y < screen.height; y++) { - for (uint32_t x = 0; x < screen.width * 2; x++) { - screen.upbuffer[y - 1][x] = screen.upbuffer[y][x]; - } - } -} - -void video_scroll_up() -{ - char *ptr = screen.memory; - - if (screen.is_scrolled || !screen.is_shifted_once) { - return; - } - - for (uint32_t y = 0; y < screen.height; y++) { - for (uint32_t x = 0; x < screen.width * 2; x++) { - screen.downbuffer[y][x] = *ptr; - *ptr++ = screen.upbuffer[y][x]; - } - } - - screen.is_scrolled = true; - - screen.stored_x = video_get_column(); - - screen.stored_y = video_get_line(); - - video_move_cursor(screen.width, screen.height); -} - -void video_scroll_down() -{ - char *ptr = screen.memory; - - // If PAGEUP hasn't been pressed, it's useless to go down, there is nothing. - if (!screen.is_scrolled) { - return; - } - for (uint32_t y = 0; y < screen.height; y++) { - for (uint32_t x = 0; x < screen.width * 2; x++) { - *ptr++ = screen.downbuffer[y][x]; - } - } - - screen.is_scrolled = false; - - video_move_cursor(screen.stored_x, screen.stored_y); - - screen.stored_x = 0; - - screen.stored_y = 0; -} - -void video_print_ok() -{ - video_move_cursor(60, video_get_line()); - - video_set_color(WHITE); - - video_putc('['); - - video_set_color(BRIGHT_GREEN); - - video_puts("OK"); - - video_set_color(WHITE); - - video_puts("]\n"); -} - -void video_print_fail() -{ - video_move_cursor(60, video_get_line()); - - video_set_color(WHITE); - - video_putc('['); - - video_set_color(BRIGHT_RED); - - video_puts("FAIL"); - - video_set_color(WHITE); - - video_puts("]\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file video.c +/// @brief Video functions and costants. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "video.h" +#include "debug.h" +#include "stdbool.h" + +/// The height of the screen. +#define SCREEN_HEIGHT 25 + +/// The width of the screen. +#define SCREEN_WIDTH 80 + +/// @brief Structure used to hold information about the screen. +typedef struct screen_t { + /// The width of the screen. + uint32_t width; + /// The height of the screen. + uint32_t height; + /// Pointer to the memory of the screen. + char *memory; + /// Pointer to a position of the screen. + char *pointer; + /// The current foreground color. + char foreground_color; + /// The current background color. + char background_color; + /// The buffer used when scrolling upward. + char upbuffer[SCREEN_HEIGHT][SCREEN_WIDTH * 2]; + /// The buffer used when scrolling downward. + char downbuffer[SCREEN_HEIGHT][SCREEN_WIDTH * 2]; + /// The output has been scrolled. + bool_t is_scrolled; + /// If the output has been shifted at least once. + bool_t is_shifted_once; + /// Used to store the last x coordiantes (used when scrolling). + uint32_t stored_x; + /// Used to store the last y coordiantes (used when scrolling). + uint32_t stored_y; +} screen_t; + +/// The information concerning the screen. +screen_t screen; + +void video_init() +{ + // =================================== + screen.height = 25; + screen.width = 80; + screen.memory = (char *)0xb8000; + screen.pointer = (char *)0xb8000; + screen.foreground_color = GREY; + screen.background_color = BLACK; + screen.is_scrolled = false; + screen.is_shifted_once = false; + // =================================== + video_clear(); +} + +static inline void _draw_char(char c) +{ + *(screen.pointer++) = c; + *(screen.pointer++) = + (screen.foreground_color + 16 * screen.background_color); +} + +void video_putc(int c) +{ + // If we have stored the last coordinates, this means that we are + // currently scrolling upwards. Thus, we need to scroll down first. + if (screen.stored_x && screen.stored_y) { + video_scroll_down(); + } + // If the character is '\n' go the new line. + if (c == '\n') { + video_new_line(); + } else if (c == '\033') { + __asm__("nop"); + } else if (c == '\t') { + video_put_tab(); + } else if (c == '\b') { + video_delete_last_character(); + } else if (c == '\r') { + video_cartridge_return(); + } else { + _draw_char(c); + } + video_shift_one_line(); + video_set_cursor_auto(); +} + +void video_puts(const char *str) +{ + while ((*str) != 0) { + if ((*str) == '\n') { + video_new_line(); + } else if ((*str) == '\033') { + video_set_color(*(++str)); + } else if ((*str) == '\t') { + video_put_tab(); + } else if ((*str) == '\b') { + video_delete_last_character(); + } else if ((*str) == '\r') { + video_cartridge_return(); + } else { + video_putc((*str)); + } + ++str; + } +} + +void video_set_color(const video_color_t foreground) +{ + screen.foreground_color = foreground; +} + +void video_set_background(const video_color_t background) +{ + screen.background_color = background; +} + +void video_delete_last_character() +{ + if (lower_bound_y != video_get_line() || + lower_bound_x < video_get_column()) { + video_set_color(WHITE); + video_set_background(BLACK); + // Delete any tabular. + int x = video_get_column(); + if ((*(screen.pointer - 2)) == '\t') { + for (int i = 0; (i < (4 - x % 4)); ++i) { + if ((*(screen.pointer - 2)) != '\t') + break; + // Bring back the pointer. + screen.pointer -= 2; + // Delete the character. + _draw_char(' '); + // Bring back the pointer. + screen.pointer -= 2; + } + } else { + // Bring back the pointer. + screen.pointer -= 2; + // Delete the character. + _draw_char(' '); + // Bring back the pointer. + screen.pointer -= 2; + } + } +} + +void video_set_cursor(const unsigned int x, const unsigned int y) +{ + uint32_t position = (x * 80) + y; + + // Cursor LOW port to vga INDEX register. + outportb(0x3D4, 0x0F); + outportb(0x3D5, (uint8_t)(position & 0xFF)); + + // Cursor HIGH port to vga INDEX register. + outportb(0x3D4, 0x0E); + outportb(0x3D5, (uint8_t)((position >> 8) & 0xFF)); +} + +void video_set_cursor_auto() +{ + long x = ((screen.pointer - screen.memory) / 2) / screen.width; + long y = ((screen.pointer - screen.memory) / 2) % screen.width; + + if (x < 0) { + dbg_print("Negative x while setting auto-cursor.\n"); + x = 0; + } + + if (y < 0) { + dbg_print("Negative x while setting auto-cursor.\n"); + y = 0; + } + + video_set_cursor((uint32_t)x, (uint32_t)y); +} + +void video_move_cursor(int x, int y) +{ + screen.pointer = screen.memory + ((y * screen.width * 2) + (x * 2)); + video_set_cursor_auto(); +} + +void video_put_tab() +{ + int foreground = screen.foreground_color; + video_set_color(screen.background_color); + int x = video_get_column(); + for (int i = 0; i < (4 - x % 4); ++i) + _draw_char('\t'); + video_set_color(foreground); +} + +void video_clear() +{ + screen.pointer = screen.memory; + + for (uint32_t y = 0; y < screen.height; y++) { + for (uint32_t x = 0; x < screen.width; x++) { + *(screen.pointer++) = ' '; + *(screen.pointer++) = 0x7; + } + } + + screen.pointer = screen.memory; +} + +void video_new_line() +{ + screen.pointer = + screen.memory + + ((((screen.pointer - screen.memory) / (screen.width * 2)) + 1) * + (screen.width * 2)); + + video_shift_one_line(); + video_set_cursor_auto(); +} + +void video_cartridge_return() +{ + screen.pointer = + screen.memory + + ((((screen.pointer - screen.memory) / (screen.width * 2)) - 1) * + (screen.width * 2)); + + video_new_line(); + + video_shift_one_line(); + + video_set_cursor_auto(); +} + +uint32_t video_get_column() +{ + if (screen.pointer < screen.memory) { + dbg_print("Get negative value while getting video column.\n"); + + return 0; + } + + return ((screen.pointer - screen.memory) % (screen.width * 2)) / 2; +} + +uint32_t video_get_line() +{ + if (screen.pointer < screen.memory) { + dbg_print("Get negative value while getting video line.\n"); + + return 0; + } + + return ((screen.pointer - screen.memory) / (screen.width * 2)); +} + +void video_shift_one_line(void) +{ + if (screen.pointer >= + screen.memory + ((screen.height) * screen.width * 2)) { + /* We save the line to be lost in a buffer, this will be useful for + * scrolling. + */ + video_rotate_scroll_buffer(); + uint32_t index; + + for (index = 0; index < screen.width * 2; index++) { + screen.upbuffer[screen.height - 1][index] = + *(screen.memory + index); + } + + for (char *i = screen.memory; + i <= (screen.memory + ((screen.height) * screen.width * 2) + + (screen.width * 2)); + ++i) { + *i = i[screen.width * 2]; + } + screen.pointer = + screen.memory + + ((((screen.pointer - screen.memory) / (screen.width * 2)) - 1) * + (screen.width * 2)); + // Set that the scroll has been shifted at least once. + screen.is_shifted_once = true; + } +} + +void video_rotate_scroll_buffer() +{ + for (uint32_t y = 1; y < screen.height; y++) { + for (uint32_t x = 0; x < screen.width * 2; x++) { + screen.upbuffer[y - 1][x] = screen.upbuffer[y][x]; + } + } +} + +void video_scroll_up() +{ + char *ptr = screen.memory; + + if (screen.is_scrolled || !screen.is_shifted_once) { + return; + } + + for (uint32_t y = 0; y < screen.height; y++) { + for (uint32_t x = 0; x < screen.width * 2; x++) { + screen.downbuffer[y][x] = *ptr; + *ptr++ = screen.upbuffer[y][x]; + } + } + + screen.is_scrolled = true; + + screen.stored_x = video_get_column(); + + screen.stored_y = video_get_line(); + + video_move_cursor(screen.width, screen.height); +} + +void video_scroll_down() +{ + char *ptr = screen.memory; + + // If PAGEUP hasn't been pressed, it's useless to go down, there is nothing. + if (!screen.is_scrolled) { + return; + } + for (uint32_t y = 0; y < screen.height; y++) { + for (uint32_t x = 0; x < screen.width * 2; x++) { + *ptr++ = screen.downbuffer[y][x]; + } + } + + screen.is_scrolled = false; + + video_move_cursor(screen.stored_x, screen.stored_y); + + screen.stored_x = 0; + + screen.stored_y = 0; +} + +void video_print_ok() +{ + video_move_cursor(60, video_get_line()); + + video_set_color(WHITE); + + video_putc('['); + + video_set_color(BRIGHT_GREEN); + + video_puts("OK"); + + video_set_color(WHITE); + + video_puts("]\n"); +} + +void video_print_fail() +{ + video_move_cursor(60, video_get_line()); + + video_set_color(WHITE); + + video_putc('['); + + video_set_color(BRIGHT_RED); + + video_puts("FAIL"); + + video_set_color(WHITE); + + video_puts("]\n"); +} diff --git a/mentos/src/kernel.c b/mentos/src/kernel.c index 87d6c28..4344ef8 100644 --- a/mentos/src/kernel.c +++ b/mentos/src/kernel.c @@ -1,261 +1,261 @@ -/// MentOS, The Mentoring Operating system project -/// @file kernel.c -/// @brief Kernel main function. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "kernel.h" -#include "zone_allocator.h" -#include "gdt.h" -#include "syscall.h" -#include "version.h" -#include "video.h" - -#include "pic8259.h" - -#include "cmd_cpuid.h" -#include "debug.h" -#include "fdc.h" -#include "initrd.h" -#include "irqflags.h" -#include "keyboard.h" -#include "scheduler.h" -#include "shell.h" -#include "stdio.h" -#include "timer.h" -#include "vfs.h" - -#include "kheap.h" - -#include "init.h" - -#include "pci.h" -#include "fpu.h" -#include "ata.h" - -#include "printk.h" - -/// Describe start and end address of grub multiboot modules -char *module_start[MAX_MODULES]; -char *module_end[MAX_MODULES]; - -/// Defined in kernel.ld, points at the multiheader grub info. -extern uint32_t _multiboot_header_start; -extern uint32_t _multiboot_header_end; -/// Defined in kernel.ld, points at the kernel code. -extern uint32_t _text_start; -extern uint32_t _text_end; -/// Defined in kernel.ld, points at the read-only kernel data. -extern uint32_t _rodata_start; -extern uint32_t _rodata_end; -/// Defined in kernel.ld, points at the read-write kernel data initialized. -extern uint32_t _data_start; -extern uint32_t _data_end; -/// Defined in kernel.ld, points at the read-write kernel data uninitialized an kernel stack. -extern uint32_t _bss_start; -extern uint32_t _bss_end; -extern uint32_t stack_top; -extern uint32_t stack_bottom; -/// Defined in kernel.ld, points at the end of kernel code/data. -extern uint32_t end; - -uintptr_t initial_esp = 0; - -int kmain(uint32_t magic, multiboot_info_t *header, uintptr_t esp) -{ - dbg_print("\n"); - dbg_print("--------------------------------------------------\n"); - dbg_print("- Booting...\n"); - dbg_print("--------------------------------------------------\n"); - - // Print kernel initial state - dbg_print("\n KERNEL STATE ON BOOTING"); - dbg_print("\nKernel multiboot header: [ 0x%p - 0x%p ] ", - &_multiboot_header_start, &_multiboot_header_end); - dbg_print("\nKernel code: [ 0x%p - 0x%p ] <- text ", - &_text_start, &_text_end); - dbg_print("\nKernel read-only data: [ 0x%p - 0x%p ] <- rodata ", - &_rodata_start, &_rodata_end); - dbg_print("\nKernel initialized data: [ 0x%p - 0x%p ] <- data ", - &_data_start, &_data_end); - dbg_print("\nKernel uninitialized data: [ 0x%p - 0x%p ] <- stack & bss", - &_bss_start, &_bss_end); - dbg_print("\n - Kernel stack: [ 0x%p - 0x%p ] ", - &stack_bottom, &stack_top); - dbg_print("\n - Kernel bss: [ 0x%p - 0x%p ] ", - &stack_top, &_bss_end); - dbg_print("\nKernel image end: 0x%p", &end); - - // Am I booted by a Multiboot-compliant boot loader? - if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { - printk("Invalid magic number: 0x%x\n", (unsigned)magic); - return 1; - } - - // Set the initial esp. - initial_esp = esp; - - // Dump the multiboot structure. - dump_multiboot(header); - - //=== Initialize the video ================================================= - video_init(); - //-------------------------------------------------------------------------- - - //==== Show Operating System Version ======================================= - video_set_color(BRIGHT_GREEN); - printk(OS_NAME " " OS_VERSION); - video_set_color(WHITE); - printk("\nSite:"); - video_set_color(BRIGHT_BLUE); - printk(OS_SITEURL); - printk("\n"); - video_set_color(WHITE); - printk("\n"); - //-------------------------------------------------------------------------- - - //==== Set the starting point and end point of the module ================== - int i = 0; - multiboot_module_t *mod = (multiboot_module_t *)header->mods_addr; - for (; i < header->mods_count && i < MAX_MODULES; i++, mod++) { - module_start[i] = (char *)mod->mod_start; - module_end[i] = (char *)mod->mod_end; - } - //========================================================================== - - //==== Initialize memory =================================================== - printk("Initialize physical memory manager..."); - // Memoria fisica totale allocata: 1096 MB - if (!pmmngr_init(1096 * M + 512 * 4 * K)) { - video_print_fail(); - return 1; - } - video_print_ok(); - //========================================================================== - - //==== Initialize kernel heap ============================================== - dbg_print("Initialize kernel heap.\n"); - printk("Initialize heap..."); - kheap_init(KHEAP_INITIAL_SIZE); - video_print_ok(); - //========================================================================== - - //==== Initialize core modules ============================================= - // The Global Descriptor Table (GDT) is a data structure used by Intel - // x86-family processors starting with the 80286 in order to define the - // characteristics of the various memory areas used during program execution, - // including the base address, the size, and access privileges like - // executability and writability. These memory areas are called segments in - // Intel terminology. - printk("Initialize GDT..."); - init_gdt(); - video_print_ok(); - - // The IDT is used to show the processor what Interrupt Service Routine - // (ISR) to call to handle an exception. IDT entries are also called - // Interrupt requests whenever a device has completed a request and needs to - // be serviced. - // ISRs are used to save the current processor state and set up the - // appropriate segment registers needed for kernel mode before the kernel’s - // C-level interrupt handler is called. To handle the right exception, the - // correct entry in the IDT should be pointed to the correct ISR. - printk("Initialize IDT..."); - init_idt(); - video_print_ok(); - //-------------------------------------------------------------------------- - - // Initialize the system calls. - printk("Initialize system calls..."); - syscall_init(); - video_print_ok(); - - // Set the IRQs. - printk("Initialize IRQ..."); - pic8259_init_irq(); - video_print_ok(); - - //dbg_print("Initialize the paging.\n"); - // Initialize the paging. - //printk("Initialize the paging..."); - //paging_init(); - //video_print_ok(); - - dbg_print("Install the timer.\n"); - // Install the timer. - printk(" * Setting up timer..."); - timer_install(); - video_print_ok(); - - //dbg_print("Alloc and fill CPUID structure.\n"); - // Alloc and fill CPUID structure. - //printk(LNG_INIT_CPUID); - //get_cpuid(&sinfo); - //video_print_ok(); - - dbg_print("Initialize the filesystem.\n"); - // Initialize the filesystem. - printk("Initialize the fylesystem..."); - vfs_init(); - video_print_ok(); - initfs_init(); - - //dbg_print("Get the kernel image from the boot info.\n"); - // Get the kernel image from the boot info - //build_elf_symbols_from_multiboot(header); - - //==== Install/Uninstall devices =========================================== - // For debugging, show the list of PCI devices. - // pci_debug_scan(); - // Scan for ata devices. - // ata_initialize(); - - dbg_print("Install the keyboard.\n"); - printk(" * Setting up keyboard driver..."); - keyboard_install(); - video_print_ok(); - - // dbg_print("Install the mouse.\n"); - // printf(" * Setting up mouse driver..."); - // mouse_install(); // Install the mouse. - // video_print_ok(); - - dbg_print("Uninstall the floppy driver.\n"); - fdc_disable_motor(); // We disable floppy driver motor - //-------------------------------------------------------------------------- - - //==== Initialize the scheduler ============================================ - dbg_print("Initialize the scheduler.\n"); - printk("Initialize the scheduler..."); - kernel_initialize_scheduler(); - video_print_ok(); - //-------------------------------------------------------------------------- - - // create init process - task_struct *init_p = create_init_process(); - - //==== Initialize the FPU ================================================= - // Initialize the Floating Point Unit (FPU). - dbg_print("Initialize the Floating Point Unit (FPU).\n"); - printk("Initialize floating point unit..."); - if (!fpu_install()) { - video_print_fail(); - return 1; - } - video_print_ok(); - - dbg_print("--------------------------------------------------\n"); - dbg_print("- Booting Done\n"); - dbg_print("- Jumping into init process, hopefully...\n"); - dbg_print("--------------------------------------------------\n"); - - // Jump into init process. - enter_user_jmp( - // Entry point. - init_p->thread.eip, - // Stack pointer. - init_p->thread.useresp); - - dbg_print("Dear developer, we have to talk...\n"); - - return 1; -} +/// MentOS, The Mentoring Operating system project +/// @file kernel.c +/// @brief Kernel main function. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "kernel.h" +#include "zone_allocator.h" +#include "gdt.h" +#include "syscall.h" +#include "version.h" +#include "video.h" + +#include "pic8259.h" + +#include "cmd_cpuid.h" +#include "debug.h" +#include "fdc.h" +#include "initrd.h" +#include "irqflags.h" +#include "keyboard.h" +#include "scheduler.h" +#include "shell.h" +#include "stdio.h" +#include "timer.h" +#include "vfs.h" + +#include "kheap.h" + +#include "init.h" + +#include "pci.h" +#include "fpu.h" +#include "ata.h" + +#include "printk.h" + +/// Describe start and end address of grub multiboot modules +char *module_start[MAX_MODULES]; +char *module_end[MAX_MODULES]; + +/// Defined in kernel.ld, points at the multiheader grub info. +extern uint32_t _multiboot_header_start; +extern uint32_t _multiboot_header_end; +/// Defined in kernel.ld, points at the kernel code. +extern uint32_t _text_start; +extern uint32_t _text_end; +/// Defined in kernel.ld, points at the read-only kernel data. +extern uint32_t _rodata_start; +extern uint32_t _rodata_end; +/// Defined in kernel.ld, points at the read-write kernel data initialized. +extern uint32_t _data_start; +extern uint32_t _data_end; +/// Defined in kernel.ld, points at the read-write kernel data uninitialized an kernel stack. +extern uint32_t _bss_start; +extern uint32_t _bss_end; +extern uint32_t stack_top; +extern uint32_t stack_bottom; +/// Defined in kernel.ld, points at the end of kernel code/data. +extern uint32_t end; + +uintptr_t initial_esp = 0; + +int kmain(uint32_t magic, multiboot_info_t *header, uintptr_t esp) +{ + dbg_print("\n"); + dbg_print("--------------------------------------------------\n"); + dbg_print("- Booting...\n"); + dbg_print("--------------------------------------------------\n"); + + // Print kernel initial state + dbg_print("\n KERNEL STATE ON BOOTING"); + dbg_print("\nKernel multiboot header: [ 0x%p - 0x%p ] ", + &_multiboot_header_start, &_multiboot_header_end); + dbg_print("\nKernel code: [ 0x%p - 0x%p ] <- text ", + &_text_start, &_text_end); + dbg_print("\nKernel read-only data: [ 0x%p - 0x%p ] <- rodata ", + &_rodata_start, &_rodata_end); + dbg_print("\nKernel initialized data: [ 0x%p - 0x%p ] <- data ", + &_data_start, &_data_end); + dbg_print("\nKernel uninitialized data: [ 0x%p - 0x%p ] <- stack & bss", + &_bss_start, &_bss_end); + dbg_print("\n - Kernel stack: [ 0x%p - 0x%p ] ", + &stack_bottom, &stack_top); + dbg_print("\n - Kernel bss: [ 0x%p - 0x%p ] ", + &stack_top, &_bss_end); + dbg_print("\nKernel image end: 0x%p", &end); + + // Am I booted by a Multiboot-compliant boot loader? + if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { + printk("Invalid magic number: 0x%x\n", (unsigned)magic); + return 1; + } + + // Set the initial esp. + initial_esp = esp; + + // Dump the multiboot structure. + dump_multiboot(header); + + //=== Initialize the video ================================================= + video_init(); + //-------------------------------------------------------------------------- + + //==== Show Operating System Version ======================================= + video_set_color(BRIGHT_GREEN); + printk(OS_NAME " " OS_VERSION); + video_set_color(WHITE); + printk("\nSite:"); + video_set_color(BRIGHT_BLUE); + printk(OS_SITEURL); + printk("\n"); + video_set_color(WHITE); + printk("\n"); + //-------------------------------------------------------------------------- + + //==== Set the starting point and end point of the module ================== + int i = 0; + multiboot_module_t *mod = (multiboot_module_t *)header->mods_addr; + for (; i < header->mods_count && i < MAX_MODULES; i++, mod++) { + module_start[i] = (char *)mod->mod_start; + module_end[i] = (char *)mod->mod_end; + } + //========================================================================== + + //==== Initialize memory =================================================== + printk("Initialize physical memory manager..."); + // Memoria fisica totale allocata: 1096 MB + if (!pmmngr_init(1096 * M + 512 * 4 * K)) { + video_print_fail(); + return 1; + } + video_print_ok(); + //========================================================================== + + //==== Initialize kernel heap ============================================== + dbg_print("Initialize kernel heap.\n"); + printk("Initialize heap..."); + kheap_init(KHEAP_INITIAL_SIZE); + video_print_ok(); + //========================================================================== + + //==== Initialize core modules ============================================= + // The Global Descriptor Table (GDT) is a data structure used by Intel + // x86-family processors starting with the 80286 in order to define the + // characteristics of the various memory areas used during program execution, + // including the base address, the size, and access privileges like + // executability and writability. These memory areas are called segments in + // Intel terminology. + printk("Initialize GDT..."); + init_gdt(); + video_print_ok(); + + // The IDT is used to show the processor what Interrupt Service Routine + // (ISR) to call to handle an exception. IDT entries are also called + // Interrupt requests whenever a device has completed a request and needs to + // be serviced. + // ISRs are used to save the current processor state and set up the + // appropriate segment registers needed for kernel mode before the kernel’s + // C-level interrupt handler is called. To handle the right exception, the + // correct entry in the IDT should be pointed to the correct ISR. + printk("Initialize IDT..."); + init_idt(); + video_print_ok(); + //-------------------------------------------------------------------------- + + // Initialize the system calls. + printk("Initialize system calls..."); + syscall_init(); + video_print_ok(); + + // Set the IRQs. + printk("Initialize IRQ..."); + pic8259_init_irq(); + video_print_ok(); + + //dbg_print("Initialize the paging.\n"); + // Initialize the paging. + //printk("Initialize the paging..."); + //paging_init(); + //video_print_ok(); + + dbg_print("Install the timer.\n"); + // Install the timer. + printk(" * Setting up timer..."); + timer_install(); + video_print_ok(); + + //dbg_print("Alloc and fill CPUID structure.\n"); + // Alloc and fill CPUID structure. + //printk(LNG_INIT_CPUID); + //get_cpuid(&sinfo); + //video_print_ok(); + + dbg_print("Initialize the filesystem.\n"); + // Initialize the filesystem. + printk("Initialize the fylesystem..."); + vfs_init(); + video_print_ok(); + initfs_init(); + + //dbg_print("Get the kernel image from the boot info.\n"); + // Get the kernel image from the boot info + //build_elf_symbols_from_multiboot(header); + + //==== Install/Uninstall devices =========================================== + // For debugging, show the list of PCI devices. + // pci_debug_scan(); + // Scan for ata devices. + // ata_initialize(); + + dbg_print("Install the keyboard.\n"); + printk(" * Setting up keyboard driver..."); + keyboard_install(); + video_print_ok(); + + // dbg_print("Install the mouse.\n"); + // printf(" * Setting up mouse driver..."); + // mouse_install(); // Install the mouse. + // video_print_ok(); + + dbg_print("Uninstall the floppy driver.\n"); + fdc_disable_motor(); // We disable floppy driver motor + //-------------------------------------------------------------------------- + + //==== Initialize the scheduler ============================================ + dbg_print("Initialize the scheduler.\n"); + printk("Initialize the scheduler..."); + kernel_initialize_scheduler(); + video_print_ok(); + //-------------------------------------------------------------------------- + + // create init process + task_struct *init_p = create_init_process(); + + //==== Initialize the FPU ================================================= + // Initialize the Floating Point Unit (FPU). + dbg_print("Initialize the Floating Point Unit (FPU).\n"); + printk("Initialize floating point unit..."); + if (!fpu_install()) { + video_print_fail(); + return 1; + } + video_print_ok(); + + dbg_print("--------------------------------------------------\n"); + dbg_print("- Booting Done\n"); + dbg_print("- Jumping into init process, hopefully...\n"); + dbg_print("--------------------------------------------------\n"); + + // Jump into init process. + enter_user_jmp( + // Entry point. + init_p->thread.eip, + // Stack pointer. + init_p->thread.useresp); + + dbg_print("Dear developer, we have to talk...\n"); + + return 1; +} diff --git a/mentos/src/kernel/sys.c b/mentos/src/kernel/sys.c index e1c022e..0248062 100644 --- a/mentos/src/kernel/sys.c +++ b/mentos/src/kernel/sys.c @@ -1,72 +1,72 @@ -/// MentOS, The Mentoring Operating system project -/// @file sys.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "stdio.h" -#include "errno.h" -#include "mutex.h" -#include "reboot.h" -#include "stdatomic.h" - -static void machine_power_off() -{ - while (true) { - cpu_relax(); - } -} - -/// @brief Shutdown everything and perform a clean system power_off. -static void kernel_power_off() -{ - // kernel_shutdown_prepare(SYSTEM_POWER_OFF); - // if (pm_power_off_prepare) - // { - // pm_power_off_prepare(); - // } - // migrate_to_reboot_cpu(); - // syscore_shutdown(); - printf("Power down\n"); - // kmsg_dump(KMSG_DUMP_POWEROFF); - machine_power_off(); -} - -int sys_reboot(int magic1, int magic2, unsigned int cmd, void *arg) -{ - static mutex_t reboot_mutex; - - // For safety, we require "magic" arguments. - if (magic1 != LINUX_REBOOT_MAGIC1 || - (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && - magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C)) { - return -EINVAL; - } - - mutex_lock(&reboot_mutex, 0); - - switch (cmd) { - case LINUX_REBOOT_CMD_RESTART: - break; - case LINUX_REBOOT_CMD_CAD_ON: - break; - case LINUX_REBOOT_CMD_CAD_OFF: - break; - case LINUX_REBOOT_CMD_HALT: - break; - case LINUX_REBOOT_CMD_POWER_OFF: - kernel_power_off(); - break; - case LINUX_REBOOT_CMD_RESTART2: - break; - case LINUX_REBOOT_CMD_KEXEC: - break; - case LINUX_REBOOT_CMD_SW_SUSPEND: - break; - default: - return -EINVAL; - } - mutex_unlock(&reboot_mutex); - - return 0; -} +/// MentOS, The Mentoring Operating system project +/// @file sys.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "stdio.h" +#include "errno.h" +#include "mutex.h" +#include "reboot.h" +#include "stdatomic.h" + +static void machine_power_off() +{ + while (true) { + cpu_relax(); + } +} + +/// @brief Shutdown everything and perform a clean system power_off. +static void kernel_power_off() +{ + // kernel_shutdown_prepare(SYSTEM_POWER_OFF); + // if (pm_power_off_prepare) + // { + // pm_power_off_prepare(); + // } + // migrate_to_reboot_cpu(); + // syscore_shutdown(); + printf("Power down\n"); + // kmsg_dump(KMSG_DUMP_POWEROFF); + machine_power_off(); +} + +int sys_reboot(int magic1, int magic2, unsigned int cmd, void *arg) +{ + static mutex_t reboot_mutex; + + // For safety, we require "magic" arguments. + if (magic1 != LINUX_REBOOT_MAGIC1 || + (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && + magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C)) { + return -EINVAL; + } + + mutex_lock(&reboot_mutex, 0); + + switch (cmd) { + case LINUX_REBOOT_CMD_RESTART: + break; + case LINUX_REBOOT_CMD_CAD_ON: + break; + case LINUX_REBOOT_CMD_CAD_OFF: + break; + case LINUX_REBOOT_CMD_HALT: + break; + case LINUX_REBOOT_CMD_POWER_OFF: + kernel_power_off(); + break; + case LINUX_REBOOT_CMD_RESTART2: + break; + case LINUX_REBOOT_CMD_KEXEC: + break; + case LINUX_REBOOT_CMD_SW_SUSPEND: + break; + default: + return -EINVAL; + } + mutex_unlock(&reboot_mutex); + + return 0; +} diff --git a/mentos/src/libc/assert.c b/mentos/src/libc/assert.c index 6e49f96..624725f 100644 --- a/mentos/src/libc/assert.c +++ b/mentos/src/libc/assert.c @@ -1,22 +1,22 @@ -/// MentOS, The Mentoring Operating system project -/// @file assert.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "assert.h" -#include "stdio.h" -#include "panic.h" - -void __assert_fail(const char *assertion, const char *file, unsigned int line, - const char *function) -{ - char message[1024]; - sprintf(message, - "FILE: %s\n" - "LINE: %d\n" - "FUNC: %s\n\n" - "Assertion `%s` failed.\n", - file, line, (function ? function : "NO_FUN"), assertion); - kernel_panic(message); -} +/// MentOS, The Mentoring Operating system project +/// @file assert.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "assert.h" +#include "stdio.h" +#include "panic.h" + +void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function) +{ + char message[1024]; + sprintf(message, + "FILE: %s\n" + "LINE: %d\n" + "FUNC: %s\n\n" + "Assertion `%s` failed.\n", + file, line, (function ? function : "NO_FUN"), assertion); + kernel_panic(message); +} diff --git a/mentos/src/libc/bitset.c b/mentos/src/libc/bitset.c index b9f3112..815abda 100644 --- a/mentos/src/libc/bitset.c +++ b/mentos/src/libc/bitset.c @@ -1,120 +1,120 @@ -/// MentOS, The Mentoring Operating system project -/// @file bitset.c -/// @brief Bitset data structure. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "bitset.h" -#include "math.h" -#include "string.h" -#include "stdlib.h" -#include "assert.h" - -/// @brief -/// @param bit -/// @param index -/// @param mask -static void get_index_and_mask(size_t bit, size_t *index, size_t *mask) -{ - assert(index); - - assert(mask); - - (*index) = bit >> 3; - - bit = bit - (*index) * 8; - - size_t offset = bit & 7; - - (*mask) = 1UL << offset; -} - -/// @brief -/// @param set -/// @param size - -/* - * static void bitset_resize(bitset_t *set, size_t size) - * { - * assert(set && "Received NULL set."); - * - * if (set->size >= size) - * { - * return; - * } - * set->data = realloc(set->data, size); - * - * memset(set->data + set->size, 0, size - set->size); - * - * set->size = size; - * - * } - */ - -void bitset_init(bitset_t *set, size_t size) -{ - assert(set && "Received NULL set."); - - set->size = ceil(size, 8); - - set->data = calloc(set->size, 1); -} - -void bitset_free(bitset_t *set) -{ - assert(set && "Received NULL set."); - - free(set->data); -} - -/* - * void bitset_set(bitset_t *set, size_t bit) - * { - * assert(set && "Received NULL set."); - * size_t index, mask; - * - * get_index_and_mask(bit, &index, &mask); - * - * if (set->size <= index) - * { - * bitset_resize(set, set->size << 1); - * } - * - * set->data[index] |= mask; - * } - */ - -void bitset_clear(bitset_t *set, size_t bit) -{ - assert(set && "Received NULL set."); - - size_t index, mask; - - get_index_and_mask(bit, &index, &mask); - - set->data[index] &= ~mask; -} - -bool_t bitset_test(bitset_t *set, size_t bit) -{ - assert(set && "Received NULL set."); - - size_t index, mask; - - get_index_and_mask(bit, &index, &mask); - - return (mask & set->data[index]) != 0; -} - -signed long bitset_find_first_unset_bit(bitset_t *set) -{ - assert(set && "Received NULL set."); - - for (size_t i = 0; i < (set->size * 8); i++) { - if (!bitset_test(set, i)) { - return (signed long)i; - } - } - - return -1; -} +/// MentOS, The Mentoring Operating system project +/// @file bitset.c +/// @brief Bitset data structure. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "bitset.h" +#include "math.h" +#include "string.h" +#include "stdlib.h" +#include "assert.h" + +/// @brief +/// @param bit +/// @param index +/// @param mask +static void get_index_and_mask(size_t bit, size_t *index, size_t *mask) +{ + assert(index); + + assert(mask); + + (*index) = bit >> 3; + + bit = bit - (*index) * 8; + + size_t offset = bit & 7; + + (*mask) = 1UL << offset; +} + +/// @brief +/// @param set +/// @param size + +/* + * static void bitset_resize(bitset_t *set, size_t size) + * { + * assert(set && "Received NULL set."); + * + * if (set->size >= size) + * { + * return; + * } + * set->data = realloc(set->data, size); + * + * memset(set->data + set->size, 0, size - set->size); + * + * set->size = size; + * + * } + */ + +void bitset_init(bitset_t *set, size_t size) +{ + assert(set && "Received NULL set."); + + set->size = ceil(size, 8); + + set->data = calloc(set->size, 1); +} + +void bitset_free(bitset_t *set) +{ + assert(set && "Received NULL set."); + + free(set->data); +} + +/* + * void bitset_set(bitset_t *set, size_t bit) + * { + * assert(set && "Received NULL set."); + * size_t index, mask; + * + * get_index_and_mask(bit, &index, &mask); + * + * if (set->size <= index) + * { + * bitset_resize(set, set->size << 1); + * } + * + * set->data[index] |= mask; + * } + */ + +void bitset_clear(bitset_t *set, size_t bit) +{ + assert(set && "Received NULL set."); + + size_t index, mask; + + get_index_and_mask(bit, &index, &mask); + + set->data[index] &= ~mask; +} + +bool_t bitset_test(bitset_t *set, size_t bit) +{ + assert(set && "Received NULL set."); + + size_t index, mask; + + get_index_and_mask(bit, &index, &mask); + + return (mask & set->data[index]) != 0; +} + +signed long bitset_find_first_unset_bit(bitset_t *set) +{ + assert(set && "Received NULL set."); + + for (size_t i = 0; i < (set->size * 8); i++) { + if (!bitset_test(set, i)) { + return (signed long)i; + } + } + + return -1; +} diff --git a/mentos/src/libc/ctype.c b/mentos/src/libc/ctype.c index e1e6a50..519a542 100644 --- a/mentos/src/libc/ctype.c +++ b/mentos/src/libc/ctype.c @@ -1,63 +1,63 @@ -/// MentOS, The Mentoring Operating system project -/// @file ctype.c -/// @brief Functions related to character handling. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "ctype.h" - -/// Distance from a uppercase character to the correspondent lowercase in ASCII. -#define OFFSET 32 - -int isdigit(int c) -{ - return (c >= 48 && c <= 57); -} - -int isalpha(int c) -{ - return ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)); -} - -int isalnum(int c) -{ - return (isalpha(c) || isdigit(c)); -} - -int isxdigit(int c) -{ - return (isdigit(c) || (c >= 65 && c <= 70)); -} - -int islower(int c) -{ - return (c >= 97 && c <= 122); -} - -int isupper(int c) -{ - return (c >= 65 && c <= 90); -} - -int tolower(int c) -{ - if (isalpha(c) == 0 || islower(c)) { - return c; - } - - return c + OFFSET; -} - -int toupper(int c) -{ - if (isalpha(c) == 0 || isupper(c)) { - return c; - } - - return c - OFFSET; -} - -int isspace(int c) -{ - return (c == ' '); -} +/// MentOS, The Mentoring Operating system project +/// @file ctype.c +/// @brief Functions related to character handling. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "ctype.h" + +/// Distance from a uppercase character to the correspondent lowercase in ASCII. +#define OFFSET 32 + +int isdigit(int c) +{ + return (c >= 48 && c <= 57); +} + +int isalpha(int c) +{ + return ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)); +} + +int isalnum(int c) +{ + return (isalpha(c) || isdigit(c)); +} + +int isxdigit(int c) +{ + return (isdigit(c) || (c >= 65 && c <= 70)); +} + +int islower(int c) +{ + return (c >= 97 && c <= 122); +} + +int isupper(int c) +{ + return (c >= 65 && c <= 90); +} + +int tolower(int c) +{ + if (isalpha(c) == 0 || islower(c)) { + return c; + } + + return c + OFFSET; +} + +int toupper(int c) +{ + if (isalpha(c) == 0 || isupper(c)) { + return c; + } + + return c - OFFSET; +} + +int isspace(int c) +{ + return (c == ' '); +} diff --git a/mentos/src/libc/fcvt.c b/mentos/src/libc/fcvt.c index cb5eb67..11863b0 100644 --- a/mentos/src/libc/fcvt.c +++ b/mentos/src/libc/fcvt.c @@ -1,114 +1,114 @@ -/// MentOS, The Mentoring Operating system project -/// @file fcvt.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "fcvt.h" -#include - -/* - * cvt.c - IEEE floating point formatting routines for FreeBSD - * from GNU libc-4.6.27 - */ - -#define CVTBUFSIZE 500 - -static char *cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, - int eflag) -{ - int r2; - double fi, fj; - char *p, *p1; - - if (ndigits < 0) { - ndigits = 0; - } - - if (ndigits >= CVTBUFSIZE - 1) { - ndigits = CVTBUFSIZE - 2; - } - - r2 = 0; - *sign = 0; - p = &buf[0]; - - if (arg < 0) { - *sign = 1; - arg = -arg; - } - - arg = modf(arg, &fi); - p1 = &buf[CVTBUFSIZE]; - - if (fi != 0) { - p1 = &buf[CVTBUFSIZE]; - while (fi != 0) { - fj = modf(fi / 10, &fi); - *--p1 = (int)((fj + .03) * 10) + '0'; - r2++; - } - while (p1 < &buf[CVTBUFSIZE]) { - *p++ = *p1++; - } - } else if (arg > 0) { - while ((fj = arg * 10) < 1) { - arg = fj; - r2--; - } - } - - p1 = &buf[ndigits]; - if (eflag == 0) { - p1 += r2; - } - - *decpt = r2; - if (p1 < &buf[0]) { - buf[0] = '\0'; - - return buf; - } - - while (p <= p1 && p < &buf[CVTBUFSIZE]) { - arg *= 10; - arg = modf(arg, &fj); - *p++ = (int)fj + '0'; - } - - if (p1 >= &buf[CVTBUFSIZE]) { - buf[CVTBUFSIZE - 1] = '\0'; - - return buf; - } - - p = p1; - *p1 += 5; - while (*p1 > '9') { - *p1 = '0'; - if (p1 > buf) { - ++*--p1; - } else { - *p1 = '1'; - (*decpt)++; - if (eflag == 0) { - if (p > buf) - *p = '0'; - p++; - } - } - } - *p = '\0'; - - return buf; -} - -char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) -{ - return cvt(arg, ndigits, decpt, sign, buf, 1); -} - -char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) -{ - return cvt(arg, ndigits, decpt, sign, buf, 0); -} +/// MentOS, The Mentoring Operating system project +/// @file fcvt.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "fcvt.h" +#include + +/* + * cvt.c - IEEE floating point formatting routines for FreeBSD + * from GNU libc-4.6.27 + */ + +#define CVTBUFSIZE 500 + +static char *cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, + int eflag) +{ + int r2; + double fi, fj; + char *p, *p1; + + if (ndigits < 0) { + ndigits = 0; + } + + if (ndigits >= CVTBUFSIZE - 1) { + ndigits = CVTBUFSIZE - 2; + } + + r2 = 0; + *sign = 0; + p = &buf[0]; + + if (arg < 0) { + *sign = 1; + arg = -arg; + } + + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) { + *p++ = *p1++; + } + } else if (arg > 0) { + while ((fj = arg * 10) < 1) { + arg = fj; + r2--; + } + } + + p1 = &buf[ndigits]; + if (eflag == 0) { + p1 += r2; + } + + *decpt = r2; + if (p1 < &buf[0]) { + buf[0] = '\0'; + + return buf; + } + + while (p <= p1 && p < &buf[CVTBUFSIZE]) { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int)fj + '0'; + } + + if (p1 >= &buf[CVTBUFSIZE]) { + buf[CVTBUFSIZE - 1] = '\0'; + + return buf; + } + + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) { + ++*--p1; + } else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + + return buf; +} + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/mentos/src/libc/hashmap.c b/mentos/src/libc/hashmap.c index c553e63..50813f8 100644 --- a/mentos/src/libc/hashmap.c +++ b/mentos/src/libc/hashmap.c @@ -1,267 +1,267 @@ -/// MentOS, The Mentoring Operating system project -/// @file hashmap.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "hashmap.h" -#include "string.h" -#include "stdlib.h" - -struct hashmap_entry_t { - char *key; - void *value; - struct hashmap_entry_t *next; -}; - -struct hashmap_t { - hashmap_hash_t hash_func; - hashmap_comp_t hash_comp; - hashmap_dupe_t hash_key_dup; - hashmap_free_t hash_key_free; - hashmap_free_t hash_val_free; - size_t size; - hashmap_entry_t **entries; -}; - -size_t hashmap_string_hash(void *_key) -{ - size_t hash = 0; - char *key = (char *)_key; - int c; - // This is the so-called "sdbm" hash. It comes from a piece of public - // domain code from a clone of ndbm. - while ((c = *key++)) { - hash = c + (hash << 6) + (hash << 16) - hash; - } - return hash; -} - -bool_t hashmap_string_comp(void *a, void *b) -{ - return !strcmp(a, b); -} - -void *hashmap_string_dupe(void *key) -{ - return strdup(key); -} - -static size_t hashmap_int_hash(void *key) -{ - return (size_t)key; -} - -static bool_t hashmap_int_comp(void *a, void *b) -{ - return (int)a == (int)b; -} - -static void *hashmap_int_dupe(void *key) -{ - return key; -} - -static void hashmap_int_free(void *ptr) -{ - (void)ptr; -} - -hashmap_t *hashmap_create(size_t size) -{ - hashmap_t *map = malloc(sizeof(hashmap_t)); - - map->hash_func = &hashmap_string_hash; - map->hash_comp = &hashmap_string_comp; - map->hash_key_dup = &hashmap_string_dupe; - map->hash_key_free = &free; - map->hash_val_free = &free; - - map->size = size; - map->entries = malloc(sizeof(hashmap_entry_t *) * size); - memset(map->entries, 0, sizeof(hashmap_entry_t *) * size); - - return map; -} - -hashmap_t *hashmap_create_int(size_t size) -{ - hashmap_t *map = malloc(sizeof(hashmap_t)); - - map->hash_func = &hashmap_int_hash; - map->hash_comp = &hashmap_int_comp; - map->hash_key_dup = &hashmap_int_dupe; - map->hash_key_free = &hashmap_int_free; - map->hash_val_free = &free; - - map->size = size; - map->entries = malloc(sizeof(hashmap_entry_t *) * size); - memset(map->entries, 0, sizeof(hashmap_entry_t *) * size); - - return map; -} - -void hashmap_free(hashmap_t *map) -{ - for (size_t i = 0; i < map->size; ++i) { - hashmap_entry_t *x = map->entries[i], *p; - while (x) { - p = x; - x = x->next; - map->hash_key_free(p->key); - map->hash_val_free(p); - } - } - - free(map->entries); -} - -void *hashmap_set(hashmap_t *map, void *key, void *value) -{ - size_t hash = map->hash_func(key) % map->size; - hashmap_entry_t *x = map->entries[hash]; - - if (x == NULL) { - hashmap_entry_t *e = malloc(sizeof(hashmap_entry_t)); - e->key = map->hash_key_dup(key); - e->value = value; - e->next = NULL; - map->entries[hash] = e; - - return NULL; - } - - hashmap_entry_t *p = NULL; - - do { - if (map->hash_comp(x->key, key)) { - void *out = x->value; - x->value = value; - - return out; - } - p = x; - x = x->next; - } while (x); - - hashmap_entry_t *e = malloc(sizeof(hashmap_entry_t)); - e->key = map->hash_key_dup(key); - e->value = value; - e->next = NULL; - p->next = e; - - return NULL; -} - -void *hashmap_get(hashmap_t *map, void *key) -{ - size_t hash = map->hash_func(key) % map->size; - hashmap_entry_t *x = map->entries[hash]; - - if (x == NULL) { - return NULL; - } - do { - if (map->hash_comp(x->key, key)) { - return x->value; - } - x = x->next; - } while (x); - - return NULL; -} - -void *hashmap_remove(hashmap_t *map, void *key) -{ - size_t hash = map->hash_func(key) % map->size; - hashmap_entry_t *x = map->entries[hash]; - - if (x == NULL) { - return NULL; - } - if (map->hash_comp(x->key, key)) { - void *out = x->value; - map->entries[hash] = x->next; - map->hash_key_free(x->key); - map->hash_val_free(x); - - return out; - } - - hashmap_entry_t *p = x; - x = x->next; - do { - if (map->hash_comp(x->key, key)) { - void *out = x->value; - p->next = x->next; - map->hash_key_free(x->key); - map->hash_val_free(x); - - return out; - } - p = x; - x = x->next; - } while (x); - - return NULL; -} - -bool_t hashmap_is_empty(hashmap_t *map) -{ - for (size_t i = 0; i < map->size; ++i) { - if (map->entries[i]) { - return false; - } - } - - return true; -} - -bool_t hashmap_has(hashmap_t *map, void *key) -{ - size_t hash = map->hash_func(key) % map->size; - hashmap_entry_t *x = map->entries[hash]; - - if (x == NULL) { - return false; - } - do { - if (map->hash_comp(x->key, key)) { - return true; - } - x = x->next; - } while (x); - - return false; -} - -list_t *hashmap_keys(hashmap_t *map) -{ - list_t *l = list_create(); - - for (size_t i = 0; i < map->size; ++i) { - hashmap_entry_t *x = map->entries[i]; - while (x) { - list_insert_back(l, x->key); - x = x->next; - } - } - - return l; -} - -list_t *hashmap_values(hashmap_t *map) -{ - list_t *l = list_create(); - - for (size_t i = 0; i < map->size; ++i) { - hashmap_entry_t *x = map->entries[i]; - - while (x) { - list_insert_back(l, x->value); - x = x->next; - } - } - - return l; -} +/// MentOS, The Mentoring Operating system project +/// @file hashmap.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "hashmap.h" +#include "string.h" +#include "stdlib.h" + +struct hashmap_entry_t { + char *key; + void *value; + struct hashmap_entry_t *next; +}; + +struct hashmap_t { + hashmap_hash_t hash_func; + hashmap_comp_t hash_comp; + hashmap_dupe_t hash_key_dup; + hashmap_free_t hash_key_free; + hashmap_free_t hash_val_free; + size_t size; + hashmap_entry_t **entries; +}; + +size_t hashmap_string_hash(void *_key) +{ + size_t hash = 0; + char *key = (char *)_key; + int c; + // This is the so-called "sdbm" hash. It comes from a piece of public + // domain code from a clone of ndbm. + while ((c = *key++)) { + hash = c + (hash << 6) + (hash << 16) - hash; + } + return hash; +} + +bool_t hashmap_string_comp(void *a, void *b) +{ + return !strcmp(a, b); +} + +void *hashmap_string_dupe(void *key) +{ + return strdup(key); +} + +static size_t hashmap_int_hash(void *key) +{ + return (size_t)key; +} + +static bool_t hashmap_int_comp(void *a, void *b) +{ + return (int)a == (int)b; +} + +static void *hashmap_int_dupe(void *key) +{ + return key; +} + +static void hashmap_int_free(void *ptr) +{ + (void)ptr; +} + +hashmap_t *hashmap_create(size_t size) +{ + hashmap_t *map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_string_hash; + map->hash_comp = &hashmap_string_comp; + map->hash_key_dup = &hashmap_string_dupe; + map->hash_key_free = &free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0, sizeof(hashmap_entry_t *) * size); + + return map; +} + +hashmap_t *hashmap_create_int(size_t size) +{ + hashmap_t *map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_int_hash; + map->hash_comp = &hashmap_int_comp; + map->hash_key_dup = &hashmap_int_dupe; + map->hash_key_free = &hashmap_int_free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0, sizeof(hashmap_entry_t *) * size); + + return map; +} + +void hashmap_free(hashmap_t *map) +{ + for (size_t i = 0; i < map->size; ++i) { + hashmap_entry_t *x = map->entries[i], *p; + while (x) { + p = x; + x = x->next; + map->hash_key_free(p->key); + map->hash_val_free(p); + } + } + + free(map->entries); +} + +void *hashmap_set(hashmap_t *map, void *key, void *value) +{ + size_t hash = map->hash_func(key) % map->size; + hashmap_entry_t *x = map->entries[hash]; + + if (x == NULL) { + hashmap_entry_t *e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + map->entries[hash] = e; + + return NULL; + } + + hashmap_entry_t *p = NULL; + + do { + if (map->hash_comp(x->key, key)) { + void *out = x->value; + x->value = value; + + return out; + } + p = x; + x = x->next; + } while (x); + + hashmap_entry_t *e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + p->next = e; + + return NULL; +} + +void *hashmap_get(hashmap_t *map, void *key) +{ + size_t hash = map->hash_func(key) % map->size; + hashmap_entry_t *x = map->entries[hash]; + + if (x == NULL) { + return NULL; + } + do { + if (map->hash_comp(x->key, key)) { + return x->value; + } + x = x->next; + } while (x); + + return NULL; +} + +void *hashmap_remove(hashmap_t *map, void *key) +{ + size_t hash = map->hash_func(key) % map->size; + hashmap_entry_t *x = map->entries[hash]; + + if (x == NULL) { + return NULL; + } + if (map->hash_comp(x->key, key)) { + void *out = x->value; + map->entries[hash] = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + + return out; + } + + hashmap_entry_t *p = x; + x = x->next; + do { + if (map->hash_comp(x->key, key)) { + void *out = x->value; + p->next = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + + return out; + } + p = x; + x = x->next; + } while (x); + + return NULL; +} + +bool_t hashmap_is_empty(hashmap_t *map) +{ + for (size_t i = 0; i < map->size; ++i) { + if (map->entries[i]) { + return false; + } + } + + return true; +} + +bool_t hashmap_has(hashmap_t *map, void *key) +{ + size_t hash = map->hash_func(key) % map->size; + hashmap_entry_t *x = map->entries[hash]; + + if (x == NULL) { + return false; + } + do { + if (map->hash_comp(x->key, key)) { + return true; + } + x = x->next; + } while (x); + + return false; +} + +list_t *hashmap_keys(hashmap_t *map) +{ + list_t *l = list_create(); + + for (size_t i = 0; i < map->size; ++i) { + hashmap_entry_t *x = map->entries[i]; + while (x) { + list_insert_back(l, x->key); + x = x->next; + } + } + + return l; +} + +list_t *hashmap_values(hashmap_t *map) +{ + list_t *l = list_create(); + + for (size_t i = 0; i < map->size; ++i) { + hashmap_entry_t *x = map->entries[i]; + + while (x) { + list_insert_back(l, x->value); + x = x->next; + } + } + + return l; +} diff --git a/mentos/src/libc/libgen.c b/mentos/src/libc/libgen.c index 47f2bab..7fea1cf 100644 --- a/mentos/src/libc/libgen.c +++ b/mentos/src/libc/libgen.c @@ -1,74 +1,74 @@ -/// MentOS, The Mentoring Operating system project -/// @file libgen.c -/// @brief String routines. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "libgen.h" -#include "string.h" -#include "initrd.h" -#include "limits.h" - -int parse_path(char *out, char **cur, char sep, size_t max) -{ - if (**cur == '\0') { - return 0; - } - - *out++ = **cur; - ++*cur; - --max; - - while ((max > 0) && (**cur != '\0') && (**cur != sep)) { - *out++ = **cur; - ++*cur; - --max; - } - - *out = '\0'; - - return 1; -} - -char *dirname(const char *path) -{ - static char s[PATH_MAX]; - - static char dot[2] = "."; - - // Check the input path. - if (path == NULL) - return dot; - - // Copy the path to the support string. - strcpy(s, path); - - // Get the last occurrence of '/'. - char *last_slash = strrchr(s, '/'); - - if (last_slash == s) { - // If the slash is acutally the first character of the string, move the - // pointer to the last slash after it. - ++last_slash; - } else if ((last_slash != NULL) && (last_slash[1] == '\0')) { - // If the slash is the last character, we need to search before it. - last_slash = memchr(s, '/', last_slash - s); - } - - if (last_slash != NULL) { - // If we have found it, close the string. - last_slash[0] = '\0'; - } else { - // Otherwise, return '.'. - return dot; - } - - return s; -} - -char *basename(const char *path) -{ - char *p = strrchr(path, '/'); - - return p ? p + 1 : (char *)path; -} +/// MentOS, The Mentoring Operating system project +/// @file libgen.c +/// @brief String routines. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "libgen.h" +#include "string.h" +#include "initrd.h" +#include "limits.h" + +int parse_path(char *out, char **cur, char sep, size_t max) +{ + if (**cur == '\0') { + return 0; + } + + *out++ = **cur; + ++*cur; + --max; + + while ((max > 0) && (**cur != '\0') && (**cur != sep)) { + *out++ = **cur; + ++*cur; + --max; + } + + *out = '\0'; + + return 1; +} + +char *dirname(const char *path) +{ + static char s[PATH_MAX]; + + static char dot[2] = "."; + + // Check the input path. + if (path == NULL) + return dot; + + // Copy the path to the support string. + strcpy(s, path); + + // Get the last occurrence of '/'. + char *last_slash = strrchr(s, '/'); + + if (last_slash == s) { + // If the slash is acutally the first character of the string, move the + // pointer to the last slash after it. + ++last_slash; + } else if ((last_slash != NULL) && (last_slash[1] == '\0')) { + // If the slash is the last character, we need to search before it. + last_slash = memchr(s, '/', last_slash - s); + } + + if (last_slash != NULL) { + // If we have found it, close the string. + last_slash[0] = '\0'; + } else { + // Otherwise, return '.'. + return dot; + } + + return s; +} + +char *basename(const char *path) +{ + char *p = strrchr(path, '/'); + + return p ? p + 1 : (char *)path; +} diff --git a/mentos/src/libc/list.c b/mentos/src/libc/list.c index 7f50731..41db428 100644 --- a/mentos/src/libc/list.c +++ b/mentos/src/libc/list.c @@ -1,344 +1,344 @@ -/// MentOS, The Mentoring Operating system project -/// @file list.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "list.h" -#include "assert.h" -#include "stdlib.h" - -list_t *list_create() -{ - list_t *list = calloc(sizeof(list_t), 1); - - return list; -} - -size_t list_size(list_t *list) -{ - assert(list && "List is null."); - - return list->size; -} - -bool_t list_empty(list_t *list) -{ - assert(list && "List is null."); - - if (list->size == 0) { - return true; - } - - return false; -} - -listnode_t *list_insert_front(list_t *list, void *value) -{ - assert(list && "List is null."); - assert(value && "Value is null."); - - // Create a new node. - listnode_t *node = calloc(sizeof(listnode_t), 1); - - list->head->prev = node; - node->next = list->head; - node->value = value; - - // If it's the first element, then it's both head and tail - if (!list->head) { - list->tail = node; - } - - list->head = node; - list->size++; - - return node; -} - -listnode_t *list_insert_back(list_t *list, void *value) -{ - assert(list && "List is null."); - assert(value && "Value is null."); - - // Create a new node. - listnode_t *node = calloc(sizeof(listnode_t), 1); - node->prev = list->tail; - - if (list->tail) { - list->tail->next = node; - } - node->value = value; - - if (!list->head) { - list->head = node; - } - - list->tail = node; - list->size++; - - return node; -} - -void list_insert_node_back(list_t *list, listnode_t *node) -{ - assert(list && "List is null."); - assert(node && "Node is null."); - - node->prev = list->tail; - if (list->tail) { - list->tail->next = node; - } - - if (!list->head) { - list->head = node; - } - - list->tail = node; - list->size++; -} - -void *list_remove_node(list_t *list, listnode_t *node) -{ - assert(list && "List is null."); - assert(node && "Node is null."); - - if (list->head == node) { - return list_remove_front(list); - } else if (list->tail == node) { - return list_remove_back(list); - } - - void *value = node->value; - node->next->prev = node->prev; - node->prev->next = node->next; - list->size--; - free(node); - - return value; -} - -void *list_remove_front(list_t *list) -{ - assert(list && "List is null."); - - if (list->head == NULL) { - return NULL; - } - - listnode_t *node = list->head; - void *value = node->value; - list->head = node->next; - - if (list->head) { - list->head->prev = NULL; - } - free(node); - list->size--; - - return value; -} - -void *list_remove_back(list_t *list) -{ - assert(list && "List is null."); - - if (list->head == NULL) { - return NULL; - } - - listnode_t *node = list->tail; - void *value = node->value; - list->tail = node->prev; - - if (list->tail) { - list->tail->next = NULL; - } - free(node); - list->size--; - - return value; -} - -listnode_t *list_find(list_t *list, void *value) -{ - listnode_foreach(listnode, list) - { - if (listnode->value == value) { - return listnode; - } - } - - return NULL; -} - -void list_push(list_t *list, void *value) -{ - assert(list && "List is null."); - assert(value && "Value is null."); - - list_insert_back(list, value); -} - -listnode_t *list_pop_back(list_t *list) -{ - assert(list && "List is null."); - - if (!list->head) { - return NULL; - } - - listnode_t *node = list->tail; - list->tail = node->prev; - - if (list->tail) { - list->tail->next = NULL; - } - - list->size--; - - return node; -} - -listnode_t *list_pop_front(list_t *list) -{ - assert(list && "List is null."); - - if (!list->head) { - return NULL; - } - - listnode_t *node = list->head; - list->head = list->head->next; - list->size--; - - return node; -} - -void list_enqueue(list_t *list, void *value) -{ - assert(list && "List is null."); - assert(value && "Value is null."); - - list_insert_front(list, value); -} - -listnode_t *list_dequeue(list_t *list) -{ - assert(list && "List is null."); - - return list_pop_back(list); -} - -void *list_peek_front(list_t *list) -{ - assert(list && "List is null."); - - if (!list->head) { - return NULL; - } - - return list->head->value; -} - -void *list_peek_back(list_t *list) -{ - assert(list && "List is null."); - - if (!list->tail) { - return NULL; - } - - return list->tail->value; -} - -int list_contain(list_t *list, void *value) -{ - assert(list && "List is null."); - assert(value && "Value is null."); - - int idx = 0; - listnode_foreach(listnode, list) - { - if (listnode->value == value) { - return idx; - } - ++idx; - } - - return -1; -} - -listnode_t *list_get_node_by_index(list_t *list, size_t index) -{ - assert(list && "List is null."); - - if (index >= list_size(list)) { - return NULL; - } - - size_t curr = 0; - listnode_foreach(listnode, list) - { - if (index == curr) { - return listnode; - } - curr++; - } - return NULL; -} - -void *list_remove_by_index(list_t *list, size_t index) -{ - assert(list && "List is null."); - - listnode_t *node = list_get_node_by_index(list, index); - if (node != NULL) { - return list_remove_node(list, node); - } - - return NULL; -} - -void list_destroy(list_t *list) -{ - assert(list && "List is null."); - - // Free each node's value and the node itself. - listnode_t *node = list->head; - while (node != NULL) { - listnode_t *save = node; - node = node->next; - free(save); - } - - // Free the list. - free(list); -} - -void listnode_destroy(listnode_t *node) -{ - assert(node && "Node is null."); - - free(node); -} - -void list_merge(list_t *target, list_t *source) -{ - assert(target && "Target list is null."); - assert(source && "Source list is null."); - - // Destructively merges source into target. - if (target->tail) { - target->tail->next = source->head; - } else { - target->head = source->head; - } - - if (source->tail) { - target->tail = source->tail; - } - - target->size += source->size; - free(source); -} +/// MentOS, The Mentoring Operating system project +/// @file list.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "list.h" +#include "assert.h" +#include "stdlib.h" + +list_t *list_create() +{ + list_t *list = calloc(sizeof(list_t), 1); + + return list; +} + +size_t list_size(list_t *list) +{ + assert(list && "List is null."); + + return list->size; +} + +bool_t list_empty(list_t *list) +{ + assert(list && "List is null."); + + if (list->size == 0) { + return true; + } + + return false; +} + +listnode_t *list_insert_front(list_t *list, void *value) +{ + assert(list && "List is null."); + assert(value && "Value is null."); + + // Create a new node. + listnode_t *node = calloc(sizeof(listnode_t), 1); + + list->head->prev = node; + node->next = list->head; + node->value = value; + + // If it's the first element, then it's both head and tail + if (!list->head) { + list->tail = node; + } + + list->head = node; + list->size++; + + return node; +} + +listnode_t *list_insert_back(list_t *list, void *value) +{ + assert(list && "List is null."); + assert(value && "Value is null."); + + // Create a new node. + listnode_t *node = calloc(sizeof(listnode_t), 1); + node->prev = list->tail; + + if (list->tail) { + list->tail->next = node; + } + node->value = value; + + if (!list->head) { + list->head = node; + } + + list->tail = node; + list->size++; + + return node; +} + +void list_insert_node_back(list_t *list, listnode_t *node) +{ + assert(list && "List is null."); + assert(node && "Node is null."); + + node->prev = list->tail; + if (list->tail) { + list->tail->next = node; + } + + if (!list->head) { + list->head = node; + } + + list->tail = node; + list->size++; +} + +void *list_remove_node(list_t *list, listnode_t *node) +{ + assert(list && "List is null."); + assert(node && "Node is null."); + + if (list->head == node) { + return list_remove_front(list); + } else if (list->tail == node) { + return list_remove_back(list); + } + + void *value = node->value; + node->next->prev = node->prev; + node->prev->next = node->next; + list->size--; + free(node); + + return value; +} + +void *list_remove_front(list_t *list) +{ + assert(list && "List is null."); + + if (list->head == NULL) { + return NULL; + } + + listnode_t *node = list->head; + void *value = node->value; + list->head = node->next; + + if (list->head) { + list->head->prev = NULL; + } + free(node); + list->size--; + + return value; +} + +void *list_remove_back(list_t *list) +{ + assert(list && "List is null."); + + if (list->head == NULL) { + return NULL; + } + + listnode_t *node = list->tail; + void *value = node->value; + list->tail = node->prev; + + if (list->tail) { + list->tail->next = NULL; + } + free(node); + list->size--; + + return value; +} + +listnode_t *list_find(list_t *list, void *value) +{ + listnode_foreach(listnode, list) + { + if (listnode->value == value) { + return listnode; + } + } + + return NULL; +} + +void list_push(list_t *list, void *value) +{ + assert(list && "List is null."); + assert(value && "Value is null."); + + list_insert_back(list, value); +} + +listnode_t *list_pop_back(list_t *list) +{ + assert(list && "List is null."); + + if (!list->head) { + return NULL; + } + + listnode_t *node = list->tail; + list->tail = node->prev; + + if (list->tail) { + list->tail->next = NULL; + } + + list->size--; + + return node; +} + +listnode_t *list_pop_front(list_t *list) +{ + assert(list && "List is null."); + + if (!list->head) { + return NULL; + } + + listnode_t *node = list->head; + list->head = list->head->next; + list->size--; + + return node; +} + +void list_enqueue(list_t *list, void *value) +{ + assert(list && "List is null."); + assert(value && "Value is null."); + + list_insert_front(list, value); +} + +listnode_t *list_dequeue(list_t *list) +{ + assert(list && "List is null."); + + return list_pop_back(list); +} + +void *list_peek_front(list_t *list) +{ + assert(list && "List is null."); + + if (!list->head) { + return NULL; + } + + return list->head->value; +} + +void *list_peek_back(list_t *list) +{ + assert(list && "List is null."); + + if (!list->tail) { + return NULL; + } + + return list->tail->value; +} + +int list_contain(list_t *list, void *value) +{ + assert(list && "List is null."); + assert(value && "Value is null."); + + int idx = 0; + listnode_foreach(listnode, list) + { + if (listnode->value == value) { + return idx; + } + ++idx; + } + + return -1; +} + +listnode_t *list_get_node_by_index(list_t *list, size_t index) +{ + assert(list && "List is null."); + + if (index >= list_size(list)) { + return NULL; + } + + size_t curr = 0; + listnode_foreach(listnode, list) + { + if (index == curr) { + return listnode; + } + curr++; + } + return NULL; +} + +void *list_remove_by_index(list_t *list, size_t index) +{ + assert(list && "List is null."); + + listnode_t *node = list_get_node_by_index(list, index); + if (node != NULL) { + return list_remove_node(list, node); + } + + return NULL; +} + +void list_destroy(list_t *list) +{ + assert(list && "List is null."); + + // Free each node's value and the node itself. + listnode_t *node = list->head; + while (node != NULL) { + listnode_t *save = node; + node = node->next; + free(save); + } + + // Free the list. + free(list); +} + +void listnode_destroy(listnode_t *node) +{ + assert(node && "Node is null."); + + free(node); +} + +void list_merge(list_t *target, list_t *source) +{ + assert(target && "Target list is null."); + assert(source && "Source list is null."); + + // Destructively merges source into target. + if (target->tail) { + target->tail->next = source->head; + } else { + target->head = source->head; + } + + if (source->tail) { + target->tail = source->tail; + } + + target->size += source->size; + free(source); +} diff --git a/mentos/src/libc/math.c b/mentos/src/libc/math.c index 19ca124..9dcfb71 100644 --- a/mentos/src/libc/math.c +++ b/mentos/src/libc/math.c @@ -1,150 +1,150 @@ -/// MentOS, The Mentoring Operating system project -/// @file math.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "math.h" -#include - -double round(double x) -{ - double out; - __asm__ __volatile__("fldln2; fldl %1; frndint" : "=t"(out) : "m"(x)); - return out; -} - -double floor(double x) -{ - if (x > -1.0 && x < 1.0) { - if (x >= 0) - return 0.0; - return -1.0; - } - int i = (int)x; - if (x < 0) - return (double)(i - 1); - return (double)i; -} - -double pow(double x, double y) -{ - double out; - __asm__ __volatile__("fyl2x;" - "fld %%st;" - "frndint;" - "fsub %%st,%%st(1);" - "fxch;" - "fchs;" - "f2xm1;" - "fld1;" - "faddp;" - "fxch;" - "fld1;" - "fscale;" - "fstp %%st(1);" - "fmulp;" - : "=t"(out) - : "0"(x), "u"(y) - : "st(1)"); - return out; -} - -long find_nearest_pow_greater(double base, double value) -{ - if (base <= 1) - return -1; - long pow_value = 0; - while (pow(base, pow_value) < value) - pow_value++; - return pow_value; -} - -double exp(double x) -{ - return pow(M_E, x); -} - -double fabs(double x) -{ - double out; - __asm__ __volatile__("fldln2; fldl %1; fabs" : "=t"(out) : "m"(x)); - return out; -} - -double sqrt(double x) -{ - double out; - __asm__ __volatile__("fldln2; fldl %1; fsqrt" : "=t"(out) : "m"(x)); - return out; -} - -int isinf(double x) -{ - union { - unsigned long long u; - double f; - } ieee754; - ieee754.f = x; - return ((unsigned)(ieee754.u >> 32U) & 0x7fffffffU) == 0x7ff00000U && - ((unsigned)ieee754.u == 0); -} - -int isnan(double x) -{ - union { - unsigned long long u; - double f; - } ieee754; - ieee754.f = x; - return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) + - ((unsigned)ieee754.u != 0) > - 0x7ff00000; -} - -double log10(double x) -{ - return ln(x) / ln(10); -} - -double ln(double x) -{ - double out; - __asm__ __volatile__("fldln2; fldl %1; fyl2x" : "=t"(out) : "m"(x)); - return out; -} - -double logx(double x, double y) -{ - // Base may not equal 1 or be negative. - if (y == 1.f || y < 0.f || ln(y) == 0.f) - return 0.f; - return ln(x) / ln(y); -} - -#define MAXPOWTWO 4.503599627370496000E+15 - -double modf(double x, double *intpart) -{ - register double absvalue; - if ((absvalue = (x >= 0.0) ? x : -x) >= MAXPOWTWO) { - // It must be an integer. - (*intpart) = x; - } else { - // Shift fraction off right. - (*intpart) = absvalue + MAXPOWTWO; - // Shift back without fraction. - (*intpart) -= MAXPOWTWO; - - // Above arithmetic might round. - while ((*intpart) > absvalue) { - // Test again just to be sure. - (*intpart) -= 1.0; - } - if (x < 0.0) { - (*intpart) = -(*intpart); - } - } - // Signed fractional part. - return (x - (*intpart)); -} +/// MentOS, The Mentoring Operating system project +/// @file math.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "math.h" +#include + +double round(double x) +{ + double out; + __asm__ __volatile__("fldln2; fldl %1; frndint" : "=t"(out) : "m"(x)); + return out; +} + +double floor(double x) +{ + if (x > -1.0 && x < 1.0) { + if (x >= 0) + return 0.0; + return -1.0; + } + int i = (int)x; + if (x < 0) + return (double)(i - 1); + return (double)i; +} + +double pow(double x, double y) +{ + double out; + __asm__ __volatile__("fyl2x;" + "fld %%st;" + "frndint;" + "fsub %%st,%%st(1);" + "fxch;" + "fchs;" + "f2xm1;" + "fld1;" + "faddp;" + "fxch;" + "fld1;" + "fscale;" + "fstp %%st(1);" + "fmulp;" + : "=t"(out) + : "0"(x), "u"(y) + : "st(1)"); + return out; +} + +long find_nearest_pow_greater(double base, double value) +{ + if (base <= 1) + return -1; + long pow_value = 0; + while (pow(base, pow_value) < value) + pow_value++; + return pow_value; +} + +double exp(double x) +{ + return pow(M_E, x); +} + +double fabs(double x) +{ + double out; + __asm__ __volatile__("fldln2; fldl %1; fabs" : "=t"(out) : "m"(x)); + return out; +} + +double sqrt(double x) +{ + double out; + __asm__ __volatile__("fldln2; fldl %1; fsqrt" : "=t"(out) : "m"(x)); + return out; +} + +int isinf(double x) +{ + union { + unsigned long long u; + double f; + } ieee754; + ieee754.f = x; + return ((unsigned)(ieee754.u >> 32U) & 0x7fffffffU) == 0x7ff00000U && + ((unsigned)ieee754.u == 0); +} + +int isnan(double x) +{ + union { + unsigned long long u; + double f; + } ieee754; + ieee754.f = x; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) + + ((unsigned)ieee754.u != 0) > + 0x7ff00000; +} + +double log10(double x) +{ + return ln(x) / ln(10); +} + +double ln(double x) +{ + double out; + __asm__ __volatile__("fldln2; fldl %1; fyl2x" : "=t"(out) : "m"(x)); + return out; +} + +double logx(double x, double y) +{ + // Base may not equal 1 or be negative. + if (y == 1.f || y < 0.f || ln(y) == 0.f) + return 0.f; + return ln(x) / ln(y); +} + +#define MAXPOWTWO 4.503599627370496000E+15 + +double modf(double x, double *intpart) +{ + register double absvalue; + if ((absvalue = (x >= 0.0) ? x : -x) >= MAXPOWTWO) { + // It must be an integer. + (*intpart) = x; + } else { + // Shift fraction off right. + (*intpart) = absvalue + MAXPOWTWO; + // Shift back without fraction. + (*intpart) -= MAXPOWTWO; + + // Above arithmetic might round. + while ((*intpart) > absvalue) { + // Test again just to be sure. + (*intpart) -= 1.0; + } + if (x < 0.0) { + (*intpart) = -(*intpart); + } + } + // Signed fractional part. + return (x - (*intpart)); +} diff --git a/mentos/src/libc/mutex.c b/mentos/src/libc/mutex.c index 59a5cc6..8d3779c 100644 --- a/mentos/src/libc/mutex.c +++ b/mentos/src/libc/mutex.c @@ -1,38 +1,38 @@ -/// MentOS, The Mentoring Operating system project -/// @file mutex.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "mutex.h" -#include "debug.h" - -void mutex_lock(mutex_t *mutex, uint32_t owner) -{ - dbg_print("[%d] Trying to lock mutex...\n", owner); - int failure = 1; - - while (mutex->state == 0 || failure || mutex->owner != owner) { - failure = 1; - if (mutex->state == 0) { - asm("movl $0x01,%%eax\n\t" // move 1 to eax - "xchg %%eax,%0\n\t" // try to set the lock bit - "mov %%eax,%1\n\t" // export our result to a test var - : "=m"(mutex->state), "=r"(failure) - : "m"(mutex->state) - : "%eax"); - } - - if (failure == 0) { - dbg_print("[%d] Acquired mutex...\n", owner); - mutex->owner = - owner; //test to see if we got the lock bit - } - } -} - -void mutex_unlock(mutex_t *mutex) -{ - dbg_print("[%d] Unlock mutex...\n", mutex->owner); - mutex->state = 0; -} +/// MentOS, The Mentoring Operating system project +/// @file mutex.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "mutex.h" +#include "debug.h" + +void mutex_lock(mutex_t *mutex, uint32_t owner) +{ + dbg_print("[%d] Trying to lock mutex...\n", owner); + int failure = 1; + + while (mutex->state == 0 || failure || mutex->owner != owner) { + failure = 1; + if (mutex->state == 0) { + asm("movl $0x01,%%eax\n\t" // move 1 to eax + "xchg %%eax,%0\n\t" // try to set the lock bit + "mov %%eax,%1\n\t" // export our result to a test var + : "=m"(mutex->state), "=r"(failure) + : "m"(mutex->state) + : "%eax"); + } + + if (failure == 0) { + dbg_print("[%d] Acquired mutex...\n", owner); + mutex->owner = + owner; //test to see if we got the lock bit + } + } +} + +void mutex_unlock(mutex_t *mutex) +{ + dbg_print("[%d] Unlock mutex...\n", mutex->owner); + mutex->state = 0; +} diff --git a/mentos/src/libc/ordered_array.c b/mentos/src/libc/ordered_array.c index c9c3af9..585aed6 100644 --- a/mentos/src/libc/ordered_array.c +++ b/mentos/src/libc/ordered_array.c @@ -1,90 +1,90 @@ -/// MentOS, The Mentoring Operating system project -/// @file ordered_array.c -/// @brief Interface for creating, inserting and deleting from ordered arrays. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "ordered_array.h" -#include "string.h" -#include "assert.h" -#include "stdlib.h" - -int8_t standard_lessthan_predicate(array_type_t a, array_type_t b) -{ - return (a < b); -} - -ordered_array_t create_ordered_array(uint32_t max_size, - lessthan_predicate_t less_than) -{ - ordered_array_t to_ret; - to_ret.array = malloc(max_size * sizeof(array_type_t)); - memset(to_ret.array, 0, max_size * sizeof(array_type_t)); - to_ret.size = 0; - to_ret.max_size = max_size; - to_ret.less_than = less_than; - - return to_ret; -} - -ordered_array_t place_ordered_array(void *addr, uint32_t max_size, - lessthan_predicate_t less_than) -{ - ordered_array_t to_ret; - to_ret.array = (array_type_t *)addr; - memset(to_ret.array, 0, max_size * sizeof(array_type_t)); - to_ret.size = 0; - to_ret.max_size = max_size; - to_ret.less_than = less_than; - - return to_ret; -} - -void destroy_ordered_array(ordered_array_t *array) -{ - free(array->array); -} - -void insert_ordered_array(array_type_t item, ordered_array_t *array) -{ - assert(array->less_than); - - uint32_t iterator = 0; - while (iterator < array->size && - array->less_than(array->array[iterator], item)) { - iterator++; - } - - // Just add at the end of the array. - if (iterator == array->size) { - array->array[array->size++] = item; - } else { - array_type_t tmp = array->array[iterator]; - array->array[iterator] = item; - - while (iterator < array->size) { - iterator++; - array_type_t tmp2 = array->array[iterator]; - array->array[iterator] = tmp; - tmp = tmp2; - } - array->size++; - } -} - -array_type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) -{ - assert(i < array->size); - - return array->array[i]; -} - -void remove_ordered_array(uint32_t i, ordered_array_t *array) -{ - while (i < array->size) { - array->array[i] = array->array[i + 1]; - i++; - } - - array->size--; -} +/// MentOS, The Mentoring Operating system project +/// @file ordered_array.c +/// @brief Interface for creating, inserting and deleting from ordered arrays. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "ordered_array.h" +#include "string.h" +#include "assert.h" +#include "stdlib.h" + +int8_t standard_lessthan_predicate(array_type_t a, array_type_t b) +{ + return (a < b); +} + +ordered_array_t create_ordered_array(uint32_t max_size, + lessthan_predicate_t less_than) +{ + ordered_array_t to_ret; + to_ret.array = malloc(max_size * sizeof(array_type_t)); + memset(to_ret.array, 0, max_size * sizeof(array_type_t)); + to_ret.size = 0; + to_ret.max_size = max_size; + to_ret.less_than = less_than; + + return to_ret; +} + +ordered_array_t place_ordered_array(void *addr, uint32_t max_size, + lessthan_predicate_t less_than) +{ + ordered_array_t to_ret; + to_ret.array = (array_type_t *)addr; + memset(to_ret.array, 0, max_size * sizeof(array_type_t)); + to_ret.size = 0; + to_ret.max_size = max_size; + to_ret.less_than = less_than; + + return to_ret; +} + +void destroy_ordered_array(ordered_array_t *array) +{ + free(array->array); +} + +void insert_ordered_array(array_type_t item, ordered_array_t *array) +{ + assert(array->less_than); + + uint32_t iterator = 0; + while (iterator < array->size && + array->less_than(array->array[iterator], item)) { + iterator++; + } + + // Just add at the end of the array. + if (iterator == array->size) { + array->array[array->size++] = item; + } else { + array_type_t tmp = array->array[iterator]; + array->array[iterator] = item; + + while (iterator < array->size) { + iterator++; + array_type_t tmp2 = array->array[iterator]; + array->array[iterator] = tmp; + tmp = tmp2; + } + array->size++; + } +} + +array_type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) +{ + assert(i < array->size); + + return array->array[i]; +} + +void remove_ordered_array(uint32_t i, ordered_array_t *array) +{ + while (i < array->size) { + array->array[i] = array->array[i + 1]; + i++; + } + + array->size--; +} diff --git a/mentos/src/libc/queue.c b/mentos/src/libc/queue.c index c4e08dc..8b2a7e8 100644 --- a/mentos/src/libc/queue.c +++ b/mentos/src/libc/queue.c @@ -1,162 +1,162 @@ -/// MentOS, The Mentoring Operating system project -/// @file queue.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "queue.h" -#include "stdio.h" -#include "stdlib.h" -#include "string.h" - -queue_t queue_create(size_t data_size) -{ - queue_t queue = malloc(sizeof(struct queue_t)); - if (queue == NULL) { - printf("Cannot create the queue.\n"); - return NULL; - } - queue->data_size = data_size; - queue->front = NULL; - queue->back = NULL; - - return queue; -} - -bool_t queue_destroy(queue_t queue) -{ - if (queue == NULL) { - printf("Queue is NULL.\n"); - return false; - } - queue_clear(queue); - free(queue); - - return true; -} - -bool_t queue_is_empty(queue_t queue) -{ - if (queue == NULL) { - printf("Queue is NULL.\n"); - - return false; - } - - return (bool_t)(queue->front == NULL); -} - -bool_t queue_enqueue(queue_t queue, void *data) -{ - if (queue == NULL) { - printf("Queue is NULL.\n"); - - return false; - } - if (data == NULL) { - printf("Data is NULL.\n"); - - return false; - } - queue_node_t *node = malloc(sizeof(struct queue_node_t)); - - if (node == NULL) { - printf("New node of the queue is NULL.\n"); - - return false; - } - // Initialize the new node. - node->data = data; - // Since the new node is the tail, nobody is behind it. - node->next = NULL; - // If the queue is empty, the data is placed also on the front. - if (queue->front == NULL) { - queue->front = node; - } else { - queue->back->next = node; - } - queue->back = node; - - return true; -} - -bool_t queue_dequeue(queue_t queue) -{ - struct queue_node_t *front_node = queue->front; - if (front_node == NULL) { - printf("Queue is Empty\n"); - - return false; - } - if (queue->front == queue->back) { - queue->front = queue->back = NULL; - } else { - queue->front = queue->front->next; - } - free(front_node); - - return true; -} - -bool_t queue_front(queue_t queue, void *data) -{ - if (queue == NULL) { - printf("Queue is NULL.\n"); - - return false; - } - if (queue->front == NULL) { - printf("Queue is empty\n"); - - return false; - } - memcpy(data, queue->front->data, queue->data_size); - - return true; -} - -bool_t queue_back(queue_t queue, void *data) -{ - if (queue == NULL) { - printf("Queue is NULL.\n"); - - return false; - } - if (queue->back == NULL) { - printf("Queue is empty\n"); - - return false; - } - memcpy(data, queue->back->data, queue->data_size); - - return true; -} - -bool_t queue_front_and_dequeue(queue_t queue, void *data) -{ - if (!queue_front(queue, data)) { - return false; - } - if (!queue_dequeue(queue)) { - return false; - } - - return true; -} - -bool_t queue_clear(queue_t queue) -{ - if (queue == NULL) { - printf("Queue is NULL.\n"); - - return false; - } - if (queue->front == NULL) { - return true; - } - while (queue->front) { - queue_dequeue(queue); - } - - return true; -} +/// MentOS, The Mentoring Operating system project +/// @file queue.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "queue.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" + +queue_t queue_create(size_t data_size) +{ + queue_t queue = malloc(sizeof(struct queue_t)); + if (queue == NULL) { + printf("Cannot create the queue.\n"); + return NULL; + } + queue->data_size = data_size; + queue->front = NULL; + queue->back = NULL; + + return queue; +} + +bool_t queue_destroy(queue_t queue) +{ + if (queue == NULL) { + printf("Queue is NULL.\n"); + return false; + } + queue_clear(queue); + free(queue); + + return true; +} + +bool_t queue_is_empty(queue_t queue) +{ + if (queue == NULL) { + printf("Queue is NULL.\n"); + + return false; + } + + return (bool_t)(queue->front == NULL); +} + +bool_t queue_enqueue(queue_t queue, void *data) +{ + if (queue == NULL) { + printf("Queue is NULL.\n"); + + return false; + } + if (data == NULL) { + printf("Data is NULL.\n"); + + return false; + } + queue_node_t *node = malloc(sizeof(struct queue_node_t)); + + if (node == NULL) { + printf("New node of the queue is NULL.\n"); + + return false; + } + // Initialize the new node. + node->data = data; + // Since the new node is the tail, nobody is behind it. + node->next = NULL; + // If the queue is empty, the data is placed also on the front. + if (queue->front == NULL) { + queue->front = node; + } else { + queue->back->next = node; + } + queue->back = node; + + return true; +} + +bool_t queue_dequeue(queue_t queue) +{ + struct queue_node_t *front_node = queue->front; + if (front_node == NULL) { + printf("Queue is Empty\n"); + + return false; + } + if (queue->front == queue->back) { + queue->front = queue->back = NULL; + } else { + queue->front = queue->front->next; + } + free(front_node); + + return true; +} + +bool_t queue_front(queue_t queue, void *data) +{ + if (queue == NULL) { + printf("Queue is NULL.\n"); + + return false; + } + if (queue->front == NULL) { + printf("Queue is empty\n"); + + return false; + } + memcpy(data, queue->front->data, queue->data_size); + + return true; +} + +bool_t queue_back(queue_t queue, void *data) +{ + if (queue == NULL) { + printf("Queue is NULL.\n"); + + return false; + } + if (queue->back == NULL) { + printf("Queue is empty\n"); + + return false; + } + memcpy(data, queue->back->data, queue->data_size); + + return true; +} + +bool_t queue_front_and_dequeue(queue_t queue, void *data) +{ + if (!queue_front(queue, data)) { + return false; + } + if (!queue_dequeue(queue)) { + return false; + } + + return true; +} + +bool_t queue_clear(queue_t queue) +{ + if (queue == NULL) { + printf("Queue is NULL.\n"); + + return false; + } + if (queue->front == NULL) { + return true; + } + while (queue->front) { + queue_dequeue(queue); + } + + return true; +} diff --git a/mentos/src/libc/rbtree.c b/mentos/src/libc/rbtree.c index 99fda45..e19d03c 100644 --- a/mentos/src/libc/rbtree.c +++ b/mentos/src/libc/rbtree.c @@ -1,613 +1,613 @@ -/// MentOS, The Mentoring Operating system project -/// @file rbtree.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "rbtree.h" -#include "assert.h" -#include "stdlib.h" - -struct rbtree_node_t { - /// Color red (1), black (0) - int red; - /// Link left [0] and right [1] - rbtree_node_t *link[2]; - /// User provided, used indirectly via rbtree_tree_node_cmp_f. - void *value; -}; - -struct rbtree_t { - rbtree_node_t *root; - rbtree_tree_node_cmp_f cmp; - size_t size; -}; - -struct rbtree_iter_t { - /// Pointer to the tree itself. - rbtree_t *tree; - /// Current node - rbtree_node_t *node; - /// Traversal path - rbtree_node_t *path[RBTREE_ITER_MAX_HEIGHT]; - /// Top of stack - size_t top; -}; - -rbtree_node_t *rbtree_node_alloc() -{ - return malloc(sizeof(rbtree_node_t)); -} - -rbtree_node_t *rbtree_node_init(rbtree_node_t *self, void *value) -{ - if (self) { - self->red = 1; - self->link[0] = self->link[1] = NULL; - self->value = value; - } - - return self; -} - -rbtree_node_t *rbtree_node_create(void *value) -{ - return rbtree_node_init(rbtree_node_alloc(), value); -} - -void *rbtree_node_get_value(rbtree_node_t *self) -{ - if (self) { - return self->value; - } - - return NULL; -} - -void rbtree_node_dealloc(rbtree_node_t *self) -{ - if (self) { - free(self); - } -} - -static int rbtree_node_is_red(const rbtree_node_t *self) -{ - return self ? self->red : 0; -} - -static rbtree_node_t *rbtree_node_rotate(rbtree_node_t *self, int dir) -{ - rbtree_node_t *result = NULL; - if (self) { - result = self->link[!dir]; - self->link[!dir] = result->link[dir]; - result->link[dir] = self; - self->red = 1; - result->red = 0; - } - - return result; -} - -static rbtree_node_t *rbtree_node_rotate2(rbtree_node_t *self, int dir) -{ - rbtree_node_t *result = NULL; - if (self) { - self->link[!dir] = rbtree_node_rotate(self->link[!dir], !dir); - result = rbtree_node_rotate(self, dir); - } - - return result; -} - -// rbtree_t - default callbacks. - -static int rbtree_tree_node_cmp_ptr_cb(rbtree_t *self, rbtree_node_t *a, - rbtree_node_t *b) -{ - (void)self; - - return (a->value > b->value) - (a->value < b->value); -} - -static void rbtree_tree_node_dealloc_cb(rbtree_t *self, rbtree_node_t *node) -{ - if (self) { - if (node) { - rbtree_node_dealloc(node); - } - } -} - -// rbtree_t - -rbtree_t *rbtree_tree_alloc() -{ - return malloc(sizeof(rbtree_t)); -} - -rbtree_t *rbtree_tree_init(rbtree_t *self, rbtree_tree_node_cmp_f node_cmp_cb) -{ - if (self) { - self->root = NULL; - self->size = 0; - self->cmp = - node_cmp_cb ? node_cmp_cb : rbtree_tree_node_cmp_ptr_cb; - } - - return self; -} - -rbtree_t *rbtree_tree_create(rbtree_tree_node_cmp_f node_cb) -{ - return rbtree_tree_init(rbtree_tree_alloc(), node_cb); -} - -void rbtree_tree_dealloc(rbtree_t *self, rbtree_tree_node_f node_cb) -{ - assert(self); - if (node_cb) { - rbtree_node_t *node = self->root; - rbtree_node_t *save = NULL; - - /* Rotate away the left links so that - * we can treat this like the destruction - * of a linked list. - */ - while (node) { - if (node->link[0] == NULL) { - // No left links, just kill the node and move on. - save = node->link[1]; - node_cb(self, node); - free(node); - node = NULL; - } else { - // Rotate away the left link and check again. - save = node->link[0]; - node->link[0] = save->link[1]; - save->link[1] = node; - } - node = save; - } - } - - free(self); -} - -void *rbtree_tree_find(rbtree_t *self, void *value) -{ - void *result = NULL; - if (self) { - rbtree_node_t node = { .value = value }; - rbtree_node_t *it = self->root; - int cmp = 0; - while (it) { - if ((cmp = self->cmp(self, it, &node))) { - /* If the tree supports duplicates, they should be - * chained to the right subtree for this to work. - */ - it = it->link[cmp < 0]; - } else { - break; - } - } - result = it ? it->value : NULL; - } - - return result; -} - -void *rbtree_tree_find_by_value(rbtree_t *self, rbtree_tree_cmp_f cmp_fun, - void *value) -{ - void *result = NULL; - if (self) { - rbtree_node_t *it = self->root; - int cmp = 0; - while (it) { - if ((cmp = cmp_fun(self, it, value))) { - /* If the tree supports duplicates, they should be - * chained to the right subtree for this to work. - */ - it = it->link[cmp < 0]; - } else { - break; - } - } - result = it ? it->value : NULL; - } - - return result; -} - -// Creates (malloc'ates). -int rbtree_tree_insert(rbtree_t *self, void *value) -{ - return rbtree_tree_insert_node(self, rbtree_node_create(value)); -} - -// Returns 1 on success, 0 otherwise. -int rbtree_tree_insert_node(rbtree_t *self, rbtree_node_t *node) -{ - if (self && node) { - if (self->root == NULL) { - self->root = node; - } else { - // False tree root. - rbtree_node_t head = { 0 }; - // Grandparent & parent. - rbtree_node_t *g, *t; - // Iterator & parent. - rbtree_node_t *p, *q; - int dir = 0, last = 0; - - // Set up our helpers. - t = &head; - g = p = NULL; - q = t->link[1] = self->root; - - // Search down the tree for a place to insert. - while (1) { - if (q == NULL) { - // Insert node at the first null link. - p->link[dir] = q = node; - } else if (rbtree_node_is_red(q->link[0]) && - rbtree_node_is_red(q->link[1])) { - // Simple red violation: color flip. - q->red = 1; - q->link[0]->red = 0; - q->link[1]->red = 0; - } - - if (rbtree_node_is_red(q) && - rbtree_node_is_red(p)) { - // Hard red violation: rotations necessary. - int dir2 = t->link[1] == g; - - if (q == p->link[last]) { - t->link[dir2] = - rbtree_node_rotate( - g, !last); - } else { - t->link[dir2] = - rbtree_node_rotate2( - g, !last); - } - } - /* Stop working if we inserted a node. This - * check also disallows duplicates in the tree. - */ - if (self->cmp(self, q, node) == 0) { - break; - } - last = dir; - dir = self->cmp(self, q, node) < 0; - - // Move the helpers down. - if (g != NULL) { - t = g; - } - g = p, p = q; - q = q->link[dir]; - } - // Update the root (it may be different). - self->root = head.link[1]; - } - // Make the root black for simplified logic. - self->root->red = 0; - ++self->size; - } - - return 1; -} - -/* Returns 1 if the value was removed, 0 otherwise. Optional node callback - * can be provided to dealloc node and/or user data. Use - * rbtree_tree_node_dealloc - * default callback to deallocate node created by rbtree_tree_insert(...). - */ -int rbtree_tree_remove_with_cb(rbtree_t *self, void *value, - rbtree_tree_node_f node_cb) -{ - if (self->root != NULL) { - // False tree root. - rbtree_node_t head = { 0 }; - // Value wrapper node. - rbtree_node_t node = { .value = value }; - // Helpers. - rbtree_node_t *q, *p, *g; - // Found item. - rbtree_node_t *f = NULL; - int dir = 1; - - // Set up our helpers. - q = &head; - g = p = NULL; - q->link[1] = self->root; - - /* Search and push a red node down - * to fix red violations as we go. - */ - while (q->link[dir] != NULL) { - int last = dir; - - // Move the helpers down. - g = p, p = q; - q = q->link[dir]; - dir = self->cmp(self, q, &node) < 0; - - /* Save the node with matching value and keep - * going; we'll do removal tasks at the end. - */ - if (self->cmp(self, q, &node) == 0) { - f = q; - } - - // Push the red node down with rotations and color flips. - if (!rbtree_node_is_red(q) && - !rbtree_node_is_red(q->link[dir])) { - if (rbtree_node_is_red(q->link[!dir])) { - p = p->link[last] = - rbtree_node_rotate(q, dir); - } else if (!rbtree_node_is_red(q->link[!dir])) { - rbtree_node_t *s = p->link[!last]; - if (s) { - if (!rbtree_node_is_red( - s->link[!last]) && - !rbtree_node_is_red( - s->link[last])) { - // Color flip. - p->red = 0; - s->red = 1; - q->red = 1; - } else { - int dir2 = - g->link[1] == p; - if (rbtree_node_is_red( - s->link[last])) { - g->link[dir2] = rbtree_node_rotate2( - p, - last); - } else if ( - rbtree_node_is_red( - s->link[!last])) { - g->link[dir2] = rbtree_node_rotate( - p, - last); - } - // Ensure correct coloring. - q->red = g->link[dir2] - ->red = - 1; - g->link[dir2] - ->link[0] - ->red = 0; - g->link[dir2] - ->link[1] - ->red = 0; - } - } - } - } - } - // Replace and remove the saved node. - if (f) { - void *tmp = f->value; - f->value = q->value; - q->value = tmp; - - p->link[p->link[1] == q] = q->link[q->link[0] == NULL]; - - if (node_cb) { - node_cb(self, q); - } - q = NULL; - } - - // Update the root (it may be different). - self->root = head.link[1]; - - // Make the root black for simplified logic. - if (self->root != NULL) { - self->root->red = 0; - } - - --self->size; - } - - return 1; -} - -int rbtree_tree_remove(rbtree_t *self, void *value) -{ - int result = 0; - if (self) { - result = rbtree_tree_remove_with_cb( - self, value, rbtree_tree_node_dealloc_cb); - } - - return result; -} - -size_t rbtree_tree_size(rbtree_t *self) -{ - size_t result = 0; - if (self) { - result = self->size; - } - - return result; -} - -// rbtree_iter_t - -rbtree_iter_t *rbtree_iter_alloc() -{ - return malloc(sizeof(rbtree_iter_t)); -} - -rbtree_iter_t *rbtree_iter_init(rbtree_iter_t *self) -{ - if (self) { - self->tree = NULL; - self->node = NULL; - self->top = 0; - } - - return self; -} - -rbtree_iter_t *rbtree_iter_create() -{ - return rbtree_iter_init(rbtree_iter_alloc()); -} - -void rbtree_iter_dealloc(rbtree_iter_t *self) -{ - if (self) { - free(self); - } -} - -/* Internal function, init traversal object, dir determines whether - * to begin traversal at the smallest or largest valued node. - */ -static void *rbtree_iter_start(rbtree_iter_t *self, rbtree_t *tree, int dir) -{ - void *result = NULL; - if (self) { - self->tree = tree; - self->node = tree->root; - self->top = 0; - // Save the path for later selfersal. - if (self->node != NULL) { - while (self->node->link[dir] != NULL) { - self->path[self->top++] = self->node; - self->node = self->node->link[dir]; - } - } - - result = self->node == NULL ? NULL : self->node->value; - } - - return result; -} - -// Traverse a red black tree in the user-specified direction (0 asc, 1 desc). -static void *rbtree_iter_move(rbtree_iter_t *self, int dir) -{ - if (self->node->link[dir] != NULL) { - // Continue down this branch. - self->path[self->top++] = self->node; - self->node = self->node->link[dir]; - while (self->node->link[!dir] != NULL) { - self->path[self->top++] = self->node; - self->node = self->node->link[!dir]; - } - } else { - // Move to the next branch. - rbtree_node_t *last = NULL; - do { - if (self->top == 0) { - self->node = NULL; - - break; - } - last = self->node; - self->node = self->path[--self->top]; - } while (last == self->node->link[dir]); - } - - return self->node == NULL ? NULL : self->node->value; -} - -void *rbtree_iter_first(rbtree_iter_t *self, rbtree_t *tree) -{ - return rbtree_iter_start(self, tree, 0); -} - -void *rbtree_iter_last(rbtree_iter_t *self, rbtree_t *tree) -{ - return rbtree_iter_start(self, tree, 1); -} - -void *rbtree_iter_next(rbtree_iter_t *self) -{ - return rbtree_iter_move(self, 1); -} - -void *rbtree_iter_prev(rbtree_iter_t *self) -{ - return rbtree_iter_move(self, 0); -} - -int rbtree_tree_test(rbtree_t *self, rbtree_node_t *root) -{ - int lh, rh; - - if (root == NULL) { - return 1; - } else { - rbtree_node_t *ln = root->link[0]; - rbtree_node_t *rn = root->link[1]; - - // Consecutive red links. - if (rbtree_node_is_red(root)) { - if (rbtree_node_is_red(ln) || rbtree_node_is_red(rn)) { - printf("Red violation"); - - return 0; - } - } - - lh = rbtree_tree_test(self, ln); - rh = rbtree_tree_test(self, rn); - - // Invalid binary search tree. - if ((ln != NULL && self->cmp(self, ln, root) >= 0) || - (rn != NULL && self->cmp(self, rn, root) <= 0)) { - puts("Binary tree violation"); - - return 0; - } - - // Black height mismatch. - if (lh != 0 && rh != 0 && lh != rh) { - puts("Black violation"); - - return 0; - } - - // Only count black links. - if (lh != 0 && rh != 0) { - return rbtree_node_is_red(root) ? lh : lh + 1; - } else { - return 0; - } - } -} - -static void rbtree_tree_print_iter(rbtree_t *self, rbtree_node_t *node, - rbtree_tree_node_f fun) -{ - assert(self); - assert(node); - assert(fun); - - fun(self, node); - if (node->link[0]) { - rbtree_tree_print_iter(self, node->link[0], fun); - } - if (node->link[1]) { - rbtree_tree_print_iter(self, node->link[1], fun); - } -} - -void rbtree_tree_print(rbtree_t *self, rbtree_tree_node_f fun) -{ - assert(self); - assert(fun); - - rbtree_tree_print_iter(self, self->root, fun); -} +/// MentOS, The Mentoring Operating system project +/// @file rbtree.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "rbtree.h" +#include "assert.h" +#include "stdlib.h" + +struct rbtree_node_t { + /// Color red (1), black (0) + int red; + /// Link left [0] and right [1] + rbtree_node_t *link[2]; + /// User provided, used indirectly via rbtree_tree_node_cmp_f. + void *value; +}; + +struct rbtree_t { + rbtree_node_t *root; + rbtree_tree_node_cmp_f cmp; + size_t size; +}; + +struct rbtree_iter_t { + /// Pointer to the tree itself. + rbtree_t *tree; + /// Current node + rbtree_node_t *node; + /// Traversal path + rbtree_node_t *path[RBTREE_ITER_MAX_HEIGHT]; + /// Top of stack + size_t top; +}; + +rbtree_node_t *rbtree_node_alloc() +{ + return malloc(sizeof(rbtree_node_t)); +} + +rbtree_node_t *rbtree_node_init(rbtree_node_t *self, void *value) +{ + if (self) { + self->red = 1; + self->link[0] = self->link[1] = NULL; + self->value = value; + } + + return self; +} + +rbtree_node_t *rbtree_node_create(void *value) +{ + return rbtree_node_init(rbtree_node_alloc(), value); +} + +void *rbtree_node_get_value(rbtree_node_t *self) +{ + if (self) { + return self->value; + } + + return NULL; +} + +void rbtree_node_dealloc(rbtree_node_t *self) +{ + if (self) { + free(self); + } +} + +static int rbtree_node_is_red(const rbtree_node_t *self) +{ + return self ? self->red : 0; +} + +static rbtree_node_t *rbtree_node_rotate(rbtree_node_t *self, int dir) +{ + rbtree_node_t *result = NULL; + if (self) { + result = self->link[!dir]; + self->link[!dir] = result->link[dir]; + result->link[dir] = self; + self->red = 1; + result->red = 0; + } + + return result; +} + +static rbtree_node_t *rbtree_node_rotate2(rbtree_node_t *self, int dir) +{ + rbtree_node_t *result = NULL; + if (self) { + self->link[!dir] = rbtree_node_rotate(self->link[!dir], !dir); + result = rbtree_node_rotate(self, dir); + } + + return result; +} + +// rbtree_t - default callbacks. + +static int rbtree_tree_node_cmp_ptr_cb(rbtree_t *self, rbtree_node_t *a, + rbtree_node_t *b) +{ + (void)self; + + return (a->value > b->value) - (a->value < b->value); +} + +static void rbtree_tree_node_dealloc_cb(rbtree_t *self, rbtree_node_t *node) +{ + if (self) { + if (node) { + rbtree_node_dealloc(node); + } + } +} + +// rbtree_t + +rbtree_t *rbtree_tree_alloc() +{ + return malloc(sizeof(rbtree_t)); +} + +rbtree_t *rbtree_tree_init(rbtree_t *self, rbtree_tree_node_cmp_f node_cmp_cb) +{ + if (self) { + self->root = NULL; + self->size = 0; + self->cmp = + node_cmp_cb ? node_cmp_cb : rbtree_tree_node_cmp_ptr_cb; + } + + return self; +} + +rbtree_t *rbtree_tree_create(rbtree_tree_node_cmp_f node_cb) +{ + return rbtree_tree_init(rbtree_tree_alloc(), node_cb); +} + +void rbtree_tree_dealloc(rbtree_t *self, rbtree_tree_node_f node_cb) +{ + assert(self); + if (node_cb) { + rbtree_node_t *node = self->root; + rbtree_node_t *save = NULL; + + /* Rotate away the left links so that + * we can treat this like the destruction + * of a linked list. + */ + while (node) { + if (node->link[0] == NULL) { + // No left links, just kill the node and move on. + save = node->link[1]; + node_cb(self, node); + free(node); + node = NULL; + } else { + // Rotate away the left link and check again. + save = node->link[0]; + node->link[0] = save->link[1]; + save->link[1] = node; + } + node = save; + } + } + + free(self); +} + +void *rbtree_tree_find(rbtree_t *self, void *value) +{ + void *result = NULL; + if (self) { + rbtree_node_t node = { .value = value }; + rbtree_node_t *it = self->root; + int cmp = 0; + while (it) { + if ((cmp = self->cmp(self, it, &node))) { + /* If the tree supports duplicates, they should be + * chained to the right subtree for this to work. + */ + it = it->link[cmp < 0]; + } else { + break; + } + } + result = it ? it->value : NULL; + } + + return result; +} + +void *rbtree_tree_find_by_value(rbtree_t *self, rbtree_tree_cmp_f cmp_fun, + void *value) +{ + void *result = NULL; + if (self) { + rbtree_node_t *it = self->root; + int cmp = 0; + while (it) { + if ((cmp = cmp_fun(self, it, value))) { + /* If the tree supports duplicates, they should be + * chained to the right subtree for this to work. + */ + it = it->link[cmp < 0]; + } else { + break; + } + } + result = it ? it->value : NULL; + } + + return result; +} + +// Creates (malloc'ates). +int rbtree_tree_insert(rbtree_t *self, void *value) +{ + return rbtree_tree_insert_node(self, rbtree_node_create(value)); +} + +// Returns 1 on success, 0 otherwise. +int rbtree_tree_insert_node(rbtree_t *self, rbtree_node_t *node) +{ + if (self && node) { + if (self->root == NULL) { + self->root = node; + } else { + // False tree root. + rbtree_node_t head = { 0 }; + // Grandparent & parent. + rbtree_node_t *g, *t; + // Iterator & parent. + rbtree_node_t *p, *q; + int dir = 0, last = 0; + + // Set up our helpers. + t = &head; + g = p = NULL; + q = t->link[1] = self->root; + + // Search down the tree for a place to insert. + while (1) { + if (q == NULL) { + // Insert node at the first null link. + p->link[dir] = q = node; + } else if (rbtree_node_is_red(q->link[0]) && + rbtree_node_is_red(q->link[1])) { + // Simple red violation: color flip. + q->red = 1; + q->link[0]->red = 0; + q->link[1]->red = 0; + } + + if (rbtree_node_is_red(q) && + rbtree_node_is_red(p)) { + // Hard red violation: rotations necessary. + int dir2 = t->link[1] == g; + + if (q == p->link[last]) { + t->link[dir2] = + rbtree_node_rotate( + g, !last); + } else { + t->link[dir2] = + rbtree_node_rotate2( + g, !last); + } + } + /* Stop working if we inserted a node. This + * check also disallows duplicates in the tree. + */ + if (self->cmp(self, q, node) == 0) { + break; + } + last = dir; + dir = self->cmp(self, q, node) < 0; + + // Move the helpers down. + if (g != NULL) { + t = g; + } + g = p, p = q; + q = q->link[dir]; + } + // Update the root (it may be different). + self->root = head.link[1]; + } + // Make the root black for simplified logic. + self->root->red = 0; + ++self->size; + } + + return 1; +} + +/* Returns 1 if the value was removed, 0 otherwise. Optional node callback + * can be provided to dealloc node and/or user data. Use + * rbtree_tree_node_dealloc + * default callback to deallocate node created by rbtree_tree_insert(...). + */ +int rbtree_tree_remove_with_cb(rbtree_t *self, void *value, + rbtree_tree_node_f node_cb) +{ + if (self->root != NULL) { + // False tree root. + rbtree_node_t head = { 0 }; + // Value wrapper node. + rbtree_node_t node = { .value = value }; + // Helpers. + rbtree_node_t *q, *p, *g; + // Found item. + rbtree_node_t *f = NULL; + int dir = 1; + + // Set up our helpers. + q = &head; + g = p = NULL; + q->link[1] = self->root; + + /* Search and push a red node down + * to fix red violations as we go. + */ + while (q->link[dir] != NULL) { + int last = dir; + + // Move the helpers down. + g = p, p = q; + q = q->link[dir]; + dir = self->cmp(self, q, &node) < 0; + + /* Save the node with matching value and keep + * going; we'll do removal tasks at the end. + */ + if (self->cmp(self, q, &node) == 0) { + f = q; + } + + // Push the red node down with rotations and color flips. + if (!rbtree_node_is_red(q) && + !rbtree_node_is_red(q->link[dir])) { + if (rbtree_node_is_red(q->link[!dir])) { + p = p->link[last] = + rbtree_node_rotate(q, dir); + } else if (!rbtree_node_is_red(q->link[!dir])) { + rbtree_node_t *s = p->link[!last]; + if (s) { + if (!rbtree_node_is_red( + s->link[!last]) && + !rbtree_node_is_red( + s->link[last])) { + // Color flip. + p->red = 0; + s->red = 1; + q->red = 1; + } else { + int dir2 = + g->link[1] == p; + if (rbtree_node_is_red( + s->link[last])) { + g->link[dir2] = rbtree_node_rotate2( + p, + last); + } else if ( + rbtree_node_is_red( + s->link[!last])) { + g->link[dir2] = rbtree_node_rotate( + p, + last); + } + // Ensure correct coloring. + q->red = g->link[dir2] + ->red = + 1; + g->link[dir2] + ->link[0] + ->red = 0; + g->link[dir2] + ->link[1] + ->red = 0; + } + } + } + } + } + // Replace and remove the saved node. + if (f) { + void *tmp = f->value; + f->value = q->value; + q->value = tmp; + + p->link[p->link[1] == q] = q->link[q->link[0] == NULL]; + + if (node_cb) { + node_cb(self, q); + } + q = NULL; + } + + // Update the root (it may be different). + self->root = head.link[1]; + + // Make the root black for simplified logic. + if (self->root != NULL) { + self->root->red = 0; + } + + --self->size; + } + + return 1; +} + +int rbtree_tree_remove(rbtree_t *self, void *value) +{ + int result = 0; + if (self) { + result = rbtree_tree_remove_with_cb( + self, value, rbtree_tree_node_dealloc_cb); + } + + return result; +} + +size_t rbtree_tree_size(rbtree_t *self) +{ + size_t result = 0; + if (self) { + result = self->size; + } + + return result; +} + +// rbtree_iter_t + +rbtree_iter_t *rbtree_iter_alloc() +{ + return malloc(sizeof(rbtree_iter_t)); +} + +rbtree_iter_t *rbtree_iter_init(rbtree_iter_t *self) +{ + if (self) { + self->tree = NULL; + self->node = NULL; + self->top = 0; + } + + return self; +} + +rbtree_iter_t *rbtree_iter_create() +{ + return rbtree_iter_init(rbtree_iter_alloc()); +} + +void rbtree_iter_dealloc(rbtree_iter_t *self) +{ + if (self) { + free(self); + } +} + +/* Internal function, init traversal object, dir determines whether + * to begin traversal at the smallest or largest valued node. + */ +static void *rbtree_iter_start(rbtree_iter_t *self, rbtree_t *tree, int dir) +{ + void *result = NULL; + if (self) { + self->tree = tree; + self->node = tree->root; + self->top = 0; + // Save the path for later selfersal. + if (self->node != NULL) { + while (self->node->link[dir] != NULL) { + self->path[self->top++] = self->node; + self->node = self->node->link[dir]; + } + } + + result = self->node == NULL ? NULL : self->node->value; + } + + return result; +} + +// Traverse a red black tree in the user-specified direction (0 asc, 1 desc). +static void *rbtree_iter_move(rbtree_iter_t *self, int dir) +{ + if (self->node->link[dir] != NULL) { + // Continue down this branch. + self->path[self->top++] = self->node; + self->node = self->node->link[dir]; + while (self->node->link[!dir] != NULL) { + self->path[self->top++] = self->node; + self->node = self->node->link[!dir]; + } + } else { + // Move to the next branch. + rbtree_node_t *last = NULL; + do { + if (self->top == 0) { + self->node = NULL; + + break; + } + last = self->node; + self->node = self->path[--self->top]; + } while (last == self->node->link[dir]); + } + + return self->node == NULL ? NULL : self->node->value; +} + +void *rbtree_iter_first(rbtree_iter_t *self, rbtree_t *tree) +{ + return rbtree_iter_start(self, tree, 0); +} + +void *rbtree_iter_last(rbtree_iter_t *self, rbtree_t *tree) +{ + return rbtree_iter_start(self, tree, 1); +} + +void *rbtree_iter_next(rbtree_iter_t *self) +{ + return rbtree_iter_move(self, 1); +} + +void *rbtree_iter_prev(rbtree_iter_t *self) +{ + return rbtree_iter_move(self, 0); +} + +int rbtree_tree_test(rbtree_t *self, rbtree_node_t *root) +{ + int lh, rh; + + if (root == NULL) { + return 1; + } else { + rbtree_node_t *ln = root->link[0]; + rbtree_node_t *rn = root->link[1]; + + // Consecutive red links. + if (rbtree_node_is_red(root)) { + if (rbtree_node_is_red(ln) || rbtree_node_is_red(rn)) { + printf("Red violation"); + + return 0; + } + } + + lh = rbtree_tree_test(self, ln); + rh = rbtree_tree_test(self, rn); + + // Invalid binary search tree. + if ((ln != NULL && self->cmp(self, ln, root) >= 0) || + (rn != NULL && self->cmp(self, rn, root) <= 0)) { + puts("Binary tree violation"); + + return 0; + } + + // Black height mismatch. + if (lh != 0 && rh != 0 && lh != rh) { + puts("Black violation"); + + return 0; + } + + // Only count black links. + if (lh != 0 && rh != 0) { + return rbtree_node_is_red(root) ? lh : lh + 1; + } else { + return 0; + } + } +} + +static void rbtree_tree_print_iter(rbtree_t *self, rbtree_node_t *node, + rbtree_tree_node_f fun) +{ + assert(self); + assert(node); + assert(fun); + + fun(self, node); + if (node->link[0]) { + rbtree_tree_print_iter(self, node->link[0], fun); + } + if (node->link[1]) { + rbtree_tree_print_iter(self, node->link[1], fun); + } +} + +void rbtree_tree_print(rbtree_t *self, rbtree_tree_node_f fun) +{ + assert(self); + assert(fun); + + rbtree_tree_print_iter(self, self->root, fun); +} diff --git a/mentos/src/libc/spinlock.c b/mentos/src/libc/spinlock.c index 235906d..4aa15dd 100644 --- a/mentos/src/libc/spinlock.c +++ b/mentos/src/libc/spinlock.c @@ -1,34 +1,34 @@ -/// MentOS, The Mentoring Operating system project -/// @file spinlock.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "spinlock.h" - -void spinlock_init(spinlock_t *spinlock) -{ - (*spinlock) = 0; -} - -void spinlock_lock(spinlock_t *spinlock) -{ - while (true) { - if (atomic_set_and_test(spinlock, SPINLOCK_BUSY) == 0) { - break; - } - while (*spinlock) - cpu_relax(); - } -} - -void spinlock_unlock(spinlock_t *spinlock) -{ - barrier(); - atomic_set(spinlock, SPINLOCK_FREE); -} - -bool_t spinlock_trylock(spinlock_t *spinlock) -{ - return (bool_t)(atomic_set_and_test(spinlock, SPINLOCK_BUSY) == 0); -} +/// MentOS, The Mentoring Operating system project +/// @file spinlock.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "spinlock.h" + +void spinlock_init(spinlock_t *spinlock) +{ + (*spinlock) = 0; +} + +void spinlock_lock(spinlock_t *spinlock) +{ + while (true) { + if (atomic_set_and_test(spinlock, SPINLOCK_BUSY) == 0) { + break; + } + while (*spinlock) + cpu_relax(); + } +} + +void spinlock_unlock(spinlock_t *spinlock) +{ + barrier(); + atomic_set(spinlock, SPINLOCK_FREE); +} + +bool_t spinlock_trylock(spinlock_t *spinlock) +{ + return (bool_t)(atomic_set_and_test(spinlock, SPINLOCK_BUSY) == 0); +} diff --git a/mentos/src/libc/stdio.c b/mentos/src/libc/stdio.c index a1b246c..48a37c0 100644 --- a/mentos/src/libc/stdio.c +++ b/mentos/src/libc/stdio.c @@ -1,160 +1,160 @@ -/// @file stdio.c -/// @brief Standard I/0 functions. -/// @date Apr 2019 - -#include "stdio.h" -#include "video.h" -#include "ctype.h" -#include "string.h" -#include "keyboard.h" -#include "unistd.h" -#include "debug.h" - -void putchar(int character) -{ - write(STDOUT_FILENO, &character, 1); -} - -void puts(char *str) -{ - write(STDOUT_FILENO, str, strlen(str)); -} - -int getchar(void) -{ - char c; - while (true) { - read(STDIN_FILENO, &c, 1); - if (c != -1) - break; - } - return c; -} - -char *gets(char *str) -{ - // Check the input string. - if (str == NULL) - return NULL; - // Buffer for reading input. - char buffer[GETS_BUFFERSIZE]; - memset(buffer, '\0', GETS_BUFFERSIZE); - // Char pointer to the buffer. - char *cptr = buffer; - // Character storage and counter to prevent overflow. - int ch, counter = 0; - // Read until we find a newline or we exceed the buffer size. - while (((ch = getchar()) != '\n') && (counter++ < GETS_BUFFERSIZE)) { - // If we encounter EOF, stop. - if (ch == EOF) { - // EOF at start of line return NULL. - if (cptr == str) - return NULL; - break; - } - // The character is stored at address, and the pointer is incremented. - *cptr++ = ch; - } - // Add the null-terminating character. - *cptr = '\0'; - // Copy the string we have read. - strcpy(str, buffer); - // Return a pointer to the original string. - return str; -} - -int atoi(const char *str) -{ - // Check the input string. - if (str == NULL) - return 0; - // Initialize sign. - int sign = (str[0] == '-') ? -1 : +1; - // Initialize the result. - int result = 0; - // Check that the rest of the numbers are digits. - for (int i = (sign == -1) ? 1 : 0; str[i] != '\0'; ++i) - if (!isdigit(str[i])) - return -1; - // Iterate through all digits and update the result. - for (int i = (sign == -1) ? 1 : 0; str[i] != '\0'; ++i) - result = (result * 10) + str[i] - '0'; - return sign * result; -} - -int printf(const char *format, ...) -{ - char buffer[4096]; - va_list ap; - - // Start variabile argument's list. - va_start(ap, format); - - int len = vsprintf(buffer, format, ap); - va_end(ap); - - // Write the contento to standard output. - write(STDOUT_FILENO, buffer, len); - - return len; -} - -size_t scanf(const char *format, ...) -{ - size_t count = 0; - va_list scan; - va_start(scan, format); - - for (; *format; format++) { - if (*format == '%') { - // Declare an input string. - char input[GETS_BUFFERSIZE]; - // Get the input string. - gets(input); - // Evaluate the length of the string. - size_t input_length = strlen(input); - // Add the length of the input to the counter. - count += input_length; - // Evaluate the maximum number of input characters. - size_t max_chars = 0; - if (isdigit(*++format)) { - char max_char_num[16]; - int i = 0; - - while (isdigit(*format)) { - max_char_num[i++] = *format; - format++; - } - max_char_num[i] = '\0'; - int number = atoi(max_char_num); - - if (number > 0) { - max_chars = (size_t)number; - } - } - switch (*format) { - case 's': { - char *s_ptr = va_arg(scan, char *); - if (max_chars == 0 || input_length <= max_chars) - strncpy(s_ptr, input, input_length); - else - strncpy(s_ptr, input, max_chars); - break; - } - case 'd': { - int *d_ptr = va_arg(scan, int *); - if (max_chars != 0 && input_length > max_chars) { - input[max_chars] = '\0'; - } - (*d_ptr) = atoi(input); - break; - } - default: - break; - } - } - } - va_end(scan); - - return count; -} +/// @file stdio.c +/// @brief Standard I/0 functions. +/// @date Apr 2019 + +#include "stdio.h" +#include "video.h" +#include "ctype.h" +#include "string.h" +#include "keyboard.h" +#include "unistd.h" +#include "debug.h" + +void putchar(int character) +{ + write(STDOUT_FILENO, &character, 1); +} + +void puts(char *str) +{ + write(STDOUT_FILENO, str, strlen(str)); +} + +int getchar(void) +{ + char c; + while (true) { + read(STDIN_FILENO, &c, 1); + if (c != -1) + break; + } + return c; +} + +char *gets(char *str) +{ + // Check the input string. + if (str == NULL) + return NULL; + // Buffer for reading input. + char buffer[GETS_BUFFERSIZE]; + memset(buffer, '\0', GETS_BUFFERSIZE); + // Char pointer to the buffer. + char *cptr = buffer; + // Character storage and counter to prevent overflow. + int ch, counter = 0; + // Read until we find a newline or we exceed the buffer size. + while (((ch = getchar()) != '\n') && (counter++ < GETS_BUFFERSIZE)) { + // If we encounter EOF, stop. + if (ch == EOF) { + // EOF at start of line return NULL. + if (cptr == str) + return NULL; + break; + } + // The character is stored at address, and the pointer is incremented. + *cptr++ = ch; + } + // Add the null-terminating character. + *cptr = '\0'; + // Copy the string we have read. + strcpy(str, buffer); + // Return a pointer to the original string. + return str; +} + +int atoi(const char *str) +{ + // Check the input string. + if (str == NULL) + return 0; + // Initialize sign. + int sign = (str[0] == '-') ? -1 : +1; + // Initialize the result. + int result = 0; + // Check that the rest of the numbers are digits. + for (int i = (sign == -1) ? 1 : 0; str[i] != '\0'; ++i) + if (!isdigit(str[i])) + return -1; + // Iterate through all digits and update the result. + for (int i = (sign == -1) ? 1 : 0; str[i] != '\0'; ++i) + result = (result * 10) + str[i] - '0'; + return sign * result; +} + +int printf(const char *format, ...) +{ + char buffer[4096]; + va_list ap; + + // Start variabile argument's list. + va_start(ap, format); + + int len = vsprintf(buffer, format, ap); + va_end(ap); + + // Write the contento to standard output. + write(STDOUT_FILENO, buffer, len); + + return len; +} + +size_t scanf(const char *format, ...) +{ + size_t count = 0; + va_list scan; + va_start(scan, format); + + for (; *format; format++) { + if (*format == '%') { + // Declare an input string. + char input[GETS_BUFFERSIZE]; + // Get the input string. + gets(input); + // Evaluate the length of the string. + size_t input_length = strlen(input); + // Add the length of the input to the counter. + count += input_length; + // Evaluate the maximum number of input characters. + size_t max_chars = 0; + if (isdigit(*++format)) { + char max_char_num[16]; + int i = 0; + + while (isdigit(*format)) { + max_char_num[i++] = *format; + format++; + } + max_char_num[i] = '\0'; + int number = atoi(max_char_num); + + if (number > 0) { + max_chars = (size_t)number; + } + } + switch (*format) { + case 's': { + char *s_ptr = va_arg(scan, char *); + if (max_chars == 0 || input_length <= max_chars) + strncpy(s_ptr, input, input_length); + else + strncpy(s_ptr, input, max_chars); + break; + } + case 'd': { + int *d_ptr = va_arg(scan, int *); + if (max_chars != 0 && input_length > max_chars) { + input[max_chars] = '\0'; + } + (*d_ptr) = atoi(input); + break; + } + default: + break; + } + } + } + va_end(scan); + + return count; +} diff --git a/mentos/src/libc/stdlib.c b/mentos/src/libc/stdlib.c index 8cde7c1..e78d4df 100644 --- a/mentos/src/libc/stdlib.c +++ b/mentos/src/libc/stdlib.c @@ -1,48 +1,67 @@ -/// MentOS, The Mentoring Operating system project -/// @file stdlib.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "syscall.h" -#include "stdlib.h" -#include "string.h" - -void *malloc(unsigned int size) -{ - void *_res; - DEFN_SYSCALL1(_res, __NR_brk, size); - - return _res; -} - -void free(void *p) -{ - int _res; - DEFN_SYSCALL1(_res, __NR_free, p); -} - -void *calloc(size_t element_number, size_t element_size) -{ - void *ptr = malloc(element_number * element_size); - if (ptr) { - memset(ptr, 0, element_number * element_size); - } - - return ptr; -} - -/// Seed used to generate random numbers. -static int rseed = 0; - -inline void srand(int x) -{ - rseed = x; -} - -/// @brief Returns a pseudo-random integral number in the range -/// between 0 and RAND_MAX. -inline int rand() -{ - return rseed = (rseed * 1103515245U + 12345U) & RAND_MAX; -} +/// MentOS, The Mentoring Operating system project +/// @file stdlib.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "syscall.h" +#include "stdlib.h" +#include "string.h" + +void *malloc(unsigned int size) +{ + void *_res; + DEFN_SYSCALL1(_res, __NR_brk, size); + + return _res; +} + +void free(void *p) +{ + int _res; + DEFN_SYSCALL1(_res, __NR_free, p); +} + +void *calloc(size_t element_number, size_t element_size) +{ + void *ptr = malloc(element_number * element_size); + if (ptr) { + memset(ptr, 0, element_number * element_size); + } + + return ptr; +} + +void **mmalloc(size_t n, size_t size) +{ + void **ret = (void **) malloc(n * sizeof(void *)); + for (size_t i = 0; i < n; i++) + { + *(ret + i) = malloc(size); + } + return ret; +} + +void mfree(void **src, size_t n) +{ + for (size_t i = 0; i < n; i++) + { + free(*(src + i)); + } + free(src); +} + +/// Seed used to generate random numbers. +static int rseed = 0; + +inline void srand(int x) +{ + rseed = x; +} + +/// @brief Returns a pseudo-random integral number in the range +/// between 0 and RAND_MAX. +inline int rand() +{ + return rseed = (rseed * 1103515245U + 12345U) & RAND_MAX; +} diff --git a/mentos/src/libc/strerror.c b/mentos/src/libc/strerror.c index afcb482..6d89d1b 100644 --- a/mentos/src/libc/strerror.c +++ b/mentos/src/libc/strerror.c @@ -1,470 +1,470 @@ -/// MentOS, The Mentoring Operating system project -/// @file strerror.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "strerror.h" -#include "string.h" - -char *strerror(int errnum) -{ - static char error[1024]; - - switch (errnum) { - case 0: - strcpy(error, "Success"); - break; -#ifdef ENOENT - case ENOENT: - strcpy(error, "No such file or directory"); - break; -#endif -#ifdef ESRCH - case ESRCH: - strcpy(error, "No such process"); - break; -#endif -#ifdef EINTR - case EINTR: - strcpy(error, "Interrupted system call"); - break; -#endif -#ifdef EIO - case EIO: - strcpy(error, "I/O error"); - break; -#endif -#if defined(ENXIO) && (!defined(ENODEV) || (ENXIO != ENODEV)) - case ENXIO: - strcpy(error, "No such device or address"); - break; -#endif -#ifdef E2BIG - case E2BIG: - strcpy(error, "Arg list too long"); - break; -#endif -#ifdef ENOEXEC - case ENOEXEC: - strcpy(error, "Exec format error"); - break; -#endif -#ifdef EALREADY - case EALREADY: - strcpy(error, "Socket already connected"); - break; -#endif -#ifdef EBADF - case EBADF: - strcpy(error, "Bad file number"); - break; -#endif -#ifdef ECHILD - case ECHILD: - strcpy(error, "No children"); - break; -#endif -#ifdef EDESTADDRREQ - case EDESTADDRREQ: - strcpy(error, "Destination address required"); - break; -#endif -#ifdef EAGAIN - case EAGAIN: - strcpy(error, "No more processes"); - break; -#endif -#ifdef ENOMEM - case ENOMEM: - strcpy(error, "Not enough space"); - break; -#endif -#ifdef EACCES - case EACCES: - strcpy(error, "Permission denied"); - break; -#endif -#ifdef EFAULT - case EFAULT: - strcpy(error, "Bad address"); - break; -#endif -#ifdef ENOTBLK - case ENOTBLK: - strcpy(error, "Block device required"); - break; -#endif -#ifdef EBUSY - case EBUSY: - strcpy(error, "Device or resource busy"); - break; -#endif -#ifdef EEXIST - case EEXIST: - strcpy(error, "File exists"); - break; -#endif -#ifdef EXDEV - case EXDEV: - strcpy(error, "Cross-device link"); - break; -#endif -#ifdef ENODEV - case ENODEV: - strcpy(error, "No such device"); - break; -#endif -#ifdef ENOTDIR - case ENOTDIR: - strcpy(error, "Not a directory"); - break; -#endif -#ifdef EHOSTDOWN - case EHOSTDOWN: - strcpy(error, "Host is down"); - break; -#endif -#ifdef EINPROGRESS - case EINPROGRESS: - strcpy(error, "Connection already in progress"); - break; -#endif -#ifdef EISDIR - case EISDIR: - strcpy(error, "Is a directory"); - break; -#endif -#ifdef EINVAL - case EINVAL: - strcpy(error, "Invalid argument"); - break; -#endif -#ifdef ENETDOWN - case ENETDOWN: - strcpy(error, "Network interface is not configured"); - break; -#endif -#ifdef ENFILE - case ENFILE: - strcpy(error, "Too many open files in system"); - break; -#endif -#ifdef EMFILE - case EMFILE: - strcpy(error, "Too many open files"); - break; -#endif -#ifdef ENOTTY - case ENOTTY: - strcpy(error, "Not a character device"); - break; -#endif -#ifdef ETXTBSY - case ETXTBSY: - strcpy(error, "Text file busy"); - break; -#endif -#ifdef EFBIG - case EFBIG: - strcpy(error, "File too large"); - break; -#endif -#ifdef EHOSTUNREACH - case EHOSTUNREACH: - strcpy(error, "Host is unreachable"); - break; -#endif -#ifdef ENOSPC - case ENOSPC: - strcpy(error, "No space left on device"); - break; -#endif -#ifdef ENOTSUP - case ENOTSUP: - strcpy(error, "Not supported"); - break; -#endif -#ifdef ESPIPE - case ESPIPE: - strcpy(error, "Illegal seek"); - break; -#endif -#ifdef EROFS - case EROFS: - strcpy(error, "Read-only file system"); - break; -#endif -#ifdef EMLINK - case EMLINK: - strcpy(error, "Too many links"); - break; -#endif -#ifdef EPIPE - case EPIPE: - strcpy(error, "Broken pipe"); - break; -#endif -#ifdef EDOM - case EDOM: - strcpy(error, "Math argument"); - break; -#endif -#ifdef ERANGE - case ERANGE: - strcpy(error, "Result too large"); - break; -#endif -#ifdef ENOMSG - case ENOMSG: - strcpy(error, "No message of desired type"); - break; -#endif -#ifdef EIDRM - case EIDRM: - strcpy(error, "Identifier removed"); - break; -#endif -#ifdef EDEADLK - case EDEADLK: - strcpy(error, "Deadlock"); - break; -#endif -#ifdef ENETUNREACH - case ENETUNREACH: - strcpy(error, "Network is unreachable"); - break; -#endif -#ifdef ENOLCK - case ENOLCK: - strcpy(error, "No lock"); - break; -#endif -#ifdef ENOSTR - case ENOSTR: - strcpy(error, "Not a stream"); - break; -#endif -#ifdef ETIME - case ETIME: - strcpy(error, "Stream ioctl timeout"); - break; -#endif -#ifdef ENOSR - case ENOSR: - strcpy(error, "No stream resources"); - break; -#endif -#ifdef ENONET - case ENONET: - strcpy(error, "Machine is not on the network"); - break; -#endif -#ifdef ENOPKG - case ENOPKG: - strcpy(error, "No package"); - break; -#endif -#ifdef EREMOTE - case EREMOTE: - strcpy(error, "Resource is remote"); - break; -#endif -#ifdef ENOLINK - case ENOLINK: - strcpy(error, "Virtual circuit is gone"); - break; -#endif -#ifdef EADV - case EADV: - strcpy(error, "Advertise error"); - break; -#endif -#ifdef ESRMNT - case ESRMNT: - strcpy(error, "Srmount error"); - break; -#endif -#ifdef ECOMM - case ECOMM: - strcpy(error, "Communication error"); - break; -#endif -#ifdef EPROTO - case EPROTO: - strcpy(error, "Protocol error"); - break; -#endif -#ifdef EPROTONOSUPPORT - case EPROTONOSUPPORT: - strcpy(error, "Unknown protocol"); - break; -#endif -#ifdef EMULTIHOP - case EMULTIHOP: - strcpy(error, "Multihop attempted"); - break; -#endif -#ifdef EBADMSG - case EBADMSG: - strcpy(error, "Bad message"); - break; -#endif -#ifdef ELIBACC - case ELIBACC: - strcpy(error, "Cannot access a needed shared library"); - break; -#endif -#ifdef ELIBBAD - case ELIBBAD: - strcpy(error, "Accessing a corrupted shared library"); - break; -#endif -#ifdef ELIBSCN - case ELIBSCN: - strcpy(error, ".lib section in a.out corrupted"); - break; -#endif -#ifdef ELIBMAX - case ELIBMAX: - strcpy(error, - "Attempting to link in more shared libraries than system limit"); - break; -#endif -#ifdef ELIBEXEC - case ELIBEXEC: - strcpy(error, "Cannot exec a shared library directly"); - break; -#endif -#ifdef ENOSYS - case ENOSYS: - strcpy(error, "Function not implemented"); - break; -#endif -#ifdef ENMFILE - case ENMFILE: - strcpy(error, "No more files"); - break; -#endif -#ifdef ENOTEMPTY - case ENOTEMPTY: - strcpy(error, "Directory not empty"); - break; -#endif -#ifdef ENAMETOOLONG - case ENAMETOOLONG: - strcpy(error, "File or path name too long"); - break; -#endif -#ifdef ELOOP - case ELOOP: - strcpy(error, "Too many symbolic links"); - break; -#endif -#ifdef ENOBUFS - case ENOBUFS: - strcpy(error, "No buffer space available"); - break; -#endif -#ifdef EAFNOSUPPORT - case EAFNOSUPPORT: - strcpy(error, "Address family not supported by protocol family"); - break; -#endif -#ifdef EPROTOTYPE - case EPROTOTYPE: - strcpy(error, "Protocol wrong type for socket"); - break; -#endif -#ifdef ENOTSOCK - case ENOTSOCK: - strcpy(error, "Socket operation on non-socket"); - break; -#endif -#ifdef ENOPROTOOPT - case ENOPROTOOPT: - strcpy(error, "Protocol not available"); - break; -#endif -#ifdef ESHUTDOWN - case ESHUTDOWN: - strcpy(error, "Can't send after socket shutdown"); - break; -#endif -#ifdef ECONNREFUSED - case ECONNREFUSED: - strcpy(error, "Connection refused"); - break; -#endif -#ifdef EADDRINUSE - case EADDRINUSE: - strcpy(error, "Address already in use"); - break; -#endif -#ifdef ECONNABORTED - case ECONNABORTED: - strcpy(error, "Software caused connection abort"); - break; -#endif -#if (defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))) - case EWOULDBLOCK: - strcpy(error, "Operation would block"); - break; -#endif -#ifdef ENOTCONN - case ENOTCONN: - strcpy(error, "Socket is not connected"); - break; -#endif -#ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: - strcpy(error, "Socket type not supported"); - break; -#endif -#ifdef EISCONN - case EISCONN: - strcpy(error, "Socket is already connected"); - break; -#endif -#ifdef ECANCELED - case ECANCELED: - strcpy(error, "Operation canceled"); - break; -#endif -#ifdef ENOTRECOVERABLE - case ENOTRECOVERABLE: - strcpy(error, "State not recoverable"); - break; -#endif -#ifdef EOWNERDEAD - case EOWNERDEAD: - strcpy(error, "Previous owner died"); - break; -#endif -#ifdef ESTRPIPE - case ESTRPIPE: - strcpy(error, "Streams pipe error"); - break; -#endif -#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP)) - case EOPNOTSUPP: - strcpy(error, "Operation not supported on socket"); - break; -#endif -#ifdef EMSGSIZE - case EMSGSIZE: - strcpy(error, "Message too long"); - break; -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: - strcpy(error, "Connection timed out"); - break; -#endif - default: - strcpy(error, "Unknown error"); - break; - } - - return error; -} +/// MentOS, The Mentoring Operating system project +/// @file strerror.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "strerror.h" +#include "string.h" + +char *strerror(int errnum) +{ + static char error[1024]; + + switch (errnum) { + case 0: + strcpy(error, "Success"); + break; +#ifdef ENOENT + case ENOENT: + strcpy(error, "No such file or directory"); + break; +#endif +#ifdef ESRCH + case ESRCH: + strcpy(error, "No such process"); + break; +#endif +#ifdef EINTR + case EINTR: + strcpy(error, "Interrupted system call"); + break; +#endif +#ifdef EIO + case EIO: + strcpy(error, "I/O error"); + break; +#endif +#if defined(ENXIO) && (!defined(ENODEV) || (ENXIO != ENODEV)) + case ENXIO: + strcpy(error, "No such device or address"); + break; +#endif +#ifdef E2BIG + case E2BIG: + strcpy(error, "Arg list too long"); + break; +#endif +#ifdef ENOEXEC + case ENOEXEC: + strcpy(error, "Exec format error"); + break; +#endif +#ifdef EALREADY + case EALREADY: + strcpy(error, "Socket already connected"); + break; +#endif +#ifdef EBADF + case EBADF: + strcpy(error, "Bad file number"); + break; +#endif +#ifdef ECHILD + case ECHILD: + strcpy(error, "No children"); + break; +#endif +#ifdef EDESTADDRREQ + case EDESTADDRREQ: + strcpy(error, "Destination address required"); + break; +#endif +#ifdef EAGAIN + case EAGAIN: + strcpy(error, "No more processes"); + break; +#endif +#ifdef ENOMEM + case ENOMEM: + strcpy(error, "Not enough space"); + break; +#endif +#ifdef EACCES + case EACCES: + strcpy(error, "Permission denied"); + break; +#endif +#ifdef EFAULT + case EFAULT: + strcpy(error, "Bad address"); + break; +#endif +#ifdef ENOTBLK + case ENOTBLK: + strcpy(error, "Block device required"); + break; +#endif +#ifdef EBUSY + case EBUSY: + strcpy(error, "Device or resource busy"); + break; +#endif +#ifdef EEXIST + case EEXIST: + strcpy(error, "File exists"); + break; +#endif +#ifdef EXDEV + case EXDEV: + strcpy(error, "Cross-device link"); + break; +#endif +#ifdef ENODEV + case ENODEV: + strcpy(error, "No such device"); + break; +#endif +#ifdef ENOTDIR + case ENOTDIR: + strcpy(error, "Not a directory"); + break; +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: + strcpy(error, "Host is down"); + break; +#endif +#ifdef EINPROGRESS + case EINPROGRESS: + strcpy(error, "Connection already in progress"); + break; +#endif +#ifdef EISDIR + case EISDIR: + strcpy(error, "Is a directory"); + break; +#endif +#ifdef EINVAL + case EINVAL: + strcpy(error, "Invalid argument"); + break; +#endif +#ifdef ENETDOWN + case ENETDOWN: + strcpy(error, "Network interface is not configured"); + break; +#endif +#ifdef ENFILE + case ENFILE: + strcpy(error, "Too many open files in system"); + break; +#endif +#ifdef EMFILE + case EMFILE: + strcpy(error, "Too many open files"); + break; +#endif +#ifdef ENOTTY + case ENOTTY: + strcpy(error, "Not a character device"); + break; +#endif +#ifdef ETXTBSY + case ETXTBSY: + strcpy(error, "Text file busy"); + break; +#endif +#ifdef EFBIG + case EFBIG: + strcpy(error, "File too large"); + break; +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: + strcpy(error, "Host is unreachable"); + break; +#endif +#ifdef ENOSPC + case ENOSPC: + strcpy(error, "No space left on device"); + break; +#endif +#ifdef ENOTSUP + case ENOTSUP: + strcpy(error, "Not supported"); + break; +#endif +#ifdef ESPIPE + case ESPIPE: + strcpy(error, "Illegal seek"); + break; +#endif +#ifdef EROFS + case EROFS: + strcpy(error, "Read-only file system"); + break; +#endif +#ifdef EMLINK + case EMLINK: + strcpy(error, "Too many links"); + break; +#endif +#ifdef EPIPE + case EPIPE: + strcpy(error, "Broken pipe"); + break; +#endif +#ifdef EDOM + case EDOM: + strcpy(error, "Math argument"); + break; +#endif +#ifdef ERANGE + case ERANGE: + strcpy(error, "Result too large"); + break; +#endif +#ifdef ENOMSG + case ENOMSG: + strcpy(error, "No message of desired type"); + break; +#endif +#ifdef EIDRM + case EIDRM: + strcpy(error, "Identifier removed"); + break; +#endif +#ifdef EDEADLK + case EDEADLK: + strcpy(error, "Deadlock"); + break; +#endif +#ifdef ENETUNREACH + case ENETUNREACH: + strcpy(error, "Network is unreachable"); + break; +#endif +#ifdef ENOLCK + case ENOLCK: + strcpy(error, "No lock"); + break; +#endif +#ifdef ENOSTR + case ENOSTR: + strcpy(error, "Not a stream"); + break; +#endif +#ifdef ETIME + case ETIME: + strcpy(error, "Stream ioctl timeout"); + break; +#endif +#ifdef ENOSR + case ENOSR: + strcpy(error, "No stream resources"); + break; +#endif +#ifdef ENONET + case ENONET: + strcpy(error, "Machine is not on the network"); + break; +#endif +#ifdef ENOPKG + case ENOPKG: + strcpy(error, "No package"); + break; +#endif +#ifdef EREMOTE + case EREMOTE: + strcpy(error, "Resource is remote"); + break; +#endif +#ifdef ENOLINK + case ENOLINK: + strcpy(error, "Virtual circuit is gone"); + break; +#endif +#ifdef EADV + case EADV: + strcpy(error, "Advertise error"); + break; +#endif +#ifdef ESRMNT + case ESRMNT: + strcpy(error, "Srmount error"); + break; +#endif +#ifdef ECOMM + case ECOMM: + strcpy(error, "Communication error"); + break; +#endif +#ifdef EPROTO + case EPROTO: + strcpy(error, "Protocol error"); + break; +#endif +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: + strcpy(error, "Unknown protocol"); + break; +#endif +#ifdef EMULTIHOP + case EMULTIHOP: + strcpy(error, "Multihop attempted"); + break; +#endif +#ifdef EBADMSG + case EBADMSG: + strcpy(error, "Bad message"); + break; +#endif +#ifdef ELIBACC + case ELIBACC: + strcpy(error, "Cannot access a needed shared library"); + break; +#endif +#ifdef ELIBBAD + case ELIBBAD: + strcpy(error, "Accessing a corrupted shared library"); + break; +#endif +#ifdef ELIBSCN + case ELIBSCN: + strcpy(error, ".lib section in a.out corrupted"); + break; +#endif +#ifdef ELIBMAX + case ELIBMAX: + strcpy(error, + "Attempting to link in more shared libraries than system limit"); + break; +#endif +#ifdef ELIBEXEC + case ELIBEXEC: + strcpy(error, "Cannot exec a shared library directly"); + break; +#endif +#ifdef ENOSYS + case ENOSYS: + strcpy(error, "Function not implemented"); + break; +#endif +#ifdef ENMFILE + case ENMFILE: + strcpy(error, "No more files"); + break; +#endif +#ifdef ENOTEMPTY + case ENOTEMPTY: + strcpy(error, "Directory not empty"); + break; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: + strcpy(error, "File or path name too long"); + break; +#endif +#ifdef ELOOP + case ELOOP: + strcpy(error, "Too many symbolic links"); + break; +#endif +#ifdef ENOBUFS + case ENOBUFS: + strcpy(error, "No buffer space available"); + break; +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: + strcpy(error, "Address family not supported by protocol family"); + break; +#endif +#ifdef EPROTOTYPE + case EPROTOTYPE: + strcpy(error, "Protocol wrong type for socket"); + break; +#endif +#ifdef ENOTSOCK + case ENOTSOCK: + strcpy(error, "Socket operation on non-socket"); + break; +#endif +#ifdef ENOPROTOOPT + case ENOPROTOOPT: + strcpy(error, "Protocol not available"); + break; +#endif +#ifdef ESHUTDOWN + case ESHUTDOWN: + strcpy(error, "Can't send after socket shutdown"); + break; +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: + strcpy(error, "Connection refused"); + break; +#endif +#ifdef EADDRINUSE + case EADDRINUSE: + strcpy(error, "Address already in use"); + break; +#endif +#ifdef ECONNABORTED + case ECONNABORTED: + strcpy(error, "Software caused connection abort"); + break; +#endif +#if (defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))) + case EWOULDBLOCK: + strcpy(error, "Operation would block"); + break; +#endif +#ifdef ENOTCONN + case ENOTCONN: + strcpy(error, "Socket is not connected"); + break; +#endif +#ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: + strcpy(error, "Socket type not supported"); + break; +#endif +#ifdef EISCONN + case EISCONN: + strcpy(error, "Socket is already connected"); + break; +#endif +#ifdef ECANCELED + case ECANCELED: + strcpy(error, "Operation canceled"); + break; +#endif +#ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: + strcpy(error, "State not recoverable"); + break; +#endif +#ifdef EOWNERDEAD + case EOWNERDEAD: + strcpy(error, "Previous owner died"); + break; +#endif +#ifdef ESTRPIPE + case ESTRPIPE: + strcpy(error, "Streams pipe error"); + break; +#endif +#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP)) + case EOPNOTSUPP: + strcpy(error, "Operation not supported on socket"); + break; +#endif +#ifdef EMSGSIZE + case EMSGSIZE: + strcpy(error, "Message too long"); + break; +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: + strcpy(error, "Connection timed out"); + break; +#endif + default: + strcpy(error, "Unknown error"); + break; + } + + return error; +} diff --git a/mentos/src/libc/string.c b/mentos/src/libc/string.c index 196163d..f48d43d 100644 --- a/mentos/src/libc/string.c +++ b/mentos/src/libc/string.c @@ -1,850 +1,850 @@ -/// MentOS, The Mentoring Operating system project -/// @file string.c -/// @brief String routines. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include -#include "string.h" -#include "ctype.h" -#include "stdlib.h" -#include "stdio.h" - -char *strncpy(char *destination, const char *source, size_t num) -{ - char *start = destination; - while (num && (*destination++ = *source++)) { - num--; - } - if (num) { - while (--num) { - *destination++ = '\0'; - } - } - - return start; -} - -int strncmp(const char *s1, const char *s2, size_t n) -{ - if (!n) - return 0; - while ((--n > 0) && (*s1) && (*s2) && (*s1 == *s2)) { - s1++; - s2++; - } - - return *(unsigned char *)s1 - *(unsigned char *)s2; -} - -int stricmp(const char *s1, const char *s2) -{ - while (*s2 != 0 && toupper(*s1) == toupper(*s2)) { - s1++, s2++; - } - - return (toupper(*s1) - toupper(*s2)); -} - -int strnicmp(const char *s1, const char *s2, size_t n) -{ - int f, l; - - do { - if (((f = (unsigned char)(*(s1++))) >= 'A') && (f <= 'Z')) { - f -= 'A' - 'a'; - } - if (((l = (unsigned char)(*(s2++))) >= 'A') && (l <= 'Z')) { - l -= 'A' - 'a'; - } - } while (--n && f && (f == l)); - - return f - l; -} - -char *strchr(const char *s, int ch) -{ - while (*s && *s != (char)ch) { - s++; - } - if (*s == (char)ch) - return (char *)s; - { - return NULL; - } -} - -char *strrchr(const char *s, int ch) -{ - char *start = (char *)s; - - while (*s++) - ; - - while (--s != start && *s != (char)ch) - ; - - if (*s == (char)ch) { - return (char *)s; - } - - return NULL; -} - -char *strstr(const char *str1, const char *str2) -{ - char *cp = (char *)str1; - char *s1, *s2; - - if (!*str2) { - return (char *)str1; - } - - while (*cp) { - s1 = cp; - s2 = (char *)str2; - - while (*s1 && *s2 && !(*s1 - *s2)) { - s1++, s2++; - } - if (!*s2) { - return cp; - } - cp++; - } - - return NULL; -} - -size_t strspn(const char *string, const char *control) -{ - const char *str = string; - const char *ctrl = control; - - char map[32]; - size_t n; - - // Clear out bit map. - for (n = 0; n < 32; n++) { - map[n] = 0; - } - - // Set bits in control map. - while (*ctrl) { - map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); - ctrl++; - } - - // 1st char NOT in control map stops search. - if (*str) { - n = 0; - while (map[*str >> 3] & (1 << (*str & 7))) { - n++; - str++; - } - - return n; - } - - return 0; -} - -size_t strcspn(const char *string, const char *control) -{ - const char *str = string; - const char *ctrl = control; - - char map[32]; - size_t n; - - // Clear out bit map. - for (n = 0; n < 32; n++) - map[n] = 0; - - // Set bits in control map. - while (*ctrl) { - map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); - ctrl++; - } - - // 1st char in control map stops search. - n = 0; - map[0] |= 1; - while (!(map[*str >> 3] & (1 << (*str & 7)))) { - n++; - str++; - } - - return n; -} - -char *strpbrk(const char *string, const char *control) -{ - const char *str = string; - const char *ctrl = control; - - char map[32]; - int n; - - // Clear out bit map. - for (n = 0; n < 32; n++) - map[n] = 0; - - // Set bits in control map. - while (*ctrl) { - map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); - ctrl++; - } - - // 1st char in control map stops search. - while (*str) { - if (map[*str >> 3] & (1 << (*str & 7))) { - return (char *)str; - } - str++; - } - - return NULL; -} - -void *memmove(void *dst, const void *src, size_t n) -{ - void *ret = dst; - - if (dst <= src || (char *)dst >= ((char *)src + n)) { - /* Non-overlapping buffers; copy from lower addresses to higher - * addresses. - */ - while (n--) { - *(char *)dst = *(char *)src; - dst = (char *)dst + 1; - src = (char *)src + 1; - } - } else { - // Overlapping buffers; copy from higher addresses to lower addresses. - dst = (char *)dst + n - 1; - src = (char *)src + n - 1; - - while (n--) { - *(char *)dst = *(char *)src; - dst = (char *)dst - 1; - src = (char *)src - 1; - } - } - - return ret; -} - -void *memchr(const void *buf, int ch, size_t n) -{ - while (n && (*(unsigned char *)buf != (unsigned char)ch)) { - buf = (unsigned char *)buf + 1; - n--; - } - - return (n ? (void *)buf : NULL); -} - -char *strlwr(char *s) -{ - char *p = s; - - while (*p) { - *p = (char)tolower(*p); - p++; - } - - return s; -} - -char *strupr(char *s) -{ - char *p = s; - - while (*p) { - *p = (char)toupper(*p); - p++; - } - - return s; -} - -char *strncat(char *s1, const char *s2, size_t n) -{ - char *start = s1; - - while (*s1++) - ; - { - s1--; - } - - while (n--) { - if (!(*s1++ = *s2++)) - return start; - } - - *s1 = '\0'; - - return start; -} - -char *strnset(char *s, int c, size_t n) -{ - while (n-- && *s) { - *s++ = (char)c; - } - - return s; -} - -char *strrev(char *s) -{ - char *start = s; - char *left = s; - char ch; - - while (*s++) - ; - s -= 2; - - while (left < s) { - ch = *left; - *left++ = *s; - *s-- = ch; - } - - return start; -} - -char *strtok_r(char *string, const char *control, char **lasts) -{ - char *str; - const char *ctrl = control; - - char map[32]; - int n; - - // Clear control map. - for (n = 0; n < 32; n++) { - map[n] = 0; - } - - // Set bits in delimiter table. - do { - map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); - } while (*ctrl++); - - /* Initialize str. If string is NULL, set str to the saved - * pointer (i.e., continue breaking tokens out of the string - * from the last strtok call). - */ - if (string) { - str = string; - } else { - str = *lasts; - } - - /* Find beginning of token (skip over leading delimiters). Note that - * there is no token iff this loop sets str to point to the terminal - * null (*str == '\0'). - */ - while ((map[*str >> 3] & (1 << (*str & 7))) && *str) { - str++; - } - - string = str; - - /* Find the end of the token. If it is not the end of the string, - * put a null there. - */ - for (; *str; str++) { - if (map[*str >> 3] & (1 << (*str & 7))) { - *str++ = '\0'; - - break; - } - } - - // Update nexttoken. - *lasts = str; - - // Determine if a token has been found. - if (string == (char *)str) { - return NULL; - } else { - return string; - } -} - -// Intrinsic functions. - -/* - * #pragma function(memset) - * #pragma function(memcmp) - * #pragma function(memcpy) - * #pragma function(strcpy) - * #pragma function(strlen) - * #pragma function(strcat) - * #pragma function(strcmp) - * #pragma function(strset) - */ - -void *memset(void *ptr, int value, size_t num) -{ - // Truncate c to 8 bits. - value = (value & 0xFF); - - char *dst = (char *)ptr; - - // Initialize the rest of the size. - while (num--) { - *dst++ = (char)value; - } - - return ptr; -} - -int memcmp(const void *dst, const void *src, size_t n) -{ - if (!n) { - return 0; - } - - while (--n && *(char *)dst == *(char *)src) { - dst = (char *)dst + 1; - src = (char *)src + 1; - } - - return *((unsigned char *)dst) - *((unsigned char *)src); -} - -void *memcpy(void *_dst, const void *_src, size_t num) -{ - char *dst = _dst; - const char *src = _src; - - while (num--) { - *dst++ = *src++; - } - - return _dst; -} - -void *memccpy(void *dst, const void *src, int c, size_t n) -{ - while (n && (*((char *)(dst = (char *)dst + 1) - 1) = - *((char *)(src = (char *)src + 1) - 1)) != (char)c) { - n--; - } - - return n ? dst : NULL; -} - -char *strcpy(char *dst, const char *src) -{ - char *save = dst; - - while ((*dst++ = *src++) != '\0') - ; - - return save; -} - -size_t strlen(const char *s) -{ - const char *eos; - - for (eos = s; *eos != 0; ++eos) - ; - - long len = eos - s; - - return (len < 0) ? 0 : (size_t)len; -} - -size_t strnlen(const char *s, size_t count) -{ - const char *sc; - - for (sc = s; *sc != '\0' && count--; ++sc) - ; - - long len = sc - s; - - return (len < 0) ? 0 : (size_t)len; -} - -int strcmp(const char *s1, const char *s2) -{ - int ret = 0; - const char *s1t = s1, *s2t = s2; - - for (; !(ret = *s1t - *s2t) && *s2t; ++s1t, ++s2t) - ; - - return (ret < 0) ? -1 : (ret > 0) ? 1 : 0; -} - -char *strcat(char *dst, const char *src) -{ - char *cp = dst; - - while (*cp) { - cp++; - } - - while ((*cp++ = *src++) != '\0') - ; - - return dst; -} - -char *strset(char *s, int c) -{ - char *start = s; - - while (*s) { - *s++ = (char)c; - } - - return start; -} - -char *strtok(char *str, const char *delim) -{ - const char *spanp; - int c, sc; - char *tok; - static char *last; - - if (str == NULL && (str = last) == NULL) { - return (NULL); - } - -cont: - c = *str++; - for (spanp = delim; (sc = *spanp++) != 0;) { - if (c == sc) { - goto cont; - } - } - - if (c == 0) { - last = NULL; - - return (NULL); - } - tok = str - 1; - - for (;;) { - c = *str++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) { - str = NULL; - } else { - str[-1] = 0; - } - last = str; - - return (tok); - } - } while (sc != 0); - } -} - -int _kstrncmp(const char *s1, const char *s2, size_t num) -{ - /* If the number of characters that has to be checked is equal to zero, - * just return 0. - */ - if (num == 0) { - return 0; - } - size_t sn = 0; - - while ((*s1 == *s2) && (sn < (num - 1))) { - ++s1; - ++s2; - ++sn; - } - - if (*s1 > *s2) { - return 1; - } - - if (*s1 < *s2) { - return -1; - } - - return 0; -} - -char *trim(char *str) -{ - size_t len = 0; - char *frontp = str; - char *endp = NULL; - - if (str == NULL) { - return NULL; - } - if (str[0] == '\0') { - return str; - } - - len = strlen(str); - endp = str + len; - - /* Move the front and back pointers to address the first non-whitespace - * characters from each end. - */ - while (isspace((unsigned char)*frontp)) { - ++frontp; - } - if (endp != frontp) { - while (isspace((unsigned char)*(--endp)) && endp != frontp) - ; - } - if (str + len - 1 != endp) { - *(endp + 1) = '\0'; - } else if (frontp != str && endp == frontp) { - *str = '\0'; - } - /* Shift the string so that it starts at str so that if it's dynamically - * allocated, we can still free it on the returned pointer. Note the reuse - * of endp to mean the front of the string buffer now. - */ - endp = str; - if (frontp != str) { - while (*frontp) { - *endp++ = *frontp++; - } - *endp = '\0'; - } - - return str; -} - -char *strdup(const char *s) -{ - size_t len = strlen(s) + 1; - - return memcpy(malloc(len), s, len); -} - -char *kstrdup(const char *s) -{ - size_t len = strlen(s) + 1; - - return memcpy(kmalloc(len), s, len); -} - -char *strsep(char **stringp, const char *delim) -{ - char *s; - const char *spanp; - int c, sc; - char *tok; - if ((s = *stringp) == NULL) { - return (NULL); - } - for (tok = s;;) { - c = *s++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) { - s = NULL; - } else { - s[-1] = 0; - } - *stringp = s; - - return (tok); - } - } while (sc != 0); - } -} - -list_t *str_split(const char *str, const char *delim, unsigned int *num) -{ - list_t *ret_list = list_create(); - char *s = strdup(str); - char *token, *rest = s; - - while ((token = strsep(&rest, delim)) != NULL) { - if (!strcmp(token, ".")) { - continue; - } - if (!strcmp(token, "..")) { - if (list_size(ret_list) > 0) - list_pop_back(ret_list); - - continue; - } - list_push(ret_list, strdup(token)); - - if (num) { - (*num)++; - } - } - free(s); - - return ret_list; -} - -char *list2str(list_t *list, const char *delim) -{ - char *ret = malloc(256); - memset(ret, 0, 256); - size_t len = 0; - size_t ret_len = 256; - - while (list_size(list) > 0) { - char *temp = list_pop_back(list)->value; - size_t len_temp = strlen(temp); - if (len + len_temp + 1 + 1 > ret_len) { - ret_len = ret_len * 2; - free(ret); - ret = malloc(ret_len); - len = len + len_temp + 1; - } - strcat(ret, delim); - strcat(ret, temp); - } - - return ret; -} - -void int_to_str(char *buffer, unsigned int num, unsigned int base) -{ - // int numval; - char *p, *pbase; - - p = pbase = buffer; - - if (base == 16) { - sprintf(buffer, "%0x", num); - } else { - if (num == 0) { - *p++ = '0'; - } - while (num != 0) { - *p++ = (char)('0' + (num % base)); - num = num / base; - } - *p-- = 0; - - while (p > pbase) { - char tmp; - tmp = *p; - *p = *pbase; - *pbase = tmp; - - p--; - pbase++; - } - } -} - -void _knntos(char *buffer, int num, int base) -{ - // int numval; - char *p, *pbase; - - p = pbase = buffer; - - if (num < 0) { - num = (~num) + 1; - *p++ = '-'; - pbase++; - } - while (num > 0) { - *p++ = (char)('0' + (num % base)); - num = num / base; - } - - *p-- = 0; - while (p > pbase) { - char tmp; - tmp = *p; - *p = *pbase; - *pbase = tmp; - - p--; - pbase++; - } -} - -char *replace_char(char *str, char find, char replace) -{ - char *current_pos = strchr(str, find); - - while (current_pos) { - *current_pos = replace; - current_pos = strchr(current_pos, find); - } - - return str; -} - -void strmode(mode_t mode, char *p) -{ - // Usr. - if (mode & 0400) { - *p++ = 'r'; - } else { - *p++ = '-'; - } - if (mode & 0200) { - *p++ = 'w'; - } else { - *p++ = '-'; - } - if (mode & 0100) { - *p++ = 'x'; - } else { - *p++ = '-'; - } - - // Group. - if (mode & 0040) { - *p++ = 'r'; - } else { - *p++ = '-'; - } - if (mode & 0020) { - *p++ = 'w'; - } else { - *p++ = '-'; - } - if (mode & 0010) { - *p++ = 'x'; - } else { - *p++ = '-'; - } - - // Other. - if (mode & 0004) { - *p++ = 'r'; - } else { - *p++ = '-'; - } - if (mode & 0002) { - *p++ = 'w'; - } else { - *p++ = '-'; - } - if (mode & 0001) { - *p++ = 'x'; - } else { - *p++ = '-'; - } - - // Will be a '+' if ACL's implemented. - *p++ = ' '; - *p = '\0'; -} +/// MentOS, The Mentoring Operating system project +/// @file string.c +/// @brief String routines. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include "string.h" +#include "ctype.h" +#include "stdlib.h" +#include "stdio.h" + +char *strncpy(char *destination, const char *source, size_t num) +{ + char *start = destination; + while (num && (*destination++ = *source++)) { + num--; + } + if (num) { + while (--num) { + *destination++ = '\0'; + } + } + + return start; +} + +int strncmp(const char *s1, const char *s2, size_t n) +{ + if (!n) + return 0; + while ((--n > 0) && (*s1) && (*s2) && (*s1 == *s2)) { + s1++; + s2++; + } + + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +int stricmp(const char *s1, const char *s2) +{ + while (*s2 != 0 && toupper(*s1) == toupper(*s2)) { + s1++, s2++; + } + + return (toupper(*s1) - toupper(*s2)); +} + +int strnicmp(const char *s1, const char *s2, size_t n) +{ + int f, l; + + do { + if (((f = (unsigned char)(*(s1++))) >= 'A') && (f <= 'Z')) { + f -= 'A' - 'a'; + } + if (((l = (unsigned char)(*(s2++))) >= 'A') && (l <= 'Z')) { + l -= 'A' - 'a'; + } + } while (--n && f && (f == l)); + + return f - l; +} + +char *strchr(const char *s, int ch) +{ + while (*s && *s != (char)ch) { + s++; + } + if (*s == (char)ch) + return (char *)s; + { + return NULL; + } +} + +char *strrchr(const char *s, int ch) +{ + char *start = (char *)s; + + while (*s++) + ; + + while (--s != start && *s != (char)ch) + ; + + if (*s == (char)ch) { + return (char *)s; + } + + return NULL; +} + +char *strstr(const char *str1, const char *str2) +{ + char *cp = (char *)str1; + char *s1, *s2; + + if (!*str2) { + return (char *)str1; + } + + while (*cp) { + s1 = cp; + s2 = (char *)str2; + + while (*s1 && *s2 && !(*s1 - *s2)) { + s1++, s2++; + } + if (!*s2) { + return cp; + } + cp++; + } + + return NULL; +} + +size_t strspn(const char *string, const char *control) +{ + const char *str = string; + const char *ctrl = control; + + char map[32]; + size_t n; + + // Clear out bit map. + for (n = 0; n < 32; n++) { + map[n] = 0; + } + + // Set bits in control map. + while (*ctrl) { + map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); + ctrl++; + } + + // 1st char NOT in control map stops search. + if (*str) { + n = 0; + while (map[*str >> 3] & (1 << (*str & 7))) { + n++; + str++; + } + + return n; + } + + return 0; +} + +size_t strcspn(const char *string, const char *control) +{ + const char *str = string; + const char *ctrl = control; + + char map[32]; + size_t n; + + // Clear out bit map. + for (n = 0; n < 32; n++) + map[n] = 0; + + // Set bits in control map. + while (*ctrl) { + map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); + ctrl++; + } + + // 1st char in control map stops search. + n = 0; + map[0] |= 1; + while (!(map[*str >> 3] & (1 << (*str & 7)))) { + n++; + str++; + } + + return n; +} + +char *strpbrk(const char *string, const char *control) +{ + const char *str = string; + const char *ctrl = control; + + char map[32]; + int n; + + // Clear out bit map. + for (n = 0; n < 32; n++) + map[n] = 0; + + // Set bits in control map. + while (*ctrl) { + map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); + ctrl++; + } + + // 1st char in control map stops search. + while (*str) { + if (map[*str >> 3] & (1 << (*str & 7))) { + return (char *)str; + } + str++; + } + + return NULL; +} + +void *memmove(void *dst, const void *src, size_t n) +{ + void *ret = dst; + + if (dst <= src || (char *)dst >= ((char *)src + n)) { + /* Non-overlapping buffers; copy from lower addresses to higher + * addresses. + */ + while (n--) { + *(char *)dst = *(char *)src; + dst = (char *)dst + 1; + src = (char *)src + 1; + } + } else { + // Overlapping buffers; copy from higher addresses to lower addresses. + dst = (char *)dst + n - 1; + src = (char *)src + n - 1; + + while (n--) { + *(char *)dst = *(char *)src; + dst = (char *)dst - 1; + src = (char *)src - 1; + } + } + + return ret; +} + +void *memchr(const void *buf, int ch, size_t n) +{ + while (n && (*(unsigned char *)buf != (unsigned char)ch)) { + buf = (unsigned char *)buf + 1; + n--; + } + + return (n ? (void *)buf : NULL); +} + +char *strlwr(char *s) +{ + char *p = s; + + while (*p) { + *p = (char)tolower(*p); + p++; + } + + return s; +} + +char *strupr(char *s) +{ + char *p = s; + + while (*p) { + *p = (char)toupper(*p); + p++; + } + + return s; +} + +char *strncat(char *s1, const char *s2, size_t n) +{ + char *start = s1; + + while (*s1++) + ; + { + s1--; + } + + while (n--) { + if (!(*s1++ = *s2++)) + return start; + } + + *s1 = '\0'; + + return start; +} + +char *strnset(char *s, int c, size_t n) +{ + while (n-- && *s) { + *s++ = (char)c; + } + + return s; +} + +char *strrev(char *s) +{ + char *start = s; + char *left = s; + char ch; + + while (*s++) + ; + s -= 2; + + while (left < s) { + ch = *left; + *left++ = *s; + *s-- = ch; + } + + return start; +} + +char *strtok_r(char *string, const char *control, char **lasts) +{ + char *str; + const char *ctrl = control; + + char map[32]; + int n; + + // Clear control map. + for (n = 0; n < 32; n++) { + map[n] = 0; + } + + // Set bits in delimiter table. + do { + map[*ctrl >> 3] |= (char)(1 << (*ctrl & 7)); + } while (*ctrl++); + + /* Initialize str. If string is NULL, set str to the saved + * pointer (i.e., continue breaking tokens out of the string + * from the last strtok call). + */ + if (string) { + str = string; + } else { + str = *lasts; + } + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets str to point to the terminal + * null (*str == '\0'). + */ + while ((map[*str >> 3] & (1 << (*str & 7))) && *str) { + str++; + } + + string = str; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. + */ + for (; *str; str++) { + if (map[*str >> 3] & (1 << (*str & 7))) { + *str++ = '\0'; + + break; + } + } + + // Update nexttoken. + *lasts = str; + + // Determine if a token has been found. + if (string == (char *)str) { + return NULL; + } else { + return string; + } +} + +// Intrinsic functions. + +/* + * #pragma function(memset) + * #pragma function(memcmp) + * #pragma function(memcpy) + * #pragma function(strcpy) + * #pragma function(strlen) + * #pragma function(strcat) + * #pragma function(strcmp) + * #pragma function(strset) + */ + +void *memset(void *ptr, int value, size_t num) +{ + // Truncate c to 8 bits. + value = (value & 0xFF); + + char *dst = (char *)ptr; + + // Initialize the rest of the size. + while (num--) { + *dst++ = (char)value; + } + + return ptr; +} + +int memcmp(const void *dst, const void *src, size_t n) +{ + if (!n) { + return 0; + } + + while (--n && *(char *)dst == *(char *)src) { + dst = (char *)dst + 1; + src = (char *)src + 1; + } + + return *((unsigned char *)dst) - *((unsigned char *)src); +} + +void *memcpy(void *_dst, const void *_src, size_t num) +{ + char *dst = _dst; + const char *src = _src; + + while (num--) { + *dst++ = *src++; + } + + return _dst; +} + +void *memccpy(void *dst, const void *src, int c, size_t n) +{ + while (n && (*((char *)(dst = (char *)dst + 1) - 1) = + *((char *)(src = (char *)src + 1) - 1)) != (char)c) { + n--; + } + + return n ? dst : NULL; +} + +char *strcpy(char *dst, const char *src) +{ + char *save = dst; + + while ((*dst++ = *src++) != '\0') + ; + + return save; +} + +size_t strlen(const char *s) +{ + const char *eos; + + for (eos = s; *eos != 0; ++eos) + ; + + long len = eos - s; + + return (len < 0) ? 0 : (size_t)len; +} + +size_t strnlen(const char *s, size_t count) +{ + const char *sc; + + for (sc = s; *sc != '\0' && count--; ++sc) + ; + + long len = sc - s; + + return (len < 0) ? 0 : (size_t)len; +} + +int strcmp(const char *s1, const char *s2) +{ + int ret = 0; + const char *s1t = s1, *s2t = s2; + + for (; !(ret = *s1t - *s2t) && *s2t; ++s1t, ++s2t) + ; + + return (ret < 0) ? -1 : (ret > 0) ? 1 : 0; +} + +char *strcat(char *dst, const char *src) +{ + char *cp = dst; + + while (*cp) { + cp++; + } + + while ((*cp++ = *src++) != '\0') + ; + + return dst; +} + +char *strset(char *s, int c) +{ + char *start = s; + + while (*s) { + *s++ = (char)c; + } + + return start; +} + +char *strtok(char *str, const char *delim) +{ + const char *spanp; + int c, sc; + char *tok; + static char *last; + + if (str == NULL && (str = last) == NULL) { + return (NULL); + } + +cont: + c = *str++; + for (spanp = delim; (sc = *spanp++) != 0;) { + if (c == sc) { + goto cont; + } + } + + if (c == 0) { + last = NULL; + + return (NULL); + } + tok = str - 1; + + for (;;) { + c = *str++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) { + str = NULL; + } else { + str[-1] = 0; + } + last = str; + + return (tok); + } + } while (sc != 0); + } +} + +int _kstrncmp(const char *s1, const char *s2, size_t num) +{ + /* If the number of characters that has to be checked is equal to zero, + * just return 0. + */ + if (num == 0) { + return 0; + } + size_t sn = 0; + + while ((*s1 == *s2) && (sn < (num - 1))) { + ++s1; + ++s2; + ++sn; + } + + if (*s1 > *s2) { + return 1; + } + + if (*s1 < *s2) { + return -1; + } + + return 0; +} + +char *trim(char *str) +{ + size_t len = 0; + char *frontp = str; + char *endp = NULL; + + if (str == NULL) { + return NULL; + } + if (str[0] == '\0') { + return str; + } + + len = strlen(str); + endp = str + len; + + /* Move the front and back pointers to address the first non-whitespace + * characters from each end. + */ + while (isspace((unsigned char)*frontp)) { + ++frontp; + } + if (endp != frontp) { + while (isspace((unsigned char)*(--endp)) && endp != frontp) + ; + } + if (str + len - 1 != endp) { + *(endp + 1) = '\0'; + } else if (frontp != str && endp == frontp) { + *str = '\0'; + } + /* Shift the string so that it starts at str so that if it's dynamically + * allocated, we can still free it on the returned pointer. Note the reuse + * of endp to mean the front of the string buffer now. + */ + endp = str; + if (frontp != str) { + while (*frontp) { + *endp++ = *frontp++; + } + *endp = '\0'; + } + + return str; +} + +char *strdup(const char *s) +{ + size_t len = strlen(s) + 1; + + return memcpy(malloc(len), s, len); +} + +char *kstrdup(const char *s) +{ + size_t len = strlen(s) + 1; + + return memcpy(kmalloc(len), s, len); +} + +char *strsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + if ((s = *stringp) == NULL) { + return (NULL); + } + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) { + s = NULL; + } else { + s[-1] = 0; + } + *stringp = s; + + return (tok); + } + } while (sc != 0); + } +} + +list_t *str_split(const char *str, const char *delim, unsigned int *num) +{ + list_t *ret_list = list_create(); + char *s = strdup(str); + char *token, *rest = s; + + while ((token = strsep(&rest, delim)) != NULL) { + if (!strcmp(token, ".")) { + continue; + } + if (!strcmp(token, "..")) { + if (list_size(ret_list) > 0) + list_pop_back(ret_list); + + continue; + } + list_push(ret_list, strdup(token)); + + if (num) { + (*num)++; + } + } + free(s); + + return ret_list; +} + +char *list2str(list_t *list, const char *delim) +{ + char *ret = malloc(256); + memset(ret, 0, 256); + size_t len = 0; + size_t ret_len = 256; + + while (list_size(list) > 0) { + char *temp = list_pop_back(list)->value; + size_t len_temp = strlen(temp); + if (len + len_temp + 1 + 1 > ret_len) { + ret_len = ret_len * 2; + free(ret); + ret = malloc(ret_len); + len = len + len_temp + 1; + } + strcat(ret, delim); + strcat(ret, temp); + } + + return ret; +} + +void int_to_str(char *buffer, unsigned int num, unsigned int base) +{ + // int numval; + char *p, *pbase; + + p = pbase = buffer; + + if (base == 16) { + sprintf(buffer, "%0x", num); + } else { + if (num == 0) { + *p++ = '0'; + } + while (num != 0) { + *p++ = (char)('0' + (num % base)); + num = num / base; + } + *p-- = 0; + + while (p > pbase) { + char tmp; + tmp = *p; + *p = *pbase; + *pbase = tmp; + + p--; + pbase++; + } + } +} + +void _knntos(char *buffer, int num, int base) +{ + // int numval; + char *p, *pbase; + + p = pbase = buffer; + + if (num < 0) { + num = (~num) + 1; + *p++ = '-'; + pbase++; + } + while (num > 0) { + *p++ = (char)('0' + (num % base)); + num = num / base; + } + + *p-- = 0; + while (p > pbase) { + char tmp; + tmp = *p; + *p = *pbase; + *pbase = tmp; + + p--; + pbase++; + } +} + +char *replace_char(char *str, char find, char replace) +{ + char *current_pos = strchr(str, find); + + while (current_pos) { + *current_pos = replace; + current_pos = strchr(current_pos, find); + } + + return str; +} + +void strmode(mode_t mode, char *p) +{ + // Usr. + if (mode & 0400) { + *p++ = 'r'; + } else { + *p++ = '-'; + } + if (mode & 0200) { + *p++ = 'w'; + } else { + *p++ = '-'; + } + if (mode & 0100) { + *p++ = 'x'; + } else { + *p++ = '-'; + } + + // Group. + if (mode & 0040) { + *p++ = 'r'; + } else { + *p++ = '-'; + } + if (mode & 0020) { + *p++ = 'w'; + } else { + *p++ = '-'; + } + if (mode & 0010) { + *p++ = 'x'; + } else { + *p++ = '-'; + } + + // Other. + if (mode & 0004) { + *p++ = 'r'; + } else { + *p++ = '-'; + } + if (mode & 0002) { + *p++ = 'w'; + } else { + *p++ = '-'; + } + if (mode & 0001) { + *p++ = 'x'; + } else { + *p++ = '-'; + } + + // Will be a '+' if ACL's implemented. + *p++ = ' '; + *p = '\0'; +} diff --git a/mentos/src/libc/tree.c b/mentos/src/libc/tree.c index 3afd337..24c29ec 100644 --- a/mentos/src/libc/tree.c +++ b/mentos/src/libc/tree.c @@ -1,217 +1,217 @@ -/// MentOS, The Mentoring Operating system project -/// @file tree.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "tree.h" -#include "list.h" -#include "stdlib.h" -#include "debug.h" -#include "panic.h" - -tree_t *tree_create() -{ - tree_t *out = malloc(sizeof(tree_t)); - out->nodes = 0; - out->root = NULL; - - return out; -} - -tree_node_t *tree_set_root(tree_t *tree, void *value) -{ - tree_node_t *root = tree_node_create(value); - tree->root = root; - tree->nodes = 1; - - return root; -} - -void tree_node_destroy(tree_node_t *node) -{ - listnode_foreach(child, node->children) - { - tree_node_destroy((tree_node_t *)child->value); - } - free(node->value); -} - -void tree_destroy(tree_t *tree) -{ - if (tree->root) { - tree_node_destroy(tree->root); - } -} - -/// @brief Free a node and its children, but not their contents. -static void tree_node_free(tree_node_t *node) -{ - if (!node) { - return; - } - listnode_foreach(child, node->children) - { - tree_node_free(child->value); - } - list_destroy(node->children); - free(node); -} - -void tree_free(tree_t *tree) -{ - tree_node_free(tree->root); -} - -tree_node_t *tree_node_create(void *value) -{ - tree_node_t *out = malloc(sizeof(tree_node_t)); - out->value = value; - out->children = list_create(); - out->parent = NULL; - - return out; -} - -void tree_node_insert_child_node(tree_t *tree, tree_node_t *parent, - tree_node_t *node) -{ - list_insert_back(parent->children, node); - node->parent = parent; - tree->nodes++; -} - -tree_node_t *tree_node_insert_child(tree_t *tree, tree_node_t *parent, - void *value) -{ - tree_node_t *out = tree_node_create(value); - tree_node_insert_child_node(tree, parent, out); - - return out; -} - -tree_node_t *tree_node_find_parent(tree_node_t *haystack, tree_node_t *needle) -{ - tree_node_t *found = NULL; - listnode_foreach(child, haystack->children) - { - if (child->value == needle) { - return haystack; - } - found = tree_node_find_parent((tree_node_t *)child->value, needle); - if (found) { - break; - } - } - - return found; -} - -/// @brief Return the parent of a node, inefficiently. -tree_node_t *tree_find_parent(tree_t *tree, tree_node_t *node) -{ - if (!tree->root) { - return NULL; - } - - return tree_node_find_parent(tree->root, node); -} - -/// @brief Return the number of children this node has. -static size_t tree_count_children(tree_node_t *node) -{ - if (!node) { - return 0; - } - - if (!node->children) { - return 0; - } - - size_t out = node->children->size; - listnode_foreach(child, node->children) - { - out += tree_count_children((tree_node_t *)child->value); - } - - return out; -} - -void tree_node_parent_remove(tree_t *tree, tree_node_t *parent, - tree_node_t *node) -{ - tree->nodes -= tree_count_children(node) + 1; - list_remove_node(parent->children, list_find(parent->children, node)); - tree_node_free(node); -} - -void tree_node_remove(tree_t *tree, tree_node_t *node) -{ - tree_node_t *parent = node->parent; - if (!parent) { - if (node == tree->root) { - tree->nodes = 0; - tree->root = NULL; - tree_node_free(node); - } else - kernel_panic("Found node with no parent which is not root."); - } - tree_node_parent_remove(tree, parent, node); -} - -void tree_remove(tree_t *tree, tree_node_t *node) -{ - tree_node_t *parent = node->parent; - /* This is something we just can't do. We don't know how to merge our - * children into our "parent" because then we'd have more than one root node. - * A good way to think about this is actually what this tree struct - * primarily exists for: processes. Trying to remove the root is equivalent - * to trying to kill init! Which is bad. We immediately fault on such - * a case anyway ("Tried to kill init, shutting down!"). - */ - if (!parent) { - return; - } - tree->nodes--; - list_remove_node(parent->children, list_find(parent->children, node)); - listnode_foreach(child, node->children) - { - // Reassign the parents. - ((tree_node_t *)child->value)->parent = parent; - } - list_merge(parent->children, node->children); - free(node); -} - -void tree_break_off(tree_t *tree, tree_node_t *node) -{ - tree_node_t *parent = node->parent; - if (!parent) { - return; - } - list_remove_node(parent->children, list_find(parent->children, node)); -} - -/// @brief Searches the item inside tree and returns the node which contains it. -tree_node_t *tree_node_find(tree_node_t *node, void *search, - tree_comparator_t comparator) -{ - if (comparator(node->value, search)) { - return node; - } - tree_node_t *found; - listnode_foreach(child, node->children) - { - found = tree_node_find((tree_node_t *)child->value, search, comparator); - if (found) { - return found; - } - } - - return NULL; -} - -tree_node_t *tree_find(tree_t *tree, void *value, tree_comparator_t comparator) -{ - return tree_node_find(tree->root, value, comparator); -} +/// MentOS, The Mentoring Operating system project +/// @file tree.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "tree.h" +#include "list.h" +#include "stdlib.h" +#include "debug.h" +#include "panic.h" + +tree_t *tree_create() +{ + tree_t *out = malloc(sizeof(tree_t)); + out->nodes = 0; + out->root = NULL; + + return out; +} + +tree_node_t *tree_set_root(tree_t *tree, void *value) +{ + tree_node_t *root = tree_node_create(value); + tree->root = root; + tree->nodes = 1; + + return root; +} + +void tree_node_destroy(tree_node_t *node) +{ + listnode_foreach(child, node->children) + { + tree_node_destroy((tree_node_t *)child->value); + } + free(node->value); +} + +void tree_destroy(tree_t *tree) +{ + if (tree->root) { + tree_node_destroy(tree->root); + } +} + +/// @brief Free a node and its children, but not their contents. +static void tree_node_free(tree_node_t *node) +{ + if (!node) { + return; + } + listnode_foreach(child, node->children) + { + tree_node_free(child->value); + } + list_destroy(node->children); + free(node); +} + +void tree_free(tree_t *tree) +{ + tree_node_free(tree->root); +} + +tree_node_t *tree_node_create(void *value) +{ + tree_node_t *out = malloc(sizeof(tree_node_t)); + out->value = value; + out->children = list_create(); + out->parent = NULL; + + return out; +} + +void tree_node_insert_child_node(tree_t *tree, tree_node_t *parent, + tree_node_t *node) +{ + list_insert_back(parent->children, node); + node->parent = parent; + tree->nodes++; +} + +tree_node_t *tree_node_insert_child(tree_t *tree, tree_node_t *parent, + void *value) +{ + tree_node_t *out = tree_node_create(value); + tree_node_insert_child_node(tree, parent, out); + + return out; +} + +tree_node_t *tree_node_find_parent(tree_node_t *haystack, tree_node_t *needle) +{ + tree_node_t *found = NULL; + listnode_foreach(child, haystack->children) + { + if (child->value == needle) { + return haystack; + } + found = tree_node_find_parent((tree_node_t *)child->value, needle); + if (found) { + break; + } + } + + return found; +} + +/// @brief Return the parent of a node, inefficiently. +tree_node_t *tree_find_parent(tree_t *tree, tree_node_t *node) +{ + if (!tree->root) { + return NULL; + } + + return tree_node_find_parent(tree->root, node); +} + +/// @brief Return the number of children this node has. +static size_t tree_count_children(tree_node_t *node) +{ + if (!node) { + return 0; + } + + if (!node->children) { + return 0; + } + + size_t out = node->children->size; + listnode_foreach(child, node->children) + { + out += tree_count_children((tree_node_t *)child->value); + } + + return out; +} + +void tree_node_parent_remove(tree_t *tree, tree_node_t *parent, + tree_node_t *node) +{ + tree->nodes -= tree_count_children(node) + 1; + list_remove_node(parent->children, list_find(parent->children, node)); + tree_node_free(node); +} + +void tree_node_remove(tree_t *tree, tree_node_t *node) +{ + tree_node_t *parent = node->parent; + if (!parent) { + if (node == tree->root) { + tree->nodes = 0; + tree->root = NULL; + tree_node_free(node); + } else + kernel_panic("Found node with no parent which is not root."); + } + tree_node_parent_remove(tree, parent, node); +} + +void tree_remove(tree_t *tree, tree_node_t *node) +{ + tree_node_t *parent = node->parent; + /* This is something we just can't do. We don't know how to merge our + * children into our "parent" because then we'd have more than one root node. + * A good way to think about this is actually what this tree struct + * primarily exists for: processes. Trying to remove the root is equivalent + * to trying to kill init! Which is bad. We immediately fault on such + * a case anyway ("Tried to kill init, shutting down!"). + */ + if (!parent) { + return; + } + tree->nodes--; + list_remove_node(parent->children, list_find(parent->children, node)); + listnode_foreach(child, node->children) + { + // Reassign the parents. + ((tree_node_t *)child->value)->parent = parent; + } + list_merge(parent->children, node->children); + free(node); +} + +void tree_break_off(tree_t *tree, tree_node_t *node) +{ + tree_node_t *parent = node->parent; + if (!parent) { + return; + } + list_remove_node(parent->children, list_find(parent->children, node)); +} + +/// @brief Searches the item inside tree and returns the node which contains it. +tree_node_t *tree_node_find(tree_node_t *node, void *search, + tree_comparator_t comparator) +{ + if (comparator(node->value, search)) { + return node; + } + tree_node_t *found; + listnode_foreach(child, node->children) + { + found = tree_node_find((tree_node_t *)child->value, search, comparator); + if (found) { + return found; + } + } + + return NULL; +} + +tree_node_t *tree_find(tree_t *tree, void *value, tree_comparator_t comparator) +{ + return tree_node_find(tree->root, value, comparator); +} diff --git a/mentos/src/libc/unistd/chdir.c b/mentos/src/libc/unistd/chdir.c index 790f5e5..8f551e7 100644 --- a/mentos/src/libc/unistd/chdir.c +++ b/mentos/src/libc/unistd/chdir.c @@ -1,19 +1,19 @@ -/// MentOS, The Mentoring Operating system project -/// @file chdir.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "syscall.h" -#include "errno.h" - -void chdir(char const * path) -{ - ssize_t retval; - DEFN_SYSCALL1(retval, __NR_chdir, path); - if (retval < 0) - { - errno = -retval; - } -} +/// MentOS, The Mentoring Operating system project +/// @file chdir.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "syscall.h" +#include "errno.h" + +void chdir(char const * path) +{ + ssize_t retval; + DEFN_SYSCALL1(retval, __NR_chdir, path); + if (retval < 0) + { + errno = -retval; + } +} diff --git a/mentos/src/libc/unistd/close.c b/mentos/src/libc/unistd/close.c index 5be29f7..b69d6a5 100644 --- a/mentos/src/libc/unistd/close.c +++ b/mentos/src/libc/unistd/close.c @@ -1,20 +1,20 @@ -/// MentOS, The Mentoring Operating system project -/// @file close.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "errno.h" -#include "syscall.h" - -int close(int fd) -{ - int retval; - DEFN_SYSCALL1(retval, __NR_close, fd); - if (retval < 0) { - errno = -retval; - retval = -1; - } - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file close.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "errno.h" +#include "syscall.h" + +int close(int fd) +{ + int retval; + DEFN_SYSCALL1(retval, __NR_close, fd); + if (retval < 0) { + errno = -retval; + retval = -1; + } + return retval; +} diff --git a/mentos/src/libc/unistd/execve.c b/mentos/src/libc/unistd/execve.c index c0351ee..760197f 100644 --- a/mentos/src/libc/unistd/execve.c +++ b/mentos/src/libc/unistd/execve.c @@ -1,24 +1,24 @@ -/// MentOS, The Mentoring Operating system project -/// @file execve.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "errno.h" -#include "syscall.h" - -int execve(const char *path, char *const argv[], char *const envp[]) -{ - ssize_t retval; - - DEFN_SYSCALL3(retval, __NR_execve, path, argv, envp); - - if (retval < 0) - { - errno = -retval; - retval = -1; - } - - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file execve.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "errno.h" +#include "syscall.h" + +int execve(const char *path, char *const argv[], char *const envp[]) +{ + ssize_t retval; + + DEFN_SYSCALL3(retval, __NR_execve, path, argv, envp); + + if (retval < 0) + { + errno = -retval; + retval = -1; + } + + return retval; +} diff --git a/mentos/src/libc/unistd/exit.c b/mentos/src/libc/unistd/exit.c index aa8a3f5..8673c0b 100644 --- a/mentos/src/libc/unistd/exit.c +++ b/mentos/src/libc/unistd/exit.c @@ -1,17 +1,17 @@ -/// MentOS, The Mentoring Operating system project -/// @file exit.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "types.h" -#include "syscall.h" - -void exit(int status) { - int _res; - - DEFN_SYSCALL1(_res, __NR_exit, status); - - // The process never returns from this system call! -} +/// MentOS, The Mentoring Operating system project +/// @file exit.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "types.h" +#include "syscall.h" + +void exit(int status) { + int _res; + + DEFN_SYSCALL1(_res, __NR_exit, status); + + // The process never returns from this system call! +} diff --git a/mentos/src/libc/unistd/getcwd.c b/mentos/src/libc/unistd/getcwd.c index 2e2ad1b..74617b3 100644 --- a/mentos/src/libc/unistd/getcwd.c +++ b/mentos/src/libc/unistd/getcwd.c @@ -1,19 +1,19 @@ -/// MentOS, The Mentoring Operating system project -/// @file getcwd.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "syscall.h" -#include "errno.h" - -void getcwd(char * path, size_t size) -{ - ssize_t retval; - DEFN_SYSCALL2(retval, __NR_getcwd, path, size); - if (retval < 0) - { - errno = -retval; - } -} +/// MentOS, The Mentoring Operating system project +/// @file getcwd.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "syscall.h" +#include "errno.h" + +void getcwd(char * path, size_t size) +{ + ssize_t retval; + DEFN_SYSCALL2(retval, __NR_getcwd, path, size); + if (retval < 0) + { + errno = -retval; + } +} diff --git a/mentos/src/libc/unistd/getpid.c b/mentos/src/libc/unistd/getpid.c index c1059b8..0c2074c 100644 --- a/mentos/src/libc/unistd/getpid.c +++ b/mentos/src/libc/unistd/getpid.c @@ -1,19 +1,19 @@ -/// MentOS, The Mentoring Operating system project -/// @file getpid.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" - -#include "syscall.h" -#include "types.h" - -pid_t getpid() -{ - pid_t ret; - - DEFN_SYSCALL0(ret, __NR_getpid); - - return ret; -} +/// MentOS, The Mentoring Operating system project +/// @file getpid.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" + +#include "syscall.h" +#include "types.h" + +pid_t getpid() +{ + pid_t ret; + + DEFN_SYSCALL0(ret, __NR_getpid); + + return ret; +} diff --git a/mentos/src/libc/unistd/getppid.c b/mentos/src/libc/unistd/getppid.c index c881377..0de3c69 100644 --- a/mentos/src/libc/unistd/getppid.c +++ b/mentos/src/libc/unistd/getppid.c @@ -1,18 +1,18 @@ -/// MentOS, The Mentoring Operating system project -/// @file getppid.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "types.h" -#include "syscall.h" - -pid_t getppid() -{ - pid_t ret; - - DEFN_SYSCALL0(ret, __NR_getppid); - - return ret; -} +/// MentOS, The Mentoring Operating system project +/// @file getppid.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "types.h" +#include "syscall.h" + +pid_t getppid() +{ + pid_t ret; + + DEFN_SYSCALL0(ret, __NR_getppid); + + return ret; +} diff --git a/mentos/src/libc/unistd/mkdir.c b/mentos/src/libc/unistd/mkdir.c index 6ccad7a..fa3addb 100644 --- a/mentos/src/libc/unistd/mkdir.c +++ b/mentos/src/libc/unistd/mkdir.c @@ -1,21 +1,21 @@ -/// MentOS, The Mentoring Operating system project -/// @file mkdir.c -/// @brief Make directory functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "syscall.h" -#include "unistd.h" -#include "errno.h" -#include "stat.h" - -int mkdir(const char *path, mode_t mode) -{ - ssize_t retval; - DEFN_SYSCALL2(retval, __NR_mkdir, path, mode); - if (retval < 0) { - errno = -retval; - retval = -1; - } - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file mkdir.c +/// @brief Make directory functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "syscall.h" +#include "unistd.h" +#include "errno.h" +#include "stat.h" + +int mkdir(const char *path, mode_t mode) +{ + ssize_t retval; + DEFN_SYSCALL2(retval, __NR_mkdir, path, mode); + if (retval < 0) { + errno = -retval; + retval = -1; + } + return retval; +} diff --git a/mentos/src/libc/unistd/nice.c b/mentos/src/libc/unistd/nice.c index dd6d8c9..52d2066 100644 --- a/mentos/src/libc/unistd/nice.c +++ b/mentos/src/libc/unistd/nice.c @@ -1,17 +1,17 @@ -/// MentOS, The Mentoring Operating system project -/// @file nice.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "syscall.h" - -int nice(int inc) -{ - ssize_t _res; - - DEFN_SYSCALL1(_res, __NR_nice, inc); - - return _res; -} +/// MentOS, The Mentoring Operating system project +/// @file nice.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "syscall.h" + +int nice(int inc) +{ + ssize_t _res; + + DEFN_SYSCALL1(_res, __NR_nice, inc); + + return _res; +} diff --git a/mentos/src/libc/unistd/open.c b/mentos/src/libc/unistd/open.c index 20b1e71..651bde9 100644 --- a/mentos/src/libc/unistd/open.c +++ b/mentos/src/libc/unistd/open.c @@ -1,22 +1,22 @@ -/// MentOS, The Mentoring Operating system project -/// @file open.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "errno.h" -#include "syscall.h" - -int open(const char *pathname, int flags, mode_t mode) -{ - ssize_t retval; - - DEFN_SYSCALL3(retval, __NR_open, pathname, flags, mode); - - if (retval < 0) { - errno = -retval; - retval = -1; - } - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file open.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "errno.h" +#include "syscall.h" + +int open(const char *pathname, int flags, mode_t mode) +{ + ssize_t retval; + + DEFN_SYSCALL3(retval, __NR_open, pathname, flags, mode); + + if (retval < 0) { + errno = -retval; + retval = -1; + } + return retval; +} diff --git a/mentos/src/libc/unistd/read.c b/mentos/src/libc/unistd/read.c index 396dafa..df3ebae 100644 --- a/mentos/src/libc/unistd/read.c +++ b/mentos/src/libc/unistd/read.c @@ -1,23 +1,23 @@ -/// MentOS, The Mentoring Operating system project -/// @file read.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "errno.h" -#include "syscall.h" - -ssize_t read(int fd, void *buf, size_t nbytes) -{ - ssize_t retval; - - DEFN_SYSCALL3(retval, __NR_read, fd, buf, nbytes); - - if (retval < 0) { - errno = -retval; - retval = -1; - } - - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file read.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "errno.h" +#include "syscall.h" + +ssize_t read(int fd, void *buf, size_t nbytes) +{ + ssize_t retval; + + DEFN_SYSCALL3(retval, __NR_read, fd, buf, nbytes); + + if (retval < 0) { + errno = -retval; + retval = -1; + } + + return retval; +} diff --git a/mentos/src/libc/unistd/reboot.c b/mentos/src/libc/unistd/reboot.c index f1e347d..6e48606 100644 --- a/mentos/src/libc/unistd/reboot.c +++ b/mentos/src/libc/unistd/reboot.c @@ -1,23 +1,23 @@ -/// MentOS, The Mentoring Operating system project -/// @file reboot.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "errno.h" -#include "syscall.h" - -int reboot(int magic1, int magic2, unsigned int cmd, void *arg) -{ - ssize_t retval; - - DEFN_SYSCALL4(retval, __NR_reboot, magic1, magic2, cmd, arg); - - if (retval < 0) { - errno = -retval; - retval = -1; - } - - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file reboot.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "errno.h" +#include "syscall.h" + +int reboot(int magic1, int magic2, unsigned int cmd, void *arg) +{ + ssize_t retval; + + DEFN_SYSCALL4(retval, __NR_reboot, magic1, magic2, cmd, arg); + + if (retval < 0) { + errno = -retval; + retval = -1; + } + + return retval; +} diff --git a/mentos/src/libc/unistd/stat.c b/mentos/src/libc/unistd/stat.c index d301501..6669823 100644 --- a/mentos/src/libc/unistd/stat.c +++ b/mentos/src/libc/unistd/stat.c @@ -1,21 +1,21 @@ -/// MentOS, The Mentoring Operating system project -/// @file stat.c -/// @brief Stat functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "syscall.h" -#include "unistd.h" -#include "errno.h" -#include "stat.h" - -int stat(const char *path, stat_t *buf) -{ - ssize_t retval; - DEFN_SYSCALL2(retval, __NR_stat, path, buf); - if (retval < 0) { - errno = -retval; - retval = -1; - } - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file stat.c +/// @brief Stat functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "syscall.h" +#include "unistd.h" +#include "errno.h" +#include "stat.h" + +int stat(const char *path, stat_t *buf) +{ + ssize_t retval; + DEFN_SYSCALL2(retval, __NR_stat, path, buf); + if (retval < 0) { + errno = -retval; + retval = -1; + } + return retval; +} diff --git a/mentos/src/libc/unistd/vfork.c b/mentos/src/libc/unistd/vfork.c index f6c4f18..c37efb7 100644 --- a/mentos/src/libc/unistd/vfork.c +++ b/mentos/src/libc/unistd/vfork.c @@ -1,26 +1,26 @@ -/// MentOS, The Mentoring Operating system project -/// @file vfork.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "types.h" -#include "errno.h" -#include "syscall.h" -#include -#include -#include - -pid_t vfork() -{ - pid_t retval = 0; - - DEFN_SYSCALL0(retval, __NR_vfork); - - if (retval < 0) { - errno = -retval; - retval = -1; - } - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file vfork.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "types.h" +#include "errno.h" +#include "syscall.h" +#include +#include +#include + +pid_t vfork() +{ + pid_t retval = 0; + + DEFN_SYSCALL0(retval, __NR_vfork); + + if (retval < 0) { + errno = -retval; + retval = -1; + } + return retval; +} diff --git a/mentos/src/libc/unistd/waitpid.c b/mentos/src/libc/unistd/waitpid.c index 04320ec..79e0850 100644 --- a/mentos/src/libc/unistd/waitpid.c +++ b/mentos/src/libc/unistd/waitpid.c @@ -1,41 +1,41 @@ -/// MentOS, The Mentoring Operating system project -/// @file waitpid.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "wait.h" -#include "errno.h" -#include "syscall.h" -#include "scheduler.h" - -pid_t wait(int *status) -{ - return waitpid(-1, status, 0); -} - -pid_t waitpid(pid_t pid, int *status, int options) -{ - pid_t retval; - - int _status = 0, *_status_ptr = &_status; - - do - { - DEFN_SYSCALL3(retval, __NR_waitpid, pid, _status_ptr, options); - } while (((*_status_ptr) != EXIT_ZOMBIE) && !(options && WNOHANG)); - - if (status != NULL) - { - (*status) = (*_status_ptr); - } - - if (retval < 0) - { - errno = -retval; - retval = -1; - } - - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file waitpid.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "wait.h" +#include "errno.h" +#include "syscall.h" +#include "scheduler.h" + +pid_t wait(int *status) +{ + return waitpid(-1, status, 0); +} + +pid_t waitpid(pid_t pid, int *status, int options) +{ + pid_t retval; + + int _status = 0, *_status_ptr = &_status; + + do + { + DEFN_SYSCALL3(retval, __NR_waitpid, pid, _status_ptr, options); + } while (((*_status_ptr) != EXIT_ZOMBIE) && !(options && WNOHANG)); + + if (status != NULL) + { + (*status) = (*_status_ptr); + } + + if (retval < 0) + { + errno = -retval; + retval = -1; + } + + return retval; +} diff --git a/mentos/src/libc/unistd/write.c b/mentos/src/libc/unistd/write.c index 50c994f..6ee4061 100644 --- a/mentos/src/libc/unistd/write.c +++ b/mentos/src/libc/unistd/write.c @@ -1,25 +1,25 @@ -/// MentOS, The Mentoring Operating system project -/// @file write.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" -#include "errno.h" -#include "syscall.h" - -ssize_t write(int fd, void *buf, size_t nbytes) -{ - ssize_t retval; - - DEFN_SYSCALL3(retval, __NR_write, fd, buf, nbytes); - - if (retval < 0) - { - errno = -retval; - retval = -1; - - } - - return retval; -} +/// MentOS, The Mentoring Operating system project +/// @file write.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" +#include "errno.h" +#include "syscall.h" + +ssize_t write(int fd, void *buf, size_t nbytes) +{ + ssize_t retval; + + DEFN_SYSCALL3(retval, __NR_write, fd, buf, nbytes); + + if (retval < 0) + { + errno = -retval; + retval = -1; + + } + + return retval; +} diff --git a/mentos/src/libc/vsprintf.c b/mentos/src/libc/vsprintf.c index 92554d3..2fa5205 100644 --- a/mentos/src/libc/vsprintf.c +++ b/mentos/src/libc/vsprintf.c @@ -1,787 +1,787 @@ -/// MentOS, The Mentoring Operating system project -/// @file vsprintf.c -/// @brief Print formatting routines. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "math.h" -#include "fcvt.h" -#include "ctype.h" -#include "string.h" -#include "stdarg.h" -#include "stdbool.h" - -#define CVTBUFSIZE 500 - -#define FLAGS_ZEROPAD (1U << 0U) -#define FLAGS_LEFT (1U << 1U) -#define FLAGS_PLUS (1U << 2U) -#define FLAGS_SPACE (1U << 3U) -#define FLAGS_HASH (1U << 4U) -#define FLAGS_UPPERCASE (1U << 5U) -#define FLAGS_SIGN (1U << 6U) - -/* 'ftoa' conversion buffer size, this must be big enough to hold one converted - * float number including padded zeros (dynamically created on stack) - * default: 32 byte. - */ -#ifndef PRINTF_FTOA_BUFFER_SIZE -#define PRINTF_FTOA_BUFFER_SIZE 32U -#endif - -/// The list of digits. -static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; - -/// The list of uppercase digits. -static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -/// @brief Returns the index of the first non-integer character. -static int skip_atoi(const char **s) -{ - int i = 0; - do { - i = i * 10 + *((*s)++) - '0'; - } while (isdigit(**s)); - - return i; -} - -#if 0 -char *dtoa(char *str, - double num, - int32_t precision) -{ - // Handle special cases. - if (isnan(num)) - { - strcpy(str, "nan"); - } - else if (isinf(num)) - { - strcpy(str, "inf"); - } - else if (num == 0.0) - { - strcpy(str, "0"); - } - else - { - int digit, m, m1; - char *c = str; - int neg = (num < 0); - if (neg) - { - num = -num; - } - // Calculate magnitude. - m = log10(num); - int useExp = (m >= 14 || (neg && m >= 9) || m <= -9); - if (neg) - { - *(c++) = '-'; - } - // Set up for scientific notation. - if (useExp) - { - if (m < 0) - { - m -= 1.0; - } - num = num / pow(10.0, m); - m1 = m; - m = 0; - } - if (m < 1.0) - { - m = 0; - } - // Convert the number. - while (num > precision || m >= 0) - { - double weight = pow(10.0, m); - if (weight > 0 && !isinf(weight)) - { - digit = floor(num / weight); - num -= (digit * weight); - *(c++) = '0' + digit; - } - if (m == 0 && num > 0) - *(c++) = '.'; - m--; - } - if (useExp) - { - // Convert the exponent. - int i, j; - *(c++) = 'e'; - if (m1 > 0) - { - *(c++) = '+'; - } - else - { - *(c++) = '-'; - m1 = -m1; - } - m = 0; - while (m1 > 0) - { - *(c++) = '0' + m1 % 10; - m1 /= 10; - m++; - } - c -= m; - for (i = 0, j = m - 1; i < j; i++, j--) - { - // Swap without temporary. - c[i] ^= c[j]; - c[j] ^= c[i]; - c[i] ^= c[j]; - } - c += m; - } - *(c) = '\0'; - } - - return str; -} -#endif - -static char *number(char *str, long num, int base, int size, int32_t precision, - int type) -{ - char c, tmp[66]; - char *dig = digits; - - if (type & FLAGS_UPPERCASE) { - dig = upper_digits; - } - if (type & FLAGS_LEFT) { - type &= ~FLAGS_ZEROPAD; - } - if (base < 2 || base > 36) { - return 0; - } - - c = (type & FLAGS_ZEROPAD) ? '0' : ' '; - - // -------------------------------- - // Set the sign. - // -------------------------------- - char sign = 0; - if (type & FLAGS_SIGN) { - if (num < 0) { - sign = '-'; - num = -num; - size--; - } else if (type & FLAGS_PLUS) { - sign = '+'; - size--; - } else if (type & FLAGS_SPACE) { - sign = ' '; - size--; - } - } - // Sice I've removed the sign (if negative), i can transform it to unsigned. - uint32_t uns_num = (uint32_t)num; - - if (type & FLAGS_HASH) { - if (base == 16) { - size -= 2; - } else if (base == 8) { - size--; - } - } - - int32_t i = 0; - if (uns_num == 0) { - tmp[i++] = '0'; - } else { - while (uns_num != 0) { - tmp[i++] = dig[((unsigned long)uns_num) % (unsigned)base]; - uns_num = ((unsigned long)uns_num) / (unsigned)base; - } - } - - if (i > precision) { - precision = i; - } - size -= precision; - if (!(type & (FLAGS_ZEROPAD | FLAGS_LEFT))) { - while (size-- > 0) - *str++ = ' '; - } - if (sign) { - *str++ = sign; - } - - if (type & FLAGS_HASH) { - if (base == 8) - *str++ = '0'; - else if (base == 16) { - *str++ = '0'; - *str++ = digits[33]; - } - } - - if (!(type & FLAGS_LEFT)) { - while (size-- > 0) { - *str++ = c; - } - } - while (i < precision--) { - *str++ = '0'; - } - while (i-- > 0) { - *str++ = tmp[i]; - } - while (size-- > 0) { - *str++ = ' '; - } - - return str; -} - -static char *eaddr(char *str, unsigned char *addr, int size, int precision, - int type) -{ - (void)precision; - char tmp[24]; - char *dig = digits; - int i, len; - - if (type & FLAGS_UPPERCASE) { - dig = upper_digits; - } - - len = 0; - for (i = 0; i < 6; i++) { - if (i != 0) { - tmp[len++] = ':'; - } - tmp[len++] = dig[addr[i] >> 4]; - tmp[len++] = dig[addr[i] & 0x0F]; - } - - if (!(type & FLAGS_LEFT)) { - while (len < size--) { - *str++ = ' '; - } - } - - for (i = 0; i < len; ++i) { - *str++ = tmp[i]; - } - - while (len < size--) { - *str++ = ' '; - } - - return str; -} - -static char *iaddr(char *str, unsigned char *addr, int size, int precision, - int type) -{ - (void)precision; - char tmp[24]; - int i, n, len; - - len = 0; - for (i = 0; i < 4; i++) { - if (i != 0) { - tmp[len++] = '.'; - } - n = addr[i]; - - if (n == 0) { - tmp[len++] = digits[0]; - } else { - if (n >= 100) { - tmp[len++] = digits[n / 100]; - n = n % 100; - tmp[len++] = digits[n / 10]; - n = n % 10; - } else if (n >= 10) { - tmp[len++] = digits[n / 10]; - n = n % 10; - } - - tmp[len++] = digits[n]; - } - } - - if (!(type & FLAGS_LEFT)) { - while (len < size--) { - *str++ = ' '; - } - } - - for (i = 0; i < len; ++i) { - *str++ = tmp[i]; - } - - while (len < size--) { - *str++ = ' '; - } - - return str; -} - -static void cfltcvt(double value, char *buffer, char fmt, int precision) -{ - int decpt, sign, exp, pos; - char *digits = NULL; - char cvtbuf[CVTBUFSIZE]; - int capexp = 0; - int magnitude; - - if (fmt == 'G' || fmt == 'E') { - capexp = 1; - fmt += 'a' - 'A'; - } - - if (fmt == 'g') { - digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); - magnitude = decpt - 1; - if (magnitude < -4 || magnitude > precision - 1) { - fmt = 'e'; - precision -= 1; - } else { - fmt = 'f'; - precision -= decpt; - } - } - - if (fmt == 'e') { - digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); - - if (sign) { - *buffer++ = '-'; - } - *buffer++ = *digits; - if (precision > 0) { - *buffer++ = '.'; - } - memcpy(buffer, digits + 1, precision); - buffer += precision; - *buffer++ = capexp ? 'E' : 'e'; - - if (decpt == 0) { - if (value == 0.0) { - exp = 0; - } else { - exp = -1; - } - } else { - exp = decpt - 1; - } - - if (exp < 0) { - *buffer++ = '-'; - exp = -exp; - } else { - *buffer++ = '+'; - } - - buffer[2] = (char)((exp % 10) + '0'); - exp = exp / 10; - buffer[1] = (char)((exp % 10) + '0'); - exp = exp / 10; - buffer[0] = (char)((exp % 10) + '0'); - buffer += 3; - } else if (fmt == 'f') { - digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); - if (sign) { - *buffer++ = '-'; - } - if (*digits) { - if (decpt <= 0) { - *buffer++ = '0'; - *buffer++ = '.'; - for (pos = 0; pos < -decpt; pos++) { - *buffer++ = '0'; - } - while (*digits) { - *buffer++ = *digits++; - } - } else { - pos = 0; - while (*digits) { - if (pos++ == decpt) { - *buffer++ = '.'; - } - *buffer++ = *digits++; - } - } - } else { - *buffer++ = '0'; - if (precision > 0) { - *buffer++ = '.'; - for (pos = 0; pos < precision; pos++) { - *buffer++ = '0'; - } - } - } - } - - *buffer = '\0'; -} - -static void forcdecpt(char *buffer) -{ - while (*buffer) { - if (*buffer == '.') { - return; - } - if (*buffer == 'e' || *buffer == 'E') { - break; - } - - buffer++; - } - - if (*buffer) { - long n = (long)strlen(buffer); - while (n > 0) { - buffer[n + 1] = buffer[n]; - n--; - } - *buffer = '.'; - } else { - *buffer++ = '.'; - *buffer = '\0'; - } -} - -static void cropzeros(char *buffer) -{ - char *stop; - - while (*buffer && *buffer != '.') { - buffer++; - } - - if (*buffer++) { - while (*buffer && *buffer != 'e' && *buffer != 'E') { - buffer++; - } - stop = buffer--; - while (*buffer == '0') { - buffer--; - } - if (*buffer == '.') { - buffer--; - } - while ((*++buffer = *stop++)) - ; - } -} - -static char *flt(char *str, double num, int size, int precision, char fmt, - int flags) -{ - char tmp[80]; - char c, sign; - int n, i; - - // Left align means no zero padding. - if (flags & FLAGS_LEFT) - flags &= ~FLAGS_ZEROPAD; - - // Determine padding and sign char. - c = (flags & FLAGS_ZEROPAD) ? '0' : ' '; - sign = 0; - if (flags & FLAGS_SIGN) { - if (num < 0.0) { - sign = '-'; - num = -num; - size--; - } else if (flags & FLAGS_PLUS) { - sign = '+'; - size--; - } else if (flags & FLAGS_SPACE) { - sign = ' '; - size--; - } - } - - // Compute the precision value. - if (precision < 0) { - // Default precision: 6. - precision = 6; - } else if (precision == 0 && fmt == 'g') { - // ANSI specified. - precision = 1; - } - - // Convert floating point number to text. - cfltcvt(num, tmp, fmt, precision); - - // '#' and precision == 0 means force a decimal point. - if ((flags & FLAGS_HASH) && precision == 0) { - forcdecpt(tmp); - } - - // 'g' format means crop zero unless '#' given. - if (fmt == 'g' && !(flags & FLAGS_HASH)) { - cropzeros(tmp); - } - - n = strlen(tmp); - - // Output number with alignment and padding. - size -= n; - if (!(flags & (FLAGS_ZEROPAD | FLAGS_LEFT))) { - while (size-- > 0) { - *str++ = ' '; - } - } - - if (sign) { - *str++ = sign; - } - - if (!(flags & FLAGS_LEFT)) { - while (size-- > 0) { - *str++ = c; - } - } - - for (i = 0; i < n; i++) { - *str++ = tmp[i]; - } - - while (size-- > 0) { - *str++ = ' '; - } - - return str; -} - -int vsprintf(char *str, const char *fmt, va_list args) -{ - int base; - char *tmp; - char *s; - - // Flags to number(). - int flags; - - // 'h', 'l', or 'L' for integer fields. - int qualifier; - - for (tmp = str; *fmt; fmt++) { - if (*fmt != '%') { - *tmp++ = *fmt; - - continue; - } - - // Process flags- - flags = 0; - repeat: - // This also skips first '%'. - fmt++; - switch (*fmt) { - case '-': - flags |= FLAGS_LEFT; - goto repeat; - case '+': - flags |= FLAGS_PLUS; - goto repeat; - case ' ': - flags |= FLAGS_SPACE; - goto repeat; - case '#': - flags |= FLAGS_HASH; - goto repeat; - case '0': - flags |= FLAGS_ZEROPAD; - goto repeat; - } - - // Get the width of the output field. - int32_t field_width; - field_width = -1; - - if (isdigit(*fmt)) { - field_width = skip_atoi(&fmt); - } else if (*fmt == '*') { - fmt++; - field_width = va_arg(args, int32_t); - if (field_width < 0) { - field_width = -field_width; - flags |= FLAGS_LEFT; - } - } - - /* Get the precision, thus the minimum number of digits for - * integers; max number of chars for from string. - */ - int32_t precision = -1; - if (*fmt == '.') { - ++fmt; - if (isdigit(*fmt)) { - precision = skip_atoi(&fmt); - } else if (*fmt == '*') { - ++fmt; - precision = va_arg(args, int); - } - if (precision < 0) { - precision = 0; - } - } - - // Get the conversion qualifier. - qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { - qualifier = *fmt; - fmt++; - } - - // Default base. - base = 10; - - switch (*fmt) { - case 'c': - if (!(flags & FLAGS_LEFT)) { - while (--field_width > 0) { - *tmp++ = ' '; - } - } - *tmp++ = va_arg(args, char); - while (--field_width > 0) { - *tmp++ = ' '; - } - continue; - - case 's': - s = va_arg(args, char *); - if (!s) { - s = ""; - } - - int32_t len = (int32_t)strnlen(s, (uint32_t)precision); - if (!(flags & FLAGS_LEFT)) { - while (len < field_width--) { - *tmp++ = ' '; - } - } - - int32_t it; - for (it = 0; it < len; ++it) { - *tmp++ = *s++; - } - while (len < field_width--) { - *tmp++ = ' '; - } - continue; - - case 'p': - if (field_width == -1) { - field_width = 2 * sizeof(void *); - flags |= FLAGS_ZEROPAD; - } - tmp = number(tmp, (unsigned long)va_arg(args, void *), 16, - field_width, precision, flags); - continue; - - case 'n': - if (qualifier == 'l') { - long *ip = va_arg(args, long *); - *ip = (tmp - str); - } else { - int *ip = va_arg(args, int *); - *ip = (tmp - str); - } - continue; - - case 'A': - flags |= FLAGS_UPPERCASE; - break; - - case 'a': - if (qualifier == 'l') - tmp = eaddr(tmp, va_arg(args, unsigned char *), field_width, - precision, flags); - else - tmp = iaddr(tmp, va_arg(args, unsigned char *), field_width, - precision, flags); - continue; - - // Integer number formats - set up the flags and "break". - case 'o': - base = 8; - break; - - case 'X': - flags |= FLAGS_UPPERCASE; - break; - - case 'x': - base = 16; - break; - - case 'd': - case 'i': - flags |= FLAGS_SIGN; - - case 'u': - break; - case 'E': - case 'G': - case 'e': - case 'f': - case 'g': - tmp = flt(tmp, va_arg(args, double), field_width, precision, *fmt, - flags | FLAGS_SIGN); - continue; - default: - if (*fmt != '%') - *tmp++ = '%'; - if (*fmt) - *tmp++ = *fmt; - else - --fmt; - continue; - } - - if (flags & FLAGS_SIGN) { - long num; - if (qualifier == 'l') { - num = va_arg(args, long); - } else if (qualifier == 'h') { - num = va_arg(args, short); - } else { - num = va_arg(args, int); - } - tmp = number(tmp, num, base, field_width, precision, flags); - } else { - unsigned long num; - if (qualifier == 'l') { - num = va_arg(args, unsigned long); - } else if (qualifier == 'h') { - num = va_arg(args, unsigned short); - } else { - num = va_arg(args, unsigned int); - } - tmp = number(tmp, num, base, field_width, precision, flags); - } - } - - *tmp = '\0'; - return tmp - str; -} - -int sprintf(char *str, const char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(str, fmt, args); - va_end(args); - - return n; -} +/// MentOS, The Mentoring Operating system project +/// @file vsprintf.c +/// @brief Print formatting routines. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "math.h" +#include "fcvt.h" +#include "ctype.h" +#include "string.h" +#include "stdarg.h" +#include "stdbool.h" + +#define CVTBUFSIZE 500 + +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_SIGN (1U << 6U) + +/* 'ftoa' conversion buffer size, this must be big enough to hold one converted + * float number including padded zeros (dynamically created on stack) + * default: 32 byte. + */ +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +/// The list of digits. +static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + +/// The list of uppercase digits. +static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +/// @brief Returns the index of the first non-integer character. +static int skip_atoi(const char **s) +{ + int i = 0; + do { + i = i * 10 + *((*s)++) - '0'; + } while (isdigit(**s)); + + return i; +} + +#if 0 +char *dtoa(char *str, + double num, + int32_t precision) +{ + // Handle special cases. + if (isnan(num)) + { + strcpy(str, "nan"); + } + else if (isinf(num)) + { + strcpy(str, "inf"); + } + else if (num == 0.0) + { + strcpy(str, "0"); + } + else + { + int digit, m, m1; + char *c = str; + int neg = (num < 0); + if (neg) + { + num = -num; + } + // Calculate magnitude. + m = log10(num); + int useExp = (m >= 14 || (neg && m >= 9) || m <= -9); + if (neg) + { + *(c++) = '-'; + } + // Set up for scientific notation. + if (useExp) + { + if (m < 0) + { + m -= 1.0; + } + num = num / pow(10.0, m); + m1 = m; + m = 0; + } + if (m < 1.0) + { + m = 0; + } + // Convert the number. + while (num > precision || m >= 0) + { + double weight = pow(10.0, m); + if (weight > 0 && !isinf(weight)) + { + digit = floor(num / weight); + num -= (digit * weight); + *(c++) = '0' + digit; + } + if (m == 0 && num > 0) + *(c++) = '.'; + m--; + } + if (useExp) + { + // Convert the exponent. + int i, j; + *(c++) = 'e'; + if (m1 > 0) + { + *(c++) = '+'; + } + else + { + *(c++) = '-'; + m1 = -m1; + } + m = 0; + while (m1 > 0) + { + *(c++) = '0' + m1 % 10; + m1 /= 10; + m++; + } + c -= m; + for (i = 0, j = m - 1; i < j; i++, j--) + { + // Swap without temporary. + c[i] ^= c[j]; + c[j] ^= c[i]; + c[i] ^= c[j]; + } + c += m; + } + *(c) = '\0'; + } + + return str; +} +#endif + +static char *number(char *str, long num, int base, int size, int32_t precision, + int type) +{ + char c, tmp[66]; + char *dig = digits; + + if (type & FLAGS_UPPERCASE) { + dig = upper_digits; + } + if (type & FLAGS_LEFT) { + type &= ~FLAGS_ZEROPAD; + } + if (base < 2 || base > 36) { + return 0; + } + + c = (type & FLAGS_ZEROPAD) ? '0' : ' '; + + // -------------------------------- + // Set the sign. + // -------------------------------- + char sign = 0; + if (type & FLAGS_SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & FLAGS_PLUS) { + sign = '+'; + size--; + } else if (type & FLAGS_SPACE) { + sign = ' '; + size--; + } + } + // Sice I've removed the sign (if negative), i can transform it to unsigned. + uint32_t uns_num = (uint32_t)num; + + if (type & FLAGS_HASH) { + if (base == 16) { + size -= 2; + } else if (base == 8) { + size--; + } + } + + int32_t i = 0; + if (uns_num == 0) { + tmp[i++] = '0'; + } else { + while (uns_num != 0) { + tmp[i++] = dig[((unsigned long)uns_num) % (unsigned)base]; + uns_num = ((unsigned long)uns_num) / (unsigned)base; + } + } + + if (i > precision) { + precision = i; + } + size -= precision; + if (!(type & (FLAGS_ZEROPAD | FLAGS_LEFT))) { + while (size-- > 0) + *str++ = ' '; + } + if (sign) { + *str++ = sign; + } + + if (type & FLAGS_HASH) { + if (base == 8) + *str++ = '0'; + else if (base == 16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & FLAGS_LEFT)) { + while (size-- > 0) { + *str++ = c; + } + } + while (i < precision--) { + *str++ = '0'; + } + while (i-- > 0) { + *str++ = tmp[i]; + } + while (size-- > 0) { + *str++ = ' '; + } + + return str; +} + +static char *eaddr(char *str, unsigned char *addr, int size, int precision, + int type) +{ + (void)precision; + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & FLAGS_UPPERCASE) { + dig = upper_digits; + } + + len = 0; + for (i = 0; i < 6; i++) { + if (i != 0) { + tmp[len++] = ':'; + } + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & FLAGS_LEFT)) { + while (len < size--) { + *str++ = ' '; + } + } + + for (i = 0; i < len; ++i) { + *str++ = tmp[i]; + } + + while (len < size--) { + *str++ = ' '; + } + + return str; +} + +static char *iaddr(char *str, unsigned char *addr, int size, int precision, + int type) +{ + (void)precision; + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) { + if (i != 0) { + tmp[len++] = '.'; + } + n = addr[i]; + + if (n == 0) { + tmp[len++] = digits[0]; + } else { + if (n >= 100) { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } else if (n >= 10) { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & FLAGS_LEFT)) { + while (len < size--) { + *str++ = ' '; + } + } + + for (i = 0; i < len; ++i) { + *str++ = tmp[i]; + } + + while (len < size--) { + *str++ = ' '; + } + + return str; +} + +static void cfltcvt(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[CVTBUFSIZE]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) { + fmt = 'e'; + precision -= 1; + } else { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) { + *buffer++ = '-'; + } + *buffer++ = *digits; + if (precision > 0) { + *buffer++ = '.'; + } + memcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) { + if (value == 0.0) { + exp = 0; + } else { + exp = -1; + } + } else { + exp = decpt - 1; + } + + if (exp < 0) { + *buffer++ = '-'; + exp = -exp; + } else { + *buffer++ = '+'; + } + + buffer[2] = (char)((exp % 10) + '0'); + exp = exp / 10; + buffer[1] = (char)((exp % 10) + '0'); + exp = exp / 10; + buffer[0] = (char)((exp % 10) + '0'); + buffer += 3; + } else if (fmt == 'f') { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) { + *buffer++ = '-'; + } + if (*digits) { + if (decpt <= 0) { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) { + *buffer++ = '0'; + } + while (*digits) { + *buffer++ = *digits++; + } + } else { + pos = 0; + while (*digits) { + if (pos++ == decpt) { + *buffer++ = '.'; + } + *buffer++ = *digits++; + } + } + } else { + *buffer++ = '0'; + if (precision > 0) { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) { + *buffer++ = '0'; + } + } + } + } + + *buffer = '\0'; +} + +static void forcdecpt(char *buffer) +{ + while (*buffer) { + if (*buffer == '.') { + return; + } + if (*buffer == 'e' || *buffer == 'E') { + break; + } + + buffer++; + } + + if (*buffer) { + long n = (long)strlen(buffer); + while (n > 0) { + buffer[n + 1] = buffer[n]; + n--; + } + *buffer = '.'; + } else { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') { + buffer++; + } + + if (*buffer++) { + while (*buffer && *buffer != 'e' && *buffer != 'E') { + buffer++; + } + stop = buffer--; + while (*buffer == '0') { + buffer--; + } + if (*buffer == '.') { + buffer--; + } + while ((*++buffer = *stop++)) + ; + } +} + +static char *flt(char *str, double num, int size, int precision, char fmt, + int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding. + if (flags & FLAGS_LEFT) + flags &= ~FLAGS_ZEROPAD; + + // Determine padding and sign char. + c = (flags & FLAGS_ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & FLAGS_SIGN) { + if (num < 0.0) { + sign = '-'; + num = -num; + size--; + } else if (flags & FLAGS_PLUS) { + sign = '+'; + size--; + } else if (flags & FLAGS_SPACE) { + sign = ' '; + size--; + } + } + + // Compute the precision value. + if (precision < 0) { + // Default precision: 6. + precision = 6; + } else if (precision == 0 && fmt == 'g') { + // ANSI specified. + precision = 1; + } + + // Convert floating point number to text. + cfltcvt(num, tmp, fmt, precision); + + // '#' and precision == 0 means force a decimal point. + if ((flags & FLAGS_HASH) && precision == 0) { + forcdecpt(tmp); + } + + // 'g' format means crop zero unless '#' given. + if (fmt == 'g' && !(flags & FLAGS_HASH)) { + cropzeros(tmp); + } + + n = strlen(tmp); + + // Output number with alignment and padding. + size -= n; + if (!(flags & (FLAGS_ZEROPAD | FLAGS_LEFT))) { + while (size-- > 0) { + *str++ = ' '; + } + } + + if (sign) { + *str++ = sign; + } + + if (!(flags & FLAGS_LEFT)) { + while (size-- > 0) { + *str++ = c; + } + } + + for (i = 0; i < n; i++) { + *str++ = tmp[i]; + } + + while (size-- > 0) { + *str++ = ' '; + } + + return str; +} + +int vsprintf(char *str, const char *fmt, va_list args) +{ + int base; + char *tmp; + char *s; + + // Flags to number(). + int flags; + + // 'h', 'l', or 'L' for integer fields. + int qualifier; + + for (tmp = str; *fmt; fmt++) { + if (*fmt != '%') { + *tmp++ = *fmt; + + continue; + } + + // Process flags- + flags = 0; + repeat: + // This also skips first '%'. + fmt++; + switch (*fmt) { + case '-': + flags |= FLAGS_LEFT; + goto repeat; + case '+': + flags |= FLAGS_PLUS; + goto repeat; + case ' ': + flags |= FLAGS_SPACE; + goto repeat; + case '#': + flags |= FLAGS_HASH; + goto repeat; + case '0': + flags |= FLAGS_ZEROPAD; + goto repeat; + } + + // Get the width of the output field. + int32_t field_width; + field_width = -1; + + if (isdigit(*fmt)) { + field_width = skip_atoi(&fmt); + } else if (*fmt == '*') { + fmt++; + field_width = va_arg(args, int32_t); + if (field_width < 0) { + field_width = -field_width; + flags |= FLAGS_LEFT; + } + } + + /* Get the precision, thus the minimum number of digits for + * integers; max number of chars for from string. + */ + int32_t precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) { + precision = skip_atoi(&fmt); + } else if (*fmt == '*') { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) { + precision = 0; + } + } + + // Get the conversion qualifier. + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + fmt++; + } + + // Default base. + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & FLAGS_LEFT)) { + while (--field_width > 0) { + *tmp++ = ' '; + } + } + *tmp++ = va_arg(args, char); + while (--field_width > 0) { + *tmp++ = ' '; + } + continue; + + case 's': + s = va_arg(args, char *); + if (!s) { + s = ""; + } + + int32_t len = (int32_t)strnlen(s, (uint32_t)precision); + if (!(flags & FLAGS_LEFT)) { + while (len < field_width--) { + *tmp++ = ' '; + } + } + + int32_t it; + for (it = 0; it < len; ++it) { + *tmp++ = *s++; + } + while (len < field_width--) { + *tmp++ = ' '; + } + continue; + + case 'p': + if (field_width == -1) { + field_width = 2 * sizeof(void *); + flags |= FLAGS_ZEROPAD; + } + tmp = number(tmp, (unsigned long)va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + case 'n': + if (qualifier == 'l') { + long *ip = va_arg(args, long *); + *ip = (tmp - str); + } else { + int *ip = va_arg(args, int *); + *ip = (tmp - str); + } + continue; + + case 'A': + flags |= FLAGS_UPPERCASE; + break; + + case 'a': + if (qualifier == 'l') + tmp = eaddr(tmp, va_arg(args, unsigned char *), field_width, + precision, flags); + else + tmp = iaddr(tmp, va_arg(args, unsigned char *), field_width, + precision, flags); + continue; + + // Integer number formats - set up the flags and "break". + case 'o': + base = 8; + break; + + case 'X': + flags |= FLAGS_UPPERCASE; + break; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= FLAGS_SIGN; + + case 'u': + break; + case 'E': + case 'G': + case 'e': + case 'f': + case 'g': + tmp = flt(tmp, va_arg(args, double), field_width, precision, *fmt, + flags | FLAGS_SIGN); + continue; + default: + if (*fmt != '%') + *tmp++ = '%'; + if (*fmt) + *tmp++ = *fmt; + else + --fmt; + continue; + } + + if (flags & FLAGS_SIGN) { + long num; + if (qualifier == 'l') { + num = va_arg(args, long); + } else if (qualifier == 'h') { + num = va_arg(args, short); + } else { + num = va_arg(args, int); + } + tmp = number(tmp, num, base, field_width, precision, flags); + } else { + unsigned long num; + if (qualifier == 'l') { + num = va_arg(args, unsigned long); + } else if (qualifier == 'h') { + num = va_arg(args, unsigned short); + } else { + num = va_arg(args, unsigned int); + } + tmp = number(tmp, num, base, field_width, precision, flags); + } + } + + *tmp = '\0'; + return tmp - str; +} + +int sprintf(char *str, const char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(str, fmt, args); + va_end(args); + + return n; +} diff --git a/mentos/src/mem/buddysystem.c b/mentos/src/mem/buddysystem.c index ad3dac2..39d41eb 100644 --- a/mentos/src/mem/buddysystem.c +++ b/mentos/src/mem/buddysystem.c @@ -1,173 +1,173 @@ -/// @file buddysystem.c -/// @brief Buddy System. -/// @date Apr 2019. - -#include "buddysystem.h" -#include "debug.h" -#include "assert.h" - -/// @brief Get the buddy index of a page. -/// @param page_idx A page index. -/// @param order The logarithm of the size of the block. -/// @return The page index of the buddy of page. -static unsigned long get_buddy_idx(unsigned long page_idx, unsigned int order) -{ - /* Get the index of the buddy block. - * - * ----------------------- xor ----------------------- - * | page_idx ^ (1UL << order) = buddy_idx | - * | 1 1 0 | - * | 0 1 1 | - * --------------------------------------------------- - * - * If the bit of page_idx that corresponds to the block - * size, is 1, then we have to take the block on the - * left (0), otherwise we have to take the block on the right (1). - */ - unsigned long buddy_idx = page_idx ^ (1UL << order); - - return buddy_idx; -} - - -page_t *bb_alloc_pages(zone_t *zone, unsigned int order) -{ - page_t *page = NULL; - free_area_t *area = NULL; - - // Search for a free_area_t with at least one available block of pages. - unsigned int current_order; - for (current_order = order; current_order < MAX_ORDER; ++current_order) { - // get the free_area_t at index 'current_order' - area = // ... - - // check if area is not empty (is there at least a block here?) - if (!list_head_empty(&/*...*/)) { - goto block_found; - } - } - - // No suitable free block has been found. - return NULL; - -block_found: - // Get a block of pages from the found free_area_t. - // Here we have to manage pages. Recall, free_area_t collects the first - // page_t of each free block of 2^order contiguous page frames. - - page = list_entry(/*...*/); - - // Remove page from the list_head in the found free_area_t. - list_head_del(/*...*/); - - // Set page as taken. - page->_count = // ... - page->private = 0; - - // Decrease the number of free blocks in the found free_area_t. - // ... - - /* We found a block with 2^k page frames to satisfy a request - * of 2^h page frames. If h < k, then we can split the block with 2^k - * pages until it is large 2^h pages, namely k == h. - */ - - // We can exploit size(=2^k) to have at each loop the address the page that - // resides in the midle of the found block. - unsigned int size = 1 << current_order; - while (current_order > order) { - - // At each loop, we have to set free the right half of the found block. - - // Split the block size in half - size = // ... - - // get the address of the page in the midle of the found block. - page_t *buddy = // ... - - // set the order of pages after the buddy page_t (the field 'private') - // ... - - // get the free_area_t collecting blocks with 2^(k-1) page frames - area = // ... - - // add the buddy block in its list of available blocks - // ... - - // Increase the number of free blocks of the free_area_t. - // ... - } - - buddy_system_dump(zone); - - return page; -} - -void bb_free_pages(zone_t *zone, page_t *page, unsigned int order) -{ - // Take the first page descriptor of the zone. - page_t *base = zone->zone_mem_map; - - // Take the page frame index of page compared to the zone. - unsigned long page_idx = page - base; - - // Set the given page as free - page->_count = // ... - - // At each loop, check if the buddy block can be merged with page. - while (order < MAX_ORDER - 1) { - // Get the index of the buddy block of page. - unsigned long buddy_idx = get_buddy_idx(page_idx, order); - // Get the page_t of the buddy block, namely its first page frame. - page_t *buddy = base + buddy_idx; - - // If the buddy is free and it has the same size of page, then - // they can be merged. Otherwise, we can stop the while-loop and insert - // page in the list of free blocks. - - if (!(/*...it is free...*/ && /*...they have the same size...*/)) { - break; - } - - // we are here only if buddy is free and can be merged with page. - - // remove buddy from the list of available blocks in its free_area_t - // .... - - // Decrease the number of free block of the current free_area_t. - // ... - - // buddy no longer represents a free block, so clear the private field. - buddy->private = 0; - - // Update the page index with the index of the coalesced block. - // ... - - order++; - } - - // The coalesced block is the result of the merging procedure. - page_t *coalesced = base + page_idx; - - // Update the field private to set the size. - coalesced->private = // ... - - // Insert the coalesced block in the free_area as available block - // ... - - // Increase the number of free blocks of the free_area. - // ... - - buddy_system_dump(zone); -} - -void buddy_system_dump(zone_t *zone) -{ - // Print free_list's size of each area of the zone. - dbg_print("Zone\t%s\t", zone->name); - for (int order = 0; order < MAX_ORDER; order++) { - free_area_t *area = zone->free_area + order; - dbg_print("%d\t", area->nr_free); - } - dbg_print("\n"); -} +/// @file buddysystem.c +/// @brief Buddy System. +/// @date Apr 2019. + +#include "buddysystem.h" +#include "debug.h" +#include "assert.h" + +/// @brief Get the buddy index of a page. +/// @param page_idx A page index. +/// @param order The logarithm of the size of the block. +/// @return The page index of the buddy of page. +static unsigned long get_buddy_idx(unsigned long page_idx, unsigned int order) +{ + /* Get the index of the buddy block. + * + * ----------------------- xor ----------------------- + * | page_idx ^ (1UL << order) = buddy_idx | + * | 1 1 0 | + * | 0 1 1 | + * --------------------------------------------------- + * + * If the bit of page_idx that corresponds to the block + * size, is 1, then we have to take the block on the + * left (0), otherwise we have to take the block on the right (1). + */ + unsigned long buddy_idx = page_idx ^ (1UL << order); + + return buddy_idx; +} + + +page_t *bb_alloc_pages(zone_t *zone, unsigned int order) +{ + page_t *page = NULL; + free_area_t *area = NULL; + + // Search for a free_area_t with at least one available block of pages. + unsigned int current_order; + for (current_order = order; current_order < MAX_ORDER; ++current_order) { + // get the free_area_t at index 'current_order' + area = // ... + + // check if area is not empty (is there at least a block here?) + if (!list_head_empty(&/*...*/)) { + goto block_found; + } + } + + // No suitable free block has been found. + return NULL; + +block_found: + // Get a block of pages from the found free_area_t. + // Here we have to manage pages. Recall, free_area_t collects the first + // page_t of each free block of 2^order contiguous page frames. + + page = list_entry(/*...*/); + + // Remove page from the list_head in the found free_area_t. + list_head_del(/*...*/); + + // Set page as taken. + page->_count = // ... + page->private = 0; + + // Decrease the number of free blocks in the found free_area_t. + // ... + + /* We found a block with 2^k page frames to satisfy a request + * of 2^h page frames. If h < k, then we can split the block with 2^k + * pages until it is large 2^h pages, namely k == h. + */ + + // We can exploit size(=2^k) to have at each loop the address the page that + // resides in the midle of the found block. + unsigned int size = 1 << current_order; + while (current_order > order) { + + // At each loop, we have to set free the right half of the found block. + + // Split the block size in half + size = // ... + + // get the address of the page in the midle of the found block. + page_t *buddy = // ... + + // set the order of pages after the buddy page_t (the field 'private') + // ... + + // get the free_area_t collecting blocks with 2^(k-1) page frames + area = // ... + + // add the buddy block in its list of available blocks + // ... + + // Increase the number of free blocks of the free_area_t. + // ... + } + + buddy_system_dump(zone); + + return page; +} + +void bb_free_pages(zone_t *zone, page_t *page, unsigned int order) +{ + // Take the first page descriptor of the zone. + page_t *base = zone->zone_mem_map; + + // Take the page frame index of page compared to the zone. + unsigned long page_idx = page - base; + + // Set the given page as free + page->_count = // ... + + // At each loop, check if the buddy block can be merged with page. + while (order < MAX_ORDER - 1) { + // Get the index of the buddy block of page. + unsigned long buddy_idx = get_buddy_idx(page_idx, order); + // Get the page_t of the buddy block, namely its first page frame. + page_t *buddy = base + buddy_idx; + + // If the buddy is free and it has the same size of page, then + // they can be merged. Otherwise, we can stop the while-loop and insert + // page in the list of free blocks. + + if (!(/*...it is free...*/ && /*...they have the same size...*/)) { + break; + } + + // we are here only if buddy is free and can be merged with page. + + // remove buddy from the list of available blocks in its free_area_t + // .... + + // Decrease the number of free block of the current free_area_t. + // ... + + // buddy no longer represents a free block, so clear the private field. + buddy->private = 0; + + // Update the page index with the index of the coalesced block. + // ... + + order++; + } + + // The coalesced block is the result of the merging procedure. + page_t *coalesced = base + page_idx; + + // Update the field private to set the size. + coalesced->private = // ... + + // Insert the coalesced block in the free_area as available block + // ... + + // Increase the number of free blocks of the free_area. + // ... + + buddy_system_dump(zone); +} + +void buddy_system_dump(zone_t *zone) +{ + // Print free_list's size of each area of the zone. + dbg_print("Zone\t%s\t", zone->name); + for (int order = 0; order < MAX_ORDER; order++) { + free_area_t *area = zone->free_area + order; + dbg_print("%d\t", area->nr_free); + } + dbg_print("\n"); +} diff --git a/mentos/src/mem/kheap.c b/mentos/src/mem/kheap.c index 244e770..2211b4e 100644 --- a/mentos/src/mem/kheap.c +++ b/mentos/src/mem/kheap.c @@ -1,941 +1,960 @@ -/// MentOS, The Mentoring Operating system project -/// @file kheap.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "kheap.h" -#include "math.h" -#include "debug.h" -#include "string.h" -#include "paging.h" -#include "assert.h" - -#define PAGE_SIZE 4096 - -// 16 byte. -// #define OVERHEAD (sizeof(unsigned int) + sizeof(block_t)) -#define OVERHEAD sizeof(block_t) -#define ADDR_ALIGN(addr) ((((uint32_t)(addr)) & 0xFFFFF000) + 0x1000) -#define IS_ALIGN(addr) ((((uint32_t)(addr)) & 0x00000FFF) == 0) - - -//============= Heap memory descriptor ========================================= -// Kernel heap section. -static struct vm_area_struct kernel_heap; -// Top of heap. -static uint32_t kernel_heap_curr; -static bool_t kheap_enabled = false; -//============================================================================== - -static void *__do_brk(uint32_t *pointer_heap_curr, - struct vm_area_struct *heap, - int increment) -{ - assert(pointer_heap_curr && "Pointer to heap curr is NULL."); - assert(heap && "Heap do not exist."); - - uint32_t heap_curr = *pointer_heap_curr; - uint32_t old_heap_curr = heap_curr; - - uint32_t heap_end = heap->vm_end; - -// dbg_print("BRK> %s: heap_start: %p, free space: %d\n", -// (heap == &kernel_heap)? "KERNEL" : "USER", -// heap->vm_start, heap_end - heap_curr); - - if (increment > 0) - { - uint32_t new_boundary = heap_curr + increment; - /* If new size is smaller or equal to end, simply add size to - * kernel_heap_curr and return the old kernel_heap_curr. - */ - if (new_boundary <= heap_end) - { - *pointer_heap_curr = new_boundary; - - return (void *) old_heap_curr; - } - } - - return NULL; -} - -/// @brief Given the field size in a Block(which contain free/alloc -/// information), extract the size. -/// @param size -/// @return -static inline uint32_t get_real_size(uint32_t size) -{ - return (size >> 1U) << 1U; -} - -/// @brief Sets the free/alloc bit of the size field. -static inline void blkmngr_set_free(uint32_t *size, bool_t x) -{ - (*size) = (x) ? ((*size) | 1U) - : ((*size) & 0xFFFFFFFE); -} - -/// @brief Checks if a block is freed or allocated. -static inline bool_t blkmngr_is_free(block_t *block) -{ - if (block == NULL) return false; - - return (block->size & 1U); -} - -/* - * /// @brief Checks if it is the end block. - * static inline bool_t blkmngr_is_end(block_t * block) - * { - * assert(block && "Received null block."); - * assert(tail && "Tail has not set."); - * - * return block == tail; - * } - */ - -/// @brief Checks if the given size fits inside the block. -/// @param block The given block. -/// @param size The size to check -/// @return -static inline bool_t blkmngr_does_it_fit(block_t *block, uint32_t size) -{ - assert(block && "Received null block."); - - return (block->size >= get_real_size(size)) && blkmngr_is_free(block); -} - -/// @brief Removes the block from freelist. -static inline void blkmngr_remove_from_freelist(block_t *block, uint32_t *freelist) -{ - assert(block && "Received null block."); - assert(freelist && "Freelist is a null pointer."); - - block_t *first_free_block = (block_t *) *freelist; - assert(first_free_block && "Freelist is empty."); - - if (block == first_free_block) - { - *freelist = (uint32_t) block->nextfree; - } - else - { - block_t *prev = first_free_block; - while (prev != NULL && prev->nextfree != block) prev = prev->nextfree; - - if (prev) - { - prev->nextfree = block->nextfree; - } - } - - block->nextfree = NULL; -} - -/// @brief Add the block to the free list. -static inline void blkmngr_add_to_freelist(block_t *block, uint32_t *freelist) -{ - assert(block && "Received null block."); - assert(freelist && "Freelist is a null pointer."); - block_t * first_free_block = (block_t *) *freelist; - block->nextfree = first_free_block; - *freelist = (uint32_t) block; -} - -/// @brief Find the best fitting block in the memory pool. -static inline block_t *blkmngr_find_best_fitting(uint32_t size, uint32_t *freelist) -{ - assert(freelist && "Freelist is a null pointer."); - block_t *first_free_block = (block_t *) *freelist; - - if (first_free_block == NULL) - { - return NULL; - } - block_t *best_fitting = NULL; - for (block_t * current = first_free_block; current; current = current->nextfree) - { - if (!blkmngr_does_it_fit(current, size)) - { - continue; - } - if ((best_fitting == NULL) || (current->size < best_fitting->size)) - { - best_fitting = current; - } - } - return best_fitting; -} - -/// @brief Given a block, finds its previous block. -static inline block_t *blkmngr_get_previous_block(block_t *block, uint32_t *head) -{ - assert(block && "Received null block."); - assert(head && "The head of the list is not set."); - - block_t *head_block = (block_t *) *head; - assert(head_block && "The head of the list is not set."); - - if (block == head_block) - { - return NULL; - } - block_t *prev = head_block; - while (prev->next != block) - { - prev = prev->next; - } - - return prev; -} - -/// @brief Given a block, finds its next block. -static inline block_t *blkmngr_get_next_block(block_t *block, uint32_t *tail) -{ - assert(block && "Received null block."); - assert(tail && "The tail of the list is not set."); - - block_t *tail_block = (block_t *) *tail; - assert(tail_block && "The head of the list is not set."); - - if (block == tail_block) - { - return NULL; - } - - return block->next; -} - -/// @brief Allocates size bytes of uninitialized storage. -static void *__do_malloc(struct vm_area_struct *heap, size_t size) -{ - if (size == 0) return NULL; - - // Get: - // 1) First memory block. - // block_t *head = NULL; - // 2) Last memory block. - // block_t *tail = NULL; - // 3) All the memory blocks that are freed. - // block_t *freelist = NULL; - - // We will use these in writing. - uint32_t *head = (uint32_t *) (heap->vm_start); - uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); - uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); - // assert(head && tail && freelist && "Heap block lists point to null."); - - // We will use these others in reading. - block_t *head_block = (block_t *) *head; - block_t *tail_block = (block_t *) *tail; - // block_t *first_free_block = (block_t *) *freelist; - - // Calculate real size that's used, round it to multiple of 16. - uint32_t rounded_size = ceil(size, 16); - // The block size takes into account also the block_t overhead. - uint32_t block_size = rounded_size + OVERHEAD; - - // Find bestfit in avl tree. This bestfit function will remove the - // best-fit node when there is more than one such node in tree. - block_t *best_fitting = blkmngr_find_best_fitting(rounded_size, freelist); - - if (best_fitting != NULL) - { - // and! put a SIZE to the last four byte of the chunk - void *block_ptr = (void *) best_fitting; - // Store a pointer to the next block. - void *stored_next_block = blkmngr_get_next_block(best_fitting, tail); - // Get the size of the chunk. - uint32_t chunk_size = get_real_size(best_fitting->size) + OVERHEAD; - // Get what's left. - uint32_t remaining_size = chunk_size - block_size; - // Get the real size. - uint32_t real_size = (remaining_size < (8 + OVERHEAD)) ? chunk_size - : block_size; - // Set the size of the best fitting block. - best_fitting->size = real_size - OVERHEAD; - // Set the content of the block as free. - blkmngr_set_free(&(best_fitting->size), false); - // Store the base pointer. - void *base_ptr = block_ptr; - - block_ptr = (void *) (block_ptr + real_size); - - if (remaining_size < (8 + OVERHEAD)) - { - goto no_split; - } - else if (remaining_size >= (8 + OVERHEAD)) - { - if (blkmngr_is_free(stored_next_block)) - { - // Choice b) merge! - // Gather info about next block - void *nextblock = stored_next_block; - block_t *n_nextblock = nextblock; - /* Remove next from list because it no longer exists(just - * unlink it) - */ - blkmngr_remove_from_freelist(n_nextblock, freelist); - - // Merge! - block_t *t = block_ptr; - t->size = remaining_size + get_real_size(n_nextblock->size); - blkmngr_set_free(&(t->size), true); - - t->next = blkmngr_get_next_block(stored_next_block, tail); - - if (nextblock == tail_block) - { - // I don't want to set it to tail now, instead, reclaim it - *tail = (uint32_t) t; - // int reclaimSize = get_real_size(t->size) + OVERHEAD; - // ksbrk(-reclaimSize); - // goto no_split; - } - // then add merged one into the front of the list - blkmngr_add_to_freelist(t, freelist); - } - else - { - // Choice a) seperate! - block_t *putThisBack = block_ptr; - putThisBack->size = remaining_size - OVERHEAD; - blkmngr_set_free(&(putThisBack->size), true); - - putThisBack->next = stored_next_block; - - if (base_ptr == tail_block) - { - *tail = (uint32_t) putThisBack; - // int reclaimSize = get_real_size(putThisBack->size) +OVERHEAD; - // ksbrk(-reclaimSize); - // goto no_split; - } - blkmngr_add_to_freelist(putThisBack, freelist); - } - - ((block_t *) base_ptr)->next = block_ptr; - } - no_split: - // Remove the block from the free list. - blkmngr_remove_from_freelist(base_ptr, freelist); - - return base_ptr + sizeof(block_t); - } - else - { - uint32_t realsize = block_size; - block_t *ret; - - if (heap == &kernel_heap) - { - ret = ksbrk(realsize); - } - else - { - ret = usbrk(realsize); - } - - assert(ret != NULL && "Heap is running out of space\n"); - - if (!head_block) - { - *head = (uint32_t) ret; - } - else - { - tail_block->next = ret; - } - - ret->next = NULL; - ret->nextfree = NULL; - *tail = (uint32_t) ret; - - void *save = ret; - - /* After sbrk(), split the block into half [block_size | the rest], - * and put the rest into the tree. - */ - ret->size = block_size - OVERHEAD; - blkmngr_set_free(&(ret->size), - false); - // Set the block allocated. - // ptr = ptr + block_size - sizeof(uint32_t); - // trailing_space = ptr; - // *trailing_space = ret->size; - - // Now, return it! - return save + sizeof(block_t); - } -} - -/// @brief Allocates size bytes of uninitialized storage with block align. -static void *__do_malloc_align(struct vm_area_struct *heap, uint32_t size) -{ - if (size == 0) return NULL; - - // Get: - // 1) First memory block. - // static block_t *head = NULL; - // 2) Last memory block. - // static block_t *tail = NULL; - // 3) All the memory blocks that are freed. - // static block_t *freelist = NULL; - - // We will use these in writing. - uint32_t *head = (uint32_t *) (heap->vm_start); - uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); - uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); - assert(head && tail && freelist && "Heap block lists point to null."); - - // We will use these others in reading. - block_t *head_block = (block_t *) *head; - block_t *tail_block = (block_t *) *tail; - // block_t *first_free_block = (block_t *) *freelist; - - // Calculate real size that's used, round it to multiple of 16. - uint32_t rounded_size = ceil(size, 16); - - /* Find bestfit in avl tree. This bestfit function will remove - * thebest-fit node when there is more than one such node in tree. - */ - block_t *best_fitting = blkmngr_find_best_fitting(rounded_size, freelist); - if (best_fitting != NULL && (IS_ALIGN(best_fitting + sizeof(block_t)))) - { - return kmalloc(size); - } - else - { - void *needed_addr = (void *) ADDR_ALIGN( - ((uint32_t) kernel_heap_curr + sizeof(block_t)) & 0xFFFFF000); - block_t *block_addr = needed_addr - sizeof(block_t); - - uint32_t realsize = - (uint32_t) block_addr - (uint32_t) (kernel_heap_curr) + OVERHEAD + - rounded_size; - block_t *ret; - if(heap == &kernel_heap) - { - ret = ksbrk(realsize); - } - else - { - ret = usbrk(realsize); - } - assert(ret != NULL && "Heap is running out of space\n"); - if (!head_block) - { - *head = (uint32_t) block_addr; - } - else - { - tail_block->next = block_addr; - } - - ret->next = NULL; - ret->nextfree = NULL; - *tail = (uint32_t) block_addr; - - /* After sbrk(), split the block into half [block_size | the rest], - * and put the rest into the tree. - */ - block_addr->size = rounded_size; - blkmngr_set_free(&(block_addr->size), - false); - // Set the block allocated. - // ptr = ptr + block_size - sizeof(uint32_t); - // trailing_space = ptr; - // *trailing_space = block_addr->size; - - // Now, return it! - return needed_addr; - } -} - -/// @brief Reallocates the given area of memory. It must be still allocated -/// and not yet freed with a call to free or realloc. -/// @param ptr -/// @param size -/// @return -static void *__do_realloc(struct vm_area_struct *heap, void *ptr, uint32_t size) -{ - // Get: - // 1) First memory block. - // static block_t *head = NULL; - // 2) Last memory block. - // static block_t *tail = NULL; - // 3) All the memory blocks that are freed. - // static block_t *freelist = NULL; - - // We will use these in writing. - uint32_t *head = (uint32_t *) (heap->vm_start); - uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); - uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); - assert(head && tail && freelist && "Heap block lists point to null."); - - // We will use these others in reading. - block_t *head_block = (block_t *) *head; - block_t *tail_block = (block_t *) *tail; - // block_t *first_free_block = (block_t *) *freelist; - - uint32_t *trailing_space = NULL; - if (!ptr) - { - return kmalloc(size); - } - if (size == 0 && ptr != NULL) - { - kfree(ptr); - - return NULL; - } - uint32_t rounded_size = ceil(size, 16); - uint32_t block_size = rounded_size + OVERHEAD; - block_t *nextBlock; - block_t *prevBlock; - - /* Shrink or expand? - * - * Shrink: - * Now, we would just return the same address, later we may split this - * block. - * - * Expand: - * First, try if the actual size of the memory block is enough - * to hold the current size. - * Second, if not, try if merging the next block works. - * Third, if none of the above works, malloc another block, move all the - * data there, and then free the original block. - */ - block_t *nptr = ptr - sizeof(block_t); - nextBlock = blkmngr_get_next_block(nptr, tail); - prevBlock = blkmngr_get_previous_block(nptr, head); - if (nptr->size == size) - { - return ptr; - } - if (nptr->size < size) - { - // Expand, size of the block is just not enough. - if (tail_block != nptr && blkmngr_is_free(nextBlock) && - (get_real_size(nptr->size) + OVERHEAD + - get_real_size(nextBlock->size)) >= rounded_size) - { - // Merge with the next block, and return! - // Change size to curr's size + OVERHEAD + next's size. - blkmngr_remove_from_freelist(nextBlock, freelist); - nptr->size = get_real_size(nptr->size) + OVERHEAD + - get_real_size(nextBlock->size); - blkmngr_set_free(&(nptr->size), false); - trailing_space = - (void *) nptr + sizeof(block_t) + get_real_size(nptr->size); - *trailing_space = nptr->size; - if (tail_block == nextBlock) - { - // Set it to tail for now, or we can reclaim it. - *tail = (uint32_t) nptr; - } - return nptr + 1; - } - // Hey! Try merging with the previous block! - else if (head_block != nptr && blkmngr_is_free(prevBlock) && - (get_real_size(nptr->size) + OVERHEAD + - get_real_size(prevBlock->size)) >= rounded_size) - { - // db_print(); - uint32_t originalSize = get_real_size(nptr->size); - // Hey! one more thing to do , copy data over to new block. - blkmngr_remove_from_freelist(prevBlock, freelist); - prevBlock->size = - originalSize + OVERHEAD + get_real_size(prevBlock->size); - blkmngr_set_free(&(prevBlock->size), false); - trailing_space = (void *) prevBlock + sizeof(block_t) + - get_real_size(prevBlock->size); - *trailing_space = prevBlock->size; - if (tail_block == nptr) - { - *tail = (uint32_t) prevBlock; - } - memcpy(prevBlock + 1, ptr, originalSize); - - return prevBlock + 1; - } - - // Move to somewhere else. - void *newplace = kmalloc(size); - // Copy data over. - memcpy(newplace, ptr, get_real_size(nptr->size)); - // Free original one - kfree(ptr); - - return newplace; - } - else - { - /* Shrink/Do nothing, you can leave it as it's, but yeah... shrink - * it What's left after shrinking the original block. - */ - uint32_t rest = get_real_size(nptr->size) + OVERHEAD - block_size; - if (rest < 8 + OVERHEAD) return ptr; - - nptr->size = block_size - OVERHEAD; - blkmngr_set_free(&(nptr->size), false); - trailing_space = - (void *) nptr + sizeof(block_t) + get_real_size(nptr->size); - *trailing_space = nptr->size; - /* - * if(tail == nptr) - * { - * ksbrk(-reclaimSize); - * - * return ptr; - * } - */ - block_t *splitBlock = (void *) trailing_space + sizeof(uint32_t); - - /* Set the next, if the next of the next is also freed.. then merge!! - * Wait... what if after merge, I get a much much more bigger block - * than I even need? split again hahahahahah fuck! - * Instead of spliting after merge, let's give splitBlock. - */ - if (nextBlock && blkmngr_is_free(nextBlock)) - { - splitBlock->size = rest + get_real_size(nextBlock->size); - blkmngr_set_free(&(splitBlock->size), true); - trailing_space = (void *) splitBlock + sizeof(block_t) + - get_real_size(splitBlock->size); - *trailing_space = splitBlock->size; - - // Remove next block from freelist. - blkmngr_remove_from_freelist(nextBlock, freelist); - // This can be deleted when you correctly implemented malloc() - if (tail_block == nextBlock) - { - *tail = (uint32_t) splitBlock; - } - // Add splitblock to freelist. - blkmngr_add_to_freelist(splitBlock, freelist); - - return ptr; - } - // Separate! - splitBlock->size = rest - OVERHEAD; - blkmngr_set_free(&(splitBlock->size), true); - trailing_space = (void *) splitBlock + sizeof(block_t) + - get_real_size(splitBlock->size); - *trailing_space = splitBlock->size; - - // Add this mo** f**r to the freelist! - blkmngr_add_to_freelist(splitBlock, freelist); - - return ptr; - } -} - -/// @brief Deallocates previously allocated space. -static void __do_free(struct vm_area_struct * heap, void * ptr) -{ - assert(ptr); - - // Get: - // 1) First memory block. - // static block_t *head = NULL; - // 2) Last memory block. - // static block_t *tail = NULL; - // 3) All the memory blocks that are freed. - // static block_t *freelist = NULL; - - // We will use these in writing. - uint32_t *head = (uint32_t *) (heap->vm_start); - uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); - uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); - assert(head && tail && freelist && "Heap block lists point to null."); - - // We will use these others in reading. - block_t *tail_block = (block_t *) *tail; - - block_t *curr = ptr - sizeof(block_t); - - block_t *prev = blkmngr_get_previous_block(curr, head); - block_t *next = blkmngr_get_next_block(curr, tail); - if (blkmngr_is_free(prev) && blkmngr_is_free(next)) - { - prev->size = - get_real_size(prev->size) + 2 * OVERHEAD + - get_real_size(curr->size) + - get_real_size(next->size); - blkmngr_set_free(&(prev->size), true); - - prev->next = blkmngr_get_next_block(next, tail); - - // If next used to be tail, set prev = tail. - if (tail_block == next) - { - *tail = (uint32_t) prev; - } - blkmngr_remove_from_freelist(next, freelist); - } - else if (blkmngr_is_free(prev)) - { - prev->size = - get_real_size(prev->size) + OVERHEAD + get_real_size(curr->size); - blkmngr_set_free(&(prev->size), true); - - prev->next = next; - - if (tail_block == curr) - { - *tail = (uint32_t) prev; - } - } - else if (blkmngr_is_free(next)) - { - // Change size to curr's size + OVERHEAD + next's size. - curr->size = - get_real_size(curr->size) + OVERHEAD + get_real_size(next->size); - blkmngr_set_free(&(curr->size), true); - - curr->next = blkmngr_get_next_block(next, tail); - - if (tail_block == next) - { - *tail = (uint32_t) curr; - } - blkmngr_remove_from_freelist(next, freelist); - blkmngr_add_to_freelist(curr, freelist); - } - else - { - // Just mark curr freed. - blkmngr_set_free(&(curr->size), true); - blkmngr_add_to_freelist(curr, freelist); - } -} - -void kheap_init(size_t initial_size) -{ - // Starting allocate kheap after paging. - if (paging_is_enabled()) - { - assert(0 && "Paging must not be enabled!"); - } - - unsigned int order = find_nearest_order_greater(initial_size); - - // Kernel_heap_start. - kernel_heap.vm_start = __alloc_pages(GFP_KERNEL, order); - kernel_heap.vm_end = kernel_heap.vm_start + ((1UL << order) * PAGE_SIZE); - - // Kernel_heap_start. - kernel_heap_curr = kernel_heap.vm_start; - - // Set kernel_heap vm_area_struct info: - kernel_heap.vm_next = NULL; - kernel_heap.vm_mm = NULL; - - // Reserved space for: - // 1) First memory block. - // static block_t *head = NULL; - // 2) Last memory block. - // static block_t *tail = NULL; - // 3) All the memory blocks that are freed. - // static block_t *freelist = NULL; - memset((void *)kernel_heap_curr, 0, 3 * sizeof(block_t *)); - kernel_heap_curr += 3 * sizeof(block_t *); - - kheap_enabled = true; -} - -bool_t kheap_is_enabled() -{ - return kheap_enabled; -} - -void *ksbrk(int increment) -{ - return __do_brk(&kernel_heap_curr, &kernel_heap, increment); -} - - - -void *kmalloc(uint32_t sz) -{ - assert(kheap_enabled && "KHEAP not initialized!"); - - return __do_malloc(&kernel_heap, sz); -} - -// TODO: check! -void *kmalloc_align(size_t size) -{ - assert(kheap_enabled && "KHEAP not initialized!"); - - return __do_malloc_align(&kernel_heap, size); -} - -void *kcalloc(uint32_t num, uint32_t size) -{ - void *ptr = kmalloc(num * size); - if (ptr) - { - memset(ptr, 0, num * size); - } - - return ptr; -} - -// TODO: check! -void *krealloc(void *ptr, uint32_t size) -{ - return __do_realloc(&kernel_heap, ptr, size); -} - -void kfree(void *ptr) -{ - __do_free(&kernel_heap, ptr); -} - -/// @brief Find the current user heap. -/// @return The heap structure if heap exists, otherwise NULL. -static struct vm_area_struct *find_user_heap() -{ - // Get the memory descriptor of the current process. - task_struct *current_task = kernel_get_current_process(); - struct mm_struct *current_mm = current_task->mm; - - // Get the starting address of the heap. - uint32_t start_heap = current_mm->start_brk; - // If not set return NULL. - if(start_heap == 0) - { - return NULL; - } - - // Otherwise find the respective heap segment. - struct vm_area_struct *segment = current_mm->mmap; - while(segment->vm_start != start_heap) - { - segment = segment->vm_next; - } - - return segment; -} - -// TODO: rename in sys_brk -void *umalloc(unsigned int size) -{ - // Get user heap segment structure. - struct vm_area_struct *heap_segment = find_user_heap(); - - // Allocate the segment if don't exist. - if(heap_segment == NULL) - { - task_struct *current_task = kernel_get_current_process(); - struct mm_struct *current_mm = current_task->mm; - current_mm->start_brk = create_segment(current_mm, UHEAP_INITIAL_SIZE); - current_mm->brk = current_mm->start_brk; - // Reserved space for: - // 1) First memory block. - // static block_t *head = NULL; - // 2) Last memory block. - // static block_t *tail = NULL; - // 3) All the memory blocks that are freed. - // static block_t *freelist = NULL; - current_mm->brk += 3 * sizeof(block_t *); - heap_segment = find_user_heap(); - } - - return __do_malloc(heap_segment, size); -} - -// TODO: rename in sys_brk -void ufree(void *p) -{ - // Get user heap segment structure. - struct vm_area_struct *heap_segment = find_user_heap(); - - // If the segment exists, user did a malloc previously. - if (heap_segment != NULL) - { - __do_free(heap_segment, p); - } -} - -void *usbrk(int increment) -{ - task_struct *current_task = kernel_get_current_process(); - struct mm_struct *task_mm = current_task->mm; - uint32_t *heap_curr = &task_mm->brk; - - struct vm_area_struct *heap_segment = find_user_heap(); - - return __do_brk(heap_curr, heap_segment, increment); -} - -void kheap_dump() -{ - // 1) First memory block. - // static block_t *head = NULL; - // 2) Last memory block. - // static block_t *tail = NULL; - // 3) All the memory blocks that are freed. - // static block_t *freelist = NULL; - - // We will use these in writing. - uint32_t *head = (uint32_t *) (kernel_heap.vm_start); - uint32_t *tail = (uint32_t *) (kernel_heap.vm_start + sizeof(block_t *)); - uint32_t *freelist = (uint32_t *) (kernel_heap.vm_start + 2 * sizeof(block_t *)); - assert(head && tail && freelist && "Heap block lists point to null."); - - // We will use these others in reading. - block_t *head_block = (block_t *) *head; - // block_t *tail_block = (block_t *) *tail; - block_t *first_free_block = (block_t *) *freelist; - - if (!head_block) - { - dbg_print("your heap is empty now\n"); - - return; - } - - // dbg_print("HEAP:\n"); - uint32_t total = 0; - uint32_t total_overhead = 0; - block_t * it = head_block; - while (it) - { - dbg_print("[%c] %12u (%12u) from 0x%p to 0x%p\n", - (blkmngr_is_free(it)) ? 'F' : 'A', - get_real_size(it->size), - it->size, - it, - (void *) it + OVERHEAD + get_real_size(it->size)); - total += get_real_size(it->size); - total_overhead += OVERHEAD; - - it = it->next; - } - dbg_print("\nTotal usable bytes : %d", total); - dbg_print("\nTotal overhead bytes : %d", total_overhead); - dbg_print("\nTotal bytes : %d", total + total_overhead); - dbg_print("\nFreelist: "); - for (it = first_free_block; it != NULL; it = it->nextfree) - { - dbg_print("(%p)->", it); - } - dbg_print("\n\n"); -} - -uint32_t get_kheap_start() -{ - return kernel_heap.vm_start; -} - -uint32_t get_kheap_curr() -{ - return kernel_heap_curr; -} +/// MentOS, The Mentoring Operating system project +/// @file kheap.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "kheap.h" +#include "math.h" +#include "debug.h" +#include "string.h" +#include "paging.h" +#include "assert.h" + +#define PAGE_SIZE 4096 + +// 16 byte. +// #define OVERHEAD (sizeof(unsigned int) + sizeof(block_t)) +#define OVERHEAD sizeof(block_t) +#define ADDR_ALIGN(addr) ((((uint32_t)(addr)) & 0xFFFFF000) + 0x1000) +#define IS_ALIGN(addr) ((((uint32_t)(addr)) & 0x00000FFF) == 0) + + +//============= Heap memory descriptor ========================================= +// Kernel heap section. +static struct vm_area_struct kernel_heap; +// Top of heap. +static uint32_t kernel_heap_curr; +static bool_t kheap_enabled = false; +//============================================================================== + +static void *__do_brk(uint32_t *pointer_heap_curr, + struct vm_area_struct *heap, + int increment) +{ + assert(pointer_heap_curr && "Pointer to heap curr is NULL."); + assert(heap && "Heap do not exist."); + + uint32_t heap_curr = *pointer_heap_curr; + uint32_t old_heap_curr = heap_curr; + + uint32_t heap_end = heap->vm_end; + +// dbg_print("BRK> %s: heap_start: %p, free space: %d\n", +// (heap == &kernel_heap)? "KERNEL" : "USER", +// heap->vm_start, heap_end - heap_curr); + + if (increment > 0) + { + uint32_t new_boundary = heap_curr + increment; + /* If new size is smaller or equal to end, simply add size to + * kernel_heap_curr and return the old kernel_heap_curr. + */ + if (new_boundary <= heap_end) + { + *pointer_heap_curr = new_boundary; + + return (void *) old_heap_curr; + } + } + + return NULL; +} + +/// @brief Given the field size in a Block(which contain free/alloc +/// information), extract the size. +/// @param size +/// @return +static inline uint32_t get_real_size(uint32_t size) +{ + return (size >> 1U) << 1U; +} + +/// @brief Sets the free/alloc bit of the size field. +static inline void blkmngr_set_free(uint32_t *size, bool_t x) +{ + (*size) = (x) ? ((*size) | 1U) + : ((*size) & 0xFFFFFFFE); +} + +/// @brief Checks if a block is freed or allocated. +static inline bool_t blkmngr_is_free(block_t *block) +{ + if (block == NULL) return false; + + return (block->size & 1U); +} + +/* + * /// @brief Checks if it is the end block. + * static inline bool_t blkmngr_is_end(block_t * block) + * { + * assert(block && "Received null block."); + * assert(tail && "Tail has not set."); + * + * return block == tail; + * } + */ + +/// @brief Checks if the given size fits inside the block. +/// @param block The given block. +/// @param size The size to check +/// @return +static inline bool_t blkmngr_does_it_fit(block_t *block, uint32_t size) +{ + assert(block && "Received null block."); + + return (block->size >= get_real_size(size)) && blkmngr_is_free(block); +} + +/// @brief Removes the block from freelist. +static inline void blkmngr_remove_from_freelist(block_t *block, uint32_t *freelist) +{ + assert(block && "Received null block."); + assert(freelist && "Freelist is a null pointer."); + + block_t *first_free_block = (block_t *) *freelist; + assert(first_free_block && "Freelist is empty."); + + if (block == first_free_block) + { + *freelist = (uint32_t) block->nextfree; + } + else + { + block_t *prev = first_free_block; + while (prev != NULL && prev->nextfree != block) prev = prev->nextfree; + + if (prev) + { + prev->nextfree = block->nextfree; + } + } + + block->nextfree = NULL; +} + +/// @brief Add the block to the free list. +static inline void blkmngr_add_to_freelist(block_t *block, uint32_t *freelist) +{ + assert(block && "Received null block."); + assert(freelist && "Freelist is a null pointer."); + block_t * first_free_block = (block_t *) *freelist; + block->nextfree = first_free_block; + *freelist = (uint32_t) block; +} + +/// @brief Find the best fitting block in the memory pool. +static inline block_t *blkmngr_find_best_fitting(uint32_t size, uint32_t *freelist) +{ + assert(freelist && "Freelist is a null pointer."); + block_t *first_free_block = (block_t *) *freelist; + + if (first_free_block == NULL) + { + return NULL; + } + block_t *best_fitting = NULL; + for (block_t * current = first_free_block; current; current = current->nextfree) + { + if (!blkmngr_does_it_fit(current, size)) + { + continue; + } + if ((best_fitting == NULL) || (current->size < best_fitting->size)) + { + best_fitting = current; + } + } + return best_fitting; +} + +/// @brief Given a block, finds its previous block. +static inline block_t *blkmngr_get_previous_block(block_t *block, uint32_t *head) +{ + assert(block && "Received null block."); + assert(head && "The head of the list is not set."); + + block_t *head_block = (block_t *) *head; + assert(head_block && "The head of the list is not set."); + + if (block == head_block) + { + return NULL; + } + block_t *prev = head_block; + while (prev->next != block) + { + prev = prev->next; + } + + return prev; +} + +/// @brief Given a block, finds its next block. +static inline block_t *blkmngr_get_next_block(block_t *block, uint32_t *tail) +{ + assert(block && "Received null block."); + assert(tail && "The tail of the list is not set."); + + block_t *tail_block = (block_t *) *tail; + assert(tail_block && "The head of the list is not set."); + + if (block == tail_block) + { + return NULL; + } + + return block->next; +} + +/// @brief Allocates size bytes of uninitialized storage. +static void *__do_malloc(struct vm_area_struct *heap, size_t size) +{ + if (size == 0) return NULL; + + // Get: + // 1) First memory block. + // block_t *head = NULL; + // 2) Last memory block. + // block_t *tail = NULL; + // 3) All the memory blocks that are freed. + // block_t *freelist = NULL; + + // We will use these in writing. + uint32_t *head = (uint32_t *) (heap->vm_start); + uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); + uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); + // assert(head && tail && freelist && "Heap block lists point to null."); + + // We will use these others in reading. + block_t *head_block = (block_t *) *head; + block_t *tail_block = (block_t *) *tail; + // block_t *first_free_block = (block_t *) *freelist; + + // Calculate real size that's used, round it to multiple of 16. + uint32_t rounded_size = ceil(size, 16); + // The block size takes into account also the block_t overhead. + uint32_t block_size = rounded_size + OVERHEAD; + + // Find bestfit in avl tree. This bestfit function will remove the + // best-fit node when there is more than one such node in tree. + block_t *best_fitting = blkmngr_find_best_fitting(rounded_size, freelist); + + if (best_fitting != NULL) + { + // and! put a SIZE to the last four byte of the chunk + void *block_ptr = (void *) best_fitting; + // Store a pointer to the next block. + void *stored_next_block = blkmngr_get_next_block(best_fitting, tail); + // Get the size of the chunk. + uint32_t chunk_size = get_real_size(best_fitting->size) + OVERHEAD; + // Get what's left. + uint32_t remaining_size = chunk_size - block_size; + // Get the real size. + uint32_t real_size = (remaining_size < (8 + OVERHEAD)) ? chunk_size + : block_size; + // Set the size of the best fitting block. + best_fitting->size = real_size - OVERHEAD; + // Set the content of the block as free. + blkmngr_set_free(&(best_fitting->size), false); + // Store the base pointer. + void *base_ptr = block_ptr; + + block_ptr = (void *) (block_ptr + real_size); + + if (remaining_size < (8 + OVERHEAD)) + { + goto no_split; + } + else if (remaining_size >= (8 + OVERHEAD)) + { + if (blkmngr_is_free(stored_next_block)) + { + // Choice b) merge! + // Gather info about next block + void *nextblock = stored_next_block; + block_t *n_nextblock = nextblock; + /* Remove next from list because it no longer exists(just + * unlink it) + */ + blkmngr_remove_from_freelist(n_nextblock, freelist); + + // Merge! + block_t *t = block_ptr; + t->size = remaining_size + get_real_size(n_nextblock->size); + blkmngr_set_free(&(t->size), true); + + t->next = blkmngr_get_next_block(stored_next_block, tail); + + if (nextblock == tail_block) + { + // I don't want to set it to tail now, instead, reclaim it + *tail = (uint32_t) t; + // int reclaimSize = get_real_size(t->size) + OVERHEAD; + // ksbrk(-reclaimSize); + // goto no_split; + } + // then add merged one into the front of the list + blkmngr_add_to_freelist(t, freelist); + } + else + { + // Choice a) seperate! + block_t *putThisBack = block_ptr; + putThisBack->size = remaining_size - OVERHEAD; + blkmngr_set_free(&(putThisBack->size), true); + + putThisBack->next = stored_next_block; + + if (base_ptr == tail_block) + { + *tail = (uint32_t) putThisBack; + // int reclaimSize = get_real_size(putThisBack->size) +OVERHEAD; + // ksbrk(-reclaimSize); + // goto no_split; + } + blkmngr_add_to_freelist(putThisBack, freelist); + } + + ((block_t *) base_ptr)->next = block_ptr; + } + no_split: + // Remove the block from the free list. + blkmngr_remove_from_freelist(base_ptr, freelist); + + return base_ptr + sizeof(block_t); + } + else + { + uint32_t realsize = block_size; + block_t *ret; + + if (heap == &kernel_heap) + { + ret = ksbrk(realsize); + } + else + { + ret = usbrk(realsize); + } + + assert(ret != NULL && "Heap is running out of space\n"); + + if (!head_block) + { + *head = (uint32_t) ret; + } + else + { + tail_block->next = ret; + } + + ret->next = NULL; + ret->nextfree = NULL; + *tail = (uint32_t) ret; + + void *save = ret; + + /* After sbrk(), split the block into half [block_size | the rest], + * and put the rest into the tree. + */ + ret->size = block_size - OVERHEAD; + blkmngr_set_free(&(ret->size), + false); + // Set the block allocated. + // ptr = ptr + block_size - sizeof(uint32_t); + // trailing_space = ptr; + // *trailing_space = ret->size; + + // Now, return it! + return save + sizeof(block_t); + } +} + +/// @brief Allocates size bytes of uninitialized storage with block align. +static void *__do_malloc_align(struct vm_area_struct *heap, uint32_t size) +{ + if (size == 0) return NULL; + + // Get: + // 1) First memory block. + // static block_t *head = NULL; + // 2) Last memory block. + // static block_t *tail = NULL; + // 3) All the memory blocks that are freed. + // static block_t *freelist = NULL; + + // We will use these in writing. + uint32_t *head = (uint32_t *) (heap->vm_start); + uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); + uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); + assert(head && tail && freelist && "Heap block lists point to null."); + + // We will use these others in reading. + block_t *head_block = (block_t *) *head; + block_t *tail_block = (block_t *) *tail; + // block_t *first_free_block = (block_t *) *freelist; + + // Calculate real size that's used, round it to multiple of 16. + uint32_t rounded_size = ceil(size, 16); + + /* Find bestfit in avl tree. This bestfit function will remove + * thebest-fit node when there is more than one such node in tree. + */ + block_t *best_fitting = blkmngr_find_best_fitting(rounded_size, freelist); + if (best_fitting != NULL && (IS_ALIGN(best_fitting + sizeof(block_t)))) + { + return kmalloc(size); + } + else + { + void *needed_addr = (void *) ADDR_ALIGN( + ((uint32_t) kernel_heap_curr + sizeof(block_t)) & 0xFFFFF000); + block_t *block_addr = needed_addr - sizeof(block_t); + + uint32_t realsize = + (uint32_t) block_addr - (uint32_t) (kernel_heap_curr) + OVERHEAD + + rounded_size; + block_t *ret; + if(heap == &kernel_heap) + { + ret = ksbrk(realsize); + } + else + { + ret = usbrk(realsize); + } + assert(ret != NULL && "Heap is running out of space\n"); + if (!head_block) + { + *head = (uint32_t) block_addr; + } + else + { + tail_block->next = block_addr; + } + + ret->next = NULL; + ret->nextfree = NULL; + *tail = (uint32_t) block_addr; + + /* After sbrk(), split the block into half [block_size | the rest], + * and put the rest into the tree. + */ + block_addr->size = rounded_size; + blkmngr_set_free(&(block_addr->size), + false); + // Set the block allocated. + // ptr = ptr + block_size - sizeof(uint32_t); + // trailing_space = ptr; + // *trailing_space = block_addr->size; + + // Now, return it! + return needed_addr; + } +} + +/// @brief Reallocates the given area of memory. It must be still allocated +/// and not yet freed with a call to free or realloc. +/// @param ptr +/// @param size +/// @return +static void *__do_realloc(struct vm_area_struct *heap, void *ptr, uint32_t size) +{ + // Get: + // 1) First memory block. + // static block_t *head = NULL; + // 2) Last memory block. + // static block_t *tail = NULL; + // 3) All the memory blocks that are freed. + // static block_t *freelist = NULL; + + // We will use these in writing. + uint32_t *head = (uint32_t *) (heap->vm_start); + uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); + uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); + assert(head && tail && freelist && "Heap block lists point to null."); + + // We will use these others in reading. + block_t *head_block = (block_t *) *head; + block_t *tail_block = (block_t *) *tail; + // block_t *first_free_block = (block_t *) *freelist; + + uint32_t *trailing_space = NULL; + if (!ptr) + { + return kmalloc(size); + } + if (size == 0 && ptr != NULL) + { + kfree(ptr); + + return NULL; + } + uint32_t rounded_size = ceil(size, 16); + uint32_t block_size = rounded_size + OVERHEAD; + block_t *nextBlock; + block_t *prevBlock; + + /* Shrink or expand? + * + * Shrink: + * Now, we would just return the same address, later we may split this + * block. + * + * Expand: + * First, try if the actual size of the memory block is enough + * to hold the current size. + * Second, if not, try if merging the next block works. + * Third, if none of the above works, malloc another block, move all the + * data there, and then free the original block. + */ + block_t *nptr = ptr - sizeof(block_t); + nextBlock = blkmngr_get_next_block(nptr, tail); + prevBlock = blkmngr_get_previous_block(nptr, head); + if (nptr->size == size) + { + return ptr; + } + if (nptr->size < size) + { + // Expand, size of the block is just not enough. + if (tail_block != nptr && blkmngr_is_free(nextBlock) && + (get_real_size(nptr->size) + OVERHEAD + + get_real_size(nextBlock->size)) >= rounded_size) + { + // Merge with the next block, and return! + // Change size to curr's size + OVERHEAD + next's size. + blkmngr_remove_from_freelist(nextBlock, freelist); + nptr->size = get_real_size(nptr->size) + OVERHEAD + + get_real_size(nextBlock->size); + blkmngr_set_free(&(nptr->size), false); + trailing_space = + (void *) nptr + sizeof(block_t) + get_real_size(nptr->size); + *trailing_space = nptr->size; + if (tail_block == nextBlock) + { + // Set it to tail for now, or we can reclaim it. + *tail = (uint32_t) nptr; + } + return nptr + 1; + } + // Hey! Try merging with the previous block! + else if (head_block != nptr && blkmngr_is_free(prevBlock) && + (get_real_size(nptr->size) + OVERHEAD + + get_real_size(prevBlock->size)) >= rounded_size) + { + // db_print(); + uint32_t originalSize = get_real_size(nptr->size); + // Hey! one more thing to do , copy data over to new block. + blkmngr_remove_from_freelist(prevBlock, freelist); + prevBlock->size = + originalSize + OVERHEAD + get_real_size(prevBlock->size); + blkmngr_set_free(&(prevBlock->size), false); + trailing_space = (void *) prevBlock + sizeof(block_t) + + get_real_size(prevBlock->size); + *trailing_space = prevBlock->size; + if (tail_block == nptr) + { + *tail = (uint32_t) prevBlock; + } + memcpy(prevBlock + 1, ptr, originalSize); + + return prevBlock + 1; + } + + // Move to somewhere else. + void *newplace = kmalloc(size); + // Copy data over. + memcpy(newplace, ptr, get_real_size(nptr->size)); + // Free original one + kfree(ptr); + + return newplace; + } + else + { + /* Shrink/Do nothing, you can leave it as it's, but yeah... shrink + * it What's left after shrinking the original block. + */ + uint32_t rest = get_real_size(nptr->size) + OVERHEAD - block_size; + if (rest < 8 + OVERHEAD) return ptr; + + nptr->size = block_size - OVERHEAD; + blkmngr_set_free(&(nptr->size), false); + trailing_space = + (void *) nptr + sizeof(block_t) + get_real_size(nptr->size); + *trailing_space = nptr->size; + /* + * if(tail == nptr) + * { + * ksbrk(-reclaimSize); + * + * return ptr; + * } + */ + block_t *splitBlock = (void *) trailing_space + sizeof(uint32_t); + + /* Set the next, if the next of the next is also freed.. then merge!! + * Wait... what if after merge, I get a much much more bigger block + * than I even need? split again hahahahahah fuck! + * Instead of spliting after merge, let's give splitBlock. + */ + if (nextBlock && blkmngr_is_free(nextBlock)) + { + splitBlock->size = rest + get_real_size(nextBlock->size); + blkmngr_set_free(&(splitBlock->size), true); + trailing_space = (void *) splitBlock + sizeof(block_t) + + get_real_size(splitBlock->size); + *trailing_space = splitBlock->size; + + // Remove next block from freelist. + blkmngr_remove_from_freelist(nextBlock, freelist); + // This can be deleted when you correctly implemented malloc() + if (tail_block == nextBlock) + { + *tail = (uint32_t) splitBlock; + } + // Add splitblock to freelist. + blkmngr_add_to_freelist(splitBlock, freelist); + + return ptr; + } + // Separate! + splitBlock->size = rest - OVERHEAD; + blkmngr_set_free(&(splitBlock->size), true); + trailing_space = (void *) splitBlock + sizeof(block_t) + + get_real_size(splitBlock->size); + *trailing_space = splitBlock->size; + + // Add this mo** f**r to the freelist! + blkmngr_add_to_freelist(splitBlock, freelist); + + return ptr; + } +} + +/// @brief Deallocates previously allocated space. +static void __do_free(struct vm_area_struct * heap, void * ptr) +{ + assert(ptr); + + // Get: + // 1) First memory block. + // static block_t *head = NULL; + // 2) Last memory block. + // static block_t *tail = NULL; + // 3) All the memory blocks that are freed. + // static block_t *freelist = NULL; + + // We will use these in writing. + uint32_t *head = (uint32_t *) (heap->vm_start); + uint32_t *tail = (uint32_t *) (heap->vm_start + sizeof(block_t *)); + uint32_t *freelist = (uint32_t *) (heap->vm_start + 2 * sizeof(block_t *)); + assert(head && tail && freelist && "Heap block lists point to null."); + + // We will use these others in reading. + block_t *tail_block = (block_t *) *tail; + + block_t *curr = ptr - sizeof(block_t); + + block_t *prev = blkmngr_get_previous_block(curr, head); + block_t *next = blkmngr_get_next_block(curr, tail); + if (blkmngr_is_free(prev) && blkmngr_is_free(next)) + { + prev->size = + get_real_size(prev->size) + 2 * OVERHEAD + + get_real_size(curr->size) + + get_real_size(next->size); + blkmngr_set_free(&(prev->size), true); + + prev->next = blkmngr_get_next_block(next, tail); + + // If next used to be tail, set prev = tail. + if (tail_block == next) + { + *tail = (uint32_t) prev; + } + blkmngr_remove_from_freelist(next, freelist); + } + else if (blkmngr_is_free(prev)) + { + prev->size = + get_real_size(prev->size) + OVERHEAD + get_real_size(curr->size); + blkmngr_set_free(&(prev->size), true); + + prev->next = next; + + if (tail_block == curr) + { + *tail = (uint32_t) prev; + } + } + else if (blkmngr_is_free(next)) + { + // Change size to curr's size + OVERHEAD + next's size. + curr->size = + get_real_size(curr->size) + OVERHEAD + get_real_size(next->size); + blkmngr_set_free(&(curr->size), true); + + curr->next = blkmngr_get_next_block(next, tail); + + if (tail_block == next) + { + *tail = (uint32_t) curr; + } + blkmngr_remove_from_freelist(next, freelist); + blkmngr_add_to_freelist(curr, freelist); + } + else + { + // Just mark curr freed. + blkmngr_set_free(&(curr->size), true); + blkmngr_add_to_freelist(curr, freelist); + } +} + +void kheap_init(size_t initial_size) +{ + // Starting allocate kheap after paging. + if (paging_is_enabled()) + { + assert(0 && "Paging must not be enabled!"); + } + + unsigned int order = find_nearest_order_greater(initial_size); + + // Kernel_heap_start. + kernel_heap.vm_start = __alloc_pages(GFP_KERNEL, order); + kernel_heap.vm_end = kernel_heap.vm_start + ((1UL << order) * PAGE_SIZE); + + // Kernel_heap_start. + kernel_heap_curr = kernel_heap.vm_start; + + // Set kernel_heap vm_area_struct info: + kernel_heap.vm_next = NULL; + kernel_heap.vm_mm = NULL; + + // Reserved space for: + // 1) First memory block. + // static block_t *head = NULL; + // 2) Last memory block. + // static block_t *tail = NULL; + // 3) All the memory blocks that are freed. + // static block_t *freelist = NULL; + memset((void *)kernel_heap_curr, 0, 3 * sizeof(block_t *)); + kernel_heap_curr += 3 * sizeof(block_t *); + + kheap_enabled = true; +} + +bool_t kheap_is_enabled() +{ + return kheap_enabled; +} + +void *ksbrk(int increment) +{ + return __do_brk(&kernel_heap_curr, &kernel_heap, increment); +} + + + +void *kmalloc(uint32_t sz) +{ + assert(kheap_enabled && "KHEAP not initialized!"); + + return __do_malloc(&kernel_heap, sz); +} + +// TODO: check! +void *kmalloc_align(size_t size) +{ + assert(kheap_enabled && "KHEAP not initialized!"); + + return __do_malloc_align(&kernel_heap, size); +} + +void *kcalloc(uint32_t num, uint32_t size) +{ + void *ptr = kmalloc(num * size); + if (ptr) + { + memset(ptr, 0, num * size); + } + + return ptr; +} + +// TODO: check! +void *krealloc(void *ptr, uint32_t size) +{ + return __do_realloc(&kernel_heap, ptr, size); +} + +void **kmmalloc(size_t n, size_t size) +{ + void **ret = (void **) kmalloc(n * sizeof(void *)); + for (size_t i = 0; i < n; i++) + { + *(ret + i) = kmalloc(size); + } + return ret; +} + +void kfree(void *ptr) +{ + __do_free(&kernel_heap, ptr); +} + +void kmfree(void **src, size_t n) +{ + for (size_t i = 0; i < n; i++) + { + kfree(*(src + i)); + } + kfree(src); +} + +/// @brief Find the current user heap. +/// @return The heap structure if heap exists, otherwise NULL. +static struct vm_area_struct *find_user_heap() +{ + // Get the memory descriptor of the current process. + task_struct *current_task = kernel_get_current_process(); + struct mm_struct *current_mm = current_task->mm; + + // Get the starting address of the heap. + uint32_t start_heap = current_mm->start_brk; + // If not set return NULL. + if(start_heap == 0) + { + return NULL; + } + + // Otherwise find the respective heap segment. + struct vm_area_struct *segment = current_mm->mmap; + while(segment->vm_start != start_heap) + { + segment = segment->vm_next; + } + + return segment; +} + +// TODO: rename in sys_brk +void *umalloc(unsigned int size) +{ + // Get user heap segment structure. + struct vm_area_struct *heap_segment = find_user_heap(); + + // Allocate the segment if don't exist. + if(heap_segment == NULL) + { + task_struct *current_task = kernel_get_current_process(); + struct mm_struct *current_mm = current_task->mm; + current_mm->start_brk = create_segment(current_mm, UHEAP_INITIAL_SIZE); + current_mm->brk = current_mm->start_brk; + // Reserved space for: + // 1) First memory block. + // static block_t *head = NULL; + // 2) Last memory block. + // static block_t *tail = NULL; + // 3) All the memory blocks that are freed. + // static block_t *freelist = NULL; + current_mm->brk += 3 * sizeof(block_t *); + heap_segment = find_user_heap(); + } + + return __do_malloc(heap_segment, size); +} + +// TODO: rename in sys_brk +void ufree(void *p) +{ + // Get user heap segment structure. + struct vm_area_struct *heap_segment = find_user_heap(); + + // If the segment exists, user did a malloc previously. + if (heap_segment != NULL) + { + __do_free(heap_segment, p); + } +} + +void *usbrk(int increment) +{ + task_struct *current_task = kernel_get_current_process(); + struct mm_struct *task_mm = current_task->mm; + uint32_t *heap_curr = &task_mm->brk; + + struct vm_area_struct *heap_segment = find_user_heap(); + + return __do_brk(heap_curr, heap_segment, increment); +} + +void kheap_dump() +{ + // 1) First memory block. + // static block_t *head = NULL; + // 2) Last memory block. + // static block_t *tail = NULL; + // 3) All the memory blocks that are freed. + // static block_t *freelist = NULL; + + // We will use these in writing. + uint32_t *head = (uint32_t *) (kernel_heap.vm_start); + uint32_t *tail = (uint32_t *) (kernel_heap.vm_start + sizeof(block_t *)); + uint32_t *freelist = (uint32_t *) (kernel_heap.vm_start + 2 * sizeof(block_t *)); + assert(head && tail && freelist && "Heap block lists point to null."); + + // We will use these others in reading. + block_t *head_block = (block_t *) *head; + // block_t *tail_block = (block_t *) *tail; + block_t *first_free_block = (block_t *) *freelist; + + if (!head_block) + { + dbg_print("your heap is empty now\n"); + + return; + } + + // dbg_print("HEAP:\n"); + uint32_t total = 0; + uint32_t total_overhead = 0; + block_t * it = head_block; + while (it) + { + dbg_print("[%c] %12u (%12u) from 0x%p to 0x%p\n", + (blkmngr_is_free(it)) ? 'F' : 'A', + get_real_size(it->size), + it->size, + it, + (void *) it + OVERHEAD + get_real_size(it->size)); + total += get_real_size(it->size); + total_overhead += OVERHEAD; + + it = it->next; + } + dbg_print("\nTotal usable bytes : %d", total); + dbg_print("\nTotal overhead bytes : %d", total_overhead); + dbg_print("\nTotal bytes : %d", total + total_overhead); + dbg_print("\nFreelist: "); + for (it = first_free_block; it != NULL; it = it->nextfree) + { + dbg_print("(%p)->", it); + } + dbg_print("\n\n"); +} + +uint32_t get_kheap_start() +{ + return kernel_heap.vm_start; +} + +uint32_t get_kheap_curr() +{ + return kernel_heap_curr; +} diff --git a/mentos/src/mem/paging.c b/mentos/src/mem/paging.c index e304439..2bf482f 100644 --- a/mentos/src/mem/paging.c +++ b/mentos/src/mem/paging.c @@ -1,88 +1,88 @@ -/// MentOS, The Mentoring Operating system project -/// @file paging.c -/// @brief Implementation of a memory paging management. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "paging.h" -#include "zone_allocator.h" -#include "kheap.h" -#include "debug.h" -#include "assert.h" -#include "string.h" - -bool_t paging_is_enabled() -{ - return false; -} - -struct mm_struct *create_process_image(size_t stack_size) -{ - // Allocate the mm_struct. - struct mm_struct *mm = kmalloc(sizeof(struct mm_struct)); - memset(mm, 0, sizeof(struct mm_struct)); - - // Allocate the stack segment. - mm->start_stack = create_segment(mm, stack_size); - - return mm; -} - -uint32_t create_segment(struct mm_struct *mm, size_t size) -{ - // Allocate on kernel space the structure for the segment. - struct vm_area_struct *new_segment = kmalloc(sizeof(struct vm_area_struct)); - - // Allocate the space requested for the segment on user space. - if (paging_is_enabled()) { - assert(0 && "Paging must not be enabled"); - } - - unsigned int order = find_nearest_order_greater(size); - uint32_t vm_start = __alloc_pages(GFP_HIGHUSER, order); - - // Update vm_area_struct info. - new_segment->vm_start = vm_start; - new_segment->vm_end = vm_start + (1 << order) * PAGE_SIZE; - new_segment->vm_mm = mm; - - // Update memory descriptor list of vm_area_struct. - new_segment->vm_next = mm->mmap; - mm->mmap = new_segment; - mm->mmap_cache = new_segment; - - // Update memory descriptor info. - mm->map_count++; - - mm->total_vm += (1 << order); - - return vm_start; -} - -void destroy_process_image(struct mm_struct *mm) -{ - assert(mm != NULL); - - // Free each segment inside mm. - struct vm_area_struct *segment = mm->mmap; - while (segment != NULL) { - // Free the pages represented by the segment. - if (paging_is_enabled()) { - assert(0 && "Paging must not be enabled"); - } - - size_t size = segment->vm_end - segment->vm_start; - unsigned int order = find_nearest_order_greater(size); - - free_pages(segment->vm_start, order); - - struct vm_area_struct *tmp = segment; - segment = segment->vm_next; - - // Free the vm_area_struct. - kfree(tmp); - } - - // Free the mm_struct. - kfree(mm); -} +/// MentOS, The Mentoring Operating system project +/// @file paging.c +/// @brief Implementation of a memory paging management. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "paging.h" +#include "zone_allocator.h" +#include "kheap.h" +#include "debug.h" +#include "assert.h" +#include "string.h" + +bool_t paging_is_enabled() +{ + return false; +} + +struct mm_struct *create_process_image(size_t stack_size) +{ + // Allocate the mm_struct. + struct mm_struct *mm = kmalloc(sizeof(struct mm_struct)); + memset(mm, 0, sizeof(struct mm_struct)); + + // Allocate the stack segment. + mm->start_stack = create_segment(mm, stack_size); + + return mm; +} + +uint32_t create_segment(struct mm_struct *mm, size_t size) +{ + // Allocate on kernel space the structure for the segment. + struct vm_area_struct *new_segment = kmalloc(sizeof(struct vm_area_struct)); + + // Allocate the space requested for the segment on user space. + if (paging_is_enabled()) { + assert(0 && "Paging must not be enabled"); + } + + unsigned int order = find_nearest_order_greater(size); + uint32_t vm_start = __alloc_pages(GFP_HIGHUSER, order); + + // Update vm_area_struct info. + new_segment->vm_start = vm_start; + new_segment->vm_end = vm_start + (1 << order) * PAGE_SIZE; + new_segment->vm_mm = mm; + + // Update memory descriptor list of vm_area_struct. + new_segment->vm_next = mm->mmap; + mm->mmap = new_segment; + mm->mmap_cache = new_segment; + + // Update memory descriptor info. + mm->map_count++; + + mm->total_vm += (1 << order); + + return vm_start; +} + +void destroy_process_image(struct mm_struct *mm) +{ + assert(mm != NULL); + + // Free each segment inside mm. + struct vm_area_struct *segment = mm->mmap; + while (segment != NULL) { + // Free the pages represented by the segment. + if (paging_is_enabled()) { + assert(0 && "Paging must not be enabled"); + } + + size_t size = segment->vm_end - segment->vm_start; + unsigned int order = find_nearest_order_greater(size); + + free_pages(segment->vm_start, order); + + struct vm_area_struct *tmp = segment; + segment = segment->vm_next; + + // Free the vm_area_struct. + kfree(tmp); + } + + // Free the mm_struct. + kfree(mm); +} diff --git a/mentos/src/mem/zone_allocator.c b/mentos/src/mem/zone_allocator.c index ddb3989..859e3fc 100644 --- a/mentos/src/mem/zone_allocator.c +++ b/mentos/src/mem/zone_allocator.c @@ -1,474 +1,474 @@ -/// MentOS, The Mentoring Operating system project -/// @file zone_allocator.c -/// @brief Implementation of the Zone Allocator -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "zone_allocator.h" -#include "buddysystem.h" -#include "debug.h" -#include "kheap.h" -#include "kernel.h" -#include "assert.h" -#include "paging.h" - -#define MAX_ORDER_ALIGN(addr) \ - ((addr) & (~(PAGE_SIZE * (1 << (MAX_ORDER - 1)) - 1))) + \ - (PAGE_SIZE * (1 << (MAX_ORDER - 1))) - -/// Defined in kernel.ld, points at the end of kernel's data segment. -extern uint32_t end; - -/// End address of the kernel's data segment. -static uint8_t *_mmngr_memory_start = (uint8_t *)(&end); - -/// Array of all physical blocks -page_t *mem_map = NULL; - -/// Memory node. -pg_data_t *contig_page_data = NULL; - -/// @brief Get the zone that contains a page frame. -/// @param page A page descriptor. -/// @return The zone requested. -static zone_t *get_zone_from_page(page_t *page) -{ - zone_t *zone = NULL; - int nr_zones = contig_page_data->nr_zones; - - for (int zone_index = 0; zone_index < nr_zones; zone_index++) { - zone = contig_page_data->node_zones + zone_index; - page_t *last_page = zone->zone_mem_map + zone->size; - - if (page < last_page) { - return zone; - } - } - - // Error: page is over memory size. - return (zone_t *)NULL; -} - -/// @brief Get a zone from gfp_mask -/// @param gfp_mask GFP_FLAG see gfp.h. -/// @return The zone requested. -static zone_t *get_zone_from_flags(gfp_t gfp_mask) -{ - switch (gfp_mask) { - case GFP_KERNEL: - case GFP_ATOMIC: - case GFP_NOFS: - case GFP_NOIO: - case GFP_NOWAIT: - return &contig_page_data->node_zones[ZONE_NORMAL]; - case GFP_HIGHUSER: - return &contig_page_data->node_zones[ZONE_HIGHMEM]; - default: - return (zone_t *)NULL; - } -} - -static bool_t is_memory_clean(gfp_t gfp_mask) -{ - bool_t memory_clean = true; - zone_t *zone = get_zone_from_flags(gfp_mask); - assert((zone != NULL) && "Invalid zone flag!"); - -#ifdef ENABLE_BUDDYSYSTEM - /* Check every field nr_free of the buddy system - * descriptor of the zone that all blocks are - * allocated on the last free list. - */ - unsigned int order = 0; - for (; order < MAX_ORDER - 1; ++order) { - free_area_t *area = zone->free_area + order; - if (area->nr_free != 0) { - memory_clean = false; - - break; - } - } - - if (memory_clean && - (zone->free_area[order].nr_free != (zone->size / (1UL << order)))) { - memory_clean = false; - } - -#else - /* Check every field _count of the page descriptor - * of the zone as free. - */ - for (int i = 0; i < zone->size; ++i) { - page_t *page = zone->zone_mem_map + i; - if (page->_count != -1) { - memory_clean = false; - - break; - } - } -#endif - - return memory_clean; -} - -/// @brief Checks if the physical memory manager is working properly. -/// @return If the check was done correctly. -static bool_t pmm_check() -{ - dbg_print( - "\n=================== ZONE ALLOCATOR TEST ==================== \n"); - - dbg_print("\t[STEP1] One page frame in kernel-space... "); - dbg_print("\n\t ===== [STEP1] One page frame in kernel-space ====\n"); - uint32_t ptr1 = __alloc_page(GFP_KERNEL); - free_page(ptr1); - if (!is_memory_clean(GFP_KERNEL)) { - return false; - } - - dbg_print("\t[STEP2] Five page frames in user-space... "); - dbg_print("\n\t ===== [STEP2] Five page frames in user-space ====\n"); - uint32_t ptr2[5]; - for (int i = 0; i < 5; i++) { - ptr2[i] = __alloc_page(GFP_HIGHUSER); - } - for (int i = 0; i < 5; i++) { - free_page(ptr2[i]); - } - if (!is_memory_clean(GFP_HIGHUSER)) { - return false; - } - - dbg_print("\t[STEP3] 2^{3} page frames in kernel-space... "); - dbg_print("\n\t ===== [STEP3] 2^{3} page frames in kernel-space ====\n"); - uint32_t ptr3 = __alloc_pages(GFP_KERNEL, 3); - free_pages(ptr3, 3); - if (!is_memory_clean(GFP_KERNEL)) { - return false; - } - - dbg_print("\t[STEP4] Five 2^{i} page frames in user-space... "); - dbg_print("\n\t ===== [STEP4] Five 2^{i} page frames in user-space ====\n"); - uint32_t ptr4[5]; - for (int i = 0; i < 5; i++) { - ptr4[i] = __alloc_pages(GFP_HIGHUSER, i); - } - for (int i = 0; i < 5; i++) { - free_pages(ptr4[i], i); - } - if (!is_memory_clean(GFP_HIGHUSER)) { - return false; - } - - dbg_print("\t[STEP5] Mixed page frames in kernel-space... "); - dbg_print("\n\t ===== [STEP5] Mixed page frames in kernel-space ====\n"); - int **ptr = (int **)__alloc_page(GFP_KERNEL); - int i = 0; - for (; i < 5; ++i) { - ptr[i] = (int *)__alloc_page(GFP_KERNEL); - } - for (; i < 20; ++i) { - ptr[i] = (int *)__alloc_pages(GFP_KERNEL, 2); - } - - int j = 0; - for (; j < 5; ++j) { - free_page((uint32_t)ptr[j]); - } - for (; j < 20; ++j) { - free_pages((uint32_t)ptr[j], 2); - } - free_page((uint32_t)ptr1); - - if (!is_memory_clean(GFP_KERNEL)) { - return false; - } - return true; -} - -/// @brief Initialize Buddy System. -/// @param zone A memory zone. -static void buddy_system_init(zone_t *zone) -{ - // Initialize the free_lists of each area of the zone. - for (unsigned int order = 0; order < MAX_ORDER; order++) { - free_area_t *area = zone->free_area + order; - area->nr_free = 0; - list_head_init(&area->free_list); - } - - // Current base page descriptor of the zone. - page_t *page = zone->zone_mem_map; - // Address of the last page descriptor of the zone. - page_t *last_page = page + zone->size; - - // Get the free area collecting the larges block of page frames. - const unsigned int order = MAX_ORDER - 1; - free_area_t *area = zone->free_area + order; - - // Add all zone's pages to the largest free area block. - uint32_t block_size = 1UL << order; - while ((page + block_size) <= last_page) { - /* page has already the _count field set to -1, - * therefore only save the order of the page. - */ - page->private = order; - - // Insert page as first element in the list. - list_head_add_tail(&page->lru, &area->free_list); - // Increase the number of free block of the free_area_t. - area->nr_free++; - - page += block_size; - } - - assert(page == last_page && - "Memory size is not aligned to MAX_ORDER size!"); -} - -/// @brief Initializes the memory attributes. -/// @param name Zone's name. -/// @param zone_index Zone's index. -/// @param adr_from the lowest address of the zone -/// @param adr_to the highest address of the zone (not included!) -static void zone_init(char *name, int zone_index, uint32_t adr_from, - uint32_t adr_to) -{ - assert((adr_from < adr_to) && ((adr_from & 0xfffff000) == adr_from) && - ((adr_to & 0xfffff000) == adr_to) && - "Inserted bad block addresses!"); - - // Take the zone_t structure that correspondes to the zone_index. - zone_t *zone = contig_page_data->node_zones + zone_index; - - // Number of page frames in the zone. - size_t num_page_frames = (adr_to - adr_from) / PAGE_SIZE; - - // Index of the first page frame of the zone. - uint32_t first_page_frame = adr_from / PAGE_SIZE; - - // Update zone info. - zone->name = name; - zone->size = num_page_frames; - zone->free_pages = num_page_frames; - zone->zone_mem_map = mem_map + first_page_frame; - zone->zone_start_pfn = first_page_frame; - - dbg_print("ZONE %s, first page: %p, last page: %p, npages:%d\n", zone->name, - zone->zone_mem_map, zone->zone_mem_map + zone->size, zone->size); - -#ifdef ENABLE_BUDDYSYSTEM - buddy_system_init(zone); - buddy_system_dump(zone); -#endif -} - -unsigned int find_nearest_order_greater(uint32_t amount) -{ - amount = (amount + PAGE_SIZE - 1) / PAGE_SIZE; - unsigned int order = 0; - while ((1UL << order) < amount) { - ++order; - } - - return order; -} - -bool_t pmmngr_init(uint32_t mem_size) -{ - //==== Get RAM size ===================================================== - // Align mem_size to a page frame size, namely 4KB. - uint32_t _mmngr_memory_size = MAX_ORDER_ALIGN(mem_size); - - // Total number of blocks (all RAM). - uint32_t _mmngr_num_frames = _mmngr_memory_size / PAGE_SIZE; - //======================================================================= - - //==== Skip modules ===================================================== - dbg_print("[PMM] Start memory address previous skip modules : 0x%p \n", - _mmngr_memory_start); - - for (int i = 0; i < MAX_MODULES; i++) { - uint8_t *skip_addr = (uint8_t *)module_end[i]; - if (skip_addr != NULL && _mmngr_memory_start < skip_addr) { - _mmngr_memory_start = skip_addr; - } - } - - dbg_print("[PMM] Start memory address after skip modules : 0x%p \n", - _mmngr_memory_start); - //======================================================================= - - //==== Initialize array of page_t ======================================= - dbg_print("[PMM] Initializing memory map structure...\n"); - mem_map = (page_t *)_mmngr_memory_start; - - // Initialize each page_t. - for (int page_index = 0; page_index < _mmngr_num_frames; ++page_index) { - page_t *page = mem_map + page_index; - // Mark page as free. - page->_count = -1; - list_head_init(&(page->lru)); - } - //======================================================================= - - //==== Skip memory space used for page_t[] ============================== - _mmngr_memory_start += sizeof(page_t) * _mmngr_num_frames; - dbg_print( - "[PMM] Size of mem_map : %i byte [0x%p - 0x%p]\n", - (void *)_mmngr_memory_start - (void *)mem_map, mem_map, - _mmngr_memory_start); - //======================================================================= - - //==== Initialize contig_page_data node ================================= - dbg_print("[PMM] Initializing contig_page_data node...\n"); - contig_page_data = (pg_data_t *)_mmngr_memory_start; - // ZONE_NORMAL and ZONE_HIGHMEM - contig_page_data->nr_zones = __MAX_NR_ZONES; - // NID start from 0. - contig_page_data->node_id = 0; - // Corresponds with mem_map. - contig_page_data->node_mem_map = mem_map; - // In UMA we have only one node. - contig_page_data->node_next = NULL; - // All the memory. - contig_page_data->node_size = _mmngr_num_frames; - // mem_map[0]. - contig_page_data->node_start_mapnr = 0; - // The first physical page. - contig_page_data->node_start_paddr = 0x0; - //======================================================================= - - //==== Skip memory space used for pg_data_t ============================= - _mmngr_memory_start += sizeof(pg_data_t); - //======================================================================= - - //==== Initialize zones zone_t ========================================== - dbg_print("[PMM] Initializing zones...\n"); - - // ZONE_NORMAL [ memory_start - mem_size/4 ] - uint32_t start_normal_addr = MAX_ORDER_ALIGN((uint32_t)_mmngr_memory_start); - uint32_t stop_normal_addr = MAX_ORDER_ALIGN(_mmngr_memory_size >> 2); - zone_init("Normal", ZONE_NORMAL, start_normal_addr, stop_normal_addr); - - // ZONE_HIGHMEM [ mem_size/4 - mem_size ] - uint32_t start_high_addr = stop_normal_addr; - uint32_t stop_high_addr = _mmngr_memory_size; - zone_init("HighMem", ZONE_HIGHMEM, start_high_addr, stop_high_addr); - //======================================================================= - - dbg_print("[PMM] Memory Size : %u MB \n", - _mmngr_memory_size / M); - dbg_print("[PMM] Total page frames (MemorySize/4096) : %u \n", - _mmngr_num_frames); - dbg_print("[PMM] mem_map address : 0x%p \n", - mem_map); - dbg_print("[PMM] Memory Start : 0x%p \n", - _mmngr_memory_start); - - return pmm_check(); -} - -uint32_t __alloc_page(gfp_t gfp_mask) -{ - return __alloc_pages(gfp_mask, 0); -} - -void free_page(uint32_t addr) -{ - free_pages(addr, 0); -} - -uint32_t __alloc_pages(gfp_t gfp_mask, uint32_t order) -{ - zone_t *zone = get_zone_from_flags(gfp_mask); - assert((zone != NULL) && "Invalid zone flag!"); - assert((order <= (MAX_ORDER - 1)) && "Invalid order!"); - - int block_size = 1UL << order; - - page_t *page = NULL; -#ifdef ENABLE_BUDDYSYSTEM - // Search for a block of page frames by using the BuddySystem. - page = bb_alloc_pages(zone, order); - -#else - // First page of the zone. - page_t *block = zone->zone_mem_map; - // Last page of the zone. - page_t *last_frame = zone->zone_mem_map + zone->size - order + 1; - // When true, then we found a block of pages - int found = 0; - // Search for a block of pages - while (block < last_frame && found == 0) { - // Suppose this is the right block. - found = 1; - // Check if enough pages are available in current block. - for (unsigned int i = 0; i < block_size; ++i) { - found = ((block + i)->_count == -1); - if (!found) { - /* The block is not large enough. We have to skip it - * and restart to search for another one. - */ - block += i + 1; - - break; - } - } - - if (found) { - // Set the found block of pages as taken, and not available. - for (unsigned int i = 0; i < block_size; ++i) { - (block + i)->_count = 0; - } - } - } - page = (found == 1) ? block : NULL; -#endif - - uint32_t block_frame_adr = -1; - if (page != NULL) { - // Decrement the number of pages in the zone. - zone->free_pages -= block_size; - // Get the index of the first page frame of the block. - uint32_t delta_block_frame = (uint32_t)(page - zone->zone_mem_map); - block_frame_adr = zone->zone_start_pfn + delta_block_frame; - block_frame_adr = block_frame_adr * PAGE_SIZE; - } - - if (block_frame_adr == -1) { - dbg_print("MEM. REQUEST FAILED"); - } else { - dbg_print("BS-G: addr: %p (page: %p order: %d)\n", block_frame_adr, - page, order); - } - - return block_frame_adr; -} - -void free_pages(uint32_t addr, uint32_t order) -{ - page_t *page = mem_map + (addr / PAGE_SIZE); - zone_t *zone = get_zone_from_page(page); - assert((zone != NULL) && "Page is over memory size"); - - int block_size = 1UL << order; - -#ifdef ENABLE_BUDDYSYSTEM - bb_free_pages(zone, page, order); -#else - // Set the given block of page frames as free, and available again. - for (unsigned int i = 0; i < block_size; ++i) { - (page + i)->_count = -1; - } -#endif - - zone->free_pages += block_size; - - dbg_print("BS-F: addr: %p (page: %p order: %d)\n", addr, page, order); -} - -uint32_t get_memory_start() -{ - return (uint32_t)_mmngr_memory_start; -} +/// MentOS, The Mentoring Operating system project +/// @file zone_allocator.c +/// @brief Implementation of the Zone Allocator +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "zone_allocator.h" +#include "buddysystem.h" +#include "debug.h" +#include "kheap.h" +#include "kernel.h" +#include "assert.h" +#include "paging.h" + +#define MAX_ORDER_ALIGN(addr) \ + ((addr) & (~(PAGE_SIZE * (1 << (MAX_ORDER - 1)) - 1))) + \ + (PAGE_SIZE * (1 << (MAX_ORDER - 1))) + +/// Defined in kernel.ld, points at the end of kernel's data segment. +extern uint32_t end; + +/// End address of the kernel's data segment. +static uint8_t *_mmngr_memory_start = (uint8_t *)(&end); + +/// Array of all physical blocks +page_t *mem_map = NULL; + +/// Memory node. +pg_data_t *contig_page_data = NULL; + +/// @brief Get the zone that contains a page frame. +/// @param page A page descriptor. +/// @return The zone requested. +static zone_t *get_zone_from_page(page_t *page) +{ + zone_t *zone = NULL; + int nr_zones = contig_page_data->nr_zones; + + for (int zone_index = 0; zone_index < nr_zones; zone_index++) { + zone = contig_page_data->node_zones + zone_index; + page_t *last_page = zone->zone_mem_map + zone->size; + + if (page < last_page) { + return zone; + } + } + + // Error: page is over memory size. + return (zone_t *)NULL; +} + +/// @brief Get a zone from gfp_mask +/// @param gfp_mask GFP_FLAG see gfp.h. +/// @return The zone requested. +static zone_t *get_zone_from_flags(gfp_t gfp_mask) +{ + switch (gfp_mask) { + case GFP_KERNEL: + case GFP_ATOMIC: + case GFP_NOFS: + case GFP_NOIO: + case GFP_NOWAIT: + return &contig_page_data->node_zones[ZONE_NORMAL]; + case GFP_HIGHUSER: + return &contig_page_data->node_zones[ZONE_HIGHMEM]; + default: + return (zone_t *)NULL; + } +} + +static bool_t is_memory_clean(gfp_t gfp_mask) +{ + bool_t memory_clean = true; + zone_t *zone = get_zone_from_flags(gfp_mask); + assert((zone != NULL) && "Invalid zone flag!"); + +#ifdef ENABLE_BUDDYSYSTEM + /* Check every field nr_free of the buddy system + * descriptor of the zone that all blocks are + * allocated on the last free list. + */ + unsigned int order = 0; + for (; order < MAX_ORDER - 1; ++order) { + free_area_t *area = zone->free_area + order; + if (area->nr_free != 0) { + memory_clean = false; + + break; + } + } + + if (memory_clean && + (zone->free_area[order].nr_free != (zone->size / (1UL << order)))) { + memory_clean = false; + } + +#else + /* Check every field _count of the page descriptor + * of the zone as free. + */ + for (int i = 0; i < zone->size; ++i) { + page_t *page = zone->zone_mem_map + i; + if (page->_count != -1) { + memory_clean = false; + + break; + } + } +#endif + + return memory_clean; +} + +/// @brief Checks if the physical memory manager is working properly. +/// @return If the check was done correctly. +static bool_t pmm_check() +{ + dbg_print( + "\n=================== ZONE ALLOCATOR TEST ==================== \n"); + + dbg_print("\t[STEP1] One page frame in kernel-space... "); + dbg_print("\n\t ===== [STEP1] One page frame in kernel-space ====\n"); + uint32_t ptr1 = __alloc_page(GFP_KERNEL); + free_page(ptr1); + if (!is_memory_clean(GFP_KERNEL)) { + return false; + } + + dbg_print("\t[STEP2] Five page frames in user-space... "); + dbg_print("\n\t ===== [STEP2] Five page frames in user-space ====\n"); + uint32_t ptr2[5]; + for (int i = 0; i < 5; i++) { + ptr2[i] = __alloc_page(GFP_HIGHUSER); + } + for (int i = 0; i < 5; i++) { + free_page(ptr2[i]); + } + if (!is_memory_clean(GFP_HIGHUSER)) { + return false; + } + + dbg_print("\t[STEP3] 2^{3} page frames in kernel-space... "); + dbg_print("\n\t ===== [STEP3] 2^{3} page frames in kernel-space ====\n"); + uint32_t ptr3 = __alloc_pages(GFP_KERNEL, 3); + free_pages(ptr3, 3); + if (!is_memory_clean(GFP_KERNEL)) { + return false; + } + + dbg_print("\t[STEP4] Five 2^{i} page frames in user-space... "); + dbg_print("\n\t ===== [STEP4] Five 2^{i} page frames in user-space ====\n"); + uint32_t ptr4[5]; + for (int i = 0; i < 5; i++) { + ptr4[i] = __alloc_pages(GFP_HIGHUSER, i); + } + for (int i = 0; i < 5; i++) { + free_pages(ptr4[i], i); + } + if (!is_memory_clean(GFP_HIGHUSER)) { + return false; + } + + dbg_print("\t[STEP5] Mixed page frames in kernel-space... "); + dbg_print("\n\t ===== [STEP5] Mixed page frames in kernel-space ====\n"); + int **ptr = (int **)__alloc_page(GFP_KERNEL); + int i = 0; + for (; i < 5; ++i) { + ptr[i] = (int *)__alloc_page(GFP_KERNEL); + } + for (; i < 20; ++i) { + ptr[i] = (int *)__alloc_pages(GFP_KERNEL, 2); + } + + int j = 0; + for (; j < 5; ++j) { + free_page((uint32_t)ptr[j]); + } + for (; j < 20; ++j) { + free_pages((uint32_t)ptr[j], 2); + } + free_page((uint32_t)ptr1); + + if (!is_memory_clean(GFP_KERNEL)) { + return false; + } + return true; +} + +/// @brief Initialize Buddy System. +/// @param zone A memory zone. +static void buddy_system_init(zone_t *zone) +{ + // Initialize the free_lists of each area of the zone. + for (unsigned int order = 0; order < MAX_ORDER; order++) { + free_area_t *area = zone->free_area + order; + area->nr_free = 0; + list_head_init(&area->free_list); + } + + // Current base page descriptor of the zone. + page_t *page = zone->zone_mem_map; + // Address of the last page descriptor of the zone. + page_t *last_page = page + zone->size; + + // Get the free area collecting the larges block of page frames. + const unsigned int order = MAX_ORDER - 1; + free_area_t *area = zone->free_area + order; + + // Add all zone's pages to the largest free area block. + uint32_t block_size = 1UL << order; + while ((page + block_size) <= last_page) { + /* page has already the _count field set to -1, + * therefore only save the order of the page. + */ + page->private = order; + + // Insert page as first element in the list. + list_head_add_tail(&page->lru, &area->free_list); + // Increase the number of free block of the free_area_t. + area->nr_free++; + + page += block_size; + } + + assert(page == last_page && + "Memory size is not aligned to MAX_ORDER size!"); +} + +/// @brief Initializes the memory attributes. +/// @param name Zone's name. +/// @param zone_index Zone's index. +/// @param adr_from the lowest address of the zone +/// @param adr_to the highest address of the zone (not included!) +static void zone_init(char *name, int zone_index, uint32_t adr_from, + uint32_t adr_to) +{ + assert((adr_from < adr_to) && ((adr_from & 0xfffff000) == adr_from) && + ((adr_to & 0xfffff000) == adr_to) && + "Inserted bad block addresses!"); + + // Take the zone_t structure that correspondes to the zone_index. + zone_t *zone = contig_page_data->node_zones + zone_index; + + // Number of page frames in the zone. + size_t num_page_frames = (adr_to - adr_from) / PAGE_SIZE; + + // Index of the first page frame of the zone. + uint32_t first_page_frame = adr_from / PAGE_SIZE; + + // Update zone info. + zone->name = name; + zone->size = num_page_frames; + zone->free_pages = num_page_frames; + zone->zone_mem_map = mem_map + first_page_frame; + zone->zone_start_pfn = first_page_frame; + + dbg_print("ZONE %s, first page: %p, last page: %p, npages:%d\n", zone->name, + zone->zone_mem_map, zone->zone_mem_map + zone->size, zone->size); + +#ifdef ENABLE_BUDDYSYSTEM + buddy_system_init(zone); + buddy_system_dump(zone); +#endif +} + +unsigned int find_nearest_order_greater(uint32_t amount) +{ + amount = (amount + PAGE_SIZE - 1) / PAGE_SIZE; + unsigned int order = 0; + while ((1UL << order) < amount) { + ++order; + } + + return order; +} + +bool_t pmmngr_init(uint32_t mem_size) +{ + //==== Get RAM size ===================================================== + // Align mem_size to a page frame size, namely 4KB. + uint32_t _mmngr_memory_size = MAX_ORDER_ALIGN(mem_size); + + // Total number of blocks (all RAM). + uint32_t _mmngr_num_frames = _mmngr_memory_size / PAGE_SIZE; + //======================================================================= + + //==== Skip modules ===================================================== + dbg_print("[PMM] Start memory address previous skip modules : 0x%p \n", + _mmngr_memory_start); + + for (int i = 0; i < MAX_MODULES; i++) { + uint8_t *skip_addr = (uint8_t *)module_end[i]; + if (skip_addr != NULL && _mmngr_memory_start < skip_addr) { + _mmngr_memory_start = skip_addr; + } + } + + dbg_print("[PMM] Start memory address after skip modules : 0x%p \n", + _mmngr_memory_start); + //======================================================================= + + //==== Initialize array of page_t ======================================= + dbg_print("[PMM] Initializing memory map structure...\n"); + mem_map = (page_t *)_mmngr_memory_start; + + // Initialize each page_t. + for (int page_index = 0; page_index < _mmngr_num_frames; ++page_index) { + page_t *page = mem_map + page_index; + // Mark page as free. + page->_count = -1; + list_head_init(&(page->lru)); + } + //======================================================================= + + //==== Skip memory space used for page_t[] ============================== + _mmngr_memory_start += sizeof(page_t) * _mmngr_num_frames; + dbg_print( + "[PMM] Size of mem_map : %i byte [0x%p - 0x%p]\n", + (void *)_mmngr_memory_start - (void *)mem_map, mem_map, + _mmngr_memory_start); + //======================================================================= + + //==== Initialize contig_page_data node ================================= + dbg_print("[PMM] Initializing contig_page_data node...\n"); + contig_page_data = (pg_data_t *)_mmngr_memory_start; + // ZONE_NORMAL and ZONE_HIGHMEM + contig_page_data->nr_zones = __MAX_NR_ZONES; + // NID start from 0. + contig_page_data->node_id = 0; + // Corresponds with mem_map. + contig_page_data->node_mem_map = mem_map; + // In UMA we have only one node. + contig_page_data->node_next = NULL; + // All the memory. + contig_page_data->node_size = _mmngr_num_frames; + // mem_map[0]. + contig_page_data->node_start_mapnr = 0; + // The first physical page. + contig_page_data->node_start_paddr = 0x0; + //======================================================================= + + //==== Skip memory space used for pg_data_t ============================= + _mmngr_memory_start += sizeof(pg_data_t); + //======================================================================= + + //==== Initialize zones zone_t ========================================== + dbg_print("[PMM] Initializing zones...\n"); + + // ZONE_NORMAL [ memory_start - mem_size/4 ] + uint32_t start_normal_addr = MAX_ORDER_ALIGN((uint32_t)_mmngr_memory_start); + uint32_t stop_normal_addr = MAX_ORDER_ALIGN(_mmngr_memory_size >> 2); + zone_init("Normal", ZONE_NORMAL, start_normal_addr, stop_normal_addr); + + // ZONE_HIGHMEM [ mem_size/4 - mem_size ] + uint32_t start_high_addr = stop_normal_addr; + uint32_t stop_high_addr = _mmngr_memory_size; + zone_init("HighMem", ZONE_HIGHMEM, start_high_addr, stop_high_addr); + //======================================================================= + + dbg_print("[PMM] Memory Size : %u MB \n", + _mmngr_memory_size / M); + dbg_print("[PMM] Total page frames (MemorySize/4096) : %u \n", + _mmngr_num_frames); + dbg_print("[PMM] mem_map address : 0x%p \n", + mem_map); + dbg_print("[PMM] Memory Start : 0x%p \n", + _mmngr_memory_start); + + return pmm_check(); +} + +uint32_t __alloc_page(gfp_t gfp_mask) +{ + return __alloc_pages(gfp_mask, 0); +} + +void free_page(uint32_t addr) +{ + free_pages(addr, 0); +} + +uint32_t __alloc_pages(gfp_t gfp_mask, uint32_t order) +{ + zone_t *zone = get_zone_from_flags(gfp_mask); + assert((zone != NULL) && "Invalid zone flag!"); + assert((order <= (MAX_ORDER - 1)) && "Invalid order!"); + + int block_size = 1UL << order; + + page_t *page = NULL; +#ifdef ENABLE_BUDDYSYSTEM + // Search for a block of page frames by using the BuddySystem. + page = bb_alloc_pages(zone, order); + +#else + // First page of the zone. + page_t *block = zone->zone_mem_map; + // Last page of the zone. + page_t *last_frame = zone->zone_mem_map + zone->size - order + 1; + // When true, then we found a block of pages + int found = 0; + // Search for a block of pages + while (block < last_frame && found == 0) { + // Suppose this is the right block. + found = 1; + // Check if enough pages are available in current block. + for (unsigned int i = 0; i < block_size; ++i) { + found = ((block + i)->_count == -1); + if (!found) { + /* The block is not large enough. We have to skip it + * and restart to search for another one. + */ + block += i + 1; + + break; + } + } + + if (found) { + // Set the found block of pages as taken, and not available. + for (unsigned int i = 0; i < block_size; ++i) { + (block + i)->_count = 0; + } + } + } + page = (found == 1) ? block : NULL; +#endif + + uint32_t block_frame_adr = -1; + if (page != NULL) { + // Decrement the number of pages in the zone. + zone->free_pages -= block_size; + // Get the index of the first page frame of the block. + uint32_t delta_block_frame = (uint32_t)(page - zone->zone_mem_map); + block_frame_adr = zone->zone_start_pfn + delta_block_frame; + block_frame_adr = block_frame_adr * PAGE_SIZE; + } + + if (block_frame_adr == -1) { + dbg_print("MEM. REQUEST FAILED"); + } else { + dbg_print("BS-G: addr: %p (page: %p order: %d)\n", block_frame_adr, + page, order); + } + + return block_frame_adr; +} + +void free_pages(uint32_t addr, uint32_t order) +{ + page_t *page = mem_map + (addr / PAGE_SIZE); + zone_t *zone = get_zone_from_page(page); + assert((zone != NULL) && "Page is over memory size"); + + int block_size = 1UL << order; + +#ifdef ENABLE_BUDDYSYSTEM + bb_free_pages(zone, page, order); +#else + // Set the given block of page frames as free, and available again. + for (unsigned int i = 0; i < block_size; ++i) { + (page + i)->_count = -1; + } +#endif + + zone->free_pages += block_size; + + dbg_print("BS-F: addr: %p (page: %p order: %d)\n", addr, page, order); +} + +uint32_t get_memory_start() +{ + return (uint32_t)_mmngr_memory_start; +} diff --git a/mentos/src/misc/bitops.c b/mentos/src/misc/bitops.c index 7bcecbf..68861b4 100644 --- a/mentos/src/misc/bitops.c +++ b/mentos/src/misc/bitops.c @@ -1,38 +1,38 @@ -/// MentOS, The Mentoring Operating system project -/// @file bitops.c -/// @brief Bitmasks functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "bitops.h" -#include "video.h" - -int find_first_bit(unsigned short int irq_mask) -{ - int i = 0; - if (irq_mask == 0) { - return 0; - } - for (i = 0; i < 8; i++) { - if ((1 << i) & irq_mask) { - break; - } - } - - return i; -} - -bool_t has_flag(uint32_t flags, uint32_t flag) -{ - return (bool_t)((flags & flag) != 0); -} - -void set_flag(uint32_t *flags, uint32_t flag) -{ - (*flags) |= flag; -} - -void clear_flag(uint32_t *flags, uint32_t flag) -{ - (*flags) &= ~flag; -} +/// MentOS, The Mentoring Operating system project +/// @file bitops.c +/// @brief Bitmasks functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "bitops.h" +#include "video.h" + +int find_first_bit(unsigned short int irq_mask) +{ + int i = 0; + if (irq_mask == 0) { + return 0; + } + for (i = 0; i < 8; i++) { + if ((1 << i) & irq_mask) { + break; + } + } + + return i; +} + +bool_t has_flag(uint32_t flags, uint32_t flag) +{ + return (bool_t)((flags & flag) != 0); +} + +void set_flag(uint32_t *flags, uint32_t flag) +{ + (*flags) |= flag; +} + +void clear_flag(uint32_t *flags, uint32_t flag) +{ + (*flags) &= ~flag; +} diff --git a/mentos/src/misc/clock.c b/mentos/src/misc/clock.c index cfb2918..60f5bb1 100644 --- a/mentos/src/misc/clock.c +++ b/mentos/src/misc/clock.c @@ -1,178 +1,178 @@ -/// MentOS, The Mentoring Operating system project -/// @file clock.c -/// @brief Clock functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "clock.h" -#include "timer.h" -#include "stdio.h" -#include "stddef.h" -#include "port_io.h" - -time_t get_millisecond() -{ - return timer_get_subticks(); -} - -time_t get_second() -{ - outportb(0x70, SECOND_RTC); - time_t c = inportb(0x71); - - return c; -} - -time_t get_minute() -{ - outportb(0x70, MINUTE_RTC); - time_t c = inportb(0x71); - - return c; -} - -time_t get_hour() -{ - outportb(0x70, HOUR_RTC); - time_t c = inportb(0x71); - - return c; -} - -time_t get_day_w() -{ - outportb(0x70, DAY_W_RTC); - time_t c = inportb(0x71); - - return c; -} - -time_t get_day_m() -{ - outportb(0x70, DAY_M_RTC); - time_t c = inportb(0x71); - - return c; -} - -time_t get_month() -{ - outportb(0x70, MONTH_RTC); - time_t c = inportb(0x71); - - return c; -} - -time_t get_year() -{ - outportb(0x70, YEAR_RTC); - time_t c = inportb(0x71); - - return c; -} - -char *get_month_lng() -{ - switch (get_month()) { - case 1: - return "January"; - case 2: - return "February"; - case 3: - return "March"; - case 4: - return "April"; - case 5: - return "May"; - case 6: - return "June"; - case 7: - return "July"; - case 8: - return "August"; - case 9: - return "September"; - case 10: - return "October"; - case 11: - return "November"; - case 12: - return "December"; - default: - break; - } - return ""; -} - -char *get_day_lng() -{ - switch (get_day_w()) { - case 1: - return "Sunday"; - case 2: - return "Monday"; - case 3: - return "Tuesday"; - case 4: - return "Wednesday"; - case 5: - return "Thursday"; - case 6: - return "Friday"; - case 7: - return "Saturday"; - default: - break; - } - return ""; -} - -time_t time(time_t *timer) -{ - // Jan 1, 1970 - time_t t = 0; - t += get_millisecond(); - t += get_second(); - t += get_minute() * 60; - t += get_hour() * 3600; - t += get_day_m() * 86400; - t += get_month() * 2629743; - t += (1970 - get_year()) * 31556926; - if (timer != NULL) { - (*timer) = t; - } - - return t; -} - -time_t difftime(time_t time1, time_t time2) -{ - return time1 - time2; -} - -void strhourminutesecond(char *dst) -{ - time_t s, m, h; - s = get_second(); - m = get_minute(); - h = get_hour(); - - sprintf(dst, "%i:%i:%i", h, m, s); -} - -void strdaymonthyear(char *dst) -{ - sprintf(dst, "%s %i %s %i", get_day_lng(), get_day_m(), get_month_lng(), - 1970 - get_year()); -} - -void strdatehour(char *dst) -{ - time_t s, m, h; - s = get_second(); - m = get_minute(); - h = get_hour(); - - sprintf(dst, "%s %i %s %i %i:%i:%i", get_day_lng(), get_day_m(), - get_month_lng(), 1970 - get_year(), h, m, s); -} +/// MentOS, The Mentoring Operating system project +/// @file clock.c +/// @brief Clock functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "clock.h" +#include "timer.h" +#include "stdio.h" +#include "stddef.h" +#include "port_io.h" + +time_t get_millisecond() +{ + return timer_get_subticks(); +} + +time_t get_second() +{ + outportb(0x70, SECOND_RTC); + time_t c = inportb(0x71); + + return c; +} + +time_t get_minute() +{ + outportb(0x70, MINUTE_RTC); + time_t c = inportb(0x71); + + return c; +} + +time_t get_hour() +{ + outportb(0x70, HOUR_RTC); + time_t c = inportb(0x71); + + return c; +} + +time_t get_day_w() +{ + outportb(0x70, DAY_W_RTC); + time_t c = inportb(0x71); + + return c; +} + +time_t get_day_m() +{ + outportb(0x70, DAY_M_RTC); + time_t c = inportb(0x71); + + return c; +} + +time_t get_month() +{ + outportb(0x70, MONTH_RTC); + time_t c = inportb(0x71); + + return c; +} + +time_t get_year() +{ + outportb(0x70, YEAR_RTC); + time_t c = inportb(0x71); + + return c; +} + +char *get_month_lng() +{ + switch (get_month()) { + case 1: + return "January"; + case 2: + return "February"; + case 3: + return "March"; + case 4: + return "April"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "August"; + case 9: + return "September"; + case 10: + return "October"; + case 11: + return "November"; + case 12: + return "December"; + default: + break; + } + return ""; +} + +char *get_day_lng() +{ + switch (get_day_w()) { + case 1: + return "Sunday"; + case 2: + return "Monday"; + case 3: + return "Tuesday"; + case 4: + return "Wednesday"; + case 5: + return "Thursday"; + case 6: + return "Friday"; + case 7: + return "Saturday"; + default: + break; + } + return ""; +} + +time_t time(time_t *timer) +{ + // Jan 1, 1970 + time_t t = 0; + t += get_millisecond(); + t += get_second(); + t += get_minute() * 60; + t += get_hour() * 3600; + t += get_day_m() * 86400; + t += get_month() * 2629743; + t += (1970 - get_year()) * 31556926; + if (timer != NULL) { + (*timer) = t; + } + + return t; +} + +time_t difftime(time_t time1, time_t time2) +{ + return time1 - time2; +} + +void strhourminutesecond(char *dst) +{ + time_t s, m, h; + s = get_second(); + m = get_minute(); + h = get_hour(); + + sprintf(dst, "%i:%i:%i", h, m, s); +} + +void strdaymonthyear(char *dst) +{ + sprintf(dst, "%s %i %s %i", get_day_lng(), get_day_m(), get_month_lng(), + 1970 - get_year()); +} + +void strdatehour(char *dst) +{ + time_t s, m, h; + s = get_second(); + m = get_minute(); + h = get_hour(); + + sprintf(dst, "%s %i %s %i %i:%i:%i", get_day_lng(), get_day_m(), + get_month_lng(), 1970 - get_year(), h, m, s); +} diff --git a/mentos/src/misc/debug.c b/mentos/src/misc/debug.c index 2c4cd5e..f3ca588 100644 --- a/mentos/src/misc/debug.c +++ b/mentos/src/misc/debug.c @@ -1,99 +1,99 @@ -/// MentOS, The Mentoring Operating system project -/// @file debug.c -/// @brief Debugging primitives. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "debug.h" -#include "stdio.h" -#include "string.h" -#include "spinlock.h" - -/// Serial port for QEMU. -#define SERIAL_COM1 (0x03F8) - -#define DEBUG_BUFFER_SIZE 1024 - -static inline void dbg_putchar(char c) -{ -#if (defined(DEBUG_STDIO) || defined(DEBUG_LOG)) - outportb(SERIAL_COM1, c); -#endif -} - -static inline void dbg_print_header(const char *file, const char *fun, int line) -{ - static char prefix[300], final_prefix[300]; - - sprintf(prefix, "[%s:%s:%d", file, fun, line); - - sprintf(final_prefix, "%-40s] ", prefix); - - for (register int it = 0; final_prefix[it] != 0; ++it) { - dbg_putchar(final_prefix[it]); - } -} - -void _dbg_print(const char *file, const char *fun, int line, const char *msg, - ...) -{ - // Define a buffer for the formatted string. - static char formatted[DEBUG_BUFFER_SIZE]; - static bool_t new_line = true; - - // Stage 1: FORMAT - if (strlen(msg) >= 1024) { - return; - } - // Start variabile argument's list. - va_list ap; - va_start(ap, msg); - // Format the message. - vsprintf(formatted, msg, ap); - // End the list of arguments. - va_end(ap); - - // Stage 2: SEND - if (new_line) { - dbg_print_header(file, fun, line); - new_line = false; - } - for (int it = 0; (formatted[it] != 0) && (it < DEBUG_BUFFER_SIZE); ++it) { - dbg_putchar(formatted[it]); - if (formatted[it] != '\n') { - continue; - } - if ((it + 1) >= DEBUG_BUFFER_SIZE) { - continue; - } - if (formatted[it + 1] == 0) { - new_line = true; - } else { - dbg_print_header(file, fun, line); - } - } -} - -void print_intrframe(pt_regs *frame) -{ - dbg_print("Interrupt stack frame:\n"); - dbg_print("GS = 0x%-04x\n", frame->gs); - dbg_print("FS = 0x%-04x\n", frame->fs); - dbg_print("ES = 0x%-04x\n", frame->es); - dbg_print("DS = 0x%-04x\n", frame->ds); - dbg_print("EDI = 0x%-09x\n", frame->edi); - dbg_print("ESI = 0x%-09x\n", frame->esi); - dbg_print("EBP = 0x%-09x\n", frame->ebp); - dbg_print("ESP = 0x%-09x\n", frame->esp); - dbg_print("EBX = 0x%-09x\n", frame->ebx); - dbg_print("EDX = 0x%-09x\n", frame->edx); - dbg_print("ECX = 0x%-09x\n", frame->ecx); - dbg_print("EAX = 0x%-09x\n", frame->eax); - dbg_print("INT_NO = %-9d\n", frame->int_no); - dbg_print("ERR_CD = %-9d\n", frame->err_code); - dbg_print("EIP = 0x%-09x\n", frame->eip); - dbg_print("CS = 0x%-04x\n", frame->cs); - dbg_print("EFLAGS = 0x%-09x\n", frame->eflags); - dbg_print("UESP = 0x%-09x\n", frame->useresp); - dbg_print("SS = 0x%-04x\n", frame->ss); -} +/// MentOS, The Mentoring Operating system project +/// @file debug.c +/// @brief Debugging primitives. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "debug.h" +#include "stdio.h" +#include "string.h" +#include "spinlock.h" + +/// Serial port for QEMU. +#define SERIAL_COM1 (0x03F8) + +#define DEBUG_BUFFER_SIZE 1024 + +static inline void dbg_putchar(char c) +{ +#if (defined(DEBUG_STDIO) || defined(DEBUG_LOG)) + outportb(SERIAL_COM1, c); +#endif +} + +static inline void dbg_print_header(const char *file, const char *fun, int line) +{ + static char prefix[300], final_prefix[300]; + + sprintf(prefix, "[%s:%s:%d", file, fun, line); + + sprintf(final_prefix, "%-40s] ", prefix); + + for (register int it = 0; final_prefix[it] != 0; ++it) { + dbg_putchar(final_prefix[it]); + } +} + +void _dbg_print(const char *file, const char *fun, int line, const char *msg, + ...) +{ + // Define a buffer for the formatted string. + static char formatted[DEBUG_BUFFER_SIZE]; + static bool_t new_line = true; + + // Stage 1: FORMAT + if (strlen(msg) >= 1024) { + return; + } + // Start variabile argument's list. + va_list ap; + va_start(ap, msg); + // Format the message. + vsprintf(formatted, msg, ap); + // End the list of arguments. + va_end(ap); + + // Stage 2: SEND + if (new_line) { + dbg_print_header(file, fun, line); + new_line = false; + } + for (int it = 0; (formatted[it] != 0) && (it < DEBUG_BUFFER_SIZE); ++it) { + dbg_putchar(formatted[it]); + if (formatted[it] != '\n') { + continue; + } + if ((it + 1) >= DEBUG_BUFFER_SIZE) { + continue; + } + if (formatted[it + 1] == 0) { + new_line = true; + } else { + dbg_print_header(file, fun, line); + } + } +} + +void print_intrframe(pt_regs *frame) +{ + dbg_print("Interrupt stack frame:\n"); + dbg_print("GS = 0x%-04x\n", frame->gs); + dbg_print("FS = 0x%-04x\n", frame->fs); + dbg_print("ES = 0x%-04x\n", frame->es); + dbg_print("DS = 0x%-04x\n", frame->ds); + dbg_print("EDI = 0x%-09x\n", frame->edi); + dbg_print("ESI = 0x%-09x\n", frame->esi); + dbg_print("EBP = 0x%-09x\n", frame->ebp); + dbg_print("ESP = 0x%-09x\n", frame->esp); + dbg_print("EBX = 0x%-09x\n", frame->ebx); + dbg_print("EDX = 0x%-09x\n", frame->edx); + dbg_print("ECX = 0x%-09x\n", frame->ecx); + dbg_print("EAX = 0x%-09x\n", frame->eax); + dbg_print("INT_NO = %-9d\n", frame->int_no); + dbg_print("ERR_CD = %-9d\n", frame->err_code); + dbg_print("EIP = 0x%-09x\n", frame->eip); + dbg_print("CS = 0x%-04x\n", frame->cs); + dbg_print("EFLAGS = 0x%-09x\n", frame->eflags); + dbg_print("UESP = 0x%-09x\n", frame->useresp); + dbg_print("SS = 0x%-04x\n", frame->ss); +} diff --git a/mentos/src/multiboot.c b/mentos/src/multiboot.c index 3597250..9aba874 100644 --- a/mentos/src/multiboot.c +++ b/mentos/src/multiboot.c @@ -1,201 +1,201 @@ -/// MentOS, The Mentoring Operating system project -/// @file multiboot.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "multiboot.h" -#include "bitops.h" -#include "debug.h" -#include "panic.h" - -#define CHECK_FLAG(flags, bit) ((flags) & (1 << (bit))) - -static inline multiboot_memory_map_t *first_mmap_entry(multiboot_info_t *info) -{ - if (!has_flag(info->flags, MULTIBOOT_FLAG_MMAP)) - return NULL; - return (multiboot_memory_map_t *)((uintptr_t)info->mmap_addr); -} - -static inline multiboot_memory_map_t * -next_mmap_entry(multiboot_info_t *info, multiboot_memory_map_t *entry) -{ - uintptr_t next = ((uintptr_t)entry) + entry->size + sizeof(entry->size); - if (next >= info->mmap_addr + info->mmap_length) - return NULL; - return (multiboot_memory_map_t *)next; -} - -static inline multiboot_memory_map_t * -next_mmap_entry_of_type(multiboot_info_t *info, multiboot_memory_map_t *entry, - uint32_t type) -{ - do { - entry = next_mmap_entry(info, entry); - } while (entry && entry->type != type); - return entry; -} - -static inline multiboot_memory_map_t * -first_mmap_entry_of_type(multiboot_info_t *info, uint32_t type) -{ - multiboot_memory_map_t *entry = first_mmap_entry(info); - if (entry && (entry->type == type)) - return entry; - return next_mmap_entry_of_type(info, entry, type); -} - -static inline char *mmap_type_name(multiboot_memory_map_t *entry) -{ - if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) - return "AVAILABLE"; - if (entry->type == MULTIBOOT_MEMORY_RESERVED) - return "RESERVED"; - return "NONE"; -} - -static inline multiboot_module_t *first_module(multiboot_info_t *info) -{ - if (!has_flag(info->flags, MULTIBOOT_FLAG_MODS)) - return NULL; - if (!info->mods_count) - return NULL; - return (multiboot_module_t *)(uintptr_t)info->mods_addr; -} - -static inline multiboot_module_t *next_module(multiboot_info_t *info, - multiboot_module_t *mod) -{ - multiboot_module_t *first = - (multiboot_module_t *)((uintptr_t)info->mods_addr); - ++mod; - if ((mod - first) >= info->mods_count) - return NULL; - return mod; -} - -void dump_multiboot(multiboot_info_t *mbi) -{ - dbg_print("\n--------------------------------------------------\n"); - dbg_print("MULTIBOOT header at 0x%x:\n", mbi); - - // Print out the flags. - dbg_print("%-16s = 0x%x\n", "flags", mbi->flags); - - // Are mem_* valid? - if (has_flag(mbi->flags, MULTIBOOT_FLAG_MEM)) { - dbg_print("%-16s = %u Kb (%u Mb)\n", "mem_lower", mbi->mem_lower, - mbi->mem_lower / K); - dbg_print("%-16s = %u Kb (%u Mb)\n", "mem_upper", mbi->mem_upper, - mbi->mem_upper / K); - dbg_print("%-16s = %u Kb (%u Mb)\n", "total", - mbi->mem_lower + mbi->mem_upper, - (mbi->mem_lower + mbi->mem_upper) / K); - } - - // Is boot_device valid? - if (has_flag(mbi->flags, MULTIBOOT_FLAG_DEVICE)) { - dbg_print("%-16s = 0x%x (0x%x)", "boot_device", mbi->boot_device); - switch ((mbi->boot_device) & 0xFF000000) { - case 0x00000000: - dbg_print("(floppy)\n"); - break; - case 0x80000000: - dbg_print("(disk)\n"); - break; - default: - dbg_print("(unknown)\n"); - } - } - - // Is the command line passed? - if (has_flag(mbi->flags, MULTIBOOT_FLAG_CMDLINE)) { - dbg_print("%-16s = %s\n", "cmdline", (char *)mbi->cmdline); - } - - // Are mods_* valid? - if (has_flag(mbi->flags, MULTIBOOT_FLAG_MODS)) { - dbg_print("%-16s = %d\n", "mods_count", mbi->mods_count); - dbg_print("%-16s = 0x%x\n", "mods_addr", mbi->mods_addr); - multiboot_module_t *mod = first_module(mbi); - for (int i = 0; mod; ++i, mod = next_module(mbi, mod)) { - dbg_print(" [%2d] " - "mod_start = 0x%x, " - "mod_end = 0x%x, " - "cmdline = %s\n", - i, mod->mod_start, mod->mod_end, (char *)mod->cmdline); - } - } - // Bits 4 and 5 are mutually exclusive! - if (has_flag(mbi->flags, MULTIBOOT_FLAG_AOUT) && - has_flag(mbi->flags, MULTIBOOT_FLAG_ELF)) { - kernel_panic("Both bits 4 and 5 are set.\n"); - return; - } - - // Is the symbol table of a.out valid? - if (has_flag(mbi->flags, MULTIBOOT_FLAG_AOUT)) { - multiboot_aout_symbol_table_t *multiboot_aout_sym = &(mbi->u.aout_sym); - dbg_print("multiboot_aout_symbol_table: tabsize = 0x%0x, " - "strsize = 0x%x, addr = 0x%x\n", - multiboot_aout_sym->tabsize, multiboot_aout_sym->strsize, - multiboot_aout_sym->addr); - } - - // Is the section header table of ELF valid? - if (has_flag(mbi->flags, MULTIBOOT_FLAG_ELF)) { - multiboot_elf_section_header_table_t *multiboot_elf_sec = - &(mbi->u.elf_sec); - dbg_print("multiboot_elf_sec: num = %u, size = 0x%x," - " addr = 0x%x, shndx = 0x%x\n", - multiboot_elf_sec->num, multiboot_elf_sec->size, - multiboot_elf_sec->addr, multiboot_elf_sec->shndx); - } - - // Are mmap_* valid? - if (has_flag(mbi->flags, MULTIBOOT_FLAG_MMAP)) { - dbg_print("%-16s = 0x%x\n", "mmap_addr", mbi->mmap_addr); - dbg_print("%-16s = 0x%x (%d entries)\n", "mmap_length", - mbi->mmap_length, - mbi->mmap_length / sizeof(multiboot_memory_map_t)); - multiboot_memory_map_t *mmap = first_mmap_entry(mbi); - for (int i = 0; mmap; ++i, mmap = next_mmap_entry(mbi, mmap)) { - dbg_print(" [%2d] " - "base_addr = 0x%09x%09x, " - "length = 0x%09x%09x, " - "type = 0x%x (%s)\n", - i, mmap->base_addr_high, mmap->base_addr_low, - mmap->length_high, mmap->length_low, mmap->type, - mmap_type_name(mmap)); - } - } - - if (has_flag(mbi->flags, MULTIBOOT_FLAG_DRIVE_INFO)) { - dbg_print("Drives: 0x%x\n", mbi->drives_length); - dbg_print("Addr : 0x%x\n", mbi->drives_addr); - } - - if (has_flag(mbi->flags, MULTIBOOT_FLAG_CONFIG_TABLE)) { - dbg_print("Config: 0x%x\n", mbi->config_table); - } - - if (has_flag(mbi->flags, MULTIBOOT_FLAG_BOOT_LOADER_NAME)) { - dbg_print("boot_loader_name: %s\n", (char *)mbi->boot_loader_name); - } - - if (has_flag(mbi->flags, MULTIBOOT_FLAG_APM_TABLE)) { - dbg_print("APM : 0x%x\n", mbi->apm_table); - } - - if (has_flag(mbi->flags, MULTIBOOT_FLAG_VBE_INFO)) { - dbg_print("VBE Co: 0x%x\n", mbi->vbe_control_info); - dbg_print("VBE Mo: 0x%x\n", mbi->vbe_mode_info); - dbg_print("VBE In: 0x%x\n", mbi->vbe_mode); - dbg_print("VBE se: 0x%x\n", mbi->vbe_interface_seg); - dbg_print("VBE of: 0x%x\n", mbi->vbe_interface_off); - dbg_print("VBE le: 0x%x\n", mbi->vbe_interface_len); - } - dbg_print("--------------------------------------------------\n"); - dbg_print("\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file multiboot.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "multiboot.h" +#include "bitops.h" +#include "debug.h" +#include "panic.h" + +#define CHECK_FLAG(flags, bit) ((flags) & (1 << (bit))) + +static inline multiboot_memory_map_t *first_mmap_entry(multiboot_info_t *info) +{ + if (!has_flag(info->flags, MULTIBOOT_FLAG_MMAP)) + return NULL; + return (multiboot_memory_map_t *)((uintptr_t)info->mmap_addr); +} + +static inline multiboot_memory_map_t * +next_mmap_entry(multiboot_info_t *info, multiboot_memory_map_t *entry) +{ + uintptr_t next = ((uintptr_t)entry) + entry->size + sizeof(entry->size); + if (next >= info->mmap_addr + info->mmap_length) + return NULL; + return (multiboot_memory_map_t *)next; +} + +static inline multiboot_memory_map_t * +next_mmap_entry_of_type(multiboot_info_t *info, multiboot_memory_map_t *entry, + uint32_t type) +{ + do { + entry = next_mmap_entry(info, entry); + } while (entry && entry->type != type); + return entry; +} + +static inline multiboot_memory_map_t * +first_mmap_entry_of_type(multiboot_info_t *info, uint32_t type) +{ + multiboot_memory_map_t *entry = first_mmap_entry(info); + if (entry && (entry->type == type)) + return entry; + return next_mmap_entry_of_type(info, entry, type); +} + +static inline char *mmap_type_name(multiboot_memory_map_t *entry) +{ + if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) + return "AVAILABLE"; + if (entry->type == MULTIBOOT_MEMORY_RESERVED) + return "RESERVED"; + return "NONE"; +} + +static inline multiboot_module_t *first_module(multiboot_info_t *info) +{ + if (!has_flag(info->flags, MULTIBOOT_FLAG_MODS)) + return NULL; + if (!info->mods_count) + return NULL; + return (multiboot_module_t *)(uintptr_t)info->mods_addr; +} + +static inline multiboot_module_t *next_module(multiboot_info_t *info, + multiboot_module_t *mod) +{ + multiboot_module_t *first = + (multiboot_module_t *)((uintptr_t)info->mods_addr); + ++mod; + if ((mod - first) >= info->mods_count) + return NULL; + return mod; +} + +void dump_multiboot(multiboot_info_t *mbi) +{ + dbg_print("\n--------------------------------------------------\n"); + dbg_print("MULTIBOOT header at 0x%x:\n", mbi); + + // Print out the flags. + dbg_print("%-16s = 0x%x\n", "flags", mbi->flags); + + // Are mem_* valid? + if (has_flag(mbi->flags, MULTIBOOT_FLAG_MEM)) { + dbg_print("%-16s = %u Kb (%u Mb)\n", "mem_lower", mbi->mem_lower, + mbi->mem_lower / K); + dbg_print("%-16s = %u Kb (%u Mb)\n", "mem_upper", mbi->mem_upper, + mbi->mem_upper / K); + dbg_print("%-16s = %u Kb (%u Mb)\n", "total", + mbi->mem_lower + mbi->mem_upper, + (mbi->mem_lower + mbi->mem_upper) / K); + } + + // Is boot_device valid? + if (has_flag(mbi->flags, MULTIBOOT_FLAG_DEVICE)) { + dbg_print("%-16s = 0x%x (0x%x)", "boot_device", mbi->boot_device); + switch ((mbi->boot_device) & 0xFF000000) { + case 0x00000000: + dbg_print("(floppy)\n"); + break; + case 0x80000000: + dbg_print("(disk)\n"); + break; + default: + dbg_print("(unknown)\n"); + } + } + + // Is the command line passed? + if (has_flag(mbi->flags, MULTIBOOT_FLAG_CMDLINE)) { + dbg_print("%-16s = %s\n", "cmdline", (char *)mbi->cmdline); + } + + // Are mods_* valid? + if (has_flag(mbi->flags, MULTIBOOT_FLAG_MODS)) { + dbg_print("%-16s = %d\n", "mods_count", mbi->mods_count); + dbg_print("%-16s = 0x%x\n", "mods_addr", mbi->mods_addr); + multiboot_module_t *mod = first_module(mbi); + for (int i = 0; mod; ++i, mod = next_module(mbi, mod)) { + dbg_print(" [%2d] " + "mod_start = 0x%x, " + "mod_end = 0x%x, " + "cmdline = %s\n", + i, mod->mod_start, mod->mod_end, (char *)mod->cmdline); + } + } + // Bits 4 and 5 are mutually exclusive! + if (has_flag(mbi->flags, MULTIBOOT_FLAG_AOUT) && + has_flag(mbi->flags, MULTIBOOT_FLAG_ELF)) { + kernel_panic("Both bits 4 and 5 are set.\n"); + return; + } + + // Is the symbol table of a.out valid? + if (has_flag(mbi->flags, MULTIBOOT_FLAG_AOUT)) { + multiboot_aout_symbol_table_t *multiboot_aout_sym = &(mbi->u.aout_sym); + dbg_print("multiboot_aout_symbol_table: tabsize = 0x%0x, " + "strsize = 0x%x, addr = 0x%x\n", + multiboot_aout_sym->tabsize, multiboot_aout_sym->strsize, + multiboot_aout_sym->addr); + } + + // Is the section header table of ELF valid? + if (has_flag(mbi->flags, MULTIBOOT_FLAG_ELF)) { + multiboot_elf_section_header_table_t *multiboot_elf_sec = + &(mbi->u.elf_sec); + dbg_print("multiboot_elf_sec: num = %u, size = 0x%x," + " addr = 0x%x, shndx = 0x%x\n", + multiboot_elf_sec->num, multiboot_elf_sec->size, + multiboot_elf_sec->addr, multiboot_elf_sec->shndx); + } + + // Are mmap_* valid? + if (has_flag(mbi->flags, MULTIBOOT_FLAG_MMAP)) { + dbg_print("%-16s = 0x%x\n", "mmap_addr", mbi->mmap_addr); + dbg_print("%-16s = 0x%x (%d entries)\n", "mmap_length", + mbi->mmap_length, + mbi->mmap_length / sizeof(multiboot_memory_map_t)); + multiboot_memory_map_t *mmap = first_mmap_entry(mbi); + for (int i = 0; mmap; ++i, mmap = next_mmap_entry(mbi, mmap)) { + dbg_print(" [%2d] " + "base_addr = 0x%09x%09x, " + "length = 0x%09x%09x, " + "type = 0x%x (%s)\n", + i, mmap->base_addr_high, mmap->base_addr_low, + mmap->length_high, mmap->length_low, mmap->type, + mmap_type_name(mmap)); + } + } + + if (has_flag(mbi->flags, MULTIBOOT_FLAG_DRIVE_INFO)) { + dbg_print("Drives: 0x%x\n", mbi->drives_length); + dbg_print("Addr : 0x%x\n", mbi->drives_addr); + } + + if (has_flag(mbi->flags, MULTIBOOT_FLAG_CONFIG_TABLE)) { + dbg_print("Config: 0x%x\n", mbi->config_table); + } + + if (has_flag(mbi->flags, MULTIBOOT_FLAG_BOOT_LOADER_NAME)) { + dbg_print("boot_loader_name: %s\n", (char *)mbi->boot_loader_name); + } + + if (has_flag(mbi->flags, MULTIBOOT_FLAG_APM_TABLE)) { + dbg_print("APM : 0x%x\n", mbi->apm_table); + } + + if (has_flag(mbi->flags, MULTIBOOT_FLAG_VBE_INFO)) { + dbg_print("VBE Co: 0x%x\n", mbi->vbe_control_info); + dbg_print("VBE Mo: 0x%x\n", mbi->vbe_mode_info); + dbg_print("VBE In: 0x%x\n", mbi->vbe_mode); + dbg_print("VBE se: 0x%x\n", mbi->vbe_interface_seg); + dbg_print("VBE of: 0x%x\n", mbi->vbe_interface_off); + dbg_print("VBE le: 0x%x\n", mbi->vbe_interface_len); + } + dbg_print("--------------------------------------------------\n"); + dbg_print("\n"); +} diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index 4f07c0c..72a41aa 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -1,308 +1,308 @@ -/// MentOS, The Mentoring Operating system project -/// @file process.c -/// @brief Process data structures and functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "process.h" -#include "prio.h" -#include "init.h" -#include "panic.h" -#include "kheap.h" -#include "debug.h" -#include "unistd.h" -#include "string.h" -#include "list_head.h" -#include "stdatomic.h" -#include "scheduler.h" - -#define PUSH_ON_STACK(stack, type, item) \ - *((type *)(stack -= sizeof(type))) = item - -/// @brief The task_struct of the init process. -static task_struct *init_proc; - -void exit_handler() -{ - exit(1); - kernel_panic("I should not be here.\n"); -} - -task_struct *create_init_process() -{ - dbg_print("Building init process...\n"); - // Create a new task_struct. - init_proc = kmalloc(sizeof(task_struct)); - // TODO: process is IN USER SPACE! it should be in KERNEL SPACE! - memset(init_proc, 0, sizeof(task_struct)); - // Set the id of the process. - init_proc->pid = get_new_pid(); - // Set the name of the process. - strcpy(init_proc->name, "init"); - // Set the statistics of the process. - init_proc->se.prio = DEFAULT_PRIO; - init_proc->se.start_runtime = 0; - init_proc->se.exec_start = 0; - init_proc->se.sum_exec_runtime = 0; - init_proc->se.vruntime = 0; - // Initialize the list_head. - list_head_init(&init_proc->run_list); - // Initialize the children list_head. - list_head_init(&init_proc->children); - // Initialize the sibling list_head. - list_head_init(&init_proc->sibling); - // Create a new stack segment. - init_proc->mm = create_process_image(DEFAULT_STACK_SIZE); - char *stack = (char *)init_proc->mm->start_stack; - // Clean stack space. - memset(stack, 0, DEFAULT_STACK_SIZE); - // Set the base address of the stack. - char *ebp = (char *)(stack + DEFAULT_STACK_SIZE); - // Create a pointer to keep track of the top of the stack. - char *esp = ebp; - // Set exit_handler as terminating function for init. - PUSH_ON_STACK(esp, uintptr_t, (uintptr_t)&exit_handler); - // Set the top address of the stack. - init_proc->thread.useresp = (uintptr_t)esp; - // Set the base address of the stack. - init_proc->thread.ebp = (uintptr_t)ebp; - // Set the program counter. - init_proc->thread.eip = (uintptr_t)&main_init; - // Enable the interrupts. - init_proc->thread.eflags = init_proc->thread.eflags | EFLAG_IF; - // Clear the current working directory. - memset(init_proc->cwd, '\0', PATH_MAX); - // Set the state of the process as running. - init_proc->state = TASK_RUNNING; - // Active the current process. - enqueue_task(init_proc); - - dbg_print("--------------------------------------------------\n"); - dbg_print("- %s process (PID: %d, eflags: %d)\n", init_proc->name, - init_proc->pid, init_proc->thread.eflags); - dbg_print("\tStack: [0x%p - 0x%p]\n", init_proc->mm->start_stack, - init_proc->mm->start_stack + DEFAULT_STACK_SIZE); - dbg_print("\tebp: 0x%p\n", init_proc->thread.ebp); - dbg_print("\tesp: 0x%p\n", init_proc->thread.useresp); - dbg_print("\teip: 0x%p\n", init_proc->thread.eip); - dbg_print("--------------------------------------------------\n"); - - return init_proc; -} - -char *get_current_dir_name() -{ - task_struct *current_process = kernel_get_current_process(); - if (current_process != NULL) { - return strdup(current_process->cwd); - } - - return kstrdup("/"); -} - -void sys_getcwd(char *path, size_t size) -{ - task_struct *current_process = kernel_get_current_process(); - if ((current_process != NULL) && (path != NULL)) { - strncpy(path, current_process->cwd, size); - } -} - -void sys_chdir(char const *path) -{ - task_struct *current_process = kernel_get_current_process(); - if ((current_process != NULL) && (path != NULL)) { - strcpy(current_process->cwd, path); - } -} - -pid_t sys_vfork(pt_regs *r) -{ - task_struct *current = kernel_get_current_process(); - if (current == NULL) { - kernel_panic("There is no current process!"); - } - - dbg_print("Forking '%s'(%d) process...\n", current->name, current->pid); - - // Create a new task_struct. - // TODO: process is IN USER SPACE! it should be in KERNEL SPACE! - task_struct *new_process = kmalloc(sizeof(task_struct)); - - // TODO: this is NOT a deep copy. should a deep copy be used here? - memcpy(new_process, current, sizeof(task_struct)); - - // Set the id of the process. - new_process->pid = get_new_pid(); - - // Set the statistics of the process. - new_process->se.prio = DEFAULT_PRIO; - new_process->se.start_runtime = 0; - new_process->se.exec_start = 0; - new_process->se.sum_exec_runtime = 0; - // TODO: vruntime should be the scheduled highest values so far. - new_process->se.vruntime = current->se.vruntime; - - // Create a new stack segment. - new_process->mm = create_process_image(DEFAULT_STACK_SIZE); - char *stack = (char *)new_process->mm->start_stack; - // Copy the father's stack. - memcpy((char *)new_process->mm->start_stack, - (char *)current->mm->start_stack, DEFAULT_STACK_SIZE); - // Set the base address of the stack. - char *ebp = stack + DEFAULT_STACK_SIZE; // TODO: da controllare - // Create a pointer to keep track of the top of the stack. - char *esp = stack + (r->useresp - current->mm->start_stack); - - // Set the top address of the stack. - new_process->thread.useresp = (uintptr_t)esp; - // Set the base address of the stack. - new_process->thread.ebp = (uintptr_t)ebp; - // Set the program counter. - new_process->thread.eip = r->eip; - - // Set the base registers. - new_process->thread.eax = 0; - new_process->thread.ebx = r->ebx; - new_process->thread.ecx = r->ecx; - new_process->thread.edx = r->edx; - - // Enable the interrupts. - new_process->thread.eflags = new_process->thread.eflags | EFLAG_IF; - - // Set the state of the process as running. - new_process->state = TASK_RUNNING; - - // Set current as parent for the new process - new_process->parent = current; - - // Initialize the list_head. - list_head_init(&new_process->run_list); - - // Initialize the children list_head. - list_head_init(&new_process->children); - - // Initialize the children list_head. - list_head_init(&new_process->sibling); - - // Set the new_process as child of current. - list_head_add_tail(¤t->children, &new_process->sibling); - - // Active the new process. - enqueue_task(new_process); - - dbg_print("--------------------------------------------------\n"); - dbg_print("- %s process (PID: %d, eflags: %d)\n", new_process->name, - new_process->pid, new_process->thread.eflags); - dbg_print("\teip : 0x%p\n", new_process->thread.eip); - dbg_print("\tebp : 0x%p\n", new_process->thread.ebp); - dbg_print("\tesp : 0x%p\n", new_process->thread.useresp); - dbg_print("\tStack : 0x%p\n", new_process->mm->start_stack); - dbg_print("\tRunList: 0x%p\n", &new_process->run_list); - dbg_print("--------------------------------------------------\n"); - - dbg_print("Fork of '%s' (child pid: %d) process completed.\n", - current->name, current->pid); - - // Return PID of child process to parent. - return new_process->pid; -} - -static inline int push_args_on_stack(uintptr_t *esp, char *args[], - char ***argsptr) -{ - int argc = 0; - char *args_ptr[256]; - // Count the number of arguments. - while (args[argc] != NULL) { - ++argc; - } - // Push terminating NULL. - PUSH_ON_STACK((*esp), char *, (char *)NULL); - // Prepare args with space for the terminating NULL. - for (int i = argc - 1; i >= 0; --i) { - for (int j = strlen(args[i]); j >= 0; --j) { - PUSH_ON_STACK((*esp), char, args[i][j]); - } - args_ptr[i] = (char *)(*esp); - } - // Push terminating NULL. - PUSH_ON_STACK((*esp), char *, (char *)NULL); - // Push array of pointers to the arguments. - for (int i = argc - 1; i >= 0; --i) { - PUSH_ON_STACK((*esp), char *, args_ptr[i]); - } - (*argsptr) = (char **)(*esp); - - return argc; -} - -int sys_execve(pt_regs *r) -{ - char **argv, **_argv, **envp, **_envp; - // Check the current process. - task_struct *current = kernel_get_current_process(); - if (current == NULL) { - kernel_panic("There is no current process!"); - } - - // Get the filename. - uintptr_t *filename = (uintptr_t *)r->ebx; - if (filename == NULL) { - return -1; - } - - // Get the arguments. - argv = (char **)r->ecx; - // Get the environment. - envp = (char **)r->edx; - - // Check the argument and that at least the name is provided. - if ((argv == NULL) || (argv[0] == NULL)) { - return -1; - } - - // Check that the environment is provided. - if (envp == NULL) { - kernel_panic("You must provide at least an empty list for envp!"); - } - - // Set the name. - strcpy(current->name, argv[0]); - - // Set the top address of the stack. - current->thread.useresp = (uintptr_t)current->thread.ebp; - - // Set the program counter. - current->thread.eip = (uintptr_t)filename; - - int argc = push_args_on_stack(¤t->thread.useresp, argv, &_argv); - push_args_on_stack(¤t->thread.useresp, envp, &_envp); - - PUSH_ON_STACK(current->thread.useresp, char **, _envp); - PUSH_ON_STACK(current->thread.useresp, char **, _argv); - PUSH_ON_STACK(current->thread.useresp, int, argc); - PUSH_ON_STACK(current->thread.useresp, uintptr_t, (uintptr_t)exit_handler); - - // dbg_print("_ARGV:0x%09x {\n", _argv); - // for (int i = 0; _argv[i] != NULL; ++i) { - // dbg_print("\t[%d][0x%09x]%s\n", i, _argv[i], _argv[i]); - // } - // dbg_print("}\n"); - // - // if (_envp != NULL) { - // dbg_print("_ENVP:0x%09x {\n", _envp); - // for (int i = 0; _envp[i] != NULL; ++i) { - // dbg_print("\t[%d][0x%09x]%s\n", i, _envp[i], _envp[i]); - // } - // dbg_print("}\n"); - // } - - // Perform the switch to the new process. - do_switch(current, r); - - dbg_print("Executing '0x%p' for process %d with %d arguments (0x%p)...\n", - filename, current->pid, argc, argv); - - return 0; -} +/// MentOS, The Mentoring Operating system project +/// @file process.c +/// @brief Process data structures and functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "process.h" +#include "prio.h" +#include "init.h" +#include "panic.h" +#include "kheap.h" +#include "debug.h" +#include "unistd.h" +#include "string.h" +#include "list_head.h" +#include "stdatomic.h" +#include "scheduler.h" + +#define PUSH_ON_STACK(stack, type, item) \ + *((type *)(stack -= sizeof(type))) = item + +/// @brief The task_struct of the init process. +static task_struct *init_proc; + +void exit_handler() +{ + exit(1); + kernel_panic("I should not be here.\n"); +} + +task_struct *create_init_process() +{ + dbg_print("Building init process...\n"); + // Create a new task_struct. + init_proc = kmalloc(sizeof(task_struct)); + // TODO: process is IN USER SPACE! it should be in KERNEL SPACE! + memset(init_proc, 0, sizeof(task_struct)); + // Set the id of the process. + init_proc->pid = get_new_pid(); + // Set the name of the process. + strcpy(init_proc->name, "init"); + // Set the statistics of the process. + init_proc->se.prio = DEFAULT_PRIO; + init_proc->se.start_runtime = 0; + init_proc->se.exec_start = 0; + init_proc->se.sum_exec_runtime = 0; + init_proc->se.vruntime = 0; + // Initialize the list_head. + list_head_init(&init_proc->run_list); + // Initialize the children list_head. + list_head_init(&init_proc->children); + // Initialize the sibling list_head. + list_head_init(&init_proc->sibling); + // Create a new stack segment. + init_proc->mm = create_process_image(DEFAULT_STACK_SIZE); + char *stack = (char *)init_proc->mm->start_stack; + // Clean stack space. + memset(stack, 0, DEFAULT_STACK_SIZE); + // Set the base address of the stack. + char *ebp = (char *)(stack + DEFAULT_STACK_SIZE); + // Create a pointer to keep track of the top of the stack. + char *esp = ebp; + // Set exit_handler as terminating function for init. + PUSH_ON_STACK(esp, uintptr_t, (uintptr_t)&exit_handler); + // Set the top address of the stack. + init_proc->thread.useresp = (uintptr_t)esp; + // Set the base address of the stack. + init_proc->thread.ebp = (uintptr_t)ebp; + // Set the program counter. + init_proc->thread.eip = (uintptr_t)&main_init; + // Enable the interrupts. + init_proc->thread.eflags = init_proc->thread.eflags | EFLAG_IF; + // Clear the current working directory. + memset(init_proc->cwd, '\0', PATH_MAX); + // Set the state of the process as running. + init_proc->state = TASK_RUNNING; + // Active the current process. + enqueue_task(init_proc); + + dbg_print("--------------------------------------------------\n"); + dbg_print("- %s process (PID: %d, eflags: %d)\n", init_proc->name, + init_proc->pid, init_proc->thread.eflags); + dbg_print("\tStack: [0x%p - 0x%p]\n", init_proc->mm->start_stack, + init_proc->mm->start_stack + DEFAULT_STACK_SIZE); + dbg_print("\tebp: 0x%p\n", init_proc->thread.ebp); + dbg_print("\tesp: 0x%p\n", init_proc->thread.useresp); + dbg_print("\teip: 0x%p\n", init_proc->thread.eip); + dbg_print("--------------------------------------------------\n"); + + return init_proc; +} + +char *get_current_dir_name() +{ + task_struct *current_process = kernel_get_current_process(); + if (current_process != NULL) { + return strdup(current_process->cwd); + } + + return kstrdup("/"); +} + +void sys_getcwd(char *path, size_t size) +{ + task_struct *current_process = kernel_get_current_process(); + if ((current_process != NULL) && (path != NULL)) { + strncpy(path, current_process->cwd, size); + } +} + +void sys_chdir(char const *path) +{ + task_struct *current_process = kernel_get_current_process(); + if ((current_process != NULL) && (path != NULL)) { + strcpy(current_process->cwd, path); + } +} + +pid_t sys_vfork(pt_regs *r) +{ + task_struct *current = kernel_get_current_process(); + if (current == NULL) { + kernel_panic("There is no current process!"); + } + + dbg_print("Forking '%s'(%d) process...\n", current->name, current->pid); + + // Create a new task_struct. + // TODO: process is IN USER SPACE! it should be in KERNEL SPACE! + task_struct *new_process = kmalloc(sizeof(task_struct)); + + // TODO: this is NOT a deep copy. should a deep copy be used here? + memcpy(new_process, current, sizeof(task_struct)); + + // Set the id of the process. + new_process->pid = get_new_pid(); + + // Set the statistics of the process. + new_process->se.prio = DEFAULT_PRIO; + new_process->se.start_runtime = 0; + new_process->se.exec_start = 0; + new_process->se.sum_exec_runtime = 0; + // TODO: vruntime should be the scheduled highest values so far. + new_process->se.vruntime = current->se.vruntime; + + // Create a new stack segment. + new_process->mm = create_process_image(DEFAULT_STACK_SIZE); + char *stack = (char *)new_process->mm->start_stack; + // Copy the father's stack. + memcpy((char *)new_process->mm->start_stack, + (char *)current->mm->start_stack, DEFAULT_STACK_SIZE); + // Set the base address of the stack. + char *ebp = stack + DEFAULT_STACK_SIZE; // TODO: da controllare + // Create a pointer to keep track of the top of the stack. + char *esp = stack + (r->useresp - current->mm->start_stack); + + // Set the top address of the stack. + new_process->thread.useresp = (uintptr_t)esp; + // Set the base address of the stack. + new_process->thread.ebp = (uintptr_t)ebp; + // Set the program counter. + new_process->thread.eip = r->eip; + + // Set the base registers. + new_process->thread.eax = 0; + new_process->thread.ebx = r->ebx; + new_process->thread.ecx = r->ecx; + new_process->thread.edx = r->edx; + + // Enable the interrupts. + new_process->thread.eflags = new_process->thread.eflags | EFLAG_IF; + + // Set the state of the process as running. + new_process->state = TASK_RUNNING; + + // Set current as parent for the new process + new_process->parent = current; + + // Initialize the list_head. + list_head_init(&new_process->run_list); + + // Initialize the children list_head. + list_head_init(&new_process->children); + + // Initialize the children list_head. + list_head_init(&new_process->sibling); + + // Set the new_process as child of current. + list_head_add_tail(¤t->children, &new_process->sibling); + + // Active the new process. + enqueue_task(new_process); + + dbg_print("--------------------------------------------------\n"); + dbg_print("- %s process (PID: %d, eflags: %d)\n", new_process->name, + new_process->pid, new_process->thread.eflags); + dbg_print("\teip : 0x%p\n", new_process->thread.eip); + dbg_print("\tebp : 0x%p\n", new_process->thread.ebp); + dbg_print("\tesp : 0x%p\n", new_process->thread.useresp); + dbg_print("\tStack : 0x%p\n", new_process->mm->start_stack); + dbg_print("\tRunList: 0x%p\n", &new_process->run_list); + dbg_print("--------------------------------------------------\n"); + + dbg_print("Fork of '%s' (child pid: %d) process completed.\n", + current->name, current->pid); + + // Return PID of child process to parent. + return new_process->pid; +} + +static inline int push_args_on_stack(uintptr_t *esp, char *args[], + char ***argsptr) +{ + int argc = 0; + char *args_ptr[256]; + // Count the number of arguments. + while (args[argc] != NULL) { + ++argc; + } + // Push terminating NULL. + PUSH_ON_STACK((*esp), char *, (char *)NULL); + // Prepare args with space for the terminating NULL. + for (int i = argc - 1; i >= 0; --i) { + for (int j = strlen(args[i]); j >= 0; --j) { + PUSH_ON_STACK((*esp), char, args[i][j]); + } + args_ptr[i] = (char *)(*esp); + } + // Push terminating NULL. + PUSH_ON_STACK((*esp), char *, (char *)NULL); + // Push array of pointers to the arguments. + for (int i = argc - 1; i >= 0; --i) { + PUSH_ON_STACK((*esp), char *, args_ptr[i]); + } + (*argsptr) = (char **)(*esp); + + return argc; +} + +int sys_execve(pt_regs *r) +{ + char **argv, **_argv, **envp, **_envp; + // Check the current process. + task_struct *current = kernel_get_current_process(); + if (current == NULL) { + kernel_panic("There is no current process!"); + } + + // Get the filename. + uintptr_t *filename = (uintptr_t *)r->ebx; + if (filename == NULL) { + return -1; + } + + // Get the arguments. + argv = (char **)r->ecx; + // Get the environment. + envp = (char **)r->edx; + + // Check the argument and that at least the name is provided. + if ((argv == NULL) || (argv[0] == NULL)) { + return -1; + } + + // Check that the environment is provided. + if (envp == NULL) { + kernel_panic("You must provide at least an empty list for envp!"); + } + + // Set the name. + strcpy(current->name, argv[0]); + + // Set the top address of the stack. + current->thread.useresp = (uintptr_t)current->thread.ebp; + + // Set the program counter. + current->thread.eip = (uintptr_t)filename; + + int argc = push_args_on_stack(¤t->thread.useresp, argv, &_argv); + push_args_on_stack(¤t->thread.useresp, envp, &_envp); + + PUSH_ON_STACK(current->thread.useresp, char **, _envp); + PUSH_ON_STACK(current->thread.useresp, char **, _argv); + PUSH_ON_STACK(current->thread.useresp, int, argc); + PUSH_ON_STACK(current->thread.useresp, uintptr_t, (uintptr_t)exit_handler); + + // dbg_print("_ARGV:0x%09x {\n", _argv); + // for (int i = 0; _argv[i] != NULL; ++i) { + // dbg_print("\t[%d][0x%09x]%s\n", i, _argv[i], _argv[i]); + // } + // dbg_print("}\n"); + // + // if (_envp != NULL) { + // dbg_print("_ENVP:0x%09x {\n", _envp); + // for (int i = 0; _envp[i] != NULL; ++i) { + // dbg_print("\t[%d][0x%09x]%s\n", i, _envp[i], _envp[i]); + // } + // dbg_print("}\n"); + // } + + // Perform the switch to the new process. + do_switch(current, r); + + dbg_print("Executing '0x%p' for process %d with %d arguments (0x%p)...\n", + filename, current->pid, argc, argv); + + return 0; +} diff --git a/mentos/src/process/scheduler.c b/mentos/src/process/scheduler.c index feac995..821e017 100644 --- a/mentos/src/process/scheduler.c +++ b/mentos/src/process/scheduler.c @@ -1,383 +1,395 @@ -/// MentOS, The Mentoring Operating system project -/// @file scheduler.c -/// @brief Scheduler structures and functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "scheduler.h" -#include "tss.h" -#include "fpu.h" -#include "prio.h" -#include "wait.h" -#include "kheap.h" -#include "panic.h" -#include "debug.h" -#include "clock.h" -#include "errno.h" -#include "rbtree.h" -#include "stdlib.h" -#include "list_head.h" - -/// @brief Assembly function setting the kernel stack to jump into -/// location in Ring 3 mode (USER mode). -/// @param location The location where to jump. -/// @param stack The stack to use. -extern void enter_userspace(uintptr_t location, uintptr_t stack); - -/// The list of processes. -runqueue_t runqueue; - -uint32_t get_new_pid(void) -{ - /// The current unused PID. - static unsigned long int tid = 1; - - // Return the pid and increment. - return tid++; -} - -task_struct *kernel_get_current_process() -{ - return runqueue.curr; -} - -task_struct *kernel_get_running_process(pid_t pid) -{ - list_head *it; - list_for_each (it, &runqueue.queue) { - task_struct *entry = list_entry(it, task_struct, run_list); - if (entry != NULL) { - if (entry->pid == pid) { - return entry; - } - } - } - return NULL; -} - -size_t kernel_get_active_processes() -{ - return runqueue.num_active; -} - -void kernel_initialize_scheduler() -{ - // Initialize the runqueue list of tasks. - list_head_init(&runqueue.queue); - // Reset the current task. - runqueue.curr = NULL; - // Reset the number of active tasks. - runqueue.num_active = 0; -} - -void enqueue_task(task_struct *process) -{ - // If current_process is NULL, then process is the current process. - if (runqueue.curr == NULL) { - runqueue.curr = process; - } - // Add the new process at the end. - list_head_add_tail(&process->run_list, &runqueue.queue); - // Increment the number of active processes. - ++runqueue.num_active; -} - -void dequeue_task(task_struct *process) -{ - // Delete the process from the list of running processes. - list_head_del(&process->run_list); - // Decrement the number of active processes. - --runqueue.num_active; -} - -void kernel_schedule(pt_regs *f) -{ - // Check if there is a running process. - if (runqueue.curr == NULL) { - return; - } - - //==== Update Statistics =================================================== - time_t delta_exec = get_millisecond() - runqueue.curr->se.exec_start; - // dbg_print("[%3d] %d = %d - %d\n", runqueue.curr->pid, delta_exec, - // get_millisecond(), runqueue.curr->se.exec_start); - // set the sum_exec_runtime - runqueue.curr->se.sum_exec_runtime += delta_exec; - //========================================================================== - - //==== Handle Zombies ====================================================== - task_struct *next_process = NULL; - if (runqueue.curr->state == EXIT_ZOMBIE) { - // get the next process after the current one - list_head *nNode = runqueue.curr->run_list.next; - // check if we reached the head of list_head - if (nNode == &runqueue.queue) - nNode = nNode->next; - // get the task_struct - next_process = list_entry(nNode, task_struct, run_list); - // Remove the zombie task. - dequeue_task(runqueue.curr); - } else { - //==== Scheduling ====================================================== - // Pointer to the next process to be executed. - next_process = pick_next_task(&runqueue, delta_exec); - //====================================================================== - } - //========================================================================== - - // Print, for debugging purpose, data about the current process. - if (runqueue.num_active > 2) { - dbg_print("PID:%3d, PRIO:%3d, VRUNTIME:%9d, SUM_EXEC:%9d\n", - next_process->pid, next_process->se.prio, - next_process->se.vruntime, next_process->se.sum_exec_runtime); - } - - //==== Context switch ====================================================== - // Update the context of the current process. - update_context(f, runqueue.curr); - // Check if the next and current processes are different. - if (next_process != runqueue.curr) { - // Copy into Kernel stack the next process's context. - do_switch(next_process, f); - runqueue.curr->se.sum_exec_runtime = get_millisecond(); - // Update the last context switch time of the next process. - next_process->se.exec_start = get_millisecond(); - } - //========================================================================== - - // Update the start execution time if it is executed for the first time - if (next_process->se.start_runtime == 0) - next_process->se.start_runtime = get_millisecond(); -} - -void update_context(pt_regs *f, task_struct *process) -{ - // Store the registers. - process->thread.gs = f->gs; - process->thread.fs = f->fs; - process->thread.es = f->es; - process->thread.ds = f->ds; - process->thread.edi = f->edi; - process->thread.esi = f->esi; - process->thread.ebp = f->ebp; - process->thread.ebx = f->ebx; - process->thread.edx = f->edx; - process->thread.ecx = f->ecx; - process->thread.eax = f->eax; - process->thread.eip = f->eip; - process->thread.eflags = f->eflags; - process->thread.useresp = f->useresp; - // TODO: Check if the following registers should be saved. - // process->thread.cs = f->cs; - // process->thread.ss = f->ss; - // Store the FPU. - switch_fpu(); -} - -void do_switch(task_struct *process, pt_regs *f) -{ - // Switch to the next process. - runqueue.curr = process; - // Restore the registers. - f->gs = process->thread.gs; - f->fs = process->thread.fs; - f->es = process->thread.es; - f->ds = process->thread.ds; - f->edi = process->thread.edi; - f->esi = process->thread.esi; - f->ebp = process->thread.ebp; - f->ebx = process->thread.ebx; - f->edx = process->thread.edx; - f->ecx = process->thread.ecx; - f->eax = process->thread.eax; - f->eip = process->thread.eip; - f->eflags = process->thread.eflags; - f->useresp = process->thread.useresp; - // TODO: Check if the following registers should be restored. - // f->cs = process->thread.cs; - // f->ss = process->thread.ss; - // Restore the FPU. - unswitch_fpu(); -} - -int set_user_nice(task_struct *p, long nice) -{ - if (PRIO_TO_NICE(p->se.prio) != nice && nice >= MIN_NICE && - nice <= MAX_NICE) { - p->se.prio = NICE_TO_PRIO(nice); - } - - return PRIO_TO_NICE(p->se.prio); -} - -void enter_user_jmp(uintptr_t location, uintptr_t stack) -{ - // Reset stack pointer for kernel. - tss_set_stack(0x10, initial_esp); - - // update start execution time. - runqueue.curr->se.start_runtime = get_millisecond(); - - // last context switch time. - runqueue.curr->se.exec_start = get_millisecond(); - - // Jump in location. - enter_userspace(location, stack); -} - -pid_t sys_getpid() -{ - // Get the current task. - if (runqueue.curr == NULL) { - kernel_panic("There is no current process!"); - } - - // Return the process identifer of the process. - return runqueue.curr->pid; -} - -pid_t sys_getppid() -{ - // Get the current task. - if (runqueue.curr == NULL) { - kernel_panic("There is no current process!"); - } - if (runqueue.curr->parent == NULL) { - return 0; - } - - // Return the parent process identifer of the process. - return runqueue.curr->parent->pid; -} - -int sys_nice(int increment) -{ - // Get the current task. - if (runqueue.curr == NULL) { - kernel_panic("There is no current process!"); - } - - if (increment < -40) { - increment = -40; - } - if (increment > 40) { - increment = 40; - } - - int newNice = PRIO_TO_NICE(runqueue.curr->se.prio) + increment; - dbg_print("New nice value would be : %d\n", newNice); - - if (newNice < MIN_NICE) { - newNice = MIN_NICE; - } - if (newNice > MAX_NICE) { - newNice = MAX_NICE; - } - - int actualNice = set_user_nice(runqueue.curr, newNice); - dbg_print("Actual new nice value is: %d\n", actualNice); - - return actualNice; -} - -pid_t sys_waitpid(pid_t pid, int *status, int options) -{ - // Get the current task. - if (runqueue.curr == NULL) { - kernel_panic("There is no current process!"); - } - - /* For now we do not support waiting for processes inside the given - * process group (pid < -1). - */ - if ((pid < -1) || (pid == 0)) { - errno = ESRCH; - - return (-1); - } - if (pid == runqueue.curr->pid) { - errno = ECHILD; - - return (-1); - } - if (options != 0 && options != WNOHANG) { - errno = EINVAL; - - return (-1); - } - if (status == NULL) { - errno = EFAULT; - - return (-1); - } - list_head *it; - list_for_each (it, &runqueue.curr->children) { - task_struct *entry = list_entry(it, task_struct, sibling); - if (entry == NULL) { - continue; - } - if (entry->state != EXIT_ZOMBIE) { - continue; - } - if ((pid > 1) && (entry->pid != pid)) { - continue; - } - // Save the pid to return. - pid_t ppid = entry->pid; - // Save the state. - (*status) = entry->state; //TODO: da rivedere - // Remove entry from children of parent. - list_head_del(&entry->sibling); - // Delete the task_struct. - kfree(entry); - dbg_print("Freeing memory of process %d.\n", ppid); - - return ppid; - } - - return 0; -} - -void sys_exit(int exit_code) -{ - // Get the current task. - if (runqueue.curr == NULL) { - kernel_panic("There is no current process!"); - } - - task_struct *init_proc = kernel_get_running_process(1); - if (runqueue.curr == init_proc) { - kernel_panic("Init process cannot call sys_exit!"); - } - // Set the termination code of the process. - runqueue.curr->exit_code = (exit_code << 8) & 0xFF00; - // Set the state of the process to zombie. - runqueue.curr->state = EXIT_ZOMBIE; - // If it has children, then init process has to take care of them. - if (!list_head_empty(&runqueue.curr->children)) { - dbg_print("Moving children of %s(%d) to init(%d): {\n", - runqueue.curr->name, runqueue.curr->pid, init_proc->pid); - // TODO: Try to plug the list of children instead of iterating. - list_head *it; - list_for_each (it, &runqueue.curr->children) { - task_struct *entry = list_entry(it, task_struct, sibling); - dbg_print(" [%d] %s\n", entry->pid, entry->name); - it = entry->sibling.prev; - list_head_del(&entry->sibling); - list_head_add_tail(&init_proc->children, &entry->sibling); - entry->parent = init_proc; - } - dbg_print("}\n"); - dbg_print("Listing children of init(%d): {\n", init_proc->pid); - list_for_each (it, &init_proc->children) { - task_struct *entry = list_entry(it, task_struct, sibling); - dbg_print(" [%d] %s\n", entry->pid, entry->name); - } - dbg_print("}\n"); - } - // Free the space occupied by the stack. - destroy_process_image(runqueue.curr->mm); - // Debugging message. - dbg_print("Process %d exited with value %d\n", runqueue.curr->pid, - exit_code); -} +/// MentOS, The Mentoring Operating system project +/// @file scheduler.c +/// @brief Scheduler structures and functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "scheduler.h" +#include "tss.h" +#include "fpu.h" +#include "prio.h" +#include "wait.h" +#include "kheap.h" +#include "panic.h" +#include "debug.h" +#include "clock.h" +#include "errno.h" +#include "rbtree.h" +#include "stdlib.h" +#include "list_head.h" +#include "deadlock_simulation.h" + +/// @brief Assembly function setting the kernel stack to jump into +/// location in Ring 3 mode (USER mode). +/// @param location The location where to jump. +/// @param stack The stack to use. +extern void enter_userspace(uintptr_t location, uintptr_t stack); + +/// The list of processes. +runqueue_t runqueue; + +uint32_t get_new_pid(void) +{ + /// The current unused PID. + static unsigned long int tid = 1; + + // Return the pid and increment. + return tid++; +} + +task_struct *kernel_get_current_process() +{ + return runqueue.curr; +} + +task_struct *kernel_get_running_process(pid_t pid) +{ + list_head *it; + list_for_each (it, &runqueue.queue) { + task_struct *entry = list_entry(it, task_struct, run_list); + if (entry != NULL) { + if (entry->pid == pid) { + return entry; + } + } + } + return NULL; +} + +size_t kernel_get_active_processes() +{ + return runqueue.num_active; +} + +void kernel_initialize_scheduler() +{ + // Initialize the runqueue list of tasks. + list_head_init(&runqueue.queue); + // Reset the current task. + runqueue.curr = NULL; + // Reset the number of active tasks. + runqueue.num_active = 0; + +#if ENABLE_DEADLOCK_PREVENTION + // Simulate deadlock. + deadlock_simulation(); +#endif +} + +void enqueue_task(task_struct *process) +{ + // If current_process is NULL, then process is the current process. + if (runqueue.curr == NULL) { + runqueue.curr = process; + } + // Add the new process at the end. + list_head_add_tail(&process->run_list, &runqueue.queue); + // Increment the number of active processes. + ++runqueue.num_active; +} + +void dequeue_task(task_struct *process) +{ + // Delete the process from the list of running processes. + list_head_del(&process->run_list); + // Decrement the number of active processes. + --runqueue.num_active; +} + +void kernel_schedule(pt_regs *f) +{ + // Check if there is a running process. + if (runqueue.curr == NULL) { + return; + } + + //==== Update Statistics =================================================== + time_t delta_exec = get_millisecond() - runqueue.curr->se.exec_start; + // dbg_print("[%3d] %d = %d - %d\n", runqueue.curr->pid, delta_exec, + // get_millisecond(), runqueue.curr->se.exec_start); + // set the sum_exec_runtime + runqueue.curr->se.sum_exec_runtime += delta_exec; + //========================================================================== + + //==== Handle Zombies ====================================================== + task_struct *next_process = NULL; + if (runqueue.curr->state == EXIT_ZOMBIE) { + // get the next process after the current one + list_head *nNode = runqueue.curr->run_list.next; + // check if we reached the head of list_head + if (nNode == &runqueue.queue) + nNode = nNode->next; + // get the task_struct + next_process = list_entry(nNode, task_struct, run_list); + // Remove the zombie task. + dequeue_task(runqueue.curr); + } else { + //==== Scheduling ====================================================== + // Pointer to the next process to be executed. + next_process = pick_next_task(&runqueue, delta_exec); + //====================================================================== + } + //========================================================================== + +#if 0 + // Print, for debugging purpose, data about the current process. + if (runqueue.num_active > 2) { + dbg_print("PID:%3d, PRIO:%3d, VRUNTIME:%9d, SUM_EXEC:%9d\n", + next_process->pid, next_process->se.prio, + next_process->se.vruntime, next_process->se.sum_exec_runtime); + } +#endif + + //==== Context switch ====================================================== + // Update the context of the current process. + update_context(f, runqueue.curr); + // Check if the next and current processes are different. + if (next_process != runqueue.curr) { + // Copy into Kernel stack the next process's context. + do_switch(next_process, f); + runqueue.curr->se.sum_exec_runtime = get_millisecond(); + // Update the last context switch time of the next process. + next_process->se.exec_start = get_millisecond(); + } + //========================================================================== + + // Update the start execution time if it is executed for the first time + if (next_process->se.start_runtime == 0) + next_process->se.start_runtime = get_millisecond(); +} + +void update_context(pt_regs *f, task_struct *process) +{ + // Store the registers. + process->thread.gs = f->gs; + process->thread.fs = f->fs; + process->thread.es = f->es; + process->thread.ds = f->ds; + process->thread.edi = f->edi; + process->thread.esi = f->esi; + process->thread.ebp = f->ebp; + process->thread.ebx = f->ebx; + process->thread.edx = f->edx; + process->thread.ecx = f->ecx; + process->thread.eax = f->eax; + process->thread.eip = f->eip; + process->thread.eflags = f->eflags; + process->thread.useresp = f->useresp; + // TODO: Check if the following registers should be saved. + // process->thread.cs = f->cs; + // process->thread.ss = f->ss; + // Store the FPU. + switch_fpu(); +} + +void do_switch(task_struct *process, pt_regs *f) +{ + // Switch to the next process. + runqueue.curr = process; + // Restore the registers. + f->gs = process->thread.gs; + f->fs = process->thread.fs; + f->es = process->thread.es; + f->ds = process->thread.ds; + f->edi = process->thread.edi; + f->esi = process->thread.esi; + f->ebp = process->thread.ebp; + f->ebx = process->thread.ebx; + f->edx = process->thread.edx; + f->ecx = process->thread.ecx; + f->eax = process->thread.eax; + f->eip = process->thread.eip; + f->eflags = process->thread.eflags; + f->useresp = process->thread.useresp; + // TODO: Check if the following registers should be restored. + // f->cs = process->thread.cs; + // f->ss = process->thread.ss; + // Restore the FPU. + unswitch_fpu(); +} + +int set_user_nice(task_struct *p, long nice) +{ + if (PRIO_TO_NICE(p->se.prio) != nice && nice >= MIN_NICE && + nice <= MAX_NICE) { + p->se.prio = NICE_TO_PRIO(nice); + } + + return PRIO_TO_NICE(p->se.prio); +} + +void enter_user_jmp(uintptr_t location, uintptr_t stack) +{ + // Reset stack pointer for kernel. + tss_set_stack(0x10, initial_esp); + + // update start execution time. + runqueue.curr->se.start_runtime = get_millisecond(); + + // last context switch time. + runqueue.curr->se.exec_start = get_millisecond(); + + // Jump in location. + enter_userspace(location, stack); +} + +pid_t sys_getpid() +{ + // Get the current task. + if (runqueue.curr == NULL) { + kernel_panic("There is no current process!"); + } + + // Return the process identifer of the process. + return runqueue.curr->pid; +} + +pid_t sys_getppid() +{ + // Get the current task. + if (runqueue.curr == NULL) { + kernel_panic("There is no current process!"); + } + if (runqueue.curr->parent == NULL) { + return 0; + } + + // Return the parent process identifer of the process. + return runqueue.curr->parent->pid; +} + +int sys_nice(int increment) +{ + // Get the current task. + if (runqueue.curr == NULL) { + kernel_panic("There is no current process!"); + } + + if (increment < -40) { + increment = -40; + } + if (increment > 40) { + increment = 40; + } + + int newNice = PRIO_TO_NICE(runqueue.curr->se.prio) + increment; + dbg_print("New nice value would be : %d\n", newNice); + + if (newNice < MIN_NICE) { + newNice = MIN_NICE; + } + if (newNice > MAX_NICE) { + newNice = MAX_NICE; + } + + int actualNice = set_user_nice(runqueue.curr, newNice); + dbg_print("Actual new nice value is: %d\n", actualNice); + + return actualNice; +} + +pid_t sys_waitpid(pid_t pid, int *status, int options) +{ + // Get the current task. + if (runqueue.curr == NULL) { + kernel_panic("There is no current process!"); + } + + /* For now we do not support waiting for processes inside the given + * process group (pid < -1). + */ + if ((pid < -1) || (pid == 0)) { + errno = ESRCH; + + return (-1); + } + if (pid == runqueue.curr->pid) { + errno = ECHILD; + + return (-1); + } + if (options != 0 && options != WNOHANG) { + errno = EINVAL; + + return (-1); + } + if (status == NULL) { + errno = EFAULT; + + return (-1); + } + list_head *it; + list_for_each (it, &runqueue.curr->children) { + task_struct *entry = list_entry(it, task_struct, sibling); + if (entry == NULL) { + continue; + } + if (entry->state != EXIT_ZOMBIE) { + continue; + } + if ((pid > 1) && (entry->pid != pid)) { + continue; + } + // Save the pid to return. + pid_t ppid = entry->pid; + // Save the state. + (*status) = entry->state; //TODO: da rivedere + // Remove entry from children of parent. + list_head_del(&entry->sibling); + // Delete the task_struct. + kfree(entry); + dbg_print("Freeing memory of process %d.\n", ppid); + + return ppid; + } + + return 0; +} + +void sys_exit(int exit_code) +{ + // Get the current task. + if (runqueue.curr == NULL) { + kernel_panic("There is no current process!"); + } + + task_struct *init_proc = kernel_get_running_process(1); + if (runqueue.curr == init_proc) { + kernel_panic("Init process cannot call sys_exit!"); + } + // Set the termination code of the process. + runqueue.curr->exit_code = (exit_code << 8) & 0xFF00; + // Set the state of the process to zombie. + runqueue.curr->state = EXIT_ZOMBIE; + // If it has children, then init process has to take care of them. + if (!list_head_empty(&runqueue.curr->children)) { + dbg_print("Moving children of %s(%d) to init(%d): {\n", + runqueue.curr->name, runqueue.curr->pid, init_proc->pid); + // TODO: Try to plug the list of children instead of iterating. + list_head *it; + list_for_each (it, &runqueue.curr->children) { + task_struct *entry = list_entry(it, task_struct, sibling); + dbg_print(" [%d] %s\n", entry->pid, entry->name); + it = entry->sibling.prev; + list_head_del(&entry->sibling); + list_head_add_tail(&init_proc->children, &entry->sibling); + entry->parent = init_proc; + } + dbg_print("}\n"); + dbg_print("Listing children of init(%d): {\n", init_proc->pid); + list_for_each (it, &init_proc->children) { + task_struct *entry = list_entry(it, task_struct, sibling); + dbg_print(" [%d] %s\n", entry->pid, entry->name); + } + dbg_print("}\n"); + } + // Free the space occupied by the stack. + destroy_process_image(runqueue.curr->mm); + // Clean resources needed by. + for (size_t i = 0; i < TASK_RESOURCE_MAX_AMOUNT; i++) { + runqueue.curr->resources[i] = NULL; + } + // Debugging message. + dbg_print("Process %d exited with value %d\n", runqueue.curr->pid, + exit_code); +} diff --git a/mentos/src/process/scheduler_algorithm.c b/mentos/src/process/scheduler_algorithm.c index eb5667d..a320d54 100644 --- a/mentos/src/process/scheduler_algorithm.c +++ b/mentos/src/process/scheduler_algorithm.c @@ -1,73 +1,81 @@ -/// @file scheduler_algorithm.c -/// @brief Round Robin algorithm. -/// @date Mar 2019. - -#include "prio.h" -#include "debug.h" -#include "assert.h" -#include "list_head.h" -#include "scheduler.h" - -#define GET_WEIGHT(prio) prio_to_weight[USER_PRIO((prio))] -#define NICE_0_LOAD GET_WEIGHT(DEFAULT_PRIO) - -task_struct *pick_next_task(runqueue_t *runqueue, time_t delta_exec) -{ - // Pointer to the next task to schedule. - task_struct *next = NULL; - -#if defined(SCHEDULER_RR) - //==== Implementatin of the Round-Robin Scheduling algorithm ============ - - - - //======================================================================= -#elif defined(SCHEDULER_PRIORITY) - //==== Implementatin of the Priority Scheduling algorithm =============== - - // get the first element of the list - next = list_entry(/*...*/); - - // Get its static priority. - time_t min = /*...*/ - - list_head *it; - // Inter over the runqueue to find the task with the smallest priority value - list_for_each (it, &runqueue->queue) { - task_struct *entry = list_entry(/*...*/); - // Check entry has a lower priority - if (/*...*/) { - /*...*/ - } - } - - //======================================================================= -#elif defined(SCHEDULER_CFS) - //==== Implementatin of the Completely Fair Scheduling ================== - - // Get the weight of the current process. - // (use GET_WEIGHT macro!) - int weight = /*...*/ - - if (weight != NICE_0_LOAD) { - // get the multiplicative factor for its delta_exec. - double factor = /*...*/ - - // weight the delta_exec with the multiplicative factor. - delta_exec = // ... - } - - // Update vruntime of the current process. - // ... - - // Inter over the runqueue to find the task with the smallest vruntime value - // ... - - //======================================================================== -#else -#error "You should enable a scheduling algorithm!" -#endif - assert(next && "No valid task selected. Have you implemented a scheduling algorithm?"); - - return next; -} +/// @file scheduler_algorithm.c +/// @brief Round Robin algorithm. +/// @date Mar 2019. + +#include "prio.h" +#include "debug.h" +#include "assert.h" +#include "list_head.h" +#include "scheduler.h" + +#define GET_WEIGHT(prio) prio_to_weight[USER_PRIO((prio))] +#define NICE_0_LOAD GET_WEIGHT(DEFAULT_PRIO) + +task_struct *pick_next_task(runqueue_t *runqueue, time_t delta_exec) +{ + // Pointer to the next task to schedule. + task_struct *next = NULL; + +#if defined(SCHEDULER_RR) + //==== Implementatin of the Round-Robin Scheduling algorithm ============ + + // nNode = next(c) + struct list_head *nNode = runqueue->curr->run_list.next; + + // if isHead(L, nNode) + if (nNode == &runqueue->queue) + nNode = nNode->next; + + // n = entry(nNode) + next = list_entry(nNode, struct task_struct, run_list); + + //======================================================================= +#elif defined(SCHEDULER_PRIORITY) + //==== Implementatin of the Priority Scheduling algorithm =============== + + // get the first element of the list + next = list_entry(/*...*/); + + // Get its static priority. + time_t min = /*...*/ + + list_head *it; + // Inter over the runqueue to find the task with the smallest priority value + list_for_each (it, &runqueue->queue) { + task_struct *entry = list_entry(/*...*/); + // Check entry has a lower priority + if (/*...*/) { + /*...*/ + } + } + + //======================================================================= +#elif defined(SCHEDULER_CFS) + //==== Implementatin of the Completely Fair Scheduling ================== + + // Get the weight of the current process. + // (use GET_WEIGHT macro!) + int weight = /*...*/ + + if (weight != NICE_0_LOAD) { + // get the multiplicative factor for its delta_exec. + double factor = /*...*/ + + // weight the delta_exec with the multiplicative factor. + delta_exec = // ... + } + + // Update vruntime of the current process. + // ... + + // Inter over the runqueue to find the task with the smallest vruntime value + // ... + + //======================================================================== +#else +#error "You should enable a scheduling algorithm!" +#endif + assert(next && "No valid task selected. Have you implemented a scheduling algorithm?"); + + return next; +} diff --git a/mentos/src/process/user.asm b/mentos/src/process/user.asm index 4116e81..ee982aa 100644 --- a/mentos/src/process/user.asm +++ b/mentos/src/process/user.asm @@ -1,82 +1,82 @@ -; MentOS, The Mentoring Operating system project -; @file user.asm -; @brief -; @copyright (c) 2019 This file is distributed under the MIT License. -; See LICENSE.md for details. - -; Enter userspace (ring3) (from Ring 0, namely Kernel) -; Usage: enter_userspace(uintptr_t location, uintptr_t stack); -; On stack -; | stack | -; | location | -; | return address | -; | EBP | EBP -; | SS | -; | ESP | -; | EFLAGS | -; | CS | -; | EIP | - -global enter_userspace ; Allows the C code to call enter_userspace(...). -enter_userspace: - - push ebp ; Save current ebp - mov ebp, esp ; open a new stack frame - - ;==== Segment selector ===================================================== - mov ax, 0x23 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - ; we don't need to worry about SS. it's handled by iret - ;--------------------------------------------------------------------------- - - ; We have to prepare the following stack before executing iret - ; SS --> Segment selector - ; ESP --> Stack address - ; EFLAGS --> CPU state flgas - ; CS --> Code segment - ; EIP --> Entry point - ; - - ;==== User data segmenet with bottom 2 bits set for ring3 ?================= - push 0x23 ; push SS on Kernel's stack - ;--------------------------------------------------------------------------- - - ;==== (ESP) Stack address ================================================== - mov eax, [ebp + 0xC] ; get uintptr_t stack - push eax ; push process's stack address on Kernel's stack - ;--------------------------------------------------------------------------- - - ;==== (EFLAGS) ============================================================= - pushf ; push EFLAGS into Kernel's stack - pop eax ; pop EFLAGS into eax - or eax, 0x200 ; enable interrupt ?request ring3 - push eax ; push new EFLAGS on Kernel's stack - ;--------------------------------------------------------------------------- - - ;==== (CS) Code Segment ==================================================== - push 0x1B ; - ;--------------------------------------------------------------------------- - - ;==== (EIP) Entry point ==================================================== - mov eax, [ebp + 0x8] ; get uintptr_t location - push eax ; push uintptr_t location on Kernel's stack - ;--------------------------------------------------------------------------- - - iret ; interrupt return - - ; WE SHOULD NOT STILL BE HERE! :( - - ;==== Reset segment selector =============================================== - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - ;--------------------------------------------------------------------------- - - add esp, 0x14 ; reset stack pointer (20 bytes) - pop ebp ; reset value of ebp - ret ; return to kernel code +; MentOS, The Mentoring Operating system project +; @file user.asm +; @brief +; @copyright (c) 2019 This file is distributed under the MIT License. +; See LICENSE.md for details. + +; Enter userspace (ring3) (from Ring 0, namely Kernel) +; Usage: enter_userspace(uintptr_t location, uintptr_t stack); +; On stack +; | stack | +; | location | +; | return address | +; | EBP | EBP +; | SS | +; | ESP | +; | EFLAGS | +; | CS | +; | EIP | + +global enter_userspace ; Allows the C code to call enter_userspace(...). +enter_userspace: + + push ebp ; Save current ebp + mov ebp, esp ; open a new stack frame + + ;==== Segment selector ===================================================== + mov ax, 0x23 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + ; we don't need to worry about SS. it's handled by iret + ;--------------------------------------------------------------------------- + + ; We have to prepare the following stack before executing iret + ; SS --> Segment selector + ; ESP --> Stack address + ; EFLAGS --> CPU state flgas + ; CS --> Code segment + ; EIP --> Entry point + ; + + ;==== User data segmenet with bottom 2 bits set for ring3 ?================= + push 0x23 ; push SS on Kernel's stack + ;--------------------------------------------------------------------------- + + ;==== (ESP) Stack address ================================================== + mov eax, [ebp + 0xC] ; get uintptr_t stack + push eax ; push process's stack address on Kernel's stack + ;--------------------------------------------------------------------------- + + ;==== (EFLAGS) ============================================================= + pushf ; push EFLAGS into Kernel's stack + pop eax ; pop EFLAGS into eax + or eax, 0x200 ; enable interrupt ?request ring3 + push eax ; push new EFLAGS on Kernel's stack + ;--------------------------------------------------------------------------- + + ;==== (CS) Code Segment ==================================================== + push 0x1B ; + ;--------------------------------------------------------------------------- + + ;==== (EIP) Entry point ==================================================== + mov eax, [ebp + 0x8] ; get uintptr_t location + push eax ; push uintptr_t location on Kernel's stack + ;--------------------------------------------------------------------------- + + iret ; interrupt return + + ; WE SHOULD NOT STILL BE HERE! :( + + ;==== Reset segment selector =============================================== + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + ;--------------------------------------------------------------------------- + + add esp, 0x14 ; reset stack pointer (20 bytes) + pop ebp ; reset value of ebp + ret ; return to kernel code diff --git a/mentos/src/sys/dirent.c b/mentos/src/sys/dirent.c index 18a851e..7521772 100644 --- a/mentos/src/sys/dirent.c +++ b/mentos/src/sys/dirent.c @@ -1,84 +1,84 @@ -/// MentOS, The Mentoring Operating system project -/// @file dirent.c -/// @brief Functions used to manage directories. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "dirent.h" -#include "string.h" -#include "vfs.h" -#include "kheap.h" -#include "stdio.h" -#include "initrd.h" -#include "debug.h" -#include "syscall_types.h" -#include "assert.h" -#include "errno.h" - -DIR *opendir(const char *path) -{ - char absolute_path[PATH_MAX]; - DIR *pdir = NULL; - - strcpy(absolute_path, path); - // If the first character is not the '/' then get the absolute path. - if (absolute_path[0] != '/') { - if (!get_absolute_path(absolute_path)) { - dbg_print("Cannot get the absolute path.\n"); - - return NULL; - } - } - - // Get the mount point id. - int32_t mp_id = get_mountpoint_id(absolute_path); - if (mp_id < 0) { - printf("opendir: cannot open directory '%s':" - "Cannot find mount-point\n", - absolute_path); - - return NULL; - } - - if (mountpoint_list[mp_id].dir_op.opendir_f == NULL) { - printf("opendir: cannot open directory '%s':" - "No opendir function\n", - absolute_path); - - return NULL; - } - - pdir = mountpoint_list[mp_id].dir_op.opendir_f(absolute_path); - // If the directiry is correctly open, set the handle. - if (pdir != NULL) { - pdir->fd = mp_id; - } - - return pdir; -} - -int closedir(DIR *dirp) -{ - if (dirp == NULL) { - printf("closedir: cannot close directory :" - "Directory pointer is not valid\n"); - - return -1; - } - if (mountpoint_list[dirp->fd].dir_op.closedir_f == NULL) { - printf("closedir: cannot close directory '%s':" - "No closedir function\n", - dirp->path); - - return -1; - } - return mountpoint_list[dirp->fd].dir_op.closedir_f(dirp); -} - -dirent_t *readdir(DIR *dirp) -{ - dirent_t *dent; - // Call the readdir system call. - DEFN_SYSCALL1(dent, __NR_readdir, dirp); - return dent; -} +/// MentOS, The Mentoring Operating system project +/// @file dirent.c +/// @brief Functions used to manage directories. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "dirent.h" +#include "string.h" +#include "vfs.h" +#include "kheap.h" +#include "stdio.h" +#include "initrd.h" +#include "debug.h" +#include "syscall_types.h" +#include "assert.h" +#include "errno.h" + +DIR *opendir(const char *path) +{ + char absolute_path[PATH_MAX]; + DIR *pdir = NULL; + + strcpy(absolute_path, path); + // If the first character is not the '/' then get the absolute path. + if (absolute_path[0] != '/') { + if (!get_absolute_path(absolute_path)) { + dbg_print("Cannot get the absolute path.\n"); + + return NULL; + } + } + + // Get the mount point id. + int32_t mp_id = get_mountpoint_id(absolute_path); + if (mp_id < 0) { + printf("opendir: cannot open directory '%s':" + "Cannot find mount-point\n", + absolute_path); + + return NULL; + } + + if (mountpoint_list[mp_id].dir_op.opendir_f == NULL) { + printf("opendir: cannot open directory '%s':" + "No opendir function\n", + absolute_path); + + return NULL; + } + + pdir = mountpoint_list[mp_id].dir_op.opendir_f(absolute_path); + // If the directiry is correctly open, set the handle. + if (pdir != NULL) { + pdir->fd = mp_id; + } + + return pdir; +} + +int closedir(DIR *dirp) +{ + if (dirp == NULL) { + printf("closedir: cannot close directory :" + "Directory pointer is not valid\n"); + + return -1; + } + if (mountpoint_list[dirp->fd].dir_op.closedir_f == NULL) { + printf("closedir: cannot close directory '%s':" + "No closedir function\n", + dirp->path); + + return -1; + } + return mountpoint_list[dirp->fd].dir_op.closedir_f(dirp); +} + +dirent_t *readdir(DIR *dirp) +{ + dirent_t *dent; + // Call the readdir system call. + DEFN_SYSCALL1(dent, __NR_readdir, dirp); + return dent; +} diff --git a/mentos/src/sys/module.c b/mentos/src/sys/module.c index 62bce4e..4a05767 100644 --- a/mentos/src/sys/module.c +++ b/mentos/src/sys/module.c @@ -1,7 +1,7 @@ -/// MentOS, The Mentoring Operating system project -/// @file module.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "module.h" +/// MentOS, The Mentoring Operating system project +/// @file module.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "module.h" diff --git a/mentos/src/sys/shm.c b/mentos/src/sys/shm.c index a2c8d21..60c0bbd 100644 --- a/mentos/src/sys/shm.c +++ b/mentos/src/sys/shm.c @@ -1,362 +1,362 @@ -/// MentOS, The Mentoring Operating system project -/// @file shm.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "shm.h" - -struct shmid_ds *head = NULL; -static ushort shm_descriptor = 0; - -int syscall_shmctl(int *args) -{ - int shmid = args[0]; - int cmd = args[1]; - - // TODO: for IPC_STAT - // struct shmid_ds * buf = (struct shmid_ds *) args[2]; - - struct shmid_ds *myshmid_ds = find_shm_fromid(shmid); - - if (myshmid_ds == NULL) { - return -1; - } - - // Upgrade shm info. - myshmid_ds->shm_lpid = kernel_get_current_process()->pid; - myshmid_ds->shm_ctime = time(NULL); - - switch (cmd) { - case IPC_RMID: - if (myshmid_ds->shm_nattch == 0) { - kfree(myshmid_ds->shm_location); - - // Manage list. - if (myshmid_ds == head) { - head = head->next; - } else { - // Finding the previous shmid_ds. - struct shmid_ds *prev = head; - while (prev->next != myshmid_ds) { - prev = prev->next; - } - prev->next = myshmid_ds->next; - } - kfree(myshmid_ds); - } else { - (myshmid_ds->shm_perm).mode |= SHM_DEST; - } - - return 0; - - case IPC_STAT: - break; - case IPC_SET: - break; - case SHM_LOCK: - break; - case SHM_UNLOCK: - break; - default: - break; - } - - return -1; -} - -// Get shared memory segment. -int syscall_shmget(int *args) -{ - int flags = args[2]; - key_t key = (key_t)args[0]; - size_t size = (size_t)args[1]; - - struct shmid_ds *shmid_ds; - - if (flags & IPC_EXCL) { - return -1; - } - - if (flags & IPC_CREAT) { - shmid_ds = find_shm_fromkey(key); - - if (shmid_ds != NULL) { - return -1; - } - - shmid_ds = kmalloc(sizeof(struct shmid_ds)); - dbg_print("\n[SHM] shmget() shmid_ds : 0x%p", shmid_ds); - - shmid_ds->shm_location = kmalloc_align(size); - dbg_print("\n[SHM] shmget() Location : 0x%p", - shmid_ds->shm_location); - dbg_print("\n[SHM] shmget() physLocation : 0x%p", - paging_virtual_to_physical(get_current_page_directory(), - shmid_ds->shm_location)); - - shmid_ds->next = head; - head = shmid_ds; - - shmid_ds->shm_segsz = size; - shmid_ds->shm_atime = 0; - shmid_ds->shm_dtime = 0; - shmid_ds->shm_ctime = 0; - shmid_ds->shm_cpid = kernel_get_current_process()->pid; - shmid_ds->shm_lpid = kernel_get_current_process()->pid; - shmid_ds->shm_nattch = 0; - - // No user implementation. - (shmid_ds->shm_perm).cuid = 0; - // No group implementation. - (shmid_ds->shm_perm).cgid = 0; - // No user implementation - (shmid_ds->shm_perm).uid = 0; - // No group implementation. - (shmid_ds->shm_perm).gid = 0; - (shmid_ds->shm_perm).mode = flags & 0777; - (shmid_ds->shm_perm).seq = shm_descriptor++; - (shmid_ds->shm_perm).key = key; - } else { - shmid_ds = find_shm_fromkey(key); - dbg_print("\n[SHM] shmget() shmid_ds found : 0x%p", shmid_ds); - - if (shmid_ds == NULL) { - return -1; - } - - if ((flags & 0777) > ((shmid_ds->shm_perm).mode & 0777)) { - return -1; - } - shmid_ds->shm_lpid = kernel_get_current_process()->pid; - } - - return (shmid_ds->shm_perm).seq; -} - -// Attach shared memory segment. -void *syscall_shmat(int *args) -{ - int shmid = args[0]; - void *shmaddr = (void *)args[1]; - - // TODO: for more settings - // int flags = args[2]; - - struct shmid_ds *myshmid_ds = find_shm_fromid(shmid); - dbg_print("\n[SHM] shmat() shmid_ds found : 0x%p", myshmid_ds); - - if (myshmid_ds == NULL) { - return (void *)-1; - } - - void *shm_start = myshmid_ds->shm_location; - - if (shmaddr == NULL) { - void *ret = kmalloc_align(myshmid_ds->shm_segsz); - - uint32_t shm_vaddr_start = (uint32_t)ret & 0xfffff000; - uint32_t shm_vaddr_end = - ((uint32_t)ret + myshmid_ds->shm_segsz) & 0xfffff000; - - uint32_t shm_paddr_start = (uint32_t)paging_virtual_to_physical( - get_current_page_directory(), shm_start); - - free_map_region(get_current_page_directory(), shm_vaddr_start, - shm_vaddr_end, true); - - while (shm_vaddr_start <= shm_vaddr_end) { - paging_allocate_page(get_current_page_directory(), shm_vaddr_start, - shm_paddr_start / PAGE_SIZE, true, true); - shm_vaddr_start += PAGE_SIZE; - shm_paddr_start += PAGE_SIZE; - } - - dbg_print("\n[SHM] shmat() vaddr : 0x%p", ret); - dbg_print("\n[SHM] shmat() paddr : 0x%p", - (void *)shm_paddr_start); - dbg_print("\n[SHM] shmat() paddr after map: 0x%p", - paging_virtual_to_physical(get_current_page_directory(), - ret)); - - // Upgrade shm info. - myshmid_ds->shm_lpid = kernel_get_current_process()->pid; - (myshmid_ds->shm_nattch)++; - myshmid_ds->shm_atime = time(NULL); - - return ret; - } - - return (void *)-1; -} - -// Detach shared memory segment. -int syscall_shmdt(int *args) -{ - void *shmaddr = (void *)args[0]; - - if (shmaddr == NULL) { - return -1; - } - - struct shmid_ds *myshmid_ds = find_shm_fromvaddr(shmaddr); - dbg_print("\n[SHM] shmdt() shmid_ds found : 0x%p", myshmid_ds); - - if (myshmid_ds == NULL) { - return -1; - } - - // ===== Test ============================================================== - uint32_t shm_vaddr_start = (uint32_t)shmaddr & 0xfffff000; - uint32_t shm_vaddr_end = - ((uint32_t)shmaddr + myshmid_ds->shm_segsz) & 0xfffff000; - - free_map_region(get_current_page_directory(), shm_vaddr_start, - shm_vaddr_end, false); - - while (shm_vaddr_start <= shm_vaddr_end) { - paging_allocate_page(get_current_page_directory(), shm_vaddr_start, - shm_vaddr_start / PAGE_SIZE, true, true); - shm_vaddr_start += PAGE_SIZE; - } - // ========================================================================= - - kfree(shmaddr); - - // Upgrade shm info. - myshmid_ds->shm_lpid = kernel_get_current_process()->pid; - (myshmid_ds->shm_nattch)--; - myshmid_ds->shm_dtime = time(NULL); - - // Manage SHM_DEST flag on. - if (myshmid_ds->shm_nattch == 0 && (myshmid_ds->shm_perm).mode & SHM_DEST) { - kfree(myshmid_ds->shm_location); - - // Manage list. - if (myshmid_ds == head) { - head = head->next; - } else { - // Finding the previous shmid_ds. - struct shmid_ds *prev = head; - while (prev->next != myshmid_ds) { - prev = prev->next; - } - prev->next = myshmid_ds->next; - } - kfree(myshmid_ds); - } - - return 0; -} - -int shmctl(int shmid, int cmd, struct shmid_ds *buf) -{ - int error; - - __asm__("movl %0, %%ecx\n" - "movl %1, %%ebx\n" - "movl %2, %%edx\n" - "movl $6, %%eax\n" - "int $80\n" - : - : "r"(shmid), "r"(cmd), "r"(buf)); - __asm__("movl %%eax, %0\n\t" : "=r"(error)); - - return error; -} - -int shmget(key_t key, size_t size, int flags) -{ - int id; - - __asm__("movl %0, %%ecx\n" - "movl %1, %%ebx\n" - "movl %2, %%edx\n" - "movl $3, %%eax\n" - "int $80\n" - : - : "r"(key), "r"(size), "r"(flags)); - __asm__("movl %%eax, %0\n\t" : "=r"(id)); - - return id; -} - -void *shmat(int shmid, void *shmaddr, int flag) -{ - void *addr; - - __asm__("movl %0, %%ecx\n" - "movl %1, %%ebx\n" - "movl %2, %%edx\n" - "movl $4, %%eax\n" - "int $80\n" - : - : "r"(shmid), "r"(shmaddr), "r"(flag)); - // The kernel is serving my system call - - // Now I have the control - __asm__("movl %%eax, %0\n\t" : "=r"(addr)); - - return addr; -} - -int shmdt(void *shmaddr) -{ - int error; - - __asm__("movl %0, %%ecx\n" - "movl $5, %%eax\n" - "int $80\n" - : - : "r"(shmaddr)); - __asm__("movl %%eax, %0\n\t" : "=r"(error)); - - return error; -} - -struct shmid_ds *find_shm_fromid(int shmid) -{ - struct shmid_ds *res = head; - - while (res != NULL) { - if ((res->shm_perm).seq == shmid) { - return res; - } - res = res->next; - } - - return NULL; -} - -struct shmid_ds *find_shm_fromkey(key_t key) -{ - struct shmid_ds *res = head; - - while (res != NULL) { - if ((res->shm_perm).key == key) { - return res; - } - res = res->next; - } - - return NULL; -} - -struct shmid_ds *find_shm_fromvaddr(void *shmvaddr) -{ - void *shmpaddr = - paging_virtual_to_physical(get_current_page_directory(), shmvaddr); - void *paddr; - struct shmid_ds *res = head; - - while (res != NULL) { - paddr = paging_virtual_to_physical(get_current_page_directory(), - res->shm_location); - if (paddr == shmpaddr) { - return res; - } - res = res->next; - } - - return NULL; -} +/// MentOS, The Mentoring Operating system project +/// @file shm.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "shm.h" + +struct shmid_ds *head = NULL; +static ushort shm_descriptor = 0; + +int syscall_shmctl(int *args) +{ + int shmid = args[0]; + int cmd = args[1]; + + // TODO: for IPC_STAT + // struct shmid_ds * buf = (struct shmid_ds *) args[2]; + + struct shmid_ds *myshmid_ds = find_shm_fromid(shmid); + + if (myshmid_ds == NULL) { + return -1; + } + + // Upgrade shm info. + myshmid_ds->shm_lpid = kernel_get_current_process()->pid; + myshmid_ds->shm_ctime = time(NULL); + + switch (cmd) { + case IPC_RMID: + if (myshmid_ds->shm_nattch == 0) { + kfree(myshmid_ds->shm_location); + + // Manage list. + if (myshmid_ds == head) { + head = head->next; + } else { + // Finding the previous shmid_ds. + struct shmid_ds *prev = head; + while (prev->next != myshmid_ds) { + prev = prev->next; + } + prev->next = myshmid_ds->next; + } + kfree(myshmid_ds); + } else { + (myshmid_ds->shm_perm).mode |= SHM_DEST; + } + + return 0; + + case IPC_STAT: + break; + case IPC_SET: + break; + case SHM_LOCK: + break; + case SHM_UNLOCK: + break; + default: + break; + } + + return -1; +} + +// Get shared memory segment. +int syscall_shmget(int *args) +{ + int flags = args[2]; + key_t key = (key_t)args[0]; + size_t size = (size_t)args[1]; + + struct shmid_ds *shmid_ds; + + if (flags & IPC_EXCL) { + return -1; + } + + if (flags & IPC_CREAT) { + shmid_ds = find_shm_fromkey(key); + + if (shmid_ds != NULL) { + return -1; + } + + shmid_ds = kmalloc(sizeof(struct shmid_ds)); + dbg_print("\n[SHM] shmget() shmid_ds : 0x%p", shmid_ds); + + shmid_ds->shm_location = kmalloc_align(size); + dbg_print("\n[SHM] shmget() Location : 0x%p", + shmid_ds->shm_location); + dbg_print("\n[SHM] shmget() physLocation : 0x%p", + paging_virtual_to_physical(get_current_page_directory(), + shmid_ds->shm_location)); + + shmid_ds->next = head; + head = shmid_ds; + + shmid_ds->shm_segsz = size; + shmid_ds->shm_atime = 0; + shmid_ds->shm_dtime = 0; + shmid_ds->shm_ctime = 0; + shmid_ds->shm_cpid = kernel_get_current_process()->pid; + shmid_ds->shm_lpid = kernel_get_current_process()->pid; + shmid_ds->shm_nattch = 0; + + // No user implementation. + (shmid_ds->shm_perm).cuid = 0; + // No group implementation. + (shmid_ds->shm_perm).cgid = 0; + // No user implementation + (shmid_ds->shm_perm).uid = 0; + // No group implementation. + (shmid_ds->shm_perm).gid = 0; + (shmid_ds->shm_perm).mode = flags & 0777; + (shmid_ds->shm_perm).seq = shm_descriptor++; + (shmid_ds->shm_perm).key = key; + } else { + shmid_ds = find_shm_fromkey(key); + dbg_print("\n[SHM] shmget() shmid_ds found : 0x%p", shmid_ds); + + if (shmid_ds == NULL) { + return -1; + } + + if ((flags & 0777) > ((shmid_ds->shm_perm).mode & 0777)) { + return -1; + } + shmid_ds->shm_lpid = kernel_get_current_process()->pid; + } + + return (shmid_ds->shm_perm).seq; +} + +// Attach shared memory segment. +void *syscall_shmat(int *args) +{ + int shmid = args[0]; + void *shmaddr = (void *)args[1]; + + // TODO: for more settings + // int flags = args[2]; + + struct shmid_ds *myshmid_ds = find_shm_fromid(shmid); + dbg_print("\n[SHM] shmat() shmid_ds found : 0x%p", myshmid_ds); + + if (myshmid_ds == NULL) { + return (void *)-1; + } + + void *shm_start = myshmid_ds->shm_location; + + if (shmaddr == NULL) { + void *ret = kmalloc_align(myshmid_ds->shm_segsz); + + uint32_t shm_vaddr_start = (uint32_t)ret & 0xfffff000; + uint32_t shm_vaddr_end = + ((uint32_t)ret + myshmid_ds->shm_segsz) & 0xfffff000; + + uint32_t shm_paddr_start = (uint32_t)paging_virtual_to_physical( + get_current_page_directory(), shm_start); + + free_map_region(get_current_page_directory(), shm_vaddr_start, + shm_vaddr_end, true); + + while (shm_vaddr_start <= shm_vaddr_end) { + paging_allocate_page(get_current_page_directory(), shm_vaddr_start, + shm_paddr_start / PAGE_SIZE, true, true); + shm_vaddr_start += PAGE_SIZE; + shm_paddr_start += PAGE_SIZE; + } + + dbg_print("\n[SHM] shmat() vaddr : 0x%p", ret); + dbg_print("\n[SHM] shmat() paddr : 0x%p", + (void *)shm_paddr_start); + dbg_print("\n[SHM] shmat() paddr after map: 0x%p", + paging_virtual_to_physical(get_current_page_directory(), + ret)); + + // Upgrade shm info. + myshmid_ds->shm_lpid = kernel_get_current_process()->pid; + (myshmid_ds->shm_nattch)++; + myshmid_ds->shm_atime = time(NULL); + + return ret; + } + + return (void *)-1; +} + +// Detach shared memory segment. +int syscall_shmdt(int *args) +{ + void *shmaddr = (void *)args[0]; + + if (shmaddr == NULL) { + return -1; + } + + struct shmid_ds *myshmid_ds = find_shm_fromvaddr(shmaddr); + dbg_print("\n[SHM] shmdt() shmid_ds found : 0x%p", myshmid_ds); + + if (myshmid_ds == NULL) { + return -1; + } + + // ===== Test ============================================================== + uint32_t shm_vaddr_start = (uint32_t)shmaddr & 0xfffff000; + uint32_t shm_vaddr_end = + ((uint32_t)shmaddr + myshmid_ds->shm_segsz) & 0xfffff000; + + free_map_region(get_current_page_directory(), shm_vaddr_start, + shm_vaddr_end, false); + + while (shm_vaddr_start <= shm_vaddr_end) { + paging_allocate_page(get_current_page_directory(), shm_vaddr_start, + shm_vaddr_start / PAGE_SIZE, true, true); + shm_vaddr_start += PAGE_SIZE; + } + // ========================================================================= + + kfree(shmaddr); + + // Upgrade shm info. + myshmid_ds->shm_lpid = kernel_get_current_process()->pid; + (myshmid_ds->shm_nattch)--; + myshmid_ds->shm_dtime = time(NULL); + + // Manage SHM_DEST flag on. + if (myshmid_ds->shm_nattch == 0 && (myshmid_ds->shm_perm).mode & SHM_DEST) { + kfree(myshmid_ds->shm_location); + + // Manage list. + if (myshmid_ds == head) { + head = head->next; + } else { + // Finding the previous shmid_ds. + struct shmid_ds *prev = head; + while (prev->next != myshmid_ds) { + prev = prev->next; + } + prev->next = myshmid_ds->next; + } + kfree(myshmid_ds); + } + + return 0; +} + +int shmctl(int shmid, int cmd, struct shmid_ds *buf) +{ + int error; + + __asm__("movl %0, %%ecx\n" + "movl %1, %%ebx\n" + "movl %2, %%edx\n" + "movl $6, %%eax\n" + "int $80\n" + : + : "r"(shmid), "r"(cmd), "r"(buf)); + __asm__("movl %%eax, %0\n\t" : "=r"(error)); + + return error; +} + +int shmget(key_t key, size_t size, int flags) +{ + int id; + + __asm__("movl %0, %%ecx\n" + "movl %1, %%ebx\n" + "movl %2, %%edx\n" + "movl $3, %%eax\n" + "int $80\n" + : + : "r"(key), "r"(size), "r"(flags)); + __asm__("movl %%eax, %0\n\t" : "=r"(id)); + + return id; +} + +void *shmat(int shmid, void *shmaddr, int flag) +{ + void *addr; + + __asm__("movl %0, %%ecx\n" + "movl %1, %%ebx\n" + "movl %2, %%edx\n" + "movl $4, %%eax\n" + "int $80\n" + : + : "r"(shmid), "r"(shmaddr), "r"(flag)); + // The kernel is serving my system call + + // Now I have the control + __asm__("movl %%eax, %0\n\t" : "=r"(addr)); + + return addr; +} + +int shmdt(void *shmaddr) +{ + int error; + + __asm__("movl %0, %%ecx\n" + "movl $5, %%eax\n" + "int $80\n" + : + : "r"(shmaddr)); + __asm__("movl %%eax, %0\n\t" : "=r"(error)); + + return error; +} + +struct shmid_ds *find_shm_fromid(int shmid) +{ + struct shmid_ds *res = head; + + while (res != NULL) { + if ((res->shm_perm).seq == shmid) { + return res; + } + res = res->next; + } + + return NULL; +} + +struct shmid_ds *find_shm_fromkey(key_t key) +{ + struct shmid_ds *res = head; + + while (res != NULL) { + if ((res->shm_perm).key == key) { + return res; + } + res = res->next; + } + + return NULL; +} + +struct shmid_ds *find_shm_fromvaddr(void *shmvaddr) +{ + void *shmpaddr = + paging_virtual_to_physical(get_current_page_directory(), shmvaddr); + void *paddr; + struct shmid_ds *res = head; + + while (res != NULL) { + paddr = paging_virtual_to_physical(get_current_page_directory(), + res->shm_location); + if (paddr == shmpaddr) { + return res; + } + res = res->next; + } + + return NULL; +} diff --git a/mentos/src/sys/unistd.c b/mentos/src/sys/unistd.c index fb76d9d..770f899 100644 --- a/mentos/src/sys/unistd.c +++ b/mentos/src/sys/unistd.c @@ -1,37 +1,37 @@ -/// MentOS, The Mentoring Operating system project -/// @file unistd.c -/// @brief Functions used to manage files. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "unistd.h" - -#include "string.h" -#include "limits.h" -#include "stdio.h" -#include "vfs.h" - -int rmdir(const char *path) -{ - char absolute_path[PATH_MAX]; - strcpy(absolute_path, path); - - if (path[0] != '/') { - get_absolute_path(absolute_path); - } - - int32_t mp_id = get_mountpoint_id(absolute_path); - if (mp_id < 0) { - printf("rmdir: failed to remove '%s':" - "Cannot find mount-point\n", - path); - - return -1; - } - - if (mountpoint_list[mp_id].dir_op.rmdir_f == NULL) { - return -1; - } - - return mountpoint_list[mp_id].dir_op.rmdir_f(absolute_path); -} +/// MentOS, The Mentoring Operating system project +/// @file unistd.c +/// @brief Functions used to manage files. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "unistd.h" + +#include "string.h" +#include "limits.h" +#include "stdio.h" +#include "vfs.h" + +int rmdir(const char *path) +{ + char absolute_path[PATH_MAX]; + strcpy(absolute_path, path); + + if (path[0] != '/') { + get_absolute_path(absolute_path); + } + + int32_t mp_id = get_mountpoint_id(absolute_path); + if (mp_id < 0) { + printf("rmdir: failed to remove '%s':" + "Cannot find mount-point\n", + path); + + return -1; + } + + if (mountpoint_list[mp_id].dir_op.rmdir_f == NULL) { + return -1; + } + + return mountpoint_list[mp_id].dir_op.rmdir_f(absolute_path); +} diff --git a/mentos/src/sys/utsname.c b/mentos/src/sys/utsname.c index c72a8d7..c4f321e 100644 --- a/mentos/src/sys/utsname.c +++ b/mentos/src/sys/utsname.c @@ -1,20 +1,20 @@ -/// MentOS, The Mentoring Operating system project -/// @file utsname.c -/// @brief Functions used to provide information about the machine & OS. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "string.h" -#include "utsname.h" -#include "version.h" - -int uname(utsname_t *os_infos) -{ - // Uname code goes here. - strcpy(os_infos->sysname, OS_NAME); - strcpy(os_infos->version, OS_VERSION); - strcpy(os_infos->nodename, "testbed"); - strcpy(os_infos->machine, "i686"); - - return 0; -} +/// MentOS, The Mentoring Operating system project +/// @file utsname.c +/// @brief Functions used to provide information about the machine & OS. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "string.h" +#include "utsname.h" +#include "version.h" + +int uname(utsname_t *os_infos) +{ + // Uname code goes here. + strcpy(os_infos->sysname, OS_NAME); + strcpy(os_infos->version, OS_VERSION); + strcpy(os_infos->nodename, "testbed"); + strcpy(os_infos->machine, "i686"); + + return 0; +} diff --git a/mentos/src/system/errno.c b/mentos/src/system/errno.c index a48bdfc..c401531 100644 --- a/mentos/src/system/errno.c +++ b/mentos/src/system/errno.c @@ -1,22 +1,22 @@ -/// MentOS, The Mentoring Operating system project -/// @file errno.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "errno.h" -#include "scheduler.h" - -int *__geterrno() -{ - static int _errno = 0; - - task_struct *current_process = kernel_get_current_process(); - - if (current_process == NULL) - { - return &_errno; - } - - return ¤t_process->error_no; -} +/// MentOS, The Mentoring Operating system project +/// @file errno.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "errno.h" +#include "scheduler.h" + +int *__geterrno() +{ + static int _errno = 0; + + task_struct *current_process = kernel_get_current_process(); + + if (current_process == NULL) + { + return &_errno; + } + + return ¤t_process->error_no; +} diff --git a/mentos/src/system/panic.c b/mentos/src/system/panic.c index 57e0030..37191eb 100644 --- a/mentos/src/system/panic.c +++ b/mentos/src/system/panic.c @@ -1,18 +1,18 @@ -/// MentOS, The Mentoring Operating system project -/// @file panic.c -/// @brief Functions used to manage kernel panic. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "panic.h" -#include "elf.h" -#include "stdio.h" -#include "kernel.h" -#include "debug.h" - -void kernel_panic(const char *msg) -{ - dbg_print("\nPANIC:\n%s\n\nWelcome to Kernel Debugging Land...\n\n", msg); - dbg_print("\n"); - for (;;); -} +/// MentOS, The Mentoring Operating system project +/// @file panic.c +/// @brief Functions used to manage kernel panic. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "panic.h" +#include "elf.h" +#include "stdio.h" +#include "kernel.h" +#include "debug.h" + +void kernel_panic(const char *msg) +{ + dbg_print("\nPANIC:\n%s\n\nWelcome to Kernel Debugging Land...\n\n", msg); + dbg_print("\n"); + for (;;); +} diff --git a/mentos/src/system/printk.c b/mentos/src/system/printk.c index a0a308b..b3bb895 100644 --- a/mentos/src/system/printk.c +++ b/mentos/src/system/printk.c @@ -1,23 +1,23 @@ -/// MentOS, The Mentoring Operating system project -/// @file printk.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "printk.h" -#include "stdarg.h" -#include "stdio.h" -#include "video.h" - -void printk(const char *format, ...) -{ - char buffer[4096]; - va_list ap; - // Start variabile argument's list. - va_start(ap, format); - int len = vsprintf(buffer, format, ap); - va_end(ap); - - for (size_t i = 0; (i < len); ++i) - video_putc(buffer[i]); -} +/// MentOS, The Mentoring Operating system project +/// @file printk.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "printk.h" +#include "stdarg.h" +#include "stdio.h" +#include "video.h" + +void printk(const char *format, ...) +{ + char buffer[4096]; + va_list ap; + // Start variabile argument's list. + va_start(ap, format); + int len = vsprintf(buffer, format, ap); + va_end(ap); + + for (size_t i = 0; (i < len); ++i) + video_putc(buffer[i]); +} diff --git a/mentos/src/system/syscall.c b/mentos/src/system/syscall.c index d794e52..7e50eab 100644 --- a/mentos/src/system/syscall.c +++ b/mentos/src/system/syscall.c @@ -1,100 +1,108 @@ -/// MentOS, The Mentoring Operating system project -/// @file syscall.c -/// @brief System Call management functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "syscall.h" -#include "shm.h" -#include "isr.h" -#include "errno.h" -#include "video.h" -#include "fcntl.h" -#include "kernel.h" -#include "unistd.h" -#include "process.h" -#include "process.h" -#include "irqflags.h" -#include "scheduler.h" - -/// @brief The signature of a function call. -typedef int (*SystemCall)(); - -/// @brief The signature used to call the system call. -typedef uint32_t (*SystemCallFun)(uint32_t, ...); - -/// @brief The list of function call. -SystemCall sys_call_table[SYSCALL_NUMBER]; - -// Linux provides a "not implemented" system call, sys_ni_syscall(), which does -// nothing except return ENOSYS, the error corresponding to an invalid -// system call. This function is used to "plug the hole" in the rare event that -// a syscall is removed or otherwise made unavailable. -int sys_ni_syscall() -{ - return ENOSYS; -} - -void syscall_init() -{ - // Initialize the list of system calls. - for (uint32_t it = 0; it < SYSCALL_NUMBER; ++it) { - sys_call_table[it] = sys_ni_syscall; - } - - sys_call_table[__NR_exit] = (SystemCall)sys_exit; - sys_call_table[__NR_read] = (SystemCall)sys_read; - sys_call_table[__NR_write] = (SystemCall)sys_write; - sys_call_table[__NR_open] = (SystemCall)sys_open; - sys_call_table[__NR_close] = (SystemCall)sys_close; - sys_call_table[__NR_stat] = (SystemCall)sys_stat; - sys_call_table[__NR_mkdir] = (SystemCall)sys_mkdir; - sys_call_table[__NR_readdir] = (SystemCall)sys_readdir; - sys_call_table[__NR_getpid] = (SystemCall)sys_getpid; - sys_call_table[__NR_getppid] = (SystemCall)sys_getppid; - sys_call_table[__NR_vfork] = (SystemCall)sys_vfork; - sys_call_table[__NR_execve] = (SystemCall)sys_execve; - sys_call_table[__NR_nice] = (SystemCall)sys_nice; - sys_call_table[__NR_reboot] = (SystemCall)sys_reboot; - sys_call_table[__NR_waitpid] = (SystemCall)sys_waitpid; - sys_call_table[__NR_chdir] = (SystemCall)sys_chdir; - sys_call_table[__NR_getcwd] = (SystemCall)sys_getcwd; - sys_call_table[__NR_brk] = (SystemCall)umalloc; // TODO: sys_brk - sys_call_table[__NR_free] = (SystemCall)ufree; // TODO: sys_brk - - isr_install_handler(SYSTEM_CALL, &syscall_handler, "syscall_handler"); -} - -void syscall_handler(pt_regs *f) -{ - // print_intrframe(f); - - // The index of the requested system call. - uint32_t sc_index = f->eax; - - // The result of the system call. - int ret; - if (sc_index >= SYSCALL_NUMBER) { - ret = ENOSYS; - } else { - uintptr_t ptr = (uintptr_t)sys_call_table[sc_index]; - - SystemCallFun func = (SystemCallFun)ptr; - - uint32_t arg0 = f->ebx; - uint32_t arg1 = f->ecx; - uint32_t arg2 = f->edx; - uint32_t arg3 = f->esi; - uint32_t arg4 = f->edi; - if ((sc_index == __NR_vfork) || (sc_index == __NR_clone)) { - arg0 = (uintptr_t)f; - } else if (sc_index == __NR_execve) { - arg0 = (uintptr_t)f; - } - ret = func(arg0, arg1, arg2, arg3, arg4); - } - f->eax = ret; - - // Schedule next process. - kernel_schedule(f); -} +/// MentOS, The Mentoring Operating system project +/// @file syscall.c +/// @brief System Call management functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "syscall.h" +#include "shm.h" +#include "isr.h" +#include "errno.h" +#include "video.h" +#include "fcntl.h" +#include "kernel.h" +#include "unistd.h" +#include "process.h" +#include "process.h" +#include "irqflags.h" +#include "scheduler.h" + +#include "smart_sem_kernel.h" + +/// @brief The signature of a function call. +typedef int (*SystemCall)(); + +/// @brief The signature used to call the system call. +typedef uint32_t (*SystemCallFun)(uint32_t, ...); + +/// @brief The list of function call. +SystemCall sys_call_table[SYSCALL_NUMBER]; + +// Linux provides a "not implemented" system call, sys_ni_syscall(), which does +// nothing except return ENOSYS, the error corresponding to an invalid +// system call. This function is used to "plug the hole" in the rare event that +// a syscall is removed or otherwise made unavailable. +int sys_ni_syscall() +{ + return ENOSYS; +} + +void syscall_init() +{ + // Initialize the list of system calls. + for (uint32_t it = 0; it < SYSCALL_NUMBER; ++it) { + sys_call_table[it] = sys_ni_syscall; + } + + sys_call_table[__NR_exit] = (SystemCall)sys_exit; + sys_call_table[__NR_read] = (SystemCall)sys_read; + sys_call_table[__NR_write] = (SystemCall)sys_write; + sys_call_table[__NR_open] = (SystemCall)sys_open; + sys_call_table[__NR_close] = (SystemCall)sys_close; + sys_call_table[__NR_stat] = (SystemCall)sys_stat; + sys_call_table[__NR_mkdir] = (SystemCall)sys_mkdir; + sys_call_table[__NR_readdir] = (SystemCall)sys_readdir; + sys_call_table[__NR_getpid] = (SystemCall)sys_getpid; + sys_call_table[__NR_getppid] = (SystemCall)sys_getppid; + sys_call_table[__NR_vfork] = (SystemCall)sys_vfork; + sys_call_table[__NR_execve] = (SystemCall)sys_execve; + sys_call_table[__NR_nice] = (SystemCall)sys_nice; + sys_call_table[__NR_reboot] = (SystemCall)sys_reboot; + sys_call_table[__NR_waitpid] = (SystemCall)sys_waitpid; + sys_call_table[__NR_chdir] = (SystemCall)sys_chdir; + sys_call_table[__NR_getcwd] = (SystemCall)sys_getcwd; + sys_call_table[__NR_brk] = (SystemCall)umalloc; // TODO: sys_brk + sys_call_table[__NR_free] = (SystemCall)ufree; // TODO: sys_brk + + // sys_call_table[__NR_sem_...] = (SystemCall)sys_sem_...; + // sys_call_table[__NR_sem_...] = (SystemCall)sys_sem_...; + // sys_call_table[__NR_sem_...] = (SystemCall)sys_sem_...; + // sys_call_table[__NR_sem_...] = (SystemCall)sys_sem_...; + // sys_call_table[__NR_sem_...] = (SystemCall)sys_sem_...; + + isr_install_handler(SYSTEM_CALL, &syscall_handler, "syscall_handler"); +} + +void syscall_handler(pt_regs *f) +{ + // print_intrframe(f); + + // The index of the requested system call. + uint32_t sc_index = f->eax; + + // The result of the system call. + int ret; + if (sc_index >= SYSCALL_NUMBER) { + ret = ENOSYS; + } else { + uintptr_t ptr = (uintptr_t)sys_call_table[sc_index]; + + SystemCallFun func = (SystemCallFun)ptr; + + uint32_t arg0 = f->ebx; + uint32_t arg1 = f->ecx; + uint32_t arg2 = f->edx; + uint32_t arg3 = f->esi; + uint32_t arg4 = f->edi; + if ((sc_index == __NR_vfork) || (sc_index == __NR_clone)) { + arg0 = (uintptr_t)f; + } else if (sc_index == __NR_execve) { + arg0 = (uintptr_t)f; + } + ret = func(arg0, arg1, arg2, arg3, arg4); + } + f->eax = ret; + + // Schedule next process. + kernel_schedule(f); +} diff --git a/mentos/src/ui/command/cmd_cd.c b/mentos/src/ui/command/cmd_cd.c index a38e5f9..15c4ce0 100644 --- a/mentos/src/ui/command/cmd_cd.c +++ b/mentos/src/ui/command/cmd_cd.c @@ -1,59 +1,59 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_cd.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include -#include -#include "commands.h" -#include "vfs.h" -#include "stdio.h" -#include "dirent.h" -#include "string.h" -#include "libgen.h" - -void cmd_cd(int argc, char **argv) -{ - DIR *dirp = NULL; - char path[PATH_MAX]; - memset(path, 0, PATH_MAX); - - char current_path[PATH_MAX]; - getcwd(current_path, PATH_MAX); - - if (argc <= 1) { - strcpy(path, "/"); - } else if (argc > 2) { - printf("%s: too many arguments\n\n", argv[0]); - - return; - } else if (strncmp(argv[1], "..", 2) == 0) { - if (strcmp(current_path, dirname(current_path)) == 0) { - return; - } - strcpy(path, dirname(current_path)); - } else if (strncmp(argv[1], ".", 1) == 0) { - return; - } else { - // Copy the current path. - strcpy(path, current_path); - // Get the absolute path. - get_absolute_path(path); - // If the current directory is not the root, add a '/'. - if (strcmp(path, "/") != 0) { - strncat(path, "/", 1); - } - // Concatenate the input dir. - strncat(path, argv[1], strlen(argv[1])); - } - - dirp = opendir(path); - if (dirp == NULL) { - printf("%s: no such file or directory: %s\n\n", argv[0], argv[1]); - - return; - } - chdir(path); - closedir(dirp); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_cd.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include "commands.h" +#include "vfs.h" +#include "stdio.h" +#include "dirent.h" +#include "string.h" +#include "libgen.h" + +void cmd_cd(int argc, char **argv) +{ + DIR *dirp = NULL; + char path[PATH_MAX]; + memset(path, 0, PATH_MAX); + + char current_path[PATH_MAX]; + getcwd(current_path, PATH_MAX); + + if (argc <= 1) { + strcpy(path, "/"); + } else if (argc > 2) { + printf("%s: too many arguments\n\n", argv[0]); + + return; + } else if (strncmp(argv[1], "..", 2) == 0) { + if (strcmp(current_path, dirname(current_path)) == 0) { + return; + } + strcpy(path, dirname(current_path)); + } else if (strncmp(argv[1], ".", 1) == 0) { + return; + } else { + // Copy the current path. + strcpy(path, current_path); + // Get the absolute path. + get_absolute_path(path); + // If the current directory is not the root, add a '/'. + if (strcmp(path, "/") != 0) { + strncat(path, "/", 1); + } + // Concatenate the input dir. + strncat(path, argv[1], strlen(argv[1])); + } + + dirp = opendir(path); + if (dirp == NULL) { + printf("%s: no such file or directory: %s\n\n", argv[0], argv[1]); + + return; + } + chdir(path); + closedir(dirp); +} diff --git a/mentos/src/ui/command/cmd_clear.c b/mentos/src/ui/command/cmd_clear.c index fa2060b..d1826b9 100644 --- a/mentos/src/ui/command/cmd_clear.c +++ b/mentos/src/ui/command/cmd_clear.c @@ -1,15 +1,15 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_clear.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "video.h" - -void cmd_clear(int argc, char **argv) -{ - (void) argc; - (void) argv; - video_clear(); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_clear.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "video.h" + +void cmd_clear(int argc, char **argv) +{ + (void) argc; + (void) argv; + video_clear(); +} diff --git a/mentos/src/ui/command/cmd_cpuid.c b/mentos/src/ui/command/cmd_cpuid.c index fc9ab06..0dcdc01 100644 --- a/mentos/src/ui/command/cmd_cpuid.c +++ b/mentos/src/ui/command/cmd_cpuid.c @@ -1,118 +1,118 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_cpuid.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "string.h" -#include "cmd_cpuid.h" - -void cmd_cpuid(int argc, char **argv) -{ - (void)argc; - (void)argv; - - // List of features. - const char *ecx_features[ECX_FLAGS_SIZE] = { - "SSE3", - "Reserved", - "Reserved", - "Monitor/MWAIT", - "CPL Debug Store", - "Virtual Machine", - "Safer Mode", - "Enhanced Intel SpeedStep Technology", - "Thermal Monitor 2", - "SSSE3", - "L1 Context ID", - "Reserved", - "Reserved", - "CMPXCHG16B", - "xTPR Update Control", - "Perfmon and Debug Capability", - "Reserved", - "Reserved", - "DCA", - "SSE4.1", - "SSE4.2", - "Reserved", - "Reserved", - "POPCNT" - }; - - const char *edx_features[EDX_FLAGS_SIZE] = { - "x87 FPU", - "Virtual 8086 Mode", - "Debugging Extensions", - "Page Size Extensions", - "Time Stamp Counter", - "RDMSR and WRMSR", - "Physical Address Extensions", - "Machine Check Exception", - "CMPXCHG8B", - "APIC On-chip", - "Reserved", - "SYSENTER and SYSEXIT", - "Memory Type Range Registers", - "PTE Global Bit", - "Machine Check Architecture", - "Conditional Move Instructions", - "Page Attribute Table", - "36-bit Page Size", - "Processor Serial Number", - "Reserved", - "Debug Store", - "Thermal Monitor and Clock Facilities", - "Intel MMX", - "FXSAVE and FXRSTOR", - "SSE", - "SSE2", - "Self Snoop", - "Multi-Threading", - "TTC", - "Reserved", - "Pending Break Enable" - }; - - int i; - int verbose = 0; - - // Examine possible options. - if (argv[1] != NULL) { - if (strcmp(argv[1], "-v") == 0) { - verbose = 1; - } else { - printf("Unknown option %s\n", argv[1]); - printf("CPUID help message\n" - "-v : shows verbose CPUID information\n"); - - return; - } - } - - printf("----- CPU ID Information -----\n"); - if (strcmp(sinfo.brand_string, "Reserved") != 0) { - printf("%s\n", sinfo.brand_string); - } - printf("Vendor: %s\n", sinfo.cpu_vendor); - printf("Type: %s, Family: %x, Model: %x\n", sinfo.cpu_type, - sinfo.cpu_family, sinfo.cpu_model); - printf("Apic ID: %d\n", sinfo.apic_id); - - if (verbose == 1) { - printf("\n--- Supported features ---\n"); - for (i = 0; i < ECX_FLAGS_SIZE; i++) { - if (sinfo.cpuid_ecx_flags[i] == 1) { - printf("%s\n", ecx_features[i]); - } - } - for (i = 0; i < EDX_FLAGS_SIZE; i++) { - if (sinfo.cpuid_edx_flags[i] == 1) { - printf("%s\n", edx_features[i]); - } - } - printf("---------------------------\n"); - } -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_cpuid.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "string.h" +#include "cmd_cpuid.h" + +void cmd_cpuid(int argc, char **argv) +{ + (void)argc; + (void)argv; + + // List of features. + const char *ecx_features[ECX_FLAGS_SIZE] = { + "SSE3", + "Reserved", + "Reserved", + "Monitor/MWAIT", + "CPL Debug Store", + "Virtual Machine", + "Safer Mode", + "Enhanced Intel SpeedStep Technology", + "Thermal Monitor 2", + "SSSE3", + "L1 Context ID", + "Reserved", + "Reserved", + "CMPXCHG16B", + "xTPR Update Control", + "Perfmon and Debug Capability", + "Reserved", + "Reserved", + "DCA", + "SSE4.1", + "SSE4.2", + "Reserved", + "Reserved", + "POPCNT" + }; + + const char *edx_features[EDX_FLAGS_SIZE] = { + "x87 FPU", + "Virtual 8086 Mode", + "Debugging Extensions", + "Page Size Extensions", + "Time Stamp Counter", + "RDMSR and WRMSR", + "Physical Address Extensions", + "Machine Check Exception", + "CMPXCHG8B", + "APIC On-chip", + "Reserved", + "SYSENTER and SYSEXIT", + "Memory Type Range Registers", + "PTE Global Bit", + "Machine Check Architecture", + "Conditional Move Instructions", + "Page Attribute Table", + "36-bit Page Size", + "Processor Serial Number", + "Reserved", + "Debug Store", + "Thermal Monitor and Clock Facilities", + "Intel MMX", + "FXSAVE and FXRSTOR", + "SSE", + "SSE2", + "Self Snoop", + "Multi-Threading", + "TTC", + "Reserved", + "Pending Break Enable" + }; + + int i; + int verbose = 0; + + // Examine possible options. + if (argv[1] != NULL) { + if (strcmp(argv[1], "-v") == 0) { + verbose = 1; + } else { + printf("Unknown option %s\n", argv[1]); + printf("CPUID help message\n" + "-v : shows verbose CPUID information\n"); + + return; + } + } + + printf("----- CPU ID Information -----\n"); + if (strcmp(sinfo.brand_string, "Reserved") != 0) { + printf("%s\n", sinfo.brand_string); + } + printf("Vendor: %s\n", sinfo.cpu_vendor); + printf("Type: %s, Family: %x, Model: %x\n", sinfo.cpu_type, + sinfo.cpu_family, sinfo.cpu_model); + printf("Apic ID: %d\n", sinfo.apic_id); + + if (verbose == 1) { + printf("\n--- Supported features ---\n"); + for (i = 0; i < ECX_FLAGS_SIZE; i++) { + if (sinfo.cpuid_ecx_flags[i] == 1) { + printf("%s\n", ecx_features[i]); + } + } + for (i = 0; i < EDX_FLAGS_SIZE; i++) { + if (sinfo.cpuid_edx_flags[i] == 1) { + printf("%s\n", edx_features[i]); + } + } + printf("---------------------------\n"); + } +} diff --git a/mentos/src/ui/command/cmd_credits.c b/mentos/src/ui/command/cmd_credits.c index b6d7cd8..5fe410d 100644 --- a/mentos/src/ui/command/cmd_credits.c +++ b/mentos/src/ui/command/cmd_credits.c @@ -1,28 +1,28 @@ -/// MentOS, The Mentoring Operating system project -/// @file credits.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "video.h" -#include "stdio.h" -#include "version.h" - -void cmd_credits(int argc, char **argv) -{ - (void) argc; - (void) argv; - video_set_color(BRIGHT_BLUE); - printf(OS_NAME" Credits\n\n"); - printf("Main Developers:\n"); - video_set_color(GREEN); - printf("Enrico Fraccaroli (Galfurian)\n"); - printf("Alessando Danese\n"); - video_set_color(BRIGHT_BLUE); - printf("Developers:\n"); - video_set_color(GREEN); - printf("Luigi C.\n" - "Mirco D.\n\n"); - video_set_color(WHITE); -} +/// MentOS, The Mentoring Operating system project +/// @file credits.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "video.h" +#include "stdio.h" +#include "version.h" + +void cmd_credits(int argc, char **argv) +{ + (void) argc; + (void) argv; + video_set_color(BRIGHT_BLUE); + printf(OS_NAME" Credits\n\n"); + printf("Main Developers:\n"); + video_set_color(GREEN); + printf("Enrico Fraccaroli (Galfurian)\n"); + printf("Alessando Danese\n"); + video_set_color(BRIGHT_BLUE); + printf("Developers:\n"); + video_set_color(GREEN); + printf("Luigi C.\n" + "Mirco D.\n\n"); + video_set_color(WHITE); +} diff --git a/mentos/src/ui/command/cmd_date.c b/mentos/src/ui/command/cmd_date.c index 3c96565..6791cb1 100644 --- a/mentos/src/ui/command/cmd_date.c +++ b/mentos/src/ui/command/cmd_date.c @@ -1,19 +1,19 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_date.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "clock.h" -#include "irqflags.h" - -void cmd_date(int argc, char **argv) -{ - (void)argc; - (void)argv; - printf("It's %x:%x:%x of %s %02x %s %02x\n", get_hour(), - get_minute(), get_second(), get_day_lng(), - get_day_m(), get_month_lng(), 0x2000 + get_year()); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_date.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "clock.h" +#include "irqflags.h" + +void cmd_date(int argc, char **argv) +{ + (void)argc; + (void)argv; + printf("It's %x:%x:%x of %s %02x %s %02x\n", get_hour(), + get_minute(), get_second(), get_day_lng(), + get_day_m(), get_month_lng(), 0x2000 + get_year()); +} diff --git a/mentos/src/ui/command/cmd_deadlock.c b/mentos/src/ui/command/cmd_deadlock.c new file mode 100644 index 0000000..6dcd4da --- /dev/null +++ b/mentos/src/ui/command/cmd_deadlock.c @@ -0,0 +1,123 @@ +/// MentOS, The Mentoring Operating system project +/// @file cmd_deadlock.c +/// @brief Source file of deadlock shell command to test deadlock behavior with tasks and shared resources. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "unistd.h" +#include "wait.h" + +#include "smart_sem_user.h" + +#define DEFAULT_ITER "1" + +/// @brief Task 1 for reproducing deadlock on resource r1 and r2. +static int _deadlock_task1(int argc, char **argv, char **envp); +/// @brief Task 2 for reproducing deadlock on resource r1 and r2. +static int _deadlock_task2(int argc, char **argv, char **envp); + +/// @brief Mutex semaphores that manage the resources access. +int mutex_r1, mutex_r2; +/// @brief Resources accessed by tasks. +uint32_t r1 = 0, r2 = 0; + +static int _deadlock_task1(int argc, char **argv, char **envp) +{ + (void) envp; + pid_t cpid2; + + size_t iter = (size_t) atoi(argc > 1 ? argv[1] : DEFAULT_ITER); + + if ((cpid2 = vfork()) == 0) { + char *_argv[] = {"_deadlock_task2", argc > 1 ? argv[1] : DEFAULT_ITER, (char *) NULL}; + char *_envp[] = {(char *) NULL}; + + execve((const char *) _deadlock_task2, _argv, _envp); + + printf("cmd_deadlock should not arrive here\n"); + return 0; + } + + for (size_t i = 0; i < iter; i++) { + sem_acquire(mutex_r1); + sem_acquire(mutex_r2); //< DEADLOCK! + + // Access shared resources. + uint32_t tmp = r1; + r1 = r2; + r2 = tmp; + + r1++; + + printf("[T1] { r1: %4i, r2: %4i }\n", r1, r2); + + sem_release(mutex_r2); + sem_release(mutex_r1); + } + + int status; + waitpid(cpid2, &status, 0); + return 0; +} + +static int _deadlock_task2(int argc, char **argv, char **envp) +{ + (void) envp; + + size_t iter = (size_t) atoi(argc > 1 ? argv[1] : DEFAULT_ITER); + + for (size_t i = 0; i < iter; i++) { + sem_acquire(mutex_r2); + sem_acquire(mutex_r1); //< DEADLOCK! + + // Access shared resources. + uint32_t tmp = r2; + r2 = r1; + r1 = tmp; + + r2++; + + printf("[T2] { r1: %4i, r2: %4i }\n", r1, r2); + + sem_release(mutex_r1); + sem_release(mutex_r2); + } + + return 0; +} + +void cmd_deadlock(int argc, char **argv) +{ + mutex_r1 = sem_create(); + mutex_r2 = sem_create(); + + sem_init(mutex_r1); + sem_init(mutex_r2); + + pid_t cpid1; + + char *iter_str = DEFAULT_ITER; + if (argc > 2 && (strcmp(argv[1], "-i") == 0)) { + iter_str = argv[2]; + } + + if ((cpid1 = vfork()) == 0) { + char *_argv[] = {"_deadlock_task1", iter_str, (char *) NULL}; + char *_envp[] = {(char *) NULL}; + + execve((const char *) _deadlock_task1, _argv, _envp); + + printf("cmd_deadlock should not arrive here\n"); + return; + } + + int status; + waitpid(cpid1, &status, 0); + + sem_destroy(mutex_r1); + sem_destroy(mutex_r2); +} \ No newline at end of file diff --git a/mentos/src/ui/command/cmd_drv_load.c b/mentos/src/ui/command/cmd_drv_load.c index 685eef1..87dea2d 100644 --- a/mentos/src/ui/command/cmd_drv_load.c +++ b/mentos/src/ui/command/cmd_drv_load.c @@ -1,53 +1,53 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_drv_load.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "mouse.h" -#include "string.h" -#include "stdio.h" - -void cmd_drv_load(int argc, char **argv) -{ - if (argc < 2) { - printf( - "No driver inserted or bad usage! Type %s --help for the usage.\n", - argv[0]); - } else { - if ((_kstrncmp(argv[1], "-r", 2) == 0)) { - if ((argv[2] != NULL)) { - if (_kstrncmp(argv[2], "mouse", 5) == 0) { - printf("Disattivamento %s in corso..\n", argv[2]); - mouse_disable(); - } else - printf("FATAL: Driver %s not found.\n", argv[2]); - } else - printf("Warning, no driver name inserted!\n"); - } else if (_kstrncmp(argv[1], "mouse", 5) == 0) { - // Enabling mouse. - mouse_install(); - } else if ((_kstrncmp(argv[1], "--help", 6) == 0) || - (_kstrncmp(argv[1], "-h", 2) == 0)) { - printf("---------------------------------------------------\n" - "Driver tool to load and kill driver\n" - "Simple to use, just type:\n" - "\n" - "Usage: %s - driver_name\n" - "\t-> %s module_name - to load driver\n" - "\t-> %s -r module_name - to kill driver\n" - "---------------------------------------------------\n", - argv[0], argv[0], argv[0]); - } else { - if ((_kstrncmp(argv[1], "-r", 2) == 0) && - (_kstrncmp(argv[2], "mouse", 5) == -1)) { - printf("FATAL: Driver %s not found.\n", argv[2]); - } - - else { - printf("FATAL: Driver %s not found.\n", argv[1]); - } - } - } -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_drv_load.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "mouse.h" +#include "string.h" +#include "stdio.h" + +void cmd_drv_load(int argc, char **argv) +{ + if (argc < 2) { + printf( + "No driver inserted or bad usage! Type %s --help for the usage.\n", + argv[0]); + } else { + if ((_kstrncmp(argv[1], "-r", 2) == 0)) { + if ((argv[2] != NULL)) { + if (_kstrncmp(argv[2], "mouse", 5) == 0) { + printf("Disattivamento %s in corso..\n", argv[2]); + mouse_disable(); + } else + printf("FATAL: Driver %s not found.\n", argv[2]); + } else + printf("Warning, no driver name inserted!\n"); + } else if (_kstrncmp(argv[1], "mouse", 5) == 0) { + // Enabling mouse. + mouse_install(); + } else if ((_kstrncmp(argv[1], "--help", 6) == 0) || + (_kstrncmp(argv[1], "-h", 2) == 0)) { + printf("---------------------------------------------------\n" + "Driver tool to load and kill driver\n" + "Simple to use, just type:\n" + "\n" + "Usage: %s - driver_name\n" + "\t-> %s module_name - to load driver\n" + "\t-> %s -r module_name - to kill driver\n" + "---------------------------------------------------\n", + argv[0], argv[0], argv[0]); + } else { + if ((_kstrncmp(argv[1], "-r", 2) == 0) && + (_kstrncmp(argv[2], "mouse", 5) == -1)) { + printf("FATAL: Driver %s not found.\n", argv[2]); + } + + else { + printf("FATAL: Driver %s not found.\n", argv[1]); + } + } + } +} diff --git a/mentos/src/ui/command/cmd_echo.c b/mentos/src/ui/command/cmd_echo.c index d8967b5..85f1804 100644 --- a/mentos/src/ui/command/cmd_echo.c +++ b/mentos/src/ui/command/cmd_echo.c @@ -1,22 +1,22 @@ -/// MentOS, The Mentoring Operating system project -/// @file echo.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" - -void cmd_echo(int argc, char **argv) -{ - int i = argc; - int j = 0; - if (argc == 1) { - printf(""); - } else { - while (--i > 0) { - printf("%s ", argv[++j]); - } - } - printf("\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file echo.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" + +void cmd_echo(int argc, char **argv) +{ + int i = argc; + int j = 0; + if (argc == 1) { + printf(""); + } else { + while (--i > 0) { + printf("%s ", argv[++j]); + } + } + printf("\n"); +} diff --git a/mentos/src/ui/command/cmd_ipcrm.c b/mentos/src/ui/command/cmd_ipcrm.c index 05856ca..92fa60b 100644 --- a/mentos/src/ui/command/cmd_ipcrm.c +++ b/mentos/src/ui/command/cmd_ipcrm.c @@ -1,50 +1,50 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_ipcrm.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "stdio.h" -#include "shm.h" -#include "string.h" - -extern struct shmid_ds *head; - -void cmd_ipcrm(int argc, char **argv) -{ - if (argc != 2) { - printf("Bad arguments: you have to specify only IPC id, see ipcs.\n"); - - return; - } - - struct shmid_ds *shmid_ds = head; - struct shmid_ds *prev = NULL; - - while (shmid_ds != NULL) { - char strid[10]; - int_to_str(strid, (shmid_ds->shm_perm).seq, 10); - - if (strcmp(strid, argv[1]) == 0) { - break; - } - - prev = shmid_ds; - shmid_ds = shmid_ds->next; - } - - if (shmid_ds == NULL) { - printf("No shared memory find. \n"); - } else { - kfree(shmid_ds->shm_location); - - // shmid_ds = head. - if (prev == NULL) { - head = head->next; - } else { - prev->next = shmid_ds->next; - } - - kfree(shmid_ds); - } -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_ipcrm.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "stdio.h" +#include "shm.h" +#include "string.h" + +extern struct shmid_ds *head; + +void cmd_ipcrm(int argc, char **argv) +{ + if (argc != 2) { + printf("Bad arguments: you have to specify only IPC id, see ipcs.\n"); + + return; + } + + struct shmid_ds *shmid_ds = head; + struct shmid_ds *prev = NULL; + + while (shmid_ds != NULL) { + char strid[10]; + int_to_str(strid, (shmid_ds->shm_perm).seq, 10); + + if (strcmp(strid, argv[1]) == 0) { + break; + } + + prev = shmid_ds; + shmid_ds = shmid_ds->next; + } + + if (shmid_ds == NULL) { + printf("No shared memory find. \n"); + } else { + kfree(shmid_ds->shm_location); + + // shmid_ds = head. + if (prev == NULL) { + head = head->next; + } else { + prev->next = shmid_ds->next; + } + + kfree(shmid_ds); + } +} diff --git a/mentos/src/ui/command/cmd_ipcs.c b/mentos/src/ui/command/cmd_ipcs.c index 9f39744..22cc6ba 100644 --- a/mentos/src/ui/command/cmd_ipcs.c +++ b/mentos/src/ui/command/cmd_ipcs.c @@ -1,83 +1,83 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_ipcs.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "shm.h" -#include "stdio.h" -#include "string.h" -#include "version.h" - -extern struct shmid_ds *head; - -static void print_sem_stat() -{ - printf("Semaphores: \n"); - printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", - "OWNER", "GROUP"); - printf("%-20s %-10s %-20s \n\n", "", "Semaphores not implemented", ""); -} - -static void print_shm_stat() -{ - struct shmid_ds *shm_list = head; - - printf("Shared Memory: \n"); - printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", - "OWNER", "GROUP"); - - while (shm_list != NULL) { - char mode[12]; - strmode((shm_list->shm_perm).mode, mode); - - printf("%-10s %-10i %-10i %-10s %-10s %-10s \n", "m", - (shm_list->shm_perm).seq, (shm_list->shm_perm).key, mode, "-", - "-"); - - shm_list = shm_list->next; - } - - printf("\n"); -} - -static void print_msg_stat() -{ - printf("Message Queues: \n"); - printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", - "OWNER", "GROUP"); - printf("%-20s %-10s %-20s \n\n", "", "Message Queues not implemented", ""); -} - -void cmd_ipcs(int argc, char **argv) -{ - if (argc > 2) { - printf("Too much arguments.\n"); - - return; - } - - char datehour[100] = ""; - strdatehour(datehour); - - printf("IPC status from " OS_NAME " as of %s\n", datehour); - - if (argc == 2) { - if (strcmp(argv[1], "-s") == 0) { - print_sem_stat(); - } else if (strcmp(argv[1], "-m") == 0) { - print_shm_stat(); - } else if (strcmp(argv[1], "-q") == 0) { - print_msg_stat(); - } else { - printf("Option not recognize.\n"); - } - } else { - print_sem_stat(); - print_shm_stat(); - print_msg_stat(); - } - - return; -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_ipcs.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "shm.h" +#include "stdio.h" +#include "string.h" +#include "version.h" + +extern struct shmid_ds *head; + +static void print_sem_stat() +{ + printf("Semaphores: \n"); + printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", + "OWNER", "GROUP"); + printf("%-20s %-10s %-20s \n\n", "", "Semaphores not implemented", ""); +} + +static void print_shm_stat() +{ + struct shmid_ds *shm_list = head; + + printf("Shared Memory: \n"); + printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", + "OWNER", "GROUP"); + + while (shm_list != NULL) { + char mode[12]; + strmode((shm_list->shm_perm).mode, mode); + + printf("%-10s %-10i %-10i %-10s %-10s %-10s \n", "m", + (shm_list->shm_perm).seq, (shm_list->shm_perm).key, mode, "-", + "-"); + + shm_list = shm_list->next; + } + + printf("\n"); +} + +static void print_msg_stat() +{ + printf("Message Queues: \n"); + printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", + "OWNER", "GROUP"); + printf("%-20s %-10s %-20s \n\n", "", "Message Queues not implemented", ""); +} + +void cmd_ipcs(int argc, char **argv) +{ + if (argc > 2) { + printf("Too much arguments.\n"); + + return; + } + + char datehour[100] = ""; + strdatehour(datehour); + + printf("IPC status from " OS_NAME " as of %s\n", datehour); + + if (argc == 2) { + if (strcmp(argv[1], "-s") == 0) { + print_sem_stat(); + } else if (strcmp(argv[1], "-m") == 0) { + print_shm_stat(); + } else if (strcmp(argv[1], "-q") == 0) { + print_msg_stat(); + } else { + printf("Option not recognize.\n"); + } + } else { + print_sem_stat(); + print_shm_stat(); + print_msg_stat(); + } + + return; +} diff --git a/mentos/src/ui/command/cmd_logo.c b/mentos/src/ui/command/cmd_logo.c index a1eb2e5..f326e69 100644 --- a/mentos/src/ui/command/cmd_logo.c +++ b/mentos/src/ui/command/cmd_logo.c @@ -1,38 +1,38 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_logo.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "video.h" -#include "stdio.h" -#include "version.h" - -#define LOGO_TAB " " -void cmd_logo(int argc, char **argv) -{ - (void)argc; - (void)argv; - video_set_color(BRIGHT_GREEN); - printf(LOGO_TAB " __ __ _ ___ ____ \n"); - printf(LOGO_TAB "| \\/ | ___ _ __ | |_ / _ \\ / ___| \n"); - printf(LOGO_TAB "| |\\/| | / _ \\ | '_ \\ | __| | | | | \\___ \\ \n"); - printf(LOGO_TAB "| | | | | __/ | | | | | |_ | |_| | ___) |\n"); - printf(LOGO_TAB "|_| |_| \\___| |_| |_| \\__| \\___/ |____/ \n"); - video_set_color(BRIGHT_BLUE); - printf("\n"); - printf(LOGO_TAB " Welcome to "); - video_set_color(WHITE); - printf(OS_NAME "\n"); - video_set_color(BRIGHT_BLUE); - printf(LOGO_TAB " The "); - video_set_color(WHITE); - printf("Mentoring Operating System"); - video_set_color(BRIGHT_BLUE); - printf(" ver. "); - video_set_color(WHITE); - printf(OS_VERSION "\n"); - printf("\n"); - video_set_color(WHITE); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_logo.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "video.h" +#include "stdio.h" +#include "version.h" + +#define LOGO_TAB " " +void cmd_logo(int argc, char **argv) +{ + (void)argc; + (void)argv; + video_set_color(BRIGHT_GREEN); + printf(LOGO_TAB " __ __ _ ___ ____ \n"); + printf(LOGO_TAB "| \\/ | ___ _ __ | |_ / _ \\ / ___| \n"); + printf(LOGO_TAB "| |\\/| | / _ \\ | '_ \\ | __| | | | | \\___ \\ \n"); + printf(LOGO_TAB "| | | | | __/ | | | | | |_ | |_| | ___) |\n"); + printf(LOGO_TAB "|_| |_| \\___| |_| |_| \\__| \\___/ |____/ \n"); + video_set_color(BRIGHT_BLUE); + printf("\n"); + printf(LOGO_TAB " Welcome to "); + video_set_color(WHITE); + printf(OS_NAME "\n"); + video_set_color(BRIGHT_BLUE); + printf(LOGO_TAB " The "); + video_set_color(WHITE); + printf("Mentoring Operating System"); + video_set_color(BRIGHT_BLUE); + printf(" ver. "); + video_set_color(WHITE); + printf(OS_VERSION "\n"); + printf("\n"); + video_set_color(WHITE); +} diff --git a/mentos/src/ui/command/cmd_ls.c b/mentos/src/ui/command/cmd_ls.c index 8e10f1d..ad79761 100644 --- a/mentos/src/ui/command/cmd_ls.c +++ b/mentos/src/ui/command/cmd_ls.c @@ -1,104 +1,104 @@ -/// MentOS, The Mentoring Operating system project -/// @file ls.c -/// @brief Command 'ls'. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include -#include -#include "commands.h" -#include "vfs.h" -#include "stdio.h" -#include "video.h" -#include "dirent.h" -#include "string.h" -#include "bitops.h" -#include "libgen.h" -#include "strerror.h" - -#define FLAG_L 1 - -static void print_ls(DIR *dirp, uint32_t flags) -{ - // If the directory is open. - if (dirp == NULL) { - return; - } - - size_t total_size = 0; - dirent_t *dirent = readdir(dirp); - while (dirent != NULL) { - if (dirent->d_type == FS_DIRECTORY) { - video_set_color(BRIGHT_CYAN); - } - if (dirent->d_type == FS_MOUNTPOINT) { - video_set_color(BRIGHT_GREEN); - } - if (has_flag(flags, FLAG_L)) { - stat_t entry_stat; - if (stat(dirent->d_name, &entry_stat) != -1) { - printf("%d %3d %3d %8d %s\n", dirent->d_type, entry_stat.st_uid, - entry_stat.st_gid, entry_stat.st_size, - basename(dirent->d_name)); - total_size += entry_stat.st_size; - } - } else { - printf("%s ", basename(dirent->d_name)); - } - video_set_color(WHITE); - dirent = readdir(dirp); - } - - closedir(dirp); - printf("\n"); - if (has_flag(flags, FLAG_L)) { - printf("Total: %d byte\n", total_size); - } - printf("\n"); -} - -void cmd_ls(int argc, char **argv) -{ - // Create a variable to store flags. - uint32_t flags = 0; - // Check the number of arguments. - for (int i = 1; i < argc; ++i) { - if (strcmp(argv[i], "--help") == 0) { - printf("List information about files inside a given directory.\n"); - printf("Usage:\n"); - printf(" ls [options] [directory]\n\n"); - - return; - } else if (strcmp(argv[i], "-l") == 0) { - set_flag(&flags, FLAG_L); - } - } - - bool_t no_directory = true; - for (int i = 1; i < argc; ++i) { - if (strcmp(argv[i], "-l") == 0) { - continue; - } - - no_directory = false; - DIR *dirp = opendir(argv[i]); - if (dirp == NULL) { - printf("%s: cannot access '%s': %s\n\n", argv[0], argv[i], - "unknown" /*strerror(errno)*/); - - continue; - } - printf("%s:\n", argv[i]); - print_ls(dirp, flags); - } - if (no_directory) { - char cwd[PATH_MAX]; - getcwd(cwd, PATH_MAX); - DIR *dirp = opendir(cwd); - if (dirp == NULL) { - printf("%s: cannot access '%s': %s\n\n", argv[0], cwd, "unknown"); - } else { - print_ls(dirp, flags); - } - } -} +/// MentOS, The Mentoring Operating system project +/// @file ls.c +/// @brief Command 'ls'. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include "commands.h" +#include "vfs.h" +#include "stdio.h" +#include "video.h" +#include "dirent.h" +#include "string.h" +#include "bitops.h" +#include "libgen.h" +#include "strerror.h" + +#define FLAG_L 1 + +static void print_ls(DIR *dirp, uint32_t flags) +{ + // If the directory is open. + if (dirp == NULL) { + return; + } + + size_t total_size = 0; + dirent_t *dirent = readdir(dirp); + while (dirent != NULL) { + if (dirent->d_type == FS_DIRECTORY) { + video_set_color(BRIGHT_CYAN); + } + if (dirent->d_type == FS_MOUNTPOINT) { + video_set_color(BRIGHT_GREEN); + } + if (has_flag(flags, FLAG_L)) { + stat_t entry_stat; + if (stat(dirent->d_name, &entry_stat) != -1) { + printf("%d %3d %3d %8d %s\n", dirent->d_type, entry_stat.st_uid, + entry_stat.st_gid, entry_stat.st_size, + basename(dirent->d_name)); + total_size += entry_stat.st_size; + } + } else { + printf("%s ", basename(dirent->d_name)); + } + video_set_color(WHITE); + dirent = readdir(dirp); + } + + closedir(dirp); + printf("\n"); + if (has_flag(flags, FLAG_L)) { + printf("Total: %d byte\n", total_size); + } + printf("\n"); +} + +void cmd_ls(int argc, char **argv) +{ + // Create a variable to store flags. + uint32_t flags = 0; + // Check the number of arguments. + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--help") == 0) { + printf("List information about files inside a given directory.\n"); + printf("Usage:\n"); + printf(" ls [options] [directory]\n\n"); + + return; + } else if (strcmp(argv[i], "-l") == 0) { + set_flag(&flags, FLAG_L); + } + } + + bool_t no_directory = true; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "-l") == 0) { + continue; + } + + no_directory = false; + DIR *dirp = opendir(argv[i]); + if (dirp == NULL) { + printf("%s: cannot access '%s': %s\n\n", argv[0], argv[i], + "unknown" /*strerror(errno)*/); + + continue; + } + printf("%s:\n", argv[i]); + print_ls(dirp, flags); + } + if (no_directory) { + char cwd[PATH_MAX]; + getcwd(cwd, PATH_MAX); + DIR *dirp = opendir(cwd); + if (dirp == NULL) { + printf("%s: cannot access '%s': %s\n\n", argv[0], cwd, "unknown"); + } else { + print_ls(dirp, flags); + } + } +} diff --git a/mentos/src/ui/command/cmd_mkdir.c b/mentos/src/ui/command/cmd_mkdir.c index f1fca69..800e106 100644 --- a/mentos/src/ui/command/cmd_mkdir.c +++ b/mentos/src/ui/command/cmd_mkdir.c @@ -1,29 +1,29 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_mkdir.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stat.h" -#include "stdio.h" -#include "string.h" - -void cmd_mkdir(int argc, char **argv) -{ - // Check the number of arguments. - if (argc != 2) { - printf("%s: missing operand.\n", argv[0]); - printf("Try '%s --help' for more information.\n\n", argv[0]); - - return; - } - if (strcmp(argv[1], "--help") == 0) { - printf("Creates a new directory.\n"); - printf("Usage:\n"); - printf(" %s \n", argv[0]); - - return; - } - mkdir(argv[1], 0); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_mkdir.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stat.h" +#include "stdio.h" +#include "string.h" + +void cmd_mkdir(int argc, char **argv) +{ + // Check the number of arguments. + if (argc != 2) { + printf("%s: missing operand.\n", argv[0]); + printf("Try '%s --help' for more information.\n\n", argv[0]); + + return; + } + if (strcmp(argv[1], "--help") == 0) { + printf("Creates a new directory.\n"); + printf("Usage:\n"); + printf(" %s \n", argv[0]); + + return; + } + mkdir(argv[1], 0); +} diff --git a/mentos/src/ui/command/cmd_more.c b/mentos/src/ui/command/cmd_more.c index 0cc3575..df96c34 100644 --- a/mentos/src/ui/command/cmd_more.c +++ b/mentos/src/ui/command/cmd_more.c @@ -1,47 +1,47 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_more.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "fcntl.h" -#include "stdio.h" -#include "string.h" -#include "unistd.h" -#include "strerror.h" - -void cmd_more(int argc, char **argv) -{ - if (argc != 2) { - printf("%s: missing operand.\n", argv[0]); - printf("Try '%s --help' for more information.\n\n", argv[0]); - - return; - } - - if (strcmp(argv[1], "--help") == 0) { - printf("Prints the content of the given file.\n"); - printf("Usage:\n"); - printf(" %s \n\n", argv[0]); - - return; - } - - int fd = open(argv[1], O_RDONLY, 42); - if (fd < 0) { - printf("%s: Cannot stat file '%s': %s\n\n", argv[0], argv[1], - "unknown" /*strerror(errno)*/); - - return; - } - - char c; - // Put on the standard output the characters. - while (read(fd, &c, 1) > 0) { - putchar(c); - } - putchar('\n'); - putchar('\n'); - close(fd); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_more.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "fcntl.h" +#include "stdio.h" +#include "string.h" +#include "unistd.h" +#include "strerror.h" + +void cmd_more(int argc, char **argv) +{ + if (argc != 2) { + printf("%s: missing operand.\n", argv[0]); + printf("Try '%s --help' for more information.\n\n", argv[0]); + + return; + } + + if (strcmp(argv[1], "--help") == 0) { + printf("Prints the content of the given file.\n"); + printf("Usage:\n"); + printf(" %s \n\n", argv[0]); + + return; + } + + int fd = open(argv[1], O_RDONLY, 42); + if (fd < 0) { + printf("%s: Cannot stat file '%s': %s\n\n", argv[0], argv[1], + "unknown" /*strerror(errno)*/); + + return; + } + + char c; + // Put on the standard output the characters. + while (read(fd, &c, 1) > 0) { + putchar(c); + } + putchar('\n'); + putchar('\n'); + close(fd); +} diff --git a/mentos/src/ui/command/cmd_newfile.c b/mentos/src/ui/command/cmd_newfile.c index 2ac8ef3..257d123 100644 --- a/mentos/src/ui/command/cmd_newfile.c +++ b/mentos/src/ui/command/cmd_newfile.c @@ -1,57 +1,57 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_newfile.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "fcntl.h" -#include "string.h" -#include "unistd.h" -#include "strerror.h" -#include - -void cmd_newfile(int argc, char **argv) -{ - if (argc != 2) { - printf("%s: missing operand.\n", argv[0]); - printf("Try '%s --help' for more information.\n\n", argv[0]); - - return; - } - - if (strcmp(argv[1], "--help") == 0) { - printf("Makes a new file, and prompt for it's content.\n"); - printf("Usage:\n"); - printf(" %s \n", argv[0]); - - return; - } - - char text[256]; - printf("Filename: %s\n", argv[1]); - int fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, 0); - if (fd < 0) { - printf("%s: Cannot create file '%s': %s\n\n", argv[0], argv[1], - "unknown" /*strerror(errno)*/); - - return; - } - - printf("Type one line of text here (new line to complete):\n"); - scanf("%s", text); - if (write(fd, text, strlen(text)) == -1) { - printf("%s: Cannot write on file '%s': %s\n\n", argv[0], argv[1], - "unknown" /*strerror(errno)*/); - - return; - } - - if (close(fd) == -1) { - printf("%s: Cannot close file '%s': %s\n\n", argv[0], argv[1], - "unknown" /*strerror(errno)*/); - - return; - } -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_newfile.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "fcntl.h" +#include "string.h" +#include "unistd.h" +#include "strerror.h" +#include + +void cmd_newfile(int argc, char **argv) +{ + if (argc != 2) { + printf("%s: missing operand.\n", argv[0]); + printf("Try '%s --help' for more information.\n\n", argv[0]); + + return; + } + + if (strcmp(argv[1], "--help") == 0) { + printf("Makes a new file, and prompt for it's content.\n"); + printf("Usage:\n"); + printf(" %s \n", argv[0]); + + return; + } + + char text[256]; + printf("Filename: %s\n", argv[1]); + int fd = open(argv[1], O_RDWR | O_CREAT | O_APPEND, 0); + if (fd < 0) { + printf("%s: Cannot create file '%s': %s\n\n", argv[0], argv[1], + "unknown" /*strerror(errno)*/); + + return; + } + + printf("Type one line of text here (new line to complete):\n"); + scanf("%s", text); + if (write(fd, text, strlen(text)) == -1) { + printf("%s: Cannot write on file '%s': %s\n\n", argv[0], argv[1], + "unknown" /*strerror(errno)*/); + + return; + } + + if (close(fd) == -1) { + printf("%s: Cannot close file '%s': %s\n\n", argv[0], argv[1], + "unknown" /*strerror(errno)*/); + + return; + } +} diff --git a/mentos/src/ui/command/cmd_nice.c b/mentos/src/ui/command/cmd_nice.c index 497d366..fd6506f 100644 --- a/mentos/src/ui/command/cmd_nice.c +++ b/mentos/src/ui/command/cmd_nice.c @@ -1,43 +1,43 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_nice.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "unistd.h" -#include "string.h" - -void cmd_nice(int argc, char **argv) -{ - if (argc == 1) { - int current = nice(0); - printf("%d \n\n", current); - - return; - } - - if (argc != 2) { - printf("%s: missing operand.\n", argv[0]); - printf("Try '%s --help' for more information.\n\n", argv[0]); - - return; - } - - if (!strcmp(argv[1], "--help")) { - printf("Usage: %s \n\n", argv[0]); - - return; - } - - int increment = atoi(argv[1]); - if ((increment < -40) || (increment > 40)) { - printf("Error: You must provide a value between (-40,+40). \n\n", - increment); - - return; - } - int newNice = nice(increment); - printf("Your new nice value is %d.\n\n", newNice); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_nice.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "unistd.h" +#include "string.h" + +void cmd_nice(int argc, char **argv) +{ + if (argc == 1) { + int current = nice(0); + printf("%d \n\n", current); + + return; + } + + if (argc != 2) { + printf("%s: missing operand.\n", argv[0]); + printf("Try '%s --help' for more information.\n\n", argv[0]); + + return; + } + + if (!strcmp(argv[1], "--help")) { + printf("Usage: %s \n\n", argv[0]); + + return; + } + + int increment = atoi(argv[1]); + if ((increment < -40) || (increment > 40)) { + printf("Error: You must provide a value between (-40,+40). \n\n", + increment); + + return; + } + int newNice = nice(increment); + printf("Your new nice value is %d.\n\n", newNice); +} diff --git a/mentos/src/ui/command/cmd_poweroff.c b/mentos/src/ui/command/cmd_poweroff.c index 4c9ea1d..8b46ed1 100644 --- a/mentos/src/ui/command/cmd_poweroff.c +++ b/mentos/src/ui/command/cmd_poweroff.c @@ -1,21 +1,21 @@ -/// MentOS, The Mentoring Operating system project -/// @file poweroff.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "reboot.h" -#include "unistd.h" - -void cmd_poweroff(int argc, char **argv) -{ - (void) argc; - (void) argv; - printf("Executing power-off...\n"); - reboot(LINUX_REBOOT_MAGIC1, - LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_POWER_OFF, - NULL); -} +/// MentOS, The Mentoring Operating system project +/// @file poweroff.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "reboot.h" +#include "unistd.h" + +void cmd_poweroff(int argc, char **argv) +{ + (void) argc; + (void) argv; + printf("Executing power-off...\n"); + reboot(LINUX_REBOOT_MAGIC1, + LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_POWER_OFF, + NULL); +} diff --git a/mentos/src/ui/command/cmd_ps.c b/mentos/src/ui/command/cmd_ps.c index fd59ba8..375bd16 100644 --- a/mentos/src/ui/command/cmd_ps.c +++ b/mentos/src/ui/command/cmd_ps.c @@ -1,54 +1,54 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_ps.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "list.h" -#include "stdio.h" -#include "string.h" -#include "bitops.h" -#include "scheduler.h" - -#define PS_OPT_F (1 << 1) - -void cmd_ps(int argc, char **argv) -{ - // Flag variable. - uint32_t flags = 0; - - // Check arguments. - for (int i = 0; i < argc; ++i) { - size_t optlen = strlen(argv[i]); - if (optlen == 0) { - continue; - } - - if (argv[i][0] != '-') { - continue; - } - - for (size_t j = 1; j < optlen; ++j) { - if (argv[i][j] == 'f') { - set_flag(&flags, PS_OPT_F); - } - } - } - - if (has_flag(flags, PS_OPT_F)) { - // Print the header. - printf("%-6s", "PID"); - printf("%-6s", "STATE"); - printf("%-50s", "COMMAND"); - printf("\n"); - // print_tree(task_structree->root, 0); - } else { - // Print the header. - printf("%-6s", "PID"); - printf("%-6s", "STATE"); - printf("%-50s", "COMMAND"); - printf("\n"); - } - printf("\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_ps.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "list.h" +#include "stdio.h" +#include "string.h" +#include "bitops.h" +#include "scheduler.h" + +#define PS_OPT_F (1 << 1) + +void cmd_ps(int argc, char **argv) +{ + // Flag variable. + uint32_t flags = 0; + + // Check arguments. + for (int i = 0; i < argc; ++i) { + size_t optlen = strlen(argv[i]); + if (optlen == 0) { + continue; + } + + if (argv[i][0] != '-') { + continue; + } + + for (size_t j = 1; j < optlen; ++j) { + if (argv[i][j] == 'f') { + set_flag(&flags, PS_OPT_F); + } + } + } + + if (has_flag(flags, PS_OPT_F)) { + // Print the header. + printf("%-6s", "PID"); + printf("%-6s", "STATE"); + printf("%-50s", "COMMAND"); + printf("\n"); + // print_tree(task_structree->root, 0); + } else { + // Print the header. + printf("%-6s", "PID"); + printf("%-6s", "STATE"); + printf("%-50s", "COMMAND"); + printf("\n"); + } + printf("\n"); +} diff --git a/mentos/src/ui/command/cmd_pwd.c b/mentos/src/ui/command/cmd_pwd.c index 73a515e..799b8d2 100644 --- a/mentos/src/ui/command/cmd_pwd.c +++ b/mentos/src/ui/command/cmd_pwd.c @@ -1,19 +1,19 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_pwd.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include -#include -#include "commands.h" -#include "stdio.h" - -void cmd_pwd(int argc, char **argv) -{ - (void)argc; - (void)argv; - char cwd[PATH_MAX]; - getcwd(cwd, PATH_MAX); - printf("%s\n", cwd); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_pwd.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include "commands.h" +#include "stdio.h" + +void cmd_pwd(int argc, char **argv) +{ + (void)argc; + (void)argv; + char cwd[PATH_MAX]; + getcwd(cwd, PATH_MAX); + printf("%s\n", cwd); +} diff --git a/mentos/src/ui/command/cmd_rm.c b/mentos/src/ui/command/cmd_rm.c index 4e80b27..eb1ab06 100644 --- a/mentos/src/ui/command/cmd_rm.c +++ b/mentos/src/ui/command/cmd_rm.c @@ -1,51 +1,51 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_rm.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "fcntl.h" -#include "stdio.h" -#include "string.h" -#include "unistd.h" -#include "strerror.h" - -void cmd_rm(int argc, char **argv) -{ - if (argc != 2) - { - printf("%s: missing operand.\n", argv[0]); - printf("Try '%s --help' for more information.\n\n", argv[0]); - - return; - } - - if (strcmp(argv[1], "--help") == 0) - { - printf("Remove (unlink) the FILE(s).\n"); - printf("Usage:\n"); - printf(" rm \n"); - - return; - } - - int fd = open(argv[1], O_RDONLY, 0); - if (fd < 0) - { - printf("%s: cannot remove '%s': %s\n\n", - argv[0], argv[1], "unknown"/*strerror(errno)*/); - - return; - } - - close(fd); - if (remove(argv[1]) != 0) - { - printf("rm: cannot remove '%s': Failed to remove file\n\n", - argv[1]); - - return; - } - printf("\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_rm.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "fcntl.h" +#include "stdio.h" +#include "string.h" +#include "unistd.h" +#include "strerror.h" + +void cmd_rm(int argc, char **argv) +{ + if (argc != 2) + { + printf("%s: missing operand.\n", argv[0]); + printf("Try '%s --help' for more information.\n\n", argv[0]); + + return; + } + + if (strcmp(argv[1], "--help") == 0) + { + printf("Remove (unlink) the FILE(s).\n"); + printf("Usage:\n"); + printf(" rm \n"); + + return; + } + + int fd = open(argv[1], O_RDONLY, 0); + if (fd < 0) + { + printf("%s: cannot remove '%s': %s\n\n", + argv[0], argv[1], "unknown"/*strerror(errno)*/); + + return; + } + + close(fd); + if (remove(argv[1]) != 0) + { + printf("rm: cannot remove '%s': Failed to remove file\n\n", + argv[1]); + + return; + } + printf("\n"); +} diff --git a/mentos/src/ui/command/cmd_rmdir.c b/mentos/src/ui/command/cmd_rmdir.c index e423560..015bd4c 100644 --- a/mentos/src/ui/command/cmd_rmdir.c +++ b/mentos/src/ui/command/cmd_rmdir.c @@ -1,37 +1,37 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_rmdir.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "string.h" -#include "unistd.h" -#include "strerror.h" - -void cmd_rmdir(int argc, char **argv) -{ - // Check the number of arguments. - if (argc != 2) { - printf("Bad usage.\n"); - printf("Try 'rmdir --help' for more information.\n"); - - return; - } - - if (strcmp(argv[1], "--help") == 0) { - printf("Removes a directory.\n"); - printf("Usage:\n"); - printf(" rmdir \n"); - - return; - } - - if (rmdir(argv[1]) != 0) { - printf("%s: failed to remove '%s': %s\n\n", argv[0], argv[1], - "unknown" /*strerror(errno)*/); - - return; - } -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_rmdir.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "string.h" +#include "unistd.h" +#include "strerror.h" + +void cmd_rmdir(int argc, char **argv) +{ + // Check the number of arguments. + if (argc != 2) { + printf("Bad usage.\n"); + printf("Try 'rmdir --help' for more information.\n"); + + return; + } + + if (strcmp(argv[1], "--help") == 0) { + printf("Removes a directory.\n"); + printf("Usage:\n"); + printf(" rmdir \n"); + + return; + } + + if (rmdir(argv[1]) != 0) { + printf("%s: failed to remove '%s': %s\n\n", argv[0], argv[1], + "unknown" /*strerror(errno)*/); + + return; + } +} diff --git a/mentos/src/ui/command/cmd_showpid.c b/mentos/src/ui/command/cmd_showpid.c index 30e2d87..b105f00 100644 --- a/mentos/src/ui/command/cmd_showpid.c +++ b/mentos/src/ui/command/cmd_showpid.c @@ -1,15 +1,15 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_showpid.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "unistd.h" -#include "scheduler.h" - -void cmd_showpid(int argc, char **argv) -{ - printf("pid %d\n", getpid()); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_showpid.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "unistd.h" +#include "scheduler.h" + +void cmd_showpid(int argc, char **argv) +{ + printf("pid %d\n", getpid()); +} diff --git a/mentos/src/ui/command/cmd_sleep.c b/mentos/src/ui/command/cmd_sleep.c index b588807..f77659c 100644 --- a/mentos/src/ui/command/cmd_sleep.c +++ b/mentos/src/ui/command/cmd_sleep.c @@ -1,43 +1,43 @@ -/// MentOS, The Mentoring Operating system project -/// @file sleep.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "string.h" -#include "stdio.h" -#include "timer.h" -#include "clock.h" - -void cmd_sleep(int argc, char ** argv) -{ - if (argc != 2) - { - printf("%s: missing operand.\n", argv[0]); - printf("Try '%s --help' for more information.\n\n", argv[0]); - - return; - } - - if (!strcmp(argv[1], "--help")) - { - printf("Usage: %s \n\n", argv[0]); - - return; - } - - int seconds = atoi(argv[1]); - if (seconds <= 0) - { - printf("Error: You must provide a positive value (%d). \n\n", seconds); - - return; - } - - time_t t0 = get_hour() * 60 * 60 + get_minute() * 60 + get_second(); - printf("Start sleeping at '%d' for %ds...\n", t0, seconds); - sleep((time_t) seconds); - time_t t1 = get_hour() * 60 * 60 + get_minute() * 60 + get_second(); - printf("End sleeping at '%d' after %ds.\n", t1, t1 - t0); -} +/// MentOS, The Mentoring Operating system project +/// @file sleep.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "string.h" +#include "stdio.h" +#include "timer.h" +#include "clock.h" + +void cmd_sleep(int argc, char ** argv) +{ + if (argc != 2) + { + printf("%s: missing operand.\n", argv[0]); + printf("Try '%s --help' for more information.\n\n", argv[0]); + + return; + } + + if (!strcmp(argv[1], "--help")) + { + printf("Usage: %s \n\n", argv[0]); + + return; + } + + int seconds = atoi(argv[1]); + if (seconds <= 0) + { + printf("Error: You must provide a positive value (%d). \n\n", seconds); + + return; + } + + time_t t0 = get_hour() * 60 * 60 + get_minute() * 60 + get_second(); + printf("Start sleeping at '%d' for %ds...\n", t0, seconds); + sleep((time_t) seconds); + time_t t1 = get_hour() * 60 * 60 + get_minute() * 60 + get_second(); + printf("End sleeping at '%d' after %ds.\n", t1, t1 - t0); +} diff --git a/mentos/src/ui/command/cmd_tester.c b/mentos/src/ui/command/cmd_tester.c index 2921455..efd3f68 100644 --- a/mentos/src/ui/command/cmd_tester.c +++ b/mentos/src/ui/command/cmd_tester.c @@ -1,353 +1,353 @@ -/// MentOS, The Mentoring Operating system project -/// @file testing.c -/// @brief Commands used to test OS functionalities. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "shm.h" -#include "stdio.h" -#include "timer.h" -#include "debug.h" -#include "shell.h" -#include "video.h" -#include "assert.h" -#include "stdlib.h" -#include "unistd.h" -#include "string.h" -#include "spinlock.h" - -//Function used to test vfork. -int task_test_function(int argc, char *argv[]) -{ - (void)argc; - (void)argv; - printf("Hey there, here is %s with pid %d!\n", argv[0], getpid()); - sleep(12); - printf("Here is %s with pid %d, I'm leaving.\n", argv[0], getpid()); - - return 0; -} - -void try_process(int argc, char **argv) -{ - printf("I'm %d, testing task creation functions...\n", getpid()); - pid_t cpid = vfork(); - - if (cpid == 0) { - char *_cmd[] = { "task_test_function", (char *)NULL }; - char *_env[] = { (char *)NULL }; - execve((const char *)task_test_function, _cmd, _env); - assert(false && "I should not be here."); - } - printf("Executed process with pid %d...\n", cpid); -} - -void try_stress_heap(int argc, char **argv) -{ - uint32_t max_element = 1000; - if (argc >= 1) { - int val = atoi(argv[0]); - if (val > 0) { - max_element = (uint32_t)val; - } - } - - dbg_print("Starting allocation of matrix of %d...\n", max_element); - uint32_t **elements = malloc(max_element * sizeof(uint32_t *)); - dbg_print("Starting allocation of each vector...\n"); - for (uint32_t i = 0; i < max_element; ++i) { - elements[i] = malloc(100 * sizeof(uint32_t)); - (*elements[i]) = i; - } - - dbg_print("Starting de-allocation of each vector...\n"); - for (uint32_t i = 0; i < max_element; ++i) { - free(elements[i]); - } - free(elements); - dbg_print("Done\n"); -} - -// Share memory keys used in shm test. -#define SHMKEY1 81 -#define SHMKEY2 82 - -// Spinlock used in the following shm test. -static spinlock_t shmspinlock1; -static spinlock_t shmspinlock2; - -// @brief Function used to test the shm. -int shm_test_1(void *args) -{ - (void)args; - - printf("[T1] I am the first process to be executed.\n"); - - int shmid = shmget(SHMKEY1, 128 * sizeof(char), 0777); - if (shmid == -1) { - printf("[T1] Error: shmget() failed!\n"); - - return -1; - } - printf("[T1] I have got a share memory with ID %i.\n", shmid); - - char *myshm = shmat(shmid, NULL, 0); - if (myshm == (void *)-1) { - printf("[T1] Error: shmat() failed!\n"); - - return -1; - } - printf("[T1] I attached the share memory in my virtual address. \n"); - printf("[T1] SHM VIRTUAL ADDRESS %p\n", myshm); - printf("[T1] SHM PHYSICAL ADDRESS %p\n", - paging_virtual_to_physical(get_current_page_directory(), myshm)); - - printf("[T1] Writing something on share memory.\n"); - memcpy(myshm, "Bella questa Share Memory!", 27); - - int ret = shmdt(myshm); - if (ret == -1) { - printf("[T1] Error: shmdt() failed!\n"); - - return -1; - } - printf("[T1] Share memory detached\n"); - - printf("[T2] Passing the control to Task 2.\n"); - spinlock_unlock(&shmspinlock1); - - return 0; -} - -// Function used to test the shm. -int shm_test_2(void *args) -{ - (void)args; - printf("[T2] I'm waiting that T1 finishes...\n"); - spinlock_lock(&shmspinlock1); - printf("[T2] Now it's my turn!\n"); - - int shmid = shmget(SHMKEY1, 128 * sizeof(char), 0777); - if (shmid == -1) { - printf("[T2] Error: shmget() failed!\n"); - - return -1; - } - printf("[T2] I have got a share memory with ID %i.\n", shmid); - - char *myshm = shmat(shmid, NULL, 0); - if (myshm == (void *)-1) { - printf("[T2] Error: shmat() failed!\n"); - - return -1; - } - printf("[T2] I attached the share memory in my virtual address. \n"); - printf("[T2] SHM VIRTUAL ADDRESS %p\n", myshm); - printf("[T2] SHM PHYSICAL ADDRESS %p\n", - paging_virtual_to_physical(get_current_page_directory(), myshm)); - - printf("[T2] I'm going to see what's inside this share memory...\n"); - printf(" << "); - - char *c = myshm; - while (*c != '\0') { - printf("%c", *c++); - } - printf(" >>\n"); - - int ret = shmdt(myshm); - if (ret == -1) { - printf("[T2] Error: shmdt() failed!\n"); - - return -1; - } - printf("[T2] Share memory detached\n"); - - printf("[T2] Passing the control to my father\n"); - spinlock_unlock(&shmspinlock2); - - return 0; -} - -void try_shm(int argc, char **argv) -{ - printf("Testing shm functions...\n"); - // printf("[F] I am the father process.\n"); - // printf("[F] Creating shm: shmget()\n"); - // - // size_t size = 128 *sizeof(char); - // - // int shmid = shmget(SHMKEY1, size, IPC_CREAT | 0777); - // if (shmid == -1) - // { - // printf( - // "[F] Error: attempt to create a shared memory already created!\n"); - // - // return; - // } - // printf("[F] Share memory %i with ID %i and SIZE %i byte. \n", SHMKEY1, - // shmid, size); - // - // spinlock_init(&shmspinlock1); - // spinlock_init(&shmspinlock2); - // - // spinlock_lock(&shmspinlock1); - // spinlock_lock(&shmspinlock2); - // - // int process1_id = execvp(shm_test_1, - // "shm_test_1", - // "shm_test_1"); - // printf("[F] I have created Task 1 with pid: %d\n", process1_id); - // int process2_id = execvp(shm_test_2, - // "shm_test_2", - // "shm_test_2"); - // printf("[F] I have created Task 2 with pid: %d\n", process2_id); - // - // printf("[F] Now I have to wait child finished processing.\n"); - // spinlock_lock(&shmspinlock2); - // - // int ret = shmctl(shmid, IPC_RMID, NULL); - // if (ret == -1) - // { - // printf("[F] Error: shmctl() failed!\n"); - // return; - // } - // - // printf("[F] Share memory removed... Finished! :)\n"); -} - -void try_badshm() -{ - // Attempt to create a Shared Memory. - size_t size = sizeof(int); - mode_t mode = 0777; - - int shmid = shmget(SHMKEY2, size, IPC_CREAT | mode); - if (shmid == -1) { - printf("Error: attempt to create a shared memory already created!\n"); - - return; - } - - printf("I created a Shared Memory with: \n"); - printf(" -> KEY: %5i \n", SHMKEY2); - printf(" -> ID: %5i \n", shmid); - printf(" -> SIZE: %5i \n", size); - printf(" -> FLAGS: %5o \n", IPC_CREAT | mode); - - char mode_str[100]; - strmode(mode, mode_str); - printf(" -> PERMISSIONS: %5s \n", mode_str); - printf("but I don't want to free it! \n"); - printf("Other process/functions can get this share memory. \n"); - printf("Try ipcs. \n"); -} - -int run_to_2(void *args) -{ - (void)args; - for (int i = 1; i <= 2; i++) { - sleep(i); - } - - return 0; -} - -int run_to_3(void *args) -{ - (void)args; - (void)args; - - for (int i = 1; i <= 3; i++) { - sleep(i); - } - - return 0; -} - -void try_scheduler() -{ - unsigned int start = timer_get_ticks(); - // // Disable the IRQs. - // irq_disable(); - // struct task_struct * process1 = kernel_create_process(run_to_2, - // "run_to_2", - // "run_to_2"); - // printf("I have created Task 1 with pid: %d\n", process1->id); - // struct task_struct * process2 = kernel_create_process(run_to_3, - // "run_to_3", - // "run_to_3"); - // printf("I have created Task 2 with pid: %d\n", process2->id); - // // Re-Enable the IRQs. - // irq_enable(); - // wait(process1); - // wait(process2); - unsigned int end = timer_get_ticks(); - printf("Total time of execution: %d\n", end - start); -} - -// The maximum number of tests. -#define MAX_TEST 20 - -/// @brief Define testing functions. -struct { - /// The name of the test. - char cmd_testname[CMD_LEN]; - /// A description of the test. - char cmd_description[DESC_LEN]; - - /// A pointer to the function. - void (*func)(int, char **); -} _testing_functions[MAX_TEST] = { - { "try_process", "Test multiple processes creation", try_process }, - { "try_stress_heap", "Tries to stress the heap", try_stress_heap }, - { "try_shm", "Test shared memory", try_shm }, - { "try_badshm", "Test shared memory without free it", try_badshm }, - { "try_scheduler", "Test the performance of different schduler", - try_scheduler } -}; - -void cmd_tester(int argc, char **argv) -{ - if (argc <= 1) { - printf("Bad usage. Try '%s --help' for more info about the usage.\n", - argv[0]); - - return; - } - if (!strcmp(argv[1], "--help")) { - printf("Testing functions.. "); - video_set_color(RED); - printf("Warning: for developers only!\n"); - video_set_color(GREY); - for (size_t i = 0; i < MAX_TEST; i++) { - if (_testing_functions[i].func == NULL) { - break; - } - printf(" [%-2d] %-20s%-20s\n", i, - _testing_functions[i].cmd_testname, - _testing_functions[i].cmd_description); - } - video_set_color(WHITE); - - return; - } - int testid = atoi(argv[1]); - for (size_t i = 0; i < MAX_TEST; i++) { - if (testid != i) { - continue; - } - if (_testing_functions[i].func == NULL) { - break; - } - printf("Running test %d...\n", testid); - ++argv; - ++argv; - (_testing_functions[i].func)(argc - 2, argv); - printf("Done running test %d...\n", testid); - - return; - } - printf("Error: Test %s not found.\n", argv[1]); - printf(" You have to provide the test id.\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file testing.c +/// @brief Commands used to test OS functionalities. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "shm.h" +#include "stdio.h" +#include "timer.h" +#include "debug.h" +#include "shell.h" +#include "video.h" +#include "assert.h" +#include "stdlib.h" +#include "unistd.h" +#include "string.h" +#include "spinlock.h" + +//Function used to test vfork. +int task_test_function(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + printf("Hey there, here is %s with pid %d!\n", argv[0], getpid()); + sleep(12); + printf("Here is %s with pid %d, I'm leaving.\n", argv[0], getpid()); + + return 0; +} + +void try_process(int argc, char **argv) +{ + printf("I'm %d, testing task creation functions...\n", getpid()); + pid_t cpid = vfork(); + + if (cpid == 0) { + char *_cmd[] = { "task_test_function", (char *)NULL }; + char *_env[] = { (char *)NULL }; + execve((const char *)task_test_function, _cmd, _env); + assert(false && "I should not be here."); + } + printf("Executed process with pid %d...\n", cpid); +} + +void try_stress_heap(int argc, char **argv) +{ + uint32_t max_element = 1000; + if (argc >= 1) { + int val = atoi(argv[0]); + if (val > 0) { + max_element = (uint32_t)val; + } + } + + dbg_print("Starting allocation of matrix of %d...\n", max_element); + uint32_t **elements = malloc(max_element * sizeof(uint32_t *)); + dbg_print("Starting allocation of each vector...\n"); + for (uint32_t i = 0; i < max_element; ++i) { + elements[i] = malloc(100 * sizeof(uint32_t)); + (*elements[i]) = i; + } + + dbg_print("Starting de-allocation of each vector...\n"); + for (uint32_t i = 0; i < max_element; ++i) { + free(elements[i]); + } + free(elements); + dbg_print("Done\n"); +} + +// Share memory keys used in shm test. +#define SHMKEY1 81 +#define SHMKEY2 82 + +// Spinlock used in the following shm test. +static spinlock_t shmspinlock1; +static spinlock_t shmspinlock2; + +// @brief Function used to test the shm. +int shm_test_1(void *args) +{ + (void)args; + + printf("[T1] I am the first process to be executed.\n"); + + int shmid = shmget(SHMKEY1, 128 * sizeof(char), 0777); + if (shmid == -1) { + printf("[T1] Error: shmget() failed!\n"); + + return -1; + } + printf("[T1] I have got a share memory with ID %i.\n", shmid); + + char *myshm = shmat(shmid, NULL, 0); + if (myshm == (void *)-1) { + printf("[T1] Error: shmat() failed!\n"); + + return -1; + } + printf("[T1] I attached the share memory in my virtual address. \n"); + printf("[T1] SHM VIRTUAL ADDRESS %p\n", myshm); + printf("[T1] SHM PHYSICAL ADDRESS %p\n", + paging_virtual_to_physical(get_current_page_directory(), myshm)); + + printf("[T1] Writing something on share memory.\n"); + memcpy(myshm, "Bella questa Share Memory!", 27); + + int ret = shmdt(myshm); + if (ret == -1) { + printf("[T1] Error: shmdt() failed!\n"); + + return -1; + } + printf("[T1] Share memory detached\n"); + + printf("[T2] Passing the control to Task 2.\n"); + spinlock_unlock(&shmspinlock1); + + return 0; +} + +// Function used to test the shm. +int shm_test_2(void *args) +{ + (void)args; + printf("[T2] I'm waiting that T1 finishes...\n"); + spinlock_lock(&shmspinlock1); + printf("[T2] Now it's my turn!\n"); + + int shmid = shmget(SHMKEY1, 128 * sizeof(char), 0777); + if (shmid == -1) { + printf("[T2] Error: shmget() failed!\n"); + + return -1; + } + printf("[T2] I have got a share memory with ID %i.\n", shmid); + + char *myshm = shmat(shmid, NULL, 0); + if (myshm == (void *)-1) { + printf("[T2] Error: shmat() failed!\n"); + + return -1; + } + printf("[T2] I attached the share memory in my virtual address. \n"); + printf("[T2] SHM VIRTUAL ADDRESS %p\n", myshm); + printf("[T2] SHM PHYSICAL ADDRESS %p\n", + paging_virtual_to_physical(get_current_page_directory(), myshm)); + + printf("[T2] I'm going to see what's inside this share memory...\n"); + printf(" << "); + + char *c = myshm; + while (*c != '\0') { + printf("%c", *c++); + } + printf(" >>\n"); + + int ret = shmdt(myshm); + if (ret == -1) { + printf("[T2] Error: shmdt() failed!\n"); + + return -1; + } + printf("[T2] Share memory detached\n"); + + printf("[T2] Passing the control to my father\n"); + spinlock_unlock(&shmspinlock2); + + return 0; +} + +void try_shm(int argc, char **argv) +{ + printf("Testing shm functions...\n"); + // printf("[F] I am the father process.\n"); + // printf("[F] Creating shm: shmget()\n"); + // + // size_t size = 128 *sizeof(char); + // + // int shmid = shmget(SHMKEY1, size, IPC_CREAT | 0777); + // if (shmid == -1) + // { + // printf( + // "[F] Error: attempt to create a shared memory already created!\n"); + // + // return; + // } + // printf("[F] Share memory %i with ID %i and SIZE %i byte. \n", SHMKEY1, + // shmid, size); + // + // spinlock_init(&shmspinlock1); + // spinlock_init(&shmspinlock2); + // + // spinlock_lock(&shmspinlock1); + // spinlock_lock(&shmspinlock2); + // + // int process1_id = execvp(shm_test_1, + // "shm_test_1", + // "shm_test_1"); + // printf("[F] I have created Task 1 with pid: %d\n", process1_id); + // int process2_id = execvp(shm_test_2, + // "shm_test_2", + // "shm_test_2"); + // printf("[F] I have created Task 2 with pid: %d\n", process2_id); + // + // printf("[F] Now I have to wait child finished processing.\n"); + // spinlock_lock(&shmspinlock2); + // + // int ret = shmctl(shmid, IPC_RMID, NULL); + // if (ret == -1) + // { + // printf("[F] Error: shmctl() failed!\n"); + // return; + // } + // + // printf("[F] Share memory removed... Finished! :)\n"); +} + +void try_badshm() +{ + // Attempt to create a Shared Memory. + size_t size = sizeof(int); + mode_t mode = 0777; + + int shmid = shmget(SHMKEY2, size, IPC_CREAT | mode); + if (shmid == -1) { + printf("Error: attempt to create a shared memory already created!\n"); + + return; + } + + printf("I created a Shared Memory with: \n"); + printf(" -> KEY: %5i \n", SHMKEY2); + printf(" -> ID: %5i \n", shmid); + printf(" -> SIZE: %5i \n", size); + printf(" -> FLAGS: %5o \n", IPC_CREAT | mode); + + char mode_str[100]; + strmode(mode, mode_str); + printf(" -> PERMISSIONS: %5s \n", mode_str); + printf("but I don't want to free it! \n"); + printf("Other process/functions can get this share memory. \n"); + printf("Try ipcs. \n"); +} + +int run_to_2(void *args) +{ + (void)args; + for (int i = 1; i <= 2; i++) { + sleep(i); + } + + return 0; +} + +int run_to_3(void *args) +{ + (void)args; + (void)args; + + for (int i = 1; i <= 3; i++) { + sleep(i); + } + + return 0; +} + +void try_scheduler() +{ + unsigned int start = timer_get_ticks(); + // // Disable the IRQs. + // irq_disable(); + // struct task_struct * process1 = kernel_create_process(run_to_2, + // "run_to_2", + // "run_to_2"); + // printf("I have created Task 1 with pid: %d\n", process1->id); + // struct task_struct * process2 = kernel_create_process(run_to_3, + // "run_to_3", + // "run_to_3"); + // printf("I have created Task 2 with pid: %d\n", process2->id); + // // Re-Enable the IRQs. + // irq_enable(); + // wait(process1); + // wait(process2); + unsigned int end = timer_get_ticks(); + printf("Total time of execution: %d\n", end - start); +} + +// The maximum number of tests. +#define MAX_TEST 20 + +/// @brief Define testing functions. +struct { + /// The name of the test. + char cmd_testname[CMD_LEN]; + /// A description of the test. + char cmd_description[DESC_LEN]; + + /// A pointer to the function. + void (*func)(int, char **); +} _testing_functions[MAX_TEST] = { + { "try_process", "Test multiple processes creation", try_process }, + { "try_stress_heap", "Tries to stress the heap", try_stress_heap }, + { "try_shm", "Test shared memory", try_shm }, + { "try_badshm", "Test shared memory without free it", try_badshm }, + { "try_scheduler", "Test the performance of different schduler", + try_scheduler } +}; + +void cmd_tester(int argc, char **argv) +{ + if (argc <= 1) { + printf("Bad usage. Try '%s --help' for more info about the usage.\n", + argv[0]); + + return; + } + if (!strcmp(argv[1], "--help")) { + printf("Testing functions.. "); + video_set_color(RED); + printf("Warning: for developers only!\n"); + video_set_color(GREY); + for (size_t i = 0; i < MAX_TEST; i++) { + if (_testing_functions[i].func == NULL) { + break; + } + printf(" [%-2d] %-20s%-20s\n", i, + _testing_functions[i].cmd_testname, + _testing_functions[i].cmd_description); + } + video_set_color(WHITE); + + return; + } + int testid = atoi(argv[1]); + for (size_t i = 0; i < MAX_TEST; i++) { + if (testid != i) { + continue; + } + if (_testing_functions[i].func == NULL) { + break; + } + printf("Running test %d...\n", testid); + ++argv; + ++argv; + (_testing_functions[i].func)(argc - 2, argv); + printf("Done running test %d...\n", testid); + + return; + } + printf("Error: Test %s not found.\n", argv[1]); + printf(" You have to provide the test id.\n"); +} diff --git a/mentos/src/ui/command/cmd_touch.c b/mentos/src/ui/command/cmd_touch.c index 860b5aa..15ce32e 100644 --- a/mentos/src/ui/command/cmd_touch.c +++ b/mentos/src/ui/command/cmd_touch.c @@ -1,43 +1,43 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_touch.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "fcntl.h" -#include "stdio.h" -#include "string.h" -#include "unistd.h" - -void cmd_touch(int argc, char **argv) -{ - if (argc != 2) - { - printf("%s: missing operand.\n", argv[0]); - printf("Try '%s --help' for more information.\n\n", argv[0]); - - return; - } - - if (strcmp(argv[1], "--help") == 0) - { - printf("Updates modification times of a given fine. If the does not" - "exists, it creates it.\n"); - printf("Usage:\n"); - printf(" touch \n"); - - return; - } - - int fd = open(argv[1], O_RDONLY, 0); - if (fd < 0) - { - fd = open(argv[1], O_CREAT, 0); - if (fd >= 0) - { - close(fd); - } - } - printf("\n"); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_touch.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "fcntl.h" +#include "stdio.h" +#include "string.h" +#include "unistd.h" + +void cmd_touch(int argc, char **argv) +{ + if (argc != 2) + { + printf("%s: missing operand.\n", argv[0]); + printf("Try '%s --help' for more information.\n\n", argv[0]); + + return; + } + + if (strcmp(argv[1], "--help") == 0) + { + printf("Updates modification times of a given fine. If the does not" + "exists, it creates it.\n"); + printf("Usage:\n"); + printf(" touch \n"); + + return; + } + + int fd = open(argv[1], O_RDONLY, 0); + if (fd < 0) + { + fd = open(argv[1], O_CREAT, 0); + if (fd >= 0) + { + close(fd); + } + } + printf("\n"); +} diff --git a/mentos/src/ui/command/cmd_uname.c b/mentos/src/ui/command/cmd_uname.c index e0a7013..30263ec 100644 --- a/mentos/src/ui/command/cmd_uname.c +++ b/mentos/src/ui/command/cmd_uname.c @@ -1,97 +1,97 @@ -/// MentOS, The Mentoring Operating system project -/// @file uname.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" -#include "video.h" -#include "string.h" -#include "utsname.h" -#include "version.h" -#include "cmd_cpuid.h" - -void cmd_uname(int argc, char **argv) -{ - utsname_t utsname; - uname(&utsname); - if (argc != 2) { - printf("%s\n", utsname.sysname); - - return; - } - - if (!(strcmp(argv[1], "-a")) || !(strcmp(argv[1], "--all"))) { - printf("%s %s #1 CEST 2013 %s\n", utsname.sysname, utsname.version, - sinfo.cpu_vendor); - } else if (!(strcmp(argv[1], "-r")) || !(strcmp(argv[1], "--rev"))) { - printf("%s\n", utsname.version); - } else if (!(strcmp(argv[1], "-h")) || !(strcmp(argv[1], "--help"))) { - printf( - "Uname function allow you to see the kernel and system information.\n"); - printf("Function avaibles:\n"); - printf("1) -a - Kernel version and processor type\n" - "2) -r - Only the kernel version\n" - "3) -i - All info of system and kernel\n"); - } else if (!(strcmp(argv[1], "-i")) || !(strcmp(argv[1], "--info"))) { - printf("\n:==========: :System info: :==========:\n\n"); - printf("Version: %s\n", OS_VERSION); - printf("Major: %d\n", OS_MAJOR_VERSION); - printf("Minor: %d\n", OS_MINOR_VERSION); - printf("Micro: %d\n", OS_MICRO_VERSION); - - // CPU Info. - printf("\nCPU:"); - video_set_color(BRIGHT_RED); - video_move_cursor(61, video_get_line()); - printf(sinfo.cpu_vendor); - video_set_color(WHITE); - printf("\n"); - - // Memory RAM Info. - /* - * printf("Memory RAM: "); - * video_move_cursor(60, video_get_line()); - * printf(" %d Kb\n", get_memsize()/1024); - * - * // Memory free RAM Info - * printf(LNG_FREERAM); - * video_move_cursor(60, video_get_line()); - * printf(" %d Kb\n", get_numpages()); - * - * printf("\n"); - * // Bitmap Info - * printf("Number bitmap's elements: "); - * video_move_cursor(60, video_get_line()); - * printf(" %d", get_bmpelements()); - * video_move_cursor(60, video_get_line()); - */ - - // Mem_area Info. - /* - * printf("\nSize of mem_area: "); - * video_move_cursor(60, video_get_line()); - * printf(" %d\n", sizeof(mem_area)); - */ - - // Page Dir Info. - /* - * printf("Page Dir Entry n.0 is: "); - * video_move_cursor(60, video_get_line()); - * printf(" %d\n", get_pagedir_entry(0)); - */ - - // Page Table Info. - /* - * printf("Page Table Entry n.4 in Page dir 0 is: "); - * video_move_cursor(60, video_get_line()); - * printf(" %d\n", get_pagetable_entry(0,4)); - */ - - printf("\n:==========: :===========: :==========:\n\n"); - } else { - printf("%s. For more info about this tool, please do 'uname --help'\n", - utsname.sysname); - } -} +/// MentOS, The Mentoring Operating system project +/// @file uname.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" +#include "video.h" +#include "string.h" +#include "utsname.h" +#include "version.h" +#include "cmd_cpuid.h" + +void cmd_uname(int argc, char **argv) +{ + utsname_t utsname; + uname(&utsname); + if (argc != 2) { + printf("%s\n", utsname.sysname); + + return; + } + + if (!(strcmp(argv[1], "-a")) || !(strcmp(argv[1], "--all"))) { + printf("%s %s #1 CEST 2013 %s\n", utsname.sysname, utsname.version, + sinfo.cpu_vendor); + } else if (!(strcmp(argv[1], "-r")) || !(strcmp(argv[1], "--rev"))) { + printf("%s\n", utsname.version); + } else if (!(strcmp(argv[1], "-h")) || !(strcmp(argv[1], "--help"))) { + printf( + "Uname function allow you to see the kernel and system information.\n"); + printf("Function avaibles:\n"); + printf("1) -a - Kernel version and processor type\n" + "2) -r - Only the kernel version\n" + "3) -i - All info of system and kernel\n"); + } else if (!(strcmp(argv[1], "-i")) || !(strcmp(argv[1], "--info"))) { + printf("\n:==========: :System info: :==========:\n\n"); + printf("Version: %s\n", OS_VERSION); + printf("Major: %d\n", OS_MAJOR_VERSION); + printf("Minor: %d\n", OS_MINOR_VERSION); + printf("Micro: %d\n", OS_MICRO_VERSION); + + // CPU Info. + printf("\nCPU:"); + video_set_color(BRIGHT_RED); + video_move_cursor(61, video_get_line()); + printf(sinfo.cpu_vendor); + video_set_color(WHITE); + printf("\n"); + + // Memory RAM Info. + /* + * printf("Memory RAM: "); + * video_move_cursor(60, video_get_line()); + * printf(" %d Kb\n", get_memsize()/1024); + * + * // Memory free RAM Info + * printf(LNG_FREERAM); + * video_move_cursor(60, video_get_line()); + * printf(" %d Kb\n", get_numpages()); + * + * printf("\n"); + * // Bitmap Info + * printf("Number bitmap's elements: "); + * video_move_cursor(60, video_get_line()); + * printf(" %d", get_bmpelements()); + * video_move_cursor(60, video_get_line()); + */ + + // Mem_area Info. + /* + * printf("\nSize of mem_area: "); + * video_move_cursor(60, video_get_line()); + * printf(" %d\n", sizeof(mem_area)); + */ + + // Page Dir Info. + /* + * printf("Page Dir Entry n.0 is: "); + * video_move_cursor(60, video_get_line()); + * printf(" %d\n", get_pagedir_entry(0)); + */ + + // Page Table Info. + /* + * printf("Page Table Entry n.4 in Page dir 0 is: "); + * video_move_cursor(60, video_get_line()); + * printf(" %d\n", get_pagetable_entry(0,4)); + */ + + printf("\n:==========: :===========: :==========:\n\n"); + } else { + printf("%s. For more info about this tool, please do 'uname --help'\n", + utsname.sysname); + } +} diff --git a/mentos/src/ui/command/cmd_whoami.c b/mentos/src/ui/command/cmd_whoami.c index 3be652f..f9ef50a 100644 --- a/mentos/src/ui/command/cmd_whoami.c +++ b/mentos/src/ui/command/cmd_whoami.c @@ -1,15 +1,15 @@ -/// MentOS, The Mentoring Operating system project -/// @file cmd_whoami.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "commands.h" -#include "stdio.h" - -void cmd_whoami(int argc, char **argv) -{ - (void) argc; - (void) argv; - printf("%s\n", current_user.username); -} +/// MentOS, The Mentoring Operating system project +/// @file cmd_whoami.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "commands.h" +#include "stdio.h" + +void cmd_whoami(int argc, char **argv) +{ + (void) argc; + (void) argv; + printf("%s\n", current_user.username); +} diff --git a/mentos/src/ui/init/init.c b/mentos/src/ui/init/init.c index d215ec0..b0ac35f 100644 --- a/mentos/src/ui/init/init.c +++ b/mentos/src/ui/init/init.c @@ -1,40 +1,40 @@ -/// MentOS, The Mentoring Operating system project -/// @file init.c -/// @brief -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "init.h" -#include "wait.h" -#include "shell.h" -#include "errno.h" -#include "stdio.h" -#include "stdlib.h" -#include "unistd.h" -#include - -int main_init() -{ - pid_t cpid = vfork(); - - if (cpid == 0) - { - char *_argv[] = {"shell", "hello", (char *) NULL}; - char *_envp[] = {"/", (char *) NULL}; - - execve((const char *) shell, _argv, _envp); - - printf("This is bad, I should not be here! EXEC NOT WORKING\n"); - - return 1; - } - - int status; - while (true) - { - if ((cpid = wait(&status)) > 0) - dbg_print("Init has removed zombie children %d.\n", cpid); - } - - return 0; -} +/// MentOS, The Mentoring Operating system project +/// @file init.c +/// @brief +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "init.h" +#include "wait.h" +#include "shell.h" +#include "errno.h" +#include "stdio.h" +#include "stdlib.h" +#include "unistd.h" +#include "debug.h" + +int main_init() +{ + pid_t cpid = vfork(); + + if (cpid == 0) + { + char *_argv[] = {"shell", "hello", (char *) NULL}; + char *_envp[] = {"/", (char *) NULL}; + + execve((const char *) shell, _argv, _envp); + + printf("This is bad, I should not be here! EXEC NOT WORKING\n"); + + return 1; + } + + int status; + while (true) + { + if ((cpid = wait(&status)) > 0) + dbg_print("Init has removed zombie children %d.\n", cpid); + } + + return 0; +} diff --git a/mentos/src/ui/shell/shell.c b/mentos/src/ui/shell/shell.c index 7a0d4c1..5ff39a8 100644 --- a/mentos/src/ui/shell/shell.c +++ b/mentos/src/ui/shell/shell.c @@ -1,479 +1,480 @@ -/// MentOS, The Mentoring Operating system project -/// @file shell.c -/// @brief Implement shell functions. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "wait.h" -#include "video.h" -#include "types.h" -#include "stdio.h" -#include "debug.h" -#include "panic.h" -#include "stdlib.h" -#include "unistd.h" -#include "string.h" -#include "version.h" -#include "process.h" -#include "keyboard.h" -#include "commands.h" -#include "shell_login.h" - -#define HISTORY_MAX 10 - -/// The current user. -userenv_t current_user; - -/// The input command. -static char cmd[CMD_LEN]; - -/// The index of the cursor. -static uint32_t cmd_cursor_index; - -/// History of commands. -char history[HISTORY_MAX][CMD_LEN]; - -/// -static int history_write_index = 0; - -/// -static int history_read_index = 0; - -static bool_t history_full = false; - -#define MAX_NUM_COM 50 ///< Maximum number of saved commands. -struct { - /// The name of the command. - char cmdname[CMD_LEN]; - /// The function pointer to the command. - CommandFunction function; - /// The description of the command. - char cmddesc[DESC_LEN]; -} _shell_commands[] = { - { "logo", cmd_logo, "Show an ascii art logo" }, - { "clear", cmd_clear, "Clear the screen" }, - { "echo", cmd_echo, "Print some lines of text" }, - { "poweroff", cmd_poweroff, "Turn off the machine" }, - { "uname", cmd_uname, - "Print kernel version, try uname --help for more info" }, - { "credits", cmd_credits, "Show " OS_NAME " credits" }, - { "sleep", cmd_sleep, "Pause the OS for a particular number of seconds" }, - { "cpuid", cmd_cpuid, "Show cpu identification informations" }, - { "help", cmd_help, "See the 'help' list to learn commands now available" }, - { "ls", cmd_ls, "Tool for listing dir - not complete-" }, - { "cd", cmd_cd, "Change dir - not complete-" }, - { "mkdir", cmd_mkdir, "Creates a new directory." }, - { "rm", cmd_rm, "Removes a file." }, - { "rmdir", cmd_rmdir, "Removes a directory." }, - { "whoami", cmd_whoami, "Show the current user name" }, - { "pwd", cmd_pwd, "Print current working directory" }, - { "more", cmd_more, "Read content of a file" }, - { "touch", cmd_touch, "Create a new file" }, - { "newfile", cmd_newfile, "Create a new file" }, - { "ps", cmd_ps, "Show task list" }, - { "date", cmd_date, "Show date and time" }, - { "clear", cmd_clear, "Clears the screen" }, - { "showpid", cmd_showpid, "Shows the PID of the shell" }, - { "history", cmd_show_history, "Shows the shell history" }, - { "nice", cmd_nice, "Change the nice value of the process" } -}; - -/// @brief Completely delete the current command. -static void shell_command_clear() -{ - for (size_t it = 0; it < cmd_cursor_index; ++it) { - putchar('\b'); - } - cmd_cursor_index = 0; -} - -/// -/// @brief -/// @param _cmd -static void shell_command_set(char *_cmd) -{ - // Outputs the command. - printf(_cmd); - // Moves the cursore. - cmd_cursor_index += strlen(_cmd); - // Copies the command. - strcpy(cmd, _cmd); -} - -static void shell_command_erase_char() -{ - if (cmd_cursor_index > 0) { - cmd[--cmd_cursor_index] = '\0'; - } -} - -static bool_t shell_command_append_char(char c) -{ - if ((cmd_cursor_index + 1) < CMD_LEN) { - cmd[cmd_cursor_index++] = c; - cmd[cmd_cursor_index] = '\0'; - - return true; - } - - return false; -} - -static inline void history_debug_print() -{ -#if 1 - // Prints the history stack with current indexes values. - dbg_print("------------------------------\n"); - for (size_t index = 0; index < HISTORY_MAX; ++index) { - dbg_print("[%d]%c%c: %s\n", index, - (index == history_write_index) ? 'w' : ' ', - (index == history_read_index) ? 'r' : ' ', history[index]); - } -#endif -} - -/// @brief Push the command inside the history. -static void history_push(char *_cmd) -{ - // Reset the read index. - history_read_index = history_write_index; - // Check if it is a duplicated entry. - if (history_write_index > 0) { - if (strcmp(history[history_write_index - 1], _cmd) == 0) { - return; - } - } - // Insert the node. - strcpy(history[history_write_index], _cmd); - if (++history_write_index >= HISTORY_MAX) { - history_write_index = 0; - history_full = true; - } - // Reset the read index. - history_read_index = history_write_index; - history_debug_print(); -} - -/// @brief Give the key allows to navigate through the history. -static char *history_fetch(const int key) -{ - if ((history_write_index == 0) && (history_full == false)) { - return NULL; - } - // If the history is empty do nothing. - char *_cmd = NULL; - int next_index = history_read_index; - // Update the position inside the history. - if (key == KEY_DOWN) { - ++next_index; - } else if (key == KEY_UP) { - --next_index; - } - // Check the next index. - if (history_full) { - if (next_index < 0) { - next_index = HISTORY_MAX - 1; - } else if (next_index >= HISTORY_MAX) { - next_index = 0; - } - // Do no read where ne will have to write next. - if (next_index == history_write_index) { - next_index = history_read_index; - } - } else { - if (next_index < 0) { - next_index = 0; - } else if (next_index >= history_write_index) { - next_index = history_read_index; - } - } - history_read_index = next_index; - _cmd = history[history_read_index]; - history_debug_print(); - // Return the command. - return _cmd; -} - -void cmd_show_history(int argc, char **argv) -{ - (void)argc; - (void)argv; - // Prints the history stack with current indexes values - printf("------------------------------\n"); - printf(" Debug history \n"); - printf("------------------------------\n"); - for (size_t index = 0; index < HISTORY_MAX; ++index) { - printf("[%d]%c%c: %s\n", index, - (index == history_write_index) ? 'w' : ' ', - (index == history_read_index) ? 'r' : ' ', history[index]); - } -} - -/// @brief Prints the prompt. -static void shell_print_prompt() -{ - video_set_color(BRIGHT_BLUE); - printf(current_user.username); - video_set_color(WHITE); - char cwd[PATH_MAX]; - getcwd(cwd, PATH_MAX); - printf("~:%s# ", cwd); - // Update the lower-bounds for the video. - lower_bound_x = video_get_column(); - lower_bound_y = video_get_line(); -} - -/// @brief Gets the inserted command. -static void shell_get_command() -{ - // Re-Initialize the cursor index. - cmd_cursor_index = 0; - //Initializing the current command line buffer - memset(cmd, '\0', CMD_LEN); - do { - int c = getchar(); - // Return Key - if (c == '\n') { - if (strlen(cmd) == 0) { - printf("\n"); - } - // Break the while loop. - break; - } else if (c == '\033') { - getchar(); // Skip '[' - c = getchar(); // Get the char. - char *_cmd = NULL; - if ((c == KEY_UP) || (c == KEY_DOWN)) { - _cmd = history_fetch(c); - } - if (_cmd != NULL) { - // Clear the current command. - shell_command_clear(); - // Sets the command. - shell_command_set(_cmd); - } - } else if (keyboard_is_ctrl_pressed() && (c == 'c')) { - // However, the ISR of the keyboard has already put the char. - // Thus, delete it by using backspace. - putchar('\b'); - // Re-set the index to the beginning. - cmd_cursor_index = 0; - // Go to the new line. - printf("\n\n"); - // Sets the command. - shell_command_set("\0"); - - // Break the while loop. - break; - } else if (c == '\b') { - shell_command_erase_char(); - } else { - if (!shell_command_append_char(c)) { - putchar('\b'); - } - } - } while (cmd_cursor_index < CMD_LEN); - - // Cleans all blanks at the beginning of the command. - trim(cmd); -} - -/// @brief Gets the inserted command. -static CommandFunction shell_find_command(char *command) -{ - if (command == NULL) { - return NULL; - } - // Matching and executing the command. - for (size_t it = 0; it < MAX_NUM_COM; ++it) { - // Skip commands with undefined functions. - if (_shell_commands[it].function == NULL) { - continue; - } - if (strcmp(command, _shell_commands[it].cmdname) != 0) { - continue; - } - - return _shell_commands[it].function; - } - - return NULL; -} - -static inline bool_t shell_is_separator(char c) -{ - return ((c == '\0') || (c == ' ') || (c == '\t') || (c == '\n') || - (c == '\r')); -} - -static int shell_count_words(const char *sentence) -{ - int result = 0; - bool_t inword = false; - const char *it = sentence; - do - if (shell_is_separator(*it)) { - if (inword) { - inword = false; - result++; - } - } else { - inword = true; - } - while (*it++); - - return result; -} - -/// @brief Gets the options from the command. -/// @param command The executed command. -static void shell_get_options(char *command, int *argc, char ***argv) -{ - // Get the number of arguments, return if zero. - if (((*argc) = shell_count_words(command)) == 0) { - return; - } - (*argv) = (char **)malloc(sizeof(char *) * ((*argc) + 1)); - bool_t inword = false; - const char *cit = command; - size_t argcIt = 0, argIt = 0; - do { - if (shell_is_separator(*cit)) { - if (inword) { - inword = false; - (*argv)[argcIt++][argIt] = '\0'; - argIt = 0; - } - } else { - // Allocate string for argument. - if (!inword) { - (*argv)[argcIt] = (char *)malloc(sizeof(char) * CMD_LEN); - } - inword = true; - (*argv)[argcIt][argIt++] = (*cit); - } - } while (*cit++); - (*argv)[argcIt] = NULL; -} - -void cmd_help(int argc, char **argv) -{ - if (argc > 2) { - printf("Too many arguments.\n\n"); - return; - } - if (argc == 1) { - printf("Available commands:\n"); - for (int i = 0, j = 0; i < MAX_NUM_COM; ++i) { - if (_shell_commands[i].function != NULL) { - printf("%-10s ", _shell_commands[i].cmdname); - if ((j++) == 3) { - printf("\n"); - j = 0; - } - } - } - printf("\n\n"); - return; - } - if (argc == 2) { - for (int i = 0; i < MAX_NUM_COM; ++i) { - if (strcmp(_shell_commands[i].cmdname, argv[1]) == 0) { - printf("%s\n\n", _shell_commands[i].cmddesc); - - return; - } - } - printf("Cannot find command: '%s'\n\n", argv[1]); - } - printf("\n"); -} - -int shell(int argc, char **argv, char **envp) -{ - dbg_print("I'm shell, I am the knight here...\n"); - - video_set_color(BRIGHT_BLUE); - printf("\t\t.: Welcome to MentOS :.\n\n"); - video_set_color(WHITE); - - dbg_print("I'm shell, I'll let my pawn, login, handle any intruder...\n"); - shell_login(); - - chdir("/"); - current_user.uid = 1; - current_user.gid = 0; - - for (int i = 0; i < 50; ++i) { - putchar('\n'); - } - cmd_logo(1, NULL); - printf("\n\n\n\n"); - - dbg_print("I'm shell, let us begin...\n"); - - while (true) { - // First print the prompt. - shell_print_prompt(); - // Get the input command. - shell_get_command(); - // Check if the command is empty. - if (strlen(cmd) <= 0) { - continue; - } - // Retrieve the options from the command. - /// The current number of arguments. - int _argc = 1; - /// The vector of arguments. - char **_argv; - shell_get_options(cmd, &_argc, &_argv); - // Check if the command is empty. - if (_argc == 0) { - continue; - } - // Add the command to the history. - history_push(cmd); - // Find the command. - CommandFunction commandFunction = shell_find_command(_argv[0]); - if (commandFunction == NULL) { - printf("\nUnknown command: %s\n", _argv[0]); - } else if (strcmp(_argv[0], "cd") == 0) { - commandFunction(_argc, _argv); - } else { - int status; - pid_t cpid = vfork(); - if (cpid == 0) { - char *_envp[] = { (char *)NULL }; - execve((const char *)commandFunction, _argv, _envp); - kernel_panic("This is bad, I should not be here!\n"); - } - waitpid(cpid, &status, 0); - } - - // Free up the memory reserved for the arguments. - for (int it = 0; it < _argc; ++it) { - // Check if the argument is not empty. - if (_argv[it] != NULL) { - // Free up its memory. - free(_argv[it]); - } - } - free(_argv); - } - - return 0; -} - -void move_cursor_left(void) -{ - if (cmd_cursor_index > lower_bound_x) { - --cmd_cursor_index; - } -} - -void move_cursor_right(void) -{ - if (cmd_cursor_index < shell_lower_bound_x) { - ++cmd_cursor_index; - } -} +/// MentOS, The Mentoring Operating system project +/// @file shell.c +/// @brief Implement shell functions. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "wait.h" +#include "video.h" +#include "types.h" +#include "stdio.h" +#include "debug.h" +#include "panic.h" +#include "stdlib.h" +#include "unistd.h" +#include "string.h" +#include "version.h" +#include "process.h" +#include "keyboard.h" +#include "commands.h" +#include "shell_login.h" + +#define HISTORY_MAX 10 + +/// The current user. +userenv_t current_user; + +/// The input command. +static char cmd[CMD_LEN]; + +/// The index of the cursor. +static uint32_t cmd_cursor_index; + +/// History of commands. +char history[HISTORY_MAX][CMD_LEN]; + +/// +static int history_write_index = 0; + +/// +static int history_read_index = 0; + +static bool_t history_full = false; + +#define MAX_NUM_COM 50 ///< Maximum number of saved commands. +struct { + /// The name of the command. + char cmdname[CMD_LEN]; + /// The function pointer to the command. + CommandFunction function; + /// The description of the command. + char cmddesc[DESC_LEN]; +} _shell_commands[] = { + { "logo", cmd_logo, "Show an ascii art logo" }, + { "clear", cmd_clear, "Clear the screen" }, + { "echo", cmd_echo, "Print some lines of text" }, + { "poweroff", cmd_poweroff, "Turn off the machine" }, + { "uname", cmd_uname, + "Print kernel version, try uname --help for more info" }, + { "credits", cmd_credits, "Show " OS_NAME " credits" }, + { "sleep", cmd_sleep, "Pause the OS for a particular number of seconds" }, + { "cpuid", cmd_cpuid, "Show cpu identification informations" }, + { "help", cmd_help, "See the 'help' list to learn commands now available" }, + { "ls", cmd_ls, "Tool for listing dir - not complete-" }, + { "cd", cmd_cd, "Change dir - not complete-" }, + { "mkdir", cmd_mkdir, "Creates a new directory." }, + { "rm", cmd_rm, "Removes a file." }, + { "rmdir", cmd_rmdir, "Removes a directory." }, + { "whoami", cmd_whoami, "Show the current user name" }, + { "pwd", cmd_pwd, "Print current working directory" }, + { "more", cmd_more, "Read content of a file" }, + { "touch", cmd_touch, "Create a new file" }, + { "newfile", cmd_newfile, "Create a new file" }, + { "ps", cmd_ps, "Show task list" }, + { "date", cmd_date, "Show date and time" }, + { "clear", cmd_clear, "Clears the screen" }, + { "showpid", cmd_showpid, "Shows the PID of the shell" }, + { "history", cmd_show_history, "Shows the shell history" }, + { "nice", cmd_nice, "Change the nice value of the process" }, + { "deadlock", cmd_deadlock, "Test deadlock behavior" } +}; + +/// @brief Completely delete the current command. +static void shell_command_clear() +{ + for (size_t it = 0; it < cmd_cursor_index; ++it) { + putchar('\b'); + } + cmd_cursor_index = 0; +} + +/// +/// @brief +/// @param _cmd +static void shell_command_set(char *_cmd) +{ + // Outputs the command. + printf(_cmd); + // Moves the cursore. + cmd_cursor_index += strlen(_cmd); + // Copies the command. + strcpy(cmd, _cmd); +} + +static void shell_command_erase_char() +{ + if (cmd_cursor_index > 0) { + cmd[--cmd_cursor_index] = '\0'; + } +} + +static bool_t shell_command_append_char(char c) +{ + if ((cmd_cursor_index + 1) < CMD_LEN) { + cmd[cmd_cursor_index++] = c; + cmd[cmd_cursor_index] = '\0'; + + return true; + } + + return false; +} + +static inline void history_debug_print() +{ +#if 1 + // Prints the history stack with current indexes values. + dbg_print("------------------------------\n"); + for (size_t index = 0; index < HISTORY_MAX; ++index) { + dbg_print("[%d]%c%c: %s\n", index, + (index == history_write_index) ? 'w' : ' ', + (index == history_read_index) ? 'r' : ' ', history[index]); + } +#endif +} + +/// @brief Push the command inside the history. +static void history_push(char *_cmd) +{ + // Reset the read index. + history_read_index = history_write_index; + // Check if it is a duplicated entry. + if (history_write_index > 0) { + if (strcmp(history[history_write_index - 1], _cmd) == 0) { + return; + } + } + // Insert the node. + strcpy(history[history_write_index], _cmd); + if (++history_write_index >= HISTORY_MAX) { + history_write_index = 0; + history_full = true; + } + // Reset the read index. + history_read_index = history_write_index; + history_debug_print(); +} + +/// @brief Give the key allows to navigate through the history. +static char *history_fetch(const int key) +{ + if ((history_write_index == 0) && (history_full == false)) { + return NULL; + } + // If the history is empty do nothing. + char *_cmd = NULL; + int next_index = history_read_index; + // Update the position inside the history. + if (key == KEY_DOWN) { + ++next_index; + } else if (key == KEY_UP) { + --next_index; + } + // Check the next index. + if (history_full) { + if (next_index < 0) { + next_index = HISTORY_MAX - 1; + } else if (next_index >= HISTORY_MAX) { + next_index = 0; + } + // Do no read where ne will have to write next. + if (next_index == history_write_index) { + next_index = history_read_index; + } + } else { + if (next_index < 0) { + next_index = 0; + } else if (next_index >= history_write_index) { + next_index = history_read_index; + } + } + history_read_index = next_index; + _cmd = history[history_read_index]; + history_debug_print(); + // Return the command. + return _cmd; +} + +void cmd_show_history(int argc, char **argv) +{ + (void)argc; + (void)argv; + // Prints the history stack with current indexes values + printf("------------------------------\n"); + printf(" Debug history \n"); + printf("------------------------------\n"); + for (size_t index = 0; index < HISTORY_MAX; ++index) { + printf("[%d]%c%c: %s\n", index, + (index == history_write_index) ? 'w' : ' ', + (index == history_read_index) ? 'r' : ' ', history[index]); + } +} + +/// @brief Prints the prompt. +static void shell_print_prompt() +{ + video_set_color(BRIGHT_BLUE); + printf(current_user.username); + video_set_color(WHITE); + char cwd[PATH_MAX]; + getcwd(cwd, PATH_MAX); + printf("~:%s# ", cwd); + // Update the lower-bounds for the video. + lower_bound_x = video_get_column(); + lower_bound_y = video_get_line(); +} + +/// @brief Gets the inserted command. +static void shell_get_command() +{ + // Re-Initialize the cursor index. + cmd_cursor_index = 0; + //Initializing the current command line buffer + memset(cmd, '\0', CMD_LEN); + do { + int c = getchar(); + // Return Key + if (c == '\n') { + if (strlen(cmd) == 0) { + printf("\n"); + } + // Break the while loop. + break; + } else if (c == '\033') { + getchar(); // Skip '[' + c = getchar(); // Get the char. + char *_cmd = NULL; + if ((c == KEY_UP) || (c == KEY_DOWN)) { + _cmd = history_fetch(c); + } + if (_cmd != NULL) { + // Clear the current command. + shell_command_clear(); + // Sets the command. + shell_command_set(_cmd); + } + } else if (keyboard_is_ctrl_pressed() && (c == 'c')) { + // However, the ISR of the keyboard has already put the char. + // Thus, delete it by using backspace. + putchar('\b'); + // Re-set the index to the beginning. + cmd_cursor_index = 0; + // Go to the new line. + printf("\n\n"); + // Sets the command. + shell_command_set("\0"); + + // Break the while loop. + break; + } else if (c == '\b') { + shell_command_erase_char(); + } else { + if (!shell_command_append_char(c)) { + putchar('\b'); + } + } + } while (cmd_cursor_index < CMD_LEN); + + // Cleans all blanks at the beginning of the command. + trim(cmd); +} + +/// @brief Gets the inserted command. +static CommandFunction shell_find_command(char *command) +{ + if (command == NULL) { + return NULL; + } + // Matching and executing the command. + for (size_t it = 0; it < MAX_NUM_COM; ++it) { + // Skip commands with undefined functions. + if (_shell_commands[it].function == NULL) { + continue; + } + if (strcmp(command, _shell_commands[it].cmdname) != 0) { + continue; + } + + return _shell_commands[it].function; + } + + return NULL; +} + +static inline bool_t shell_is_separator(char c) +{ + return ((c == '\0') || (c == ' ') || (c == '\t') || (c == '\n') || + (c == '\r')); +} + +static int shell_count_words(const char *sentence) +{ + int result = 0; + bool_t inword = false; + const char *it = sentence; + do + if (shell_is_separator(*it)) { + if (inword) { + inword = false; + result++; + } + } else { + inword = true; + } + while (*it++); + + return result; +} + +/// @brief Gets the options from the command. +/// @param command The executed command. +static void shell_get_options(char *command, int *argc, char ***argv) +{ + // Get the number of arguments, return if zero. + if (((*argc) = shell_count_words(command)) == 0) { + return; + } + (*argv) = (char **)malloc(sizeof(char *) * ((*argc) + 1)); + bool_t inword = false; + const char *cit = command; + size_t argcIt = 0, argIt = 0; + do { + if (shell_is_separator(*cit)) { + if (inword) { + inword = false; + (*argv)[argcIt++][argIt] = '\0'; + argIt = 0; + } + } else { + // Allocate string for argument. + if (!inword) { + (*argv)[argcIt] = (char *)malloc(sizeof(char) * CMD_LEN); + } + inword = true; + (*argv)[argcIt][argIt++] = (*cit); + } + } while (*cit++); + (*argv)[argcIt] = NULL; +} + +void cmd_help(int argc, char **argv) +{ + if (argc > 2) { + printf("Too many arguments.\n\n"); + return; + } + if (argc == 1) { + printf("Available commands:\n"); + for (int i = 0, j = 0; i < MAX_NUM_COM; ++i) { + if (_shell_commands[i].function != NULL) { + printf("%-10s ", _shell_commands[i].cmdname); + if ((j++) == 3) { + printf("\n"); + j = 0; + } + } + } + printf("\n\n"); + return; + } + if (argc == 2) { + for (int i = 0; i < MAX_NUM_COM; ++i) { + if (strcmp(_shell_commands[i].cmdname, argv[1]) == 0) { + printf("%s\n\n", _shell_commands[i].cmddesc); + + return; + } + } + printf("Cannot find command: '%s'\n\n", argv[1]); + } + printf("\n"); +} + +int shell(int argc, char **argv, char **envp) +{ + dbg_print("I'm shell, I am the knight here...\n"); + + video_set_color(BRIGHT_BLUE); + printf("\t\t.: Welcome to MentOS :.\n\n"); + video_set_color(WHITE); + + dbg_print("I'm shell, I'll let my pawn, login, handle any intruder...\n"); + shell_login(); + + chdir("/"); + current_user.uid = 1; + current_user.gid = 0; + + for (int i = 0; i < 50; ++i) { + putchar('\n'); + } + cmd_logo(1, NULL); + printf("\n\n\n\n"); + + dbg_print("I'm shell, let us begin...\n"); + + while (true) { + // First print the prompt. + shell_print_prompt(); + // Get the input command. + shell_get_command(); + // Check if the command is empty. + if (strlen(cmd) <= 0) { + continue; + } + // Retrieve the options from the command. + /// The current number of arguments. + int _argc = 1; + /// The vector of arguments. + char **_argv; + shell_get_options(cmd, &_argc, &_argv); + // Check if the command is empty. + if (_argc == 0) { + continue; + } + // Add the command to the history. + history_push(cmd); + // Find the command. + CommandFunction commandFunction = shell_find_command(_argv[0]); + if (commandFunction == NULL) { + printf("\nUnknown command: %s\n", _argv[0]); + } else if (strcmp(_argv[0], "cd") == 0) { + commandFunction(_argc, _argv); + } else { + int status; + pid_t cpid = vfork(); + if (cpid == 0) { + char *_envp[] = { (char *)NULL }; + execve((const char *)commandFunction, _argv, _envp); + kernel_panic("This is bad, I should not be here!\n"); + } + waitpid(cpid, &status, 0); + } + + // Free up the memory reserved for the arguments. + for (int it = 0; it < _argc; ++it) { + // Check if the argument is not empty. + if (_argv[it] != NULL) { + // Free up its memory. + free(_argv[it]); + } + } + free(_argv); + } + + return 0; +} + +void move_cursor_left(void) +{ + if (cmd_cursor_index > lower_bound_x) { + --cmd_cursor_index; + } +} + +void move_cursor_right(void) +{ + if (cmd_cursor_index < shell_lower_bound_x) { + ++cmd_cursor_index; + } +} diff --git a/mentos/src/ui/shell/shell_login.c b/mentos/src/ui/shell/shell_login.c index 7c1f124..1eea3ad 100644 --- a/mentos/src/ui/shell/shell_login.c +++ b/mentos/src/ui/shell/shell_login.c @@ -1,152 +1,152 @@ -/// MentOS, The Mentoring Operating system project -/// @file shell_login.c -/// @brief Functions used to manage login. -/// @copyright (c) 2019 This file is distributed under the MIT License. -/// See LICENSE.md for details. - -#include "shell_login.h" -#include "vfs.h" -#include "stdio.h" -#include "fcntl.h" -#include "debug.h" -#include "video.h" -#include "string.h" -#include "keyboard.h" - -/// @brief Contains the credentials retrieved from the file. -typedef struct credentials_t { - /// The username. - char username[CREDENTIALS_LENGTH]; - /// The password. - char password[CREDENTIALS_LENGTH]; -} credentials_t; - -/// @brief Initialize the given credentials. -void init_credentials(credentials_t *credentials) -{ - if (credentials != NULL) { - memset(credentials->username, '\0', CREDENTIALS_LENGTH); - memset(credentials->password, '\0', CREDENTIALS_LENGTH); - } -} - -/// @brief -/// @param fd The FD of the file which contains the credentials. -/// @param credentials The structure which has to be filled with the -/// credentials. -/// @return If the credentials has been retrieved. -bool_t user_get(int fd, struct credentials_t *credentials) -{ - // Create a support array of char. - static char support[CREDENTIALS_LENGTH]; - // Cariable which will contain the number of bytes actually transferred. - ssize_t bytes_read = 0; - - // Get the USERNAME. - memset(support, '\0', CREDENTIALS_LENGTH); - for (int it = 0; it < CREDENTIALS_LENGTH; ++it) { - bytes_read = read(fd, &support[it], 1); - if (support[it] == ':') { - support[it] = '\0'; - - break; - } - } - replace_char(support, '\r', 0); - if ((bytes_read == 0) || (strlen(support) == 0)) { - return false; - } - strcpy(credentials->username, support); - - // Get the PASSWORD. - memset(support, '\0', CREDENTIALS_LENGTH); - for (int it = 0; it < CREDENTIALS_LENGTH; ++it) { - bytes_read = read(fd, &support[it], 1); - if ((support[it] == '\n') || (support[it] == EOF)) { - support[it] = '\0'; - - break; - } - } - - replace_char(support, '\r', 0); - if ((bytes_read == 0) || (strlen(support) == 0)) { - return false; - } - strcpy(credentials->password, support); - - return true; -} - -/// @brief Checks if the given credentials are correct. -bool_t check_credentials(credentials_t *credentials) -{ - // Initialize a variable for the return value. - bool_t status = false; - - /* Initialize the structure which will contain the username and the - * password. - */ - credentials_t existing; - init_credentials(&existing); - - // Open the file which contains the credentials. - // TODO: BUG: The first time the open is called, it fails. - int fd = open("/passwd", O_RDONLY, 0); - - // Check the file descriptor. - if (fd >= 0) { - // Get the next row inside the file containing the credentials. - while (user_get(fd, &existing) == true) { - if (!strcmp(credentials->username, existing.username) && - !strcmp(credentials->password, existing.password)) { - status = true; - - break; - } - } - // Close the file descriptor. - close(fd); - } else { - dbg_print("Can't open passwd file\n"); - } - return status; -} - -void shell_login() -{ - do { - // Initialize the credentials. - credentials_t credentials; - init_credentials(&credentials); - - // Ask the username. - printf("Username :"); - // Update the lower-bounds for the video. - lower_bound_x = video_get_column(); - lower_bound_y = video_get_line(); - // Get the username. - scanf("%50s", credentials.username); - - // Ask the password. - printf("Password :"); - // Update the lower-bounds for the video. - lower_bound_x = video_get_column(); - lower_bound_y = video_get_line(); - // Set the shadow option. - keyboard_set_shadow(true); - keyboard_set_shadow_character('*'); - // Get the password. - scanf("%50s", credentials.password); - // Disable the shadow option. - keyboard_set_shadow(false); - - // Check if the data are correct. - if (check_credentials(&credentials)) { - strcpy(current_user.username, credentials.username); - - break; - } - printf("Sorry, try again.\n"); - } while (true); -} +/// MentOS, The Mentoring Operating system project +/// @file shell_login.c +/// @brief Functions used to manage login. +/// @copyright (c) 2019 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "shell_login.h" +#include "vfs.h" +#include "stdio.h" +#include "fcntl.h" +#include "debug.h" +#include "video.h" +#include "string.h" +#include "keyboard.h" + +/// @brief Contains the credentials retrieved from the file. +typedef struct credentials_t { + /// The username. + char username[CREDENTIALS_LENGTH]; + /// The password. + char password[CREDENTIALS_LENGTH]; +} credentials_t; + +/// @brief Initialize the given credentials. +void init_credentials(credentials_t *credentials) +{ + if (credentials != NULL) { + memset(credentials->username, '\0', CREDENTIALS_LENGTH); + memset(credentials->password, '\0', CREDENTIALS_LENGTH); + } +} + +/// @brief +/// @param fd The FD of the file which contains the credentials. +/// @param credentials The structure which has to be filled with the +/// credentials. +/// @return If the credentials has been retrieved. +bool_t user_get(int fd, struct credentials_t *credentials) +{ + // Create a support array of char. + static char support[CREDENTIALS_LENGTH]; + // Cariable which will contain the number of bytes actually transferred. + ssize_t bytes_read = 0; + + // Get the USERNAME. + memset(support, '\0', CREDENTIALS_LENGTH); + for (int it = 0; it < CREDENTIALS_LENGTH; ++it) { + bytes_read = read(fd, &support[it], 1); + if (support[it] == ':') { + support[it] = '\0'; + + break; + } + } + replace_char(support, '\r', 0); + if ((bytes_read == 0) || (strlen(support) == 0)) { + return false; + } + strcpy(credentials->username, support); + + // Get the PASSWORD. + memset(support, '\0', CREDENTIALS_LENGTH); + for (int it = 0; it < CREDENTIALS_LENGTH; ++it) { + bytes_read = read(fd, &support[it], 1); + if ((support[it] == '\n') || (support[it] == EOF)) { + support[it] = '\0'; + + break; + } + } + + replace_char(support, '\r', 0); + if ((bytes_read == 0) || (strlen(support) == 0)) { + return false; + } + strcpy(credentials->password, support); + + return true; +} + +/// @brief Checks if the given credentials are correct. +bool_t check_credentials(credentials_t *credentials) +{ + // Initialize a variable for the return value. + bool_t status = false; + + /* Initialize the structure which will contain the username and the + * password. + */ + credentials_t existing; + init_credentials(&existing); + + // Open the file which contains the credentials. + // TODO: BUG: The first time the open is called, it fails. + int fd = open("/passwd", O_RDONLY, 0); + + // Check the file descriptor. + if (fd >= 0) { + // Get the next row inside the file containing the credentials. + while (user_get(fd, &existing) == true) { + if (!strcmp(credentials->username, existing.username) && + !strcmp(credentials->password, existing.password)) { + status = true; + + break; + } + } + // Close the file descriptor. + close(fd); + } else { + dbg_print("Can't open passwd file\n"); + } + return status; +} + +void shell_login() +{ + do { + // Initialize the credentials. + credentials_t credentials; + init_credentials(&credentials); + + // Ask the username. + printf("Username :"); + // Update the lower-bounds for the video. + lower_bound_x = video_get_column(); + lower_bound_y = video_get_line(); + // Get the username. + scanf("%50s", credentials.username); + + // Ask the password. + printf("Password :"); + // Update the lower-bounds for the video. + lower_bound_x = video_get_column(); + lower_bound_y = video_get_line(); + // Set the shadow option. + keyboard_set_shadow(true); + keyboard_set_shadow_character('*'); + // Get the password. + scanf("%50s", credentials.password); + // Disable the shadow option. + keyboard_set_shadow(false); + + // Check if the data are correct. + if (check_credentials(&credentials)) { + strcpy(current_user.username, credentials.username); + + break; + } + printf("Sorry, try again.\n"); + } while (true); +}