12 Commits

Author SHA1 Message Date
Red Bear OS 6e11964121 uefi: demote expected no-GPT and no-EDID fallbacks from warn to debug 2026-07-16 07:30:29 +09:00
Red Bear OS c78c3a63c0 BIOS: implement get_key_timeout with INT 16h/01h polling + INT 15h/86h delay
Fixes autoboot countdown blocking forever because the default trait impl
calls blocking get_key(). Uses non-destructive key check (INT 16h AH=01h)
with EDX sentinel to detect key availability without EFLAGS access, and
INT 15h AH=86h for 10ms polling intervals.
2026-07-12 05:02:08 +03:00
Red Bear OS 2f79630b0e Cargo.toml: 1.0.0+rb0.3.0 -> 1.0.0+rb0.3.1
Bootloader fork was the only Cat 2 fork that didn't get its
+rb suffix updated during the 0.3.0->0.3.1 sync-versions run.
Manual fix applied. Also regenerated its Cargo.lock to match
the new version.
2026-07-12 01:20:43 +03:00
Red Bear OS 6b43b7f9c5 0.3.0: bump local fork lockfile versions to +rb0.3.0 2026-07-06 20:41:30 +03:00
vasilito 62fa9f9a1b 0.3.0: bump version suffix to +rb0.3.0 2026-07-06 19:47:08 +03:00
vasilito ea5b2418e6 redbear: migrate bootloader patches into local fork
Apply the full Red Bear bootloader patch set:
- P0-gpt-partition-offset
- fix-uefi-alloc-panic
- redox.patch (Makefile/mk and misc fixes)
- P1-bootloader-timeout-and-default-resolution
- P2-live-preload-guard
- P3-uefi-live-image-safe-read
- P4-live-large-iso-boot
- P5-live-preload-cap-1gib

Also switch redoxfs dependency to the local fork path.
2026-07-06 08:03:08 +03:00
Red Bear OS 6c3c312819 fix: use local path deps for redox_syscall 2026-07-05 23:54:34 +03:00
Red Bear OS e7bc6a56dc version: use +rb0.2.5 build metadata instead of -rb0.2.5 pre-release
Semver pre-release suffix (-rb0.2.5) breaks Cargo's [patch.crates-io]
matching for transitive deps. Build metadata (+rb0.2.5) is semver-
compatible: ^0.9.0 matches 0.9.0+rb0.2.5, patch redirection works,
and the Red Bear suffix is still visible in the version string.
2026-07-05 09:16:12 +03:00
Red Bear OS db006c0b72 fork: add Red Bear author attribution to Cargo.toml 2026-07-05 08:48:16 +03:00
Red Bear OS 83a34a1515 fork: bump to -rb1 version suffix
Per local/AGENTS.md \xC2\xA7 "Category 2 - Local forks of upstream packages",
all Cat 2 forks must use the `<upstream-tag>-rb<N>` version convention. The
`-rb1` suffix is a Cargo pre-release identifier that prevents upstream
`<upstream-tag>` from silently substituting for this fork in transitive
dependency resolution.

- The base tag (e.g. 0.9.0 for redox_syscall) tracks upstream
  unchanged.
- The `rb1` part records that one Red Bear patch round has been
  applied on top of the upstream tag.

This is the initial policy enforcement pass. The branch is
considered unfrozen at this point; once a freeze is declared, future
`-rbN` increments will land on a frozen `0.X.Y` branch per
local/AGENTS.md.
2026-07-04 10:07:31 +03:00
Red Bear OS 3cc7ed909c bios: add -Zunstable-options for custom JSON target spec
Rust nightly requires -Zunstable-options for custom target JSON specs
(such as x86-unknown-none.json). Without it, the build fails with:
  error: error loading target specification: custom targets are
  unstable and require `-Zunstable-options`

