├── .github └── workflows │ └── sitegen.yml ├── .gitignore ├── LICENSE ├── README.md ├── adoc ├── adoctor_input_template.adoc └── html5 │ └── embedded.html.erb ├── categories.yml ├── css ├── layout.css ├── stork.css └── styles.css ├── generator ├── .gitignore ├── LICENSE ├── README.md ├── Setup.hs ├── app │ ├── Main.hs │ └── Stork.hs ├── default.nix ├── generator.cabal ├── nix │ ├── sources.json │ └── sources.nix ├── package.yaml ├── stack.yaml └── stack.yaml.lock ├── html ├── error_page.html ├── navbar.html ├── tag_index.html ├── tag_list.html └── wrapper.html ├── index.adoc ├── licenses └── CC0.txt ├── pages ├── .stivale_cs_barebones.adoc ├── calling_conventions.adoc ├── cross_clang.adoc ├── editorial_rules.adoc ├── fundamentals.adoc ├── guidelines.adoc ├── stivale.adoc ├── stivale_barebones.adoc ├── visual_studio.adoc ├── writer_tutorial.adoc └── x86.adoc ├── sources.bib └── static ├── logo.svg └── search.js /.github/workflows/sitegen.yml: -------------------------------------------------------------------------------- 1 | name: Generate pages 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ main ] 7 | 8 | env: 9 | STORK_VERSION: 1.6.0 10 | 11 | jobs: 12 | gen: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout wiki 16 | uses: actions/checkout@v2 17 | with: 18 | fetch-depth: 0 19 | path: wiki 20 | 21 | - uses: cachix/install-nix-action@v15 22 | with: 23 | extra_nix_config: | 24 | trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= osdev-wiki-cache-2:xnfH8Tkm0Sp5c8dDxpuFE0/w1PB6E4NUxjcnShNdkZ0= 25 | substituters = https://cache.nixos.org/ https://hydra.iohk.io s3://osdev-wiki-cache?scheme=https&endpoint=s3.us-west-000.backblazeb2.com 26 | 27 | - name: Maybe add secrets 28 | run: | 29 | set -uxe 30 | [ -z "$AWS_CREDS$NIX_SIGNING_KEY" ] && exit 31 | mkdir ~/.aws 32 | echo "$AWS_CREDS" > ~/.aws/credentials 33 | echo "$NIX_SIGNING_KEY" > ~/.nix-key 34 | echo secret-key-files = ~/.nix-key | sudo tee -a /etc/nix/nix.conf 35 | env: 36 | NIX_SIGNING_KEY: ${{ secrets.NIX_SIGNING_KEY }} 37 | AWS_CREDS: ${{ secrets.AWS_CREDS }} 38 | 39 | - name: Cache dependency builds 40 | uses: actions/cache@v2 41 | with: 42 | path: | 43 | ~/.cache/nix/*sqlite* 44 | key: ${{ runner.os }} 45 | - name: Get deps 46 | run: | 47 | set -xe 48 | gem install --user-install asciidoctor asciidoctor-bibtex tilt \ 49 | pygments.rb 50 | pip install --user -U Pygments 51 | nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs 52 | nix-channel --update nixpkgs 53 | nix-env -i "stork-$STORK_VERSION" 54 | 55 | - name: Build generator 56 | run: | 57 | cd wiki/generator 58 | nix-build 59 | 60 | - name: Update nix caches 61 | if: always() 62 | run: | 63 | set -xe 64 | [ -r ~/.nix-key ] || exit 0 65 | cd wiki/generator 66 | nix store sign -k ~/.nix-key "$(readlink result)" 67 | stork_path="$(nix-env -q --installed --out-path --no-name stork)" 68 | nix copy --to 's3://osdev-wiki-cache?scheme=https&endpoint=s3.us-west-000.backblazeb2.com&profile=osdev-wiki-cache' \ 69 | "$(readlink result)" "$stork_path" 70 | 71 | - name: Build site 72 | run: | 73 | export GEM_HOME="$(ruby -e 'puts Gem.user_dir')" 74 | export PATH="$GEM_HOME/bin:$HOME/.cargo/bin:$HOME/.local/bin:$PATH" 75 | export PATH="$HOME/.nix-profile/bin:$PATH" 76 | 77 | cd wiki 78 | export GIT_HASH="$(git rev-parse HEAD)" 79 | generator/result/bin/generator build 80 | env: 81 | WIKI_FORGE: ${{ format('https://github.com/{0}', github.repository) }} 82 | 83 | - name: Checkout publishing 84 | uses: actions/checkout@v2 85 | with: 86 | path: _out 87 | repository: osdev-wiki/osdev-wiki.github.io 88 | fetch-depth: 0 89 | ssh-key: "${{ secrets.DEPLOY_KEY }}" 90 | if: ${{ github.repository == 'osdev-wiki/wiki' }} 91 | - name: Checkout publishing (for forks) 92 | uses: actions/checkout@v2 93 | with: 94 | path: _out 95 | token: "${{ github.token }}" 96 | fetch-depth: 0 97 | ref: gh-pages 98 | if: ${{ github.repository != 'osdev-wiki/wiki' }} 99 | 100 | - name: Publish 101 | run: | 102 | set -xe 103 | 104 | cd _out 105 | find . -not -path './.git/*' -not -path ./.git -delete 106 | echo osdev.wiki > CNAME 107 | touch .nojekyll 108 | 109 | rsync -a ../wiki/_site/ ./ 110 | 111 | export COMMIT_HASH="$(git -C ../wiki rev-parse HEAD)" 112 | git config user.name "Wiki Autobuild" 113 | git config user.email "autobuild@osdev.wiki" 114 | git add . 115 | git commit -m "$COMMIT_HASH" 116 | git push 117 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | _cache 3 | _site 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## The OSDev Wiki 2 | 3 | The goal of this wiki is to create a decentralized repository of accurate and 4 | up-to-date information on operating system development. 5 | It is currently **WIP** and **not ready** for use. 6 | 7 | This wiki is not endorsed by, does not have any connection to, and is not 8 | related in any way with another wiki found at 9 | [wiki.osdev.org](https://wiki.osdev.org). 10 | 11 | # Contributing 12 | 13 | ## Installing dependencies 14 | 15 | This wiki is written in Haskell. 16 | 17 | The project has some non-Haskell dependencies: 18 | 19 | - [Pygments](https://github.com/pygments/pygments) - `pip install Pygments` 20 | - [AsciiDoctor](https://asciidoctor.org/) - `gem install asciidoctor` 21 | - [asciidoctor-bibtex](https://github.com/asciidoctor/asciidoctor-bibtex) - `gem install asciidoctor-bibtex` 22 | - [stork](https://stork-search.net/docs/install) - `cargo install stork-search --locked` 23 | 24 | ## Building and running 25 | 26 | Because building the Haskell dependencies takes a long time, we recommend using 27 | our Nix binary cache to get all the dependencies without building (~10 min 28 | setup time). 29 | 30 | ### With Nix 31 | 32 | [Install nix](https://nixos.org/download.html#download-nix). 33 | 34 | Edit the configuration file added by Nix at `/etc/nix/nix.conf` and add these 35 | two lines to setup the binary cache: 36 | 37 | ```nix 38 | trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= osdev-wiki-cache-2:xnfH8Tkm0Sp5c8dDxpuFE0/w1PB6E4NUxjcnShNdkZ0= 39 | substituters = https://cache.nixos.org/ https://hydra.iohk.io s3://osdev-wiki-cache?scheme=https&endpoint=s3.us-west-000.backblazeb2.com 40 | ``` 41 | 42 | From the root of the project, build: 43 | 44 | ```shell 45 | cd generator 46 | nix-build 47 | ``` 48 | 49 | Run the generator: 50 | 51 | ```shell 52 | cd .. 53 | ./generator/result/bin/generator watch 54 | ``` 55 | 56 | ### Building locally 57 | 58 | **Alternatively**, you can build locally (~1 hour build time). You do _not_ 59 | need to do this if you have done the Nix setup above. 60 | 61 | You will need to have Stack installed to compile and run the main binary. 62 | 63 | From the root of the project, run: 64 | 65 | ```shell 66 | cd generator 67 | stack build 68 | ``` 69 | 70 | Run the generator: 71 | 72 | ```shell 73 | stack run --cwd .. watch 74 | ``` 75 | 76 | ## Writing content 77 | 78 | All content can be found in `pages/`. 79 | You can find our [quick guide here](https://osdev.wiki/pages/writer_tutorial.html) 80 | to learn the basics (~2 min reading). 81 | -------------------------------------------------------------------------------- /adoc/adoctor_input_template.adoc: -------------------------------------------------------------------------------- 1 | = $title$ 2 | 3 | $body$ 4 | -------------------------------------------------------------------------------- /adoc/html5/embedded.html.erb: -------------------------------------------------------------------------------- 1 |
<%= converter.convert self, 'outline' %>
2 |
3 | <%= header.render() %> 4 | <%= content %> 5 | <% if self.footnotes? %> 6 |
7 |
8 | 15 | <% end %> 16 |
17 | -------------------------------------------------------------------------------- /categories.yml: -------------------------------------------------------------------------------- 1 | # KV pairs (Text -> Text) of category name to description mappings 2 | Assembly: Topics related to assembly and machine code, calling conventions, et cetera 3 | x86: x86-specific documentation 4 | Tutorial: Guides on how to do simple things, to get you off the ground with a given tool 5 | Bootloaders: Bootloaders and boot protocols 6 | Toolchain: LLVM, GCC, and others, and how to use them 7 | 8 | # Special pages 9 | Meta: Pages about wiki administration, editing, and processes 10 | -------------------------------------------------------------------------------- /css/layout.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2021 Arsen Arsenovic, CC0 */ 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | body, html { 8 | width: 100%; 9 | min-height: 100vh; 10 | margin: 0; 11 | padding: 0; 12 | } 13 | 14 | div#content { 15 | display: grid; 16 | grid-template-areas: 17 | "header" 18 | "sitemap" 19 | "toc" 20 | "content" 21 | "footer"; 22 | grid-template-rows: 23 | min-content 24 | min-content 25 | min-content 26 | 1fr 27 | min-content; 28 | grid-template-columns: auto; 29 | grid-gap: 10px; 30 | min-height: 100vh; 31 | } 32 | 33 | div#content > * { 34 | padding: 5px; 35 | } 36 | 37 | div#header { 38 | grid-area: header; 39 | } 40 | 41 | div#navbar { 42 | grid-area: sitemap; 43 | } 44 | 45 | div#navbar > ul { 46 | display: flex; 47 | width: 100%; 48 | flex-direction: row; 49 | justify-content: space-evenly; 50 | } 51 | 52 | div#toc { 53 | grid-area: toc; 54 | } 55 | 56 | a#forgebtn { 57 | display: block; 58 | height: 1em; 59 | } 60 | 61 | div#padding { 62 | display: none; 63 | grid-area: filler; 64 | } 65 | 66 | div#content > article { 67 | grid-area: content; 68 | max-width: 900px; 69 | justify-self: center; 70 | } 71 | 72 | div#content > footer { 73 | grid-area: footer; 74 | text-align: center; 75 | } 76 | 77 | a.listSlug { 78 | font-size: 1.4em; 79 | font-family: monospace; 80 | } 81 | 82 | ul.pageList > li { 83 | margin: 0.5em 0; 84 | } 85 | 86 | span#roothack { 87 | display: none; 88 | } 89 | 90 | dd, dt { 91 | --dd-margin: 1em; 92 | margin-top: var(--dd-margin); 93 | margin-bottom: var(--dd-margin); 94 | } 95 | 96 | svg#logo { 97 | max-height: 50px; 98 | margin: 0 auto; 99 | } 100 | 101 | @media only screen and (min-width: 768px) { 102 | div#content { 103 | display: grid; 104 | grid-template-columns: 250px auto; 105 | grid-template-areas: 106 | "header content" 107 | "sitemap content" 108 | "toc content" 109 | "filler content" 110 | "footer footer"; 111 | grid-gap: 10px; 112 | min-height: 100vh; 113 | } 114 | 115 | div#navbar > ul { 116 | display: block; 117 | flex-direction: row; 118 | justify-content: space-evenly; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /css/stork.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2021 Arsen Arsenovic, CC0 */ 2 | /* inspired by storks upstream styling but reimplemented */ 3 | :root { 4 | --stork-dialog-margins: 0.75em; 5 | } 6 | 7 | .stork-wrapper { 8 | box-sizing: border-box; 9 | 10 | display: none; /* hide without JS */ 11 | width: 100%; 12 | } 13 | 14 | .stork-wrapper > * { 15 | display: none; 16 | box-sizing: border-box; 17 | } 18 | 19 | .stork-wrapper > input { 20 | display: block; 21 | grid-row: 1; 22 | grid-column-start: 1; 23 | grid-column-end: 1; 24 | width: 100%; 25 | margin: 0; 26 | } 27 | 28 | /* display as overlay */ 29 | .stork-fullscreen { 30 | position: fixed; 31 | margin: 3%; 32 | top: 0; 33 | bottom: 0; 34 | left: 0; 35 | right: 0; 36 | box-sizing: border-box; 37 | max-width: 700px; 38 | max-height: min-content; 39 | margin: auto auto; 40 | z-index: 100; 41 | 42 | background-color: var(--background); 43 | grid-template-columns: 1fr min-content; 44 | grid-template-rows: min-content min-content 1fr; 45 | grid-template-areas: 46 | "input close" 47 | "progress progress" 48 | "results results"; 49 | } 50 | 51 | .stork-fullscreen > * { 52 | display: revert; 53 | } 54 | 55 | .stork-results { 56 | --shadow-size: 0.5em; 57 | --neg-shadow-size: calc(-1 * var(--shadow-size)); 58 | 59 | overflow-y: auto; 60 | max-height: 25em; 61 | border: var(--foreground) 1px solid; 62 | border-left: none; 63 | border-right: none; 64 | box-shadow: inset 0em var(--shadow-size) var(--shadow-size) var(--neg-shadow-size) var(--black0), 65 | inset 0em var(--neg-shadow-size) var(--shadow-size) var(--neg-shadow-size) var(--black0); 66 | padding: var(--shadow-size) 0; 67 | margin: 0; 68 | } 69 | 70 | .stork-close-button { 71 | grid-area: close; 72 | aspect-ratio: 1 / 1; 73 | margin-left: var(--stork-dialog-margins); 74 | } 75 | 76 | .stork-progress { 77 | grid-area: progress; 78 | } 79 | 80 | .stork-fullscreen > input { 81 | grid-area: input; 82 | } 83 | 84 | [data-stork="wiki-output"] { 85 | grid-area: results; 86 | } 87 | 88 | .stork-fullscreen > .stork-output-visible { 89 | display: flex; 90 | flex-direction: column; 91 | margin-top: var(--stork-dialog-margins); 92 | 93 | border: var(--foreground) 1px solid; 94 | border-radius: 5px; 95 | box-shadow: 5px var(--foreground); 96 | } 97 | 98 | .stork-result { 99 | margin: 0; 100 | padding: 0 1ch; 101 | } 102 | 103 | .stork-result a { 104 | display: block; 105 | color: currentcolor; 106 | } 107 | 108 | .stork-title { 109 | font-weight: bold; 110 | font-size: 1.2em; 111 | 112 | display: flex; 113 | justify-content: space-between; 114 | } 115 | 116 | .stork-excerpt { 117 | font-size: 0.9em; 118 | line-height: 1; 119 | margin: 0; 120 | 121 | display: flex; 122 | justify-content: space-between; 123 | } 124 | 125 | .stork-excerpt:not(:last-of-type) { 126 | margin-bottom: 0.6em; 127 | } 128 | 129 | .stork-result.selected { 130 | background-color: var(--background-active); 131 | } 132 | 133 | .stork-message { 134 | font-size: 1.5em; 135 | padding: 0.5em; 136 | } 137 | 138 | .stork-attribution { 139 | font-style: italic; 140 | font-size: 0.6em; 141 | padding: 1em 2ch; 142 | text-align: right; 143 | } 144 | 145 | div.stork-wrapper > input { 146 | background-color: var(--background-input); 147 | color: var(--foreground); 148 | } 149 | -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2021 Arsen Arsenovic, CC0 */ 2 | @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; 3 | 4 | :root { 5 | --white0: #ccc; 6 | --white1: #fefefe; 7 | --whitef: #fff; 8 | --black0: #111; 9 | --black1: #222; 10 | --black2: #181818; 11 | --blackf: #000; 12 | --blue0: #0645ad; 13 | --cyan0: hsl(210deg, 60%, 65%); 14 | --cyan1: hsl(210deg, 60%, 80%); 15 | --cyan2: hsl(210deg, 60%, 30%); 16 | 17 | --yellow0: hsl(45deg, 100%, 50%); 18 | --orange0: hsl(25deg, 100%, 50%); 19 | --blue0: hsl(250deg, 85%, 50%); 20 | --purple0: hsl(280deg, 85%, 50%); 21 | --red0: hsl(358deg, 85%, 50%); 22 | 23 | --foreground: var(--white0); 24 | --foreground-hc: var(--whitef); 25 | --background: var(--black0); 26 | --background-code: var(--black1); 27 | --background-active: var(--cyan2); 28 | --background-admonition: var(--black1); 29 | --background-input: var(--black1); 30 | --accent: var(--white1); 31 | --links: var(--cyan0); 32 | 33 | /* always dark */ 34 | --dark-foreground: var(--white0); 35 | --dark-background: var(--black2); 36 | --dark-links: var(--cyan0); 37 | } 38 | 39 | html, body { 40 | font-family: sans-serif; 41 | background-color: var(--background); 42 | color: var(--foreground); 43 | } 44 | 45 | @media(prefers-color-scheme: light) { 46 | :root { 47 | --foreground: var(--black0); 48 | --background: var(--white1); 49 | --foreground-hc: var(--blackf); 50 | --background-active: var(--cyan1); 51 | --background-admonition: var(--white0); 52 | --background-input: var(--white1); 53 | --accent: var(--black1); 54 | --links: var(--blue0); 55 | } 56 | } 57 | 58 | pre { 59 | margin: 0.5ch 1ch; 60 | } 61 | 62 | a { 63 | color: var(--links); 64 | text-decoration: none; 65 | } 66 | 67 | .listingblock { 68 | width: 100%; 69 | background-color: var(--background-code); 70 | border-radius: 0.3em; 71 | border: 1px var(--accent) solid; 72 | } 73 | 74 | .listingblock > .title { 75 | width: 100%; 76 | font-family: monospace; 77 | font-size: 0.9em; 78 | padding: 1px 1ch; 79 | background-color: var(--accent); 80 | color: var(--background); 81 | } 82 | .listingblock > .title::before { 83 | content: "$ edit "; 84 | text-decoration: italic; 85 | opacity: 50%; 86 | } 87 | 88 | .literalblock pre, 89 | .listingblock > .content > pre { 90 | overflow-x: auto; 91 | } 92 | 93 | .listingblock > .content { 94 | position: relative; 95 | } 96 | 97 | .listingblock { 98 | color: var(--dark-foreground); 99 | background-color: var(--dark-background); 100 | } 101 | 102 | .listingblock code[data-lang]::before { 103 | display: none; 104 | 105 | content: attr(data-lang); 106 | text-transform: uppercase; 107 | font-size: 0.75em; 108 | 109 | position: absolute; 110 | top: 0.4em; 111 | right: 0.4em; 112 | line-height: 1; 113 | opacity: 0.5; 114 | } 115 | 116 | .listingblock:hover code[data-lang]::before { 117 | display: block; 118 | } 119 | 120 | /* these specific ul shouldn't have bullets or padding */ 121 | #navbar ul, 122 | #toc ul { 123 | list-style: none; 124 | padding-left: 1ch; 125 | } 126 | 127 | a#forgebtn { 128 | color: var(--foreground); 129 | } 130 | 131 | div#navbar, div#toc:not(.intentionallyEmpty) { 132 | border-bottom: 2px solid var(--accent); 133 | } 134 | 135 | footer { 136 | background-color: var(--dark-background); 137 | color: var(--dark-foreground); 138 | font-size: 0.75rem; 139 | } 140 | 141 | footer > a { 142 | color: var(--dark-links); 143 | } 144 | 145 | /* admonitions */ 146 | 147 | .admonitionblock { 148 | margin: 1.4rem 0 0; 149 | background-color: var(--background-admonition); 150 | border-radius: 0.5em; 151 | } 152 | 153 | .admonitionblock > table { 154 | table-layout: fixed; 155 | position: relative; 156 | width: 100%; 157 | } 158 | 159 | .admonitionblock td.icon { 160 | position: absolute; 161 | top: 0; 162 | left: 0; 163 | transform: translate(-0.5rem,-50%); 164 | padding: 0.25em 0.25em; 165 | text-transform: uppercase; 166 | border-radius: 5px; 167 | 168 | background-color: var(--cyan0); 169 | color: var(--whitef); 170 | font-size: 0.9em; 171 | } 172 | 173 | .admonitionblock td.content { 174 | width: 100%; 175 | padding: 1rem 1rem 0.75rem 1rem; 176 | } 177 | 178 | .admonitionblock.warning td.icon { 179 | background-color: var(--yellow0); 180 | } 181 | 182 | .admonitionblock.caution td.icon { 183 | background-color: var(--orange0); 184 | } 185 | 186 | .admonitionblock.tip td.icon { 187 | background-color: var(--blue0); 188 | } 189 | 190 | .admonitionblock.note td.icon { 191 | background-color: var(--purple0); 192 | } 193 | 194 | .admonitionblock.important td.icon { 195 | background-color: var(--red0); 196 | } 197 | -------------------------------------------------------------------------------- /generator/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/haskell 2 | 3 | result 4 | 5 | ### Haskell ### 6 | dist 7 | cabal-dev 8 | *.o 9 | *.hi 10 | *.chi 11 | *.chs.h 12 | *.dyn_o 13 | *.dyn_hi 14 | .hpc 15 | .hsenv 16 | .cabal-sandbox/ 17 | cabal.sandbox.config 18 | *.prof 19 | *.aux 20 | *.hp 21 | .stack-work/ 22 | _cache/ 23 | _site/ 24 | -------------------------------------------------------------------------------- /generator/LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /generator/README.md: -------------------------------------------------------------------------------- 1 | # generator 2 | -------------------------------------------------------------------------------- /generator/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /generator/app/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE TypeApplications #-} 3 | import GHC.IO.Encoding (setLocaleEncoding, utf8) 4 | import Hakyll 5 | import System.Environment (lookupEnv) 6 | import Control.Applicative ((<|>)) 7 | import Data.Maybe (fromMaybe, maybeToList) 8 | import Data.Char (toLower) 9 | import Data.List (stripPrefix) 10 | import Data.Time.Clock (getCurrentTime, utctDay) 11 | import Data.Time.Calendar (toGregorian) 12 | import Data.Traversable (forM) 13 | import Data.Yaml (decodeFileEither, prettyPrintParseException) 14 | import qualified Data.HashMap.Strict as HM 15 | import qualified Data.Text as T 16 | import qualified Stork as S 17 | import System.Exit (die) 18 | 19 | type Categories = HM.HashMap T.Text T.Text 20 | 21 | adocTemplates :: String 22 | adocTemplates = "erb" 23 | 24 | asciidoctorOptions :: [String] 25 | asciidoctorOptions = 26 | [ "-s" -- standalone page 27 | , "-S", "secure" -- disable potentially dangerous features 28 | , "-a", "source-highlighter=pygments" -- use pygments 29 | , "-a", "toc" -- generate TOC 30 | , "-a", "source-linenums-option" -- generate line numbers 31 | , "-a", "sectnums" 32 | , "-a", "showtitle" 33 | 34 | , "-r", "asciidoctor-bibtex" 35 | , "-a", "bibtex-file=sources.bib" 36 | , "-a", "bibtex-throw=true" 37 | , "-a", "bibtex-style=apa" 38 | 39 | , "-a", "relfileprefix=/pages/" 40 | , "-a", "relfilesuffix=.html" -- correctly locate xref'd pages 41 | 42 | 43 | , "-T", "adoc", "-E", adocTemplates 44 | , "-" -- stdin/stdout 45 | ] 46 | 47 | itemCompiler :: Compiler (Item String) 48 | itemCompiler = do 49 | ext <- getUnderlyingExtension 50 | if ext == ".adoc" then 51 | getResourceBody 52 | >>= loadAndApplyTemplate adocInputTemplate defaultContext 53 | >>= withItemBody adoctor 54 | else 55 | pandocCompiler 56 | where adoctor = unixFilter "asciidoctor" asciidoctorOptions 57 | adocInputTemplate = "adoc/adoctor_input_template.adoc" 58 | 59 | noCategoryError :: String -> Compiler a 60 | noCategoryError x = fail $ "Category " ++ x ++ " does not exist." 61 | 62 | getMetadataCategory :: MonadMetadata m => Identifier -> m [String] 63 | getMetadataCategory x = do 64 | maybeCategory <- getMetadataField x "category" 65 | let catList = (:[]) <$> maybeCategory 66 | return $ fromMaybe [] catList 67 | 68 | pageCompiler :: Categories -> Compiler (Item String) 69 | pageCompiler cs = do 70 | identifier <- getUnderlying 71 | categoryName' <- getMetadataCategory @Compiler identifier 72 | categoryName <- case categoryName' of 73 | x:[] -> return x 74 | _ -> fail "Failed to get category from page (is it set?)" 75 | 76 | if ((T.pack categoryName) `HM.member` cs) then itemCompiler 77 | else noCategoryError categoryName 78 | 79 | categoryDescription :: Categories -> String -> Maybe String 80 | categoryDescription cats cat = T.unpack <$> HM.lookup catText cats 81 | where catText = T.pack cat 82 | 83 | 84 | removeField :: String -> Context String 85 | removeField n = field n (\_ -> noResult $ "Field '"++n++"' removed.") 86 | 87 | genericContext' :: String -> Integer -> Maybe String -> Context String 88 | genericContext' gitHash year forge = constField "year" (show year) 89 | <> forgeField 90 | <> constField "hash" gitHash 91 | <> field "description" (doDescriptionField "description") 92 | <> field "og-description" (doDescriptionField "og-description") 93 | <> defaultContext 94 | where doDescriptionField x _ = do 95 | ident <- getUnderlying 96 | descriptionMaybe <- getMetadataField ident "description" 97 | titleMaybe <- getMetadataField ident "title" 98 | case descriptionMaybe <|> titleMaybe of 99 | Nothing -> noResult $ "No description provided (for " ++ x ++ ")" 100 | Just d -> return d 101 | forgeField = fromMaybe (removeField "forge") 102 | (fmap (constField "forge") forge) 103 | 104 | stripIfPrefixed :: Eq a => [a] -> [a] -> [a] 105 | stripIfPrefixed p xs = fromMaybe xs $ stripPrefix p xs 106 | 107 | hakyllConfig :: Configuration 108 | hakyllConfig = defaultConfiguration 109 | { destinationDirectory = "_site" -- hard code default 110 | } 111 | 112 | main :: IO () 113 | main = do 114 | setLocaleEncoding utf8 115 | 116 | gitHash <- fromMaybe "main" <$> lookupEnv "GIT_HASH" 117 | wikiForge <- lookupEnv "WIKI_FORGE" 118 | (year, _, _) <- toGregorian <$> utctDay <$> getCurrentTime 119 | categoryFile' <- decodeFileEither @Categories "categories.yml" 120 | categories <- case categoryFile' of 121 | Left e -> die $ prettyPrintParseException e 122 | Right c -> return c 123 | 124 | hakyllWith hakyllConfig $ do 125 | let genericContext = let gc = genericContext' gitHash year wikiForge in 126 | openGraphField "opengraph" gc <> gc 127 | let pageContext path = constField "path" path <> genericContext 128 | let templatePath = fromGlob $ ("adoc/html5/*." ++ adocTemplates) 129 | adocTemplateDep <- makePatternDependency $ templatePath 130 | categoriesDep <- makePatternDependency "categories.yml" 131 | let adocExtraDeps = rulesExtraDependencies [ categoriesDep 132 | , adocTemplateDep 133 | ] 134 | 135 | -- null rule to load categories.yml into the cache 136 | -- the contents here don't matter since we don't use them 137 | -- TODO(arsen): load the category set out of hakyll rather than on 138 | -- startup to prevent it going out of date when using 139 | -- watch 140 | match "categories.yml" $ compile $ makeItem () 141 | 142 | match "html/*" $ compile templateCompiler 143 | match "adoc/*.adoc" $ compile templateCompiler 144 | 145 | match "css/*" $ compile compressCssCompiler 146 | match "static/*" $ do 147 | route $ customRoute (\i -> "_/" ++ (toFilePath i)) 148 | compile $ copyFileCompiler 149 | 150 | create ["css/pygments.css"] $ 151 | compile $ 152 | unixFilter "pygmentize" [ "-S", "gruvbox-dark" 153 | , "-f", "html" 154 | , "-O", "classprefix=tok-" 155 | ] "" >>= makeItem 156 | 157 | create ["_/stylesheet.css"] $ do 158 | route idRoute 159 | compile $ do 160 | sheets <- loadAll "css/*" 161 | makeItem $ unlines $ map itemBody sheets 162 | 163 | match "licenses/*" $ do 164 | route idRoute 165 | compile $ copyFileCompiler 166 | 167 | let pageHandler compiler = do 168 | route $ setExtension "html" 169 | compile $ do 170 | path' <- getResourceFilePath 171 | let path = stripIfPrefixed "./" path' 172 | let ctx = pageContext path 173 | getResourceBody 174 | >>= saveSnapshot "source" -- needed for indexes 175 | >> compiler 176 | >>= loadAndApplyTemplate "html/wrapper.html" ctx 177 | >>= relativizeUrls 178 | 179 | adocExtraDeps $ match "pages/*.adoc" $ pageHandler $ pageCompiler categories 180 | adocExtraDeps $ match "index.adoc" $ pageHandler $ itemCompiler 181 | 182 | -- index pages with stork 183 | create ["searchidx.st"] $ do 184 | route idRoute 185 | compile $ loadAll "pages/*" 186 | >>= (S.render $ destinationDirectory hakyllConfig) 187 | 188 | tags <- buildTags "pages/*" (fromCapture "tags/*.html") 189 | cats <- let fromLowCapture pat x = fromCapture pat (map toLower x) in 190 | buildTagsWith getMetadataCategory "pages/*" 191 | (fromLowCapture "categories/*.html") 192 | 193 | let tagIdxPage = \titlePfx fdesc tag pattern -> do 194 | route idRoute 195 | let title = concat [titlePfx," \"",tag,"\""] 196 | let descriptionMaybe = constField "tagDescription" <$> fdesc tag 197 | compile $ do 198 | pages <- loadAllSnapshots pattern "source" 199 | let idxContext = mconcat $ 200 | [ constField "title" title 201 | , constField "description" title 202 | , listField "pages" genericContext $ return pages 203 | , removeField "forge" 204 | , genericContext 205 | ] ++ (maybeToList $ descriptionMaybe) 206 | makeItem "" 207 | >>= loadAndApplyTemplate "html/tag_index.html" idxContext 208 | >>= loadAndApplyTemplate "html/wrapper.html" idxContext 209 | >>= relativizeUrls 210 | 211 | tagsRules tags $ tagIdxPage "Pages tagged with" (const Nothing) 212 | tagsRules cats $ tagIdxPage "Pages categorized under" $ 213 | categoryDescription categories 214 | 215 | -- TODO(arsen): provide better context for templates to use 216 | let renderTagPage = \title tagList -> do 217 | route idRoute 218 | compile $ do 219 | let listContext = mconcat 220 | [ constField "title" title 221 | , constField "description" title 222 | , tagsField "tags" tagList 223 | , removeField "forge" 224 | , genericContext 225 | ] 226 | renderredList <- renderTagList tagList 227 | makeItem renderredList 228 | >>= loadAndApplyTemplate "html/tag_list.html" listContext 229 | >>= loadAndApplyTemplate "html/wrapper.html" listContext 230 | >>= relativizeUrls 231 | 232 | create ["tags/index.html"] $ renderTagPage "Global tag list" tags 233 | create ["categories/index.html"] $ renderTagPage "Global category list" cats 234 | 235 | let errorPageIdentifier = fromFilePath . (++".html") . show 236 | forM [(404 :: Int, "Not Found")] $ 237 | \(code', msg) -> create [errorPageIdentifier code'] $ do 238 | let code = show code' 239 | route idRoute 240 | let title = code ++ " " ++ msg 241 | let errorContext = mconcat 242 | [ constField "title" title 243 | , constField "description" title 244 | , constField "error" code 245 | , constField "errormsg" msg 246 | , removeField "forge" 247 | , genericContext 248 | ] 249 | compile $ makeItem "" 250 | >>= loadAndApplyTemplate "html/error_page.html" errorContext 251 | >>= loadAndApplyTemplate "html/wrapper.html" errorContext 252 | >>= relativizeUrls 253 | -------------------------------------------------------------------------------- /generator/app/Stork.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE TypeApplications #-} 3 | 4 | module Stork where 5 | -- intentionally nongeneric, reuse with care 6 | 7 | import Data.Aeson.Types 8 | import qualified Data.Aeson as A 9 | import qualified Data.Text as T 10 | import Data.Text (Text) 11 | import qualified Data.Text.Encoding as E 12 | import qualified Data.ByteString.Lazy as LBS 13 | import qualified Hakyll as H 14 | 15 | data File = File 16 | { fileTitle :: Text 17 | , fileUrl :: Text 18 | , filePath :: Text 19 | , fileFileType :: Text 20 | } 21 | 22 | instance ToJSON File where 23 | toJSON (File title url path ftype) = 24 | object [ "title" .= title 25 | , "url" .= url 26 | , "path" .= path 27 | , "filetype" .= ftype 28 | ] 29 | 30 | data Output = Output 31 | { outputSaveNearestId :: Bool 32 | } 33 | 34 | instance ToJSON Output where 35 | toJSON (Output saveNearestId) = 36 | object [ "save_nearest_html_id" .= saveNearestId ] 37 | 38 | data Input = Input 39 | { inputFiles :: [File] 40 | , inputUrlPrefix :: Text 41 | , inputBaseDirectory :: Text 42 | , inputHtmlSelector :: Text 43 | } 44 | 45 | instance ToJSON Input where 46 | toJSON (Input files prefix basedir selector) = 47 | object [ "files" .= files 48 | , "url_prefix" .= prefix 49 | , "base_directory" .= basedir 50 | , "html_selector" .= selector 51 | ] 52 | 53 | data IndexerConfig = IndexerConfig 54 | { indexerInput :: Input 55 | , indexerOutput :: Output 56 | } 57 | 58 | instance ToJSON IndexerConfig where 59 | toJSON (IndexerConfig input output) = 60 | object [ "input" .= input 61 | , "output" .= output 62 | ] 63 | 64 | itemToFile :: H.Item String -> H.Compiler File 65 | itemToFile i = do 66 | let identifier = H.itemIdentifier i 67 | title <- H.getMetadataField' identifier "title" 68 | routeMaybe <- H.getRoute identifier 69 | route <- case routeMaybe of 70 | Nothing -> fail $ "No route for " ++ (show identifier) 71 | Just x -> return x 72 | 73 | return $ File 74 | { fileTitle = T.pack title 75 | , fileUrl = T.pack route 76 | , filePath = T.pack route 77 | , fileFileType = "HTML" 78 | } 79 | 80 | encodeToLazyUtf8 :: Text -> LBS.ByteString 81 | encodeToLazyUtf8 = LBS.fromChunks . return . E.encodeUtf8 82 | 83 | render :: String -> [H.Item String] -> H.Compiler (H.Item LBS.ByteString) 84 | render outPath is = do 85 | files <- sequenceA $ map itemToFile is 86 | let input = Input 87 | { inputFiles = files 88 | , inputUrlPrefix = "/" 89 | , inputBaseDirectory = T.pack $ outPath ++ "/" 90 | , inputHtmlSelector = "#content > article" 91 | } 92 | let output = Output 93 | { outputSaveNearestId = False 94 | } 95 | let json = A.encode $ IndexerConfig input output 96 | 97 | storkDb <- H.unixFilterLBS storkCmd' storkArgs json 98 | H.makeItem storkDb 99 | where storkCmd = ["stork", "build", "--input", "-", "--output", "/dev/stdout"] 100 | (storkCmd':storkArgs) = storkCmd 101 | -------------------------------------------------------------------------------- /generator/default.nix: -------------------------------------------------------------------------------- 1 | { staticCross ? false }: 2 | let 3 | # Read in the Niv sources 4 | sources = import ./nix/sources.nix {}; 5 | # If ./nix/sources.nix file is not found run: 6 | # niv init 7 | # niv add input-output-hk/haskell.nix -n haskellNix 8 | 9 | # Fetch the haskell.nix commit we have pinned with Niv 10 | haskellNix = import sources.haskellNix {}; 11 | # If haskellNix is not found run: 12 | # niv add input-output-hk/haskell.nix -n haskellNix 13 | 14 | # Import nixpkgs and pass the haskell.nix provided nixpkgsArgs 15 | nixpkgs = import 16 | # haskell.nix provides access to the nixpkgs pins which are used by our CI, 17 | # hence you will be more likely to get cache hits when using these. 18 | # But you can also just use your own, e.g. ''. 19 | haskellNix.sources.nixpkgs-unstable 20 | # These arguments passed to nixpkgs, include some patches and also 21 | # the haskell.nix functionality itself as an overlay. 22 | haskellNix.nixpkgsArgs; 23 | 24 | pkgs = if staticCross then nixpkgs.pkgsCross.musl64 else nixpkgs; 25 | 26 | project = pkgs.haskell-nix.project { 27 | # 'cleanGit' cleans a source directory based on the files known by git 28 | src = pkgs.haskell-nix.haskellLib.cleanSourceWith { 29 | src = pkgs.haskell-nix.haskellLib.cleanGit { 30 | name = "osdev-wiki"; 31 | src = ../.; 32 | }; 33 | subDir = "generator"; 34 | }; 35 | }; 36 | in project.generator.components.exes.generator 37 | 38 | # vim: sw=2 et : 39 | -------------------------------------------------------------------------------- /generator/generator.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.4. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: generator 8 | version: 0.1.0.0 9 | synopsis: Static site generator for https://osdev.wiki based on Hakyll 10 | category: Web 11 | license: PublicDomain 12 | license-file: LICENSE 13 | build-type: Simple 14 | 15 | executable generator 16 | main-is: Main.hs 17 | other-modules: 18 | Stork 19 | Paths_generator 20 | hs-source-dirs: 21 | app 22 | ghc-options: -Wall 23 | build-depends: 24 | aeson 25 | , base >=4.7 && <5 26 | , bytestring 27 | , hakyll 28 | , pandoc 29 | , text 30 | , time 31 | , unordered-containers 32 | , yaml 33 | default-language: Haskell2010 34 | -------------------------------------------------------------------------------- /generator/nix/sources.json: -------------------------------------------------------------------------------- 1 | { 2 | "haskellNix": { 3 | "branch": "master", 4 | "description": "Alternative Haskell Infrastructure for Nixpkgs", 5 | "homepage": "https://input-output-hk.github.io/haskell.nix", 6 | "owner": "input-output-hk", 7 | "repo": "haskell.nix", 8 | "rev": "84532e8105cd845a56e06a3ea5e5c31135b7049d", 9 | "sha256": "07lbafxzz7mp1i1wfmvyj2nv0221bwsj0b73k1d6i4h793ls2v7f", 10 | "type": "tarball", 11 | "url": "https://github.com/input-output-hk/haskell.nix/archive/84532e8105cd845a56e06a3ea5e5c31135b7049d.tar.gz", 12 | "url_template": "https://github.com///archive/.tar.gz" 13 | }, 14 | "niv": { 15 | "branch": "master", 16 | "description": "Easy dependency management for Nix projects", 17 | "homepage": "https://github.com/nmattia/niv", 18 | "owner": "nmattia", 19 | "repo": "niv", 20 | "rev": "9cb7ef336bb71fd1ca84fc7f2dff15ef4b033f2a", 21 | "sha256": "1ajyqr8zka1zlb25jx1v4xys3zqmdy3prbm1vxlid6ah27a8qnzh", 22 | "type": "tarball", 23 | "url": "https://github.com/nmattia/niv/archive/9cb7ef336bb71fd1ca84fc7f2dff15ef4b033f2a.tar.gz", 24 | "url_template": "https://github.com///archive/.tar.gz" 25 | }, 26 | "nixpkgs": { 27 | "branch": "release-20.03", 28 | "description": "Nix Packages collection", 29 | "homepage": "", 30 | "owner": "NixOS", 31 | "repo": "nixpkgs", 32 | "rev": "eb73405ecceb1dc505b7cbbd234f8f94165e2696", 33 | "sha256": "06k21wbyhhvq2f1xczszh3c2934p0m02by3l2ixvd6nkwrqklax7", 34 | "type": "tarball", 35 | "url": "https://github.com/NixOS/nixpkgs/archive/eb73405ecceb1dc505b7cbbd234f8f94165e2696.tar.gz", 36 | "url_template": "https://github.com///archive/.tar.gz" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /generator/nix/sources.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by Niv. 2 | 3 | let 4 | 5 | # 6 | # The fetchers. fetch_ fetches specs of type . 7 | # 8 | 9 | fetch_file = pkgs: name: spec: 10 | let 11 | name' = sanitizeName name + "-src"; 12 | in 13 | if spec.builtin or true then 14 | builtins_fetchurl { inherit (spec) url sha256; name = name'; } 15 | else 16 | pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; 17 | 18 | fetch_tarball = pkgs: name: spec: 19 | let 20 | name' = sanitizeName name + "-src"; 21 | in 22 | if spec.builtin or true then 23 | builtins_fetchTarball { name = name'; inherit (spec) url sha256; } 24 | else 25 | pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; 26 | 27 | fetch_git = name: spec: 28 | let 29 | ref = 30 | if spec ? ref then spec.ref else 31 | if spec ? branch then "refs/heads/${spec.branch}" else 32 | if spec ? tag then "refs/tags/${spec.tag}" else 33 | abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; 34 | in 35 | builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; 36 | 37 | fetch_local = spec: spec.path; 38 | 39 | fetch_builtin-tarball = name: throw 40 | ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. 41 | $ niv modify ${name} -a type=tarball -a builtin=true''; 42 | 43 | fetch_builtin-url = name: throw 44 | ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. 45 | $ niv modify ${name} -a type=file -a builtin=true''; 46 | 47 | # 48 | # Various helpers 49 | # 50 | 51 | # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 52 | sanitizeName = name: 53 | ( 54 | concatMapStrings (s: if builtins.isList s then "-" else s) 55 | ( 56 | builtins.split "[^[:alnum:]+._?=-]+" 57 | ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) 58 | ) 59 | ); 60 | 61 | # The set of packages used when specs are fetched using non-builtins. 62 | mkPkgs = sources: system: 63 | let 64 | sourcesNixpkgs = 65 | import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; 66 | hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; 67 | hasThisAsNixpkgsPath = == ./.; 68 | in 69 | if builtins.hasAttr "nixpkgs" sources 70 | then sourcesNixpkgs 71 | else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then 72 | import {} 73 | else 74 | abort 75 | '' 76 | Please specify either (through -I or NIX_PATH=nixpkgs=...) or 77 | add a package called "nixpkgs" to your sources.json. 78 | ''; 79 | 80 | # The actual fetching function. 81 | fetch = pkgs: name: spec: 82 | 83 | if ! builtins.hasAttr "type" spec then 84 | abort "ERROR: niv spec ${name} does not have a 'type' attribute" 85 | else if spec.type == "file" then fetch_file pkgs name spec 86 | else if spec.type == "tarball" then fetch_tarball pkgs name spec 87 | else if spec.type == "git" then fetch_git name spec 88 | else if spec.type == "local" then fetch_local spec 89 | else if spec.type == "builtin-tarball" then fetch_builtin-tarball name 90 | else if spec.type == "builtin-url" then fetch_builtin-url name 91 | else 92 | abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; 93 | 94 | # If the environment variable NIV_OVERRIDE_${name} is set, then use 95 | # the path directly as opposed to the fetched source. 96 | replace = name: drv: 97 | let 98 | saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; 99 | ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; 100 | in 101 | if ersatz == "" then drv else 102 | # this turns the string into an actual Nix path (for both absolute and 103 | # relative paths) 104 | if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; 105 | 106 | # Ports of functions for older nix versions 107 | 108 | # a Nix version of mapAttrs if the built-in doesn't exist 109 | mapAttrs = builtins.mapAttrs or ( 110 | f: set: with builtins; 111 | listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) 112 | ); 113 | 114 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 115 | range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); 116 | 117 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 118 | stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); 119 | 120 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 121 | stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); 122 | concatMapStrings = f: list: concatStrings (map f list); 123 | concatStrings = builtins.concatStringsSep ""; 124 | 125 | # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 126 | optionalAttrs = cond: as: if cond then as else {}; 127 | 128 | # fetchTarball version that is compatible between all the versions of Nix 129 | builtins_fetchTarball = { url, name ? null, sha256 }@attrs: 130 | let 131 | inherit (builtins) lessThan nixVersion fetchTarball; 132 | in 133 | if lessThan nixVersion "1.12" then 134 | fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) 135 | else 136 | fetchTarball attrs; 137 | 138 | # fetchurl version that is compatible between all the versions of Nix 139 | builtins_fetchurl = { url, name ? null, sha256 }@attrs: 140 | let 141 | inherit (builtins) lessThan nixVersion fetchurl; 142 | in 143 | if lessThan nixVersion "1.12" then 144 | fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) 145 | else 146 | fetchurl attrs; 147 | 148 | # Create the final "sources" from the config 149 | mkSources = config: 150 | mapAttrs ( 151 | name: spec: 152 | if builtins.hasAttr "outPath" spec 153 | then abort 154 | "The values in sources.json should not have an 'outPath' attribute" 155 | else 156 | spec // { outPath = replace name (fetch config.pkgs name spec); } 157 | ) config.sources; 158 | 159 | # The "config" used by the fetchers 160 | mkConfig = 161 | { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null 162 | , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) 163 | , system ? builtins.currentSystem 164 | , pkgs ? mkPkgs sources system 165 | }: rec { 166 | # The sources, i.e. the attribute set of spec name to spec 167 | inherit sources; 168 | 169 | # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers 170 | inherit pkgs; 171 | }; 172 | 173 | in 174 | mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } 175 | -------------------------------------------------------------------------------- /generator/package.yaml: -------------------------------------------------------------------------------- 1 | name: generator 2 | version: 0.1.0.0 3 | synopsis: Static site generator for https://osdev.wiki based on Hakyll 4 | category: Web 5 | license: PublicDomain 6 | license-file: LICENSE 7 | ghc-options: -Wall 8 | 9 | dependencies: 10 | - base >= 4.7 && < 5 11 | - hakyll 12 | - pandoc 13 | - time 14 | - yaml 15 | - text 16 | - unordered-containers 17 | - bytestring 18 | - aeson 19 | 20 | executable: 21 | main: Main.hs 22 | source-dirs: app 23 | -------------------------------------------------------------------------------- /generator/stack.yaml: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by 'stack init' 2 | # 3 | # Some commonly used options have been documented as comments in this file. 4 | # For advanced use and comprehensive documentation of the format, please see: 5 | # https://docs.haskellstack.org/en/stable/yaml_configuration/ 6 | 7 | # Resolver to choose a 'specific' stackage snapshot or a compiler version. 8 | # A snapshot resolver dictates the compiler version and the set of packages 9 | # to be used for project dependencies. For example: 10 | # 11 | # resolver: lts-3.5 12 | # resolver: nightly-2015-09-21 13 | # resolver: ghc-7.10.2 14 | # 15 | # The location of a snapshot can be provided as a file or url. Stack assumes 16 | # a snapshot provided as a file might change, whereas a url resource does not. 17 | # 18 | # resolver: ./custom-snapshot.yaml 19 | # resolver: https://example.com/snapshots/2018-01-01.yaml 20 | resolver: nightly-2022-02-12 21 | 22 | # User packages to be built. 23 | # Various formats can be used as shown in the example below. 24 | # 25 | # packages: 26 | # - some-directory 27 | # - https://example.com/foo/bar/baz-0.0.2.tar.gz 28 | # subdirs: 29 | # - auto-update 30 | # - wai 31 | packages: 32 | - . 33 | # Dependency packages to be pulled from upstream that are not in the resolver. 34 | # These entries can reference officially published versions as well as 35 | # forks / in-progress versions pinned to a git hash. For example: 36 | # 37 | # extra-deps: [] 38 | 39 | # Override default flag values for local packages and extra-deps 40 | # flags: {} 41 | 42 | # Extra package databases containing global packages 43 | # extra-package-dbs: [] 44 | 45 | # Control whether we use the GHC we find on the path 46 | # system-ghc: true 47 | # 48 | # Require a specific version of stack, using version ranges 49 | # require-stack-version: -any # Default 50 | # require-stack-version: ">=2.7" 51 | # 52 | # Override the architecture used by stack, especially useful on Windows 53 | # arch: i386 54 | # arch: x86_64 55 | # 56 | # Extra directories used by stack for building 57 | # extra-include-dirs: [/path/to/dir] 58 | # extra-lib-dirs: [/path/to/dir] 59 | # 60 | # Allow a newer minor version of GHC than the snapshot specifies 61 | # compiler-check: newer-minor 62 | -------------------------------------------------------------------------------- /generator/stack.yaml.lock: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by Stack. 2 | # You should not edit this file by hand. 3 | # For more information, please see the documentation at: 4 | # https://docs.haskellstack.org/en/stable/lock_files 5 | 6 | packages: [] 7 | snapshots: 8 | - completed: 9 | size: 604770 10 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2022/2/12.yaml 11 | sha256: a91681fc48fadce5dc56dc2d37070116bc0765459b2cc70226242b778a27ab89 12 | original: nightly-2022-02-12 13 | -------------------------------------------------------------------------------- /html/error_page.html: -------------------------------------------------------------------------------- 1 |
2 |

