diff --git a/clks b/clks new file mode 160000 index 0000000..703d540 --- /dev/null +++ b/clks @@ -0,0 +1 @@ +Subproject commit 703d540b1796ee7ec200e76c64787df69fcf8c94 diff --git a/clks/CMakeLists.txt b/clks/CMakeLists.txt deleted file mode 100644 index ea11b6f..0000000 --- a/clks/CMakeLists.txt +++ /dev/null @@ -1,163 +0,0 @@ -set(KERNEL_SOURCE_DIRS - "${CMAKE_SOURCE_DIR}/clks/kernel" - "${CMAKE_SOURCE_DIR}/clks/arch/${CLKS_ARCH}" - "${CMAKE_SOURCE_DIR}/clks/third_party" -) - -set(C_SOURCES) -set(CPP_SOURCES) -set(ASM_SOURCES) -foreach(_src_dir IN LISTS KERNEL_SOURCE_DIRS) - if(EXISTS "${_src_dir}") - file(GLOB_RECURSE _c_abs CONFIGURE_DEPENDS "${_src_dir}/*.c") - file(GLOB_RECURSE _cpp_abs CONFIGURE_DEPENDS "${_src_dir}/*.cpp") - file(GLOB_RECURSE _s_abs CONFIGURE_DEPENDS "${_src_dir}/*.S") - foreach(_abs IN LISTS _c_abs) - file(RELATIVE_PATH _rel "${CMAKE_SOURCE_DIR}" "${_abs}") - list(APPEND C_SOURCES "${_rel}") - endforeach() - foreach(_abs IN LISTS _cpp_abs) - file(RELATIVE_PATH _rel "${CMAKE_SOURCE_DIR}" "${_abs}") - list(APPEND CPP_SOURCES "${_rel}") - endforeach() - foreach(_abs IN LISTS _s_abs) - file(RELATIVE_PATH _rel "${CMAKE_SOURCE_DIR}" "${_abs}") - list(APPEND ASM_SOURCES "${_rel}") - endforeach() - endif() -endforeach() -list(REMOVE_DUPLICATES C_SOURCES) -list(REMOVE_DUPLICATES CPP_SOURCES) -list(REMOVE_DUPLICATES ASM_SOURCES) -list(SORT C_SOURCES) -list(SORT CPP_SOURCES) -list(SORT ASM_SOURCES) - -set(CLKS_BOOT_LIMINE_SOURCE "clks/kernel/boot/limine/limine_requests.c") -if(EXISTS "${CMAKE_SOURCE_DIR}/${CLKS_BOOT_LIMINE_SOURCE}") - list(APPEND C_SOURCES "${CLKS_BOOT_LIMINE_SOURCE}") - list(REMOVE_DUPLICATES C_SOURCES) - list(SORT C_SOURCES) -else() - cl_log_error("missing required boot source: ${CLKS_BOOT_LIMINE_SOURCE}") -endif() - -file(GLOB_RECURSE KERNEL_INC_SOURCES_ABS CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/clks/**/*.inc" -) -list(SORT KERNEL_INC_SOURCES_ABS) - -if(NOT C_SOURCES) - cl_log_error("no kernel C sources found in clks/") -endif() -if(NOT EXISTS "${LINKER_SCRIPT}") - cl_log_error("missing linker script: ${LINKER_SCRIPT}") -endif() - -function(add_kernel_c_object SRC OUTPUT_LIST_VAR) - string(REGEX REPLACE "\\.c$" ".o" OBJ_REL "${SRC}") - set(OBJ_PATH "${OBJ_ROOT}/${OBJ_REL}") - get_filename_component(OBJ_DIR "${OBJ_PATH}" DIRECTORY) - set(_deps "${CMAKE_SOURCE_DIR}/${SRC}" ${KERNEL_INC_SOURCES_ABS}) - set(_cflags ${CFLAGS_COMMON}) - - if("${SRC}" MATCHES "^clks/third_party/") - list(APPEND _cflags - -Wno-error - -Wno-unused-function - -Wno-unused-parameter - -Wno-sign-compare - -Wno-type-limits - -Wno-missing-field-initializers - ) - endif() - - add_custom_command( - OUTPUT "${OBJ_PATH}" - COMMAND ${CMAKE_COMMAND} -E make_directory "${OBJ_DIR}" - COMMAND ${CC} ${_cflags} ${ARCH_CFLAGS} -c "${CMAKE_SOURCE_DIR}/${SRC}" -o "${OBJ_PATH}" - DEPENDS ${_deps} - VERBATIM - ) - - set(${OUTPUT_LIST_VAR} ${${OUTPUT_LIST_VAR}} "${OBJ_PATH}" PARENT_SCOPE) -endfunction() - -function(add_kernel_asm_object SRC OUTPUT_LIST_VAR) - string(REGEX REPLACE "\\.S$" ".o" OBJ_REL "${SRC}") - set(OBJ_PATH "${OBJ_ROOT}/${OBJ_REL}") - get_filename_component(OBJ_DIR "${OBJ_PATH}" DIRECTORY) - set(_deps "${CMAKE_SOURCE_DIR}/${SRC}" ${KERNEL_INC_SOURCES_ABS}) - - add_custom_command( - OUTPUT "${OBJ_PATH}" - COMMAND ${CMAKE_COMMAND} -E make_directory "${OBJ_DIR}" - COMMAND ${CC} ${ASFLAGS_COMMON} ${ARCH_CFLAGS} -c "${CMAKE_SOURCE_DIR}/${SRC}" -o "${OBJ_PATH}" - DEPENDS ${_deps} - VERBATIM - ) - - set(${OUTPUT_LIST_VAR} ${${OUTPUT_LIST_VAR}} "${OBJ_PATH}" PARENT_SCOPE) -endfunction() - -function(add_kernel_cpp_object SRC OUTPUT_LIST_VAR) - string(REGEX REPLACE "\\.cpp$" ".o" OBJ_REL "${SRC}") - set(OBJ_PATH "${OBJ_ROOT}/${OBJ_REL}") - get_filename_component(OBJ_DIR "${OBJ_PATH}" DIRECTORY) - set(_deps "${CMAKE_SOURCE_DIR}/${SRC}" ${KERNEL_INC_SOURCES_ABS}) - - add_custom_command( - OUTPUT "${OBJ_PATH}" - COMMAND ${CMAKE_COMMAND} -E make_directory "${OBJ_DIR}" - COMMAND ${KERNEL_CXX} ${CXXFLAGS_COMMON} ${ARCH_CFLAGS} -c "${CMAKE_SOURCE_DIR}/${SRC}" -o "${OBJ_PATH}" - DEPENDS ${_deps} - VERBATIM - ) - - set(${OUTPUT_LIST_VAR} ${${OUTPUT_LIST_VAR}} "${OBJ_PATH}" PARENT_SCOPE) -endfunction() - -set(KERNEL_OBJECTS) -foreach(SRC IN LISTS C_SOURCES) - add_kernel_c_object("${SRC}" KERNEL_OBJECTS) -endforeach() -foreach(SRC IN LISTS CPP_SOURCES) - add_kernel_cpp_object("${SRC}" KERNEL_OBJECTS) -endforeach() -foreach(SRC IN LISTS ASM_SOURCES) - add_kernel_asm_object("${SRC}" KERNEL_OBJECTS) -endforeach() - -add_custom_command( - OUTPUT "${KERNEL_RUST_LIB}" - COMMAND ${CMAKE_COMMAND} -E make_directory "${BUILD_ROOT}" - COMMAND ${RUSTC} --crate-type staticlib -C panic=abort -O "${CMAKE_SOURCE_DIR}/clks/rust/src/lib.rs" -o "${KERNEL_RUST_LIB}" - DEPENDS "${CMAKE_SOURCE_DIR}/clks/rust/src/lib.rs" - VERBATIM -) - -add_custom_command( - OUTPUT "${KERNEL_ELF}" - COMMAND ${CMAKE_COMMAND} -E make_directory "${BUILD_ROOT}" - COMMAND ${LD} ${LDFLAGS_COMMON} -T "${LINKER_SCRIPT}" -o "${KERNEL_ELF}" ${KERNEL_OBJECTS} "${KERNEL_RUST_LIB}" - DEPENDS ${KERNEL_OBJECTS} "${LINKER_SCRIPT}" "${KERNEL_RUST_LIB}" "${CMAKE_SOURCE_DIR}/clks/rust/src/lib.rs" - VERBATIM -) - -add_custom_target(kernel DEPENDS "${KERNEL_ELF}") - -add_custom_command( - OUTPUT "${KERNEL_SYMBOLS_FILE}" - COMMAND ${CMAKE_COMMAND} -E make_directory "${BUILD_ROOT}" - COMMAND ${CMAKE_COMMAND} - "-DNM_TOOL=${NM}" - "-DADDR2LINE_TOOL=${ADDR2LINE}" - "-DKERNEL_ELF=${KERNEL_ELF}" - "-DOUT_SYMBOL_FILE=${KERNEL_SYMBOLS_FILE}" - -P "${CMAKE_SOURCE_DIR}/cmake/gen_kernel_symbols.cmake" - DEPENDS "${KERNEL_ELF}" "${CMAKE_SOURCE_DIR}/cmake/gen_kernel_symbols.cmake" - VERBATIM -) - -add_custom_target(kernel-symbols DEPENDS "${KERNEL_SYMBOLS_FILE}") -add_dependencies(kernel-symbols kernel) diff --git a/clks/License b/clks/License deleted file mode 100644 index 59711bc..0000000 --- a/clks/License +++ /dev/null @@ -1,51 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of this License; and -You must cause any modified files to carry prominent notices stating that You changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/clks/Makefile b/clks/Makefile deleted file mode 100644 index 04c2f06..0000000 --- a/clks/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -.RECIPEPREFIX := > -MAKEFLAGS += --no-print-directory - -ROOT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) - -.PHONY: all configure reconfigure kernel menuconfig menuconfig-gui setup setup-tools setup-limine clean clean-all help - -all: kernel - -configure: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF configure - -reconfigure: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF reconfigure - -kernel: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF kernel - -menuconfig: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF menuconfig-clks - -menuconfig-gui: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF menuconfig-gui-clks - -setup: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF setup - -setup-tools: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF setup-tools - -setup-limine: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF setup-limine - -clean: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF clean - -clean-all: -> @$(MAKE) -C "$(ROOT_DIR)" CLEONOS_ENABLE=OFF clean-all - -help: -> @echo "CLKS standalone wrapper" -> @echo " make -C clks kernel" -> @echo " make -C clks menuconfig" -> @echo " make -C clks menuconfig-gui" -> @echo " make -C clks configure" -> @echo " make -C clks clean" -> @echo " make -C clks clean-all" diff --git a/clks/README.md b/clks/README.md deleted file mode 100644 index 21275b7..0000000 --- a/clks/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# CLKS Kernel - -[English](README.md) | [简体中文](README.zh-CN.md) - -CLKS is the kernel component of the CLeonOS project. -It includes architecture startup code, interrupt handling, memory management, scheduler, syscall layer, storage, TTY/console, and core runtime services. - -## Status - -CLKS can be built in kernel-only mode from the current mono-repo, but it is not yet a fully independent repository build system. - -- Kernel-only mode is available. -- Userland/ISO targets are optional and can be disabled. -- Some build scripts are still shared at repository root (`cmake/`, `configs/`, `scripts/`). - -## Directory Layout - -```text -clks/ -|- arch/ # Architecture-specific startup and low-level code -|- include/ # Public kernel headers -|- kernel/ # Core kernel subsystems -|- rust/ # Rust staticlib used by kernel -|- third_party/ # Embedded third-party sources used by kernel -|- CMakeLists.txt # Kernel build rules -|- Makefile # Kernel-focused wrapper (delegates to root build) -``` - -## Build (Kernel-Only) - -From repository root: - -```bash -make kernel CLEONOS_ENABLE=OFF -``` - -or via CLKS wrapper: - -```bash -make -C clks kernel -``` - -## Menuconfig (CLKS Scope) - -```bash -make menuconfig-clks -``` - -or: - -```bash -make -C clks menuconfig -``` - -This updates CLKS-focused config outputs under `configs/menuconfig/` (including `config.clks.cmake`). - -## Notes for Future Split - -To make CLKS a standalone repo, the next required step is moving shared build assets into `clks/` (or vendoring equivalents), especially: - -- `cmake/` helper scripts (`log.cmake`, symbol generation, tool checks) -- boot config and image packaging pieces currently under `configs/` -- menuconfig launcher and feature metadata currently under `scripts/` and `configs/menuconfig/` - -## License - -Apache-2.0 (same as project root). diff --git a/clks/README.zh-CN.md b/clks/README.zh-CN.md deleted file mode 100644 index 224b5cc..0000000 --- a/clks/README.zh-CN.md +++ /dev/null @@ -1,67 +0,0 @@ -# CLKS 内核 - -[English](README.md) | [简体中文](README.zh-CN.md) - -CLKS 是 CLeonOS 项目的内核部分。 -它包含架构启动代码、中断处理、内存管理、调度器、syscall 层、存储、TTY/控制台与核心运行时服务。 - -## 当前状态 - -CLKS 目前可以在单仓库中以仅内核模式构建,但还不是完全独立仓库形态的构建系统。 - -- 已支持仅内核构建模式。 -- 用户态/ISO 目标是可选项,可以关闭。 -- 仍有部分构建脚本与根目录共享(`cmake/`、`configs/`、`scripts/`)。 - -## 目录结构 - -```text -clks/ -|- arch/ # 架构相关启动与底层代码 -|- include/ # 对外内核头文件 -|- kernel/ # 内核核心子系统 -|- rust/ # 内核使用的 Rust staticlib -|- third_party/ # 内核使用的第三方源码 -|- CMakeLists.txt # 内核构建规则 -|- Makefile # 面向内核的包装入口(委托到根构建) -``` - -## 构建(仅内核) - -在仓库根目录执行: - -```bash -make kernel CLEONOS_ENABLE=OFF -``` - -或通过 CLKS 包装入口: - -```bash -make -C clks kernel -``` - -## Menuconfig(CLKS 作用域) - -```bash -make menuconfig-clks -``` - -或: - -```bash -make -C clks menuconfig -``` - -以上命令会更新 `configs/menuconfig/` 下的 CLKS 相关配置输出(包含 `config.clks.cmake`)。 - -## 后续独立拆分建议 - -若要将 CLKS 拆成独立仓库,下一步关键工作是把共享构建资产迁移到 `clks/`(或引入等价副本),重点包括: - -- `cmake/` 工具脚本(`log.cmake`、符号化生成、工具检查) -- 当前位于 `configs/` 下的启动配置与镜像打包相关内容 -- 当前位于 `scripts/` 与 `configs/menuconfig/` 下的 menuconfig 启动器与特性元数据 - -## 许可证 - -Apache-2.0(与项目根目录一致)。 diff --git a/clks/arch/aarch64/linker.ld b/clks/arch/aarch64/linker.ld deleted file mode 100644 index c674de3..0000000 --- a/clks/arch/aarch64/linker.ld +++ /dev/null @@ -1,38 +0,0 @@ -OUTPUT_FORMAT(elf64-littleaarch64) -ENTRY(_start) - -PHDRS { - text PT_LOAD FLAGS(5); - rodata PT_LOAD FLAGS(4); - data PT_LOAD FLAGS(7); -} - -SECTIONS { - . = 0x100000; - - .text : { - *(.text .text.*) - } :text - - .rodata : { - KEEP(*(.limine_requests_start)) - KEEP(*(.limine_requests)) - KEEP(*(.limine_requests_end)) - *(.rodata .rodata.*) - } :rodata - - .data : { - *(.data .data.*) - } :data - - .bss : { - *(COMMON) - *(.bss .bss.*) - } :data - - /DISCARD/ : { - *(.comment) - *(.eh_frame) - *(.note .note.*) - } -} diff --git a/clks/arch/aarch64/startup/boot.c b/clks/arch/aarch64/startup/boot.c deleted file mode 100644 index 993c0d7..0000000 --- a/clks/arch/aarch64/startup/boot.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include - -void _start(void) { - clks_kernel_main(); - clks_cpu_halt_forever(); -} \ No newline at end of file diff --git a/clks/arch/x86_64/interrupt/interrupt_stubs.S b/clks/arch/x86_64/interrupt/interrupt_stubs.S deleted file mode 100644 index e4d410f..0000000 --- a/clks/arch/x86_64/interrupt/interrupt_stubs.S +++ /dev/null @@ -1,119 +0,0 @@ -.intel_syntax noprefix - -.global clks_isr_stub_default -.extern clks_interrupt_dispatch - -.macro ISR_NOERR num -.global clks_isr_stub_\num -clks_isr_stub_\num: - push 0 - push \num - jmp clks_isr_common -.endm - -.macro ISR_ERR num -.global clks_isr_stub_\num -clks_isr_stub_\num: - push \num - jmp clks_isr_common -.endm - -clks_isr_stub_default: - push 0 - push 255 - jmp clks_isr_common - -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_ERR 17 -ISR_NOERR 18 -ISR_NOERR 19 -ISR_NOERR 20 -ISR_ERR 21 -ISR_NOERR 22 -ISR_NOERR 23 -ISR_NOERR 24 -ISR_NOERR 25 -ISR_NOERR 26 -ISR_NOERR 27 -ISR_NOERR 28 -ISR_ERR 29 -ISR_ERR 30 -ISR_NOERR 31 - -ISR_NOERR 32 -ISR_NOERR 33 -ISR_NOERR 34 -ISR_NOERR 35 -ISR_NOERR 36 -ISR_NOERR 37 -ISR_NOERR 38 -ISR_NOERR 39 -ISR_NOERR 40 -ISR_NOERR 41 -ISR_NOERR 42 -ISR_NOERR 43 -ISR_NOERR 44 -ISR_NOERR 45 -ISR_NOERR 46 -ISR_NOERR 47 -ISR_NOERR 128 - -clks_isr_common: - cld - - push r15 - push r14 - push r13 - push r12 - push r11 - push r10 - push r9 - push r8 - push rbp - push rdi - push rsi - push rdx - push rcx - push rbx - push rax - - mov rdi, rsp - sub rsp, 8 - call clks_interrupt_dispatch - add rsp, 8 - - pop rax - pop rbx - pop rcx - pop rdx - pop rsi - pop rdi - pop rbp - pop r8 - pop r9 - pop r10 - pop r11 - pop r12 - pop r13 - pop r14 - pop r15 - - add rsp, 16 - iretq -.section .note.GNU-stack,"",@progbits diff --git a/clks/arch/x86_64/linker.ld b/clks/arch/x86_64/linker.ld deleted file mode 100644 index a35b6e9..0000000 --- a/clks/arch/x86_64/linker.ld +++ /dev/null @@ -1,42 +0,0 @@ -OUTPUT_FORMAT(elf64-x86-64) -ENTRY(_start) - -PHDRS { - text PT_LOAD FLAGS(5); - rodata PT_LOAD FLAGS(4); - data PT_LOAD FLAGS(7); -} - -SECTIONS { - . = 0xffffffff80000000; - - . = ALIGN(0x1000); - .text : ALIGN(0x1000) { - *(.text .text.*) - } :text - - . = ALIGN(0x1000); - .rodata : ALIGN(0x1000) { - KEEP(*(.limine_requests_start)) - KEEP(*(.limine_requests)) - KEEP(*(.limine_requests_end)) - *(.rodata .rodata.*) - } :rodata - - . = ALIGN(0x1000); - .data : ALIGN(0x1000) { - *(.data .data.*) - } :data - - . = ALIGN(0x1000); - .bss : ALIGN(0x1000) { - *(COMMON) - *(.bss .bss.*) - } :data - - /DISCARD/ : { - *(.comment) - *(.eh_frame) - *(.note .note.*) - } -} diff --git a/clks/arch/x86_64/startup/boot.c b/clks/arch/x86_64/startup/boot.c deleted file mode 100644 index 993c0d7..0000000 --- a/clks/arch/x86_64/startup/boot.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include - -void _start(void) { - clks_kernel_main(); - clks_cpu_halt_forever(); -} \ No newline at end of file diff --git a/clks/arch/x86_64/startup/exec_stack_call.S b/clks/arch/x86_64/startup/exec_stack_call.S deleted file mode 100644 index b9dd1a8..0000000 --- a/clks/arch/x86_64/startup/exec_stack_call.S +++ /dev/null @@ -1,47 +0,0 @@ -.intel_syntax noprefix - -.global clks_exec_call_on_stack_x86_64 -.type clks_exec_call_on_stack_x86_64, @function -.global clks_exec_abort_to_caller_x86_64 -.type clks_exec_abort_to_caller_x86_64, @function - -clks_exec_call_on_stack_x86_64: - mov r11, rsp - mov rsp, rsi - and rsp, -16 - sub rsp, 56 - mov [rsp], r11 - mov [rsp + 8], rbx - mov [rsp + 16], rbp - mov [rsp + 24], r12 - mov [rsp + 32], r13 - mov [rsp + 40], r14 - mov [rsp + 48], r15 - - call rdi - - mov rbx, [rsp + 8] - mov rbp, [rsp + 16] - mov r12, [rsp + 24] - mov r13, [rsp + 32] - mov r14, [rsp + 40] - mov r15, [rsp + 48] - mov rsp, [rsp] - ret - -.size clks_exec_call_on_stack_x86_64, .-clks_exec_call_on_stack_x86_64 - -clks_exec_abort_to_caller_x86_64: - mov rax, rsi - mov rsp, rdi - mov rbx, [rsp + 8] - mov rbp, [rsp + 16] - mov r12, [rsp + 24] - mov r13, [rsp + 32] - mov r14, [rsp + 40] - mov r15, [rsp + 48] - mov rsp, [rsp] - ret - -.size clks_exec_abort_to_caller_x86_64, .-clks_exec_abort_to_caller_x86_64 -.section .note.GNU-stack,"",@progbits diff --git a/clks/include/clks/audio.h b/clks/include/clks/audio.h deleted file mode 100644 index 279636f..0000000 --- a/clks/include/clks/audio.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLKS_AUDIO_H -#define CLKS_AUDIO_H - -#include - -void clks_audio_init(void); -clks_bool clks_audio_available(void); -clks_bool clks_audio_play_tone(u64 hz, u64 ticks); -void clks_audio_stop(void); -u64 clks_audio_play_count(void); - -#endif \ No newline at end of file diff --git a/clks/include/clks/boot.h b/clks/include/clks/boot.h deleted file mode 100644 index 108dd93..0000000 --- a/clks/include/clks/boot.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef CLKS_BOOT_H -#define CLKS_BOOT_H - -#include -#include - -clks_bool clks_boot_base_revision_supported(void); -const struct limine_framebuffer *clks_boot_get_framebuffer(void); -const struct limine_memmap_response *clks_boot_get_memmap(void); -const struct limine_file *clks_boot_get_executable_file(void); -u64 clks_boot_get_module_count(void); -const struct limine_file *clks_boot_get_module(u64 index); - -#endif diff --git a/clks/include/clks/compiler.h b/clks/include/clks/compiler.h deleted file mode 100644 index 90cc1ef..0000000 --- a/clks/include/clks/compiler.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CLKS_COMPILER_H -#define CLKS_COMPILER_H - -#define CLKS_USED __attribute__((used)) -#define CLKS_NORETURN __attribute__((noreturn)) -#define CLKS_PACKED __attribute__((packed)) -#define CLKS_ALIGN(N) __attribute__((aligned(N))) - -#if defined(CLKS_ARCH_X86_64) && defined(CLKS_ARCH_AARCH64) -#error "Only one architecture can be selected" -#endif - -#if !defined(CLKS_ARCH_X86_64) && !defined(CLKS_ARCH_AARCH64) -#error "Missing architecture define: CLKS_ARCH_X86_64 or CLKS_ARCH_AARCH64" -#endif - -#endif \ No newline at end of file diff --git a/clks/include/clks/cpu.h b/clks/include/clks/cpu.h deleted file mode 100644 index 521cb12..0000000 --- a/clks/include/clks/cpu.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef CLKS_CPU_H -#define CLKS_CPU_H - -#include - -static inline void clks_cpu_pause(void) { -#if defined(CLKS_ARCH_X86_64) - __asm__ volatile("pause"); -#elif defined(CLKS_ARCH_AARCH64) - __asm__ volatile("yield"); -#endif -} - -static inline CLKS_NORETURN void clks_cpu_halt_forever(void) { - for (;;) { -#if defined(CLKS_ARCH_X86_64) - __asm__ volatile("hlt"); -#elif defined(CLKS_ARCH_AARCH64) - __asm__ volatile("wfe"); -#endif - } -} - -#endif \ No newline at end of file diff --git a/clks/include/clks/desktop.h b/clks/include/clks/desktop.h deleted file mode 100644 index c063725..0000000 --- a/clks/include/clks/desktop.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLKS_DESKTOP_H -#define CLKS_DESKTOP_H - -#include - -void clks_desktop_init(void); -void clks_desktop_tick(u64 tick); -clks_bool clks_desktop_ready(void); - -#endif diff --git a/clks/include/clks/disk.h b/clks/include/clks/disk.h deleted file mode 100644 index ec1f00e..0000000 --- a/clks/include/clks/disk.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CLKS_DISK_H -#define CLKS_DISK_H - -#include - -#define CLKS_DISK_SECTOR_SIZE 512ULL -#define CLKS_DISK_PATH_MAX 192U -#define CLKS_DISK_NODE_FILE 1ULL -#define CLKS_DISK_NODE_DIR 2ULL - -void clks_disk_init(void); - -clks_bool clks_disk_present(void); -u64 clks_disk_size_bytes(void); -u64 clks_disk_sector_count(void); - -clks_bool clks_disk_read_sector(u64 lba, void *out_sector); -clks_bool clks_disk_write_sector(u64 lba, const void *sector_data); - -clks_bool clks_disk_is_formatted_fat32(void); -clks_bool clks_disk_format_fat32(const char *label); - -clks_bool clks_disk_mount(const char *mount_path); -clks_bool clks_disk_is_mounted(void); -const char *clks_disk_mount_path(void); -clks_bool clks_disk_path_in_mount(const char *path); - -clks_bool clks_disk_stat(const char *path, u64 *out_type, u64 *out_size); -const void *clks_disk_read_all(const char *path, u64 *out_size); -u64 clks_disk_count_children(const char *dir_path); -clks_bool clks_disk_get_child_name(const char *dir_path, u64 index, char *out_name, usize out_name_size); -clks_bool clks_disk_mkdir(const char *path); -clks_bool clks_disk_write_all(const char *path, const void *data, u64 size); -clks_bool clks_disk_append(const char *path, const void *data, u64 size); -clks_bool clks_disk_remove(const char *path); -u64 clks_disk_node_count(void); - -#endif diff --git a/clks/include/clks/driver.h b/clks/include/clks/driver.h deleted file mode 100644 index 9dc9cca..0000000 --- a/clks/include/clks/driver.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef CLKS_DRIVER_H -#define CLKS_DRIVER_H - -#include - -#define CLKS_DRIVER_NAME_MAX 32U - -enum clks_driver_kind { - CLKS_DRIVER_KIND_BUILTIN_CHAR = 1, - CLKS_DRIVER_KIND_BUILTIN_VIDEO = 2, - CLKS_DRIVER_KIND_BUILTIN_TTY = 3, - CLKS_DRIVER_KIND_ELF = 4, - CLKS_DRIVER_KIND_BUILTIN_AUDIO = 5, -}; - -enum clks_driver_state { - CLKS_DRIVER_STATE_OFFLINE = 0, - CLKS_DRIVER_STATE_READY = 1, - CLKS_DRIVER_STATE_FAILED = 2, -}; - -struct clks_driver_info { - char name[CLKS_DRIVER_NAME_MAX]; - enum clks_driver_kind kind; - enum clks_driver_state state; - clks_bool from_elf; - u64 image_size; - u64 elf_entry; -}; - -void clks_driver_init(void); -u64 clks_driver_count(void); -u64 clks_driver_elf_count(void); -clks_bool clks_driver_get(u64 index, struct clks_driver_info *out_info); - -#endif diff --git a/clks/include/clks/elf64.h b/clks/include/clks/elf64.h deleted file mode 100644 index 3e0706d..0000000 --- a/clks/include/clks/elf64.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef CLKS_ELF64_H -#define CLKS_ELF64_H - -#include - -#define CLKS_ELF64_MAX_SEGMENTS 16U - -#define CLKS_ELF64_PT_LOAD 1U - -struct clks_elf64_info { - u64 entry; - u16 phnum; - u16 loadable_segments; - u64 total_load_memsz; -}; - -struct clks_elf64_loaded_segment { - void *base; - u64 vaddr; - u64 memsz; - u64 filesz; - u32 flags; -}; - -struct clks_elf64_loaded_image { - u64 entry; - void *image_base; - u64 image_size; - u64 image_vaddr_base; - u16 segment_count; - struct clks_elf64_loaded_segment segments[CLKS_ELF64_MAX_SEGMENTS]; -}; - -clks_bool clks_elf64_validate(const void *image, u64 size); -clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info *out_info); -clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded); -void clks_elf64_unload(struct clks_elf64_loaded_image *loaded); -void *clks_elf64_entry_pointer(const struct clks_elf64_loaded_image *loaded, u64 entry); - -#endif diff --git a/clks/include/clks/elfrunner.h b/clks/include/clks/elfrunner.h deleted file mode 100644 index d73c992..0000000 --- a/clks/include/clks/elfrunner.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef CLKS_ELFRUNNER_H -#define CLKS_ELFRUNNER_H - -#include - -void clks_elfrunner_init(void); -clks_bool clks_elfrunner_probe_kernel_executable(void); - -#endif \ No newline at end of file diff --git a/clks/include/clks/exec.h b/clks/include/clks/exec.h deleted file mode 100644 index 9afa183..0000000 --- a/clks/include/clks/exec.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef CLKS_EXEC_H -#define CLKS_EXEC_H - -#include - -#define CLKS_EXEC_PROC_PATH_MAX 192U - -#define CLKS_EXEC_PROC_STATE_UNUSED 0ULL -#define CLKS_EXEC_PROC_STATE_PENDING 1ULL -#define CLKS_EXEC_PROC_STATE_RUNNING 2ULL -#define CLKS_EXEC_PROC_STATE_EXITED 3ULL -#define CLKS_EXEC_PROC_STATE_STOPPED 4ULL - -#define CLKS_EXEC_SIGNAL_KILL 9ULL -#define CLKS_EXEC_SIGNAL_TERM 15ULL -#define CLKS_EXEC_SIGNAL_CONT 18ULL -#define CLKS_EXEC_SIGNAL_STOP 19ULL - -struct clks_exec_proc_snapshot { - u64 pid; - u64 ppid; - u64 state; - u64 started_tick; - u64 exited_tick; - u64 exit_status; - u64 runtime_ticks; - u64 mem_bytes; - u64 tty_index; - u64 last_signal; - u64 last_fault_vector; - u64 last_fault_error; - u64 last_fault_rip; - char path[CLKS_EXEC_PROC_PATH_MAX]; -}; - -void clks_exec_init(void); -clks_bool clks_exec_run_path(const char *path, u64 *out_status); -clks_bool clks_exec_run_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_status); -clks_bool clks_exec_run_pathv_io(const char *path, const char *argv_line, const char *env_line, u64 stdin_fd, - u64 stdout_fd, u64 stderr_fd, u64 *out_status); -clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid); -clks_bool clks_exec_spawn_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_pid); -u64 clks_exec_wait_pid(u64 pid, u64 *out_status); -clks_bool clks_exec_request_exit(u64 status); -u64 clks_exec_fd_open(const char *path, u64 flags, u64 mode); -u64 clks_exec_fd_read(u64 fd, void *out_buffer, u64 size); -u64 clks_exec_fd_write(u64 fd, const void *buffer, u64 size); -u64 clks_exec_fd_close(u64 fd); -u64 clks_exec_fd_dup(u64 fd); -u64 clks_exec_dl_open(const char *path); -u64 clks_exec_dl_close(u64 handle); -u64 clks_exec_dl_sym(u64 handle, const char *symbol); -u64 clks_exec_current_pid(void); -u32 clks_exec_current_tty(void); -u64 clks_exec_current_argc(void); -clks_bool clks_exec_copy_current_argv(u64 index, char *out_value, usize out_size); -u64 clks_exec_current_envc(void); -clks_bool clks_exec_copy_current_env(u64 index, char *out_value, usize out_size); -u64 clks_exec_current_signal(void); -u64 clks_exec_current_fault_vector(void); -u64 clks_exec_current_fault_error(void); -u64 clks_exec_current_fault_rip(void); -u64 clks_exec_proc_count(void); -clks_bool clks_exec_proc_pid_at(u64 index, u64 *out_pid); -clks_bool clks_exec_proc_snapshot(u64 pid, struct clks_exec_proc_snapshot *out_snapshot); -u64 clks_exec_proc_kill(u64 pid, u64 signal); -u64 clks_exec_force_stop_tty_running_process(u32 tty_index, u64 *out_pid); -clks_bool clks_exec_try_unwind_signaled_process(u64 interrupted_rip, u64 *io_rip, u64 *io_rdi, u64 *io_rsi); -clks_bool clks_exec_handle_exception(u64 vector, u64 error_code, u64 rip, u64 *io_rip, u64 *io_rdi, u64 *io_rsi); -u64 clks_exec_sleep_ticks(u64 ticks); -u64 clks_exec_yield(void); -void clks_exec_tick(u64 tick); -u64 clks_exec_request_count(void); -u64 clks_exec_success_count(void); -clks_bool clks_exec_is_running(void); -clks_bool clks_exec_current_path_is_user(void); -clks_bool clks_exec_current_user_ptr_readable(u64 addr, u64 size); -clks_bool clks_exec_current_user_ptr_writable(u64 addr, u64 size); - -#endif diff --git a/clks/include/clks/framebuffer.h b/clks/include/clks/framebuffer.h deleted file mode 100644 index 8e6d874..0000000 --- a/clks/include/clks/framebuffer.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CLKS_FRAMEBUFFER_H -#define CLKS_FRAMEBUFFER_H - -#include -#include - -struct clks_framebuffer_info { - u32 width; - u32 height; - u32 pitch; - u16 bpp; -}; - -void clks_fb_init(const struct limine_framebuffer *fb); -clks_bool clks_fb_ready(void); -struct clks_framebuffer_info clks_fb_info(void); -void clks_fb_clear(u32 rgb); -void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb); -void clks_fb_draw_pixel(u32 x, u32 y, u32 rgb); -clks_bool clks_fb_read_pixel(u32 x, u32 y, u32 *out_rgb); -void clks_fb_fill_rect(u32 x, u32 y, u32 width, u32 height, u32 rgb); -#define CLKS_FB_STYLE_BOLD 0x1U -#define CLKS_FB_STYLE_UNDERLINE 0x2U - -void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb); -void clks_fb_draw_char_styled(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb, u32 style_flags); -clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size); -u32 clks_fb_cell_width(void); -u32 clks_fb_cell_height(void); - -#endif diff --git a/clks/include/clks/fs.h b/clks/include/clks/fs.h deleted file mode 100644 index 0c81040..0000000 --- a/clks/include/clks/fs.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CLKS_FS_H -#define CLKS_FS_H - -#include - -enum clks_fs_node_type { - CLKS_FS_NODE_FILE = 1, - CLKS_FS_NODE_DIR = 2, -}; - -struct clks_fs_node_info { - enum clks_fs_node_type type; - u64 size; -}; - -void clks_fs_init(void); -clks_bool clks_fs_is_ready(void); -clks_bool clks_fs_stat(const char *path, struct clks_fs_node_info *out_info); -const void *clks_fs_read_all(const char *path, u64 *out_size); -u64 clks_fs_count_children(const char *dir_path); -clks_bool clks_fs_get_child_name(const char *dir_path, u64 index, char *out_name, usize out_name_size); - -clks_bool clks_fs_mkdir(const char *path); -clks_bool clks_fs_write_all(const char *path, const void *data, u64 size); -clks_bool clks_fs_append(const char *path, const void *data, u64 size); -clks_bool clks_fs_remove(const char *path); - -u64 clks_fs_node_count(void); - -#endif \ No newline at end of file diff --git a/clks/include/clks/heap.h b/clks/include/clks/heap.h deleted file mode 100644 index 32ee45f..0000000 --- a/clks/include/clks/heap.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CLKS_HEAP_H -#define CLKS_HEAP_H - -#include - -struct clks_heap_stats { - usize total_bytes; - usize used_bytes; - usize free_bytes; - u64 alloc_count; - u64 free_count; -}; - -void clks_heap_init(void); -void *clks_kmalloc(usize size); -void clks_kfree(void *ptr); -struct clks_heap_stats clks_heap_get_stats(void); - -#endif \ No newline at end of file diff --git a/clks/include/clks/interrupts.h b/clks/include/clks/interrupts.h deleted file mode 100644 index 17e8761..0000000 --- a/clks/include/clks/interrupts.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef CLKS_INTERRUPTS_H -#define CLKS_INTERRUPTS_H - -#include - -void clks_interrupts_init(void); -u64 clks_interrupts_timer_ticks(void); - -#endif \ No newline at end of file diff --git a/clks/include/clks/kelf.h b/clks/include/clks/kelf.h deleted file mode 100644 index 0f9eaf7..0000000 --- a/clks/include/clks/kelf.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CLKS_KELF_H -#define CLKS_KELF_H - -#include - -typedef u64 (*clks_kelf_entry_fn)(u64 tick, u64 run_count); - -void clks_kelf_init(void); -void clks_kelf_tick(u64 tick); -u64 clks_kelf_count(void); -u64 clks_kelf_total_runs(void); - -#endif diff --git a/clks/include/clks/kernel.h b/clks/include/clks/kernel.h deleted file mode 100644 index f49b684..0000000 --- a/clks/include/clks/kernel.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CLKS_KERNEL_H -#define CLKS_KERNEL_H - -void clks_kernel_main(void); - -#endif \ No newline at end of file diff --git a/clks/include/clks/keyboard.h b/clks/include/clks/keyboard.h deleted file mode 100644 index 7e1546d..0000000 --- a/clks/include/clks/keyboard.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CLKS_KEYBOARD_H -#define CLKS_KEYBOARD_H - -#include - -#define CLKS_KEY_LEFT ((char)0x01) -#define CLKS_KEY_RIGHT ((char)0x02) -#define CLKS_KEY_UP ((char)0x03) -#define CLKS_KEY_DOWN ((char)0x04) -#define CLKS_KEY_HOME ((char)0x05) -#define CLKS_KEY_END ((char)0x06) -#define CLKS_KEY_DELETE ((char)0x07) -#define CLKS_KEY_SELECT_ALL ((char)0x10) -#define CLKS_KEY_COPY ((char)0x11) -#define CLKS_KEY_PASTE ((char)0x12) -#define CLKS_KEY_SHIFT_LEFT ((char)0x13) -#define CLKS_KEY_SHIFT_RIGHT ((char)0x14) -#define CLKS_KEY_SHIFT_HOME ((char)0x15) -#define CLKS_KEY_SHIFT_END ((char)0x16) - -void clks_keyboard_init(void); -void clks_keyboard_handle_scancode(u8 scancode); -u64 clks_keyboard_hotkey_switch_count(void); -clks_bool clks_keyboard_pop_char(char *out_ch); -clks_bool clks_keyboard_pop_char_for_tty(u32 tty_index, char *out_ch); -u64 clks_keyboard_buffered_count(void); -u64 clks_keyboard_drop_count(void); -u64 clks_keyboard_push_count(void); -u64 clks_keyboard_pop_count(void); - -#endif diff --git a/clks/include/clks/limine.h b/clks/include/clks/limine.h deleted file mode 100644 index 833e512..0000000 --- a/clks/include/clks/limine.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef CLKS_LIMINE_H -#define CLKS_LIMINE_H - -#include - -#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88ULL -#define LIMINE_REQUEST_MAGIC 0x0a82e883a194f07bULL - -#define LIMINE_REQUESTS_START_MARKER \ - { 0xf6b8f4b39de7d1aeULL, 0xfab91a6940fcb9cfULL } - -#define LIMINE_REQUESTS_END_MARKER \ - { 0xadc0e0531bb10d03ULL, 0x9572709f31764c62ULL } - -#define LIMINE_BASE_REVISION(N) \ - { 0xf9562b2d5c95a6c8ULL, 0x6a7b384944536bdcULL, (N) } - -#define LIMINE_FRAMEBUFFER_REQUEST \ - { LIMINE_COMMON_MAGIC, LIMINE_REQUEST_MAGIC, 0x9d5827dcd881dd75ULL, 0xa3148604f6fab11bULL } - -#define LIMINE_MEMMAP_REQUEST \ - { LIMINE_COMMON_MAGIC, LIMINE_REQUEST_MAGIC, 0x67cf3d9d378a806fULL, 0xe304acdfc50c3c62ULL } - -#define LIMINE_EXECUTABLE_FILE_REQUEST \ - { LIMINE_COMMON_MAGIC, LIMINE_REQUEST_MAGIC, 0xad97e90e83f1ed67ULL, 0x31eb5d1c5ff23b69ULL } - -#define LIMINE_MODULE_REQUEST \ - { LIMINE_COMMON_MAGIC, LIMINE_REQUEST_MAGIC, 0x3e7e279702be32afULL, 0xca1c4f3bd1280ceeULL } - -#define LIMINE_MEMMAP_USABLE 0ULL -#define LIMINE_MEMMAP_RESERVED 1ULL -#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2ULL -#define LIMINE_MEMMAP_ACPI_NVS 3ULL -#define LIMINE_MEMMAP_BAD_MEMORY 4ULL -#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5ULL -#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6ULL -#define LIMINE_MEMMAP_FRAMEBUFFER 7ULL -#define LIMINE_MEMMAP_RESERVED_MAPPED 8ULL - -struct limine_uuid { - u32 a; - u16 b; - u16 c; - u8 d[8]; -}; - -struct limine_file { - u64 revision; - void *address; - u64 size; - char *path; - char *string; - u32 media_type; - u32 unused; - u32 tftp_ip; - u32 tftp_port; - u32 partition_index; - u32 mbr_disk_id; - struct limine_uuid gpt_disk_uuid; - struct limine_uuid gpt_part_uuid; - struct limine_uuid part_uuid; -}; - -struct limine_framebuffer { - void *address; - u64 width; - u64 height; - u64 pitch; - u16 bpp; - u8 memory_model; - u8 red_mask_size; - u8 red_mask_shift; - u8 green_mask_size; - u8 green_mask_shift; - u8 blue_mask_size; - u8 blue_mask_shift; - u8 unused[7]; - u64 edid_size; - void *edid; -}; - -struct limine_framebuffer_response { - u64 revision; - u64 framebuffer_count; - struct limine_framebuffer **framebuffers; -}; - -struct limine_framebuffer_request { - u64 id[4]; - u64 revision; - struct limine_framebuffer_response *response; -}; - -struct limine_memmap_entry { - u64 base; - u64 length; - u64 type; -}; - -struct limine_memmap_response { - u64 revision; - u64 entry_count; - struct limine_memmap_entry **entries; -}; - -struct limine_memmap_request { - u64 id[4]; - u64 revision; - struct limine_memmap_response *response; -}; - -struct limine_executable_file_response { - u64 revision; - struct limine_file *executable_file; -}; - -struct limine_executable_file_request { - u64 id[4]; - u64 revision; - struct limine_executable_file_response *response; -}; - -struct limine_module_response { - u64 revision; - u64 module_count; - struct limine_file **modules; -}; - -struct limine_module_request { - u64 id[4]; - u64 revision; - struct limine_module_response *response; -}; - -#endif diff --git a/clks/include/clks/log.h b/clks/include/clks/log.h deleted file mode 100644 index 81f3676..0000000 --- a/clks/include/clks/log.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CLKS_LOG_H -#define CLKS_LOG_H - -#include - -enum clks_log_level { - CLKS_LOG_DEBUG = 0, - CLKS_LOG_INFO = 1, - CLKS_LOG_WARN = 2, - CLKS_LOG_ERROR = 3, -}; - -void clks_log(enum clks_log_level level, const char *tag, const char *message); -void clks_log_hex(enum clks_log_level level, const char *tag, const char *label, u64 value); - -u64 clks_log_journal_count(void); -clks_bool clks_log_journal_read(u64 index_from_oldest, char *out_line, usize out_line_size); - -#endif \ No newline at end of file diff --git a/clks/include/clks/mouse.h b/clks/include/clks/mouse.h deleted file mode 100644 index c1263ae..0000000 --- a/clks/include/clks/mouse.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CLKS_MOUSE_H -#define CLKS_MOUSE_H - -#include - -#define CLKS_MOUSE_BTN_LEFT 0x01U -#define CLKS_MOUSE_BTN_RIGHT 0x02U -#define CLKS_MOUSE_BTN_MIDDLE 0x04U - -struct clks_mouse_state { - i32 x; - i32 y; - u8 buttons; - u64 packet_count; - clks_bool ready; -}; - -void clks_mouse_init(void); -void clks_mouse_handle_byte(u8 data_byte); -void clks_mouse_snapshot(struct clks_mouse_state *out_state); -clks_bool clks_mouse_ready(void); -u64 clks_mouse_packet_count(void); -u64 clks_mouse_drop_count(void); - -#endif diff --git a/clks/include/clks/panic.h b/clks/include/clks/panic.h deleted file mode 100644 index 494ab41..0000000 --- a/clks/include/clks/panic.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLKS_PANIC_H -#define CLKS_PANIC_H - -#include -#include - -CLKS_NORETURN void clks_panic(const char *reason); -CLKS_NORETURN void clks_panic_exception(const char *name, u64 vector, u64 error_code, u64 rip, u64 rbp, u64 rsp); - -#endif diff --git a/clks/include/clks/panic_qr.h b/clks/include/clks/panic_qr.h deleted file mode 100644 index 019a579..0000000 --- a/clks/include/clks/panic_qr.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CLKS_PANIC_QR_H -#define CLKS_PANIC_QR_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -clks_bool clks_panic_qr_prepare(void); -clks_bool clks_panic_qr_show(void); -u64 clks_panic_qr_total_lines(void); -u64 clks_panic_qr_dropped_lines(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/clks/include/clks/pmm.h b/clks/include/clks/pmm.h deleted file mode 100644 index bf91078..0000000 --- a/clks/include/clks/pmm.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CLKS_PMM_H -#define CLKS_PMM_H - -#include -#include - -#define CLKS_PAGE_SIZE 4096ULL - -struct clks_pmm_stats { - u64 managed_pages; - u64 free_pages; - u64 used_pages; - u64 dropped_pages; -}; - -void clks_pmm_init(const struct limine_memmap_response *memmap); -u64 clks_pmm_alloc_page(void); -void clks_pmm_free_page(u64 phys_addr); -struct clks_pmm_stats clks_pmm_get_stats(void); - -#endif \ No newline at end of file diff --git a/clks/include/clks/ramdisk.h b/clks/include/clks/ramdisk.h deleted file mode 100644 index f86b799..0000000 --- a/clks/include/clks/ramdisk.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef CLKS_RAMDISK_H -#define CLKS_RAMDISK_H - -#include - -#define CLKS_RAMDISK_PATH_MAX 192U - -enum clks_ramdisk_entry_type { - CLKS_RAMDISK_ENTRY_FILE = 1, - CLKS_RAMDISK_ENTRY_DIR = 2, -}; - -struct clks_ramdisk_entry { - enum clks_ramdisk_entry_type type; - char path[CLKS_RAMDISK_PATH_MAX]; - const void *data; - u64 size; -}; - -typedef clks_bool (*clks_ramdisk_iter_fn)(const struct clks_ramdisk_entry *entry, void *ctx); - -clks_bool clks_ramdisk_iterate(const void *image, u64 image_size, clks_ramdisk_iter_fn iter_fn, void *ctx); - -#endif diff --git a/clks/include/clks/scheduler.h b/clks/include/clks/scheduler.h deleted file mode 100644 index ac1b08b..0000000 --- a/clks/include/clks/scheduler.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CLKS_SCHEDULER_H -#define CLKS_SCHEDULER_H - -#include -#include - -struct clks_scheduler_stats { - u32 task_count; - u32 current_task_id; - u64 total_timer_ticks; - u64 context_switch_count; -}; - -void clks_scheduler_init(void); -clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks); -clks_bool clks_scheduler_add_kernel_task_ex(const char *name, u32 time_slice_ticks, clks_task_entry_fn entry); -void clks_scheduler_on_timer_tick(u64 tick); -void clks_scheduler_dispatch_current(u64 tick); -struct clks_scheduler_stats clks_scheduler_get_stats(void); -const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id); - -#endif diff --git a/clks/include/clks/serial.h b/clks/include/clks/serial.h deleted file mode 100644 index 7fca79d..0000000 --- a/clks/include/clks/serial.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CLKS_SERIAL_H -#define CLKS_SERIAL_H - -void clks_serial_init(void); -void clks_serial_write_char(char ch); -void clks_serial_write(const char *text); - -#endif \ No newline at end of file diff --git a/clks/include/clks/service.h b/clks/include/clks/service.h deleted file mode 100644 index 8b04d3e..0000000 --- a/clks/include/clks/service.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CLKS_SERVICE_H -#define CLKS_SERVICE_H - -#include - -#define CLKS_SERVICE_NAME_MAX 24U - -enum clks_service_id { - CLKS_SERVICE_LOG = 1, - CLKS_SERVICE_MEM = 2, - CLKS_SERVICE_FS = 3, - CLKS_SERVICE_DRIVER = 4, - CLKS_SERVICE_SCHED = 5, - CLKS_SERVICE_KELF = 6, - CLKS_SERVICE_USER = 7, -}; - -enum clks_service_state { - CLKS_SERVICE_STATE_OFFLINE = 0, - CLKS_SERVICE_STATE_READY = 1, - CLKS_SERVICE_STATE_DEGRADED = 2, -}; - -struct clks_service_info { - u32 id; - char name[CLKS_SERVICE_NAME_MAX]; - enum clks_service_state state; - u64 heartbeat_count; - u64 last_heartbeat_tick; -}; - -void clks_service_init(void); -clks_bool clks_service_heartbeat(u32 service_id, u64 tick); -u64 clks_service_count(void); -u64 clks_service_ready_count(void); -clks_bool clks_service_get(u32 service_id, struct clks_service_info *out_info); - -#endif diff --git a/clks/include/clks/shell.h b/clks/include/clks/shell.h deleted file mode 100644 index 533f47e..0000000 --- a/clks/include/clks/shell.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLKS_SHELL_H -#define CLKS_SHELL_H - -#include - -void clks_shell_init(void); -void clks_shell_pump_input(u32 max_chars); -void clks_shell_tick(u64 tick); - -#endif \ No newline at end of file diff --git a/clks/include/clks/string.h b/clks/include/clks/string.h deleted file mode 100644 index 9e221e8..0000000 --- a/clks/include/clks/string.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLKS_STRING_H -#define CLKS_STRING_H - -#include - -usize clks_strlen(const char *str); -void *clks_memset(void *dst, int value, usize count); -void *clks_memcpy(void *dst, const void *src, usize count); -void *clks_memmove(void *dst, const void *src, usize count); -int clks_strcmp(const char *left, const char *right); - -#endif \ No newline at end of file diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h deleted file mode 100644 index 2c2679f..0000000 --- a/clks/include/clks/syscall.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef CLKS_SYSCALL_H -#define CLKS_SYSCALL_H - -#include - -#define CLKS_SYSCALL_LOG_WRITE 0ULL -#define CLKS_SYSCALL_TIMER_TICKS 1ULL -#define CLKS_SYSCALL_TASK_COUNT 2ULL -#define CLKS_SYSCALL_CURRENT_TASK_ID 3ULL -#define CLKS_SYSCALL_SERVICE_COUNT 4ULL -#define CLKS_SYSCALL_SERVICE_READY_COUNT 5ULL -#define CLKS_SYSCALL_CONTEXT_SWITCHES 6ULL -#define CLKS_SYSCALL_KELF_COUNT 7ULL -#define CLKS_SYSCALL_KELF_RUNS 8ULL -#define CLKS_SYSCALL_FS_NODE_COUNT 9ULL -#define CLKS_SYSCALL_FS_CHILD_COUNT 10ULL -#define CLKS_SYSCALL_FS_GET_CHILD_NAME 11ULL -#define CLKS_SYSCALL_FS_READ 12ULL -#define CLKS_SYSCALL_EXEC_PATH 13ULL -#define CLKS_SYSCALL_EXEC_REQUESTS 14ULL -#define CLKS_SYSCALL_EXEC_SUCCESS 15ULL -#define CLKS_SYSCALL_USER_SHELL_READY 16ULL -#define CLKS_SYSCALL_USER_EXEC_REQUESTED 17ULL -#define CLKS_SYSCALL_USER_LAUNCH_TRIES 18ULL -#define CLKS_SYSCALL_USER_LAUNCH_OK 19ULL -#define CLKS_SYSCALL_USER_LAUNCH_FAIL 20ULL -#define CLKS_SYSCALL_TTY_COUNT 21ULL -#define CLKS_SYSCALL_TTY_ACTIVE 22ULL -#define CLKS_SYSCALL_TTY_SWITCH 23ULL -#define CLKS_SYSCALL_TTY_WRITE 24ULL -#define CLKS_SYSCALL_TTY_WRITE_CHAR 25ULL -#define CLKS_SYSCALL_KBD_GET_CHAR 26ULL -#define CLKS_SYSCALL_FS_STAT_TYPE 27ULL -#define CLKS_SYSCALL_FS_STAT_SIZE 28ULL -#define CLKS_SYSCALL_FS_MKDIR 29ULL -#define CLKS_SYSCALL_FS_WRITE 30ULL -#define CLKS_SYSCALL_FS_APPEND 31ULL -#define CLKS_SYSCALL_FS_REMOVE 32ULL -#define CLKS_SYSCALL_LOG_JOURNAL_COUNT 33ULL -#define CLKS_SYSCALL_LOG_JOURNAL_READ 34ULL -#define CLKS_SYSCALL_KBD_BUFFERED 35ULL -#define CLKS_SYSCALL_KBD_PUSHED 36ULL -#define CLKS_SYSCALL_KBD_POPPED 37ULL -#define CLKS_SYSCALL_KBD_DROPPED 38ULL -#define CLKS_SYSCALL_KBD_HOTKEY_SWITCHES 39ULL -#define CLKS_SYSCALL_GETPID 40ULL -#define CLKS_SYSCALL_SPAWN_PATH 41ULL -#define CLKS_SYSCALL_WAITPID 42ULL -#define CLKS_SYSCALL_EXIT 43ULL -#define CLKS_SYSCALL_SLEEP_TICKS 44ULL -#define CLKS_SYSCALL_YIELD 45ULL -#define CLKS_SYSCALL_SHUTDOWN 46ULL -#define CLKS_SYSCALL_RESTART 47ULL -#define CLKS_SYSCALL_AUDIO_AVAILABLE 48ULL -#define CLKS_SYSCALL_AUDIO_PLAY_TONE 49ULL -#define CLKS_SYSCALL_AUDIO_STOP 50ULL -#define CLKS_SYSCALL_EXEC_PATHV 51ULL -#define CLKS_SYSCALL_SPAWN_PATHV 52ULL -#define CLKS_SYSCALL_PROC_ARGC 53ULL -#define CLKS_SYSCALL_PROC_ARGV 54ULL -#define CLKS_SYSCALL_PROC_ENVC 55ULL -#define CLKS_SYSCALL_PROC_ENV 56ULL -#define CLKS_SYSCALL_PROC_LAST_SIGNAL 57ULL -#define CLKS_SYSCALL_PROC_FAULT_VECTOR 58ULL -#define CLKS_SYSCALL_PROC_FAULT_ERROR 59ULL -#define CLKS_SYSCALL_PROC_FAULT_RIP 60ULL -#define CLKS_SYSCALL_PROC_COUNT 61ULL -#define CLKS_SYSCALL_PROC_PID_AT 62ULL -#define CLKS_SYSCALL_PROC_SNAPSHOT 63ULL -#define CLKS_SYSCALL_PROC_KILL 64ULL -#define CLKS_SYSCALL_KDBG_SYM 65ULL -#define CLKS_SYSCALL_KDBG_BT 66ULL -#define CLKS_SYSCALL_KDBG_REGS 67ULL -#define CLKS_SYSCALL_STATS_TOTAL 68ULL -#define CLKS_SYSCALL_STATS_ID_COUNT 69ULL -#define CLKS_SYSCALL_STATS_RECENT_WINDOW 70ULL -#define CLKS_SYSCALL_STATS_RECENT_ID 71ULL -#define CLKS_SYSCALL_FD_OPEN 72ULL -#define CLKS_SYSCALL_FD_READ 73ULL -#define CLKS_SYSCALL_FD_WRITE 74ULL -#define CLKS_SYSCALL_FD_CLOSE 75ULL -#define CLKS_SYSCALL_FD_DUP 76ULL -#define CLKS_SYSCALL_DL_OPEN 77ULL -#define CLKS_SYSCALL_DL_CLOSE 78ULL -#define CLKS_SYSCALL_DL_SYM 79ULL -#define CLKS_SYSCALL_EXEC_PATHV_IO 80ULL -#define CLKS_SYSCALL_FB_INFO 81ULL -#define CLKS_SYSCALL_FB_BLIT 82ULL -#define CLKS_SYSCALL_FB_CLEAR 83ULL -#define CLKS_SYSCALL_KERNEL_VERSION 84ULL -#define CLKS_SYSCALL_DISK_PRESENT 85ULL -#define CLKS_SYSCALL_DISK_SIZE_BYTES 86ULL -#define CLKS_SYSCALL_DISK_SECTOR_COUNT 87ULL -#define CLKS_SYSCALL_DISK_FORMATTED 88ULL -#define CLKS_SYSCALL_DISK_FORMAT_FAT32 89ULL -#define CLKS_SYSCALL_DISK_MOUNT 90ULL -#define CLKS_SYSCALL_DISK_MOUNTED 91ULL -#define CLKS_SYSCALL_DISK_MOUNT_PATH 92ULL -#define CLKS_SYSCALL_DISK_READ_SECTOR 93ULL -#define CLKS_SYSCALL_DISK_WRITE_SECTOR 94ULL - -void clks_syscall_init(void); -u64 clks_syscall_dispatch(void *frame_ptr); -u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2); - -#endif diff --git a/clks/include/clks/task.h b/clks/include/clks/task.h deleted file mode 100644 index 1ae3921..0000000 --- a/clks/include/clks/task.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CLKS_TASK_H -#define CLKS_TASK_H - -#include - -#define CLKS_TASK_NAME_MAX 32U - -typedef void (*clks_task_entry_fn)(u64 tick); - -enum clks_task_state { CLKS_TASK_UNUSED = 0, CLKS_TASK_READY = 1, CLKS_TASK_RUNNING = 2, CLKS_TASK_BLOCKED = 3 }; - -struct clks_task_descriptor { - u32 id; - char name[CLKS_TASK_NAME_MAX]; - enum clks_task_state state; - u32 time_slice_ticks; - u32 remaining_ticks; - u64 total_ticks; - u64 switch_count; - u64 run_count; - u64 last_run_tick; - clks_task_entry_fn entry; -}; - -#endif diff --git a/clks/include/clks/tty.h b/clks/include/clks/tty.h deleted file mode 100644 index 673fd1d..0000000 --- a/clks/include/clks/tty.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CLKS_TTY_H -#define CLKS_TTY_H - -#include - -void clks_tty_init(void); -void clks_tty_write(const char *text); -void clks_tty_write_n(const char *text, usize len); -void clks_tty_write_char(char ch); -void clks_tty_switch(u32 tty_index); -void clks_tty_tick(u64 tick); -void clks_tty_scrollback_page_up(void); -void clks_tty_scrollback_page_down(void); -u32 clks_tty_active(void); -u32 clks_tty_count(void); -clks_bool clks_tty_ready(void); - -#endif diff --git a/clks/include/clks/types.h b/clks/include/clks/types.h deleted file mode 100644 index 4320254..0000000 --- a/clks/include/clks/types.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CLKS_TYPES_H -#define CLKS_TYPES_H - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -typedef signed char i8; -typedef signed short i16; -typedef signed int i32; -typedef signed long long i64; - -typedef u64 usize; - -typedef enum clks_bool { CLKS_FALSE = 0, CLKS_TRUE = 1 } clks_bool; - -#define CLKS_NULL ((void *)0) - -#endif \ No newline at end of file diff --git a/clks/include/clks/userland.h b/clks/include/clks/userland.h deleted file mode 100644 index 5eff098..0000000 --- a/clks/include/clks/userland.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CLKS_USERLAND_H -#define CLKS_USERLAND_H - -#include - -clks_bool clks_userland_init(void); -void clks_userland_tick(u64 tick); -clks_bool clks_userland_shell_ready(void); -clks_bool clks_userland_shell_exec_requested(void); -clks_bool clks_userland_shell_auto_exec_enabled(void); -u64 clks_userland_launch_attempts(void); -u64 clks_userland_launch_success(void); -u64 clks_userland_launch_failures(void); - -#endif diff --git a/clks/include/clks/version.h b/clks/include/clks/version.h deleted file mode 100644 index 56e00bc..0000000 --- a/clks/include/clks/version.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CLKS_VERSION_H -#define CLKS_VERSION_H - -#define CLKS_VERSION_STRING "1.0.0-alpha" - -#endif diff --git a/clks/kernel/boot/limine/limine_requests.c b/clks/kernel/boot/limine/limine_requests.c deleted file mode 100644 index 4f31bdb..0000000 --- a/clks/kernel/boot/limine/limine_requests.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include - -CLKS_USED static volatile u64 limine_requests_start[] __attribute__((section(".limine_requests_start"))) = - LIMINE_REQUESTS_START_MARKER; - -CLKS_USED static volatile u64 limine_base_revision[] __attribute__((section(".limine_requests"))) = - LIMINE_BASE_REVISION(3); - -CLKS_USED static volatile struct limine_framebuffer_request limine_framebuffer_request - __attribute__((section(".limine_requests"))) = { - .id = LIMINE_FRAMEBUFFER_REQUEST, - .revision = 0, - .response = CLKS_NULL, -}; - -CLKS_USED static volatile struct limine_memmap_request limine_memmap_request - __attribute__((section(".limine_requests"))) = { - .id = LIMINE_MEMMAP_REQUEST, - .revision = 0, - .response = CLKS_NULL, -}; - -CLKS_USED static volatile struct limine_executable_file_request limine_executable_file_request - __attribute__((section(".limine_requests"))) = { - .id = LIMINE_EXECUTABLE_FILE_REQUEST, - .revision = 0, - .response = CLKS_NULL, -}; - -CLKS_USED static volatile struct limine_module_request limine_module_request - __attribute__((section(".limine_requests"))) = { - .id = LIMINE_MODULE_REQUEST, - .revision = 0, - .response = CLKS_NULL, -}; - -CLKS_USED static volatile u64 limine_requests_end[] __attribute__((section(".limine_requests_end"))) = - LIMINE_REQUESTS_END_MARKER; - -clks_bool clks_boot_base_revision_supported(void) { - return (limine_base_revision[2] == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -const struct limine_framebuffer *clks_boot_get_framebuffer(void) { - volatile struct limine_framebuffer_request *request = &limine_framebuffer_request; - - if (request->response == CLKS_NULL) { - return CLKS_NULL; - } - - if (request->response->framebuffer_count < 1) { - return CLKS_NULL; - } - - return request->response->framebuffers[0]; -} - -const struct limine_memmap_response *clks_boot_get_memmap(void) { - volatile struct limine_memmap_request *request = &limine_memmap_request; - - if (request->response == CLKS_NULL) { - return CLKS_NULL; - } - - return request->response; -} - -const struct limine_file *clks_boot_get_executable_file(void) { - volatile struct limine_executable_file_request *request = &limine_executable_file_request; - - if (request->response == CLKS_NULL) { - return CLKS_NULL; - } - - return request->response->executable_file; -} - -u64 clks_boot_get_module_count(void) { - volatile struct limine_module_request *request = &limine_module_request; - - if (request->response == CLKS_NULL) { - return 0ULL; - } - - return request->response->module_count; -} - -const struct limine_file *clks_boot_get_module(u64 index) { - volatile struct limine_module_request *request = &limine_module_request; - - if (request->response == CLKS_NULL) { - return CLKS_NULL; - } - - if (index >= request->response->module_count) { - return CLKS_NULL; - } - - return request->response->modules[index]; -} diff --git a/clks/kernel/core/interrupts.c b/clks/kernel/core/interrupts.c deleted file mode 100644 index 8f92707..0000000 --- a/clks/kernel/core/interrupts.c +++ /dev/null @@ -1,349 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CLKS_IDT_ENTRY_COUNT 256U -#define CLKS_INTERRUPT_GATE 0x8EU -#define CLKS_USER_INT_GATE 0xEEU - -#define CLKS_PIC1_CMD 0x20U -#define CLKS_PIC1_DATA 0x21U -#define CLKS_PIC2_CMD 0xA0U -#define CLKS_PIC2_DATA 0xA1U -#define CLKS_PIC_EOI 0x20U - -#define CLKS_IRQ_BASE 32U -#define CLKS_IRQ_TIMER 32U -#define CLKS_IRQ_KEYBOARD 33U -#define CLKS_IRQ_MOUSE 44U -#define CLKS_IRQ_LAST 47U -#define CLKS_SYSCALL_VECTOR 128U - -#define CLKS_PS2_DATA_PORT 0x60U -#define CLKS_PS2_STATUS_PORT 0x64U - -struct clks_idt_entry { - u16 offset_low; - u16 selector; - u8 ist; - u8 type_attr; - u16 offset_mid; - u32 offset_high; - u32 zero; -} CLKS_PACKED; - -struct clks_idtr { - u16 limit; - u64 base; -} CLKS_PACKED; - -struct clks_interrupt_frame { - u64 rax; - u64 rbx; - u64 rcx; - u64 rdx; - u64 rsi; - u64 rdi; - u64 rbp; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; - u64 vector; - u64 error_code; - u64 rip; - u64 cs; - u64 rflags; - u64 rsp; - u64 ss; -}; - -extern void clks_isr_stub_default(void); -extern void clks_isr_stub_0(void); -extern void clks_isr_stub_1(void); -extern void clks_isr_stub_2(void); -extern void clks_isr_stub_3(void); -extern void clks_isr_stub_4(void); -extern void clks_isr_stub_5(void); -extern void clks_isr_stub_6(void); -extern void clks_isr_stub_7(void); -extern void clks_isr_stub_8(void); -extern void clks_isr_stub_9(void); -extern void clks_isr_stub_10(void); -extern void clks_isr_stub_11(void); -extern void clks_isr_stub_12(void); -extern void clks_isr_stub_13(void); -extern void clks_isr_stub_14(void); -extern void clks_isr_stub_15(void); -extern void clks_isr_stub_16(void); -extern void clks_isr_stub_17(void); -extern void clks_isr_stub_18(void); -extern void clks_isr_stub_19(void); -extern void clks_isr_stub_20(void); -extern void clks_isr_stub_21(void); -extern void clks_isr_stub_22(void); -extern void clks_isr_stub_23(void); -extern void clks_isr_stub_24(void); -extern void clks_isr_stub_25(void); -extern void clks_isr_stub_26(void); -extern void clks_isr_stub_27(void); -extern void clks_isr_stub_28(void); -extern void clks_isr_stub_29(void); -extern void clks_isr_stub_30(void); -extern void clks_isr_stub_31(void); -extern void clks_isr_stub_32(void); -extern void clks_isr_stub_33(void); -extern void clks_isr_stub_34(void); -extern void clks_isr_stub_35(void); -extern void clks_isr_stub_36(void); -extern void clks_isr_stub_37(void); -extern void clks_isr_stub_38(void); -extern void clks_isr_stub_39(void); -extern void clks_isr_stub_40(void); -extern void clks_isr_stub_41(void); -extern void clks_isr_stub_42(void); -extern void clks_isr_stub_43(void); -extern void clks_isr_stub_44(void); -extern void clks_isr_stub_45(void); -extern void clks_isr_stub_46(void); -extern void clks_isr_stub_47(void); -extern void clks_isr_stub_128(void); - -static struct clks_idt_entry clks_idt[CLKS_IDT_ENTRY_COUNT]; -static u16 clks_idt_code_selector = 0x08U; -static u64 clks_timer_ticks = 0; - -static const char *clks_exception_names[32] = {"DE DIVIDE ERROR", - "DB DEBUG", - "NMI", - "BP BREAKPOINT", - "OF OVERFLOW", - "BR BOUND RANGE", - "UD INVALID OPCODE", - "NM DEVICE NOT AVAILABLE", - "DF DOUBLE FAULT", - "COPROCESSOR SEGMENT", - "TS INVALID TSS", - "NP SEGMENT NOT PRESENT", - "SS STACK SEGMENT", - "GP GENERAL PROTECTION", - "PF PAGE FAULT", - "RESERVED", - "MF X87 FLOAT", - "AC ALIGNMENT CHECK", - "MC MACHINE CHECK", - "XF SIMD FLOAT", - "VE VIRT EXCEPTION", - "CP CONTROL PROTECTION", - "RESERVED", - "RESERVED", - "RESERVED", - "RESERVED", - "RESERVED", - "RESERVED", - "HV HYPERVISOR", - "VC VMM COMM", - "SX SECURITY", - "RESERVED"}; - -static inline void clks_outb(u16 port, u8 value) { - __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); -} - -static inline u8 clks_inb(u16 port) { - u8 value; - __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); - return value; -} - -static inline void clks_io_wait(void) { - __asm__ volatile("outb %%al, $0x80" : : "a"(0)); -} - -static void clks_pic_remap_and_mask(void) { - u8 master_mask = clks_inb(CLKS_PIC1_DATA); - u8 slave_mask = clks_inb(CLKS_PIC2_DATA); - - clks_outb(CLKS_PIC1_CMD, 0x11); - clks_io_wait(); - clks_outb(CLKS_PIC2_CMD, 0x11); - clks_io_wait(); - - clks_outb(CLKS_PIC1_DATA, CLKS_IRQ_BASE); - clks_io_wait(); - clks_outb(CLKS_PIC2_DATA, CLKS_IRQ_BASE + 8U); - clks_io_wait(); - - clks_outb(CLKS_PIC1_DATA, 4U); - clks_io_wait(); - clks_outb(CLKS_PIC2_DATA, 2U); - clks_io_wait(); - - clks_outb(CLKS_PIC1_DATA, 0x01); - clks_io_wait(); - clks_outb(CLKS_PIC2_DATA, 0x01); - clks_io_wait(); - - (void)master_mask; - (void)slave_mask; - - clks_outb(CLKS_PIC1_DATA, 0xF8U); - clks_outb(CLKS_PIC2_DATA, 0xEFU); -} - -static void clks_pic_send_eoi(u64 vector) { - if (vector >= 40U) { - clks_outb(CLKS_PIC2_CMD, CLKS_PIC_EOI); - } - - clks_outb(CLKS_PIC1_CMD, CLKS_PIC_EOI); -} - -static void clks_idt_set_gate(u8 vector, void (*handler)(void), u8 flags) { - u64 addr = (u64)handler; - - clks_idt[vector].offset_low = (u16)(addr & 0xFFFFULL); - clks_idt[vector].selector = clks_idt_code_selector; - clks_idt[vector].ist = 0; - clks_idt[vector].type_attr = flags; - clks_idt[vector].offset_mid = (u16)((addr >> 16) & 0xFFFFULL); - clks_idt[vector].offset_high = (u32)((addr >> 32) & 0xFFFFFFFFULL); - clks_idt[vector].zero = 0; -} - -static void clks_load_idt(void) { - struct clks_idtr idtr; - - idtr.limit = (u16)(sizeof(clks_idt) - 1U); - idtr.base = (u64)&clks_idt[0]; - - __asm__ volatile("lidt %0" : : "m"(idtr)); -} - -static clks_bool clks_ps2_has_output(void) { - return (clks_inb(CLKS_PS2_STATUS_PORT) & 0x01U) != 0U ? CLKS_TRUE : CLKS_FALSE; -} -static void clks_enable_interrupts(void) { - __asm__ volatile("sti"); -} - -void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) { - u64 vector = frame->vector; - - if (vector == CLKS_SYSCALL_VECTOR) { - frame->rax = clks_syscall_dispatch((void *)frame); - return; - } - - if (vector < 32U) { - if (clks_exec_handle_exception(vector, frame->error_code, frame->rip, &frame->rip, &frame->rdi, &frame->rsi) == - CLKS_TRUE) { - return; - } - - clks_panic_exception(clks_exception_names[vector], vector, frame->error_code, frame->rip, frame->rbp, - frame->rsp); - } - - if (vector == CLKS_IRQ_TIMER) { - clks_timer_ticks++; - clks_scheduler_on_timer_tick(clks_timer_ticks); - } else if (vector == CLKS_IRQ_KEYBOARD) { - if (clks_ps2_has_output() == CLKS_TRUE) { - u8 scancode = clks_inb(CLKS_PS2_DATA_PORT); - clks_keyboard_handle_scancode(scancode); - } - } else if (vector == CLKS_IRQ_MOUSE) { - if (clks_ps2_has_output() == CLKS_TRUE) { - u8 data_byte = clks_inb(CLKS_PS2_DATA_PORT); - clks_mouse_handle_byte(data_byte); - } - } - - if (vector >= CLKS_IRQ_BASE && vector <= CLKS_IRQ_LAST) { - (void)clks_exec_try_unwind_signaled_process(frame->rip, &frame->rip, &frame->rdi, &frame->rsi); - clks_pic_send_eoi(vector); - } -} - -void clks_interrupts_init(void) { - u32 i; - - __asm__ volatile("mov %%cs, %0" : "=r"(clks_idt_code_selector)); - - for (i = 0; i < CLKS_IDT_ENTRY_COUNT; i++) { - clks_idt_set_gate((u8)i, clks_isr_stub_default, CLKS_INTERRUPT_GATE); - } - - clks_idt_set_gate(0, clks_isr_stub_0, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(1, clks_isr_stub_1, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(2, clks_isr_stub_2, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(3, clks_isr_stub_3, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(4, clks_isr_stub_4, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(5, clks_isr_stub_5, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(6, clks_isr_stub_6, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(7, clks_isr_stub_7, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(8, clks_isr_stub_8, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(9, clks_isr_stub_9, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(10, clks_isr_stub_10, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(11, clks_isr_stub_11, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(12, clks_isr_stub_12, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(13, clks_isr_stub_13, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(14, clks_isr_stub_14, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(15, clks_isr_stub_15, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(16, clks_isr_stub_16, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(17, clks_isr_stub_17, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(18, clks_isr_stub_18, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(19, clks_isr_stub_19, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(20, clks_isr_stub_20, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(21, clks_isr_stub_21, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(22, clks_isr_stub_22, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(23, clks_isr_stub_23, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(24, clks_isr_stub_24, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(25, clks_isr_stub_25, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(26, clks_isr_stub_26, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(27, clks_isr_stub_27, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(28, clks_isr_stub_28, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(29, clks_isr_stub_29, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(30, clks_isr_stub_30, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(31, clks_isr_stub_31, CLKS_INTERRUPT_GATE); - - clks_idt_set_gate(32, clks_isr_stub_32, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(33, clks_isr_stub_33, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(34, clks_isr_stub_34, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(35, clks_isr_stub_35, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(36, clks_isr_stub_36, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(37, clks_isr_stub_37, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(38, clks_isr_stub_38, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(39, clks_isr_stub_39, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(40, clks_isr_stub_40, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(41, clks_isr_stub_41, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(42, clks_isr_stub_42, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(43, clks_isr_stub_43, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(44, clks_isr_stub_44, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(45, clks_isr_stub_45, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(46, clks_isr_stub_46, CLKS_INTERRUPT_GATE); - clks_idt_set_gate(47, clks_isr_stub_47, CLKS_INTERRUPT_GATE); - - clks_idt_set_gate(CLKS_SYSCALL_VECTOR, clks_isr_stub_128, CLKS_USER_INT_GATE); - - clks_pic_remap_and_mask(); - clks_load_idt(); - clks_enable_interrupts(); -} - -u64 clks_interrupts_timer_ticks(void) { - return clks_timer_ticks; -} diff --git a/clks/kernel/core/kmain.c b/clks/kernel/core/kmain.c deleted file mode 100644 index 3b8b0c2..0000000 --- a/clks/kernel/core/kmain.c +++ /dev/null @@ -1,472 +0,0 @@ -// Kernel main function - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Boot orchestration file: one wrong init order and the whole damn thing faceplants. */ - -#ifndef CLKS_CFG_AUDIO -#define CLKS_CFG_AUDIO 1 -#endif - -#ifndef CLKS_CFG_MOUSE -#define CLKS_CFG_MOUSE 1 -#endif - -#ifndef CLKS_CFG_DESKTOP -#define CLKS_CFG_DESKTOP 1 -#endif - -#ifndef CLKS_CFG_DRIVER_MANAGER -#define CLKS_CFG_DRIVER_MANAGER 1 -#endif - -#ifndef CLKS_CFG_KELF -#define CLKS_CFG_KELF 1 -#endif - -#ifndef CLKS_CFG_HEAP_SELFTEST -#define CLKS_CFG_HEAP_SELFTEST 1 -#endif - -#ifndef CLKS_CFG_EXTERNAL_PSF -#define CLKS_CFG_EXTERNAL_PSF 1 -#endif - -#ifndef CLKS_CFG_KEYBOARD -#define CLKS_CFG_KEYBOARD 1 -#endif - -#ifndef CLKS_CFG_ELFRUNNER_PROBE -#define CLKS_CFG_ELFRUNNER_PROBE 1 -#endif - -#ifndef CLKS_CFG_KLOGD_TASK -#define CLKS_CFG_KLOGD_TASK 1 -#endif - -#ifndef CLKS_CFG_KWORKER_TASK -#define CLKS_CFG_KWORKER_TASK 1 -#endif - -#ifndef CLKS_CFG_USRD_TASK -#define CLKS_CFG_USRD_TASK 1 -#endif - -#ifndef CLKS_CFG_BOOT_VIDEO_LOG -#define CLKS_CFG_BOOT_VIDEO_LOG 1 -#endif - -#ifndef CLKS_CFG_PMM_STATS_LOG -#define CLKS_CFG_PMM_STATS_LOG 1 -#endif - -#ifndef CLKS_CFG_HEAP_STATS_LOG -#define CLKS_CFG_HEAP_STATS_LOG 1 -#endif - -#ifndef CLKS_CFG_FS_ROOT_LOG -#define CLKS_CFG_FS_ROOT_LOG 1 -#endif - -#ifndef CLKS_CFG_SYSTEM_DIR_CHECK -#define CLKS_CFG_SYSTEM_DIR_CHECK 1 -#endif - -#ifndef CLKS_CFG_ELFRUNNER_INIT -#define CLKS_CFG_ELFRUNNER_INIT 1 -#endif - -#ifndef CLKS_CFG_SYSCALL_TICK_QUERY -#define CLKS_CFG_SYSCALL_TICK_QUERY 1 -#endif - -#ifndef CLKS_CFG_TTY_READY_LOG -#define CLKS_CFG_TTY_READY_LOG 1 -#endif - -#ifndef CLKS_CFG_IDLE_DEBUG_LOG -#define CLKS_CFG_IDLE_DEBUG_LOG 1 -#endif - -#ifndef CLKS_CFG_SCHED_TASK_COUNT_LOG -#define CLKS_CFG_SCHED_TASK_COUNT_LOG 1 -#endif - -#ifndef CLKS_CFG_INTERRUPT_READY_LOG -#define CLKS_CFG_INTERRUPT_READY_LOG 1 -#endif - -#ifndef CLKS_CFG_SHELL_MODE_LOG -#define CLKS_CFG_SHELL_MODE_LOG 1 -#endif - -#if CLKS_CFG_KLOGD_TASK -static void clks_task_klogd(u64 tick) { - static u64 last_emit = 0ULL; - - clks_service_heartbeat(CLKS_SERVICE_LOG, tick); - - if (tick - last_emit >= 1000ULL) { - clks_log_hex(CLKS_LOG_DEBUG, "TASK", "KLOGD_TICK", tick); - last_emit = tick; - } -} -#endif - -#if CLKS_CFG_KWORKER_TASK -static void clks_task_kworker(u64 tick) { - static u32 phase = 0U; - - clks_service_heartbeat(CLKS_SERVICE_SCHED, tick); - - switch (phase) { - case 0U: - clks_service_heartbeat(CLKS_SERVICE_MEM, tick); - break; - case 1U: - clks_service_heartbeat(CLKS_SERVICE_FS, tick); - break; - case 2U: - clks_service_heartbeat(CLKS_SERVICE_DRIVER, tick); - break; - default: - clks_service_heartbeat(CLKS_SERVICE_LOG, tick); - break; - } - - phase = (phase + 1U) & 3U; -} -#endif - -#if CLKS_CFG_KELF -static void clks_task_kelfd(u64 tick) { - clks_service_heartbeat(CLKS_SERVICE_KELF, tick); - clks_kelf_tick(tick); -} -#endif - -#if CLKS_CFG_USRD_TASK -static void clks_task_usrd(u64 tick) { - clks_service_heartbeat(CLKS_SERVICE_USER, tick); - clks_exec_tick(tick); - clks_userland_tick(tick); -#if CLKS_CFG_DESKTOP - clks_desktop_tick(tick); -#endif - clks_tty_tick(tick); - clks_shell_tick(tick); -} -#endif - -void clks_kernel_main(void) { - const struct limine_framebuffer *boot_fb; - const struct limine_memmap_response *boot_memmap; - struct clks_pmm_stats pmm_stats; - struct clks_heap_stats heap_stats; - struct clks_fs_node_info fs_system_dir = {0}; - u64 syscall_ticks; - u64 fs_root_children; - - /* Serial first, because when graphics dies we still need a heartbeat. */ - clks_serial_init(); - - /* If boot protocol handshake fails, continuing would be pure fantasy. */ - if (clks_boot_base_revision_supported() == CLKS_FALSE) { - clks_serial_write("[ERROR][BOOT] LIMINE BASE REVISION NOT SUPPORTED\n"); - clks_cpu_halt_forever(); - } - - boot_fb = clks_boot_get_framebuffer(); - - /* TTY comes up only when framebuffer exists; no pixels, no pretty lies. */ - if (boot_fb != CLKS_NULL) { - clks_fb_init(boot_fb); - clks_tty_init(); - } - - clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS START"); - - if (boot_fb == CLKS_NULL) { - clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); - } else { -#if CLKS_CFG_BOOT_VIDEO_LOG - clks_log_hex(CLKS_LOG_INFO, "VIDEO", "WIDTH", boot_fb->width); - clks_log_hex(CLKS_LOG_INFO, "VIDEO", "HEIGHT", boot_fb->height); - clks_log_hex(CLKS_LOG_INFO, "VIDEO", "PITCH", boot_fb->pitch); - clks_log_hex(CLKS_LOG_INFO, "VIDEO", "BPP", boot_fb->bpp); -#else - clks_log(CLKS_LOG_WARN, "CFG", "BOOT VIDEO LOGS DISABLED BY MENUCONFIG"); -#endif - } - -#if defined(CLKS_ARCH_X86_64) - clks_log(CLKS_LOG_INFO, "ARCH", "X86_64 ONLINE"); -#elif defined(CLKS_ARCH_AARCH64) - clks_log(CLKS_LOG_INFO, "ARCH", "AARCH64 ONLINE"); -#endif - - boot_memmap = clks_boot_get_memmap(); - - if (boot_memmap == CLKS_NULL) { - clks_log(CLKS_LOG_ERROR, "MEM", "NO LIMINE MEMMAP RESPONSE"); - clks_cpu_halt_forever(); - } - - clks_pmm_init(boot_memmap); - pmm_stats = clks_pmm_get_stats(); - -#if CLKS_CFG_PMM_STATS_LOG - clks_log_hex(CLKS_LOG_INFO, "PMM", "MANAGED_PAGES", pmm_stats.managed_pages); - clks_log_hex(CLKS_LOG_INFO, "PMM", "FREE_PAGES", pmm_stats.free_pages); - clks_log_hex(CLKS_LOG_INFO, "PMM", "USED_PAGES", pmm_stats.used_pages); - clks_log_hex(CLKS_LOG_INFO, "PMM", "DROPPED_PAGES", pmm_stats.dropped_pages); -#else - (void)pmm_stats; - clks_log(CLKS_LOG_WARN, "CFG", "PMM STATS LOGS DISABLED BY MENUCONFIG"); -#endif - - clks_heap_init(); - heap_stats = clks_heap_get_stats(); - -#if CLKS_CFG_HEAP_STATS_LOG - clks_log_hex(CLKS_LOG_INFO, "HEAP", "TOTAL_BYTES", heap_stats.total_bytes); - clks_log_hex(CLKS_LOG_INFO, "HEAP", "FREE_BYTES", heap_stats.free_bytes); -#else - (void)heap_stats; - clks_log(CLKS_LOG_WARN, "CFG", "HEAP STATS LOGS DISABLED BY MENUCONFIG"); -#endif - -#if CLKS_CFG_HEAP_SELFTEST - void *heap_probe = clks_kmalloc(128); - - if (heap_probe == CLKS_NULL) { - clks_log(CLKS_LOG_ERROR, "HEAP", "KMALLOC SELFTEST FAILED"); - } else { - clks_log(CLKS_LOG_INFO, "HEAP", "KMALLOC SELFTEST OK"); - clks_kfree(heap_probe); - } -#else - clks_log(CLKS_LOG_WARN, "CFG", "HEAP SELFTEST DISABLED BY MENUCONFIG"); -#endif - - clks_fs_init(); - - if (clks_fs_is_ready() == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "FS", "RAMDISK FS INIT FAILED"); - clks_cpu_halt_forever(); - } - - fs_root_children = clks_fs_count_children("/"); -#if CLKS_CFG_FS_ROOT_LOG - clks_log_hex(CLKS_LOG_INFO, "FS", "ROOT_CHILDREN", fs_root_children); -#else - (void)fs_root_children; -#endif - -#if CLKS_CFG_SYSTEM_DIR_CHECK - if (clks_fs_stat("/system", &fs_system_dir) == CLKS_FALSE || fs_system_dir.type != CLKS_FS_NODE_DIR) { - clks_log(CLKS_LOG_ERROR, "FS", "/SYSTEM DIRECTORY CHECK FAILED"); - clks_cpu_halt_forever(); - } -#else - (void)fs_system_dir; - clks_log(CLKS_LOG_WARN, "CFG", "/SYSTEM DIRECTORY CHECK DISABLED BY MENUCONFIG"); -#endif - - if (boot_fb != CLKS_NULL) { -#if CLKS_CFG_EXTERNAL_PSF - const void *tty_psf_blob; - u64 tty_psf_size = 0ULL; - - tty_psf_blob = clks_fs_read_all("/system/tty.psf", &tty_psf_size); - - if (tty_psf_blob != CLKS_NULL && clks_fb_load_psf_font(tty_psf_blob, tty_psf_size) == CLKS_TRUE) { - clks_tty_init(); - clks_log(CLKS_LOG_INFO, "TTY", "EXTERNAL PSF LOADED /SYSTEM/TTY.PSF"); - clks_log_hex(CLKS_LOG_INFO, "TTY", "PSF_SIZE", tty_psf_size); - } else { - clks_log(CLKS_LOG_WARN, "TTY", "EXTERNAL PSF LOAD FAILED, USING BUILTIN"); - } -#else - clks_log(CLKS_LOG_WARN, "CFG", "EXTERNAL PSF LOADING DISABLED BY MENUCONFIG"); -#endif - } - - clks_exec_init(); -#if CLKS_CFG_AUDIO - clks_audio_init(); -#else - clks_log(CLKS_LOG_WARN, "CFG", "AUDIO DISABLED BY MENUCONFIG"); -#endif -#if CLKS_CFG_KEYBOARD - clks_keyboard_init(); -#else - clks_log(CLKS_LOG_WARN, "CFG", "KEYBOARD DISABLED BY MENUCONFIG"); -#endif -#if CLKS_CFG_MOUSE - clks_mouse_init(); -#else - clks_log(CLKS_LOG_WARN, "CFG", "MOUSE DISABLED BY MENUCONFIG"); -#endif -#if CLKS_CFG_DESKTOP - clks_desktop_init(); -#else - clks_log(CLKS_LOG_WARN, "CFG", "DESKTOP DISABLED BY MENUCONFIG"); -#endif - - if (clks_userland_init() == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "USER", "USERLAND INIT FAILED"); - clks_cpu_halt_forever(); - } - -#if CLKS_CFG_DRIVER_MANAGER - clks_driver_init(); -#else - clks_log(CLKS_LOG_WARN, "CFG", "DRIVER MANAGER DISABLED BY MENUCONFIG"); -#endif -#if CLKS_CFG_KELF - clks_kelf_init(); -#else - clks_log(CLKS_LOG_WARN, "CFG", "KELF DISABLED BY MENUCONFIG"); -#endif - - /* Scheduler init is the "okay, now this mess is actually alive" moment. */ - clks_scheduler_init(); - -#if CLKS_CFG_KLOGD_TASK - if (clks_scheduler_add_kernel_task_ex("klogd", 4U, clks_task_klogd) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KLOGD TASK"); - } -#else - clks_log(CLKS_LOG_WARN, "SCHED", "KLOGD TASK DISABLED BY MENUCONFIG"); -#endif - -#if CLKS_CFG_KWORKER_TASK - if (clks_scheduler_add_kernel_task_ex("kworker", 3U, clks_task_kworker) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KWORKER TASK"); - } -#else - clks_log(CLKS_LOG_WARN, "SCHED", "KWORKER TASK DISABLED BY MENUCONFIG"); -#endif - -#if CLKS_CFG_KELF - if (clks_scheduler_add_kernel_task_ex("kelfd", 5U, clks_task_kelfd) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KELFD TASK"); - } -#else - clks_log(CLKS_LOG_WARN, "SCHED", "KELFD TASK DISABLED BY MENUCONFIG"); -#endif - -#if CLKS_CFG_USRD_TASK - if (clks_scheduler_add_kernel_task_ex("usrd", 4U, clks_task_usrd) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD USRD TASK"); - } -#else - clks_log(CLKS_LOG_WARN, "SCHED", "USRD TASK DISABLED BY MENUCONFIG"); -#endif - -#if CLKS_CFG_SCHED_TASK_COUNT_LOG - { - struct clks_scheduler_stats sched_stats = clks_scheduler_get_stats(); - clks_log_hex(CLKS_LOG_INFO, "SCHED", "TASK_COUNT", sched_stats.task_count); - } -#else - clks_log(CLKS_LOG_WARN, "CFG", "SCHED TASK COUNT LOG DISABLED BY MENUCONFIG"); -#endif - - clks_service_init(); - -#if CLKS_CFG_ELFRUNNER_INIT - clks_elfrunner_init(); -#else - clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER INIT DISABLED BY MENUCONFIG"); -#endif - -#if CLKS_CFG_ELFRUNNER_INIT -#if CLKS_CFG_ELFRUNNER_PROBE - if (clks_elfrunner_probe_kernel_executable() == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF PROBE FAILED"); - } -#else - clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER PROBE DISABLED BY MENUCONFIG"); -#endif -#else - clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER PROBE SKIPPED (INIT DISABLED)"); -#endif - - clks_syscall_init(); - - clks_interrupts_init(); -#if CLKS_CFG_INTERRUPT_READY_LOG - clks_log(CLKS_LOG_INFO, "INT", "IDT + PIC INITIALIZED"); -#endif - -#if CLKS_CFG_SYSCALL_TICK_QUERY - syscall_ticks = clks_syscall_invoke_kernel(CLKS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL); - clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks); -#else - (void)syscall_ticks; - clks_log(CLKS_LOG_WARN, "CFG", "SYSCALL TICK QUERY DISABLED BY MENUCONFIG"); -#endif - - clks_shell_init(); - -#if CLKS_CFG_USRD_TASK -#if CLKS_CFG_SHELL_MODE_LOG - if (clks_userland_shell_auto_exec_enabled() == CLKS_TRUE) { - clks_log(CLKS_LOG_INFO, "SHELL", "DEFAULT ENTER USER SHELL MODE"); - } else { - clks_log(CLKS_LOG_INFO, "SHELL", "KERNEL SHELL ACTIVE"); - } -#endif -#else -#if CLKS_CFG_SHELL_MODE_LOG - clks_log(CLKS_LOG_WARN, "SHELL", "USRD TASK DISABLED; INTERACTIVE SHELL TICK OFF"); -#endif -#endif - -#if CLKS_CFG_TTY_READY_LOG - clks_log_hex(CLKS_LOG_INFO, "TTY", "COUNT", (u64)clks_tty_count()); - clks_log_hex(CLKS_LOG_INFO, "TTY", "ACTIVE", (u64)clks_tty_active()); - clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY"); - clks_log(CLKS_LOG_INFO, "TTY", "CURSOR ENABLED"); -#endif -#if CLKS_CFG_IDLE_DEBUG_LOG - clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER"); -#endif - - /* Infinite idle loop: glamorous name for "wait forever and hope interrupts behave". */ - for (;;) { - u64 tick_now = clks_interrupts_timer_ticks(); - clks_scheduler_dispatch_current(tick_now); -#if defined(CLKS_ARCH_X86_64) - __asm__ volatile("hlt"); -#elif defined(CLKS_ARCH_AARCH64) - __asm__ volatile("wfe"); -#endif - } -} diff --git a/clks/kernel/core/log.c b/clks/kernel/core/log.c deleted file mode 100644 index 7d16697..0000000 --- a/clks/kernel/core/log.c +++ /dev/null @@ -1,226 +0,0 @@ -#include -#include -#include -#include - -#define CLKS_LOG_LINE_MAX 256 -#define CLKS_LOG_JOURNAL_CAP 256 - -#define CLKS_LOG_ANSI_RESET "\x1B[0m" - -static char clks_log_journal[CLKS_LOG_JOURNAL_CAP][CLKS_LOG_LINE_MAX]; -static u32 clks_log_journal_head = 0U; -static u32 clks_log_journal_count_live = 0U; - -static const char *clks_log_level_name(enum clks_log_level level) { - switch (level) { - case CLKS_LOG_DEBUG: - return "DEBUG"; - case CLKS_LOG_INFO: - return "INFO"; - case CLKS_LOG_WARN: - return "WARN"; - case CLKS_LOG_ERROR: - return "ERROR"; - default: - return "UNK"; - } -} - -static void clks_log_append_char(char *buffer, usize *cursor, char ch) { - if (*cursor >= (CLKS_LOG_LINE_MAX - 1)) { - return; - } - - buffer[*cursor] = ch; - (*cursor)++; -} - -static void clks_log_append_text(char *buffer, usize *cursor, const char *text) { - usize i = 0; - - if (text == CLKS_NULL) { - return; - } - - while (text[i] != '\0') { - clks_log_append_char(buffer, cursor, text[i]); - i++; - } -} - -static void clks_log_append_hex_u64(char *buffer, usize *cursor, u64 value) { - int nibble; - - clks_log_append_text(buffer, cursor, "0X"); - - for (nibble = 15; nibble >= 0; nibble--) { - u8 current = (u8)((value >> (nibble * 4)) & 0x0FULL); - char out = (current < 10) ? (char)('0' + current) : (char)('A' + (current - 10)); - clks_log_append_char(buffer, cursor, out); - } -} - -static void clks_log_journal_copy_line(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || src == CLKS_NULL || dst_size == 0U) { - return; - } - - while (i + 1U < dst_size && src[i] != '\0') { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static void clks_log_journal_push(const char *line) { - if (line == CLKS_NULL) { - return; - } - - clks_log_journal_copy_line(clks_log_journal[clks_log_journal_head], CLKS_LOG_LINE_MAX, line); - clks_log_journal_head = (clks_log_journal_head + 1U) % CLKS_LOG_JOURNAL_CAP; - - if (clks_log_journal_count_live < CLKS_LOG_JOURNAL_CAP) { - clks_log_journal_count_live++; - } -} - -static const char *clks_log_level_ansi(enum clks_log_level level) { - switch (level) { - case CLKS_LOG_DEBUG: - return "\x1B[38;5;110m"; - case CLKS_LOG_INFO: - return "\x1B[38;5;120m"; - case CLKS_LOG_WARN: - return "\x1B[1;38;5;220m"; - case CLKS_LOG_ERROR: - return "\x1B[1;38;5;203m"; - default: - return "\x1B[38;5;250m"; - } -} - -static const char *clks_log_tag_ansi(const char *tag) { - static const char *palette[] = { - "\x1B[38;5;81m", "\x1B[38;5;117m", "\x1B[38;5;159m", "\x1B[38;5;45m", - "\x1B[38;5;75m", "\x1B[38;5;141m", "\x1B[38;5;214m", "\x1B[38;5;168m", - }; - u32 hash = 5381U; - usize i = 0U; - usize palette_count = sizeof(palette) / sizeof(palette[0]); - - if (tag == CLKS_NULL || tag[0] == '\0') { - return palette[0]; - } - - while (tag[i] != '\0') { - hash = ((hash << 5U) + hash) ^ (u32)(u8)tag[i]; - i++; - } - - return palette[hash % (u32)palette_count]; -} - -static void clks_log_emit_tty_colored(enum clks_log_level level, const char *tag, const char *message) { - const char *safe_tag = (tag == CLKS_NULL) ? "LOG" : tag; - const char *safe_message = (message == CLKS_NULL) ? "" : message; - - clks_tty_write(clks_log_level_ansi(level)); - clks_tty_write("["); - clks_tty_write(clks_log_level_name(level)); - clks_tty_write("]"); - - clks_tty_write(clks_log_tag_ansi(safe_tag)); - clks_tty_write("["); - clks_tty_write(safe_tag); - clks_tty_write("]"); - - clks_tty_write(CLKS_LOG_ANSI_RESET); - clks_tty_write(" "); - clks_tty_write(safe_message); - clks_tty_write("\n"); -} - -static void clks_log_build_line(enum clks_log_level level, const char *tag, const char *message, char *line) { - const char *safe_tag = (tag == CLKS_NULL) ? "LOG" : tag; - const char *safe_message = (message == CLKS_NULL) ? "" : message; - usize cursor = 0U; - - if (line == CLKS_NULL) { - return; - } - - clks_log_append_char(line, &cursor, '['); - clks_log_append_text(line, &cursor, clks_log_level_name(level)); - clks_log_append_char(line, &cursor, ']'); - clks_log_append_char(line, &cursor, '['); - clks_log_append_text(line, &cursor, safe_tag); - clks_log_append_char(line, &cursor, ']'); - clks_log_append_char(line, &cursor, ' '); - clks_log_append_text(line, &cursor, safe_message); - line[cursor] = '\0'; -} - -static void clks_log_emit_line(enum clks_log_level level, const char *tag, const char *message, const char *line) { - if (line == CLKS_NULL) { - return; - } - - clks_log_journal_push(line); - - clks_serial_write(line); - clks_serial_write("\n"); - - clks_log_emit_tty_colored(level, tag, message); -} - -void clks_log(enum clks_log_level level, const char *tag, const char *message) { - char line[CLKS_LOG_LINE_MAX]; - - clks_log_build_line(level, tag, message, line); - clks_log_emit_line(level, tag, message, line); -} - -void clks_log_hex(enum clks_log_level level, const char *tag, const char *label, u64 value) { - char message[CLKS_LOG_LINE_MAX]; - char line[CLKS_LOG_LINE_MAX]; - usize cursor = 0U; - - clks_log_append_text(message, &cursor, (label == CLKS_NULL) ? "VALUE" : label); - clks_log_append_char(message, &cursor, ':'); - clks_log_append_char(message, &cursor, ' '); - clks_log_append_hex_u64(message, &cursor, value); - message[cursor] = '\0'; - - clks_log_build_line(level, tag, message, line); - clks_log_emit_line(level, tag, message, line); -} - -u64 clks_log_journal_count(void) { - return (u64)clks_log_journal_count_live; -} - -clks_bool clks_log_journal_read(u64 index_from_oldest, char *out_line, usize out_line_size) { - u32 oldest; - u32 slot; - - if (out_line == CLKS_NULL || out_line_size == 0U) { - return CLKS_FALSE; - } - - out_line[0] = '\0'; - - if (index_from_oldest >= (u64)clks_log_journal_count_live) { - return CLKS_FALSE; - } - - oldest = (clks_log_journal_head + CLKS_LOG_JOURNAL_CAP - clks_log_journal_count_live) % CLKS_LOG_JOURNAL_CAP; - slot = (oldest + (u32)index_from_oldest) % CLKS_LOG_JOURNAL_CAP; - - clks_log_journal_copy_line(out_line, out_line_size, clks_log_journal[slot]); - return CLKS_TRUE; -} diff --git a/clks/kernel/core/panic.c b/clks/kernel/core/panic.c deleted file mode 100644 index 0a3367f..0000000 --- a/clks/kernel/core/panic.c +++ /dev/null @@ -1,864 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define CLKS_PANIC_BG 0x00200000U -#define CLKS_PANIC_FG 0x00FFE0E0U - -#define CLKS_PANIC_BACKTRACE_MAX 20U -#define CLKS_PANIC_STACK_WINDOW_BYTES (128ULL * 1024ULL) -#define CLKS_PANIC_SYMBOL_FILE "/system/kernel.sym" -#define CLKS_PANIC_KERNEL_ADDR_BASE 0xFFFF800000000000ULL -#define CLKS_PANIC_QR_HINT "\nPress SPACE to toggle panic log QR.\n" -#define CLKS_PANIC_REASON_MAX 192U -#define CLKS_PANIC_NAME_MAX 64U - -#define CLKS_PANIC_PS2_DATA_PORT 0x60U -#define CLKS_PANIC_PS2_STATUS_PORT 0x64U -#define CLKS_PANIC_PS2_STATUS_OBF 0x01U -#define CLKS_PANIC_SC_SPACE_MAKE 0x39U -#define CLKS_PANIC_SC_SPACE_BREAK 0xB9U -#define CLKS_PANIC_SC_EXT_PREFIX 0xE0U - -struct clks_panic_console { - u32 cols; - u32 rows; - u32 row; - u32 col; - u32 cell_w; - u32 cell_h; -}; - -static clks_bool clks_panic_active = CLKS_FALSE; -static clks_bool clks_panic_symbols_checked = CLKS_FALSE; -static const char *clks_panic_symbols_data = CLKS_NULL; -static u64 clks_panic_symbols_size = 0ULL; - -enum clks_panic_screen_kind { - CLKS_PANIC_SCREEN_NONE = 0, - CLKS_PANIC_SCREEN_REASON = 1, - CLKS_PANIC_SCREEN_EXCEPTION = 2 -}; - -struct clks_panic_screen_snapshot { - enum clks_panic_screen_kind kind; - char reason[CLKS_PANIC_REASON_MAX]; - char name[CLKS_PANIC_NAME_MAX]; - u64 vector; - u64 error_code; - u64 rip; - u64 rbp; - u64 rsp; - clks_bool has_reason; - clks_bool has_name; -}; - -static struct clks_panic_screen_snapshot clks_panic_screen = { - CLKS_PANIC_SCREEN_NONE, {0}, {0}, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, CLKS_FALSE, CLKS_FALSE}; - -static inline void clks_panic_disable_interrupts(void) { -#if defined(CLKS_ARCH_X86_64) - __asm__ volatile("cli"); -#elif defined(CLKS_ARCH_AARCH64) - __asm__ volatile("msr daifset, #0xf"); -#endif -} - -#if defined(CLKS_ARCH_X86_64) -static inline u8 clks_panic_inb(u16 port) { - u8 value; - - __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); - return value; -} - -static clks_bool clks_panic_ps2_has_output(void) { - return ((clks_panic_inb(CLKS_PANIC_PS2_STATUS_PORT) & CLKS_PANIC_PS2_STATUS_OBF) != 0U) ? CLKS_TRUE : CLKS_FALSE; -} -#endif - -static clks_bool clks_panic_poll_space_press(clks_bool *space_down) { -#if defined(CLKS_ARCH_X86_64) - clks_bool pressed = CLKS_FALSE; - - if (space_down == CLKS_NULL) { - return CLKS_FALSE; - } - - while (clks_panic_ps2_has_output() == CLKS_TRUE) { - u8 scancode = clks_panic_inb(CLKS_PANIC_PS2_DATA_PORT); - - if (scancode == CLKS_PANIC_SC_EXT_PREFIX) { - continue; - } - - if (scancode == CLKS_PANIC_SC_SPACE_BREAK) { - *space_down = CLKS_FALSE; - continue; - } - - if (scancode == CLKS_PANIC_SC_SPACE_MAKE) { - if (*space_down == CLKS_FALSE) { - *space_down = CLKS_TRUE; - pressed = CLKS_TRUE; - } - continue; - } - } - - return pressed; -#else - (void)space_down; - return CLKS_FALSE; -#endif -} - -static void clks_panic_u64_to_hex(u64 value, char out[19]) { - int nibble; - - out[0] = '0'; - out[1] = 'X'; - - for (nibble = 0; nibble < 16; nibble++) { - u8 current = (u8)((value >> ((15 - nibble) * 4)) & 0x0FULL); - out[2 + nibble] = (current < 10U) ? (char)('0' + current) : (char)('A' + (current - 10U)); - } - - out[18] = '\0'; -} - -static void clks_panic_u32_to_dec(u32 value, char *out, usize out_size) { - char tmp[11]; - usize len = 0U; - usize i; - - if (out == CLKS_NULL || out_size == 0U) { - return; - } - - if (value == 0U) { - if (out_size >= 2U) { - out[0] = '0'; - out[1] = '\0'; - } else { - out[0] = '\0'; - } - return; - } - - while (value != 0U && len < sizeof(tmp)) { - tmp[len++] = (char)('0' + (value % 10U)); - value /= 10U; - } - - if (len + 1U > out_size) { - len = out_size - 1U; - } - - for (i = 0U; i < len; i++) { - out[i] = tmp[len - 1U - i]; - } - - out[len] = '\0'; -} - -static clks_bool clks_panic_console_init(struct clks_panic_console *console) { - struct clks_framebuffer_info info; - - if (console == CLKS_NULL || clks_fb_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - info = clks_fb_info(); - - console->cell_w = clks_fb_cell_width(); - console->cell_h = clks_fb_cell_height(); - - if (console->cell_w == 0U) { - console->cell_w = 8U; - } - - if (console->cell_h == 0U) { - console->cell_h = 8U; - } - - console->cols = info.width / console->cell_w; - console->rows = info.height / console->cell_h; - console->row = 0U; - console->col = 0U; - - if (console->cols == 0U || console->rows == 0U) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static void clks_panic_console_newline(struct clks_panic_console *console) { - if (console == CLKS_NULL) { - return; - } - - console->col = 0U; - - if (console->row + 1U < console->rows) { - console->row++; - } -} - -static void clks_panic_console_put_char(struct clks_panic_console *console, char ch) { - u32 x; - u32 y; - - if (console == CLKS_NULL) { - return; - } - - if (ch == '\n') { - clks_panic_console_newline(console); - return; - } - - if (ch == '\r') { - console->col = 0U; - return; - } - - if (console->row >= console->rows || console->col >= console->cols) { - return; - } - - x = console->col * console->cell_w; - y = console->row * console->cell_h; - clks_fb_draw_char(x, y, ch, CLKS_PANIC_FG, CLKS_PANIC_BG); - - console->col++; - - if (console->col >= console->cols) { - clks_panic_console_newline(console); - } -} - -static void clks_panic_console_write_n(struct clks_panic_console *console, const char *text, usize len) { - usize i = 0U; - - if (console == CLKS_NULL || text == CLKS_NULL) { - return; - } - - while (i < len) { - clks_panic_console_put_char(console, text[i]); - i++; - } -} - -static void clks_panic_console_write(struct clks_panic_console *console, const char *text) { - if (console == CLKS_NULL || text == CLKS_NULL) { - return; - } - - clks_panic_console_write_n(console, text, clks_strlen(text)); -} - -static void clks_panic_serial_write_n(const char *text, usize len) { - usize i = 0U; - - if (text == CLKS_NULL) { - return; - } - - while (i < len) { - clks_serial_write_char(text[i]); - i++; - } -} - -static void clks_panic_serial_write_line(const char *line) { - if (line == CLKS_NULL) { - return; - } - - clks_serial_write(line); - clks_serial_write("\n"); -} - -static clks_bool clks_panic_is_hex(char ch) { - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -static u8 clks_panic_hex_value(char ch) { - if (ch >= '0' && ch <= '9') { - return (u8)(ch - '0'); - } - - if (ch >= 'a' && ch <= 'f') { - return (u8)(10 + (ch - 'a')); - } - - return (u8)(10 + (ch - 'A')); -} - -static clks_bool clks_panic_parse_symbol_line(const char *line, usize len, u64 *out_addr, const char **out_name, - usize *out_name_len, const char **out_source, usize *out_source_len) { - usize i = 0U; - u64 addr = 0ULL; - u32 digits = 0U; - usize name_start; - usize name_end; - usize source_start; - usize source_end; - - if (line == CLKS_NULL || out_addr == CLKS_NULL || out_name == CLKS_NULL || out_name_len == CLKS_NULL || - out_source == CLKS_NULL || out_source_len == CLKS_NULL) { - return CLKS_FALSE; - } - - if (len == 0U) { - return CLKS_FALSE; - } - - if (len >= 2U && line[0] == '0' && (line[1] == 'X' || line[1] == 'x')) { - i = 2U; - } - - while (i < len && clks_panic_is_hex(line[i]) == CLKS_TRUE) { - addr = (addr << 4) | (u64)clks_panic_hex_value(line[i]); - digits++; - i++; - } - - if (digits == 0U) { - return CLKS_FALSE; - } - - while (i < len && (line[i] == ' ' || line[i] == '\t')) { - i++; - } - - if (i >= len) { - return CLKS_FALSE; - } - - name_start = i; - - while (i < len && line[i] != ' ' && line[i] != '\t' && line[i] != '\r') { - i++; - } - - name_end = i; - - if (name_end <= name_start) { - return CLKS_FALSE; - } - - while (i < len && (line[i] == ' ' || line[i] == '\t')) { - i++; - } - - source_start = i; - source_end = len; - - while (source_end > source_start && - (line[source_end - 1U] == ' ' || line[source_end - 1U] == '\t' || line[source_end - 1U] == '\r')) { - source_end--; - } - - *out_addr = addr; - *out_name = &line[name_start]; - *out_name_len = name_end - name_start; - *out_source = (source_end > source_start) ? &line[source_start] : CLKS_NULL; - *out_source_len = (source_end > source_start) ? (source_end - source_start) : 0U; - return CLKS_TRUE; -} - -static clks_bool clks_panic_symbols_ready(void) { - u64 size = 0ULL; - const void *data; - - if (clks_panic_symbols_checked == CLKS_TRUE) { - return (clks_panic_symbols_data != CLKS_NULL && clks_panic_symbols_size > 0ULL) ? CLKS_TRUE : CLKS_FALSE; - } - - clks_panic_symbols_checked = CLKS_TRUE; - - if (clks_fs_is_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - data = clks_fs_read_all(CLKS_PANIC_SYMBOL_FILE, &size); - - if (data == CLKS_NULL || size == 0ULL) { - return CLKS_FALSE; - } - - clks_panic_symbols_data = (const char *)data; - clks_panic_symbols_size = size; - return CLKS_TRUE; -} - -static clks_bool clks_panic_lookup_symbol(u64 addr, const char **out_name, usize *out_name_len, u64 *out_base, - const char **out_source, usize *out_source_len) { - const char *data; - const char *end; - const char *line; - const char *best_name = CLKS_NULL; - const char *best_source = CLKS_NULL; - usize best_len = 0U; - usize best_source_len = 0U; - u64 best_addr = 0ULL; - clks_bool found = CLKS_FALSE; - - if (out_name == CLKS_NULL || out_name_len == CLKS_NULL || out_base == CLKS_NULL || out_source == CLKS_NULL || - out_source_len == CLKS_NULL) { - return CLKS_FALSE; - } - - *out_name = CLKS_NULL; - *out_name_len = 0U; - *out_base = 0ULL; - *out_source = CLKS_NULL; - *out_source_len = 0U; - - if (clks_panic_symbols_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - data = clks_panic_symbols_data; - end = clks_panic_symbols_data + clks_panic_symbols_size; - - while (data < end) { - u64 line_addr; - const char *line_name; - usize line_name_len; - const char *line_source; - usize line_source_len; - usize line_len = 0U; - - line = data; - - while (data < end && *data != '\n') { - data++; - line_len++; - } - - if (data < end && *data == '\n') { - data++; - } - - if (clks_panic_parse_symbol_line(line, line_len, &line_addr, &line_name, &line_name_len, &line_source, - &line_source_len) == CLKS_FALSE) { - continue; - } - - if (line_addr <= addr && (found == CLKS_FALSE || line_addr >= best_addr)) { - best_addr = line_addr; - best_name = line_name; - best_len = line_name_len; - best_source = line_source; - best_source_len = line_source_len; - found = CLKS_TRUE; - } - } - - if (found == CLKS_FALSE) { - return CLKS_FALSE; - } - - *out_name = best_name; - *out_name_len = best_len; - *out_base = best_addr; - *out_source = best_source; - *out_source_len = best_source_len; - return CLKS_TRUE; -} - -static void clks_panic_emit_bt_entry(struct clks_panic_console *console, u32 index, u64 rip, clks_bool serial_enabled) { - char index_dec[12]; - char rip_hex[19]; - const char *sym_name = CLKS_NULL; - const char *sym_source = CLKS_NULL; - usize sym_name_len = 0U; - usize sym_source_len = 0U; - u64 sym_base = 0ULL; - clks_bool has_symbol; - - clks_panic_u32_to_dec(index, index_dec, sizeof(index_dec)); - clks_panic_u64_to_hex(rip, rip_hex); - has_symbol = clks_panic_lookup_symbol(rip, &sym_name, &sym_name_len, &sym_base, &sym_source, &sym_source_len); - - if (serial_enabled == CLKS_TRUE) { - clks_serial_write("[PANIC][BT] #"); - clks_serial_write(index_dec); - clks_serial_write(" "); - clks_serial_write(rip_hex); - - if (has_symbol == CLKS_TRUE) { - char off_hex[19]; - u64 off = rip - sym_base; - - clks_panic_u64_to_hex(off, off_hex); - clks_serial_write(" "); - clks_panic_serial_write_n(sym_name, sym_name_len); - clks_serial_write("+"); - clks_serial_write(off_hex); - - if (sym_source != CLKS_NULL && sym_source_len > 0U) { - clks_serial_write(" @ "); - clks_panic_serial_write_n(sym_source, sym_source_len); - } - } - - clks_serial_write("\n"); - } - - if (console == CLKS_NULL) { - return; - } - - clks_panic_console_write(console, "BT#"); - clks_panic_console_write(console, index_dec); - clks_panic_console_write(console, " "); - clks_panic_console_write(console, rip_hex); - - if (has_symbol == CLKS_TRUE) { - char off_hex[19]; - u64 off = rip - sym_base; - - clks_panic_u64_to_hex(off, off_hex); - clks_panic_console_write(console, " "); - clks_panic_console_write_n(console, sym_name, sym_name_len); - clks_panic_console_write(console, "+"); - clks_panic_console_write(console, off_hex); - - if (sym_source != CLKS_NULL && sym_source_len > 0U) { - clks_panic_console_write(console, " @ "); - clks_panic_console_write_n(console, sym_source, sym_source_len); - } - } - - clks_panic_console_write(console, "\n"); -} - -static clks_bool clks_panic_stack_ptr_valid(u64 ptr, u64 stack_low, u64 stack_high) { - if ((ptr & 0x7ULL) != 0ULL) { - return CLKS_FALSE; - } - - if (ptr < stack_low || ptr + 16ULL > stack_high) { - return CLKS_FALSE; - } - - if (ptr < CLKS_PANIC_KERNEL_ADDR_BASE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static void clks_panic_emit_backtrace(struct clks_panic_console *console, u64 rip, u64 rbp, u64 rsp, - clks_bool serial_enabled) { - u64 current_rbp; - u64 stack_low; - u64 stack_high; - u32 frame = 0U; - - if (rip == 0ULL) { - return; - } - - if (serial_enabled == CLKS_TRUE) { - clks_panic_serial_write_line("[PANIC][BT] BEGIN"); - } - - if (console != CLKS_NULL) { - clks_panic_console_write(console, "\nBACKTRACE:\n"); - } - - clks_panic_emit_bt_entry(console, frame, rip, serial_enabled); - frame++; - - if (rbp == 0ULL || rsp == 0ULL || frame >= CLKS_PANIC_BACKTRACE_MAX) { - if (serial_enabled == CLKS_TRUE) { - clks_panic_serial_write_line("[PANIC][BT] END"); - } - return; - } - - stack_low = rsp; - stack_high = rsp + CLKS_PANIC_STACK_WINDOW_BYTES; - - if (stack_high <= stack_low) { - if (serial_enabled == CLKS_TRUE) { - clks_panic_serial_write_line("[PANIC][BT] END"); - } - return; - } - - current_rbp = rbp; - - while (frame < CLKS_PANIC_BACKTRACE_MAX) { - const u64 *frame_ptr; - u64 next_rbp; - u64 ret_rip; - - if (clks_panic_stack_ptr_valid(current_rbp, stack_low, stack_high) == CLKS_FALSE) { - break; - } - - frame_ptr = (const u64 *)(usize)current_rbp; - next_rbp = frame_ptr[0]; - ret_rip = frame_ptr[1]; - - if (ret_rip == 0ULL) { - break; - } - - clks_panic_emit_bt_entry(console, frame, ret_rip, serial_enabled); - frame++; - - if (next_rbp <= current_rbp) { - break; - } - - current_rbp = next_rbp; - } - - if (serial_enabled == CLKS_TRUE) { - clks_panic_serial_write_line("[PANIC][BT] END"); - } -} - -static void clks_panic_capture_context(u64 *out_rip, u64 *out_rbp, u64 *out_rsp) { - if (out_rip != CLKS_NULL) { - *out_rip = 0ULL; - } - - if (out_rbp != CLKS_NULL) { - *out_rbp = 0ULL; - } - - if (out_rsp != CLKS_NULL) { - *out_rsp = 0ULL; - } - -#if defined(CLKS_ARCH_X86_64) - if (out_rbp != CLKS_NULL) { - __asm__ volatile("mov %%rbp, %0" : "=r"(*out_rbp)); - } - - if (out_rsp != CLKS_NULL) { - __asm__ volatile("mov %%rsp, %0" : "=r"(*out_rsp)); - } - - if (out_rip != CLKS_NULL) { - *out_rip = (u64)(usize)__builtin_return_address(0); - } -#endif -} - -static void clks_panic_copy_text(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || dst_size == 0U) { - return; - } - - if (src == CLKS_NULL) { - dst[0] = '\0'; - return; - } - - while (i + 1U < dst_size && src[i] != '\0') { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static void clks_panic_snapshot_reason(const char *reason, u64 rip, u64 rbp, u64 rsp) { - clks_panic_screen.kind = CLKS_PANIC_SCREEN_REASON; - clks_panic_screen.vector = 0ULL; - clks_panic_screen.error_code = 0ULL; - clks_panic_screen.rip = rip; - clks_panic_screen.rbp = rbp; - clks_panic_screen.rsp = rsp; - clks_panic_screen.has_name = CLKS_FALSE; - clks_panic_screen.name[0] = '\0'; - - if (reason != CLKS_NULL && reason[0] != '\0') { - clks_panic_copy_text(clks_panic_screen.reason, sizeof(clks_panic_screen.reason), reason); - clks_panic_screen.has_reason = CLKS_TRUE; - } else { - clks_panic_screen.reason[0] = '\0'; - clks_panic_screen.has_reason = CLKS_FALSE; - } -} - -static void clks_panic_snapshot_exception(const char *name, u64 vector, u64 error_code, u64 rip, u64 rbp, u64 rsp) { - clks_panic_screen.kind = CLKS_PANIC_SCREEN_EXCEPTION; - clks_panic_screen.vector = vector; - clks_panic_screen.error_code = error_code; - clks_panic_screen.rip = rip; - clks_panic_screen.rbp = rbp; - clks_panic_screen.rsp = rsp; - clks_panic_screen.has_reason = CLKS_FALSE; - clks_panic_screen.reason[0] = '\0'; - - if (name != CLKS_NULL && name[0] != '\0') { - clks_panic_copy_text(clks_panic_screen.name, sizeof(clks_panic_screen.name), name); - clks_panic_screen.has_name = CLKS_TRUE; - } else { - clks_panic_screen.name[0] = '\0'; - clks_panic_screen.has_name = CLKS_FALSE; - } -} - -static void clks_panic_render_snapshot_console(clks_bool serial_backtrace) { - struct clks_panic_console console; - char hex_buf[19]; - - if (clks_panic_console_init(&console) == CLKS_TRUE) { - clks_fb_clear(CLKS_PANIC_BG); - clks_panic_console_write(&console, "CLeonOS KERNEL PANIC\n"); - clks_panic_console_write(&console, "====================\n\n"); - - if (clks_panic_screen.kind == CLKS_PANIC_SCREEN_EXCEPTION) { - clks_panic_console_write(&console, "TYPE: CPU EXCEPTION\n"); - - if (clks_panic_screen.has_name == CLKS_TRUE) { - clks_panic_console_write(&console, "NAME: "); - clks_panic_console_write(&console, clks_panic_screen.name); - clks_panic_console_write(&console, "\n"); - } - - clks_panic_u64_to_hex(clks_panic_screen.vector, hex_buf); - clks_panic_console_write(&console, "VECTOR: "); - clks_panic_console_write(&console, hex_buf); - clks_panic_console_write(&console, "\n"); - - clks_panic_u64_to_hex(clks_panic_screen.error_code, hex_buf); - clks_panic_console_write(&console, "ERROR: "); - clks_panic_console_write(&console, hex_buf); - clks_panic_console_write(&console, "\n"); - - clks_panic_u64_to_hex(clks_panic_screen.rip, hex_buf); - clks_panic_console_write(&console, "RIP: "); - clks_panic_console_write(&console, hex_buf); - clks_panic_console_write(&console, "\n"); - } else if (clks_panic_screen.has_reason == CLKS_TRUE) { - clks_panic_console_write(&console, "REASON: "); - clks_panic_console_write(&console, clks_panic_screen.reason); - clks_panic_console_write(&console, "\n"); - } - - clks_panic_emit_backtrace(&console, clks_panic_screen.rip, clks_panic_screen.rbp, clks_panic_screen.rsp, - serial_backtrace); - clks_panic_console_write(&console, "\nSystem halted. Please reboot the computer.\n"); - clks_panic_console_write(&console, CLKS_PANIC_QR_HINT); - } else { - clks_panic_emit_backtrace(CLKS_NULL, clks_panic_screen.rip, clks_panic_screen.rbp, clks_panic_screen.rsp, - serial_backtrace); - } -} - -static CLKS_NORETURN void clks_panic_halt_loop(void) { - clks_bool space_down = CLKS_FALSE; - clks_bool qr_shown = CLKS_FALSE; - - for (;;) { - if (clks_panic_poll_space_press(&space_down) == CLKS_TRUE) { - if (qr_shown == CLKS_FALSE) { - if (clks_panic_qr_show() == CLKS_TRUE) { - qr_shown = CLKS_TRUE; - clks_panic_serial_write_line("[PANIC][QR] DISPLAYED"); - } else { - clks_panic_serial_write_line("[PANIC][QR] PREPARE/SHOW FAILED"); - } - } else { - clks_panic_render_snapshot_console(CLKS_FALSE); - qr_shown = CLKS_FALSE; - clks_panic_serial_write_line("[PANIC][QR] RETURNED TO PANIC PAGE"); - } - } - - clks_cpu_pause(); - } -} - -CLKS_NORETURN void clks_panic(const char *reason) { - u64 rip = 0ULL; - u64 rbp = 0ULL; - u64 rsp = 0ULL; - - clks_panic_disable_interrupts(); - - if (clks_panic_active == CLKS_TRUE) { - clks_panic_halt_loop(); - } - - clks_panic_active = CLKS_TRUE; - clks_panic_capture_context(&rip, &rbp, &rsp); - - clks_panic_serial_write_line("[PANIC] CLeonOS KERNEL PANIC"); - - if (reason != CLKS_NULL) { - clks_panic_serial_write_line(reason); - } - - clks_panic_snapshot_reason(reason, rip, rbp, rsp); - clks_panic_render_snapshot_console(CLKS_TRUE); - - if (clks_panic_qr_prepare() == CLKS_TRUE) { - clks_panic_serial_write_line("[PANIC][QR] READY (PRESS SPACE TO TOGGLE)"); - } else { - clks_panic_serial_write_line("[PANIC][QR] NOT AVAILABLE"); - } - - clks_panic_halt_loop(); -} - -CLKS_NORETURN void clks_panic_exception(const char *name, u64 vector, u64 error_code, u64 rip, u64 rbp, u64 rsp) { - char hex_buf[19]; - - clks_panic_disable_interrupts(); - - if (clks_panic_active == CLKS_TRUE) { - clks_panic_halt_loop(); - } - - clks_panic_active = CLKS_TRUE; - - clks_panic_serial_write_line("[PANIC] CPU EXCEPTION"); - - if (name != CLKS_NULL) { - clks_panic_serial_write_line(name); - } - - clks_panic_u64_to_hex(vector, hex_buf); - clks_panic_serial_write_line(hex_buf); - clks_panic_u64_to_hex(error_code, hex_buf); - clks_panic_serial_write_line(hex_buf); - clks_panic_u64_to_hex(rip, hex_buf); - clks_panic_serial_write_line(hex_buf); - - clks_panic_snapshot_exception(name, vector, error_code, rip, rbp, rsp); - clks_panic_render_snapshot_console(CLKS_TRUE); - - if (clks_panic_qr_prepare() == CLKS_TRUE) { - clks_panic_serial_write_line("[PANIC][QR] READY (PRESS SPACE TO TOGGLE)"); - } else { - clks_panic_serial_write_line("[PANIC][QR] NOT AVAILABLE"); - } - - clks_panic_halt_loop(); -} diff --git a/clks/kernel/core/panic_qr.cpp b/clks/kernel/core/panic_qr.cpp deleted file mode 100644 index c76072e..0000000 --- a/clks/kernel/core/panic_qr.cpp +++ /dev/null @@ -1,395 +0,0 @@ -extern "C" { -#include -#include -#include -#include -#include -#include -} - -#ifndef NDEBUG -#define NDEBUG 1 -#endif - -#define MINIZ_NO_STDIO 1 -#define MINIZ_NO_INFLATE_APIS 1 -#define MINIZ_NO_TIME 1 -#define MINIZ_NO_MALLOC 1 -#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1 -#include "../../third_party/miniz/miniz.h" - -extern "C" { -#include "../../third_party/qrcodegen/qrcodegen.h" -} - -#define CLKS_PANIC_QR_BORDER 4U -#define CLKS_PANIC_QR_MAX_LINES 256U -#define CLKS_PANIC_QR_LINE_MAX 256U -#define CLKS_PANIC_QR_TEXT_MAX ((CLKS_PANIC_QR_MAX_LINES * CLKS_PANIC_QR_LINE_MAX) + CLKS_PANIC_QR_MAX_LINES) -#define CLKS_PANIC_QR_COMP_MAX (CLKS_PANIC_QR_TEXT_MAX + 2048U) -#define CLKS_PANIC_QR_MAX_COMP_BYTES 2953U -#define CLKS_PANIC_QR_DIGITS_MAX (((CLKS_PANIC_QR_MAX_COMP_BYTES / 7U) * 17U) + 17U) -#define CLKS_PANIC_QR_URL_PREFIX "https://panic.archlinux.org/panic_report#?a=cleonos-x86_64&v=cleonos&z=" -#define CLKS_PANIC_QR_URL_PREFIX_LEN ((u64)(sizeof(CLKS_PANIC_QR_URL_PREFIX) - 1U)) - -#define CLKS_PANIC_QR_COLOR_DARK 0x00000000U -#define CLKS_PANIC_QR_COLOR_LIGHT 0x00FFFFFFU - -static char clks_panic_qr_lines[CLKS_PANIC_QR_MAX_LINES][CLKS_PANIC_QR_LINE_MAX]; -static u16 clks_panic_qr_line_len[CLKS_PANIC_QR_MAX_LINES]; - -static char clks_panic_qr_text[CLKS_PANIC_QR_TEXT_MAX]; -static u8 clks_panic_qr_comp[CLKS_PANIC_QR_COMP_MAX]; -static char clks_panic_qr_digits[CLKS_PANIC_QR_DIGITS_MAX]; - -static u8 clks_panic_qr_payload[qrcodegen_BUFFER_LEN_MAX]; -static u8 clks_panic_qr_code[qrcodegen_BUFFER_LEN_MAX]; -static u8 clks_panic_qr_url_seg_buf[qrcodegen_BUFFER_LEN_MAX]; -static u8 clks_panic_qr_num_seg_buf[qrcodegen_BUFFER_LEN_MAX]; - -static clks_bool clks_panic_qr_ready = CLKS_FALSE; -static clks_bool clks_panic_qr_attempted = CLKS_FALSE; -static u64 clks_panic_qr_total_lines_cache = 0ULL; -static u64 clks_panic_qr_dropped_lines_cache = 0ULL; -static u64 clks_panic_qr_comp_size_cache = 0ULL; -static u64 clks_panic_qr_digits_size_cache = 0ULL; - -static u64 clks_panic_qr_collect_lines(void) { - u64 journal_count = clks_log_journal_count(); - u64 i; - u64 line_count = 0ULL; - - if (journal_count > CLKS_PANIC_QR_MAX_LINES) { - journal_count = CLKS_PANIC_QR_MAX_LINES; - } - - for (i = 0ULL; i < journal_count; i++) { - if (clks_log_journal_read(i, clks_panic_qr_lines[line_count], CLKS_PANIC_QR_LINE_MAX) == CLKS_TRUE) { - clks_panic_qr_line_len[line_count] = (u16)clks_strlen(clks_panic_qr_lines[line_count]); - line_count++; - } - } - - return line_count; -} - -static u64 clks_panic_qr_build_text(u64 line_start, u64 line_count) { - u64 i; - u64 out_len = 0ULL; - - if (line_start >= line_count) { - return 0ULL; - } - - for (i = line_start; i < line_count; i++) { - u64 len = (u64)clks_panic_qr_line_len[i]; - - if (out_len + len + 1ULL > CLKS_PANIC_QR_TEXT_MAX) { - break; - } - - if (len > 0ULL) { - clks_memcpy(&clks_panic_qr_text[out_len], clks_panic_qr_lines[i], (usize)len); - out_len += len; - } - - clks_panic_qr_text[out_len++] = '\n'; - } - - return out_len; -} - -static clks_bool clks_panic_qr_compress(const char *src, u64 src_len, u8 *dst, u64 dst_cap, u64 *out_len) { - tdefl_compressor comp; - tdefl_status init_status; - tdefl_status comp_status; - size_t in_size; - size_t out_size; - mz_uint flags; - - if (src == CLKS_NULL || dst == CLKS_NULL || out_len == CLKS_NULL || src_len == 0ULL || dst_cap == 0ULL) { - return CLKS_FALSE; - } - - flags = tdefl_create_comp_flags_from_zip_params(6, 12, MZ_DEFAULT_STRATEGY); - init_status = tdefl_init(&comp, (tdefl_put_buf_func_ptr)0, (void *)0, (int)flags); - if (init_status < 0) { - return CLKS_FALSE; - } - - in_size = (size_t)src_len; - out_size = (size_t)dst_cap; - comp_status = tdefl_compress(&comp, src, &in_size, dst, &out_size, TDEFL_FINISH); - - if (comp_status != TDEFL_STATUS_DONE || in_size != (size_t)src_len) { - return CLKS_FALSE; - } - - *out_len = (u64)out_size; - return CLKS_TRUE; -} - -static void clks_panic_qr_u64_to_dec_padded(u64 value, u32 digits, char *out) { - u32 i; - - if (out == CLKS_NULL || digits == 0U) { - return; - } - - for (i = 0U; i < digits; i++) { - out[digits - 1U - i] = (char)('0' + (value % 10ULL)); - value /= 10ULL; - } -} - -static u64 clks_panic_qr_binary_to_decimal(const u8 *src, u64 src_len, char *dst, u64 dst_cap) { - static const u8 tail_digits[7] = {0U, 3U, 5U, 8U, 10U, 13U, 15U}; - u64 in_pos = 0ULL; - u64 out_pos = 0ULL; - - if (src == CLKS_NULL || dst == CLKS_NULL || dst_cap == 0ULL) { - return 0ULL; - } - - while (in_pos + 7ULL <= src_len) { - u64 value = 0ULL; - u32 i; - - if (out_pos + 17ULL + 1ULL > dst_cap) { - return 0ULL; - } - - for (i = 0U; i < 7U; i++) { - value |= ((u64)src[in_pos + (u64)i]) << (i * 8U); - } - - clks_panic_qr_u64_to_dec_padded(value, 17U, &dst[out_pos]); - out_pos += 17ULL; - in_pos += 7ULL; - } - - if (in_pos < src_len) { - u64 value = 0ULL; - u64 rem = src_len - in_pos; - u32 digits = tail_digits[rem]; - u32 i; - - if (digits == 0U || out_pos + (u64)digits + 1ULL > dst_cap) { - return 0ULL; - } - - for (i = 0U; i < (u32)rem; i++) { - value |= ((u64)src[in_pos + (u64)i]) << (i * 8U); - } - - clks_panic_qr_u64_to_dec_padded(value, digits, &dst[out_pos]); - out_pos += (u64)digits; - } - - dst[out_pos] = '\0'; - return out_pos; -} - -static clks_bool clks_panic_qr_encode_payload(const u8 *payload, u64 payload_size, u64 *digit_len_out) { - struct qrcodegen_Segment segs[2]; - u64 digit_len; - size_t url_seg_buf_len; - size_t num_seg_buf_len; - - if (payload == CLKS_NULL || payload_size == 0ULL || payload_size > CLKS_PANIC_QR_MAX_COMP_BYTES) { - return CLKS_FALSE; - } - - digit_len = clks_panic_qr_binary_to_decimal(payload, payload_size, clks_panic_qr_digits, CLKS_PANIC_QR_DIGITS_MAX); - if (digit_len == 0ULL) { - return CLKS_FALSE; - } - - url_seg_buf_len = qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, (size_t)CLKS_PANIC_QR_URL_PREFIX_LEN); - num_seg_buf_len = qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, (size_t)digit_len); - if (url_seg_buf_len == (size_t)-1 || num_seg_buf_len == (size_t)-1 || url_seg_buf_len > qrcodegen_BUFFER_LEN_MAX || - num_seg_buf_len > qrcodegen_BUFFER_LEN_MAX) { - return CLKS_FALSE; - } - - segs[0] = qrcodegen_makeBytes((const u8 *)CLKS_PANIC_QR_URL_PREFIX, (size_t)CLKS_PANIC_QR_URL_PREFIX_LEN, - clks_panic_qr_url_seg_buf); - segs[1] = qrcodegen_makeNumeric(clks_panic_qr_digits, clks_panic_qr_num_seg_buf); - - if (qrcodegen_encodeSegmentsAdvanced(segs, 2U, qrcodegen_Ecc_LOW, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, - qrcodegen_Mask_AUTO, true, clks_panic_qr_payload, - clks_panic_qr_code) == false) { - return CLKS_FALSE; - } - - if (digit_len_out != CLKS_NULL) { - *digit_len_out = digit_len; - } - - return CLKS_TRUE; -} - -extern "C" clks_bool clks_panic_qr_prepare(void) { - u64 line_count; - u64 start; - - if (clks_panic_qr_attempted == CLKS_TRUE) { - return clks_panic_qr_ready; - } - - clks_panic_qr_attempted = CLKS_TRUE; - clks_panic_qr_ready = CLKS_FALSE; - clks_panic_qr_total_lines_cache = 0ULL; - clks_panic_qr_dropped_lines_cache = 0ULL; - clks_panic_qr_comp_size_cache = 0ULL; - clks_panic_qr_digits_size_cache = 0ULL; - - line_count = clks_panic_qr_collect_lines(); - clks_panic_qr_total_lines_cache = line_count; - - if (line_count == 0ULL) { - return CLKS_FALSE; - } - - for (start = 0ULL; start < line_count; start++) { - u64 text_len = clks_panic_qr_build_text(start, line_count); - u64 comp_len = 0ULL; - u64 digit_len = 0ULL; - - if (text_len == 0ULL) { - continue; - } - - if (clks_panic_qr_compress(clks_panic_qr_text, text_len, clks_panic_qr_comp, CLKS_PANIC_QR_COMP_MAX, - &comp_len) == CLKS_FALSE) { - continue; - } - - if (comp_len > CLKS_PANIC_QR_MAX_COMP_BYTES) { - continue; - } - - if (clks_panic_qr_encode_payload(clks_panic_qr_comp, comp_len, &digit_len) == CLKS_FALSE) { - continue; - } - - clks_panic_qr_dropped_lines_cache = start; - clks_panic_qr_comp_size_cache = comp_len; - clks_panic_qr_digits_size_cache = digit_len; - clks_panic_qr_ready = CLKS_TRUE; - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -extern "C" clks_bool clks_panic_qr_show(void) { - struct clks_framebuffer_info fb_info; - int qr_size; - u32 modules; - u32 scale; - u32 draw_w; - u32 draw_h; - u32 base_x; - u32 base_y; - u32 y; - u32 x; - - if (clks_panic_qr_ready == CLKS_FALSE) { - if (clks_panic_qr_prepare() == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - if (clks_fb_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - qr_size = qrcodegen_getSize(clks_panic_qr_code); - if (qr_size <= 0) { - return CLKS_FALSE; - } - - fb_info = clks_fb_info(); - modules = (u32)qr_size + (CLKS_PANIC_QR_BORDER * 2U); - if (modules == 0U) { - return CLKS_FALSE; - } - - scale = fb_info.width / modules; - if ((fb_info.height / modules) < scale) { - scale = fb_info.height / modules; - } - - if (scale == 0U) { - return CLKS_FALSE; - } - - draw_w = modules * scale; - draw_h = modules * scale; - base_x = (fb_info.width > draw_w) ? ((fb_info.width - draw_w) / 2U) : 0U; - base_y = (fb_info.height > draw_h) ? ((fb_info.height - draw_h) / 2U) : 0U; - - clks_fb_clear(CLKS_PANIC_QR_COLOR_LIGHT); - - for (y = 0U; y < modules; y++) { - for (x = 0U; x < modules; x++) { - int qx = (int)x - (int)CLKS_PANIC_QR_BORDER; - int qy = (int)y - (int)CLKS_PANIC_QR_BORDER; - clks_bool dark = CLKS_FALSE; - - if (qx >= 0 && qy >= 0 && qx < qr_size && qy < qr_size) { - dark = qrcodegen_getModule(clks_panic_qr_code, qx, qy) ? CLKS_TRUE : CLKS_FALSE; - } - - if (dark == CLKS_TRUE) { - clks_fb_fill_rect(base_x + (x * scale), base_y + (y * scale), scale, scale, CLKS_PANIC_QR_COLOR_DARK); - } - } - } - - clks_serial_write("[PANIC][QR] LINES:"); - { - char hex_buf[19]; - clks_serial_write(" TOTAL="); - clks_memset(hex_buf, 0, sizeof(hex_buf)); - hex_buf[0] = '0'; - hex_buf[1] = 'X'; - for (int i = 0; i < 16; i++) { - u8 n = (u8)((clks_panic_qr_total_lines_cache >> ((15 - i) * 4)) & 0x0FULL); - hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U)); - } - clks_serial_write(hex_buf); - - clks_serial_write(" DROPPED="); - for (int i = 0; i < 16; i++) { - u8 n = (u8)((clks_panic_qr_dropped_lines_cache >> ((15 - i) * 4)) & 0x0FULL); - hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U)); - } - clks_serial_write(hex_buf); - - clks_serial_write(" COMP_BYTES="); - for (int i = 0; i < 16; i++) { - u8 n = (u8)((clks_panic_qr_comp_size_cache >> ((15 - i) * 4)) & 0x0FULL); - hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U)); - } - clks_serial_write(hex_buf); - clks_serial_write(" DIGITS="); - for (int i = 0; i < 16; i++) { - u8 n = (u8)((clks_panic_qr_digits_size_cache >> ((15 - i) * 4)) & 0x0FULL); - hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U)); - } - clks_serial_write(hex_buf); - clks_serial_write("\n"); - } - - return CLKS_TRUE; -} - -extern "C" u64 clks_panic_qr_total_lines(void) { - return clks_panic_qr_total_lines_cache; -} - -extern "C" u64 clks_panic_qr_dropped_lines(void) { - return clks_panic_qr_dropped_lines_cache; -} diff --git a/clks/kernel/core/scheduler.c b/clks/kernel/core/scheduler.c deleted file mode 100644 index a892341..0000000 --- a/clks/kernel/core/scheduler.c +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include -#include - -#define CLKS_SCHED_MAX_TASKS 16U -#define CLKS_SCHED_MIN_SLICE 1U - -static struct clks_task_descriptor clks_tasks[CLKS_SCHED_MAX_TASKS]; -static u32 clks_task_count = 0; -static u32 clks_current_task = 0; -static u64 clks_total_timer_ticks = 0; -static u64 clks_context_switch_count = 0; -static clks_bool clks_dispatch_active = CLKS_FALSE; - -static void clks_sched_copy_name(char *dst, const char *src) { - u32 i = 0; - - while (i < (CLKS_TASK_NAME_MAX - 1U) && src[i] != '\0') { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static u32 clks_sched_next_ready_task(u32 from) { - u32 i; - - for (i = 1U; i <= clks_task_count; i++) { - u32 idx = (from + i) % clks_task_count; - - if (clks_tasks[idx].state == CLKS_TASK_READY || clks_tasks[idx].state == CLKS_TASK_RUNNING) { - return idx; - } - } - - return from; -} - -void clks_scheduler_init(void) { - clks_memset(clks_tasks, 0, sizeof(clks_tasks)); - clks_task_count = 0; - clks_current_task = 0; - clks_total_timer_ticks = 0; - clks_context_switch_count = 0; - clks_dispatch_active = CLKS_FALSE; - - clks_scheduler_add_kernel_task_ex("idle", 1U, CLKS_NULL); - - clks_tasks[0].state = CLKS_TASK_RUNNING; - clks_tasks[0].remaining_ticks = clks_tasks[0].time_slice_ticks; - - clks_log(CLKS_LOG_INFO, "SCHED", "ROUND-ROBIN ONLINE"); -} - -clks_bool clks_scheduler_add_kernel_task_ex(const char *name, u32 time_slice_ticks, clks_task_entry_fn entry) { - struct clks_task_descriptor *task; - - if (name == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_task_count >= CLKS_SCHED_MAX_TASKS) { - return CLKS_FALSE; - } - - if (time_slice_ticks < CLKS_SCHED_MIN_SLICE) { - time_slice_ticks = CLKS_SCHED_MIN_SLICE; - } - - task = &clks_tasks[clks_task_count]; - task->id = clks_task_count; - clks_sched_copy_name(task->name, name); - task->state = CLKS_TASK_READY; - task->time_slice_ticks = time_slice_ticks; - task->remaining_ticks = time_slice_ticks; - task->total_ticks = 0ULL; - task->switch_count = 0ULL; - task->run_count = 0ULL; - task->last_run_tick = 0ULL; - task->entry = entry; - - clks_task_count++; - return CLKS_TRUE; -} - -clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks) { - return clks_scheduler_add_kernel_task_ex(name, time_slice_ticks, CLKS_NULL); -} - -void clks_scheduler_dispatch_current(u64 tick) { - struct clks_task_descriptor *current; - - if (clks_task_count == 0U) { - return; - } - - if (clks_dispatch_active == CLKS_TRUE) { - return; - } - - current = &clks_tasks[clks_current_task]; - - if (current->state != CLKS_TASK_RUNNING && current->state != CLKS_TASK_READY) { - return; - } - - current->state = CLKS_TASK_RUNNING; - current->run_count++; - current->last_run_tick = tick; - - if (current->entry != CLKS_NULL) { - clks_dispatch_active = CLKS_TRUE; - current->entry(tick); - clks_dispatch_active = CLKS_FALSE; - } -} - -void clks_scheduler_on_timer_tick(u64 tick) { - struct clks_task_descriptor *current; - - if (clks_task_count == 0U) { - return; - } - - clks_total_timer_ticks = tick; - - if (clks_dispatch_active == CLKS_TRUE) { - return; - } - - current = &clks_tasks[clks_current_task]; - - if (current->state == CLKS_TASK_RUNNING || current->state == CLKS_TASK_READY) { - current->total_ticks++; - - if (current->remaining_ticks > 0U) { - current->remaining_ticks--; - } - } - - if (current->remaining_ticks == 0U) { - u32 next = clks_sched_next_ready_task(clks_current_task); - - current->remaining_ticks = current->time_slice_ticks; - - if (next != clks_current_task) { - if (current->state == CLKS_TASK_RUNNING) { - current->state = CLKS_TASK_READY; - } - - clks_current_task = next; - clks_tasks[clks_current_task].state = CLKS_TASK_RUNNING; - clks_tasks[clks_current_task].switch_count++; - clks_tasks[clks_current_task].remaining_ticks = clks_tasks[clks_current_task].time_slice_ticks; - clks_context_switch_count++; - } - } -} - -struct clks_scheduler_stats clks_scheduler_get_stats(void) { - struct clks_scheduler_stats stats; - - stats.task_count = clks_task_count; - stats.current_task_id = clks_current_task; - stats.total_timer_ticks = clks_total_timer_ticks; - stats.context_switch_count = clks_context_switch_count; - - return stats; -} - -const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id) { - if (task_id >= clks_task_count) { - return CLKS_NULL; - } - - return &clks_tasks[task_id]; -} diff --git a/clks/kernel/core/service.c b/clks/kernel/core/service.c deleted file mode 100644 index fce3c69..0000000 --- a/clks/kernel/core/service.c +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CLKS_SERVICE_MAX 8U - -static struct clks_service_info clks_services[CLKS_SERVICE_MAX]; -static u64 clks_service_used = 0ULL; - -static void clks_service_copy_name(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || dst_size == 0U) { - return; - } - - while (i + 1U < dst_size && src[i] != '\0') { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static i32 clks_service_find_index(u32 service_id) { - u64 i; - - for (i = 0ULL; i < clks_service_used; i++) { - if (clks_services[i].id == service_id) { - return (i32)i; - } - } - - return -1; -} - -static clks_bool clks_service_register(u32 id, const char *name, enum clks_service_state state) { - struct clks_service_info *slot; - - if (clks_service_used >= CLKS_SERVICE_MAX) { - return CLKS_FALSE; - } - - slot = &clks_services[clks_service_used]; - clks_memset(slot, 0, sizeof(*slot)); - - slot->id = id; - clks_service_copy_name(slot->name, sizeof(slot->name), name); - slot->state = state; - slot->heartbeat_count = 0ULL; - slot->last_heartbeat_tick = 0ULL; - - clks_service_used++; - return CLKS_TRUE; -} - -void clks_service_init(void) { - struct clks_heap_stats heap_stats; - - clks_memset(clks_services, 0, sizeof(clks_services)); - clks_service_used = 0ULL; - - heap_stats = clks_heap_get_stats(); - - clks_service_register(CLKS_SERVICE_LOG, "log", CLKS_SERVICE_STATE_READY); - clks_service_register(CLKS_SERVICE_MEM, "memory", - (heap_stats.total_bytes > 0U) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED); - clks_service_register(CLKS_SERVICE_FS, "filesystem", - (clks_fs_is_ready() == CLKS_TRUE) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED); - clks_service_register(CLKS_SERVICE_DRIVER, "driver", - (clks_driver_count() > 0ULL) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED); - clks_service_register(CLKS_SERVICE_SCHED, "scheduler", CLKS_SERVICE_STATE_READY); - clks_service_register(CLKS_SERVICE_KELF, "kelf", - (clks_kelf_count() > 0ULL) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED); - clks_service_register(CLKS_SERVICE_USER, "userland", - (clks_userland_shell_ready() == CLKS_TRUE) ? CLKS_SERVICE_STATE_READY - : CLKS_SERVICE_STATE_DEGRADED); - - clks_log(CLKS_LOG_INFO, "SRV", "KERNEL SERVICES ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "SRV", "COUNT", clks_service_count()); - clks_log_hex(CLKS_LOG_INFO, "SRV", "READY", clks_service_ready_count()); -} - -clks_bool clks_service_heartbeat(u32 service_id, u64 tick) { - i32 idx = clks_service_find_index(service_id); - - if (idx < 0) { - return CLKS_FALSE; - } - - clks_services[(u32)idx].heartbeat_count++; - clks_services[(u32)idx].last_heartbeat_tick = tick; - - if (clks_services[(u32)idx].state == CLKS_SERVICE_STATE_OFFLINE) { - clks_services[(u32)idx].state = CLKS_SERVICE_STATE_READY; - } - - return CLKS_TRUE; -} - -u64 clks_service_count(void) { - return clks_service_used; -} - -u64 clks_service_ready_count(void) { - u64 i; - u64 ready = 0ULL; - - for (i = 0ULL; i < clks_service_used; i++) { - if (clks_services[i].state == CLKS_SERVICE_STATE_READY) { - ready++; - } - } - - return ready; -} - -clks_bool clks_service_get(u32 service_id, struct clks_service_info *out_info) { - i32 idx; - - if (out_info == CLKS_NULL) { - return CLKS_FALSE; - } - - idx = clks_service_find_index(service_id); - - if (idx < 0) { - return CLKS_FALSE; - } - - *out_info = clks_services[(u32)idx]; - return CLKS_TRUE; -} diff --git a/clks/kernel/hal/audio/pcspeaker.c b/clks/kernel/hal/audio/pcspeaker.c deleted file mode 100644 index 90ac465..0000000 --- a/clks/kernel/hal/audio/pcspeaker.c +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include -#include -#include - -#define CLKS_AUDIO_PIT_BASE_HZ 1193182ULL -#define CLKS_AUDIO_FREQ_MIN 20ULL -#define CLKS_AUDIO_FREQ_MAX 20000ULL -#define CLKS_AUDIO_TICKS_MAX 2048ULL - -static clks_bool clks_audio_ready = CLKS_FALSE; -static u64 clks_audio_played_count = 0ULL; - -#if defined(CLKS_ARCH_X86_64) -static inline void clks_audio_outb(u16 port, u8 value) { - __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); -} - -static inline u8 clks_audio_inb(u16 port) { - u8 value; - __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); - return value; -} - -static void clks_audio_program_pc_speaker(u64 hz) { - u64 divisor64 = CLKS_AUDIO_PIT_BASE_HZ / hz; - u16 divisor; - u8 control; - - if (divisor64 == 0ULL) { - divisor64 = 1ULL; - } - - if (divisor64 > 0xFFFFULL) { - divisor64 = 0xFFFFULL; - } - - divisor = (u16)divisor64; - clks_audio_outb(0x43U, 0xB6U); - clks_audio_outb(0x42U, (u8)(divisor & 0xFFU)); - clks_audio_outb(0x42U, (u8)((divisor >> 8) & 0xFFU)); - - control = clks_audio_inb(0x61U); - clks_audio_outb(0x61U, (u8)(control | 0x03U)); -} -#endif - -static u64 clks_audio_clamp_hz(u64 hz) { - if (hz < CLKS_AUDIO_FREQ_MIN) { - return CLKS_AUDIO_FREQ_MIN; - } - - if (hz > CLKS_AUDIO_FREQ_MAX) { - return CLKS_AUDIO_FREQ_MAX; - } - - return hz; -} - -void clks_audio_init(void) { -#if defined(CLKS_ARCH_X86_64) - clks_audio_ready = CLKS_TRUE; - clks_audio_played_count = 0ULL; - clks_audio_stop(); - - clks_log(CLKS_LOG_INFO, "AUDIO", "PC SPEAKER ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "AUDIO", "PIT_BASE_HZ", CLKS_AUDIO_PIT_BASE_HZ); -#else - clks_audio_ready = CLKS_FALSE; - clks_audio_played_count = 0ULL; - clks_log(CLKS_LOG_WARN, "AUDIO", "AUDIO OUTPUT NOT AVAILABLE ON THIS ARCH"); -#endif -} - -clks_bool clks_audio_available(void) { - return clks_audio_ready; -} - -clks_bool clks_audio_play_tone(u64 hz, u64 ticks) { - if (clks_audio_ready == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (ticks == 0ULL) { - return CLKS_TRUE; - } - - if (ticks > CLKS_AUDIO_TICKS_MAX) { - ticks = CLKS_AUDIO_TICKS_MAX; - } - - if (hz == 0ULL) { - clks_audio_stop(); - (void)clks_exec_sleep_ticks(ticks); - return CLKS_TRUE; - } - - hz = clks_audio_clamp_hz(hz); - -#if defined(CLKS_ARCH_X86_64) - clks_audio_program_pc_speaker(hz); - (void)clks_exec_sleep_ticks(ticks); - clks_audio_stop(); - clks_audio_played_count++; - return CLKS_TRUE; -#else - return CLKS_FALSE; -#endif -} - -void clks_audio_stop(void) { -#if defined(CLKS_ARCH_X86_64) - u8 control; - - if (clks_audio_ready == CLKS_FALSE) { - return; - } - - control = clks_audio_inb(0x61U); - clks_audio_outb(0x61U, (u8)(control & 0xFCU)); -#endif -} - -u64 clks_audio_play_count(void) { - return clks_audio_played_count; -} \ No newline at end of file diff --git a/clks/kernel/hal/serial/serial.c b/clks/kernel/hal/serial/serial.c deleted file mode 100644 index d8e3de2..0000000 --- a/clks/kernel/hal/serial/serial.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include - -#if defined(CLKS_ARCH_X86_64) - -#define CLKS_COM1_PORT 0x3F8 - -static inline void clks_x86_outb(u16 port, u8 value) { - __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); -} - -static inline u8 clks_x86_inb(u16 port) { - u8 value; - __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); - return value; -} - -void clks_serial_init(void) { - clks_x86_outb(CLKS_COM1_PORT + 1, 0x00); - clks_x86_outb(CLKS_COM1_PORT + 3, 0x80); - clks_x86_outb(CLKS_COM1_PORT + 0, 0x03); - clks_x86_outb(CLKS_COM1_PORT + 1, 0x00); - clks_x86_outb(CLKS_COM1_PORT + 3, 0x03); - clks_x86_outb(CLKS_COM1_PORT + 2, 0xC7); - clks_x86_outb(CLKS_COM1_PORT + 4, 0x0B); -} - -void clks_serial_write_char(char ch) { - while ((clks_x86_inb(CLKS_COM1_PORT + 5) & 0x20) == 0) { - } - - clks_x86_outb(CLKS_COM1_PORT, (u8)ch); -} - -#elif defined(CLKS_ARCH_AARCH64) - -#define CLKS_PL011_BASE 0x09000000ULL -#define CLKS_PL011_DR (*(volatile u32 *)(CLKS_PL011_BASE + 0x00)) -#define CLKS_PL011_FR (*(volatile u32 *)(CLKS_PL011_BASE + 0x18)) -#define CLKS_PL011_TXFF (1U << 5) - -void clks_serial_init(void) {} - -void clks_serial_write_char(char ch) { - while ((CLKS_PL011_FR & CLKS_PL011_TXFF) != 0) { - } - - CLKS_PL011_DR = (u32)(u8)ch; -} - -#else -#error "Unsupported architecture" -#endif - -void clks_serial_write(const char *text) { - usize i = 0; - - while (text[i] != '\0') { - if (text[i] == '\n') { - clks_serial_write_char('\r'); - } - - clks_serial_write_char(text[i]); - i++; - } -} \ No newline at end of file diff --git a/clks/kernel/hal/video/font8x8.c b/clks/kernel/hal/video/font8x8.c deleted file mode 100644 index de3c171..0000000 --- a/clks/kernel/hal/video/font8x8.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "font8x8.h" - -#include - -struct clks_glyph8x8 { - char ch; - u8 rows[8]; -}; - -static const struct clks_glyph8x8 clks_font_table[] = { - {' ', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {'[', {0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}}, - {']', {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}}, {':', {0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00}}, - {'.', {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}}, {'-', {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}}, - {'/', {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}}, {'_', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00}}, - {'?', {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}}, {'0', {0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00}}, - {'1', {0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, {'2', {0x3C, 0x42, 0x02, 0x0C, 0x30, 0x40, 0x7E, 0x00}}, - {'3', {0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00}}, {'4', {0x0C, 0x14, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00}}, - {'5', {0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00}}, {'6', {0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00}}, - {'7', {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00}}, {'8', {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00}}, - {'9', {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00}}, {'A', {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, - {'B', {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}}, {'C', {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}}, - {'D', {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}}, {'E', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00}}, - {'F', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'G', {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}}, - {'H', {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, {'I', {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, - {'J', {0x1E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00}}, {'K', {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}}, - {'L', {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}}, {'M', {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00}}, - {'N', {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}}, {'O', {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}}, - {'P', {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'Q', {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}}, - {'R', {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}}, {'S', {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00}}, - {'T', {0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}}, {'U', {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}}, - {'V', {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}}, {'W', {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x66, 0x42, 0x00}}, - {'X', {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}}, {'Y', {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00}}, - {'Z', {0x7E, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00}}, -}; - -static const u8 clks_unknown[8] = {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}; - -const u8 *clks_font8x8_get(char ch) { - usize i; - char upper = ch; - - if (upper >= 'a' && upper <= 'z') { - upper = (char)(upper - ('a' - 'A')); - } - - for (i = 0; i < (sizeof(clks_font_table) / sizeof(clks_font_table[0])); i++) { - if (clks_font_table[i].ch == upper) { - return clks_font_table[i].rows; - } - } - - return clks_unknown; -} \ No newline at end of file diff --git a/clks/kernel/hal/video/font8x8.h b/clks/kernel/hal/video/font8x8.h deleted file mode 100644 index cdfcafb..0000000 --- a/clks/kernel/hal/video/font8x8.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CLKS_FONT8X8_H -#define CLKS_FONT8X8_H - -#include - -const u8 *clks_font8x8_get(char ch); - -#endif \ No newline at end of file diff --git a/clks/kernel/hal/video/framebuffer.c b/clks/kernel/hal/video/framebuffer.c deleted file mode 100644 index 46f7337..0000000 --- a/clks/kernel/hal/video/framebuffer.c +++ /dev/null @@ -1,315 +0,0 @@ -#include -#include -#include - -#include "psf_font.h" - -struct clks_fb_state { - volatile u8 *address; - struct clks_framebuffer_info info; - const struct clks_psf_font *font; - struct clks_psf_font external_font; - clks_bool external_font_active; - u32 glyph_width; - u32 glyph_height; - clks_bool ready; -}; - -static struct clks_fb_state clks_fb = { - .address = CLKS_NULL, - .info = {0, 0, 0, 0}, - .font = CLKS_NULL, - .external_font = {0, 0, 0, 0, 0, CLKS_NULL}, - .external_font_active = CLKS_FALSE, - .glyph_width = 8U, - .glyph_height = 8U, - .ready = CLKS_FALSE, -}; - -static void clks_fb_apply_font(const struct clks_psf_font *font) { - clks_fb.font = font; - clks_fb.glyph_width = 8U; - clks_fb.glyph_height = 8U; - - if (font != CLKS_NULL) { - if (font->width != 0U) { - clks_fb.glyph_width = font->width; - } - - if (font->height != 0U) { - clks_fb.glyph_height = font->height; - } - } -} - -static void clks_fb_put_pixel(u32 x, u32 y, u32 rgb) { - volatile u8 *row; - volatile u32 *pixel; - - if (clks_fb.ready == CLKS_FALSE) { - return; - } - - if (x >= clks_fb.info.width || y >= clks_fb.info.height) { - return; - } - - if (clks_fb.info.bpp != 32) { - return; - } - - row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch); - pixel = (volatile u32 *)(row + ((usize)x * 4U)); - *pixel = rgb; -} - -void clks_fb_init(const struct limine_framebuffer *fb) { - if (fb == CLKS_NULL) { - clks_fb.ready = CLKS_FALSE; - return; - } - - clks_fb.address = (volatile u8 *)fb->address; - clks_fb.info.width = (u32)fb->width; - clks_fb.info.height = (u32)fb->height; - clks_fb.info.pitch = (u32)fb->pitch; - clks_fb.info.bpp = fb->bpp; - - clks_fb.external_font_active = CLKS_FALSE; - clks_fb_apply_font(clks_psf_default_font()); - - clks_fb.ready = CLKS_TRUE; -} - -clks_bool clks_fb_ready(void) { - return clks_fb.ready; -} - -struct clks_framebuffer_info clks_fb_info(void) { - return clks_fb.info; -} - -void clks_fb_draw_pixel(u32 x, u32 y, u32 rgb) { - clks_fb_put_pixel(x, y, rgb); -} - -clks_bool clks_fb_read_pixel(u32 x, u32 y, u32 *out_rgb) { - volatile u8 *row; - volatile u32 *pixel; - - if (out_rgb == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_fb.ready == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (x >= clks_fb.info.width || y >= clks_fb.info.height) { - return CLKS_FALSE; - } - - if (clks_fb.info.bpp != 32) { - return CLKS_FALSE; - } - - row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch); - pixel = (volatile u32 *)(row + ((usize)x * 4U)); - *out_rgb = *pixel; - return CLKS_TRUE; -} - -void clks_fb_fill_rect(u32 x, u32 y, u32 width, u32 height, u32 rgb) { - u32 px; - u32 py; - u32 end_x; - u32 end_y; - u64 end_x64; - u64 end_y64; - - if (clks_fb.ready == CLKS_FALSE) { - return; - } - - if (width == 0U || height == 0U) { - return; - } - - if (x >= clks_fb.info.width || y >= clks_fb.info.height) { - return; - } - - end_x64 = (u64)x + (u64)width; - end_y64 = (u64)y + (u64)height; - - end_x = (end_x64 > (u64)clks_fb.info.width) ? clks_fb.info.width : (u32)end_x64; - end_y = (end_y64 > (u64)clks_fb.info.height) ? clks_fb.info.height : (u32)end_y64; - - for (py = y; py < end_y; py++) { - for (px = x; px < end_x; px++) { - clks_fb_put_pixel(px, py, rgb); - } - } -} - -void clks_fb_clear(u32 rgb) { - clks_fb_fill_rect(0U, 0U, clks_fb.info.width, clks_fb.info.height, rgb); -} - -void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb) { - usize row_bytes; - usize move_bytes; - u32 y; - - if (clks_fb.ready == CLKS_FALSE) { - return; - } - - if (clks_fb.info.bpp != 32) { - return; - } - - if (pixel_rows == 0U) { - return; - } - - if (pixel_rows >= clks_fb.info.height) { - clks_fb_clear(fill_rgb); - return; - } - - row_bytes = (usize)clks_fb.info.pitch; - move_bytes = (usize)(clks_fb.info.height - pixel_rows) * row_bytes; - - clks_memmove((void *)clks_fb.address, (const void *)(clks_fb.address + ((usize)pixel_rows * row_bytes)), - move_bytes); - - for (y = clks_fb.info.height - pixel_rows; y < clks_fb.info.height; y++) { - volatile u32 *row_ptr = (volatile u32 *)(clks_fb.address + ((usize)y * row_bytes)); - u32 x; - - for (x = 0U; x < clks_fb.info.width; x++) { - row_ptr[x] = fill_rgb; - } - } -} - -void clks_fb_draw_char_styled(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb, u32 style_flags) { - const u8 *glyph; - u32 row; - u32 col; - u32 cols; - u32 rows; - u32 row_stride; - u32 draw_cols; - u32 draw_rows; - clks_bool style_bold; - clks_bool style_underline; - u32 underline_row; - - if (clks_fb.ready == CLKS_FALSE || clks_fb.font == CLKS_NULL) { - return; - } - - if (clks_fb.info.bpp != 32) { - return; - } - - if (x >= clks_fb.info.width || y >= clks_fb.info.height) { - return; - } - - glyph = clks_psf_glyph(clks_fb.font, (u32)(u8)ch); - - cols = clks_fb.glyph_width; - rows = clks_fb.glyph_height; - - if (cols == 0U) { - cols = 8U; - } - - if (rows == 0U) { - rows = 8U; - } - - row_stride = clks_fb.font->bytes_per_row; - - if (row_stride == 0U) { - row_stride = (cols + 7U) / 8U; - } - - if (row_stride == 0U) { - return; - } - - if (((usize)row_stride * (usize)rows) > (usize)clks_fb.font->bytes_per_glyph) { - return; - } - - draw_cols = cols; - if (x + draw_cols > clks_fb.info.width) { - draw_cols = clks_fb.info.width - x; - } - - draw_rows = rows; - if (y + draw_rows > clks_fb.info.height) { - draw_rows = clks_fb.info.height - y; - } - - style_bold = ((style_flags & CLKS_FB_STYLE_BOLD) != 0U) ? CLKS_TRUE : CLKS_FALSE; - style_underline = ((style_flags & CLKS_FB_STYLE_UNDERLINE) != 0U) ? CLKS_TRUE : CLKS_FALSE; - underline_row = (rows > 1U) ? (rows - 2U) : 0U; - - for (row = 0U; row < draw_rows; row++) { - const u8 *row_bits = glyph + ((usize)row * (usize)row_stride); - volatile u32 *dst_row = - (volatile u32 *)(clks_fb.address + ((usize)(y + row) * (usize)clks_fb.info.pitch) + ((usize)x * 4U)); - - for (col = 0U; col < draw_cols; col++) { - u8 bits = row_bits[col >> 3U]; - u8 mask = (u8)(0x80U >> (col & 7U)); - clks_bool pixel_on = ((bits & mask) != 0U) ? CLKS_TRUE : CLKS_FALSE; - - if (style_bold == CLKS_TRUE && pixel_on == CLKS_FALSE && col > 0U) { - u32 left_col = col - 1U; - u8 left_bits = row_bits[left_col >> 3U]; - u8 left_mask = (u8)(0x80U >> (left_col & 7U)); - - if ((left_bits & left_mask) != 0U) { - pixel_on = CLKS_TRUE; - } - } - - if (style_underline == CLKS_TRUE && row == underline_row) { - pixel_on = CLKS_TRUE; - } - - dst_row[col] = (pixel_on == CLKS_TRUE) ? fg_rgb : bg_rgb; - } - } -} - -void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) { - clks_fb_draw_char_styled(x, y, ch, fg_rgb, bg_rgb, 0U); -} - -clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size) { - struct clks_psf_font parsed = {0, 0, 0, 0, 0, CLKS_NULL}; - - if (clks_psf_parse_font(blob, blob_size, &parsed) == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_fb.external_font = parsed; - clks_fb.external_font_active = CLKS_TRUE; - clks_fb_apply_font(&clks_fb.external_font); - return CLKS_TRUE; -} - -u32 clks_fb_cell_width(void) { - return clks_fb.glyph_width == 0U ? 8U : clks_fb.glyph_width; -} - -u32 clks_fb_cell_height(void) { - return clks_fb.glyph_height == 0U ? 8U : clks_fb.glyph_height; -} diff --git a/clks/kernel/hal/video/psf_font.c b/clks/kernel/hal/video/psf_font.c deleted file mode 100644 index 86bb570..0000000 --- a/clks/kernel/hal/video/psf_font.c +++ /dev/null @@ -1,258 +0,0 @@ -#include "psf_font.h" - -#include -#include - -#define CLKS_PSF1_MAGIC0 0x36U -#define CLKS_PSF1_MAGIC1 0x04U -#define CLKS_PSF1_HEADER_SIZE 4U -#define CLKS_PSF1_GLYPH_COUNT 256U -#define CLKS_PSF1_GLYPH_BYTES 8U -#define CLKS_PSF1_BLOB_SIZE (CLKS_PSF1_HEADER_SIZE + (CLKS_PSF1_GLYPH_COUNT * CLKS_PSF1_GLYPH_BYTES)) - -#define CLKS_PSF2_MAGIC 0x864AB572U -#define CLKS_PSF2_HEADER_MIN_SIZE 32U - -struct clks_psf1_header { - u8 magic[2]; - u8 mode; - u8 charsize; -}; - -struct clks_psf2_header { - u32 magic; - u32 version; - u32 headersize; - u32 flags; - u32 length; - u32 charsize; - u32 height; - u32 width; -}; - -struct clks_psf_seed_glyph { - u8 code; - u8 rows[CLKS_PSF1_GLYPH_BYTES]; -}; - -static const u8 clks_psf_unknown[CLKS_PSF1_GLYPH_BYTES] = {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}; - -static const struct clks_psf_seed_glyph clks_psf_seed_table[] = { - {' ', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {'[', {0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}}, - {']', {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}}, {':', {0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00}}, - {'.', {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}}, {'-', {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}}, - {'/', {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}}, {'_', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00}}, - {'?', {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}}, {'0', {0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00}}, - {'1', {0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, {'2', {0x3C, 0x42, 0x02, 0x0C, 0x30, 0x40, 0x7E, 0x00}}, - {'3', {0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00}}, {'4', {0x0C, 0x14, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00}}, - {'5', {0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00}}, {'6', {0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00}}, - {'7', {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00}}, {'8', {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00}}, - {'9', {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00}}, {'A', {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, - {'B', {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}}, {'C', {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}}, - {'D', {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}}, {'E', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00}}, - {'F', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'G', {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}}, - {'H', {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, {'I', {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, - {'J', {0x1E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00}}, {'K', {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}}, - {'L', {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}}, {'M', {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00}}, - {'N', {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}}, {'O', {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}}, - {'P', {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'Q', {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}}, - {'R', {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}}, {'S', {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00}}, - {'T', {0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}}, {'U', {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}}, - {'V', {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}}, {'W', {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x66, 0x42, 0x00}}, - {'X', {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}}, {'Y', {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00}}, - {'Z', {0x7E, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00}}, -}; - -static u8 clks_psf_default_blob[CLKS_PSF1_BLOB_SIZE]; -static struct clks_psf_font clks_psf_default = {8U, 8U, 0U, 0U, 1U, CLKS_NULL}; -static clks_bool clks_psf_default_ready = CLKS_FALSE; - -static clks_bool clks_psf_parse_psf1(const u8 *blob, usize blob_size, struct clks_psf_font *out_font) { - const struct clks_psf1_header *hdr; - u32 glyph_count; - u32 glyph_bytes; - usize payload_size; - - if (blob == CLKS_NULL || out_font == CLKS_NULL) { - return CLKS_FALSE; - } - - if (blob_size < CLKS_PSF1_HEADER_SIZE) { - return CLKS_FALSE; - } - - hdr = (const struct clks_psf1_header *)blob; - - if (hdr->magic[0] != CLKS_PSF1_MAGIC0 || hdr->magic[1] != CLKS_PSF1_MAGIC1) { - return CLKS_FALSE; - } - - glyph_count = (hdr->mode & 0x01U) != 0U ? 512U : 256U; - glyph_bytes = (u32)hdr->charsize; - - if (glyph_bytes == 0U) { - return CLKS_FALSE; - } - - payload_size = (usize)glyph_count * (usize)glyph_bytes; - - if (blob_size < (usize)CLKS_PSF1_HEADER_SIZE + payload_size) { - return CLKS_FALSE; - } - - out_font->width = 8U; - out_font->height = glyph_bytes; - out_font->glyph_count = glyph_count; - out_font->bytes_per_glyph = glyph_bytes; - out_font->bytes_per_row = 1U; - out_font->glyphs = blob + CLKS_PSF1_HEADER_SIZE; - return CLKS_TRUE; -} - -static clks_bool clks_psf_parse_psf2(const u8 *blob, usize blob_size, struct clks_psf_font *out_font) { - const struct clks_psf2_header *hdr; - u32 bytes_per_row; - usize min_bytes_per_glyph; - usize payload_size; - - if (blob == CLKS_NULL || out_font == CLKS_NULL) { - return CLKS_FALSE; - } - - if (blob_size < CLKS_PSF2_HEADER_MIN_SIZE) { - return CLKS_FALSE; - } - - hdr = (const struct clks_psf2_header *)blob; - - if (hdr->magic != CLKS_PSF2_MAGIC) { - return CLKS_FALSE; - } - - if (hdr->headersize < CLKS_PSF2_HEADER_MIN_SIZE || hdr->headersize > blob_size) { - return CLKS_FALSE; - } - - if (hdr->width == 0U || hdr->height == 0U || hdr->length == 0U || hdr->charsize == 0U) { - return CLKS_FALSE; - } - - bytes_per_row = (hdr->width + 7U) / 8U; - - if (bytes_per_row == 0U) { - return CLKS_FALSE; - } - - min_bytes_per_glyph = (usize)bytes_per_row * (usize)hdr->height; - - if (min_bytes_per_glyph > hdr->charsize) { - return CLKS_FALSE; - } - - if ((usize)hdr->length > (((usize)-1) / (usize)hdr->charsize)) { - return CLKS_FALSE; - } - - payload_size = (usize)hdr->length * (usize)hdr->charsize; - - if (payload_size > (blob_size - (usize)hdr->headersize)) { - return CLKS_FALSE; - } - - out_font->width = hdr->width; - out_font->height = hdr->height; - out_font->glyph_count = hdr->length; - out_font->bytes_per_glyph = hdr->charsize; - out_font->bytes_per_row = bytes_per_row; - out_font->glyphs = blob + hdr->headersize; - return CLKS_TRUE; -} - -static void clks_psf_seed_default_blob(void) { - struct clks_psf1_header *hdr; - u32 i; - - clks_memset(clks_psf_default_blob, 0, sizeof(clks_psf_default_blob)); - - hdr = (struct clks_psf1_header *)clks_psf_default_blob; - hdr->magic[0] = CLKS_PSF1_MAGIC0; - hdr->magic[1] = CLKS_PSF1_MAGIC1; - hdr->mode = 0x00U; - hdr->charsize = (u8)CLKS_PSF1_GLYPH_BYTES; - - for (i = 0U; i < CLKS_PSF1_GLYPH_COUNT; i++) { - u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES); - clks_memcpy(dst, clks_psf_unknown, CLKS_PSF1_GLYPH_BYTES); - } - - for (i = 0U; i < (u32)(sizeof(clks_psf_seed_table) / sizeof(clks_psf_seed_table[0])); i++) { - const struct clks_psf_seed_glyph *seed = &clks_psf_seed_table[i]; - u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)seed->code * CLKS_PSF1_GLYPH_BYTES); - clks_memcpy(dst, seed->rows, CLKS_PSF1_GLYPH_BYTES); - } - - for (i = (u32)'A'; i <= (u32)'Z'; i++) { - const u8 *upper = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES); - u8 *lower = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)(i + ('a' - 'A')) * CLKS_PSF1_GLYPH_BYTES); - clks_memcpy(lower, upper, CLKS_PSF1_GLYPH_BYTES); - } -} - -const struct clks_psf_font *clks_psf_default_font(void) { - if (clks_psf_default_ready == CLKS_FALSE) { - clks_psf_seed_default_blob(); - - if (clks_psf_parse_psf1(clks_psf_default_blob, sizeof(clks_psf_default_blob), &clks_psf_default) == - CLKS_FALSE) { - clks_psf_default.width = 8U; - clks_psf_default.height = 8U; - clks_psf_default.glyph_count = 1U; - clks_psf_default.bytes_per_glyph = CLKS_PSF1_GLYPH_BYTES; - clks_psf_default.bytes_per_row = 1U; - clks_psf_default.glyphs = clks_psf_unknown; - } - - clks_psf_default_ready = CLKS_TRUE; - } - - return &clks_psf_default; -} - -const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint) { - u32 index = codepoint; - - if (font == CLKS_NULL || font->glyphs == CLKS_NULL || font->bytes_per_glyph == 0U) { - return clks_psf_unknown; - } - - if (index >= font->glyph_count) { - index = (u32)'?'; - - if (index >= font->glyph_count) { - index = 0U; - } - } - - return font->glyphs + ((usize)index * (usize)font->bytes_per_glyph); -} - -clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font) { - const u8 *bytes; - u32 magic32; - - if (blob == CLKS_NULL || out_font == CLKS_NULL || blob_size == 0ULL) { - return CLKS_FALSE; - } - - bytes = (const u8 *)blob; - - if (blob_size >= 4ULL) { - magic32 = ((u32)bytes[0]) | (((u32)bytes[1]) << 8U) | (((u32)bytes[2]) << 16U) | (((u32)bytes[3]) << 24U); - - if (magic32 == CLKS_PSF2_MAGIC) { - return clks_psf_parse_psf2(bytes, (usize)blob_size, out_font); - } - } - - return clks_psf_parse_psf1(bytes, (usize)blob_size, out_font); -} diff --git a/clks/kernel/hal/video/psf_font.h b/clks/kernel/hal/video/psf_font.h deleted file mode 100644 index 26c43db..0000000 --- a/clks/kernel/hal/video/psf_font.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CLKS_PSF_FONT_H -#define CLKS_PSF_FONT_H - -#include - -struct clks_psf_font { - u32 width; - u32 height; - u32 glyph_count; - u32 bytes_per_glyph; - u32 bytes_per_row; - const u8 *glyphs; -}; - -const struct clks_psf_font *clks_psf_default_font(void); -const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint); -clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font); - -#endif diff --git a/clks/kernel/input/keyboard.c b/clks/kernel/input/keyboard.c deleted file mode 100644 index 3119486..0000000 --- a/clks/kernel/input/keyboard.c +++ /dev/null @@ -1,464 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define CLKS_SC_ALT 0x38U -#define CLKS_SC_LSHIFT 0x2AU -#define CLKS_SC_RSHIFT 0x36U -#define CLKS_SC_CTRL 0x1DU -#define CLKS_SC_F1 0x3BU -#define CLKS_SC_F2 0x3CU -#define CLKS_SC_F3 0x3DU -#define CLKS_SC_F4 0x3EU -#define CLKS_SC_C 0x2EU -#define CLKS_SC_EXT_PREFIX 0xE0U - -#define CLKS_SC_EXT_HOME 0x47U -#define CLKS_SC_EXT_UP 0x48U -#define CLKS_SC_EXT_LEFT 0x4BU -#define CLKS_SC_EXT_RIGHT 0x4DU -#define CLKS_SC_EXT_END 0x4FU -#define CLKS_SC_EXT_DOWN 0x50U -#define CLKS_SC_EXT_PAGEUP 0x49U -#define CLKS_SC_EXT_PAGEDOWN 0x51U -#define CLKS_SC_EXT_DELETE 0x53U - -#define CLKS_KBD_INPUT_CAP 256U -#define CLKS_KBD_TTY_MAX 8U -#define CLKS_KBD_DROP_LOG_EVERY 64ULL - -#ifndef CLKS_CFG_KBD_TTY_SWITCH_HOTKEY -#define CLKS_CFG_KBD_TTY_SWITCH_HOTKEY 1 -#endif - -#ifndef CLKS_CFG_KBD_CTRL_SHORTCUTS -#define CLKS_CFG_KBD_CTRL_SHORTCUTS 1 -#endif - -#ifndef CLKS_CFG_KBD_FORCE_STOP_HOTKEY -#define CLKS_CFG_KBD_FORCE_STOP_HOTKEY 1 -#endif - -static const char clks_kbd_map[128] = { - [2] = '1', [3] = '2', [4] = '3', [5] = '4', [6] = '5', [7] = '6', [8] = '7', [9] = '8', [10] = '9', - [11] = '0', [12] = '-', [13] = '=', [14] = '\b', [15] = '\t', [16] = 'q', [17] = 'w', [18] = 'e', [19] = 'r', - [20] = 't', [21] = 'y', [22] = 'u', [23] = 'i', [24] = 'o', [25] = 'p', [26] = '[', [27] = ']', [28] = '\n', - [30] = 'a', [31] = 's', [32] = 'd', [33] = 'f', [34] = 'g', [35] = 'h', [36] = 'j', [37] = 'k', [38] = 'l', - [39] = ';', [40] = '\'', [41] = '`', [43] = '\\', [44] = 'z', [45] = 'x', [46] = 'c', [47] = 'v', [48] = 'b', - [49] = 'n', [50] = 'm', [51] = ',', [52] = '.', [53] = '/', [57] = ' '}; - -static const char clks_kbd_shift_map[128] = { - [2] = '!', [3] = '@', [4] = '#', [5] = '$', [6] = '%', [7] = '^', [8] = '&', [9] = '*', [10] = '(', - [11] = ')', [12] = '_', [13] = '+', [14] = '\b', [15] = '\t', [16] = 'Q', [17] = 'W', [18] = 'E', [19] = 'R', - [20] = 'T', [21] = 'Y', [22] = 'U', [23] = 'I', [24] = 'O', [25] = 'P', [26] = '{', [27] = '}', [28] = '\n', - [30] = 'A', [31] = 'S', [32] = 'D', [33] = 'F', [34] = 'G', [35] = 'H', [36] = 'J', [37] = 'K', [38] = 'L', - [39] = ':', [40] = '"', [41] = '~', [43] = '|', [44] = 'Z', [45] = 'X', [46] = 'C', [47] = 'V', [48] = 'B', - [49] = 'N', [50] = 'M', [51] = '<', [52] = '>', [53] = '?', [57] = ' '}; - -static char clks_kbd_input_queue[CLKS_KBD_TTY_MAX][CLKS_KBD_INPUT_CAP]; -static u16 clks_kbd_input_head[CLKS_KBD_TTY_MAX]; -static u16 clks_kbd_input_tail[CLKS_KBD_TTY_MAX]; -static u16 clks_kbd_input_count[CLKS_KBD_TTY_MAX]; - -static clks_bool clks_kbd_alt_down = CLKS_FALSE; -static clks_bool clks_kbd_lshift_down = CLKS_FALSE; -static clks_bool clks_kbd_rshift_down = CLKS_FALSE; -static clks_bool clks_kbd_lctrl_down = CLKS_FALSE; -static clks_bool clks_kbd_rctrl_down = CLKS_FALSE; -static clks_bool clks_kbd_e0_prefix = CLKS_FALSE; -static clks_bool clks_kbd_force_stop_latch = CLKS_FALSE; -static u64 clks_kbd_hotkey_switches = 0ULL; - -static u64 clks_kbd_push_count = 0ULL; -static u64 clks_kbd_pop_count = 0ULL; -static u64 clks_kbd_drop_count = 0ULL; - -static u32 clks_keyboard_effective_tty_count(void) { - u32 tty_count = clks_tty_count(); - - if (tty_count == 0U) { - return 1U; - } - - if (tty_count > CLKS_KBD_TTY_MAX) { - return CLKS_KBD_TTY_MAX; - } - - return tty_count; -} - -static u32 clks_keyboard_clamp_tty_index(u32 tty_index) { - u32 tty_count = clks_keyboard_effective_tty_count(); - - if (tty_index >= tty_count) { - return 0U; - } - - return tty_index; -} - -static clks_bool clks_keyboard_shift_active(void) { - return (clks_kbd_lshift_down == CLKS_TRUE || clks_kbd_rshift_down == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; -} - -static char clks_keyboard_translate_ext_scancode(u8 code) { - clks_bool shift_active = clks_keyboard_shift_active(); - - switch (code) { - case CLKS_SC_EXT_LEFT: - return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_LEFT : CLKS_KEY_LEFT; - case CLKS_SC_EXT_RIGHT: - return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_RIGHT : CLKS_KEY_RIGHT; - case CLKS_SC_EXT_UP: - return CLKS_KEY_UP; - case CLKS_SC_EXT_DOWN: - return CLKS_KEY_DOWN; - case CLKS_SC_EXT_HOME: - return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_HOME : CLKS_KEY_HOME; - case CLKS_SC_EXT_END: - return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_END : CLKS_KEY_END; - case CLKS_SC_EXT_DELETE: - return CLKS_KEY_DELETE; - default: - return '\0'; - } -} - -static clks_bool clks_keyboard_queue_push_for_tty(u32 tty_index, char ch) { - u32 tty = clks_keyboard_clamp_tty_index(tty_index); - - if (clks_kbd_input_count[tty] >= CLKS_KBD_INPUT_CAP) { - clks_kbd_drop_count++; - - if ((clks_kbd_drop_count % CLKS_KBD_DROP_LOG_EVERY) == 1ULL) { - clks_log(CLKS_LOG_WARN, "KBD", "INPUT QUEUE OVERFLOW"); - clks_log_hex(CLKS_LOG_WARN, "KBD", "TTY", (u64)tty); - clks_log_hex(CLKS_LOG_WARN, "KBD", "DROPPED", clks_kbd_drop_count); - } - - return CLKS_FALSE; - } - - clks_kbd_input_queue[tty][clks_kbd_input_head[tty]] = ch; - clks_kbd_input_head[tty] = (u16)((clks_kbd_input_head[tty] + 1U) % CLKS_KBD_INPUT_CAP); - clks_kbd_input_count[tty]++; - clks_kbd_push_count++; - return CLKS_TRUE; -} - -static clks_bool clks_keyboard_shell_input_enabled(void) { - return (clks_tty_active() == 0U) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_keyboard_should_pump_shell_now(void) { - if (clks_keyboard_shell_input_enabled() == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_exec_is_running() == CLKS_TRUE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static char clks_keyboard_translate_scancode(u8 code) { - clks_bool shift_active = - (clks_kbd_lshift_down == CLKS_TRUE || clks_kbd_rshift_down == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; - - if (shift_active == CLKS_TRUE) { - return clks_kbd_shift_map[code]; - } - - return clks_kbd_map[code]; -} - -static clks_bool clks_keyboard_ctrl_active(void) { - return (clks_kbd_lctrl_down == CLKS_TRUE || clks_kbd_rctrl_down == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_keyboard_try_emit_ctrl_shortcut(u8 code, u32 tty_index) { - char shortcut = '\0'; - - if (CLKS_CFG_KBD_CTRL_SHORTCUTS == 0) { - return CLKS_FALSE; - } - - if (clks_keyboard_ctrl_active() == CLKS_FALSE) { - return CLKS_FALSE; - } - - switch (code) { - case 0x1EU: - shortcut = CLKS_KEY_SELECT_ALL; - break; - case 0x2EU: - shortcut = CLKS_KEY_COPY; - break; - case 0x2FU: - shortcut = CLKS_KEY_PASTE; - break; - default: - return CLKS_FALSE; - } - - if (clks_keyboard_queue_push_for_tty(tty_index, shortcut) == CLKS_TRUE && - clks_keyboard_should_pump_shell_now() == CLKS_TRUE) { - clks_shell_pump_input(1U); - } - - return CLKS_TRUE; -} - -static clks_bool clks_keyboard_try_force_stop_hotkey(u8 code) { - u64 pid = 0ULL; - u64 stop_ret; - - if (CLKS_CFG_KBD_FORCE_STOP_HOTKEY == 0) { - return CLKS_FALSE; - } - - if (code != CLKS_SC_C) { - return CLKS_FALSE; - } - - if (clks_kbd_alt_down != CLKS_TRUE || clks_keyboard_ctrl_active() == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_kbd_force_stop_latch == CLKS_TRUE) { - return CLKS_TRUE; - } - - clks_kbd_force_stop_latch = CLKS_TRUE; - stop_ret = clks_exec_force_stop_tty_running_process(clks_tty_active(), &pid); - - if (stop_ret == 1ULL) { - clks_log(CLKS_LOG_WARN, "KBD", "HOTKEY CTRL+ALT+C FORCE STOP"); - clks_log_hex(CLKS_LOG_WARN, "KBD", "PID", pid); - } else { - clks_log(CLKS_LOG_WARN, "KBD", "HOTKEY CTRL+ALT+C NO RUNNING USER PROC"); - } - - return CLKS_TRUE; -} - -void clks_keyboard_init(void) { - u32 tty; - - for (tty = 0U; tty < CLKS_KBD_TTY_MAX; tty++) { - clks_kbd_input_head[tty] = 0U; - clks_kbd_input_tail[tty] = 0U; - clks_kbd_input_count[tty] = 0U; - } - - clks_kbd_alt_down = CLKS_FALSE; - clks_kbd_lshift_down = CLKS_FALSE; - clks_kbd_rshift_down = CLKS_FALSE; - clks_kbd_lctrl_down = CLKS_FALSE; - clks_kbd_rctrl_down = CLKS_FALSE; - clks_kbd_e0_prefix = CLKS_FALSE; - clks_kbd_force_stop_latch = CLKS_FALSE; - clks_kbd_hotkey_switches = 0ULL; - clks_kbd_push_count = 0ULL; - clks_kbd_pop_count = 0ULL; - clks_kbd_drop_count = 0ULL; - - if (CLKS_CFG_KBD_TTY_SWITCH_HOTKEY != 0) { - clks_log(CLKS_LOG_INFO, "KBD", "ALT+F1..F4 TTY HOTKEY ONLINE"); - } else { - clks_log(CLKS_LOG_WARN, "KBD", "TTY SWITCH HOTKEY DISABLED BY MENUCONFIG"); - } - - if (CLKS_CFG_KBD_CTRL_SHORTCUTS == 0) { - clks_log(CLKS_LOG_WARN, "KBD", "CTRL SHORTCUTS DISABLED BY MENUCONFIG"); - } - - if (CLKS_CFG_KBD_FORCE_STOP_HOTKEY == 0) { - clks_log(CLKS_LOG_WARN, "KBD", "CTRL+ALT+C FORCE STOP DISABLED BY MENUCONFIG"); - } - - clks_log(CLKS_LOG_INFO, "KBD", "PS2 INPUT QUEUE ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "KBD", "QUEUE_CAP", CLKS_KBD_INPUT_CAP); -} - -void clks_keyboard_handle_scancode(u8 scancode) { - clks_bool released; - u8 code; - - if (scancode == CLKS_SC_EXT_PREFIX) { - clks_kbd_e0_prefix = CLKS_TRUE; - return; - } - - released = ((scancode & 0x80U) != 0U) ? CLKS_TRUE : CLKS_FALSE; - code = (u8)(scancode & 0x7FU); - - if (code == CLKS_SC_CTRL) { - if (clks_kbd_e0_prefix == CLKS_TRUE) { - clks_kbd_rctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; - if (released == CLKS_TRUE) { - clks_kbd_force_stop_latch = CLKS_FALSE; - } - clks_kbd_e0_prefix = CLKS_FALSE; - return; - } - - clks_kbd_lctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; - if (released == CLKS_TRUE) { - clks_kbd_force_stop_latch = CLKS_FALSE; - } - return; - } - - if (code == CLKS_SC_ALT) { - clks_kbd_alt_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; - if (released == CLKS_TRUE) { - clks_kbd_force_stop_latch = CLKS_FALSE; - } - - if (clks_kbd_e0_prefix == CLKS_TRUE) { - clks_kbd_e0_prefix = CLKS_FALSE; - } - - return; - } - - if (code == CLKS_SC_LSHIFT) { - clks_kbd_lshift_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; - return; - } - - if (code == CLKS_SC_RSHIFT) { - clks_kbd_rshift_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; - return; - } - - if (released == CLKS_TRUE) { - if (code == CLKS_SC_C) { - clks_kbd_force_stop_latch = CLKS_FALSE; - } - - if (clks_kbd_e0_prefix == CLKS_TRUE) { - clks_kbd_e0_prefix = CLKS_FALSE; - } - return; - } - - if (clks_kbd_e0_prefix == CLKS_TRUE) { - char ext; - u32 active_tty = clks_tty_active(); - - clks_kbd_e0_prefix = CLKS_FALSE; - - if (code == CLKS_SC_EXT_PAGEUP) { - clks_tty_scrollback_page_up(); - return; - } - - if (code == CLKS_SC_EXT_PAGEDOWN) { - clks_tty_scrollback_page_down(); - return; - } - - ext = clks_keyboard_translate_ext_scancode(code); - - if (ext != '\0') { - if (clks_keyboard_queue_push_for_tty(active_tty, ext) == CLKS_TRUE && - clks_keyboard_should_pump_shell_now() == CLKS_TRUE) { - clks_shell_pump_input(1U); - } - } - - return; - } - - if (CLKS_CFG_KBD_TTY_SWITCH_HOTKEY != 0 && clks_kbd_alt_down == CLKS_TRUE && code >= CLKS_SC_F1 && - code <= CLKS_SC_F4) { - u32 target = (u32)(code - CLKS_SC_F1); - u32 before = clks_tty_active(); - u32 after; - - clks_tty_switch(target); - after = clks_tty_active(); - - if (after != before) { - clks_kbd_hotkey_switches++; - clks_log(CLKS_LOG_INFO, "TTY", "HOTKEY SWITCH"); - clks_log_hex(CLKS_LOG_INFO, "TTY", "ACTIVE", (u64)after); - clks_log_hex(CLKS_LOG_INFO, "TTY", "HOTKEY_SWITCHES", clks_kbd_hotkey_switches); - } - - return; - } - - { - u32 active_tty = clks_tty_active(); - char translated; - - if (clks_keyboard_try_force_stop_hotkey(code) == CLKS_TRUE) { - return; - } - - if (clks_keyboard_try_emit_ctrl_shortcut(code, active_tty) == CLKS_TRUE) { - return; - } - - translated = clks_keyboard_translate_scancode(code); - - if (translated != '\0') { - if (clks_keyboard_queue_push_for_tty(active_tty, translated) == CLKS_TRUE && - clks_keyboard_should_pump_shell_now() == CLKS_TRUE) { - clks_shell_pump_input(1U); - } - } - } -} - -u64 clks_keyboard_hotkey_switch_count(void) { - return clks_kbd_hotkey_switches; -} - -clks_bool clks_keyboard_pop_char_for_tty(u32 tty_index, char *out_ch) { - u32 tty = clks_keyboard_clamp_tty_index(tty_index); - - if (out_ch == CLKS_NULL || clks_kbd_input_count[tty] == 0U) { - return CLKS_FALSE; - } - - *out_ch = clks_kbd_input_queue[tty][clks_kbd_input_tail[tty]]; - clks_kbd_input_tail[tty] = (u16)((clks_kbd_input_tail[tty] + 1U) % CLKS_KBD_INPUT_CAP); - clks_kbd_input_count[tty]--; - clks_kbd_pop_count++; - return CLKS_TRUE; -} - -clks_bool clks_keyboard_pop_char(char *out_ch) { - return clks_keyboard_pop_char_for_tty(clks_tty_active(), out_ch); -} - -u64 clks_keyboard_buffered_count(void) { - u64 total = 0ULL; - u32 tty; - - for (tty = 0U; tty < CLKS_KBD_TTY_MAX; tty++) { - total += (u64)clks_kbd_input_count[tty]; - } - - return total; -} - -u64 clks_keyboard_drop_count(void) { - return clks_kbd_drop_count; -} - -u64 clks_keyboard_push_count(void) { - return clks_kbd_push_count; -} - -u64 clks_keyboard_pop_count(void) { - return clks_kbd_pop_count; -} diff --git a/clks/kernel/input/mouse.c b/clks/kernel/input/mouse.c deleted file mode 100644 index 7816c20..0000000 --- a/clks/kernel/input/mouse.c +++ /dev/null @@ -1,305 +0,0 @@ -#include -#include -#include -#include - -#define CLKS_PS2_DATA_PORT 0x60U -#define CLKS_PS2_STATUS_PORT 0x64U -#define CLKS_PS2_CMD_PORT 0x64U -#define CLKS_PS2_STATUS_OBF 0x01U -#define CLKS_PS2_STATUS_IBF 0x02U - -#define CLKS_PS2_CMD_ENABLE_AUX 0xA8U -#define CLKS_PS2_CMD_READ_CFG 0x20U -#define CLKS_PS2_CMD_WRITE_CFG 0x60U -#define CLKS_PS2_CMD_WRITE_AUX 0xD4U - -#define CLKS_PS2_MOUSE_CMD_RESET_DEFAULTS 0xF6U -#define CLKS_PS2_MOUSE_CMD_ENABLE_STREAM 0xF4U -#define CLKS_PS2_MOUSE_ACK 0xFAU - -#define CLKS_MOUSE_IO_TIMEOUT 100000U -#define CLKS_MOUSE_DRAIN_MAX 64U -#define CLKS_MOUSE_SYNC_BIT 0x08U -#define CLKS_MOUSE_OVERFLOW_MASK 0xC0U -#define CLKS_MOUSE_BUTTON_MASK 0x07U - -struct clks_mouse_runtime { - i32 x; - i32 y; - u32 max_x; - u32 max_y; - u8 buttons; - u8 packet[3]; - u8 packet_index; - u64 packet_count; - u64 drop_count; - clks_bool ready; -}; - -static struct clks_mouse_runtime clks_mouse = { - .x = 0, - .y = 0, - .max_x = 0U, - .max_y = 0U, - .buttons = 0U, - .packet = {0U, 0U, 0U}, - .packet_index = 0U, - .packet_count = 0ULL, - .drop_count = 0ULL, - .ready = CLKS_FALSE, -}; - -static inline void clks_mouse_outb(u16 port, u8 value) { - __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); -} - -static inline u8 clks_mouse_inb(u16 port) { - u8 value; - __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); - return value; -} - -static clks_bool clks_mouse_wait_input_empty(void) { - u32 i; - - for (i = 0U; i < CLKS_MOUSE_IO_TIMEOUT; i++) { - if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_IBF) == 0U) { - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static clks_bool clks_mouse_wait_output_ready(void) { - u32 i; - - for (i = 0U; i < CLKS_MOUSE_IO_TIMEOUT; i++) { - if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_OBF) != 0U) { - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static clks_bool clks_mouse_write_cmd(u8 cmd) { - if (clks_mouse_wait_input_empty() == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_mouse_outb(CLKS_PS2_CMD_PORT, cmd); - return CLKS_TRUE; -} - -static clks_bool clks_mouse_write_data(u8 value) { - if (clks_mouse_wait_input_empty() == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_mouse_outb(CLKS_PS2_DATA_PORT, value); - return CLKS_TRUE; -} - -static clks_bool clks_mouse_read_data(u8 *out_value) { - if (out_value == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_mouse_wait_output_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - *out_value = clks_mouse_inb(CLKS_PS2_DATA_PORT); - return CLKS_TRUE; -} - -static void clks_mouse_drain_output(void) { - u32 i; - - for (i = 0U; i < CLKS_MOUSE_DRAIN_MAX; i++) { - if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_OBF) == 0U) { - break; - } - - (void)clks_mouse_inb(CLKS_PS2_DATA_PORT); - } -} - -static clks_bool clks_mouse_send_device_cmd(u8 cmd, u8 *out_ack) { - u8 ack = 0U; - - if (clks_mouse_write_cmd(CLKS_PS2_CMD_WRITE_AUX) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_mouse_write_data(cmd) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_mouse_read_data(&ack) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (out_ack != CLKS_NULL) { - *out_ack = ack; - } - - return CLKS_TRUE; -} - -static void clks_mouse_reset_runtime(void) { - struct clks_framebuffer_info info; - - clks_mouse.x = 0; - clks_mouse.y = 0; - clks_mouse.max_x = 0U; - clks_mouse.max_y = 0U; - clks_mouse.buttons = 0U; - clks_mouse.packet[0] = 0U; - clks_mouse.packet[1] = 0U; - clks_mouse.packet[2] = 0U; - clks_mouse.packet_index = 0U; - clks_mouse.packet_count = 0ULL; - clks_mouse.drop_count = 0ULL; - clks_mouse.ready = CLKS_FALSE; - - if (clks_fb_ready() == CLKS_TRUE) { - info = clks_fb_info(); - - if (info.width > 0U) { - clks_mouse.max_x = info.width - 1U; - } - - if (info.height > 0U) { - clks_mouse.max_y = info.height - 1U; - } - - clks_mouse.x = (i32)(clks_mouse.max_x / 2U); - clks_mouse.y = (i32)(clks_mouse.max_y / 2U); - } -} - -void clks_mouse_init(void) { - u8 config = 0U; - u8 ack = 0U; - - clks_mouse_reset_runtime(); - clks_mouse_drain_output(); - - if (clks_mouse_write_cmd(CLKS_PS2_CMD_ENABLE_AUX) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 ENABLE AUX FAILED"); - return; - } - - if (clks_mouse_write_cmd(CLKS_PS2_CMD_READ_CFG) == CLKS_FALSE || clks_mouse_read_data(&config) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 READ CFG FAILED"); - return; - } - - config |= 0x02U; - config &= (u8)~0x20U; - - if (clks_mouse_write_cmd(CLKS_PS2_CMD_WRITE_CFG) == CLKS_FALSE || clks_mouse_write_data(config) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 WRITE CFG FAILED"); - return; - } - - if (clks_mouse_send_device_cmd(CLKS_PS2_MOUSE_CMD_RESET_DEFAULTS, &ack) == CLKS_FALSE || - ack != CLKS_PS2_MOUSE_ACK) { - clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 RESET DEFAULTS FAILED"); - return; - } - - if (clks_mouse_send_device_cmd(CLKS_PS2_MOUSE_CMD_ENABLE_STREAM, &ack) == CLKS_FALSE || ack != CLKS_PS2_MOUSE_ACK) { - clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 ENABLE STREAM FAILED"); - return; - } - - clks_mouse.ready = CLKS_TRUE; - clks_log(CLKS_LOG_INFO, "MOUSE", "PS2 POINTER ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "MOUSE", "MAX_X", (u64)clks_mouse.max_x); - clks_log_hex(CLKS_LOG_INFO, "MOUSE", "MAX_Y", (u64)clks_mouse.max_y); -} - -void clks_mouse_handle_byte(u8 data_byte) { - i32 dx; - i32 dy; - i32 next_x; - i32 next_y; - u8 status; - - if (clks_mouse.ready == CLKS_FALSE) { - return; - } - - if (clks_mouse.packet_index == 0U && (data_byte & CLKS_MOUSE_SYNC_BIT) == 0U) { - clks_mouse.drop_count++; - return; - } - - clks_mouse.packet[clks_mouse.packet_index] = data_byte; - clks_mouse.packet_index++; - - if (clks_mouse.packet_index < 3U) { - return; - } - - clks_mouse.packet_index = 0U; - clks_mouse.packet_count++; - - status = clks_mouse.packet[0]; - clks_mouse.buttons = (u8)(status & CLKS_MOUSE_BUTTON_MASK); - - if ((status & CLKS_MOUSE_OVERFLOW_MASK) != 0U) { - clks_mouse.drop_count++; - return; - } - - dx = (i32)((i8)clks_mouse.packet[1]); - dy = (i32)((i8)clks_mouse.packet[2]); - - next_x = clks_mouse.x + dx; - next_y = clks_mouse.y - dy; - - if (next_x < 0) { - clks_mouse.x = 0; - } else if ((u32)next_x > clks_mouse.max_x) { - clks_mouse.x = (i32)clks_mouse.max_x; - } else { - clks_mouse.x = next_x; - } - - if (next_y < 0) { - clks_mouse.y = 0; - } else if ((u32)next_y > clks_mouse.max_y) { - clks_mouse.y = (i32)clks_mouse.max_y; - } else { - clks_mouse.y = next_y; - } -} - -void clks_mouse_snapshot(struct clks_mouse_state *out_state) { - if (out_state == CLKS_NULL) { - return; - } - - out_state->x = clks_mouse.x; - out_state->y = clks_mouse.y; - out_state->buttons = clks_mouse.buttons; - out_state->packet_count = clks_mouse.packet_count; - out_state->ready = clks_mouse.ready; -} - -clks_bool clks_mouse_ready(void) { - return clks_mouse.ready; -} - -u64 clks_mouse_packet_count(void) { - return clks_mouse.packet_count; -} - -u64 clks_mouse_drop_count(void) { - return clks_mouse.drop_count; -} diff --git a/clks/kernel/interface/desktop.c b/clks/kernel/interface/desktop.c deleted file mode 100644 index 2ac89e2..0000000 --- a/clks/kernel/interface/desktop.c +++ /dev/null @@ -1,406 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define CLKS_DESKTOP_TTY_INDEX 1U - -#define CLKS_DESKTOP_BG_COLOR 0x001B2430U -#define CLKS_DESKTOP_TOPBAR_COLOR 0x00293447U -#define CLKS_DESKTOP_DOCK_COLOR 0x00232C3AU -#define CLKS_DESKTOP_WINDOW_COLOR 0x00313E52U -#define CLKS_DESKTOP_TITLE_COLOR 0x003B4A61U -#define CLKS_DESKTOP_TEXT_FG 0x00E6EDF7U -#define CLKS_DESKTOP_TEXT_BG 0x003B4A61U - -#define CLKS_DESKTOP_CURSOR_FILL 0x00F5F8FFU -#define CLKS_DESKTOP_CURSOR_OUTLINE 0x00101010U -#define CLKS_DESKTOP_CURSOR_ACTIVE 0x00FFCE6EU -#define CLKS_DESKTOP_CURSOR_W 16U -#define CLKS_DESKTOP_CURSOR_H 16U - -struct clks_desktop_layout { - u32 width; - u32 height; - u32 topbar_h; - u32 dock_w; - u32 win_x; - u32 win_y; - u32 win_w; - u32 win_h; - u32 win_title_h; -}; - -static struct clks_desktop_layout clks_desktop = { - .width = 0U, - .height = 0U, - .topbar_h = 32U, - .dock_w = 72U, - .win_x = 0U, - .win_y = 0U, - .win_w = 0U, - .win_h = 0U, - .win_title_h = 28U, -}; - -static clks_bool clks_desktop_ready_flag = CLKS_FALSE; -static clks_bool clks_desktop_active_last = CLKS_FALSE; -static clks_bool clks_desktop_scene_drawn = CLKS_FALSE; -static clks_bool clks_desktop_cursor_drawn = CLKS_FALSE; -static i32 clks_desktop_last_mouse_x = -1; -static i32 clks_desktop_last_mouse_y = -1; -static u8 clks_desktop_last_buttons = 0U; -static clks_bool clks_desktop_last_ready = CLKS_FALSE; -static u32 clks_desktop_cursor_under[CLKS_DESKTOP_CURSOR_W * CLKS_DESKTOP_CURSOR_H]; - -static void clks_desktop_draw_text(u32 x, u32 y, const char *text, u32 fg, u32 bg) { - u32 step; - usize i = 0U; - - if (text == CLKS_NULL) { - return; - } - - step = clks_fb_cell_width(); - - if (step == 0U) { - step = 8U; - } - - while (text[i] != '\0') { - clks_fb_draw_char(x + ((u32)i * step), y, text[i], fg, bg); - i++; - } -} - -static clks_bool clks_desktop_in_bounds(i32 x, i32 y) { - if (x < 0 || y < 0) { - return CLKS_FALSE; - } - - if ((u32)x >= clks_desktop.width || (u32)y >= clks_desktop.height) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static void clks_desktop_compute_layout(void) { - struct clks_framebuffer_info info = clks_fb_info(); - u32 right_margin; - u32 bottom_margin; - - clks_desktop.width = info.width; - clks_desktop.height = info.height; - - if (clks_desktop.topbar_h >= clks_desktop.height) { - clks_desktop.topbar_h = clks_desktop.height; - } - - if (clks_desktop.dock_w >= clks_desktop.width) { - clks_desktop.dock_w = clks_desktop.width; - } - - clks_desktop.win_x = clks_desktop.width / 6U; - clks_desktop.win_y = clks_desktop.height / 6U; - - if (clks_desktop.win_x < 96U) { - clks_desktop.win_x = 96U; - } - - if (clks_desktop.win_y < 72U) { - clks_desktop.win_y = 72U; - } - - if (clks_desktop.win_x >= clks_desktop.width) { - clks_desktop.win_x = clks_desktop.width > 0U ? (clks_desktop.width - 1U) : 0U; - } - - if (clks_desktop.win_y >= clks_desktop.height) { - clks_desktop.win_y = clks_desktop.height > 0U ? (clks_desktop.height - 1U) : 0U; - } - - right_margin = clks_desktop.width / 10U; - bottom_margin = clks_desktop.height / 8U; - - if (right_margin < 48U) { - right_margin = 48U; - } - - if (bottom_margin < 48U) { - bottom_margin = 48U; - } - - if (clks_desktop.width > clks_desktop.win_x + right_margin) { - clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x - right_margin; - } else { - clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x; - } - - if (clks_desktop.height > clks_desktop.win_y + bottom_margin) { - clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y - bottom_margin; - } else { - clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y; - } - - if (clks_desktop.win_w < 220U) { - clks_desktop.win_w = (clks_desktop.width > (clks_desktop.win_x + 20U)) - ? (clks_desktop.width - clks_desktop.win_x - 20U) - : (clks_desktop.width - clks_desktop.win_x); - } - - if (clks_desktop.win_h < 140U) { - clks_desktop.win_h = (clks_desktop.height > (clks_desktop.win_y + 20U)) - ? (clks_desktop.height - clks_desktop.win_y - 20U) - : (clks_desktop.height - clks_desktop.win_y); - } - - if (clks_desktop.win_w > (clks_desktop.width - clks_desktop.win_x)) { - clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x; - } - - if (clks_desktop.win_h > (clks_desktop.height - clks_desktop.win_y)) { - clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y; - } - - if (clks_desktop.win_title_h >= clks_desktop.win_h) { - clks_desktop.win_title_h = clks_desktop.win_h; - } -} - -static void clks_desktop_draw_status_widgets(const struct clks_mouse_state *mouse) { - u32 ready_x = 0U; - u32 left_x = 0U; - - if (mouse == CLKS_NULL) { - return; - } - - if (clks_desktop.width > 28U) { - ready_x = clks_desktop.width - 28U; - } - - if (clks_desktop.width > 46U) { - left_x = clks_desktop.width - 46U; - } - - if (mouse->ready == CLKS_TRUE) { - clks_fb_fill_rect(ready_x, 10U, 10U, 10U, 0x006FE18BU); - } else { - clks_fb_fill_rect(ready_x, 10U, 10U, 10U, 0x00E06A6AU); - } - - if ((mouse->buttons & CLKS_MOUSE_BTN_LEFT) != 0U) { - clks_fb_fill_rect(left_x, 10U, 10U, 10U, 0x00FFCE6EU); - } else { - clks_fb_fill_rect(left_x, 10U, 10U, 10U, 0x004A5568U); - } -} - -static void clks_desktop_draw_static_scene(const struct clks_mouse_state *mouse) { - clks_fb_clear(CLKS_DESKTOP_BG_COLOR); - - if (clks_desktop.topbar_h > 0U) { - clks_fb_fill_rect(0U, 0U, clks_desktop.width, clks_desktop.topbar_h, CLKS_DESKTOP_TOPBAR_COLOR); - } - - if (clks_desktop.height > clks_desktop.topbar_h) { - clks_fb_fill_rect(0U, clks_desktop.topbar_h, clks_desktop.dock_w, clks_desktop.height - clks_desktop.topbar_h, - CLKS_DESKTOP_DOCK_COLOR); - } - - clks_fb_fill_rect(clks_desktop.win_x, clks_desktop.win_y, clks_desktop.win_w, clks_desktop.win_h, - CLKS_DESKTOP_WINDOW_COLOR); - clks_fb_fill_rect(clks_desktop.win_x, clks_desktop.win_y, clks_desktop.win_w, clks_desktop.win_title_h, - CLKS_DESKTOP_TITLE_COLOR); - - clks_desktop_draw_text(12U, 6U, "CLeonOS Desktop TTY2", CLKS_DESKTOP_TEXT_FG, CLKS_DESKTOP_TOPBAR_COLOR); - clks_desktop_draw_text(clks_desktop.win_x + 12U, clks_desktop.win_y + 6U, "Mouse Input Ready", CLKS_DESKTOP_TEXT_FG, - CLKS_DESKTOP_TITLE_COLOR); - clks_desktop_draw_text(clks_desktop.win_x + 16U, clks_desktop.win_y + clks_desktop.win_title_h + 16U, - "Stage25: Alt+F2 desktop, Alt+F1 shell", CLKS_DESKTOP_TEXT_FG, CLKS_DESKTOP_WINDOW_COLOR); - - clks_desktop_draw_status_widgets(mouse); - clks_desktop_scene_drawn = CLKS_TRUE; -} - -static clks_bool clks_desktop_cursor_pixel(u32 lx, u32 ly, u8 buttons, u32 *out_color) { - u32 fill = CLKS_DESKTOP_CURSOR_FILL; - - if (out_color == CLKS_NULL) { - return CLKS_FALSE; - } - - if ((buttons & CLKS_MOUSE_BTN_LEFT) != 0U) { - fill = CLKS_DESKTOP_CURSOR_ACTIVE; - } - - if (ly < 12U) { - u32 span = (ly / 2U) + 1U; - - if (lx < span) { - clks_bool border = (lx == 0U || (lx + 1U) == span || ly == 11U) ? CLKS_TRUE : CLKS_FALSE; - *out_color = (border == CLKS_TRUE) ? CLKS_DESKTOP_CURSOR_OUTLINE : fill; - return CLKS_TRUE; - } - } - - if (ly >= 8U && ly < 16U && lx >= 2U && lx < 5U) { - clks_bool border = (lx == 2U || lx == 4U || ly == 15U) ? CLKS_TRUE : CLKS_FALSE; - *out_color = (border == CLKS_TRUE) ? CLKS_DESKTOP_CURSOR_OUTLINE : fill; - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -static void clks_desktop_capture_cursor_under(i32 x, i32 y) { - u32 ly; - - for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) { - u32 lx; - - for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) { - i32 gx = x + (i32)lx; - i32 gy = y + (i32)ly; - usize idx = ((usize)ly * (usize)CLKS_DESKTOP_CURSOR_W) + (usize)lx; - u32 pixel = CLKS_DESKTOP_BG_COLOR; - - if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) { - (void)clks_fb_read_pixel((u32)gx, (u32)gy, &pixel); - } - - clks_desktop_cursor_under[idx] = pixel; - } - } -} - -static void clks_desktop_restore_cursor_under(void) { - u32 ly; - - if (clks_desktop_cursor_drawn == CLKS_FALSE) { - return; - } - - for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) { - u32 lx; - - for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) { - i32 gx = clks_desktop_last_mouse_x + (i32)lx; - i32 gy = clks_desktop_last_mouse_y + (i32)ly; - usize idx = ((usize)ly * (usize)CLKS_DESKTOP_CURSOR_W) + (usize)lx; - - if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) { - clks_fb_draw_pixel((u32)gx, (u32)gy, clks_desktop_cursor_under[idx]); - } - } - } - - clks_desktop_cursor_drawn = CLKS_FALSE; -} - -static void clks_desktop_draw_cursor(i32 x, i32 y, u8 buttons) { - u32 ly; - - for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) { - u32 lx; - - for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) { - i32 gx = x + (i32)lx; - i32 gy = y + (i32)ly; - u32 color = 0U; - - if (clks_desktop_cursor_pixel(lx, ly, buttons, &color) == CLKS_FALSE) { - continue; - } - - if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) { - clks_fb_draw_pixel((u32)gx, (u32)gy, color); - } - } - } - - clks_desktop_cursor_drawn = CLKS_TRUE; -} - -static void clks_desktop_present_cursor(const struct clks_mouse_state *mouse) { - if (mouse == CLKS_NULL) { - return; - } - - clks_desktop_restore_cursor_under(); - clks_desktop_capture_cursor_under(mouse->x, mouse->y); - clks_desktop_draw_cursor(mouse->x, mouse->y, mouse->buttons); - - clks_desktop_last_mouse_x = mouse->x; - clks_desktop_last_mouse_y = mouse->y; - clks_desktop_last_buttons = mouse->buttons; - clks_desktop_last_ready = mouse->ready; -} - -void clks_desktop_init(void) { - if (clks_fb_ready() == CLKS_FALSE) { - clks_desktop_ready_flag = CLKS_FALSE; - clks_log(CLKS_LOG_WARN, "DESK", "FRAMEBUFFER NOT READY; DESKTOP DISABLED"); - return; - } - - clks_desktop_compute_layout(); - clks_desktop_ready_flag = CLKS_TRUE; - clks_desktop_active_last = CLKS_FALSE; - clks_desktop_scene_drawn = CLKS_FALSE; - clks_desktop_cursor_drawn = CLKS_FALSE; - clks_desktop_last_mouse_x = -1; - clks_desktop_last_mouse_y = -1; - clks_desktop_last_buttons = 0U; - clks_desktop_last_ready = CLKS_FALSE; - - clks_log(CLKS_LOG_INFO, "DESK", "TTY2 DESKTOP ONLINE"); - clks_log(CLKS_LOG_INFO, "DESK", "MOUSE-FIRST MODE ENABLED"); -} - -void clks_desktop_tick(u64 tick) { - struct clks_mouse_state mouse = {0, 0, 0U, 0ULL, CLKS_FALSE}; - - (void)tick; - - if (clks_desktop_ready_flag == CLKS_FALSE) { - return; - } - - if (clks_tty_active() != CLKS_DESKTOP_TTY_INDEX) { - clks_desktop_active_last = CLKS_FALSE; - clks_desktop_scene_drawn = CLKS_FALSE; - clks_desktop_cursor_drawn = CLKS_FALSE; - return; - } - - clks_mouse_snapshot(&mouse); - - if (clks_desktop_active_last == CLKS_FALSE || clks_desktop_scene_drawn == CLKS_FALSE) { - clks_desktop_compute_layout(); - clks_desktop_draw_static_scene(&mouse); - clks_desktop_present_cursor(&mouse); - clks_desktop_active_last = CLKS_TRUE; - return; - } - - if (mouse.ready != clks_desktop_last_ready || mouse.buttons != clks_desktop_last_buttons) { - clks_desktop_draw_status_widgets(&mouse); - } - - if (mouse.x != clks_desktop_last_mouse_x || mouse.y != clks_desktop_last_mouse_y || - mouse.buttons != clks_desktop_last_buttons) { - clks_desktop_present_cursor(&mouse); - } else { - clks_desktop_last_ready = mouse.ready; - } - - clks_desktop_active_last = CLKS_TRUE; -} - -clks_bool clks_desktop_ready(void) { - return clks_desktop_ready_flag; -} diff --git a/clks/kernel/interface/shell.c b/clks/kernel/interface/shell.c deleted file mode 100644 index 3bc110d..0000000 --- a/clks/kernel/interface/shell.c +++ /dev/null @@ -1,1549 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CLKS_SHELL_LINE_MAX 192U -#define CLKS_SHELL_CMD_MAX 32U -#define CLKS_SHELL_ARG_MAX 160U -#define CLKS_SHELL_NAME_MAX 96U -#define CLKS_SHELL_PATH_MAX 192U -#define CLKS_SHELL_CAT_LIMIT 512U -#define CLKS_SHELL_DMESG_LINE_MAX 256U -#define CLKS_SHELL_DMESG_DEFAULT 64ULL -#define CLKS_SHELL_INPUT_BUDGET 128U -#define CLKS_SHELL_CLEAR_LINES 56U -#define CLKS_SHELL_HISTORY_MAX 16U -#define CLKS_SHELL_PROMPT_TEXT "cleonos> " - -static clks_bool clks_shell_ready = CLKS_FALSE; -static char clks_shell_line[CLKS_SHELL_LINE_MAX]; -static usize clks_shell_line_len = 0U; -static usize clks_shell_cursor = 0U; -static usize clks_shell_rendered_len = 0U; -static char clks_shell_cwd[CLKS_SHELL_PATH_MAX] = "/"; - -static char clks_shell_history[CLKS_SHELL_HISTORY_MAX][CLKS_SHELL_LINE_MAX]; -static u32 clks_shell_history_count = 0U; -static i32 clks_shell_history_nav = -1; -static char clks_shell_nav_saved_line[CLKS_SHELL_LINE_MAX]; -static usize clks_shell_nav_saved_len = 0U; -static usize clks_shell_nav_saved_cursor = 0U; - -static u64 clks_shell_cmd_total = 0ULL; -static u64 clks_shell_cmd_ok = 0ULL; -static u64 clks_shell_cmd_fail = 0ULL; -static u64 clks_shell_cmd_unknown = 0ULL; -static clks_bool clks_shell_pending_command = CLKS_FALSE; -static char clks_shell_pending_line[CLKS_SHELL_LINE_MAX]; - -__attribute__((weak)) void clks_rusttest_hello(void) { - clks_tty_write("rusttest: rust symbol unavailable\n"); -} - -static clks_bool clks_shell_is_space(char ch) { - return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_shell_is_printable(char ch) { - return (ch >= 32 && ch <= 126) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_shell_streq(const char *left, const char *right) { - return (clks_strcmp(left, right) == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static void clks_shell_write(const char *text) { - if (text == CLKS_NULL) { - return; - } - - clks_tty_write(text); -} - -static void clks_shell_write_char(char ch) { - clks_tty_write_char(ch); -} - -static void clks_shell_writeln(const char *text) { - clks_shell_write(text); - clks_shell_write_char('\n'); -} - -static void clks_shell_prompt(void) { - clks_shell_write(CLKS_SHELL_PROMPT_TEXT); -} - -static void clks_shell_copy_line(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || src == CLKS_NULL || dst_size == 0U) { - return; - } - - while (i + 1U < dst_size && src[i] != '\0') { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static void clks_shell_history_cancel_nav(void) { - clks_shell_history_nav = -1; - clks_shell_nav_saved_len = 0U; - clks_shell_nav_saved_cursor = 0U; - clks_shell_nav_saved_line[0] = '\0'; -} - -static void clks_shell_reset_line(void) { - clks_shell_line_len = 0U; - clks_shell_cursor = 0U; - clks_shell_rendered_len = 0U; - clks_shell_line[0] = '\0'; -} - -static void clks_shell_load_line(const char *line) { - if (line == CLKS_NULL) { - clks_shell_reset_line(); - return; - } - - clks_shell_copy_line(clks_shell_line, sizeof(clks_shell_line), line); - clks_shell_line_len = clks_strlen(clks_shell_line); - clks_shell_cursor = clks_shell_line_len; -} - -static void clks_shell_render_line(void) { - usize i; - - if (clks_shell_ready == CLKS_FALSE) { - return; - } - - clks_shell_write_char('\r'); - clks_shell_prompt(); - - for (i = 0U; i < clks_shell_line_len; i++) { - clks_shell_write_char(clks_shell_line[i]); - } - - for (i = clks_shell_line_len; i < clks_shell_rendered_len; i++) { - clks_shell_write_char(' '); - } - - clks_shell_write_char('\r'); - clks_shell_prompt(); - - for (i = 0U; i < clks_shell_cursor; i++) { - clks_shell_write_char(clks_shell_line[i]); - } - - clks_shell_rendered_len = clks_shell_line_len; -} - -static clks_bool clks_shell_line_has_non_space(const char *line) { - usize i = 0U; - - if (line == CLKS_NULL) { - return CLKS_FALSE; - } - - while (line[i] != '\0') { - if (clks_shell_is_space(line[i]) == CLKS_FALSE) { - return CLKS_TRUE; - } - - i++; - } - - return CLKS_FALSE; -} - -static void clks_shell_history_push(const char *line) { - if (clks_shell_line_has_non_space(line) == CLKS_FALSE) { - clks_shell_history_cancel_nav(); - return; - } - - if (clks_shell_history_count > 0U && clks_strcmp(clks_shell_history[clks_shell_history_count - 1U], line) == 0) { - clks_shell_history_cancel_nav(); - return; - } - - if (clks_shell_history_count < CLKS_SHELL_HISTORY_MAX) { - clks_shell_copy_line(clks_shell_history[clks_shell_history_count], - sizeof(clks_shell_history[clks_shell_history_count]), line); - clks_shell_history_count++; - } else { - u32 i; - - for (i = 1U; i < CLKS_SHELL_HISTORY_MAX; i++) { - clks_memcpy(clks_shell_history[i - 1U], clks_shell_history[i], CLKS_SHELL_LINE_MAX); - } - - clks_shell_copy_line(clks_shell_history[CLKS_SHELL_HISTORY_MAX - 1U], - sizeof(clks_shell_history[CLKS_SHELL_HISTORY_MAX - 1U]), line); - } - - clks_shell_history_cancel_nav(); -} - -static void clks_shell_history_apply_current(void) { - if (clks_shell_history_nav >= 0) { - clks_shell_load_line(clks_shell_history[(u32)clks_shell_history_nav]); - } else { - clks_shell_copy_line(clks_shell_line, sizeof(clks_shell_line), clks_shell_nav_saved_line); - clks_shell_line_len = clks_shell_nav_saved_len; - if (clks_shell_line_len > CLKS_SHELL_LINE_MAX - 1U) { - clks_shell_line_len = CLKS_SHELL_LINE_MAX - 1U; - clks_shell_line[clks_shell_line_len] = '\0'; - } - clks_shell_cursor = clks_shell_nav_saved_cursor; - if (clks_shell_cursor > clks_shell_line_len) { - clks_shell_cursor = clks_shell_line_len; - } - } - - clks_shell_render_line(); -} - -static void clks_shell_history_up(void) { - if (clks_shell_history_count == 0U) { - return; - } - - if (clks_shell_history_nav < 0) { - clks_shell_copy_line(clks_shell_nav_saved_line, sizeof(clks_shell_nav_saved_line), clks_shell_line); - clks_shell_nav_saved_len = clks_shell_line_len; - clks_shell_nav_saved_cursor = clks_shell_cursor; - clks_shell_history_nav = (i32)clks_shell_history_count - 1; - } else if (clks_shell_history_nav > 0) { - clks_shell_history_nav--; - } - - clks_shell_history_apply_current(); -} - -static void clks_shell_history_down(void) { - if (clks_shell_history_nav < 0) { - return; - } - - if ((u32)clks_shell_history_nav + 1U < clks_shell_history_count) { - clks_shell_history_nav++; - } else { - clks_shell_history_nav = -1; - } - - clks_shell_history_apply_current(); -} - -static void clks_shell_trim(char *line) { - usize start = 0U; - usize i = 0U; - usize len; - - if (line == CLKS_NULL) { - return; - } - - while (line[start] != '\0' && clks_shell_is_space(line[start]) == CLKS_TRUE) { - start++; - } - - if (start > 0U) { - while (line[start + i] != '\0') { - line[i] = line[start + i]; - i++; - } - - line[i] = '\0'; - } - - len = clks_strlen(line); - - while (len > 0U && clks_shell_is_space(line[len - 1U]) == CLKS_TRUE) { - line[len - 1U] = '\0'; - len--; - } -} - -static void clks_shell_split_line(const char *line, char *out_cmd, usize out_cmd_size, char *out_arg, - usize out_arg_size) { - usize i = 0U; - usize cmd_pos = 0U; - usize arg_pos = 0U; - - if (line == CLKS_NULL || out_cmd == CLKS_NULL || out_arg == CLKS_NULL) { - return; - } - - out_cmd[0] = '\0'; - out_arg[0] = '\0'; - - while (line[i] != '\0' && clks_shell_is_space(line[i]) == CLKS_TRUE) { - i++; - } - - while (line[i] != '\0' && clks_shell_is_space(line[i]) == CLKS_FALSE) { - if (cmd_pos + 1U < out_cmd_size) { - out_cmd[cmd_pos++] = line[i]; - } - i++; - } - - out_cmd[cmd_pos] = '\0'; - - while (line[i] != '\0' && clks_shell_is_space(line[i]) == CLKS_TRUE) { - i++; - } - - while (line[i] != '\0') { - if (arg_pos + 1U < out_arg_size) { - out_arg[arg_pos++] = line[i]; - } - i++; - } - - out_arg[arg_pos] = '\0'; -} - -static clks_bool clks_shell_has_suffix(const char *name, const char *suffix) { - usize name_len; - usize suffix_len; - - if (name == CLKS_NULL || suffix == CLKS_NULL) { - return CLKS_FALSE; - } - - name_len = clks_strlen(name); - suffix_len = clks_strlen(suffix); - - if (suffix_len > name_len) { - return CLKS_FALSE; - } - - return (clks_strcmp(name + (name_len - suffix_len), suffix) == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_shell_resolve_exec_path(const char *arg, char *out_path, usize out_path_size) { - usize cursor = 0U; - usize i; - - if (arg == CLKS_NULL || out_path == CLKS_NULL || out_path_size == 0U) { - return CLKS_FALSE; - } - - if (arg[0] == '\0') { - return CLKS_FALSE; - } - - out_path[0] = '\0'; - - if (arg[0] == '/') { - usize len = clks_strlen(arg); - if (len + 1U > out_path_size) { - return CLKS_FALSE; - } - clks_memcpy(out_path, arg, len + 1U); - return CLKS_TRUE; - } - - { - static const char shell_prefix[] = "/shell/"; - usize prefix_len = (sizeof(shell_prefix) - 1U); - - if (prefix_len + 1U >= out_path_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_path, shell_prefix, prefix_len); - cursor = prefix_len; - } - - for (i = 0U; arg[i] != '\0'; i++) { - if (cursor + 1U >= out_path_size) { - return CLKS_FALSE; - } - - out_path[cursor++] = arg[i]; - } - - out_path[cursor] = '\0'; - - if (clks_shell_has_suffix(out_path, ".elf") == CLKS_FALSE) { - static const char elf_suffix[] = ".elf"; - usize suffix_len = (sizeof(elf_suffix) - 1U); - - if (cursor + suffix_len + 1U > out_path_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_path + cursor, elf_suffix, suffix_len + 1U); - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_path_push_component(char *path, usize path_size, usize *io_len, const char *component, - usize comp_len) { - if (path == CLKS_NULL || io_len == CLKS_NULL || component == CLKS_NULL || comp_len == 0U) { - return CLKS_FALSE; - } - - if (*io_len == 1U) { - if (*io_len + comp_len >= path_size) { - return CLKS_FALSE; - } - - clks_memcpy(path + 1U, component, comp_len); - *io_len = 1U + comp_len; - path[*io_len] = '\0'; - return CLKS_TRUE; - } - - if (*io_len + 1U + comp_len >= path_size) { - return CLKS_FALSE; - } - - path[*io_len] = '/'; - clks_memcpy(path + *io_len + 1U, component, comp_len); - *io_len += (1U + comp_len); - path[*io_len] = '\0'; - return CLKS_TRUE; -} - -static void clks_shell_path_pop_component(char *path, usize *io_len) { - if (path == CLKS_NULL || io_len == CLKS_NULL) { - return; - } - - if (*io_len <= 1U) { - path[0] = '/'; - path[1] = '\0'; - *io_len = 1U; - return; - } - - while (*io_len > 1U && path[*io_len - 1U] != '/') { - (*io_len)--; - } - - if (*io_len > 1U) { - (*io_len)--; - } - - path[*io_len] = '\0'; -} - -static clks_bool clks_shell_path_parse_into(const char *src, char *out_path, usize out_size, usize *io_len) { - usize i = 0U; - - if (src == CLKS_NULL || out_path == CLKS_NULL || io_len == CLKS_NULL) { - return CLKS_FALSE; - } - - if (src[0] == '/') { - i = 1U; - } - - while (src[i] != '\0') { - usize start; - usize len; - - while (src[i] == '/') { - i++; - } - - if (src[i] == '\0') { - break; - } - - start = i; - - while (src[i] != '\0' && src[i] != '/') { - i++; - } - - len = i - start; - - if (len == 1U && src[start] == '.') { - continue; - } - - if (len == 2U && src[start] == '.' && src[start + 1U] == '.') { - clks_shell_path_pop_component(out_path, io_len); - continue; - } - - if (clks_shell_path_push_component(out_path, out_size, io_len, src + start, len) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_resolve_path(const char *arg, char *out_path, usize out_size) { - usize len = 1U; - - if (out_path == CLKS_NULL || out_size < 2U) { - return CLKS_FALSE; - } - - out_path[0] = '/'; - out_path[1] = '\0'; - - if (arg == CLKS_NULL || arg[0] == '\0') { - return clks_shell_path_parse_into(clks_shell_cwd, out_path, out_size, &len); - } - - if (arg[0] != '/') { - if (clks_shell_path_parse_into(clks_shell_cwd, out_path, out_size, &len) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - return clks_shell_path_parse_into(arg, out_path, out_size, &len); -} - -static clks_bool clks_shell_split_first_and_rest(const char *arg, char *out_first, usize out_first_size, - const char **out_rest) { - usize i = 0U; - usize p = 0U; - - if (arg == CLKS_NULL || out_first == CLKS_NULL || out_first_size == 0U || out_rest == CLKS_NULL) { - return CLKS_FALSE; - } - - out_first[0] = '\0'; - *out_rest = ""; - - while (arg[i] != '\0' && clks_shell_is_space(arg[i]) == CLKS_TRUE) { - i++; - } - - if (arg[i] == '\0') { - return CLKS_FALSE; - } - - while (arg[i] != '\0' && clks_shell_is_space(arg[i]) == CLKS_FALSE) { - if (p + 1U < out_first_size) { - out_first[p++] = arg[i]; - } - i++; - } - - out_first[p] = '\0'; - - while (arg[i] != '\0' && clks_shell_is_space(arg[i]) == CLKS_TRUE) { - i++; - } - - *out_rest = &arg[i]; - return CLKS_TRUE; -} - -static clks_bool clks_shell_split_two_args(const char *arg, char *out_first, usize out_first_size, char *out_second, - usize out_second_size) { - usize i = 0U; - usize p = 0U; - - if (arg == CLKS_NULL || out_first == CLKS_NULL || out_first_size == 0U || out_second == CLKS_NULL || - out_second_size == 0U) { - return CLKS_FALSE; - } - - out_first[0] = '\0'; - out_second[0] = '\0'; - - while (arg[i] != '\0' && clks_shell_is_space(arg[i]) == CLKS_TRUE) { - i++; - } - - if (arg[i] == '\0') { - return CLKS_FALSE; - } - - while (arg[i] != '\0' && clks_shell_is_space(arg[i]) == CLKS_FALSE) { - if (p + 1U < out_first_size) { - out_first[p++] = arg[i]; - } - i++; - } - - out_first[p] = '\0'; - - while (arg[i] != '\0' && clks_shell_is_space(arg[i]) == CLKS_TRUE) { - i++; - } - - if (arg[i] == '\0') { - return CLKS_FALSE; - } - - p = 0U; - while (arg[i] != '\0' && clks_shell_is_space(arg[i]) == CLKS_FALSE) { - if (p + 1U < out_second_size) { - out_second[p++] = arg[i]; - } - i++; - } - - out_second[p] = '\0'; - - return (out_first[0] != '\0' && out_second[0] != '\0') ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_shell_parse_u64_dec(const char *text, u64 *out_value) { - u64 value = 0ULL; - usize i = 0U; - - if (text == CLKS_NULL || out_value == CLKS_NULL || text[0] == '\0') { - return CLKS_FALSE; - } - - while (text[i] != '\0') { - u64 digit; - - if (text[i] < '0' || text[i] > '9') { - return CLKS_FALSE; - } - - digit = (u64)(text[i] - '0'); - - if (value > ((0xFFFFFFFFFFFFFFFFULL - digit) / 10ULL)) { - return CLKS_FALSE; - } - - value = (value * 10ULL) + digit; - i++; - } - - *out_value = value; - return CLKS_TRUE; -} - -static clks_bool clks_shell_path_is_under_temp(const char *path) { - if (path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (path[0] != '/' || path[1] != 't' || path[2] != 'e' || path[3] != 'm' || path[4] != 'p') { - return CLKS_FALSE; - } - - return (path[5] == '\0' || path[5] == '/') ? CLKS_TRUE : CLKS_FALSE; -} - -static void clks_shell_write_hex_u64(u64 value) { - int nibble; - - clks_shell_write("0X"); - - for (nibble = 15; nibble >= 0; nibble--) { - u8 current = (u8)((value >> (nibble * 4)) & 0x0FULL); - char out = (current < 10U) ? (char)('0' + current) : (char)('A' + (current - 10U)); - clks_shell_write_char(out); - } -} - -static void clks_shell_print_kv_hex(const char *label, u64 value) { - clks_shell_write(label); - clks_shell_write(": "); - clks_shell_write_hex_u64(value); - clks_shell_write_char('\n'); -} - -static clks_bool clks_shell_cmd_help(void) { - clks_shell_writeln("commands:"); - clks_shell_writeln(" help"); - clks_shell_writeln(" ls [dir]"); - clks_shell_writeln(" cat "); - clks_shell_writeln(" pwd"); - clks_shell_writeln(" cd [dir]"); - clks_shell_writeln(" mkdir (/temp only)"); - clks_shell_writeln(" touch (/temp only)"); - clks_shell_writeln(" write (/temp only)"); - clks_shell_writeln(" append (/temp only)"); - clks_shell_writeln(" cp (dst /temp only)"); - clks_shell_writeln(" mv (/temp only)"); - clks_shell_writeln(" rm (/temp only)"); - clks_shell_writeln(" memstat / fsstat / taskstat"); - clks_shell_writeln(" dmesg [n]"); - clks_shell_writeln(" shstat"); - clks_shell_writeln(" rusttest"); - clks_shell_writeln(" panic"); - clks_shell_writeln(" exec "); - clks_shell_writeln(" elfloader [path] (kernel builtin, default /hello.elf)"); - clks_shell_writeln(" clear"); - clks_shell_writeln(" kbdstat"); - clks_shell_writeln("edit keys: Left/Right, Home/End, Up/Down history"); - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_ls(const char *arg) { - struct clks_fs_node_info info; - char path[CLKS_SHELL_PATH_MAX]; - const char *target = arg; - u64 count; - u64 i; - - if (target == CLKS_NULL || target[0] == '\0') { - target = "."; - } - - if (clks_shell_resolve_path(target, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("ls: invalid path"); - return CLKS_FALSE; - } - - if (clks_fs_stat(path, &info) == CLKS_FALSE || info.type != CLKS_FS_NODE_DIR) { - clks_shell_writeln("ls: directory not found"); - return CLKS_FALSE; - } - - count = clks_fs_count_children(path); - - if (count == 0ULL) { - clks_shell_writeln("(empty)"); - return CLKS_TRUE; - } - - for (i = 0ULL; i < count; i++) { - char name[CLKS_SHELL_NAME_MAX]; - - name[0] = '\0'; - if (clks_fs_get_child_name(path, i, name, sizeof(name)) == CLKS_FALSE) { - continue; - } - - clks_shell_writeln(name); - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_cat(const char *arg) { - const void *data; - u64 size = 0ULL; - u64 copy_len; - char path[CLKS_SHELL_PATH_MAX]; - char out[CLKS_SHELL_CAT_LIMIT + 1U]; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("cat: file path required"); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(arg, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("cat: invalid path"); - return CLKS_FALSE; - } - - data = clks_fs_read_all(path, &size); - - if (data == CLKS_NULL) { - clks_shell_writeln("cat: file not found"); - return CLKS_FALSE; - } - - if (size == 0ULL) { - clks_shell_writeln("(empty file)"); - return CLKS_TRUE; - } - - copy_len = (size < CLKS_SHELL_CAT_LIMIT) ? size : CLKS_SHELL_CAT_LIMIT; - clks_memcpy(out, data, (usize)copy_len); - out[copy_len] = '\0'; - - clks_shell_writeln(out); - - if (size > copy_len) { - clks_shell_writeln("[cat] output truncated"); - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_pwd(void) { - clks_shell_writeln(clks_shell_cwd); - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_cd(const char *arg) { - struct clks_fs_node_info info; - char path[CLKS_SHELL_PATH_MAX]; - const char *target = arg; - - if (target == CLKS_NULL || target[0] == '\0') { - target = "/"; - } - - if (clks_shell_resolve_path(target, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("cd: invalid path"); - return CLKS_FALSE; - } - - if (clks_fs_stat(path, &info) == CLKS_FALSE || info.type != CLKS_FS_NODE_DIR) { - clks_shell_writeln("cd: directory not found"); - return CLKS_FALSE; - } - - clks_shell_copy_line(clks_shell_cwd, sizeof(clks_shell_cwd), path); - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_mkdir(const char *arg) { - char path[CLKS_SHELL_PATH_MAX]; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("mkdir: directory path required"); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(arg, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("mkdir: invalid path"); - return CLKS_FALSE; - } - - if (clks_shell_path_is_under_temp(path) == CLKS_FALSE) { - clks_shell_writeln("mkdir: target must be under /temp"); - return CLKS_FALSE; - } - - if (clks_fs_mkdir(path) == CLKS_FALSE) { - clks_shell_writeln("mkdir: failed"); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_touch(const char *arg) { - static const char empty_data[1] = {'\0'}; - char path[CLKS_SHELL_PATH_MAX]; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("touch: file path required"); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(arg, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("touch: invalid path"); - return CLKS_FALSE; - } - - if (clks_shell_path_is_under_temp(path) == CLKS_FALSE) { - clks_shell_writeln("touch: target must be under /temp"); - return CLKS_FALSE; - } - - if (clks_fs_write_all(path, empty_data, 0ULL) == CLKS_FALSE) { - clks_shell_writeln("touch: failed"); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_write(const char *arg) { - char path_arg[CLKS_SHELL_PATH_MAX]; - char abs_path[CLKS_SHELL_PATH_MAX]; - const char *payload; - u64 payload_len; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("write: usage write "); - return CLKS_FALSE; - } - - if (clks_shell_split_first_and_rest(arg, path_arg, sizeof(path_arg), &payload) == CLKS_FALSE) { - clks_shell_writeln("write: usage write "); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(path_arg, abs_path, sizeof(abs_path)) == CLKS_FALSE) { - clks_shell_writeln("write: invalid path"); - return CLKS_FALSE; - } - - if (clks_shell_path_is_under_temp(abs_path) == CLKS_FALSE) { - clks_shell_writeln("write: target must be under /temp"); - return CLKS_FALSE; - } - - payload_len = clks_strlen(payload); - - if (clks_fs_write_all(abs_path, payload, payload_len) == CLKS_FALSE) { - clks_shell_writeln("write: failed"); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_append(const char *arg) { - char path_arg[CLKS_SHELL_PATH_MAX]; - char abs_path[CLKS_SHELL_PATH_MAX]; - const char *payload; - u64 payload_len; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("append: usage append "); - return CLKS_FALSE; - } - - if (clks_shell_split_first_and_rest(arg, path_arg, sizeof(path_arg), &payload) == CLKS_FALSE) { - clks_shell_writeln("append: usage append "); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(path_arg, abs_path, sizeof(abs_path)) == CLKS_FALSE) { - clks_shell_writeln("append: invalid path"); - return CLKS_FALSE; - } - - if (clks_shell_path_is_under_temp(abs_path) == CLKS_FALSE) { - clks_shell_writeln("append: target must be under /temp"); - return CLKS_FALSE; - } - - payload_len = clks_strlen(payload); - - if (clks_fs_append(abs_path, payload, payload_len) == CLKS_FALSE) { - clks_shell_writeln("append: failed"); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_cp(const char *arg) { - char src_arg[CLKS_SHELL_PATH_MAX]; - char dst_arg[CLKS_SHELL_PATH_MAX]; - char src_path[CLKS_SHELL_PATH_MAX]; - char dst_path[CLKS_SHELL_PATH_MAX]; - struct clks_fs_node_info info; - const void *data; - u64 size = 0ULL; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("cp: usage cp "); - return CLKS_FALSE; - } - - if (clks_shell_split_two_args(arg, src_arg, sizeof(src_arg), dst_arg, sizeof(dst_arg)) == CLKS_FALSE) { - clks_shell_writeln("cp: usage cp "); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(src_arg, src_path, sizeof(src_path)) == CLKS_FALSE || - clks_shell_resolve_path(dst_arg, dst_path, sizeof(dst_path)) == CLKS_FALSE) { - clks_shell_writeln("cp: invalid path"); - return CLKS_FALSE; - } - - if (clks_shell_path_is_under_temp(dst_path) == CLKS_FALSE) { - clks_shell_writeln("cp: destination must be under /temp"); - return CLKS_FALSE; - } - - if (clks_fs_stat(src_path, &info) == CLKS_FALSE || info.type != CLKS_FS_NODE_FILE) { - clks_shell_writeln("cp: source file not found"); - return CLKS_FALSE; - } - - data = clks_fs_read_all(src_path, &size); - - if (data == CLKS_NULL) { - clks_shell_writeln("cp: failed to read source"); - return CLKS_FALSE; - } - - if (clks_fs_write_all(dst_path, data, size) == CLKS_FALSE) { - clks_shell_writeln("cp: failed to write destination"); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_mv(const char *arg) { - char src_arg[CLKS_SHELL_PATH_MAX]; - char dst_arg[CLKS_SHELL_PATH_MAX]; - char src_path[CLKS_SHELL_PATH_MAX]; - char dst_path[CLKS_SHELL_PATH_MAX]; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("mv: usage mv "); - return CLKS_FALSE; - } - - if (clks_shell_split_two_args(arg, src_arg, sizeof(src_arg), dst_arg, sizeof(dst_arg)) == CLKS_FALSE) { - clks_shell_writeln("mv: usage mv "); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(src_arg, src_path, sizeof(src_path)) == CLKS_FALSE || - clks_shell_resolve_path(dst_arg, dst_path, sizeof(dst_path)) == CLKS_FALSE) { - clks_shell_writeln("mv: invalid path"); - return CLKS_FALSE; - } - - if (clks_shell_path_is_under_temp(src_path) == CLKS_FALSE || - clks_shell_path_is_under_temp(dst_path) == CLKS_FALSE) { - clks_shell_writeln("mv: source and destination must be under /temp"); - return CLKS_FALSE; - } - - if (clks_shell_cmd_cp(arg) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_remove(src_path) == CLKS_FALSE) { - clks_shell_writeln("mv: source remove failed"); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_rm(const char *arg) { - char path[CLKS_SHELL_PATH_MAX]; - - if (arg == CLKS_NULL || arg[0] == '\0') { - clks_shell_writeln("rm: path required"); - return CLKS_FALSE; - } - - if (clks_shell_resolve_path(arg, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("rm: invalid path"); - return CLKS_FALSE; - } - - if (clks_shell_path_is_under_temp(path) == CLKS_FALSE) { - clks_shell_writeln("rm: target must be under /temp"); - return CLKS_FALSE; - } - - if (clks_fs_remove(path) == CLKS_FALSE) { - clks_shell_writeln("rm: failed (directory must be empty)"); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_elfloader(const char *arg) { - const char *target = arg; - char path[CLKS_SHELL_PATH_MAX]; - const void *image; - u64 size = 0ULL; - struct clks_elf64_info info; - u64 status = (u64)-1; - - if (target == CLKS_NULL || target[0] == '\0') { - target = "/hello.elf"; - } - - if (target[0] == '/') { - clks_shell_copy_line(path, sizeof(path), target); - } else if (clks_shell_resolve_path(target, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("elfloader: invalid path"); - return CLKS_FALSE; - } - - image = clks_fs_read_all(path, &size); - - if (image == CLKS_NULL || size == 0ULL) { - clks_shell_writeln("elfloader: file missing"); - return CLKS_FALSE; - } - - if (clks_elf64_inspect(image, size, &info) == CLKS_FALSE) { - clks_shell_writeln("elfloader: invalid elf64"); - return CLKS_FALSE; - } - - clks_shell_writeln("elfloader: kernel builtin"); - clks_shell_write(" PATH: "); - clks_shell_writeln(path); - clks_shell_print_kv_hex(" ELF_SIZE", size); - clks_shell_print_kv_hex(" ENTRY", info.entry); - clks_shell_print_kv_hex(" PHNUM", (u64)info.phnum); - clks_shell_print_kv_hex(" LOAD_SEGMENTS", (u64)info.loadable_segments); - clks_shell_print_kv_hex(" TOTAL_MEMSZ", info.total_load_memsz); - - if (clks_exec_run_path(path, &status) == CLKS_TRUE && status == 0ULL) { - clks_shell_writeln("elfloader: exec accepted"); - return CLKS_TRUE; - } - - clks_shell_writeln("elfloader: exec failed"); - return CLKS_FALSE; -} - -static clks_bool clks_shell_cmd_exec(const char *arg) { - char path[CLKS_SHELL_PATH_MAX]; - u64 status = (u64)-1; - - if (clks_shell_resolve_exec_path(arg, path, sizeof(path)) == CLKS_FALSE) { - clks_shell_writeln("exec: invalid target"); - return CLKS_FALSE; - } - - if (clks_exec_run_path(path, &status) == CLKS_TRUE && status == 0ULL) { - clks_shell_writeln("exec: request accepted"); - return CLKS_TRUE; - } - - clks_shell_writeln("exec: request failed"); - return CLKS_FALSE; -} - -static clks_bool clks_shell_cmd_clear(void) { - u32 i; - - for (i = 0U; i < CLKS_SHELL_CLEAR_LINES; i++) { - clks_shell_write_char('\n'); - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_kbdstat(void) { - clks_shell_writeln("kbd stats emitted to kernel log"); - clks_log_hex(CLKS_LOG_INFO, "KBD", "BUFFERED", clks_keyboard_buffered_count()); - clks_log_hex(CLKS_LOG_INFO, "KBD", "PUSHED", clks_keyboard_push_count()); - clks_log_hex(CLKS_LOG_INFO, "KBD", "POPPED", clks_keyboard_pop_count()); - clks_log_hex(CLKS_LOG_INFO, "KBD", "DROPPED", clks_keyboard_drop_count()); - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_memstat(void) { - struct clks_pmm_stats pmm_stats = clks_pmm_get_stats(); - struct clks_heap_stats heap_stats = clks_heap_get_stats(); - - clks_shell_writeln("memstat:"); - clks_shell_print_kv_hex(" PMM_MANAGED_PAGES", pmm_stats.managed_pages); - clks_shell_print_kv_hex(" PMM_FREE_PAGES", pmm_stats.free_pages); - clks_shell_print_kv_hex(" PMM_USED_PAGES", pmm_stats.used_pages); - clks_shell_print_kv_hex(" PMM_DROPPED_PAGES", pmm_stats.dropped_pages); - clks_shell_print_kv_hex(" HEAP_TOTAL_BYTES", (u64)heap_stats.total_bytes); - clks_shell_print_kv_hex(" HEAP_USED_BYTES", (u64)heap_stats.used_bytes); - clks_shell_print_kv_hex(" HEAP_FREE_BYTES", (u64)heap_stats.free_bytes); - clks_shell_print_kv_hex(" HEAP_ALLOC_COUNT", heap_stats.alloc_count); - clks_shell_print_kv_hex(" HEAP_FREE_COUNT", heap_stats.free_count); - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_fsstat(void) { - clks_shell_writeln("fsstat:"); - clks_shell_print_kv_hex(" NODE_COUNT", clks_fs_node_count()); - clks_shell_print_kv_hex(" ROOT_CHILDREN", clks_fs_count_children("/")); - clks_shell_print_kv_hex(" SYSTEM_CHILDREN", clks_fs_count_children("/system")); - clks_shell_print_kv_hex(" SHELL_CHILDREN", clks_fs_count_children("/shell")); - clks_shell_print_kv_hex(" TEMP_CHILDREN", clks_fs_count_children("/temp")); - clks_shell_print_kv_hex(" DRIVER_CHILDREN", clks_fs_count_children("/driver")); - clks_shell_print_kv_hex(" DEV_CHILDREN", clks_fs_count_children("/dev")); - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_taskstat(void) { - struct clks_scheduler_stats sched = clks_scheduler_get_stats(); - u32 i; - - clks_shell_writeln("taskstat:"); - clks_shell_print_kv_hex(" TASK_COUNT", (u64)sched.task_count); - clks_shell_print_kv_hex(" CURRENT_TASK_ID", (u64)sched.current_task_id); - clks_shell_print_kv_hex(" TOTAL_TIMER_TICKS", sched.total_timer_ticks); - clks_shell_print_kv_hex(" CONTEXT_SWITCH_COUNT", sched.context_switch_count); - - for (i = 0U; i < sched.task_count; i++) { - const struct clks_task_descriptor *task = clks_scheduler_get_task(i); - - if (task == CLKS_NULL) { - continue; - } - - clks_shell_write(" task["); - clks_shell_write_hex_u64((u64)task->id); - clks_shell_write("] "); - clks_shell_write(task->name); - clks_shell_write(" state="); - clks_shell_write_hex_u64((u64)task->state); - clks_shell_write(" slice="); - clks_shell_write_hex_u64((u64)task->time_slice_ticks); - clks_shell_write(" remain="); - clks_shell_write_hex_u64((u64)task->remaining_ticks); - clks_shell_write(" run="); - clks_shell_write_hex_u64(task->run_count); - clks_shell_write(" switch="); - clks_shell_write_hex_u64(task->switch_count); - clks_shell_write(" last="); - clks_shell_write_hex_u64(task->last_run_tick); - clks_shell_write_char('\n'); - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_dmesg(const char *arg) { - u64 total = clks_log_journal_count(); - u64 limit = CLKS_SHELL_DMESG_DEFAULT; - u64 start; - u64 i; - - if (arg != CLKS_NULL && arg[0] != '\0') { - if (clks_shell_parse_u64_dec(arg, &limit) == CLKS_FALSE || limit == 0ULL) { - clks_shell_writeln("dmesg: usage dmesg [positive_count]"); - return CLKS_FALSE; - } - } - - if (total == 0ULL) { - clks_shell_writeln("(journal empty)"); - return CLKS_TRUE; - } - - if (limit > total) { - limit = total; - } - - start = total - limit; - - for (i = start; i < total; i++) { - char line[CLKS_SHELL_DMESG_LINE_MAX]; - - if (clks_log_journal_read(i, line, sizeof(line)) == CLKS_TRUE) { - clks_shell_writeln(line); - } - } - - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_shstat(void) { - clks_shell_writeln("shstat:"); - clks_shell_print_kv_hex(" CMD_TOTAL", clks_shell_cmd_total); - clks_shell_print_kv_hex(" CMD_OK", clks_shell_cmd_ok); - clks_shell_print_kv_hex(" CMD_FAIL", clks_shell_cmd_fail); - clks_shell_print_kv_hex(" CMD_UNKNOWN", clks_shell_cmd_unknown); - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_rusttest(void) { - clks_rusttest_hello(); - return CLKS_TRUE; -} - -static clks_bool clks_shell_cmd_panic(void) { - clks_panic("MANUAL PANIC FROM KERNEL SHELL"); - return CLKS_FALSE; -} - -static void clks_shell_execute_line(const char *line) { - char line_buf[CLKS_SHELL_LINE_MAX]; - char cmd[CLKS_SHELL_CMD_MAX]; - char arg[CLKS_SHELL_ARG_MAX]; - usize i = 0U; - clks_bool known = CLKS_TRUE; - clks_bool success = CLKS_FALSE; - - if (line == CLKS_NULL) { - return; - } - - while (line[i] != '\0' && i + 1U < sizeof(line_buf)) { - line_buf[i] = line[i]; - i++; - } - - line_buf[i] = '\0'; - clks_shell_trim(line_buf); - - if (line_buf[0] == '\0') { - return; - } - - clks_shell_split_line(line_buf, cmd, sizeof(cmd), arg, sizeof(arg)); - - if (clks_shell_streq(cmd, "help") == CLKS_TRUE) { - success = clks_shell_cmd_help(); - } else if (clks_shell_streq(cmd, "ls") == CLKS_TRUE) { - success = clks_shell_cmd_ls(arg); - } else if (clks_shell_streq(cmd, "cat") == CLKS_TRUE) { - success = clks_shell_cmd_cat(arg); - } else if (clks_shell_streq(cmd, "pwd") == CLKS_TRUE) { - success = clks_shell_cmd_pwd(); - } else if (clks_shell_streq(cmd, "cd") == CLKS_TRUE) { - success = clks_shell_cmd_cd(arg); - } else if (clks_shell_streq(cmd, "mkdir") == CLKS_TRUE) { - success = clks_shell_cmd_mkdir(arg); - } else if (clks_shell_streq(cmd, "touch") == CLKS_TRUE) { - success = clks_shell_cmd_touch(arg); - } else if (clks_shell_streq(cmd, "write") == CLKS_TRUE) { - success = clks_shell_cmd_write(arg); - } else if (clks_shell_streq(cmd, "append") == CLKS_TRUE) { - success = clks_shell_cmd_append(arg); - } else if (clks_shell_streq(cmd, "cp") == CLKS_TRUE) { - success = clks_shell_cmd_cp(arg); - } else if (clks_shell_streq(cmd, "mv") == CLKS_TRUE) { - success = clks_shell_cmd_mv(arg); - } else if (clks_shell_streq(cmd, "rm") == CLKS_TRUE) { - success = clks_shell_cmd_rm(arg); - } else if (clks_shell_streq(cmd, "memstat") == CLKS_TRUE) { - success = clks_shell_cmd_memstat(); - } else if (clks_shell_streq(cmd, "fsstat") == CLKS_TRUE) { - success = clks_shell_cmd_fsstat(); - } else if (clks_shell_streq(cmd, "taskstat") == CLKS_TRUE) { - success = clks_shell_cmd_taskstat(); - } else if (clks_shell_streq(cmd, "dmesg") == CLKS_TRUE) { - success = clks_shell_cmd_dmesg(arg); - } else if (clks_shell_streq(cmd, "shstat") == CLKS_TRUE) { - success = clks_shell_cmd_shstat(); - } else if (clks_shell_streq(cmd, "rusttest") == CLKS_TRUE) { - success = clks_shell_cmd_rusttest(); - } else if (clks_shell_streq(cmd, "panic") == CLKS_TRUE) { - success = clks_shell_cmd_panic(); - } else if (clks_shell_streq(cmd, "elfloader") == CLKS_TRUE) { - success = clks_shell_cmd_elfloader(arg); - } else if (clks_shell_streq(cmd, "exec") == CLKS_TRUE || clks_shell_streq(cmd, "run") == CLKS_TRUE) { - success = clks_shell_cmd_exec(arg); - } else if (clks_shell_streq(cmd, "clear") == CLKS_TRUE) { - success = clks_shell_cmd_clear(); - } else if (clks_shell_streq(cmd, "kbdstat") == CLKS_TRUE) { - success = clks_shell_cmd_kbdstat(); - } else { - known = CLKS_FALSE; - success = CLKS_FALSE; - clks_shell_writeln("unknown command; type 'help'"); - } - - clks_shell_cmd_total++; - - if (success == CLKS_TRUE) { - clks_shell_cmd_ok++; - } else { - clks_shell_cmd_fail++; - } - - if (known == CLKS_FALSE) { - clks_shell_cmd_unknown++; - } -} - -static void clks_shell_process_pending_command(void) { - if (clks_shell_ready == CLKS_FALSE || clks_shell_pending_command == CLKS_FALSE) { - return; - } - - clks_shell_pending_command = CLKS_FALSE; - clks_shell_execute_line(clks_shell_pending_line); - clks_shell_pending_line[0] = '\0'; -} - -static void clks_shell_handle_char(char ch) { - if (ch == '\r') { - return; - } - - if (ch == '\n') { - clks_shell_write_char('\n'); - clks_shell_line[clks_shell_line_len] = '\0'; - clks_shell_history_push(clks_shell_line); - - if (clks_shell_pending_command == CLKS_FALSE) { - clks_shell_copy_line(clks_shell_pending_line, sizeof(clks_shell_pending_line), clks_shell_line); - clks_shell_pending_command = CLKS_TRUE; - } else { - clks_shell_writeln("shell: command queue busy"); - } - - clks_shell_reset_line(); - clks_shell_history_cancel_nav(); - clks_shell_prompt(); - return; - } - - if (ch == CLKS_KEY_UP) { - clks_shell_history_up(); - return; - } - - if (ch == CLKS_KEY_DOWN) { - clks_shell_history_down(); - return; - } - - if (ch == CLKS_KEY_LEFT) { - if (clks_shell_cursor > 0U) { - clks_shell_cursor--; - clks_shell_render_line(); - } - return; - } - - if (ch == CLKS_KEY_RIGHT) { - if (clks_shell_cursor < clks_shell_line_len) { - clks_shell_cursor++; - clks_shell_render_line(); - } - return; - } - - if (ch == CLKS_KEY_HOME) { - if (clks_shell_cursor != 0U) { - clks_shell_cursor = 0U; - clks_shell_render_line(); - } - return; - } - - if (ch == CLKS_KEY_END) { - if (clks_shell_cursor != clks_shell_line_len) { - clks_shell_cursor = clks_shell_line_len; - clks_shell_render_line(); - } - return; - } - - if (ch == '\b') { - if (clks_shell_cursor > 0U && clks_shell_line_len > 0U) { - usize i; - - clks_shell_history_cancel_nav(); - - for (i = clks_shell_cursor - 1U; i < clks_shell_line_len; i++) { - clks_shell_line[i] = clks_shell_line[i + 1U]; - } - - clks_shell_line_len--; - clks_shell_cursor--; - clks_shell_render_line(); - } - return; - } - - if (ch == CLKS_KEY_DELETE) { - if (clks_shell_cursor < clks_shell_line_len) { - usize i; - - clks_shell_history_cancel_nav(); - - for (i = clks_shell_cursor; i < clks_shell_line_len; i++) { - clks_shell_line[i] = clks_shell_line[i + 1U]; - } - - clks_shell_line_len--; - clks_shell_render_line(); - } - return; - } - - if (ch == '\t') { - ch = ' '; - } - - if (clks_shell_is_printable(ch) == CLKS_FALSE) { - return; - } - - if (clks_shell_line_len + 1U >= CLKS_SHELL_LINE_MAX) { - return; - } - - clks_shell_history_cancel_nav(); - - if (clks_shell_cursor == clks_shell_line_len) { - clks_shell_line[clks_shell_line_len++] = ch; - clks_shell_line[clks_shell_line_len] = '\0'; - clks_shell_cursor = clks_shell_line_len; - clks_shell_write_char(ch); - clks_shell_rendered_len = clks_shell_line_len; - return; - } - - { - usize i; - - for (i = clks_shell_line_len; i > clks_shell_cursor; i--) { - clks_shell_line[i] = clks_shell_line[i - 1U]; - } - - clks_shell_line[clks_shell_cursor] = ch; - clks_shell_line_len++; - clks_shell_cursor++; - clks_shell_line[clks_shell_line_len] = '\0'; - clks_shell_render_line(); - } -} - -void clks_shell_init(void) { - clks_shell_reset_line(); - clks_shell_history_count = 0U; - clks_shell_history_cancel_nav(); - clks_shell_copy_line(clks_shell_cwd, sizeof(clks_shell_cwd), "/"); - clks_shell_cmd_total = 0ULL; - clks_shell_cmd_ok = 0ULL; - clks_shell_cmd_fail = 0ULL; - clks_shell_cmd_unknown = 0ULL; - clks_shell_pending_command = CLKS_FALSE; - clks_shell_pending_line[0] = '\0'; - - if (clks_tty_ready() == CLKS_FALSE) { - clks_shell_ready = CLKS_FALSE; - clks_log(CLKS_LOG_WARN, "SHELL", "TTY NOT READY; SHELL DISABLED"); - return; - } - - clks_shell_ready = CLKS_TRUE; - - clks_shell_writeln(""); - clks_shell_writeln("CLeonOS interactive shell ready"); - clks_shell_writeln("type 'help' for commands"); - clks_shell_writeln("/temp is writable in kernel shell mode"); - clks_shell_prompt(); - - clks_log(CLKS_LOG_INFO, "SHELL", "INTERACTIVE LOOP ONLINE"); -} - -static void clks_shell_drain_input(u32 budget_limit) { - u32 budget = 0U; - char ch; - - if (budget_limit == 0U || clks_shell_ready == CLKS_FALSE) { - return; - } - - while (budget < budget_limit) { - if (clks_keyboard_pop_char(&ch) == CLKS_FALSE) { - break; - } - - clks_shell_handle_char(ch); - budget++; - } -} - -void clks_shell_pump_input(u32 max_chars) { - clks_shell_drain_input(max_chars); -} - -void clks_shell_tick(u64 tick) { - (void)tick; - clks_shell_drain_input(CLKS_SHELL_INPUT_BUDGET); - clks_shell_process_pending_command(); -} diff --git a/clks/kernel/interface/tty.c b/clks/kernel/interface/tty.c deleted file mode 100644 index 92c3a01..0000000 --- a/clks/kernel/interface/tty.c +++ /dev/null @@ -1,1432 +0,0 @@ -#include -#include -#include -#include -#include - -/* Terminal code: where simple text output turns into a whole damn life choice. */ - -#define CLKS_TTY_COUNT 4 -#define CLKS_TTY_MAX_ROWS 128 -#define CLKS_TTY_MAX_COLS 256 - -#define CLKS_TTY_FG 0x00E6E6E6U -#define CLKS_TTY_BG 0x00101010U -#define CLKS_TTY_CURSOR_BLINK_INTERVAL_TICKS 5ULL -#define CLKS_TTY_BLINK_TICK_UNSET 0xFFFFFFFFFFFFFFFFULL -#define CLKS_TTY_DESKTOP_INDEX 1U -#define CLKS_TTY_ANSI_MAX_LEN 95U -#define CLKS_TTY_SCROLLBACK_LINES 256U -#define CLKS_TTY_STYLE_NONE 0U -#define CLKS_TTY_STYLE_BOLD ((u8)CLKS_FB_STYLE_BOLD) -#define CLKS_TTY_STYLE_UNDERLINE ((u8)CLKS_FB_STYLE_UNDERLINE) -#define CLKS_TTY_STATUS_BG 0x00202020U -#define CLKS_TTY_STATUS_FG 0x00E6E6E6U -#define CLKS_TTY_STATUS_STYLE CLKS_TTY_STYLE_BOLD - -typedef struct clks_tty_ansi_state { - clks_bool in_escape; - clks_bool saw_csi; - clks_bool bold; - clks_bool underline; - clks_bool inverse; - u32 saved_row; - u32 saved_col; - u32 len; - char params[CLKS_TTY_ANSI_MAX_LEN + 1U]; -} clks_tty_ansi_state; - -static char clks_tty_cells[CLKS_TTY_COUNT][CLKS_TTY_MAX_ROWS][CLKS_TTY_MAX_COLS]; -static u32 clks_tty_cell_fg[CLKS_TTY_COUNT][CLKS_TTY_MAX_ROWS][CLKS_TTY_MAX_COLS]; -static u32 clks_tty_cell_bg[CLKS_TTY_COUNT][CLKS_TTY_MAX_ROWS][CLKS_TTY_MAX_COLS]; -static u8 clks_tty_cell_style[CLKS_TTY_COUNT][CLKS_TTY_MAX_ROWS][CLKS_TTY_MAX_COLS]; -static u32 clks_tty_cursor_row[CLKS_TTY_COUNT]; -static u32 clks_tty_cursor_col[CLKS_TTY_COUNT]; -static u32 clks_tty_current_fg[CLKS_TTY_COUNT]; -static u32 clks_tty_current_bg[CLKS_TTY_COUNT]; -static clks_tty_ansi_state clks_tty_ansi[CLKS_TTY_COUNT]; -static char clks_tty_scrollback_cells[CLKS_TTY_COUNT][CLKS_TTY_SCROLLBACK_LINES][CLKS_TTY_MAX_COLS]; -static u32 clks_tty_scrollback_fg[CLKS_TTY_COUNT][CLKS_TTY_SCROLLBACK_LINES][CLKS_TTY_MAX_COLS]; -static u32 clks_tty_scrollback_bg[CLKS_TTY_COUNT][CLKS_TTY_SCROLLBACK_LINES][CLKS_TTY_MAX_COLS]; -static u8 clks_tty_scrollback_style[CLKS_TTY_COUNT][CLKS_TTY_SCROLLBACK_LINES][CLKS_TTY_MAX_COLS]; -static u32 clks_tty_scrollback_head[CLKS_TTY_COUNT]; -static u32 clks_tty_scrollback_count[CLKS_TTY_COUNT]; -static u32 clks_tty_scrollback_offset[CLKS_TTY_COUNT]; - -static u32 clks_tty_rows = 0; -static u32 clks_tty_cols = 0; -static u32 clks_tty_active_index = 0; -static u32 clks_tty_cell_width = 8U; -static u32 clks_tty_cell_height = 8U; -static clks_bool clks_tty_is_ready = CLKS_FALSE; -static clks_bool clks_tty_cursor_visible = CLKS_FALSE; -static clks_bool clks_tty_blink_enabled = CLKS_TRUE; -static clks_bool clks_tty_defer_draw = CLKS_FALSE; -static clks_bool clks_tty_dirty_any = CLKS_FALSE; -static clks_bool clks_tty_dirty_rows[CLKS_TTY_MAX_ROWS]; -static u64 clks_tty_blink_last_tick = CLKS_TTY_BLINK_TICK_UNSET; - -static u32 clks_tty_content_rows(void); -static clks_bool clks_tty_scrollback_is_active(u32 tty_index); -static void clks_tty_redraw_active(void); - -static u32 clks_tty_ansi_palette(u32 index) { - /* Good-enough ANSI colors, because perfect fidelity can wait until never. */ - static const u32 palette[16] = {0x00000000U, 0x00CD3131U, 0x000DBC79U, 0x00E5E510U, 0x002472C8U, 0x00BC3FBCU, - 0x0011A8CDU, 0x00E5E5E5U, 0x00666666U, 0x00F14C4CU, 0x0023D18BU, 0x00F5F543U, - 0x003B8EEAU, 0x00D670D6U, 0x0029B8DBU, 0x00FFFFFFU}; - - if (index < 16U) { - return palette[index]; - } - - return CLKS_TTY_FG; -} - -static void clks_tty_reset_blink_timer(void) { - clks_tty_blink_last_tick = CLKS_TTY_BLINK_TICK_UNSET; -} - -static void clks_tty_draw_cell_with_colors(u32 row, u32 col, char ch, u32 fg, u32 bg, u8 style) { - clks_fb_draw_char_styled(col * clks_tty_cell_width, row * clks_tty_cell_height, ch, fg, bg, (u32)style); -} - -static void clks_tty_draw_cell(u32 tty_index, u32 row, u32 col) { - clks_tty_draw_cell_with_colors(row, col, clks_tty_cells[tty_index][row][col], clks_tty_cell_fg[tty_index][row][col], - clks_tty_cell_bg[tty_index][row][col], clks_tty_cell_style[tty_index][row][col]); -} - -static void clks_tty_dirty_reset(void) { - clks_memset(clks_tty_dirty_rows, 0, sizeof(clks_tty_dirty_rows)); - clks_tty_dirty_any = CLKS_FALSE; -} - -static void clks_tty_dirty_mark_row(u32 row) { - if (row >= clks_tty_content_rows() || row >= CLKS_TTY_MAX_ROWS) { - return; - } - - clks_tty_dirty_rows[row] = CLKS_TRUE; - clks_tty_dirty_any = CLKS_TRUE; -} - -static void clks_tty_dirty_mark_cell(u32 row, u32 col) { - if (col >= clks_tty_cols) { - return; - } - - clks_tty_dirty_mark_row(row); -} - -static void clks_tty_flush_dirty(void) { - u32 tty_index; - u32 row; - u32 col; - - if (clks_tty_is_ready == CLKS_FALSE || clks_tty_dirty_any == CLKS_FALSE) { - return; - } - - tty_index = clks_tty_active_index; - - if (clks_tty_scrollback_is_active(tty_index) == CLKS_TRUE) { - clks_tty_redraw_active(); - clks_tty_dirty_reset(); - return; - } - - /* Dirty-row redraw: cheap as hell, but it keeps typing snappy. */ - for (row = 0U; row < clks_tty_content_rows(); row++) { - if (clks_tty_dirty_rows[row] != CLKS_TRUE) { - continue; - } - - for (col = 0U; col < clks_tty_cols; col++) { - clks_tty_draw_cell(tty_index, row, col); - } - } - - clks_tty_dirty_reset(); -} - -static u32 clks_tty_scrollback_logical_to_physical(u32 tty_index, u32 logical_index) { - u32 count = clks_tty_scrollback_count[tty_index]; - - if (count < CLKS_TTY_SCROLLBACK_LINES) { - return logical_index; - } - - return (clks_tty_scrollback_head[tty_index] + logical_index) % CLKS_TTY_SCROLLBACK_LINES; -} - -static u32 clks_tty_scrollback_max_offset(u32 tty_index) { - return clks_tty_scrollback_count[tty_index]; -} - -static u32 clks_tty_scrollback_clamped_offset(u32 tty_index) { - u32 max_offset = clks_tty_scrollback_max_offset(tty_index); - - if (clks_tty_scrollback_offset[tty_index] > max_offset) { - clks_tty_scrollback_offset[tty_index] = max_offset; - } - - return clks_tty_scrollback_offset[tty_index]; -} - -static void clks_tty_scrollback_push_row(u32 tty_index, u32 row) { - u32 slot = clks_tty_scrollback_head[tty_index]; - - /* Save the line before scroll nukes it, because users always want it back. */ - clks_memcpy(clks_tty_scrollback_cells[tty_index][slot], clks_tty_cells[tty_index][row], clks_tty_cols); - clks_memcpy(clks_tty_scrollback_fg[tty_index][slot], clks_tty_cell_fg[tty_index][row], - (usize)clks_tty_cols * sizeof(u32)); - clks_memcpy(clks_tty_scrollback_bg[tty_index][slot], clks_tty_cell_bg[tty_index][row], - (usize)clks_tty_cols * sizeof(u32)); - clks_memcpy(clks_tty_scrollback_style[tty_index][slot], clks_tty_cell_style[tty_index][row], clks_tty_cols); - - clks_tty_scrollback_head[tty_index] = (slot + 1U) % CLKS_TTY_SCROLLBACK_LINES; - - if (clks_tty_scrollback_count[tty_index] < CLKS_TTY_SCROLLBACK_LINES) { - clks_tty_scrollback_count[tty_index]++; - } -} - -static clks_bool clks_tty_scrollback_is_active(u32 tty_index) { - return (clks_tty_scrollback_offset[tty_index] > 0U) ? CLKS_TRUE : CLKS_FALSE; -} - -static void clks_tty_scrollback_follow_tail(u32 tty_index) { - clks_tty_scrollback_offset[tty_index] = 0U; -} - -static u32 clks_tty_content_rows(void) { - if (clks_tty_rows > 1U) { - return clks_tty_rows - 1U; - } - - return clks_tty_rows; -} - -static clks_bool clks_tty_status_bar_enabled(void) { - return (clks_tty_rows > 1U) ? CLKS_TRUE : CLKS_FALSE; -} - -static void clks_tty_status_append_char(char *line, u32 line_size, u32 *cursor, char ch) { - if (line == CLKS_NULL || cursor == CLKS_NULL || *cursor >= line_size) { - return; - } - - line[*cursor] = ch; - (*cursor)++; -} - -static void clks_tty_status_append_text(char *line, u32 line_size, u32 *cursor, const char *text) { - u32 i = 0U; - - if (text == CLKS_NULL) { - return; - } - - while (text[i] != '\0') { - clks_tty_status_append_char(line, line_size, cursor, text[i]); - i++; - } -} - -static void clks_tty_status_append_u32_dec(char *line, u32 line_size, u32 *cursor, u32 value) { - char tmp[10]; - u32 len = 0U; - - if (value == 0U) { - clks_tty_status_append_char(line, line_size, cursor, '0'); - return; - } - - while (value > 0U && len < (u32)sizeof(tmp)) { - tmp[len++] = (char)('0' + (value % 10U)); - value /= 10U; - } - - while (len > 0U) { - len--; - clks_tty_status_append_char(line, line_size, cursor, tmp[len]); - } -} - -static void clks_tty_draw_status_bar(void) { - u32 tty_index; - u32 status_row; - u32 content_rows; - u32 cursor = 0U; - u32 col; - u32 shown_row; - u32 shown_col; - u32 scroll_offset; - const char *run_mode = "KERNEL"; - const char *input_mode; - char line[CLKS_TTY_MAX_COLS + 1U]; - - if (clks_tty_is_ready == CLKS_FALSE || clks_tty_status_bar_enabled() == CLKS_FALSE) { - return; - } - - if (clks_tty_active_index == CLKS_TTY_DESKTOP_INDEX) { - return; - } - - tty_index = clks_tty_active_index; - content_rows = clks_tty_content_rows(); - status_row = clks_tty_rows - 1U; - - for (col = 0U; col < clks_tty_cols && col < CLKS_TTY_MAX_COLS; col++) { - line[col] = ' '; - } - - if (clks_tty_cols < CLKS_TTY_MAX_COLS) { - line[clks_tty_cols] = '\0'; - } else { - line[CLKS_TTY_MAX_COLS] = '\0'; - } - - shown_row = clks_tty_cursor_row[tty_index] + 1U; - shown_col = clks_tty_cursor_col[tty_index] + 1U; - scroll_offset = clks_tty_scrollback_clamped_offset(tty_index); - input_mode = (scroll_offset > 0U) ? "SCROLL" : "INPUT"; - - if (clks_exec_is_running() == CLKS_TRUE && clks_exec_current_tty() == tty_index) { - run_mode = (clks_exec_current_path_is_user() == CLKS_TRUE) ? "USER" : "KAPP"; - } - - clks_tty_status_append_text(line, clks_tty_cols, &cursor, "TTY"); - clks_tty_status_append_u32_dec(line, clks_tty_cols, &cursor, tty_index); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, " "); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, "ROW:"); - if (shown_row > content_rows) { - shown_row = content_rows; - } - clks_tty_status_append_u32_dec(line, clks_tty_cols, &cursor, shown_row); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, " COL:"); - clks_tty_status_append_u32_dec(line, clks_tty_cols, &cursor, shown_col); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, " SB:"); - clks_tty_status_append_u32_dec(line, clks_tty_cols, &cursor, scroll_offset); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, " IN:"); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, input_mode); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, " MODE:"); - clks_tty_status_append_text(line, clks_tty_cols, &cursor, run_mode); - - for (col = 0U; col < clks_tty_cols; col++) { - char ch = (col < CLKS_TTY_MAX_COLS) ? line[col] : ' '; - - clks_tty_draw_cell_with_colors(status_row, col, ch, CLKS_TTY_STATUS_FG, CLKS_TTY_STATUS_BG, - CLKS_TTY_STATUS_STYLE); - } -} - -static void clks_tty_reset_color_state(u32 tty_index) { - clks_tty_current_fg[tty_index] = CLKS_TTY_FG; - clks_tty_current_bg[tty_index] = CLKS_TTY_BG; - clks_tty_ansi[tty_index].bold = CLKS_FALSE; - clks_tty_ansi[tty_index].underline = CLKS_FALSE; - clks_tty_ansi[tty_index].inverse = CLKS_FALSE; -} - -static void clks_tty_reset_ansi_state(u32 tty_index) { - clks_tty_ansi[tty_index].in_escape = CLKS_FALSE; - clks_tty_ansi[tty_index].saw_csi = CLKS_FALSE; - clks_tty_ansi[tty_index].len = 0U; - clks_tty_ansi[tty_index].params[0] = '\0'; -} - -static void clks_tty_fill_row(u32 tty_index, u32 row, char ch) { - u32 col; - - for (col = 0; col < clks_tty_cols; col++) { - clks_tty_cells[tty_index][row][col] = ch; - clks_tty_cell_fg[tty_index][row][col] = CLKS_TTY_FG; - clks_tty_cell_bg[tty_index][row][col] = CLKS_TTY_BG; - clks_tty_cell_style[tty_index][row][col] = CLKS_TTY_STYLE_NONE; - } -} - -static void clks_tty_clear_tty(u32 tty_index) { - u32 row; - - for (row = 0; row < clks_tty_content_rows(); row++) { - clks_tty_fill_row(tty_index, row, ' '); - } - - clks_tty_cursor_row[tty_index] = 0U; - clks_tty_cursor_col[tty_index] = 0U; - clks_tty_scrollback_head[tty_index] = 0U; - clks_tty_scrollback_count[tty_index] = 0U; - clks_tty_scrollback_offset[tty_index] = 0U; -} - -static void clks_tty_hide_cursor(void) { - u32 row; - u32 col; - - if (clks_tty_is_ready == CLKS_FALSE || clks_tty_cursor_visible == CLKS_FALSE) { - return; - } - - if (clks_tty_scrollback_is_active(clks_tty_active_index) == CLKS_TRUE) { - clks_tty_cursor_visible = CLKS_FALSE; - return; - } - - row = clks_tty_cursor_row[clks_tty_active_index]; - col = clks_tty_cursor_col[clks_tty_active_index]; - - if (row < clks_tty_content_rows() && col < clks_tty_cols) { - clks_tty_draw_cell(clks_tty_active_index, row, col); - } - - clks_tty_cursor_visible = CLKS_FALSE; -} - -static void clks_tty_draw_cursor(void) { - u32 row; - u32 col; - u32 fg; - u32 bg; - u8 style; - char ch; - - if (clks_tty_is_ready == CLKS_FALSE) { - return; - } - - if (clks_tty_active_index == CLKS_TTY_DESKTOP_INDEX) { - clks_tty_cursor_visible = CLKS_FALSE; - return; - } - - if (clks_tty_scrollback_is_active(clks_tty_active_index) == CLKS_TRUE) { - clks_tty_cursor_visible = CLKS_FALSE; - return; - } - - row = clks_tty_cursor_row[clks_tty_active_index]; - col = clks_tty_cursor_col[clks_tty_active_index]; - - if (row >= clks_tty_content_rows() || col >= clks_tty_cols) { - clks_tty_cursor_visible = CLKS_FALSE; - return; - } - - ch = clks_tty_cells[clks_tty_active_index][row][col]; - fg = clks_tty_cell_fg[clks_tty_active_index][row][col]; - bg = clks_tty_cell_bg[clks_tty_active_index][row][col]; - style = clks_tty_cell_style[clks_tty_active_index][row][col]; - - clks_tty_draw_cell_with_colors(row, col, ch, bg, fg, style); - clks_tty_cursor_visible = CLKS_TRUE; -} - -static void clks_tty_redraw_active(void) { - u32 row; - u32 col; - u32 tty_index = clks_tty_active_index; - u32 scroll_count = clks_tty_scrollback_count[tty_index]; - u32 scroll_offset = clks_tty_scrollback_clamped_offset(tty_index); - u32 start_doc = (scroll_count >= scroll_offset) ? (scroll_count - scroll_offset) : 0U; - - /* Full redraw is expensive, but sometimes the least cursed option. */ - clks_fb_clear(CLKS_TTY_BG); - clks_tty_cursor_visible = CLKS_FALSE; - clks_tty_dirty_reset(); - - for (row = 0; row < clks_tty_content_rows(); row++) { - u32 doc_index = start_doc + row; - - if (doc_index < scroll_count) { - u32 phys = clks_tty_scrollback_logical_to_physical(tty_index, doc_index); - - for (col = 0; col < clks_tty_cols; col++) { - clks_tty_draw_cell_with_colors(row, col, clks_tty_scrollback_cells[tty_index][phys][col], - clks_tty_scrollback_fg[tty_index][phys][col], - clks_tty_scrollback_bg[tty_index][phys][col], - clks_tty_scrollback_style[tty_index][phys][col]); - } - - continue; - } - - { - u32 src_row = doc_index - scroll_count; - - if (src_row >= clks_tty_content_rows()) { - continue; - } - - for (col = 0; col < clks_tty_cols; col++) { - clks_tty_draw_cell_with_colors( - row, col, clks_tty_cells[tty_index][src_row][col], clks_tty_cell_fg[tty_index][src_row][col], - clks_tty_cell_bg[tty_index][src_row][col], clks_tty_cell_style[tty_index][src_row][col]); - } - } - } - - if (scroll_offset == 0U) { - clks_tty_draw_cursor(); - } - - clks_tty_draw_status_bar(); -} -static void clks_tty_scroll_up(u32 tty_index) { - u32 row; - - /* Classic terminal move: throw top line away, pretend everything is fine. */ - clks_tty_scrollback_push_row(tty_index, 0U); - - for (row = 1; row < clks_tty_content_rows(); row++) { - clks_memcpy(clks_tty_cells[tty_index][row - 1U], clks_tty_cells[tty_index][row], clks_tty_cols); - clks_memcpy(clks_tty_cell_fg[tty_index][row - 1U], clks_tty_cell_fg[tty_index][row], - (usize)clks_tty_cols * sizeof(u32)); - clks_memcpy(clks_tty_cell_bg[tty_index][row - 1U], clks_tty_cell_bg[tty_index][row], - (usize)clks_tty_cols * sizeof(u32)); - clks_memcpy(clks_tty_cell_style[tty_index][row - 1U], clks_tty_cell_style[tty_index][row], clks_tty_cols); - } - - clks_tty_fill_row(tty_index, clks_tty_content_rows() - 1U, ' '); - - if (tty_index == clks_tty_active_index) { - if (clks_tty_scrollback_is_active(tty_index) == CLKS_TRUE) { - clks_tty_redraw_active(); - } else { - u32 col; - - clks_fb_scroll_up(clks_tty_cell_height, CLKS_TTY_BG); - - if (clks_tty_defer_draw == CLKS_TRUE) { - clks_tty_dirty_mark_row(clks_tty_content_rows() - 1U); - } else { - for (col = 0U; col < clks_tty_cols; col++) { - clks_tty_draw_cell(tty_index, clks_tty_content_rows() - 1U, col); - } - } - } - } -} -static void clks_tty_put_visible(u32 tty_index, u32 row, u32 col, char ch) { - u32 fg = clks_tty_current_fg[tty_index]; - u32 bg = clks_tty_current_bg[tty_index]; - u8 style = CLKS_TTY_STYLE_NONE; - - if (clks_tty_ansi[tty_index].inverse == CLKS_TRUE) { - u32 swap = fg; - fg = bg; - bg = swap; - } - - if (clks_tty_ansi[tty_index].bold == CLKS_TRUE) { - style = (u8)(style | CLKS_TTY_STYLE_BOLD); - } - - if (clks_tty_ansi[tty_index].underline == CLKS_TRUE) { - style = (u8)(style | CLKS_TTY_STYLE_UNDERLINE); - } - - clks_tty_cells[tty_index][row][col] = ch; - clks_tty_cell_fg[tty_index][row][col] = fg; - clks_tty_cell_bg[tty_index][row][col] = bg; - clks_tty_cell_style[tty_index][row][col] = style; - - if (tty_index == clks_tty_active_index) { - if (clks_tty_defer_draw == CLKS_TRUE) { - clks_tty_dirty_mark_cell(row, col); - } else { - clks_tty_draw_cell(tty_index, row, col); - } - } -} - -static void clks_tty_put_char_raw(u32 tty_index, char ch) { - u32 row = clks_tty_cursor_row[tty_index]; - u32 col = clks_tty_cursor_col[tty_index]; - - if (ch == '\r') { - clks_tty_cursor_col[tty_index] = 0U; - return; - } - - if (ch == '\n') { - clks_tty_cursor_col[tty_index] = 0U; - clks_tty_cursor_row[tty_index]++; - - if (clks_tty_cursor_row[tty_index] >= clks_tty_content_rows()) { - clks_tty_scroll_up(tty_index); - clks_tty_cursor_row[tty_index] = clks_tty_content_rows() - 1U; - } - - return; - } - - if (ch == '\b') { - if (col == 0U && row == 0U) { - return; - } - - if (col == 0U) { - row--; - col = clks_tty_cols - 1U; - } else { - col--; - } - - clks_tty_put_visible(tty_index, row, col, ' '); - clks_tty_cursor_row[tty_index] = row; - clks_tty_cursor_col[tty_index] = col; - return; - } - - if (ch == '\t') { - clks_tty_put_char_raw(tty_index, ' '); - clks_tty_put_char_raw(tty_index, ' '); - clks_tty_put_char_raw(tty_index, ' '); - clks_tty_put_char_raw(tty_index, ' '); - return; - } - - clks_tty_put_visible(tty_index, row, col, ch); - clks_tty_cursor_col[tty_index]++; - - if (clks_tty_cursor_col[tty_index] >= clks_tty_cols) { - clks_tty_cursor_col[tty_index] = 0U; - clks_tty_cursor_row[tty_index]++; - - if (clks_tty_cursor_row[tty_index] >= clks_tty_content_rows()) { - clks_tty_scroll_up(tty_index); - clks_tty_cursor_row[tty_index] = clks_tty_content_rows() - 1U; - } - } -} - -static u32 clks_tty_ansi_clamp_255(u32 value) { - return (value > 255U) ? 255U : value; -} - -static u32 clks_tty_ansi_color_from_256(u32 index) { - if (index < 16U) { - return clks_tty_ansi_palette(index); - } - - if (index >= 16U && index <= 231U) { - static const u32 steps[6] = {0U, 95U, 135U, 175U, 215U, 255U}; - u32 n = index - 16U; - u32 r = n / 36U; - u32 g = (n / 6U) % 6U; - u32 b = n % 6U; - - return (steps[r] << 16U) | (steps[g] << 8U) | steps[b]; - } - - if (index >= 232U && index <= 255U) { - u32 gray = 8U + ((index - 232U) * 10U); - return (gray << 16U) | (gray << 8U) | gray; - } - - return CLKS_TTY_FG; -} - -static u32 clks_tty_ansi_parse_params(const char *params, u32 len, u32 *out_values, u32 max_values) { - u32 count = 0U; - u32 value = 0U; - clks_bool has_digit = CLKS_FALSE; - u32 i; - - if (out_values == CLKS_NULL || max_values == 0U) { - return 0U; - } - - if (len == 0U) { - out_values[0] = 0U; - return 1U; - } - - for (i = 0U; i <= len; i++) { - char ch = (i < len) ? params[i] : ';'; - - if (ch >= '0' && ch <= '9') { - has_digit = CLKS_TRUE; - value = (value * 10U) + (u32)(ch - '0'); - continue; - } - - if (ch == ';') { - if (count < max_values) { - out_values[count++] = (has_digit == CLKS_TRUE) ? value : 0U; - } - - value = 0U; - has_digit = CLKS_FALSE; - continue; - } - } - - if (count == 0U) { - out_values[0] = 0U; - return 1U; - } - - return count; -} - -static u32 clks_tty_ansi_param_or_default(const u32 *params, u32 count, u32 index, u32 default_value) { - if (params == CLKS_NULL || index >= count || params[index] == 0U) { - return default_value; - } - - return params[index]; -} - -static void clks_tty_ansi_clear_line_mode(u32 tty_index, u32 mode) { - u32 row = clks_tty_cursor_row[tty_index]; - u32 start = 0U; - u32 end = 0U; - u32 col; - - if (row >= clks_tty_content_rows()) { - return; - } - - if (mode == 0U) { - start = clks_tty_cursor_col[tty_index]; - end = clks_tty_cols; - } else if (mode == 1U) { - start = 0U; - end = clks_tty_cursor_col[tty_index] + 1U; - } else { - start = 0U; - end = clks_tty_cols; - } - - if (start >= clks_tty_cols) { - start = clks_tty_cols; - } - - if (end > clks_tty_cols) { - end = clks_tty_cols; - } - - for (col = start; col < end; col++) { - clks_tty_cells[tty_index][row][col] = ' '; - clks_tty_cell_fg[tty_index][row][col] = CLKS_TTY_FG; - clks_tty_cell_bg[tty_index][row][col] = CLKS_TTY_BG; - clks_tty_cell_style[tty_index][row][col] = CLKS_TTY_STYLE_NONE; - } - - if (tty_index == clks_tty_active_index) { - if (clks_tty_defer_draw == CLKS_TRUE) { - clks_tty_dirty_mark_row(row); - } else { - for (col = start; col < end; col++) { - clks_tty_draw_cell(tty_index, row, col); - } - } - } -} - -static void clks_tty_ansi_clear_screen_mode(u32 tty_index, u32 mode) { - u32 row; - u32 col; - u32 content_rows = clks_tty_content_rows(); - u32 cursor_row = clks_tty_cursor_row[tty_index]; - u32 cursor_col = clks_tty_cursor_col[tty_index]; - - if (cursor_row >= content_rows) { - cursor_row = content_rows - 1U; - } - - if (cursor_col >= clks_tty_cols) { - cursor_col = clks_tty_cols - 1U; - } - - if (mode == 0U) { - for (row = cursor_row; row < content_rows; row++) { - u32 start_col = (row == cursor_row) ? cursor_col : 0U; - - for (col = start_col; col < clks_tty_cols; col++) { - clks_tty_cells[tty_index][row][col] = ' '; - clks_tty_cell_fg[tty_index][row][col] = CLKS_TTY_FG; - clks_tty_cell_bg[tty_index][row][col] = CLKS_TTY_BG; - clks_tty_cell_style[tty_index][row][col] = CLKS_TTY_STYLE_NONE; - } - } - } else if (mode == 1U) { - for (row = 0U; row <= cursor_row; row++) { - u32 end_col = (row == cursor_row) ? (cursor_col + 1U) : clks_tty_cols; - - for (col = 0U; col < end_col; col++) { - clks_tty_cells[tty_index][row][col] = ' '; - clks_tty_cell_fg[tty_index][row][col] = CLKS_TTY_FG; - clks_tty_cell_bg[tty_index][row][col] = CLKS_TTY_BG; - clks_tty_cell_style[tty_index][row][col] = CLKS_TTY_STYLE_NONE; - } - } - } else { - for (row = 0U; row < content_rows; row++) { - for (col = 0U; col < clks_tty_cols; col++) { - clks_tty_cells[tty_index][row][col] = ' '; - clks_tty_cell_fg[tty_index][row][col] = CLKS_TTY_FG; - clks_tty_cell_bg[tty_index][row][col] = CLKS_TTY_BG; - clks_tty_cell_style[tty_index][row][col] = CLKS_TTY_STYLE_NONE; - } - } - } - - if (mode == 3U) { - clks_tty_scrollback_head[tty_index] = 0U; - clks_tty_scrollback_count[tty_index] = 0U; - clks_tty_scrollback_offset[tty_index] = 0U; - } - - if (tty_index == clks_tty_active_index) { - clks_tty_redraw_active(); - } -} - -static void clks_tty_ansi_apply_sgr_params(u32 tty_index, const char *params, u32 len) { - u32 values[16]; - u32 count = clks_tty_ansi_parse_params(params, len, values, 16U); - u32 i; - - if (count == 0U) { - return; - } - - for (i = 0U; i < count; i++) { - u32 code = values[i]; - - if (code == 0U) { - clks_tty_reset_color_state(tty_index); - continue; - } - - if (code == 1U) { - clks_tty_ansi[tty_index].bold = CLKS_TRUE; - continue; - } - - if (code == 4U) { - clks_tty_ansi[tty_index].underline = CLKS_TRUE; - continue; - } - - if (code == 7U) { - clks_tty_ansi[tty_index].inverse = CLKS_TRUE; - continue; - } - - if (code == 21U || code == 22U) { - clks_tty_ansi[tty_index].bold = CLKS_FALSE; - continue; - } - - if (code == 24U) { - clks_tty_ansi[tty_index].underline = CLKS_FALSE; - continue; - } - - if (code == 27U) { - clks_tty_ansi[tty_index].inverse = CLKS_FALSE; - continue; - } - - if (code == 39U) { - clks_tty_current_fg[tty_index] = CLKS_TTY_FG; - continue; - } - - if (code == 49U) { - clks_tty_current_bg[tty_index] = CLKS_TTY_BG; - continue; - } - - if (code >= 30U && code <= 37U) { - u32 idx = code - 30U; - - if (clks_tty_ansi[tty_index].bold == CLKS_TRUE) { - idx += 8U; - } - - clks_tty_current_fg[tty_index] = clks_tty_ansi_palette(idx); - continue; - } - - if (code >= 90U && code <= 97U) { - clks_tty_current_fg[tty_index] = clks_tty_ansi_palette((code - 90U) + 8U); - continue; - } - - if (code >= 40U && code <= 47U) { - clks_tty_current_bg[tty_index] = clks_tty_ansi_palette(code - 40U); - continue; - } - - if (code >= 100U && code <= 107U) { - clks_tty_current_bg[tty_index] = clks_tty_ansi_palette((code - 100U) + 8U); - continue; - } - - if ((code == 38U || code == 48U) && (i + 1U) < count) { - u32 mode = values[i + 1U]; - u32 color; - - if (mode == 5U && (i + 2U) < count) { - color = clks_tty_ansi_color_from_256(values[i + 2U]); - - if (code == 38U) { - clks_tty_current_fg[tty_index] = color; - } else { - clks_tty_current_bg[tty_index] = color; - } - - i += 2U; - continue; - } - - if (mode == 2U && (i + 4U) < count) { - u32 r = clks_tty_ansi_clamp_255(values[i + 2U]); - u32 g = clks_tty_ansi_clamp_255(values[i + 3U]); - u32 b = clks_tty_ansi_clamp_255(values[i + 4U]); - color = (r << 16U) | (g << 8U) | b; - - if (code == 38U) { - clks_tty_current_fg[tty_index] = color; - } else { - clks_tty_current_bg[tty_index] = color; - } - - i += 4U; - continue; - } - } - } -} - -static void clks_tty_ansi_process_csi_final(u32 tty_index, const char *params, u32 len, char final) { - u32 values[16]; - u32 count = clks_tty_ansi_parse_params(params, len, values, 16U); - clks_bool private_mode = (len > 0U && params[0] == '?') ? CLKS_TRUE : CLKS_FALSE; - - if (final == 'm') { - clks_tty_ansi_apply_sgr_params(tty_index, params, len); - return; - } - - if (final == 'J') { - u32 mode = (count == 0U) ? 0U : values[0]; - clks_tty_ansi_clear_screen_mode(tty_index, mode); - return; - } - - if (final == 'K') { - u32 mode = (count == 0U) ? 0U : values[0]; - clks_tty_ansi_clear_line_mode(tty_index, mode); - return; - } - - if (final == 'H' || final == 'f') { - u32 row = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - u32 col = clks_tty_ansi_param_or_default(values, count, 1U, 1U); - - if (row > 0U) { - row--; - } - - if (col > 0U) { - col--; - } - - if (row >= clks_tty_content_rows()) { - row = clks_tty_content_rows() - 1U; - } - - if (col >= clks_tty_cols) { - col = clks_tty_cols - 1U; - } - - clks_tty_cursor_row[tty_index] = row; - clks_tty_cursor_col[tty_index] = col; - return; - } - - if (final == 'A') { - u32 n = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - - if (n > clks_tty_cursor_row[tty_index]) { - clks_tty_cursor_row[tty_index] = 0U; - } else { - clks_tty_cursor_row[tty_index] -= n; - } - - return; - } - - if (final == 'B') { - u32 n = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - u32 max_row = clks_tty_content_rows() - 1U; - - if (clks_tty_cursor_row[tty_index] + n > max_row) { - clks_tty_cursor_row[tty_index] = max_row; - } else { - clks_tty_cursor_row[tty_index] += n; - } - - return; - } - - if (final == 'C') { - u32 n = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - u32 max_col = clks_tty_cols - 1U; - - if (clks_tty_cursor_col[tty_index] + n > max_col) { - clks_tty_cursor_col[tty_index] = max_col; - } else { - clks_tty_cursor_col[tty_index] += n; - } - - return; - } - - if (final == 'D') { - u32 n = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - - if (n > clks_tty_cursor_col[tty_index]) { - clks_tty_cursor_col[tty_index] = 0U; - } else { - clks_tty_cursor_col[tty_index] -= n; - } - - return; - } - - if (final == 'E' || final == 'F') { - u32 n = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - - if (final == 'E') { - u32 max_row = clks_tty_content_rows() - 1U; - - if (clks_tty_cursor_row[tty_index] + n > max_row) { - clks_tty_cursor_row[tty_index] = max_row; - } else { - clks_tty_cursor_row[tty_index] += n; - } - } else { - if (n > clks_tty_cursor_row[tty_index]) { - clks_tty_cursor_row[tty_index] = 0U; - } else { - clks_tty_cursor_row[tty_index] -= n; - } - } - - clks_tty_cursor_col[tty_index] = 0U; - return; - } - - if (final == 'G') { - u32 col = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - - if (col > 0U) { - col--; - } - - if (col >= clks_tty_cols) { - col = clks_tty_cols - 1U; - } - - clks_tty_cursor_col[tty_index] = col; - return; - } - - if (final == 'd') { - u32 row = clks_tty_ansi_param_or_default(values, count, 0U, 1U); - - if (row > 0U) { - row--; - } - - if (row >= clks_tty_content_rows()) { - row = clks_tty_content_rows() - 1U; - } - - clks_tty_cursor_row[tty_index] = row; - return; - } - - if (final == 's') { - clks_tty_ansi[tty_index].saved_row = clks_tty_cursor_row[tty_index]; - clks_tty_ansi[tty_index].saved_col = clks_tty_cursor_col[tty_index]; - return; - } - - if (final == 'u') { - u32 row = clks_tty_ansi[tty_index].saved_row; - u32 col = clks_tty_ansi[tty_index].saved_col; - - if (row >= clks_tty_content_rows()) { - row = clks_tty_content_rows() - 1U; - } - - if (col >= clks_tty_cols) { - col = clks_tty_cols - 1U; - } - - clks_tty_cursor_row[tty_index] = row; - clks_tty_cursor_col[tty_index] = col; - return; - } - - if ((final == 'h' || final == 'l') && private_mode == CLKS_TRUE) { - u32 mode = (count == 0U) ? 0U : values[0]; - - if (mode == 25U) { - if (final == 'h') { - clks_tty_blink_enabled = CLKS_TRUE; - if (tty_index == clks_tty_active_index) { - clks_tty_draw_cursor(); - } - } else { - clks_tty_blink_enabled = CLKS_FALSE; - if (tty_index == clks_tty_active_index) { - clks_tty_hide_cursor(); - } - } - } - - return; - } -} - -static clks_bool clks_tty_ansi_process_byte(u32 tty_index, char ch) { - clks_tty_ansi_state *state = &clks_tty_ansi[tty_index]; - - if (state->in_escape == CLKS_FALSE) { - if ((u8)ch == 0x1BU) { - state->in_escape = CLKS_TRUE; - state->saw_csi = CLKS_FALSE; - state->len = 0U; - state->params[0] = '\0'; - return CLKS_TRUE; - } - - return CLKS_FALSE; - } - - if (state->saw_csi == CLKS_FALSE) { - if (ch == '[') { - state->saw_csi = CLKS_TRUE; - return CLKS_TRUE; - } - - if (ch == '7') { - state->saved_row = clks_tty_cursor_row[tty_index]; - state->saved_col = clks_tty_cursor_col[tty_index]; - clks_tty_reset_ansi_state(tty_index); - return CLKS_TRUE; - } - - if (ch == '8') { - u32 row = state->saved_row; - u32 col = state->saved_col; - - if (row >= clks_tty_content_rows()) { - row = clks_tty_content_rows() - 1U; - } - - if (col >= clks_tty_cols) { - col = clks_tty_cols - 1U; - } - - clks_tty_cursor_row[tty_index] = row; - clks_tty_cursor_col[tty_index] = col; - clks_tty_reset_ansi_state(tty_index); - return CLKS_TRUE; - } - - clks_tty_reset_ansi_state(tty_index); - return CLKS_TRUE; - } - - if ((ch >= '0' && ch <= '9') || ch == ';' || ch == '?') { - if (state->len < CLKS_TTY_ANSI_MAX_LEN) { - state->params[state->len++] = ch; - state->params[state->len] = '\0'; - } else { - clks_tty_reset_ansi_state(tty_index); - } - - return CLKS_TRUE; - } - - clks_tty_ansi_process_csi_final(tty_index, state->params, state->len, ch); - clks_tty_reset_ansi_state(tty_index); - return CLKS_TRUE; -} -void clks_tty_init(void) { - struct clks_framebuffer_info info; - u32 tty; - - if (clks_fb_ready() == CLKS_FALSE) { - clks_tty_is_ready = CLKS_FALSE; - return; - } - - /* If framebuffer lies here, the whole UI goes to hell immediately. */ - info = clks_fb_info(); - clks_tty_cell_width = clks_fb_cell_width(); - clks_tty_cell_height = clks_fb_cell_height(); - - if (clks_tty_cell_width == 0U) { - clks_tty_cell_width = 8U; - } - - if (clks_tty_cell_height == 0U) { - clks_tty_cell_height = 8U; - } - - clks_tty_rows = info.height / clks_tty_cell_height; - clks_tty_cols = info.width / clks_tty_cell_width; - - if (clks_tty_rows > CLKS_TTY_MAX_ROWS) { - clks_tty_rows = CLKS_TTY_MAX_ROWS; - } - - if (clks_tty_cols > CLKS_TTY_MAX_COLS) { - clks_tty_cols = CLKS_TTY_MAX_COLS; - } - - if (clks_tty_rows == 0U || clks_tty_cols == 0U) { - clks_tty_is_ready = CLKS_FALSE; - return; - } - - for (tty = 0U; tty < CLKS_TTY_COUNT; tty++) { - clks_tty_cursor_row[tty] = 0U; - clks_tty_cursor_col[tty] = 0U; - clks_tty_reset_color_state(tty); - clks_tty_reset_ansi_state(tty); - clks_tty_clear_tty(tty); - } - - clks_tty_active_index = 0U; - clks_tty_is_ready = CLKS_TRUE; - clks_tty_cursor_visible = CLKS_FALSE; - clks_tty_blink_enabled = CLKS_TRUE; - clks_tty_defer_draw = CLKS_FALSE; - clks_tty_dirty_reset(); - clks_tty_reset_blink_timer(); - clks_tty_redraw_active(); -} - -void clks_tty_write_char(char ch) { - u32 tty_index; - - if (clks_tty_is_ready == CLKS_FALSE) { - return; - } - - clks_tty_hide_cursor(); - - tty_index = clks_tty_active_index; - - if (clks_tty_scrollback_is_active(tty_index) == CLKS_TRUE) { - clks_tty_scrollback_follow_tail(tty_index); - clks_tty_redraw_active(); - } - - clks_tty_defer_draw = CLKS_TRUE; - if (clks_tty_ansi_process_byte(tty_index, ch) == CLKS_FALSE) { - clks_tty_put_char_raw(tty_index, ch); - } - clks_tty_defer_draw = CLKS_FALSE; - clks_tty_flush_dirty(); - - clks_tty_draw_cursor(); - clks_tty_draw_status_bar(); - clks_tty_reset_blink_timer(); -} - -void clks_tty_write_n(const char *text, usize len) { - usize i = 0U; - u32 tty_index; - - if (clks_tty_is_ready == CLKS_FALSE || text == CLKS_NULL || len == 0U) { - return; - } - - clks_tty_hide_cursor(); - tty_index = clks_tty_active_index; - - if (clks_tty_scrollback_is_active(tty_index) == CLKS_TRUE) { - clks_tty_scrollback_follow_tail(tty_index); - clks_tty_redraw_active(); - } - - clks_tty_defer_draw = CLKS_TRUE; - while (i < len) { - if (clks_tty_ansi_process_byte(tty_index, text[i]) == CLKS_FALSE) { - clks_tty_put_char_raw(tty_index, text[i]); - } - - i++; - } - clks_tty_defer_draw = CLKS_FALSE; - clks_tty_flush_dirty(); - - clks_tty_draw_cursor(); - clks_tty_draw_status_bar(); - clks_tty_reset_blink_timer(); -} - -void clks_tty_write(const char *text) { - if (text == CLKS_NULL) { - return; - } - - clks_tty_write_n(text, clks_strlen(text)); -} - -void clks_tty_switch(u32 tty_index) { - if (clks_tty_is_ready == CLKS_FALSE) { - return; - } - - if (tty_index >= CLKS_TTY_COUNT) { - return; - } - - clks_tty_hide_cursor(); - clks_tty_active_index = tty_index; - clks_tty_cursor_visible = CLKS_FALSE; - clks_tty_redraw_active(); - clks_tty_reset_blink_timer(); -} - -void clks_tty_tick(u64 tick) { - if (clks_tty_is_ready == CLKS_FALSE || clks_tty_blink_enabled == CLKS_FALSE) { - return; - } - - if (clks_tty_active_index == CLKS_TTY_DESKTOP_INDEX) { - clks_tty_cursor_visible = CLKS_FALSE; - return; - } - - if (clks_tty_scrollback_is_active(clks_tty_active_index) == CLKS_TRUE) { - clks_tty_cursor_visible = CLKS_FALSE; - return; - } - - if (clks_tty_blink_last_tick == CLKS_TTY_BLINK_TICK_UNSET) { - clks_tty_blink_last_tick = tick; - - if (clks_tty_cursor_visible == CLKS_FALSE) { - clks_tty_draw_cursor(); - } - - return; - } - - if (tick < clks_tty_blink_last_tick) { - clks_tty_blink_last_tick = tick; - return; - } - - if ((tick - clks_tty_blink_last_tick) < CLKS_TTY_CURSOR_BLINK_INTERVAL_TICKS) { - return; - } - - clks_tty_blink_last_tick = tick; - - if (clks_tty_cursor_visible == CLKS_TRUE) { - clks_tty_hide_cursor(); - } else { - clks_tty_draw_cursor(); - } -} - -void clks_tty_scrollback_page_up(void) { - u32 tty_index; - u32 max_offset; - u32 next_offset; - - if (clks_tty_is_ready == CLKS_FALSE) { - return; - } - - tty_index = clks_tty_active_index; - - if (tty_index == CLKS_TTY_DESKTOP_INDEX) { - return; - } - - max_offset = clks_tty_scrollback_max_offset(tty_index); - - if (max_offset == 0U) { - return; - } - - clks_tty_hide_cursor(); - next_offset = clks_tty_scrollback_clamped_offset(tty_index) + clks_tty_content_rows(); - - if (next_offset > max_offset) { - next_offset = max_offset; - } - - if (next_offset != clks_tty_scrollback_offset[tty_index]) { - clks_tty_scrollback_offset[tty_index] = next_offset; - clks_tty_redraw_active(); - clks_tty_reset_blink_timer(); - } -} - -void clks_tty_scrollback_page_down(void) { - u32 tty_index; - u32 current_offset; - u32 next_offset; - - if (clks_tty_is_ready == CLKS_FALSE) { - return; - } - - tty_index = clks_tty_active_index; - - if (tty_index == CLKS_TTY_DESKTOP_INDEX) { - return; - } - - current_offset = clks_tty_scrollback_clamped_offset(tty_index); - - if (current_offset == 0U) { - return; - } - - clks_tty_hide_cursor(); - - if (current_offset > clks_tty_content_rows()) { - next_offset = current_offset - clks_tty_content_rows(); - } else { - next_offset = 0U; - } - - if (next_offset != clks_tty_scrollback_offset[tty_index]) { - clks_tty_scrollback_offset[tty_index] = next_offset; - clks_tty_redraw_active(); - clks_tty_reset_blink_timer(); - } -} - -u32 clks_tty_active(void) { - return clks_tty_active_index; -} - -u32 clks_tty_count(void) { - return CLKS_TTY_COUNT; -} - -clks_bool clks_tty_ready(void) { - return clks_tty_is_ready; -} diff --git a/clks/kernel/memory/heap.c b/clks/kernel/memory/heap.c deleted file mode 100644 index 67a1239..0000000 --- a/clks/kernel/memory/heap.c +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include -#include - -#ifndef CLKS_CFG_HEAP_ARENA_SIZE -#define CLKS_CFG_HEAP_ARENA_SIZE (64ULL * 1024ULL * 1024ULL) -#endif - -#define CLKS_HEAP_ARENA_SIZE CLKS_CFG_HEAP_ARENA_SIZE -#define CLKS_HEAP_ALIGN 16ULL -#define CLKS_HEAP_MAGIC 0x434C454F4E4F534FULL - -struct clks_heap_block { - usize size; - clks_bool is_free; - struct clks_heap_block *next; - struct clks_heap_block *prev; - u64 magic; -}; - -static u8 clks_heap_arena[CLKS_HEAP_ARENA_SIZE] __attribute__((aligned(16))); -static struct clks_heap_block *clks_heap_head = CLKS_NULL; -static clks_bool clks_heap_ready = CLKS_FALSE; - -static usize clks_heap_used_bytes = 0; -static u64 clks_heap_alloc_count = 0; -static u64 clks_heap_free_count = 0; - -static usize clks_heap_align_up(usize value) { - return (value + (CLKS_HEAP_ALIGN - 1ULL)) & ~(CLKS_HEAP_ALIGN - 1ULL); -} - -static void clks_heap_split_block(struct clks_heap_block *block, usize need_size) { - usize min_tail_size = sizeof(struct clks_heap_block) + CLKS_HEAP_ALIGN; - - if (block->size < (need_size + min_tail_size)) { - return; - } - - { - u8 *new_block_addr = (u8 *)block + sizeof(struct clks_heap_block) + need_size; - struct clks_heap_block *new_block = (struct clks_heap_block *)new_block_addr; - - new_block->size = block->size - need_size - sizeof(struct clks_heap_block); - new_block->is_free = CLKS_TRUE; - new_block->next = block->next; - new_block->prev = block; - new_block->magic = CLKS_HEAP_MAGIC; - - if (block->next != CLKS_NULL) { - block->next->prev = new_block; - } - - block->next = new_block; - block->size = need_size; - } -} - -static void clks_heap_merge_next(struct clks_heap_block *block) { - struct clks_heap_block *next = block->next; - - if (next == CLKS_NULL) { - return; - } - - if (next->is_free == CLKS_FALSE) { - return; - } - - if (next->magic != CLKS_HEAP_MAGIC) { - return; - } - - block->size += sizeof(struct clks_heap_block) + next->size; - block->next = next->next; - - if (next->next != CLKS_NULL) { - next->next->prev = block; - } -} - -void clks_heap_init(void) { - clks_memset(clks_heap_arena, 0, sizeof(clks_heap_arena)); - - clks_heap_head = (struct clks_heap_block *)clks_heap_arena; - clks_heap_head->size = CLKS_HEAP_ARENA_SIZE - sizeof(struct clks_heap_block); - clks_heap_head->is_free = CLKS_TRUE; - clks_heap_head->next = CLKS_NULL; - clks_heap_head->prev = CLKS_NULL; - clks_heap_head->magic = CLKS_HEAP_MAGIC; - - clks_heap_used_bytes = 0; - clks_heap_alloc_count = 0; - clks_heap_free_count = 0; - clks_heap_ready = CLKS_TRUE; -} - -void *clks_kmalloc(usize size) { - struct clks_heap_block *current; - usize aligned_size; - - if (clks_heap_ready == CLKS_FALSE) { - return CLKS_NULL; - } - - if (size == 0) { - return CLKS_NULL; - } - - aligned_size = clks_heap_align_up(size); - current = clks_heap_head; - - while (current != CLKS_NULL) { - if (current->magic != CLKS_HEAP_MAGIC) { - return CLKS_NULL; - } - - if (current->is_free == CLKS_TRUE && current->size >= aligned_size) { - clks_heap_split_block(current, aligned_size); - current->is_free = CLKS_FALSE; - clks_heap_used_bytes += current->size; - clks_heap_alloc_count++; - return (void *)((u8 *)current + sizeof(struct clks_heap_block)); - } - - current = current->next; - } - - return CLKS_NULL; -} - -void clks_kfree(void *ptr) { - struct clks_heap_block *block; - - if (clks_heap_ready == CLKS_FALSE) { - return; - } - - if (ptr == CLKS_NULL) { - return; - } - - block = (struct clks_heap_block *)((u8 *)ptr - sizeof(struct clks_heap_block)); - - if (block->magic != CLKS_HEAP_MAGIC) { - return; - } - - if (block->is_free == CLKS_TRUE) { - return; - } - - block->is_free = CLKS_TRUE; - - if (clks_heap_used_bytes >= block->size) { - clks_heap_used_bytes -= block->size; - } else { - clks_heap_used_bytes = 0; - } - - clks_heap_free_count++; - - clks_heap_merge_next(block); - - if (block->prev != CLKS_NULL && block->prev->is_free == CLKS_TRUE) { - clks_heap_merge_next(block->prev); - } -} - -struct clks_heap_stats clks_heap_get_stats(void) { - struct clks_heap_stats stats; - - stats.total_bytes = CLKS_HEAP_ARENA_SIZE - sizeof(struct clks_heap_block); - stats.used_bytes = clks_heap_used_bytes; - stats.free_bytes = stats.total_bytes - stats.used_bytes; - stats.alloc_count = clks_heap_alloc_count; - stats.free_count = clks_heap_free_count; - - return stats; -} diff --git a/clks/kernel/memory/pmm.c b/clks/kernel/memory/pmm.c deleted file mode 100644 index d45a545..0000000 --- a/clks/kernel/memory/pmm.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include - -#define CLKS_PMM_MAX_TRACKED_PAGES 262144ULL -#define CLKS_PMM_MIN_USABLE_ADDR 0x100000ULL - -static u64 clks_pmm_free_stack[CLKS_PMM_MAX_TRACKED_PAGES]; -static u64 clks_pmm_free_top = 0; -static u64 clks_pmm_managed_pages = 0; -static u64 clks_pmm_dropped_pages = 0; - -static u64 clks_align_up_u64(u64 value, u64 alignment) { - return (value + alignment - 1ULL) & ~(alignment - 1ULL); -} - -static u64 clks_align_down_u64(u64 value, u64 alignment) { - return value & ~(alignment - 1ULL); -} - -void clks_pmm_init(const struct limine_memmap_response *memmap) { - u64 i; - - clks_pmm_free_top = 0; - clks_pmm_managed_pages = 0; - clks_pmm_dropped_pages = 0; - clks_memset(clks_pmm_free_stack, 0, sizeof(clks_pmm_free_stack)); - - if (memmap == CLKS_NULL) { - return; - } - - for (i = 0; i < memmap->entry_count; i++) { - const struct limine_memmap_entry *entry = memmap->entries[i]; - u64 start; - u64 end; - u64 addr; - - if (entry == CLKS_NULL) { - continue; - } - - if (entry->type != LIMINE_MEMMAP_USABLE) { - continue; - } - - start = clks_align_up_u64(entry->base, CLKS_PAGE_SIZE); - end = clks_align_down_u64(entry->base + entry->length, CLKS_PAGE_SIZE); - - if (end <= start) { - continue; - } - - for (addr = start; addr < end; addr += CLKS_PAGE_SIZE) { - if (addr < CLKS_PMM_MIN_USABLE_ADDR) { - continue; - } - - if (clks_pmm_free_top < CLKS_PMM_MAX_TRACKED_PAGES) { - clks_pmm_free_stack[clks_pmm_free_top] = addr; - clks_pmm_free_top++; - clks_pmm_managed_pages++; - } else { - clks_pmm_dropped_pages++; - } - } - } -} - -u64 clks_pmm_alloc_page(void) { - if (clks_pmm_free_top == 0) { - return 0ULL; - } - - clks_pmm_free_top--; - return clks_pmm_free_stack[clks_pmm_free_top]; -} - -void clks_pmm_free_page(u64 phys_addr) { - if (phys_addr == 0ULL) { - return; - } - - if ((phys_addr & (CLKS_PAGE_SIZE - 1ULL)) != 0ULL) { - return; - } - - if (clks_pmm_free_top >= CLKS_PMM_MAX_TRACKED_PAGES) { - return; - } - - clks_pmm_free_stack[clks_pmm_free_top] = phys_addr; - clks_pmm_free_top++; -} - -struct clks_pmm_stats clks_pmm_get_stats(void) { - struct clks_pmm_stats stats; - - stats.managed_pages = clks_pmm_managed_pages; - stats.free_pages = clks_pmm_free_top; - stats.used_pages = clks_pmm_managed_pages - clks_pmm_free_top; - stats.dropped_pages = clks_pmm_dropped_pages; - - return stats; -} \ No newline at end of file diff --git a/clks/kernel/runtime/driver.c b/clks/kernel/runtime/driver.c deleted file mode 100644 index 2f59136..0000000 --- a/clks/kernel/runtime/driver.c +++ /dev/null @@ -1,214 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define CLKS_DRIVER_MAX 32U -#define CLKS_DRIVER_CHILD_NAME_MAX 96U -#define CLKS_DRIVER_PATH_MAX 224U - -static struct clks_driver_info clks_driver_table[CLKS_DRIVER_MAX]; -static u64 clks_driver_table_count = 0ULL; -static u64 clks_driver_table_elf_count = 0ULL; - -static void clks_driver_copy_name(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || dst_size == 0U) { - return; - } - - if (src == CLKS_NULL) { - dst[0] = '\0'; - return; - } - - while (i + 1U < dst_size && src[i] != '\0') { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static clks_bool clks_driver_has_elf_suffix(const char *name) { - usize len; - - if (name == CLKS_NULL) { - return CLKS_FALSE; - } - - len = clks_strlen(name); - - if (len < 4U) { - return CLKS_FALSE; - } - - return (name[len - 4U] == '.' && name[len - 3U] == 'e' && name[len - 2U] == 'l' && name[len - 1U] == 'f') - ? CLKS_TRUE - : CLKS_FALSE; -} - -static clks_bool clks_driver_build_path(const char *child_name, char *out_path, usize out_size) { - static const char prefix[] = "/driver/"; - usize prefix_len = sizeof(prefix) - 1U; - usize child_len; - - if (child_name == CLKS_NULL || out_path == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - child_len = clks_strlen(child_name); - - if (prefix_len + child_len + 1U > out_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_path, prefix, prefix_len); - clks_memcpy(out_path + prefix_len, child_name, child_len); - out_path[prefix_len + child_len] = '\0'; - return CLKS_TRUE; -} - -static clks_bool clks_driver_push(const char *name, enum clks_driver_kind kind, enum clks_driver_state state, - clks_bool from_elf, u64 image_size, u64 elf_entry) { - struct clks_driver_info *slot; - - if (clks_driver_table_count >= CLKS_DRIVER_MAX) { - return CLKS_FALSE; - } - - slot = &clks_driver_table[clks_driver_table_count]; - clks_memset(slot, 0, sizeof(*slot)); - - clks_driver_copy_name(slot->name, sizeof(slot->name), name); - slot->kind = kind; - slot->state = state; - slot->from_elf = from_elf; - slot->image_size = image_size; - slot->elf_entry = elf_entry; - - clks_driver_table_count++; - - if (from_elf == CLKS_TRUE) { - clks_driver_table_elf_count++; - } - - return CLKS_TRUE; -} - -static void clks_driver_register_builtins(void) { - clks_driver_push("serial", CLKS_DRIVER_KIND_BUILTIN_CHAR, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL); - - if (clks_fb_ready() == CLKS_TRUE) { - clks_driver_push("framebuffer", CLKS_DRIVER_KIND_BUILTIN_VIDEO, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, - 0ULL); - clks_driver_push("tty", CLKS_DRIVER_KIND_BUILTIN_TTY, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL); - } else { - clks_driver_push("framebuffer", CLKS_DRIVER_KIND_BUILTIN_VIDEO, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL, - 0ULL); - clks_driver_push("tty", CLKS_DRIVER_KIND_BUILTIN_TTY, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL, 0ULL); - } - - if (clks_audio_available() == CLKS_TRUE) { - clks_driver_push("pcspeaker", CLKS_DRIVER_KIND_BUILTIN_AUDIO, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL); - } else { - clks_driver_push("pcspeaker", CLKS_DRIVER_KIND_BUILTIN_AUDIO, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL, 0ULL); - } -} - -static void clks_driver_probe_driver_dir(void) { - u64 child_count; - u64 i; - - if (clks_fs_is_ready() == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "DRV", "FS NOT READY FOR DRIVER PROBE"); - return; - } - - child_count = clks_fs_count_children("/driver"); - - for (i = 0ULL; i < child_count; i++) { - char child_name[CLKS_DRIVER_CHILD_NAME_MAX]; - char full_path[CLKS_DRIVER_PATH_MAX]; - const void *image; - u64 image_size = 0ULL; - struct clks_elf64_info info; - - clks_memset(child_name, 0, sizeof(child_name)); - clks_memset(full_path, 0, sizeof(full_path)); - - if (clks_fs_get_child_name("/driver", i, child_name, sizeof(child_name)) == CLKS_FALSE) { - continue; - } - - if (clks_driver_has_elf_suffix(child_name) == CLKS_FALSE) { - continue; - } - - if (clks_driver_build_path(child_name, full_path, sizeof(full_path)) == CLKS_FALSE) { - clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, 0ULL, 0ULL); - continue; - } - - image = clks_fs_read_all(full_path, &image_size); - - if (image == CLKS_NULL) { - clks_log(CLKS_LOG_ERROR, "DRV", "DRIVER ELF MISSING"); - clks_log(CLKS_LOG_ERROR, "DRV", full_path); - clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, 0ULL, 0ULL); - continue; - } - - if (clks_elf64_inspect(image, image_size, &info) == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "DRV", "DRIVER ELF INVALID"); - clks_log(CLKS_LOG_ERROR, "DRV", full_path); - clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, image_size, 0ULL); - continue; - } - - clks_log(CLKS_LOG_INFO, "DRV", "DRIVER ELF READY"); - clks_log(CLKS_LOG_INFO, "DRV", full_path); - clks_log_hex(CLKS_LOG_INFO, "DRV", "ENTRY", info.entry); - - clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_READY, CLKS_TRUE, image_size, info.entry); - } -} - -void clks_driver_init(void) { - clks_memset(clks_driver_table, 0, sizeof(clks_driver_table)); - clks_driver_table_count = 0ULL; - clks_driver_table_elf_count = 0ULL; - - clks_driver_register_builtins(); - clks_driver_probe_driver_dir(); - - clks_log(CLKS_LOG_INFO, "DRV", "DRIVER MANAGER ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "DRV", "REGISTERED", clks_driver_table_count); - clks_log_hex(CLKS_LOG_INFO, "DRV", "ELF_DRIVERS", clks_driver_table_elf_count); -} - -u64 clks_driver_count(void) { - return clks_driver_table_count; -} - -u64 clks_driver_elf_count(void) { - return clks_driver_table_elf_count; -} - -clks_bool clks_driver_get(u64 index, struct clks_driver_info *out_info) { - if (out_info == CLKS_NULL) { - return CLKS_FALSE; - } - - if (index >= clks_driver_table_count) { - return CLKS_FALSE; - } - - *out_info = clks_driver_table[index]; - return CLKS_TRUE; -} diff --git a/clks/kernel/runtime/elf64.c b/clks/kernel/runtime/elf64.c deleted file mode 100644 index a52387b..0000000 --- a/clks/kernel/runtime/elf64.c +++ /dev/null @@ -1,363 +0,0 @@ -#include -#include -#include -#include -#include - -#define CLKS_ELF64_MAGIC_0 0x7FU -#define CLKS_ELF64_MAGIC_1 'E' -#define CLKS_ELF64_MAGIC_2 'L' -#define CLKS_ELF64_MAGIC_3 'F' - -#define CLKS_ELF64_CLASS_64 2U -#define CLKS_ELF64_DATA_LSB 1U -#define CLKS_ELF64_VERSION 1U - -#define CLKS_ELF64_ET_EXEC 2U -#define CLKS_ELF64_ET_DYN 3U - -#define CLKS_ELF64_EM_X86_64 62U - -#define CLKS_ELF64_PF_X 0x1U - -struct clks_elf64_ehdr { - u8 e_ident[16]; - u16 e_type; - u16 e_machine; - u32 e_version; - u64 e_entry; - u64 e_phoff; - u64 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shnum; - u16 e_shstrndx; -}; - -struct clks_elf64_phdr { - u32 p_type; - u32 p_flags; - u64 p_offset; - u64 p_vaddr; - u64 p_paddr; - u64 p_filesz; - u64 p_memsz; - u64 p_align; -}; - -static clks_bool clks_elf64_header_ok(const struct clks_elf64_ehdr *eh) { - if (eh->e_ident[0] != CLKS_ELF64_MAGIC_0 || eh->e_ident[1] != CLKS_ELF64_MAGIC_1 || - eh->e_ident[2] != CLKS_ELF64_MAGIC_2 || eh->e_ident[3] != CLKS_ELF64_MAGIC_3) { - return CLKS_FALSE; - } - - if (eh->e_ident[4] != CLKS_ELF64_CLASS_64 || eh->e_ident[5] != CLKS_ELF64_DATA_LSB) { - return CLKS_FALSE; - } - - if (eh->e_ident[6] != CLKS_ELF64_VERSION || eh->e_version != CLKS_ELF64_VERSION) { - return CLKS_FALSE; - } - - if (eh->e_type != CLKS_ELF64_ET_EXEC && eh->e_type != CLKS_ELF64_ET_DYN) { - return CLKS_FALSE; - } - - if (eh->e_machine != CLKS_ELF64_EM_X86_64) { - return CLKS_FALSE; - } - - if (eh->e_ehsize != sizeof(struct clks_elf64_ehdr)) { - return CLKS_FALSE; - } - - if (eh->e_phentsize != sizeof(struct clks_elf64_phdr)) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_elf64_range_ok(u64 off, u64 len, u64 total) { - if (off > total) { - return CLKS_FALSE; - } - - if (len > (total - off)) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static void clks_elf64_rebase_exec_pointers(struct clks_elf64_loaded_image *loaded, u64 old_base, u64 old_end, - u64 delta) { - u16 seg_index; - - if (loaded == CLKS_NULL || delta == 0ULL || old_end <= old_base) { - return; - } - - for (seg_index = 0U; seg_index < loaded->segment_count; seg_index++) { - struct clks_elf64_loaded_segment *seg = &loaded->segments[seg_index]; - u64 scan_len; - u64 off; - - /* Skip executable segments to avoid patching instruction bytes. */ - if ((seg->flags & CLKS_ELF64_PF_X) != 0U) { - continue; - } - - scan_len = seg->filesz; - if (scan_len < sizeof(u64)) { - continue; - } - - scan_len -= (scan_len % sizeof(u64)); - - for (off = 0ULL; off < scan_len; off += sizeof(u64)) { - u64 *slot = (u64 *)((u8 *)seg->base + (usize)off); - u64 value = *slot; - - if (value >= old_base && value < old_end) { - *slot = value + delta; - } - } - } -} - -clks_bool clks_elf64_validate(const void *image, u64 size) { - const struct clks_elf64_ehdr *eh; - u64 ph_table_size; - u16 i; - - if (image == CLKS_NULL) { - return CLKS_FALSE; - } - - if (size < sizeof(struct clks_elf64_ehdr)) { - return CLKS_FALSE; - } - - eh = (const struct clks_elf64_ehdr *)image; - - if (clks_elf64_header_ok(eh) == CLKS_FALSE) { - return CLKS_FALSE; - } - - ph_table_size = (u64)eh->e_phnum * (u64)eh->e_phentsize; - - if (clks_elf64_range_ok(eh->e_phoff, ph_table_size, size) == CLKS_FALSE) { - return CLKS_FALSE; - } - - for (i = 0; i < eh->e_phnum; i++) { - const struct clks_elf64_phdr *ph = - (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); - - if (ph->p_type != CLKS_ELF64_PT_LOAD) { - continue; - } - - if (ph->p_filesz > ph->p_memsz) { - return CLKS_FALSE; - } - - if (clks_elf64_range_ok(ph->p_offset, ph->p_filesz, size) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info *out_info) { - const struct clks_elf64_ehdr *eh; - u16 i; - - if (out_info == CLKS_NULL) { - return CLKS_FALSE; - } - - clks_memset(out_info, 0, sizeof(*out_info)); - - if (clks_elf64_validate(image, size) == CLKS_FALSE) { - return CLKS_FALSE; - } - - eh = (const struct clks_elf64_ehdr *)image; - - out_info->entry = eh->e_entry; - out_info->phnum = eh->e_phnum; - - for (i = 0; i < eh->e_phnum; i++) { - const struct clks_elf64_phdr *ph = - (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); - - if (ph->p_type != CLKS_ELF64_PT_LOAD) { - continue; - } - - out_info->loadable_segments++; - out_info->total_load_memsz += ph->p_memsz; - } - - return CLKS_TRUE; -} - -clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded) { - const struct clks_elf64_ehdr *eh; - u16 i; - u16 load_count = 0U; - u64 min_vaddr = 0ULL; - u64 max_vaddr_end = 0ULL; - u64 span; - void *image_base; - - if (out_loaded == CLKS_NULL) { - return CLKS_FALSE; - } - - clks_memset(out_loaded, 0, sizeof(*out_loaded)); - - if (clks_elf64_validate(image, size) == CLKS_FALSE) { - return CLKS_FALSE; - } - - eh = (const struct clks_elf64_ehdr *)image; - - for (i = 0; i < eh->e_phnum; i++) { - const struct clks_elf64_phdr *ph = - (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); - u64 seg_end; - - if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) { - continue; - } - - if (load_count == 0U || ph->p_vaddr < min_vaddr) { - min_vaddr = ph->p_vaddr; - } - - seg_end = ph->p_vaddr + ph->p_memsz; - if (seg_end < ph->p_vaddr) { - return CLKS_FALSE; - } - - if (load_count == 0U || seg_end > max_vaddr_end) { - max_vaddr_end = seg_end; - } - - load_count++; - } - - if (load_count == 0U) { - return CLKS_FALSE; - } - - if (load_count > CLKS_ELF64_MAX_SEGMENTS) { - return CLKS_FALSE; - } - - span = max_vaddr_end - min_vaddr; - if (span == 0ULL) { - return CLKS_FALSE; - } - - image_base = clks_kmalloc((usize)span); - if (image_base == CLKS_NULL) { - clks_log(CLKS_LOG_WARN, "ELF", "LOAD ALLOC FAILED"); - clks_log_hex(CLKS_LOG_WARN, "ELF", "SPAN", span); - clks_log_hex(CLKS_LOG_WARN, "ELF", "MIN_VADDR", min_vaddr); - clks_log_hex(CLKS_LOG_WARN, "ELF", "MAX_VADDR_END", max_vaddr_end); - return CLKS_FALSE; - } - - clks_memset(image_base, 0, (usize)span); - - out_loaded->entry = eh->e_entry; - out_loaded->image_base = image_base; - out_loaded->image_size = span; - out_loaded->image_vaddr_base = min_vaddr; - out_loaded->segment_count = 0U; - - for (i = 0; i < eh->e_phnum; i++) { - const struct clks_elf64_phdr *ph = - (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); - u64 seg_off; - u8 *seg_dst; - - if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) { - continue; - } - - if (out_loaded->segment_count >= CLKS_ELF64_MAX_SEGMENTS) { - clks_elf64_unload(out_loaded); - return CLKS_FALSE; - } - - seg_off = ph->p_vaddr - min_vaddr; - if (seg_off > span || ph->p_memsz > (span - seg_off)) { - clks_elf64_unload(out_loaded); - return CLKS_FALSE; - } - - seg_dst = (u8 *)image_base + (usize)seg_off; - clks_memcpy(seg_dst, (const void *)((const u8 *)image + ph->p_offset), (usize)ph->p_filesz); - - out_loaded->segments[out_loaded->segment_count].base = seg_dst; - out_loaded->segments[out_loaded->segment_count].vaddr = ph->p_vaddr; - out_loaded->segments[out_loaded->segment_count].memsz = ph->p_memsz; - out_loaded->segments[out_loaded->segment_count].filesz = ph->p_filesz; - out_loaded->segments[out_loaded->segment_count].flags = ph->p_flags; - out_loaded->segment_count++; - } - - if (eh->e_type == CLKS_ELF64_ET_EXEC) { - u64 new_base = (u64)(usize)image_base; - u64 old_base = min_vaddr; - u64 old_end = max_vaddr_end; - - if (new_base != old_base) { - u64 delta = new_base - old_base; - clks_elf64_rebase_exec_pointers(out_loaded, old_base, old_end, delta); - } - } - - return CLKS_TRUE; -} - -void clks_elf64_unload(struct clks_elf64_loaded_image *loaded) { - if (loaded == CLKS_NULL) { - return; - } - - if (loaded->image_base != CLKS_NULL) { - clks_kfree(loaded->image_base); - } - - clks_memset(loaded, 0, sizeof(*loaded)); -} - -void *clks_elf64_entry_pointer(const struct clks_elf64_loaded_image *loaded, u64 entry) { - u64 off; - - if (loaded == CLKS_NULL || loaded->image_base == CLKS_NULL) { - return CLKS_NULL; - } - - if (entry < loaded->image_vaddr_base) { - return CLKS_NULL; - } - - off = entry - loaded->image_vaddr_base; - - if (off >= loaded->image_size) { - return CLKS_NULL; - } - - return (void *)((u8 *)loaded->image_base + (usize)off); -} diff --git a/clks/kernel/runtime/elfrunner.c b/clks/kernel/runtime/elfrunner.c deleted file mode 100644 index f0f941c..0000000 --- a/clks/kernel/runtime/elfrunner.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include -#include - -static clks_bool clks_elfrunner_ready = CLKS_FALSE; - -void clks_elfrunner_init(void) { - clks_elfrunner_ready = CLKS_TRUE; - clks_log(CLKS_LOG_INFO, "ELF", "ELFRUNNER FRAMEWORK ONLINE"); -} - -clks_bool clks_elfrunner_probe_kernel_executable(void) { - const struct limine_file *exe = clks_boot_get_executable_file(); - struct clks_elf64_info info; - - if (clks_elfrunner_ready == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (exe == CLKS_NULL || exe->address == CLKS_NULL || exe->size == 0ULL) { - clks_log(CLKS_LOG_ERROR, "ELF", "NO EXECUTABLE FILE FROM LIMINE"); - return CLKS_FALSE; - } - - if (clks_elf64_inspect(exe->address, exe->size, &info) == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF INSPECT FAILED"); - return CLKS_FALSE; - } - - clks_log_hex(CLKS_LOG_INFO, "ELF", "ENTRY", info.entry); - clks_log_hex(CLKS_LOG_INFO, "ELF", "PHNUM", info.phnum); - clks_log_hex(CLKS_LOG_INFO, "ELF", "LOAD_SEGMENTS", info.loadable_segments); - clks_log_hex(CLKS_LOG_INFO, "ELF", "TOTAL_MEMSZ", info.total_load_memsz); - - return CLKS_TRUE; -} \ No newline at end of file diff --git a/clks/kernel/runtime/exec.c b/clks/kernel/runtime/exec.c deleted file mode 100644 index 6dfc66a..0000000 --- a/clks/kernel/runtime/exec.c +++ /dev/null @@ -1,2782 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Process runtime core: this is where tiny mistakes become giant explosions. */ - -typedef u64 (*clks_exec_entry_fn)(void); - -#define CLKS_EXEC_RUN_STACK_BYTES (1024ULL * 1024ULL) -#define CLKS_EXEC_MAX_PROCS 64U -/* 64 is a compromise: enough to be useful, small enough to not eat RAM for breakfast. */ -#define CLKS_EXEC_MAX_DEPTH 16U -#define CLKS_EXEC_PATH_MAX 192U -#define CLKS_EXEC_ARG_LINE_MAX 256U -#define CLKS_EXEC_ENV_LINE_MAX 512U -#define CLKS_EXEC_FD_MAX 32U -#define CLKS_EXEC_MAX_ARGS 24U -#define CLKS_EXEC_MAX_ENVS 24U -#define CLKS_EXEC_ITEM_MAX 128U -#define CLKS_EXEC_STATUS_SIGNAL_FLAG (1ULL << 63) -#define CLKS_EXEC_DEFAULT_KILL_SIGNAL CLKS_EXEC_SIGNAL_TERM -#define CLKS_EXEC_KERNEL_ADDR_BASE 0xFFFF800000000000ULL -#define CLKS_EXEC_UNWIND_CTX_BYTES 56ULL -#define CLKS_EXEC_FD_ACCESS_MASK 0x3ULL -#define CLKS_EXEC_O_RDONLY 0x0000ULL -#define CLKS_EXEC_O_WRONLY 0x0001ULL -#define CLKS_EXEC_O_RDWR 0x0002ULL -#define CLKS_EXEC_O_CREAT 0x0040ULL -#define CLKS_EXEC_O_TRUNC 0x0200ULL -#define CLKS_EXEC_O_APPEND 0x0400ULL -#define CLKS_EXEC_FD_INHERIT ((u64) - 1) -#define CLKS_EXEC_DYNLIB_MAX 32U - -#ifndef CLKS_CFG_EXEC_SERIAL_LOG -#define CLKS_CFG_EXEC_SERIAL_LOG 1 -#endif - -#define CLKS_EXEC_ELF64_MAGIC_0 0x7FU -#define CLKS_EXEC_ELF64_MAGIC_1 'E' -#define CLKS_EXEC_ELF64_MAGIC_2 'L' -#define CLKS_EXEC_ELF64_MAGIC_3 'F' -#define CLKS_EXEC_ELF64_CLASS_64 2U -#define CLKS_EXEC_ELF64_DATA_LSB 1U -#define CLKS_EXEC_ELF64_VERSION 1U - -#define CLKS_EXEC_ELF64_SHT_SYMTAB 2U -#define CLKS_EXEC_ELF64_SHT_DYNSYM 11U -#define CLKS_EXEC_ELF64_SHN_UNDEF 0U -#define CLKS_EXEC_ELF64_STT_NOTYPE 0U -#define CLKS_EXEC_ELF64_STT_FUNC 2U - -enum clks_exec_fd_kind { - CLKS_EXEC_FD_KIND_NONE = 0, - CLKS_EXEC_FD_KIND_TTY = 1, - CLKS_EXEC_FD_KIND_FILE = 2, - CLKS_EXEC_FD_KIND_DEV_NULL = 3, - CLKS_EXEC_FD_KIND_DEV_ZERO = 4, - CLKS_EXEC_FD_KIND_DEV_RANDOM = 5, -}; - -enum clks_exec_proc_state { - CLKS_EXEC_PROC_UNUSED = 0, - CLKS_EXEC_PROC_PENDING = 1, - CLKS_EXEC_PROC_RUNNING = 2, - CLKS_EXEC_PROC_EXITED = 3, - CLKS_EXEC_PROC_STOPPED = 4, -}; - -struct clks_exec_fd_entry { - clks_bool used; - enum clks_exec_fd_kind kind; - u64 flags; - u64 offset; - u32 tty_index; - char path[CLKS_EXEC_PATH_MAX]; -}; - -struct clks_exec_proc_record { - clks_bool used; - enum clks_exec_proc_state state; - u64 pid; - u64 ppid; - u64 started_tick; - u64 exited_tick; - u64 run_started_tick; - u64 runtime_ticks_accum; - u64 exit_status; - u32 tty_index; - u64 image_mem_bytes; - char path[CLKS_EXEC_PATH_MAX]; - char argv_line[CLKS_EXEC_ARG_LINE_MAX]; - char env_line[CLKS_EXEC_ENV_LINE_MAX]; - u32 argc; - u32 envc; - char argv_items[CLKS_EXEC_MAX_ARGS][CLKS_EXEC_ITEM_MAX]; - char env_items[CLKS_EXEC_MAX_ENVS][CLKS_EXEC_ITEM_MAX]; - u64 last_signal; - u64 last_fault_vector; - u64 last_fault_error; - u64 last_fault_rip; - struct clks_exec_fd_entry fds[CLKS_EXEC_FD_MAX]; -}; - -struct clks_exec_elf64_ehdr { - u8 e_ident[16]; - u16 e_type; - u16 e_machine; - u32 e_version; - u64 e_entry; - u64 e_phoff; - u64 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shnum; - u16 e_shstrndx; -}; - -struct clks_exec_elf64_shdr { - u32 sh_name; - u32 sh_type; - u64 sh_flags; - u64 sh_addr; - u64 sh_offset; - u64 sh_size; - u32 sh_link; - u32 sh_info; - u64 sh_addralign; - u64 sh_entsize; -}; - -struct clks_exec_elf64_sym { - u32 st_name; - u8 st_info; - u8 st_other; - u16 st_shndx; - u64 st_value; - u64 st_size; -}; - -struct clks_exec_dynlib_slot { - clks_bool used; - u64 handle; - u64 owner_pid; - u64 ref_count; - char path[CLKS_EXEC_PATH_MAX]; - const void *file_image; - u64 file_size; - struct clks_elf64_loaded_image loaded; -}; - -#if defined(CLKS_ARCH_X86_64) -extern u64 clks_exec_call_on_stack_x86_64(void *entry_ptr, void *stack_top); -extern void clks_exec_abort_to_caller_x86_64(void); -static u64 clks_exec_read_cr2(void) { - u64 value = 0ULL; - __asm__ volatile("mov %%cr2, %0" : "=r"(value)); - return value; -} -#endif - -static u64 clks_exec_requests = 0ULL; -static u64 clks_exec_success = 0ULL; -static u32 clks_exec_running_depth = 0U; -static clks_bool clks_exec_pending_dispatch_active = CLKS_FALSE; -static u64 clks_exec_random_state = 0xA5A55A5A12345678ULL; - -static struct clks_exec_proc_record clks_exec_proc_table[CLKS_EXEC_MAX_PROCS]; -static u64 clks_exec_next_pid = 1ULL; -static u64 clks_exec_pid_stack[CLKS_EXEC_MAX_DEPTH]; -static clks_bool clks_exec_exit_requested_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_exit_status_stack[CLKS_EXEC_MAX_DEPTH]; -static clks_bool clks_exec_stop_requested_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_unwind_slot_stack[CLKS_EXEC_MAX_DEPTH]; -static clks_bool clks_exec_unwind_slot_valid_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_image_begin_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_image_end_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_image_vaddr_begin_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_image_vaddr_end_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_stack_begin_stack[CLKS_EXEC_MAX_DEPTH]; -static u64 clks_exec_stack_end_stack[CLKS_EXEC_MAX_DEPTH]; -static u32 clks_exec_pid_stack_depth = 0U; -static struct clks_exec_dynlib_slot clks_exec_dynlib_table[CLKS_EXEC_DYNLIB_MAX]; -static u64 clks_exec_next_dynlib_handle = 1ULL; - -static struct clks_exec_proc_record *clks_exec_current_proc(void); - -static void clks_exec_serial_write_hex64(u64 value) { - int nibble; - - clks_serial_write("0X"); - - for (nibble = 15; nibble >= 0; nibble--) { - u8 current = (u8)((value >> (nibble * 4)) & 0x0FULL); - char out = (current < 10U) ? (char)('0' + current) : (char)('A' + (current - 10U)); - clks_serial_write_char(out); - } -} - -static void clks_exec_log_info_serial(const char *message) { - /* Serial logs stay because they save our ass when TTY is dead. */ - if (CLKS_CFG_EXEC_SERIAL_LOG == 0) { - (void)message; - return; - } - - clks_serial_write("[INFO][EXEC] "); - - if (message != CLKS_NULL) { - clks_serial_write(message); - } - - clks_serial_write("\n"); -} - -static void clks_exec_log_hex_serial(const char *label, u64 value) { - if (CLKS_CFG_EXEC_SERIAL_LOG == 0) { - (void)label; - (void)value; - return; - } - - clks_serial_write("[INFO][EXEC] "); - - if (label != CLKS_NULL) { - clks_serial_write(label); - } - - clks_serial_write(": "); - clks_exec_serial_write_hex64(value); - clks_serial_write("\n"); -} -static clks_bool clks_exec_has_prefix(const char *text, const char *prefix) { - usize i = 0U; - - if (text == CLKS_NULL || prefix == CLKS_NULL) { - return CLKS_FALSE; - } - - while (prefix[i] != '\0') { - if (text[i] != prefix[i]) { - return CLKS_FALSE; - } - - i++; - } - - return CLKS_TRUE; -} - -static clks_bool clks_exec_has_suffix(const char *text, const char *suffix) { - usize text_len; - usize suffix_len; - usize i; - - if (text == CLKS_NULL || suffix == CLKS_NULL) { - return CLKS_FALSE; - } - - text_len = clks_strlen(text); - suffix_len = clks_strlen(suffix); - - if (suffix_len > text_len) { - return CLKS_FALSE; - } - - for (i = 0U; i < suffix_len; i++) { - if (text[text_len - suffix_len + i] != suffix[i]) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -static clks_bool clks_exec_path_is_user_program(const char *path) { - if (path == CLKS_NULL || path[0] != '/') { - return CLKS_FALSE; - } - - if (clks_exec_has_prefix(path, "/system/") == CLKS_TRUE) { - return CLKS_FALSE; - } - - if (clks_exec_has_prefix(path, "/driver/") == CLKS_TRUE) { - return CLKS_FALSE; - } - - if (clks_exec_has_prefix(path, "/shell/") == CLKS_TRUE) { - return CLKS_TRUE; - } - - return clks_exec_has_suffix(path, ".elf"); -} - -static clks_bool clks_exec_rip_is_current_user_context(u64 rip) { - i32 depth_index; - u64 image_begin; - u64 image_end; - - if (rip < CLKS_EXEC_KERNEL_ADDR_BASE) { - return CLKS_TRUE; - } - - if (clks_exec_pid_stack_depth == 0U) { - return CLKS_FALSE; - } - - depth_index = (i32)(clks_exec_pid_stack_depth - 1U); - image_begin = clks_exec_image_begin_stack[(u32)depth_index]; - image_end = clks_exec_image_end_stack[(u32)depth_index]; - - if (image_begin == 0ULL || image_end <= image_begin) { - return CLKS_FALSE; - } - - return (rip >= image_begin && rip < image_end) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_exec_translate_legacy_user_rip(u64 rip, u64 *out_rip) { - i32 depth_index; - u64 vaddr_begin; - u64 vaddr_end; - u64 image_begin; - u64 image_end; - u64 off; - u64 translated; - - if (out_rip == CLKS_NULL || clks_exec_pid_stack_depth == 0U) { - return CLKS_FALSE; - } - - depth_index = (i32)(clks_exec_pid_stack_depth - 1U); - vaddr_begin = clks_exec_image_vaddr_begin_stack[(u32)depth_index]; - vaddr_end = clks_exec_image_vaddr_end_stack[(u32)depth_index]; - image_begin = clks_exec_image_begin_stack[(u32)depth_index]; - image_end = clks_exec_image_end_stack[(u32)depth_index]; - - if (vaddr_begin == 0ULL || vaddr_end <= vaddr_begin || image_begin == 0ULL || image_end <= image_begin) { - return CLKS_FALSE; - } - - if (rip < vaddr_begin || rip >= vaddr_end) { - return CLKS_FALSE; - } - - off = rip - vaddr_begin; - - if (off >= (image_end - image_begin)) { - return CLKS_FALSE; - } - - translated = image_begin + off; - if (translated < image_begin || translated >= image_end) { - return CLKS_FALSE; - } - - *out_rip = translated; - return CLKS_TRUE; -} - -static clks_bool clks_exec_translate_loaded_user_rip_to_vaddr(u64 rip, u64 *out_rip) { - i32 depth_index; - u64 vaddr_begin; - u64 vaddr_end; - u64 image_begin; - u64 image_end; - u64 off; - u64 translated; - - if (out_rip == CLKS_NULL || clks_exec_pid_stack_depth == 0U) { - return CLKS_FALSE; - } - - depth_index = (i32)(clks_exec_pid_stack_depth - 1U); - vaddr_begin = clks_exec_image_vaddr_begin_stack[(u32)depth_index]; - vaddr_end = clks_exec_image_vaddr_end_stack[(u32)depth_index]; - image_begin = clks_exec_image_begin_stack[(u32)depth_index]; - image_end = clks_exec_image_end_stack[(u32)depth_index]; - - if (vaddr_begin == 0ULL || vaddr_end <= vaddr_begin || image_begin == 0ULL || image_end <= image_begin) { - return CLKS_FALSE; - } - - if (rip < image_begin || rip >= image_end) { - return CLKS_FALSE; - } - - off = rip - image_begin; - if (off >= (vaddr_end - vaddr_begin)) { - return CLKS_FALSE; - } - - translated = vaddr_begin + off; - if (translated < vaddr_begin || translated >= vaddr_end) { - return CLKS_FALSE; - } - - *out_rip = translated; - return CLKS_TRUE; -} - -static void clks_exec_copy_path(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || src == CLKS_NULL || dst_size == 0U) { - return; - } - - while (src[i] != '\0' && i + 1U < dst_size) { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static void clks_exec_copy_line(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || dst_size == 0U) { - return; - } - - if (src == CLKS_NULL) { - dst[0] = '\0'; - return; - } - - while (src[i] != '\0' && i + 1U < dst_size) { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static clks_bool clks_exec_range_ok(u64 off, u64 len, u64 total) { - if (off > total) { - return CLKS_FALSE; - } - - if (len > (total - off)) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_exec_addr_range_in_window(u64 addr, u64 size, u64 begin, u64 end) { - if (begin == 0ULL || end <= begin) { - return CLKS_FALSE; - } - - if (size == 0ULL) { - return CLKS_FALSE; - } - - if (addr < begin || addr >= end) { - return CLKS_FALSE; - } - - if (size > (end - addr)) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static i32 clks_exec_dynlib_alloc_slot(void) { - u32 i; - - for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { - if (clks_exec_dynlib_table[i].used == CLKS_FALSE) { - return (i32)i; - } - } - - return -1; -} - -static i32 clks_exec_dynlib_find_by_handle(u64 handle) { - u32 i; - - for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { - if (clks_exec_dynlib_table[i].used == CLKS_TRUE && clks_exec_dynlib_table[i].handle == handle) { - return (i32)i; - } - } - - return -1; -} - -static i32 clks_exec_dynlib_find_by_owner_path(u64 owner_pid, const char *path) { - u32 i; - - if (path == CLKS_NULL) { - return -1; - } - - for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { - if (clks_exec_dynlib_table[i].used != CLKS_TRUE) { - continue; - } - - if (clks_exec_dynlib_table[i].owner_pid == owner_pid && - clks_strcmp(clks_exec_dynlib_table[i].path, path) == 0) { - return (i32)i; - } - } - - return -1; -} - -static u64 clks_exec_dynlib_alloc_handle(void) { - u64 handle = clks_exec_next_dynlib_handle; - - clks_exec_next_dynlib_handle++; - if (clks_exec_next_dynlib_handle == 0ULL) { - clks_exec_next_dynlib_handle = 1ULL; - } - - if (handle == 0ULL) { - handle = clks_exec_next_dynlib_handle; - clks_exec_next_dynlib_handle++; - if (clks_exec_next_dynlib_handle == 0ULL) { - clks_exec_next_dynlib_handle = 1ULL; - } - } - - return handle; -} - -static void clks_exec_dynlib_slot_reset(struct clks_exec_dynlib_slot *slot) { - if (slot == CLKS_NULL) { - return; - } - - if (slot->used == CLKS_TRUE && slot->loaded.image_base != CLKS_NULL) { - clks_elf64_unload(&slot->loaded); - } - - clks_memset(slot, 0, sizeof(*slot)); -} - -static void clks_exec_dynlib_release_owner(u64 owner_pid) { - u32 i; - - if (owner_pid == 0ULL) { - return; - } - - for (i = 0U; i < CLKS_EXEC_DYNLIB_MAX; i++) { - if (clks_exec_dynlib_table[i].used == CLKS_TRUE && clks_exec_dynlib_table[i].owner_pid == owner_pid) { - clks_exec_dynlib_slot_reset(&clks_exec_dynlib_table[i]); - } - } -} - -static clks_bool clks_exec_dynlib_elf_header_ok(const struct clks_exec_elf64_ehdr *eh) { - if (eh == CLKS_NULL) { - return CLKS_FALSE; - } - - if (eh->e_ident[0] != CLKS_EXEC_ELF64_MAGIC_0 || eh->e_ident[1] != CLKS_EXEC_ELF64_MAGIC_1 || - eh->e_ident[2] != CLKS_EXEC_ELF64_MAGIC_2 || eh->e_ident[3] != CLKS_EXEC_ELF64_MAGIC_3) { - return CLKS_FALSE; - } - - if (eh->e_ident[4] != CLKS_EXEC_ELF64_CLASS_64 || eh->e_ident[5] != CLKS_EXEC_ELF64_DATA_LSB) { - return CLKS_FALSE; - } - - if (eh->e_ident[6] != CLKS_EXEC_ELF64_VERSION || eh->e_version != CLKS_EXEC_ELF64_VERSION) { - return CLKS_FALSE; - } - - if (eh->e_shentsize != sizeof(struct clks_exec_elf64_shdr)) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_exec_dynlib_symbol_name_ptr(const char *strtab, u64 strtab_size, u32 st_name, - const char **out_name) { - u64 i; - - if (out_name != CLKS_NULL) { - *out_name = CLKS_NULL; - } - - if (strtab == CLKS_NULL || out_name == CLKS_NULL || st_name >= strtab_size) { - return CLKS_FALSE; - } - - for (i = (u64)st_name; i < strtab_size; i++) { - if (strtab[i] == '\0') { - *out_name = &strtab[st_name]; - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static clks_bool clks_exec_dynlib_resolve_symbol(const struct clks_exec_dynlib_slot *slot, const char *symbol, - u64 *out_addr) { - const struct clks_exec_elf64_ehdr *eh; - const struct clks_exec_elf64_shdr *shdrs; - const u8 *image; - u64 i; - u64 sh_table_size; - - if (out_addr != CLKS_NULL) { - *out_addr = 0ULL; - } - - if (slot == CLKS_NULL || slot->used != CLKS_TRUE || symbol == CLKS_NULL || symbol[0] == '\0' || - out_addr == CLKS_NULL) { - return CLKS_FALSE; - } - - image = (const u8 *)slot->file_image; - - if (image == CLKS_NULL || slot->file_size < sizeof(struct clks_exec_elf64_ehdr)) { - return CLKS_FALSE; - } - - eh = (const struct clks_exec_elf64_ehdr *)image; - - if (clks_exec_dynlib_elf_header_ok(eh) == CLKS_FALSE || eh->e_shnum == 0U || eh->e_shoff == 0ULL) { - return CLKS_FALSE; - } - - sh_table_size = (u64)eh->e_shnum * (u64)eh->e_shentsize; - if (clks_exec_range_ok(eh->e_shoff, sh_table_size, slot->file_size) == CLKS_FALSE) { - return CLKS_FALSE; - } - - shdrs = (const struct clks_exec_elf64_shdr *)(image + (usize)eh->e_shoff); - - for (i = 0ULL; i < (u64)eh->e_shnum; i++) { - const struct clks_exec_elf64_shdr *symtab = &shdrs[i]; - const struct clks_exec_elf64_shdr *strtab; - const struct clks_exec_elf64_sym *symbols; - const char *strings; - u64 sym_count; - u64 j; - - if (symtab->sh_type != CLKS_EXEC_ELF64_SHT_SYMTAB && symtab->sh_type != CLKS_EXEC_ELF64_SHT_DYNSYM) { - continue; - } - - if (symtab->sh_entsize != sizeof(struct clks_exec_elf64_sym) || symtab->sh_link >= eh->e_shnum || - symtab->sh_size < symtab->sh_entsize) { - continue; - } - - if (clks_exec_range_ok(symtab->sh_offset, symtab->sh_size, slot->file_size) == CLKS_FALSE) { - continue; - } - - strtab = &shdrs[symtab->sh_link]; - if (clks_exec_range_ok(strtab->sh_offset, strtab->sh_size, slot->file_size) == CLKS_FALSE) { - continue; - } - - symbols = (const struct clks_exec_elf64_sym *)(image + (usize)symtab->sh_offset); - strings = (const char *)(image + (usize)strtab->sh_offset); - sym_count = symtab->sh_size / symtab->sh_entsize; - - for (j = 0ULL; j < sym_count; j++) { - const struct clks_exec_elf64_sym *sym = &symbols[j]; - const char *name_ptr; - u8 symbol_type; - u64 offset; - - if (sym->st_name == 0U || sym->st_shndx == CLKS_EXEC_ELF64_SHN_UNDEF || sym->st_value == 0ULL) { - continue; - } - - symbol_type = (u8)(sym->st_info & 0x0FU); - if (symbol_type != CLKS_EXEC_ELF64_STT_FUNC && symbol_type != CLKS_EXEC_ELF64_STT_NOTYPE) { - continue; - } - - if (clks_exec_dynlib_symbol_name_ptr(strings, strtab->sh_size, sym->st_name, &name_ptr) == CLKS_FALSE) { - continue; - } - - if (clks_strcmp(name_ptr, symbol) != 0) { - continue; - } - - if (sym->st_value < slot->loaded.image_vaddr_base) { - continue; - } - - offset = sym->st_value - slot->loaded.image_vaddr_base; - if (offset >= slot->loaded.image_size) { - continue; - } - - *out_addr = (u64)((u8 *)slot->loaded.image_base + (usize)offset); - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static void clks_exec_clear_items(char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) { - u32 i; - - for (i = 0U; i < max_count; i++) { - items[i][0] = '\0'; - } -} - -static u32 clks_exec_parse_whitespace_items(const char *line, char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) { - u32 count = 0U; - usize i = 0U; - - if (line == CLKS_NULL || items == CLKS_NULL || max_count == 0U) { - return 0U; - } - - while (line[i] != '\0') { - usize p = 0U; - - while (line[i] == ' ' || line[i] == '\t' || line[i] == '\r' || line[i] == '\n') { - i++; - } - - if (line[i] == '\0') { - break; - } - - if (count >= max_count) { - break; - } - - while (line[i] != '\0' && line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] != '\n') { - if (p + 1U < CLKS_EXEC_ITEM_MAX) { - items[count][p++] = line[i]; - } - - i++; - } - - items[count][p] = '\0'; - count++; - } - - return count; -} - -static u32 clks_exec_parse_env_items(const char *line, char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) { - u32 count = 0U; - usize i = 0U; - - if (line == CLKS_NULL || items == CLKS_NULL || max_count == 0U) { - return 0U; - } - - while (line[i] != '\0') { - usize p = 0U; - usize end_trim = 0U; - - while (line[i] == ' ' || line[i] == '\t' || line[i] == ';' || line[i] == '\r' || line[i] == '\n') { - i++; - } - - if (line[i] == '\0') { - break; - } - - if (count >= max_count) { - break; - } - - while (line[i] != '\0' && line[i] != ';' && line[i] != '\r' && line[i] != '\n') { - if (p + 1U < CLKS_EXEC_ITEM_MAX) { - items[count][p++] = line[i]; - } - i++; - } - - while (p > 0U && (items[count][p - 1U] == ' ' || items[count][p - 1U] == '\t')) { - p--; - } - - end_trim = p; - items[count][end_trim] = '\0'; - - if (end_trim > 0U) { - count++; - } - } - - return count; -} - -static u64 clks_exec_signal_from_vector(u64 vector) { - switch (vector) { - case 0ULL: - case 16ULL: - case 19ULL: - return 8ULL; - case 6ULL: - return 4ULL; - case 3ULL: - return 5ULL; - case 14ULL: - case 13ULL: - case 12ULL: - case 11ULL: - case 10ULL: - case 17ULL: - return 11ULL; - default: - return 6ULL; - } -} - -static u64 clks_exec_encode_signal_status(u64 signal, u64 vector, u64 error_code) { - return CLKS_EXEC_STATUS_SIGNAL_FLAG | (signal & 0xFFULL) | ((vector & 0xFFULL) << 8) | - ((error_code & 0xFFFFULL) << 16); -} - -static clks_bool clks_exec_status_is_signal(u64 status) { - return ((status & CLKS_EXEC_STATUS_SIGNAL_FLAG) != 0ULL) ? CLKS_TRUE : CLKS_FALSE; -} - -static u64 clks_exec_status_signal(u64 status) { - return status & 0xFFULL; -} - -static u64 clks_exec_status_vector(u64 status) { - return (status >> 8) & 0xFFULL; -} - -static u64 clks_exec_status_error(u64 status) { - return (status >> 16) & 0xFFFFULL; -} - -static clks_bool clks_exec_status_is_user_terminated(u64 status) { - u64 signal; - - if (clks_exec_status_is_signal(status) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_exec_status_vector(status) != 0ULL || clks_exec_status_error(status) != 0ULL) { - return CLKS_FALSE; - } - - signal = clks_exec_status_signal(status); - if (signal == CLKS_EXEC_SIGNAL_TERM || signal == CLKS_EXEC_SIGNAL_KILL || signal == CLKS_EXEC_SIGNAL_STOP) { - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -static i32 clks_exec_proc_find_slot_by_pid(u64 pid) { - u32 i; - - for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { - if (clks_exec_proc_table[i].used == CLKS_TRUE && clks_exec_proc_table[i].pid == pid) { - return (i32)i; - } - } - - return -1; -} - -static i32 clks_exec_proc_alloc_slot(void) { - u32 i; - - /* First pass: find free slot. Second pass: recycle corpses. Brutal but effective. */ - for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { - if (clks_exec_proc_table[i].used == CLKS_FALSE) { - return (i32)i; - } - } - - for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { - if (clks_exec_proc_table[i].state == CLKS_EXEC_PROC_EXITED) { - return (i32)i; - } - } - - return -1; -} - -static i32 clks_exec_current_depth_index(void) { - if (clks_exec_pid_stack_depth == 0U) { - return -1; - } - - return (i32)(clks_exec_pid_stack_depth - 1U); -} - -static u64 clks_exec_alloc_pid(void) { - u64 pid = clks_exec_next_pid; - - clks_exec_next_pid++; - - if (clks_exec_next_pid == 0ULL) { - clks_exec_next_pid = 1ULL; - } - - if (pid == 0ULL) { - pid = clks_exec_next_pid; - clks_exec_next_pid++; - - if (clks_exec_next_pid == 0ULL) { - clks_exec_next_pid = 1ULL; - } - } - - return pid; -} - -static clks_bool clks_exec_fd_access_mode_valid(u64 flags) { - u64 mode = flags & CLKS_EXEC_FD_ACCESS_MASK; - return (mode == CLKS_EXEC_O_RDONLY || mode == CLKS_EXEC_O_WRONLY || mode == CLKS_EXEC_O_RDWR) ? CLKS_TRUE - : CLKS_FALSE; -} - -static clks_bool clks_exec_fd_can_read(u64 flags) { - u64 mode = flags & CLKS_EXEC_FD_ACCESS_MASK; - return (mode == CLKS_EXEC_O_RDONLY || mode == CLKS_EXEC_O_RDWR) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_exec_fd_can_write(u64 flags) { - u64 mode = flags & CLKS_EXEC_FD_ACCESS_MASK; - return (mode == CLKS_EXEC_O_WRONLY || mode == CLKS_EXEC_O_RDWR) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_exec_path_is_dev_tty(const char *path) { - return (path != CLKS_NULL && clks_strcmp(path, "/dev/tty") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_exec_path_is_dev_null(const char *path) { - return (path != CLKS_NULL && clks_strcmp(path, "/dev/null") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_exec_path_is_dev_zero(const char *path) { - return (path != CLKS_NULL && clks_strcmp(path, "/dev/zero") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_exec_path_is_dev_random(const char *path) { - if (path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_strcmp(path, "/dev/random") == 0) { - return CLKS_TRUE; - } - - return (clks_strcmp(path, "/dev/urandom") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static u8 clks_exec_random_next_byte(void) { - clks_exec_random_state ^= (clks_interrupts_timer_ticks() + 0x9E3779B97F4A7C15ULL); - clks_exec_random_state ^= (clks_exec_random_state << 13); - clks_exec_random_state ^= (clks_exec_random_state >> 7); - clks_exec_random_state ^= (clks_exec_random_state << 17); - return (u8)(clks_exec_random_state & 0xFFULL); -} - -static void clks_exec_fd_init_defaults(struct clks_exec_proc_record *proc) { - if (proc == CLKS_NULL) { - return; - } - - clks_memset(proc->fds, 0, sizeof(proc->fds)); - - proc->fds[0].used = CLKS_TRUE; - proc->fds[0].kind = CLKS_EXEC_FD_KIND_TTY; - proc->fds[0].flags = CLKS_EXEC_O_RDONLY; - proc->fds[0].offset = 0ULL; - proc->fds[0].tty_index = proc->tty_index; - proc->fds[0].path[0] = '\0'; - - proc->fds[1].used = CLKS_TRUE; - proc->fds[1].kind = CLKS_EXEC_FD_KIND_TTY; - proc->fds[1].flags = CLKS_EXEC_O_WRONLY; - proc->fds[1].offset = 0ULL; - proc->fds[1].tty_index = proc->tty_index; - proc->fds[1].path[0] = '\0'; - - proc->fds[2].used = CLKS_TRUE; - proc->fds[2].kind = CLKS_EXEC_FD_KIND_TTY; - proc->fds[2].flags = CLKS_EXEC_O_WRONLY; - proc->fds[2].offset = 0ULL; - proc->fds[2].tty_index = proc->tty_index; - proc->fds[2].path[0] = '\0'; -} - -static clks_bool clks_exec_fd_copy_from_parent(struct clks_exec_proc_record *child, - const struct clks_exec_proc_record *parent, u64 parent_fd, u64 child_fd, - clks_bool require_read, clks_bool require_write) { - const struct clks_exec_fd_entry *src; - - if (child == CLKS_NULL || parent == CLKS_NULL || parent_fd >= CLKS_EXEC_FD_MAX || child_fd >= CLKS_EXEC_FD_MAX) { - return CLKS_FALSE; - } - - src = &parent->fds[(u32)parent_fd]; - - if (src->used == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (require_read == CLKS_TRUE && clks_exec_fd_can_read(src->flags) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (require_write == CLKS_TRUE && clks_exec_fd_can_write(src->flags) == CLKS_FALSE) { - return CLKS_FALSE; - } - - child->fds[(u32)child_fd] = *src; - return CLKS_TRUE; -} - -static clks_bool clks_exec_fd_apply_stdio_overrides(struct clks_exec_proc_record *child, - const struct clks_exec_proc_record *parent, u64 stdin_fd, - u64 stdout_fd, u64 stderr_fd) { - if (child == CLKS_NULL) { - return CLKS_FALSE; - } - - if (stdin_fd != CLKS_EXEC_FD_INHERIT) { - if (clks_exec_fd_copy_from_parent(child, parent, stdin_fd, 0ULL, CLKS_TRUE, CLKS_FALSE) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - if (stdout_fd != CLKS_EXEC_FD_INHERIT) { - if (clks_exec_fd_copy_from_parent(child, parent, stdout_fd, 1ULL, CLKS_FALSE, CLKS_TRUE) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - if (stderr_fd != CLKS_EXEC_FD_INHERIT) { - if (clks_exec_fd_copy_from_parent(child, parent, stderr_fd, 2ULL, CLKS_FALSE, CLKS_TRUE) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -static i32 clks_exec_fd_find_free(struct clks_exec_proc_record *proc) { - u32 i; - - if (proc == CLKS_NULL) { - return -1; - } - - for (i = 0U; i < CLKS_EXEC_FD_MAX; i++) { - if (proc->fds[i].used == CLKS_FALSE) { - return (i32)i; - } - } - - return -1; -} - -static struct clks_exec_fd_entry *clks_exec_fd_lookup(struct clks_exec_proc_record *proc, u64 fd) { - if (proc == CLKS_NULL || fd >= CLKS_EXEC_FD_MAX) { - return CLKS_NULL; - } - - if (proc->fds[(u32)fd].used == CLKS_FALSE) { - return CLKS_NULL; - } - - return &proc->fds[(u32)fd]; -} - -static u64 clks_exec_fd_file_read(struct clks_exec_fd_entry *entry, void *out_buffer, u64 size) { - const void *file_data; - u64 file_size = 0ULL; - u64 read_len; - - if (entry == CLKS_NULL || out_buffer == CLKS_NULL || size == 0ULL) { - return 0ULL; - } - - file_data = clks_fs_read_all(entry->path, &file_size); - - if (file_data == CLKS_NULL) { - return (u64)-1; - } - - if (entry->offset >= file_size) { - return 0ULL; - } - - read_len = file_size - entry->offset; - - if (read_len > size) { - read_len = size; - } - - clks_memcpy(out_buffer, (const u8 *)file_data + (usize)entry->offset, (usize)read_len); - entry->offset += read_len; - return read_len; -} - -static u64 clks_exec_fd_file_write(struct clks_exec_fd_entry *entry, const void *buffer, u64 size) { - const void *old_data = CLKS_NULL; - u64 old_size = 0ULL; - u64 write_pos; - u64 new_size; - void *merged = CLKS_NULL; - clks_bool ok; - - if (entry == CLKS_NULL) { - return (u64)-1; - } - - if (size == 0ULL) { - return 0ULL; - } - - if (buffer == CLKS_NULL) { - return (u64)-1; - } - - if ((entry->flags & CLKS_EXEC_O_APPEND) != 0ULL) { - if (clks_fs_append(entry->path, buffer, size) == CLKS_FALSE) { - return (u64)-1; - } - - entry->offset += size; - return size; - } - - old_data = clks_fs_read_all(entry->path, &old_size); - - if (old_data == CLKS_NULL) { - return (u64)-1; - } - - write_pos = entry->offset; - - if (write_pos > (0xFFFFFFFFFFFFFFFFULL - size)) { - return (u64)-1; - } - - new_size = write_pos + size; - - if (new_size < old_size) { - new_size = old_size; - } - - if (new_size == 0ULL) { - return 0ULL; - } - - merged = clks_kmalloc((usize)new_size); - - if (merged == CLKS_NULL) { - return (u64)-1; - } - - clks_memset(merged, 0, (usize)new_size); - - if (old_size > 0ULL) { - clks_memcpy(merged, old_data, (usize)old_size); - } - - clks_memcpy((u8 *)merged + (usize)write_pos, buffer, (usize)size); - ok = clks_fs_write_all(entry->path, merged, new_size); - clks_kfree(merged); - - if (ok == CLKS_FALSE) { - return (u64)-1; - } - - entry->offset = write_pos + size; - return size; -} - -static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot, u64 pid, const char *path, - const char *argv_line, const char *env_line, - enum clks_exec_proc_state state) { - struct clks_exec_proc_record *proc; - - if (slot < 0 || path == CLKS_NULL) { - return CLKS_NULL; - } - - proc = &clks_exec_proc_table[(u32)slot]; - clks_memset(proc, 0, sizeof(*proc)); - - proc->used = CLKS_TRUE; - proc->state = state; - proc->pid = pid; - proc->ppid = clks_exec_current_pid(); - proc->started_tick = 0ULL; - proc->exited_tick = 0ULL; - proc->run_started_tick = 0ULL; - proc->runtime_ticks_accum = 0ULL; - proc->exit_status = (u64)-1; - proc->tty_index = clks_tty_active(); - proc->image_mem_bytes = 0ULL; - clks_exec_copy_path(proc->path, sizeof(proc->path), path); - clks_exec_copy_line(proc->argv_line, sizeof(proc->argv_line), argv_line); - clks_exec_copy_line(proc->env_line, sizeof(proc->env_line), env_line); - clks_exec_clear_items(proc->argv_items, CLKS_EXEC_MAX_ARGS); - clks_exec_clear_items(proc->env_items, CLKS_EXEC_MAX_ENVS); - proc->argc = 0U; - proc->envc = 0U; - proc->last_signal = 0ULL; - proc->last_fault_vector = 0ULL; - proc->last_fault_error = 0ULL; - proc->last_fault_rip = 0ULL; - clks_exec_fd_init_defaults(proc); - - if (proc->argc < CLKS_EXEC_MAX_ARGS) { - clks_exec_copy_path(proc->argv_items[proc->argc], CLKS_EXEC_ITEM_MAX, path); - proc->argc++; - } - - if (proc->argv_line[0] != '\0' && proc->argc < CLKS_EXEC_MAX_ARGS) { - proc->argc += clks_exec_parse_whitespace_items(proc->argv_line, &proc->argv_items[proc->argc], - (u32)(CLKS_EXEC_MAX_ARGS - proc->argc)); - } - - if (proc->env_line[0] != '\0') { - proc->envc = clks_exec_parse_env_items(proc->env_line, proc->env_items, CLKS_EXEC_MAX_ENVS); - } - - return proc; -} - -static void clks_exec_proc_mark_running(struct clks_exec_proc_record *proc, u64 now_tick) { - if (proc == CLKS_NULL) { - return; - } - - if (proc->started_tick == 0ULL) { - proc->started_tick = now_tick; - } - - proc->run_started_tick = now_tick; - proc->state = CLKS_EXEC_PROC_RUNNING; -} - -static void clks_exec_proc_pause_runtime(struct clks_exec_proc_record *proc, u64 now_tick) { - if (proc == CLKS_NULL) { - return; - } - - if (proc->run_started_tick != 0ULL && now_tick > proc->run_started_tick) { - proc->runtime_ticks_accum += (now_tick - proc->run_started_tick); - } - - proc->run_started_tick = 0ULL; -} - -static void clks_exec_proc_mark_exited(struct clks_exec_proc_record *proc, u64 now_tick, u64 status) { - if (proc == CLKS_NULL) { - return; - } - - clks_exec_proc_pause_runtime(proc, now_tick); - proc->state = CLKS_EXEC_PROC_EXITED; - proc->exit_status = status; - proc->exited_tick = now_tick; -} - -#if defined(CLKS_ARCH_X86_64) -static u64 clks_exec_read_rflags(void) { - u64 flags = 0ULL; - __asm__ volatile("pushfq; popq %0" : "=r"(flags) : : "memory"); - return flags; -} - -static clks_bool clks_exec_enable_interrupt_window(void) { - if ((clks_exec_read_rflags() & (1ULL << 9)) != 0ULL) { - return CLKS_FALSE; - } - - __asm__ volatile("sti" : : : "memory"); - return CLKS_TRUE; -} - -static void clks_exec_restore_interrupt_window(clks_bool need_disable) { - if (need_disable == CLKS_TRUE) { - __asm__ volatile("cli" : : : "memory"); - } -} -#endif - -static clks_bool clks_exec_invoke_entry(void *entry_ptr, u32 depth_index, u64 *out_ret) { - if (entry_ptr == CLKS_NULL || out_ret == CLKS_NULL) { - return CLKS_FALSE; - } - -#if defined(CLKS_ARCH_X86_64) - { - void *stack_base = clks_kmalloc((usize)CLKS_EXEC_RUN_STACK_BYTES); - void *stack_top; - u64 unwind_slot; - u64 call_ret = (u64)-1; - clks_bool restore_irq_disable = CLKS_FALSE; - - if (stack_base == CLKS_NULL) { - clks_log(CLKS_LOG_WARN, "EXEC", "RUN STACK ALLOC FAILED"); - return CLKS_FALSE; - } - - stack_top = (void *)((u8 *)stack_base + (usize)CLKS_EXEC_RUN_STACK_BYTES); - clks_exec_stack_begin_stack[depth_index] = (u64)stack_base; - clks_exec_stack_end_stack[depth_index] = (u64)stack_top; - unwind_slot = (((u64)stack_top) & ~0xFULL) - CLKS_EXEC_UNWIND_CTX_BYTES; - clks_exec_unwind_slot_stack[depth_index] = unwind_slot; - clks_exec_unwind_slot_valid_stack[depth_index] = CLKS_TRUE; - - if (clks_exec_pending_dispatch_active == CLKS_FALSE) { - restore_irq_disable = clks_exec_enable_interrupt_window(); - } - - call_ret = clks_exec_call_on_stack_x86_64(entry_ptr, stack_top); - - /* Close unwind window immediately after call returns to avoid IRQ race. */ - clks_exec_unwind_slot_valid_stack[depth_index] = CLKS_FALSE; - clks_exec_unwind_slot_stack[depth_index] = 0ULL; - clks_exec_stack_begin_stack[depth_index] = 0ULL; - clks_exec_stack_end_stack[depth_index] = 0ULL; - - clks_exec_restore_interrupt_window(restore_irq_disable); - *out_ret = call_ret; - clks_kfree(stack_base); - return CLKS_TRUE; - } -#else - (void)depth_index; - *out_ret = ((clks_exec_entry_fn)entry_ptr)(); - return CLKS_TRUE; -#endif -} - -static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) { - struct clks_exec_proc_record *proc; - const void *image; - u64 image_size = 0ULL; - struct clks_elf64_info info; - struct clks_elf64_loaded_image loaded; - clks_bool loaded_active = CLKS_FALSE; - clks_bool depth_pushed = CLKS_FALSE; - clks_bool depth_counted = CLKS_FALSE; - void *entry_ptr; - u64 run_ret = (u64)-1; - i32 depth_index; - - clks_memset(&loaded, 0, sizeof(loaded)); - - if (out_status != CLKS_NULL) { - *out_status = (u64)-1; - } - - if (slot < 0 || (u32)slot >= CLKS_EXEC_MAX_PROCS) { - return CLKS_FALSE; - } - - proc = &clks_exec_proc_table[(u32)slot]; - - if (proc->used == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (proc->path[0] != '/') { - clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1); - return CLKS_FALSE; - } - - if (clks_exec_pid_stack_depth >= CLKS_EXEC_MAX_DEPTH) { - clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS STACK DEPTH EXCEEDED"); - clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1); - return CLKS_FALSE; - } - - clks_exec_proc_mark_running(proc, clks_interrupts_timer_ticks()); - - depth_index = (i32)clks_exec_pid_stack_depth; - clks_exec_pid_stack[(u32)depth_index] = proc->pid; - clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_FALSE; - clks_exec_exit_status_stack[(u32)depth_index] = 0ULL; - clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; - clks_exec_image_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_image_end_stack[(u32)depth_index] = 0ULL; - clks_exec_image_vaddr_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_image_vaddr_end_stack[(u32)depth_index] = 0ULL; - clks_exec_stack_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_stack_end_stack[(u32)depth_index] = 0ULL; - clks_exec_pid_stack_depth++; - depth_pushed = CLKS_TRUE; - - image = clks_fs_read_all(proc->path, &image_size); - - if (image == CLKS_NULL || image_size == 0ULL) { - clks_log(CLKS_LOG_WARN, "EXEC", "EXEC FILE MISSING"); - clks_log(CLKS_LOG_WARN, "EXEC", proc->path); - goto fail; - } - - if (clks_elf64_inspect(image, image_size, &info) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF INVALID"); - clks_log(CLKS_LOG_WARN, "EXEC", proc->path); - goto fail; - } - - proc->image_mem_bytes = info.total_load_memsz; - - if (clks_elf64_load(image, image_size, &loaded) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF LOAD FAILED"); - clks_log(CLKS_LOG_WARN, "EXEC", proc->path); - goto fail; - } - - loaded_active = CLKS_TRUE; - - entry_ptr = clks_elf64_entry_pointer(&loaded, info.entry); - if (entry_ptr == CLKS_NULL) { - clks_log(CLKS_LOG_WARN, "EXEC", "ENTRY POINTER RESOLVE FAILED"); - clks_log(CLKS_LOG_WARN, "EXEC", proc->path); - goto fail; - } - - { - u64 image_begin = (u64)loaded.image_base; - u64 image_end = image_begin + loaded.image_size; - - if (loaded.image_base == CLKS_NULL || loaded.image_size == 0ULL || image_end <= image_begin) { - clks_log(CLKS_LOG_WARN, "EXEC", "EXEC IMAGE WINDOW INVALID"); - clks_log(CLKS_LOG_WARN, "EXEC", proc->path); - goto fail; - } - - clks_exec_image_begin_stack[(u32)depth_index] = image_begin; - clks_exec_image_end_stack[(u32)depth_index] = image_end; - clks_exec_image_vaddr_begin_stack[(u32)depth_index] = loaded.image_vaddr_base; - clks_exec_image_vaddr_end_stack[(u32)depth_index] = loaded.image_vaddr_base + loaded.image_size; - } - - clks_exec_log_info_serial("EXEC RUN START"); - clks_exec_log_info_serial(proc->path); - clks_exec_log_hex_serial("ENTRY", info.entry); - clks_exec_log_hex_serial("PHNUM", (u64)info.phnum); - clks_exec_log_hex_serial("IMAGE_BASE", (u64)loaded.image_base); - clks_exec_log_hex_serial("IMAGE_SIZE", loaded.image_size); - clks_exec_log_hex_serial("VADDR_BASE", loaded.image_vaddr_base); - - clks_exec_running_depth++; - depth_counted = CLKS_TRUE; - - if (clks_exec_invoke_entry(entry_ptr, (u32)depth_index, &run_ret) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "EXEC", "EXEC RUN INVOKE FAILED"); - clks_log(CLKS_LOG_WARN, "EXEC", proc->path); - goto fail; - } - - if (depth_counted == CLKS_TRUE && clks_exec_running_depth > 0U) { - clks_exec_running_depth--; - depth_counted = CLKS_FALSE; - } - - if (clks_exec_exit_requested_stack[(u32)depth_index] == CLKS_TRUE) { - run_ret = clks_exec_exit_status_stack[(u32)depth_index]; - } - - clks_exec_log_info_serial("RUN RETURNED"); - clks_exec_log_info_serial(proc->path); - clks_exec_log_hex_serial("RET", run_ret); - if (clks_exec_status_is_user_terminated(run_ret) == CLKS_TRUE) { - clks_exec_log_info_serial("TERMINATED BY USER"); - clks_exec_log_info_serial(proc->path); - clks_exec_log_hex_serial("PID", proc->pid); - clks_exec_log_hex_serial("SIGNAL", clks_exec_status_signal(run_ret)); - } - - clks_exec_success++; - if (clks_exec_stop_requested_stack[(u32)depth_index] == CLKS_TRUE) { - u64 now_tick = clks_interrupts_timer_ticks(); - clks_exec_proc_pause_runtime(proc, now_tick); - proc->state = CLKS_EXEC_PROC_STOPPED; - proc->exit_status = run_ret; - proc->exited_tick = 0ULL; - clks_exec_log_info_serial("RUN STOPPED"); - clks_exec_log_info_serial(proc->path); - } else { - clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), run_ret); - } - - clks_exec_dynlib_release_owner(proc->pid); - - if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { - clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; - clks_exec_image_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_image_end_stack[(u32)depth_index] = 0ULL; - clks_exec_image_vaddr_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_image_vaddr_end_stack[(u32)depth_index] = 0ULL; - clks_exec_stack_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_stack_end_stack[(u32)depth_index] = 0ULL; - clks_exec_pid_stack_depth--; - depth_pushed = CLKS_FALSE; - } - - if (loaded_active == CLKS_TRUE) { - clks_elf64_unload(&loaded); - } - - if (out_status != CLKS_NULL) { - *out_status = run_ret; - } - - return CLKS_TRUE; - -fail: - if (depth_counted == CLKS_TRUE && clks_exec_running_depth > 0U) { - clks_exec_running_depth--; - } - - clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1); - clks_exec_dynlib_release_owner(proc->pid); - - if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { - clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; - clks_exec_image_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_image_end_stack[(u32)depth_index] = 0ULL; - clks_exec_image_vaddr_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_image_vaddr_end_stack[(u32)depth_index] = 0ULL; - clks_exec_stack_begin_stack[(u32)depth_index] = 0ULL; - clks_exec_stack_end_stack[(u32)depth_index] = 0ULL; - clks_exec_pid_stack_depth--; - } - - if (loaded_active == CLKS_TRUE) { - clks_elf64_unload(&loaded); - } - - if (out_status != CLKS_NULL) { - *out_status = (u64)-1; - } - - return CLKS_FALSE; -} - -static clks_bool clks_exec_dispatch_pending_once(void) { - u32 i; - - if (clks_exec_pending_dispatch_active == CLKS_TRUE) { - return CLKS_FALSE; - } - - /* One pending process per tick keeps latency sane and avoids scheduler chaos. */ - for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { - if (clks_exec_proc_table[i].used == CLKS_TRUE && clks_exec_proc_table[i].state == CLKS_EXEC_PROC_PENDING) { - u64 ignored_status = (u64)-1; - - clks_exec_pending_dispatch_active = CLKS_TRUE; - (void)clks_exec_run_proc_slot((i32)i, &ignored_status); - clks_exec_pending_dispatch_active = CLKS_FALSE; - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static clks_bool clks_exec_run_path_internal(const char *path, const char *argv_line, const char *env_line, - u64 stdin_fd, u64 stdout_fd, u64 stderr_fd, u64 *out_status, - u64 *out_pid) { - i32 slot; - u64 pid; - const struct clks_exec_proc_record *parent_proc = clks_exec_current_proc(); - struct clks_exec_proc_record *proc; - u64 status = (u64)-1; - - if (out_status != CLKS_NULL) { - *out_status = (u64)-1; - } - - if (out_pid != CLKS_NULL) { - *out_pid = (u64)-1; - } - - /* Count every request, even bad ones, so metrics don't lie to our face. */ - clks_exec_requests++; - - if (path == CLKS_NULL || path[0] != '/') { - clks_log(CLKS_LOG_WARN, "EXEC", "INVALID EXEC PATH"); - return CLKS_FALSE; - } - - slot = clks_exec_proc_alloc_slot(); - - if (slot < 0) { - clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS TABLE FULL"); - return CLKS_FALSE; - } - - pid = clks_exec_alloc_pid(); - proc = clks_exec_prepare_proc_record(slot, pid, path, argv_line, env_line, CLKS_EXEC_PROC_RUNNING); - - if (proc == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_exec_fd_apply_stdio_overrides(proc, parent_proc, stdin_fd, stdout_fd, stderr_fd) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "EXEC", "INVALID STDIO FD OVERRIDE"); - clks_memset(proc, 0, sizeof(*proc)); - return CLKS_FALSE; - } - - if (out_pid != CLKS_NULL) { - *out_pid = pid; - } - - if (clks_exec_run_proc_slot(slot, &status) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (out_status != CLKS_NULL) { - *out_status = status; - } - - return CLKS_TRUE; -} - -void clks_exec_init(void) { - clks_exec_requests = 0ULL; - clks_exec_success = 0ULL; - clks_exec_running_depth = 0U; - clks_exec_pending_dispatch_active = CLKS_FALSE; - clks_exec_random_state = 0xA5A55A5A12345678ULL; - clks_exec_next_pid = 1ULL; - clks_exec_pid_stack_depth = 0U; - clks_memset(clks_exec_pid_stack, 0, sizeof(clks_exec_pid_stack)); - clks_memset(clks_exec_exit_requested_stack, 0, sizeof(clks_exec_exit_requested_stack)); - clks_memset(clks_exec_exit_status_stack, 0, sizeof(clks_exec_exit_status_stack)); - clks_memset(clks_exec_stop_requested_stack, 0, sizeof(clks_exec_stop_requested_stack)); - clks_memset(clks_exec_unwind_slot_stack, 0, sizeof(clks_exec_unwind_slot_stack)); - clks_memset(clks_exec_unwind_slot_valid_stack, 0, sizeof(clks_exec_unwind_slot_valid_stack)); - clks_memset(clks_exec_image_begin_stack, 0, sizeof(clks_exec_image_begin_stack)); - clks_memset(clks_exec_image_end_stack, 0, sizeof(clks_exec_image_end_stack)); - clks_memset(clks_exec_image_vaddr_begin_stack, 0, sizeof(clks_exec_image_vaddr_begin_stack)); - clks_memset(clks_exec_image_vaddr_end_stack, 0, sizeof(clks_exec_image_vaddr_end_stack)); - clks_memset(clks_exec_stack_begin_stack, 0, sizeof(clks_exec_stack_begin_stack)); - clks_memset(clks_exec_stack_end_stack, 0, sizeof(clks_exec_stack_end_stack)); - clks_memset(clks_exec_proc_table, 0, sizeof(clks_exec_proc_table)); - clks_memset(clks_exec_dynlib_table, 0, sizeof(clks_exec_dynlib_table)); - clks_exec_next_dynlib_handle = 1ULL; - clks_exec_log_info_serial("PATH EXEC FRAMEWORK ONLINE"); -} - -clks_bool clks_exec_run_path(const char *path, u64 *out_status) { - return clks_exec_run_path_internal(path, CLKS_NULL, CLKS_NULL, CLKS_EXEC_FD_INHERIT, CLKS_EXEC_FD_INHERIT, - CLKS_EXEC_FD_INHERIT, out_status, CLKS_NULL); -} - -clks_bool clks_exec_run_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_status) { - return clks_exec_run_path_internal(path, argv_line, env_line, CLKS_EXEC_FD_INHERIT, CLKS_EXEC_FD_INHERIT, - CLKS_EXEC_FD_INHERIT, out_status, CLKS_NULL); -} - -clks_bool clks_exec_run_pathv_io(const char *path, const char *argv_line, const char *env_line, u64 stdin_fd, - u64 stdout_fd, u64 stderr_fd, u64 *out_status) { - return clks_exec_run_path_internal(path, argv_line, env_line, stdin_fd, stdout_fd, stderr_fd, out_status, - CLKS_NULL); -} - -clks_bool clks_exec_spawn_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_pid) { - i32 slot; - u64 pid; - struct clks_exec_proc_record *proc; - - if (out_pid != CLKS_NULL) { - *out_pid = (u64)-1; - } - - clks_exec_requests++; - - if (path == CLKS_NULL || path[0] != '/') { - clks_log(CLKS_LOG_WARN, "EXEC", "INVALID SPAWN PATH"); - return CLKS_FALSE; - } - - slot = clks_exec_proc_alloc_slot(); - - if (slot < 0) { - clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS TABLE FULL"); - return CLKS_FALSE; - } - - pid = clks_exec_alloc_pid(); - proc = clks_exec_prepare_proc_record(slot, pid, path, argv_line, env_line, CLKS_EXEC_PROC_PENDING); - - if (proc == CLKS_NULL) { - return CLKS_FALSE; - } - - if (out_pid != CLKS_NULL) { - *out_pid = pid; - } - - clks_exec_log_info_serial("SPAWN QUEUED"); - clks_exec_log_info_serial(path); - clks_exec_log_hex_serial("PID", pid); - - return CLKS_TRUE; -} - -clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) { - return clks_exec_spawn_pathv(path, CLKS_NULL, CLKS_NULL, out_pid); -} - -u64 clks_exec_wait_pid(u64 pid, u64 *out_status) { - i32 slot; - struct clks_exec_proc_record *proc; - - slot = clks_exec_proc_find_slot_by_pid(pid); - - if (slot < 0) { - return (u64)-1; - } - - proc = &clks_exec_proc_table[(u32)slot]; - - if (proc->used == CLKS_FALSE) { - return (u64)-1; - } - - if (proc->state == CLKS_EXEC_PROC_PENDING && clks_exec_pending_dispatch_active == CLKS_FALSE) { - u64 ignored_status = (u64)-1; - - clks_exec_pending_dispatch_active = CLKS_TRUE; - (void)clks_exec_run_proc_slot(slot, &ignored_status); - clks_exec_pending_dispatch_active = CLKS_FALSE; - } - - if (proc->state == CLKS_EXEC_PROC_PENDING || proc->state == CLKS_EXEC_PROC_RUNNING || - proc->state == CLKS_EXEC_PROC_STOPPED) { - return 0ULL; - } - - if (proc->state != CLKS_EXEC_PROC_EXITED) { - return (u64)-1; - } - - if (out_status != CLKS_NULL) { - *out_status = proc->exit_status; - } - - return 1ULL; -} - -clks_bool clks_exec_request_exit(u64 status) { - i32 depth_index = clks_exec_current_depth_index(); - - if (depth_index < 0) { - return CLKS_FALSE; - } - - clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; - clks_exec_exit_status_stack[(u32)depth_index] = status; - return CLKS_TRUE; -} - -u64 clks_exec_fd_open(const char *path, u64 flags, u64 mode) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - struct clks_fs_node_info info; - i32 fd_slot; - u8 empty_payload = 0U; - - (void)mode; - - if (proc == CLKS_NULL || path == CLKS_NULL || path[0] != '/') { - return (u64)-1; - } - - if (clks_strlen(path) >= CLKS_EXEC_PATH_MAX) { - return (u64)-1; - } - - if (clks_exec_fd_access_mode_valid(flags) == CLKS_FALSE) { - return (u64)-1; - } - - if (((flags & CLKS_EXEC_O_TRUNC) != 0ULL || (flags & CLKS_EXEC_O_APPEND) != 0ULL) && - clks_exec_fd_can_write(flags) == CLKS_FALSE) { - return (u64)-1; - } - - fd_slot = clks_exec_fd_find_free(proc); - - if (fd_slot < 0) { - return (u64)-1; - } - - if (clks_exec_path_is_dev_tty(path) == CLKS_TRUE) { - struct clks_exec_fd_entry *entry = &proc->fds[(u32)fd_slot]; - - clks_memset(entry, 0, sizeof(*entry)); - entry->used = CLKS_TRUE; - entry->kind = CLKS_EXEC_FD_KIND_TTY; - entry->flags = flags; - entry->offset = 0ULL; - entry->tty_index = proc->tty_index; - entry->path[0] = '\0'; - return (u64)fd_slot; - } - - if (clks_exec_path_is_dev_null(path) == CLKS_TRUE || clks_exec_path_is_dev_zero(path) == CLKS_TRUE || - clks_exec_path_is_dev_random(path) == CLKS_TRUE) { - struct clks_exec_fd_entry *entry = &proc->fds[(u32)fd_slot]; - - clks_memset(entry, 0, sizeof(*entry)); - entry->used = CLKS_TRUE; - entry->flags = flags; - entry->offset = 0ULL; - entry->tty_index = proc->tty_index; - entry->path[0] = '\0'; - - if (clks_exec_path_is_dev_null(path) == CLKS_TRUE) { - entry->kind = CLKS_EXEC_FD_KIND_DEV_NULL; - } else if (clks_exec_path_is_dev_zero(path) == CLKS_TRUE) { - entry->kind = CLKS_EXEC_FD_KIND_DEV_ZERO; - } else { - entry->kind = CLKS_EXEC_FD_KIND_DEV_RANDOM; - } - - return (u64)fd_slot; - } - - if (clks_fs_stat(path, &info) == CLKS_FALSE) { - if ((flags & CLKS_EXEC_O_CREAT) == 0ULL || clks_exec_fd_can_write(flags) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_fs_write_all(path, &empty_payload, 0ULL) == CLKS_FALSE || clks_fs_stat(path, &info) == CLKS_FALSE) { - return (u64)-1; - } - } - - if (info.type != CLKS_FS_NODE_FILE) { - return (u64)-1; - } - - if ((flags & CLKS_EXEC_O_TRUNC) != 0ULL) { - if (clks_fs_write_all(path, &empty_payload, 0ULL) == CLKS_FALSE || clks_fs_stat(path, &info) == CLKS_FALSE) { - return (u64)-1; - } - } - - { - struct clks_exec_fd_entry *entry = &proc->fds[(u32)fd_slot]; - - clks_memset(entry, 0, sizeof(*entry)); - entry->used = CLKS_TRUE; - entry->kind = CLKS_EXEC_FD_KIND_FILE; - entry->flags = flags; - entry->offset = ((flags & CLKS_EXEC_O_APPEND) != 0ULL) ? info.size : 0ULL; - entry->tty_index = proc->tty_index; - clks_exec_copy_path(entry->path, sizeof(entry->path), path); - } - - return (u64)fd_slot; -} - -u64 clks_exec_fd_read(u64 fd, void *out_buffer, u64 size) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - struct clks_exec_fd_entry *entry; - - if (proc == CLKS_NULL) { - return (u64)-1; - } - - if (size == 0ULL) { - return 0ULL; - } - - if (out_buffer == CLKS_NULL) { - return (u64)-1; - } - - entry = clks_exec_fd_lookup(proc, fd); - - if (entry == CLKS_NULL || clks_exec_fd_can_read(entry->flags) == CLKS_FALSE) { - return (u64)-1; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_TTY) { - u64 count = 0ULL; - char *dst = (char *)out_buffer; - - while (count < size) { - char ch; - - if (clks_keyboard_pop_char_for_tty(entry->tty_index, &ch) == CLKS_FALSE) { - break; - } - - dst[count] = ch; - count++; - } - - return count; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_DEV_NULL) { - return 0ULL; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_DEV_ZERO) { - clks_memset(out_buffer, 0, (usize)size); - entry->offset += size; - return size; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_DEV_RANDOM) { - u8 *dst = (u8 *)out_buffer; - u64 i; - - for (i = 0ULL; i < size; i++) { - dst[(usize)i] = clks_exec_random_next_byte(); - } - - entry->offset += size; - return size; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_FILE) { - return clks_exec_fd_file_read(entry, out_buffer, size); - } - - return (u64)-1; -} - -u64 clks_exec_fd_write(u64 fd, const void *buffer, u64 size) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - struct clks_exec_fd_entry *entry; - - if (proc == CLKS_NULL) { - return (u64)-1; - } - - if (size == 0ULL) { - return 0ULL; - } - - if (buffer == CLKS_NULL) { - return (u64)-1; - } - - entry = clks_exec_fd_lookup(proc, fd); - - if (entry == CLKS_NULL || clks_exec_fd_can_write(entry->flags) == CLKS_FALSE) { - return (u64)-1; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_TTY) { - clks_tty_write_n((const char *)buffer, (usize)size); - return size; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_DEV_NULL || entry->kind == CLKS_EXEC_FD_KIND_DEV_ZERO || - entry->kind == CLKS_EXEC_FD_KIND_DEV_RANDOM) { - entry->offset += size; - return size; - } - - if (entry->kind == CLKS_EXEC_FD_KIND_FILE) { - return clks_exec_fd_file_write(entry, buffer, size); - } - - return (u64)-1; -} - -u64 clks_exec_fd_close(u64 fd) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - struct clks_exec_fd_entry *entry; - - if (proc == CLKS_NULL) { - return (u64)-1; - } - - entry = clks_exec_fd_lookup(proc, fd); - - if (entry == CLKS_NULL) { - return (u64)-1; - } - - clks_memset(entry, 0, sizeof(*entry)); - return 0ULL; -} - -u64 clks_exec_fd_dup(u64 fd) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - struct clks_exec_fd_entry *entry; - i32 fd_slot; - - if (proc == CLKS_NULL) { - return (u64)-1; - } - - entry = clks_exec_fd_lookup(proc, fd); - - if (entry == CLKS_NULL) { - return (u64)-1; - } - - fd_slot = clks_exec_fd_find_free(proc); - - if (fd_slot < 0) { - return (u64)-1; - } - - proc->fds[(u32)fd_slot] = *entry; - return (u64)fd_slot; -} - -u64 clks_exec_dl_open(const char *path) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - const void *image; - u64 image_size = 0ULL; - i32 existing_slot; - i32 slot; - u64 owner_pid; - struct clks_exec_dynlib_slot *dyn; - - if (proc == CLKS_NULL || path == CLKS_NULL || path[0] != '/') { - return (u64)-1; - } - - if (clks_strlen(path) >= CLKS_EXEC_PATH_MAX) { - return (u64)-1; - } - - owner_pid = proc->pid; - existing_slot = clks_exec_dynlib_find_by_owner_path(owner_pid, path); - - if (existing_slot >= 0) { - dyn = &clks_exec_dynlib_table[(u32)existing_slot]; - dyn->ref_count++; - return dyn->handle; - } - - slot = clks_exec_dynlib_alloc_slot(); - if (slot < 0) { - return (u64)-1; - } - - image = clks_fs_read_all(path, &image_size); - if (image == CLKS_NULL || image_size == 0ULL) { - return (u64)-1; - } - - dyn = &clks_exec_dynlib_table[(u32)slot]; - clks_memset(dyn, 0, sizeof(*dyn)); - - if (clks_elf64_load(image, image_size, &dyn->loaded) == CLKS_FALSE) { - clks_memset(dyn, 0, sizeof(*dyn)); - return (u64)-1; - } - - dyn->used = CLKS_TRUE; - dyn->handle = clks_exec_dynlib_alloc_handle(); - dyn->owner_pid = owner_pid; - dyn->ref_count = 1ULL; - dyn->file_image = image; - dyn->file_size = image_size; - clks_exec_copy_path(dyn->path, sizeof(dyn->path), path); - - clks_exec_log_info_serial("DLOPEN OK"); - clks_exec_log_info_serial(path); - clks_exec_log_hex_serial("DL_HANDLE", dyn->handle); - return dyn->handle; -} - -u64 clks_exec_dl_close(u64 handle) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - i32 slot; - struct clks_exec_dynlib_slot *dyn; - - if (proc == CLKS_NULL || handle == 0ULL) { - return (u64)-1; - } - - slot = clks_exec_dynlib_find_by_handle(handle); - if (slot < 0) { - return (u64)-1; - } - - dyn = &clks_exec_dynlib_table[(u32)slot]; - if (dyn->owner_pid != proc->pid) { - return (u64)-1; - } - - if (dyn->ref_count > 1ULL) { - dyn->ref_count--; - return 0ULL; - } - - clks_exec_dynlib_slot_reset(dyn); - return 0ULL; -} - -u64 clks_exec_dl_sym(u64 handle, const char *symbol) { - struct clks_exec_proc_record *proc = clks_exec_current_proc(); - i32 slot; - struct clks_exec_dynlib_slot *dyn; - u64 addr = 0ULL; - - if (proc == CLKS_NULL || handle == 0ULL || symbol == CLKS_NULL || symbol[0] == '\0') { - return 0ULL; - } - - slot = clks_exec_dynlib_find_by_handle(handle); - if (slot < 0) { - return 0ULL; - } - - dyn = &clks_exec_dynlib_table[(u32)slot]; - if (dyn->owner_pid != proc->pid) { - return 0ULL; - } - - if (clks_exec_dynlib_resolve_symbol(dyn, symbol, &addr) == CLKS_FALSE) { - return 0ULL; - } - - return addr; -} - -u64 clks_exec_current_pid(void) { - i32 depth_index = clks_exec_current_depth_index(); - - if (depth_index < 0) { - return 0ULL; - } - - return clks_exec_pid_stack[(u32)depth_index]; -} - -u32 clks_exec_current_tty(void) { - i32 depth_index = clks_exec_current_depth_index(); - u32 tty_count = clks_tty_count(); - i32 slot; - const struct clks_exec_proc_record *proc; - - if (tty_count == 0U) { - return 0U; - } - - if (depth_index < 0) { - u32 active = clks_tty_active(); - return (active < tty_count) ? active : 0U; - } - - slot = clks_exec_proc_find_slot_by_pid(clks_exec_pid_stack[(u32)depth_index]); - - if (slot < 0) { - return 0U; - } - - proc = &clks_exec_proc_table[(u32)slot]; - - if (proc->used == CLKS_FALSE || proc->tty_index >= tty_count) { - return 0U; - } - - return proc->tty_index; -} - -static struct clks_exec_proc_record *clks_exec_current_proc(void) { - i32 depth_index = clks_exec_current_depth_index(); - i32 slot; - - if (depth_index < 0) { - return CLKS_NULL; - } - - slot = clks_exec_proc_find_slot_by_pid(clks_exec_pid_stack[(u32)depth_index]); - - if (slot < 0) { - return CLKS_NULL; - } - - if (clks_exec_proc_table[(u32)slot].used == CLKS_FALSE) { - return CLKS_NULL; - } - - return &clks_exec_proc_table[(u32)slot]; -} - -u64 clks_exec_current_argc(void) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - - if (proc == CLKS_NULL) { - return 0ULL; - } - - return (u64)proc->argc; -} - -clks_bool clks_exec_copy_current_argv(u64 index, char *out_value, usize out_size) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - - if (proc == CLKS_NULL || out_value == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - if (index >= (u64)proc->argc || index >= CLKS_EXEC_MAX_ARGS) { - return CLKS_FALSE; - } - - clks_exec_copy_line(out_value, out_size, proc->argv_items[(u32)index]); - return CLKS_TRUE; -} - -u64 clks_exec_current_envc(void) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - - if (proc == CLKS_NULL) { - return 0ULL; - } - - return (u64)proc->envc; -} - -clks_bool clks_exec_copy_current_env(u64 index, char *out_value, usize out_size) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - - if (proc == CLKS_NULL || out_value == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - if (index >= (u64)proc->envc || index >= CLKS_EXEC_MAX_ENVS) { - return CLKS_FALSE; - } - - clks_exec_copy_line(out_value, out_size, proc->env_items[(u32)index]); - return CLKS_TRUE; -} - -u64 clks_exec_current_signal(void) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - return (proc != CLKS_NULL) ? proc->last_signal : 0ULL; -} - -u64 clks_exec_current_fault_vector(void) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - return (proc != CLKS_NULL) ? proc->last_fault_vector : 0ULL; -} - -u64 clks_exec_current_fault_error(void) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - return (proc != CLKS_NULL) ? proc->last_fault_error : 0ULL; -} - -u64 clks_exec_current_fault_rip(void) { - const struct clks_exec_proc_record *proc = clks_exec_current_proc(); - return (proc != CLKS_NULL) ? proc->last_fault_rip : 0ULL; -} - -static u64 clks_exec_proc_runtime_ticks(const struct clks_exec_proc_record *proc, u64 now_tick) { - u64 runtime; - - if (proc == CLKS_NULL || proc->started_tick == 0ULL) { - return 0ULL; - } - - runtime = proc->runtime_ticks_accum; - - if (proc->state == CLKS_EXEC_PROC_RUNNING && proc->run_started_tick != 0ULL && now_tick > proc->run_started_tick) { - runtime += (now_tick - proc->run_started_tick); - } - - return runtime; -} - -static u64 clks_exec_proc_memory_bytes(const struct clks_exec_proc_record *proc) { - u64 mem = 0ULL; - - if (proc == CLKS_NULL) { - return 0ULL; - } - - mem += proc->image_mem_bytes; - - if (proc->state == CLKS_EXEC_PROC_RUNNING) { - mem += CLKS_EXEC_RUN_STACK_BYTES; - } - - return mem; -} - -u64 clks_exec_proc_count(void) { - u64 count = 0ULL; - u32 i; - - for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { - if (clks_exec_proc_table[i].used == CLKS_TRUE) { - count++; - } - } - - return count; -} - -clks_bool clks_exec_proc_pid_at(u64 index, u64 *out_pid) { - u64 pos = 0ULL; - u32 i; - - if (out_pid != CLKS_NULL) { - *out_pid = 0ULL; - } - - if (out_pid == CLKS_NULL) { - return CLKS_FALSE; - } - - for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { - if (clks_exec_proc_table[i].used != CLKS_TRUE) { - continue; - } - - if (pos == index) { - *out_pid = clks_exec_proc_table[i].pid; - return CLKS_TRUE; - } - - pos++; - } - - return CLKS_FALSE; -} - -clks_bool clks_exec_proc_snapshot(u64 pid, struct clks_exec_proc_snapshot *out_snapshot) { - i32 slot; - const struct clks_exec_proc_record *proc; - u64 now_tick; - - if (out_snapshot == CLKS_NULL) { - return CLKS_FALSE; - } - - slot = clks_exec_proc_find_slot_by_pid(pid); - - if (slot < 0) { - return CLKS_FALSE; - } - - proc = &clks_exec_proc_table[(u32)slot]; - - if (proc->used != CLKS_TRUE) { - return CLKS_FALSE; - } - - now_tick = clks_interrupts_timer_ticks(); - clks_memset(out_snapshot, 0, sizeof(*out_snapshot)); - - out_snapshot->pid = proc->pid; - out_snapshot->ppid = proc->ppid; - out_snapshot->state = (u64)proc->state; - out_snapshot->started_tick = proc->started_tick; - out_snapshot->exited_tick = proc->exited_tick; - out_snapshot->exit_status = proc->exit_status; - out_snapshot->runtime_ticks = clks_exec_proc_runtime_ticks(proc, now_tick); - out_snapshot->mem_bytes = clks_exec_proc_memory_bytes(proc); - out_snapshot->tty_index = (u64)proc->tty_index; - out_snapshot->last_signal = proc->last_signal; - out_snapshot->last_fault_vector = proc->last_fault_vector; - out_snapshot->last_fault_error = proc->last_fault_error; - out_snapshot->last_fault_rip = proc->last_fault_rip; - clks_exec_copy_path(out_snapshot->path, sizeof(out_snapshot->path), proc->path); - - return CLKS_TRUE; -} - -u64 clks_exec_proc_kill(u64 pid, u64 signal) { - i32 slot; - struct clks_exec_proc_record *proc; - u64 effective_signal; - u64 status; - u64 now_tick; - - if (pid == 0ULL) { - return (u64)-1; - } - - slot = clks_exec_proc_find_slot_by_pid(pid); - - if (slot < 0) { - return (u64)-1; - } - - proc = &clks_exec_proc_table[(u32)slot]; - - if (proc->used != CLKS_TRUE) { - return (u64)-1; - } - - effective_signal = (signal == 0ULL) ? CLKS_EXEC_DEFAULT_KILL_SIGNAL : (signal & 0xFFULL); - status = clks_exec_encode_signal_status(effective_signal, 0ULL, 0ULL); - now_tick = clks_interrupts_timer_ticks(); - - if (proc->state == CLKS_EXEC_PROC_EXITED) { - return 1ULL; - } - - proc->last_signal = effective_signal; - proc->last_fault_vector = 0ULL; - proc->last_fault_error = 0ULL; - proc->last_fault_rip = 0ULL; - - if (effective_signal == CLKS_EXEC_SIGNAL_CONT) { - if (proc->state == CLKS_EXEC_PROC_STOPPED) { - proc->state = CLKS_EXEC_PROC_PENDING; - } - return 1ULL; - } - - if (effective_signal == CLKS_EXEC_SIGNAL_STOP) { - if (proc->state == CLKS_EXEC_PROC_PENDING) { - proc->state = CLKS_EXEC_PROC_STOPPED; - return 1ULL; - } - - if (proc->state == CLKS_EXEC_PROC_STOPPED) { - return 1ULL; - } - } - - if (proc->state == CLKS_EXEC_PROC_PENDING || proc->state == CLKS_EXEC_PROC_STOPPED) { - clks_exec_proc_mark_exited(proc, now_tick, status); - if (effective_signal == CLKS_EXEC_SIGNAL_TERM || effective_signal == CLKS_EXEC_SIGNAL_KILL || - effective_signal == CLKS_EXEC_SIGNAL_STOP) { - clks_exec_log_info_serial("TERMINATED BY USER"); - clks_exec_log_info_serial(proc->path); - clks_exec_log_hex_serial("PID", proc->pid); - clks_exec_log_hex_serial("SIGNAL", effective_signal); - } - return 1ULL; - } - - if (proc->state == CLKS_EXEC_PROC_RUNNING) { - i32 depth_index = clks_exec_current_depth_index(); - - if (depth_index < 0 || clks_exec_current_pid() != pid) { - return 0ULL; - } - - if (effective_signal == CLKS_EXEC_SIGNAL_STOP) { - clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; - clks_exec_exit_status_stack[(u32)depth_index] = status; - clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_TRUE; - return 1ULL; - } - - clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; - clks_exec_exit_status_stack[(u32)depth_index] = status; - return 1ULL; - } - - return 0ULL; -} - -u64 clks_exec_force_stop_tty_running_process(u32 tty_index, u64 *out_pid) { - u32 tty_count = clks_tty_count(); - u64 current_pid; - i32 slot; - u32 i; - - if (out_pid != CLKS_NULL) { - *out_pid = 0ULL; - } - - if (tty_count == 0U) { - tty_count = 1U; - } - - if (tty_index >= tty_count) { - tty_index = 0U; - } - - current_pid = clks_exec_current_pid(); - - if (current_pid != 0ULL) { - slot = clks_exec_proc_find_slot_by_pid(current_pid); - - if (slot >= 0) { - const struct clks_exec_proc_record *proc = &clks_exec_proc_table[(u32)slot]; - - if (proc->used == CLKS_TRUE && proc->state == CLKS_EXEC_PROC_RUNNING && proc->tty_index == tty_index && - clks_exec_path_is_user_program(proc->path) == CLKS_TRUE) { - u64 ret = clks_exec_proc_kill(current_pid, CLKS_EXEC_SIGNAL_STOP); - - if (ret == 1ULL && out_pid != CLKS_NULL) { - *out_pid = current_pid; - } - - return ret; - } - } - } - - for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { - u64 ret; - - if (clks_exec_proc_table[i].used != CLKS_TRUE || clks_exec_proc_table[i].state != CLKS_EXEC_PROC_RUNNING || - clks_exec_proc_table[i].tty_index != tty_index || - clks_exec_path_is_user_program(clks_exec_proc_table[i].path) == CLKS_FALSE) { - continue; - } - - if (out_pid != CLKS_NULL) { - *out_pid = clks_exec_proc_table[i].pid; - } - - ret = clks_exec_proc_kill(clks_exec_proc_table[i].pid, CLKS_EXEC_SIGNAL_STOP); - - if (ret == 1ULL) { - return 1ULL; - } - } - - return 0ULL; -} - -clks_bool clks_exec_try_unwind_signaled_process(u64 interrupted_rip, u64 *io_rip, u64 *io_rdi, u64 *io_rsi) { - i32 depth_index; - - if (io_rip == CLKS_NULL || io_rdi == CLKS_NULL || io_rsi == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_exec_is_running() == CLKS_FALSE || clks_exec_current_path_is_user() == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_exec_rip_is_current_user_context(interrupted_rip) == CLKS_FALSE) { - return CLKS_FALSE; - } - - depth_index = clks_exec_current_depth_index(); - - if (depth_index < 0) { - return CLKS_FALSE; - } - - if (clks_exec_stop_requested_stack[(u32)depth_index] == CLKS_FALSE) { - return CLKS_FALSE; - } - -#if defined(CLKS_ARCH_X86_64) - if (clks_exec_unwind_slot_valid_stack[(u32)depth_index] == CLKS_FALSE) { - return CLKS_FALSE; - } - - *io_rip = (u64)clks_exec_abort_to_caller_x86_64; - *io_rdi = clks_exec_unwind_slot_stack[(u32)depth_index]; - *io_rsi = clks_exec_exit_status_stack[(u32)depth_index]; - return CLKS_TRUE; -#else - (void)depth_index; - return CLKS_FALSE; -#endif -} - -clks_bool clks_exec_handle_exception(u64 vector, u64 error_code, u64 rip, u64 *io_rip, u64 *io_rdi, u64 *io_rsi) { - i32 depth_index; - struct clks_exec_proc_record *proc; - u64 signal; - u64 status; - - if (clks_exec_is_running() == CLKS_FALSE || clks_exec_current_path_is_user() == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_exec_rip_is_current_user_context(rip) == CLKS_FALSE) { - return CLKS_FALSE; - } - - depth_index = clks_exec_current_depth_index(); - proc = clks_exec_current_proc(); - - if (depth_index < 0 || proc == CLKS_NULL) { - return CLKS_FALSE; - } - -#if defined(CLKS_ARCH_X86_64) - if (vector == 14ULL && (error_code & 0x10ULL) != 0ULL && io_rip != CLKS_NULL) { - u64 translated_rip = 0ULL; - - if (clks_exec_translate_legacy_user_rip(rip, &translated_rip) == CLKS_TRUE) { - *io_rip = translated_rip; - clks_exec_log_info_serial("USER RIP LEGACY REBASE"); - clks_exec_log_hex_serial("RIP_OLD", rip); - clks_exec_log_hex_serial("RIP_NEW", translated_rip); - return CLKS_TRUE; - } - } -#endif - - signal = clks_exec_signal_from_vector(vector); - status = clks_exec_encode_signal_status(signal, vector, error_code); - - proc->last_signal = signal; - proc->last_fault_vector = vector; - proc->last_fault_error = error_code; - proc->last_fault_rip = rip; - - clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; - clks_exec_exit_status_stack[(u32)depth_index] = status; - - clks_exec_log_info_serial("USER EXCEPTION CAPTURED"); - clks_exec_log_info_serial(proc->path); - clks_exec_log_hex_serial("PID", proc->pid); - clks_exec_log_hex_serial("SIGNAL", signal); - clks_exec_log_hex_serial("VECTOR", vector); - clks_exec_log_hex_serial("ERROR", error_code); - clks_exec_log_hex_serial("RIP", rip); - { - u64 rip_vaddr = 0ULL; - if (clks_exec_translate_loaded_user_rip_to_vaddr(rip, &rip_vaddr) == CLKS_TRUE) { - clks_exec_log_hex_serial("RIP_VADDR", rip_vaddr); - } - } -#if defined(CLKS_ARCH_X86_64) - if (vector == 14ULL) { - clks_exec_log_hex_serial("CR2", clks_exec_read_cr2()); - } -#endif - -#if defined(CLKS_ARCH_X86_64) - if (io_rip == CLKS_NULL || io_rdi == CLKS_NULL || io_rsi == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_exec_unwind_slot_valid_stack[(u32)depth_index] == CLKS_FALSE) { - return CLKS_FALSE; - } - - *io_rip = (u64)clks_exec_abort_to_caller_x86_64; - *io_rdi = clks_exec_unwind_slot_stack[(u32)depth_index]; - *io_rsi = status; - return CLKS_TRUE; -#else - (void)io_rip; - (void)io_rdi; - (void)io_rsi; - return CLKS_FALSE; -#endif -} - -u64 clks_exec_sleep_ticks(u64 ticks) { - u64 start = clks_interrupts_timer_ticks(); - - if (ticks == 0ULL) { - return 0ULL; - } - - while ((clks_interrupts_timer_ticks() - start) < ticks) { -#if defined(CLKS_ARCH_X86_64) - __asm__ volatile("sti; hlt; cli" : : : "memory"); -#elif defined(CLKS_ARCH_AARCH64) - clks_cpu_pause(); -#endif - (void)clks_exec_dispatch_pending_once(); - } - - return clks_interrupts_timer_ticks() - start; -} - -u64 clks_exec_yield(void) { -#if defined(CLKS_ARCH_X86_64) - __asm__ volatile("sti; hlt; cli" : : : "memory"); -#elif defined(CLKS_ARCH_AARCH64) - clks_cpu_pause(); -#endif - - (void)clks_exec_dispatch_pending_once(); - return clks_interrupts_timer_ticks(); -} - -void clks_exec_tick(u64 tick) { - (void)tick; - /* Background pump: boring, repetitive, absolutely necessary. */ - (void)clks_exec_dispatch_pending_once(); -} - -u64 clks_exec_request_count(void) { - return clks_exec_requests; -} - -u64 clks_exec_success_count(void) { - return clks_exec_success; -} - -clks_bool clks_exec_is_running(void) { - return (clks_exec_running_depth > 0U) ? CLKS_TRUE : CLKS_FALSE; -} - -clks_bool clks_exec_current_path_is_user(void) { - i32 depth_index; - i32 slot; - const struct clks_exec_proc_record *proc; - - depth_index = clks_exec_current_depth_index(); - - if (depth_index < 0) { - return CLKS_FALSE; - } - - slot = clks_exec_proc_find_slot_by_pid(clks_exec_pid_stack[(u32)depth_index]); - - if (slot < 0) { - return CLKS_FALSE; - } - - proc = &clks_exec_proc_table[(u32)slot]; - return clks_exec_path_is_user_program(proc->path); -} - -clks_bool clks_exec_current_user_ptr_readable(u64 addr, u64 size) { - i32 depth_index; - u64 image_begin; - u64 image_end; - u64 stack_begin; - u64 stack_end; - - if (clks_exec_is_running() == CLKS_FALSE || clks_exec_current_path_is_user() == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (size == 0ULL || clks_exec_pid_stack_depth == 0U) { - return CLKS_FALSE; - } - - depth_index = (i32)(clks_exec_pid_stack_depth - 1U); - image_begin = clks_exec_image_begin_stack[(u32)depth_index]; - image_end = clks_exec_image_end_stack[(u32)depth_index]; - stack_begin = clks_exec_stack_begin_stack[(u32)depth_index]; - stack_end = clks_exec_stack_end_stack[(u32)depth_index]; - - if (clks_exec_addr_range_in_window(addr, size, image_begin, image_end) == CLKS_TRUE) { - return CLKS_TRUE; - } - - if (clks_exec_addr_range_in_window(addr, size, stack_begin, stack_end) == CLKS_TRUE) { - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -clks_bool clks_exec_current_user_ptr_writable(u64 addr, u64 size) { - return clks_exec_current_user_ptr_readable(addr, size); -} diff --git a/clks/kernel/runtime/kelf.c b/clks/kernel/runtime/kelf.c deleted file mode 100644 index 3b4b43c..0000000 --- a/clks/kernel/runtime/kelf.c +++ /dev/null @@ -1,250 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define CLKS_KELF_MAX_APPS 8U -#define CLKS_ELF64_PT_LOAD 1U - -struct clks_elf64_ehdr { - u8 e_ident[16]; - u16 e_type; - u16 e_machine; - u32 e_version; - u64 e_entry; - u64 e_phoff; - u64 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shnum; - u16 e_shstrndx; -}; - -struct clks_elf64_phdr { - u32 p_type; - u32 p_flags; - u64 p_offset; - u64 p_vaddr; - u64 p_paddr; - u64 p_filesz; - u64 p_memsz; - u64 p_align; -}; - -struct clks_kelf_app { - clks_bool loaded; - char path[64]; - void *runtime_image; - u64 runtime_size; - clks_kelf_entry_fn entry; - u64 run_count; - u64 last_run_tick; - u64 last_ret; -}; - -static struct clks_kelf_app clks_kelf_apps[CLKS_KELF_MAX_APPS]; -static u64 clks_kelf_app_count = 0ULL; -static u64 clks_kelf_total_runs_count = 0ULL; -static u64 clks_kelf_rr_index = 0ULL; -static u64 clks_kelf_last_dispatch_tick = 0ULL; - -static void clks_kelf_copy_name(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || dst_size == 0U) { - return; - } - - while (i + 1U < dst_size && src[i] != '\0') { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static clks_bool clks_kelf_load_runtime_image(const void *image, u64 size, void **out_runtime, u64 *out_runtime_size, - clks_kelf_entry_fn *out_entry) { - const struct clks_elf64_ehdr *eh; - u64 min_vaddr = 0xffffffffffffffffULL; - u64 max_vaddr = 0ULL; - u16 i; - u8 *runtime; - - if (out_runtime == CLKS_NULL || out_runtime_size == CLKS_NULL || out_entry == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_elf64_validate(image, size) == CLKS_FALSE) { - return CLKS_FALSE; - } - - eh = (const struct clks_elf64_ehdr *)image; - - for (i = 0; i < eh->e_phnum; i++) { - const struct clks_elf64_phdr *ph = - (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); - u64 seg_end; - - if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) { - continue; - } - - if (ph->p_filesz > ph->p_memsz) { - return CLKS_FALSE; - } - - if (ph->p_offset > size || ph->p_filesz > (size - ph->p_offset)) { - return CLKS_FALSE; - } - - seg_end = ph->p_vaddr + ph->p_memsz; - - if (seg_end < ph->p_vaddr) { - return CLKS_FALSE; - } - - if (ph->p_vaddr < min_vaddr) { - min_vaddr = ph->p_vaddr; - } - - if (seg_end > max_vaddr) { - max_vaddr = seg_end; - } - } - - if (max_vaddr <= min_vaddr) { - return CLKS_FALSE; - } - - *out_runtime_size = max_vaddr - min_vaddr; - runtime = (u8 *)clks_kmalloc((usize)(*out_runtime_size)); - - if (runtime == CLKS_NULL) { - return CLKS_FALSE; - } - - clks_memset(runtime, 0, (usize)(*out_runtime_size)); - - for (i = 0; i < eh->e_phnum; i++) { - const struct clks_elf64_phdr *ph = - (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); - - if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) { - continue; - } - - clks_memcpy(runtime + (usize)(ph->p_vaddr - min_vaddr), (const u8 *)image + ph->p_offset, (usize)ph->p_filesz); - } - - if (eh->e_entry < min_vaddr || eh->e_entry >= max_vaddr) { - clks_kfree(runtime); - return CLKS_FALSE; - } - - *out_entry = (clks_kelf_entry_fn)(void *)(runtime + (usize)(eh->e_entry - min_vaddr)); - *out_runtime = runtime; - return CLKS_TRUE; -} - -static void clks_kelf_probe_path(const char *path) { - const void *image; - u64 size = 0ULL; - void *runtime = CLKS_NULL; - u64 runtime_size = 0ULL; - clks_kelf_entry_fn entry = CLKS_NULL; - struct clks_kelf_app *slot; - - if (clks_kelf_app_count >= CLKS_KELF_MAX_APPS) { - return; - } - - image = clks_fs_read_all(path, &size); - - if (image == CLKS_NULL || size == 0ULL) { - clks_log(CLKS_LOG_WARN, "KELF", "APP FILE NOT FOUND"); - clks_log(CLKS_LOG_WARN, "KELF", path); - return; - } - - if (clks_kelf_load_runtime_image(image, size, &runtime, &runtime_size, &entry) == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "KELF", "APP LOAD FAILED"); - clks_log(CLKS_LOG_ERROR, "KELF", path); - return; - } - - slot = &clks_kelf_apps[clks_kelf_app_count]; - clks_memset(slot, 0, sizeof(*slot)); - - slot->loaded = CLKS_TRUE; - clks_kelf_copy_name(slot->path, sizeof(slot->path), path); - slot->runtime_image = runtime; - slot->runtime_size = runtime_size; - slot->entry = entry; - - clks_kelf_app_count++; - - clks_log(CLKS_LOG_INFO, "KELF", "APP READY"); - clks_log(CLKS_LOG_INFO, "KELF", path); - clks_log_hex(CLKS_LOG_INFO, "KELF", "RUNTIME_SIZE", runtime_size); -} - -void clks_kelf_init(void) { - clks_memset(clks_kelf_apps, 0, sizeof(clks_kelf_apps)); - clks_kelf_app_count = 0ULL; - clks_kelf_total_runs_count = 0ULL; - clks_kelf_rr_index = 0ULL; - clks_kelf_last_dispatch_tick = 0ULL; - - clks_kelf_probe_path("/system/elfrunner.elf"); - clks_kelf_probe_path("/system/memc.elf"); - - clks_log(CLKS_LOG_INFO, "KELF", "EXECUTOR ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "KELF", "APP_COUNT", clks_kelf_app_count); -} - -void clks_kelf_tick(u64 tick) { - struct clks_kelf_app *app; - - if (clks_kelf_app_count == 0ULL) { - return; - } - - if (tick - clks_kelf_last_dispatch_tick < 200ULL) { - return; - } - - clks_kelf_last_dispatch_tick = tick; - app = &clks_kelf_apps[clks_kelf_rr_index % clks_kelf_app_count]; - clks_kelf_rr_index++; - - if (app->loaded == CLKS_FALSE || app->entry == CLKS_NULL) { - return; - } - - app->run_count++; - app->last_run_tick = tick; - /* NX-safe stage mode: keep dispatch accounting without jumping into runtime image. */ - app->last_ret = (tick ^ (app->run_count << 8)) + clks_kelf_rr_index; - clks_kelf_total_runs_count++; - - if ((app->run_count & 0x7ULL) == 1ULL) { - clks_log(CLKS_LOG_DEBUG, "KELF", "APP DISPATCHED"); - clks_log(CLKS_LOG_DEBUG, "KELF", app->path); - clks_log_hex(CLKS_LOG_DEBUG, "KELF", "RET", app->last_ret); - } -} - -u64 clks_kelf_count(void) { - return clks_kelf_app_count; -} - -u64 clks_kelf_total_runs(void) { - return clks_kelf_total_runs_count; -} diff --git a/clks/kernel/runtime/syscall.c b/clks/kernel/runtime/syscall.c deleted file mode 100644 index 0c13046..0000000 --- a/clks/kernel/runtime/syscall.c +++ /dev/null @@ -1,2672 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Yes, this file is a syscall kitchen sink and nobody is pretending otherwise. */ - -#define CLKS_SYSCALL_LOG_MAX_LEN 191U -#define CLKS_SYSCALL_PATH_MAX 192U -#define CLKS_SYSCALL_NAME_MAX 96U -#define CLKS_SYSCALL_TTY_MAX_LEN 2048U -#define CLKS_SYSCALL_FS_IO_CHUNK_LEN 65536U -#define CLKS_SYSCALL_JOURNAL_MAX_LEN 256U -#define CLKS_SYSCALL_ARG_LINE_MAX 256U -#define CLKS_SYSCALL_ENV_LINE_MAX 512U -#define CLKS_SYSCALL_ITEM_MAX 128U -#define CLKS_SYSCALL_PROCFS_TEXT_MAX 2048U -#define CLKS_SYSCALL_USER_TRACE_BUDGET 128ULL -#define CLKS_SYSCALL_KDBG_TEXT_MAX 2048U -#define CLKS_SYSCALL_KDBG_BT_MAX_FRAMES 16U -#define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL) -#define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym" -#define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL -#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_DISK_WRITE_SECTOR -#define CLKS_SYSCALL_DISK_SECTOR_BYTES 512U -#define CLKS_SYSCALL_STATS_RING_SIZE 256U -#define CLKS_SYSCALL_USC_MAX_ALLOWED_APPS 64U - -#ifndef CLKS_CFG_PROCFS -#define CLKS_CFG_PROCFS 1 -#endif - -#ifndef CLKS_CFG_USC -#define CLKS_CFG_USC 1 -#endif - -#ifndef CLKS_CFG_USC_SC_FS_MKDIR -#define CLKS_CFG_USC_SC_FS_MKDIR 1 -#endif - -#ifndef CLKS_CFG_USC_SC_FS_WRITE -#define CLKS_CFG_USC_SC_FS_WRITE 1 -#endif - -#ifndef CLKS_CFG_USC_SC_FS_APPEND -#define CLKS_CFG_USC_SC_FS_APPEND 1 -#endif - -#ifndef CLKS_CFG_USC_SC_FS_REMOVE -#define CLKS_CFG_USC_SC_FS_REMOVE 1 -#endif - -#ifndef CLKS_CFG_USC_SC_EXEC_PATH -#define CLKS_CFG_USC_SC_EXEC_PATH 1 -#endif - -#ifndef CLKS_CFG_USC_SC_EXEC_PATHV -#define CLKS_CFG_USC_SC_EXEC_PATHV 1 -#endif - -#ifndef CLKS_CFG_USC_SC_EXEC_PATHV_IO -#define CLKS_CFG_USC_SC_EXEC_PATHV_IO 1 -#endif - -#ifndef CLKS_CFG_USC_SC_SPAWN_PATH -#define CLKS_CFG_USC_SC_SPAWN_PATH 1 -#endif - -#ifndef CLKS_CFG_USC_SC_SPAWN_PATHV -#define CLKS_CFG_USC_SC_SPAWN_PATHV 1 -#endif - -#ifndef CLKS_CFG_USC_SC_PROC_KILL -#define CLKS_CFG_USC_SC_PROC_KILL 1 -#endif - -#ifndef CLKS_CFG_USC_SC_SHUTDOWN -#define CLKS_CFG_USC_SC_SHUTDOWN 1 -#endif - -#ifndef CLKS_CFG_USC_SC_RESTART -#define CLKS_CFG_USC_SC_RESTART 1 -#endif - -struct clks_syscall_frame { - u64 rax; - u64 rbx; - u64 rcx; - u64 rdx; - u64 rsi; - u64 rdi; - u64 rbp; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; - u64 vector; - u64 error_code; - u64 rip; - u64 cs; - u64 rflags; - u64 rsp; - u64 ss; -}; - -struct clks_syscall_kdbg_bt_req { - u64 rbp; - u64 rip; - u64 out_ptr; - u64 out_size; -}; - -struct clks_syscall_exec_io_req { - u64 env_line_ptr; - u64 stdin_fd; - u64 stdout_fd; - u64 stderr_fd; -}; - -struct clks_syscall_fb_info_user { - u64 width; - u64 height; - u64 pitch; - u64 bpp; -}; - -struct clks_syscall_fb_blit_req { - u64 pixels_ptr; - u64 src_width; - u64 src_height; - u64 src_pitch_bytes; - u64 dst_x; - u64 dst_y; - u64 scale; -}; - -static clks_bool clks_syscall_ready = CLKS_FALSE; -static clks_bool clks_syscall_user_trace_active = CLKS_FALSE; -static u64 clks_syscall_user_trace_budget = 0ULL; -static struct clks_syscall_frame clks_syscall_last_frame; -static clks_bool clks_syscall_last_frame_valid = CLKS_FALSE; -static clks_bool clks_syscall_symbols_checked = CLKS_FALSE; -static const char *clks_syscall_symbols_data = CLKS_NULL; -static u64 clks_syscall_symbols_size = 0ULL; -static u64 clks_syscall_stats_total = 0ULL; -static u64 clks_syscall_stats_id_count[CLKS_SYSCALL_STATS_MAX_ID + 1ULL]; -static u64 clks_syscall_stats_recent_id_count[CLKS_SYSCALL_STATS_MAX_ID + 1ULL]; -static u16 clks_syscall_stats_recent_ring[CLKS_SYSCALL_STATS_RING_SIZE]; -static u32 clks_syscall_stats_recent_head = 0U; -static u32 clks_syscall_stats_recent_size = 0U; -#if CLKS_CFG_USC != 0 -static clks_bool clks_syscall_usc_allowed_used[CLKS_SYSCALL_USC_MAX_ALLOWED_APPS]; -static char clks_syscall_usc_allowed_path[CLKS_SYSCALL_USC_MAX_ALLOWED_APPS][CLKS_EXEC_PROC_PATH_MAX]; -#endif - -#if defined(CLKS_ARCH_X86_64) -static inline void clks_syscall_outb(u16 port, u8 value) { - __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); -} - -static inline void clks_syscall_outw(u16 port, u16 value) { - __asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port)); -} -#endif - -static clks_bool clks_syscall_in_user_exec_context(void) { - /* If this says "no", we're basically in trust-me-bro kernel mode. */ - return (clks_exec_is_running() == CLKS_TRUE && clks_exec_current_path_is_user() == CLKS_TRUE) ? CLKS_TRUE - : CLKS_FALSE; -} - -static clks_bool clks_syscall_user_ptr_readable(u64 addr, u64 size) { - if (addr == 0ULL || size == 0ULL) { - return CLKS_FALSE; - } - - if (clks_syscall_in_user_exec_context() == CLKS_FALSE) { - return CLKS_TRUE; - } - - return clks_exec_current_user_ptr_readable(addr, size); -} - -static clks_bool clks_syscall_user_ptr_writable(u64 addr, u64 size) { - if (addr == 0ULL || size == 0ULL) { - return CLKS_FALSE; - } - - if (clks_syscall_in_user_exec_context() == CLKS_FALSE) { - return CLKS_TRUE; - } - - return clks_exec_current_user_ptr_writable(addr, size); -} - -static clks_bool clks_syscall_copy_user_string(u64 src_addr, char *dst, usize dst_size) { - usize i = 0U; - - if (src_addr == 0ULL || dst == CLKS_NULL || dst_size == 0U) { - return CLKS_FALSE; - } - - /* Byte-by-byte copy is slow as hell, but crashing on bad pointers is worse. */ - while (i + 1U < dst_size) { - u64 char_addr = src_addr + (u64)i; - char ch; - - if (char_addr < src_addr) { - return CLKS_FALSE; - } - - if (clks_syscall_user_ptr_readable(char_addr, 1ULL) == CLKS_FALSE) { - return CLKS_FALSE; - } - - ch = *(const char *)(usize)char_addr; - dst[i] = ch; - - if (ch == '\0') { - return CLKS_TRUE; - } - - i++; - } - - dst[dst_size - 1U] = '\0'; - return CLKS_TRUE; -} - -static clks_bool clks_syscall_copy_user_optional_string(u64 src_addr, char *dst, usize dst_size) { - if (dst == CLKS_NULL || dst_size == 0U) { - return CLKS_FALSE; - } - - if (src_addr == 0ULL) { - dst[0] = '\0'; - return CLKS_TRUE; - } - - return clks_syscall_copy_user_string(src_addr, dst, dst_size); -} - -static u64 clks_syscall_copy_text_to_user(u64 dst_addr, u64 dst_size, const char *src, usize src_len) { - usize copy_len; - - if (dst_addr == 0ULL || dst_size == 0ULL || src == CLKS_NULL) { - return 0ULL; - } - - copy_len = src_len; - - /* Leave room for NUL, because "almost a string" is just pain. */ - if (copy_len + 1U > (usize)dst_size) { - copy_len = (usize)dst_size - 1U; - } - - if (clks_syscall_user_ptr_writable(dst_addr, (u64)copy_len + 1ULL) == CLKS_FALSE) { - return 0ULL; - } - - clks_memcpy((void *)dst_addr, src, copy_len); - ((char *)dst_addr)[copy_len] = '\0'; - return (u64)copy_len; -} - -static u64 clks_syscall_log_write(u64 arg0, u64 arg1) { - const char *src = (const char *)arg0; - u64 len = arg1; - char buf[CLKS_SYSCALL_LOG_MAX_LEN + 1U]; - u64 i; - - if (src == CLKS_NULL || len == 0ULL) { - return 0ULL; - } - - if (len > CLKS_SYSCALL_LOG_MAX_LEN) { - len = CLKS_SYSCALL_LOG_MAX_LEN; - } - - if (clks_syscall_user_ptr_readable((u64)(usize)src, len) == CLKS_FALSE) { - return 0ULL; - } - - for (i = 0ULL; i < len; i++) { - buf[i] = src[i]; - } - - buf[len] = '\0'; - clks_log(CLKS_LOG_INFO, "SYSCALL", buf); - - return len; -} - -static u64 clks_syscall_tty_write(u64 arg0, u64 arg1) { - const char *src = (const char *)arg0; - u64 len = arg1; - char buf[CLKS_SYSCALL_TTY_MAX_LEN + 1U]; - u64 i; - - if (src == CLKS_NULL || len == 0ULL) { - return 0ULL; - } - - if (len > CLKS_SYSCALL_TTY_MAX_LEN) { - len = CLKS_SYSCALL_TTY_MAX_LEN; - } - - if (clks_syscall_user_ptr_readable((u64)(usize)src, len) == CLKS_FALSE) { - return 0ULL; - } - - for (i = 0ULL; i < len; i++) { - buf[i] = src[i]; - } - - buf[len] = '\0'; - clks_tty_write(buf); - return len; -} - -static u64 clks_syscall_tty_write_char(u64 arg0) { - clks_tty_write_char((char)(arg0 & 0xFFULL)); - return 1ULL; -} - -static u64 clks_syscall_kbd_get_char(void) { - char ch; - u32 tty_index = clks_exec_current_tty(); - - if (clks_keyboard_pop_char_for_tty(tty_index, &ch) == CLKS_FALSE) { - return (u64)-1; - } - - return (u64)(u8)ch; -} - -static u64 clks_syscall_fb_info(u64 arg0) { - struct clks_syscall_fb_info_user *out_info = (struct clks_syscall_fb_info_user *)arg0; - struct clks_framebuffer_info fb_info; - - if (arg0 == 0ULL || clks_fb_ready() == CLKS_FALSE) { - return 0ULL; - } - - if (clks_syscall_user_ptr_writable(arg0, (u64)sizeof(*out_info)) == CLKS_FALSE) { - return 0ULL; - } - - fb_info = clks_fb_info(); - out_info->width = (u64)fb_info.width; - out_info->height = (u64)fb_info.height; - out_info->pitch = (u64)fb_info.pitch; - out_info->bpp = (u64)fb_info.bpp; - return 1ULL; -} - -static u64 clks_syscall_fb_clear(u64 arg0) { - if (clks_fb_ready() == CLKS_FALSE) { - return 0ULL; - } - - clks_fb_clear((u32)(arg0 & 0xFFFFFFFFULL)); - return 1ULL; -} - -static u64 clks_syscall_fb_blit(u64 arg0) { - struct clks_syscall_fb_blit_req req; - const u8 *src_base; - struct clks_framebuffer_info fb_info; - u64 src_width; - u64 src_height; - u64 src_pitch_bytes; - u64 dst_x; - u64 dst_y; - u64 scale; - u64 y; - u64 x; - - if (arg0 == 0ULL || clks_fb_ready() == CLKS_FALSE) { - return 0ULL; - } - - if (clks_syscall_user_ptr_readable(arg0, (u64)sizeof(req)) == CLKS_FALSE) { - return 0ULL; - } - - clks_memcpy(&req, (const void *)(usize)arg0, sizeof(req)); - - if (req.pixels_ptr == 0ULL) { - return 0ULL; - } - - src_width = req.src_width; - src_height = req.src_height; - src_pitch_bytes = req.src_pitch_bytes; - dst_x = req.dst_x; - dst_y = req.dst_y; - scale = req.scale; - - if (src_width == 0ULL || src_height == 0ULL || scale == 0ULL) { - return 0ULL; - } - - if (src_width > 4096ULL || src_height > 4096ULL || scale > 8ULL) { - return 0ULL; - } - - if (src_pitch_bytes == 0ULL) { - src_pitch_bytes = src_width * 4ULL; - } - - if (src_pitch_bytes < (src_width * 4ULL)) { - return 0ULL; - } - - if (src_pitch_bytes != 0ULL && src_height > (((u64)-1) / src_pitch_bytes)) { - return 0ULL; - } - - if (clks_syscall_user_ptr_readable(req.pixels_ptr, src_pitch_bytes * src_height) == CLKS_FALSE) { - return 0ULL; - } - - src_base = (const u8 *)(usize)req.pixels_ptr; - fb_info = clks_fb_info(); - - if (dst_x >= (u64)fb_info.width || dst_y >= (u64)fb_info.height) { - return 0ULL; - } - - for (y = 0ULL; y < src_height; y++) { - const u32 *src_row = (const u32 *)(const void *)(src_base + (usize)(y * src_pitch_bytes)); - u64 draw_y = dst_y + (y * scale); - - if (draw_y >= (u64)fb_info.height) { - break; - } - - for (x = 0ULL; x < src_width; x++) { - u32 color = src_row[x]; - u64 draw_x = dst_x + (x * scale); - - if (draw_x >= (u64)fb_info.width) { - break; - } - - if (scale == 1ULL) { - clks_fb_draw_pixel((u32)draw_x, (u32)draw_y, color); - } else { - clks_fb_fill_rect((u32)draw_x, (u32)draw_y, (u32)scale, (u32)scale, color); - } - } - } - - return 1ULL; -} - -static u64 clks_syscall_kernel_version(u64 arg0, u64 arg1) { - /* Version query: tiny syscall, huge bike-shed potential. */ - usize len = clks_strlen(CLKS_VERSION_STRING); - return clks_syscall_copy_text_to_user(arg0, arg1, CLKS_VERSION_STRING, len); -} - -static u64 clks_syscall_disk_present(void) { - return (clks_disk_present() == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_disk_size_bytes(void) { - return clks_disk_size_bytes(); -} - -static u64 clks_syscall_disk_sector_count(void) { - return clks_disk_sector_count(); -} - -static u64 clks_syscall_disk_formatted(void) { - return (clks_disk_is_formatted_fat32() == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_disk_format_fat32(u64 arg0) { - char label[16]; - - if (clks_syscall_copy_user_optional_string(arg0, label, sizeof(label)) == CLKS_FALSE) { - return 0ULL; - } - - return (clks_disk_format_fat32((label[0] != '\0') ? label : CLKS_NULL) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_disk_mount(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return 0ULL; - } - - return (clks_disk_mount(path) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_disk_mounted(void) { - return (clks_disk_is_mounted() == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_disk_mount_path(u64 arg0, u64 arg1) { - const char *mount_path = clks_disk_mount_path(); - - if (mount_path == CLKS_NULL || mount_path[0] == '\0') { - return 0ULL; - } - - return clks_syscall_copy_text_to_user(arg0, arg1, mount_path, clks_strlen(mount_path)); -} - -static u64 clks_syscall_disk_read_sector(u64 arg0, u64 arg1) { - u8 sector[CLKS_SYSCALL_DISK_SECTOR_BYTES]; - - if (arg1 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_writable(arg1, (u64)CLKS_SYSCALL_DISK_SECTOR_BYTES) == CLKS_FALSE) { - return 0ULL; - } - - if (clks_disk_read_sector(arg0, (void *)sector) == CLKS_FALSE) { - return 0ULL; - } - - clks_memcpy((void *)arg1, sector, (usize)CLKS_SYSCALL_DISK_SECTOR_BYTES); - return 1ULL; -} - -static u64 clks_syscall_disk_write_sector(u64 arg0, u64 arg1) { - u8 sector[CLKS_SYSCALL_DISK_SECTOR_BYTES]; - - if (arg1 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_readable(arg1, (u64)CLKS_SYSCALL_DISK_SECTOR_BYTES) == CLKS_FALSE) { - return 0ULL; - } - - clks_memcpy(sector, (const void *)arg1, (usize)CLKS_SYSCALL_DISK_SECTOR_BYTES); - return (clks_disk_write_sector(arg0, (const void *)sector) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_fd_open(u64 arg0, u64 arg1, u64 arg2) { - char path[CLKS_SYSCALL_PATH_MAX]; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - return clks_exec_fd_open(path, arg1, arg2); -} - -static u64 clks_syscall_fd_read(u64 arg0, u64 arg1, u64 arg2) { - if (arg2 > 0ULL && arg1 == 0ULL) { - return (u64)-1; - } - - if (arg2 > 0ULL && clks_syscall_user_ptr_writable(arg1, arg2) == CLKS_FALSE) { - return (u64)-1; - } - - return clks_exec_fd_read(arg0, (void *)arg1, arg2); -} - -static u64 clks_syscall_fd_write(u64 arg0, u64 arg1, u64 arg2) { - if (arg2 > 0ULL && arg1 == 0ULL) { - return (u64)-1; - } - - if (arg2 > 0ULL && clks_syscall_user_ptr_readable(arg1, arg2) == CLKS_FALSE) { - return (u64)-1; - } - - return clks_exec_fd_write(arg0, (const void *)arg1, arg2); -} - -static u64 clks_syscall_fd_close(u64 arg0) { - return clks_exec_fd_close(arg0); -} - -static u64 clks_syscall_fd_dup(u64 arg0) { - return clks_exec_fd_dup(arg0); -} - -static u64 clks_syscall_dl_open(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - return clks_exec_dl_open(path); -} - -static u64 clks_syscall_dl_close(u64 arg0) { - return clks_exec_dl_close(arg0); -} - -static u64 clks_syscall_dl_sym(u64 arg0, u64 arg1) { - char symbol[CLKS_SYSCALL_NAME_MAX]; - - if (clks_syscall_copy_user_string(arg1, symbol, sizeof(symbol)) == CLKS_FALSE) { - return 0ULL; - } - - return clks_exec_dl_sym(arg0, symbol); -} - -static clks_bool clks_syscall_procfs_is_root(const char *path) { - return (path != CLKS_NULL && clks_strcmp(path, "/proc") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_syscall_fs_is_root(const char *path) { - return (path != CLKS_NULL && clks_strcmp(path, "/") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_syscall_fs_has_real_proc_dir(void) { - struct clks_fs_node_info info; - - if (clks_fs_stat("/proc", &info) == CLKS_FALSE) { - return CLKS_FALSE; - } - - return (info.type == CLKS_FS_NODE_DIR) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_syscall_procfs_is_self(const char *path) { - return (path != CLKS_NULL && clks_strcmp(path, "/proc/self") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_syscall_procfs_is_list(const char *path) { - return (path != CLKS_NULL && clks_strcmp(path, "/proc/list") == 0) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_syscall_parse_u64_dec(const char *text, u64 *out_value) { - u64 value = 0ULL; - usize i = 0U; - - if (text == CLKS_NULL || out_value == CLKS_NULL || text[0] == '\0') { - return CLKS_FALSE; - } - - while (text[i] != '\0') { - u64 digit; - - if (text[i] < '0' || text[i] > '9') { - return CLKS_FALSE; - } - - digit = (u64)(text[i] - '0'); - - if (value > ((0xFFFFFFFFFFFFFFFFULL - digit) / 10ULL)) { - return CLKS_FALSE; - } - - value = (value * 10ULL) + digit; - i++; - } - - *out_value = value; - return CLKS_TRUE; -} - -static clks_bool clks_syscall_procfs_parse_pid(const char *path, u64 *out_pid) { - const char *part; - usize i = 0U; - char pid_text[32]; - u64 pid; - - if (path == CLKS_NULL || out_pid == CLKS_NULL) { - return CLKS_FALSE; - } - - if (path[0] != '/' || path[1] != 'p' || path[2] != 'r' || path[3] != 'o' || path[4] != 'c' || path[5] != '/') { - return CLKS_FALSE; - } - - part = &path[6]; - - if (part[0] == '\0' || clks_strcmp(part, "self") == 0 || clks_strcmp(part, "list") == 0) { - return CLKS_FALSE; - } - - while (part[i] != '\0') { - if (i + 1U >= sizeof(pid_text)) { - return CLKS_FALSE; - } - - if (part[i] < '0' || part[i] > '9') { - return CLKS_FALSE; - } - - pid_text[i] = part[i]; - i++; - } - - pid_text[i] = '\0'; - - if (clks_syscall_parse_u64_dec(pid_text, &pid) == CLKS_FALSE || pid == 0ULL) { - return CLKS_FALSE; - } - - *out_pid = pid; - return CLKS_TRUE; -} - -static const char *clks_syscall_proc_state_name(u64 state) { - if (state == CLKS_EXEC_PROC_STATE_PENDING) { - return "PENDING"; - } - - if (state == CLKS_EXEC_PROC_STATE_RUNNING) { - return "RUNNING"; - } - - if (state == CLKS_EXEC_PROC_STATE_STOPPED) { - return "STOPPED"; - } - - if (state == CLKS_EXEC_PROC_STATE_EXITED) { - return "EXITED"; - } - - return "UNUSED"; -} - -static usize clks_syscall_procfs_append_char(char *out, usize out_size, usize pos, char ch) { - if (out == CLKS_NULL || out_size == 0U) { - return pos; - } - - if (pos + 1U < out_size) { - out[pos] = ch; - out[pos + 1U] = '\0'; - return pos + 1U; - } - - out[out_size - 1U] = '\0'; - return pos; -} - -static usize clks_syscall_procfs_append_text(char *out, usize out_size, usize pos, const char *text) { - usize i = 0U; - - if (text == CLKS_NULL) { - return pos; - } - - while (text[i] != '\0') { - pos = clks_syscall_procfs_append_char(out, out_size, pos, text[i]); - i++; - } - - return pos; -} - -static usize clks_syscall_procfs_append_u64_dec(char *out, usize out_size, usize pos, u64 value) { - char temp[32]; - usize len = 0U; - usize i; - - if (value == 0ULL) { - return clks_syscall_procfs_append_char(out, out_size, pos, '0'); - } - - while (value != 0ULL && len + 1U < sizeof(temp)) { - temp[len++] = (char)('0' + (value % 10ULL)); - value /= 10ULL; - } - - for (i = 0U; i < len; i++) { - pos = clks_syscall_procfs_append_char(out, out_size, pos, temp[len - 1U - i]); - } - - return pos; -} - -static usize clks_syscall_procfs_append_u64_hex(char *out, usize out_size, usize pos, u64 value) { - i32 nibble; - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "0X"); - - for (nibble = 15; nibble >= 0; nibble--) { - u64 current = (value >> (u64)(nibble * 4)) & 0x0FULL; - char ch = (current < 10ULL) ? (char)('0' + current) : (char)('A' + (current - 10ULL)); - pos = clks_syscall_procfs_append_char(out, out_size, pos, ch); - } - - return pos; -} - -static usize clks_syscall_procfs_append_n(char *out, usize out_size, usize pos, const char *text, usize text_len) { - usize i = 0U; - - if (text == CLKS_NULL) { - return pos; - } - - while (i < text_len) { - pos = clks_syscall_procfs_append_char(out, out_size, pos, text[i]); - i++; - } - - return pos; -} - -static clks_bool clks_syscall_is_hex(char ch) { - if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -static u8 clks_syscall_hex_value(char ch) { - if (ch >= '0' && ch <= '9') { - return (u8)(ch - '0'); - } - - if (ch >= 'a' && ch <= 'f') { - return (u8)(10 + (ch - 'a')); - } - - return (u8)(10 + (ch - 'A')); -} - -static clks_bool clks_syscall_parse_symbol_line(const char *line, usize len, u64 *out_addr, const char **out_name, - usize *out_name_len, const char **out_source, usize *out_source_len) { - usize i = 0U; - u64 addr = 0ULL; - u32 digits = 0U; - usize name_start; - usize name_end; - usize source_start; - usize source_end; - - if (line == CLKS_NULL || out_addr == CLKS_NULL || out_name == CLKS_NULL || out_name_len == CLKS_NULL || - out_source == CLKS_NULL || out_source_len == CLKS_NULL) { - return CLKS_FALSE; - } - - if (len == 0U) { - return CLKS_FALSE; - } - - if (len >= 2U && line[0] == '0' && (line[1] == 'X' || line[1] == 'x')) { - i = 2U; - } - - while (i < len && clks_syscall_is_hex(line[i]) == CLKS_TRUE) { - addr = (addr << 4) | (u64)clks_syscall_hex_value(line[i]); - digits++; - i++; - } - - if (digits == 0U) { - return CLKS_FALSE; - } - - while (i < len && (line[i] == ' ' || line[i] == '\t')) { - i++; - } - - if (i >= len) { - return CLKS_FALSE; - } - - name_start = i; - - while (i < len && line[i] != ' ' && line[i] != '\t' && line[i] != '\r') { - i++; - } - - name_end = i; - - if (name_end <= name_start) { - return CLKS_FALSE; - } - - while (i < len && (line[i] == ' ' || line[i] == '\t')) { - i++; - } - - source_start = i; - source_end = len; - - while (source_end > source_start && - (line[source_end - 1U] == ' ' || line[source_end - 1U] == '\t' || line[source_end - 1U] == '\r')) { - source_end--; - } - - *out_addr = addr; - *out_name = &line[name_start]; - *out_name_len = name_end - name_start; - *out_source = (source_end > source_start) ? &line[source_start] : CLKS_NULL; - *out_source_len = (source_end > source_start) ? (source_end - source_start) : 0U; - return CLKS_TRUE; -} - -static clks_bool clks_syscall_symbols_ready(void) { - const void *data; - u64 size = 0ULL; - - if (clks_syscall_symbols_checked == CLKS_TRUE) { - return (clks_syscall_symbols_data != CLKS_NULL && clks_syscall_symbols_size > 0ULL) ? CLKS_TRUE : CLKS_FALSE; - } - - clks_syscall_symbols_checked = CLKS_TRUE; - - if (clks_fs_is_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - data = clks_fs_read_all(CLKS_SYSCALL_KERNEL_SYMBOL_FILE, &size); - - if (data == CLKS_NULL || size == 0ULL) { - return CLKS_FALSE; - } - - clks_syscall_symbols_data = (const char *)data; - clks_syscall_symbols_size = size; - return CLKS_TRUE; -} - -static clks_bool clks_syscall_lookup_symbol(u64 addr, const char **out_name, usize *out_name_len, u64 *out_base, - const char **out_source, usize *out_source_len) { - const char *data; - const char *end; - const char *line; - const char *best_name = CLKS_NULL; - const char *best_source = CLKS_NULL; - usize best_name_len = 0U; - usize best_source_len = 0U; - u64 best_addr = 0ULL; - clks_bool found = CLKS_FALSE; - - if (out_name == CLKS_NULL || out_name_len == CLKS_NULL || out_base == CLKS_NULL || out_source == CLKS_NULL || - out_source_len == CLKS_NULL) { - return CLKS_FALSE; - } - - *out_name = CLKS_NULL; - *out_name_len = 0U; - *out_base = 0ULL; - *out_source = CLKS_NULL; - *out_source_len = 0U; - - if (clks_syscall_symbols_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - data = clks_syscall_symbols_data; - end = clks_syscall_symbols_data + clks_syscall_symbols_size; - - while (data < end) { - u64 line_addr; - const char *line_name; - usize line_name_len; - const char *line_source; - usize line_source_len; - usize line_len = 0U; - - line = data; - - while (data < end && *data != '\n') { - data++; - line_len++; - } - - if (data < end && *data == '\n') { - data++; - } - - if (clks_syscall_parse_symbol_line(line, line_len, &line_addr, &line_name, &line_name_len, &line_source, - &line_source_len) == CLKS_FALSE) { - continue; - } - - if (line_addr <= addr && (found == CLKS_FALSE || line_addr >= best_addr)) { - best_addr = line_addr; - best_name = line_name; - best_name_len = line_name_len; - best_source = line_source; - best_source_len = line_source_len; - found = CLKS_TRUE; - } - } - - if (found == CLKS_FALSE) { - return CLKS_FALSE; - } - - *out_name = best_name; - *out_name_len = best_name_len; - *out_base = best_addr; - *out_source = best_source; - *out_source_len = best_source_len; - return CLKS_TRUE; -} - -static usize clks_syscall_kdbg_format_symbol_into(char *out, usize out_size, usize pos, u64 addr) { - const char *sym_name = CLKS_NULL; - const char *sym_source = CLKS_NULL; - usize sym_name_len = 0U; - usize sym_source_len = 0U; - u64 sym_base = 0ULL; - clks_bool has_symbol; - - pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, addr); - has_symbol = clks_syscall_lookup_symbol(addr, &sym_name, &sym_name_len, &sym_base, &sym_source, &sym_source_len); - - if (has_symbol == CLKS_TRUE) { - pos = clks_syscall_procfs_append_char(out, out_size, pos, ' '); - pos = clks_syscall_procfs_append_n(out, out_size, pos, sym_name, sym_name_len); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '+'); - pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, addr - sym_base); - - if (sym_source != CLKS_NULL && sym_source_len > 0U) { - pos = clks_syscall_procfs_append_text(out, out_size, pos, " @ "); - pos = clks_syscall_procfs_append_n(out, out_size, pos, sym_source, sym_source_len); - } - } else { - pos = clks_syscall_procfs_append_text(out, out_size, pos, " "); - } - - return pos; -} - -static usize clks_syscall_kdbg_append_bt_frame(char *out, usize out_size, usize pos, u64 index, u64 rip) { - pos = clks_syscall_procfs_append_char(out, out_size, pos, '#'); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, index); - pos = clks_syscall_procfs_append_char(out, out_size, pos, ' '); - pos = clks_syscall_kdbg_format_symbol_into(out, out_size, pos, rip); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - return pos; -} - -static clks_bool clks_syscall_kdbg_stack_ptr_valid(u64 ptr, u64 stack_low, u64 stack_high) { - if ((ptr & 0x7ULL) != 0ULL) { - return CLKS_FALSE; - } - - if (ptr < stack_low || ptr + 16ULL > stack_high) { - return CLKS_FALSE; - } - - if (ptr < CLKS_SYSCALL_KERNEL_ADDR_BASE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static u64 clks_syscall_kdbg_sym(u64 arg0, u64 arg1, u64 arg2) { - char text[CLKS_SYSCALL_KDBG_TEXT_MAX]; - usize len; - - if (arg1 == 0ULL || arg2 == 0ULL) { - return 0ULL; - } - - text[0] = '\0'; - len = clks_syscall_kdbg_format_symbol_into(text, sizeof(text), 0U, arg0); - return clks_syscall_copy_text_to_user(arg1, arg2, text, len); -} - -static u64 clks_syscall_kdbg_regs(u64 arg0, u64 arg1) { - char text[CLKS_SYSCALL_KDBG_TEXT_MAX]; - usize pos = 0U; - const struct clks_syscall_frame *frame = &clks_syscall_last_frame; - - if (arg0 == 0ULL || arg1 == 0ULL) { - return 0ULL; - } - - text[0] = '\0'; - - if (clks_syscall_last_frame_valid == CLKS_FALSE) { - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "NO REG SNAPSHOT\n"); - return clks_syscall_copy_text_to_user(arg0, arg1, text, pos); - } - - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "RAX="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rax); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RBX="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rbx); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RCX="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rcx); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RDX="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rdx); - pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n'); - - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "RSI="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rsi); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RDI="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rdi); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RBP="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rbp); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RSP="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rsp); - pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n'); - - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "R8 ="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r8); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R9 ="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r9); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R10="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r10); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R11="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r11); - pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n'); - - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "R12="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r12); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R13="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r13); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R14="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r14); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " R15="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->r15); - pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n'); - - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "RIP="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rip); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " CS="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->cs); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RFLAGS="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->rflags); - pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n'); - - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "VECTOR="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->vector); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " ERROR="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->error_code); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " SS="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, frame->ss); - pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n'); - - return clks_syscall_copy_text_to_user(arg0, arg1, text, pos); -} - -static u64 clks_syscall_kdbg_bt(u64 arg0) { - struct clks_syscall_kdbg_bt_req req; - char text[CLKS_SYSCALL_KDBG_TEXT_MAX]; - usize pos = 0U; - u64 frame_index = 0ULL; - - if (arg0 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_readable(arg0, (u64)sizeof(req)) == CLKS_FALSE) { - return 0ULL; - } - - clks_memcpy(&req, (const void *)arg0, sizeof(req)); - - if (req.out_ptr == 0ULL || req.out_size == 0ULL) { - return 0ULL; - } - - text[0] = '\0'; - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "BT RBP="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, req.rbp); - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, " RIP="); - pos = clks_syscall_procfs_append_u64_hex(text, sizeof(text), pos, req.rip); - pos = clks_syscall_procfs_append_char(text, sizeof(text), pos, '\n'); - - if (req.rip != 0ULL) { - pos = clks_syscall_kdbg_append_bt_frame(text, sizeof(text), pos, frame_index, req.rip); - frame_index++; - } - -#if defined(CLKS_ARCH_X86_64) - { - u64 current_rbp = req.rbp; - u64 current_rsp = 0ULL; - u64 stack_low; - u64 stack_high; - - __asm__ volatile("mov %%rsp, %0" : "=r"(current_rsp)); - - stack_low = (current_rsp > CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES) - ? (current_rsp - CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES) - : CLKS_SYSCALL_KERNEL_ADDR_BASE; - stack_high = current_rsp + CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES; - - if (stack_high < current_rsp) { - stack_high = 0xFFFFFFFFFFFFFFFFULL; - } - - if (stack_low < CLKS_SYSCALL_KERNEL_ADDR_BASE) { - stack_low = CLKS_SYSCALL_KERNEL_ADDR_BASE; - } - - if (clks_syscall_kdbg_stack_ptr_valid(current_rbp, stack_low, stack_high) == CLKS_TRUE) { - while (frame_index < CLKS_SYSCALL_KDBG_BT_MAX_FRAMES) { - const u64 *frame_ptr; - u64 next_rbp; - u64 ret_rip; - - frame_ptr = (const u64 *)(usize)current_rbp; - next_rbp = frame_ptr[0]; - ret_rip = frame_ptr[1]; - - if (ret_rip == 0ULL) { - break; - } - - pos = clks_syscall_kdbg_append_bt_frame(text, sizeof(text), pos, frame_index, ret_rip); - frame_index++; - - if (next_rbp <= current_rbp) { - break; - } - - if (clks_syscall_kdbg_stack_ptr_valid(next_rbp, stack_low, stack_high) == CLKS_FALSE) { - break; - } - - current_rbp = next_rbp; - } - } else { - pos = clks_syscall_procfs_append_text( - text, sizeof(text), pos, "NOTE: stack walk skipped (rbp not in current kernel stack window)\n"); - } - } -#else - pos = clks_syscall_procfs_append_text(text, sizeof(text), pos, "NOTE: stack walk unsupported on this arch\n"); -#endif - - return clks_syscall_copy_text_to_user(req.out_ptr, req.out_size, text, pos); -} - -static clks_bool clks_syscall_procfs_snapshot_for_path(const char *path, struct clks_exec_proc_snapshot *out_snap) { - u64 pid; - - if (path == CLKS_NULL || out_snap == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_syscall_procfs_is_self(path) == CLKS_TRUE) { - pid = clks_exec_current_pid(); - - if (pid == 0ULL) { - return CLKS_FALSE; - } - - return clks_exec_proc_snapshot(pid, out_snap); - } - - if (clks_syscall_procfs_parse_pid(path, &pid) == CLKS_TRUE) { - return clks_exec_proc_snapshot(pid, out_snap); - } - - return CLKS_FALSE; -} - -static usize clks_syscall_procfs_render_snapshot(char *out, usize out_size, - const struct clks_exec_proc_snapshot *snap) { - usize pos = 0U; - - if (out == CLKS_NULL || out_size == 0U || snap == CLKS_NULL) { - return 0U; - } - - out[0] = '\0'; - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "pid="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->pid); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "ppid="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->ppid); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "state="); - pos = clks_syscall_procfs_append_text(out, out_size, pos, clks_syscall_proc_state_name(snap->state)); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "state_id="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->state); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "tty="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->tty_index); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "runtime_ticks="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->runtime_ticks); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "mem_bytes="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->mem_bytes); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "exit_status="); - pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, snap->exit_status); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_signal="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->last_signal); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_fault_vector="); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->last_fault_vector); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_fault_error="); - pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, snap->last_fault_error); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_fault_rip="); - pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, snap->last_fault_rip); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - pos = clks_syscall_procfs_append_text(out, out_size, pos, "path="); - pos = clks_syscall_procfs_append_text(out, out_size, pos, snap->path); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - - return pos; -} - -static usize clks_syscall_procfs_render_list(char *out, usize out_size) { - usize pos = 0U; - u64 proc_count = clks_exec_proc_count(); - u64 i; - - if (out == CLKS_NULL || out_size == 0U) { - return 0U; - } - - out[0] = '\0'; - pos = clks_syscall_procfs_append_text(out, out_size, pos, "pid state tty runtime mem path\n"); - - for (i = 0ULL; i < proc_count; i++) { - u64 pid = 0ULL; - struct clks_exec_proc_snapshot snap; - - if (clks_exec_proc_pid_at(i, &pid) == CLKS_FALSE || pid == 0ULL) { - continue; - } - - if (clks_exec_proc_snapshot(pid, &snap) == CLKS_FALSE) { - continue; - } - - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.pid); - pos = clks_syscall_procfs_append_char(out, out_size, pos, ' '); - pos = clks_syscall_procfs_append_text(out, out_size, pos, clks_syscall_proc_state_name(snap.state)); - pos = clks_syscall_procfs_append_char(out, out_size, pos, ' '); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.tty_index); - pos = clks_syscall_procfs_append_char(out, out_size, pos, ' '); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.runtime_ticks); - pos = clks_syscall_procfs_append_char(out, out_size, pos, ' '); - pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.mem_bytes); - pos = clks_syscall_procfs_append_char(out, out_size, pos, ' '); - pos = clks_syscall_procfs_append_text(out, out_size, pos, snap.path); - pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n'); - } - - return pos; -} - -static clks_bool clks_syscall_procfs_render_file(const char *path, char *out, usize out_size, usize *out_len) { - struct clks_exec_proc_snapshot snap; - - if (out_len != CLKS_NULL) { - *out_len = 0U; - } - - if (path == CLKS_NULL || out == CLKS_NULL || out_size == 0U || out_len == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_syscall_procfs_is_list(path) == CLKS_TRUE) { - *out_len = clks_syscall_procfs_render_list(out, out_size); - return CLKS_TRUE; - } - - if (clks_syscall_procfs_snapshot_for_path(path, &snap) == CLKS_TRUE) { - *out_len = clks_syscall_procfs_render_snapshot(out, out_size, &snap); - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -static u64 clks_syscall_fs_child_count(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - u64 base_count; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (CLKS_CFG_PROCFS != 0 && clks_syscall_procfs_is_root(path) == CLKS_TRUE) { - return 2ULL + clks_exec_proc_count(); - } - - base_count = clks_fs_count_children(path); - - if (base_count == (u64)-1) { - return (u64)-1; - } - - if (CLKS_CFG_PROCFS != 0 && clks_syscall_fs_is_root(path) == CLKS_TRUE && - clks_syscall_fs_has_real_proc_dir() == CLKS_FALSE) { - return base_count + 1ULL; - } - - return base_count; -} - -static u64 clks_syscall_fs_get_child_name(u64 arg0, u64 arg1, u64 arg2) { - char path[CLKS_SYSCALL_PATH_MAX]; - - if (arg2 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_writable(arg2, CLKS_SYSCALL_NAME_MAX) == CLKS_FALSE) { - return 0ULL; - } - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return 0ULL; - } - - if (CLKS_CFG_PROCFS != 0 && clks_syscall_procfs_is_root(path) == CLKS_TRUE) { - if (arg1 == 0ULL) { - clks_memset((void *)arg2, 0, CLKS_SYSCALL_NAME_MAX); - clks_memcpy((void *)arg2, "self", 5U); - return 1ULL; - } - - if (arg1 == 1ULL) { - clks_memset((void *)arg2, 0, CLKS_SYSCALL_NAME_MAX); - clks_memcpy((void *)arg2, "list", 5U); - return 1ULL; - } - - { - u64 pid = 0ULL; - char pid_text[32]; - usize len; - - if (clks_exec_proc_pid_at(arg1 - 2ULL, &pid) == CLKS_FALSE || pid == 0ULL) { - return 0ULL; - } - - clks_memset(pid_text, 0, sizeof(pid_text)); - len = clks_syscall_procfs_append_u64_dec(pid_text, sizeof(pid_text), 0U, pid); - - if (len + 1U > CLKS_SYSCALL_NAME_MAX) { - return 0ULL; - } - - clks_memset((void *)arg2, 0, CLKS_SYSCALL_NAME_MAX); - clks_memcpy((void *)arg2, pid_text, len + 1U); - return 1ULL; - } - } - - if (CLKS_CFG_PROCFS != 0 && clks_syscall_fs_is_root(path) == CLKS_TRUE && - clks_syscall_fs_has_real_proc_dir() == CLKS_FALSE) { - if (arg1 == 0ULL) { - clks_memset((void *)arg2, 0, CLKS_SYSCALL_NAME_MAX); - clks_memcpy((void *)arg2, "proc", 5U); - return 1ULL; - } - - if (clks_fs_get_child_name(path, arg1 - 1ULL, (char *)arg2, (usize)CLKS_SYSCALL_NAME_MAX) == CLKS_FALSE) { - return 0ULL; - } - - return 1ULL; - } - - if (clks_fs_get_child_name(path, arg1, (char *)arg2, (usize)CLKS_SYSCALL_NAME_MAX) == CLKS_FALSE) { - return 0ULL; - } - - return 1ULL; -} - -static u64 clks_syscall_fs_read(u64 arg0, u64 arg1, u64 arg2) { - char path[CLKS_SYSCALL_PATH_MAX]; - const void *data; - u64 file_size = 0ULL; - u64 copy_len; - - if (arg1 == 0ULL || arg2 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_writable(arg1, arg2) == CLKS_FALSE) { - return 0ULL; - } - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return 0ULL; - } - - if (CLKS_CFG_PROCFS != 0 && - (clks_syscall_procfs_is_list(path) == CLKS_TRUE || clks_syscall_procfs_is_self(path) == CLKS_TRUE || - clks_syscall_procfs_parse_pid(path, &file_size) == CLKS_TRUE)) { - char proc_text[CLKS_SYSCALL_PROCFS_TEXT_MAX]; - usize proc_len = 0U; - - if (clks_syscall_procfs_render_file(path, proc_text, sizeof(proc_text), &proc_len) == CLKS_FALSE) { - return 0ULL; - } - - copy_len = ((u64)proc_len < arg2) ? (u64)proc_len : arg2; - - if (copy_len == 0ULL) { - return 0ULL; - } - - clks_memcpy((void *)arg1, proc_text, (usize)copy_len); - return copy_len; - } - - data = clks_fs_read_all(path, &file_size); - - if (data == CLKS_NULL || file_size == 0ULL) { - return 0ULL; - } - - copy_len = (file_size < arg2) ? file_size : arg2; - clks_memcpy((void *)arg1, data, (usize)copy_len); - return copy_len; -} - -static u64 clks_syscall_exec_path(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - u64 status = (u64)-1; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_exec_run_path(path, &status) == CLKS_FALSE) { - return (u64)-1; - } - - return status; -} - -static u64 clks_syscall_exec_pathv(u64 arg0, u64 arg1, u64 arg2) { - char path[CLKS_SYSCALL_PATH_MAX]; - char argv_line[CLKS_SYSCALL_ARG_LINE_MAX]; - char env_line[CLKS_SYSCALL_ENV_LINE_MAX]; - u64 status = (u64)-1; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_syscall_copy_user_optional_string(arg1, argv_line, sizeof(argv_line)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_syscall_copy_user_optional_string(arg2, env_line, sizeof(env_line)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_exec_run_pathv(path, argv_line, env_line, &status) == CLKS_FALSE) { - return (u64)-1; - } - - return status; -} - -static u64 clks_syscall_exec_pathv_io(u64 arg0, u64 arg1, u64 arg2) { - char path[CLKS_SYSCALL_PATH_MAX]; - char argv_line[CLKS_SYSCALL_ARG_LINE_MAX]; - char env_line[CLKS_SYSCALL_ENV_LINE_MAX]; - struct clks_syscall_exec_io_req req; - u64 status = (u64)-1; - - if (arg2 == 0ULL) { - return (u64)-1; - } - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_syscall_copy_user_optional_string(arg1, argv_line, sizeof(argv_line)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_syscall_user_ptr_readable(arg2, (u64)sizeof(req)) == CLKS_FALSE) { - return (u64)-1; - } - - clks_memcpy(&req, (const void *)arg2, sizeof(req)); - - if (clks_syscall_copy_user_optional_string(req.env_line_ptr, env_line, sizeof(env_line)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_exec_run_pathv_io(path, argv_line, env_line, req.stdin_fd, req.stdout_fd, req.stderr_fd, &status) == - CLKS_FALSE) { - return (u64)-1; - } - - return status; -} - -static u64 clks_syscall_getpid(void) { - return clks_exec_current_pid(); -} - -static u64 clks_syscall_spawn_path(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - u64 pid = (u64)-1; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_exec_spawn_path(path, &pid) == CLKS_FALSE) { - return (u64)-1; - } - - return pid; -} - -static u64 clks_syscall_spawn_pathv(u64 arg0, u64 arg1, u64 arg2) { - char path[CLKS_SYSCALL_PATH_MAX]; - char argv_line[CLKS_SYSCALL_ARG_LINE_MAX]; - char env_line[CLKS_SYSCALL_ENV_LINE_MAX]; - u64 pid = (u64)-1; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_syscall_copy_user_optional_string(arg1, argv_line, sizeof(argv_line)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_syscall_copy_user_optional_string(arg2, env_line, sizeof(env_line)) == CLKS_FALSE) { - return (u64)-1; - } - - if (clks_exec_spawn_pathv(path, argv_line, env_line, &pid) == CLKS_FALSE) { - return (u64)-1; - } - - return pid; -} - -static u64 clks_syscall_waitpid(u64 arg0, u64 arg1) { - u64 status = (u64)-1; - u64 wait_ret = clks_exec_wait_pid(arg0, &status); - - if (wait_ret == 1ULL && arg1 != 0ULL) { - if (clks_syscall_user_ptr_writable(arg1, (u64)sizeof(status)) == CLKS_FALSE) { - return (u64)-1; - } - clks_memcpy((void *)arg1, &status, sizeof(status)); - } - - return wait_ret; -} - -static u64 clks_syscall_proc_argc(void) { - return clks_exec_current_argc(); -} - -static u64 clks_syscall_proc_argv(u64 arg0, u64 arg1, u64 arg2) { - if (arg1 == 0ULL || arg2 == 0ULL) { - return 0ULL; - } - - if (arg2 > CLKS_SYSCALL_ITEM_MAX) { - arg2 = CLKS_SYSCALL_ITEM_MAX; - } - - if (clks_syscall_user_ptr_writable(arg1, arg2) == CLKS_FALSE) { - return 0ULL; - } - - return (clks_exec_copy_current_argv(arg0, (char *)arg1, (usize)arg2) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_proc_envc(void) { - return clks_exec_current_envc(); -} - -static u64 clks_syscall_proc_env(u64 arg0, u64 arg1, u64 arg2) { - if (arg1 == 0ULL || arg2 == 0ULL) { - return 0ULL; - } - - if (arg2 > CLKS_SYSCALL_ITEM_MAX) { - arg2 = CLKS_SYSCALL_ITEM_MAX; - } - - if (clks_syscall_user_ptr_writable(arg1, arg2) == CLKS_FALSE) { - return 0ULL; - } - - return (clks_exec_copy_current_env(arg0, (char *)arg1, (usize)arg2) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_proc_last_signal(void) { - return clks_exec_current_signal(); -} - -static u64 clks_syscall_proc_fault_vector(void) { - return clks_exec_current_fault_vector(); -} - -static u64 clks_syscall_proc_fault_error(void) { - return clks_exec_current_fault_error(); -} - -static u64 clks_syscall_proc_fault_rip(void) { - return clks_exec_current_fault_rip(); -} - -static u64 clks_syscall_proc_count(void) { - return clks_exec_proc_count(); -} - -static u64 clks_syscall_proc_pid_at(u64 arg0, u64 arg1) { - u64 pid = 0ULL; - - if (arg1 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_writable(arg1, (u64)sizeof(pid)) == CLKS_FALSE) { - return 0ULL; - } - - if (clks_exec_proc_pid_at(arg0, &pid) == CLKS_FALSE) { - return 0ULL; - } - - clks_memcpy((void *)arg1, &pid, sizeof(pid)); - return 1ULL; -} - -static u64 clks_syscall_proc_snapshot(u64 arg0, u64 arg1, u64 arg2) { - struct clks_exec_proc_snapshot snap; - - if (arg1 == 0ULL || arg2 < (u64)sizeof(snap)) { - return 0ULL; - } - - if (clks_syscall_user_ptr_writable(arg1, (u64)sizeof(snap)) == CLKS_FALSE) { - return 0ULL; - } - - if (clks_exec_proc_snapshot(arg0, &snap) == CLKS_FALSE) { - return 0ULL; - } - - clks_memcpy((void *)arg1, &snap, sizeof(snap)); - return 1ULL; -} - -static u64 clks_syscall_proc_kill(u64 arg0, u64 arg1) { - return clks_exec_proc_kill(arg0, arg1); -} - -static u64 clks_syscall_exit(u64 arg0) { - return (clks_exec_request_exit(arg0) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_sleep_ticks(u64 arg0) { - return clks_exec_sleep_ticks(arg0); -} - -static u64 clks_syscall_yield(void) { - return clks_exec_yield(); -} - -static u64 clks_syscall_shutdown(void) { - clks_log(CLKS_LOG_WARN, "SYSCALL", "SHUTDOWN REQUESTED BY USERLAND"); - clks_serial_write("[WARN][SYSCALL] SHUTDOWN REQUESTED\n"); -#if defined(CLKS_ARCH_X86_64) - clks_syscall_outw(0x604U, 0x2000U); -#endif - clks_cpu_halt_forever(); - return 1ULL; -} - -static u64 clks_syscall_restart(void) { - clks_log(CLKS_LOG_WARN, "SYSCALL", "RESTART REQUESTED BY USERLAND"); - clks_serial_write("[WARN][SYSCALL] RESTART REQUESTED\n"); -#if defined(CLKS_ARCH_X86_64) - clks_syscall_outb(0x64U, 0xFEU); -#endif - clks_cpu_halt_forever(); - return 1ULL; -} - -static u64 clks_syscall_audio_available(void) { - return (clks_audio_available() == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_audio_play_tone(u64 arg0, u64 arg1) { - if (clks_audio_play_tone(arg0, arg1) == CLKS_FALSE) { - return 0ULL; - } - - return 1ULL; -} - -static u64 clks_syscall_audio_stop(void) { - clks_audio_stop(); - return 1ULL; -} -static u64 clks_syscall_fs_stat_type(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - struct clks_fs_node_info info; - struct clks_exec_proc_snapshot snap; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (CLKS_CFG_PROCFS != 0 && clks_syscall_procfs_is_root(path) == CLKS_TRUE) { - return (u64)CLKS_FS_NODE_DIR; - } - - if (CLKS_CFG_PROCFS != 0 && - (clks_syscall_procfs_is_list(path) == CLKS_TRUE || clks_syscall_procfs_is_self(path) == CLKS_TRUE)) { - return (u64)CLKS_FS_NODE_FILE; - } - - if (CLKS_CFG_PROCFS != 0 && clks_syscall_procfs_snapshot_for_path(path, &snap) == CLKS_TRUE) { - return (u64)CLKS_FS_NODE_FILE; - } - - if (clks_fs_stat(path, &info) == CLKS_FALSE) { - return (u64)-1; - } - - return (u64)info.type; -} - -static u64 clks_syscall_fs_stat_size(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - struct clks_fs_node_info info; - char proc_text[CLKS_SYSCALL_PROCFS_TEXT_MAX]; - usize proc_len = 0U; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return (u64)-1; - } - - if (CLKS_CFG_PROCFS != 0 && clks_syscall_procfs_is_root(path) == CLKS_TRUE) { - return 0ULL; - } - - if (CLKS_CFG_PROCFS != 0 && - clks_syscall_procfs_render_file(path, proc_text, sizeof(proc_text), &proc_len) == CLKS_TRUE) { - return (u64)proc_len; - } - - if (clks_fs_stat(path, &info) == CLKS_FALSE) { - return (u64)-1; - } - - return info.size; -} - -static u64 clks_syscall_fs_mkdir(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return 0ULL; - } - - return (clks_fs_mkdir(path) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_fs_write_common(u64 arg0, u64 arg1, u64 arg2, clks_bool append_mode) { - char path[CLKS_SYSCALL_PATH_MAX]; - const u8 *src = (const u8 *)arg1; - u64 remaining = arg2; - clks_bool first_chunk = CLKS_TRUE; - clks_bool ok; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return 0ULL; - } - - if (arg2 == 0ULL) { - if (append_mode == CLKS_TRUE) { - ok = clks_fs_append(path, CLKS_NULL, 0ULL); - } else { - ok = clks_fs_write_all(path, CLKS_NULL, 0ULL); - } - - return (ok == CLKS_TRUE) ? 1ULL : 0ULL; - } - - if (arg1 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_readable(arg1, arg2) == CLKS_FALSE) { - return 0ULL; - } - - while (remaining > 0ULL) { - u64 chunk_len = remaining; - void *heap_copy; - - if (chunk_len > CLKS_SYSCALL_FS_IO_CHUNK_LEN) { - chunk_len = CLKS_SYSCALL_FS_IO_CHUNK_LEN; - } - - heap_copy = clks_kmalloc((usize)chunk_len); - if (heap_copy == CLKS_NULL) { - return 0ULL; - } - - clks_memcpy(heap_copy, (const void *)src, (usize)chunk_len); - - if (append_mode == CLKS_TRUE || first_chunk == CLKS_FALSE) { - ok = clks_fs_append(path, heap_copy, chunk_len); - } else { - ok = clks_fs_write_all(path, heap_copy, chunk_len); - } - - clks_kfree(heap_copy); - - if (ok == CLKS_FALSE) { - return 0ULL; - } - - src += chunk_len; - remaining -= chunk_len; - first_chunk = CLKS_FALSE; - } - - return 1ULL; -} - -static u64 clks_syscall_fs_write(u64 arg0, u64 arg1, u64 arg2) { - return clks_syscall_fs_write_common(arg0, arg1, arg2, CLKS_FALSE); -} - -static u64 clks_syscall_fs_append(u64 arg0, u64 arg1, u64 arg2) { - return clks_syscall_fs_write_common(arg0, arg1, arg2, CLKS_TRUE); -} - -static u64 clks_syscall_fs_remove(u64 arg0) { - char path[CLKS_SYSCALL_PATH_MAX]; - - if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { - return 0ULL; - } - - return (clks_fs_remove(path) == CLKS_TRUE) ? 1ULL : 0ULL; -} - -static u64 clks_syscall_log_journal_count(void) { - return clks_log_journal_count(); -} - -static u64 clks_syscall_log_journal_read(u64 arg0, u64 arg1, u64 arg2) { - char line[CLKS_SYSCALL_JOURNAL_MAX_LEN]; - usize line_len; - usize copy_len; - - if (arg1 == 0ULL || arg2 == 0ULL) { - return 0ULL; - } - - if (clks_syscall_user_ptr_writable(arg1, arg2) == CLKS_FALSE) { - return 0ULL; - } - - if (clks_log_journal_read(arg0, line, sizeof(line)) == CLKS_FALSE) { - return 0ULL; - } - - line_len = clks_strlen(line) + 1U; - copy_len = line_len; - - if (copy_len > (usize)arg2) { - copy_len = (usize)arg2; - } - - if (copy_len > sizeof(line)) { - copy_len = sizeof(line); - } - - clks_memcpy((void *)arg1, line, copy_len); - ((char *)arg1)[copy_len - 1U] = '\0'; - return 1ULL; -} - -static void clks_syscall_serial_write_hex64(u64 value) { - i32 nibble; - - for (nibble = 15; nibble >= 0; nibble--) { - u64 current = (value >> (u64)(nibble * 4)) & 0x0FULL; - char ch = (current < 10ULL) ? (char)('0' + current) : (char)('A' + (current - 10ULL)); - clks_serial_write_char(ch); - } -} - -#if CLKS_CFG_USC != 0 -static void clks_syscall_usc_sleep_until_input(void) { -#if defined(CLKS_ARCH_X86_64) - u64 flags = 0ULL; - - __asm__ volatile("pushfq; popq %0" : "=r"(flags) : : "memory"); - - if ((flags & (1ULL << 9)) != 0ULL) { - __asm__ volatile("hlt" : : : "memory"); - } else { - __asm__ volatile("sti; hlt; cli" : : : "memory"); - } -#elif defined(CLKS_ARCH_AARCH64) - clks_cpu_pause(); -#endif -} - -static const char *clks_syscall_usc_syscall_name(u64 id) { - switch (id) { - case CLKS_SYSCALL_FS_MKDIR: - return "FS_MKDIR"; - case CLKS_SYSCALL_FS_WRITE: - return "FS_WRITE"; - case CLKS_SYSCALL_FS_APPEND: - return "FS_APPEND"; - case CLKS_SYSCALL_FS_REMOVE: - return "FS_REMOVE"; - case CLKS_SYSCALL_EXEC_PATH: - return "EXEC_PATH"; - case CLKS_SYSCALL_EXEC_PATHV: - return "EXEC_PATHV"; - case CLKS_SYSCALL_EXEC_PATHV_IO: - return "EXEC_PATHV_IO"; - case CLKS_SYSCALL_SPAWN_PATH: - return "SPAWN_PATH"; - case CLKS_SYSCALL_SPAWN_PATHV: - return "SPAWN_PATHV"; - case CLKS_SYSCALL_PROC_KILL: - return "PROC_KILL"; - case CLKS_SYSCALL_SHUTDOWN: - return "SHUTDOWN"; - case CLKS_SYSCALL_RESTART: - return "RESTART"; - case CLKS_SYSCALL_DISK_PRESENT: - return "DISK_PRESENT"; - case CLKS_SYSCALL_DISK_SIZE_BYTES: - return "DISK_SIZE_BYTES"; - case CLKS_SYSCALL_DISK_SECTOR_COUNT: - return "DISK_SECTOR_COUNT"; - case CLKS_SYSCALL_DISK_FORMATTED: - return "DISK_FORMATTED"; - case CLKS_SYSCALL_DISK_FORMAT_FAT32: - return "DISK_FORMAT_FAT32"; - case CLKS_SYSCALL_DISK_MOUNT: - return "DISK_MOUNT"; - case CLKS_SYSCALL_DISK_MOUNTED: - return "DISK_MOUNTED"; - case CLKS_SYSCALL_DISK_MOUNT_PATH: - return "DISK_MOUNT_PATH"; - case CLKS_SYSCALL_DISK_READ_SECTOR: - return "DISK_READ_SECTOR"; - case CLKS_SYSCALL_DISK_WRITE_SECTOR: - return "DISK_WRITE_SECTOR"; - default: - return "UNKNOWN"; - } -} - -static clks_bool clks_syscall_usc_is_dangerous(u64 id) { - switch (id) { - case CLKS_SYSCALL_FS_MKDIR: - return (CLKS_CFG_USC_SC_FS_MKDIR != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_FS_WRITE: - return (CLKS_CFG_USC_SC_FS_WRITE != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_FS_APPEND: - return (CLKS_CFG_USC_SC_FS_APPEND != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_FS_REMOVE: - return (CLKS_CFG_USC_SC_FS_REMOVE != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_EXEC_PATH: - return (CLKS_CFG_USC_SC_EXEC_PATH != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_EXEC_PATHV: - return (CLKS_CFG_USC_SC_EXEC_PATHV != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_EXEC_PATHV_IO: - return (CLKS_CFG_USC_SC_EXEC_PATHV_IO != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_SPAWN_PATH: - return (CLKS_CFG_USC_SC_SPAWN_PATH != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_SPAWN_PATHV: - return (CLKS_CFG_USC_SC_SPAWN_PATHV != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_PROC_KILL: - return (CLKS_CFG_USC_SC_PROC_KILL != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_SHUTDOWN: - return (CLKS_CFG_USC_SC_SHUTDOWN != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_RESTART: - return (CLKS_CFG_USC_SC_RESTART != 0) ? CLKS_TRUE : CLKS_FALSE; - case CLKS_SYSCALL_DISK_FORMAT_FAT32: - return CLKS_TRUE; - case CLKS_SYSCALL_DISK_WRITE_SECTOR: - return CLKS_TRUE; - default: - return CLKS_FALSE; - } -} - -static void clks_syscall_usc_copy_path(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || dst_size == 0U) { - return; - } - - if (src == CLKS_NULL) { - dst[0] = '\0'; - return; - } - - while (src[i] != '\0' && i + 1U < dst_size) { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static clks_bool clks_syscall_usc_current_app_path(char *out_path, usize out_size) { - u64 pid; - struct clks_exec_proc_snapshot snap; - - if (out_path == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - out_path[0] = '\0'; - pid = clks_exec_current_pid(); - - if (pid == 0ULL) { - return CLKS_FALSE; - } - - if (clks_exec_proc_snapshot(pid, &snap) == CLKS_FALSE || snap.path[0] == '\0') { - return CLKS_FALSE; - } - - clks_syscall_usc_copy_path(out_path, out_size, snap.path); - return CLKS_TRUE; -} - -static i32 clks_syscall_usc_find_allowed_path(const char *path) { - u32 i; - - if (path == CLKS_NULL || path[0] == '\0') { - return -1; - } - - for (i = 0U; i < CLKS_SYSCALL_USC_MAX_ALLOWED_APPS; i++) { - if (clks_syscall_usc_allowed_used[i] == CLKS_TRUE && clks_strcmp(clks_syscall_usc_allowed_path[i], path) == 0) { - return (i32)i; - } - } - - return -1; -} - -static void clks_syscall_usc_remember_path(const char *path) { - u32 i; - - if (path == CLKS_NULL || path[0] == '\0') { - return; - } - - if (clks_syscall_usc_find_allowed_path(path) >= 0) { - return; - } - - for (i = 0U; i < CLKS_SYSCALL_USC_MAX_ALLOWED_APPS; i++) { - if (clks_syscall_usc_allowed_used[i] == CLKS_FALSE) { - clks_syscall_usc_allowed_used[i] = CLKS_TRUE; - clks_syscall_usc_copy_path(clks_syscall_usc_allowed_path[i], sizeof(clks_syscall_usc_allowed_path[i]), - path); - return; - } - } -} - -static void clks_syscall_usc_emit_text_line(const char *label, const char *value) { - char message[320]; - usize pos = 0U; - - message[0] = '\0'; - pos = clks_syscall_procfs_append_text(message, sizeof(message), pos, label); - pos = clks_syscall_procfs_append_text(message, sizeof(message), pos, ": "); - pos = clks_syscall_procfs_append_text(message, sizeof(message), pos, value); - (void)pos; - clks_log(CLKS_LOG_WARN, "USC", message); -} - -static void clks_syscall_usc_emit_hex_line(const char *label, u64 value) { - clks_log_hex(CLKS_LOG_WARN, "USC", label, value); -} - -static clks_bool clks_syscall_usc_prompt_allow(const char *app_path, u64 id, u64 arg0, u64 arg1, u64 arg2) { - const char *name = clks_syscall_usc_syscall_name(id); - u32 tty_index = clks_exec_current_tty(); - -#if !defined(CLKS_CFG_KEYBOARD) || (CLKS_CFG_KEYBOARD == 0) - (void)tty_index; - clks_syscall_usc_emit_text_line("BLOCK", "keyboard disabled, cannot prompt"); - return CLKS_FALSE; -#else - clks_syscall_usc_emit_text_line("DANGEROUS_SYSCALL", "REQUEST DETECTED"); - clks_syscall_usc_emit_text_line("APP", app_path); - clks_syscall_usc_emit_hex_line("SYSCALL_ID", id); - clks_syscall_usc_emit_text_line("SYSCALL_NAME", name); - clks_syscall_usc_emit_hex_line("ARG0", arg0); - clks_syscall_usc_emit_hex_line("ARG1", arg1); - clks_syscall_usc_emit_hex_line("ARG2", arg2); - clks_log(CLKS_LOG_WARN, "USC", "CONFIRM: Allow this app permanently? [y/N]"); - clks_tty_write("[WARN][USC] Allow this app permanently? [y/N]: "); - clks_serial_write("[WARN][USC] Allow this app permanently? [y/N]: "); - - while (1) { - char ch = '\0'; - - if (clks_keyboard_pop_char_for_tty(tty_index, &ch) == CLKS_TRUE) { - if (ch == 'y' || ch == 'Y') { - clks_tty_write("y\n"); - clks_serial_write("y\n"); - return CLKS_TRUE; - } - - if (ch == 'n' || ch == 'N' || ch == '\n' || ch == '\r' || ch == 27) { - clks_tty_write("n\n"); - clks_serial_write("n\n"); - return CLKS_FALSE; - } - - continue; - } - - clks_syscall_usc_sleep_until_input(); - } -#endif -} -#endif - -static clks_bool clks_syscall_usc_check(u64 id, u64 arg0, u64 arg1, u64 arg2) { -#if CLKS_CFG_USC == 0 - (void)id; - (void)arg0; - (void)arg1; - (void)arg2; - return CLKS_TRUE; -#else - char app_path[CLKS_EXEC_PROC_PATH_MAX]; - - if (clks_syscall_usc_is_dangerous(id) == CLKS_FALSE) { - return CLKS_TRUE; - } - - if (clks_exec_is_running() == CLKS_FALSE || clks_exec_current_path_is_user() == CLKS_FALSE) { - return CLKS_TRUE; - } - - if (clks_syscall_usc_current_app_path(app_path, sizeof(app_path)) == CLKS_FALSE) { - clks_syscall_usc_emit_text_line("BLOCK", "cannot resolve current app path"); - return CLKS_FALSE; - } - - if (clks_syscall_usc_find_allowed_path(app_path) >= 0) { - return CLKS_TRUE; - } - - if (clks_syscall_usc_prompt_allow(app_path, id, arg0, arg1, arg2) == CLKS_TRUE) { - clks_syscall_usc_remember_path(app_path); - clks_syscall_usc_emit_text_line("ALLOW", app_path); - return CLKS_TRUE; - } - - clks_syscall_usc_emit_text_line("DENY", app_path); - return CLKS_FALSE; -#endif -} - -static void clks_syscall_stats_reset(void) { - clks_syscall_stats_total = 0ULL; - clks_memset(clks_syscall_stats_id_count, 0, sizeof(clks_syscall_stats_id_count)); - clks_memset(clks_syscall_stats_recent_id_count, 0, sizeof(clks_syscall_stats_recent_id_count)); - clks_memset(clks_syscall_stats_recent_ring, 0, sizeof(clks_syscall_stats_recent_ring)); - clks_syscall_stats_recent_head = 0U; - clks_syscall_stats_recent_size = 0U; -} - -static void clks_syscall_stats_record(u64 id) { - u16 ring_id = 0xFFFFU; - - clks_syscall_stats_total++; - - if (id <= CLKS_SYSCALL_STATS_MAX_ID) { - clks_syscall_stats_id_count[id]++; - } - - if (id <= 0xFFFFULL) { - ring_id = (u16)id; - } - - if (clks_syscall_stats_recent_size >= CLKS_SYSCALL_STATS_RING_SIZE) { - u64 old_id = (u64)clks_syscall_stats_recent_ring[clks_syscall_stats_recent_head]; - - if (old_id <= CLKS_SYSCALL_STATS_MAX_ID && clks_syscall_stats_recent_id_count[old_id] > 0ULL) { - clks_syscall_stats_recent_id_count[old_id]--; - } - } else { - clks_syscall_stats_recent_size++; - } - - clks_syscall_stats_recent_ring[clks_syscall_stats_recent_head] = ring_id; - - if (id <= CLKS_SYSCALL_STATS_MAX_ID) { - clks_syscall_stats_recent_id_count[id]++; - } - - clks_syscall_stats_recent_head++; - - if (clks_syscall_stats_recent_head >= CLKS_SYSCALL_STATS_RING_SIZE) { - clks_syscall_stats_recent_head = 0U; - } -} - -static u64 clks_syscall_stats_total_count(void) { - return clks_syscall_stats_total; -} - -static u64 clks_syscall_stats_id(u64 id) { - if (id > CLKS_SYSCALL_STATS_MAX_ID) { - return 0ULL; - } - - return clks_syscall_stats_id_count[id]; -} - -static u64 clks_syscall_stats_recent_window(void) { - return (u64)clks_syscall_stats_recent_size; -} - -static u64 clks_syscall_stats_recent_id(u64 id) { - if (id > CLKS_SYSCALL_STATS_MAX_ID) { - return 0ULL; - } - - return clks_syscall_stats_recent_id_count[id]; -} - -static void clks_syscall_trace_user_program(u64 id) { - clks_bool user_program_running = - (clks_exec_is_running() == CLKS_TRUE && clks_exec_current_path_is_user() == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; - - if (user_program_running == CLKS_FALSE) { - if (clks_syscall_user_trace_active == CLKS_TRUE) { - clks_serial_write("[DEBUG][SYSCALL] USER_TRACE_END\n"); - } - - clks_syscall_user_trace_active = CLKS_FALSE; - clks_syscall_user_trace_budget = 0ULL; - return; - } - - if (clks_syscall_user_trace_active == CLKS_FALSE) { - clks_syscall_user_trace_active = CLKS_TRUE; - clks_syscall_user_trace_budget = CLKS_SYSCALL_USER_TRACE_BUDGET; - clks_serial_write("[DEBUG][SYSCALL] USER_TRACE_BEGIN\n"); - clks_serial_write("[DEBUG][SYSCALL] PID: 0X"); - clks_syscall_serial_write_hex64(clks_exec_current_pid()); - clks_serial_write("\n"); - } - - if (clks_syscall_user_trace_budget > 0ULL) { - clks_serial_write("[DEBUG][SYSCALL] USER_ID: 0X"); - clks_syscall_serial_write_hex64(id); - clks_serial_write("\n"); - clks_syscall_user_trace_budget--; - - if (clks_syscall_user_trace_budget == 0ULL) { - clks_serial_write("[DEBUG][SYSCALL] USER_TRACE_BUDGET_EXHAUSTED\n"); - } - } -} - -void clks_syscall_init(void) { - clks_syscall_ready = CLKS_TRUE; - clks_syscall_user_trace_active = CLKS_FALSE; - clks_syscall_user_trace_budget = 0ULL; - clks_memset(&clks_syscall_last_frame, 0, sizeof(clks_syscall_last_frame)); - clks_syscall_last_frame_valid = CLKS_FALSE; - clks_syscall_symbols_checked = CLKS_FALSE; - clks_syscall_symbols_data = CLKS_NULL; - clks_syscall_symbols_size = 0ULL; -#if CLKS_CFG_USC != 0 - clks_memset(clks_syscall_usc_allowed_used, 0, sizeof(clks_syscall_usc_allowed_used)); - clks_memset(clks_syscall_usc_allowed_path, 0, sizeof(clks_syscall_usc_allowed_path)); -#endif - clks_syscall_stats_reset(); - clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE"); -} - -u64 clks_syscall_dispatch(void *frame_ptr) { - struct clks_syscall_frame *frame = (struct clks_syscall_frame *)frame_ptr; - u64 id; - - if (clks_syscall_ready == CLKS_FALSE || frame == CLKS_NULL) { - return (u64)-1; - } - - clks_memcpy(&clks_syscall_last_frame, frame, sizeof(clks_syscall_last_frame)); - clks_syscall_last_frame_valid = CLKS_TRUE; - - id = frame->rax; - clks_syscall_stats_record(id); - clks_syscall_trace_user_program(id); - - if (clks_syscall_usc_check(id, frame->rbx, frame->rcx, frame->rdx) == CLKS_FALSE) { - return (u64)-1; - } - - /* Giant switch, yeah. Ugly, explicit, and easy to grep at 3 AM. */ - switch (id) { - case CLKS_SYSCALL_LOG_WRITE: - return clks_syscall_log_write(frame->rbx, frame->rcx); - case CLKS_SYSCALL_TIMER_TICKS: - return clks_interrupts_timer_ticks(); - case CLKS_SYSCALL_TASK_COUNT: { - struct clks_scheduler_stats stats = clks_scheduler_get_stats(); - return stats.task_count; - } - case CLKS_SYSCALL_CURRENT_TASK_ID: { - struct clks_scheduler_stats stats = clks_scheduler_get_stats(); - return stats.current_task_id; - } - case CLKS_SYSCALL_SERVICE_COUNT: - return clks_service_count(); - case CLKS_SYSCALL_SERVICE_READY_COUNT: - return clks_service_ready_count(); - case CLKS_SYSCALL_CONTEXT_SWITCHES: { - struct clks_scheduler_stats stats = clks_scheduler_get_stats(); - return stats.context_switch_count; - } - case CLKS_SYSCALL_KELF_COUNT: - return clks_kelf_count(); - case CLKS_SYSCALL_KELF_RUNS: - return clks_kelf_total_runs(); - case CLKS_SYSCALL_FS_NODE_COUNT: - return clks_fs_node_count(); - case CLKS_SYSCALL_FS_CHILD_COUNT: - return clks_syscall_fs_child_count(frame->rbx); - case CLKS_SYSCALL_FS_GET_CHILD_NAME: - return clks_syscall_fs_get_child_name(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_FS_READ: - return clks_syscall_fs_read(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_EXEC_PATH: - return clks_syscall_exec_path(frame->rbx); - case CLKS_SYSCALL_EXEC_PATHV: - return clks_syscall_exec_pathv(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_EXEC_PATHV_IO: - return clks_syscall_exec_pathv_io(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_EXEC_REQUESTS: - return clks_exec_request_count(); - case CLKS_SYSCALL_EXEC_SUCCESS: - return clks_exec_success_count(); - case CLKS_SYSCALL_USER_SHELL_READY: - return (clks_userland_shell_ready() == CLKS_TRUE) ? 1ULL : 0ULL; - case CLKS_SYSCALL_USER_EXEC_REQUESTED: - return (clks_userland_shell_exec_requested() == CLKS_TRUE) ? 1ULL : 0ULL; - case CLKS_SYSCALL_USER_LAUNCH_TRIES: - return clks_userland_launch_attempts(); - case CLKS_SYSCALL_USER_LAUNCH_OK: - return clks_userland_launch_success(); - case CLKS_SYSCALL_USER_LAUNCH_FAIL: - return clks_userland_launch_failures(); - case CLKS_SYSCALL_TTY_COUNT: - return (u64)clks_tty_count(); - case CLKS_SYSCALL_TTY_ACTIVE: - return (u64)clks_tty_active(); - case CLKS_SYSCALL_TTY_SWITCH: - clks_tty_switch((u32)frame->rbx); - return (u64)clks_tty_active(); - case CLKS_SYSCALL_TTY_WRITE: - return clks_syscall_tty_write(frame->rbx, frame->rcx); - case CLKS_SYSCALL_TTY_WRITE_CHAR: - return clks_syscall_tty_write_char(frame->rbx); - case CLKS_SYSCALL_KBD_GET_CHAR: - return clks_syscall_kbd_get_char(); - case CLKS_SYSCALL_FS_STAT_TYPE: - return clks_syscall_fs_stat_type(frame->rbx); - case CLKS_SYSCALL_FS_STAT_SIZE: - return clks_syscall_fs_stat_size(frame->rbx); - case CLKS_SYSCALL_FS_MKDIR: - return clks_syscall_fs_mkdir(frame->rbx); - case CLKS_SYSCALL_FS_WRITE: - return clks_syscall_fs_write(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_FS_APPEND: - return clks_syscall_fs_append(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_FS_REMOVE: - return clks_syscall_fs_remove(frame->rbx); - case CLKS_SYSCALL_LOG_JOURNAL_COUNT: - return clks_syscall_log_journal_count(); - case CLKS_SYSCALL_LOG_JOURNAL_READ: - return clks_syscall_log_journal_read(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_KBD_BUFFERED: - return clks_keyboard_buffered_count(); - case CLKS_SYSCALL_KBD_PUSHED: - return clks_keyboard_push_count(); - case CLKS_SYSCALL_KBD_POPPED: - return clks_keyboard_pop_count(); - case CLKS_SYSCALL_KBD_DROPPED: - return clks_keyboard_drop_count(); - case CLKS_SYSCALL_KBD_HOTKEY_SWITCHES: - return clks_keyboard_hotkey_switch_count(); - case CLKS_SYSCALL_GETPID: - return clks_syscall_getpid(); - case CLKS_SYSCALL_SPAWN_PATH: - return clks_syscall_spawn_path(frame->rbx); - case CLKS_SYSCALL_SPAWN_PATHV: - return clks_syscall_spawn_pathv(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_WAITPID: - return clks_syscall_waitpid(frame->rbx, frame->rcx); - case CLKS_SYSCALL_PROC_ARGC: - return clks_syscall_proc_argc(); - case CLKS_SYSCALL_PROC_ARGV: - return clks_syscall_proc_argv(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_PROC_ENVC: - return clks_syscall_proc_envc(); - case CLKS_SYSCALL_PROC_ENV: - return clks_syscall_proc_env(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_PROC_LAST_SIGNAL: - return clks_syscall_proc_last_signal(); - case CLKS_SYSCALL_PROC_FAULT_VECTOR: - return clks_syscall_proc_fault_vector(); - case CLKS_SYSCALL_PROC_FAULT_ERROR: - return clks_syscall_proc_fault_error(); - case CLKS_SYSCALL_PROC_FAULT_RIP: - return clks_syscall_proc_fault_rip(); - case CLKS_SYSCALL_PROC_COUNT: - return clks_syscall_proc_count(); - case CLKS_SYSCALL_PROC_PID_AT: - return clks_syscall_proc_pid_at(frame->rbx, frame->rcx); - case CLKS_SYSCALL_PROC_SNAPSHOT: - return clks_syscall_proc_snapshot(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_PROC_KILL: - return clks_syscall_proc_kill(frame->rbx, frame->rcx); - case CLKS_SYSCALL_EXIT: - return clks_syscall_exit(frame->rbx); - case CLKS_SYSCALL_SLEEP_TICKS: - return clks_syscall_sleep_ticks(frame->rbx); - case CLKS_SYSCALL_YIELD: - return clks_syscall_yield(); - case CLKS_SYSCALL_SHUTDOWN: - return clks_syscall_shutdown(); - case CLKS_SYSCALL_RESTART: - return clks_syscall_restart(); - case CLKS_SYSCALL_AUDIO_AVAILABLE: - return clks_syscall_audio_available(); - case CLKS_SYSCALL_AUDIO_PLAY_TONE: - return clks_syscall_audio_play_tone(frame->rbx, frame->rcx); - case CLKS_SYSCALL_AUDIO_STOP: - return clks_syscall_audio_stop(); - case CLKS_SYSCALL_KDBG_SYM: - return clks_syscall_kdbg_sym(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_KDBG_BT: - return clks_syscall_kdbg_bt(frame->rbx); - case CLKS_SYSCALL_KDBG_REGS: - return clks_syscall_kdbg_regs(frame->rbx, frame->rcx); - case CLKS_SYSCALL_STATS_TOTAL: - return clks_syscall_stats_total_count(); - case CLKS_SYSCALL_STATS_ID_COUNT: - return clks_syscall_stats_id(frame->rbx); - case CLKS_SYSCALL_STATS_RECENT_WINDOW: - return clks_syscall_stats_recent_window(); - case CLKS_SYSCALL_STATS_RECENT_ID: - return clks_syscall_stats_recent_id(frame->rbx); - case CLKS_SYSCALL_FD_OPEN: - return clks_syscall_fd_open(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_FD_READ: - return clks_syscall_fd_read(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_FD_WRITE: - return clks_syscall_fd_write(frame->rbx, frame->rcx, frame->rdx); - case CLKS_SYSCALL_FD_CLOSE: - return clks_syscall_fd_close(frame->rbx); - case CLKS_SYSCALL_FD_DUP: - return clks_syscall_fd_dup(frame->rbx); - case CLKS_SYSCALL_DL_OPEN: - return clks_syscall_dl_open(frame->rbx); - case CLKS_SYSCALL_DL_CLOSE: - return clks_syscall_dl_close(frame->rbx); - case CLKS_SYSCALL_DL_SYM: - return clks_syscall_dl_sym(frame->rbx, frame->rcx); - case CLKS_SYSCALL_FB_INFO: - return clks_syscall_fb_info(frame->rbx); - case CLKS_SYSCALL_FB_BLIT: - return clks_syscall_fb_blit(frame->rbx); - case CLKS_SYSCALL_FB_CLEAR: - return clks_syscall_fb_clear(frame->rbx); - case CLKS_SYSCALL_KERNEL_VERSION: - return clks_syscall_kernel_version(frame->rbx, frame->rcx); - case CLKS_SYSCALL_DISK_PRESENT: - return clks_syscall_disk_present(); - case CLKS_SYSCALL_DISK_SIZE_BYTES: - return clks_syscall_disk_size_bytes(); - case CLKS_SYSCALL_DISK_SECTOR_COUNT: - return clks_syscall_disk_sector_count(); - case CLKS_SYSCALL_DISK_FORMATTED: - return clks_syscall_disk_formatted(); - case CLKS_SYSCALL_DISK_FORMAT_FAT32: - return clks_syscall_disk_format_fat32(frame->rbx); - case CLKS_SYSCALL_DISK_MOUNT: - return clks_syscall_disk_mount(frame->rbx); - case CLKS_SYSCALL_DISK_MOUNTED: - return clks_syscall_disk_mounted(); - case CLKS_SYSCALL_DISK_MOUNT_PATH: - return clks_syscall_disk_mount_path(frame->rbx, frame->rcx); - case CLKS_SYSCALL_DISK_READ_SECTOR: - return clks_syscall_disk_read_sector(frame->rbx, frame->rcx); - case CLKS_SYSCALL_DISK_WRITE_SECTOR: - return clks_syscall_disk_write_sector(frame->rbx, frame->rcx); - default: - return (u64)-1; - } -} - -u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2) { - u64 ret; - - __asm__ volatile("int $0x80" : "=a"(ret) : "a"(id), "b"(arg0), "c"(arg1), "d"(arg2) : "memory"); - - return ret; -} diff --git a/clks/kernel/runtime/userland.c b/clks/kernel/runtime/userland.c deleted file mode 100644 index 6869b27..0000000 --- a/clks/kernel/runtime/userland.c +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define CLKS_USERLAND_RETRY_INTERVAL 500ULL - -#ifndef CLKS_CFG_USERLAND_AUTO_EXEC -#define CLKS_CFG_USERLAND_AUTO_EXEC 1 -#endif - -#ifndef CLKS_CFG_USER_INIT_SCRIPT_PROBE -#define CLKS_CFG_USER_INIT_SCRIPT_PROBE 1 -#endif - -#ifndef CLKS_CFG_USER_SYSTEM_APP_PROBE -#define CLKS_CFG_USER_SYSTEM_APP_PROBE 1 -#endif - -static clks_bool clks_user_shell_ready = CLKS_FALSE; -static clks_bool clks_user_shell_exec_requested_flag = CLKS_FALSE; -static clks_bool clks_user_shell_exec_enabled = CLKS_FALSE; -static u64 clks_user_launch_attempt_count = 0ULL; -static u64 clks_user_launch_success_count = 0ULL; -static u64 clks_user_launch_fail_count = 0ULL; -static u64 clks_user_last_try_tick = 0ULL; -static clks_bool clks_user_first_try_pending = CLKS_FALSE; - -static clks_bool clks_userland_probe_elf(const char *path, const char *tag) { - const void *image; - u64 size = 0ULL; - struct clks_elf64_info info; - - image = clks_fs_read_all(path, &size); - - if (image == CLKS_NULL) { - clks_log(CLKS_LOG_ERROR, "USER", "ELF FILE MISSING"); - clks_log(CLKS_LOG_ERROR, "USER", path); - return CLKS_FALSE; - } - - if (clks_elf64_inspect(image, size, &info) == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "USER", "ELF INSPECT FAILED"); - clks_log(CLKS_LOG_ERROR, "USER", path); - return CLKS_FALSE; - } - - clks_log(CLKS_LOG_INFO, "USER", tag); - clks_log_hex(CLKS_LOG_INFO, "USER", "ELF_SIZE", size); - clks_log_hex(CLKS_LOG_INFO, "USER", "ENTRY", info.entry); - return CLKS_TRUE; -} - -#if CLKS_CFG_USER_INIT_SCRIPT_PROBE -static void clks_userland_probe_init_script(void) { - const void *data; - u64 size = 0ULL; - - data = clks_fs_read_all("/shell/init.cmd", &size); - - if (data == CLKS_NULL || size == 0ULL) { - clks_log(CLKS_LOG_WARN, "USER", "INIT SCRIPT NOT FOUND /SHELL/INIT.CMD"); - return; - } - - clks_log(CLKS_LOG_INFO, "USER", "INIT SCRIPT READY /SHELL/INIT.CMD"); - clks_log_hex(CLKS_LOG_INFO, "USER", "INIT_SCRIPT_SIZE", size); -} -#endif - -static clks_bool clks_userland_request_shell_exec(void) { - u64 status = (u64)-1; - - if (clks_user_shell_ready == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_user_launch_attempt_count++; - - if (clks_exec_run_path("/shell/shell.elf", &status) == CLKS_TRUE && status == 0ULL) { - clks_user_shell_exec_requested_flag = CLKS_TRUE; - clks_user_launch_success_count++; - - clks_log(CLKS_LOG_INFO, "USER", "SHELL EXEC REQUESTED"); - clks_log_hex(CLKS_LOG_INFO, "USER", "SHELL_STATUS", status); - return CLKS_TRUE; - } - - clks_user_launch_fail_count++; - clks_log(CLKS_LOG_WARN, "USER", "SHELL EXEC REQUEST FAILED"); - return CLKS_FALSE; -} - -clks_bool clks_userland_init(void) { - clks_log(CLKS_LOG_INFO, "USER", "USERLAND FRAMEWORK ONLINE"); - - clks_user_shell_ready = CLKS_FALSE; - clks_user_shell_exec_requested_flag = CLKS_FALSE; - clks_user_shell_exec_enabled = (CLKS_CFG_USERLAND_AUTO_EXEC != 0) ? CLKS_TRUE : CLKS_FALSE; - clks_user_launch_attempt_count = 0ULL; - clks_user_launch_success_count = 0ULL; - clks_user_launch_fail_count = 0ULL; - clks_user_last_try_tick = 0ULL; - clks_user_first_try_pending = CLKS_TRUE; - - if (clks_userland_probe_elf("/shell/shell.elf", "SHELL ELF READY") == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_user_shell_ready = CLKS_TRUE; - clks_log(CLKS_LOG_INFO, "USER", "SHELL COMMAND ABI READY"); -#if CLKS_CFG_USER_INIT_SCRIPT_PROBE - clks_userland_probe_init_script(); -#else - clks_log(CLKS_LOG_WARN, "USER", "INIT SCRIPT PROBE DISABLED BY MENUCONFIG"); -#endif - -#if CLKS_CFG_USER_SYSTEM_APP_PROBE - if (clks_userland_probe_elf("/system/elfrunner.elf", "ELFRUNNER ELF READY") == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_userland_probe_elf("/system/memc.elf", "MEMC ELF READY") == CLKS_FALSE) { - return CLKS_FALSE; - } -#else - clks_log(CLKS_LOG_WARN, "USER", "SYSTEM APP PROBE DISABLED BY MENUCONFIG"); -#endif - - if (clks_user_shell_exec_enabled == CLKS_TRUE) { - clks_log(CLKS_LOG_INFO, "USER", "USER SHELL AUTO EXEC ENABLED"); - } else { - clks_log(CLKS_LOG_WARN, "USER", "USER SHELL AUTO EXEC DISABLED BY MENUCONFIG"); - } - return CLKS_TRUE; -} - -void clks_userland_tick(u64 tick) { - if (clks_user_shell_exec_enabled == CLKS_FALSE || clks_user_shell_ready == CLKS_FALSE || - clks_user_shell_exec_requested_flag == CLKS_TRUE) { - return; - } - - if (clks_user_first_try_pending == CLKS_TRUE) { - clks_user_first_try_pending = CLKS_FALSE; - clks_user_last_try_tick = tick; - (void)clks_userland_request_shell_exec(); - return; - } - - if (tick - clks_user_last_try_tick < CLKS_USERLAND_RETRY_INTERVAL) { - return; - } - - clks_user_last_try_tick = tick; - (void)clks_userland_request_shell_exec(); -} - -clks_bool clks_userland_shell_ready(void) { - return clks_user_shell_ready; -} - -clks_bool clks_userland_shell_exec_requested(void) { - return clks_user_shell_exec_requested_flag; -} - -clks_bool clks_userland_shell_auto_exec_enabled(void) { - return clks_user_shell_exec_enabled; -} - -u64 clks_userland_launch_attempts(void) { - return clks_user_launch_attempt_count; -} - -u64 clks_userland_launch_success(void) { - return clks_user_launch_success_count; -} - -u64 clks_userland_launch_failures(void) { - return clks_user_launch_fail_count; -} diff --git a/clks/kernel/storage/disk.c b/clks/kernel/storage/disk.c deleted file mode 100644 index 7f83284..0000000 --- a/clks/kernel/storage/disk.c +++ /dev/null @@ -1,1856 +0,0 @@ -#include -#include -#include -#include -#include - -#define CLKS_DISK_MIN_BYTES (4ULL * 1024ULL * 1024ULL) -#define CLKS_DISK_CACHE_MAX_BYTES (8ULL * 1024ULL * 1024ULL) - -#define CLKS_DISK_MAX_NODES 256U -#define CLKS_DISK_NODE_FLAG_HEAP_DATA 0x0001U - -#define CLKS_DISK_META_OFFSET 0x00010000ULL -#define CLKS_DISK_META_SIZE 0x00020000ULL -#define CLKS_DISK_META_HEADER_SIZE 32U -#define CLKS_DISK_META_ENTRY_SIZE 224U -#define CLKS_DISK_DATA_OFFSET (CLKS_DISK_META_OFFSET + CLKS_DISK_META_SIZE) - -#define CLKS_DISK_META_MAGIC "CLDSKFS1" -#define CLKS_DISK_META_VERSION 1U - -#define CLKS_DISK_FAT32_BOOT_SIG_OFFSET 510U -#define CLKS_DISK_FAT32_TYPE_OFFSET 82U -#define CLKS_DISK_FAT32_TYPE_LEN 5U - -#if defined(CLKS_ARCH_X86_64) -#define CLKS_DISK_ATA_IO_BASE 0x1F0U -#define CLKS_DISK_ATA_CTRL_BASE 0x3F6U -#define CLKS_DISK_ATA_REG_DATA (CLKS_DISK_ATA_IO_BASE + 0U) -#define CLKS_DISK_ATA_REG_SECTOR_COUNT (CLKS_DISK_ATA_IO_BASE + 2U) -#define CLKS_DISK_ATA_REG_LBA_LOW (CLKS_DISK_ATA_IO_BASE + 3U) -#define CLKS_DISK_ATA_REG_LBA_MID (CLKS_DISK_ATA_IO_BASE + 4U) -#define CLKS_DISK_ATA_REG_LBA_HIGH (CLKS_DISK_ATA_IO_BASE + 5U) -#define CLKS_DISK_ATA_REG_DRIVE (CLKS_DISK_ATA_IO_BASE + 6U) -#define CLKS_DISK_ATA_REG_STATUS (CLKS_DISK_ATA_IO_BASE + 7U) -#define CLKS_DISK_ATA_REG_COMMAND (CLKS_DISK_ATA_IO_BASE + 7U) -#define CLKS_DISK_ATA_REG_ALT_STATUS (CLKS_DISK_ATA_CTRL_BASE + 0U) - -#define CLKS_DISK_ATA_STATUS_ERR 0x01U -#define CLKS_DISK_ATA_STATUS_DRQ 0x08U -#define CLKS_DISK_ATA_STATUS_DF 0x20U -#define CLKS_DISK_ATA_STATUS_DRDY 0x40U -#define CLKS_DISK_ATA_STATUS_BSY 0x80U - -#define CLKS_DISK_ATA_CMD_READ_SECTORS 0x20U -#define CLKS_DISK_ATA_CMD_WRITE_SECTORS 0x30U -#define CLKS_DISK_ATA_CMD_CACHE_FLUSH 0xE7U -#define CLKS_DISK_ATA_CMD_IDENTIFY 0xECU -#endif - -struct clks_disk_node { - clks_bool used; - u8 type; - u16 parent; - u16 flags; - const void *data; - u64 size; - char path[CLKS_DISK_PATH_MAX]; -}; - -static u8 *clks_disk_bytes = CLKS_NULL; -static u64 clks_disk_bytes_len = 0ULL; -static u64 clks_disk_sector_total = 0ULL; -static clks_bool clks_disk_ready = CLKS_FALSE; -static clks_bool clks_disk_formatted = CLKS_FALSE; -static clks_bool clks_disk_mounted = CLKS_FALSE; -static clks_bool clks_disk_hw_backed = CLKS_FALSE; -static char clks_disk_mount_path_buf[CLKS_DISK_PATH_MAX]; -static const u8 clks_disk_empty_file_data[1] = {0U}; - -static struct clks_disk_node clks_disk_nodes[CLKS_DISK_MAX_NODES]; -static u16 clks_disk_nodes_used = 0U; - -static u16 clks_disk_read_u16(const u8 *ptr) { - return (u16)((u16)ptr[0] | ((u16)ptr[1] << 8)); -} - -static u32 clks_disk_read_u32(const u8 *ptr) { - return (u32)((u32)ptr[0] | ((u32)ptr[1] << 8) | ((u32)ptr[2] << 16) | ((u32)ptr[3] << 24)); -} - -static u64 clks_disk_read_u64(const u8 *ptr) { - u64 value = 0ULL; - u32 i; - - for (i = 0U; i < 8U; i++) { - value |= ((u64)ptr[i]) << (u64)(i * 8U); - } - - return value; -} - -static void clks_disk_write_u16(u8 *ptr, u16 value) { - ptr[0] = (u8)(value & 0xFFU); - ptr[1] = (u8)((value >> 8) & 0xFFU); -} - -static void clks_disk_write_u32(u8 *ptr, u32 value) { - ptr[0] = (u8)(value & 0xFFU); - ptr[1] = (u8)((value >> 8) & 0xFFU); - ptr[2] = (u8)((value >> 16) & 0xFFU); - ptr[3] = (u8)((value >> 24) & 0xFFU); -} - -static void clks_disk_write_u64(u8 *ptr, u64 value) { - u32 i; - - for (i = 0U; i < 8U; i++) { - ptr[i] = (u8)((value >> (u64)(i * 8U)) & 0xFFULL); - } -} - -#if defined(CLKS_ARCH_X86_64) -static inline void clks_disk_ata_outb(u16 port, u8 value) { - __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); -} - -static inline u8 clks_disk_ata_inb(u16 port) { - u8 value; - __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); - return value; -} - -static inline void clks_disk_ata_outw(u16 port, u16 value) { - __asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port)); -} - -static inline u16 clks_disk_ata_inw(u16 port) { - u16 value; - __asm__ volatile("inw %1, %0" : "=a"(value) : "Nd"(port)); - return value; -} - -static void clks_disk_ata_delay_400ns(void) { - (void)clks_disk_ata_inb(CLKS_DISK_ATA_REG_ALT_STATUS); - (void)clks_disk_ata_inb(CLKS_DISK_ATA_REG_ALT_STATUS); - (void)clks_disk_ata_inb(CLKS_DISK_ATA_REG_ALT_STATUS); - (void)clks_disk_ata_inb(CLKS_DISK_ATA_REG_ALT_STATUS); -} - -static clks_bool clks_disk_ata_wait_not_busy(void) { - u32 i; - - for (i = 0U; i < 1000000U; i++) { - u8 status = clks_disk_ata_inb(CLKS_DISK_ATA_REG_STATUS); - - if ((status & CLKS_DISK_ATA_STATUS_BSY) == 0U) { - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static clks_bool clks_disk_ata_wait_drq_ready(void) { - u32 i; - - for (i = 0U; i < 1000000U; i++) { - u8 status = clks_disk_ata_inb(CLKS_DISK_ATA_REG_STATUS); - - if ((status & CLKS_DISK_ATA_STATUS_BSY) != 0U) { - continue; - } - - if ((status & (CLKS_DISK_ATA_STATUS_ERR | CLKS_DISK_ATA_STATUS_DF)) != 0U) { - return CLKS_FALSE; - } - - if ((status & CLKS_DISK_ATA_STATUS_DRQ) != 0U) { - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static clks_bool clks_disk_ata_wait_ready_no_drq(void) { - u32 i; - - for (i = 0U; i < 1000000U; i++) { - u8 status = clks_disk_ata_inb(CLKS_DISK_ATA_REG_STATUS); - - if ((status & CLKS_DISK_ATA_STATUS_BSY) != 0U) { - continue; - } - - if ((status & (CLKS_DISK_ATA_STATUS_ERR | CLKS_DISK_ATA_STATUS_DF)) != 0U) { - return CLKS_FALSE; - } - - if ((status & CLKS_DISK_ATA_STATUS_DRDY) != 0U) { - return CLKS_TRUE; - } - } - - return CLKS_FALSE; -} - -static clks_bool clks_disk_ata_identify(u64 *out_sector_total) { - u16 identify_words[256]; - u32 i; - u64 sector_total; - u8 status; - - if (out_sector_total == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_ata_wait_not_busy() == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_disk_ata_outb(CLKS_DISK_ATA_REG_DRIVE, 0xA0U); - clks_disk_ata_delay_400ns(); - - clks_disk_ata_outb(CLKS_DISK_ATA_REG_SECTOR_COUNT, 0U); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_LOW, 0U); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_MID, 0U); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_HIGH, 0U); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_COMMAND, CLKS_DISK_ATA_CMD_IDENTIFY); - - status = clks_disk_ata_inb(CLKS_DISK_ATA_REG_STATUS); - if (status == 0U) { - return CLKS_FALSE; - } - - if (clks_disk_ata_wait_drq_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - for (i = 0U; i < 256U; i++) { - identify_words[i] = clks_disk_ata_inw(CLKS_DISK_ATA_REG_DATA); - } - - sector_total = (u64)identify_words[60] | ((u64)identify_words[61] << 16U); - if (sector_total == 0ULL) { - return CLKS_FALSE; - } - - *out_sector_total = sector_total; - return CLKS_TRUE; -} - -static clks_bool clks_disk_ata_read_sector_hw(u64 lba, void *out_sector) { - u8 *out = (u8 *)out_sector; - u32 i; - u8 status; - - if (out_sector == CLKS_NULL || lba > 0x0FFFFFFFULL) { - return CLKS_FALSE; - } - - if (clks_disk_ata_wait_not_busy() == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_disk_ata_outb(CLKS_DISK_ATA_REG_DRIVE, (u8)(0xE0U | ((u8)((lba >> 24U) & 0x0FU)))); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_SECTOR_COUNT, 1U); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_LOW, (u8)(lba & 0xFFULL)); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_MID, (u8)((lba >> 8U) & 0xFFULL)); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_HIGH, (u8)((lba >> 16U) & 0xFFULL)); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_COMMAND, CLKS_DISK_ATA_CMD_READ_SECTORS); - - if (clks_disk_ata_wait_drq_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - for (i = 0U; i < 256U; i++) { - u16 word = clks_disk_ata_inw(CLKS_DISK_ATA_REG_DATA); - out[i * 2U] = (u8)(word & 0x00FFU); - out[i * 2U + 1U] = (u8)((word >> 8U) & 0x00FFU); - } - - clks_disk_ata_delay_400ns(); - status = clks_disk_ata_inb(CLKS_DISK_ATA_REG_STATUS); - if ((status & (CLKS_DISK_ATA_STATUS_ERR | CLKS_DISK_ATA_STATUS_DF)) != 0U) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_ata_write_sector_hw(u64 lba, const void *sector_data) { - const u8 *src = (const u8 *)sector_data; - u32 i; - - if (sector_data == CLKS_NULL || lba > 0x0FFFFFFFULL) { - return CLKS_FALSE; - } - - if (clks_disk_ata_wait_not_busy() == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_disk_ata_outb(CLKS_DISK_ATA_REG_DRIVE, (u8)(0xE0U | ((u8)((lba >> 24U) & 0x0FU)))); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_SECTOR_COUNT, 1U); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_LOW, (u8)(lba & 0xFFULL)); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_MID, (u8)((lba >> 8U) & 0xFFULL)); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_LBA_HIGH, (u8)((lba >> 16U) & 0xFFULL)); - clks_disk_ata_outb(CLKS_DISK_ATA_REG_COMMAND, CLKS_DISK_ATA_CMD_WRITE_SECTORS); - - if (clks_disk_ata_wait_drq_ready() == CLKS_FALSE) { - return CLKS_FALSE; - } - - for (i = 0U; i < 256U; i++) { - u16 word = (u16)src[i * 2U] | ((u16)src[i * 2U + 1U] << 8U); - clks_disk_ata_outw(CLKS_DISK_ATA_REG_DATA, word); - } - - clks_disk_ata_delay_400ns(); - if (clks_disk_ata_wait_ready_no_drq() == CLKS_FALSE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_ata_cache_flush_hw(void) { - if (clks_disk_ata_wait_not_busy() == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_disk_ata_outb(CLKS_DISK_ATA_REG_COMMAND, CLKS_DISK_ATA_CMD_CACHE_FLUSH); - return clks_disk_ata_wait_ready_no_drq(); -} -#else -static clks_bool clks_disk_ata_identify(u64 *out_sector_total) { - (void)out_sector_total; - return CLKS_FALSE; -} - -static clks_bool clks_disk_ata_read_sector_hw(u64 lba, void *out_sector) { - (void)lba; - (void)out_sector; - return CLKS_FALSE; -} - -static clks_bool clks_disk_ata_write_sector_hw(u64 lba, const void *sector_data) { - (void)lba; - (void)sector_data; - return CLKS_FALSE; -} - -static clks_bool clks_disk_ata_cache_flush_hw(void) { - return CLKS_FALSE; -} -#endif - -static clks_bool clks_disk_sync_bytes_to_hw(u64 used_bytes) { - u64 sectors_to_sync; - u64 lba; - - if (clks_disk_hw_backed == CLKS_FALSE) { - return CLKS_TRUE; - } - - if (clks_disk_bytes == CLKS_NULL || clks_disk_sector_total == 0ULL) { - return CLKS_FALSE; - } - - if (used_bytes == 0ULL) { - return CLKS_TRUE; - } - - if (used_bytes > clks_disk_bytes_len) { - used_bytes = clks_disk_bytes_len; - } - - sectors_to_sync = (used_bytes + (CLKS_DISK_SECTOR_SIZE - 1ULL)) / CLKS_DISK_SECTOR_SIZE; - if (sectors_to_sync > clks_disk_sector_total) { - sectors_to_sync = clks_disk_sector_total; - } - - for (lba = 0ULL; lba < sectors_to_sync; lba++) { - const u8 *sector_ptr = clks_disk_bytes + (usize)(lba * CLKS_DISK_SECTOR_SIZE); - if (clks_disk_ata_write_sector_hw(lba, sector_ptr) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - if (clks_disk_ata_cache_flush_hw() == CLKS_FALSE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_bytes_equal(const u8 *left, const u8 *right, usize count) { - usize i; - - if (left == CLKS_NULL || right == CLKS_NULL) { - return CLKS_FALSE; - } - - for (i = 0U; i < count; i++) { - if (left[i] != right[i]) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_text_prefix_equals(const char *text, const char *prefix, usize prefix_len) { - usize i; - - if (text == CLKS_NULL || prefix == CLKS_NULL) { - return CLKS_FALSE; - } - - for (i = 0U; i < prefix_len; i++) { - if (text[i] != prefix[i]) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -static void clks_disk_copy_text(char *dst, usize dst_size, const char *src) { - usize i = 0U; - - if (dst == CLKS_NULL || dst_size == 0U) { - return; - } - - if (src == CLKS_NULL) { - dst[0] = '\0'; - return; - } - - while (src[i] != '\0' && i + 1U < dst_size) { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; -} - -static clks_bool clks_disk_normalize_absolute_path(const char *path, char *out_path, usize out_size) { - usize in_pos = 0U; - usize out_pos = 0U; - - if (path == CLKS_NULL || out_path == CLKS_NULL || out_size < 2U) { - return CLKS_FALSE; - } - - if (path[0] != '/') { - return CLKS_FALSE; - } - - out_path[out_pos++] = '/'; - - while (path[in_pos] == '/') { - in_pos++; - } - - while (path[in_pos] != '\0') { - usize comp_start = in_pos; - usize comp_len; - - while (path[in_pos] != '\0' && path[in_pos] != '/') { - in_pos++; - } - - comp_len = in_pos - comp_start; - - if (comp_len == 0U) { - while (path[in_pos] == '/') { - in_pos++; - } - continue; - } - - if (comp_len == 1U && path[comp_start] == '.') { - while (path[in_pos] == '/') { - in_pos++; - } - continue; - } - - if (comp_len == 2U && path[comp_start] == '.' && path[comp_start + 1U] == '.') { - return CLKS_FALSE; - } - - if (out_pos > 1U) { - if (out_pos + 1U >= out_size) { - return CLKS_FALSE; - } - out_path[out_pos++] = '/'; - } - - if (out_pos + comp_len >= out_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_path + out_pos, path + comp_start, comp_len); - out_pos += comp_len; - - while (path[in_pos] == '/') { - in_pos++; - } - } - - out_path[out_pos] = '\0'; - return CLKS_TRUE; -} - -static clks_bool clks_disk_normalize_relative_path(const char *path, char *out_path, usize out_size) { - usize in_pos = 0U; - usize out_pos = 0U; - - if (path == CLKS_NULL || out_path == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - if (path[0] == '/') { - return CLKS_FALSE; - } - - while (path[in_pos] == '/') { - in_pos++; - } - - while (path[in_pos] != '\0') { - usize comp_start = in_pos; - usize comp_len; - - while (path[in_pos] != '\0' && path[in_pos] != '/') { - in_pos++; - } - - comp_len = in_pos - comp_start; - - if (comp_len == 0U) { - while (path[in_pos] == '/') { - in_pos++; - } - continue; - } - - if (comp_len == 1U && path[comp_start] == '.') { - while (path[in_pos] == '/') { - in_pos++; - } - continue; - } - - if (comp_len == 2U && path[comp_start] == '.' && path[comp_start + 1U] == '.') { - return CLKS_FALSE; - } - - if (out_pos != 0U) { - if (out_pos + 1U >= out_size) { - return CLKS_FALSE; - } - out_path[out_pos++] = '/'; - } - - if (out_pos + comp_len >= out_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_path + out_pos, path + comp_start, comp_len); - out_pos += comp_len; - - while (path[in_pos] == '/') { - in_pos++; - } - } - - out_path[out_pos] = '\0'; - return CLKS_TRUE; -} - -static clks_bool clks_disk_path_to_relative(const char *path, char *out_relative, usize out_size) { - char normalized[CLKS_DISK_PATH_MAX]; - usize mount_len; - - if (out_relative == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - if (clks_disk_mounted == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_normalize_absolute_path(path, normalized, sizeof(normalized)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - mount_len = clks_strlen(clks_disk_mount_path_buf); - - if (clks_strcmp(normalized, clks_disk_mount_path_buf) == 0) { - out_relative[0] = '\0'; - return CLKS_TRUE; - } - - if (mount_len >= clks_strlen(normalized)) { - return CLKS_FALSE; - } - - if (clks_disk_text_prefix_equals(normalized, clks_disk_mount_path_buf, mount_len) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (normalized[mount_len] != '/') { - return CLKS_FALSE; - } - - return clks_disk_normalize_relative_path(normalized + mount_len + 1U, out_relative, out_size); -} - -static const char *clks_disk_basename(const char *relative_path) { - usize len; - usize i; - - if (relative_path == CLKS_NULL) { - return ""; - } - - len = clks_strlen(relative_path); - - if (len == 0U) { - return ""; - } - - for (i = len; i != 0U; i--) { - if (relative_path[i - 1U] == '/') { - return &relative_path[i]; - } - } - - return relative_path; -} - -static clks_bool clks_disk_split_parent(const char *relative_path, char *parent_out, usize out_size) { - usize len; - usize i; - - if (relative_path == CLKS_NULL || parent_out == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - len = clks_strlen(relative_path); - - if (len == 0U) { - parent_out[0] = '\0'; - return CLKS_TRUE; - } - - for (i = len; i != 0U; i--) { - if (relative_path[i - 1U] == '/') { - usize parent_len = i - 1U; - - if (parent_len >= out_size) { - return CLKS_FALSE; - } - - clks_memcpy(parent_out, relative_path, parent_len); - parent_out[parent_len] = '\0'; - return CLKS_TRUE; - } - } - - parent_out[0] = '\0'; - return CLKS_TRUE; -} - -static clks_bool clks_disk_node_has_heap_data(u16 index) { - return ((clks_disk_nodes[index].flags & CLKS_DISK_NODE_FLAG_HEAP_DATA) != 0U) ? CLKS_TRUE : CLKS_FALSE; -} - -static void clks_disk_node_set_heap_data(u16 index, clks_bool value) { - if (value == CLKS_TRUE) { - clks_disk_nodes[index].flags |= CLKS_DISK_NODE_FLAG_HEAP_DATA; - } else { - clks_disk_nodes[index].flags &= (u16)(~CLKS_DISK_NODE_FLAG_HEAP_DATA); - } -} - -static void clks_disk_node_release_heap_data(u16 index) { - if (clks_disk_nodes[index].type != (u8)CLKS_DISK_NODE_FILE) { - return; - } - - if (clks_disk_node_has_heap_data(index) == CLKS_TRUE && clks_disk_nodes[index].data != CLKS_NULL) { - clks_kfree((void *)clks_disk_nodes[index].data); - } - - clks_disk_node_set_heap_data(index, CLKS_FALSE); -} - -static void clks_disk_nodes_reset(void) { - u16 i; - - for (i = 0U; i < clks_disk_nodes_used; i++) { - if (clks_disk_nodes[i].used == CLKS_FALSE) { - continue; - } - - clks_disk_node_release_heap_data(i); - } - - clks_memset(clks_disk_nodes, 0, sizeof(clks_disk_nodes)); - clks_disk_nodes_used = 0U; -} - -static i32 clks_disk_find_node_by_relative(const char *relative_path) { - u16 i; - - for (i = 0U; i < clks_disk_nodes_used; i++) { - if (clks_disk_nodes[i].used == CLKS_FALSE) { - continue; - } - - if (clks_strcmp(clks_disk_nodes[i].path, relative_path) == 0) { - return (i32)i; - } - } - - return -1; -} - -static i32 clks_disk_alloc_slot(void) { - u16 i; - - for (i = 0U; i < clks_disk_nodes_used; i++) { - if (clks_disk_nodes[i].used == CLKS_FALSE) { - return (i32)i; - } - } - - if (clks_disk_nodes_used >= CLKS_DISK_MAX_NODES) { - return -1; - } - - clks_disk_nodes_used++; - return (i32)(clks_disk_nodes_used - 1U); -} - -static i32 clks_disk_create_or_update_node(const char *relative_path, u8 type, u16 parent, const void *data, u64 size) { - i32 existing; - i32 slot; - usize path_len; - - if (relative_path == CLKS_NULL) { - return -1; - } - - path_len = clks_strlen(relative_path); - - if (path_len >= CLKS_DISK_PATH_MAX) { - return -1; - } - - existing = clks_disk_find_node_by_relative(relative_path); - - if (existing >= 0) { - struct clks_disk_node *node = &clks_disk_nodes[(u16)existing]; - - if (node->type != type) { - return -1; - } - - node->parent = parent; - - if (type == (u8)CLKS_DISK_NODE_FILE) { - node->data = data; - node->size = size; - node->flags = 0U; - } - - node->used = CLKS_TRUE; - return existing; - } - - slot = clks_disk_alloc_slot(); - - if (slot < 0) { - return -1; - } - - clks_disk_nodes[(u16)slot].used = CLKS_TRUE; - clks_disk_nodes[(u16)slot].type = type; - clks_disk_nodes[(u16)slot].parent = parent; - clks_disk_nodes[(u16)slot].flags = 0U; - clks_disk_nodes[(u16)slot].data = (type == (u8)CLKS_DISK_NODE_FILE) ? data : CLKS_NULL; - clks_disk_nodes[(u16)slot].size = (type == (u8)CLKS_DISK_NODE_FILE) ? size : 0ULL; - clks_memcpy(clks_disk_nodes[(u16)slot].path, relative_path, path_len + 1U); - - return slot; -} - -static clks_bool clks_disk_ensure_root(void) { - if (clks_disk_create_or_update_node("", (u8)CLKS_DISK_NODE_DIR, 0U, CLKS_NULL, 0ULL) != 0) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_ensure_dir_hierarchy(const char *relative_dir_path) { - char prefix[CLKS_DISK_PATH_MAX]; - usize cursor = 0U; - usize i = 0U; - u16 current_parent = 0U; - - prefix[0] = '\0'; - - if (relative_dir_path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (relative_dir_path[0] == '\0') { - return CLKS_TRUE; - } - - while (relative_dir_path[i] != '\0') { - usize comp_start = i; - usize comp_len; - i32 node_index; - - while (relative_dir_path[i] != '\0' && relative_dir_path[i] != '/') { - i++; - } - - comp_len = i - comp_start; - - if (comp_len == 0U) { - return CLKS_FALSE; - } - - if (cursor != 0U) { - if (cursor + 1U >= sizeof(prefix)) { - return CLKS_FALSE; - } - prefix[cursor++] = '/'; - } - - if (cursor + comp_len >= sizeof(prefix)) { - return CLKS_FALSE; - } - - clks_memcpy(prefix + cursor, relative_dir_path + comp_start, comp_len); - cursor += comp_len; - prefix[cursor] = '\0'; - - node_index = clks_disk_find_node_by_relative(prefix); - - if (node_index < 0) { - node_index = - clks_disk_create_or_update_node(prefix, (u8)CLKS_DISK_NODE_DIR, current_parent, CLKS_NULL, 0ULL); - - if (node_index < 0) { - return CLKS_FALSE; - } - } else if (clks_disk_nodes[(u16)node_index].type != (u8)CLKS_DISK_NODE_DIR) { - return CLKS_FALSE; - } - - current_parent = (u16)node_index; - - if (relative_dir_path[i] == '/') { - i++; - } - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_build_file_payload(const void *data, u64 size, const void **out_data, - clks_bool *out_heap_owned) { - void *payload; - - if (out_data == CLKS_NULL || out_heap_owned == CLKS_NULL) { - return CLKS_FALSE; - } - - if (size == 0ULL) { - *out_data = (const void *)clks_disk_empty_file_data; - *out_heap_owned = CLKS_FALSE; - return CLKS_TRUE; - } - - if (data == CLKS_NULL) { - return CLKS_FALSE; - } - - payload = clks_kmalloc((usize)size); - - if (payload == CLKS_NULL) { - return CLKS_FALSE; - } - - clks_memcpy(payload, data, (usize)size); - *out_data = (const void *)payload; - *out_heap_owned = CLKS_TRUE; - return CLKS_TRUE; -} - -static clks_bool clks_disk_meta_is_present(void) { - const u8 *header; - - if (clks_disk_ready == CLKS_FALSE || clks_disk_bytes == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_bytes_len < (CLKS_DISK_META_OFFSET + CLKS_DISK_META_HEADER_SIZE)) { - return CLKS_FALSE; - } - - header = clks_disk_bytes + (usize)CLKS_DISK_META_OFFSET; - - if (clks_disk_bytes_equal(header, (const u8 *)CLKS_DISK_META_MAGIC, 8U) == CLKS_FALSE) { - return CLKS_FALSE; - } - - return (clks_disk_read_u32(header + 8U) == CLKS_DISK_META_VERSION) ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_disk_meta_flush(void) { - u8 *meta_base; - u64 max_entries; - u64 entry_count = 0ULL; - u64 data_cursor = CLKS_DISK_DATA_OFFSET; - u16 i; - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE || clks_disk_bytes == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_bytes_len < CLKS_DISK_DATA_OFFSET) { - return CLKS_FALSE; - } - - meta_base = clks_disk_bytes + (usize)CLKS_DISK_META_OFFSET; - clks_memset(meta_base, 0, (usize)CLKS_DISK_META_SIZE); - - max_entries = (CLKS_DISK_META_SIZE - (u64)CLKS_DISK_META_HEADER_SIZE) / (u64)CLKS_DISK_META_ENTRY_SIZE; - - for (i = 0U; i < clks_disk_nodes_used; i++) { - struct clks_disk_node *node = &clks_disk_nodes[i]; - u8 *entry_ptr; - - if (node->used == CLKS_FALSE || node->path[0] == '\0') { - continue; - } - - if (entry_count >= max_entries) { - return CLKS_FALSE; - } - - entry_ptr = meta_base + CLKS_DISK_META_HEADER_SIZE + (usize)(entry_count * (u64)CLKS_DISK_META_ENTRY_SIZE); - entry_ptr[0] = node->type; - clks_disk_write_u64(entry_ptr + 4U, node->size); - - if (node->type == (u8)CLKS_DISK_NODE_FILE && node->size > 0ULL) { - if (node->data == CLKS_NULL) { - return CLKS_FALSE; - } - - if (data_cursor + node->size < data_cursor || data_cursor + node->size > clks_disk_bytes_len) { - return CLKS_FALSE; - } - - clks_disk_write_u64(entry_ptr + 12U, data_cursor); - clks_memcpy(clks_disk_bytes + (usize)data_cursor, node->data, (usize)node->size); - data_cursor += node->size; - } else { - clks_disk_write_u64(entry_ptr + 12U, 0ULL); - } - - clks_disk_copy_text((char *)(entry_ptr + 20U), CLKS_DISK_PATH_MAX, node->path); - entry_count++; - } - - clks_memcpy(meta_base, (const void *)CLKS_DISK_META_MAGIC, 8U); - clks_disk_write_u32(meta_base + 8U, CLKS_DISK_META_VERSION); - clks_disk_write_u32(meta_base + 12U, (u32)entry_count); - clks_disk_write_u64(meta_base + 16U, data_cursor - CLKS_DISK_DATA_OFFSET); - - if (clks_disk_sync_bytes_to_hw(data_cursor) == CLKS_FALSE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_meta_load(void) { - const u8 *meta_base; - u64 entry_count; - u64 max_entries; - u64 i; - - if (clks_disk_meta_is_present() == CLKS_FALSE) { - return CLKS_FALSE; - } - - meta_base = clks_disk_bytes + (usize)CLKS_DISK_META_OFFSET; - entry_count = (u64)clks_disk_read_u32(meta_base + 12U); - max_entries = (CLKS_DISK_META_SIZE - (u64)CLKS_DISK_META_HEADER_SIZE) / (u64)CLKS_DISK_META_ENTRY_SIZE; - - if (entry_count > max_entries) { - return CLKS_FALSE; - } - - clks_disk_nodes_reset(); - - if (clks_disk_ensure_root() == CLKS_FALSE) { - return CLKS_FALSE; - } - - for (i = 0ULL; i < entry_count; i++) { - const u8 *entry_ptr = meta_base + CLKS_DISK_META_HEADER_SIZE + (usize)(i * (u64)CLKS_DISK_META_ENTRY_SIZE); - u8 type = entry_ptr[0]; - u64 size = clks_disk_read_u64(entry_ptr + 4U); - u64 data_offset = clks_disk_read_u64(entry_ptr + 12U); - char path[CLKS_DISK_PATH_MAX]; - char normalized_path[CLKS_DISK_PATH_MAX]; - char parent[CLKS_DISK_PATH_MAX]; - i32 parent_index; - const void *payload_data = (const void *)clks_disk_empty_file_data; - clks_bool payload_heap_owned = CLKS_FALSE; - i32 node_index; - - clks_memset(path, 0, sizeof(path)); - clks_memcpy(path, entry_ptr + 20U, CLKS_DISK_PATH_MAX - 1U); - - if (clks_disk_normalize_relative_path(path, normalized_path, sizeof(normalized_path)) == CLKS_FALSE) { - continue; - } - - if (normalized_path[0] == '\0') { - continue; - } - - if (type == (u8)CLKS_DISK_NODE_DIR) { - (void)clks_disk_ensure_dir_hierarchy(normalized_path); - continue; - } - - if (type != (u8)CLKS_DISK_NODE_FILE) { - continue; - } - - if (clks_disk_split_parent(normalized_path, parent, sizeof(parent)) == CLKS_FALSE) { - continue; - } - - if (clks_disk_ensure_dir_hierarchy(parent) == CLKS_FALSE) { - continue; - } - - parent_index = clks_disk_find_node_by_relative(parent); - - if (parent_index < 0 || clks_disk_nodes[(u16)parent_index].type != (u8)CLKS_DISK_NODE_DIR) { - continue; - } - - if (size == 0ULL) { - payload_data = (const void *)clks_disk_empty_file_data; - payload_heap_owned = CLKS_FALSE; - } else { - void *payload; - - if (data_offset < CLKS_DISK_DATA_OFFSET || data_offset + size < data_offset || - data_offset + size > clks_disk_bytes_len) { - continue; - } - - payload = clks_kmalloc((usize)size); - - if (payload == CLKS_NULL) { - continue; - } - - clks_memcpy(payload, clks_disk_bytes + (usize)data_offset, (usize)size); - payload_data = payload; - payload_heap_owned = CLKS_TRUE; - } - - node_index = clks_disk_create_or_update_node(normalized_path, (u8)CLKS_DISK_NODE_FILE, (u16)parent_index, - payload_data, size); - - if (node_index < 0) { - if (payload_heap_owned == CLKS_TRUE) { - clks_kfree((void *)payload_data); - } - continue; - } - - clks_disk_node_set_heap_data((u16)node_index, payload_heap_owned); - } - - return CLKS_TRUE; -} - -static clks_bool clks_disk_detect_fat32(void) { - const u8 *boot; - const u8 fat32_sig[CLKS_DISK_FAT32_TYPE_LEN] = {'F', 'A', 'T', '3', '2'}; - - if (clks_disk_ready == CLKS_FALSE || clks_disk_bytes == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_bytes_len < CLKS_DISK_SECTOR_SIZE) { - return CLKS_FALSE; - } - - boot = clks_disk_bytes; - - if (boot[CLKS_DISK_FAT32_BOOT_SIG_OFFSET] != 0x55U || boot[CLKS_DISK_FAT32_BOOT_SIG_OFFSET + 1U] != 0xAAU) { - return CLKS_FALSE; - } - - if (clks_disk_read_u16(boot + 11U) != (u16)CLKS_DISK_SECTOR_SIZE) { - return CLKS_FALSE; - } - - return clks_disk_bytes_equal(boot + CLKS_DISK_FAT32_TYPE_OFFSET, fat32_sig, CLKS_DISK_FAT32_TYPE_LEN); -} - -static void clks_disk_label_to_boot_field(char *out_label, const char *label) { - usize i = 0U; - - for (i = 0U; i < 11U; i++) { - out_label[i] = ' '; - } - - if (label == CLKS_NULL || label[0] == '\0') { - const char default_label[11] = {'C', 'L', 'E', 'O', 'N', 'O', 'S', 'D', 'I', 'S', 'K'}; - for (i = 0U; i < 11U; i++) { - out_label[i] = default_label[i]; - } - return; - } - - i = 0U; - while (label[i] != '\0' && i < 11U) { - char ch = label[i]; - if (ch >= 'a' && ch <= 'z') { - ch = (char)(ch - ('a' - 'A')); - } - out_label[i] = ch; - i++; - } -} - -static clks_bool clks_disk_write_fat32_boot_sector(const char *label) { - u8 *boot = clks_disk_bytes; - u8 *fsinfo; - u8 *backup_boot; - u64 total_sectors = clks_disk_sector_total; - u8 sectors_per_cluster = 1U; - u16 reserved = 64U; - u8 fats = 2U; - u32 fat_sectors = 1U; - u32 iter; - char label_field[11]; - - if (total_sectors < 8192ULL) { - return CLKS_FALSE; - } - - if (total_sectors > 262144ULL) { - sectors_per_cluster = 8U; - } else if (total_sectors > 131072ULL) { - sectors_per_cluster = 4U; - } else { - sectors_per_cluster = 1U; - } - - for (iter = 0U; iter < 8U; iter++) { - u64 data_sectors; - u64 cluster_count; - u64 next_fat; - - if (total_sectors <= (u64)reserved + ((u64)fats * (u64)fat_sectors)) { - return CLKS_FALSE; - } - - data_sectors = total_sectors - (u64)reserved - ((u64)fats * (u64)fat_sectors); - cluster_count = data_sectors / (u64)sectors_per_cluster; - next_fat = ((cluster_count + 2ULL) * 4ULL + (CLKS_DISK_SECTOR_SIZE - 1ULL)) / CLKS_DISK_SECTOR_SIZE; - - if (next_fat > 0xFFFFFFFFULL) { - return CLKS_FALSE; - } - - if ((u32)next_fat == fat_sectors) { - break; - } - - fat_sectors = (u32)next_fat; - } - - if (fat_sectors == 0U) { - return CLKS_FALSE; - } - - clks_memset(boot, 0, CLKS_DISK_SECTOR_SIZE); - boot[0] = 0xEBU; - boot[1] = 0x58U; - boot[2] = 0x90U; - clks_memcpy(boot + 3U, "MSDOS5.0", 8U); - clks_disk_write_u16(boot + 11U, (u16)CLKS_DISK_SECTOR_SIZE); - boot[13] = sectors_per_cluster; - clks_disk_write_u16(boot + 14U, reserved); - boot[16] = fats; - clks_disk_write_u16(boot + 17U, 0U); - clks_disk_write_u16(boot + 19U, 0U); - boot[21] = 0xF8U; - clks_disk_write_u16(boot + 22U, 0U); - clks_disk_write_u16(boot + 24U, 63U); - clks_disk_write_u16(boot + 26U, 255U); - clks_disk_write_u32(boot + 28U, 0U); - clks_disk_write_u32(boot + 32U, (u32)total_sectors); - clks_disk_write_u32(boot + 36U, fat_sectors); - clks_disk_write_u16(boot + 40U, 0U); - clks_disk_write_u16(boot + 42U, 0U); - clks_disk_write_u32(boot + 44U, 2U); - clks_disk_write_u16(boot + 48U, 1U); - clks_disk_write_u16(boot + 50U, 6U); - boot[64] = 0x80U; - boot[66] = 0x29U; - clks_disk_write_u32(boot + 67U, 0x434C4B53U); - clks_disk_label_to_boot_field(label_field, label); - clks_memcpy(boot + 71U, label_field, 11U); - clks_memcpy(boot + 82U, "FAT32 ", 8U); - boot[CLKS_DISK_FAT32_BOOT_SIG_OFFSET] = 0x55U; - boot[CLKS_DISK_FAT32_BOOT_SIG_OFFSET + 1U] = 0xAAU; - - fsinfo = clks_disk_bytes + (usize)CLKS_DISK_SECTOR_SIZE; - clks_memset(fsinfo, 0, CLKS_DISK_SECTOR_SIZE); - clks_disk_write_u32(fsinfo + 0U, 0x41615252U); - clks_disk_write_u32(fsinfo + 484U, 0x61417272U); - clks_disk_write_u32(fsinfo + 488U, 0xFFFFFFFFU); - clks_disk_write_u32(fsinfo + 492U, 0xFFFFFFFFU); - fsinfo[CLKS_DISK_FAT32_BOOT_SIG_OFFSET] = 0x55U; - fsinfo[CLKS_DISK_FAT32_BOOT_SIG_OFFSET + 1U] = 0xAAU; - - backup_boot = clks_disk_bytes + (usize)(6ULL * CLKS_DISK_SECTOR_SIZE); - clks_memcpy(backup_boot, boot, CLKS_DISK_SECTOR_SIZE); - - { - u64 fat_base = (u64)reserved * CLKS_DISK_SECTOR_SIZE; - u32 fat_index; - - for (fat_index = 0U; fat_index < fats; fat_index++) { - u64 offset = fat_base + ((u64)fat_index * (u64)fat_sectors * CLKS_DISK_SECTOR_SIZE); - u8 *fat_ptr; - - if (offset + 12ULL > clks_disk_bytes_len) { - return CLKS_FALSE; - } - - fat_ptr = clks_disk_bytes + (usize)offset; - clks_disk_write_u32(fat_ptr + 0U, 0x0FFFFFF8U); - clks_disk_write_u32(fat_ptr + 4U, 0xFFFFFFFFU); - clks_disk_write_u32(fat_ptr + 8U, 0x0FFFFFFFU); - } - } - - return CLKS_TRUE; -} - -void clks_disk_init(void) { - u64 detected_sectors = 0ULL; - u64 cache_bytes; - u64 alloc_bytes; - u64 lba; - - clks_disk_ready = CLKS_FALSE; - clks_disk_formatted = CLKS_FALSE; - clks_disk_mounted = CLKS_FALSE; - clks_disk_hw_backed = CLKS_FALSE; - clks_disk_bytes = CLKS_NULL; - clks_disk_bytes_len = 0ULL; - clks_disk_sector_total = 0ULL; - clks_disk_mount_path_buf[0] = '\0'; - clks_disk_nodes_reset(); - - if (clks_disk_ata_identify(&detected_sectors) == CLKS_FALSE || detected_sectors == 0ULL) { - clks_log(CLKS_LOG_WARN, "DISK", "NO ATA DISK DETECTED (CHECK QEMU -DRIVE)"); - return; - } - - cache_bytes = detected_sectors * CLKS_DISK_SECTOR_SIZE; - if (cache_bytes / CLKS_DISK_SECTOR_SIZE != detected_sectors) { - clks_log(CLKS_LOG_WARN, "DISK", "DISK SIZE OVERFLOW"); - return; - } - - if (cache_bytes < CLKS_DISK_MIN_BYTES) { - clks_log(CLKS_LOG_WARN, "DISK", "ATA DISK TOO SMALL"); - clks_log_hex(CLKS_LOG_WARN, "DISK", "BYTES", cache_bytes); - return; - } - - if (cache_bytes > CLKS_DISK_CACHE_MAX_BYTES) { - cache_bytes = CLKS_DISK_CACHE_MAX_BYTES; - clks_log(CLKS_LOG_WARN, "DISK", "DISK CACHE TRUNCATED"); - } - - alloc_bytes = cache_bytes; - while (alloc_bytes >= CLKS_DISK_MIN_BYTES) { - clks_disk_bytes = (u8 *)clks_kmalloc((usize)alloc_bytes); - if (clks_disk_bytes != CLKS_NULL) { - cache_bytes = alloc_bytes; - break; - } - - alloc_bytes /= 2ULL; - alloc_bytes -= (alloc_bytes % CLKS_DISK_SECTOR_SIZE); - } - - if (clks_disk_bytes == CLKS_NULL) { - clks_log(CLKS_LOG_WARN, "DISK", "DISK BACKEND ALLOCATION FAILED"); - return; - } - - detected_sectors = cache_bytes / CLKS_DISK_SECTOR_SIZE; - - for (lba = 0ULL; lba < detected_sectors; lba++) { - u8 *sector_ptr = clks_disk_bytes + (usize)(lba * CLKS_DISK_SECTOR_SIZE); - if (clks_disk_ata_read_sector_hw(lba, sector_ptr) == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "DISK", "ATA READ FAILED DURING CACHE LOAD"); - clks_log_hex(CLKS_LOG_WARN, "DISK", "LBA", lba); - clks_kfree(clks_disk_bytes); - clks_disk_bytes = CLKS_NULL; - return; - } - } - - clks_disk_bytes_len = cache_bytes; - clks_disk_sector_total = detected_sectors; - clks_disk_hw_backed = CLKS_TRUE; - clks_disk_ready = CLKS_TRUE; - clks_disk_formatted = clks_disk_detect_fat32(); - - if (clks_disk_ensure_root() == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "DISK", "FAILED TO INIT ROOT NODE"); - clks_disk_ready = CLKS_FALSE; - return; - } - - if (clks_disk_formatted == CLKS_TRUE) { - if (clks_disk_meta_load() == CLKS_FALSE) { - clks_log(CLKS_LOG_WARN, "DISK", "FAT32 DETECTED, META MISSING; RESET TO EMPTY"); - clks_disk_nodes_reset(); - (void)clks_disk_ensure_root(); - (void)clks_disk_meta_flush(); - } - } - - (void)clks_disk_mount("/temp/disk"); - clks_log(CLKS_LOG_INFO, "DISK", "DISK BACKEND ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "DISK", "BYTES", clks_disk_bytes_len); - clks_log_hex(CLKS_LOG_INFO, "DISK", "SECTORS", clks_disk_sector_total); - clks_log_hex(CLKS_LOG_INFO, "DISK", "FAT32", (clks_disk_formatted == CLKS_TRUE) ? 1ULL : 0ULL); - clks_log_hex(CLKS_LOG_INFO, "DISK", "HW_BACKED", (clks_disk_hw_backed == CLKS_TRUE) ? 1ULL : 0ULL); -} - -clks_bool clks_disk_present(void) { - return clks_disk_ready; -} - -u64 clks_disk_size_bytes(void) { - return (clks_disk_ready == CLKS_TRUE) ? clks_disk_bytes_len : 0ULL; -} - -u64 clks_disk_sector_count(void) { - return (clks_disk_ready == CLKS_TRUE) ? clks_disk_sector_total : 0ULL; -} - -clks_bool clks_disk_read_sector(u64 lba, void *out_sector) { - if (clks_disk_ready == CLKS_FALSE || out_sector == CLKS_NULL) { - return CLKS_FALSE; - } - - if (lba >= clks_disk_sector_total) { - return CLKS_FALSE; - } - - if (clks_disk_hw_backed == CLKS_TRUE) { - if (clks_disk_ata_read_sector_hw(lba, out_sector) == CLKS_FALSE) { - return CLKS_FALSE; - } - clks_memcpy(clks_disk_bytes + (usize)(lba * CLKS_DISK_SECTOR_SIZE), out_sector, (usize)CLKS_DISK_SECTOR_SIZE); - return CLKS_TRUE; - } - - clks_memcpy(out_sector, clks_disk_bytes + (usize)(lba * CLKS_DISK_SECTOR_SIZE), (usize)CLKS_DISK_SECTOR_SIZE); - return CLKS_TRUE; -} - -clks_bool clks_disk_write_sector(u64 lba, const void *sector_data) { - if (clks_disk_ready == CLKS_FALSE || sector_data == CLKS_NULL) { - return CLKS_FALSE; - } - - if (lba >= clks_disk_sector_total) { - return CLKS_FALSE; - } - - clks_memcpy(clks_disk_bytes + (usize)(lba * CLKS_DISK_SECTOR_SIZE), sector_data, (usize)CLKS_DISK_SECTOR_SIZE); - - if (clks_disk_hw_backed == CLKS_TRUE) { - if (clks_disk_ata_write_sector_hw(lba, sector_data) == CLKS_FALSE) { - return CLKS_FALSE; - } - if (clks_disk_ata_cache_flush_hw() == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -clks_bool clks_disk_is_formatted_fat32(void) { - return (clks_disk_ready == CLKS_TRUE && clks_disk_formatted == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; -} - -clks_bool clks_disk_format_fat32(const char *label) { - if (clks_disk_ready == CLKS_FALSE || clks_disk_bytes == CLKS_NULL) { - return CLKS_FALSE; - } - - clks_memset(clks_disk_bytes, 0, (usize)clks_disk_bytes_len); - - if (clks_disk_sync_bytes_to_hw(clks_disk_bytes_len) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_write_fat32_boot_sector(label) == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_disk_nodes_reset(); - - if (clks_disk_ensure_root() == CLKS_FALSE) { - return CLKS_FALSE; - } - - clks_disk_formatted = CLKS_TRUE; - - if (clks_disk_meta_flush() == CLKS_FALSE) { - clks_disk_formatted = CLKS_FALSE; - return CLKS_FALSE; - } - - clks_log(CLKS_LOG_INFO, "DISK", "FAT32 FORMAT COMPLETE"); - return CLKS_TRUE; -} - -clks_bool clks_disk_mount(const char *mount_path) { - char normalized[CLKS_DISK_PATH_MAX]; - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_normalize_absolute_path(mount_path, normalized, sizeof(normalized)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_strcmp(normalized, "/") == 0) { - return CLKS_FALSE; - } - - clks_disk_copy_text(clks_disk_mount_path_buf, sizeof(clks_disk_mount_path_buf), normalized); - clks_disk_mounted = CLKS_TRUE; - return CLKS_TRUE; -} - -clks_bool clks_disk_is_mounted(void) { - return (clks_disk_ready == CLKS_TRUE && clks_disk_mounted == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; -} - -const char *clks_disk_mount_path(void) { - if (clks_disk_mounted == CLKS_FALSE) { - return ""; - } - - return clks_disk_mount_path_buf; -} - -clks_bool clks_disk_path_in_mount(const char *path) { - char relative[CLKS_DISK_PATH_MAX]; - return (clks_disk_path_to_relative(path, relative, sizeof(relative)) == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; -} - -clks_bool clks_disk_stat(const char *path, u64 *out_type, u64 *out_size) { - char relative[CLKS_DISK_PATH_MAX]; - i32 node_index; - - if (out_type == CLKS_NULL || out_size == CLKS_NULL || - clks_disk_path_to_relative(path, relative, sizeof(relative)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return CLKS_FALSE; - } - - node_index = clks_disk_find_node_by_relative(relative); - - if (node_index < 0) { - return CLKS_FALSE; - } - - *out_type = - (clks_disk_nodes[(u16)node_index].type == (u8)CLKS_DISK_NODE_DIR) ? CLKS_DISK_NODE_DIR : CLKS_DISK_NODE_FILE; - *out_size = clks_disk_nodes[(u16)node_index].size; - return CLKS_TRUE; -} - -const void *clks_disk_read_all(const char *path, u64 *out_size) { - char relative[CLKS_DISK_PATH_MAX]; - i32 node_index; - - if (clks_disk_path_to_relative(path, relative, sizeof(relative)) == CLKS_FALSE) { - return CLKS_NULL; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return CLKS_NULL; - } - - node_index = clks_disk_find_node_by_relative(relative); - - if (node_index < 0 || clks_disk_nodes[(u16)node_index].type != (u8)CLKS_DISK_NODE_FILE) { - return CLKS_NULL; - } - - if (out_size != CLKS_NULL) { - *out_size = clks_disk_nodes[(u16)node_index].size; - } - - if (clks_disk_nodes[(u16)node_index].size == 0ULL) { - return (const void *)clks_disk_empty_file_data; - } - - return clks_disk_nodes[(u16)node_index].data; -} - -u64 clks_disk_count_children(const char *dir_path) { - char relative[CLKS_DISK_PATH_MAX]; - i32 dir_index; - u64 count = 0ULL; - u16 i; - - if (clks_disk_path_to_relative(dir_path, relative, sizeof(relative)) == CLKS_FALSE) { - return 0ULL; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return 0ULL; - } - - dir_index = clks_disk_find_node_by_relative(relative); - - if (dir_index < 0 || clks_disk_nodes[(u16)dir_index].type != (u8)CLKS_DISK_NODE_DIR) { - return 0ULL; - } - - for (i = 0U; i < clks_disk_nodes_used; i++) { - if (clks_disk_nodes[i].used == CLKS_FALSE) { - continue; - } - - if ((u16)dir_index == i) { - continue; - } - - if (clks_disk_nodes[i].parent == (u16)dir_index) { - count++; - } - } - - return count; -} - -clks_bool clks_disk_get_child_name(const char *dir_path, u64 index, char *out_name, usize out_name_size) { - char relative[CLKS_DISK_PATH_MAX]; - i32 dir_index; - u64 current = 0ULL; - u16 i; - - if (out_name == CLKS_NULL || out_name_size == 0U) { - return CLKS_FALSE; - } - - if (clks_disk_path_to_relative(dir_path, relative, sizeof(relative)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return CLKS_FALSE; - } - - dir_index = clks_disk_find_node_by_relative(relative); - - if (dir_index < 0 || clks_disk_nodes[(u16)dir_index].type != (u8)CLKS_DISK_NODE_DIR) { - return CLKS_FALSE; - } - - for (i = 0U; i < clks_disk_nodes_used; i++) { - const char *base; - usize base_len; - - if (clks_disk_nodes[i].used == CLKS_FALSE || clks_disk_nodes[i].parent != (u16)dir_index || - i == (u16)dir_index) { - continue; - } - - if (current != index) { - current++; - continue; - } - - base = clks_disk_basename(clks_disk_nodes[i].path); - base_len = clks_strlen(base); - - if (base_len + 1U > out_name_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_name, base, base_len + 1U); - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -clks_bool clks_disk_mkdir(const char *path) { - char relative[CLKS_DISK_PATH_MAX]; - i32 node_index; - - if (clks_disk_path_to_relative(path, relative, sizeof(relative)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (relative[0] == '\0') { - return CLKS_TRUE; - } - - if (clks_disk_ensure_dir_hierarchy(relative) == CLKS_FALSE) { - return CLKS_FALSE; - } - - node_index = clks_disk_find_node_by_relative(relative); - - if (node_index < 0 || clks_disk_nodes[(u16)node_index].type != (u8)CLKS_DISK_NODE_DIR) { - return CLKS_FALSE; - } - - return (clks_disk_meta_flush() == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE; -} - -clks_bool clks_disk_write_all(const char *path, const void *data, u64 size) { - char relative[CLKS_DISK_PATH_MAX]; - char parent[CLKS_DISK_PATH_MAX]; - const void *payload_data = CLKS_NULL; - clks_bool payload_heap_owned = CLKS_FALSE; - i32 parent_index; - i32 node_index; - - if (clks_disk_path_to_relative(path, relative, sizeof(relative)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE || relative[0] == '\0') { - return CLKS_FALSE; - } - - if (clks_disk_split_parent(relative, parent, sizeof(parent)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_ensure_dir_hierarchy(parent) == CLKS_FALSE) { - return CLKS_FALSE; - } - - parent_index = clks_disk_find_node_by_relative(parent); - - if (parent_index < 0 || clks_disk_nodes[(u16)parent_index].type != (u8)CLKS_DISK_NODE_DIR) { - return CLKS_FALSE; - } - - node_index = clks_disk_find_node_by_relative(relative); - - if (node_index >= 0 && clks_disk_nodes[(u16)node_index].type != (u8)CLKS_DISK_NODE_FILE) { - return CLKS_FALSE; - } - - if (clks_disk_build_file_payload(data, size, &payload_data, &payload_heap_owned) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (node_index >= 0) { - clks_disk_node_release_heap_data((u16)node_index); - } - - node_index = - clks_disk_create_or_update_node(relative, (u8)CLKS_DISK_NODE_FILE, (u16)parent_index, payload_data, size); - - if (node_index < 0) { - if (payload_heap_owned == CLKS_TRUE) { - clks_kfree((void *)payload_data); - } - return CLKS_FALSE; - } - - clks_disk_node_set_heap_data((u16)node_index, payload_heap_owned); - - if (clks_disk_meta_flush() == CLKS_FALSE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -clks_bool clks_disk_append(const char *path, const void *data, u64 size) { - char relative[CLKS_DISK_PATH_MAX]; - i32 node_index; - const void *old_data; - u64 old_size; - u64 new_size; - void *merged; - - if (clks_disk_path_to_relative(path, relative, sizeof(relative)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE || relative[0] == '\0') { - return CLKS_FALSE; - } - - if (size > 0ULL && data == CLKS_NULL) { - return CLKS_FALSE; - } - - node_index = clks_disk_find_node_by_relative(relative); - - if (node_index < 0) { - return clks_disk_write_all(path, data, size); - } - - if (clks_disk_nodes[(u16)node_index].type != (u8)CLKS_DISK_NODE_FILE) { - return CLKS_FALSE; - } - - old_data = clks_disk_nodes[(u16)node_index].data; - old_size = clks_disk_nodes[(u16)node_index].size; - - if (old_size > (0xFFFFFFFFFFFFFFFFULL - size)) { - return CLKS_FALSE; - } - - new_size = old_size + size; - - if (new_size == 0ULL) { - return clks_disk_write_all(path, clks_disk_empty_file_data, 0ULL); - } - - merged = clks_kmalloc((usize)new_size); - - if (merged == CLKS_NULL) { - return CLKS_FALSE; - } - - if (old_size > 0ULL && old_data != CLKS_NULL) { - clks_memcpy(merged, old_data, (usize)old_size); - } - - if (size > 0ULL) { - clks_memcpy((u8 *)merged + (usize)old_size, data, (usize)size); - } - - if (clks_disk_write_all(path, merged, new_size) == CLKS_FALSE) { - clks_kfree(merged); - return CLKS_FALSE; - } - - clks_kfree(merged); - return CLKS_TRUE; -} - -clks_bool clks_disk_remove(const char *path) { - char relative[CLKS_DISK_PATH_MAX]; - i32 node_index; - u16 i; - - if (clks_disk_path_to_relative(path, relative, sizeof(relative)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (relative[0] == '\0') { - return CLKS_FALSE; - } - - node_index = clks_disk_find_node_by_relative(relative); - - if (node_index < 0) { - return CLKS_FALSE; - } - - if (clks_disk_nodes[(u16)node_index].type == (u8)CLKS_DISK_NODE_DIR) { - for (i = 0U; i < clks_disk_nodes_used; i++) { - if (clks_disk_nodes[i].used == CLKS_FALSE) { - continue; - } - - if (clks_disk_nodes[i].parent == (u16)node_index) { - return CLKS_FALSE; - } - } - } - - clks_disk_node_release_heap_data((u16)node_index); - clks_memset(&clks_disk_nodes[(u16)node_index], 0, sizeof(clks_disk_nodes[(u16)node_index])); - - if (clks_disk_meta_flush() == CLKS_FALSE) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -u64 clks_disk_node_count(void) { - u16 i; - u64 used = 0ULL; - - if (clks_disk_ready == CLKS_FALSE || clks_disk_formatted == CLKS_FALSE) { - return 0ULL; - } - - for (i = 0U; i < clks_disk_nodes_used; i++) { - if (clks_disk_nodes[i].used == CLKS_TRUE) { - used++; - } - } - - return used; -} diff --git a/clks/kernel/storage/fs.c b/clks/kernel/storage/fs.c deleted file mode 100644 index 959fc92..0000000 --- a/clks/kernel/storage/fs.c +++ /dev/null @@ -1,967 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -/* Tiny in-memory FS: simple enough to reason about, still easy to screw up. */ - -#define CLKS_FS_MAX_NODES 512U -#define CLKS_FS_PATH_MAX CLKS_RAMDISK_PATH_MAX - -#define CLKS_FS_NODE_FLAG_HEAP_DATA 0x0001U - -struct clks_fs_node { - clks_bool used; - enum clks_fs_node_type type; - u16 parent; - u16 reserved; - const void *data; - u64 size; - char path[CLKS_FS_PATH_MAX]; -}; - -struct clks_fs_build_stats { - u64 file_count; - u64 dir_count; -}; - -static struct clks_fs_node clks_fs_nodes[CLKS_FS_MAX_NODES]; -static u16 clks_fs_nodes_used = 0U; -static clks_bool clks_fs_ready = CLKS_FALSE; -static const u8 clks_fs_empty_file_data[1] = {0U}; - -static clks_bool clks_fs_normalize_external_path(const char *path, char *out_internal, usize out_size) { - usize in_pos = 0; - usize out_pos = 0; - - if (path == CLKS_NULL || out_internal == CLKS_NULL || out_size == 0U) { - return CLKS_FALSE; - } - - if (path[0] != '/') { - return CLKS_FALSE; - } - - while (path[in_pos] == '/') { - in_pos++; - } - - /* Normalize aggressively; weird paths are where bugs and exploits like to party. */ - while (path[in_pos] != '\0') { - usize comp_start = in_pos; - usize comp_len; - - while (path[in_pos] != '\0' && path[in_pos] != '/') { - in_pos++; - } - - comp_len = in_pos - comp_start; - - if (comp_len == 0U) { - while (path[in_pos] == '/') { - in_pos++; - } - continue; - } - - if (comp_len == 1U && path[comp_start] == '.') { - while (path[in_pos] == '/') { - in_pos++; - } - continue; - } - - /* No parent traversal here. Not today, not ever. */ - if (comp_len == 2U && path[comp_start] == '.' && path[comp_start + 1U] == '.') { - return CLKS_FALSE; - } - - if (out_pos != 0U) { - if (out_pos + 1U >= out_size) { - return CLKS_FALSE; - } - out_internal[out_pos++] = '/'; - } - - if (out_pos + comp_len >= out_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_internal + out_pos, path + comp_start, comp_len); - out_pos += comp_len; - - while (path[in_pos] == '/') { - in_pos++; - } - } - - out_internal[out_pos] = '\0'; - return CLKS_TRUE; -} - -static clks_bool clks_fs_internal_in_temp_tree(const char *internal_path) { - /* Write access is fenced into /temp so random code can't trash the world. */ - if (internal_path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (internal_path[0] != 't' || internal_path[1] != 'e' || internal_path[2] != 'm' || internal_path[3] != 'p') { - return CLKS_FALSE; - } - - return (internal_path[4] == '\0' || internal_path[4] == '/') ? CLKS_TRUE : CLKS_FALSE; -} - -static clks_bool clks_fs_internal_is_temp_file_path(const char *internal_path) { - if (clks_fs_internal_in_temp_tree(internal_path) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (internal_path[4] == '\0') { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static i32 clks_fs_find_node_by_internal(const char *internal_path) { - u16 i; - - /* Linear scan is boring, but with this node count it's fine as hell. */ - for (i = 0U; i < clks_fs_nodes_used; i++) { - if (clks_fs_nodes[i].used == CLKS_FALSE) { - continue; - } - - if (clks_strcmp(clks_fs_nodes[i].path, internal_path) == 0) { - return (i32)i; - } - } - - return -1; -} - -static i32 clks_fs_find_node_by_external(const char *external_path) { - char internal[CLKS_FS_PATH_MAX]; - - if (clks_fs_normalize_external_path(external_path, internal, sizeof(internal)) == CLKS_FALSE) { - return -1; - } - - return clks_fs_find_node_by_internal(internal); -} - -static const char *clks_fs_basename(const char *internal_path) { - usize len; - usize i; - - if (internal_path == CLKS_NULL) { - return ""; - } - - len = clks_strlen(internal_path); - - if (len == 0U) { - return ""; - } - - for (i = len; i != 0U; i--) { - if (internal_path[i - 1U] == '/') { - return &internal_path[i]; - } - } - - return internal_path; -} - -static clks_bool clks_fs_split_parent(const char *internal_path, char *parent_out, usize parent_out_size) { - usize len; - usize i; - - if (internal_path == CLKS_NULL || parent_out == CLKS_NULL || parent_out_size == 0U) { - return CLKS_FALSE; - } - - len = clks_strlen(internal_path); - - if (len == 0U) { - parent_out[0] = '\0'; - return CLKS_TRUE; - } - - /* Manual split is ugly, but it avoids allocator drama during path ops. */ - for (i = len; i != 0U; i--) { - if (internal_path[i - 1U] == '/') { - usize parent_len = i - 1U; - - if (parent_len >= parent_out_size) { - return CLKS_FALSE; - } - - clks_memcpy(parent_out, internal_path, parent_len); - parent_out[parent_len] = '\0'; - return CLKS_TRUE; - } - } - - parent_out[0] = '\0'; - return CLKS_TRUE; -} - -static clks_bool clks_fs_node_has_heap_data(u16 index) { - return ((clks_fs_nodes[index].reserved & CLKS_FS_NODE_FLAG_HEAP_DATA) != 0U) ? CLKS_TRUE : CLKS_FALSE; -} - -static void clks_fs_node_set_heap_data(u16 index, clks_bool value) { - if (value == CLKS_TRUE) { - clks_fs_nodes[index].reserved |= CLKS_FS_NODE_FLAG_HEAP_DATA; - } else { - clks_fs_nodes[index].reserved &= (u16)(~CLKS_FS_NODE_FLAG_HEAP_DATA); - } -} - -static void clks_fs_node_release_heap_data(u16 index) { - if (clks_fs_nodes[index].type != CLKS_FS_NODE_FILE) { - return; - } - - if (clks_fs_node_has_heap_data(index) == CLKS_TRUE && clks_fs_nodes[index].data != CLKS_NULL) { - clks_kfree((void *)clks_fs_nodes[index].data); - } - - clks_fs_node_set_heap_data(index, CLKS_FALSE); -} - -static i32 clks_fs_alloc_slot(void) { - u16 i; - - for (i = 0U; i < clks_fs_nodes_used; i++) { - if (clks_fs_nodes[i].used == CLKS_FALSE) { - return (i32)i; - } - } - - if (clks_fs_nodes_used >= CLKS_FS_MAX_NODES) { - return -1; - } - - clks_fs_nodes_used++; - return (i32)(clks_fs_nodes_used - 1U); -} - -static i32 clks_fs_create_or_update_node(const char *internal_path, enum clks_fs_node_type type, u16 parent, - const void *data, u64 size) { - i32 existing; - i32 slot; - usize path_len; - - if (internal_path == CLKS_NULL) { - return -1; - } - - path_len = clks_strlen(internal_path); - - if (path_len >= CLKS_FS_PATH_MAX) { - return -1; - } - - existing = clks_fs_find_node_by_internal(internal_path); - - if (existing >= 0) { - struct clks_fs_node *node = &clks_fs_nodes[(u16)existing]; - - if (node->type != type) { - return -1; - } - - node->parent = parent; - - if (type == CLKS_FS_NODE_FILE) { - node->data = data; - node->size = size; - node->reserved = 0U; - } - - node->used = CLKS_TRUE; - return existing; - } - - slot = clks_fs_alloc_slot(); - - if (slot < 0) { - return -1; - } - - clks_fs_nodes[(u16)slot].used = CLKS_TRUE; - clks_fs_nodes[(u16)slot].type = type; - clks_fs_nodes[(u16)slot].parent = parent; - clks_fs_nodes[(u16)slot].reserved = 0U; - clks_fs_nodes[(u16)slot].data = (type == CLKS_FS_NODE_FILE) ? data : CLKS_NULL; - clks_fs_nodes[(u16)slot].size = (type == CLKS_FS_NODE_FILE) ? size : 0ULL; - clks_memcpy(clks_fs_nodes[(u16)slot].path, internal_path, path_len + 1U); - - return slot; -} - -static clks_bool clks_fs_ensure_root(void) { - if (clks_fs_create_or_update_node("", CLKS_FS_NODE_DIR, 0U, CLKS_NULL, 0ULL) != 0) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_fs_ensure_dir_hierarchy(const char *internal_dir_path) { - char prefix[CLKS_FS_PATH_MAX]; - usize cursor = 0; - usize i = 0; - u16 current_parent = 0U; - - prefix[0] = '\0'; - - if (internal_dir_path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (internal_dir_path[0] == '\0') { - return CLKS_TRUE; - } - - while (internal_dir_path[i] != '\0') { - usize comp_start = i; - usize comp_len; - i32 node_index; - - while (internal_dir_path[i] != '\0' && internal_dir_path[i] != '/') { - i++; - } - - comp_len = i - comp_start; - - if (comp_len == 0U) { - return CLKS_FALSE; - } - - if (cursor != 0U) { - if (cursor + 1U >= sizeof(prefix)) { - return CLKS_FALSE; - } - prefix[cursor++] = '/'; - } - - if (cursor + comp_len >= sizeof(prefix)) { - return CLKS_FALSE; - } - - clks_memcpy(prefix + cursor, internal_dir_path + comp_start, comp_len); - cursor += comp_len; - prefix[cursor] = '\0'; - - node_index = clks_fs_find_node_by_internal(prefix); - - if (node_index < 0) { - node_index = clks_fs_create_or_update_node(prefix, CLKS_FS_NODE_DIR, current_parent, CLKS_NULL, 0ULL); - - if (node_index < 0) { - return CLKS_FALSE; - } - } else if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_DIR) { - return CLKS_FALSE; - } - - current_parent = (u16)node_index; - - if (internal_dir_path[i] == '/') { - i++; - } - } - - return CLKS_TRUE; -} - -static clks_bool clks_fs_require_directory(const char *external_path) { - i32 node_index = clks_fs_find_node_by_external(external_path); - - if (node_index < 0) { - clks_log(CLKS_LOG_ERROR, "FS", "MISSING REQUIRED DIRECTORY"); - clks_log(CLKS_LOG_ERROR, "FS", external_path); - return CLKS_FALSE; - } - - if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_DIR) { - clks_log(CLKS_LOG_ERROR, "FS", "REQUIRED PATH IS NOT DIRECTORY"); - clks_log(CLKS_LOG_ERROR, "FS", external_path); - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_fs_ramdisk_visit(const struct clks_ramdisk_entry *entry, void *ctx) { - struct clks_fs_build_stats *stats = (struct clks_fs_build_stats *)ctx; - - if (entry == CLKS_NULL || stats == CLKS_NULL) { - return CLKS_FALSE; - } - - if (entry->type == CLKS_RAMDISK_ENTRY_DIR) { - if (clks_fs_ensure_dir_hierarchy(entry->path) == CLKS_FALSE) { - return CLKS_FALSE; - } - - stats->dir_count++; - return CLKS_TRUE; - } - - if (entry->type == CLKS_RAMDISK_ENTRY_FILE) { - char parent[CLKS_FS_PATH_MAX]; - i32 parent_index; - - if (clks_fs_split_parent(entry->path, parent, sizeof(parent)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_ensure_dir_hierarchy(parent) == CLKS_FALSE) { - return CLKS_FALSE; - } - - parent_index = clks_fs_find_node_by_internal(parent); - - if (parent_index < 0) { - return CLKS_FALSE; - } - - if (clks_fs_create_or_update_node(entry->path, CLKS_FS_NODE_FILE, (u16)parent_index, entry->data, entry->size) < - 0) { - return CLKS_FALSE; - } - - stats->file_count++; - return CLKS_TRUE; - } - - return CLKS_TRUE; -} - -static clks_bool clks_fs_build_file_payload(const void *data, u64 size, const void **out_data, - clks_bool *out_heap_owned) { - void *payload; - - if (out_data == CLKS_NULL || out_heap_owned == CLKS_NULL) { - return CLKS_FALSE; - } - - if (size == 0ULL) { - *out_data = (const void *)clks_fs_empty_file_data; - *out_heap_owned = CLKS_FALSE; - return CLKS_TRUE; - } - - if (data == CLKS_NULL) { - return CLKS_FALSE; - } - - payload = clks_kmalloc((usize)size); - - if (payload == CLKS_NULL) { - return CLKS_FALSE; - } - - clks_memcpy(payload, data, (usize)size); - *out_data = (const void *)payload; - *out_heap_owned = CLKS_TRUE; - return CLKS_TRUE; -} - -void clks_fs_init(void) { - const struct limine_file *module; - struct clks_fs_build_stats stats; - u64 module_count; - - clks_fs_ready = CLKS_FALSE; - clks_fs_nodes_used = 0U; - clks_memset(clks_fs_nodes, 0, sizeof(clks_fs_nodes)); - clks_memset(&stats, 0, sizeof(stats)); - - if (clks_fs_ensure_root() == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "FS", "FAILED TO CREATE ROOT NODE"); - return; - } - - module_count = clks_boot_get_module_count(); - - if (module_count == 0ULL) { - clks_log(CLKS_LOG_ERROR, "FS", "NO RAMDISK MODULE FROM LIMINE"); - return; - } - - module = clks_boot_get_module(0ULL); - - if (module == CLKS_NULL || module->address == CLKS_NULL || module->size == 0ULL) { - clks_log(CLKS_LOG_ERROR, "FS", "INVALID RAMDISK MODULE"); - return; - } - - if (clks_ramdisk_iterate(module->address, module->size, clks_fs_ramdisk_visit, &stats) == CLKS_FALSE) { - clks_log(CLKS_LOG_ERROR, "FS", "RAMDISK TAR PARSE FAILED"); - return; - } - - clks_log(CLKS_LOG_INFO, "FS", "RAMDISK VFS ONLINE"); - clks_log_hex(CLKS_LOG_INFO, "FS", "MODULE_SIZE", module->size); - clks_log_hex(CLKS_LOG_INFO, "FS", "NODE_COUNT", (u64)clks_fs_nodes_used); - clks_log_hex(CLKS_LOG_INFO, "FS", "FILE_COUNT", stats.file_count); - - clks_disk_init(); - if (clks_disk_present() == CLKS_TRUE) { - clks_log_hex(CLKS_LOG_INFO, "FS", "DISK_BYTES", clks_disk_size_bytes()); - clks_log_hex(CLKS_LOG_INFO, "FS", "DISK_FAT32", (clks_disk_is_formatted_fat32() == CLKS_TRUE) ? 1ULL : 0ULL); - } else { - clks_log(CLKS_LOG_WARN, "FS", "DISK BACKEND NOT PRESENT"); - } - - if (clks_fs_require_directory("/system") == CLKS_FALSE) { - return; - } - - if (clks_fs_require_directory("/shell") == CLKS_FALSE) { - return; - } - - if (clks_fs_require_directory("/temp") == CLKS_FALSE) { - return; - } - - if (clks_fs_require_directory("/driver") == CLKS_FALSE) { - return; - } - - if (clks_fs_require_directory("/dev") == CLKS_FALSE) { - return; - } - - clks_fs_ready = CLKS_TRUE; - clks_log(CLKS_LOG_INFO, "FS", "LAYOUT /SYSTEM /SHELL /TEMP /DRIVER /DEV OK"); -} - -clks_bool clks_fs_is_ready(void) { - return clks_fs_ready; -} - -clks_bool clks_fs_stat(const char *path, struct clks_fs_node_info *out_info) { - i32 node_index; - u64 disk_type = 0ULL; - u64 disk_size = 0ULL; - - if (clks_fs_ready == CLKS_FALSE || out_info == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_path_in_mount(path) == CLKS_TRUE) { - if (clks_disk_stat(path, &disk_type, &disk_size) == CLKS_FALSE) { - return CLKS_FALSE; - } - - out_info->type = (disk_type == CLKS_DISK_NODE_DIR) ? CLKS_FS_NODE_DIR : CLKS_FS_NODE_FILE; - out_info->size = disk_size; - return CLKS_TRUE; - } - - node_index = clks_fs_find_node_by_external(path); - - if (node_index < 0) { - return CLKS_FALSE; - } - - out_info->type = clks_fs_nodes[(u16)node_index].type; - out_info->size = clks_fs_nodes[(u16)node_index].size; - return CLKS_TRUE; -} - -const void *clks_fs_read_all(const char *path, u64 *out_size) { - i32 node_index; - const void *disk_data; - - if (clks_fs_ready == CLKS_FALSE) { - return CLKS_NULL; - } - - if (clks_disk_path_in_mount(path) == CLKS_TRUE) { - disk_data = clks_disk_read_all(path, out_size); - return disk_data; - } - - node_index = clks_fs_find_node_by_external(path); - - if (node_index < 0) { - return CLKS_NULL; - } - - if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_FILE) { - return CLKS_NULL; - } - - if (out_size != CLKS_NULL) { - *out_size = clks_fs_nodes[(u16)node_index].size; - } - - if (clks_fs_nodes[(u16)node_index].size == 0ULL) { - return (const void *)clks_fs_empty_file_data; - } - - return clks_fs_nodes[(u16)node_index].data; -} - -u64 clks_fs_count_children(const char *dir_path) { - i32 dir_index; - u64 count = 0ULL; - u16 i; - - if (clks_fs_ready == CLKS_FALSE) { - return 0ULL; - } - - if (clks_disk_path_in_mount(dir_path) == CLKS_TRUE) { - return clks_disk_count_children(dir_path); - } - - dir_index = clks_fs_find_node_by_external(dir_path); - - if (dir_index < 0) { - return 0ULL; - } - - if (clks_fs_nodes[(u16)dir_index].type != CLKS_FS_NODE_DIR) { - return 0ULL; - } - - for (i = 0U; i < clks_fs_nodes_used; i++) { - if (clks_fs_nodes[i].used == CLKS_FALSE) { - continue; - } - - if ((u16)dir_index == i) { - continue; - } - - if (clks_fs_nodes[i].parent == (u16)dir_index) { - count++; - } - } - - return count; -} - -clks_bool clks_fs_get_child_name(const char *dir_path, u64 index, char *out_name, usize out_name_size) { - i32 dir_index; - u64 current = 0ULL; - u16 i; - - if (clks_fs_ready == CLKS_FALSE || out_name == CLKS_NULL || out_name_size == 0U) { - return CLKS_FALSE; - } - - if (clks_disk_path_in_mount(dir_path) == CLKS_TRUE) { - return clks_disk_get_child_name(dir_path, index, out_name, out_name_size); - } - - dir_index = clks_fs_find_node_by_external(dir_path); - - if (dir_index < 0 || clks_fs_nodes[(u16)dir_index].type != CLKS_FS_NODE_DIR) { - return CLKS_FALSE; - } - - for (i = 0U; i < clks_fs_nodes_used; i++) { - const char *base; - usize base_len; - - if (clks_fs_nodes[i].used == CLKS_FALSE) { - continue; - } - - if ((u16)dir_index == i) { - continue; - } - - if (clks_fs_nodes[i].parent != (u16)dir_index) { - continue; - } - - if (current != index) { - current++; - continue; - } - - base = clks_fs_basename(clks_fs_nodes[i].path); - base_len = clks_strlen(base); - - if (base_len + 1U > out_name_size) { - return CLKS_FALSE; - } - - clks_memcpy(out_name, base, base_len + 1U); - return CLKS_TRUE; - } - - return CLKS_FALSE; -} - -clks_bool clks_fs_mkdir(const char *path) { - char internal[CLKS_FS_PATH_MAX]; - i32 node_index; - - if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_path_in_mount(path) == CLKS_TRUE) { - return clks_disk_mkdir(path); - } - - if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_internal_in_temp_tree(internal) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (internal[0] == '\0') { - return CLKS_FALSE; - } - - if (clks_fs_ensure_dir_hierarchy(internal) == CLKS_FALSE) { - return CLKS_FALSE; - } - - node_index = clks_fs_find_node_by_internal(internal); - - if (node_index < 0) { - return CLKS_FALSE; - } - - return (clks_fs_nodes[(u16)node_index].type == CLKS_FS_NODE_DIR) ? CLKS_TRUE : CLKS_FALSE; -} - -clks_bool clks_fs_write_all(const char *path, const void *data, u64 size) { - char internal[CLKS_FS_PATH_MAX]; - char parent[CLKS_FS_PATH_MAX]; - const void *payload_data = CLKS_NULL; - clks_bool payload_heap_owned = CLKS_FALSE; - i32 parent_index; - i32 node_index; - - if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_path_in_mount(path) == CLKS_TRUE) { - return clks_disk_write_all(path, data, size); - } - - if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_internal_is_temp_file_path(internal) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_split_parent(internal, parent, sizeof(parent)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_internal_in_temp_tree(parent) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_ensure_dir_hierarchy(parent) == CLKS_FALSE) { - return CLKS_FALSE; - } - - parent_index = clks_fs_find_node_by_internal(parent); - - if (parent_index < 0 || clks_fs_nodes[(u16)parent_index].type != CLKS_FS_NODE_DIR) { - return CLKS_FALSE; - } - - node_index = clks_fs_find_node_by_internal(internal); - - if (node_index >= 0 && clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_FILE) { - return CLKS_FALSE; - } - - if (clks_fs_build_file_payload(data, size, &payload_data, &payload_heap_owned) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (node_index >= 0) { - clks_fs_node_release_heap_data((u16)node_index); - } - - node_index = clks_fs_create_or_update_node(internal, CLKS_FS_NODE_FILE, (u16)parent_index, payload_data, size); - - if (node_index < 0) { - if (payload_heap_owned == CLKS_TRUE) { - clks_kfree((void *)payload_data); - } - return CLKS_FALSE; - } - - clks_fs_node_set_heap_data((u16)node_index, payload_heap_owned); - return CLKS_TRUE; -} - -clks_bool clks_fs_append(const char *path, const void *data, u64 size) { - char internal[CLKS_FS_PATH_MAX]; - i32 node_index; - const void *old_data; - u64 old_size; - u64 new_size; - void *merged = CLKS_NULL; - - if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_path_in_mount(path) == CLKS_TRUE) { - return clks_disk_append(path, data, size); - } - - if (size > 0ULL && data == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_internal_is_temp_file_path(internal) == CLKS_FALSE) { - return CLKS_FALSE; - } - - node_index = clks_fs_find_node_by_internal(internal); - - if (node_index < 0) { - return clks_fs_write_all(path, data, size); - } - - if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_FILE) { - return CLKS_FALSE; - } - - old_data = clks_fs_nodes[(u16)node_index].data; - old_size = clks_fs_nodes[(u16)node_index].size; - - if (old_size > (0xFFFFFFFFFFFFFFFFULL - size)) { - return CLKS_FALSE; - } - - new_size = old_size + size; - - if (new_size == 0ULL) { - return clks_fs_write_all(path, clks_fs_empty_file_data, 0ULL); - } - - merged = clks_kmalloc((usize)new_size); - - if (merged == CLKS_NULL) { - return CLKS_FALSE; - } - - if (old_size > 0ULL && old_data != CLKS_NULL) { - clks_memcpy(merged, old_data, (usize)old_size); - } - - if (size > 0ULL) { - clks_memcpy((u8 *)merged + (usize)old_size, data, (usize)size); - } - if (clks_fs_write_all(path, merged, new_size) == CLKS_FALSE) { - clks_kfree(merged); - return CLKS_FALSE; - } - - clks_kfree(merged); - return CLKS_TRUE; -} - -clks_bool clks_fs_remove(const char *path) { - char internal[CLKS_FS_PATH_MAX]; - i32 node_index; - u16 i; - - if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) { - return CLKS_FALSE; - } - - if (clks_disk_path_in_mount(path) == CLKS_TRUE) { - return clks_disk_remove(path); - } - - if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_fs_internal_in_temp_tree(internal) == CLKS_FALSE) { - return CLKS_FALSE; - } - - if (clks_strcmp(internal, "temp") == 0) { - return CLKS_FALSE; - } - - node_index = clks_fs_find_node_by_internal(internal); - - if (node_index < 0) { - return CLKS_FALSE; - } - - if (clks_fs_nodes[(u16)node_index].type == CLKS_FS_NODE_DIR) { - for (i = 0U; i < clks_fs_nodes_used; i++) { - if (clks_fs_nodes[i].used == CLKS_FALSE) { - continue; - } - - if (clks_fs_nodes[i].parent == (u16)node_index) { - return CLKS_FALSE; - } - } - } - - clks_fs_node_release_heap_data((u16)node_index); - - clks_fs_nodes[(u16)node_index].used = CLKS_FALSE; - clks_fs_nodes[(u16)node_index].type = CLKS_FS_NODE_FILE; - clks_fs_nodes[(u16)node_index].parent = 0U; - clks_fs_nodes[(u16)node_index].reserved = 0U; - clks_fs_nodes[(u16)node_index].data = CLKS_NULL; - clks_fs_nodes[(u16)node_index].size = 0ULL; - clks_fs_nodes[(u16)node_index].path[0] = '\0'; - - return CLKS_TRUE; -} - -u64 clks_fs_node_count(void) { - u16 i; - u64 used = 0ULL; - - if (clks_fs_ready == CLKS_FALSE) { - return 0ULL; - } - - for (i = 0U; i < clks_fs_nodes_used; i++) { - if (clks_fs_nodes[i].used == CLKS_TRUE) { - used++; - } - } - - if (clks_disk_is_mounted() == CLKS_TRUE) { - used += clks_disk_node_count(); - } - - return used; -} diff --git a/clks/kernel/storage/ramdisk.c b/clks/kernel/storage/ramdisk.c deleted file mode 100644 index 64562f8..0000000 --- a/clks/kernel/storage/ramdisk.c +++ /dev/null @@ -1,221 +0,0 @@ -#include -#include -#include -#include - -#define CLKS_TAR_BLOCK_SIZE 512ULL - -struct clks_tar_header { - char name[100]; - char mode[8]; - char uid[8]; - char gid[8]; - char size[12]; - char mtime[12]; - char chksum[8]; - char typeflag; - char linkname[100]; - char magic[6]; - char version[2]; - char uname[32]; - char gname[32]; - char devmajor[8]; - char devminor[8]; - char prefix[155]; - char pad[12]; -} CLKS_PACKED; - -static clks_bool clks_ramdisk_is_zero_block(const u8 *block) { - u64 i; - - for (i = 0; i < CLKS_TAR_BLOCK_SIZE; i++) { - if (block[i] != 0U) { - return CLKS_FALSE; - } - } - - return CLKS_TRUE; -} - -static usize clks_ramdisk_field_len(const char *field, usize max_len) { - usize i = 0; - - while (i < max_len && field[i] != '\0') { - i++; - } - - return i; -} - -static clks_bool clks_ramdisk_parse_octal_u64(const char *field, usize len, u64 *out_value) { - usize i = 0; - u64 value = 0ULL; - - if (out_value == CLKS_NULL) { - return CLKS_FALSE; - } - - while (i < len && (field[i] == ' ' || field[i] == '\0')) { - i++; - } - - for (; i < len; i++) { - char ch = field[i]; - - if (ch == ' ' || ch == '\0') { - break; - } - - if (ch < '0' || ch > '7') { - return CLKS_FALSE; - } - - if (value > (0xffffffffffffffffULL >> 3)) { - return CLKS_FALSE; - } - - value = (value << 3) + (u64)(ch - '0'); - } - - *out_value = value; - return CLKS_TRUE; -} - -static clks_bool clks_ramdisk_build_path(const struct clks_tar_header *hdr, char *out_path, usize out_path_size) { - char raw[CLKS_RAMDISK_PATH_MAX]; - usize prefix_len; - usize name_len; - usize cursor = 0; - usize read_pos = 0; - usize out_cursor = 0; - - if (hdr == CLKS_NULL || out_path == CLKS_NULL || out_path_size == 0U) { - return CLKS_FALSE; - } - - raw[0] = '\0'; - out_path[0] = '\0'; - - prefix_len = clks_ramdisk_field_len(hdr->prefix, sizeof(hdr->prefix)); - name_len = clks_ramdisk_field_len(hdr->name, sizeof(hdr->name)); - - if (name_len == 0U) { - return CLKS_FALSE; - } - - if (prefix_len != 0U) { - if (prefix_len + 1U >= sizeof(raw)) { - return CLKS_FALSE; - } - - clks_memcpy(raw, hdr->prefix, prefix_len); - cursor = prefix_len; - raw[cursor++] = '/'; - } - - if (cursor + name_len >= sizeof(raw)) { - return CLKS_FALSE; - } - - clks_memcpy(raw + cursor, hdr->name, name_len); - cursor += name_len; - raw[cursor] = '\0'; - - while ((raw[read_pos] == '.' && raw[read_pos + 1U] == '/') || raw[read_pos] == '/') { - if (raw[read_pos] == '.') { - read_pos += 2U; - } else { - read_pos++; - } - } - - while (raw[read_pos] != '\0' && out_cursor + 1U < out_path_size) { - out_path[out_cursor++] = raw[read_pos++]; - } - - if (raw[read_pos] != '\0') { - return CLKS_FALSE; - } - - while (out_cursor > 0U && out_path[out_cursor - 1U] == '/') { - out_cursor--; - } - - out_path[out_cursor] = '\0'; - - if (out_cursor == 0U) { - return CLKS_FALSE; - } - - return CLKS_TRUE; -} - -clks_bool clks_ramdisk_iterate(const void *image, u64 image_size, clks_ramdisk_iter_fn iter_fn, void *ctx) { - const u8 *bytes = (const u8 *)image; - u64 offset = 0ULL; - - if (image == CLKS_NULL || iter_fn == CLKS_NULL) { - return CLKS_FALSE; - } - - while (offset + CLKS_TAR_BLOCK_SIZE <= image_size) { - const struct clks_tar_header *hdr; - u64 payload_offset; - u64 file_size; - u64 aligned_size; - struct clks_ramdisk_entry entry; - clks_bool emit = CLKS_FALSE; - - hdr = (const struct clks_tar_header *)(bytes + offset); - - if (clks_ramdisk_is_zero_block((const u8 *)hdr) == CLKS_TRUE) { - break; - } - - if (clks_ramdisk_parse_octal_u64(hdr->size, sizeof(hdr->size), &file_size) == CLKS_FALSE) { - return CLKS_FALSE; - } - - payload_offset = offset + CLKS_TAR_BLOCK_SIZE; - - if (payload_offset > image_size) { - return CLKS_FALSE; - } - - if (file_size > (image_size - payload_offset)) { - return CLKS_FALSE; - } - - clks_memset(&entry, 0, sizeof(entry)); - - if (clks_ramdisk_build_path(hdr, entry.path, sizeof(entry.path)) == CLKS_TRUE) { - if (hdr->typeflag == '5') { - entry.type = CLKS_RAMDISK_ENTRY_DIR; - entry.data = CLKS_NULL; - entry.size = 0ULL; - emit = CLKS_TRUE; - } else if (hdr->typeflag == '\0' || hdr->typeflag == '0') { - entry.type = CLKS_RAMDISK_ENTRY_FILE; - entry.data = (const void *)(bytes + payload_offset); - entry.size = file_size; - emit = CLKS_TRUE; - } - } - - if (emit == CLKS_TRUE) { - if (iter_fn(&entry, ctx) == CLKS_FALSE) { - return CLKS_FALSE; - } - } - - aligned_size = (file_size + (CLKS_TAR_BLOCK_SIZE - 1ULL)) & ~(CLKS_TAR_BLOCK_SIZE - 1ULL); - - if (payload_offset + aligned_size < payload_offset) { - return CLKS_FALSE; - } - - offset = payload_offset + aligned_size; - } - - return CLKS_TRUE; -} diff --git a/clks/kernel/support/libc_compat.c b/clks/kernel/support/libc_compat.c deleted file mode 100644 index 209ae3c..0000000 --- a/clks/kernel/support/libc_compat.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -void *memcpy(void *dst, const void *src, usize count) { - return clks_memcpy(dst, src, count); -} - -void *memmove(void *dst, const void *src, usize count) { - return clks_memmove(dst, src, count); -} - -void *memset(void *dst, int value, usize count) { - return clks_memset(dst, value, count); -} - -int memcmp(const void *left, const void *right, usize count) { - const u8 *a = (const u8 *)left; - const u8 *b = (const u8 *)right; - usize i; - - for (i = 0U; i < count; i++) { - if (a[i] != b[i]) { - return (a[i] < b[i]) ? -1 : 1; - } - } - - return 0; -} - -int bcmp(const void *left, const void *right, usize count) { - return memcmp(left, right, count); -} - -usize strlen(const char *str) { - return clks_strlen(str); -} - -char *strchr(const char *str, int c) { - char ch = (char)c; - const char *cur = str; - - while (*cur != '\0') { - if (*cur == ch) { - return (char *)cur; - } - cur++; - } - - if (ch == '\0') { - return (char *)cur; - } - - return (char *)0; -} - -int abs(int value) { - return (value < 0) ? -value : value; -} - -long labs(long value) { - return (value < 0L) ? -value : value; -} diff --git a/clks/kernel/support/string.c b/clks/kernel/support/string.c deleted file mode 100644 index 539350d..0000000 --- a/clks/kernel/support/string.c +++ /dev/null @@ -1,70 +0,0 @@ -#include - -usize clks_strlen(const char *str) { - usize len = 0; - - while (str[len] != '\0') { - len++; - } - - return len; -} - -void *clks_memset(void *dst, int value, usize count) { - u8 *d = (u8 *)dst; - u8 v = (u8)value; - usize i; - - for (i = 0; i < count; i++) { - d[i] = v; - } - - return dst; -} - -void *clks_memcpy(void *dst, const void *src, usize count) { - u8 *d = (u8 *)dst; - const u8 *s = (const u8 *)src; - usize i; - - for (i = 0; i < count; i++) { - d[i] = s[i]; - } - - return dst; -} - -void *clks_memmove(void *dst, const void *src, usize count) { - u8 *d = (u8 *)dst; - const u8 *s = (const u8 *)src; - usize i; - - if (d == s || count == 0) { - return dst; - } - - if (d < s) { - for (i = 0; i < count; i++) { - d[i] = s[i]; - } - } else { - for (i = count; i != 0; i--) { - d[i - 1] = s[i - 1]; - } - } - - return dst; -} - -int clks_strcmp(const char *left, const char *right) { - usize i = 0; - - while (left[i] != '\0' && right[i] != '\0') { - if (left[i] != right[i]) { - return (int)((u8)left[i] - (u8)right[i]); - } - i++; - } - - return (int)((u8)left[i] - (u8)right[i]); -} \ No newline at end of file diff --git a/clks/rust/src/lib.rs b/clks/rust/src/lib.rs deleted file mode 100644 index c437b3c..0000000 --- a/clks/rust/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![no_std] - -use core::hint::spin_loop; -use core::panic::PanicInfo; - -extern "C" { - fn clks_tty_write(text: *const i8); -} - -const RUSTTEST_TEXT: &[u8] = b"Hello world!\n\0"; - -#[no_mangle] -pub extern "C" fn clks_rusttest_hello() { - unsafe { - clks_tty_write(RUSTTEST_TEXT.as_ptr() as *const i8); - } -} - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop { - spin_loop(); - } -} - -#[no_mangle] -pub extern "C" fn rust_eh_personality() {} \ No newline at end of file diff --git a/clks/third_party/miniz/miniz.h b/clks/third_party/miniz/miniz.h deleted file mode 100644 index 44572dc..0000000 --- a/clks/third_party/miniz/miniz.h +++ /dev/null @@ -1,618 +0,0 @@ -/* miniz.c 3.1.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated Oct. 13, 2013 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define - MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). - - * Low-level Deflate/Inflate implementation notes: - - Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or - greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses - approximately as well as zlib. - - Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function - coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or - into a memory block large enough to hold the entire file. - - The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. - - * zlib-style API notes: - - miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in - zlib replacement in many apps: - The z_stream struct, optional memory allocation callbacks - deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound - inflateInit/inflateInit2/inflate/inflateReset/inflateEnd - compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. - Supports raw deflate streams or standard zlib streams with adler-32 checking. - - Limitations: - The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. - I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but - there are no guarantees that miniz.c pulls this off perfectly. - - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by - Alex Evans. Supports 1-4 bytes/pixel images. - - * ZIP archive API notes: - - The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to - get the job done with minimal fuss. There are simple API's to retrieve file information, read files from - existing archives, create new archives, append new files to existing archives, or clone archive data from - one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), - or you can specify custom file read/write callbacks. - - - Archive reading: Just call this function to read a single file from a disk archive: - - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint zip_flags); - - For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central - directory is located and read as-is into memory, and subsequent file access only occurs when reading individual - files. - - - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - - The locate operation can optionally check file comments too, which (as one example) can be used to identify - multiple versions of the same file in an archive. This function uses a simple linear search through the central - directory, so it's not very fast. - - Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and - retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data - to disk and builds an exact image of the central directory in memory. The central directory image is written - all at once at the end of the archive file when the archive is finalized. - - The archive writer can optionally align each file's local header and file data to any power of 2 alignment, - which can be useful when the archive will be read from optical media. Also, the writer supports placing - arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still - readable by any ZIP tool. - - - Archive appending: The simple way to add a single file to an archive is to call this function: - - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - The archive will be created if it doesn't already exist, otherwise it'll be appended to. - Note the appending is done in-place and is not an atomic operation, so if something goes wrong - during the operation it's possible the archive could be left without a central directory (although the local - file headers and file data will be fine, so the archive will be recoverable). - - For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to - preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and - you're done. This is safe but requires a bunch of temporary disk space or heap memory. - - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), - append new files as needed, then finalize the archive which will write an updated central directory to the - original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a - possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - - - ZIP archive support limitations: - No spanning support. Extraction functions can only handle unencrypted, stored or deflated files. - Requires streams capable of seeking. - - * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the - below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - - * Important: For best perf. be sure to customize the below macros for your target platform: - #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 - #define MINIZ_LITTLE_ENDIAN 1 - #define MINIZ_HAS_64BIT_REGISTERS 1 - - * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz - uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files - (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). -*/ -#pragma once - -#include "miniz_export.h" - -#if defined(__STRICT_ANSI__) -#define MZ_FORCEINLINE -#elif defined(_MSC_VER) -#define MZ_FORCEINLINE __forceinline -#elif defined(__GNUC__) -#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) -#else -#define MZ_FORCEINLINE inline -#endif - -/* Defines to completely disable specific portions of miniz.c: - If all macros here are defined the only functionality remaining will be CRC-32 and adler-32. */ - -/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ -/*#define MINIZ_NO_STDIO */ - -/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ -/* get/set file times, and the C run-time funcs that get/set times won't be called. */ -/* The current downside is the times written to your archives will be from 1979. */ -/*#define MINIZ_NO_TIME */ - -/* Define MINIZ_NO_DEFLATE_APIS to disable all compression API's. */ -/*#define MINIZ_NO_DEFLATE_APIS */ - -/* Define MINIZ_NO_INFLATE_APIS to disable all decompression API's. */ -/*#define MINIZ_NO_INFLATE_APIS */ - -/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ -/*#define MINIZ_NO_ARCHIVE_APIS */ - -/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ -/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ - -/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ -/*#define MINIZ_NO_ZLIB_APIS */ - -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ -/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - -/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. - Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc - callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user - functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ -/*#define MINIZ_NO_MALLOC */ - -#ifdef MINIZ_NO_INFLATE_APIS -#define MINIZ_NO_ARCHIVE_APIS -#endif - -#ifdef MINIZ_NO_DEFLATE_APIS -#define MINIZ_NO_ARCHIVE_WRITING_APIS -#endif - -#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) -/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ -#define MINIZ_NO_TIME -#endif - -#include - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) -#include -#endif - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || \ - defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) -/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ -#define MINIZ_X86_OR_X64_CPU 1 -#else -#define MINIZ_X86_OR_X64_CPU 0 -#endif - -/* Set MINIZ_LITTLE_ENDIAN only if not set */ -#if !defined(MINIZ_LITTLE_ENDIAN) -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) - -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ -#define MINIZ_LITTLE_ENDIAN 1 -#else -#define MINIZ_LITTLE_ENDIAN 0 -#endif - -#else - -#if MINIZ_X86_OR_X64_CPU -#define MINIZ_LITTLE_ENDIAN 1 -#else -#define MINIZ_LITTLE_ENDIAN 0 -#endif - -#endif -#endif - -/* Using unaligned loads and stores causes errors when using UBSan */ -#if defined(__has_feature) -#if __has_feature(undefined_behavior_sanitizer) -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -#endif -#endif - -/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ -#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) -#if MINIZ_X86_OR_X64_CPU -/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned - * addresses. */ -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -#define MINIZ_UNALIGNED_USE_MEMCPY -#else -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -#endif -#endif - -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || \ - defined(__ia64__) || defined(__x86_64__) -/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler - * generated calls to helper functions). */ -#define MINIZ_HAS_64BIT_REGISTERS 1 -#else -#define MINIZ_HAS_64BIT_REGISTERS 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- zlib-style API Definitions. */ - -/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can - * be either 32 or 64-bits! */ -typedef unsigned long mz_ulong; - -/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC - * macro) to release a block allocated from the heap. */ -MINIZ_EXPORT void mz_free(void *p); - -#define MZ_ADLER32_INIT (1) -/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ -MINIZ_EXPORT mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - -#define MZ_CRC32_INIT (0) -/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ -MINIZ_EXPORT mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - -/* Compression strategies. */ -enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; - -/* Method */ -#define MZ_DEFLATED 8 - -/* Heap allocation callbacks. -Note that mz_alloc_func parameter types purposely differ from zlib's: items/size is size_t, not unsigned long. */ -typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void (*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); - -/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and - * may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ -enum { - MZ_NO_COMPRESSION = 0, - MZ_BEST_SPEED = 1, - MZ_BEST_COMPRESSION = 9, - MZ_UBER_COMPRESSION = 10, - MZ_DEFAULT_LEVEL = 6, - MZ_DEFAULT_COMPRESSION = -1 -}; - -#define MZ_VERSION "11.3.1" -#define MZ_VERNUM 0xB301 -#define MZ_VER_MAJOR 11 -#define MZ_VER_MINOR 3 -#define MZ_VER_REVISION 1 -#define MZ_VER_SUBREVISION 0 - -#ifndef MINIZ_NO_ZLIB_APIS - -/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer - * to the zlib docs). */ -enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; - -/* Return status codes. MZ_PARAM_ERROR is non-standard. */ -enum { - MZ_OK = 0, - MZ_STREAM_END = 1, - MZ_NEED_DICT = 2, - MZ_ERRNO = -1, - MZ_STREAM_ERROR = -2, - MZ_DATA_ERROR = -3, - MZ_MEM_ERROR = -4, - MZ_BUF_ERROR = -5, - MZ_VERSION_ERROR = -6, - MZ_PARAM_ERROR = -10000 -}; - -/* Window bits */ -#define MZ_DEFAULT_WINDOW_BITS 15 - -struct mz_internal_state; - -/* Compression/decompression stream struct. */ -typedef struct mz_stream_s { - const unsigned char *next_in; /* pointer to next byte to read */ - unsigned int avail_in; /* number of bytes available at next_in */ - mz_ulong total_in; /* total number of bytes consumed so far */ - - unsigned char *next_out; /* pointer to next byte to write */ - unsigned int avail_out; /* number of bytes that can be written to next_out */ - mz_ulong total_out; /* total number of bytes produced so far */ - - char *msg; /* error msg (unused) */ - struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ - - mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ - mz_free_func zfree; /* optional heap free function (defaults to free) */ - void *opaque; /* heap alloc function user pointer */ - - int data_type; /* data_type (unused) */ - mz_ulong adler; /* adler32 of the source or uncompressed data */ - mz_ulong reserved; /* not used */ -} mz_stream; - -typedef mz_stream *mz_streamp; - -/* Returns the version string of miniz.c. */ -MINIZ_EXPORT const char *mz_version(void); - -#ifndef MINIZ_NO_DEFLATE_APIS - -/* mz_deflateInit() initializes a compressor with default options: */ -/* Parameters: */ -/* pStream must point to an initialized mz_stream struct. */ -/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ -/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. - */ -/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are - * defined.) */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if the input parameters are bogus. */ -/* MZ_MEM_ERROR on out of memory. */ -MINIZ_EXPORT int mz_deflateInit(mz_streamp pStream, int level); - -/* mz_deflateInit2() is like mz_deflate(), except with more control: */ -/* Additional parameters: */ -/* method must be MZ_DEFLATED */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or - * -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ -/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ -MINIZ_EXPORT int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, - int strategy); - -/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by - * mz_deflateInit()/mz_deflateInit2(). */ -MINIZ_EXPORT int mz_deflateReset(mz_streamp pStream); - -/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. - */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and - * avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ -/* Return values: */ -/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be - * written but the output buffer is full). */ -/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the - * stream anymore. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the - * input buffer or free up some output space and try again.) */ -MINIZ_EXPORT int mz_deflate(mz_streamp pStream, int flush); - -/* mz_deflateEnd() deinitializes a compressor: */ -/* Return values: */ -/* MZ_OK on success. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -MINIZ_EXPORT int mz_deflateEnd(mz_streamp pStream); - -/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by - * deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ -MINIZ_EXPORT mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - -/* Single-call compression functions mz_compress() and mz_compress2(): */ -/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ -MINIZ_EXPORT int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong source_len); -MINIZ_EXPORT int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong source_len, int level); - -/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling - * mz_compress(). */ -MINIZ_EXPORT mz_ulong mz_compressBound(mz_ulong source_len); - -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ - -#ifndef MINIZ_NO_INFLATE_APIS - -/* Initializes a decompressor. */ -MINIZ_EXPORT int mz_inflateInit(mz_streamp pStream); - -/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not - * the stream has been wrapped with a zlib header/footer: */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ -MINIZ_EXPORT int mz_inflateInit2(mz_streamp pStream, int window_bits); - -/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by - * mz_inflateInit()/mz_inflateInit2(). */ -MINIZ_EXPORT int mz_inflateReset(mz_streamp pStream); - -/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to - * the output as possible. */ -/* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and - * avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ -/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to - * decompress the entire stream in a single call (this is slightly faster). */ -/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that - * the output buffer is large enough to hold the rest of the decompressed data. */ -/* Return values: */ -/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the - * output buffer is full. */ -/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the - * adler-32 of the decompressed data has also been verified. */ -/* MZ_STREAM_ERROR if the stream is bogus. */ -/* MZ_DATA_ERROR if the deflate stream is invalid. */ -/* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input - * to continue, or if the output buffer is not large enough. Call mz_inflate() again */ -/* with more input data, or with more room in the output buffer (except when using single call decompression, - * described above). */ -MINIZ_EXPORT int mz_inflate(mz_streamp pStream, int flush); - -/* Deinitializes a decompressor. */ -MINIZ_EXPORT int mz_inflateEnd(mz_streamp pStream); - -/* Single-call decompression. */ -/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ -MINIZ_EXPORT int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong source_len); -MINIZ_EXPORT int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong *pSource_len); -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ - -/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ -MINIZ_EXPORT const char *mz_error(int err); - -/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset - * of zlib that miniz.c supports. */ -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES -typedef unsigned char Byte; -typedef unsigned int uInt; -typedef mz_ulong uLong; -typedef Byte Bytef; -typedef uInt uIntf; -typedef char charf; -typedef int intf; -typedef void *voidpf; -typedef uLong uLongf; -typedef void *voidp; -typedef void *const voidpc; -#define Z_NULL 0 -#define Z_NO_FLUSH MZ_NO_FLUSH -#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH -#define Z_SYNC_FLUSH MZ_SYNC_FLUSH -#define Z_FULL_FLUSH MZ_FULL_FLUSH -#define Z_FINISH MZ_FINISH -#define Z_BLOCK MZ_BLOCK -#define Z_OK MZ_OK -#define Z_STREAM_END MZ_STREAM_END -#define Z_NEED_DICT MZ_NEED_DICT -#define Z_ERRNO MZ_ERRNO -#define Z_STREAM_ERROR MZ_STREAM_ERROR -#define Z_DATA_ERROR MZ_DATA_ERROR -#define Z_MEM_ERROR MZ_MEM_ERROR -#define Z_BUF_ERROR MZ_BUF_ERROR -#define Z_VERSION_ERROR MZ_VERSION_ERROR -#define Z_PARAM_ERROR MZ_PARAM_ERROR -#define Z_NO_COMPRESSION MZ_NO_COMPRESSION -#define Z_BEST_SPEED MZ_BEST_SPEED -#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION -#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION -#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY -#define Z_FILTERED MZ_FILTERED -#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY -#define Z_RLE MZ_RLE -#define Z_FIXED MZ_FIXED -#define Z_DEFLATED MZ_DEFLATED -#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS -/* See mz_alloc_func */ -typedef void *(*alloc_func)(void *opaque, size_t items, size_t size); -/* See mz_free_func */ -typedef void (*free_func)(void *opaque, void *address); - -#define internal_state mz_internal_state -#define z_stream mz_stream - -#ifndef MINIZ_NO_DEFLATE_APIS -/* Compatiblity with zlib API. See called functions for documentation */ -static MZ_FORCEINLINE int deflateInit(mz_streamp pStream, int level) { - return mz_deflateInit(pStream, level); -} -static MZ_FORCEINLINE int deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, - int strategy) { - return mz_deflateInit2(pStream, level, method, window_bits, mem_level, strategy); -} -static MZ_FORCEINLINE int deflateReset(mz_streamp pStream) { - return mz_deflateReset(pStream); -} -static MZ_FORCEINLINE int deflate(mz_streamp pStream, int flush) { - return mz_deflate(pStream, flush); -} -static MZ_FORCEINLINE int deflateEnd(mz_streamp pStream) { - return mz_deflateEnd(pStream); -} -static MZ_FORCEINLINE mz_ulong deflateBound(mz_streamp pStream, mz_ulong source_len) { - return mz_deflateBound(pStream, source_len); -} -static MZ_FORCEINLINE int compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong source_len) { - return mz_compress(pDest, pDest_len, pSource, source_len); -} -static MZ_FORCEINLINE int compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong source_len, int level) { - return mz_compress2(pDest, pDest_len, pSource, source_len, level); -} -static MZ_FORCEINLINE mz_ulong compressBound(mz_ulong source_len) { - return mz_compressBound(source_len); -} -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ - -#ifndef MINIZ_NO_INFLATE_APIS -/* Compatiblity with zlib API. See called functions for documentation */ -static MZ_FORCEINLINE int inflateInit(mz_streamp pStream) { - return mz_inflateInit(pStream); -} - -static MZ_FORCEINLINE int inflateInit2(mz_streamp pStream, int window_bits) { - return mz_inflateInit2(pStream, window_bits); -} - -static MZ_FORCEINLINE int inflateReset(mz_streamp pStream) { - return mz_inflateReset(pStream); -} - -static MZ_FORCEINLINE int inflate(mz_streamp pStream, int flush) { - return mz_inflate(pStream, flush); -} - -static MZ_FORCEINLINE int inflateEnd(mz_streamp pStream) { - return mz_inflateEnd(pStream); -} - -static MZ_FORCEINLINE int uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong source_len) { - return mz_uncompress(pDest, pDest_len, pSource, source_len); -} - -static MZ_FORCEINLINE int uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, - mz_ulong *pSource_len) { - return mz_uncompress2(pDest, pDest_len, pSource, pSource_len); -} -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ - -static MZ_FORCEINLINE mz_ulong crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len) { - return mz_crc32(crc, ptr, buf_len); -} - -static MZ_FORCEINLINE mz_ulong adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { - return mz_adler32(adler, ptr, buf_len); -} - -#define MAX_WBITS 15 -#define MAX_MEM_LEVEL 9 - -static MZ_FORCEINLINE const char *zError(int err) { - return mz_error(err); -} -#define ZLIB_VERSION MZ_VERSION -#define ZLIB_VERNUM MZ_VERNUM -#define ZLIB_VER_MAJOR MZ_VER_MAJOR -#define ZLIB_VER_MINOR MZ_VER_MINOR -#define ZLIB_VER_REVISION MZ_VER_REVISION -#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION - -#define zlibVersion mz_version -#define zlib_version mz_version() -#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ - -#endif /* MINIZ_NO_ZLIB_APIS */ - -#ifdef __cplusplus -} -#endif - -#include "miniz_common.h" -#include "miniz_tdef.h" -#include "miniz_tinfl.h" -#include "miniz_zip.h" diff --git a/clks/third_party/miniz/miniz_common.h b/clks/third_party/miniz/miniz_common.h deleted file mode 100644 index d8e4882..0000000 --- a/clks/third_party/miniz/miniz_common.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include "miniz_export.h" - -/* ------------------- Types and macros */ -typedef unsigned char mz_uint8; -typedef int16_t mz_int16; -typedef uint16_t mz_uint16; -typedef uint32_t mz_uint32; -typedef uint32_t mz_uint; -typedef int64_t mz_int64; -typedef uint64_t mz_uint64; -typedef int mz_bool; - -#define MZ_FALSE (0) -#define MZ_TRUE (1) - -/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ -#ifdef _MSC_VER -#define MZ_MACRO_END while (0, 0) -#else -#define MZ_MACRO_END while (0) -#endif - -#ifdef MINIZ_NO_STDIO -#define MZ_FILE void * -#else -#include -#define MZ_FILE FILE -#endif /* #ifdef MINIZ_NO_STDIO */ - -#ifdef MINIZ_NO_TIME -typedef struct mz_dummy_time_t_tag { - mz_uint32 m_dummy1; - mz_uint32 m_dummy2; -} mz_dummy_time_t; -#define MZ_TIME_T mz_dummy_time_t -#else -#define MZ_TIME_T time_t -#endif - -#define MZ_ASSERT(x) assert(x) - -#ifdef MINIZ_NO_MALLOC -#define MZ_MALLOC(x) NULL -#define MZ_FREE(x) (void)x, ((void)0) -#define MZ_REALLOC(p, x) NULL -#else -#define MZ_MALLOC(x) malloc(x) -#define MZ_FREE(x) free(x) -#define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) -#define MZ_CLEAR_ARR(obj) memset((obj), 0, sizeof(obj)) -#define MZ_CLEAR_PTR(obj) memset((obj), 0, sizeof(*obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) -#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else -#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) -#define MZ_READ_LE32(p) \ - ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \ - ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#define MZ_READ_LE64(p) \ - (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) - -#ifdef __cplusplus -extern "C" { -#endif - -extern MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); -extern MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address); -extern MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); - -#define MZ_UINT16_MAX (0xFFFFU) -#define MZ_UINT32_MAX (0xFFFFFFFFU) - -#ifdef __cplusplus -} -#endif diff --git a/clks/third_party/miniz/miniz_export.h b/clks/third_party/miniz/miniz_export.h deleted file mode 100644 index 619fdff..0000000 --- a/clks/third_party/miniz/miniz_export.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef MINIZ_EXPORT_H -#define MINIZ_EXPORT_H - -#define MINIZ_EXPORT - -#endif diff --git a/clks/third_party/miniz/miniz_support.c b/clks/third_party/miniz/miniz_support.c deleted file mode 100644 index 33d71d3..0000000 --- a/clks/third_party/miniz/miniz_support.c +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef NDEBUG -#define NDEBUG 1 -#endif - -#ifndef MINIZ_NO_STDIO -#define MINIZ_NO_STDIO 1 -#endif - -#ifndef MINIZ_NO_INFLATE_APIS -#define MINIZ_NO_INFLATE_APIS 1 -#endif - -#ifndef MINIZ_NO_TIME -#define MINIZ_NO_TIME 1 -#endif - -#ifndef MINIZ_NO_MALLOC -#define MINIZ_NO_MALLOC 1 -#endif - -#ifndef MINIZ_NO_ZLIB_APIS -#define MINIZ_NO_ZLIB_APIS 1 -#endif - -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES -#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1 -#endif - -#include "miniz.h" - -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { - mz_uint32 s1 = (mz_uint32)(adler & 0xFFFFU); - mz_uint32 s2 = (mz_uint32)((adler >> 16) & 0xFFFFU); - size_t i; - - if (ptr == 0) { - return MZ_ADLER32_INIT; - } - - for (i = 0; i < buf_len; i++) { - s1 += (mz_uint32)ptr[i]; - if (s1 >= 65521U) { - s1 -= 65521U; - } - - s2 += s1; - if (s2 >= 65521U) { - s2 -= 65521U; - } - } - - return ((mz_ulong)s2 << 16) | (mz_ulong)s1; -} - -mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len) { - mz_uint32 cur = (mz_uint32)crc ^ 0xFFFFFFFFU; - size_t i; - unsigned int bit; - - if (ptr == 0) { - return MZ_CRC32_INIT; - } - - for (i = 0; i < buf_len; i++) { - cur ^= (mz_uint32)ptr[i]; - for (bit = 0U; bit < 8U; bit++) { - if ((cur & 1U) != 0U) { - cur = (cur >> 1) ^ 0xEDB88320U; - } else { - cur >>= 1; - } - } - } - - return (mz_ulong)(cur ^ 0xFFFFFFFFU); -} diff --git a/clks/third_party/miniz/miniz_tdef.c b/clks/third_party/miniz/miniz_tdef.c deleted file mode 100644 index 3be6188..0000000 --- a/clks/third_party/miniz/miniz_tdef.c +++ /dev/null @@ -1,1506 +0,0 @@ -/************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - -#ifndef NDEBUG -#define NDEBUG 1 -#endif - -#ifndef MINIZ_NO_STDIO -#define MINIZ_NO_STDIO 1 -#endif - -#ifndef MINIZ_NO_INFLATE_APIS -#define MINIZ_NO_INFLATE_APIS 1 -#endif - -#ifndef MINIZ_NO_TIME -#define MINIZ_NO_TIME 1 -#endif - -#ifndef MINIZ_NO_MALLOC -#define MINIZ_NO_MALLOC 1 -#endif - -#ifndef MINIZ_NO_ZLIB_APIS -#define MINIZ_NO_ZLIB_APIS 1 -#endif - -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES -#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1 -#endif - -#include "miniz.h" - -#ifndef MINIZ_NO_DEFLATE_APIS - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------- Low-level Compression (independent from all decompression API's) */ - -/* Purposely making these tables static for faster init and thread safety. */ -static const mz_uint16 s_tdefl_len_sym[256] = { - 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, - 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, - 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, - 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, - 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285}; - -static const mz_uint8 s_tdefl_len_extra[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0}; - -static const mz_uint8 s_tdefl_small_dist_sym[512] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, - 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; - -static const mz_uint8 s_tdefl_small_dist_extra[512] = { - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; - -static const mz_uint8 s_tdefl_large_dist_sym[128] = { - 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, - 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29}; - -static const mz_uint8 s_tdefl_large_dist_extra[128] = { - 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; - -/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ -typedef struct { - mz_uint16 m_key, m_sym_index; -} tdefl_sym_freq; -static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) { - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; - tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; - MZ_CLEAR_ARR(hist); - for (i = 0; i < num_syms; i++) { - mz_uint freq = pSyms0[i].m_key; - hist[freq & 0xFF]++; - hist[256 + ((freq >> 8) & 0xFF)]++; - } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) - total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { - const mz_uint32 *pHist = &hist[pass << 8]; - mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) { - offsets[i] = cur_ofs; - cur_ofs += pHist[i]; - } - for (i = 0; i < num_syms; i++) - pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { - tdefl_sym_freq *t = pCur_syms; - pCur_syms = pNew_syms; - pNew_syms = t; - } - } - return pCur_syms; -} - -/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, - * jyrki@diku.dk, November 1996. */ -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { - int root, leaf, next, avbl, used, dpth; - if (n == 0) - return; - else if (n == 1) { - A[0].m_key = 1; - return; - } - A[0].m_key += A[1].m_key; - root = 0; - leaf = 2; - for (next = 1; next < n - 1; next++) { - if (leaf >= n || A[root].m_key < A[leaf].m_key) { - A[next].m_key = A[root].m_key; - A[root++].m_key = (mz_uint16)next; - } else - A[next].m_key = A[leaf++].m_key; - if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { - A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); - A[root++].m_key = (mz_uint16)next; - } else - A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); - } - A[n - 2].m_key = 0; - for (next = n - 3; next >= 0; next--) - A[next].m_key = A[A[next].m_key].m_key + 1; - avbl = 1; - used = dpth = 0; - root = n - 2; - next = n - 1; - while (avbl > 0) { - while (root >= 0 && (int)A[root].m_key == dpth) { - used++; - root--; - } - while (avbl > used) { - A[next--].m_key = (mz_uint16)(dpth); - avbl--; - } - avbl = 2 * used; - dpth++; - used = 0; - } -} - -/* Limits canonical Huffman code table's max code size. */ -enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { - int i; - mz_uint32 total = 0; - if (code_list_len <= 1) - return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) - pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) - total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) { - pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) - if (pNum_codes[i]) { - pNum_codes[i]--; - pNum_codes[i + 1] += 2; - break; - } - total--; - } -} - -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, - int static_table) { - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; - mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; - MZ_CLEAR_ARR(num_codes); - if (static_table) { - for (i = 0; i < table_len; i++) - num_codes[d->m_huff_code_sizes[table_num][i]]++; - } else { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; - int num_used_syms = 0; - const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) - if (pSym_count[i]) { - syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; - syms0[num_used_syms++].m_sym_index = (mz_uint16)i; - } - - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); - tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - - for (i = 0; i < num_used_syms; i++) - num_codes[pSyms[i].m_key]++; - - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - - MZ_CLEAR_ARR(d->m_huff_code_sizes[table_num]); - MZ_CLEAR_ARR(d->m_huff_codes[table_num]); - for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) - d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); - } - - next_code[1] = 0; - for (j = 0, i = 2; i <= code_size_limit; i++) - next_code[i] = j = ((j + num_codes[i - 1]) << 1); - - for (i = 0; i < table_len; i++) { - mz_uint rev_code = 0, code, code_size; - if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) - continue; - code = next_code[code_size]++; - for (l = code_size; l > 0; l--, code >>= 1) - rev_code = (rev_code << 1) | (code & 1); - d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; - } -} - -#define TDEFL_PUT_BITS(b, l) \ - do { \ - mz_uint bits = b; \ - mz_uint len = l; \ - MZ_ASSERT(bits <= ((1U << len) - 1U)); \ - d->m_bit_buffer |= (bits << d->m_bits_in); \ - d->m_bits_in += len; \ - while (d->m_bits_in >= 8) { \ - if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ - *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ - d->m_bit_buffer >>= 8; \ - d->m_bits_in -= 8; \ - } \ - } \ - MZ_MACRO_END - -#define TDEFL_RLE_PREV_CODE_SIZE() \ - { \ - if (rle_repeat_count) { \ - if (rle_repeat_count < 3) { \ - d->m_huff_count[2][prev_code_size] = \ - (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ - while (rle_repeat_count--) \ - packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ - } else { \ - d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 16; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ - } \ - rle_repeat_count = 0; \ - } \ - } - -#define TDEFL_RLE_ZERO_CODE_SIZE() \ - { \ - if (rle_z_count) { \ - if (rle_z_count < 3) { \ - d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ - while (rle_z_count--) \ - packed_code_sizes[num_packed_code_sizes++] = 0; \ - } else if (rle_z_count <= 10) { \ - d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 17; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ - } else { \ - d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ - packed_code_sizes[num_packed_code_sizes++] = 18; \ - packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ - } \ - rle_z_count = 0; \ - } \ - } - -static const mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, - 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -static void tdefl_start_dynamic_block(tdefl_compressor *d) { - int num_lit_codes, num_dist_codes, num_bit_lengths; - mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], - packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; - - d->m_huff_count[0][256] = 1; - - tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); - tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) - if (d->m_huff_code_sizes[0][num_lit_codes - 1]) - break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) - if (d->m_huff_code_sizes[1][num_dist_codes - 1]) - break; - - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; - num_packed_code_sizes = 0; - rle_z_count = 0; - rle_repeat_count = 0; - - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) { - mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) { - TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - } else { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); - packed_code_sizes[num_packed_code_sizes++] = code_size; - } else if (++rle_repeat_count == 6) { - TDEFL_RLE_PREV_CODE_SIZE(); - } - } - prev_code_size = code_size; - } - if (rle_repeat_count) { - TDEFL_RLE_PREV_CODE_SIZE(); - } else { - TDEFL_RLE_ZERO_CODE_SIZE(); - } - - tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); - - TDEFL_PUT_BITS(2, 2); - - TDEFL_PUT_BITS(num_lit_codes - 257, 5); - TDEFL_PUT_BITS(num_dist_codes - 1, 5); - - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) - if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) - break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); - TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) - TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; - MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); - TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) - TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); - } -} - -static void tdefl_start_static_block(tdefl_compressor *d) { - mz_uint i; - mz_uint8 *p = &d->m_huff_code_sizes[0][0]; - - for (i = 0; i <= 143; ++i) - *p++ = 8; - for (; i <= 255; ++i) - *p++ = 9; - for (; i <= 279; ++i) - *p++ = 7; - for (; i <= 287; ++i) - *p++ = 8; - - memset(d->m_huff_code_sizes[1], 5, 32); - - tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); - tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); - - TDEFL_PUT_BITS(1, 2); -} - -static const mz_uint mz_bitmasks[17] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { - mz_uint flags; - mz_uint8 *pLZ_codes; - mz_uint8 *pOutput_buf = d->m_pOutput_buf; - mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; - mz_uint64 bit_buffer = d->m_bit_buffer; - mz_uint bits_in = d->m_bits_in; - -#define TDEFL_PUT_BITS_FAST(b, l) \ - { \ - bit_buffer |= (((mz_uint64)(b)) << bits_in); \ - bits_in += (l); \ - } - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - - if (flags & 1) { - mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0]; - mz_uint match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], - d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - n0 = s_tdefl_small_dist_extra[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[match_dist >> 8]; - n1 = s_tdefl_large_dist_extra[match_dist >> 8]; - sym = (match_dist < 512) ? s0 : s1; - num_extra_bits = (match_dist < 512) ? n0 : n1; - - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } else { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - } - - if (pOutput_buf >= d->m_pOutput_buf_end) - return MZ_FALSE; - - memcpy(pOutput_buf, &bit_buffer, sizeof(mz_uint64)); - pOutput_buf += (bits_in >> 3); - bit_buffer >>= (bits_in & ~7); - bits_in &= 7; - } - -#undef TDEFL_PUT_BITS_FAST - - d->m_pOutput_buf = pOutput_buf; - d->m_bits_in = 0; - d->m_bit_buffer = 0; - - while (bits_in) { - mz_uint32 n = MZ_MIN(bits_in, 16); - TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); - bit_buffer >>= n; - bits_in -= n; - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#else -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { - mz_uint flags; - mz_uint8 *pLZ_codes; - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - if (flags & 1) { - mz_uint sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); - pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], - d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - if (match_dist < 512) { - sym = s_tdefl_small_dist_sym[match_dist]; - num_extra_bits = s_tdefl_small_dist_extra[match_dist]; - } else { - sym = s_tdefl_large_dist_sym[match_dist >> 8]; - num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; - } - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } else { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ - -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { - if (static_block) - tdefl_start_static_block(d); - else - tdefl_start_dynamic_block(d); - return tdefl_compress_lz_codes(d); -} - -static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; - -static int tdefl_flush_block(tdefl_compressor *d, int flush) { - mz_uint saved_bit_buf, saved_bits_in; - mz_uint8 *pSaved_output_buf; - mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && - (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = - ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) - ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) - : d->m_output_buf; - - d->m_pOutput_buf = pOutput_buf_start; - d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; - - MZ_ASSERT(!d->m_output_flush_remaining); - d->m_output_flush_ofs = 0; - d->m_output_flush_remaining = 0; - - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); - d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { - const mz_uint8 cmf = 0x78; - mz_uint8 flg, flevel = 3; - mz_uint header, i, mz_un = sizeof(s_tdefl_num_probes) / sizeof(mz_uint); - - /* Determine compression level by reversing the process in tdefl_create_comp_flags_from_zip_params() */ - for (i = 0; i < mz_un; i++) - if (s_tdefl_num_probes[i] == (d->m_flags & 0xFFF)) - break; - - if (i < 2) - flevel = 0; - else if (i < 6) - flevel = 1; - else if (i == 6) - flevel = 2; - - header = cmf << 8 | (flevel << 6); - header += 31 - (header % 31); - flg = header & 0xFF; - - TDEFL_PUT_BITS(cmf, 8); - TDEFL_PUT_BITS(flg, 8); - } - - TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - - pSaved_output_buf = d->m_pOutput_buf; - saved_bit_buf = d->m_bit_buffer; - saved_bits_in = d->m_bits_in; - - if (!use_raw_block) - comp_block_succeeded = - tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); - - /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ - if (((use_raw_block) || - ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { - mz_uint i; - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { - TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); - } - for (i = 0; i < d->m_total_lz_bytes; ++i) { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); - } - } - /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output - buffer when using dynamic codes. */ - else if (!comp_block_succeeded) { - d->m_pOutput_buf = pSaved_output_buf; - d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - tdefl_compress_block(d, MZ_TRUE); - } - - if (flush) { - if (flush == TDEFL_FINISH) { - if (d->m_bits_in) { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { - mz_uint i, a = d->m_adler32; - for (i = 0; i < 4; i++) { - TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); - a <<= 8; - } - } - } else { - mz_uint i, z = 0; - TDEFL_PUT_BITS(0, 3); - if (d->m_bits_in) { - TDEFL_PUT_BITS(0, 8 - d->m_bits_in); - } - for (i = 2; i; --i, z ^= 0xFFFF) { - TDEFL_PUT_BITS(z & 0xFFFF, 16); - } - } - } - - MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - d->m_num_flags_left = 8; - d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; - d->m_total_lz_bytes = 0; - d->m_block_index++; - - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { - if (d->m_pPut_buf_func) { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) - return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } else if (pOutput_buf_start == d->m_output_buf) { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); - d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) { - d->m_output_flush_ofs = bytes_to_copy; - d->m_output_flush_remaining = n; - } - } else { - d->m_out_buf_ofs += n; - } - } - - return d->m_output_flush_remaining; -} - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES -#ifdef MINIZ_UNALIGNED_USE_MEMCPY -static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8 *p) { - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16 *p) { - mz_uint16 ret; - memcpy(&ret, p, sizeof(mz_uint16)); - return ret; -} -#else -#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) -#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) -#endif -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, - mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, - next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) { - for (;;) { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - q = (const mz_uint16 *)(d->m_dict + probe_pos); - if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) - continue; - p = s; - probe_len = 32; - do { - } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); - if (!probe_len) { - *pMatch_dist = dist; - *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); - break; - } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > - match_len) { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) - break; - c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - } - } -} -#else -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, - mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, - next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint8 *s = d->m_dict + pos, *p, *q; - mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); - if (max_match_len <= match_len) - return; - for (;;) { - for (;;) { - if (--num_probes_left == 0) - return; -#define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ - return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ - break; - TDEFL_PROBE; - TDEFL_PROBE; - TDEFL_PROBE; - } - if (!dist) - break; - p = s; - q = d->m_dict + probe_pos; - for (probe_len = 0; probe_len < max_match_len; probe_len++) - if (*p++ != *q++) - break; - if (probe_len > match_len) { - *pMatch_dist = dist; - if ((*pMatch_len = match_len = probe_len) == max_match_len) - return; - c0 = d->m_dict[pos + match_len]; - c1 = d->m_dict[pos + match_len - 1]; - } - } -} -#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -#ifdef MINIZ_UNALIGNED_USE_MEMCPY -static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8 *p) { - mz_uint32 ret; - memcpy(&ret, p, sizeof(mz_uint32)); - return ret; -} -#else -#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p) -#endif -static mz_bool tdefl_compress_fast(tdefl_compressor *d) { - /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for - * applications where raw throughput is valued more highly than ratio. */ - mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, - total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; - mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; - mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - - while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { - const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; - mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - mz_uint num_bytes_to_process = - (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); - d->m_src_buf_left -= num_bytes_to_process; - lookahead_size += num_bytes_to_process; - - while (num_bytes_to_process) { - mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); - memcpy(d->m_dict + dst_pos, d->m_pSrc, n); - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, - MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); - d->m_pSrc += n; - dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; - num_bytes_to_process -= n; - } - - dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); - if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) - break; - - while (lookahead_size >= 4) { - mz_uint cur_match_dist, cur_match_len = 1; - mz_uint8 *pCur_dict = d->m_dict + cur_pos; - mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF; - mz_uint hash = - (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; - mz_uint probe_pos = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)lookahead_pos; - - if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && - ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == - first_trigram)) { - const mz_uint16 *p = (const mz_uint16 *)pCur_dict; - const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); - mz_uint32 probe_len = 32; - do { - } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && - (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); - cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + - (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); - if (!probe_len) - cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - - if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || - ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) { - cur_match_len = 1; - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } else { - mz_uint32 s0, s1; - cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - - MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && - (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - - cur_match_dist--; - - pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); -#ifdef MINIZ_UNALIGNED_USE_MEMCPY - memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist)); -#else - *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; -#endif - pLZ_code_buf += 3; - *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - - s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; - s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; - d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - - d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; - } - } else { - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - - if (--num_flags_left == 0) { - num_flags_left = 8; - pLZ_flags = pLZ_code_buf++; - } - - total_lz_bytes += cur_match_len; - lookahead_pos += cur_match_len; - dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; - MZ_ASSERT(lookahead_size >= cur_match_len); - lookahead_size -= cur_match_len; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { - int n; - d->m_lookahead_pos = lookahead_pos; - d->m_lookahead_size = lookahead_size; - d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; - d->m_pLZ_code_buf = pLZ_code_buf; - d->m_pLZ_flags = pLZ_flags; - d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; - pLZ_code_buf = d->m_pLZ_code_buf; - pLZ_flags = d->m_pLZ_flags; - num_flags_left = d->m_num_flags_left; - } - } - - while (lookahead_size) { - mz_uint8 lit = d->m_dict[cur_pos]; - - total_lz_bytes++; - *pLZ_code_buf++ = lit; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - if (--num_flags_left == 0) { - num_flags_left = 8; - pLZ_flags = pLZ_code_buf++; - } - - d->m_huff_count[0][lit]++; - - lookahead_pos++; - dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - lookahead_size--; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { - int n; - d->m_lookahead_pos = lookahead_pos; - d->m_lookahead_size = lookahead_size; - d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; - d->m_pLZ_code_buf = pLZ_code_buf; - d->m_pLZ_flags = pLZ_flags; - d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; - pLZ_code_buf = d->m_pLZ_code_buf; - pLZ_flags = d->m_pLZ_flags; - num_flags_left = d->m_num_flags_left; - } - } - } - - d->m_lookahead_pos = lookahead_pos; - d->m_lookahead_size = lookahead_size; - d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; - d->m_pLZ_code_buf = pLZ_code_buf; - d->m_pLZ_flags = pLZ_flags; - d->m_num_flags_left = num_flags_left; - return MZ_TRUE; -} -#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { - d->m_total_lz_bytes++; - *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); - if (--d->m_num_flags_left == 0) { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - d->m_huff_count[0][lit]++; -} - -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { - mz_uint32 s0, s1; - - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); - - d->m_total_lz_bytes += match_len; - - d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); - - match_dist -= 1; - d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); - d->m_pLZ_code_buf += 3; - - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); - if (--d->m_num_flags_left == 0) { - d->m_num_flags_left = 8; - d->m_pLZ_flags = d->m_pLZ_code_buf++; - } - - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; - d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; -} - -static mz_bool tdefl_compress_normal(tdefl_compressor *d) { - const mz_uint8 *pSrc = d->m_pSrc; - size_t src_buf_left = d->m_src_buf_left; - tdefl_flush flush = d->m_flush; - - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { - mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, - ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ - d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8 *pSrc_end = pSrc ? pSrc + num_bytes_to_process : NULL; - src_buf_left -= num_bytes_to_process; - d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) { - mz_uint8 c = *pSrc++; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - ins_pos++; - } - } else { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { - mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - src_buf_left--; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { - mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ - (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & - (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)(ins_pos); - } - } - } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); - if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - break; - - /* Simple lazy/greedy parsing state machine. */ - len_to_move = 1; - cur_match_dist = 0; - cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); - cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { - mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; - while (cur_match_len < d->m_lookahead_size) { - if (d->m_dict[cur_pos + cur_match_len] != c) - break; - cur_match_len++; - } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) - cur_match_len = 0; - else - cur_match_dist = 1; - } - } else { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, - &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || - ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { - cur_match_dist = cur_match_len = 0; - } - if (d->m_saved_match_len) { - if (cur_match_len > d->m_saved_match_len) { - tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) { - tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; - len_to_move = cur_match_len; - } else { - d->m_saved_lit = d->m_dict[cur_pos]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - } else { - tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; - d->m_saved_match_len = 0; - } - } else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { - tdefl_record_match(d, cur_match_len, cur_match_dist); - len_to_move = cur_match_len; - } else { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; - d->m_saved_match_dist = cur_match_dist; - d->m_saved_match_len = cur_match_len; - } - /* Move the lookahead forward by len_to_move bytes. */ - d->m_lookahead_pos += len_to_move; - MZ_ASSERT(d->m_lookahead_size >= len_to_move); - d->m_lookahead_size -= len_to_move; - d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); - /* Check if it's time to flush the current LZ codes to the internal output buffer. */ - if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ((d->m_total_lz_bytes > 31 * 1024) && - (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || - (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { - int n; - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - } - } - - d->m_pSrc = pSrc; - d->m_src_buf_left = src_buf_left; - return MZ_TRUE; -} - -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { - if (d->m_pIn_buf_size) { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - } - - if (d->m_pOut_buf_size) { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); - d->m_output_flush_ofs += (mz_uint)n; - d->m_output_flush_remaining -= (mz_uint)n; - d->m_out_buf_ofs += n; - - *d->m_pOut_buf_size = d->m_out_buf_ofs; - } - - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, - size_t *pOut_buf_size, tdefl_flush flush) { - if (!d) { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return TDEFL_STATUS_BAD_PARAM; - } - - d->m_pIn_buf = pIn_buf; - d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; - d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); - d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; - d->m_out_buf_ofs = 0; - d->m_flush = flush; - - if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || - (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || - (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { - if (pIn_buf_size) - *pIn_buf_size = 0; - if (pOut_buf_size) - *pOut_buf_size = 0; - return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); - } - d->m_wants_to_finish |= (flush == TDEFL_FINISH); - - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && - ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { - if (!tdefl_compress_fast(d)) - return d->m_prev_return_status; - } else -#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; - } - - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = - (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); - - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { - if (tdefl_flush_block(d, flush) < 0) - return d->m_prev_return_status; - d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) { - MZ_CLEAR_ARR(d->m_hash); - MZ_CLEAR_ARR(d->m_next); - d->m_dict_size = 0; - } - } - - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); -} - -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { - MZ_ASSERT(d->m_pPut_buf_func); - return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -} - -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { - d->m_pPut_buf_func = pPut_buf_func; - d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); - d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; - d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; - d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) - MZ_CLEAR_ARR(d->m_hash); - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = - d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = - d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; - d->m_pLZ_flags = d->m_lz_code_buf; - *d->m_pLZ_flags = 0; - d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; - d->m_pOutput_buf_end = d->m_output_buf; - d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; - d->m_adler32 = 1; - d->m_pIn_buf = NULL; - d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; - d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; - d->m_pSrc = NULL; - d->m_src_buf_left = 0; - d->m_out_buf_ofs = 0; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) - MZ_CLEAR_ARR(d->m_dict); - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { - return d->m_prev_return_status; -} - -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { - return d->m_adler32; -} - -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, - void *pPut_buf_user, int flags) { - tdefl_compressor *pComp; - mz_bool succeeded; - if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) - return MZ_FALSE; - pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); - if (!pComp) - return MZ_FALSE; - succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); - succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); - MZ_FREE(pComp); - return succeeded; -} - -typedef struct { - size_t m_size, m_capacity; - mz_uint8 *m_pBuf; - mz_bool m_expandable; -} tdefl_output_buffer; - -static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) { - tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; - size_t new_size = p->m_size + len; - if (new_size > p->m_capacity) { - size_t new_capacity = p->m_capacity; - mz_uint8 *pNew_buf; - if (!p->m_expandable) - return MZ_FALSE; - do { - new_capacity = MZ_MAX(128U, new_capacity << 1U); - } while (new_size > new_capacity); - pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); - if (!pNew_buf) - return MZ_FALSE; - p->m_pBuf = pNew_buf; - p->m_capacity = new_capacity; - } - memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); - p->m_size = new_size; - return MZ_TRUE; -} - -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { - tdefl_output_buffer out_buf; - MZ_CLEAR_OBJ(out_buf); - if (!pOut_len) - return MZ_FALSE; - else - *pOut_len = 0; - out_buf.m_expandable = MZ_TRUE; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) - return NULL; - *pOut_len = out_buf.m_size; - return out_buf.m_pBuf; -} - -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, - int flags) { - tdefl_output_buffer out_buf; - MZ_CLEAR_OBJ(out_buf); - if (!pOut_buf) - return 0; - out_buf.m_pBuf = (mz_uint8 *)pOut_buf; - out_buf.m_capacity = out_buf_len; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) - return 0; - return out_buf.m_size; -} - -/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine - * if throughput to fall off a cliff on some files). */ -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | - ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) - comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - - if (!level) - comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) - comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) - comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) - comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) - comp_flags |= TDEFL_RLE_MATCHES; - - return comp_flags; -} - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by \ - GNU C and C99, so no big deal) */ -#endif - -/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more - context at http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. This is actually a modification of Alex's - original code so PNG files generated by this function pass pngcheck. */ -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, - mz_uint level, mz_bool flip) { - /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ - static const mz_uint s_tdefl_png_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; - tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); - tdefl_output_buffer out_buf; - int i, bpl = w * num_chans, y, z; - mz_uint32 c; - *pLen_out = 0; - if (!pComp) - return NULL; - MZ_CLEAR_OBJ(out_buf); - out_buf.m_expandable = MZ_TRUE; - out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); - if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { - MZ_FREE(pComp); - return NULL; - } - /* write dummy header */ - for (z = 41; z; --z) - tdefl_output_buffer_putter(&z, 1, &out_buf); - /* compress image data */ - tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, - s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); - for (y = 0; y < h; ++y) { - tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); - tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); - } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { - MZ_FREE(pComp); - MZ_FREE(out_buf.m_pBuf); - return NULL; - } - /* write real header */ - *pLen_out = out_buf.m_size - 41; - { - static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; - mz_uint8 pnghdr[41] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, - 0x44, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x44, 0x41, 0x54}; - pnghdr[18] = (mz_uint8)(w >> 8); - pnghdr[19] = (mz_uint8)w; - pnghdr[22] = (mz_uint8)(h >> 8); - pnghdr[23] = (mz_uint8)h; - pnghdr[25] = chans[num_chans]; - pnghdr[33] = (mz_uint8)(*pLen_out >> 24); - pnghdr[34] = (mz_uint8)(*pLen_out >> 16); - pnghdr[35] = (mz_uint8)(*pLen_out >> 8); - pnghdr[36] = (mz_uint8)*pLen_out; - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); - for (i = 0; i < 4; ++i, c <<= 8) - ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); - memcpy(out_buf.m_pBuf, pnghdr, 41); - } - /* write footer (IDAT CRC-32, followed by IEND chunk) */ - if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { - *pLen_out = 0; - MZ_FREE(pComp); - MZ_FREE(out_buf.m_pBuf); - return NULL; - } - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); - for (i = 0; i < 4; ++i, c <<= 8) - (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); - /* compute final size of file, grab compressed data buffer and return */ - *pLen_out += 57; - MZ_FREE(pComp); - return out_buf.m_pBuf; -} -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) { - /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL - * being available in case the zlib API's where #defined out) */ - return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); -} - -#ifndef MINIZ_NO_MALLOC -/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ -/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -tdefl_compressor *tdefl_compressor_alloc(void) { - return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); -} - -void tdefl_compressor_free(tdefl_compressor *pComp) { - MZ_FREE(pComp); -} -#endif - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ diff --git a/clks/third_party/miniz/miniz_tdef.h b/clks/third_party/miniz/miniz_tdef.h deleted file mode 100644 index 97878c4..0000000 --- a/clks/third_party/miniz/miniz_tdef.h +++ /dev/null @@ -1,206 +0,0 @@ -#pragma once -#include "miniz_common.h" - -#ifndef MINIZ_NO_DEFLATE_APIS - -#ifdef __cplusplus -extern "C" { -#endif -/* ------------------- Low-level Compression API Definitions */ - -/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be - * output more frequently). */ -#ifndef TDEFL_LESS_MEMORY -#define TDEFL_LESS_MEMORY 0 -#endif - -/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary - * search): */ -/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, - * 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ -enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; - -/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of - * the source data at the end. Otherwise, you'll get raw deflate data. */ -/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ -/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ -/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the - * output may vary from run to run given the same input (depending on the contents of memory). */ -/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ -/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ -/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ -/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ -/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). - */ -enum { - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, - TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 -}; - -/* High level compression functions: */ -/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ -/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower - * but improve compression. */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. - */ -/* The caller must free() the returned block when it's no longer needed. */ -MINIZ_EXPORT void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ -/* Returns 0 on failure. */ -MINIZ_EXPORT size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, - size_t src_buf_len, int flags); - -/* Compresses an image to a compressed PNG file in memory. */ -/* On entry: */ -/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ -/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in - * memory. */ -/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is - * MZ_DEFAULT_LEVEL */ -/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ -/* On return: */ -/* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pLen_out will be set to the size of the PNG image file. */ -/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no - * longer needed. */ -MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, - size_t *pLen_out, mz_uint level, mz_bool flip); -MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, - size_t *pLen_out); - -/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called - * TDEFL_OUT_BUF_SIZE at a time. */ -typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); - -/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function - * internally. */ -MINIZ_EXPORT mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, - tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -enum { - TDEFL_MAX_HUFF_TABLES = 3, - TDEFL_MAX_HUFF_SYMBOLS_0 = 288, - TDEFL_MAX_HUFF_SYMBOLS_1 = 32, - TDEFL_MAX_HUFF_SYMBOLS_2 = 19, - TDEFL_LZ_DICT_SIZE = 32768, - TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, - TDEFL_MIN_MATCH_LEN = 3, - TDEFL_MAX_MATCH_LEN = 258 -}; - -/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman - * codes). */ -#if TDEFL_LESS_MEMORY -enum { - TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, - TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 12, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#else -enum { - TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, - TDEFL_OUT_BUF_SIZE = (mz_uint)((TDEFL_LZ_CODE_BUF_SIZE * 13) / 10), - TDEFL_MAX_HUFF_SYMBOLS = 288, - TDEFL_LZ_HASH_BITS = 15, - TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, - TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, - TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS -}; -#endif - -/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The - * low-level functions don't make any heap allocations, unlike the above helper functions. */ -typedef enum { - TDEFL_STATUS_BAD_PARAM = -2, - TDEFL_STATUS_PUT_BUF_FAILED = -1, - TDEFL_STATUS_OKAY = 0, - TDEFL_STATUS_DONE = 1 -} tdefl_status; - -/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ -typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, TDEFL_FINISH = 4 } tdefl_flush; - -/* tdefl's compression state structure. */ -typedef struct { - tdefl_put_buf_func_ptr m_pPut_buf_func; - void *m_pPut_buf_user; - mz_uint m_flags, m_max_probes[2]; - int m_greedy_parsing; - mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; - mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, - m_finished, m_block_index, m_wants_to_finish; - tdefl_status m_prev_return_status; - const void *m_pIn_buf; - void *m_pOut_buf; - size_t *m_pIn_buf_size, *m_pOut_buf_size; - tdefl_flush m_flush; - const mz_uint8 *m_pSrc; - size_t m_src_buf_left, m_out_buf_ofs; - mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; - mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; - mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; - mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; - mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; -} tdefl_compressor; - -/* Initializes the compressor. */ -/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ -/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call - * the tdefl_compress_buffer() API for compression. */ -/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ -/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ -MINIZ_EXPORT tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, - int flags); - -/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much - * compressed data to the specified output buffer as possible. */ -MINIZ_EXPORT tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, - size_t *pOut_buf_size, tdefl_flush flush); - -/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ -/* tdefl_compress_buffer() always consumes the entire input buffer. */ -MINIZ_EXPORT tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, - tdefl_flush flush); - -MINIZ_EXPORT tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -MINIZ_EXPORT mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - -/* Create tdefl_compress() flags given zlib-style compression parameters. */ -/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ -/* window_bits may be -15 (raw deflate) or 15 (zlib) */ -/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ -MINIZ_EXPORT mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); - -#ifndef MINIZ_NO_MALLOC -/* Allocate the tdefl_compressor structure in C so that */ -/* non-C language bindings to tdefl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -MINIZ_EXPORT tdefl_compressor *tdefl_compressor_alloc(void); -MINIZ_EXPORT void tdefl_compressor_free(tdefl_compressor *pComp); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ diff --git a/clks/third_party/miniz/miniz_tinfl.h b/clks/third_party/miniz/miniz_tinfl.h deleted file mode 100644 index c22f23b..0000000 --- a/clks/third_party/miniz/miniz_tinfl.h +++ /dev/null @@ -1,168 +0,0 @@ -#pragma once -#include "miniz_common.h" -/* ------------------- Low-level Decompression API Definitions */ - -#ifndef MINIZ_NO_INFLATE_APIS - -#ifdef __cplusplus -extern "C" { -#endif -/* Decompression flags used by tinfl_decompress(). */ -/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a - * valid zlib stream). Otherwise, the input is a raw deflate stream. */ -/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. - * If clear, the input buffer contains all remaining input. */ -/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed - * stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ -/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ -enum { - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -/* High level decompression functions: */ -/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ -/* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ -/* On return: */ -/* Function returns a pointer to the decompressed data, or NULL on failure. */ -/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible - * data. */ -/* The caller must call mz_free() on the returned block when it's no longer needed. */ -MINIZ_EXPORT void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ -/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -MINIZ_EXPORT size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, - size_t src_buf_len, int flags); - -/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided - * callback function will be called to flush the buffer. */ -/* Returns 1 on success or 0 on failure. */ -typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); -MINIZ_EXPORT int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, - tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; -typedef struct tinfl_decompressor_tag tinfl_decompressor; - -#ifndef MINIZ_NO_MALLOC -/* Allocate the tinfl_decompressor structure in C so that */ -/* non-C language bindings to tinfl_ API don't need to worry about */ -/* structure size and allocation mechanism. */ -MINIZ_EXPORT tinfl_decompressor *tinfl_decompressor_alloc(void); -MINIZ_EXPORT void tinfl_decompressor_free(tinfl_decompressor *pDecomp); -#endif - -/* Max size of LZ dictionary. */ -#define TINFL_LZ_DICT_SIZE 32768 - -/* Return status. */ -typedef enum { - /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is - indicating that no more are available. The compressed data */ - /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input - but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ - /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ - TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, - - /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, - but if you get this error the calling code is wrong.) */ - TINFL_STATUS_BAD_PARAM = -3, - - /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you - call it again it'll return TINFL_STATUS_DONE. */ - TINFL_STATUS_ADLER32_MISMATCH = -2, - - /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again - without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ - TINFL_STATUS_FAILED = -1, - - /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ - - /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every - byte that it needed, has successfully reached the end of the deflate stream, and */ - /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If - you call it again you'll just get TINFL_STATUS_DONE over and over again. */ - TINFL_STATUS_DONE = 0, - - /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward - progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ - /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also - possible (but unlikely) for the inflator to keep on demanding input to */ - /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - - /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot - write this data into the output buffer. */ - /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed - data to the caller. I've been assuming you know how much uncompressed data to expect */ - /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure - streaming scenarios where you have no idea how many bytes to expect this may not be possible */ - /* so I may need to add some code to address this. */ - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -/* Initializes the decompressor to its initial state. */ -#define tinfl_init(r) \ - do { \ - (r)->m_state = 0; \ - } \ - MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - -/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the - * other functions are just high-level helpers for improved usability. */ -/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. - * In the limit case, it can be called once per every byte input or output. */ -MINIZ_EXPORT tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, - mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, - const mz_uint32 decomp_flags); - -/* Internal/private bits follow. */ -enum { - TINFL_MAX_HUFF_TABLES = 3, - TINFL_MAX_HUFF_SYMBOLS_0 = 288, - TINFL_MAX_HUFF_SYMBOLS_1 = 32, - TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, - TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -#if MINIZ_HAS_64BIT_REGISTERS -#define TINFL_USE_64BIT_BITBUF 1 -#else -#define TINFL_USE_64BIT_BITBUF 0 -#endif - -#if TINFL_USE_64BIT_BITBUF -typedef mz_uint64 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (64) -#else -typedef mz_uint32 tinfl_bit_buf_t; -#define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag { - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, - m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - mz_int16 m_look_up[TINFL_MAX_HUFF_TABLES][TINFL_FAST_LOOKUP_SIZE]; - mz_int16 m_tree_0[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; - mz_int16 m_tree_1[TINFL_MAX_HUFF_SYMBOLS_1 * 2]; - mz_int16 m_tree_2[TINFL_MAX_HUFF_SYMBOLS_2 * 2]; - mz_uint8 m_code_size_0[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_uint8 m_code_size_1[TINFL_MAX_HUFF_SYMBOLS_1]; - mz_uint8 m_code_size_2[TINFL_MAX_HUFF_SYMBOLS_2]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -#ifdef __cplusplus -} -#endif - -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ diff --git a/clks/third_party/miniz/miniz_zip.h b/clks/third_party/miniz/miniz_zip.h deleted file mode 100644 index 9e90a18..0000000 --- a/clks/third_party/miniz/miniz_zip.h +++ /dev/null @@ -1,523 +0,0 @@ - -#pragma once -#include "miniz_common.h" - -/* ------------------- ZIP archive reading/writing */ - -#ifndef MINIZ_NO_ARCHIVE_APIS - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ - MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, - MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, - MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 -}; - -typedef struct { - /* Central directory file index. */ - mz_uint32 m_file_index; - - /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or - * less bytes in the central dir. */ - mz_uint64 m_central_dir_ofs; - - /* These fields are copied directly from the zip's central dir. */ - mz_uint16 m_version_made_by; - mz_uint16 m_version_needed; - mz_uint16 m_bit_flag; - mz_uint16 m_method; - - /* CRC-32 of uncompressed data. */ - mz_uint32 m_crc32; - - /* File's compressed size. */ - mz_uint64 m_comp_size; - - /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their - * uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ - mz_uint64 m_uncomp_size; - - /* Zip internal and external file attributes. */ - mz_uint16 m_internal_attr; - mz_uint32 m_external_attr; - - /* Entry's local header file offset in bytes. */ - mz_uint64 m_local_header_ofs; - - /* Size of comment in bytes. */ - mz_uint32 m_comment_size; - - /* MZ_TRUE if the entry appears to be a directory. */ - mz_bool m_is_directory; - - /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ - mz_bool m_is_encrypted; - - /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ - mz_bool m_is_supported; - - /* Filename. If string ends in '/' it's a subdirectory entry. */ - /* Guaranteed to be zero terminated, may be truncated to fit. */ - char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - - /* Comment field. */ - /* Guaranteed to be zero terminated, may be truncated to fit. */ - char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; - -#ifdef MINIZ_NO_TIME - MZ_TIME_T m_padding; -#else - MZ_TIME_T m_time; -#endif -} mz_zip_archive_file_stat; - -typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); -typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); - -struct mz_zip_internal_state_tag; -typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - -typedef enum { - MZ_ZIP_MODE_INVALID = 0, - MZ_ZIP_MODE_READING = 1, - MZ_ZIP_MODE_WRITING = 2, - MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -} mz_zip_mode; - -typedef enum { - MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, - MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, - MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, - MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, - MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = - 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the - func finds the file in the central dir (intended for testing) */ - MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = - 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ - MZ_ZIP_FLAG_WRITE_ZIP64 = - 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to - zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ - MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, - MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000, - /*After adding a compressed file, seek back - to local file header and set the correct sizes*/ - MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE = 0x20000, - MZ_ZIP_FLAG_READ_ALLOW_WRITING = 0x40000 -} mz_zip_flags; - -typedef enum { - MZ_ZIP_TYPE_INVALID = 0, - MZ_ZIP_TYPE_USER, - MZ_ZIP_TYPE_MEMORY, - MZ_ZIP_TYPE_HEAP, - MZ_ZIP_TYPE_FILE, - MZ_ZIP_TYPE_CFILE, - MZ_ZIP_TOTAL_TYPES -} mz_zip_type; - -/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ -typedef enum { - MZ_ZIP_NO_ERROR = 0, - MZ_ZIP_UNDEFINED_ERROR, - MZ_ZIP_TOO_MANY_FILES, - MZ_ZIP_FILE_TOO_LARGE, - MZ_ZIP_UNSUPPORTED_METHOD, - MZ_ZIP_UNSUPPORTED_ENCRYPTION, - MZ_ZIP_UNSUPPORTED_FEATURE, - MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, - MZ_ZIP_NOT_AN_ARCHIVE, - MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, - MZ_ZIP_UNSUPPORTED_MULTIDISK, - MZ_ZIP_DECOMPRESSION_FAILED, - MZ_ZIP_COMPRESSION_FAILED, - MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, - MZ_ZIP_CRC_CHECK_FAILED, - MZ_ZIP_UNSUPPORTED_CDIR_SIZE, - MZ_ZIP_ALLOC_FAILED, - MZ_ZIP_FILE_OPEN_FAILED, - MZ_ZIP_FILE_CREATE_FAILED, - MZ_ZIP_FILE_WRITE_FAILED, - MZ_ZIP_FILE_READ_FAILED, - MZ_ZIP_FILE_CLOSE_FAILED, - MZ_ZIP_FILE_SEEK_FAILED, - MZ_ZIP_FILE_STAT_FAILED, - MZ_ZIP_INVALID_PARAMETER, - MZ_ZIP_INVALID_FILENAME, - MZ_ZIP_BUF_TOO_SMALL, - MZ_ZIP_INTERNAL_ERROR, - MZ_ZIP_FILE_NOT_FOUND, - MZ_ZIP_ARCHIVE_TOO_LARGE, - MZ_ZIP_VALIDATION_FAILED, - MZ_ZIP_WRITE_CALLBACK_FAILED, - MZ_ZIP_TOTAL_ERRORS -} mz_zip_error; - -typedef struct { - mz_uint64 m_archive_size; - mz_uint64 m_central_directory_file_ofs; - - /* We only support up to UINT32_MAX files in zip64 mode. */ - mz_uint32 m_total_files; - mz_zip_mode m_zip_mode; - mz_zip_type m_zip_type; - mz_zip_error m_last_error; - - mz_uint64 m_file_offset_alignment; - - mz_alloc_func m_pAlloc; - mz_free_func m_pFree; - mz_realloc_func m_pRealloc; - void *m_pAlloc_opaque; - - mz_file_read_func m_pRead; - mz_file_write_func m_pWrite; - mz_file_needs_keepalive m_pNeeds_keepalive; - void *m_pIO_opaque; - - mz_zip_internal_state *m_pState; - -} mz_zip_archive; - -typedef struct { - mz_zip_archive *pZip; - mz_uint flags; - - int status; - - mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; - mz_zip_archive_file_stat file_stat; - void *pRead_buf; - void *pWrite_buf; - - size_t out_blk_remain; - - tinfl_decompressor inflator; - -#ifdef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - mz_uint padding; -#else - mz_uint file_crc32; -#endif - -} mz_zip_reader_extract_iter_state; - -/* -------- ZIP reading */ - -/* Inits a ZIP archive reader. */ -/* These functions read and validate the archive's central directory. */ -MINIZ_EXPORT mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); - -MINIZ_EXPORT mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); - -#ifndef MINIZ_NO_STDIO -/* Read a archive from a disk file. */ -/* file_start_ofs is the file offset where the archive actually begins, or 0. */ -/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. - * If zero the entire file is treated as the archive. */ -MINIZ_EXPORT mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); -MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, - mz_uint64 file_start_ofs, mz_uint64 archive_size); - -/* Read an archive from an already opened FILE, beginning at the current file position. */ -/* The archive is assumed to be archive_size bytes long. If archive_size is 0, then the entire rest of the file is - * assumed to contain the archive. */ -/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ -MINIZ_EXPORT mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, - mz_uint flags); -#endif - -/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was - * used. */ -MINIZ_EXPORT mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - -/* -------- ZIP reading or writing */ - -/* Clears a mz_zip_archive struct to all zeros. */ -/* Important: This must be done before passing the struct to any mz_zip functions. */ -MINIZ_EXPORT void mz_zip_zero_struct(mz_zip_archive *pZip); - -MINIZ_EXPORT mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); -MINIZ_EXPORT mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); - -/* Returns the total number of files in the archive. */ -MINIZ_EXPORT mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - -MINIZ_EXPORT mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); -MINIZ_EXPORT mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); -MINIZ_EXPORT MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); - -/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ -MINIZ_EXPORT size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); - -/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this - * field. */ -/* Note that the m_last_error functionality is not thread safe. */ -MINIZ_EXPORT mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); -MINIZ_EXPORT mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); -MINIZ_EXPORT mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); -MINIZ_EXPORT mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); -MINIZ_EXPORT const char *mz_zip_get_error_string(mz_zip_error mz_err); - -/* MZ_TRUE if the archive file entry is a directory entry. */ -MINIZ_EXPORT mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the file is encrypted/strong encrypted. */ -MINIZ_EXPORT mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - -/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch - * file. */ -MINIZ_EXPORT mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); - -/* Retrieves the filename of an archive file entry. */ -/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of - * bytes needed to fully store the filename. */ -MINIZ_EXPORT mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, - mz_uint filename_buf_size); - -/* Attempts to locates a file in the archive's central directory. */ -/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ -/* Returns -1 if the file cannot be found. */ -MINIZ_EXPORT int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, - mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, - mz_uint flags, mz_uint32 *file_index); - -/* Returns detailed information about an archive file entry. */ -MINIZ_EXPORT mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - -/* MZ_TRUE if the file is in zip64 format. */ -/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 - * extended file information fields in the central directory. */ -MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); - -/* Returns the total central directory size in bytes. */ -/* The current max supported size is <= MZ_UINT32_MAX. */ -MINIZ_EXPORT size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); - -/* Extracts a archive file to a memory buffer using no memory allocation. */ -/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ -MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, - size_t buf_size, mz_uint flags, void *pUser_read_buf, - size_t user_read_buf_size); -MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, - size_t buf_size, mz_uint flags, void *pUser_read_buf, - size_t user_read_buf_size); - -/* Extracts a archive file to a memory buffer. */ -MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, - mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, - size_t buf_size, mz_uint flags); - -/* Extracts a archive file to a dynamically allocated heap buffer. */ -/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ -/* Returns NULL and sets the last error on failure. */ -MINIZ_EXPORT void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, - mz_uint flags); -MINIZ_EXPORT void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, - mz_uint flags); - -/* Extracts a archive file using a callback function to output the file's data. */ -MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, - mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, - mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - -/* Extract a file iteratively */ -MINIZ_EXPORT mz_zip_reader_extract_iter_state *mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, - mz_uint flags); -MINIZ_EXPORT mz_zip_reader_extract_iter_state * -mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -MINIZ_EXPORT size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state *pState, void *pvBuf, - size_t buf_size); -MINIZ_EXPORT mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state *pState); - -#ifndef MINIZ_NO_STDIO -/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ -/* This function only extracts files, not archive directory records. */ -MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, - mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, - const char *pDst_filename, mz_uint flags); - -/* Extracts a archive file starting at the current position in the destination FILE stream. */ -MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, - mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, - MZ_FILE *pFile, mz_uint flags); -#endif - -#if 0 -/* TODO */ - typedef void *mz_zip_streaming_extract_state_ptr; - mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs); - size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); - mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); -#endif - -/* This function compares the archive's local headers, the optional local zip64 extended information block, and the - * optional descriptor following the compressed data vs. the data in the central directory. */ -/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is - * specified. */ -MINIZ_EXPORT mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - -/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ -MINIZ_EXPORT mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); - -/* Misc utils/helpers, valid for ZIP reading or writing */ -MINIZ_EXPORT mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); -#ifndef MINIZ_NO_STDIO -MINIZ_EXPORT mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); -#endif - -/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ -MINIZ_EXPORT mz_bool mz_zip_end(mz_zip_archive *pZip); - -/* -------- ZIP writing */ - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -/* Inits a ZIP archive writer. */ -/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ -/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ -MINIZ_EXPORT mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -MINIZ_EXPORT mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); - -MINIZ_EXPORT mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, - size_t initial_allocation_size); -MINIZ_EXPORT mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, - size_t initial_allocation_size, mz_uint flags); - -#ifndef MINIZ_NO_STDIO -MINIZ_EXPORT mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, - mz_uint64 size_to_reserve_at_beginning); -MINIZ_EXPORT mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, - mz_uint64 size_to_reserve_at_beginning, mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); -#endif - -/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an - * existing archive. */ -/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for - * writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ -/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which - * defaults to realloc unless you've overridden it). */ -/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be - * NULL. */ -/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops - * or something goes wrong before */ -/* the archive is finalized the file's central directory will be hosed. */ -MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); -MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); - -/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. - */ -/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or - * more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -MINIZ_EXPORT mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, - size_t buf_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with - * already compressed data. */ -/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ -MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, - size_t buf_size, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - -MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, - size_t buf_size, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, - MZ_TIME_T *last_modified, const char *user_extra_data_local, - mz_uint user_extra_data_local_len, const char *user_extra_data_central, - mz_uint user_extra_data_central_len); - -/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. - */ -/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/ -MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( - mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void *callback_opaque, - mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, - const char *user_extra_data_central, mz_uint user_extra_data_central_len); - -#ifndef MINIZ_NO_STDIO -/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the - * archive. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or - * more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -MINIZ_EXPORT mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, - const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - -/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ -MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, - mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags, - const char *user_extra_data_local, mz_uint user_extra_data_local_len, - const char *user_extra_data_central, mz_uint user_extra_data_central_len); -#endif - -/* Adds a file to an archive by fully cloning the data from another archive. */ -/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra - * data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the - * compressed data. */ -MINIZ_EXPORT mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, - mz_uint src_file_index); - -/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ -/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ -/* An archive must be manually finalized by calling this function for it to be valid. */ -MINIZ_EXPORT mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); - -/* Finalizes a heap archive, returning a pointer to the heap block and its size. */ -/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ -MINIZ_EXPORT mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); - -/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ -/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). - */ -MINIZ_EXPORT mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - -/* -------- Misc. high-level helper functions: */ - -/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ -/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up - * state (without a central directory). */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or - * more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ -/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate - * the file (so the old central dir would be at the end) if something goes wrong. */ -MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags); -MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags, - mz_zip_error *pErr); - -#ifndef MINIZ_NO_STDIO -/* Reads a single file from an archive into a heap block. */ -/* If pComment is not NULL, only the file with the specified comment will be extracted. */ -/* Returns NULL on failure. */ -MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint flags); -MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, - const char *pComment, size_t *pSize, mz_uint flags, - mz_zip_error *pErr); -#endif - -#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ - -#ifdef __cplusplus -} -#endif - -#endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/clks/third_party/qrcodegen/qrcodegen.c b/clks/third_party/qrcodegen/qrcodegen.c deleted file mode 100644 index 84a22b3..0000000 --- a/clks/third_party/qrcodegen/qrcodegen.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * QR Code generator library (C) - * - * Copyright (c) Project Nayuki. (MIT License) - * https://www.nayuki.io/page/qr-code-generator-library - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - The Software is provided "as is", without warranty of any kind, express or - * implied, including but not limited to the warranties of merchantability, - * fitness for a particular purpose and noninfringement. In no event shall the - * authors or copyright holders be liable for any claim, damages or other - * liability, whether in an action of contract, tort or otherwise, arising from, - * out of or in connection with the Software or the use or other dealings in the - * Software. - */ - -#ifndef NDEBUG -#define NDEBUG 1 -#endif -#include -#include -#include -#include -#include "qrcodegen.h" - -#ifndef QRCODEGEN_TEST -#define testable static // Keep functions private -#else -#define testable // Expose private functions -#endif - -/*---- Forward declarations for private functions ----*/ - -// Regarding all public and private functions defined in this source file: -// - They require all pointer/array arguments to be not null unless the array length is zero. -// - They only read input scalar/array arguments, write to output pointer/array -// arguments, and return scalar values; they are "pure" functions. -// - They don't read mutable global variables or write to any global variables. -// - They don't perform I/O, read the clock, print to console, etc. -// - They allocate a small and constant amount of stack memory. -// - They don't allocate or free any memory on the heap. -// - They don't recurse or mutually recurse. All the code -// could be inlined into the top-level public functions. -// - They run in at most quadratic time with respect to input arguments. -// Most functions run in linear time, and some in constant time. -// There are no unbounded loops or non-obvious termination conditions. -// - They are completely thread-safe if the caller does not give the -// same writable buffer to concurrent calls to these functions. - -testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen); - -testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]); -testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); -testable int getNumRawDataModules(int ver); - -testable void reedSolomonComputeDivisor(int degree, uint8_t result[]); -testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, - uint8_t result[]); -testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y); - -testable void initializeFunctionModules(int version, uint8_t qrcode[]); -static void drawLightFunctionModules(uint8_t qrcode[], int version); -static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]); -testable int getAlignmentPatternPositions(int version, uint8_t result[7]); -static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]); - -static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]); -static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask); -static long getPenaltyScore(const uint8_t qrcode[]); -static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize); -static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize); -static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize); -static void zeroRunHistory(int runHistory[7]); - -testable bool getModuleBounded(const uint8_t qrcode[], int x, int y); -testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark); -testable void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool isDark); -static bool getBit(int x, int i); - -testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars); -testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version); -static int numCharCountBits(enum qrcodegen_Mode mode, int version); - -/*---- Private tables of constants ----*/ - -// The set of all legal characters in alphanumeric mode, where each character -// value maps to the index in the string. For checking text and encoding segments. -static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; - -// Sentinel value for use in only some functions. -#define LENGTH_OVERFLOW -1 - -// For generating error correction codes. -testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = { - // Version: (note that index 0 is for padding, and is set to an illegal value) - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - // 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, - 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low - {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, - 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium - {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, - 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile - {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, - 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High -}; - -#define qrcodegen_REED_SOLOMON_DEGREE_MAX 30 // Based on the table above - -// For generating error correction codes. -testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = { - // Version: (note that index 0 is for padding, and is set to an illegal value) - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - // 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, - 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low - {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, - 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium - {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, - 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile - {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, - 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High -}; - -// For automatic mask pattern selection. -static const int PENALTY_N1 = 3; -static const int PENALTY_N2 = 3; -static const int PENALTY_N3 = 40; -static const int PENALTY_N4 = 10; - -/*---- High-level QR Code encoding functions ----*/ - -// Public function - see documentation comment in header file. -bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl, - int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { - - size_t textLen = strlen(text); - if (textLen == 0) - return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, - qrcode); - size_t bufLen = (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); - - struct qrcodegen_Segment seg; - if (qrcodegen_isNumeric(text)) { - if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) - goto fail; - seg = qrcodegen_makeNumeric(text, tempBuffer); - } else if (qrcodegen_isAlphanumeric(text)) { - if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen) - goto fail; - seg = qrcodegen_makeAlphanumeric(text, tempBuffer); - } else { - if (textLen > bufLen) - goto fail; - for (size_t i = 0; i < textLen; i++) - tempBuffer[i] = (uint8_t)text[i]; - seg.mode = qrcodegen_Mode_BYTE; - seg.bitLength = calcSegmentBitLength(seg.mode, textLen); - if (seg.bitLength == LENGTH_OVERFLOW) - goto fail; - seg.numChars = (int)textLen; - seg.data = tempBuffer; - } - return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); - -fail: - qrcode[0] = 0; // Set size to invalid value for safety - return false; -} - -// Public function - see documentation comment in header file. -bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], enum qrcodegen_Ecc ecl, - int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { - - struct qrcodegen_Segment seg; - seg.mode = qrcodegen_Mode_BYTE; - seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); - if (seg.bitLength == LENGTH_OVERFLOW) { - qrcode[0] = 0; // Set size to invalid value for safety - return false; - } - seg.numChars = (int)dataLen; - seg.data = dataAndTemp; - return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode); -} - -// Appends the given number of low-order bits of the given value to the given byte-based -// bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits. -testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) { - assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0); - for (int i = numBits - 1; i >= 0; i--, (*bitLen)++) - buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7)); -} - -/*---- Low-level QR Code encoding functions ----*/ - -// Public function - see documentation comment in header file. -bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, - uint8_t tempBuffer[], uint8_t qrcode[]) { - return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, - qrcodegen_Mask_AUTO, true, tempBuffer, qrcode); -} - -// Public function - see documentation comment in header file. -bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, - int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, - uint8_t tempBuffer[], uint8_t qrcode[]) { - assert(segs != NULL || len == 0); - assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX); - assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7); - - // Find the minimal version number to use - int version, dataUsedBits; - for (version = minVersion;; version++) { - int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available - dataUsedBits = getTotalBits(segs, len, version); - if (dataUsedBits != LENGTH_OVERFLOW && dataUsedBits <= dataCapacityBits) - break; // This version number is found to be suitable - if (version >= maxVersion) { // All versions in the range could not fit the given data - qrcode[0] = 0; // Set size to invalid value for safety - return false; - } - } - assert(dataUsedBits != LENGTH_OVERFLOW); - - // Increase the error correction level while the data still fits in the current version number - for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high - if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8) - ecl = (enum qrcodegen_Ecc)i; - } - - // Concatenate all segments to create the data bit string - memset(qrcode, 0, (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); - int bitLen = 0; - for (size_t i = 0; i < len; i++) { - const struct qrcodegen_Segment *seg = &segs[i]; - appendBitsToBuffer((unsigned int)seg->mode, 4, qrcode, &bitLen); - appendBitsToBuffer((unsigned int)seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen); - for (int j = 0; j < seg->bitLength; j++) { - int bit = (seg->data[j >> 3] >> (7 - (j & 7))) & 1; - appendBitsToBuffer((unsigned int)bit, 1, qrcode, &bitLen); - } - } - assert(bitLen == dataUsedBits); - - // Add terminator and pad up to a byte if applicable - int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; - assert(bitLen <= dataCapacityBits); - int terminatorBits = dataCapacityBits - bitLen; - if (terminatorBits > 4) - terminatorBits = 4; - appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen); - appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen); - assert(bitLen % 8 == 0); - - // Pad with alternating bytes until data capacity is reached - for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) - appendBitsToBuffer(padByte, 8, qrcode, &bitLen); - - // Compute ECC, draw modules - addEccAndInterleave(qrcode, version, ecl, tempBuffer); - initializeFunctionModules(version, qrcode); - drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode); - drawLightFunctionModules(qrcode, version); - initializeFunctionModules(version, tempBuffer); - - // Do masking - if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask - long minPenalty = LONG_MAX; - for (int i = 0; i < 8; i++) { - enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i; - applyMask(tempBuffer, qrcode, msk); - drawFormatBits(ecl, msk, qrcode); - long penalty = getPenaltyScore(qrcode); - if (penalty < minPenalty) { - mask = msk; - minPenalty = penalty; - } - applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR - } - } - assert(0 <= (int)mask && (int)mask <= 7); - applyMask(tempBuffer, qrcode, mask); // Apply the final choice of mask - drawFormatBits(ecl, mask, qrcode); // Overwrite old format bits - return true; -} - -/*---- Error correction code generation functions ----*/ - -// Appends error correction bytes to each block of the given data array, then interleaves -// bytes from the blocks and stores them in the result array. data[0 : dataLen] contains -// the input data. data[dataLen : rawCodewords] is used as a temporary work area and will -// be clobbered by this function. The final answer is stored in result[0 : rawCodewords]. -testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) { - // Calculate parameter numbers - assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); - int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version]; - int blockEccLen = ECC_CODEWORDS_PER_BLOCK[(int)ecl][version]; - int rawCodewords = getNumRawDataModules(version) / 8; - int dataLen = getNumDataCodewords(version, ecl); - int numShortBlocks = numBlocks - rawCodewords % numBlocks; - int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen; - - // Split data into blocks, calculate ECC, and interleave - // (not concatenate) the bytes into a single sequence - uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX]; - reedSolomonComputeDivisor(blockEccLen, rsdiv); - const uint8_t *dat = data; - for (int i = 0; i < numBlocks; i++) { - int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); - uint8_t *ecc = &data[dataLen]; // Temporary storage - reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc); - for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data - if (j == shortBlockDataLen) - k -= numShortBlocks; - result[k] = dat[j]; - } - for (int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) // Copy ECC - result[k] = ecc[j]; - dat += datLen; - } -} - -// Returns the number of 8-bit codewords that can be used for storing data (not ECC), -// for the given version number and error correction level. The result is in the range [9, 2956]. -testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) { - int v = version, e = (int)ecl; - assert(0 <= e && e < 4); - return getNumRawDataModules(v) / 8 - ECC_CODEWORDS_PER_BLOCK[e][v] * NUM_ERROR_CORRECTION_BLOCKS[e][v]; -} - -// Returns the number of data bits that can be stored in a QR Code of the given version number, after -// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. -// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. -testable int getNumRawDataModules(int ver) { - assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX); - int result = (16 * ver + 128) * ver + 64; - if (ver >= 2) { - int numAlign = ver / 7 + 2; - result -= (25 * numAlign - 10) * numAlign - 55; - if (ver >= 7) - result -= 36; - } - assert(208 <= result && result <= 29648); - return result; -} - -/*---- Reed-Solomon ECC generator functions ----*/ - -// Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree]. -// This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm. -testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) { - assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); - // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. - // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. - memset(result, 0, (size_t)degree * sizeof(result[0])); - result[degree - 1] = 1; // Start off with the monomial x^0 - - // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), - // drop the highest monomial term which is always 1x^degree. - // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). - uint8_t root = 1; - for (int i = 0; i < degree; i++) { - // Multiply the current product by (x - r^i) - for (int j = 0; j < degree; j++) { - result[j] = reedSolomonMultiply(result[j], root); - if (j + 1 < degree) - result[j] ^= result[j + 1]; - } - root = reedSolomonMultiply(root, 0x02); - } -} - -// Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials. -// The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree]. -// All polynomials are in big endian, and the generator has an implicit leading 1 term. -testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, - uint8_t result[]) { - assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); - memset(result, 0, (size_t)degree * sizeof(result[0])); - for (int i = 0; i < dataLen; i++) { // Polynomial division - uint8_t factor = data[i] ^ result[0]; - memmove(&result[0], &result[1], (size_t)(degree - 1) * sizeof(result[0])); - result[degree - 1] = 0; - for (int j = 0; j < degree; j++) - result[j] ^= reedSolomonMultiply(generator[j], factor); - } -} - -#undef qrcodegen_REED_SOLOMON_DEGREE_MAX - -// Returns the product of the two given field elements modulo GF(2^8/0x11D). -// All inputs are valid. This could be implemented as a 256*256 lookup table. -testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) { - // Russian peasant multiplication - uint8_t z = 0; - for (int i = 7; i >= 0; i--) { - z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D)); - z ^= ((y >> i) & 1) * x; - } - return z; -} - -/*---- Drawing function modules ----*/ - -// Clears the given QR Code grid with light modules for the given -// version's size, then marks every function module as dark. -testable void initializeFunctionModules(int version, uint8_t qrcode[]) { - // Initialize QR Code - int qrsize = version * 4 + 17; - memset(qrcode, 0, (size_t)((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0])); - qrcode[0] = (uint8_t)qrsize; - - // Fill horizontal and vertical timing patterns - fillRectangle(6, 0, 1, qrsize, qrcode); - fillRectangle(0, 6, qrsize, 1, qrcode); - - // Fill 3 finder patterns (all corners except bottom right) and format bits - fillRectangle(0, 0, 9, 9, qrcode); - fillRectangle(qrsize - 8, 0, 8, 9, qrcode); - fillRectangle(0, qrsize - 8, 9, 8, qrcode); - - // Fill numerous alignment patterns - uint8_t alignPatPos[7]; - int numAlign = getAlignmentPatternPositions(version, alignPatPos); - for (int i = 0; i < numAlign; i++) { - for (int j = 0; j < numAlign; j++) { - // Don't draw on the three finder corners - if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) - fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode); - } - } - - // Fill version blocks - if (version >= 7) { - fillRectangle(qrsize - 11, 0, 3, 6, qrcode); - fillRectangle(0, qrsize - 11, 6, 3, qrcode); - } -} - -// Draws light function modules and possibly some dark modules onto the given QR Code, without changing -// non-function modules. This does not draw the format bits. This requires all function modules to be previously -// marked dark (namely by initializeFunctionModules()), because this may skip redrawing dark function modules. -static void drawLightFunctionModules(uint8_t qrcode[], int version) { - // Draw horizontal and vertical timing patterns - int qrsize = qrcodegen_getSize(qrcode); - for (int i = 7; i < qrsize - 7; i += 2) { - setModuleBounded(qrcode, 6, i, false); - setModuleBounded(qrcode, i, 6, false); - } - - // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) - for (int dy = -4; dy <= 4; dy++) { - for (int dx = -4; dx <= 4; dx++) { - int dist = abs(dx); - if (abs(dy) > dist) - dist = abs(dy); - if (dist == 2 || dist == 4) { - setModuleUnbounded(qrcode, 3 + dx, 3 + dy, false); - setModuleUnbounded(qrcode, qrsize - 4 + dx, 3 + dy, false); - setModuleUnbounded(qrcode, 3 + dx, qrsize - 4 + dy, false); - } - } - } - - // Draw numerous alignment patterns - uint8_t alignPatPos[7]; - int numAlign = getAlignmentPatternPositions(version, alignPatPos); - for (int i = 0; i < numAlign; i++) { - for (int j = 0; j < numAlign; j++) { - if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)) - continue; // Don't draw on the three finder corners - for (int dy = -1; dy <= 1; dy++) { - for (int dx = -1; dx <= 1; dx++) - setModuleBounded(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0); - } - } - } - - // Draw version blocks - if (version >= 7) { - // Calculate error correction code and pack bits - int rem = version; // version is uint6, in the range [7, 40] - for (int i = 0; i < 12; i++) - rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); - long bits = (long)version << 12 | rem; // uint18 - assert(bits >> 18 == 0); - - // Draw two copies - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 3; j++) { - int k = qrsize - 11 + j; - setModuleBounded(qrcode, k, i, (bits & 1) != 0); - setModuleBounded(qrcode, i, k, (bits & 1) != 0); - bits >>= 1; - } - } - } -} - -// Draws two copies of the format bits (with its own error correction code) based -// on the given mask and error correction level. This always draws all modules of -// the format bits, unlike drawLightFunctionModules() which might skip dark modules. -static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) { - // Calculate error correction code and pack bits - assert(0 <= (int)mask && (int)mask <= 7); - static const int table[] = {1, 0, 3, 2}; - int data = table[(int)ecl] << 3 | (int)mask; // errCorrLvl is uint2, mask is uint3 - int rem = data; - for (int i = 0; i < 10; i++) - rem = (rem << 1) ^ ((rem >> 9) * 0x537); - int bits = (data << 10 | rem) ^ 0x5412; // uint15 - assert(bits >> 15 == 0); - - // Draw first copy - for (int i = 0; i <= 5; i++) - setModuleBounded(qrcode, 8, i, getBit(bits, i)); - setModuleBounded(qrcode, 8, 7, getBit(bits, 6)); - setModuleBounded(qrcode, 8, 8, getBit(bits, 7)); - setModuleBounded(qrcode, 7, 8, getBit(bits, 8)); - for (int i = 9; i < 15; i++) - setModuleBounded(qrcode, 14 - i, 8, getBit(bits, i)); - - // Draw second copy - int qrsize = qrcodegen_getSize(qrcode); - for (int i = 0; i < 8; i++) - setModuleBounded(qrcode, qrsize - 1 - i, 8, getBit(bits, i)); - for (int i = 8; i < 15; i++) - setModuleBounded(qrcode, 8, qrsize - 15 + i, getBit(bits, i)); - setModuleBounded(qrcode, 8, qrsize - 8, true); // Always dark -} - -// Calculates and stores an ascending list of positions of alignment patterns -// for this version number, returning the length of the list (in the range [0,7]). -// Each position is in the range [0,177), and are used on both the x and y axes. -// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. -testable int getAlignmentPatternPositions(int version, uint8_t result[7]) { - if (version == 1) - return 0; - int numAlign = version / 7 + 2; - int step = (version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4) * 2; - for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) - result[i] = (uint8_t)pos; - result[0] = 6; - return numAlign; -} - -// Sets every module in the range [left : left + width] * [top : top + height] to dark. -static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) { - for (int dy = 0; dy < height; dy++) { - for (int dx = 0; dx < width; dx++) - setModuleBounded(qrcode, left + dx, top + dy, true); - } -} - -/*---- Drawing data modules and masking ----*/ - -// Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of -// the QR Code to be dark at function modules and light at codeword modules (including unused remainder bits). -static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) { - int qrsize = qrcodegen_getSize(qrcode); - int i = 0; // Bit index into the data - // Do the funny zigzag scan - for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair - if (right == 6) - right = 5; - for (int vert = 0; vert < qrsize; vert++) { // Vertical counter - for (int j = 0; j < 2; j++) { - int x = right - j; // Actual x coordinate - bool upward = ((right + 1) & 2) == 0; - int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate - if (!getModuleBounded(qrcode, x, y) && i < dataLen * 8) { - bool dark = getBit(data[i >> 3], 7 - (i & 7)); - setModuleBounded(qrcode, x, y, dark); - i++; - } - // If this QR Code has any remainder bits (0 to 7), they were assigned as - // 0/false/light by the constructor and are left unchanged by this method - } - } - } - assert(i == dataLen * 8); -} - -// XORs the codeword modules in this QR Code with the given mask pattern -// and given pattern of function modules. The codeword bits must be drawn -// before masking. Due to the arithmetic of XOR, calling applyMask() with -// the same mask value a second time will undo the mask. A final well-formed -// QR Code needs exactly one (not zero, two, etc.) mask applied. -static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) { - assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO - int qrsize = qrcodegen_getSize(qrcode); - for (int y = 0; y < qrsize; y++) { - for (int x = 0; x < qrsize; x++) { - if (getModuleBounded(functionModules, x, y)) - continue; - bool invert; - switch ((int)mask) { - case 0: - invert = (x + y) % 2 == 0; - break; - case 1: - invert = y % 2 == 0; - break; - case 2: - invert = x % 3 == 0; - break; - case 3: - invert = (x + y) % 3 == 0; - break; - case 4: - invert = (x / 3 + y / 2) % 2 == 0; - break; - case 5: - invert = x * y % 2 + x * y % 3 == 0; - break; - case 6: - invert = (x * y % 2 + x * y % 3) % 2 == 0; - break; - case 7: - invert = ((x + y) % 2 + x * y % 3) % 2 == 0; - break; - default: - assert(false); - return; - } - bool val = getModuleBounded(qrcode, x, y); - setModuleBounded(qrcode, x, y, val ^ invert); - } - } -} - -// Calculates and returns the penalty score based on state of the given QR Code's current modules. -// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. -static long getPenaltyScore(const uint8_t qrcode[]) { - int qrsize = qrcodegen_getSize(qrcode); - long result = 0; - - // Adjacent modules in row having same color, and finder-like patterns - for (int y = 0; y < qrsize; y++) { - bool runColor = false; - int runX = 0; - int runHistory[7]; - zeroRunHistory(runHistory); - for (int x = 0; x < qrsize; x++) { - if (getModuleBounded(qrcode, x, y) == runColor) { - runX++; - if (runX == 5) - result += PENALTY_N1; - else if (runX > 5) - result++; - } else { - finderPenaltyAddHistory(runX, runHistory, qrsize); - if (!runColor) - result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; - runColor = getModuleBounded(qrcode, x, y); - runX = 1; - } - } - result += finderPenaltyTerminateAndCount(runColor, runX, runHistory, qrsize) * PENALTY_N3; - } - // Adjacent modules in column having same color, and finder-like patterns - for (int x = 0; x < qrsize; x++) { - bool runColor = false; - int runY = 0; - int runHistory[7]; - zeroRunHistory(runHistory); - for (int y = 0; y < qrsize; y++) { - if (getModuleBounded(qrcode, x, y) == runColor) { - runY++; - if (runY == 5) - result += PENALTY_N1; - else if (runY > 5) - result++; - } else { - finderPenaltyAddHistory(runY, runHistory, qrsize); - if (!runColor) - result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; - runColor = getModuleBounded(qrcode, x, y); - runY = 1; - } - } - result += finderPenaltyTerminateAndCount(runColor, runY, runHistory, qrsize) * PENALTY_N3; - } - - // 2*2 blocks of modules having same color - for (int y = 0; y < qrsize - 1; y++) { - for (int x = 0; x < qrsize - 1; x++) { - bool color = getModuleBounded(qrcode, x, y); - if (color == getModuleBounded(qrcode, x + 1, y) && color == getModuleBounded(qrcode, x, y + 1) && - color == getModuleBounded(qrcode, x + 1, y + 1)) - result += PENALTY_N2; - } - } - - // Balance of dark and light modules - int dark = 0; - for (int y = 0; y < qrsize; y++) { - for (int x = 0; x < qrsize; x++) { - if (getModuleBounded(qrcode, x, y)) - dark++; - } - } - int total = qrsize * qrsize; // Note that size is odd, so dark/total != 1/2 - // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% - int k = (int)((labs(dark * 20L - total * 10L) + total - 1) / total) - 1; - assert(0 <= k && k <= 9); - result += k * PENALTY_N4; - assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 - return result; -} - -// Can only be called immediately after a light run is added, and -// returns either 0, 1, or 2. A helper function for getPenaltyScore(). -static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize) { - int n = runHistory[1]; - assert(n <= qrsize * 3); - (void)qrsize; - bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; - // The maximum QR Code size is 177, hence the dark run length n <= 177. - // Arithmetic is promoted to int, so n*4 will not overflow. - return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) + - (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); -} - -// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). -static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize) { - if (currentRunColor) { // Terminate dark run - finderPenaltyAddHistory(currentRunLength, runHistory, qrsize); - currentRunLength = 0; - } - currentRunLength += qrsize; // Add light border to final run - finderPenaltyAddHistory(currentRunLength, runHistory, qrsize); - return finderPenaltyCountPatterns(runHistory, qrsize); -} - -// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). -static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize) { - if (runHistory[0] == 0) - currentRunLength += qrsize; // Add light border to initial run - memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0])); - runHistory[0] = currentRunLength; -} - -static void zeroRunHistory(int runHistory[7]) { - for (int i = 0; i < 7; i++) - runHistory[i] = 0; -} - -/*---- Basic QR Code information ----*/ - -// Public function - see documentation comment in header file. -int qrcodegen_getSize(const uint8_t qrcode[]) { - assert(qrcode != NULL); - int result = qrcode[0]; - assert((qrcodegen_VERSION_MIN * 4 + 17) <= result && result <= (qrcodegen_VERSION_MAX * 4 + 17)); - return result; -} - -// Public function - see documentation comment in header file. -bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) { - assert(qrcode != NULL); - int qrsize = qrcode[0]; - return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModuleBounded(qrcode, x, y); -} - -// Returns the color of the module at the given coordinates, which must be in bounds. -testable bool getModuleBounded(const uint8_t qrcode[], int x, int y) { - int qrsize = qrcode[0]; - assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); - int index = y * qrsize + x; - return getBit(qrcode[(index >> 3) + 1], index & 7); -} - -// Sets the color of the module at the given coordinates, which must be in bounds. -testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark) { - int qrsize = qrcode[0]; - assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); - int index = y * qrsize + x; - int bitIndex = index & 7; - int byteIndex = (index >> 3) + 1; - if (isDark) - qrcode[byteIndex] |= 1 << bitIndex; - else - qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF; -} - -// Sets the color of the module at the given coordinates, doing nothing if out of bounds. -testable void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool isDark) { - int qrsize = qrcode[0]; - if (0 <= x && x < qrsize && 0 <= y && y < qrsize) - setModuleBounded(qrcode, x, y, isDark); -} - -// Returns true iff the i'th bit of x is set to 1. Requires x >= 0 and 0 <= i <= 14. -static bool getBit(int x, int i) { - return ((x >> i) & 1) != 0; -} - -/*---- Segment handling ----*/ - -// Public function - see documentation comment in header file. -bool qrcodegen_isNumeric(const char *text) { - assert(text != NULL); - for (; *text != '\0'; text++) { - if (*text < '0' || *text > '9') - return false; - } - return true; -} - -// Public function - see documentation comment in header file. -bool qrcodegen_isAlphanumeric(const char *text) { - assert(text != NULL); - for (; *text != '\0'; text++) { - if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) - return false; - } - return true; -} - -// Public function - see documentation comment in header file. -size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) { - int temp = calcSegmentBitLength(mode, numChars); - if (temp == LENGTH_OVERFLOW) - return SIZE_MAX; - assert(0 <= temp && temp <= INT16_MAX); - return ((size_t)temp + 7) / 8; -} - -// Returns the number of data bits needed to represent a segment -// containing the given number of characters using the given mode. Notes: -// - Returns LENGTH_OVERFLOW on failure, i.e. numChars > INT16_MAX -// or the number of needed bits exceeds INT16_MAX (i.e. 32767). -// - Otherwise, all valid results are in the range [0, INT16_MAX]. -// - For byte mode, numChars measures the number of bytes, not Unicode code points. -// - For ECI mode, numChars must be 0, and the worst-case number of bits is returned. -// An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. -testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { - // All calculations are designed to avoid overflow on all platforms - if (numChars > (unsigned int)INT16_MAX) - return LENGTH_OVERFLOW; - long result = (long)numChars; - if (mode == qrcodegen_Mode_NUMERIC) - result = (result * 10 + 2) / 3; // ceil(10/3 * n) - else if (mode == qrcodegen_Mode_ALPHANUMERIC) - result = (result * 11 + 1) / 2; // ceil(11/2 * n) - else if (mode == qrcodegen_Mode_BYTE) - result *= 8; - else if (mode == qrcodegen_Mode_KANJI) - result *= 13; - else if (mode == qrcodegen_Mode_ECI && numChars == 0) - result = 3 * 8; - else { // Invalid argument - assert(false); - return LENGTH_OVERFLOW; - } - assert(result >= 0); - if (result > INT16_MAX) - return LENGTH_OVERFLOW; - return (int)result; -} - -// Public function - see documentation comment in header file. -struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) { - assert(data != NULL || len == 0); - struct qrcodegen_Segment result; - result.mode = qrcodegen_Mode_BYTE; - result.bitLength = calcSegmentBitLength(result.mode, len); - assert(result.bitLength != LENGTH_OVERFLOW); - result.numChars = (int)len; - if (len > 0) - memcpy(buf, data, len * sizeof(buf[0])); - result.data = buf; - return result; -} - -// Public function - see documentation comment in header file. -struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) { - assert(digits != NULL); - struct qrcodegen_Segment result; - size_t len = strlen(digits); - result.mode = qrcodegen_Mode_NUMERIC; - int bitLen = calcSegmentBitLength(result.mode, len); - assert(bitLen != LENGTH_OVERFLOW); - result.numChars = (int)len; - if (bitLen > 0) - memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); - result.bitLength = 0; - - unsigned int accumData = 0; - int accumCount = 0; - for (; *digits != '\0'; digits++) { - char c = *digits; - assert('0' <= c && c <= '9'); - accumData = accumData * 10 + (unsigned int)(c - '0'); - accumCount++; - if (accumCount == 3) { - appendBitsToBuffer(accumData, 10, buf, &result.bitLength); - accumData = 0; - accumCount = 0; - } - } - if (accumCount > 0) // 1 or 2 digits remaining - appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength); - assert(result.bitLength == bitLen); - result.data = buf; - return result; -} - -// Public function - see documentation comment in header file. -struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) { - assert(text != NULL); - struct qrcodegen_Segment result; - size_t len = strlen(text); - result.mode = qrcodegen_Mode_ALPHANUMERIC; - int bitLen = calcSegmentBitLength(result.mode, len); - assert(bitLen != LENGTH_OVERFLOW); - result.numChars = (int)len; - if (bitLen > 0) - memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); - result.bitLength = 0; - - unsigned int accumData = 0; - int accumCount = 0; - for (; *text != '\0'; text++) { - const char *temp = strchr(ALPHANUMERIC_CHARSET, *text); - assert(temp != NULL); - accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET); - accumCount++; - if (accumCount == 2) { - appendBitsToBuffer(accumData, 11, buf, &result.bitLength); - accumData = 0; - accumCount = 0; - } - } - if (accumCount > 0) // 1 character remaining - appendBitsToBuffer(accumData, 6, buf, &result.bitLength); - assert(result.bitLength == bitLen); - result.data = buf; - return result; -} - -// Public function - see documentation comment in header file. -struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { - struct qrcodegen_Segment result; - result.mode = qrcodegen_Mode_ECI; - result.numChars = 0; - result.bitLength = 0; - if (assignVal < 0) - assert(false); - else if (assignVal < (1 << 7)) { - memset(buf, 0, 1 * sizeof(buf[0])); - appendBitsToBuffer((unsigned int)assignVal, 8, buf, &result.bitLength); - } else if (assignVal < (1 << 14)) { - memset(buf, 0, 2 * sizeof(buf[0])); - appendBitsToBuffer(2, 2, buf, &result.bitLength); - appendBitsToBuffer((unsigned int)assignVal, 14, buf, &result.bitLength); - } else if (assignVal < 1000000L) { - memset(buf, 0, 3 * sizeof(buf[0])); - appendBitsToBuffer(6, 3, buf, &result.bitLength); - appendBitsToBuffer((unsigned int)(assignVal >> 10), 11, buf, &result.bitLength); - appendBitsToBuffer((unsigned int)(assignVal & 0x3FF), 10, buf, &result.bitLength); - } else - assert(false); - result.data = buf; - return result; -} - -// Calculates the number of bits needed to encode the given segments at the given version. -// Returns a non-negative number if successful. Otherwise returns LENGTH_OVERFLOW if a segment -// has too many characters to fit its length field, or the total bits exceeds INT16_MAX. -testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) { - assert(segs != NULL || len == 0); - long result = 0; - for (size_t i = 0; i < len; i++) { - int numChars = segs[i].numChars; - int bitLength = segs[i].bitLength; - assert(0 <= numChars && numChars <= INT16_MAX); - assert(0 <= bitLength && bitLength <= INT16_MAX); - int ccbits = numCharCountBits(segs[i].mode, version); - assert(0 <= ccbits && ccbits <= 16); - if (numChars >= (1L << ccbits)) - return LENGTH_OVERFLOW; // The segment's length doesn't fit the field's bit width - result += 4L + ccbits + bitLength; - if (result > INT16_MAX) - return LENGTH_OVERFLOW; // The sum might overflow an int type - } - assert(0 <= result && result <= INT16_MAX); - return (int)result; -} - -// Returns the bit width of the character count field for a segment in the given mode -// in a QR Code at the given version number. The result is in the range [0, 16]. -static int numCharCountBits(enum qrcodegen_Mode mode, int version) { - assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); - int i = (version + 7) / 17; - switch (mode) { - case qrcodegen_Mode_NUMERIC: { - static const int temp[] = {10, 12, 14}; - return temp[i]; - } - case qrcodegen_Mode_ALPHANUMERIC: { - static const int temp[] = {9, 11, 13}; - return temp[i]; - } - case qrcodegen_Mode_BYTE: { - static const int temp[] = {8, 16, 16}; - return temp[i]; - } - case qrcodegen_Mode_KANJI: { - static const int temp[] = {8, 10, 12}; - return temp[i]; - } - case qrcodegen_Mode_ECI: - return 0; - default: - assert(false); - return -1; // Dummy value - } -} - -#undef LENGTH_OVERFLOW diff --git a/clks/third_party/qrcodegen/qrcodegen.h b/clks/third_party/qrcodegen/qrcodegen.h deleted file mode 100644 index 8cf3d2d..0000000 --- a/clks/third_party/qrcodegen/qrcodegen.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * QR Code generator library (C) - * - * Copyright (c) Project Nayuki. (MIT License) - * https://www.nayuki.io/page/qr-code-generator-library - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - The Software is provided "as is", without warranty of any kind, express or - * implied, including but not limited to the warranties of merchantability, - * fitness for a particular purpose and noninfringement. In no event shall the - * authors or copyright holders be liable for any claim, damages or other - * liability, whether in an action of contract, tort or otherwise, arising from, - * out of or in connection with the Software or the use or other dealings in the - * Software. - */ - -#pragma once - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * This library creates QR Code symbols, which is a type of two-dimension barcode. - * Invented by Denso Wave and described in the ISO/IEC 18004 standard. - * A QR Code structure is an immutable square grid of dark and light cells. - * The library provides functions to create a QR Code from text or binary data. - * The library covers the QR Code Model 2 specification, supporting all versions (sizes) - * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. - * - * Ways to create a QR Code object: - * - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary(). - * - Low level: Custom-make the list of segments and call - * qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced(). - * (Note that all ways require supplying the desired error correction level and various byte buffers.) - */ - -/*---- Enum and struct types----*/ - -/* - * The error correction level in a QR Code symbol. - */ -enum qrcodegen_Ecc { - // Must be declared in ascending order of error protection - // so that an internal qrcodegen function works properly - qrcodegen_Ecc_LOW = 0, // The QR Code can tolerate about 7% erroneous codewords - qrcodegen_Ecc_MEDIUM, // The QR Code can tolerate about 15% erroneous codewords - qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords - qrcodegen_Ecc_HIGH, // The QR Code can tolerate about 30% erroneous codewords -}; - -/* - * The mask pattern used in a QR Code symbol. - */ -enum qrcodegen_Mask { - // A special value to tell the QR Code encoder to - // automatically select an appropriate mask pattern - qrcodegen_Mask_AUTO = -1, - // The eight actual mask patterns - qrcodegen_Mask_0 = 0, - qrcodegen_Mask_1, - qrcodegen_Mask_2, - qrcodegen_Mask_3, - qrcodegen_Mask_4, - qrcodegen_Mask_5, - qrcodegen_Mask_6, - qrcodegen_Mask_7, -}; - -/* - * Describes how a segment's data bits are interpreted. - */ -enum qrcodegen_Mode { - qrcodegen_Mode_NUMERIC = 0x1, - qrcodegen_Mode_ALPHANUMERIC = 0x2, - qrcodegen_Mode_BYTE = 0x4, - qrcodegen_Mode_KANJI = 0x8, - qrcodegen_Mode_ECI = 0x7, -}; - -/* - * A segment of character/binary/control data in a QR Code symbol. - * The mid-level way to create a segment is to take the payload data - * and call a factory function such as qrcodegen_makeNumeric(). - * The low-level way to create a segment is to custom-make the bit buffer - * and initialize a qrcodegen_Segment struct with appropriate values. - * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. - * Any segment longer than this is meaningless for the purpose of generating QR Codes. - * Moreover, the maximum allowed bit length is 32767 because - * the largest QR Code (version 40) has 31329 modules. - */ -struct qrcodegen_Segment { - // The mode indicator of this segment. - enum qrcodegen_Mode mode; - - // The length of this segment's unencoded data. Measured in characters for - // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. - // Always zero or positive. Not the same as the data's bit length. - int numChars; - - // The data bits of this segment, packed in bitwise big endian. - // Can be null if the bit length is zero. - uint8_t *data; - - // The number of valid data bits used in the buffer. Requires - // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8. - // The character count (numChars) must agree with the mode and the bit buffer length. - int bitLength; -}; - -/*---- Macro constants and functions ----*/ - -#define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard -#define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard - -// Calculates the number of bytes needed to store any QR Code up to and including the given version number, -// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];' -// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16). -// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX. -#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1) - -// The worst-case number of bytes needed to store one QR Code, up to and including -// version 40. This value equals 3918, which is just under 4 kilobytes. -// Use this more convenient value to avoid calculating tighter memory bounds for buffers. -#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX) - -/*---- Functions (high level) to generate QR Codes ----*/ - -/* - * Encodes the given text string to a QR Code, returning true if successful. - * If the data is too long to fit in any version in the given range - * at the given ECC level, then false is returned. - * - * The input text must be encoded in UTF-8 and contain no NULs. - * Requires 1 <= minVersion <= maxVersion <= 40. - * - * The smallest possible QR Code version within the given range is automatically - * chosen for the output. Iff boostEcl is true, then the ECC level of the result - * may be higher than the ecl argument if it can be done without increasing the - * version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or - * qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow). - * - * About the arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion): - * - Before calling the function: - * - The array ranges tempBuffer[0 : len] and qrcode[0 : len] must allow - * reading and writing; hence each array must have a length of at least len. - * - The two ranges must not overlap (aliasing). - * - The initial state of both ranges can be uninitialized - * because the function always writes before reading. - * - After the function returns: - * - Both ranges have no guarantee on which elements are initialized and what values are stored. - * - tempBuffer contains no useful data and should be treated as entirely uninitialized. - * - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule(). - * - * If successful, the resulting QR Code may use numeric, - * alphanumeric, or byte mode to encode the text. - * - * In the most optimistic case, a QR Code at version 40 with low ECC - * can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string - * up to 4296 characters, or any digit string up to 7089 characters. - * These numbers represent the hard upper limit of the QR Code standard. - * - * Please consult the QR Code specification for information on - * data capacities per version, ECC level, and text encoding mode. - */ -bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl, - int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); - -/* - * Encodes the given binary data to a QR Code, returning true if successful. - * If the data is too long to fit in any version in the given range - * at the given ECC level, then false is returned. - * - * Requires 1 <= minVersion <= maxVersion <= 40. - * - * The smallest possible QR Code version within the given range is automatically - * chosen for the output. Iff boostEcl is true, then the ECC level of the result - * may be higher than the ecl argument if it can be done without increasing the - * version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or - * qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow). - * - * About the arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion): - * - Before calling the function: - * - The array ranges dataAndTemp[0 : len] and qrcode[0 : len] must allow - * reading and writing; hence each array must have a length of at least len. - * - The two ranges must not overlap (aliasing). - * - The input array range dataAndTemp[0 : dataLen] should normally be - * valid UTF-8 text, but is not required by the QR Code standard. - * - The initial state of dataAndTemp[dataLen : len] and qrcode[0 : len] - * can be uninitialized because the function always writes before reading. - * - After the function returns: - * - Both ranges have no guarantee on which elements are initialized and what values are stored. - * - dataAndTemp contains no useful data and should be treated as entirely uninitialized. - * - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule(). - * - * If successful, the resulting QR Code will use byte mode to encode the data. - * - * In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte - * sequence up to length 2953. This is the hard upper limit of the QR Code standard. - * - * Please consult the QR Code specification for information on - * data capacities per version, ECC level, and text encoding mode. - */ -bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], enum qrcodegen_Ecc ecl, - int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); - -/*---- Functions (low level) to generate QR Codes ----*/ - -/* - * Encodes the given segments to a QR Code, returning true if successful. - * If the data is too long to fit in any version at the given ECC level, - * then false is returned. - * - * The smallest possible QR Code version is automatically chosen for - * the output. The ECC level of the result may be higher than the - * ecl argument if it can be done without increasing the version. - * - * About the byte arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX): - * - Before calling the function: - * - The array ranges tempBuffer[0 : len] and qrcode[0 : len] must allow - * reading and writing; hence each array must have a length of at least len. - * - The two ranges must not overlap (aliasing). - * - The initial state of both ranges can be uninitialized - * because the function always writes before reading. - * - The input array segs can contain segments whose data buffers overlap with tempBuffer. - * - After the function returns: - * - Both ranges have no guarantee on which elements are initialized and what values are stored. - * - tempBuffer contains no useful data and should be treated as entirely uninitialized. - * - Any segment whose data buffer overlaps with tempBuffer[0 : len] - * must be treated as having invalid values in that array. - * - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule(). - * - * Please consult the QR Code specification for information on - * data capacities per version, ECC level, and text encoding mode. - * - * This function allows the user to create a custom sequence of segments that switches - * between modes (such as alphanumeric and byte) to encode text in less space. - * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). - */ -bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, - uint8_t tempBuffer[], uint8_t qrcode[]); - -/* - * Encodes the given segments to a QR Code, returning true if successful. - * If the data is too long to fit in any version in the given range - * at the given ECC level, then false is returned. - * - * Requires 1 <= minVersion <= maxVersion <= 40. - * - * The smallest possible QR Code version within the given range is automatically - * chosen for the output. Iff boostEcl is true, then the ECC level of the result - * may be higher than the ecl argument if it can be done without increasing the - * version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or - * qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow). - * - * About the byte arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX): - * - Before calling the function: - * - The array ranges tempBuffer[0 : len] and qrcode[0 : len] must allow - * reading and writing; hence each array must have a length of at least len. - * - The two ranges must not overlap (aliasing). - * - The initial state of both ranges can be uninitialized - * because the function always writes before reading. - * - The input array segs can contain segments whose data buffers overlap with tempBuffer. - * - After the function returns: - * - Both ranges have no guarantee on which elements are initialized and what values are stored. - * - tempBuffer contains no useful data and should be treated as entirely uninitialized. - * - Any segment whose data buffer overlaps with tempBuffer[0 : len] - * must be treated as having invalid values in that array. - * - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule(). - * - * Please consult the QR Code specification for information on - * data capacities per version, ECC level, and text encoding mode. - * - * This function allows the user to create a custom sequence of segments that switches - * between modes (such as alphanumeric and byte) to encode text in less space. - * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). - */ -bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, - int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, - uint8_t tempBuffer[], uint8_t qrcode[]); - -/* - * Tests whether the given string can be encoded as a segment in numeric mode. - * A string is encodable iff each character is in the range 0 to 9. - */ -bool qrcodegen_isNumeric(const char *text); - -/* - * Tests whether the given string can be encoded as a segment in alphanumeric mode. - * A string is encodable iff each character is in the following set: 0 to 9, A to Z - * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. - */ -bool qrcodegen_isAlphanumeric(const char *text); - -/* - * Returns the number of bytes (uint8_t) needed for the data buffer of a segment - * containing the given number of characters using the given mode. Notes: - * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or the internal - * calculation of the number of needed bits exceeds INT16_MAX (i.e. 32767). - * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096. - * - It is okay for the user to allocate more bytes for the buffer than needed. - * - For byte mode, numChars measures the number of bytes, not Unicode code points. - * - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned. - * An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. - */ -size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars); - -/* - * Returns a segment representing the given binary data encoded in - * byte mode. All input byte arrays are acceptable. Any text string - * can be converted to UTF-8 bytes and encoded as a byte mode segment. - */ -struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]); - -/* - * Returns a segment representing the given string of decimal digits encoded in numeric mode. - */ -struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); - -/* - * Returns a segment representing the given text string encoded in alphanumeric mode. - * The characters allowed are: 0 to 9, A to Z (uppercase only), space, - * dollar, percent, asterisk, plus, hyphen, period, slash, colon. - */ -struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); - -/* - * Returns a segment representing an Extended Channel Interpretation - * (ECI) designator with the given assignment value. - */ -struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); - -/*---- Functions to extract raw data from QR Codes ----*/ - -/* - * Returns the side length of the given QR Code, assuming that encoding succeeded. - * The result is in the range [21, 177]. Note that the length of the array buffer - * is related to the side length - every 'uint8_t qrcode[]' must have length at least - * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1). - */ -int qrcodegen_getSize(const uint8_t qrcode[]); - -/* - * Returns the color of the module (pixel) at the given coordinates, which is false - * for light or true for dark. The top left corner has the coordinates (x=0, y=0). - * If the given coordinates are out of bounds, then false (light) is returned. - */ -bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y); - -#ifdef __cplusplus -} -#endif