mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-24 11:14:01 +00:00
接着上个
This commit is contained in:
163
clks.local.bak/CMakeLists.txt
Normal file
163
clks.local.bak/CMakeLists.txt
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
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)
|
||||||
51
clks.local.bak/License
Normal file
51
clks.local.bak/License
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
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
|
||||||
47
clks.local.bak/Makefile
Normal file
47
clks.local.bak/Makefile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
.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"
|
||||||
67
clks.local.bak/README.md
Normal file
67
clks.local.bak/README.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# 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).
|
||||||
67
clks.local.bak/README.zh-CN.md
Normal file
67
clks.local.bak/README.zh-CN.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# 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(与项目根目录一致)。
|
||||||
38
clks.local.bak/arch/aarch64/linker.ld
Normal file
38
clks.local.bak/arch/aarch64/linker.ld
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
clks.local.bak/arch/aarch64/startup/boot.c
Normal file
7
clks.local.bak/arch/aarch64/startup/boot.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <clks/cpu.h>
|
||||||
|
#include <clks/kernel.h>
|
||||||
|
|
||||||
|
void _start(void) {
|
||||||
|
clks_kernel_main();
|
||||||
|
clks_cpu_halt_forever();
|
||||||
|
}
|
||||||
119
clks.local.bak/arch/x86_64/interrupt/interrupt_stubs.S
Normal file
119
clks.local.bak/arch/x86_64/interrupt/interrupt_stubs.S
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
.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
|
||||||
42
clks.local.bak/arch/x86_64/linker.ld
Normal file
42
clks.local.bak/arch/x86_64/linker.ld
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
clks.local.bak/arch/x86_64/startup/boot.c
Normal file
7
clks.local.bak/arch/x86_64/startup/boot.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <clks/cpu.h>
|
||||||
|
#include <clks/kernel.h>
|
||||||
|
|
||||||
|
void _start(void) {
|
||||||
|
clks_kernel_main();
|
||||||
|
clks_cpu_halt_forever();
|
||||||
|
}
|
||||||
47
clks.local.bak/arch/x86_64/startup/exec_stack_call.S
Normal file
47
clks.local.bak/arch/x86_64/startup/exec_stack_call.S
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
.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
|
||||||
12
clks.local.bak/include/clks/audio.h
Normal file
12
clks.local.bak/include/clks/audio.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef CLKS_AUDIO_H
|
||||||
|
#define CLKS_AUDIO_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
14
clks.local.bak/include/clks/boot.h
Normal file
14
clks.local.bak/include/clks/boot.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef CLKS_BOOT_H
|
||||||
|
#define CLKS_BOOT_H
|
||||||
|
|
||||||
|
#include <clks/limine.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
17
clks.local.bak/include/clks/compiler.h
Normal file
17
clks.local.bak/include/clks/compiler.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#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
|
||||||
24
clks.local.bak/include/clks/cpu.h
Normal file
24
clks.local.bak/include/clks/cpu.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef CLKS_CPU_H
|
||||||
|
#define CLKS_CPU_H
|
||||||
|
|
||||||
|
#include <clks/compiler.h>
|
||||||
|
|
||||||
|
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
|
||||||
10
clks.local.bak/include/clks/desktop.h
Normal file
10
clks.local.bak/include/clks/desktop.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef CLKS_DESKTOP_H
|
||||||
|
#define CLKS_DESKTOP_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
void clks_desktop_init(void);
|
||||||
|
void clks_desktop_tick(u64 tick);
|
||||||
|
clks_bool clks_desktop_ready(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
38
clks.local.bak/include/clks/disk.h
Normal file
38
clks.local.bak/include/clks/disk.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef CLKS_DISK_H
|
||||||
|
#define CLKS_DISK_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
36
clks.local.bak/include/clks/driver.h
Normal file
36
clks.local.bak/include/clks/driver.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef CLKS_DRIVER_H
|
||||||
|
#define CLKS_DRIVER_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
40
clks.local.bak/include/clks/elf64.h
Normal file
40
clks.local.bak/include/clks/elf64.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef CLKS_ELF64_H
|
||||||
|
#define CLKS_ELF64_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
9
clks.local.bak/include/clks/elfrunner.h
Normal file
9
clks.local.bak/include/clks/elfrunner.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CLKS_ELFRUNNER_H
|
||||||
|
#define CLKS_ELFRUNNER_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
void clks_elfrunner_init(void);
|
||||||
|
clks_bool clks_elfrunner_probe_kernel_executable(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
80
clks.local.bak/include/clks/exec.h
Normal file
80
clks.local.bak/include/clks/exec.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#ifndef CLKS_EXEC_H
|
||||||
|
#define CLKS_EXEC_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
31
clks.local.bak/include/clks/framebuffer.h
Normal file
31
clks.local.bak/include/clks/framebuffer.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef CLKS_FRAMEBUFFER_H
|
||||||
|
#define CLKS_FRAMEBUFFER_H
|
||||||
|
|
||||||
|
#include <clks/limine.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
30
clks.local.bak/include/clks/fs.h
Normal file
30
clks.local.bak/include/clks/fs.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef CLKS_FS_H
|
||||||
|
#define CLKS_FS_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
19
clks.local.bak/include/clks/heap.h
Normal file
19
clks.local.bak/include/clks/heap.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef CLKS_HEAP_H
|
||||||
|
#define CLKS_HEAP_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
9
clks.local.bak/include/clks/interrupts.h
Normal file
9
clks.local.bak/include/clks/interrupts.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CLKS_INTERRUPTS_H
|
||||||
|
#define CLKS_INTERRUPTS_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
void clks_interrupts_init(void);
|
||||||
|
u64 clks_interrupts_timer_ticks(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
13
clks.local.bak/include/clks/kelf.h
Normal file
13
clks.local.bak/include/clks/kelf.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef CLKS_KELF_H
|
||||||
|
#define CLKS_KELF_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
6
clks.local.bak/include/clks/kernel.h
Normal file
6
clks.local.bak/include/clks/kernel.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef CLKS_KERNEL_H
|
||||||
|
#define CLKS_KERNEL_H
|
||||||
|
|
||||||
|
void clks_kernel_main(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
31
clks.local.bak/include/clks/keyboard.h
Normal file
31
clks.local.bak/include/clks/keyboard.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef CLKS_KEYBOARD_H
|
||||||
|
#define CLKS_KEYBOARD_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
135
clks.local.bak/include/clks/limine.h
Normal file
135
clks.local.bak/include/clks/limine.h
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#ifndef CLKS_LIMINE_H
|
||||||
|
#define CLKS_LIMINE_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
19
clks.local.bak/include/clks/log.h
Normal file
19
clks.local.bak/include/clks/log.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef CLKS_LOG_H
|
||||||
|
#define CLKS_LOG_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
25
clks.local.bak/include/clks/mouse.h
Normal file
25
clks.local.bak/include/clks/mouse.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef CLKS_MOUSE_H
|
||||||
|
#define CLKS_MOUSE_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
10
clks.local.bak/include/clks/panic.h
Normal file
10
clks.local.bak/include/clks/panic.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef CLKS_PANIC_H
|
||||||
|
#define CLKS_PANIC_H
|
||||||
|
|
||||||
|
#include <clks/compiler.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
19
clks.local.bak/include/clks/panic_qr.h
Normal file
19
clks.local.bak/include/clks/panic_qr.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef CLKS_PANIC_QR_H
|
||||||
|
#define CLKS_PANIC_QR_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
21
clks.local.bak/include/clks/pmm.h
Normal file
21
clks.local.bak/include/clks/pmm.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef CLKS_PMM_H
|
||||||
|
#define CLKS_PMM_H
|
||||||
|
|
||||||
|
#include <clks/limine.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
24
clks.local.bak/include/clks/ramdisk.h
Normal file
24
clks.local.bak/include/clks/ramdisk.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef CLKS_RAMDISK_H
|
||||||
|
#define CLKS_RAMDISK_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
22
clks.local.bak/include/clks/scheduler.h
Normal file
22
clks.local.bak/include/clks/scheduler.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef CLKS_SCHEDULER_H
|
||||||
|
#define CLKS_SCHEDULER_H
|
||||||
|
|
||||||
|
#include <clks/task.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
8
clks.local.bak/include/clks/serial.h
Normal file
8
clks.local.bak/include/clks/serial.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#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
|
||||||
38
clks.local.bak/include/clks/service.h
Normal file
38
clks.local.bak/include/clks/service.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef CLKS_SERVICE_H
|
||||||
|
#define CLKS_SERVICE_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
10
clks.local.bak/include/clks/shell.h
Normal file
10
clks.local.bak/include/clks/shell.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef CLKS_SHELL_H
|
||||||
|
#define CLKS_SHELL_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
void clks_shell_init(void);
|
||||||
|
void clks_shell_pump_input(u32 max_chars);
|
||||||
|
void clks_shell_tick(u64 tick);
|
||||||
|
|
||||||
|
#endif
|
||||||
12
clks.local.bak/include/clks/string.h
Normal file
12
clks.local.bak/include/clks/string.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef CLKS_STRING_H
|
||||||
|
#define CLKS_STRING_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
106
clks.local.bak/include/clks/syscall.h
Normal file
106
clks.local.bak/include/clks/syscall.h
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#ifndef CLKS_SYSCALL_H
|
||||||
|
#define CLKS_SYSCALL_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
25
clks.local.bak/include/clks/task.h
Normal file
25
clks.local.bak/include/clks/task.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef CLKS_TASK_H
|
||||||
|
#define CLKS_TASK_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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
|
||||||
18
clks.local.bak/include/clks/tty.h
Normal file
18
clks.local.bak/include/clks/tty.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CLKS_TTY_H
|
||||||
|
#define CLKS_TTY_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
20
clks.local.bak/include/clks/types.h
Normal file
20
clks.local.bak/include/clks/types.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#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
|
||||||
15
clks.local.bak/include/clks/userland.h
Normal file
15
clks.local.bak/include/clks/userland.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef CLKS_USERLAND_H
|
||||||
|
#define CLKS_USERLAND_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
6
clks.local.bak/include/clks/version.h
Normal file
6
clks.local.bak/include/clks/version.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef CLKS_VERSION_H
|
||||||
|
#define CLKS_VERSION_H
|
||||||
|
|
||||||
|
#define CLKS_VERSION_STRING "1.0.0-alpha"
|
||||||
|
|
||||||
|
#endif
|
||||||
101
clks.local.bak/kernel/boot/limine/limine_requests.c
Normal file
101
clks.local.bak/kernel/boot/limine/limine_requests.c
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#include <clks/boot.h>
|
||||||
|
#include <clks/compiler.h>
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
349
clks.local.bak/kernel/core/interrupts.c
Normal file
349
clks.local.bak/kernel/core/interrupts.c
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
#include <clks/compiler.h>
|
||||||
|
#include <clks/cpu.h>
|
||||||
|
#include <clks/exec.h>
|
||||||
|
#include <clks/interrupts.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/keyboard.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
|
#include <clks/panic.h>
|
||||||
|
#include <clks/scheduler.h>
|
||||||
|
#include <clks/syscall.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
472
clks.local.bak/kernel/core/kmain.c
Normal file
472
clks.local.bak/kernel/core/kmain.c
Normal file
@@ -0,0 +1,472 @@
|
|||||||
|
// Kernel main function
|
||||||
|
|
||||||
|
#include <clks/boot.h>
|
||||||
|
#include <clks/audio.h>
|
||||||
|
#include <clks/cpu.h>
|
||||||
|
#include <clks/desktop.h>
|
||||||
|
#include <clks/driver.h>
|
||||||
|
#include <clks/elfrunner.h>
|
||||||
|
#include <clks/exec.h>
|
||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/fs.h>
|
||||||
|
#include <clks/heap.h>
|
||||||
|
#include <clks/interrupts.h>
|
||||||
|
#include <clks/keyboard.h>
|
||||||
|
#include <clks/kelf.h>
|
||||||
|
#include <clks/kernel.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
|
#include <clks/pmm.h>
|
||||||
|
#include <clks/scheduler.h>
|
||||||
|
#include <clks/serial.h>
|
||||||
|
#include <clks/service.h>
|
||||||
|
#include <clks/shell.h>
|
||||||
|
#include <clks/syscall.h>
|
||||||
|
#include <clks/tty.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
#include <clks/userland.h>
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
226
clks.local.bak/kernel/core/log.c
Normal file
226
clks.local.bak/kernel/core/log.c
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/serial.h>
|
||||||
|
#include <clks/tty.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
864
clks.local.bak/kernel/core/panic.c
Normal file
864
clks.local.bak/kernel/core/panic.c
Normal file
@@ -0,0 +1,864 @@
|
|||||||
|
#include <clks/cpu.h>
|
||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/fs.h>
|
||||||
|
#include <clks/panic.h>
|
||||||
|
#include <clks/panic_qr.h>
|
||||||
|
#include <clks/serial.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
395
clks.local.bak/kernel/core/panic_qr.cpp
Normal file
395
clks.local.bak/kernel/core/panic_qr.cpp
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
extern "C" {
|
||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/panic_qr.h>
|
||||||
|
#include <clks/serial.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
179
clks.local.bak/kernel/core/scheduler.c
Normal file
179
clks.local.bak/kernel/core/scheduler.c
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/scheduler.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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];
|
||||||
|
}
|
||||||
140
clks.local.bak/kernel/core/service.c
Normal file
140
clks.local.bak/kernel/core/service.c
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include <clks/driver.h>
|
||||||
|
#include <clks/fs.h>
|
||||||
|
#include <clks/heap.h>
|
||||||
|
#include <clks/kelf.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/scheduler.h>
|
||||||
|
#include <clks/service.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
#include <clks/userland.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
126
clks.local.bak/kernel/hal/audio/pcspeaker.c
Normal file
126
clks.local.bak/kernel/hal/audio/pcspeaker.c
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#include <clks/audio.h>
|
||||||
|
#include <clks/exec.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
67
clks.local.bak/kernel/hal/serial/serial.c
Normal file
67
clks.local.bak/kernel/hal/serial/serial.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <clks/compiler.h>
|
||||||
|
#include <clks/serial.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
clks.local.bak/kernel/hal/video/font8x8.c
Normal file
53
clks.local.bak/kernel/hal/video/font8x8.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#include "font8x8.h"
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
8
clks.local.bak/kernel/hal/video/font8x8.h
Normal file
8
clks.local.bak/kernel/hal/video/font8x8.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef CLKS_FONT8X8_H
|
||||||
|
#define CLKS_FONT8X8_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
const u8 *clks_font8x8_get(char ch);
|
||||||
|
|
||||||
|
#endif
|
||||||
315
clks.local.bak/kernel/hal/video/framebuffer.c
Normal file
315
clks.local.bak/kernel/hal/video/framebuffer.c
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
258
clks.local.bak/kernel/hal/video/psf_font.c
Normal file
258
clks.local.bak/kernel/hal/video/psf_font.c
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
#include "psf_font.h"
|
||||||
|
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
19
clks.local.bak/kernel/hal/video/psf_font.h
Normal file
19
clks.local.bak/kernel/hal/video/psf_font.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef CLKS_PSF_FONT_H
|
||||||
|
#define CLKS_PSF_FONT_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
464
clks.local.bak/kernel/input/keyboard.c
Normal file
464
clks.local.bak/kernel/input/keyboard.c
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
#include <clks/exec.h>
|
||||||
|
#include <clks/keyboard.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/shell.h>
|
||||||
|
#include <clks/tty.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
305
clks.local.bak/kernel/input/mouse.c
Normal file
305
clks.local.bak/kernel/input/mouse.c
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
406
clks.local.bak/kernel/interface/desktop.c
Normal file
406
clks.local.bak/kernel/interface/desktop.c
Normal file
@@ -0,0 +1,406 @@
|
|||||||
|
#include <clks/desktop.h>
|
||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
|
#include <clks/tty.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
1549
clks.local.bak/kernel/interface/shell.c
Normal file
1549
clks.local.bak/kernel/interface/shell.c
Normal file
File diff suppressed because it is too large
Load Diff
1432
clks.local.bak/kernel/interface/tty.c
Normal file
1432
clks.local.bak/kernel/interface/tty.c
Normal file
File diff suppressed because it is too large
Load Diff
180
clks.local.bak/kernel/memory/heap.c
Normal file
180
clks.local.bak/kernel/memory/heap.c
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
#include <clks/heap.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
105
clks.local.bak/kernel/memory/pmm.c
Normal file
105
clks.local.bak/kernel/memory/pmm.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#include <clks/pmm.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
214
clks.local.bak/kernel/runtime/driver.c
Normal file
214
clks.local.bak/kernel/runtime/driver.c
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
#include <clks/driver.h>
|
||||||
|
#include <clks/audio.h>
|
||||||
|
#include <clks/elf64.h>
|
||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/fs.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
363
clks.local.bak/kernel/runtime/elf64.c
Normal file
363
clks.local.bak/kernel/runtime/elf64.c
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
#include <clks/elf64.h>
|
||||||
|
#include <clks/heap.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
38
clks.local.bak/kernel/runtime/elfrunner.c
Normal file
38
clks.local.bak/kernel/runtime/elfrunner.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include <clks/boot.h>
|
||||||
|
#include <clks/elf64.h>
|
||||||
|
#include <clks/elfrunner.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
2782
clks.local.bak/kernel/runtime/exec.c
Normal file
2782
clks.local.bak/kernel/runtime/exec.c
Normal file
File diff suppressed because it is too large
Load Diff
250
clks.local.bak/kernel/runtime/kelf.c
Normal file
250
clks.local.bak/kernel/runtime/kelf.c
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
#include <clks/elf64.h>
|
||||||
|
#include <clks/fs.h>
|
||||||
|
#include <clks/heap.h>
|
||||||
|
#include <clks/kelf.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
2672
clks.local.bak/kernel/runtime/syscall.c
Normal file
2672
clks.local.bak/kernel/runtime/syscall.c
Normal file
File diff suppressed because it is too large
Load Diff
183
clks.local.bak/kernel/runtime/userland.c
Normal file
183
clks.local.bak/kernel/runtime/userland.c
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
#include <clks/elf64.h>
|
||||||
|
#include <clks/exec.h>
|
||||||
|
#include <clks/fs.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
#include <clks/userland.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
1856
clks.local.bak/kernel/storage/disk.c
Normal file
1856
clks.local.bak/kernel/storage/disk.c
Normal file
File diff suppressed because it is too large
Load Diff
967
clks.local.bak/kernel/storage/fs.c
Normal file
967
clks.local.bak/kernel/storage/fs.c
Normal file
@@ -0,0 +1,967 @@
|
|||||||
|
#include <clks/boot.h>
|
||||||
|
#include <clks/disk.h>
|
||||||
|
#include <clks/fs.h>
|
||||||
|
#include <clks/heap.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/ramdisk.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
221
clks.local.bak/kernel/storage/ramdisk.c
Normal file
221
clks.local.bak/kernel/storage/ramdisk.c
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
#include <clks/compiler.h>
|
||||||
|
#include <clks/ramdisk.h>
|
||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
62
clks.local.bak/kernel/support/libc_compat.c
Normal file
62
clks.local.bak/kernel/support/libc_compat.c
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include <clks/string.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
70
clks.local.bak/kernel/support/string.c
Normal file
70
clks.local.bak/kernel/support/string.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#include <clks/string.h>
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
27
clks.local.bak/rust/src/lib.rs
Normal file
27
clks.local.bak/rust/src/lib.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#![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() {}
|
||||||
618
clks.local.bak/third_party/miniz/miniz.h
vendored
Normal file
618
clks.local.bak/third_party/miniz/miniz.h
vendored
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
/* 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 <richgel99@gmail.com>, 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 <stddef.h>
|
||||||
|
|
||||||
|
#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
|
||||||
|
#include <time.h>
|
||||||
|
#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"
|
||||||
90
clks.local.bak/third_party/miniz/miniz_common.h
vendored
Normal file
90
clks.local.bak/third_party/miniz/miniz_common.h
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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 <stdio.h>
|
||||||
|
#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
|
||||||
6
clks.local.bak/third_party/miniz/miniz_export.h
vendored
Normal file
6
clks.local.bak/third_party/miniz/miniz_export.h
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef MINIZ_EXPORT_H
|
||||||
|
#define MINIZ_EXPORT_H
|
||||||
|
|
||||||
|
#define MINIZ_EXPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
76
clks.local.bak/third_party/miniz/miniz_support.c
vendored
Normal file
76
clks.local.bak/third_party/miniz/miniz_support.c
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
1506
clks.local.bak/third_party/miniz/miniz_tdef.c
vendored
Normal file
1506
clks.local.bak/third_party/miniz/miniz_tdef.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
206
clks.local.bak/third_party/miniz/miniz_tdef.h
vendored
Normal file
206
clks.local.bak/third_party/miniz/miniz_tdef.h
vendored
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
#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*/
|
||||||
168
clks.local.bak/third_party/miniz/miniz_tinfl.h
vendored
Normal file
168
clks.local.bak/third_party/miniz/miniz_tinfl.h
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
#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*/
|
||||||
523
clks.local.bak/third_party/miniz/miniz_zip.h
vendored
Normal file
523
clks.local.bak/third_party/miniz/miniz_zip.h
vendored
Normal file
@@ -0,0 +1,523 @@
|
|||||||
|
|
||||||
|
#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 */
|
||||||
1030
clks.local.bak/third_party/qrcodegen/qrcodegen.c
vendored
Normal file
1030
clks.local.bak/third_party/qrcodegen/qrcodegen.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
363
clks.local.bak/third_party/qrcodegen/qrcodegen.h
vendored
Normal file
363
clks.local.bak/third_party/qrcodegen/qrcodegen.h
vendored
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
||||||
Reference in New Issue
Block a user