31 Commits

Author SHA1 Message Date
Justin C. Miller
2be70976ca Merge branch 'real-hardware' into fb-driver 2021-01-18 13:38:51 -08:00
Justin C. Miller
699fc57e0a [boot] Log address of new table pages
Since it's often needed when debugging between the bootloader and
kernel, log the address of the table pages the bootloader allocated.
2021-01-18 13:36:05 -08:00
Justin C. Miller
f3bb2e5259 [boot] Save commented-out mem map dumping code
This is often needed, so I'm commiting it commented out.
2021-01-18 13:35:01 -08:00
Justin C. Miller
34120fc4c1 [cpu] Split cpuid validation into separate lib
In order to allow the bootloader to do preliminary CPUID validation
while UEFI is still handling displaying information to the user, split
most of the kernel's CPUID handling into a library to be used by both
kernel and boot.
2021-01-18 13:26:45 -08:00
Justin C. Miller
e52fd8eacf [libc] Attempt to speed up memcpy for aligned mem
Copy long-by-long instead of byte-by-byte if both pointers are similarly
aligned.
2021-01-17 20:54:38 -08:00
Justin C. Miller
a97073848c [fb] Use double-buffering in fb driver
Allocate and use a back buffer, so that draws to the screen are always a
single memcpy()
2021-01-17 20:53:41 -08:00
Justin C. Miller
03b2d0dac7 [kernel] Set framebuffer to write-combining
Several changes were needed to make this work:

- Update the page_table::flags to understand memory caching types
- Set up the PAT MSR to add the WC option
- Make page-offset area mapped as WT
- Add all the MTRR and PAT MSRs, and log the MTRRs for verification
- Add a vm_area flag for write_combining
2021-01-17 20:49:47 -08:00
Justin C. Miller
cfeeba4400 [kenrel] Ensure page tables are zeroed before use
I forgot to zero out pages used for page tables, which didn't come back
to bite me until testing on physical hardware..
2021-01-17 10:35:19 -08:00
Justin C. Miller
45b52633bb [boot] Add scanline size to fb boot message
Scanline size can differ from horizontal resolution in some
framebuffers. This isn't currently handled, but at least log it so
it's visible if this lack of handling is a potential error.
2021-01-17 10:28:54 -08:00
Justin C. Miller
b9af081a44 [boot] Don't use custom UEFI memory types
The UEFI spec specifically calls out memory types with the high bit set
as being available for OS loaders' custom use. However, it seems many
UEFI firmware implementations don't handle this well. (Virtualbox, and
the firmware on my Intel NUC and Dell XPS laptop to name a few.)

So sadly since we can't rely on this feature of UEFI in all cases, we
can't use it at all. Instead, treat _all_ memory tagged as EfiLoaderData
as possibly containing data that's been passed to the OS by the
bootloader and don't free it yet.

This will need to be followed up with a change that copies anything we
need to save and frees this memory.

See: https://github.com/kiznit/rainbow-os/blob/master/boot/machine/efi/README.md
2021-01-17 10:26:24 -08:00
Justin C. Miller
d75b9c22d4 [boot] Don't use custom UEFI memory types
The UEFI spec specifically calls out memory types with the high bit set
as being available for OS loaders' custom use. However, it seems many
UEFI firmware implementations don't handle this well. (Virtualbox, and
the firmware on my Intel NUC and Dell XPS laptop to name a few.)

So sadly since we can't rely on this feature of UEFI in all cases, we
can't use it at all. Instead, treat _all_ memory tagged as EfiLoaderData
as possibly containing data that's been passed to the OS by the
bootloader and don't free it yet.

This will need to be followed up with a change that copies anything we
need to save and frees this memory.

See: https://github.com/kiznit/rainbow-os/blob/master/boot/machine/efi/README.md
2021-01-08 22:40:30 -08:00
Justin C. Miller
e20c53f193 [boot] Add framebuffer progress bar
After exiting UEFI, the bootloader had no way of displaying status to
the user. Now it will display a series of small boxes as a progress bar
along the bottom of the screen if a framebuffer exists. Errors or
warnings during a step will cause that step's box to turn red or orange,
and display bars above it to signal the error code.

This caused the simplification of the error handling system (which was
mostly just calling status_line::fail) and added different types of
status objects.
2021-01-08 22:25:37 -08:00
Justin C. Miller
6d4a32b6e8 [boot] List the detected framebuffer in boot log
List information about the detected framebuffer device (or lack thereof)
in the bootloader log messages.
2021-01-06 23:29:31 -08:00
Justin C. Miller
63a5c2da00 Merge branch 'fb-driver' of github.com:justinian/jsix into fb-driver 2021-01-06 23:26:26 -08:00
Justin C. Miller
bdcd0c2fda [kernel] Clean up process::exit
Make process::exit slightly more resilient to being called again.
2021-01-06 23:25:48 -08:00
Justin C. Miller
1be929b9d5 [fb] Simplify scrollback line counting
Using a start and a count was redundant when we know how many lines are
in the buffer already.
2021-01-06 23:20:29 -08:00
Justin C. Miller
d11dd0c3f9 [kernel] Fix memory clobbering from endpoint
The endpoint receive syscalls can block and then write to userspace
memory. Since the current address space may be different after blocking,
make sure to only actually write to the user memory after returning to
the syscall handler - pass values that are on the syscall handler stack
deeper into the kernel.
2021-01-06 23:16:16 -08:00
Justin C. Miller
e08e00790f [kernel] Give processes and threads self handles
It was not consistent how processes got handles to themselves or their
threads, ending up with double entries. Now make such handles automatic
and expose them with new self_handle() methods.
2021-01-06 23:14:39 -08:00
Justin C. Miller
8b3356e9d8 [kutil] Remove uint64_t hash_node specialization
Using a hash of zero to signal an empty slot doesn't play nice with the
hash_node specialization that uses the key for the hash, when 0 is a
common key.

I thought it would be ok, that it'd just be something to remember. But
then I used 0 as a key anyway, so clearly it was a bad idea.
2021-01-06 23:09:50 -08:00
Justin C. Miller
cd30126f17 [boot] Reduce loader spam
Now that the ELF loader is known to be working correctly, remove its
extra print statements about section loading to keep the bootloader
output to one screen.
2021-01-06 11:34:34 -08:00
Justin C. Miller
2c444dccd6 [build] Remove fake terminal.elf
A fake terminal.elf (copy of nulldrv.elf) was added to test the loader.
Now that there actually are multiple programs to load, remove the fake
one.
2021-01-06 11:32:45 -08:00
Justin C. Miller
bd490c4c7b [scripts] Ignore demangle errors building sym table
For some reason, cxxfilt fails to demangle some names on some systems.
Instead of failing the build process, just skip those symbols.
2021-01-06 11:30:40 -08:00
Justin C. Miller
3a67e461de [scripts] Allow qemu.sh to not remove VGA device
Added --vga option to qemu.sh to stop it from passing "-vga none" to
qemu. This allows the console version to act like it has a video device.
2021-01-04 01:00:03 -08:00
Justin C. Miller
972ef39295 [fb] Output klog to fb if video exists
If there's no video, do as we did before, otherwise route logs to the fb
driver instead. (Need to clean this up to just have a log consumer
general interface?) Also added a "scrollback" class to fb driver and
updated the system_get_log syscall.
2021-01-03 18:13:41 -08:00
Justin C. Miller
4c41205e73 [fb] Change to embedding PSF file
Moved old PSF parsing code from kernel, and switched to embedding whole
PSF instead of just glyph data to make font class the same code paths
for both cases.
2021-01-03 00:08:20 -08:00
Justin C. Miller
f6b4a4a103 [fb] Add default hard-coded font
For the fb driver to have a font before loading from disk is available,
create a hard-coded font as a byte array.

To create this, added a new scripts/psf_to_cpp.py which also refactored
out much of scripts/parse_font.py into a new shared module
scripts/fontpsf.py.
2021-01-02 15:52:26 -08:00
327cd93c04 [kernel] Fix vm_space extra deletion
vm_space::clear() was freeing pages on process exit even when free was
false, and potentially double-freeing some pages.
2020-12-31 00:59:48 -08:00
0e6b27e741 [kernel] Improve process init
Move process init from each process needing a main.s with _start to
crt0.s in libc. Also change to a sysv-like initial stack with a
j6-specific array of initialization values after the program arguments.
2020-12-31 00:57:51 -08:00
db8a14720b [kernel] Rename kernel entrypoint
The kernel entrypoint being named _start conflicts with userspace
program entrypoints and makes debugging more difficult. Rename it to
_kernel_start.
2020-12-30 17:56:37 -08:00
87a7293ac1 [tools] Improve j6stack GDB command
Improve the j6stack command in two ways: first, swap the order of the
arguments, as depth is much more likely to be changed. Second, on any
exception accessing memory in the stack, print the exception and
continue instead of failing the whole command.
2020-12-30 17:49:27 -08:00
5787aff866 [fb] Create fb driver
Create a new framebuffer driver. Also hackily passing frame buffer size
in the list of init handles to all processes and mapping the framebuffer
into all processes. Changed bootloader passing frame buffer as a module
to its own struct.
2020-12-27 18:49:38 -08:00
890 changed files with 36929 additions and 62004 deletions

21
.clang-format Normal file
View File

@@ -0,0 +1,21 @@
---
Language: Cpp
BasedOnStyle: LLVM
ColumnLimit: 100
IndentWidth: 4
TabWidth: 4
UseTab: Always
AccessModifierOffset: -4
AlignEscapedNewlinesLeft: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: AllDefinitions
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Linux

View File

@@ -1,56 +0,0 @@
name: Deploy docs site with Sphinx
on:
push:
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
# Default to bash
defaults:
run:
shell: bash
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
- name: Sphinx build
uses: jsix-os/sphinx-action@master
with:
docs-folder: "docs/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./docs/_build/html
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

11
.gitignore vendored
View File

@@ -1,19 +1,10 @@
.cache
.lock* .lock*
/build* /build*
*.bak *.bak
tags tags
*.log jsix.log
*.out
*.o *.o
*.a *.a
sysroot sysroot
.gdb_history .gdb_history
.peru .peru
__pycache__
/venv
compile_commands.json
buddy_allocs.txt
frame_allocs.txt
heap_allocs.txt
/docs/_build

View File

@@ -1,19 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/src/libraries/**",
"${workspaceFolder}/build/**",
"${workspaceFolder}/sysroot/include"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "linux-clang-x64",
"compileCommands": "${workspaceFolder}/compile_commands.json"
}
],
"version": 4
}

32
.vscode/launch.json vendored
View File

@@ -1,32 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "QEMU Debug Server",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/jsix.elf",
"args": [],
"cwd": "${workspaceFolder}",
"logging": {
//"engineLogging": true,
"programOutput": true
},
"stopAtConnect": true,
"stopAtEntry": false,
"setupCommands": [
{"text": "dashboard -enabled off", "ignoreFailures": true}
],
"MIMode": "gdb",
"miDebuggerServerAddress": "localhost:1234",
"debugServerPath": "${workspaceFolder}/qemu.sh",
"debugServerArgs": "--debug --no-build",
"serverLaunchTimeout": 5000,
}
]
}

45
.vscode/tasks.json vendored
View File

@@ -1,41 +1,28 @@
{ {
// See https://go.microsoft.com/fwlink/?LinkId=733558 // See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format // for the documentation about the tasks.json format
"version": "2.0.0", "version": "0.1.0",
"tasks": [ "tasks": [
{ {
"label": "Ninja", "taskName": "make",
"type": "shell", "command": "make.bat",
"command": "source ${workspaceFolder}/venv/bin/activate.fish; ninja", "isBuildCommand": true
"detail": "Build the project",
"options": {
"cwd": "${workspaceFolder}/build"
},
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}, },
{ {
"label": "Run QEMU", "taskName": "clean",
"command": "./qemu.sh", "command": "make.bat",
"args": [ "--no-build", "--kvm" ], "args": [ "clean" ],
"dependsOn": ["Ninja"], "isShellCommand": true
"options": {
"cwd": "${workspaceFolder}"
},
}, },
{ {
"label": "clean", "taskName": "qemu (windowed)",
"command": "${workspaceFolder}/venv/bin/ninja", "command": "qemu-win.bat",
"options": { "showOutput": "never",
"cwd": "${workspaceFolder}/build" "isTestCommand": true
}, },
"args": [ {
"-t", "taskName": "qemu",
"clean" "command": "qemu.bat"
]
} }
] ]
} }

38
NOTES.md Normal file
View File

@@ -0,0 +1,38 @@
# Design / WIP notes
## TODO
- Paging manager
- Copy-on-write pages
- Better page-allocation model?
- Allow for more than one IOAPIC in ACPI module
- The objects get created, but GSI lookup only uses the one at index 0
- mark kernel memory pages global
- Serial out based on circular/bip biffer and interrupts, not spinning on
`write_ready()`
- Split out more code into kutil for testing
- AHCI / MSI interrupts on Vbox break?
- FXSAVE to save XMM registers.
- optimization using #NM (0x7) to detect SSE usage
- Clean up of process memory maps
- Better stack tracer
- Bootloader rewrite
- C++ and sharing library code for ELF, initrd, etc
- Parse initrd and pre-load certain ELF images, eg the process loader process?
- Do initial memory bootstrap?
- Calling global ctors
- Device Tree
- Actual serial driver
- Disk driver
- File system
- Multiprocessing
- Fast syscalls using syscall/sysret
### Build
- Clean up build generator and its templates
- More robust objects to represent modules & targets to pass to templates
- Read project setup from a simple JSON/TOML/etc
- Better compartmentalizing when doing template inheritance
- Move to LLD as sysroot linker

185
README.md
View File

@@ -1,19 +1,15 @@
![jsix](assets/jsix.svg) # jsix: A toy OS kernel
# The jsix operating system **jsix** is the kernel for the hobby OS that I am currently building. It's
far from finished, or even being usable. Instead, it's a sandbox for me to play
**jsix** is a custom multi-core x64 operating system that I am building from with kernel-level code and explore architectures.
scratch. It's far from finished, or even being usable (see the *Status and
Roadmap* section, below) but all currently-planned major kernel features are
now implemented to at least a passable level.
The design goals of the project are: The design goals of the project are:
* Modernity - I'm not interested in designing for legacy systems, or running on * Modernity - I'm not interested in designing for legacy systems, or running on
all hardware out there. My target is only 64 bit architectures, and modern all hardware out there. My target is only 64 bit architecutres, and modern
commodity hardware. Currently that means x64 systems with Nehalem or newer commodity hardware. Currently that means x64 systems with Nehalem or newer
CPUs and UEFI firmware. (See [this list][cpu_features] for the currently CPUs and UEFI firmware. Eventually I'd like to work on an AArch64 port,
required CPU features.) Eventually I'd like to work on an AArch64 port,
partly to force myself to factor out the architecture-dependent pieces of the partly to force myself to factor out the architecture-dependent pieces of the
code base. code base.
@@ -21,11 +17,13 @@ The design goals of the project are:
processes as possible, in the microkernel fashion. A sub-goal of this is to processes as possible, in the microkernel fashion. A sub-goal of this is to
explore where the bottlenecks of such a microkernel are now, and whether explore where the bottlenecks of such a microkernel are now, and whether
eschewing legacy hardware will let me design a system that's less bogged down eschewing legacy hardware will let me design a system that's less bogged down
by the traditional microkernel problems. by the traditional microkernel problems. Given that there are no processes
yet, the kernel is monolithic by default.
* Exploration - I'm really mostly doing this to have fun learning and exploring * Exploration - I'm really mostly doing this to have fun learning and exploring
modern OS development. Initial feature implementations may temporarily throw modern OS development. Modular design may be tossed out (hopefully
away modular design to allow for exploration of the related hardware. temporarily) in some places to allow me to play around with the related
hardware.
A note on the name: This kernel was originally named Popcorn, but I have since A note on the name: This kernel was originally named Popcorn, but I have since
discovered that the Popcorn Linux project is also developing a kernel with that discovered that the Popcorn Linux project is also developing a kernel with that
@@ -33,149 +31,48 @@ name, started around the same time as this project. So I've renamed this kernel
jsix (Always styled _jsix_ or `j6`, never capitalized) as an homage to L4, xv6, jsix (Always styled _jsix_ or `j6`, never capitalized) as an homage to L4, xv6,
and my wonderful wife. and my wonderful wife.
[cpu_features]: https://github.com/justinian/jsix/blob/master/src/libraries/cpu/include/cpu/features.inc
## Status and Roadmap
The following major feature areas are targets for jsix development:
#### UEFI boot loader
_Done._ The bootloader loads the kernel and initial userspace programs, and
sets up necessary kernel arguments about the memory map and EFI GOP
framebuffer. Possible future ideas:
- take over more init-time functions from the kernel
- rewrite it in Zig
#### Memory
_Virtual memory: Sufficient._ The kernel manages virtual memory with a number
of kinds of `vm_area` objects representing mapped areas, which can belong to
one or more `vm_space` objects which represent a whole virtual memory space.
(Each process has a `vm_space`, and so does the kernel itself.)
Remaining to do:
- TLB shootdowns
- Page swapping
- Large / huge page support
_Physical page allocation: Sufficient._ The current physical page allocator
implementation uses a group of blocks representing up-to-1GiB areas of usable
memory as defined by the bootloader. Each block has a three-level bitmap
denoting free/used pages.
Future work:
- Align blocks so that their first page is 1GiB-aligned, making finding free
large/huge pages easier.
#### Multitasking
_Sufficient._ The global scheduler object keeps separate ready/blocked lists
per core. Cores periodically attempt to balance load via work stealing.
User-space tasks are able to create threads as well as other processes.
#### API
_Syscalls: Sufficient._ User-space tasks are able to make syscalls to the
kernel via fast SYSCALL/SYSRET instructions. Syscalls made via `libj6` look to
both the callee and the caller like standard SysV ABI function calls. The
implementations are wrapped in generated wrapper functions which validate the
request, check capabilities, and find the appropriate kernel objects or handles
before calling the implementation functions.
_IPC: Working, needs optimization._ The current IPC primitives are:
- _Mailboxes_: endpoints for asynchronously-delivered small messages. Currently
these messages are double-copied - once from the caller into a kernel buffer,
and once from the kernel to the receiver. This works and is not a major cause
of slowdown, but will need to be optimized in the future.
- _Channels_: endpoints for asynchronous uni-directional streams of bytes.
Currently these also suffer from a double-copy problem, and should probably
be replaced eventually by userspace shared memory communication.
- _Events_: objects that can be signalled to send asynchronous notifications to
waiting threads.
#### Hardware Support
- Framebuffer driver: _In progress._ Currently on machines with a video
device accessible by UEFI, jsix starts a user-space framebuffer driver that
only prints out kernel logs.
- Serial driver: _In progress._ The current UART currently only exposes COM1
as an output channel, but no input or other serial ports are exposed.
- USB driver: _To do_
- AHCI (SATA) driver: _To do_
## Building ## Building
jsix uses the [Ninja][] build tool, and generates the build files for it with jsix uses the [Ninja][] build tool, and generates the build files for it with a
the `configure` script. The build also relies on a custom toolchain sysroot, which can be custom tool called [Bonnibel][]. Bonnibel can be installed with [Cargo][], or
downloaded or built using the scripts in [jsix-os/toolchain][]. downloaded as a prebuilt binary from its Github repository.
[Ninja]: https://ninja-build.org [Ninja]: https://ninja-build.org
[jsix-os/toolchain]: https://github.com/jsix-os/toolchain [Bonnibel]: https://github.com/justinian/bonnibel
[Cargo]: https://crates.io/crates/bonnibel
Other build dependencies: Requrirements:
* [clang][]: the C/C++ compiler * bonnibel
* [nasm][]: the assembler * ninja
* [lld][]: the linker * clang
* [mtools][]: for creating the FAT image * nasm
* mtools
* curl for downloading the toolchain
[clang]: https://clang.llvm.org ### Setting up the cross toolchain
[nasm]: https://www.nasm.us
[lld]: https://lld.llvm.org
[mtools]: https://www.gnu.org/software/mtools/
The `configure` script has some Python dependencies - these can be installed via Running `pb sync` will download and unpack the toolchain into `sysroot`.
`pip`, though doing so in a python virtual environment is recommended.
Installing via `pip` will also install `ninja`.
A Debian 11 (Bullseye) system can be configured with the necessary build #### Compiling the toolchain yourself
dependencies by running the following commands from the jsix repository root:
```bash If you have `clang` and `curl` installed, runing the `scripts/build_sysroot.sh`
sudo apt install clang lld nasm mtools python3-pip python3-venv script will download and build a LLVM toolchain configured for building jsix
python3 -m venv ./venv host binaries.
source venv/bin/activate
pip install -r requirements.txt
peru sync
```
### Setting up the sysroot
Build or download the toolchain sysroot as mentioned above with
[jsix-os/toolchain][], and symlink the built toolchain directory as `sysroot`
at the root of this project.
```bash
# Example if both the toolchain and this project are cloned under ~/src
ln -s ~/src/toolchain/toolchains/llvm-13 ~/src/jsix/sysroot
```
### Building and running jsix ### Building and running jsix
Once the toolchain has been set up, running the `./configure` script (see Once the toolchain has been set up, running Bonnibel's `pb init` command will
`./configure --help` for available options) will set up the build configuration, set up the build configuration, and `pb build` will actually run the build. If
and `ninja -C build` (or wherever you put the build directory) will actually run you have `qemu-system-x86_64` installed, the `qemu.sh` script will to run jsix
the build. If you have `qemu-system-x86_64` installed, the `qemu.sh` script will in QEMU `-nographic` mode.
to run jsix in QEMU `-nographic` mode.
I personally run this either from a real debian amd64 bullseye machine or I personally run this either from a real debian amd64 testing/buster machine or
a windows WSL debian bullseye installation. Your mileage may vary with other a windows WSL debian testing/buster installation. The following should be
setups and distros. enough to set up such a system to build the kernel:
### Running the test suite sudo apt install qemu-system-x86 nasm clang-6.0 mtools curl
sudo update-alternatives /usr/bin/clang clang /usr/bin/clang-6.0 1000
sudo update-alternatives /usr/bin/clang++ clang++ /usr/bin/clang++-6.0 1000
curl -L -o pb https://github.com/justinian/bonnibel/releases/download/2.0.0/pb_linux_amd64 && chmod a+x pb
jsix now has the `test_runner` userspace program that runs various automated
tests. It is not included in the default build, but if you use the `test.yml`
manifest it will be built, and can be run with the `test.sh` script or the
`qemu.sh` script.
```bash
./configure --manifest=assets/manifests/test.yml
if ./test.sh; then echo "All tests passed!"; else echo "Failed."; fi
```

View File

@@ -1,9 +0,0 @@
---
ccflags: [
"-g3",
"-ggdb",
]
ldflags: [
"-g",
]

View File

@@ -1,3 +0,0 @@
ccflags: [
"-O3",
]

View File

@@ -1,39 +0,0 @@
---
cc: "${source_root}/sysroot/bin/clang"
cxx: "${source_root}/sysroot/bin/clang++"
ld: "${source_root}/sysroot/bin/ld.lld"
ar: ar
nasm: nasm
objcopy: objcopy
ccflags: [
"-I${source_root}/src/include",
"-fcolor-diagnostics",
"-U__STDCPP_THREADS__",
"-D_LIBCPP_HAS_NO_THREADS",
"-D__jsix_config=${build_config}",
"-D__jsix_config_${build_config}",
"-DVERSION_MAJOR=${version_major}",
"-DVERSION_MINOR=${version_minor}",
"-DVERSION_PATCH=${version_patch}",
"-DVERSION_GITSHA=0x${version_sha}",
'-DGIT_VERSION=\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
'-DGIT_VERSION_WIDE=L\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
"-Wformat=2", "-Winit-self", "-Winline", "-Wmissing-format-attribute",
"-Wmissing-include-dirs", "-Wswitch", "-Wundef", "-Wdisabled-optimization",
"-Wpointer-arith", "-Wno-attributes", "-Wno-sign-compare", "-Wno-multichar",
"-Wno-div-by-zero", "-Wno-endif-labels", "-Wno-pragmas", "-Wno-format-extra-args",
"-Wno-unused-result", "-Wno-deprecated-declarations", "-Wno-unused-function",
"-Wno-address-of-packed-member", "-Wno-invalid-offsetof", "-Wno-format-nonliteral",
"-Werror" ]
asflags: [
"-DVERSION_MAJOR=${version_major}",
"-DVERSION_MINOR=${version_minor}",
"-DVERSION_PATCH=${version_patch}",
"-DVERSION_GITSHA=0x${version_sha}",
"-I${source_root}/src/include" ]
cflags: [ "-std=c11" ]
cxxflags: [ "-std=c++17" ]

View File

@@ -1,91 +0,0 @@
rule compile.c
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
description = Compiling [$target]:$name
depfile = $out.d
deps = gcc
rule dump_c_defs
command = echo | $cc $ccflags $cflags -dM -E - > $out
description = Dumping C defines for $target
rule dump_c_run
command = echo '#!/bin/bash' > $out; echo '$cc $ccflags $cflags $$*' >> $
$out; chmod a+x $out
description = Dumping C arguments for $target
rule compile.cpp
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
description = Compiling [$target]:$name
depfile = $out.d
deps = gcc
rule dump_cpp_defs
command = echo | $cxx -x c++ $ccflags $cxxflags -dM -E - > $out
description = Dumping C++ defines for $target
rule dump_cpp_run
command = echo '#!/bin/bash' > $out; echo '$cxx $ccflags $cxxflags $$*' $
>> $out; chmod a+x $out
description = Dumping C++ arguments for $target
rule compile.s
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
description = Assembling [$target]:$name
depfile = $out.d
deps = gcc
rule parse.cog
command = cog -o $out -d -D target=$target $cogflags $in
description = Parsing [$target]:$name
rule exe
command = $ld $ldflags -o $out $in $libs
description = Linking exe [$target]:$name
rule driver
command = $ld $ldflags -o $out $in $libs
description = Linking driver [$target]:$name
rule lib
command = $ld -shared -soname $soname $ldflags -o $out $in $libs
description = Linking [$target]:$name
rule lib_static
command = $ar qcs $out $in
description = Archiving [$target]:$name
rule cp
command = cp $in $out
description = Copying [$target]:$name
rule dump
command = objdump -DSC -M intel $in > $out
description = Dumping decompiled $name
rule makest
description = Making symbol table
command = nm -n -S --demangle $in | ${source_root}/scripts/build_symbol_table.py $out
rule makeinitrd
description = Creating $name
command = ${source_root}/scripts/mkj6romfs.py -c $format $in $out
rule makefat
description = Creating $name
command = $
cp $in $out; $
mcopy -s -D o -i $out@@1M ${build_root}/fatroot/* ::/
rule strip
description = Stripping $name
command = $
cp $in $out; $
objcopy --only-keep-debug $out $debug; $
strip --discard-all -g $out; $
objcopy --add-gnu-debuglink=$debug $out
rule touch
command = touch $out
rule compdb
command = ninja -t compdb > $out

View File

@@ -1,26 +0,0 @@
---
ld: clang++
ccflags: [
"-nostdlib",
"-nodefaultlibs",
"-fno-builtin",
"-I${source_root}/external",
"--target=x86_64-unknown-windows",
"-ffreestanding",
"-mno-red-zone",
"-fshort-wchar",
"-fno-omit-frame-pointer",
]
cxxflags: [ "-fno-exceptions", "-fno-rtti" ]
ldflags: [
"--target=x86_64-unknown-windows",
"-nostdlib",
"-Wl,-entry:efi_main",
"-Wl,-subsystem:efi_application",
"-fuse-ld=lld-link",
]

View File

@@ -1,40 +0,0 @@
---
ccflags: [
"--target=x86_64-jsix-elf",
"-fno-omit-frame-pointer",
"-fno-stack-protector",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-D__ELF__",
"-D__jsix__",
"-U__linux",
"-U__linux__",
"-DMSPACES",
"--sysroot='${source_root}/sysroot'"
]
cxxflags: [
"-fno-exceptions",
"-fno-rtti",
"-isystem", "${source_root}/sysroot/include/c++/v1",
]
ldflags: [
"-Bstatic",
"-m", "elf_x86_64",
"--sysroot='${source_root}/sysroot'",
"--no-eh-frame-hdr",
"-L", "${source_root}/sysroot/lib",
"-z", "separate-code",
"-lc++", "-lc++abi", "-lunwind",
"--no-dependent-libraries",
]
libs: [
"${target_dir}/crt0.o",
]

View File

@@ -1,52 +0,0 @@
---
asflags: [ "-I${source_root}/src/kernel/" ]
ccflags: [
"--target=x86_64-jsix-elf",
"-fno-stack-protector",
"-I${source_root}/external",
"-nostdinc",
"-nostdlib",
"-ffreestanding",
"-nodefaultlibs",
"-fno-builtin",
"-fno-plt",
"-mno-sse",
"-fno-omit-frame-pointer",
"-mno-red-zone",
"-mcmodel=kernel",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-D__ELF__",
"-D__jsix__",
"-D__j6kernel",
"-U__linux",
"-U__linux__",
"-DPRINTF_ALIAS_STANDARD_FUNCTION_NAMES=1",
"-DPRINTF_INCLUDE_CONFIG_H=1",
"--sysroot='${source_root}/sysroot'"
]
cflags: [ '-nostdinc' ]
cxxflags: [
"-fno-exceptions",
"-fno-rtti",
"-nostdinc",
]
ldflags: [
"-m", "elf_x86_64",
"-nostdlib",
"-Bstatic",
"--no-eh-frame-hdr",
"-z", "norelro",
"-z", "separate-code"
]

View File

@@ -1,15 +0,0 @@
---
ccflags: [
"-fpie"
]
ldflags: [
"-pie",
"--dynamic-linker", "/jsix/lib/ld.so",
"--push-state", "--as-needed", "-Bstatic", "-lc++", "-lc++abi", "-lunwind", "--pop-state",
]
libs: [
"${target_dir}/crt0.o",
]

View File

@@ -1,7 +0,0 @@
---
ccflags: [
]
ldflags: [
"-shared",
]

View File

@@ -1,34 +0,0 @@
---
asflags: []
ccflags: [
"--target=x86_64-jsix-elf",
"-fno-omit-frame-pointer",
"-fno-stack-protector",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-D__ELF__",
"-D__jsix__",
"-U__linux",
"-U__linux__",
"--sysroot='${source_root}/sysroot'",
"-fpic",
]
cxxflags: [
"-fno-exceptions",
"-fno-rtti",
"-isystem", "${source_root}/sysroot/include/c++/v1",
]
ldflags: [
"-m", "elf_x86_64",
"--sysroot='${source_root}/sysroot'",
"--no-eh-frame-hdr",
"-L", "${source_root}/sysroot/lib",
"-z", "separate-code",
"--no-dependent-libraries",
]

View File

@@ -1,9 +0,0 @@
---
ccflags: [
"-g3",
"-ggdb",
]
ldflags: [
"-g",
]

View File

@@ -1,3 +0,0 @@
ccflags: [
"-O3",
]

View File

@@ -1,39 +0,0 @@
---
cc: "clang-16"
cxx: "clang++-16"
ld: "ld.lld-16"
ar: ar
nasm: nasm
objcopy: objcopy
ccflags: [
"-I${source_root}/src/include",
"-I${source_root}/sysroot/include/c++/v1",
"-fcolor-diagnostics",
"-U__STDCPP_THREADS__",
"-D__jsix_config=${build_config}",
"-D__jsix_config_${build_config}",
"-DVERSION_MAJOR=${version_major}",
"-DVERSION_MINOR=${version_minor}",
"-DVERSION_PATCH=${version_patch}",
"-DVERSION_GITSHA=0x${version_sha}",
'-DGIT_VERSION=\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
'-DGIT_VERSION_WIDE=L\"${version_major}.${version_minor}.${version_patch}+${version_sha}\"',
"-Wformat=2", "-Winit-self", "-Winline", "-Wmissing-format-attribute",
"-Wmissing-include-dirs", "-Wswitch", "-Wundef", "-Wdisabled-optimization",
"-Wpointer-arith", "-Wno-attributes", "-Wno-sign-compare", "-Wno-multichar",
"-Wno-div-by-zero", "-Wno-endif-labels", "-Wno-pragmas", "-Wno-format-extra-args",
"-Wno-unused-result", "-Wno-deprecated-declarations", "-Wno-unused-function",
"-Wno-address-of-packed-member", "-Wno-invalid-offsetof", "-Wno-format-nonliteral",
"-Werror" ]
asflags: [
"-DVERSION_MAJOR=${version_major}",
"-DVERSION_MINOR=${version_minor}",
"-DVERSION_PATCH=${version_patch}",
"-DVERSION_GITSHA=0x${version_sha}",
"-I${source_root}/src/include" ]
cflags: [ "-std=c11" ]
cxxflags: [ "-std=c++17" ]

View File

@@ -1,91 +0,0 @@
rule compile.c
command = $cc -MMD -MF $out.d $cflags $ccflags -o $out -c $in
description = Compiling [$target]:$name
depfile = $out.d
deps = gcc
rule dump_c_defs
command = echo | $cc $ccflags $cflags -dM -E - > $out
description = Dumping C defines for $target
rule dump_c_run
command = echo '#!/bin/bash' > $out; echo '$cc $ccflags $cflags $$*' >> $
$out; chmod a+x $out
description = Dumping C arguments for $target
rule compile.cpp
command = $cxx -MMD -MF $out.d $cxxflags $ccflags -o $out -c $in
description = Compiling [$target]:$name
depfile = $out.d
deps = gcc
rule dump_cpp_defs
command = echo | $cxx -x c++ $ccflags $cxxflags -dM -E - > $out
description = Dumping C++ defines for $target
rule dump_cpp_run
command = echo '#!/bin/bash' > $out; echo '$cxx $ccflags $cxxflags $$*' $
>> $out; chmod a+x $out
description = Dumping C++ arguments for $target
rule compile.s
command = $nasm -o $out -felf64 -MD $out.d $asflags $in
description = Assembling [$target]:$name
depfile = $out.d
deps = gcc
rule parse.cog
command = cog -o $out -d -D target=$target $cogflags $in
description = Parsing [$target]:$name
rule exe
command = $ld $ldflags -o $out $in $libs
description = Linking exe [$target]:$name
rule driver
command = $ld $ldflags -o $out $in $libs
description = Linking driver [$target]:$name
rule lib
command = $ld -shared -soname $soname $ldflags -o $out $in $libs
description = Linking [$target]:$name
rule lib_static
command = $ar qcs $out $in
description = Archiving [$target]:$name
rule cp
command = cp $in $out
description = Copying [$target]:$name
rule dump
command = objdump -DSC -M intel $in > $out
description = Dumping decompiled $name
rule makest
description = Making symbol table
command = nm -n -S --demangle $in | ${source_root}/scripts/build_symbol_table.py $out
rule makeinitrd
description = Creating $name
command = ${source_root}/scripts/mkj6romfs.py -c $format $in $out
rule makefat
description = Creating $name
command = $
cp $in $out; $
mcopy -s -D o -i $out@@1M ${build_root}/fatroot/* ::/
rule strip
description = Stripping $name
command = $
cp $in $out; $
objcopy --only-keep-debug $out $debug; $
strip --discard-all -g $out; $
objcopy --add-gnu-debuglink=$debug $out
rule touch
command = touch $out
rule compdb
command = ninja -t compdb > $out

View File

@@ -1,39 +0,0 @@
---
ccflags: [
"--target=x86_64-jsix-elf",
"-fno-omit-frame-pointer",
"-fno-stack-protector",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-D__ELF__",
"-D__jsix__",
"-U__linux",
"-U__linux__",
"-DMSPACES",
"--sysroot='${source_root}/sysroot'"
]
cxxflags: [
"-fno-exceptions",
"-fno-rtti",
]
ldflags: [
"-Bstatic",
"-m", "elf_x86_64",
"--sysroot='${source_root}/sysroot'",
"--no-eh-frame-hdr",
"-L", "${source_root}/sysroot/lib",
"-z", "separate-code",
"-lc++", "-lc++abi", "-lunwind",
"--no-dependent-libraries",
]
libs: [
"${target_dir}/crt0.o",
]

View File

@@ -1,16 +0,0 @@
---
ccflags: [
"-fpie"
]
ldflags: [
"-pie",
"-rpath", "${target_dir}",
"--dynamic-linker", "/lib64/ld-linux-x86-64.so.2",
"--push-state", "--as-needed", "-Bstatic", "-lc++", "-lc++abi", "-lunwind", "--pop-state",
]
libs: [
"${target_dir}/crt0.o",
]

View File

@@ -1,7 +0,0 @@
---
ccflags: [
]
ldflags: [
"-shared",
]

View File

@@ -1,33 +0,0 @@
---
asflags: []
ccflags: [
"--target=x86_64-jsix-elf",
"-fno-omit-frame-pointer",
"-fno-stack-protector",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-D__ELF__",
"-D__jsix__",
"-U__linux",
"-U__linux__",
"--sysroot='${source_root}/sysroot'",
"-fpic",
]
cxxflags: [
"-fno-exceptions",
"-fno-rtti",
]
ldflags: [
"-m", "elf_x86_64",
"--sysroot='${source_root}/sysroot'",
"--no-eh-frame-hdr",
"-L", "${source_root}/sysroot/lib",
"-z", "separate-code",
"--no-dependent-libraries",
]

View File

@@ -1,14 +1,4 @@
import gdb import gdb
import gdb.printing
import sys
sys.path.append('./scripts')
import re
from collections import namedtuple
Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"])
LogEntry = namedtuple("LogHeader", ["id", "bytes", "severity", "area", "message"])
class PrintStackCommand(gdb.Command): class PrintStackCommand(gdb.Command):
def __init__(self): def __init__(self):
@@ -20,7 +10,6 @@ class PrintStackCommand(gdb.Command):
base = "$rsp" base = "$rsp"
if len(args) > 0: if len(args) > 0:
base = args[0] base = args[0]
base = int(gdb.parse_and_eval(base))
depth = 22 depth = 22
if len(args) > 1: if len(args) > 1:
@@ -29,35 +18,14 @@ class PrintStackCommand(gdb.Command):
for i in range(depth-1, -1, -1): for i in range(depth-1, -1, -1):
try: try:
offset = i * 8 offset = i * 8
value = gdb.parse_and_eval(f"*(uint64_t*)({base:#x} + {offset:#x})") base_addr = gdb.parse_and_eval(base)
print("{:016x} (+{:04x}): {:016x}".format(base + offset, offset, int(value))) value = gdb.parse_and_eval(f"*(uint64_t*)({base} + {offset})")
print("{:016x} (+{:04x}): {:016x}".format(int(base_addr) + offset, offset, int(value)))
except Exception as e: except Exception as e:
print(e) print(e)
continue continue
def stack_walk(frame, depth):
for i in range(depth-1, -1, -1):
ret = gdb.parse_and_eval(f"*(uint64_t*)({frame:#x} + 0x8)")
name = ""
try:
block = gdb.block_for_pc(int(ret))
if block:
name = block.function or ""
except RuntimeError:
pass
try:
print("{:016x}: {:016x} {}".format(int(frame), int(ret), name))
frame = int(gdb.parse_and_eval(f"*(uint64_t*)({frame:#x})"))
except gdb.MemoryError:
return
if frame == 0 or ret == 0:
return
class PrintBacktraceCommand(gdb.Command): class PrintBacktraceCommand(gdb.Command):
def __init__(self): def __init__(self):
super().__init__("j6bt", gdb.COMMAND_DATA) super().__init__("j6bt", gdb.COMMAND_DATA)
@@ -65,477 +33,31 @@ class PrintBacktraceCommand(gdb.Command):
def invoke(self, arg, from_tty): def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg) args = gdb.string_to_argv(arg)
frame = "$rbp"
if len(args) > 0:
frame = args[0]
frame = int(gdb.parse_and_eval(f"{frame}"))
depth = 30 depth = 30
if len(args) > 0:
depth = int(args[0])
frame = "$rbp"
if len(args) > 1: if len(args) > 1:
depth = int(gdb.parse_and_eval(args[1])) frame = args[1]
stack_walk(frame, depth) for i in range(depth-1, -1, -1):
ret = gdb.parse_and_eval(f"*(uint64_t*)({frame} + 8)")
frame = gdb.parse_and_eval(f"*(uint64_t*)({frame})")
name = ""
block = gdb.block_for_pc(int(ret))
if block:
name = block.function or ""
class TableWalkCommand(gdb.Command): print("{:016x} {}".format(int(ret), name))
def __init__(self):
super().__init__("j6tw", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty): if frame == 0 or ret == 0:
args = gdb.string_to_argv(arg) return
if len(args) < 2:
raise Exception("Must be: j6tw <pml4> <addr>")
pml4 = int(gdb.parse_and_eval(args[0]))
addr = int(gdb.parse_and_eval(args[1]))
indices = [
(addr >> 39) & 0x1ff,
(addr >> 30) & 0x1ff,
(addr >> 21) & 0x1ff,
(addr >> 12) & 0x1ff,
]
names = ["PML4", "PDP", "PD", "PT"]
table_flags = [
(0x0001, "present"),
(0x0002, "write"),
(0x0004, "user"),
(0x0008, "pwt"),
(0x0010, "pcd"),
(0x0020, "accessed"),
(0x0040, "dirty"),
(0x0080, "largepage"),
(0x0100, "global"),
(0x1080, "pat"),
((1<<63), "xd"),
]
page_flags = [
(0x0001, "present"),
(0x0002, "write"),
(0x0004, "user"),
(0x0008, "pwt"),
(0x0010, "pcd"),
(0x0020, "accessed"),
(0x0040, "dirty"),
(0x0080, "pat"),
(0x0100, "global"),
((1<<63), "xd"),
]
flagsets = [table_flags, table_flags, table_flags, page_flags]
table = pml4
entry = 0
for i in range(len(indices)):
entry = int(gdb.parse_and_eval(f'((uint64_t*)0x{table:x})[0x{indices[i]:x}]'))
flagset = flagsets[i]
flag_names = " | ".join([f[1] for f in flagset if (entry & f[0]) == f[0]])
print(f"{names[i]:>4}: {table:016x}")
print(f" index: {indices[i]:3} {entry:016x}")
print(f" flags: {flag_names}")
if (entry & 1) == 0 or (i < 3 and (entry & 0x80)):
break
table = (entry & 0x7ffffffffffffe00) | 0xffffc00000000000
class GetThreadsCommand(gdb.Command):
FLAGS = {
"ready": 0x01,
"loading": 0x02,
"exited": 0x04,
"constant": 0x80,
}
def __init__(self):
super().__init__("j6threads", gdb.COMMAND_DATA)
def get_flags(self, bitset):
flags = []
for k, v in GetThreadsCommand.FLAGS.items():
if bitset & v:
flags.append(k)
return " ".join(flags)
def print_thread(self, addr):
if addr == 0:
print(" <no thread>\n")
return
tcb = f"((TCB*){addr:#x})"
thread = f"({tcb}->thread)"
stack = int(gdb.parse_and_eval(f"{tcb}->kernel_stack"))
rsp = int(gdb.parse_and_eval(f"{tcb}->rsp"))
pri = int(gdb.parse_and_eval(f"{tcb}->priority"))
flags = int(gdb.parse_and_eval(f"{thread}->m_state"))
koid = int(gdb.parse_and_eval(f"{thread}->m_obj_id"))
proc = int(gdb.parse_and_eval(f"{thread}->m_parent.m_obj_id"))
creator = int(gdb.parse_and_eval(f"{thread}->m_creator"))
if creator != 0:
creator_koid = int(gdb.parse_and_eval(f"{thread}->m_creator->m_obj_id"))
creator = f"{creator_koid:x}"
else:
creator = "<no thread>"
print(f" Thread {proc:x}:{koid:x}")
print(f" creator: {creator}")
print(f" priority: {pri}")
print(f" flags: {self.get_flags(flags)}")
print(f" kstack: {stack:#x}")
print(f" rsp: {rsp:#x}")
if stack == 0: return 0
return int(gdb.parse_and_eval(f"{tcb}->rsp"))
def print_thread_list(self, addr, name):
if addr == 0:
return
print(f"=== {name} ===")
while addr != 0:
rsp = self.print_thread(addr)
if rsp != 0:
print("------------------------------------")
stack_walk(rsp + 5*8, 5)
addr = int(gdb.parse_and_eval(f"((tcb_node*){addr:#x})->m_next"))
print()
def print_cpudata(self, index):
cpu = f"(g_cpu_data[{index}])"
tss = f"{cpu}->tss"
tss_rsp0 = int(gdb.parse_and_eval(f"{tss}->m_rsp[0]"))
tss_ist = [int(gdb.parse_and_eval(f"{tss}->m_ist[{i}]")) for i in range(8)]
print(f" tss rsp0: {tss_rsp0:#x}")
for i in range(1,8):
if tss_ist[i] == 0: continue
print(f" tss ist{i}: {tss_ist[i]:#x}")
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
if len(args) > 1:
raise RuntimeError("Usage: j6threads [cpu]")
ncpus = int(gdb.parse_and_eval("g_num_cpus"))
cpus = list(range(ncpus))
if len(args) == 1:
cpus = [int(args[0])]
for cpu in cpus:
runlist = f"scheduler::s_instance->m_run_queues.m_elements[{cpu:#x}]"
print(f"=== CPU {cpu:2}: CURRENT ===")
current = int(gdb.parse_and_eval(f"{runlist}.current"))
self.print_thread(current)
self.print_cpudata(cpu)
previous = int(gdb.parse_and_eval(f"{runlist}.prev"))
print(f" prev: {previous:x}")
print()
for pri in range(8):
ready = int(gdb.parse_and_eval(f"{runlist}.ready[{pri:#x}].m_head"))
self.print_thread_list(ready, f"CPU {cpu:2}: PRIORITY {pri}")
blocked = int(gdb.parse_and_eval(f"{runlist}.blocked.m_head"))
self.print_thread_list(blocked, f"CPU {cpu:2}: BLOCKED")
print()
class PrintProfilesCommand(gdb.Command):
def __init__(self):
super().__init__("j6prof", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
if len(args) != 1:
raise RuntimeError("Usage: j6prof <profiler class>")
profclass = args[0]
root_type = f"profile_class<{profclass}>"
try:
baseclass = gdb.lookup_type(root_type)
except Exception as e:
print(e)
return
results = {}
max_len = 0
count = gdb.parse_and_eval(f"{profclass}::count")
for i in range(count):
name = gdb.parse_and_eval(f"{root_type}::function_names[{i:#x}]")
if name == 0: continue
call_counts = gdb.parse_and_eval(f"{root_type}::call_counts[{i:#x}]")
call_durations = gdb.parse_and_eval(f"{root_type}::call_durations[{i:#x}]")
results[name.string()] = float(call_durations) / float(call_counts)
max_len = max(max_len, len(name.string()))
for name, avg in results.items():
print(f"{name:>{max_len}}: {avg:15.3f}")
class DumpLogCommand(gdb.Command):
level_names = ["", "fatal", "error", "warn", "info", "verbose", "spam"]
def __init__(self):
super().__init__("j6log", gdb.COMMAND_DATA)
from memory import Layout
layout = Layout("definitions/memory_layout.yaml")
for region in layout.regions:
if region.name == "logs":
self.base_addr = region.start
break
self.areas = []
area_re = re.compile(r"LOG\(\s*(\w+).*")
with open("src/libraries/j6/include/j6/tables/log_areas.inc", 'r') as areas_inc:
for line in areas_inc:
m = area_re.match(line)
if m:
self.areas.append(m.group(1))
def get_entry(self, addr):
addr = int(addr)
size = int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->bytes"))
mlen = size - 8
return LogEntry(
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->id")),
size,
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->severity")),
int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->area")),
gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->message").string(length=mlen))
def invoke(self, arg, from_tty):
start = gdb.parse_and_eval("g_logger.m_start & (g_logger.m_buffer.count - 1)")
end = gdb.parse_and_eval("g_logger.m_end & (g_logger.m_buffer.count - 1)")
if end < start:
end += gdb.parse_and_eval("g_logger.m_buffer.count")
print(f"Logs are {start} -> {end}")
addr = self.base_addr + start
end += self.base_addr
while addr < end:
entry = self.get_entry(addr)
if entry.bytes < 8:
print(f"Bad log header size: {entry.bytes}")
break
addr += entry.bytes
area = "??"
if entry.area < len(self.areas):
area = self.areas[entry.area]
level = self.level_names[entry.severity]
print(f"{area:>7}:{level:7} {entry.message}")
class ShowCurrentProcessCommand(gdb.Command):
def __init__(self):
super().__init__("j6current", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
def get_obj_and_id(name):
obj = int(gdb.parse_and_eval(f"((cpu_data*)$gs_base)->{name}"))
oid = -1
if obj != 0:
oid = int(gdb.parse_and_eval(f"((obj::kobject*){obj:#x})->m_obj_id"))
return obj, oid
process, pid = get_obj_and_id("process")
thread, tid = get_obj_and_id("thread")
print(f"{pid:02x}/{tid:02x} [ {process:x} / {thread:x} ]")
class CapTablePrinter:
def __init__(self, val):
node_map = val["m_caps"]
self.nodes = node_map["m_nodes"]
self.count = int(node_map["m_count"])
self.capacity = int(node_map["m_capacity"])
class _iterator:
def __init__(self, nodes, capacity):
self.nodes = []
for i in range(capacity):
node = nodes[i]
node_id = int(node["id"])
if node_id == 0:
continue
self.nodes.append(Capability(
id = node_id,
parent = int(node["parent"]),
refcount = int(node["holders"]),
caps = int(node["caps"]),
type = str(node["type"])[14:],
koid = node['object']['m_obj_id']))
self.nodes.sort(key=lambda n: n.id, reverse=True)
def __iter__(self):
return self
def __next__(self):
if not self.nodes:
raise StopIteration
node = self.nodes.pop()
desc = f'p:{node.parent:016x} refs:{node.refcount:2} caps:{node.caps:04x} {node.type:14} {node.koid}'
return (f"{node.id:016x}", desc)
def to_string(self):
return f"Cap table with {self.count}/{self.capacity} nodes.\n"
def children(self):
return self._iterator(self.nodes, self.capacity)
class VectorPrinter:
def __init__(self, vector):
self.name = vector.type.tag
self.count = vector["m_size"]
self.array = vector["m_elements"]
class _iterator:
def __init__(self, array, count, deref):
self.array = array
self.count = count
self.deref = deref
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= self.count:
raise StopIteration
item = self.array[self.index]
if self.deref:
item = item.dereference()
result = (f"{self.index:3}", item)
self.index += 1
return result
def to_string(self):
return f"{self.name} [{self.count}]"
def children(self):
deref = self.count > 0 and self.array[0].type.code == gdb.TYPE_CODE_PTR
return self._iterator(self.array, int(self.count), deref)
class HandleSetPrinter:
def __init__(self, nodeset):
self.node_map = nodeset['m_map']
self.count = self.node_map['m_count']
self.capacity = self.node_map['m_capacity']
class _iterator:
def __init__(self, nodes, capacity):
self.items = []
self.index = 0
for i in range(capacity):
item = nodes[i]
if int(item) != 0:
self.items.append(int(item))
self.items.sort()
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.items):
raise StopIteration
result = (f"{self.index}", f"{self.items[self.index]:016x}")
self.index += 1
return result
def to_string(self):
return f"node_set[{self.count} / {self.capacity}]:"
def children(self):
return self._iterator(self.node_map['m_nodes'], self.capacity)
class LinkedListPrinter:
def __init__(self, llist):
self.name = llist.type.tag
self.head = llist['m_head']
self.tail = llist['m_tail']
self.items = []
current = self.head
while current:
item = current.dereference()
self.items.append((str(len(self.items)), item))
current = item['m_next']
class _iterator:
def __iter__(self):
return self
def __next__(self):
raise StopIteration
def to_string(self):
return f"{self.name}[{len(self.items)}]"
def children(self):
return self.items
class IsRunning(gdb.Function):
def __init__(self):
super(IsRunning, self).__init__("is_running")
def invoke(self):
inferior = gdb.selected_inferior()
return \
inferior is not None and \
inferior.is_valid() and \
len(inferior.threads()) > 0
def build_pretty_printers():
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
pp.add_printer("handle set", '^util::node_set<unsigned long, 0, heap_allocated>$', HandleSetPrinter)
pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter)
pp.add_printer("linked list", '^util::linked_list<.*>$', LinkedListPrinter)
return pp
gdb.printing.register_pretty_printer(
gdb.current_objfile(),
build_pretty_printers())
PrintStackCommand() PrintStackCommand()
PrintBacktraceCommand() PrintBacktraceCommand()
TableWalkCommand()
GetThreadsCommand()
PrintProfilesCommand()
DumpLogCommand()
ShowCurrentProcessCommand()
IsRunning()
gdb.execute("target remote :1234")
gdb.execute("display/i $rip") gdb.execute("display/i $rip")
gdb.execute("define hook-quit\nif $is_running()\n kill\nend\nend")
if not gdb.selected_inferior().was_attached:
gdb.execute("add-symbol-file build/panic.serial.elf")
gdb.execute("target remote :1234")

Binary file not shown.

View File

@@ -1,49 +0,0 @@
start: import_statement* (object|interface)+
import_statement: "import" PATH
object: description? "object" name options? super? "{" uid cname? capabilities? method* "}"
interface: description? "interface" name options? "{" uid interface_param* "}"
?interface_param: expose | function
expose: "expose" type
uid: "uid" UID
cname: "cname" IDENTIFIER
capabilities: "capabilities" "[" IDENTIFIER+ "]"
super: ":" name
function: description? "function" name options? ("{" param* "}")?
method: description? "method" name options? ("{" param* "}")?
param: "param" name type options? description?
?type: PRIMITIVE | object_name | struct_name
object_name: "ref" name
struct_name: "struct" name
id: NUMBER
name: IDENTIFIER
options: "[" ( OPTION | IDENTIFIER )+ "]"
description: COMMENT+
PRIMITIVE: INT_TYPE "*"? | "size" | "string" | "buffer" | "address"
INT_TYPE: /u?int(8|16|32|64)?/
NUMBER: /(0x)?[0-9a-fA-F]+/
UID: /[0-9a-fA-F]{16}/
OPTION.2: IDENTIFIER ":" IDENTIFIER
COMMENT: /#.*/
PATH: /"[^"]*"/
%import common.LETTER
%import common.CNAME -> IDENTIFIER
%import common.WS
%ignore WS

