diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..58da6937 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.svg binary diff --git a/README.md b/README.md index 0758499b..a26ac6cd 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Obliteration is a free and open-source PlayStation 4 kernel rewritten in Rust. Our goal is not running on the PlayStation 4 but to run the dumped PlayStation 4 system software on Windows, Linux and macOS using a custom made virtualization stack optimized specifically for Obliteration. +

Architecture

+ This project started as a hard-fork from [Kyty](https://github.com/InoriRus/Kyty). Then we decided to rewrite the whole project from scratch by using Kyty and [Uplift](https://github.com/idc/uplift) as a reference to help us getting started with the project. Our ultimate goal is to become a permissive free and open-source operating system optimized for gaming that can run on a variety of hardware. The reason we want to built this because: @@ -21,7 +23,9 @@ The project logo and icon was designed by [VocalFan](https://github.com/VocalFan ## Status -Currently we cannot run any games yet. The reason it take so long is because we try to implement things without stubbing as much as possible. +Currently we cannot run any games yet. What we have is a working [64-bit](https://en.wikipedia.org/wiki/Long_mode) kernel and the VMM to run it. The kernel has been successfully setup [GDT](https://en.wikipedia.org/wiki/Global_Descriptor_Table), [TSS](https://en.wikipedia.org/wiki/Task_state_segment), [IDT](https://en.wikipedia.org/wiki/Interrupt_descriptor_table) and [syscall](https://en.wikipedia.org/wiki/System_call) instruction. Right now we are working on [UMA](https://man.freebsd.org/cgi/man.cgi?query=uma) system. Once this finished we will start migrating code from our [legacy user-mode kernel](https://github.com/obhq/obliteration/tree/main/legacy/src) then execute `mini-syscore.elf`. + +The reason it take so long is because we try to implement the kernel without stubbing as much as possible. ## Key features diff --git a/architecture.svg b/architecture.svg new file mode 100644 index 00000000..e83d9307 --- /dev/null +++ b/architecture.svg @@ -0,0 +1,4 @@ + + + +
Hardware
Hyper-V
Windows
Vulkan
obliteration.exe
WHP
obkrnl
Ring 0
Ring 3
mini-syscore.elf
SceSysCore.elf
SceShellCore.elf
...
eboot.bin
\ No newline at end of file diff --git a/gui/src/graphics/metal/window.rs b/gui/src/graphics/metal/window.rs index dad870ad..c8dc0970 100644 --- a/gui/src/graphics/metal/window.rs +++ b/gui/src/graphics/metal/window.rs @@ -1,5 +1,6 @@ use super::Metal; use crate::rt::{Hook, WindowHandler, WinitWindow}; +use crate::ui::DesktopWindow; use metal::{CAMetalLayer, MetalLayer}; use objc::runtime::{Object, NO, YES}; use objc::{msg_send, sel, sel_impl}; @@ -56,11 +57,10 @@ impl WinitWindow for MetalWindow { fn id(&self) -> WindowId { self.window.id() } +} - fn handle(&self) -> impl HasWindowHandle + '_ - where - Self: Sized, - { +impl DesktopWindow for MetalWindow { + fn handle(&self) -> impl HasWindowHandle + '_ { &self.window } } diff --git a/gui/src/graphics/vulkan/window.rs b/gui/src/graphics/vulkan/window.rs index 11caf48f..41edf286 100644 --- a/gui/src/graphics/vulkan/window.rs +++ b/gui/src/graphics/vulkan/window.rs @@ -1,6 +1,7 @@ use super::engine::Vulkan; use super::GraphicsError; use crate::rt::{Hook, WindowHandler, WinitWindow}; +use crate::ui::DesktopWindow; use ash::vk::SurfaceKHR; use raw_window_handle::HasWindowHandle; use std::error::Error; @@ -50,11 +51,10 @@ impl WinitWindow for VulkanWindow { fn id(&self) -> WindowId { self.window.id() } +} - fn handle(&self) -> impl HasWindowHandle + '_ - where - Self: Sized, - { +impl DesktopWindow for VulkanWindow { + fn handle(&self) -> impl HasWindowHandle + '_ { &self.window } diff --git a/gui/src/main.rs b/gui/src/main.rs index b16d382e..a03e6e76 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -8,7 +8,7 @@ use self::log::LogWriter; use self::profile::{DisplayResolution, Profile}; use self::setup::{run_setup, SetupError}; use self::ui::{ - DesktopWindow, MainWindow, ProfileModel, ResolutionModel, RuntimeExt, SlintBackend, + DesktopExt, MainWindow, ProfileModel, ResolutionModel, RuntimeExt, SlintBackend, WaitForDebugger, }; use self::vmm::{CpuError, Vmm, VmmError, VmmEvent}; diff --git a/gui/src/rt/window.rs b/gui/src/rt/window.rs index e02d4219..51238206 100644 --- a/gui/src/rt/window.rs +++ b/gui/src/rt/window.rs @@ -1,4 +1,3 @@ -use raw_window_handle::HasWindowHandle; use std::error::Error; use winit::dpi::{PhysicalPosition, PhysicalSize}; use winit::event::{DeviceId, ElementState, InnerSizeWriter, MouseButton}; @@ -34,9 +33,4 @@ pub trait WindowHandler: WinitWindow { /// Provides method to return winit properties. pub trait WinitWindow { fn id(&self) -> WindowId; - fn handle(&self) -> impl HasWindowHandle + '_ - where - Self: Sized; - #[cfg(target_os = "linux")] - fn xdg_toplevel(&self) -> *mut std::ffi::c_void; } diff --git a/gui/src/setup/mod.rs b/gui/src/setup/mod.rs index 56ca88c2..86a8584e 100644 --- a/gui/src/setup/mod.rs +++ b/gui/src/setup/mod.rs @@ -4,8 +4,8 @@ use self::data::{read_data_root, write_data_root}; use crate::data::{DataError, DataMgr}; use crate::rt::yield_now; use crate::ui::{ - error, open_dir, open_file, spawn_handler, DesktopWindow, FileType, InstallFirmware, - RuntimeExt, SetupWizard, + error, open_dir, open_file, spawn_handler, DesktopExt, FileType, InstallFirmware, RuntimeExt, + SetupWizard, }; use crate::vfs::{FsType, FS_TYPE}; use erdp::ErrorDisplay; diff --git a/gui/src/ui/backend/window.rs b/gui/src/ui/backend/window.rs index e5df6be6..ddeddcab 100644 --- a/gui/src/ui/backend/window.rs +++ b/gui/src/ui/backend/window.rs @@ -57,6 +57,10 @@ impl Window { .unwrap() } + pub fn winit(&self) -> &winit::window::Window { + &self.winit + } + pub fn hidden(&self) -> &Signal<()> { &self.hidden } @@ -66,20 +70,6 @@ impl WinitWindow for Window { fn id(&self) -> WindowId { self.winit.id() } - - fn handle(&self) -> impl HasWindowHandle + '_ - where - Self: Sized, - { - &self.winit - } - - #[cfg(target_os = "linux")] - fn xdg_toplevel(&self) -> *mut std::ffi::c_void { - use winit::platform::wayland::WindowExtWayland; - - self.winit.xdg_toplevel() - } } impl WindowHandler for Window { diff --git a/gui/src/ui/linux/dialogs.rs b/gui/src/ui/linux/dialogs.rs index 273a0a43..aedfb794 100644 --- a/gui/src/ui/linux/dialogs.rs +++ b/gui/src/ui/linux/dialogs.rs @@ -1,5 +1,5 @@ -use crate::rt::{global, WinitWindow}; -use crate::ui::{FileType, SlintBackend}; +use crate::rt::global; +use crate::ui::{DesktopWindow, FileType, SlintBackend}; use ashpd::desktop::file_chooser::{FileFilter, SelectedFiles}; use ashpd::desktop::ResponseError; use ashpd::WindowIdentifier; @@ -11,7 +11,7 @@ use wayland_client::protocol::wl_surface::WlSurface; use wayland_client::Proxy; use wayland_protocols::xdg::foreign::zv2::client::zxdg_exported_v2::ZxdgExportedV2; -pub async fn open_file( +pub async fn open_file( parent: &T, title: impl AsRef, ty: FileType, @@ -46,7 +46,7 @@ pub async fn open_file( Some(resp.uris().first().unwrap().to_file_path().unwrap()) } -pub async fn open_dir(parent: &T, title: impl AsRef) -> Option { +pub async fn open_dir(parent: &T, title: impl AsRef) -> Option { // Send the request let parent = get_parent_id(parent); let req = SelectedFiles::open_file() @@ -74,7 +74,7 @@ pub async fn open_dir(parent: &T, title: impl AsRef) -> Opt fn get_parent_id

(parent: &P) -> Parent where - P: WinitWindow, + P: DesktopWindow, { // Check window type. let parent = parent.handle(); diff --git a/gui/src/ui/linux/mod.rs b/gui/src/ui/linux/mod.rs index 34cd2bc4..e4b7b132 100644 --- a/gui/src/ui/linux/mod.rs +++ b/gui/src/ui/linux/mod.rs @@ -1,8 +1,8 @@ pub use self::dialogs::*; use self::modal::Modal; -use super::{DesktopWindow, SlintBackend}; -use crate::rt::{global, WinitWindow}; +use super::{DesktopExt, DesktopWindow, SlintBackend}; +use crate::rt::global; use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use thiserror::Error; @@ -10,11 +10,11 @@ mod dialogs; mod modal; mod wayland; -impl DesktopWindow for T { +impl DesktopExt for T { type Modal<'a, P> = Modal<'a, Self, P> where - P: WinitWindow + 'a; + P: DesktopWindow + 'a; fn set_center(&self) -> Result<(), PlatformError> { let win = self.handle(); @@ -33,7 +33,7 @@ impl DesktopWindow for T { fn set_modal

(self, parent: &P) -> Result, PlatformError> where - P: WinitWindow, + P: DesktopWindow, Self: Sized, { let back = global::().unwrap(); @@ -49,7 +49,7 @@ impl DesktopWindow for T { } } -/// Linux-specific error for [`PlatformExt`]. +/// Linux-specific error for [`DesktopExt`]. #[derive(Debug, Error)] pub enum PlatformError { #[error("couldn't create xdg_dialog_v1")] diff --git a/gui/src/ui/linux/modal.rs b/gui/src/ui/linux/modal.rs index 8f1982da..f545afe8 100644 --- a/gui/src/ui/linux/modal.rs +++ b/gui/src/ui/linux/modal.rs @@ -1,18 +1,19 @@ -use crate::rt::{block, Blocker, WinitWindow}; +use crate::rt::{block, Blocker}; +use crate::ui::DesktopWindow; use std::ops::Deref; use wayland_protocols::xdg::dialog::v1::client::xdg_dialog_v1::XdgDialogV1; /// Encapsulates a modal window and its parent. /// /// This struct forces the modal window to be dropped before its parent. -pub struct Modal<'a, W, P: WinitWindow> { +pub struct Modal<'a, W, P: DesktopWindow> { window: W, wayland: Option, #[allow(dead_code)] blocker: Blocker<'a, P>, } -impl<'a, W, P: WinitWindow> Modal<'a, W, P> { +impl<'a, W, P: DesktopWindow> Modal<'a, W, P> { pub fn new(window: W, parent: &'a P, wayland: Option) -> Self { Self { window, @@ -22,7 +23,7 @@ impl<'a, W, P: WinitWindow> Modal<'a, W, P> { } } -impl<'a, W, P: WinitWindow> Drop for Modal<'a, W, P> { +impl<'a, W, P: DesktopWindow> Drop for Modal<'a, W, P> { fn drop(&mut self) { if let Some(v) = self.wayland.take() { v.destroy(); @@ -30,7 +31,7 @@ impl<'a, W, P: WinitWindow> Drop for Modal<'a, W, P> { } } -impl<'a, W, P: WinitWindow> Deref for Modal<'a, W, P> { +impl<'a, W, P: DesktopWindow> Deref for Modal<'a, W, P> { type Target = W; fn deref(&self) -> &Self::Target { diff --git a/gui/src/ui/linux/wayland.rs b/gui/src/ui/linux/wayland.rs index d8ced4b8..45974702 100644 --- a/gui/src/ui/linux/wayland.rs +++ b/gui/src/ui/linux/wayland.rs @@ -1,6 +1,5 @@ use super::PlatformError; -use crate::rt::WinitWindow; -use crate::ui::Wayland; +use crate::ui::{DesktopWindow, Wayland}; use wayland_backend::sys::client::ObjectId; use wayland_client::Proxy; use wayland_protocols::xdg::dialog::v1::client::xdg_dialog_v1::XdgDialogV1; @@ -10,8 +9,8 @@ use wayland_protocols::xdg::shell::client::xdg_toplevel::XdgToplevel; /// `parent` must outlive `target`. pub unsafe fn set_modal( wayland: &Wayland, - target: &impl WinitWindow, - parent: &impl WinitWindow, + target: &impl DesktopWindow, + parent: &impl DesktopWindow, ) -> Result { // Get xdg_toplevel for parent. let mut queue = wayland.queue().borrow_mut(); @@ -40,7 +39,7 @@ pub unsafe fn set_modal( /// # Safety /// `win` must outlive the returned [`XdgToplevel`]. -unsafe fn get_xdg_toplevel(wayland: &Wayland, win: &impl WinitWindow) -> XdgToplevel { +unsafe fn get_xdg_toplevel(wayland: &Wayland, win: &impl DesktopWindow) -> XdgToplevel { let obj = win.xdg_toplevel(); let obj = ObjectId::from_ptr(XdgToplevel::interface(), obj.cast()).unwrap(); diff --git a/gui/src/ui/macos/dialogs.rs b/gui/src/ui/macos/dialogs.rs index 21af9f2b..c26ea801 100644 --- a/gui/src/ui/macos/dialogs.rs +++ b/gui/src/ui/macos/dialogs.rs @@ -1,8 +1,7 @@ -use crate::rt::WinitWindow; -use crate::ui::FileType; +use crate::ui::{DesktopWindow, FileType}; use std::path::PathBuf; -pub async fn open_file( +pub async fn open_file( parent: &T, title: impl AsRef, ty: FileType, @@ -10,6 +9,6 @@ pub async fn open_file( todo!(); } -pub async fn open_dir(parent: &T, title: impl AsRef) -> Option { +pub async fn open_dir(parent: &T, title: impl AsRef) -> Option { todo!() } diff --git a/gui/src/ui/macos/mod.rs b/gui/src/ui/macos/mod.rs index 952dcee5..d142bd68 100644 --- a/gui/src/ui/macos/mod.rs +++ b/gui/src/ui/macos/mod.rs @@ -2,8 +2,7 @@ pub use self::dialogs::*; use self::modal::Modal; use self::view::with_window; -use super::DesktopWindow; -use crate::rt::WinitWindow; +use super::{DesktopExt, DesktopWindow}; use block::ConcreteBlock; use objc::{msg_send, sel, sel_impl}; use std::ffi::c_long; @@ -14,11 +13,11 @@ mod dialogs; mod modal; mod view; -impl DesktopWindow for T { +impl DesktopExt for T { type Modal<'a, P> = Modal<'a, Self, P> where - P: WinitWindow + 'a; + P: DesktopWindow + 'a; fn set_center(&self) -> Result<(), PlatformError> { with_window::<()>(self.handle(), |win| unsafe { msg_send![win, center] }); @@ -28,7 +27,7 @@ impl DesktopWindow for T { fn set_modal

(self, parent: &P) -> Result, PlatformError> where - P: WinitWindow, + P: DesktopWindow, Self: Sized, { // Setup completionHandler. @@ -45,6 +44,6 @@ impl DesktopWindow for T { } } -/// macOS-specific error for [`DesktopWindow`]. +/// macOS-specific error for [`DesktopExt`]. #[derive(Debug, Error)] pub enum PlatformError {} diff --git a/gui/src/ui/macos/modal.rs b/gui/src/ui/macos/modal.rs index c6d43a6a..3d19a26f 100644 --- a/gui/src/ui/macos/modal.rs +++ b/gui/src/ui/macos/modal.rs @@ -1,16 +1,17 @@ -use crate::rt::{block, Blocker, WinitWindow}; +use crate::rt::{block, Blocker}; +use crate::ui::DesktopWindow; use std::ops::Deref; /// Encapsulates a modal window and its parent. /// /// This struct forces the modal window to be dropped before its parent. -pub struct Modal<'a, W, P: WinitWindow> { +pub struct Modal<'a, W, P: DesktopWindow> { window: W, #[allow(dead_code)] blocker: Blocker<'a, P>, } -impl<'a, W, P: WinitWindow> Modal<'a, W, P> { +impl<'a, W, P: DesktopWindow> Modal<'a, W, P> { pub(super) fn new(window: W, parent: &'a P) -> Self { Self { window, @@ -19,7 +20,7 @@ impl<'a, W, P: WinitWindow> Modal<'a, W, P> { } } -impl<'a, W, P: WinitWindow> Deref for Modal<'a, W, P> { +impl<'a, W, P: DesktopWindow> Deref for Modal<'a, W, P> { type Target = W; fn deref(&self) -> &Self::Target { diff --git a/gui/src/ui/mod.rs b/gui/src/ui/mod.rs index 59d367ee..9a1116f7 100644 --- a/gui/src/ui/mod.rs +++ b/gui/src/ui/mod.rs @@ -31,7 +31,7 @@ where spawn_blocker(w, f); } -pub async fn error(parent: Option<&P>, msg: impl Into) { +pub async fn error(parent: Option<&P>, msg: impl Into) { let win = ErrorWindow::new().unwrap(); win.set_message(msg.into()); @@ -55,27 +55,40 @@ pub async fn error(parent: Option<&P>, msg: impl Into WinitWindow for T { fn id(&self) -> WindowId { let win = WindowInner::from_pub(self.window()).window_adapter(); + let win = Window::from_adapter(win.as_ref()); - Window::from_adapter(win.as_ref()).id() + win.id() } +} +impl DesktopWindow for T { fn handle(&self) -> impl HasWindowHandle + '_ { self.window().window_handle() } #[cfg(target_os = "linux")] fn xdg_toplevel(&self) -> *mut std::ffi::c_void { - let win = WindowInner::from_pub(self.window()).window_adapter(); + use winit::platform::wayland::WindowExtWayland; - Window::from_adapter(win.as_ref()).xdg_toplevel() + let win = WindowInner::from_pub(self.window()).window_adapter(); + let win = Window::from_adapter(win.as_ref()); + + win.winit().xdg_toplevel() } } -/// Provides methods to operate on a desktop window. +/// Provides methods to return platform-specific handle for a desktop window. pub trait DesktopWindow: WinitWindow { + fn handle(&self) -> impl HasWindowHandle + '_; + #[cfg(target_os = "linux")] + fn xdg_toplevel(&self) -> *mut std::ffi::c_void; +} + +/// Provides methods to operate on a [`DesktopWindow`]. +pub trait DesktopExt: DesktopWindow { type Modal<'a, P>: Deref where - P: WinitWindow + 'a; + P: DesktopWindow + 'a; /// Center window on the screen. /// @@ -84,7 +97,7 @@ pub trait DesktopWindow: WinitWindow { fn set_center(&self) -> Result<(), PlatformError>; fn set_modal

(self, parent: &P) -> Result, PlatformError> where - P: WinitWindow, + P: DesktopWindow, Self: Sized; } diff --git a/gui/src/ui/windows/dialogs.rs b/gui/src/ui/windows/dialogs.rs index 976ad8fb..a93675d1 100644 --- a/gui/src/ui/windows/dialogs.rs +++ b/gui/src/ui/windows/dialogs.rs @@ -1,5 +1,4 @@ -use crate::rt::WinitWindow; -use crate::ui::FileType; +use crate::ui::{DesktopWindow, FileType}; use futures::channel::oneshot; use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use std::future::Future; @@ -11,31 +10,7 @@ use windows_sys::Win32::UI::Shell::{ SHBrowseForFolderW, SHGetPathFromIDListW, BIF_NEWDIALOGSTYLE, BIF_RETURNONLYFSDIRS, BROWSEINFOW, }; -fn get_hwnd(parent: &T) -> NonZero { - let parent = parent.handle(); - let parent = parent.window_handle().unwrap(); - let RawWindowHandle::Win32(win) = parent.as_ref() else { - unreachable!(); - }; - - win.hwnd -} - -fn spawn_dialog(dialog_fn: F) -> impl Future> -where - F: Send + 'static + FnOnce() -> Option, -{ - let (tx, rx) = oneshot::channel(); - - std::thread::spawn(move || { - let res = dialog_fn(); - tx.send(res).unwrap(); - }); - - async move { rx.await.unwrap_or(None) } -} - -pub async fn open_file( +pub async fn open_file( parent: &T, title: impl AsRef, ty: FileType, @@ -43,7 +18,7 @@ pub async fn open_file( todo!() } -pub async fn open_dir(parent: &T, title: impl AsRef) -> Option { +pub async fn open_dir(parent: &T, title: impl AsRef) -> Option { let hwnd = get_hwnd(parent); let title_wide: Vec = title @@ -81,3 +56,27 @@ pub async fn open_dir(parent: &T, title: impl AsRef) -> Opt }) .await } + +fn get_hwnd(parent: &T) -> NonZero { + let parent = parent.handle(); + let parent = parent.window_handle().unwrap(); + let RawWindowHandle::Win32(win) = parent.as_ref() else { + unreachable!(); + }; + + win.hwnd +} + +fn spawn_dialog(dialog_fn: F) -> impl Future> +where + F: Send + 'static + FnOnce() -> Option, +{ + let (tx, rx) = oneshot::channel(); + + std::thread::spawn(move || { + let res = dialog_fn(); + tx.send(res).unwrap(); + }); + + async move { rx.await.unwrap_or(None) } +} diff --git a/gui/src/ui/windows/mod.rs b/gui/src/ui/windows/mod.rs index 5d1b2013..99697f90 100644 --- a/gui/src/ui/windows/mod.rs +++ b/gui/src/ui/windows/mod.rs @@ -1,8 +1,7 @@ pub use self::dialogs::*; use self::modal::Modal; -use super::DesktopWindow; -use crate::rt::WinitWindow; +use super::{DesktopExt, DesktopWindow}; use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use std::io::Error; use std::mem::zeroed; @@ -16,11 +15,11 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ mod dialogs; mod modal; -impl DesktopWindow for T { +impl DesktopExt for T { type Modal<'a, P> = Modal<'a, Self, P> where - P: WinitWindow + 'a; + P: DesktopWindow + 'a; fn set_center(&self) -> Result<(), PlatformError> { // Get HWND. @@ -69,14 +68,14 @@ impl DesktopWindow for T { fn set_modal

(self, parent: &P) -> Result, PlatformError> where - P: WinitWindow, + P: DesktopWindow, Self: Sized, { todo!() } } -/// Windows-specific error for [`DesktopWindow`]. +/// Windows-specific error for [`DesktopExt`]. #[derive(Debug, Error)] pub enum PlatformError { #[error("couldn't get window rectangle")] diff --git a/gui/src/ui/windows/modal.rs b/gui/src/ui/windows/modal.rs index c6d43a6a..3d19a26f 100644 --- a/gui/src/ui/windows/modal.rs +++ b/gui/src/ui/windows/modal.rs @@ -1,16 +1,17 @@ -use crate::rt::{block, Blocker, WinitWindow}; +use crate::rt::{block, Blocker}; +use crate::ui::DesktopWindow; use std::ops::Deref; /// Encapsulates a modal window and its parent. /// /// This struct forces the modal window to be dropped before its parent. -pub struct Modal<'a, W, P: WinitWindow> { +pub struct Modal<'a, W, P: DesktopWindow> { window: W, #[allow(dead_code)] blocker: Blocker<'a, P>, } -impl<'a, W, P: WinitWindow> Modal<'a, W, P> { +impl<'a, W, P: DesktopWindow> Modal<'a, W, P> { pub(super) fn new(window: W, parent: &'a P) -> Self { Self { window, @@ -19,7 +20,7 @@ impl<'a, W, P: WinitWindow> Modal<'a, W, P> { } } -impl<'a, W, P: WinitWindow> Deref for Modal<'a, W, P> { +impl<'a, W, P: DesktopWindow> Deref for Modal<'a, W, P> { type Target = W; fn deref(&self) -> &Self::Target {