From d1cc8703377de1f2f2e34669058b96bf438d5413 Mon Sep 17 00:00:00 2001 From: Nero <41307858+nero@users.noreply.github.com> Date: Fri, 29 Jan 2021 00:44:26 +0000 Subject: [PATCH] Import work --- Makefile | 13 +++ README.md | 73 +++++++++++++ mon8086.asm | 297 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 383 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 mon8086.asm diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..367da87 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +NASM = nasm +QEMU = qemu-system-i386 + +default: mon8086.bs + +%.bs: %.asm + $(NASM) -o $@ $< + +qemu: mon8086.bs + $(QEMU) -hda mon8086.bs + +clean: + rm *.bs diff --git a/README.md b/README.md new file mode 100644 index 0000000..b6dcc95 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +A control monitor program for the Intel 8086 in a single sector (512 bytes) + +Its main use it to help me debugging disk i/o and boot issues on IBM PC compatibles. + +## Building + +Run `make`. Requires the NASM assembler. + +## How to get it running + +You can run `make qemu` to make it run in qemu. + +If you want to run it on a real machine, you need to write it to the boot sector first: + +`dd if=mon8086.bs of=/dev/sdb1`. + +## Input commands + +There is no real line editing - key presses have instant effect. + +- D: Dump the memory at the memory pointer. The pointer is advanced by the dumped bytes. +- E: Edit bytes at the memory pointer. You can cancel the editing by pressing space. +- S: Edit the segment of the memory pointer. +- O: Edit the offset of the memory pointer. +- R: Show the register set and next instruction bytes. +- V: This command expects a two-character argument naming the register to be changed. It allows then to edit the register value. +- G: Start execution at CS:IP address +- T: Single-step a single instruction at CS-IP + +Several commands allow the user to edit a value. +While editing, pressing space results in the value being discarded. +The monitor will then return to the prompt. +This is useful for the inspection of values. + +## Sample inputs + +### Hexdump the bios data area + +``` +S 0040 +O 0000 +D +``` + +### Query drive parameters + +``` +E B4 08 B2 80 CD 13 CC +G +``` + +Replace the 80 with the bios drive number (00, 01 and 80 are common values). +The results are spread over the CX and DX registers, check Ralf Browns Interrupt List or your BIOS documentation for INT 13h/AH=8 on how to interpret the results. + + +### Boot arbitrary drive + +``` +O 7BF2 +E B8 01 02 B9 01 00 BA 80 00 BB 00 7C CD 13 +V IP 7BF2 +G +``` + +Replace the 80 with the bios drive number (00, 01 and 80 are common values). + +### Reboot the machine + +``` +V CS FFFF +V IP 0000 +G +``` diff --git a/mon8086.asm b/mon8086.asm new file mode 100644 index 0000000..9d8caaf --- /dev/null +++ b/mon8086.asm @@ -0,0 +1,297 @@ +; monitor program that fits in a boot sector +; for debugging disk i/o and bootstrapping + +%define base (0x10000 - 0x200) + + org base + cpu 8086 + + ; relocate to end of memory +init: ; set up src addr + xor ax, ax + mov ds, ax + mov si, 0x7C00 + ; calculate target segment + mov ax, [0x413] + mov cl, 6 + shl ax, cl + sub ax, 0x1000 + ; set up dst addr + mov es, ax + mov di, base + ; set up stack + mov ss, ax + mov sp, di + ; push defptr + push ds + push si + ; relocate + mov cx, 0x100 + rep movsw + ; reset ES for later prog + mov es, cx + ; set up intr vectors + mov bx, 1*4 + call .l02 + ; enter + mov si, 0x7C00-1 + mov byte [si], 0xCC + push cs + push si + sti + retf + + ; call here = run proc tail twice +.l02: call .l01 +.l01: mov word [bx], entry + mov word [bx+2], ss + add bx, 2*4 + ret + +nl: mov ax, 0x0e0A + int 0x10 + mov al, 0x0D + jmp putc + +space: mov al, ' ' +putc: mov ah, 0x0e + int 0x10 + ret + + ; print register set +printr: call nl + xor si, si +.l02: mov ah, 0x0e + mov al, [cs:lbls+si] + int 0x10 + mov al, [cs:lbls+si+1] + int 0x10 + mov al, '=' + int 0x10 + mov dx, [bp+si] + mov ch, ' ' + call prints + add si, 2 + cmp si, 24 + jc .l02 + les bx, [bp+18] + jmp dump + + ; print 16 bytes from ES:BX +dump: mov dx, es + mov ch, ':' + call prints + mov dx, bx + mov ch, ' ' + call prints + push bx + mov cx, 0x10 +.l01: mov dh, [es:bx] + inc bx + push cx + call printb + call space + pop cx + loop .l01 + pop bx + ret + +printw: call printb ; print dx +printb: call .l01 ; print dh +.l01: mov cl, 4 + ; grab highest nibble from dx + mov al, dh + ; remove highest nibble from dx + shl dx, cl + ; shift away second-highest nibble that we accidentally copied + shr al, cl +printn: ; map 0-9 to ascii codes for '0' to '9' + add al, 0x30 + ; if result is larger than '9', ... + cmp al, 0x3a + jl .noadj + ; ... add 7 so we continue at 'A' + add al, 7 +.noadj: mov ah, 0x0e + int 0x10 + ret + + ; print dx and char ch +prints: call printw + mov al, ch + int 0x10 + ret + +getc: xor ax, ax + int 0x16 + test al, al + jz getc + ; to uppercase + cmp al, 0x60 + jc .ret + sub al, 0x20 +.ret: ret + +inputw: call inputb +inputb: call inputn +inputn: jc .ret + call getc + cmp al, 0x20 + stc + je .ret + sub al, 0x30 + ; if >9, turn 'A' to A + cmp al, 0x0A + jc .noadj + sub al, 7 +.noadj: ; must be smaller than 'F' + cmp al, 0x10 + jnc inputn + ; append to dx + mov cl, 4 + shl dx, cl + or dl, al + ; print, loop & clear exit + call printn + clc +.ret: ret + + ; edit word at ES:BX + ; space exits with carry +editw: mov dx, [es:bx] + mov ch, '.' + call prints + clc + call inputw + jc .err + mov [es:bx], dx +.err: ret + +cmd_o: mov bx, di + jmp cmd_s.l01 + +cmd_s: lea bx, [di+2] +.l01: call editw + jmp cmd + +cmd_e: les bx, [cs:di] + mov dh, [es:bx] + call printb + mov al, '.' + int 0x10 + mov cx, 2 + clc + call inputb + jc cmd + mov [es:bx], dl + inc word [cs:di] + call space + jmp cmd_e + +entry: push es + push ds + push di + push si + push bp + push bx + push dx + push cx + push ax + mov bp, sp + +cmd_r: call printr +cmd: ; display prompt + call nl + mov al, '-' + call putc +.l01: call getc + cmp al, 0x41 + jc .l01 + ; process input char + call putc + push ax + call space + pop ax + ; set up default for cmds + mov dx, cs + mov ds, dx + mov es, dx + mov di, defptr + ; show and edit mem + cmp al, 'D' + je cmd_d + cmp al, 'E' + je cmd_e + ; show and edit regs + cmp al, 'R' + je cmd_r + cmp al, 'V' + je cmd_v + ; actions + cmp al, 'G' + je cmd_g + cmp al, 'T' + je cmd_t + ; set working ptr + cmp al, 'S' + je cmd_s + cmp al, 'O' + je cmd_o + +err: mov al, '?' + call putc + jmp cmd + +cmd_d: les bx, [di] + mov cx, 8 +.l01: push cx + call nl + call dump + pop cx + add bx, 0x10 + mov [cs:di], bx + loop .l01 + jmp cmd + +cmd_v: call regn + mov ax, dx + mov di, lbls + mov cx, 11 + repne scasw + jne err + sub di, lbls+2 + lea bx, [bp+di] + call space + call editw + jmp cmd + +regn: call .l01 + xchg dh, dl +.l01: call getc + call putc + mov dh, al + ret + +cmd_t: or byte [bp+23], 1 + jmp exit +cmd_g: and byte [bp+23], 0xFE +exit: pop ax + pop cx + pop dx + pop bx + pop bp + pop si + pop di + pop ds + pop es + iret + + ; names for registers +lbls: db "AXCXDXBXBPSIDI" ; gpr + db "DSES" ; seg regs + db "IPCSFL" ; iret frmae + +defptr: equ (base-4) + + times 510-($-$$) db 0x00 + db 0x55,0xaa