diff --git a/.appveyor.yml b/.appveyor.yml index dd760320..c586473b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -5,87 +5,7 @@ branches: - master - /post-.*/ -# Appveyor configuration template for Rust using rustup for Rust installation -# https://github.com/starkat99/appveyor-rust - -## Operating System (VM environment) ## - -# Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. -os: Visual Studio 2015 - -## Build Matrix ## -environment: - matrix: - -### MSVC Toolchains ### - # Nightly 64-bit MSVC - - channel: nightly - target: x86_64-pc-windows-msvc - MSYS_BITS: 64 - # Nightly 32-bit MSVC - - channel: nightly - target: i686-pc-windows-msvc - MSYS_BITS: 32 - -### GNU Toolchains ### - # Nightly 64-bit GNU - - channel: nightly - target: x86_64-pc-windows-gnu - MSYS_BITS: 64 - # Nightly 32-bit GNU - - channel: nightly - target: i686-pc-windows-gnu - MSYS_BITS: 32 - -cache: - - '%USERPROFILE%\.cargo\bin' - - '%USERPROFILE%\.cargo\.crates.toml' - -## Install Script ## - -# This is the most important part of the Appveyor configuration. This installs the version of Rust -# specified by the 'channel' and 'target' environment variables from the build matrix. This uses -# rustup to install Rust. -# -# For simple configurations, instead of using the build matrix, you can simply set the -# default-toolchain and default-host manually here. -install: - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init -yv --default-toolchain %channel% --default-host %target% - - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - - rustc -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 ## - -# 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents -# the "directory does not contain a project or solution file" error. build: false -before_test: - - set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% - # Fix undefined references to __acrt_iob_func() - - sed -rie "s/#define std([[:alpha:]]+)[[:space:]]+\(__acrt_iob_func\(([[:digit:]]+)\)\)/#define std\1 (\&__iob_func()[\2])/" "C:\msys64\mingw64\x86_64-w64-mingw32\include\stdio.h" - - sed -rie "s/#define std([[:alpha:]]+)[[:space:]]+\(__acrt_iob_func\(([[:digit:]]+)\)\)/#define std\1 (\&__iob_func()[\2])/" "C:\msys64\mingw32\i686-w64-mingw32\include\stdio.h" - - rustup component add rust-src - - set RUST_BACKTRACE=1 - - if not exist %USERPROFILE%\.cargo\bin\cargo-install-latest.exe cargo install cargo-install-latest - - cargo install-latest cargo-xbuild bootimage - test_script: - - bootimage build - - if %target%==x86_64-pc-windows-gnu cargo test - - if %target%==x86_64-pc-windows-msvc cargo test - - bootimage test + - echo "Nothing to do for master branch" diff --git a/.gitignore b/.gitignore index f0e3bcac..01b2d72f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -/target -**/*.rs.bk \ No newline at end of file +code diff --git a/.travis.yml b/.travis.yml index 6395333a..22f1dd0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,4 @@ -language: rust - -rust: - - nightly - -os: - - linux - - osx - - windows - -notifications: - email: - on_success: never - on_failure: always +language: minimal branches: only: @@ -24,29 +11,5 @@ branches: # Build post braches - /^post-.*$/ -cache: - directories: - - $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: - - rustup component add rust-src - - (test -x $HOME/.cargo/bin/cargo-install-latest || cargo install cargo-install-latest) - - cargo install-latest cargo-xbuild bootimage cargo-cache - script: - - bootimage build - - cargo test - - bootimage test - - cargo cache --autoclean + - echo "Nothing to do for master branch" diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 709bfe80..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,327 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "array-init" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "array-init" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit_field" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "blog_os" -version = "0.1.0" -dependencies = [ - "array-init 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bootloader 0.3.12 (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)", - "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)", - "x86_64 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bootloader" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.14 (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 = "cpuio" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixedvec" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "font8x8" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getopts" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.48" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "os_bootinfo" -version = "0.2.1" -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]] -name = "pulldown-cmark" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "skeptic" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spin" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.5 (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]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "usize_conversions" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ux" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "volatile" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -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]] -name = "x86_64" -version = "0.4.0" -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)", - "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]] -name = "xmas-elf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zero" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum array-init 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c3cc8456d0ae81a8c76f59e384683a601548c38949a4bfcb65dd31ded5c75ff3" -"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" -"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 bootloader 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "2b498d7168288f3667f80aee93b4894e355dfce867803e1ccd5d9ee42a0b0e1a" -"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 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-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"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 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 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.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"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 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 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 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 volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" -"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-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.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f893c7b302f824d1bb6ab25353e585583fa451c918d950e6f81ff5b4267cc18" -"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" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index af3f7846..00000000 --- a/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "blog_os" -version = "0.1.0" -authors = ["Philipp Oppermann "] -edition = "2018" - -[dependencies] -bootloader = "0.3.12" -volatile = "0.2.3" -spin = "0.4.9" -uart_16550 = "0.1.0" -x86_64 = "0.4.0" -pic8259_simple = "0.1.1" -pc-keyboard = "0.3.1" - -[dependencies.lazy_static] -version = "1.0" -features = ["spin_no_std"] - -[dev-dependencies] -array-init = "0.0.3" - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" - -[package.metadata.bootimage] -default-target = "x86_64-blog_os.json" diff --git a/README.md b/README.md index deb9db63..91cdbe8b 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,27 @@ This repository contains the source code for the _Writing an OS in Rust_ series at [os.phil-opp.com](https://os.phil-opp.com). -## Building -You need a nightly Rust compiler and the `cargo-xbuild` and `bootimage` tools. You can install the tools by executing the following command: +## Where is the code? + +The code for each post lives in a separate git branch. This makes it possible to see the intermediate state after each post. You can find the branch for each post by following the `(source code)` link in the [post list](#posts) below. The branches are named `post-XX` where `XX` is the post number, for example `post-03` for the third post ("VGA Text Mode"). + +**You can find the code for the latest post [here][latest-post].** + +[latest-post]: https://github.com/phil-opp/blog_os/tree/post-10 + +For build instructions, see the Readme of the post branches. + +### Checking out the Code in a Subdirectory + +To check out the code in a subdirectory use [git worktree]: + +[git worktree]: https://git-scm.com/docs/git-worktree ``` -cargo install cargo-xbuild bootimage +git worktree add code post-10 ``` -Afterwards you can invoke `bootimage build` to produce a bootable disk image. Please file an issue if you run into any problems. - -To run the image in [QEMU], you can execute `bootimage run`. Note that you need to have QEMU installed. - -[QEMU]: https://www.qemu.org/ +This creates a subdirectory named `code` that contains the code for the latest post ("Advanced Paging"). ## Posts diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d0bab98a..50b69815 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,20 +13,8 @@ trigger: # Build post braches - post-* -strategy: - matrix: - linux: - image_name: 'ubuntu-16.04' - rustup_toolchain: nightly - mac: - image_name: 'macos-10.13' - rustup_toolchain: nightly - windows: - image_name: 'vs2017-win2016' - rustup_toolchain: nightly - pool: - vmImage: $(image_name) + vmImage: ubuntu-16.04 steps: - bash: | @@ -36,58 +24,5 @@ steps: displayName: 'Build Info' continueOnError: true -- script: | - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" - condition: or(eq( variables['Agent.OS'], 'Linux' ), eq( variables['Agent.OS'], 'Darwin' )) - displayName: 'Install Rust (Linux/macOS)' - -- script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% - echo ##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - displayName: 'Install Rust (Windows)' - -- script: | - rustc -Vv - cargo -V - displayName: 'Print Rust Version' - continueOnError: true - -- script: rustup component add rust-src - displayName: 'Install Rustup Src Component' - -- script: | - cargo install cargo-xbuild --debug - cargo install bootimage --debug - displayName: 'Install cargo-xbuild and bootimage' - -- script: bootimage build - displayName: 'Build' - -- script: cargo test - 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: echo "Nothing to do for master branch" + displayName: "Nothing to do" diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index bf867e0a..00000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly diff --git a/src/bin/test-basic-boot.rs b/src/bin/test-basic-boot.rs deleted file mode 100644 index f77d4a02..00000000 --- a/src/bin/test-basic-boot.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points -#![cfg_attr(test, allow(unused_imports))] - -use blog_os::{exit_qemu, serial_println}; -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 {} -} diff --git a/src/bin/test-exception-breakpoint.rs b/src/bin/test-exception-breakpoint.rs deleted file mode 100644 index c6bf114a..00000000 --- a/src/bin/test-exception-breakpoint.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] -#![cfg_attr(not(test), no_main)] -#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))] - -use blog_os::{exit_qemu, serial_println}; -use core::panic::PanicInfo; - -#[cfg(not(test))] -#[no_mangle] -pub extern "C" fn _start() -> ! { - blog_os::interrupts::init_idt(); - - x86_64::instructions::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 {} -} diff --git a/src/bin/test-exception-double-fault-stack-overflow.rs b/src/bin/test-exception-double-fault-stack-overflow.rs deleted file mode 100644 index 3d934a4c..00000000 --- a/src/bin/test-exception-double-fault-stack-overflow.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![feature(abi_x86_interrupt)] -#![no_std] -#![cfg_attr(not(test), no_main)] -#![cfg_attr(test, allow(dead_code, unused_macros, unused_imports))] - -use blog_os::{exit_qemu, serial_println}; -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 {} -} - -use x86_64::structures::idt::{ExceptionStackFrame, InterruptDescriptorTable}; - -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 ExceptionStackFrame, - _error_code: u64, -) { - serial_println!("ok"); - - unsafe { - exit_qemu(); - } - loop {} -} diff --git a/src/bin/test-panic.rs b/src/bin/test-panic.rs deleted file mode 100644 index c68ac51d..00000000 --- a/src/bin/test-panic.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![cfg_attr(not(test), no_main)] -#![cfg_attr(test, allow(unused_imports))] - -use blog_os::{exit_qemu, serial_println}; -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 {} -} diff --git a/src/gdt.rs b/src/gdt.rs deleted file mode 100644 index de61a7d8..00000000 --- a/src/gdt.rs +++ /dev/null @@ -1,52 +0,0 @@ -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); - } -} diff --git a/src/interrupts.rs b/src/interrupts.rs deleted file mode 100644 index 83ba18dc..00000000 --- a/src/interrupts.rs +++ /dev/null @@ -1,96 +0,0 @@ -// 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::{ExceptionStackFrame, InterruptDescriptorTable, PageFaultErrorCode}; - -pub const PIC_1_OFFSET: u8 = 32; -pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; - -pub const TIMER_INTERRUPT_ID: u8 = PIC_1_OFFSET; -pub const KEYBOARD_INTERRUPT_ID: u8 = PIC_1_OFFSET + 1; - -pub static PICS: spin::Mutex = - 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[usize::from(TIMER_INTERRUPT_ID)].set_handler_fn(timer_interrupt_handler); - idt[usize::from(KEYBOARD_INTERRUPT_ID)].set_handler_fn(keyboard_interrupt_handler); - idt - }; -} - -pub fn init_idt() { - IDT.load(); -} - -extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut ExceptionStackFrame) { - println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); -} - -extern "x86-interrupt" fn page_fault_handler( - stack_frame: &mut ExceptionStackFrame, - _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 ExceptionStackFrame, - _error_code: u64, -) { - println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); - hlt_loop(); -} - -extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut ExceptionStackFrame) { - print!("."); - unsafe { PICS.lock().notify_end_of_interrupt(TIMER_INTERRUPT_ID) } -} - -extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut ExceptionStackFrame) { - use pc_keyboard::{layouts, DecodedKey, Keyboard, ScancodeSet1}; - use spin::Mutex; - use x86_64::instructions::port::Port; - - lazy_static! { - static ref KEYBOARD: Mutex> = - 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(KEYBOARD_INTERRUPT_ID) } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 5974e73c..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![feature(abi_x86_interrupt)] - -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::::new(0xf4); - port.write(0); -} - -pub fn hlt_loop() -> ! { - loop { - x86_64::instructions::hlt(); - } -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index a6493875..00000000 --- a/src/main.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![cfg_attr(not(test), no_main)] -#![cfg_attr(test, allow(unused_imports))] - -use blog_os::println; -use bootloader::{bootinfo::BootInfo, entry_point}; -use core::panic::PanicInfo; - -entry_point!(kernel_main); - -#[cfg(not(test))] -fn kernel_main(boot_info: &'static BootInfo) -> ! { - use blog_os::interrupts::PICS; - use blog_os::memory::{self, create_example_mapping}; - - println!("Hello World{}", "!"); - - blog_os::gdt::init(); - blog_os::interrupts::init_idt(); - unsafe { PICS.lock().initialize() }; - x86_64::instructions::interrupts::enable(); - - let mut recursive_page_table = unsafe { memory::init(boot_info.p4_table_addr as usize) }; - let mut frame_allocator = memory::init_frame_allocator(&boot_info.memory_map); - - create_example_mapping(&mut recursive_page_table, &mut frame_allocator); - unsafe { (0xdeadbeaf900 as *mut u64).write_volatile(0xf021f077f065f04e) }; - - println!("It did not crash!"); - blog_os::hlt_loop(); -} - -/// This function is called on panic. -#[cfg(not(test))] -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - println!("{}", info); - blog_os::hlt_loop(); -} diff --git a/src/memory.rs b/src/memory.rs deleted file mode 100644 index 612f4209..00000000 --- a/src/memory.rs +++ /dev/null @@ -1,90 +0,0 @@ -use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; -use x86_64::structures::paging::{ - FrameAllocator, Mapper, Page, PageTable, PhysFrame, RecursivePageTable, Size4KiB, -}; -use x86_64::{PhysAddr, VirtAddr}; - -/// Creates a RecursivePageTable instance from the level 4 address. -/// -/// This function is unsafe because it can break memory safety if an invalid -/// address is passed. -pub unsafe fn init(level_4_table_addr: usize) -> RecursivePageTable<'static> { - /// Rust currently treats the whole body of unsafe functions as an unsafe - /// block, which makes it difficult to see which operations are unsafe. To - /// limit the scope of unsafe we use a safe inner function. - fn init_inner(level_4_table_addr: usize) -> RecursivePageTable<'static> { - let level_4_table_ptr = level_4_table_addr as *mut PageTable; - let level_4_table = unsafe { &mut *level_4_table_ptr }; - RecursivePageTable::new(level_4_table).unwrap() - } - - init_inner(level_4_table_addr) -} - -/// Create a FrameAllocator from the passed memory map -pub fn init_frame_allocator( - memory_map: &'static MemoryMap, -) -> BootInfoFrameAllocator> { - // 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 the physical address for the given virtual address, or `None` if -/// the virtual address is not mapped. -pub fn translate_addr(addr: u64, recursive_page_table: &RecursivePageTable) -> Option { - let addr = VirtAddr::new(addr); - let page: Page = Page::containing_address(addr); - - // perform the translation - let frame = recursive_page_table.translate_page(page); - frame.map(|frame| frame.start_address() + u64::from(addr.page_offset())) -} - -pub fn create_example_mapping( - recursive_page_table: &mut RecursivePageTable, - frame_allocator: &mut impl FrameAllocator, -) { - use x86_64::structures::paging::PageTableFlags as Flags; - - let page: Page = Page::containing_address(VirtAddr::new(0xdeadbeaf000)); - let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000)); - let flags = Flags::PRESENT | Flags::WRITABLE; - - let map_to_result = unsafe { recursive_page_table.map_to(page, frame, flags, frame_allocator) }; - map_to_result.expect("map_to failed").flush(); -} - -/// A FrameAllocator that always returns `None`. -pub struct EmptyFrameAllocator; - -impl FrameAllocator for EmptyFrameAllocator { - fn allocate_frame(&mut self) -> Option { - None - } -} - -pub struct BootInfoFrameAllocator -where - I: Iterator, -{ - frames: I, -} - -impl FrameAllocator for BootInfoFrameAllocator -where - I: Iterator, -{ - fn allocate_frame(&mut self) -> Option { - self.frames.next() - } -} diff --git a/src/serial.rs b/src/serial.rs deleted file mode 100644 index c742b09c..00000000 --- a/src/serial.rs +++ /dev/null @@ -1,40 +0,0 @@ -use lazy_static::lazy_static; -use spin::Mutex; -use uart_16550::SerialPort; - -lazy_static! { - pub static ref SERIAL1: Mutex = { - 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)*)); -} diff --git a/src/vga_buffer.rs b/src/vga_buffer.rs deleted file mode 100644 index 60fe21d4..00000000 --- a/src/vga_buffer.rs +++ /dev/null @@ -1,259 +0,0 @@ -use core::fmt; -use lazy_static::lazy_static; -use spin::Mutex; -use volatile::Volatile; - -lazy_static! { - /// A global `Writer` instance that can be used for printing to the VGA text buffer. - /// - /// Used by the `print!` and `println!` macros. - pub static ref WRITER: Mutex = Mutex::new(Writer { - column_position: 0, - color_code: ColorCode::new(Color::Yellow, Color::Black), - buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, - }); -} - -/// The standard color palette in VGA text mode. -#[allow(dead_code)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum Color { - Black = 0, - Blue = 1, - Green = 2, - Cyan = 3, - Red = 4, - Magenta = 5, - Brown = 6, - LightGray = 7, - DarkGray = 8, - LightBlue = 9, - LightGreen = 10, - LightCyan = 11, - LightRed = 12, - Pink = 13, - Yellow = 14, - White = 15, -} - -/// A combination of a foreground and a background color. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(transparent)] -struct ColorCode(u8); - -impl ColorCode { - /// Create a new `ColorCode` with the given foreground and background colors. - fn new(foreground: Color, background: Color) -> ColorCode { - ColorCode((background as u8) << 4 | (foreground as u8)) - } -} - -/// A screen character in the VGA text buffer, consisting of an ASCII character and a `ColorCode`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(C)] -struct ScreenChar { - ascii_character: u8, - color_code: ColorCode, -} - -/// The height of the text buffer (normally 25 lines). -const BUFFER_HEIGHT: usize = 25; -/// The width of the text buffer (normally 80 columns). -const BUFFER_WIDTH: usize = 80; - -/// A structure representing the VGA text buffer. -#[repr(transparent)] -struct Buffer { - chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], -} - -/// A writer type that allows writing ASCII bytes and strings to an underlying `Buffer`. -/// -/// Wraps lines at `BUFFER_WIDTH`. Supports newline characters and implements the -/// `core::fmt::Write` trait. -pub struct Writer { - column_position: usize, - color_code: ColorCode, - buffer: &'static mut Buffer, -} - -impl Writer { - /// Writes an ASCII byte to the buffer. - /// - /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character. - pub fn write_byte(&mut self, byte: u8) { - match byte { - b'\n' => self.new_line(), - byte => { - if self.column_position >= BUFFER_WIDTH { - self.new_line(); - } - - let row = BUFFER_HEIGHT - 1; - let col = self.column_position; - - let color_code = self.color_code; - self.buffer.chars[row][col].write(ScreenChar { - ascii_character: byte, - color_code, - }); - self.column_position += 1; - } - } - } - - /// Writes the given ASCII string to the buffer. - /// - /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character. Does **not** - /// support strings with non-ASCII characters, since they can't be printed in the VGA text - /// mode. - fn write_string(&mut self, s: &str) { - for byte in s.bytes() { - match byte { - // printable ASCII byte or newline - 0x20...0x7e | b'\n' => self.write_byte(byte), - // not part of printable ASCII range - _ => self.write_byte(0xfe), - } - } - } - - /// Shifts all lines one line up and clears the last row. - fn new_line(&mut self) { - for row in 1..BUFFER_HEIGHT { - for col in 0..BUFFER_WIDTH { - let character = self.buffer.chars[row][col].read(); - self.buffer.chars[row - 1][col].write(character); - } - } - self.clear_row(BUFFER_HEIGHT - 1); - self.column_position = 0; - } - - /// Clears a row by overwriting it with blank characters. - fn clear_row(&mut self, row: usize) { - let blank = ScreenChar { - ascii_character: b' ', - color_code: self.color_code, - }; - for col in 0..BUFFER_WIDTH { - self.buffer.chars[row][col].write(blank); - } - } -} - -impl fmt::Write for Writer { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.write_string(s); - Ok(()) - } -} - -/// Like the `print!` macro in the standard library, but prints to the VGA text buffer. -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*))); -} - -/// Like the `println!` macro in the standard library, but prints to the VGA text buffer. -#[macro_export] -macro_rules! println { - () => ($crate::print!("\n")); - ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); -} - -/// Prints the given formatted string to the VGA text buffer -/// through the global `WRITER` instance. -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - use core::fmt::Write; - use x86_64::instructions::interrupts; - - interrupts::without_interrupts(|| { - WRITER.lock().write_fmt(args).unwrap(); - }); -} - -#[cfg(test)] -mod test { - use super::*; - - fn construct_writer() -> Writer { - use std::boxed::Box; - - let buffer = construct_buffer(); - Writer { - column_position: 0, - color_code: ColorCode::new(Color::Blue, Color::Magenta), - buffer: Box::leak(Box::new(buffer)), - } - } - - fn construct_buffer() -> Buffer { - use array_init::array_init; - - Buffer { - chars: array_init(|_| array_init(|_| Volatile::new(empty_char()))), - } - } - - fn empty_char() -> ScreenChar { - ScreenChar { - ascii_character: b' ', - color_code: ColorCode::new(Color::Green, Color::Brown), - } - } - - #[test] - fn write_byte() { - let mut writer = construct_writer(); - writer.write_byte(b'X'); - writer.write_byte(b'Y'); - - for (i, row) in writer.buffer.chars.iter().enumerate() { - for (j, screen_char) in row.iter().enumerate() { - let screen_char = screen_char.read(); - if i == BUFFER_HEIGHT - 1 && j == 0 { - assert_eq!(screen_char.ascii_character, b'X'); - assert_eq!(screen_char.color_code, writer.color_code); - } else if i == BUFFER_HEIGHT - 1 && j == 1 { - assert_eq!(screen_char.ascii_character, b'Y'); - assert_eq!(screen_char.color_code, writer.color_code); - } else { - assert_eq!(screen_char, empty_char()); - } - } - } - } - - #[test] - fn write_formatted() { - use core::fmt::Write; - - let mut writer = construct_writer(); - writeln!(&mut writer, "a").unwrap(); - writeln!(&mut writer, "b{}", "c").unwrap(); - - for (i, row) in writer.buffer.chars.iter().enumerate() { - for (j, screen_char) in row.iter().enumerate() { - let screen_char = screen_char.read(); - if i == BUFFER_HEIGHT - 3 && j == 0 { - assert_eq!(screen_char.ascii_character, b'a'); - assert_eq!(screen_char.color_code, writer.color_code); - } else if i == BUFFER_HEIGHT - 2 && j == 0 { - assert_eq!(screen_char.ascii_character, b'b'); - assert_eq!(screen_char.color_code, writer.color_code); - } else if i == BUFFER_HEIGHT - 2 && j == 1 { - assert_eq!(screen_char.ascii_character, b'c'); - assert_eq!(screen_char.color_code, writer.color_code); - } else if i >= BUFFER_HEIGHT - 2 { - assert_eq!(screen_char.ascii_character, b' '); - assert_eq!(screen_char.color_code, writer.color_code); - } else { - assert_eq!(screen_char, empty_char()); - } - } - } - } -} diff --git a/x86_64-blog_os.json b/x86_64-blog_os.json deleted file mode 100644 index c1c29f9e..00000000 --- a/x86_64-blog_os.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "arch": "x86_64", - "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", - "os": "none", - "executables": true, - "linker-flavor": "ld.lld", - "linker": "rust-lld", - "panic-strategy": "abort", - "disable-redzone": true, - "features": "-mmx,-sse,+soft-float" - } \ No newline at end of file