28
assets/initrd.toml Normal file
View File

@@ -0,0 +1,28 @@
# This is the manifest for the initial ramdisk, read by the `makerd` tool.
# The contents should be a table array of files to add to the ramdistk:
#
# [[files]]
# dest = "foo.bar" # Name of the file in the ramdisk
# source = "build/foo/foo.bar" # Location of the file from the project root
# executable = true # Optional, default false. Whether this is an
# # initial application for the kernel to execute
# # on startup
[[files]]
dest = "screenfont.psf"
source = "../assets/fonts/tamsyn8x16r.psf"
[[files]]
dest = "symbol_table.dat"
source = "symbol_table.dat"
symbols = true
[[files]]
dest = "nulldrv1"
source = "user/nulldrv"
executable = true
[[files]]
dest = "nulldrv2"
source = "user/nulldrv"
executable = true

View File

@@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!-- Generator: Gravit.io --><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="176.562 356.069 211.11 113" width="211.11pt" height="113pt"><g><g><rect x="176.562" y="356.069" width="211.11" height="113" transform="matrix(1,0,0,1,0,0)" fill="rgb(255,255,255)"/><g><path d=" M 212.981 372.36 L 219.564 376.16 L 226.147 379.961 L 226.147 387.563 L 226.147 395.164 L 219.564 398.965 L 212.981 402.766 L 206.398 398.965 L 199.815 395.164 L 199.815 387.563 L 199.815 379.961 L 206.398 376.16 L 212.981 372.36 L 212.981 372.36 L 212.981 372.36 Z M 256.292 397.366 L 262.875 401.166 L 269.458 404.967 L 269.458 412.569 L 269.458 420.17 L 262.875 423.971 L 256.292 427.772 L 249.709 423.971 L 243.126 420.17 L 243.126 412.569 L 243.126 404.967 L 249.709 401.166 L 256.292 397.366 L 256.292 397.366 Z M 183.622 387.283 L 205.52 374.64 L 227.418 361.997 L 249.316 374.64 L 271.214 387.283 L 271.214 412.569 L 271.214 437.854 L 249.316 450.497 L 227.418 463.14 L 205.52 450.497 L 183.622 437.854 L 183.622 412.569 L 183.622 387.283 L 183.622 387.283 L 183.622 387.283 Z M 241.855 372.36 L 248.438 376.16 L 255.021 379.961 L 255.021 387.563 L 255.021 395.164 L 248.438 398.965 L 241.855 402.766 L 235.272 398.965 L 228.689 395.164 L 228.689 387.563 L 228.689 379.961 L 235.272 376.16 L 241.855 372.36 Z " fill-rule="evenodd" fill="rgb(49,79,128)"/><path d=" M 298.642 379.579 L 291.621 379.579 L 291.621 372.558 L 298.642 372.558 L 298.642 379.579 Z M 285.214 446.718 L 285.214 441.452 L 287.32 441.452 L 287.32 441.452 Q 289.339 441.452 290.524 440.092 L 290.524 440.092 L 290.524 440.092 Q 291.708 438.731 291.708 436.625 L 291.708 436.625 L 291.708 387.039 L 298.729 387.039 L 298.729 436.011 L 298.729 436.011 Q 298.729 440.925 295.921 443.822 L 295.921 443.822 L 295.921 443.822 Q 293.113 446.718 288.286 446.718 L 288.286 446.718 L 285.214 446.718 Z M 306.628 432.676 L 306.628 427.41 L 314.088 427.41 L 314.088 427.41 Q 317.862 427.41 319.573 425.347 L 319.573 425.347 L 319.573 425.347 Q 321.285 423.285 321.285 419.95 L 321.285 419.95 L 321.285 419.95 Q 321.285 417.317 319.705 415.474 L 319.705 415.474 L 319.705 415.474 Q 318.125 413.631 314.966 411.174 L 314.966 411.174 L 314.966 411.174 Q 312.245 408.98 310.621 407.356 L 310.621 407.356 L 310.621 407.356 Q 308.998 405.732 307.813 403.319 L 307.813 403.319 L 307.813 403.319 Q 306.628 400.905 306.628 397.746 L 306.628 397.746 L 306.628 397.746 Q 306.628 393.095 309.744 390.067 L 309.744 390.067 L 309.744 390.067 Q 312.859 387.039 318.125 387.039 L 318.125 387.039 L 325.76 387.039 L 325.76 392.305 L 319.441 392.305 L 319.441 392.305 Q 313.21 392.305 313.21 398.185 L 313.21 398.185 L 313.21 398.185 Q 313.21 400.467 314.615 402.134 L 314.615 402.134 L 314.615 402.134 Q 316.019 403.802 319.003 406.083 L 319.003 406.083 L 319.003 406.083 Q 321.723 408.19 323.479 409.901 L 323.479 409.901 L 323.479 409.901 Q 325.234 411.613 326.463 414.202 L 326.463 414.202 L 326.463 414.202 Q 327.691 416.791 327.691 420.301 L 327.691 420.301 L 327.691 420.301 Q 327.691 426.532 324.4 429.604 L 324.4 429.604 L 324.4 429.604 Q 321.109 432.676 315.141 432.676 L 315.141 432.676 L 306.628 432.676 Z M 342.611 379.579 L 335.59 379.579 L 335.59 372.558 L 342.611 372.558 L 342.611 379.579 Z M 342.611 432.676 L 335.59 432.676 L 335.59 387.039 L 342.611 387.039 L 342.611 432.676 Z M 356.126 432.676 L 348.754 432.676 L 361.392 409.77 L 349.632 387.039 L 356.39 387.039 L 364.639 403.187 L 372.977 387.039 L 379.735 387.039 L 367.974 409.77 L 380.612 432.676 L 373.24 432.676 L 364.639 416.001 L 356.126 432.676 Z " fill="rgb(49,79,128)"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,16 +0,0 @@
---
location: jsix
init: srv.init
initrd:
name: initrd.dat
format: zstd
panic:
- panic.serial
services:
- srv.logger
- testapp
drivers:
- drv.uart
- drv.uefi_fb
libs:
- ld.so

View File

@@ -1,14 +0,0 @@
---
location: jsix
init: srv.init
initrd:
name: initrd.dat
format: zstd
panic:
- panic.serial
services:
- srv.logger
drivers:
- drv.uart
libs:
- ld.so

View File

@@ -1,14 +0,0 @@
---
location: jsix
init: srv.init
initrd:
name: initrd.dat
format: zstd
panic:
- panic.serial
services:
- 6s
drivers:
- drv.uart
libs:
- ld.so

View File

@@ -1,11 +0,0 @@
---
location: jsix
init: srv.init
initrd:
name: initrd.dat
format: zstd
flags: ["test"]
panic:
- panic.serial
services:
- test_runner

Binary file not shown.

Binary file not shown.

Binary file not shown.

82
configure vendored
View File

@@ -1,82 +0,0 @@
#!/usr/bin/env python3
def generate(output, config, arch, manifest):
from os import makedirs
from glob import iglob
from pathlib import Path
from bonnibel.module import Module, ModuleList
from bonnibel.project import Project
root = Path(__file__).parent.resolve()
project = Project(root)
output = root / output
manifest = root / manifest
sources = [
str(root / "src/**/*.module"),
str(root / "external/*.module"),
]
modules = ModuleList(arch)
for source in sources:
for modfile in iglob(source, recursive=True):
modfile = Path(modfile)
path = modfile.parent
def module_init(name, **kwargs):
if not "root" in kwargs:
kwargs["root"] = path
m = Module(name, modfile, **kwargs)
modules.add(m)
return m
glo = {
"module": module_init,
"source_root": root,
"build_root": output,
"module_root": path,
"config": config,
"arch": arch,
}
code = compile(open(modfile, 'r').read(), modfile, "exec")
loc = {}
exec(code, glo, loc)
makedirs(output.resolve(), exist_ok=True)
project.generate(root, output, modules, config, arch, manifest)
modules.generate(output)
if __name__ == "__main__":
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "scripts"))
from argparse import ArgumentParser
from bonnibel import BonnibelError
default_arch = "amd64"
p = ArgumentParser(description="Generate jsix build files")
p.add_argument("--manifest", "-m", metavar="FILE", default="assets/manifests/default.yaml",
help="File to use as the system manifest")
p.add_argument("--conf", "-c", metavar="NAME", default="debug",
help="Configuration to build (eg, 'debug' or 'release')")
p.add_argument("--arch", "-a", metavar="NAME", default=default_arch,
help="Architecture to build (eg, 'amd64' or 'linux')")
p.add_argument("--verbose", "-v", action='count', default=0,
help="More verbose log output")
p.add_argument("output", metavar="DIR", default=None, nargs='?',
help="Where to create the build root")
args = p.parse_args()
output = args.output or f"build.{args.arch}"
try:
generate(output, args.conf, args.arch, args.manifest)
except BonnibelError as be:
import sys
print(f"Error: {be}", file=sys.stderr)
sys.exit(1)

View File

@@ -1,38 +0,0 @@
---
- name: linear
desc: Linearly-mapped physical memory
size: 64T
shared: true
- name: bitmap
desc: Used/free page tracking bitmap
size: 1T
shared: true
- name: heapmap
desc: Kernel heap accounting structures
size: 32G
- name: heap
desc: Kernel heap
size: 32G
- name: capsmap
desc: Capabilities accounting structures
size: 32G
- name: caps
desc: Capabilities
size: 32G
- name: stacks
desc: Kernel thread stacks
size: 64G
- name: buffers
desc: Kernel buffers
size: 64G
- name: logs
desc: Kernel logs circular buffer
size: 2G

View File

@@ -1,25 +0,0 @@
# An ``event`` is a simple synchronization object. It contains up to 64 signals
# that threads can wait for and signal in parallel.
object event : object {
uid f441e03da5516b1a
capabilities [
signal
wait
]
method create [constructor]
# Signal events on this object
method signal [cap:signal] {
param signals uint64 # A bitset of which events to signal
}
# Wait for signaled events on this object
method wait [cap:wait] {
param signals uint64 [out] # A bitset of which events were signaled
param timeout uint64 # Wait timeout in nanoseconds
}
}

View File

@@ -1,41 +0,0 @@
# Mailboxes are objects that enable synchronous IPC via arbitrary
# message-passing of tagged data and/or handles. Not as efficient
# as shared memory channels, but more flexible.
object mailbox : object {
uid 99934ad04ece1e07
capabilities [
send
receive
close
]
method create [constructor]
method close [destructor cap:close]
# Send a message to the reciever, and block until a response is
# sent. Note that getting this response does not require the
# receive capability.
method call [cap:send] {
param tag uint64 [inout]
param data buffer [optional inout]
param data_size size # number of total bytes in data buffer
param handles ref object [optional inout handle list]
param handles_size size # total size of handles buffer
}
# Respond to a message sent using call, and wait for another
# message to arrive. Note that this does not require the send
# capability. A reply tag of 0 skips the reply and goes directly
# to waiting for a new message.
method respond [cap:receive] {
param tag uint64 [inout]
param data buffer [optional inout]
param data_size size # number of total bytes in data buffer
param handles ref object [optional inout handle list]
param handles_size size # total size of handles buffer
param reply_tag uint64 [inout]
param flags uint64
}
}

