OS in Rust
0.rustc protects$ cargo r
Compiling divzero v0.1.0 (/home/user/tmp/divzero)
error: this operation will panic at runtime
--> src/main.rs:3:20
|
3 | println!("{}", 1 / 0);
| ^^^^^ attempt to divide `1_i32` by zero
|
= note: `#[deny(unconditional_panic)]` on by default
error: could not compile `divzero` (bin "divzero") due to 1 previous error#[allow(unconditional_panic)]rustc provided panic handler.$ cargo r
Compiling divzero v0.1.0 (/home/user/tmp/divzero)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/divzero`
thread 'main' (2292) panicked at src/main.rs:3:14:
attempt to divide by zero
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace$ gcc main.c -std=c89 -Wall -Wextra -Werror -Wpedantic -O2 -o main
main.c: In function ‘main’:
main.c:2:19: error: division by zero [-Werror=div-by-zero]
2 | int x = 1 / 0;
| ^
main.c:2:13: error: unused variable ‘x’ [-Werror=unused-variable]
2 | int x = 1 / 0;
| ^
cc1: all warnings being treated as errorsgcc you will get the following:clang fans (vs. gcc)clang does not trigger an exception.$ cat main.c
#include <stdio.h>
int main() {
int x = 1 / 0;
printf("%d\n", x);
return 0;
}
user@cd-desk:~/tmp/divzero$ clang main.c -o main
main.c:4:12: warning: division by zero is undefined [-Wdivision-by-zero]
int x = 1 / 0;
^ ~
1 warning generated.
user@cd-desk:~/tmp/divzero$ ./main
267243840
user@cd-desk:~/tmp/divzero$ ./main
2140340544clang fans.gcc does and therefore so should you.On x86, there are about 20 different CPU exception types. The most important are:
On x86, there are about 20 different CPU exception types. The most important are:
On x86, there are about 20 different CPU exception types. The most important are:
On x86, there are about 20 different CPU exception types. The most important are:
On x86, there are about 20 different CPU exception types. The most important are:
| Type | Name | Description |
|---|---|---|
| u16 | Function Pointer [0:15] | The lower bits of the pointer to the handler function. |
| u16 | GDT selector | Selector of a code segment in the global descriptor table. |
| u16 | Options | (next slide) |
| u16 | Function Pointer [16:31] | The middle bits of the pointer to the handler function. |
| u32 | Function Pointer [32:63] | The remaining bits of the pointer to the handler function. |
| u32 | Reserved |
| Bits | Name | Description |
|---|---|---|
| 0-2 | Interrupt Stack Table Index | 0: Don’t switch stacks, 1-7: Switch to the n-th stack in the Interrupt Stack Table when this handler is called. |
| 3-7 | Reserved | |
| 8 | 0: Interrupt Gate, 1: Trap Gate | If this bit is 0, interrupts are disabled when this handler is called. |
| 9-11 | must be one | |
| 12 | must be zero | |
| 13-14 | Descriptor Privilege Level (DPL) | The minimal privilege level required for calling this handler. |
| 15 | Present |
When an exception occurs, the CPU roughly does the following:
| Bit | Mask | Name | Description | Category | =1 | =0 |
|---|---|---|---|---|---|---|
| 0 | 0x0001 | CF | Carry flag | Status | CY (Carry) | NC (No Carry) |
| 1 | 0x0002 | — | Reserved, always 1 in EFLAGS | — | — | — |
| 2 | 0x0004 | PF | Parity flag | Status | PE (Parity Even) | PO (Parity Odd) |
| 3 | 0x0008 | — | Reserved | — | — | — |
| 4 | 0x0010 | AF | Auxiliary Carry flag | Status | AC (Auxiliary Carry) | NA (No Auxiliary Carry) |
| 5 | 0x0020 | — | Reserved | — | — | — |
| Bit | Mask | Name | Description | Category | =1 | =0 |
|---|---|---|---|---|---|---|
| 6 | 0x0040 | ZF | Zero flag | Status | ZR (Zero) | NZ (Not Zero) |
| 7 | 0x0080 | SF | Sign flag | Status | NG (Negative) | PL (Positive) |
| 8 | 0x0100 | TF | Trap flag (single step) | Control | — | — |
| 9 | 0x0200 | IF | Interrupt enable flag | Control | EI (Enable Interrupt) | DI (Disable Interrupt) |
| 10 | 0x0400 | DF | Direction flag | Control | DN (Down) | UP (Up) |
| Bit | Mask | Name | Description | Category | =1 | =0 |
|---|---|---|---|---|---|---|
| 11 | 0x0800 | OF | Overflow flag | Status | OV (Overflow) | NV (Not Overflow) |
| 12–13 | 0x3000 | IOPL | I/O privilege level (286+) | System | — | — |
| 14 | 0x4000 | NT | Nested task flag (286+) | System | — | — |
| 15 | 0x8000 | MD | Mode flag (NEC V-series only) | Control | Native Mode (186) | Emulation Mode (8080) |
the
ininstruction
To communicate with such an I/O port, there are special CPU instructions called
inandout, which take a port number and a data byte
in via the x86_64 crate to print to serial.current privilege level
Used to prevent virtual machine escape, safely sandbox browser code.
When an exception occurs, the CPU roughly does the following:
When an exception occurs, the CPU roughly does the following:
When an exception occurs, the CPU roughly does the following:
When an exception occurs, the CPU roughly does the following:
When an exception occurs, the CPU roughly does the following:
When an exception occurs, the CPU roughly does the following:
InterruptDescriptorTable struct of the x86_64 crate.#[repr(C)]
pub struct InterruptDescriptorTable {
pub divide_by_zero: Entry<HandlerFunc>,
pub debug: Entry<HandlerFunc>,
pub non_maskable_interrupt: Entry<HandlerFunc>,
pub breakpoint: Entry<HandlerFunc>,
pub overflow: Entry<HandlerFunc>,
pub bound_range_exceeded: Entry<HandlerFunc>,
pub invalid_opcode: Entry<HandlerFunc>,
pub device_not_available: Entry<HandlerFunc>,
pub double_fault: Entry<HandlerFuncWithErrCode>,
pub invalid_tss: Entry<HandlerFuncWithErrCode>,
pub segment_not_present: Entry<HandlerFuncWithErrCode>,
pub stack_segment_fault: Entry<HandlerFuncWithErrCode>,
pub general_protection_fault: Entry<HandlerFuncWithErrCode>,
pub page_fault: Entry<PageFaultHandlerFunc>,
pub x87_floating_point: Entry<HandlerFunc>,
pub alignment_check: Entry<HandlerFuncWithErrCode>,
pub machine_check: Entry<HandlerFunc>,
pub simd_floating_point: Entry<HandlerFunc>,
pub virtualization: Entry<HandlerFunc>,
pub security_exception: Entry<HandlerFuncWithErrCode>,
// some fields omitted
}idt::Entry<F>
F defines the expected handler function type.
HandlerFunc first:extern "x86-interrupt" fn typeextern for C, here we use it to interface with hardware.x86-interrupt calling convention:
call instruction.
In bonus lecture “The Call”