forked from koniifer/ableos
adding a deadlock to master :>
This commit is contained in:
parent
25e87735e6
commit
a4cc9cdf4f
60
Cargo.lock
generated
60
Cargo.lock
generated
|
@ -29,9 +29,9 @@ dependencies = [
|
|||
"ab_glyph",
|
||||
"acpi",
|
||||
"axel",
|
||||
"bitflags",
|
||||
"bootloader",
|
||||
"cpuio",
|
||||
"embedded-graphics",
|
||||
"ext2",
|
||||
"externc-libm",
|
||||
"facepalm",
|
||||
|
@ -134,7 +134,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|||
[[package]]
|
||||
name = "axel"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.ablecorp.us/able/aos_userland#a9721a7b034ec24c3bc2b6ffe6fa989b47b144ef"
|
||||
source = "git+https://git.ablecorp.us/able/aos_userland#7f61266a9b6a5d0032ff84b3ee971eb7b14bd1fa"
|
||||
dependencies = [
|
||||
"hashbrown 0.7.2",
|
||||
"log",
|
||||
|
@ -142,12 +142,6 @@ dependencies = [
|
|||
"versioning",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "az"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "1.0.0"
|
||||
|
@ -178,12 +172,6 @@ version = "0.9.22"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de78decc37247c7cfac5dbf3495c7298c6ac97cb355161caa7e15969c6648e6c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -283,29 +271,6 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-graphics"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "750082c65094fbcc4baf9ba31583ce9a8bb7f52cadfb96f6164b1bc7f922f32b"
|
||||
dependencies = [
|
||||
"az",
|
||||
"byteorder",
|
||||
"embedded-graphics-core",
|
||||
"float-cmp",
|
||||
"micromath",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-graphics-core"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8b1239db5f3eeb7e33e35bd10bd014e7b2537b17e071f726a09351431337cfa"
|
||||
dependencies = [
|
||||
"az",
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ext2"
|
||||
version = "0.1.1"
|
||||
|
@ -331,15 +296,6 @@ dependencies = [
|
|||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -490,9 +446,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.16"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
@ -533,12 +489,6 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882"
|
||||
|
||||
[[package]]
|
||||
name = "micromath"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc4010833aea396656c2f91ee704d51a6f1329ec2ab56ffd00bfd56f7481ea94"
|
||||
|
||||
[[package]]
|
||||
name = "no-std-compat"
|
||||
version = "0.4.1"
|
||||
|
@ -1029,7 +979,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||
[[package]]
|
||||
name = "versioning"
|
||||
version = "0.1.2"
|
||||
source = "git+https://git.ablecorp.us/able/aos_userland#a9721a7b034ec24c3bc2b6ffe6fa989b47b144ef"
|
||||
source = "git+https://git.ablecorp.us/able/aos_userland#7f61266a9b6a5d0032ff84b3ee971eb7b14bd1fa"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
BIN
__pycache__/qmp.cpython-310.pyc
Normal file
BIN
__pycache__/qmp.cpython-310.pyc
Normal file
Binary file not shown.
|
@ -46,14 +46,13 @@ test-args = [
|
|||
]
|
||||
|
||||
[dependencies]
|
||||
lazy_static = { version = "*", features = ["spin_no_std"] }
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
qrcode = { path = "../qrcode-rust" }
|
||||
|
||||
|
||||
bitflags = "1.2.1"
|
||||
linked_list_allocator = "0.9.0"
|
||||
lliw = "0.2.0"
|
||||
spin = "0.9"
|
||||
log = "*"
|
||||
log = "0.4.17"
|
||||
pretty-hex = "0.2.1"
|
||||
unicode-width = "0.1.7"
|
||||
picorand = "0.1.0"
|
||||
|
@ -63,8 +62,9 @@ rhai = "1.6.0"
|
|||
libwasm = { git = "https://git.ablecorp.us:443/able/libwasm.git" }
|
||||
axel = { git = "https://git.ablecorp.us/able/aos_userland" }
|
||||
versioning = { git = "https://git.ablecorp.us/able/aos_userland" }
|
||||
embedded-graphics = "*"
|
||||
# embedded-graphics = "*"
|
||||
pc-keyboard = "0.5"
|
||||
|
||||
[dependencies.logos]
|
||||
version = "0.12"
|
||||
default-features = false
|
||||
|
@ -138,7 +138,7 @@ cpuio = { git = "https://git.ablecorp.us/ondra05/cpuio.git" }
|
|||
pic8259 = "0.10.1"
|
||||
uart_16550 = "0.2.0"
|
||||
volatile = "0.2.6"
|
||||
x86_64 = "*"
|
||||
x86_64 = "0.14.8"
|
||||
pc-beeper = { git = "https://github.com/AbleOS/pc-beeper" }
|
||||
vga = "*"
|
||||
vga = "0.2.7"
|
||||
acpi = "4.1.0"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub mod allocator;
|
||||
pub mod graphics;
|
||||
// pub mod graphics;
|
||||
pub mod serial;
|
||||
pub mod sysinfo;
|
||||
pub mod timer;
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
// #![allow(clippy::print_literal)]
|
||||
use super::{gdt, interrupts};
|
||||
use super::{drivers::serial, gdt, interrupts};
|
||||
use crate::{logger, serial_println};
|
||||
|
||||
/// x86_64 initialization
|
||||
pub fn init() {
|
||||
use crate::{network::socket::SimpleSock, relib::network::socket::Socket};
|
||||
// use crate::{network::socket::SimpleSock, relib::network::socket::Socket};
|
||||
|
||||
let mut log_socket_id = SimpleSock::new();
|
||||
log_socket_id.register_protocol("Logger".to_string());
|
||||
// let mut log_socket_id = SimpleSock::new();
|
||||
// log_socket_id.register_protocol("Logger".to_string());
|
||||
|
||||
let result = logger::init();
|
||||
match result {
|
||||
Ok(_) => {
|
||||
serial_println!("Logger initialized");
|
||||
info!("Logger initialized");
|
||||
}
|
||||
Err(err) => error!("{}", err),
|
||||
Err(err) => serial_println!("{}", err),
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
gdt::init();
|
||||
|
||||
interrupts::init_idt();
|
||||
|
|
|
@ -18,6 +18,8 @@ use spin::Lazy;
|
|||
use vga::colors::Color16;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
|
||||
use super::sloop;
|
||||
|
||||
pub const PIC_1_OFFSET: u8 = 32;
|
||||
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
||||
|
||||
|
@ -30,6 +32,9 @@ pub static PICS: spin::Mutex<ChainedPics> =
|
|||
pub enum InterruptIndex {
|
||||
Timer = PIC_1_OFFSET,
|
||||
Keyboard,
|
||||
/// Mouse offset
|
||||
Mouse = 44,
|
||||
|
||||
// SecondInterrupt = PIC_2_OFFSET,
|
||||
Cmos = 0x70,
|
||||
}
|
||||
|
@ -56,11 +61,11 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
|||
|
||||
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
||||
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||
|
||||
idt[6].set_handler_fn(floppy_disk_interrupt_handler);
|
||||
idt[InterruptIndex::Mouse.as_usize()].set_handler_fn(crate::hardware::mouse_interrupt_handler);
|
||||
|
||||
// run `a + b + l + e + o + s print;` in ablescript and its 54 thats why this seemingly arbitrary number was chosen
|
||||
idt[54].set_handler_fn(software_int_handler);
|
||||
|
||||
idt
|
||||
});
|
||||
|
||||
|
@ -78,7 +83,7 @@ extern "x86-interrupt" fn double_fault_handler(
|
|||
_error_code: u64,
|
||||
) -> ! {
|
||||
bsod(BSODSource::DoubleFault(&stack_frame));
|
||||
// panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||
}
|
||||
|
||||
#[naked]
|
||||
|
@ -87,6 +92,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
|
|||
unsafe {
|
||||
// print!(".");
|
||||
asm!(
|
||||
|
||||
// Kernel tick
|
||||
"call {tick}",
|
||||
|
||||
|
@ -99,7 +105,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
|
|||
// Switch to next task (interrupt'll be returned there)
|
||||
"jmp {switch_to_next}",
|
||||
|
||||
tick = sym kernel::tick,
|
||||
tick = sym crate::kmain::tick,
|
||||
save = sym task_switcher::save_and_enqueue,
|
||||
switch_to_next = sym task_switcher::switch_to_next,
|
||||
options(noreturn),
|
||||
|
@ -122,14 +128,16 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
|
|||
.add_byte(unsafe { Port::new(0x60).read() })
|
||||
.map(|x| x.and_then(|ev| keyboard.process_keyevent(ev)))
|
||||
{
|
||||
trace!("{key:?}");
|
||||
match key {
|
||||
DecodedKey::Unicode(chr) => match chr {
|
||||
// Backspace
|
||||
'\u{8}' => {
|
||||
// TODO: Fix this and apply to new term
|
||||
WRITER.lock().backspace();
|
||||
KEYBUFF.lock().push(8.into());
|
||||
}
|
||||
'^' => KERNEL_STATE.lock().shutdown(),
|
||||
// '^' => KERNEL_STATE.lock().shutdown(),
|
||||
chr => {
|
||||
KEYBUFF.lock().push(chr);
|
||||
print!("{chr}");
|
||||
|
@ -155,10 +163,6 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
|
|||
}
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn floppy_disk_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
println!("EXCEPTION: FLOPPY DISK");
|
||||
}
|
||||
|
||||
pub fn init_idt() {
|
||||
IDT.load();
|
||||
}
|
||||
|
@ -200,6 +204,8 @@ pub fn reset_pit_for_cpu() {
|
|||
set_pit_3(1000);
|
||||
}
|
||||
pub fn bsod(src: BSODSource) -> ! {
|
||||
trace!("{src:?}");
|
||||
|
||||
let mut mode = SCREEN_BUFFER.lock();
|
||||
mode.force_redraw();
|
||||
/*
|
||||
|
@ -214,17 +220,20 @@ pub fn bsod(src: BSODSource) -> ! {
|
|||
let mut y = 0;
|
||||
|
||||
let src1 = match src {
|
||||
BSODSource::DoubleFault(_) => "DoubleFault",
|
||||
BSODSource::Panic(_) => "Panic",
|
||||
BSODSource::DoubleFault(_) => "DoubleFault".to_string(),
|
||||
BSODSource::Panic(panic_info) => {
|
||||
let strr = format!("PANIC: {}", panic_info);
|
||||
strr
|
||||
}
|
||||
};
|
||||
|
||||
let st = format!(
|
||||
"We fucked up ඞ : {}\nThe following qr code will link you to the\nwiki which hopefully solves your problems",
|
||||
"We fucked up ඞ : \n{}\nThe following qr code will link you to the wiki which hopefully solves your problems",
|
||||
src1
|
||||
);
|
||||
|
||||
for current in st.chars() {
|
||||
if current == '\n' {
|
||||
if current == '\n' || x == 40 {
|
||||
y += 1;
|
||||
x = 1;
|
||||
} else {
|
||||
|
@ -239,16 +248,15 @@ pub fn bsod(src: BSODSource) -> ! {
|
|||
}
|
||||
|
||||
let mut x = 1;
|
||||
let mut y = 11;
|
||||
let mut y = 34;
|
||||
|
||||
// let sf = format!("https://git.ablecorp.us/able/ableos/wiki/Double-Faults");
|
||||
|
||||
let sd = match src {
|
||||
BSODSource::DoubleFault(_) => "https://git.ablecorp.us/able/ableos/wiki/Double-Faults",
|
||||
BSODSource::Panic(_) => {
|
||||
//
|
||||
trace!("panic");
|
||||
"https://git.ablecorp.us/able/ableos/wiki/"
|
||||
"https://git.ablecorp.us/able/ableos/wiki/Panic"
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -274,7 +282,7 @@ pub fn bsod(src: BSODSource) -> ! {
|
|||
|
||||
mode.copy_to_buffer();
|
||||
|
||||
loop {}
|
||||
sloop();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::driver_traits::graphics::Point;
|
||||
// use crate::driver_traits::graphics::Point;
|
||||
|
||||
pub type MenuBar = Vec<MenuOption>;
|
||||
|
||||
|
@ -8,16 +8,16 @@ pub struct MenuOption {
|
|||
|
||||
pub struct Window {
|
||||
title: String,
|
||||
position: Point,
|
||||
// position: Point,
|
||||
fullscreen: bool,
|
||||
}
|
||||
|
||||
// all of these should return a result
|
||||
impl Window {
|
||||
pub fn new(title: String, position: Point, fullscreen: bool) -> Self {
|
||||
pub fn new(title: String, /*position: Point,*/ fullscreen: bool) -> Self {
|
||||
Self {
|
||||
title,
|
||||
position,
|
||||
// position,
|
||||
fullscreen,
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ impl Window {
|
|||
pub fn set_title(&mut self) {
|
||||
todo!();
|
||||
}
|
||||
pub fn set_position(&mut self, pos: Point) {
|
||||
self.position = pos;
|
||||
pub fn set_position(&mut self /*pos: Point*/) {
|
||||
// self.position = pos;
|
||||
}
|
||||
}
|
||||
|
|
130
ableos/src/hardware/mod.rs
Normal file
130
ableos/src/hardware/mod.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
use crate::arch::interrupts::InterruptIndex;
|
||||
use crate::arch::interrupts::PICS;
|
||||
use crate::ps2_mouse::{Mouse, MouseState};
|
||||
use crate::vga_e::VGAE;
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use spin::Mutex;
|
||||
use vga::colors::Color16;
|
||||
use vga::writers::GraphicsWriter;
|
||||
use x86_64::instructions::port::PortReadOnly;
|
||||
use x86_64::structures::idt::InterruptStackFrame;
|
||||
|
||||
const MOUSE_MAX_X: u16 = 638;
|
||||
const MOUSE_MAX_Y: u16 = 478;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref _MOUSE: Mutex<Mouse> = Mutex::new(Mouse::new());
|
||||
pub static ref MOUSE: Mutex<OnScreenMouse> = Mutex::new(OnScreenMouse::default());
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OnScreenMouse {
|
||||
// absolute position on screen
|
||||
x: u16,
|
||||
// absolute position on screen
|
||||
y: u16,
|
||||
}
|
||||
|
||||
impl OnScreenMouse {
|
||||
pub fn get_x(&self) -> u16 {
|
||||
return self.x;
|
||||
}
|
||||
|
||||
pub fn get_y(&self) -> u16 {
|
||||
return self.y;
|
||||
}
|
||||
|
||||
pub fn change_x(&mut self, delta_x: i16) {
|
||||
if delta_x.is_negative() {
|
||||
self.x = self.x.saturating_sub((-delta_x) as u16)
|
||||
} else {
|
||||
self.x = self.x.saturating_add(delta_x as u16)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_y(&mut self, delta_y: i16) {
|
||||
if delta_y.is_negative() {
|
||||
self.y = self.y.saturating_add((-delta_y) as u16)
|
||||
} else {
|
||||
self.y = self.y.saturating_sub(delta_y as u16)
|
||||
}
|
||||
}
|
||||
pub fn set_x(&mut self, x: u16) {
|
||||
if x >= MOUSE_MAX_X {
|
||||
self.x = MOUSE_MAX_X - 1;
|
||||
} else {
|
||||
self.x = x;
|
||||
}
|
||||
}
|
||||
pub fn set_y(&mut self, y: u16) {
|
||||
if y >= MOUSE_MAX_Y {
|
||||
self.y = MOUSE_MAX_Y - 1;
|
||||
} else {
|
||||
self.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the mouse and set the on complete event.
|
||||
pub fn init_mouse() {
|
||||
let mut mouse = _MOUSE.lock();
|
||||
// debug!("Trying to initialize mouse");
|
||||
mouse.init().unwrap();
|
||||
mouse.set_on_complete(on_complete);
|
||||
// info!("Mouse initialized");
|
||||
}
|
||||
|
||||
// This will be fired when a packet is finished being processed.
|
||||
fn on_complete(mouse_state: MouseState) {
|
||||
// how much the cursor has moved
|
||||
let delta_x = mouse_state.get_x();
|
||||
let delta_y = mouse_state.get_y();
|
||||
/*
|
||||
trace!("MOUSE CHANGE: X{{{}}} Y{{{}}}", delta_x, delta_y);
|
||||
trace!(
|
||||
"MOUSE BUTTONS: LEFT{{{}}} RIGHT{{{}}}",
|
||||
mouse_state._left_button_down(),
|
||||
mouse_state._right_button_down()
|
||||
);
|
||||
*/
|
||||
|
||||
let mut mouse = MOUSE.lock();
|
||||
if mouse.get_x() >= MOUSE_MAX_X {
|
||||
mouse.set_x(MOUSE_MAX_X - 1);
|
||||
} else {
|
||||
mouse.change_x(delta_x);
|
||||
}
|
||||
|
||||
if mouse.get_y() >= MOUSE_MAX_Y {
|
||||
mouse.set_y(MOUSE_MAX_Y - 1);
|
||||
} else {
|
||||
mouse.change_y(delta_y);
|
||||
}
|
||||
// only move the cursor when delta_x is in some range
|
||||
// i.e. if the cursor moves too fast, ignore it.
|
||||
// if the mouse moves too fast the delta will overflow
|
||||
mouse.change_y(delta_y);
|
||||
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
use crate::TERM;
|
||||
let mut term = TERM.lock();
|
||||
term.set_dirty(true);
|
||||
});
|
||||
|
||||
// draw_mouse((mouse.get_x() as usize, mouse.get_y() as usize));
|
||||
}
|
||||
|
||||
// An example interrupt based on https://os.phil-opp.com/hardware-interrupts/.
|
||||
// The ps2 mouse is configured to fire
|
||||
// interrupts at PIC offset 12.
|
||||
pub extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||
let mut port = PortReadOnly::new(0x60);
|
||||
let packet = unsafe { port.read() };
|
||||
_MOUSE.lock().process_packet(packet);
|
||||
|
||||
unsafe {
|
||||
PICS.lock()
|
||||
.notify_end_of_interrupt(InterruptIndex::Mouse as u8);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::empty_loop)]
|
||||
|
||||
use core::sync::atomic::Ordering;
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
use crate::arch::drivers::sysinfo::master;
|
||||
use crate::ipc::channel::ChannelMessage;
|
||||
|
@ -13,9 +13,9 @@ use crate::{
|
|||
scratchpad,
|
||||
};
|
||||
use crate::{boot_conf::KernelConfig, systeminfo::RELEASE_TYPE};
|
||||
use crate::{wasm_jumploader, SectionType};
|
||||
use crate::{hardware, wasm_jumploader, SectionType, TERM};
|
||||
use genfs::{Fs, OpenOptions};
|
||||
use kernel::{KERNEL_VERSION, TICK};
|
||||
use kernel::KERNEL_VERSION;
|
||||
use libwasm::syscalls::time_calls::get_time;
|
||||
use qrcode::render::unicode;
|
||||
use qrcode::QrCode;
|
||||
|
@ -35,29 +35,43 @@ pub fn kernel_main() -> ! {
|
|||
} else {
|
||||
log::set_max_level(log::LevelFilter::Off);
|
||||
}
|
||||
let mut term = TERM.lock();
|
||||
term.initialize();
|
||||
term.set_dirty(true);
|
||||
term.draw_term();
|
||||
drop(term);
|
||||
|
||||
/*
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
hardware::init_mouse();
|
||||
});
|
||||
|
||||
// println!("abc");
|
||||
let mut ipc_service = IPC.lock();
|
||||
// create some channels or whatever here then drop it
|
||||
let log_handle = ipc_service.create_channel("LOG", true);
|
||||
let log_sock_handle = ipc_service.create_socket("LOG", true);
|
||||
|
||||
for handle in ipc_service.examine_board() {
|
||||
println!("Discovered: {}", handle);
|
||||
// println!("Discovered: {}", handle);
|
||||
}
|
||||
|
||||
drop(ipc_service);
|
||||
|
||||
use x86_ata::{init, list, read, ATA_BLOCK_SIZE};
|
||||
|
||||
*/
|
||||
|
||||
// use x86_ata::{init, ATA_BLOCK_SIZE};
|
||||
// 1. Initialise ATA Subsystem. (Perform Once, on boot)
|
||||
init().expect("Failed To Start ATA...");
|
||||
let mut buffer: [u8; ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE];
|
||||
// init().expect("Failed To Start ATA...");
|
||||
// let mut buffer: [u8; ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE];
|
||||
// FIXME: Calls to read panic the kernel
|
||||
// read(0, 0, 0, &mut buffer);
|
||||
|
||||
// for abc in list() {
|
||||
// trace!("{:?}", abc);
|
||||
// }
|
||||
|
||||
log_version_data();
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
let mut scheduler = SCHEDULER.lock();
|
||||
// comment this out to resume normal use
|
||||
|
@ -116,9 +130,28 @@ pub fn cpu_socket_startup() {
|
|||
}
|
||||
|
||||
pub fn log_version_data() {
|
||||
info!("{} v{:?}", RELEASE_TYPE, KERNEL_VERSION);
|
||||
info!("{} v{}", RELEASE_TYPE, KERNEL_VERSION);
|
||||
info!(
|
||||
"Brand String: {}",
|
||||
master().unwrap().brand_string().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
pub static TICK: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
pub fn tick() {
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
trace!("ticking time");
|
||||
|
||||
let mut term = TERM.lock();
|
||||
|
||||
term.draw_term();
|
||||
use core::sync::atomic::Ordering::Relaxed;
|
||||
|
||||
let mut data = TICK.load(Relaxed);
|
||||
data = data.wrapping_add(1);
|
||||
|
||||
TICK.store(data, Relaxed);
|
||||
trace!("time ticked");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ pub mod keyboard;
|
|||
pub mod kmain;
|
||||
pub mod logger;
|
||||
pub mod prelude;
|
||||
pub mod ps2_mouse;
|
||||
pub mod relib;
|
||||
pub mod rhai_shell;
|
||||
pub mod scheduler;
|
||||
|
@ -69,10 +70,13 @@ pub mod allocator;
|
|||
// pub use allocator as aalloc;
|
||||
pub mod channels;
|
||||
pub mod handle;
|
||||
pub mod hardware;
|
||||
pub mod ipc;
|
||||
pub mod panic;
|
||||
mod unicode_utils;
|
||||
pub mod vga_e;
|
||||
pub mod vgai;
|
||||
pub mod vterm;
|
||||
|
||||
#[prelude_import]
|
||||
pub use prelude::rust_2021::*;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::kmain::KERNEL_CONF;
|
||||
use crate::network::socket::{SimpleSock, Socket};
|
||||
use crate::time::fetch_time;
|
||||
use alloc::borrow::ToOwned;
|
||||
use lliw::{Fg, Reset};
|
||||
use log::{Level, Metadata, Record};
|
||||
use log::{LevelFilter, SetLoggerError};
|
||||
|
@ -17,6 +18,8 @@ impl log::Log for SimpleLogger {
|
|||
fn log(&self, record: &Record) {
|
||||
if self.enabled(record.metadata()) {
|
||||
let time_float = fetch_time();
|
||||
use log::Level::*;
|
||||
use Fg::*;
|
||||
|
||||
let color = match record.level() {
|
||||
log::Level::Error => (Fg::Red, "$RED$"),
|
||||
|
@ -26,6 +29,7 @@ impl log::Log for SimpleLogger {
|
|||
log::Level::Trace => (Fg::Yellow, "$YELLOW$"),
|
||||
};
|
||||
|
||||
/*
|
||||
let msg = format!(
|
||||
"[{}{}$RESET$][$GREEN${}$RESET$]{}\n",
|
||||
color.1,
|
||||
|
@ -33,29 +37,33 @@ impl log::Log for SimpleLogger {
|
|||
time_float,
|
||||
record.args()
|
||||
);
|
||||
// kprint!("{}", msg);
|
||||
*/
|
||||
let mod_path = match record.module_path() {
|
||||
Some(p) => p,
|
||||
None => "unknown",
|
||||
};
|
||||
|
||||
let line = match record.line() {
|
||||
Some(line_number) => line_number.to_string(),
|
||||
None => "??".to_string(),
|
||||
};
|
||||
|
||||
if KERNEL_CONF.logging.log_to_serial {
|
||||
serial_println!(
|
||||
"[{}{}{}][{}{}{}] {}",
|
||||
"[{}{}{}][{}{}{}][{}{}@{}{}] {}",
|
||||
color.0,
|
||||
record.level(),
|
||||
Fg::Reset,
|
||||
Fg::Green,
|
||||
time_float,
|
||||
Reset,
|
||||
Fg::Blue,
|
||||
mod_path,
|
||||
line,
|
||||
Reset,
|
||||
record.args()
|
||||
);
|
||||
}
|
||||
/*
|
||||
TODO: Get a proper socket from IPC instead of this deprecated method
|
||||
let log_socket_id = SimpleSock::grab_socket("Logger".to_string());
|
||||
match log_socket_id {
|
||||
Some(mut log_socket_id) => {
|
||||
log_socket_id.write(msg.as_bytes().to_vec());
|
||||
}
|
||||
None => warn!("No socket found for Logger"),
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
/// Clear the log buffer
|
||||
|
@ -64,4 +72,9 @@ impl log::Log for SimpleLogger {
|
|||
|
||||
pub fn init() -> Result<(), SetLoggerError> {
|
||||
log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Trace))
|
||||
// ?;
|
||||
|
||||
// trace!("Logger started");
|
||||
|
||||
// Ok(())
|
||||
}
|
||||
|
|
|
@ -5,4 +5,5 @@ pub use core::arch::asm;
|
|||
|
||||
pub use core::prelude::rust_2021::*;
|
||||
pub use core::prelude::v1::*;
|
||||
pub use core::result::Result::*;
|
||||
pub use log::{debug, info, trace, warn};
|
||||
|
|
|
@ -21,8 +21,15 @@ impl core::fmt::Write for Stdout {
|
|||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), Error> {
|
||||
use crate::kprint;
|
||||
kprint!("{}", s);
|
||||
use crate::TERM;
|
||||
|
||||
trace!("printing");
|
||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
let mut term = TERM.lock();
|
||||
term.set_dirty(true);
|
||||
term.print(s.to_string());
|
||||
drop(term);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
|
|
300
ableos/src/ps2_mouse.rs
Normal file
300
ableos/src/ps2_mouse.rs
Normal file
|
@ -0,0 +1,300 @@
|
|||
use bitflags::bitflags;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
const ADDRESS_PORT_ADDRESS: u16 = 0x64;
|
||||
const DATA_PORT_ADDRESS: u16 = 0x60;
|
||||
const GET_STATUS_BYTE: u8 = 0x20;
|
||||
const SET_STATUS_BYTE: u8 = 0x60;
|
||||
|
||||
const DISABLE_FIRST: u8 = 0xAD;
|
||||
const DISABLE_SECOND: u8 = 0xA7;
|
||||
const ENABLE_FIRST: u8 = 0xAE;
|
||||
const ENABLE_SECOND: u8 = 0xA8;
|
||||
|
||||
bitflags! {
|
||||
/// Represents the flags currently set for the mouse.
|
||||
#[derive(Default)]
|
||||
pub struct MouseFlags: u8 {
|
||||
/// Whether or not the left mouse button is pressed.
|
||||
const LEFT_BUTTON = 0b0000_0001;
|
||||
|
||||
/// Whether or not the right mouse button is pressed.
|
||||
const RIGHT_BUTTON = 0b0000_0010;
|
||||
|
||||
/// Whether or not the middle mouse button is pressed.
|
||||
const MIDDLE_BUTTON = 0b0000_0100;
|
||||
|
||||
/// Whether or not the packet is valid or not.
|
||||
const ALWAYS_ONE = 0b0000_1000;
|
||||
|
||||
/// Whether or not the x delta is negative.
|
||||
const X_SIGN = 0b0001_0000;
|
||||
|
||||
/// Whether or not the y delta is negative.
|
||||
const Y_SIGN = 0b0010_0000;
|
||||
|
||||
/// Whether or not the x delta overflowed.
|
||||
const X_OVERFLOW = 0b0100_0000;
|
||||
|
||||
/// Whether or not the y delta overflowed.
|
||||
const Y_OVERFLOW = 0b1000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
enum Command {
|
||||
EnablePacketStreaming = 0xF4,
|
||||
SetDefaults = 0xF6,
|
||||
}
|
||||
|
||||
/// A basic interface to interact with a PS2 mouse.
|
||||
#[derive(Debug)]
|
||||
pub struct Mouse {
|
||||
command_port: Port<u8>,
|
||||
data_port: Port<u8>,
|
||||
current_packet: u8,
|
||||
current_state: MouseState,
|
||||
completed_state: MouseState,
|
||||
on_complete: Option<fn(MouseState)>,
|
||||
}
|
||||
|
||||
impl Default for Mouse {
|
||||
fn default() -> Mouse {
|
||||
Mouse::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// A snapshot of the mouse flags, x delta and y delta.
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct MouseState {
|
||||
flags: MouseFlags,
|
||||
x: i16,
|
||||
y: i16,
|
||||
}
|
||||
|
||||
impl MouseState {
|
||||
/// Returns a new `MouseState`.
|
||||
pub const fn new() -> MouseState {
|
||||
MouseState {
|
||||
flags: MouseFlags::empty(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the left mouse button is currently down.
|
||||
pub fn _left_button_down(&self) -> bool {
|
||||
self.flags.contains(MouseFlags::LEFT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the left mouse button is currently up.
|
||||
pub fn _left_button_up(&self) -> bool {
|
||||
!self.flags.contains(MouseFlags::LEFT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the right mouse button is currently down.
|
||||
pub fn _right_button_down(&self) -> bool {
|
||||
self.flags.contains(MouseFlags::RIGHT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the right mouse button is currently up.
|
||||
pub fn _right_button_up(&self) -> bool {
|
||||
!self.flags.contains(MouseFlags::RIGHT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the x axis has moved.
|
||||
pub fn _x_moved(&self) -> bool {
|
||||
self.x != 0
|
||||
}
|
||||
|
||||
/// Returns true if the y axis has moved.
|
||||
pub fn _y_moved(&self) -> bool {
|
||||
self.y != 0
|
||||
}
|
||||
|
||||
/// Returns true if the x or y axis has moved.
|
||||
pub fn _moved(&self) -> bool {
|
||||
self._x_moved() || self._y_moved()
|
||||
}
|
||||
|
||||
/// Returns the x delta of the mouse state.
|
||||
pub fn get_x(&self) -> i16 {
|
||||
self.x
|
||||
}
|
||||
|
||||
/// Returns the y delta of the mouse state.
|
||||
pub fn get_y(&self) -> i16 {
|
||||
self.y
|
||||
}
|
||||
}
|
||||
|
||||
impl Mouse {
|
||||
/// Creates a new `Mouse`.
|
||||
pub const fn new() -> Mouse {
|
||||
Mouse {
|
||||
command_port: Port::new(ADDRESS_PORT_ADDRESS),
|
||||
data_port: Port::new(DATA_PORT_ADDRESS),
|
||||
current_packet: 0,
|
||||
current_state: MouseState::new(),
|
||||
completed_state: MouseState::new(),
|
||||
on_complete: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the last completed state of the mouse.
|
||||
pub fn _get_state(&self) -> MouseState {
|
||||
self.completed_state
|
||||
}
|
||||
|
||||
// super helpful resource, albeit in C
|
||||
// https://github.com/29jm/SnowflakeOS/blob/master/kernel/src/devices/ps2.c#L18
|
||||
/// Attempts to initialize a `Mouse`. If successful, interrupts will be generated
|
||||
/// as `PIC offset + 12`.
|
||||
pub fn init(&mut self) -> Result<(), &'static str> {
|
||||
// Disable both PS/2 device ports
|
||||
// Even if only one is present, disabling the second is harmless
|
||||
self.write_command_port(DISABLE_FIRST)?;
|
||||
self.write_command_port(DISABLE_SECOND)?;
|
||||
|
||||
// Flush output buffer: if the controller had anything to say, ignore it
|
||||
unsafe {
|
||||
self.data_port.read();
|
||||
}
|
||||
|
||||
debug!("mouse driver: writing GET_STATUS to port...");
|
||||
self.write_command_port(GET_STATUS_BYTE)?;
|
||||
debug!("mouse driver: reading status from port...");
|
||||
let status = self.read_data_port()? | 0x02;
|
||||
|
||||
debug!("Got status {}", status);
|
||||
|
||||
// self.write_command_port(0xa8)?;
|
||||
|
||||
self.write_command_port(SET_STATUS_BYTE)?;
|
||||
|
||||
self.write_data_port(status & 0xDF)?;
|
||||
|
||||
self.send_command(Command::SetDefaults)?;
|
||||
self.send_command(Command::EnablePacketStreaming)?;
|
||||
|
||||
self.write_command_port(ENABLE_FIRST)?;
|
||||
self.write_command_port(ENABLE_SECOND)?;
|
||||
|
||||
// Some keyboards actually send a reply, flush it
|
||||
unsafe {
|
||||
self.data_port.read();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to process a packet.
|
||||
pub fn process_packet(&mut self, packet: u8) {
|
||||
match self.current_packet {
|
||||
0 => {
|
||||
let flags = MouseFlags::from_bits_truncate(packet);
|
||||
if !flags.contains(MouseFlags::ALWAYS_ONE) {
|
||||
return;
|
||||
}
|
||||
self.current_state.flags = flags;
|
||||
}
|
||||
1 => self.process_x_movement(packet),
|
||||
2 => {
|
||||
self.process_y_movement(packet);
|
||||
self.completed_state = self.current_state;
|
||||
if let Some(on_complete) = self.on_complete {
|
||||
on_complete(self.completed_state);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
self.current_packet = (self.current_packet + 1) % 3;
|
||||
}
|
||||
|
||||
/// Sets the `on_complete` function to be called when a packet is completed.
|
||||
pub fn set_on_complete(&mut self, handler: fn(MouseState)) {
|
||||
self.on_complete = Some(handler);
|
||||
}
|
||||
|
||||
fn process_x_movement(&mut self, packet: u8) {
|
||||
if !self.current_state.flags.contains(MouseFlags::X_OVERFLOW) {
|
||||
self.current_state.x = if self.current_state.flags.contains(MouseFlags::X_SIGN) {
|
||||
self.sign_extend(packet)
|
||||
} else {
|
||||
packet as i16
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn process_y_movement(&mut self, packet: u8) {
|
||||
if !self.current_state.flags.contains(MouseFlags::Y_OVERFLOW) {
|
||||
self.current_state.y = if self.current_state.flags.contains(MouseFlags::Y_SIGN) {
|
||||
self.sign_extend(packet)
|
||||
} else {
|
||||
packet as i16
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn read_data_port(&mut self) -> Result<u8, &'static str> {
|
||||
// INFO: What the fuck
|
||||
debug!("owo");
|
||||
self.wait_for_read()?;
|
||||
// HERESY: Stop
|
||||
debug!("what's this");
|
||||
Ok(unsafe { self.data_port.read() })
|
||||
}
|
||||
|
||||
fn send_command(&mut self, command: Command) -> Result<(), &'static str> {
|
||||
self.write_command_port(0xD4)?;
|
||||
self.write_data_port(command as u8)?;
|
||||
if self.read_data_port()? != 0xFA {
|
||||
return Err("mouse did not respond to the command");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sign_extend(&self, packet: u8) -> i16 {
|
||||
((packet as u16) | 0xFF00) as i16
|
||||
}
|
||||
|
||||
fn write_command_port(&mut self, value: u8) -> Result<(), &'static str> {
|
||||
debug!("mouse driver: waiting for write");
|
||||
self.wait_for_write()?;
|
||||
unsafe {
|
||||
self.command_port.write(value);
|
||||
}
|
||||
debug!("mouse driver: command written");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_data_port(&mut self, value: u8) -> Result<(), &'static str> {
|
||||
self.wait_for_write()?;
|
||||
unsafe {
|
||||
self.data_port.write(value);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait_for_read(&mut self) -> Result<(), &'static str> {
|
||||
let timeout = 100_000;
|
||||
for _x in 0..timeout {
|
||||
let value = unsafe { self.command_port.read() };
|
||||
if (value & 0x1) == 0x1 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err("wait for mouse read timeout")
|
||||
}
|
||||
|
||||
fn wait_for_write(&mut self) -> Result<(), &'static str> {
|
||||
let timeout = 100_000;
|
||||
for _ in 0..timeout {
|
||||
let value = unsafe { self.command_port.read() };
|
||||
if (value & 0x2) == 0x0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err("wait for mouse write timeout")
|
||||
}
|
||||
}
|
|
@ -10,8 +10,9 @@ use crate::handle::Handle;
|
|||
use crate::ipc::IPC;
|
||||
use crate::rhai_shell::shell;
|
||||
use crate::rhai_shell::KEYBUFF;
|
||||
use crate::vterm::Term;
|
||||
use crate::wasm_jumploader::run_program;
|
||||
use crate::SCREEN_BUFFER;
|
||||
use crate::{vgai, SCREEN_BUFFER};
|
||||
use acpi::{AcpiTables, PlatformInfo};
|
||||
use alloc::collections::{vec_deque, VecDeque};
|
||||
use cpuio::inb;
|
||||
|
@ -24,6 +25,7 @@ use genfs::OpenOptions;
|
|||
use genfs::{DirEntry, Fs};
|
||||
use kernel::proccess::PID;
|
||||
use kernel::software_int;
|
||||
use spin::Lazy;
|
||||
use vga::writers::GraphicsWriter;
|
||||
|
||||
// TODO: move to a better place
|
||||
|
@ -43,6 +45,8 @@ impl acpi::AcpiHandler for AcpiStruct {
|
|||
todo!("unmap_physical_region");
|
||||
}
|
||||
}
|
||||
|
||||
pub static TERM: Lazy<spin::Mutex<Term>> = Lazy::new(|| spin::Mutex::new(Term::new()));
|
||||
#[derive(Debug)]
|
||||
|
||||
pub struct Path {
|
||||
|
@ -65,50 +69,8 @@ impl Path {
|
|||
|
||||
/// Experimental scratchpad for testing.
|
||||
pub fn scratchpad() {
|
||||
let axel_raw = "kernel{
|
||||
vals=
|
||||
time: 123
|
||||
fn|
|
||||
print: (None) -> (None);
|
||||
foo: (None) -> (Num);
|
||||
}";
|
||||
|
||||
let axel = axel::parse(axel_raw.to_string());
|
||||
|
||||
// software_int();
|
||||
|
||||
// let xyz = pci::brute_force_scan();
|
||||
// for dev in xyz {
|
||||
// trace!("{:?}", dev);
|
||||
// dev.bars.iter().for_each(|bar| {
|
||||
// trace!("{:?}", bar);
|
||||
// });
|
||||
// }
|
||||
|
||||
for node in axel {
|
||||
info!("{:?}", node);
|
||||
}
|
||||
/*
|
||||
use crate::devices::pci::brute_force_scan;
|
||||
let infos = brute_force_scan();
|
||||
for device in infos {
|
||||
match device.vendor_id {
|
||||
0x1af4 => {
|
||||
info!("Found virtio device");
|
||||
use crate::virtio::device_handler;
|
||||
device_handler(device);
|
||||
}
|
||||
_ => {
|
||||
info!("Found unknown device");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
real_shell();
|
||||
}
|
||||
use crate::graphics::VgaBuffer;
|
||||
|
||||
pub fn acpi() {
|
||||
let acpi_handler = AcpiStruct {};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::kmain::TICK;
|
||||
use core::sync::atomic::Ordering;
|
||||
use kernel::TICK;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn fetch_time() -> f64 {
|
||||
|
|
64
ableos/src/vgai.rs
Normal file
64
ableos/src/vgai.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use vga::writers::{Graphics640x480x16, GraphicsWriter};
|
||||
|
||||
pub enum Color {
|
||||
/// Represents the color `Black (0x0)`.
|
||||
Black = 0x0,
|
||||
/// Represents the color `Blue (0x1)`.
|
||||
Blue = 0x1,
|
||||
/// Represents the color `Green (0x2)`.
|
||||
Green = 0x2,
|
||||
/// Represents the color `Cyan (0x3)`.
|
||||
Cyan = 0x3,
|
||||
/// Represents the color `Red (0x4)`.
|
||||
Red = 0x4,
|
||||
/// Represents the color `Magenta (0x5)`.
|
||||
Magenta = 0x5,
|
||||
/// Represents the color `Brown (0x6)`.
|
||||
Brown = 0x6,
|
||||
/// Represents the color `LightGrey (0x7)`.
|
||||
LightGrey = 0x7,
|
||||
/// Represents the color `DarkGrey (0x8)`.
|
||||
DarkGrey = 0x8,
|
||||
/// Represents the color `LightBlue (0x9)`.
|
||||
LightBlue = 0x9,
|
||||
/// Represents the color `LightGreen (0xA)`.
|
||||
LightGreen = 0xA,
|
||||
/// Represents the color `LightCyan (0xB)`.
|
||||
LightCyan = 0xB,
|
||||
/// Represents the color `LightRed (0xC)`.
|
||||
LightRed = 0xC,
|
||||
/// Represents the color `Pink (0xD)`.
|
||||
Pink = 0xD,
|
||||
/// Represents the color `Yellow (0xE)`.
|
||||
Yellow = 0xE,
|
||||
/// Represents the color `White (0xF)`.
|
||||
White = 0xF,
|
||||
}
|
||||
|
||||
const VGA_BUFFER_SIZE: usize = 480;
|
||||
|
||||
pub struct ScreenBuffer {}
|
||||
impl ScreenBuffer {
|
||||
pub fn initialise() {}
|
||||
|
||||
pub fn flip_buffer() {
|
||||
/*
|
||||
before doing anything past here we need to tell the VGA about some things
|
||||
*/
|
||||
let setup = false;
|
||||
if setup {
|
||||
use Color::*;
|
||||
let dualpixel: u8 = Red as u8;
|
||||
|
||||
let buff: [u8; VGA_BUFFER_SIZE] = [dualpixel; VGA_BUFFER_SIZE];
|
||||
|
||||
let buff_ptr = buff.as_ptr();
|
||||
let vga_buffer = 0xb8000 as *mut u8;
|
||||
|
||||
use core::ptr;
|
||||
unsafe {
|
||||
ptr::copy(buff_ptr, vga_buffer, VGA_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
100
ableos/src/vterm.rs
Normal file
100
ableos/src/vterm.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
use vga::{colors::Color16, writers::GraphicsWriter};
|
||||
|
||||
use crate::{
|
||||
hardware::{MOUSE, _MOUSE},
|
||||
vga_e::VGAE,
|
||||
};
|
||||
const TERM_MINUS_ONE_LINE: usize = 4720;
|
||||
const CURSOR_COLOR: Color16 = Color16::Cyan;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Term {
|
||||
dirty: bool,
|
||||
term: [char; 80 * 60],
|
||||
x: usize,
|
||||
}
|
||||
impl Term {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
dirty: false,
|
||||
x: 0,
|
||||
term: ['\0'; 80 * 60],
|
||||
}
|
||||
}
|
||||
pub fn is_dirty(&self) -> bool {
|
||||
self.dirty
|
||||
}
|
||||
|
||||
pub fn set_dirty(&mut self, dirty: bool) {
|
||||
self.dirty = dirty
|
||||
}
|
||||
|
||||
pub fn print(&mut self, data: String) {
|
||||
for c in data.chars() {
|
||||
if self.x == 79 || c == '\n' {
|
||||
self.move_up();
|
||||
self.x = 0;
|
||||
} else {
|
||||
self.term[TERM_MINUS_ONE_LINE + self.x] = c;
|
||||
self.x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn move_up(&mut self) {
|
||||
self.term.rotate_left(80);
|
||||
for x in 0..80 {
|
||||
self.term[TERM_MINUS_ONE_LINE + x] = '\0';
|
||||
}
|
||||
}
|
||||
pub fn initialize(&self) {
|
||||
let mode = VGAE.lock();
|
||||
mode.set_mode();
|
||||
drop(mode);
|
||||
}
|
||||
|
||||
pub fn draw_term(&mut self) {
|
||||
if self.is_dirty() {
|
||||
trace!("Redrawing");
|
||||
let mode = VGAE.lock();
|
||||
mode.clear_screen(Color16::Black);
|
||||
|
||||
let mouse_coord = x86_64::instructions::interrupts::without_interrupts(|| {
|
||||
let cursor = MOUSE.lock();
|
||||
|
||||
(cursor.get_x() as usize, cursor.get_y() as usize)
|
||||
});
|
||||
|
||||
mode.draw_line(
|
||||
(mouse_coord.0 as isize + 0, mouse_coord.1 as isize + 0),
|
||||
(mouse_coord.0 as isize + 10, mouse_coord.1 as isize + 10),
|
||||
CURSOR_COLOR,
|
||||
);
|
||||
mode.draw_line(
|
||||
(mouse_coord.0 as isize + 0, mouse_coord.1 as isize + 0),
|
||||
(mouse_coord.0 as isize + 5, mouse_coord.1 as isize + 0),
|
||||
CURSOR_COLOR,
|
||||
);
|
||||
mode.draw_line(
|
||||
(mouse_coord.0 as isize + 0, mouse_coord.1 as isize + 0),
|
||||
(mouse_coord.0 as isize + 0, mouse_coord.1 as isize + 5),
|
||||
CURSOR_COLOR,
|
||||
);
|
||||
|
||||
let mut x = 0;
|
||||
let mut y = 0;
|
||||
|
||||
for c in self.term {
|
||||
mode.draw_character(x * 8, y * 8, c, Color16::White);
|
||||
|
||||
if x == 79 {
|
||||
y += 1;
|
||||
x = 0;
|
||||
} else {
|
||||
x += 1
|
||||
}
|
||||
}
|
||||
self.set_dirty(true);
|
||||
trace!("Finished drawing");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -136,7 +136,7 @@ host_externals! {
|
|||
trace!("SYSCALL: get time");
|
||||
|
||||
x86_64::instructions::interrupts::disable();
|
||||
let tick_time = kernel::TICK.load(Relaxed);
|
||||
let tick_time = crate::kmain::TICK.load(Relaxed);
|
||||
x86_64::instructions::interrupts::enable();
|
||||
|
||||
let ret: u32 = tick_time.try_into().unwrap();
|
||||
|
|
|
@ -25,7 +25,7 @@ use core::{
|
|||
use versioning::Version;
|
||||
|
||||
/// The number of ticks since the first CPU was started
|
||||
pub static TICK: AtomicU64 = AtomicU64::new(0);
|
||||
// pub static TICK: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
/// Kernel's version
|
||||
pub const KERNEL_VERSION: Version = Version {
|
||||
|
@ -34,6 +34,7 @@ pub const KERNEL_VERSION: Version = Version {
|
|||
patch: 2,
|
||||
};
|
||||
|
||||
/*
|
||||
/// called by arch specific timers to tick up all kernel related functions
|
||||
pub fn tick() {
|
||||
let mut data = TICK.load(Relaxed);
|
||||
|
@ -41,7 +42,7 @@ pub fn tick() {
|
|||
|
||||
TICK.store(data, Relaxed)
|
||||
}
|
||||
|
||||
*/
|
||||
/// Cause a software interrupt
|
||||
pub fn software_int() {
|
||||
unsafe { asm!("int 54") }
|
||||
|
|
243
qmp.py
Normal file
243
qmp.py
Normal file
|
@ -0,0 +1,243 @@
|
|||
# QEMU Monitor Protocol Python class
|
||||
#
|
||||
# Copyright (C) 2009, 2010 Red Hat Inc.
|
||||
#
|
||||
# Authors:
|
||||
# Luiz Capitulino <lcapitulino@redhat.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
# the COPYING file in the top-level directory.
|
||||
|
||||
import json
|
||||
import errno
|
||||
import socket
|
||||
import logging
|
||||
|
||||
|
||||
class QMPError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class QMPConnectError(QMPError):
|
||||
pass
|
||||
|
||||
|
||||
class QMPCapabilitiesError(QMPError):
|
||||
pass
|
||||
|
||||
|
||||
class QMPTimeoutError(QMPError):
|
||||
pass
|
||||
|
||||
|
||||
class QEMUMonitorProtocol(object):
|
||||
|
||||
#: Logger object for debugging messages
|
||||
logger = logging.getLogger('QMP')
|
||||
#: Socket's error class
|
||||
error = socket.error
|
||||
#: Socket's timeout
|
||||
timeout = socket.timeout
|
||||
|
||||
def __init__(self, address, server=False):
|
||||
"""
|
||||
Create a QEMUMonitorProtocol class.
|
||||
@param address: QEMU address, can be either a unix socket path (string)
|
||||
or a tuple in the form ( address, port ) for a TCP
|
||||
connection
|
||||
@param server: server mode listens on the socket (bool)
|
||||
@raise socket.error on socket connection errors
|
||||
@note No connection is established, this is done by the connect() or
|
||||
accept() methods
|
||||
"""
|
||||
self.__events = []
|
||||
self.__address = address
|
||||
self.__sock = self.__get_sock()
|
||||
self.__sockfile = None
|
||||
if server:
|
||||
self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.__sock.bind(self.__address)
|
||||
self.__sock.listen(1)
|
||||
|
||||
def __get_sock(self):
|
||||
if isinstance(self.__address, tuple):
|
||||
family = socket.AF_INET
|
||||
else:
|
||||
family = socket.AF_UNIX
|
||||
return socket.socket(family, socket.SOCK_STREAM)
|
||||
|
||||
def __negotiate_capabilities(self):
|
||||
greeting = self.__json_read()
|
||||
if greeting is None or "QMP" not in greeting:
|
||||
raise QMPConnectError
|
||||
# Greeting seems ok, negotiate capabilities
|
||||
resp = self.cmd('qmp_capabilities')
|
||||
if "return" in resp:
|
||||
return greeting
|
||||
raise QMPCapabilitiesError
|
||||
|
||||
def __json_read(self, only_event=False):
|
||||
while True:
|
||||
data = self.__sockfile.readline()
|
||||
if not data:
|
||||
return
|
||||
resp = json.loads(data)
|
||||
if 'event' in resp:
|
||||
self.logger.debug("<<< %s", resp)
|
||||
self.__events.append(resp)
|
||||
if not only_event:
|
||||
continue
|
||||
return resp
|
||||
|
||||
def __get_events(self, wait=False):
|
||||
"""
|
||||
Check for new events in the stream and cache them in __events.
|
||||
@param wait (bool): block until an event is available.
|
||||
@param wait (float): If wait is a float, treat it as a timeout value.
|
||||
@raise QMPTimeoutError: If a timeout float is provided and the timeout
|
||||
period elapses.
|
||||
@raise QMPConnectError: If wait is True but no events could be
|
||||
retrieved or if some other error occurred.
|
||||
"""
|
||||
|
||||
# Check for new events regardless and pull them into the cache:
|
||||
self.__sock.setblocking(0)
|
||||
try:
|
||||
self.__json_read()
|
||||
except socket.error as err:
|
||||
if err[0] == errno.EAGAIN:
|
||||
# No data available
|
||||
pass
|
||||
self.__sock.setblocking(1)
|
||||
|
||||
# Wait for new events, if needed.
|
||||
# if wait is 0.0, this means "no wait" and is also implicitly false.
|
||||
if not self.__events and wait:
|
||||
if isinstance(wait, float):
|
||||
self.__sock.settimeout(wait)
|
||||
try:
|
||||
ret = self.__json_read(only_event=True)
|
||||
except socket.timeout:
|
||||
raise QMPTimeoutError("Timeout waiting for event")
|
||||
except:
|
||||
raise QMPConnectError("Error while reading from socket")
|
||||
if ret is None:
|
||||
raise QMPConnectError("Error while reading from socket")
|
||||
self.__sock.settimeout(None)
|
||||
|
||||
def connect(self, negotiate=True):
|
||||
"""
|
||||
Connect to the QMP Monitor and perform capabilities negotiation.
|
||||
@return QMP greeting dict
|
||||
@raise socket.error on socket connection errors
|
||||
@raise QMPConnectError if the greeting is not received
|
||||
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
||||
"""
|
||||
self.__sock.connect(self.__address)
|
||||
self.__sockfile = self.__sock.makefile()
|
||||
if negotiate:
|
||||
return self.__negotiate_capabilities()
|
||||
|
||||
def accept(self):
|
||||
"""
|
||||
Await connection from QMP Monitor and perform capabilities negotiation.
|
||||
@return QMP greeting dict
|
||||
@raise socket.error on socket connection errors
|
||||
@raise QMPConnectError if the greeting is not received
|
||||
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
||||
"""
|
||||
self.__sock.settimeout(15)
|
||||
self.__sock, _ = self.__sock.accept()
|
||||
self.__sockfile = self.__sock.makefile()
|
||||
return self.__negotiate_capabilities()
|
||||
|
||||
def cmd_obj(self, qmp_cmd):
|
||||
"""
|
||||
Send a QMP command to the QMP Monitor.
|
||||
@param qmp_cmd: QMP command to be sent as a Python dict
|
||||
@return QMP response as a Python dict or None if the connection has
|
||||
been closed
|
||||
"""
|
||||
self.logger.debug(">>> %s", qmp_cmd)
|
||||
try:
|
||||
self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8'))
|
||||
except socket.error as err:
|
||||
if err[0] == errno.EPIPE:
|
||||
return
|
||||
raise socket.error(err)
|
||||
resp = self.__json_read()
|
||||
self.logger.debug("<<< %s", resp)
|
||||
return resp
|
||||
|
||||
def cmd(self, name, args=None, cmd_id=None):
|
||||
"""
|
||||
Build a QMP command and send it to the QMP Monitor.
|
||||
@param name: command name (string)
|
||||
@param args: command arguments (dict)
|
||||
@param cmd_id: command id (dict, list, string or int)
|
||||
"""
|
||||
qmp_cmd = {'execute': name}
|
||||
if args:
|
||||
qmp_cmd['arguments'] = args
|
||||
if cmd_id:
|
||||
qmp_cmd['id'] = cmd_id
|
||||
return self.cmd_obj(qmp_cmd)
|
||||
|
||||
def command(self, cmd, **kwds):
|
||||
"""
|
||||
Build and send a QMP command to the monitor, report errors if any
|
||||
"""
|
||||
ret = self.cmd(cmd, kwds)
|
||||
if "error" in ret:
|
||||
raise Exception(ret['error']['desc'])
|
||||
return ret['return']
|
||||
|
||||
def pull_event(self, wait=False):
|
||||
"""
|
||||
Pulls a single event.
|
||||
@param wait (bool): block until an event is available.
|
||||
@param wait (float): If wait is a float, treat it as a timeout value.
|
||||
@raise QMPTimeoutError: If a timeout float is provided and the timeout
|
||||
period elapses.
|
||||
@raise QMPConnectError: If wait is True but no events could be
|
||||
retrieved or if some other error occurred.
|
||||
@return The first available QMP event, or None.
|
||||
"""
|
||||
self.__get_events(wait)
|
||||
|
||||
if self.__events:
|
||||
return self.__events.pop(0)
|
||||
return None
|
||||
|
||||
def get_events(self, wait=False):
|
||||
"""
|
||||
Get a list of available QMP events.
|
||||
@param wait (bool): block until an event is available.
|
||||
@param wait (float): If wait is a float, treat it as a timeout value.
|
||||
@raise QMPTimeoutError: If a timeout float is provided and the timeout
|
||||
period elapses.
|
||||
@raise QMPConnectError: If wait is True but no events could be
|
||||
retrieved or if some other error occurred.
|
||||
@return The list of available QMP events.
|
||||
"""
|
||||
self.__get_events(wait)
|
||||
return self.__events
|
||||
|
||||
def clear_events(self):
|
||||
"""
|
||||
Clear current list of pending events.
|
||||
"""
|
||||
self.__events = []
|
||||
|
||||
def close(self):
|
||||
self.__sock.close()
|
||||
self.__sockfile.close()
|
||||
|
||||
def settimeout(self, timeout):
|
||||
self.__sock.settimeout(timeout)
|
||||
|
||||
def get_sock_fd(self):
|
||||
return self.__sock.fileno()
|
||||
|
||||
def is_scm_available(self):
|
||||
return self.__sock.family == socket.AF_UNIX
|
118
qprofiler.py
Normal file
118
qprofiler.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# QProfiler is a QEMU profiler based on QMP
|
||||
#
|
||||
# Copyright (c) 2019-2022 Matias Vara <matiasevara@gmail.com>
|
||||
# All Rights Reserved
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from __future__ import print_function
|
||||
import sys, os, re
|
||||
from qmp import QEMUMonitorProtocol
|
||||
from time import sleep
|
||||
import subprocess
|
||||
|
||||
def main(args):
|
||||
path = None
|
||||
filename = None
|
||||
|
||||
# duration of the test in seconds
|
||||
duration = 5
|
||||
|
||||
# sampling frequency in seconds
|
||||
frequency = 0.05
|
||||
|
||||
while len(args):
|
||||
arg = args[0]
|
||||
|
||||
if arg.startswith('--'):
|
||||
arg = arg[2:]
|
||||
if arg.find('=') == -1:
|
||||
value = True
|
||||
else:
|
||||
arg, value = arg.split('=', 1)
|
||||
|
||||
if arg in ['path']:
|
||||
if type(value) == str:
|
||||
path = value
|
||||
elif arg in ['duration']:
|
||||
duration = int(value)
|
||||
elif arg in ['frequency']:
|
||||
frequency = float(value)
|
||||
elif arg in ['filename']:
|
||||
filename = value
|
||||
else:
|
||||
print('Unknown argument "%s"' % arg)
|
||||
return 1
|
||||
|
||||
args = args[1:]
|
||||
else:
|
||||
break
|
||||
|
||||
if not path:
|
||||
print("Path isn't set, use --path=qmp-monitor-address")
|
||||
return 1
|
||||
|
||||
def do_command(srv, cmd, **kwds):
|
||||
rsp = srv.cmd(cmd, kwds)
|
||||
if 'error' in rsp:
|
||||
raise Exception(rsp['error']['desc'])
|
||||
return rsp['return']
|
||||
|
||||
srv = QEMUMonitorProtocol(path)
|
||||
srv.connect()
|
||||
|
||||
arguments = {}
|
||||
command = 'human-monitor-command'
|
||||
|
||||
r = int(duration // frequency)
|
||||
|
||||
rip_hash = {}
|
||||
|
||||
for i in range(r):
|
||||
arguments['command-line'] = 'info registers'
|
||||
rsp = do_command(srv, command, **arguments)
|
||||
|
||||
regs = re.search(r'RIP=([\w]+)\s', rsp)
|
||||
rip = regs.group(1)
|
||||
|
||||
if rip in rip_hash:
|
||||
rip_hash[rip] += 1
|
||||
else:
|
||||
rip_hash[rip] = 1
|
||||
|
||||
sleep(frequency)
|
||||
|
||||
srv.close()
|
||||
rip_hash_name = {}
|
||||
|
||||
for i in rip_hash:
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
# pass
|
||||
tmp = subprocess.check_output("addr2line --demangle -p -s -f -e "
|
||||
+ filename
|
||||
+ " "
|
||||
+ i , shell=True, stderr=devnull).rstrip()
|
||||
|
||||
if tmp in rip_hash_name:
|
||||
rip_hash_name[tmp] += rip_hash[i]
|
||||
else:
|
||||
rip_hash_name[tmp] = rip_hash[i]
|
||||
|
||||
for i in rip_hash_name:
|
||||
print('{:>8} {}'.format(rip_hash_name[i], i))
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
|
@ -11,6 +11,8 @@ enum Command {
|
|||
Run {
|
||||
#[clap(long, short)]
|
||||
debug: bool,
|
||||
#[clap(long, short)]
|
||||
profile: bool,
|
||||
|
||||
#[clap(long, short, arg_enum)]
|
||||
machine: Option<MachineType>,
|
||||
|
@ -44,7 +46,12 @@ fn main() -> anyhow::Result<()> {
|
|||
let args = Command::parse();
|
||||
|
||||
match args {
|
||||
Command::Run { debug, machine } => {
|
||||
Command::Run {
|
||||
debug,
|
||||
profile,
|
||||
|
||||
machine,
|
||||
} => {
|
||||
let _dir = xshell::pushd("./ableos");
|
||||
|
||||
let _debug_log: &[&str] = match debug {
|
||||
|
@ -54,15 +61,18 @@ fn main() -> anyhow::Result<()> {
|
|||
match machine.unwrap_or(MachineType::X86) {
|
||||
MachineType::X86 => {
|
||||
xshell::cmd!("cargo run --release").run()?;
|
||||
if profile {
|
||||
xshell::cmd!("python qprofiler.py --path=qmp-sock --filename=target/x86_64-ableos/release/ableos").run()?;
|
||||
}
|
||||
}
|
||||
MachineType::Arm => {
|
||||
xshell::cmd!("cargo build --release --target=json_targets/aarch64-ableos.json")
|
||||
.run()?;
|
||||
#[rustfmt::skip]
|
||||
xshell::cmd!(
|
||||
"qemu-system-aarch64
|
||||
-machine virt
|
||||
-m 1024M
|
||||
xshell::cmd!(
|
||||
"qemu-system-aarch64
|
||||
-machine virt
|
||||
-m 1024M
|
||||
-cpu cortex-a53
|
||||
-kernel target/aarch64-ableos/release/ableos
|
||||
-device virtio-keyboard
|
||||
|
@ -75,15 +85,15 @@ fn main() -> anyhow::Result<()> {
|
|||
#[rustfmt::skip]
|
||||
xshell::cmd!(
|
||||
"qemu-system-riscv64
|
||||
-machine virt
|
||||
-cpu rv64
|
||||
-smp 8
|
||||
-m 128M
|
||||
-bios src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin
|
||||
-kernel target/riscv64gc-unknown-none-elf/release/ableos
|
||||
"
|
||||
// -serial stdio
|
||||
).run()?;
|
||||
-machine virt
|
||||
-cpu rv64
|
||||
-smp 8
|
||||
-m 128M
|
||||
-bios src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin
|
||||
-kernel target/riscv64gc-unknown-none-elf/release/ableos
|
||||
"
|
||||
// -serial stdio
|
||||
).run()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue