init
This commit is contained in:
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/limine
|
||||||
|
/ovmf
|
||||||
|
*.iso
|
||||||
|
*.hdd
|
||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
**/*.rlib
|
||||||
|
**/Cargo.lock
|
||||||
|
/kernel/build.rs
|
||||||
|
/kernel/linker-*.ld
|
||||||
|
/kernel/*.o
|
||||||
|
/kernel/*.elf
|
||||||
|
/kernel/*.bin
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.DS_Store
|
||||||
|
*.idea/
|
||||||
|
*.vscode/
|
||||||
251
GNUmakefile
Normal file
251
GNUmakefile
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# Nuke built-in rules and variables.
|
||||||
|
MAKEFLAGS += -rR
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
# Convenience macro to reliably declare user overridable variables.
|
||||||
|
override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2)))
|
||||||
|
|
||||||
|
# Target architecture to build for. Default to x86_64.
|
||||||
|
$(call USER_VARIABLE,KARCH,x86_64)
|
||||||
|
|
||||||
|
# Default user QEMU flags. These are appended to the QEMU command calls.
|
||||||
|
$(call USER_VARIABLE,QEMUFLAGS,-m 2G)
|
||||||
|
|
||||||
|
override IMAGE_NAME := elyz-$(KARCH)
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(IMAGE_NAME).iso
|
||||||
|
|
||||||
|
.PHONY: all-hdd
|
||||||
|
all-hdd: $(IMAGE_NAME).hdd
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run: run-$(KARCH)
|
||||||
|
|
||||||
|
.PHONY: run-hdd
|
||||||
|
run-hdd: run-hdd-$(KARCH)
|
||||||
|
|
||||||
|
.PHONY: run-x86_64
|
||||||
|
run-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-x86_64
|
||||||
|
run-hdd-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-aarch64
|
||||||
|
run-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu cortex-a72 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-aarch64
|
||||||
|
run-hdd-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu cortex-a72 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-riscv64
|
||||||
|
run-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu rv64 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-riscv64
|
||||||
|
run-hdd-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu rv64 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-loongarch64
|
||||||
|
run-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu la464 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-loongarch64
|
||||||
|
run-hdd-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu la464 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: run-bios
|
||||||
|
run-bios: $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
-boot d \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-bios
|
||||||
|
run-hdd-bios: $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
ovmf/ovmf-code-$(KARCH).fd:
|
||||||
|
mkdir -p ovmf
|
||||||
|
curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-code-$(KARCH).fd
|
||||||
|
case "$(KARCH)" in \
|
||||||
|
aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \
|
||||||
|
loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \
|
||||||
|
riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \
|
||||||
|
esac
|
||||||
|
|
||||||
|
ovmf/ovmf-vars-$(KARCH).fd:
|
||||||
|
mkdir -p ovmf
|
||||||
|
curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-vars-$(KARCH).fd
|
||||||
|
case "$(KARCH)" in \
|
||||||
|
aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \
|
||||||
|
loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \
|
||||||
|
riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \
|
||||||
|
esac
|
||||||
|
|
||||||
|
limine/limine:
|
||||||
|
rm -rf limine
|
||||||
|
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
|
||||||
|
$(MAKE) -C limine
|
||||||
|
|
||||||
|
.PHONY: kernel
|
||||||
|
kernel:
|
||||||
|
$(MAKE) -C kernel
|
||||||
|
|
||||||
|
$(IMAGE_NAME).iso: limine/limine kernel
|
||||||
|
rm -rf iso_root
|
||||||
|
mkdir -p iso_root/boot
|
||||||
|
cp -v kernel/kernel iso_root/boot/
|
||||||
|
mkdir -p iso_root/boot/limine
|
||||||
|
cp -v limine.conf iso_root/boot/limine/
|
||||||
|
mkdir -p iso_root/EFI/BOOT
|
||||||
|
ifeq ($(KARCH),x86_64)
|
||||||
|
cp -v limine/limine-bios.sys limine/limine-bios-cd.bin limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT/
|
||||||
|
cp -v limine/BOOTIA32.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs -b boot/limine/limine-bios-cd.bin \
|
||||||
|
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
./limine/limine bios-install $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),aarch64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTAA64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),riscv64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTRISCV64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),loongarch64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTLOONGARCH64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
rm -rf iso_root
|
||||||
|
|
||||||
|
$(IMAGE_NAME).hdd: limine/limine kernel
|
||||||
|
rm -f $(IMAGE_NAME).hdd
|
||||||
|
dd if=/dev/zero bs=1M count=0 seek=64 of=$(IMAGE_NAME).hdd
|
||||||
|
sgdisk $(IMAGE_NAME).hdd -n 1:2048 -t 1:ef00
|
||||||
|
ifeq ($(KARCH),x86_64)
|
||||||
|
./limine/limine bios-install $(IMAGE_NAME).hdd
|
||||||
|
endif
|
||||||
|
mformat -i $(IMAGE_NAME).hdd@@1M
|
||||||
|
mmd -i $(IMAGE_NAME).hdd@@1M ::/EFI ::/EFI/BOOT ::/boot ::/boot/limine
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M kernel/bin-$(KARCH)/kernel ::/boot
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine.conf ::/boot/limine
|
||||||
|
ifeq ($(KARCH),x86_64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/limine-bios.sys ::/boot/limine
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),aarch64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTAA64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),riscv64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTRISCV64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),loongarch64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTLOONGARCH64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C kernel clean
|
||||||
|
rm -rf iso_root $(IMAGE_NAME).iso $(IMAGE_NAME).hdd
|
||||||
|
|
||||||
|
.PHONY: distclean
|
||||||
|
distclean: clean
|
||||||
|
$(MAKE) -C kernel distclean
|
||||||
|
rm -rf limine ovmf
|
||||||
12
LICENSE
Normal file
12
LICENSE
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Copyright (C) 2023-2024 mintsuki and contributors.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
98
README.md
Normal file
98
README.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# 🦀 Elyz
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📂 Структура проекта
|
||||||
|
|
||||||
|
* `kernel/` — Исходный код ядра на.
|
||||||
|
* `limine/` — Файлы загрузчика Limine.
|
||||||
|
* `ovmf/` — Файлы прошивки для поддержки загрузки через UEFI.
|
||||||
|
* `limine.conf` — Конфигурация меню загрузки.
|
||||||
|
* `GNUmakefile` — Основной сценарий сборки и запуска.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠 Требования
|
||||||
|
|
||||||
|
Для работы со сборкой понадобятся следующие инструменты:
|
||||||
|
|
||||||
|
| Инструмент | Описание |
|
||||||
|
| :--- | :--- |
|
||||||
|
| **GNU Make** | Утилита для сборки (`make`). |
|
||||||
|
| **Rust** | Nightly версия, включая `rust-src`. |
|
||||||
|
| **xorriso** | Необходим для создания загрузочных ISO-образов. |
|
||||||
|
| **sgdisk & mtools** | Необходимы для создания образов жесткого диска (HDD/USB). |
|
||||||
|
| **QEMU** | Эмулятор для тестирования ядра. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Запуск и отладка
|
||||||
|
|
||||||
|
* **Склонируйте репозиторий**
|
||||||
|
```bash
|
||||||
|
git clone https://git.inotfail.com/INotFail/elyz.git
|
||||||
|
cd elyz
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Сборка ядра**
|
||||||
|
```bash
|
||||||
|
cd kernel
|
||||||
|
make all
|
||||||
|
cd ../
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Запуск (основные способы)**
|
||||||
|
```bash
|
||||||
|
make run-bios
|
||||||
|
```
|
||||||
|
или
|
||||||
|
```bash
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
или
|
||||||
|
```bash
|
||||||
|
make run-uefi
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
`make all` скомпилирует ядро (из kernel/), а затем сгенерирует загрузочный ISO-образ.
|
||||||
|
|
||||||
|
`make run` соберет ядро и загрузочный ISO-образ (эквивалент команды make all), а затем запустит его с помощью команды qemu (если установлено).
|
||||||
|
|
||||||
|
`make all-hdd` скомпилирует ядро, а затем сгенерирует исходный образ, подходящий для записи на USB-накопитель или жесткий диск/SSD.
|
||||||
|
|
||||||
|
`make run-hdd` соберет ядро и необработанный образ жесткого диска (эквивалентно созданию образа для всех жестких дисков), а затем запустит его с помощью qemu (если установлено).
|
||||||
|
|
||||||
|
`run-uefi` и `run-hdd-uefi` цели эквивалентны своим нецелевым `-uefi` аналогам, за исключением того, что они загружаются `qemu` с использованием прошивки, совместимой с UEFI.
|
||||||
|
|
||||||
|
|
||||||
|
## 🏗 Поддерживаемые архитектуры
|
||||||
|
|
||||||
|
Переменная `KARCH` определяет целевую архитектуру. По умолчанию используется `x86_64`.
|
||||||
|
|
||||||
|
Вы можете изменить архитектуру при вызове `make`:
|
||||||
|
```bash
|
||||||
|
make run KARCH=aarch64
|
||||||
|
```
|
||||||
|
|
||||||
|
**Доступные варианты:**
|
||||||
|
* `x86_64` (Default)
|
||||||
|
* `aarch64`
|
||||||
|
* `riscv64`
|
||||||
|
* `loongarch64`
|
||||||
|
|
||||||
|
> Для архитектур, отличных от x86, потребуется настройка соответствующих целевых платформ в `kernel/rust-toolchain.toml`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Важное
|
||||||
|
|
||||||
|
* **Очистка проекта:** Чтобы удалить все артефакты сборки и скомпилированные файлы, выполните:
|
||||||
|
```bash
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
* **Логи:** Ядро выводит данные в консоль QEMU.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Boot основан на оригинальном шаблоне:** [jasondyoungberg/limine-rust-template](https://github.com/jasondyoungberg/limine-rust-template)
|
||||||
2
kernel/.gitignore
vendored
Normal file
2
kernel/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/kernel
|
||||||
|
/target
|
||||||
18
kernel/Cargo.toml
Normal file
18
kernel/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "RINA"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "kernel"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
limine = "0.5"
|
||||||
|
embedded-graphics = "0.8"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
44
kernel/GNUmakefile
Normal file
44
kernel/GNUmakefile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Nuke built-in rules and variables.
|
||||||
|
MAKEFLAGS += -rR
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
# This is the name that our final executable will have.
|
||||||
|
# Change as needed.
|
||||||
|
override OUTPUT := kernel
|
||||||
|
|
||||||
|
# Convenience macro to reliably declare user overridable variables.
|
||||||
|
override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2)))
|
||||||
|
|
||||||
|
# Target architecture to build for. Default to x86_64.
|
||||||
|
$(call USER_VARIABLE,KARCH,x86_64)
|
||||||
|
|
||||||
|
ifeq ($(RUST_TARGET),)
|
||||||
|
override RUST_TARGET := $(KARCH)-unknown-none
|
||||||
|
ifeq ($(KARCH),riscv64)
|
||||||
|
override RUST_TARGET := riscv64gc-unknown-none-elf
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(RUST_PROFILE),)
|
||||||
|
override RUST_PROFILE := dev
|
||||||
|
endif
|
||||||
|
|
||||||
|
override RUST_PROFILE_SUBDIR := $(RUST_PROFILE)
|
||||||
|
ifeq ($(RUST_PROFILE),dev)
|
||||||
|
override RUST_PROFILE_SUBDIR := debug
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Default target.
|
||||||
|
.PHONY: all
|
||||||
|
all:
|
||||||
|
RUSTFLAGS="-C relocation-model=static" cargo build --target $(RUST_TARGET) --profile $(RUST_PROFILE)
|
||||||
|
cp target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR)/$$(cd target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR) && find -maxdepth 1 -perm -111 -type f) kernel
|
||||||
|
|
||||||
|
# Remove object files and the final executable.
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
cargo clean
|
||||||
|
rm -rf kernel
|
||||||
|
|
||||||
|
.PHONY: distclean
|
||||||
|
distclean: clean
|
||||||
8
kernel/rust-toolchain.toml
Normal file
8
kernel/rust-toolchain.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
|
targets = [
|
||||||
|
"x86_64-unknown-none",
|
||||||
|
# "aarch64-unknown-none",
|
||||||
|
# "riscv64gc-unknown-none-elf",
|
||||||
|
# "loongarch64-unknown-none",
|
||||||
|
]
|
||||||
193
kernel/src/main.rs
Normal file
193
kernel/src/main.rs
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
|
use core::fmt::{self, Write};
|
||||||
|
use limine::BaseRevision;
|
||||||
|
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker};
|
||||||
|
|
||||||
|
use embedded_graphics::{
|
||||||
|
mono_font::{ascii::FONT_6X10, MonoTextStyle},
|
||||||
|
pixelcolor::Rgb888,
|
||||||
|
prelude::*,
|
||||||
|
text::Text,
|
||||||
|
Drawable,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Отрисовка пикселей
|
||||||
|
struct FramebufferDisplay<'a> {
|
||||||
|
framebuffer: &'a limine::framebuffer::Framebuffer<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawTarget for FramebufferDisplay<'_> {
|
||||||
|
type Color = Rgb888;
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
|
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||||
|
where I: IntoIterator<Item = Pixel<Self::Color>> {
|
||||||
|
for Pixel(coord, color) in pixels {
|
||||||
|
if coord.x >= 0 && coord.x < self.framebuffer.width() as i32 &&
|
||||||
|
coord.y >= 0 && coord.y < self.framebuffer.height() as i32 {
|
||||||
|
|
||||||
|
let offset = (coord.y as usize * self.framebuffer.pitch() as usize) + (coord.x as usize * 4);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.framebuffer.addr().add(offset).cast::<u32>().write(color.into_storage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OriginDimensions for FramebufferDisplay<'_> {
|
||||||
|
fn size(&self) -> Size {
|
||||||
|
Size::new(self.framebuffer.width() as u32, self.framebuffer.height() as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Терминальный вывод. Следит за положением курсора и умеет двигать текст
|
||||||
|
struct Console<'a> {
|
||||||
|
display: FramebufferDisplay<'a>,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Console<'a> {
|
||||||
|
pub fn new(display: FramebufferDisplay<'a>) -> Self {
|
||||||
|
Self { display, x: 10, y: 20 } // Начальный отступ
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод для очистки экрана
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
let size = self.display.size();
|
||||||
|
let fb = self.display.framebuffer;
|
||||||
|
unsafe {
|
||||||
|
// Быстрая очистка через заполнение памяти нулями
|
||||||
|
core::ptr::write_bytes(fb.addr(), 0, fb.pitch() as usize * fb.height() as usize);
|
||||||
|
}
|
||||||
|
self.x = 10;
|
||||||
|
self.y = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Логика скроллинга. копирует пиксели снизу вверх
|
||||||
|
fn scroll(&mut self) {
|
||||||
|
let fb = self.display.framebuffer;
|
||||||
|
let pitch = fb.pitch() as usize;
|
||||||
|
let height = fb.height() as usize;
|
||||||
|
let font_height = 10; // Высота FONT_6X10
|
||||||
|
let shift = font_height * pitch;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let addr = fb.addr();
|
||||||
|
// Копируем всё содержимое экрана на одну строку вверх
|
||||||
|
core::ptr::copy(
|
||||||
|
addr.add(shift),
|
||||||
|
addr,
|
||||||
|
pitch * (height - font_height)
|
||||||
|
);
|
||||||
|
// Очищаем последнюю строку
|
||||||
|
core::ptr::write_bytes(
|
||||||
|
addr.add(pitch * (height - font_height)),
|
||||||
|
0,
|
||||||
|
shift
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.y -= font_height as i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывод текста. write!(console, "Hello {}", name)
|
||||||
|
impl fmt::Write for Console<'_> {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
let style = MonoTextStyle::new(&FONT_6X10, Rgb888::WHITE);
|
||||||
|
|
||||||
|
for c in s.chars() {
|
||||||
|
if c == '\n' {
|
||||||
|
self.x = 10;
|
||||||
|
self.y += 10;
|
||||||
|
} else {
|
||||||
|
// Если текст выходит за границы экрана — перенос строки
|
||||||
|
if self.x + 6 > self.display.framebuffer.width() as i32 {
|
||||||
|
self.x = 10;
|
||||||
|
self.y += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Рисуем символ (превращаем char в временную строку &str)
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
let s_char = c.encode_utf8(&mut buf);
|
||||||
|
let _ = Text::new(s_char, Point::new(self.x, self.y), style).draw(&mut self.display);
|
||||||
|
|
||||||
|
self.x += 6; // Ширина FONT_6X10
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если достигли низа экрана, то скроллим
|
||||||
|
if self.y > self.display.framebuffer.height() as i32 - 10 {
|
||||||
|
self.scroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// boot
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".requests")]
|
||||||
|
static BASE_REVISION: BaseRevision = BaseRevision::new();
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".requests")]
|
||||||
|
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
||||||
|
|
||||||
|
#[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();
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
unsafe extern "C" fn kmain() -> ! {
|
||||||
|
assert!(BASE_REVISION.is_supported());
|
||||||
|
|
||||||
|
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
|
||||||
|
if let Some(fb) = framebuffer_response.framebuffers().next() {
|
||||||
|
|
||||||
|
// Инициализируем консоль
|
||||||
|
let mut console = Console::new(FramebufferDisplay { framebuffer: &fb });
|
||||||
|
console.clear();
|
||||||
|
|
||||||
|
let _ = writeln!(console, "RINA Kernel");
|
||||||
|
let _ = writeln!(console, "-----------------------");
|
||||||
|
let _ = writeln!(console, "Framebuffer: {}x{}", fb.width(), fb.height());
|
||||||
|
let _ = writeln!(console, "Memory mapping... OK");
|
||||||
|
let _ = writeln!(console, "Hello, Arina! Terminal mode active :3");
|
||||||
|
|
||||||
|
// Тест скроллинга: выведем много строк
|
||||||
|
for i in 0..5 {
|
||||||
|
let _ = writeln!(console, "System log entry #{}", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
// В будущем тут будет выводиться текст ошибки
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hcf() -> ! {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
limine.conf
Normal file
10
limine.conf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Timeout in seconds that Limine will use before automatically booting.
|
||||||
|
timeout: 3
|
||||||
|
|
||||||
|
# The entry name that will be displayed in the boot menu.
|
||||||
|
/Elyz (RINA KERNEL)
|
||||||
|
# We use the Limine boot protocol.
|
||||||
|
protocol: limine
|
||||||
|
|
||||||
|
# Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located.
|
||||||
|
kernel_path: boot():/boot/kernel
|
||||||
Reference in New Issue
Block a user