├── .gitignore
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── app_background
├── .cargo
│ └── config.toml
├── .cargo_x86
│ └── config.toml
├── Cargo.lock
├── Cargo.toml
├── rust-toolchain
├── src
│ ├── main.rs
│ ├── qr.png
│ └── st.rs
└── x86_64.json
├── app_c
├── README.md
├── build.sh
└── main.c
├── app_console
├── .cargo
│ └── config.toml
├── Cargo.lock
├── Cargo.toml
├── rust-toolchain
├── src
│ ├── main.rs
│ └── st.rs
└── x86_64.json
├── app_cursor
├── .cargo
│ └── config.toml
├── Cargo.lock
├── Cargo.toml
├── rust-toolchain
├── src
│ ├── main.rs
│ └── st.rs
└── x86_64.json
├── app_test
├── .cargo
│ └── config.toml
├── Cargo.lock
├── Cargo.toml
├── rust-toolchain
├── src
│ └── main.rs
└── x86_64.json
├── assets
└── demo.mp4
├── bootloader
├── .cargo
│ └── config.toml
├── Cargo.lock
├── Cargo.toml
├── build.rs
├── kernel
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── src
│ │ ├── allocator.rs
│ │ ├── app.rs
│ │ ├── drivers
│ │ ├── mod.rs
│ │ ├── virtio_gpu.rs
│ │ └── virtio_input.rs
│ │ ├── framebuffer.rs
│ │ ├── gdt.rs
│ │ ├── globals.rs
│ │ ├── interrupts.rs
│ │ ├── ioapic.rs
│ │ ├── local_apic.rs
│ │ ├── logger.rs
│ │ ├── main.rs
│ │ ├── memory.rs
│ │ ├── pci.rs
│ │ ├── serial.rs
│ │ ├── task
│ │ ├── executor.rs
│ │ └── mod.rs
│ │ └── virtio.rs
├── ovmf
├── rust-toolchain
└── src
│ └── main.rs
├── build.sh
└── docs
└── BUILD.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 |
3 | */target
4 | replay.bin
5 | uefi.img
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // "rust-analyzer.check.allTargets": false,
3 | // "rust-analyzer.check.extraArgs": [
4 | // "--target",
5 | // "x86_64"
6 | // ],
7 | "rust-analyzer.linkedProjects": [
8 | "./bootloader/Cargo.toml",
9 | "./app_background/Cargo.toml",
10 | "./app_console/Cargo.toml",
11 | "./app_cursor/Cargo.toml",
12 | "./app_test/Cargo.toml"
13 | ],
14 | "git.ignoreLimitWarning": true
15 | }
16 |
17 | // "app_back",
18 | // "bootloader",
19 | // "func",
20 | // "app_cursor",
21 | // "vconsol",
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Thomas SIMON
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > You can support this night time project by hiring me for a day time job !
2 |
3 | # Fomos
4 |
5 | Experimental OS, built with Rust
6 |
7 | https://github.com/Ruddle/Fomos/assets/14235713/3ee75d5e-5ebe-4cc1-b267-8b73337ee157
8 |
9 | **Fun fact**: there are 3 apps running in the video. A background app, a cursor app, and a console app.
10 |
11 | # Why
12 |
13 | I wanted to experiment with Non-Unix OS ideas.
14 |
15 | Exo-kernels are interesting, but it is mostly a theory. This project helps me understand the challenges involved in that pattern.
16 |
17 | OS development is extremely hard, Rust makes it more bearable.
18 |
19 | # Features
20 |
21 | - Has a graphical output
22 | - Dynamic allocation
23 | - Load and run concurrent apps
24 | - All apps run in an async loop
25 | - Support Virtio mouse and keyboard (drivers are async tasks)
26 | - Cooperative scheduling (apps yield control as much as possible)
27 | - No context switches once booted
28 | - _Nearly support Virgl_ ™
29 |
30 | There is 5 examples of apps in this repo named `app_*`, some in Rust, one in C.
31 | The kernel is in `bootloader`.
32 |
33 | # What is unique
34 |
35 | The signature of an app in Fomos:
36 |
37 | ```rust
38 | pub extern "C" fn _start(ctx: &mut Context) -> i32
39 | ```
40 |
41 | Apps do not need a standard library, any OS functionality is given to the app through the _Context_.
42 |
43 | the _Context_ is mostly a pointer to a bag of kernel functionnalities
44 |
45 | ```rust
46 | pub extern "C" fn
47 | ```
48 |
49 | In Fomos, an app is really just a **function**. There is nothing else ! This is a **huge** claim. An executable for a Unix or Windows OS is extremely complex compared to a freestanding function.
50 |
51 | ``
52 |
53 | It is out a frustration for all my Glibc problems during day job dev on linux that I chose to try this approach.
54 |
55 | I want a flat contract between an app and the OS. So what if an app was a function ? The contract is then **only** the explicit argument type.
56 |
57 | In Unix, an app has to know the target OS, but also what standard library it uses, that is 2 levels of indirections. Sometimes the os level has a conflict, sometimes the standard library level has a conflict, and sometimes I just don't have the level to understand why something doesn't work. I merely know it is related.
58 |
59 | ``
60 |
61 | I am trying to know if it is possible to have an OS-App ecosystem that does not suppose **ANY** **implicit** configuration. An app would **JUST** have to handle its explicit `start` _context_ argument.
62 |
63 | _Context_ gives any OS function necessary, think alloc, free, access to a framebuffer, or any hardware, any system calls etc.
64 |
65 | That way, apps could be freestanding, and compatible on multiple OS.
66 |
67 | ### More about Context
68 |
69 | Here is the _Context_ for the last version of this OS
70 |
71 | ```rust
72 | #[repr(C)]
73 | pub struct Context<'a, T> {
74 | pub version: u8,
75 | pub start_time: u64,
76 | pub log: extern "C" fn(s: *const u8, l: u32),
77 | pub pid: u64,
78 | pub fb: FB<'a>,
79 | pub calloc: extern "C" fn(usize, usize) -> *mut u8,
80 | pub cdalloc: extern "C" fn(*mut u8, usize, usize),
81 | pub store: &'a mut Option>,
82 | pub input: &'a Input,
83 | }
84 | ```
85 |
86 | Note that `app_test` for instance, uses an old version of the _Context_, and still works on the newer version of the OS
87 |
88 | Old Context used by `app_test`:
89 |
90 | ```rust
91 | #[repr(C)]
92 | pub struct Context<'a> {
93 | pub version: u8,
94 | start_time: u64,
95 | log: extern "C" fn(s: *const u8, l: u32),
96 | pid: u64,
97 | fb: FB<'a>,
98 | }
99 | ```
100 |
101 | Meaning Fomos already handles gracefully Apps designed for a much older version of itself. As long as the OS stays compatible with the old stuff in the context, it can add new functionalities for other App by just appending to the context the new functions (here calloc, cdalloc, store, and input).
102 |
103 | `app_test` precedes the dynamic allocation age !
104 |
105 | Could that pattern work in the long term ?
106 |
107 | ### How about system calls
108 |
109 | None. Lets try to put everything into _Context_ functions. No voodoo cpu instruction magic.
110 |
111 | > But how do you give back control to the OS ?
112 |
113 | Just
114 |
115 | ```rust
116 | return;
117 | ```
118 |
119 | > How do you sleep, or wait asynchronously ?
120 |
121 | Just
122 |
123 | ```rust
124 | return;
125 | ```
126 |
127 | Apps are **cooperative** in Fomos, They can just return (which would exit permanently an app on a classic OS), and assume that they are gonna be called through their only function `start` again soon, maybe even instantly if the "system call" works that way.
128 |
129 | > But an app loses all RAM data everytime it yields that way !
130 |
131 | No, an app can store anything it wants in Context.store during its execution, and get it back every `start` call. The OS keeps everything in RAM (on the heap). The stack itself is "reset". But it is not more "reset" than it is after any function execution in a normal program. You don't lose anything. In Fomos, apps are merely a single function called multiple times!
132 |
133 | Over simplification of the kernel loop:
134 |
135 | ```rust
136 | loop {
137 | for app in apps.iter_mut() {
138 | app._start(Context::new(...));
139 | }
140 | }
141 | ```
142 |
143 | There are a lot of questions without answer yet, but by now you might be curious, what if all the question had an answer in the pattern ? It looks like it could actually work (with a lot of work).
144 |
145 | # Advantages
146 |
147 | A lot of stuff comes free once you accept the premises.
148 |
149 | #### Sandboxing, instrumentation, debugging
150 |
151 | Every functionnality and side effect given to an app goes explicitely through the _Context_. The _Context_ is just a struct, we can wrap or replace anything in it.
152 | Lets instrument an app we'll call `special_app`. Over simplification :
153 |
154 | ```rust
155 | loop {
156 | for normal_app in normal_apps.iter_mut() {
157 | app._start(Context::new(alloc,..));
158 | }
159 | // special_app alloc instrumentation
160 | fn alloc_log(..){log("allocation detected!"); return alloc(..);}
161 | special_app._start(Context::new(alloc_log,..));
162 | }
163 | ```
164 |
165 | #### Restart, sleep, change of hardware
166 |
167 | An app memory lives in its context. The stack is fleeting. It is reset after each yield and doesn't mean much in Fomos.
168 | Since the _Context_ is explicit, it can be stored. A restart _can_ be made completely transparent to an app.
169 |
170 | Pseudo code:
171 |
172 | ```rust
173 | //kernel just started
174 | ...
175 | let app = App::new(..);
176 | let ctx = disk.load(app.id).unwrap_or(Context::new(..));
177 | loop{
178 | app._start(ctx);
179 | if restart_request{
180 | disk.save(app.id, ctx)
181 | break;
182 | }
183 | }
184 | //handle restart
185 | ...
186 | ```
187 |
188 | Quickload and quicksave of an app complete state is trivial.
189 | Note that some change of hardware could make an app bug. It would be a problem if it was transparent. However, it could be made opaque and obvious, in an opt-in manner, again through the _Context_.
190 |
191 | # Disadvantages
192 |
193 | ### Security
194 |
195 | Right now it is not implemented, any app can casually check the ram of another app ^^. This is going to be a hard problem to solve. I have plans to have data security without context switch, and without giving every damn app its own virtual memory stack.
196 |
197 | ### Cooperative vs preemptive scheduling
198 |
199 | The argument that a cooperative scheduling is doomed to fail is overblown. Apps are already very much cooperative.
200 | For proof, run a version of that on your nice preemptive system :
201 |
202 | ```js
203 | while(true){
204 | new Thread( () => {
205 | fs.writeFile("/home/"+randomString(),randomString())
206 | malloc(randomInt())
207 | curl("http://"+randomString()+".com")
208 | }
209 | }
210 | ```
211 |
212 | - Blender does a compelling impression of that when you increase the level of details one too many times. Might fill your swap and crash unsaved work on other apps.
213 | - Badly written Webgl websites crash my gpu driver.
214 |
215 | Not only is preemptive scheduling not enough, IMO it is not necessary. Also it is a spectrum. A system can be optimistically cooperative, and turn preemptive pessimistically.
216 |
217 | However the ecosystem is made for preemptive OS. There is friction in doing things differently.
218 |
219 | # Missing
220 |
221 | - Permanent storage (should be easy since virtio is already implemented)
222 | - Gpu support (virgl wip)
223 | - Networking
224 | - A nice abstraction for apps to share data and functionnalities between themselves
225 |
226 | The rest should live in userland.
227 |
228 | # Building
229 |
230 | run
231 |
232 | ```sh
233 | ./build.sh
234 | ```
235 |
236 | _You might need rust nightly, gcc, qemu with virgl & sdl flag_
237 |
238 | [More info here](/docs/BUILD.md)
239 |
240 | # Credit
241 |
242 | Heavily inspired by [Philipp Oppermann's blog](https://os.phil-opp.com/).
243 |
244 | Thanks to [darbysauter](https://github.com/darbysauter/myOS) for the advice given.
245 |
--------------------------------------------------------------------------------
/app_background/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std-features = ["compiler-builtins-mem"]
3 | build-std = ["core", "compiler_builtins","alloc"]
4 |
5 | [build]
6 | target = "x86_64.json"
--------------------------------------------------------------------------------
/app_background/.cargo_x86/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std-features = ["compiler-builtins-mem"]
3 | build-std = ["core", "compiler_builtins","alloc"]
4 |
5 | [build]
6 | target = "x86_64.json"
--------------------------------------------------------------------------------
/app_background/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "adler"
7 | version = "1.0.2"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
10 |
11 | [[package]]
12 | name = "approx"
13 | version = "0.5.1"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 | checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
16 | dependencies = [
17 | "num-traits",
18 | ]
19 |
20 | [[package]]
21 | name = "arrform"
22 | version = "0.1.1"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "e7cf566ecc5c9d82b973e81d30babf6583c9b497f86295c952d538c3254ef4e6"
25 |
26 | [[package]]
27 | name = "autocfg"
28 | version = "1.1.0"
29 | source = "registry+https://github.com/rust-lang/crates.io-index"
30 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
31 |
32 | [[package]]
33 | name = "bit_field"
34 | version = "0.10.2"
35 | source = "registry+https://github.com/rust-lang/crates.io-index"
36 | checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
37 |
38 | [[package]]
39 | name = "bitflags"
40 | version = "1.3.2"
41 | source = "registry+https://github.com/rust-lang/crates.io-index"
42 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
43 |
44 | [[package]]
45 | name = "bitfrob"
46 | version = "0.2.3"
47 | source = "registry+https://github.com/rust-lang/crates.io-index"
48 | checksum = "fb18fff2e974c4b95a45f47398bb6ed5b040ccdaac9d41ed045d33dbe960f75f"
49 |
50 | [[package]]
51 | name = "bytemuck"
52 | version = "1.13.1"
53 | source = "registry+https://github.com/rust-lang/crates.io-index"
54 | checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
55 |
56 | [[package]]
57 | name = "func"
58 | version = "0.1.0"
59 | dependencies = [
60 | "arrform",
61 | "imagine",
62 | "libm",
63 | "vek",
64 | "x86_64",
65 | ]
66 |
67 | [[package]]
68 | name = "imagine"
69 | version = "0.4.0"
70 | source = "registry+https://github.com/rust-lang/crates.io-index"
71 | checksum = "c24475037443b4c1d7ae5da440b07ee4eeec46311ed7e5c8cdc97e6ef03948f5"
72 | dependencies = [
73 | "bitfrob",
74 | "bytemuck",
75 | "miniz_oxide",
76 | "wide",
77 | ]
78 |
79 | [[package]]
80 | name = "libm"
81 | version = "0.2.6"
82 | source = "registry+https://github.com/rust-lang/crates.io-index"
83 | checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
84 |
85 | [[package]]
86 | name = "miniz_oxide"
87 | version = "0.6.2"
88 | source = "registry+https://github.com/rust-lang/crates.io-index"
89 | checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
90 | dependencies = [
91 | "adler",
92 | ]
93 |
94 | [[package]]
95 | name = "num-integer"
96 | version = "0.1.45"
97 | source = "registry+https://github.com/rust-lang/crates.io-index"
98 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
99 | dependencies = [
100 | "autocfg",
101 | "num-traits",
102 | ]
103 |
104 | [[package]]
105 | name = "num-traits"
106 | version = "0.2.15"
107 | source = "registry+https://github.com/rust-lang/crates.io-index"
108 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
109 | dependencies = [
110 | "autocfg",
111 | "libm",
112 | ]
113 |
114 | [[package]]
115 | name = "rustc_version"
116 | version = "0.4.0"
117 | source = "registry+https://github.com/rust-lang/crates.io-index"
118 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
119 | dependencies = [
120 | "semver",
121 | ]
122 |
123 | [[package]]
124 | name = "rustversion"
125 | version = "1.0.12"
126 | source = "registry+https://github.com/rust-lang/crates.io-index"
127 | checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
128 |
129 | [[package]]
130 | name = "safe_arch"
131 | version = "0.6.0"
132 | source = "registry+https://github.com/rust-lang/crates.io-index"
133 | checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529"
134 | dependencies = [
135 | "bytemuck",
136 | ]
137 |
138 | [[package]]
139 | name = "semver"
140 | version = "1.0.17"
141 | source = "registry+https://github.com/rust-lang/crates.io-index"
142 | checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
143 |
144 | [[package]]
145 | name = "vek"
146 | version = "0.15.10"
147 | source = "registry+https://github.com/rust-lang/crates.io-index"
148 | checksum = "8085882662f9bc47fc8b0cdafa5e19df8f592f650c02b9083da8d45ac9eebd17"
149 | dependencies = [
150 | "approx",
151 | "num-integer",
152 | "num-traits",
153 | "rustc_version",
154 | ]
155 |
156 | [[package]]
157 | name = "volatile"
158 | version = "0.4.6"
159 | source = "registry+https://github.com/rust-lang/crates.io-index"
160 | checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793"
161 |
162 | [[package]]
163 | name = "wide"
164 | version = "0.7.8"
165 | source = "registry+https://github.com/rust-lang/crates.io-index"
166 | checksum = "b689b6c49d6549434bf944e6b0f39238cf63693cb7a147e9d887507fffa3b223"
167 | dependencies = [
168 | "bytemuck",
169 | "safe_arch",
170 | ]
171 |
172 | [[package]]
173 | name = "x86_64"
174 | version = "0.14.10"
175 | source = "registry+https://github.com/rust-lang/crates.io-index"
176 | checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69"
177 | dependencies = [
178 | "bit_field",
179 | "bitflags",
180 | "rustversion",
181 | "volatile",
182 | ]
183 |
--------------------------------------------------------------------------------
/app_background/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "func"
3 | version = "0.1.0"
4 | edition = "2021"
5 | [[bin]]
6 | name="func"
7 | test = false
8 | bench = false
9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10 |
11 | [dependencies]
12 | imagine = { version= "0.4.0"}
13 | x86_64 = { version = "0.14.8" }
14 | arrform = "0.1.1"
15 | vek = { version = "0.15.10", default-features = false, features = ["libm"] }
16 | libm = "0.2.6"
17 | # [dependencies.zune-jpeg]
18 | # version ="0.3.14"
19 | # default-features = false
20 | # features = ["x86"]
21 |
22 |
23 | [features]
24 | default = []
25 |
26 | [profile.dev]
27 | panic = "abort"
28 |
29 | [profile.release]
30 | panic = "abort"
31 | lto = true
32 | strip = true
33 | codegen-units = 1
34 |
35 | [workspace]
36 |
37 | #RUSTFLAGS="-C relocation-model=pie -C link-arg=-nostartfiles -C link-arg=-pie"
38 |
39 | # RUSTFLAGS="-C relocation-model=pie -C link-arg=-nostartfiles -C link-arg=-pie" cargo build --release --target x86_64-unknown-linux-gnu
40 |
41 |
42 | # CURRENT WORKING with custom target in .cargo
43 | # RUSTFLAGS="-C relocation-model=pie -C link-arg=-pie" cargo build --release
--------------------------------------------------------------------------------
/app_background/rust-toolchain:
--------------------------------------------------------------------------------
1 | nightly
--------------------------------------------------------------------------------
/app_background/src/main.rs:
--------------------------------------------------------------------------------
1 | #![no_std]
2 | #![no_main]
3 | #![feature(alloc_error_handler)]
4 |
5 | extern crate alloc;
6 | mod st;
7 |
8 | use st::*;
9 |
10 | use alloc::boxed::Box;
11 | use imagine::pixel_formats::RGBA8888;
12 |
13 | const IMG: &[u8] = include_bytes!("./qr.png");
14 |
15 | pub struct Store {
16 | pix: imagine::image::Bitmap,
17 | }
18 |
19 | #[no_mangle]
20 | pub extern "C" fn _start(ctx: &mut Context) -> i32 {
21 | unsafe { ALLOCATOR.swap(ctx) };
22 | unsafe { LOGGER.swap(ctx.log) };
23 |
24 | // (ctx.log)("back start");
25 | // x86_64::instructions::interrupts::int3();
26 |
27 | let store: Box;
28 | if let Some(ptr) = ctx.store.take() {
29 | store = ptr;
30 | } else {
31 | st::log("store not found");
32 | let pix = imagine::image::Bitmap::try_from_png_bytes(IMG);
33 | if pix.is_none() {
34 | st::log("No pix");
35 | return -1;
36 | }
37 | store = Box::new(Store { pix: pix.unwrap() })
38 | }
39 |
40 | let pix = &store.pix;
41 |
42 | let dx = (libm::cosf((ctx.start_time as f32) * 0.001) * 2.0) as usize;
43 |
44 | for y in 0..ctx.fb.h {
45 | for x in 0..ctx.fb.w {
46 | let lx = x as f32 / (ctx.fb.w) as f32;
47 | let ly = y as f32 / (ctx.fb.h) as f32;
48 | let px = (lx * pix.width as f32) as usize;
49 | let py = (ly * pix.height as f32) as usize;
50 | let v = pix.pixels[px + py * pix.width as usize];
51 | let p = &mut ctx.fb.pixels[x + y * ctx.fb.w];
52 | p.r = v.r;
53 | p.g = v.g;
54 | p.b = v.b;
55 | }
56 | }
57 |
58 | *ctx.store = Some(store);
59 |
60 | return 0;
61 | }
62 |
--------------------------------------------------------------------------------
/app_background/src/qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ruddle/Fomos/336be2d5bb2733f27e593dec70034a4f59650efd/app_background/src/qr.png
--------------------------------------------------------------------------------
/app_background/src/st.rs:
--------------------------------------------------------------------------------
1 | #[panic_handler]
2 | fn panic(info: &core::panic::PanicInfo) -> ! {
3 | x86_64::instructions::interrupts::int3();
4 | unsafe {
5 | (LOGGER.f)("panic".as_ptr(), 5);
6 | };
7 | unsafe {
8 | let s = &format!("{:?}", info);
9 | (LOGGER.f)(s.as_ptr(), s.len() as u32)
10 | };
11 | loop {}
12 | }
13 |
14 | pub static mut LOGGER: Logger = Logger::init();
15 |
16 | pub fn log(s: &str) {
17 | unsafe { (LOGGER.f)(s.as_ptr(), s.len() as u32) }
18 | }
19 |
20 | type LogFn = extern "C" fn(*const u8, u32);
21 | extern "C" fn nop(s: *const u8, l: u32) {}
22 | pub struct Logger {
23 | pub f: LogFn,
24 | }
25 | impl Logger {
26 | pub const fn init() -> Self {
27 | Self { f: nop }
28 | }
29 | pub fn swap(&mut self, f2: LogFn) {
30 | self.f = f2;
31 | }
32 | }
33 | #[repr(C)]
34 | pub struct Context<'a, T> {
35 | pub version: u8,
36 | pub start_time: u64,
37 | pub log: extern "C" fn(s: *const u8, l: u32),
38 | pub pid: u64,
39 | pub fb: FB<'a>,
40 | pub calloc: extern "C" fn(usize, usize) -> *mut u8,
41 | pub cdalloc: extern "C" fn(*mut u8, usize, usize),
42 | pub store: &'a mut Option>,
43 | pub input: &'a Input,
44 | }
45 |
46 | const HISTORY_SIZE: usize = 64;
47 |
48 | #[repr(C)]
49 | #[derive(Clone, Debug, Copy)]
50 | pub struct InputEvent {
51 | pub trigger: bool,
52 | pub key: usize,
53 | }
54 | #[repr(C)]
55 | pub struct Input {
56 | pub mx: usize,
57 | pub my: usize,
58 | pub keys: [u8; 1024],
59 | pub history_last_index: usize,
60 | pub history_ring: [InputEvent; HISTORY_SIZE],
61 | }
62 |
63 | #[derive(Debug, Clone, Copy, PartialEq, Eq)]
64 | #[repr(C)]
65 | pub struct RGBA {
66 | pub r: u8,
67 | pub g: u8,
68 | pub b: u8,
69 | pub a: u8,
70 | }
71 |
72 | #[repr(C)]
73 | pub struct FB<'a> {
74 | pub pixels: &'a mut [RGBA],
75 | pub w: usize,
76 | pub h: usize,
77 | }
78 |
79 | use core::alloc::GlobalAlloc;
80 |
81 | use alloc::{boxed::Box, format};
82 |
83 | extern "C" fn a_init(size: usize, align: usize) -> *mut u8 {
84 | panic!("")
85 | }
86 | extern "C" fn d_init(ptr: *mut u8, size: usize, align: usize) {
87 | panic!("")
88 | }
89 | #[repr(C)]
90 | pub struct AllocFromCtx {
91 | a: extern "C" fn(usize, usize) -> *mut u8,
92 | d: extern "C" fn(*mut u8, usize, usize),
93 | }
94 | unsafe impl GlobalAlloc for AllocFromCtx {
95 | unsafe fn alloc(&self, layout: alloc::alloc::Layout) -> *mut u8 {
96 | (self.a)(layout.size(), layout.align())
97 | }
98 |
99 | unsafe fn dealloc(&self, ptr: *mut u8, layout: alloc::alloc::Layout) {
100 | (self.d)(ptr, layout.size(), layout.align());
101 | }
102 | }
103 | impl AllocFromCtx {
104 | pub const fn init() -> Self {
105 | Self {
106 | a: a_init,
107 | d: d_init,
108 | }
109 | }
110 | pub fn swap(&mut self, ctx: &mut Context) {
111 | let ptr = self;
112 | ptr.a = ctx.calloc;
113 | ptr.d = ctx.cdalloc;
114 | }
115 | }
116 | #[global_allocator]
117 | pub static mut ALLOCATOR: AllocFromCtx = AllocFromCtx::init();
118 |
--------------------------------------------------------------------------------
/app_background/x86_64.json:
--------------------------------------------------------------------------------
1 | {
2 | "llvm-target": "x86_64-unknown-none",
3 | "code-model": "small",
4 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
5 | "arch": "x86_64",
6 | "target-endian": "little",
7 | "target-pointer-width": "64",
8 | "target-c-int-width": "32",
9 | "os": "none",
10 | "executables": true,
11 | "linker-flavor": "ld.lld",
12 | "linker": "rust-lld",
13 | "relocation-model": "pie",
14 | "position-independent-executables": true,
15 | "static-position-independent-executables": true,
16 | "panic-strategy": "abort",
17 | "disable-redzone": true,
18 | "features": "+mmx,+sse,+sse2,+sse3"
19 | }
20 |
--------------------------------------------------------------------------------
/app_c/README.md:
--------------------------------------------------------------------------------
1 | # Example of C program for Fomos
2 |
3 | Notice that you can do stuff without any include.
4 |
5 | That is a core idea of Fomos.
6 |
7 | All capabilities of the OS are given explicitly through a single level of abstraction : the `Context` argument.
8 |
--------------------------------------------------------------------------------
/app_c/build.sh:
--------------------------------------------------------------------------------
1 | mkdir -p target
2 | gcc -nostdlib -static -fPIE -pie -o ./target/main main.c
--------------------------------------------------------------------------------
/app_c/main.c:
--------------------------------------------------------------------------------
1 | typedef struct
2 | {
3 | unsigned char version;
4 | unsigned long long start_time;
5 | void (*log)(const char *, unsigned int);
6 | unsigned long long pid;
7 |
8 | } Context;
9 |
10 | int _start(Context *ctx)
11 | {
12 | char text[] = "[pid:_] Hello from C!";
13 | text[5] = '0' + ctx->pid;
14 | ctx->log(text, sizeof(text) - 1);
15 | return 0;
16 | }
--------------------------------------------------------------------------------
/app_console/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std-features = ["compiler-builtins-mem"]
3 | build-std = ["core", "compiler_builtins","alloc"]
4 |
5 | [build]
6 | target = "x86_64.json"
--------------------------------------------------------------------------------
/app_console/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "approx"
7 | version = "0.5.1"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
10 | dependencies = [
11 | "num-traits",
12 | ]
13 |
14 | [[package]]
15 | name = "arrayvec"
16 | version = "0.7.2"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
19 |
20 | [[package]]
21 | name = "autocfg"
22 | version = "1.1.0"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
25 |
26 | [[package]]
27 | name = "fomoscript"
28 | version = "0.2.1"
29 | source = "registry+https://github.com/rust-lang/crates.io-index"
30 | checksum = "2ea747010079579506b23ad9ec9d6a33fdf18c5d84dfb65a5a47eab37cb77450"
31 | dependencies = [
32 | "log",
33 | ]
34 |
35 | [[package]]
36 | name = "func"
37 | version = "0.1.0"
38 | dependencies = [
39 | "fomoscript",
40 | "noto-sans-mono-bitmap",
41 | "taffy",
42 | "vek",
43 | ]
44 |
45 | [[package]]
46 | name = "libm"
47 | version = "0.2.6"
48 | source = "registry+https://github.com/rust-lang/crates.io-index"
49 | checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
50 |
51 | [[package]]
52 | name = "log"
53 | version = "0.4.20"
54 | source = "registry+https://github.com/rust-lang/crates.io-index"
55 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
56 |
57 | [[package]]
58 | name = "noto-sans-mono-bitmap"
59 | version = "0.2.0"
60 | source = "registry+https://github.com/rust-lang/crates.io-index"
61 | checksum = "a27daf9557165efe1d09b52f97393bf6283cadb0a76fbe64a1061e15553a994a"
62 |
63 | [[package]]
64 | name = "num-integer"
65 | version = "0.1.45"
66 | source = "registry+https://github.com/rust-lang/crates.io-index"
67 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
68 | dependencies = [
69 | "autocfg",
70 | "num-traits",
71 | ]
72 |
73 | [[package]]
74 | name = "num-traits"
75 | version = "0.2.15"
76 | source = "registry+https://github.com/rust-lang/crates.io-index"
77 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
78 | dependencies = [
79 | "autocfg",
80 | "libm",
81 | ]
82 |
83 | [[package]]
84 | name = "rustc_version"
85 | version = "0.4.0"
86 | source = "registry+https://github.com/rust-lang/crates.io-index"
87 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
88 | dependencies = [
89 | "semver",
90 | ]
91 |
92 | [[package]]
93 | name = "semver"
94 | version = "1.0.17"
95 | source = "registry+https://github.com/rust-lang/crates.io-index"
96 | checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
97 |
98 | [[package]]
99 | name = "slotmap"
100 | version = "1.0.6"
101 | source = "registry+https://github.com/rust-lang/crates.io-index"
102 | checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
103 | dependencies = [
104 | "version_check",
105 | ]
106 |
107 | [[package]]
108 | name = "taffy"
109 | version = "0.3.11"
110 | source = "git+https://github.com/Ruddle/taffy#44b858f3f9d6e2dffb4da719d5bf98e92a75af05"
111 | dependencies = [
112 | "arrayvec",
113 | "num-traits",
114 | "slotmap",
115 | ]
116 |
117 | [[package]]
118 | name = "vek"
119 | version = "0.15.10"
120 | source = "registry+https://github.com/rust-lang/crates.io-index"
121 | checksum = "8085882662f9bc47fc8b0cdafa5e19df8f592f650c02b9083da8d45ac9eebd17"
122 | dependencies = [
123 | "approx",
124 | "num-integer",
125 | "num-traits",
126 | "rustc_version",
127 | ]
128 |
129 | [[package]]
130 | name = "version_check"
131 | version = "0.9.4"
132 | source = "registry+https://github.com/rust-lang/crates.io-index"
133 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
134 |
--------------------------------------------------------------------------------
/app_console/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "func"
3 | version = "0.1.0"
4 | edition = "2021"
5 | [[bin]]
6 | name="func"
7 | test = false
8 | bench = false
9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10 |
11 | [dependencies]
12 |
13 | # x86_64 = { version = "0.14.8" }
14 | vek = { version = "0.15.10", default-features = false, features = ["libm"] }
15 | taffy = { git = "https://github.com/Ruddle/taffy", default-features = false, features = ["alloc","flexbox"] }
16 | fomoscript= "0.2.1"
17 | # [dependencies.zune-jpeg]
18 | # version ="0.3.14"
19 | # default-features = false
20 | # features = ["x86"]
21 |
22 | [dependencies.noto-sans-mono-bitmap]
23 | version = "0.2.0"
24 | default-features = false
25 | features = [
26 | "regular",
27 | "size_16",
28 | "unicode-basic-latin",
29 | # required for the fallback char '�'
30 | "unicode-specials",
31 | ]
32 |
33 |
34 |
35 | [features]
36 | default = []
37 |
38 | [profile.dev]
39 | panic = "abort"
40 |
41 | [profile.release]
42 | panic = "abort"
43 | lto = true
44 | strip = true
45 | codegen-units = 1
46 |
47 | [workspace]
48 |
49 | #RUSTFLAGS="-C relocation-model=pie -C link-arg=-nostartfiles -C link-arg=-pie"
50 |
51 | # RUSTFLAGS="-C relocation-model=pie -C link-arg=-nostartfiles -C link-arg=-pie" cargo build --release --target x86_64-unknown-linux-gnu
52 |
53 |
54 | # CURRENT WORKING with custom target in .cargo
55 | # RUSTFLAGS="-C relocation-model=pie -C link-arg=-pie" cargo build --release
--------------------------------------------------------------------------------
/app_console/rust-toolchain:
--------------------------------------------------------------------------------
1 | nightly
--------------------------------------------------------------------------------
/app_console/src/main.rs:
--------------------------------------------------------------------------------
1 | #![no_std]
2 | #![no_main]
3 | #![feature(alloc_error_handler)]
4 | #![feature(option_get_or_insert_default)]
5 | extern crate alloc;
6 | mod st;
7 |
8 | use st::*;
9 |
10 | use alloc::{boxed::Box, vec::Vec};
11 |
12 | use vek::{num_traits::Zero, Vec3};
13 |
14 | use vek::num_traits::Float;
15 |
16 | use taffy::prelude::*;
17 |
18 | pub struct ConsoleHistory {
19 | atoms: alloc::vec::Vec,
20 | }
21 | impl ConsoleHistory {
22 | pub fn new() -> ConsoleHistory {
23 | ConsoleHistory { atoms: Vec::new() }
24 | }
25 | }
26 |
27 | pub struct Atom {
28 | is_user: bool,
29 | text: alloc::string::String,
30 | }
31 |
32 | enum Mode {
33 | Shell,
34 | FomoscriptREPL,
35 | }
36 |
37 | pub struct Store {
38 | x: usize,
39 | y: usize,
40 | x2: usize,
41 | y2: usize,
42 | resizing: [bool; 4],
43 | moving: Option<(usize, usize)>,
44 | b1: Vec,
45 | b2: Vec,
46 | step: usize,
47 | taffy: Taffy,
48 | input_history_last_index: usize,
49 | console_history: ConsoleHistory,
50 | active: bool,
51 | local: Local,
52 | shift: bool,
53 | altg: bool,
54 | script_ctx: fomoscript::Ctx,
55 | mode: Mode,
56 | }
57 |
58 | fn put(pixel: &mut RGBA, v: Vec3) {
59 | pixel.r = v.x as u8;
60 | pixel.g = v.y as u8;
61 | pixel.b = v.z as u8;
62 | }
63 |
64 | fn get(mut x: isize, mut y: isize, src: &[RGBA], wi: isize, hi: isize) -> Vec3 {
65 | if x < 0 {
66 | x = 0;
67 | } else if x >= wi - 1 {
68 | x = wi - 1;
69 | }
70 | if y < 0 {
71 | y = 0;
72 | } else if y >= hi - 1 {
73 | y = hi - 1;
74 | }
75 |
76 | let (x, y) = (x as usize, y as usize);
77 | let index = x + y * wi as usize;
78 | // st::log(&format!("{} {} {} {}", x, y, wi, hi));
79 | let r = src[index];
80 | Vec3::new(r.r as f32, r.g as f32, r.b as f32)
81 | }
82 |
83 | fn getf(mut x: f32, mut y: f32, src: &[RGBA], wi: isize, hi: isize) -> RGBA {
84 | let x0 = x as isize;
85 | let x1 = x0 + 1;
86 | let y0 = y as isize;
87 | let y1 = y0 + 1;
88 |
89 | let fx = x - x0 as f32;
90 | let fy = y - y0 as f32;
91 |
92 | let a = get(x0, y0, src, wi, hi);
93 | let b = get(x1, y0, src, wi, hi);
94 | let c = get(x1, y1, src, wi, hi);
95 | let d = get(x0, y1, src, wi, hi);
96 |
97 | let ax = (1.0 - fx) * a + fx * b;
98 | let ay = (1.0 - fx) * d + fx * c;
99 |
100 | let avg = ax * (1.0 - fy) + ay * fy;
101 | RGBA {
102 | r: avg.x as u8,
103 | g: avg.y as u8,
104 | b: avg.z as u8,
105 | a: 0,
106 | }
107 | }
108 |
109 | fn pt_in_rect(px: usize, py: usize, x: usize, y: usize, x2: usize, y2: usize) -> bool {
110 | px >= x && px <= x2 && py >= y && py <= y2
111 | }
112 |
113 | fn kernel(sigma: f32) -> [f32; S] {
114 | let mut kernel = [0.0; S];
115 | let mid = S / 2;
116 |
117 | // calculate the Gaussian distribution
118 | let variance = sigma.powi(2);
119 | let factor = 1.0 / (2.0 * 3.141592 * variance);
120 | let mut sum = 0.0;
121 | for i in 0..S {
122 | let x = (i as i32 - mid as i32) as f32;
123 | let value = factor * (-x.powi(2) / (2.0 * variance)).exp();
124 | kernel[i] = value;
125 | sum += value;
126 | }
127 | sum *= 0.997;
128 | // normalize the kernel
129 | for i in 0..S {
130 | kernel[i] /= sum;
131 | }
132 |
133 | kernel
134 | }
135 | fn blur(
136 | fx: isize,
137 | fy: isize,
138 | src: &[RGBA],
139 | dst: &mut Vec,
140 | wi: isize,
141 | hi: isize,
142 | boxes: &[f32; KSIZE],
143 | ) {
144 | let mut avg: Vec3 = Vec3::zero();
145 |
146 | for y in 0..hi {
147 | for x in 0..wi {
148 | avg.set_zero();
149 | for (k, &coef) in boxes.iter().enumerate() {
150 | let dk = k as isize - KH;
151 | let v = get(x + fx * dk, y + fy * dk, src, wi, hi);
152 | avg += v * coef * 0.99;
153 | }
154 | put(&mut dst[(x + y * wi) as usize], avg);
155 | }
156 | }
157 | }
158 |
159 | fn hash(n: usize) -> usize {
160 | // integer hash copied from Hugo Elias
161 | let n = (n << 13) ^ n;
162 | let n = n.wrapping_mul(n.wrapping_mul(n).wrapping_mul(15731) + 789221) + 1376312589;
163 | n
164 | }
165 |
166 | fn hash2(x: usize) -> usize {
167 | let mut x = ((x >> 16) ^ x) * 0x45d9f3b;
168 | x = ((x >> 16) ^ x) * 0x45d9f3b;
169 | (x >> 16) ^ x
170 | }
171 | const KSIZE: usize = 5;
172 | const KH: isize = (KSIZE / 2) as isize;
173 | const DIV: isize = 4;
174 | const ORANGE: RGBA = RGBA {
175 | r: 255,
176 | g: 128,
177 | b: 0,
178 | a: 0,
179 | };
180 | const GREY3: RGBA = RGBA {
181 | r: 150,
182 | g: 150,
183 | b: 150,
184 | a: 0,
185 | };
186 | const GREY2: RGBA = RGBA {
187 | r: 80,
188 | g: 80,
189 | b: 80,
190 | a: 0,
191 | };
192 | const GREY: RGBA = RGBA {
193 | r: 50,
194 | g: 50,
195 | b: 50,
196 | a: 0,
197 | };
198 | #[no_mangle]
199 | pub extern "C" fn _start(ctx: &mut Context) -> i32 {
200 | unsafe { ALLOCATOR.swap(ctx) };
201 | unsafe { LOGGER.swap(ctx.log) };
202 |
203 | let hi = ctx.fb.h as isize / DIV;
204 | let wi = ctx.fb.w as isize / DIV;
205 |
206 | let store = ctx.store.get_or_insert_with(|| {
207 | Box::new({
208 | Store {
209 | x: 100 + ctx.pid as usize * 100,
210 | y: 100 + ctx.pid as usize * 100,
211 | x2: 1000 + ctx.pid as usize * 100,
212 | y2: 700 + ctx.pid as usize * 100,
213 | resizing: [false; 4],
214 | b1: Vec::with_capacity((wi * hi) as usize),
215 | b2: Vec::with_capacity((wi * hi) as usize),
216 |
217 | step: 0,
218 | moving: None,
219 | taffy: Taffy::new(),
220 | input_history_last_index: ctx.input.history_last_index,
221 | console_history: ConsoleHistory::new(),
222 | active: false,
223 | local: Local::En,
224 | shift: false,
225 | altg: false,
226 | script_ctx: fomoscript::Ctx::new(),
227 | mode: Mode::Shell,
228 | }
229 | })
230 | });
231 |
232 | if store.step == 0 {
233 | store.console_history.atoms.push(Atom {
234 | is_user: false,
235 | text: alloc::format!("Welcome to Fomos !"),
236 | });
237 | store.console_history.atoms.push(Atom {
238 | is_user: true,
239 | text: alloc::format!(">"),
240 | });
241 | }
242 |
243 | store.step += 1;
244 | let blured1 = &mut store.b1;
245 | let blured2 = &mut store.b2;
246 |
247 | let (src, dst) = if store.step % 2 == 0 {
248 | (blured1, blured2)
249 | } else {
250 | (blured2, blured1)
251 | };
252 |
253 | if src.len() == 0 {
254 | for y in 0..hi {
255 | for x in 0..wi {
256 | let v = ctx.fb.pixels[((x * DIV) + (y * DIV) * (wi * DIV)) as usize];
257 | src.push(v);
258 | dst.push(v);
259 | }
260 | }
261 | } else {
262 | for y in 0..hi {
263 | for x in 0..wi {
264 | if true {
265 | //|| (hash2((x + y * wi) as usize) + store.step) % 2 == 0
266 | let v = ctx.fb.pixels[((x * DIV) + (y * DIV) * (wi * DIV)) as usize];
267 | let s = src[(x + y * wi) as usize];
268 | let a = 0.03;
269 | let b = 1.0 - a;
270 | let r = (v.r as f32 * a + s.r as f32 * b) as u8;
271 | let g = (v.g as f32 * a + s.g as f32 * b) as u8;
272 | let b = (v.b as f32 * a + s.b as f32 * b) as u8;
273 |
274 | src[(x + y * wi) as usize] = RGBA { r, g, b, a: 0 };
275 | }
276 | }
277 | }
278 | }
279 |
280 | let boxes = kernel::(1.0);
281 |
282 | let fx = if store.step % 2 == 0 { 1 } else { 0 };
283 | blur(fx, 1 - fx, src, dst, wi, hi, &boxes);
284 |
285 | // blur(1, 0, &blured2, &mut blured1);
286 | // for y in 0..hi {
287 | // for x in 0..wi {
288 | // avg.set_zero();
289 | // for (k, coef) in boxes.iter().enumerate() {
290 | // let coef = boxes[k as usize];
291 | // let v = get(x + (k as isize - KH), y);
292 | // avg += v * coef;
293 | // }
294 | // put(&mut blured1[(x + y * wi) as usize], avg);
295 | // }
296 | // }
297 |
298 | if ctx.input.keys[272] < 128 {
299 | store.resizing = [false; 4];
300 | store.moving = None;
301 | }
302 |
303 | if ctx.input.keys[272] == 128 {
304 | if (store.x as isize - ctx.input.mx as isize).abs() < 10 {
305 | store.resizing[3] = true;
306 | }
307 | if (store.x2 as isize - ctx.input.mx as isize).abs() < 10 {
308 | store.resizing[1] = true;
309 | }
310 | if (store.y as isize - ctx.input.my as isize).abs() < 10
311 | && store.x <= ctx.input.mx
312 | && store.x2 >= ctx.input.mx
313 | {
314 | store.resizing[0] = true;
315 | }
316 | if (store.y2 as isize - ctx.input.my as isize).abs() < 10
317 | && store.x <= ctx.input.mx
318 | && store.x2 >= ctx.input.mx
319 | {
320 | store.resizing[2] = true;
321 | }
322 |
323 | if !store.resizing.iter().any(|&e| e) {
324 | if store.x <= ctx.input.mx
325 | && store.x2 >= ctx.input.mx
326 | && store.y <= ctx.input.my
327 | && store.y2 >= ctx.input.my
328 | {
329 | store.moving = Some((ctx.input.mx, ctx.input.my));
330 | store.active = true;
331 | } else {
332 | store.active = false;
333 | }
334 | }
335 | }
336 |
337 | if let Some((x0, y0)) = store.moving.as_mut() {
338 | let dx = ctx.input.mx as isize - *x0 as isize;
339 | let dy = ctx.input.my as isize - *y0 as isize;
340 |
341 | store.x = (store.x as isize + dx) as usize;
342 | store.x2 = (store.x2 as isize + dx) as usize;
343 | store.y = (store.y as isize + dy) as usize;
344 | store.y2 = (store.y2 as isize + dy) as usize;
345 |
346 | *x0 = ctx.input.mx;
347 | *y0 = ctx.input.my;
348 | }
349 |
350 | for (index, &r) in store.resizing.iter().enumerate() {
351 | if r {
352 | match index {
353 | 0 => store.y = ctx.input.my,
354 | 1 => store.x2 = ctx.input.mx,
355 | 2 => store.y2 = ctx.input.my,
356 | 3 => store.x = ctx.input.mx,
357 | _ => {}
358 | }
359 | }
360 | }
361 |
362 | if store.x < 0 || store.x > 10000 {
363 | store.x = 0;
364 | }
365 | if store.y < 0 || store.y > 10000 {
366 | store.y = 0;
367 | }
368 | if store.x2 >= ctx.fb.w {
369 | store.x2 = ctx.fb.w - 1;
370 | }
371 | if store.y2 >= ctx.fb.h {
372 | store.y2 = ctx.fb.h - 1;
373 | }
374 |
375 | let taffy = &mut store.taffy;
376 | taffy.clear();
377 |
378 | let header_node = taffy
379 | .new_leaf(Style {
380 | size: Size {
381 | width: percent(1.0),
382 | height: points(20.0),
383 | },
384 | ..Default::default()
385 | })
386 | .unwrap();
387 |
388 | let body_node = taffy
389 | .new_leaf(Style {
390 | flex_direction: FlexDirection::Column,
391 | size: Size {
392 | width: percent(1.0),
393 | height: auto(),
394 | },
395 | // padding: Rect {
396 | // left: points(10.),
397 | // right: points(10.),
398 | // top: points(10.),
399 | // bottom: points(10.),
400 | // },
401 | flex_grow: 1.0,
402 | ..Default::default()
403 | })
404 | .unwrap();
405 |
406 | for i in 0..0 {
407 | let text_node = taffy
408 | .new_leaf(Style {
409 | size: Size {
410 | width: auto(),
411 | height: points(10.),
412 | },
413 | margin: Rect {
414 | left: points(10.),
415 | right: points(10.),
416 | top: points(10.),
417 | bottom: points(10.),
418 | },
419 | flex_grow: 1.0,
420 | ..Default::default()
421 | })
422 | .unwrap();
423 |
424 | let _ = taffy.add_child(body_node, text_node);
425 | }
426 |
427 | let root_node = taffy
428 | .new_with_children(
429 | Style {
430 | flex_direction: FlexDirection::Column,
431 | size: Size {
432 | width: points(store.x2 as f32 - store.x as f32),
433 | height: points(store.y2 as f32 - store.y as f32),
434 | },
435 | ..Default::default()
436 | },
437 | &[header_node, body_node],
438 | )
439 | .unwrap();
440 |
441 | // Call compute_layout on the root of your tree to run the layout algorithm
442 | taffy
443 | .compute_layout(
444 | root_node,
445 | Size {
446 | width: points(store.x2 as f32 - store.x as f32),
447 | height: points(store.y2 as f32 - store.y as f32),
448 | },
449 | )
450 | .unwrap();
451 |
452 | let get_rect = |node| {
453 | let l = taffy.layout(node).unwrap();
454 | let (x, y) = (l.location.x as usize, l.location.y as usize);
455 | let (x2, y2) = (x + l.size.width as usize, y + l.size.height as usize);
456 | (x + store.x, y + store.y, x2 + store.x, y2 + store.y)
457 | };
458 |
459 | // for i in 0..5 {
460 | // let (cx, cy, cx2, cy2) = get_rect(taffy.child_at_index(body_node, i).unwrap());
461 | // st::log(&format!("{}: {:?}", i, (cx, cy, cx2, cy2)));
462 | // }
463 |
464 | for y in store.y..=store.y2 {
465 | for x in store.x..=store.x2 {
466 | let p = &mut ctx.fb.pixels[x + y * ctx.fb.w];
467 | let mut drawn = false;
468 |
469 | // *p = dst[x / div + (y / div) * (ctx.fb.w / div)];
470 |
471 | // if y - store.y < 20 {
472 | // *p = GREY;
473 | // }
474 |
475 | {
476 | let (cx, cy, cx2, cy2) = get_rect(header_node);
477 |
478 | if pt_in_rect(x, y, cx, cy, cx2, cy2) {
479 | *p = if store.active { GREY2 } else { GREY };
480 | drawn = true;
481 | }
482 | }
483 |
484 | for i in 0..taffy.child_count(body_node).unwrap() {
485 | let (cx, cy, cx2, cy2) = get_rect(taffy.child_at_index(body_node, i).unwrap());
486 | if pt_in_rect(x, y, cx, cy, cx2, cy2) {
487 | *p = if i % 2 == 0 { GREY3 } else { ORANGE };
488 | drawn = true;
489 | }
490 | }
491 |
492 | if (x == store.x) || (x == store.x2) || (y == store.y) || (y == store.y2) {
493 | *p = if store.active { GREY2 } else { GREY };
494 | if store.moving.is_some() {
495 | *p = ORANGE;
496 | }
497 | drawn = true;
498 | }
499 |
500 | if (x == store.x && store.resizing[3])
501 | || (x == store.x2 && store.resizing[1])
502 | || (y == store.y && store.resizing[0])
503 | || (y == store.y2 && store.resizing[2])
504 | {
505 | *p = ORANGE;
506 | drawn = true;
507 | }
508 |
509 | if !drawn {
510 | let div = DIV as usize;
511 | // *p = getf(x as f32 / div as f32, y as f32 / div as f32, dst, wi, hi);
512 | *p = dst[x / div + (y / div) * (ctx.fb.w / div)];
513 | }
514 | }
515 | }
516 |
517 | //Write window title
518 | {
519 | use noto_sans_mono_bitmap::{get_raster, get_raster_width, FontWeight, RasterHeight};
520 | let s = alloc::format!("app_console [{}]", ctx.pid);
521 | let mut cursor_x = 0;
522 | let padding = 2;
523 | let weight = FontWeight::Regular;
524 | for c in s.chars() {
525 | let width = get_raster_width(weight, RasterHeight::Size16);
526 |
527 | let char_raster =
528 | get_raster(c, weight, RasterHeight::Size16).expect("unsupported char");
529 |
530 | for (row_i, row) in char_raster.raster().iter().enumerate() {
531 | for (col_i, pixel) in row.iter().enumerate() {
532 | let x = store.x + col_i + padding + cursor_x;
533 | let y = store.y + row_i + padding + 0;
534 | if x <= 0
535 | || x >= ctx.fb.w
536 | || y <= 0
537 | || y >= ctx.fb.h
538 | || x >= store.x2
539 | || y >= store.y2
540 | {
541 | continue;
542 | }
543 | let p = &mut ctx.fb.pixels[x + y * ctx.fb.w];
544 | p.r = *pixel.max(&p.r);
545 | p.g = *pixel.max(&p.g);
546 | p.b = *pixel.max(&p.b);
547 | }
548 | }
549 | cursor_x += width;
550 | }
551 | }
552 | //Write text buffer
553 | {
554 | use noto_sans_mono_bitmap::{get_raster, get_raster_width, FontWeight, RasterHeight};
555 |
556 | let mut cursor_x = 0;
557 | let mut cursor_y = 20;
558 | let padding = 2;
559 | let weight = FontWeight::Regular;
560 |
561 | for Atom { is_user, text } in store.console_history.atoms.iter() {
562 | for c in text.chars() {
563 | if (c == '\n') {
564 | cursor_y += 16;
565 | cursor_x = 0;
566 | continue;
567 | }
568 | let width = get_raster_width(weight, RasterHeight::Size16);
569 |
570 | let char_raster =
571 | get_raster(c, weight, RasterHeight::Size16).expect("unsupported char");
572 |
573 | for (row_i, row) in char_raster.raster().iter().enumerate() {
574 | for (col_i, pixel) in row.iter().enumerate() {
575 | let x = store.x + col_i + padding + cursor_x;
576 | let y = store.y + row_i + padding + cursor_y;
577 | if x <= 0
578 | || x >= ctx.fb.w
579 | || y <= 0
580 | || y >= ctx.fb.h
581 | || x >= store.x2
582 | || y >= store.y2
583 | {
584 | continue;
585 | }
586 | let p = &mut ctx.fb.pixels[x + y * ctx.fb.w];
587 |
588 | p.r = *pixel.max(&p.r);
589 | p.g = *pixel.max(&p.g);
590 | if *is_user {
591 | p.b = *pixel.max(&p.b);
592 | };
593 | }
594 | }
595 | cursor_x += width;
596 | }
597 |
598 | cursor_y += 16;
599 | cursor_x = 0;
600 | }
601 | }
602 |
603 | if store.active {
604 | 'new_inputs: for i in (store.input_history_last_index + 1)..=ctx.input.history_last_index {
605 | let InputEvent { trigger, key } = ctx.input.history_ring[i % HISTORY_SIZE];
606 |
607 | match key {
608 | Key::KeyLeftShift => {
609 | store.shift = trigger;
610 | }
611 | Key::KeyRightAlt => {
612 | store.altg = trigger;
613 | }
614 | _ => {}
615 | }
616 |
617 | if (trigger) {
618 | let last = store.console_history.atoms.last_mut();
619 | match last {
620 | Some(Atom { is_user, text }) if *is_user => {
621 | log(&alloc::format!("{:?}", key));
622 |
623 | match key {
624 | Key::KeyEnter if !store.shift => {
625 | if let Mode::FomoscriptREPL = store.mode {
626 | use fomoscript::*;
627 | store.script_ctx.insert_code(&text[4..]);
628 | if let Ok(parent) = store.script_ctx.parse_next_expr() {
629 | let res = eval(&parent, &mut store.script_ctx);
630 | store.console_history.atoms.push(Atom {
631 | is_user: false,
632 | text: alloc::format!("eval: {:?}", res),
633 | });
634 | }
635 | } else {
636 | match text.as_ref() {
637 | ">repl" => {
638 | use fomoscript::*;
639 | store.mode = Mode::FomoscriptREPL;
640 | store.console_history.atoms.push(Atom {
641 | is_user: false,
642 | text: alloc::format!(
643 | "Call quit() to exit the REPL"
644 | ),
645 | });
646 |
647 | let store_mode_ptr: *mut Mode = &mut store.mode;
648 | let quit = alloc::rc::Rc::new(
649 | move |a: N, b: N, c: N, d: N| -> N {
650 | let store_mode =
651 | unsafe { &mut *store_mode_ptr };
652 | *store_mode = Mode::Shell;
653 | N::Unit
654 | },
655 | );
656 | store.script_ctx.set_var_absolute(
657 | "quit",
658 | N::FuncNativeDef(Native(quit)),
659 | );
660 | }
661 | ">pid" => {
662 | store.console_history.atoms.push(Atom {
663 | is_user: false,
664 | text: alloc::format!("pid: {}", ctx.pid),
665 | });
666 | }
667 | ">time" => {
668 | store.console_history.atoms.push(Atom {
669 | is_user: false,
670 | text: alloc::format!("time: {} ms", ctx.start_time),
671 | });
672 | }
673 | ">lang en" => {
674 | store.local = Local::En;
675 | store.console_history.atoms.push(Atom {
676 | is_user: false,
677 | text: alloc::format!("ok"),
678 | });
679 | }
680 | ">lang fr" => {
681 | store.local = Local::Fr;
682 | store.console_history.atoms.push(Atom {
683 | is_user: false,
684 | text: alloc::format!("ok"),
685 | });
686 | }
687 | ">reset" => {
688 | drop(store);
689 | let old = ctx.store.take().unwrap();
690 | drop(old);
691 | return 0;
692 | }
693 | ">help" => {
694 | store.console_history.atoms.push(Atom {
695 | is_user: false,
696 | text: alloc::format!(
697 | "commands:
698 | - pid Display the app pid
699 | - time Display the kernel time
700 | - reset Clear the app memory
701 | - lang .. Set key locale (en,fr)
702 | - eval .. Eval fomoscript
703 | - repl launch fomoscript REPL
704 | - help You are here
705 | "
706 | ),
707 | });
708 | }
709 | _ => {
710 | if text.starts_with(">eval ") {
711 | use crate::alloc::borrow::ToOwned;
712 | use fomoscript::*;
713 |
714 | let res = {
715 | store.script_ctx.insert_code(&text[5..]);
716 | store.script_ctx.set_var_absolute(
717 | "time",
718 | N::Num(ctx.start_time as f64),
719 | );
720 | store.script_ctx.set_var_absolute(
721 | "pid",
722 | N::Num(ctx.pid as f64),
723 | );
724 |
725 | {
726 | //TODO find a safe way to share native function to interpreter
727 | let ptr: *mut [RGBA] = ctx.fb.pixels;
728 | let w = ctx.fb.w;
729 | let draw_pixel = alloc::rc::Rc::new(
730 | move |a: N, b: N, c: N, d: N| -> N {
731 | let arr: &mut [RGBA] =
732 | unsafe { &mut *ptr };
733 | let p = &mut arr[a.as_f64()
734 | as usize
735 | + (b.as_f64() as usize) * w];
736 |
737 | p.r = (c.as_f64() * 255.0) as u8;
738 | p.g = p.r;
739 | p.b = p.b;
740 | N::Unit
741 | },
742 | );
743 | store.script_ctx.set_var_absolute(
744 | "draw",
745 | N::FuncNativeDef(Native(draw_pixel)),
746 | );
747 | }
748 | let mut res = N::Unit;
749 | while let Ok(parent) =
750 | store.script_ctx.parse_next_expr()
751 | {
752 | res = eval(&parent, &mut store.script_ctx);
753 | }
754 |
755 | log(&alloc::format!("res {:?}", res));
756 |
757 | res
758 | };
759 |
760 | store.console_history.atoms.push(Atom {
761 | is_user: false,
762 | text: alloc::format!("eval: {:?}", res),
763 | });
764 | } else {
765 | store.console_history.atoms.push(Atom {
766 | is_user: false,
767 | text: alloc::format!("unknown command"),
768 | });
769 | }
770 | }
771 | }
772 | }
773 |
774 | store.console_history.atoms.push(Atom {
775 | is_user: true,
776 | text: alloc::string::String::from(
777 | if let Mode::Shell = store.mode {
778 | ">"
779 | } else {
780 | "fos>"
781 | },
782 | ),
783 | });
784 | break 'new_inputs;
785 | }
786 |
787 | Key::KeyBackspace => {
788 | if text.len() > 1 {
789 | text.pop();
790 | }
791 | }
792 | _ => {}
793 | }
794 |
795 | if let Some(c) = key.char(store.local, store.shift, store.altg) {
796 | *text = alloc::format!("{}{}", text, c)
797 | } else {
798 | match key {
799 | Key::KeyEnter if store.shift => {
800 | *text = alloc::format!("{}\n", text,)
801 | }
802 | _ => {}
803 | }
804 | // store.text_buffer = alloc::format!("{}{:?}", store.text_buffer, key)
805 | }
806 | }
807 | _ => {}
808 | }
809 | }
810 | }
811 | }
812 | store.input_history_last_index = ctx.input.history_last_index;
813 |
814 | return 0;
815 | }
816 |
--------------------------------------------------------------------------------
/app_console/x86_64.json:
--------------------------------------------------------------------------------
1 | {
2 | "llvm-target": "x86_64-unknown-none",
3 | "code-model": "small",
4 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
5 | "arch": "x86_64",
6 | "target-endian": "little",
7 | "target-pointer-width": "64",
8 | "target-c-int-width": "32",
9 | "os": "none",
10 | "executables": true,
11 | "linker-flavor": "ld.lld",
12 | "linker": "rust-lld",
13 | "relocation-model": "pie",
14 | "position-independent-executables": true,
15 | "static-position-independent-executables": true,
16 | "panic-strategy": "abort",
17 | "disable-redzone": true,
18 | "features": "+mmx,+sse,+sse2,+sse3"
19 | }
20 |
--------------------------------------------------------------------------------
/app_cursor/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std-features = ["compiler-builtins-mem"]
3 | build-std = ["core", "compiler_builtins","alloc"]
4 |
5 | [build]
6 | target = "x86_64.json"
--------------------------------------------------------------------------------
/app_cursor/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "approx"
7 | version = "0.5.1"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
10 | dependencies = [
11 | "num-traits",
12 | ]
13 |
14 | [[package]]
15 | name = "arrform"
16 | version = "0.1.1"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "e7cf566ecc5c9d82b973e81d30babf6583c9b497f86295c952d538c3254ef4e6"
19 |
20 | [[package]]
21 | name = "autocfg"
22 | version = "1.1.0"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
25 |
26 | [[package]]
27 | name = "bit_field"
28 | version = "0.10.2"
29 | source = "registry+https://github.com/rust-lang/crates.io-index"
30 | checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
31 |
32 | [[package]]
33 | name = "bitflags"
34 | version = "1.3.2"
35 | source = "registry+https://github.com/rust-lang/crates.io-index"
36 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
37 |
38 | [[package]]
39 | name = "func"
40 | version = "0.1.0"
41 | dependencies = [
42 | "arrform",
43 | "vek",
44 | "x86_64",
45 | ]
46 |
47 | [[package]]
48 | name = "libm"
49 | version = "0.2.6"
50 | source = "registry+https://github.com/rust-lang/crates.io-index"
51 | checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
52 |
53 | [[package]]
54 | name = "num-integer"
55 | version = "0.1.45"
56 | source = "registry+https://github.com/rust-lang/crates.io-index"
57 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
58 | dependencies = [
59 | "autocfg",
60 | "num-traits",
61 | ]
62 |
63 | [[package]]
64 | name = "num-traits"
65 | version = "0.2.15"
66 | source = "registry+https://github.com/rust-lang/crates.io-index"
67 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
68 | dependencies = [
69 | "autocfg",
70 | "libm",
71 | ]
72 |
73 | [[package]]
74 | name = "rustc_version"
75 | version = "0.4.0"
76 | source = "registry+https://github.com/rust-lang/crates.io-index"
77 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
78 | dependencies = [
79 | "semver",
80 | ]
81 |
82 | [[package]]
83 | name = "rustversion"
84 | version = "1.0.12"
85 | source = "registry+https://github.com/rust-lang/crates.io-index"
86 | checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
87 |
88 | [[package]]
89 | name = "semver"
90 | version = "1.0.17"
91 | source = "registry+https://github.com/rust-lang/crates.io-index"
92 | checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
93 |
94 | [[package]]
95 | name = "vek"
96 | version = "0.15.10"
97 | source = "registry+https://github.com/rust-lang/crates.io-index"
98 | checksum = "8085882662f9bc47fc8b0cdafa5e19df8f592f650c02b9083da8d45ac9eebd17"
99 | dependencies = [
100 | "approx",
101 | "num-integer",
102 | "num-traits",
103 | "rustc_version",
104 | ]
105 |
106 | [[package]]
107 | name = "volatile"
108 | version = "0.4.6"
109 | source = "registry+https://github.com/rust-lang/crates.io-index"
110 | checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793"
111 |
112 | [[package]]
113 | name = "x86_64"
114 | version = "0.14.10"
115 | source = "registry+https://github.com/rust-lang/crates.io-index"
116 | checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69"
117 | dependencies = [
118 | "bit_field",
119 | "bitflags",
120 | "rustversion",
121 | "volatile",
122 | ]
123 |
--------------------------------------------------------------------------------
/app_cursor/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "func"
3 | version = "0.1.0"
4 | edition = "2021"
5 | [[bin]]
6 | name="func"
7 | test = false
8 | bench = false
9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10 |
11 | [dependencies]
12 | x86_64 = { version = "0.14.8" }
13 | arrform = "0.1.1"
14 | vek = { version = "0.15.10", default-features = false, features = ["libm"] }
15 |
16 | # [dependencies.zune-jpeg]
17 | # version ="0.3.14"
18 | # default-features = false
19 | # features = ["x86"]
20 |
21 |
22 | [features]
23 | default = []
24 |
25 | [profile.dev]
26 | panic = "abort"
27 |
28 | [profile.release]
29 | panic = "abort"
30 | lto = true
31 | strip = true
32 | codegen-units = 1
33 |
34 | [workspace]
35 |
36 | #RUSTFLAGS="-C relocation-model=pie -C link-arg=-nostartfiles -C link-arg=-pie"
37 |
38 | # RUSTFLAGS="-C relocation-model=pie -C link-arg=-nostartfiles -C link-arg=-pie" cargo build --release --target x86_64-unknown-linux-gnu
39 |
40 |
41 | # CURRENT WORKING with custom target in .cargo
42 | # RUSTFLAGS="-C relocation-model=pie -C link-arg=-pie" cargo build --release
--------------------------------------------------------------------------------
/app_cursor/rust-toolchain:
--------------------------------------------------------------------------------
1 | nightly
--------------------------------------------------------------------------------
/app_cursor/src/main.rs:
--------------------------------------------------------------------------------
1 | #![no_std]
2 | #![no_main]
3 | #![feature(alloc_error_handler)]
4 |
5 | extern crate alloc;
6 | mod st;
7 | use alloc::boxed::Box;
8 | use st::*;
9 | use vek::Vec2;
10 |
11 | pub struct Store {
12 | x: usize,
13 | y: usize,
14 | xm: usize,
15 | ym: usize,
16 | }
17 |
18 | #[no_mangle]
19 | pub extern "C" fn _start(ctx: &mut Context) -> i32 {
20 | unsafe { ALLOCATOR.swap(ctx) };
21 | unsafe { LOGGER.swap(ctx.log) };
22 |
23 | // (ctx.log)("back start");
24 | // x86_64::instructions::interrupts::int3();
25 |
26 | let mut store: Box;
27 | if let Some(ptr) = ctx.store.take() {
28 | // st::log("store found");
29 | store = ptr;
30 | } else {
31 | st::log("store not found");
32 |
33 | store = Box::new(Store {
34 | x: ctx.input.mx,
35 | y: ctx.input.my,
36 | xm: ctx.input.mx,
37 | ym: ctx.input.my,
38 | })
39 | }
40 |
41 | let am = Vec2::new(store.xm as f32 + 0.01, store.ym as f32);
42 | let a = Vec2::new(store.x as f32, store.y as f32);
43 | let b = Vec2::new(ctx.input.mx as f32 + 0.01, ctx.input.my as f32 + 0.01);
44 |
45 | fn cro(a: Vec2, b: Vec2) -> f32 {
46 | a.x * b.y - a.y * b.x
47 | }
48 |
49 | fn sd_bezier(p: Vec2, v0: Vec2, v1: Vec2, v2: Vec2) -> f32 {
50 | let mid = (v0 + v2) * 0.5;
51 | let to_v1 = v1 - mid;
52 | let v1 = v1 + to_v1 * 1.;
53 |
54 | let i = v0 - v2;
55 | let j = v2 - v1;
56 | let k = v1 - v0;
57 | let w = j - k;
58 |
59 | let v0 = v0 - p;
60 | let v1 = v1 - p;
61 | let v2 = v2 - p;
62 |
63 | let x = cro(v0, v2);
64 | let y = cro(v1, v0);
65 | let z = cro(v2, v1);
66 |
67 | let s = 2.0 * (y * j + z * k) - x * i;
68 |
69 | let r = (y * z - x * x * 0.25) / s.dot(s);
70 | let t = ((0.5 * x + y + r * s.dot(w)) / (x + y + z)).clamp(0.0, 1.0);
71 |
72 | (v0 + t * (k + k + t * w)).magnitude()
73 | }
74 |
75 | for y in 0..ctx.fb.h {
76 | for x in 0..ctx.fb.w {
77 | let p = &mut ctx.fb.pixels[x + y * ctx.fb.w];
78 | if (x as i32 - ctx.input.mx as i32).abs() + (y as i32 - ctx.input.my as i32).abs() < 80
79 | {
80 | let pos = Vec2::new(x as f32, y as f32);
81 | let d = sd_bezier(pos, am, a, b);
82 | if d < 3. {
83 | p.r = 255;
84 |
85 | let left_click = ctx.input.keys[0x110];
86 | if left_click < 128 {
87 | p.g = 255;
88 | p.b = 255;
89 | } else if left_click == 128 {
90 | p.g = 255;
91 | p.b = 0;
92 | } else {
93 | p.g = 0;
94 | p.b = 0;
95 | }
96 | } else if d < 4. {
97 | p.r = 0;
98 | p.g = 0;
99 | p.b = 0;
100 | }
101 | }
102 | }
103 | }
104 | store.xm = store.x;
105 | store.ym = store.y;
106 | store.x = ctx.input.mx;
107 | store.y = ctx.input.my;
108 | *ctx.store = Some(store);
109 |
110 | return 0;
111 | }
112 |
--------------------------------------------------------------------------------
/app_cursor/src/st.rs:
--------------------------------------------------------------------------------
1 | #[panic_handler]
2 | fn panic(info: &core::panic::PanicInfo) -> ! {
3 | x86_64::instructions::interrupts::int3();
4 | unsafe {
5 | (LOGGER.f)("panic".as_ptr(), 5);
6 | };
7 | unsafe {
8 | let s = &format!("{:?}", info);
9 | (LOGGER.f)(s.as_ptr(), s.len() as u32)
10 | };
11 | loop {}
12 | }
13 |
14 | pub static mut LOGGER: Logger = Logger::init();
15 |
16 | pub fn log(s: &str) {
17 | unsafe { (LOGGER.f)(s.as_ptr(), s.len() as u32) }
18 | }
19 |
20 | type LogFn = extern "C" fn(*const u8, u32);
21 | extern "C" fn nop(s: *const u8, l: u32) {}
22 | pub struct Logger {
23 | pub f: LogFn,
24 | }
25 | impl Logger {
26 | pub const fn init() -> Self {
27 | Self { f: nop }
28 | }
29 | pub fn swap(&mut self, f2: LogFn) {
30 | self.f = f2;
31 | }
32 | }
33 | #[repr(C)]
34 | pub struct Context<'a, T> {
35 | pub version: u8,
36 | pub start_time: u64,
37 | pub log: extern "C" fn(s: *const u8, l: u32),
38 | pub pid: u64,
39 | pub fb: FB<'a>,
40 | pub calloc: extern "C" fn(usize, usize) -> *mut u8,
41 | pub cdalloc: extern "C" fn(*mut u8, usize, usize),
42 | pub store: &'a mut Option>,
43 | pub input: &'a Input,
44 | }
45 |
46 | const HISTORY_SIZE: usize = 64;
47 |
48 | #[repr(C)]
49 | #[derive(Clone, Debug, Copy)]
50 | pub struct InputEvent {
51 | pub trigger: bool,
52 | pub key: usize,
53 | }
54 | #[repr(C)]
55 | pub struct Input {
56 | pub mx: usize,
57 | pub my: usize,
58 | pub keys: [u8; 1024],
59 | pub history_last_index: usize,
60 | pub history_ring: [InputEvent; HISTORY_SIZE],
61 | }
62 |
63 | #[derive(Debug, Clone, Copy, PartialEq, Eq)]
64 | #[repr(C)]
65 | pub struct RGBA {
66 | pub r: u8,
67 | pub g: u8,
68 | pub b: u8,
69 | pub a: u8,
70 | }
71 |
72 | #[repr(C)]
73 | pub struct FB<'a> {
74 | pub pixels: &'a mut [RGBA],
75 | pub w: usize,
76 | pub h: usize,
77 | }
78 |
79 | use core::alloc::GlobalAlloc;
80 |
81 | use alloc::{boxed::Box, format};
82 |
83 | extern "C" fn a_init(size: usize, align: usize) -> *mut u8 {
84 | panic!("")
85 | }
86 | extern "C" fn d_init(ptr: *mut u8, size: usize, align: usize) {
87 | panic!("")
88 | }
89 | #[repr(C)]
90 | pub struct AllocFromCtx {
91 | a: extern "C" fn(usize, usize) -> *mut u8,
92 | d: extern "C" fn(*mut u8, usize, usize),
93 | }
94 | unsafe impl GlobalAlloc for AllocFromCtx {
95 | unsafe fn alloc(&self, layout: alloc::alloc::Layout) -> *mut u8 {
96 | (self.a)(layout.size(), layout.align())
97 | }
98 |
99 | unsafe fn dealloc(&self, ptr: *mut u8, layout: alloc::alloc::Layout) {
100 | (self.d)(ptr, layout.size(), layout.align());
101 | }
102 | }
103 | impl AllocFromCtx {
104 | pub const fn init() -> Self {
105 | Self {
106 | a: a_init,
107 | d: d_init,
108 | }
109 | }
110 | pub fn swap(&mut self, ctx: &mut Context) {
111 | let ptr = self;
112 | ptr.a = ctx.calloc;
113 | ptr.d = ctx.cdalloc;
114 | }
115 | }
116 | #[global_allocator]
117 | pub static mut ALLOCATOR: AllocFromCtx = AllocFromCtx::init();
118 |
--------------------------------------------------------------------------------
/app_cursor/x86_64.json:
--------------------------------------------------------------------------------
1 | {
2 | "llvm-target": "x86_64-unknown-none",
3 | "code-model": "small",
4 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
5 | "arch": "x86_64",
6 | "target-endian": "little",
7 | "target-pointer-width": "64",
8 | "target-c-int-width": "32",
9 | "os": "none",
10 | "executables": true,
11 | "linker-flavor": "ld.lld",
12 | "linker": "rust-lld",
13 | "relocation-model": "pie",
14 | "position-independent-executables": true,
15 | "static-position-independent-executables": true,
16 | "panic-strategy": "abort",
17 | "disable-redzone": true,
18 | "features": "+mmx,+sse,+sse2,+sse3"
19 | }
20 |
--------------------------------------------------------------------------------
/app_test/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std-features = ["compiler-builtins-mem"]
3 | build-std = ["core", "compiler_builtins"]
4 |
5 | [build]
6 | target = "x86_64.json"
--------------------------------------------------------------------------------
/app_test/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "func"
7 | version = "0.1.0"
8 |
--------------------------------------------------------------------------------
/app_test/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "func"
3 | version = "0.1.0"
4 | edition = "2021"
5 | [[bin]]
6 | name="func"
7 | test = false
8 | bench = false
9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10 |
11 | [dependencies]
12 | [profile.dev]
13 | panic = "abort"
14 |
15 | [profile.release]
16 | panic = "abort"
17 |
18 | [workspace]
--------------------------------------------------------------------------------
/app_test/rust-toolchain:
--------------------------------------------------------------------------------
1 | nightly
--------------------------------------------------------------------------------
/app_test/src/main.rs:
--------------------------------------------------------------------------------
1 | #![no_std]
2 | #![no_main]
3 |
4 | #[panic_handler]
5 | fn panic(_info: &core::panic::PanicInfo) -> ! {
6 | loop {}
7 | }
8 |
9 | const TEXT: &str = "Writting from pid: ";
10 | #[repr(C)]
11 | pub struct Context<'a> {
12 | pub version: u8,
13 | start_time: u64,
14 | log: extern "C" fn(s: *const u8, l: u32),
15 | pid: u64,
16 | fb: FB<'a>,
17 | }
18 |
19 | #[derive(Debug, Clone, Copy, PartialEq, Eq)]
20 | #[repr(C)]
21 | pub struct RGBA {
22 | pub r: u8,
23 | pub g: u8,
24 | pub b: u8,
25 | pub a: u8,
26 | }
27 |
28 | #[repr(C)]
29 | pub struct FB<'a> {
30 | pub pixels: &'a mut [RGBA],
31 | pub w: usize,
32 | pub h: usize,
33 | }
34 |
35 | #[no_mangle]
36 | pub extern "C" fn _start(ctx: &mut Context) -> i32 {
37 | ctx.version += 1;
38 |
39 | let mut txt = [0; TEXT.len()];
40 | let m = &mut txt;
41 | m.copy_from_slice(TEXT.as_bytes());
42 | m[m.len() - 1] = '0' as u8 + ctx.pid as u8;
43 |
44 | let s = unsafe { core::str::from_utf8_unchecked(&txt) };
45 | (ctx.log)(s.as_ptr(), s.len() as u32);
46 |
47 | //make thinks blue
48 | // for px in ctx.fb.pixels.iter_mut() {
49 | // px.b = 255;
50 | // }
51 |
52 | return 0;
53 | }
54 |
--------------------------------------------------------------------------------
/app_test/x86_64.json:
--------------------------------------------------------------------------------
1 | {
2 | "llvm-target": "x86_64-unknown-none",
3 | "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
4 | "arch": "x86_64",
5 | "target-endian": "little",
6 | "target-pointer-width": "64",
7 | "target-c-int-width": "32",
8 | "os": "none",
9 | "executables": true,
10 | "linker-flavor": "ld.lld",
11 | "linker": "rust-lld",
12 | "panic-strategy": "abort",
13 | "disable-redzone": true,
14 | "features": "-mmx,-sse,+soft-float"
15 | }
16 |
--------------------------------------------------------------------------------
/assets/demo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ruddle/Fomos/336be2d5bb2733f27e593dec70034a4f59650efd/assets/demo.mp4
--------------------------------------------------------------------------------
/bootloader/.cargo/config.toml:
--------------------------------------------------------------------------------
1 |
2 | [unstable]
3 | # enable the unstable artifact-dependencies feature, see
4 | # https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies
5 | bindeps = true
6 |
7 |
8 |
--------------------------------------------------------------------------------
/bootloader/Cargo.toml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [package]
5 | name = "loader"
6 | version = "0.1.0"
7 | edition = "2021"
8 |
9 | [build-dependencies]
10 | bootloader = "0.11.3"
11 | kernel = { path = "kernel", artifact = "bin", target = "x86_64-unknown-none" }
12 | #
13 | [dependencies]
14 |
15 | [workspace]
16 | members = ["kernel"]
--------------------------------------------------------------------------------
/bootloader/build.rs:
--------------------------------------------------------------------------------
1 | use std::path::PathBuf;
2 |
3 | use bootloader::BootConfig;
4 |
5 | fn main() {
6 | // set by cargo, build scripts should use this directory for output files
7 | let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
8 | // set by cargo's artifact dependency feature, see
9 | // https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies
10 | let kernel = PathBuf::from(std::env::var_os("CARGO_BIN_FILE_KERNEL_kernel").unwrap());
11 |
12 | // create an UEFI disk image (optional)
13 | let uefi_path = out_dir.join("uefi.img");
14 |
15 | let mut conf = BootConfig::default();
16 | conf.frame_buffer.minimum_framebuffer_width = Some(1200);
17 | bootloader::UefiBoot::new(&kernel)
18 | .set_boot_config(&conf)
19 | .create_disk_image(&uefi_path)
20 | .unwrap();
21 |
22 | // create a BIOS disk image
23 | let bios_path = out_dir.join("bios.img");
24 | bootloader::BiosBoot::new(&kernel)
25 | .create_disk_image(&bios_path)
26 | .unwrap();
27 |
28 | // pass the disk image paths as env variables to the `main.rs`
29 | println!("cargo:rustc-env=UEFI_PATH={}", uefi_path.display());
30 | println!("cargo:rustc-env=BIOS_PATH={}", bios_path.display());
31 | }
32 |
--------------------------------------------------------------------------------
/bootloader/kernel/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "kernel"
7 | version = "0.1.0"
8 |
--------------------------------------------------------------------------------
/bootloader/kernel/Cargo.toml:
--------------------------------------------------------------------------------
1 |
2 | [package]
3 | name = "kernel"
4 | version = "0.1.0"
5 | edition = "2021"
6 | [[bin]]
7 | name="kernel"
8 | test = false
9 | bench = false
10 |
11 | [dependencies]
12 | bootloader_api = "0.11.3"
13 | bootloader-boot-config = "0.11.3"
14 | conquer-once = { version = "0.3.2", default-features = false }
15 | spinning_top = "0.2.4"
16 | usize_conversions = "0.2.0"
17 | x86_64 = { version = "0.14.8" }
18 | xmas-elf = "0.8.0"
19 | raw-cpuid = "10.2.0"
20 | rand = { version = "0.8.4", default-features = false }
21 | rand_hc = "0.3.1"
22 | uart_16550 = "0.2.18"
23 | log = "0.4.17"
24 | acpi = "4.1.1"
25 | linked_list_allocator = "0.9.0"
26 | iced-x86 = {version = "1.18.0", default-features = false, features= ["decoder", "no_std","nasm"]}
27 | arrayvec = {version="0.7.2", default-features = false}
28 | bitfield = "0.14.0"
29 | crossbeam = {version="0.8", default-features=false, features=["alloc"]}
30 | hashbrown = {version="0.13.2"}
31 | edid-rs = {version="0.1.0", default-features=false, features=["no_std"]}
32 | spin = "0.5.2"
33 | # virtio-drivers = "0.3.0"
34 | [dependencies.noto-sans-mono-bitmap]
35 | version = "0.2.0"
36 | default-features = false
37 | features = [
38 | "regular",
39 | "size_16",
40 | "unicode-basic-latin",
41 | # required for the fallback char '�'
42 | "unicode-specials",
43 | ]
44 |
45 | [dependencies.lazy_static]
46 | version = "1.0"
47 | features = ["spin_no_std"]
48 |
49 | [dependencies.futures]
50 | version = "0.3.4"
51 | default-features = false
52 | features = ["alloc","async-await"]
--------------------------------------------------------------------------------
/bootloader/kernel/src/allocator.rs:
--------------------------------------------------------------------------------
1 | use alloc::alloc::{GlobalAlloc, Layout};
2 | use core::ptr::null_mut;
3 | extern "C" fn a_init(l: alloc::alloc::Layout) -> *mut u8 {
4 | panic!("")
5 | }
6 | extern "C" fn d_init(ptr: *mut u8, layout: alloc::alloc::Layout) {
7 | panic!("")
8 | }
9 |
10 | #[repr(C)]
11 | pub struct AllocFromCtx {
12 | a: extern "C" fn(alloc::alloc::Layout) -> *mut u8,
13 | d: extern "C" fn(*mut u8, alloc::alloc::Layout),
14 | }
15 | impl AllocFromCtx {
16 | pub fn init() -> Self {
17 | Self {
18 | a: a_init,
19 | d: d_init,
20 | }
21 | }
22 | pub fn new(
23 | a: extern "C" fn(alloc::alloc::Layout) -> *mut u8,
24 | d: extern "C" fn(*mut u8, alloc::alloc::Layout),
25 | ) -> Self {
26 | Self { a, d }
27 | }
28 | }
29 | unsafe impl GlobalAlloc for AllocFromCtx {
30 | unsafe fn alloc(&self, layout: alloc::alloc::Layout) -> *mut u8 {
31 | (self.a)(layout)
32 | }
33 |
34 | unsafe fn dealloc(&self, ptr: *mut u8, layout: alloc::alloc::Layout) {
35 | (self.d)(ptr, layout)
36 | }
37 | }
38 | // #[global_allocator]
39 | // static ALLOCATOR: AllocFromCtx = AllocFromCtx;
40 |
41 | use linked_list_allocator::LockedHeap;
42 |
43 | #[global_allocator]
44 | pub static ALLOCATOR: LockedHeap = LockedHeap::empty();
45 |
46 | pub const HEAP_START: usize = 0x_4444_4444_0000;
47 | pub const HEAP_SIZE: usize = 128 * 1024 * 1024; // 100 KiB
48 |
49 | use x86_64::{
50 | structures::paging::{
51 | mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB,
52 | },
53 | VirtAddr,
54 | };
55 |
56 | pub fn init_heap(
57 | mapper: &mut impl Mapper,
58 | frame_allocator: &mut impl FrameAllocator,
59 | ) -> Result<(), MapToError> {
60 | let page_range = {
61 | let heap_start = VirtAddr::new(HEAP_START as u64);
62 | let heap_end = heap_start + HEAP_SIZE - 1u64;
63 | let heap_start_page = Page::containing_address(heap_start);
64 | let heap_end_page = Page::containing_address(heap_end);
65 | Page::range_inclusive(heap_start_page, heap_end_page)
66 | };
67 |
68 | for page in page_range {
69 | let frame = frame_allocator
70 | .allocate_frame()
71 | .ok_or(MapToError::FrameAllocationFailed)?;
72 | let flags =
73 | PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
74 | unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
75 | }
76 |
77 | unsafe {
78 | ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
79 | }
80 |
81 | Ok(())
82 | }
83 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/app.rs:
--------------------------------------------------------------------------------
1 | use core::{
2 | alloc::Layout,
3 | sync::atomic::{AtomicU64, Ordering},
4 | };
5 |
6 | use alloc::{boxed::Box, fmt::format, format, string::String, vec::Vec};
7 | use xmas_elf::{program, sections::SectionData, ElfFile};
8 |
9 | use crate::{allocator::ALLOCATOR, framebuffer::FBShare, globals, interrupts::global_time_ms};
10 |
11 | #[repr(C)]
12 | pub struct Context<'a> {
13 | pub version: u8,
14 | pub start_time: u64,
15 | pub log: extern "C" fn(*const u8, u32),
16 | pub pid: u64,
17 | pub fb: FBShare<'a>,
18 | pub calloc: extern "C" fn(usize, usize) -> *mut u8,
19 | pub cdalloc: extern "C" fn(*mut u8, usize, usize),
20 | pub store: &'a mut Option>,
21 | pub input: &'a globals::Input,
22 | }
23 | static mut none: Option> = None;
24 | impl<'a> Context<'a> {
25 | pub fn new(
26 | log: extern "C" fn(*const u8, u32),
27 | fb: FBShare<'a>,
28 | calloc: extern "C" fn(usize, usize) -> *mut u8,
29 | cdalloc: extern "C" fn(*mut u8, usize, usize),
30 | input: &'a globals::Input,
31 | ) -> Context<'a> {
32 | let x = Context {
33 | version: 1,
34 | start_time: global_time_ms(),
35 | log,
36 | pid: 0,
37 | fb,
38 | calloc,
39 | cdalloc,
40 | store: unsafe { &mut none },
41 | input,
42 | };
43 |
44 | return x;
45 | }
46 | }
47 |
48 | type FuncType = extern "C" fn(arg: &mut Context) -> i32;
49 |
50 | pub struct App {
51 | pub code: Vec,
52 | pub func: FuncType,
53 | pub pid: u64,
54 | pub store: Option>,
55 | }
56 | impl App {
57 | pub fn new(code: &[u8], show: bool) -> App {
58 | let code = code.to_vec();
59 | let code = &code[..];
60 |
61 | // log::info!("loa efl");
62 | let elf = ElfFile::new(code).expect("elf");
63 | // log::info!("Elf file loaded at {:#p}", elf.input);
64 | // log::info!("{:#?}", elf.header);
65 |
66 | let mut min_virt = u64::MAX;
67 | let mut max_virt = 0;
68 |
69 | for program_header in elf.program_iter() {
70 | if program_header.mem_size() > 0 {
71 | min_virt = min_virt.min(program_header.virtual_addr());
72 | max_virt = max_virt.max(program_header.virtual_addr() + program_header.mem_size());
73 | }
74 | }
75 |
76 | min_virt = 0;
77 | let cap = max_virt as usize;
78 | use core::alloc::GlobalAlloc;
79 | let ptr = unsafe { ALLOCATOR.alloc(Layout::from_size_align_unchecked(cap, 4096)) };
80 |
81 | let mut owned_code: Vec = unsafe { Vec::from_raw_parts(ptr, 0, cap) }; //Vec::with_capacity((max_virt - min_virt) as usize);
82 | for i in min_virt..max_virt {
83 | owned_code.push(0);
84 | }
85 |
86 | for program_header in elf.program_iter() {
87 | // log::info!("{:?}", program_header);
88 |
89 | if let Ok(program::Type::Load) = program_header.get_type() {
90 | let mut byte = 0;
91 | let seg_offset = (program_header.virtual_addr() - min_virt) as usize;
92 | for e in (program_header.offset() as usize)
93 | ..(program_header.offset() as usize + ((program_header.file_size()) as usize))
94 | {
95 | owned_code[byte + seg_offset] = code[e];
96 | byte += 1;
97 | }
98 |
99 | if let Some(rela) = elf.find_section_by_name(".rela.dyn") {
100 | if let Ok(SectionData::Rela64(arr)) = rela.get_data(&elf) {
101 | for r in &arr[0..] {
102 | let off = r.get_offset() as usize;
103 | let add = r.get_addend() as usize;
104 | let typ = r.get_type() as usize;
105 | if off >= program_header.virtual_addr() as usize
106 | && off
107 | < program_header.virtual_addr() as usize
108 | + program_header.mem_size() as usize
109 | {
110 | // log::info!("{:?}", r);
111 | unsafe {
112 | let global_off = owned_code.as_ptr() as u64;
113 | let p64 = owned_code.as_ptr().offset(off as isize) as *mut u64;
114 | p64.write(add as u64 + global_off);
115 | }
116 |
117 | // for k in 0..8 {
118 | // owned_code[off + k] = owned_code[add + k];
119 | // }
120 | }
121 | }
122 | }
123 | }
124 | }
125 | }
126 |
127 | // log::info!("{:?}", owned_code);
128 | let codep = unsafe {
129 | owned_code
130 | .as_mut_ptr()
131 | .offset((elf.header.pt2.entry_point() - min_virt) as isize)
132 | };
133 | // log::info!("ptr {:?}", codep);
134 | let codef: FuncType = unsafe { core::intrinsics::transmute(codep) };
135 |
136 | static NEXT_ID: AtomicU64 = AtomicU64::new(0);
137 |
138 | if show {
139 | let entry = (elf.header.pt2.entry_point() - min_virt) as usize;
140 | let code = &mut owned_code[entry..];
141 | use iced_x86::{Decoder, DecoderOptions, Formatter, Instruction, NasmFormatter};
142 | let EXAMPLE_CODE_RIP = entry as u64;
143 | let HEXBYTES_COLUMN_BYTE_LENGTH = 8;
144 | let mut decoder = Decoder::with_ip(64, code, EXAMPLE_CODE_RIP, DecoderOptions::NONE);
145 |
146 | // Formatters: Masm*, Nasm*, Gas* (AT&T) and Intel* (XED).
147 | // For fastest code, see `SpecializedFormatter` which is ~3.3x faster. Use it if formatting
148 | // speed is more important than being able to re-assemble formatted instructions.
149 | let mut formatter = NasmFormatter::new();
150 |
151 | // Change some options, there are many more
152 | formatter.options_mut().set_digit_separator("`");
153 | formatter.options_mut().set_first_operand_char_index(10);
154 |
155 | // String implements FormatterOutput
156 | let mut output = String::new();
157 |
158 | // Initialize this outside the loop because decode_out() writes to every field
159 | let mut instruction = Instruction::default();
160 |
161 | // The decoder also implements Iterator/IntoIterator so you could use a for loop:
162 | // for instruction in &mut decoder { /* ... */ }
163 | // or collect():
164 | // let instructions: Vec<_> = decoder.into_iter().collect();
165 | // but can_decode()/decode_out() is a little faster:
166 | while decoder.can_decode() {
167 | // There's also a decode() method that returns an instruction but that also
168 | // means it copies an instruction (40 bytes):
169 | // instruction = decoder.decode();
170 | decoder.decode_out(&mut instruction);
171 |
172 | log::info!("{:?}", instruction);
173 |
174 | // Format the instruction ("disassemble" it)
175 | output.clear();
176 | formatter.format(&instruction, &mut output);
177 |
178 | // Eg. "00007FFAC46ACDB2 488DAC2400FFFFFF lea rbp,[rsp-100h]"
179 | let mut strbuild = String::new();
180 |
181 | strbuild = format!("{}{:016X} ", strbuild, instruction.ip());
182 | let start_index = (instruction.ip() - EXAMPLE_CODE_RIP) as usize;
183 | let instr_bytes = &code[start_index..start_index + instruction.len()];
184 | for b in instr_bytes.iter() {
185 | strbuild = format!("{}{:02X}", strbuild, b);
186 | }
187 | if instr_bytes.len() < HEXBYTES_COLUMN_BYTE_LENGTH {
188 | for _ in 0..HEXBYTES_COLUMN_BYTE_LENGTH - instr_bytes.len() {
189 | strbuild = format!("{} ", strbuild);
190 | }
191 | }
192 | log::info!("{} {}", strbuild, output);
193 | }
194 | }
195 |
196 | App {
197 | code: owned_code,
198 | func: codef,
199 | pid: NEXT_ID.fetch_add(1, Ordering::Relaxed),
200 | store: None,
201 | }
202 | }
203 | pub fn call(&mut self, arg: &mut Context) -> i32 {
204 | *arg.store = None;
205 |
206 | arg.pid = self.pid;
207 |
208 | let self_store = self.store.take();
209 |
210 | *arg.store = self_store;
211 | let res = (self.func)(arg);
212 |
213 | self.store = arg.store.take();
214 |
215 | res
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/drivers/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod virtio_gpu;
2 | pub mod virtio_input;
3 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/drivers/virtio_input.rs:
--------------------------------------------------------------------------------
1 | use crate::{task::executor::yield_once, virtio::Virtio};
2 |
3 | #[repr(C)]
4 | #[derive(Debug)]
5 | struct VirtioInputEvent {
6 | type_: u16,
7 | code: u16,
8 | value: u32,
9 | }
10 | ///Handle the virtio device and export all data to globals::Input
11 | pub async fn drive(mut virtio: Virtio) {
12 | unsafe {
13 | let q = 0;
14 | virtio.queue_select(q);
15 | while let Some(desc_id) = virtio.get_free_desc_id() {
16 | virtio.set_writable_available(desc_id);
17 | }
18 | loop {
19 | while let Some(used) = virtio.next_used() {
20 | let desc = virtio.read_desc(used.id as u16);
21 | let evt = (desc.addr as *const VirtioInputEvent).read_volatile();
22 | crate::globals::INPUT.update(|input| match evt.type_ {
23 | 0 => { /*no op */ }
24 | 1 => input.handle_incoming_state(evt.code as usize, evt.value != 0),
25 | 2 => {
26 | let d: i32 = core::intrinsics::transmute(evt.value);
27 | match evt.code {
28 | 0 => input.mouse_x = (input.mouse_x as i32 + d).max(0) as usize,
29 | 1 => input.mouse_y = (input.mouse_y as i32 + d).max(0) as usize,
30 | _ => log::error!("virtio_input: unknown event {:?}", evt),
31 | }
32 | }
33 | _ => log::error!("virtio_input: unknown event {:?}", evt),
34 | });
35 | virtio.set_writable_available(used.id as u16);
36 | }
37 | yield_once().await;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/framebuffer.rs:
--------------------------------------------------------------------------------
1 | use bootloader_api::info::{FrameBufferInfo, PixelFormat};
2 |
3 | use core::{fmt, ptr};
4 | use font_constants::BACKUP_CHAR;
5 | use noto_sans_mono_bitmap::{
6 | get_raster, get_raster_width, FontWeight, RasterHeight, RasterizedChar,
7 | };
8 |
9 | /// Additional vertical space between lines
10 | const LINE_SPACING: usize = 2;
11 | /// Additional horizontal space between characters.
12 | const LETTER_SPACING: usize = 0;
13 |
14 | /// Padding from the border. Prevent that font is too close to border.
15 | const BORDER_PADDING: usize = 1;
16 |
17 | /// Constants for the usage of the [`noto_sans_mono_bitmap`] crate.
18 | mod font_constants {
19 | use super::*;
20 |
21 | /// Height of each char raster. The font size is ~0.84% of this. Thus, this is the line height that
22 | /// enables multiple characters to be side-by-side and appear optically in one line in a natural way.
23 | pub const CHAR_RASTER_HEIGHT: RasterHeight = RasterHeight::Size16;
24 |
25 | /// The width of each single symbol of the mono space font.
26 | pub const CHAR_RASTER_WIDTH: usize = get_raster_width(FontWeight::Regular, CHAR_RASTER_HEIGHT);
27 |
28 | /// Backup character if a desired symbol is not available by the font.
29 | /// The '�' character requires the feature "unicode-specials".
30 | pub const BACKUP_CHAR: char = '�';
31 |
32 | pub const FONT_WEIGHT: FontWeight = FontWeight::Regular;
33 | }
34 |
35 | /// Returns the raster of the given char or the raster of [`font_constants::BACKUP_CHAR`].
36 | fn get_char_raster(c: char) -> RasterizedChar {
37 | fn get(c: char) -> Option {
38 | get_raster(
39 | c,
40 | font_constants::FONT_WEIGHT,
41 | font_constants::CHAR_RASTER_HEIGHT,
42 | )
43 | }
44 | get(c).unwrap_or_else(|| get(BACKUP_CHAR).expect("Should get raster of backup char."))
45 | }
46 |
47 | /// Allows logging text to a pixel-based framebuffer.
48 | pub struct FrameBufferWriter {
49 | framebuffer: &'static mut [u8],
50 | info: FrameBufferInfo,
51 | x_pos: usize,
52 | y_pos: usize,
53 | pub level: usize,
54 | }
55 |
56 | impl FrameBufferWriter {
57 | /// Creates a new logger that uses the given framebuffer.
58 | pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
59 | let mut logger = Self {
60 | framebuffer,
61 | info,
62 | x_pos: 0,
63 | y_pos: 0,
64 | level: 0,
65 | };
66 | logger.clear();
67 | logger
68 | }
69 |
70 | fn newline(&mut self) {
71 | self.y_pos += font_constants::CHAR_RASTER_HEIGHT.val() + LINE_SPACING;
72 | self.carriage_return()
73 | }
74 |
75 | fn carriage_return(&mut self) {
76 | self.x_pos = BORDER_PADDING;
77 | }
78 |
79 | /// Erases all text on the screen. Resets `self.x_pos` and `self.y_pos`.
80 | pub fn clear(&mut self) {
81 | self.x_pos = BORDER_PADDING;
82 | self.y_pos = BORDER_PADDING;
83 | self.framebuffer.fill(0);
84 | }
85 |
86 | fn width(&self) -> usize {
87 | self.info.width
88 | }
89 |
90 | fn height(&self) -> usize {
91 | self.info.height
92 | }
93 |
94 | /// Writes a single char to the framebuffer. Takes care of special control characters, such as
95 | /// newlines and carriage returns.
96 | fn write_char(&mut self, c: char) {
97 | match c {
98 | '\n' => self.newline(),
99 | '\r' => self.carriage_return(),
100 | c => {
101 | let new_xpos = self.x_pos + font_constants::CHAR_RASTER_WIDTH;
102 | if new_xpos >= self.width() {
103 | self.newline();
104 | }
105 | let new_ypos =
106 | self.y_pos + font_constants::CHAR_RASTER_HEIGHT.val() + BORDER_PADDING;
107 | if new_ypos >= self.height() {
108 | self.clear();
109 | }
110 | self.write_rendered_char(get_char_raster(c));
111 | }
112 | }
113 | }
114 |
115 | /// Prints a rendered char into the framebuffer.
116 | /// Updates `self.x_pos`.
117 | fn write_rendered_char(&mut self, rendered_char: RasterizedChar) {
118 | for (y, row) in rendered_char.raster().iter().enumerate() {
119 | for (x, byte) in row.iter().enumerate() {
120 | self.write_pixel(self.x_pos + x, self.y_pos + y, *byte);
121 | }
122 | }
123 | self.x_pos += rendered_char.width() + LETTER_SPACING;
124 | }
125 |
126 | fn write_pixel(&mut self, x: usize, y: usize, intensity: u8) {
127 | let pixel_offset = y * self.info.stride + x;
128 |
129 | let r = intensity;
130 | let g = [intensity, 0][self.level];
131 | let b = [intensity / 2, 0][self.level];
132 | let color = match self.info.pixel_format {
133 | PixelFormat::Rgb => [r, g, b, 0],
134 | PixelFormat::Bgr => [b, g, r, 0],
135 | PixelFormat::U8 => [if intensity > 200 { 0xf } else { 0 }, 0, 0, 0],
136 | other => {
137 | // set a supported (but invalid) pixel format before panicking to avoid a double
138 | // panic; it might not be readable though
139 | self.info.pixel_format = PixelFormat::Rgb;
140 | panic!("pixel format {:?} not supported in logger", other)
141 | }
142 | };
143 | let bytes_per_pixel = self.info.bytes_per_pixel;
144 | let byte_offset = pixel_offset * bytes_per_pixel;
145 | self.framebuffer[byte_offset..(byte_offset + bytes_per_pixel)]
146 | .copy_from_slice(&color[..bytes_per_pixel]);
147 | let _ = unsafe { ptr::read_volatile(&self.framebuffer[byte_offset]) };
148 | }
149 | }
150 |
151 | unsafe impl Send for FrameBufferWriter {}
152 | unsafe impl Sync for FrameBufferWriter {}
153 |
154 | impl fmt::Write for FrameBufferWriter {
155 | fn write_str(&mut self, s: &str) -> fmt::Result {
156 | // for c in s.chars() {
157 | // self.write_char(c);
158 | // }
159 |
160 | Ok(())
161 | }
162 | }
163 | use alloc::{slice, vec::Vec};
164 |
165 | use crate::interrupts::global_time_ms;
166 | // extern crate alloc;
167 | #[derive(Debug, Clone, Copy, PartialEq, Eq)]
168 | #[repr(C)]
169 | pub struct RGBA {
170 | pub r: u8,
171 | pub g: u8,
172 | pub b: u8,
173 | pub a: u8,
174 | }
175 | #[derive(Clone)]
176 | #[repr(C)]
177 | pub struct FB {
178 | pub pixels: Vec,
179 | pub backbuffer: Vec,
180 | pub w: usize,
181 | pub h: usize,
182 | }
183 |
184 | #[repr(C)]
185 | pub struct FBShare<'a> {
186 | pub pixels: &'a mut [RGBA],
187 | pub w: usize,
188 | pub h: usize,
189 | }
190 | impl FB {
191 | pub fn new(info: &FrameBufferInfo) -> Self {
192 | let w = info.width;
193 | let h = info.height;
194 | let mut pixels = Vec::with_capacity(w * h);
195 | let mut backbuffer = Vec::with_capacity(w * h);
196 | for y in 0..h {
197 | for x in 0..w {
198 | pixels.push(RGBA {
199 | r: x as u8,
200 | g: y as u8,
201 | b: 0,
202 | a: 0,
203 | });
204 | backbuffer.push(pixels[pixels.len() - 1]);
205 | }
206 | }
207 | FB {
208 | pixels,
209 | w,
210 | h,
211 | backbuffer,
212 | }
213 | }
214 |
215 | pub fn update(&mut self, vec: *mut RGBA, w: usize, h: usize) {
216 | self.pixels = unsafe { Vec::from_raw_parts(vec, h * w, w * h) };
217 | self.w = w;
218 | self.h = h;
219 | }
220 |
221 | pub fn share(&mut self) -> FBShare {
222 | FBShare {
223 | pixels: &mut self.pixels[..],
224 | w: self.w,
225 | h: self.h,
226 | }
227 | }
228 |
229 | pub fn flush(&mut self, framebuffer: &mut [u8], info: &FrameBufferInfo) {
230 | let mut todraw = &self.pixels;
231 |
232 | let start = global_time_ms();
233 |
234 | // match info.pixel_format {
235 | // PixelFormat::Bgr => {
236 | // for (idx, &i) in self.pixels.iter().enumerate() {
237 | // self.backbuffer[idx].r = i.b;
238 | // self.backbuffer[idx].g = i.g;
239 | // self.backbuffer[idx].b = i.r;
240 | // }
241 | // // todraw = &self.backbuffer;
242 | // }
243 | // _ => {}
244 | // }
245 |
246 | // let time0 = get_time_ms() - start;
247 |
248 | // let start = get_time_ms();
249 | framebuffer.copy_from_slice(unsafe {
250 | slice::from_raw_parts(todraw.as_ptr() as *const u8, framebuffer.len())
251 | });
252 | // log::info!("step 0 FB {}ms", time0);
253 | // log::info!("step 1 FB {}ms", get_time_ms() - start);
254 | // for y in 0..self.h {
255 | // for x in 0..self.w {
256 | // let RGBA { r, g, b, a } = self.pixels[x + self.w * y];
257 | // let pixel_offset = y * info.stride + x;
258 |
259 | // let color = match info.pixel_format {
260 | // PixelFormat::Rgb => [r, g, b, 0],
261 | // PixelFormat::Bgr => [b, g, r, 0],
262 | // PixelFormat::U8 => [if (g + b + r) as usize > 200 { 0xf } else { 0 }, 0, 0, 0],
263 | // other => {
264 | // // set a supported (but invalid) pixel format before panicking to avoid a double
265 | // // panic; it might not be readable though
266 | // // info.pixel_format = PixelFormat::Rgb;
267 | // panic!("pixel format {:?} not supported in logger", other)
268 | // }
269 | // };
270 | // let bytes_per_pixel = info.bytes_per_pixel;
271 | // let byte_offset = pixel_offset * bytes_per_pixel;
272 | // framebuffer[byte_offset..(byte_offset + bytes_per_pixel)]
273 | // .copy_from_slice(&color[..bytes_per_pixel]);
274 | // }
275 | // }
276 | }
277 |
278 | // pub fn set(x: usize, y: usize)
279 | }
280 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/gdt.rs:
--------------------------------------------------------------------------------
1 | use lazy_static::lazy_static;
2 | use x86_64::structures::tss::TaskStateSegment;
3 | use x86_64::VirtAddr;
4 |
5 | use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
6 |
7 | lazy_static! {
8 | static ref GDT: (GlobalDescriptorTable, Selectors) = {
9 | let mut gdt = GlobalDescriptorTable::new();
10 | let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
11 | let data_selector = gdt.add_entry(Descriptor::kernel_data_segment());
12 | let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
13 | (
14 | gdt,
15 | Selectors {
16 | code_selector,
17 | tss_selector,
18 | data_selector,
19 | },
20 | )
21 | };
22 | }
23 | struct Selectors {
24 | code_selector: SegmentSelector,
25 | data_selector: SegmentSelector,
26 | tss_selector: SegmentSelector,
27 | }
28 | pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
29 |
30 | lazy_static! {
31 | static ref TSS: TaskStateSegment = {
32 | let mut tss = TaskStateSegment::new();
33 | tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
34 | const STACK_SIZE: usize = 4*1024 ; //4096 * 5;
35 | static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
36 |
37 | let stack_start = VirtAddr::from_ptr(unsafe { &STACK });
38 | let stack_end = stack_start + STACK_SIZE;
39 | stack_end
40 | };
41 | tss
42 | };
43 | }
44 | pub fn init() {
45 | use x86_64::instructions::segmentation::{Segment, CS, DS, ES, SS};
46 | use x86_64::instructions::tables::load_tss;
47 | GDT.0.load();
48 | unsafe {
49 | // CS::set_reg(code_selector);
50 | DS::set_reg(GDT.1.data_selector);
51 | ES::set_reg(GDT.1.data_selector);
52 | SS::set_reg(GDT.1.data_selector);
53 | CS::set_reg(GDT.1.code_selector);
54 | load_tss(GDT.1.tss_selector);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/globals.rs:
--------------------------------------------------------------------------------
1 | use crossbeam::atomic::AtomicCell;
2 |
3 | pub static INPUT: GLOBAL = GLOBAL::new(Input::new());
4 | pub struct GLOBAL(AtomicCell);
5 |
6 | const HISTORY_SIZE: usize = 64;
7 | impl GLOBAL {
8 | pub const fn new(t: T) -> Self {
9 | Self(AtomicCell::new(t))
10 | }
11 | ///Might lose data if multiple thread calls it simultaneously
12 | pub fn update(&self, func: F)
13 | where
14 | F: FnOnce(&mut T),
15 | {
16 | let mut v = self.0.load();
17 | func(&mut v);
18 | self.0.store(v)
19 | }
20 | pub fn read(&self) -> T {
21 | self.0.load()
22 | }
23 | }
24 | #[repr(C)]
25 | #[derive(Clone, Debug, Copy)]
26 | pub struct InputEvent {
27 | pub trigger: bool,
28 | pub key: usize,
29 | }
30 | #[repr(C)]
31 | #[derive(Clone, Debug, Copy)]
32 | pub struct Input {
33 | pub mouse_x: usize,
34 | pub mouse_y: usize,
35 | pub keys: [KeyState; 1024],
36 | pub history_last_index: usize,
37 | pub history_ring: [InputEvent; HISTORY_SIZE],
38 | }
39 |
40 | impl Input {
41 | pub const fn new() -> Self {
42 | Self {
43 | mouse_x: 0,
44 | mouse_y: 0,
45 | keys: [KeyState::Off; 1024],
46 | history_last_index: 0,
47 | history_ring: [InputEvent {
48 | trigger: false,
49 | key: 0,
50 | }; HISTORY_SIZE],
51 | }
52 | }
53 | pub fn step(&mut self) {
54 | for k in self.keys.iter_mut() {
55 | k.step();
56 | }
57 | }
58 | }
59 |
60 | #[repr(u8)]
61 | #[derive(Clone, Debug, Copy)]
62 | pub enum KeyState {
63 | ///Key is not pressed now
64 | Off = 0,
65 | ///Key is not pressed now, but was last frame
66 | OffFromOn = 1,
67 | ///Key is not pressed now, it was not pressed last frame either, but was during frame (sequence Off -> On -> Off)
68 | OffTransientOn = 2,
69 | OnFromOff = 128,
70 | OnTransientOff = 129,
71 | On = 130,
72 | }
73 | impl Default for KeyState {
74 | fn default() -> Self {
75 | KeyState::Off
76 | }
77 | }
78 |
79 | impl Input {
80 | pub fn handle_incoming_state(&mut self, key: usize, b: bool) {
81 | self.history_last_index += 1;
82 | self.history_ring[self.history_last_index % HISTORY_SIZE] = InputEvent { trigger: b, key };
83 | self.keys[key].handle_incoming_state(b);
84 | }
85 | }
86 |
87 | impl KeyState {
88 | pub fn handle_incoming_state(&mut self, b: bool) {
89 | *self = match (*self, b) {
90 | (KeyState::Off, true) => KeyState::OnFromOff,
91 | (KeyState::On, false) => KeyState::OffFromOn,
92 | (KeyState::OffFromOn, true) => KeyState::OnTransientOff,
93 | (KeyState::OnFromOff, false) => KeyState::OffTransientOn,
94 | (_, false) => KeyState::Off,
95 | (_, true) => KeyState::On,
96 | }
97 | }
98 | ///To call every kernel loop
99 | pub fn step(&mut self) {
100 | *self = match *self {
101 | KeyState::OffTransientOn => KeyState::Off,
102 | KeyState::OffFromOn => KeyState::Off,
103 | KeyState::OnFromOff => KeyState::On,
104 | KeyState::OnTransientOff => KeyState::On,
105 | _ => *self,
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/interrupts.rs:
--------------------------------------------------------------------------------
1 | use core::sync::atomic::AtomicU64;
2 | use core::sync::atomic::Ordering;
3 | use core::task::Waker;
4 |
5 | use crate::gdt;
6 | use crate::globals::GLOBAL;
7 | use crate::ioapic;
8 |
9 | use conquer_once::spin::OnceCell;
10 | use crossbeam::queue::ArrayQueue;
11 | use lazy_static::lazy_static;
12 | use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
13 | lazy_static! {
14 | static ref IDT: InterruptDescriptorTable = {
15 | let mut idt = InterruptDescriptorTable::new();
16 | idt.breakpoint.set_handler_fn(breakpoint_handler);
17 | idt.alignment_check.set_handler_fn(alignment_check);
18 |
19 |
20 | idt.invalid_opcode.set_handler_fn(invalid_opcode);
21 | idt.bound_range_exceeded.set_handler_fn(bound_range_exceeded);
22 | idt.general_protection_fault.set_handler_fn(general_protection_fault);
23 | unsafe {
24 | idt.double_fault.set_handler_fn(double_fault_handler)
25 | .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); // new
26 | }
27 | unsafe {
28 | idt.overflow.set_handler_fn(overflow_handler)
29 | .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); // new
30 | }
31 |
32 | idt.invalid_tss.set_handler_fn(invalid_tss_handler);
33 | idt.segment_not_present.set_handler_fn(segment_not_present_handler);
34 | idt.stack_segment_fault.set_handler_fn(stack_segment_fault_handler);
35 | idt.alignment_check.set_handler_fn(alignment_check_handler);
36 |
37 |
38 |
39 | idt.page_fault.set_handler_fn(page_fault_handler);
40 |
41 |
42 | for i in 32..=255{
43 | idt[i].set_handler_fn(generic_handler);
44 | }
45 |
46 | idt[48].set_handler_fn(lapic_timer);
47 | idt[49].set_handler_fn(lapic_timer2);
48 |
49 | idt[50+0].set_handler_fn(ioapic_handler_0);
50 | idt[50+1].set_handler_fn(ioapic_handler_1);
51 | idt[50+2].set_handler_fn(ioapic_handler_2);
52 | idt[50+3].set_handler_fn(ioapic_handler_3);
53 | idt[50+4].set_handler_fn(ioapic_handler_4);
54 | idt[50+5].set_handler_fn(ioapic_handler_5);
55 | idt[50+6].set_handler_fn(ioapic_handler_6);
56 | idt[50+7].set_handler_fn(ioapic_handler_7);
57 | idt[50+8].set_handler_fn(ioapic_handler_8);
58 | idt[50+9].set_handler_fn(ioapic_handler_9);
59 | idt[50+10].set_handler_fn(ioapic_handler_10);
60 | idt[50+11].set_handler_fn(ioapic_handler_11);
61 | idt[50+12].set_handler_fn(ioapic_handler_12);
62 | idt[50+13].set_handler_fn(ioapic_handler_13);
63 | idt[50+14].set_handler_fn(ioapic_handler_14);
64 | idt[50+15].set_handler_fn(ioapic_handler_15);
65 | idt[50+16].set_handler_fn(ioapic_handler_16);
66 | idt[50+17].set_handler_fn(ioapic_handler_17);
67 | idt[50+18].set_handler_fn(ioapic_handler_18);
68 | idt[50+19].set_handler_fn(ioapic_handler_19);
69 | idt[50+20].set_handler_fn(ioapic_handler_20);
70 | idt[50+21].set_handler_fn(ioapic_handler_21);
71 | idt[50+22].set_handler_fn(ioapic_handler_22);
72 | idt[50+23].set_handler_fn(ioapic_handler_23);
73 |
74 | idt
75 | };
76 | }
77 |
78 | pub static TIME_MS: AtomicU64 = AtomicU64::new(0);
79 | extern "x86-interrupt" fn lapic_timer(stack_frame: InterruptStackFrame) {
80 | unsafe {
81 | crate::local_apic::LOCAL_APIC.get().unwrap().eoi();
82 | };
83 | let ms = 1 + TIME_MS.fetch_add(1, Ordering::Relaxed);
84 |
85 | let mut arr = WAKERS.lock();
86 | for w in arr.iter_mut() {
87 | if let Some(waker) = w {
88 | waker.wake();
89 | }
90 | *w = None;
91 | }
92 | WAKER.wake();
93 | }
94 |
95 | pub fn global_time_ms() -> u64 {
96 | TIME_MS.load(Ordering::Relaxed)
97 | }
98 |
99 | pub fn wait_block(ms: u64) {
100 | let current = TIME_MS.load(Ordering::Relaxed);
101 | loop {
102 | if TIME_MS.load(Ordering::Relaxed) > current + ms {
103 | break;
104 | } else {
105 | x86_64::instructions::nop();
106 | x86_64::instructions::nop();
107 | x86_64::instructions::nop();
108 | x86_64::instructions::nop();
109 | x86_64::instructions::nop();
110 | x86_64::instructions::nop();
111 | x86_64::instructions::nop();
112 | x86_64::instructions::nop();
113 | }
114 | }
115 | }
116 | pub async fn a_sleep(ms: u64) {
117 | let timer = Timer::new(ms);
118 | timer.await;
119 | }
120 | pub struct Timer {
121 | stop: u64,
122 | }
123 |
124 | impl Timer {
125 | pub fn new(ms: u64) -> Self {
126 | Timer {
127 | stop: global_time_ms() + ms,
128 | }
129 | }
130 | }
131 | impl futures::future::Future for Timer {
132 | type Output = ();
133 | fn poll(
134 | self: core::pin::Pin<&mut Self>,
135 | cx: &mut core::task::Context<'_>,
136 | ) -> core::task::Poll {
137 | if global_time_ms() >= self.stop {
138 | return core::task::Poll::Ready(());
139 | }
140 |
141 | let id = add_waker(&cx.waker());
142 | // WAKER.register(&cx.waker());
143 |
144 | if global_time_ms() >= self.stop {
145 | core::task::Poll::Ready(())
146 | } else {
147 | core::task::Poll::Pending
148 | }
149 | }
150 | }
151 |
152 | use spin::Mutex;
153 |
154 | type WAKERS_T = [Option; 128];
155 | lazy_static! {
156 | pub static ref WAKERS: Mutex = Mutex::new([(); 128].map(|_| None));
157 | }
158 |
159 | pub fn add_waker(waker: &Waker) -> u64 {
160 | let mut arr = WAKERS.lock();
161 | for (index, aw) in arr.iter_mut().enumerate() {
162 | if aw.is_none() {
163 | let w = AtomicWaker::new();
164 | w.register(waker);
165 | *aw = Some(w);
166 | return index as u64;
167 | }
168 | }
169 |
170 | 0
171 | }
172 |
173 | use futures::task::AtomicWaker;
174 |
175 | static WAKER: AtomicWaker = AtomicWaker::new();
176 |
177 | extern "x86-interrupt" fn lapic_timer2(stack_frame: InterruptStackFrame) {
178 | log::info!("timer2");
179 |
180 | unsafe {
181 | // crate::local_apic::LocalApic.get().unwrap().eoi();
182 | };
183 | }
184 | pub fn init_idt() {
185 | IDT.load();
186 | }
187 | extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
188 | log::error!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
189 | }
190 |
191 | extern "x86-interrupt" fn overflow_handler(stack_frame: InterruptStackFrame) {
192 | log::error!("EXCEPTION: overflow_handler\n{:#?}", stack_frame);
193 | panic!("");
194 | }
195 | extern "x86-interrupt" fn invalid_tss_handler(stack_frame: InterruptStackFrame, error_code: u64) {
196 | log::error!("EXCEPTION: invalid_tss {}\n{:#?}", error_code, stack_frame);
197 | panic!("");
198 | }
199 | extern "x86-interrupt" fn segment_not_present_handler(
200 | stack_frame: InterruptStackFrame,
201 | error_code: u64,
202 | ) {
203 | log::error!(
204 | "EXCEPTION: segment_not_present {}\n{:#?}",
205 | error_code,
206 | stack_frame
207 | );
208 | panic!("");
209 | }
210 | extern "x86-interrupt" fn stack_segment_fault_handler(
211 | stack_frame: InterruptStackFrame,
212 | error_code: u64,
213 | ) {
214 | log::error!(
215 | "EXCEPTION: stack_segment_fault {}\n{:#?}",
216 | error_code,
217 | stack_frame
218 | );
219 | panic!("");
220 | }
221 | extern "x86-interrupt" fn alignment_check_handler(
222 | stack_frame: InterruptStackFrame,
223 | error_code: u64,
224 | ) {
225 | log::error!(
226 | "EXCEPTION: alignment_check {}\n{:#?}",
227 | error_code,
228 | stack_frame
229 | );
230 | panic!("");
231 | }
232 | extern "x86-interrupt" fn double_fault_handler(
233 | stack_frame: InterruptStackFrame,
234 | _error_code: u64,
235 | ) -> ! {
236 | panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
237 | }
238 |
239 | extern "x86-interrupt" fn alignment_check(stack_frame: InterruptStackFrame, _error_code: u64) {
240 | panic!("EXCEPTION: alignment_check{:#?}", stack_frame);
241 | }
242 | extern "x86-interrupt" fn invalid_opcode(stack_frame: InterruptStackFrame) {
243 | panic!("EXCEPTION: invalid_opcode{:#?}", stack_frame);
244 | }
245 | extern "x86-interrupt" fn bound_range_exceeded(stack_frame: InterruptStackFrame) {
246 | panic!("EXCEPTION: bound_range_exceeded{:#?}", stack_frame);
247 | }
248 |
249 | extern "x86-interrupt" fn general_protection_fault(
250 | stack_frame: InterruptStackFrame,
251 | _error_code: u64,
252 | ) {
253 | panic!(
254 | "EXCEPTION: general_protection_fault {}\n{:#?}",
255 | _error_code, stack_frame
256 | );
257 | }
258 |
259 | use x86_64::structures::idt::PageFaultErrorCode;
260 |
261 | extern "x86-interrupt" fn page_fault_handler(
262 | stack_frame: InterruptStackFrame,
263 | error_code: PageFaultErrorCode,
264 | ) {
265 | use x86_64::registers::control::Cr2;
266 |
267 | log::error!("EXCEPTION: PAGE FAULT");
268 | log::error!("Accessed Address: {:?}", Cr2::read());
269 | log::error!("Error Code: {:?}", error_code);
270 | // log::error!("{:#?}", stack_frame);
271 |
272 | panic!("EXCEPTION: PAGE FAULT\n{:#?}", stack_frame);
273 | }
274 |
275 | extern "x86-interrupt" fn ioapic_handler_0(stack_frame: InterruptStackFrame) {
276 | log::info!("______ioapic_handler_0_____");
277 | }
278 | extern "x86-interrupt" fn ioapic_handler_1(stack_frame: InterruptStackFrame) {
279 | log::info!("______ioapic_handler_1_____");
280 | let ioa = ioapic::IO_APIC_0.get().expect("IoApic0");
281 | let n = ioa.read_redtlb(1);
282 | let mut red = ioapic::RedTbl::new(n);
283 | log::info!("{:?}", red);
284 | // let stored = red.store();
285 |
286 | unsafe {
287 | crate::local_apic::LOCAL_APIC.get().unwrap().eoi();
288 | };
289 | }
290 | extern "x86-interrupt" fn ioapic_handler_2(stack_frame: InterruptStackFrame) {
291 | // log::info!("______ioapic_handler_2_____");
292 |
293 | let ioa = ioapic::IO_APIC_0.get().expect("IoApic0");
294 | let n = ioa.read_redtlb(2);
295 | let mut red = ioapic::RedTbl::new(n);
296 |
297 | // log::info!("{:?}", red);
298 | let stored = red.store();
299 | ioa.write_redtlb(2, stored);
300 | unsafe {
301 | crate::local_apic::LOCAL_APIC.get().unwrap().eoi();
302 | };
303 | }
304 | extern "x86-interrupt" fn ioapic_handler_3(stack_frame: InterruptStackFrame) {
305 | log::info!("______ioapic_handler_3_____");
306 | }
307 | extern "x86-interrupt" fn ioapic_handler_4(stack_frame: InterruptStackFrame) {
308 | log::info!("______ioapic_handler_4_____");
309 | }
310 | extern "x86-interrupt" fn ioapic_handler_5(stack_frame: InterruptStackFrame) {
311 | log::info!("______ioapic_handler_5_____");
312 | }
313 | extern "x86-interrupt" fn ioapic_handler_6(stack_frame: InterruptStackFrame) {
314 | log::info!("______ioapic_handler_6_____");
315 | }
316 | extern "x86-interrupt" fn ioapic_handler_7(stack_frame: InterruptStackFrame) {
317 | log::info!("______ioapic_handler_7_____");
318 | }
319 | extern "x86-interrupt" fn ioapic_handler_8(stack_frame: InterruptStackFrame) {
320 | log::info!("______ioapic_handler_8_____");
321 | }
322 | extern "x86-interrupt" fn ioapic_handler_9(stack_frame: InterruptStackFrame) {
323 | log::info!("______ioapic_handler_9_____");
324 | }
325 | extern "x86-interrupt" fn ioapic_handler_10(stack_frame: InterruptStackFrame) {
326 | log::info!("______ioapic_handler_10_____");
327 | unsafe {
328 | crate::local_apic::LOCAL_APIC.get().unwrap().eoi();
329 | };
330 | }
331 | extern "x86-interrupt" fn ioapic_handler_11(stack_frame: InterruptStackFrame) {
332 | log::info!("______ioapic_handler_11_____");
333 |
334 | unsafe {
335 | crate::local_apic::LOCAL_APIC.get().unwrap().eoi();
336 | };
337 | }
338 | extern "x86-interrupt" fn ioapic_handler_12(stack_frame: InterruptStackFrame) {
339 | log::info!("______ioapic_handler_12_____");
340 | }
341 | extern "x86-interrupt" fn ioapic_handler_13(stack_frame: InterruptStackFrame) {
342 | log::info!("______ioapic_handler_13_____");
343 | }
344 | extern "x86-interrupt" fn ioapic_handler_14(stack_frame: InterruptStackFrame) {
345 | log::info!("______ioapic_handler_14_____");
346 | }
347 | extern "x86-interrupt" fn ioapic_handler_15(stack_frame: InterruptStackFrame) {
348 | log::info!("______ioapic_handler_15_____");
349 | }
350 | extern "x86-interrupt" fn ioapic_handler_16(stack_frame: InterruptStackFrame) {
351 | log::info!("______ioapic_handler_16_____");
352 | }
353 | extern "x86-interrupt" fn ioapic_handler_17(stack_frame: InterruptStackFrame) {
354 | log::info!("______ioapic_handler_17_____");
355 | }
356 | extern "x86-interrupt" fn ioapic_handler_18(stack_frame: InterruptStackFrame) {
357 | log::info!("______ioapic_handler_18_____");
358 | }
359 | extern "x86-interrupt" fn ioapic_handler_19(stack_frame: InterruptStackFrame) {
360 | log::info!("______ioapic_handler_19_____");
361 | }
362 | extern "x86-interrupt" fn ioapic_handler_20(stack_frame: InterruptStackFrame) {
363 | log::info!("______ioapic_handler_20_____");
364 | }
365 | extern "x86-interrupt" fn ioapic_handler_21(stack_frame: InterruptStackFrame) {
366 | log::info!("______ioapic_handler_21_____");
367 | }
368 | extern "x86-interrupt" fn ioapic_handler_22(stack_frame: InterruptStackFrame) {
369 | log::info!("______ioapic_handler_22_____");
370 | }
371 | extern "x86-interrupt" fn ioapic_handler_23(stack_frame: InterruptStackFrame) {
372 | log::info!("______ioapic_handler_23_____");
373 | }
374 | extern "x86-interrupt" fn generic_handler(stack_frame: InterruptStackFrame) {
375 | log::info!("______generic_handler_____");
376 | }
377 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/ioapic.rs:
--------------------------------------------------------------------------------
1 | use core::intrinsics::{volatile_load, volatile_store};
2 |
3 | use conquer_once::spin::OnceCell;
4 | use x86_64::{structures::DescriptorTablePointer, PhysAddr, VirtAddr};
5 |
6 | use crate::phys_to_virt;
7 | pub static IO_APIC_0: OnceCell = OnceCell::uninit();
8 |
9 | pub struct IoApic {
10 | virt_address: VirtAddr,
11 | global_system_int: u32,
12 | id: u8,
13 | }
14 |
15 | pub const IOAPICID: u32 = 0;
16 | pub const IOAPICVER: u32 = 1;
17 | impl IoApic {
18 | pub fn init(info: &acpi::platform::interrupt::IoApic) -> &Self {
19 | let this = IO_APIC_0.get_or_init(move || Self {
20 | id: info.id,
21 | virt_address: phys_to_virt(PhysAddr::new(info.address as u64)),
22 | global_system_int: info.global_system_interrupt_base,
23 | });
24 | this
25 | }
26 | pub unsafe fn set_sel(&self, reg: u32) {
27 | volatile_store(self.virt_address.as_u64() as *mut u32, reg);
28 | }
29 | pub fn read(&self, reg: u32) -> u32 {
30 | unsafe {
31 | self.set_sel(reg);
32 | let sec: VirtAddr = self.virt_address + 0x10_u64;
33 | volatile_load(sec.as_u64() as *const u32)
34 | }
35 | }
36 | pub fn write(&self, reg: u32, value: u32) {
37 | unsafe {
38 | self.set_sel(reg);
39 | let sec: VirtAddr = self.virt_address + 0x10_u64;
40 | volatile_store(sec.as_u64() as *mut u32, value);
41 | }
42 | }
43 |
44 | pub fn read_redtlb(&self, index: u32) -> u64 {
45 | let low = self.read(0x10 + 2 * index) as u64;
46 | let high = self.read(0x10 + 2 * index + 1) as u64;
47 | (high << 32) + low
48 | }
49 | pub fn write_redtlb(&self, index: u32, redtlb: u64) {
50 | let low = self.write(0x10 + 2 * index, (redtlb & 0xffff) as u32);
51 | let high = self.write(0x10 + 2 * index + 1, (redtlb >> 32) as u32);
52 | }
53 | }
54 | #[derive(Clone, Debug)]
55 | pub struct RedTbl {
56 | pub vector: u8,
57 | pub delivery_mode: u8,
58 | pub destination_mode: bool,
59 | pub delivery_status: bool,
60 | pub pin_polarity: bool,
61 | pub remote_irr: bool,
62 | pub trigger_mode: bool,
63 | pub mask: bool,
64 | pub destination: u8,
65 | }
66 |
67 | impl RedTbl {
68 | pub fn new(n: u64) -> Self {
69 | let mut c = n;
70 | let vector = (c & 0xff) as u8;
71 | c >>= 8;
72 | let delivery_mode = (c & 0b11) as u8;
73 | c >>= 2;
74 | let destination_mode = c & 0b1 != 0;
75 | c >>= 1;
76 | let delivery_status = c & 0b1 != 0;
77 | c >>= 1;
78 | let pin_polarity = c & 0b1 != 0;
79 | c >>= 1;
80 | let remote_irr = c & 0b1 != 0;
81 | c >>= 1;
82 | let trigger_mode = c & 0b1 != 0;
83 | c >>= 1;
84 | let mask = c & 0b1 != 0;
85 | c >>= 1;
86 | let destination = (n >> 56) as u8;
87 | Self {
88 | vector,
89 | delivery_mode,
90 | destination_mode,
91 | delivery_status,
92 | pin_polarity,
93 | remote_irr,
94 | trigger_mode,
95 | mask,
96 | destination,
97 | }
98 | }
99 | pub fn store(&self) -> u64 {
100 | let &Self {
101 | vector,
102 | delivery_mode,
103 | destination_mode,
104 | delivery_status,
105 | pin_polarity,
106 | remote_irr,
107 | trigger_mode,
108 | mask,
109 | destination,
110 | } = self;
111 |
112 | let mut r = 0_u64;
113 | r += (destination as u64) << 56;
114 | r += vector as u64;
115 | r += (delivery_mode as u64) << 8;
116 | r += if destination_mode { 1 } else { 0 } << 10;
117 | r += if delivery_status { 1 } else { 0 } << 11;
118 | r += if pin_polarity { 1 } else { 0 } << 12;
119 | r += if remote_irr { 1 } else { 0 } << 13;
120 | r += if trigger_mode { 1 } else { 0 } << 14;
121 | r += if mask { 1 } else { 0 } << 15;
122 | r
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/local_apic.rs:
--------------------------------------------------------------------------------
1 | use conquer_once::spin::OnceCell;
2 | use core::intrinsics::{volatile_load, volatile_store};
3 | use raw_cpuid::{CpuId, CpuIdResult};
4 | use x86_64::{
5 | registers::model_specific::Msr,
6 | structures::paging::{FrameAllocator, Size4KiB},
7 | PhysAddr, VirtAddr,
8 | };
9 |
10 | use crate::phys_to_virt;
11 |
12 | pub fn cpuid() -> Option {
13 | //TODO: ensure that CPUID exists! https://wiki.osdev.org/CPUID#Checking_CPUID_availability
14 | Some(CpuId::with_cpuid_fn(|a, c| {
15 | let result = unsafe { core::arch::x86_64::__cpuid_count(a, c) };
16 | CpuIdResult {
17 | eax: result.eax,
18 | ebx: result.ebx,
19 | ecx: result.ecx,
20 | edx: result.edx,
21 | }
22 | }))
23 | }
24 |
25 | pub static LOCAL_APIC: OnceCell = OnceCell::uninit();
26 |
27 | pub struct LocalApic {
28 | pub virt_address: VirtAddr,
29 | }
30 |
31 | impl LocalApic {
32 | pub unsafe fn init(local_apic_address: PhysAddr) -> &'static Self {
33 | disable_pic();
34 |
35 | let virtaddr: VirtAddr = phys_to_virt(local_apic_address);
36 | let this = LOCAL_APIC.get_or_init(|| Self {
37 | virt_address: virtaddr,
38 | });
39 | log::info!("LocalApic {:?}", virtaddr);
40 |
41 | let mut msr = Msr::new(0x1B);
42 | let r = msr.read();
43 | msr.write(r | (1 << 11));
44 |
45 | this.write(0xF0, this.read(0xF0) | 0x1FF);
46 | this
47 | }
48 |
49 | unsafe fn read(&self, reg: u32) -> u32 {
50 | volatile_load((self.virt_address.as_u64() + reg as u64) as *const u32)
51 | }
52 |
53 | unsafe fn write(&self, reg: u32, value: u32) {
54 | volatile_store((self.virt_address.as_u64() + reg as u64) as *mut u32, value);
55 | }
56 |
57 | pub fn id(&self) -> u32 {
58 | unsafe { self.read(0x20) }
59 | }
60 |
61 | pub fn version(&self) -> u32 {
62 | unsafe { self.read(0x30) }
63 | }
64 |
65 | pub fn icr(&self) -> u64 {
66 | unsafe { (self.read(0x310) as u64) << 32 | self.read(0x300) as u64 }
67 | }
68 |
69 | pub fn set_icr(&self, value: u64) {
70 | unsafe {
71 | const PENDING: u32 = 1 << 12;
72 | while self.read(0x300) & PENDING == PENDING {
73 | core::hint::spin_loop();
74 | }
75 | self.write(0x310, (value >> 32) as u32);
76 | self.write(0x300, value as u32);
77 | while self.read(0x300) & PENDING == PENDING {
78 | core::hint::spin_loop();
79 | }
80 | }
81 | }
82 |
83 | pub fn ipi(&self, apic_id: usize) {
84 | let mut icr = 0x4040;
85 |
86 | icr |= (apic_id as u64) << 56;
87 |
88 | self.set_icr(icr);
89 | }
90 | // Not used just yet, but allows triggering an NMI to another processor.
91 | pub fn ipi_nmi(&self, apic_id: u32) {
92 | let shift = { 56 };
93 | self.set_icr((u64::from(apic_id) << shift) | (1 << 14) | (0b100 << 8));
94 | }
95 |
96 | pub unsafe fn eoi(&self) {
97 | self.write(0xB0, 0);
98 | }
99 | /// Reads the Error Status Register.
100 | pub unsafe fn esr(&self) -> u32 {
101 | self.write(0x280, 0);
102 | self.read(0x280)
103 | }
104 | pub unsafe fn lvt_timer(&self) -> u32 {
105 | self.read(0x320)
106 | }
107 | pub unsafe fn set_lvt_timer(&self, value: u32) {
108 | self.write(0x320, value);
109 | }
110 | pub unsafe fn init_count(&self) -> u32 {
111 | self.read(0x380)
112 | }
113 | pub unsafe fn set_init_count(&self, initial_count: u32) {
114 | self.write(0x380, initial_count);
115 | }
116 | pub unsafe fn cur_count(&self) -> u32 {
117 | self.read(0x390)
118 | }
119 | pub unsafe fn div_conf(&self) -> u32 {
120 | self.read(0x3E0)
121 | }
122 | pub unsafe fn set_div_conf(&self, div_conf: u32) {
123 | self.write(0x3E0, div_conf);
124 | }
125 | pub unsafe fn lvt_error(&self) -> u32 {
126 | self.read(0x370)
127 | }
128 | pub unsafe fn set_lvt_error(&self, lvt_error: u32) {
129 | self.write(0x370, lvt_error);
130 | }
131 | unsafe fn setup_error_int(&self) {
132 | let vector = 49u32;
133 | self.set_lvt_error(vector);
134 | }
135 | }
136 | pub unsafe fn disable_pic() {
137 | use x86_64::instructions::port::Port;
138 | let mut wait_port: Port = Port::new(0x80);
139 | let mut wait = || {
140 | wait_port.write(0);
141 | };
142 | let mut p0c: Port = Port::new(0x20);
143 | let mut p0d: Port = Port::new(0x21);
144 | let mut p1c: Port = Port::new(0xA0);
145 | let mut p1d: Port = Port::new(0xA1);
146 | p0c.write(0x11);
147 | wait();
148 | p1c.write(0x11);
149 | wait();
150 |
151 | //OFFSET
152 | p0d.write(0xf0);
153 | wait();
154 | p1d.write(0xf8);
155 | wait();
156 | //CHAINING
157 | p0d.write(0x4);
158 | wait();
159 | p1d.write(0x2);
160 | wait();
161 | //ICW4_8086 MODE
162 | p0d.write(0x1);
163 | wait();
164 | p1d.write(0x1);
165 | wait();
166 | //CLOSE
167 | p0d.write(0xff);
168 | wait();
169 | p1d.write(0xff);
170 | wait();
171 | }
172 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/logger.rs:
--------------------------------------------------------------------------------
1 | use crate::{framebuffer::FrameBufferWriter, serial::SerialPort};
2 | use bootloader_api::info::FrameBufferInfo;
3 | use bootloader_boot_config::LevelFilter;
4 | use conquer_once::spin::OnceCell;
5 | use core::fmt::Write;
6 | use log::Level;
7 | use spinning_top::Spinlock;
8 |
9 | /// The global logger instance used for the `log` crate.
10 | pub static LOGGER: OnceCell = OnceCell::uninit();
11 |
12 | /// A logger instance protected by a spinlock.
13 | pub struct LockedLogger {
14 | framebuffer: Option>,
15 | serial: Option>,
16 | }
17 |
18 | impl LockedLogger {
19 | /// Create a new instance that logs to the given framebuffer.
20 | pub fn new(
21 | framebuffer: &'static mut [u8],
22 | info: FrameBufferInfo,
23 | frame_buffer_logger_status: bool,
24 | serial_logger_status: bool,
25 | ) -> Self {
26 | let framebuffer = match frame_buffer_logger_status {
27 | true => Some(Spinlock::new(FrameBufferWriter::new(framebuffer, info))),
28 | false => None,
29 | };
30 |
31 | let serial = match serial_logger_status {
32 | true => Some(Spinlock::new(unsafe { SerialPort::init() })),
33 | false => None,
34 | };
35 |
36 | LockedLogger {
37 | framebuffer,
38 | serial,
39 | }
40 | }
41 |
42 | /// Force-unlocks the logger to prevent a deadlock.
43 | ///
44 | /// ## Safety
45 | /// This method is not memory safe and should be only used when absolutely necessary.
46 | pub unsafe fn force_unlock(&self) {
47 | if let Some(framebuffer) = &self.framebuffer {
48 | unsafe { framebuffer.force_unlock() };
49 | }
50 | if let Some(serial) = &self.serial {
51 | unsafe { serial.force_unlock() };
52 | }
53 | }
54 | }
55 |
56 | impl log::Log for LockedLogger {
57 | fn enabled(&self, _metadata: &log::Metadata) -> bool {
58 | true
59 | }
60 |
61 | fn log(&self, record: &log::Record) {
62 | x86_64::instructions::interrupts::without_interrupts(|| {
63 | if let Some(framebuffer) = &self.framebuffer {
64 | let mut framebuffer = framebuffer.lock();
65 |
66 | if record.level() == Level::Error {
67 | framebuffer.level = 1;
68 | }
69 |
70 | writeln!(framebuffer, "{:5}: {}", record.level(), record.args()).unwrap();
71 | framebuffer.level = 0;
72 | }
73 | if let Some(serial) = &self.serial {
74 | let mut serial = serial.lock();
75 | writeln!(serial, "{:5}: {}", record.level(), record.args()).unwrap();
76 | }
77 | });
78 | }
79 |
80 | fn flush(&self) {}
81 | }
82 |
83 | pub fn init_logger(
84 | framebuffer: &'static mut [u8],
85 | info: FrameBufferInfo,
86 | log_level: LevelFilter,
87 | frame_buffer_logger_status: bool,
88 | serial_logger_status: bool,
89 | ) {
90 | let logger = LOGGER.get_or_init(move || {
91 | LockedLogger::new(
92 | framebuffer,
93 | info,
94 | frame_buffer_logger_status,
95 | serial_logger_status,
96 | )
97 | });
98 | log::set_logger(logger).expect("logger already set");
99 | log::set_max_level(convert_level(log_level));
100 | log::info!("Framebuffer info: {:?}", info);
101 | }
102 | fn convert_level(level: LevelFilter) -> log::LevelFilter {
103 | match level {
104 | LevelFilter::Off => log::LevelFilter::Off,
105 | LevelFilter::Error => log::LevelFilter::Error,
106 | LevelFilter::Warn => log::LevelFilter::Warn,
107 | LevelFilter::Info => log::LevelFilter::Info,
108 | LevelFilter::Debug => log::LevelFilter::Debug,
109 | LevelFilter::Trace => log::LevelFilter::Trace,
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/main.rs:
--------------------------------------------------------------------------------
1 | #![no_std]
2 | #![no_main]
3 | #![feature(abi_x86_interrupt)]
4 | #![feature(alloc_error_handler)]
5 | #![feature(core_intrinsics)]
6 |
7 | use acpi::{AcpiHandler, HpetInfo, InterruptModel, PhysicalMapping};
8 | use alloc::{boxed::Box, fmt, format, slice, string::String, sync::Arc, vec::Vec};
9 | extern crate alloc;
10 | extern crate edid_rs;
11 | use arrayvec::ArrayVec;
12 | use bitfield::bitfield;
13 | use bootloader_api::{entry_point, info::FrameBufferInfo, BootInfo};
14 | use bootloader_boot_config::LevelFilter;
15 | use core::{
16 | alloc::{GlobalAlloc, Layout},
17 | intrinsics::volatile_set_memory,
18 | panic::PanicInfo,
19 | ptr::{read_volatile, write_volatile, NonNull},
20 | sync::atomic::{AtomicU64, Ordering},
21 | };
22 | use crossbeam::queue::ArrayQueue;
23 |
24 | mod framebuffer;
25 | use framebuffer::FB;
26 |
27 | use conquer_once::spin::OnceCell;
28 | use hashbrown::HashMap;
29 | use x86_64::{
30 | instructions::hlt,
31 | structures::paging::{
32 | mapper::MapToError, FrameAllocator, Mapper, OffsetPageTable, Page, PageTableFlags,
33 | PhysFrame, Size1GiB, Size2MiB, Size4KiB,
34 | },
35 | PhysAddr, VirtAddr,
36 | };
37 | use xmas_elf::{header::Type, program, sections::SectionData, ElfFile};
38 | mod allocator;
39 | mod app;
40 | mod drivers;
41 | mod gdt;
42 | mod globals;
43 | mod interrupts;
44 | mod ioapic;
45 | mod local_apic;
46 | mod logger;
47 | mod memory;
48 | mod pci;
49 | mod serial;
50 | mod task;
51 | mod virtio;
52 | /// This function is called on panic.
53 | #[panic_handler]
54 | fn panic(info: &PanicInfo) -> ! {
55 | log::error!("{:?}", info);
56 | loop {}
57 | }
58 | use bootloader_api::config::{BootloaderConfig, Mapping};
59 |
60 | use crate::{
61 | allocator::{AllocFromCtx, ALLOCATOR},
62 | framebuffer::FBShare,
63 | interrupts::{a_sleep, global_time_ms, wait_block, Timer, TIME_MS},
64 | logger::init_logger,
65 | memory::BootInfoFrameAllocator,
66 | pci::Bar,
67 | task::{
68 | executor::{qpush, yield_once},
69 | Task,
70 | },
71 | virtio::{DeviceType, Virtio},
72 | };
73 |
74 | extern "C" fn log_fn(s: *const u8, l: u32) {
75 | unsafe {
76 | let slice = core::slice::from_raw_parts(s, l as usize);
77 | let str_slice = core::str::from_utf8_unchecked(slice);
78 | log::info!("{}", str_slice)
79 | }
80 | }
81 |
82 | extern "C" fn calloc(size: usize, align: usize) -> *mut u8 {
83 | // log::info!("alloc {} {}", size, align);
84 | unsafe { ALLOCATOR.alloc(core::alloc::Layout::from_size_align(size, align).unwrap()) }
85 | }
86 | extern "C" fn cdalloc(ptr: *mut u8, size: usize, align: usize) {
87 | // log::info!("dealloc {:?} {} {}", ptr, size, align);
88 | unsafe {
89 | ALLOCATOR.dealloc(
90 | ptr,
91 | core::alloc::Layout::from_size_align(size, align).unwrap(),
92 | );
93 | };
94 | }
95 |
96 | use acpi::AcpiTables;
97 | #[derive(Clone)]
98 | struct AcpiHandlerImpl;
99 | impl AcpiHandler for AcpiHandlerImpl {
100 | unsafe fn map_physical_region(
101 | &self,
102 | physical_address: usize,
103 | size: usize,
104 | ) -> PhysicalMapping {
105 | let s = (size / 4096 + 1) * 4096;
106 | PhysicalMapping::new(
107 | physical_address,
108 | NonNull::new(phys_to_virt(PhysAddr::new(physical_address as u64)).as_mut_ptr())
109 | .unwrap(),
110 | s,
111 | s,
112 | self.clone(),
113 | )
114 | }
115 | fn unmap_physical_region(region: &PhysicalMapping) {}
116 | }
117 | const ACPI_HANDLER: AcpiHandlerImpl = AcpiHandlerImpl;
118 |
119 | use spin::Mutex;
120 | pub static MAPPER: OnceCell> = OnceCell::uninit();
121 | pub static FRAME_ALLOCATOR: OnceCell> = OnceCell::uninit();
122 |
123 | pub static mut VIRTUAL_MAPPING_OFFSET: VirtAddr = VirtAddr::new_truncate(0);
124 | pub fn phys_to_virt(addr: PhysAddr) -> VirtAddr {
125 | unsafe { VIRTUAL_MAPPING_OFFSET + addr.as_u64() }
126 | }
127 | static OTHER_VIRT: AtomicU64 = AtomicU64::new(0x_5000_0000_0000);
128 | pub fn create_virt_from_phys(
129 | mapper: &mut impl Mapper,
130 | frame_allocator: &mut impl FrameAllocator,
131 | frame: PhysFrame,
132 | ) -> Result> {
133 | let start = VirtAddr::new(OTHER_VIRT.fetch_add(4096, Ordering::Relaxed) as u64);
134 | let page = Page::containing_address(start);
135 | let flags =
136 | PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
137 | unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
138 | return Ok(page);
139 | }
140 |
141 | pub fn create_identity_virt_from_phys(
142 | mapper: &mut impl Mapper,
143 | frame_allocator: &mut impl FrameAllocator,
144 | ) -> Result> {
145 | let frame = frame_allocator.allocate_frame().unwrap();
146 | let start = VirtAddr::new(frame.start_address().as_u64());
147 | let page = Page::containing_address(start);
148 | let flags =
149 | PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
150 | unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
151 | return Ok(page);
152 | }
153 |
154 | pub fn with_mapper_framealloc(f: FUNC) -> R
155 | where
156 | FUNC: FnOnce(&mut OffsetPageTable, &mut BootInfoFrameAllocator) -> R,
157 | {
158 | let mut mapper = MAPPER.get().unwrap().lock();
159 | let mut frame_allocator = FRAME_ALLOCATOR.get().unwrap().lock();
160 | let mapper = &mut *mapper;
161 | let frame_allocator = &mut *frame_allocator;
162 | f(mapper, frame_allocator)
163 | }
164 |
165 | pub fn create_identity_virt_from_phys_n(pages: usize) -> Result> {
166 | with_mapper_framealloc(|mapper, frame_allocator| {
167 | let first_frame = frame_allocator.allocate_frame().unwrap();
168 | log::info!("first_frame {}", first_frame.start_address().as_u64());
169 | for i in 1..pages {
170 | let frame = frame_allocator.allocate_frame().unwrap();
171 | let frame_start = frame.start_address().as_u64();
172 |
173 | // log::info!("{} : {}", i, frame_start);
174 | if first_frame.start_address().as_u64() + (i as u64) * 4096 != frame_start {
175 | panic!("create_identity_virt_from_phys_n NON CONTIGUOUS, {}", i)
176 | }
177 | }
178 |
179 | for i in 0..pages {
180 | let addr = first_frame.start_address().as_u64() + (i as u64) * 4096;
181 | let frame = PhysFrame::containing_address(PhysAddr::new(addr));
182 | let page = Page::containing_address(VirtAddr::new(addr));
183 | let flags = PageTableFlags::PRESENT
184 | | PageTableFlags::WRITABLE
185 | | PageTableFlags::USER_ACCESSIBLE;
186 | unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
187 | }
188 |
189 | return Ok(Page::containing_address(VirtAddr::new(
190 | first_frame.start_address().as_u64(),
191 | )));
192 | })
193 | }
194 |
195 | pub static BOOTLOADER_CONFIG: BootloaderConfig = {
196 | let mut config = BootloaderConfig::new_default();
197 | config.mappings.physical_memory = Some(Mapping::Dynamic);
198 | config.kernel_stack_size = 128 * 1024;
199 | config
200 | };
201 |
202 | entry_point!(kernel_main, config = &BOOTLOADER_CONFIG);
203 |
204 | fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
205 | gdt::init();
206 | interrupts::init_idt();
207 |
208 | let framebuffer = boot_info.framebuffer.as_mut().unwrap();
209 | let fbinfo = framebuffer.info();
210 |
211 | let fbm = framebuffer.buffer_mut();
212 | let fbm2 = unsafe {
213 | let p = fbm.as_mut_ptr();
214 | slice::from_raw_parts_mut(p, fbinfo.byte_len)
215 | };
216 | init_logger(fbm, fbinfo.clone(), LevelFilter::Trace, true, true);
217 |
218 | // x86_64::instructions::interrupts::int3();
219 | let virtual_full_mapping_offset = VirtAddr::new(
220 | boot_info
221 | .physical_memory_offset
222 | .into_option()
223 | .expect("no physical_memory_offset"),
224 | );
225 | log::info!("physical_memory_offset {:x}", virtual_full_mapping_offset);
226 | unsafe {
227 | VIRTUAL_MAPPING_OFFSET = virtual_full_mapping_offset;
228 | }
229 | let mapper = unsafe { memory::init(virtual_full_mapping_offset) };
230 | let frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_regions) };
231 | MAPPER.init_once(|| Mutex::new(mapper));
232 | FRAME_ALLOCATOR.init_once(|| Mutex::new(frame_allocator));
233 | {
234 | log::info!("Complete Bootloader Map physical memory");
235 | type VirtualMappingPageSize = Size2MiB; // Size2MiB;Size1GiB Size4KiB
236 |
237 | let start_frame: PhysFrame =
238 | PhysFrame::containing_address(PhysAddr::new(0));
239 | let max_phys = PhysAddr::new(virtual_full_mapping_offset.as_u64() - 1u64);
240 | let max_phys = PhysAddr::new(Size1GiB::SIZE * 64 - 1);
241 |
242 | let end_frame: PhysFrame = PhysFrame::containing_address(max_phys);
243 |
244 | use x86_64::structures::paging::PageSize;
245 | let mut news = 0;
246 | let mut olds = 0;
247 | for frame in PhysFrame::range_inclusive(start_frame, end_frame) {
248 | let page: Page = Page::containing_address(
249 | virtual_full_mapping_offset + frame.start_address().as_u64(),
250 | );
251 | let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
252 | match unsafe {
253 | MAPPER.get_unchecked().lock().map_to(
254 | page,
255 | frame,
256 | flags,
257 | &mut *FRAME_ALLOCATOR.get_unchecked().lock(),
258 | )
259 | } {
260 | Ok(tlb) => {
261 | tlb.flush();
262 | news += 1;
263 | }
264 | Err(_) => {
265 | olds += 1;
266 | }
267 | };
268 | }
269 | log::info!("new:{} already_mapped:{}", news, olds);
270 | }
271 |
272 | with_mapper_framealloc(|mapper, frame_allocator| {
273 | allocator::init_heap(mapper, frame_allocator).expect("heap initialization failed");
274 | });
275 |
276 | let rsdp_addr = boot_info.rsdp_addr.into_option().expect("no rsdp");
277 | let acpi_tables = unsafe { AcpiTables::from_rsdp(ACPI_HANDLER, rsdp_addr as usize).unwrap() };
278 | log::info!("acpi_read");
279 |
280 | let x = HpetInfo::new(&acpi_tables).expect("hpet");
281 | // log::info!("{:#?}]", x);
282 |
283 | let pi = acpi_tables.platform_info().expect("platform info");
284 |
285 | if let InterruptModel::Apic(apic) = pi.interrupt_model {
286 | // log::info!("{:#?}", apic);
287 |
288 | unsafe {
289 | log::info!("init apic");
290 | let lapic = local_apic::LocalApic::init(PhysAddr::new(apic.local_apic_address));
291 | log::info!("start apic c");
292 | let mut freq = 1000_000_000;
293 | if let Some(cpuid) = local_apic::cpuid() {
294 | log::info!("cpuid");
295 | if let Some(tsc) = cpuid.get_tsc_info() {
296 | log::info!(
297 | "{} {}",
298 | tsc.nominal_frequency(),
299 | tsc.tsc_frequency().unwrap()
300 | );
301 | freq = tsc.nominal_frequency();
302 | } else {
303 | }
304 | }
305 | lapic.set_div_conf(0b1011);
306 | log::info!("start apic c");
307 | lapic.set_lvt_timer((1 << 17) + 48);
308 | let wanted_freq_hz = 1000;
309 | lapic.set_init_count(freq / wanted_freq_hz);
310 | }
311 |
312 | for io_apic in apic.io_apics.iter() {
313 | log::info!("{:x}", io_apic.address);
314 | let mut ioa = ioapic::IoApic::init(io_apic);
315 | let val = ioa.read(ioapic::IOAPICVER);
316 | log::info!("{:x}", val);
317 | for i in 0..24 {
318 | let n = ioa.read_redtlb(i);
319 | let mut red = ioapic::RedTbl::new(n);
320 | red.vector = (50 + i) as u8;
321 |
322 | let stored = red.store();
323 |
324 | ioa.write_redtlb(i, stored);
325 | }
326 | }
327 |
328 | x86_64::instructions::interrupts::enable();
329 |
330 | // x86_64::instructions::interrupts::disable();
331 | }
332 |
333 | {
334 | // aml::AmlContext::new()
335 | }
336 | // .expect("no acpi table");
337 |
338 | let proc_info = pi.processor_info.expect("processor_info");
339 | // log::info!("{:?}", pi.power_profile);
340 | // log::info!("{:#?}", pi.interrupt_model);
341 | // log::info!("{:?}", proc_info.boot_processor);
342 | for proc in proc_info.application_processors.iter() {
343 | log::info!("{:?}", proc);
344 | }
345 |
346 | // for ent in mapper.level_4_table().iter().take(30) {
347 | // log::info!("{:?}", ent);
348 | // }
349 |
350 | let pcis = pci::Pcis::new();
351 |
352 | let mut virtio_devices = Vec::new();
353 |
354 | {
355 | for (pci_index, pci) in pcis.devs.iter().enumerate() {
356 | let vector_base = 50 + 2 * pci_index;
357 | let status = pci.config_read_u16(pci::PCIConfigRegisters::PCIStatus as u8);
358 | let vendor = pci.config_read_u16(pci::PCIConfigRegisters::PCIVendorID as u8);
359 | let device_id =
360 | pci.config_read_u16(pci::PCIConfigRegisters::PCIDeviceID as u8) as isize - 0x1040;
361 | log::info!(
362 | "{:?} status {} irq:{} ipin:{}, {:x} {} ________________",
363 | pci,
364 | status,
365 | pci.get_irq(),
366 | pci.get_ipin(),
367 | vendor,
368 | device_id,
369 | );
370 | const VIRTIO_VENDOR_ID: u16 = 0x1af4;
371 | if vendor == VIRTIO_VENDOR_ID {
372 | let virtio = with_mapper_framealloc(|mapper, frame_allocator| {
373 | Virtio::init(pci, mapper, frame_allocator)
374 | });
375 | if let Some(virtio) = virtio {
376 | virtio_devices.push(virtio);
377 | }
378 | }
379 | }
380 | }
381 |
382 | let mut fb = Box::new(FB::new(&fbinfo));
383 | // fb.flush(fbm2, &fbinfo);
384 | let fb_clone: *mut FB = &mut *fb;
385 | log::info!("fbclone {:?}", fb_clone);
386 |
387 | {
388 | let mut executor = task::executor::Executor::new();
389 | let spawner = executor.spawner();
390 |
391 | for virtio in virtio_devices.into_iter() {
392 | match virtio.device_type {
393 | DeviceType::Input => spawner.run(drivers::virtio_input::drive(virtio)),
394 | DeviceType::Gpu => spawner.run(drivers::virtio_gpu::drive(
395 | virtio,
396 | spawner.clone(),
397 | fb_clone,
398 | )),
399 | }
400 | }
401 |
402 | spawner.run(async move {
403 | use app::*;
404 | let mut apps: Vec = Vec::new();
405 | let apps_raw = [
406 | &include_bytes!("../../../app_background/target/x86_64/release/func")[..],
407 | &include_bytes!("../../../app_console/target/x86_64/release/func")[..],
408 | &include_bytes!("../../../app_cursor/target/x86_64/release/func")[..],
409 | // &include_bytes!("../../../app_test/target/x86_64/release/func")[..],
410 | // &include_bytes!("../../../app_c/target/main")[..],
411 | ];
412 | for app_bytes in apps_raw.iter() {
413 | apps.push(App::new(app_bytes, false));
414 | }
415 |
416 | loop {
417 | let input = globals::INPUT.read();
418 | for app in apps.iter_mut() {
419 | let mut arg = Context::new(log_fn, fb.share(), calloc, cdalloc, &input);
420 | app.call(&mut arg);
421 | }
422 |
423 | globals::INPUT.update(|e| e.step());
424 | yield_once().await;
425 | }
426 | });
427 | executor.run();
428 | }
429 | }
430 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/memory.rs:
--------------------------------------------------------------------------------
1 | use arrayvec::ArrayVec;
2 | use x86_64::PhysAddr;
3 | use x86_64::{structures::paging::PageTable, VirtAddr};
4 |
5 | use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PhysFrame, Size4KiB};
6 | /// Initialize a new OffsetPageTable.
7 | ///
8 | /// This function is unsafe because the caller must guarantee that the
9 | /// complete physical memory is mapped to virtual memory at the passed
10 | /// `physical_memory_offset`. Also, this function must be only called once
11 | /// to avoid aliasing `&mut` references (which is undefined behavior).
12 | pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
13 | let level_4_table = active_level_4_table(physical_memory_offset);
14 | OffsetPageTable::new(level_4_table, physical_memory_offset)
15 | }
16 |
17 | /// Returns a mutable reference to the active level 4 table.
18 | ///
19 | /// This function is unsafe because the caller must guarantee that the
20 | /// complete physical memory is mapped to virtual memory at the passed
21 | /// `physical_memory_offset`. Also, this function must be only called once
22 | /// to avoid aliasing `&mut` references (which is undefined behavior).
23 | unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
24 | use x86_64::registers::control::Cr3;
25 |
26 | let (level_4_table_frame, _) = Cr3::read();
27 |
28 | let phys = level_4_table_frame.start_address();
29 |
30 | log::info!("level_4_table_frame.start_address {:?}", phys);
31 | let virt = physical_memory_offset + phys.as_u64();
32 | let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
33 |
34 | &mut *page_table_ptr // unsafe
35 | }
36 |
37 | pub unsafe fn kern_phy_to_virt(physical_memory_offset: VirtAddr, target_phy: PhysAddr) -> VirtAddr {
38 | let virt = VirtAddr::new(physical_memory_offset.as_u64() + target_phy.as_u64());
39 | virt
40 | }
41 |
42 | const BUFFER_SIZE_ADVANCE: usize = 32;
43 | use bootloader_api::info::{MemoryRegionKind, MemoryRegions};
44 | /// A FrameAllocator that returns usable frames from the bootloader's memory map.
45 | pub struct BootInfoFrameAllocator {
46 | memory_map: &'static MemoryRegions,
47 | next: usize,
48 | buf: ArrayVec,
49 | }
50 | unsafe impl Send for BootInfoFrameAllocator {}
51 |
52 | impl BootInfoFrameAllocator {
53 | /// Create a FrameAllocator from the passed memory map.
54 | ///
55 | /// This function is unsafe because the caller must guarantee that the passed
56 | /// memory map is valid. The main requirement is that all frames that are marked
57 | /// as `USABLE` in it are really unused.
58 | pub unsafe fn init(memory_map: &'static MemoryRegions) -> Self {
59 | BootInfoFrameAllocator {
60 | memory_map,
61 | next: 1,
62 | buf: ArrayVec::new(),
63 | }
64 | }
65 |
66 | /// Returns an iterator over the usable frames specified in the memory map.
67 | fn usable_frames(&self) -> impl Iterator- {
68 | // get usable regions from memory map
69 | let regions = self.memory_map.iter();
70 | let usable_regions = regions.filter(|r| r.kind == MemoryRegionKind::Usable);
71 | // map each region to its address range
72 | let addr_ranges = usable_regions.map(|r| r.start..r.end);
73 | // transform to an iterator of frame start addresses
74 | let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
75 | // create `PhysFrame` types from the start addresses
76 | frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)))
77 | }
78 | }
79 |
80 | unsafe impl FrameAllocator for BootInfoFrameAllocator {
81 | fn allocate_frame(&mut self) -> Option {
82 | if self.buf.len() == 0 {
83 | for frame in self
84 | .usable_frames()
85 | .skip(self.next - 1)
86 | .take(BUFFER_SIZE_ADVANCE)
87 | {
88 | self.buf.push(frame);
89 | }
90 |
91 | self.buf.reverse();
92 | self.next += BUFFER_SIZE_ADVANCE;
93 | }
94 |
95 | self.buf.pop()
96 | // let frame = self.usable_frames().nth(self.next);
97 | // self.next += 1;
98 | // frame
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/pci.rs:
--------------------------------------------------------------------------------
1 | use core::fmt::Debug;
2 |
3 | use alloc::vec::Vec;
4 | use x86_64::{
5 | instructions::port::{Port, PortGeneric, ReadWriteAccess},
6 | PhysAddr,
7 | };
8 | pub enum PCIConfigRegisters {
9 | PCIDeviceID = 0x2,
10 | PCIVendorID = 0x0,
11 | PCIStatus = 0x6,
12 | PCICommand = 0x4,
13 | PCIClassCode = 0xB,
14 | PCISubclass = 0xA,
15 | PCIProgIF = 0x9,
16 | PCIRevisionID = 0x8,
17 | PCIBIST = 0xF,
18 | PCIHeaderType = 0xE,
19 | PCILatencyTimer = 0xD,
20 | PCICacheLineSize = 0xC,
21 | PCIBAR0 = 0x10,
22 | PCIBAR1 = 0x14,
23 | PCIBAR2 = 0x18,
24 | PCIBAR3 = 0x1C,
25 | PCIBAR4 = 0x20,
26 | PCIBAR5 = 0x24,
27 | PCICardbusCISPointer = 0x28,
28 | PCISubsystemID = 0x2E,
29 | PCISubsystemVendorID = 0x2C,
30 | PCIExpansionROMBaseAddress = 0x30,
31 | PCICapabilitiesPointer = 0x34,
32 | PCIMaxLatency = 0x3F,
33 | PCIMinGrant = 0x3E,
34 | PCIInterruptPIN = 0x3D,
35 | PCIInterruptLine = 0x3C,
36 | }
37 |
38 | const port_config_address: PortGeneric = Port::new(0xCF8);
39 | const port_config_data: PortGeneric = Port::new(0xCFC);
40 | const port_config_data_u8: PortGeneric = Port::new(0xCFC);
41 | pub fn config_address(bus: u8, slot: u8, func: u8, off: u8) {
42 | let address: u32 = (((bus as u32) << 16)
43 | | ((slot as u32) << 11)
44 | | ((func as u32) << 8)
45 | | ((off as u32) & 0xfc)
46 | | 0x80000000);
47 |
48 | unsafe {
49 | port_config_address.write(address);
50 | }
51 | }
52 | pub fn config_read_u32(bus: u8, slot: u8, func: u8, off: u8) -> u32 {
53 | config_address(bus, slot, func, off);
54 | let read: u32 = unsafe { port_config_data.read() };
55 | read
56 | }
57 |
58 | pub fn config_read_u16(bus: u8, slot: u8, func: u8, off: u8) -> u16 {
59 | config_address(bus, slot, func, off);
60 |
61 | let read: u32 = unsafe { port_config_data.read() };
62 | let read = (read >> ((off & 2) * 8)) & 0xffff;
63 | read as u16
64 | }
65 |
66 | pub fn config_read_u8(bus: u8, slot: u8, func: u8, off: u8) -> u8 {
67 | config_address(bus, slot, func, off);
68 |
69 | // unsafe { port_config_data_u8.read() }
70 | let read: u32 = unsafe { port_config_data.read() };
71 | let read = (read >> ((off & 3) * 8)) & 0xff;
72 | read as u8
73 | }
74 |
75 | pub fn config_write_u32(bus: u8, slot: u8, func: u8, off: u8, data: u32) {
76 | config_address(bus, slot, func, off);
77 | unsafe {
78 | port_config_data.write(data);
79 | };
80 | }
81 |
82 | pub fn config_write_u16(bus: u8, slot: u8, func: u8, off: u8, data: u16) {
83 | config_address(bus, slot, func, off);
84 |
85 | let read: u32 = unsafe { port_config_data.read() };
86 | let val = (read & (!(0xFFFF << ((off & 2) * 8)))) | ((data as u32) << ((off & 2) * 8));
87 | unsafe {
88 | port_config_data.write(val);
89 | };
90 | }
91 |
92 | pub fn config_write_u8(bus: u8, slot: u8, func: u8, off: u8, data: u8) {
93 | config_address(bus, slot, func, off);
94 |
95 | let read: u32 = unsafe { port_config_data.read() };
96 | let val = (read & (!(0xFF << ((off & 3) * 8)))) | ((data as u32) << ((off & 3) * 8));
97 | unsafe {
98 | port_config_data.write(val);
99 | };
100 | }
101 | #[derive(Clone)]
102 | pub struct Pci {
103 | pub bus: u8,
104 | pub slot: u8,
105 | pub func: u8,
106 | }
107 |
108 | impl Debug for Pci {
109 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
110 | write!(
111 | f,
112 | "pci:{:02x}:{:02x}:{:02x}",
113 | self.bus, self.slot, self.func
114 | )
115 | }
116 | }
117 |
118 | #[derive(Clone, Debug, Copy, PartialEq)]
119 | pub enum Bar {
120 | None,
121 | Io(u32),
122 | Mm(PhysAddr),
123 | }
124 |
125 | impl Pci {
126 | pub fn config_read_u8(&self, off: u8) -> u8 {
127 | config_read_u8(self.bus, self.slot, self.func, off as u8)
128 | }
129 | pub fn config_write_u8(&self, off: u8, val: u8) {
130 | config_write_u8(self.bus, self.slot, self.func, off as u8, val)
131 | }
132 | pub fn config_read_u16(&self, off: u8) -> u16 {
133 | config_read_u16(self.bus, self.slot, self.func, off as u8)
134 | }
135 | pub fn config_write_u16(&self, off: u8, val: u16) {
136 | config_write_u16(self.bus, self.slot, self.func, off as u8, val)
137 | }
138 | pub fn config_read_u32(&self, off: u8) -> u32 {
139 | config_read_u32(self.bus, self.slot, self.func, off as u8)
140 | }
141 |
142 | pub fn get_bar(&self, idx: u8) -> Bar {
143 | fn idx_to_enum(idx: u8) -> PCIConfigRegisters {
144 | match idx {
145 | 0 => PCIConfigRegisters::PCIBAR0,
146 | 1 => PCIConfigRegisters::PCIBAR1,
147 | 2 => PCIConfigRegisters::PCIBAR2,
148 | 3 => PCIConfigRegisters::PCIBAR3,
149 | 4 => PCIConfigRegisters::PCIBAR4,
150 | _ => PCIConfigRegisters::PCIBAR5,
151 | }
152 | }
153 | let mut bar = self.config_read_u32(idx_to_enum(idx) as u8) as u64;
154 | if bar == 0 {
155 | return Bar::None;
156 | }
157 | let io = bar & 0x1 != 0;
158 |
159 | if io {
160 | return Bar::Io((bar & 0xFFFFFFFFFFFFFFFC) as u32);
161 | }
162 |
163 | let bit64 = bar & 0x4 != 0;
164 | let not_last = idx < 5;
165 | if bit64 && not_last {
166 | bar |= (config_read_u32(
167 | self.bus,
168 | self.slot,
169 | self.func,
170 | PCIConfigRegisters::PCIBAR0 as u8 + ((idx as u8 + 1) * 4),
171 | ) as u64)
172 | << 32;
173 | }
174 | let masked = bar & 0xFFFFFFFFFFFFFFF0;
175 | if masked == 0 {
176 | return Bar::None;
177 | }
178 | Bar::Mm(PhysAddr::new(masked))
179 | }
180 | pub fn get_irq(&self) -> u8 {
181 | self.config_read_u8(PCIConfigRegisters::PCIInterruptLine as u8)
182 | }
183 | pub fn get_ipin(&self) -> u8 {
184 | self.config_read_u8(PCIConfigRegisters::PCIInterruptPIN as u8)
185 | }
186 | }
187 |
188 | pub struct Pcis {
189 | pub devs: Vec,
190 | }
191 |
192 | impl Pcis {
193 | pub fn new() -> Self {
194 | let mut devs = Vec::new();
195 | for bus in 0..=255 {
196 | for slot in 0..32 {
197 | for func in 0..8 {
198 | let vendor =
199 | config_read_u16(bus, slot, func, PCIConfigRegisters::PCIVendorID as u8);
200 | if vendor != 0xFFFF {
201 | let device_id =
202 | config_read_u16(bus, slot, func, PCIConfigRegisters::PCIDeviceID as u8);
203 | let header_type = config_read_u8(
204 | bus,
205 | slot,
206 | func,
207 | PCIConfigRegisters::PCIHeaderType as u8,
208 | );
209 | // log::trace!(
210 | // "{:x}:{:x}:{:x} vendor: {:x} id:{:x} ht: {:x}",
211 | // bus,
212 | // slot,
213 | // func,
214 | // vendor,
215 | // device_id,
216 | // header_type
217 | // );
218 |
219 | devs.push(Pci { bus, slot, func });
220 | if func == 0 && (header_type & 0x80) == 0 {
221 | break;
222 | }
223 | }
224 | }
225 | }
226 | }
227 | Self { devs }
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/serial.rs:
--------------------------------------------------------------------------------
1 | use core::fmt;
2 |
3 | pub struct SerialPort {
4 | port: uart_16550::SerialPort,
5 | }
6 |
7 | impl SerialPort {
8 | /// # Safety
9 | ///
10 | /// unsafe because this function must only be called once
11 | pub unsafe fn init() -> Self {
12 | let mut port = unsafe { uart_16550::SerialPort::new(0x3F8) };
13 | port.init();
14 | Self { port }
15 | }
16 | }
17 |
18 | impl fmt::Write for SerialPort {
19 | fn write_str(&mut self, s: &str) -> fmt::Result {
20 | self.port.write_str(s).unwrap();
21 | Ok(())
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/bootloader/kernel/src/task/executor.rs:
--------------------------------------------------------------------------------
1 | use super::{Task, TaskId};
2 | use alloc::collections::VecDeque;
3 | use alloc::{collections::BTreeMap, sync::Arc};
4 | use crossbeam::queue::ArrayQueue;
5 | use futures::task::AtomicWaker;
6 | use futures::Future;
7 | use lazy_static::lazy_static;
8 | pub struct SimpleExecutor {
9 | task_queue: VecDeque,
10 | }
11 |
12 | impl SimpleExecutor {
13 | pub fn new() -> SimpleExecutor {
14 | SimpleExecutor {
15 | task_queue: VecDeque::new(),
16 | }
17 | }
18 |
19 | pub fn spawn(&mut self, task: Task) {
20 | self.task_queue.push_back(task)
21 | }
22 | }
23 | use core::task::RawWakerVTable;
24 | use core::task::{RawWaker, Waker};
25 |
26 | fn dummy_raw_waker() -> RawWaker {
27 | fn no_op(_: *const ()) {}
28 | fn clone(_: *const ()) -> RawWaker {
29 | dummy_raw_waker()
30 | }
31 |
32 | let vtable = &RawWakerVTable::new(clone, no_op, no_op, no_op);
33 | RawWaker::new(0 as *const (), vtable)
34 | }
35 |
36 | fn dummy_waker() -> Waker {
37 | unsafe { Waker::from_raw(dummy_raw_waker()) }
38 | }
39 | use core::task::{Context, Poll};
40 |
41 | impl SimpleExecutor {
42 | pub fn run(&mut self) {
43 | while let Some(mut task) = self.task_queue.pop_front() {
44 | let waker = dummy_waker();
45 | let mut context = Context::from_waker(&waker);
46 | match task.poll(&mut context) {
47 | Poll::Ready(()) => {} // task done
48 | Poll::Pending => self.task_queue.push_back(task),
49 | }
50 | }
51 | }
52 | }
53 |
54 | #[derive(Debug, Clone)]
55 | pub struct Spawner(Arc>);
56 |
57 | impl Spawner {
58 | pub fn run(&self, future: impl Future