1
0
Fork 0
mirror of https://git.sr.ht/~asya/copycat synced 2024-11-21 23:18:42 -06:00

Start CrabBIOS, implement firmware loading and push/pop/ret

Signed-off-by: AsyaTheAbove <asya@waifu.club>
This commit is contained in:
AsyaTheAbove 2023-10-08 17:50:05 +03:00
parent 911d6e844b
commit e3906f2dc3
8 changed files with 297 additions and 3 deletions

160
Cargo.lock generated
View file

@ -19,6 +19,54 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "anstream"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.4.0" version = "2.4.0"
@ -31,11 +79,45 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]] [[package]]
name = "copycat" name = "copycat"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"clap",
"hashbrown", "hashbrown",
] ]
@ -55,8 +137,86 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View file

@ -7,4 +7,5 @@ edition = "2021"
[dependencies] [dependencies]
bitflags = "2.4.0" bitflags = "2.4.0"
clap = { version = "4.4.6", features = ["cargo"] }
hashbrown = "0.14.0" hashbrown = "0.14.0"

13
build.rs Normal file
View file

@ -0,0 +1,13 @@
use std::process::Command;
fn main() {
// Tell Cargo that if the given file changes, to rerun this build script.
println!("cargo:rerun-if-changed=crabbios/crabbios.asm");
Command::new("nasm")
.arg("crabbios/crabbios.asm")
.args(["-f", "bin"])
.args(["-o", "roms/crabbios.bin"])
.args(["-I", "crabbios"])
.spawn()
.unwrap();
}

3
crabbios/README.md Normal file
View file

@ -0,0 +1,3 @@
# CrabBIOS
BIOS implementation in x86 real mode assembly

27
crabbios/crabbios.asm Normal file
View file

@ -0,0 +1,27 @@
bits 16 ; we're in 16 bit real mode
org 0xfe000 ; that's where we're loaded
start: ; we jump here after the entry point
mov ax, 0xFF
push ax
pop bx
hlt
; fill until the reset vector
times 4080 - ($ - start) db 0
; entry point
; we shouldn't assume any initial state here
cli
; set up stack at 0:0x7c00
; that's just below where we'll load the boot sector
mov ax, 0
mov ss, ax
mov sp, 0x7c00
; jump over to start
jmp start
; fill the last bytes
times 4096 - ($ - start) db 0

View file