View File

@@ -1,16 +0,0 @@
# All kernel-exposed objects inherit from the base ``object`` type, so the
# ``object`` syscalls can be used with any object's handle.
object object [virtual] {
uid 667f61fb2cd57bb4
cname kobject
capabilities [
clone
]
# Get the internal kernel object id of an object
method koid {
param koid uint64 [out]
}
}

View File

@@ -1,32 +0,0 @@
import "objects/object.def"
# A ``process`` object represents a process running on the system, and allows
# control over the threads, handles, and virtual memory space of that process.
object process : object {
uid 0c69ee0b7502ba31
capabilities [
kill
create_thread
]
# Create a new empty process
method create [constructor] {
param name string
}
# Stop all threads and exit the given process
method kill [destructor cap:kill]
# Stop all threads and exit the current process
method exit [static noreturn] {
param result int64 # The result to retrun to the parent process
}
# Give the given process a handle that points to the same
# object as the specified handle.
method give_handle {
param target ref object [handle] # A handle in the caller process to send
}
}

View File

@@ -1,42 +0,0 @@
# The singular ``system`` object represents a handle to kernel functionality
# needed by drivers and other priviledged services.
object system : object {
uid fa72506a2cf71a30
capabilities [
get_log
bind_irq
map_phys
change_iopl
]
# Get the next log line from the kernel log
method get_log [cap:get_log] {
param seen uint64 # Last seen log id
param buffer buffer [out zero_ok] # Buffer for the log message data structure
}
# Ask the kernel to send this process messages whenever
# the given IRQ fires
method bind_irq [cap:bind_irq] {
param dest ref event # Event object that will receive messages
param irq uint # IRQ number to bind
param signal uint # Signal number on the event to bind to
}
# Create a VMA and map an area of physical memory into it,
# also mapping that VMA into the current process
method map_phys [cap:map_phys] {
param area ref vma [out] # Receives a handle to the VMA created
param phys address # The physical address of the area
param size size # Size of the area, in bytes
param flags uint32 # Flags to apply to the created VMA
}
# Request the kernel change the IOPL for this process. The only values
# that make sense are 0 and 3.
method request_iopl [cap:change_iopl] {
param iopl uint # The IOPL to set for this process
}
}

View File

@@ -1,30 +0,0 @@
# A ``thread`` object represents a thread of execution within a process running
# on the system. The actual thread does not need to be currently running to
# hold a handle to it.
object thread : object {
uid 11f23e593d5761bd
capabilities [
kill
join
]
method create [constructor] {
param process ref process [optional cap:create_thread]
param stack_top address
param entrypoint address
param arg0 uint64
param arg1 uint64
}
method kill [destructor cap:kill]
method join [cap:join]
method exit [static]
method sleep [static] {
param duration uint64
}
}

View File

@@ -1,41 +0,0 @@
import "objects/process.def"
# A ``vma`` object represents a single virtual memory area, which may be shared
# between several processes. A process having a handle to a ``vma`` does not
# necessarily mean that it is mapped into that process' virtual memory space.
object vma : object {
uid d6a12b63b3ed3937
cname vm_area
capabilities [
map
unmap
resize
]
method create [constructor] {
param size size
param flags uint32
}
method create_map [constructor cap:map] {
param size size
param address address [inout]
param flags uint32
}
method map [cap:map] {
param process ref process [optional]
param address address [inout]
param flags uint32
}
method unmap [cap:unmap] {
param process ref process [optional]
}
method resize [cap:resize] {
param size size [inout] # New size for the VMA, or 0 to query the current size without changing
}
}

View File

@@ -1,69 +0,0 @@
import "objects/object.def"
import "objects/event.def"
import "objects/mailbox.def"
import "objects/process.def"
import "objects/system.def"
import "objects/thread.def"
import "objects/vma.def"
interface syscalls [syscall] {
uid 01d9b6a948961097
expose ref object
expose ref event
expose ref mailbox
expose ref process
expose ref system
expose ref thread
expose ref vma
# Simple no-op syscall for testing
function noop
# Write a message to the kernel log
function log {
param area uint8
param severity uint8
param message string
}
# Get a list of handles owned by this process. If the
# supplied list is not big enough, will set the size
# needed in `size` and return j6_err_insufficient
function handle_list {
param handles struct handle_descriptor [list inout zero_ok] # A list of handles to be filled
}
# Create a clone of an existing handle, possibly with
# some capabilities masked out.
function handle_clone {
param orig ref object [handle cap:clone] # The handle to clone
param clone ref object [out] # The new handle
param mask uint32 # The capability bitmask
}
# Close the handle to an object
function handle_close {
param hnd ref object [handle] # The handle to close
}
# Block waiting on a futex
function futex_wait [static] {
param address uint32* # Address of the futex value
param current uint32 # Current value of the futex
param timeout uint64 # Wait timeout in nanoseconds
}
# Wake threads waiting on a futex
function futex_wake [static] {
param address uint32* # Address of the futex value
param count uint64 # Number of threads to wake, or 0 for all
}
# Testing mode only: Have the kernel finish and exit QEMU with the given exit code
function test_finish [test] {
param exit_code uint32
}
}

View File

@@ -1,34 +0,0 @@
---
address: 0x6a360000
vars:
- name: version_major
section: kernel
type: uint8_t
- name: version_minor
section: kernel
type: uint8_t
- name: version_patch
section: kernel
type: uint16_t
- name: version_gitsha
section: kernel
type: uint32_t
- name: page_size
section: sys
type: size_t
- name: large_page_size
section: sys
type: size_t
- name: huge_page_size
section: sys
type: size_t
- name: num_cpus
section: sys
type: uint32_t

View File

