Skip to content

Instantly share code, notes, and snippets.

@berkus
Forked from shikhin/Selfer.asm
Created March 19, 2013 08:34
Show Gist options
  • Save berkus/5194529 to your computer and use it in GitHub Desktop.
Save berkus/5194529 to your computer and use it in GitHub Desktop.
;
; Selfer.
;
; Shikhin Sethi, the author of selfer, has dedicated the work to the public domain
; by waiving all of his or her rights to the work worldwide under copyright law,
; including all related and neighboring rights, to the extent allowed by law.
;
; You can copy, modify, distribute and perform the work, even for commercial purposes,
; all without asking permission.
;
; https://creativecommons.org/publicdomain/zero/1.0/
;
BITS 16
ORG 0x7C00
; Some defines.
%define SECTOR_SIZE 512
%define SECTORS_PER_TRACK 18
%define HEADS 2
%define TRACKS 80
%define READ_SECTOR 0x00
%define WRITE_SECTOR 0x01
%define LEFT_SCANCODE 75
%define RIGHT_SCANCODE 77
%define UP_SCANCODE 72
%define DOWN_SCANCODE 80
%define FREE_SPACE 0x500
; Output an entire sector.
; EBP -> contains the base address of the sector to output.
; ESI -> current index.
%macro OUTPUT_SECTOR 0
pushad
; ES for screen output.
mov ax, 0xB800
mov es, ax
xor di, di
mov cx, 512
mov eax, 0x0F300C30
rep stosd
mov ecx, ebp
add cx, si
shl si, 2
mov dword [es:si], 0x02300230
xor si, si
call Main.GetSegment
.Loop:
mov dl, [gs:bx]
call HexToASCII
mov [es:si], ah
mov [es:si + 2], al
add si, 4
inc bx
cmp si, 2048
jb .Loop
mov edx, ecx
mov si, 0xF0E
mov cx, 4
.L2:
call HexToASCII
mov [es:si], al
mov [es:si - 2], ah
.Next8Bits:
sub si, 4
shr edx, 8
loop .L2
popad
%endmacro
CPU 8086
; Main entry point where BIOS leaves us.
; DL -> Expects the drive number to be present in dl.
; CS:IP -> Expects CS:IP to point to the linear address 0x7C00.
Main:
jmp 0x0000:.FlushCS ; Some BIOS' may load us at 0x0000:0x7C00, while others at 0x07C0:0x0000. Let's just make this uniform.
CPU 386
; I was lazy, so just stuffed this here.
; EBP + SI -> somewhere.
;
; Returns:
; GS:BX -> same somewhere.
.GetSegment:
add ebp, esi
mov ebx, ebp
shr ebx, 4
and bx, 0xF000
mov gs, bx
mov bx, bp
sub ebp, esi
ret
CPU 8086
.Error386:
mov al, '$'
.Error:
; Print AL.
xor bx, bx
mov ah, 0x0E
int 0x10
jmp $
CPU 386
.GetLBA:
mov ebx, ebp
shr ebx, 9
sub bx, 0x3E
; Since a write is going to follow, do that.
xor di, di
inc di
ret
CPU 8086
.FlushCS:
; Set up segments.
xor bx, bx
; Stack.
mov ss, bx
mov sp, Main
mov ds, bx
; Check if CPU is 80386 or not.
; Invert the IOPL bits, since on 8086/80186 they are hardwired to 1.
; In real mode on the 286, they are always 0, though.
pushf
pop ax
xor ah, 0x30
; Get them back.
push ax
popf
; Get flags to check if anything changed.
pushf
; Get new flags in CX.
pop cx
; Test if bits changed, or not.
xor ah, ch
test ah, ah
jnz .Error386
CPU 386
cld
mov [FREE_SPACE], dl
; Set to mode 0x03, or 80x25 text mode.
; AH should be zero as used above.
mov al, 0x03
int 0x10
; Set EBP (base address of sector/512b segment)
.ReturnJmp:
movzx ebp, sp
xor esi, esi
; Events.
EventLoop:
OUTPUT_SECTOR
; GS:BX now points to where we are.
call Main.GetSegment
xor ah, ah
; Get input.
int 0x16
; Left key (previous byte)
.Left:
cmp ah, LEFT_SCANCODE
jne .Right
dec si
jmp .Next
; Right key (next byte)
.Right:
cmp ah, RIGHT_SCANCODE
jne .Retain
inc si
jmp .Next
; Retain.
.Retain:
cmp al, 'k'
jne .Paste
; Save the current byte pointing too.
mov [FREE_SPACE + 2], gs
mov [FREE_SPACE + 4], bx
jmp .Next
; Paste.
.Paste:
cmp al, 'p'
jne .Run
; Get the pair in ES:DI.
mov edi, [FREE_SPACE + 2]
mov es, di
shr edi, 16
; Paste the byte.
mov cx, [es:di]
mov [gs:bx], cx
; Move one point below, and decrement the byte pointing to at.
dec si
dec word [FREE_SPACE + 4]
; We wrote something.
jmp .WroteNext
; Run from the current cell.
.Run:
cmp al, 'r'
jne .Write
; So that you can far ret from the code.
push cs
push .Next
; Get where to jump to.
push gs
push bx
retf
; Write's the current sector.
.Write:
cmp al, 'w'
jne .DownUp
; Get the LBA, and write.
call Main.GetLBA
call RWSector
jmp .Next
; Down/up key (next sector/previous sector)
.DownUp:
cmp ah, DOWN_SCANCODE
jne .Up
; Not fit?
cmp ebp, 0x80000 - SECTOR_SIZE
jge .Next
jmp .Cont
.Up:
cmp ah, UP_SCANCODE
jne .Input
; Not fit?
cmp ebp, 0x7C00
jbe .Next
.Cont:
call Main.GetLBA
cmp byte [FREE_SPACE + 1], 1
je .SkipWrite
call RWSector
.SkipWrite:
cmp ah, DOWN_SCANCODE
jne .Up2
; Down.
add ebp, SECTOR_SIZE
inc bx
jmp .ReadSector
.Up2:
sub ebp, SECTOR_SIZE
dec bx
.ReadSector:
dec di
call RWSector
mov byte [FREE_SPACE + 1], 1
.Next:
and si, 0x1FF
jmp EventLoop
.Input:
; Get another keystroke.
shl eax, 16
int 0x16
xchg ah, al
shr eax, 8
cmp al, 0x1B
je .Next
mov cx, 2
.GetHexLoop:
; Get '0' to '9'.
sub al, 48
; If larger, subtract 7 to get hex.
cmp al, 9
jbe .NextChar
; If larger than 0xF still, then perhaps lowercase.
sub al, 7
cmp al, 0xF
jbe .NextChar
; Get normal digit.
sub al, 32
.NextChar:
xchg al, ah
loop .GetHexLoop
.Display:
shl al, 4
shr ax, 4
mov [gs:bx], al
inc si
.WroteNext:
; Zero out FREE_SPACE + 1.
xor al, al
mov [FREE_SPACE + 1], al
jmp .Next
; Read/write a sector.
; BX -> logical block address.
; EBP -> where to read/write to/from.
; EDI -> 0x00 for read; 0x01 for write.
RWSector:
pushad
xchg ax, bx
xor si, si
call Main.GetSegment
mov cx, gs
mov es, cx
; Three tries.
mov si, 3
; Get CHS.
; CH -> cylinder number.
; CL -> sector number.
; DH -> head number.
xor dx, dx
mov cx, SECTORS_PER_TRACK
div cx
; Get sector.
mov cl, dl
inc cl
; Get head number.
mov dh, al
and dh, 0x1
; Get track number.
shr ax, 1
mov ch, al
mov dl, [FREE_SPACE]
shl di, 8
.Loop:
clc
; Prepare for interrupt.
mov ax, 0x0201
add ax, di
int 0x13
jnc .Return
xor ah, ah
int 0x13
dec si
jnz .Loop
; Get in the character.
mov al, '@'
jmp Main.Error
.Return:
popad
ret
; Converts a byte to a ASCII hexadecimal value.
; DL -> the byte to convert.
;
; Returns:
; AX -> the output.
HexToASCII:
movzx ax, dl
shl ax, 4
shr al, 4
mov dl, 2
.Loop:
cmp al, 9
jg .Char
add al, 48
jmp .Next
.Char:
add al, 55
.Next:
xchg ah, al
dec dl
jnz .Loop
ret
; Padding.
times 510 - ($ - $$) db 0
BIOSSignature:
dw 0xAA55
; Pad to floppy disk.
times (1440 * 1024) - ($ - $$) db 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment