14,9 → 14,7 |
|
struct V86_machine |
; page directory |
pagedir dd ? |
; translation table: V86 address -> flat linear address |
pages dd ? |
process dd ? |
; mutex to protect all data from writing by multiple threads at one time |
mutex dd ? |
; i/o permission map |
38,91 → 36,87 |
and dword [eax+V86_machine.mutex], 0 |
; allocate tables |
mov ebx, eax |
; We allocate 4 pages. |
; First is main page directory for V86 mode. |
; Second page: |
; first half (0x800 bytes) is page table for addresses 0 - 0x100000, |
; second half is for V86-to-linear translation. |
; Third and fourth are for I/O permission map. |
push 8000h ; blocks less than 8 pages are discontinuous |
|
stdcall create_process, 4096, OS_BASE, 4096 |
test eax, eax |
jz .fail2 |
|
mov [eax+PROC.mem_used], 4096 |
mov [ebx+V86_machine.process], eax |
|
push 2000h |
call kernel_alloc |
test eax, eax |
jz .fail2 |
mov [ebx+V86_machine.pagedir], eax |
push edi eax |
|
mov [ebx+V86_machine.iopm], eax |
|
|
; initialize tables |
push edi |
mov edi, eax |
add eax, 1800h |
mov [ebx+V86_machine.pages], eax |
; initialize tables |
mov eax, -1 |
mov ecx, 2000h/4 |
xor eax, eax |
rep stosd |
mov [ebx+V86_machine.iopm], edi |
dec eax |
mov ecx, 2000h/4 |
rep stosd |
pop eax |
; page directory: first entry is page table... |
mov edi, eax |
add eax, 1000h |
push eax |
call get_pg_addr |
or al, PG_UW |
stosd |
; ...and also copy system page tables |
; thx to Serge, system is located at high addresses |
add edi, (OS_BASE shr 20) - 4 |
push esi |
mov esi, (OS_BASE shr 20) + sys_pgdir |
mov ecx, 0x80000000 shr 22 |
rep movsd |
|
mov eax, [ebx+V86_machine.pagedir] ;root dir also is |
call get_pg_addr ;used as page table |
or al, PG_SW |
mov [edi-4096+(page_tabs shr 20)], eax |
mov eax, [ebx+V86_machine.process] |
mov eax, [eax+PROC.pdt_0_phys] |
|
pop esi |
pushfd |
cli |
mov cr3, eax |
|
|
; now V86 specific: initialize known addresses in first Mb |
pop eax |
|
; first page - BIOS data (shared between all machines!) |
; physical address = 0 |
; linear address = OS_BASE |
mov dword [eax], 111b |
mov dword [eax+800h], OS_BASE |
; page before 0xA0000 - Extended BIOS Data Area (shared between all machines!) |
; physical address = 0x9C000 |
; linear address = 0x8009C000 |
; (I have seen one computer with EBDA segment = 0x9D80, |
; all other computers use less memory) |
mov ecx, 4 |
mov edx, 0x9C000 |
push eax |
lea edi, [eax+0x9C*4] |
|
mov eax, PG_UW |
mov [page_tabs], eax |
invlpg [eax] |
|
mov byte [0x500], 0xCD |
mov byte [0x501], 0x13 |
mov byte [0x502], 0xF4 |
mov byte [0x503], 0xCD |
mov byte [0x504], 0x10 |
mov byte [0x505], 0xF4 |
|
mov eax, 0x99000+PG_UW |
mov edi, page_tabs+0x99*4 |
mov edx, 0x1000 |
mov ecx, 7 |
@@: |
lea eax, [edx + OS_BASE] |
mov [edi+800h], eax |
lea eax, [edx + 111b] |
stosd |
add edx, 0x1000 |
add eax, edx |
loop @b |
pop eax |
pop edi |
|
; addresses 0xC0000 - 0xFFFFF - BIOS code (shared between all machines!) |
; physical address = 0xC0000 |
; linear address = 0x800C0000 |
mov ecx, 0xC0 |
|
mov eax, 0xC0000+PG_UW |
mov edi, page_tabs+0xC0*4 |
mov ecx, 64 |
@@: |
mov edx, ecx |
shl edx, 12 |
push edx |
or edx, 111b |
mov [eax+ecx*4], edx |
pop edx |
add edx, OS_BASE |
mov [eax+ecx*4+0x800], edx |
inc cl |
jnz @b |
stosd |
add eax, edx |
loop @b |
|
mov eax, sys_proc |
push ebx |
call set_cr3 |
pop ebx |
popfd |
|
pop edi |
|
mov eax, ebx |
ret |
.fail2: |
132,15 → 126,16 |
xor eax, eax |
ret |
|
;not used |
; Destroy V86 machine |
; in: eax = handle |
; out: nothing |
; destroys: eax, ebx, ecx, edx (due to free) |
v86_destroy: |
push eax |
stdcall kernel_free, [eax+V86_machine.pagedir] |
pop eax |
jmp free |
;v86_destroy: |
; push eax |
; stdcall kernel_free, [eax+V86_machine.pagedir] |
; pop eax |
; jmp free |
|
; Translate V86-address to linear address |
; in: eax=V86 address |
150,13 → 145,15 |
v86_get_lin_addr: |
push ecx edx |
mov ecx, eax |
mov edx, [esi+V86_machine.pages] |
shr ecx, 12 |
mov edx, [page_tabs+ecx*4] |
and eax, 0xFFF |
add eax, [edx+ecx*4] ; atomic operation, no mutex needed |
and edx, 0xFFFFF000 |
or eax, edx |
pop edx ecx |
ret |
|
;not used |
; Sets linear address for V86-page |
; in: eax=linear address (must be page-aligned) |
; ecx=V86 page (NOT address!) |
163,15 → 160,15 |
; esi=handle |
; out: nothing |
; destroys: nothing |
v86_set_page: |
push eax ebx |
mov ebx, [esi+V86_machine.pagedir] |
mov [ebx+ecx*4+0x1800], eax |
call get_pg_addr |
or al, 111b |
mov [ebx+ecx*4+0x1000], eax |
pop ebx eax |
ret |
;v86_set_page: |
; push eax ebx |
; mov ebx, [esi+V86_machine.pagedir] |
; mov [ebx+ecx*4+0x1800], eax |
; call get_pg_addr |
; or al, 111b |
; mov [ebx+ecx*4+0x1000], eax |
; pop ebx eax |
; ret |
|
; Allocate memory in V86 machine |
; in: eax=size (in bytes) |
214,21 → 211,7 |
mov [sys_v86_machine], eax |
test eax, eax |
jz .ret |
mov byte [OS_BASE + 0x500], 0xCD |
mov byte [OS_BASE + 0x501], 0x13 |
mov byte [OS_BASE + 0x502], 0xF4 |
mov byte [OS_BASE + 0x503], 0xCD |
mov byte [OS_BASE + 0x504], 0x10 |
mov byte [OS_BASE + 0x505], 0xF4 |
mov esi, eax |
mov ebx, [eax+V86_machine.pagedir] |
; one page for stack, two pages for results (0x2000 bytes = 16 sectors) |
mov dword [ebx+0x99*4+0x1000], 0x99000 or 111b |
mov dword [ebx+0x99*4+0x1800], OS_BASE + 0x99000 |
mov dword [ebx+0x9A*4+0x1000], 0x9A000 or 111b |
mov dword [ebx+0x9A*4+0x1800], OS_BASE + 0x9A000 |
mov dword [ebx+0x9B*4+0x1000], 0x9B000 or 111b |
mov dword [ebx+0x9B*4+0x1800], OS_BASE + 0x9B000 |
if ~DEBUG_SHOW_IO |
; allow access to all ports |
mov ecx, [esi+V86_machine.iopm] |
272,37 → 255,39 |
; eax = 3 - IRQ is already hooked by another VM |
; destroys: nothing |
v86_start: |
|
pushad |
|
cli |
|
mov ecx, [CURRENT_TASK] |
shl ecx, 8 |
add ecx, SLOT_BASE |
mov ecx, [current_slot] |
|
push dword [ecx+APPDATA.io_map] |
push dword [ecx+APPDATA.io_map+4] |
push [ecx+APPDATA.process] |
push [ecx+APPDATA.saved_esp0] |
mov [ecx+APPDATA.saved_esp0], esp |
mov [tss._esp0], esp |
|
mov eax, [esi+V86_machine.iopm] |
call get_pg_addr |
inc eax |
push dword [ecx+APPDATA.io_map] |
push dword [ecx+APPDATA.io_map+4] |
mov dword [ecx+APPDATA.io_map], eax |
mov dword [page_tabs + (tss._io_map_0 shr 10)], eax |
|
mov eax, [esi+V86_machine.iopm] |
add eax, 0x1000 |
call get_pg_addr |
inc eax |
mov dword [ecx+APPDATA.io_map+4], eax |
mov dword [page_tabs + (tss._io_map_1 shr 10)], eax |
|
push [ecx+APPDATA.dir_table] |
push [ecx+APPDATA.saved_esp0] |
mov [ecx+APPDATA.saved_esp0], esp |
mov [tss._esp0], esp |
|
mov eax, [esi+V86_machine.pagedir] |
call get_pg_addr |
mov [ecx+APPDATA.dir_table], eax |
mov eax, [esi+V86_machine.process] |
mov [ecx+APPDATA.process], eax |
mov [current_process], eax |
mov eax, [eax+PROC.pdt_0_phys] |
mov cr3, eax |
|
; mov [irq_tab+5*4], my05 |
|
; We do not enable interrupts, because V86 IRQ redirector assumes that |
; machine is running |
; They will be enabled by IRET. |
782,19 → 767,21 |
mov esp, esi |
|
cli |
mov ecx, [CURRENT_TASK] |
shl ecx, 8 |
mov ecx, [current_slot] |
pop eax |
mov [SLOT_BASE+ecx+APPDATA.saved_esp0], eax |
|
mov [ecx+APPDATA.saved_esp0], eax |
mov [tss._esp0], eax |
pop eax |
mov [SLOT_BASE+ecx+APPDATA.dir_table], eax |
mov [ecx+APPDATA.process], eax |
mov [current_process], eax |
pop ebx |
mov dword [SLOT_BASE+ecx+APPDATA.io_map+4], ebx |
mov dword [ecx+APPDATA.io_map+4], ebx |
mov dword [page_tabs + (tss._io_map_1 shr 10)], ebx |
pop ebx |
mov dword [SLOT_BASE+ecx+APPDATA.io_map], ebx |
mov dword [ecx+APPDATA.io_map], ebx |
mov dword [page_tabs + (tss._io_map_0 shr 10)], ebx |
mov eax, [eax+PROC.pdt_0_phys] |
mov cr3, eax |
sti |
|
843,11 → 830,10 |
pop eax |
v86_irq2: |
mov esi, [v86_irqhooks+edi*8] ; get VM handle |
mov eax, [esi+V86_machine.pagedir] |
call get_pg_addr |
mov eax, [esi+V86_machine.process] |
mov ecx, [CURRENT_TASK] |
shl ecx, 8 |
cmp [SLOT_BASE+ecx+APPDATA.dir_table], eax |
cmp [SLOT_BASE+ecx+APPDATA.process], eax |
jnz .notcurrent |
lea eax, [edi+8] |
cmp al, 10h |
860,7 → 846,7 |
mov ebx, SLOT_BASE + 0x100 |
mov ecx, [TASK_COUNT] |
.scan: |
cmp [ebx+APPDATA.dir_table], eax |
cmp [ebx+APPDATA.process], eax |
jnz .cont |
push ecx |
mov ecx, [ebx+APPDATA.saved_esp0] |
895,6 → 881,7 |
popad |
iretd |
.found: |
mov eax, [eax+PROC.pdt_0_phys] |
mov cr3, eax |
mov esi, [ebx+APPDATA.saved_esp0] |
sub word [esi-sizeof.v86_regs+v86_regs.esp], 6 |