UEFI already uses the built-in x86_64-unknown-uefi target, so it
didn't need this flag. The kernel recipe already has this fix; the
bootloader BIOS Makefile was missing it.
2026-06-28 04:40:40 +03:00
Red Bear OS 89c68d0738 Red Bear OS bootloader baseline from 0.1.0 pre-patched archive 2026-06-27 09:21:43 +03:00
1193 changed files with 7174 additions and 100712 deletions
-7
View File
@@ -1,7 +0,0 @@
[**.c]
indent_size = 4
indent_style = space
[**.yml]
indent_size = 4
indent_style = space
+2 -11
View File
@@ -1,11 +1,2 @@
.idea/
prefix/
sysroot/
**/target/
.gdb_history
*.patch
*.swp
*.swo
/.vim
.vscode/
/build
/target
+29 -81
View File
@@ -1,87 +1,35 @@
image: "redoxos/redoxer:latest"
variables:
GIT_SUBMODULE_STRATEGY: recursive
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "master" && $CI_PROJECT_NAMESPACE == "redox-os"'
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
before_script:
- apt-get install nasm
- rustup component add rust-src
stages:
- build
- cross-build
- test
before_script:
cargo install cbindgen
- host
build:i686:
stage: host
script:
- mkdir -p target/i686
- cd target/i686
- TARGET=x86-unknown-none make -f ${CI_PROJECT_DIR}/Makefile -C `pwd` `pwd`/bootloader.bin `pwd`/bootloader-live.bin
build:x86_64:
stage: host
script:
- mkdir -p target/x86_64
- cd target/x86_64
- TARGET=x86_64-unknown-uefi make -f ${CI_PROJECT_DIR}/Makefile -C `pwd` `pwd`/bootloader.efi `pwd`/bootloader-live.efi
build:aarch64:
stage: host
script:
- mkdir -p target/aarch64
- cd target/aarch64
- TARGET=aarch64-unknown-uefi make -f ${CI_PROJECT_DIR}/Makefile -C `pwd` `pwd`/bootloader.efi `pwd`/bootloader-live.efi
fmt:
stage: build
needs: []
script:
- rustup component add rustfmt-preview
- ./fmt.sh -- --check
clippy:
stage: build
needs: []
# TODO: remove when passed
allow_failure: true
script:
- ./check.sh --clippy
linux:
stage: build
script:
- rustup component add clippy
- ./check.sh --host
# - ./check.sh --host --clippy
x86_64:
stage: build
script:
- ./check.sh --arch=x86_64
i586:
stage: cross-build
script:
- ./check.sh --arch=i586
# - ./check.sh --arch=i586 --clippy
aarch64:
stage: cross-build
image: "redoxos/redoxer:aarch64"
script:
- ./check.sh --arch=aarch64
# - ./check.sh --arch=aarch64 --clippy
riscv64gc:
stage: cross-build
script:
- ./check.sh --arch=riscv64gc
# - ./check.sh --arch=riscv64gc --clippy
test:linux:
stage: test
needs: [linux]
script:
- ./check.sh --host --test
test:x86_64:
stage: test
needs: [x86_64]
script:
# timeout: https://gitlab.redox-os.org/redox-os/relibc/-/issues/238
- timeout -s KILL 9m ./check.sh --arch=x86_64 --test
test:aarch64:
stage: test
needs: [aarch64]
image: "redoxos/redoxer:aarch64"
# many issues that not exist in x86_64, and lack of interest to fix so far
allow_failure: true
when: manual
script:
- timeout -s KILL 9m ./check.sh --arch=aarch64 --test
#TODO: Enable more arch once dynamic linker working
stage: host
script:
- rustup component add rustfmt-preview
- cargo fmt -- --check
-7
View File
@@ -1,7 +0,0 @@
[submodule "openlibm"]
path = openlibm
url = https://gitlab.redox-os.org/redox-os/openlibm.git
branch = master
[submodule "src/dlmalloc-rs"]
path = dlmalloc-rs
url = https://gitlab.redox-os.org/redox-os/dlmalloc-rs.git
+2
View File
@@ -0,0 +1,2 @@
[editor]
auto-format = false
+5
View File
@@ -0,0 +1,5 @@
[[language]]
name = "rust"
# TODO: Add more targets (BIOS, x86_32)
# Uncomment this line and set cargo.target to your target to get accurate completions
# config = { cargo.target = "aarch64-unknown-uefi", check.targets = ["x86_64-unknown-uefi", "aarch64-unknown-uefi"] }
-123
View File
@@ -1,123 +0,0 @@
# Contributing
## Table of contents
1. [What to do](#what-to-do)
2. [Code style](#code-style)
3. [Sending merge requests](#sending-merge-requests)
4. [Writing tests](#writing-tests)
5. [Running tests](#running-tests)
Maintaining a libc is tough work, and we'd love some help!
## What to do
For now, we are still trying to get full libc compatibility before we move on to
any optimisation.
- We currently have a number of unimplemented functions. Search for
`unimplemented!()` and hop right in!
- If you notice any missing functionality, feel free to add it in
## Code style
We have a `rustfmt.toml` in the root directory of relibc. Please run `./fmt.sh`
before sending in any merge requests as it will automatically format your code.
With regards to general style:
### Where applicable, prefer using references to raw pointers
This is most obvious when looking at `stdio` functions. If raw pointers were
used instead of references, then the resulting code would be significantly
uglier. Instead try to check for pointer being valid with `pointer::as_ref()`
and `pointer::as_mut()` and then immediately use those references instead.
Internal functions should always take references.
### Use the c types exposed in our platform module instead of Rust's inbuilt integer types
This is so we can guarantee that everything works across platforms. While it is
generally accepted these days that an `int` has 32 bits (which matches against
an `i32`), some platforms have `int` as having 16 bits, and others have long as
being 32 bits instead of 64. If you use the types in platform, then we can
guarantee that your code will "just work" should we port relibc to a different
architecture.
### Use our internal functions
If you need to use a C string, don't reinvent the wheel. We have functions in
the platform module that convert C strings to Rust slices.
We also have structures that wrap files, wrap writable strings, and wrap various
other commonly used things that you should use instead of rolling your own.
## Sending merge requests
If you have sent us a merge request, first of all, thanks for taking your time
to help us!
The first thing to note is that we do most of our development on our
[GitLab server](https://gitlab.redox-os.org/redox-os/relibc), and as such it is
possible that none of the maintainers will see your merge request if it is
opened on GitHub.
In your merge request, please put in the description:
- What functions (if any) have been implemented or changed
- The rationale behind your merge request (e.g. why you thought this change was
required. If you are just implementing some functions, you can ignore this)
- Any issues that are related to the merge request
We have CI attached to our GitLab instance, so all merge requests are checked to
make sure that they are tested before they are merged. Please write tests for
the functions that you add/change and test locally on your own machine
***before*** submitting a merge request.
## Writing tests
Every function that gets written needs to have a test in C in order to make sure
it works as intended. Here are a few guidelines for writing good tests.
### Ensure that any literals you have are mapped to variables instead of being directly passed to a function.
Sometimes compilers take literals put into libc functions and run them
internally during compilation, which can cause some false positives. All tests
are compiled with `-fno-builtin`, which theoretically solves this issue, but
just in case, it'd be a good idea to map inputs to variables.
```c
#include "string.h"
#include "stdio.h"
int main(void) {
// Don't do this
printf("%d\n", strcspn("Hello", "Hi"));
// Do this
char *first = "Hello";
char *second = "Hi";
printf("%d\n", strcspn(first, second));
}
```
### Ensure your tests cover every section of code.
What happens if a string in `strcmp()` is shorter than the other string? What
happens if the first argument to `strcspn()` is longer than the second string?
In order to make sure that all functions work as expected, we ask that any tests
cover as much of the code that you have written as possible.
## Running tests
Running tests is an important part in trying to find bugs. Before opening a
merge request, we ask that you test on your own machine to make sure there are
no regressions.
You can run tests with `make test` in the root directory of relibc to compile
relibc, compile the tests and run them. This *will* print a lot of output to
stdout, so be warned!
You can test against verified correct output with `make verify` in the tests
directory. You will need to manually create the correct output and put it in the
tests/expected directory. Running any `make` commands in the tests directory
will ***not*** rebuild relibc, so you'll need to go back to the root directory
if you need to rebuild relibc.
Generated
+119 -502
View File
@@ -3,28 +3,25 @@
version = 4
[[package]]
name = "argon2"
version = "0.5.3"
name = "aes"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
dependencies = [
"base64ct",
"blake2",
"cfg-if",
"cipher",
"cpufeatures",
"password-hash",
]
[[package]]
name = "arrayvec"
version = "0.7.8"
name = "argon2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
[[package]]
name = "autocfg"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73"
dependencies = [
"base64ct",
"blake2",
]
[[package]]
name = "base64ct"
@@ -33,15 +30,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "bcrypt-pbkdf"
version = "0.10.0"
name = "bit_field"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2"
dependencies = [
"blowfish",
"pbkdf2",
"sha2",
]
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
@@ -67,64 +65,18 @@ dependencies = [
"generic-array",
]
[[package]]
name = "blowfish"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
dependencies = [
"byteorder",
"cipher",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b"
dependencies = [
"num-traits",
]
[[package]]
name = "cc"
version = "1.1.22"
source = "git+https://github.com/tea/cc-rs?branch=riscv-abi-arch-fix#588ceacb084af41415690c57688e338a32a1f1b4"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chrono"
version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"num-traits",
]
[[package]]
name = "chrono-tz"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3"
dependencies = [
"chrono",
"phf",
]
[[package]]
name = "cipher"
version = "0.4.4"
@@ -144,18 +96,6 @@ dependencies = [
"libc",
]
[[package]]
name = "crt0"
version = "0.1.0"
[[package]]
name = "crti"
version = "0.1.0"
[[package]]
name = "crtn"
version = "0.1.0"
[[package]]
name = "crypto-common"
version = "0.1.7"
@@ -178,22 +118,24 @@ dependencies = [
]
[[package]]
name = "dlmalloc"
version = "0.2.8"
name = "dmidecode"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5a070ca68f8ba202b05487d52b9ac56eaebb5b66cdd68d1a17e63174bb11e3b"
dependencies = [
"cfg-if",
"windows-sys",
"bitflags 1.3.2",
]
[[package]]
name = "drm-sys"
version = "0.8.1"
name = "endian-num"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8"
dependencies = [
"libc",
"linux-raw-sys",
]
checksum = "f8f59926911ef34d1efb9ea1ee8ca78385df62ce700ccf2bcb149011bd226888"
[[package]]
name = "fdt"
version = "0.2.0-alpha1"
source = "git+https://github.com/repnop/fdt.git?rev=2fb1409edd1877c714a0aa36b6a7c5351004be54#2fb1409edd1877c714a0aa36b6a7c5351004be54"
[[package]]
name = "generic-array"
@@ -205,30 +147,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "generic-rt"
version = "0.1.0"
[[package]]
name = "goblin"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17582616a7718cca54cec18e534a76c7c4aec11a8b9a85695712f262fd15a4c8"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "inout"
version = "0.1.4"
@@ -238,16 +156,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "ioslice"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e571352c8a3b89074d12e3ee5173ffe162159105352aaaf1fc5764da747e31b"
[[package]]
name = "ld_so"
version = "0.1.0"
[[package]]
name = "libc"
version = "0.2.186"
@@ -255,26 +163,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libm"
version = "0.2.16"
name = "linked_list_allocator"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.18+rb0.3.1"
checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897"
dependencies = [
"bitflags",
"libc",
"plain",
"spinning_top",
]
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "lock_api"
version = "0.4.14"
@@ -291,155 +187,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
[[package]]
name = "md-5"
version = "0.10.6"
name = "lz4_flex"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
checksum = "373f5eceeeab7925e0c1098212f2fbc4d416adec9d35051a6ab251e824c1854a"
[[package]]
name = "raw-cpuid"
version = "10.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
dependencies = [
"cfg-if",
"digest",
]
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "object"
version = "0.36.7"
source = "git+https://gitlab.redox-os.org/andypython/object#7270e3f0d06e5ef4c2b80abc6166d31f4ddf4fea"
dependencies = [
"memchr",
]
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest",
"hmac",
"sha2",
]
[[package]]
name = "phf"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_shared"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
dependencies = [
"siphasher",
]
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "posix-regex"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66df580334caab2f744839ab1be85493d7ec731a92d6cf928008ab0b212bf3bc"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
dependencies = [
"rand_core 0.10.1",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rand_jitter"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdcd80e68f0a8f9ca5ec7cfd02fd5fbb8fbe6ef4e9b90ea2f48bb929b74f88e"
dependencies = [
"libc",
"rand_core 0.10.1",
"windows-sys",
]
[[package]]
name = "rand_xorshift"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60aa6af80be32871323012e02e6e65f8a7cc7890931ae421d217ad8fe0df2ccf"
dependencies = [
"rand_core 0.10.1",
]
[[package]]
name = "redox-ioctl"
version = "0.1.0"
dependencies = [
"drm-sys",
"redox_syscall",
"bitflags 1.3.2",
]
[[package]]
@@ -449,94 +208,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54ec1b67c01c63545205ea6d218b336751399f0d8974c1a635c28604bedb81bc"
[[package]]
name = "redox-rt"
version = "0.1.0"
name = "redox_bootloader"
version = "1.0.0+rb0.3.1"
dependencies = [
"bitflags",
"generic-rt",
"goblin",
"ioslice",
"libredox",
"plain",
"redox-path",
"redox_syscall",
]
[[package]]
name = "redox_event"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5018d583d6d2f5499352aea8d177e9067d1eb03ab17c78169d5ba7a30001b15"
dependencies = [
"bitflags",
"libredox",
"bitflags 1.3.2",
"byteorder",
"dmidecode",
"fdt",
"linked_list_allocator",
"log",
"redox_syscall",
"redox_uefi",
"redox_uefi_std",
"redoxfs",
"spin",
"x86",
]
[[package]]
name = "redox_syscall"
version = "0.9.0+rb0.3.1"
dependencies = [
"bitflags",
"bitflags 2.13.0",
]
[[package]]
name = "relibc"
version = "0.2.5+rb0.3.1"
name = "redox_uefi"
version = "0.1.14"
source = "git+https://gitlab.redox-os.org/redox-os/uefi.git#26a499eeaf55d42fb24206830345e26fb8f5f835"
[[package]]
name = "redox_uefi_alloc"
version = "0.1.14"
source = "git+https://gitlab.redox-os.org/redox-os/uefi.git#26a499eeaf55d42fb24206830345e26fb8f5f835"
dependencies = [
"redox_uefi",
]
[[package]]
name = "redox_uefi_std"
version = "0.1.14"
source = "git+https://gitlab.redox-os.org/redox-os/uefi.git#26a499eeaf55d42fb24206830345e26fb8f5f835"
dependencies = [
"redox_uefi",
"redox_uefi_alloc",
]
[[package]]
name = "redoxfs"
version = "0.9.1+rb0.3.1"
dependencies = [
"aes",
"argon2",
"arrayvec",
"base64ct",
"bcrypt-pbkdf",
"bitflags",
"cbitset",
"cc",
"chrono",
"chrono-tz",
"dlmalloc",
"generic-rt",
"ioslice",
"bitflags 2.13.0",
"endian-num",
"libc",
"libm",
"libredox",
"log",
"md-5",
"memchr",
"object",
"pbkdf2",
"plain",
"posix-regex",
"rand",
"rand_jitter",
"rand_xorshift",
"redox-ioctl",
"lz4_flex",
"redox-path",
"redox-rt",
"redox_event",
"redox_syscall",
"sc",
"scrypt",
"sha-crypt",
"sha2",
"spin",
"unicode-width",
"seahash",
"uuid",
"xts-mode",
]
[[package]]
name = "salsa20"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
dependencies = [
"cipher",
]
[[package]]
name = "sc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "010e18bd3bfd1d45a7e666b236c78720df0d9a7698ebaa9c1c559961eb60a38b"
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -544,69 +280,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scroll"
version = "0.13.0"
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "scrypt"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
dependencies = [
"password-hash",
"pbkdf2",
"salsa20",
"sha2",
]
[[package]]
name = "sha-crypt"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88e79009728d8311d42d754f2f319a975f9e38f156fd5e422d2451486c78b286"
dependencies = [
"base64ct",
"sha2",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "spin"
@@ -617,23 +294,21 @@ dependencies = [
"lock_api",
]
[[package]]
name = "spinning_top"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
dependencies = [
"lock_api",
]
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "typenum"
version = "1.20.1"
@@ -641,16 +316,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "unicode-ident"
version = "1.0.24"
name = "uuid"
version = "1.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53"
[[package]]
name = "version_check"
@@ -659,74 +328,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "windows-sys"
version = "0.59.0"
name = "x86"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
dependencies = [
"windows-targets",
"bit_field",
"bitflags 1.3.2",
"raw-cpuid",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
name = "xts-mode"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
checksum = "09cbddb7545ca0b9ffa7bdc653e8743303e1712687a6918ced25f2cdbed42520"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"byteorder",
"cipher",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+38 -134
View File
@@ -1,153 +1,57 @@
[package]
name = "relibc"
version = "0.2.5+rb0.3.1"
name = "redox_bootloader"
version = "1.0.0+rb0.3.1"
authors = ["Jeremy Soller <jackpot51@gmail.com>", "vasilito <adminpupkin@gmail.com>"]
edition = "2024"
# UEFI uses bin target
[[bin]]
name = "bootloader"
path = "src/main.rs"
# BIOS uses lib target
[lib]
name = "relibc"
name = "bootloader"
path = "src/main.rs"
crate-type = ["staticlib"]
[workspace]
members = [
"src/crt0",
"src/crti",
"src/crtn",
"redox-rt",
"ld_so",
"generic-rt",
]
exclude = ["tests", "dlmalloc-rs"]
[workspace.lints.clippy]
borrow_as_ptr = "deny"
cast_lossless = "warn" # TODO review occurrences
cast_possible_truncation = "allow" # TODO review occurrences
cast_possible_wrap = "allow" # TODO review occurrences
cast_precision_loss = "allow" # TODO review occurrences
cast_ptr_alignment = "allow" # TODO review occurrences
cast_sign_loss = "allow" # TODO review occurrences
ignored_unit_patterns = "deny"
implicit_clone = "deny"
manual_let_else = "deny"
missing_errors_doc = "allow" # TODO review occurrences
missing_panics_doc = "allow" # TODO review occurrences
missing_safety_doc = "allow" # TODO review occurrences
mut_from_ref = "deny"
precedence = "deny"
ptr_as_ptr = "warn" # TODO review occurrences
ptr_cast_constness = "warn" # TODO review occurrences
ptr_offset_by_literal = "deny"
ref_as_ptr = "warn" # TODO review occurrences
type_complexity = "allow" # TODO review occurrences
upper_case_acronyms = "allow" # TODO review occurrences
zero_ptr = "deny" # must allow on public constants due to cbindgen issue
[workspace.lints.rust]
dangling_pointers_from_temporaries = "deny"
dead_code = "allow" # TODO review occuurences
deprecated = "deny"
improper_ctypes_definitions = "deny"
internal_features = "allow" # core_intrinsics and lang_items
irrefutable_let_patterns = "deny"
mismatched_lifetime_syntaxes = "deny"
non_camel_case_types = "allow" # needed for most POSIX type names
non_snake_case = "allow" # TODO review occuurences
non_upper_case_globals = "allow" # TODO review occuurences
unexpected_cfgs = "deny"
unpredictable_function_pointer_comparisons = "deny"
unreachable_code = "allow" # TODO review occuurences
unsafe_op_in_unsafe_fn = "deny"
unused_imports = "deny"
unused_must_use = "deny"
unused_mut = "deny"
unused_unsafe = "deny"
unused_variables = "allow" # TODO review occurrences (too many for now)
[lints]
workspace = true
[workspace.dependencies]
bitflags = "2"
ioslice = { version = "0.6", default-features = false }
plain = "0.2"
redox-path = "0.4.0"
redox_protocols = { package = "libredox", path = "../libredox", default-features = false, features = ["protocol"] }
redox_syscall = { path = "../syscall" }
[build-dependencies]
cc = "1"
[dependencies]
bitflags.workspace = true
arrayvec = { version = "0.7.6", default-features = false }
cbitset = "0.2"
posix-regex = { version = "0.1.4", features = ["no_std"] }
bitflags = "1.3.2"
linked_list_allocator = "0.10.5"
log = "0.4.17"
redox_syscall = { path = "../syscall" }
spin = "0.9.5"
rand = { version = "0.10", default-features = false }
rand_xorshift = "0.5"
rand_jitter = "0.6"
memchr = { version = "2.2.0", default-features = false }
plain.workspace = true
unicode-width = "0.1"
__libc_only_for_layout_checks = { package = "libc", version = "0.2.149", optional = true }
md5-crypto = { package = "md-5", version = "0.10.6", default-features = false }
sha-crypt = { version = "0.5", default-features = false }
base64ct = { version = "1.6", default-features = false, features = ["alloc"] }
bcrypt-pbkdf = { version = "0.10", default-features = false, features = [
"alloc",
] }
scrypt = { version = "0.11", default-features = false, features = ["simple"] }
pbkdf2 = { version = "0.12", features = ["sha2"] }
sha2 = { version = "0.10", default-features = false }
generic-rt = { path = "generic-rt" }
chrono-tz = { version = "0.10", default-features = false }
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
libm = "0.2"
log = "0.4"
spin = "0.9.8"
argon2 = "0.5.3"
[dependencies.dlmalloc]
path = "dlmalloc-rs"
[dependencies.redoxfs]
path = "../redoxfs"
default-features = false
features = ["c_api"]
features = ["log"]
[dependencies.object]
version = "0.36.7"
git = "https://gitlab.redox-os.org/andypython/object"
default-features = false
features = ["elf", "read_core"]
[target.'cfg(target_os = "uefi")'.dependencies]
redox_uefi = { git = "https://gitlab.redox-os.org/redox-os/uefi.git" }
redox_uefi_std = { git = "https://gitlab.redox-os.org/redox-os/uefi.git" }
[target.'cfg(target_os = "linux")'.dependencies]
sc = "0.2.7"
#TODO: riscv cannot use target_os = "uefi" at this time
[target.'cfg(target_arch = "riscv64")'.dependencies]
redox_uefi = { git = "https://gitlab.redox-os.org/redox-os/uefi.git" }
redox_uefi_std = { git = "https://gitlab.redox-os.org/redox-os/uefi.git" }
[target.'cfg(target_os = "redox")'.dependencies]
redox_syscall.workspace = true
redox-rt = { path = "redox-rt" }
redox-path.workspace = true
redox_event = { version = "0.4.8", default-features = false, features = ["redox_syscall"] }
ioslice.workspace = true
redox-ioctl = { path = "redox-ioctl" }
redox_protocols.workspace = true
[target."aarch64-unknown-uefi".dependencies]
dmidecode = "0.8.0"
[target."x86_64-unknown-uefi".dependencies]
x86 = "0.52.0"
[target.'cfg(any(target_arch = "aarch64", target_arch = "riscv64"))'.dependencies]
byteorder = { version = "1", default-features = false }
fdt = { git = "https://github.com/repnop/fdt.git", rev = "2fb1409edd1877c714a0aa36b6a7c5351004be54" }
[features]
# to enable trace level, take out this `no_trace`
default = ["check_against_libc_crate", "no_trace"]
check_against_libc_crate = ["__libc_only_for_layout_checks"]
math_libm = []
no_trace = ["log/release_max_level_debug"]
# for very verbose activity beyond trace level
trace_tls = []
default = []
live = []
serial_debug = []
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[patch.crates-io]
cc-11 = { git = "https://github.com/tea/cc-rs", branch = "riscv-abi-arch-fix", package = "cc" }
redox_syscall = { path = "../syscall" }
libredox = { path = "../libredox" }
redoxfs = { path = "../redoxfs" }
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018 Redox OS
Copyright (c) 2017-2022 Redox OS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+19 -222
View File
@@ -1,229 +1,26 @@
include config.mk
TARGET?=x86_64-unknown-uefi
SOURCE:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))
BUILD:=$(CURDIR)
export RUST_TARGET_PATH?=$(SOURCE)/targets
CARGO_ARGS=--release --locked --target $(TARGET) \
-Z build-std=core,alloc \
-Z build-std-features=compiler-builtins-mem
CARGO?=cargo
CARGO_TEST?=$(CARGO)
CARGO_COMMON_FLAGS=-Z build-std=core,alloc,compiler_builtins
CARGOFLAGS?=$(CARGO_COMMON_FLAGS)
CC_WRAPPER?=
RUSTCFLAGS?=
LINKFLAGS?=-lgcc
USE_RUST_LIBM?=
TESTBIN?=
export OBJCOPY?=objcopy
export CARGO_TARGET_DIR?=$(shell pwd)/target
BUILD?=$(CARGO_TARGET_DIR)/$(TARGET)
CARGOFLAGS+=--target=$(TARGET)
EXCEPT_MATH=-not -name "math"
FEATURE_MATH=
ifneq ($(USE_RUST_LIBM),)
FEATURE_MATH=--features math_libm
EXCEPT_MATH=
endif
TARGET_HEADERS?=$(BUILD)/include
export CFLAGS=-I$(TARGET_HEADERS)
PROFILE?=release
HEADERS_UNPARSED=$(shell find src/header -mindepth 1 -maxdepth 1 -type d -not -name "_*" $(EXCEPT_MATH) -printf "%f\n")
HEADERS_DEPS=$(shell find src/header -type f \( -name "cbindgen.toml" -o -name "*.rs" \))
#HEADERS=$(patsubst %,%.h,$(subst _,/,$(HEADERS_UNPARSED)))
SRC=\
Cargo.* \
$(shell find src/ redox-rt/src/ ld_so/src/ redox-ioctl/src/ include/ -type f)
BUILTINS_VERSION=0.1.70
.PHONY: all clean fmt install install-libs install-headers install-tests libs headers submodules test
all: | headers libs
headers: $(HEADERS_DEPS)
rm -rf $(TARGET_HEADERS)
mkdir -p $(TARGET_HEADERS)
cp -r include/* $(TARGET_HEADERS)
ifeq ($(USE_RUST_LIBM),)
cp "openlibm/include"/*.h $(TARGET_HEADERS)
cp "openlibm/src"/*.h $(TARGET_HEADERS)
endif
@set -e ; \
for header in $(HEADERS_UNPARSED); do \
if test -f "src/header/$$header/cbindgen.toml"; then \
echo -e "\033[0;36;49mWriting Header $$header\033[0m"; \
out=`echo "$$header" | sed 's/_/\//g'`; \
out="$(TARGET_HEADERS)/$$out.h"; \
cat "src/header/$$header/cbindgen.toml" cbindgen.globdefs.toml \
| cbindgen "src/header/$$header/mod.rs" --config=/dev/stdin --output "$$out"; \
fi \
done; echo -e "\033[0;36;49mAll headers written\033[0m";
include $(SOURCE)/mk/$(TARGET).mk
clean:
$(CARGO) clean
$(MAKE) -C tests clean
rm -rf sysroot
rm -rf build target
check:
$(CARGO) check
fmt:
./fmt.sh
install-headers: headers libs
mkdir -pv "$(DESTDIR)/include"
cp -rv "$(TARGET_HEADERS)"/* "$(DESTDIR)/include"
libs: \
$(BUILD)/$(PROFILE)/libc.a \
$(BUILD)/$(PROFILE)/libc.so \
$(BUILD)/$(PROFILE)/crt0.o \
$(BUILD)/$(PROFILE)/crti.o \
$(BUILD)/$(PROFILE)/crtn.o \
$(BUILD)/$(PROFILE)/ld.so
install-libs: headers libs
mkdir -pv "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/libc.a" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/libc.so" "$(DESTDIR)/lib"
ln -vnfs libc.so "$(DESTDIR)/lib/libc.so.6"
cp -v "$(BUILD)/$(PROFILE)/crt0.o" "$(DESTDIR)/lib"
ln -vnfs crt0.o "$(DESTDIR)/lib/crt1.o"
ln -vnfs crt0.o "$(DESTDIR)/lib/Scrt1.o"
cp -v "$(BUILD)/$(PROFILE)/crti.o" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/crtn.o" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/ld.so" "$(DESTDIR)/$(LD_SO_PATH)"
ifeq ($(USE_RUST_LIBM),)
cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a"
else
$(AR) -rcs "$(DESTDIR)/lib/libm.a"
endif
# Empty libraries for dl, pthread, and rt
$(AR) -rcs "$(DESTDIR)/lib/libdl.a"
$(AR) -rcs "$(DESTDIR)/lib/libpthread.a"
$(AR) -rcs "$(DESTDIR)/lib/librt.a"
install-tests: tests
$(MAKE) -C tests
mkdir -p "$(DESTDIR)/relibc-tests"
cp -vr tests/build_$(TARGET)/* "$(DESTDIR)/relibc-tests/"
install: install-headers install-libs
submodules:
git submodule sync
git submodule update --init --recursive
sysroot:
@mkdir -p $@
.PHONY: sysroot/$(TARGET)
sysroot/$(TARGET): | sysroot
rm -rf $@
rm -rf $@.partial
mkdir -p $@.partial
$(MAKE) install DESTDIR=$(shell pwd)/$@.partial
mv $@.partial $@
touch $@
test: sysroot/$(TARGET)
# TODO: Fix SIGILL when running cargo test
# $(CARGO_TEST) test
$(MAKE) -C tests run
test-once: sysroot/$(TARGET)
$(MAKE) -C tests run-once TESTBIN=$(TESTBIN)
$(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/libc.a
$(CC) -nostdlib \
-shared \
-Wl,--gc-sections \
-Wl,-z,pack-relative-relocs \
-Wl,--sort-common \
-Wl,--whole-archive $^ -Wl,--no-whole-archive \
-Wl,-soname,libc.so.6 \
$(LINKFLAGS) \
-o $@
$(BUILD)/$(PROFILE)/ld.so: $(BUILD)/$(PROFILE)/ld_so.o $(BUILD)/$(PROFILE)/libc.a
# TODO: merge ld.so with libc.so: --dynamic-list=dynamic-list-file
$(LD) --shared -Bsymbolic --no-relax -T ld_so/ld_script/$(TARGET).ld --gc-sections $^ -o $@
$(BUILD)/$(PROFILE)/libc.a: $(BUILD)/$(PROFILE)/librelibc.a $(BUILD)/openlibm/libopenlibm.a
echo "create $@" > "$@.mri"
for lib in $^; do\
echo "addlib $$lib" >> "$@.mri"; \
done
echo "save" >> "$@.mri"
echo "end" >> "$@.mri"
$(AR) -M < "$@.mri"
# Debug targets
$(BUILD)/debug/librelibc.a: $(SRC)
$(CARGO) rustc $(CARGOFLAGS) $(FEATURE_MATH) -- --emit link=$@ -g -C debug-assertions=no $(RUSTCFLAGS)
./renamesyms.sh "$@" "$(BUILD)/debug/deps/"
./stripcore.sh "$@"
touch $@
$(BUILD)/debug/crt0.o: $(SRC)
$(CARGO) rustc --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/debug/crti.o: $(SRC)
$(CARGO) rustc --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/debug/crtn.o: $(SRC)
$(CARGO) rustc --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/debug/ld_so.o: $(SRC)
$(CARGO) rustc --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort -g -C debug-assertions=no $(RUSTCFLAGS)
touch $@
# Release targets
$(BUILD)/release/librelibc.a: $(SRC)
$(CARGO) rustc --release $(CARGOFLAGS) $(FEATURE_MATH) -- --emit link=$@ $(RUSTCFLAGS)
@# TODO: Better to only allow a certain whitelisted set of symbols? Perhaps
@# use some cbindgen hook, specify them manually, or grep for #[unsafe(no_mangle)].
./renamesyms.sh "$@" "$(BUILD)/release/deps/"
./stripcore.sh "$@"
touch $@
$(BUILD)/release/crt0.o: $(SRC)
$(CARGO) rustc --release --manifest-path src/crt0/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/crti.o: $(SRC)
$(CARGO) rustc --release --manifest-path src/crti/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/crtn.o: $(SRC)
$(CARGO) rustc --release --manifest-path src/crtn/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
$(BUILD)/release/ld_so.o: $(SRC)
$(CARGO) rustc --release --manifest-path ld_so/Cargo.toml $(CARGOFLAGS) -- --emit obj=$@ -C panic=abort $(RUSTCFLAGS)
touch $@
# Other targets
$(BUILD)/openlibm: openlibm
rm -rf $@ $@.partial
$(BUILD)/filesystem:
mkdir -p $(BUILD)
cp -r $< $@.partial
rm -f $@.partial
mkdir $@.partial
fallocate -l 1MiB $@.partial/kernel
mv $@.partial $@
touch $@
ifeq ($(USE_RUST_LIBM),)
$(BUILD)/openlibm/libopenlibm.a: $(BUILD)/openlibm $(BUILD)/$(PROFILE)/librelibc.a
$(MAKE) -s AR=$(AR) CC="$(CC_WRAPPER) $(CC)" LD=$(LD) CPPFLAGS="$(CPPFLAGS) -fno-stack-protector -I$(shell pwd)/include -I$(TARGET_HEADERS)" -C $< libopenlibm.a
./renamesyms.sh "$@" "$(BUILD)/release/deps/"
else
$(BUILD)/openlibm/libopenlibm.a:
mkdir -p "$(BUILD)/openlibm"
$(AR) -rcs "$(BUILD)/openlibm/libopenlibm.a"
endif
$(BUILD)/filesystem.bin: $(BUILD)/filesystem
mkdir -p $(BUILD)
rm -f $@.partial
fallocate -l 254MiB $@.partial
redoxfs-ar $@.partial $<
mv $@.partial $@
+42 -153
View File
@@ -1,173 +1,62 @@
# Redox C Library (relibc)
# Bootloader
relibc is a portable C standard library written in Rust and is under heavy development, this library contains the following items:
Redox OS Bootloader
- C, Linux, BSD functions and extensions
- POSIX compatibility layer
- Interfaces for system components
## Requirements
The motivation for this project is twofold: Reduce issues that the Redox developers were having with [newlib](https://sourceware.org/newlib/), and create a more stable and safe alternative to C standard libraries written in C. It is mainly designed to be used under Redox, as an alternative to newlib, but it also supports Linux via the [sc](https://crates.io/crates/sc) crate.
These software needs to be available on the PATH at build time:
Currently Redox and Linux are supported.
+ [mtools](https://www.gnu.org/software/mtools/)
+ [nasm](https://nasm.us/)
+ [redoxfs-ar](https://gitlab.redox-os.org/redox-os/redoxfs)
## `redox-rt`
`redox-rt` is a runtime library that provides much of the code that enables POSIX on Redox, like `fork`, `exec`, signal handling, etc.
Relibc uses it as backend in `src/platform/redox`, and it's intended to eventually be usable independently, without relibc.
## Repository Layout
- `include` - Header files (mostly macros and variadic functions `cbindgen` can't generate)
- `src` - Source files
- `src/c` - C code
- `src/crt0` - Runtime code
- `src/crti` - Runtime code
- `src/crtn` - Runtime code
- `src/header` - Header files implementation
- `src/header/*` - Each folder has a `cbindgen.toml` file, it generates a C-to-Rust interface and header files
- `src/ld_so` - Dynamic loader code
- `src/platform` - Platform-specific and common code
- `src/platform/redox` - Redox-specific code
- `src/platform/linux` - Linux-specific code
- `src/pthread` - pthread implementation
- `src/sync` - Synchronization primitives
- `tests` - C tests (each MR needs to give success in all of them)
## Download the sources
To download the relibc sources run the following command:
## Building
```sh
git clone --recursive https://gitlab.redox-os.org/redox-os/relibc
make TARGET=<triplet> BUILD=build all
```
## Build Instructions
The `<triplet>` is one of:
To build relibc out of the Redox build system, do the following steps:
| ARCH | Boot Mode | Triplets |
|---|---|---|
| `i686` | BIOS | `x86-unknown-none` |
| `x86_64` | BIOS | `x86-unknown-none` |
| `x86_64` | UEFI | `x86_64-unknown-uefi` |
| `aarch64` | UEFI | `aarch64-unknown-uefi` |
| `riscv64gc` | UEFI | `riscv64gc-unknown-uefi` |
### Dependencies
See [mk directory](./mk) for more information of how the build is working.
- Install `cbindgen`
## Entry points
Please read [Boot Process](https://doc.redox-os.org/book/boot-process.html) in the Redox OS Book for an introductory guide.
In this source code, some interesting files for entry points are:
+ BIOS boot stages: [asm/x86-unknown-none/bootloader.asm](./asm/x86-unknown-none/bootloader.asm)
+ BIOS boot entry: `fn start` at [src/os/bios/mod.rs](./src/os/bios/mod.rs)
+ UEFI boot entry: `fn main` at [src/os/uefi/mod.rs](src/os/uefi/mod.rs)
+ Common boot process: `fn main` at [src/main.rs](src/main.rs)
+ UEFI kernel entry: `fn kernel_entry` in each arch:
- `x86_64`: [src/os/uefi/arch/x86_64.rs](src/os/uefi/arch/x86_64.rs)
- `aarch64`: [src/os/uefi/arch/aarch64.rs](src/os/uefi/arch/aarch64.rs)
- `riscv64gc`: [src/os/uefi/arch/riscv64/mod.rs](src/os/uefi/arch/riscv64/mod.rs)
## Debugging
### QEMU
```sh
cargo install cbindgen
make TARGET=<triplet> BUILD=build qemu
```
#### Install the `expect` tool
## How To Contribute
- Debian, Ubuntu and PopOS:
To learn how to contribute to this system component you need to read the following document:
```sh
sudo apt install expect
```
- [CONTRIBUTING.md](https://gitlab.redox-os.org/redox-os/redox/-/blob/master/CONTRIBUTING.md)
- Fedora:
## Development
```sh
sudo dnf install expect
```
- Arch Linux:
```sh
sudo pacman -S expect
```
### Build Relibc
To build the relibc library objects, run the following command:
```sh
make all
```
- Clean old library objects and tests
```sh
make clean
```
## Build relibc inside the Redox build system
Inside of your Redox build system, run:
```sh
make prefix
```
If you need to rebuild `relibc` for testing a Cookbook recipe, run:
```sh
touch relibc
make prefix r.recipe-name
```
Touching (changing the "last modified time" of) the `relibc` folder is needed to trigger recompilation for `make prefix`. Replace `recipe-name` with your desired recipe name.
Note: Do not edit `relibc` inside `prefix` folder! Do your work on `relibc` folder directly inside your Redox build system instead.
## Tests
Relibc has a test suite that also runs every time a new commit get pushed. You can see `.gitlab-ci.yml` to see how it's being executed. That being said, `./check.sh` is the recommended way to run tests. Here's few examples:
+ `./check.sh` - Run build, without running the test
+ `./check.sh --test` - Run all tests in x86_64 Redox using Redoxer
+ `./check.sh --test --host` - Run all tests in host (Linux)
+ `./check.sh --test --arch=aarch64` - Run all tests in specified arch
- Arch can be `x86_64`, `aarch64`, `i586`, or `riscv64gc`
+ `./check.sh --test=stdio/printf` - Run a single test
- Can be combined with `--host` or `--arch`
- Will run statically linked test in Linux, dynamically linked in Redox
Couple of notes:
- Relibc and its tests will rebuild if files are changed, however switching between arch or host requires you to run `make clean`
- Redoxer is needed to run tests for Redox without `--host`. You can install it using `cargo install redoxer`
- Tests can hang, the test runner can anticipate this, assuming the kernel doesn't hang too.
## Issues
#### I'm building for my own platform which I run, and am getting `x86_64-linux-gnu-ar: command not found` (or similar)
The Makefile expects GNU compiler tools prefixed with the platform specifier, as would be present when you installed a cross compiler. Since you are building for your own platform, some Linux distributions (like Manjaro) don't install/symlink the prefixed executables.
An easy fix would be to replace the corresponding lines in `config.mk`, e.g.
```diff
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
- export CC=x86_64-linux-gnu-gcc
- export LD=x86_64-linux-gnu-ld
- export AR=x86_64-linux-gnu-ar
- export NM=x86_64-linux-gnu-nm
+ export CC=gcc
+ export LD=ld
+ export AR=ar
+ export NM=nm
export OBJCOPY=objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
endif
```
## Contributing
Before starting to contribute, read [this](CONTRIBUTING.md) document.
## Supported OSes
- Redox OS
- Linux
## Supported architectures
- i586 (Intel/AMD)
- x86_64 (Intel/AMD)
- aarch64 (ARM64)
- riscv64gc (RISC-V)
## Funding - _Unix-style Signals and Process Management_
This project is funded through [NGI Zero Core](https://nlnet.nl/core), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/RedoxOS-Signals).
[<img src="https://nlnet.nl/logo/banner.png" alt="NLnet foundation logo" width="20%" />](https://nlnet.nl)
[<img src="https://nlnet.nl/image/logos/NGI0_tag.svg" alt="NGI Zero Logo" width="20%" />](https://nlnet.nl/core)
To learn how to do development with this system component inside the Redox build system you need to read the [Build System](https://doc.redox-os.org/book/build-system-reference.html) and [Coding and Building](https://doc.redox-os.org/book/coding-and-building.html) pages.
+17
View File
@@ -0,0 +1,17 @@
interrupt_vector_table:
b . @ Reset
b .
b . @ SWI instruction
b .
b .
b .
b .
b .
.comm stack, 0x10000 @ Reserve 64k stack in the BSS
_start:
.globl _start
ldr sp, =stack+0x10000 @ Set up the stack
bl kstart @ Jump to the main function
1:
b 1b @ Halt
+31
View File
@@ -0,0 +1,31 @@
sectalign off
; stage 1 is sector 0, loaded at 0x7C00
%include "stage1.asm"
; GPT area from sector 1 to 33, loaded at 0x7E00
times (33*512) db 0
; stage 2, loaded at 0xC000
stage2:
%include "stage2.asm"
align 512, db 0
stage2.end:
; the maximum size of stage2 is 4 KiB
times (4*1024)-($-stage2) db 0
; ISO compatibility, uses up space until 0x12400
%include "iso.asm"
times 3072 db 0 ; Pad to 0x13000
; stage3, loaded at 0x13000
stage3:
%defstr STAGE3_STR %[STAGE3]
incbin STAGE3_STR
align 512, db 0
.end:
; the maximum size of the boot loader portion is 384 KiB
times (384*1024)-($-$$) db 0
+176
View File
@@ -0,0 +1,176 @@
SECTION .text
USE16
cpuid_required_features:
.edx equ cpuid_edx.fpu | cpuid_edx.pse | cpuid_edx.pge | cpuid_edx.fxsr
.ecx equ 0
cpuid_check:
; If bit 21 of EFLAGS can be changed, then CPUID is supported
pushfd ;Save EFLAGS
pushfd ;Store EFLAGS
xor dword [esp],0x00200000 ;Invert the ID bit in stored EFLAGS
popfd ;Load stored EFLAGS (with ID bit inverted)
pushfd ;Store EFLAGS again (ID bit may or may not be inverted)
pop eax ;eax = modified EFLAGS (ID bit may or may not be inverted)
xor eax,[esp] ;eax = whichever bits were changed
popfd ;Restore original EFLAGS
test eax,0x00200000 ;eax = zero if ID bit can't be changed, else non-zero
jz .no_cpuid
mov eax, 1
cpuid
and edx, cpuid_required_features.edx
cmp edx, cpuid_required_features.edx
jne .error
and ecx, cpuid_required_features.ecx
cmp ecx, cpuid_required_features.ecx
jne .error
ret
.no_cpuid:
mov si, .msg_cpuid
call print
mov si, .msg_line
call print
jmp .halt
.error:
push ecx
push edx
mov si, .msg_features
call print
mov si, .msg_line
call print
mov si, .msg_edx
call print
pop ebx
push ebx
shr ebx, 16
call print_hex
pop ebx
call print_hex
mov si, .msg_must_contain
call print
mov ebx, cpuid_required_features.edx
shr ebx, 16
call print_hex
mov ebx, cpuid_required_features.edx
call print_hex
mov si, .msg_line
call print
mov si, .msg_ecx
call print
pop ebx
push ebx
shr ebx, 16
call print_hex
pop ebx
call print_hex
mov si, .msg_must_contain
call print
mov ebx, cpuid_required_features.ecx
shr ebx, 16
call print_hex
mov ebx, cpuid_required_features.ecx
call print_hex
mov si, .msg_line
call print
.halt:
cli
hlt
jmp .halt
.msg_cpuid: db "CPUID not supported",0
.msg_features: db "Required CPU features are not present",0
.msg_line: db 13,10,0
.msg_edx: db "EDX ",0
.msg_ecx: db "ECX ",0
.msg_must_contain: db " must contain ",0
cpuid_edx:
.fpu equ 1 << 0
.vme equ 1 << 1
.de equ 1 << 2
.pse equ 1 << 3
.tsc equ 1 << 4
.msr equ 1 << 5
.pae equ 1 << 6
.mce equ 1 << 7
.cx8 equ 1 << 8
.apic equ 1 << 9
.sep equ 1 << 11
.mtrr equ 1 << 12
.pge equ 1 << 13
.mca equ 1 << 14
.cmov equ 1 << 15
.pat equ 1 << 16
.pse_36 equ 1 << 17
.psn equ 1 << 18
.clfsh equ 1 << 19
.ds equ 1 << 21
.acpi equ 1 << 22
.mmx equ 1 << 23
.fxsr equ 1 << 24
.sse equ 1 << 25
.sse2 equ 1 << 26
.ss equ 1 << 27
.htt equ 1 << 28
.tm equ 1 << 29
.ia64 equ 1 << 30
.pbe equ 1 << 31
cpuid_ecx:
.sse3 equ 1 << 0
.pclmulqdq equ 1 << 1
.dtes64 equ 1 << 2
.monitor equ 1 << 3
.ds_cpl equ 1 << 4
.vmx equ 1 << 5
.smx equ 1 << 6
.est equ 1 << 7
.tm2 equ 1 << 8
.ssse3 equ 1 << 9
.cnxt_id equ 1 << 10
.sdbg equ 1 << 11
.fma equ 1 << 12
.cmpxchg16b equ 1 << 13
.xtpr equ 1 << 14
.pdcm equ 1 << 15
.pcid equ 1 << 17
.dca equ 1 << 18
.sse4_1 equ 1 << 19
.sse4_2 equ 1 << 20
.x2apic equ 1 << 21
.movbe equ 1 << 22
.popcnt equ 1 << 23
.tsc_deadline equ 1 << 24
.aes equ 1 << 25
.xsave equ 1 << 26
.osxsave equ 1 << 27
.avx equ 1 << 28
.f16c equ 1 << 29
.rdrand equ 1 << 30
.hypervisor equ 1 << 31
+128
View File
@@ -0,0 +1,128 @@
SECTION .text ; cannot use .data
struc GDTEntry
.limitl resw 1
.basel resw 1
.basem resb 1
.attribute resb 1
.flags__limith resb 1
.baseh resb 1
endstruc
gdt_attr:
.present equ 1 << 7
.ring1 equ 1 << 5
.ring2 equ 1 << 6
.ring3 equ 1 << 5 | 1 << 6
.user equ 1 << 4
;user
.code equ 1 << 3
; code
.conforming equ 1 << 2
.readable equ 1 << 1
; data
.expand_down equ 1 << 2
.writable equ 1 << 1
.accessed equ 1 << 0
;system
; legacy
.tssAvailabe16 equ 0x1
.ldt equ 0x2
.tssBusy16 equ 0x3
.call16 equ 0x4
.task equ 0x5
.interrupt16 equ 0x6
.trap16 equ 0x7
.tssAvailabe32 equ 0x9
.tssBusy32 equ 0xB
.call32 equ 0xC
.interrupt32 equ 0xE
.trap32 equ 0xF
; long mode
.ldt32 equ 0x2
.tssAvailabe64 equ 0x9
.tssBusy64 equ 0xB
.call64 equ 0xC
.interrupt64 equ 0xE
.trap64 equ 0xF
gdt_flag:
.granularity equ 1 << 7
.available equ 1 << 4
;user
.default_operand_size equ 1 << 6
; code
.long_mode equ 1 << 5
; data
.reserved equ 1 << 5
gdtr:
dw gdt.end + 1 ; size
dq gdt ; offset
gdt:
.null equ $ - gdt
dq 0
.lm64_code equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code
at GDTEntry.flags__limith, db gdt_flag.long_mode
at GDTEntry.baseh, db 0
iend
.lm64_data equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
at GDTEntry.flags__limith, db 0
at GDTEntry.baseh, db 0
iend
.pm32_code equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code | gdt_attr.readable
at GDTEntry.flags__limith, db 0xF | gdt_flag.granularity | gdt_flag.default_operand_size
at GDTEntry.baseh, db 0
iend
.pm32_data equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
at GDTEntry.flags__limith, db 0xF | gdt_flag.granularity | gdt_flag.default_operand_size
at GDTEntry.baseh, db 0
iend
.pm16_code equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code | gdt_attr.readable
at GDTEntry.flags__limith, db 0xF
at GDTEntry.baseh, db 0
iend
.pm16_data equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
at GDTEntry.flags__limith, db 0xF
at GDTEntry.baseh, db 0
iend
.end equ $ - gdt
+161
View File
@@ -0,0 +1,161 @@
; Simple ISO emulation with el torito
; Fill until CD sector 0x10
times (0x10*2048)-($-$$) db 0
; Volume record
;TODO: fill in more fields
iso_volume_record:
db 1 ; Type volume record
db "CD001" ; Identifier
db 1 ; Version
db 0 ; Unused
times 32 db ' ' ; System identifier
.volume_id: ; Volume identifier
db 'Redox OS'
times 32-($-.volume_id) db ' '
times 8 db 0 ; Unused
db 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15 ; Volume space size (0x15)
times 32 db 0 ; Unused
db 0x01, 0x00, 0x00, 0x01 ; Volume set size
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
db 0x00, 0x08, 0x08, 0x00 ; Logical block size in little and big endian
times 156-($-iso_volume_record) db 0
; Root directory entry
.root_directory:
db 0x22 ; Length of entry
db 0x00 ; Length of extended attributes
db 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 ; Location of extent (0x14)
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
db 0x02 ; File flags
db 0x00 ; Interleaved file unit size
db 0x00 ; Interleaved gap size
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
db 0x01 ; Length of file identifier
db 0x00 ; File identifier
times 128 db ' ' ; Volume set identifier
times 128 db ' ' ; Publisher identifier
times 128 db ' ' ; Data preparer identifier
times 128 db ' ' ; Application identifier
times 37 db ' ' ; Copyright file ID
times 37 db ' ' ; Abstract file ID
times 37 db ' ' ; Bibliographic file ID
times 881-($-iso_volume_record) db 0
db 1 ; File structure version
; Fill until CD sector 0x11
times (0x11*2048)-($-$$) db 0
; Boot record
iso_boot_record:
db 0 ; Type boot record
db "CD001" ; Identifier
db 1 ; Version
db "EL TORITO SPECIFICATION" ; Boot system identifier
times 0x47-($ - iso_boot_record) db 0 ; Padding
dd 0x13 ; Sector of boot catalog
; Fill until CD sector 0x12
times (0x12*2048)-($-$$) db 0
; Terminator
iso_terminator:
db 0xFF ; Type terminator
db "CD001" ; Identifier
db 1 ; Version
; Fill until CD sector 0x13
times (0x13*2048)-($-$$) db 0
; Boot catalog
iso_boot_catalog:
; Validation entry
.validation:
db 1 ; Header ID
db 0 ; Platform ID (x86)
dw 0 ; Reserved
times 24 db 0 ; ID string
dw 0x55aa ; Checksum
dw 0xaa55 ; Key
; Default entry
.default:
db 0x88 ; Bootable
db 4 ; Hard drive emulation
dw 0 ; Load segment (0 is platform default)
db 0xEE ; Partition type (0xEE is protective MBR)
db 0 ; Unused
dw 1 ; Sector count
dd 0 ; Start address for virtual disk
times 20 db 0 ; Padding
; EFI section header entry
.efi_section_header:
db 0x91 ; Final header
db 0xEF ; Platform ID (EFI)
dw 1 ; Number of section header entries
times 28 db 0 ; ID string
; EFI section entry
.efi_section_entry:
db 0x88 ; Bootable
db 0 ; No emulation
dw 0 ; Load segment (0 is platform default)
db 0 ; Partition type (not used)
db 0 ; Unused
dw 512 ; Sector count (1 MiB = 512 CD sectors)
dd 512 ; Start address for virtual disk (1 MiB = 512 CD sectors)
times 20 db 0 ; Padding
; Fill until CD sector 0x14
times (0x14*2048)-($-$$) db 0
iso_root_directory:
.self:
db 0x22 ; Length of entry
db 0x00 ; Length of extended attributes
db 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 ; Location of extent (0x14)
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
db 0x02 ; File flags
db 0x00 ; Interleaved file unit size
db 0x00 ; Interleaved gap size
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
db 0x01 ; Length of file identifier
db 0x00 ; File identifier
.parent:
db 0x22 ; Length of entry
db 0x00 ; Length of extended attributes
db 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 ; Location of extent (0x14)
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
db 0x02 ; File flags
db 0x00 ; Interleaved file unit size
db 0x00 ; Interleaved gap size
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
db 0x01 ; Length of file identifier
db 0x01 ; File identifier
.boot_cat:
db 0x2C ; Length of entry
db 0x00 ; Length of extended attributes
db 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13 ; Location of extent (0x13)
db 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ; Size of extent
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Recording time
db 0x00 ; File flags
db 0x00 ; Interleaved file unit size
db 0x00 ; Interleaved gap size
db 0x01, 0x00, 0x00, 0x01 ; Volume sequence number
db 0x0A ; Length of file identifier
db "BOOT.CAT;1",0 ; File identifier
; Fill until CD sector 0x15
times (0x15*2048)-($-$$) db 0
+56
View File
@@ -0,0 +1,56 @@
SECTION .text
USE32
long_mode:
.func: dq 0
.page_table: dd 0
.entry:
; disable interrupts
cli
; disable paging
mov eax, cr0
and eax, 0x7FFFFFFF
mov cr0, eax
; enable FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension
mov eax, cr4
or eax, 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4
mov cr4, eax
; load long mode GDT
lgdt [gdtr]
; enable long mode
mov ecx, 0xC0000080 ; Read from the EFER MSR.
rdmsr
or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit.
wrmsr
; set page table
mov eax, [.page_table]
mov cr3, eax
; enabling paging and protection simultaneously
mov eax, cr0
or eax, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
mov cr0, eax
; far jump to enable Long Mode and load CS with 64 bit segment
jmp gdt.lm64_code:.inner
USE64
.inner:
; load all the other segments with 64 bit data segments
mov rax, gdt.lm64_data
mov ds, rax
mov es, rax
mov fs, rax
mov gs, rax
mov ss, rax
; jump to specified function
mov rax, [.func]
jmp rax
+67
View File
@@ -0,0 +1,67 @@
SECTION .text
USE16
; provide function for printing in x86 real mode
; print a string and a newline
; CLOBBER
; ax
print_line:
mov al, 13
call print_char
mov al, 10
jmp print_char
; print a string
; IN
; si: points at zero-terminated String
; CLOBBER
; si, ax
print:
pushf
cld
.loop:
lodsb
test al, al
jz .done
call print_char
jmp .loop
.done:
popf
ret
; print a character
; IN
; al: character to print
print_char:
pusha
mov bx, 7
mov ah, 0x0e
int 0x10
popa
ret
; print a number in hex
; IN
; bx: the number
; CLOBBER
; al, cx
print_hex:
mov cx, 4
.lp:
mov al, bh
shr al, 4
cmp al, 0xA
jb .below_0xA
add al, 'A' - 0xA - '0'
.below_0xA:
add al, '0'
call print_char
shl bx, 4
loop .lp
ret
+36
View File
@@ -0,0 +1,36 @@
SECTION .text
USE16
protected_mode:
.func: dd 0
.entry:
; disable interrupts
cli
; load protected mode GDT
lgdt [gdtr]
; set protected mode bit of cr0
mov eax, cr0
or eax, 1
mov cr0, eax
; far jump to load CS with 32 bit segment
jmp gdt.pm32_code:.inner
USE32
.inner:
; load all the other segments with 32 bit data segments
mov eax, gdt.pm32_data
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
; jump to specified function
mov eax, [.func]
jmp eax
+222
View File
@@ -0,0 +1,222 @@
ORG 0x7C00
SECTION .text
USE16
stage1: ; dl comes with disk
; initialize segment registers
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
; initialize stack
mov sp, 0x7C00
; initialize CS
push ax
push word .set_cs
retf
.set_cs:
; save disk number
mov [disk], dl
mov si, stage_msg
call print
mov al, '1'
call print_char
call print_line
; read CHS gemotry
; CL (bits 0-5) = maximum sector number
; CL (bits 6-7) = high bits of max cylinder number
; CH = low bits of maximum cylinder number
; DH = maximum head number
mov ah, 0x08
mov dl, [disk]
xor di, di
int 0x13
jc error ; carry flag set on error
mov bl, ch
mov bh, cl
shr bh, 6
mov [chs.c], bx
shr dx, 8
inc dx ; returns heads - 1
mov [chs.h], dx
and cl, 0x3f
mov [chs.s], cl
mov eax, (stage2 - stage1) / 512
mov bx, stage2
mov cx, (stage3.end - stage2) / 512
mov dx, 0
call load
mov si, stage_msg
call print
mov al, '2'
call print_char
call print_line
jmp stage2.entry
; load some sectors from disk to a buffer in memory
; buffer has to be below 1MiB
; IN
; ax: start sector
; bx: offset of buffer
; cx: number of sectors (512 Bytes each)
; dx: segment of buffer
; CLOBBER
; ax, bx, cx, dx, si
; TODO rewrite to (eventually) move larger parts at once
; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end)
load:
cmp cx, 127
jbe .good_size
pusha
mov cx, 127
call load
popa
add eax, 127
add dx, 127 * 512 / 16
sub cx, 127
jmp load
.good_size:
mov [DAPACK.addr], eax
mov [DAPACK.buf], bx
mov [DAPACK.count], cx
mov [DAPACK.seg], dx
call print_dapack
cmp byte [chs.s], 0
jne .chs
;INT 0x13 extended read does not work on CDROM!
mov dl, [disk]
mov si, DAPACK
mov ah, 0x42
int 0x13
jc error ; carry flag set on error
ret
.chs:
; calculate CHS
xor edx, edx
mov eax, [DAPACK.addr]
div dword [chs.s] ; divide by sectors
mov ecx, edx ; move sector remainder to ecx
xor edx, edx
div dword [chs.h] ; divide by heads
; eax has cylinders, edx has heads, ecx has sectors
; Sector cannot be greater than 63
inc ecx ; Sector is base 1
cmp ecx, 63
ja error_chs
; Head cannot be greater than 255
cmp edx, 255
ja error_chs
; Cylinder cannot be greater than 1023
cmp eax, 1023
ja error_chs
; Move CHS values to parameters
mov ch, al
shl ah, 6
and cl, 0x3f
or cl, ah
shl dx, 8
; read from disk using CHS
mov al, [DAPACK.count]
mov ah, 0x02 ; disk read (CHS)
mov bx, [DAPACK.buf]
mov dl, [disk]
push es ; save ES
mov es, [DAPACK.seg]
int 0x13
pop es ; restore EC
jc error ; carry flag set on error
ret
print_dapack:
mov bx, [DAPACK.addr + 2]
call print_hex
mov bx, [DAPACK.addr]
call print_hex
mov al, '#'
call print_char
mov bx, [DAPACK.count]
call print_hex
mov al, ' '
call print_char
mov bx, [DAPACK.seg]
call print_hex
mov al, ':'
call print_char
mov bx, [DAPACK.buf]
call print_hex
call print_line
ret
error_chs:
mov ah, 0
error:
call print_line
mov bh, 0
mov bl, ah
call print_hex
mov al, ' '
call print_char
mov si, error_msg
call print
call print_line
.halt:
cli
hlt
jmp .halt
%include "print.asm"
stage_msg: db "Stage ",0
error_msg: db "ERROR",0
disk: db 0
chs:
.c: dd 0
.h: dd 0
.s: dd 0
DAPACK:
db 0x10
db 0
.count: dw 0 ; int 13 resets this to # of blocks actually read/written
.buf: dw 0 ; memory buffer destination address (0:7c00)
.seg: dw 0 ; in memory page zero
.addr: dq 0 ; put the lba to read in this spot
times 446-($-$$) db 0
partitions: times 4 * 16 db 0
db 0x55
db 0xaa
+134
View File
@@ -0,0 +1,134 @@
SECTION .text
USE16
stage2.entry:
; check for required features
call cpuid_check
; enable A20-Line via IO-Port 92, might not work on all motherboards
in al, 0x92
or al, 2
out 0x92, al
mov dword [protected_mode.func], stage3.entry
jmp protected_mode.entry
%include "cpuid.asm"
%include "gdt.asm"
%include "long_mode.asm"
%include "protected_mode.asm"
%include "thunk.asm"
USE32
stage3.entry:
; stage3 stack at 448 KiB (512KiB minus 64KiB disk buffer)
mov esp, 0x70000
; push arguments
mov eax, thunk.int16
push eax
mov eax, thunk.int15
push eax
mov eax, thunk.int13
push eax
mov eax, thunk.int10
push eax
xor eax, eax
mov al, [disk]
push eax
mov eax, kernel.entry
push eax
mov eax, [stage3 + 0x18]
call eax
.halt:
cli
hlt
jmp .halt
kernel:
.stack: dq 0
.func: dq 0
.args: dq 0
.entry:
; page_table: usize
mov eax, [esp + 4]
mov [long_mode.page_table], eax
; stack: u64
mov eax, [esp + 8]
mov [.stack], eax
mov eax, [esp + 12]
mov [.stack + 4], eax
; func: u64
mov eax, [esp + 16]
mov [.func], eax
mov eax, [esp + 20]
mov [.func + 4], eax
; args: *const KernelArgs
mov eax, [esp + 24]
mov [.args], eax
; long_mode: usize
mov eax, [esp + 28]
test eax, eax
jz .inner32
mov eax, .inner64
mov [long_mode.func], eax
jmp long_mode.entry
.inner32:
; disable paging
mov eax, cr0
and eax, 0x7FFFFFFF
mov cr0, eax
;TODO: PAE (1 << 5)
; enable FXSAVE/FXRSTOR, Page Global, and Page Size Extension
mov eax, cr4
or eax, 1 << 9 | 1 << 7 | 1 << 4
mov cr4, eax
; set page table
mov eax, [long_mode.page_table]
mov cr3, eax
; enabling paging and protection simultaneously
mov eax, cr0
; Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
or eax, 1 << 31 | 1 << 16 | 1
mov cr0, eax
; enable FPU
;TODO: move to Rust
mov eax, cr0
and al, 11110011b ; Clear task switched (3) and emulation (2)
or al, 00100010b ; Set numeric error (5) monitor co-processor (1)
mov cr0, eax
fninit
mov esp, [.stack]
mov eax, [.args]
push eax
mov eax, [.func]
call eax
.halt32:
cli
hlt
jmp .halt32
USE64
.inner64:
mov rsp, [.stack]
mov rax, [.func]
mov rdi, [.args]
call rax
.halt64:
cli
hlt
jmp .halt64
+149
View File
@@ -0,0 +1,149 @@
SECTION .text
USE32
thunk:
.int10:
mov dword [.func], .int10_real
jmp .enter
.int13:
mov dword [.func], .int13_real
jmp .enter
.int15:
mov dword [.func], .int15_real
jmp .enter
.int16:
mov dword [.func], .int16_real
jmp .enter
.func: dd 0
.esp: dd 0
.cr0: dd 0
.enter:
; save flags
pushfd
; save registers
pushad
; save esp
mov [.esp], esp
; load gdt
lgdt [gdtr]
; far jump to protected mode 16-bit
jmp gdt.pm16_code:.pm16
.exit:
; set segment selectors to 32-bit protected mode
mov eax, gdt.pm32_data
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
; restore esp
mov esp, [.esp]
; restore registers
popad
; restore flags
popfd
; return
ret
USE16
.int10_real:
int 0x10
ret
.int13_real:
int 0x13
ret
.int15_real:
int 0x15
ret
.int16_real:
int 0x16
ret
.pm16:
; set segment selectors to protected mode 16-bit
mov eax, gdt.pm16_data
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
; save cr0
mov eax, cr0
mov [.cr0], eax
; disable paging and protected mode
and eax, 0x7FFFFFFE
mov cr0, eax
; far jump to real mode
jmp 0:.real
.real:
; set segment selectors to real mode
mov eax, 0
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
; set stack
mov esp, 0x7C00 - 64
; load registers and ES
pop es
pop edi
pop esi
pop ebp
pop ebx
pop edx
pop ecx
pop eax
; enable interrupts
sti
; call real mode function
call [.func]
; disable interrupts
cli
; save registers and ES
push eax
push ecx
push edx
push ebx
push ebp
push esi
push edi
push es
; load gdt (BIOS sometimes overwrites this)
lgdt [gdtr]
; restore cr0, will enable protected mode
mov eax, [.cr0]
mov cr0, eax
; far jump to protected mode 32-bit
jmp gdt.pm32_code:.exit
-30
View File
@@ -1,30 +0,0 @@
extern crate cc;
use std::{env, fs};
fn main() {
let _crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
let target = env::var("TARGET").unwrap();
println!("cargo:rerun-if-changed=src/c");
let mut cc_builder = &mut cc::Build::new();
cc_builder = cc_builder.flag("-nostdinc").flag("-nostdlib");
if target.starts_with("aarch64") {
cc_builder = cc_builder.flag("-mno-outline-atomics")
}
cc_builder
.flag("-fno-stack-protector")
.flag("-Wno-expansion-to-defined")
.files(
fs::read_dir("src/c")
.expect("src/c directory missing")
.map(|res| res.expect("read_dir error").path()),
)
.compile("relibc_c");
println!("cargo:rustc-link-lib=static=relibc_c");
}
-25
View File
@@ -1,25 +0,0 @@
# needs a leading newline
[defines]
"target_os=redox" = "__redox__"
"target_os=linux" = "__linux__"
"target_pointer_width=64" = "__LP64__"
"target_pointer_width=32" = "__ILP32__"
"target_arch=x86" = "__i386__"
"target_arch=x86_64" = "__x86_64__"
"target_arch=aarch64" = "__aarch64__"
# This is not exact. It should be `defined(__riscv) && defined(__LP64__)`, or `defined(__riscv) && __riscv_xlen==64`
# This will do however, as long as we only support riscv64 and not riscv32
"target_arch=riscv64" = "__riscv"
# XXX: silences a warning
"feature = no_std" = "__relibc__"
"feature = ip6" = "__ip6__"
# Ensure attributes are passed down from Rust
# <features.h> must be included where attributes are used in relibc
[fn]
must_use = "__nodiscard"
deprecated = "__deprecated"
deprecated_with_note = "__deprecatedNote({})"
no_return = "__noreturn"
-170
View File
@@ -1,170 +0,0 @@
#!/bin/bash
RED='\033[1;38;5;196m'
GREEN='\033[1;38;5;46m'
NC='\033[0m'
show_help() {
echo "Usage: $(basename "$0") [OPTIONS]"
echo ""
echo "Description:"
echo " Wrapper for Makefile / Cargo to run checks or tests on Redox OS targets."
echo ""
echo "Options:"
echo " --test Run 'make test' instead of 'make all'"
echo " --test= Run single 'make test'"
echo " --cargo Run 'cargo check' / 'cargo test' instead"
echo " (note: cargo test is currently not maintained for relibc)"
echo " --host Run the command on host (linux) target"
echo " --all-target Run the command on all supported Redox architectures"
echo " --target=<target> Override the target architecture (e.g., i586-unknown-redox)"
echo " --arch=<arch> Override the target architecture using arch (e.g., i586)"
echo " --help Show this help message"
echo ""
echo "Supported Targets:"
for t in "${SUPPORTED_TARGETS[@]}"; do
echo " - $t"
done
echo " - $(uname -m)-unknown-linux-gnu"
echo ""
echo "Environment:"
echo " TARGET Sets the default target (overridden by --target)"
}
if ! command -v cbindgen &> /dev/null; then
echo "Error: 'cbindgen' CLI not found."
echo "Please install it: cargo install cbindgen"
exit 1
fi
SUPPORTED_TARGETS=(
"x86_64-unknown-redox"
"i586-unknown-redox"
"aarch64-unknown-redox"
"riscv64gc-unknown-redox"
)
CURRENT_TARGET="${TARGET:-x86_64-unknown-redox}"
CHECK_ALL=false
CMD_ACTION="make"
CARGO_ACTION="check"
MAKE_ACTION="all"
TEST_BIN=""
IS_HOST=0
while [[ $# -gt 0 ]]; do
case "$1" in
--all-target)
CHECK_ALL=true
;;
--test)
MAKE_ACTION="test"
CARGO_ACTION="test"
;;
--test=*)
TEST_BIN="${1#*=}"
MAKE_ACTION="test-once"
;;
--cargo)
CMD_ACTION="cargo"
;;
--clippy)
CMD_ACTION="cargo"
CARGO_ACTION="clippy"
;;
--host)
CURRENT_TARGET="$(uname -m)-unknown-linux-gnu"
IS_HOST=1
;;
--target=*)
CURRENT_TARGET="${1#*=}"
;;
--arch=*)
CURRENT_TARGET="${1#*=}-unknown-redox"
;;
--help)
show_help
exit 0
;;
*)
echo -e "${RED}Error: Unknown option '$1'${NC}"
show_help
exit 1
;;
esac
shift
done
if [ "$IS_HOST" -eq 0 ]; then
if ! command -v redoxer &> /dev/null; then
echo "Error: 'redoxer' CLI not found."
echo "Please install it: cargo install redoxer"
exit 1
fi
fi
run_redoxer() {
export TARGET=$1
REDOXER_ENV="redoxer env"
if [ "$IS_HOST" -eq 0 ]; then
redoxer toolchain || { echo -e "${RED}Fail: redoxer toolchain for: $target.${NC}" && exit 1; }
export CARGO_TEST="redoxer"
export TEST_RUNNER="redoxer exec --folder ../../sysroot/$TARGET/:/usr --folder . --"
MAKE_ACTION="$MAKE_ACTION IS_REDOX=1"
else
REDOXER_ENV=""
fi
if [ "$TEST_BIN" != "" ]; then
if [ "$IS_HOST" -eq 0 ]; then
MAKE_ACTION="$MAKE_ACTION TESTBIN=bins_dynamic/$TEST_BIN"
else
MAKE_ACTION="$MAKE_ACTION TESTBIN=bins_static/$TEST_BIN"
fi
fi
if [ "$CMD_ACTION" == "make" ]; then
CMD_OPT="-j $(nproc) $MAKE_ACTION"
else
CMD_OPT="$CARGO_ACTION --target=$TARGET"
fi
echo "----------------------------------------"
echo "Running $REDOXER_ENV $CMD_ACTION $CMD_OPT for: $TARGET"
if $REDOXER_ENV $CMD_ACTION $CMD_OPT; then
return 0
else
echo -e "${RED}Fail: $CMD_ACTION $CMD_OPT for $TARGET failed.${NC}"
return 1
fi
}
if [ "$CHECK_ALL" = true ]; then
echo "Running $CMD_ACTION for all supported Redox targets..."
has_error=false
for target in "${SUPPORTED_TARGETS[@]}"; do
if ! run_redoxer "$target"; then
has_error=true
fi
done
echo "----------------------------------------"
if [ "$has_error" = true ]; then
echo -e "${RED}Summary: One or more targets failed.${NC}"
exit 1
else
echo -e "${GREEN}Summary: All targets passed!${NC}"
exit 0
fi
else
if run_redoxer "$CURRENT_TARGET"; then
echo -e "${GREEN}Success: $CARGO_ACTION for $CURRENT_TARGET passed.${NC}"
exit 0
else
exit 1
fi
fi
-94
View File
@@ -1,94 +0,0 @@
ifndef TARGET
export TARGET:=$(shell rustc -Z unstable-options --print target-spec-json | grep llvm-target | cut -d '"' -f4)
endif
ifeq ($(TARGET),aarch64-unknown-linux-gnu)
export CC=aarch64-linux-gnu-gcc
export LD=aarch64-linux-gnu-ld
export AR=aarch64-linux-gnu-ar
export NM=aarch64-linux-gnu-nm
export OBJCOPY=aarch64-linux-gnu-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
endif
ifeq ($(TARGET),aarch64-unknown-linux-relibc)
export CC=aarch64-linux-relibc-gcc
export LD=aarch64-linux-relibc-ld
export AR=aarch64-linux-relibc-ar
export NM=aarch64-linux-relibc-nm
export OBJCOPY=aarch64-linux-relibc-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
endif
ifeq ($(TARGET),aarch64-unknown-redox)
export CC=aarch64-unknown-redox-gcc
export LD=aarch64-unknown-redox-ld
export AR=aarch64-unknown-redox-ar
export NM=aarch64-unknown-redox-nm
export OBJCOPY=aarch64-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
endif
ifeq ($(TARGET),i586-unknown-redox)
export CC=i586-unknown-redox-gcc
export LD=i586-unknown-redox-ld
export AR=i586-unknown-redox-ar
export NM=i586-unknown-redox-nm
export OBJCOPY=i586-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1
endif
ifeq ($(TARGET),i686-unknown-redox)
export CC=i686-unknown-redox-gcc
export LD=i686-unknown-redox-ld
export AR=i686-unknown-redox-ar
export NM=i686-unknown-redox-nm
export OBJCOPY=i686-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1
endif
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
export CC=x86_64-linux-gnu-gcc
export LD=x86_64-linux-gnu-ld
export AR=x86_64-linux-gnu-ar
export NM=x86_64-linux-gnu-nm
export OBJCOPY=objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
endif
ifeq ($(TARGET),x86_64-unknown-linux-relibc)
export CC=x86_64-linux-relibc-gcc
export LD=x86_64-linux-relibc-ld
export AR=x86_64-linux-relibc-ar
export NM=x86_64-linux-relibc-nm
export OBJCOPY=x86_64-linux-relibc-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
endif
ifeq ($(TARGET),x86_64-unknown-redox)
export CC=x86_64-unknown-redox-gcc
export LD=x86_64-unknown-redox-ld
export AR=x86_64-unknown-redox-ar
export NM=x86_64-unknown-redox-nm
export OBJCOPY=x86_64-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
endif
ifeq ($(TARGET),riscv64gc-unknown-redox)
export CC=riscv64-unknown-redox-gcc
export LD=riscv64-unknown-redox-ld
export AR=riscv64-unknown-redox-ar
export NM=riscv64-unknown-redox-nm
export OBJCOPY=riscv64-unknown-redox-objcopy
export CPPFLAGS=-march=rv64gc -mabi=lp64d
LD_SO_PATH=lib/ld.so.1
endif
Submodule dlmalloc-rs deleted from 3b0ee3b467
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env bash
cargo fmt --package relibc --package crt0 --package redox-rt "$@"
-7
View File
@@ -1,7 +0,0 @@
[package]
name = "generic-rt"
version = "0.1.0"
edition = "2024"
[lints]
workspace = true
-100
View File
@@ -1,100 +0,0 @@
#![no_std]
#![allow(internal_features)]
#![feature(core_intrinsics)]
#![deny(unsafe_op_in_unsafe_fn)]
use core::{
arch::asm,
mem::{self, offset_of},
};
#[derive(Debug)]
#[repr(C)]
pub struct GenericTcb<Os> {
/// Pointer to the end of static TLS. Must be the first member
pub tls_end: *mut u8,
/// Size of the memory allocated for the static TLS in bytes (multiple of page size)
pub tls_len: usize,
/// Pointer to this structure
pub tcb_ptr: *mut Self,
/// Size of the memory allocated for this structure in bytes (should be same as page size)
pub tcb_len: usize,
pub os_specific: Os,
}
impl<Os> GenericTcb<Os> {
/// Architecture specific code to read a usize from the TCB - aarch64
#[allow(unsafe_op_in_unsafe_fn)]
#[inline(always)]
#[cfg(target_arch = "aarch64")]
pub unsafe fn arch_read(offset: usize) -> usize {
let abi_ptr: usize;
asm!(
"mrs {}, tpidr_el0",
out(reg) abi_ptr,
);
let tcb_ptr = *(abi_ptr as *const usize);
*((tcb_ptr + offset) as *const usize)
}
/// Architecture specific code to read a usize from the TCB - x86
#[allow(unsafe_op_in_unsafe_fn)]
#[inline(always)]
#[cfg(target_arch = "x86")]
pub unsafe fn arch_read(offset: usize) -> usize {
let value;
asm!(
"
mov {}, gs:[{}]
",
out(reg) value,
in(reg) offset,
);
value
}
/// Architecture specific code to read a usize from the TCB - x86_64
#[allow(unsafe_op_in_unsafe_fn)]
#[inline(always)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn arch_read(offset: usize) -> usize {
let value;
asm!(
"
mov {}, fs:[{}]
",
out(reg) value,
in(reg) offset,
);
value
}
/// Architecture specific code to read a usize from the TCB - riscv64
#[allow(unsafe_op_in_unsafe_fn)]
#[inline(always)]
#[cfg(target_arch = "riscv64")]
unsafe fn arch_read(offset: usize) -> usize {
let value;
asm!(
"ld {value}, -8(tp)", // TCB
"add {value}, {value}, {offset}",
"ld {value}, 0({value})",
value = out(reg) value,
offset = in(reg) offset,
);
value
}
pub unsafe fn current_ptr() -> Option<*mut Self> {
let tcb_ptr = unsafe { Self::arch_read(offset_of!(Self, tcb_ptr)) as *mut Self };
let tcb_len = unsafe { Self::arch_read(offset_of!(Self, tcb_len)) };
if tcb_ptr.is_null() || tcb_len < mem::size_of::<Self>() {
None
} else {
Some(tcb_ptr)
}
}
pub unsafe fn current() -> Option<&'static mut Self> {
unsafe { Some(&mut *Self::current_ptr()?) }
}
}
-6
View File
@@ -1,6 +0,0 @@
#ifndef _ALLOCA_H
#define _ALLOCA_H
#define alloca(size) __builtin_alloca (size)
#endif /* _ALLOCA_H */
-1
View File
@@ -1 +0,0 @@
#include <openlibm_complex.h>
-112
View File
@@ -1,112 +0,0 @@
/*
* MIT License
* Copyright (c) 2020 Rich Felker musl-libc
*/
#ifndef _FEATURES_H__RELIBC
#define _FEATURES_H__RELIBC
// Version metadata for feature gating
// This is useful for divergent implementation specific behavior
// glibc, ulibc, and likely others define a similar macro
// musl does not define an equivalent macro
#define __RELIBC__ 1
#define __RELIBC__MAJOR 0
#define __RELIBC__MINOR 2
/*
* Sources:
* https://en.cppreference.com/w/c/language/attributes
* https://clang.llvm.org/docs/LanguageExtensions.html
* https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fc_005fattribute.html
* https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
*/
// Clang doesn't define __has_cpp_attribute if compiling C code
#if !defined(__has_cpp_attribute)
#define __has_cpp_attribute(x) 0
#endif
// Clang doesn't define __has_c_attribute if compiling C++ code
#if !defined(__has_c_attribute)
#define __has_c_attribute(x) 0
#endif
// Check if C23+ attributes are available
#if defined(__cplusplus)
// HACK: GCC backports C++ attributes to C++98 but doesn't accept attributes
// placed before the function like cbindgen emits.
// Let's just disable attributes for C++98 by checking if a random C++11
// feature is available.
#define __HAS_ATTRIBUTE(x) __cpp_variable_templates &&__has_cpp_attribute(x)
#else
#define __HAS_ATTRIBUTE(x) \
(__has_c_attribute(x) || __STDC_VERSION__ >= 202311L || \
__has_cpp_attribute(x))
#endif
// From musl, license MIT {
#if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE 1
#endif
#if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE)
#define _BSD_SOURCE 1
#endif
#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) \
&& !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) \
&& !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__)
#define _BSD_SOURCE 1
#define _XOPEN_SOURCE 700
#endif
// } from musl
// TODO: Not emitted with cbindgen
#if __STDC_VERSION__ >= 199901L
#define __restrict restrict
#elif !defined(__GNUC__)
#define __restrict
#endif
// TODO: Not emitted with cbindgen
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
#define __inline inline
#elif !defined(__GNUC__)
#define __inline
#endif
// Analogous to Rust's Never type
//TODO: clang fails to compile C with [[noreturn]]
#if defined(__cplusplus) && __HAS_ATTRIBUTE(noreturn) && !(__clang__)
#define __noreturn [[noreturn]]
// #elif __STDC_VERSION__ >= 201112L
// FIXME: cbindgen incorrectly places _Noreturn
// #define __noreturn _Noreturn
#elif defined(__GNUC__)
#define __noreturn __attribute__((__noreturn__))
#else
#define __noreturn
#endif
// Analogous to Rust's #[must_use]
// C23 only
#if __HAS_ATTRIBUTE(nodiscard)
#define __nodiscard [[nodiscard]]
#define __nodiscardNote(x) [[nodiscard(x)]]
#else
#define __nodiscard
#define __nodiscardNote(x)
#endif
// Analogous to Rust's #[deprecated]
// C23 only
#if __HAS_ATTRIBUTE(deprecated)
#define __deprecated [[deprecated]]
#define __deprecatedNote(x) [[deprecated(x)]]
#else
#define __deprecated
#define __deprecatedNote(x)
#endif
#endif
-3
View File
@@ -1,3 +0,0 @@
#include <openlibm_fenv.h>
#undef complex
#undef I
-22
View File
@@ -1,22 +0,0 @@
// Copied from musl
#ifndef _ISO646_H
#define _ISO646_H
#ifndef __cplusplus
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=
#endif
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef __MACHINE_ENDIAN_H__
/* TODO: Forcing little endian, if you need a big endian system, fix this { */
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 4321
#endif
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif
/* } */
#endif /* __MACHINE_ENDIAN_H__ */
-113
View File
@@ -1,113 +0,0 @@
#include <openlibm_math.h>
// Missing typedefs
typedef float float_t;
typedef double double_t;
/* double */
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923 /* pi/2 */
#endif
#ifndef M_PI_4
#define M_PI_4 0.78539816339744830962 /* pi/4 */
#endif
#ifndef M_2_PI
#define M_2_PI 0.63661977236758134308 /* 2/pi */
#endif
#ifndef M_E
#define M_E 2.7182818284590452354 /* e */
#endif
#ifndef M_LOG2E
#define M_LOG2E 1.4426950408889634074 /* log_2 e */
#endif
#ifndef M_LOG10E
#define M_LOG10E 0.43429448190325182765 /* log_10 e */
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942 /* log_e 2 */
#endif
#ifndef M_LN10
#define M_LN10 2.30258509299404568402 /* log_e 10 */
#endif
#ifndef M_1_PI
#define M_1_PI 0.31830988618379067154 /* 1/pi */
#endif
#ifndef M_2_SQRTPI
#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
#endif
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
#endif
/* long double */
#ifndef M_El
#define M_El 2.718281828459045235360287471352662498L /* e */
#endif
#ifndef M_LOG2El
#define M_LOG2El 1.442695040888963407359924681001892137L /* log_2 e */
#endif
#ifndef M_LOG10El
#define M_LOG10El 0.434294481903251827651128918916605082L /* log_10 e */
#endif
#ifndef M_LN2l
#define M_LN2l 0.693147180559945309417232121458176568L /* log_e 2 */
#endif
#ifndef M_LN10l
#define M_LN10l 2.302585092994045684017991454684364208L /* log_e 10 */
#endif
#ifndef M_PIl
#define M_PIl 3.141592653589793238462643383279502884L /* pi */
#endif
#ifndef M_PI_2l
#define M_PI_2l 1.570796326794896619231321691639751442L /* pi/2 */
#endif
#ifndef M_PI_4l
#define M_PI_4l 0.785398163397448309615660845819875721L /* pi/4 */
#endif
#ifndef M_1_PIl
#define M_1_PIl 0.318309886183790671537767526745028724L /* 1/pi */
#endif
#ifndef M_2_PIl
#define M_2_PIl 0.636619772367581343075535053490057448L /* 2/pi */
#endif
#ifndef M_2_SQRTPIl
#define M_2_SQRTPIl 1.128379167095512573896158903121545172L /* 2/sqrt(pi) */
#endif
#ifndef M_SQRT2l
#define M_SQRT2l 1.414213562373095048801688724209698079L /* sqrt(2) */
#endif
#ifndef M_SQRT1_2l
#define M_SQRT1_2l 0.707106781186547524400844362104849039L /* 1/sqrt(2) */
#endif
-1
View File
@@ -1 +0,0 @@
#include <string.h>
-10
View File
@@ -1,10 +0,0 @@
#ifndef _NETINET_IN_SYSTM_H
#define _NETINET_IN_SYSTM_H
#include <stdint.h>
typedef uint16_t n_short;
typedef uint32_t n_long;
typedef uint32_t n_time;
#endif
-6
View File
@@ -1,6 +0,0 @@
#ifndef _RELIBC_PATHS_H
#define _RELIBC_PATHS_H
#define _PATH_BSHELL "/bin/sh"
#endif
-35
View File
@@ -1,35 +0,0 @@
#ifndef _SETJMP_H
#define _SETJMP_H
#ifdef __aarch64__
typedef unsigned long long jmp_buf[22];
#endif
#ifdef __i386__
typedef unsigned long long jmp_buf[6];
#endif
#ifdef __x86_64__
typedef unsigned long long jmp_buf[16];
#endif
#ifdef __riscv
typedef unsigned long long jmp_buf[26];
#endif
typedef jmp_buf sigjmp_buf;
#ifdef __cplusplus
extern "C" {
#endif
int setjmp(jmp_buf buf);
void longjmp(jmp_buf buf, int value);
int sigsetjmp(jmp_buf buf, int savemask);
int siglongjmp(jmp_buf buf, int savemask);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* _SETJMP_H */
-243
View File
@@ -1,243 +0,0 @@
/* Copyright (C) 2013-2022 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
/* ISO C11 Standard: 7.17 Atomics <stdatomic.h>. */
#ifndef _STDATOMIC_H
#define _STDATOMIC_H
typedef enum
{
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;
typedef _Atomic _Bool atomic_bool;
typedef _Atomic char atomic_char;
typedef _Atomic signed char atomic_schar;
typedef _Atomic unsigned char atomic_uchar;
typedef _Atomic short atomic_short;
typedef _Atomic unsigned short atomic_ushort;
typedef _Atomic int atomic_int;
typedef _Atomic unsigned int atomic_uint;
typedef _Atomic long atomic_long;
typedef _Atomic unsigned long atomic_ulong;
typedef _Atomic long long atomic_llong;
typedef _Atomic unsigned long long atomic_ullong;
typedef _Atomic __CHAR16_TYPE__ atomic_char16_t;
typedef _Atomic __CHAR32_TYPE__ atomic_char32_t;
typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t;
typedef _Atomic __INT_LEAST8_TYPE__ atomic_int_least8_t;
typedef _Atomic __UINT_LEAST8_TYPE__ atomic_uint_least8_t;
typedef _Atomic __INT_LEAST16_TYPE__ atomic_int_least16_t;
typedef _Atomic __UINT_LEAST16_TYPE__ atomic_uint_least16_t;
typedef _Atomic __INT_LEAST32_TYPE__ atomic_int_least32_t;
typedef _Atomic __UINT_LEAST32_TYPE__ atomic_uint_least32_t;
typedef _Atomic __INT_LEAST64_TYPE__ atomic_int_least64_t;
typedef _Atomic __UINT_LEAST64_TYPE__ atomic_uint_least64_t;
typedef _Atomic __INT_FAST8_TYPE__ atomic_int_fast8_t;
typedef _Atomic __UINT_FAST8_TYPE__ atomic_uint_fast8_t;
typedef _Atomic __INT_FAST16_TYPE__ atomic_int_fast16_t;
typedef _Atomic __UINT_FAST16_TYPE__ atomic_uint_fast16_t;
typedef _Atomic __INT_FAST32_TYPE__ atomic_int_fast32_t;
typedef _Atomic __UINT_FAST32_TYPE__ atomic_uint_fast32_t;
typedef _Atomic __INT_FAST64_TYPE__ atomic_int_fast64_t;
typedef _Atomic __UINT_FAST64_TYPE__ atomic_uint_fast64_t;
typedef _Atomic __INTPTR_TYPE__ atomic_intptr_t;
typedef _Atomic __UINTPTR_TYPE__ atomic_uintptr_t;
typedef _Atomic __SIZE_TYPE__ atomic_size_t;
typedef _Atomic __PTRDIFF_TYPE__ atomic_ptrdiff_t;
typedef _Atomic __INTMAX_TYPE__ atomic_intmax_t;
typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
#define ATOMIC_VAR_INIT(VALUE) (VALUE)
/* Initialize an atomic object pointed to by PTR with VAL. */
#define atomic_init(PTR, VAL) \
atomic_store_explicit (PTR, VAL, __ATOMIC_RELAXED)
#define kill_dependency(Y) \
__extension__ \
({ \
__auto_type __kill_dependency_tmp = (Y); \
__kill_dependency_tmp; \
})
extern void atomic_thread_fence (memory_order);
#define atomic_thread_fence(MO) __atomic_thread_fence (MO)
extern void atomic_signal_fence (memory_order);
#define atomic_signal_fence(MO) __atomic_signal_fence (MO)
#define atomic_is_lock_free(OBJ) __atomic_is_lock_free (sizeof (*(OBJ)), (OBJ))
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
/* Note that these macros require __auto_type to remove
_Atomic qualifiers (and const qualifiers, if those are valid on
macro operands).
Also note that the header file uses the generic form of __atomic
builtins, which requires the address to be taken of the value
parameter, and then we pass that value on. This allows the macros
to work for any type, and the compiler is smart enough to convert
these to lock-free _N variants if possible, and throw away the
temps. */
#define atomic_store_explicit(PTR, VAL, MO) \
__extension__ \
({ \
__auto_type __atomic_store_ptr = (PTR); \
__typeof__ ((void)0, *__atomic_store_ptr) __atomic_store_tmp = (VAL); \
__atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO)); \
})
#define atomic_store(PTR, VAL) \
atomic_store_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
#define atomic_load_explicit(PTR, MO) \
__extension__ \
({ \
__auto_type __atomic_load_ptr = (PTR); \
__typeof__ ((void)0, *__atomic_load_ptr) __atomic_load_tmp; \
__atomic_load (__atomic_load_ptr, &__atomic_load_tmp, (MO)); \
__atomic_load_tmp; \
})
#define atomic_load(PTR) atomic_load_explicit (PTR, __ATOMIC_SEQ_CST)
#define atomic_exchange_explicit(PTR, VAL, MO) \
__extension__ \
({ \
__auto_type __atomic_exchange_ptr = (PTR); \
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_val = (VAL); \
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_tmp; \
__atomic_exchange (__atomic_exchange_ptr, &__atomic_exchange_val, \
&__atomic_exchange_tmp, (MO)); \
__atomic_exchange_tmp; \
})
#define atomic_exchange(PTR, VAL) \
atomic_exchange_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
#define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) \
__extension__ \
({ \
__auto_type __atomic_compare_exchange_ptr = (PTR); \
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
= (DES); \
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
&__atomic_compare_exchange_tmp, 0, \
(SUC), (FAIL)); \
})
#define atomic_compare_exchange_strong(PTR, VAL, DES) \
atomic_compare_exchange_strong_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
__ATOMIC_SEQ_CST)
#define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) \
__extension__ \
({ \
__auto_type __atomic_compare_exchange_ptr = (PTR); \
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
= (DES); \
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
&__atomic_compare_exchange_tmp, 1, \
(SUC), (FAIL)); \
})
#define atomic_compare_exchange_weak(PTR, VAL, DES) \
atomic_compare_exchange_weak_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
__ATOMIC_SEQ_CST)
#define atomic_fetch_add(PTR, VAL) __atomic_fetch_add ((PTR), (VAL), \
__ATOMIC_SEQ_CST)
#define atomic_fetch_add_explicit(PTR, VAL, MO) \
__atomic_fetch_add ((PTR), (VAL), (MO))
#define atomic_fetch_sub(PTR, VAL) __atomic_fetch_sub ((PTR), (VAL), \
__ATOMIC_SEQ_CST)
#define atomic_fetch_sub_explicit(PTR, VAL, MO) \
__atomic_fetch_sub ((PTR), (VAL), (MO))
#define atomic_fetch_or(PTR, VAL) __atomic_fetch_or ((PTR), (VAL), \
__ATOMIC_SEQ_CST)
#define atomic_fetch_or_explicit(PTR, VAL, MO) \
__atomic_fetch_or ((PTR), (VAL), (MO))
#define atomic_fetch_xor(PTR, VAL) __atomic_fetch_xor ((PTR), (VAL), \
__ATOMIC_SEQ_CST)
#define atomic_fetch_xor_explicit(PTR, VAL, MO) \
__atomic_fetch_xor ((PTR), (VAL), (MO))
#define atomic_fetch_and(PTR, VAL) __atomic_fetch_and ((PTR), (VAL), \
__ATOMIC_SEQ_CST)
#define atomic_fetch_and_explicit(PTR, VAL, MO) \
__atomic_fetch_and ((PTR), (VAL), (MO))
typedef _Atomic struct
{
#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
_Bool __val;
#else
unsigned char __val;
#endif
} atomic_flag;
#define ATOMIC_FLAG_INIT { 0 }
extern _Bool atomic_flag_test_and_set (volatile atomic_flag *);
#define atomic_flag_test_and_set(PTR) \
__atomic_test_and_set ((PTR), __ATOMIC_SEQ_CST)
extern _Bool atomic_flag_test_and_set_explicit (volatile atomic_flag *,
memory_order);
#define atomic_flag_test_and_set_explicit(PTR, MO) \
__atomic_test_and_set ((PTR), (MO))
extern void atomic_flag_clear (volatile atomic_flag *);
#define atomic_flag_clear(PTR) __atomic_clear ((PTR), __ATOMIC_SEQ_CST)
extern void atomic_flag_clear_explicit (volatile atomic_flag *, memory_order);
#define atomic_flag_clear_explicit(PTR, MO) __atomic_clear ((PTR), (MO))
#endif /* _STDATOMIC_H */
-18
View File
@@ -1,18 +0,0 @@
#ifndef _STDBOOL_H
#define _STDBOOL_H
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#else /* __cplusplus */
#if __cplusplus < 201103L
#define bool bool
#define false false
#define true true
#endif /*__cplusplus < 201103L*/
#endif /* __cplusplus */
#define __bool_true_false_are_defined 1
#endif /* _STDBOOL_H */
-370
View File
@@ -1,370 +0,0 @@
/* Copyright (C) 2008-2018 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
/*
* ISO C Standard: 7.18 Integer types <stdint.h>
*/
#ifndef _STDINT_H
#define _STDINT_H
/* 7.8.1.1 Exact-width integer types */
#ifdef __INT8_TYPE__
typedef __INT8_TYPE__ int8_t;
#endif
#ifdef __INT16_TYPE__
typedef __INT16_TYPE__ int16_t;
#endif
#ifdef __INT32_TYPE__
typedef __INT32_TYPE__ int32_t;
#endif
#ifdef __INT64_TYPE__
typedef __INT64_TYPE__ int64_t;
#endif
#ifdef __UINT8_TYPE__
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT8_TYPE__ u_int8_t;
#endif
#ifdef __UINT16_TYPE__
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT16_TYPE__ u_int16_t;
#endif
#include <bits/uint32-t.h> // for uint32_t
#ifdef __UINT64_TYPE__
typedef __UINT64_TYPE__ uint64_t;
typedef __UINT64_TYPE__ u_int64_t;
// Required by openlibm
typedef __UINT64_TYPE__ __uint64_t;
#endif
/* 7.8.1.2 Minimum-width integer types */
typedef __INT_LEAST8_TYPE__ int_least8_t;
typedef __INT_LEAST16_TYPE__ int_least16_t;
typedef __INT_LEAST32_TYPE__ int_least32_t;
typedef __INT_LEAST64_TYPE__ int_least64_t;
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
/* 7.8.1.3 Fastest minimum-width integer types */
typedef __INT_FAST8_TYPE__ int_fast8_t;
typedef __INT_FAST16_TYPE__ int_fast16_t;
typedef __INT_FAST32_TYPE__ int_fast32_t;
typedef __INT_FAST64_TYPE__ int_fast64_t;
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
/* 7.8.1.4 Integer types capable of holding object pointers */
#include <bits/intptr-t.h> // for intptr_t
#ifdef __UINTPTR_TYPE__
typedef __UINTPTR_TYPE__ uintptr_t;
#endif
/* 7.8.1.5 Greatest-width integer types */
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
#if (!defined __cplusplus || __cplusplus >= 201103L \
|| defined __STDC_LIMIT_MACROS)
/* 7.18.2 Limits of specified-width integer types */
#ifdef __INT8_MAX__
# undef INT8_MAX
# define INT8_MAX __INT8_MAX__
# undef INT8_MIN
# define INT8_MIN (-INT8_MAX - 1)
#endif
#ifdef __UINT8_MAX__
# undef UINT8_MAX
# define UINT8_MAX __UINT8_MAX__
#endif
#ifdef __INT16_MAX__
# undef INT16_MAX
# define INT16_MAX __INT16_MAX__
# undef INT16_MIN
# define INT16_MIN (-INT16_MAX - 1)
#endif
#ifdef __UINT16_MAX__
# undef UINT16_MAX
# define UINT16_MAX __UINT16_MAX__
#endif
#ifdef __INT32_MAX__
# undef INT32_MAX
# define INT32_MAX __INT32_MAX__
# undef INT32_MIN
# define INT32_MIN (-INT32_MAX - 1)
#endif
#ifdef __UINT32_MAX__
# undef UINT32_MAX
# define UINT32_MAX __UINT32_MAX__
#endif
#ifdef __INT64_MAX__
# undef INT64_MAX
# define INT64_MAX __INT64_MAX__
# undef INT64_MIN
# define INT64_MIN (-INT64_MAX - 1)
#endif
#ifdef __UINT64_MAX__
# undef UINT64_MAX
# define UINT64_MAX __UINT64_MAX__
#endif
#undef INT_LEAST8_MAX
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
#undef INT_LEAST8_MIN
#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
#undef UINT_LEAST8_MAX
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
#undef INT_LEAST16_MAX
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
#undef INT_LEAST16_MIN
#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
#undef UINT_LEAST16_MAX
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
#undef INT_LEAST32_MAX
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
#undef INT_LEAST32_MIN
#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
#undef UINT_LEAST32_MAX
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
#undef INT_LEAST64_MAX
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
#undef INT_LEAST64_MIN
#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
#undef UINT_LEAST64_MAX
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
#undef INT_FAST8_MAX
#define INT_FAST8_MAX __INT_FAST8_MAX__
#undef INT_FAST8_MIN
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
#undef UINT_FAST8_MAX
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
#undef INT_FAST16_MAX
#define INT_FAST16_MAX __INT_FAST16_MAX__
#undef INT_FAST16_MIN
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
#undef UINT_FAST16_MAX
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
#undef INT_FAST32_MAX
#define INT_FAST32_MAX __INT_FAST32_MAX__
#undef INT_FAST32_MIN
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
#undef UINT_FAST32_MAX
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
#undef INT_FAST64_MAX
#define INT_FAST64_MAX __INT_FAST64_MAX__
#undef INT_FAST64_MIN
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
#undef UINT_FAST64_MAX
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
#ifdef __INTPTR_MAX__
# undef INTPTR_MAX
# define INTPTR_MAX __INTPTR_MAX__
# undef INTPTR_MIN
# define INTPTR_MIN (-INTPTR_MAX - 1)
#endif
#ifdef __UINTPTR_MAX__
# undef UINTPTR_MAX
# define UINTPTR_MAX __UINTPTR_MAX__
#endif
#undef INTMAX_MAX
#define INTMAX_MAX __INTMAX_MAX__
#undef INTMAX_MIN
#define INTMAX_MIN (-INTMAX_MAX - 1)
#undef UINTMAX_MAX
#define UINTMAX_MAX __UINTMAX_MAX__
/* 7.18.3 Limits of other integer types */
#undef PTRDIFF_MAX
#define PTRDIFF_MAX __PTRDIFF_MAX__
#undef PTRDIFF_MIN
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
#undef SIG_ATOMIC_MAX
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
#undef SIG_ATOMIC_MIN
#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
#undef SIZE_MAX
#define SIZE_MAX __SIZE_MAX__
#undef WCHAR_MAX
#define WCHAR_MAX __WCHAR_MAX__
#undef WCHAR_MIN
#define WCHAR_MIN __WCHAR_MIN__
#undef WINT_MAX
#define WINT_MAX __WINT_MAX__
#undef WINT_MIN
#define WINT_MIN __WINT_MIN__
#endif /* (!defined __cplusplus || __cplusplus >= 201103L
|| defined __STDC_LIMIT_MACROS) */
#if (!defined __cplusplus || __cplusplus >= 201103L \
|| defined __STDC_CONSTANT_MACROS)
#undef INT8_C
#define INT8_C(c) __INT8_C(c)
#undef INT16_C
#define INT16_C(c) __INT16_C(c)
#undef INT32_C
#define INT32_C(c) __INT32_C(c)
#undef INT64_C
#define INT64_C(c) __INT64_C(c)
#undef UINT8_C
#define UINT8_C(c) __UINT8_C(c)
#undef UINT16_C
#define UINT16_C(c) __UINT16_C(c)
#undef UINT32_C
#define UINT32_C(c) __UINT32_C(c)
#undef UINT64_C
#define UINT64_C(c) __UINT64_C(c)
#undef INTMAX_C
#define INTMAX_C(c) __INTMAX_C(c)
#undef UINTMAX_C
#define UINTMAX_C(c) __UINTMAX_C(c)
#endif /* (!defined __cplusplus || __cplusplus >= 201103L
|| defined __STDC_CONSTANT_MACROS) */
#ifdef __STDC_WANT_IEC_60559_BFP_EXT__
/* TS 18661-1 widths of integer types. */
#ifdef __INT8_TYPE__
# undef INT8_WIDTH
# define INT8_WIDTH 8
#endif
#ifdef __UINT8_TYPE__
# undef UINT8_WIDTH
# define UINT8_WIDTH 8
#endif
#ifdef __INT16_TYPE__
# undef INT16_WIDTH
# define INT16_WIDTH 16
#endif
#ifdef __UINT16_TYPE__
# undef UINT16_WIDTH
# define UINT16_WIDTH 16
#endif
#ifdef __INT32_TYPE__
# undef INT32_WIDTH
# define INT32_WIDTH 32
#endif
#ifdef __UINT32_TYPE__
# undef UINT32_WIDTH
# define UINT32_WIDTH 32
#endif
#ifdef __INT64_TYPE__
# undef INT64_WIDTH
# define INT64_WIDTH 64
#endif
#ifdef __UINT64_TYPE__
# undef UINT64_WIDTH
# define UINT64_WIDTH 64
#endif
#undef INT_LEAST8_WIDTH
#define INT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
#undef UINT_LEAST8_WIDTH
#define UINT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
#undef INT_LEAST16_WIDTH
#define INT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
#undef UINT_LEAST16_WIDTH
#define UINT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
#undef INT_LEAST32_WIDTH
#define INT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
#undef UINT_LEAST32_WIDTH
#define UINT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
#undef INT_LEAST64_WIDTH
#define INT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
#undef UINT_LEAST64_WIDTH
#define UINT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
#undef INT_FAST8_WIDTH
#define INT_FAST8_WIDTH __INT_FAST8_WIDTH__
#undef UINT_FAST8_WIDTH
#define UINT_FAST8_WIDTH __INT_FAST8_WIDTH__
#undef INT_FAST16_WIDTH
#define INT_FAST16_WIDTH __INT_FAST16_WIDTH__
#undef UINT_FAST16_WIDTH
#define UINT_FAST16_WIDTH __INT_FAST16_WIDTH__
#undef INT_FAST32_WIDTH
#define INT_FAST32_WIDTH __INT_FAST32_WIDTH__
#undef UINT_FAST32_WIDTH
#define UINT_FAST32_WIDTH __INT_FAST32_WIDTH__
#undef INT_FAST64_WIDTH
#define INT_FAST64_WIDTH __INT_FAST64_WIDTH__
#undef UINT_FAST64_WIDTH
#define UINT_FAST64_WIDTH __INT_FAST64_WIDTH__
#ifdef __INTPTR_TYPE__
# undef INTPTR_WIDTH
# define INTPTR_WIDTH __INTPTR_WIDTH__
#endif
#ifdef __UINTPTR_TYPE__
# undef UINTPTR_WIDTH
# define UINTPTR_WIDTH __INTPTR_WIDTH__
#endif
#undef INTMAX_WIDTH
#define INTMAX_WIDTH __INTMAX_WIDTH__
#undef UINTMAX_WIDTH
#define UINTMAX_WIDTH __INTMAX_WIDTH__
#undef PTRDIFF_WIDTH
#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__
#undef SIG_ATOMIC_WIDTH
#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__
#undef SIZE_WIDTH
#define SIZE_WIDTH __SIZE_WIDTH__
#undef WCHAR_WIDTH
#define WCHAR_WIDTH __WCHAR_WIDTH__
#undef WINT_WIDTH
#define WINT_WIDTH __WINT_WIDTH__
#ifdef __ILP32__
#define SIZE_MAX UINT32_MAX
#else
#define SIZE_MAX UINT64_MAX
#endif
#endif
#endif /* _GCC_STDINT_H */
-22
View File
@@ -1,22 +0,0 @@
#ifndef _STDIO_EXT_H
#define _STDIO_EXT_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
size_t __freadahead(FILE *stream);
size_t __fpending(FILE *stream);
int __freadable(FILE *stream);
int __freading(FILE *stream);
void __fseterr(FILE *stream);
int __fwritable(FILE *stream);
int __fwriting(FILE *stream);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* _STDIO_EXT_H */
-19
View File
@@ -1,19 +0,0 @@
/* Spec:
* The <stdnoreturn.h> header shall define the macro noreturn which shall
* expand to _Noreturn */
#ifndef _STDNORETURN_H
#define _STDNORETURN_H
#ifndef __cplusplus
/* Borrowed from musl */
#if __STDC_VERSION__ >= 201112L
#elif defined(__GNUC__)
#define _Noreturn __attribute__((__noreturn__))
#else
#define _Noreturn
#endif
#define noreturn _Noreturn
#endif
#endif
-36
View File
@@ -1,36 +0,0 @@
#ifndef _SYS_PARAM_H
#define _SYS_PARAM_H
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define __bitop(array, index, op) ((array)[(index) / 8] op (1 << (index) % 8))
#define setbit(array, index) __bitop(array, index, |=)
#define clrbit(array, index) __bitop(array, index, &= ~)
#define isset(array, index) __bitop(array, index, &)
#define isclr(array, index) !isset(array, index)
#define howmany(bits, size) (((bits) + (size) - 1) / (size))
#define roundup(bits, size) (howmany(bits, size) * (size))
#define powerof2(n) !(((n) - 1) & (n))
// Shamelessly copied from musl.
// Tweak as needed.
#define MAXSYMLINKS 20
#define MAXHOSTNAMELEN 64
#define MAXNAMLEN 255
#define MAXPATHLEN 4096
#define NBBY 8
#define NGROUPS 32
#define CANBSIZ 255
#define NOFILE 256
#define NCARGS 131072
#define DEV_BSIZE 512
#define NOGROUP (-1)
#include <sys/resource.h>
#include <limits.h>
#include <machine/endian.h>
#endif
-1
View File
@@ -1 +0,0 @@
#include <poll.h>
-846
View File
@@ -1,846 +0,0 @@
/* $NetBSD: queue.h,v 1.70 2015/11/02 15:21:23 christos Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
* A singly-linked list is headed by a single forward pointer. The
* elements are singly linked for minimum space and pointer manipulation
* overhead at the expense of O(n) removal for arbitrary elements. New
* elements can be added to the list after an existing element or at the
* head of the list. Elements being removed from the head of the list
* should use the explicit macro for this purpose for optimum
* efficiency. A singly-linked list may only be traversed in the forward
* direction. Singly-linked lists are ideal for applications with large
* datasets and few or no removals or for implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
/*
* Include the definition of NULL only on NetBSD because sys/null.h
* is not available elsewhere. This conditional makes the header
* portable and it can simply be dropped verbatim into any system.
* The caveat is that on other systems some other header
* must provide NULL before the macros can be used.
*/
#ifdef __NetBSD__
#include <sys/null.h>
#endif
#if defined(QUEUEDEBUG)
# if defined(_KERNEL)
# define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__)
# else
# include <err.h>
# define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__)
# endif
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = (head)->slh_first; \
(var) != SLIST_END(head); \
(var) = (var)->field.sle_next)
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) != SLIST_END(head) && \
((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) do { \
(head)->slh_first = SLIST_END(head); \
} while (/*CONSTCOND*/0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (/*CONSTCOND*/0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (/*CONSTCOND*/0)
#define SLIST_REMOVE_AFTER(slistelm, field) do { \
(slistelm)->field.sle_next = \
SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \
} while (/*CONSTCOND*/0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (/*CONSTCOND*/0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = (head)->slh_first; \
while(curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
} \
} while (/*CONSTCOND*/0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods.
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for ((var) = ((head)->lh_first); \
(var) != LIST_END(head); \
(var) = ((var)->field.le_next))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) != LIST_END(head) && \
((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_MOVE(head1, head2) do { \
LIST_INIT((head2)); \
if (!LIST_EMPTY((head1))) { \
(head2)->lh_first = (head1)->lh_first; \
LIST_INIT((head1)); \
} \
} while (/*CONSTCOND*/0)
/*
* List functions.
*/
#if defined(QUEUEDEBUG)
#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \
if ((head)->lh_first && \
(head)->lh_first->field.le_prev != &(head)->lh_first) \
QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \
__FILE__, __LINE__);
#define QUEUEDEBUG_LIST_OP(elm, field) \
if ((elm)->field.le_next && \
(elm)->field.le_next->field.le_prev != \
&(elm)->field.le_next) \
QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \
__FILE__, __LINE__); \
if (*(elm)->field.le_prev != (elm)) \
QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \
__FILE__, __LINE__);
#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \
(elm)->field.le_next = (void *)1L; \
(elm)->field.le_prev = (void *)1L;
#else
#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)
#define QUEUEDEBUG_LIST_OP(elm, field)
#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field)
#endif
#define LIST_INIT(head) do { \
(head)->lh_first = LIST_END(head); \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
QUEUEDEBUG_LIST_OP((listelm), field) \
if (((elm)->field.le_next = (listelm)->field.le_next) != \
LIST_END(head)) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
QUEUEDEBUG_LIST_OP((listelm), field) \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \
if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (/*CONSTCOND*/0)
#define LIST_REMOVE(elm, field) do { \
QUEUEDEBUG_LIST_OP((elm), field) \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
} while (/*CONSTCOND*/0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
} while (/*CONSTCOND*/0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for ((var) = ((head)->sqh_first); \
(var) != SIMPLEQ_END(head); \
(var) = ((var)->field.sqe_next))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
for ((var) = ((head)->sqh_first); \
(var) != SIMPLEQ_END(head) && \
((next = ((var)->field.sqe_next)), 1); \
(var) = (next))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
== NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
if ((head)->sqh_first == (elm)) { \
SIMPLEQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->sqh_first; \
while (curelm->field.sqe_next != (elm)) \
curelm = curelm->field.sqe_next; \
if ((curelm->field.sqe_next = \
curelm->field.sqe_next->field.sqe_next) == NULL) \
(head)->sqh_last = &(curelm)->field.sqe_next; \
} \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_CONCAT(head1, head2) do { \
if (!SIMPLEQ_EMPTY((head2))) { \
*(head1)->sqh_last = (head2)->sqh_first; \
(head1)->sqh_last = (head2)->sqh_last; \
SIMPLEQ_INIT((head2)); \
} \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_LAST(head, type, field) \
(SIMPLEQ_EMPTY((head)) ? \
NULL : \
((struct type *)(void *) \
((char *)((head)->sqh_last) - offsetof(struct type, field))))
/*
* Tail queue definitions.
*/
#define _TAILQ_HEAD(name, type, qual) \
struct name { \
qual type *tqh_first; /* first element */ \
qual type *qual *tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
#define TAILQ_HEAD_INITIALIZER(head) \
{ TAILQ_END(head), &(head).tqh_first }
#define _TAILQ_ENTRY(type, qual) \
struct { \
qual type *tqe_next; /* next element */ \
qual type *qual *tqe_prev; /* address of previous next element */\
}
#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
/*
* Tail queue access methods.
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) (NULL)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)(void *)((head)->tqh_last))->tqh_last))
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)(void *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for ((var) = ((head)->tqh_first); \
(var) != TAILQ_END(head); \
(var) = ((var)->field.tqe_next))
#define TAILQ_FOREACH_SAFE(var, head, field, next) \
for ((var) = ((head)->tqh_first); \
(var) != TAILQ_END(head) && \
((next) = TAILQ_NEXT(var, field), 1); (var) = (next))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \
for ((var) = TAILQ_LAST((head), headname); \
(var) != TAILQ_END(head) && \
((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev))
/*
* Tail queue functions.
*/
#if defined(QUEUEDEBUG)
#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \
if ((head)->tqh_first && \
(head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \
QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \
__FILE__, __LINE__);
#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \
if (*(head)->tqh_last != NULL) \
QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \
__FILE__, __LINE__);
#define QUEUEDEBUG_TAILQ_OP(elm, field) \
if ((elm)->field.tqe_next && \
(elm)->field.tqe_next->field.tqe_prev != \
&(elm)->field.tqe_next) \
QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \
__FILE__, __LINE__); \
if (*(elm)->field.tqe_prev != (elm)) \
QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \
__FILE__, __LINE__);
#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \
if ((elm)->field.tqe_next == NULL && \
(head)->tqh_last != &(elm)->field.tqe_next) \
QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\
(head), (elm), __FILE__, __LINE__);
#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \
(elm)->field.tqe_next = (void *)1L; \
(elm)->field.tqe_prev = (void *)1L;
#else
#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)
#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)
#define QUEUEDEBUG_TAILQ_OP(elm, field)
#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)
#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)
#endif
#define TAILQ_INIT(head) do { \
(head)->tqh_first = TAILQ_END(head); \
(head)->tqh_last = &(head)->tqh_first; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \
if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \
(elm)->field.tqe_next = TAILQ_END(head); \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
QUEUEDEBUG_TAILQ_OP((listelm), field) \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \
TAILQ_END(head)) \
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
QUEUEDEBUG_TAILQ_OP((listelm), field) \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (/*CONSTCOND*/0)
#define TAILQ_REMOVE(head, elm, field) do { \
QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \
QUEUEDEBUG_TAILQ_OP((elm), field) \
if (((elm)->field.tqe_next) != TAILQ_END(head)) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
} while (/*CONSTCOND*/0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \
TAILQ_END(head)) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
} while (/*CONSTCOND*/0)
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (/*CONSTCOND*/0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first; /* first element */ \
struct type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue access methods.
*/
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_END(head) NULL
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head))
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_INIT(head) do { \
(head)->stqh_first = NULL; \
(head)->stqh_last = &(head)->stqh_first; \
} while (/*CONSTCOND*/0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
(head)->stqh_last = &(elm)->field.stqe_next; \
(head)->stqh_first = (elm); \
} while (/*CONSTCOND*/0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.stqe_next = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &(elm)->field.stqe_next; \
} while (/*CONSTCOND*/0)
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
(head)->stqh_last = &(elm)->field.stqe_next; \
(listelm)->field.stqe_next = (elm); \
} while (/*CONSTCOND*/0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
(head)->stqh_last = &(head)->stqh_first; \
} while (/*CONSTCOND*/0)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if ((head)->stqh_first == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->stqh_first; \
while (curelm->field.stqe_next != (elm)) \
curelm = curelm->field.stqe_next; \
if ((curelm->field.stqe_next = \
curelm->field.stqe_next->field.stqe_next) == NULL) \
(head)->stqh_last = &(curelm)->field.stqe_next; \
} \
} while (/*CONSTCOND*/0)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = ((head)->stqh_first); \
(var); \
(var) = ((var)->field.stqe_next))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (/*CONSTCOND*/0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? \
NULL : \
((struct type *)(void *) \
((char *)((head)->stqh_last) - offsetof(struct type, field))))
#ifndef _KERNEL
/*
* Circular queue definitions. Do not use. We still keep the macros
* for compatibility but because of pointer aliasing issues their use
* is discouraged!
*/
/*
* __launder_type(): We use this ugly hack to work around the the compiler
* noticing that two types may not alias each other and elide tests in code.
* We hit this in the CIRCLEQ macros when comparing 'struct name *' and
* 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC
* 4.8) declare these comparisons as always false, causing the code to
* not run as designed.
*
* This hack is only to be used for comparisons and thus can be fully const.
* Do not use for assignment.
*
* If we ever choose to change the ABI of the CIRCLEQ macros, we could fix
* this by changing the head/tail sentinal values, but see the note above
* this one.
*/
static __inline const void * __launder_type(const void *);
static __inline const void *
__launder_type(const void *__x)
{
__asm __volatile("" : "+r" (__x));
return __x;
}
#if defined(QUEUEDEBUG)
#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \
if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \
(head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \
QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \
__FILE__, __LINE__); \
if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \
(head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \
QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \
__FILE__, __LINE__);
#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \
if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \
if ((head)->cqh_last != (elm)) \
QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \
(elm), __FILE__, __LINE__); \
} else { \
if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \
QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \
(elm), __FILE__, __LINE__); \
} \
if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \
if ((head)->cqh_first != (elm)) \
QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \
(elm), __FILE__, __LINE__); \
} else { \
if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \
QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \
(elm), __FILE__, __LINE__); \
}
#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \
(elm)->field.cqe_next = (void *)1L; \
(elm)->field.cqe_prev = (void *)1L;
#else
#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field)
#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field)
#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field)
#endif
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \
if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_FOREACH(var, head, field) \
for ((var) = ((head)->cqh_first); \
(var) != CIRCLEQ_ENDC(head); \
(var) = ((var)->field.cqe_next))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for ((var) = ((head)->cqh_last); \
(var) != CIRCLEQ_ENDC(head); \
(var) = ((var)->field.cqe_prev))
/*
* Circular queue access methods.
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
/* For comparisons */
#define CIRCLEQ_ENDC(head) (__launder_type(head))
/* For assignments */
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head))
#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
(((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
? ((head)->cqh_first) \
: (elm->field.cqe_next))
#define CIRCLEQ_LOOP_PREV(head, elm, field) \
(((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
? ((head)->cqh_last) \
: (elm->field.cqe_prev))
#endif /* !_KERNEL */
#endif /* !_SYS_QUEUE_H_ */
-22
View File
@@ -1,22 +0,0 @@
#ifndef _SYS_REDOX_H
#define _SYS_REDOX_H
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __redox__
ssize_t redox_fpath(int fd, void * buf, size_t count);
void * redox_physalloc(size_t size);
int redox_physfree(void * physical_address, size_t size);
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif
-16
View File
@@ -1,16 +0,0 @@
// From musl, license MIT
#ifndef _SYS_SYSMACROS_H
#define _SYS_SYSMACROS_H
#define major(x) \
((unsigned)( (((x)>>31>>1) & 0xfffff000) | (((x)>>8) & 0x00000fff) ))
#define minor(x) \
((unsigned)( (((x)>>12) & 0xffffff00) | ((x) & 0x000000ff) ))
#define makedev(x,y) ( \
(((x)&0xfffff000ULL) << 32) | \
(((x)&0x00000fffULL) << 8) | \
(((y)&0xffffff00ULL) << 12) | \
(((y)&0x000000ffULL)) )
#endif
-13
View File
@@ -1,13 +0,0 @@
#ifndef _SYS_USER_H
#define _SYS_USER_H
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
#include <arch/x64/user.h>
#elif defined(__aarch64__)
#include <arch/aarch64/user.h>
#elif defined(__riscv) && __riscv_xlen==64
#include <arch/riscv64/user.h>
#else
#error "Unknown architecture"
#endif
#endif
-1
View File
@@ -1 +0,0 @@
#include <sys/syslog.h>
-12
View File
@@ -1,12 +0,0 @@
[package]
name = "ld_so"
version = "0.1.0"
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
edition = "2024"
[lib]
name = "ld_so"
crate-type = ["staticlib"]
[lints]
workspace = true
@@ -1,263 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2025 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SEARCH_DIR("=/usr/aarch64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/aarch64-linux-gnu/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000));
. = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
/* Place the build-id as close to the ELF headers as possible. This
maximises the chance the build-id will be present in core files,
which GDB can then use to locate the associated debuginfo file. */
.note.gnu.build-id : { *(.note.gnu.build-id) }
.interp : { *(.interp) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.relr.dyn : { *(.relr.dyn) }
/* Start of the executable code region. */
.init :
{
KEEP (*(SORT_NONE(.init)))
} =0x1f2003d5
.plt : ALIGN(16) { *(.plt) *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
} =0x1f2003d5
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} =0x1f2003d5
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
/* Start of the Read Only Data region. */
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.sframe : ONLY_IF_RO { *(.sframe) *(.sframe.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Various note sections. Placed here so that they are always included
in the read-only segment and not treated as orphan sections. The
current orphan handling algorithm does place note sections after R/O
data, but this is not guaranteed to always be the case. */
.note.build-id : { *(.note.build-id) }
.note.GNU-stack : { *(.note.GNU-stack) }
.note.gnu-property : { *(.note.gnu-property) }
.note.ABI-tag : { *(.note.ABI-tag) }
.note.package : { *(.note.package) }
.note.dlopen : { *(.note.dlopen) }
.note.netbsd.ident : { *(.note.netbsd.ident) }
.note.openbsd.ident : { *(.note.openbsd.ident) }
/* Start of the Read Write Data region. */
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling. */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.sframe : ONLY_IF_RW { *(.sframe) *(.sframe.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections. */
/* .tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
/* .init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} */
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (24, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
PROVIDE (__data_start = .);
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .;
PROVIDE (edata = .);
. = ALIGN(ALIGNOF(NEXT_SECTION));
__bss_start = .;
__bss_start__ = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that in the common case of there only being one
type of .bss section, the section occupies space up to _end.
Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
_bss_end__ = .; __bss_end__ = .;
. = ALIGN(64 / 8);
/* Start of the Large Data region. */
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(64 / 8);
__end__ = .;
_end = .;
PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Start of the Tiny Data region. */
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 (INFO) : { *(.comment); LINKER_VERSION; }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3. */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF 5. */
.debug_addr 0 : { *(.debug_addr) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_names 0 : { *(.debug_names) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.debug_sup 0 : { *(.debug_sup) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
/DISCARD/ : {
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
/*
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
* that may reference use thread local storage.
*
* .init_array also depends on TLS and is discarded as we don't need it.
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
*(.init_array)
}
}
@@ -1 +0,0 @@
./aarch64-unknown-linux-gnu.ld
-255
View File
@@ -1,255 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64",
"elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SEARCH_DIR("/aarch64-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
/* .tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : {
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
/*
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
* that may reference use thread local storage.
*
* .init_array need to be not discarded unlike x86_64 linker variant
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
}
}
-256
View File
@@ -1,256 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/i686-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib32");
SEARCH_DIR("/lib32");
SEARCH_DIR("/usr/lib32");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
/* .tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
/* .init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} */
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : {
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
/*
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
* that may reference use thread local storage.
*
* .init_array also depends on TLS and is discarded as we don't need it.
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
*(.init_array)
}
}
-256
View File
@@ -1,256 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/i686-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib32");
SEARCH_DIR("/lib32");
SEARCH_DIR("/usr/lib32");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
/* .tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
/* .init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} */
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : {
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
/*
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
* that may reference use thread local storage.
*
* .init_array also depends on TLS and is discarded as we don't need it.
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
*(.init_array)
}
}
-247
View File
@@ -1,247 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv" )
OUTPUT_ARCH(riscv)
ENTRY(_start)
SEARCH_DIR("/riscv64-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
/* .tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
/* .init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} */
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : {
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
/*
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
* that may reference use thread local storage.
*
* .init_array also depends on TLS and is discarded as we don't need it.
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
*(.init_array)
}
}
-259
View File
@@ -1,259 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64");
SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.164");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib");
SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.1");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
/* .tdata : ALIGN(4K)
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
/* .init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} */
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : {
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
/*
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
* that may reference use thread local storage.
*
* .init_array also depends on TLS and is discarded as we don't need it.
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
*(.init_array)
}
}
@@ -1 +0,0 @@
./x86_64-unknown-linux-gnu.ld
-256
View File
@@ -1,256 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/x86_64-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
/* .tdata : ALIGN(4K)
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
/* .init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} */
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : {
*(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*)
/*
* XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor,
* ld.so will be moved out of relibc. So, till that time, we have to discard any sections
* that may reference use thread local storage.
*
* .init_array also depends on TLS and is discarded as we don't need it.
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
*(.init_array)
}
}
-136
View File
@@ -1,136 +0,0 @@
#![no_std]
#![feature(linkage)]
#![deny(unsafe_op_in_unsafe_fn)]
use core::arch::global_asm;
#[cfg(target_arch = "aarch64")]
global_asm!(
"
.weak _DYNAMIC
.hidden _DYNAMIC
.global _start
_start:
mov x28, sp
// align stack to 16 bytes
and sp, x28, #0xfffffffffffffff0
adr x1, _start
mov x0, x28
adrp x2, _DYNAMIC
add x2, x2, #:lo12:_DYNAMIC
// ld_so_start(stack=x0, ld_entry=x1, dynamic=x2)
bl relibc_ld_so_start
// restore original stack, clear registers, and jump to the new start function
mov sp, x28
mov x1, xzr
mov x2, xzr
mov x3, xzr
mov x4, xzr
mov x5, xzr
mov x6, xzr
mov x7, xzr
mov x8, xzr
mov x9, xzr
mov x10, xzr
mov x11, xzr
mov x12, xzr
mov x13, xzr
mov x14, xzr
mov x15, xzr
mov x16, xzr
mov x17, xzr
mov x18, xzr
mov x19, xzr
mov x20, xzr
mov x21, xzr
mov x22, xzr
mov x23, xzr
mov x24, xzr
mov x25, xzr
mov x26, xzr
mov x27, xzr
mov x28, xzr
mov x29, xzr
mov x30, xzr
br x0
udf #0
"
);
#[cfg(target_arch = "x86")]
global_asm!(
"
.globl _start
_start:
push esp
call relibc_ld_so_start
pop esp
# TODO: x86
ud2
"
);
#[cfg(target_arch = "x86_64")]
global_asm!(
"
.weak _DYNAMIC
.hidden _DYNAMIC
.globl _start
_start:
lea rsi, [rip + _start]
# Save original stack and align stack to 16 bytes
mov rbp, rsp
and rsp, 0xfffffffffffffff0
# Call ld_so_start(stack=rdi, ld_entry=rsi, dynamic=rdx)
mov rdi, rbp
lea rdx, [rip + _DYNAMIC]
call relibc_ld_so_start
# Restore original stack, clear registers, and jump to new start function
mov rsp, rbp
xor rcx, rcx
xor rdx, rdx
xor rdi, rdi
xor rsi, rsi
xor r8, r8
xor r9, r9
xor r10, r10
xor r11, r11
fninit
jmp rax
ud2
"
);
#[cfg(target_arch = "riscv64")]
global_asm!(
"
.globl _start
_start:
mv a0, sp
jal relibc_ld_so_start
unimp
"
);
#[unsafe(no_mangle)]
pub unsafe extern "C" fn main(_argc: isize, _argv: *const *const i8) -> usize {
// LD
0x1D
}
#[linkage = "weak"]
#[unsafe(no_mangle)]
extern "C" fn relibc_panic(_pi: &::core::panic::PanicInfo) -> ! {
loop {}
}
#[panic_handler]
#[linkage = "weak"]
pub unsafe fn rust_begin_unwind(pi: &::core::panic::PanicInfo) -> ! {
relibc_panic(pi)
}
+78
View File
@@ -0,0 +1,78 @@
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(coff_start)
SECTIONS
{
PROVIDE(ImageBase = .);
. = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) *(.gnu.hash) }
. = ALIGN(4096);
.text :
{
PROVIDE(_text = .);
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(4096);
.rdata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
KEEP (*(.eh_frame))
*(.eh_frame.*)
*(.dynamic)
}
. = ALIGN(4096);
.data :
{
*(.got) *(.igot)
*(.got.plt) *(.igot.plt)
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
PROVIDE (_edata = .); PROVIDE (edata = .);
. = ALIGN(4096);
PROVIDE (__bss_start = .);
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4096);
}
.reloc :
{
KEEP(*(.reloc*))
}
.rela :
{
*(.rela.*)
}
.data.rel.ro :
{
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
}
. = ALIGN(4096);
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
+57
View File
@@ -0,0 +1,57 @@
ENTRY(start)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
/* The start address must match bootloader.asm */
. = 0x13000;
. += SIZEOF_HEADERS;
. = ALIGN(4096);
.text : {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : {
__rodata_start = .;
*(.rodata*)
. = ALIGN(4096);
__rodata_end = .;
}
.data : {
__data_start = .;
*(.data*)
. = ALIGN(4096);
__data_end = .;
__bss_start = .;
*(.bss*)
. = ALIGN(4096);
__bss_end = .;
}
.tdata : {
__tdata_start = .;
*(.tdata*)
. = ALIGN(4096);
__tdata_end = .;
__tbss_start = .;
*(.tbss*)
. += 8;
. = ALIGN(4096);
__tbss_end = .;
}
__end = .;
/DISCARD/ : {
*(.comment*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}
+63
View File
@@ -0,0 +1,63 @@
export PARTED?=parted
export QEMU?=qemu-system-aarch64
all: $(BUILD)/bootloader.efi
$(BUILD)/bootloader.efi: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p "$(BUILD)"
env RUSTFLAGS="--cfg aes_force_soft -Zunstable-options" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--bin bootloader \
-- \
--emit link="$@"
$(BUILD)/bootloader-live.efi: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p "$(BUILD)"
env RUSTFLAGS="--cfg aes_force_soft -Zunstable-options" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--bin bootloader \
--features live \
-- \
--emit link="$@"
$(BUILD)/esp.bin: $(BUILD)/bootloader.efi
rm -f "$@.partial"
fallocate -l 64MiB "$@.partial"
mkfs.vfat -F 32 "$@.partial"
mmd -i "$@.partial" efi
mmd -i "$@.partial" efi/boot
mcopy -i "$@.partial" "$<" ::efi/boot/bootaa64.efi
mv "$@.partial" "$@"
$(BUILD)/harddrive.bin: $(BUILD)/esp.bin $(BUILD)/filesystem.bin
rm -f "$@.partial"
fallocate -l 320MiB "$@.partial"
$(PARTED) -s -a minimal "$@.partial" mklabel gpt
$(PARTED) -s -a minimal "$@.partial" mkpart ESP FAT32 1MiB 65MiB
$(PARTED) -s -a minimal "$@.partial" mkpart REDOXFS 65MiB 100%
$(PARTED) -s -a minimal "$@.partial" toggle 1 boot
dd if="$(BUILD)/esp.bin" of="$@.partial" bs=1MiB seek=1 conv=notrunc
dd if="$(BUILD)/filesystem.bin" of="$@.partial" bs=1MiB seek=65 conv=notrunc
mv "$@.partial" "$@"
$(BUILD)/firmware.rom: /usr/share/AAVMF/AAVMF_CODE.fd
cp "$<" "$@"
qemu: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom
$(QEMU) \
-d cpu_reset \
-no-reboot \
-smp 4 -m 2048 \
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-device virtio-gpu-pci \
-machine virt \
-net none \
-cpu max \
-bios "$(BUILD)/firmware.rom" \
-drive file="$<",format=raw
+102
View File
@@ -0,0 +1,102 @@
LD=riscv64-unknown-redox-ld
OBJCOPY=riscv64-unknown-redox-objcopy
SCRIPT=$(SOURCE)/linkers/riscv64-unknown-uefi.ld
PARTED?=parted
QEMU?=qemu-system-riscv64
all: $(BUILD)/bootloader.efi
$(BUILD)/%.efi: $(BUILD)/%.efi.elf $(BUILD)/%.efi.sym
$(OBJCOPY) -j .text -j .data -j .rdata -j .rela -j .reloc --target pei-riscv64-little \
--file-alignment 512 --section-alignment 4096 --subsystem 10 "$<" "$@"
.PRECIOUS: $(BUILD)/%.efi.sym
$(BUILD)/%.efi.sym: $(BUILD)/%.efi.elf
$(OBJCOPY) --only-keep-debug "$<" "$@"
$(BUILD)/%.efi.elf: $(BUILD)/%.a $(SCRIPT)
$(LD) --gc-sections -z max-page-size=0x1000 --warn-common --no-undefined -z nocombreloc -shared \
--fatal-warnings -Bsymbolic --entry coff_start -T "$(SCRIPT)" -o "$@" "$<"
$(BUILD)/bootloader.a: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p "$(BUILD)"
env RUSTFLAGS="--cfg aes_force_soft -Zunstable-options" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--lib \
-- \
--emit link=$@
$(BUILD)/bootloader-live.a: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p "$(BUILD)"
env RUSTFLAGS="--cfg aes_force_soft -Zunstable-options" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--lib \
--features live \
-- \
--emit link=$@
$(BUILD)/esp.bin: $(BUILD)/bootloader.efi
rm -f $@.partial
fallocate -l 64MiB $@.partial
mkfs.vfat -F 32 $@.partial
mmd -i $@.partial EFI
mmd -i $@.partial EFI/BOOT
mcopy -i $@.partial $< ::EFI/BOOT/BOOTRISCV64.EFI
mv $@.partial $@
$(BUILD)/harddrive.bin: $(BUILD)/esp.bin $(BUILD)/filesystem.bin
rm -f $@.partial
fallocate -l 320MiB $@.partial
$(PARTED) -s -a minimal $@.partial mklabel gpt
$(PARTED) -s -a minimal $@.partial mkpart ESP FAT32 1MiB 65MiB
$(PARTED) -s -a minimal $@.partial mkpart REDOXFS 65MiB 100%
$(PARTED) -s -a minimal $@.partial toggle 1 boot
dd if=$(BUILD)/esp.bin of=$@.partial bs=1MiB seek=1 conv=notrunc
dd if=$(BUILD)/filesystem.bin of=$@.partial bs=1MiB seek=65 conv=notrunc
mv $@.partial $@
$(BUILD)/fw_vars.img: /usr/share/qemu-efi-riscv64/RISCV_VIRT_VARS.fd
cp "$<" "$@"
$(BUILD)/firmware.rom: /usr/share/qemu-efi-riscv64/RISCV_VIRT_CODE.fd
cp "$<" "$@"
qemu-acpi: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom $(BUILD)/fw_vars.img
$(QEMU) \
-M virt \
-d cpu_reset \
-no-reboot \
-smp 4 -m 2048 \
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-device virtio-gpu-pci \
-machine virt \
-net none \
-cpu max \
-drive if=pflash,format=raw,unit=0,file=$(BUILD)/firmware.rom,readonly=on \
-drive if=pflash,format=raw,unit=1,file=$(BUILD)/fw_vars.img \
-drive file=$(BUILD)/harddrive.bin,format=raw,if=virtio
qemu-dtb: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom $(BUILD)/fw_vars.img
$(QEMU) \
-M virt,acpi=off \
-d cpu_reset \
-no-reboot \
-smp 4 -m 2048 \
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-device virtio-gpu-pci \
-machine virt \
-net none \
-cpu max \
-drive if=pflash,format=raw,unit=0,file=$(BUILD)/firmware.rom,readonly=on \
-drive if=pflash,format=raw,unit=1,file=$(BUILD)/fw_vars.img \
-drive file=$(BUILD)/harddrive.bin,format=raw,if=virtio -s
+59
View File
@@ -0,0 +1,59 @@
export LD?=ld
export OBJCOPY?=objcopy
export PARTED?=parted
export QEMU?=qemu-system-x86_64
all: $(BUILD)/bootloader.bin
$(BUILD)/libbootloader.a: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p "$(BUILD)"
env RUSTFLAGS="--cfg aes_force_soft -Zunstable-options" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--lib \
-- \
--emit link="$@"
$(BUILD)/libbootloader-live.a: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p "$(BUILD)"
env RUSTFLAGS="--cfg aes_force_soft -Zunstable-options" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--lib \
--features live \
-- \
--emit link="$@"
$(BUILD)/%.elf: $(BUILD)/lib%.a $(SOURCE)/linkers/$(TARGET).ld
$(LD) -m elf_i386 --gc-sections -z max-page-size=0x1000 -T "$(SOURCE)/linkers/$(TARGET).ld" -o "$@" "$<"
$(OBJCOPY) --only-keep-debug "$@" "$@.sym"
$(OBJCOPY) --strip-debug "$@"
$(BUILD)/%.bin: $(BUILD)/%.elf $(shell find $(SOURCE)/asm/$(TARGET) -type f)
nasm -f bin -o "$@" -l "$@.lst" -D STAGE3="$<" -i"$(SOURCE)/asm/$(TARGET)/" "$(SOURCE)/asm/$(TARGET)/bootloader.asm"
$(BUILD)/harddrive.bin: $(BUILD)/bootloader.bin $(BUILD)/filesystem.bin
rm -f "$@.partial"
fallocate -l 256MiB "$@.partial"
$(PARTED) -s -a minimal "$@.partial" mklabel msdos
$(PARTED) -s -a minimal "$@.partial" mkpart primary 2MiB 100%
dd if="$<" of="$@.partial" bs=1 count=446 conv=notrunc
dd if="$<" of="$@.partial" bs=512 skip=1 seek=1 conv=notrunc
dd if="$(BUILD)/filesystem.bin" of="$@.partial" bs=1MiB seek=2 conv=notrunc
mv "$@.partial" "$@"
qemu: $(BUILD)/harddrive.bin
$(QEMU) \
-d cpu_reset \
-no-reboot \
-smp 4 -m 2048 \
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-machine q35 \
-net none \
-enable-kvm \
-cpu host \
-drive file="$<",format=raw
+64
View File
@@ -0,0 +1,64 @@
export PARTED?=parted
export QEMU?=qemu-system-x86_64
all: $(BUILD)/bootloader.efi
$(BUILD)/bootloader.efi: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p "$(BUILD)"
env RUSTFLAGS="--cfg aes_force_soft" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--bin bootloader \
-- \
--emit link="$@"
$(BUILD)/bootloader-live.efi: $(SOURCE)/Cargo.toml $(SOURCE)/Cargo.lock $(shell find $(SOURCE)/src -type f)
mkdir -p $(BUILD)
cd "$(SOURCE)"
env RUSTFLAGS="--cfg aes_force_soft" \
cargo rustc \
--manifest-path="$<" \
$(CARGO_ARGS) \
--bin bootloader \
--features live \
-- \
--emit link="$@"
$(BUILD)/esp.bin: $(BUILD)/bootloader.efi
rm -f "$@.partial"
fallocate -l 1MiB $@.partial
mkfs.vfat "$@.partial"
mmd -i "$@.partial" efi
mmd -i "$@.partial" efi/boot
mcopy -i "$@.partial" "$<" ::efi/boot/bootx64.efi
mv "$@.partial" "$@"
$(BUILD)/harddrive.bin: $(BUILD)/esp.bin $(BUILD)/filesystem.bin
rm -f "$@.partial"
fallocate -l 320MiB "$@.partial"
$(PARTED) -s -a minimal "$@.partial" mklabel gpt
$(PARTED) -s -a minimal "$@.partial" mkpart ESP FAT32 1MiB 2MiB
$(PARTED) -s -a minimal "$@.partial" mkpart REDOXFS 2MiB 100%
$(PARTED) -s -a minimal "$@.partial" toggle 1 boot
dd if="$(BUILD)/esp.bin" of="$@.partial" bs=1MiB seek=1 conv=notrunc
dd if="$(BUILD)/filesystem.bin" of="$@.partial" bs=1MiB seek=2 conv=notrunc
mv "$@.partial" "$@"
$(BUILD)/firmware.rom: /usr/share/OVMF/OVMF_CODE.fd
cp "$<" "$@"
qemu: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom
$(QEMU) \
-d cpu_reset \
-no-reboot \
-smp 4 -m 2048 \
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-machine q35 \
-net none \
-enable-kvm \
-cpu host \
-bios "$(BUILD)/firmware.rom" \
-drive file="$<",format=raw
Submodule openlibm deleted from f5ed774593
-16
View File
@@ -1,16 +0,0 @@
[package]
name = "redox-ioctl"
authors = ["bjorn3 <bjorn3_gh@protonmail.com>"]
version = "0.1.0"
edition = "2024"
license = "MIT"
description = "Ioctl definitions and (de)serialization for Redox"
[dependencies]
drm-sys = "0.8.0"
redox_syscall = "0.9.0"
[features]
[lints]
workspace = true
-347
View File
@@ -1,347 +0,0 @@
use alloc::vec::Vec;
use core::{
cmp,
ffi::{c_char, c_int, c_uint},
iter, mem, slice,
};
pub use drm_sys::{
__kernel_size_t, DRM_PROP_NAME_LEN, drm_clip_rect, drm_get_cap, drm_mode_card_res,
drm_mode_closefb, drm_mode_connector_set_property, drm_mode_create_dumb, drm_mode_crtc,
drm_mode_crtc_page_flip_target, drm_mode_cursor, drm_mode_cursor2, drm_mode_destroy_dumb,
drm_mode_fb_cmd, drm_mode_fb_cmd2, drm_mode_fb_dirty_cmd, drm_mode_get_blob,
drm_mode_get_connector, drm_mode_get_encoder, drm_mode_get_plane, drm_mode_get_plane_res,
drm_mode_get_property, drm_mode_map_dumb, drm_mode_modeinfo, drm_mode_obj_get_properties,
drm_mode_property_enum, drm_mode_set_plane, drm_set_client_cap, drm_set_version, drm_unique,
drm_version,
};
pub const VERSION: u64 = 0;
define_ioctl_data! {
struct drm_version, DrmVersion {
version_major: c_int,
version_minor: c_int,
version_patchlevel: c_int,
name_len: __kernel_size_t,
name: *mut c_char [array<c_char, name_len>],
date_len: __kernel_size_t,
date: *mut c_char [array<c_char, date_len>],
desc_len: __kernel_size_t,
desc: *mut c_char [array<c_char, desc_len>],
}
}
pub const GET_UNIQUE: u64 = 0x01;
define_ioctl_data! {
struct drm_unique, DrmUnique {
unique_len: __kernel_size_t,
unique: *mut c_char [array<c_char, unique_len>],
}
}
pub const SET_VERSION: u64 = 0x07;
define_ioctl_data! {
struct drm_set_version, DrmSetVersion {
drm_di_major: c_int,
drm_di_minor: c_int,
drm_dd_major: c_int,
drm_dd_minor: c_int,
}
}
pub const GET_CAP: u64 = 0x0C;
pub use drm_sys::DRM_CAP_DUMB_BUFFER;
define_ioctl_data! {
struct drm_get_cap, DrmGetCap {
capability: u64,
value: u64,
}
}
pub const SET_CLIENT_CAP: u64 = 0x0D;
pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT;
define_ioctl_data! {
struct drm_set_client_cap, DrmSetClientCap {
capability: u64,
value: u64,
}
}
pub const MODE_CARD_RES: u64 = 0xA0;
define_ioctl_data! {
struct drm_mode_card_res, DrmModeCardRes {
fb_id_ptr: u64 [array<u32, count_fbs>],
crtc_id_ptr: u64 [array<u32, count_crtcs>],
connector_id_ptr: u64 [array<u32, count_connectors>],
encoder_id_ptr: u64 [array<u32, count_encoders>],
count_fbs: u32,
count_crtcs: u32,
count_connectors: u32,
count_encoders: u32,
min_width: u32,
max_width: u32,
min_height: u32,
max_height: u32,
}
}
pub const MODE_GET_CRTC: u64 = 0xA1;
pub const MODE_SET_CRTC: u64 = 0xA2;
define_ioctl_data! {
struct drm_mode_crtc, DrmModeCrtc {
set_connectors_ptr: u64 [array<u32, count_connectors>],
count_connectors: u32,
crtc_id: u32,
fb_id: u32,
x: u32,
y: u32,
gamma_size: u32,
mode_valid: u32,
mode: drm_mode_modeinfo,
}
}
pub const MODE_CURSOR: u64 = 0xA3;
define_ioctl_data! {
struct drm_mode_cursor, DrmModeCursor {
flags: u32,
crtc_id: u32,
x: i32,
y:i32,
width:u32,
height:u32,
handle:u32,
}
}
pub const MODE_GET_ENCODER: u64 = 0xA6;
define_ioctl_data! {
struct drm_mode_get_encoder, DrmModeGetEncoder {
encoder_id: u32,
encoder_type: u32,
crtc_id: u32,
possible_crtcs: u32,
possible_clones: u32,
}
}
pub const MODE_GET_CONNECTOR: u64 = 0xA7;
define_ioctl_data! {
struct drm_mode_get_connector, DrmModeGetConnector {
encoders_ptr: u64 [array<u32, count_encoders>],
modes_ptr: u64 [array<drm_mode_modeinfo, count_modes>],
props_ptr: u64 [array<u32, count_props>],
prop_values_ptr: u64 [array<u64, count_props>],
count_modes: u32,
count_props: u32,
count_encoders: u32,
encoder_id: u32,
connector_id: u32,
connector_type: u32,
connector_type_id: u32,
connection: u32,
mm_width: u32,
mm_height: u32,
subpixel: u32,
pad: u32,
}
}
pub const MODE_GET_PROPERTY: u64 = 0xAA;
define_ioctl_data! {
struct drm_mode_get_property, DrmModeGetProperty {
values_ptr: u64 [array<u64, count_values>],
enum_blob_ptr: u64 [array<drm_mode_property_enum, count_enum_blobs>],
prop_id: u32,
flags: u32,
name: [c_char; DRM_PROP_NAME_LEN as usize],
count_values: u32,
count_enum_blobs: u32,
}
}
pub const MODE_SET_PROPERTY: u64 = 0xAB;
define_ioctl_data! {
struct drm_mode_connector_set_property, DrmModeConnectorSetProperty {
value: u64,
prop_id: u32,
connector_id: u32,
}
}
pub const MODE_GET_PROP_BLOB: u64 = 0xAC;
define_ioctl_data! {
struct drm_mode_get_blob, DrmModeGetBlob {
blob_id: u32,
length: u32,
data: u64 [array<u8, length>],
}
}
pub const MODE_GET_FB: u64 = 0xAD;
pub const MODE_ADD_FB: u64 = 0xAE;
define_ioctl_data! {
struct drm_mode_fb_cmd, DrmModeFbCmd {
fb_id: u32,
width: u32,
height: u32,
pitch: u32,
bpp: u32,
depth: u32,
handle: u32,
}
}
pub const MODE_RM_FB: u64 = 0xAF;
define_ioctl_data! {
struct standin_for_uint, StandinForUint {
inner: c_uint,
}
}
#[repr(transparent)]
#[allow(non_camel_case_types)]
pub struct standin_for_uint {
pub inner: c_uint,
}
pub const MODE_PAGE_FLIP: u64 = 0xB0;
define_ioctl_data! {
struct drm_mode_crtc_page_flip_target, DrmModeCrtcPageFlipTarget {
crtc_id: u32,
fb_id: u32,
flags: u32,
sequence: u32,
user_data: u64,
}
}
pub const MODE_DIRTYFB: u64 = 0xB1;
define_ioctl_data! {
struct drm_mode_fb_dirty_cmd, DrmModeFbDirtyCmd {
fb_id: u32,
flags: u32,
color: u32,
num_clips: u32,
clips_ptr: u64 [array<drm_clip_rect, num_clips>],
}
}
pub const MODE_CREATE_DUMB: u64 = 0xB2;
define_ioctl_data! {
struct drm_mode_create_dumb, DrmModeCreateDumb {
height: u32,
width: u32,
bpp: u32,
flags: u32,
handle: u32,
pitch: u32,
size: u64,
}
}
pub const MODE_MAP_DUMB: u64 = 0xB3;
define_ioctl_data! {
struct drm_mode_map_dumb, DrmModeMapDumb {
handle: u32,
pad: u32,
offset: u64,
}
}
pub const MODE_DESTROY_DUMB: u64 = 0xB4;
define_ioctl_data! {
struct drm_mode_destroy_dumb, DrmModeDestroyDumb {
handle: u32,
}
}
pub const MODE_GET_PLANE_RES: u64 = 0xB5;
define_ioctl_data! {
struct drm_mode_get_plane_res, DrmModeGetPlaneRes {
plane_id_ptr: u64 [array<u32, count_planes>],
count_planes: u32,
}
}
pub const MODE_GET_PLANE: u64 = 0xB6;
define_ioctl_data! {
struct drm_mode_get_plane, DrmModeGetPlane {
plane_id: u32,
crtc_id: u32,
fb_id: u32,
possible_crtcs: u32,
gamma_size: u32,
count_format_types: u32,
format_type_ptr: u64 [array<u32, count_format_types>],
}
}
pub const MODE_SET_PLANE: u64 = 0xB7;
define_ioctl_data! {
struct drm_mode_set_plane, DrmModeSetPlane {
plane_id: u32,
crtc_id: u32,
fb_id: u32,
flags: u32,
crtc_x: i32,
crtc_y: i32,
crtc_w: u32,
crtc_h: u32,
src_x: u32,
src_y: u32,
src_h: u32,
src_w: u32,
}
}
pub const MODE_ADD_FB2: u64 = 0xB8;
pub const MODE_OBJ_GET_PROPERTIES: u64 = 0xB9;
define_ioctl_data! {
struct drm_mode_obj_get_properties, DrmModeObjGetProperties {
props_ptr: u64 [array<u32, count_props>],
prop_values_ptr: u64 [array<u64, count_props>],
count_props: u32,
obj_id: u32,
obj_type: u32,
}
}
pub const MODE_CURSOR2: u64 = 0xBB;
define_ioctl_data! {
struct drm_mode_cursor2, DrmModeCursor2 {
flags: u32,
crtc_id: u32,
x: i32,
y: i32,
width: u32,
height: u32,
handle: u32,
hot_x: i32,
hot_y: i32,
}
}
pub const MODE_GET_FB2: u64 = 0xCE;
define_ioctl_data! {
struct drm_mode_fb_cmd2, DrmModeFbCmd2 {
fb_id: u32,
width: u32,
height: u32,
pixel_format: u32,
flags: u32,
handles: [u32; 4],
pitches: [u32; 4],
offsets: [u32; 4],
modifier: [u64; 4],
}
}
pub const MODE_CLOSE_FB: u64 = 0xD0;
define_ioctl_data! {
struct drm_mode_closefb, DrmModeClosefb {
fb_id: u32,
pad: u32,
}
}
-168
View File
@@ -1,168 +0,0 @@
use alloc::vec::Vec;
pub trait IoctlData {
unsafe fn write(&self) -> Vec<u8>;
unsafe fn read_from(&mut self, buf: &[u8]);
}
macro_rules! define_ioctl_data {
(struct $ioctl_ty:ident, $mem_ty:ident {
$($rest:tt)*
}) => {
define_ioctl_data!(
struct $ioctl_ty, $mem_ty { $($rest)* } => (), (), ()
);
};
(struct $ioctl_ty:ident, $mem_ty:ident {
$field:ident: $ty:ty,
$($rest:tt)*
} =>
($($ioctl_fields:tt)*),
($($counted_fields:tt)*),
($($noncounted_fields:tt)*)
) => {
define_ioctl_data!(
struct $ioctl_ty, $mem_ty { $($rest)* } =>
($($ioctl_fields)* $field: $ty,),
($($counted_fields)*),
($($noncounted_fields)* $field: $ty,)
);
};
(struct $ioctl_ty:ident, $mem_ty:ident {
$field:ident: $ty:ty [array<$el:ty, $counted_by:ident>],
$($rest:tt)*
} =>
($($ioctl_fields:tt)*),
($($counted_fields:tt)*),
($($noncounted_fields:tt)*)
) => {
define_ioctl_data!(
struct $ioctl_ty, $mem_ty { $($rest)* } =>
($($ioctl_fields)* $field: $ty,),
($($counted_fields)* $field: $ty [array<$el, $counted_by>],),
($($noncounted_fields)*)
);
};
(struct $ioctl_ty:ident, $mem_ty:ident {} =>
($($ioctl_field:ident: $ioctl_field_ty:ty,)*),
($($counted_field:ident: $counted_ty:ty [array<$el:ty, $counted_by:ident>],)*),
($($noncounted_field:ident: $noncounted_ty:ty,)*)
) => {
// FIXME check ioctl_ty doesn't have padding
const _: $ioctl_ty = $ioctl_ty {
$($ioctl_field: unsafe { mem::zeroed::<$ioctl_field_ty>() },)*
};
#[repr(C)]
pub struct ${concat(__, $mem_ty, Noncounted)} {
$($noncounted_field: $noncounted_ty,)*
}
pub struct $mem_ty<'a> {
noncounted_fields: &'a mut ${concat(__, $mem_ty, Noncounted)},
$($counted_field: &'a mut [$el],)*
}
impl $crate::ioctl_data::IoctlData for $ioctl_ty {
unsafe fn write(&self) -> Vec<u8> {
let noncounted_fields = ${concat(__, $mem_ty, Noncounted)} {
$($noncounted_field: self.$noncounted_field,)*
};
// FIXME use Vec::with_capacity
let mut data = Vec::<u8>::new();
data.extend_from_slice(&unsafe {
mem::transmute::<
${concat(__, $mem_ty, Noncounted)},
[u8; size_of::<${concat(__, $mem_ty, Noncounted)}>()],
>(noncounted_fields)
});
$(
let size = self.$counted_by as usize * size_of::<$el>();
if self.$counted_field as usize != 0 {
let $counted_field = unsafe {
slice::from_raw_parts(self.$counted_field as *const u8, size)
};
data.extend_from_slice(&$counted_field);
} else {
data.extend(iter::repeat(0u8).take(size));
};
)*
data
}
unsafe fn read_from(&mut self, mut buf: &[u8]) {
// FIXME be robust against malicious scheme implementations by returning an error
// when the buf is the wrong size
let noncounted_fields = buf.split_off(..size_of::<${concat(__, $mem_ty, Noncounted)}>()).unwrap();
$(
let size = self.$counted_by as usize * size_of::<$el>();
let $counted_field = buf.split_off(..size).unwrap();
if self.$counted_field as usize != 0 {
unsafe {
slice::from_raw_parts_mut(self.$counted_field as *mut u8, size).copy_from_slice($counted_field);
}
}
)*
assert!(buf.is_empty());
let noncounted_fields = unsafe { &*core::ptr::from_ref(noncounted_fields).cast::<${concat(__, $mem_ty, Noncounted)}>() };
$(self.$noncounted_field = noncounted_fields.$noncounted_field;)*
}
}
impl<'a> $mem_ty<'a> {
pub fn with(
mut buf: &'a mut [u8],
f: impl FnOnce($mem_ty<'a>) -> syscall::Result<usize>,
) -> syscall::Result<usize> {
let noncounted_fields = buf.split_off_mut(..size_of::<${concat(__, $mem_ty, Noncounted)}>())
.ok_or(syscall::Error::new(syscall::EINVAL))?;
let noncounted_fields = unsafe { &mut *core::ptr::from_mut(noncounted_fields).cast::<${concat(__, $mem_ty, Noncounted)}>() };
$(
let $counted_field = buf.split_off_mut(..noncounted_fields.$counted_by as usize * size_of::<$el>())
.ok_or(syscall::Error::new(syscall::EINVAL))?;
let $counted_field = unsafe {
slice::from_raw_parts_mut(core::ptr::from_mut($counted_field).cast::<$el>(), noncounted_fields.$counted_by as usize)
};
)*
if !buf.is_empty() {
return Err(syscall::Error::new(syscall::EINVAL));
}
f($mem_ty {
noncounted_fields,
$($counted_field,)*
})
}
$(
pub fn $noncounted_field(&self) -> $noncounted_ty {
self.noncounted_fields.$noncounted_field
}
/// Should not be called for fields used as array length
pub fn ${concat(set_, $noncounted_field)}(&mut self, data: $noncounted_ty) {
self.noncounted_fields.$noncounted_field = data;
}
)*
$(
pub fn $counted_field(&self) -> &[$el] {
self.$counted_field
}
pub fn ${concat(set_, $counted_field)}(&mut self, data: &[$el]) {
let copied_count = cmp::min(data.len(), self.$counted_field.len());
self.$counted_field[..copied_count].copy_from_slice(&data[..copied_count]);
self.noncounted_fields.$counted_by = data.len() as _;
}
)*
}
};
}
-11
View File
@@ -1,11 +0,0 @@
#![feature(macro_metavar_expr_concat)]
#![deny(unsafe_op_in_unsafe_fn)]
#![no_std]
extern crate alloc;
#[macro_use]
mod ioctl_data;
pub use ioctl_data::IoctlData;
pub mod drm;
-27
View File
@@ -1,27 +0,0 @@
[package]
name = "redox-rt"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
version = "0.1.0"
edition = "2024"
license = "MIT"
description = "Libc-independent runtime for Redox"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bitflags.workspace = true
goblin = { version = "0.10", default-features = false, features = ["elf32", "elf64", "endian_fd"] }
plain.workspace = true
ioslice.workspace = true
redox_syscall.workspace = true
redox-path.workspace = true
redox_protocols.workspace = true
generic-rt = { path = "../generic-rt" }
[features]
proc = []
default = ["proc"]
[lints]
workspace = true
-492
View File
@@ -1,492 +0,0 @@
use core::{cell::SyncUnsafeCell, mem::offset_of, ptr::NonNull};
use syscall::{data::*, error::*};
use crate::{
Tcb,
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
signal::{PosixStackt, RtSigarea, SigStack, inner_c},
};
use redox_protocols::protocol::{ProcCall, RtSigInfo};
use super::ForkScratchpad;
// Setup a stack starting from the very end of the address space, and then growing downwards.
pub const STACK_TOP: usize = 1 << 47;
pub const STACK_SIZE: usize = 1024 * 1024;
#[derive(Debug, Default)]
#[repr(C)]
pub struct SigArea {
pub altstack_top: usize,
pub altstack_bottom: usize,
pub tmp_x1_x2: [usize; 2],
pub tmp_x3_x4: [usize; 2],
pub tmp_x5_x6: [usize; 2],
pub tmp_x7_x8: [usize; 2],
pub tmp_sp: usize,
pub onstack: u64,
pub disable_signals_depth: u64,
pub pctl: usize, // TODO: remove
pub last_sig_was_restart: bool,
pub last_sigstack: Option<NonNull<SigStack>>,
pub tmp_rt_inf: RtSigInfo,
pub tmp_id_inf: u64,
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct ArchIntRegs {
pub x30: usize,
pub x29: usize,
pub x28: usize,
pub x27: usize,
pub x26: usize,
pub x25: usize,
pub x24: usize,
pub x23: usize,
pub x22: usize,
pub x21: usize,
pub x20: usize,
pub x19: usize,
pub x18: usize,
pub x17: usize,
pub x16: usize,
pub x15: usize,
pub x14: usize,
pub x13: usize,
pub x12: usize,
pub x11: usize,
pub x10: usize,
pub x9: usize,
pub x8: usize,
pub x7: usize,
pub x6: usize,
pub x5: usize,
pub x4: usize,
pub x3: usize,
pub x2: usize,
pub x1: usize,
pub sp: usize,
pub nzcv: usize, // user-accessible PSTATE bits
pub pc: usize,
pub x0: usize,
}
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
/// is already initialized as if it was a thread.
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
let mut env = syscall::EnvRegisters::default();
let file = open_via_dup.dup_into_upper(b"regs/env")?;
env.tpidr_el0 = 0;
file.write(&mut env)?;
crate::TLS_ACTIVATED.store(false, core::sync::atomic::Ordering::Relaxed);
Ok(())
}
unsafe extern "C" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
Error::mux(fork_inner(initial_rsp, args))
}
unsafe extern "C" fn child_hook(scratchpad: &ForkScratchpad) {
//let _ = syscall::write(1, alloc::format!("CUR{cur_filetable_fd}PROC{new_proc_fd}THR{new_thr_fd}\n").as_bytes());
let _ = crate::sys::close(scratchpad.cur_filetable_fd);
unsafe {
crate::child_hook_common(crate::ChildHookCommonArgs {
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
None
} else {
Some(FdGuard::new(scratchpad.new_proc_fd))
},
new_filetable_fd: FdGuard::new(scratchpad.new_filetable_fd)
.to_upper()
.unwrap(),
})
};
}
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
stp x29, x30, [sp, #-16]!
stp x27, x28, [sp, #-16]!
stp x25, x26, [sp, #-16]!
stp x23, x24, [sp, #-16]!
stp x21, x22, [sp, #-16]!
stp x19, x20, [sp, #-16]!
//TODO: store floating point regs
// x0: &ForkArgs
mov x1, sp
bl {fork_impl}
ldp x19, x20, [sp], #16
ldp x21, x22, [sp], #16
ldp x23, x24, [sp], #16
ldp x25, x26, [sp], #16
ldp x27, x28, [sp], #16
ldp x29, x30, [sp], #16
ret
"] <= [fork_impl = sym fork_impl]);
asmfunction!(__relibc_internal_fork_ret: ["
# scratchpad is in x1, move to x0 for child_hook
mov x0, x1
bl {child_hook}
//TODO: load floating point regs
mov x0, xzr
ldp x19, x20, [sp], #16
ldp x21, x22, [sp], #16
ldp x23, x24, [sp], #16
ldp x25, x26, [sp], #16
ldp x27, x28, [sp], #16
ldp x29, x30, [sp], #16
ret
"] <= [child_hook = sym child_hook]);
// https://devblogs.microsoft.com/oldnewthing/20220811-00/?p=106963
asmfunction!(__relibc_internal_sigentry: ["
// Clear any active reservation.
clrex
// The old pc and x0 are saved in the sigcontrol struct.
mrs x0, tpidr_el0 // ABI ptr
ldr x0, [x0] // TCB ptr
// Save x1-x6 and sp
stp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
stp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
stp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
stp x7, x8, [x0, #{tcb_sa_off} + {sa_tmp_x7_x8}]
mov x1, sp
str x1, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
ldr x6, [x0, #{tcb_sa_off} + {sa_pctl}]
1:
// Load x1 with the thread's bits
add x5, x0, #{tcb_sc_off} + {sc_word}
ldaxr x1, [x5]
// First check if there are standard thread signals,
and x4, x1, x1, lsr #32 // x4 := x1 & (x1 >> 32)
cbnz x4, 3f // jump if x4 != 0
clrex
// and if not, load process pending bitset.
add x5, x6, #{pctl_pending}
ldaxr x2, [x5]
// Check if there are standard proc signals:
lsr x3, x1, #32 // mask
and w3, w2, w3 // pending unblocked proc
cbz w3, 4f // skip 'fetch_andn' step if zero
// If there was one, find which one, and try clearing the bit (last value in x3, addr in x6)
// this picks the MSB rather than the LSB, unlike x86. POSIX does not require any specific
// ordering though.
clz w3, w3
mov w4, #31
sub w3, w4, w3
// x3 now contains the sig_idx
mov x4, #1
lsl x4, x4, x3 // bit to remove
sub x4, x2, x4 // bit was certainly set, so sub is allowed
// x4 is now the new mask to be set
add x5, x6, #{pctl_pending}
add x2, x5, #{pctl_sender_infos}
add x2, x2, w3, uxtb 3
ldar x2, [x2]
// Try clearing the bit, retrying on failure.
stxr w1, x4, [x5] // try setting pending set to x4, set w1 := 0 on success
cbnz w1, 1b // retry everything if this fails
mov x1, x3
b 2f
4:
// Check for realtime signals, thread/proc.
clrex
// Load the pending set again. TODO: optimize this?
// Process pending - realtime
add x1, x6, #{pctl_pending}
ldaxr x2, [x1]
lsr x2, x2, #32
// Thread pending - realtime and allowset
add x5, x0, #{tcb_sc_off} + {sc_word} + 8
ldar x1, [x5]
orr x2, x1, x2 // combine proc and thread pending
and x2, x2, x2, lsr #32 // AND pending with allowset
cbz x2, 7f // spurious signal if realtime is clear
rbit x2, x2
clz x2, x2
// x2 now contains sig_idx - 32
// If realtime signal was directed at thread, handle it as an idempotent signal.
lsr x3, x1, x2 // x3 := x1 >> x2; x1 is thread pending
tbnz x3, #0, 5f // jump if bit is nonzero
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base | (flags << 8))
// x8 x0 x1 x2 x3 x4
mov x5, x0 // save TCB pointer
mov x6, x2
ldr x8, ={SYS_CALL}
adrp x0, {proc_fd}
ldr x0, [x0, #:lo12:{proc_fd}]
add x1, x5, #{tcb_sa_off} + {sa_tmp_rt_inf}
str x6, [x1]
mov x2, #{RTINF_SIZE}
adrp x4, {proc_call}
add x4, x4, :lo12:{proc_call}
mov x3, #1
svc 0
mov x3, x0
mov x0, x5 // restore TCB pointer
mov x2, x6 // restore signal number - 32
add x1, x2, #32 // signal number
cbnz x3, 1b
b 2f
5:
// A realtime signal was sent to this thread, try clearing its bit.
// x3 contains last rt signal word, x2 contains rt_idx
clrex
// Calculate the absolute sig_idx
add x1, x3, 32
// Load si_pid and si_uid
add x2, x0, #{tcb_sc_off} + {sc_sender_infos}
add x2, x2, w1, uxtb #3
ldar x2, [x2]
add x3, x0, #{tcb_sc_off} + {sc_word} + 8
ldxr x2, [x3]
// Calculate new mask
mov x4, #1
lsl x4, x4, x2
sub x2, x2, x4 // remove bit
stxr w5, x2, [x3]
cbnz w5, 1b
str x2, [x0, #{tcb_sa_off} + {sa_tmp_id_inf}]
b 2f
3:
// A standard signal was sent to this thread, try clearing its bit.
clz w1, w1
mov x2, #31
sub x1, x2, x1
// Load si_pid and si_uid
add x2, x0, #{tcb_sc_off} + {sc_sender_infos}
add x2, x2, w1, uxtb #3
ldar x2, [x2]
// Clear bit from mask
mov x3, #1
lsl x3, x3, x1
sub x4, x4, x3
// Try updating the mask
stxr w3, x1, [x5]
cbnz w3, 1b
str x2, [x0, #{tcb_sa_off} + {sa_tmp_id_inf}]
2:
ldr x3, [x0, #{tcb_sa_off} + {sa_pctl}]
add x3, x3, {pctl_actions}
add x2, x3, w1, uxtb #4 // actions_base + sig_idx * sizeof Action
// TODO: NOT ATOMIC (tearing allowed between regs)!
ldxp x2, x3, [x2]
clrex
// Calculate new sp wrt redzone and alignment
mov x4, sp
sub x4, x4, {REDZONE_SIZE}
and x4, x4, -{STACK_ALIGN}
mov sp, x4
// skip sigaltstack step if SA_ONSTACK is clear
// tbz x2, #{SA_ONSTACK_BIT}, 2f
ldr x2, [x0, #{tcb_sc_off} + {sc_saved_pc}]
ldr x3, [x0, #{tcb_sc_off} + {sc_saved_x0}]
stp x2, x3, [sp, #-16]!
ldr x2, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
mrs x3, nzcv
stp x2, x3, [sp, #-16]!
ldp x2, x3, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
stp x2, x3, [sp, #-16]!
ldp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
stp x4, x3, [sp, #-16]!
ldp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
stp x6, x5, [sp, #-16]!
ldp x7, x8, [x0, #{tcb_sa_off} + {sa_tmp_x7_x8}]
stp x8, x7, [sp, #-16]!
stp x10, x9, [sp, #-16]!
stp x12, x11, [sp, #-16]!
stp x14, x13, [sp, #-16]!
stp x16, x15, [sp, #-16]!
stp x18, x17, [sp, #-16]!
stp x20, x19, [sp, #-16]!
stp x22, x21, [sp, #-16]!
stp x24, x23, [sp, #-16]!
stp x26, x25, [sp, #-16]!
stp x28, x27, [sp, #-16]!
stp x30, x29, [sp, #-16]!
str w1, [sp, #-4]
sub sp, sp, #64
mov x0, sp
bl {inner}
add sp, sp, #64
ldp x30, x29, [sp], #16
ldp x28, x27, [sp], #16
ldp x26, x25, [sp], #16
ldp x24, x23, [sp], #16
ldp x22, x21, [sp], #16
ldp x20, x19, [sp], #16
ldp x18, x17, [sp], #16
ldp x16, x15, [sp], #16
ldp x14, x13, [sp], #16
ldp x12, x11, [sp], #16
ldp x10, x9, [sp], #16
ldp x8, x7, [sp], #16
ldp x6, x5, [sp], #16
ldp x4, x3, [sp], #16
ldp x2, x1, [sp], #16
ldr x0, [sp, #8]
msr nzcv, x0
8:
// x18 is reserved by ABI as 'platform register', so clobbering it should be safe.
mov x18, sp
ldr x0, [x18]
mov sp, x0
ldp x18, x0, [x18, #16]
br x18
7:
// Spurious signal, i.e. all bitsets were 0 at the time they were checked
clrex
ldr x1, [x0, #{tcb_sc_off} + {sc_flags}]
and x1, x1, ~1
str x1, [x0, #{tcb_sc_off} + {sc_flags}]
ldp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
ldp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
ldp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
ldr x18, [x0, #{tcb_sc_off} + {sc_saved_pc}]
ldr x0, [x0, #{tcb_sc_off} + {sc_saved_x0}]
br x18
"] <= [
pctl_pending = const (offset_of!(SigProcControl, pending)),
pctl_actions = const (offset_of!(SigProcControl, actions)),
pctl_sender_infos = const (offset_of!(SigProcControl, sender_infos)),
tcb_sc_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control)),
tcb_sa_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch)),
sa_tmp_x1_x2 = const offset_of!(SigArea, tmp_x1_x2),
sa_tmp_x3_x4 = const offset_of!(SigArea, tmp_x3_x4),
sa_tmp_x5_x6 = const offset_of!(SigArea, tmp_x5_x6),
sa_tmp_x7_x8 = const offset_of!(SigArea, tmp_x7_x8),
sa_tmp_sp = const offset_of!(SigArea, tmp_sp),
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
sa_pctl = const offset_of!(SigArea, pctl),
sc_saved_pc = const offset_of!(Sigcontrol, saved_ip),
sc_saved_x0 = const offset_of!(Sigcontrol, saved_archdep_reg),
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
sc_word = const offset_of!(Sigcontrol, word),
sc_flags = const offset_of!(Sigcontrol, control_flags),
proc_fd = sym PROC_FD,
inner = sym inner_c,
proc_call = sym PROC_CALL,
SA_ONSTACK_BIT = const 58, // (1 << 58) >> 32 = 0x0400_0000
SYS_CALL = const syscall::SYS_CALL,
STACK_ALIGN = const 16,
REDZONE_SIZE = const 128,
RTINF_SIZE = const size_of::<RtSigInfo>(),
]);
asmfunction!(__relibc_internal_rlct_clone_ret: ["
# Load registers
ldp x8, x0, [sp], #16
ldp x1, x2, [sp], #16
ldp x3, x4, [sp], #16
# Call entry point
blr x8
ret
"] <= []);
pub fn current_sp() -> usize {
let sp: usize;
unsafe {
core::arch::asm!("mov {}, sp", out(reg) sp);
}
sp
}
pub unsafe fn manually_enter_trampoline() {
let ctl = unsafe { &Tcb::current().unwrap().os_specific.control };
ctl.saved_archdep_reg.set(0);
let ip_location = &ctl.saved_ip as *const _ as usize;
unsafe {
core::arch::asm!("
bl 2f
b 3f
2:
str lr, [x0]
b __relibc_internal_sigentry
3:
",
inout("x0") ip_location => _, out("lr") _);
}
}
pub unsafe fn arch_pre(stack: &mut SigStack, os: &mut SigArea) -> PosixStackt {
PosixStackt {
sp: core::ptr::null_mut(), // TODO
size: 0, // TODO
flags: 0, // TODO
}
}
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_pc = core::mem::replace(
&mut stack.regs.pc,
__relibc_internal_sigentry as *const () as usize,
);
control.saved_ip.set(orig_pc);
control.saved_archdep_reg.set(stack.regs.x0);
}
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
-418
View File
@@ -1,418 +0,0 @@
use core::{cell::SyncUnsafeCell, mem::offset_of, ptr::NonNull, sync::atomic::Ordering};
use syscall::*;
use crate::{
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
signal::{PROC_CONTROL_STRUCT, PosixStackt, RtSigarea, SigStack, inner_fastcall},
};
use redox_protocols::protocol::{ProcCall, RtSigInfo};
use super::ForkScratchpad;
// Setup a stack starting from the very end of the address space, and then growing downwards.
pub const STACK_TOP: usize = 1 << 31;
pub const STACK_SIZE: usize = 1024 * 1024;
#[derive(Debug, Default)]
#[repr(C)]
pub struct SigArea {
pub altstack_top: usize,
pub altstack_bottom: usize,
pub tmp_eip: usize,
pub tmp_esp: usize,
pub tmp_eax: usize,
pub tmp_ebx: usize,
pub tmp_ecx: usize,
pub tmp_edx: usize,
pub tmp_edi: usize,
pub tmp_esi: usize,
pub tmp_rt_inf: RtSigInfo,
pub tmp_signo: usize,
pub tmp_id_inf: u64,
pub tmp_mm0: u64,
pub disable_signals_depth: u64,
pub last_sig_was_restart: bool,
pub last_sigstack: Option<NonNull<SigStack>>,
}
#[derive(Debug, Default)]
#[repr(C, align(16))]
pub struct ArchIntRegs {
pub fxsave: [u16; 29],
// ensure fxsave region is 16 byte aligned
pub _pad: [usize; 2], // fxsave "available" +0
pub ebp: usize, // fxsave "available" +8
pub esi: usize, // avail +12
pub edi: usize, // avail +16
pub ebx: usize, // avail +20
pub eax: usize, // avail +24
pub ecx: usize, // avail +28
pub edx: usize, // avail +32
pub eflags: usize, // avail +36
pub eip: usize, // avail +40
pub esp: usize, // avail +44
}
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
/// is already initialized as if it was a thread.
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
let mut env = syscall::EnvRegisters::default();
let file = open_via_dup.dup_into_upper(b"regs/env")?;
env.fsbase = 0;
env.gsbase = 0;
file.write(&mut env)?;
crate::TLS_ACTIVATED.store(false, core::sync::atomic::Ordering::Relaxed);
Ok(())
}
unsafe extern "fastcall" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
Error::mux(fork_inner(initial_rsp, args))
}
// TODO: duplicate code with x86_64
unsafe extern "cdecl" fn child_hook(scratchpad: ForkScratchpad) {
let _ = crate::sys::close(scratchpad.cur_filetable_fd);
unsafe {
crate::child_hook_common(crate::ChildHookCommonArgs {
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
None
} else {
Some(FdGuard::new(scratchpad.new_proc_fd))
},
new_filetable_fd: FdGuard::new(scratchpad.new_filetable_fd)
.to_upper()
.unwrap(),
})
};
}
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
mov ecx, [esp+4]
push ebp
mov ebp, esp
// Push preserved registers
push ebx
push edi
push esi
push ebp
sub esp, 32
//TODO stmxcsr [esp+16]
fnstcw [esp+24]
mov edx, esp
call {fork_impl}
jmp 2f
"] <= [fork_impl = sym fork_impl]);
asmfunction!(__relibc_internal_fork_ret: ["
// Arguments already on the stack
call {child_hook}
//TODO ldmxcsr [esp+16]
fldcw [esp+24]
xor eax, eax
.p2align 4
2:
add esp, 32
// Pop preserved registers
pop ebp
pop esi
pop edi
pop ebx
pop ebp
ret
"] <= [child_hook = sym child_hook]);
asmfunction!(__relibc_internal_sigentry: ["
// Save some registers
mov gs:[{tcb_sa_off} + {sa_tmp_esp}], esp
mov gs:[{tcb_sa_off} + {sa_tmp_eax}], eax
mov gs:[{tcb_sa_off} + {sa_tmp_edx}], edx
mov gs:[{tcb_sa_off} + {sa_tmp_ecx}], ecx
mov gs:[{tcb_sa_off} + {sa_tmp_ebx}], ebx
mov gs:[{tcb_sa_off} + {sa_tmp_edi}], edi
mov gs:[{tcb_sa_off} + {sa_tmp_esi}], esi
1:
// Read standard signal word - first for this thread
mov edx, gs:[{tcb_sc_off} + {sc_word} + 4]
mov eax, gs:[{tcb_sc_off} + {sc_word}]
and eax, edx
bsf eax, eax
jnz 9f
// Read standard signal word - for the process
lea ecx, [{pctl}]
mov eax, [ecx + {pctl_pending}]
and eax, edx
bsf eax, eax
jz 3f
// Read si_pid and si_uid, atomically.
movq gs:[{tcb_sa_off} + {sa_tmp_mm0}], mm0
movq mm0, [ecx + {pctl_sender_infos} + eax * 8]
movq gs:[{tcb_sa_off} + {sa_tmp_id_inf}], mm0
movq mm0, gs:[{tcb_sa_off} + {sa_tmp_mm0}]
// Try clearing the pending bit, otherwise retry if another thread did that first
lock btr [ecx + {pctl_pending}], eax
jnc 1b
jmp 2f
3:
// Read realtime thread and process signal word together
mov edx, [ecx + {pctl_pending} + 4]
mov eax, gs:[{tcb_sc_off} + {sc_word} + 8]
or eax, edx
and eax, gs:[{tcb_sc_off} + {sc_word} + 12]
bsf eax, eax
jz 7f // spurious signal
// If thread rather than process was specifically targeted, send the signal to it first.
bt edx, eax
jnc 8f
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base)
// eax ebx ecx edx esi edi
mov ebx, [{proc_fd}]
mov ecx, gs:[0]
add ecx, {tcb_sa_off} + {sa_tmp_rt_inf}
mov [ecx], eax
mov gs:[{tcb_sa_off} + {sa_tmp_signo}], eax
mov edx, {RTINF_SIZE}
mov esi, 1
lea edi, [{proc_call}]
mov eax, {SYS_CALL}
int 0x80
test eax, eax
jnz 1b
mov eax, gs:[{tcb_sa_off} + {sa_tmp_signo}]
add eax, 32
jmp 2f
8:
add eax, 32
9:
// Read si_pid and si_uid, atomically.
movq gs:[{tcb_sa_off} + {sa_tmp_mm0}], mm0
movq mm0, gs:[{tcb_sc_off} + {sc_sender_infos} + eax * 8]
movq gs:[{tcb_sa_off} + {sa_tmp_id_inf}], mm0
movq mm0, gs:[{tcb_sa_off} + {sa_tmp_mm0}]
mov edx, eax
shr edx, 5
mov ecx, eax
and ecx, 31
lock btr gs:[{tcb_sc_off} + {sc_word} + edx * 8], ecx
add eax, 64
2:
and esp, -{STACK_ALIGN}
mov edx, eax
add edx, edx
bt dword ptr [{pctl} + {pctl_actions} + edx * 8 + 4], 28
jnc 4f
mov edx, gs:[{tcb_sa_off} + {sa_altstack_top}]
cmp esp, edx
ja 3f
cmp esp, gs:[{tcb_sa_off} + {sa_altstack_bottom}]
jnbe 4f
3:
mov esp, edx
4:
// Now that we have a stack, we can finally start populating the signal stack.
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_esp}]
push dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}]
push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}]
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edx}]
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_ecx}]
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_eax}]
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_ebx}]
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edi}]
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_esi}]
push ebp
sub esp, 2 * 4 + 29 * 16
fxsave [esp]
mov [esp - 4], eax
sub esp, 48
mov ecx, esp
call {inner}
fxrstor [esp + 48]
add esp, 48 + 29 * 16 + 2 * 4
pop ebp
pop esi
pop edi
pop ebx
pop eax
pop ecx
pop edx
popfd
pop dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
.globl __relibc_internal_sigentry_crit_first
__relibc_internal_sigentry_crit_first:
pop esp
.globl __relibc_internal_sigentry_crit_second
__relibc_internal_sigentry_crit_second:
jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
7:
mov eax, gs:[0]
lea esp, [eax + {tcb_sc_off} + {sc_saved_eflags}]
popfd
mov esp, gs:[{tcb_sa_off} + {sa_tmp_esp}]
mov eax, gs:[{tcb_sc_off} + {sc_saved_eip}]
mov gs:[{tcb_sa_off} + {sa_tmp_eip}], eax
mov eax, gs:[{tcb_sa_off} + {sa_tmp_eax}]
mov ebx, gs:[{tcb_sa_off} + {sa_tmp_ebx}]
mov ecx, gs:[{tcb_sa_off} + {sa_tmp_ecx}]
mov edx, gs:[{tcb_sa_off} + {sa_tmp_edx}]
mov edi, gs:[{tcb_sa_off} + {sa_tmp_edi}]
mov esi, gs:[{tcb_sa_off} + {sa_tmp_esi}]
and dword ptr gs:[{tcb_sc_off} + {sc_control}], ~1
.globl __relibc_internal_sigentry_crit_third
__relibc_internal_sigentry_crit_third:
jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp_eip}]
"] <= [
inner = sym inner_fastcall,
sa_tmp_eip = const offset_of!(SigArea, tmp_eip),
sa_tmp_esp = const offset_of!(SigArea, tmp_esp),
sa_tmp_eax = const offset_of!(SigArea, tmp_eax),
sa_tmp_ebx = const offset_of!(SigArea, tmp_ebx),
sa_tmp_ecx = const offset_of!(SigArea, tmp_ecx),
sa_tmp_edx = const offset_of!(SigArea, tmp_edx),
sa_tmp_edi = const offset_of!(SigArea, tmp_edi),
sa_tmp_esi = const offset_of!(SigArea, tmp_esi),
sa_tmp_mm0 = const offset_of!(SigArea, tmp_mm0),
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
sa_tmp_signo = const offset_of!(SigArea, tmp_signo),
sa_altstack_top = const offset_of!(SigArea, altstack_top),
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
sc_control = const offset_of!(Sigcontrol, control_flags),
sc_saved_eflags = const offset_of!(Sigcontrol, saved_archdep_reg),
sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
sc_word = const offset_of!(Sigcontrol, word),
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
pctl_actions = const offset_of!(SigProcControl, actions),
pctl_sender_infos = const offset_of!(SigProcControl, sender_infos),
pctl_pending = const offset_of!(SigProcControl, pending),
pctl = sym PROC_CONTROL_STRUCT,
proc_fd = sym PROC_FD,
proc_call = sym PROC_CALL,
STACK_ALIGN = const 16,
SYS_CALL = const syscall::SYS_CALL,
RTINF_SIZE = const size_of::<RtSigInfo>(),
]);
asmfunction!(__relibc_internal_rlct_clone_ret -> usize: ["
# Load registers
pop eax
sub esp, 8
mov DWORD PTR [esp], 0x00001F80
# TODO: ldmxcsr [esp]
mov WORD PTR [esp], 0x037F
fldcw [esp]
add esp, 8
# Call entry point
call eax
ret
"] <= []);
unsafe extern "C" {
fn __relibc_internal_sigentry_crit_first();
fn __relibc_internal_sigentry_crit_second();
fn __relibc_internal_sigentry_crit_third();
}
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt {
if stack.regs.eip == __relibc_internal_sigentry_crit_first as *const () as usize {
let stack_ptr = stack.regs.esp as *const usize;
stack.regs.esp = unsafe { stack_ptr.read() };
stack.regs.eip = unsafe { stack_ptr.sub(1).read() };
} else if stack.regs.eip == __relibc_internal_sigentry_crit_second as *const () as usize
|| stack.regs.eip == __relibc_internal_sigentry_crit_third as *const () as usize
{
stack.regs.eip = area.tmp_eip;
}
PosixStackt {
sp: stack.regs.esp as *mut (),
size: 0, // TODO
flags: 0, // TODO
}
}
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_eip = core::mem::replace(
&mut stack.regs.eip,
__relibc_internal_sigentry as *const () as usize,
);
control.saved_ip.set(orig_eip);
control.saved_archdep_reg.set(stack.regs.eflags);
}
#[unsafe(no_mangle)]
pub unsafe fn manually_enter_trampoline() {
let c = unsafe { &crate::Tcb::current().unwrap().os_specific.control };
c.control_flags.store(
c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(),
Ordering::Release,
);
c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86?
unsafe {
core::arch::asm!("
call 2f
jmp 3f
2:
pop dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}]
jmp __relibc_internal_sigentry
3:
",
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
);
}
}
/// Get current stack pointer, weak granularity guarantees.
pub fn current_sp() -> usize {
let sp: usize;
unsafe {
core::arch::asm!("mov {}, esp", out(reg) sp);
}
sp
}
pub static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
static PROC_CALL: u64 = ProcCall::Sigdeq as u64;
-28
View File
@@ -1,28 +0,0 @@
#[cfg(target_arch = "aarch64")]
pub use self::aarch64::*;
#[cfg(target_arch = "aarch64")]
pub mod aarch64;
#[cfg(target_arch = "x86")]
pub use self::i686::*;
#[cfg(target_arch = "x86")]
pub mod i686;
#[cfg(target_arch = "x86_64")]
pub use self::x86_64::*;
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
#[cfg(target_arch = "riscv64")]
pub use self::riscv64::*;
#[cfg(target_arch = "riscv64")]
pub mod riscv64;
#[derive(Debug)]
#[repr(C)]
pub struct ForkScratchpad {
pub cur_filetable_fd: usize,
pub new_filetable_fd: usize,
pub new_proc_fd: usize,
pub new_thr_fd: usize,
}
-661
View File
@@ -1,661 +0,0 @@
use core::cell::SyncUnsafeCell;
use crate::{
Tcb,
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
signal::{PosixStackt, RtSigarea, SigStack, get_sigaltstack, inner_c},
};
use core::{mem::offset_of, ptr::NonNull, sync::atomic::Ordering};
use redox_protocols::protocol::{ProcCall, RtSigInfo};
use syscall::{data::*, error::*};
use super::ForkScratchpad;
// Setup a stack starting from the very end of the address space, and then growing downwards.
pub const STACK_TOP: usize = 1 << 38;
pub const STACK_SIZE: usize = 1024 * 1024;
#[derive(Debug, Default)]
#[repr(C)]
pub struct SigArea {
pub tmp_sp: u64,
pub tmp_t1: u64,
pub tmp_t2: u64,
pub tmp_t3: u64,
pub tmp_t4: u64,
pub tmp_a0: u64,
pub tmp_a1: u64,
pub tmp_a2: u64,
pub tmp_a3: u64,
pub tmp_a4: u64,
pub tmp_a7: u64,
pub pctl: usize, // TODO: remove
pub tmp_ip: u64,
pub tmp_rt_inf: RtSigInfo,
pub tmp_id_inf: u64,
pub altstack_top: usize,
pub altstack_bottom: usize,
pub disable_signals_depth: u64,
pub last_sig_was_restart: bool,
pub last_sigstack: Option<NonNull<SigStack>>,
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct ArchIntRegs {
pub int_regs: [u64; 31],
pub pc: u64,
pub fp_regs: [u64; 32],
pub fcsr: u32,
_pad: u32,
}
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
/// is already initialized as if it was a thread.
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
let mut env = syscall::EnvRegisters::default();
let file = open_via_dup.dup_into_upper(b"regs/env")?;
env.tp = 0;
file.write(&mut env)?;
crate::TLS_ACTIVATED.store(false, core::sync::atomic::Ordering::Relaxed);
Ok(())
}
unsafe extern "C" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
Error::mux(fork_inner(initial_rsp, args))
}
unsafe extern "C" fn child_hook(scratchpad: &ForkScratchpad) {
let _ = crate::sys::close(scratchpad.cur_filetable_fd);
unsafe {
crate::child_hook_common(crate::ChildHookCommonArgs {
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
None
} else {
Some(FdGuard::new(scratchpad.new_proc_fd))
},
new_filetable_fd: FdGuard::new(scratchpad.new_filetable_fd)
.to_upper()
.unwrap(),
})
};
}
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
.attribute arch, \"rv64gc\" # rust bug 80608
addi sp, sp, -200
sd s0, 0(sp)
sd s1, 8(sp)
sd s2, 16(sp)
sd s3, 24(sp)
sd s4, 32(sp)
sd s5, 40(sp)
sd s6, 48(sp)
sd s7, 56(sp)
sd s8, 64(sp)
sd s9, 72(sp)
sd s10, 80(sp)
sd s11, 88(sp)
sd ra, 96(sp)
fsd fs0, 104(sp)
fsd fs1, 112(sp)
fsd fs2, 120(sp)
fsd fs3, 128(sp)
fsd fs4, 136(sp)
fsd fs5, 144(sp)
fsd fs6, 152(sp)
fsd fs7, 160(sp)
fsd fs8, 168(sp)
fsd fs9, 176(sp)
fsd fs10, 184(sp)
fsd fs11, 192(sp)
// a0 is forwarded from this function
mv a1, sp
jal {fork_impl}
ld s0, 0(sp)
ld s1, 8(sp)
ld s2, 16(sp)
ld s3, 24(sp)
ld s4, 32(sp)
ld s5, 40(sp)
ld s6, 48(sp)
ld s7, 56(sp)
ld s8, 64(sp)
ld s9, 72(sp)
ld s10, 80(sp)
ld s11, 88(sp)
ld ra, 96(sp)
fld fs0, 104(sp)
fld fs1, 112(sp)
fld fs2, 120(sp)
fld fs3, 128(sp)
fld fs4, 136(sp)
fld fs5, 144(sp)
fld fs6, 152(sp)
fld fs7, 160(sp)
fld fs8, 168(sp)
fld fs9, 176(sp)
fld fs10, 184(sp)
fld fs11, 192(sp)
addi sp, sp, 200
ret
"] <= [fork_impl = sym fork_impl]);
asmfunction!(__relibc_internal_fork_ret: ["
.attribute arch, \"rv64gc\" # rust bug 80608
# scratchpad is in a1, move to a0 for child_hook
mv a0, a1
jal {child_hook}
mv a0, zero
ld s0, 0(sp)
ld s1, 8(sp)
ld s2, 16(sp)
ld s3, 24(sp)
ld s4, 32(sp)
ld s5, 40(sp)
ld s6, 48(sp)
ld s7, 56(sp)
ld s8, 64(sp)
ld s9, 72(sp)
ld s10, 80(sp)
ld s11, 88(sp)
ld ra, 96(sp)
fld fs0, 104(sp)
fld fs1, 112(sp)
fld fs2, 120(sp)
fld fs3, 128(sp)
fld fs4, 136(sp)
fld fs5, 144(sp)
fld fs6, 152(sp)
fld fs7, 160(sp)
fld fs8, 168(sp)
fld fs9, 176(sp)
fld fs10, 184(sp)
fld fs11, 192(sp)
addi sp, sp, 200
ret
"] <= [child_hook = sym child_hook]);
asmfunction!(__relibc_internal_sigentry: ["
.attribute arch, \"rv64gc\" # rust bug 80608
// Save some registers
ld t0, -8(tp) // Tcb
sd sp, ({tcb_sa_off} + {sa_tmp_sp})(t0)
sd t1, ({tcb_sa_off} + {sa_tmp_t1})(t0)
sd t2, ({tcb_sa_off} + {sa_tmp_t2})(t0)
sd t3, ({tcb_sa_off} + {sa_tmp_t3})(t0)
sd t4, ({tcb_sa_off} + {sa_tmp_t4})(t0)
ld t4, ({tcb_sa_off} + {sa_off_pctl})(t0)
// First, select signal, always pick first available bit
99:
// Read first signal word
ld t1, ({tcb_sc_off} + {sc_word})(t0)
srli t2, t1, 32 // bitset to low word
and t1, t1, t2 // masked bitset in low word
beqz t1, 3f
// Found in first thread signal word
mv t3, x0
2: andi t2, t1, 1
bnez t2, 10f
addi t3, t3, 1
srli t1, t1, 1
j 2b
// If no unblocked thread signal was found, check for process.
// This is competitive; we need to atomically check if *we* cleared the process-wide pending
// bit, otherwise restart.
3: lw t1, {pctl_off_pending}(t4)
and t1, t1, t2
beqz t1, 3f
// Found in first process signal word
li t3, -1
2: andi t2, t1, 1
addi t3, t3, 1
srli t1, t1, 1
beqz t2, 2b
slli t1, t3, 3 // * 8 == size_of SenderInfo
add t1, t1, t4
ld t1, {pctl_off_sender_infos}(t1)
sd t1, ({tcb_sa_off} + {sa_tmp_id_inf})(t0)
li t1, 1
sll t1, t1, t3
not t1, t1
addi t2, t4, {pctl_off_pending}
amoand.w.aq t2, t1, (t2)
and t1, t1, t2
bne t1, t2, 9f
3:
// Read second signal word - both process and thread simultaneously.
// This must be done since POSIX requires low realtime signals to be picked first.
ld t1, ({tcb_sc_off} + {sc_word} + 8)(t0)
lw t2, ({pctl_off_pending} + 4)(t4)
or t4, t1, t2
srli t2, t1, 32
and t4, t2, t4
beqz t4, 7f
li t3, -1
2: andi t2, t4, 1
addi t3, t3, 1
srli t4, t4, 1
beqz t2, 2b
li t2, 1
sll t2, t2, t3
and t1, t1, t2
addi t3, t3, 32
bnez t1, 10f // thread signal
// otherwise, try (competitively) dequeueing realtime signal
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base)
// a7 a0 a1 a2 a3 a4
// TODO: This SYS_CALL invocation has not yet been tested due to toolchain issues.
sd a0, ({tcb_sa_off} + {sa_tmp_a0})(t0)
sd a1, ({tcb_sa_off} + {sa_tmp_a1})(t0)
sd a2, ({tcb_sa_off} + {sa_tmp_a2})(t0)
sd a3, ({tcb_sa_off} + {sa_tmp_a3})(t0)
sd a4, ({tcb_sa_off} + {sa_tmp_a4})(t0)
sd a7, ({tcb_sa_off} + {sa_tmp_a7})(t0)
li a7, {SYS_CALL}
addi a2, t3, -32
add a1, t0, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
sd a2, (a1)
li a2, {RTINF_SIZE}
li a3, 1
1337:
auipc a4, %pcrel_hi({proc_fd})
addi a4, a4, %pcrel_lo(1337b)
ecall
ld a3, ({tcb_sa_off} + {sa_tmp_a3})(t0)
ld a4, ({tcb_sa_off} + {sa_tmp_a4})(t0)
bnez a0, 99b // assumes error can only be EAGAIN
j 9f
10: // thread signal. t3 holds signal number
srli t1, t3, 5
bnez t1, 2f // FIXME senderinfo?
sll t2, t3, 3 // * 8 == size_of SenderInfo
add t2, t2, t0
ld t2, ({tcb_sc_off} + {sc_sender_infos})(t2)
sd t2, ({tcb_sa_off} + {sa_tmp_id_inf})(t0)
2: andi t4, t3, 31
li t2, 1
sll t2, t2, t4
not t2, t2
sll t1, t1, 3
add t1, t1, t0
addi t1, t1, {tcb_sc_off} + {sc_word}
amoand.w.aq x0, t2, (t1)
addi t3, t3, 64 // indicate signal was targeted at thread
9: // process signal t3 holds signal number
// By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or
// not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then
// skip the sigaltstack logic.
ld t4, ({tcb_sa_off} + {sa_off_pctl})(t0)
andi t1, t3, 63
slli t1, t1, 4 // * 16 == size_of RawAction
add t1, t1, t4
ld t1, {pctl_off_actions}(t1)
slli t1, t1, 63-58 // SA_ONSTACK in sign bit
bgez t1, 3f
// If current RSP is above altstack region, switch to altstack
ld t1, ({tcb_sa_off} + {sa_altstack_top})(t0)
bgtu sp, t1, 2f
ld t2, ({tcb_sa_off} + {sa_altstack_bottom})(t0)
bgtu sp, t3, 3f
2: mv sp, t1
3:
// form mcontext on stack
addi sp, sp, -33 * 8
fsd f0, (0 * 8)(sp)
fsd f1, (1 * 8)(sp)
fsd f2, (2 * 8)(sp)
fsd f3, (3 * 8)(sp)
fsd f4, (4 * 8)(sp)
fsd f5, (5 * 8)(sp)
fsd f6, (6 * 8)(sp)
fsd f7, (7 * 8)(sp)
fsd f8, (8 * 8)(sp)
fsd f9, (9 * 8)(sp)
fsd f10, (10 * 8)(sp)
fsd f11, (11 * 8)(sp)
fsd f12, (12 * 8)(sp)
fsd f13, (13 * 8)(sp)
fsd f14, (14 * 8)(sp)
fsd f15, (15 * 8)(sp)
fsd f16, (16 * 8)(sp)
fsd f17, (17 * 8)(sp)
fsd f18, (18 * 8)(sp)
fsd f19, (19 * 8)(sp)
fsd f20, (20 * 8)(sp)
fsd f21, (21 * 8)(sp)
fsd f22, (22 * 8)(sp)
fsd f23, (23 * 8)(sp)
fsd f24, (24 * 8)(sp)
fsd f25, (25 * 8)(sp)
fsd f26, (26 * 8)(sp)
fsd f27, (27 * 8)(sp)
fsd f28, (28 * 8)(sp)
fsd f29, (29 * 8)(sp)
fsd f30, (30 * 8)(sp)
fsd f31, (31 * 8)(sp)
csrr t1, fcsr
sw t1, (32 * 8)(sp)
addi sp, sp, -32 * 8
sd x1, 0(sp)
ld t1, ({tcb_sa_off} + {sa_tmp_sp})(t0)
sd t1, (1 * 8)(sp) // x2 is sp
sd x3, (2 * 8)(sp)
sd x4, (3 * 8)(sp)
ld t1, ({tcb_sc_off} + {sc_saved_t0})(t0)
sd t1, (4 * 8)(sp) // x5 is t0
ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t0)
sd t1, (5 * 8)(sp) // x6 is t1
ld t1, ({tcb_sa_off} + {sa_tmp_t2})(t0)
sd t1, (6 * 8)(sp) // x7 is t2
sd x8, (7 * 8)(sp)
sd x9, (8 * 8)(sp)
sd x10, (9 * 8)(sp)
sd x11, (10 * 8)(sp)
sd x12, (11 * 8)(sp)
sd x13, (12 * 8)(sp)
sd x14, (13 * 8)(sp)
sd x15, (14 * 8)(sp)
sd x16, (15 * 8)(sp)
sd x17, (16 * 8)(sp)
sd x18, (17 * 8)(sp)
sd x19, (18 * 8)(sp)
sd x20, (19 * 8)(sp)
sd x21, (20 * 8)(sp)
sd x22, (21 * 8)(sp)
sd x23, (22 * 8)(sp)
sd x24, (23 * 8)(sp)
sd x25, (24 * 8)(sp)
sd x26, (25 * 8)(sp)
sd x27, (26 * 8)(sp)
ld t1, ({tcb_sa_off} + {sa_tmp_t3})(t0)
sd t1, (27 * 8)(sp) // t3 is x28
ld t1, ({tcb_sa_off} + {sa_tmp_t4})(t0)
sd t1, (28 * 8)(sp) // t4 is x29
sd x30, (29 * 8)(sp)
sd x31, (30 * 8)(sp)
ld t1, ({tcb_sc_off} + {sc_saved_ip})(t0)
sd t1, (31 * 8)(sp)
// form ucontext
addi sp, sp, -64
sw t3, 60(sp)
mv t0, sp
jal {inner}
addi sp, sp, 64
addi t0, sp, 32 * 8
fld f0, (0 * 8)(t0)
fld f1, (1 * 8)(t0)
fld f2, (2 * 8)(t0)
fld f3, (3 * 8)(t0)
fld f4, (4 * 8)(t0)
fld f5, (5 * 8)(t0)
fld f6, (6 * 8)(t0)
fld f7, (7 * 8)(t0)
fld f8, (8 * 8)(t0)
fld f9, (9 * 8)(t0)
fld f10, (10 * 8)(t0)
fld f11, (11 * 8)(t0)
fld f12, (12 * 8)(t0)
fld f13, (13 * 8)(t0)
fld f14, (14 * 8)(t0)
fld f15, (15 * 8)(t0)
fld f16, (16 * 8)(t0)
fld f17, (17 * 8)(t0)
fld f18, (18 * 8)(t0)
fld f19, (19 * 8)(t0)
fld f20, (20 * 8)(t0)
fld f21, (21 * 8)(t0)
fld f22, (22 * 8)(t0)
fld f23, (23 * 8)(t0)
fld f24, (24 * 8)(t0)
fld f25, (25 * 8)(t0)
fld f26, (26 * 8)(t0)
fld f27, (27 * 8)(t0)
fld f28, (28 * 8)(t0)
fld f29, (29 * 8)(t0)
fld f30, (30 * 8)(t0)
fld f31, (31 * 8)(t0)
lw t1, (32 * 8)(t0)
csrw fcsr, t1
ld x1, 0(sp)
// skip sp
// skip gp
ld x4, (3 * 8)(sp)
ld x5, (4 * 8)(sp)
ld x6, (5 * 8)(sp)
ld x7, (6 * 8)(sp)
ld x8, (7 * 8)(sp)
ld x9, (8 * 8)(sp)
ld x10, (9 * 8)(sp)
ld x11, (10 * 8)(sp)
ld x12, (11 * 8)(sp)
ld x13, (12 * 8)(sp)
ld x14, (13 * 8)(sp)
ld x15, (14 * 8)(sp)
ld x16, (15 * 8)(sp)
ld x17, (16 * 8)(sp)
ld x18, (17 * 8)(sp)
ld x19, (18 * 8)(sp)
ld x20, (19 * 8)(sp)
ld x21, (20 * 8)(sp)
ld x22, (21 * 8)(sp)
ld x23, (22 * 8)(sp)
ld x24, (23 * 8)(sp)
ld x25, (24 * 8)(sp)
ld x26, (25 * 8)(sp)
ld x27, (26 * 8)(sp)
ld x28, (27 * 8)(sp)
ld x29, (28 * 8)(sp)
ld x30, (29 * 8)(sp)
ld x31, (30 * 8)(sp)
ld gp, (31 * 8)(sp) // new IP; this clobbers register x3/gp which is ABI reserved
.global __relibc_internal_sigentry_crit_first
__relibc_internal_sigentry_crit_first:
ld sp, (1 * 8)(sp)
.global __relibc_internal_sigentry_crit_second
__relibc_internal_sigentry_crit_second:
jr gp
7:
// A spurious signal occurred. Signals are still disabled here, but will need to be re-enabled.
// restore stack
ld sp, ({tcb_sa_off} + {sa_tmp_sp})(t0)
// move saved IP away from control, allowing arch_pre to save us if interrupted.
ld t1, ({tcb_sc_off} + {sc_saved_ip})(t0)
sd t1, ({tcb_sa_off} + {sa_tmp_ip})(t0)
// restore regs
ld t2, ({tcb_sa_off} + {sa_tmp_t2})(t0)
ld t3, ({tcb_sa_off} + {sa_tmp_t3})(t0)
ld t4, ({tcb_sa_off} + {sa_tmp_t4})(t0)
// move saved t0 away from control as well
mv t1, t0
ld t0, ({tcb_sc_off} + {sc_saved_t0})(t0)
// Re-enable signals. This code can be interrupted after this signal, so we need to define
// 'crit_third'.
ld gp, ({tcb_sc_off} + {sc_control})(t1)
andi gp, gp, ~1
sd gp, ({tcb_sc_off} + {sc_control})(t1)
.globl __relibc_internal_sigentry_crit_third
__relibc_internal_sigentry_crit_third:
ld gp, ({tcb_sa_off} + {sa_tmp_ip})(t1)
.globl __relibc_internal_sigentry_crit_fourth
__relibc_internal_sigentry_crit_fourth:
ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t1)
.globl __relibc_internal_sigentry_crit_fifth
__relibc_internal_sigentry_crit_fifth:
jr gp
"] <= [
tcb_sc_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control)),
sc_word = const offset_of!(Sigcontrol, word),
sc_saved_t0 = const offset_of!(Sigcontrol, saved_archdep_reg),
sc_saved_ip = const offset_of!(Sigcontrol, saved_ip),
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
sc_control = const offset_of!(Sigcontrol, control_flags),
tcb_sa_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch)),
sa_off_pctl = const offset_of!(SigArea, pctl),
sa_tmp_sp = const offset_of!(SigArea, tmp_sp),
sa_tmp_t1 = const offset_of!(SigArea, tmp_t1),
sa_tmp_t2 = const offset_of!(SigArea, tmp_t2),
sa_tmp_t3 = const offset_of!(SigArea, tmp_t3),
sa_tmp_t4 = const offset_of!(SigArea, tmp_t4),
sa_tmp_a0 = const offset_of!(SigArea, tmp_a0),
sa_tmp_a1 = const offset_of!(SigArea, tmp_a1),
sa_tmp_a2 = const offset_of!(SigArea, tmp_a2),
sa_tmp_a3 = const offset_of!(SigArea, tmp_a3),
sa_tmp_a4 = const offset_of!(SigArea, tmp_a4),
sa_tmp_a7 = const offset_of!(SigArea, tmp_a7),
sa_tmp_ip = const offset_of!(SigArea, tmp_ip),
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
sa_altstack_top = const offset_of!(SigArea, altstack_top),
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
pctl_off_actions = const offset_of!(SigProcControl, actions),
inner = sym inner_c,
pctl_off_pending = const offset_of!(SigProcControl, pending),
pctl_off_sender_infos = const offset_of!(SigProcControl, sender_infos),
SYS_CALL = const syscall::SYS_CALL,
RTINF_SIZE = const size_of::<RtSigInfo>(),
proc_fd = sym PROC_FD,
]);
asmfunction!(__relibc_internal_rlct_clone_ret: ["
ld t0, 0(sp)
ld a0, 8(sp)
ld a1, 16(sp)
ld a2, 24(sp)
ld a3, 32(sp)
ld a4, 40(sp)
ld a5, 48(sp)
addi sp, sp, 56
jalr t0
ret
"] <= []);
pub fn current_sp() -> usize {
let sp: usize;
unsafe {
core::arch::asm!(
"mv {}, sp",
out(reg) sp,
options(nomem));
}
sp
}
pub unsafe fn manually_enter_trampoline() {
let ctl = unsafe { &Tcb::current().unwrap().os_specific.control };
ctl.control_flags.store(
ctl.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(),
Ordering::Release,
);
ctl.saved_archdep_reg.set(0);
let ip_location = &ctl.saved_ip as *const _ as usize;
unsafe {
core::arch::asm!("
jal 2f
j 3f
2:
sd ra, 0(t0)
la t0, __relibc_internal_sigentry
jalr x0, t0
3:
",
inout("t0") ip_location => _, out("ra") _);
}
}
unsafe extern "C" {
fn __relibc_internal_sigentry_crit_first();
fn __relibc_internal_sigentry_crit_second();
fn __relibc_internal_sigentry_crit_third();
fn __relibc_internal_sigentry_crit_fourth();
fn __relibc_internal_sigentry_crit_fifth();
}
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt {
// It is impossible to update SP and PC atomically. Instead, we abuse the fact that
// signals are disabled in the prologue of the signal trampoline, which allows us to emulate
// atomicity inside the critical section, consisting of one instruction at 'crit_first', and
// one at 'crit_second', see asm.
if stack.regs.pc == __relibc_internal_sigentry_crit_first as *const () as u64 {
// Reexecute 'ld sp, (1 * 8)(sp)'
let stack_ptr = stack.regs.int_regs[1] as *const u64; // x2
stack.regs.int_regs[1] = unsafe { stack_ptr.add(1).read() };
// and 'jr gp' steps.
stack.regs.pc = stack.regs.int_regs[2];
} else if stack.regs.pc == __relibc_internal_sigentry_crit_second as *const () as u64
|| stack.regs.pc == __relibc_internal_sigentry_crit_fifth as *const () as u64
{
// just reexecute the jump
stack.regs.pc = stack.regs.int_regs[2];
} else if stack.regs.pc == __relibc_internal_sigentry_crit_third as *const () as u64 {
// ld gp, ({tcb_sa_off} + {sa_tmp_ip})(t1)
stack.regs.int_regs[2] = area.tmp_ip;
// ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t1)
stack.regs.int_regs[5] = area.tmp_t1;
// j gp
stack.regs.pc = stack.regs.int_regs[2];
} else if stack.regs.pc == __relibc_internal_sigentry_crit_fourth as *const () as u64 {
// ld t1, ({tcb_sa_off} + {sa_tmp_t1})(t1)
stack.regs.int_regs[5] = area.tmp_t1;
// jr gp
stack.regs.pc = stack.regs.int_regs[2];
}
get_sigaltstack(area, stack.regs.int_regs[1] as usize).into()
}
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_pc = core::mem::replace(
&mut stack.regs.pc,
__relibc_internal_sigentry as *const () as u64,
);
control.saved_ip.set(orig_pc as usize);
control
.saved_archdep_reg
.set(stack.regs.int_regs[4] as usize); // t0
}
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
-535
View File
@@ -1,535 +0,0 @@
use core::{
cell::SyncUnsafeCell,
mem::offset_of,
ptr::NonNull,
sync::atomic::{AtomicU8, Ordering},
};
use syscall::{
data::{SigProcControl, Sigcontrol},
error::*,
};
use crate::{
Tcb,
proc::{FdGuard, FdGuardUpper, ForkArgs, fork_inner},
signal::{PROC_CONTROL_STRUCT, PosixStackt, RtSigarea, SigStack, get_sigaltstack, inner_c},
};
use redox_protocols::protocol::{ProcCall, RtSigInfo};
use super::ForkScratchpad;
// Setup a stack starting from the very end of the address space, and then growing downwards.
pub const STACK_TOP: usize = 1 << 47;
pub const STACK_SIZE: usize = 8 * 1024 * 1024;
#[derive(Debug, Default)]
#[repr(C)]
pub struct SigArea {
pub tmp_rip: usize,
pub tmp_rsp: usize,
pub tmp_rax: usize,
pub tmp_rdx: usize,
pub tmp_rdi: usize,
pub tmp_rsi: usize,
pub tmp_r8: usize,
pub tmp_r10: usize,
pub tmp_r12: usize,
pub tmp_rt_inf: RtSigInfo,
pub tmp_id_inf: u64,
pub altstack_top: usize,
pub altstack_bottom: usize,
pub disable_signals_depth: u64,
pub last_sig_was_restart: bool,
pub last_sigstack: Option<NonNull<SigStack>>,
}
#[repr(C, align(16))]
#[derive(Debug, Default)]
pub struct ArchIntRegs {
pub ymm_upper: [u128; 16],
pub fxsave: [u128; 29],
pub r15: usize, // fxsave "available" +0
pub r14: usize, // available +8
pub r13: usize, // available +16
pub r12: usize, // available +24
pub rbp: usize, // available +32
pub rbx: usize, // available +40
pub r11: usize, // outside fxsave, and so on
pub r10: usize,
pub r9: usize,
pub r8: usize,
pub rax: usize,
pub rcx: usize,
pub rdx: usize,
pub rsi: usize,
pub rdi: usize,
pub rflags: usize,
pub rip: usize,
pub rsp: usize,
}
/// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
/// is already initialized as if it was a thread.
pub unsafe fn deactivate_tcb(open_via_dup: &FdGuardUpper) -> Result<()> {
let mut env = syscall::EnvRegisters::default();
let file = open_via_dup.dup_into_upper(b"regs/env")?;
env.fsbase = 0;
env.gsbase = 0;
file.write(&env)?;
crate::TLS_ACTIVATED.store(false, core::sync::atomic::Ordering::Relaxed);
Ok(())
}
unsafe extern "sysv64" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
Error::mux(fork_inner(initial_rsp, args))
}
#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "sysv64" fn child_hook(scratchpad: &ForkScratchpad) {
let _ = crate::sys::close(scratchpad.cur_filetable_fd);
crate::child_hook_common(crate::ChildHookCommonArgs {
new_thr_fd: FdGuard::new(scratchpad.new_thr_fd),
new_proc_fd: if scratchpad.new_proc_fd == usize::MAX {
None
} else {
Some(FdGuard::new(scratchpad.new_proc_fd))
},
new_filetable_fd: FdGuard::new(scratchpad.new_filetable_fd)
.to_upper()
.unwrap(),
});
}
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
push rbp
mov rbp, rsp
push rbx
push rbp
push r12
push r13
push r14
push r15
sub rsp, 16
stmxcsr [rsp+16]
fnstcw [rsp+8]
// rdi: &ForkArgs
// rsi: initial_rsp
mov rsi, rsp
call {fork_impl}
add rsp, 64
pop rbp
ret
"] <= [fork_impl = sym fork_impl]);
asmfunction!(__relibc_internal_fork_ret: ["
# scratchpad is in rsi, move to rdi for child_hook
mov rdi, rsi
call {child_hook}
ldmxcsr [rsp + 16]
mov rcx, [rsp + 8]
xor rax, rax
add rsp, 16
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop rbp
ret
"] <= [child_hook = sym child_hook]);
asmfunction!(__relibc_internal_rlct_clone_ret: ["
# Load registers
pop rax
pop rdi
pop rsi
pop rdx
pop rcx
pop r8
pop r9
mov DWORD PTR [rsp - 8], 0x00001F80
ldmxcsr [rsp - 8]
mov WORD PTR [rsp - 8], 0x037F
fldcw [rsp - 8]
# Call entry point
call rax
ret
"] <= []);
asmfunction!(__relibc_internal_sigentry: ["
// Save some registers
mov fs:[{tcb_sa_off} + {sa_tmp_rsp}], rsp
mov fs:[{tcb_sa_off} + {sa_tmp_rax}], rax
mov fs:[{tcb_sa_off} + {sa_tmp_rdx}], rdx
mov fs:[{tcb_sa_off} + {sa_tmp_rdi}], rdi
mov fs:[{tcb_sa_off} + {sa_tmp_rsi}], rsi
mov fs:[{tcb_sa_off} + {sa_tmp_r8}], r8
mov fs:[{tcb_sa_off} + {sa_tmp_r10}], r10
mov fs:[{tcb_sa_off} + {sa_tmp_r12}], r12
// First, select signal, always pick first available bit
1:
// Read standard signal word - first targeting this thread
mov rax, fs:[{tcb_sc_off} + {sc_word}]
mov rdx, rax
shr rdx, 32
and eax, edx
bsf eax, eax
jnz 2f
// If no unblocked thread signal was found, check for process.
// This is competitive; we need to atomically check if *we* cleared the process-wide pending
// bit, otherwise restart.
mov eax, [rip + {pctl} + {pctl_off_pending}]
and eax, edx
bsf eax, eax
jz 8f
lea rdi, [rip + {pctl} + {pctl_off_sender_infos}]
mov rdi, [rdi + rax * 8]
lock btr [rip + {pctl} + {pctl_off_pending}], eax
mov fs:[{tcb_sa_off} + {sa_tmp_id_inf}], rdi
jc 9f
8:
// Read second signal word - both process and thread simultaneously.
// This must be done since POSIX requires low realtime signals to be picked first.
mov edx, fs:[{tcb_sc_off} + {sc_word} + 8]
mov eax, [rip + {pctl} + {pctl_off_pending} + 4]
or eax, edx
and eax, fs:[{tcb_sc_off} + {sc_word} + 12]
bsf eax, eax
jz 7f
bt edx, eax // check if signal was sent to thread specifically
jnc 81f
// if so, continue as usual
add eax, 32
jmp 2f
81:
// otherwise, try (competitively) dequeueing realtime signal
// SYS_CALL(fd, payload_base, payload_len, metadata_len | (flags << 8), metadata_base)
// rax rdi rsi rdx r10 r8
mov r12d, eax
mov rsi, fs:[0]
mov rdi, [rip+{proc_fd}]
add rsi, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
mov rdx, {RTINF_SIZE}
mov [rsi], eax
lea r8, [rip + {proc_call_sigdeq}]
mov r10, 1
mov eax, {SYS_CALL}
syscall
test eax, eax
jnz 1b // assumes error can only be EAGAIN
lea eax, [r12d + 32]
jmp 9f
2:
mov edx, eax
shr edx, 5
mov rdi, fs:[{tcb_sc_off} + {sc_sender_infos} + eax * 8]
lock btr fs:[{tcb_sc_off} + {sc_word} + edx * 4], eax
mov fs:[{tcb_sa_off} + {sa_tmp_id_inf}], rdi
add eax, 64 // indicate signal was targeted at thread
9:
sub rsp, {REDZONE_SIZE}
and rsp, -{STACK_ALIGN}
// By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or
// not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then
// skip the sigaltstack logic.
lea rdx, [rip + {pctl} + {pctl_off_actions}]
mov ecx, eax
and ecx, 63
// LEA doesn't support 16x, so just do two x8s.
lea rdx, [rdx + 8 * rcx]
lea rdx, [rdx + 8 * rcx]
bt qword ptr [rdx], {SA_ONSTACK_BIT}
jnc 4f
// Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent
// to setting 'top' to usize::MAX and 'bottom' to 0.
// If current RSP is above altstack region, switch to altstack
mov rdx, fs:[{tcb_sa_off} + {sa_altstack_top}]
cmp rsp, rdx
cmova rsp, rdx
// If current RSP is below altstack region, also switch to altstack
cmp rsp, fs:[{tcb_sa_off} + {sa_altstack_bottom}]
cmovbe rsp, rdx
.p2align 4
4:
// Now that we have a stack, we can finally start initializing the signal stack!
push fs:[{tcb_sa_off} + {sa_tmp_rsp}]
push fs:[{tcb_sc_off} + {sc_saved_rip}]
push fs:[{tcb_sc_off} + {sc_saved_rflags}]
push fs:[{tcb_sa_off} + {sa_tmp_rdi}]
push fs:[{tcb_sa_off} + {sa_tmp_rsi}]
push fs:[{tcb_sa_off} + {sa_tmp_rdx}]
push rcx
push fs:[{tcb_sa_off} + {sa_tmp_rax}]
push fs:[{tcb_sa_off} + {sa_tmp_r8}]
push r9
push fs:[{tcb_sa_off} + {sa_tmp_r10}]
push r11
push rbx
push rbp
push fs:[{tcb_sa_off} + {sa_tmp_r12}]
push r13
push r14
push r15
sub rsp, (29 + 16) * 16 // fxsave region minus available bytes
fxsave64 [rsp + 16 * 16]
// TODO: self-modifying?
cmp byte ptr [rip + {supports_avx}], 0
je 5f
// Prefer vextractf128 over vextracti128 since the former only requires AVX version 1.
vextractf128 [rsp + 15 * 16], ymm0, 1
vextractf128 [rsp + 14 * 16], ymm1, 1
vextractf128 [rsp + 13 * 16], ymm2, 1
vextractf128 [rsp + 12 * 16], ymm3, 1
vextractf128 [rsp + 11 * 16], ymm4, 1
vextractf128 [rsp + 10 * 16], ymm5, 1
vextractf128 [rsp + 9 * 16], ymm6, 1
vextractf128 [rsp + 8 * 16], ymm7, 1
vextractf128 [rsp + 7 * 16], ymm8, 1
vextractf128 [rsp + 6 * 16], ymm9, 1
vextractf128 [rsp + 5 * 16], ymm10, 1
vextractf128 [rsp + 4 * 16], ymm11, 1
vextractf128 [rsp + 3 * 16], ymm12, 1
vextractf128 [rsp + 2 * 16], ymm13, 1
vextractf128 [rsp + 16], ymm14, 1
vextractf128 [rsp], ymm15, 1
5:
mov [rsp - 4], eax
sub rsp, 64 // alloc space for ucontext fields
mov rdi, rsp
call {inner}
add rsp, 64
fxrstor64 [rsp + 16 * 16]
cmp byte ptr [rip + {supports_avx}], 0
je 6f
vinsertf128 ymm0, ymm0, [rsp + 15 * 16], 1
vinsertf128 ymm1, ymm1, [rsp + 14 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 13 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 12 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 11 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 10 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 9 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 8 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 7 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 6 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 5 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 4 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 3 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 2 * 16], 1
vinsertf128 ymm2, ymm2, [rsp + 16], 1
vinsertf128 ymm2, ymm2, [rsp], 1
6:
add rsp, (29 + 16) * 16
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop r11
pop r10
pop r9
pop r8
pop rax
pop rcx
pop rdx
pop rsi
pop rdi
popfq
pop qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
// x86 lacks atomic instructions for setting both the stack and instruction pointer
// simultaneously, except the slow microcoded IRETQ instruction. Thus, we let the arch_pre
// function emulate atomicity between the pop rsp and indirect jump.
.globl __relibc_internal_sigentry_crit_first
__relibc_internal_sigentry_crit_first:
pop rsp
.globl __relibc_internal_sigentry_crit_second
__relibc_internal_sigentry_crit_second:
jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
7:
// A spurious signal occurred. Signals are still disabled here, but will need to be re-enabled.
// restore flags
mov rax, fs:[0] // load FS base
// TODO: Use lahf/sahf rather than pushfq/popfq?
lea rsp, [rax + {tcb_sc_off} + {sc_saved_rflags}]
popfq
// restore stack
mov rsp, fs:[{tcb_sa_off} + {sa_tmp_rsp}]
// move saved RIP away from control, allowing arch_pre to save us if interrupted.
mov rax, fs:[{tcb_sc_off} + {sc_saved_rip}]
mov fs:[{tcb_sa_off} + {sa_tmp_rip}], rax
// restore regs
mov rax, fs:[{tcb_sa_off} + {sa_tmp_rax}]
mov rdx, fs:[{tcb_sa_off} + {sa_tmp_rdx}]
// Re-enable signals. This code can be interrupted after this signal, so we need to define
// 'crit_third'.
and qword ptr fs:[{tcb_sc_off} + {sc_control}], ~1
.globl __relibc_internal_sigentry_crit_third
__relibc_internal_sigentry_crit_third:
jmp qword ptr fs:[{tcb_sa_off} + {sa_tmp_rip}]
"] <= [
inner = sym inner_c,
sa_tmp_rip = const offset_of!(SigArea, tmp_rip),
sa_tmp_rsp = const offset_of!(SigArea, tmp_rsp),
sa_tmp_rax = const offset_of!(SigArea, tmp_rax),
sa_tmp_rdx = const offset_of!(SigArea, tmp_rdx),
sa_tmp_rdi = const offset_of!(SigArea, tmp_rdi),
sa_tmp_rsi = const offset_of!(SigArea, tmp_rsi),
sa_tmp_r8 = const offset_of!(SigArea, tmp_r8),
sa_tmp_r10 = const offset_of!(SigArea, tmp_r10),
sa_tmp_r12 = const offset_of!(SigArea, tmp_r12),
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
sa_altstack_top = const offset_of!(SigArea, altstack_top),
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
sc_saved_rflags = const offset_of!(Sigcontrol, saved_archdep_reg),
sc_saved_rip = const offset_of!(Sigcontrol, saved_ip),
sc_word = const offset_of!(Sigcontrol, word),
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
sc_control = const offset_of!(Sigcontrol, control_flags),
tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
pctl_off_actions = const offset_of!(SigProcControl, actions),
pctl_off_pending = const offset_of!(SigProcControl, pending),
pctl_off_sender_infos = const offset_of!(SigProcControl, sender_infos),
pctl = sym PROC_CONTROL_STRUCT,
supports_avx = sym SUPPORTS_AVX,
REDZONE_SIZE = const 128,
STACK_ALIGN = const 16,
SA_ONSTACK_BIT = const 58, // (1 << 58) >> 32 = 0x0400_0000
SYS_CALL = const syscall::SYS_CALL,
proc_call_sigdeq = sym PROC_CALL_SIGDEQ,
RTINF_SIZE = const size_of::<RtSigInfo>(),
proc_fd = sym PROC_FD,
]);
unsafe extern "C" {
fn __relibc_internal_sigentry_crit_first();
fn __relibc_internal_sigentry_crit_second();
fn __relibc_internal_sigentry_crit_third();
}
/// Fixes some edge cases, and calculates the value for uc_stack.
pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt {
// It is impossible to update RSP and RIP atomically on x86_64, without using IRETQ, which is
// almost as slow as calling a SIGRETURN syscall would be. Instead, we abuse the fact that
// signals are disabled in the prologue of the signal trampoline, which allows us to emulate
// atomicity inside the critical section, consisting of one instruction at 'crit_first', one at
// 'crit_second', and one at 'crit_third', see asm.
if stack.regs.rip == __relibc_internal_sigentry_crit_first as *const () as usize {
// Reexecute pop rsp and jump steps. This case needs to be different from the one below,
// since rsp has not been overwritten with the previous context's stack, just yet. At this
// point, we know [rsp+0] contains the saved RSP, and [rsp-8] contains the saved RIP.
let stack_ptr = stack.regs.rsp as *const usize;
stack.regs.rsp = unsafe { stack_ptr.read() };
stack.regs.rip = unsafe { stack_ptr.sub(1).read() };
} else if stack.regs.rip == __relibc_internal_sigentry_crit_second as *const () as usize
|| stack.regs.rip == __relibc_internal_sigentry_crit_third as *const () as usize
{
// Almost finished, just reexecute the jump before tmp_rip is overwritten by this
// deeper-level signal.
stack.regs.rip = area.tmp_rip;
}
get_sigaltstack(area, stack.regs.rsp).into()
}
/// Rearrange the restore-stack and sigarea in a way that makes it look like a new signal was
/// immediately delivered after restoring the allowset to what it was prior to the original signal delivery.
pub fn arch_ret_to_sig(stack: &mut SigStack, control: &Sigcontrol) {
let orig_rip = core::mem::replace(
&mut stack.regs.rip,
__relibc_internal_sigentry as *const () as usize,
);
control.saved_ip.set(orig_rip);
control.saved_archdep_reg.set(stack.regs.rflags);
}
pub(crate) static SUPPORTS_AVX: AtomicU8 = AtomicU8::new(0);
// __relibc will be prepended to the name, so no_mangle is fine
#[allow(unsafe_op_in_unsafe_fn)]
#[unsafe(no_mangle)]
pub unsafe fn manually_enter_trampoline() {
let c = &Tcb::current().unwrap().os_specific.control;
c.control_flags.store(
c.control_flags.load(Ordering::Relaxed) | syscall::flag::INHIBIT_DELIVERY.bits(),
Ordering::Release,
);
c.saved_archdep_reg.set(0); // TODO: Just reset DF on x86?
core::arch::asm!("
lea rax, [rip + 2f]
mov fs:[{tcb_sc_off} + {sc_saved_rip}], rax
jmp __relibc_internal_sigentry
2:
",
out("rax") _,
tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
sc_saved_rip = const offset_of!(Sigcontrol, saved_ip),
);
}
/// Get current stack pointer, weak granularity guarantees.
pub fn current_sp() -> usize {
let sp: usize;
unsafe {
core::arch::asm!("mov {}, rsp", out(reg) sp);
}
sp
}
static PROC_CALL_SIGDEQ: u64 = ProcCall::Sigdeq as u64;
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
-366
View File
@@ -1,366 +0,0 @@
#![no_std]
#![allow(internal_features)]
#![deny(unsafe_op_in_unsafe_fn)]
#![feature(core_intrinsics, int_roundings, slice_ptr_get, sync_unsafe_cell)]
#![forbid(unreachable_patterns)]
use core::cell::UnsafeCell;
use generic_rt::GenericTcb;
use redox_protocols::protocol::ProcMeta;
use syscall::Sigcontrol;
use self::{
proc::{FdGuard, FdGuardUpper, STATIC_PROC_INFO},
sync::Mutex,
sys::FdTbl,
};
extern crate alloc;
#[macro_export]
macro_rules! asmfunction(
($name:ident $(($($arg:ty),*))? $(-> $ret:ty)? : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => {
::core::arch::global_asm!(concat!("
.p2align 4
.section .text.", stringify!($name), ", \"ax\", @progbits
.globl ", stringify!($name), "
.type ", stringify!($name), ", @function
", stringify!($name), ":
", $($asmstmt, "\n",)* "
.size ", stringify!($name), ", . - ", stringify!($name), "
"), $($decl = $(sym $symname)?$(const $constval)?),*);
unsafe extern "C" {
pub fn $name($($(_: $arg),*)?) $(-> $ret)?;
}
}
);
pub mod arch;
pub mod proc;
// TODO: Replace auxvs with a non-stack-based interface, but keep getauxval for compatibility
#[path = "../../src/platform/auxv_defs.rs"]
pub mod auxv_defs;
pub mod signal;
pub mod sync;
pub mod sys;
pub mod thread;
#[derive(Debug, Default)]
pub struct RtTcb {
pub control: Sigcontrol,
pub arch: UnsafeCell<crate::arch::SigArea>,
pub thr_fd: UnsafeCell<Option<FdGuardUpper>>,
}
impl RtTcb {
pub fn current() -> &'static Self {
unsafe { &Tcb::current().unwrap().os_specific }
}
pub fn thread_fd(&self) -> &FdGuardUpper {
unsafe { (&*self.thr_fd.get()).as_ref().unwrap() }
}
}
pub type Tcb = GenericTcb<RtTcb>;
// TODO: Remove this by keeping the TCB initialized during exec
// and informing ld.so through some other way.
pub static TLS_ACTIVATED: core::sync::atomic::AtomicBool =
core::sync::atomic::AtomicBool::new(false);
/// OS and architecture specific code to activate TLS - Redox aarch64
#[allow(unsafe_op_in_unsafe_fn)]
#[cfg(target_arch = "aarch64")]
pub unsafe fn tcb_activate(_tcb: &RtTcb, tls_end: usize, tls_len: usize) {
// Uses ABI page
let abi_ptr = tls_end - tls_len - 16;
core::ptr::write(abi_ptr as *mut usize, tls_end);
core::arch::asm!(
"msr tpidr_el0, {}",
in(reg) abi_ptr,
);
TLS_ACTIVATED.store(true, core::sync::atomic::Ordering::Relaxed);
}
/// OS and architecture specific code to activate TLS - Redox x86
#[allow(unsafe_op_in_unsafe_fn)]
#[cfg(target_arch = "x86")]
pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end: usize, _tls_len: usize) {
let mut env = syscall::EnvRegisters::default();
let file_fd = crate::sys::dup_into_upper_raw(tcb.thread_fd().as_raw_fd(), b"regs/env")
.expect("failed to open handle for process registers");
syscall::read(file_fd, &mut env).expect("failed to read gsbase");
env.gsbase = tls_end as u32;
syscall::write(file_fd, &env).expect("failed to write gsbase");
let _ = crate::sys::close_raw(file_fd);
TLS_ACTIVATED.store(true, core::sync::atomic::Ordering::Relaxed);
}
/// OS and architecture specific code to activate TLS - Redox x86_64
#[allow(unsafe_op_in_unsafe_fn)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end_and_tcb_start: usize, _tls_len: usize) {
let mut env = syscall::EnvRegisters::default();
let file_fd = crate::sys::dup_into_upper_raw(tcb.thread_fd().as_raw_fd(), b"regs/env")
.expect("failed to open handle for process registers");
syscall::read(file_fd, &mut env).expect("failed to read fsbase");
env.fsbase = tls_end_and_tcb_start as u64;
syscall::write(file_fd, &env).expect("failed to write fsbase");
let _ = crate::sys::close_raw(file_fd);
TLS_ACTIVATED.store(true, core::sync::atomic::Ordering::Relaxed);
}
/// OS and architecture specific code to activate TLS - Redox riscv64
#[allow(unsafe_op_in_unsafe_fn)]
#[cfg(target_arch = "riscv64")]
pub unsafe fn tcb_activate(_tcb: &RtTcb, tls_end: usize, tls_len: usize) {
// tp points to static tls block
// FIXME limited to a single initial master
let tls_start = tls_end - tls_len;
let abi_ptr = tls_start - 8;
core::ptr::write(abi_ptr as *mut usize, tls_end);
core::arch::asm!(
"mv tp, {}",
in(reg) tls_start
);
TLS_ACTIVATED.store(true, core::sync::atomic::Ordering::Relaxed);
}
/// Initialize redox-rt in situations where relibc is not used
#[allow(unsafe_op_in_unsafe_fn)]
#[cfg(not(feature = "proc"))]
pub unsafe fn initialize_freestanding(this_thr_fd: FdGuardUpper) -> &'static FdGuardUpper {
// TODO: This code is a hack! Integrate the ld_so TCB code into generic-rt, and then use that
// (this function will need pointers to the ELF structs normally passed in auxvs), so the TCB
// is initialized properly.
// TODO: TLS
let page = {
&mut *(syscall::fmap(
!0,
&syscall::Map {
offset: 0,
size: syscall::PAGE_SIZE,
flags: syscall::MapFlags::PROT_READ
| syscall::MapFlags::PROT_WRITE
| syscall::MapFlags::MAP_PRIVATE,
address: 0,
},
)
.unwrap() as *mut Tcb)
};
page.tcb_ptr = page;
page.tcb_len = syscall::PAGE_SIZE;
page.tls_end = (page as *mut Tcb).cast();
let cur_filetable_fd = syscall::dup_into(
this_thr_fd.as_raw_fd(),
this_thr_fd.as_raw_fd() + 1,
b"filetable-binary",
)
.expect("failed to open filetable-binary");
*current_filetable() =
FdTbl::from_binary_fd(FdGuard::new(cur_filetable_fd).to_upper().unwrap())
.expect("failed to populate fds");
// Make sure to use ptr::write to prevent dropping the existing FdGuard
page.os_specific.thr_fd.get().write(Some(this_thr_fd));
#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
unsafe {
let tcb_addr = page as *mut Tcb as usize;
tcb_activate(&page.os_specific, tcb_addr, 0)
}
#[cfg(target_arch = "aarch64")]
unsafe {
let abi_ptr = core::ptr::addr_of_mut!(page.tcb_ptr);
core::arch::asm!("msr tpidr_el0, {}", in(reg) abi_ptr);
}
#[cfg(target_arch = "riscv64")]
unsafe {
let abi_ptr = core::ptr::addr_of_mut!(page.tcb_ptr) as usize;
core::arch::asm!("mv tp, {}", in(reg) (abi_ptr + 8));
}
TLS_ACTIVATED.store(true, core::sync::atomic::Ordering::Relaxed);
initialize();
(*page.os_specific.thr_fd.get()).as_ref().unwrap()
}
pub(crate) fn read_proc_meta(proc: &FdGuardUpper) -> syscall::Result<ProcMeta> {
let mut bytes = [0_u8; size_of::<ProcMeta>()];
proc.read(&mut bytes)?;
Ok(*plain::from_bytes::<ProcMeta>(&bytes).unwrap())
}
pub unsafe fn initialize(
#[cfg(feature = "proc")] proc_fd: FdGuardUpper,
#[cfg(feature = "proc")] ns_fd: Option<FdGuardUpper>,
) {
#[cfg(feature = "proc")]
let metadata = read_proc_meta(&proc_fd).unwrap();
#[cfg(not(feature = "proc"))]
// Bootstrap mode, don't associate proc fds with PIDs
let metadata = ProcMeta::default();
#[cfg(feature = "proc")]
{
unsafe { crate::arch::PROC_FD.get().write(proc_fd.as_raw_fd()) };
}
unsafe {
STATIC_PROC_INFO.get().write(StaticProcInfo {
pid: metadata.pid,
#[cfg(feature = "proc")]
proc_fd: Some(proc_fd),
#[cfg(not(feature = "proc"))]
proc_fd: None,
})
};
#[cfg(feature = "proc")]
{
*DYNAMIC_PROC_INFO.lock() = DynamicProcInfo {
pgid: metadata.pgid,
ruid: metadata.ruid,
euid: metadata.euid,
suid: metadata.suid,
egid: metadata.egid,
rgid: metadata.rgid,
sgid: metadata.sgid,
ns_fd,
};
}
}
pub(crate) struct StaticProcInfo {
pid: u32,
proc_fd: Option<FdGuardUpper>,
}
pub struct DynamicProcInfo {
pub pgid: u32,
pub euid: u32,
pub suid: u32,
pub ruid: u32,
pub egid: u32,
pub rgid: u32,
pub sgid: u32,
pub ns_fd: Option<FdGuardUpper>,
}
static DYNAMIC_PROC_INFO: Mutex<DynamicProcInfo> = Mutex::new(DynamicProcInfo {
pgid: u32::MAX,
ruid: u32::MAX,
euid: u32::MAX,
suid: u32::MAX,
rgid: u32::MAX,
egid: u32::MAX,
sgid: u32::MAX,
ns_fd: None,
});
#[inline]
pub(crate) fn static_proc_info() -> &'static StaticProcInfo {
unsafe { &*STATIC_PROC_INFO.get() }
}
#[inline]
pub fn current_proc_fd() -> &'static FdGuardUpper {
let info = static_proc_info();
info.proc_fd.as_ref().unwrap()
}
#[inline]
pub fn current_namespace_fd() -> syscall::Result<usize> {
DYNAMIC_PROC_INFO
.lock()
.ns_fd
.as_ref()
.map(|g| g.as_raw_fd())
.ok_or(syscall::Error::new(syscall::ENOENT))
}
struct ChildHookCommonArgs {
new_thr_fd: FdGuard,
new_proc_fd: Option<FdGuard>,
new_filetable_fd: FdGuardUpper,
}
unsafe fn child_hook_common(args: ChildHookCommonArgs) {
let new_filetable_fd = args.new_filetable_fd;
let old_filetable_fd;
{
let mut guard = current_filetable();
old_filetable_fd = guard.take();
guard.set_fd(new_filetable_fd);
guard
.override_at(args.new_thr_fd.as_raw_fd(), args.new_thr_fd.as_raw_fd())
.expect("failed to add new_thr_fd");
if let Some(new_proc_fd) = args.new_proc_fd.as_ref() {
guard
.override_at(new_proc_fd.as_raw_fd(), new_proc_fd.as_raw_fd())
.expect("failed to add new_proc_fd");
}
if let Some(ref old) = old_filetable_fd {
let _ = guard.remove(old.as_raw_fd());
}
}
let new_thr_fd = args.new_thr_fd.to_upper().unwrap();
let new_proc_fd = args.new_proc_fd.map(|x| x.to_upper().unwrap());
// TODO: just pass PID to child rather than obtaining it via IPC?
#[cfg(feature = "proc")]
let metadata = read_proc_meta(
new_proc_fd
.as_ref()
.expect("must be present with proc feature"),
)
.unwrap();
#[cfg(not(feature = "proc"))]
let metadata = ProcMeta::default();
if let Some(proc_fd) = &new_proc_fd {
unsafe { crate::arch::PROC_FD.get().write(proc_fd.as_raw_fd()) };
}
let old_proc_fd = unsafe {
STATIC_PROC_INFO
.get()
.replace(StaticProcInfo {
pid: metadata.pid,
proc_fd: new_proc_fd,
})
.proc_fd
};
drop(old_proc_fd);
let old_thr_fd = unsafe { RtTcb::current().thr_fd.get().replace(Some(new_thr_fd)) };
drop(old_thr_fd);
drop(old_filetable_fd);
}
static FILETABLE: Mutex<FdTbl> = Mutex::new(FdTbl::new());
#[inline]
pub fn current_filetable() -> crate::sync::MutexGuard<'static, FdTbl> {
FILETABLE.lock()
}
-1284
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-68
View File
@@ -1,68 +0,0 @@
// TODO: Share code for simple futex-based mutex between relibc's Mutex<()> and this.
use core::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
sync::atomic::{AtomicU32, Ordering},
};
pub struct Mutex<T> {
pub lockword: AtomicU32,
pub inner: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for Mutex<T> {}
unsafe impl<T: Send> Sync for Mutex<T> {}
impl<T> Mutex<T> {
/// Represents an unlocked [Mutex].
pub const UNLOCKED: u32 = 0;
/// Represents a locked [Mutex].
pub const LOCKED: u32 = 1;
/// Represents a waiting [Mutex].
pub const WAITING: u32 = 2;
pub const fn new(t: T) -> Self {
Self {
lockword: AtomicU32::new(0),
inner: UnsafeCell::new(t),
}
}
pub fn lock(&self) -> MutexGuard<'_, T> {
while self
.lockword
.compare_exchange(
Self::UNLOCKED,
Self::LOCKED,
Ordering::Acquire,
Ordering::Relaxed,
)
.is_err()
{
core::hint::spin_loop();
}
MutexGuard { lock: self }
}
}
pub struct MutexGuard<'l, T> {
lock: &'l Mutex<T>,
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.inner.get() }
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.inner.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.lock
.lockword
.store(Mutex::<T>::UNLOCKED, Ordering::Release);
}
}
-2011
View File
File diff suppressed because it is too large Load Diff
-76
View File
@@ -1,76 +0,0 @@
use core::mem::size_of;
use syscall::Result;
use crate::{RtTcb, arch::*, proc::*, static_proc_info};
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
pub unsafe fn rlct_clone_impl(stack: *mut usize, tcb: &RtTcb) -> Result<usize> {
let proc_info = static_proc_info();
let cur_proc_fd = proc_info.proc_fd.as_ref().unwrap();
let cur_thr_fd = RtTcb::current().thread_fd();
let new_thr_fd = cur_proc_fd.dup_into_upper(b"new-thread")?;
// Inherit existing address space
{
let cur_addr_space_fd = cur_thr_fd.dup_into_upper(b"addrspace")?;
let new_addr_space_sel_fd = new_thr_fd.dup_into_upper(b"current-addrspace")?;
let buf = create_set_addr_space_buf(
cur_addr_space_fd.as_raw_fd(),
__relibc_internal_rlct_clone_ret as *const () as usize,
stack as usize,
);
new_addr_space_sel_fd.write(&buf)?;
}
// Inherit reference to file table
{
let cur_filetable_fd = cur_thr_fd.dup_into_upper(b"filetable")?;
let new_filetable_sel_fd = new_thr_fd.dup_into_upper(b"current-filetable")?;
new_filetable_sel_fd.write(&usize::to_ne_bytes(cur_filetable_fd.as_raw_fd()))?;
}
// Since the signal handler is not yet initialized, signals specifically targeting the thread
// (relibc is only required to implement thread-specific signals that already originate from
// the same process) will be discarded. Process-specific signals will ignore this new thread,
// until it has initialized its own signal handler.
let start_fd = new_thr_fd.dup_into_upper(b"start")?;
let fd = new_thr_fd.as_raw_fd();
unsafe {
tcb.thr_fd.get().write(Some(new_thr_fd));
}
// Unblock context.
start_fd.write(&[0])?;
Ok(fd)
}
pub unsafe fn exit_this_thread(stack_base: *mut (), stack_size: usize) -> ! {
let _guard = crate::signal::tmp_disable_signals();
let thread_fd = RtTcb::current().thread_fd();
// TODO: modify interface so it writes directly to the thread fd?
let status_fd = thread_fd.dup_into_upper(b"status").unwrap();
unsafe { exit_this_thread_inner(stack_base, stack_size, status_fd) }
}
/// exit_this_thread, but current thread_fd might has disappear
pub unsafe fn exit_this_thread_inner(
stack_base: *mut (),
stack_size: usize,
status_fd: FdGuard<true>,
) -> ! {
let mut buf = [0; size_of::<usize>() * 3];
plain::slice_from_mut_bytes(&mut buf)
.unwrap()
.copy_from_slice(&[usize::MAX, stack_base as usize, stack_size]);
// TODO: SYS_CALL w/CONSUME
status_fd.write(&buf).unwrap();
unreachable!()
}
-58
View File
@@ -1,58 +0,0 @@
#!/usr/bin/env bash
set -e
target=$1
deps_dir=$2
if [ -z "$target" ] || [ -z "$deps_dir" ]; then
echo "Usage:\n\t./renamesyms.sh TARGET DEPS_DIR"
exit 1
fi
if [ ! -f "$target" ]; then
echo "Target file '$target' does not exist"
exit 1
fi
if [ ! -d "$deps_dir" ] ; then
echo "Deps dir '$deps_dir' does not exist or not a directory"
exit 1
fi
symbols_file=`mktemp`
special_syms=(
__rdl_oom
__rg_alloc
__rg_alloc_zeroed
__rg_dealloc
__rg_oom
__rg_realloc
__rust_alloc
__rust_alloc_error_handler
__rust_alloc_error_handler_should_panic
__rust_alloc_zeroed
__rust_dealloc
__rust_no_alloc_shim_is_unstable
__rust_realloc
)
for dep in `find $deps_dir -type f -name "*.rlib"`; do
"${NM}" --format=posix -g "$dep" 2>/dev/null | sed 's/.*:.*//g' | awk '{if ($2 == "T") print $1}' | sed 's/^\(.*\)$/\1 __relibc_\1/g' >> $symbols_file
done
for special_sym in "${special_syms[@]}"; do
echo "$special_sym __relibc_$special_sym" >> $symbols_file
done
mangled_alloc_syms=$("${NM}" --format=posix -g "$target" 2>/dev/null | awk '{print $1}' | grep "7___rustc" || true)
for sym in $mangled_alloc_syms; do
echo "$sym __relibc_$sym" >> $symbols_file
done
sorted_file=`mktemp`
sort -u "$symbols_file" > "$sorted_file"
rm -f "$symbols_file"
"${OBJCOPY}" --redefine-syms="$sorted_file" "$target"
rm -f "$sorted_file"
-21
View File
@@ -1,21 +0,0 @@
blank_lines_lower_bound = 0
blank_lines_upper_bound = 1
brace_style = "SameLineWhere"
disable_all_formatting = false
edition = "2024"
empty_item_single_line = true
fn_single_line = false
force_explicit_abi = true
format_strings = false
hard_tabs = false
imports_granularity = "Crate"
imports_indent = "Block"
imports_layout = "Mixed"
indent_style = "Block"
max_width = 100
newline_style = "Unix"
show_parse_errors = true
skip_children = false
tab_spaces = 4
trailing_comma = "Vertical"
where_single_line = false
+154
View File
@@ -0,0 +1,154 @@
use crate::area_add;
use crate::os::{dtb::is_in_dev_mem_region, Os, OsMemoryEntry, OsMemoryKind};
use core::slice;
pub(crate) const PF_PRESENT: u64 = 1 << 0;
pub(crate) const PF_TABLE: u64 = 1 << 1;
pub(crate) const PF_OUTER_SHAREABLE: u64 = 0b01 << 8;
pub(crate) const PF_INNER_SHAREABLE: u64 = 0b11 << 8;
pub(crate) const PF_ACCESS: u64 = 1 << 10;
pub(crate) const PF_DEV: u64 = PF_OUTER_SHAREABLE | 2 << 2;
pub(crate) const PF_RAM: u64 = PF_INNER_SHAREABLE;
pub(crate) const ENTRY_ADDRESS_MASK: u64 = 0x000F_FFFF_FFFF_F000;
pub(crate) const PAGE_ENTRIES: usize = 512;
const PAGE_SIZE: usize = 4096;
pub(crate) const PHYS_OFFSET: u64 = 0xFFFF_8000_0000_0000;
unsafe fn paging_allocate(os: &impl Os) -> Option<&'static mut [u64]> {
unsafe {
let ptr = os.alloc_zeroed_page_aligned(PAGE_SIZE);
if !ptr.is_null() {
area_add(OsMemoryEntry {
base: ptr as u64,
size: PAGE_SIZE as u64,
kind: OsMemoryKind::Reclaim,
});
Some(slice::from_raw_parts_mut(ptr as *mut u64, PAGE_ENTRIES))
} else {
None
}
}
}
pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
unsafe {
// Create L0
let l0 = paging_allocate(os)?;
{
// Create L1 for identity mapping
let l1 = paging_allocate(os)?;
// Link first user and first kernel L0 entry to L1
l0[0] = l1.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
l0[256] = l1.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
// Identity map 8 GiB using 1 GiB pages
for l1_i in 0..8 {
let addr = l1_i as u64 * 0x4000_0000;
//TODO: is PF_RAM okay?
l1[l1_i] = addr | PF_ACCESS | PF_DEV | PF_PRESENT;
}
}
{
// Create L1 for kernel mapping
let l1 = paging_allocate(os)?;
// Link second to last L0 entry to L1
l0[510] = l1.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
// Map kernel_size at kernel offset
let mut kernel_mapped = 0;
let mut l1_i = 0;
while kernel_mapped < kernel_size && l1_i < l1.len() {
let l2 = paging_allocate(os)?;
l1[l1_i] = l2.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
l1_i += 1;
let mut l2_i = 0;
while kernel_mapped < kernel_size && l2_i < l2.len() {
let l3 = paging_allocate(os)?;
l2[l2_i] = l3.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
l2_i += 1;
let mut l3_i = 0;
while kernel_mapped < kernel_size && l3_i < l3.len() {
let addr = kernel_phys + kernel_mapped;
l3[l3_i] = addr | PF_ACCESS | PF_RAM | PF_TABLE | PF_PRESENT;
l3_i += 1;
kernel_mapped += PAGE_SIZE as u64;
}
}
}
assert!(kernel_mapped >= kernel_size);
}
Some(l0.as_ptr() as usize)
}
}
pub unsafe fn paging_framebuffer(
os: &impl Os,
page_phys: usize,
framebuffer_phys: u64,
framebuffer_size: u64,
) -> Option<u64> {
unsafe {
//TODO: smarter test for framebuffer already mapped
if framebuffer_phys + framebuffer_size <= 0x2_0000_0000 {
return Some(framebuffer_phys + PHYS_OFFSET);
}
let l0_i = ((framebuffer_phys / 0x80_0000_0000) + 256) as usize;
let mut l1_i = ((framebuffer_phys % 0x80_0000_0000) / 0x4000_0000) as usize;
let mut l2_i = ((framebuffer_phys % 0x4000_0000) / 0x20_0000) as usize;
let mut l3_i = ((framebuffer_phys % 0x20_0000) / (PAGE_SIZE as u64)) as usize;
assert_eq!(framebuffer_phys % (PAGE_SIZE as u64), 0);
let l0 = slice::from_raw_parts_mut(page_phys as *mut u64, PAGE_ENTRIES);
// Create l1 for framebuffer mapping
let l1 = if l0[l0_i] == 0 {
let l1 = paging_allocate(os)?;
l0[l0_i] = l1.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
l1
} else {
slice::from_raw_parts_mut((l0[l0_i] & ENTRY_ADDRESS_MASK) as *mut u64, PAGE_ENTRIES)
};
// Map framebuffer_size at framebuffer offset
let mut framebuffer_mapped = 0;
while framebuffer_mapped < framebuffer_size && l1_i < l1.len() {
let l2 = paging_allocate(os)?;
assert_eq!(l1[l1_i], 0);
l1[l1_i] = l2.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
while framebuffer_mapped < framebuffer_size && l2_i < l2.len() {
let l3 = paging_allocate(os)?;
assert_eq!(l2[l2_i], 0);
l2[l2_i] = l3.as_ptr() as u64 | PF_ACCESS | PF_TABLE | PF_PRESENT;
while framebuffer_mapped < framebuffer_size && l3_i < l3.len() {
let addr = framebuffer_phys + framebuffer_mapped;
assert_eq!(l3[l3_i], 0);
//TODO: is PF_RAM okay?
l3[l3_i] = addr | PF_ACCESS | PF_RAM | PF_TABLE | PF_PRESENT;
framebuffer_mapped += PAGE_SIZE as u64;
l3_i += 1;
}
l2_i += 1;
l3_i = 0;
}
l1_i += 1;
l2_i = 0;
}
assert!(framebuffer_mapped >= framebuffer_size);
Some(framebuffer_phys + PHYS_OFFSET)
}
}
+17
View File
@@ -0,0 +1,17 @@
#[cfg(target_arch = "aarch64")]
pub use self::aarch64::*;
#[cfg(target_arch = "aarch64")]
mod aarch64;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use self::x86::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod x86;
#[cfg(target_arch = "riscv64")]
pub use self::riscv64::*;
#[cfg(target_arch = "riscv64")]
mod riscv64;
+59
View File
@@ -0,0 +1,59 @@
use core::slice;
use crate::area_add;
use crate::os::{Os, OsMemoryEntry, OsMemoryKind};
pub(crate) mod sv39;
pub(crate) mod sv48;
pub(crate) mod sv57;
// Common constants
const PAGE_SHIFT: usize = 12;
const TABLE_SHIFT: usize = 9;
const TABLE_MASK: usize = (1 << TABLE_SHIFT) - 1;
const PAGE_ENTRIES: usize = 512;
const PAGE_SIZE: usize = 4096;
const PHYS_MASK: usize = (1usize << 44) - 1;
const VALID: u64 = 1;
const RWX: u64 = 7 << 1;
const ACCESSED: u64 = 1 << 6;
const DIRTY: u64 = 1 << 7;
extern crate alloc;
pub(crate) use sv39::PHYS_OFFSET;
pub(crate) use sv39::SATP_BITS;
pub(crate) use sv39::paging_create;
pub(crate) use sv39::paging_physmem as paging_framebuffer;
unsafe fn paging_allocate(os: &impl Os) -> Option<&'static mut [u64]> {
unsafe {
let ptr = os.alloc_zeroed_page_aligned(PAGE_SIZE);
if !ptr.is_null() {
area_add(OsMemoryEntry {
base: ptr as u64,
size: PAGE_SIZE as u64,
kind: OsMemoryKind::Reclaim,
});
Some(slice::from_raw_parts_mut(ptr as *mut u64, PAGE_ENTRIES))
} else {
None
}
}
}
unsafe fn get_table(os: &impl Os, parent: &mut [u64], index: usize) -> Option<&'static mut [u64]> {
unsafe {
if parent[index] == 0 {
let table = paging_allocate(os)?;
parent[index] = table.as_ptr() as u64 >> 2 | VALID;
Some(table)
} else {
Some(slice::from_raw_parts_mut(
(((parent[index] >> 10) & PHYS_MASK as u64) << 12) as *mut u64,
PAGE_ENTRIES,
))
}
}
}
+90
View File
@@ -0,0 +1,90 @@
use core::slice;
use super::*;
use crate::os::Os;
// Sv39 scheme
pub(crate) const PHYS_OFFSET: u64 = 0xFFFF_FFC0_0000_0000;
pub(crate) const SATP_BITS: usize = 8;
pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
unsafe {
// Create L2
let l2 = paging_allocate(os)?;
{
// Create L1 for identity mapping
for l2_i in 0..8 {
let addr = l2_i as u64 * 0x4000_0000;
// Identity map 8 GiB using 1GB pages
l2[l2_i] = addr >> 2 | RWX | VALID | ACCESSED | DIRTY;
// map phys into kernel VAS
l2[(PAGE_ENTRIES / 2) + l2_i] = addr >> 2 | RWX | VALID | ACCESSED | DIRTY;
}
}
{
// Create L1 for kernel mapping
let l1 = paging_allocate(os)?;
// Link second to last L0 entry to L1
l2[510] = l1.as_ptr() as u64 >> 2 | VALID;
// Map kernel_size at kernel offset
let mut kernel_mapped = 0;
let mut l1_i = 0;
while kernel_mapped < kernel_size && l1_i < l1.len() {
let l0 = paging_allocate(os)?;
l1[l1_i] = l0.as_ptr() as u64 >> 2 | VALID;
l1_i += 1;
let mut l0_i = 0;
while kernel_mapped < kernel_size && l0_i < l2.len() {
let addr = kernel_phys + kernel_mapped;
l0[l0_i] = addr >> 2 | RWX | VALID | ACCESSED | DIRTY;
l0_i += 1;
kernel_mapped += PAGE_SIZE as u64;
}
}
assert!(kernel_mapped >= kernel_size);
}
Some(l2.as_ptr() as usize)
}
}
pub unsafe fn paging_physmem(os: &impl Os, page_phys: usize, phys: u64, size: u64) -> Option<u64> {
unsafe {
if phys + size <= 0x2_0000_0000 {
return Some(phys + PHYS_OFFSET);
}
let mut l1_i = (phys as usize >> (PAGE_SHIFT + 2 * TABLE_SHIFT)) + PAGE_ENTRIES / 2;
let mut l0_i = (phys as usize >> (PAGE_SHIFT + TABLE_SHIFT)) & TABLE_MASK;
assert_eq!(phys & ((1 << (PAGE_SHIFT + TABLE_SHIFT)) - 1), 0);
let l1 = slice::from_raw_parts_mut(page_phys as *mut u64, PAGE_ENTRIES);
// Map framebuffer_size at framebuffer offset
let mut mapped = 0;
while mapped < size && l1_i < l1.len() {
let l0 = get_table(os, l1, l1_i)?;
while mapped < size && l0_i < l0.len() {
let addr = phys + mapped;
assert_eq!(l0[l0_i], 0);
l0[l0_i] = (addr >> 2) | RWX | VALID | ACCESSED | DIRTY;
mapped += 1 << (PAGE_SHIFT + TABLE_SHIFT); // Map with 2mb mega-pages
l0_i += 1;
}
l1_i += 1;
l0_i = 0;
}
assert!(mapped >= size);
Some(phys + PHYS_OFFSET)
}
}
+108
View File
@@ -0,0 +1,108 @@
use core::slice;
use super::*;
use crate::os::Os;
// Sv48 scheme
pub(crate) const PHYS_OFFSET: u64 = 0xFFFF_8000_0000_0000;
pub(crate) const SATP_BITS: usize = 9;
pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
unsafe {
// Create L3
let l3 = paging_allocate(os)?;
{
// Create L2 for identity mapping
let l2 = paging_allocate(os)?;
// Map L2 into beginning of userspace and kernelspace
l3[0] = (l2.as_ptr() as u64 >> 2) | VALID;
l3[PAGE_ENTRIES / 2] = (l2.as_ptr() as u64 >> 2) | VALID;
// Identity map 8 GiB using 1GB pages
for l2_i in 0..8 {
let addr = l2_i as u64 * 0x4000_0000;
l2[l2_i] = addr >> 2 | RWX | VALID;
}
}
{
// Create L2 for kernel mapping
let l2 = paging_allocate(os)?;
// Link last L3 entry to L2
l3[511] = l2.as_ptr() as u64 >> 2 | VALID;
// Create L1 for kernel mapping
let l1 = paging_allocate(os)?;
// Link last L1 entry to L2
l2[510] = l1.as_ptr() as u64 >> 2 | VALID;
// Map kernel_size at kernel offset
let mut kernel_mapped = 0;
let mut l1_i = 0;
while kernel_mapped < kernel_size && l1_i < l1.len() {
let l0 = paging_allocate(os)?;
l1[l1_i] = l0.as_ptr() as u64 >> 2 | VALID;
l1_i += 1;
let mut l0_i = 0;
while kernel_mapped < kernel_size && l0_i < l2.len() {
let addr = kernel_phys + kernel_mapped;
l0[l0_i] = addr >> 2 | RWX | VALID | ACCESSED | DIRTY;
l0_i += 1;
kernel_mapped += PAGE_SIZE as u64;
}
}
assert!(kernel_mapped >= kernel_size);
}
Some(l3.as_ptr() as usize)
}
}
pub unsafe fn paging_physmem(os: &impl Os, page_phys: usize, phys: u64, size: u64) -> Option<u64> {
unsafe {
if phys + size <= 0x2_0000_0000 {
return Some(phys + PHYS_OFFSET);
}
let mut l2_i = (phys as usize >> (PAGE_SHIFT + 3 * TABLE_SHIFT)) + PAGE_ENTRIES / 2;
let mut l1_i = (phys as usize >> (PAGE_SHIFT + 2 * TABLE_SHIFT)) & TABLE_MASK;
let mut l0_i = (phys as usize >> (PAGE_SHIFT + TABLE_SHIFT)) & TABLE_MASK;
assert_eq!(phys & ((1 << (PAGE_SHIFT + TABLE_SHIFT)) - 1), 0);
let l2 = slice::from_raw_parts_mut(page_phys as *mut u64, PAGE_ENTRIES);
// Map framebuffer_size at framebuffer offset
let mut mapped = 0;
while mapped < size && l2_i < l2.len() {
let l1 = get_table(os, l2, l2_i)?;
while mapped < size && l1_i < l1.len() {
let l0 = get_table(os, l1, l1_i)?;
while mapped < size && l0_i < l0.len() {
let addr = phys + mapped;
assert_eq!(l0[l0_i], 0);
l0[l0_i] = (addr >> 2) | RWX | VALID;
mapped += 1 << (PAGE_SHIFT + TABLE_SHIFT);
l0_i += 1;
}
l1_i += 1;
l0_i = 0;
}
l2_i += 1;
l1_i = 0;
}
assert!(mapped >= size);
Some(phys + PHYS_OFFSET)
}
}
+124
View File
@@ -0,0 +1,124 @@
use core::slice;
use super::*;
use crate::os::Os;
// Sv57 scheme
pub(crate) const PHYS_OFFSET: u64 = 0xFF00_0000_0000_0000;
pub(crate) const SATP_BIT: usize = 10;
pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
unsafe {
// Create L4
let l4 = paging_allocate(os)?;
{
// Create L3
let l3 = paging_allocate(os)?;
// Map L3 into beginning of userspace and kernelspace
l4[0] = (l3.as_ptr() as u64 >> 2) | VALID;
l4[PAGE_ENTRIES / 2] = (l3.as_ptr() as u64 >> 2) | VALID;
// Create L2 for identity mapping
let l2 = paging_allocate(os)?;
// Identity map 8 GiB using 1GB pages
for l2_i in 0..8 {
let addr = l2_i as u64 * 0x4000_0000;
l2[l2_i] = addr >> 2 | RWX | VALID;
}
}
{
// Create L3
let l3 = paging_allocate(os)?;
// Link last L4 entry to L3
l4[511] = l3.as_ptr() as u64 >> 2 | VALID;
// Create L2 for kernel mapping
let l2 = paging_allocate(os)?;
// Link last L3 entry to L2
l3[511] = l2.as_ptr() as u64 >> 2 | VALID;
// Create L1 for kernel mapping
let l1 = paging_allocate(os)?;
// Link last L1 entry to L2
l2[510] = l1.as_ptr() as u64 >> 2 | VALID;
// Map kernel_size at kernel offset
let mut kernel_mapped = 0;
let mut l1_i = 0;
while kernel_mapped < kernel_size && l1_i < l1.len() {
let l0 = paging_allocate(os)?;
l1[l1_i] = l0.as_ptr() as u64 >> 2 | VALID;
l1_i += 1;
let mut l0_i = 0;
while kernel_mapped < kernel_size && l0_i < l2.len() {
let addr = kernel_phys + kernel_mapped;
l0[l0_i] = addr >> 2 | RWX | VALID | ACCESSED | DIRTY;
l0_i += 1;
kernel_mapped += PAGE_SIZE as u64;
}
}
assert!(kernel_mapped >= kernel_size);
}
Some(l4.as_ptr() as usize)
}
}
pub unsafe fn paging_physmem(os: &impl Os, page_phys: usize, phys: u64, size: u64) -> Option<u64> {
unsafe {
if phys + size <= 0x2_0000_0000 {
return Some(phys + PHYS_OFFSET);
}
let mut l3_i = (phys as usize >> (PAGE_SHIFT + 4 * TABLE_SHIFT)) + PAGE_ENTRIES / 2;
let mut l2_i = (phys as usize >> (PAGE_SHIFT + 3 * TABLE_SHIFT)) & TABLE_MASK;
let mut l1_i = (phys as usize >> (PAGE_SHIFT + 2 * TABLE_SHIFT)) & TABLE_MASK;
let mut l0_i = (phys as usize >> (PAGE_SHIFT + TABLE_SHIFT)) & TABLE_MASK;
assert_eq!(phys & ((1 << (PAGE_SHIFT + TABLE_SHIFT)) - 1), 0);
let l3 = slice::from_raw_parts_mut(page_phys as *mut u64, PAGE_ENTRIES);
// Map framebuffer_size at framebuffer offset
let mut mapped = 0;
while mapped < size && l3_i < l3.len() {
let l2 = get_table(os, l3, l3_i)?;
while mapped < size && l2_i < l2.len() {
let l1 = get_table(os, l2, l2_i)?;
while mapped < size && l1_i < l1.len() {
let l0 = get_table(os, l1, l1_i)?;
while mapped < size && l0_i < l0.len() {
let addr = phys + mapped;
assert_eq!(l0[l0_i], 0);
l0[l0_i] = (addr >> 2) | RWX | VALID;
mapped += 1 << (PAGE_SHIFT + TABLE_SHIFT);
l0_i += 1;
}
l1_i += 1;
l0_i = 0;
}
l2_i += 1;
l1_i = 0;
}
l3_i += 1;
l2_i += 0;
}
assert!(mapped >= size);
Some(phys + PHYS_OFFSET)
}
}
+29
View File
@@ -0,0 +1,29 @@
use crate::os::Os;
pub(crate) mod x32;
pub(crate) mod x64;
pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
unsafe {
if crate::KERNEL_64BIT {
x64::paging_create(os, kernel_phys, kernel_size)
} else {
x32::paging_create(os, kernel_phys, kernel_size)
}
}
}
pub unsafe fn paging_framebuffer(
os: &impl Os,
page_phys: usize,
framebuffer_phys: u64,
framebuffer_size: u64,
) -> Option<u64> {
unsafe {
if crate::KERNEL_64BIT {
x64::paging_framebuffer(os, page_phys, framebuffer_phys, framebuffer_size)
} else {
x32::paging_framebuffer(os, page_phys, framebuffer_phys, framebuffer_size)
}
}
}
+88
View File
@@ -0,0 +1,88 @@
use crate::area_add;
use crate::os::{Os, OsMemoryEntry, OsMemoryKind};
use core::slice;
const PAGE_ENTRIES: usize = 1024;
const PAGE_SIZE: usize = 4096;
pub(crate) const PHYS_OFFSET: u32 = 0x8000_0000;
unsafe fn paging_allocate(os: &impl Os) -> Option<&'static mut [u32]> {
unsafe {
let ptr = os.alloc_zeroed_page_aligned(PAGE_SIZE);
if !ptr.is_null() {
area_add(OsMemoryEntry {
base: ptr as u64,
size: PAGE_SIZE as u64,
kind: OsMemoryKind::Reclaim,
});
Some(slice::from_raw_parts_mut(ptr as *mut u32, PAGE_ENTRIES))
} else {
None
}
}
}
pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
unsafe {
let pd = paging_allocate(os)?;
//Identity map 1 GiB using 4 MiB pages, also map at PHYS_OFFSET
for pd_i in 0..256 {
let addr = pd_i as u32 * 0x40_0000;
pd[pd_i] = addr | 1 << 7 | 1 << 1 | 1;
pd[pd_i + 512] = addr | 1 << 7 | 1 << 1 | 1;
}
// Map kernel_size at kernel offset
let mut kernel_mapped = 0;
let mut pd_i = 0xC000_0000 / 0x40_0000;
while kernel_mapped < kernel_size && pd_i < pd.len() {
let pt = paging_allocate(os)?;
pd[pd_i] = pt.as_ptr() as u32 | 1 << 1 | 1;
pd_i += 1;
let mut pt_i = 0;
while kernel_mapped < kernel_size && pt_i < pt.len() {
let addr = kernel_phys + kernel_mapped;
pt[pt_i] = addr as u32 | 1 << 1 | 1;
pt_i += 1;
kernel_mapped += PAGE_SIZE as u64;
}
}
assert!(kernel_mapped >= kernel_size);
Some(pd.as_ptr() as usize)
}
}
pub unsafe fn paging_framebuffer(
os: &impl Os,
page_phys: usize,
framebuffer_phys: u64,
framebuffer_size: u64,
) -> Option<u64> {
unsafe {
let framebuffer_virt = 0xD000_0000; // 256 MiB after kernel mapping, but before heap mapping
let pd = slice::from_raw_parts_mut(page_phys as *mut u32, PAGE_ENTRIES);
// Map framebuffer_size at framebuffer offset
let mut framebuffer_mapped = 0;
let mut pd_i = framebuffer_virt / 0x40_0000;
while framebuffer_mapped < framebuffer_size && pd_i < pd.len() {
let pt = paging_allocate(os)?;
pd[pd_i] = pt.as_ptr() as u32 | 1 << 1 | 1;
pd_i += 1;
let mut pt_i = 0;
while framebuffer_mapped < framebuffer_size && pt_i < pt.len() {
let addr = framebuffer_phys + framebuffer_mapped;
pt[pt_i] = addr as u32 | 1 << 1 | 1;
pt_i += 1;
framebuffer_mapped += PAGE_SIZE as u64;
}
}
assert!(framebuffer_mapped >= framebuffer_size);
Some(framebuffer_virt as u64)
}
}
+148
View File
@@ -0,0 +1,148 @@
use core::slice;
use crate::area_add;
use crate::os::{Os, OsMemoryEntry, OsMemoryKind};
const ENTRY_ADDRESS_MASK: u64 = 0x000F_FFFF_FFFF_F000;
const PAGE_ENTRIES: usize = 512;
const PAGE_SIZE: usize = 4096;
pub(crate) const PHYS_OFFSET: u64 = 0xFFFF_8000_0000_0000;
unsafe fn paging_allocate(os: &impl Os) -> Option<&'static mut [u64]> {
unsafe {
let ptr = os.alloc_zeroed_page_aligned(PAGE_SIZE);
if !ptr.is_null() {
area_add(OsMemoryEntry {
base: ptr as u64,
size: PAGE_SIZE as u64,
kind: OsMemoryKind::Reclaim,
});
Some(slice::from_raw_parts_mut(ptr as *mut u64, PAGE_ENTRIES))
} else {
None
}
}
}
const PRESENT: u64 = 1;
const WRITABLE: u64 = 1 << 1;
const LARGE: u64 = 1 << 7;
pub unsafe fn paging_create(os: &impl Os, kernel_phys: u64, kernel_size: u64) -> Option<usize> {
unsafe {
// Create PML4
let pml4 = paging_allocate(os)?;
{
// Create PDP for identity mapping
let pdp = paging_allocate(os)?;
// Link first user and first kernel PML4 entry to PDP
pml4[0] = pdp.as_ptr() as u64 | WRITABLE | PRESENT;
pml4[256] = pdp.as_ptr() as u64 | WRITABLE | PRESENT;
// Identity map 8 GiB using 2 MiB pages
for pdp_i in 0..8 {
let pd = paging_allocate(os)?;
pdp[pdp_i] = pd.as_ptr() as u64 | WRITABLE | PRESENT;
for pd_i in 0..pd.len() {
let addr = pdp_i as u64 * 0x4000_0000 + pd_i as u64 * 0x20_0000;
pd[pd_i] = addr | LARGE | WRITABLE | PRESENT;
}
}
}
{
// Create PDP (spanning 512 GiB) for kernel mapping
let pdp = paging_allocate(os)?;
// Link last PML4 entry to PDP
pml4[511] = pdp.as_ptr() as u64 | WRITABLE | PRESENT;
// Create PD (spanning 1 GiB) for kernel mapping.
let pd = paging_allocate(os)?;
// The kernel is mapped at -2^31, i.e. 0xFFFF_FFFF_8000_0000. Since a PD is 1 GiB, link
// the second last PDP entry to PD.
pdp[510] = pd.as_ptr() as u64 | WRITABLE | PRESENT;
// Map kernel_size bytes to kernel offset, i.e. to the start of the PD.
let mut kernel_mapped = 0;
let mut pd_idx = 0;
while kernel_mapped < kernel_size && pd_idx < pd.len() {
let pt = paging_allocate(os)?;
pd[pd_idx] = pt.as_ptr() as u64 | WRITABLE | PRESENT;
pd_idx += 1;
let mut pt_idx = 0;
while kernel_mapped < kernel_size && pt_idx < pt.len() {
let addr = kernel_phys + kernel_mapped;
pt[pt_idx] = addr | WRITABLE | PRESENT;
pt_idx += 1;
kernel_mapped += PAGE_SIZE as u64;
}
}
assert!(kernel_mapped >= kernel_size);
}
Some(pml4.as_ptr() as usize)
}
}
pub unsafe fn paging_framebuffer(
os: &impl Os,
page_phys: usize,
framebuffer_phys: u64,
framebuffer_size: u64,
) -> Option<u64> {
unsafe {
//TODO: smarter test for framebuffer already mapped
if framebuffer_phys + framebuffer_size <= 0x2_0000_0000 {
return Some(framebuffer_phys + PHYS_OFFSET);
}
let pml4_i = ((framebuffer_phys / 0x80_0000_0000) + 256) as usize;
let mut pdp_i = ((framebuffer_phys % 0x80_0000_0000) / 0x4000_0000) as usize;
let mut pd_i = ((framebuffer_phys % 0x4000_0000) / 0x20_0000) as usize;
assert_eq!(framebuffer_phys % 0x20_0000, 0);
let pml4 = slice::from_raw_parts_mut(page_phys as *mut u64, PAGE_ENTRIES);
// Create PDP for framebuffer mapping
let pdp = if pml4[pml4_i] == 0 {
let pdp = paging_allocate(os)?;
pml4[pml4_i] = pdp.as_ptr() as u64 | 1 << 1 | 1;
pdp
} else {
slice::from_raw_parts_mut(
(pml4[pml4_i] & ENTRY_ADDRESS_MASK) as *mut u64,
PAGE_ENTRIES,
)
};
// Map framebuffer_size at framebuffer offset
let mut framebuffer_mapped = 0;
while framebuffer_mapped < framebuffer_size && pdp_i < pdp.len() {
let pd = paging_allocate(os)?;
assert_eq!(pdp[pdp_i], 0);
pdp[pdp_i] = pd.as_ptr() as u64 | 1 << 1 | 1;
while framebuffer_mapped < framebuffer_size && pd_i < pd.len() {
let addr = framebuffer_phys + framebuffer_mapped;
assert_eq!(pd[pd_i], 0);
pd[pd_i] = addr | 1 << 7 | 1 << 1 | 1;
framebuffer_mapped += 0x20_0000;
pd_i += 1;
}
pdp_i += 1;
pd_i = 0;
}
assert!(framebuffer_mapped >= framebuffer_size);
Some(framebuffer_phys + PHYS_OFFSET)
}
}

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