@@ -1,23 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
ROOTDIR = $(SOURCEDIR)/..
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c syscall_interface.rst
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c kernel_memory.rst
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@@ -1,254 +0,0 @@
/* custom.css - jsix version */
:root {
--background-color: #181820;
--link-color: #7070e0;
--link-hover-color: #9090ff;
--text-color: #3d3d3d;
--text-literal-color: #d26a98;
}
.wy-nav-side {
background: var(--background-color);
}
@media screen and (min-width: 1100px) {
.wy-nav-content-wrap {
background: var(--background-color);
}
}
a {
color: var(--link-color);
}
a:hover {
color: var(--link-hover-color);
}
a:visited {
color: var(--link-color);
}
.rst-content {
color: var(--text-color);
}
.rst-content code.literal {
color: var(--text-literal-color);
}
.rst-content tt.literal {
color: var(--text-literal-color);
}
.rst-content .note {
color: #003274;
background: #ccddf3;
padding: 1rem;
margin-bottom: 1rem;
}
.rst-content .note .admonition-title {
display: none;
}
.rst-content .warning {
color: #605000;
background: #fcf4cc;
padding: 1rem;
margin-bottom: 1rem;
}
.rst-content .warning .admonition-title {
display: none;
}
.rst-content .highlight {
background: #f5f5f5;
}
.wy-side-scroll {
background-color: var(--background-color);
}
.wy-side-nav-search {
background-color: var(--background-color);
}
.wy-side-nav-search input[type="text"] {
width: 100%;
border-radius: 0px;
padding: 6px 12px;
border-color: var(--background-color);
}
.wy-menu-vertical a {
font-size: 100%;
color: #d9d9d9;
padding-top: 0.6rem;
padding-bottom: 0.6rem;
background-color: inherit;
}
.wy-menu-vertical a:hover {
background-color: unset;
opacity: 1;
}
.wy-menu-vertical li.current > a {
background-color: var(--background-color);
color: white;
}
.wy-menu-vertical li.current > a span.toctree-expand {
display: block;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.wy-menu-vertical li.current > a span.toctree-expand:before {
display: block;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.wy-menu-vertical li.current > a span.toctree-expand:hover {
color: white;
}
.wy-menu-vertical li.current > a:hover {
background-color: var(--background-color);
color: white;
}
.wy-menu-vertical li.current > a:hover span.toctree-expand {
color: white;
}
.wy-menu-vertical .toctree-l1 {
opacity: 0.5;
}
.wy-menu-vertical .toctree-l1:hover {
opacity: 1;
background-color: inherit;
}
.wy-menu-vertical li.toctree-l1.current {
opacity: 1;
background-color: inherit;
}
.wy-menu-vertical li.toctree-l1.current > a {
border: 0px;
}
.wy-menu-vertical .toctree-l2:hover {
background-color: #566673;
}
.wy-menu-vertical li.toctree-l2.current > a {
background-color: #566673;
color: white;
}
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a {
background-color: #e4e7ea;
color: #838383;
}
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover {
color: var(--text-color);
}
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover span.toctree-expand {
color: var(--text-color);
}
.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current > a {
color: var(--text-color);
}
.wy-menu-vertical li.toctree-l2 a {
border: 0px;
background-color: #566673;
color: #d9d9d9;
}
.wy-menu-vertical li.toctree-l2 a span.toctree-expand {
display: block;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.wy-menu-vertical li.toctree-l2 a span.toctree-expand:before {
display: block;
font-size: inherit;
line-height: inherit;
color: inherit;
}
.wy-menu-vertical li.toctree-l2 a span.toctree-expand:hover {
color: white;
}
.wy-menu-vertical li.toctree-l2 a:hover {
color: white;
background-color: #566673;
}
.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand {
color: white;
}
.wy-menu-vertical li.toctree-l3.current > a {
background-color: #e4e7ea;
color: #838383;
}
.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a {
background-color: #e4e7ea;
color: #838383;
}
.wy-menu-vertical li.toctree-l3.current li.toctree-l4.current > a {
color: var(--text-color);
}
.wy-nav-top {
background-color: var(--background-color);
}
.btn {
display: inline-block;
font-weight: 400;
line-height: 1.5;
color: var(--text-color);
text-align: center;
text-decoration: none;
vertical-align: middle;
cursor: pointer;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: transparent;
border: 1px solid transparent;
padding: 0.375rem 0.75rem;
font-size: 1rem;
border-radius: 0;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
box-shadow: unset;
}
.btn-neutral {
background: unset !important;
color: #838383 !important;
}
.btn-neutral:active {
padding: 0.375rem 0.75rem;
box-shadow: unset;
}

View File

@@ -1,50 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'jsix'
copyright = '2024, Justin C. Miller'
author = 'Justin C. Miller'
release = '0.8'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = ['sphinx.ext.todo']
primary_domain = 'cpp'
todo_include_todos = True
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'renku'
html_title = 'jsix'
html_logo = 'jsix_transparent.svg'
html_static_path = ['_static']
html_css_files = ['custom.css']
html_theme_options = {
"description": "The jsix description",
"github_repo": "https://github.com/justinian/jsix",
"logo_only": True,
"footer_icons": [
{
"name": "GitHub",
"url": "https://github.com/justinian/jsix",
"html": """
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
</svg>
""",
"class": "",
},
],
}

View File

@@ -1,81 +0,0 @@
.. jsix documentation master file
.. |amd64| replace:: :abbr:`amd64 (aka x86_64)`
The jsix Operating System
=========================
Introduction
------------
**jsix** is a custom multi-core x64 operating system being built from scratch,
supporting modern [#]_ Intel or AMD CPUs, and UEFI firmware. It was initially
created out of a desire to explore UEFI and to explore what's possible with a
microkernel architecture on modern 64-bit architectures.
Most of jsix is written in C++ (C++17, using `LLVM <https://llvm.org>`_), but
you'll also find some assembly (in `NASM <https://nasm.us>`_ syntax) and Python
for development tooling.
jsix can be found `on GitHub <https://github.com/justinian/jsix>`_, and is
released under the terms of the `MPL 2.0 <https://mozilla.org/MPL/2.0/>`_.
.. admonition:: A note on the name
This kernel was originally named Popcorn, but I have since discovered that
the Popcorn Linux project is also developing a kernel with that name,
started around the same time as this project. So I've renamed this kernel
jsix as an homage to L4, xv6, and my wonderful wife.
The name jsix is always styled *jsix* or ``j6``, never capitalized.
.. [#] jsix aims to support amd64 (x86_64) CPUs released in the last 10 years.
Current Features
----------------
The jsix kernel is quite far along now, but the userland systems are still lacking.
- Platform: |amd64|
- UEFI bootloader
- Multi-core & multi-tasking microkernel
- Work-stealing SMP scheduler
- Pluggable panic handler modules
- Capability-style object-oriented syscall API
- Custom IDL for specifying and documenting syscalls
- Virtual memory based on sharable Virtual Memory Area objects (VMAs)
- Kernel API library (libj6), also provides features built on kernel primitives:
- Channels (async stream IPC) built on shared memory and futexes
- Ring buffers via doubly-mapped pages
- Custom libc
- Runtime dynamic linker
- Init service
- Built-in VFS service for the initrd
- ELF loader
- Service-lookup protocol service
- Userland UART driver
- Userland UEFI framebuffer driver
- Userland kernel log output service
- Userland unit test runner
- Build configuration system (bonnibel)
.. toctree::
:maxdepth: 1
:caption: Site Contents:
syscall_interface
kernel_memory
process_initialization
* :ref:`genindex`
* :ref:`search`

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Gravit.io -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="176.562 356.069 211.11 113" width="211.11pt" height="113pt">
<g>
<g>
<g>
<path d=" M 212.981 372.36 L 219.564 376.16 L 226.147 379.961 L 226.147 387.563 L 226.147 395.164 L 219.564 398.965 L 212.981 402.766 L 206.398 398.965 L 199.815 395.164 L 199.815 387.563 L 199.815 379.961 L 206.398 376.16 L 212.981 372.36 L 212.981 372.36 L 212.981 372.36 Z M 256.292 397.366 L 262.875 401.166 L 269.458 404.967 L 269.458 412.569 L 269.458 420.17 L 262.875 423.971 L 256.292 427.772 L 249.709 423.971 L 243.126 420.17 L 243.126 412.569 L 243.126 404.967 L 249.709 401.166 L 256.292 397.366 L 256.292 397.366 Z M 183.622 387.283 L 205.52 374.64 L 227.418 361.997 L 249.316 374.64 L 271.214 387.283 L 271.214 412.569 L 271.214 437.854 L 249.316 450.497 L 227.418 463.14 L 205.52 450.497 L 183.622 437.854 L 183.622 412.569 L 183.622 387.283 L 183.622 387.283 L 183.622 387.283 Z M 241.855 372.36 L 248.438 376.16 L 255.021 379.961 L 255.021 387.563 L 255.021 395.164 L 248.438 398.965 L 241.855 402.766 L 235.272 398.965 L 228.689 395.164 L 228.689 387.563 L 228.689 379.961 L 235.272 376.16 L 241.855 372.36 Z " fill-rule="evenodd" fill="rgb(49,79,128)"/>
<path d=" M 298.642 379.579 L 291.621 379.579 L 291.621 372.558 L 298.642 372.558 L 298.642 379.579 Z M 285.214 446.718 L 285.214 441.452 L 287.32 441.452 L 287.32 441.452 Q 289.339 441.452 290.524 440.092 L 290.524 440.092 L 290.524 440.092 Q 291.708 438.731 291.708 436.625 L 291.708 436.625 L 291.708 387.039 L 298.729 387.039 L 298.729 436.011 L 298.729 436.011 Q 298.729 440.925 295.921 443.822 L 295.921 443.822 L 295.921 443.822 Q 293.113 446.718 288.286 446.718 L 288.286 446.718 L 285.214 446.718 Z M 306.628 432.676 L 306.628 427.41 L 314.088 427.41 L 314.088 427.41 Q 317.862 427.41 319.573 425.347 L 319.573 425.347 L 319.573 425.347 Q 321.285 423.285 321.285 419.95 L 321.285 419.95 L 321.285 419.95 Q 321.285 417.317 319.705 415.474 L 319.705 415.474 L 319.705 415.474 Q 318.125 413.631 314.966 411.174 L 314.966 411.174 L 314.966 411.174 Q 312.245 408.98 310.621 407.356 L 310.621 407.356 L 310.621 407.356 Q 308.998 405.732 307.813 403.319 L 307.813 403.319 L 307.813 403.319 Q 306.628 400.905 306.628 397.746 L 306.628 397.746 L 306.628 397.746 Q 306.628 393.095 309.744 390.067 L 309.744 390.067 L 309.744 390.067 Q 312.859 387.039 318.125 387.039 L 318.125 387.039 L 325.76 387.039 L 325.76 392.305 L 319.441 392.305 L 319.441 392.305 Q 313.21 392.305 313.21 398.185 L 313.21 398.185 L 313.21 398.185 Q 313.21 400.467 314.615 402.134 L 314.615 402.134 L 314.615 402.134 Q 316.019 403.802 319.003 406.083 L 319.003 406.083 L 319.003 406.083 Q 321.723 408.19 323.479 409.901 L 323.479 409.901 L 323.479 409.901 Q 325.234 411.613 326.463 414.202 L 326.463 414.202 L 326.463 414.202 Q 327.691 416.791 327.691 420.301 L 327.691 420.301 L 327.691 420.301 Q 327.691 426.532 324.4 429.604 L 324.4 429.604 L 324.4 429.604 Q 321.109 432.676 315.141 432.676 L 315.141 432.676 L 306.628 432.676 Z M 342.611 379.579 L 335.59 379.579 L 335.59 372.558 L 342.611 372.558 L 342.611 379.579 Z M 342.611 432.676 L 335.59 432.676 L 335.59 387.039 L 342.611 387.039 L 342.611 432.676 Z M 356.126 432.676 L 348.754 432.676 L 361.392 409.77 L 349.632 387.039 L 356.39 387.039 L 364.639 403.187 L 372.977 387.039 L 379.735 387.039 L 367.974 409.77 L 380.612 432.676 L 373.24 432.676 L 364.639 416.001 L 356.126 432.676 Z " fill="rgb(49,79,128)"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,178 +0,0 @@
.. jsix syscall interface.
.. Automatically updated from the definition files using cog!
.. [[[cog code generation
.. from os.path import join
.. from memory import Layout, unit
..
.. layout = Layout(join(definitions_path, "memory_layout.yaml"))
.. l = max([len(r.name) for r in layout.regions])
.. ]]]
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
Kernel memory
=============
While jsix probably should eventually use KASLR to randomize its memory layout,
currently the layout is mostly fixed. (Kernel code locations are not consistent
but aren't explicitly randomized.)
.. [[[cog code generation
.. line_size = 128 * 1024**3 # Each line represents up to 32 GiB
.. max_lines = 32
.. totals = sum([r.size for r in layout.regions])
.. remain = unit((128 * 1024**4) - totals)
..
.. def split(val):
.. return f"0x {val >> 48:04x} {(val >> 32) & 0xffff:04x} {(val >> 16) & 0xffff:04x} {val & 0xffff:04x}"
..
.. cog.outl()
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
.. cog.outl(f"| | Address | Size | Use |")
.. cog.outl(f"+=+=============================+==========+=======================================+")
..
.. for region in layout.regions:
.. cog.outl(f"| | ``{split(region.start)}`` | {unit(region.size):>8} | {region.desc:37} |")
.. lines = min(max_lines, region.size // line_size)
.. for i in range(1, lines):
.. cog.outl(f"+-+ | | |")
.. cog.outl(f"| | | | |")
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
..
.. cog.outl(f"| | ... | | |")
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
.. cog.outl(f"| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |")
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
.. cog.outl("")
.. cog.outl("")
.. cog.outl(f"Un-reserved virtual memory address space in the higher half: {remain}")
.. cog.outl("")
..
.. ]]]
+-+-----------------------------+----------+---------------------------------------+
| | Address | Size | Use |
+=+=============================+==========+=======================================+
| | ``0x ffff c000 0000 0000`` | 64 TiB | Linearly-mapped physical memory |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bf00 0000 0000`` | 1 TiB | Used/free page tracking bitmap |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff be00 0000 0000`` | 1 TiB | Per-page state tracking structures |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+ | | |
| | | | |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bdf8 0000 0000`` | 32 GiB | Kernel heap accounting structures |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bdf0 0000 0000`` | 32 GiB | Kernel heap |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bde8 0000 0000`` | 32 GiB | Capabilities accounting structures |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bde0 0000 0000`` | 32 GiB | Capabilities |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bdd0 0000 0000`` | 64 GiB | Kernel thread stacks |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bdc0 0000 0000`` | 64 GiB | Kernel buffers |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff bdbf 8000 0000`` | 2 GiB | Kernel logs circular buffer |
+-+-----------------------------+----------+---------------------------------------+
| | ... | | |
+-+-----------------------------+----------+---------------------------------------+
| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |
+-+-----------------------------+----------+---------------------------------------+
Un-reserved virtual memory address space in the higher half: 61 TiB
.. [[[end]]] (checksum: 8c336cc8151beba1a79c8d3b653f1109)
* :ref:`genindex`
* :ref:`search`

View File

@@ -1,7 +0,0 @@
** !_build/** ../definitions/**.def {
prep: rm -rf _build; make html
}
_build/html/** {
daemon: devd -m _build/html
}

View File

@@ -1,42 +0,0 @@
.. jsix process initialization in userspace
Process Initialization
======================
jsix follows the `System V ABI`_ on the ``amd64`` architecture. All arguments
needed for program initialization are passed to the program's initial thread on
the stack.
Note that jsix adds a number of additional auxiliary vector entry types for
passing jsix-specific data to a program. The jsix-specific auxiliary vector type
codes (what the ABI document refers to as ``a_type``) start from ``0xf000``. See
the header file ``<j6/init.h>`` for more detail.
.. _System V ABI: https://gitlab.com/x86-psABIs/x86-64-ABI
The initial stack frame
-----------------------
============== ==================== ============ =======
Address Value Bytes Notes
============== ==================== ============ =======
``top`` Stack top (out of stack bounds)
``top`` - 16 0 16 Stack sentinel
\ ``envp`` string data ?
\ ``argv`` string data ?
\ ... ? Possible padding
\ 0, 0 (``AT_NULL``) 16 Aux vector sentinel
\ Aux vectors 16 * `m` ``AT_NULL``-terminated array of Aux vectors
\ 0 8 Environment sentinel
\ ``envp`` 8 * `n` 0-terminated array of environment
string pointers
\ 0 8 Args sentinel
\ ``argv`` 8 * ``argc`` Pointers to argument strings
``rsp`` ``argc`` 8 Number of elements in argv
============== ==================== ============ =======
* :ref:`genindex`
* :ref:`search`

View File

@@ -1,5 +0,0 @@
cogapp >= 3
pyyaml >= 5.4
lark == 0.12.0
sphinx
renku-sphinx-theme

View File

@@ -1,444 +0,0 @@
.. jsix syscall interface.
.. Automatically updated from the definition files using cog!
.. [[[cog code generation
.. from textwrap import indent
.. from definitions.context import Context
..
.. ctx = Context(definitions_path)
.. ctx.parse("syscalls.def")
.. syscalls = ctx.interfaces["syscalls"]
..
.. def caplist(caps):
.. return ', '.join([f"``{c}``" for c in caps])
.. ]]]
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
Syscall interface
=================
The jsix kernel's syscall design is based around object handles. Object handles
are also a collection of capabilities, encoding certain rights over the object
they reference.
Very few syscalls in jsix can be made without some handle, and most of them are
requests to the kernel to create a given kind of object. This is analogous to
methods on an object in an object-oriented programming language.
.. [[[cog code generation
.. cog.outl()
.. for obj in syscalls.exposes:
.. cog.outl(f"``{obj.name}`` syscalls")
.. cog.outl(f"-------------------------")
.. desc = obj.desc or "Undocumented"
.. cog.outl(desc)
.. cog.outl()
.. cog.outl(f":capabilites: {caplist(obj.caps)}")
.. cog.outl()
.. for method in obj.methods:
.. args = []
.. if method.constructor:
.. args.append("j6_handle_t *self")
.. elif not method.static:
.. args.append("j6_handle_t self")
..
.. for param in method.params:
.. for type, suffix in param.type.c_names(param.options):
.. args.append(f"{type} {param.name}{suffix}")
..
.. cog.outl(f".. cpp:function:: j6_result_t j6_{obj.name}_{method.name} ({', '.join(args)})")
.. cog.outl()
.. desc = method.desc or "Undocumented"
.. cog.outl(indent(desc, " "))
.. cog.outl()
.. if "cap" in method.options:
.. cog.outl(f" :capabilities: {caplist(method.options['cap'])}")
.. cog.outl()
.. if method.constructor:
.. cog.outl(f" :param self: *[out]* Handle to the new {obj.name} object")
.. elif not method.static:
.. cog.outl(f" :param self: Handle to the {obj.name} object")
.. for param in method.params:
.. opts = param.options and f"*[{', '.join(param.options)}]*" or ""
.. desc = param.desc or 'Undocumented'
.. cog.outl(f" :param {param.name}: {opts} {desc}")
.. cog.outl()
.. ]]]
``object`` syscalls
-------------------------
All kernel-exposed objects inherit from the base ``object`` type, so the
``object`` syscalls can be used with any object's handle.
:capabilites: ``clone``
.. cpp:function:: j6_result_t j6_object_koid (j6_handle_t self, uint64_t * koid)
Get the internal kernel object id of an object
:param self: Handle to the object object
:param koid: *[out]* Undocumented
``event`` syscalls
-------------------------
An ``event`` is a simple synchronization object. It contains up to 64 signals
that threads can wait for and signal in parallel.
:capabilites: ``signal``, ``wait``
.. cpp:function:: j6_result_t j6_event_create (j6_handle_t *self)
Undocumented
:param self: *[out]* Handle to the new event object
.. cpp:function:: j6_result_t j6_event_signal (j6_handle_t self, uint64_t signals)
Signal events on this object
:capabilities: ``signal``
:param self: Handle to the event object
:param signals: A bitset of which events to signal
.. cpp:function:: j6_result_t j6_event_wait (j6_handle_t self, uint64_t * signals, uint64_t timeout)
Wait for signaled events on this object
:capabilities: ``wait``
:param self: Handle to the event object
:param signals: *[out]* A bitset of which events were signaled
:param timeout: Wait timeout in nanoseconds
``mailbox`` syscalls
-------------------------
Mailboxes are objects that enable synchronous IPC via arbitrary
message-passing of tagged data and/or handles. Not as efficient
as shared memory channels, but more flexible.
:capabilites: ``send``, ``receive``, ``close``
.. cpp:function:: j6_result_t j6_mailbox_create (j6_handle_t *self)
Undocumented
:param self: *[out]* Handle to the new mailbox object
.. cpp:function:: j6_result_t j6_mailbox_close (j6_handle_t self)
Undocumented
:capabilities: ``close``
:param self: Handle to the mailbox object
.. cpp:function:: j6_result_t j6_mailbox_call (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size)
Send a message to the reciever, and block until a response is
sent. Note that getting this response does not require the
receive capability.
:capabilities: ``send``
:param self: Handle to the mailbox object
:param tag: *[inout]* Undocumented
:param data: *[optional, inout]* Undocumented
:param data_size: number of total bytes in data buffer
:param handles: *[optional, inout, handle, list]* Undocumented
:param handles_size: total size of handles buffer
.. cpp:function:: j6_result_t j6_mailbox_respond (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size, uint64_t * reply_tag, uint64_t flags)
Respond to a message sent using call, and wait for another
message to arrive. Note that this does not require the send
capability. A reply tag of 0 skips the reply and goes directly
to waiting for a new message.
:capabilities: ``receive``
:param self: Handle to the mailbox object
:param tag: *[inout]* Undocumented
:param data: *[optional, inout]* Undocumented
:param data_size: number of total bytes in data buffer
:param handles: *[optional, inout, handle, list]* Undocumented
:param handles_size: total size of handles buffer
:param reply_tag: *[inout]* Undocumented
:param flags: Undocumented
``process`` syscalls
-------------------------
A ``process`` object represents a process running on the system, and allows
control over the threads, handles, and virtual memory space of that process.
:capabilites: ``kill``, ``create_thread``
.. cpp:function:: j6_result_t j6_process_create (j6_handle_t *self)
Create a new empty process
:param self: *[out]* Handle to the new process object
.. cpp:function:: j6_result_t j6_process_kill (j6_handle_t self)
Stop all threads and exit the given process
:capabilities: ``kill``
:param self: Handle to the process object
.. cpp:function:: j6_result_t j6_process_exit (int64_t result)
Stop all threads and exit the current process
:param result: The result to retrun to the parent process
.. cpp:function:: j6_result_t j6_process_give_handle (j6_handle_t self, j6_handle_t target)
Give the given process a handle that points to the same
object as the specified handle.
:param self: Handle to the process object
:param target: *[handle]* A handle in the caller process to send
``system`` syscalls
-------------------------
The singular ``system`` object represents a handle to kernel functionality
needed by drivers and other priviledged services.
:capabilites: ``get_log``, ``bind_irq``, ``map_phys``, ``change_iopl``
.. cpp:function:: j6_result_t j6_system_get_log (j6_handle_t self, uint64_t seen, void * buffer, size_t * buffer_len)
Get the next log line from the kernel log
:capabilities: ``get_log``
:param self: Handle to the system object
:param seen: Last seen log id
:param buffer: *[out, zero_ok]* Buffer for the log message data structure
.. cpp:function:: j6_result_t j6_system_bind_irq (j6_handle_t self, j6_handle_t dest, unsigned irq, unsigned signal)
Ask the kernel to send this process messages whenever
the given IRQ fires
:capabilities: ``bind_irq``
:param self: Handle to the system object
:param dest: Event object that will receive messages
:param irq: IRQ number to bind
:param signal: Signal number on the event to bind to
.. cpp:function:: j6_result_t j6_system_map_phys (j6_handle_t self, j6_handle_t * area, uintptr_t phys, size_t size, uint32_t flags)
Create a VMA and map an area of physical memory into it,
also mapping that VMA into the current process
:capabilities: ``map_phys``
:param self: Handle to the system object
:param area: *[out]* Receives a handle to the VMA created
:param phys: The physical address of the area
:param size: Size of the area, in bytes
:param flags: Flags to apply to the created VMA
.. cpp:function:: j6_result_t j6_system_request_iopl (j6_handle_t self, unsigned iopl)
Request the kernel change the IOPL for this process. The only values
that make sense are 0 and 3.
:capabilities: ``change_iopl``
:param self: Handle to the system object
:param iopl: The IOPL to set for this process
``thread`` syscalls
-------------------------
A ``thread`` object represents a thread of execution within a process running
on the system. The actual thread does not need to be currently running to
hold a handle to it.
:capabilites: ``kill``, ``join``
.. cpp:function:: j6_result_t j6_thread_create (j6_handle_t *self, j6_handle_t process, uintptr_t stack_top, uintptr_t entrypoint, uint64_t arg0, uint64_t arg1)
Undocumented
:param self: *[out]* Handle to the new thread object
:param process: *[optional, cap]* Undocumented
:param stack_top: Undocumented
:param entrypoint: Undocumented
:param arg0: Undocumented
:param arg1: Undocumented
.. cpp:function:: j6_result_t j6_thread_kill (j6_handle_t self)
Undocumented
:capabilities: ``kill``
:param self: Handle to the thread object
.. cpp:function:: j6_result_t j6_thread_join (j6_handle_t self)
Undocumented
:capabilities: ``join``
:param self: Handle to the thread object
.. cpp:function:: j6_result_t j6_thread_exit ()
Undocumented
.. cpp:function:: j6_result_t j6_thread_sleep (uint64_t duration)
Undocumented
:param duration: Undocumented
``vma`` syscalls
-------------------------
A ``vma`` object represents a single virtual memory area, which may be shared
between several processes. A process having a handle to a ``vma`` does not
necessarily mean that it is mapped into that process' virtual memory space.
:capabilites: ``map``, ``unmap``, ``resize``
.. cpp:function:: j6_result_t j6_vma_create (j6_handle_t *self, size_t size, uint32_t flags)
Undocumented
:param self: *[out]* Handle to the new vma object
:param size: Undocumented
:param flags: Undocumented
.. cpp:function:: j6_result_t j6_vma_create_map (j6_handle_t *self, size_t size, uintptr_t * address, uint32_t flags)
Undocumented
:capabilities: ``map``
:param self: *[out]* Handle to the new vma object
:param size: Undocumented
:param address: *[inout]* Undocumented
:param flags: Undocumented
.. cpp:function:: j6_result_t j6_vma_map (j6_handle_t self, j6_handle_t process, uintptr_t * address, uint32_t flags)
Undocumented
:capabilities: ``map``
:param self: Handle to the vma object
:param process: *[optional]* Undocumented
:param address: *[inout]* Undocumented
:param flags: Undocumented
.. cpp:function:: j6_result_t j6_vma_unmap (j6_handle_t self, j6_handle_t process)
Undocumented
:capabilities: ``unmap``
:param self: Handle to the vma object
:param process: *[optional]* Undocumented
.. cpp:function:: j6_result_t j6_vma_resize (j6_handle_t self, size_t * size)
Undocumented
:capabilities: ``resize``
:param self: Handle to the vma object
:param size: *[inout]* New size for the VMA, or 0 to query the current size without changing
.. [[[end]]] (checksum: cb17f54e443d1d3b85995870f3e8dbf2)
Non-object syscalls
-------------------
The following are the system calls that aren't constructors for objects, and
either do not require an object handle, or operate generically on handles.
.. [[[cog code generation
.. cog.outl()
.. for func in syscalls.functions:
.. args = []
.. for param in func.params:
.. for type, suffix in param.type.c_names(param.options):
.. args.append(f"{type} {param.name}{suffix}")
..
.. cog.outl(f".. cpp:function:: j6_result_t j6_{func.name} ({', '.join(args)})")
.. cog.outl()
.. desc = func.desc or "Undocumented"
.. cog.outl(indent(desc, " "))
.. cog.outl()
.. for param in func.params:
.. opts = param.options and f"*[{', '.join(param.options)}]*" or ""
.. desc = param.desc or 'Undocumented'
.. cog.outl(f" :param {param.name}: {opts} {desc}")
.. cog.outl()
.. ]]]
.. cpp:function:: j6_result_t j6_noop ()
Simple no-op syscall for testing
.. cpp:function:: j6_result_t j6_log (uint8_t area, uint8_t severity, const char * message)
Write a message to the kernel log
:param area: Undocumented
:param severity: Undocumented
:param message: Undocumented
.. cpp:function:: j6_result_t j6_handle_list (struct j6_handle_descriptor * handles, size_t * handles_size)
Get a list of handles owned by this process. If the
supplied list is not big enough, will set the size
needed in `size` and return j6_err_insufficient
:param handles: *[list, inout, zero_ok]* A list of handles to be filled
.. cpp:function:: j6_result_t j6_handle_clone (j6_handle_t orig, j6_handle_t * clone, uint32_t mask)
Create a clone of an existing handle, possibly with
some capabilities masked out.
:param orig: *[handle, cap]* The handle to clone
:param clone: *[out]* The new handle
:param mask: The capability bitmask
.. cpp:function:: j6_result_t j6_handle_close (j6_handle_t hnd)
Close the handle to an object
:param hnd: *[handle]* The handle to close
.. cpp:function:: j6_result_t j6_futex_wait (const uint32_t * address, uint32_t current, uint64_t timeout)
Block waiting on a futex
:param address: Address of the futex value
:param current: Current value of the futex
:param timeout: Wait timeout in nanoseconds
.. cpp:function:: j6_result_t j6_futex_wake (const uint32_t * address, uint64_t count)
Wake threads waiting on a futex
:param address: Address of the futex value
:param count: Number of threads to wake, or 0 for all
.. cpp:function:: j6_result_t j6_test_finish (uint32_t exit_code)
Testing mode only: Have the kernel finish and exit QEMU with the given exit code
:param exit_code: Undocumented
.. [[[end]]] (checksum: 0b9d051972abcbb6de408f411331785f)

3669
external/cpptoml/cpptoml.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -14,15 +14,13 @@
namespace uefi { namespace uefi {
namespace bs_impl { namespace bs_impl {
using allocate_pages = status (*)(allocate_type, memory_type, size_t, void**); using allocate_pages = status (*)(allocate_type, memory_type, size_t, void**);
using free_pages = status (*)(void*, size_t);
using get_memory_map = status (*)(size_t*, memory_descriptor*, size_t*, size_t*, uint32_t*); using get_memory_map = status (*)(size_t*, memory_descriptor*, size_t*, size_t*, uint32_t*);
using allocate_pool = status (*)(memory_type, uint64_t, void**); using allocate_pool = status (*)(memory_type, uint64_t, void**);
using free_pool = status (*)(void*);
using handle_protocol = status (*)(handle, const guid*, void**); using handle_protocol = status (*)(handle, const guid*, void**);
using create_event = status (*)(evt, tpl, event_notify, void*, event*); using create_event = status (*)(evt, tpl, event_notify, void*, event*);
using exit_boot_services = status (*)(handle, size_t); using exit_boot_services = status (*)(handle, size_t);
using locate_protocol = status (*)(const guid*, void*, void**); using locate_protocol = status (*)(const guid*, void*, void**);
using copy_mem = void (*)(void*, const void*, size_t); using copy_mem = void (*)(void*, void*, size_t);
using set_mem = void (*)(void*, uint64_t, uint8_t); using set_mem = void (*)(void*, uint64_t, uint8_t);
} }
@@ -37,10 +35,10 @@ struct boot_services {
// Memory Services // Memory Services
bs_impl::allocate_pages allocate_pages; bs_impl::allocate_pages allocate_pages;
bs_impl::free_pages free_pages; void *free_pages;
bs_impl::get_memory_map get_memory_map; bs_impl::get_memory_map get_memory_map;
bs_impl::allocate_pool allocate_pool; bs_impl::allocate_pool allocate_pool;
bs_impl::free_pool free_pool; void *free_pool;
// Event & Timer Services // Event & Timer Services
bs_impl::create_event create_event; bs_impl::create_event create_event;

View File

@@ -1,390 +0,0 @@
#pragma once
#ifndef _uefi_networking_h_
#define _uefi_networking_h_
// This Source Code Form is part of the j6-uefi-headers project and is subject
// to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
#include <stdint.h>
#include <uefi/types.h>
namespace uefi {
//
// IPv4 definitions
//
struct ipv4_address
{
uint8_t addr[4];
};
//
// IPv6 definitions
//
struct ipv6_address
{
uint8_t addr[16];
};
struct ip6_address_info
{
ipv6_address address;
uint8_t prefix_length;
};
struct ip6_route_table
{
ipv6_address gateway;
ipv6_address destination;
uint8_t prefix_length;
};
enum class ip6_neighbor_state : int {
incomplete,
reachable,
stale,
delay,
probe,
}
struct ip6_neighbor_cache
{
ipv6_address neighbor;
mac_address link_address;
ip6_neighbor_state state;
};
enum class icmpv6_type : uint8_t
{
dest_unreachable = 0x1,
packet_too_big = 0x2,
time_exceeded = 0x3,
parameter_problem = 0x4,
echo_request = 0x80,
echo_reply = 0x81,
listener_query = 0x82,
listener_report = 0x83,
listener_done = 0x84,
router_solicit = 0x85,
router_advertise = 0x86,
neighbor_solicit = 0x87,
neighbor_advertise = 0x88,
redirect = 0x89,
listener_report_2 = 0x8f,
};
enum class icmpv6_code : uint8_t
{
// codes for icmpv6_type::dest_unreachable
no_route_to_dest = 0x0,
comm_prohibited = 0x1,
beyond_scope = 0x2,
addr_unreachable = 0x3,
port_unreachable = 0x4,
source_addr_failed = 0x5,
route_rejected = 0x6,
// codes for icmpv6_type::time_exceeded
timeout_hop_limit = 0x0,
timeout_reassemble = 0x1,
// codes for icmpv6_type::parameter_problem
erroneous_header = 0x0,
unrecognize_next_hdr = 0x1,
unrecognize_option = 0x2,
};
struct ip6_icmp_type
{
icmpv6_type type;
icmpv6_code code;
};
struct ip6_config_data
{
uint8_t default_protocol;
bool accept_any_protocol;
bool accept_icmp_errors;
bool accept_promiscuous;
ipv6_address destination_address;
ipv6_address station_address;
uint8_t traffic_class;
uint8_t hop_limit;
uint32_t flow_label;
uint32_t receive_timeout;
uint32_t transmit_timeout;
};
struct ip6_mode_data
{
bool is_started;
uint32_t max_packet_size;
ip6_config_data config_data;
bool is_configured;
uint32_t address_count;
ip6_address_info * address_list;
uint32_t group_count;
ipv6_address * group_table;
uint32_t route_count;
ip6_route_table * route_table;
uint32_t neighbor_count;
ip6_neighbor_cache * neighbor_cache;
uint32_t prefix_count;
ip6_address_info * prefix_table;
uint32_t icmp_type_count;
* icmp_type_list;
};
struct ip6_header
{
uint8_t traffic_class_h : 4;
uint8_t version : 4;
uint8_t flow_label_h : 4;
uint8_t traffic_class_l : 4;
uint16_t flow_label_l;
uint16_t payload_length;
uint8_t next_header;
uint8_t hop_limit;
ipv6_address source_address;
ipv6_address destination_address;
} __attribute__ ((packed));
struct ip6_fragment_data
{
uint32_t fragment_length;
void *fragment_buffer;
};
struct ip6_override_data
{
uint8_t protocol;
uint8_t hop_limit;
uint32_t flow_label;
};
struct ip6_receive_data
{
time time_stamp;
event recycle_signal;
uint32_t header_length;
ip6_header *header;
uint32_t data_length;
uint32_t fragment_count;
ip6_fragment_data fragment_table[1];
};
struct ip6_transmit_data
{
ipv6_address destination_address;
ip6_override_data *override_data;
uint32_t ext_hdrs_length;
void *ext_hdrs;
uint8_t next_header;
uint32_t data_length;
uint32_t fragment_count;
ip6_fragment_data fragment_table[1];
};
struct ip6_completion_token
{
event event;
status status;
union {
ip6_receive_data *rx_data;
ip6_transmit_data *tx_data;
} packet;
};
enum class ip6_config_data_type : int
{
interface_info,
alt_interface_id,
policy,
dup_addr_detect_transmits,
manual_address,
gateway,
dns_server,
maximum
};
struct ip6_config_interface_info
{
wchar_t name[32];
uint8_t if_type;
uint32_t hw_address_size;
mac_address hw_address;
uint32_t address_info_count;
ip6_address_info *address_info;
uint32_t route_count;
ip6_route_table *route_table;
};
struct ip6_config_interface_id
{
uint8_t id[8];
};
enum class ip6_config_policy : int
{
manual,
automatic
};
struct ip6_config_dup_addr_detect_transmits
{
uint32_t dup_addr_detect_transmits;
};
struct ip6_config_manual_address
{
ipv6_address address;
bool is_anycast;
uint8_t prefix_length;
};
//
// IP definitions
//
union ip_address
{
uint8_t addr[4];
ipv4_address v4;
ipv6_address v6;
};
//
// HTTP definitions
//
struct httpv4_access_point
{
bool use_default_address;
ipv4_address local_address;
ipv4_address local_subnet;
uint16_t local_port;
};
struct httpv6_access_point
{
ipv6_address local_address;
uint16_t local_port;
};
enum class http_version : int {
v10,
v11,
unsupported,
};
struct http_config_data
{
http_version http_version;
uint32_t time_out_millisec;
bool local_address_is_ipv6;
union {
httpv4_access_point *ipv4_node;
httpv6_access_point *ipv6_node;
} access_point;
};
enum class http_method : int {
get,
post,
patch,
options,
connect,
head,
put,
delete_,
trace,
};
struct http_request_data
{
http_method method;
wchar_t *url;
};
enum class http_status_code : int {
unsupported,
continue_,
switching_protocols,
ok,
created,
accepted,
non_authoritative_information,
no_content,
reset_content,
partial_content,
multiple_choices,
moved_permanently,
found,
see_other,
not_modified,
use_proxy,
temporary_redirect,
bad_request,
unauthorized,
payment_required,
forbidden,
not_found,
method_not_allowed,
not_acceptable,
proxy_authentication_required,
request_time_out,
conflict,
gone,
length_required,
precondition_failed,
request_entity_too_large,
request_uri_too_large,
unsupported_media_type,
requested_range_not_satisfied,
expectation_failed,
internal_server_error,
not_implemented,
bad_gateway,
service_unavailable,
gateway_timeout,
http_version_not_supported,
permanent_redirect, // I hate your decisions, uefi.
};
struct http_response_data
{
http_status_code status_code;
};
struct http_header
{
char *field_name;
char *field_value;
};
struct http_message
{
union {
http_request_data *request;
http_response_data *response;
} data;
size_t header_count;
http_header *headers;
size_t body_length;
void *body;
};
struct http_token
{
event event;
status status;
http_message *message;
};
} // namespace uefi
#endif

View File

@@ -16,7 +16,6 @@ struct device_path
{ {
static constexpr uefi::guid guid{ 0x09576e91,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} }; static constexpr uefi::guid guid{ 0x09576e91,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
uint8_t type; uint8_t type;
uint8_t sub_type; uint8_t sub_type;
uint16_t length; uint16_t length;
@@ -28,4 +27,4 @@ public:
} // namespace protos } // namespace protos
} // namespace uefi } // namespace uefi
#endif // _uefi_protos_device_path_h_ #endif // _uefi_protos_device_path_h_

View File

@@ -14,7 +14,7 @@ struct file;
struct file struct file
{ {
inline uefi::status open(file ** new_handle, const wchar_t * file_name, file_mode open_mode, file_attr attributes) { inline uefi::status open(file ** new_handle, const wchar_t * file_name, file_mode open_mode, file_attr attributes) {
return _open(this, new_handle, file_name, open_mode, attributes); return _open(this, new_handle, file_name, open_mode, attributes);
@@ -123,4 +123,4 @@ public:
} // namespace protos } // namespace protos
} // namespace uefi } // namespace uefi
#endif // _uefi_protos_file_h_ #endif // _uefi_protos_file_h_

View File

@@ -16,7 +16,6 @@ struct file_info
{ {
static constexpr uefi::guid guid{ 0x09576e92,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} }; static constexpr uefi::guid guid{ 0x09576e92,0x6d3f,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
uint64_t size; uint64_t size;
uint64_t file_size; uint64_t file_size;
uint64_t physical_size; uint64_t physical_size;
@@ -33,4 +32,4 @@ public:
} // namespace protos } // namespace protos
} // namespace uefi } // namespace uefi
#endif // _uefi_protos_file_info_h_ #endif // _uefi_protos_file_info_h_

View File

@@ -17,7 +17,6 @@ struct graphics_output
{ {
static constexpr uefi::guid guid{ 0x9042a9de,0x23dc,0x4a38,{0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a} }; static constexpr uefi::guid guid{ 0x9042a9de,0x23dc,0x4a38,{0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a} };
inline uefi::status query_mode(uint32_t mode_number, uint64_t * size_of_info, uefi::graphics_output_mode_info ** info) { inline uefi::status query_mode(uint32_t mode_number, uint64_t * size_of_info, uefi::graphics_output_mode_info ** info) {
return _query_mode(this, mode_number, size_of_info, info); return _query_mode(this, mode_number, size_of_info, info);
} }
@@ -48,4 +47,4 @@ public:
} // namespace protos } // namespace protos
} // namespace uefi } // namespace uefi
#endif // _uefi_protos_graphics_output_h_ #endif // _uefi_protos_graphics_output_h_

View File

@@ -1,72 +0,0 @@
#pragma once
#ifndef _uefi_protos_http_h_
#define _uefi_protos_http_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/networking.h>
namespace uefi {
namespace protos {
struct http;
struct http
{
static constexpr uefi::guid guid{ 0x7a59b29b,0x910b,0x4171,{0x82,0x42,0xa8,0x5a,0x0d,0xf2,0x5b,0x5b} };
static constexpr uefi::guid service_binding{ 0xbdc8e6af,0xd9bc,0x4379,{0xa7,0x2a,0xe0,0xc4,0xe7,0x5d,0xae,0x1c} };
inline uefi::status get_mode_data(uefi::http_config_data * http_config_data) {
return _get_mode_data(this, http_config_data);
}
inline uefi::status configure(uefi::http_config_data * http_config_data) {
return _configure(this, http_config_data);
}
inline uefi::status request(uefi::http_token * token) {
return _request(this, token);
}
inline uefi::status cancel(uefi::http_token * token) {
return _cancel(this, token);
}
inline uefi::status response(uefi::http_token * token) {
return _response(this, token);
}
inline uefi::status poll() {
return _poll(this);
}
protected:
using _get_mode_data_def = uefi::status (*)(uefi::protos::http *, uefi::http_config_data *);
_get_mode_data_def _get_mode_data;
using _configure_def = uefi::status (*)(uefi::protos::http *, uefi::http_config_data *);
_configure_def _configure;
using _request_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
_request_def _request;
using _cancel_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
_cancel_def _cancel;
using _response_def = uefi::status (*)(uefi::protos::http *, uefi::http_token *);
_response_def _response;
using _poll_def = uefi::status (*)(uefi::protos::http *);
_poll_def _poll;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_http_h_

View File

@@ -1,93 +0,0 @@
#pragma once
#ifndef _uefi_protos_ip6_h_
#define _uefi_protos_ip6_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/networking.h>
namespace uefi {
namespace protos {
struct ip6;
struct ip6
{
static constexpr uefi::guid guid{ 0x2c8759d5,0x5c2d,0x66ef,{0x92,0x5f,0xb6,0x6c,0x10,0x19,0x57,0xe2} };
static constexpr uefi::guid service_binding{ 0xec835dd3,0xfe0f,0x617b,{0xa6,0x21,0xb3,0x50,0xc3,0xe1,0x33,0x88} };
inline uefi::status get_mode_data(uefi::ip6_mode_data * ip6_mode_data, uefi::managed_network_config_data * mnp_config_data, uefi::simple_network_mode * snp_config_data) {
return _get_mode_data(this, ip6_mode_data, mnp_config_data, snp_config_data);
}
inline uefi::status configure(uefi::ip6_config_data * ip6_config_data) {
return _configure(this, ip6_config_data);
}
inline uefi::status groups(bool join_flag, uefi::ipv6_address * group_address) {
return _groups(this, join_flag, group_address);
}
inline uefi::status routes(bool delete_route, uefi::ipv6_address * destination, uint8_t prefix_length, uefi::ipv6_address * gateway_address) {
return _routes(this, delete_route, destination, prefix_length, gateway_address);
}
inline uefi::status neighbors(bool delete_flag, uefi::ipv6_address * target_ip6_address, uefi::mac_address * target_link_address, uint32_t timeout, bool override) {
return _neighbors(this, delete_flag, target_ip6_address, target_link_address, timeout, override);
}
inline uefi::status transmit(uefi::ip6_completion_token * token) {
return _transmit(this, token);
}
inline uefi::status receive(uefi::ip6_completion_token * token) {
return _receive(this, token);
}
inline uefi::status cancel(uefi::ip6_completion_token * token) {
return _cancel(this, token);
}
inline uefi::status poll() {
return _poll(this);
}
protected:
using _get_mode_data_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_mode_data *, uefi::managed_network_config_data *, uefi::simple_network_mode *);
_get_mode_data_def _get_mode_data;
using _configure_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_config_data *);
_configure_def _configure;
using _groups_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *);
_groups_def _groups;
using _routes_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *, uint8_t, uefi::ipv6_address *);
_routes_def _routes;
using _neighbors_def = uefi::status (*)(uefi::protos::ip6 *, bool, uefi::ipv6_address *, uefi::mac_address *, uint32_t, bool);
_neighbors_def _neighbors;
using _transmit_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
_transmit_def _transmit;
using _receive_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
_receive_def _receive;
using _cancel_def = uefi::status (*)(uefi::protos::ip6 *, uefi::ip6_completion_token *);
_cancel_def _cancel;
using _poll_def = uefi::status (*)(uefi::protos::ip6 *);
_poll_def _poll;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_ip6_h_

View File

@@ -1,57 +0,0 @@
#pragma once
#ifndef _uefi_protos_ip6_config_h_
#define _uefi_protos_ip6_config_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/networking.h>
namespace uefi {
namespace protos {
struct ip6_config;
struct ip6_config
{
static constexpr uefi::guid guid{ 0x937fe521,0x95ae,0x4d1a,{0x89,0x29,0x48,0xbc,0xd9,0x0a,0xd3,0x1a} };
inline uefi::status set_data(uefi::ip6_config_data_type data_type, size_t data_size, void * data) {
return _set_data(this, data_type, data_size, data);
}
inline uefi::status get_data(uefi::ip6_config_data_type data_type, size_t data_size, void * data) {
return _get_data(this, data_type, data_size, data);
}
inline uefi::status register_data_notify(uefi::ip6_config_data_type data_type, uefi::event event) {
return _register_data_notify(this, data_type, event);
}
inline uefi::status unregister_data_notify(uefi::ip6_config_data_type data_type, uefi::event event) {
return _unregister_data_notify(this, data_type, event);
}
protected:
using _set_data_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, size_t, void *);
_set_data_def _set_data;
using _get_data_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, size_t, void *);
_get_data_def _get_data;
using _register_data_notify_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, uefi::event);
_register_data_notify_def _register_data_notify;
using _unregister_data_notify_def = uefi::status (*)(uefi::protos::ip6_config *, uefi::ip6_config_data_type, uefi::event);
_unregister_data_notify_def _unregister_data_notify;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_ip6_config_h_

View File

@@ -1,36 +0,0 @@
#pragma once
#ifndef _uefi_protos_load_file_h_
#define _uefi_protos_load_file_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
#include <uefi/protos/device_path.h>
namespace uefi {
namespace protos {
struct load_file;
struct load_file
{
static constexpr uefi::guid guid{ {0x56ec3091,0x954c,0x11d2,{0x8e,0x3f,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status load_file(uefi::protos::device_path * file_path, bool boot_policy, size_t * buffer_size, void * buffer) {
return _load_file(this, file_path, boot_policy, buffer_size, buffer);
}
protected:
using _load_file_def = uefi::status (*)(uefi::protos::load_file *, uefi::protos::device_path *, bool, size_t *, void *);
_load_file_def _load_file;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_load_file_h_

View File

@@ -18,7 +18,6 @@ struct loaded_image
{ {
static constexpr uefi::guid guid{ 0x5b1b31a1,0x9562,0x11d2,{0x8e,0x3f,0x00,0xa0,0xc9,0x69,0x72,0x3b} }; static constexpr uefi::guid guid{ 0x5b1b31a1,0x9562,0x11d2,{0x8e,0x3f,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status unload(uefi::handle image_handle) { inline uefi::status unload(uefi::handle image_handle) {
return _unload(image_handle); return _unload(image_handle);
} }
@@ -46,4 +45,4 @@ public:
} // namespace protos } // namespace protos
} // namespace uefi } // namespace uefi
#endif // _uefi_protos_loaded_image_h_ #endif // _uefi_protos_loaded_image_h_

View File

@@ -1,41 +0,0 @@
#pragma once
#ifndef _uefi_protos_service_binding_h_
#define _uefi_protos_service_binding_h_
// This file was auto generated by the j6-uefi-headers project. Please see
// https://github.com/justinian/j6-uefi-headers for more information.
#include <uefi/guid.h>
#include <uefi/types.h>
namespace uefi {
namespace protos {
struct service_binding;
struct service_binding
{
inline uefi::status create_child(uefi::handle * child_handle) {
return _create_child(this, child_handle);
}
inline uefi::status destroy_child(uefi::handle child_handle) {
return _destroy_child(this, child_handle);
}
protected:
using _create_child_def = uefi::status (*)(uefi::protos::service_binding *, uefi::handle *);
_create_child_def _create_child;
using _destroy_child_def = uefi::status (*)(uefi::protos::service_binding *, uefi::handle);
_destroy_child_def _destroy_child;
public:
};
} // namespace protos
} // namespace uefi
#endif // _uefi_protos_service_binding_h_

View File

@@ -17,7 +17,6 @@ struct simple_file_system
{ {
static constexpr uefi::guid guid{ 0x0964e5b22,0x6459,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} }; static constexpr uefi::guid guid{ 0x0964e5b22,0x6459,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status open_volume(uefi::protos::file ** root) { inline uefi::status open_volume(uefi::protos::file ** root) {
return _open_volume(this, root); return _open_volume(this, root);
} }
@@ -34,4 +33,4 @@ public:
} // namespace protos } // namespace protos
} // namespace uefi } // namespace uefi
#endif // _uefi_protos_simple_file_system_h_ #endif // _uefi_protos_simple_file_system_h_

View File

@@ -17,7 +17,6 @@ struct simple_text_output
{ {
static constexpr uefi::guid guid{ 0x387477c2,0x69c7,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} }; static constexpr uefi::guid guid{ 0x387477c2,0x69c7,0x11d2,{0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} };
inline uefi::status reset(bool extended_verification) { inline uefi::status reset(bool extended_verification) {
return _reset(this, extended_verification); return _reset(this, extended_verification);
} }
@@ -90,4 +89,4 @@ public:
} // namespace protos } // namespace protos
} // namespace uefi } // namespace uefi
#endif // _uefi_protos_simple_text_output_h_ #endif // _uefi_protos_simple_text_output_h_

33
external/zstd.module vendored
View File

@@ -1,33 +0,0 @@
# vim: ft=python
zstd = module("zstd",
root = "${source_root}/external/zstd",
kind = "lib",
copy_headers = True,
deps = [ "libc" ],
sources = [
"decompress/zstd_decompress.c",
"decompress/zstd_ddict.c",
"decompress/huf_decompress.c",
"decompress/zstd_decompress_block.c",
"common/threading.c",
"common/fse_decompress.c",
"common/debug.c",
"common/xxhash.c",
"common/pool.c",
"common/error_private.c",
"common/entropy_common.c",
"common/zstd_common.c",
],
public_headers = [
"zdict.h",
"zstd.h",
"zstd_errors.h",
])
zstd.variables['ccflags'] = [
"${ccflags}",
"-DXXH_NAMESPACE=ZSTD_",
"-DDEBUGLEVEL=0",
"-DZSTD_DISABLE_ASM",
]

View File

@@ -1,3 +0,0 @@
# make install artefact
libzstd.pc
libzstd-nomt

232
external/zstd/BUCK vendored
View File

@@ -1,232 +0,0 @@
cxx_library(
name='zstd',
header_namespace='',
exported_headers=['zstd.h'],
visibility=['PUBLIC'],
deps=[
':common',
':compress',
':decompress',
':deprecated',
],
)
cxx_library(
name='compress',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('compress', 'zstd*.h'),
]),
srcs=glob(['compress/zstd*.c', 'compress/hist.c']),
deps=[':common'],
)
cxx_library(
name='decompress',
header_namespace='',
visibility=['PUBLIC'],
headers=subdir_glob([
('decompress', '*_impl.h'),
]),
srcs=glob(['decompress/zstd*.c']),
deps=[
':common',
':legacy',
],
)
cxx_library(
name='deprecated',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('deprecated', '*.h'),
]),
srcs=glob(['deprecated/*.c']),
deps=[':common'],
)
cxx_library(
name='legacy',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('legacy', '*.h'),
]),
srcs=glob(['legacy/*.c']),
deps=[':common'],
exported_preprocessor_flags=[
'-DZSTD_LEGACY_SUPPORT=4',
],
)
cxx_library(
name='zdict',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=['zdict.h'],
headers=subdir_glob([
('dictBuilder', 'divsufsort.h'),
('dictBuilder', 'cover.h'),
]),
srcs=glob(['dictBuilder/*.c']),
deps=[':common'],
)
cxx_library(
name='compiler',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'compiler.h'),
]),
)
cxx_library(
name='cpu',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'cpu.h'),
]),
)
cxx_library(
name='bitstream',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'bitstream.h'),
]),
)
cxx_library(
name='entropy',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'fse.h'),
('common', 'huf.h'),
]),
srcs=[
'common/entropy_common.c',
'common/fse_decompress.c',
'compress/fse_compress.c',
'compress/huf_compress.c',
'decompress/huf_decompress.c',
],
deps=[
':debug',
':bitstream',
':compiler',
':errors',
':mem',
],
)
cxx_library(
name='errors',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=[
'zstd_errors.h',
'common/error_private.h',
]
srcs=['common/error_private.c'],
)
cxx_library(
name='mem',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'mem.h'),
]),
)
cxx_library(
name='pool',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'pool.h'),
]),
srcs=['common/pool.c'],
deps=[
':threading',
':zstd_common',
],
)
cxx_library(
name='threading',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'threading.h'),
]),
srcs=['common/threading.c'],
exported_preprocessor_flags=[
'-DZSTD_MULTITHREAD',
],
exported_linker_flags=[
'-pthread',
],
)
cxx_library(
name='xxhash',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'xxhash.h'),
]),
srcs=['common/xxhash.c'],
exported_preprocessor_flags=[
'-DXXH_NAMESPACE=ZSTD_',
],
)
cxx_library(
name='zstd_common',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('', 'zstd.h'),
('common', 'zstd_internal.h'),
]),
srcs=['common/zstd_common.c'],
deps=[
':compiler',
':errors',
':mem',
],
)
cxx_library(
name='debug',
header_namespace='',
visibility=['PUBLIC'],
exported_headers=subdir_glob([
('common', 'debug.h'),
]),
srcs=['common/debug.c'],
)
cxx_library(
name='common',
deps=[
':debug',
':bitstream',
':compiler',
':cpu',
':entropy',
':errors',
':mem',
':pool',
':threading',
':xxhash',
':zstd_common',
]
)

30
external/zstd/LICENSE vendored
View File

@@ -1,30 +0,0 @@
BSD License
For Zstandard software
Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook, nor Meta, nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

357
external/zstd/Makefile vendored
View File

@@ -1,357 +0,0 @@
# ################################################################
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under both the BSD-style license (found in the
# LICENSE file in the root directory of this source tree) and the GPLv2 (found
# in the COPYING file in the root directory of this source tree).
# You may select, at your option, one of the above-listed licenses.
# ################################################################
# Modules
ZSTD_LIB_COMPRESSION ?= 1
ZSTD_LIB_DECOMPRESSION ?= 1
ZSTD_LIB_DICTBUILDER ?= 1
ZSTD_LIB_DEPRECATED ?= 0
# Input variables for libzstd.mk
ifeq ($(ZSTD_LIB_COMPRESSION), 0)
ZSTD_LIB_DICTBUILDER = 0
ZSTD_LIB_DEPRECATED = 0
endif
ifeq ($(ZSTD_LIB_DECOMPRESSION), 0)
ZSTD_LEGACY_SUPPORT = 0
ZSTD_LIB_DEPRECATED = 0
endif
include libzstd.mk
ZSTD_FILES := $(ZSTD_COMMON_FILES) $(ZSTD_LEGACY_FILES)
ifneq ($(ZSTD_LIB_COMPRESSION), 0)
ZSTD_FILES += $(ZSTD_COMPRESS_FILES)
endif
ifneq ($(ZSTD_LIB_DECOMPRESSION), 0)
ZSTD_FILES += $(ZSTD_DECOMPRESS_FILES)
endif
ifneq ($(ZSTD_LIB_DEPRECATED), 0)
ZSTD_FILES += $(ZSTD_DEPRECATED_FILES)
endif
ifneq ($(ZSTD_LIB_DICTBUILDER), 0)
ZSTD_FILES += $(ZSTD_DICTBUILDER_FILES)
endif
ZSTD_LOCAL_SRC := $(notdir $(ZSTD_FILES))
ZSTD_LOCAL_OBJ0 := $(ZSTD_LOCAL_SRC:.c=.o)
ZSTD_LOCAL_OBJ := $(ZSTD_LOCAL_OBJ0:.S=.o)
VERSION := $(ZSTD_VERSION)
# Note: by default, the static library is built single-threaded and dynamic library is built
# multi-threaded. It is possible to force multi or single threaded builds by appending
# -mt or -nomt to the build target (like lib-mt for multi-threaded, lib-nomt for single-threaded).
.PHONY: default
default: lib-release
CPPFLAGS_DYNLIB += -DZSTD_MULTITHREAD # dynamic library build defaults to multi-threaded
LDFLAGS_DYNLIB += -pthread
CPPFLAGS_STATLIB += # static library build defaults to single-threaded
ifeq ($(findstring GCC,$(CCVER)),GCC)
decompress/zstd_decompress_block.o : CFLAGS+=-fno-tree-vectorize
endif
# macOS linker doesn't support -soname, and use different extension
# see : https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
ifeq ($(UNAME), Darwin)
SHARED_EXT = dylib
SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT)
SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT)
SONAME_FLAGS = -install_name $(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) -compatibility_version $(LIBVER_MAJOR) -current_version $(LIBVER)
else
ifeq ($(UNAME), AIX)
SONAME_FLAGS =
else
SONAME_FLAGS = -Wl,-soname=libzstd.$(SHARED_EXT).$(LIBVER_MAJOR)
endif
SHARED_EXT = so
SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR)
SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER)
endif
.PHONY: all
all: lib
.PHONY: libzstd.a # must be run every time
libzstd.a: CPPFLAGS += $(CPPFLAGS_STATLIB)
SET_CACHE_DIRECTORY = \
+$(MAKE) --no-print-directory $@ \
BUILD_DIR=obj/$(HASH_DIR) \
CPPFLAGS="$(CPPFLAGS)" \
CFLAGS="$(CFLAGS)" \
LDFLAGS="$(LDFLAGS)"
ifndef BUILD_DIR
# determine BUILD_DIR from compilation flags
libzstd.a:
$(SET_CACHE_DIRECTORY)
else
# BUILD_DIR is defined
ZSTD_STATLIB_DIR := $(BUILD_DIR)/static
ZSTD_STATLIB := $(ZSTD_STATLIB_DIR)/libzstd.a
ZSTD_STATLIB_OBJ := $(addprefix $(ZSTD_STATLIB_DIR)/,$(ZSTD_LOCAL_OBJ))
$(ZSTD_STATLIB): ARFLAGS = rcs
$(ZSTD_STATLIB): | $(ZSTD_STATLIB_DIR)
$(ZSTD_STATLIB): $(ZSTD_STATLIB_OBJ)
# Check for multithread flag at target execution time
$(if $(filter -DZSTD_MULTITHREAD,$(CPPFLAGS)),\
@echo compiling multi-threaded static library $(LIBVER),\
@echo compiling single-threaded static library $(LIBVER))
$(AR) $(ARFLAGS) $@ $^
libzstd.a: $(ZSTD_STATLIB)
cp -f $< $@
endif
ifneq (,$(filter Windows%,$(TARGET_SYSTEM)))
LIBZSTD = dll/libzstd.dll
$(LIBZSTD): $(ZSTD_FILES)
@echo compiling dynamic library $(LIBVER)
$(CC) $(FLAGS) -DZSTD_DLL_EXPORT=1 -Wl,--out-implib,dll/libzstd.dll.a -shared $^ -o $@
else # not Windows
LIBZSTD = libzstd.$(SHARED_EXT_VER)
.PHONY: $(LIBZSTD) # must be run every time
$(LIBZSTD): CPPFLAGS += $(CPPFLAGS_DYNLIB)
$(LIBZSTD): CFLAGS += -fPIC -fvisibility=hidden
$(LIBZSTD): LDFLAGS += -shared $(LDFLAGS_DYNLIB)
ifndef BUILD_DIR
# determine BUILD_DIR from compilation flags
$(LIBZSTD):
$(SET_CACHE_DIRECTORY)
else
# BUILD_DIR is defined
ZSTD_DYNLIB_DIR := $(BUILD_DIR)/dynamic
ZSTD_DYNLIB := $(ZSTD_DYNLIB_DIR)/$(LIBZSTD)
ZSTD_DYNLIB_OBJ := $(addprefix $(ZSTD_DYNLIB_DIR)/,$(ZSTD_LOCAL_OBJ))
$(ZSTD_DYNLIB): | $(ZSTD_DYNLIB_DIR)
$(ZSTD_DYNLIB): $(ZSTD_DYNLIB_OBJ)
# Check for multithread flag at target execution time
$(if $(filter -DZSTD_MULTITHREAD,$(CPPFLAGS)),\
@echo compiling multi-threaded dynamic library $(LIBVER),\
@echo compiling single-threaded dynamic library $(LIBVER))
$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@
@echo creating versioned links
ln -sf $@ libzstd.$(SHARED_EXT_MAJOR)
ln -sf $@ libzstd.$(SHARED_EXT)
$(LIBZSTD): $(ZSTD_DYNLIB)
cp -f $< $@
endif # ifndef BUILD_DIR
endif # if windows
.PHONY: libzstd
libzstd : $(LIBZSTD)
.PHONY: lib
lib : libzstd.a libzstd
# note : do not define lib-mt or lib-release as .PHONY
# make does not consider implicit pattern rule for .PHONY target
%-mt : CPPFLAGS_DYNLIB := -DZSTD_MULTITHREAD
%-mt : CPPFLAGS_STATLIB := -DZSTD_MULTITHREAD
%-mt : LDFLAGS_DYNLIB := -pthread
%-mt : %
@echo multi-threaded build completed
%-nomt : CPPFLAGS_DYNLIB :=
%-nomt : LDFLAGS_DYNLIB :=
%-nomt : CPPFLAGS_STATLIB :=
%-nomt : %
@echo single-threaded build completed
%-release : DEBUGFLAGS :=
%-release : %
@echo release build completed
# Generate .h dependencies automatically
DEPFLAGS = -MT $@ -MMD -MP -MF
$(ZSTD_DYNLIB_DIR)/%.o : %.c $(ZSTD_DYNLIB_DIR)/%.d | $(ZSTD_DYNLIB_DIR)
@echo CC $@
$(COMPILE.c) $(DEPFLAGS) $(ZSTD_DYNLIB_DIR)/$*.d $(OUTPUT_OPTION) $<
$(ZSTD_STATLIB_DIR)/%.o : %.c $(ZSTD_STATLIB_DIR)/%.d | $(ZSTD_STATLIB_DIR)
@echo CC $@
$(COMPILE.c) $(DEPFLAGS) $(ZSTD_STATLIB_DIR)/$*.d $(OUTPUT_OPTION) $<
$(ZSTD_DYNLIB_DIR)/%.o : %.S | $(ZSTD_DYNLIB_DIR)
@echo AS $@
$(COMPILE.S) $(OUTPUT_OPTION) $<
$(ZSTD_STATLIB_DIR)/%.o : %.S | $(ZSTD_STATLIB_DIR)
@echo AS $@
$(COMPILE.S) $(OUTPUT_OPTION) $<
MKDIR ?= mkdir
$(BUILD_DIR) $(ZSTD_DYNLIB_DIR) $(ZSTD_STATLIB_DIR):
$(MKDIR) -p $@
DEPFILES := $(ZSTD_DYNLIB_OBJ:.o=.d) $(ZSTD_STATLIB_OBJ:.o=.d)
$(DEPFILES):
include $(wildcard $(DEPFILES))
# Special case : building library in single-thread mode _and_ without zstdmt_compress.c
ZSTDMT_FILES = compress/zstdmt_compress.c
ZSTD_NOMT_FILES = $(filter-out $(ZSTDMT_FILES),$(ZSTD_FILES))
libzstd-nomt: CFLAGS += -fPIC -fvisibility=hidden
libzstd-nomt: LDFLAGS += -shared
libzstd-nomt: $(ZSTD_NOMT_FILES)
@echo compiling single-thread dynamic library $(LIBVER)
@echo files : $(ZSTD_NOMT_FILES)
$(CC) $(FLAGS) $^ $(LDFLAGS) $(SONAME_FLAGS) -o $@
.PHONY: clean
clean:
$(RM) -r *.dSYM # macOS-specific
$(RM) core *.o *.a *.gcda *.$(SHARED_EXT) *.$(SHARED_EXT).* libzstd.pc
$(RM) dll/libzstd.dll dll/libzstd.lib libzstd-nomt*
$(RM) -r obj/*
@echo Cleaning library completed
#-----------------------------------------------------------------------------
# make install is validated only for below listed environments
#-----------------------------------------------------------------------------
ifneq (,$(filter $(UNAME),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS Haiku AIX))
lib: libzstd.pc
HAS_EXPLICIT_EXEC_PREFIX := $(if $(or $(EXEC_PREFIX),$(exec_prefix)),1,)
DESTDIR ?=
# directory variables : GNU conventions prefer lowercase
# see https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html
# support both lower and uppercase (BSD), use uppercase in script
prefix ?= /usr/local
PREFIX ?= $(prefix)
exec_prefix ?= $(PREFIX)
EXEC_PREFIX ?= $(exec_prefix)
libdir ?= $(EXEC_PREFIX)/lib
LIBDIR ?= $(libdir)
includedir ?= $(PREFIX)/include
INCLUDEDIR ?= $(includedir)
PCINCDIR := $(patsubst $(PREFIX)%,%,$(INCLUDEDIR))
PCLIBDIR := $(patsubst $(EXEC_PREFIX)%,%,$(LIBDIR))
# If we successfully stripped off a prefix, we'll add a reference to the
# relevant pc variable.
PCINCPREFIX := $(if $(findstring $(INCLUDEDIR),$(PCINCDIR)),,$${prefix})
PCLIBPREFIX := $(if $(findstring $(LIBDIR),$(PCLIBDIR)),,$${exec_prefix})
# If no explicit EXEC_PREFIX was set by the caller, write it out as a reference
# to PREFIX, rather than as a resolved value.
PCEXEC_PREFIX := $(if $(HAS_EXPLICIT_EXEC_PREFIX),$(EXEC_PREFIX),$${prefix})
ifneq (,$(filter $(UNAME),FreeBSD NetBSD DragonFly))
PKGCONFIGDIR ?= $(PREFIX)/libdata/pkgconfig
else
PKGCONFIGDIR ?= $(LIBDIR)/pkgconfig
endif
ifneq (,$(filter $(UNAME),SunOS))
INSTALL ?= ginstall
else
INSTALL ?= install
endif
INSTALL_PROGRAM ?= $(INSTALL)
INSTALL_DATA ?= $(INSTALL) -m 644
libzstd.pc: libzstd.pc.in
@echo creating pkgconfig
@sed \
-e 's|@PREFIX@|$(PREFIX)|' \
-e 's|@EXEC_PREFIX@|$(PCEXEC_PREFIX)|' \
-e 's|@INCLUDEDIR@|$(PCINCPREFIX)$(PCINCDIR)|' \
-e 's|@LIBDIR@|$(PCLIBPREFIX)$(PCLIBDIR)|' \
-e 's|@VERSION@|$(VERSION)|' \
-e 's|@LIBS_PRIVATE@|$(LDFLAGS_DYNLIB)|' \
$< >$@
.PHONY: install
install: install-pc install-static install-shared install-includes
@echo zstd static and shared library installed
.PHONY: install-pc
install-pc: libzstd.pc
[ -e $(DESTDIR)$(PKGCONFIGDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR)/
$(INSTALL_DATA) libzstd.pc $(DESTDIR)$(PKGCONFIGDIR)/
.PHONY: install-static
install-static:
# only generate libzstd.a if it's not already present
[ -e libzstd.a ] || $(MAKE) libzstd.a-release
[ -e $(DESTDIR)$(LIBDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/
@echo Installing static library
$(INSTALL_DATA) libzstd.a $(DESTDIR)$(LIBDIR)
.PHONY: install-shared
install-shared:
# only generate libzstd.so if it's not already present
[ -e $(LIBZSTD) ] || $(MAKE) libzstd-release
[ -e $(DESTDIR)$(LIBDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)/
@echo Installing shared library
$(INSTALL_PROGRAM) $(LIBZSTD) $(DESTDIR)$(LIBDIR)
ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR)
ln -sf $(LIBZSTD) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT)
.PHONY: install-includes
install-includes:
[ -e $(DESTDIR)$(INCLUDEDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)/
@echo Installing includes
$(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_DATA) zstd_errors.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_DATA) zdict.h $(DESTDIR)$(INCLUDEDIR)
.PHONY: uninstall
uninstall:
$(RM) $(DESTDIR)$(LIBDIR)/libzstd.a
$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT)
$(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR)
$(RM) $(DESTDIR)$(LIBDIR)/$(LIBZSTD)
$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libzstd.pc
$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h
$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_errors.h
$(RM) $(DESTDIR)$(INCLUDEDIR)/zdict.h
@echo zstd libraries successfully uninstalled
endif

View File

@@ -1,224 +0,0 @@
Zstandard library files
================================
The __lib__ directory is split into several sub-directories,
in order to make it easier to select or exclude features.
#### Building
`Makefile` script is provided, supporting [Makefile conventions](https://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html#Makefile-Conventions),
including commands variables, staged install, directory variables and standard targets.
- `make` : generates both static and dynamic libraries
- `make install` : install libraries and headers in target system directories
`libzstd` default scope is pretty large, including compression, decompression, dictionary builder,
and support for decoding legacy formats >= v0.5.0.
The scope can be reduced on demand (see paragraph _modular build_).
#### Multithreading support
When building with `make`, by default the dynamic library is multithreaded and static library is single-threaded (for compatibility reasons).
Enabling multithreading requires 2 conditions :
- set build macro `ZSTD_MULTITHREAD` (`-DZSTD_MULTITHREAD` for `gcc`)
- for POSIX systems : compile with pthread (`-pthread` compilation flag for `gcc`)
For convenience, we provide a build target to generate multi and single threaded libraries:
- Force enable multithreading on both dynamic and static libraries by appending `-mt` to the target, e.g. `make lib-mt`.
- Force disable multithreading on both dynamic and static libraries by appending `-nomt` to the target, e.g. `make lib-nomt`.
- By default, as mentioned before, dynamic library is multithreaded, and static library is single-threaded, e.g. `make lib`.
When linking a POSIX program with a multithreaded version of `libzstd`,
note that it's necessary to invoke the `-pthread` flag during link stage.
Multithreading capabilities are exposed
via the [advanced API defined in `lib/zstd.h`](https://github.com/facebook/zstd/blob/v1.4.3/lib/zstd.h#L351).
#### API
Zstandard's stable API is exposed within [lib/zstd.h](zstd.h).
#### Advanced API
Optional advanced features are exposed via :
- `lib/zstd_errors.h` : translates `size_t` function results
into a `ZSTD_ErrorCode`, for accurate error handling.
- `ZSTD_STATIC_LINKING_ONLY` : if this macro is defined _before_ including `zstd.h`,
it unlocks access to the experimental API,
exposed in the second part of `zstd.h`.
All definitions in the experimental APIs are unstable,
they may still change in the future, or even be removed.
As a consequence, experimental definitions shall ___never be used with dynamic library___ !
Only static linking is allowed.
#### Modular build
It's possible to compile only a limited set of features within `libzstd`.
The file structure is designed to make this selection manually achievable for any build system :
- Directory `lib/common` is always required, for all variants.
- Compression source code lies in `lib/compress`
- Decompression source code lies in `lib/decompress`
- It's possible to include only `compress` or only `decompress`, they don't depend on each other.
- `lib/dictBuilder` : makes it possible to generate dictionaries from a set of samples.
The API is exposed in `lib/dictBuilder/zdict.h`.
This module depends on both `lib/common` and `lib/compress` .
- `lib/legacy` : makes it possible to decompress legacy zstd formats, starting from `v0.1.0`.
This module depends on `lib/common` and `lib/decompress`.
To enable this feature, define `ZSTD_LEGACY_SUPPORT` during compilation.
Specifying a number limits versions supported to that version onward.
For example, `ZSTD_LEGACY_SUPPORT=2` means : "support legacy formats >= v0.2.0".
Conversely, `ZSTD_LEGACY_SUPPORT=0` means "do __not__ support legacy formats".
By default, this build macro is set as `ZSTD_LEGACY_SUPPORT=5`.
Decoding supported legacy format is a transparent capability triggered within decompression functions.
It's also allowed to invoke legacy API directly, exposed in `lib/legacy/zstd_legacy.h`.
Each version does also provide its own set of advanced API.
For example, advanced API for version `v0.4` is exposed in `lib/legacy/zstd_v04.h` .
- While invoking `make libzstd`, it's possible to define build macros
`ZSTD_LIB_COMPRESSION, ZSTD_LIB_DECOMPRESSION`, `ZSTD_LIB_DICTBUILDER`,
and `ZSTD_LIB_DEPRECATED` as `0` to forgo compilation of the
corresponding features. This will also disable compilation of all
dependencies (e.g. `ZSTD_LIB_COMPRESSION=0` will also disable
dictBuilder).
- There are a number of options that can help minimize the binary size of
`libzstd`.
The first step is to select the components needed (using the above-described
`ZSTD_LIB_COMPRESSION` etc.).
The next step is to set `ZSTD_LIB_MINIFY` to `1` when invoking `make`. This
disables various optional components and changes the compilation flags to
prioritize space-saving.
Detailed options: Zstandard's code and build environment is set up by default
to optimize above all else for performance. In pursuit of this goal, Zstandard
makes significant trade-offs in code size. For example, Zstandard often has
more than one implementation of a particular component, with each
implementation optimized for different scenarios. For example, the Huffman
decoder has complementary implementations that decode the stream one symbol at
a time or two symbols at a time. Zstd normally includes both (and dispatches
between them at runtime), but by defining `HUF_FORCE_DECOMPRESS_X1` or
`HUF_FORCE_DECOMPRESS_X2`, you can force the use of one or the other, avoiding
compilation of the other. Similarly, `ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT`
and `ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG` force the compilation and use of
only one or the other of two decompression implementations. The smallest
binary is achieved by using `HUF_FORCE_DECOMPRESS_X1` and
`ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT` (implied by `ZSTD_LIB_MINIFY`).
For squeezing the last ounce of size out, you can also define
`ZSTD_NO_INLINE`, which disables inlining, and `ZSTD_STRIP_ERROR_STRINGS`,
which removes the error messages that are otherwise returned by
`ZSTD_getErrorName` (implied by `ZSTD_LIB_MINIFY`).
Finally, when integrating into your application, make sure you're doing link-
time optimization and unused symbol garbage collection (via some combination of,
e.g., `-flto`, `-ffat-lto-objects`, `-fuse-linker-plugin`,
`-ffunction-sections`, `-fdata-sections`, `-fmerge-all-constants`,
`-Wl,--gc-sections`, `-Wl,-z,norelro`, and an archiver that understands
the compiler's intermediate representation, e.g., `AR=gcc-ar`). Consult your
compiler's documentation.
- While invoking `make libzstd`, the build macro `ZSTD_LEGACY_MULTITHREADED_API=1`
will expose the deprecated `ZSTDMT` API exposed by `zstdmt_compress.h` in
the shared library, which is now hidden by default.
- The build macro `DYNAMIC_BMI2` can be set to 1 or 0 in order to generate binaries
which can detect at runtime the presence of BMI2 instructions, and use them only if present.
These instructions contribute to better performance, notably on the decoder side.
By default, this feature is automatically enabled on detecting
the right instruction set (x64) and compiler (clang or gcc >= 5).
It's obviously disabled for different cpus,
or when BMI2 instruction set is _required_ by the compiler command line
(in this case, only the BMI2 code path is generated).
Setting this macro will either force to generate the BMI2 dispatcher (1)
or prevent it (0). It overrides automatic detection.
- The build macro `ZSTD_NO_UNUSED_FUNCTIONS` can be defined to hide the definitions of functions
that zstd does not use. Not all unused functions are hidden, but they can be if needed.
Currently, this macro will hide function definitions in FSE and HUF that use an excessive
amount of stack space.
- The build macro `ZSTD_NO_INTRINSICS` can be defined to disable all explicit intrinsics.
Compiler builtins are still used.
- The build macro `ZSTD_DECODER_INTERNAL_BUFFER` can be set to control
the amount of extra memory used during decompression to store literals.
This defaults to 64kB. Reducing this value reduces the memory footprint of
`ZSTD_DCtx` decompression contexts,
but might also result in a small decompression speed cost.
- The C compiler macros `ZSTDLIB_VISIBLE`, `ZSTDERRORLIB_VISIBLE` and `ZDICTLIB_VISIBLE`
can be overridden to control the visibility of zstd's API. Additionally,
`ZSTDLIB_STATIC_API` and `ZDICTLIB_STATIC_API` can be overridden to control the visibility
of zstd's static API. Specifically, it can be set to `ZSTDLIB_HIDDEN` to hide the symbols
from the shared library. These macros default to `ZSTDLIB_VISIBILITY`,
`ZSTDERRORLIB_VSIBILITY`, and `ZDICTLIB_VISIBILITY` if unset, for backwards compatibility
with the old macro names.
#### Windows : using MinGW+MSYS to create DLL
DLL can be created using MinGW+MSYS with the `make libzstd` command.
This command creates `dll\libzstd.dll` and the import library `dll\libzstd.lib`.
The import library is only required with Visual C++.
The header file `zstd.h` and the dynamic library `dll\libzstd.dll` are required to
compile a project using gcc/MinGW.
The dynamic library has to be added to linking options.
It means that if a project that uses ZSTD consists of a single `test-dll.c`
file it should be linked with `dll\libzstd.dll`. For example:
```
gcc $(CFLAGS) -Iinclude/ test-dll.c -o test-dll dll\libzstd.dll
```
The compiled executable will require ZSTD DLL which is available at `dll\libzstd.dll`.
#### Advanced Build options
The build system requires a hash function in order to
separate object files created with different compilation flags.
By default, it tries to use `md5sum` or equivalent.
The hash function can be manually switched by setting the `HASH` variable.
For example : `make HASH=xxhsum`
The hash function needs to generate at least 64-bit using hexadecimal format.
When no hash function is found,
the Makefile just generates all object files into the same default directory,
irrespective of compilation flags.
This functionality only matters if `libzstd` is compiled multiple times
with different build flags.
The build directory, where object files are stored
can also be manually controlled using variable `BUILD_DIR`,
for example `make BUILD_DIR=objectDir/v1`.
In which case, the hash function doesn't matter.
#### Deprecated API
Obsolete API on their way out are stored in directory `lib/deprecated`.
At this stage, it contains older streaming prototypes, in `lib/deprecated/zbuff.h`.
These prototypes will be removed in some future version.
Consider migrating code towards supported streaming API exposed in `zstd.h`.
#### Miscellaneous
The other files are not source code. There are :
- `BUCK` : support for `buck` build system (https://buckbuild.com/)
- `Makefile` : `make` script to build and install zstd library (static and dynamic)
- `README.md` : this file
- `dll/` : resources directory for Windows compilation
- `libzstd.pc.in` : script for `pkg-config` (used in `make install`)

View File

@@ -1,175 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef ZSTD_BITS_H
#define ZSTD_BITS_H
#include "mem.h"
MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val)
{
assert(val != 0);
{
static const int DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3,
30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7,
26, 12, 18, 6, 11, 5, 10, 9};
return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27];
}
}
MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val)
{
assert(val != 0);
# if defined(_MSC_VER)
# if STATIC_BMI2 == 1
return _tzcnt_u32(val);
# else
if (val != 0) {
unsigned long r;
_BitScanForward(&r, val);
return (unsigned)r;
} else {
/* Should not reach this code path */
__assume(0);
}
# endif
# elif defined(__GNUC__) && (__GNUC__ >= 4)
return (unsigned)__builtin_ctz(val);
# else
return ZSTD_countTrailingZeros32_fallback(val);
# endif
}
MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) {
assert(val != 0);
{
static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29,
11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7,
19, 27, 23, 6, 26, 5, 4, 31};
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27];
}
}
MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val)
{
assert(val != 0);
# if defined(_MSC_VER)
# if STATIC_BMI2 == 1
return _lzcnt_u32(val);
# else
if (val != 0) {
unsigned long r;
_BitScanReverse(&r, val);
return (unsigned)(31 - r);
} else {
/* Should not reach this code path */
__assume(0);
}
# endif
# elif defined(__GNUC__) && (__GNUC__ >= 4)
return (unsigned)__builtin_clz(val);
# else
return ZSTD_countLeadingZeros32_fallback(val);
# endif
}
MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val)
{
assert(val != 0);
# if defined(_MSC_VER) && defined(_WIN64)
# if STATIC_BMI2 == 1
return _tzcnt_u64(val);
# else
if (val != 0) {
unsigned long r;
_BitScanForward64(&r, val);
return (unsigned)r;
} else {
/* Should not reach this code path */
__assume(0);
}
# endif
# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__)
return (unsigned)__builtin_ctzll(val);
# else
{
U32 mostSignificantWord = (U32)(val >> 32);
U32 leastSignificantWord = (U32)val;
if (leastSignificantWord == 0) {
return 32 + ZSTD_countTrailingZeros32(mostSignificantWord);
} else {
return ZSTD_countTrailingZeros32(leastSignificantWord);
}
}
# endif
}
MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val)
{
assert(val != 0);
# if defined(_MSC_VER) && defined(_WIN64)
# if STATIC_BMI2 == 1
return _lzcnt_u64(val);
# else
if (val != 0) {
unsigned long r;
_BitScanReverse64(&r, val);
return (unsigned)(63 - r);
} else {
/* Should not reach this code path */
__assume(0);
}
# endif
# elif defined(__GNUC__) && (__GNUC__ >= 4)
return (unsigned)(__builtin_clzll(val));
# else
{
U32 mostSignificantWord = (U32)(val >> 32);
U32 leastSignificantWord = (U32)val;
if (mostSignificantWord == 0) {
return 32 + ZSTD_countLeadingZeros32(leastSignificantWord);
} else {
return ZSTD_countLeadingZeros32(mostSignificantWord);
}
}
# endif
}
MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val)
{
if (MEM_isLittleEndian()) {
if (MEM_64bits()) {
return ZSTD_countTrailingZeros64((U64)val) >> 3;
} else {
return ZSTD_countTrailingZeros32((U32)val) >> 3;
}
} else { /* Big Endian CPU */
if (MEM_64bits()) {
return ZSTD_countLeadingZeros64((U64)val) >> 3;
} else {
return ZSTD_countLeadingZeros32((U32)val) >> 3;
}
}
}
MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */
{
assert(val != 0);
return 31 - ZSTD_countLeadingZeros32(val);
}
#endif /* ZSTD_BITS_H */

