|
.8086 |
|
.model tiny |
|
|
|
inp macro port |
|
mov dx, port |
|
in al, dx |
|
tick3 |
|
endm |
|
|
|
inpw macro port |
|
mov dx, port |
|
in ax, dx |
|
tick3 |
|
endm |
|
|
|
movedataw macro src, dest, size |
|
setds src ; DS = source |
|
setes dest ; ES = dest |
|
|
|
mov cx, size ; CX = size in words |
|
|
|
rep movsw ; copy! |
|
endm |
|
|
|
outp macro port, data |
|
mov al, data |
|
mov dx, port |
|
out dx, al |
|
tick3 |
|
endm |
|
|
|
outpw macro port, data |
|
mov ax, data |
|
mov dx, port |
|
out dx, ax |
|
tick3 |
|
endm |
|
|
|
setborder macro color |
|
inp 0x3DA ; clear VGA attribute flip-flop |
|
outp 0x3C0, 0x11 ; select VGA register 0x11 (overscan color) |
|
outp 0x3C0, color ; set color |
|
endm |
|
|
|
setds macro seg |
|
mov ax, seg ; |
|
mov ds, ax ; set DS to provided segment |
|
|
|
xor si, si ; set DS:SI = seg:0000 |
|
endm |
|
|
|
setes macro seg |
|
mov ax, seg ; |
|
mov es, ax ; set ES to provided segment |
|
|
|
xor di, di ; set ES:DI = seg:0000 |
|
endm |
|
|
|
tick macro |
|
db 0xeb, 0x00 ; jmp to the next instruction, as a delay |
|
endm |
|
|
|
tick3 macro |
|
tick |
|
tick |
|
tick |
|
endm |
|
|
|
wd76_lock macro |
|
outp 0xf073, 0x00 ; lock registers |
|
endm |
|
|
|
wd76_unlock macro |
|
outp 0xf073, 0xda ; unlock registers |
|
endm |
|
|
|
.code |
|
|
|
; |
|
; setsize - sets the memory size register to whatever is passed in ax |
|
; |
|
public setsize_ |
|
setsize_ proc near |
|
mov bx, ax ; we need to stash this for a moment |
|
|
|
setborder 0x04 ; red |
|
|
|
setds cs |
|
|
|
lea si, [setsize_vram] ; the start of the data to copy |
|
|
|
setes 0xB800 |
|
|
|
xor di, di ; set VRAM offset |
|
|
|
mov ax, end_setsize_code ; |
|
sub ax, setsize_vram ; set ax to number of bytes to copy |
|
|
|
shr ax, 1 ; |
|
mov cx, ax ; setup copy |
|
|
|
rep movsw ; perform copy |
|
|
|
setborder 0x05 ; magenta |
|
|
|
setds 0xB800 |
|
|
|
mov ax, bx ; put the parameter in ax |
|
|
|
jmp 0xB800, 0x0500 ; jump to VRAM, offset by our buffers |
|
|
|
hlt ; you shouldn't get here |
|
|
|
setsize_vram: |
|
db 0x0400 dup (0x00) ; space for the entire IVT, 1024 bytes |
|
db 0x0100 dup (0x00) ; space for the entire BDA, 256 bytes |
|
|
|
setsize_code_start: |
|
mov bx, ax ; ax and cx are used later |
|
|
|
setborder 0x01 ; blue |
|
|
|
cli ; clear interrupts |
|
|
|
setborder 0x38 ; lavender |
|
|
|
; |
|
; backup IVT and BDA |
|
; |
|
|
|
movedataw 0x0000, 0xB800, 0x0200 ; backup the IVT (0x200 words = 1024 bytes) |
|
movedataw 0x0040, 0xB840, 0x0080 ; backup the BDA (0x80 words = 256 bytes) |
|
|
|
setds 0xB800 ; put DS back to this segment |
|
|
|
; |
|
; set our new memory size, which jumbles all RAM |
|
; except VRAM |
|
; |
|
|
|
wd76_unlock |
|
|
|
setborder 0x02 ; green |
|
|
|
mov ax, bx ; put the new size back |
|
outpw 0x3872, ax ; write the new memory size |
|
|
|
setborder 0x07 ; white |
|
|
|
; |
|
; restore IVT and BDA |
|
; |
|
|
|
movedataw 0xB800, 0x0000, 0x0200 ; restore the IVT |
|
movedataw 0xB840, 0x0040, 0x0080 ; restore the BDA |
|
|
|
setds 0xB800 ; put DS back to this segment |
|
|
|
setborder 0x03 ; cyan |
|
|
|
; |
|
; disable BIOS shadowing and write protect |
|
; |
|
|
|
inpw 0x6072 ; get current value of RAM shadow & WP register |
|
mov cx, ax ; store original register in cx |
|
and ax, 0xECFF ; mask out the shadow write protect and disable shadowing |
|
mov bx, ax ; move to bx so I don't have to write another macro |
|
outpw 0x6072, bx ; disable RAM shadow write protect + shadowing |
|
mov bx, cx ; store original register in bx so we don't overwrite it |
|
|
|
setborder 0x09 ; bright blue |
|
|
|
wd76_lock |
|
|
|
; |
|
; backup the unshadowed BIOS |
|
; |
|
|
|
movedataw 0xe000, 0x4000, 0x8000 ; backup VGA BIOS to 0x4000 |
|
movedataw 0xf000, 0x5000, 0x8000 ; backup BIOS to 0x5000 |
|
|
|
setds 0xB800 ; put DS back to this segment |
|
|
|
; |
|
; re-enable BIOS shadowing but keep write protect disabled |
|
; |
|
|
|
wd76_unlock |
|
|
|
and bx, 0xEFFF ; |
|
outpw 0x6072, bx ; mask out write protect but turn shadowing on |
|
|
|
wd76_lock |
|
|
|
; |
|
; re-shadow the BIOS |
|
; |
|
|
|
movedataw 0x4000, 0xe000, 0x8000 ; restore VGA BIOS from 0x4000 |
|
movedataw 0x5000, 0xf000, 0x8000 ; restore BIOS from 0x5000 |
|
|
|
setds 0xB800 ; set DS once again back to this segment |
|
|
|
; |
|
; re-enable BIOS shadow write protect |
|
; |
|
|
|
setborder 0x0A ; bright green |
|
|
|
wd76_unlock |
|
|
|
inpw 0x6072 ; get current value of RAM shadow & WP register |
|
|
|
or ax, 0x1000 ; |
|
mov bx, ax ; |
|
outpw 0x6072, bx ; turn write protect back on |
|
|
|
wd76_lock |
|
|
|
; |
|
; set warm boot flag |
|
; |
|
|
|
setborder 0x0B ; bright cyan |
|
|
|
setes 0x40 ; set ES to BIOS data area |
|
|
|
mov ax, 0x72 ; |
|
mov di, ax ; set DI to warm boot flag field of BDA |
|
|
|
mov word ptr es:[di], 0x1234 ; set warm boot flag |
|
|
|
; |
|
; reset via 8042 |
|
; https://wiki.osdev.org/Reboot |
|
; |
|
|
|
setborder 0x0D ; bright magenta |
|
|
|
empty_kbd_buffer: |
|
inp 0x64 ; read 8042 status |
|
mov bl, al ; we write al with outp |
|
|
|
test bl, 0x01 ; check for keyboard data |
|
jz short check_kbd_user_data ; no keyboard data |
|
|
|
inp 0x60 ; there was keyboard data, read port |
|
|
|
check_kbd_user_data: |
|
test bl, 0x02 ; check for user data |
|
jz short reset ; no more user data, reset this fucker |
|
|
|
jmp short empty_kbd_buffer ; another loop |
|
|
|
reset: |
|
setborder 0x0F ; bright white |
|
|
|
outp 0x64, 0xFE |
|
|
|
end_setsize_code: |
|
hlt ; you shouldn't get here |
|
|
|
setsize_ endp |
|
|
|
end |
Seems like reshadowing the BIOS is required but backing up and restoring the IVT and BDA are not