initial commit
This commit is contained in:
commit
5e07492252
7
.cargo/config.toml
Normal file
7
.cargo/config.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[unstable]
|
||||||
|
build-std = ["core", "compiler_builtins", "alloc"]
|
||||||
|
build-std-features = ["compiler-builtins-mem"]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target = "dos.json"
|
||||||
|
rustflags = ["-C", "opt-level=z"]
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust-le-demo"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["lucia"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
heapless = { version = "0.7.16", features = ["ufmt-impl"] }
|
||||||
|
spin = "0.9.4"
|
||||||
|
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
lto = "fat"
|
||||||
|
codegen-units = 1
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
lto = "fat"
|
||||||
|
codegen-units = 1
|
30
dos.json
Normal file
30
dos.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"arch": "x86",
|
||||||
|
"cpu": "i386",
|
||||||
|
"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128",
|
||||||
|
"dynamic-linking": false,
|
||||||
|
"executables": true,
|
||||||
|
"exe-suffix": ".elf",
|
||||||
|
"linker-flavor": "gcc",
|
||||||
|
"linker-is-gnu": true,
|
||||||
|
"llvm-target": "i586-unknown-none-none",
|
||||||
|
"max-atomic-width": 64,
|
||||||
|
"position-independent-executables": false,
|
||||||
|
"relocation-model": "static",
|
||||||
|
"disable-redzone": true,
|
||||||
|
"pre-link-args": {
|
||||||
|
"gcc": [
|
||||||
|
"-m32",
|
||||||
|
"-nostdlib",
|
||||||
|
"-march=i386",
|
||||||
|
"-Wl,-r"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"relro-level": "full",
|
||||||
|
"target-c-int-width": "32",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": "32",
|
||||||
|
"os": "none",
|
||||||
|
"vendor": "unknown",
|
||||||
|
"panic-strategy": "abort"
|
||||||
|
}
|
1
rust-toolchain
Normal file
1
rust-toolchain
Normal file
@ -0,0 +1 @@
|
|||||||
|
nightly
|
120
src/dpmi.rs
Normal file
120
src/dpmi.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
use core::{arch::asm, fmt::{Arguments, Write}};
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct DpmiRegs {
|
||||||
|
pub edi: u32,
|
||||||
|
pub esi: u32,
|
||||||
|
pub ebp: u32,
|
||||||
|
reserved_zero: u32,
|
||||||
|
pub ebx: u32,
|
||||||
|
pub edx: u32,
|
||||||
|
pub ecx: u32,
|
||||||
|
pub eax: u32,
|
||||||
|
pub status_flags: u16,
|
||||||
|
pub es: u16,
|
||||||
|
pub ds: u16,
|
||||||
|
pub fs: u16,
|
||||||
|
pub gs: u16,
|
||||||
|
ip_ignored: u16,
|
||||||
|
cs_ignored: u16,
|
||||||
|
pub sp: u16,
|
||||||
|
pub ss: u16
|
||||||
|
}
|
||||||
|
impl DpmiRegs {
|
||||||
|
pub const fn zero() -> Self {
|
||||||
|
DpmiRegs { edi: 0, esi: 0, ebp: 0, reserved_zero: 0, ebx: 0, edx: 0, ecx: 0, eax: 0, status_flags: 0, es: 0, ds: 0, fs: 0, gs: 0, ip_ignored: 0, cs_ignored: 0, sp: 0, ss: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_video_mode(mode: u8) {
|
||||||
|
let mut regs = DpmiRegs::zero();
|
||||||
|
regs.eax = mode as u32;
|
||||||
|
real_int(0x10, &mut regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getchar() -> u16 {
|
||||||
|
let mut regs = DpmiRegs::zero();
|
||||||
|
real_int(0x16, &mut regs);
|
||||||
|
regs.eax as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kb_status() -> Option<u16> {
|
||||||
|
let mut regs = DpmiRegs::zero();
|
||||||
|
regs.eax = 0x100;
|
||||||
|
real_int(0x16, &mut regs);
|
||||||
|
match regs.status_flags & 0x40 {
|
||||||
|
0 => match regs.eax as u16 {
|
||||||
|
0 => None,
|
||||||
|
v => Some(v),
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_psp() -> *const u8 {
|
||||||
|
let psp: u32;
|
||||||
|
unsafe { asm!(
|
||||||
|
"int 0x21",
|
||||||
|
in("ax") 0x5100_u16,
|
||||||
|
out("ebx") psp
|
||||||
|
); }
|
||||||
|
(psp << 4) as *const u8
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn real_int(int: u8, regs: &mut DpmiRegs) {
|
||||||
|
unsafe { asm!(
|
||||||
|
"int 0x31",
|
||||||
|
in("bx") 0x0000_u16 | int as u16,
|
||||||
|
in("cx") 0x0000_u16,
|
||||||
|
in("edi") regs,
|
||||||
|
inout("ax") 0x0300_u16 => _
|
||||||
|
);}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dpmi_print(string: &str) {
|
||||||
|
// DOS DPMI function 21h, AH 9h
|
||||||
|
// Prints string pointed to
|
||||||
|
// by EDX, terminated with $
|
||||||
|
unsafe { asm!(
|
||||||
|
"int 0x21",
|
||||||
|
in("ah") 0x9_u8,
|
||||||
|
in("edx") string.as_ptr()
|
||||||
|
); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dpmi_exit() -> ! {
|
||||||
|
// DOS DPMI function Exit: 21h, AH 4Ch
|
||||||
|
unsafe { asm!(
|
||||||
|
"int 0x21",
|
||||||
|
in("ah") 0x4C_u8
|
||||||
|
); }
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! _raw_print {
|
||||||
|
($($arg:tt)*) => ($crate::dpmi::_print(format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ($crate::_raw_print!("{}$", format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
() => (_raw_print!("\r\n$"));
|
||||||
|
($($arg:tt)*) => ($crate::_raw_print!("{}\r\n$", format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn _print(args: Arguments) {
|
||||||
|
let mut s: alloc::string::String = alloc::string::String::new();
|
||||||
|
//let mut s: heapless::String<20> = heapless::String::new();
|
||||||
|
s.write_fmt(args).unwrap();
|
||||||
|
dpmi_print(s.as_str());
|
||||||
|
}
|
||||||
|
|
192
src/dpmi_alloc.rs
Normal file
192
src/dpmi_alloc.rs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
use core::{ptr::null_mut, arch::asm, alloc::Layout};
|
||||||
|
use core::fmt::Write;
|
||||||
|
use heapless::String;
|
||||||
|
|
||||||
|
const PTR_COUNT: usize = 1024;
|
||||||
|
|
||||||
|
struct Locked<A> {
|
||||||
|
inner: spin::Mutex<A>,
|
||||||
|
}
|
||||||
|
impl<A> Locked<A> {
|
||||||
|
pub const fn new(inner: A) -> Self {
|
||||||
|
Locked {
|
||||||
|
inner: spin::Mutex::new(inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn lock(&self) -> spin::MutexGuard<A> {
|
||||||
|
self.inner.lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_allocator() { unsafe {
|
||||||
|
ALLOCATOR.inner.force_unlock();
|
||||||
|
let mut t = ALLOCATOR.lock();
|
||||||
|
// 3.53 - DOS function 0FF91h - DOS/32 Advanced Allocate High Memory Block
|
||||||
|
// In: AX = 0FF91h
|
||||||
|
// EBX = size of memory block in bytes
|
||||||
|
// Out:
|
||||||
|
// if successful:
|
||||||
|
// CF clear
|
||||||
|
// EBX = linear address of allocated memory block
|
||||||
|
// ESI = handle of allocated memory block
|
||||||
|
// if failed:
|
||||||
|
// CF set
|
||||||
|
let ptr: u32;
|
||||||
|
let handle: u32;
|
||||||
|
asm!(
|
||||||
|
"mov edx, esi",
|
||||||
|
"int 0x21",
|
||||||
|
"mov eax, esi",
|
||||||
|
"mov esi, edx",
|
||||||
|
inout("eax") 0x0FF91 => handle,
|
||||||
|
inout("ebx") PTR_COUNT * core::mem::size_of::<DpmiPtr>() => ptr,
|
||||||
|
out("edx") _
|
||||||
|
);
|
||||||
|
t.ptrs = ptr;
|
||||||
|
t.global_handle = handle;
|
||||||
|
let mut ptrs = core::slice::from_raw_parts_mut::<DpmiPtr>(t.ptrs as *mut DpmiPtr, PTR_COUNT);
|
||||||
|
for p in ptrs.iter_mut() {
|
||||||
|
*p = DpmiPtr { ptr: 0, handle: 0 };
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct DpmiPtr {
|
||||||
|
ptr: u32,
|
||||||
|
handle: u32
|
||||||
|
}
|
||||||
|
pub struct DpmiAlloc {
|
||||||
|
ptrs: u32,
|
||||||
|
global_handle: u32
|
||||||
|
}
|
||||||
|
impl DpmiAlloc {
|
||||||
|
const fn new() -> Self { DpmiAlloc { ptrs: 0, global_handle: 0 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl core::alloc::GlobalAlloc for Locked<DpmiAlloc> {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let mut dat = self.lock();
|
||||||
|
let mut ptrs = unsafe { core::slice::from_raw_parts_mut::<DpmiPtr>(dat.ptrs as *mut DpmiPtr, PTR_COUNT) };
|
||||||
|
let free_idx: usize = {
|
||||||
|
let mut tmp = None;
|
||||||
|
for (i, p) in ptrs.iter().enumerate() {
|
||||||
|
if p.ptr == 0 { tmp = Some(i); break; }
|
||||||
|
}
|
||||||
|
match tmp {
|
||||||
|
None => { asm!("int 0x1", in("eax") ptrs.as_ptr()); return null_mut(); }
|
||||||
|
Some(i) => i
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 3.53 - DOS function 0FF91h - DOS/32 Advanced Allocate High Memory Block
|
||||||
|
// In: AX = 0FF91h
|
||||||
|
// EBX = size of memory block in bytes
|
||||||
|
// Out:
|
||||||
|
// if successful:
|
||||||
|
// CF clear
|
||||||
|
// EBX = linear address of allocated memory block
|
||||||
|
// ESI = handle of allocated memory block
|
||||||
|
// if failed:
|
||||||
|
// CF set
|
||||||
|
let ptr: u32;
|
||||||
|
let handle: u32;
|
||||||
|
asm!(
|
||||||
|
"mov edx, esi",
|
||||||
|
"int 0x21",
|
||||||
|
"mov eax, esi",
|
||||||
|
"mov esi, edx",
|
||||||
|
inout("eax") 0x0FF91 => handle,
|
||||||
|
inout("ebx") layout.size() as u32 => ptr,
|
||||||
|
out("edx") _
|
||||||
|
);
|
||||||
|
ptrs[free_idx] = DpmiPtr { ptr, handle };
|
||||||
|
ptr as *mut u8
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||||
|
if ptr as u32 == 0 { return; }
|
||||||
|
let mut dat = self.lock();
|
||||||
|
let mut ptrs = unsafe { core::slice::from_raw_parts_mut::<DpmiPtr>(dat.ptrs as *mut DpmiPtr, PTR_COUNT) };
|
||||||
|
let mut found_idx: Option<usize> = None;
|
||||||
|
for i in 0..ptrs.len() {
|
||||||
|
if ptrs[i].ptr == ptr as u32 { found_idx = Some(i); break; }
|
||||||
|
}
|
||||||
|
let handle = match found_idx {
|
||||||
|
None => return,
|
||||||
|
Some(i) => ptrs[i].handle
|
||||||
|
};
|
||||||
|
// 3.54 - DOS function 0FF92h - DOS/32 Advanced Free High Memory Block
|
||||||
|
// In: AX = 0FF92h
|
||||||
|
// ESI = handle of previously allocated memory block
|
||||||
|
// Out:
|
||||||
|
// if successful:
|
||||||
|
// CF clear
|
||||||
|
// if failed:
|
||||||
|
// CF set
|
||||||
|
asm!(
|
||||||
|
"mov edx, esi",
|
||||||
|
"mov esi, ebx",
|
||||||
|
"int 0x21",
|
||||||
|
"mov esi, edx",
|
||||||
|
in("eax") 0x0FF92,
|
||||||
|
in("ebx") handle,
|
||||||
|
out("edx") _
|
||||||
|
);
|
||||||
|
ptrs[found_idx.unwrap()] = DpmiPtr { ptr: 0, handle: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 {
|
||||||
|
if ptr.is_null() { return null_mut(); }
|
||||||
|
let mut dat = self.lock();
|
||||||
|
let mut ptrs = core::slice::from_raw_parts_mut::<DpmiPtr>(dat.ptrs as *mut DpmiPtr, PTR_COUNT);
|
||||||
|
let mut found_idx: Option<usize> = None;
|
||||||
|
for i in 0..ptrs.len() {
|
||||||
|
if ptrs[i].ptr == ptr as u32 { found_idx = Some(i); break; }
|
||||||
|
}
|
||||||
|
let old_handle = match found_idx {
|
||||||
|
None => return null_mut(),
|
||||||
|
Some(i) => ptrs[i].handle
|
||||||
|
};
|
||||||
|
// 3.55 - DOS function 0FF93h - DOS/32 Advanced Resize High Memory Block
|
||||||
|
// In: AX = 0FF93h
|
||||||
|
// EBX = new size of memory block in bytes
|
||||||
|
// ESI = handle of previously allocated memory block
|
||||||
|
// Out:
|
||||||
|
|
||||||
|
// if successful:
|
||||||
|
// CF clear
|
||||||
|
// EBX = new linear address of allocated memory block
|
||||||
|
// ESI = new handle of allocated memory block
|
||||||
|
|
||||||
|
// if failed:
|
||||||
|
// CF set
|
||||||
|
let ptr: u32;
|
||||||
|
let handle: u32;
|
||||||
|
asm!(
|
||||||
|
"xchg edx, esi",
|
||||||
|
"int 0x21",
|
||||||
|
"xchg esi, edx",
|
||||||
|
inout("eax") 0x0FF93 => _,
|
||||||
|
inout("ebx") new_size as u32 => ptr,
|
||||||
|
inout("edx") old_handle => handle
|
||||||
|
);
|
||||||
|
ptrs[found_idx.unwrap()] = DpmiPtr { ptr, handle };
|
||||||
|
ptr as *mut u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: Locked<DpmiAlloc> = Locked::new(DpmiAlloc::new());
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn _print(args: core::fmt::Arguments) {
|
||||||
|
let mut s: String<256> = String::new();
|
||||||
|
s.write_fmt(args).unwrap();
|
||||||
|
crate::dpmi::dpmi_print(s.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn alloc_error_handler(layout: Layout) -> ! {
|
||||||
|
_print(format_args!("allocation error: {:?}$", layout));
|
||||||
|
crate::dpmi::dpmi_exit();
|
||||||
|
}
|
||||||
|
|
34
src/main.rs
Normal file
34
src/main.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
#![feature(abi_x86_interrupt)]
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
mod dpmi;
|
||||||
|
mod dpmi_alloc;
|
||||||
|
mod panic;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
debug_trap!();
|
||||||
|
println!("Done.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug_trap {
|
||||||
|
() => { unsafe { asm!("int 0x1"); } };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn start() {
|
||||||
|
unsafe { asm!(
|
||||||
|
"push ds",
|
||||||
|
"pop es",
|
||||||
|
); }
|
||||||
|
main();
|
||||||
|
dpmi::dpmi_exit();
|
||||||
|
}
|
8
src/panic.rs
Normal file
8
src/panic.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use crate::dpmi::dpmi_exit;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
//crate::println!("Panic! {}", info);
|
||||||
|
dpmi_exit();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user