Compare commits

...

3 Commits

Author SHA1 Message Date
1afc66acb1
build tool stuff 2025-02-10 14:23:27 -05:00
79c8e12671
build tool stuff 2025-02-10 14:22:53 -05:00
ae43d587f7
It boots! 2025-02-10 14:14:17 -05:00
18 changed files with 376 additions and 9 deletions

View File

@ -1,2 +1,3 @@
[build]
rustflags = "-C relocation-model=static"
target = "x86_64-unknown-none"

1
.envrc Normal file
View File

@ -0,0 +1 @@
use nix

2
.gitignore vendored
View File

@ -1 +1,3 @@
/target
/iso
/gila.iso

2
Cargo.lock generated
View File

@ -55,7 +55,7 @@ checksum = "875488b8711a968268c7cf5d139578713097ca4635a76044e8fe8eedf831d07e"
[[package]]
name = "gila"
version = "0.1.1"
version = "0.2.0"
dependencies = [
"flagset",
"lazy_static",

View File

@ -1,6 +1,6 @@
[package]
name = "gila"
version = "0.1.1"
version = "0.2.0"
edition = "2024"
[dependencies]

View File

@ -1,5 +1,5 @@
# Gila v0.1.1 - a Rust Microkernel
# Gila v0.2.0 - a Rust Microkernel
Gila is a Rust microkernel OS, inspired by the Xinu embedded OS. It will
hopefully be capable of multitasking some day. I do not intend for Gila to
@ -24,6 +24,21 @@ Licensed under the GNU Public License v3. See [LICENSE](LICENSE) for details.
- [process.rs](src/process.rs): Process types and functions.
- [resources.rs](src/resources.rs): Resources that are accessible from multiple parts of the code.
## Building and running - TODO
## Building and running
This section is under construction.
To build an ISO image that you can boot, there are several prerequisites:
- `limine` command installed
- `xorriso` command installed
Then run the [build_iso.sh](build_iso.sh) script. It will generate `gila.iso`.
Running the kernel requires `qemu-system-{ARCH}`.
You can install all these dependencies automatically by using `nix-shell` and
supplying [shell.nix](shell.nix) as an argument.
## Credits
The linker script stuff is from [limine-rust-template](https://github.com/jasondyoungberg/limine-rust-template),
which is available under the BSD 0-Clause License.

8
build.rs Normal file
View File

@ -0,0 +1,8 @@
fn main() {
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
// Tell cargo to pass the linker script to the linker..
println!("cargo:rustc-link-arg=-Tlinker-scripts/linker-{arch}.ld");
// ..and to re-run if it changes.
println!("cargo:rerun-if-changed=linker-scripts/linker-{arch}.ld");
}

31
build_iso.sh Normal file → Executable file
View File

@ -0,0 +1,31 @@
#!/bin/bash
if [ -z "$1" ]; then
echo "Argument 1 must be the Rust target triple."
exit 1
fi
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 || exit 1 ; pwd -P )"
cd "$SCRIPTPATH" || exit 1
rm -rf ./iso/
rm ./gila.iso
#cargo clean
set -euxo pipefail
mkdir -p ./iso/limine/
cp ./limine.conf ./iso/
cp /usr/share/limine/limine-bios.sys ./iso/limine/
cp /usr/share/limine/limine-bios-cd.bin ./iso/limine/
cp /usr/share/limine/limine-uefi-cd.bin ./iso/limine/
cargo build --target="$1" --release
cp target/"$1"/release/gila ./iso/
xorriso -as mkisofs -b limine/limine-bios-cd.bin -no-emul-boot \
-boot-load-size 4 -boot-info-table --efi-boot \
limine/limine-uefi-cd.bin -efi-boot-part --efi-boot-image \
--protective-msdos-label iso -o gila.iso
limine bios-install gila.iso

View File

@ -2,4 +2,4 @@ timeout: 5
/Gila
protocol: limine
kernel_path: boot():/gila.bin
kernel_path: boot():/gila

View File

@ -0,0 +1,63 @@
/* Tell the linker that we want an aarch64 ELF64 output file */
OUTPUT_FORMAT(elf64-littleaarch64)
/* We want the symbol main to be our entry point */
ENTRY(main)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions; this also allows us to exert more control over the linking */
/* process. */
PHDRS
{
text PT_LOAD;
rodata PT_LOAD;
data PT_LOAD;
}
SECTIONS
{
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
/* and because that is what the Limine spec mandates. */
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
/* that is the beginning of the region. */
. = 0xffffffff80000000;
.text : {
*(.text .text.*)
} :text
/* Move to the next memory page for .rodata */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.rodata : {
*(.rodata .rodata.*)
} :rodata
/* Move to the next memory page for .data */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.data : {
*(.data .data.*)
/* Place the sections that contain the Limine requests as part of the .data */
/* output section. */
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
} :data
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
/* unnecessary zeros will be written to the binary. */
/* If you need, for example, .init_array and .fini_array, those should be placed */
/* above this. */
.bss : {
*(.bss .bss.*)
*(COMMON)
} :data
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
/DISCARD/ : {
*(.eh_frame*)
*(.note .note.*)
}
}

View File

@ -0,0 +1,63 @@
/* Tell the linker that we want a loongarch64 ELF64 output file */
OUTPUT_FORMAT(elf64-loongarch)
/* We want the symbol main to be our entry point */
ENTRY(main)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions; this also allows us to exert more control over the linking */
/* process. */
PHDRS
{
text PT_LOAD;
rodata PT_LOAD;
data PT_LOAD;
}
SECTIONS
{
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
/* and because that is what the Limine spec mandates. */
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
/* that is the beginning of the region. */
. = 0xffffffff80000000;
.text : {
*(.text .text.*)
} :text
/* Move to the next memory page for .rodata */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.rodata : {
*(.rodata .rodata.*)
} :rodata
/* Move to the next memory page for .data */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.data : {
*(.data .data.*)
/* Place the sections that contain the Limine requests as part of the .data */
/* output section. */
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
} :data
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
/* unnecessary zeros will be written to the binary. */
/* If you need, for example, .init_array and .fini_array, those should be placed */
/* above this. */
.bss : {
*(.bss .bss.*)
*(COMMON)
} :data
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
/DISCARD/ : {
*(.eh_frame*)
*(.note .note.*)
}
}

View File

@ -0,0 +1,66 @@
/* Tell the linker that we want a riscv64 ELF64 output file */
OUTPUT_FORMAT(elf64-littleriscv)
/* We want the symbol main to be our entry point */
ENTRY(main)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions; this also allows us to exert more control over the linking */
/* process. */
PHDRS
{
text PT_LOAD;
rodata PT_LOAD;
data PT_LOAD;
}
SECTIONS
{
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
/* and because that is what the Limine spec mandates. */
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
/* that is the beginning of the region. */
. = 0xffffffff80000000;
.text : {
*(.text .text.*)
} :text
/* Move to the next memory page for .rodata */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.rodata : {
*(.rodata .rodata.*)
} :rodata
/* Move to the next memory page for .data */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.data : {
*(.data .data.*)
/* Place the sections that contain the Limine requests as part of the .data */
/* output section. */
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
*(.sdata .sdata.*)
} :data
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
/* unnecessary zeros will be written to the binary. */
/* If you need, for example, .init_array and .fini_array, those should be placed */
/* above this. */
.bss : {
*(.sbss .sbss.*)
*(.bss .bss.*)
*(COMMON)
} :data
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
/DISCARD/ : {
*(.eh_frame*)
*(.note .note.*)
}
}

View File

@ -0,0 +1,63 @@
/* Tell the linker that we want an x86_64 ELF64 output file */
OUTPUT_FORMAT(elf64-x86-64)
/* We want the symbol main to be our entry point */
ENTRY(main)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions; this also allows us to exert more control over the linking */
/* process. */
PHDRS
{
text PT_LOAD;
rodata PT_LOAD;
data PT_LOAD;
}
SECTIONS
{
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
/* and because that is what the Limine spec mandates. */
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
/* that is the beginning of the region. */
. = 0xffffffff80000000;
.text : {
*(.text .text.*)
} :text
/* Move to the next memory page for .rodata */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.rodata : {
*(.rodata .rodata.*)
} :rodata
/* Move to the next memory page for .data */
. = ALIGN(CONSTANT(MAXPAGESIZE));
.data : {
*(.data .data.*)
/* Place the sections that contain the Limine requests as part of the .data */
/* output section. */
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
} :data
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
/* unnecessary zeros will be written to the binary. */
/* If you need, for example, .init_array and .fini_array, those should be placed */
/* above this. */
.bss : {
*(.bss .bss.*)
*(COMMON)
} :data
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
/DISCARD/ : {
*(.eh_frame*)
*(.note .note.*)
}
}

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

27
shell.nix Normal file
View File

@ -0,0 +1,27 @@
let
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
pkgs = import nixpkgs { config = {}; overlays = []; };
in
pkgs.mkShell {
packages = with pkgs; [
bash
limine
xorriso
rustup
qemu
];
shellHook = ''
rustup default nightly;
rustup target add x86_64-unknown-none
'';
}

View File

@ -1,6 +1,17 @@
#![allow(dead_code)]
use limine::{request::SmpRequest, BaseRevision};
use limine::{request::*, BaseRevision};
#[used]
#[unsafe(link_section = ".requests_start_marker")]
static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new();
#[used]
#[unsafe(link_section = ".requests_end_marker")]
static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new();
#[used]
#[unsafe(link_section = ".requests")]
pub static BASE_REVISION: BaseRevision = limine::BaseRevision::new();
#[used]
#[unsafe(link_section = ".requests")]
pub static SMP_REQUEST: SmpRequest = limine::request::SmpRequest::new();

View File

@ -1,8 +1,9 @@
#![allow(dead_code)]
use vga;
pub use vga::writers::TextWriter;
struct TextDisplay {
pub struct TextDisplay {
writer: vga::writers::Text80x25,
column: usize,
row: usize,

View File

@ -5,6 +5,8 @@
#![allow(dead_code)]
#![allow(unused_imports)]
use core::arch::asm;
use gila::boot::*;
use gila::process;
use gila::memory;
@ -13,10 +15,21 @@ use gila::boot;
use gila::display::{self, TextWriter};
#[unsafe(no_mangle)]
pub extern "C" fn main() {
unsafe extern "C" fn main() -> !{
assert!(BASE_REVISION.is_supported());
let _smp_response = SMP_REQUEST.get_response();
loop {
unsafe {
#[cfg(target_arch = "x86_64")]
asm!("hlt");
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
asm!("wfi");
#[cfg(target_arch = "loongarch64")]
asm!("idle 0");
}
}
}