You've hit an error!

3 |

$error$ - $errormsg$

4 | The page you were attempting to visit does not exist. 5 | If you believe this is an error, please contact us. 6 | In the meanwhile, you can find links to other pages on the 7 | main page. 8 |
9 | -------------------------------------------------------------------------------- /html/navbar.html: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | 12 |
13 |
14 | 15 | -------------------------------------------------------------------------------- /html/tag_index.html: -------------------------------------------------------------------------------- 1 |
2 |

$title$

3 | $if(tagDescription)$ 4 | $tagDescription$ 5 | $endif$ 6 |
    7 | $for(pages)$ 8 |
  • 9 | $title$ 10 |
    11 | $description$ 12 |
  • 13 | $endfor$ 14 |
15 |
16 | -------------------------------------------------------------------------------- /html/tag_list.html: -------------------------------------------------------------------------------- 1 |
2 |

$title$

3 | $body$ 4 |
5 | -------------------------------------------------------------------------------- /html/wrapper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | $title$ - osdev.wiki 9 | $if(opengraph)$$opengraph$$endif$ 10 | 11 | 12 | 13 | 14 | 15 |
16 | 19 | 20 |
21 | $body$ 22 |
23 | © 2021 osdev.wiki contributors. 24 | All contents released under the Creative Commons Zero license. 25 | Search provided by 26 | Stork under the 27 | Apache-2.0 license. 28 | $if(forge)$$if(path)$ 29 | Source code. 30 | $else$ 31 | Source code. 32 | $endif$ 33 | $endif$ 34 |
35 |
36 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /index.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Main page 3 | description: The place to start for operating system development in the 2020s. 4 | --- 5 | 6 | Welcome to *osdev.wiki*! 7 | 8 | The goal of this wiki is to create a decentralized repository of accurate and 9 | up-to-date information on operating system development. 10 | This site is currently *WIP* and very incomplete, thus contributions are 11 | welcome! 12 | 13 | [IMPORTANT] 14 | This wiki is not endorsed by, does not have any connection to, and 15 | is not related in any way with another wiki found at 16 | https://wiki.osdev.org[wiki.osdev.org]. 17 | 18 | == Contributing 19 | Before contributing to this wiki, you should read following pages: 20 | 21 | * xref:writer_tutorial.adoc[Writing a document], for a quick tutorial on how to 22 | write pages for this wiki. 23 | 24 | * xref:guidelines.adoc[Style guidelines], for rules on article structure, 25 | vocabulary, commit messages and much more. 26 | 27 | [IMPORTANT] 28 | By submitting a contribution to this wiki, you irrevocably agree to release 29 | your contribution under the link:/licenses/CC0.txt[CC0 license] and certify 30 | that you have the right to do so. 31 | 32 | == Quick Access 33 | === Tutorials 34 | * xref:stivale_barebones.adoc[Stivale C bare bones] 35 | * xref:cross_clang.adoc[Cross compiling using Clang] 36 | 37 | === Toolchain 38 | * xref:visual_studio.adoc[Visual Studio] 39 | * xref:calling_conventions.adoc[Calling conventions] 40 | 41 | === Hardware 42 | * xref:x86.adoc[x86] 43 | 44 | === Learning 45 | * xref:fundamentals.adoc[Computer science fundamentals] 46 | 47 | === Bootloaders 48 | * xref:stivale.adoc[Stivale] 49 | 50 | == Todo 51 | * Welcome to the modern era 52 | * Stivale C# bare bones 53 | * LLVM + Clang 54 | -------------------------------------------------------------------------------- /licenses/CC0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /pages/.stivale_cs_barebones.adoc: -------------------------------------------------------------------------------- 1 | = Stivale CSharp Barebones 2 | :description: Tutorial on writing a minimal kernel using C# and the limine bootloader. 3 | 4 | == Introduction 5 | 6 | === What is stivale? 7 | 8 | include::partial$stivale.adoc[] 9 | 10 | === What is Limine? 11 | 12 | [Limine](https://wiki.osdev.org/Limine) is a modern, advanced x86 bootloader for [BIOS](https://wiki.osdev.org/BIOS) and [UEFI](https://wiki.osdev.org/UEFI), with support for cutting edge features such as 5-level paging, 64-bit [Long Mode](https://wiki.osdev.org/Long_Mode), and direct higher half loading thanks to the [stivale](https://github.com/stivale/stivale) boot protocol. [Limine GitHub repository](https://github.com/limine-bootloader/limine) 13 | 14 | == Getting started 15 | 16 | NOTE: It is recommended to check out this [repository](https://github.com/ilobilo/stivale2-cs-barebones) for buildable code. 17 | 18 | === Install required packages 19 | 20 | To compile and run the kernel you will need following programs 21 | installed: 22 | 23 | - [Dotnet](https://docs.microsoft.com/en-us/dotnet/core/install/linux) 24 | (C\# compiler) should be installed in /usr/share/dotnet/ 25 | - Tysila2 (Debian package included in repository) 26 | - [Mono](https://www.mono-project.com) (To run tysila2) 27 | - Make (To run everything) 28 | - Nasm (Assembly compiler) 29 | - ld.lld (Linker) 30 | - Xorriso (To build the iso) 31 | - Qemu-system-x86 (To run the OS) 32 | 33 | If you are using debian based system you can install most of them with 34 | these commands: 35 | 36 | `sudo apt install nasm ld.lld xorriso qemu-system-x86 mono-runtime`\ 37 | `// First download tysila2.deb from project's repository`\ 38 | `sudo dpkg -i tysila2.deb` 39 | 40 | ### Actual code 41 | 42 | First of all you need to create following files and directories: 43 | 44 | `├── limine.cfg`\ 45 | `├── Makefile`\ 46 | `└── source`\ 47 |        `├── Console.cs`\ 48 |        `|── kernel.asm`\ 49 |        `├── kernel.cs`\ 50 |        `├── linker.ld`\ 51 |        `├── Makefile`\ 52 |        `└── stivale2.cs` 53 | 54 | #### Limine configuration file 55 | 56 | This is [Limine](https://wiki.osdev.org/Limine) configuration file which tells 57 | bootloader what to do: 58 | 59 | 60 | limine.cfg 61 | ```ini 62 | # Kernel entry name in bootloader menu 63 | :Stivale2 64 | # Boot protocol to use 65 | PROTOCOL=stivale2 66 | # Kernel elf file path on iso 67 | KERNEL_PATH=boot:///kernel.elf 68 | # Disable KASLR 69 | KASLR=no 70 | ``` 71 | 72 | #### Makefile 73 | 74 | These are simple makefile that will be excecuted when you run make 75 | command: 76 | 77 | Note: Make sure to use tabs instead of 8 spaces 78 | 79 | Makefile: 80 | 81 | ```makefile 82 | KERNELDIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 83 | 84 | all: limine 85 | mkdir -p $(KERNELDIR)/iso_root 86 | $(MAKE) -s -C $(KERNELDIR)/source 87 | 88 | limine: 89 | git clone https://github.com/limine-bootloader/limine.git --single-branch --branch=latest-binary --depth=1 90 | $(MAKE) -C $(KERNELDIR)/limine 91 | 92 | clean: 93 | $(MAKE) -s -C $(KERNELDIR)/source clean 94 | 95 | distclean: 96 | $(MAKE) -s -C $(KERNELDIR)/source clean 97 | rm -rf $(KERNELDIR)/limine 98 | rm -rf $(KERNELDIR)/iso_root 99 | ``` 100 | 101 | source/Makefile: 102 | 103 | ```makefile 104 | SOURCEDIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 105 | 106 | KERNEL := $(SOURCEDIR)/kernel.elf 107 | KERNELEXE := $(KERNEL:.elf=.exe) 108 | KERNELO := $(KERNEL:.elf=.o) 109 | ISO = $(SOURCEDIR)/../image.iso 110 | 111 | LIMINE = $(SOURCEDIR)/../limine/limine-install 112 | 113 | QEMU = qemu-system-x86_64 114 | QEMUFLAGS = -enable-kvm -M q35 -cpu max -smp 2 -m 512M -boot d -rtc base=localtime -serial stdio 115 | 116 | XORRISO = xorriso 117 | XORRISOFLAGS = -as mkisofs -b limine-cd.bin \ 118 | -no-emul-boot -boot-load-size 4 -boot-info-table \ 119 | --efi-boot limine-eltorito-efi.bin -efi-boot-part \ 120 | --efi-boot-image --protective-msdos-label 121 | 122 | LD = ld.lld 123 | AS = nasm 124 | AOT = tysila2 125 | DOTNET = /usr/share/dotnet/dotnet 126 | CSC = /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll 127 | 128 | ASMFLAGS = -f elf64 129 | AOTFLAGS = --arch x86_64-elf64-tysos -fno-rtti -fno-exceptions 130 | CSCFLAGS = -unsafe -target:exe -platform:x86 -nostdlib /r:/usr/share/tysila2/mscorlib.dll 131 | 132 | LDFLAGS = -T $(SOURCEDIR)/linker.ld -m elf_x86_64 -z max-page-size=0x1000 133 | 134 | CSFILES = $(shell find $(SOURCEDIR)/ -type f -name '*.cs') 135 | ASMFILES = $(shell find $(SOURCEDIR)/ -type f -name '*.asm') 136 | OBJ = $(ASMFILES:.asm=_asm.o) 137 | 138 | .PHONY: all 139 | all: $(KERNEL) 140 | $(MAKE) iso 141 | $(MAKE) clean run 142 | 143 | $(KERNEL): $(OBJ) 144 | $(DOTNET) $(CSC) $(CSCFLAGS) $(CSFILES) -out:$(KERNELEXE) 145 | $(AOT) $(AOTFLAGS) $(KERNELEXE) -o $(KERNELO) 146 | $(LD) $(LDFLAGS) $(INTERNALLDFLAGS) $(OBJ) $(KERNELO) -o $@ 147 | 148 | %_asm.o: %.asm 149 | $(AS) $(ASMFLAGS) $^ -o $@ 150 | 151 | iso: 152 | cp $(KERNEL) $(SOURCEDIR)/../limine.cfg $(SOURCEDIR)/../limine/limine.sys \ 153 | $(SOURCEDIR)/../limine/limine-cd.bin $(SOURCEDIR)/../limine/limine-eltorito-efi.bin $(SOURCEDIR)/../iso_root/ 154 | $(XORRISO) $(XORRISOFLAGS) $(SOURCEDIR)/../iso_root -o $(ISO) 155 | $(LIMINE) $(ISO) 156 | 157 | clean: 158 | rm -rf $(KERNEL) $(OBJ) $(KERNELEXE) $(KERNELO) $(SOURCEDIR)/../iso_root/* 159 | 160 | run: 161 | $(QEMU) $(QEMUFLAGS) -cdrom $(ISO) 162 | ``` 163 | 164 | #### Linker script 165 | 166 | Script that ld.lld will use to link relocatable elf objects 167 | 168 | source/linker.ld 169 | 170 | ``` 171 | OUTPUT_FORMAT(elf64-x86-64) 172 | OUTPUT_ARCH(i386:x86-64) 173 | 174 | ENTRY(_start) 175 | 176 | PHDRS 177 | { 178 | null PT_NULL FLAGS(0) ; 179 | text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; 180 | rodata PT_LOAD FLAGS((1 << 2)) ; 181 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; 182 | dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ; 183 | } 184 | 185 | SECTIONS 186 | { 187 | . = 0xffffffff80200000; 188 | 189 | .text : { 190 | *(.text*) 191 | } :text 192 | 193 | . += 0x1000; 194 | 195 | .stivale2hdr : { 196 | KEEP(*(.stivale2hdr)) 197 | } :rodata 198 | 199 | .rodata : { 200 | *(.rodata*) 201 | } :rodata 202 | 203 | . += 0x1000; 204 | 205 | .data : { 206 | *(.data*) 207 | } :data 208 | 209 | .dynamic : { 210 | *(.dynamic) 211 | } :data :dynamic 212 | 213 | .bss : { 214 | *(COMMON) 215 | *(.bss*) 216 | } :data 217 | } 218 | ``` 219 | 220 | #### Kernel 221 | 222 | These files contain code that will be executed when kernel runs: 223 | 224 | source/kernel.asm 225 | 226 | ```as 227 | global sthrow 228 | 229 | ; C# entry point 230 | extern _ZN6kernel6Kernel7ProgramM_0_8RealMain_Rv_P1PV26stivale2#2Bstivale2_struct 231 | 232 | section .data 233 | 234 | stivale2_smp_tag: 235 | dq 0x1ab015085f3273df 236 | dq 0 237 | dq 0 238 | 239 | ; Framebuffer 240 | stivale2_framebuffer_tag: 241 | dq 0x3ecc1bc43d0f7971 242 | dq stivale2_smp_tag 243 | dw 0 244 | dw 0 245 | dw 32 246 | 247 | ; Text mode 248 | stivale2_any_video_tag: 249 | dq 0xc75c9fa92a44c4db 250 | dq stivale2_smp_tag 251 | dq 1 252 | 253 | ; Kernel stack 254 | section .bss 255 | align 16 256 | stack_bottom: 257 | resb 8192 258 | stack_top: 259 | 260 | ; Stivale2 header 261 | section .stivale2hdr 262 | align 4 263 | stivale_hdr: 264 | dq kmain 265 | dq stack_top 266 | dq (1 << 1) 267 | ; Replace this with "stivale2_framebuffer_tag" to enable framebuffer 268 | dq stivale2_any_video_tag 269 | 270 | section .text 271 | kmain: 272 | push rdi 273 | call _ZN6kernel6Kernel7ProgramM_0_8RealMain_Rv_P1PV26stivale2#2Bstivale2_struct 274 | 275 | sthrow: 276 | hlt 277 | jmp sthrow 278 | ``` 279 | 280 | source/kernel.cs 281 | 282 | ```csharp 283 | namespace Kernel 284 | { 285 | // Class is unsafe so we can use pointers 286 | public unsafe class Program 287 | { 288 | // Fake kernel entry point 289 | // Do not remove 290 | public static void Main() 291 | { 292 | // These lines of code are required 293 | // Without them compiler will remove RealMain from kernel 294 | stivale2.stivale2_struct* test = null; 295 | RealMain(test); 296 | } 297 | 298 | public static stivale2.stivale2_struct_tag_smp *smp_tag; 299 | 300 | // Real entry 301 | public static void RealMain(stivale2.stivale2_struct* stiv) 302 | { 303 | // If Stivale2 struct was not found halt 304 | if (stiv == null) while (true); 305 | 306 | // Example on how to get Stivale2 structure tags 307 | smp_tag = (stivale2.stivale2_struct_tag_smp*)stivale2.get_tag(stiv, stivale2.STIVALE2_STRUCT_TAG_SMP_ID); 308 | 309 | // Print text 310 | Console.WriteLine("Hello, World!"); 311 | 312 | // Halt 313 | while (true); 314 | } 315 | } 316 | } 317 | ``` 318 | 319 | #### Console 320 | 321 | This is an example code that provides console write and writeline 322 | functions: source/Console.cs 323 | 324 | ```csharp 325 | namespace Kernel 326 | { 327 | // Console colours 328 | public enum ConsoleColour 329 | { 330 | Black, 331 | Blue, 332 | Green, 333 | Cyan, 334 | Red, 335 | Purple, 336 | Brown, 337 | Grey, 338 | DarkGrey, 339 | LightBlue, 340 | LightGreen, 341 | LightCyan, 342 | LightRed, 343 | LightPurple, 344 | Yellow, 345 | White, 346 | }; 347 | public unsafe static class Console 348 | { 349 | // VGA text mode address 350 | public static ushort* vga = (ushort*)0xB8000; 351 | // Cursor positions 352 | public static int x = 0, y = 0, lastx = 0; 353 | // Text colours 354 | public static ConsoleColour ForegroundColour = ConsoleColour.White; 355 | public static ConsoleColour BackgroundColour = ConsoleColour.Black; 356 | 357 | public static void Write(string s) 358 | { 359 | foreach(char c in s) 360 | { 361 | PutChar(c, BackgroundColour, ForegroundColour); 362 | } 363 | } 364 | 365 | public static void WriteLine(string s) 366 | { 367 | foreach(char c in s) 368 | { 369 | PutChar(c, BackgroundColour, ForegroundColour); 370 | } 371 | PutChar('\n', BackgroundColour, ForegroundColour); 372 | } 373 | 374 | static void PutChar(char c, ConsoleColour bgcolour, ConsoleColour fgcolour) 375 | { 376 | switch (c) 377 | { 378 | // Newline 379 | case '\n': 380 | lastx = x; 381 | x = 0; 382 | y++; 383 | break; 384 | // Backspace 385 | case '\b': 386 | if (x > 0) 387 | { 388 | x--; 389 | vga[y * 80 + x] = (ushort)(((byte)bgcolour << 12) | ((byte)fgcolour << 8) | ' '); 390 | } 391 | else 392 | { 393 | x = lastx; 394 | y--; 395 | } 396 | break; 397 | // Everything else 398 | default: 399 | vga[y * 80 + x] = (ushort)(((byte)bgcolour << 12) | ((byte)fgcolour << 8) | c); 400 | if (x < 80) x++; 401 | else 402 | { 403 | lastx = x; 404 | x = 0; 405 | y++; 406 | } 407 | break; 408 | } 409 | } 410 | } 411 | } 412 | ``` 413 | 414 | #### Stivale2.cs 415 | 416 | [download](https://github.com/ilobilo/stivale2-cs-barebones/blob/main/source/stivale2.cs) 417 | it and place under source/ 418 | 419 | ### Building and running the kernel 420 | 421 | To compile and run the kernel go to main directory (Where limine.cfg, 422 | Makefile and source/ are) and run: 423 | 424 | `make -j$(nproc --all)` 425 | 426 | See Also 427 | -------- 428 | 429 | - [Stivale2 430 | Specification](https://github.com/stivale/stivale/blob/master/STIVALE2.md) 431 | - [Limine bootloader](https://github.com/limine-bootloader/limine) 432 | - [Project github 433 | repository](https://github.com/ilobilo/stivale2-cs-barebones/) 434 | -------------------------------------------------------------------------------- /pages/calling_conventions.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Calling conventions 3 | tags: assembly, x86, x64, sysv, msvc 4 | category: Assembly 5 | description: Examples of calling conventions on common platforms. 6 | --- 7 | :source-language: c 8 | 9 | A *calling convention* is the set of contracts that compiler-generated machine 10 | code respects and expects external functions to respect. 11 | Among other things, the calling convention specifies: 12 | 13 | - how parameters are passed to functions; 14 | - how the stack is handled and cleaned (for example if needs to be aligned at 15 | function entry); 16 | - how structures are going to be laid out in memory; 17 | - which registers need to be restored by the caller and which by the callee. 18 | 19 | == x86-64 calling conventions 20 | The Windows (including UEFI) world and the UNIX (Linux, macOS, BSDs) world have 21 | adopted two different conventions. 22 | Note that MSVC can only generate code using the Windows calling convention. 23 | 24 | === Microsoft x64 25 | The x64 Application Binary Interfacefootnote:[https://github.com/MicrosoftDocs/cpp-docs/blob/main/docs/build/x64-calling-convention.md] 26 | (ABI) uses a four-register fast-call calling convention by default. 27 | Space is allocated on the call stack as a shadow store for callees to save 28 | those registers. 29 | 30 | There is a strict one-to-one correspondence between a function call's arguments 31 | and the registers used for those arguments. 32 | Any argument that does not fit in 8 bytes, or is not 1, 2, 4, or 8 bytes, must 33 | be passed by reference. 34 | A single argument is never spread across multiple registers. 35 | 36 | The x87 register stack is unused. 37 | It may be used by the callee, but is considered volatile across function calls. 38 | All floating point operations are done using the 16 XMM registers. 39 | 40 | Integer arguments are passed in registers RCX, RDX, R8, and R9; floating point 41 | arguments are passed in XMM0L, XMM1L, XMM2L, and XMM3L. 42 | 16-byte arguments are passed by reference. 43 | Parameter passing is described in detail in the parameter section. 44 | These registers, and RAX, R10, R11, XMM4, and XMM5, are considered volatile. 45 | 46 | ==== Register allocation 47 | [cols="1,1"] 48 | |=== 49 | 50 | | Caller saved 51 | | RAX, RCX, RDX, R8, R9, R10, R11 52 | 53 | | Callee saved 54 | | RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 55 | |=== 56 | 57 | ==== Stack 58 | The stack is always 16-byte aligned at _function entry_: this requires the 59 | stack to be aligned to 8 bytes, but _not_ 16 bytes, before the `CALL`, since 60 | the instruction pushes 8 bytes on the stack. 61 | 62 | All functions need to have 32 bytes of home space (also known as spill space or 63 | shadow space), which is allocated _before_ pushing the other parameters on the 64 | stack. 65 | This allows for an easier implementation of variadic functions: `va_start` can 66 | just put the four register parameters in the home space, so that `va_arg` simply 67 | becomes a lookup starting at RSP. 68 | 69 | For example, if the caller calls a function with 4 or 5 arguments, it needs to 70 | allocate 40 bytes of stack in order for the stack at the callee entry to be 48 71 | bytes below the caller's stack. 72 | 73 | ==== Parameters 74 | `RCX`/`XMM0`, `RDX`/`XMM1`, `R8`/`XMM2`, `R9`/`XMM3`, stack (`[RSP+0x20]`, 75 | `[RSP+0x28]` and so on, 0x20 is due to the home space). 76 | 77 | For example, a function with the prototype 78 | 79 | [source,c] 80 | ---- 81 | void do_something(int a, float b, int c, int d, int e, float f); 82 | ---- 83 | 84 | would pass parameters in RCX, XMM1, R8, R9, [RSP+0x20] and [RSP+0x28] 85 | respectively. 86 | A function calling this needs to have at least 56 bytes of stack to store the 87 | parameters and home space and ensure that the stack is aligned after the `CALL`. 88 | 89 | ==== Return value 90 | If the return value is an integer, struct, or union whose size is less than or 91 | equal to 64 bits, it is returned in RAX; otherwise, the struct is allocated by 92 | the caller, and a pointer to it is passed as the first parameter. 93 | 94 | [source,c] 95 | --- 96 | // large_struct_t is larger than 64 bits, this: 97 | large_struct_t do_something(int a) 98 | // effectively becomes this: 99 | void do_something(large_struct_t *ret, int a) 100 | --- 101 | 102 | === System V 103 | The standard calling sequence requirementsfootnote:[https://raw.githubusercontent.com/wiki/hjl-tools/x86-psABI/x86-64-psABI-1.0.pdf] 104 | apply only to global functions. 105 | Local functions that are not reachable from other compilation units may use 106 | different conventions. 107 | Nevertheless, it is recommended that all functions use the standard calling 108 | sequence when possible. 109 | 110 | The CPU shall be in x87 mode upon entry to a function. 111 | Therefore, every function that uses the MMX registers is required to issue an 112 | EMMS or FEMMS instruction after using MMX registers, before returning or calling 113 | another function. 114 | 115 | The direction flag DF in the RFLAGS register must be clear (set to "forward" 116 | direction) on function entry and return. 117 | Other user flags have no specified role in the standard calling sequence and are 118 | not preserved across calls. 119 | 120 | Registers RBP, RBX and R12 through R15 "belong" to the calling function and the 121 | called function is required to preserve their values. 122 | In other words, a called function must preserve these registers’ values for its 123 | caller. 124 | Remaining registers "belong" to the called function. 125 | 126 | ==== Register allocation 127 | [cols="1,1"] 128 | |=== 129 | 130 | | Caller saved 131 | | RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11 132 | 133 | | Callee saved 134 | | RBX, RBP, RSP, R12, R13, R14, R15 135 | |=== 136 | 137 | ==== Stack 138 | The stack is always 16-byte aligned at function _call_: this requires the 139 | stack to be aligned to 16 bytes before the `CALL`. 140 | The push of the return address onto the stack by `CALL` is immediately succeeded 141 | by the push of RBP onto the stack by the callee function, thereby re-aligning 142 | the stack shortly after function entry. 143 | 144 | ==== Parameters 145 | `RDI`, `RSI`, `RDX`, `RCX`, `R8`, `R9`, stack (`[RSP+0x00]`, `[RSP+0x08]` and so 146 | on). 147 | 148 | If the parameter is of type `float` or `double`, it will be stored in the next 149 | available SSE register (`XMM0`-`XMM7`). 150 | 151 | For example, a function with the prototype 152 | `void do_something(int a, float b, int c, int d, int e, float f)` would pass 153 | parameters in `RDI`, `XMM0`, `R8`, `R9`, `[RSP+0x00]` and `XMM1` respectively. 154 | A function calling this needs to have at least 32 bytes of stack to store the 155 | parameters and align the stack upon call. 156 | 157 | ==== Return value 158 | If the return value is an integer, struct, or union whose size is less than or 159 | equal than 64 bits, it is returned in `RAX`; otherwise, the struct is allocated 160 | by the caller and a pointer to it is passed as the first parameter, like the 161 | Microsoft x64 ABI. 162 | Unlike the Microsoft ABI, the pointer is actually returned in `RAX` upon return. 163 | 164 | [source,c] 165 | --- 166 | // large_struct_t is larger than 64 bits, this: 167 | large_struct_t do_something(int a) 168 | // effectively becomes this: 169 | void do_something(large_struct_t *ret, int a) 170 | --- 171 | -------------------------------------------------------------------------------- /pages/cross_clang.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Clang cross compiler 3 | tags: compiler, clang, tutorial 4 | category: Tutorial 5 | description: Tutorial on how to setup cross compilation for OS development using Clang. 6 | --- 7 | 8 | A https://en.wikipedia.org/wiki/Cross_compiler[*cross compiler*] is a compiler 9 | generates a code for a different platform (the **target**) than platform it 10 | runs on (the **host**). 11 | The platforms may differ in CPU architecture, library environment, 12 | xref:calling_conventions.adoc[ABI], and executable format. 13 | For operating system development, the host is our development system, and the 14 | target is the developed OS. 15 | It is important to realize that these two platforms are not the same: the 16 | developed OS will always differ from the development OS. 17 | Thus it is necessary to use a cross compiler to avoid various troubles down the 18 | road. 19 | 20 | == Why is cross-compilation necessary? 21 | Unless development is being done on the OS being developed, a cross compiler is 22 | necessary. 23 | The compiler must know the correct target platform, otherwise there will be 24 | issues, if not now then later. 25 | If the system compiler is used, it will not know that it is not targeting the 26 | host OS: it compiles something else entirely. 27 | Some tutorials suggest using the system compiler, and passing it several 28 | options to tell it that it is not targetting the host. 29 | This is not sustainable in the long run and the real solution is to use a 30 | cross-compiler. 31 | 32 | == What is Clang? 33 | As an operating system developer in the 2020s, newer technologies have been 34 | developed that not only simplify the development process, but are of higher 35 | quality and are more powerful than what was used before. 36 | One of these technologies is https://llvm.org[LLVM]. 37 | Most osdev guides instruct the developer to use GCC. 38 | Using LLVM and Clang makes the life of an OS developer easier at the beginning, 39 | because unlike GCC, this compiler was designed to cross-compile from the very 40 | beginning, and thus it is not neccessary to build an entire toolchain from 41 | scratch for each desired target platform. 42 | It is also the native compiler on BSD and Mac OS X systems. 43 | The error messages are more accurate and informational. 44 | The main drawbacks is that when adding support for your custom platform is 45 | slower, as LLVM is much larger and slower to compile. 46 | GCC also compiles code faster. 47 | Ultimately, the compiler you use does not matter too much. 48 | 49 | == Targets 50 | Cross compilation is done using a target triplet, which conveys information to 51 | the compiler about the platform that is being compiled to. 52 | 53 | == Start 54 | Install Clang on the host system. 55 | It is the standard compiler on BSD-like systems, and virtually all Linux 56 | distributions have Clang packaged in their software repositories. 57 | There is an installer for Windows. 58 | 59 | === Linux 60 | Install Clang through the distribution package manager: 61 | 62 | * Ubuntu-based: `# apt install clang` 63 | * Arch-based: `# pacman -S clang` 64 | * Fedora: `# dnf install clang` 65 | * Gentoo: `# emerge -a clang` 66 | - Be sure to enable the target architecture(s) in the LLVM_TARGETS variable 67 | in /etc/portage/make.conf 68 | * Alpine: `# apk add clang` 69 | * Others: It is highly unlikely the distribution does not provide Clang 70 | packaged. 71 | Search the repositories. 72 | 73 | In the case that Clang isn't packaged, it can be built from source. 74 | 75 | === Windows 76 | If xref:visual_studio.adoc[Visual Studio] with the "Desktop Development with 77 | C++" toolset is installed, Clang can be installed as an individual component 78 | through the Visual Studio Installer. 79 | See https://docs.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-170[Clang/LLVM support in Visual Studio]. 80 | 81 | If Visual Studio is not desired or installed, the latest release of Clang can 82 | be installed from the 83 | https://github.com/llvm/llvm-project/releases[LLVM GitHub release page]. 84 | 85 | // TODO: Windows 86 | 87 | === *BSD 88 | Clang is the default compiler for OpenBSD, NetBSD and FreeBSD, so it should be 89 | pre-installed. 90 | 91 | === macOS 92 | The built-in apple Clang comes crippled: it only ships with x86_64 and arm64 93 | support (but still supports ELF). 94 | It is recommended to get Clang from https://brew.sh[Homebrew], as the LLVM 95 | linker (lld) is needed to get anything meaningful done either way. 96 | It is also worth noting that proper cross-compilation GCC tools are also in the 97 | Homebrew repositories (under the names x86_64-elf-binutils and x86_64-elf-gcc). 98 | 99 | // == Enabling cross-compilation 100 | // TODO 101 | -------------------------------------------------------------------------------- /pages/editorial_rules.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Editorial process 3 | tags: meta 4 | category: Meta 5 | description: Wiki governance 6 | --- 7 | Contributions are submitted via pull requests on GitHub. 8 | A pull request is reviewed by someone who is a member of the "osdev-wiki" 9 | organization ("reviewers") and that therefore has the permission to merge it. 10 | Reviewers must make sure that following things hold before merging a pull 11 | request: 12 | 13 | . The pull request complies with the content guidelines. 14 | In particular, the reviewer must make sure that the commit messages are 15 | compliant. 16 | In addition, the reviewer must check the contribution for plagiarism. 17 | 18 | . The contribution is within the scope of the wiki. 19 | In particular, reviewers may make discretionary decisions on whether a 20 | contribution is accepted or rejected. 21 | 22 | . The contribution was not submitted or authored, in part or in whole, by the 23 | reviewer reviewing the contribution. 24 | 25 | Multiple reviewers may review the same pull request. 26 | Diagreements between reviewers may be mediated or resolved by another member of 27 | the "osdev-wiki" organization who is uninvolved in the dispute. 28 | If no such mediation is possible, the dispute is resolved through general 29 | consensus among the members of the "osdev-wiki" organization. 30 | If there is no conseus, the _status quo_ remains. 31 | -------------------------------------------------------------------------------- /pages/fundamentals.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Computer science fundamentals 3 | tags: tutorial, theory 4 | category: Tutorial 5 | description: Some guidance on learning fundamentals of computer science 6 | --- 7 | 8 | The internet has many freely available resources for learning computer science 9 | fundamentals. 10 | This is a list of those resources, that are most useful for OS development. 11 | 12 | == Open Source Society University 13 | The OSSU has a https://github.com/ossu/computer-science[complete CS curriculum] 14 | of currated online materials. 15 | 16 | Following prerequisites are recommended to make sure there is some familiarity 17 | with the material. 18 | They can be skimmed quickly if the material seems basic. 19 | 20 | === Strongly recommended 21 | These subjects are very relevant to OS development. 22 | 23 | * Core programming 24 | ** all 25 | * Core math 26 | ** Mathematics for Computer Science 27 | * CS Tools 28 | ** all 29 | * Core systems 30 | ** all 31 | * Core theory 32 | ** Divide and Conquer, Sorting and Searching, and Randomized Algorithms 33 | ** Graph Search, Shortest Paths, and Data Structures 34 | * Advanced programming 35 | ** Software Debugging 36 | 37 | === Highly recommended 38 | These teach you details of how the underlying hardware works. 39 | 40 | * Advanced systems 41 | ** all 42 | 43 | == MIT OpenCourseWare 44 | https://ocw.mit.edu/[MIT OpenCourseWare] publishes free courses from MIT online, 45 | many with lectures. 46 | 47 | * https://ocw.mit.edu/courses/find-by-topic/#cat=engineering&subcat=computerscience[All 48 | computer science courses] 49 | * https://ocw.mit.edu/courses/mit-curriculum-guide/#map[Interactive map of 50 | prerequisites for each class] 51 | -------------------------------------------------------------------------------- /pages/guidelines.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Style guidelines 3 | tags: meta 4 | category: Meta 5 | description: An overview of wiki tone, source code style, and more 6 | --- 7 | 8 | == Content guide 9 | . The style guide will always leave some leeway, since there is no single best 10 | way of doing something, but the overall style should be consistent _within_ 11 | an article and may be different _across_ articles. 12 | This also means one should keep the current style when expanding an article. 13 | An article's style should only be changed when there is good reason to. 14 | + 15 | NOTE: Inconsistent styling within an article might cause confusion to the 16 | reader, however imposing one arbitrary decision across the entire wiki 17 | will be cumbersome and will be of limited use. 18 | In addition, different topics may require different treatment. 19 | 20 | . An article should be structured as follows: 21 | 22 | * Warning templates 23 | + 24 | NOTE: This is the first thing any reader should see. 25 | 26 | * Lead section (a short, self-contained overview of the topic) 27 | + 28 | NOTE: A reader should be able to get a quick overview of the topic without 29 | reading a long text. 30 | A person encountering the article should be able to assess quickly, if 31 | they are interested in reading it further or not. 32 | The lead section is also the part displayed in search engines and social 33 | media embeds. 34 | 35 | * Main matter 36 | 37 | * See also (internal links to tangentially related topics that might be of 38 | interest to the reader, in order to facilitate navigation) 39 | + 40 | NOTE: The reader will be able to easily find articles they want to read next. 41 | 42 | * Further reading (external links, books, etc ..., such as tutorials, 43 | references, and documentation, that might be of interest to someone writing 44 | an OS) 45 | + 46 | NOTE: The wiki cannot and should not cover everything, it serves as a starting 47 | point for further research. 48 | 49 | * References (list of inline citations that appear as footnotes throughout the 50 | article) 51 | 52 | . American English spelling and terminology used in technical literature should 53 | be used when writing articles. 54 | However, terms that are widely used across all English-speaking countries 55 | should be preferred over terms used exclusively in the US. 56 | + 57 | NOTE: Most technical literature is written in American English. 58 | 59 | . An article should be logically divided into sections and subsections. 60 | + 61 | NOTE: It facilitates navigation of long articles. 62 | Sections may appear in search engine results. 63 | 64 | * Article and section titles should be written in sentence case (first letter 65 | of first word capitalized) and should not contain redundant "the" or "a". 66 | This means "BIOS", not "The BIOS". 67 | Exception: proper names. 68 | 69 | * A subsection title should not redundantly contain the title of its parent 70 | section. 71 | + 72 | NOTE: Do not repeat yourself. 73 | 74 | * Avoid markup in article and section titles. 75 | + 76 | NOTE: They appear in cross-references, tables of contents and search engine 77 | results. 78 | Use of certain markup may cause unforeseen problems. 79 | 80 | . Every claim in an article should be sourced, preferably using inline 81 | footnotes. 82 | Primary sources (official documentation, references or specifications) should 83 | be preferred over secondary ones, unless primary sources are not available or 84 | have errors. 85 | + 86 | NOTE: The reader should be able to easily verify the correctness of content. 87 | Factual errors and hearsay should also be avoided. 88 | 89 | * Claims in the lead section must not have an inline citation, if they appear 90 | in the main matter. 91 | + 92 | NOTE: Do not repeat yourself. 93 | 94 | . Articles should have a neutral point of view. 95 | They should not prefer a certain solution over another one, when the 96 | alternative is also widely used (avoid holy wars). 97 | However, arguments for and against a solution may be presented in an 98 | objective and sourced way. 99 | 100 | * If opinions must be included, they must be quoted from a source. 101 | + 102 | NOTE: The wiki is not a place for holy wars. 103 | Different people have different opinions and there is no objective way to 104 | settle all disputes. 105 | 106 | * Modern methods and solutions should be emphasized over obsolete ones. 107 | This does not mean that older technologies are not covered. 108 | However, the reader must always be aware of legacy. 109 | + 110 | NOTE: This wiki should focus on modern OS development. 111 | 112 | . If the title of an article is mentioned in another article, the first mention 113 | of that title should be linked. 114 | + 115 | NOTE: Navigation in any wiki lives from internal links. 116 | However, articles should not be cluttered with internal links. 117 | 118 | * If a link to an article exists in the lead section, another link may exist in 119 | the main matter. 120 | 121 | * An article may be linked more than once within a long article, but not more 122 | than once within the same section. 123 | + 124 | NOTE: The one link guideline should not get in the way of navigability. 125 | 126 | . Code examples should be small self-contained snippets of code (as a rule of 127 | thumb, not larger than a screen). 128 | Articles should not be written as step-by-step tutorials. 129 | + 130 | NOTE: OS development requires a certain level of skill. 131 | This includes being able to implement code based on a specification. 132 | Providing large and complete code examples gives novice programmers the 133 | incentive to simply copy and paste them, without fully understanding them. 134 | OS development is not a linear process and there are a lot of choices that have 135 | to be made. 136 | Tutorials cannot cover the broadness of OS development. 137 | Large code examples are also harder to test and maintain. 138 | Buggy code should not be in the wiki. 139 | 140 | * Code examples should be written in C. 141 | However, they must not be completely valid source files. 142 | For example, functions may be used that are not declared anywhere in the code 143 | snippet. 144 | Snippets should be vague and generic and should have pseudocode-like 145 | qualities. 146 | + 147 | NOTE: C is the _lingua franca_ of programming languages and _the_ generic 148 | programming language. 149 | It is known by most programmers. 150 | In addition, it is a simple language that does not contain a lot of 151 | features that some programmers might not know. 152 | 153 | * An exception to the C rule is low level code that must be written in 154 | assembly. 155 | Assembly is architecture-specific and therefore should be used only on 156 | architecture-specific pages or sections. 157 | When it comes to x86 assembly, the most convenient syntax (Intel or AT&T) in 158 | the relevant context should be used. 159 | 160 | . Articles should be written in proper English with encyclopedic tone. 161 | A list of common things to look out for is provided. 162 | No rationale is provided, since these are common rules of English and are 163 | essentially linguistic conventions. 164 | 165 | * General rules, grammar, tone and vocabulary 166 | 167 | ** Avoid repeating yourself. 168 | Avoid redundant phrases in sentences. 169 | Avoid long run-on sentences. 170 | For example, "OS development requires a certain level of skill" is preferred 171 | over "OS development requires the programmer to have a certain level of 172 | general skill". 173 | 174 | ** Articles should be written in encyclopedic tone, this includes _never_ using 175 | the first or second person ("I", "me", "you"), unless quoting. 176 | 177 | ** "The" should never be capitalized mid-sentence, unless it is part of a 178 | proper name. 179 | 180 | ** Plural forms of nouns are formed by using -s or -es, not -'s. 181 | 182 | ** Possessive forms of nouns are formed by using -'s. 183 | + 184 | IMPORTANT: "It" is not a noun, but a personal pronoun. 185 | The corresponding possessive pronoun is "its", not "it's". 186 | 187 | ** Use the present tense by default. 188 | 189 | ** Avoid contractions like "can't" or "don't". 190 | 191 | ** Avoid language like "note", "remember" or "obviously", which either address 192 | the reader directly or makes presumptions about the reader's knowledge. 193 | 194 | ** Use gender-neutral language, avoid the use of "he" or "she". 195 | 196 | ** Abbreviations may be used in article or section titles, if they are used 197 | more commonly than the full expression (for example "BIOS" instead of "Basic 198 | Input/Output System"). 199 | 200 | ** The first occurrence of an abbreviation must be written out, with the 201 | abbreviation following in parentheses: "Basic Input/Output System (BIOS)". 202 | 203 | ** Abbreviations may or may not include full stops, however no spaces may exist 204 | within the abbreviation ("B.I.O.S." is allowed, but "B. I. O. S." is not). 205 | However their use must be consistent and must follow conventions set in 206 | technical literature (use "BIOS", not "B.I.O.S."). 207 | 208 | * Punctuation and symbols 209 | 210 | ** Do not use ampersands (&), use "and", unless quoting or part of a proper 211 | name like "AT&T". 212 | 213 | ** Use boldface to highlight an important term being introduced (such as the 214 | first occurrence of the article title), but do not use it more than once for 215 | the same term. 216 | For emphasis and foreign words, use italics. 217 | Do not italicize or boldface nearby punctuation. 218 | 219 | ** When quoting a source, the source must be mentioned _in the text_, in 220 | addition to having a footnote as reference. 221 | 222 | ** Straight quotes (") and apostrophes (') should be used (no curly quotes or 223 | apostrophes, no backticks, no low-high quotes, no guillemet). 224 | 225 | ** Nested quotes should use alternating quotes and apostrophes. 226 | 227 | ** Quotations should change the original text only minimally, any omitted, 228 | added, or changed words should be enclosed in square brackets. 229 | 230 | ** A comma before a quotation can be omitted, if the sentence is still 231 | grammatically correct and if the meaning of the quote is not changed. 232 | 233 | ** Punctuation may be included inside a quotation, if it makes logical sense 234 | and the punctuation is present in the original text. 235 | If isolated fragments of a sentence are quoted, nearby punctuation should 236 | usually be outside of the quote. 237 | 238 | ** An ellipsis consists of three dot characters (...) without spaces. 239 | They should be used when content is omitted from quotes. 240 | Square brackets may be placed around them to indicate that they are not part 241 | of the original quote. 242 | 243 | ** The main text may include side notes or clarifications in parentheses. 244 | However, the text around the parentheses must still make grammatical and 245 | logical sense without the content inside the parentheses. 246 | 247 | ** Nested parentheses should be avoided. 248 | Adjacent set of parentheses should also be avoided, the phrases should be 249 | joined by a comma. 250 | This means "the BIOS (a type of firmware) (replaced by UEFI)" is not 251 | allowed, and should be replaced by "the BIOS (a type of interface, replaced 252 | by UEFI)". 253 | 254 | ** Semicolons may be used to join two phrases that could stand as independent 255 | sentences: "stivale2 can load a kernel in long mode; multiboot cannot". 256 | Phrases that cannot stand alone may not be joined with a semicolon. 257 | 258 | ** Hyphens should be used to link prefixes ("quasi-multipliers") and compound 259 | modifiers ("well-known"). 260 | 261 | ** Dashes may be used to punctuate a sentence, in order to indicate that the 262 | two surrounding phrases indicate a pair. 263 | They should be used sparingly. 264 | 265 | ** _Never_ put a space before punctuation. 266 | 267 | * Dates and numbers 268 | 269 | ** Months and days of week are upper case, while seasons are lower case 270 | ("Monday", "July", "summer"). 271 | 272 | ** Either use 12-hour ("2:45 pm" or "2:45 p.m.") or 24-hour dates ("14:45"). 273 | Avoid "12 am" and "12 pm", when using the 12-hour format. 274 | Rather, use "noon" or "midnight". 275 | The latter is ambiguous, so specify whether it is the beginning or the end 276 | of the day. 277 | The 24-hour format has no such ambiguity "0:00" is the beginning of the day 278 | and "24:00" the end. 279 | 280 | ** Dates are either written as "19 December 2021" or "December 19, 2021". 281 | Numerical dates may be written in the yyyy-mm-dd format: "2021-12-19". 282 | 283 | ** When omitting the year write either "19 December" or "December 19". 284 | 285 | ** When referring to months, use "December 2021". 286 | You may use abbreviations like "Dec", if the space is limited. 287 | 288 | ** Avoid "#", use "No.", "Nos." or "number". 289 | 290 | * List items should be formatted consistently and follow a certain "schema", 291 | such as being all complete sentences, sentence fragments or names. 292 | Mixing of different types of items should not occur. 293 | 294 | . It is important to note that these are guidelines. 295 | They apply in the vast majority of cases, but there may be some rare 296 | exceptions. 297 | Exceptions should be introduced with care and with a good rationale. 298 | + 299 | NOTE: Not every edge case can be reasonably covered. 300 | 301 | == AsciiDoc and source code style 302 | As much as we strive for clean content, we should strive for clean source code. 303 | The following guidelines will help ensure future contributors and/or editors of 304 | the wiki have no problems making changes. 305 | 306 | === AsciiDoc formatting guidelines 307 | For an AsciiDoc reference, please see the 308 | https://docs.asciidoctor.org/asciidoc/latest/syntax-quick-reference/[AsciiDoc 309 | Syntax Quick reference] as well as the more broad 310 | https://docs.asciidoctor.org/asciidoc/latest/[AsciiDoc Language Documentation]. 311 | 312 | A useful tool for formatting your AsciiDoc is 313 | https://www.nicemice.net/par/[`par`], although, as it is not specific to 314 | AsciiDoc, it will break formatting elements. 315 | Use sparingly and explicitly, on ranges of text. 316 | 317 | Full stops are line breaks:: 318 | AsciiDoc does not care about line breaks, only paragraph breaks. 319 | By breaking lines on full stops, we minimize the chance of inducing conflicts 320 | with future contributors to the same page, but different parts. 321 | `par` violates this rule, so it is best to reformat a paragraph, break on 322 | full stops, and then rejoin lines to fit. 323 | + 324 | [source,asciidoc] 325 | ---- 326 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor 327 | incididunt ut labore et dolore magna aliqua. 328 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut 329 | aliquip ex ea commodo consequat. 330 | ---- 331 | 332 | Long lines should be broken:: 333 | Long lines in the source code are hard to read. 334 | If your AsciiDoc sources include lines longer than 100 columns (including 335 | leading whitespace, for simplicity sake), hard wrap them. 336 | Many text editors can do this out of the box for you. 337 | 338 | Links to other bits of AsciiDoc should be ``xref``s:: 339 | https://docs.asciidoctor.org/asciidoc/latest/macros/xref/[`xref`] macros 340 | should be used to connect contents on the wiki. 341 | For this reason, please be careful when removing sections or IDs, at least 342 | until stronger verification is introduced. 343 | 344 | Referenced sections should always have explicit IDs:: 345 | For the sake of preventing issues induced by cross references, and for the 346 | sake of clarity, all cross references must be made to explicit anchors. 347 | + 348 | [source,asciidoc] 349 | ---- 350 | See <>. 351 | 352 | [#section_1] 353 | == Section 1 354 | ---- 355 | 356 | Leave comments for further editors:: 357 | AsciiDoc supports comments. 358 | When something is not immediately obvious, or when something is left out, add 359 | a comment attributed to yourself. 360 | These should be in the format of `// TYPE(author): text`. 361 | `TYPE` should be `TODO`, `XXX`, `FIXME`, `NOTE`, etc. 362 | Please note that comments also tend to go stale, so their overuse is strongly 363 | discouraged. 364 | + 365 | [source,asciidoc] 366 | ---- 367 | // TODO(arsen): add xref validation 368 | 369 | //// 370 | NOTE(steve): This paragraph is quite noteworthy! 371 | I should talk about it in more detail. 372 | //// 373 | ---- 374 | 375 | Align text elements, use 2-space indent:: 376 | On text elements such as lists, align continuation lines (and in turn 377 | sentences) to the start of the text on the first line of the element. 378 | Indentation, for instance when writing definition lists, should be done in 379 | two space increments. 380 | We are dealing with text, not code; text is much more dense. 381 | + 382 | Exception: places where syntax makes it impossible to do otherwise. 383 | [source,asciidoc] 384 | ---- 385 | . This first example demonstrates how to indent continuations. 386 | Isn't this lovely? 387 | 388 | . This example is wrong. 389 | Some would even consider it unintuitive. 390 | 391 | Indentation:: 392 | The blank space produced by indenting, often used for clarity of scope 393 | + 394 | Sadly, to insert a newline above this line, we must lose indentation here as to 395 | not make this paragraph verbatim. 396 | ---- 397 | 398 | === C source code formatting 399 | As established, C is the _lingua franca_ of programming, all code that is not 400 | platform-specific assembly should be written in C, with placeholders for 401 | platform details (e.g. port I/O). 402 | Here are a few guidelines on C code: 403 | 404 | * Do not assume a compiler. 405 | If absolutely necessary, assume the common subset of Clang and GCC. 406 | + 407 | Exception: compiler-specific pages. 408 | 409 | * Format code in the 410 | https://en.wikipedia.org/wiki/Indentation_style#Variant:_1TBS_(OTBS)[One True 411 | Brace Style]. 412 | + 413 | This style is a variant of K&R with optional braces explicitly stated, and 414 | opening braces of blocks on the same line as their respective statements. 415 | Crucially, adding a line of code should never result in editing another line 416 | (e.g. to add a brace) or result in flow that disagrees with indentation. 417 | + 418 | [source,c] 419 | ---- 420 | /* bad */ 421 | f1(int a, int b, int c) 422 | { 423 | if (a) 424 | { 425 | return b + c; 426 | } 427 | else { 428 | return a * c; 429 | } 430 | } 431 | 432 | /* good */ 433 | int f1(int a, int b, int c) { 434 | if (a) { 435 | return b + c; 436 | } else { 437 | return a * c; 438 | } 439 | } 440 | ---- 441 | 442 | * The unit of indentation is four spaces, and alignment is allowed. 443 | + 444 | [source,c] 445 | ---- 446 | int function1(int a, /* carried over for demonstration sake */ 447 | int b, 448 | int c) { 449 | /* ... */ 450 | } 451 | ---- 452 | 453 | * Use a `snake_case` naming convention, with names up to around 16 characters. 454 | + 455 | While modern compilers _are_ able to handle more, over-verbose function names 456 | will lead to less readable code on the wiki. 457 | Since code on the wiki should be considered pseudo-C and incomplete, there 458 | is no need to worry about function names conflicting, and hence no need to 459 | introduce namespacing (i.e. `whatever_` prefixes). 460 | 461 | 462 | == Hard rules 463 | These rules must not and cannot be broken under any conditions. 464 | Violations of these rules will not be accepted under any circumstance. 465 | 466 | . Absolutely no copyright violation. 467 | By submitting a contribution to this wiki, you irrevocably agree to release 468 | your contribution under the link:/licenses/CC0.txt[CC0 license] and certify 469 | that you have the right to do so. 470 | 471 | . Commit messages must conform with the 472 | https://www.conventionalcommits.org/en/v1.0.0/[Conventional Commits] 473 | standard. 474 | 475 | * The following list contains some commit types that may be used: 476 | 477 | ** `deletion`: removal of a wiki article. 478 | 479 | ** `expansion`: expansion of a wiki article. 480 | 481 | ** `fix`: a minor fix that does not change the essence of the thing being 482 | changed (applies to all sections of the wiki). 483 | 484 | ** `feat`: introduction of a new feature (does not apply to edits of wiki 485 | articles). 486 | 487 | ** `generator`: changes to files related to site generation, other than CI. 488 | 489 | ** `new`: creation of a new wiki article. 490 | 491 | ** `ref`: changes to references. 492 | 493 | ** `style`: changes related to code or markup style, without changing the 494 | meaning of the code or markup itself. 495 | 496 | ** `trim`: partial removal of content form a wiki article. 497 | 498 | * Commits should also contain a scope indicating what part of the repository 499 | has been changed: 500 | 501 | ** `ci`: changes related to CI. 502 | 503 | ** `content`: content articles of the wiki (i.e. articles about OSDev). 504 | 505 | ** `css`: CSS files in the `css` folder. 506 | 507 | ** `generator`: files related to the site generator. 508 | 509 | ** `html`: HTML files in the `html` folder. 510 | 511 | ** `static`: assets that go in the `static` folder. 512 | 513 | ** `meta`: articles in the wiki, related to rules and governance (i.e. 514 | articles with the category `Meta`). 515 | 516 | ** `misc`: other miscellaneous files. 517 | 518 | * Commits changing articles should usually modify a single article, however 519 | frequent exceptions are allowed, especially for commits of the type `fix` and 520 | `style`. 521 | In case a single article is changed, the slug (i.e. filename without the 522 | filename extension) of the article must be listed as the scope of the commit. 523 | In case multiple articles, that are all members of a certain category or tag, 524 | are modified, that tag or category may be modified. 525 | 526 | * The description of the commit must summarize all changes; descriptions must 527 | not be vague (e.g. "updated bios.adoc"). 528 | -------------------------------------------------------------------------------- /pages/stivale.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stivale 3 | tags: protocols, boot 4 | category: Bootloaders 5 | description: Brief introduction to the Stivale boot protocol. 6 | --- 7 | 8 | *stivale* means "boot" in Italian. 9 | It is a boot protocol designed to overcome shortcomings of common boot 10 | protocols used by hobbyist OS developers, such as 11 | xref:multiboot.adoc[Multiboot]. 12 | 13 | There are actually 2 revisions of the stivale boot protocol, namely: 14 | *stivale*, and *stivale2*. The earlier stivale revision (simply "stivale", 15 | but for clarity we are going to call it "stivale1" from now on), is a very 16 | simple https://en.wikipedia.org/wiki/KISS_principle["KISS"] boot protocol 17 | only supporting what was deemed necessary at the time, but versioning and 18 | expandability issues made creating stivale2 a necessity. stivale2 makes use 19 | of tags for bootloader writers' and kernel writers' convenience, and to make 20 | future expandability and revisioning easier. 21 | 22 | NOTE: stivale1 is deprecated and should be avoided for new kernels. 23 | 24 | stivale is firmware and architecture agnostic, though the only 25 | bootloader fully supporting the stivale protocols as of writing 26 | this article (2021/01/09) is xref:limine.adoc[], which is an 27 | x86/x86_64 xref:bios.adoc[] and xref:uefi.adoc[] bootloader, with 28 | https://github.com/TomatOrg/TomatBoot[TomatBoot] (now archived) and 29 | https://github.com/FlorenceOS/Sabaton[Sabaton] offering limited stivale 30 | compliance for xref:uefi.adoc#x86[x86_64 UEFI] exclusively, and 31 | xref:arm.adoc#AArch64[aarch64], respectively. 32 | -------------------------------------------------------------------------------- /pages/stivale_barebones.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stivale Barebones 3 | tags: tutorial, kernel, barebones 4 | category: Tutorial 5 | description: A tutorial on how to write a minimal kernel using a stivale2-compliant bootloader. 6 | --- 7 | :source-language: c 8 | 9 | == Introduction 10 | 11 | === What is stivale? 12 | This article will demonstrate how to write a small 64-bit higher-half 13 | xref:stivale[stivale2] kernel in (GNU) C, and boot it using the 14 | xref:limine.adoc[Limine] bootloader. 15 | 16 | It is also recommended to check out 17 | https://github.com/limine-bootloader/limine-barebones[this] project as it 18 | provides example buildable code to go along with this tutorial. 19 | 20 | == Tutorial 21 | 22 | === The Code 23 | For this example, we will create these 2 files and place them in the same directory: 24 | 25 | * kernel.c 26 | * linker.ld 27 | 28 | As one may notice, there is no "entry point" assembly stub, as one is not necessary with either stivale1 or 2, when using a language which can make use of a standard System V x86 xref:calling_conventions.adoc[calling convention]. 29 | 30 | Furthermore, we will download the header file `stivale2.h` which defines structures that we will use to interact with the bootloader from https://raw.githubusercontent.com/stivale/stivale/master/stivale2.h[here], and place it in the same directory as the other files. 31 | 32 | Obviously, this is just a bare bones example, and one should always refer to the https://github.com/stivale/stivale/blob/master/STIVALE2.md[stivale2 specification] for more details and information. 33 | 34 | This is the kernel "main". 35 | 36 | .kernel.c 37 | [source] 38 | ---- 39 | #include 40 | #include 41 | #include 42 | 43 | // We need to tell the stivale bootloader where we want our stack to be. 44 | // We are going to allocate our stack as an array in .bss. 45 | static uint8_t stack[8192]; 46 | 47 | // stivale2 uses a linked list of tags for both communicating TO the 48 | // bootloader, or receiving info FROM it. More information about these tags 49 | // is found in the stivale2 specification. 50 | 51 | // stivale2 offers a runtime terminal service which can be ditched at any 52 | // time, but it provides an easy way to print out to graphical terminal, 53 | // especially during early boot. 54 | // Read the notes about the requirements for using this feature below this 55 | // code block. 56 | static struct stivale2_header_tag_terminal terminal_hdr_tag = { 57 | // All tags need to begin with an identifier and a pointer to the next tag. 58 | .tag = { 59 | // Identification constant defined in stivale2.h and the specification. 60 | .identifier = STIVALE2_HEADER_TAG_TERMINAL_ID, 61 | // If next is 0, it marks the end of the linked list of header tags. 62 | .next = 0 63 | }, 64 | // The terminal header tag possesses a flags field, leave it as 0 for now 65 | // as it is unused. 66 | .flags = 0 67 | }; 68 | 69 | // We are now going to define a framebuffer header tag. 70 | // This tag tells the bootloader that we want a graphical framebuffer instead 71 | // of a CGA-compatible text mode. Omitting this tag will make the bootloader 72 | // default to text mode, if available. 73 | static struct stivale2_header_tag_framebuffer framebuffer_hdr_tag = { 74 | // Same as above. 75 | .tag = { 76 | .identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID, 77 | // Instead of 0, we now point to the previous header tag. The order in 78 | // which header tags are linked does not matter. 79 | .next = (uint64_t)&terminal_hdr_tag 80 | }, 81 | // We set all the framebuffer specifics to 0 as we want the bootloader 82 | // to pick the best it can. 83 | .framebuffer_width = 0, 84 | .framebuffer_height = 0, 85 | .framebuffer_bpp = 0 86 | }; 87 | 88 | // The stivale2 specification says we need to define a "header structure". 89 | // This structure needs to reside in the .stivale2hdr ELF section in order 90 | // for the bootloader to find it. We use this __attribute__ directive to 91 | // tell the compiler to put the following structure in said section. 92 | __attribute__((section(".stivale2hdr"), used)) 93 | static struct stivale2_header stivale_hdr = { 94 | // The entry_point member is used to specify an alternative entry 95 | // point that the bootloader should jump to instead of the executable's 96 | // ELF entry point. We do not care about that so we leave it zeroed. 97 | .entry_point = 0, 98 | // Let's tell the bootloader where our stack is. 99 | // We need to add the sizeof(stack) since in x86(_64) the stack grows 100 | // downwards. 101 | .stack = (uintptr_t)stack + sizeof(stack), 102 | // Bit 1, if set, causes the bootloader to return to us pointers in the 103 | // higher half, which we likely want since this is a higher half kernel. 104 | // Bit 2, if set, tells the bootloader to enable protected memory ranges, 105 | // that is, to respect the ELF PHDR mandated permissions for the executable's 106 | // segments. 107 | // Bit 3, if set, enables fully virtual kernel mappings, which we want as 108 | // they allow the bootloader to pick whichever *physical* memory address is 109 | // available to load the kernel, rather than relying on us telling it where 110 | // to load it. 111 | // Bit 4 disables a deprecated feature and should always be set. 112 | .flags = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4), 113 | // This header structure is the root of the linked list of header tags and 114 | // points to the first one in the linked list. 115 | .tags = (uintptr_t)&framebuffer_hdr_tag 116 | }; 117 | 118 | // We will now write a helper function which will allow us to scan for tags 119 | // that we want FROM the bootloader (structure tags). 120 | void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id) { 121 | struct stivale2_tag *current_tag = (void *)stivale2_struct->tags; 122 | for (;;) { 123 | // If the tag pointer is NULL (end of linked list), we did not find 124 | // the tag. Return NULL to signal this. 125 | if (current_tag == NULL) { 126 | return NULL; 127 | } 128 | 129 | // Check whether the identifier matches. If it does, return a pointer 130 | // to the matching tag. 131 | if (current_tag->identifier == id) { 132 | return current_tag; 133 | } 134 | 135 | // Get a pointer to the next tag in the linked list and repeat. 136 | current_tag = (void *)current_tag->next; 137 | } 138 | } 139 | 140 | // The following will be our kernel's entry point. 141 | void _start(struct stivale2_struct *stivale2_struct) { 142 | // Let's get the terminal structure tag from the bootloader. 143 | struct stivale2_struct_tag_terminal *term_str_tag; 144 | term_str_tag = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_TERMINAL_ID); 145 | 146 | // Check if the tag was actually found. 147 | if (term_str_tag == NULL) { 148 | // It wasn't found, just hang... 149 | for (;;) { 150 | asm ("hlt"); 151 | } 152 | } 153 | 154 | // Let's get the address of the terminal write function. 155 | void *term_write_ptr = (void *)term_str_tag->term_write; 156 | 157 | // Now, let's assign this pointer to a function pointer which 158 | // matches the prototype described in the stivale2 specification for 159 | // the stivale2_term_write function. 160 | void (*term_write)(const char *string, size_t length) = term_write_ptr; 161 | 162 | // We should now be able to call the above function pointer to print out 163 | // a simple "Hello World" to screen. 164 | term_write("Hello World", 11); 165 | 166 | // We're done, just hang... 167 | for (;;) { 168 | asm ("hlt"); 169 | } 170 | } 171 | ---- 172 | 173 | NOTE: Using the stivale2 terminal requires that the kernel maintains some state as described in the https://github.com/stivale/stivale/blob/master/STIVALE2.md\#x86\_64-1[specification]. 174 | 175 | This is going to be our linker script describing where our sections will end up in memory. 176 | 177 | .linker.ld 178 | [source] 179 | ---- 180 | /* Tell the linker that we want an x86_64 ELF64 output file */ 181 | OUTPUT_FORMAT(elf64-x86-64) 182 | OUTPUT_ARCH(i386:x86-64) 183 | 184 | /* We want the symbol _start to be our entry point */ 185 | ENTRY(_start) 186 | 187 | /* Define the program headers we want so the bootloader gives us the right */ 188 | /* MMU permissions */ 189 | PHDRS 190 | { 191 | null PT_NULL FLAGS(0) ; /* Null segment */ 192 | text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ 193 | rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ 194 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ 195 | } 196 | 197 | SECTIONS 198 | { 199 | /* We wanna be placed in the topmost 2GiB of the address space, for optimisations */ 200 | /* and because that is what the stivale2 spec mandates. */ 201 | /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ 202 | /* that is the beginning of the region. */ 203 | . = 0xffffffff80000000; 204 | 205 | .text : { 206 | *(.text*) 207 | } :text 208 | 209 | /* Move to the next memory page for .rodata */ 210 | . += CONSTANT(MAXPAGESIZE); 211 | 212 | /* We place the .stivale2hdr section containing the header in its own section, */ 213 | /* and we use the KEEP directive on it to make sure it doesn't get discarded. */ 214 | .stivale2hdr : { 215 | KEEP(*(.stivale2hdr)) 216 | } :rodata 217 | 218 | .rodata : { 219 | *(.rodata*) 220 | } :rodata 221 | 222 | /* Move to the next memory page for .data */ 223 | . += CONSTANT(MAXPAGESIZE); 224 | 225 | .data : { 226 | *(.data*) 227 | } :data 228 | 229 | .bss : { 230 | *(COMMON) 231 | *(.bss*) 232 | } :data 233 | } 234 | ---- 235 | 236 | === Building the kernel and creating an image 237 | 238 | ==== Makefile 239 | 240 | In order to build our kernel, we are going to use a Makefile. 241 | 242 | [source, makefile] 243 | ---- 244 | # This is the name that our final kernel executable will have. 245 | # Change as needed. 246 | KERNEL := myos.elf 247 | 248 | # It is highly recommended to use a custom built cross toolchain to build a kernel. 249 | # We are only using "cc" as a placeholder here. It may work by using 250 | # the host system's toolchain, but this is not guaranteed. 251 | CC ?= cc 252 | 253 | # Likewise, "ld" here is just a placeholder and your mileage may vary if using the 254 | # host's "ld". 255 | LD ?= ld 256 | 257 | # User controllable CFLAGS. 258 | CFLAGS ?= -Wall -Wextra -O2 -pipe 259 | 260 | # User controllable linker flags. We set none by default. 261 | LDFLAGS ?= 262 | 263 | # Internal C flags that should not be changed by the user. 264 | INTERNALCFLAGS := \ 265 | -I. \ 266 | -std=gnu11 \ 267 | -ffreestanding \ 268 | -fno-stack-protector \ 269 | -fno-pic \ 270 | -mno-80387 \ 271 | -mno-mmx \ 272 | -mno-3dnow \ 273 | -mno-sse \ 274 | -mno-sse2 \ 275 | -mno-red-zone \ 276 | -mcmodel=kernel \ 277 | -MMD 278 | 279 | # Internal linker flags that should not be changed by the user. 280 | INTERNALLDFLAGS := \ 281 | -Tlinker.ld \ 282 | -nostdlib \ 283 | -zmax-page-size=0x1000 \ 284 | -static 285 | 286 | # Use find to glob all *.c files in the directory and extract the object names. 287 | CFILES := $(shell find ./ -type f -name '*.c') 288 | OBJ := $(CFILES:.c=.o) 289 | HEADER_DEPS := $(CFILES:.c=.d) 290 | 291 | # Default target. 292 | .PHONY: all 293 | all: $(KERNEL) 294 | 295 | # Link rules for the final kernel executable. 296 | $(KERNEL): $(OBJ) 297 | $(LD) $(OBJ) $(LDFLAGS) $(INTERNALLDFLAGS) -o $@ 298 | 299 | # Compilation rules for *.c files. 300 | -include $(HEADER_DEPS) 301 | %.o: %.c 302 | $(CC) $(CFLAGS) $(INTERNALCFLAGS) -c $< -o $@ 303 | 304 | # Remove object files and the final executable. 305 | .PHONY: clean 306 | clean: 307 | rm -rf $(KERNEL) $(OBJ) $(HEADER_DEPS) 308 | ---- 309 | 310 | ==== limine.cfg 311 | 312 | This file is parsed by Limine and it describes boot entries and other bootloader configuration variables. Further information https://github.com/limine-bootloader/limine/blob/trunk/CONFIG.md[here]. 313 | 314 | [source, ini] 315 | ---- 316 | # Timeout in seconds that Limine will use before automatically booting. 317 | TIMEOUT=5 318 | 319 | # The entry name that will be displayed in the boot menu 320 | :myOS 321 | 322 | # Change the protocol line depending on the used protocol. 323 | PROTOCOL=stivale2 324 | 325 | # Path to the kernel to boot. boot:/// represents the partition on which limine.cfg is located. 326 | KERNEL_PATH=boot:///myos.elf 327 | ---- 328 | 329 | ==== Compiling the kernel 330 | 331 | We can now build our example kernel by running *make*. This command, if successful, should generate a file called `myos.elf` (or the chosen kernel name). This is our stivale2-compliant kernel executable. 332 | 333 | ==== Creating the image 334 | 335 | We can now create either an ISO or a hard disk/USB drive image with our kernel on it. xref:limine.adoc[] can boot on both xref:bios.adoc[] and xref:uefi.adoc[] if the image is set up to do so, which is what we are going to do. 336 | 337 | === Creating an ISO 338 | 339 | In this example we are going to create a CD-ROM ISO capable of booting on both xref:uefi.adoc[] and legacy xref:bios.adoc[] systems. 340 | 341 | For this to work, we will need the *xorriso* utility. 342 | 343 | These are shell commands. They can also be compiled into a script or Makefile. 344 | 345 | [source, sh] 346 | ---- 347 | # Download the latest Limine binary release. 348 | git clone https://github.com/limine-bootloader/limine.git --branch=v2.0-branch-binary --depth=1 349 | 350 | # Build limine-install. 351 | make -C limine 352 | 353 | # Create a directory which will be our ISO root. 354 | mkdir -p iso_root 355 | 356 | # Copy the relevant files over. 357 | cp -v myos.elf limine.cfg limine/limine.sys \ 358 | limine/limine-cd.bin limine/limine-eltorito-efi.bin iso_root/ 359 | 360 | # Create the bootable ISO. 361 | xorriso -as mkisofs -b limine-cd.bin \ 362 | -no-emul-boot -boot-load-size 4 -boot-info-table \ 363 | --efi-boot limine-eltorito-efi.bin \ 364 | -efi-boot-part --efi-boot-image --protective-msdos-label \ 365 | iso_root -o image.iso 366 | 367 | # Install Limine stage 1 and 2 for legacy BIOS boot. 368 | ./limine/limine-install image.iso 369 | ---- 370 | 371 | === Creating a hard disk/USB drive image 372 | 373 | In this example we'll create a xref:gpt.adoc[] partition table using **parted**, containing a single FAT partition, also known as the xref:uefi.adoc#ESP[ESP] in EFI terminology, which will store our kernel, configs, and bootloader. 374 | 375 | This example is more involved and is made up of more steps than creating an ISO image. 376 | 377 | These are shell commands. They can also be compiled into a script or Makefile. 378 | 379 | [source, sh] 380 | ---- 381 | # Create an empty zeroed out 64MiB image file. 382 | dd if=/dev/zero bs=1M count=0 seek=64 of=image.hdd 383 | 384 | # Create a GPT partition table. 385 | parted -s image.hdd mklabel gpt 386 | 387 | # Create an ESP partition that spans the whole disk. 388 | parted -s image.hdd mkpart ESP fat32 2048s 100% 389 | parted -s image.hdd set 1 esp on 390 | 391 | # Download the latest Limine binary release. 392 | git clone https://github.com/limine-bootloader/limine.git --branch=v2.0-branch-binary --depth=1 393 | 394 | # Build limine-install. 395 | make -C limine 396 | 397 | # Install the Limine BIOS stages onto the image. 398 | ./limine/limine-install image.hdd 399 | 400 | # Mount the loopback device. 401 | USED_LOOPBACK=$(sudo losetup -Pf --show image.hdd) 402 | 403 | # Format the ESP partition as FAT32. 404 | sudo mkfs.fat -F 32 ${USED_LOOPBACK}p1 405 | 406 | # Mount the partition itself. 407 | mkdir -p img_mount 408 | sudo mount ${USED_LOOPBACK}p1 img_mount 409 | 410 | # Copy the relevant files over. 411 | sudo mkdir -p img_mount/EFI/BOOT 412 | sudo cp -v myos.elf limine.cfg limine/limine.sys img_mount/ 413 | sudo cp -v limine/BOOTX64.EFI img_mount/EFI/BOOT/ 414 | 415 | # Sync system cache and unmount partition and loopback device. 416 | sync 417 | sudo umount img_mount 418 | sudo losetup -d ${USED_LOOPBACK} 419 | ---- 420 | 421 | == Conclusion 422 | 423 | If everything above has been completed successfully, you should now have a bootable ISO or hard drive/USB image containing your 64-bit higher half stivale2 kernel and Limine to boot it. Once the kernel is successfully booted, you should see "Hello World" printed on screen. 424 | 425 | == See Also 426 | 427 | * https://github.com/stivale/stivale/blob/master/STIVALE2.md[stivale2 specification] 428 | * https://github.com/FlorenceOS/Sabaton[The sabaton aarch64 stivale2 bootloader] 429 | * https://github.com/TomatOrg/TomatBoot[The TomatBoot x86\_64 UEFI stivale1 and 2 bootloader] (now archived) 430 | -------------------------------------------------------------------------------- /pages/visual_studio.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Visual Studio 3 | tags: compiler, msvc, toolchain 4 | category: Toolchain 5 | description: How to use Visual Studio, with either MSVC or Clang for OS development. 6 | --- 7 | 8 | This page describes how to use *Visual Studio* as an IDE and build system for OS 9 | development. 10 | The use of the Clang toolchain is recommended, but using Microsoft's native 11 | MSVC compiler is possible as well. 12 | 13 | // == Using Clang and cmake with Visual Studio 14 | // TODO 15 | 16 | == Using MSVC and msbuild with Visual Studio 17 | [CAUTION] 18 | .MSVC for OSDev 19 | ==== 20 | It is possible to use MSVC for OS development, but it is heavily advised 21 | against for a number of reasons. 22 | 23 | * It is proprietary and not properly documented. 24 | * It is difficult and sometimes impossible to do certain things required for OS 25 | development using a pure MS toolchain. 26 | * Few people will be willing to provide help when something goes wrong. 27 | ==== 28 | -------------------------------------------------------------------------------- /pages/writer_tutorial.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: Writing a document 3 | tags: meta 4 | category: Meta 5 | description: An overview of how to write and submit an article 6 | --- 7 | == Writing the AsciiDoc 8 | The wiki consists of documents written in AsciiDoc under the `pages/` directory 9 | in the source tree. 10 | Documents are prefaced with a nonstandard preamble containing page metadata. 11 | This preamble is surrounded by `---` and is a standard YAML document. 12 | The following fields are required: 13 | 14 | - `title`: The document title, 15 | - `tags`: A comma separated list of page tags (see a list of current tags on 16 | link:/tags[the tag index page]), 17 | - `category`: The main category of this page (see a list of current categories 18 | on link:/categories[the category index page]), 19 | - `description`: A brief description of the page (to show in overviews and 20 | OpenGraph metadata). 21 | 22 | The convention for the names of documents on the wiki is 23 | `pages/snake_case_slug.adoc`. 24 | 25 | Categories are defined in a YAML-formatted category description mapping in the 26 | `categories.yaml` file. 27 | 28 | === References and bibliographies 29 | We use https://github.com/asciidoctor/asciidoctor-bibtex[asciidoctor-bibtex] to 30 | emit bibliographies and references on the wiki. 31 | If you wish to cite something, first check whether `sources.bib` in the root of 32 | the repository has the document you wish to cite and if its metadata is 33 | correct, if your entry is not present, or is incorrect, please update it. 34 | 35 | When adding references to a page, please add the following to the end of the 36 | document in order to render its bibliography: 37 | 38 | [source,asciidoc] 39 | ---- 40 | == Bibliography 41 | bibliography::[] 42 | ---- 43 | 44 | === Things of note 45 | - Written documents will be prefixed with their title emitted as a level zero 46 | heading automatically. 47 | Start with level one headings (`==`) when dividing up documents. 48 | - All AsciiDoctor features _should_ work. 49 | If there is a construct we missed and is broken, it is likely a bug in the 50 | generator. 51 | Please report it. 52 | 53 | === Further reading 54 | - https://docs.asciidoctor.org/asciidoc/latest/[AsciiDoc manual] 55 | - https://docs.asciidoctor.org/asciidoc/latest/syntax-quick-reference/[Syntax 56 | Quick Reference] 57 | - https://docs.asciidoctor.org/asciidoctor/latest/[AsciiDoctor manual] 58 | 59 | === Example document 60 | [source,asciidoc] 61 | ---- 62 | --- 63 | title: Lorem Ipsum 64 | tags: examples 65 | category: Examples 66 | description: Lorem ipsum 67 | --- 68 | == Ipsum 69 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor 70 | incididunt ut labore et dolore magna aliqua. 71 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut 72 | aliquip ex ea commodo consequat. 73 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 74 | fugiat nulla pariatur. 75 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia 76 | deserunt mollit anim id est laborum. 77 | ---- 78 | 79 | == Submitting your changes 80 | When submitting your change, please confirm it adheres to our 81 | xref:guidelines.adoc[style guidelines] and make commits accordingly. 82 | Please ensure these commits are atomic and encompass one change each. 83 | 84 | After you are done, push your changes to a fork of our source repository and 85 | submit a pull request. 86 | It will then be reviewed by our editorial team and merged if appropriate. 87 | 88 | We suggest that you enable GitHub actions on your fork and use them to ensure 89 | your pages look like what you intended them to. 90 | Our workflows will push changes to `gh-pages` on the same repository. 91 | You might need to create that branch, even if empty. 92 | 93 | // TODO(arsen): make creating the branch unnecessary. 94 | -------------------------------------------------------------------------------- /pages/x86.adoc: -------------------------------------------------------------------------------- 1 | --- 2 | title: x86 3 | tags: x86, architecture 4 | category: x86 5 | description: Description and brief history of the x86 CPU architecture. 6 | --- 7 | 8 | *x86* is a backwards compatible family of little-endian, complex instruction 9 | set architectures (ISA) introduced in 1978 by 10 | Intelfootnote:[https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html]. 11 | The iterations of the ISA can be broadly classified by integer width: 12 | 13 | * 16-bit x86, also referred to as x86_16 or IA-16 (introduced with the Intel 14 | 8086 in 1978) 15 | * 32-bit x86, also referred to as x86_32 or IA-32 (introduced with the Intel 16 | 386 in 1985) 17 | * 64-bit x86 (not to be confused with IA-64), also referred to as x86_64, AMD64 18 | or x64. 19 | It is also referred to as EM64T, IA-32e or Intel64 by Intel. 20 | 21 | == History 22 | The first iteration of the x86 architecture was introduced in 1978 with the 23 | 8086. 24 | The 8086 was a 16-bit CPU, with 16-bit registers, a 16-bit data bus and a 25 | 20-bit address bus. 26 | Thus it was able to address one megabyte of RAM. 27 | Slightly later, the 8088 CPU was introduced, which was internally identical to 28 | the 8086, but had a 8-bit data bus. 29 | The 8088 was used by the original IBM PC, introduced in 1981, which was the 30 | predecessor of all modern PCs. 31 | Thus, the x86 architecture became the dominant architecture on personal 32 | computers. 33 | 34 | In 1982, Intel introduced the 186, 188 and 286. 35 | The 186 and 188 where similar to the 8086 and 8088 respectively, but where 36 | intended for embedded systems, and included peripheral that were not compatible 37 | with IBM PCs. 38 | The Intel 286, however, was intended for multi-user, multitasking environments. 39 | Thus the 286 introduced features for multitasking and memory protection and was 40 | able to address up to 16 megabytes of RAM. 41 | To preserve compatibility with the 8086, most of the features introduced with 42 | the 286 could only be used in a mode called *protected mode*. 43 | The 286 and most subsequent x86 processors start in *real mode*, which emulates 44 | the behavior of a 8086. 45 | The 286 started to gain wide adoption with the introduction of the IBM AT in 46 | 1984. 47 | 48 | In 1985, Intel introduced the 386. 49 | This new interation introduced support for 32-bit integers and extended 50 | protected mode to introduce, among other things, paging and support for up to 51 | four gigabytes of RAM. 52 | 53 | In 1989, the Intel 486 was introduced, with new features, such as: 54 | 55 | - An integrated "x87" FPU 56 | - L1 cache used for increased IPC 57 | - System management capabilities 58 | 59 | To this day, every properly-implemented x86 processor has backwards 60 | compatibility, all the way back to the original Intel 8086. 61 | 62 | == Operating modes 63 | 64 | x86 has a handful of operating modes, used for backwards compatibility. 65 | 66 | === Real mode 67 | Real mode is the operating mode that an x86 processor boots into. It mostly 68 | models the original 16-bit 8086 processor, with a few extensions. 69 | 70 | While data can be handled 16 bits at a time, segment offset registers offer 71 | addressing up to 21 bits, which provides the processor with 1MiB of addressable 72 | memory. 73 | 74 | Real mode contains no access rings or protection of any kind. 75 | 76 | === Protected mode (16-bit) 77 | 16-bit protected mode runs with 16-bit data and instructions, but segment 78 | offset registers are replaced with segment selector registers, which point to 79 | an entry into the 16-bit GDT. 80 | 81 | Programs written for real mode may have a handful of compatibility issues with 82 | 16-bit protected mode, but instructions are still read in the same format. 83 | 84 | 16-bit protected mode is rarely used. 85 | 86 | === Protected mode (32-bit) 87 | 32-bit protected mode reads and addresses with 32-bit values. This is the mode 88 | commonly referred to as "protected mode". 89 | Protected mode mandates a 32-bit before entry. 90 | Protected mode is officially entered when a far jump is performed that sets CS 91 | to an offset which points to a code segment in a 32-bit GDT. 92 | 93 | 32 bits of addressing provide up to 4GiB of addressable virtual memory. 94 | However, with PAE paging extensions, the virtual address space can be mapped to 95 | 64-bit physical addresses, theoretically allowing up to 16PiB of physical 96 | memory to be addressed. 97 | 98 | === Compatibility mode (x86-64 only) 99 | Compatibility mode runs during the transition from protected mode to long mode. 100 | Compatibility mode runs similarly to protected mode, and is used to allow 101 | 64-bit structures to be loaded before entering proper long mode. 102 | 103 | === Long mode (x86-64 only) 104 | Long mode handles data up to 64 bits in general purpose registers, with 105 | extensions that allow for the handling of up to 512 bits of data at a time. 106 | Addressing in long mode is 64-bit, theoretically allowing for up to 16PiB of 107 | virtual memory to be _directly_ addressed. 108 | 109 | However, on most x86-64 processors, only 48 bits of addressing are actually 110 | implemented, with the notable exception of processors that support 5-level 111 | paging. 112 | These 48-bit addresses must all have the top unsupported bits be set or unset, 113 | resulting in two "halves" of the virtual address space. These addresses are 114 | referred to as "canonical" addresses. 115 | 116 | The name "long mode" refers to the commonplace technical term for a 64-bit 117 | integer, a "long". 118 | 119 | Due to the unfulfillable amount of virtual memory, PAE paging is mandated in 120 | long mode. 121 | This allows for contiguous mapping of physical RAM, with memory-mapped IO out 122 | of physical RAM space. 123 | This also allows x86-64 operating systems to implement "swap memory", a process 124 | where virtual addresses point to data not in physical RAM, but rather stored on 125 | disk. 126 | 127 | == Extensions 128 | x86 processors have a plethora of extensions that expand on standard behavior. 129 | The most notable, x86-64, implements 64-bit addressing and long mode. 130 | 131 | This section only contains a handful of extensions, there are too many to list 132 | at once. 133 | 134 | === x86-64 135 | The x86-64 extension is quite expansive, implementing the 64-bit operating mode 136 | and 64-bit addressing. 137 | It is nearly impossible to find a working computer today that does not support 138 | x86-64. 139 | 140 | === PAE/NX 141 | PAE/NX implements 4-level paging, and adds a handful of properties to pages to 142 | implement extensive memory protection, including NX, a flag to disable 143 | execution on a particular page. 144 | 145 | Most operational computers today support PAE/NX. 146 | 147 | === x87 148 | x87 is a floating-point calculation extension. 149 | While technically an extension, it is supported on most x86 processors. 150 | 151 | === SSE 152 | SSE is a 128-bit data extension. 153 | It adds 8-16 128-bit general purpose `XMM` registers, and instructions to 154 | perform SIMD vector math. 155 | 156 | SSE has several versions. x86-64 processors are mandated to support at least 157 | SSE2. 158 | 159 | === AVX 160 | AVX is a 256-bit data extension. It performs a purpose similar to SSE, and 161 | implements a handful of 256-bit `YMM` registers. 162 | 163 | AVX was released alongside the Sandy Bridge microarchitecture in 2011. 164 | A not-insignificant number of operational computers today do not support AVX. 165 | 166 | ==== AVX-512 167 | AVX-512 is not a single extension, but rather a family of extensions. 168 | It is similar to AVX, but implements a handful of 512-bit `ZMM` registers. 169 | 170 | AVX-512 is quite new, with consumer processors supporting AVX-512 being 171 | released in 2018.footnote:[https://web.archive.org/web/20161023135525/http://www.legitreviews.com/intel-cannonlake-added-to-llvms-clang_179210] 172 | It is yet to become widely supported. 173 | 174 | == See Also 175 | * https://en.wikipedia.org/wiki/X86[x86 on Wikipedia] 176 | * https://www.amd.com/en/support/tech-docs/amd64-architecture-programmers-manual-volumes-1-5[AMD64 Architecture Programmers' Manuals] 177 | * https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html[Intel Software Developer Manuals] 178 | -------------------------------------------------------------------------------- /sources.bib: -------------------------------------------------------------------------------- 1 | Please double check this file before committing new entries. 2 | Duplicates are not appreciated. 3 | If you believe information related to an entry is wrong, feel free to submit an 4 | update. 5 | 6 | 7 | -------------------------------------------------------------------------------- /static/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 41 | 43 | 47 | 50 | 55 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /static/search.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2021 Arsen Arsenovic, CC0 */ 2 | function blowSearchUp(searchDiv) { 3 | searchDiv.classList.add("stork-fullscreen"); 4 | } 5 | 6 | function hideSearch(searchDiv) { 7 | searchDiv.classList.remove("stork-fullscreen"); 8 | } 9 | 10 | (() => { 11 | const searchDiv = document.querySelector(".stork-wrapper"); 12 | const inputBox = searchDiv.querySelector("input"); 13 | /* I am sorry. */ 14 | const root = document.querySelector("#roothack").getAttribute("href"); 15 | let path = document.location.pathname; 16 | path = path.substring(0, path.lastIndexOf("/") + 1); 17 | const rootPath = document.location.protocol 18 | + "//" + document.location.host 19 | + path 20 | + root; 21 | 22 | function onQueryUpdate(query, results) { 23 | if (query === "") { 24 | hideSearch(searchDiv); 25 | return; 26 | } 27 | blowSearchUp(searchDiv); 28 | } 29 | 30 | function onResultsHidden(query, results) { 31 | hideSearch(searchDiv); 32 | } 33 | 34 | inputBox.addEventListener('input', ev => onQueryUpdate(inputBox.value)); 35 | 36 | /* TODO(arsen): SRI for this, needs upstream support */ 37 | stork.initialize("https://files.stork-search.net/releases/v1.4.0/stork.wasm") 38 | stork.register("wiki", rootPath + "/searchidx.st", { 39 | "onQueryUpdate": onQueryUpdate, 40 | "onResultsHidden": onResultsHidden, 41 | }); 42 | 43 | /* show the search again */ 44 | document.querySelector(".stork-wrapper").style.display = "grid"; 45 | })(); 46 | 47 | /* vim: set sw=4 et : */ 48 | --------------------------------------------------------------------------------