├── .cargo
└── config.toml
├── .gitignore
├── .gitmodules
├── .vscode
└── settings.json
├── Cargo.lock
├── Cargo.toml
├── Makefile
├── README.md
├── canicula-common
├── .cargo
│ └── config.toml
├── Cargo.toml
└── src
│ ├── bootloader.rs
│ ├── bootloader
│ └── x86.rs
│ ├── entry.rs
│ ├── fs.rs
│ └── libs.rs
├── canicula-ext4
├── .cargo
│ └── config.toml
├── Cargo.toml
└── src
│ ├── ext4.rs
│ ├── tests.rs
│ ├── types.rs
│ └── types
│ ├── data_block.rs
│ ├── data_block_bitmap.rs
│ ├── group_descriptors.rs
│ ├── inode_bitmap.rs
│ ├── inode_table.rs
│ └── super_block.rs
├── canicula-kernel
├── Cargo.toml
├── aarch64-unknown-none.json
├── riscv64gc-unknown-none-elf.json
├── src
│ ├── arch
│ │ ├── aarch64
│ │ │ └── mod.rs
│ │ ├── mod.rs
│ │ ├── riscv64
│ │ │ ├── console.rs
│ │ │ ├── entry.asm
│ │ │ ├── logging.rs
│ │ │ ├── mod.rs
│ │ │ ├── panic.rs
│ │ │ ├── qemu.rs
│ │ │ └── sbi.rs
│ │ └── x86
│ │ │ ├── acpi
│ │ │ ├── handler.rs
│ │ │ └── mod.rs
│ │ │ ├── apic.rs
│ │ │ ├── bga.rs
│ │ │ ├── console.rs
│ │ │ ├── gdt.rs
│ │ │ ├── interrupts.rs
│ │ │ ├── logging.rs
│ │ │ ├── memory
│ │ │ ├── heap_allocator.rs
│ │ │ ├── mod.rs
│ │ │ └── page_allocator.rs
│ │ │ ├── mod.rs
│ │ │ ├── pcie.rs
│ │ │ ├── process.rs
│ │ │ ├── qemu.rs
│ │ │ ├── serial.rs
│ │ │ └── virtualization
│ │ │ ├── mod.rs
│ │ │ ├── svm.rs
│ │ │ ├── vmcb.rs
│ │ │ ├── vmcs.rs
│ │ │ └── vmx.rs
│ ├── linker
│ │ ├── aarch64-linker.ld
│ │ ├── riscv64-linker.ld
│ │ └── x86-linker.ld
│ ├── main.rs
│ ├── resources.rs
│ └── types
│ │ ├── elf.rs
│ │ └── mod.rs
└── x86_64-unknown-none.json
├── canicula-libs
├── Cargo.toml
└── src
│ ├── config.rs
│ ├── config
│ ├── aarch64.rs
│ ├── riscv64.rs
│ └── x86_64.rs
│ └── libs.rs
├── docs
├── architecture.md
├── bootloader.md
├── bootloader.old.md
├── dev-environment.md
└── ext4.md
├── resources
└── images
│ └── logo.png
└── rust-toolchain.toml
/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std = ["core", "compiler_builtins", "alloc"]
3 |
4 | [target.x86_64-unknown-none]
5 | rustflags = [
6 | "-Clink-arg=-Tcanicula-kernel/src/linker/x86-linker.ld",
7 | ]
8 |
9 | [target.riscv64gc-unknown-none-elf]
10 | rustflags = [
11 | "-Clink-arg=-Tcanicula-kernel/src/linker/riscv64-linker.ld",
12 | "-Cforce-frame-pointers=yes",
13 | ]
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Does not come with compiled products.
2 | /target
3 |
4 | # EFI files
5 | /esp
6 |
7 | # This file is the rustsbi startup image of qemu and needs to be downloaded by the user.
8 | rustsbi-qemu.bin
9 |
10 | # GDB Files
11 | .gdb_history
12 | .gdbinit
13 |
14 | .tasks
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "bootloader"]
2 | path = bootloader
3 | url = git@github.com:rust-osdev/bootloader.git
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "rust-analyzer.cargo.target": "x86_64-unknown-none",
3 | "rust-analyzer.checkOnSave.allTargets": false,
4 | "rust-analyzer.checkOnSave.target": "x86_64-unknown-none",
5 | "rust-analyzer.linkedProjects": [
6 | "./Cargo.toml",
7 | "./canicula-common/Cargo.toml",
8 | "./canicula-ext4/Cargo.toml",
9 | "./canicula-kernel/Cargo.toml",
10 | "./canicula-libs/Cargo.toml",
11 | ],
12 | "cSpell.words": [
13 | "rustc",
14 | "rustup",
15 | "builtins",
16 | "rustflags",
17 | "Tkernel",
18 | "Cforce",
19 | "riscv",
20 | "aarch",
21 | "riscv64gc-unknown-none-elf",
22 | "cafs",
23 | "libc",
24 | "bootloader",
25 | "uefi",
26 | "repr",
27 | "proto",
28 | "e_phoff",
29 | "e_shoff",
30 | "e_ehsize",
31 | "e_phentsize",
32 | "e_phnum",
33 | "e_shentsize",
34 | "e_shnum",
35 | "e_shstrndx",
36 | "p_vaddr",
37 | "p_paddr",
38 | "p_filesz",
39 | "p_memsz",
40 | "sh_addralign",
41 | "sh_entsize",
42 | "inodes",
43 | "wtime",
44 | "lastcheck",
45 | "checkinterval",
46 | "resuid",
47 | "resgid",
48 | "incompat",
49 | "prealloc",
50 | "inum",
51 | "kbytes",
52 | "uninit",
53 | ],
54 | "rust-analyzer.runnables.extraArgs": [
55 | "--target=x86_64-unknown-none",
56 | "-Zbuild-std=std,panic_abort",
57 | ],
58 | }
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 4
4 |
5 | [[package]]
6 | name = "acpi"
7 | version = "5.2.0"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "94476c7ef97af4c4d998b3f422c1b01d5211aad57c80ed200baf148d1f1efab6"
10 | dependencies = [
11 | "bit_field",
12 | "bitflags 2.5.0",
13 | "log",
14 | ]
15 |
16 | [[package]]
17 | name = "adler"
18 | version = "1.0.2"
19 | source = "registry+https://github.com/rust-lang/crates.io-index"
20 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
21 |
22 | [[package]]
23 | name = "aml"
24 | version = "0.16.4"
25 | source = "registry+https://github.com/rust-lang/crates.io-index"
26 | checksum = "c4f8cba7d4260ea05671dda81029f6f718b54402a4ec926a0d9a41bdbb96b415"
27 | dependencies = [
28 | "bit_field",
29 | "bitvec",
30 | "byteorder",
31 | "log",
32 | "spinning_top",
33 | ]
34 |
35 | [[package]]
36 | name = "arrayvec"
37 | version = "0.7.6"
38 | source = "registry+https://github.com/rust-lang/crates.io-index"
39 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
40 |
41 | [[package]]
42 | name = "atomic-polyfill"
43 | version = "1.0.3"
44 | source = "registry+https://github.com/rust-lang/crates.io-index"
45 | checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
46 | dependencies = [
47 | "critical-section",
48 | ]
49 |
50 | [[package]]
51 | name = "autocfg"
52 | version = "1.4.0"
53 | source = "registry+https://github.com/rust-lang/crates.io-index"
54 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
55 |
56 | [[package]]
57 | name = "bit"
58 | version = "0.1.1"
59 | source = "registry+https://github.com/rust-lang/crates.io-index"
60 | checksum = "2b645c5c09a7d4035949cfce1a915785aaad6f17800c35fda8a8c311c491f284"
61 |
62 | [[package]]
63 | name = "bit_field"
64 | version = "0.10.2"
65 | source = "registry+https://github.com/rust-lang/crates.io-index"
66 | checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
67 |
68 | [[package]]
69 | name = "bitflags"
70 | version = "1.3.2"
71 | source = "registry+https://github.com/rust-lang/crates.io-index"
72 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
73 |
74 | [[package]]
75 | name = "bitflags"
76 | version = "2.5.0"
77 | source = "registry+https://github.com/rust-lang/crates.io-index"
78 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
79 |
80 | [[package]]
81 | name = "bitvec"
82 | version = "1.0.1"
83 | source = "registry+https://github.com/rust-lang/crates.io-index"
84 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
85 | dependencies = [
86 | "funty",
87 | "radium",
88 | "tap",
89 | "wyz",
90 | ]
91 |
92 | [[package]]
93 | name = "bootloader-boot-config"
94 | version = "0.11.8"
95 | dependencies = [
96 | "serde",
97 | ]
98 |
99 | [[package]]
100 | name = "bootloader-x86_64-common"
101 | version = "0.11.8"
102 | dependencies = [
103 | "bootloader-boot-config",
104 | "bootloader_api 0.11.8",
105 | "conquer-once 0.3.2",
106 | "log",
107 | "noto-sans-mono-bitmap 0.2.0",
108 | "rand",
109 | "rand_hc",
110 | "raw-cpuid",
111 | "spinning_top",
112 | "uart_16550 0.2.19",
113 | "usize_conversions",
114 | "x86_64 0.14.13",
115 | "xmas-elf",
116 | ]
117 |
118 | [[package]]
119 | name = "bootloader-x86_64-uefi"
120 | version = "0.11.8"
121 | dependencies = [
122 | "bootloader-boot-config",
123 | "bootloader-x86_64-common",
124 | "bootloader_api 0.11.8",
125 | "log",
126 | "serde-json-core",
127 | "uefi 0.20.0",
128 | "x86_64 0.14.13",
129 | ]
130 |
131 | [[package]]
132 | name = "bootloader_api"
133 | version = "0.11.8"
134 | dependencies = [
135 | "rand",
136 | ]
137 |
138 | [[package]]
139 | name = "bootloader_api"
140 | version = "0.11.9"
141 | source = "registry+https://github.com/rust-lang/crates.io-index"
142 | checksum = "57a08a674787a3711ea0ba3bd730e6ffeb74832dcf6c51caf553528b33b54f73"
143 |
144 | [[package]]
145 | name = "byteorder"
146 | version = "1.5.0"
147 | source = "registry+https://github.com/rust-lang/crates.io-index"
148 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
149 |
150 | [[package]]
151 | name = "canicula-common"
152 | version = "0.1.0"
153 | dependencies = [
154 | "arrayvec",
155 | "noto-sans-mono-bitmap 0.3.1",
156 | "uefi 0.28.0",
157 | ]
158 |
159 | [[package]]
160 | name = "canicula-ext4"
161 | version = "0.1.0"
162 | dependencies = [
163 | "canicula-common",
164 | ]
165 |
166 | [[package]]
167 | name = "canicula-kernel"
168 | version = "0.1.0"
169 | dependencies = [
170 | "acpi",
171 | "aml",
172 | "bootloader_api 0.11.9",
173 | "canicula-common",
174 | "conquer-once 0.4.0",
175 | "lazy_static",
176 | "linked_list_allocator",
177 | "log",
178 | "nostd",
179 | "noto-sans-mono-bitmap 0.3.1",
180 | "png-decoder",
181 | "riscv",
182 | "sbi-rt",
183 | "spin 0.10.0",
184 | "uart_16550 0.3.2",
185 | "x2apic",
186 | "x86",
187 | "x86_64 0.15.2",
188 | ]
189 |
190 | [[package]]
191 | name = "canicula-libs"
192 | version = "0.1.0"
193 |
194 | [[package]]
195 | name = "cfg-if"
196 | version = "1.0.0"
197 | source = "registry+https://github.com/rust-lang/crates.io-index"
198 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
199 |
200 | [[package]]
201 | name = "conquer-once"
202 | version = "0.3.2"
203 | source = "registry+https://github.com/rust-lang/crates.io-index"
204 | checksum = "7c6d3a9775a69f6d1fe2cc888999b67ed30257d3da4d2af91984e722f2ec918a"
205 | dependencies = [
206 | "conquer-util",
207 | ]
208 |
209 | [[package]]
210 | name = "conquer-once"
211 | version = "0.4.0"
212 | source = "registry+https://github.com/rust-lang/crates.io-index"
213 | checksum = "5d008a441c0f269f36ca13712528069a86a3e60dffee1d98b976eb3b0b2160b4"
214 | dependencies = [
215 | "conquer-util",
216 | ]
217 |
218 | [[package]]
219 | name = "conquer-util"
220 | version = "0.3.0"
221 | source = "registry+https://github.com/rust-lang/crates.io-index"
222 | checksum = "e763eef8846b13b380f37dfecda401770b0ca4e56e95170237bd7c25c7db3582"
223 |
224 | [[package]]
225 | name = "crc32fast"
226 | version = "1.4.2"
227 | source = "registry+https://github.com/rust-lang/crates.io-index"
228 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
229 | dependencies = [
230 | "cfg-if",
231 | ]
232 |
233 | [[package]]
234 | name = "critical-section"
235 | version = "1.2.0"
236 | source = "registry+https://github.com/rust-lang/crates.io-index"
237 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
238 |
239 | [[package]]
240 | name = "embedded-hal"
241 | version = "1.0.0"
242 | source = "registry+https://github.com/rust-lang/crates.io-index"
243 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
244 |
245 | [[package]]
246 | name = "funty"
247 | version = "2.0.0"
248 | source = "registry+https://github.com/rust-lang/crates.io-index"
249 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
250 |
251 | [[package]]
252 | name = "getrandom"
253 | version = "0.2.15"
254 | source = "registry+https://github.com/rust-lang/crates.io-index"
255 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
256 | dependencies = [
257 | "cfg-if",
258 | "libc",
259 | "wasi",
260 | ]
261 |
262 | [[package]]
263 | name = "hash32"
264 | version = "0.2.1"
265 | source = "registry+https://github.com/rust-lang/crates.io-index"
266 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
267 | dependencies = [
268 | "byteorder",
269 | ]
270 |
271 | [[package]]
272 | name = "heapless"
273 | version = "0.7.17"
274 | source = "registry+https://github.com/rust-lang/crates.io-index"
275 | checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
276 | dependencies = [
277 | "atomic-polyfill",
278 | "hash32",
279 | "rustc_version",
280 | "spin 0.9.8",
281 | "stable_deref_trait",
282 | ]
283 |
284 | [[package]]
285 | name = "lazy_static"
286 | version = "1.5.0"
287 | source = "registry+https://github.com/rust-lang/crates.io-index"
288 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
289 | dependencies = [
290 | "spin 0.9.8",
291 | ]
292 |
293 | [[package]]
294 | name = "libc"
295 | version = "0.2.169"
296 | source = "registry+https://github.com/rust-lang/crates.io-index"
297 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
298 |
299 | [[package]]
300 | name = "linked_list_allocator"
301 | version = "0.10.5"
302 | source = "registry+https://github.com/rust-lang/crates.io-index"
303 | checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
304 | dependencies = [
305 | "spinning_top",
306 | ]
307 |
308 | [[package]]
309 | name = "lock_api"
310 | version = "0.4.12"
311 | source = "registry+https://github.com/rust-lang/crates.io-index"
312 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
313 | dependencies = [
314 | "autocfg",
315 | "scopeguard",
316 | ]
317 |
318 | [[package]]
319 | name = "log"
320 | version = "0.4.27"
321 | source = "registry+https://github.com/rust-lang/crates.io-index"
322 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
323 |
324 | [[package]]
325 | name = "memchr"
326 | version = "2.7.4"
327 | source = "registry+https://github.com/rust-lang/crates.io-index"
328 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
329 |
330 | [[package]]
331 | name = "miniz_oxide"
332 | version = "0.4.4"
333 | source = "registry+https://github.com/rust-lang/crates.io-index"
334 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
335 | dependencies = [
336 | "adler",
337 | "autocfg",
338 | ]
339 |
340 | [[package]]
341 | name = "nostd"
342 | version = "0.1.4"
343 | source = "registry+https://github.com/rust-lang/crates.io-index"
344 | checksum = "fa3dd4c68516f7c5a1838eda0de376d4bc3c2aba3893da0ca2cf400bbc18435f"
345 | dependencies = [
346 | "memchr",
347 | ]
348 |
349 | [[package]]
350 | name = "noto-sans-mono-bitmap"
351 | version = "0.2.0"
352 | source = "registry+https://github.com/rust-lang/crates.io-index"
353 | checksum = "a27daf9557165efe1d09b52f97393bf6283cadb0a76fbe64a1061e15553a994a"
354 |
355 | [[package]]
356 | name = "noto-sans-mono-bitmap"
357 | version = "0.3.1"
358 | source = "registry+https://github.com/rust-lang/crates.io-index"
359 | checksum = "1064d564ae026ae123bf5d607318b42a5b31d70a3c48e6ea7ee44cce4cdb095e"
360 |
361 | [[package]]
362 | name = "num_enum"
363 | version = "0.5.11"
364 | source = "registry+https://github.com/rust-lang/crates.io-index"
365 | checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
366 | dependencies = [
367 | "num_enum_derive",
368 | ]
369 |
370 | [[package]]
371 | name = "num_enum_derive"
372 | version = "0.5.11"
373 | source = "registry+https://github.com/rust-lang/crates.io-index"
374 | checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
375 | dependencies = [
376 | "proc-macro2",
377 | "quote",
378 | "syn 1.0.109",
379 | ]
380 |
381 | [[package]]
382 | name = "paste"
383 | version = "1.0.15"
384 | source = "registry+https://github.com/rust-lang/crates.io-index"
385 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
386 |
387 | [[package]]
388 | name = "png-decoder"
389 | version = "0.1.1"
390 | source = "registry+https://github.com/rust-lang/crates.io-index"
391 | checksum = "3e3e93d4884a2609f2dccbafabd3e25c49e89bb872ab84bfea60feaf17615944"
392 | dependencies = [
393 | "crc32fast",
394 | "miniz_oxide",
395 | "num_enum",
396 | ]
397 |
398 | [[package]]
399 | name = "ppv-lite86"
400 | version = "0.2.20"
401 | source = "registry+https://github.com/rust-lang/crates.io-index"
402 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
403 | dependencies = [
404 | "zerocopy",
405 | ]
406 |
407 | [[package]]
408 | name = "proc-macro2"
409 | version = "1.0.82"
410 | source = "registry+https://github.com/rust-lang/crates.io-index"
411 | checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
412 | dependencies = [
413 | "unicode-ident",
414 | ]
415 |
416 | [[package]]
417 | name = "ptr_meta"
418 | version = "0.2.0"
419 | source = "registry+https://github.com/rust-lang/crates.io-index"
420 | checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607"
421 | dependencies = [
422 | "ptr_meta_derive",
423 | ]
424 |
425 | [[package]]
426 | name = "ptr_meta_derive"
427 | version = "0.2.0"
428 | source = "registry+https://github.com/rust-lang/crates.io-index"
429 | checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
430 | dependencies = [
431 | "proc-macro2",
432 | "quote",
433 | "syn 1.0.109",
434 | ]
435 |
436 | [[package]]
437 | name = "quote"
438 | version = "1.0.36"
439 | source = "registry+https://github.com/rust-lang/crates.io-index"
440 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
441 | dependencies = [
442 | "proc-macro2",
443 | ]
444 |
445 | [[package]]
446 | name = "radium"
447 | version = "0.7.0"
448 | source = "registry+https://github.com/rust-lang/crates.io-index"
449 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
450 |
451 | [[package]]
452 | name = "rand"
453 | version = "0.8.5"
454 | source = "registry+https://github.com/rust-lang/crates.io-index"
455 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
456 | dependencies = [
457 | "libc",
458 | "rand_chacha",
459 | "rand_core",
460 | ]
461 |
462 | [[package]]
463 | name = "rand_chacha"
464 | version = "0.3.1"
465 | source = "registry+https://github.com/rust-lang/crates.io-index"
466 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
467 | dependencies = [
468 | "ppv-lite86",
469 | "rand_core",
470 | ]
471 |
472 | [[package]]
473 | name = "rand_core"
474 | version = "0.6.4"
475 | source = "registry+https://github.com/rust-lang/crates.io-index"
476 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
477 | dependencies = [
478 | "getrandom",
479 | ]
480 |
481 | [[package]]
482 | name = "rand_hc"
483 | version = "0.3.2"
484 | source = "registry+https://github.com/rust-lang/crates.io-index"
485 | checksum = "7b363d4f6370f88d62bf586c80405657bde0f0e1b8945d47d2ad59b906cb4f54"
486 | dependencies = [
487 | "rand_core",
488 | ]
489 |
490 | [[package]]
491 | name = "raw-cpuid"
492 | version = "10.7.0"
493 | source = "registry+https://github.com/rust-lang/crates.io-index"
494 | checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
495 | dependencies = [
496 | "bitflags 1.3.2",
497 | ]
498 |
499 | [[package]]
500 | name = "riscv"
501 | version = "0.13.0"
502 | source = "registry+https://github.com/rust-lang/crates.io-index"
503 | checksum = "afa3cdbeccae4359f6839a00e8b77e5736caa200ba216caf38d24e4c16e2b586"
504 | dependencies = [
505 | "critical-section",
506 | "embedded-hal",
507 | "paste",
508 | "riscv-macros",
509 | "riscv-pac",
510 | ]
511 |
512 | [[package]]
513 | name = "riscv-macros"
514 | version = "0.2.0"
515 | source = "registry+https://github.com/rust-lang/crates.io-index"
516 | checksum = "e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc"
517 | dependencies = [
518 | "proc-macro2",
519 | "quote",
520 | "syn 2.0.64",
521 | ]
522 |
523 | [[package]]
524 | name = "riscv-pac"
525 | version = "0.2.0"
526 | source = "registry+https://github.com/rust-lang/crates.io-index"
527 | checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436"
528 |
529 | [[package]]
530 | name = "rustc_version"
531 | version = "0.4.1"
532 | source = "registry+https://github.com/rust-lang/crates.io-index"
533 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
534 | dependencies = [
535 | "semver",
536 | ]
537 |
538 | [[package]]
539 | name = "rustversion"
540 | version = "1.0.19"
541 | source = "registry+https://github.com/rust-lang/crates.io-index"
542 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
543 |
544 | [[package]]
545 | name = "ryu"
546 | version = "1.0.18"
547 | source = "registry+https://github.com/rust-lang/crates.io-index"
548 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
549 |
550 | [[package]]
551 | name = "sbi-rt"
552 | version = "0.0.3"
553 | source = "registry+https://github.com/rust-lang/crates.io-index"
554 | checksum = "7fbaa69be1eedc61c426e6d489b2260482e928b465360576900d52d496a58bd0"
555 | dependencies = [
556 | "sbi-spec",
557 | ]
558 |
559 | [[package]]
560 | name = "sbi-spec"
561 | version = "0.0.7"
562 | source = "registry+https://github.com/rust-lang/crates.io-index"
563 | checksum = "e6e36312fb5ddc10d08ecdc65187402baba4ac34585cb9d1b78522ae2358d890"
564 |
565 | [[package]]
566 | name = "scopeguard"
567 | version = "1.2.0"
568 | source = "registry+https://github.com/rust-lang/crates.io-index"
569 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
570 |
571 | [[package]]
572 | name = "semver"
573 | version = "1.0.25"
574 | source = "registry+https://github.com/rust-lang/crates.io-index"
575 | checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
576 |
577 | [[package]]
578 | name = "serde"
579 | version = "1.0.210"
580 | source = "registry+https://github.com/rust-lang/crates.io-index"
581 | checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
582 | dependencies = [
583 | "serde_derive",
584 | ]
585 |
586 | [[package]]
587 | name = "serde-json-core"
588 | version = "0.5.1"
589 | source = "registry+https://github.com/rust-lang/crates.io-index"
590 | checksum = "3c9e1ab533c0bc414c34920ec7e5f097101d126ed5eac1a1aac711222e0bbb33"
591 | dependencies = [
592 | "heapless",
593 | "ryu",
594 | "serde",
595 | ]
596 |
597 | [[package]]
598 | name = "serde_derive"
599 | version = "1.0.210"
600 | source = "registry+https://github.com/rust-lang/crates.io-index"
601 | checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
602 | dependencies = [
603 | "proc-macro2",
604 | "quote",
605 | "syn 2.0.64",
606 | ]
607 |
608 | [[package]]
609 | name = "spin"
610 | version = "0.9.8"
611 | source = "registry+https://github.com/rust-lang/crates.io-index"
612 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
613 | dependencies = [
614 | "lock_api",
615 | ]
616 |
617 | [[package]]
618 | name = "spin"
619 | version = "0.10.0"
620 | source = "registry+https://github.com/rust-lang/crates.io-index"
621 | checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
622 | dependencies = [
623 | "lock_api",
624 | ]
625 |
626 | [[package]]
627 | name = "spinning_top"
628 | version = "0.2.5"
629 | source = "registry+https://github.com/rust-lang/crates.io-index"
630 | checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
631 | dependencies = [
632 | "lock_api",
633 | ]
634 |
635 | [[package]]
636 | name = "stable_deref_trait"
637 | version = "1.2.0"
638 | source = "registry+https://github.com/rust-lang/crates.io-index"
639 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
640 |
641 | [[package]]
642 | name = "syn"
643 | version = "1.0.109"
644 | source = "registry+https://github.com/rust-lang/crates.io-index"
645 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
646 | dependencies = [
647 | "proc-macro2",
648 | "quote",
649 | "unicode-ident",
650 | ]
651 |
652 | [[package]]
653 | name = "syn"
654 | version = "2.0.64"
655 | source = "registry+https://github.com/rust-lang/crates.io-index"
656 | checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
657 | dependencies = [
658 | "proc-macro2",
659 | "quote",
660 | "unicode-ident",
661 | ]
662 |
663 | [[package]]
664 | name = "tap"
665 | version = "1.0.1"
666 | source = "registry+https://github.com/rust-lang/crates.io-index"
667 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
668 |
669 | [[package]]
670 | name = "uart_16550"
671 | version = "0.2.19"
672 | source = "registry+https://github.com/rust-lang/crates.io-index"
673 | checksum = "614ff2a87880d4bd4374722268598a970bbad05ced8bf630439417347254ab2e"
674 | dependencies = [
675 | "bitflags 1.3.2",
676 | "rustversion",
677 | "x86_64 0.14.13",
678 | ]
679 |
680 | [[package]]
681 | name = "uart_16550"
682 | version = "0.3.2"
683 | source = "registry+https://github.com/rust-lang/crates.io-index"
684 | checksum = "e492212ac378a5e00da953718dafb1340d9fbaf4f27d6f3c5cab03d931d1c049"
685 | dependencies = [
686 | "bitflags 2.5.0",
687 | "rustversion",
688 | "x86",
689 | ]
690 |
691 | [[package]]
692 | name = "ucs2"
693 | version = "0.3.3"
694 | source = "registry+https://github.com/rust-lang/crates.io-index"
695 | checksum = "df79298e11f316400c57ec268f3c2c29ac3c4d4777687955cd3d4f3a35ce7eba"
696 | dependencies = [
697 | "bit_field",
698 | ]
699 |
700 | [[package]]
701 | name = "uefi"
702 | version = "0.20.0"
703 | source = "registry+https://github.com/rust-lang/crates.io-index"
704 | checksum = "ab39d5e7740f21ed4c46d6659f31038bbe3fe7a8be1f702d8a984348837c43b1"
705 | dependencies = [
706 | "bitflags 1.3.2",
707 | "log",
708 | "ptr_meta",
709 | "ucs2",
710 | "uefi-macros 0.11.0",
711 | ]
712 |
713 | [[package]]
714 | name = "uefi"
715 | version = "0.28.0"
716 | source = "registry+https://github.com/rust-lang/crates.io-index"
717 | checksum = "a9c0a56dc9fed2589aad6ddca11c2584968fc21f227b5d7083bb8961d26a69fa"
718 | dependencies = [
719 | "bitflags 2.5.0",
720 | "cfg-if",
721 | "log",
722 | "ptr_meta",
723 | "ucs2",
724 | "uefi-macros 0.13.0",
725 | "uefi-raw",
726 | "uguid",
727 | ]
728 |
729 | [[package]]
730 | name = "uefi-macros"
731 | version = "0.11.0"
732 | source = "registry+https://github.com/rust-lang/crates.io-index"
733 | checksum = "e0caeb0e7b31b9f1f347e541106be10aa8c66c76fa722a3298a4cd21433fabd4"
734 | dependencies = [
735 | "proc-macro2",
736 | "quote",
737 | "syn 1.0.109",
738 | ]
739 |
740 | [[package]]
741 | name = "uefi-macros"
742 | version = "0.13.0"
743 | source = "registry+https://github.com/rust-lang/crates.io-index"
744 | checksum = "26a7b1c2c808c3db854a54d5215e3f7e7aaf5dcfbce095598cba6af29895695d"
745 | dependencies = [
746 | "proc-macro2",
747 | "quote",
748 | "syn 2.0.64",
749 | ]
750 |
751 | [[package]]
752 | name = "uefi-raw"
753 | version = "0.5.2"
754 | source = "registry+https://github.com/rust-lang/crates.io-index"
755 | checksum = "efa8716f52e8cab8bcedfd5052388a0f263b69fe5cc2561548dc6a530678333c"
756 | dependencies = [
757 | "bitflags 2.5.0",
758 | "ptr_meta",
759 | "uguid",
760 | ]
761 |
762 | [[package]]
763 | name = "uguid"
764 | version = "2.2.0"
765 | source = "registry+https://github.com/rust-lang/crates.io-index"
766 | checksum = "ab14ea9660d240e7865ce9d54ecdbd1cd9fa5802ae6f4512f093c7907e921533"
767 |
768 | [[package]]
769 | name = "unicode-ident"
770 | version = "1.0.12"
771 | source = "registry+https://github.com/rust-lang/crates.io-index"
772 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
773 |
774 | [[package]]
775 | name = "usize_conversions"
776 | version = "0.2.0"
777 | source = "registry+https://github.com/rust-lang/crates.io-index"
778 | checksum = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
779 |
780 | [[package]]
781 | name = "volatile"
782 | version = "0.4.6"
783 | source = "registry+https://github.com/rust-lang/crates.io-index"
784 | checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793"
785 |
786 | [[package]]
787 | name = "wasi"
788 | version = "0.11.0+wasi-snapshot-preview1"
789 | source = "registry+https://github.com/rust-lang/crates.io-index"
790 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
791 |
792 | [[package]]
793 | name = "wyz"
794 | version = "0.5.1"
795 | source = "registry+https://github.com/rust-lang/crates.io-index"
796 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
797 | dependencies = [
798 | "tap",
799 | ]
800 |
801 | [[package]]
802 | name = "x2apic"
803 | version = "0.5.0"
804 | source = "registry+https://github.com/rust-lang/crates.io-index"
805 | checksum = "db5cbcb7faedfa15f90376004ffc0cb42e427623ab56629f0073d275ee8e7043"
806 | dependencies = [
807 | "bit",
808 | "bitflags 1.3.2",
809 | "paste",
810 | "raw-cpuid",
811 | "x86_64 0.15.2",
812 | ]
813 |
814 | [[package]]
815 | name = "x86"
816 | version = "0.52.0"
817 | source = "registry+https://github.com/rust-lang/crates.io-index"
818 | checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
819 | dependencies = [
820 | "bit_field",
821 | "bitflags 1.3.2",
822 | "raw-cpuid",
823 | ]
824 |
825 | [[package]]
826 | name = "x86_64"
827 | version = "0.14.13"
828 | source = "registry+https://github.com/rust-lang/crates.io-index"
829 | checksum = "c101112411baafbb4bf8d33e4c4a80ab5b02d74d2612331c61e8192fc9710491"
830 | dependencies = [
831 | "bit_field",
832 | "bitflags 2.5.0",
833 | "rustversion",
834 | "volatile",
835 | ]
836 |
837 | [[package]]
838 | name = "x86_64"
839 | version = "0.15.2"
840 | source = "registry+https://github.com/rust-lang/crates.io-index"
841 | checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae"
842 | dependencies = [
843 | "bit_field",
844 | "bitflags 2.5.0",
845 | "rustversion",
846 | "volatile",
847 | ]
848 |
849 | [[package]]
850 | name = "xmas-elf"
851 | version = "0.8.0"
852 | source = "registry+https://github.com/rust-lang/crates.io-index"
853 | checksum = "8d29b4d8e7beaceb4e77447ba941a7600d23d0319ab52da0461abea214832d5a"
854 | dependencies = [
855 | "zero",
856 | ]
857 |
858 | [[package]]
859 | name = "zero"
860 | version = "0.1.3"
861 | source = "registry+https://github.com/rust-lang/crates.io-index"
862 | checksum = "2fe21bcc34ca7fe6dd56cc2cb1261ea59d6b93620215aefb5ea6032265527784"
863 |
864 | [[package]]
865 | name = "zerocopy"
866 | version = "0.7.35"
867 | source = "registry+https://github.com/rust-lang/crates.io-index"
868 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
869 | dependencies = [
870 | "byteorder",
871 | "zerocopy-derive",
872 | ]
873 |
874 | [[package]]
875 | name = "zerocopy-derive"
876 | version = "0.7.35"
877 | source = "registry+https://github.com/rust-lang/crates.io-index"
878 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
879 | dependencies = [
880 | "proc-macro2",
881 | "quote",
882 | "syn 2.0.64",
883 | ]
884 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | resolver = "2"
3 | members = [
4 | "bootloader/uefi",
5 | "bootloader/api",
6 | "bootloader/common",
7 | "bootloader/common/config",
8 |
9 | "canicula-common",
10 | "canicula-ext4",
11 | "canicula-kernel",
12 | "canicula-libs",
13 | ]
14 |
15 | [workspace.dependencies]
16 | bootloader_api = { version = "0.11.8", path = "bootloader/api" }
17 | bootloader-x86_64-common = { version = "0.11.8", path = "bootloader/common" }
18 | bootloader-boot-config = { version = "0.11.8", path = "bootloader/common/config" }
19 | bootloader-x86_64-bios-common = { version = "0.11.8", path = "bootloader/bios/common" }
20 |
21 | [workspace.package]
22 | version = "0.11.8"
23 | authors = ["hanbings hanbings@hanbings.io"]
24 | repository = "https://github.com/hanbings/canicula"
25 | license = "MIT"
26 |
27 | [profile.release]
28 | debug = true
29 | panic = "unwind"
30 |
31 | [profile.dev]
32 | debug = true
33 | panic = "unwind"
34 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | OS := $(shell uname)
2 | DISTRO := $(shell cat /etc/*release | grep '^ID=' | cut -d '=' -f2)
3 | LOG_LEVEL ?= DEBUG
4 |
5 | OVMF_CODE_PATH := /usr/share/OVMF/OVMF_CODE.fd
6 | OVMF_VARS_PATH := /usr/share/OVMF/OVMF_VARS.fd
7 |
8 | ifeq ($(OS),Linux)
9 | ifeq ($(DISTRO),arch)
10 | OVMF_CODE_PATH := /usr/share/OVMF/x64/OVMF_CODE.4m.fd
11 | OVMF_VARS_PATH := /usr/share/OVMF/x64/OVMF_VARS.4m.fd
12 | endif
13 |
14 | ifeq ($(DISTRO),debian)
15 | OVMF_CODE_PATH := /usr/share/OVMF/OVMF_CODE_4M.fd
16 | OVMF_VARS_PATH := /usr/share/OVMF/OVMF_VARS_4M.fd
17 | endif
18 | endif
19 |
20 | $(info OS=$(OS))
21 | $(info DISTRO=$(DISTRO))
22 | $(info OVMF_CODE_PATH=$(OVMF_CODE_PATH))
23 | $(info OVMF_VARS_PATH=$(OVMF_VARS_PATH))
24 |
25 | all: efi kernel
26 |
27 | efi:
28 | cd bootloader/uefi && cargo build --target x86_64-unknown-uefi --release -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem
29 | mkdir -p esp/efi/boot/
30 | cp bootloader/target/x86_64-unknown-uefi/release/bootloader-x86_64-uefi.efi esp/efi/boot/bootx64.efi
31 |
32 | kernel:
33 | LOG_LEVEL=$(LOG_LEVEL) cargo build --bin canicula-kernel --target x86_64-unknown-none
34 | mkdir -p esp
35 | cp target/x86_64-unknown-none/debug/canicula-kernel esp/kernel-x86_64
36 |
37 | clean:
38 | rm -rf target
39 | rm -rf esp
40 |
41 | clean-esp:
42 | rm -rf esp
43 |
44 | qemu:
45 | qemu-system-x86_64 \
46 | -m 256M \
47 | -serial stdio \
48 | -enable-kvm \
49 | -device isa-debug-exit,iobase=0xf4,iosize=0x04 \
50 | -drive if=pflash,format=raw,readonly=on,file=$(OVMF_CODE_PATH) \
51 | -drive if=pflash,format=raw,readonly=on,file=$(OVMF_VARS_PATH) \
52 | -drive format=raw,file=fat:rw:esp
53 |
54 | kill-qemu:
55 | pgrep qemu | xargs kill -9
56 |
57 | .PHONY: efi kernel clean qemu kill-qemu clean-esp all
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
⭐ Canicula OS
4 |
5 | ## ⭐ Canicula OS
6 |
7 | 感谢 [xv6-rev7](https://pdos.csail.mit.edu/6.828/2012/xv6/book-rev7.pdf)、[xv6(中文文档)](https://th0ar.gitbooks.io/xv6-chinese/content/)、[rCore](https://rcore-os.cn/rCore-Tutorial-Book-v3/index.html) 和 [os.phil-opp.com](https://os.phil-opp.com/zh-CN/) 这样优秀的教材!
8 |
9 | 那么旅途从这里开始!
10 |
11 | ## 🔨 快速构建
12 |
13 | ```shell
14 | git submodule init
15 | git submodule update
16 |
17 | # 构建 bootloader 和内核
18 | make
19 | # 使用 qemu 运行
20 | make qemu
21 | ```
22 |
23 | ## 📦 博客 / 文档
24 |
25 | > [!WARNING]
26 | > 本人还并不是很熟悉 Rust 语言并且这份文档只是作为学习操作系统的知识的记录,还会存在很多错误的地方,仅供参考。
27 | > 还请多多指教!
28 |
29 | > [!NOTE]
30 | > Blog 主要为补充性内容,用于补充文档中的前置知识。
31 | > 数字序号部分是主要的文档,用于描述一个内核中应该有的功能。
32 | > Ext 部分补充 “教学” 内核之外的扩展性内容。
33 |
34 | [Blog - Rust:使用 uefi-rs 编写一个 UEFI 应用并加载内核](https://blog.hanbings.io/posts/rust-uefi-bootloader/)
35 |
36 | [0 - 基本开发环境](docs/dev-environment.md)
37 |
38 | [1 - 引导](docs/bootloader.md)
39 |
40 | [2 - 中断与异常处理(WIP)](docs/exceptions-and-interrupts.md)
41 |
42 | [3 - 段、分段、分页与页表(WIP)](docs/paging.md)
43 |
44 | [4 - 内存管理(WIP)](docs/mm.md)
45 |
46 | [5 - 进程调度(WIP)](docs/process.md)
47 |
48 | [6 - 文件系统(WIP)](bdocs/fs.md)
49 |
50 | [7 - 线程、线程通信(WIP)](docs/thread.md)
51 |
52 | [8 - 多核(WIP)](docs/muilt-core.md)
53 |
54 | [9 - 外部接口:USB、网卡与显卡(WIP)](docs/extend-interface.md)
55 |
56 | [10 - 显存映射与图形化(WIP)](docs/graphics.md)
57 |
58 | [Ext - 处理器架构(WIP)](docs/architecture.md)
59 |
60 | [Ext - 模块化设计(WIP)](docs/design.md)
61 |
62 | [Ext - Ext4 文件系统(WIP)](docs/ext4.md)
63 |
64 | **引用名称说明**
65 |
66 | | 手册 | 原始链接 | 文中引用名称 |
67 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------ |
68 | | Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4 (Order Number: 253665-086US December 2024) | https://cdrdv2-public.intel.com/843820/325462-sdm-vol-1-2abcd-3abcd-4-1.pdf | Intel 手册 |
69 | | AMD64 Architecture Programmer’s Manual Volumes 1–5 (Publication No. 40332 Revision 4.08 Date April 2024) | https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/40332.pdf | AMD 手册 |
70 | | Unified Extensible Firmware Interface (UEFI) Specification Release 2.11 (Nov 21, 2024) | https://uefi.org/sites/default/files/resources/UEFI_Spec_Final_2.11.pdf | UEFI Spec |
--------------------------------------------------------------------------------
/canicula-common/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std = ["core", "compiler_builtins", "alloc"]
3 |
4 | [build]
5 | target = [
6 | "x86_64-unknown-none",
7 | "aarch64-unknown-none",
8 | "riscv64gc-unknown-none-elf",
9 | "x86_64-unknown-linux-gnu",
10 | ]
11 |
--------------------------------------------------------------------------------
/canicula-common/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "canicula-common"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | name = "canicula_common"
8 | path = "src/libs.rs"
9 |
10 | [dependencies]
11 | noto-sans-mono-bitmap = "0.3.1"
12 |
13 | [target.x86_64-unknown-uefi.dependencies]
14 | uefi = { version = "0.28.0", features = ["logger", "panic_handler"] }
15 | arrayvec = { version = "0.7.2", default-features = false }
16 |
17 | [target.aarch64-unknown-uefi.dependencies]
18 |
19 | [target.x86_64-unknown-none.dependencies]
20 | uefi = { version = "0.28.0", features = ["logger", "panic_handler"] }
21 | arrayvec = { version = "0.7.2", default-features = false }
22 |
23 | [target.aarch64-unknown-none.dependencies]
24 |
25 | [target.riscv64gc-unknown-none-elf.dependencies]
--------------------------------------------------------------------------------
/canicula-common/src/bootloader.rs:
--------------------------------------------------------------------------------
1 | #[cfg(target_arch = "x86_64")]
2 | pub mod x86;
3 |
--------------------------------------------------------------------------------
/canicula-common/src/bootloader/x86.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/canicula-common/src/entry.rs:
--------------------------------------------------------------------------------
1 | pub trait KernelEntry {
2 | fn entry() -> !;
3 | }
4 |
--------------------------------------------------------------------------------
/canicula-common/src/fs.rs:
--------------------------------------------------------------------------------
1 | #[derive(Debug)]
2 | pub enum OperateError {
3 | InvalidFileDescriptor,
4 | Fault,
5 | SystemInterrupted,
6 | IO,
7 | DeviceNoFreeSpace,
8 | NotFoundDev,
9 | TimeOut,
10 | }
11 |
--------------------------------------------------------------------------------
/canicula-common/src/libs.rs:
--------------------------------------------------------------------------------
1 | #![no_std]
2 | #![no_main]
3 |
4 | pub mod bootloader;
5 | pub mod entry;
6 | pub mod fs;
7 |
--------------------------------------------------------------------------------
/canicula-ext4/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [unstable]
2 | build-std = ["core", "compiler_builtins", "alloc"]
3 |
4 | [build]
5 | target = [
6 | "x86_64-unknown-none",
7 | "aarch64-unknown-none",
8 | "riscv64gc-unknown-none-elf",
9 | "x86_64-unknown-linux-gnu",
10 | ]
11 |
--------------------------------------------------------------------------------
/canicula-ext4/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "canicula-ext4"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | name = "canicula_ext4"
8 | path = "src/ext4.rs"
9 |
10 | [dependencies]
11 | canicula-common = { path = "../canicula-common" }
12 |
--------------------------------------------------------------------------------
/canicula-ext4/src/ext4.rs:
--------------------------------------------------------------------------------
1 | #![cfg_attr(not(test), no_std)]
2 |
3 | extern crate alloc;
4 |
5 | use alloc::vec::Vec;
6 | use canicula_common::fs::OperateError;
7 | use core::mem::MaybeUninit;
8 | use types::super_block::SuperBlock;
9 |
10 | mod tests;
11 | mod types;
12 |
13 | const GROUP_ZERO_PADDING: usize = 1024;
14 |
15 | #[allow(unused)]
16 | pub struct Ext4FS {
17 | read_byte: fn(usize) -> Result,
18 | write_byte: fn(u8, usize) -> Result,
19 | super_block: Option,
20 | }
21 |
22 | #[allow(unused)]
23 | impl Ext4FS {
24 | pub fn new(
25 | read_byte: fn(usize) -> Result,
26 | write_byte: fn(u8, usize) -> Result,
27 | ) -> Self {
28 | let mut super_block = MaybeUninit::::uninit();
29 | let void_super_block_fields = unsafe {
30 | core::slice::from_raw_parts(
31 | &super_block as *const _ as *const u8,
32 | core::mem::size_of::(),
33 | )
34 | };
35 |
36 | let mut data_index = 0;
37 | for (i, field) in void_super_block_fields
38 | .chunks(core::mem::size_of::())
39 | .enumerate()
40 | {
41 | // get the current field length.
42 | let size = field.len();
43 | let length = size / 8;
44 | let mut contents: Vec = Vec::new();
45 |
46 | // read data from physical device.
47 | let mut count = 0;
48 | while count < length {
49 | count = count + 1;
50 | let byte = (read_byte)(length + GROUP_ZERO_PADDING);
51 |
52 | match byte {
53 | Ok(byte) => contents.push(byte),
54 | Err(_) => contents.push(0),
55 | }
56 | }
57 |
58 | let ptr = super_block.as_mut_ptr();
59 | // initialize the value of the structure
60 | // because it is little-endian data, it is read backwards
61 | for content in contents.iter().rev() {
62 | unsafe {
63 | core::ptr::write((ptr as *const u8).offset(data_index) as *mut u8, *content)
64 | };
65 | data_index = data_index + 1;
66 | }
67 | }
68 |
69 | Ext4FS {
70 | read_byte,
71 | write_byte,
72 | super_block: Some(unsafe { super_block.assume_init() }),
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/canicula-ext4/src/tests.rs:
--------------------------------------------------------------------------------
1 | mod test {
2 | #[test]
3 | fn test() {
4 | use crate::Ext4FS;
5 | use canicula_common::fs::OperateError;
6 |
7 | let read_byte = |_offset: usize| -> Result {
8 | // Implement your read_byte function here
9 | Ok(0)
10 | };
11 |
12 | let write_byte = |_byte: u8, _offset: usize| -> Result {
13 | // Implement your write_byte function here
14 | Ok(1)
15 | };
16 |
17 | let _fs: Ext4FS<1024> = Ext4FS::new(read_byte, write_byte);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/canicula-ext4/src/types.rs:
--------------------------------------------------------------------------------
1 | pub mod data_block;
2 | pub mod data_block_bitmap;
3 | pub mod group_descriptors;
4 | pub mod inode_bitmap;
5 | pub mod inode_table;
6 | pub mod super_block;
7 |
--------------------------------------------------------------------------------
/canicula-ext4/src/types/data_block.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/canicula-ext4/src/types/data_block_bitmap.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/canicula-ext4/src/types/group_descriptors.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/canicula-ext4/src/types/inode_bitmap.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/canicula-ext4/src/types/inode_table.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/canicula-ext4/src/types/super_block.rs:
--------------------------------------------------------------------------------
1 | #![allow(dead_code)]
2 | #[derive(Debug, Clone, PartialEq, Eq)]
3 | pub enum SuperBlock {
4 | InodesCount,
5 | BlocksCountLo,
6 | RBlocksCountLo,
7 | FreeBlocksCountLo,
8 | FreeInodesCount,
9 | FirstDataBlock,
10 | LogBlockSize,
11 | LogClusterSize,
12 | BlocksPerGroup,
13 | ClustersPerGroup,
14 | InodesPerGroup,
15 | Mtime,
16 | Wtime,
17 | MntCount,
18 | MaxMntCount,
19 | Magic,
20 | State,
21 | Errors,
22 | MinorRevLevel,
23 | LastCheck,
24 | CheckInterval,
25 | CreatorOs,
26 | RevLevel,
27 | DefResuid,
28 | DefResgid,
29 | FirstIno,
30 | InodeSize,
31 | BlockGroupNr,
32 | FeatureCompat,
33 | FeatureIncompat,
34 | FeatureRoCompat,
35 | Uuid,
36 | VolumeName,
37 | LastMounted,
38 | AlgorithmUsageBitmap,
39 | PreallocBlocks,
40 | PreallocDirBlocks,
41 | ReservedGdtBlocks,
42 | JournalUuid,
43 | JournalInum,
44 | JournalDev,
45 | LastOrphan,
46 | HashSeed,
47 | DefHashVersion,
48 | JnlBackupType,
49 | DescSize,
50 | DefaultMountOpts,
51 | FirstMetaBg,
52 | MkfsTime,
53 | JnlBlocks,
54 | BlocksCountHi,
55 | RBlocksCountHi,
56 | FreeBlocksCountHi,
57 | MinExtraIsize,
58 | WantExtraIsize,
59 | Flags,
60 | RaidStride,
61 | MMPInterval,
62 | MMPBlock,
63 | RaidStripeWidth,
64 | LogGroupsPerFlex,
65 | ChecksumType,
66 | ReservedPad,
67 | KbytesWritten,
68 | SnapshotInum,
69 | SnapshotId,
70 | SnapshotRBlocksCount,
71 | SnapshotList,
72 | ErrorCount,
73 | FirstErrorTime,
74 | FirstErrorIno,
75 | FirstErrorBlock,
76 | FirstErrorFunc,
77 | FirstErrorLine,
78 | LastErrorTime,
79 | LastErrorIno,
80 | LastErrorLine,
81 | LastErrorBlock,
82 | LastErrorFunc,
83 | MountOpts,
84 | UsrQuotaInum,
85 | GrpQuotaInum,
86 | OverheadBlocks,
87 | BackupBgs,
88 | EncryptAlgos,
89 | EncryptPwSalt,
90 | LpfIno,
91 | PrjQuotaInum,
92 | ChecksumSeed,
93 | Reserved,
94 | Checksum,
95 | }
96 |
97 | impl SuperBlock {
98 | pub fn slice(&self) -> SuperBlockSlice {
99 | match self {
100 | SuperBlock::InodesCount => SuperBlockSlice { offset: 0, size: 4 },
101 | SuperBlock::BlocksCountLo => SuperBlockSlice { offset: 4, size: 4 },
102 | SuperBlock::RBlocksCountLo => SuperBlockSlice { offset: 8, size: 4 },
103 | SuperBlock::FreeBlocksCountLo => SuperBlockSlice {
104 | offset: 12,
105 | size: 4,
106 | },
107 | SuperBlock::FreeInodesCount => SuperBlockSlice {
108 | offset: 16,
109 | size: 4,
110 | },
111 | SuperBlock::FirstDataBlock => SuperBlockSlice {
112 | offset: 20,
113 | size: 4,
114 | },
115 | SuperBlock::LogBlockSize => SuperBlockSlice {
116 | offset: 24,
117 | size: 4,
118 | },
119 | SuperBlock::LogClusterSize => SuperBlockSlice {
120 | offset: 28,
121 | size: 4,
122 | },
123 | SuperBlock::BlocksPerGroup => SuperBlockSlice {
124 | offset: 32,
125 | size: 4,
126 | },
127 | SuperBlock::ClustersPerGroup => SuperBlockSlice {
128 | offset: 36,
129 | size: 4,
130 | },
131 | SuperBlock::InodesPerGroup => SuperBlockSlice {
132 | offset: 40,
133 | size: 4,
134 | },
135 | SuperBlock::Mtime => SuperBlockSlice {
136 | offset: 44,
137 | size: 4,
138 | },
139 | SuperBlock::Wtime => SuperBlockSlice {
140 | offset: 48,
141 | size: 4,
142 | },
143 | SuperBlock::MntCount => SuperBlockSlice {
144 | offset: 52,
145 | size: 2,
146 | },
147 | SuperBlock::MaxMntCount => SuperBlockSlice {
148 | offset: 54,
149 | size: 2,
150 | },
151 | SuperBlock::Magic => SuperBlockSlice {
152 | offset: 56,
153 | size: 2,
154 | },
155 | SuperBlock::State => SuperBlockSlice {
156 | offset: 58,
157 | size: 2,
158 | },
159 | SuperBlock::Errors => SuperBlockSlice {
160 | offset: 60,
161 | size: 2,
162 | },
163 | SuperBlock::MinorRevLevel => SuperBlockSlice {
164 | offset: 62,
165 | size: 2,
166 | },
167 | SuperBlock::LastCheck => SuperBlockSlice {
168 | offset: 64,
169 | size: 4,
170 | },
171 | SuperBlock::CheckInterval => SuperBlockSlice {
172 | offset: 68,
173 | size: 4,
174 | },
175 | SuperBlock::CreatorOs => SuperBlockSlice {
176 | offset: 72,
177 | size: 4,
178 | },
179 | SuperBlock::RevLevel => SuperBlockSlice {
180 | offset: 76,
181 | size: 2,
182 | },
183 | SuperBlock::DefResuid => SuperBlockSlice {
184 | offset: 78,
185 | size: 2,
186 | },
187 | SuperBlock::DefResgid => SuperBlockSlice {
188 | offset: 80,
189 | size: 2,
190 | },
191 | SuperBlock::FirstIno => SuperBlockSlice {
192 | offset: 82,
193 | size: 4,
194 | },
195 | SuperBlock::InodeSize => SuperBlockSlice {
196 | offset: 86,
197 | size: 2,
198 | },
199 | SuperBlock::BlockGroupNr => SuperBlockSlice {
200 | offset: 88,
201 | size: 2,
202 | },
203 | SuperBlock::FeatureCompat => SuperBlockSlice {
204 | offset: 90,
205 | size: 4,
206 | },
207 | SuperBlock::FeatureIncompat => SuperBlockSlice {
208 | offset: 94,
209 | size: 4,
210 | },
211 | SuperBlock::FeatureRoCompat => SuperBlockSlice {
212 | offset: 98,
213 | size: 4,
214 | },
215 | SuperBlock::Uuid => SuperBlockSlice {
216 | offset: 102,
217 | size: 16,
218 | },
219 | SuperBlock::VolumeName => SuperBlockSlice {
220 | offset: 118,
221 | size: 16,
222 | },
223 | SuperBlock::LastMounted => SuperBlockSlice {
224 | offset: 134,
225 | size: 4,
226 | },
227 | SuperBlock::AlgorithmUsageBitmap => SuperBlockSlice {
228 | offset: 138,
229 | size: 4,
230 | },
231 | SuperBlock::PreallocBlocks => SuperBlockSlice {
232 | offset: 142,
233 | size: 4,
234 | },
235 | SuperBlock::PreallocDirBlocks => SuperBlockSlice {
236 | offset: 146,
237 | size: 4,
238 | },
239 | SuperBlock::ReservedGdtBlocks => SuperBlockSlice {
240 | offset: 150,
241 | size: 16,
242 | },
243 | SuperBlock::JournalUuid => SuperBlockSlice {
244 | offset: 166,
245 | size: 16,
246 | },
247 | SuperBlock::JournalInum => SuperBlockSlice {
248 | offset: 182,
249 | size: 4,
250 | },
251 | SuperBlock::JournalDev => SuperBlockSlice {
252 | offset: 186,
253 | size: 4,
254 | },
255 | SuperBlock::LastOrphan => SuperBlockSlice {
256 | offset: 190,
257 | size: 4,
258 | },
259 | SuperBlock::HashSeed => SuperBlockSlice {
260 | offset: 194,
261 | size: 8,
262 | },
263 | SuperBlock::DefHashVersion => SuperBlockSlice {
264 | offset: 202,
265 | size: 4,
266 | },
267 | SuperBlock::JnlBackupType => SuperBlockSlice {
268 | offset: 206,
269 | size: 4,
270 | },
271 | SuperBlock::DescSize => SuperBlockSlice {
272 | offset: 210,
273 | size: 4,
274 | },
275 | SuperBlock::DefaultMountOpts => SuperBlockSlice {
276 | offset: 214,
277 | size: 4,
278 | },
279 | SuperBlock::FirstMetaBg => SuperBlockSlice {
280 | offset: 218,
281 | size: 4,
282 | },
283 | SuperBlock::MkfsTime => SuperBlockSlice {
284 | offset: 222,
285 | size: 4,
286 | },
287 | SuperBlock::JnlBlocks => SuperBlockSlice {
288 | offset: 226,
289 | size: 12,
290 | },
291 | SuperBlock::RBlocksCountHi => SuperBlockSlice {
292 | offset: 238,
293 | size: 4,
294 | },
295 | SuperBlock::FreeBlocksCountHi => SuperBlockSlice {
296 | offset: 242,
297 | size: 4,
298 | },
299 | SuperBlock::MinExtraIsize => SuperBlockSlice {
300 | offset: 246,
301 | size: 4,
302 | },
303 | SuperBlock::WantExtraIsize => SuperBlockSlice {
304 | offset: 250,
305 | size: 4,
306 | },
307 | SuperBlock::Flags => SuperBlockSlice {
308 | offset: 254,
309 | size: 4,
310 | },
311 | SuperBlock::RaidStride => SuperBlockSlice {
312 | offset: 258,
313 | size: 4,
314 | },
315 | SuperBlock::MMPInterval => SuperBlockSlice {
316 | offset: 262,
317 | size: 4,
318 | },
319 | SuperBlock::MMPBlock => SuperBlockSlice {
320 | offset: 266,
321 | size: 4,
322 | },
323 | SuperBlock::RaidStripeWidth => SuperBlockSlice {
324 | offset: 270,
325 | size: 4,
326 | },
327 | SuperBlock::LogGroupsPerFlex => SuperBlockSlice {
328 | offset: 274,
329 | size: 4,
330 | },
331 | SuperBlock::ChecksumType => SuperBlockSlice {
332 | offset: 278,
333 | size: 4,
334 | },
335 | SuperBlock::ReservedPad => SuperBlockSlice {
336 | offset: 282,
337 | size: 6,
338 | },
339 | SuperBlock::KbytesWritten => SuperBlockSlice {
340 | offset: 288,
341 | size: 8,
342 | },
343 | SuperBlock::SnapshotInum => SuperBlockSlice {
344 | offset: 296,
345 | size: 4,
346 | },
347 | SuperBlock::SnapshotId => SuperBlockSlice {
348 | offset: 300,
349 | size: 4,
350 | },
351 | SuperBlock::SnapshotRBlocksCount => SuperBlockSlice {
352 | offset: 304,
353 | size: 8,
354 | },
355 | SuperBlock::SnapshotList => SuperBlockSlice {
356 | offset: 312,
357 | size: 8,
358 | },
359 | SuperBlock::ErrorCount => SuperBlockSlice {
360 | offset: 320,
361 | size: 4,
362 | },
363 | SuperBlock::FirstErrorTime => SuperBlockSlice {
364 | offset: 324,
365 | size: 4,
366 | },
367 | SuperBlock::FirstErrorIno => SuperBlockSlice {
368 | offset: 328,
369 | size: 4,
370 | },
371 | SuperBlock::FirstErrorBlock => SuperBlockSlice {
372 | offset: 332,
373 | size: 4,
374 | },
375 | SuperBlock::FirstErrorFunc => SuperBlockSlice {
376 | offset: 336,
377 | size: 4,
378 | },
379 | SuperBlock::FirstErrorLine => SuperBlockSlice {
380 | offset: 340,
381 | size: 4,
382 | },
383 | SuperBlock::LastErrorTime => SuperBlockSlice {
384 | offset: 344,
385 | size: 8,
386 | },
387 | SuperBlock::LastErrorIno => SuperBlockSlice {
388 | offset: 352,
389 | size: 4,
390 | },
391 | SuperBlock::LastErrorLine => SuperBlockSlice {
392 | offset: 364,
393 | size: 4,
394 | },
395 | SuperBlock::LastErrorBlock => SuperBlockSlice {
396 | offset: 356,
397 | size: 4,
398 | },
399 | SuperBlock::LastErrorFunc => SuperBlockSlice {
400 | offset: 360,
401 | size: 4,
402 | },
403 | SuperBlock::MountOpts => SuperBlockSlice {
404 | offset: 368,
405 | size: 64,
406 | },
407 | SuperBlock::UsrQuotaInum => SuperBlockSlice {
408 | offset: 432,
409 | size: 4,
410 | },
411 | SuperBlock::GrpQuotaInum => SuperBlockSlice {
412 | offset: 436,
413 | size: 4,
414 | },
415 | SuperBlock::OverheadBlocks => SuperBlockSlice {
416 | offset: 440,
417 | size: 4,
418 | },
419 | SuperBlock::BackupBgs => SuperBlockSlice {
420 | offset: 444,
421 | size: 6,
422 | },
423 | SuperBlock::EncryptAlgos => SuperBlockSlice {
424 | offset: 450,
425 | size: 4,
426 | },
427 | SuperBlock::EncryptPwSalt => SuperBlockSlice {
428 | offset: 454,
429 | size: 16,
430 | },
431 | SuperBlock::LpfIno => SuperBlockSlice {
432 | offset: 470,
433 | size: 4,
434 | },
435 | SuperBlock::PrjQuotaInum => SuperBlockSlice {
436 | offset: 474,
437 | size: 4,
438 | },
439 | SuperBlock::ChecksumSeed => SuperBlockSlice {
440 | offset: 478,
441 | size: 8,
442 | },
443 | SuperBlock::Reserved => SuperBlockSlice {
444 | offset: 486,
445 | size: 2,
446 | },
447 | SuperBlock::Checksum => SuperBlockSlice {
448 | offset: 488,
449 | size: 4,
450 | },
451 | _ => SuperBlockSlice { offset: 0, size: 0 },
452 | }
453 | }
454 |
455 | #[allow(dead_code)]
456 | pub fn offset(&self) -> usize {
457 | self.slice().offset
458 | }
459 |
460 | #[allow(dead_code)]
461 | pub fn size(&self) -> usize {
462 | self.slice().size
463 | }
464 | }
465 |
466 | #[derive(Debug, Clone, PartialEq, Eq)]
467 | pub struct SuperBlockSlice {
468 | pub offset: usize,
469 | pub size: usize,
470 | }
471 |
472 | #[derive(Debug, Clone, PartialEq, Eq)]
473 | pub struct SuperBlockSnapshot {
474 | pub s_inodes_count: u32,
475 | pub s_blocks_count_lo: u32,
476 | pub s_r_blocks_count_lo: u32,
477 | pub s_free_blocks_count_lo: u32,
478 | pub s_free_inodes_count: u32,
479 | pub s_first_data_block: u32,
480 | pub s_log_block_size: u32,
481 | pub s_log_cluster_size: u32,
482 | pub s_blocks_per_group: u32,
483 | pub s_clusters_per_group: u32,
484 | pub s_inodes_per_group: u32,
485 | pub s_mtime: u32,
486 | pub s_wtime: u32,
487 | pub s_mnt_count: u16,
488 | pub s_max_mnt_count: u16,
489 | pub s_magic: u16,
490 | pub s_state: u16,
491 | pub s_errors: u16,
492 | pub s_minor_rev_level: u16,
493 | pub s_lastcheck: u32,
494 | pub s_checkinterval: u32,
495 | pub s_creator_os: u32,
496 | pub s_rev_level: u32,
497 | pub s_def_resuid: u16,
498 | pub s_def_resgid: u16,
499 | pub s_first_ino: u32,
500 | pub s_inode_size: u16,
501 | pub s_block_group_nr: u16,
502 | pub s_feature_compat: u32,
503 | pub s_feature_incompat: u32,
504 | pub s_feature_ro_compat: u32,
505 | pub s_uuid: [u8; 16],
506 | pub s_volume_name: [char; 16],
507 | pub s_last_mounted: [char; 64],
508 | pub s_algorithm_usage_bitmap: u32,
509 | pub s_prealloc_blocks: u8,
510 | pub s_prealloc_dir_blocks: u8,
511 | pub s_reserved_gdt_blocks: u16,
512 | pub s_journal_uuid: [u8; 16],
513 | pub s_journal_inum: u32,
514 | pub s_journal_dev: u32,
515 | pub s_last_orphan: u32,
516 | pub s_hash_seed: [u32; 4],
517 | pub s_def_hash_version: u8,
518 | pub s_jnl_backup_type: u8,
519 | pub s_desc_size: u16,
520 | pub s_default_mount_opts: u32,
521 | pub s_first_meta_bg: u32,
522 | pub s_mkfs_time: u32,
523 | pub s_jnl_blocks: [u32; 17],
524 | pub s_blocks_count_hi: u32,
525 | pub s_r_blocks_count_hi: u32,
526 | pub s_free_blocks_count_hi: u32,
527 | pub s_min_extra_isize: u16,
528 | pub s_want_extra_isize: u16,
529 | pub s_flags: u32,
530 | pub s_raid_stride: u16,
531 | pub s_mmp_interval: u16,
532 | pub s_mmp_block: u64,
533 | pub s_raid_stripe_width: u32,
534 | pub s_log_groups_per_flex: u8,
535 | pub s_checksum_type: u8,
536 | pub s_reserved_pad: u16,
537 | pub s_kbytes_written: u64,
538 | pub s_snapshot_inum: u32,
539 | pub s_snapshot_id: u32,
540 | pub s_snapshot_r_blocks_count: u64,
541 | pub s_snapshot_list: u32,
542 | pub s_error_count: u32,
543 | pub s_first_error_time: u32,
544 | pub s_first_error_ino: u32,
545 | pub s_first_error_block: u64,
546 | pub s_first_error_func: [u8; 32],
547 | pub s_first_error_line: u32,
548 | pub s_last_error_time: u32,
549 | pub s_last_error_ino: u32,
550 | pub s_last_error_line: u32,
551 | pub s_last_error_block: u64,
552 | pub s_last_error_func: [u8; 32],
553 | pub s_mount_opts: [u8; 64],
554 | pub s_usr_quota_inum: u32,
555 | pub s_grp_quota_inum: u32,
556 | pub s_overhead_blocks: u32,
557 | pub s_backup_bgs: [u32; 2],
558 | pub s_encrypt_algos: [u8; 4],
559 | pub s_encrypt_pw_salt: [u8; 16],
560 | pub s_lpf_ino: u32,
561 | pub s_prj_quota_inum: u32,
562 | pub s_checksum_seed: u32,
563 | pub s_reserved: [u32; 98],
564 | pub s_checksum: u32,
565 | }
566 |
--------------------------------------------------------------------------------
/canicula-kernel/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "canicula-kernel"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [[bin]]
7 | name = "canicula-kernel"
8 | path = "src/main.rs"
9 |
10 | [dependencies]
11 | log = "0.4.27"
12 | spin = "0.10.0"
13 | bootloader_api = "0.11.8"
14 | noto-sans-mono-bitmap = { version = "0.3.1", features = [ "font_weights_all", "raster_heights_all"] }
15 |
16 | canicula-common = { path = "../canicula-common" }
17 |
18 | [target.x86_64-unknown-none.dependencies]
19 | aml = "0.16.4"
20 | acpi = "5.2.0"
21 | x86 = "0.52.0"
22 | nostd = "0.1.4"
23 | x2apic = "0.5.0"
24 | x86_64 = "0.15.2"
25 | uart_16550 = "0.3.2"
26 | png-decoder = "0.1.1"
27 | conquer-once = { version = "0.4.0", default-features = false }
28 | lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
29 | linked_list_allocator = "0.10.5"
30 |
31 | [target.aarch64-unknown-none.dependencies]
32 |
33 | [target.riscv64gc-unknown-none-elf.dependencies]
34 | sbi-rt = { version = "0.0.3", features = ["legacy"] }
35 | riscv = "0.13.0"
--------------------------------------------------------------------------------
/canicula-kernel/aarch64-unknown-none.json:
--------------------------------------------------------------------------------
1 | {
2 | "arch": "aarch64-unknown-none",
3 | "crt-objects-fallback": "false",
4 | "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
5 | "disable-redzone": true,
6 | "features": "+v8a,+strict-align,+neon,+fp-armv8",
7 | "linker": "rust-lld",
8 | "linker-flavor": "gnu-lld",
9 | "llvm-target": "aarch64-unknown-none",
10 | "max-atomic-width": 128,
11 | "metadata": {
12 | "description": "Bare ARM64, hardfloat",
13 | "host_tools": false,
14 | "std": false,
15 | "tier": 2
16 | },
17 | "panic-strategy": "abort",
18 | "pre-link-args": {
19 | "gnu": ["--fix-cortex-a53-843419"],
20 | "gnu-lld": ["--fix-cortex-a53-843419"],
21 | "ld.lld": ["-Tcanicula-kernel/src/linker/aarch64-linker.ld", "--strip-all"]
22 | },
23 | "relocation-model": "static",
24 | "stack-probes": {
25 | "kind": "inline"
26 | },
27 | "supported-sanitizers": [
28 | "kcfi",
29 | "kernel-address"
30 | ],
31 | "target-pointer-width": "64"
32 | }
33 |
--------------------------------------------------------------------------------
/canicula-kernel/riscv64gc-unknown-none-elf.json:
--------------------------------------------------------------------------------
1 | {
2 | "arch": "riscv64",
3 | "code-model": "medium",
4 | "cpu": "generic-rv64",
5 | "crt-objects-fallback": "false",
6 | "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
7 | "eh-frame-header": false,
8 | "emit-debug-gdb-scripts": false,
9 | "features": "+m,+a,+f,+d,+c",
10 | "linker": "rust-lld",
11 | "linker-flavor": "gnu-lld",
12 | "llvm-abiname": "lp64d",
13 | "llvm-target": "riscv64",
14 | "max-atomic-width": 64,
15 | "metadata": {
16 | "description": "Bare RISC-V (RV64IMAFDC ISA)",
17 | "host_tools": false,
18 | "std": false,
19 | "tier": 2
20 | },
21 | "panic-strategy": "abort",
22 | "relocation-model": "static",
23 | "supported-sanitizers": [
24 | "shadow-call-stack",
25 | "kernel-address"
26 | ],
27 | "target-pointer-width": "64",
28 | "pre-link-args": {
29 | "ld.lld": ["-Tcanicula-kernel/src/linker/riscv64-linker.ld"]
30 | }
31 | }
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/aarch64/mod.rs:
--------------------------------------------------------------------------------
1 | use core::panic::PanicInfo;
2 |
3 | pub fn entry() -> ! {
4 | loop {}
5 | }
6 |
7 | #[panic_handler]
8 | fn panic(_info: &PanicInfo) -> ! {
9 | loop {}
10 | }
11 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/mod.rs:
--------------------------------------------------------------------------------
1 | #[cfg(target_arch = "aarch64")]
2 | #[path = "aarch64/mod.rs"]
3 | pub mod aarch;
4 | #[cfg(target_arch = "riscv64")]
5 | #[path = "riscv64/mod.rs"]
6 | pub mod riscv;
7 | #[cfg(target_arch = "x86_64")]
8 | #[path = "x86/mod.rs"]
9 | pub mod x86;
10 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/riscv64/console.rs:
--------------------------------------------------------------------------------
1 | use super::sbi::console_write_byte;
2 | use core::fmt::{self, Write};
3 |
4 | struct Stdout;
5 |
6 | impl Write for Stdout {
7 | fn write_str(&mut self, s: &str) -> fmt::Result {
8 | for c in s.chars() {
9 | console_write_byte(c as usize);
10 | }
11 | Ok(())
12 | }
13 | }
14 |
15 | pub fn print(args: fmt::Arguments) {
16 | Stdout.write_fmt(args).unwrap();
17 | }
18 |
19 | #[macro_export]
20 | macro_rules! print {
21 | ($fmt: literal $(, $($arg: tt)+)?) => {
22 | $crate::console::print(format_args!($fmt $(, $($arg)+)?))
23 | }
24 | }
25 |
26 | #[macro_export]
27 | macro_rules! println {
28 | ($fmt: literal $(, $($arg: tt)+)?) => {
29 | $crate::arch::riscv::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?))
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/riscv64/entry.asm:
--------------------------------------------------------------------------------
1 | .section .text.entry
2 | .globl _start
3 | _start:
4 | la sp, boot_stack_top
5 | call kernel
6 |
7 | .section .bss.stack
8 | .globl boot_stack_lower_bound
9 | boot_stack_lower_bound:
10 | .space 4096 * 16
11 | .globl boot_stack_top
12 | boot_stack_top:
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/riscv64/logging.rs:
--------------------------------------------------------------------------------
1 | use crate::println;
2 | use log::{Level, LevelFilter, Log, Metadata, Record};
3 |
4 | struct SimpleLogger;
5 |
6 | impl Log for SimpleLogger {
7 | fn enabled(&self, _metadata: &Metadata) -> bool {
8 | true
9 | }
10 | fn log(&self, record: &Record) {
11 | if !self.enabled(record.metadata()) {
12 | return;
13 | }
14 | let color = match record.level() {
15 | // Red
16 | Level::Error => 31,
17 | // BrightYellow
18 | Level::Warn => 93,
19 | // Blue
20 | Level::Info => 34,
21 | // Green
22 | Level::Debug => 32,
23 | // BrightBlack
24 | Level::Trace => 90,
25 | };
26 | println!(
27 | "\u{1B}[{}m[{:>5}] {}\u{1B}[0m",
28 | color,
29 | record.level(),
30 | record.args(),
31 | );
32 | }
33 | fn flush(&self) {}
34 | }
35 |
36 | pub fn init() {
37 | static LOGGER: SimpleLogger = SimpleLogger;
38 | log::set_logger(&LOGGER).unwrap();
39 | log::set_max_level(match option_env!("log_level") {
40 | Some("ERROR") => LevelFilter::Error,
41 | Some("WARN") => LevelFilter::Warn,
42 | Some("INFO") => LevelFilter::Info,
43 | Some("DEBUG") => LevelFilter::Debug,
44 | Some("TRACE") => LevelFilter::Trace,
45 | _ => LevelFilter::Off,
46 | });
47 | }
48 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/riscv64/mod.rs:
--------------------------------------------------------------------------------
1 | use core::arch::global_asm;
2 | use log::*;
3 | use qemu::QEMUExit;
4 | use qemu::QEMU_EXIT_HANDLE;
5 |
6 | use crate::println;
7 |
8 | #[macro_use]
9 | mod panic;
10 | mod console;
11 | mod logging;
12 | mod qemu;
13 | mod sbi;
14 |
15 | pub fn clear_bss() {
16 | extern "C" {
17 | fn sbss();
18 | fn ebss();
19 | }
20 | (sbss as usize..ebss as usize).for_each(|a| unsafe { (a as *mut u8).write_volatile(0) });
21 | }
22 |
23 | global_asm!(include_str!("entry.asm"));
24 |
25 | pub fn entry() -> ! {
26 | extern "C" {
27 | // begin addr of text segment
28 | fn stext();
29 | fn etext();
30 | // start addr of Read-Only data segment
31 | fn srodata();
32 | fn erodata();
33 | // start addr of data segment
34 | fn sdata();
35 | fn edata();
36 | // start addr of BSS segment
37 | fn sbss();
38 | fn ebss();
39 | // stack lower bound
40 | fn boot_stack_lower_bound();
41 | fn boot_stack_top();
42 | }
43 | clear_bss();
44 | logging::init();
45 | println!("[kernel] Hello, world!");
46 | debug!(
47 | "[kernel] .text [{:#x}, {:#x})",
48 | stext as usize, etext as usize
49 | );
50 | debug!(
51 | "[kernel] .rodata [{:#x}, {:#x})",
52 | srodata as usize, erodata as usize
53 | );
54 | debug!(
55 | "[kernel] .data [{:#x}, {:#x})",
56 | sdata as usize, edata as usize
57 | );
58 | debug!(
59 | "[kernel] boot_stack top=bottom={:#x}, lower_bound={:#x}",
60 | boot_stack_top as usize, boot_stack_lower_bound as usize
61 | );
62 | debug!("[kernel] .bss [{:#x}, {:#x})", sbss as usize, ebss as usize);
63 |
64 | QEMU_EXIT_HANDLE.exit_success();
65 | }
66 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/riscv64/panic.rs:
--------------------------------------------------------------------------------
1 | use core::panic::PanicInfo;
2 |
3 | use crate::println;
4 |
5 | use super::sbi::shutdown;
6 |
7 | #[panic_handler]
8 | fn panic(info: &PanicInfo) -> ! {
9 | if let Some(location) = info.location() {
10 | println!(
11 | "Panicked at {}:{} {}",
12 | location.file(),
13 | location.line(),
14 | info.message()
15 | );
16 | } else {
17 | println!("Panicked: {}", info.message());
18 | }
19 |
20 | shutdown(true);
21 | }
22 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/riscv64/qemu.rs:
--------------------------------------------------------------------------------
1 | //ref:: https://github.com/andre-richter/qemu-exit
2 | use core::arch::asm;
3 |
4 | const VIRT_TEST: u64 = 0x100000;
5 | const EXIT_SUCCESS: u32 = 0x5555; // Equals `exit(0)`. qemu successful exit
6 | const EXIT_FAILURE_FLAG: u32 = 0x3333;
7 | const EXIT_FAILURE: u32 = exit_code_encode(1); // Equals `exit(1)`. qemu failed exit
8 | const EXIT_RESET: u32 = 0x7777; // qemu reset
9 |
10 | pub trait QEMUExit {
11 | /// Exit with specified return code.
12 | ///
13 | /// Note: For `X86`, code is binary-OR'ed with `0x1` inside QEMU.
14 | fn exit(&self, code: u32) -> !;
15 |
16 | /// Exit QEMU using `EXIT_SUCCESS`, aka `0`, if possible.
17 | ///
18 | /// Note: Not possible for `X86`.
19 | fn exit_success(&self) -> !;
20 |
21 | /// Exit QEMU using `EXIT_FAILURE`, aka `1`.
22 | fn exit_failure(&self) -> !;
23 | }
24 |
25 | /// RISCV64 configuration
26 | pub struct RISCV64 {
27 | /// Address of the sifive_test mapped device.
28 | addr: u64,
29 | }
30 |
31 | /// Encode the exit code using EXIT_FAILURE_FLAG.
32 | const fn exit_code_encode(code: u32) -> u32 {
33 | (code << 16) | EXIT_FAILURE_FLAG
34 | }
35 |
36 | impl RISCV64 {
37 | /// Create an instance.
38 | pub const fn new(addr: u64) -> Self {
39 | RISCV64 { addr }
40 | }
41 | }
42 |
43 | impl QEMUExit for RISCV64 {
44 | /// Exit qemu with specified exit code.
45 | fn exit(&self, code: u32) -> ! {
46 | // If code is not a special value, we need to encode it with EXIT_FAILURE_FLAG.
47 | let code_new = match code {
48 | EXIT_SUCCESS | EXIT_FAILURE | EXIT_RESET => code,
49 | _ => exit_code_encode(code),
50 | };
51 |
52 | unsafe {
53 | asm!(
54 | "sw {0}, 0({1})",
55 | in(reg)code_new, in(reg)self.addr
56 | );
57 |
58 | // For the case that the QEMU exit attempt did not work, transition into an infinite
59 | // loop. Calling `panic!()` here is unfeasible, since there is a good chance
60 | // this function here is the last expression in the `panic!()` handler
61 | // itself. This prevents a possible infinite loop.
62 | loop {
63 | asm!("wfi", options(nomem, nostack));
64 | }
65 | }
66 | }
67 |
68 | fn exit_success(&self) -> ! {
69 | self.exit(EXIT_SUCCESS);
70 | }
71 |
72 | fn exit_failure(&self) -> ! {
73 | self.exit(EXIT_FAILURE);
74 | }
75 | }
76 |
77 | pub const QEMU_EXIT_HANDLE: RISCV64 = RISCV64::new(VIRT_TEST);
78 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/riscv64/sbi.rs:
--------------------------------------------------------------------------------
1 | use sbi_rt::{system_reset, NoReason, Shutdown, SystemFailure};
2 |
3 | pub fn console_write_byte(c: usize) {
4 | #[allow(deprecated)]
5 | sbi_rt::legacy::console_putchar(c);
6 | }
7 |
8 | pub fn shutdown(failure: bool) -> ! {
9 | if !failure {
10 | system_reset(Shutdown, NoReason);
11 | } else {
12 | system_reset(Shutdown, SystemFailure);
13 | }
14 | unreachable!()
15 | }
16 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/x86/acpi/handler.rs:
--------------------------------------------------------------------------------
1 | use core::ptr::NonNull;
2 |
3 | use acpi::PhysicalMapping;
4 | use x86_64::{instructions::port::Port, PhysAddr};
5 |
6 | #[derive(Debug, Clone, Copy)]
7 | pub struct AcpiHandler;
8 |
9 | impl acpi::AcpiHandler for AcpiHandler {
10 | unsafe fn map_physical_region(
11 | &self,
12 | physical_address: usize,
13 | size: usize,
14 | ) -> acpi::PhysicalMapping {
15 | let phys_addr = PhysAddr::new(physical_address as u64);
16 | let virt_addr = crate::arch::x86::memory::physical_to_virtual(phys_addr);
17 | let ptr = NonNull::new(virt_addr.as_mut_ptr()).unwrap();
18 | PhysicalMapping::new(physical_address, ptr, size, size, Self)
19 | }
20 |
21 | fn unmap_physical_region(_region: &acpi::PhysicalMapping) {}
22 | }
23 |
24 | #[derive(Debug, Clone, Copy)]
25 | pub(crate) struct AmlHandler;
26 |
27 | impl aml::Handler for AmlHandler {
28 | fn read_u8(&self, address: usize) -> u8 {
29 | read_addr::(address)
30 | }
31 |
32 | fn read_u16(&self, address: usize) -> u16 {
33 | read_addr::(address)
34 | }
35 |
36 | fn read_u32(&self, address: usize) -> u32 {
37 | read_addr::(address)
38 | }
39 |
40 | fn read_u64(&self, address: usize) -> u64 {
41 | read_addr::(address)
42 | }
43 |
44 | fn write_u8(&mut self, address: usize, value: u8) {
45 | write_addr::(address, value)
46 | }
47 |
48 | fn write_u16(&mut self, address: usize, value: u16) {
49 | write_addr::(address, value)
50 | }
51 |
52 | fn write_u32(&mut self, address: usize, value: u32) {
53 | write_addr::(address, value)
54 | }
55 |
56 | fn write_u64(&mut self, address: usize, value: u64) {
57 | write_addr::(address, value)
58 | }
59 |
60 | // ==== IO Port Read ====
61 | fn read_io_u8(&self, port: u16) -> u8 {
62 | unsafe { Port::new(port).read() }
63 | }
64 |
65 | fn read_io_u16(&self, port: u16) -> u16 {
66 | unsafe { Port::new(port).read() }
67 | }
68 |
69 | fn read_io_u32(&self, port: u16) -> u32 {
70 | unsafe { Port::new(port).read() }
71 | }
72 |
73 | fn write_io_u8(&self, port: u16, value: u8) {
74 | unsafe { Port::new(port).write(value) }
75 | }
76 |
77 | fn write_io_u16(&self, port: u16, value: u16) {
78 | unsafe { Port::new(port).write(value) }
79 | }
80 |
81 | fn write_io_u32(&self, port: u16, value: u32) {
82 | unsafe { Port::new(port).write(value) }
83 | }
84 |
85 | fn read_pci_u8(&self, seg: u16, bus: u8, dev: u8, func: u8, offset: u16) -> u8 {
86 | pci_config_read_u32(seg, bus, dev, func, offset) as u8
87 | }
88 |
89 | fn read_pci_u16(&self, seg: u16, bus: u8, dev: u8, func: u8, offset: u16) -> u16 {
90 | pci_config_read_u32(seg, bus, dev, func, offset) as u16
91 | }
92 |
93 | fn read_pci_u32(&self, seg: u16, bus: u8, dev: u8, func: u8, offset: u16) -> u32 {
94 | pci_config_read_u32(seg, bus, dev, func, offset)
95 | }
96 |
97 | fn write_pci_u8(&self, seg: u16, bus: u8, dev: u8, func: u8, offset: u16, value: u8) {
98 | let old = pci_config_read_u32(seg, bus, dev, func, offset);
99 | let shift = ((offset & 3) * 8) as u32;
100 | let mask = !(0xFF << shift);
101 | let new = (old & mask) | ((value as u32) << shift);
102 | pci_config_write_u32(seg, bus, dev, func, offset, new);
103 | }
104 |
105 | fn write_pci_u16(&self, seg: u16, bus: u8, dev: u8, func: u8, offset: u16, value: u16) {
106 | let old = pci_config_read_u32(seg, bus, dev, func, offset);
107 | let shift = ((offset & 2) * 8) as u32;
108 | let mask = !(0xFFFF << shift);
109 | let new = (old & mask) | ((value as u32) << shift);
110 | pci_config_write_u32(seg, bus, dev, func, offset, new);
111 | }
112 |
113 | fn write_pci_u32(&self, seg: u16, bus: u8, dev: u8, func: u8, offset: u16, value: u32) {
114 | pci_config_write_u32(seg, bus, dev, func, offset, value);
115 | }
116 | }
117 |
118 | fn read_addr(addr: usize) -> T {
119 | let virt = unsafe { crate::arch::x86::memory::physical_to_virtual(PhysAddr::new(addr as u64)) };
120 | unsafe { *virt.as_ptr::() }
121 | }
122 |
123 | fn write_addr(addr: usize, value: T) {
124 | let virt = unsafe { crate::arch::x86::memory::physical_to_virtual(PhysAddr::new(addr as u64)) };
125 | unsafe { *virt.as_mut_ptr::() = value };
126 | }
127 |
128 | fn pci_config_address(bus: u8, dev: u8, func: u8, offset: u16) -> u32 {
129 | (1 << 31)
130 | | ((bus as u32) << 16)
131 | | ((dev as u32) << 11)
132 | | ((func as u32) << 8)
133 | | ((offset as u32) & 0xFC)
134 | }
135 |
136 | fn pci_config_read_u32(_seg: u16, bus: u8, dev: u8, func: u8, offset: u16) -> u32 {
137 | unsafe {
138 | let addr = pci_config_address(bus, dev, func, offset);
139 | Port::new(0xCF8).write(addr);
140 | Port::new(0xCFC).read()
141 | }
142 | }
143 |
144 | fn pci_config_write_u32(_seg: u16, bus: u8, dev: u8, func: u8, offset: u16, value: u32) {
145 | unsafe {
146 | let addr = pci_config_address(bus, dev, func, offset);
147 | Port::new(0xCF8).write(addr);
148 | Port::new(0xCFC).write(value);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/x86/acpi/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod handler;
2 |
3 | use acpi::{fadt::Fadt, AcpiTables};
4 | use aml::{AmlContext, AmlName, AmlValue, DebugVerbosity};
5 | use lazy_static::lazy_static;
6 | use log::debug;
7 | use spin::Mutex;
8 | use x86_64::{instructions::port::Port, PhysAddr};
9 |
10 | extern crate alloc;
11 | use alloc::boxed::Box;
12 |
13 | #[derive(Debug, Clone, Copy)]
14 | pub struct AcpiShutdown {
15 | pub pm1a_control_block: u64,
16 | pub slp_typ_a: u16,
17 | pub slp_len: u16,
18 | }
19 |
20 | lazy_static! {
21 | pub static ref ACPI_SHUTDOWN: Mutex = Mutex::new(AcpiShutdown {
22 | pm1a_control_block: 0,
23 | slp_typ_a: 0,
24 | slp_len: 0,
25 | });
26 | }
27 |
28 | pub fn init(rsdp_addr: &u64) {
29 | let tables = unsafe {
30 | AcpiTables::from_rsdp(
31 | crate::arch::x86::acpi::handler::AcpiHandler,
32 | *rsdp_addr as usize,
33 | )
34 | .unwrap()
35 | };
36 |
37 | let dsdt = tables
38 | .dsdt()
39 | .unwrap_or_else(|_| panic!("Failed to get DSDT table"));
40 | let fadt = tables
41 | .find_table::()
42 | .unwrap_or_else(|_| panic!("Failed to get FADT table"));
43 |
44 | let pm1a_control_block = fadt.pm1a_control_block().unwrap();
45 | let slp_typ_a = {
46 | let table = unsafe {
47 | let ptr =
48 | crate::arch::x86::memory::physical_to_virtual(PhysAddr::new(dsdt.address as u64));
49 | core::slice::from_raw_parts(ptr.as_ptr(), dsdt.length as usize)
50 | };
51 |
52 | let handler = Box::new(crate::arch::x86::acpi::handler::AmlHandler);
53 | let mut aml = AmlContext::new(handler, DebugVerbosity::None);
54 |
55 | let name = AmlName::from_str("\\_S5").unwrap();
56 | aml.parse_table(table).unwrap();
57 |
58 | let s5 = match aml.namespace.get_by_path(&name).unwrap() {
59 | AmlValue::Package(p) => p,
60 | _ => panic!("\\_S5 is not a Package"),
61 | };
62 |
63 | let value = match s5[0] {
64 | AmlValue::Integer(v) => v as u16,
65 | _ => panic!("\\_S5[0] is not an Integer"),
66 | };
67 |
68 | value
69 | };
70 | let slp_len = 1 << 13;
71 |
72 | *ACPI_SHUTDOWN.lock() = AcpiShutdown {
73 | pm1a_control_block: pm1a_control_block.address,
74 | slp_typ_a,
75 | slp_len,
76 | };
77 |
78 | debug!("PM1A Control Block: {:#x}", pm1a_control_block.address);
79 | debug!("S5 Sleep Type: {:#x}", slp_typ_a);
80 | debug!("S5 Sleep Length: {:#x}", slp_len);
81 | }
82 |
83 | pub fn shutdown() {
84 | let pm1a_control_block = ACPI_SHUTDOWN.lock().pm1a_control_block;
85 | let slp_typ_a = ACPI_SHUTDOWN.lock().slp_typ_a;
86 | let slp_len = ACPI_SHUTDOWN.lock().slp_len;
87 |
88 | unsafe {
89 | let mut port: Port = Port::new(pm1a_control_block as u16);
90 | port.write(slp_typ_a | slp_len);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/x86/apic.rs:
--------------------------------------------------------------------------------
1 | use acpi::{AcpiTables, InterruptModel};
2 | use conquer_once::spin::OnceCell;
3 | use log::debug;
4 | use spin::{Mutex, Once};
5 |
6 | extern crate alloc;
7 | use alloc::vec::Vec;
8 |
9 | use x2apic::{
10 | ioapic::{IoApic, IrqMode, RedirectionTableEntry},
11 | lapic::{LocalApic, LocalApicBuilder},
12 | };
13 | use x86_64::{instructions::port::Port, PhysAddr};
14 |
15 | pub static IOAPIC: Once>> = Once::new();
16 | pub static mut LAPIC: OnceCell> = OnceCell::uninit();
17 |
18 | pub struct IOApic {
19 | addr: u64,
20 | ioapic: Option,
21 | }
22 |
23 | pub struct LApic {
24 | addr: u64,
25 | lapic: Option,
26 | }
27 |
28 | impl IOApic {
29 | pub fn new(addr: u64) -> Self {
30 | Self {
31 | addr: unsafe {
32 | crate::arch::x86::memory::physical_to_virtual(PhysAddr::new(addr)).as_u64()
33 | },
34 | ioapic: None,
35 | }
36 | }
37 |
38 | pub fn init(&mut self) {
39 | debug!("Initializing IOAPIC");
40 | self.ioapic = unsafe { Some(IoApic::new(self.addr)) };
41 | debug!("IOAPIC initialized");
42 | }
43 |
44 | #[allow(clippy::missing_safety_doc)]
45 | pub unsafe fn enable(&mut self) {
46 | if let Some(ioapic) = self.ioapic.as_mut() {
47 | ioapic.init(32);
48 | let mut entry = RedirectionTableEntry::default();
49 | entry.set_mode(IrqMode::Fixed);
50 | entry.set_vector(33);
51 | entry.set_dest(0);
52 |
53 | ioapic.set_table_entry(1, entry);
54 | ioapic.enable_irq(1);
55 | }
56 | }
57 |
58 | pub fn get_ioapic(&self) -> Option<&IoApic> {
59 | self.ioapic.as_ref()
60 | }
61 | }
62 |
63 | impl LApic {
64 | pub fn new(addr: u64) -> Self {
65 | Self {
66 | addr: unsafe {
67 | crate::arch::x86::memory::physical_to_virtual(PhysAddr::new(addr)).as_u64()
68 | },
69 | lapic: None,
70 | }
71 | }
72 |
73 | pub fn init(&mut self) {
74 | unsafe {
75 | let mut cmd_8259a = Port::::new(0x20);
76 | let mut data_8259a = Port::::new(0x21);
77 | let mut cmd_8259b = Port::::new(0xa0);
78 | let mut data_8259b = Port::::new(0xa1);
79 |
80 | let mut spin_port = Port::::new(0x80);
81 | let mut spin = || spin_port.write(0);
82 |
83 | cmd_8259a.write(0x11);
84 | cmd_8259b.write(0x11);
85 | spin();
86 |
87 | data_8259a.write(0xf8);
88 | data_8259b.write(0xff);
89 | spin();
90 |
91 | data_8259a.write(0b100);
92 | spin();
93 |
94 | data_8259b.write(0b10);
95 | spin();
96 |
97 | data_8259a.write(0x1);
98 | data_8259b.write(0x1);
99 | spin();
100 |
101 | data_8259a.write(u8::MAX);
102 | data_8259b.write(u8::MAX);
103 | }
104 |
105 | self.lapic = LocalApicBuilder::default()
106 | .timer_vector(32)
107 | .error_vector(51)
108 | .spurious_vector(0xff)
109 | .set_xapic_base(self.addr)
110 | .build()
111 | .ok();
112 | }
113 |
114 | pub fn enable(&mut self) {
115 | unsafe {
116 | self.lapic.as_mut().unwrap().enable();
117 | }
118 | }
119 |
120 | pub fn end_interrupts(&mut self) {
121 | unsafe {
122 | self.lapic.as_mut().unwrap().end_of_interrupt();
123 | }
124 | }
125 | }
126 |
127 | #[allow(static_mut_refs)]
128 | pub fn init_lapic(lapic_addr: u64) {
129 | unsafe {
130 | LAPIC.init_once(|| Mutex::new(LApic::new(lapic_addr)));
131 | LAPIC.get().unwrap().lock().init();
132 | }
133 | }
134 |
135 | pub fn init_ioapic(ioapic_addr: u64) {
136 | IOAPIC.call_once(|| Mutex::new(alloc::vec![IOApic::new(ioapic_addr)]));
137 |
138 | let mut ioapic_lock = IOAPIC.get().unwrap().lock();
139 | ioapic_lock.push(IOApic::new(ioapic_addr));
140 | }
141 |
142 | pub fn init(rsdp_addr: &u64) {
143 | let tables = unsafe {
144 | AcpiTables::from_rsdp(
145 | crate::arch::x86::acpi::handler::AcpiHandler,
146 | *rsdp_addr as usize,
147 | )
148 | .unwrap()
149 | };
150 | let platform_info = tables.platform_info().unwrap();
151 | let interrupt_model = platform_info.interrupt_model;
152 |
153 | debug!("Interrupt Model: {:?}", interrupt_model);
154 |
155 | if let InterruptModel::Apic(apic) = interrupt_model {
156 | let lapic_physical_address: u64 = apic.local_apic_address;
157 | init_lapic(lapic_physical_address);
158 | for i in apic.io_apics.iter() {
159 | init_ioapic(i.address as u64);
160 | debug!("IO Pushed: {:?}", i);
161 | }
162 |
163 | unsafe {
164 | for ioapic in IOAPIC.get().unwrap().lock().iter_mut() {
165 | ioapic.init();
166 | ioapic.enable();
167 | debug!("IO Enabled: {:?}", ioapic.get_ioapic());
168 | }
169 | }
170 |
171 | #[allow(static_mut_refs)]
172 | unsafe {
173 | LAPIC.get().unwrap().lock().enable();
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/x86/bga.rs:
--------------------------------------------------------------------------------
1 | #![allow(dead_code)]
2 |
3 | use x86_64::instructions::port::Port;
4 |
5 | const VBE_DISPI_IOPORT_INDEX: u16 = 0x01CE;
6 | const VBE_DISPI_IOPORT_DATA: u16 = 0x01CF;
7 |
8 | const VBE_DISPI_INDEX_ID: u16 = 0x00;
9 | const VBE_DISPI_INDEX_XRES: u16 = 0x01;
10 | const VBE_DISPI_INDEX_YRES: u16 = 0x02;
11 | const VBE_DISPI_INDEX_BPP: u16 = 0x03;
12 | const VBE_DISPI_INDEX_ENABLE: u16 = 0x04;
13 | const VBE_DISPI_INDEX_BANK: u16 = 0x05;
14 | const VBE_DISPI_INDEX_VIRT_WIDTH: u16 = 0x06;
15 | const VBE_DISPI_INDEX_VIRT_HEIGHT: u16 = 0x07;
16 | const VBE_DISPI_INDEX_X_OFFSET: u16 = 0x08;
17 | const VBE_DISPI_INDEX_Y_OFFSET: u16 = 0x09;
18 |
19 | const VBE_DISPI_ID5: u16 = 0xB0C5;
20 | const VBE_DISPI_DISABLED: u16 = 0x00;
21 | const VBE_DISPI_ENABLED: u16 = 0x01;
22 | const VBE_DISPI_LFB_ENABLED: u16 = 0x02;
23 | const VBE_DISPI_NOCLEARMEM: u16 = 0x04;
24 |
25 | pub const VBE_DISPI_BPP_4: u16 = 0x04;
26 | pub const VBE_DISPI_BPP_8: u16 = 0x08;
27 | pub const VBE_DISPI_BPP_15: u16 = 0x0F;
28 | pub const VBE_DISPI_BPP_16: u16 = 0x10;
29 | pub const VBE_DISPI_BPP_24: u16 = 0x18;
30 | pub const VBE_DISPI_BPP_32: u16 = 0x20;
31 |
32 | pub fn bga_write_register(index_value: u16, data_value: u16) {
33 | let mut index_port = Port::::new(VBE_DISPI_IOPORT_INDEX);
34 | let mut data_port = Port::::new(VBE_DISPI_IOPORT_DATA);
35 | unsafe {
36 | index_port.write(index_value);
37 | data_port.write(data_value);
38 | }
39 | }
40 |
41 | pub fn bga_read_register(index_value: u16) -> u16 {
42 | let mut index_port = Port::::new(VBE_DISPI_IOPORT_INDEX);
43 | let mut data_port = Port::::new(VBE_DISPI_IOPORT_DATA);
44 | unsafe {
45 | index_port.write(index_value);
46 | data_port.read()
47 | }
48 | }
49 |
50 | pub fn bga_is_available() -> bool {
51 | bga_read_register(VBE_DISPI_INDEX_ID) == VBE_DISPI_ID5
52 | }
53 |
54 | pub fn bga_set_video_mode(
55 | width: u32,
56 | height: u32,
57 | bit_depth: u32,
58 | use_linear_frame_buffer: bool,
59 | clear_video_memory: bool,
60 | ) {
61 | bga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
62 |
63 | bga_write_register(VBE_DISPI_INDEX_XRES, width as u16);
64 | bga_write_register(VBE_DISPI_INDEX_YRES, height as u16);
65 | bga_write_register(VBE_DISPI_INDEX_BPP, bit_depth as u16);
66 |
67 | let mut enable_value = VBE_DISPI_ENABLED;
68 | if use_linear_frame_buffer {
69 | enable_value |= VBE_DISPI_LFB_ENABLED;
70 | }
71 | if !clear_video_memory {
72 | enable_value |= VBE_DISPI_NOCLEARMEM;
73 | }
74 | bga_write_register(VBE_DISPI_INDEX_ENABLE, enable_value);
75 | }
76 |
77 | pub fn bga_set_bank(bank_number: u16) {
78 | bga_write_register(VBE_DISPI_INDEX_BANK, bank_number);
79 | }
80 |
--------------------------------------------------------------------------------
/canicula-kernel/src/arch/x86/console.rs:
--------------------------------------------------------------------------------
1 | use core::fmt::Write;
2 |
3 | use bootloader_api::info::FrameBuffer;
4 |
5 | use lazy_static::lazy_static;
6 | use noto_sans_mono_bitmap::get_raster;
7 | use noto_sans_mono_bitmap::FontWeight;
8 | use noto_sans_mono_bitmap::RasterHeight;
9 | use spin::Mutex;
10 | use x86_64::instructions::interrupts;
11 |
12 | lazy_static! {
13 | pub static ref CONSOLE: Mutex