Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
05b78ca
Add template for titles
sagi21805 May 11, 2026
ea2c8ab
Wrote more about macros
sagi21805 May 13, 2026
7ace298
added more colors to css
sagi21805 May 13, 2026
d5a7310
Add explanation about proceadural and declerative macros
sagi21805 May 13, 2026
5b9a52f
Add a lot of explanation on syn and stared to explain about quote
sagi21805 May 16, 2026
3f29e9d
Add ast img
sagi21805 May 16, 2026
9306693
Change to latest version on submodules.
sagi21805 May 16, 2026
ec1a5e6
Add explanation about quote
sagi21805 May 16, 2026
c005f62
update submodule
sagi21805 May 16, 2026
a89421e
Add definition of the bitfields proc macro
sagi21805 May 17, 2026
7a8d96f
Add svg image of example.
sagi21805 May 17, 2026
b225aaf
Updated to mdbook 0.5.3
sagi21805 May 22, 2026
d448371
explanation about bitshifting
sagi21805 May 22, 2026
1c8230f
Add simple flags example
sagi21805 May 22, 2026
1b77f17
Add more explanations
sagi21805 May 23, 2026
3dc2401
Change mdbook version on ci
sagi21805 May 23, 2026
42325c5
Add picture
sagi21805 May 23, 2026
09fd8a6
Add some more explanations
sagi21805 May 25, 2026
6a41e23
More explanations!
sagi21805 May 25, 2026
1864811
Add explanation on better method to create mask.
sagi21805 May 26, 2026
fffe3c5
explanation about the FieldTypes struct
sagi21805 May 26, 2026
81f2cc8
Add ra-mod-macro to css
sagi21805 May 26, 2026
d1b739f
Add explanations about read and write
sagi21805 May 27, 2026
90173e7
Finished draft for writing, should check grammar, and add snippets to
sagi21805 May 27, 2026
73e4f6e
Automatically adds file paths links
sagi21805 May 29, 2026
40adf90
Organized
sagi21805 May 29, 2026
2df2df8
Final draft for proc macro chapter before grammar and wording analysis
sagi21805 May 29, 2026
1146df7
Correction
sagi21805 May 29, 2026
1e3c320
Fixed typos
sagi21805 May 30, 2026
fe13600
Add yamls for preview before deploying on master.
sagi21805 May 30, 2026
09831f2
Merge branch 'master' into feat/writing-bitfields-proc-macro
sagi21805 May 30, 2026
a098b55
Update typos action to version 1.47
sagi21805 May 30, 2026
ac4ba9c
Update deploy.yml
sagi21805 May 30, 2026
48f7fde
Update deploy.yml
sagi21805 May 30, 2026
4e497a3
Update deploy.yml
sagi21805 May 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
theme/whichlang.js linguist-vendored
theme/highlight.js linguist-vendored
31 changes: 31 additions & 0 deletions .github/workflows/cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: cleanup-preview

on:
delete:

jobs:
cleanup:
if: github.event.ref_type == 'branch'
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v4
with:
ref: gh-pages
fetch-depth: 0

- name: Remove preview folder
run: |
BRANCH="${{ github.event.ref }}"
if [ -d "preview/$BRANCH" ]; then
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git rm -rf "preview/$BRANCH"
git commit -m "chore: remove preview for $BRANCH"
git push
else
echo "No preview found for $BRANCH, nothing to clean up."
fi
56 changes: 52 additions & 4 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,75 @@ jobs:
submodules: true
fetch-depth: 0

- name: Install mdBook and mdbook-linkcheck (cached by action)
- name: Cache Rust toolchain & registry
uses: actions/cache@v4
with:
path: |
~/.rustup
~/.cargo/registry
~/.cargo/git
key: rust-toolchain-${{ runner.os }}-v1

- name: Cache compiled binaries
id: cache-bins
uses: actions/cache@v4
with:
path: ~/.cargo/bin
key: mdbook-bins-${{ runner.os }}-mdbook-0.5.3-v1

