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",
|
"ab_glyph",
|
||||||
"acpi",
|
"acpi",
|
||||||
"axel",
|
"axel",
|
||||||
|
"bitflags",
|
||||||
"bootloader",
|
"bootloader",
|
||||||
"cpuio",
|
"cpuio",
|
||||||
"embedded-graphics",
|
|
||||||
"ext2",
|
"ext2",
|
||||||
"externc-libm",
|
"externc-libm",
|
||||||
"facepalm",
|
"facepalm",
|
||||||
|
@ -134,7 +134,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axel"
|
name = "axel"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"hashbrown 0.7.2",
|
"hashbrown 0.7.2",
|
||||||
"log",
|
"log",
|
||||||
|
@ -142,12 +142,6 @@ dependencies = [
|
||||||
"versioning",
|
"versioning",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "az"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bare-metal"
|
name = "bare-metal"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -178,12 +172,6 @@ version = "0.9.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de78decc37247c7cfac5dbf3495c7298c6ac97cb355161caa7e15969c6648e6c"
|
checksum = "de78decc37247c7cfac5dbf3495c7298c6ac97cb355161caa7e15969c6648e6c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -283,29 +271,6 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
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]]
|
[[package]]
|
||||||
name = "ext2"
|
name = "ext2"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -331,15 +296,6 @@ dependencies = [
|
||||||
"log",
|
"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]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
@ -490,9 +446,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.16"
|
version = "0.4.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
@ -533,12 +489,6 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882"
|
checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "micromath"
|
|
||||||
version = "1.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bc4010833aea396656c2f91ee704d51a6f1329ec2ab56ffd00bfd56f7481ea94"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "no-std-compat"
|
name = "no-std-compat"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -1029,7 +979,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "versioning"
|
name = "versioning"
|
||||||
version = "0.1.2"
|
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 = [
|
dependencies = [
|
||||||
"serde",
|
"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]
|
[dependencies]
|
||||||
lazy_static = { version = "*", features = ["spin_no_std"] }
|
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||||
qrcode = { path = "../qrcode-rust" }
|
qrcode = { path = "../qrcode-rust" }
|
||||||
|
bitflags = "1.2.1"
|
||||||
|
|
||||||
linked_list_allocator = "0.9.0"
|
linked_list_allocator = "0.9.0"
|
||||||
lliw = "0.2.0"
|
lliw = "0.2.0"
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
log = "*"
|
log = "0.4.17"
|
||||||
pretty-hex = "0.2.1"
|
pretty-hex = "0.2.1"
|
||||||
unicode-width = "0.1.7"
|
unicode-width = "0.1.7"
|
||||||
picorand = "0.1.0"
|
picorand = "0.1.0"
|
||||||
|
@ -63,8 +62,9 @@ rhai = "1.6.0"
|
||||||
libwasm = { git = "https://git.ablecorp.us:443/able/libwasm.git" }
|
libwasm = { git = "https://git.ablecorp.us:443/able/libwasm.git" }
|
||||||
axel = { git = "https://git.ablecorp.us/able/aos_userland" }
|
axel = { git = "https://git.ablecorp.us/able/aos_userland" }
|
||||||
versioning = { 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"
|
pc-keyboard = "0.5"
|
||||||
|
|
||||||
[dependencies.logos]
|
[dependencies.logos]
|
||||||
version = "0.12"
|
version = "0.12"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
@ -138,7 +138,7 @@ cpuio = { git = "https://git.ablecorp.us/ondra05/cpuio.git" }
|
||||||
pic8259 = "0.10.1"
|
pic8259 = "0.10.1"
|
||||||
uart_16550 = "0.2.0"
|
uart_16550 = "0.2.0"
|
||||||
volatile = "0.2.6"
|
volatile = "0.2.6"
|
||||||
x86_64 = "*"
|
x86_64 = "0.14.8"
|
||||||
pc-beeper = { git = "https://github.com/AbleOS/pc-beeper" }
|
pc-beeper = { git = "https://github.com/AbleOS/pc-beeper" }
|
||||||
vga = "*"
|
vga = "0.2.7"
|
||||||
acpi = "4.1.0"
|
acpi = "4.1.0"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod allocator;
|
pub mod allocator;
|
||||||
pub mod graphics;
|
// pub mod graphics;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod sysinfo;
|
pub mod sysinfo;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
// #![allow(clippy::print_literal)]
|
// #![allow(clippy::print_literal)]
|
||||||
use super::{gdt, interrupts};
|
use super::{drivers::serial, gdt, interrupts};
|
||||||
use crate::{logger, serial_println};
|
use crate::{logger, serial_println};
|
||||||
|
|
||||||
/// x86_64 initialization
|
/// x86_64 initialization
|
||||||
pub fn init() {
|
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();
|
// let mut log_socket_id = SimpleSock::new();
|
||||||
log_socket_id.register_protocol("Logger".to_string());
|
// log_socket_id.register_protocol("Logger".to_string());
|
||||||
|
|
||||||
let result = logger::init();
|
let result = logger::init();
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
serial_println!("Logger initialized");
|
info!("Logger initialized");
|
||||||
}
|
}
|
||||||
Err(err) => error!("{}", err),
|
Err(err) => serial_println!("{}", err),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
gdt::init();
|
gdt::init();
|
||||||
|
|
||||||
interrupts::init_idt();
|
interrupts::init_idt();
|
||||||
|
|
|
@ -18,6 +18,8 @@ use spin::Lazy;
|
||||||
use vga::colors::Color16;
|
use vga::colors::Color16;
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
|
use super::sloop;
|
||||||
|
|
||||||
pub const PIC_1_OFFSET: u8 = 32;
|
pub const PIC_1_OFFSET: u8 = 32;
|
||||||
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
|
||||||
|
|
||||||
|
@ -30,6 +32,9 @@ pub static PICS: spin::Mutex<ChainedPics> =
|
||||||
pub enum InterruptIndex {
|
pub enum InterruptIndex {
|
||||||
Timer = PIC_1_OFFSET,
|
Timer = PIC_1_OFFSET,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
|
/// Mouse offset
|
||||||
|
Mouse = 44,
|
||||||
|
|
||||||
// SecondInterrupt = PIC_2_OFFSET,
|
// SecondInterrupt = PIC_2_OFFSET,
|
||||||
Cmos = 0x70,
|
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::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
||||||
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||||
|
idt[InterruptIndex::Mouse.as_usize()].set_handler_fn(crate::hardware::mouse_interrupt_handler);
|
||||||
idt[6].set_handler_fn(floppy_disk_interrupt_handler);
|
|
||||||
|
|
||||||
// run `a + b + l + e + o + s print;` in ablescript and its 54 thats why this seemingly arbitrary number was chosen
|
// 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[54].set_handler_fn(software_int_handler);
|
||||||
|
|
||||||
idt
|
idt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -78,7 +83,7 @@ extern "x86-interrupt" fn double_fault_handler(
|
||||||
_error_code: u64,
|
_error_code: u64,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
bsod(BSODSource::DoubleFault(&stack_frame));
|
bsod(BSODSource::DoubleFault(&stack_frame));
|
||||||
// panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
|
@ -87,6 +92,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
|
||||||
unsafe {
|
unsafe {
|
||||||
// print!(".");
|
// print!(".");
|
||||||
asm!(
|
asm!(
|
||||||
|
|
||||||
// Kernel tick
|
// Kernel tick
|
||||||
"call {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)
|
// Switch to next task (interrupt'll be returned there)
|
||||||
"jmp {switch_to_next}",
|
"jmp {switch_to_next}",
|
||||||
|
|
||||||
tick = sym kernel::tick,
|
tick = sym crate::kmain::tick,
|
||||||
save = sym task_switcher::save_and_enqueue,
|
save = sym task_switcher::save_and_enqueue,
|
||||||
switch_to_next = sym task_switcher::switch_to_next,
|
switch_to_next = sym task_switcher::switch_to_next,
|
||||||
options(noreturn),
|
options(noreturn),
|
||||||
|
@ -122,14 +128,16 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
|
||||||
.add_byte(unsafe { Port::new(0x60).read() })
|
.add_byte(unsafe { Port::new(0x60).read() })
|
||||||
.map(|x| x.and_then(|ev| keyboard.process_keyevent(ev)))
|
.map(|x| x.and_then(|ev| keyboard.process_keyevent(ev)))
|
||||||
{
|
{
|
||||||
|
trace!("{key:?}");
|
||||||
match key {
|
match key {
|
||||||
DecodedKey::Unicode(chr) => match chr {
|
DecodedKey::Unicode(chr) => match chr {
|
||||||
// Backspace
|
// Backspace
|
||||||
'\u{8}' => {
|
'\u{8}' => {
|
||||||
|
// TODO: Fix this and apply to new term
|
||||||
WRITER.lock().backspace();
|
WRITER.lock().backspace();
|
||||||
KEYBUFF.lock().push(8.into());
|
KEYBUFF.lock().push(8.into());
|
||||||
}
|
}
|
||||||
'^' => KERNEL_STATE.lock().shutdown(),
|
// '^' => KERNEL_STATE.lock().shutdown(),
|
||||||
chr => {
|
chr => {
|
||||||
KEYBUFF.lock().push(chr);
|
KEYBUFF.lock().push(chr);
|
||||||
print!("{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() {
|
pub fn init_idt() {
|
||||||
IDT.load();
|
IDT.load();
|
||||||
}
|
}
|
||||||
|
@ -200,6 +204,8 @@ pub fn reset_pit_for_cpu() {
|
||||||
set_pit_3(1000);
|
set_pit_3(1000);
|
||||||
}
|
}
|
||||||
pub fn bsod(src: BSODSource) -> ! {
|
pub fn bsod(src: BSODSource) -> ! {
|
||||||
|
trace!("{src:?}");
|
||||||
|
|
||||||
let mut mode = SCREEN_BUFFER.lock();
|
let mut mode = SCREEN_BUFFER.lock();
|
||||||
mode.force_redraw();
|
mode.force_redraw();
|
||||||
/*
|
/*
|
||||||
|
@ -214,17 +220,20 @@ pub fn bsod(src: BSODSource) -> ! {
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
|
|
||||||
let src1 = match src {
|
let src1 = match src {
|
||||||
BSODSource::DoubleFault(_) => "DoubleFault",
|
BSODSource::DoubleFault(_) => "DoubleFault".to_string(),
|
||||||
BSODSource::Panic(_) => "Panic",
|
BSODSource::Panic(panic_info) => {
|
||||||
|
let strr = format!("PANIC: {}", panic_info);
|
||||||
|
strr
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let st = format!(
|
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
|
src1
|
||||||
);
|
);
|
||||||
|
|
||||||
for current in st.chars() {
|
for current in st.chars() {
|
||||||
if current == '\n' {
|
if current == '\n' || x == 40 {
|
||||||
y += 1;
|
y += 1;
|
||||||
x = 1;
|
x = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -239,16 +248,15 @@ pub fn bsod(src: BSODSource) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut x = 1;
|
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 sf = format!("https://git.ablecorp.us/able/ableos/wiki/Double-Faults");
|
||||||
|
|
||||||
let sd = match src {
|
let sd = match src {
|
||||||
BSODSource::DoubleFault(_) => "https://git.ablecorp.us/able/ableos/wiki/Double-Faults",
|
BSODSource::DoubleFault(_) => "https://git.ablecorp.us/able/ableos/wiki/Double-Faults",
|
||||||
BSODSource::Panic(_) => {
|
BSODSource::Panic(_) => {
|
||||||
//
|
|
||||||
trace!("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();
|
mode.copy_to_buffer();
|
||||||
|
|
||||||
loop {}
|
sloop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::driver_traits::graphics::Point;
|
// use crate::driver_traits::graphics::Point;
|
||||||
|
|
||||||
pub type MenuBar = Vec<MenuOption>;
|
pub type MenuBar = Vec<MenuOption>;
|
||||||
|
|
||||||
|
@ -8,16 +8,16 @@ pub struct MenuOption {
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
title: String,
|
title: String,
|
||||||
position: Point,
|
// position: Point,
|
||||||
fullscreen: bool,
|
fullscreen: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// all of these should return a result
|
// all of these should return a result
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(title: String, position: Point, fullscreen: bool) -> Self {
|
pub fn new(title: String, /*position: Point,*/ fullscreen: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title,
|
title,
|
||||||
position,
|
// position,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ impl Window {
|
||||||
pub fn set_title(&mut self) {
|
pub fn set_title(&mut self) {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
pub fn set_position(&mut self, pos: Point) {
|
pub fn set_position(&mut self /*pos: Point*/) {
|
||||||
self.position = pos;
|
// 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)]
|
#![allow(clippy::empty_loop)]
|
||||||
|
|
||||||
use core::sync::atomic::Ordering;
|
use core::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
use crate::arch::drivers::sysinfo::master;
|
use crate::arch::drivers::sysinfo::master;
|
||||||
use crate::ipc::channel::ChannelMessage;
|
use crate::ipc::channel::ChannelMessage;
|
||||||
|
@ -13,9 +13,9 @@ use crate::{
|
||||||
scratchpad,
|
scratchpad,
|
||||||
};
|
};
|
||||||
use crate::{boot_conf::KernelConfig, systeminfo::RELEASE_TYPE};
|
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 genfs::{Fs, OpenOptions};
|
||||||
use kernel::{KERNEL_VERSION, TICK};
|
use kernel::KERNEL_VERSION;
|
||||||
use libwasm::syscalls::time_calls::get_time;
|
use libwasm::syscalls::time_calls::get_time;
|
||||||
use qrcode::render::unicode;
|
use qrcode::render::unicode;
|
||||||
use qrcode::QrCode;
|
use qrcode::QrCode;
|
||||||
|
@ -35,29 +35,43 @@ pub fn kernel_main() -> ! {
|
||||||
} else {
|
} else {
|
||||||
log::set_max_level(log::LevelFilter::Off);
|
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();
|
let mut ipc_service = IPC.lock();
|
||||||
// create some channels or whatever here then drop it
|
// create some channels or whatever here then drop it
|
||||||
let log_handle = ipc_service.create_channel("LOG", true);
|
let log_handle = ipc_service.create_channel("LOG", true);
|
||||||
let log_sock_handle = ipc_service.create_socket("LOG", true);
|
let log_sock_handle = ipc_service.create_socket("LOG", true);
|
||||||
|
|
||||||
for handle in ipc_service.examine_board() {
|
for handle in ipc_service.examine_board() {
|
||||||
println!("Discovered: {}", handle);
|
// println!("Discovered: {}", handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(ipc_service);
|
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)
|
// 1. Initialise ATA Subsystem. (Perform Once, on boot)
|
||||||
init().expect("Failed To Start ATA...");
|
// init().expect("Failed To Start ATA...");
|
||||||
let mut buffer: [u8; ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE];
|
// let mut buffer: [u8; ATA_BLOCK_SIZE] = [0; ATA_BLOCK_SIZE];
|
||||||
// FIXME: Calls to read panic the kernel
|
// FIXME: Calls to read panic the kernel
|
||||||
// read(0, 0, 0, &mut buffer);
|
// read(0, 0, 0, &mut buffer);
|
||||||
|
|
||||||
// for abc in list() {
|
// for abc in list() {
|
||||||
// trace!("{:?}", abc);
|
// trace!("{:?}", abc);
|
||||||
// }
|
// }
|
||||||
|
log_version_data();
|
||||||
x86_64::instructions::interrupts::without_interrupts(|| {
|
x86_64::instructions::interrupts::without_interrupts(|| {
|
||||||
let mut scheduler = SCHEDULER.lock();
|
let mut scheduler = SCHEDULER.lock();
|
||||||
// comment this out to resume normal use
|
// comment this out to resume normal use
|
||||||
|
@ -116,9 +130,28 @@ pub fn cpu_socket_startup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_version_data() {
|
pub fn log_version_data() {
|
||||||
info!("{} v{:?}", RELEASE_TYPE, KERNEL_VERSION);
|
info!("{} v{}", RELEASE_TYPE, KERNEL_VERSION);
|
||||||
info!(
|
info!(
|
||||||
"Brand String: {}",
|
"Brand String: {}",
|
||||||
master().unwrap().brand_string().unwrap()
|
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 kmain;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
pub mod ps2_mouse;
|
||||||
pub mod relib;
|
pub mod relib;
|
||||||
pub mod rhai_shell;
|
pub mod rhai_shell;
|
||||||
pub mod scheduler;
|
pub mod scheduler;
|
||||||
|
@ -69,10 +70,13 @@ pub mod allocator;
|
||||||
// pub use allocator as aalloc;
|
// pub use allocator as aalloc;
|
||||||
pub mod channels;
|
pub mod channels;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
|
pub mod hardware;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
pub mod panic;
|
pub mod panic;
|
||||||
mod unicode_utils;
|
mod unicode_utils;
|
||||||
pub mod vga_e;
|
pub mod vga_e;
|
||||||
|
pub mod vgai;
|
||||||
|
pub mod vterm;
|
||||||
|
|
||||||
#[prelude_import]
|
#[prelude_import]
|
||||||
pub use prelude::rust_2021::*;
|
pub use prelude::rust_2021::*;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::kmain::KERNEL_CONF;
|
use crate::kmain::KERNEL_CONF;
|
||||||
use crate::network::socket::{SimpleSock, Socket};
|
use crate::network::socket::{SimpleSock, Socket};
|
||||||
use crate::time::fetch_time;
|
use crate::time::fetch_time;
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
use lliw::{Fg, Reset};
|
use lliw::{Fg, Reset};
|
||||||
use log::{Level, Metadata, Record};
|
use log::{Level, Metadata, Record};
|
||||||
use log::{LevelFilter, SetLoggerError};
|
use log::{LevelFilter, SetLoggerError};
|
||||||
|
@ -17,6 +18,8 @@ impl log::Log for SimpleLogger {
|
||||||
fn log(&self, record: &Record) {
|
fn log(&self, record: &Record) {
|
||||||
if self.enabled(record.metadata()) {
|
if self.enabled(record.metadata()) {
|
||||||
let time_float = fetch_time();
|
let time_float = fetch_time();
|
||||||
|
use log::Level::*;
|
||||||
|
use Fg::*;
|
||||||
|
|
||||||
let color = match record.level() {
|
let color = match record.level() {
|
||||||
log::Level::Error => (Fg::Red, "$RED$"),
|
log::Level::Error => (Fg::Red, "$RED$"),
|
||||||
|
@ -26,6 +29,7 @@ impl log::Log for SimpleLogger {
|
||||||
log::Level::Trace => (Fg::Yellow, "$YELLOW$"),
|
log::Level::Trace => (Fg::Yellow, "$YELLOW$"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"[{}{}$RESET$][$GREEN${}$RESET$]{}\n",
|
"[{}{}$RESET$][$GREEN${}$RESET$]{}\n",
|
||||||
color.1,
|
color.1,
|
||||||
|
@ -33,29 +37,33 @@ impl log::Log for SimpleLogger {
|
||||||
time_float,
|
time_float,
|
||||||
record.args()
|
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 {
|
if KERNEL_CONF.logging.log_to_serial {
|
||||||
serial_println!(
|
serial_println!(
|
||||||
"[{}{}{}][{}{}{}] {}",
|
"[{}{}{}][{}{}{}][{}{}@{}{}] {}",
|
||||||
color.0,
|
color.0,
|
||||||
record.level(),
|
record.level(),
|
||||||
Fg::Reset,
|
Fg::Reset,
|
||||||
Fg::Green,
|
Fg::Green,
|
||||||
time_float,
|
time_float,
|
||||||
Reset,
|
Reset,
|
||||||
|
Fg::Blue,
|
||||||
|
mod_path,
|
||||||
|
line,
|
||||||
|
Reset,
|
||||||
record.args()
|
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
|
/// Clear the log buffer
|
||||||
|
@ -64,4 +72,9 @@ impl log::Log for SimpleLogger {
|
||||||
|
|
||||||
pub fn init() -> Result<(), SetLoggerError> {
|
pub fn init() -> Result<(), SetLoggerError> {
|
||||||
log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Trace))
|
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::rust_2021::*;
|
||||||
pub use core::prelude::v1::*;
|
pub use core::prelude::v1::*;
|
||||||
|
pub use core::result::Result::*;
|
||||||
pub use log::{debug, info, trace, warn};
|
pub use log::{debug, info, trace, warn};
|
||||||
|
|
|
@ -21,8 +21,15 @@ impl core::fmt::Write for Stdout {
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), Error> {
|
fn write_str(&mut self, s: &str) -> Result<(), Error> {
|
||||||
use crate::kprint;
|
use crate::TERM;
|
||||||
kprint!("{}", s);
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[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::ipc::IPC;
|
||||||
use crate::rhai_shell::shell;
|
use crate::rhai_shell::shell;
|
||||||
use crate::rhai_shell::KEYBUFF;
|
use crate::rhai_shell::KEYBUFF;
|
||||||
|
use crate::vterm::Term;
|
||||||
use crate::wasm_jumploader::run_program;
|
use crate::wasm_jumploader::run_program;
|
||||||
use crate::SCREEN_BUFFER;
|
use crate::{vgai, SCREEN_BUFFER};
|
||||||
use acpi::{AcpiTables, PlatformInfo};
|
use acpi::{AcpiTables, PlatformInfo};
|
||||||
use alloc::collections::{vec_deque, VecDeque};
|
use alloc::collections::{vec_deque, VecDeque};
|
||||||
use cpuio::inb;
|
use cpuio::inb;
|
||||||
|
@ -24,6 +25,7 @@ use genfs::OpenOptions;
|
||||||
use genfs::{DirEntry, Fs};
|
use genfs::{DirEntry, Fs};
|
||||||
use kernel::proccess::PID;
|
use kernel::proccess::PID;
|
||||||
use kernel::software_int;
|
use kernel::software_int;
|
||||||
|
use spin::Lazy;
|
||||||
use vga::writers::GraphicsWriter;
|
use vga::writers::GraphicsWriter;
|
||||||
|
|
||||||
// TODO: move to a better place
|
// TODO: move to a better place
|
||||||
|
@ -43,6 +45,8 @@ impl acpi::AcpiHandler for AcpiStruct {
|
||||||
todo!("unmap_physical_region");
|
todo!("unmap_physical_region");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static TERM: Lazy<spin::Mutex<Term>> = Lazy::new(|| spin::Mutex::new(Term::new()));
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
|
@ -65,50 +69,8 @@ impl Path {
|
||||||
|
|
||||||
/// Experimental scratchpad for testing.
|
/// Experimental scratchpad for testing.
|
||||||
pub fn scratchpad() {
|
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();
|
real_shell();
|
||||||
}
|
}
|
||||||
use crate::graphics::VgaBuffer;
|
|
||||||
|
|
||||||
pub fn acpi() {
|
pub fn acpi() {
|
||||||
let acpi_handler = AcpiStruct {};
|
let acpi_handler = AcpiStruct {};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::kmain::TICK;
|
||||||
use core::sync::atomic::Ordering;
|
use core::sync::atomic::Ordering;
|
||||||
use kernel::TICK;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub fn fetch_time() -> f64 {
|
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");
|
trace!("SYSCALL: get time");
|
||||||
|
|
||||||
x86_64::instructions::interrupts::disable();
|
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();
|
x86_64::instructions::interrupts::enable();
|
||||||
|
|
||||||
let ret: u32 = tick_time.try_into().unwrap();
|
let ret: u32 = tick_time.try_into().unwrap();
|
||||||
|
|
|
@ -25,7 +25,7 @@ use core::{
|
||||||
use versioning::Version;
|
use versioning::Version;
|
||||||
|
|
||||||
/// The number of ticks since the first CPU was started
|
/// 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
|
/// Kernel's version
|
||||||
pub const KERNEL_VERSION: Version = Version {
|
pub const KERNEL_VERSION: Version = Version {
|
||||||
|
@ -34,6 +34,7 @@ pub const KERNEL_VERSION: Version = Version {
|
||||||
patch: 2,
|
patch: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
/// called by arch specific timers to tick up all kernel related functions
|
/// called by arch specific timers to tick up all kernel related functions
|
||||||
pub fn tick() {
|
pub fn tick() {
|
||||||
let mut data = TICK.load(Relaxed);
|
let mut data = TICK.load(Relaxed);
|
||||||
|
@ -41,7 +42,7 @@ pub fn tick() {
|
||||||
|
|
||||||
TICK.store(data, Relaxed)
|
TICK.store(data, Relaxed)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
/// Cause a software interrupt
|
/// Cause a software interrupt
|
||||||
pub fn software_int() {
|
pub fn software_int() {
|
||||||
unsafe { asm!("int 54") }
|
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 {
|
Run {
|
||||||
#[clap(long, short)]
|
#[clap(long, short)]
|
||||||
debug: bool,
|
debug: bool,
|
||||||
|
#[clap(long, short)]
|
||||||
|
profile: bool,
|
||||||
|
|
||||||
#[clap(long, short, arg_enum)]
|
#[clap(long, short, arg_enum)]
|
||||||
machine: Option<MachineType>,
|
machine: Option<MachineType>,
|
||||||
|
@ -44,7 +46,12 @@ fn main() -> anyhow::Result<()> {
|
||||||
let args = Command::parse();
|
let args = Command::parse();
|
||||||
|
|
||||||
match args {
|
match args {
|
||||||
Command::Run { debug, machine } => {
|
Command::Run {
|
||||||
|
debug,
|
||||||
|
profile,
|
||||||
|
|
||||||
|
machine,
|
||||||
|
} => {
|
||||||
let _dir = xshell::pushd("./ableos");
|
let _dir = xshell::pushd("./ableos");
|
||||||
|
|
||||||
let _debug_log: &[&str] = match debug {
|
let _debug_log: &[&str] = match debug {
|
||||||
|
@ -54,6 +61,9 @@ fn main() -> anyhow::Result<()> {
|
||||||
match machine.unwrap_or(MachineType::X86) {
|
match machine.unwrap_or(MachineType::X86) {
|
||||||
MachineType::X86 => {
|
MachineType::X86 => {
|
||||||
xshell::cmd!("cargo run --release").run()?;
|
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 => {
|
MachineType::Arm => {
|
||||||
xshell::cmd!("cargo build --release --target=json_targets/aarch64-ableos.json")
|
xshell::cmd!("cargo build --release --target=json_targets/aarch64-ableos.json")
|
||||||
|
|
Loading…
Reference in a new issue