mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-08-05 03:14:18 +00:00
Compare commits
248 Commits
958a3ed263
...
master
Author | SHA1 | Date | |
---|---|---|---|
a047edc97d
|
|||
2c1d6c2608
|
|||
97a892d114
|
|||
3be150da53
|
|||
455224ceb4
|
|||
e01f1dc97c
|
|||
76113df5a9
|
|||
1addd310ad
|
|||
3d92a87bef
|
|||
f7177f92cf
|
|||
6a6c3bfc67
|
|||
8dbeee4d9a
|
|||
5d5b674aed
|
|||
31bbc29c9f
|
|||
f5c8ae9323
|
|||
154d857c2e
|
|||
12ae5a83da
|
|||
13ce994edf
|
|||
814175ddaf
|
|||
43e7ddb9de
|
|||
0187fa5b66
|
|||
33c284091d
|
|||
9538589c11
|
|||
905b6933c9
|
|||
07d0ca0438
|
|||
7d37f8a8a1
|
|||
8103caa52c
|
|||
4929b76c7c
|
|||
d20d4f7bf9
|
|||
f06c0b19fa
|
|||
70a08e46bd
|
|||
2349610e47
|
|||
fda5ede37f
|
|||
81da8dd989
|
|||
557c7e6235
|
|||
83a7f83f81
|
|||
6592db3f4e
|
|||
d7abd36717
|
|||
7873d0e724
|
|||
9626ec4662
|
|||
dbb5a483e0
|
|||
aca55f993f
|
|||
41fe55fd1f
|
|||
c491351fd0
|
|||
75d51fb9d9
|
|||
21db83b943
|
|||
fa2e37f603
|
|||
fab3be67ee
|
|||
6e26184a04
|
|||
6b6028434d
|
|||
ca02557df4
|
|||
527ad803d3
|
|||
2791a602b5
|
|||
3404bbc3bc
|
|||
c254b96256
|
|||
1e4d404a43
|
|||
16ec6cbdb6
|
|||
ba99275700
|
|||
80c313b02d
|
|||
fe8682aa85
|
|||
cd23c59c46
|
|||
f5c9b561a9
|
|||
366fd97c0a
|
|||
d3fd61c068
|
|||
0a037f1ae1
|
|||
292bfa362a
|
|||
bcc2c9d0ab
|
|||
e270c9f35b
|
|||
7902726239
|
|||
abb7899a9d
|
|||
8c4c8d36de
|
|||
0fffc6c914
|
|||
34e24df7c9
|
|||
550e98e87c
|
|||
4ff6790072
|
|||
205ddb1e49
|
|||
0735743f44
|
|||
33eee9c628
|
|||
ef5d61df9d
|
|||
11d326b693
|
|||
5293bb2039
|
|||
bc84c406d9
|
|||
ed1f4f3c1b
|
|||
ec04e5abe9
|
|||
5ecfffc049
|
|||
c7d501b466
|
|||
1f646d6826
|
|||
3315d79742
|
|||
a1b58bacd8
|
|||
69122746de
|
|||
764dfe67a5
|
|||
3d87345a51
|
|||
eb89b060f6
|
|||
25713e0f13
|
|||
03147b532c
|
|||
d8cd27196d
|
|||
832833a56f
|
|||
a4e5f4785c
|
|||
a268f8dc2f
|
|||
a16a88b5f9
|
|||
2d2d28689c
|
|||
d4346202ca
|
|||
b1a30059ed
|
|||
58accf8acf
|
|||
24c0848797
|
|||
b232dc6b40
|
|||
120d67fb1a
|
|||
f6eb4bd3dc
|
|||
7e7e475dac
|
|||
23d0056098
|
|||
3edb4b4761
|
|||
fd24431eea
|
|||
5c1c26b135
|
|||
a333d8aa7c
|
|||
f054e9976a
|
|||
f87c3d7e11
|
|||
0041300a00
|
|||
fe6d7f4b08
|
|||
a1622cc885
|
|||
bd32020876
|
|||
44323c85a3
|
|||
027d77ed66
|
|||
bbb70eb621
|
|||
1593e3107d
|
|||
1a48d05042
|
|||
75dd958316
|
|||
cccbfd2c95
|
|||
bf20bd89ed
|
|||
c3fd55bb00
|
|||
c660a7fe4f
|
|||
91ad0e14df
|
|||
a6ca98987e
|
|||
f8f08a11db
|
|||
5d64c05446
|
|||
a1064d8978
|
|||
6d01cf4e69
|
|||
ffd992cd74
|
|||
8d71ed0ad5
|
|||
93d897e95c
|
|||
31181d5b5d
|
|||
2f18d390e4
|
|||
5ffb0e704d
|
|||
ad0c1e15e0
|
|||
b74d4db23b
|
|||
022d99f795
|
|||
3482131b3f
|
|||
0a32c19923
|
|||
36c5c8ad67
|
|||
6240d6638f
|
|||
7491f19f9a
|
|||
13d52897b8
|
|||
4cc058ab42
|
|||
a7f754c5e8
|
|||
9304cafe0c
|
|||
7b42b46942
|
|||
2ce0e0ed79
|
|||
d69eb73a59
|
|||
aa8f415b98
|
|||
ec792f1fe2
|
|||
4c31568329
|
|||
e9dd70c6c4
|
|||
4e9d25143e
|
|||
92fe4bdd81
|
|||
0b21c57ee5
|
|||
c412a75f91
|
|||
0cc4d5096b
|
|||
34bd348f25
|
|||
d251d9d03f | |||
8f88d9028e | |||
fcdc26c1f7 | |||
fc588f10bc | |||
527e1708ce | |||
1286c4cd90 | |||
0d8c65e44b | |||
27356b7826 | |||
d06b6d3270 | |||
f9476d8c57 | |||
79f2faf55b | |||
2d0245f2ac | |||
79e55140e3 | |||
ae7f39d0de | |||
be72d2dc06 | |||
a8e4dd08bb | |||
c2e31827d8 | |||
7087ce7ec5 | |||
36bb7b7a88 | |||
2080d1f2b7 | |||
b05a6a14e8 | |||
c4225f7bdf | |||
76b3d30db9 | |||
e89e984ccb | |||
dd1ffe0d17 | |||
3feb4e72aa | |||
a43fac0c2d | |||
67a3527e29 | |||
f4a96e0b2e | |||
7e69b8f82a | |||
8258d40115 | |||
568dffbca1 | |||
9a82d812d6 | |||
49ee634822 | |||
babf792c30 | |||
65f9a805e2 | |||
6e077acc66 | |||
5af9c9b0a2 | |||
201ace7eec | |||
40f46312f8 | |||
a53d41008c | |||
8a6910bf04 | |||
1d7a9edd46 | |||
58477bae6a | |||
cbc6238d9d | |||
9f393754f6 | |||
fc43512c75 | |||
551853c5d6 | |||
6b4faf9f78 | |||
4a6cf4f2e5 | |||
b008b8089c | |||
2f33ea4dfd | |||
87540ab0b9 | |||
88a3b0912b | |||
7ec85e67df | |||
67692f2cef | |||
cc81facf50 | |||
95cc190b54 | |||
1c842ef3d1 | |||
27ad61fa17 | |||
45d34c688f | |||
1ff62e22bf | |||
2c02da7eaf | |||
8ef7a25728 | |||
b4cc1d9e66 | |||
793ccfd5ba | |||
66362ed387 | |||
11e7d8c2dd | |||
e1e9ce050d | |||
92610b6678 | |||
15a9a21448 | |||
d4c4016c7c | |||
19055409cd | |||
839dfb74b2 | |||
0bfb45020f | |||
9e746c52bc | |||
3740b65263 | |||
77e51a6f2c | |||
42b8b6895f | |||
9da2650486 | |||
e01f488768 |
@@ -24,20 +24,6 @@ RUN apt-get -y install --no-install-recommends \
|
||||
file \
|
||||
python3-dev
|
||||
|
||||
# Required packages for building gcc & binutils
|
||||
RUN <<EOF
|
||||
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb -O /tmp/autoconf.deb
|
||||
sudo dpkg --force-all -i /tmp/autoconf.deb
|
||||
EOF
|
||||
|
||||
# Required packages for building gcc & binutils
|
||||
RUN <<EOF
|
||||
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz -O /tmp/automake.tar.gz
|
||||
tar -xzf /tmp/automake.tar.gz -C /tmp
|
||||
cd /tmp/automake-1.15.1
|
||||
./configure && make && sudo make install
|
||||
EOF
|
||||
|
||||
# Required packages for building qemu
|
||||
RUN apt-get -y install --no-install-recommends \
|
||||
git \
|
||||
@@ -80,9 +66,11 @@ RUN apt-get -y install --no-install-recommends \
|
||||
|
||||
# Required packages for building test apps in userspace
|
||||
RUN apt-get -y install --no-install-recommends \
|
||||
mingw-w64
|
||||
mingw-w64 \
|
||||
libtool \
|
||||
libltdl-dev
|
||||
|
||||
# Required packages for building the OS
|
||||
# Required packages for building the OS and misc
|
||||
RUN apt-get -y install --no-install-recommends \
|
||||
grub2-common \
|
||||
xorriso \
|
||||
@@ -93,7 +81,15 @@ RUN apt-get -y install --no-install-recommends \
|
||||
grub-gfxpayload-lists \
|
||||
grub-pc-bin \
|
||||
grub-pc \
|
||||
grub2-common
|
||||
grub2-common \
|
||||
pip \
|
||||
cmake
|
||||
|
||||
# Install git-cliff
|
||||
RUN pip install git-cliff --break-system-packages
|
||||
|
||||
# Install meson
|
||||
RUN pip install meson --break-system-packages
|
||||
|
||||
# Configure git
|
||||
RUN <<EOF
|
||||
@@ -110,3 +106,22 @@ ENV NO_AT_BRIDGE=1
|
||||
RUN <<EOF
|
||||
echo PATH=$PATH:/workspaces/Fennix/cross/bin >> /etc/profile
|
||||
EOF
|
||||
|
||||
ENV CHMOD_KVM=1
|
||||
|
||||
# Remove autoconf & automake
|
||||
RUN sudo apt-get -y remove autoconf automake
|
||||
|
||||
# Required packages for building gcc & binutils
|
||||
RUN <<EOF
|
||||
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb -O /tmp/autoconf.deb
|
||||
sudo dpkg --force-all -i /tmp/autoconf.deb
|
||||
EOF
|
||||
|
||||
# Required packages for building gcc & binutils
|
||||
RUN <<EOF
|
||||
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz -O /tmp/automake.tar.gz
|
||||
tar -xzf /tmp/automake.tar.gz -C /tmp
|
||||
cd /tmp/automake-1.15.1
|
||||
./configure && make && sudo make install
|
||||
EOF
|
||||
|
@@ -25,27 +25,21 @@
|
||||
}
|
||||
},
|
||||
// From this line below are for qemu, so not that important.
|
||||
"initializeCommand": "[ -x \"$(command -v xhost)\" ] && xhost +local:docker || true", // "xhost -local:docker" to disable
|
||||
"mounts": [
|
||||
"source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached",
|
||||
"source=${localEnv:XAUTHORITY},target=/home/vscode/.Xauthority,type=bind,consistency=cached",
|
||||
"source=/dev/kvm,target=/dev/kvm,type=bind,consistency=cached",
|
||||
"source=/run/user/1000/pulse/native,target=/run/user/1000/pulse/native,type=bind,consistency=cached"
|
||||
{
|
||||
"source": "/tmp/.X11-unix",
|
||||
"target": "/tmp/.X11-unix",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"source": "/run/user/1000/pulse/native",
|
||||
"target": "/run/user/1000/pulse/native",
|
||||
"type": "bind"
|
||||
}
|
||||
],
|
||||
"runArgs": [
|
||||
"--privileged"
|
||||
"--privileged",
|
||||
"--network=host"
|
||||
]
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "gcc -v",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
|
@@ -19,3 +19,8 @@ indent_size = 2
|
||||
[{CMakeLists.txt,*.cmake}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = false
|
||||
|
325
.github/workflows/makefile.yml
vendored
325
.github/workflows/makefile.yml
vendored
@@ -22,53 +22,19 @@ jobs:
|
||||
path: tools/cross
|
||||
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
|
||||
|
||||
- name: Update System
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
run: sudo apt update
|
||||
|
||||
- name: Install GCC Dependencies
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
run: sudo apt --no-install-recommends -y install build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo libzstd-dev libisl-dev m4 automake gettext gperf dejagnu guile-3.0 guile-3.0-dev expect tcl autogen tex-common sphinx-common git ssh diffutils patch autoconf2.69 libtool wget dpkg
|
||||
|
||||
- name: Check autoconf
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
- name: Prepare Environment for Dev Container
|
||||
run: |
|
||||
if [ "$(autoconf --version | head -n 1 | awk '{print $NF}')" != "2.69" ]; then
|
||||
echo "Autoconf version is not 2.69, performing additional steps..."
|
||||
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb
|
||||
sudo dpkg --force-all -i ./autoconf_2.69-11.1_all.deb
|
||||
fi
|
||||
sudo mkdir -p /tmp/.X11-unix
|
||||
sudo mkdir -p /run/user/1000/pulse
|
||||
sudo touch /run/user/1000/pulse/native
|
||||
|
||||
- name: Check automake
|
||||
- name: Run make ci-setup in dev container
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
if [ "$(automake --version | head -n 1 | awk '{print $NF}')" != "1.15.1" ]; then
|
||||
echo "Automake version is not 1.15.1, performing additional steps..."
|
||||
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz
|
||||
tar -xzf automake-1.15.1.tar.gz
|
||||
cd automake-1.15.1
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
fi
|
||||
|
||||
- name: Clone All
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
run: make --quiet -C tools __clone_all_no_qemu
|
||||
|
||||
- name: Compile Binutils
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
run: make --quiet -C tools do_binutils
|
||||
|
||||
- name: Compile GCC
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
run: make --quiet -C tools do_gcc
|
||||
|
||||
- name: Clean Up
|
||||
if: steps.cache-cross.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd tools
|
||||
rm -rf binutils-gdb gcc
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: |
|
||||
/usr/bin/make ci-setup
|
||||
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
@@ -145,47 +111,15 @@ jobs:
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
deploydoc:
|
||||
name: Deploy Documentation to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Update System
|
||||
run: sudo apt update
|
||||
|
||||
- name: Install Doxygen
|
||||
run: sudo apt --no-install-recommends -y install doxygen make
|
||||
|
||||
- name: Generate Documentation
|
||||
run: make doxygen
|
||||
|
||||
- name: Copy GitHub Pages Website
|
||||
run: cp -r tools/website/* doxygen-doc/
|
||||
|
||||
- name: Deploy documentation
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: doxygen-doc
|
||||
|
||||
compile_amd64:
|
||||
name: Build amd64
|
||||
compile:
|
||||
name: Build OS
|
||||
runs-on: ubuntu-latest
|
||||
needs: [buildcompiler]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Update & Install Required Packages
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
|
||||
make --quiet -C tools do_limine
|
||||
make --quiet prepare
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache cross Folder
|
||||
id: cache-cross
|
||||
@@ -194,167 +128,98 @@ jobs:
|
||||
path: tools/cross
|
||||
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
|
||||
|
||||
- name: Configure config.mk
|
||||
run: sed -i 's/.*OSARCH = .*/OSARCH = amd64/' ./config.mk && cat config.mk | grep OSARCH
|
||||
|
||||
- name: Compile Debug and Release ISO
|
||||
- name: Prepare Environment for Dev Container
|
||||
run: |
|
||||
make build
|
||||
mv Fennix.iso Fennix-debug.iso
|
||||
make clean
|
||||
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
|
||||
make build
|
||||
mv Fennix.iso Fennix-release.iso
|
||||
sudo mkdir -p /tmp/.X11-unix
|
||||
sudo mkdir -p /run/user/1000/pulse
|
||||
sudo touch /run/user/1000/pulse/native
|
||||
|
||||
- name: Upload Artifact (Fennix-debug.iso)
|
||||
- name: Build AMD64 Debug
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-amd64-debug
|
||||
|
||||
- name: Build AMD64 Release
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-amd64-release
|
||||
|
||||
- name: Build i386 Debug
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-i386-debug
|
||||
|
||||
- name: Build i386 Release
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-i386-release
|
||||
|
||||
- name: Build ARM Debug
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-arm-debug
|
||||
|
||||
- name: Build ARM Release
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-arm-release
|
||||
|
||||
- name: Build AArch64 Debug
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-aarch64-debug
|
||||
|
||||
- name: Build AArch64 Release
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-aarch64-release
|
||||
|
||||
- name: Build Prepare Archive
|
||||
if: always()
|
||||
uses: devcontainers/ci@v0.3
|
||||
with:
|
||||
push: never
|
||||
runCmd: /usr/bin/make __ci-prepare-archive
|
||||
|
||||
- name: Upload Artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-amd64-debug
|
||||
path: Fennix-debug.iso
|
||||
name: artifacts
|
||||
path: artifacts/
|
||||
|
||||
- name: Upload Artifact (Fennix-release.iso)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-amd64-release
|
||||
path: Fennix-release.iso
|
||||
|
||||
compile_i386:
|
||||
name: Build i386
|
||||
nightly:
|
||||
if: always()
|
||||
name: Upload Nightly Build to GitHub Releases
|
||||
runs-on: ubuntu-latest
|
||||
needs: [buildcompiler]
|
||||
needs: [compile]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Update & Install Required Packages
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
|
||||
make --quiet -C tools do_limine
|
||||
make --quiet prepare
|
||||
- name: Download All Builds
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Cache cross Folder
|
||||
id: cache-cross
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: tools/cross
|
||||
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
|
||||
- name: Update Nightly
|
||||
run: gh release upload nightly artifacts/* -R ${{github.repository}} --clobber
|
||||
|
||||
- name: Configure config.mk
|
||||
run: sed -i 's/.*OSARCH = .*/OSARCH = i386/' ./config.mk && cat config.mk | grep OSARCH
|
||||
|
||||
- name: Compile Debug and Release ISO
|
||||
run: |
|
||||
make build
|
||||
mv Fennix.iso Fennix-debug.iso
|
||||
make clean
|
||||
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
|
||||
make build
|
||||
mv Fennix.iso Fennix-release.iso
|
||||
|
||||
- name: Upload Artifact (Fennix-debug.iso)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-i386-debug
|
||||
path: Fennix-debug.iso
|
||||
|
||||
- name: Upload Artifact (Fennix-release.iso)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-i386-release
|
||||
path: Fennix-release.iso
|
||||
|
||||
compile_aarch64:
|
||||
name: Build aarch64
|
||||
runs-on: ubuntu-latest
|
||||
needs: [buildcompiler]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Update & Install Required Packages
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
|
||||
make --quiet -C tools do_limine
|
||||
make --quiet prepare
|
||||
|
||||
- name: Cache cross Folder
|
||||
id: cache-cross
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: tools/cross
|
||||
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
|
||||
|
||||
- name: Configure config.mk
|
||||
run: sed -i 's/.*OSARCH = .*/OSARCH = aarch64/' ./config.mk && cat config.mk | grep OSARCH
|
||||
|
||||
- name: Compile Debug and Release ISO
|
||||
run: |
|
||||
make build
|
||||
mv Fennix.iso Fennix-debug.iso
|
||||
make clean
|
||||
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
|
||||
make build
|
||||
mv Fennix.iso Fennix-release.iso
|
||||
|
||||
- name: Upload Artifact (Fennix-debug.iso)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-aarch64-debug
|
||||
path: Fennix-debug.iso
|
||||
|
||||
- name: Upload Artifact (Fennix-release.iso)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-aarch64-release
|
||||
path: Fennix-release.iso
|
||||
|
||||
compile_arm:
|
||||
name: Build arm
|
||||
runs-on: ubuntu-latest
|
||||
needs: [buildcompiler]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Update & Install Required Packages
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt --no-install-recommends -y install rustc xorriso mtools genisoimage ovmf nasm doxygen make meson gcc-10 g++-10 gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 mingw-w64
|
||||
make --quiet -C tools do_limine
|
||||
make --quiet prepare
|
||||
|
||||
- name: Cache cross Folder
|
||||
id: cache-cross
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: tools/cross
|
||||
key: ${{ runner.os }}-cross-${{ hashFiles('tools/Makefile') }}
|
||||
|
||||
- name: Configure config.mk
|
||||
run: sed -i 's/.*OSARCH = .*/OSARCH = arm/' ./config.mk && cat config.mk | grep OSARCH
|
||||
|
||||
- name: Compile Debug and Release ISO
|
||||
run: |
|
||||
make build
|
||||
mv Fennix.iso Fennix-debug.iso
|
||||
make clean
|
||||
sed -i 's/.*DEBUG = .*/DEBUG = 0/' ./config.mk && cat config.mk | grep DEBUG
|
||||
make build
|
||||
mv Fennix.iso Fennix-release.iso
|
||||
|
||||
- name: Upload Artifact (Fennix-debug.iso)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-arm-debug
|
||||
path: Fennix-debug.iso
|
||||
|
||||
- name: Upload Artifact (Fennix-release.iso)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Fennix-arm-release
|
||||
path: Fennix-release.iso
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
33
.github/workflows/website.yml
vendored
Normal file
33
.github/workflows/website.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Deploy Website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- tools/website/**
|
||||
- Kernel/include/interface/**
|
||||
- Doxyfile
|
||||
|
||||
jobs:
|
||||
deploydoc:
|
||||
name: Deploy Website to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code 🛎️
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Doxygen 📦
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt --no-install-recommends -y install doxygen make
|
||||
|
||||
- name: Generate Documentation 📚
|
||||
run: make doxygen
|
||||
|
||||
- name: Copy GitHub Pages Website 📁
|
||||
run: cp -r tools/website/* doxygen-doc/
|
||||
|
||||
- name: Deploy documentation 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: doxygen-doc
|
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,9 +1,10 @@
|
||||
iso_tmp_data
|
||||
initrd_tmp_data
|
||||
initrd/usr/include/*
|
||||
!initrd/usr/include/.gitkeep
|
||||
artifacts
|
||||
tmp_rootfs
|
||||
rootfs/usr/include/*
|
||||
!rootfs/usr/include/.gitkeep
|
||||
doxygen-doc
|
||||
initrd.tar
|
||||
rootfs.tar.gz
|
||||
.dccache
|
||||
*.log
|
||||
*.log.*
|
||||
|
16
.vscode/launch.json
vendored
16
.vscode/launch.json
vendored
@@ -19,12 +19,12 @@
|
||||
"description": "Make breakpoint pending on future shared library load."
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
|
||||
"description": "/bin/utest (0x00400000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
|
||||
"description": "/bin/libc_test (0x00600000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
@@ -52,12 +52,12 @@
|
||||
"description": "Make breakpoint pending on future shared library load."
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
|
||||
"description": "/bin/utest (0x00400000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
|
||||
"description": "/bin/libc_test (0x00600000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
@@ -85,12 +85,12 @@
|
||||
"description": "Make breakpoint pending on future shared library load."
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
|
||||
"description": "/bin/utest (0x00400000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
|
||||
"description": "/bin/libc_test (0x00600000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
@@ -118,12 +118,12 @@
|
||||
"description": "Make breakpoint pending on future shared library load."
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/utest",
|
||||
"description": "/bin/utest (0x00400000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/libc_test",
|
||||
"text": "add-symbol-file ${workspaceFolder}/../tmp_rootfs/bin/libc_test",
|
||||
"description": "/bin/libc_test (0x00600000)",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -16,5 +16,6 @@
|
||||
"**/tools/qemu/**": true,
|
||||
"**/tools/cross/**": true,
|
||||
"**/doxygen-doc/**": true,
|
||||
}
|
||||
}
|
||||
},
|
||||
"cmake.ignoreCMakeListsMissing": true
|
||||
}
|
||||
|
325
.vscode/tasks.json
vendored
325
.vscode/tasks.json
vendored
@@ -1,11 +1,87 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Clean",
|
||||
"type": "shell",
|
||||
"command": "make clean",
|
||||
"isBackground": false,
|
||||
"hide": false,
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build",
|
||||
"type": "shell",
|
||||
"command": "make build",
|
||||
"isBackground": false,
|
||||
"hide": false,
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run",
|
||||
"type": "shell",
|
||||
"command": "make qemu",
|
||||
"isBackground": false,
|
||||
"hide": false,
|
||||
"dependsOn": [
|
||||
"Build"
|
||||
],
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build Bootloader",
|
||||
"type": "shell",
|
||||
"command": "make -C ../ build_bootloader",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
@@ -28,6 +104,7 @@
|
||||
"type": "shell",
|
||||
"command": "make -C ../ build_kernel",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"Build Bootloader"
|
||||
],
|
||||
@@ -53,6 +130,7 @@
|
||||
"type": "shell",
|
||||
"command": "make -C ../ build_drivers",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"Build Kernel"
|
||||
],
|
||||
@@ -78,6 +156,7 @@
|
||||
"type": "shell",
|
||||
"command": "make -C ../ build_userspace",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"Build Drivers"
|
||||
],
|
||||
@@ -103,6 +182,7 @@
|
||||
"type": "shell",
|
||||
"command": "make -C ../ build_image",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"Build Userspace"
|
||||
],
|
||||
@@ -147,7 +227,7 @@
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": ".",
|
||||
"endsPattern": "CR0 update",
|
||||
"endsPattern": "CPU Reset",
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -170,6 +250,249 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI AMD64 Debug",
|
||||
"type": "shell",
|
||||
"command": "make __ci-amd64-debug",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"Clean"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI AMD64 Release",
|
||||
"type": "shell",
|
||||
"command": "make __ci-amd64-release",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"CI AMD64 Debug"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI i386 Debug",
|
||||
"type": "shell",
|
||||
"command": "make __ci-i386-debug",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"CI AMD64 Release"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI i386 Release",
|
||||
"type": "shell",
|
||||
"command": "make __ci-i386-release",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"CI i386 Debug"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI ARM Debug",
|
||||
"type": "shell",
|
||||
"command": "make __ci-arm-debug",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"CI i386 Release"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI ARM Release",
|
||||
"type": "shell",
|
||||
"command": "make __ci-arm-release",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"CI ARM Debug"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI AARCH64 Debug",
|
||||
"type": "shell",
|
||||
"command": "make __ci-aarch64-debug",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"CI ARM Release"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "CI AARCH64 Release",
|
||||
"type": "shell",
|
||||
"command": "make __ci-aarch64-release",
|
||||
"isBackground": false,
|
||||
"hide": true,
|
||||
"dependsOn": [
|
||||
"CI AARCH64 Debug"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Test CI Build",
|
||||
"type": "shell",
|
||||
"command": "make __ci-restore-config",
|
||||
"isBackground": false,
|
||||
"dependsOn": [
|
||||
"CI AARCH64 Release",
|
||||
"clean"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../",
|
||||
"shell": {
|
||||
"executable": "bash",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
1883
CHANGELOG.md
Normal file
1883
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,8 @@ Follow the coding style used in the repository to ensure consistency. Adhere to:
|
||||
- Start function and global declaration names with an uppercase letter.
|
||||
- Start local variable names with a lowercase letter.
|
||||
- Maintain consistent formatting and commenting guidelines.
|
||||
- Commit messages must follow [Conventional Commits](https://conventionalcommits.org).
|
||||
- Release versions must follow [Semantic Versioning](https://semver.org).
|
||||
|
||||
Refer to the [style guide document](STYLE_GUIDE.md) if available.
|
||||
|
||||
|
15
CREDITS.md
15
CREDITS.md
@@ -27,6 +27,9 @@ License information can be found in the [LICENSES.md](LICENSES.md) file.
|
||||
## CPUID 0x7
|
||||
- [CPUID](https://en.wikipedia.org/wiki/CPUID)
|
||||
|
||||
## KVM CPUID
|
||||
- [kernel.org KVM CPUID](https://www.kernel.org/doc/html/v6.9/virt/kvm/x86/cpuid.html?highlight=cpuid)
|
||||
|
||||
## Network
|
||||
- [Beej's Guide to Network Programming](https://web.archive.org/web/20051210132103/http://users.pcnet.ro/dmoroian/beej/Beej.html)
|
||||
- [UDP Socket Programming](https://web.archive.org/web/20060229214053/http://www.cs.rutgers.edu/~pxk/417/notes/sockets/udp.html)
|
||||
@@ -120,6 +123,18 @@ License information can be found in the [LICENSES.md](LICENSES.md) file.
|
||||
## UART
|
||||
- [Interfacing the Serial / RS232 Port V5.0](http://www.senet.com.au/~cpeacock)
|
||||
|
||||
## UEFI
|
||||
- [U-Boot EFI Commands](https://docs.u-boot.org/en/latest/usage/cmd/efi.html)
|
||||
- [UEFI Specification 2.10](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf)
|
||||
- [UEFI Boot Process Overview](https://gist.github.com/Velocet/d394281d96191e235ff46a8aa2018d80)
|
||||
- [Rust OS Development: UEFI](https://blog.malware.re/2023/09/01/rust-os-part2/index.html)
|
||||
- [GUIDs Database](https://github.com/DSecurity/efiSeek/blob/master/data/guids-db.ini)
|
||||
|
||||
## BGRT
|
||||
- [BGRT on OSDev](https://wiki.osdev.org/BGRT)
|
||||
- [BMP File Structure @ Gdansk University of Technology](http://www.ue.eti.pg.gda.pl/fpgalab/zadania.spartan3/zad_vga_struktura_pliku_bmp_en.html)
|
||||
- [BGRT @ Purdue University](https://engineering.purdue.edu/ece264/16au/hw/HW13)
|
||||
|
||||
---
|
||||
|
||||
Special thanks to all contributors and the creators of the referenced projects and resources!
|
||||
|
@@ -43,30 +43,47 @@ endif
|
||||
export DRIVER_LDFLAGS
|
||||
export DRIVER_CFLAGS
|
||||
|
||||
copy_driver_signatures:
|
||||
@TMP_FILE="$(OUTPUT_DIR)../../Kernel/drivers/trusted.c.tmp"; \
|
||||
OUT_FILE="$(OUTPUT_DIR)../../Kernel/drivers/trusted.c"; \
|
||||
mkdir -p $(OUTPUT_DIR)../../Kernel/drivers/; \
|
||||
echo "const char *trusted_drivers[] = {" > $$TMP_FILE; \
|
||||
find $(OUTPUT_DIR) -name "*.drv" -exec sha512sum {} \; | awk '{gsub(/.*\//, "", $$2); gsub(/\./, "_", $$2); sub(/_drv$$/, "_drv", $$2); print "\"" $$1 "\"," }' >> $$TMP_FILE; \
|
||||
echo "};" >> $$TMP_FILE; \
|
||||
echo "const __SIZE_TYPE__ trusted_drivers_count = sizeof(trusted_drivers) / sizeof(trusted_drivers[0]);" >> $$TMP_FILE; \
|
||||
if [ ! -f $$OUT_FILE ] || ! cmp -s $$TMP_FILE $$OUT_FILE; then \
|
||||
mv $$TMP_FILE $$OUT_FILE; \
|
||||
printf '\033[0;32m[trusted.c updated]\033[0m\n'; \
|
||||
else \
|
||||
rm $$TMP_FILE; \
|
||||
printf '\033[0;33m[trusted.c unchanged]\033[0m\n'; \
|
||||
fi
|
||||
|
||||
build:
|
||||
cp -rf ../Kernel/include/interface/* include/
|
||||
mkdir -p out
|
||||
make -C library build
|
||||
$(MAKE) -C library build
|
||||
ifneq ($(filter amd64 i386,$(OSARCH)),)
|
||||
make -C audio build
|
||||
make -C input build
|
||||
make -C misc build
|
||||
make -C network build
|
||||
make -C storage build
|
||||
make -C filesystem build
|
||||
$(MAKE) -C audio build
|
||||
$(MAKE) -C input build
|
||||
$(MAKE) -C misc build
|
||||
$(MAKE) -C network build
|
||||
$(MAKE) -C storage build
|
||||
$(MAKE) -C filesystem build
|
||||
endif
|
||||
$(MAKE) copy_driver_signatures
|
||||
|
||||
prepare:
|
||||
$(info Nothing to prepare)
|
||||
|
||||
clean:
|
||||
rm -rf out
|
||||
make -C library clean
|
||||
$(MAKE) -C library clean
|
||||
ifneq ($(filter amd64 i386,$(OSARCH)),)
|
||||
make -C audio clean
|
||||
make -C input clean
|
||||
make -C misc clean
|
||||
make -C network clean
|
||||
make -C storage clean
|
||||
make -C filesystem clean
|
||||
$(MAKE) -C audio clean
|
||||
$(MAKE) -C input clean
|
||||
$(MAKE) -C misc clean
|
||||
$(MAKE) -C network clean
|
||||
$(MAKE) -C storage clean
|
||||
$(MAKE) -C filesystem clean
|
||||
endif
|
||||
|
110
Drivers/include/block.h
Normal file
110
Drivers/include/block.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_API_BLOCK_H__
|
||||
#define __FENNIX_API_BLOCK_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#if __has_include(<interface/fs.h>)
|
||||
#include <interface/fs.h>
|
||||
#else
|
||||
#include <fs.h>
|
||||
#endif
|
||||
|
||||
struct BlockDevice
|
||||
{
|
||||
/**
|
||||
* @brief Base name of the device.
|
||||
*
|
||||
* This name is used to identify the device in the system. It should be unique
|
||||
* across all block devices. The kernel may append a number to this name to
|
||||
* create a unique device name (e.g., "ahci0", "ahci1").
|
||||
*/
|
||||
const char *Name;
|
||||
|
||||
/**
|
||||
* @brief Total size of the device in bytes.
|
||||
*
|
||||
* This value represents the total addressable storage capacity of the device.
|
||||
* It is used for bounds checking and partitioning.
|
||||
*/
|
||||
size_t Size;
|
||||
|
||||
/**
|
||||
* @brief Size of a single block in bytes.
|
||||
*
|
||||
* All read and write operations are performed in multiples of this block size.
|
||||
* Typical values are 512 or 4096 bytes.
|
||||
*/
|
||||
uint32_t BlockSize;
|
||||
|
||||
/**
|
||||
* @brief Number of blocks in the device.
|
||||
*
|
||||
* This value is calculated as Size / BlockSize. It represents the total number
|
||||
* of addressable blocks on the device.
|
||||
*/
|
||||
size_t BlockCount;
|
||||
|
||||
/**
|
||||
* @brief Pointer to the block device operations structure.
|
||||
*
|
||||
* This structure contains function pointers for various operations that can
|
||||
* be performed on the block device, such as read, write, and ioctl.
|
||||
*
|
||||
* Yea, inode operations are used for block devices too.
|
||||
*/
|
||||
const InodeOperations *Ops;
|
||||
|
||||
/**
|
||||
* @brief Opaque pointer to driver-specific or hardware-specific data.
|
||||
*
|
||||
* This field allows the driver to associate private context or state with the
|
||||
* device, such as controller registers or internal buffers.
|
||||
*/
|
||||
void *PrivateData;
|
||||
};
|
||||
|
||||
#ifndef __kernel__
|
||||
/**
|
||||
* @brief Registers a block device with the kernel block subsystem.
|
||||
*
|
||||
* This function should be called by block device drivers after initializing
|
||||
* a device. The kernel will take ownership of the device structure and assign
|
||||
* it a unique device ID. The device will then be accessible for filesystem
|
||||
* mounting and I/O operations.
|
||||
*
|
||||
* @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device.
|
||||
* @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure.
|
||||
*/
|
||||
dev_t RegisterBlockDevice(struct BlockDevice *Device);
|
||||
|
||||
/**
|
||||
* @brief Unregisters a block device from the kernel block subsystem.
|
||||
*
|
||||
* This function should be called by drivers when a device is being removed
|
||||
* or is no longer available. The kernel will release any resources associated
|
||||
* with the device and invalidate its device ID.
|
||||
*
|
||||
* @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice().
|
||||
* @return 0 on success, or an error code.
|
||||
*/
|
||||
int UnregisterBlockDevice(dev_t DeviceID);
|
||||
#endif // __kernel__
|
||||
|
||||
#endif // __FENNIX_API_BLOCK_H__
|
File diff suppressed because it is too large
Load Diff
109
Drivers/include/fcntl.h
Normal file
109
Drivers/include/fcntl.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_API_FCNTL_H__
|
||||
#define __FENNIX_API_FCNTL_H__
|
||||
|
||||
#ifdef __kernel__
|
||||
#include <types.h>
|
||||
#endif
|
||||
|
||||
/* cmd */
|
||||
#define F_DUPFD 0x1
|
||||
#define F_DUPFD_CLOEXEC 0x101
|
||||
#define F_DUPFD_CLOFORK 0x201
|
||||
#define F_GETFD 0x2
|
||||
#define F_SETFD 0x3
|
||||
#define F_GETFL 0x4
|
||||
#define F_SETFL 0x5
|
||||
#define F_GETLK 0x6
|
||||
#define F_SETLK 0x7
|
||||
#define F_SETLKW 0x8
|
||||
#define F_OFD_GETLK 0x9
|
||||
#define F_OFD_SETLK 0xA
|
||||
#define F_OFD_SETLKW 0xB
|
||||
#define F_GETOWN 0xC
|
||||
#define F_GETOWN_EX 0xD
|
||||
#define F_SETOWN 0xE
|
||||
#define F_SETOWN_EX 0xF
|
||||
|
||||
#define FD_CLOEXEC 0x1
|
||||
#define FD_CLOFORK 0x2
|
||||
|
||||
/* l_type */
|
||||
#define F_RDLCK 0x1
|
||||
#define F_UNLCK 0x2
|
||||
#define F_WRLCK 0x3
|
||||
|
||||
/* type */
|
||||
#define F_OWNER_PID 0
|
||||
#define F_OWNER_PGRP 1
|
||||
|
||||
/* oflag */
|
||||
#define O_CLOEXEC 02000000
|
||||
#define O_CLOFORK 04000000
|
||||
#define O_CREAT 0x8
|
||||
#define O_DIRECTORY 0200000
|
||||
#define O_EXCL 0x20
|
||||
#define O_NOCTTY 0x40
|
||||
#define O_NOFOLLOW 0400000
|
||||
#define O_TRUNC 0x400
|
||||
#define O_TTY_INIT 0x800
|
||||
|
||||
#define O_APPEND 0x4
|
||||
#define O_DSYNC 0x10
|
||||
#define O_NONBLOCK 0x80
|
||||
#define O_RSYNC 0x100
|
||||
#define O_SYNC 0x200
|
||||
|
||||
#define O_ACCMODE 0x3
|
||||
|
||||
#define O_EXEC 0x4
|
||||
#define O_RDONLY 0x1
|
||||
#define O_RDWR 0x3
|
||||
#define O_SEARCH 0x10
|
||||
#define O_WRONLY 0x2
|
||||
|
||||
#define AT_FDCWD
|
||||
#define AT_EACCESS
|
||||
#define AT_SYMLINK_NOFOLLOW
|
||||
#define AT_SYMLINK_FOLLOW
|
||||
#define AT_REMOVEDIR
|
||||
|
||||
#define POSIX_FADV_DONTNEED
|
||||
#define POSIX_FADV_NOREUSE
|
||||
#define POSIX_FADV_NORMAL
|
||||
#define POSIX_FADV_RANDOM
|
||||
#define POSIX_FADV_SEQUENTIAL
|
||||
#define POSIX_FADV_WILLNEED
|
||||
|
||||
typedef struct f_owner_ex
|
||||
{
|
||||
int type; /* Discriminator for pid. */
|
||||
pid_t pid; /* Process ID or process group ID. */
|
||||
} f_owner_ex;
|
||||
|
||||
typedef struct flock
|
||||
{
|
||||
short l_type; /* Type of lock; F_RDLCK, F_WRLCK, F_UNLCK. */
|
||||
short l_whence; /* Flag for starting offset. */
|
||||
off_t l_start; /* Relative offset in bytes. */
|
||||
off_t l_len; /* Size; if 0 then until EOF. */
|
||||
pid_t l_pid; /* For a process-owned file lock, ignored on input or the process ID of the owning process on output; for an OFD-owned file lock, zero on input or (pid_t)-1 on output. */
|
||||
} flock;
|
||||
|
||||
#endif // !__FENNIX_API_FCNTL_H__
|
@@ -95,16 +95,6 @@
|
||||
/** Other: X */
|
||||
#define S_IXOTH 0001
|
||||
|
||||
#define O_RDONLY 00
|
||||
#define O_WRONLY 01
|
||||
#define O_RDWR 02
|
||||
#define O_CREAT 0100
|
||||
#define O_EXCL 0200
|
||||
#define O_TRUNC 01000
|
||||
#define O_APPEND 02000
|
||||
#define O_NOFOLLOW 0400000
|
||||
#define O_CLOEXEC 02000000
|
||||
|
||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
|
||||
@@ -332,11 +322,29 @@ struct InodeOperations
|
||||
int (*Stat)(struct Inode *Node, struct kstat *Stat);
|
||||
} __attribute__((packed));
|
||||
|
||||
#define I_FLAG_ROOT 0x1
|
||||
#define I_FLAG_MOUNTPOINT 0x2
|
||||
#define I_FLAG_CACHE_KEEP 0x4
|
||||
|
||||
struct FileSystemInfo;
|
||||
|
||||
struct FileSystemDevice
|
||||
{
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* @brief Inode
|
||||
*
|
||||
* If the device is a block device, this will be NULL.
|
||||
*/
|
||||
struct Inode *node;
|
||||
struct InodeOperations *ops;
|
||||
} inode;
|
||||
|
||||
/**
|
||||
* @brief Block Device
|
||||
*
|
||||
* If the device is a block device, this will be non-NULL.
|
||||
*/
|
||||
struct BlockDevice *Block;
|
||||
};
|
||||
|
||||
struct SuperBlockOperations
|
||||
{
|
||||
int (*AllocateInode)(struct FileSystemInfo *Info, struct Inode **Result);
|
||||
@@ -347,8 +355,8 @@ struct SuperBlockOperations
|
||||
*
|
||||
* Write all pending changes to the disk.
|
||||
*
|
||||
* @param Info Inode to synchronize. If NULL, synchronize all inodes.
|
||||
* @param Node Inode to synchronize.
|
||||
* @param Info Inode to synchronize.
|
||||
* @param Node Inode to synchronize. If NULL, synchronize all inodes.
|
||||
*
|
||||
* @return Zero on success, otherwise an error code.
|
||||
*/
|
||||
@@ -364,13 +372,50 @@ struct SuperBlockOperations
|
||||
* @return Zero on success, otherwise an error code.
|
||||
*/
|
||||
int (*Destroy)(struct FileSystemInfo *Info);
|
||||
|
||||
/**
|
||||
* Probe the filesystem.
|
||||
*
|
||||
* Check if the filesystem is supported by the driver.
|
||||
*
|
||||
* @param Device Device to probe.
|
||||
*
|
||||
* @return Zero on success, otherwise an error code.
|
||||
*/
|
||||
int (*Probe)(struct FileSystemDevice *Device);
|
||||
|
||||
/**
|
||||
* Mount the filesystem.
|
||||
*
|
||||
* Mount the filesystem on the given device.
|
||||
*
|
||||
* @param FS Filesystem to mount.
|
||||
* @param Root Pointer to the root inode.
|
||||
* @param Device Device to mount. This pointer will be undefined after the function returns!
|
||||
*
|
||||
* @return Zero on success, otherwise an error code.
|
||||
*/
|
||||
int (*Mount)(struct FileSystemInfo *FS, struct Inode **Root, struct FileSystemDevice *Device);
|
||||
|
||||
/**
|
||||
* Unmount the filesystem.
|
||||
*
|
||||
* Unmount the filesystem from the given device.
|
||||
*
|
||||
* @param FS Filesystem to unmount.
|
||||
*
|
||||
* @return Zero on success, otherwise an error code.
|
||||
*/
|
||||
int (*Unmount)(struct FileSystemInfo *FS);
|
||||
} __attribute__((packed));
|
||||
|
||||
struct FileSystemInfo
|
||||
{
|
||||
const char *Name;
|
||||
const char *RootName;
|
||||
|
||||
int Flags;
|
||||
int Capabilities;
|
||||
|
||||
struct SuperBlockOperations SuperOps;
|
||||
struct InodeOperations Ops;
|
||||
|
||||
@@ -378,6 +423,9 @@ struct FileSystemInfo
|
||||
} __attribute__((packed));
|
||||
|
||||
#ifndef __kernel__
|
||||
dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root);
|
||||
int UnregisterMountPoint(dev_t Device);
|
||||
|
||||
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
||||
int UnregisterFileSystem(dev_t Device);
|
||||
#endif // !__kernel__
|
||||
|
@@ -15,13 +15,44 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_API_SYSCALLS_LIST_H__
|
||||
#define __FENNIX_API_SYSCALLS_LIST_H__
|
||||
#ifndef __FENNIX_API_SYSTEM_CALLS_LIST_H__
|
||||
#define __FENNIX_API_SYSTEM_CALLS_LIST_H__
|
||||
|
||||
#if __has_include(<interface/fcntl.h>)
|
||||
#include <interface/fcntl.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifndef __fennix__
|
||||
#error "__fennix__ not defined"
|
||||
#endif
|
||||
|
||||
#pragma region Syscall Wrappers
|
||||
|
||||
#define scarg __UINTPTR_TYPE__
|
||||
|
||||
#ifdef __arm__
|
||||
#ifdef __thumb__
|
||||
#define __thumb_r7
|
||||
#define __arm_call(...)
|
||||
#warning "arm thumb code not implemented"
|
||||
#else /* __thumb__ */
|
||||
#define __thumb_r7 __asm__("r7")
|
||||
#define __arm_call(...) \
|
||||
__asm__ __volatile__("svc 0" \
|
||||
: "=r"(r0) \
|
||||
: __VA_ARGS__ \
|
||||
: "memory")
|
||||
#endif /* __thumb__ */
|
||||
|
||||
#ifdef __thumb2__
|
||||
#define __r7_operand "rI"(r7)
|
||||
#else /* __thumb2__ */
|
||||
#define __r7_operand "r"(r7)
|
||||
#endif /* __thumb2__ */
|
||||
#endif /* __arm__ */
|
||||
|
||||
/**
|
||||
* @brief Syscall wrapper with 0 arguments
|
||||
*
|
||||
@@ -39,12 +70,17 @@ static inline scarg syscall0(scarg syscall)
|
||||
: "a"(syscall)
|
||||
: "rcx", "r11", "memory");
|
||||
#elif defined(__i386__)
|
||||
#warning "i386 syscall wrapper not implemented"
|
||||
__asm__ __volatile__("int $0x30"
|
||||
: "=a"(ret)
|
||||
: "a"(syscall)
|
||||
: "memory");
|
||||
#elif defined(__arm__)
|
||||
#warning "arm syscall wrapper not implemented"
|
||||
register scarg r7 __thumb_r7 = syscall;
|
||||
register scarg r0 __asm__("r0");
|
||||
__arm_call(__r7_operand);
|
||||
#elif defined(__aarch64__)
|
||||
register long x8 __asm__("x8") = syscall;
|
||||
register long x0 __asm__("x0");
|
||||
register scarg x8 __asm__("x8") = syscall;
|
||||
register scarg x0 __asm__("x0");
|
||||
__asm__ __volatile__("svc 0"
|
||||
: "=r"(x0)
|
||||
: "r"(x8)
|
||||
@@ -73,12 +109,17 @@ static inline scarg syscall1(scarg syscall, scarg arg1)
|
||||
: "a"(syscall), "D"(arg1)
|
||||
: "rcx", "r11", "memory");
|
||||
#elif defined(__i386__)
|
||||
#warning "i386 syscall wrapper not implemented"
|
||||
__asm__ __volatile__("int $0x30"
|
||||
: "=a"(ret)
|
||||
: "a"(syscall), "b"(arg1)
|
||||
: "memory");
|
||||
#elif defined(__arm__)
|
||||
#warning "arm syscall wrapper not implemented"
|
||||
register scarg r7 __thumb_r7 = syscall;
|
||||
register scarg r0 __asm__("r0") = arg1;
|
||||
__arm_call(__r7_operand, "0"(r0));
|
||||
#elif defined(__aarch64__)
|
||||
register long x8 __asm__("x8") = syscall;
|
||||
register long x0 __asm__("x0") = arg1;
|
||||
register scarg x8 __asm__("x8") = syscall;
|
||||
register scarg x0 __asm__("x0") = arg1;
|
||||
__asm__ __volatile__("svc 0"
|
||||
: "=r"(ret)
|
||||
: "r"(x8), "0"(x0)
|
||||
@@ -108,13 +149,19 @@ static inline scarg syscall2(scarg syscall, scarg arg1, scarg arg2)
|
||||
: "a"(syscall), "D"(arg1), "S"(arg2)
|
||||
: "rcx", "r11", "memory");
|
||||
#elif defined(__i386__)
|
||||
#warning "i386 syscall wrapper not implemented"
|
||||
__asm__ __volatile__("int $0x30"
|
||||
: "=a"(ret)
|
||||
: "a"(syscall), "b"(arg1), "c"(arg2)
|
||||
: "memory");
|
||||
#elif defined(__arm__)
|
||||
#warning "arm syscall wrapper not implemented"
|
||||
register scarg r7 __thumb_r7 = syscall;
|
||||
register scarg r0 __asm__("r0") = arg1;
|
||||
register scarg r1 __asm__("r1") = arg2;
|
||||
__arm_call(__r7_operand, "0"(r0), "r"(r1));
|
||||
#elif defined(__aarch64__)
|
||||
register long x8 __asm__("x8") = syscall;
|
||||
register long x0 __asm__("x0") = arg1;
|
||||
register long x1 __asm__("x1") = arg2;
|
||||
register scarg x8 __asm__("x8") = syscall;
|
||||
register scarg x0 __asm__("x0") = arg1;
|
||||
register scarg x1 __asm__("x1") = arg2;
|
||||
__asm__ __volatile__("svc 0"
|
||||
: "=r"(ret)
|
||||
: "r"(x8), "0"(x0), "r"(x1)
|
||||
@@ -145,14 +192,21 @@ static inline scarg syscall3(scarg syscall, scarg arg1, scarg arg2, scarg arg3)
|
||||
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3)
|
||||
: "rcx", "r11", "memory");
|
||||
#elif defined(__i386__)
|
||||
#warning "i386 syscall wrapper not implemented"
|
||||
__asm__ __volatile__("int $0x30"
|
||||
: "=a"(ret)
|
||||
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3)
|
||||
: "memory");
|
||||
#elif defined(__arm__)
|
||||
#warning "arm syscall wrapper not implemented"
|
||||
register scarg r7 __thumb_r7 = syscall;
|
||||
register scarg r0 __asm__("r0") = arg1;
|
||||
register scarg r1 __asm__("r1") = arg2;
|
||||
register scarg r2 __asm__("r2") = arg3;
|
||||
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2));
|
||||
#elif defined(__aarch64__)
|
||||
register long x8 __asm__("x8") = syscall;
|
||||
register long x0 __asm__("x0") = arg1;
|
||||
register long x1 __asm__("x1") = arg2;
|
||||
register long x2 __asm__("x2") = arg3;
|
||||
register scarg x8 __asm__("x8") = syscall;
|
||||
register scarg x0 __asm__("x0") = arg1;
|
||||
register scarg x1 __asm__("x1") = arg2;
|
||||
register scarg x2 __asm__("x2") = arg3;
|
||||
__asm__ __volatile__("svc 0"
|
||||
: "=r"(ret)
|
||||
: "r"(x8), "0"(x0), "r"(x1), "r"(x2)
|
||||
@@ -185,15 +239,23 @@ static inline scarg syscall4(scarg syscall, scarg arg1, scarg arg2, scarg arg3,
|
||||
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
|
||||
: "rcx", "r11", "memory");
|
||||
#elif defined(__i386__)
|
||||
#warning "i386 syscall wrapper not implemented"
|
||||
__asm__ __volatile__("int $0x30"
|
||||
: "=a"(ret)
|
||||
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4)
|
||||
: "memory");
|
||||
#elif defined(__arm__)
|
||||
#warning "arm syscall wrapper not implemented"
|
||||
register scarg r7 __thumb_r7 = syscall;
|
||||
register scarg r0 __asm__("r0") = arg1;
|
||||
register scarg r1 __asm__("r1") = arg2;
|
||||
register scarg r2 __asm__("r2") = arg3;
|
||||
register scarg r3 __asm__("r3") = arg4;
|
||||
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2), "r"(r3));
|
||||
#elif defined(__aarch64__)
|
||||
register long x8 __asm__("x8") = syscall;
|
||||
register long x0 __asm__("x0") = arg1;
|
||||
register long x1 __asm__("x1") = arg2;
|
||||
register long x2 __asm__("x2") = arg3;
|
||||
register long x3 __asm__("x3") = arg4;
|
||||
register scarg x8 __asm__("x8") = syscall;
|
||||
register scarg x0 __asm__("x0") = arg1;
|
||||
register scarg x1 __asm__("x1") = arg2;
|
||||
register scarg x2 __asm__("x2") = arg3;
|
||||
register scarg x3 __asm__("x3") = arg4;
|
||||
__asm__ __volatile__("svc 0"
|
||||
: "=r"(ret)
|
||||
: "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3)
|
||||
@@ -228,16 +290,25 @@ static inline scarg syscall5(scarg syscall, scarg arg1, scarg arg2, scarg arg3,
|
||||
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
|
||||
: "rcx", "r11", "memory");
|
||||
#elif defined(__i386__)
|
||||
#warning "i386 syscall wrapper not implemented"
|
||||
__asm__ __volatile__("int $0x30"
|
||||
: "=a"(ret)
|
||||
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5)
|
||||
: "memory");
|
||||
#elif defined(__arm__)
|
||||
#warning "arm syscall wrapper not implemented"
|
||||
register scarg r7 __thumb_r7 = syscall;
|
||||
register scarg r0 __asm__("r0") = arg1;
|
||||
register scarg r1 __asm__("r1") = arg2;
|
||||
register scarg r2 __asm__("r2") = arg3;
|
||||
register scarg r3 __asm__("r3") = arg4;
|
||||
register scarg r4 __asm__("r4") = arg5;
|
||||
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4));
|
||||
#elif defined(__aarch64__)
|
||||
register long x8 __asm__("x8") = syscall;
|
||||
register long x0 __asm__("x0") = arg1;
|
||||
register long x1 __asm__("x1") = arg2;
|
||||
register long x2 __asm__("x2") = arg3;
|
||||
register long x3 __asm__("x3") = arg4;
|
||||
register long x4 __asm__("x4") = arg5;
|
||||
register scarg x8 __asm__("x8") = syscall;
|
||||
register scarg x0 __asm__("x0") = arg1;
|
||||
register scarg x1 __asm__("x1") = arg2;
|
||||
register scarg x2 __asm__("x2") = arg3;
|
||||
register scarg x3 __asm__("x3") = arg4;
|
||||
register scarg x4 __asm__("x4") = arg5;
|
||||
__asm__ __volatile__("svc 0"
|
||||
: "=r"(ret)
|
||||
: "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4)
|
||||
@@ -274,17 +345,27 @@ static inline scarg syscall6(scarg syscall, scarg arg1, scarg arg2, scarg arg3,
|
||||
: "a"(syscall), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9)
|
||||
: "rcx", "r11", "memory");
|
||||
#elif defined(__i386__)
|
||||
#warning "i386 syscall wrapper not implemented"
|
||||
__asm__ __volatile__("int $0x30"
|
||||
: "=a"(ret)
|
||||
: "a"(syscall), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5), "g"(arg6)
|
||||
: "memory");
|
||||
#elif defined(__arm__)
|
||||
#warning "arm syscall wrapper not implemented"
|
||||
register scarg r7 __thumb_r7 = syscall;
|
||||
register scarg r0 __asm__("r0") = arg1;
|
||||
register scarg r1 __asm__("r1") = arg2;
|
||||
register scarg r2 __asm__("r2") = arg3;
|
||||
register scarg r3 __asm__("r3") = arg4;
|
||||
register scarg r4 __asm__("r4") = arg5;
|
||||
register scarg r5 __asm__("r5") = arg6;
|
||||
__arm_call(__r7_operand, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5));
|
||||
#elif defined(__aarch64__)
|
||||
register long x8 __asm__("x8") = syscall;
|
||||
register long x0 __asm__("x0") = arg1;
|
||||
register long x1 __asm__("x1") = arg2;
|
||||
register long x2 __asm__("x2") = arg3;
|
||||
register long x3 __asm__("x3") = arg4;
|
||||
register long x4 __asm__("x4") = arg5;
|
||||
register long x5 __asm__("x5") = arg6;
|
||||
register scarg x8 __asm__("x8") = syscall;
|
||||
register scarg x0 __asm__("x0") = arg1;
|
||||
register scarg x1 __asm__("x1") = arg2;
|
||||
register scarg x2 __asm__("x2") = arg3;
|
||||
register scarg x3 __asm__("x3") = arg4;
|
||||
register scarg x4 __asm__("x4") = arg5;
|
||||
register scarg x5 __asm__("x5") = arg6;
|
||||
__asm__ __volatile__("svc 0"
|
||||
: "=r"(ret)
|
||||
: "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
|
||||
@@ -322,18 +403,18 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
__SYS_O_RDONLY = 0x1,
|
||||
__SYS_O_WRONLY = 0x2,
|
||||
__SYS_O_RDWR = 0x3,
|
||||
__SYS_O_APPEND = 0x4,
|
||||
__SYS_O_CREAT = 0x8,
|
||||
__SYS_O_DSYNC = 0x10,
|
||||
__SYS_O_EXCL = 0x20,
|
||||
__SYS_O_NOCTTY = 0x40,
|
||||
__SYS_O_NONBLOCK = 0x80,
|
||||
__SYS_O_RSYNC = 0x100,
|
||||
__SYS_O_SYNC = 0x200,
|
||||
__SYS_O_TRUNC = 0x400
|
||||
__SYS_O_RDONLY = O_RDONLY,
|
||||
__SYS_O_WRONLY = O_WRONLY,
|
||||
__SYS_O_RDWR = O_RDWR,
|
||||
__SYS_O_APPEND = O_APPEND,
|
||||
__SYS_O_CREAT = O_CREAT,
|
||||
__SYS_O_DSYNC = O_DSYNC,
|
||||
__SYS_O_EXCL = O_EXCL,
|
||||
__SYS_O_NOCTTY = O_NOCTTY,
|
||||
__SYS_O_NONBLOCK = O_NONBLOCK,
|
||||
__SYS_O_RSYNC = O_RSYNC,
|
||||
__SYS_O_SYNC = O_SYNC,
|
||||
__SYS_O_TRUNC = O_TRUNC
|
||||
} syscall_open_flags_t;
|
||||
|
||||
typedef enum
|
||||
@@ -553,6 +634,14 @@ typedef struct FramebufferScreenInfo
|
||||
*/
|
||||
#define FBIOGET_SCREEN_INFO 0xf0
|
||||
|
||||
struct kutsname
|
||||
{
|
||||
char sysname[65];
|
||||
char release[65];
|
||||
char version[65];
|
||||
char machine[65];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief List of syscalls
|
||||
*
|
||||
@@ -585,6 +674,8 @@ typedef enum
|
||||
*/
|
||||
SYS_API_VERSION = 0,
|
||||
|
||||
SYS_DEBUG_REPORT = 1,
|
||||
|
||||
/* I/O */
|
||||
|
||||
/**
|
||||
@@ -741,6 +832,25 @@ typedef enum
|
||||
* - #EINVAL if the request is invalid
|
||||
*/
|
||||
SYS_IOCTL,
|
||||
/**
|
||||
* @brief Function control
|
||||
*
|
||||
* @code
|
||||
* int fcntl(int fd, int cmd, void *arg);
|
||||
* @endcode
|
||||
*
|
||||
* @details Manipulates the underlying parameters of a device.
|
||||
*
|
||||
* @param fd File descriptor referring to the device
|
||||
* @param cmd Device-specific request code
|
||||
* @param arg Argument for the request
|
||||
*
|
||||
* @return
|
||||
* - #EOK on success
|
||||
* - #EBADF if `fd` is not valid
|
||||
* - #EINVAL if the request is invalid
|
||||
*/
|
||||
SYS_FCNTL,
|
||||
|
||||
/* File Status */
|
||||
|
||||
@@ -1530,6 +1640,22 @@ typedef enum
|
||||
* - #EACCES if permission is denied
|
||||
*/
|
||||
SYS_RENAME,
|
||||
/**
|
||||
* @brief Get unix name information
|
||||
*
|
||||
* @code
|
||||
* int uname(struct kutsname *buf);
|
||||
* @endcode
|
||||
*
|
||||
* @details Retrieves information about the operating system.
|
||||
*
|
||||
* @param buf Pointer to `kutsname` structure to store information
|
||||
*
|
||||
* @return
|
||||
* - #EOK on success
|
||||
* - #EFAULT if `buf` is outside accessible address space
|
||||
*/
|
||||
SYS_UNAME,
|
||||
|
||||
/**
|
||||
* @brief Max number of syscalls
|
||||
@@ -1573,6 +1699,9 @@ typedef enum
|
||||
/** @copydoc SYS_IOCTL */
|
||||
#define call_ioctl(fd, request, argp) syscall3(SYS_IOCTL, (scarg)fd, (scarg)request, (scarg)argp)
|
||||
|
||||
/** @copydoc SYS_FCNTL */
|
||||
#define call_fcntl(fd, cmd, arg) syscall3(SYS_FCNTL, (scarg)fd, (scarg)cmd, (scarg)arg)
|
||||
|
||||
/* File Status */
|
||||
|
||||
/** @copydoc SYS_STAT */
|
||||
@@ -1680,7 +1809,7 @@ typedef enum
|
||||
/* Time */
|
||||
|
||||
/** @copydoc SYS_TIME */
|
||||
#define call_time(t) syscall1(SYS_TIME, t)
|
||||
#define call_time(t) syscall1(SYS_TIME, (scarg)t)
|
||||
|
||||
/** @copydoc SYS_CLOCK_GETTIME */
|
||||
#define call_clock_gettime(clockid, tp) syscall2(SYS_CLOCK_GETTIME, (scarg)clockid, (scarg)tp)
|
||||
@@ -1711,4 +1840,7 @@ typedef enum
|
||||
/** @copydoc SYS_RENAME */
|
||||
#define call_rename(oldpath, newpath) syscall2(SYS_RENAME, (scarg)oldpath, (scarg)newpath)
|
||||
|
||||
#endif // !__FENNIX_API_SYSCALLS_LIST_H__
|
||||
/** @copydoc SYS_UNAME */
|
||||
#define call_uname(buf) syscall1(SYS_UNAME, (scarg)buf)
|
||||
|
||||
#endif // !__FENNIX_API_SYSTEM_CALLS_LIST_H__
|
||||
|
@@ -7,9 +7,8 @@
|
||||
"settings": {
|
||||
"terminal.integrated.cwd": "../",
|
||||
"debug.allowBreakpointsEverywhere": true,
|
||||
"git.alwaysSignOff": true,
|
||||
"git.defaultBranchName": "master",
|
||||
"git.openRepositoryInParentFolders": "always",
|
||||
"C_Cpp.autoAddFileAssociations": false
|
||||
"C_Cpp.autoAddFileAssociations": false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,9 +7,8 @@
|
||||
"settings": {
|
||||
"terminal.integrated.cwd": "../",
|
||||
"debug.allowBreakpointsEverywhere": true,
|
||||
"git.alwaysSignOff": true,
|
||||
"git.defaultBranchName": "master",
|
||||
"git.openRepositoryInParentFolders": "always",
|
||||
"C_Cpp.autoAddFileAssociations": false
|
||||
"C_Cpp.autoAddFileAssociations": false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,23 +7,6 @@
|
||||
"settings": {
|
||||
"terminal.integrated.cwd": "../",
|
||||
"debug.allowBreakpointsEverywhere": true,
|
||||
"editor.tabCompletion": "on",
|
||||
"diffEditor.codeLens": true,
|
||||
"editor.quickSuggestionsDelay": 100,
|
||||
"zenMode.hideLineNumbers": false,
|
||||
"zenMode.hideActivityBar": false,
|
||||
"zenMode.hideStatusBar": true,
|
||||
"zenMode.centerLayout": true,
|
||||
"zenMode.fullScreen": true,
|
||||
"zenMode.restore": true,
|
||||
"zenMode.silentNotifications": true,
|
||||
"window.commandCenter": false,
|
||||
"window.density.editorTabHeight": "default",
|
||||
"editor.cursorBlinking": "blink",
|
||||
"editor.cursorSmoothCaretAnimation": "on",
|
||||
"editor.cursorStyle": "line",
|
||||
"editor.cursorWidth": 2,
|
||||
"git.alwaysSignOff": true,
|
||||
"git.defaultBranchName": "master",
|
||||
"git.openRepositoryInParentFolders": "always",
|
||||
"C_Cpp.autoAddFileAssociations": false,
|
||||
@@ -34,7 +17,15 @@
|
||||
"kernel",
|
||||
"kernel/pci",
|
||||
"kernel/driver",
|
||||
"kernel/drivers"
|
||||
"kernel/drivers",
|
||||
"kernel/elf",
|
||||
"kernel/scheduler",
|
||||
"kernel/tty",
|
||||
"kernel/std",
|
||||
"kernel/vfs",
|
||||
"kernel/memory",
|
||||
"kernel/efi",
|
||||
"kernel/bootstrap"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -7,18 +7,20 @@
|
||||
"settings": {
|
||||
"terminal.integrated.cwd": "../",
|
||||
"debug.allowBreakpointsEverywhere": true,
|
||||
"git.alwaysSignOff": true,
|
||||
"git.defaultBranchName": "master",
|
||||
"git.openRepositoryInParentFolders": "always",
|
||||
"C_Cpp.autoAddFileAssociations": false,
|
||||
"conventionalCommits.scopes": [
|
||||
"userspace",
|
||||
"userspace/libc",
|
||||
"vscode",
|
||||
"userspace/apps/sys/init",
|
||||
"userspace/libs/libm",
|
||||
"devcontainer",
|
||||
"userspace/coreutils",
|
||||
"userspace/apps",
|
||||
"userspace/libs",
|
||||
"userspace/apps/test"
|
||||
"userspace/apps/sys",
|
||||
"userspace/apps/test",
|
||||
"userspace/apps/usr",
|
||||
"devcontainer",
|
||||
"vscode"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -6,9 +6,8 @@
|
||||
],
|
||||
"settings": {
|
||||
"debug.allowBreakpointsEverywhere": true,
|
||||
"git.alwaysSignOff": true,
|
||||
"git.defaultBranchName": "master",
|
||||
"git.openRepositoryInParentFolders": "always",
|
||||
"C_Cpp.autoAddFileAssociations": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,14 +6,14 @@
|
||||
],
|
||||
"settings": {
|
||||
"debug.allowBreakpointsEverywhere": true,
|
||||
"git.alwaysSignOff": true,
|
||||
"git.defaultBranchName": "master",
|
||||
"git.openRepositoryInParentFolders": "always",
|
||||
"C_Cpp.autoAddFileAssociations": false,
|
||||
"conventionalCommits.scopes": [
|
||||
"initrd",
|
||||
"rootfs",
|
||||
"tools",
|
||||
"devcontainer"
|
||||
"devcontainer",
|
||||
"workspace"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
72
INSTALL.md
Normal file
72
INSTALL.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# 🚀 Installation Guide
|
||||
|
||||
This guide will help you install Fennix on your system.
|
||||
|
||||
## 🛠️ Preparing the Environment
|
||||
|
||||
There are two ways to build the project:
|
||||
|
||||
1. **🐳 Use Dev Container (Recommended)**
|
||||
* This is the easiest way to prepare the environment for building the project. But firstly, you need to install [Docker](https://docs.docker.com/get-docker/) and [Visual Studio Code](https://code.visualstudio.com/).
|
||||
* After installing Docker and Visual Studio Code, you can open the project in Visual Studio Code and click on the "Reopen in Container" button.
|
||||
* This will open the project in a Dev Container with all the required tools installed.
|
||||
* If you encounter errors while the Dev Container is building, ensure the following are correctly configured:
|
||||
* `/tmp/.X11-unix`
|
||||
* Environment variable `XAUTHORITY`
|
||||
* `/run/user/1000/pulse/native`
|
||||
* **Note:** These configurations are only necessary if you plan to use QEMU inside the container.
|
||||
2. **💻 Build the Project Locally**
|
||||
* The instructions below will guide you through the process of building the project locally.
|
||||
|
||||
**NOTE:** You MUST have `autoconf 2.69` and `automake 1.15.1` versions installed on your system. A complete list of dependencies can be found in the [.devcontainer/Dockerfile](.devcontainer/Dockerfile) file.
|
||||
|
||||
Before building the project, you need to build the cross-compiler toolchain and QEMU.
|
||||
You can do this by running the following command:
|
||||
|
||||
```sh
|
||||
make setup
|
||||
```
|
||||
|
||||
This will clone, patch, and build the required tools for you.
|
||||
|
||||
Alternatively, if you wish to skip building QEMU, you can run `make setup-no-qemu`.
|
||||
However, in this case, you will need to manually specify the path to the QEMU binary in the `config.mk` file.
|
||||
|
||||
## 🏗️ Building the Project
|
||||
|
||||
To build the project, run:
|
||||
|
||||
```sh
|
||||
make build
|
||||
```
|
||||
|
||||
This will build the kernel, userspace, and drivers. The resulting ISO image will be `Fennix.iso`.
|
||||
|
||||
## 🚀 Running the OS
|
||||
|
||||
To run the OS, execute:
|
||||
|
||||
```sh
|
||||
make run
|
||||
```
|
||||
|
||||
The `run` target will automatically build the project if it hasn't been built yet.
|
||||
|
||||
## ⚙️ Additional Configuration
|
||||
|
||||
You can customize the project by editing the `config.mk` file.
|
||||
|
||||
## 🧪 Debugging
|
||||
|
||||
If you use Visual Studio Code, you can press `F5` to start debugging the OS.
|
||||
The configuration is already set up for you.
|
||||
|
||||
Alternatively, you can run the following command to start debugging:
|
||||
|
||||
```sh
|
||||
make debug
|
||||
```
|
||||
|
||||
This will start QEMU in debug mode, allowing you to connect to it using GDB.
|
||||
|
||||
The GDB FIFO file is located at `/tmp/gdb-fennix`.
|
@@ -9,5 +9,9 @@ insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
@@ -1,91 +0,0 @@
|
||||
# Usage: add-symbol-file-all <filename> [<offset>]
|
||||
# remove-symbol-file-all <filename> [<offset>]
|
||||
#
|
||||
# Credit: https://stackoverflow.com/a/33087762/9352057
|
||||
# CC BY-SA 4.0
|
||||
|
||||
python
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
def relocatesections(filename, addr):
|
||||
p = subprocess.Popen(["readelf", "-S", filename], stdout = subprocess.PIPE)
|
||||
|
||||
sections = []
|
||||
textaddr = '0'
|
||||
for line in p.stdout.readlines():
|
||||
line = line.decode("utf-8").strip()
|
||||
if not line.startswith('[') or line.startswith('[Nr]'):
|
||||
continue
|
||||
|
||||
line = re.sub(r' +', ' ', line)
|
||||
line = re.sub(r'\[ *(\d+)\]', '\g<1>', line)
|
||||
fieldsvalue = line.split(' ')
|
||||
fieldsname = ['number', 'name', 'type', 'addr', 'offset', 'size', 'entsize', 'flags', 'link', 'info', 'addralign']
|
||||
sec = dict(zip(fieldsname, fieldsvalue))
|
||||
|
||||
if sec['number'] == '0':
|
||||
continue
|
||||
|
||||
sections.append(sec)
|
||||
|
||||
if sec['name'] == '.text':
|
||||
textaddr = sec['addr']
|
||||
|
||||
return (textaddr, sections)
|
||||
|
||||
|
||||
class AddSymbolFileAll(gdb.Command):
|
||||
"""The right version for add-symbol-file"""
|
||||
|
||||
def __init__(self):
|
||||
super(AddSymbolFileAll, self).__init__("add-symbol-file-all", gdb.COMMAND_USER)
|
||||
self.dont_repeat()
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
argv = gdb.string_to_argv(arg)
|
||||
filename = argv[0]
|
||||
|
||||
if len(argv) > 1:
|
||||
offset = int(str(gdb.parse_and_eval(argv[1])), 0)
|
||||
else:
|
||||
offset = 0
|
||||
|
||||
(textaddr, sections) = relocatesections(filename, offset)
|
||||
|
||||
cmd = "add-symbol-file %s 0x%08x" % (filename, int(textaddr, 16) + offset)
|
||||
|
||||
for s in sections:
|
||||
addr = int(s['addr'], 16)
|
||||
if s['name'] == '.text' or addr == 0:
|
||||
continue
|
||||
|
||||
cmd += " -s %s 0x%08x" % (s['name'], addr + offset)
|
||||
|
||||
gdb.execute(cmd)
|
||||
|
||||
class RemoveSymbolFileAll(gdb.Command):
|
||||
"""The right version for remove-symbol-file"""
|
||||
|
||||
def __init__(self):
|
||||
super(RemoveSymbolFileAll, self).__init__("remove-symbol-file-all", gdb.COMMAND_USER)
|
||||
self.dont_repeat()
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
argv = gdb.string_to_argv(arg)
|
||||
filename = argv[0]
|
||||
|
||||
if len(argv) > 1:
|
||||
offset = int(str(gdb.parse_and_eval(argv[1])), 0)
|
||||
else:
|
||||
offset = 0
|
||||
|
||||
(textaddr, _) = relocatesections(filename, offset)
|
||||
|
||||
cmd = "remove-symbol-file -a 0x%08x" % (int(textaddr, 16) + offset)
|
||||
gdb.execute(cmd)
|
||||
|
||||
|
||||
AddSymbolFileAll()
|
||||
RemoveSymbolFileAll()
|
||||
end
|
2
Kernel/.vscode/preinclude.h
vendored
2
Kernel/.vscode/preinclude.h
vendored
@@ -9,6 +9,6 @@
|
||||
#define __kernel__ 1
|
||||
#define KERNEL_NAME "Fennix"
|
||||
#define KERNEL_ARCH "amd64"
|
||||
#define KERNEL_VERSION "1.0"
|
||||
#define KERNEL_VERSION "1.0.0"
|
||||
#define GIT_COMMIT "0000000000000000000000000000000000000000"
|
||||
#define GIT_COMMIT_SHORT "0000000"
|
||||
|
@@ -10,14 +10,14 @@ define find-sources
|
||||
$(shell find ./ -type f -name '$1' $(shell echo $(foreach arch,$(filter-out $(OSARCH),$(AVAILABLE_ARCHS)), -not -path \"./arch/$(arch)/*\")) -print0 | xargs -0)
|
||||
endef
|
||||
|
||||
BMP_SOURCES := $(call find-sources,*.bmp)
|
||||
PNG_SOURCES := $(call find-sources,*.png)
|
||||
PSF_SOURCES := $(call find-sources,*.psf)
|
||||
S_SOURCES := $(call find-sources,*.S)
|
||||
s_SOURCES := $(call find-sources,*.s)
|
||||
C_SOURCES := $(call find-sources,*.c)
|
||||
CXX_SOURCES := $(call find-sources,*.cpp)
|
||||
|
||||
OBJ = $(BMP_SOURCES:.bmp=.o) $(PSF_SOURCES:.psf=.o) $(s_SOURCES:.s=.o) $(S_SOURCES:.S=.o) $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
|
||||
OBJ = $(PNG_SOURCES:.png=.o) $(PSF_SOURCES:.psf=.o) $(s_SOURCES:.s=.o) $(S_SOURCES:.S=.o) $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
|
||||
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CXX_SOURCES:.cpp=.su)
|
||||
GCNO_OBJ = $(C_SOURCES:.c=.gcno) $(CXX_SOURCES:.cpp=.gcno)
|
||||
|
||||
@@ -68,6 +68,7 @@ ifeq ($(DEBUG), 1)
|
||||
# CFLAGS += -pg
|
||||
# CFLAGS += -finstrument-functions
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage -fsanitize=undefined
|
||||
CXXFLAGS += -fdiagnostics-all-candidates
|
||||
ifeq ($(OSARCH), amd64)
|
||||
CFLAGS += -fverbose-asm
|
||||
endif # amd64
|
||||
@@ -111,7 +112,7 @@ $(KERNEL_FILENAME): $(OBJ)
|
||||
# https://gcc.gnu.org/projects/cxx-status.html
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(__CONF_CXX) $(CFLAGS) -fcoroutines $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-rtti
|
||||
$(__CONF_CXX) $(CFLAGS) $(CXXFLAGS) -fcoroutines $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-rtti
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
@@ -133,7 +134,7 @@ else ifeq ($(OSARCH), aarch64)
|
||||
endif
|
||||
$(__CONF_NM) $@
|
||||
|
||||
%.o: %.bmp
|
||||
%.o: %.png
|
||||
ifeq ($(OSARCH), amd64)
|
||||
$(__CONF_OBJCOPY) -O elf64-x86-64 -I binary $< $@
|
||||
else ifeq ($(OSARCH), i386)
|
||||
|
@@ -9,7 +9,7 @@
|
||||
- [ ] ~~Do not map the entire memory. Map only the needed memory address at allocation time.~~ (we just copy the pages for userland, see `Fork()` inside [core/memory/page_table.cpp](core/memory/page_table.cpp))
|
||||
- [ ] Implementation of logging (beside serial) with log rotation.
|
||||
- [x] Implement a better task manager. (replace struct P/TCB with classes)
|
||||
- [ ] Rewrite virtual file system.
|
||||
- [x] Rewrite virtual file system.
|
||||
- [ ] Colors in crash screen are not following the kernel color scheme.
|
||||
- [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly)
|
||||
- [ ] Rework PSF1 font loader.
|
||||
|
@@ -25,33 +25,41 @@
|
||||
|
||||
void InitLimine();
|
||||
|
||||
static volatile struct limine_entry_point_request EntryPointRequest = {
|
||||
#define LIMREQ __attribute__((used, section(".limine_requests"))) static volatile
|
||||
#define LIMREQ_S __attribute__((used, section(".limine_requests_start"))) static volatile
|
||||
#define LIMREQ_E __attribute__((used, section(".limine_requests_end"))) static volatile
|
||||
|
||||
LIMREQ LIMINE_BASE_REVISION(3);
|
||||
LIMREQ_S LIMINE_REQUESTS_START_MARKER;
|
||||
LIMREQ_E LIMINE_REQUESTS_END_MARKER;
|
||||
|
||||
LIMREQ struct limine_entry_point_request EntryPointRequest = {
|
||||
.id = LIMINE_ENTRY_POINT_REQUEST,
|
||||
.revision = 0,
|
||||
.response = NULL,
|
||||
.entry = InitLimine};
|
||||
static volatile struct limine_bootloader_info_request BootloaderInfoRequest = {
|
||||
LIMREQ struct limine_bootloader_info_request BootloaderInfoRequest = {
|
||||
.id = LIMINE_BOOTLOADER_INFO_REQUEST,
|
||||
.revision = 0};
|
||||
static volatile struct limine_framebuffer_request FramebufferRequest = {
|
||||
LIMREQ struct limine_framebuffer_request FramebufferRequest = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||
.revision = 0};
|
||||
static volatile struct limine_memmap_request MemmapRequest = {
|
||||
LIMREQ struct limine_memmap_request MemmapRequest = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
.revision = 0};
|
||||
static volatile struct limine_kernel_address_request KernelAddressRequest = {
|
||||
LIMREQ struct limine_kernel_address_request KernelAddressRequest = {
|
||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
||||
.revision = 0};
|
||||
static volatile struct limine_rsdp_request RsdpRequest = {
|
||||
LIMREQ struct limine_rsdp_request RsdpRequest = {
|
||||
.id = LIMINE_RSDP_REQUEST,
|
||||
.revision = 0};
|
||||
static volatile struct limine_kernel_file_request KernelFileRequest = {
|
||||
LIMREQ struct limine_kernel_file_request KernelFileRequest = {
|
||||
.id = LIMINE_KERNEL_FILE_REQUEST,
|
||||
.revision = 0};
|
||||
static volatile struct limine_module_request ModuleRequest = {
|
||||
LIMREQ struct limine_module_request ModuleRequest = {
|
||||
.id = LIMINE_MODULE_REQUEST,
|
||||
.revision = 0};
|
||||
static volatile struct limine_smbios_request SmbiosRequest = {
|
||||
LIMREQ struct limine_smbios_request SmbiosRequest = {
|
||||
.id = LIMINE_SMBIOS_REQUEST,
|
||||
.revision = 0};
|
||||
|
||||
@@ -84,7 +92,7 @@ __naked __used __no_stack_protector void InitLimine()
|
||||
asmv("jmp InitLimineAfterStack");
|
||||
}
|
||||
|
||||
nsa NIF void InitLimineAfterStack()
|
||||
nsa nif void InitLimineAfterStack()
|
||||
{
|
||||
struct BootInfo binfo = {};
|
||||
struct limine_bootloader_info_response *BootloaderInfoResponse = BootloaderInfoRequest.response;
|
||||
|
@@ -38,14 +38,14 @@ union __attribute__((packed)) PageTableEntry
|
||||
};
|
||||
uint64_t raw;
|
||||
|
||||
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address)
|
||||
__always_inline inline nsa nif void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
__always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) PageTableEntryPtr
|
||||
@@ -72,14 +72,14 @@ union __attribute__((packed)) PageDirectoryEntry
|
||||
};
|
||||
uint64_t raw;
|
||||
|
||||
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address)
|
||||
__always_inline inline nsa nif void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
__always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) PageDirectoryEntryPtr
|
||||
@@ -106,14 +106,14 @@ union __attribute__((packed)) PageDirectoryPointerTableEntry
|
||||
};
|
||||
uint64_t raw;
|
||||
|
||||
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address)
|
||||
__always_inline inline nsa nif void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
__always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) PageDirectoryPointerTableEntryPtr
|
||||
@@ -140,14 +140,14 @@ union __attribute__((packed)) PageMapLevel4
|
||||
};
|
||||
uint64_t raw;
|
||||
|
||||
__always_inline inline nsa NIF void SetAddress(uintptr_t _Address)
|
||||
__always_inline inline nsa nif void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
__always_inline inline nsa nif uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
|
||||
};
|
||||
|
||||
struct PageTable4
|
||||
@@ -161,7 +161,7 @@ extern uintptr_t _kernel_start, _kernel_end;
|
||||
__attribute__((section(".bootstrap.data"))) static PageTable4 *BPTable = (PageTable4 *)BootPageTable;
|
||||
__attribute__((section(".bootstrap.data"))) static size_t BPT_Allocated = 0x4000;
|
||||
|
||||
__always_inline inline nsa NIF void *RequestPage()
|
||||
__always_inline inline nsa nif void *RequestPage()
|
||||
{
|
||||
void *Page = (void *)(BootPageTable + BPT_Allocated);
|
||||
BPT_Allocated += 0x1000;
|
||||
@@ -180,7 +180,7 @@ public:
|
||||
uintptr_t PDPTEIndex = 0;
|
||||
uintptr_t PDEIndex = 0;
|
||||
uintptr_t PTEIndex = 0;
|
||||
__always_inline inline nsa NIF PageMapIndexer(uintptr_t VirtualAddress)
|
||||
__always_inline inline nsa nif PageMapIndexer(uintptr_t VirtualAddress)
|
||||
{
|
||||
uintptr_t Address = VirtualAddress;
|
||||
Address >>= 12;
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
__attribute__((section(".bootstrap.text"))) nsa NIF void MB2_64_Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
|
||||
__attribute__((section(".bootstrap.text"))) nsa nif void MB2_64_Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
|
||||
{
|
||||
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
|
||||
// Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only
|
||||
@@ -280,7 +280,7 @@ __attribute__((section(".bootstrap.text"))) nsa NIF void MB2_64_Map(void *Virtua
|
||||
: "memory");
|
||||
}
|
||||
|
||||
EXTERNC __attribute__((section(".bootstrap.text"))) nsa NIF __attribute__((section(".bootstrap.text"))) void UpdatePageTable64()
|
||||
EXTERNC __attribute__((section(".bootstrap.text"))) nsa nif __attribute__((section(".bootstrap.text"))) void UpdatePageTable64()
|
||||
{
|
||||
BPTable = (PageTable4 *)BootPageTable;
|
||||
|
||||
|
@@ -24,10 +24,8 @@
|
||||
|
||||
void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
{
|
||||
auto InfoAddress = Info;
|
||||
for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8);
|
||||
;
|
||||
Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
|
||||
auto infoAddr = Info;
|
||||
for (auto Tag = (struct multiboot_tag *)((uint8_t *)infoAddr + 8);; Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
|
||||
{
|
||||
if (Tag->type == MULTIBOOT_TAG_TYPE_END)
|
||||
{
|
||||
@@ -39,17 +37,17 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
{
|
||||
case MULTIBOOT_TAG_TYPE_CMDLINE:
|
||||
{
|
||||
strncpy(mb2binfo.Kernel.CommandLine,
|
||||
((multiboot_tag_string *)Tag)->string,
|
||||
strlen(((multiboot_tag_string *)Tag)->string));
|
||||
multiboot_tag_string *cmdline = (multiboot_tag_string *)Tag;
|
||||
strncpy(mb2binfo.Kernel.CommandLine, cmdline->string, strlen(cmdline->string));
|
||||
|
||||
debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
|
||||
{
|
||||
strncpy(mb2binfo.Bootloader.Name,
|
||||
((multiboot_tag_string *)Tag)->string,
|
||||
strlen(((multiboot_tag_string *)Tag)->string));
|
||||
multiboot_tag_string *blName = (multiboot_tag_string *)Tag;
|
||||
strncpy(mb2binfo.Bootloader.Name, blName->string, strlen(blName->string));
|
||||
|
||||
debug("Bootloader name: %s", mb2binfo.Bootloader.Name);
|
||||
break;
|
||||
}
|
||||
@@ -60,24 +58,29 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
mb2binfo.Modules[module_count].Address = (void *)(uint64_t)module->mod_start;
|
||||
mb2binfo.Modules[module_count].Size = module->mod_end - module->mod_start;
|
||||
strncpy(mb2binfo.Modules[module_count].Path, "(null)", 6);
|
||||
strncpy(mb2binfo.Modules[module_count].CommandLine, module->cmdline,
|
||||
strlen(module->cmdline));
|
||||
debug("Module: %s", mb2binfo.Modules[module_count].Path);
|
||||
strncpy(mb2binfo.Modules[module_count].CommandLine, module->cmdline, strlen(module->cmdline));
|
||||
|
||||
debug("Module: %s", mb2binfo.Modules[module_count].CommandLine);
|
||||
module_count++;
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
|
||||
{
|
||||
multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag;
|
||||
|
||||
fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]",
|
||||
meminfo->mem_lower, meminfo->mem_upper);
|
||||
meminfo->mem_lower,
|
||||
meminfo->mem_upper);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_BOOTDEV:
|
||||
{
|
||||
multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag;
|
||||
|
||||
fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]",
|
||||
bootdev->biosdev, bootdev->slice, bootdev->part);
|
||||
bootdev->biosdev,
|
||||
bootdev->slice,
|
||||
bootdev->part);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_MMAP:
|
||||
@@ -92,6 +95,7 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
warn("Too many memory entries, skipping the rest...");
|
||||
break;
|
||||
}
|
||||
|
||||
multiboot_mmap_entry entry = mmap->entries[i];
|
||||
mb2binfo.Memory.Size += entry.len;
|
||||
switch (entry.type)
|
||||
@@ -127,6 +131,7 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
mb2binfo.Memory.Entry[i].Type = Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]",
|
||||
mb2binfo.Memory.Entry[i].BaseAddress,
|
||||
mb2binfo.Memory.Entry[i].Length,
|
||||
@@ -137,54 +142,52 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
case MULTIBOOT_TAG_TYPE_VBE:
|
||||
{
|
||||
multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag;
|
||||
|
||||
fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]",
|
||||
vbe->vbe_mode, vbe->vbe_interface_seg, vbe->vbe_interface_off, vbe->vbe_interface_len);
|
||||
vbe->vbe_mode,
|
||||
vbe->vbe_interface_seg,
|
||||
vbe->vbe_interface_off,
|
||||
vbe->vbe_interface_len);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
|
||||
{
|
||||
multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag;
|
||||
static int fb_count = 0;
|
||||
mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)fb->common.framebuffer_addr;
|
||||
mb2binfo.Framebuffer[fb_count].Width = fb->common.framebuffer_width;
|
||||
mb2binfo.Framebuffer[fb_count].Height = fb->common.framebuffer_height;
|
||||
mb2binfo.Framebuffer[fb_count].Pitch = fb->common.framebuffer_pitch;
|
||||
mb2binfo.Framebuffer[fb_count].BitsPerPixel = fb->common.framebuffer_bpp;
|
||||
static int fbCount = 0;
|
||||
mb2binfo.Framebuffer[fbCount].BaseAddress = (void *)fb->common.framebuffer_addr;
|
||||
mb2binfo.Framebuffer[fbCount].Width = fb->common.framebuffer_width;
|
||||
mb2binfo.Framebuffer[fbCount].Height = fb->common.framebuffer_height;
|
||||
mb2binfo.Framebuffer[fbCount].Pitch = fb->common.framebuffer_pitch;
|
||||
mb2binfo.Framebuffer[fbCount].BitsPerPixel = fb->common.framebuffer_bpp;
|
||||
switch (fb->common.framebuffer_type)
|
||||
{
|
||||
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
|
||||
{
|
||||
mb2binfo.Framebuffer[fb_count].Type = Indexed;
|
||||
mb2binfo.Framebuffer[fbCount].Type = Indexed;
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
|
||||
{
|
||||
mb2binfo.Framebuffer[fb_count].Type = RGB;
|
||||
mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size;
|
||||
mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position;
|
||||
mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size;
|
||||
mb2binfo.Framebuffer[fb_count].GreenMaskShift = fb->framebuffer_green_field_position;
|
||||
mb2binfo.Framebuffer[fb_count].BlueMaskSize = fb->framebuffer_blue_mask_size;
|
||||
mb2binfo.Framebuffer[fb_count].BlueMaskShift = fb->framebuffer_blue_field_position;
|
||||
mb2binfo.Framebuffer[fbCount].Type = RGB;
|
||||
mb2binfo.Framebuffer[fbCount].RedMaskSize = fb->framebuffer_red_mask_size;
|
||||
mb2binfo.Framebuffer[fbCount].RedMaskShift = fb->framebuffer_red_field_position;
|
||||
mb2binfo.Framebuffer[fbCount].GreenMaskSize = fb->framebuffer_green_mask_size;
|
||||
mb2binfo.Framebuffer[fbCount].GreenMaskShift = fb->framebuffer_green_field_position;
|
||||
mb2binfo.Framebuffer[fbCount].BlueMaskSize = fb->framebuffer_blue_mask_size;
|
||||
mb2binfo.Framebuffer[fbCount].BlueMaskShift = fb->framebuffer_blue_field_position;
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
|
||||
{
|
||||
mb2binfo.Framebuffer[fb_count].Type = EGA;
|
||||
mb2binfo.Framebuffer[fbCount].Type = EGA;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
mb2binfo.Framebuffer[fb_count].Type = Unknown_Framebuffer_Type;
|
||||
mb2binfo.Framebuffer[fbCount].Type = Unknown_Framebuffer_Type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug("Framebuffer %d: %dx%d %d bpp", fb_count, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp);
|
||||
debug("More info:\nAddress: %p\nPitch: %d\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d",
|
||||
|
||||
debug("fb %d: %dx%d %d bpp", fbCount, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp);
|
||||
debug("More info: addr:%#lx pitch:%d mm:%d RMSize:%d RMShift:%d GMSize:%d GMShift:%d BMSize:%d BMShift:%d",
|
||||
fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type,
|
||||
fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size,
|
||||
fb->framebuffer_green_field_position, fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position);
|
||||
fb_count++;
|
||||
fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position,
|
||||
fb->framebuffer_green_mask_size, fb->framebuffer_green_field_position,
|
||||
fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position);
|
||||
fbCount++;
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
|
||||
@@ -194,73 +197,115 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
mb2binfo.Kernel.Symbols.EntSize = elf->entsize;
|
||||
mb2binfo.Kernel.Symbols.Shndx = elf->shndx;
|
||||
mb2binfo.Kernel.Symbols.Sections = r_cst(uintptr_t, elf->sections);
|
||||
|
||||
debug("elf_sections->[num: %d, entsize: %d, shndx: %d, sections: %#lx]",
|
||||
elf->num, elf->entsize, elf->shndx, elf->sections);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_APM:
|
||||
{
|
||||
multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag;
|
||||
fixme("apm->[version: %d, cseg: %d, offset: %d, cseg_16: %d, dseg: %d, flags: %d, cseg_len: %d, cseg_16_len: %d, dseg_len: %d]",
|
||||
apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg, apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len);
|
||||
|
||||
fixme("apm->[version:%d, cseg:%d, offset:%d, cseg_16:%d, dseg:%d, flags:%d, cseg_len:%d, cseg_16_len:%d, dseg_len:%d]",
|
||||
apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg,
|
||||
apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI32:
|
||||
{
|
||||
mb2binfo.EFI.Info.Enabled = 1;
|
||||
mb2binfo.EFI.Info.ST = 1;
|
||||
|
||||
multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag;
|
||||
fixme("efi32->[pointer: %p, size: %d]", efi32->pointer, efi32->size);
|
||||
mb2binfo.EFI.SystemTable = (void *)(uintptr_t)efi32->pointer;
|
||||
|
||||
debug("efi32->[pointer: %#lx, size: %d]", efi32->pointer, efi32->size);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI64:
|
||||
{
|
||||
mb2binfo.EFI.Info.Enabled = 1;
|
||||
mb2binfo.EFI.Info.ST = 1;
|
||||
|
||||
multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag;
|
||||
fixme("efi64->[pointer: %p, size: %d]", efi64->pointer, efi64->size);
|
||||
mb2binfo.EFI.SystemTable = (void *)(uintptr_t)efi64->pointer;
|
||||
|
||||
debug("efi64->[pointer: %#lx, size: %d]", efi64->pointer, efi64->size);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_SMBIOS:
|
||||
{
|
||||
multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag;
|
||||
fixme("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor);
|
||||
mb2binfo.SMBIOSPtr = (void *)smbios->tables;
|
||||
|
||||
debug("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_ACPI_OLD:
|
||||
{
|
||||
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp;
|
||||
debug("OLD ACPI RSDP: %p", mb2binfo.RSDP);
|
||||
|
||||
debug("OLD ACPI RSDP: %#lx", mb2binfo.RSDP);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_ACPI_NEW:
|
||||
{
|
||||
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp;
|
||||
debug("NEW ACPI RSDP: %p", mb2binfo.RSDP);
|
||||
|
||||
debug("NEW ACPI RSDP: %#lx", mb2binfo.RSDP);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_NETWORK:
|
||||
{
|
||||
multiboot_tag_network *net = (multiboot_tag_network *)Tag;
|
||||
fixme("network->[dhcpack: %p]", net->dhcpack);
|
||||
|
||||
fixme("network->[dhcpack: %#lx]", net->dhcpack);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI_MMAP:
|
||||
{
|
||||
mb2binfo.EFI.Info.Enabled = 1;
|
||||
mb2binfo.EFI.Info.MemoryMap = 1;
|
||||
|
||||
multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag;
|
||||
fixme("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %p]",
|
||||
mb2binfo.EFI.MemoryMap.BaseAddress = (void *)efi_mmap->efi_mmap;
|
||||
mb2binfo.EFI.MemoryMap.DescriptorSize = efi_mmap->descr_size;
|
||||
mb2binfo.EFI.MemoryMap.DescriptorVersion = efi_mmap->descr_vers;
|
||||
mb2binfo.EFI.MemoryMap.NumberOfEntries = (efi_mmap->size - sizeof(multiboot_tag_efi_mmap)) / efi_mmap->descr_size;
|
||||
// mb2binfo.EFI.MemoryMap.NumberOfEntries = efi_mmap->size / efi_mmap->descr_size;
|
||||
|
||||
debug("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %#lx]",
|
||||
efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI_BS:
|
||||
{
|
||||
fixme("efi_bs->[%p] (unknown structure)", Tag);
|
||||
mb2binfo.EFI.Info.Enabled = 1;
|
||||
mb2binfo.EFI.Info.BS = 1;
|
||||
|
||||
debug("efi_bs");
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI32_IH:
|
||||
{
|
||||
mb2binfo.EFI.Info.Enabled = 1;
|
||||
mb2binfo.EFI.Info.IH = 1;
|
||||
|
||||
multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag;
|
||||
fixme("efi32_ih->[pointer: %p]", efi32_ih->pointer);
|
||||
mb2binfo.EFI.ImageHandle = (void *)(uintptr_t)efi32_ih->pointer;
|
||||
|
||||
debug("efi32_ih->[pointer: %#lx]", efi32_ih->pointer);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_EFI64_IH:
|
||||
{
|
||||
mb2binfo.EFI.Info.Enabled = 1;
|
||||
mb2binfo.EFI.Info.IH = 1;
|
||||
|
||||
multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag;
|
||||
fixme("efi64_ih->[pointer: %p]", efi64_ih->pointer);
|
||||
mb2binfo.EFI.ImageHandle = (void *)(uintptr_t)efi64_ih->pointer;
|
||||
|
||||
debug("efi64_ih->[pointer: %#lx]", efi64_ih->pointer);
|
||||
break;
|
||||
}
|
||||
case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
|
||||
@@ -269,7 +314,8 @@ void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
mb2binfo.Kernel.PhysicalBase = (void *)(uint64_t)load_base_addr->load_base_addr;
|
||||
mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)(load_base_addr->load_base_addr + 0xFFFFFFFF80000000);
|
||||
mb2binfo.Kernel.Size = ((uint64_t)&_kernel_end - (uint64_t)&_kernel_start) + ((uint64_t)&_bootstrap_end - (uint64_t)&_bootstrap_start);
|
||||
debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
|
||||
|
||||
debug("Kernel base: %#lx (physical) %#lx (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@@ -68,8 +68,10 @@ Multiboot_start:
|
||||
je x32Hang
|
||||
|
||||
mov %cr4, %ecx
|
||||
or $0x00000010, %ecx /* PSE */
|
||||
or $0x00000020, %ecx /* PAE */
|
||||
or $0x10, %ecx /* PSE */
|
||||
or $0x20, %ecx /* PAE */
|
||||
or $0x200, %ecx /* OSFXSR */
|
||||
or $0x400, %ecx /* OSXMMEXCPT */
|
||||
mov %ecx, %cr4
|
||||
|
||||
call LoadGDT32
|
||||
@@ -82,12 +84,14 @@ Multiboot_start:
|
||||
rdmsr
|
||||
or $0x800, %eax /* LME */
|
||||
or $0x100, %eax /* LMA */
|
||||
or $0x1, %eax /* SCE */
|
||||
or $0x1, %eax /* SCE */
|
||||
wrmsr
|
||||
|
||||
mov %cr0, %ecx
|
||||
and $~0x4, %ecx /* EM */
|
||||
or $0x2, %ecx /* MP */
|
||||
or $0x80000000, %ecx /* PG */
|
||||
or $0x1, %ecx /* PE */
|
||||
or $0x1, %ecx /* PE */
|
||||
mov %ecx, %cr0
|
||||
|
||||
lgdt [GDT64.Ptr]
|
||||
|
@@ -442,7 +442,7 @@ namespace APIC
|
||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
||||
TimeManager->Sleep(Time::FromMilliseconds(1));
|
||||
|
||||
// Mask the timer
|
||||
if (this->lapic->x2APIC)
|
||||
|
@@ -650,7 +650,7 @@ namespace InterruptDescriptorTable
|
||||
#ifdef DEBUG
|
||||
EnableISRs = !DebuggerIsAttached;
|
||||
if (!EnableISRs)
|
||||
KPrint("\x1b[34mThe debugger is attached, disabling all ISRs.");
|
||||
KPrint("\x1b[32mThe debugger is attached, disabling all ISRs.");
|
||||
#endif
|
||||
|
||||
/* ISR */
|
||||
|
@@ -167,14 +167,14 @@ namespace SMP
|
||||
}
|
||||
|
||||
apic->SendInitIPI(lapic->APICId);
|
||||
TimeManager->Sleep(20, Time::Units::Milliseconds);
|
||||
TimeManager->Sleep(Time::FromMilliseconds(20));
|
||||
apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
|
||||
debug("Waiting for CPU %d to load...", lapic->APICId);
|
||||
|
||||
uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds);
|
||||
uint64_t Timeout = TimeManager->GetTimeNs() + Time::FromSeconds(2);
|
||||
while (CPUEnabled.load(std::memory_order_acquire) == false)
|
||||
{
|
||||
if (TimeManager->GetCounter() > Timeout)
|
||||
if (TimeManager->GetTimeNs() > Timeout)
|
||||
{
|
||||
error("CPU %d failed to load!", lapic->APICId);
|
||||
KPrint("\x1b[1;37;41mCPU %d failed to load!",
|
||||
|
@@ -46,9 +46,17 @@ SECTIONS
|
||||
*(.bootstrap .bootstrap.*)
|
||||
} :bootstrap
|
||||
_bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
. += KERNEL_VMA;
|
||||
|
||||
/* . += KERNEL_VMA;
|
||||
_bootstrap_start = .;
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
KEEP(*(.limine_requests_end))
|
||||
} :bootstrap
|
||||
_bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE)); */
|
||||
|
||||
_kernel_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
_kernel_text_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.text ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.text) - KERNEL_VMA)
|
||||
|
@@ -368,7 +368,7 @@ namespace APIC
|
||||
this->lapic->Write(APIC_TDCR, DivideBy128);
|
||||
else
|
||||
this->lapic->Write(APIC_TDCR, DivideBy16);
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds));
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks *Miliseconds));
|
||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||
}
|
||||
|
||||
@@ -383,7 +383,7 @@ namespace APIC
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||
|
||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
||||
TimeManager->Sleep(Time::FromMilliseconds(1));
|
||||
|
||||
// Mask the timer
|
||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
|
@@ -464,7 +464,7 @@ namespace InterruptDescriptorTable
|
||||
// #ifdef DEBUG
|
||||
EnableISRs = !DebuggerIsAttached;
|
||||
if (!EnableISRs)
|
||||
KPrint("\x1b[34mThe debugger is attached, disabling all ISRs.");
|
||||
KPrint("\x1b[32mThe debugger is attached, disabling all ISRs.");
|
||||
// #endif
|
||||
|
||||
SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
|
@@ -20,13 +20,16 @@
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <ini.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace KernelConsole
|
||||
{
|
||||
int TermColors[] = {
|
||||
static int TermColors[] = {
|
||||
[TerminalColor::BLACK] = 0x000000,
|
||||
[TerminalColor::RED] = 0xAA0000,
|
||||
[TerminalColor::GREEN] = 0x00AA00,
|
||||
@@ -37,7 +40,7 @@ namespace KernelConsole
|
||||
[TerminalColor::GREY] = 0xAAAAAA,
|
||||
};
|
||||
|
||||
int TermBrightColors[] = {
|
||||
static int TermBrightColors[] = {
|
||||
[TerminalColor::BLACK] = 0x858585,
|
||||
[TerminalColor::RED] = 0xFF5555,
|
||||
[TerminalColor::GREEN] = 0x55FF55,
|
||||
@@ -112,6 +115,33 @@ namespace KernelConsole
|
||||
|
||||
FontRenderer Renderer;
|
||||
|
||||
ConsoleTerminal *Terminals[16] = {nullptr};
|
||||
std::atomic<ConsoleTerminal *> CurrentTerminal = nullptr;
|
||||
|
||||
void paint_blinker(bool Enable)
|
||||
{
|
||||
if (CurrentTerminal == nullptr)
|
||||
return;
|
||||
|
||||
ConsoleTerminal *term = CurrentTerminal.load();
|
||||
ConsoleTerminal::Blinker &blinker = term->Blink;
|
||||
size_t cellIndex = Renderer.Cursor.Y * term->Term->GetWinsize()->ws_col + Renderer.Cursor.X;
|
||||
TerminalCell *cell = term->Term->GetCell(cellIndex);
|
||||
uint32_t bgColor = cell->attr.Bright ? TermBrightColors[cell->attr.Background] : TermColors[cell->attr.Background];
|
||||
Renderer.Paint(Renderer.Cursor.X, Renderer.Cursor.Y, blinker.Character, Enable ? blinker.Color : bgColor, bgColor);
|
||||
}
|
||||
|
||||
void paint_blinker_thread()
|
||||
{
|
||||
bool blink = false;
|
||||
while (true)
|
||||
{
|
||||
paint_blinker(blink);
|
||||
blink = !blink;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CurrentTerminal.load()->Blink.Delay));
|
||||
}
|
||||
}
|
||||
|
||||
void paint_callback(TerminalCell *cell, long x, long y)
|
||||
{
|
||||
if (cell->attr.Bright)
|
||||
@@ -123,22 +153,20 @@ namespace KernelConsole
|
||||
void cursor_callback(TerminalCursor *cur)
|
||||
{
|
||||
Renderer.Cursor = {cur->X, cur->Y};
|
||||
paint_blinker(false);
|
||||
}
|
||||
|
||||
VirtualTerminal *Terminals[16] = {nullptr};
|
||||
std::atomic<VirtualTerminal *> CurrentTerminal = nullptr;
|
||||
|
||||
bool SetTheme(std::string Theme)
|
||||
{
|
||||
FileNode *rn = fs->GetByPath("/etc/term", thisProcess->Info.RootNode);
|
||||
Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term");
|
||||
if (rn == nullptr)
|
||||
return false;
|
||||
|
||||
kstat st{};
|
||||
rn->Stat(&st);
|
||||
kstat st;
|
||||
fs->Stat(rn, &st);
|
||||
|
||||
char *sh = new char[st.Size];
|
||||
rn->Read(sh, st.Size, 0);
|
||||
fs->Read(rn, sh, st.Size, 0);
|
||||
|
||||
ini_t *ini = ini_load(sh, NULL);
|
||||
int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx;
|
||||
@@ -267,24 +295,15 @@ namespace KernelConsole
|
||||
size_t Rows = Display->GetWidth / Renderer.CurrentFont->GetInfo().Width;
|
||||
size_t Cols = Display->GetHeight / Renderer.CurrentFont->GetInfo().Height;
|
||||
debug("Terminal size: %ux%u", Rows, Cols);
|
||||
Terminals[0] = new VirtualTerminal(Rows, Cols, Display->GetWidth, Display->GetHeight, paint_callback, cursor_callback);
|
||||
Terminals[0]->Clear(0, 0, Rows, Cols - 1);
|
||||
Terminals[0] = new ConsoleTerminal;
|
||||
Terminals[0]->Term = new VirtualTerminal(Rows, Cols, Display->GetWidth, Display->GetHeight, paint_callback, cursor_callback);
|
||||
Terminals[0]->Term->Clear(0, 0, Rows, Cols - 1);
|
||||
CurrentTerminal.store(Terminals[0], std::memory_order_release);
|
||||
}
|
||||
|
||||
void LateInit()
|
||||
void LoadConsoleConfig(std::string &Config)
|
||||
{
|
||||
FileNode *rn = fs->GetByPath("/etc/term", thisProcess->Info.RootNode);
|
||||
if (rn == nullptr)
|
||||
return;
|
||||
|
||||
kstat st{};
|
||||
rn->Stat(&st);
|
||||
|
||||
char *sh = new char[st.Size];
|
||||
rn->Read(sh, st.Size, 0);
|
||||
|
||||
ini_t *ini = ini_load(sh, NULL);
|
||||
ini_t *ini = ini_load(Config.c_str(), NULL);
|
||||
int general = ini_find_section(ini, "general", NULL);
|
||||
int cursor = ini_find_section(ini, "cursor", NULL);
|
||||
assert(general != INI_NOT_FOUND && cursor != INI_NOT_FOUND);
|
||||
@@ -292,16 +311,22 @@ namespace KernelConsole
|
||||
int themeIndex = ini_find_property(ini, general, "theme", NULL);
|
||||
assert(themeIndex != INI_NOT_FOUND);
|
||||
|
||||
int cursorColor = ini_find_property(ini, cursor, "color", NULL);
|
||||
int cursorBlink = ini_find_property(ini, cursor, "blink", NULL);
|
||||
assert(cursorColor != INI_NOT_FOUND && cursorBlink != INI_NOT_FOUND);
|
||||
int cursorColor = ini_find_property(ini, cursor, "color", NULL);
|
||||
int cursorChar = ini_find_property(ini, cursor, "char", NULL);
|
||||
int cursorDelay = ini_find_property(ini, cursor, "delay", NULL);
|
||||
assert(cursorBlink != INI_NOT_FOUND && cursorColor != INI_NOT_FOUND && cursorChar != INI_NOT_FOUND && cursorDelay != INI_NOT_FOUND);
|
||||
|
||||
const char *colorThemeStr = ini_property_value(ini, general, themeIndex);
|
||||
const char *cursorColorStr = ini_property_value(ini, cursor, cursorColor);
|
||||
const char *cursorBlinkStr = ini_property_value(ini, cursor, cursorBlink);
|
||||
const char *cursorCharStr = ini_property_value(ini, cursor, cursorChar);
|
||||
const char *cursorDelayStr = ini_property_value(ini, cursor, cursorDelay);
|
||||
debug("colorThemeStr=%s", colorThemeStr);
|
||||
debug("cursorColorStr=%s", cursorColorStr);
|
||||
debug("cursorBlinkStr=%s", cursorBlinkStr);
|
||||
debug("cursorColorStr=%s", cursorColorStr);
|
||||
debug("cursorCharStr=%s", cursorCharStr);
|
||||
debug("cursorDelayStr=%s", cursorDelayStr);
|
||||
|
||||
auto getColorComponent = [](const char *str, int &index) -> int
|
||||
{
|
||||
@@ -335,11 +360,36 @@ namespace KernelConsole
|
||||
uint32_t blinkColor = 0xFFFFFF;
|
||||
if (cursorColorStr != 0)
|
||||
blinkColor = parseColor(cursorColorStr);
|
||||
fixme("cursor blink with colors %X", blinkColor);
|
||||
debug("cursor blink with colors %X and char '%s' and delay %s", blinkColor, cursorCharStr, cursorDelayStr);
|
||||
Terminals[0]->Blink.Enabled = true;
|
||||
Terminals[0]->Blink.Color = blinkColor;
|
||||
Terminals[0]->Blink.Character = *cursorCharStr;
|
||||
Terminals[0]->Blink.Delay = atoi(cursorDelayStr);
|
||||
}
|
||||
|
||||
ini_destroy(ini);
|
||||
delete[] sh;
|
||||
}
|
||||
|
||||
void LateInit()
|
||||
{
|
||||
Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term");
|
||||
if (rn == nullptr)
|
||||
return;
|
||||
|
||||
{
|
||||
kstat st;
|
||||
fs->Stat(rn, &st);
|
||||
std::string cfg;
|
||||
cfg.resize(st.Size);
|
||||
fs->Read(rn, cfg.data(), st.Size, 0);
|
||||
LoadConsoleConfig(cfg);
|
||||
}
|
||||
|
||||
if (Terminals[0]->Blink.Enabled)
|
||||
{
|
||||
std::thread t = std::thread(paint_blinker_thread);
|
||||
t.detach();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// __test_themes();
|
||||
|
@@ -27,12 +27,12 @@ NewLock(DebuggerLock);
|
||||
|
||||
extern bool serialports[8];
|
||||
|
||||
EXTERNC NIF void uart_wrapper(char c, void *)
|
||||
EXTERNC nif void uart_wrapper(char c, void *)
|
||||
{
|
||||
uart.DebugWrite(c);
|
||||
}
|
||||
|
||||
static inline NIF bool WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, va_list args)
|
||||
static inline nif bool WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, va_list args)
|
||||
{
|
||||
const char *DbgLvlString;
|
||||
switch (Level)
|
||||
@@ -79,7 +79,7 @@ static inline NIF bool WritePrefix(DebugLevel Level, const char *File, int Line,
|
||||
|
||||
namespace SysDbg
|
||||
{
|
||||
NIF void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
nif void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
@@ -92,7 +92,7 @@ namespace SysDbg
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
NIF void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
nif void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
@@ -106,7 +106,7 @@ namespace SysDbg
|
||||
uart_wrapper('\n', nullptr);
|
||||
}
|
||||
|
||||
NIF void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
nif void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
va_list args;
|
||||
@@ -120,7 +120,7 @@ namespace SysDbg
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
NIF void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
nif void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
va_list args;
|
||||
@@ -137,7 +137,7 @@ namespace SysDbg
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
extern "C" nif void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
@@ -151,7 +151,7 @@ extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Lin
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
extern "C" nif void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
@@ -166,7 +166,7 @@ extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
extern "C" nif void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
va_list args;
|
||||
@@ -181,7 +181,7 @@ extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, i
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
extern "C" nif void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
va_list args;
|
||||
|
@@ -191,11 +191,11 @@ namespace v0
|
||||
|
||||
/* --------- */
|
||||
|
||||
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root)
|
||||
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info)
|
||||
{
|
||||
dbg_api("%d, %#lx, %#lx", DriverID, Info, Root);
|
||||
dbg_api("%d, %#lx", DriverID, Info);
|
||||
|
||||
return fs->RegisterFileSystem(Info, Root);
|
||||
return fs->RegisterFileSystem(Info);
|
||||
}
|
||||
|
||||
int UnregisterFileSystem(dev_t DriverID, dev_t Device)
|
||||
@@ -273,7 +273,7 @@ namespace v0
|
||||
{
|
||||
dbg_api("%d, %d", DriverID, Milliseconds);
|
||||
|
||||
TaskManager->Sleep(Milliseconds);
|
||||
TaskManager->Sleep(Time::FromMilliseconds(Milliseconds));
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
@@ -333,7 +333,7 @@ namespace v0
|
||||
|
||||
void PS2Wait(dev_t DriverID, const bool Output)
|
||||
{
|
||||
dbg_api("%d, %d", DriverID, Output);
|
||||
// dbg_api("%d, %d", DriverID, Output);
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
int Timeout = 100000;
|
||||
@@ -379,7 +379,7 @@ namespace v0
|
||||
|
||||
uint8_t PS2ReadData(dev_t DriverID)
|
||||
{
|
||||
dbg_api("%d", DriverID);
|
||||
// dbg_api("%d", DriverID);
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
WaitOutput;
|
||||
@@ -571,7 +571,7 @@ namespace v0
|
||||
__PCIArray *head = nullptr;
|
||||
__PCIArray *array = nullptr;
|
||||
|
||||
foreach (auto &dev in Devices)
|
||||
for (auto &dev : Devices)
|
||||
{
|
||||
/* TODO: optimize memory allocation */
|
||||
PCI::PCIDevice *dptr = (PCI::PCIDevice *)vma->RequestPages(TO_PAGES(sizeof(PCI::PCIDevice)));
|
||||
@@ -710,6 +710,20 @@ namespace v0
|
||||
|
||||
return DriverManager->ReportInputEvent(DriverID, Report);
|
||||
}
|
||||
|
||||
dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device)
|
||||
{
|
||||
dbg_api("%d, %#lx", DriverID, Device);
|
||||
|
||||
return DriverManager->RegisterBlockDevice(DriverID, Device);
|
||||
}
|
||||
|
||||
int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID)
|
||||
{
|
||||
dbg_api("%d, %d", DriverID, DeviceID);
|
||||
|
||||
return DriverManager->UnregisterBlockDevice(DriverID, DeviceID);
|
||||
}
|
||||
}
|
||||
|
||||
struct APISymbols
|
||||
@@ -777,6 +791,8 @@ static struct APISymbols APISymbols_v0[] = {
|
||||
{"__RegisterDevice", (void *)v0::RegisterDevice},
|
||||
{"__UnregisterDevice", (void *)v0::UnregisterDevice},
|
||||
{"__ReportInputEvent", (void *)v0::ReportInputEvent},
|
||||
{"__RegisterBlockDevice", (void *)v0::RegisterBlockDevice},
|
||||
{"__UnregisterBlockDevice", (void *)v0::UnregisterBlockDevice},
|
||||
};
|
||||
|
||||
long __KernelUndefinedFunction(long arg0, long arg1, long arg2, long arg3,
|
||||
|
@@ -1,726 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
|
||||
#include <interface/driver.h>
|
||||
#include <interface/input.h>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <exec.hpp>
|
||||
#include <rand.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
/**
|
||||
* maj = 0
|
||||
* min:
|
||||
* 0 - <ROOT>
|
||||
* 1 - /proc/self
|
||||
*
|
||||
* maj = 1
|
||||
* min:
|
||||
* 0 - /dev/input/keyboard
|
||||
* 1 - /dev/input/mouse
|
||||
* ..- /dev/input/eventN
|
||||
*/
|
||||
|
||||
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %#lx", _Parent, Name, Result);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
if (basename == NULL)
|
||||
{
|
||||
error("Invalid name %s", Name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
for (const auto &child : Parent->Children)
|
||||
{
|
||||
debug("Comparing %s with %s", basename, child->Name.c_str());
|
||||
if (strcmp(child->Name.c_str(), basename) != 0)
|
||||
continue;
|
||||
|
||||
*Result = &child->Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Not found %s", Name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %d", _Parent, Name, Mode);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
/* We expect to be /dev or children of it */
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
auto _dev = new Manager::DeviceInode;
|
||||
_dev->Parent = nullptr;
|
||||
_dev->ParentInode = _Parent;
|
||||
_dev->Name = Name;
|
||||
_dev->Node.Device = Parent->Node.Device;
|
||||
_dev->Node.Mode = Mode;
|
||||
_dev->Node.Index = Parent->Node.Index + Parent->Children.size();
|
||||
_dev->Node.Offset = Parent->Children.size();
|
||||
Parent->Children.push_back(_dev);
|
||||
|
||||
*Result = &_dev->Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %d %d", Node, Size, Offset);
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
if (Size < sizeof(KeyboardReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(KeyboardReport);
|
||||
|
||||
KeyboardReport *report = (KeyboardReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
|
||||
return sizeof(KeyboardReport) * nReads;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
if (Size < sizeof(MouseReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(MouseReport);
|
||||
|
||||
MouseReport *report = (MouseReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalMouseInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalMouseInputReports.Read(report, nReads);
|
||||
return sizeof(MouseReport) * nReads;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
|
||||
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
|
||||
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
|
||||
{
|
||||
func("%#lx %d %d", Node, Flags, Mode);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
|
||||
return dOps->second.Ops->Open(Node, Flags, Mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __fs_Close(struct Inode *Node)
|
||||
{
|
||||
func("%#lx", Node);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
|
||||
return dOps->second.Ops->Close(Node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
func("%#lx %lu %#lx", Node, Request, Argp);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOSYS;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
|
||||
return dOps->second.Ops->Ioctl(Node, Request, Argp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__no_sanitize("alignment")
|
||||
ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
|
||||
|
||||
auto Node = (Manager::DeviceInode *)_Node;
|
||||
|
||||
off_t realOffset = Offset;
|
||||
|
||||
size_t totalSize = 0;
|
||||
uint16_t reclen = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
|
||||
if (Offset == 0)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
|
||||
if (totalSize + reclen >= Size)
|
||||
return -EINVAL;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = Node->Node.Index;
|
||||
ent->d_off = Offset++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
}
|
||||
|
||||
if (Offset <= 1)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
|
||||
if (totalSize + reclen >= Size)
|
||||
{
|
||||
if (realOffset == 1)
|
||||
return -EINVAL;
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
|
||||
if (Node->Parent)
|
||||
ent->d_ino = Node->Parent->Node->Index;
|
||||
else if (Node->ParentInode)
|
||||
ent->d_ino = Node->ParentInode->Index;
|
||||
else
|
||||
{
|
||||
warn("Parent is null for %s", Node->Name.c_str());
|
||||
ent->d_ino = Node->Node.Index;
|
||||
}
|
||||
ent->d_off = Offset++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(Node->Node.Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size())
|
||||
return -EINVAL;
|
||||
|
||||
off_t entries = 0;
|
||||
for (const auto &var : Node->Children)
|
||||
{
|
||||
debug("iterating \"%s\" inside \"%s\"", var->Name.c_str(), Node->Name.c_str());
|
||||
if (var->Node.Offset < realOffset)
|
||||
{
|
||||
debug("skipping \"%s\" (%d < %d)", var->Name.c_str(), var->Node.Offset, Offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entries >= Entries)
|
||||
break;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
|
||||
if (totalSize + reclen >= Size)
|
||||
break;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->Node.Index;
|
||||
ent->d_off = var->Node.Offset;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = IFTODT(var->Node.Mode);
|
||||
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
||||
|
||||
totalSize += reclen;
|
||||
entries++;
|
||||
}
|
||||
|
||||
if (totalSize + sizeof(struct kdirent) >= Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
void ManagerDaemonWrapper() { DriverManager->Daemon(); }
|
||||
|
||||
void Manager::Daemon()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
TaskManager->Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterInputDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
|
||||
dev_t DriverID, size_t i, const InodeOperations *Operations)
|
||||
{
|
||||
std::string prefix = "event";
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
|
||||
if (node)
|
||||
continue;
|
||||
|
||||
/* c rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFCHR;
|
||||
|
||||
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
|
||||
node->Node->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->Node;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
return -1; /* -Werror=return-type */
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterBlockDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
|
||||
dev_t DriverID, size_t i, const InodeOperations *Operations)
|
||||
{
|
||||
std::string prefix = "event";
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
|
||||
if (node)
|
||||
continue;
|
||||
|
||||
/* c rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFBLK;
|
||||
|
||||
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
|
||||
node->Node->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->Node;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
return -1; /* -Werror=return-type */
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
const auto dOpsEnd = dop->end();
|
||||
if (dOps != dOpsEnd)
|
||||
continue;
|
||||
|
||||
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
|
||||
switch (devType)
|
||||
{
|
||||
case DEVICE_TYPE_INPUT:
|
||||
return RegisterInputDevice(dop, DriverID, i, Operations);
|
||||
case DEVICE_TYPE_BLOCK:
|
||||
return RegisterBlockDevice(dop, DriverID, i, Operations);
|
||||
default:
|
||||
ReturnLogError(-1, "Invalid device type %d", Type);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
if (dOps != dop->end())
|
||||
continue;
|
||||
|
||||
FileNode *node = fs->GetByPath(name, devNode);
|
||||
if (node)
|
||||
ReturnLogError(-EEXIST, "Device file %s already exists", name);
|
||||
|
||||
node = fs->Create(devNode, name, mode);
|
||||
if (node == nullptr)
|
||||
ReturnLogError(-ENOMEM, "Failed to create device file %s", name);
|
||||
|
||||
node->Node->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->Node;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
return -1; /* -Werror=return-type */
|
||||
}
|
||||
|
||||
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
const auto dOps = dop->find(Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Device);
|
||||
dop->erase(dOps);
|
||||
fixme("remove eventX from /dev/input");
|
||||
fixme("delete InputReports");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
void *ptr = itr->second.vma->RequestPages(Pages);
|
||||
memset(ptr, 0, FROM_PAGES(Pages));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
itr->second.vma->FreePages(Pointer, Pages);
|
||||
}
|
||||
|
||||
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Report->Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
|
||||
|
||||
dOps->second.InputReports->Write(Report, 1);
|
||||
|
||||
switch (Report->Type)
|
||||
{
|
||||
case INPUT_TYPE_KEYBOARD:
|
||||
{
|
||||
KeyboardReport *kReport = &Report->Keyboard;
|
||||
GlobalKeyboardInputReports.Write(kReport, 1);
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_MOUSE:
|
||||
{
|
||||
MouseReport *mReport = &Report->Mouse;
|
||||
GlobalMouseInputReports.Write(mReport, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(!"Invalid input type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Manager::InitializeDaemonFS()
|
||||
{
|
||||
dev_t MinorID = 0;
|
||||
DeviceInode *_dev = new DeviceInode;
|
||||
_dev->Name = "dev";
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
Inode *dev = (Inode *)_dev;
|
||||
dev->Mode = mode;
|
||||
dev->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Device Virtual File System";
|
||||
fsi->RootName = "dev";
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps = {};
|
||||
fsi->Ops.Lookup = __fs_Lookup;
|
||||
fsi->Ops.Create = __fs_Create;
|
||||
fsi->Ops.Remove = nullptr;
|
||||
fsi->Ops.Rename = nullptr;
|
||||
fsi->Ops.Read = __fs_Read;
|
||||
fsi->Ops.Write = __fs_Write;
|
||||
fsi->Ops.Truncate = nullptr;
|
||||
fsi->Ops.Open = __fs_Open;
|
||||
fsi->Ops.Close = __fs_Close;
|
||||
fsi->Ops.Ioctl = __fs_Ioctl;
|
||||
fsi->Ops.ReadDir = __fs_Readdir;
|
||||
fsi->Ops.MkDir = nullptr;
|
||||
fsi->Ops.RmDir = nullptr;
|
||||
fsi->Ops.SymLink = nullptr;
|
||||
fsi->Ops.ReadLink = nullptr;
|
||||
fsi->Ops.Seek = nullptr;
|
||||
fsi->Ops.Stat = nullptr;
|
||||
|
||||
dev->Device = fs->RegisterFileSystem(fsi, dev);
|
||||
dev->SetDevice(0, MinorID++);
|
||||
MinorID++; /* 1 = /proc/self */
|
||||
|
||||
devNode = fs->Mount(fs->GetRoot(0), dev, "/dev");
|
||||
_dev->Parent = devNode->Parent;
|
||||
_dev->ParentInode = devNode->Parent->Node;
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
DeviceInode *input = new DeviceInode;
|
||||
input->Parent = devNode;
|
||||
input->ParentInode = devNode->Node;
|
||||
input->Name = "input";
|
||||
input->Node.Device = dev->Device;
|
||||
input->Node.Mode = mode;
|
||||
input->Node.Flags = I_FLAG_CACHE_KEEP;
|
||||
input->Node.Offset = _dev->Children.size();
|
||||
_dev->Children.push_back(input);
|
||||
devInputNode = fs->GetByPath("input", devNode);
|
||||
|
||||
auto createDevice = [](DeviceInode *p1, FileNode *p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
|
||||
{
|
||||
DeviceInode *device = new DeviceInode;
|
||||
device->Parent = p2;
|
||||
device->ParentInode = p2->Node;
|
||||
device->Name = name;
|
||||
device->Node.Device = p2->Node->Device;
|
||||
device->Node.Mode = mode;
|
||||
device->Node.SetDevice(maj, min);
|
||||
device->Node.Flags = I_FLAG_CACHE_KEEP;
|
||||
device->Node.Offset = p1->Children.size();
|
||||
p1->Children.push_back(device);
|
||||
};
|
||||
|
||||
MinorID = 0;
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "keyboard", 1, MinorID++, mode);
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "mouse", 1, MinorID++, mode);
|
||||
}
|
||||
}
|
483
Kernel/core/driver/dev.cpp
Normal file
483
Kernel/core/driver/dev.cpp
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
dev_t DeviceDirID;
|
||||
|
||||
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %#lx", _Parent, Name, Result);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
if (basename == NULL)
|
||||
{
|
||||
error("Invalid name %s", Name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
for (const auto &child : Parent->Children)
|
||||
{
|
||||
debug("Comparing %s with %s", basename, child->Name.c_str());
|
||||
if (strcmp(child->Name.c_str(), basename) != 0)
|
||||
continue;
|
||||
|
||||
*Result = &child->inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Not found %s", Name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %d", _Parent, Name, Mode);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
/* We expect to be /dev or children of it */
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
auto _dev = new Manager::DeviceInode;
|
||||
_dev->Parent = nullptr;
|
||||
_dev->ParentInode = _Parent;
|
||||
_dev->Name = Name;
|
||||
_dev->inode.Device = Parent->inode.Device;
|
||||
_dev->inode.Mode = Mode;
|
||||
_dev->inode.Index = Parent->inode.Index + Parent->Children.size();
|
||||
_dev->inode.Offset = Parent->Children.size();
|
||||
Parent->Children.push_back(_dev);
|
||||
|
||||
*Result = &_dev->inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %d %d", Node, Size, Offset);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
if (Size < sizeof(KeyboardReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(KeyboardReport);
|
||||
|
||||
KeyboardReport *report = (KeyboardReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
|
||||
return sizeof(KeyboardReport) * nReads;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
if (Size < sizeof(MouseReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(MouseReport);
|
||||
|
||||
MouseReport *report = (MouseReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalMouseInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalMouseInputReports.Read(report, nReads);
|
||||
return sizeof(MouseReport) * nReads;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
|
||||
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
|
||||
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
|
||||
{
|
||||
func("%#lx %d %d", Node, Flags, Mode);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
|
||||
return dOps->second.Ops->Open(Node, Flags, Mode);
|
||||
}
|
||||
|
||||
int __fs_Close(struct Inode *Node)
|
||||
{
|
||||
func("%#lx", Node);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
|
||||
return dOps->second.Ops->Close(Node);
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
func("%#lx %lu %#lx", Node, Request, Argp);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOSYS;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
|
||||
return dOps->second.Ops->Ioctl(Node, Request, Argp);
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
|
||||
|
||||
auto node = (Manager::DeviceInode *)_Node;
|
||||
off_t realOffset = Offset;
|
||||
size_t totalSize = 0;
|
||||
uint16_t reclen = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
|
||||
if (!S_ISDIR(node->inode.Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
if (Offset == 0)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
return -EINVAL;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = node->inode.Index;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
Offset++;
|
||||
}
|
||||
|
||||
if (Offset == 1)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
return totalSize;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
if (node->Parent)
|
||||
ent->d_ino = node->Parent->inode->Index;
|
||||
else if (node->ParentInode)
|
||||
ent->d_ino = node->ParentInode->Index;
|
||||
else
|
||||
ent->d_ino = node->inode.Index;
|
||||
ent->d_off = 1;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
Offset++;
|
||||
}
|
||||
|
||||
off_t entryIndex = 0;
|
||||
for (const auto &var : node->Children)
|
||||
{
|
||||
if (entryIndex + 2 < realOffset)
|
||||
{
|
||||
entryIndex++;
|
||||
continue;
|
||||
}
|
||||
if (Entries && entryIndex >= Entries)
|
||||
break;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
break;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->inode.Index;
|
||||
ent->d_off = entryIndex + 2;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = IFTODT(var->inode.Mode);
|
||||
strcpy(ent->d_name, var->Name.c_str());
|
||||
totalSize += reclen;
|
||||
entryIndex++;
|
||||
}
|
||||
|
||||
if (totalSize + offsetof(struct kdirent, d_name) + 1 > Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int __fs_Stat(struct Inode *_Node, struct kstat *Stat)
|
||||
{
|
||||
func("%#lx %#lx", _Node, Stat);
|
||||
auto node = (Manager::DeviceInode *)_Node;
|
||||
|
||||
assert(node != nullptr);
|
||||
assert(Stat != nullptr);
|
||||
|
||||
Stat->Device = node->inode.Device;
|
||||
Stat->Index = node->inode.Index;
|
||||
Stat->HardLinks = 1;
|
||||
Stat->UserID = 0;
|
||||
Stat->GroupID = 0;
|
||||
Stat->RawDevice = node->inode.RawDevice;
|
||||
Stat->Size = node->Size;
|
||||
Stat->AccessTime = node->AccessTime;
|
||||
Stat->ModifyTime = node->ModifyTime;
|
||||
Stat->ChangeTime = node->ChangeTime;
|
||||
Stat->BlockSize = node->BlockSize;
|
||||
Stat->Blocks = node->Blocks;
|
||||
Stat->Attribute = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Manager::InitializeDeviceDirectory()
|
||||
{
|
||||
dev_t MinorID = 0;
|
||||
DeviceInode *_dev = new DeviceInode;
|
||||
_dev->Name = "dev";
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
Inode *dev = (Inode *)_dev;
|
||||
dev->Mode = mode;
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "devfs";
|
||||
fsi->SuperOps = {};
|
||||
fsi->Ops.Lookup = __fs_Lookup;
|
||||
fsi->Ops.Create = __fs_Create;
|
||||
fsi->Ops.Remove = nullptr;
|
||||
fsi->Ops.Rename = nullptr;
|
||||
fsi->Ops.Read = __fs_Read;
|
||||
fsi->Ops.Write = __fs_Write;
|
||||
fsi->Ops.Truncate = nullptr;
|
||||
fsi->Ops.Open = __fs_Open;
|
||||
fsi->Ops.Close = __fs_Close;
|
||||
fsi->Ops.Ioctl = __fs_Ioctl;
|
||||
fsi->Ops.ReadDir = __fs_Readdir;
|
||||
fsi->Ops.MkDir = nullptr;
|
||||
fsi->Ops.RmDir = nullptr;
|
||||
fsi->Ops.SymLink = nullptr;
|
||||
fsi->Ops.ReadLink = nullptr;
|
||||
fsi->Ops.Seek = nullptr;
|
||||
fsi->Ops.Stat = __fs_Stat;
|
||||
|
||||
DeviceDirID = dev->Device = fs->RegisterFileSystem(fsi);
|
||||
dev->SetDevice(0, MinorID++);
|
||||
|
||||
Node root = fs->GetRoot(0);
|
||||
devNode = fs->Mount(root, dev, "dev", fsi);
|
||||
assert(devNode->Parent != nullptr);
|
||||
|
||||
_dev->Parent = devNode->Parent;
|
||||
_dev->ParentInode = devNode->Parent->inode;
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
DeviceInode *blk = new DeviceInode;
|
||||
blk->Parent = devNode;
|
||||
blk->ParentInode = devNode->inode;
|
||||
blk->Name = "block";
|
||||
blk->inode.Device = dev->Device;
|
||||
blk->inode.Mode = mode;
|
||||
blk->inode.Offset = _dev->Children.size();
|
||||
_dev->Children.push_back(blk);
|
||||
devBlockNode = fs->Lookup(devNode, "block");
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
DeviceInode *input = new DeviceInode;
|
||||
input->Parent = devNode;
|
||||
input->ParentInode = devNode->inode;
|
||||
input->Name = "input";
|
||||
input->inode.Device = dev->Device;
|
||||
input->inode.Mode = mode;
|
||||
input->inode.Offset = _dev->Children.size();
|
||||
_dev->Children.push_back(input);
|
||||
devInputNode = fs->Lookup(devNode, "input");
|
||||
|
||||
auto createDevice = [](DeviceInode *p1, Node p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
|
||||
{
|
||||
DeviceInode *device = new DeviceInode;
|
||||
device->Parent = p2;
|
||||
device->ParentInode = p2->inode;
|
||||
device->Name = name;
|
||||
device->inode.Device = p2->inode->Device;
|
||||
device->inode.Mode = mode;
|
||||
device->inode.SetDevice(maj, min);
|
||||
device->inode.Offset = p1->Children.size();
|
||||
p1->Children.push_back(device);
|
||||
};
|
||||
|
||||
MinorID = 0;
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "keyboard", DeviceDirID, MinorID++, mode);
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "mouse", DeviceDirID, MinorID++, mode);
|
||||
}
|
||||
}
|
@@ -26,14 +26,48 @@
|
||||
#include <exec.hpp>
|
||||
#include <rand.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <sha512.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
extern const char *trusted_drivers[];
|
||||
extern const __SIZE_TYPE__ trusted_drivers_count;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
bool Manager::IsDriverTrusted(Node File)
|
||||
{
|
||||
kstat st;
|
||||
fs->Stat(File, &st);
|
||||
std::unique_ptr<uint8_t[]> ptr(new uint8_t[st.Size]);
|
||||
fs->Read(File, ptr.get(), st.Size, 0);
|
||||
uint8_t *sha = sha512_sum(ptr.get(), st.Size);
|
||||
char hash_str[129];
|
||||
for (int j = 0; j < 64; j++)
|
||||
sprintf(hash_str + j * 2, "%02x", sha[j]);
|
||||
hash_str[128] = '\0';
|
||||
|
||||
for (__SIZE_TYPE__ i = 0; i < trusted_drivers_count; i++)
|
||||
{
|
||||
if (strcmp(hash_str, trusted_drivers[i]) == 0)
|
||||
{
|
||||
kfree(sha);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace("Expected \"%s\" but got \"%s\" for driver %s",
|
||||
trusted_drivers[i], hash_str, File->GetName().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
kfree(sha);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Manager::PreloadDrivers()
|
||||
{
|
||||
debug("Initializing driver manager");
|
||||
@@ -68,7 +102,8 @@ namespace Driver
|
||||
}
|
||||
|
||||
const char *DriverDirectory = Config.DriverDirectory;
|
||||
FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node drvDirNode = fs->Lookup(root, DriverDirectory);
|
||||
if (!drvDirNode)
|
||||
{
|
||||
error("Failed to open driver directory %s", DriverDirectory);
|
||||
@@ -76,15 +111,25 @@ namespace Driver
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (const auto &drvNode in drvDirNode->Children)
|
||||
for (const auto &drvNode : fs->ReadDirectory(drvDirNode))
|
||||
{
|
||||
debug("Checking driver %s", drvNode->Path.c_str());
|
||||
if (!drvNode->IsRegularFile())
|
||||
continue;
|
||||
|
||||
if (std::string(drvNode->Path).find(".drv") == std::string::npos)
|
||||
continue;
|
||||
|
||||
if (Execute::GetBinaryType(drvNode->Path) != Execute::BinTypeELF)
|
||||
{
|
||||
error("Driver %s is not an ELF binary", drvNode->Path.c_str());
|
||||
error("Driver %s is not an ELF binary", drvNode->GetPath().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsDriverTrusted(drvNode))
|
||||
{
|
||||
error("Driver %s is not trusted", drvNode->GetName().c_str());
|
||||
KPrint("%s is not in the list of trusted drivers", drvNode->GetName().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -125,7 +170,7 @@ namespace Driver
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (auto &var in Drivers)
|
||||
for (auto &var : Drivers)
|
||||
{
|
||||
DriverObject &Drv = var.second;
|
||||
|
||||
@@ -180,7 +225,7 @@ namespace Driver
|
||||
|
||||
void Manager::UnloadAllDrivers()
|
||||
{
|
||||
foreach (auto &var in Drivers)
|
||||
for (auto &var : Drivers)
|
||||
{
|
||||
DriverObject *Drv = &var.second;
|
||||
if (!Drv->Initialized)
|
||||
@@ -196,7 +241,7 @@ namespace Driver
|
||||
|
||||
if (!Drv->InterruptHandlers->empty())
|
||||
{
|
||||
foreach (auto &rInt in * Drv->InterruptHandlers)
|
||||
for (auto &rInt : *Drv->InterruptHandlers)
|
||||
{
|
||||
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))rInt.second);
|
||||
}
|
||||
@@ -212,7 +257,7 @@ namespace Driver
|
||||
if (Drivers.size() == 0)
|
||||
return;
|
||||
|
||||
foreach (auto Driver in Drivers)
|
||||
for (auto Driver : Drivers)
|
||||
{
|
||||
if (!Driver.second.Initialized)
|
||||
continue;
|
||||
@@ -229,12 +274,12 @@ namespace Driver
|
||||
}
|
||||
}
|
||||
|
||||
int Manager::LoadDriverFile(DriverObject &Drv, FileNode *File)
|
||||
int Manager::LoadDriverFile(DriverObject &Drv, Node File)
|
||||
{
|
||||
trace("Loading driver %s in memory", File->Name.c_str());
|
||||
|
||||
Elf_Ehdr ELFHeader{};
|
||||
File->Read(&ELFHeader, sizeof(Elf_Ehdr), 0);
|
||||
fs->Read(File, &ELFHeader, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
AssertReturnError(ELFHeader.e_ident[EI_CLASS] == ELFCLASS64, -ENOEXEC);
|
||||
AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC);
|
||||
@@ -251,7 +296,7 @@ namespace Driver
|
||||
Elf_Phdr phdr{};
|
||||
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
if (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC)
|
||||
{
|
||||
if (segSize < phdr.p_vaddr + phdr.p_memsz)
|
||||
@@ -262,7 +307,7 @@ namespace Driver
|
||||
if (phdr.p_type == PT_INTERP)
|
||||
{
|
||||
char interp[17];
|
||||
File->Read(interp, sizeof(interp), phdr.p_offset);
|
||||
fs->Read(File, interp, sizeof(interp), phdr.p_offset);
|
||||
if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0)
|
||||
{
|
||||
error("Interpreter is not /boot/fennix.elf");
|
||||
@@ -282,13 +327,13 @@ namespace Driver
|
||||
Elf_Shdr shstrtab{};
|
||||
Elf_Shdr shdr{};
|
||||
__DriverInfo driverInfo{};
|
||||
File->Read(&shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize));
|
||||
fs->Read(File, &shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize));
|
||||
for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++)
|
||||
{
|
||||
if (i == ELFHeader.e_shstrndx)
|
||||
continue;
|
||||
|
||||
File->Read(&shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize));
|
||||
fs->Read(File, &shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize));
|
||||
|
||||
switch (shdr.sh_type)
|
||||
{
|
||||
@@ -306,11 +351,11 @@ namespace Driver
|
||||
}
|
||||
|
||||
char symName[16];
|
||||
File->Read(symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name);
|
||||
fs->Read(File, symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name);
|
||||
if (strcmp(symName, ".driver.info") != 0)
|
||||
continue;
|
||||
|
||||
File->Read(&driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
|
||||
fs->Read(File, &driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
|
||||
|
||||
/* Perform relocations */
|
||||
driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name);
|
||||
@@ -319,17 +364,17 @@ namespace Driver
|
||||
driverInfo.License = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.License);
|
||||
}
|
||||
|
||||
for (size_t h = 0; h < (sht_symtab.sh_size / sizeof(Elf64_Sym)); h++)
|
||||
for (size_t h = 0; h < (sht_symtab.sh_size / sizeof(Elf_Sym)); h++)
|
||||
{
|
||||
Elf64_Sym symEntry{};
|
||||
uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf64_Sym));
|
||||
File->Read(&symEntry, sizeof(Elf64_Sym), symOffset);
|
||||
Elf_Sym symEntry{};
|
||||
uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf_Sym));
|
||||
fs->Read(File, &symEntry, sizeof(Elf_Sym), symOffset);
|
||||
|
||||
if (symEntry.st_name == 0)
|
||||
continue;
|
||||
|
||||
char symName[16];
|
||||
File->Read(symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name);
|
||||
fs->Read(File, symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name);
|
||||
|
||||
switch (symEntry.st_shndx)
|
||||
{
|
||||
@@ -361,7 +406,7 @@ namespace Driver
|
||||
|
||||
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
|
||||
switch (phdr.p_type)
|
||||
{
|
||||
@@ -377,7 +422,7 @@ namespace Driver
|
||||
phdr.p_filesz, phdr.p_memsz);
|
||||
|
||||
if (phdr.p_filesz > 0)
|
||||
File->Read(dest, phdr.p_filesz, phdr.p_offset);
|
||||
fs->Read(File, (void *)dest, phdr.p_filesz, phdr.p_offset);
|
||||
|
||||
if (phdr.p_memsz - phdr.p_filesz > 0)
|
||||
{
|
||||
@@ -433,10 +478,10 @@ namespace Driver
|
||||
{
|
||||
AssertReturnError(relaSize != nullptr, -ENOEXEC);
|
||||
|
||||
Elf64_Rela *rela = (Elf64_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr);
|
||||
for (size_t i = 0; i < (relaSize->d_un.d_val / sizeof(Elf64_Rela)); i++)
|
||||
Elf_Rela *rela = (Elf_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr);
|
||||
for (size_t i = 0; i < (relaSize->d_un.d_val / sizeof(Elf_Rela)); i++)
|
||||
{
|
||||
Elf64_Rela *r = &rela[i];
|
||||
Elf_Rela *r = &rela[i];
|
||||
uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset);
|
||||
uintptr_t relocTarget = 0;
|
||||
|
||||
@@ -456,8 +501,7 @@ namespace Driver
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("Unhandled relocation type: %#lx",
|
||||
ELF64_R_TYPE(r->r_info));
|
||||
fixme("Unhandled relocation type: %#lx", ELF_R_TYPE(r->r_info));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -473,26 +517,26 @@ namespace Driver
|
||||
{
|
||||
AssertReturnError(pltrelSize != nullptr, -ENOEXEC);
|
||||
|
||||
std::vector<Elf64_Dyn> symtab = Execute::ELFGetDynamicTag_x86_64(File, DT_SYMTAB);
|
||||
Elf64_Sym *symbols = (Elf64_Sym *)((uintptr_t)Drv.BaseAddress + symtab[0].d_un.d_ptr);
|
||||
std::vector<Elf_Dyn> symtab = Execute::ELFGetDynamicTag(File, DT_SYMTAB);
|
||||
Elf_Sym *symbols = (Elf_Sym *)((uintptr_t)Drv.BaseAddress + symtab[0].d_un.d_ptr);
|
||||
|
||||
std::vector<Elf64_Dyn> StrTab = Execute::ELFGetDynamicTag_x86_64(File, DT_STRTAB);
|
||||
char *DynStr = (char *)((uintptr_t)Drv.BaseAddress + StrTab[0].d_un.d_ptr);
|
||||
std::vector<Elf_Dyn> StrTab = Execute::ELFGetDynamicTag(File, DT_STRTAB);
|
||||
char *dynStr = (char *)((uintptr_t)Drv.BaseAddress + StrTab[0].d_un.d_ptr);
|
||||
|
||||
Elf64_Rela *rela = (Elf64_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr);
|
||||
for (size_t i = 0; i < (pltrelSize->d_un.d_val / sizeof(Elf64_Rela)); i++)
|
||||
Elf_Rela *rela = (Elf_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr);
|
||||
for (size_t i = 0; i < (pltrelSize->d_un.d_val / sizeof(Elf_Rela)); i++)
|
||||
{
|
||||
Elf64_Rela *r = &rela[i];
|
||||
Elf_Rela *r = &rela[i];
|
||||
uintptr_t *reloc = (uintptr_t *)(Drv.BaseAddress + r->r_offset);
|
||||
|
||||
switch (ELF64_R_TYPE(r->r_info))
|
||||
switch (ELF_R_TYPE(r->r_info))
|
||||
{
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
{
|
||||
Elf64_Xword symIndex = ELF64_R_SYM(r->r_info);
|
||||
Elf64_Sym *sym = symbols + symIndex;
|
||||
Elf_Xword symIndex = ELF_R_SYM(r->r_info);
|
||||
Elf_Sym *sym = symbols + symIndex;
|
||||
|
||||
const char *symName = DynStr + sym->st_name;
|
||||
const char *symName = dynStr + sym->st_name;
|
||||
debug("Resolving symbol %s", symName);
|
||||
|
||||
*reloc = (uintptr_t)GetSymbolByName(symName, driverInfo.Version.APIVersion);
|
||||
@@ -500,8 +544,7 @@ namespace Driver
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("Unhandled relocation type: %#lx",
|
||||
ELF64_R_TYPE(r->r_info));
|
||||
fixme("Unhandled relocation type: %#lx", ELF_R_TYPE(r->r_info));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -578,7 +621,8 @@ namespace Driver
|
||||
delete Drv.DeviceOperations;
|
||||
|
||||
/* Reload the driver */
|
||||
FileNode *drvNode = fs->GetByPath(Drv.Path.c_str(), nullptr);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node drvNode = fs->Lookup(root, Drv.Path);
|
||||
if (!drvNode)
|
||||
{
|
||||
error("Failed to open driver file %s", Drv.Path.c_str());
|
||||
@@ -642,7 +686,7 @@ namespace Driver
|
||||
newDrvObj.Initialized = true;
|
||||
}
|
||||
|
||||
Manager::Manager() { this->InitializeDaemonFS(); }
|
||||
Manager::Manager() { this->InitializeDeviceDirectory(); }
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
|
256
Kernel/core/driver/manager.cpp
Normal file
256
Kernel/core/driver/manager.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
|
||||
#include <interface/driver.h>
|
||||
#include <interface/input.h>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <exec.hpp>
|
||||
#include <rand.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
const auto dOpsEnd = dop->end();
|
||||
if (dOps != dOpsEnd)
|
||||
continue;
|
||||
|
||||
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
|
||||
switch (devType)
|
||||
{
|
||||
case DEVICE_TYPE_INPUT:
|
||||
{
|
||||
std::string prefix = "event";
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
Node node = fs->Lookup(devInputNode, deviceName);
|
||||
if (node)
|
||||
continue;
|
||||
|
||||
/* c rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFCHR;
|
||||
|
||||
node = fs->Create(devInputNode, deviceName, mode);
|
||||
node->inode->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->inode;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
default:
|
||||
ReturnLogError(-EINVAL, "Invalid device type %d", Type);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
if (dOps != dop->end())
|
||||
continue;
|
||||
|
||||
eNode node = fs->Lookup(devNode, name);
|
||||
if (node == true)
|
||||
ReturnLogError(-EEXIST, "Device file %s already exists", name);
|
||||
|
||||
node = fs->Create(devNode, name, mode);
|
||||
if (node == false)
|
||||
ReturnLogError(-node.Error, "Failed to create device file %s; %s", name, node.what());
|
||||
|
||||
node.Value->inode->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node.Value->inode;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
const auto dOps = dop->find(Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Device);
|
||||
dop->erase(dOps);
|
||||
fixme("remove eventX from /dev/input");
|
||||
fixme("delete InputReports");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
std::string prefix = Device->Name;
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
Node node = fs->Lookup(devBlockNode, deviceName);
|
||||
if (node)
|
||||
continue;
|
||||
debug("Creating \"%s\"", deviceName.c_str());
|
||||
|
||||
/* b rwx --- --- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IFBLK;
|
||||
|
||||
node = fs->Create(devBlockNode, deviceName, mode);
|
||||
node->inode->SetDevice(DriverID, j);
|
||||
auto devNode = (Manager::DeviceInode *)node->inode;
|
||||
devNode->Size = Device->Size;
|
||||
devNode->BlockSize = Device->BlockSize;
|
||||
devNode->Blocks = Device->BlockCount;
|
||||
devNode->inode.PrivateData = Device->PrivateData;
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Device->Ops;
|
||||
dh.Node = node->inode;
|
||||
dop->insert({j, std::move(dh)});
|
||||
debug("dh ops:%#lx node:%#lx %d", dh.Ops, dh.Node, j);
|
||||
return j;
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
int Manager::UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
const auto dOps = dop->find(DeviceID);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", DeviceID);
|
||||
dop->erase(dOps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
void *ptr = itr->second.vma->RequestPages(Pages);
|
||||
memset(ptr, 0, FROM_PAGES(Pages));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
itr->second.vma->FreePages(Pointer, Pages);
|
||||
}
|
||||
|
||||
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Report->Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
|
||||
|
||||
dOps->second.InputReports->Write(Report, 1);
|
||||
|
||||
switch (Report->Type)
|
||||
{
|
||||
case INPUT_TYPE_KEYBOARD:
|
||||
{
|
||||
KeyboardReport *kReport = &Report->Keyboard;
|
||||
GlobalKeyboardInputReports.Write(kReport, 1);
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_MOUSE:
|
||||
{
|
||||
MouseReport *mReport = &Report->Mouse;
|
||||
GlobalMouseInputReports.Write(mReport, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(!"Invalid input type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -331,6 +331,80 @@ namespace Driver
|
||||
: ScanCodeConversionTableLower[ScanCode];
|
||||
}
|
||||
|
||||
char GetControlCharacter(KeyScanCodes ScanCode)
|
||||
{
|
||||
ScanCode = static_cast<KeyScanCodes>(static_cast<int>(ScanCode) & 0x7F); /* Remove KEY_PRESSED bit */
|
||||
switch (ScanCode)
|
||||
{
|
||||
case KEY_2:
|
||||
return 0x00; /* Ctrl-@ (NUL) */
|
||||
case KEY_A:
|
||||
return 0x01; /* Ctrl-A (SOH) */
|
||||
case KEY_B:
|
||||
return 0x02; /* Ctrl-B (STX) */
|
||||
case KEY_C:
|
||||
return 0x03; /* Ctrl-C (ETX) */
|
||||
case KEY_D:
|
||||
return 0x04; /* Ctrl-D (EOT) */
|
||||
case KEY_E:
|
||||
return 0x05; /* Ctrl-E (ENQ) */
|
||||
case KEY_F:
|
||||
return 0x06; /* Ctrl-F (ACK) */
|
||||
case KEY_G:
|
||||
return 0x07; /* Ctrl-G (BEL) */
|
||||
case KEY_H:
|
||||
return 0x08; /* Ctrl-H (BS) */
|
||||
case KEY_I:
|
||||
return 0x09; /* Ctrl-I (HT) */
|
||||
case KEY_J:
|
||||
return 0x0A; /* Ctrl-J (LF) */
|
||||
case KEY_K:
|
||||
return 0x0B; /* Ctrl-K (VT) */
|
||||
case KEY_L:
|
||||
return 0x0C; /* Ctrl-L (FF) */
|
||||
case KEY_M:
|
||||
return 0x0D; /* Ctrl-M (CR) */
|
||||
case KEY_N:
|
||||
return 0x0E; /* Ctrl-N (SO) */
|
||||
case KEY_O:
|
||||
return 0x0F; /* Ctrl-O (SI) */
|
||||
case KEY_P:
|
||||
return 0x10; /* Ctrl-P (DLE) */
|
||||
case KEY_Q:
|
||||
return 0x11; /* Ctrl-Q (DC1) */
|
||||
case KEY_R:
|
||||
return 0x12; /* Ctrl-R (DC2) */
|
||||
case KEY_S:
|
||||
return 0x13; /* Ctrl-S (DC3) */
|
||||
case KEY_T:
|
||||
return 0x14; /* Ctrl-T (DC4) */
|
||||
case KEY_U:
|
||||
return 0x15; /* Ctrl-U (NAK) */
|
||||
case KEY_V:
|
||||
return 0x16; /* Ctrl-V (SYN) */
|
||||
case KEY_W:
|
||||
return 0x17; /* Ctrl-W (ETB) */
|
||||
case KEY_X:
|
||||
return 0x18; /* Ctrl-X (CAN) */
|
||||
case KEY_Y:
|
||||
return 0x19; /* Ctrl-Y (EM) */
|
||||
case KEY_Z:
|
||||
return 0x1A; /* Ctrl-Z (SUB) */
|
||||
case KEY_LEFT_BRACKET:
|
||||
return 0x1B; /* Ctrl-[ (ESC) */
|
||||
case KEY_BACKSLASH:
|
||||
return 0x1C; /* Ctrl-\ (FS) */
|
||||
case KEY_RIGHT_BRACKET:
|
||||
return 0x1D; /* Ctrl-] (GS) */
|
||||
case KEY_6:
|
||||
return 0x1E; /* Ctrl-^ (RS) */
|
||||
case KEY_MINUS:
|
||||
return 0x1F; /* Ctrl-_ (US) */
|
||||
default:
|
||||
return 0x00; /* Not a control character */
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidChar(uint8_t ScanCode)
|
||||
{
|
||||
ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */
|
||||
|
@@ -191,7 +191,7 @@ namespace Interrupts
|
||||
void *ctx, bool Critical)
|
||||
{
|
||||
/* Just log a warning if the interrupt is already registered. */
|
||||
foreach (auto ev in RegisteredEvents)
|
||||
for (auto ev : RegisteredEvents)
|
||||
{
|
||||
if (ev.IRQ == InterruptNumber &&
|
||||
ev.Callback == Callback)
|
||||
@@ -264,7 +264,7 @@ namespace Interrupts
|
||||
warn("IRQ%d not found.", InterruptNumber);
|
||||
}
|
||||
|
||||
nsa inline void ReturnFromInterrupt()
|
||||
nsa hot inline void ReturnFromInterrupt()
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
CPUData *CoreData = GetCurrentCPU();
|
||||
@@ -279,7 +279,7 @@ namespace Interrupts
|
||||
{ return a.Priority < b.Priority; });
|
||||
|
||||
#ifdef DEBUG
|
||||
foreach (auto ev in RegisteredEvents)
|
||||
for (auto ev : RegisteredEvents)
|
||||
{
|
||||
void *fct = ev.IsHandler
|
||||
? ev.Data
|
||||
@@ -302,14 +302,14 @@ namespace Interrupts
|
||||
}
|
||||
else
|
||||
fixme("APIC not found for core %d", Core);
|
||||
// TODO: Handle PIC too
|
||||
// TODO: Handle PIC too
|
||||
|
||||
#endif
|
||||
assert(!"EOI not handled.");
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
extern "C" nsa void MainInterruptHandler(void *Data)
|
||||
extern "C" nsa hot void MainInterruptHandler(void *Data)
|
||||
{
|
||||
class AutoSwitchPageTable
|
||||
{
|
||||
@@ -384,7 +384,7 @@ namespace Interrupts
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" nsa void SchedulerInterruptHandler(void *Data)
|
||||
extern "C" nsa hot void SchedulerInterruptHandler(void *Data)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
KernelPageTable->Update();
|
||||
@@ -421,13 +421,12 @@ namespace Interrupts
|
||||
|
||||
Handler::Handler(int InterruptNumber, bool Critical)
|
||||
{
|
||||
foreach (auto ev in RegisteredEvents)
|
||||
for (auto ev : RegisteredEvents)
|
||||
{
|
||||
if (ev.IRQ == InterruptNumber)
|
||||
{
|
||||
warn("IRQ%d is already registered.",
|
||||
InterruptNumber);
|
||||
}
|
||||
if (ev.IRQ != InterruptNumber)
|
||||
continue;
|
||||
|
||||
warn("IRQ%d is already registered.", InterruptNumber);
|
||||
}
|
||||
|
||||
this->InterruptNumber = InterruptNumber;
|
||||
@@ -441,15 +440,12 @@ namespace Interrupts
|
||||
0, /* Priority */
|
||||
Critical}; /* Critical */
|
||||
RegisteredEvents.push_back(newEvent);
|
||||
debug("Registered interrupt handler for IRQ%d.",
|
||||
InterruptNumber);
|
||||
debug("Registered interrupt handler for IRQ%d.", InterruptNumber);
|
||||
}
|
||||
|
||||
Handler::Handler(PCI::PCIDevice Device, bool Critical)
|
||||
: Handler(((PCI::PCIHeader0 *)Device.Header)->InterruptLine, Critical)
|
||||
{
|
||||
PCI::PCIHeader0 *hdr0 =
|
||||
(PCI::PCIHeader0 *)Device.Header;
|
||||
Handler(hdr0->InterruptLine, Critical);
|
||||
}
|
||||
|
||||
Handler::Handler()
|
||||
@@ -459,16 +455,14 @@ namespace Interrupts
|
||||
|
||||
Handler::~Handler()
|
||||
{
|
||||
debug("Unregistering interrupt handler for IRQ%d.",
|
||||
this->InterruptNumber);
|
||||
|
||||
debug("Unregistering interrupt handler for IRQ%d.", this->InterruptNumber);
|
||||
forItr(itr, RegisteredEvents)
|
||||
{
|
||||
if (itr->IRQ == this->InterruptNumber)
|
||||
{
|
||||
RegisteredEvents.erase(itr);
|
||||
return;
|
||||
}
|
||||
if (itr->IRQ != this->InterruptNumber)
|
||||
continue;
|
||||
|
||||
RegisteredEvents.erase(itr);
|
||||
return;
|
||||
}
|
||||
warn("Event %d not found.", this->InterruptNumber);
|
||||
}
|
||||
|
@@ -195,7 +195,7 @@ void LockClass::TimeoutDeadLock(SpinLockData &Lock, uint64_t Timeout)
|
||||
if (CoreData != nullptr)
|
||||
CCore = CoreData->ID;
|
||||
|
||||
uint64_t Counter = TimeManager->GetCounter();
|
||||
uint64_t Counter = TimeManager->GetTimeNs();
|
||||
|
||||
warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. Timeout in %ld (%ld ticks remaining).",
|
||||
Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count, Lock.Count > 1 ? "locks" : "lock",
|
||||
@@ -235,8 +235,7 @@ Retry:
|
||||
if (i >= DEADLOCK_TIMEOUT)
|
||||
{
|
||||
if (Target.load() == 0)
|
||||
Target.store(TimeManager->CalculateTarget(Timeout,
|
||||
Time::Units::Milliseconds));
|
||||
Target.store(TimeManager->GetTimeNs() + Timeout);
|
||||
TimeoutDeadLock(LockData, Target.load());
|
||||
goto Retry;
|
||||
}
|
||||
|
@@ -28,8 +28,7 @@
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
__no_sanitize("alignment") void Physical::FindBitmapRegion(uintptr_t &BitmapAddress,
|
||||
size_t &BitmapAddressSize)
|
||||
__no_sanitize("alignment") void Physical::FindBitmapRegion(uintptr_t &BitmapAddress, size_t &BitmapAddressSize)
|
||||
{
|
||||
size_t BitmapSize = (size_t)(bInfo.Memory.Size / PAGE_SIZE) / 8 + 1;
|
||||
|
||||
@@ -47,24 +46,19 @@ namespace Memory
|
||||
uintptr_t RSDPStart = 0x0;
|
||||
uintptr_t RSDPEnd = 0x0;
|
||||
|
||||
if (bInfo.Kernel.Symbols.Num &&
|
||||
bInfo.Kernel.Symbols.EntSize &&
|
||||
bInfo.Kernel.Symbols.Shndx)
|
||||
if (bInfo.Kernel.Symbols.Num && bInfo.Kernel.Symbols.EntSize && bInfo.Kernel.Symbols.Shndx)
|
||||
{
|
||||
char *sections = r_cst(char *, bInfo.Kernel.Symbols.Sections);
|
||||
|
||||
SectionsStart = (uintptr_t)sections;
|
||||
SectionsEnd = (uintptr_t)sections + bInfo.Kernel.Symbols.EntSize *
|
||||
bInfo.Kernel.Symbols.Num;
|
||||
SectionsEnd = (uintptr_t)sections + bInfo.Kernel.Symbols.EntSize * bInfo.Kernel.Symbols.Num;
|
||||
|
||||
for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i)
|
||||
{
|
||||
Elf_Shdr *sym = (Elf_Shdr *)§ions[bInfo.Kernel.Symbols.EntSize * i];
|
||||
Elf_Shdr *str = (Elf_Shdr *)§ions[bInfo.Kernel.Symbols.EntSize *
|
||||
sym->sh_link];
|
||||
Elf_Shdr *str = (Elf_Shdr *)§ions[bInfo.Kernel.Symbols.EntSize * sym->sh_link];
|
||||
|
||||
if (sym->sh_type == SHT_SYMTAB &&
|
||||
str->sh_type == SHT_STRTAB)
|
||||
if (sym->sh_type == SHT_SYMTAB && str->sh_type == SHT_STRTAB)
|
||||
{
|
||||
Symbols = (uintptr_t)sym->sh_addr;
|
||||
StringAddress = (uintptr_t)str->sh_addr;
|
||||
@@ -95,8 +89,7 @@ namespace Memory
|
||||
|
||||
if (Memory::Virtual().Check(ACPIPtr))
|
||||
{
|
||||
size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) /
|
||||
(XSDT ? 8 : 4));
|
||||
size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) / (XSDT ? 8 : 4));
|
||||
debug("There are %d ACPI tables", TableSize);
|
||||
}
|
||||
#endif
|
||||
@@ -131,6 +124,7 @@ namespace Memory
|
||||
{
|
||||
uintptr_t Start;
|
||||
uintptr_t End;
|
||||
char Description[16];
|
||||
};
|
||||
|
||||
auto SortAddresses = [](AddrRange *Array, size_t n)
|
||||
@@ -151,61 +145,57 @@ namespace Memory
|
||||
|
||||
AddrRange PtrArray[] =
|
||||
{
|
||||
{KernelStart,
|
||||
KernelEnd},
|
||||
{SectionsStart,
|
||||
SectionsEnd},
|
||||
{Symbols,
|
||||
Symbols + SymbolSize},
|
||||
{StringAddress,
|
||||
StringAddress + StringSize},
|
||||
{RSDPStart,
|
||||
RSDPEnd},
|
||||
{(uintptr_t)bInfo.Kernel.FileBase,
|
||||
(uintptr_t)bInfo.Kernel.FileBase + bInfo.Kernel.Size},
|
||||
{(uintptr_t)bInfo.Modules[0].Address,
|
||||
(uintptr_t)bInfo.Modules[0].Address + bInfo.Modules[0].Size},
|
||||
{(uintptr_t)bInfo.Modules[1].Address,
|
||||
(uintptr_t)bInfo.Modules[1].Address + bInfo.Modules[1].Size},
|
||||
{(uintptr_t)bInfo.Modules[2].Address,
|
||||
(uintptr_t)bInfo.Modules[2].Address + bInfo.Modules[2].Size},
|
||||
{(uintptr_t)bInfo.Modules[3].Address,
|
||||
(uintptr_t)bInfo.Modules[3].Address + bInfo.Modules[3].Size},
|
||||
{KernelStart, KernelEnd, "kernel"},
|
||||
{SectionsStart, SectionsEnd, "sections"},
|
||||
{Symbols, Symbols + SymbolSize, "symbols"},
|
||||
{StringAddress, StringAddress + StringSize, "string"},
|
||||
{RSDPStart, RSDPEnd, "rsdp"},
|
||||
{(uintptr_t)bInfo.Kernel.FileBase, (uintptr_t)bInfo.Kernel.FileBase + bInfo.Kernel.Size, "file"},
|
||||
{(uintptr_t)bInfo.Modules[0].Address, (uintptr_t)bInfo.Modules[0].Address + bInfo.Modules[0].Size, "module 0"},
|
||||
{(uintptr_t)bInfo.Modules[1].Address, (uintptr_t)bInfo.Modules[1].Address + bInfo.Modules[1].Size, "module 1"},
|
||||
{(uintptr_t)bInfo.Modules[2].Address, (uintptr_t)bInfo.Modules[2].Address + bInfo.Modules[2].Size, "module 2"},
|
||||
{(uintptr_t)bInfo.Modules[3].Address, (uintptr_t)bInfo.Modules[3].Address + bInfo.Modules[3].Size, "module 3"},
|
||||
/* MAX_MODULES == 4 */
|
||||
};
|
||||
|
||||
SortAddresses(PtrArray, sizeof(PtrArray) / sizeof(PtrArray[0]));
|
||||
|
||||
uintptr_t MaxEnd = RegionAddress;
|
||||
for (size_t i = 0; i < sizeof(PtrArray) / sizeof(PtrArray[0]); i++)
|
||||
{
|
||||
if (PtrArray[i].Start == 0x0)
|
||||
{
|
||||
debug("skipping %#lx %zu %s", PtrArray[i].Start, i, PtrArray[i].Description);
|
||||
continue;
|
||||
}
|
||||
|
||||
uintptr_t Start = PtrArray[i].Start;
|
||||
uintptr_t End = PtrArray[i].End;
|
||||
debug("%#lx - %#lx", Start, End);
|
||||
debug("[%s] %#lx - %#lx", PtrArray[i].Description, Start, End);
|
||||
|
||||
if (RegionAddress >= Start &&
|
||||
End <= (RegionAddress + RegionSize))
|
||||
if ((Start < (RegionAddress + RegionSize)) && (End > RegionAddress))
|
||||
{
|
||||
BitmapAddress = End;
|
||||
BitmapAddressSize = RegionSize - (End - RegionAddress);
|
||||
if (End > MaxEnd)
|
||||
MaxEnd = End;
|
||||
}
|
||||
}
|
||||
|
||||
if ((BitmapSize + 0x100) > BitmapAddressSize)
|
||||
if (MaxEnd >= RegionAddress && MaxEnd < (RegionAddress + RegionSize))
|
||||
{
|
||||
debug("Region %p-%p (%d MiB) is too small for bitmap.",
|
||||
(void *)BitmapAddress,
|
||||
(void *)(BitmapAddress + BitmapAddressSize),
|
||||
TO_MiB(BitmapAddressSize));
|
||||
continue;
|
||||
}
|
||||
BitmapAddress = MaxEnd;
|
||||
BitmapAddressSize = RegionAddress + RegionSize - MaxEnd;
|
||||
|
||||
debug("Found free memory for bitmap: %p (%d MiB)",
|
||||
(void *)BitmapAddress,
|
||||
TO_MiB(BitmapAddressSize));
|
||||
break;
|
||||
debug("BitmapAddress = %#lx; Size = %zu", BitmapAddress, BitmapAddressSize);
|
||||
|
||||
if ((BitmapSize + 0x100) > BitmapAddressSize)
|
||||
{
|
||||
debug("Region %#lx-%#lx (%d MiB) is too small for bitmap.", BitmapAddress, BitmapAddress + BitmapAddressSize, TO_MiB(BitmapAddressSize));
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Found free memory for bitmap: %#lx (%d MiB)", BitmapAddress, TO_MiB(BitmapAddressSize));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -52,7 +52,7 @@ Xalloc::V1 *XallocV1Allocator = nullptr;
|
||||
Xalloc::V2 *XallocV2Allocator = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
NIF void tracepagetable(PageTable *pt)
|
||||
nif void tracepagetable(PageTable *pt)
|
||||
{
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
@@ -71,7 +71,7 @@ NIF void tracepagetable(PageTable *pt)
|
||||
}
|
||||
#endif
|
||||
|
||||
NIF void MapEntries(PageTable *PT)
|
||||
nif void MapEntries(PageTable *PT)
|
||||
{
|
||||
debug("mapping %d memory entries", bInfo.Memory.Entries);
|
||||
Virtual vmm = Virtual(PT);
|
||||
@@ -89,7 +89,7 @@ NIF void MapEntries(PageTable *PT)
|
||||
vmm.Unmap((void *)0);
|
||||
}
|
||||
|
||||
NIF void MapFramebuffer(PageTable *PT)
|
||||
nif void MapFramebuffer(PageTable *PT)
|
||||
{
|
||||
debug("Mapping Framebuffer");
|
||||
Virtual vmm = Virtual(PT);
|
||||
@@ -123,7 +123,7 @@ NIF void MapFramebuffer(PageTable *PT)
|
||||
}
|
||||
}
|
||||
|
||||
NIF void MapKernel(PageTable *PT)
|
||||
nif void MapKernel(PageTable *PT)
|
||||
{
|
||||
debug("Mapping Kernel");
|
||||
|
||||
@@ -237,7 +237,7 @@ NIF void MapKernel(PageTable *PT)
|
||||
info("Cannot determine kernel file address. Ignoring.");
|
||||
}
|
||||
|
||||
NIF void CreatePageTable(PageTable *pt)
|
||||
nif void CreatePageTable(PageTable *pt)
|
||||
{
|
||||
static int check_cpuid = 0;
|
||||
|
||||
@@ -286,7 +286,7 @@ NIF void CreatePageTable(PageTable *pt)
|
||||
#endif
|
||||
}
|
||||
|
||||
NIF void InitializeMemoryManagement()
|
||||
nif void InitializeMemoryManagement()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifndef __i386__
|
||||
@@ -340,7 +340,7 @@ NIF void InitializeMemoryManagement()
|
||||
KernelAllocator.Init();
|
||||
debug("Memory Info:\n\n%lld MiB / %lld MiB (%lld MiB reserved)\n",
|
||||
TO_MiB(KernelAllocator.GetUsedMemory()),
|
||||
TO_MiB(KernelAllocator.GetTotalMemory()),
|
||||
TO_MiB(KernelAllocator.GetTotalMemory() - KernelAllocator.GetReservedMemory()),
|
||||
TO_MiB(KernelAllocator.GetReservedMemory()));
|
||||
|
||||
/* -- Debugging --
|
||||
@@ -361,8 +361,7 @@ NIF void InitializeMemoryManagement()
|
||||
|
||||
CreatePageTable(KernelPageTable);
|
||||
|
||||
trace("Applying new page table from address %#lx",
|
||||
KernelPageTable);
|
||||
trace("Applying new page table from address %#lx", KernelPageTable);
|
||||
CPU::PageTable(KernelPageTable);
|
||||
debug("Page table updated.");
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include <memory.hpp>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <signal.hpp>
|
||||
#include <utsname.h>
|
||||
#include <time.h>
|
||||
|
@@ -264,7 +264,7 @@ namespace Memory
|
||||
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
|
||||
|
||||
if (unlikely(PageBitmap[Index] == true))
|
||||
return;
|
||||
continue;
|
||||
|
||||
if (PageBitmap.Set(Index, true))
|
||||
{
|
||||
@@ -322,8 +322,7 @@ namespace Memory
|
||||
SmartLock(this->MemoryLock);
|
||||
|
||||
uint64_t MemorySize = bInfo.Memory.Size;
|
||||
debug("Memory size: %lld bytes (%ld pages)",
|
||||
MemorySize, TO_PAGES(MemorySize));
|
||||
debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize));
|
||||
TotalMemory.store(MemorySize);
|
||||
FreeMemory.store(MemorySize);
|
||||
|
||||
@@ -338,16 +337,10 @@ namespace Memory
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
debug("Initializing Bitmap at %p-%p (%d Bytes)",
|
||||
BitmapAddress,
|
||||
(void *)(BitmapAddress + BitmapSize),
|
||||
BitmapSize);
|
||||
|
||||
debug("Initializing Bitmap at %#lx-%#lx (%zu Bytes)", BitmapAddress, BitmapAddress + BitmapSize, BitmapSize);
|
||||
PageBitmap.Size = BitmapSize;
|
||||
PageBitmap.Buffer = (uint8_t *)BitmapAddress;
|
||||
for (size_t i = 0; i < BitmapSize; i++)
|
||||
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
|
||||
|
||||
memset((void *)BitmapAddress, 0, BitmapSize);
|
||||
ReserveEssentials();
|
||||
}
|
||||
|
||||
|
@@ -80,12 +80,9 @@ namespace Memory
|
||||
{
|
||||
char *sections = r_cst(char *, bInfo.Kernel.Symbols.Sections);
|
||||
debug("Reserving sections region %#lx-%#lx...",
|
||||
sections,
|
||||
(void *)((uintptr_t)sections + bInfo.Kernel.Symbols.EntSize *
|
||||
bInfo.Kernel.Symbols.Num));
|
||||
sections, (uintptr_t)sections + bInfo.Kernel.Symbols.EntSize * bInfo.Kernel.Symbols.Num);
|
||||
|
||||
this->ReservePages(sections, TO_PAGES(bInfo.Kernel.Symbols.EntSize *
|
||||
bInfo.Kernel.Symbols.Num));
|
||||
this->ReservePages(sections, TO_PAGES(bInfo.Kernel.Symbols.EntSize * bInfo.Kernel.Symbols.Num));
|
||||
|
||||
Elf_Sym *Symbols = nullptr;
|
||||
uint8_t *StringAddress = nullptr;
|
||||
@@ -101,11 +98,9 @@ namespace Memory
|
||||
for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i)
|
||||
{
|
||||
Elf_Shdr *sym = (Elf_Shdr *)§ions[bInfo.Kernel.Symbols.EntSize * i];
|
||||
Elf_Shdr *str = (Elf_Shdr *)§ions[bInfo.Kernel.Symbols.EntSize *
|
||||
sym->sh_link];
|
||||
Elf_Shdr *str = (Elf_Shdr *)§ions[bInfo.Kernel.Symbols.EntSize * sym->sh_link];
|
||||
|
||||
if (sym->sh_type == SHT_SYMTAB &&
|
||||
str->sh_type == SHT_STRTAB)
|
||||
if (sym->sh_type == SHT_SYMTAB && str->sh_type == SHT_STRTAB)
|
||||
{
|
||||
Symbols = (Elf_Sym *)sym->sh_addr;
|
||||
StringAddress = (uint8_t *)str->sh_addr;
|
||||
@@ -145,8 +140,7 @@ namespace Memory
|
||||
bInfo.Modules[i].Address,
|
||||
(void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size));
|
||||
|
||||
this->ReservePages((void *)bInfo.Modules[i].Address,
|
||||
TO_PAGES(bInfo.Modules[i].Size));
|
||||
this->ReservePages((void *)bInfo.Modules[i].Address, TO_PAGES(bInfo.Modules[i].Size));
|
||||
}
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
@@ -200,6 +194,15 @@ namespace Memory
|
||||
#pragma GCC diagnostic pop
|
||||
this->ReservePages(SDTHdr, TO_PAGES(SDTHdr->Length));
|
||||
}
|
||||
|
||||
if (bInfo.EFI.Info.Enabled)
|
||||
{
|
||||
debug("Reserving EFI related...");
|
||||
if (bInfo.EFI.Info.IH)
|
||||
this->ReservePage(bInfo.EFI.ImageHandle);
|
||||
if (bInfo.EFI.Info.ST)
|
||||
this->ReservePage(bInfo.EFI.SystemTable);
|
||||
}
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
#endif
|
||||
|
@@ -79,7 +79,7 @@ namespace Memory
|
||||
this->Expanded = Parent->Expanded;
|
||||
|
||||
std::list<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages();
|
||||
foreach (auto Page in ParentAllocatedPages)
|
||||
for (auto Page : ParentAllocatedPages)
|
||||
{
|
||||
void *NewPhysical = vma->RequestPages(1);
|
||||
debug("Forking address %#lx to %#lx", Page.PhysicalAddress, NewPhysical);
|
||||
|
@@ -82,7 +82,7 @@ namespace Memory
|
||||
func("%#lx, %lld", Address, Count);
|
||||
|
||||
SmartLock(MgrLock);
|
||||
foreach (auto &apl in AllocatedPagesList)
|
||||
for (auto &apl : AllocatedPagesList)
|
||||
{
|
||||
if (apl.VirtualAddress != Address)
|
||||
continue;
|
||||
@@ -128,7 +128,7 @@ namespace Memory
|
||||
/* No need to remap pages, the page table will be destroyed */
|
||||
|
||||
Virtual vmm(this->Table);
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
for (auto ap : AllocatedPagesList)
|
||||
{
|
||||
KernelAllocator.FreePages(ap.PhysicalAddress, ap.PageCount);
|
||||
|
||||
|
@@ -29,7 +29,7 @@ namespace Memory
|
||||
{
|
||||
SmartLock(MgrLock);
|
||||
uint64_t Size = 0;
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
for (auto ap : AllocatedPagesList)
|
||||
Size += ap.PageCount;
|
||||
return FROM_PAGES(Size);
|
||||
}
|
||||
@@ -214,7 +214,7 @@ namespace Memory
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (auto sr in SharedRegions)
|
||||
for (auto sr : SharedRegions)
|
||||
{
|
||||
uintptr_t Start = (uintptr_t)sr.Address;
|
||||
uintptr_t End = (uintptr_t)sr.Address + sr.Length;
|
||||
@@ -263,7 +263,7 @@ namespace Memory
|
||||
void VirtualMemoryArea::FreeAllPages()
|
||||
{
|
||||
SmartLock(MgrLock);
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
for (auto ap : AllocatedPagesList)
|
||||
{
|
||||
KernelAllocator.FreePages(ap.Address, ap.PageCount);
|
||||
Virtual vmm(this->Table);
|
||||
@@ -287,7 +287,7 @@ namespace Memory
|
||||
|
||||
Virtual vmm(this->Table);
|
||||
SmartLock(MgrLock);
|
||||
foreach (auto &ap in Parent->AllocatedPagesList)
|
||||
for (auto &ap : Parent->AllocatedPagesList)
|
||||
{
|
||||
if (ap.Protected)
|
||||
{
|
||||
@@ -339,7 +339,7 @@ namespace Memory
|
||||
(uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE));
|
||||
}
|
||||
|
||||
foreach (auto &sr in Parent->SharedRegions)
|
||||
for (auto &sr : Parent->SharedRegions)
|
||||
{
|
||||
MgrLock.Unlock();
|
||||
void *Address = this->CreateCoWRegion(sr.Address, sr.Length,
|
||||
@@ -496,7 +496,7 @@ namespace Memory
|
||||
/* No need to remap pages, the page table will be destroyed */
|
||||
|
||||
SmartLock(MgrLock);
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
for (auto ap : AllocatedPagesList)
|
||||
KernelAllocator.FreePages(ap.Address, ap.PageCount);
|
||||
}
|
||||
}
|
||||
|
@@ -64,7 +64,7 @@ struct DiagnosticFile
|
||||
} Data;
|
||||
};
|
||||
|
||||
nsa bool WriteDiagDataToNode(FileNode *node)
|
||||
nsa bool WriteDiagDataToNode(Node node)
|
||||
{
|
||||
uintptr_t KStart = (uintptr_t)&_kernel_start;
|
||||
uintptr_t kEnd = (uintptr_t)&_kernel_end;
|
||||
@@ -89,7 +89,7 @@ nsa bool WriteDiagDataToNode(FileNode *node)
|
||||
memcpy(file->Data.KernelMemory, (void *)KStart, kSize);
|
||||
|
||||
ExPrint("Writing to %s\n", node->Path.c_str());
|
||||
size_t w = node->Write(buf, fileSize, 0);
|
||||
size_t w = fs->Write(node, buf, fileSize, 0);
|
||||
if (w != fileSize)
|
||||
{
|
||||
debug("%d out of %d bytes written", w, fileSize);
|
||||
@@ -115,22 +115,23 @@ nsa void DiagnosticDataCollection()
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
|
||||
FileNode *panicDir = fs->ForceCreate(nullptr, "/var/panic", mode);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node panicDir = fs->Create(root, "/sys/log/panic", mode);
|
||||
if (!panicDir)
|
||||
{
|
||||
ExPrint("\x1b[0;30;41mFailed to create /var/panic\x1b[0m\n");
|
||||
ExPrint("\x1b[0;30;41mFailed to create /sys/log/panic\x1b[0m\n");
|
||||
Display->UpdateBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
FileNode *dumpFile;
|
||||
Node dumpFile;
|
||||
Time::Clock clock = Time::ReadClock();
|
||||
char filename[64];
|
||||
for (int i = 0; i < INT32_MAX; i++)
|
||||
{
|
||||
sprintf(filename, "dump-%d-%d-%d-%d.dmp",
|
||||
clock.Year, clock.Month, clock.Day, i);
|
||||
if (fs->PathExists(filename, panicDir))
|
||||
if (fs->Lookup(panicDir, filename))
|
||||
continue;
|
||||
|
||||
mode = S_IRWXU |
|
||||
@@ -145,6 +146,6 @@ nsa void DiagnosticDataCollection()
|
||||
if (!WriteDiagDataToNode(dumpFile))
|
||||
return;
|
||||
|
||||
ExPrint("You can find the diagnostic file in /var/panic/%s\n", filename);
|
||||
ExPrint("You can find the diagnostic file in /sys/log/panic/%s\n", filename);
|
||||
Display->UpdateBuffer();
|
||||
}
|
||||
|
@@ -52,7 +52,7 @@ void *FbBeforePanic = nullptr;
|
||||
size_t FbPagesBeforePanic = 0;
|
||||
FontRenderer CrashFontRenderer;
|
||||
|
||||
int ExTermColors[] = {
|
||||
static int ExTermColors[] = {
|
||||
[TerminalColor::BLACK] = 0x000000,
|
||||
[TerminalColor::RED] = 0xAA0000,
|
||||
[TerminalColor::GREEN] = 0x00AA00,
|
||||
@@ -63,7 +63,7 @@ int ExTermColors[] = {
|
||||
[TerminalColor::GREY] = 0xAAAAAA,
|
||||
};
|
||||
|
||||
int ExTermBrightColors[] = {
|
||||
static int ExTermBrightColors[] = {
|
||||
[TerminalColor::BLACK] = 0x858585,
|
||||
[TerminalColor::RED] = 0xFF5555,
|
||||
[TerminalColor::GREEN] = 0x55FF55,
|
||||
@@ -84,7 +84,7 @@ void paint_callback(TerminalCell *cell, long x, long y)
|
||||
|
||||
nsa void __printfWrapper(char c, void *)
|
||||
{
|
||||
KernelConsole::Terminals[15]->Process(c);
|
||||
KernelConsole::Terminals[15]->Term->Process(c);
|
||||
}
|
||||
|
||||
nsa void ExPrint(const char *Format, ...)
|
||||
@@ -162,7 +162,8 @@ nsa void InitFont()
|
||||
{
|
||||
size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width;
|
||||
size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height;
|
||||
Terminals[15] = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr);
|
||||
Terminals[15] = new ConsoleTerminal;
|
||||
Terminals[15]->Term = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +373,8 @@ nsa void BaseBufferStackError(bool Stack)
|
||||
{
|
||||
size_t Cols = Display->GetWidth / CrashFontRenderer.CurrentFont->GetInfo().Width;
|
||||
size_t Rows = Display->GetHeight / CrashFontRenderer.CurrentFont->GetInfo().Height;
|
||||
Terminals[15] = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr);
|
||||
Terminals[15] = new ConsoleTerminal;
|
||||
Terminals[15]->Term = new VirtualTerminal(Cols, Rows, Display->GetWidth, Display->GetHeight, paint_callback, nullptr);
|
||||
}
|
||||
|
||||
ExceptionLock.store(true, std::memory_order_release);
|
||||
@@ -406,8 +408,7 @@ nsa __noreturn void HandleBufferOverflow()
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line,
|
||||
const char *Expression)
|
||||
EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line, const char *Expression)
|
||||
{
|
||||
DisplayAssertionFailed(File, Line, Expression);
|
||||
CPU::Stop();
|
||||
|
@@ -58,7 +58,7 @@ nsa bool CrashXHCIKeyboardDriver::TakeOwnership()
|
||||
return true;
|
||||
|
||||
exCap->USBLEGSUP.OSOwnsHC = 1;
|
||||
TimeManager->Sleep(200, Time::Milliseconds);
|
||||
TimeManager->Sleep(Time::FromMilliseconds(200));
|
||||
if (exCap->USBLEGSUP.BIOSOwnsHC == 0)
|
||||
return true;
|
||||
|
||||
|
@@ -489,12 +489,12 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru
|
||||
bool pRdy = false;
|
||||
bool showNote = false;
|
||||
/* FIXME: This is slow */
|
||||
foreach (auto Process in Plist)
|
||||
for (auto Process : Plist)
|
||||
{
|
||||
bool ignore = true;
|
||||
if (Process->State == Tasking::Ready && IgnoreReady)
|
||||
{
|
||||
foreach (auto Thread in Process->Threads)
|
||||
for (auto Thread : Process->Threads)
|
||||
{
|
||||
if (Thread->State == Tasking::Ready)
|
||||
continue;
|
||||
@@ -522,7 +522,7 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru
|
||||
: "none");
|
||||
|
||||
bool tRdy = false;
|
||||
foreach (auto Thread in Process->Threads)
|
||||
for (auto Thread : Process->Threads)
|
||||
{
|
||||
if (Thread->State == Tasking::Ready && IgnoreReady)
|
||||
{
|
||||
@@ -571,6 +571,7 @@ nsa void DisplayCrashScreen(CPU::ExceptionFrame *Frame)
|
||||
|
||||
DisplayTopOverlay();
|
||||
DisplayMainScreen(Frame);
|
||||
DisplayStackScreen(Frame);
|
||||
InitializeKeyboards();
|
||||
DisplayBottomOverlay();
|
||||
|
||||
|
@@ -897,8 +897,7 @@ namespace PCI
|
||||
BAR[4] = hdr0->BAR4;
|
||||
BAR[5] = hdr0->BAR5;
|
||||
|
||||
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx",
|
||||
BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
|
||||
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
|
||||
|
||||
/* BARs Size */
|
||||
for (short i = 0; i < 6; i++)
|
||||
@@ -927,7 +926,7 @@ namespace PCI
|
||||
size = size & UINT32_MAX;
|
||||
if (size == 0)
|
||||
{
|
||||
warn("BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
|
||||
warn("MEM BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
|
||||
size++;
|
||||
}
|
||||
BARsSize[i] = size;
|
||||
@@ -943,7 +942,7 @@ namespace PCI
|
||||
size = size & UINT16_MAX;
|
||||
if (size == 0)
|
||||
{
|
||||
warn("BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
|
||||
warn("I/O BAR%d size is zero! Device: %#x:%#x", i, Device.Header->VendorID, Device.Header->DeviceID);
|
||||
size++;
|
||||
}
|
||||
BARsSize[i] = size;
|
||||
@@ -972,10 +971,7 @@ namespace PCI
|
||||
uintptr_t BARBase = BAR[i] & (~3);
|
||||
size_t BARSize = BARsSize[i];
|
||||
|
||||
debug("Mapping BAR%d %#x-%#x", i, BARBase, BARBase + BARSize);
|
||||
|
||||
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
|
||||
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
||||
debug("no need to map BAR%d %#x-%#x as it's an I/O space", i, BARBase, BARBase + BARSize);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1079,7 +1075,7 @@ namespace PCI
|
||||
std::list<PCIDevice> Manager::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF)
|
||||
{
|
||||
std::list<PCIDevice> DeviceFound;
|
||||
foreach (auto dev in Devices)
|
||||
for (auto dev : Devices)
|
||||
{
|
||||
if (dev.Header->Class == Class &&
|
||||
dev.Header->Subclass == Subclass &&
|
||||
@@ -1094,7 +1090,7 @@ namespace PCI
|
||||
std::list<PCIDevice> Manager::FindPCIDevice(uint16_t VendorID, uint16_t DeviceID)
|
||||
{
|
||||
std::list<PCIDevice> DeviceFound;
|
||||
foreach (auto dev in Devices)
|
||||
for (auto dev : Devices)
|
||||
{
|
||||
if (dev.Header->VendorID == VendorID &&
|
||||
dev.Header->DeviceID == DeviceID)
|
||||
@@ -1109,11 +1105,11 @@ namespace PCI
|
||||
std::list<uint16_t> DeviceIDs)
|
||||
{
|
||||
std::list<PCIDevice> DeviceFound;
|
||||
foreach (auto dev in Devices)
|
||||
for (auto dev : Devices)
|
||||
{
|
||||
foreach (auto VendorID in VendorIDs)
|
||||
for (auto VendorID : VendorIDs)
|
||||
{
|
||||
foreach (auto DeviceID in DeviceIDs)
|
||||
for (auto DeviceID : DeviceIDs)
|
||||
{
|
||||
if (dev.Header->VendorID == VendorID &&
|
||||
dev.Header->DeviceID == DeviceID)
|
||||
|
@@ -67,8 +67,7 @@ namespace Random
|
||||
if (RDRANDFlag)
|
||||
{
|
||||
uint16_t RDRANDValue = 0;
|
||||
asmv("1: rdrand %0; jnc 1b"
|
||||
: "=r"(RDRANDValue));
|
||||
asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
|
||||
return RDRANDValue;
|
||||
}
|
||||
|
||||
@@ -84,8 +83,7 @@ namespace Random
|
||||
if (RDRANDFlag)
|
||||
{
|
||||
uint32_t RDRANDValue = 0;
|
||||
asmv("1: rdrand %0; jnc 1b"
|
||||
: "=r"(RDRANDValue));
|
||||
asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
|
||||
return RDRANDValue;
|
||||
}
|
||||
|
||||
@@ -101,8 +99,7 @@ namespace Random
|
||||
if (RDRANDFlag)
|
||||
{
|
||||
uintptr_t RDRANDValue = 0;
|
||||
asmv("1: rdrand %0; jnc 1b"
|
||||
: "=r"(RDRANDValue));
|
||||
asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
|
||||
return RDRANDValue;
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <symbols.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <convert.h>
|
||||
#include <algorithm>
|
||||
#include <debug.h>
|
||||
#include <elf.h>
|
||||
|
||||
@@ -25,7 +26,7 @@
|
||||
|
||||
namespace SymbolResolver
|
||||
{
|
||||
const NIF char *Symbols::GetSymbol(uintptr_t Address)
|
||||
const nif char *Symbols::GetSymbol(uintptr_t Address)
|
||||
{
|
||||
SymbolTable Result{};
|
||||
|
||||
@@ -115,8 +116,7 @@ namespace SymbolResolver
|
||||
Elf_Shdr *sym = (Elf_Shdr *)§ions[EntSize * i];
|
||||
Elf_Shdr *str = (Elf_Shdr *)§ions[EntSize * sym->sh_link];
|
||||
|
||||
if (sym->sh_type == SHT_SYMTAB &&
|
||||
str->sh_type == SHT_STRTAB)
|
||||
if (sym->sh_type == SHT_SYMTAB && str->sh_type == SHT_STRTAB)
|
||||
{
|
||||
Symbols = (Elf_Sym *)sym->sh_addr;
|
||||
StringAddress = (uint8_t *)str->sh_addr;
|
||||
@@ -124,26 +124,15 @@ namespace SymbolResolver
|
||||
// StringSize = (int)str->sh_size;
|
||||
// TotalEntries = Section.sh_size / sizeof(Elf64_Sym)
|
||||
TotalEntries = sym->sh_size / sym->sh_entsize;
|
||||
trace("Symbol table found, %d entries",
|
||||
SymbolSize / sym->sh_entsize);
|
||||
UNUSED(SymbolSize);
|
||||
trace("Symbol table found, %d entries", SymbolSize / sym->sh_entsize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Symbols != nullptr && StringAddress != nullptr)
|
||||
{
|
||||
size_t Index, MinimumIndex;
|
||||
for (size_t i = 0; i < TotalEntries - 1; i++)
|
||||
{
|
||||
MinimumIndex = i;
|
||||
for (Index = i + 1; Index < TotalEntries; Index++)
|
||||
if (Symbols[Index].st_value < Symbols[MinimumIndex].st_value)
|
||||
MinimumIndex = Index;
|
||||
Elf_Sym tmp = Symbols[MinimumIndex];
|
||||
Symbols[MinimumIndex] = Symbols[i];
|
||||
Symbols[i] = tmp;
|
||||
}
|
||||
std::sort(Symbols, Symbols + TotalEntries, [](const Elf_Sym &a, const Elf_Sym &b)
|
||||
{ return a.st_value < b.st_value; });
|
||||
|
||||
while (Symbols[0].st_value == 0)
|
||||
{
|
||||
@@ -159,8 +148,7 @@ namespace SymbolResolver
|
||||
return;
|
||||
}
|
||||
|
||||
trace("Symbol table loaded, %d entries (%ld KiB)",
|
||||
TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
|
||||
trace("Symbol table loaded, %d entries (%ld KiB)", TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
|
||||
Elf_Sym *sym;
|
||||
const char *name;
|
||||
Memory::Virtual vmm;
|
||||
@@ -178,6 +166,12 @@ namespace SymbolResolver
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unlikely(sym->st_name == (Elf_Word)-1 || sym->st_value == (Elf_Addr)-1 || sym->st_size == (uintptr_t)-1))
|
||||
{
|
||||
error("Symbol %d is invalid; ptr:%#lx", i, sym);
|
||||
continue;
|
||||
}
|
||||
|
||||
name = (const char *)&StringAddress[Symbols[i].st_name];
|
||||
if (!vmm.Check((void *)name))
|
||||
{
|
||||
@@ -191,17 +185,13 @@ namespace SymbolResolver
|
||||
|
||||
if (strlen(name) == 0)
|
||||
continue;
|
||||
SymbolTable tbl{};
|
||||
SymbolTable tbl;
|
||||
tbl.Address = sym->st_value;
|
||||
tbl.FunctionName = new char[strlen(name) + 1];
|
||||
strcpy(tbl.FunctionName, name);
|
||||
this->SymTable.push_back(tbl);
|
||||
this->SymbolTableExists = true;
|
||||
|
||||
// debug("Symbol %d: %#lx %s(%#lx)",
|
||||
// i, tbl.Address,
|
||||
// tbl.FunctionName,
|
||||
// name);
|
||||
// debug("Symbol %d: %#lx %s(%#lx)", i, tbl.Address, tbl.FunctionName, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,7 +314,7 @@ namespace SymbolResolver
|
||||
debug("- %#lx", this);
|
||||
debug("Freeing %d symbols",
|
||||
this->SymTable.size());
|
||||
foreach (auto tbl in this->SymTable)
|
||||
for (auto tbl : this->SymTable)
|
||||
delete[] tbl.FunctionName;
|
||||
}
|
||||
}
|
||||
|
@@ -59,12 +59,12 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame)
|
||||
and switch back when this function returns. */
|
||||
AutoSwitchPageTable PageSwitcher;
|
||||
|
||||
uint64_t _ctime = TimeManager->GetCounter();
|
||||
uint64_t _ctime = TimeManager->GetTimeNs();
|
||||
Tasking::TaskInfo *Ptinfo = &thisProcess->Info;
|
||||
Tasking::TaskInfo *Ttinfo = &thisThread->Info;
|
||||
uintptr_t ret;
|
||||
|
||||
if (Config.UseLinuxSyscalls)
|
||||
if (Config.LinuxSubsystem)
|
||||
{
|
||||
ret = HandleLinuxSyscalls(Frame);
|
||||
goto Ret;
|
||||
@@ -97,7 +97,7 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame)
|
||||
}
|
||||
|
||||
Ret:
|
||||
Ptinfo->KernelTime += TimeManager->GetCounter() - _ctime;
|
||||
Ttinfo->KernelTime += TimeManager->GetCounter() - _ctime;
|
||||
Ptinfo->KernelTime += TimeManager->GetTimeNs() - _ctime;
|
||||
Ttinfo->KernelTime += TimeManager->GetTimeNs() - _ctime;
|
||||
return ret;
|
||||
}
|
||||
|
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <time.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <debug.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace Time
|
||||
{
|
||||
bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit)
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
uint64_t Target = mminq(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
|
||||
while (mminq(&hpet->MainCounterValue) < Target)
|
||||
CPU::Pause();
|
||||
return true;
|
||||
#elif defined(__i386__)
|
||||
uint64_t Target = mminl(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
|
||||
while (mminl(&hpet->MainCounterValue) < Target)
|
||||
CPU::Pause();
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t HighPrecisionEventTimer::GetCounter()
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
return mminq(&hpet->MainCounterValue);
|
||||
#elif defined(__i386__)
|
||||
return mminl(&hpet->MainCounterValue);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit)
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
return mminq(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
|
||||
#elif defined(__i386__)
|
||||
return mminl(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t HighPrecisionEventTimer::GetNanosecondsSinceClassCreation()
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
uint64_t Subtraction = this->GetCounter() - this->ClassCreationTime;
|
||||
if (Subtraction <= 0 || this->clk <= 0)
|
||||
return 0;
|
||||
|
||||
Subtraction *= ConvertUnit(Units::Nanoseconds);
|
||||
return uint64_t(Subtraction / this->clk);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
HighPrecisionEventTimer::HighPrecisionEventTimer(void *hpet)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet;
|
||||
Memory::Virtual vmm;
|
||||
vmm.Map((void *)HPET_HDR->Address.Address,
|
||||
(void *)HPET_HDR->Address.Address,
|
||||
Memory::PTFlag::RW | Memory::PTFlag::PCD);
|
||||
this->hpet = (HPET *)HPET_HDR->Address.Address;
|
||||
trace("%s timer is at address %016p",
|
||||
HPET_HDR->Header.OEMID,
|
||||
(void *)HPET_HDR->Address.Address);
|
||||
clk = s_cst(uint32_t, (uint64_t)this->hpet->GeneralCapabilities >> 32);
|
||||
KPrint("HPET clock is %u Hz", clk);
|
||||
#ifdef __amd64__
|
||||
mmoutq(&this->hpet->GeneralConfiguration, 0);
|
||||
mmoutq(&this->hpet->MainCounterValue, 0);
|
||||
mmoutq(&this->hpet->GeneralConfiguration, 1);
|
||||
#else
|
||||
mmoutl(&this->hpet->GeneralConfiguration, 0);
|
||||
mmoutl(&this->hpet->MainCounterValue, 0);
|
||||
mmoutl(&this->hpet->GeneralConfiguration, 1);
|
||||
#endif
|
||||
ClassCreationTime = this->GetCounter();
|
||||
#endif
|
||||
}
|
||||
|
||||
HighPrecisionEventTimer::~HighPrecisionEventTimer()
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <time.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <debug.h>
|
||||
#include <io.h>
|
||||
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace Time
|
||||
{
|
||||
bool time::Sleep(size_t Duration, Units Unit)
|
||||
{
|
||||
switch (ActiveTimer)
|
||||
{
|
||||
case NONE:
|
||||
error("No timer is active");
|
||||
return false;
|
||||
case RTC:
|
||||
fixme("RTC sleep not implemented");
|
||||
return false;
|
||||
case PIT:
|
||||
fixme("PIT sleep not implemented");
|
||||
return false;
|
||||
case HPET:
|
||||
return this->hpet->Sleep(Duration, Unit);
|
||||
case ACPI:
|
||||
fixme("ACPI sleep not implemented");
|
||||
return false;
|
||||
case APIC:
|
||||
fixme("APIC sleep not implemented");
|
||||
return false;
|
||||
case TSC:
|
||||
return this->tsc->Sleep(Duration, Unit);
|
||||
default:
|
||||
error("Unknown timer");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t time::GetCounter()
|
||||
{
|
||||
switch (ActiveTimer)
|
||||
{
|
||||
case NONE:
|
||||
error("No timer is active");
|
||||
return 0;
|
||||
case RTC:
|
||||
fixme("RTC sleep not implemented");
|
||||
return 0;
|
||||
case PIT:
|
||||
fixme("PIT sleep not implemented");
|
||||
return 0;
|
||||
case HPET:
|
||||
return this->hpet->GetCounter();
|
||||
case ACPI:
|
||||
fixme("ACPI sleep not implemented");
|
||||
return 0;
|
||||
case APIC:
|
||||
fixme("APIC sleep not implemented");
|
||||
return 0;
|
||||
case TSC:
|
||||
return this->tsc->GetCounter();
|
||||
default:
|
||||
error("Unknown timer");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t time::CalculateTarget(uint64_t Target, Units Unit)
|
||||
{
|
||||
switch (ActiveTimer)
|
||||
{
|
||||
case NONE:
|
||||
error("No timer is active");
|
||||
return 0;
|
||||
case RTC:
|
||||
fixme("RTC sleep not implemented");
|
||||
return 0;
|
||||
case PIT:
|
||||
fixme("PIT sleep not implemented");
|
||||
return 0;
|
||||
case HPET:
|
||||
return this->hpet->CalculateTarget(Target, Unit);
|
||||
case ACPI:
|
||||
fixme("ACPI sleep not implemented");
|
||||
return 0;
|
||||
case APIC:
|
||||
fixme("APIC sleep not implemented");
|
||||
return 0;
|
||||
case TSC:
|
||||
return this->tsc->CalculateTarget(Target, Unit);
|
||||
default:
|
||||
error("Unknown timer");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t time::GetNanosecondsSinceClassCreation()
|
||||
{
|
||||
switch (ActiveTimer)
|
||||
{
|
||||
case NONE:
|
||||
error("No timer is active");
|
||||
return 0;
|
||||
case RTC:
|
||||
fixme("RTC sleep not implemented");
|
||||
return 0;
|
||||
case PIT:
|
||||
fixme("PIT sleep not implemented");
|
||||
return 0;
|
||||
case HPET:
|
||||
return this->hpet->GetNanosecondsSinceClassCreation();
|
||||
case ACPI:
|
||||
fixme("ACPI sleep not implemented");
|
||||
return 0;
|
||||
case APIC:
|
||||
fixme("APIC sleep not implemented");
|
||||
return 0;
|
||||
case TSC:
|
||||
return this->tsc->GetNanosecondsSinceClassCreation();
|
||||
default:
|
||||
error("Unknown timer");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void time::FindTimers(void *acpi)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
/* TODO: RTC check */
|
||||
/* TODO: PIT check */
|
||||
|
||||
if (acpi)
|
||||
{
|
||||
if (((ACPI::ACPI *)acpi)->HPET)
|
||||
{
|
||||
hpet = new HighPrecisionEventTimer(((ACPI::ACPI *)acpi)->HPET);
|
||||
ActiveTimer = HPET;
|
||||
SupportedTimers |= HPET;
|
||||
KPrint("HPET found");
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrint("\x1b[33mHPET not found");
|
||||
}
|
||||
|
||||
/* TODO: ACPI check */
|
||||
/* TODO: APIC check */
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrint("\x1b[33mACPI not found");
|
||||
}
|
||||
|
||||
bool TSCInvariant = false;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
CPU::x86::AMD::CPUID0x80000007 cpuid80000007;
|
||||
if (cpuid80000007.EDX.TscInvariant)
|
||||
TSCInvariant = true;
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
// TODO: Intel 0x80000007
|
||||
CPU::x86::AMD::CPUID0x80000007 cpuid80000007;
|
||||
if (cpuid80000007.EDX.TscInvariant)
|
||||
TSCInvariant = true;
|
||||
}
|
||||
|
||||
if (TSCInvariant)
|
||||
{
|
||||
tsc = new TimeStampCounter;
|
||||
// FIXME: ActiveTimer = TSC;
|
||||
SupportedTimers |= TSC;
|
||||
KPrint("Invariant TSC found");
|
||||
}
|
||||
else
|
||||
KPrint("\x1b[33mTSC is not invariant");
|
||||
#endif
|
||||
}
|
||||
|
||||
time::time()
|
||||
{
|
||||
}
|
||||
|
||||
time::~time()
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <time.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <debug.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace Time
|
||||
{
|
||||
bool TimeStampCounter::Sleep(size_t Duration, Units Unit)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
uint64_t Target = this->GetCounter() + (Duration * ConvertUnit(Unit)) / this->clk;
|
||||
while (this->GetCounter() < Target)
|
||||
CPU::Pause();
|
||||
return true;
|
||||
#elif defined(__aarch64__)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t TimeStampCounter::GetCounter()
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
return CPU::Counter();
|
||||
#elif defined(__aarch64__)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t TimeStampCounter::CalculateTarget(uint64_t Target, Units Unit)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
return uint64_t((this->GetCounter() + (Target * ConvertUnit(Unit))) / this->clk);
|
||||
#elif defined(__aarch64__)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t TimeStampCounter::GetNanosecondsSinceClassCreation()
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
return uint64_t((this->GetCounter() - this->ClassCreationTime) / this->clk);
|
||||
#elif defined(__aarch64__)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
TimeStampCounter::TimeStampCounter()
|
||||
{
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
stub; // FIXME: This is not a good way to measure the clock speed
|
||||
uint64_t Start = CPU::Counter();
|
||||
TimeManager->Sleep(1, Units::Milliseconds);
|
||||
uint64_t End = CPU::Counter();
|
||||
|
||||
this->clk = End - Start;
|
||||
this->ClassCreationTime = this->GetCounter();
|
||||
#endif
|
||||
}
|
||||
|
||||
TimeStampCounter::~TimeStampCounter()
|
||||
{
|
||||
}
|
||||
}
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
@@ -818,3 +820,5 @@ namespace Driver::AC97
|
||||
Panic,
|
||||
Probe);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -20,9 +20,9 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
namespace vfs
|
||||
namespace Driver::ExtendedFilesystem
|
||||
{
|
||||
class EXT2
|
||||
{
|
1084
Kernel/drivers/fs/ustar/ustar.cpp
Normal file
1084
Kernel/drivers/fs/ustar/ustar.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,8 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
@@ -68,3 +70,5 @@ namespace Driver::AdvancedIntegratedPeripheral
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include "aip.hpp"
|
||||
|
||||
#include <driver.hpp>
|
||||
@@ -222,3 +224,5 @@ namespace Driver::AdvancedIntegratedPeripheral
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <interface/aip.h>
|
||||
#include <cpu.hpp>
|
||||
@@ -258,3 +260,5 @@ namespace Driver::AdvancedIntegratedPeripheral
|
||||
Panic,
|
||||
Probe);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include "aip.hpp"
|
||||
|
||||
#include <driver.hpp>
|
||||
@@ -261,3 +263,5 @@ namespace Driver::AdvancedIntegratedPeripheral
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Drivers. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <io.h>
|
||||
|
||||
@@ -645,3 +647,5 @@ namespace Driver::AdvancedIntegratedPeripheral
|
||||
// ExPrint(keyBuf);
|
||||
// }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -37,7 +37,7 @@ namespace Driver::TeleTypeDevices
|
||||
{
|
||||
dev_t min = Node->GetMinor();
|
||||
if (min == ids.kcon)
|
||||
return KernelConsole::CurrentTerminal.load()->Open(Flags, Mode);
|
||||
return KernelConsole::CurrentTerminal.load()->Term->Open(Flags, Mode);
|
||||
else if (min == ids.tty)
|
||||
{
|
||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||
@@ -55,7 +55,7 @@ namespace Driver::TeleTypeDevices
|
||||
{
|
||||
dev_t min = Node->GetMinor();
|
||||
if (min == ids.kcon)
|
||||
return KernelConsole::CurrentTerminal.load()->Close();
|
||||
return KernelConsole::CurrentTerminal.load()->Term->Close();
|
||||
else if (min == ids.tty)
|
||||
{
|
||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||
@@ -73,7 +73,7 @@ namespace Driver::TeleTypeDevices
|
||||
{
|
||||
dev_t min = Node->GetMinor();
|
||||
if (min == ids.kcon)
|
||||
return KernelConsole::CurrentTerminal.load()->Ioctl(Request, Argp);
|
||||
return KernelConsole::CurrentTerminal.load()->Term->Ioctl(Request, Argp);
|
||||
else if (min == ids.tty)
|
||||
{
|
||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||
@@ -91,7 +91,7 @@ namespace Driver::TeleTypeDevices
|
||||
{
|
||||
dev_t min = Node->GetMinor();
|
||||
if (min == ids.kcon)
|
||||
return KernelConsole::CurrentTerminal.load()->Read(Buffer, Size, Offset);
|
||||
return KernelConsole::CurrentTerminal.load()->Term->Read(Buffer, Size, Offset);
|
||||
else if (min == ids.tty)
|
||||
{
|
||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||
@@ -109,7 +109,7 @@ namespace Driver::TeleTypeDevices
|
||||
{
|
||||
dev_t min = Node->GetMinor();
|
||||
if (min == ids.kcon)
|
||||
return KernelConsole::CurrentTerminal.load()->Write(Buffer, Size, Offset);
|
||||
return KernelConsole::CurrentTerminal.load()->Term->Write(Buffer, Size, Offset);
|
||||
else if (min == ids.tty)
|
||||
{
|
||||
TTY::TeletypeDriver *tty = (TTY::TeletypeDriver *)thisProcess->tty;
|
||||
@@ -156,7 +156,7 @@ namespace Driver::TeleTypeDevices
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
ids.kcon = DriverManager->CreateDeviceFile(DriverID, "kcon", mode, &ops);
|
||||
ids.kcon = DriverManager->CreateDeviceFile(DriverID, "console", mode, &ops);
|
||||
|
||||
/* c rw- rw- rw- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
@@ -176,6 +178,11 @@ namespace Driver::VMwareToolBox
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
#pragma GCC diagnostic ignored "-Wuninitialized"
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
|
||||
#define VM_PORT(cmd, in_ebx, isi, idi, \
|
||||
flags, magic, \
|
||||
ax, bx, cx, dx, si, di)
|
||||
@@ -915,3 +922,5 @@ namespace Driver::VMwareToolBox
|
||||
Panic,
|
||||
Probe);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
@@ -483,3 +485,5 @@ namespace Driver::E1000
|
||||
Panic,
|
||||
Probe);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -15,6 +15,8 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
@@ -292,3 +294,5 @@ namespace Driver::RTL8139
|
||||
Panic,
|
||||
Probe);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <interface/block.h>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
|
||||
@@ -572,6 +573,9 @@ namespace Driver::AHCI
|
||||
HBAPort *HBAPortPtr;
|
||||
uint8_t *Buffer;
|
||||
uint8_t PortNumber;
|
||||
uint32_t BlockSize;
|
||||
uint32_t BlockCount;
|
||||
size_t Size;
|
||||
ATA_IDENTIFY *IdentifyData;
|
||||
|
||||
Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
|
||||
@@ -614,6 +618,7 @@ namespace Driver::AHCI
|
||||
|
||||
void Configure()
|
||||
{
|
||||
debug("Configuring port %d", PortNumber);
|
||||
this->StopCMD();
|
||||
void *CmdBase = v0::AllocateMemory(DriverID, 1);
|
||||
HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
|
||||
@@ -639,19 +644,35 @@ namespace Driver::AHCI
|
||||
|
||||
Identify();
|
||||
|
||||
if (IdentifyData->CommandSetSupport.BigLba)
|
||||
{
|
||||
if ((IdentifyData->CommandSetActive.Words119_120Valid & 0x1) != 0)
|
||||
{
|
||||
uint32_t wordsPerLogicalSector = (IdentifyData->WordsPerLogicalSector[1] << 16) | IdentifyData->WordsPerLogicalSector[0];
|
||||
if (wordsPerLogicalSector != 0)
|
||||
this->BlockSize = wordsPerLogicalSector * 2;
|
||||
}
|
||||
}
|
||||
this->BlockSize = 512;
|
||||
|
||||
this->BlockCount = this->IdentifyData->UserAddressableSectors;
|
||||
this->Size = this->BlockCount * this->BlockSize;
|
||||
|
||||
trace("Port %d \"%x %x %x %x\" configured", PortNumber,
|
||||
HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
|
||||
HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]);
|
||||
}
|
||||
|
||||
bool ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
|
||||
int ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
|
||||
{
|
||||
if (this->AHCIPortType == PortType::SATAPI && Write == true)
|
||||
{
|
||||
trace("SATAPI port does not support write.");
|
||||
return false;
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
debug("%s op on port %d, sector %d, count %d", Write ? "Write" : "Read", this->PortNumber, Sector, SectorCount);
|
||||
|
||||
uint32_t SectorL = (uint32_t)Sector;
|
||||
uint32_t SectorH = (uint32_t)(Sector >> 32);
|
||||
|
||||
@@ -706,7 +727,7 @@ namespace Driver::AHCI
|
||||
if (spinLock == 1000000)
|
||||
{
|
||||
trace("Port not responding.");
|
||||
return false;
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
HBAPortPtr->CommandIssue = 1;
|
||||
@@ -723,7 +744,7 @@ namespace Driver::AHCI
|
||||
spinLock = 0;
|
||||
retries++;
|
||||
if (retries > 10)
|
||||
return false;
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (HBAPortPtr->CommandIssue == 0)
|
||||
@@ -733,11 +754,11 @@ namespace Driver::AHCI
|
||||
if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
|
||||
{
|
||||
trace("Error reading/writing (%d).", Write);
|
||||
return false;
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Identify()
|
||||
@@ -840,34 +861,61 @@ namespace Driver::AHCI
|
||||
}
|
||||
}
|
||||
|
||||
int Open(struct Inode *, int, mode_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Close(struct Inode *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
uint64_t sector = Offset / 512;
|
||||
uint32_t sectorCount = uint32_t(Size / 512);
|
||||
int num = Node->GetMinor();
|
||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, Buffer, false);
|
||||
return ok ? Size : 0;
|
||||
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||
{
|
||||
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint64_t sector = Offset / port->BlockSize;
|
||||
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
|
||||
if (sectorCount == 0)
|
||||
{
|
||||
trace("Attempt to read 0 sectors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool status = port->ReadWrite(sector, sectorCount, Buffer, false);
|
||||
if (status != 0)
|
||||
{
|
||||
trace("Error '%s' reading from port %d", strerror(status), port->PortNumber);
|
||||
return status;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
uint64_t sector = Offset / 512;
|
||||
uint32_t sectorCount = uint32_t(Size / 512);
|
||||
int num = Node->GetMinor();
|
||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, (void *)Buffer, true);
|
||||
return ok ? Size : 0;
|
||||
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||
{
|
||||
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint64_t sector = Offset / port->BlockSize;
|
||||
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
|
||||
if (sectorCount == 0)
|
||||
{
|
||||
trace("Attempt to write 0 sectors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool status = port->ReadWrite(sector, sectorCount, (void *)Buffer, true);
|
||||
if (status != 0)
|
||||
{
|
||||
trace("Error '%s' writing to port %d", strerror(status), port->PortNumber);
|
||||
return status;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
int Open(struct Inode *, int, mode_t) { return 0; }
|
||||
int Close(struct Inode *) { return 0; }
|
||||
|
||||
const struct InodeOperations ops = {
|
||||
.Lookup = nullptr,
|
||||
.Create = nullptr,
|
||||
@@ -915,8 +963,18 @@ namespace Driver::AHCI
|
||||
{
|
||||
KPrint("%s drive found at port %d", PortTypeName[portType], i);
|
||||
Port *port = new Port(portType, &hba->Ports[i], i);
|
||||
dev_t ret = v0::RegisterDevice(DriverID, BLOCK_TYPE_HDD, &ops);
|
||||
port->Configure();
|
||||
|
||||
BlockDevice *dev = new BlockDevice;
|
||||
dev->Name = "ahci";
|
||||
dev->BlockSize = port->BlockSize;
|
||||
dev->BlockCount = port->BlockCount;
|
||||
dev->Size = port->Size;
|
||||
dev->Ops = &ops;
|
||||
dev->PrivateData = port;
|
||||
dev_t ret = v0::RegisterBlockDevice(DriverID, dev);
|
||||
PortDevices[ret] = port;
|
||||
debug("Port %d \"%s\" registered as %d", i, port->IdentifyData->ModelNumber, ret);
|
||||
break;
|
||||
}
|
||||
case PortType::SEMB:
|
||||
@@ -942,10 +1000,6 @@ namespace Driver::AHCI
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
trace("Initializing AHCI ports");
|
||||
for (auto &&p : PortDevices)
|
||||
p.second->Configure();
|
||||
|
||||
/* We don't use the interrupt handler now... maybe we will in the future */
|
||||
// RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
|
||||
|
||||
@@ -957,7 +1011,7 @@ namespace Driver::AHCI
|
||||
for (auto &&p : PortDevices)
|
||||
{
|
||||
p.second->StopCMD();
|
||||
v0::UnregisterDevice(DriverID, p.first);
|
||||
v0::UnregisterBlockDevice(DriverID, p.first);
|
||||
delete p.second;
|
||||
}
|
||||
|
||||
@@ -966,7 +1020,7 @@ namespace Driver::AHCI
|
||||
// ctx->Device->Header->Command |= PCI::PCI_COMMAND_INTX_DISABLE;
|
||||
|
||||
// std::list<PCI::PCIDevice> Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs);
|
||||
// foreach (auto dev in Devices)
|
||||
// for (auto dev : Devices)
|
||||
// Interrupts::RemoveHandler(OnInterruptReceived, iLine(dev));
|
||||
return 0;
|
||||
}
|
||||
|
4
Kernel/drivers/trusted.c
Normal file
4
Kernel/drivers/trusted.c
Normal file
@@ -0,0 +1,4 @@
|
||||
const char *trusted_drivers[] = {
|
||||
"ae08d2e120c8370278ca9e17085a6b9e2f4a470ab6cec824c77ab1f8706c7144f5d4e1c9820914ed4fc7a4fd22de4b18bfed7c3b5d9c1e604e82280d7d45a5c7",
|
||||
};
|
||||
const __SIZE_TYPE__ trusted_drivers_count = sizeof(trusted_drivers) / sizeof(trusted_drivers[0]);
|
259
Kernel/efi/efi.cpp
Normal file
259
Kernel/efi/efi.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
|
||||
#include <boot/binfo.h>
|
||||
#include <debug.h>
|
||||
#include <memory/virtual.hpp>
|
||||
|
||||
extern struct BootInfo bInfo;
|
||||
|
||||
VOID SearchSMBIOS(EFI_SYSTEM_TABLE *SystemTable)
|
||||
{
|
||||
EFI_GUID Smbios3TableGuid = SMBIOS3_TABLE_GUID;
|
||||
EFI_GUID SmbiosTableGuid = SMBIOS_TABLE_GUID;
|
||||
|
||||
for (UINTN i = 0; i < SystemTable->NumberOfTableEntries; i++)
|
||||
{
|
||||
EFI_CONFIGURATION_TABLE *config = &SystemTable->ConfigurationTable[i];
|
||||
|
||||
/* Can a device have multiple smbios tables? If so, use SMBIOS 3.0 over <2.0 */
|
||||
|
||||
if (CompareGuid(&config->VendorGuid, &SmbiosTableGuid))
|
||||
{
|
||||
bInfo.SMBIOSPtr = config->VendorTable;
|
||||
debug("SMBIOS found at address: %#lx", bInfo.SMBIOSPtr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CompareGuid(&config->VendorGuid, &Smbios3TableGuid))
|
||||
{
|
||||
bInfo.SMBIOSPtr = config->VendorTable;
|
||||
debug("SMBIOS3 found at address: %#lx", bInfo.SMBIOSPtr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID SearchRSDP(EFI_SYSTEM_TABLE *SystemTable)
|
||||
{
|
||||
EFI_GUID AcpiTableGuid = EFI_ACPI_TABLE_GUID;
|
||||
for (UINTN i = 0; i < SystemTable->NumberOfTableEntries; i++)
|
||||
{
|
||||
EFI_CONFIGURATION_TABLE *config = &SystemTable->ConfigurationTable[i];
|
||||
if (CompareGuid(&config->VendorGuid, &AcpiTableGuid))
|
||||
{
|
||||
bInfo.RSDP = (BootInfo::RSDPInfo *)config->VendorTable;
|
||||
debug("RSDP found at address: %#lx", bInfo.RSDP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID InitializeMemoryEntries(EFI_MEMORY_DESCRIPTOR *MemoryMap, UINTN NumberOfEntries, UINTN DescriptorSize)
|
||||
{
|
||||
debug("Memory map: %#lx", MemoryMap);
|
||||
debug("Number of entries: %d", NumberOfEntries);
|
||||
debug("Descriptor size: %d", DescriptorSize);
|
||||
|
||||
for (UINTN i = 0; i < NumberOfEntries; i++)
|
||||
{
|
||||
EFI_MEMORY_DESCRIPTOR *desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + i * DescriptorSize);
|
||||
UNUSED(desc);
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *EFI_MEMORY_TYPE_STRINGS[] = {
|
||||
"ReservedMemoryType",
|
||||
"LoaderCode",
|
||||
"LoaderData",
|
||||
"BootServicesCode",
|
||||
"BootServicesData",
|
||||
"RuntimeServicesCode",
|
||||
"RuntimeServicesData",
|
||||
"ConventionalMemory",
|
||||
"UnusableMemory",
|
||||
"ACPIReclaimMemory",
|
||||
"ACPIMemoryNVS",
|
||||
"MemoryMappedIO",
|
||||
"MemoryMappedIOPortSpace",
|
||||
"PalCode",
|
||||
"PersistentMemory",
|
||||
"MaxMemoryType",
|
||||
"out of bounds?!"};
|
||||
|
||||
size_t type = desc->Type;
|
||||
if (type > sizeof(EFI_MEMORY_TYPE_STRINGS) / sizeof(EFI_MEMORY_TYPE_STRINGS[0]))
|
||||
{
|
||||
type = 16;
|
||||
debug("oh uh, %d is out of bounds!!! t:%#lx p:%#lx v:%#lx n:%lu a:%lx",
|
||||
i, desc->Type,
|
||||
desc->PhysicalStart,
|
||||
desc->VirtualStart,
|
||||
desc->NumberOfPages,
|
||||
desc->Attribute);
|
||||
}
|
||||
|
||||
debug("Entry %d: Type: %s, PhysicalStart: %p, VirtualStart: %p, NumberOfPages: %lu, Attribute: %lx",
|
||||
i, EFI_MEMORY_TYPE_STRINGS[type],
|
||||
desc->PhysicalStart,
|
||||
desc->VirtualStart,
|
||||
desc->NumberOfPages,
|
||||
desc->Attribute);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
VOID InitializeMemory(EFI_SYSTEM_TABLE *SystemTable)
|
||||
{
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMap = (EFI_MEMORY_DESCRIPTOR *)bInfo.EFI.MemoryMap.BaseAddress;
|
||||
UINTN NumberOfEntries = bInfo.EFI.MemoryMap.NumberOfEntries;
|
||||
UINTN DescriptorSize = bInfo.EFI.MemoryMap.DescriptorSize;
|
||||
|
||||
EFI_STATUS Status = SystemTable->BootServices->AllocatePool(EfiLoaderData, NumberOfEntries * DescriptorSize, (void **)&MemoryMap);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
error("Failed to allocate memory for memory map: %#lx", Status);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = SystemTable->BootServices->GetMemoryMap(&NumberOfEntries, MemoryMap, &DescriptorSize, NULL, NULL);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
error("Failed to get memory map: %#lx", Status);
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeMemoryEntries(MemoryMap, NumberOfEntries, DescriptorSize);
|
||||
}
|
||||
|
||||
VOID InitializeMemoryNoBS()
|
||||
{
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMap = (EFI_MEMORY_DESCRIPTOR *)bInfo.EFI.MemoryMap.BaseAddress;
|
||||
UINTN NumberOfEntries = bInfo.EFI.MemoryMap.NumberOfEntries;
|
||||
UINTN DescriptorSize = bInfo.EFI.MemoryMap.DescriptorSize;
|
||||
InitializeMemoryEntries(MemoryMap, NumberOfEntries, DescriptorSize);
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||
{
|
||||
Memory::Virtual va;
|
||||
bool validST = va.Check(SystemTable);
|
||||
bool validIH = va.Check(ImageHandle);
|
||||
trace("map: ST:%d IH:%d", validST, validIH);
|
||||
|
||||
#ifdef DEBUG
|
||||
debug("efi info: %x", bInfo.EFI.Info.raw);
|
||||
if (bInfo.EFI.Info.ST && validST)
|
||||
{
|
||||
EFI_GUID EfiAcpi20Table = EFI_ACPI_20_TABLE_GUID;
|
||||
EFI_GUID AcpiTable = ACPI_TABLE_GUID;
|
||||
EFI_GUID SalSystemTable = SAL_SYSTEM_TABLE_GUID;
|
||||
EFI_GUID SmbiosTable = SMBIOS_TABLE_GUID;
|
||||
EFI_GUID Smbios3Table = SMBIOS3_TABLE_GUID;
|
||||
EFI_GUID MpsTable = MPS_TABLE_GUID;
|
||||
EFI_GUID EfiAcpiTable = EFI_ACPI_TABLE_GUID;
|
||||
EFI_GUID EfiLzmaCompressed = EFI_LZMA_COMPRESSED_GUID;
|
||||
EFI_GUID EfiDxeServices = EFI_DXE_SERVICES_GUID;
|
||||
EFI_GUID EfiHobList = EFI_HOB_LIST_GUID;
|
||||
EFI_GUID EfiMemoryType = _EFI_MEMORY_TYPE_GUID;
|
||||
EFI_GUID EfiDebugImageInfoTable = EFI_DEBUG_IMAGE_INFO_TABLE_GUID;
|
||||
EFI_GUID EfiMemStatusCodeRec = EFI_MEM_STATUS_CODE_REC_GUID;
|
||||
EFI_GUID EfiGuidEfiAcpi1 = EFI_GUID_EFI_ACPI1_GUID;
|
||||
EFI_GUID EfiMemoryAttributesTable = EFI_MEMORY_ATTRIBUTES_TABLE_GUID;
|
||||
EFI_GUID EfiHiiDatabaseProtocol = EFI_HII_DATABASE_PROTOCOL_GUID;
|
||||
EFI_GUID EfiHiiConfigRoutingProtocol = EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
|
||||
EFI_GUID TCG2FinalEventsTable = TCG2_FINAL_EVENTS_TABLE_GUID;
|
||||
EFI_GUID EfiImageSecurityDatabase = EFI_IMAGE_SECURITY_DATABASE_GUID;
|
||||
EFI_GUID EfiSystemResourceTable = EFI_SYSTEM_RESOURCE_TABLE_GUID;
|
||||
|
||||
debug("there are %d configuration tables", SystemTable->NumberOfTableEntries);
|
||||
for (UINTN i = 0; i < SystemTable->NumberOfTableEntries; i++)
|
||||
{
|
||||
EFI_CONFIGURATION_TABLE *config = &SystemTable->ConfigurationTable[i];
|
||||
EFI_GUID *g = &config->VendorGuid;
|
||||
void *addr = config->VendorTable;
|
||||
|
||||
const char *guid_str = NULL;
|
||||
if (CompareGuid(g, &EfiAcpi20Table))
|
||||
guid_str = "EFI ACPI 2.0 Table";
|
||||
else if (CompareGuid(g, &AcpiTable))
|
||||
guid_str = "ACPI Table";
|
||||
else if (CompareGuid(g, &SalSystemTable))
|
||||
guid_str = "SAL System Table";
|
||||
else if (CompareGuid(g, &SmbiosTable))
|
||||
guid_str = "SMBIOS Table";
|
||||
else if (CompareGuid(g, &Smbios3Table))
|
||||
guid_str = "SMBIOS 3 Table";
|
||||
else if (CompareGuid(g, &MpsTable))
|
||||
guid_str = "MPS Table";
|
||||
else if (CompareGuid(g, &EfiAcpiTable))
|
||||
guid_str = "EFI ACPI Table";
|
||||
else if (CompareGuid(g, &EfiLzmaCompressed))
|
||||
guid_str = "EFI LZMA Compressed";
|
||||
else if (CompareGuid(g, &EfiDxeServices))
|
||||
guid_str = "EFI DXE Services";
|
||||
else if (CompareGuid(g, &EfiHobList))
|
||||
guid_str = "EFI HOB List";
|
||||
else if (CompareGuid(g, &EfiMemoryType))
|
||||
guid_str = "EFI Memory Type";
|
||||
else if (CompareGuid(g, &EfiDebugImageInfoTable))
|
||||
guid_str = "EFI Debug Image Info Table";
|
||||
else if (CompareGuid(g, &EfiMemStatusCodeRec))
|
||||
guid_str = "EFI Memory Status Code Record";
|
||||
else if (CompareGuid(g, &EfiGuidEfiAcpi1))
|
||||
guid_str = "EFI ACPI 1.0 Table";
|
||||
else if (CompareGuid(g, &EfiMemoryAttributesTable))
|
||||
guid_str = "EFI Memory Attributes Table";
|
||||
else if (CompareGuid(g, &EfiHiiDatabaseProtocol))
|
||||
guid_str = "EFI HII Database Protocol";
|
||||
else if (CompareGuid(g, &EfiHiiConfigRoutingProtocol))
|
||||
guid_str = "EFI HII Config Routing Protocol";
|
||||
else if (CompareGuid(g, &TCG2FinalEventsTable))
|
||||
guid_str = "TCG2 Final Events Table";
|
||||
else if (CompareGuid(g, &EfiImageSecurityDatabase))
|
||||
guid_str = "EFI Image Security Database";
|
||||
else if (CompareGuid(g, &EfiSystemResourceTable))
|
||||
guid_str = "EFI System Resource Table";
|
||||
else
|
||||
guid_str = "(unknown)";
|
||||
|
||||
debug("%016lx %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x %s",
|
||||
(UINT64)(uintptr_t)addr,
|
||||
g->Data1, g->Data2, g->Data3,
|
||||
g->Data4[0], g->Data4[1],
|
||||
g->Data4[2], g->Data4[3],
|
||||
g->Data4[4], g->Data4[5],
|
||||
g->Data4[6], g->Data4[7],
|
||||
guid_str);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bInfo.EFI.Info.ST == 1 && validST)
|
||||
{
|
||||
SearchSMBIOS(SystemTable);
|
||||
SearchRSDP(SystemTable);
|
||||
}
|
||||
|
||||
if (bInfo.EFI.Info.BS == 0 && bInfo.EFI.Info.MemoryMap == 1)
|
||||
InitializeMemoryNoBS();
|
||||
else if (bInfo.EFI.Info.BS == 1)
|
||||
InitializeMemory(SystemTable);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
36
Kernel/efi/lib.cpp
Normal file
36
Kernel/efi/lib.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
|
||||
#include <convert.h>
|
||||
|
||||
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
|
||||
{
|
||||
if (Guid1 == NULL || Guid2 == NULL)
|
||||
return FALSE;
|
||||
|
||||
return (Guid1->Data1 == Guid2->Data1 &&
|
||||
Guid1->Data2 == Guid2->Data2 &&
|
||||
Guid1->Data3 == Guid2->Data3 &&
|
||||
memcmp(Guid1->Data4, Guid2->Data4, sizeof(Guid1->Data4)) == 0);
|
||||
}
|
||||
|
||||
VOID InitializeLib(IN EFI_HANDLE, IN EFI_SYSTEM_TABLE *)
|
||||
{
|
||||
/* Does nothing */
|
||||
}
|
@@ -25,82 +25,88 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
BinaryType GetBinaryType(FileNode *Node)
|
||||
BinaryType GetBinaryType(Node &Node)
|
||||
{
|
||||
debug("Checking binary type of %s", Node->Path.c_str());
|
||||
BinaryType Type;
|
||||
BinaryType type;
|
||||
|
||||
if (Node == nullptr)
|
||||
ReturnLogError((BinaryType)-ENOENT, "Node is null");
|
||||
|
||||
Elf32_Ehdr ELFHeader;
|
||||
Node->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0);
|
||||
Elf_Ehdr ehdr;
|
||||
fs->Read(Node, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
mach_header MachHeader;
|
||||
Node->Read(&MachHeader, sizeof(mach_header), 0);
|
||||
mach_header mach;
|
||||
fs->Read(Node, &mach, sizeof(mach_header), 0);
|
||||
|
||||
IMAGE_DOS_HEADER MZHeader;
|
||||
Node->Read(&MZHeader, sizeof(IMAGE_DOS_HEADER), 0);
|
||||
IMAGE_DOS_HEADER mz;
|
||||
fs->Read(Node, &mz, sizeof(IMAGE_DOS_HEADER), 0);
|
||||
|
||||
/* Check ELF header. */
|
||||
if (ELFHeader.e_ident[EI_MAG0] == ELFMAG0 &&
|
||||
ELFHeader.e_ident[EI_MAG1] == ELFMAG1 &&
|
||||
ELFHeader.e_ident[EI_MAG2] == ELFMAG2 &&
|
||||
ELFHeader.e_ident[EI_MAG3] == ELFMAG3)
|
||||
if (ehdr.e_ident[EI_MAG0] == ELFMAG0 &&
|
||||
ehdr.e_ident[EI_MAG1] == ELFMAG1 &&
|
||||
ehdr.e_ident[EI_MAG2] == ELFMAG2 &&
|
||||
ehdr.e_ident[EI_MAG3] == ELFMAG3)
|
||||
{
|
||||
debug("Image - ELF");
|
||||
Type = BinaryType::BinTypeELF;
|
||||
type = BinaryType::BinTypeELF;
|
||||
goto Success;
|
||||
}
|
||||
|
||||
if (MachHeader.magic == MH_MAGIC || MachHeader.magic == MH_CIGAM)
|
||||
if (mach.magic == MH_MAGIC || mach.magic == MH_CIGAM)
|
||||
{
|
||||
debug("Image - Mach-O");
|
||||
Type = BinaryType::BinTypeMachO;
|
||||
type = BinaryType::BinTypeMachO;
|
||||
goto Success;
|
||||
}
|
||||
|
||||
/* Check MZ header. */
|
||||
else if (MZHeader.e_magic == IMAGE_DOS_SIGNATURE)
|
||||
else if (mz.e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
IMAGE_NT_HEADERS PEHeader;
|
||||
Node->Read(&PEHeader, sizeof(IMAGE_NT_HEADERS), MZHeader.e_lfanew);
|
||||
IMAGE_NT_HEADERS pe;
|
||||
fs->Read(Node, &pe, sizeof(IMAGE_NT_HEADERS), mz.e_lfanew);
|
||||
|
||||
IMAGE_OS2_HEADER NEHeader;
|
||||
Node->Read(&NEHeader, sizeof(IMAGE_OS2_HEADER), MZHeader.e_lfanew);
|
||||
IMAGE_OS2_HEADER ne;
|
||||
fs->Read(Node, &ne, sizeof(IMAGE_OS2_HEADER), mz.e_lfanew);
|
||||
|
||||
/* TODO: LE, EDOS */
|
||||
if (PEHeader.Signature == IMAGE_NT_SIGNATURE)
|
||||
if (pe.Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
debug("Image - PE");
|
||||
Type = BinaryType::BinTypePE;
|
||||
type = BinaryType::BinTypePE;
|
||||
goto Success;
|
||||
}
|
||||
else if (NEHeader.ne_magic == IMAGE_OS2_SIGNATURE)
|
||||
else if (ne.ne_magic == IMAGE_OS2_SIGNATURE)
|
||||
{
|
||||
debug("Image - NE");
|
||||
Type = BinaryType::BinTypeNE;
|
||||
type = BinaryType::BinTypeNE;
|
||||
goto Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Image - MZ");
|
||||
Type = BinaryType::BinTypeMZ;
|
||||
type = BinaryType::BinTypeMZ;
|
||||
goto Success;
|
||||
}
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
Type = BinaryType::BinTypeUnknown;
|
||||
type = BinaryType::BinTypeUnknown;
|
||||
Success:
|
||||
return Type;
|
||||
return type;
|
||||
}
|
||||
|
||||
BinaryType GetBinaryType(std::string Path)
|
||||
{
|
||||
FileNode *node = fs->GetByPath(Path.c_str(), nullptr);
|
||||
debug("Checking binary type of %s (returning %p)", Path.c_str(), node);
|
||||
Node node = fs->Lookup(thisProcess->Info.RootNode, Path);
|
||||
if (node->IsSymbolicLink())
|
||||
{
|
||||
char buffer[512];
|
||||
fs->ReadLink(node, buffer, sizeof(buffer));
|
||||
node = fs->Lookup(node->Parent, buffer);
|
||||
}
|
||||
debug("Checking binary type of %s (returning %p)", Path.c_str(), node.get());
|
||||
assert(node != nullptr);
|
||||
return GetBinaryType(node);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -25,52 +25,52 @@ namespace Execute
|
||||
{
|
||||
bool ELFIs64(void *Header)
|
||||
{
|
||||
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Header;
|
||||
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
Elf_Ehdr *ehdr = (Elf_Ehdr *)Header;
|
||||
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||
|
||||
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
|
||||
Elf_Shdr *GetELFSheader(Elf_Ehdr *Header)
|
||||
{
|
||||
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
|
||||
return (Elf_Shdr *)((uintptr_t)Header + Header->e_shoff);
|
||||
}
|
||||
|
||||
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
|
||||
Elf_Shdr *GetELFSection(Elf_Ehdr *Header, uintptr_t Index)
|
||||
{
|
||||
return &GetELFSheader(Header)[Index];
|
||||
}
|
||||
|
||||
char *GetELFStringTable(Elf64_Ehdr *Header)
|
||||
char *GetELFStringTable(Elf_Ehdr *Header)
|
||||
{
|
||||
if (Header->e_shstrndx == SHN_UNDEF)
|
||||
return nullptr;
|
||||
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
|
||||
}
|
||||
|
||||
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
|
||||
char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset)
|
||||
{
|
||||
char *StringTable = GetELFStringTable(Header);
|
||||
if (StringTable == nullptr)
|
||||
char *table = GetELFStringTable(Header);
|
||||
if (table == nullptr)
|
||||
return nullptr;
|
||||
return StringTable + Offset;
|
||||
return table + Offset;
|
||||
}
|
||||
|
||||
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, std::string Name)
|
||||
Elf_Sym *ELFLookupSymbol(Elf_Ehdr *Header, std::string Name)
|
||||
{
|
||||
Elf64_Shdr *SymbolTable = nullptr;
|
||||
Elf64_Shdr *StringTable = nullptr;
|
||||
Elf_Shdr *symTable = nullptr;
|
||||
Elf_Shdr *stringTable = nullptr;
|
||||
|
||||
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
|
||||
for (Elf_Half i = 0; i < Header->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *shdr = GetELFSection(Header, i);
|
||||
Elf_Shdr *shdr = GetELFSection(Header, i);
|
||||
switch (shdr->sh_type)
|
||||
{
|
||||
case SHT_SYMTAB:
|
||||
SymbolTable = shdr;
|
||||
StringTable = GetELFSection(Header, shdr->sh_link);
|
||||
symTable = shdr;
|
||||
stringTable = GetELFSection(Header, shdr->sh_link);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
@@ -79,117 +79,108 @@ namespace Execute
|
||||
}
|
||||
}
|
||||
|
||||
if (SymbolTable == nullptr || StringTable == nullptr)
|
||||
if (symTable == nullptr || stringTable == nullptr)
|
||||
return nullptr;
|
||||
|
||||
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
|
||||
for (size_t i = 0; i < (symTable->sh_size / sizeof(Elf_Sym)); i++)
|
||||
{
|
||||
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
Elf_Sym *sym = (Elf_Sym *)((uintptr_t)Header + symTable->sh_offset + (i * sizeof(Elf_Sym)));
|
||||
char *String = (char *)((uintptr_t)Header + stringTable->sh_offset + sym->st_name);
|
||||
if (strcmp(String, Name.c_str()) == 0)
|
||||
return Symbol;
|
||||
return sym;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Elf64_Sym ELFLookupSymbol(FileNode *fd, std::string Name)
|
||||
Elf_Sym ELFLookupSymbol(Node fd, std::string Name)
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
Elf64_Ehdr Header{};
|
||||
fd->Read(&Header, sizeof(Elf64_Ehdr), 0);
|
||||
Elf_Ehdr ehdr{};
|
||||
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
Elf64_Shdr SymbolTable{};
|
||||
Elf64_Shdr StringTable{};
|
||||
Elf_Shdr symTable{};
|
||||
Elf_Shdr stringTable{};
|
||||
|
||||
for (Elf64_Half i = 0; i < Header.e_shnum; i++)
|
||||
for (Elf64_Half i = 0; i < ehdr.e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr shdr;
|
||||
fd->Read(&shdr, sizeof(Elf64_Shdr), Header.e_shoff + (i * sizeof(Elf64_Shdr)));
|
||||
Elf_Shdr shdr;
|
||||
fs->Read(fd, &shdr, sizeof(Elf_Shdr), ehdr.e_shoff + (i * sizeof(Elf_Shdr)));
|
||||
|
||||
switch (shdr.sh_type)
|
||||
{
|
||||
case SHT_SYMTAB:
|
||||
SymbolTable = shdr;
|
||||
fd->Read(&StringTable, sizeof(Elf64_Shdr), Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)));
|
||||
symTable = shdr;
|
||||
fs->Read(fd, &stringTable, sizeof(Elf_Shdr), ehdr.e_shoff + (shdr.sh_link * sizeof(Elf_Shdr)));
|
||||
break;
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SymbolTable.sh_name == 0 || StringTable.sh_name == 0)
|
||||
if (symTable.sh_name == 0 || stringTable.sh_name == 0)
|
||||
{
|
||||
error("Symbol table not found.");
|
||||
return {};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
|
||||
for (size_t i = 0; i < (symTable.sh_size / sizeof(Elf_Sym)); i++)
|
||||
{
|
||||
// Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
Elf64_Sym Symbol;
|
||||
fd->Read(&Symbol, sizeof(Elf64_Sym), SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
// Elf_Sym *sym = (Elf_Sym *)((uintptr_t)Header + symTable->sh_offset + (i * sizeof(Elf_Sym)));
|
||||
Elf_Sym sym;
|
||||
fs->Read(fd, &sym, sizeof(Elf_Sym), symTable.sh_offset + (i * sizeof(Elf_Sym)));
|
||||
|
||||
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
char String[256];
|
||||
fd->Read(&String, sizeof(String), StringTable.sh_offset + Symbol.st_name);
|
||||
// char *str = (char *)((uintptr_t)Header + stringTable->sh_offset + sym->st_name);
|
||||
char str[256];
|
||||
fs->Read(fd, &str, sizeof(str), stringTable.sh_offset + sym.st_name);
|
||||
|
||||
if (strcmp(String, Name.c_str()) == 0)
|
||||
return Symbol;
|
||||
if (strcmp(str, Name.c_str()) == 0)
|
||||
return sym;
|
||||
}
|
||||
error("Symbol not found.");
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
|
||||
uintptr_t ELFGetSymbolValue(Elf_Ehdr *Header, uintptr_t Table, uintptr_t Index)
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
|
||||
return 0;
|
||||
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
|
||||
|
||||
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
|
||||
if (Index >= STEntries)
|
||||
Elf_Shdr *symTable = GetELFSection(Header, Table);
|
||||
|
||||
uintptr_t entries = symTable->sh_size / symTable->sh_entsize;
|
||||
if (Index >= entries)
|
||||
{
|
||||
error("Symbol index out of range %d-%u.", Table, Index);
|
||||
return 0xdead;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
|
||||
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
|
||||
uintptr_t symbolPtr = (uintptr_t)Header + symTable->sh_offset;
|
||||
Elf_Sym *sym = &((Elf_Sym *)symbolPtr)[Index];
|
||||
|
||||
if (Symbol->st_shndx == SHN_UNDEF)
|
||||
if (sym->st_shndx == SHN_UNDEF)
|
||||
{
|
||||
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
|
||||
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
|
||||
Elf_Shdr *stringTable = GetELFSection(Header, symTable->sh_link);
|
||||
const char *name = (const char *)Header + stringTable->sh_offset + sym->st_name;
|
||||
|
||||
void *Target = (void *)ELFLookupSymbol(Header, Name)->st_value;
|
||||
if (Target == nullptr)
|
||||
void *target = (void *)ELFLookupSymbol(Header, name)->st_value;
|
||||
if (target == nullptr)
|
||||
{
|
||||
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
|
||||
if (ELF64_ST_BIND(sym->st_info) & STB_WEAK)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
error("Undefined external symbol \"%s\".", Name);
|
||||
return 0xdead;
|
||||
error("Undefined external symbol \"%s\".", name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return (uintptr_t)Target;
|
||||
return (uintptr_t)target;
|
||||
}
|
||||
else if (Symbol->st_shndx == SHN_ABS)
|
||||
return Symbol->st_value;
|
||||
else if (sym->st_shndx == SHN_ABS)
|
||||
return sym->st_value;
|
||||
else
|
||||
{
|
||||
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
|
||||
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
|
||||
Elf_Shdr *shdr = GetELFSection(Header, sym->st_shndx);
|
||||
return (uintptr_t)Header + sym->st_value + shdr->sh_offset;
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
return 0xdead;
|
||||
#elif defined(__aarch64__)
|
||||
return 0xdead;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@@ -25,77 +25,72 @@ namespace Execute
|
||||
{
|
||||
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||
|
||||
void ELFLoadRel(void *BaseImage,
|
||||
const char *Name,
|
||||
Tasking::PCB *Process)
|
||||
void ELFLoadRel(void *BaseImage, const char *Name, Tasking::PCB *Process)
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
UNUSED(Name);
|
||||
debug("Relocatable");
|
||||
/* TODO: I have to fully implement this, but for now I will leave it as it is now. */
|
||||
warn("Relocatable ELF is not fully supported yet");
|
||||
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
|
||||
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
|
||||
Elf_Shdr *shdr = GetELFSheader(((Elf_Ehdr *)BaseImage));
|
||||
for (Elf_Half i = 0; i < ((Elf_Ehdr *)BaseImage)->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *Section = &shdr[i];
|
||||
if (Section->sh_type == SHT_NOBITS)
|
||||
Elf_Shdr *section = &shdr[i];
|
||||
if (section->sh_type == SHT_NOBITS)
|
||||
{
|
||||
if (!Section->sh_size)
|
||||
if (!section->sh_size)
|
||||
continue;
|
||||
if (Section->sh_flags & SHF_ALLOC)
|
||||
if (section->sh_flags & SHF_ALLOC)
|
||||
{
|
||||
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size + 1));
|
||||
memset(Buffer, 0, Section->sh_size);
|
||||
void *buffer = KernelAllocator.RequestPages(TO_PAGES(section->sh_size + 1));
|
||||
memset(buffer, 0, section->sh_size);
|
||||
|
||||
Memory::Virtual(Process->PageTable).Map((void *)Buffer, (void *)Buffer, Section->sh_size, Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
Memory::Virtual(Process->PageTable).Map((void *)buffer, (void *)buffer, section->sh_size, Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage;
|
||||
debug("Section %ld", Section->sh_size);
|
||||
section->sh_offset = (uintptr_t)buffer - (uintptr_t)BaseImage;
|
||||
debug("Section %ld", section->sh_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
|
||||
for (Elf_Half i = 0; i < ((Elf_Ehdr *)BaseImage)->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *Section = &shdr[i];
|
||||
if (Section->sh_type == SHT_REL)
|
||||
Elf_Shdr *section = &shdr[i];
|
||||
if (section->sh_type == SHT_REL)
|
||||
{
|
||||
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
|
||||
for (size_t i = 0; i < section->sh_size / section->sh_entsize; i++)
|
||||
{
|
||||
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index];
|
||||
Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info);
|
||||
Elf_Rel *rel = &((Elf_Rel *)((uintptr_t)BaseImage + section->sh_offset))[i];
|
||||
Elf_Shdr *target = GetELFSection(((Elf_Ehdr *)BaseImage), section->sh_info);
|
||||
|
||||
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset);
|
||||
uint64_t SymbolValue = 0;
|
||||
uintptr_t *relPtr = (uintptr_t *)(((uintptr_t)BaseImage + target->sh_offset) + rel->r_offset);
|
||||
uintptr_t value = 0;
|
||||
|
||||
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
|
||||
if (ELF_R_SYM(rel->r_info) != SHN_UNDEF)
|
||||
{
|
||||
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
|
||||
if (SymbolValue == 0xdead)
|
||||
value = ELFGetSymbolValue(((Elf_Ehdr *)BaseImage), section->sh_link, ELF_R_SYM(rel->r_info));
|
||||
if (value == (uintptr_t)-1)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ELF64_R_TYPE(RelTable->r_info))
|
||||
switch (ELF64_R_TYPE(rel->r_info))
|
||||
{
|
||||
case R_386_NONE:
|
||||
break;
|
||||
case R_386_32:
|
||||
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
|
||||
*relPtr = DO_64_64(value, *relPtr);
|
||||
break;
|
||||
case R_386_PC32:
|
||||
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
|
||||
*relPtr = DO_64_PC32(value, *relPtr, (uintptr_t)relPtr);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
|
||||
error("Unsupported relocation type: %d", ELF64_R_TYPE(rel->r_info));
|
||||
return;
|
||||
}
|
||||
}
|
||||
debug("Symbol value: %#lx", SymbolValue);
|
||||
debug("Symbol value: %#lx", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@@ -21,42 +21,31 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(FileNode *fd,
|
||||
DynamicArrayTags Tag)
|
||||
std::vector<Elf_Dyn> ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__aarch64__)
|
||||
std::vector<Elf64_Dyn> Ret;
|
||||
std::vector<Elf_Dyn> ret;
|
||||
std::vector<Elf_Phdr> phdrs = ELFGetSymbolType(fd, PT_DYNAMIC);
|
||||
|
||||
Elf64_Ehdr ELFHeader{};
|
||||
fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0);
|
||||
|
||||
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, PT_DYNAMIC);
|
||||
|
||||
if (DYNAMICPhdrs.size() < 1)
|
||||
if (phdrs.empty())
|
||||
{
|
||||
error("No dynamic phdrs found.");
|
||||
return Ret;
|
||||
debug("No dynamic phdrs found.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
foreach (auto Phdr in DYNAMICPhdrs)
|
||||
for (auto phdr : phdrs)
|
||||
{
|
||||
Elf64_Dyn Dynamic{};
|
||||
for (size_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++)
|
||||
Elf_Dyn dyn;
|
||||
for (size_t i = 0; i < phdr.p_filesz / sizeof(Elf_Dyn); i++)
|
||||
{
|
||||
fd->Read(&Dynamic, sizeof(Elf64_Dyn), Phdr.p_offset + (i * sizeof(Elf64_Dyn)));
|
||||
|
||||
if (Dynamic.d_tag != Tag)
|
||||
fs->Read(fd, &dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn)));
|
||||
if (dyn.d_tag != Tag)
|
||||
continue;
|
||||
|
||||
debug("Found dynamic tag %d at %#lx [d_val: %#lx]",
|
||||
Tag, &Dynamic, Dynamic.d_un.d_val);
|
||||
Ret.push_back(Dynamic);
|
||||
debug("Found dynamic tag %d at %#lx [d_val: %#lx]", Tag, &dyn, dyn.d_un.d_val);
|
||||
ret.push_back(dyn);
|
||||
}
|
||||
}
|
||||
|
||||
return Ret;
|
||||
#elif defined(__i386__)
|
||||
return {};
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@@ -21,33 +21,26 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf64_Shdr> ELFGetSections_x86_64(FileNode *fd,
|
||||
const char *SectionName)
|
||||
std::vector<Elf_Shdr> ELFGetSections(Node fd, const char *SectionName)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__aarch64__)
|
||||
std::vector<Elf64_Shdr> Ret;
|
||||
std::vector<Elf_Shdr> ret;
|
||||
|
||||
Elf64_Ehdr ELFHeader{};
|
||||
fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0);
|
||||
Elf_Ehdr ehdr;
|
||||
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum];
|
||||
fd->Read(SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum, ELFHeader.e_shoff);
|
||||
std::unique_ptr<Elf_Shdr[]> sections(new Elf_Shdr[ehdr.e_shnum]);
|
||||
fs->Read(fd, sections.get(), sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff);
|
||||
|
||||
char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size];
|
||||
fd->Read(SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size, SectionHeaders[ELFHeader.e_shstrndx].sh_offset);
|
||||
std::string sectionNames(sections[ehdr.e_shstrndx].sh_size, '\0');
|
||||
fs->Read(fd, sectionNames.data(), sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset);
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; ++i)
|
||||
for (Elf_Half i = 0; i < ehdr.e_shnum; ++i)
|
||||
{
|
||||
const char *Name = SectionNames + SectionHeaders[i].sh_name;
|
||||
const char *Name = sectionNames.data() + sections[i].sh_name;
|
||||
if (strcmp(Name, SectionName) == 0)
|
||||
Ret.push_back(SectionHeaders[i]);
|
||||
ret.push_back(sections[i]);
|
||||
}
|
||||
|
||||
delete[] SectionHeaders;
|
||||
delete[] SectionNames;
|
||||
return Ret;
|
||||
#elif defined(__i386__)
|
||||
return {};
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@@ -21,31 +21,26 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(FileNode *fd,
|
||||
SegmentTypes Tag)
|
||||
std::vector<Elf_Phdr> ELFGetSymbolType(Node &fd, SegmentTypes Tag)
|
||||
{
|
||||
#if defined(__amd64__) || defined(__aarch64__)
|
||||
std::vector<Elf64_Phdr> Ret;
|
||||
std::vector<Elf_Phdr> ret;
|
||||
|
||||
Elf64_Ehdr ELFHeader{};
|
||||
fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0);
|
||||
Elf_Ehdr ehdr;
|
||||
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
Elf64_Phdr ProgramHeaders{};
|
||||
fd->Read(&ProgramHeaders, sizeof(Elf64_Phdr), ELFHeader.e_phoff);
|
||||
Elf_Phdr phdr;
|
||||
fs->Read(fd, &phdr, sizeof(Elf_Phdr), ehdr.e_phoff);
|
||||
|
||||
off_t currentOffset = ELFHeader.e_phoff;
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
off_t off = ehdr.e_phoff;
|
||||
for (Elf_Half i = 0; i < ehdr.e_phnum; i++)
|
||||
{
|
||||
if (ProgramHeaders.p_type == Tag)
|
||||
Ret.push_back(ProgramHeaders);
|
||||
if (phdr.p_type == Tag)
|
||||
ret.push_back(phdr);
|
||||
|
||||
currentOffset += sizeof(Elf64_Phdr);
|
||||
fd->Read(&ProgramHeaders, sizeof(Elf64_Phdr), currentOffset);
|
||||
off += sizeof(Elf_Phdr);
|
||||
fs->Read(fd, &phdr, sizeof(Elf_Phdr), off);
|
||||
}
|
||||
|
||||
return Ret;
|
||||
#elif defined(__i386__)
|
||||
return {};
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@@ -30,19 +30,36 @@ using namespace Tasking;
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
int Spawn(char *Path, const char **argv, const char **envp,
|
||||
int Spawn(const char *Path, const char **argv, const char **envp,
|
||||
Tasking::PCB *Parent, bool Fork,
|
||||
Tasking::TaskCompatibility Compatibility,
|
||||
bool Critical)
|
||||
{
|
||||
FileNode *fd = fs->GetByPath(Path, nullptr);
|
||||
if (Parent == nullptr)
|
||||
{
|
||||
debug("no parent specified, using current process");
|
||||
Parent = thisProcess;
|
||||
}
|
||||
|
||||
Node fd = fs->Lookup(Parent->Info.RootNode, Path);
|
||||
if (fd == nullptr)
|
||||
return -ENOENT;
|
||||
|
||||
if (!fd->IsRegularFile())
|
||||
return -ENOEXEC;
|
||||
{
|
||||
if (fd->IsSymbolicLink())
|
||||
{
|
||||
char buffer[512];
|
||||
fs->ReadLink(fd, buffer, sizeof(buffer));
|
||||
fd = fs->Lookup(fd->Parent, buffer);
|
||||
if (fd == nullptr)
|
||||
return -ENOENT;
|
||||
}
|
||||
else
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
switch (GetBinaryType(Path))
|
||||
switch (GetBinaryType(fd))
|
||||
{
|
||||
case BinaryType::BinTypeELF:
|
||||
{
|
||||
@@ -50,7 +67,7 @@ namespace Execute
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
Elf32_Ehdr ELFHeader;
|
||||
fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0);
|
||||
fs->Read(fd, &ELFHeader, sizeof(Elf32_Ehdr), 0);
|
||||
|
||||
switch (ELFHeader.e_machine)
|
||||
{
|
||||
@@ -97,11 +114,10 @@ namespace Execute
|
||||
PCB *Process;
|
||||
if (Fork)
|
||||
{
|
||||
assert(Parent != nullptr);
|
||||
CriticalSection cs;
|
||||
|
||||
Process = Parent;
|
||||
foreach (auto tcb in Process->Threads)
|
||||
for (auto tcb : Process->Threads)
|
||||
{
|
||||
debug("Deleting thread %d", tcb->ID);
|
||||
// delete tcb;
|
||||
@@ -113,17 +129,13 @@ namespace Execute
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Parent == nullptr)
|
||||
Parent = thisProcess;
|
||||
|
||||
Process = TaskManager->CreateProcess(Parent, BaseName,
|
||||
TaskExecutionMode::User,
|
||||
false, 0, 0);
|
||||
Process = TaskManager->CreateProcess(Parent, BaseName, User, false, 0, 0);
|
||||
Process->Info.Compatibility = Compatibility;
|
||||
Process->Info.Architecture = Arch;
|
||||
}
|
||||
|
||||
Process->SetWorkingDirectory(fs->GetByPath(Path, nullptr)->Parent);
|
||||
Node cwdNode = fs->Lookup(Parent->Info.RootNode, Path);
|
||||
Process->SetWorkingDirectory(fs->Convert(cwdNode->Parent));
|
||||
Process->SetExe(Path);
|
||||
|
||||
ELFObject *obj = new ELFObject(Path, Process, argv, envp);
|
||||
@@ -137,38 +149,37 @@ namespace Execute
|
||||
vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors;
|
||||
vfs::FileDescriptorTable *fdt = Process->FileDescriptors;
|
||||
|
||||
auto ForkStdio = [pfdt, fdt](FileNode *SearchNode)
|
||||
auto ForkStdio = [pfdt, fdt](Node SearchNode)
|
||||
{
|
||||
if (unlikely(SearchNode == nullptr))
|
||||
if (unlikely(SearchNode.get() == nullptr))
|
||||
return false;
|
||||
|
||||
foreach (const auto &ffd in pfdt->FileMap)
|
||||
for (const auto &ffd : pfdt->FileMap)
|
||||
{
|
||||
if (ffd.second.Flags & O_CLOEXEC)
|
||||
continue;
|
||||
|
||||
if (ffd.second.Node == SearchNode)
|
||||
{
|
||||
fdt->usr_open(ffd.second.Node->Path.c_str(),
|
||||
ffd.second.Flags, ffd.second.Mode);
|
||||
return true;
|
||||
}
|
||||
if (ffd.second.node.get() != SearchNode.get())
|
||||
continue;
|
||||
|
||||
fdt->usr_open(ffd.second.node->Path.c_str(), ffd.second.Flags, ffd.second.Mode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
fixme("remove workarounds for stdio and tty");
|
||||
if (!Parent->tty)
|
||||
Process->tty = KernelConsole::CurrentTerminal.load();
|
||||
Process->tty = KernelConsole::CurrentTerminal.load()->Term;
|
||||
|
||||
if (!ForkStdio(Parent->stdin))
|
||||
fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
fdt->usr_open("/dev/console", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
||||
if (!ForkStdio(Parent->stdout))
|
||||
fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
fdt->usr_open("/dev/console", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
||||
if (!ForkStdio(Parent->stderr))
|
||||
fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
fdt->usr_open("/dev/console", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
||||
TCB *Thread = nullptr;
|
||||
{
|
||||
|
BIN
Kernel/files/logo.png
Normal file
BIN
Kernel/files/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
@@ -15,7 +15,7 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <stropts.h>
|
||||
@@ -47,8 +47,7 @@ namespace vfs
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath,
|
||||
mode_t Mode, int Flags)
|
||||
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags)
|
||||
{
|
||||
Tasking::PCB *pcb = thisProcess;
|
||||
|
||||
@@ -77,8 +76,7 @@ namespace vfs
|
||||
|
||||
if (Flags & O_RDWR)
|
||||
{
|
||||
if (!(Mode & S_IRUSR) ||
|
||||
!(Mode & S_IWUSR))
|
||||
if (!(Mode & S_IRUSR) || !(Mode & S_IWUSR))
|
||||
{
|
||||
debug("No read/write permission (%d)", Mode);
|
||||
return -EACCES;
|
||||
@@ -95,12 +93,11 @@ namespace vfs
|
||||
|
||||
if (Flags & O_CREAT)
|
||||
{
|
||||
FileNode *ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
|
||||
if (Flags & O_EXCL && ret == nullptr)
|
||||
eNode ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
|
||||
if (Flags & O_EXCL && ret == false)
|
||||
{
|
||||
debug("%s: File already exists?, returning EEXIST",
|
||||
AbsolutePath);
|
||||
return -EEXIST;
|
||||
debug("%s: File already exists?, returning %s", AbsolutePath, ret.what());
|
||||
return -ret.Error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,18 +106,18 @@ namespace vfs
|
||||
fixme("O_CLOEXEC");
|
||||
}
|
||||
|
||||
FileNode *File = fs->GetByPath(AbsolutePath, pcb->CWD);
|
||||
|
||||
if (!File)
|
||||
eNode ret = fs->Lookup(pcb->CWD, AbsolutePath);
|
||||
if (ret == false)
|
||||
{
|
||||
error("Failed to open file %s", AbsolutePath);
|
||||
return -ENOENT;
|
||||
error("Failed to open file %s, %s", AbsolutePath, ret.what());
|
||||
return -ret.Error;
|
||||
}
|
||||
Node node = ret;
|
||||
|
||||
if (Flags & O_TRUNC)
|
||||
{
|
||||
debug("Truncating file %s", AbsolutePath);
|
||||
File->Truncate(0);
|
||||
fs->Truncate(node, 0);
|
||||
}
|
||||
|
||||
Fildes fd{};
|
||||
@@ -129,13 +126,13 @@ namespace vfs
|
||||
{
|
||||
debug("Appending to file %s", AbsolutePath);
|
||||
struct kstat stat;
|
||||
File->Stat(&stat);
|
||||
fd.Offset = File->Seek(stat.Size);
|
||||
fs->Stat(node, &stat);
|
||||
fd.Offset = fs->Seek(node, stat.Size);
|
||||
}
|
||||
|
||||
fd.Mode = Mode;
|
||||
fd.Flags = Flags;
|
||||
fd.Node = File;
|
||||
fd.node = node;
|
||||
|
||||
int fdn = this->GetFreeFileDescriptor();
|
||||
if (fdn < 0)
|
||||
@@ -145,9 +142,8 @@ namespace vfs
|
||||
|
||||
char linkName[64];
|
||||
snprintf(linkName, 64, "%d", fdn);
|
||||
assert(fs->CreateLink(linkName, this->fdDir, AbsolutePath) != nullptr);
|
||||
|
||||
File->Open(Flags, Mode);
|
||||
assert(fs->CreateLink(this->fdDir, linkName, AbsolutePath) == true);
|
||||
fs->Open(node, Flags, Mode);
|
||||
return fdn;
|
||||
}
|
||||
|
||||
@@ -157,7 +153,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor);
|
||||
|
||||
fs->Remove(it->second.Node);
|
||||
fs->Remove(it->second.node);
|
||||
this->FileMap.erase(it);
|
||||
return 0;
|
||||
}
|
||||
@@ -209,7 +205,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Read(buf, count, it->second.Offset);
|
||||
return fs->Read(it->second.node, buf, count, it->second.Offset);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::usr_pread(int fd, void *buf, size_t count, off_t offset)
|
||||
@@ -218,7 +214,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Read(buf, count, offset);
|
||||
return fs->Read(it->second.node, buf, count, offset);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::usr_write(int fd, const void *buf, size_t count)
|
||||
@@ -227,7 +223,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Write(buf, count, it->second.Offset);
|
||||
return fs->Write(it->second.node, buf, count, it->second.Offset);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::usr_pwrite(int fd, const void *buf, size_t count, off_t offset)
|
||||
@@ -236,7 +232,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Write(buf, count, offset);
|
||||
return fs->Write(it->second.node, buf, count, offset);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_close(int fd)
|
||||
@@ -260,21 +256,19 @@ namespace vfs
|
||||
{
|
||||
case SEEK_SET:
|
||||
{
|
||||
newOffset = it->second.Node->Seek(offset);
|
||||
newOffset = fs->Seek(it->second.node, offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_CUR:
|
||||
{
|
||||
newOffset = it->second.Node->Seek(newOffset + offset);
|
||||
newOffset = fs->Seek(it->second.node, newOffset + offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_END:
|
||||
{
|
||||
struct kstat stat
|
||||
{
|
||||
};
|
||||
it->second.Node->Stat(&stat);
|
||||
newOffset = it->second.Node->Seek(stat.Size + offset);
|
||||
struct kstat stat{};
|
||||
fs->Stat(it->second.node, &stat);
|
||||
newOffset = fs->Seek(it->second.node, stat.Size + offset);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -284,48 +278,48 @@ namespace vfs
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_stat(const char *pathname,
|
||||
struct kstat *statbuf)
|
||||
int FileDescriptorTable::usr_stat(const char *pathname, kstat *statbuf)
|
||||
{
|
||||
FileNode *node = fs->GetByPath(pathname, nullptr);
|
||||
if (node == nullptr)
|
||||
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
|
||||
Node root = thisProcess->Info.RootNode;
|
||||
eNode ret = fs->Lookup(root, pathname);
|
||||
if (ret == false)
|
||||
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
|
||||
Node node = ret;
|
||||
|
||||
if (node->IsSymbolicLink())
|
||||
{
|
||||
std::unique_ptr<char[]> buffer(new char[1024]);
|
||||
ssize_t ret = node->ReadLink(buffer.get(), 1024);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ssize_t len = fs->ReadLink(node, buffer.get(), 1024);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
FileNode *target = fs->GetByPath(buffer.get(), nullptr);
|
||||
if (target == nullptr)
|
||||
return -ENOENT;
|
||||
|
||||
return target->Stat(statbuf);
|
||||
ret = fs->Lookup(root, buffer.get());
|
||||
if (ret == false)
|
||||
return -ret.Error;
|
||||
return fs->Stat(ret.Value, statbuf);
|
||||
}
|
||||
|
||||
return node->Stat(statbuf);
|
||||
return fs->Stat(node, statbuf);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_fstat(int fd, struct kstat *statbuf)
|
||||
int FileDescriptorTable::usr_fstat(int fd, kstat *statbuf)
|
||||
{
|
||||
auto it = this->FileMap.find(fd);
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||
|
||||
return fildes.Node->Stat(statbuf);
|
||||
return fs->Stat(fildes.node, statbuf);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_lstat(const char *pathname,
|
||||
struct kstat *statbuf)
|
||||
int FileDescriptorTable::usr_lstat(const char *pathname, kstat *statbuf)
|
||||
{
|
||||
FileNode *node = fs->GetByPath(pathname, nullptr);
|
||||
if (node == nullptr)
|
||||
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
|
||||
return node->Stat(statbuf);
|
||||
Node root = thisProcess->Info.RootNode;
|
||||
eNode ret = fs->Lookup(root, pathname);
|
||||
if (ret == false)
|
||||
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
|
||||
|
||||
return fs->Stat(ret.Value, statbuf);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_dup(int oldfd)
|
||||
@@ -339,7 +333,7 @@ namespace vfs
|
||||
return -EMFILE;
|
||||
|
||||
Fildes new_dfd{};
|
||||
new_dfd.Node = it->second.Node;
|
||||
new_dfd.node = it->second.node;
|
||||
new_dfd.Mode = it->second.Mode;
|
||||
|
||||
this->FileMap.insert({newfd, new_dfd});
|
||||
@@ -364,7 +358,7 @@ namespace vfs
|
||||
this->usr_close(newfd);
|
||||
|
||||
Fildes new_dfd{};
|
||||
new_dfd.Node = it->second.Node;
|
||||
new_dfd.node = it->second.node;
|
||||
new_dfd.Mode = it->second.Mode;
|
||||
|
||||
this->FileMap.insert({newfd, new_dfd});
|
||||
@@ -378,7 +372,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Ioctl(request, argp);
|
||||
return fs->Ioctl(it->second.node, request, argp);
|
||||
}
|
||||
|
||||
FileDescriptorTable::FileDescriptorTable(void *_Owner)
|
||||
@@ -386,11 +380,12 @@ namespace vfs
|
||||
{
|
||||
debug("+ %#lx", this);
|
||||
|
||||
mode_t Mode = S_IXOTH | S_IROTH |
|
||||
S_IXGRP | S_IRGRP |
|
||||
S_IXUSR | S_IRUSR |
|
||||
/* d r-x r-x r-x */
|
||||
mode_t Mode = S_IROTH | S_IXOTH |
|
||||
S_IRGRP | S_IXGRP |
|
||||
S_IRUSR | S_IXUSR |
|
||||
S_IFDIR;
|
||||
|
||||
this->fdDir = fs->Create(((Tasking::PCB *)_Owner)->ProcDirectory, "fd", Mode);
|
||||
Tasking::PCB *pcb = (Tasking::PCB *)_Owner;
|
||||
this->fdDir = fs->Create(pcb->ProcDirectory, "fd", Mode);
|
||||
}
|
||||
}
|
412
Kernel/fs/ramfs.cpp
Normal file
412
Kernel/fs/ramfs.cpp
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fs/ramfs.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <functional>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
int RAMFS::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
auto Parent = (RAMFSInode *)_Parent;
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
if (basename == NULL)
|
||||
{
|
||||
if (strcmp(Name, RootName.c_str()) == 0)
|
||||
{
|
||||
auto &it = Files.at(0);
|
||||
*Result = &it->Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
error("Invalid name %s", Name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (Parent)
|
||||
{
|
||||
for (auto &&child : Parent->Children)
|
||||
{
|
||||
if (strcmp(child->Name.c_str(), basename) != 0)
|
||||
continue;
|
||||
|
||||
*Result = &child->Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
for (auto &&i : Files)
|
||||
{
|
||||
RAMFSInode *node = i.second;
|
||||
if (strcmp(node->Name.c_str(), basename) != 0)
|
||||
continue;
|
||||
*Result = &i.second->Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int RAMFS::Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
RAMFSInode *Parent = (RAMFSInode *)_Parent;
|
||||
|
||||
Inode inode{};
|
||||
inode.Mode = Mode;
|
||||
inode.Device = this->DeviceID;
|
||||
inode.RawDevice = 0;
|
||||
inode.Index = NextInode;
|
||||
inode.Offset = 0;
|
||||
inode.PrivateData = this;
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
|
||||
RAMFSInode *node = new RAMFSInode;
|
||||
node->Name.assign(basename, length);
|
||||
node->Mode = Mode;
|
||||
node->Node = inode;
|
||||
|
||||
auto file = Files.insert(std::make_pair(NextInode, node));
|
||||
assert(file.second == true);
|
||||
*Result = &Files.at(NextInode)->Node;
|
||||
if (Parent)
|
||||
Parent->AddChild(node);
|
||||
NextInode++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t RAMFS::Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
auto fileItr = Files.find(Node->Index);
|
||||
assert(fileItr != Files.end());
|
||||
|
||||
RAMFSInode *node = fileItr->second;
|
||||
size_t fileSize = node->Stat.Size;
|
||||
|
||||
if (Size <= 0)
|
||||
{
|
||||
debug("Size is less than or equal to 0");
|
||||
Size = fileSize;
|
||||
}
|
||||
|
||||
if ((size_t)Offset > fileSize)
|
||||
{
|
||||
debug("Offset %d is greater than file size %d", Offset, fileSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((fileSize - Offset) == 0)
|
||||
{
|
||||
debug("Offset %d is equal to file size %d", Offset, fileSize);
|
||||
return 0; /* EOF */
|
||||
}
|
||||
|
||||
if ((size_t)Offset + Size > fileSize)
|
||||
{
|
||||
debug("Offset %d + Size %d is greater than file size %d",
|
||||
Offset, Size, fileSize);
|
||||
Size = fileSize;
|
||||
}
|
||||
|
||||
memcpy(Buffer, node->Buffer.Data, Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
ssize_t RAMFS::Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
auto fileItr = Files.find(Node->Index);
|
||||
assert(fileItr != Files.end());
|
||||
|
||||
RAMFSInode *node = fileItr->second;
|
||||
|
||||
if (node->Buffer.IsAllocated() == false)
|
||||
node->Buffer.Allocate(node->Stat.Size);
|
||||
|
||||
size_t fileSize = node->Stat.Size;
|
||||
|
||||
if (Size <= 0)
|
||||
{
|
||||
debug("Size is less than or equal to 0");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((size_t)Offset > fileSize)
|
||||
{
|
||||
debug("Offset %d is greater than file size %d", Offset, fileSize);
|
||||
node->Buffer.Allocate(Offset + Size, true, true);
|
||||
}
|
||||
|
||||
if ((fileSize - Offset) == 0)
|
||||
{
|
||||
debug("Offset %d is equal to file size %d", Offset, fileSize);
|
||||
node->Buffer.Allocate(Size, true, true);
|
||||
}
|
||||
|
||||
if ((size_t)Offset + Size > fileSize)
|
||||
{
|
||||
debug("Offset %d + Size %d is greater than file size %d",
|
||||
Offset, Size, fileSize);
|
||||
node->Buffer.Allocate(Offset + Size, true, true);
|
||||
}
|
||||
|
||||
memcpy(static_cast<char *>(node->Buffer.Data) + Offset, Buffer, Size);
|
||||
node->Stat.Size = Size;
|
||||
return Size;
|
||||
}
|
||||
|
||||
__no_sanitize("alignment")
|
||||
ssize_t RAMFS::ReadDir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
/* FIXME: FIX ALIGNMENT FOR DIRENT! */
|
||||
auto Node = (RAMFSInode *)_Node;
|
||||
|
||||
off_t realOffset = Offset;
|
||||
|
||||
size_t totalSize = 0;
|
||||
uint16_t reclen = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
|
||||
if (Offset == 0)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
|
||||
if (totalSize + reclen >= Size)
|
||||
return -EINVAL;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = Node->Node.Index;
|
||||
ent->d_off = Offset++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
}
|
||||
|
||||
if (Offset <= 1)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
|
||||
if (totalSize + reclen >= Size)
|
||||
{
|
||||
if (realOffset == 1)
|
||||
return -EINVAL;
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
|
||||
if (Node->Parent)
|
||||
ent->d_ino = Node->Parent->Node.Index;
|
||||
else
|
||||
{
|
||||
warn("Parent is null for %s", Node->Name.c_str());
|
||||
ent->d_ino = Node->Node.Index;
|
||||
}
|
||||
ent->d_off = Offset++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(Node->Node.Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size())
|
||||
return -EINVAL;
|
||||
|
||||
off_t entries = 0;
|
||||
for (const auto &var : Node->Children)
|
||||
{
|
||||
if (var->Node.Offset < Offset)
|
||||
continue;
|
||||
|
||||
if (entries >= Entries)
|
||||
break;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
|
||||
if (totalSize + reclen >= Size)
|
||||
break;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->Node.Index;
|
||||
ent->d_off = var->Node.Offset;
|
||||
ent->d_reclen = reclen;
|
||||
|
||||
if (S_ISREG(var->Stat.Mode))
|
||||
ent->d_type = DT_REG;
|
||||
else if (S_ISDIR(var->Stat.Mode))
|
||||
ent->d_type = DT_DIR;
|
||||
else if (S_ISLNK(var->Stat.Mode))
|
||||
ent->d_type = DT_LNK;
|
||||
else if (S_ISCHR(var->Stat.Mode))
|
||||
ent->d_type = DT_CHR;
|
||||
else if (S_ISBLK(var->Stat.Mode))
|
||||
ent->d_type = DT_BLK;
|
||||
else if (S_ISFIFO(var->Stat.Mode))
|
||||
ent->d_type = DT_FIFO;
|
||||
else if (S_ISSOCK(var->Stat.Mode))
|
||||
ent->d_type = DT_SOCK;
|
||||
else
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
|
||||
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
||||
totalSize += reclen;
|
||||
entries++;
|
||||
}
|
||||
|
||||
if (totalSize + sizeof(struct kdirent) >= Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int RAMFS::SymLink(struct Inode *Node, const char *Name, const char *Target, struct Inode **Result)
|
||||
{
|
||||
int ret = this->Create(Node, Name, S_IFLNK, Result);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
RAMFSInode *node = (RAMFSInode *)*Result;
|
||||
node->SymLink.assign(Target, strlen(Target));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t RAMFS::ReadLink(struct Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
auto fileItr = Files.find(Node->Index);
|
||||
assert(fileItr != Files.end());
|
||||
|
||||
RAMFSInode *node = fileItr->second;
|
||||
|
||||
if (node->SymLink.size() > Size)
|
||||
Size = node->SymLink.size();
|
||||
|
||||
strncpy(Buffer, node->SymLink.data(), Size);
|
||||
debug("Read link %d bytes from %d: \"%s\"", Size, Node->Index, Buffer);
|
||||
return Size;
|
||||
}
|
||||
|
||||
int RAMFS::Stat(struct Inode *Node, struct kstat *Stat)
|
||||
{
|
||||
auto fileItr = Files.find(Node->Index);
|
||||
assert(fileItr != Files.end());
|
||||
|
||||
RAMFSInode *node = fileItr->second;
|
||||
*Stat = node->Stat;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int __ramfs_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
return ((vfs::RAMFS *)Parent->PrivateData)->Lookup(Parent, Name, Result);
|
||||
}
|
||||
|
||||
int __ramfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
return ((vfs::RAMFS *)Parent->PrivateData)->Create(Parent, Name, Mode, Result);
|
||||
}
|
||||
|
||||
ssize_t __ramfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->Read(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
ssize_t __ramfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->Write(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
ssize_t __ramfs_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->ReadDir(Node, Buffer, Size, Offset, Entries);
|
||||
}
|
||||
|
||||
int __ramfs_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
|
||||
{
|
||||
return ((vfs::RAMFS *)Parent->PrivateData)->SymLink(Parent, Name, Target, Result);
|
||||
}
|
||||
|
||||
ssize_t __ramfs_ReadLink(Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->ReadLink(Node, Buffer, Size);
|
||||
}
|
||||
|
||||
int __ramfs_Stat(struct Inode *Node, kstat *Stat)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->Stat(Node, Stat);
|
||||
}
|
||||
|
||||
int __ramfs_DestroyInode(FileSystemInfo *Info, Inode *Node)
|
||||
{
|
||||
vfs::RAMFS::RAMFSInode *inode = (vfs::RAMFS::RAMFSInode *)Node;
|
||||
delete inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ramfs_Destroy(FileSystemInfo *fsi)
|
||||
{
|
||||
assert(fsi->PrivateData);
|
||||
delete (vfs::RAMFS *)fsi->PrivateData;
|
||||
delete fsi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MountAndRootRAMFS(Node Parent, const char *Name, size_t Index)
|
||||
{
|
||||
vfs::RAMFS *ramfs = new vfs::RAMFS;
|
||||
ramfs->RootName.assign(Name);
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "ramfs";
|
||||
fsi->SuperOps.DeleteInode = __ramfs_DestroyInode;
|
||||
fsi->SuperOps.Destroy = __ramfs_Destroy;
|
||||
fsi->Ops.Lookup = __ramfs_Lookup;
|
||||
fsi->Ops.Create = __ramfs_Create;
|
||||
fsi->Ops.Read = __ramfs_Read;
|
||||
fsi->Ops.Write = __ramfs_Write;
|
||||
fsi->Ops.ReadDir = __ramfs_Readdir;
|
||||
fsi->Ops.SymLink = __ramfs_SymLink;
|
||||
fsi->Ops.ReadLink = __ramfs_ReadLink;
|
||||
fsi->Ops.Stat = __ramfs_Stat;
|
||||
fsi->PrivateData = ramfs;
|
||||
ramfs->DeviceID = fs->RegisterFileSystem(fsi);
|
||||
|
||||
Inode *root = nullptr;
|
||||
ramfs->Create(nullptr, Name, S_IFDIR | 0755, &root);
|
||||
|
||||
fs->Mount(Parent, root, Name, fsi);
|
||||
fs->AddRoot(Index, fs->Convert(root));
|
||||
return true;
|
||||
}
|
@@ -15,13 +15,12 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/ustar.hpp>
|
||||
|
||||
#include <fs/ustar.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <functional>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../kernel.h"
|
||||
|
||||
#define TMAGIC "ustar"
|
||||
#define TMAGLEN 6
|
||||
@@ -33,7 +32,7 @@ namespace vfs
|
||||
int USTAR::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
auto Parent = (USTARInode *)_Parent;
|
||||
|
||||
debug("looking up for %s", Name);
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
@@ -92,7 +91,6 @@ namespace vfs
|
||||
inode.Index = NextInode;
|
||||
inode.Offset = 0;
|
||||
inode.PrivateData = this;
|
||||
inode.Flags = I_FLAG_CACHE_KEEP;
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
@@ -160,10 +158,14 @@ namespace vfs
|
||||
node->Name.assign(basename, length);
|
||||
node->Path.assign(Name, strlen(Name));
|
||||
|
||||
Files.insert(std::make_pair(NextInode, node));
|
||||
auto file = Files.insert(std::make_pair(NextInode, node));
|
||||
assert(file.second == true);
|
||||
*Result = &Files.at(NextInode)->Node;
|
||||
if (Parent)
|
||||
{
|
||||
Parent->Children.push_back(Files.at(NextInode));
|
||||
Files.at(NextInode)->Parent = Parent;
|
||||
}
|
||||
NextInode++;
|
||||
return 0;
|
||||
}
|
||||
@@ -214,6 +216,7 @@ namespace vfs
|
||||
{
|
||||
/* FIXME: FIX ALIGNMENT FOR DIRENT! */
|
||||
auto Node = (USTARInode *)_Node;
|
||||
debug("reading directory %s", Node->Path.c_str());
|
||||
|
||||
off_t realOffset = Offset;
|
||||
|
||||
@@ -234,6 +237,7 @@ namespace vfs
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
debug(".");
|
||||
}
|
||||
|
||||
if (Offset <= 1)
|
||||
@@ -260,6 +264,7 @@ namespace vfs
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
debug("..");
|
||||
}
|
||||
|
||||
// off_t entriesSkipped = 0;
|
||||
@@ -306,10 +311,13 @@ namespace vfs
|
||||
if (var->Deleted)
|
||||
continue;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + var->Name.size() + 1);
|
||||
|
||||
if (totalSize + reclen >= Size)
|
||||
if (totalSize + reclen > Size)
|
||||
{
|
||||
debug("not enough space for %s (%zu + %zu = %zu > %zu)", var->Name.c_str(), totalSize, reclen, totalSize + reclen, Size);
|
||||
break;
|
||||
}
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->Node.Index;
|
||||
@@ -346,7 +354,7 @@ namespace vfs
|
||||
break;
|
||||
}
|
||||
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
||||
|
||||
debug("%s", var->Name.c_str());
|
||||
totalSize += reclen;
|
||||
entries++;
|
||||
}
|
||||
@@ -389,7 +397,7 @@ namespace vfs
|
||||
Size = strlen(node->Header->link);
|
||||
|
||||
strncpy(Buffer, node->Header->link, Size);
|
||||
debug("Read %d bytes from %d", Size, Node->Index);
|
||||
debug("Read %d bytes from %d: \"%s\"", Size, Node->Index, Buffer);
|
||||
return Size;
|
||||
}
|
||||
|
||||
@@ -491,6 +499,10 @@ namespace vfs
|
||||
FileHeader *header = (FileHeader *)Address;
|
||||
if (strncmp(header->signature, TMAGIC, TMAGLEN) != 0)
|
||||
{
|
||||
/* For some reason if GRUB inflates the archive, the magic is "ustar " */
|
||||
if (strncmp(header->signature, TMAGIC, TMAGLEN - 1) == 0)
|
||||
return true;
|
||||
|
||||
error("Invalid signature!");
|
||||
return false;
|
||||
}
|
||||
@@ -564,7 +576,7 @@ namespace vfs
|
||||
|
||||
FileHeader *header = (FileHeader *)Address;
|
||||
|
||||
debug("USTAR signature valid! Name:%s Signature:%s Mode:%d Size:%lu",
|
||||
debug("USTAR signature valid! Name:\"%s\" Signature:\"%s\" Mode:%d Size:%lu",
|
||||
header->name, header->signature, StringToInt(header->mode), header->size);
|
||||
|
||||
Memory::Virtual vmm;
|
||||
@@ -577,7 +589,7 @@ namespace vfs
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(header->signature, TMAGIC, TMAGLEN) != 0)
|
||||
if (strncmp(header->signature, TMAGIC, TMAGLEN - 1) != 0)
|
||||
break;
|
||||
// debug("\"%s\"", header->name);
|
||||
|
||||
@@ -594,7 +606,6 @@ namespace vfs
|
||||
uNode.RawDevice = 0;
|
||||
uNode.Index = NextInode;
|
||||
SetMode(uNode, header);
|
||||
uNode.Flags = I_FLAG_CACHE_KEEP;
|
||||
uNode.Offset = 0;
|
||||
uNode.PrivateData = this;
|
||||
|
||||
@@ -817,13 +828,13 @@ O2 int __ustar_Stat(struct Inode *Node, kstat *Stat)
|
||||
return ((vfs::USTAR *)Node->PrivateData)->Stat(Node, Stat);
|
||||
}
|
||||
|
||||
int __ustar_DestroyInode(FileSystemInfo *Info, Inode *Node)
|
||||
O2 int __ustar_DestroyInode(FileSystemInfo *Info, Inode *Node)
|
||||
{
|
||||
((vfs::USTAR::USTARInode *)Node)->Deleted = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ustar_Destroy(FileSystemInfo *fsi)
|
||||
O2 int __ustar_Destroy(FileSystemInfo *fsi)
|
||||
{
|
||||
assert(fsi->PrivateData);
|
||||
delete (vfs::USTAR *)fsi->PrivateData;
|
||||
@@ -831,7 +842,7 @@ int __ustar_Destroy(FileSystemInfo *fsi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size)
|
||||
bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index)
|
||||
{
|
||||
vfs::USTAR *ustar = new vfs::USTAR();
|
||||
if (!ustar->TestArchive(Address))
|
||||
@@ -840,17 +851,8 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size)
|
||||
return false;
|
||||
}
|
||||
|
||||
ustar->DeviceID = fs->EarlyReserveDevice();
|
||||
ustar->ReadArchive(Address, Size);
|
||||
|
||||
Inode *initrd = nullptr;
|
||||
ustar->Lookup(nullptr, "/", &initrd);
|
||||
assert(initrd != nullptr);
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "ustar";
|
||||
fsi->RootName = "/";
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps.DeleteInode = __ustar_DestroyInode;
|
||||
fsi->SuperOps.Destroy = __ustar_Destroy;
|
||||
fsi->Ops.Lookup = __ustar_Lookup;
|
||||
@@ -861,8 +863,23 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size)
|
||||
fsi->Ops.ReadLink = __ustar_ReadLink;
|
||||
fsi->Ops.Stat = __ustar_Stat;
|
||||
fsi->PrivateData = ustar;
|
||||
fs->LateRegisterFileSystem(ustar->DeviceID, fsi, initrd);
|
||||
|
||||
fs->AddRoot(initrd);
|
||||
ustar->DeviceID = fs->RegisterFileSystem(fsi);
|
||||
ustar->ReadArchive(Address, Size);
|
||||
|
||||
Inode *rootfs = nullptr;
|
||||
ustar->Lookup(nullptr, "/", &rootfs);
|
||||
assert(rootfs != nullptr);
|
||||
|
||||
eNode _node = fs->Convert(rootfs);
|
||||
assert(_node.Error == 0);
|
||||
|
||||
Node node = _node;
|
||||
node->fsi = fsi;
|
||||
node->Flags.MountPoint = true;
|
||||
node->Name = "/";
|
||||
node->Path = "/";
|
||||
|
||||
fs->AddRoot(Index, node);
|
||||
return true;
|
||||
}
|
627
Kernel/fs/vfs.cpp
Normal file
627
Kernel/fs/vfs.cpp
Normal file
@@ -0,0 +1,627 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel 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 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
eNode Virtual::Convert(Inode *inode)
|
||||
{
|
||||
Node cache = std::make_shared<NodeCache>();
|
||||
cache->inode = inode;
|
||||
return {cache, 0};
|
||||
}
|
||||
|
||||
eNode Virtual::Convert(Node &Parent, Inode *inode)
|
||||
{
|
||||
Node cache = std::make_shared<NodeCache>();
|
||||
cache->inode = inode;
|
||||
cache->fsi = Parent->fsi;
|
||||
cache->Parent = Parent;
|
||||
Parent->Children.push_back(cache);
|
||||
return {cache, 0};
|
||||
}
|
||||
|
||||
std::string Virtual::NormalizePath(Node &Parent, std::string Path, bool Join)
|
||||
{
|
||||
std::string result;
|
||||
if (Join)
|
||||
{
|
||||
size_t len = Path.size() + Parent->Path.size() + 2;
|
||||
result.reserve(len);
|
||||
len = cwk_path_join(Parent->Path.c_str(), Path.c_str(), result.data(), result.capacity());
|
||||
result.resize(len);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t len = Path.size() + 2;
|
||||
result.reserve(len);
|
||||
len = cwk_path_normalize(Path.c_str(), result.data(), result.capacity());
|
||||
result.resize(len);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Virtual::RootExists(dev_t Index)
|
||||
{
|
||||
if (Roots.find(Index) == Roots.end())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
eNode Virtual::GetRoot(dev_t Index)
|
||||
{
|
||||
auto it = Roots.find(Index);
|
||||
if (it == Roots.end())
|
||||
return {nullptr, ENOENT};
|
||||
return {it->second, 0};
|
||||
}
|
||||
|
||||
ssize_t Virtual::GetRoot(Node Index)
|
||||
{
|
||||
for (auto it = Roots.begin(); it != Roots.end(); ++it)
|
||||
{
|
||||
if (it->second == Index)
|
||||
return it->first;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int Virtual::AddRoot(dev_t Index, Node Root, bool Replace)
|
||||
{
|
||||
assert(Root != nullptr);
|
||||
|
||||
auto it = Roots.find(Index);
|
||||
if (it == Roots.end())
|
||||
{
|
||||
Roots[Index] = Root;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Replace)
|
||||
{
|
||||
Roots[Index] = Root;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Root %ld already exists", Index);
|
||||
return EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi)
|
||||
{
|
||||
assert(fsi != nullptr);
|
||||
FileSystems.insert({FileSystems.size(), fsi});
|
||||
return FileSystems.size() - 1;
|
||||
}
|
||||
|
||||
int Virtual::UnregisterFileSystem(dev_t Device)
|
||||
{
|
||||
auto it = FileSystems.find(Device);
|
||||
if (it == FileSystems.end())
|
||||
return -ENOENT;
|
||||
|
||||
FileSystemInfo *fsi = it->second;
|
||||
|
||||
/* TODO: unmount */
|
||||
fixme("Unmounting %d", Device);
|
||||
|
||||
if (fsi->SuperOps.Synchronize)
|
||||
fsi->SuperOps.Synchronize(fsi, nullptr);
|
||||
if (fsi->SuperOps.Destroy)
|
||||
fsi->SuperOps.Destroy(fsi);
|
||||
|
||||
FileSystems.erase(it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
eNode Virtual::Lookup(Node &Parent, std::string Path)
|
||||
{
|
||||
assert(Parent != nullptr);
|
||||
|
||||
debug("looking up \"%s\" in \"%s\"", Path.c_str(), Parent->Path.c_str());
|
||||
|
||||
if (Path == ".")
|
||||
return {Parent, 0};
|
||||
else if (Path == "..")
|
||||
return {Parent->Parent ? Parent->Parent : Parent, 0};
|
||||
|
||||
Node base = Parent;
|
||||
bool absolute = PathIsAbsolute(Path);
|
||||
if (absolute == true)
|
||||
{
|
||||
while (base->Parent)
|
||||
base = base->Parent;
|
||||
}
|
||||
|
||||
debug("base is \"%s\" and path is \"%s\" %d", base->Path.c_str(), Path.c_str(), absolute);
|
||||
Path = this->NormalizePath(base, Path, !absolute);
|
||||
debug("after normalizing, path is \"%s\" %d", Path.c_str(), absolute);
|
||||
|
||||
struct cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(Path.c_str(), &segment))
|
||||
{
|
||||
debug("%s no segments; %d", Path.c_str(), absolute);
|
||||
if (Path == "/")
|
||||
return {base, 0};
|
||||
|
||||
assert(!"Path doesn't have any segments.");
|
||||
}
|
||||
|
||||
Node node = base;
|
||||
/* We need to go to the root after NormalizePath even if Path is relative */
|
||||
if (absolute == false)
|
||||
{
|
||||
while (node->Parent)
|
||||
{
|
||||
debug("current parent \"%s\"", node->Parent->Path.c_str());
|
||||
node = node->Parent;
|
||||
debug("new parent \"%s\"", node->Parent ? node->Parent->Path.c_str() : "<null>");
|
||||
}
|
||||
}
|
||||
|
||||
std::string currentPath = node->Path;
|
||||
if (currentPath.empty())
|
||||
currentPath = "/";
|
||||
|
||||
do
|
||||
{
|
||||
std::string segmentStr(segment.begin, segment.size);
|
||||
debug("Current segment is \"%s\"", segmentStr.c_str());
|
||||
|
||||
eNode ret = node->CachedSearch(segmentStr);
|
||||
if (ret == false)
|
||||
{
|
||||
debug("cache miss for \"%s\"", segmentStr.c_str());
|
||||
|
||||
if (node->fsi->Ops.Lookup == nullptr)
|
||||
return {nullptr, ENOTSUP};
|
||||
|
||||
Inode *inode;
|
||||
int ret = node->fsi->Ops.Lookup(node->inode, segmentStr.c_str(), &inode);
|
||||
if (ret != 0)
|
||||
return {nullptr, ret};
|
||||
|
||||
if (currentPath == "/")
|
||||
currentPath += segmentStr;
|
||||
else
|
||||
currentPath += "/" + segmentStr;
|
||||
|
||||
node = Convert(node, inode);
|
||||
node->Name = segmentStr;
|
||||
node->Path = currentPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("cache hit for \"%s\"", segmentStr.c_str());
|
||||
node = ret;
|
||||
if (currentPath == "/")
|
||||
currentPath += segmentStr;
|
||||
else
|
||||
currentPath += "/" + segmentStr;
|
||||
}
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
return {node, 0};
|
||||
}
|
||||
|
||||
eNode Virtual::Create(Node &Parent, std::string Name, mode_t Mode, bool ErrorIfExists)
|
||||
{
|
||||
eNode exists = this->Lookup(Parent, Name);
|
||||
if (exists)
|
||||
{
|
||||
if (ErrorIfExists)
|
||||
return {nullptr, EEXIST};
|
||||
|
||||
/* I should handle this in a better way */
|
||||
assert((exists.Value->inode->Mode & S_IFMT) == (Mode & S_IFMT));
|
||||
debug("File \"%s\" already exists in cache", Name.c_str());
|
||||
return exists;
|
||||
}
|
||||
|
||||
if (!Parent)
|
||||
return {nullptr, EINVAL};
|
||||
if (Parent->fsi->Ops.Create == nullptr)
|
||||
return {nullptr, ENOTSUP};
|
||||
|
||||
Inode *inode;
|
||||
int ret = Parent->fsi->Ops.Create(Parent->inode, Name.c_str(), Mode, &inode);
|
||||
if (ret != 0)
|
||||
return {nullptr, ret};
|
||||
|
||||
Node node = Convert(Parent, inode);
|
||||
node->Name = Name;
|
||||
std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name;
|
||||
node->Path = fs->NormalizePath(Parent, unormalized);
|
||||
return {node, 0};
|
||||
}
|
||||
|
||||
int Virtual::Remove(Node &Parent, std::string Name)
|
||||
{
|
||||
if (!Parent)
|
||||
return -EINVAL;
|
||||
if (Parent->fsi->Ops.Remove == nullptr)
|
||||
return -ENOTSUP;
|
||||
int ret = Parent->fsi->Ops.Remove(Parent->inode, Name.c_str());
|
||||
if (ret == 0)
|
||||
{
|
||||
for (auto it = Parent->Children.begin(); it != Parent->Children.end(); ++it)
|
||||
{
|
||||
if (it->get()->Name != Name)
|
||||
continue;
|
||||
Parent->Children.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Virtual::Remove(Node &node)
|
||||
{
|
||||
if (!node->Parent)
|
||||
return -EINVAL;
|
||||
if (node->Parent->fsi->Ops.Remove == nullptr)
|
||||
return -ENOTSUP;
|
||||
int ret = node->Parent->fsi->Ops.Remove(node->inode, node->Name.c_str());
|
||||
if (ret == 0)
|
||||
{
|
||||
Node &p = node->Parent;
|
||||
for (auto it = p->Children.begin(); it != p->Children.end(); ++it)
|
||||
{
|
||||
if (it->get() != node.get())
|
||||
continue;
|
||||
p->Children.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Virtual::Rename(Node &node, std::string NewName)
|
||||
{
|
||||
if (node->fsi->Ops.Rename == nullptr)
|
||||
return -ENOTSUP;
|
||||
int ret = node->fsi->Ops.Rename(node->inode, node->Name.c_str(), NewName.c_str());
|
||||
if (ret == 0)
|
||||
node->Name = NewName;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t Virtual::Read(Node &Target, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
if (Target->IsDirectory() || Target->IsMountPoint())
|
||||
return -EISDIR;
|
||||
|
||||
if (Target->IsSymbolicLink())
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: cache buffer */
|
||||
|
||||
return Target->__Read(Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
ssize_t Virtual::Write(Node &Target, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
if (Target->IsDirectory() || Target->IsMountPoint())
|
||||
return -EISDIR;
|
||||
|
||||
if (Target->IsSymbolicLink())
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: cache buffer */
|
||||
|
||||
return Target->__Write(Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
int Virtual::Truncate(Node &Target, off_t Size)
|
||||
{
|
||||
if (Target->IsDirectory() || Target->IsMountPoint())
|
||||
return -EISDIR;
|
||||
|
||||
if (!Target->IsRegularFile())
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: cache buffer */
|
||||
|
||||
return Target->__Truncate(Size);
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") ssize_t Virtual::ReadDirectory(Node &Target, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
if (!Target->IsDirectory() && !Target->IsMountPoint())
|
||||
return -ENOTDIR;
|
||||
|
||||
ssize_t total = 0;
|
||||
off_t entryIndex = 0;
|
||||
std::list<std::string> seen;
|
||||
|
||||
uint8_t *bufPtr = reinterpret_cast<uint8_t *>(Buffer);
|
||||
|
||||
if (Target->fsi && Target->fsi->Ops.ReadDir)
|
||||
{
|
||||
const size_t tempBufSize = 4096;
|
||||
std::unique_ptr<uint8_t[]> tempBuf(new uint8_t[tempBufSize]);
|
||||
|
||||
off_t fsOffset = Offset;
|
||||
ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)tempBuf.get(), tempBufSize, fsOffset, Entries);
|
||||
if (read > 0)
|
||||
{
|
||||
ssize_t pos = 0;
|
||||
while (pos < read)
|
||||
{
|
||||
kdirent *ent = (kdirent *)(tempBuf.get() + pos);
|
||||
if (ent->d_reclen == 0)
|
||||
break;
|
||||
|
||||
size_t reclen = ent->d_reclen;
|
||||
if (total + reclen > Size)
|
||||
break;
|
||||
|
||||
memcpy(bufPtr, ent, reclen);
|
||||
seen.push_back(ent->d_name);
|
||||
bufPtr += reclen;
|
||||
total += reclen;
|
||||
pos += reclen;
|
||||
entryIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &child : Target->Children)
|
||||
{
|
||||
if (std::find(seen.begin(), seen.end(), child->Name) != seen.end())
|
||||
continue;
|
||||
|
||||
if (entryIndex < Offset)
|
||||
{
|
||||
entryIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + child->Name.size() + 1);
|
||||
if (total + reclen > (ssize_t)Size)
|
||||
break;
|
||||
|
||||
kdirent *ent = (kdirent *)bufPtr;
|
||||
ent->d_ino = child->inode ? child->inode->Index : 0;
|
||||
ent->d_off = entryIndex++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = child->inode ? IFTODT(child->inode->Mode) : DT_UNKNOWN;
|
||||
strcpy(ent->d_name, child->Name.c_str());
|
||||
|
||||
bufPtr += reclen;
|
||||
total += reclen;
|
||||
seen.push_back(child->Name);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") std::list<Node> Virtual::ReadDirectory(Node &Target)
|
||||
{
|
||||
if (!Target->IsDirectory() && !Target->IsMountPoint())
|
||||
return {};
|
||||
std::list<Node> ret;
|
||||
std::list<std::string> seen;
|
||||
|
||||
if (Target->fsi && Target->fsi->Ops.ReadDir)
|
||||
{
|
||||
const size_t bufSize = 4096;
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
|
||||
off_t offset = 0;
|
||||
while (true)
|
||||
{
|
||||
ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)buf.get(), bufSize, offset, LONG_MAX);
|
||||
if (read <= 0)
|
||||
break;
|
||||
ssize_t pos = 0;
|
||||
while (pos < read)
|
||||
{
|
||||
kdirent *ent = (kdirent *)(buf.get() + pos);
|
||||
if (ent->d_reclen == 0)
|
||||
break;
|
||||
debug("%s", ent->d_name);
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
{
|
||||
pos += ent->d_reclen;
|
||||
continue;
|
||||
}
|
||||
|
||||
seen.push_back(ent->d_name);
|
||||
|
||||
auto it = std::find_if(Target->Children.begin(), Target->Children.end(),
|
||||
[&](const Node &n)
|
||||
{ return n->Name == ent->d_name; });
|
||||
|
||||
if (it != Target->Children.end())
|
||||
ret.push_back(*it);
|
||||
else
|
||||
{
|
||||
eNode result = Lookup(Target, ent->d_name);
|
||||
if (result.Error == 0 && result.Value)
|
||||
{
|
||||
Target->Children.push_back(result.Value);
|
||||
result.Value->Parent = Target;
|
||||
ret.push_back(result.Value);
|
||||
}
|
||||
}
|
||||
pos += ent->d_reclen;
|
||||
}
|
||||
offset += read;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &child : Target->Children)
|
||||
{
|
||||
if (std::find(seen.begin(), seen.end(), child->Name) != seen.end())
|
||||
continue;
|
||||
if (child->Name == "." || child->Name == "..")
|
||||
continue;
|
||||
ret.push_back(child);
|
||||
seen.push_back(child->Name.c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
eNode Virtual::CreateLink(Node &Parent, std::string Name, std::string Target)
|
||||
{
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFLNK;
|
||||
|
||||
eNode enode = this->Create(Parent, Name, mode);
|
||||
if (!enode)
|
||||
return enode;
|
||||
Node node = enode;
|
||||
node->Link = Target;
|
||||
return {node, 0};
|
||||
}
|
||||
|
||||
int Virtual::Stat(Node &Target, struct kstat *Stat)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Stat(Stat);
|
||||
}
|
||||
|
||||
off_t Virtual::Seek(Node &Target, off_t Offset)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Seek(Offset);
|
||||
}
|
||||
|
||||
int Virtual::Open(Node &Target, int Flags, mode_t Mode)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Open(Flags, Mode);
|
||||
}
|
||||
|
||||
int Virtual::Close(Node &Target)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Close();
|
||||
}
|
||||
|
||||
FileSystemInfo *Virtual::Probe(FileSystemDevice *Device)
|
||||
{
|
||||
for (auto &&i : FileSystems)
|
||||
{
|
||||
if (i.second->SuperOps.Probe == nullptr)
|
||||
{
|
||||
debug("%s does not support probing", i.second->Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
int ret = i.second->SuperOps.Probe(Device);
|
||||
if (ret == 0)
|
||||
return i.second;
|
||||
debug("%s returned %d", i.second->Name, ret);
|
||||
}
|
||||
|
||||
debug("No filesystems matched");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
eNode Virtual::Mount(Node &Parent, Inode *inode, std::string Name, FileSystemInfo *fsi)
|
||||
{
|
||||
assert(Parent);
|
||||
assert(inode);
|
||||
|
||||
Node ret = this->Convert(inode);
|
||||
ret->fsi = fsi;
|
||||
ret->Name = Name;
|
||||
|
||||
std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name;
|
||||
ret->Path = fs->NormalizePath(Parent, unormalized);
|
||||
// ret->Link =
|
||||
ret->Parent = Parent;
|
||||
Parent->Children.push_back(ret);
|
||||
return {ret, 0};
|
||||
}
|
||||
|
||||
eNode Virtual::Mount(Node &Parent, std::string Name, FileSystemInfo *fsi, FileSystemDevice *Device)
|
||||
{
|
||||
Inode *inode;
|
||||
int ret = fsi->SuperOps.Mount(fsi, &inode, Device);
|
||||
if (ret != 0)
|
||||
return {nullptr, ret};
|
||||
|
||||
return this->Mount(Parent, inode, Name, fsi);
|
||||
|
||||
// Node node = std::make_shared<NodeCache>();
|
||||
// node->inode = nullptr; /* FIXME: ??? */
|
||||
// node->fsi = fsi;
|
||||
// node->Flags.MountPoint = true;
|
||||
|
||||
// node->Name = Name;
|
||||
// node->Path = fs->NormalizePath(Parent, Parent->Path + "/" + Name);
|
||||
// node->Parent = Parent;
|
||||
// Parent->Children.push_back(node);
|
||||
// return {node, 0};
|
||||
}
|
||||
|
||||
int Virtual::Umount(Node &node)
|
||||
{
|
||||
if (!node->Flags.MountPoint)
|
||||
{
|
||||
debug("node %s is not a mountpoint", node->Path.c_str());
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fixme("untested code");
|
||||
std::shared_ptr<NodeCache> &ptr = node;
|
||||
ptr.reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Virtual::Umount(Node &Parent, std::string Name)
|
||||
{
|
||||
eNode node = Parent->CachedSearch(Name);
|
||||
if (!node)
|
||||
{
|
||||
debug("mountpoint %s not found: %s", Name.c_str(), node.what());
|
||||
return -node.Error;
|
||||
}
|
||||
|
||||
return this->Umount(node.Value);
|
||||
}
|
||||
|
||||
void Virtual::Initialize()
|
||||
{
|
||||
debug("Initializing virtual file system...");
|
||||
Node root = this->GetRoot(0);
|
||||
|
||||
/* d rwx rwx rwx */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFDIR;
|
||||
Node var = this->Create(root, "var", mode, false);
|
||||
Node log = this->Create(var, "log", mode, false);
|
||||
}
|
||||
|
||||
Virtual::Virtual() {}
|
||||
Virtual::~Virtual() {}
|
||||
}
|
51
Kernel/gdb_printers.py
Normal file
51
Kernel/gdb_printers.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import gdb
|
||||
|
||||
class BasicStringPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
try:
|
||||
data = self.val['_data']
|
||||
size = int(self.val['_size'])
|
||||
capacity = int(self.val['_capacity'])
|
||||
if int(data) == 0:
|
||||
return '<null>'
|
||||
content = data.string(length=size)
|
||||
return f"'{content}' (size={size}, cap={capacity})"
|
||||
except gdb.error:
|
||||
return '<invalid string>'
|
||||
|
||||
def children(self):
|
||||
try:
|
||||
data = self.val['_data']
|
||||
size = int(self.val['_size'])
|
||||
if int(data) == 0:
|
||||
return
|
||||
for i in range(size):
|
||||
yield (f'[{i}]', (data + i).dereference())
|
||||
except gdb.error:
|
||||
return
|
||||
|
||||
def display_hint(self):
|
||||
return 'array'
|
||||
|
||||
def lookup_fennix_string(val):
|
||||
try:
|
||||
typename = str(val.type.strip_typedefs())
|
||||
fields = val.type.fields()
|
||||
field_names = [f.name for f in fields]
|
||||
if '_data' in field_names and '_size' in field_names and '_capacity' in field_names:
|
||||
return BasicStringPrinter(val)
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
gdb.pretty_printers.append(lookup_fennix_string)
|
||||
|
||||
def build_pretty_printers():
|
||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennix")
|
||||
pp.add_printer('std::string', '^std::string$', BasicStringPrinter)
|
||||
return pp
|
||||
|
||||
gdb.printing.register_pretty_printer(None, build_pretty_printers(), replace=True)
|
@@ -86,7 +86,7 @@ namespace ACPI
|
||||
SUBTYPE_SERIAL_RISC_V_SBI_Console = 0x0015,
|
||||
|
||||
SUBTYPE_1394_IEEE1394_HCI = 0x0000,
|
||||
|
||||
|
||||
SUBTYPE_USB_XHCI = 0x0000,
|
||||
SUBTYPE_USB_EHCI = 0x0001,
|
||||
|
||||
@@ -193,11 +193,63 @@ namespace ACPI
|
||||
struct BGRTHeader
|
||||
{
|
||||
ACPIHeader Header;
|
||||
|
||||
/**
|
||||
* Version. This value must be 1.
|
||||
*/
|
||||
uint16_t Version;
|
||||
uint8_t Status;
|
||||
|
||||
/**
|
||||
* Status of the image
|
||||
*/
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* Indicates that the image graphic is displayed.
|
||||
*/
|
||||
uint8_t Displayed : 1;
|
||||
|
||||
/**
|
||||
* Orientation
|
||||
*
|
||||
* 0b00 - 0˚
|
||||
* 0b01 - 90˚
|
||||
* 0b10 - 180˚
|
||||
* 0b11 - 270˚
|
||||
*/
|
||||
uint8_t OrientationOffset : 2;
|
||||
|
||||
/**
|
||||
* This field is reserved and must be zero.
|
||||
*/
|
||||
uint8_t Reserved : 5;
|
||||
};
|
||||
uint8_t raw;
|
||||
} Status;
|
||||
|
||||
/**
|
||||
* Image type
|
||||
*
|
||||
* 0 - Bitmap
|
||||
* 1-255 - Reserved
|
||||
*/
|
||||
uint8_t ImageType;
|
||||
|
||||
/**
|
||||
* Physical address of the image pointing to firmware's in-memory copy of the image bitmap.
|
||||
*/
|
||||
uint64_t ImageAddress;
|
||||
|
||||
/**
|
||||
* X-offset of the boot image.
|
||||
*/
|
||||
uint32_t ImageOffsetX;
|
||||
|
||||
/**
|
||||
* Y-offset of the boot image.
|
||||
*/
|
||||
uint32_t ImageOffsetY;
|
||||
} __packed;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user