mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
195 Commits
ceb91f955a
...
code-heap-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1eb8f0f2c7 | ||
|
|
398ca5357c | ||
|
|
4acf12bb69 | ||
|
|
6f25c34d46 | ||
|
|
23e45b5b13 | ||
|
|
701823742e | ||
|
|
ea096a561a | ||
|
|
6d45ffd4d7 | ||
|
|
161d5fe7be | ||
|
|
9bf4ea7341 | ||
|
|
a1bf5651fc | ||
|
|
763228c859 | ||
|
|
770af27d75 | ||
|
|
3e59283c19 | ||
|
|
6146ccba2d | ||
|
|
b0e1527a95 | ||
|
|
cb4410c84e | ||
|
|
98b5976656 | ||
|
|
9335386928 | ||
|
|
7c30d62f33 | ||
|
|
61683bccda | ||
|
|
e1ec5159b8 | ||
|
|
7b7d19592f | ||
|
|
e387c0b6b8 | ||
|
|
d5abc119f3 | ||
|
|
59da6e5620 | ||
|
|
ef1cc0ed4f | ||
|
|
90f0caec1a | ||
|
|
7198a4d110 | ||
|
|
5c0fb63f33 | ||
|
|
6ffcb2cf1a | ||
|
|
1c72107cb1 | ||
|
|
b533bf6596 | ||
|
|
7648993b8f | ||
|
|
17bd271573 | ||
|
|
036a8e7608 | ||
|
|
3b960751f4 | ||
|
|
0ff6334026 | ||
|
|
1ed76411f7 | ||
|
|
10c4d0509d | ||
|
|
57998ea4f8 | ||
|
|
f05aaeb0ac | ||
|
|
78a30984bc | ||
|
|
09dd68a1a2 | ||
|
|
81e4eec055 | ||
|
|
8e5b6a3e3f | ||
|
|
be0ed3a54d | ||
|
|
b895f8c745 | ||
|
|
eee9d7b899 | ||
|
|
9787e6dce6 | ||
|
|
ef9a629ddc | ||
|
|
18d8d311cb | ||
|
|
7b61da94a0 | ||
|
|
d974cf5200 | ||
|
|
f5b6094521 | ||
|
|
a4f675739a | ||
|
|
94447af25a | ||
|
|
a7f487f206 | ||
|
|
b1cca8de88 | ||
|
|
36d6c6d0e9 | ||
|
|
76d3715eef | ||
|
|
babf9d8cce | ||
|
|
ff49104764 | ||
|
|
bda1b8929c | ||
|
|
38bd9a65b6 | ||
|
|
493fcb5d84 | ||
|
|
b651214f1e | ||
|
|
09ff2e01b1 | ||
|
|
03e43da9f9 | ||
|
|
58e171cce7 | ||
|
|
b3e94470e4 | ||
|
|
3fca470487 | ||
|
|
bac8703e04 | ||
|
|
901a1630eb | ||
|
|
e696d65b60 | ||
|
|
ef09418cbf | ||
|
|
7b01e9c862 | ||
|
|
290ee927e8 | ||
|
|
99171b003e | ||
|
|
28f37da07d | ||
|
|
ebf626061f | ||
|
|
4c9352d898 | ||
|
|
5452e0f455 | ||
|
|
86b17ea139 | ||
|
|
a41a007039 | ||
|
|
f15bbaea3f | ||
|
|
b66b7563c2 | ||
|
|
c3d023ad40 | ||
|
|
f3cf5b51de | ||
|
|
202902f30d | ||
|
|
223ce459a1 | ||
|
|
26be4cb84d | ||
|
|
d808cbff94 | ||
|
|
0a10b3e784 | ||
|
|
9617680e45 | ||
|
|
3bb30fd1e8 | ||
|
|
62e2cee989 | ||
|
|
8f18fb4282 | ||
|
|
69ab78108b | ||
|
|
e0f66a8196 | ||
|
|
ba54fd2503 | ||
|
|
41e36b4afa | ||
|
|
a7ada29c5e | ||
|
|
6b9d275c2d | ||
|
|
968620dce8 | ||
|
|
e5dfbd4b23 | ||
|
|
4e6ce8d16e | ||
|
|
519f47286c | ||
|
|
f76ec1ae32 | ||
|
|
1a801e3d35 | ||
|
|
5ad2962389 | ||
|
|
82e6c4b066 | ||
|
|
d564dc208f | ||
|
|
efe92e5004 | ||
|
|
f0580e82a1 | ||
|
|
a56e22b6fc | ||
|
|
67f536d7c6 | ||
|
|
741224411b | ||
|
|
818417d119 | ||
|
|
f272785861 | ||
|
|
5d807ee622 | ||
|
|
90c3cdf0f3 | ||
|
|
2bc233b2f6 | ||
|
|
0df629df47 | ||
|
|
cca85de5ed | ||
|
|
1da81c6f84 | ||
|
|
42d89c1030 | ||
|
|
233943310c | ||
|
|
ef6d69f82b | ||
|
|
94014b5a39 | ||
|
|
680aab362e | ||
|
|
92cc34712c | ||
|
|
bdbbd219d0 | ||
|
|
051b23f577 | ||
|
|
97e884e6a3 | ||
|
|
954c0bcfbb | ||
|
|
637b517f47 | ||
|
|
ab8d8b46e2 | ||
|
|
3cd7427ed8 | ||
|
|
bd1f5345da | ||
|
|
662faa8dd0 | ||
|
|
5802c97938 | ||
|
|
33f9f14391 | ||
|
|
68d09db7c5 | ||
|
|
6bbd12ba7a | ||
|
|
f2bc2d33f0 | ||
|
|
38a121a887 | ||
|
|
8b380f0692 | ||
|
|
f23ee04161 | ||
|
|
2031a8dc81 | ||
|
|
29ee6b15dd | ||
|
|
15b394f0eb | ||
|
|
17f2699277 | ||
|
|
b184f7d996 | ||
|
|
7c07a67bf5 | ||
|
|
ec2da4bebd | ||
|
|
90ad333e90 | ||
|
|
cc3a868863 | ||
|
|
d1545e7fbf | ||
|
|
afe8dc3dcf | ||
|
|
8bb0187f35 | ||
|
|
e0ed423e52 | ||
|
|
abaf5bd862 | ||
|
|
b7005b766f | ||
|
|
91ca04e8c2 | ||
|
|
ada45c6e52 | ||
|
|
207a466707 | ||
|
|
a954c02fbe | ||
|
|
895991fee3 | ||
|
|
25796110f3 | ||
|
|
1d153d694e | ||
|
|
c2e4e8c96f | ||
|
|
599a643d97 | ||
|
|
5efcecc2f2 | ||
|
|
1a39774ead | ||
|
|
1ea8cf6ed1 | ||
|
|
4060ac558c | ||
|
|
28a11e47bc | ||
|
|
6504bed810 | ||
|
|
d8edfccca4 | ||
|
|
ff25a7d86c | ||
|
|
b5202e26a1 | ||
|
|
ea1b031fd3 | ||
|
|
db4e879c34 | ||
|
|
7fd29c9cbe | ||
|
|
218cb9399e | ||
|
|
b96636984c | ||
|
|
b9dd088dc1 | ||
|
|
c6bd48e812 | ||
|
|
9448b0e025 | ||
|
|
ade6c99885 | ||
|
|
59579108a7 | ||
|
|
bd39105793 | ||
|
|
d007aae993 | ||
|
|
c21f051300 |
@@ -56,6 +56,18 @@ install:
|
|||||||
- rustc -vV
|
- rustc -vV
|
||||||
- cargo -vV
|
- cargo -vV
|
||||||
|
|
||||||
|
# Install qemu
|
||||||
|
- echo %cd%
|
||||||
|
- mkdir "C:\Program Files\qemu"
|
||||||
|
- cd "C:\Program Files\qemu"
|
||||||
|
- if %target%==i686-pc-windows-msvc appveyor DownloadFile "https://qemu.weilnetz.de/w32/2018/qemu-w32-setup-20180801.exe" -FileName "qemu-setup.exe"
|
||||||
|
- if %target%==i686-pc-windows-gnu appveyor DownloadFile "https://qemu.weilnetz.de/w32/2018/qemu-w32-setup-20180801.exe" -FileName "qemu-setup.exe"
|
||||||
|
- if %target%==x86_64-pc-windows-msvc appveyor DownloadFile "https://qemu.weilnetz.de/w64/2018/qemu-w64-setup-20180801.exe" -FileName "qemu-setup.exe"
|
||||||
|
- if %target%==x86_64-pc-windows-gnu appveyor DownloadFile "https://qemu.weilnetz.de/w64/2018/qemu-w64-setup-20180801.exe" -FileName "qemu-setup.exe"
|
||||||
|
- 7z x qemu-setup.exe
|
||||||
|
- set PATH=%PATH%;C:\Program Files\qemu
|
||||||
|
- cd "C:\projects\blog-os"
|
||||||
|
|
||||||
## Build Script ##
|
## Build Script ##
|
||||||
|
|
||||||
# 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents
|
# 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents
|
||||||
@@ -76,3 +88,4 @@ test_script:
|
|||||||
- bootimage build
|
- bootimage build
|
||||||
- if %target%==x86_64-pc-windows-gnu cargo test
|
- if %target%==x86_64-pc-windows-gnu cargo test
|
||||||
- if %target%==x86_64-pc-windows-msvc cargo test
|
- if %target%==x86_64-pc-windows-msvc cargo test
|
||||||
|
- bootimage test
|
||||||
|
|||||||
13
.travis.yml
13
.travis.yml
@@ -27,6 +27,18 @@ branches:
|
|||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.cargo
|
- $HOME/.cargo
|
||||||
|
- $HOME/Library/Caches/Homebrew
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- qemu-system-x86
|
||||||
|
homebrew:
|
||||||
|
packages:
|
||||||
|
- qemu
|
||||||
|
|
||||||
|
install:
|
||||||
|
- if [ $TRAVIS_OS_NAME = windows ]; then choco install qemu; export PATH="/c/Program Files/qemu:$PATH"; fi
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- rustup component add rust-src
|
- rustup component add rust-src
|
||||||
@@ -36,4 +48,5 @@ before_script:
|
|||||||
script:
|
script:
|
||||||
- bootimage build
|
- bootimage build
|
||||||
- cargo test
|
- cargo test
|
||||||
|
- bootimage test
|
||||||
- cargo cache --autoclean
|
- cargo cache --autoclean
|
||||||
|
|||||||
103
Cargo.lock
generated
103
Cargo.lock
generated
@@ -33,8 +33,12 @@ dependencies = [
|
|||||||
"array-init 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"array-init 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"x86_64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -49,6 +53,16 @@ dependencies = [
|
|||||||
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpuio"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedvec"
|
name = "fixedvec"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@@ -107,6 +121,19 @@ name = "os_bootinfo"
|
|||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pc-keyboard"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pic8259_simple"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pulldown-cmark"
|
name = "pulldown-cmark"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
@@ -140,6 +167,16 @@ name = "rand_core"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "raw-cpuid"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rdrand"
|
name = "rdrand"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -156,6 +193,27 @@ dependencies = [
|
|||||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver-parser"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "skeptic"
|
name = "skeptic"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -179,6 +237,15 @@ dependencies = [
|
|||||||
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uart_16550"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -218,6 +285,18 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x86_64"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x86_64"
|
name = "x86_64"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@@ -231,6 +310,19 @@ dependencies = [
|
|||||||
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x86_64"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xmas-elf"
|
name = "xmas-elf"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@@ -250,6 +342,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
|
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
"checksum bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0808c55da932b82d3ababdaa0caa3f18522c5d2d06309b98f73adda849a3f03"
|
"checksum bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0808c55da932b82d3ababdaa0caa3f18522c5d2d06309b98f73adda849a3f03"
|
||||||
|
"checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92"
|
||||||
|
"checksum cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
|
||||||
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
|
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
|
||||||
"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f"
|
"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f"
|
||||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||||
@@ -259,15 +353,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||||
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
|
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
|
||||||
|
"checksum pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fff50ab09ba31bcebc0669f4e64c0952fae1acdca9e6e0587e68e4e8443808ac"
|
||||||
|
"checksum pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc64b2fd10828da8521b6cdabe0679385d7d2a3a6d4c336b819d1fa31ba35c72"
|
||||||
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
||||||
"checksum rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dee497e66d8d76bf08ce20c8d36e16f93749ab0bf89975b4f8ae5cee660c2da2"
|
"checksum rand 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dee497e66d8d76bf08ce20c8d36e16f93749ab0bf89975b4f8ae5cee660c2da2"
|
||||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
|
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
|
||||||
|
"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d"
|
||||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||||
|
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
|
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
|
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c"
|
"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c"
|
||||||
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
|
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
|
||||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||||
|
"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e"
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
|
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
|
||||||
"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f"
|
"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f"
|
||||||
@@ -275,6 +376,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4"
|
||||||
"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177"
|
"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177"
|
||||||
|
"checksum x86_64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "de155d368de1d32afc8f90838bf81986e4bd43a0cd5fcd7f7e9c85cb8f51dc7c"
|
||||||
"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58"
|
"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58"
|
||||||
"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5"
|
"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5"
|
||||||
|
|||||||
@@ -5,9 +5,13 @@ authors = ["Philipp Oppermann <dev@phil-opp.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bootloader = "0.4.0"
|
bootloader = { version = "0.4.0", features = ["map_physical_memory"]}
|
||||||
volatile = "0.2.3"
|
volatile = "0.2.3"
|
||||||
spin = "0.4.9"
|
spin = "0.4.9"
|
||||||
|
uart_16550 = "0.1.0"
|
||||||
|
x86_64 = "0.5.2"
|
||||||
|
pic8259_simple = "0.1.1"
|
||||||
|
pc-keyboard = "0.3.1"
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -1,10 +1,10 @@
|
|||||||
# Blog OS (Unit Testing)
|
# Blog OS (Paging Implementation)
|
||||||
|
|
||||||
[](https://travis-ci.org/phil-opp/blog_os/branches)
|
[](https://travis-ci.org/phil-opp/blog_os/branches)
|
||||||
|
|
||||||
This repository contains the source code for the [Unit Testing][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
|
This repository contains the source code for the [Paging Implementation][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series.
|
||||||
|
|
||||||
[post]: https://os.phil-opp.com/unit-testing/
|
[post]: https://os.phil-opp.com/paging-implementation/
|
||||||
|
|
||||||
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**
|
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ Where `sdX` is the device name of your USB stick. **Be careful** to choose the c
|
|||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
To run the unit tests on the host system, execute `cargo test`.
|
To run the unit tests on the host system, execute `cargo test`. To run the integration tests in [QEMU], run `bootimage test`.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
The source code is dual-licensed under MIT or the Apache License (Version 2.0).
|
The source code is dual-licensed under MIT or the Apache License (Version 2.0).
|
||||||
|
|||||||
@@ -69,6 +69,29 @@ steps:
|
|||||||
- script: cargo test
|
- script: cargo test
|
||||||
displayName: 'Unit Tests'
|
displayName: 'Unit Tests'
|
||||||
|
|
||||||
|
- script: sudo apt install qemu-system-x86
|
||||||
|
condition: eq( variables['Agent.OS'], 'Linux' )
|
||||||
|
displayName: 'Install QEMU (Linux)'
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||||
|
export HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK=1
|
||||||
|
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||||
|
brew install qemu
|
||||||
|
condition: eq( variables['Agent.OS'], 'Darwin' )
|
||||||
|
displayName: 'Install QEMU (macOS)'
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
choco install qemu --limit-output --no-progress
|
||||||
|
echo ##vso[task.setvariable variable=PATH;]%PATH%;C:\Program Files\qemu
|
||||||
|
set PATH=%PATH%;C:\Program Files\qemu
|
||||||
|
qemu-system-x86_64 --version
|
||||||
|
condition: eq( variables['Agent.OS'], 'Windows_NT' )
|
||||||
|
displayName: 'Install QEMU (Windows)'
|
||||||
|
|
||||||
|
- script: bootimage test
|
||||||
|
displayName: 'Integration Tests'
|
||||||
|
|
||||||
- script: rustup component add rustfmt
|
- script: rustup component add rustfmt
|
||||||
displayName: 'Install Rustfmt'
|
displayName: 'Install Rustfmt'
|
||||||
|
|
||||||
|
|||||||
44
src/bin/test-basic-boot.rs
Normal file
44
src/bin/test-basic-boot.rs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#![cfg_attr(not(test), no_std)]
|
||||||
|
#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points
|
||||||
|
#![cfg_attr(test, allow(unused_imports))]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
|
use blog_os::memory::allocator::DummyAllocator;
|
||||||
|
use blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
/// This function is the entry point, since the linker looks for a function
|
||||||
|
/// named `_start` by default.
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[no_mangle] // don't mangle the name of this function
|
||||||
|
pub extern "C" fn _start() -> ! {
|
||||||
|
serial_println!("ok");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function is called on panic.
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
serial_println!("failed");
|
||||||
|
|
||||||
|
serial_println!("{}", info);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn out_of_memory(layout: Layout) -> ! {
|
||||||
|
panic!("out of memory: allocation for {:?} failed", layout);
|
||||||
|
}
|
||||||
45
src/bin/test-exception-breakpoint.rs
Normal file
45
src/bin/test-exception-breakpoint.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![cfg_attr(not(test), no_main)]
|
||||||
|
#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
|
use blog_os::memory::allocator::DummyAllocator;
|
||||||
|
use blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn _start() -> ! {
|
||||||
|
blog_os::interrupts::init_idt();
|
||||||
|
|
||||||
|
x86_64::instructions::interrupts::int3();
|
||||||
|
|
||||||
|
serial_println!("ok");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
serial_println!("failed");
|
||||||
|
|
||||||
|
serial_println!("{}", info);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn out_of_memory(layout: Layout) -> ! {
|
||||||
|
panic!("out of memory: allocation for {:?} failed", layout);
|
||||||
|
}
|
||||||
88
src/bin/test-exception-double-fault-stack-overflow.rs
Normal file
88
src/bin/test-exception-double-fault-stack-overflow.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#![feature(abi_x86_interrupt)]
|
||||||
|
#![no_std]
|
||||||
|
#![cfg_attr(not(test), no_main)]
|
||||||
|
#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
|
use blog_os::memory::allocator::DummyAllocator;
|
||||||
|
use blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[no_mangle]
|
||||||
|
#[allow(unconditional_recursion)]
|
||||||
|
pub extern "C" fn _start() -> ! {
|
||||||
|
blog_os::gdt::init();
|
||||||
|
init_test_idt();
|
||||||
|
|
||||||
|
fn stack_overflow() {
|
||||||
|
stack_overflow(); // for each recursion, the return address is pushed
|
||||||
|
}
|
||||||
|
|
||||||
|
// trigger a stack overflow
|
||||||
|
stack_overflow();
|
||||||
|
|
||||||
|
serial_println!("failed");
|
||||||
|
serial_println!("No exception occured");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function is called on panic.
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
serial_println!("failed");
|
||||||
|
serial_println!("{}", info);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn out_of_memory(layout: Layout) -> ! {
|
||||||
|
panic!("out of memory: allocation for {:?} failed", layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref TEST_IDT: InterruptDescriptorTable = {
|
||||||
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
|
unsafe {
|
||||||
|
idt.double_fault
|
||||||
|
.set_handler_fn(double_fault_handler)
|
||||||
|
.set_stack_index(blog_os::gdt::DOUBLE_FAULT_IST_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
idt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_test_idt() {
|
||||||
|
TEST_IDT.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn double_fault_handler(
|
||||||
|
_stack_frame: &mut InterruptStackFrame,
|
||||||
|
_error_code: u64,
|
||||||
|
) {
|
||||||
|
serial_println!("ok");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
34
src/bin/test-panic.rs
Normal file
34
src/bin/test-panic.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#![cfg_attr(not(test), no_std)]
|
||||||
|
#![cfg_attr(not(test), no_main)]
|
||||||
|
#![cfg_attr(test, allow(unused_imports))]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
|
use blog_os::memory::allocator::DummyAllocator;
|
||||||
|
use blog_os::{exit_qemu, serial_println};
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn _start() -> ! {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
|
serial_println!("ok");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit_qemu();
|
||||||
|
}
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: DummyAllocator = DummyAllocator;
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn out_of_memory(layout: Layout) -> ! {
|
||||||
|
panic!("out of memory: allocation for {:?} failed", layout);
|
||||||
|
}
|
||||||
52
src/gdt.rs
Normal file
52
src/gdt.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
|
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
|
||||||
|
use x86_64::structures::tss::TaskStateSegment;
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
|
||||||
|
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref TSS: TaskStateSegment = {
|
||||||
|
let mut tss = TaskStateSegment::new();
|
||||||
|
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
|
||||||
|
const STACK_SIZE: usize = 4096;
|
||||||
|
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
|
||||||
|
|
||||||
|
let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
|
||||||
|
let stack_end = stack_start + STACK_SIZE;
|
||||||
|
stack_end
|
||||||
|
};
|
||||||
|
tss
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref GDT: (GlobalDescriptorTable, Selectors) = {
|
||||||
|
let mut gdt = GlobalDescriptorTable::new();
|
||||||
|
let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
|
||||||
|
let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
|
||||||
|
(
|
||||||
|
gdt,
|
||||||
|
Selectors {
|
||||||
|
code_selector,
|
||||||
|
tss_selector,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Selectors {
|
||||||
|
code_selector: SegmentSelector,
|
||||||
|
tss_selector: SegmentSelector,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
use x86_64::instructions::segmentation::set_cs;
|
||||||
|
use x86_64::instructions::tables::load_tss;
|
||||||
|
|
||||||
|
GDT.0.load();
|
||||||
|
unsafe {
|
||||||
|
set_cs(GDT.1.code_selector);
|
||||||
|
load_tss(GDT.1.tss_selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
116
src/interrupts.rs
Normal file
116
src/interrupts.rs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// The x86-interrupt calling convention leads to the following LLVM error
|
||||||
|
// when compiled for a Windows target: "offset is not a multiple of 16". This
|
||||||
|
// happens for example when running `cargo test` on Windows. To avoid this
|
||||||
|
// problem we skip compilation of this module on Windows.
|
||||||
|
#![cfg(not(windows))]
|
||||||
|
|
||||||
|
use crate::{gdt, hlt_loop, print, println};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use pic8259_simple::ChainedPics;
|
||||||
|
use spin;
|
||||||
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
|
||||||
|
|
||||||
|
pub const PIC_1_OFFSET: u8 = 32;
|
||||||
|
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum InterruptIndex {
|
||||||
|
Timer = PIC_1_OFFSET,
|
||||||
|
Keyboard,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptIndex {
|
||||||
|
fn as_u8(self) -> u8 {
|
||||||
|
self as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_usize(self) -> usize {
|
||||||
|
usize::from(self.as_u8())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static PICS: spin::Mutex<ChainedPics> =
|
||||||
|
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
|
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||||
|
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||||
|
unsafe {
|
||||||
|
idt.double_fault
|
||||||
|
.set_handler_fn(double_fault_handler)
|
||||||
|
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
||||||
|
}
|
||||||
|
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
||||||
|
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||||
|
idt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_idt() {
|
||||||
|
IDT.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
|
||||||
|
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn page_fault_handler(
|
||||||
|
stack_frame: &mut InterruptStackFrame,
|
||||||
|
_error_code: PageFaultErrorCode,
|
||||||
|
) {
|
||||||
|
use crate::hlt_loop;
|
||||||
|
use x86_64::registers::control::Cr2;
|
||||||
|
|
||||||
|
println!("EXCEPTION: PAGE FAULT");
|
||||||
|
println!("Accessed Address: {:?}", Cr2::read());
|
||||||
|
println!("{:#?}", stack_frame);
|
||||||
|
hlt_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn double_fault_handler(
|
||||||
|
stack_frame: &mut InterruptStackFrame,
|
||||||
|
_error_code: u64,
|
||||||
|
) {
|
||||||
|
println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||||
|
hlt_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
|
||||||
|
print!(".");
|
||||||
|
unsafe {
|
||||||
|
PICS.lock()
|
||||||
|
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
|
||||||
|
use pc_keyboard::{layouts, DecodedKey, Keyboard, ScancodeSet1};
|
||||||
|
use spin::Mutex;
|
||||||
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||||
|
Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut keyboard = KEYBOARD.lock();
|
||||||
|
let port = Port::new(0x60);
|
||||||
|
|
||||||
|
let scancode: u8 = unsafe { port.read() };
|
||||||
|
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
|
||||||
|
if let Some(key) = keyboard.process_keyevent(key_event) {
|
||||||
|
match key {
|
||||||
|
DecodedKey::Unicode(character) => print!("{}", character),
|
||||||
|
DecodedKey::RawKey(key) => print!("{:?}", key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
PICS.lock()
|
||||||
|
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/lib.rs
Normal file
25
src/lib.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#![cfg_attr(not(test), no_std)]
|
||||||
|
#![feature(abi_x86_interrupt)]
|
||||||
|
#![feature(alloc)]
|
||||||
|
#![feature(const_fn)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
pub mod gdt;
|
||||||
|
pub mod interrupts;
|
||||||
|
pub mod memory;
|
||||||
|
pub mod serial;
|
||||||
|
pub mod vga_buffer;
|
||||||
|
|
||||||
|
pub unsafe fn exit_qemu() {
|
||||||
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
|
let mut port = Port::<u32>::new(0xf4);
|
||||||
|
port.write(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hlt_loop() -> ! {
|
||||||
|
loop {
|
||||||
|
x86_64::instructions::hlt();
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/main.rs
61
src/main.rs
@@ -1,17 +1,56 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![cfg_attr(not(test), no_main)]
|
#![cfg_attr(not(test), no_main)]
|
||||||
#![cfg_attr(test, allow(unused_imports))]
|
#![cfg_attr(test, allow(unused_imports))]
|
||||||
|
#![feature(alloc)]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use blog_os::{
|
||||||
|
memory::allocator::{BumpAllocator, LinkedListAllocator, LockedAllocator, BucketAllocator},
|
||||||
|
println,
|
||||||
|
};
|
||||||
|
use bootloader::{entry_point, BootInfo};
|
||||||
|
use core::alloc::Layout;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
mod vga_buffer;
|
entry_point!(kernel_main);
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[no_mangle]
|
fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||||
pub extern "C" fn _start() -> ! {
|
use blog_os::interrupts::PICS;
|
||||||
|
use blog_os::memory;
|
||||||
|
use x86_64::{structures::paging::Page, VirtAddr};
|
||||||
|
|
||||||
println!("Hello World{}", "!");
|
println!("Hello World{}", "!");
|
||||||
|
|
||||||
loop {}
|
blog_os::gdt::init();
|
||||||
|
blog_os::interrupts::init_idt();
|
||||||
|
unsafe { PICS.lock().initialize() };
|
||||||
|
x86_64::instructions::interrupts::enable();
|
||||||
|
|
||||||
|
let mut mapper = unsafe { memory::init(boot_info.physical_memory_offset) };
|
||||||
|
let mut frame_allocator = memory::init_frame_allocator(&boot_info.memory_map);
|
||||||
|
|
||||||
|
let heap_start = VirtAddr::new(HEAP_START);
|
||||||
|
let heap_end = VirtAddr::new(HEAP_END);
|
||||||
|
memory::map_heap(heap_start, heap_end, &mut mapper, &mut frame_allocator)
|
||||||
|
.expect("map_heap failed");
|
||||||
|
|
||||||
|
ALLOCATOR.lock().underlying().add_memory(heap_start, HEAP_END - HEAP_START);
|
||||||
|
|
||||||
|
//let mut x = Vec::with_capacity(1000);
|
||||||
|
let mut x = Vec::new();
|
||||||
|
for i in 0..1000 {
|
||||||
|
x.push(i);
|
||||||
|
}
|
||||||
|
println!("{:?}", *ALLOCATOR.lock());
|
||||||
|
println!("with vec of size {}: {}", x.len(), x.iter().sum::<i32>());
|
||||||
|
println!("with formular: {}", 999 * 1000 / 2);
|
||||||
|
|
||||||
|
println!("It did not crash!");
|
||||||
|
blog_os::hlt_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called on panic.
|
/// This function is called on panic.
|
||||||
@@ -19,5 +58,17 @@ pub extern "C" fn _start() -> ! {
|
|||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
println!("{}", info);
|
println!("{}", info);
|
||||||
loop {}
|
blog_os::hlt_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const HEAP_START: u64 = 0o_001_000_000_0000;
|
||||||
|
const HEAP_END: u64 = HEAP_START + 10 * 0x1000;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: LockedAllocator<BucketAllocator<LinkedListAllocator>> =
|
||||||
|
LockedAllocator::new(BucketAllocator::new(LinkedListAllocator::empty()));
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn out_of_memory(layout: Layout) -> ! {
|
||||||
|
panic!("out of memory: allocation for {:?} failed", layout);
|
||||||
}
|
}
|
||||||
|
|||||||
120
src/memory.rs
Normal file
120
src/memory.rs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
|
||||||
|
use x86_64::{
|
||||||
|
structures::paging::{
|
||||||
|
mapper, FrameAllocator, MappedPageTable, Mapper, MapperAllSizes, Page, PageTable,
|
||||||
|
PhysFrame, Size4KiB,
|
||||||
|
},
|
||||||
|
PhysAddr, VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod allocator;
|
||||||
|
|
||||||
|
/// Initialize a new MappedPageTable.
|
||||||
|
///
|
||||||
|
/// This function is unsafe because the caller must guarantee that the
|
||||||
|
/// complete physical memory is mapped to virtual memory at the passed
|
||||||
|
/// `physical_memory_offset`. Also, this function must be only called once
|
||||||
|
/// to avoid aliasing `&mut` references (which is undefined behavior).
|
||||||
|
pub unsafe fn init(physical_memory_offset: u64) -> impl MapperAllSizes {
|
||||||
|
let level_4_table = active_level_4_table(physical_memory_offset);
|
||||||
|
let phys_to_virt = move |frame: PhysFrame| -> *mut PageTable {
|
||||||
|
let phys = frame.start_address().as_u64();
|
||||||
|
let virt = VirtAddr::new(phys + physical_memory_offset);
|
||||||
|
virt.as_mut_ptr()
|
||||||
|
};
|
||||||
|
MappedPageTable::new(level_4_table, phys_to_virt)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a FrameAllocator from the passed memory map
|
||||||
|
pub fn init_frame_allocator(
|
||||||
|
memory_map: &'static MemoryMap,
|
||||||
|
) -> BootInfoFrameAllocator<impl Iterator<Item = PhysFrame>> {
|
||||||
|
// get usable regions from memory map
|
||||||
|
let regions = memory_map
|
||||||
|
.iter()
|
||||||
|
.filter(|r| r.region_type == MemoryRegionType::Usable);
|
||||||
|
// map each region to its address range
|
||||||
|
let addr_ranges = regions.map(|r| r.range.start_addr()..r.range.end_addr());
|
||||||
|
// transform to an iterator of frame start addresses
|
||||||
|
let frame_addresses = addr_ranges.flat_map(|r| r.into_iter().step_by(4096));
|
||||||
|
// create `PhysFrame` types from the start addresses
|
||||||
|
let frames = frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)));
|
||||||
|
|
||||||
|
BootInfoFrameAllocator { frames }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the active level 4 table.
|
||||||
|
///
|
||||||
|
/// This function is unsafe because the caller must guarantee that the
|
||||||
|
/// complete physical memory is mapped to virtual memory at the passed
|
||||||
|
/// `physical_memory_offset`. Also, this function must be only called once
|
||||||
|
/// to avoid aliasing `&mut` references (which is undefined behavior).
|
||||||
|
unsafe fn active_level_4_table(physical_memory_offset: u64) -> &'static mut PageTable {
|
||||||
|
use x86_64::{registers::control::Cr3, VirtAddr};
|
||||||
|
|
||||||
|
let (level_4_table_frame, _) = Cr3::read();
|
||||||
|
|
||||||
|
let phys = level_4_table_frame.start_address();
|
||||||
|
let virt = VirtAddr::new(phys.as_u64() + physical_memory_offset);
|
||||||
|
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
|
||||||
|
|
||||||
|
&mut *page_table_ptr // unsafe
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_heap(
|
||||||
|
heap_start: VirtAddr,
|
||||||
|
heap_end: VirtAddr,
|
||||||
|
mapper: &mut impl Mapper<Size4KiB>,
|
||||||
|
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||||
|
) -> Result<(), MapHeapError> {
|
||||||
|
use x86_64::structures::paging::PageTableFlags as Flags;
|
||||||
|
|
||||||
|
let flags = Flags::PRESENT | Flags::WRITABLE;
|
||||||
|
let start_page = Page::containing_address(heap_start);
|
||||||
|
let end_page = Page::containing_address(heap_end - 1u64);
|
||||||
|
|
||||||
|
for page in Page::range_inclusive(start_page, end_page) {
|
||||||
|
let frame = frame_allocator.allocate_frame();
|
||||||
|
let frame = frame.ok_or(MapHeapError::FrameAllocationFailed)?;
|
||||||
|
unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MapHeapError {
|
||||||
|
FrameAllocationFailed,
|
||||||
|
MapToError(mapper::MapToError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mapper::MapToError> for MapHeapError {
|
||||||
|
fn from(err: mapper::MapToError) -> Self {
|
||||||
|
MapHeapError::MapToError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A FrameAllocator that always returns `None`.
|
||||||
|
pub struct EmptyFrameAllocator;
|
||||||
|
|
||||||
|
impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
|
||||||
|
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BootInfoFrameAllocator<I>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = PhysFrame>,
|
||||||
|
{
|
||||||
|
frames: I,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> FrameAllocator<Size4KiB> for BootInfoFrameAllocator<I>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = PhysFrame>,
|
||||||
|
{
|
||||||
|
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||||
|
self.frames.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/memory/allocator.rs
Normal file
49
src/memory/allocator.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
pub use bump::BumpAllocator;
|
||||||
|
pub use dummy::DummyAllocator;
|
||||||
|
pub use linked_list::LinkedListAllocator;
|
||||||
|
pub use bucket::BucketAllocator;
|
||||||
|
|
||||||
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
use spin::{Mutex, MutexGuard};
|
||||||
|
|
||||||
|
mod bump;
|
||||||
|
mod dummy;
|
||||||
|
mod linked_list;
|
||||||
|
mod bucket;
|
||||||
|
|
||||||
|
pub struct LockedAllocator<T> {
|
||||||
|
allocator: Mutex<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LockedAllocator<T> {
|
||||||
|
pub const fn new(allocator: T) -> Self {
|
||||||
|
Self {
|
||||||
|
allocator: Mutex::new(allocator),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LockedAllocator<T> {
|
||||||
|
pub fn lock(&self) -> MutexGuard<T> {
|
||||||
|
self.allocator.lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> GlobalAlloc for LockedAllocator<T>
|
||||||
|
where
|
||||||
|
T: MutGlobalAlloc,
|
||||||
|
{
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
self.allocator.lock().alloc(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
self.allocator.lock().dealloc(ptr, layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MutGlobalAlloc {
|
||||||
|
fn alloc(&mut self, layout: Layout) -> *mut u8;
|
||||||
|
|
||||||
|
fn dealloc(&mut self, ptr: *mut u8, layout: Layout);
|
||||||
|
}
|
||||||
126
src/memory/allocator/bucket.rs
Normal file
126
src/memory/allocator/bucket.rs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
use super::MutGlobalAlloc;
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::mem::size_of;
|
||||||
|
use core::fmt::{self, Debug};
|
||||||
|
use core::cmp;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||||
|
underlying: A,
|
||||||
|
buckets: [Bucket; 10],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||||
|
pub const fn new(underlying: A) -> Self {
|
||||||
|
Self {
|
||||||
|
underlying,
|
||||||
|
buckets: [
|
||||||
|
Bucket::new(size_of::<Region>()),
|
||||||
|
Bucket::new(16),
|
||||||
|
Bucket::new(32),
|
||||||
|
Bucket::new(64),
|
||||||
|
Bucket::new(128),
|
||||||
|
Bucket::new(256),
|
||||||
|
Bucket::new(512),
|
||||||
|
Bucket::new(1024),
|
||||||
|
Bucket::new(2048),
|
||||||
|
Bucket::new(4096),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn underlying(&mut self) -> &mut A {
|
||||||
|
&mut self.underlying
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Bucket {
|
||||||
|
size: usize,
|
||||||
|
head: Option<&'static mut Region>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bucket {
|
||||||
|
const fn new(size: usize) -> Self {
|
||||||
|
Bucket {
|
||||||
|
size,
|
||||||
|
head: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(&self) -> Layout {
|
||||||
|
Layout::from_size_align(self.size, self.size).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Bucket {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter)-> fmt::Result {
|
||||||
|
let mut regions = 0;
|
||||||
|
let mut current = &self.head;
|
||||||
|
while let Some(region) = current {
|
||||||
|
current = ®ion.next;
|
||||||
|
regions += 1;
|
||||||
|
}
|
||||||
|
f.debug_struct("Bucket").field("size", &self.size).field("regions", ®ions).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Region {
|
||||||
|
next: Option<&'static mut Region>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Region {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
next: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_mut_u8(&'static mut self) -> *mut u8 {
|
||||||
|
self as *mut Region as *mut u8
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_mut_u8(ptr: *mut u8) -> &'static mut Self {
|
||||||
|
(ptr as *mut Region).write(Region::new());
|
||||||
|
&mut *(ptr as *mut Region)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||||
|
fn get_bucket_index(&self, layout: &Layout) -> Option<usize> {
|
||||||
|
let required_bucket_size = cmp::max(layout.size(), layout.align());
|
||||||
|
match self.buckets.binary_search_by(|bucket| bucket.size.cmp(&required_bucket_size)) {
|
||||||
|
Ok(index) => Some(index),
|
||||||
|
Err(index) if index < self.buckets.len() => Some(index),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> MutGlobalAlloc for BucketAllocator<A> where A: MutGlobalAlloc + Debug {
|
||||||
|
fn alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||||
|
if let Some(bucket_index) = self.get_bucket_index(&layout) {
|
||||||
|
let bucket = &mut self.buckets[bucket_index];
|
||||||
|
if let Some(head) = bucket.head.take() {
|
||||||
|
let next = head.next.take();
|
||||||
|
bucket.head = next;
|
||||||
|
return head.as_mut_u8();
|
||||||
|
} else {
|
||||||
|
self.underlying.alloc(bucket.layout())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.underlying.alloc(layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
|
||||||
|
if let Some(bucket_index) = self.get_bucket_index(&layout) {
|
||||||
|
let bucket = &mut self.buckets[bucket_index];
|
||||||
|
let region = unsafe {Region::from_mut_u8(ptr)};
|
||||||
|
region.next = bucket.head.take();
|
||||||
|
bucket.head = Some(region);
|
||||||
|
} else {
|
||||||
|
self.underlying.dealloc(ptr, layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/memory/allocator/bump.rs
Normal file
38
src/memory/allocator/bump.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use super::MutGlobalAlloc;
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use x86_64::align_up;
|
||||||
|
|
||||||
|
pub struct BumpAllocator {
|
||||||
|
heap_start: u64,
|
||||||
|
heap_end: u64,
|
||||||
|
next: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BumpAllocator {
|
||||||
|
pub const fn new(heap_start: u64, heap_end: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
heap_start,
|
||||||
|
heap_end,
|
||||||
|
next: heap_start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MutGlobalAlloc for BumpAllocator {
|
||||||
|
fn alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||||
|
let alloc_start = align_up(self.next, layout.align() as u64);
|
||||||
|
let alloc_end = alloc_start.saturating_add(layout.size() as u64);
|
||||||
|
|
||||||
|
if alloc_end >= self.heap_end {
|
||||||
|
// out of memory
|
||||||
|
return 0 as *mut u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.next = alloc_end;
|
||||||
|
alloc_start as *mut u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) {
|
||||||
|
panic!("BumpAllocator::dealloc called");
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/memory/allocator/dummy.rs
Normal file
16
src/memory/allocator/dummy.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
|
||||||
|
/// A dummy allocator that panics on every `alloc` or `dealloc` call.
|
||||||
|
pub struct DummyAllocator;
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for DummyAllocator {
|
||||||
|
/// Always panics.
|
||||||
|
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
|
||||||
|
panic!("DummyAllocator::alloc called");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always panics.
|
||||||
|
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
|
||||||
|
panic!("DummyAllocator::dealloc called");
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/memory/allocator/linked_list.rs
Normal file
95
src/memory/allocator/linked_list.rs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
use super::MutGlobalAlloc;
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::mem;
|
||||||
|
use x86_64::{align_up, VirtAddr};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LinkedListAllocator {
|
||||||
|
head: Region,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinkedListAllocator {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
let head = Region {
|
||||||
|
size: 0,
|
||||||
|
next: None,
|
||||||
|
};
|
||||||
|
Self { head }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn new(heap_start: VirtAddr, heap_size: u64) -> Self {
|
||||||
|
let mut allocator = Self::empty();
|
||||||
|
allocator.add_memory(heap_start, heap_size);
|
||||||
|
allocator
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_memory(&mut self, start: VirtAddr, size: u64) {
|
||||||
|
let aligned = start.align_up(mem::size_of::<Region>() as u64);
|
||||||
|
let mut region = Region {
|
||||||
|
size: size - (aligned - start),
|
||||||
|
next: None
|
||||||
|
};
|
||||||
|
mem::swap(&mut self.head.next, &mut region.next);
|
||||||
|
|
||||||
|
let region_ptr: *mut Region = aligned.as_mut_ptr();
|
||||||
|
unsafe { region_ptr.write(region) };
|
||||||
|
self.head.next = Some(unsafe { &mut *region_ptr });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MutGlobalAlloc for LinkedListAllocator {
|
||||||
|
fn alloc(&mut self, layout: Layout) -> *mut u8 {
|
||||||
|
let size = align_up(layout.size() as u64, mem::size_of::<Region>() as u64);
|
||||||
|
|
||||||
|
let mut current = &mut self.head;
|
||||||
|
loop {
|
||||||
|
let next = match current.next {
|
||||||
|
Some(ref mut next) => next,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
let next_start = VirtAddr::new(*next as *mut Region as u64);
|
||||||
|
let next_end = next_start + next.size;
|
||||||
|
|
||||||
|
let alloc_start = next_start.align_up(layout.align() as u64);
|
||||||
|
let alloc_end = alloc_start + size;
|
||||||
|
|
||||||
|
// check if Region large enough
|
||||||
|
if alloc_end <= next_end {
|
||||||
|
// remove Region from list
|
||||||
|
let next_next = next.next.take();
|
||||||
|
current.next = next_next;
|
||||||
|
// insert remaining Region to list
|
||||||
|
self.add_memory(alloc_end, next_end - alloc_end);
|
||||||
|
// return allocated memory
|
||||||
|
return alloc_start.as_mut_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue with next element
|
||||||
|
//
|
||||||
|
// This is basically `current = next`, but we need a new `match` expression because
|
||||||
|
// the compiler can't figure the lifetimes out when we use the `next` binding
|
||||||
|
// from above.
|
||||||
|
current = match current.next {
|
||||||
|
Some(ref mut next) => next,
|
||||||
|
None => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// no large enough Region found
|
||||||
|
0 as *mut u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
|
||||||
|
let size = align_up(layout.size() as u64, mem::size_of::<Region>() as u64);
|
||||||
|
self.add_memory(VirtAddr::new(ptr as u64), size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Region {
|
||||||
|
size: u64,
|
||||||
|
next: Option<&'static mut Region>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO recycle alignment
|
||||||
40
src/serial.rs
Normal file
40
src/serial.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
|
use uart_16550::SerialPort;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref SERIAL1: Mutex<SerialPort> = {
|
||||||
|
let mut serial_port = SerialPort::new(0x3F8);
|
||||||
|
serial_port.init();
|
||||||
|
Mutex::new(serial_port)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn _print(args: ::core::fmt::Arguments) {
|
||||||
|
use core::fmt::Write;
|
||||||
|
use x86_64::instructions::interrupts;
|
||||||
|
|
||||||
|
interrupts::without_interrupts(|| {
|
||||||
|
SERIAL1
|
||||||
|
.lock()
|
||||||
|
.write_fmt(args)
|
||||||
|
.expect("Printing to serial failed");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prints to the host through the serial interface.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! serial_print {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
$crate::serial::_print(format_args!($($arg)*));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prints to the host through the serial interface, appending a newline.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! serial_println {
|
||||||
|
() => ($crate::serial_print!("\n"));
|
||||||
|
($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n")));
|
||||||
|
($fmt:expr, $($arg:tt)*) => ($crate::serial_print!(concat!($fmt, "\n"), $($arg)*));
|
||||||
|
}
|
||||||
@@ -163,11 +163,16 @@ macro_rules! println {
|
|||||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints the given formatted string to the VGA text buffer through the global `WRITER` instance.
|
/// Prints the given formatted string to the VGA text buffer
|
||||||
|
/// through the global `WRITER` instance.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn _print(args: fmt::Arguments) {
|
pub fn _print(args: fmt::Arguments) {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
WRITER.lock().write_fmt(args).unwrap();
|
use x86_64::instructions::interrupts;
|
||||||
|
|
||||||
|
interrupts::without_interrupts(|| {
|
||||||
|
WRITER.lock().write_fmt(args).unwrap();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user