- name: Cache preprocessor build targets
uses: actions/cache@v4
with:
path: |
mdbook-rust-analyzer-highlight/target
mdbook-gh-issue-preview/target
key: cargo-preprocessors-${{ runner.os }}-${{ hashFiles('mdbook-rust-analyzer-highlight/Cargo.lock', 'mdbook-gh-issue-preview/Cargo.lock') }}
restore-keys: |
cargo-preprocessors-${{ runner.os }}-

- name: Install mdBook and plugins
if: steps.cache-bins.outputs.cache-hit != 'true'
uses: taiki-e/install-action@v2
with:
tool: mdbook@0.4.52,mdbook-linkcheck,mdbook-utils,mdbook-webinclude
tool: mdbook@0.5.3,mdbook-utils

- name: Create sitemap
run: mdbook-utils sitemap -m src -b https://www.learnix-os.com -o src/assets/sitemap.xml

- name: Build the book
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: mdbook build

- name: Deploy preview
if: github.ref_name != 'master'
uses: peaceiris/actions-gh-pages@v3
with:
personal_token: ${{ secrets.PREVIEW_DEPLOY_TOKEN }}
external_repository: sagi21805/LearnixOS-Book-previews
publish_branch: gh-pages
publish_dir: ./book
# no destination_dir → deploys to root, overwrites previous preview

- name: Print preview URL
if: github.ref_name != 'master'
run: |
echo "=========================================="
echo " Preview URL:"
echo " https://sagi21805.github.io/LearnixOS-Book-previews"
echo "=========================================="

- name: Setup Pages
if: github.ref_name == 'master'
uses: actions/configure-pages@v4

- name: Upload artifact
if: github.ref_name == 'master'
uses: actions/upload-pages-artifact@v3
with:
path: 'book'
path: "book"

- name: Deploy to GitHub Pages
if: github.ref_name == 'master'
id: deployment
uses: actions/deploy-pages@v4
2 changes: 1 addition & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ jobs:
uses: actions/checkout@v4

- name: Check the Spelling of the Book
uses: crate-ci/typos@v1.34.0
uses: crate-ci/typos@v1.47.0
2 changes: 1 addition & 1 deletion LearnixOS
Submodule LearnixOS updated 42 files
+1 −1 README.md
+6,880 −0 crates/arch/x86/log.rs
+34 −34 crates/arch/x86/src/structures/global_descriptor_table.rs
+5 −5 crates/arch/x86/src/structures/interrupt_descriptor_table.rs
+20 −14 crates/arch/x86/src/structures/paging/entry_flags.rs
+1 −3 crates/arch/x86/src/structures/paging/init.rs
+1 −3 crates/arch/x86/src/structures/paging/page_table.rs
+2 −2 crates/arch/x86/src/structures/paging/page_table_entry.rs
+6 −6 crates/common/src/address_types.rs
+369 −0 crates/macros/src/bitfields.rs
+70 −0 crates/macros/src/bitfields/bitfield.rs
+231 −0 crates/macros/src/bitfields/flag_attr.rs
+65 −0 crates/macros/src/bitfields/utils.rs
+0 −741 crates/macros/src/bitflags.rs
+7 −62 crates/macros/src/lib.rs
+1 −1 rust-toolchain.toml
+3 −0 rustfmt.toml
+5 −0 snippets/Cargo.toml
+5 −14 snippets/src/book.rs
+14 −0 snippets/src/book/ch01_01/build.rs
+15 −0 snippets/src/book/ch01_01/general.rs
+0 −3 snippets/src/book/ch01_01/init.rs
+10 −0 snippets/src/book/ch01_01/minimal_main.rs
+6 −0 snippets/src/book/ch01_01/mod.rs
+7 −0 snippets/src/book/ch01_01/no_std.rs
+5 −0 snippets/src/book/ch01_01/panic.rs
+11 −0 snippets/src/book/ch01_02/general.rs
+2 −0 snippets/src/book/ch01_02/mod.rs
+22 −0 snippets/src/book/ch01_02/print.rs
+33 −0 snippets/src/book/ch02_02/enums.rs
+411 −0 snippets/src/book/ch02_02/flag_macro_expand.rs
+2 −0 snippets/src/book/ch02_02/mod.rs
+110 −0 snippets/src/book/ch02_03/general.rs
+7 −0 snippets/src/book/ch02_03/invoke.rs
+17 −0 snippets/src/book/ch02_03/mask.rs
+5 −0 snippets/src/book/ch02_03/mod.rs
+14 −0 snippets/src/book/ch02_03/read.rs
+18 −0 snippets/src/book/ch02_03/write.rs
+1 −0 snippets/src/book/ch03_00/mod.rs
+9 −0 snippets/src/book/ch03_00/print_example.rs
+44 −0 snippets/src/lib.rs
+2 −5 tests/src/main.rs
10 changes: 6 additions & 4 deletions book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,21 @@ inlay-hint-config = "inlay_config.json"
after = ["mdbook-rust-analyzer-highlight"]
command = "cargo run --release --manifest-path mdbook-gh-issue-preview/Cargo.toml"