View File

@@ -1,437 +0,0 @@
/* ******************************************************************
* bitstream
* Part of FSE library
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
****************************************************************** */
#ifndef BITSTREAM_H_MODULE
#define BITSTREAM_H_MODULE
#if defined (__cplusplus)
extern "C" {
#endif
/*
* This API consists of small unitary functions, which must be inlined for best performance.
* Since link-time-optimization is not available for all compilers,
* these functions are defined into a .h to be included.
*/
/*-****************************************
* Dependencies
******************************************/
#include "mem.h" /* unaligned access routines */
#include "compiler.h" /* UNLIKELY() */
#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
#include "error_private.h" /* error codes and messages */
#include "bits.h" /* ZSTD_highbit32 */
/*=========================================
* Target specific
=========================================*/
#ifndef ZSTD_NO_INTRINSICS
# if (defined(__BMI__) || defined(__BMI2__)) && defined(__GNUC__)
# include <immintrin.h> /* support for bextr (experimental)/bzhi */
# elif defined(__ICCARM__)
# include <intrinsics.h>
# endif
#endif
#define STREAM_ACCUMULATOR_MIN_32 25
#define STREAM_ACCUMULATOR_MIN_64 57
#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
/*-******************************************
* bitStream encoding API (write forward)
********************************************/
/* bitStream can mix input from multiple sources.
* A critical property of these streams is that they encode and decode in **reverse** direction.
* So the first bit sequence you add will be the last to be read, like a LIFO stack.
*/
typedef struct {
size_t bitContainer;
unsigned bitPos;
char* startPtr;
char* ptr;
char* endPtr;
} BIT_CStream_t;
MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
/* Start with initCStream, providing the size of buffer to write into.
* bitStream will never write outside of this buffer.
* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
*
* bits are first added to a local register.
* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
* Writing data into memory is an explicit operation, performed by the flushBits function.
* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
* After a flushBits, a maximum of 7 bits might still be stored into local register.
*
* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
*
* Last operation is to close the bitStream.
* The function returns the final size of CStream in bytes.
* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
*/
/*-********************************************
* bitStream decoding API (read backward)
**********************************************/
typedef struct {
size_t bitContainer;
unsigned bitsConsumed;
const char* ptr;
const char* start;
const char* limitPtr;
} BIT_DStream_t;
typedef enum { BIT_DStream_unfinished = 0,
BIT_DStream_endOfBuffer = 1,
BIT_DStream_completed = 2,
BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
/* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
/* Start by invoking BIT_initDStream().
* A chunk of the bitStream is then stored into a local register.
* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
* You can then retrieve bitFields stored into the local register, **in reverse order**.
* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
* Otherwise, it can be less than that, so proceed accordingly.
* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
*/
/*-****************************************
* unsafe API
******************************************/
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
/* unsafe version; does not check buffer overflow */
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
/* faster, but works only if nbBits >= 1 */
/*===== Local Constants =====*/
static const unsigned BIT_mask[] = {
0, 1, 3, 7, 0xF, 0x1F,
0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF,
0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
/*-**************************************************************
* bitStream encoding
****************************************************************/
/*! BIT_initCStream() :
* `dstCapacity` must be > sizeof(size_t)
* @return : 0 if success,
* otherwise an error code (can be tested using ERR_isError()) */
MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
void* startPtr, size_t dstCapacity)
{
bitC->bitContainer = 0;
bitC->bitPos = 0;
bitC->startPtr = (char*)startPtr;
bitC->ptr = bitC->startPtr;
bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
return 0;
}
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
{
#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS)
return _bzhi_u64(bitContainer, nbBits);
#else
assert(nbBits < BIT_MASK_SIZE);
return bitContainer & BIT_mask[nbBits];
#endif
}
/*! BIT_addBits() :
* can add up to 31 bits into `bitC`.
* Note : does not check for register overflow ! */
MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
size_t value, unsigned nbBits)
{
DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32);
assert(nbBits < BIT_MASK_SIZE);
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
bitC->bitContainer |= BIT_getLowerBits(value, nbBits) << bitC->bitPos;
bitC->bitPos += nbBits;
}
/*! BIT_addBitsFast() :
* works only if `value` is _clean_,
* meaning all high bits above nbBits are 0 */
MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
size_t value, unsigned nbBits)
{
assert((value>>nbBits) == 0);
assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
bitC->bitContainer |= value << bitC->bitPos;
bitC->bitPos += nbBits;
}
/*! BIT_flushBitsFast() :
* assumption : bitContainer has not overflowed
* unsafe version; does not check buffer overflow */
MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
{
size_t const nbBytes = bitC->bitPos >> 3;
assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
assert(bitC->ptr <= bitC->endPtr);
MEM_writeLEST(bitC->ptr, bitC->bitContainer);
bitC->ptr += nbBytes;
bitC->bitPos &= 7;
bitC->bitContainer >>= nbBytes*8;
}
/*! BIT_flushBits() :
* assumption : bitContainer has not overflowed
* safe version; check for buffer overflow, and prevents it.
* note : does not signal buffer overflow.
* overflow will be revealed later on using BIT_closeCStream() */
MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
{
size_t const nbBytes = bitC->bitPos >> 3;
assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
assert(bitC->ptr <= bitC->endPtr);
MEM_writeLEST(bitC->ptr, bitC->bitContainer);
bitC->ptr += nbBytes;
if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
bitC->bitPos &= 7;
bitC->bitContainer >>= nbBytes*8;
}
/*! BIT_closeCStream() :
* @return : size of CStream, in bytes,
* or 0 if it could not fit into dstBuffer */
MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
{
BIT_addBitsFast(bitC, 1, 1); /* endMark */
BIT_flushBits(bitC);
if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
}
/*-********************************************************
* bitStream decoding
**********************************************************/
/*! BIT_initDStream() :
* Initialize a BIT_DStream_t.
* `bitD` : a pointer to an already allocated BIT_DStream_t structure.
* `srcSize` must be the *exact* size of the bitStream, in bytes.
* @return : size of stream (== srcSize), or an errorCode if a problem is detected
*/
MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
{
if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
bitD->start = (const char*)srcBuffer;
bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
bitD->bitContainer = MEM_readLEST(bitD->ptr);
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
} else {
bitD->ptr = bitD->start;
bitD->bitContainer = *(const BYTE*)(bitD->start);
switch(srcSize)
{
case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
ZSTD_FALLTHROUGH;
case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
ZSTD_FALLTHROUGH;
case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
ZSTD_FALLTHROUGH;
case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
ZSTD_FALLTHROUGH;
case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
ZSTD_FALLTHROUGH;
case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
ZSTD_FALLTHROUGH;
default: break;
}
{ BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0;
if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */
}
bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
}
return srcSize;
}
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
{
return bitContainer >> start;
}
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
{
U32 const regMask = sizeof(bitContainer)*8 - 1;
/* if start > regMask, bitstream is corrupted, and result is undefined */
assert(nbBits < BIT_MASK_SIZE);
/* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better
* than accessing memory. When bmi2 instruction is not present, we consider
* such cpus old (pre-Haswell, 2013) and their performance is not of that
* importance.
*/
#if defined(__x86_64__) || defined(_M_X86)
return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1);
#else
return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
#endif
}
/*! BIT_lookBits() :
* Provides next n bits from local register.
* local register is not modified.
* On 32-bits, maxNbBits==24.
* On 64-bits, maxNbBits==56.
* @return : value extracted */
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
{
/* arbitrate between double-shift and shift+mask */
#if 1
/* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
* bitstream is likely corrupted, and result is undefined */
return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
#else
/* this code path is slower on my os-x laptop */
U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask);
#endif
}
/*! BIT_lookBitsFast() :
* unsafe version; only works if nbBits >= 1 */
MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
{
U32 const regMask = sizeof(bitD->bitContainer)*8 - 1;
assert(nbBits >= 1);
return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask);
}
MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
{
bitD->bitsConsumed += nbBits;
}
/*! BIT_readBits() :
* Read (consume) next n bits from local register and update.
* Pay attention to not read more than nbBits contained into local register.
* @return : extracted value. */
MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits)
{
size_t const value = BIT_lookBits(bitD, nbBits);
BIT_skipBits(bitD, nbBits);
return value;
}
/*! BIT_readBitsFast() :
* unsafe version; only works if nbBits >= 1 */
MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits)
{
size_t const value = BIT_lookBitsFast(bitD, nbBits);
assert(nbBits >= 1);
BIT_skipBits(bitD, nbBits);
return value;
}
/*! BIT_reloadDStreamFast() :
* Similar to BIT_reloadDStream(), but with two differences:
* 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold!
* 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this
* point you must use BIT_reloadDStream() to reload.
*/
MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD)
{
if (UNLIKELY(bitD->ptr < bitD->limitPtr))
return BIT_DStream_overflow;
assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8);
bitD->ptr -= bitD->bitsConsumed >> 3;
bitD->bitsConsumed &= 7;
bitD->bitContainer = MEM_readLEST(bitD->ptr);
return BIT_DStream_unfinished;
}
/*! BIT_reloadDStream() :
* Refill `bitD` from buffer previously set in BIT_initDStream() .
* This function is safe, it guarantees it will not read beyond src buffer.
* @return : status of `BIT_DStream_t` internal register.
* when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */
MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
{
if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */
return BIT_DStream_overflow;
if (bitD->ptr >= bitD->limitPtr) {
return BIT_reloadDStreamFast(bitD);
}
if (bitD->ptr == bitD->start) {
if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
return BIT_DStream_completed;
}
/* start < ptr < limitPtr */
{ U32 nbBytes = bitD->bitsConsumed >> 3;
BIT_DStream_status result = BIT_DStream_unfinished;
if (bitD->ptr - nbBytes < bitD->start) {
nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
result = BIT_DStream_endOfBuffer;
}
bitD->ptr -= nbBytes;
bitD->bitsConsumed -= nbBytes*8;
bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */
return result;
}
}
/*! BIT_endOfDStream() :
* @return : 1 if DStream has _exactly_ reached its end (all bits consumed).
*/
MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
{
return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
}
#if defined (__cplusplus)
}
#endif
#endif /* BITSTREAM_H_MODULE */

View File

@@ -1,343 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef ZSTD_COMPILER_H
#define ZSTD_COMPILER_H
#include "portability_macros.h"
/*-*******************************************************
* Compiler specifics
*********************************************************/
/* force inlining */
#if !defined(ZSTD_NO_INLINE)
#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
# define INLINE_KEYWORD inline
#else
# define INLINE_KEYWORD
#endif
#if defined(__GNUC__) || defined(__ICCARM__)
# define FORCE_INLINE_ATTR __attribute__((always_inline))
#elif defined(_MSC_VER)
# define FORCE_INLINE_ATTR __forceinline
#else
# define FORCE_INLINE_ATTR
#endif
#else
#define INLINE_KEYWORD
#define FORCE_INLINE_ATTR
#endif
/**
On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC).
This explicitly marks such functions as __cdecl so that the code will still compile
if a CC other than __cdecl has been made the default.
*/
#if defined(_MSC_VER)
# define WIN_CDECL __cdecl
#else
# define WIN_CDECL
#endif
/**
* FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
* parameters. They must be inlined for the compiler to eliminate the constant
* branches.
*/
#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR
/**
* HINT_INLINE is used to help the compiler generate better code. It is *not*
* used for "templates", so it can be tweaked based on the compilers
* performance.
*
* gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the
* always_inline attribute.
*
* clang up to 5.0.0 (trunk) benefit tremendously from the always_inline
* attribute.
*/
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
# define HINT_INLINE static INLINE_KEYWORD
#else
# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR
#endif
/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
#if defined(__GNUC__)
# define UNUSED_ATTR __attribute__((unused))
#else
# define UNUSED_ATTR
#endif
/* force no inlining */
#ifdef _MSC_VER
# define FORCE_NOINLINE static __declspec(noinline)
#else
# if defined(__GNUC__) || defined(__ICCARM__)
# define FORCE_NOINLINE static __attribute__((__noinline__))
# else
# define FORCE_NOINLINE static
# endif
#endif
/* target attribute */
#if defined(__GNUC__) || defined(__ICCARM__)
# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
#else
# define TARGET_ATTRIBUTE(target)
#endif
/* Target attribute for BMI2 dynamic dispatch.
* Enable lzcnt, bmi, and bmi2.
* We test for bmi1 & bmi2. lzcnt is included in bmi1.
*/
#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2")
/* prefetch
* can be disabled, by declaring NO_PREFETCH build macro */
#if defined(NO_PREFETCH)
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
#else
# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */
# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
# elif defined(__aarch64__)
# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
# else
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
# endif
#endif /* NO_PREFETCH */
#define CACHELINE_SIZE 64
#define PREFETCH_AREA(p, s) { \
const char* const _ptr = (const char*)(p); \
size_t const _size = (size_t)(s); \
size_t _pos; \
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
PREFETCH_L2(_ptr + _pos); \
} \
}
/* vectorization
* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
* and some compilers, like Intel ICC and MCST LCC, do not support it at all. */
#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__)
# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5)
# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
# else
# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")")
# endif
#else
# define DONT_VECTORIZE
#endif
/* Tell the compiler that a branch is likely or unlikely.
* Only use these macros if it causes the compiler to generate better code.
* If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc
* and clang, please do.
*/
#if defined(__GNUC__)
#define LIKELY(x) (__builtin_expect((x), 1))
#define UNLIKELY(x) (__builtin_expect((x), 0))
#else
#define LIKELY(x) (x)
#define UNLIKELY(x) (x)
#endif
#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
# define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); }
#else
# define ZSTD_UNREACHABLE { assert(0); }
#endif
/* disable warnings */
#ifdef _MSC_VER /* Visual Studio */
# include <intrin.h> /* For Visual 2005 */
# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */
# pragma warning(disable : 4324) /* disable: C4324: padded structure */
#endif
/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/
#ifndef STATIC_BMI2
# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86))
# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2
# define STATIC_BMI2 1
# endif
# elif defined(__BMI2__) && defined(__x86_64__) && defined(__GNUC__)
# define STATIC_BMI2 1
# endif
#endif
#ifndef STATIC_BMI2
#define STATIC_BMI2 0
#endif
/* compile time determination of SIMD support */
#if !defined(ZSTD_NO_INTRINSICS)
# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2))
# define ZSTD_ARCH_X86_SSE2
# endif
# if defined(__ARM_NEON) || defined(_M_ARM64)
# define ZSTD_ARCH_ARM_NEON
# endif
#
# if defined(ZSTD_ARCH_X86_SSE2)
# include <emmintrin.h>
# elif defined(ZSTD_ARCH_ARM_NEON)
# include <arm_neon.h>
# endif
#endif
/* C-language Attributes are added in C23. */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute)
# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
#else
# define ZSTD_HAS_C_ATTRIBUTE(x) 0
#endif
/* Only use C++ attributes in C++. Some compilers report support for C++
* attributes when compiling with C.
*/
#if defined(__cplusplus) && defined(__has_cpp_attribute)
# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0
#endif
/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute.
* - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough
* - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough
* - Else: __attribute__((__fallthrough__))
*/
#ifndef ZSTD_FALLTHROUGH
# if ZSTD_HAS_C_ATTRIBUTE(fallthrough)
# define ZSTD_FALLTHROUGH [[fallthrough]]
# elif ZSTD_HAS_CPP_ATTRIBUTE(fallthrough)
# define ZSTD_FALLTHROUGH [[fallthrough]]
# elif __has_attribute(__fallthrough__)
/* Leading semicolon is to satisfy gcc-11 with -pedantic. Without the semicolon
* gcc complains about: a label can only be part of a statement and a declaration is not a statement.
*/
# define ZSTD_FALLTHROUGH ; __attribute__((__fallthrough__))
# else
# define ZSTD_FALLTHROUGH
# endif
#endif
/*-**************************************************************
* Alignment check
*****************************************************************/
/* this test was initially positioned in mem.h,
* but this file is removed (or replaced) for linux kernel
* so it's now hosted in compiler.h,
* which remains valid for both user & kernel spaces.
*/
#ifndef ZSTD_ALIGNOF
# if defined(__GNUC__) || defined(_MSC_VER)
/* covers gcc, clang & MSVC */
/* note : this section must come first, before C11,
* due to a limitation in the kernel source generator */
# define ZSTD_ALIGNOF(T) __alignof(T)
# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
/* C11 support */
# include <stdalign.h>
# define ZSTD_ALIGNOF(T) alignof(T)
# else
/* No known support for alignof() - imperfect backup */
# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T))
# endif
#endif /* ZSTD_ALIGNOF */
/*-**************************************************************
* Sanitizer
*****************************************************************/
#if ZSTD_MEMORY_SANITIZER
/* Not all platforms that support msan provide sanitizers/msan_interface.h.
* We therefore declare the functions we need ourselves, rather than trying to
* include the header file... */
#include <stddef.h> /* size_t */
#define ZSTD_DEPS_NEED_STDINT
#include "zstd_deps.h" /* intptr_t */
/* Make memory region fully initialized (without changing its contents). */
void __msan_unpoison(const volatile void *a, size_t size);
/* Make memory region fully uninitialized (without changing its contents).
This is a legacy interface that does not update origin information. Use
__msan_allocated_memory() instead. */
void __msan_poison(const volatile void *a, size_t size);
/* Returns the offset of the first (at least partially) poisoned byte in the
memory range, or -1 if the whole range is good. */
intptr_t __msan_test_shadow(const volatile void *x, size_t size);
#endif
#if ZSTD_ADDRESS_SANITIZER
/* Not all platforms that support asan provide sanitizers/asan_interface.h.
* We therefore declare the functions we need ourselves, rather than trying to
* include the header file... */
#include <stddef.h> /* size_t */
/**
* Marks a memory region (<c>[addr, addr+size)</c>) as unaddressable.
*
* This memory must be previously allocated by your program. Instrumented
* code is forbidden from accessing addresses in this region until it is
* unpoisoned. This function is not guaranteed to poison the entire region -
* it could poison only a subregion of <c>[addr, addr+size)</c> due to ASan
* alignment restrictions.
*
* \note This function is not thread-safe because no two threads can poison or
* unpoison memory in the same memory region simultaneously.
*
* \param addr Start of memory region.
* \param size Size of memory region. */
void __asan_poison_memory_region(void const volatile *addr, size_t size);
/**
* Marks a memory region (<c>[addr, addr+size)</c>) as addressable.
*
* This memory must be previously allocated by your program. Accessing
* addresses in this region is allowed until this region is poisoned again.
* This function could unpoison a super-region of <c>[addr, addr+size)</c> due
* to ASan alignment restrictions.
*
* \note This function is not thread-safe because no two threads can
* poison or unpoison memory in the same memory region simultaneously.
*
* \param addr Start of memory region.
* \param size Size of memory region. */
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
#endif
#endif /* ZSTD_COMPILER_H */

View File

@@ -1,213 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef ZSTD_COMMON_CPU_H
#define ZSTD_COMMON_CPU_H
/**
* Implementation taken from folly/CpuId.h
* https://github.com/facebook/folly/blob/master/folly/CpuId.h
*/
#include "mem.h"
#ifdef _MSC_VER
#include <intrin.h>
#endif
typedef struct {
U32 f1c;
U32 f1d;
U32 f7b;
U32 f7c;
} ZSTD_cpuid_t;
MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
U32 f1c = 0;
U32 f1d = 0;
U32 f7b = 0;
U32 f7c = 0;
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
int reg[4];
__cpuid((int*)reg, 0);
{
int const n = reg[0];
if (n >= 1) {
__cpuid((int*)reg, 1);
f1c = (U32)reg[2];
f1d = (U32)reg[3];
}
if (n >= 7) {
__cpuidex((int*)reg, 7, 0);
f7b = (U32)reg[1];
f7c = (U32)reg[2];
}
}
#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
/* The following block like the normal cpuid branch below, but gcc
* reserves ebx for use of its pic register so we must specially
* handle the save and restore to avoid clobbering the register
*/
U32 n;
__asm__(
"pushl %%ebx\n\t"
"cpuid\n\t"
"popl %%ebx\n\t"
: "=a"(n)
: "a"(0)
: "ecx", "edx");
if (n >= 1) {
U32 f1a;
__asm__(
"pushl %%ebx\n\t"
"cpuid\n\t"
"popl %%ebx\n\t"
: "=a"(f1a), "=c"(f1c), "=d"(f1d)
: "a"(1));
}
if (n >= 7) {
__asm__(
"pushl %%ebx\n\t"
"cpuid\n\t"
"movl %%ebx, %%eax\n\t"
"popl %%ebx"
: "=a"(f7b), "=c"(f7c)
: "a"(7), "c"(0)
: "edx");
}
#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
U32 n;
__asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
if (n >= 1) {
U32 f1a;
__asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
}
if (n >= 7) {
U32 f7a;
__asm__("cpuid"
: "=a"(f7a), "=b"(f7b), "=c"(f7c)
: "a"(7), "c"(0)
: "edx");
}
#endif
{
ZSTD_cpuid_t cpuid;
cpuid.f1c = f1c;
cpuid.f1d = f1d;
cpuid.f7b = f7b;
cpuid.f7c = f7c;
return cpuid;
}
}
#define X(name, r, bit) \
MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \
return ((cpuid.r) & (1U << bit)) != 0; \
}
/* cpuid(1): Processor Info and Feature Bits. */
#define C(name, bit) X(name, f1c, bit)
C(sse3, 0)
C(pclmuldq, 1)
C(dtes64, 2)
C(monitor, 3)
C(dscpl, 4)
C(vmx, 5)
C(smx, 6)
C(eist, 7)
C(tm2, 8)
C(ssse3, 9)
C(cnxtid, 10)
C(fma, 12)
C(cx16, 13)
C(xtpr, 14)
C(pdcm, 15)
C(pcid, 17)
C(dca, 18)
C(sse41, 19)
C(sse42, 20)
C(x2apic, 21)
C(movbe, 22)
C(popcnt, 23)
C(tscdeadline, 24)
C(aes, 25)
C(xsave, 26)
C(osxsave, 27)
C(avx, 28)
C(f16c, 29)
C(rdrand, 30)
#undef C
#define D(name, bit) X(name, f1d, bit)
D(fpu, 0)
D(vme, 1)
D(de, 2)
D(pse, 3)
D(tsc, 4)
D(msr, 5)
D(pae, 6)
D(mce, 7)
D(cx8, 8)
D(apic, 9)
D(sep, 11)
D(mtrr, 12)
D(pge, 13)
D(mca, 14)
D(cmov, 15)
D(pat, 16)
D(pse36, 17)
D(psn, 18)
D(clfsh, 19)
D(ds, 21)
D(acpi, 22)
D(mmx, 23)
D(fxsr, 24)
D(sse, 25)
D(sse2, 26)
D(ss, 27)
D(htt, 28)
D(tm, 29)
D(pbe, 31)
#undef D
/* cpuid(7): Extended Features. */
#define B(name, bit) X(name, f7b, bit)
B(bmi1, 3)
B(hle, 4)
B(avx2, 5)
B(smep, 7)
B(bmi2, 8)
B(erms, 9)
B(invpcid, 10)
B(rtm, 11)
B(mpx, 14)
B(avx512f, 16)
B(avx512dq, 17)
B(rdseed, 18)
B(adx, 19)
B(smap, 20)
B(avx512ifma, 21)
B(pcommit, 22)
B(clflushopt, 23)
B(clwb, 24)
B(avx512pf, 26)
B(avx512er, 27)
B(avx512cd, 28)
B(sha, 29)
B(avx512bw, 30)
B(avx512vl, 31)
#undef B
#define C(name, bit) X(name, f7c, bit)
C(prefetchwt1, 0)
C(avx512vbmi, 1)
#undef C
#undef X
#endif /* ZSTD_COMMON_CPU_H */

View File

@@ -1,24 +0,0 @@
/* ******************************************************************
* debug
* Part of FSE library
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
****************************************************************** */
/*
* This module only hosts one global variable
* which can be used to dynamically influence the verbosity of traces,
* such as DEBUGLOG and RAWLOG
*/
#include "debug.h"
int g_debuglevel = DEBUGLEVEL;

View File

@@ -1,107 +0,0 @@
/* ******************************************************************
* debug
* Part of FSE library
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
****************************************************************** */
/*
* The purpose of this header is to enable debug functions.
* They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,
* and DEBUG_STATIC_ASSERT() for compile-time.
*
* By default, DEBUGLEVEL==0, which means run-time debug is disabled.
*
* Level 1 enables assert() only.
* Starting level 2, traces can be generated and pushed to stderr.
* The higher the level, the more verbose the traces.
*
* It's possible to dynamically adjust level using variable g_debug_level,
* which is only declared if DEBUGLEVEL>=2,
* and is a global variable, not multi-thread protected (use with care)
*/
#ifndef DEBUG_H_12987983217
#define DEBUG_H_12987983217
#if defined (__cplusplus)
extern "C" {
#endif
/* static assert is triggered at compile time, leaving no runtime artefact.
* static assert only works with compile-time constants.
* Also, this variant can only be used inside a function. */
#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])
/* DEBUGLEVEL is expected to be defined externally,
* typically through compiler command line.
* Value must be a number. */
#ifndef DEBUGLEVEL
# define DEBUGLEVEL 0
#endif
/* recommended values for DEBUGLEVEL :
* 0 : release mode, no debug, all run-time checks disabled
* 1 : enables assert() only, no display
* 2 : reserved, for currently active debug path
* 3 : events once per object lifetime (CCtx, CDict, etc.)
* 4 : events once per frame
* 5 : events once per block
* 6 : events once per sequence (verbose)
* 7+: events at every position (*very* verbose)
*
* It's generally inconvenient to output traces > 5.
* In which case, it's possible to selectively trigger high verbosity levels
* by modifying g_debug_level.
*/
#if (DEBUGLEVEL>=1)
# define ZSTD_DEPS_NEED_ASSERT
# include "zstd_deps.h"
#else
# ifndef assert /* assert may be already defined, due to prior #include <assert.h> */
# define assert(condition) ((void)0) /* disable assert (default) */
# endif
#endif
#if (DEBUGLEVEL>=2)
# define ZSTD_DEPS_NEED_IO
# include "zstd_deps.h"
extern int g_debuglevel; /* the variable is only declared,
it actually lives in debug.c,
and is shared by the whole process.
It's not thread-safe.
It's useful when enabling very verbose levels
on selective conditions (such as position in src) */
# define RAWLOG(l, ...) { \
if (l<=g_debuglevel) { \
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
} }
# define DEBUGLOG(l, ...) { \
if (l<=g_debuglevel) { \
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
ZSTD_DEBUG_PRINT(" \n"); \
} }
#else
# define RAWLOG(l, ...) {} /* disabled */
# define DEBUGLOG(l, ...) {} /* disabled */
#endif
#if defined (__cplusplus)
}
#endif
#endif /* DEBUG_H_12987983217 */

View File

@@ -1,341 +0,0 @@
/* ******************************************************************
* Common functions of New Generation Entropy library
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
* - Public forum : https://groups.google.com/forum/#!forum/lz4c
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
****************************************************************** */
/* *************************************
* Dependencies
***************************************/
#include "mem.h"
#include "error_private.h" /* ERR_*, ERROR */
#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
#include "fse.h"
#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */
#include "huf.h"
#include "bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */
/*=== Version ===*/
unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
/*=== Error Management ===*/
unsigned FSE_isError(size_t code) { return ERR_isError(code); }
const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
unsigned HUF_isError(size_t code) { return ERR_isError(code); }
const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
/*-**************************************************************
* FSE NCount encoding-decoding
****************************************************************/
FORCE_INLINE_TEMPLATE
size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
const void* headerBuffer, size_t hbSize)
{
const BYTE* const istart = (const BYTE*) headerBuffer;
const BYTE* const iend = istart + hbSize;
const BYTE* ip = istart;
int nbBits;
int remaining;
int threshold;
U32 bitStream;
int bitCount;
unsigned charnum = 0;
unsigned const maxSV1 = *maxSVPtr + 1;
int previous0 = 0;
if (hbSize < 8) {
/* This function only works when hbSize >= 8 */
char buffer[8] = {0};
ZSTD_memcpy(buffer, headerBuffer, hbSize);
{ size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr,
buffer, sizeof(buffer));
if (FSE_isError(countSize)) return countSize;
if (countSize > hbSize) return ERROR(corruption_detected);
return countSize;
} }
assert(hbSize >= 8);
/* init */
ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */
bitStream = MEM_readLE32(ip);
nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
bitStream >>= 4;
bitCount = 4;
*tableLogPtr = nbBits;
remaining = (1<<nbBits)+1;
threshold = 1<<nbBits;
nbBits++;
for (;;) {
if (previous0) {
/* Count the number of repeats. Each time the
* 2-bit repeat code is 0b11 there is another
* repeat.
* Avoid UB by setting the high bit to 1.
*/
int repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1;
while (repeats >= 12) {
charnum += 3 * 12;
if (LIKELY(ip <= iend-7)) {
ip += 3;
} else {
bitCount -= (int)(8 * (iend - 7 - ip));
bitCount &= 31;
ip = iend - 4;
}
bitStream = MEM_readLE32(ip) >> bitCount;
repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1;
}
charnum += 3 * repeats;
bitStream >>= 2 * repeats;
bitCount += 2 * repeats;
/* Add the final repeat which isn't 0b11. */
assert((bitStream & 3) < 3);
charnum += bitStream & 3;
bitCount += 2;
/* This is an error, but break and return an error
* at the end, because returning out of a loop makes
* it harder for the compiler to optimize.
*/
if (charnum >= maxSV1) break;
/* We don't need to set the normalized count to 0
* because we already memset the whole buffer to 0.
*/
if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
assert((bitCount >> 3) <= 3); /* For first condition to work */
ip += bitCount>>3;
bitCount &= 7;
} else {
bitCount -= (int)(8 * (iend - 4 - ip));
bitCount &= 31;
ip = iend - 4;
}
bitStream = MEM_readLE32(ip) >> bitCount;
}
{
int const max = (2*threshold-1) - remaining;
int count;
if ((bitStream & (threshold-1)) < (U32)max) {
count = bitStream & (threshold-1);
bitCount += nbBits-1;
} else {
count = bitStream & (2*threshold-1);
if (count >= threshold) count -= max;
bitCount += nbBits;
}
count--; /* extra accuracy */
/* When it matters (small blocks), this is a
* predictable branch, because we don't use -1.
*/
if (count >= 0) {
remaining -= count;
} else {
assert(count == -1);
remaining += count;
}
normalizedCounter[charnum++] = (short)count;
previous0 = !count;
assert(threshold > 1);
if (remaining < threshold) {
/* This branch can be folded into the
* threshold update condition because we
* know that threshold > 1.
*/
if (remaining <= 1) break;
nbBits = ZSTD_highbit32(remaining) + 1;
threshold = 1 << (nbBits - 1);
}
if (charnum >= maxSV1) break;
if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
ip += bitCount>>3;
bitCount &= 7;
} else {
bitCount -= (int)(8 * (iend - 4 - ip));
bitCount &= 31;
ip = iend - 4;
}
bitStream = MEM_readLE32(ip) >> bitCount;
} }
if (remaining != 1) return ERROR(corruption_detected);
/* Only possible when there are too many zeros. */
if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall);
if (bitCount > 32) return ERROR(corruption_detected);
*maxSVPtr = charnum-1;
ip += (bitCount+7)>>3;
return ip-istart;
}
/* Avoids the FORCE_INLINE of the _body() function. */
static size_t FSE_readNCount_body_default(
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
const void* headerBuffer, size_t hbSize)
{
return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
}
#if DYNAMIC_BMI2
BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2(
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
const void* headerBuffer, size_t hbSize)
{
return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
}
#endif
size_t FSE_readNCount_bmi2(
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
const void* headerBuffer, size_t hbSize, int bmi2)
{
#if DYNAMIC_BMI2
if (bmi2) {
return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
}
#endif
(void)bmi2;
return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize);
}
size_t FSE_readNCount(
short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
const void* headerBuffer, size_t hbSize)
{
return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0);
}
/*! HUF_readStats() :
Read compact Huffman tree, saved by HUF_writeCTable().
`huffWeight` is destination buffer.
`rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
@return : size read from `src` , or an error Code .
Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
*/
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
U32* nbSymbolsPtr, U32* tableLogPtr,
const void* src, size_t srcSize)
{
U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32];
return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0);
}
FORCE_INLINE_TEMPLATE size_t
HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats,
U32* nbSymbolsPtr, U32* tableLogPtr,
const void* src, size_t srcSize,
void* workSpace, size_t wkspSize,
int bmi2)
{
U32 weightTotal;
const BYTE* ip = (const BYTE*) src;
size_t iSize;
size_t oSize;
if (!srcSize) return ERROR(srcSize_wrong);
iSize = ip[0];
/* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
if (iSize >= 128) { /* special header */
oSize = iSize - 127;
iSize = ((oSize+1)/2);
if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
if (oSize >= hwSize) return ERROR(corruption_detected);
ip += 1;
{ U32 n;
for (n=0; n<oSize; n+=2) {
huffWeight[n] = ip[n/2] >> 4;
huffWeight[n+1] = ip[n/2] & 15;
} } }
else { /* header compressed with FSE (normal case) */
if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
/* max (hwSize-1) values decoded, as last one is implied */
oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2);
if (FSE_isError(oSize)) return oSize;
}
/* collect weight stats */
ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
weightTotal = 0;
{ U32 n; for (n=0; n<oSize; n++) {
if (huffWeight[n] > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
rankStats[huffWeight[n]]++;
weightTotal += (1 << huffWeight[n]) >> 1;
} }
if (weightTotal == 0) return ERROR(corruption_detected);
/* get last non-null symbol weight (implied, total must be 2^n) */
{ U32 const tableLog = ZSTD_highbit32(weightTotal) + 1;
if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
*tableLogPtr = tableLog;
/* determine last weight */
{ U32 const total = 1 << tableLog;
U32 const rest = total - weightTotal;
U32 const verif = 1 << ZSTD_highbit32(rest);
U32 const lastWeight = ZSTD_highbit32(rest) + 1;
if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
huffWeight[oSize] = (BYTE)lastWeight;
rankStats[lastWeight]++;
} }
/* check tree construction validity */
if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
/* results */
*nbSymbolsPtr = (U32)(oSize+1);
return iSize+1;
}
/* Avoids the FORCE_INLINE of the _body() function. */
static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats,
U32* nbSymbolsPtr, U32* tableLogPtr,
const void* src, size_t srcSize,
void* workSpace, size_t wkspSize)
{
return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0);
}
#if DYNAMIC_BMI2
static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats,
U32* nbSymbolsPtr, U32* tableLogPtr,
const void* src, size_t srcSize,
void* workSpace, size_t wkspSize)
{
return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1);
}
#endif
size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats,
U32* nbSymbolsPtr, U32* tableLogPtr,
const void* src, size_t srcSize,
void* workSpace, size_t wkspSize,
int bmi2)
{
#if DYNAMIC_BMI2
if (bmi2) {
return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
}
#endif
(void)bmi2;
return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize);
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
/* The purpose of this file is to have a single list of error strings embedded in binary */
#include "error_private.h"
const char* ERR_getErrorString(ERR_enum code)
{
#ifdef ZSTD_STRIP_ERROR_STRINGS
(void)code;
return "Error strings stripped";
#else
static const char* const notErrorCode = "Unspecified error code";
switch( code )
{
case PREFIX(no_error): return "No error detected";
case PREFIX(GENERIC): return "Error (generic)";
case PREFIX(prefix_unknown): return "Unknown frame descriptor";
case PREFIX(version_unsupported): return "Version not supported";
case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";
case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";
case PREFIX(corruption_detected): return "Data corruption detected";
case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";
case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification";
case PREFIX(parameter_unsupported): return "Unsupported parameter";
case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters";
case PREFIX(parameter_outOfBound): return "Parameter is out of bound";
case PREFIX(init_missing): return "Context should be init first";
case PREFIX(memory_allocation): return "Allocation error : not enough memory";
case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough";
case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";
case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";
case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";
case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";
case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected";
case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";
case PREFIX(dictionary_wrong): return "Dictionary mismatch";
case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples";
case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";
case PREFIX(srcSize_wrong): return "Src size is incorrect";
case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer";
/* following error codes are not stable and may be removed or changed in a future version */
case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
case PREFIX(externalMatchFinder_failed): return "External matchfinder returned an error code";
case PREFIX(maxCode):
default: return notErrorCode;
}
#endif
}

View File

@@ -1,159 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
/* Note : this module is expected to remain private, do not expose it */
#ifndef ERROR_H_MODULE
#define ERROR_H_MODULE
#if defined (__cplusplus)
extern "C" {
#endif
/* ****************************************
* Dependencies
******************************************/
#include "../zstd_errors.h" /* enum list */
#include "compiler.h"
#include "debug.h"
#include "zstd_deps.h" /* size_t */
/* ****************************************
* Compiler-specific
******************************************/
#if defined(__GNUC__)
# define ERR_STATIC static __attribute__((unused))
#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# define ERR_STATIC static inline
#elif defined(_MSC_VER)
# define ERR_STATIC static __inline
#else
# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
#endif
/*-****************************************
* Customization (error_public.h)
******************************************/
typedef ZSTD_ErrorCode ERR_enum;
#define PREFIX(name) ZSTD_error_##name
/*-****************************************
* Error codes handling
******************************************/
#undef ERROR /* already defined on Visual Studio */
#define ERROR(name) ZSTD_ERROR(name)
#define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
/* check and forward error code */
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
/*-****************************************
* Error Strings
******************************************/
const char* ERR_getErrorString(ERR_enum code); /* error_private.c */
ERR_STATIC const char* ERR_getErrorName(size_t code)
{
return ERR_getErrorString(ERR_getErrorCode(code));
}
/**
* Ignore: this is an internal helper.
*
* This is a helper function to help force C99-correctness during compilation.
* Under strict compilation modes, variadic macro arguments can't be empty.
* However, variadic function arguments can be. Using a function therefore lets
* us statically check that at least one (string) argument was passed,
* independent of the compilation flags.
*/
static INLINE_KEYWORD UNUSED_ATTR
void _force_has_format_string(const char *format, ...) {
(void)format;
}
/**
* Ignore: this is an internal helper.
*
* We want to force this function invocation to be syntactically correct, but
* we don't want to force runtime evaluation of its arguments.
*/
#define _FORCE_HAS_FORMAT_STRING(...) \
if (0) { \
_force_has_format_string(__VA_ARGS__); \
}
#define ERR_QUOTE(str) #str
/**
* Return the specified error if the condition evaluates to true.
*
* In debug modes, prints additional information.
* In order to do that (particularly, printing the conditional that failed),
* this can't just wrap RETURN_ERROR().
*/
#define RETURN_ERROR_IF(cond, err, ...) \
if (cond) { \
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
RAWLOG(3, ": " __VA_ARGS__); \
RAWLOG(3, "\n"); \
return ERROR(err); \
}
/**
* Unconditionally return the specified error.
*
* In debug modes, prints additional information.
*/
#define RETURN_ERROR(err, ...) \
do { \
RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
__FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
RAWLOG(3, ": " __VA_ARGS__); \
RAWLOG(3, "\n"); \
return ERROR(err); \
} while(0);
/**
* If the provided expression evaluates to an error code, returns that error code.
*
* In debug modes, prints additional information.
*/
#define FORWARD_IF_ERROR(err, ...) \
do { \
size_t const err_code = (err); \
if (ERR_isError(err_code)) { \
RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
__FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
RAWLOG(3, ": " __VA_ARGS__); \
RAWLOG(3, "\n"); \
return err_code; \
} \
} while(0);
#if defined (__cplusplus)
}
#endif
#endif /* ERROR_H_MODULE */

View File

