forked from AbleOS/ableos
Rewrote RepBuild
This commit is contained in:
parent
8d640b6a9b
commit
b802732acf
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,8 +1 @@
|
|||
target/
|
||||
.gdb_history
|
||||
!*/.gitkeep
|
||||
__pycache__/
|
||||
debug.log
|
||||
/disk/
|
||||
/limine/
|
||||
/disk.img
|
||||
|
|
5
.gitmodules
vendored
Normal file
5
.gitmodules
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
[submodule "limine"]
|
||||
path = limine
|
||||
url = https://github.com/limine-bootloader/limine.git
|
||||
branch = v4.x-branch-binary
|
||||
shallow = true
|
976
Cargo.lock
generated
976
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,4 +0,0 @@
|
|||
# Base Root Filesystem
|
||||
|
||||
This is the base root filesystem for ableOS. It's used by tepbuild while
|
||||
building the disk image.
|
Binary file not shown.
|
@ -1,7 +0,0 @@
|
|||
[logging]
|
||||
enabled = true
|
||||
level = "Trace"
|
||||
log_to_serial = true
|
||||
log_to_vterm = false
|
||||
filter = ["ableos::ps2_mouse", "ableos::vterm", "ableos::devices::pci"]
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -1,252 +0,0 @@
|
|||
# Able doesn't have a full keyboard
|
||||
0-NONE
|
||||
1-
|
||||
2-
|
||||
3-BACKSPACE
|
||||
4-
|
||||
5-
|
||||
6-
|
||||
7-
|
||||
8-
|
||||
9-TAB
|
||||
10-
|
||||
11-
|
||||
12-
|
||||
13-ENTER
|
||||
14-
|
||||
15-
|
||||
16-SHIFT
|
||||
17-CONTROL
|
||||
18-ALT
|
||||
19-PAUSE
|
||||
20-CAPS_LOCK
|
||||
21-
|
||||
22-
|
||||
23-
|
||||
24-
|
||||
25-
|
||||
26-
|
||||
27-
|
||||
28-
|
||||
29-
|
||||
30-
|
||||
31-
|
||||
32-SPACE
|
||||
33-PAGE_UP
|
||||
34-PAGE_DOWN
|
||||
35-END
|
||||
36-HOME
|
||||
37-ARROW_LEFT
|
||||
38-ARROW_UP
|
||||
39-ARROW_RIGHT
|
||||
40-ARROW_DOWN
|
||||
41-
|
||||
42-
|
||||
43-
|
||||
44-
|
||||
45-INSERT
|
||||
46-DELETE
|
||||
47-
|
||||
48-0
|
||||
49-1
|
||||
50-2
|
||||
51-3
|
||||
52-4
|
||||
53-5
|
||||
54-6
|
||||
55-7
|
||||
56-8
|
||||
57-9
|
||||
58-
|
||||
59-SEMICOLON
|
||||
60-
|
||||
61-EQUAL
|
||||
62-
|
||||
63-
|
||||
64-
|
||||
65-a
|
||||
66-b
|
||||
67-c
|
||||
68-d
|
||||
69-e
|
||||
70-f
|
||||
71-g
|
||||
72-h
|
||||
73-i
|
||||
74-j
|
||||
75-k
|
||||
76-l
|
||||
77-m
|
||||
78-n
|
||||
79-o
|
||||
80-p
|
||||
81-q
|
||||
82-r
|
||||
83-s
|
||||
84-t
|
||||
85-u
|
||||
86-v
|
||||
87-w
|
||||
88-x
|
||||
89-y
|
||||
90-z
|
||||
91-
|
||||
92-
|
||||
93-
|
||||
94-
|
||||
95-
|
||||
96-
|
||||
97-
|
||||
98-
|
||||
99-
|
||||
100-
|
||||
101-
|
||||
102-
|
||||
103-
|
||||
106-
|
||||
107-
|
||||
108-
|
||||
109-
|
||||
110-
|
||||
111-
|
||||
112-FUNCTION_1
|
||||
113-FUNCTION_2
|
||||
114-FUNCTION_3
|
||||
115-FUNCTION_4
|
||||
116-FUNCTION_5
|
||||
117-FUNCTION_6
|
||||
118-FUNCTION_7
|
||||
119-FUNCTION_8
|
||||
120-FUNCTION_9
|
||||
121-FUNCTION_10
|
||||
122-FUNCTION_11
|
||||
123-FUNCTION_12
|
||||
124-
|
||||
125-
|
||||
126-
|
||||
127-
|
||||
128-
|
||||
129-
|
||||
130-
|
||||
131-
|
||||
132-
|
||||
134-
|
||||
135-
|
||||
136-
|
||||
137-
|
||||
138-
|
||||
139-
|
||||
140-
|
||||
141-
|
||||
142-
|
||||
143-
|
||||
145-SCROLL_LOCK
|
||||
146-
|
||||
147-
|
||||
148-
|
||||
149-
|
||||
150-
|
||||
151-
|
||||
152-
|
||||
153-
|
||||
154-
|
||||
155-
|
||||
156-
|
||||
157-
|
||||
158-
|
||||
159-
|
||||
160-
|
||||
161-
|
||||
162-
|
||||
163-
|
||||
164-
|
||||
165-
|
||||
166-
|
||||
167-
|
||||
168-
|
||||
169-
|
||||
170-
|
||||
171-
|
||||
172-
|
||||
173-MINUS
|
||||
174-
|
||||
175-
|
||||
176-
|
||||
177-
|
||||
178-
|
||||
179-
|
||||
180-
|
||||
181-
|
||||
182-
|
||||
183-
|
||||
184-
|
||||
185-
|
||||
186-
|
||||
187-
|
||||
188-COMMA
|
||||
189-
|
||||
190-PERIOD
|
||||
191-FORWARD_SLASH
|
||||
192-GRAVE
|
||||
193-
|
||||
194-
|
||||
195-
|
||||
196-
|
||||
197-
|
||||
198-
|
||||
199-
|
||||
200-
|
||||
201-
|
||||
202-
|
||||
203-
|
||||
204-
|
||||
205-
|
||||
206-
|
||||
207-
|
||||
208-
|
||||
209-
|
||||
210-
|
||||
211-
|
||||
212-
|
||||
213-
|
||||
214-
|
||||
215-
|
||||
216-
|
||||
218-
|
||||
219-BRACKET_LEFT
|
||||
220-BACK_SLASH
|
||||
221-BRACKET_RIGHT
|
||||
222-QUOTE
|
||||
223-
|
||||
224-
|
||||
225-
|
||||
226-
|
||||
227-
|
||||
228-
|
||||
229-
|
||||
230-
|
||||
231-
|
||||
232-
|
||||
233-
|
||||
234-
|
||||
235-
|
||||
236-
|
||||
237-
|
||||
238-
|
||||
239-
|
||||
240-
|
||||
241-
|
||||
242-
|
||||
243-
|
||||
244-
|
||||
245-
|
||||
246-
|
||||
247-
|
||||
248-
|
||||
249-
|
||||
250-
|
||||
251-
|
||||
252-
|
||||
253-
|
||||
254-
|
||||
255-
|
|
@ -1,14 +0,0 @@
|
|||
boot/
|
||||
├─ kernel.img
|
||||
home/
|
||||
├─ able/
|
||||
│ ├─ bins/
|
||||
│ ├─ config/
|
||||
│ │ ├─ able_edit/
|
||||
│ │ │ ├─ config.toml
|
||||
│ ├─ irl_pic.png
|
||||
│ ├─ password.txt
|
||||
system/
|
||||
├─ bins/
|
||||
├─ configs/
|
||||
│ ├─ kernel.toml
|
1
limine
Submodule
1
limine
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 83e6e5b4da7791ade3b367ceec8ce82c469d06db
|
|
@ -1,11 +1,15 @@
|
|||
[package]
|
||||
name = "repbuild"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
colored = "2.0"
|
||||
udisks = "0.1"
|
||||
zbus = "2.3"
|
||||
env_logger = "0.10"
|
||||
error-stack = "0.2"
|
||||
fatfs = "0.3"
|
||||
log = "0.4"
|
||||
|
||||
[dependencies.nix]
|
||||
version = "0.26"
|
||||
default-features = false
|
||||
features = ["fs"]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
${ABLEOS_KERNEL}=boot:///boot/kernel
|
||||
${ABLEOS_KERNEL}=boot:///kernel
|
||||
# TODO: Make a boot background image for ableOS
|
||||
# ${WALLPAPER_PATH}=boot:///boot/bg.bmp
|
||||
|
||||
|
@ -18,5 +18,5 @@ TERM_BACKDROP=008080
|
|||
# Setting a default resolution for the framebuffer
|
||||
RESOLUTION=800x600x24
|
||||
|
||||
MODULE_PATH=boot:///boot/initrd.tar
|
||||
MODULE_CMDLINE=This is the first module.
|
||||
# MODULE_PATH=boot:///boot/initrd.tar
|
||||
# MODULE_CMDLINE=This is the first module.
|
|
@ -1,539 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
|
||||
* Copyright (c) 2022, able <abl3theabove@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
use error_stack::{bail, report, Context, IntoReport, Result, ResultExt};
|
||||
use fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek};
|
||||
use nix::fcntl::FallocateFlags;
|
||||
use std::{fmt::Display, fs::File, io, os::fd::AsRawFd, path::Path, process::Command};
|
||||
|
||||
use colored::*;
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
os::fd::AsRawFd,
|
||||
process::Command,
|
||||
};
|
||||
use udisks::{
|
||||
filesystem::{MountOptions, UnMountOptions},
|
||||
manager::LoopSetupOptions,
|
||||
};
|
||||
fn main() -> Result<(), Error> {
|
||||
env_logger::init();
|
||||
let mut args = std::env::args();
|
||||
args.next();
|
||||
|
||||
struct Options {
|
||||
pub subcommand: Subcommand,
|
||||
pub arguments: Vec<String>,
|
||||
}
|
||||
|
||||
enum Subcommand {
|
||||
BuildImage,
|
||||
Doc,
|
||||
Help,
|
||||
Run,
|
||||
Empty,
|
||||
/// Run all tests for all architectures
|
||||
Test,
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
impl Subcommand {
|
||||
fn from_str<S: AsRef<str>>(str: S) -> Subcommand {
|
||||
match str.as_ref() {
|
||||
"build-image" => Subcommand::BuildImage,
|
||||
"doc" => Subcommand::Doc,
|
||||
"help" => Subcommand::Help,
|
||||
"run" | "r" => Subcommand::Run,
|
||||
"test" | "t" => Subcommand::Test,
|
||||
"" => Subcommand::Empty,
|
||||
unknown => Subcommand::Unknown(unknown.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum MachineType {
|
||||
X86_64,
|
||||
RiscV64,
|
||||
AArch64,
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let options = options();
|
||||
|
||||
match options.subcommand {
|
||||
Subcommand::BuildImage => {
|
||||
let machine_text = options.arguments.get(0).cloned().unwrap_or_default();
|
||||
|
||||
match machine(machine_text) {
|
||||
MachineType::X86_64 => {
|
||||
// Cleanup
|
||||
// NOTE: we are not unwrapping these, as we don't want this to fail if they
|
||||
// don't exist yet, probably not the best idea tho.
|
||||
// FIXME: figure out a better way to ignore errors about these not existing
|
||||
#[allow(unused_must_use)]
|
||||
{
|
||||
fs::remove_dir_all("./limine");
|
||||
fs::remove_dir_all("./disk");
|
||||
fs::remove_file("./target/disk.img");
|
||||
}
|
||||
|
||||
// Build ableOS in release mode
|
||||
Command::new("cargo")
|
||||
.args(["build", "--release"])
|
||||
.current_dir(fs::canonicalize("./kernel").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
// Create disk directory
|
||||
fs::create_dir("./disk").unwrap();
|
||||
|
||||
// Clone limine 4.x binaries
|
||||
Command::new("git")
|
||||
.arg("clone")
|
||||
.arg("https://github.com/limine-bootloader/limine.git")
|
||||
.arg("--branch=v4.x-branch-binary")
|
||||
.arg("--depth=1")
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
println!("{}", "Building limine".bold());
|
||||
Command::new("make")
|
||||
.args(["-C", "limine"])
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
println!("{}", "Allocating new disk image".bold());
|
||||
Command::new("fallocate")
|
||||
.args(["-l", "256M", "./target/disk.img"])
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
println!("{}", "Partitioning disk image".bold());
|
||||
let dbus_conn = zbus::blocking::Connection::system()?;
|
||||
|
||||
// Setup loop device
|
||||
let disk_img = File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open("./target/disk.img")?;
|
||||
let loopdev = udisks::manager::UDisks2ManagerProxyBlocking::new(&dbus_conn)?
|
||||
.loop_setup(
|
||||
disk_img.as_raw_fd().into(),
|
||||
LoopSetupOptions {
|
||||
no_user_interaction: true,
|
||||
offset: 0,
|
||||
size: 0,
|
||||
readonly: false,
|
||||
no_part_scan: false,
|
||||
},
|
||||
match args.next().as_deref() {
|
||||
Some("build" | "b") => build(
|
||||
args.next()
|
||||
.map(|x| x == "-r" || x == "--release")
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.change_context(Error::Build),
|
||||
Some("run" | "r") => {
|
||||
build(
|
||||
args.next()
|
||||
.map(|x| x == "-r" || x == "--release")
|
||||
.unwrap_or_default(),
|
||||
)?;
|
||||
|
||||
// Create MBR
|
||||
udisks::block::BlockProxyBlocking::builder(&dbus_conn)
|
||||
.path(&loopdev)?
|
||||
.build()?
|
||||
.format("dos", Default::default())?;
|
||||
|
||||
// Create and format partition
|
||||
let filesystem =
|
||||
udisks::partition::PartitionTableProxyBlocking::builder(&dbus_conn)
|
||||
.destination("org.freedesktop.UDisks2")?
|
||||
.path(&loopdev)?
|
||||
.build()?
|
||||
.create_partition_and_format(
|
||||
0,
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
Default::default(),
|
||||
"ext2",
|
||||
[("take-ownership", true.into())].into_iter().collect(),
|
||||
)?;
|
||||
|
||||
let fsproxy = udisks::filesystem::FilesystemProxyBlocking::builder(&dbus_conn)
|
||||
.path(&filesystem)?
|
||||
.build()?;
|
||||
|
||||
// Mount the filesystem
|
||||
let mountpoint = fsproxy
|
||||
.mount(MountOptions {
|
||||
no_user_interaction: true,
|
||||
fs_type: String::new(),
|
||||
mount_options: String::new(),
|
||||
})
|
||||
.or_else(|_| {
|
||||
Ok::<String, zbus::Error>(loop {
|
||||
if let Some(m) = fsproxy.mount_points()?.get(0) {
|
||||
break m.to_string();
|
||||
run()
|
||||
}
|
||||
})
|
||||
})?;
|
||||
|
||||
// copy ./base/* over to ./disk
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(format!("cp -r ./base/* {mountpoint}"))
|
||||
.status()?;
|
||||
|
||||
// copy ./limine/limine.sys over to ./disk/boot
|
||||
Command::new("cp")
|
||||
.args(["./limine/limine.sys", &format!("{mountpoint}/boot")])
|
||||
.status()?;
|
||||
|
||||
// copy the kernel over to ./disk/boot/kernel
|
||||
Command::new("cp")
|
||||
.arg("./target/x86_64-ableos/release/kernel")
|
||||
.arg(&format!("{mountpoint}/boot/kernel"))
|
||||
.status()?;
|
||||
|
||||
// Unmount the filesystem (and the rest of things will follow)
|
||||
fsproxy.unmount(UnMountOptions {
|
||||
no_user_interaction: true,
|
||||
force: false,
|
||||
})?;
|
||||
|
||||
println!("{}", "Deploying limine".bold());
|
||||
Command::new("./limine/limine-deploy")
|
||||
.arg("./target/disk.img")
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::Unknown(unknown) => {
|
||||
eprintln!(
|
||||
"{}: unknown machine type `{}`",
|
||||
"error".red().bold(),
|
||||
unknown.bold(),
|
||||
Some("help" | "h") => {
|
||||
println!(
|
||||
concat!(
|
||||
"AbleOS RepBuild\n",
|
||||
"Subcommands:\n",
|
||||
" build (b): Build a bootable disk image\n",
|
||||
" help (h): Print this message\n",
|
||||
" run (r): Build and run AbleOS in QEMU\n\n",
|
||||
"Options for build and run:\n",
|
||||
" -r: build in release mode",
|
||||
),
|
||||
);
|
||||
eprintln!("expected one of x86_64, riscv64 or aarch64");
|
||||
}
|
||||
_ => {
|
||||
eprintln!(
|
||||
"{}: build-image not implemented for this machine type",
|
||||
"error".red().bold(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Subcommand::Test => {
|
||||
Command::new("cargo")
|
||||
.args(["test", "--target=json_targets/x86_64-ableos.json"])
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
// panic!("Test Infrastructure missing");
|
||||
}
|
||||
Subcommand::Doc => {
|
||||
let machine_text = options.arguments.get(0).cloned().unwrap_or_default();
|
||||
|
||||
match machine(machine_text) {
|
||||
MachineType::X86_64 => {
|
||||
Command::new("cargo")
|
||||
.args(["doc", "--open"])
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::RiscV64 => {
|
||||
Command::new("cargo")
|
||||
.args(["doc", "--open", "--target=riscv64gc-unknown-none-elf"])
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::AArch64 => {
|
||||
Command::new("cargo")
|
||||
.args(["doc", "--open", "--target=json_targets/aarch64-ableos.json"])
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::Unknown(unknown) => {
|
||||
eprintln!(
|
||||
"{}: unknown machine type `{}`",
|
||||
"error".red().bold(),
|
||||
unknown.bold(),
|
||||
);
|
||||
eprintln!("expected one of x86_64, riscv64 or aarch64");
|
||||
}
|
||||
}
|
||||
}
|
||||
Subcommand::Help => help(),
|
||||
Subcommand::Run => {
|
||||
let machine_text = options.arguments.get(0).cloned().unwrap_or_default();
|
||||
let debug = options.arguments.get(1).cloned().unwrap_or_default();
|
||||
let debug = matches!(debug.as_str(), "--debug" | "--dbg" | "-d");
|
||||
|
||||
match machine(machine_text) {
|
||||
MachineType::X86_64 if debug => {
|
||||
// Build ableOS
|
||||
Command::new("cargo")
|
||||
.arg("build")
|
||||
.current_dir(fs::canonicalize("./kernel").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
// Setup loopback device for disk.img, with partitions
|
||||
// FIXME: don't do ths if running without changes
|
||||
// Setup loop device
|
||||
let disk_img = File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open("./target/disk.img")?;
|
||||
let dbus_conn = zbus::blocking::Connection::system()?;
|
||||
let loopdev = udisks::manager::UDisks2ManagerProxyBlocking::new(&dbus_conn)?
|
||||
.loop_setup(
|
||||
disk_img.as_raw_fd().into(),
|
||||
LoopSetupOptions {
|
||||
no_user_interaction: true,
|
||||
offset: 0,
|
||||
size: 0,
|
||||
readonly: false,
|
||||
no_part_scan: false,
|
||||
},
|
||||
)?;
|
||||
|
||||
let parts = udisks::partition::PartitionTableProxyBlocking::builder(&dbus_conn)
|
||||
.destination("org.freedesktop.UDisks2")?
|
||||
.path(loopdev)?
|
||||
.build()?
|
||||
.partitions()?;
|
||||
|
||||
let fsobjpath = parts.get(0).ok_or("missing boot partition")?;
|
||||
let mountpoint =
|
||||
udisks::filesystem::FilesystemProxyBlocking::builder(&dbus_conn)
|
||||
.path(fsobjpath)?
|
||||
.build()?
|
||||
.mount(MountOptions {
|
||||
no_user_interaction: true,
|
||||
fs_type: String::new(),
|
||||
mount_options: String::new(),
|
||||
})?;
|
||||
|
||||
// copy the kernel over to ./disk/boot/kernel
|
||||
Command::new("cp")
|
||||
.arg("./target/x86_64-ableos/debug/kernel")
|
||||
.arg(format!("{mountpoint}/boot/kernel"))
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
udisks::filesystem::FilesystemProxyBlocking::builder(&dbus_conn)
|
||||
.path(fsobjpath)?
|
||||
.build()?
|
||||
.unmount(UnMountOptions {
|
||||
no_user_interaction: true,
|
||||
force: false,
|
||||
})?;
|
||||
|
||||
// run qemu with "-S", "-gdb", "tcp:9000"
|
||||
Command::new("qemu-system-x86_64")
|
||||
.args(["-device", "piix4-ide,id=ide"])
|
||||
.arg("-drive")
|
||||
.arg("file=./target/disk.img,format=raw,if=none,id=disk")
|
||||
.args(["-device", "ide-hd,drive=disk,bus=ide.0"])
|
||||
// .arg("--nodefaults")
|
||||
.args(["-cpu", "Broadwell-v3"])
|
||||
.args(["-m", "4G"])
|
||||
.args(["-serial", "stdio"])
|
||||
.args(["-smp", "cores=2"])
|
||||
// .args(["-soundhw", "pcspk"])
|
||||
// .args(["-device", "VGA"])
|
||||
// .args(["-device", "virtio-gpu-pci"])
|
||||
.args(["-device", "vmware-svga"])
|
||||
.args(["-device", "sb16"])
|
||||
// .args(["-machine", "pcspk-audiodev=0"])
|
||||
// .args(["-qmp", "unix:../qmp-sock,server,nowait"])
|
||||
.args(["-S", "-gdb", "tcp:9000"])
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::X86_64 => {
|
||||
// Build ableOS
|
||||
Command::new("cargo")
|
||||
.args(["build", "--release"])
|
||||
.current_dir(fs::canonicalize("./kernel").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
// Setup loopback device for disk.img, with partitions
|
||||
// FIXME: don't do ths if running without changes
|
||||
let disk_img = File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open("./target/disk.img")?;
|
||||
let dbus_conn = zbus::blocking::Connection::system()?;
|
||||
let loopdev = udisks::manager::UDisks2ManagerProxyBlocking::new(&dbus_conn)?
|
||||
.loop_setup(
|
||||
disk_img.as_raw_fd().into(),
|
||||
LoopSetupOptions {
|
||||
no_user_interaction: true,
|
||||
offset: 0,
|
||||
size: 0,
|
||||
readonly: false,
|
||||
no_part_scan: false,
|
||||
},
|
||||
)?;
|
||||
|
||||
let parts = udisks::partition::PartitionTableProxyBlocking::builder(&dbus_conn)
|
||||
.destination("org.freedesktop.UDisks2")?
|
||||
.path(loopdev)?
|
||||
.build()?
|
||||
.partitions()?;
|
||||
|
||||
let fsproxy = udisks::filesystem::FilesystemProxyBlocking::builder(&dbus_conn)
|
||||
.path(&parts[0])?
|
||||
.build()?;
|
||||
|
||||
// Mount the filesystem
|
||||
let mountpoint = fsproxy
|
||||
.mount(MountOptions {
|
||||
no_user_interaction: true,
|
||||
fs_type: String::new(),
|
||||
mount_options: String::new(),
|
||||
})
|
||||
.or_else(|_| {
|
||||
Ok::<String, zbus::Error>(loop {
|
||||
if let Some(m) = fsproxy.mount_points()?.get(0) {
|
||||
break m.to_string();
|
||||
}
|
||||
})
|
||||
})?;
|
||||
|
||||
// copy the kernel over to ./disk/boot/kernel
|
||||
Command::new("cp")
|
||||
.arg("./target/x86_64-ableos/release/kernel")
|
||||
.arg(format!("{mountpoint}/boot/kernel"))
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
fsproxy.unmount(UnMountOptions {
|
||||
no_user_interaction: true,
|
||||
force: false,
|
||||
})?;
|
||||
|
||||
// run qemu
|
||||
Command::new("qemu-system-x86_64")
|
||||
.args(["-device", "piix4-ide,id=ide"])
|
||||
.arg("-drive")
|
||||
.arg("file=./target/disk.img,format=raw,if=none,id=disk")
|
||||
.args(["-device", "ide-hd,drive=disk,bus=ide.0"])
|
||||
// .arg("--nodefaults")
|
||||
.args(["-cpu", "Broadwell-v3"])
|
||||
.args(["-m", "4G"])
|
||||
.args(["-serial", "stdio"])
|
||||
.args(["-smp", "cores=2"])
|
||||
// .args(["-soundhw", "pcspk"])
|
||||
// .args(["-device", "VGA"])
|
||||
// .args(["-device", "virtio-gpu-pci"])
|
||||
.args(["-device", "vmware-svga"])
|
||||
.args(["-device", "sb16"])
|
||||
// .args(["-machine", "pcspk-audiodev=0"])
|
||||
// .args(["-qmp", "unix:../qmp-sock,server,nowait"])
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::RiscV64 if debug => {
|
||||
eprintln!(
|
||||
"{}: debug is not implemented for riscv64",
|
||||
"error".red().bold()
|
||||
);
|
||||
}
|
||||
MachineType::RiscV64 => {
|
||||
Command::new("cargo")
|
||||
.args(["build", "--release", "--target=riscv64gc-unknown-none-elf"])
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
Command::new("qemu-system-riscv64")
|
||||
.args(["-machine", "virt"])
|
||||
.args(["-cpu", "rv64"])
|
||||
.args(["-smp", "8"])
|
||||
.args(["-m", "128M"])
|
||||
.arg("-bios")
|
||||
.arg("src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin")
|
||||
.arg("-kernel")
|
||||
.arg("target/riscv64gc-unknown-none-elf/release/ableos")
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::AArch64 if debug => {
|
||||
eprintln!(
|
||||
"{}: debug is not implemented for aarch64",
|
||||
"error".red().bold()
|
||||
);
|
||||
}
|
||||
MachineType::AArch64 => {
|
||||
Command::new("cargo")
|
||||
.args([
|
||||
"build",
|
||||
"--release",
|
||||
"--target=json_targets/aarch64-ableos.json",
|
||||
])
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
Command::new("qemu-system-aarch64")
|
||||
.args(["-machine", "virt"])
|
||||
.args(["-m", "1024M"])
|
||||
.args(["-cpu", "cortex-a53"])
|
||||
.args(["-kernel", "target/aarch64-ableos/release/ableos"])
|
||||
.args(["-device", "virtio-keyboard"])
|
||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
MachineType::Unknown(unknown) => {
|
||||
eprintln!(
|
||||
"{}: unknown machine type `{}`",
|
||||
"error".red().bold(),
|
||||
unknown.bold(),
|
||||
);
|
||||
eprintln!("expected one of x86_64, riscv64 or aarch64");
|
||||
}
|
||||
}
|
||||
}
|
||||
Subcommand::Empty => {
|
||||
eprintln!("{}: no subcommand passed", "error".red().bold());
|
||||
help();
|
||||
}
|
||||
Subcommand::Unknown(unknown) => {
|
||||
eprintln!(
|
||||
"{}: unknown subcommand `{}`",
|
||||
"error".red().bold(),
|
||||
unknown.bold()
|
||||
);
|
||||
help();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn options() -> Options {
|
||||
let subcommand = std::env::args().nth(1).unwrap_or_default();
|
||||
let arguments = std::env::args().skip(2).collect();
|
||||
|
||||
Options {
|
||||
subcommand: Subcommand::from_str(subcommand),
|
||||
arguments,
|
||||
}
|
||||
_ => Err(report!(Error::InvalidSubCom)),
|
||||
}
|
||||
}
|
||||
|
||||
fn machine<S: AsRef<str>>(text: S) -> MachineType {
|
||||
match text.as_ref() {
|
||||
"x86" | "x86_64" => MachineType::X86_64,
|
||||
"riscv" | "riscv64" => MachineType::RiscV64,
|
||||
"arm" | "arm64" | "aarch64" => MachineType::AArch64,
|
||||
"" => {
|
||||
eprintln!(
|
||||
"{}: no machine type passed, defaulting to x86_64",
|
||||
"warning".yellow().bold()
|
||||
);
|
||||
MachineType::X86_64
|
||||
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
|
||||
let path = Path::new("target/disk.img");
|
||||
|
||||
match std::fs::metadata(path) {
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => (),
|
||||
Err(e) => bail!(e),
|
||||
Ok(_) => {
|
||||
return FileSystem::new(
|
||||
File::options().read(true).write(true).open(path)?,
|
||||
FsOptions::new(),
|
||||
)
|
||||
.into_report()
|
||||
}
|
||||
unknown => MachineType::Unknown(unknown.to_string()),
|
||||
}
|
||||
|
||||
let mut img = File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(path)?;
|
||||
|
||||
{
|
||||
#[cfg(unix)]
|
||||
nix::fcntl::fallocate(
|
||||
img.as_raw_fd(),
|
||||
FallocateFlags::from_bits(0).unwrap(),
|
||||
0,
|
||||
1024 * 1024 * 64,
|
||||
)
|
||||
.map_err(|e| std::io::Error::from_raw_os_error(e as i32))?;
|
||||
|
||||
#[cfg(not(any(unix)))]
|
||||
compile_error!("unsupported platform");
|
||||
}
|
||||
|
||||
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
|
||||
|
||||
let fs = FileSystem::new(img, FsOptions::new())?;
|
||||
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
|
||||
|
||||
io::copy(
|
||||
&mut File::open("limine/BOOTX64.EFI")?,
|
||||
&mut bootdir.create_file("bootx64.efi")?,
|
||||
)?;
|
||||
|
||||
io::copy(
|
||||
&mut File::open(Path::new("repbuild/limine.cfg"))?,
|
||||
&mut fs.root_dir().create_file("limine.cfg")?,
|
||||
)?;
|
||||
|
||||
drop(bootdir);
|
||||
Ok(fs)
|
||||
}
|
||||
|
||||
fn build(release: bool) -> Result<(), Error> {
|
||||
let fs = get_fs().change_context(Error::Io)?;
|
||||
let mut com = Command::new("cargo");
|
||||
com.current_dir("kernel");
|
||||
com.args(["b"]);
|
||||
if release {
|
||||
com.arg("-r");
|
||||
}
|
||||
|
||||
com.status().into_report().change_context(Error::Build)?;
|
||||
|
||||
(|| -> std::io::Result<_> {
|
||||
io::copy(
|
||||
&mut File::open(
|
||||
Path::new("target/x86_64-ableos")
|
||||
.join(if release { "release" } else { "debug" })
|
||||
.join("kernel"),
|
||||
)?,
|
||||
&mut fs.root_dir().create_file("kernel")?,
|
||||
)
|
||||
.map(|_| ())
|
||||
})()
|
||||
.into_report()
|
||||
.change_context(Error::Io)
|
||||
}
|
||||
|
||||
fn run() -> Result<(), Error> {
|
||||
#[rustfmt::skip]
|
||||
let args = [
|
||||
"-bios", "/usr/share/OVMF/OVMF_CODE.fd",
|
||||
"-enable-kvm",
|
||||
"-cpu", "host",
|
||||
"-drive", "file=target/disk.img,format=raw",
|
||||
"-m", "4G",
|
||||
"-serial", "stdio",
|
||||
"-smp", "cores=2",
|
||||
];
|
||||
|
||||
match Command::new("qemu-system-x86_64")
|
||||
.args(args)
|
||||
.status()
|
||||
.into_report()
|
||||
.change_context(Error::ProcessSpawn)?
|
||||
{
|
||||
s if s.success() => Ok(()),
|
||||
s => Err(report!(Error::Qemu(s.code()))),
|
||||
}
|
||||
}
|
||||
|
||||
fn help() {
|
||||
todo!("`help`")
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
Build,
|
||||
InvalidSubCom,
|
||||
Io,
|
||||
ProcessSpawn,
|
||||
Qemu(Option<i32>),
|
||||
}
|
||||
|
||||
impl Context for Error {}
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Build => f.write_str("failed to build the kernel"),
|
||||
Self::InvalidSubCom => {
|
||||
f.write_str("missing or invalid subcommand (available: build, run)")
|
||||
}
|
||||
Self::Io => f.write_str("IO error"),
|
||||
Self::ProcessSpawn => f.write_str("failed to spawn a process"),
|
||||
Self::Qemu(Some(c)) => write!(f, "QEMU Error: {c}"),
|
||||
Self::Qemu(None) => write!(f, "QEMU Error: interrupted by signal"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue