cheat-engine/dbvm/vmloader/vmloader.asm
2018-02-20 13:08:24 +01:00

908 lines
13 KiB
NASM
Executable file

;Loaded by the bootloader
;This will load the highlevel vmm code at the highest memory
;location possible, and setup the system to protected and paged mode
BITS 16
GLOBAL amain
amain:
;should be 3000:0000
;load vmm code into memory
;
;
jmp real_entry
column:
db 0
row:
db 0
display16:
;cl=byte to send
push ax
push dx
mov dl, byte [ds:bp+column-begin]
mov dh, byte [ds:bp+row-begin]
mov ax,0xb800
mov es,ax
mov al,dh
mov ah,160
imul ah ; ax=ah*al (row*160)
;add the column
push dx
and dx,0x00ff ;remove the row part of the dx register
shl dx,1 ;multiply by 2
add ax, dx
pop dx
xchg si,ax
;mov si,0
mov byte [es:si], cl ;//dl ;cl
mov byte [es:si+1], 15
;mov byte [es:si+2], dh
;mov byte [es:si+3], 15
xchg si,ax
inc dl
cmp dl, 80
jae nextrow
jmp display16_done
nextrow:
mov dl,0 ;set column to 0
inc dh ;go to next row
cmp dh,25
jb display16_done
mov dh,0
display16_done:
mov byte [ds:bp+column-begin], dl
mov byte [ds:bp+row-begin], dh
pop dx
pop ax
ret
;some 16-bit general purpose functions
sendstring16:
;ds:si=pointer to string
mov cl,[si]
call send16
inc si
cmp byte [si],'$'
jne sendstring16
ret
send16:
;param cl=byte to send
push ax
push dx
waitforready:
%ifdef SERIALPORT
%if SERIALPORT != 0
mov dx,SERIALPORT+5 ;3fdh
in al,dx
and al,0x20
cmp al,0x20
jne waitforready
mov dx,SERIALPORT ;0x3f8
mov al,cl
out dx,al
%endif
%endif
pop dx
pop ax
ret
inttostr16:
;ax = value
;di = pointer to buffer
;si = start of string (output)
;cx = max length of buffer
push ax
push bx
push cx
push di
mov si,di
add si,cx
dec si
mov byte [si],'$'
dec si
;worker
inttostr16_worker:
cmp si,di
jb inttostr16_end ; end of stringspace
xor dx,dx
mov bx,10
div bx
add dl,030h
mov [si],dl
dec si
cmp ax,0
jne inttostr16_worker
mov cx,si
inc cx
inttostr16_fillspace:
cmp si,di
jb inttostr16_end
mov byte [si],0x20
dec si
jmp inttostr16_fillspace
inttostr16_end:
mov si,cx
pop di
pop cx
pop bx
pop ax
ret
inttohex16:
;ax = value
;di = pointer to buffer
;si = start of string (output)
;cx = max length of buffer
push ax
push bx
push cx
push di
mov si,di
add si,cx
dec si
mov byte [si],'$' ;make this 0
dec si
;worker
inttohex16_worker:
cmp si,di
jb inttohex16_end ; end of stringspace
xor dx,dx
mov bx,16
div bx
cmp dl,09h
ja alpha
add dl,'0' ; add from '0'
jmp writehex
alpha:
sub dl,0ah
add dl,'a' ; add from 'a'
writehex:
mov [si],dl
dec si
cmp ax,0
jne inttohex16_worker
mov cx,si
inc cx
inttohex16_fillspace:
cmp si,di
jb inttohex16_end
mov byte [si],0x20
dec si
jmp inttohex16_fillspace
inttohex16_end:
mov si,cx
pop di
pop cx
pop bx
pop ax
ret
generatestring16:
str88: db '88=$'
stre801: db 'e801:$'
stre820: db 'e820:',13,10,'$'
strax: db 'ax=$'
strbx: db 'bx=$'
strcx: db 'cx=$'
strdx: db 'dx=$'
strsmaperror: db 'SMAP ERROR!',13,10,'$'
tempbuf: db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
newline: db 13,10,'$'
GLOBAL reservedmem_listcount
reservedmem_listcount: dd 0
GLOBAL readerror
readerror: dd 0
global sectorsread
sectorsread: dd 0
global a20state
a20state: dd 0
global bootdisk
bootdisk: dd 0
global SectorsPerTrack
SectorsPerTrack: dd 0
global NumberOfHeads
NumberOfHeads: dd 0
global NumberOfCylinders
NumberOfCylinders: dd 0
vesa_info_success:
db "get VESA info success",13,10,"$"
vesa_info_fail:
db "get VESA info failed",13,10,"$"
str_failed_getting_data:
db " Failure"
str_videomode:
db "videomode 0x$"
checka20:
push ds
push es
xor ax,ax
mov ds,ax
dec ax
mov es,ax
mov ax,[es:10h] ; read word at FFFF:0010 (1 meg)
not ax ; 1's complement
push word [0] ; save word at 0000:0000 (0)
mov [0],ax ; word at 0 = ~(word at 1 meg)
mov ax,[0] ; read it back
cmp ax,[es:10h] ; fail if word at 0 == word at 1 meg
pop word [0]
pop es
pop ds
je checka20_noa20 ;it's the same
mov ax,1
ret
checka20_noa20:
mov ax,0
ret
;^^^^^^^^^^^^^^^^^^^^^
retry: db 'retry reading disk',13
waitforkeypress:
%ifdef SERIALPORT
%if SERIALPORT != 0
mov dx,SERIALPORT+5 ;0x3fd
waitforkeypress2:
in al,dx
and al,1
cmp al,1
jne waitforkeypress2
mov dx,SERIALPORT ;0x3f8
in al,dx
%endif
%endif
ret
real_entry:
;ok
;setup rs232 (serial port communications)
;ok
;-----------------------Real Entry point--------------------
mov ax,0x8000
cli
mov ss,ax
mov sp,0xfff0
sti
xor ebp,ebp
xor esi,esi
mov ax,cs
mov ds,ax
mov es,ax
start:
call begin
begin:
pop bp ; bp now contains the address of begin
;ok
lea di,[ds:bp+reservedmem_listcount-begin]
cmp byte [ds:di],0
jne gdtsetup
mov [ds:bp+bootdisk-begin],dl ;save bootdisk
cmp byte [bp+reservedmem_listcount-begin],0
jne gdtsetup ;skip setting up hardware and enumerating memory, it's already done
%ifdef SERIALPORT
%if SERIALPORT !=0
;jmp serialsetupdone
mov dx,SERIALPORT+1 ;3f9h
mov al,0h
out dx,al
mov dx,SERIALPORT+3; 3fbh
mov al,80h
out dx ,al ;access baud rate generator
mov dx,SERIALPORT; 3f8h
mov al,1h ;0c=9600 (1152000/divisor)
out dx,al ;9600 baud
mov dx,SERIALPORT+1; 3f9h
mov al,0h ;high part of devisor
out dx,al ;
mov dx,SERIALPORT+3; 3fbh
mov al,3h
out dx,al ;8 bits, no parity, one stop
%endif
%endif
serialsetupdone:
;begin with setting up diskinfo
mov ax,0x6000
mov es,ax
xor di,di
mov ax,0x0800
mov dl,[ds:bp+bootdisk-begin]
int 13h
inc dh
mov [ds:bp+NumberOfHeads-begin],dh
mov ax,cx
and ax,3fh
inc ax
mov [ds:bp+SectorsPerTrack-begin],ax
mov al,ch
shr ch,6
mov ah,ch
mov [ds:bp+NumberOfCylinders-begin],ax
;enumerate the memory regions that can not be used by dbvm
;int 15h
;init buffer
mov ax,08000h
mov es,ax
mov di,0
mov ebx,0
enummem:
;mov byte [es:0xdead],2
;enumerate the memory regions available to the operating system and save them
xor eax,eax
mov eax,0e820h
mov ecx,20
mov edx,0534D4150h
clc
int 15h
jc endofenummem
cmp eax,0534D4150h
jne endofenummem
cmp ecx,20
jne endofenummem
push di
lea di,[ds:bp+reservedmem_listcount-begin]
inc dword [ds:di]
pop di
add di,20
cmp ebx,0
jne enummem ;still more to go
endofenummem:
lea di,[ds:bp+reservedmem_listcount-begin]
mov ax,word [di]
lea di,[ds:bp+tempbuf-begin]
mov cx,16
call inttohex16
lea si,[ds:bp+strnormal-begin]
call sendstring16
mov cl,';'
call send16
;call waitforkeypress
gdtsetup:
;enable a20
in al,92h
test al,02h
jne hasa20
or al,02h
out 92h,al
noa20:
hasa20:
call checka20
lea di,[bp+a20state-begin]
mov [di],ax
;------------------GDT setup
mov ax,0x4000
mov es,ax
mov word [es:0],0x6f
mov dword [es:2],0x50000
; 0x3000:0x02b3
mov ax,0x5000
mov es,ax
mov dword [es:0],0
mov dword [es:4],0
mov dword [es:8],0x0000ffff ;32-bit data
mov dword [es:12],0x00cf9200
mov dword [es:16],0x0000ffff ;stack (unused)
mov dword [es:20],0x00cf9600
;lea ax,[bp+entry32-begin]
;shl eax,16
;add eax,0xffff
mov dword [es:24],0x0000ffff ;32-bit code
mov dword [es:28],0x00cf9b00 ;limit=ffff*4KB base=0
mov dword [es:32],0x0000ffff ;16-bit code
mov dword [es:36],0x00009a00
mov dword [es:40],0x0000ffff ;16-bit data
mov dword [es:44],0x00009200
mov dword [es:48],0x0000ffff ;16-bit code, base 0x30000
mov dword [es:52],0x00009a03
mov dword [es:56],0 ;32-bit task , main vmm task
mov dword [es:60],0
mov dword [es:64],0 ;64-bit task , main vmm64 task
mov dword [es:68],0
mov dword [es:72],0 ;
mov dword [es:76],0
;64-bit code segment
mov dword [es:80], 0x0000ffff ;64-bit code (there is no limit checking)
mov dword [es:84], 0x00AF9B00
mov dword [es:88],0
mov dword [es:92],0
;64bit tss descriptor (initialized later)
mov dword [es:96], 0
mov dword [es:100],0
mov dword [es:104],0
mov dword [es:108],0
;64-bit data segment
;there is none...
mov ax,0x4000
mov fs,ax
db 0x66
LGDT [fs:0]
mov ax,0xffff
mov ds,ax
;setup to protected mode
cli ;no more ints for now
mov ebx,cr0
or ebx,1
mov cr0,ebx
jmp short shortjump
shortjump:
nop
nop
mov bx,cs
bits 32
db 0x66
jmp 24:entry32
;----------------------------------------------------------;
; PROTECTED MODE :32 bit section ;
;----------------------------------------------------------;
bits 32
jmp short entry32
extern _vmloader_main
strnormal:
db 'normal boot',13,10,'$'
strcalledlgdt:
db 'Called LGDT (not)',13,10,'$'
sendstring32:
;esi=pointer to zstring
mov cl,[esi]
call sendchar32
inc esi
cmp byte [esi],0
jne sendstring32
ret
sendchar32:
%ifdef SERIALPORT
%if SERIALPORT != 0
mov edx,SERIALPORT+5 ;3fdh
in al,dx
and al,0x20
cmp al,0x20
jne sendchar32
mov edx,SERIALPORT; 0x3f8
mov al,cl
out dx,al
%endif
%endif
ret
entry32:
shl ebx,16
mov bx,ds
mov cx,es
shl ecx,16
mov cx,fs
;set segments to valid entries (ss is kinda important)
mov ax,8
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
;mov esp,0x003ffffc ;4mb , the user should have that at least, else i will crash anyhow
mov esp,0x0002fffc
;mov [readerror],ebx
;mov [sectorsread],ecx
;zero the stack
xor eax,eax
mov edi,esp
and edi,0xffff0000
mov ecx,0xffff
rep stosb
;0018:0303de
call _vmloader_main ; 0x30452
mov al,1
lp:
mov byte [0x0b8000],'l'
mov byte [0x0b8001],al
inc al
mov byte [0x0b8002],'o'
mov byte [0x0b8003],al
inc al
mov byte [0x0b8004],'s'
mov byte [0x0b8005],al
inc al
mov byte [0x0b8006],'e'
mov byte [0x0b8007],al
inc al
mov byte [0x0b8008],'r'
mov byte [0x0b8009],al
inc al
jmp lp
strInsideVMM: db 'Inside gotoVMM',13,10,0
strSetGDT: db 'Have set the GDT',13,10,0
global PageMapLevel4
PageMapLevel4: dd 0
global vmmPA
vmmPA: dd 0
global GDTVA
GDTVA: dd 0
global gotoVMM
gotoVMM:
;the new gdt address is at VMMSIZE+1*4096 & 0xfff
;the pagetablebase (cr3) should be at VMMSIZE+2*4096 & 0xfffff000
mov ebx,[vmmPA]
mov esi,strInsideVMM
call sendstring32
mov eax,[PageMapLevel4]
mov cr3,eax
;set the gdt
mov word [0x40000],0x6f
mov eax,[GDTVA]
mov dword [0x40002],eax ;was 0x00400000+VMMSIZE+1*4096 & 0xfffff000
lgdt [0x40000]
mov esi,strSetGDT
call sendstring32
mov dl,[bootdisk] ;so the vmm knows the bootdisk, for whatever reason it migth need it
;mov eax,cr4
;or eax,0x30 ; enable PAE and PSE (to enable 2MB pages)
;mov cr4,eax
mov eax,0x30
mov cr4,eax
;set IA32_EFER_LME to 1 (enable 64 bits)
mov ecx,0xc0000080
rdmsr
or eax,0x100
wrmsr
mov eax,cr0
or eax,0x80000020 ;set the pg bit (and ne bit)
mov cr0,eax
xor eax,eax ;tell the vmm that it's loaded from a clean setup
jmp 80:0x00400000 ; go to 64-bit
global halt
;----------------------------;
;int halt(void);
;----------------------------;
halt:
hlt
jmp halt
global readsectorasm
;----------------------------;
;int readsectorasm(void);
;----------------------------;
;7000:0000 contains the data to read, 7000:8000 the data needed to return
;6000:0000 points to the data to fill in
;This routine will switch to realmode , execute int13, and then switch back to realmode
readsectorasm:
;save state
mov dword [0x00078000],eax
mov dword [0x00078004],ebx
mov dword [0x00078008],ecx
mov dword [0x0007800c],edx
mov dword [0x00078010],esi
mov dword [0x00078014],edi
mov dword [0x00078018],ebp
mov dword [0x0007801c],esp
mov eax,readsector16protected
and eax,0xffff
mov dword [0x00078020],eax
mov dword [0x00078024],48 ;16-bit code segment starting at 0x30000
nop
nop
nop
jmp far dword [0x00078020]
readsector16protected:
;in 16bit protected mode now
bits 16
mov ax,40 ;set segment registers to 16-bit
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
;switch to real
xor eax,eax
mov cr0,eax
mov ax,0x6000
mov ds,ax
mov eax,readsector16
mov word [0],ax
mov word [2],0x3000
jmp far word [0] ;refresh cs to point to proper base
readsector16:
;realmode here
mov ax,0x7000
mov ds,ax
mov ax,0x6000 ;target to write to (512 bytes)
mov es,ax
mov ss,ax
mov sp,0xfffe ;end of that segment
sti
;call int13
mov ax,0x0201 ;read 1 sector
xor bx,bx ;write to 0x0 ;(so ds:bx=7000:0000)
;mov word [0xdead],0xdead ;;debug for bochs (watch write 0x7dead)
mov cl,[0] ;sector
mov dh,[1] ;head
mov ch,[2] ;cylinder
mov dl,[3] ;drive
int 0x13
jc readsector_error
mov eax,1
jmp readsector_afterread
readsector_error:
xor eax,eax
readsector_afterread:
mov bx,0x7000
mov ds,bx
mov dword [0x8000],eax ;set new eax value
;go back to the protected mode caller
cli ;no more ints for now
mov ebx,cr0
or ebx,1
mov cr0,ebx
jmp short readsector_sj
readsector_sj:
nop
nop
bits 32
db 0x66
jmp 24:readsector_return
readsector_return:
mov ax,8
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,dword [0x00078000]
mov ebx,dword [0x00078004]
mov ecx,dword [0x00078008]
mov edx,dword [0x0007800c]
mov esi,dword [0x00078010]
mov edi,dword [0x00078014]
mov ebp,dword [0x00078018]
mov esp,dword [0x0007801c]
ret