@@ -1,717 +0,0 @@
/* ******************************************************************
* FSE : Finite State Entropy codec
* Public Prototypes declaration
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
****************************************************************** */
#if defined (__cplusplus)
extern "C" {
#endif
#ifndef FSE_H
#define FSE_H
/*-*****************************************
* Dependencies
******************************************/
#include "zstd_deps.h" /* size_t, ptrdiff_t */
/*-*****************************************
* FSE_PUBLIC_API : control library symbols visibility
******************************************/
#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
# define FSE_PUBLIC_API __attribute__ ((visibility ("default")))
#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
# define FSE_PUBLIC_API __declspec(dllexport)
#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
#else
# define FSE_PUBLIC_API
#endif
/*------ Version ------*/
#define FSE_VERSION_MAJOR 0
#define FSE_VERSION_MINOR 9
#define FSE_VERSION_RELEASE 0
#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
#define FSE_QUOTE(str) #str
#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
/*-****************************************
* FSE simple functions
******************************************/
/*! FSE_compress() :
Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
@return : size of compressed data (<= dstCapacity).
Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
if FSE_isError(return), compression failed (more details using FSE_getErrorName())
*/
FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity,
const void* src, size_t srcSize);
/*! FSE_decompress():
Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
into already allocated destination buffer 'dst', of size 'dstCapacity'.
@return : size of regenerated data (<= maxDstSize),
or an error code, which can be tested using FSE_isError() .
** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
Why ? : making this distinction requires a header.
Header management is intentionally delegated to the user layer, which can better manage special cases.
*/
FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity,
const void* cSrc, size_t cSrcSize);
/*-*****************************************
* Tool functions
******************************************/
FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
/* Error Management */
FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
/*-*****************************************
* FSE advanced functions
******************************************/
/*! FSE_compress2() :
Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
Both parameters can be defined as '0' to mean : use default value
@return : size of compressed data
Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
if FSE_isError(return), it's an error code.
*/
FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
/*-*****************************************
* FSE detailed API
******************************************/
/*!
FSE_compress() does the following:
1. count symbol occurrence from source[] into table count[] (see hist.h)
2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
3. save normalized counters to memory buffer using writeNCount()
4. build encoding table 'CTable' from normalized counters
5. encode the data stream using encoding table 'CTable'
FSE_decompress() does the following:
1. read normalized counters with readNCount()
2. build decoding table 'DTable' from normalized counters
3. decode the data stream using decoding table 'DTable'
The following API allows targeting specific sub-functions for advanced tasks.
For example, it's possible to compress several blocks using the same 'CTable',
or to save and provide normalized distribution using external method.
*/
/* *** COMPRESSION *** */
/*! FSE_optimalTableLog():
dynamically downsize 'tableLog' when conditions are met.
It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
@return : recommended tableLog (necessarily <= 'maxTableLog') */
FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
/*! FSE_normalizeCount():
normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
useLowProbCount is a boolean parameter which trades off compressed size for
faster header decoding. When it is set to 1, the compressed data will be slightly
smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be
faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0
is a good default, since header deserialization makes a big speed difference.
Otherwise, useLowProbCount=1 is a good default, since the speed difference is small.
@return : tableLog,
or an errorCode, which can be tested using FSE_isError() */
FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog,
const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount);
/*! FSE_NCountWriteBound():
Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
Typically useful for allocation purpose. */
FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
/*! FSE_writeNCount():
Compactly save 'normalizedCounter' into 'buffer'.
@return : size of the compressed table,
or an errorCode, which can be tested using FSE_isError(). */
FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize,
const short* normalizedCounter,
unsigned maxSymbolValue, unsigned tableLog);
/*! Constructor and Destructor of FSE_CTable.
Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog);
FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct);
/*! FSE_buildCTable():
Builds `ct`, which must be already allocated, using FSE_createCTable().
@return : 0, or an errorCode, which can be tested using FSE_isError() */
FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
/*! FSE_compress_usingCTable():
Compress `src` using `ct` into `dst` which must be already allocated.
@return : size of compressed data (<= `dstCapacity`),
or 0 if compressed data could not fit into `dst`,
or an errorCode, which can be tested using FSE_isError() */
FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
/*!
Tutorial :
----------
The first step is to count all symbols. FSE_count() does this job very fast.
Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
FSE_count() will return the number of occurrence of the most frequent symbol.
This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
The next step is to normalize the frequencies.
FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
You can use 'tableLog'==0 to mean "use default tableLog value".
If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
The result of FSE_normalizeCount() will be saved into a table,
called 'normalizedCounter', which is a table of signed short.
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
The return value is tableLog if everything proceeded as expected.
It is 0 if there is a single symbol within distribution.
If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
'buffer' must be already allocated.
For guaranteed success, buffer size must be at least FSE_headerBound().
The result of the function is the number of bytes written into 'buffer'.
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
'normalizedCounter' can then be used to create the compression table 'CTable'.
The space required by 'CTable' must be already allocated, using FSE_createCTable().
You can then use FSE_buildCTable() to fill 'CTable'.
If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
If it returns '0', compressed data could not fit into 'dst'.
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
*/
/* *** DECOMPRESSION *** */
/*! FSE_readNCount():
Read compactly saved 'normalizedCounter' from 'rBuffer'.
@return : size read from 'rBuffer',
or an errorCode, which can be tested using FSE_isError().
maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter,
unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
const void* rBuffer, size_t rBuffSize);
/*! FSE_readNCount_bmi2():
* Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise.
*/
FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter,
unsigned* maxSymbolValuePtr, unsigned* tableLogPtr,
const void* rBuffer, size_t rBuffSize, int bmi2);
/*! Constructor and Destructor of FSE_DTable.
Note that its size depends on 'tableLog' */
typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog);
FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt);
/*! FSE_buildDTable():
Builds 'dt', which must be already allocated, using FSE_createDTable().
return : 0, or an errorCode, which can be tested using FSE_isError() */
FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
/*! FSE_decompress_usingDTable():
Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
into `dst` which must be already allocated.
@return : size of regenerated data (necessarily <= `dstCapacity`),
or an errorCode, which can be tested using FSE_isError() */
FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
/*!
Tutorial :
----------
(Note : these functions only decompress FSE-compressed blocks.
If block is uncompressed, use memcpy() instead
If block is a single repeated byte, use memset() instead )
The first step is to obtain the normalized frequencies of symbols.
This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
or size the table to handle worst case situations (typically 256).
FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
If there is an error, the function will return an error code, which can be tested using FSE_isError().
The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
This is performed by the function FSE_buildDTable().
The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
If there is an error, the function will return an error code, which can be tested using FSE_isError().
`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
`cSrcSize` must be strictly correct, otherwise decompression will fail.
FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
*/
#endif /* FSE_H */
#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY)
#define FSE_H_FSE_STATIC_LINKING_ONLY
/* *** Dependency *** */
#include "bitstream.h"
/* *****************************************
* Static allocation
*******************************************/
/* FSE buffer bounds */
#define FSE_NCOUNTBOUND 512
#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */)
#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2))
#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog)))
/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */
#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable))
#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable))
/* *****************************************
* FSE advanced API
***************************************** */
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
/**< same as FSE_optimalTableLog(), which used `minus==2` */
/* FSE_compress_wksp() :
* Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
* FSE_COMPRESS_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
*/
#define FSE_COMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
/* FSE_buildCTable_wksp() :
* Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
* `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`.
* See FSE_buildCTable_wksp() for breakdown of workspace usage.
*/
#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */)
#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog))
size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8)
#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned))
FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + 1 + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1)
#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned))
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize);
/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */
size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2);
/**< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */
typedef enum {
FSE_repeat_none, /**< Cannot use the previous table */
FSE_repeat_check, /**< Can use the previous table but it must be checked */
FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */
} FSE_repeat;
/* *****************************************
* FSE symbol compression API
*******************************************/
/*!
This API consists of small unitary functions, which highly benefit from being inlined.
Hence their body are included in next section.
*/
typedef struct {
ptrdiff_t value;
const void* stateTable;
const void* symbolTT;
unsigned stateLog;
} FSE_CState_t;
static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
/**<
These functions are inner components of FSE_compress_usingCTable().
They allow the creation of custom streams, mixing multiple tables and bit sources.
A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
So the first symbol you will encode is the last you will decode, like a LIFO stack.
You will need a few variables to track your CStream. They are :
FSE_CTable ct; // Provided by FSE_buildCTable()
BIT_CStream_t bitStream; // bitStream tracking structure
FSE_CState_t state; // State tracking structure (can have several)
The first thing to do is to init bitStream and state.
size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
FSE_initCState(&state, ct);
Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
You can then encode your input data, byte after byte.
FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
Remember decoding will be done in reverse direction.
FSE_encodeByte(&bitStream, &state, symbol);
At any time, you can also add any bit sequence.
Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
BIT_addBits(&bitStream, bitField, nbBits);
The above methods don't commit data to memory, they just store it into local register, for speed.
Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
Writing data to memory is a manual operation, performed by the flushBits function.
BIT_flushBits(&bitStream);
Your last FSE encoding operation shall be to flush your last state value(s).
FSE_flushState(&bitStream, &state);
Finally, you must close the bitStream.
The function returns the size of CStream in bytes.
If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
size_t size = BIT_closeCStream(&bitStream);
*/
/* *****************************************
* FSE symbol decompression API
*******************************************/
typedef struct {
size_t state;
const void* table; /* precise table may vary, depending on U16 */
} FSE_DState_t;
static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
/**<
Let's now decompose FSE_decompress_usingDTable() into its unitary components.
You will decode FSE-encoded symbols from the bitStream,
and also any other bitFields you put in, **in reverse order**.
You will need a few variables to track your bitStream. They are :
BIT_DStream_t DStream; // Stream context
FSE_DState_t DState; // State context. Multiple ones are possible
FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
The first thing to do is to init the bitStream.
errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
You should then retrieve your initial state(s)
(in reverse flushing order if you have several ones) :
errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
You can then decode your data, symbol after symbol.
For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
Note : maximum allowed nbBits is 25, for 32-bits compatibility
size_t bitField = BIT_readBits(&DStream, nbBits);
All above operations only read from local register (which size depends on size_t).
Refueling the register from memory is manually performed by the reload method.
endSignal = FSE_reloadDStream(&DStream);
BIT_reloadDStream() result tells if there is still some more data to read from DStream.
BIT_DStream_unfinished : there is still some data left into the DStream.
BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
to properly detect the exact end of stream.
After each decoded symbol, check if DStream is fully consumed using this simple test :
BIT_reloadDStream(&DStream) >= BIT_DStream_completed
When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
Checking if DStream has reached its end is performed by :
BIT_endOfDStream(&DStream);
Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
FSE_endOfDState(&DState);
*/
/* *****************************************
* FSE unsafe API
*******************************************/
static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
/* *****************************************
* Implementation of inlined functions
*******************************************/
typedef struct {
int deltaFindState;
U32 deltaNbBits;
} FSE_symbolCompressionTransform; /* total 8 bytes */
MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
{
const void* ptr = ct;
const U16* u16ptr = (const U16*) ptr;
const U32 tableLog = MEM_read16(ptr);
statePtr->value = (ptrdiff_t)1<<tableLog;
statePtr->stateTable = u16ptr+2;
statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1);
statePtr->stateLog = tableLog;
}
/*! FSE_initCState2() :
* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
* uses the smallest state value possible, saving the cost of this symbol */
MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
{
FSE_initCState(statePtr, ct);
{ const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
const U16* stateTable = (const U16*)(statePtr->stateTable);
U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
}
}
MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol)
{
FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
const U16* const stateTable = (const U16*)(statePtr->stateTable);
U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
BIT_addBits(bitC, statePtr->value, nbBitsOut);
statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
}
MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
{
BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
BIT_flushBits(bitC);
}
/* FSE_getMaxNbBits() :
* Approximate maximum cost of a symbol, in bits.
* Fractional get rounded up (i.e. a symbol with a normalized frequency of 3 gives the same result as a frequency of 2)
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue)
{
const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16;
}
/* FSE_bitCost() :
* Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
* note 1 : assume symbolValue is valid (<= maxSymbolValue)
* note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */
MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog)
{
const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr;
U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16;
U32 const threshold = (minNbBits+1) << 16;
assert(tableLog < 16);
assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */
{ U32 const tableSize = 1 << tableLog;
U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize);
U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */
U32 const bitMultiplier = 1 << accuracyLog;
assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold);
assert(normalizedDeltaFromThreshold <= bitMultiplier);
return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold;
}
}
/* ====== Decompression ====== */
typedef struct {
U16 tableLog;
U16 fastMode;
} FSE_DTableHeader; /* sizeof U32 */
typedef struct
{
unsigned short newState;
unsigned char symbol;
unsigned char nbBits;
} FSE_decode_t; /* size == U32 */
MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
{
const void* ptr = dt;
const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
BIT_reloadDStream(bitD);
DStatePtr->table = dt + 1;
}
MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
{
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
return DInfo.symbol;
}
MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
{
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
U32 const nbBits = DInfo.nbBits;
size_t const lowBits = BIT_readBits(bitD, nbBits);
DStatePtr->state = DInfo.newState + lowBits;
}
MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
{
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
U32 const nbBits = DInfo.nbBits;
BYTE const symbol = DInfo.symbol;
size_t const lowBits = BIT_readBits(bitD, nbBits);
DStatePtr->state = DInfo.newState + lowBits;
return symbol;
}
/*! FSE_decodeSymbolFast() :
unsafe, only works if no symbol has a probability > 50% */
MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
{
FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
U32 const nbBits = DInfo.nbBits;
BYTE const symbol = DInfo.symbol;
size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
DStatePtr->state = DInfo.newState + lowBits;
return symbol;
}
MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
{
return DStatePtr->state == 0;
}
#ifndef FSE_COMMONDEFS_ONLY
/* **************************************************************
* Tuning parameters
****************************************************************/
/*!MEMORY_USAGE :
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
* Increasing memory usage improves compression ratio
* Reduced memory usage can improve speed, due to cache effect
* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
#ifndef FSE_MAX_MEMORY_USAGE
# define FSE_MAX_MEMORY_USAGE 14
#endif
#ifndef FSE_DEFAULT_MEMORY_USAGE
# define FSE_DEFAULT_MEMORY_USAGE 13
#endif
#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE)
# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE"
#endif
/*!FSE_MAX_SYMBOL_VALUE :
* Maximum symbol value authorized.
* Required for proper stack allocation */
#ifndef FSE_MAX_SYMBOL_VALUE
# define FSE_MAX_SYMBOL_VALUE 255
#endif
/* **************************************************************
* template functions type & suffix
****************************************************************/
#define FSE_FUNCTION_TYPE BYTE
#define FSE_FUNCTION_EXTENSION
#define FSE_DECODE_TYPE FSE_decode_t
#endif /* !FSE_COMMONDEFS_ONLY */
/* ***************************************************************
* Constants
*****************************************************************/
#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
#define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
#define FSE_MIN_TABLELOG 5
#define FSE_TABLELOG_ABSOLUTE_MAX 15
#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
#endif
#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3)
#endif /* FSE_STATIC_LINKING_ONLY */
#if defined (__cplusplus)
}
#endif

View File

@@ -1,405 +0,0 @@
/* ******************************************************************
* FSE : Finite State Entropy decoder
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
* - Public forum : https://groups.google.com/forum/#!forum/lz4c
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
****************************************************************** */
/* **************************************************************
* Includes
****************************************************************/
#include "debug.h" /* assert */
#include "bitstream.h"
#include "compiler.h"
#define FSE_STATIC_LINKING_ONLY
#include "fse.h"
#include "error_private.h"
#define ZSTD_DEPS_NEED_MALLOC
#include "zstd_deps.h"
#include "bits.h" /* ZSTD_highbit32 */
/* **************************************************************
* Error Management
****************************************************************/
#define FSE_isError ERR_isError
#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */
/* **************************************************************
* Templates
****************************************************************/
/*
designed to be included
for type-specific functions (template emulation in C)
Objective is to write these functions only once, for improved maintenance
*/
/* safety checks */
#ifndef FSE_FUNCTION_EXTENSION
# error "FSE_FUNCTION_EXTENSION must be defined"
#endif
#ifndef FSE_FUNCTION_TYPE
# error "FSE_FUNCTION_TYPE must be defined"
#endif
/* Function names */
#define FSE_CAT(X,Y) X##Y
#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
/* Function templates */
FSE_DTable* FSE_createDTable (unsigned tableLog)
{
if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
}
void FSE_freeDTable (FSE_DTable* dt)
{
ZSTD_free(dt);
}
static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
{
void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
U16* symbolNext = (U16*)workSpace;
BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1);
U32 const maxSV1 = maxSymbolValue + 1;
U32 const tableSize = 1 << tableLog;
U32 highThreshold = tableSize-1;
/* Sanity Checks */
if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge);
if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
/* Init, lay down lowprob symbols */
{ FSE_DTableHeader DTableH;
DTableH.tableLog = (U16)tableLog;
DTableH.fastMode = 1;
{ S16 const largeLimit= (S16)(1 << (tableLog-1));
U32 s;
for (s=0; s<maxSV1; s++) {
if (normalizedCounter[s]==-1) {
tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
symbolNext[s] = 1;
} else {
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
symbolNext[s] = normalizedCounter[s];
} } }
ZSTD_memcpy(dt, &DTableH, sizeof(DTableH));
}
/* Spread symbols */
if (highThreshold == tableSize - 1) {
size_t const tableMask = tableSize-1;
size_t const step = FSE_TABLESTEP(tableSize);
/* First lay down the symbols in order.
* We use a uint64_t to lay down 8 bytes at a time. This reduces branch
* misses since small blocks generally have small table logs, so nearly
* all symbols have counts <= 8. We ensure we have 8 bytes at the end of
* our buffer to handle the over-write.
*/
{
U64 const add = 0x0101010101010101ull;
size_t pos = 0;
U64 sv = 0;
U32 s;
for (s=0; s<maxSV1; ++s, sv += add) {
int i;
int const n = normalizedCounter[s];
MEM_write64(spread + pos, sv);
for (i = 8; i < n; i += 8) {
MEM_write64(spread + pos + i, sv);
}
pos += n;
}
}
/* Now we spread those positions across the table.
* The benefit of doing it in two stages is that we avoid the
* variable size inner loop, which caused lots of branch misses.
* Now we can run through all the positions without any branch misses.
* We unroll the loop twice, since that is what empirically worked best.
*/
{
size_t position = 0;
size_t s;
size_t const unroll = 2;
assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */
for (s = 0; s < (size_t)tableSize; s += unroll) {
size_t u;
for (u = 0; u < unroll; ++u) {
size_t const uPosition = (position + (u * step)) & tableMask;
tableDecode[uPosition].symbol = spread[s + u];
}
position = (position + (unroll * step)) & tableMask;
}
assert(position == 0);
}
} else {
U32 const tableMask = tableSize-1;
U32 const step = FSE_TABLESTEP(tableSize);
U32 s, position = 0;
for (s=0; s<maxSV1; s++) {
int i;
for (i=0; i<normalizedCounter[s]; i++) {
tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
position = (position + step) & tableMask;
while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
} }
if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
}
/* Build Decoding table */
{ U32 u;
for (u=0; u<tableSize; u++) {
FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
U32 const nextState = symbolNext[symbol]++;
tableDecode[u].nbBits = (BYTE) (tableLog - ZSTD_highbit32(nextState) );
tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
} }
return 0;
}
size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
{
return FSE_buildDTable_internal(dt, normalizedCounter, maxSymbolValue, tableLog, workSpace, wkspSize);
}
#ifndef FSE_COMMONDEFS_ONLY
/*-*******************************************************
* Decompression (Byte symbols)
*********************************************************/
size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
{
void* ptr = dt;
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
void* dPtr = dt + 1;
FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
DTableH->tableLog = 0;
DTableH->fastMode = 0;
cell->newState = 0;
cell->symbol = symbolValue;
cell->nbBits = 0;
return 0;
}
size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
{
void* ptr = dt;
FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
void* dPtr = dt + 1;
FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
const unsigned tableSize = 1 << nbBits;
const unsigned tableMask = tableSize - 1;
const unsigned maxSV1 = tableMask+1;
unsigned s;
/* Sanity checks */
if (nbBits < 1) return ERROR(GENERIC); /* min size */
/* Build Decoding Table */
DTableH->tableLog = (U16)nbBits;
DTableH->fastMode = 1;
for (s=0; s<maxSV1; s++) {
dinfo[s].newState = 0;
dinfo[s].symbol = (BYTE)s;
dinfo[s].nbBits = (BYTE)nbBits;
}
return 0;
}
FORCE_INLINE_TEMPLATE size_t FSE_decompress_usingDTable_generic(
void* dst, size_t maxDstSize,
const void* cSrc, size_t cSrcSize,
const FSE_DTable* dt, const unsigned fast)
{
BYTE* const ostart = (BYTE*) dst;
BYTE* op = ostart;
BYTE* const omax = op + maxDstSize;
BYTE* const olimit = omax-3;
BIT_DStream_t bitD;
FSE_DState_t state1;
FSE_DState_t state2;
/* Init */
CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
FSE_initDState(&state1, &bitD, dt);
FSE_initDState(&state2, &bitD, dt);
#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
/* 4 symbols per loop */
for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
op[0] = FSE_GETSYMBOL(&state1);
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
BIT_reloadDStream(&bitD);
op[1] = FSE_GETSYMBOL(&state2);
if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
{ if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
op[2] = FSE_GETSYMBOL(&state1);
if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
BIT_reloadDStream(&bitD);
op[3] = FSE_GETSYMBOL(&state2);
}
/* tail */
/* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
while (1) {
if (op>(omax-2)) return ERROR(dstSize_tooSmall);
*op++ = FSE_GETSYMBOL(&state1);
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
*op++ = FSE_GETSYMBOL(&state2);
break;
}
if (op>(omax-2)) return ERROR(dstSize_tooSmall);
*op++ = FSE_GETSYMBOL(&state2);
if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
*op++ = FSE_GETSYMBOL(&state1);
break;
} }
return op-ostart;
}
size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
const void* cSrc, size_t cSrcSize,
const FSE_DTable* dt)
{
const void* ptr = dt;
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
const U32 fastMode = DTableH->fastMode;
/* select fast mode (static) */
if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
}
size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
{
return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0);
}
typedef struct {
short ncount[FSE_MAX_SYMBOL_VALUE + 1];
FSE_DTable dtable[1]; /* Dynamically sized */
} FSE_DecompressWksp;
FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body(
void* dst, size_t dstCapacity,
const void* cSrc, size_t cSrcSize,
unsigned maxLog, void* workSpace, size_t wkspSize,
int bmi2)
{
const BYTE* const istart = (const BYTE*)cSrc;
const BYTE* ip = istart;
unsigned tableLog;
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace;
DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0);
if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC);
/* normal FSE decoding mode */
{
size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2);
if (FSE_isError(NCountLength)) return NCountLength;
if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
assert(NCountLength <= cSrcSize);
ip += NCountLength;
cSrcSize -= NCountLength;
}
if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge);
assert(sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog) <= wkspSize);
workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog);
CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) );
{
const void* ptr = wksp->dtable;
const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
const U32 fastMode = DTableH->fastMode;
/* select fast mode (static) */
if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1);
return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0);
}
}
/* Avoids the FORCE_INLINE of the _body() function. */
static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
{
return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0);
}
#if DYNAMIC_BMI2
BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize)
{
return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1);
}
#endif
size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2)
{
#if DYNAMIC_BMI2
if (bmi2) {
return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
}
#endif
(void)bmi2;
return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize);
}
typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
#ifndef ZSTD_NO_UNUSED_FUNCTIONS
size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) {
U32 wksp[FSE_BUILD_DTABLE_WKSP_SIZE_U32(FSE_TABLELOG_ABSOLUTE_MAX, FSE_MAX_SYMBOL_VALUE)];
return FSE_buildDTable_wksp(dt, normalizedCounter, maxSymbolValue, tableLog, wksp, sizeof(wksp));
}
size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)
{
/* Static analyzer seems unable to understand this table will be properly initialized later */
U32 wksp[FSE_DECOMPRESS_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, FSE_MAX_TABLELOG, wksp, sizeof(wksp));
}
#endif
#endif /* FSE_COMMONDEFS_ONLY */

View File

@@ -1,377 +0,0 @@
/* ******************************************************************
* huff0 huffman codec,
* part of Finite State Entropy library
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
****************************************************************** */
#if defined (__cplusplus)
extern "C" {
#endif
#ifndef HUF_H_298734234
#define HUF_H_298734234
/* *** Dependencies *** */
#include "zstd_deps.h" /* size_t */
/* *** library symbols visibility *** */
/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual,
* HUF symbols remain "private" (internal symbols for library only).
* Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */
#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4)
# define HUF_PUBLIC_API __attribute__ ((visibility ("default")))
#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */
# define HUF_PUBLIC_API __declspec(dllexport)
#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1)
# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */
#else
# define HUF_PUBLIC_API
#endif
/* ========================== */
/* *** simple functions *** */
/* ========================== */
/** HUF_compress() :
* Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
* 'dst' buffer must be already allocated.
* Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
* `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
* @return : size of compressed data (<= `dstCapacity`).
* Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
* if HUF_isError(return), compression failed (more details using HUF_getErrorName())
*/
HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity,
const void* src, size_t srcSize);
/** HUF_decompress() :
* Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
* into already allocated buffer 'dst', of minimum size 'dstSize'.
* `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
* Note : in contrast with FSE, HUF_decompress can regenerate
* RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
* because it knows size to regenerate (originalSize).
* @return : size of regenerated data (== originalSize),
* or an error code, which can be tested using HUF_isError()
*/
HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize,
const void* cSrc, size_t cSrcSize);
/* *** Tool functions *** */
#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
/* Error Management */
HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */
/* *** Advanced function *** */
/** HUF_compress2() :
* Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`.
* `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX .
* `tableLog` must be `<= HUF_TABLELOG_MAX` . */
HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
unsigned maxSymbolValue, unsigned tableLog);
/** HUF_compress4X_wksp() :
* Same as HUF_compress2(), but uses externally allocated @workSpace.
* @workSpace's size, aka @wkspSize, must be >= HUF_WORKSPACE_SIZE
* @srcSize must be >= 6
*/
#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */)
#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64))
HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity,
const void* src, size_t srcSize,
unsigned maxSymbolValue, unsigned tableLog,
void* workSpace, size_t wkspSize);
#endif /* HUF_H_298734234 */
/* ******************************************************************
* WARNING !!
* The following section contains advanced and experimental definitions
* which shall never be used in the context of a dynamic library,
* because they are not guaranteed to remain stable in the future.
* Only consider them in association with static linking.
* *****************************************************************/
#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY)
#define HUF_H_HUF_STATIC_LINKING_ONLY
/* *** Dependencies *** */
#include "mem.h" /* U32 */
#define FSE_STATIC_LINKING_ONLY
#include "fse.h"
/* *** Constants *** */
#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */
#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */
#define HUF_SYMBOLVALUE_MAX 255
#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
# error "HUF_TABLELOG_MAX is too large !"
#endif
/* ****************************************
* Static allocation
******************************************/
/* HUF buffer bounds */
#define HUF_CTABLEBOUND 129
#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */
#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
/* static allocation of HUF's Compression Table */
/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */
typedef size_t HUF_CElt; /* consider it an incomplete type */
#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */
#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t))
#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */
/* static allocation of HUF's DTable */
typedef U32 HUF_DTable;
#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \
HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
/* ****************************************
* Advanced decompression functions
******************************************/
size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
#endif
size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */
size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
#endif
/* ****************************************
* HUF detailed API
* ****************************************/
#define HUF_OPTIMAL_DEPTH_THRESHOLD ZSTD_btultra
typedef enum {
HUF_depth_fast, /** Use heuristic to find the table depth**/
HUF_depth_optimal /** Test possible table depths to find the one that produces the smallest header + encoded size**/
} HUF_depth_mode;
/*! HUF_compress() does the following:
* 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h")
* 2. (optional) refine tableLog using HUF_optimalTableLog()
* 3. build Huffman table from count using HUF_buildCTable()
* 4. save Huffman table to memory buffer using HUF_writeCTable()
* 5. encode the data stream using HUF_compress4X_usingCTable()
*
* The following API allows targeting specific sub-functions for advanced tasks.
* For example, it's possible to compress several blocks using the same 'CTable',
* or to save and regenerate 'CTable' using external methods.
*/
unsigned HUF_minTableLog(unsigned symbolCardinality);
unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue);
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, void* workSpace,
size_t wkspSize, HUF_CElt* table, const unsigned* count, HUF_depth_mode depthMode); /* table is used as scratch space for building and testing tables, not a return value */
size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */
size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize);
size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2);
size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue);
typedef enum {
HUF_repeat_none, /**< Cannot use the previous table */
HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */
} HUF_repeat;
/** HUF_compress4X_repeat() :
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
* If it uses hufTable it does not modify hufTable or repeat.
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
* If preferRepeat then the old table will always be used if valid.
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
const void* src, size_t srcSize,
unsigned maxSymbolValue, unsigned tableLog,
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2,
int suspectUncompressible, HUF_depth_mode depthMode);
/** HUF_buildCTable_wksp() :
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
* `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE.
*/
#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1)
#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned))
size_t HUF_buildCTable_wksp (HUF_CElt* tree,
const unsigned* count, U32 maxSymbolValue, U32 maxNbBits,
void* workSpace, size_t wkspSize);
/*! HUF_readStats() :
* Read compact Huffman tree, saved by HUF_writeCTable().
* `huffWeight` is destination buffer.
* @return : size read from `src` , or an error Code .
* Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
size_t HUF_readStats(BYTE* huffWeight, size_t hwSize,
U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
const void* src, size_t srcSize);
/*! HUF_readStats_wksp() :
* Same as HUF_readStats() but takes an external workspace which must be
* 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE.
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
*/
#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1)
#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned))
size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize,
U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr,
const void* src, size_t srcSize,
void* workspace, size_t wkspSize,
int bmi2);
/** HUF_readCTable() :
* Loading a CTable saved with HUF_writeCTable() */
size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights);
/** HUF_getNbBitsFromCTable() :
* Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX
* Note 1 : is not inlined, as HUF_CElt definition is private */
U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue);
/*
* HUF_decompress() does the following:
* 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics
* 2. build Huffman table from save, using HUF_readDTableX?()
* 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable()
*/
/** HUF_selectDecoder() :
* Tells which decoder is likely to decode faster,
* based on a set of pre-computed metrics.
* @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 .
* Assumption : 0 < dstSize <= 128 KB */
U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
/**
* The minimum workspace size for the `workSpace` used in
* HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp().
*
* The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when
* HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15.
* Buffer overflow errors may potentially occur if code modifications result in
* a required workspace size greater than that specified in the following
* macro.
*/
#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9))
#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
#ifndef HUF_FORCE_DECOMPRESS_X2
size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize);
size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
#endif
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize);
#endif
size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
#ifndef HUF_FORCE_DECOMPRESS_X2
size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
#endif
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
#endif
/* ====================== */
/* single stream variants */
/* ====================== */
size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U64 U64 */
size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2);
/** HUF_compress1X_repeat() :
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
* If it uses hufTable it does not modify hufTable or repeat.
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
* If preferRepeat then the old table will always be used if valid.
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
const void* src, size_t srcSize,
unsigned maxSymbolValue, unsigned tableLog,
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2,
int suspectUncompressible, HUF_depth_mode depthMode);
size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
#endif
size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize);
#ifndef HUF_FORCE_DECOMPRESS_X2
size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */
#endif
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */
#endif
size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
#ifndef HUF_FORCE_DECOMPRESS_X2
size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
#endif
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
#endif
/* BMI2 variants.
* If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0.
*/
size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
#ifndef HUF_FORCE_DECOMPRESS_X2
size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
#endif
size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2);
size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2);
#ifndef HUF_FORCE_DECOMPRESS_X2
size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2);
#endif
#ifndef HUF_FORCE_DECOMPRESS_X1
size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2);
#endif
#endif /* HUF_STATIC_LINKING_ONLY */
#if defined (__cplusplus)
}
#endif

View File