[preprocessor.webinclude]
before = ["mdbook-rust-analyzer-highlight"]

[output.html]
git-repository-url = "https://github.com/sagi21805/LearnixOS"
default-theme = "navy"
preferred-dark-theme = "navy"
preferred-light-theme = "navy"
additional-css = ["theme/whichlang.css", "theme/hlrs.css", "theme/gh-issue.css", "theme/tags.css"]
additional-js = [
"theme/whichlang.js",
"theme/filepath-links.js",
"theme/giscuss.js",
"theme/tags.js"
"theme/tags.js",
"theme/highlight.js"
]
mathjax-support = true

[output.html.playground]
runnable = true
editable = true
2 changes: 1 addition & 1 deletion mdbook-gh-issue-preview
3 changes: 2 additions & 1 deletion src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
# Chapters of The Book

- [Getting Started](./ch01-00-getting-started.md)
- [Making a Stand Alone Binary [OS]](./ch01-01-making-stand-alone-binary.md)
- [Making a Stand Alone Binary [OS] [RUST]](./ch01-01-making-stand-alone-binary.md)
- [Booting Our Binary [OS]](./ch01-02-booting-our-binary.md)
- [Debugging Tips](./ch01-03-debugging-methods.md)

- [A Minimal Bootloader](./ch02-00-a-minimal-bootloader.md)
- [Legacy Legacy Legacy [OS]](./ch02-01-legacy-legacy-legacy.md)
- [Entering Protected Mode [OS]](./ch02-02-entering-protected-mode.md)
- [Implementing the Bitfields Proc-Macro [RUST]](./ch02-03-implementing-the-bitfields-proc-macro.md)
- [What is Memory Paging? [OS]](./ch02-03-what-is-memory-paging.md)
- [Booting the Kernel [OS]](./ch02-04-booting-the-kernel.md)

Expand Down
2 changes: 2 additions & 0 deletions src/assets/ast.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/assets/bitflag.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/assets/parse_stream.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/assets/simple_flags_ex.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 18 additions & 15 deletions src/ch01-01-making-stand-alone-binary.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ _"Machines take me by surprise with great frequency." - Alan Turing_

The first step in making our operating system is making a program that can be compiled, and executed, without any dependency.
This is not a straightforward task, because every program that we use in our daily life uses at least one, very important dependency: `The Standard Library`.
Sometimes, this library is provided by the operating system itself, for example, libc for the Linux operating system, or the WinAPI for the Windows operating system, and most of the time it is wrapped around by our programming languages.
Sometimes, this library is provided by the operating system itself, for example, libc for the Linux kernel, or the WinAPI for the Windows operating system, and most of the time it is wrapped around by our programming languages.
Its name may vary per language, but here are some popular names:

```
Expand Down Expand Up @@ -51,8 +51,8 @@ If you have done everything correct, your project should look like this:

And the main file, should look something like this:

```rust,fp=main.rs
#![function!("snippets/src/book/init.rs", main)]
```rust,playground
#![function!("snippets/src/book/ch01_01/init.rs", main)]
```