@ -4,16 +4,40 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
use std::fs;
use clap::{command, arg};
use copycat::memory::{Memory, KiB}; use copycat::memory::{Memory, KiB};
use copycat::processor::{Instruction, Processor}; use copycat::processor::{Instruction, Processor};
use copycat::io::IoBus; use copycat::io::IoBus;
static BIOS_ROM: &[u8; 8 * KiB as usize] = include_bytes!("../roms/BIOS_IBM5150_24APR81_5700051_U33.BIN"); static BIOS_ROM: &[u8; 4 * KiB as usize] = include_bytes!("../roms/crabbios.bin");
fn main() { fn main() {
let matches = command!()
.arg(arg!(-b --bios <BIOS> "Firmware image to load"))
.get_matches();
let maybe_bios;
let bios: &[u8] = match matches.get_one::<String>("bios") {
Some(bios) => {
maybe_bios = fs::read(bios).unwrap();
&maybe_bios
},
None => BIOS_ROM,
};
if bios.len() == 0 {
panic!("firmware image empty");
}
if bios.len() % 4 * KiB as usize != 0 {
panic!("firmware image length not a multiple of a page");
}
let bios_len = bios.len() / (4 * KiB) as usize;
let mut mem = Memory::new(64 * KiB); let mut mem = Memory::new(64 * KiB);
mem.add_tlb_entry(0xfe, BIOS_ROM.as_ptr().cast_mut().cast()); for i in 0xff - bios_len + 1..=0xff {
mem.add_tlb_entry(0xff, unsafe { BIOS_ROM.as_ptr().add(4 * KiB as usize) }.cast_mut().cast()); mem.add_tlb_entry(i as u64, unsafe { bios.as_ptr().add((i - (0xff - bios_len + 1)) * 4 * KiB as usize) }.cast_mut().cast());
}
// mem.write(0xffff0, [0x90, 0x04, 0x69, 0xF4]); // mem.write(0xffff0, [0x90, 0x04, 0x69, 0xF4]);
let mut io = IoBus::default(); let mut io = IoBus::default();
let mut cpu = Processor::default(); let mut cpu = Processor::default();

View file

@ -98,6 +98,22 @@ impl Instruction {
0x4D => (Dec, BP, NoOperand), 0x4D => (Dec, BP, NoOperand),
0x4E => (Dec, SI, NoOperand), 0x4E => (Dec, SI, NoOperand),
0x4F => (Dec, DI, NoOperand), 0x4F => (Dec, DI, NoOperand),
0x50 => (Push, AX, NoOperand),
0x51 => (Push, CX, NoOperand),
0x52 => (Push, DX, NoOperand),
0x53 => (Push, BX, NoOperand),
0x54 => (Push, SP, NoOperand),
0x55 => (Push, BP, NoOperand),
0x56 => (Push, SI, NoOperand),
0x57 => (Push, DI, NoOperand),
0x58 => (Pop, AX, NoOperand),
0x59 => (Pop, CX, NoOperand),
0x5A => (Pop, DX, NoOperand),
0x5B => (Pop, BX, NoOperand),
0x5C => (Pop, SP, NoOperand),
0x5D => (Pop, BP, NoOperand),
0x5E => (Pop, SI, NoOperand),
0x5F => (Pop, DI, NoOperand),
0x70 => (Jo, Imm8, NoOperand), 0x70 => (Jo, Imm8, NoOperand),
0x71 => (Jno, Imm8, NoOperand), 0x71 => (Jno, Imm8, NoOperand),
0x72 => (Jc, Imm8, NoOperand), 0x72 => (Jc, Imm8, NoOperand),
@ -139,6 +155,10 @@ impl Instruction {
0xBD => (Mov, BP, Imm16), 0xBD => (Mov, BP, Imm16),
0xBE => (Mov, SI, Imm16), 0xBE => (Mov, SI, Imm16),
0xBF => (Mov, DI, Imm16), 0xBF => (Mov, DI, Imm16),
0xC2 => (Retn, Imm16, NoOperand),
0xC3 => (Retn, NoOperand, NoOperand),
0xCA => (Retf, Imm16, NoOperand),
0xCB => (Retf, NoOperand, NoOperand),
0xD0 => { 0xD0 => {
modrm = ModRM::from_bits(memory.read_u8(address + size as u64)); modrm = ModRM::from_bits(memory.read_u8(address + size as u64));
size += 1; size += 1;
@ -448,6 +468,10 @@ pub enum Mnemonic {
Nop, Nop,
Or, Or,
Out, Out,
Pop,
Push,
Retf,
Retn,
Sahf, Sahf,
Sbb, Sbb,
Shl, Shl,

View file

@ -195,6 +195,14 @@ impl Processor {
self.set_operand16(value, memory, op1, instruction.segment_override); self.set_operand16(value, memory, op1, instruction.segment_override);
}, },
(Push, Operand(op1, Word), _) => {
let value = self.operand16(memory, op1, instruction.segment_override);
self.push16(value, memory);
},
(Pop, Operand(op1, Word), _) => {
let value = self.pop16(memory);
self.set_operand16(value, memory, op1, instruction.segment_override);
},
(Jo, Operand(Imm8(op1), Byte), _) => (Jo, Operand(Imm8(op1), Byte), _) =>
if self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, if self.registers.of() { self.registers.add_ip(op1 as i8 as i16) },
(Jno, Operand(Imm8(op1), Byte), _) => (Jno, Operand(Imm8(op1), Byte), _) =>
@ -238,6 +246,28 @@ impl Processor {
self.set_operand8(self.operand8(memory, op2, instruction.segment_override), memory, op1, instruction.segment_override), self.set_operand8(self.operand8(memory, op2, instruction.segment_override), memory, op1, instruction.segment_override),
(Mov, Operand(op1, Word), Operand(op2, Word)) => (Mov, Operand(op1, Word), Operand(op2, Word)) =>
self.set_operand16(self.operand16(memory, op2, instruction.segment_override), memory, op1, instruction.segment_override), self.set_operand16(self.operand16(memory, op2, instruction.segment_override), memory, op1, instruction.segment_override),
(Retn, Operand(Imm16(parameters), _), _) => {
let ip = self.pop16(memory);
self.registers.set_ip(ip);
self.registers.set_sp(self.registers.sp() + parameters);
},
(Retn, _, _) => {
let ip = self.pop16(memory);
self.registers.set_ip(ip);
},
(Retf, Operand(Imm16(parameters), _), _) => {
let ip = self.pop16(memory);
let cs = self.pop16(memory);
self.registers.set_ip(ip);
self.registers.set_cs(cs);
self.registers.set_sp(self.registers.sp() + parameters);
},
(Retf, _, _) => {
let ip = self.pop16(memory);
let cs = self.pop16(memory);
self.registers.set_ip(ip);
self.registers.set_cs(cs);
},
(Shl, Operand(op1, Byte), Operand(op2, Byte)) => 'shl: { (Shl, Operand(op1, Byte), Operand(op2, Byte)) => 'shl: {
let dst = self.operand8(memory, op1, instruction.segment_override); let dst = self.operand8(memory, op1, instruction.segment_override);
let shift = self.operand8(memory, op2, instruction.segment_override); let shift = self.operand8(memory, op2, instruction.segment_override);
@ -500,4 +530,16 @@ impl Processor {
SegmentOverride::DS | SegmentOverride::None => self.registers.ds(), SegmentOverride::DS | SegmentOverride::None => self.registers.ds(),
} as u64) << 4) + offset as u64 } as u64) << 4) + offset as u64
} }
fn push16(&mut self, value: u16, memory: &mut Memory) {
self.registers.set_sp(self.registers.sp() - 2);
let address = ((self.registers.ss() as u64) << 4) + self.registers.sp() as u64;
memory.write_u16(address, value);
}
fn pop16(&mut self, memory: &Memory) -> u16 {
let address = ((self.registers.ss() as u64) << 4) + self.registers.sp() as u64;
self.registers.set_sp(self.registers.sp() + 2);
memory.read_u16(address)
}
} }