@@ -1,435 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef MEM_H_MODULE
#define MEM_H_MODULE
#if defined (__cplusplus)
extern "C" {
#endif
/*-****************************************
* Dependencies
******************************************/
#include <stddef.h> /* size_t, ptrdiff_t */
#include "compiler.h" /* __has_builtin */
#include "debug.h" /* DEBUG_STATIC_ASSERT */
#include "zstd_deps.h" /* ZSTD_memcpy */
/*-****************************************
* Compiler specifics
******************************************/
#if defined(_MSC_VER) /* Visual Studio */
# include <stdlib.h> /* _byteswap_ulong */
# include <intrin.h> /* _byteswap_* */
#endif
#if defined(__GNUC__)
# define MEM_STATIC static __inline __attribute__((unused))
#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# define MEM_STATIC static inline
#elif defined(_MSC_VER)
# define MEM_STATIC static __inline
#else
# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
#endif
/*-**************************************************************
* Basic Types
*****************************************************************/
#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# if defined(_AIX)
# include <inttypes.h>
# else
# include <stdint.h> /* intptr_t */
# endif
typedef uint8_t BYTE;
typedef uint8_t U8;
typedef int8_t S8;
typedef uint16_t U16;
typedef int16_t S16;
typedef uint32_t U32;
typedef int32_t S32;
typedef uint64_t U64;
typedef int64_t S64;
#else
# include <limits.h>
#if CHAR_BIT != 8
# error "this implementation requires char to be exactly 8-bit type"
#endif
typedef unsigned char BYTE;
typedef unsigned char U8;
typedef signed char S8;
#if USHRT_MAX != 65535
# error "this implementation requires short to be exactly 16-bit type"
#endif
typedef unsigned short U16;
typedef signed short S16;
#if UINT_MAX != 4294967295
# error "this implementation requires int to be exactly 32-bit type"
#endif
typedef unsigned int U32;
typedef signed int S32;
/* note : there are no limits defined for long long type in C90.
* limits exist in C99, however, in such case, <stdint.h> is preferred */
typedef unsigned long long U64;
typedef signed long long S64;
#endif
/*-**************************************************************
* Memory I/O API
*****************************************************************/
/*=== Static platform detection ===*/
MEM_STATIC unsigned MEM_32bits(void);
MEM_STATIC unsigned MEM_64bits(void);
MEM_STATIC unsigned MEM_isLittleEndian(void);
/*=== Native unaligned read/write ===*/
MEM_STATIC U16 MEM_read16(const void* memPtr);
MEM_STATIC U32 MEM_read32(const void* memPtr);
MEM_STATIC U64 MEM_read64(const void* memPtr);
MEM_STATIC size_t MEM_readST(const void* memPtr);
MEM_STATIC void MEM_write16(void* memPtr, U16 value);
MEM_STATIC void MEM_write32(void* memPtr, U32 value);
MEM_STATIC void MEM_write64(void* memPtr, U64 value);
/*=== Little endian unaligned read/write ===*/
MEM_STATIC U16 MEM_readLE16(const void* memPtr);
MEM_STATIC U32 MEM_readLE24(const void* memPtr);
MEM_STATIC U32 MEM_readLE32(const void* memPtr);
MEM_STATIC U64 MEM_readLE64(const void* memPtr);
MEM_STATIC size_t MEM_readLEST(const void* memPtr);
MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val);
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val);
MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32);
MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64);
MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val);
/*=== Big endian unaligned read/write ===*/
MEM_STATIC U32 MEM_readBE32(const void* memPtr);
MEM_STATIC U64 MEM_readBE64(const void* memPtr);
MEM_STATIC size_t MEM_readBEST(const void* memPtr);
MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32);
MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64);
MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val);
/*=== Byteswap ===*/
MEM_STATIC U32 MEM_swap32(U32 in);
MEM_STATIC U64 MEM_swap64(U64 in);
MEM_STATIC size_t MEM_swapST(size_t in);
/*-**************************************************************
* Memory I/O Implementation
*****************************************************************/
/* MEM_FORCE_MEMORY_ACCESS : For accessing unaligned memory:
* Method 0 : always use `memcpy()`. Safe and portable.
* Method 1 : Use compiler extension to set unaligned access.
* Method 2 : direct access. This method is portable but violate C standard.
* It can generate buggy code on targets depending on alignment.
* Default : method 1 if supported, else method 0
*/
#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
# ifdef __GNUC__
# define MEM_FORCE_MEMORY_ACCESS 1
# endif
#endif
MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
MEM_STATIC unsigned MEM_isLittleEndian(void)
{
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
return 1;
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return 0;
#elif defined(__clang__) && __LITTLE_ENDIAN__
return 1;
#elif defined(__clang__) && __BIG_ENDIAN__
return 0;
#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86)
return 1;
#elif defined(__DMC__) && defined(_M_IX86)
return 1;
#else
const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
return one.c[0];
#endif
}
#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
/* violates C standard, by lying on structure alignment.
Only use if no other choice to achieve best performance on target platform */
MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
typedef __attribute__((aligned(1))) U16 unalign16;
typedef __attribute__((aligned(1))) U32 unalign32;
typedef __attribute__((aligned(1))) U64 unalign64;
typedef __attribute__((aligned(1))) size_t unalignArch;
MEM_STATIC U16 MEM_read16(const void* ptr) { return *(const unalign16*)ptr; }
MEM_STATIC U32 MEM_read32(const void* ptr) { return *(const unalign32*)ptr; }
MEM_STATIC U64 MEM_read64(const void* ptr) { return *(const unalign64*)ptr; }
MEM_STATIC size_t MEM_readST(const void* ptr) { return *(const unalignArch*)ptr; }
MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(unalign16*)memPtr = value; }
MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(unalign32*)memPtr = value; }
MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = value; }
#else
/* default method, safe and standard.
can sometimes prove slower */
MEM_STATIC U16 MEM_read16(const void* memPtr)
{
U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
}
MEM_STATIC U32 MEM_read32(const void* memPtr)
{
U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
}
MEM_STATIC U64 MEM_read64(const void* memPtr)
{
U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
}
MEM_STATIC size_t MEM_readST(const void* memPtr)
{
size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;
}
MEM_STATIC void MEM_write16(void* memPtr, U16 value)
{
ZSTD_memcpy(memPtr, &value, sizeof(value));
}
MEM_STATIC void MEM_write32(void* memPtr, U32 value)
{
ZSTD_memcpy(memPtr, &value, sizeof(value));
}
MEM_STATIC void MEM_write64(void* memPtr, U64 value)
{
ZSTD_memcpy(memPtr, &value, sizeof(value));
}
#endif /* MEM_FORCE_MEMORY_ACCESS */
MEM_STATIC U32 MEM_swap32_fallback(U32 in)
{
return ((in << 24) & 0xff000000 ) |
((in << 8) & 0x00ff0000 ) |
((in >> 8) & 0x0000ff00 ) |
((in >> 24) & 0x000000ff );
}
MEM_STATIC U32 MEM_swap32(U32 in)
{
#if defined(_MSC_VER) /* Visual Studio */
return _byteswap_ulong(in);
#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
|| (defined(__clang__) && __has_builtin(__builtin_bswap32))
return __builtin_bswap32(in);
#else
return MEM_swap32_fallback(in);
#endif
}
MEM_STATIC U64 MEM_swap64_fallback(U64 in)
{
return ((in << 56) & 0xff00000000000000ULL) |
((in << 40) & 0x00ff000000000000ULL) |
((in << 24) & 0x0000ff0000000000ULL) |
((in << 8) & 0x000000ff00000000ULL) |
((in >> 8) & 0x00000000ff000000ULL) |
((in >> 24) & 0x0000000000ff0000ULL) |
((in >> 40) & 0x000000000000ff00ULL) |
((in >> 56) & 0x00000000000000ffULL);
}
MEM_STATIC U64 MEM_swap64(U64 in)
{
#if defined(_MSC_VER) /* Visual Studio */
return _byteswap_uint64(in);
#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \
|| (defined(__clang__) && __has_builtin(__builtin_bswap64))
return __builtin_bswap64(in);
#else
return MEM_swap64_fallback(in);
#endif
}
MEM_STATIC size_t MEM_swapST(size_t in)
{
if (MEM_32bits())
return (size_t)MEM_swap32((U32)in);
else
return (size_t)MEM_swap64((U64)in);
}
/*=== Little endian r/w ===*/
MEM_STATIC U16 MEM_readLE16(const void* memPtr)
{
if (MEM_isLittleEndian())
return MEM_read16(memPtr);
else {
const BYTE* p = (const BYTE*)memPtr;
return (U16)(p[0] + (p[1]<<8));
}
}
MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
{
if (MEM_isLittleEndian()) {
MEM_write16(memPtr, val);
} else {
BYTE* p = (BYTE*)memPtr;
p[0] = (BYTE)val;
p[1] = (BYTE)(val>>8);
}
}
MEM_STATIC U32 MEM_readLE24(const void* memPtr)
{
return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16);
}
MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
{
MEM_writeLE16(memPtr, (U16)val);
((BYTE*)memPtr)[2] = (BYTE)(val>>16);
}
MEM_STATIC U32 MEM_readLE32(const void* memPtr)
{
if (MEM_isLittleEndian())
return MEM_read32(memPtr);
else
return MEM_swap32(MEM_read32(memPtr));
}
MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
{
if (MEM_isLittleEndian())
MEM_write32(memPtr, val32);
else
MEM_write32(memPtr, MEM_swap32(val32));
}
MEM_STATIC U64 MEM_readLE64(const void* memPtr)
{
if (MEM_isLittleEndian())
return MEM_read64(memPtr);
else
return MEM_swap64(MEM_read64(memPtr));
}
MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
{
if (MEM_isLittleEndian())
MEM_write64(memPtr, val64);
else
MEM_write64(memPtr, MEM_swap64(val64));
}
MEM_STATIC size_t MEM_readLEST(const void* memPtr)
{
if (MEM_32bits())
return (size_t)MEM_readLE32(memPtr);
else
return (size_t)MEM_readLE64(memPtr);
}
MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
{
if (MEM_32bits())
MEM_writeLE32(memPtr, (U32)val);
else
MEM_writeLE64(memPtr, (U64)val);
}
/*=== Big endian r/w ===*/
MEM_STATIC U32 MEM_readBE32(const void* memPtr)
{
if (MEM_isLittleEndian())
return MEM_swap32(MEM_read32(memPtr));
else
return MEM_read32(memPtr);
}
MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
{
if (MEM_isLittleEndian())
MEM_write32(memPtr, MEM_swap32(val32));
else
MEM_write32(memPtr, val32);
}
MEM_STATIC U64 MEM_readBE64(const void* memPtr)
{
if (MEM_isLittleEndian())
return MEM_swap64(MEM_read64(memPtr));
else
return MEM_read64(memPtr);
}
MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
{
if (MEM_isLittleEndian())
MEM_write64(memPtr, MEM_swap64(val64));
else
MEM_write64(memPtr, val64);
}
MEM_STATIC size_t MEM_readBEST(const void* memPtr)
{
if (MEM_32bits())
return (size_t)MEM_readBE32(memPtr);
else
return (size_t)MEM_readBE64(memPtr);
}
MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
{
if (MEM_32bits())
MEM_writeBE32(memPtr, (U32)val);
else
MEM_writeBE64(memPtr, (U64)val);
}
/* code only tested on 32 and 64 bits systems */
MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
#if defined (__cplusplus)
}
#endif
#endif /* MEM_H_MODULE */

View File

@@ -1,369 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
/* ====== Dependencies ======= */
#include "zstd_deps.h" /* size_t */
#include "debug.h" /* assert */
#include "zstd_internal.h" /* ZSTD_customCalloc, ZSTD_customFree */
#include "pool.h"
/* ====== Compiler specifics ====== */
#if defined(_MSC_VER)
# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */
#endif
#ifdef ZSTD_MULTITHREAD
#include "threading.h" /* pthread adaptation */
/* A job is a function and an opaque argument */
typedef struct POOL_job_s {
POOL_function function;
void *opaque;
} POOL_job;
struct POOL_ctx_s {
ZSTD_customMem customMem;
/* Keep track of the threads */
ZSTD_pthread_t* threads;
size_t threadCapacity;
size_t threadLimit;
/* The queue is a circular buffer */
POOL_job *queue;
size_t queueHead;
size_t queueTail;
size_t queueSize;
/* The number of threads working on jobs */
size_t numThreadsBusy;
/* Indicates if the queue is empty */
int queueEmpty;
/* The mutex protects the queue */
ZSTD_pthread_mutex_t queueMutex;
/* Condition variable for pushers to wait on when the queue is full */
ZSTD_pthread_cond_t queuePushCond;
/* Condition variables for poppers to wait on when the queue is empty */
ZSTD_pthread_cond_t queuePopCond;
/* Indicates if the queue is shutting down */
int shutdown;
};
/* POOL_thread() :
* Work thread for the thread pool.
* Waits for jobs and executes them.
* @returns : NULL on failure else non-null.
*/
static void* POOL_thread(void* opaque) {
POOL_ctx* const ctx = (POOL_ctx*)opaque;
if (!ctx) { return NULL; }
for (;;) {
/* Lock the mutex and wait for a non-empty queue or until shutdown */
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
while ( ctx->queueEmpty
|| (ctx->numThreadsBusy >= ctx->threadLimit) ) {
if (ctx->shutdown) {
/* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit),
* a few threads will be shutdown while !queueEmpty,
* but enough threads will remain active to finish the queue */
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
return opaque;
}
ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex);
}
/* Pop a job off the queue */
{ POOL_job const job = ctx->queue[ctx->queueHead];
ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize;
ctx->numThreadsBusy++;
ctx->queueEmpty = (ctx->queueHead == ctx->queueTail);
/* Unlock the mutex, signal a pusher, and run the job */
ZSTD_pthread_cond_signal(&ctx->queuePushCond);
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
job.function(job.opaque);
/* If the intended queue size was 0, signal after finishing job */
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
ctx->numThreadsBusy--;
ZSTD_pthread_cond_signal(&ctx->queuePushCond);
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
}
} /* for (;;) */
assert(0); /* Unreachable */
}
/* ZSTD_createThreadPool() : public access point */
POOL_ctx* ZSTD_createThreadPool(size_t numThreads) {
return POOL_create (numThreads, 0);
}
POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
}
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
ZSTD_customMem customMem)
{
POOL_ctx* ctx;
/* Check parameters */
if (!numThreads) { return NULL; }
/* Allocate the context and zero initialize */
ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem);
if (!ctx) { return NULL; }
/* Initialize the job queue.
* It needs one extra space since one space is wasted to differentiate
* empty and full queues.
*/
ctx->queueSize = queueSize + 1;
ctx->queue = (POOL_job*)ZSTD_customCalloc(ctx->queueSize * sizeof(POOL_job), customMem);
ctx->queueHead = 0;
ctx->queueTail = 0;
ctx->numThreadsBusy = 0;
ctx->queueEmpty = 1;
{
int error = 0;
error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL);
error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL);
error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL);
if (error) { POOL_free(ctx); return NULL; }
}
ctx->shutdown = 0;
/* Allocate space for the thread handles */
ctx->threads = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), customMem);
ctx->threadCapacity = 0;
ctx->customMem = customMem;
/* Check for errors */
if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; }
/* Initialize the threads */
{ size_t i;
for (i = 0; i < numThreads; ++i) {
if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) {
ctx->threadCapacity = i;
POOL_free(ctx);
return NULL;
} }
ctx->threadCapacity = numThreads;
ctx->threadLimit = numThreads;
}
return ctx;
}
/*! POOL_join() :
Shutdown the queue, wake any sleeping threads, and join all of the threads.
*/
static void POOL_join(POOL_ctx* ctx) {
/* Shut down the queue */
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
ctx->shutdown = 1;
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
/* Wake up sleeping threads */
ZSTD_pthread_cond_broadcast(&ctx->queuePushCond);
ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
/* Join all of the threads */
{ size_t i;
for (i = 0; i < ctx->threadCapacity; ++i) {
ZSTD_pthread_join(ctx->threads[i]); /* note : could fail */
} }
}
void POOL_free(POOL_ctx *ctx) {
if (!ctx) { return; }
POOL_join(ctx);
ZSTD_pthread_mutex_destroy(&ctx->queueMutex);
ZSTD_pthread_cond_destroy(&ctx->queuePushCond);
ZSTD_pthread_cond_destroy(&ctx->queuePopCond);
ZSTD_customFree(ctx->queue, ctx->customMem);
ZSTD_customFree(ctx->threads, ctx->customMem);
ZSTD_customFree(ctx, ctx->customMem);
}
/*! POOL_joinJobs() :
* Waits for all queued jobs to finish executing.
*/
void POOL_joinJobs(POOL_ctx* ctx) {
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
while(!ctx->queueEmpty || ctx->numThreadsBusy > 0) {
ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
}
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
}
void ZSTD_freeThreadPool (ZSTD_threadPool* pool) {
POOL_free (pool);
}
size_t POOL_sizeof(const POOL_ctx* ctx) {
if (ctx==NULL) return 0; /* supports sizeof NULL */
return sizeof(*ctx)
+ ctx->queueSize * sizeof(POOL_job)
+ ctx->threadCapacity * sizeof(ZSTD_pthread_t);
}
/* @return : 0 on success, 1 on error */
static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
{
if (numThreads <= ctx->threadCapacity) {
if (!numThreads) return 1;
ctx->threadLimit = numThreads;
return 0;
}
/* numThreads > threadCapacity */
{ ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
if (!threadPool) return 1;
/* replace existing thread pool */
ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
ZSTD_customFree(ctx->threads, ctx->customMem);
ctx->threads = threadPool;
/* Initialize additional threads */
{ size_t threadId;
for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) {
if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) {
ctx->threadCapacity = threadId;
return 1;
} }
} }
/* successfully expanded */
ctx->threadCapacity = numThreads;
ctx->threadLimit = numThreads;
return 0;
}
/* @return : 0 on success, 1 on error */
int POOL_resize(POOL_ctx* ctx, size_t numThreads)
{
int result;
if (ctx==NULL) return 1;
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
result = POOL_resize_internal(ctx, numThreads);
ZSTD_pthread_cond_broadcast(&ctx->queuePopCond);
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
return result;
}
/**
* Returns 1 if the queue is full and 0 otherwise.
*
* When queueSize is 1 (pool was created with an intended queueSize of 0),
* then a queue is empty if there is a thread free _and_ no job is waiting.
*/
static int isQueueFull(POOL_ctx const* ctx) {
if (ctx->queueSize > 1) {
return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize);
} else {
return (ctx->numThreadsBusy == ctx->threadLimit) ||
!ctx->queueEmpty;
}
}
static void
POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque)
{
POOL_job const job = {function, opaque};
assert(ctx != NULL);
if (ctx->shutdown) return;
ctx->queueEmpty = 0;
ctx->queue[ctx->queueTail] = job;
ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize;
ZSTD_pthread_cond_signal(&ctx->queuePopCond);
}
void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque)
{
assert(ctx != NULL);
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
/* Wait until there is space in the queue for the new job */
while (isQueueFull(ctx) && (!ctx->shutdown)) {
ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex);
}
POOL_add_internal(ctx, function, opaque);
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
}
int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque)
{
assert(ctx != NULL);
ZSTD_pthread_mutex_lock(&ctx->queueMutex);
if (isQueueFull(ctx)) {
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
return 0;
}
POOL_add_internal(ctx, function, opaque);
ZSTD_pthread_mutex_unlock(&ctx->queueMutex);
return 1;
}
#else /* ZSTD_MULTITHREAD not defined */
/* ========================== */
/* No multi-threading support */
/* ========================== */
/* We don't need any data, but if it is empty, malloc() might return NULL. */
struct POOL_ctx_s {
int dummy;
};
static POOL_ctx g_poolCtx;
POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) {
return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem);
}
POOL_ctx*
POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem)
{
(void)numThreads;
(void)queueSize;
(void)customMem;
return &g_poolCtx;
}
void POOL_free(POOL_ctx* ctx) {
assert(!ctx || ctx == &g_poolCtx);
(void)ctx;
}
void POOL_joinJobs(POOL_ctx* ctx){
assert(!ctx || ctx == &g_poolCtx);
(void)ctx;
}
int POOL_resize(POOL_ctx* ctx, size_t numThreads) {
(void)ctx; (void)numThreads;
return 0;
}
void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) {
(void)ctx;
function(opaque);
}
int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) {
(void)ctx;
function(opaque);
return 1;
}
size_t POOL_sizeof(const POOL_ctx* ctx) {
if (ctx==NULL) return 0; /* supports sizeof NULL */
assert(ctx == &g_poolCtx);
return sizeof(*ctx);
}
#endif /* ZSTD_MULTITHREAD */

View File

@@ -1,90 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef POOL_H
#define POOL_H
#if defined (__cplusplus)
extern "C" {
#endif
#include "zstd_deps.h"
#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */
#include "../zstd.h"
typedef struct POOL_ctx_s POOL_ctx;
/*! POOL_create() :
* Create a thread pool with at most `numThreads` threads.
* `numThreads` must be at least 1.
* The maximum number of queued jobs before blocking is `queueSize`.
* @return : POOL_ctx pointer on success, else NULL.
*/
POOL_ctx* POOL_create(size_t numThreads, size_t queueSize);
POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize,
ZSTD_customMem customMem);
/*! POOL_free() :
* Free a thread pool returned by POOL_create().
*/
void POOL_free(POOL_ctx* ctx);
/*! POOL_joinJobs() :
* Waits for all queued jobs to finish executing.
*/
void POOL_joinJobs(POOL_ctx* ctx);
/*! POOL_resize() :
* Expands or shrinks pool's number of threads.
* This is more efficient than releasing + creating a new context,
* since it tries to preserve and re-use existing threads.
* `numThreads` must be at least 1.
* @return : 0 when resize was successful,
* !0 (typically 1) if there is an error.
* note : only numThreads can be resized, queueSize remains unchanged.
*/
int POOL_resize(POOL_ctx* ctx, size_t numThreads);
/*! POOL_sizeof() :
* @return threadpool memory usage
* note : compatible with NULL (returns 0 in this case)
*/
size_t POOL_sizeof(const POOL_ctx* ctx);
/*! POOL_function :
* The function type that can be added to a thread pool.
*/
typedef void (*POOL_function)(void*);
/*! POOL_add() :
* Add the job `function(opaque)` to the thread pool. `ctx` must be valid.
* Possibly blocks until there is room in the queue.
* Note : The function may be executed asynchronously,
* therefore, `opaque` must live until function has been completed.
*/
void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque);
/*! POOL_tryAdd() :
* Add the job `function(opaque)` to thread pool _if_ a queue slot is available.
* Returns immediately even if not (does not block).
* @return : 1 if successful, 0 if not.
*/
int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque);
#if defined (__cplusplus)
}
#endif
#endif

View File

@@ -1,148 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef ZSTD_PORTABILITY_MACROS_H
#define ZSTD_PORTABILITY_MACROS_H
/**
* This header file contains macro definitions to support portability.
* This header is shared between C and ASM code, so it MUST only
* contain macro definitions. It MUST not contain any C code.
*
* This header ONLY defines macros to detect platforms/feature support.
*
*/
/* compat. with non-clang compilers */
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
/* compat. with non-clang compilers */
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
/* compat. with non-clang compilers */
#ifndef __has_feature
# define __has_feature(x) 0
#endif
/* detects whether we are being compiled under msan */
#ifndef ZSTD_MEMORY_SANITIZER
# if __has_feature(memory_sanitizer)
# define ZSTD_MEMORY_SANITIZER 1
# else
# define ZSTD_MEMORY_SANITIZER 0
# endif
#endif
/* detects whether we are being compiled under asan */
#ifndef ZSTD_ADDRESS_SANITIZER
# if __has_feature(address_sanitizer)
# define ZSTD_ADDRESS_SANITIZER 1
# elif defined(__SANITIZE_ADDRESS__)
# define ZSTD_ADDRESS_SANITIZER 1
# else
# define ZSTD_ADDRESS_SANITIZER 0
# endif
#endif
/* detects whether we are being compiled under dfsan */
#ifndef ZSTD_DATAFLOW_SANITIZER
# if __has_feature(dataflow_sanitizer)
# define ZSTD_DATAFLOW_SANITIZER 1
# else
# define ZSTD_DATAFLOW_SANITIZER 0
# endif
#endif
/* Mark the internal assembly functions as hidden */
#ifdef __ELF__
# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func
#else
# define ZSTD_HIDE_ASM_FUNCTION(func)
#endif
/* Enable runtime BMI2 dispatch based on the CPU.
* Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.
*/
#ifndef DYNAMIC_BMI2
#if ((defined(__clang__) && __has_attribute(__target__)) \
|| (defined(__GNUC__) \
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \
&& (defined(__x86_64__) || defined(_M_X64)) \
&& !defined(__BMI2__)
# define DYNAMIC_BMI2 1
#else
# define DYNAMIC_BMI2 0
#endif
#endif
/**
* Only enable assembly for GNUC compatible compilers,
* because other platforms may not support GAS assembly syntax.
*
* Only enable assembly for Linux / MacOS, other platforms may
* work, but they haven't been tested. This could likely be
* extended to BSD systems.
*
* Disable assembly when MSAN is enabled, because MSAN requires
* 100% of code to be instrumented to work.
*/
#if defined(__GNUC__)
# if defined(__linux__) || defined(__linux) || defined(__APPLE__)
# if ZSTD_MEMORY_SANITIZER
# define ZSTD_ASM_SUPPORTED 0
# elif ZSTD_DATAFLOW_SANITIZER
# define ZSTD_ASM_SUPPORTED 0
# else
# define ZSTD_ASM_SUPPORTED 1
# endif
# else
# define ZSTD_ASM_SUPPORTED 0
# endif
#else
# define ZSTD_ASM_SUPPORTED 0
#endif
/**
* Determines whether we should enable assembly for x86-64
* with BMI2.
*
* Enable if all of the following conditions hold:
* - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM
* - Assembly is supported
* - We are compiling for x86-64 and either:
* - DYNAMIC_BMI2 is enabled
* - BMI2 is supported at compile time
*/
#if !defined(ZSTD_DISABLE_ASM) && \
ZSTD_ASM_SUPPORTED && \
defined(__x86_64__) && \
(DYNAMIC_BMI2 || defined(__BMI2__))
# define ZSTD_ENABLE_ASM_X86_64_BMI2 1
#else
# define ZSTD_ENABLE_ASM_X86_64_BMI2 0
#endif
/*
* For x86 ELF targets, add .note.gnu.property section for Intel CET in
* assembly sources when CET is enabled.
*/
#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \
&& defined(__has_include)
# if __has_include(<cet.h>)
# include <cet.h>
# endif
#endif
#endif /* ZSTD_PORTABILITY_MACROS_H */

View File

@@ -1,176 +0,0 @@
/**
* Copyright (c) 2016 Tino Reichardt
* All rights reserved.
*
* You can contact the author at:
* - zstdmt source repository: https://github.com/mcmilk/zstdmt
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
/**
* This file will hold wrapper for systems, which do not support pthreads
*/
#include "threading.h"
/* create fake symbol to avoid empty translation unit warning */
int g_ZSTD_threading_useless_symbol;
#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
/**
* Windows minimalist Pthread Wrapper
*/
/* === Dependencies === */
#include <process.h>
#include <errno.h>
/* === Implementation === */
typedef struct {
void* (*start_routine)(void*);
void* arg;
int initialized;
ZSTD_pthread_cond_t initialized_cond;
ZSTD_pthread_mutex_t initialized_mutex;
} ZSTD_thread_params_t;
static unsigned __stdcall worker(void *arg)
{
void* (*start_routine)(void*);
void* thread_arg;
/* Inialized thread_arg and start_routine and signal main thread that we don't need it
* to wait any longer.
*/
{
ZSTD_thread_params_t* thread_param = (ZSTD_thread_params_t*)arg;
thread_arg = thread_param->arg;
start_routine = thread_param->start_routine;
/* Signal main thread that we are running and do not depend on its memory anymore */
ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex);
thread_param->initialized = 1;
ZSTD_pthread_cond_signal(&thread_param->initialized_cond);
ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex);
}
start_routine(thread_arg);
return 0;
}
int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
void* (*start_routine) (void*), void* arg)
{
ZSTD_thread_params_t thread_param;
(void)unused;
thread_param.start_routine = start_routine;
thread_param.arg = arg;
thread_param.initialized = 0;
*thread = NULL;
/* Setup thread initialization synchronization */
if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) {
/* Should never happen on Windows */
return -1;
}
if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) {
/* Should never happen on Windows */
ZSTD_pthread_cond_destroy(&thread_param.initialized_cond);
return -1;
}
/* Spawn thread */
*thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL);
if (!thread) {
ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex);
ZSTD_pthread_cond_destroy(&thread_param.initialized_cond);
return errno;
}
/* Wait for thread to be initialized */
ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex);
while(!thread_param.initialized) {
ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex);
}
ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex);
ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex);
ZSTD_pthread_cond_destroy(&thread_param.initialized_cond);
return 0;
}
int ZSTD_pthread_join(ZSTD_pthread_t thread)
{
DWORD result;
if (!thread) return 0;
result = WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
switch (result) {
case WAIT_OBJECT_0:
return 0;
case WAIT_ABANDONED:
return EINVAL;
default:
return GetLastError();
}
}
#endif /* ZSTD_MULTITHREAD */
#if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32)
#define ZSTD_DEPS_NEED_MALLOC
#include "zstd_deps.h"
int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr)
{
*mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t));
if (!*mutex)
return 1;
return pthread_mutex_init(*mutex, attr);
}
int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex)
{
if (!*mutex)
return 0;
{
int const ret = pthread_mutex_destroy(*mutex);
ZSTD_free(*mutex);
return ret;
}
}
int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr)
{
*cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t));
if (!*cond)
return 1;
return pthread_cond_init(*cond, attr);
}
int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond)
{
if (!*cond)
return 0;
{
int const ret = pthread_cond_destroy(*cond);
ZSTD_free(*cond);
return ret;
}
}
#endif

View File

@@ -1,150 +0,0 @@
/**
* Copyright (c) 2016 Tino Reichardt
* All rights reserved.
*
* You can contact the author at:
* - zstdmt source repository: https://github.com/mcmilk/zstdmt
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#ifndef THREADING_H_938743
#define THREADING_H_938743
#include "debug.h"
#if defined (__cplusplus)
extern "C" {
#endif
#if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
/**
* Windows minimalist Pthread Wrapper
*/
#ifdef WINVER
# undef WINVER
#endif
#define WINVER 0x0600
#ifdef _WIN32_WINNT
# undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */
#include <windows.h>
#undef ERROR
#define ERROR(name) ZSTD_ERROR(name)
/* mutex */
#define ZSTD_pthread_mutex_t CRITICAL_SECTION
#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0)
#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a))
#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a))
#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a))
/* condition variable */
#define ZSTD_pthread_cond_t CONDITION_VARIABLE
#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0)
#define ZSTD_pthread_cond_destroy(a) ((void)(a))
#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE)
#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a))
#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a))
/* ZSTD_pthread_create() and ZSTD_pthread_join() */
typedef HANDLE ZSTD_pthread_t;
int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
void* (*start_routine) (void*), void* arg);
int ZSTD_pthread_join(ZSTD_pthread_t thread);
/**
* add here more wrappers as required
*/
#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */
/* === POSIX Systems === */
# include <pthread.h>
#if DEBUGLEVEL < 1
#define ZSTD_pthread_mutex_t pthread_mutex_t
#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b))
#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a))
#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a))
#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a))
#define ZSTD_pthread_cond_t pthread_cond_t
#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b))
#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a))
#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b))
#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a))
#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a))
#define ZSTD_pthread_t pthread_t
#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
#define ZSTD_pthread_join(a) pthread_join((a),NULL)
#else /* DEBUGLEVEL >= 1 */
/* Debug implementation of threading.
* In this implementation we use pointers for mutexes and condition variables.
* This way, if we forget to init/destroy them the program will crash or ASAN
* will report leaks.
*/
#define ZSTD_pthread_mutex_t pthread_mutex_t*
int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr);
int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex);
#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a))
#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a))
#define ZSTD_pthread_cond_t pthread_cond_t*
int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr);
int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond);
#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b))
#define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a))
#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a))
#define ZSTD_pthread_t pthread_t
#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d))
#define ZSTD_pthread_join(a) pthread_join((a),NULL)
#endif
#else /* ZSTD_MULTITHREAD not defined */
/* No multithreading support */
typedef int ZSTD_pthread_mutex_t;
#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0)
#define ZSTD_pthread_mutex_destroy(a) ((void)(a))
#define ZSTD_pthread_mutex_lock(a) ((void)(a))
#define ZSTD_pthread_mutex_unlock(a) ((void)(a))
typedef int ZSTD_pthread_cond_t;
#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0)
#define ZSTD_pthread_cond_destroy(a) ((void)(a))
#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b))
#define ZSTD_pthread_cond_signal(a) ((void)(a))
#define ZSTD_pthread_cond_broadcast(a) ((void)(a))
/* do not use ZSTD_pthread_t */
#endif /* ZSTD_MULTITHREAD */
#if defined (__cplusplus)
}
#endif
#endif /* THREADING_H_938743 */

View File

@@ -1,24 +0,0 @@
/*
* xxHash - Fast Hash algorithm
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* You can contact the author at :
* - xxHash homepage: https://cyan4973.github.io/xxHash/
* - xxHash source repository : https://github.com/Cyan4973/xxHash
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
/*
* xxhash.c instantiates functions defined in xxhash.h
*/
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
#define XXH_IMPLEMENTATION /* access definitions */
#include "xxhash.h"

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More