Expand Down Expand Up @@ -121,8 +121,8 @@ def failing_function(x: str):
```

Instead, Rust provides us with the `panic!` macro, which will call the `Panic Handler`. This function is very important and it will be called every time the `panic!` macro is invoked, for example:
```rust,fp=main.rs
#![function!("snippets/src/book/panic.rs", main)]
```rust,playground
#![function!("snippets/src/book/ch01_01/panic.rs", main)]
```
Normally, the Standard Library provides us with an implementation of the Panic Handler, which will typically print the line number and file in which the error occurred. However, because we are now not using the Standard Library, we need to define the implementation of the function ourselves.
This function can be any function, as long as it includes the attribute `#[panic_handler]`. This attribute is added so the compiler will know which function to use when invoking the `panic!` macro, to enforce that only one function of this type exists, and to enforce the correct input argument signature and return type.
Expand All @@ -144,19 +144,19 @@ This means that it wants our function to receive a reference to a structure call
But what is this struct? and what is this weird type?

The `PanicInfo` struct includes basic information about our panic such as the location, and message. Its definition can be found in the Core library:
```rust,fp=<rust-doc>core/panic/panic_info.rs
#![struct!("snippets/src/book/panic.rs", PanicInfo)]
```rust
#![struct!("<rustc>/lib/rustlib/src/rust/library/core/src/panic/panic_info.rs", PanicInfo)]
```

The `!` type is a very special type in Rust, called the `never` type, as the type name may suggest, it says that a function should **never** return, which means our program will not continue after the function is called.
In a normal operating system, this is not a problem; just print the panic message + the location, and kill the process so it will not return. But in our own OS, unfortunately, this is not possible because there is not a process that we can exit. So, how can we prove to Rust we are not returning? By endlessly looping!

So at the end, this is the minimal definition of our handler, which results in the following code

```rust,fp=main.rs
#![function!("snippets/src/book/no_std.rs", main)]
```rust
#![function!("snippets/src/book/ch01_01/no_std.rs", main)]

#![function!("snippets/src/book/no_std.rs", panic_handler)]
#![function!("snippets/src/book/ch01_01/no_std.rs", panic_handler)]
```

