mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 22:37:49 +00:00
@@ -39,7 +39,7 @@ Now we place our root source file in `src/lib.rs`:
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn main() {}
|
pub extern fn rust_main() {}
|
||||||
|
|
||||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||||
#[lang = "panic_fmt"] extern fn panic_fmt() -> ! {loop{}}
|
#[lang = "panic_fmt"] extern fn panic_fmt() -> ! {loop{}}
|
||||||
@@ -50,7 +50,7 @@ Let's break it down:
|
|||||||
- The `features` attribute is used to allow the specified _feature-gated_ attributes in this crate. You can't do that in a stable/beta compiler, so this is one reason we need a Rust nighly.
|
- The `features` attribute is used to allow the specified _feature-gated_ attributes in this crate. You can't do that in a stable/beta compiler, so this is one reason we need a Rust nighly.
|
||||||
- The `no_std` attribute prevents the automatic linking of the standard library. We can't use `std` because it relies on operating system features like files, system calls, and various device drivers. Remember that currently the only “feature” of our OS is printing `OKAY` :).
|
- The `no_std` attribute prevents the automatic linking of the standard library. We can't use `std` because it relies on operating system features like files, system calls, and various device drivers. Remember that currently the only “feature” of our OS is printing `OKAY` :).
|
||||||
- A `#` without a `!` afterwards defines an attribute for the _following_ item (a function in our case).
|
- A `#` without a `!` afterwards defines an attribute for the _following_ item (a function in our case).
|
||||||
- The `no_mangle` attribute disables the automatic [name mangling] that Rust uses to get unique function names. We want to do a `call main` from our assembly code, so this function name must stay as it is.
|
- The `no_mangle` attribute disables the automatic [name mangling] that Rust uses to get unique function names. We want to do a `call rust_main` from our assembly code, so this function name must stay as it is.
|
||||||
- We mark our main function as `extern` to make it compatible to the standard C [calling convention].
|
- We mark our main function as `extern` to make it compatible to the standard C [calling convention].
|
||||||
- The `lang` attribute defines a Rust [language item].
|
- The `lang` attribute defines a Rust [language item].
|
||||||
- The `eh_personality` function is used for Rust's [unwinding] on `panic!`. We can leave it empty since we don't have any unwinding support in our OS yet.
|
- The `eh_personality` function is used for Rust's [unwinding] on `panic!`. We can leave it empty since we don't have any unwinding support in our OS yet.
|
||||||
@@ -88,15 +88,15 @@ Now we can call the main method in `long_mode_start`:
|
|||||||
bits 64
|
bits 64
|
||||||
long_mode_start:
|
long_mode_start:
|
||||||
; call the rust main
|
; call the rust main
|
||||||
extern main ; new
|
extern rust_main ; new
|
||||||
call main ; new
|
call rust_main ; new
|
||||||
|
|
||||||
; print `OKAY` to screen
|
; print `OKAY` to screen
|
||||||
mov rax, 0x2f592f412f4b2f4f
|
mov rax, 0x2f592f412f4b2f4f
|
||||||
mov qword [0xb8000], rax
|
mov qword [0xb8000], rax
|
||||||
hlt
|
hlt
|
||||||
```
|
```
|
||||||
By defining `main` as `extern` we tell nasm that the function is defined in another file. As the linker takes care of linking them together, we'll get a linker error if we have a typo in the name or forget to mark the rust function as `pub extern`.
|
By defining `rust_main` as `extern` we tell nasm that the function is defined in another file. As the linker takes care of linking them together, we'll get a linker error if we have a typo in the name or forget to mark the rust function as `pub extern`.
|
||||||
|
|
||||||
When we've done everything right, we still see the green `OKAY` when executing `make run`. That means that we successfully called the Rust function and returned back to assembly.
|
When we've done everything right, we still see the green `OKAY` when executing `make run`. That means that we successfully called the Rust function and returned back to assembly.
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ When we've done everything right, we still see the green `OKAY` when executing `
|
|||||||
Now we can try some Rust code:
|
Now we can try some Rust code:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub extern fn main() {
|
pub extern fn rust_main() {
|
||||||
let x = ["Hello", " ", "World", "!"];
|
let x = ["Hello", " ", "World", "!"];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -127,7 +127,7 @@ and an `extern crate` in our `src/lib.rs`:
|
|||||||
extern crate rlibc;
|
extern crate rlibc;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn main() {
|
pub extern fn rust_main() {
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
Now `make run` doesn't complain about `memcpy` anymore. Instead it will show a pile of new errors:
|
Now `make run` doesn't complain about `memcpy` anymore. Instead it will show a pile of new errors:
|
||||||
@@ -201,7 +201,7 @@ Unfortunately there is one last problem left that gets triggered by the followin
|
|||||||
let mut a = 42;
|
let mut a = 42;
|
||||||
a += 1;
|
a += 1;
|
||||||
```
|
```
|
||||||
When we add that code to `main` and test it using `make run`, the OS will constantly reboot itself. Let's try to debug it.
|
When we add that code to `rust_main` and test it using `make run`, the OS will constantly reboot itself. Let's try to debug it.
|
||||||
|
|
||||||
[iter.rs:223]: https://doc.rust-lang.org/nightly/src/core/iter.rs.html#223
|
[iter.rs:223]: https://doc.rust-lang.org/nightly/src/core/iter.rs.html#223
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ setup_SSE:
|
|||||||
```
|
```
|
||||||
The code is from the great [OSDev Wiki][osdev sse] again. Notice that it sets/unsets exactly the bits that can cause the `Invalid Opcode` exception.
|
The code is from the great [OSDev Wiki][osdev sse] again. Notice that it sets/unsets exactly the bits that can cause the `Invalid Opcode` exception.
|
||||||
|
|
||||||
When we insert a `call setup_SSE` right before calling `main`, our Rust code will finally work.
|
When we insert a `call setup_SSE` right before calling `rust_main`, our Rust code will finally work.
|
||||||
|
|
||||||
[32-bit error function]: {{ site.url }}{{ page.previous.url }}#some-tests
|
[32-bit error function]: {{ site.url }}{{ page.previous.url }}#some-tests
|
||||||
[osdev sse]: http://wiki.osdev.org/SSE#Checking_for_SSE
|
[osdev sse]: http://wiki.osdev.org/SSE#Checking_for_SSE
|
||||||
@@ -304,7 +304,7 @@ Now that we're editing assembly anyway, we should change the `OKAY` message to s
|
|||||||
|
|
||||||
```nasm
|
```nasm
|
||||||
...
|
...
|
||||||
call main
|
call rust_main
|
||||||
|
|
||||||
.os_returned:
|
.os_returned:
|
||||||
; rust main returned, print `OS returned!`
|
; rust main returned, print `OS returned!`
|
||||||
@@ -331,7 +331,7 @@ extern crate rlibc;
|
|||||||
use core::intrinsics::offset;
|
use core::intrinsics::offset;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn main() {
|
pub extern fn rust_main() {
|
||||||
// ATTENTION: we have a very small stack and no guard page
|
// ATTENTION: we have a very small stack and no guard page
|
||||||
let x = ["Hello", " ", "World", "!"];
|
let x = ["Hello", " ", "World", "!"];
|
||||||
let screen_pointer = 0xb8000 as *const u16;
|
let screen_pointer = 0xb8000 as *const u16;
|
||||||
|
|||||||
Reference in New Issue
Block a user