This code unfortunately still doesn't compile, because we didn't handle the last error.
Expand Down Expand Up @@ -249,15 +249,18 @@ This will set our entry point to main, and our output into a raw binary, which m
[^5]: Operating systems have their own binary header so they can understand how to treat a binary. Some common ones are [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) and [PE](https://en.wikipedia.org/wiki/Portable_Executable)

Then, to make our linker to use this script, we mainly have two options; one is to add some arguments to our build command, and the other one is to create a [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html). In this book, we use the following build script:
```rust,fp=build.rs
#![source_file!("snippets/src/book/build.rs")]
```rust
#![source_file!("snippets/src/book/ch01_01/build.rs", 1:99)]
```

But, after we do all this and again, run `cargo build`, we get the same error. At first, this doesn't seem logical, because we defined a main function. But, although it is true that we defined one, we didn't consider Rust's default [mangling](https://doc.rust-lang.org/rustc/symbol-mangling/index.html).
This is a very clever idea done by Rust, and without it, things like the following wouldn't be possible:

```rust
#![source_file!("snippets/src/book/impl_ex.rs")]
#![struct!("snippets/src/book/ch01_01/general.rs", A)]
#![impl!("snippets/src/book/ch01_01/general.rs", A)]
#![struct!("snippets/src/book/ch01_01/general.rs", B)]
#![impl!("snippets/src/book/ch01_01/general.rs", A)]
```
Although the functions are defined on different structs, they have the same name. But, because of mangling, the actual name of the function would be something like
```
Expand All @@ -269,8 +272,8 @@ A similar thing is happening to our `main` function, which makes its name not ex
To fix it, we can add the `#[unsafe(no_mangle)]` attribute to our main function, which will make its name just 'main'.

Which makes this, our final main.rs file!
```rust,fp=main.rs
#![source_file!("snippets/src/book/minimal_main.rs")]
```rust
#![source_file!("snippets/src/book/ch01_01/minimal_main.rs", 1:99)]
```

## Build Target
Expand Down
26 changes: 16 additions & 10 deletions src/ch01-02-booting-our-binary.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ To print "Hello, World!", we can utilize the BIOS [video interrupt](https://en.w

_For now, don't worry about the code implementation and just use and play with it. This code piece, and a lot more will be explained in the next chapter._

```rust,fp=main.rs
#![source_file!("snippets/src/book/print.rs")]
```rust
#![source_file!("snippets/src/book/ch01_02/print.rs", 1:99)]
```

When we try to compile and run our code, we can see that it's indeed booting, but we don't see any message.
Expand All @@ -225,24 +225,30 @@ When we do that, we can notice that it seems that code was added, but at the end
<blockquote>

- **.text** - Includes the code of our program, which is the machine code that is generated for all of the functions

```rust,banner=no
#![source_file!("snippets/src/book/func.rs")]
#![source_file!("")]
#![function!("snippets/src/book/ch01_02/general.rs", some_function)]
#![]
```


- **.data** - Includes the initialized data of our program, like static variables.

```rust,banner=no
#![source_file!("snippets/src/book/static_var.rs")]
#![source_file!("")]
#![static!("snippets/src/book/ch01_02/general.rs", MESSAGE)]
#![]
```
- **.bss** - Includes the uninitialized data of our program

```rust,banner=no
#![source_file!("snippets/src/book/static_uninit.rs")]
#![source_file!("")]
#![static!("snippets/src/book/ch01_02/general.rs", UNINIT)]
#![]
```
- **.rodata** - Includes the read-only data of our program

```rust,banner=no
#![source_file!("snippets/src/book/static_str.rs")]
#![source_file!("")]
#![static!("snippets/src/book/ch01_02/general.rs", VAR)]
#![]
```
- **.eh_frame & .eh_frame_hdr** - Includes information that is relevant to exception handling and stack unwinding. These section are not relevant for us because we use `panic = "abort"`.
</blockquote>
Expand Down
12 changes: 6 additions & 6 deletions src/ch02-01-legacy-legacy-legacy.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ With that information, we can understand that the disk uses a 3D coordinate syst
<figure style="width: 60%; text-align: center;">
<img src="assets/Cylinder_Head_Sector.svg"
style="background-color: aliceblue; width: 80%; height: auto;">
</img>

<figcaption><strong>Figure 2-0:</strong> Cylinder Head Sector Diagram</figcaption>

</figure>
Expand Down Expand Up @@ -198,7 +198,7 @@ $$
After learning about LBA, the only logical thing to think, is how to read data from the disk using LBA instead of CHS.
This is where the `extended read` functions comes in; it expects a structure called the `disk address packet` which looks like this:

```rust,fp=<repo>bootloader/first_stage/src/disk.rs#L4
```rust
#![struct!("bootloader/first_stage/src/disk.rs", DiskAddressPacket)]
```

Expand All @@ -214,19 +214,19 @@ This is quite straight forward, we will create a `new` function that will initia

First, for organization, we will create some helpful enums:

```rust,fp=<repo>crates/common/src/enums/bios_interrupts.rs
```rust
#![enum!("crates/common/src/enums/bios_interrupts.rs", BiosInterrupts)]
#![enum!("crates/common/src/enums/bios_interrupts.rs", DiskInterrupt)]
```

Then, we can create an initializer function for our `disk packet`:

```rust,fp=<repo>bootloader/first_stage/src/disk.rs#L44
```rust
#![impl_method!("bootloader/first_stage/src/disk.rs", DiskAddressPacket::new)]
```
And then, finally the function that will call the interrupt with our packet, and will read the disk content into memory.

```rust,fp=<repo>bootloader/first_stage/src/disk.rs#L71
```rust
#![impl_method!("bootloader/first_stage/src/disk.rs", DiskAddressPacket::load)]
```

Expand All @@ -249,7 +249,7 @@ Then, we can get the disk number from the stack, and load our packet.
And create a constant for the disk number memory address
Then, in the first stage function

```rust,fp=<repo>bootloader/first_stage/src/main.rs#L29
```rust
#![const!("crates/common/src/constants/addresses.rs", DISK_NUMBER_OFFSET)]

#![function!("bootloader/first_stage/src/main.rs", load_dap)]
Expand Down
Loading
Loading