Basic VM and other minor improvements.
Not complete, probably not fully debugged or optimized.
This commit is contained in:
@@ -8,17 +8,19 @@ ARCHAR=$(ARCH).a
|
||||
# the HEAD variable is passed as an argument to this Makefile
|
||||
# by an upper level Makefile.
|
||||
|
||||
OBJS=$(ARCHAR)(exception.o) \
|
||||
$(ARCHAR)(i8259.o) \
|
||||
$(ARCHAR)(memory.o) \
|
||||
$(ARCHAR)(protect.o) \
|
||||
$(ARCHAR)(system.o) \
|
||||
$(ARCHAR)(clock.o) \
|
||||
$(ARCHAR)(klib386.o) \
|
||||
$(ARCHAR)(do_readbios.o) \
|
||||
$(ARCHAR)(do_int86.o) \
|
||||
$(ARCHAR)(do_sdevio.o) \
|
||||
$(ARCHAR)(do_iopenable.o)
|
||||
OBJS= arch_do_vmctl.o \
|
||||
clock.o \
|
||||
do_int86.o \
|
||||
do_iopenable.o \
|
||||
do_readbios.o \
|
||||
do_sdevio.o \
|
||||
exception.o \
|
||||
i8259.o \
|
||||
klib386.o \
|
||||
memory.o \
|
||||
mpx386.o \
|
||||
protect.o \
|
||||
system.o
|
||||
|
||||
CPPFLAGS=-Iinclude
|
||||
CFLAGS=$(CPPFLAGS) -Wall
|
||||
@@ -56,6 +58,9 @@ $(ARCHAR)(do_int86.o): do_int86.c
|
||||
$(ARCHAR)(do_iopenable.o): do_iopenable.c
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
$(ARCHAR)(arch_do_vmctl.o): arch_do_vmctl.c
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
$(ARCHAR)(do_readbios.o): do_readbios.c
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
|
||||
56
kernel/arch/i386/arch_do_vmctl.c
Normal file
56
kernel/arch/i386/arch_do_vmctl.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* The kernel call implemented in this file:
|
||||
* m_type: SYS_VMCTL
|
||||
*
|
||||
* The parameters for this kernel call are:
|
||||
* SVMCTL_WHO which process
|
||||
* SVMCTL_PARAM set this setting (VMCTL_*)
|
||||
* SVMCTL_VALUE to this value
|
||||
*/
|
||||
|
||||
#include "../../system.h"
|
||||
#include <minix/type.h>
|
||||
|
||||
extern u32_t kernel_cr3;
|
||||
|
||||
/*===========================================================================*
|
||||
* arch_do_vmctl *
|
||||
*===========================================================================*/
|
||||
PUBLIC int arch_do_vmctl(m_ptr, p)
|
||||
register message *m_ptr; /* pointer to request message */
|
||||
struct proc *p;
|
||||
{
|
||||
switch(m_ptr->SVMCTL_PARAM) {
|
||||
case VMCTL_I386_GETCR3:
|
||||
/* Get process CR3. */
|
||||
m_ptr->SVMCTL_VALUE = p->p_seg.p_cr3;
|
||||
return OK;
|
||||
case VMCTL_I386_SETCR3:
|
||||
/* Set process CR3. */
|
||||
if(m_ptr->SVMCTL_VALUE) {
|
||||
p->p_seg.p_cr3 = m_ptr->SVMCTL_VALUE;
|
||||
p->p_misc_flags |= MF_FULLVM;
|
||||
} else {
|
||||
p->p_seg.p_cr3 = kernel_cr3;
|
||||
p->p_misc_flags &= ~MF_FULLVM;
|
||||
}
|
||||
RTS_LOCK_UNSET(p, VMINHIBIT);
|
||||
return OK;
|
||||
case VMCTL_GET_PAGEFAULT:
|
||||
{
|
||||
struct proc *rp;
|
||||
if(!(rp=pagefaults))
|
||||
return ESRCH;
|
||||
pagefaults = rp->p_nextpagefault;
|
||||
if(!RTS_ISSET(rp, PAGEFAULT))
|
||||
minix_panic("non-PAGEFAULT process on pagefault chain",
|
||||
rp->p_endpoint);
|
||||
m_ptr->SVMCTL_PF_WHO = rp->p_endpoint;
|
||||
m_ptr->SVMCTL_PF_I386_CR2 = rp->p_pagefault.pf_virtual;
|
||||
m_ptr->SVMCTL_PF_I386_ERR = rp->p_pagefault.pf_flags;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
kprintf("arch_do_vmctl: strange param %d\n", m_ptr->SVMCTL_PARAM);
|
||||
return EINVAL;
|
||||
}
|
||||
@@ -21,28 +21,23 @@ struct reg86u reg86;
|
||||
PUBLIC int do_int86(m_ptr)
|
||||
register message *m_ptr; /* pointer to request message */
|
||||
{
|
||||
vir_bytes caller_vir;
|
||||
phys_bytes caller_phys, kernel_phys;
|
||||
|
||||
caller_vir = (vir_bytes) m_ptr->INT86_REG86;
|
||||
caller_phys = umap_local(proc_addr(who_p), D, caller_vir, sizeof(reg86));
|
||||
if (0 == caller_phys) return(EFAULT);
|
||||
kernel_phys = vir2phys(®86);
|
||||
phys_copy(caller_phys, kernel_phys, (phys_bytes) sizeof(reg86));
|
||||
data_copy(who_e, (vir_bytes) m_ptr->INT86_REG86,
|
||||
SYSTEM, (vir_bytes) ®86, sizeof(reg86));
|
||||
|
||||
level0(int86);
|
||||
|
||||
/* Copy results back to the caller */
|
||||
phys_copy(kernel_phys, caller_phys, (phys_bytes) sizeof(reg86));
|
||||
data_copy(SYSTEM, (vir_bytes) ®86,
|
||||
who_e, (vir_bytes) m_ptr->INT86_REG86, sizeof(reg86));
|
||||
|
||||
/* The BIOS call eats interrupts. Call get_randomness to generate some
|
||||
* entropy. Normally, get_randomness is called from an interrupt handler.
|
||||
* Figuring out the exact source is too complicated. CLOCK_IRQ is normally
|
||||
* not very random.
|
||||
*/
|
||||
lock(0, "do_int86");
|
||||
lock;
|
||||
get_randomness(CLOCK_IRQ);
|
||||
unlock(0);
|
||||
unlock;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -16,24 +16,14 @@
|
||||
PUBLIC int do_readbios(m_ptr)
|
||||
register message *m_ptr; /* pointer to request message */
|
||||
{
|
||||
int proc_nr;
|
||||
struct proc *p;
|
||||
phys_bytes address, phys_buf, phys_bios;
|
||||
vir_bytes buf;
|
||||
size_t size;
|
||||
struct vir_addr src, dst;
|
||||
|
||||
src.segment = BIOS_SEG;
|
||||
dst.segment = D;
|
||||
src.offset = m_ptr->RDB_ADDR;
|
||||
dst.offset = (vir_bytes) m_ptr->RDB_BUF;
|
||||
src.proc_nr_e = NONE;
|
||||
dst.proc_nr_e = m_ptr->m_source;
|
||||
|
||||
address = m_ptr->RDB_ADDR;
|
||||
buf = (vir_bytes)m_ptr->RDB_BUF;
|
||||
size = m_ptr->RDB_SIZE;
|
||||
|
||||
okendpt(m_ptr->m_source, &proc_nr);
|
||||
p = proc_addr(proc_nr);
|
||||
phys_buf = umap_local(p, D, buf, size);
|
||||
if (phys_buf == 0)
|
||||
return EFAULT;
|
||||
phys_bios = umap_bios(p, address, size);
|
||||
if (phys_bios == 0)
|
||||
return EPERM;
|
||||
phys_copy(phys_bios, phys_buf, size);
|
||||
return 0;
|
||||
return virtual_copy_vmcheck(&src, &dst, m_ptr->RDB_SIZE);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ register message *m_ptr; /* pointer to request message */
|
||||
return EPERM;
|
||||
}
|
||||
/* Get and check physical address. */
|
||||
if ((phys_buf = numap_local(proc_nr,
|
||||
if ((phys_buf = umap_virtual(proc_addr(proc_nr), D,
|
||||
(vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
|
||||
return(EFAULT);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,66 @@
|
||||
#include "../../kernel.h"
|
||||
#include "proto.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include "../../proc.h"
|
||||
|
||||
extern int vm_copy_in_progress;
|
||||
extern struct proc *vm_copy_from, *vm_copy_to;
|
||||
extern u32_t vm_copy_from_v, vm_copy_to_v;
|
||||
extern u32_t vm_copy_from_p, vm_copy_to_p, vm_copy_cr3;
|
||||
|
||||
u32_t pagefault_cr2, pagefault_count = 0;
|
||||
|
||||
void pagefault(struct proc *pr, int trap_errno)
|
||||
{
|
||||
int s;
|
||||
vir_bytes ph;
|
||||
u32_t pte;
|
||||
|
||||
if(pagefault_count != 1)
|
||||
minix_panic("recursive pagefault", pagefault_count);
|
||||
|
||||
/* Don't schedule this process until pagefault is handled. */
|
||||
if(RTS_ISSET(pr, PAGEFAULT))
|
||||
minix_panic("PAGEFAULT set", pr->p_endpoint);
|
||||
RTS_LOCK_SET(pr, PAGEFAULT);
|
||||
|
||||
if(pr->p_endpoint <= INIT_PROC_NR) {
|
||||
/* Page fault we can't / don't want to
|
||||
* handle.
|
||||
*/
|
||||
kprintf("pagefault for process %d ('%s'), pc = 0x%x\n",
|
||||
pr->p_endpoint, pr->p_name, pr->p_reg.pc);
|
||||
proc_stacktrace(pr);
|
||||
minix_panic("page fault in system process", pr->p_endpoint);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save pagefault details, suspend process,
|
||||
* add process to pagefault chain,
|
||||
* and tell VM there is a pagefault to be
|
||||
* handled.
|
||||
*/
|
||||
pr->p_pagefault.pf_virtual = pagefault_cr2;
|
||||
pr->p_pagefault.pf_flags = trap_errno;
|
||||
pr->p_nextpagefault = pagefaults;
|
||||
pagefaults = pr;
|
||||
lock_notify(HARDWARE, VM_PROC_NR);
|
||||
|
||||
pagefault_count = 0;
|
||||
|
||||
#if 0
|
||||
kprintf("pagefault for process %d ('%s'), pc = 0x%x\n",
|
||||
pr->p_endpoint, pr->p_name, pr->p_reg.pc);
|
||||
proc_stacktrace(pr);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* exception *
|
||||
*===========================================================================*/
|
||||
@@ -62,8 +120,13 @@ u32_t old_eflags;
|
||||
* k_reenter larger than zero.
|
||||
*/
|
||||
if (k_reenter == 0 && ! iskernelp(saved_proc)) {
|
||||
#if 0
|
||||
{
|
||||
switch(vec_nr) {
|
||||
case PAGE_FAULT_VECTOR:
|
||||
pagefault(saved_proc, trap_errno);
|
||||
return;
|
||||
}
|
||||
|
||||
kprintf(
|
||||
"exception for process %d, endpoint %d ('%s'), pc = 0x%x:0x%x, sp = 0x%x:0x%x\n",
|
||||
proc_nr(saved_proc), saved_proc->p_endpoint,
|
||||
@@ -75,12 +138,11 @@ u32_t old_eflags;
|
||||
vec_nr, (unsigned long)trap_errno,
|
||||
(unsigned long)old_eip, old_cs,
|
||||
(unsigned long)old_eflags);
|
||||
#if DEBUG_STACKTRACE
|
||||
stacktrace(saved_proc);
|
||||
#endif
|
||||
proc_stacktrace(saved_proc);
|
||||
}
|
||||
#endif
|
||||
|
||||
kprintf("kernel: cause_sig %d for %d\n",
|
||||
ep->signum, saved_proc->p_endpoint);
|
||||
cause_sig(proc_nr(saved_proc), ep->signum);
|
||||
return;
|
||||
}
|
||||
@@ -92,43 +154,45 @@ u32_t old_eflags;
|
||||
kprintf("\n%s\n", ep->msg);
|
||||
kprintf("k_reenter = %d ", k_reenter);
|
||||
kprintf("process %d (%s), ", proc_nr(saved_proc), saved_proc->p_name);
|
||||
kprintf("pc = %u:0x%x", (unsigned) saved_proc->p_reg.cs,
|
||||
(unsigned) saved_proc->p_reg.pc);
|
||||
kprintf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs,
|
||||
(unsigned) saved_proc->p_reg.pc);
|
||||
kprintf(
|
||||
"vec_nr= %d, trap_errno= 0x%lx, eip= 0x%lx, cs= 0x%x, eflags= 0x%lx\n",
|
||||
vec_nr, (unsigned long)trap_errno,
|
||||
(unsigned long)old_eip, old_cs, (unsigned long)old_eflags);
|
||||
proc_stacktrace(saved_proc);
|
||||
|
||||
panic("exception in a kernel task", NO_NUM);
|
||||
minix_panic("exception in a kernel task", saved_proc->p_endpoint);
|
||||
}
|
||||
|
||||
#if DEBUG_STACKTRACE
|
||||
/*===========================================================================*
|
||||
* stacktrace *
|
||||
*===========================================================================*/
|
||||
PUBLIC void stacktrace(struct proc *proc)
|
||||
PUBLIC void proc_stacktrace(struct proc *proc)
|
||||
{
|
||||
reg_t bp, v_bp, v_pc, v_hbp;
|
||||
|
||||
v_bp = proc->p_reg.fp;
|
||||
|
||||
kprintf("stacktrace: ");
|
||||
kprintf("ep %d pc 0x%lx stack ", proc->p_endpoint, proc->p_reg.pc);
|
||||
|
||||
while(v_bp) {
|
||||
phys_bytes p;
|
||||
if(!(p = umap_local(proc, D, v_bp, sizeof(v_bp)))) {
|
||||
kprintf("(bad bp %lx)", v_bp);
|
||||
if(data_copy(proc->p_endpoint, v_bp,
|
||||
SYSTEM, (vir_bytes) &v_hbp, sizeof(v_hbp)) != OK) {
|
||||
kprintf("(v_bp 0x%lx ?)", v_bp);
|
||||
break;
|
||||
}
|
||||
if(data_copy(proc->p_endpoint, v_bp + sizeof(v_pc),
|
||||
SYSTEM, (vir_bytes) &v_pc, sizeof(v_pc)) != OK) {
|
||||
kprintf("(v_pc 0x%lx ?)", v_pc);
|
||||
break;
|
||||
}
|
||||
phys_copy(p+sizeof(v_pc), vir2phys(&v_pc), sizeof(v_pc));
|
||||
phys_copy(p, vir2phys(&v_hbp), sizeof(v_hbp));
|
||||
kprintf("0x%lx ", (unsigned long) v_pc);
|
||||
if(v_hbp != 0 && v_hbp <= v_bp) {
|
||||
kprintf("(bad hbp %lx)", v_hbp);
|
||||
kprintf("(hbp %lx ?)", v_hbp);
|
||||
break;
|
||||
}
|
||||
v_bp = v_hbp;
|
||||
}
|
||||
kprintf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -135,12 +135,6 @@
|
||||
#define IF_MASK 0x00000200
|
||||
#define IOPL_MASK 0x003000
|
||||
|
||||
/* Sizes of memory tables. The boot monitor distinguishes three memory areas,
|
||||
* namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed
|
||||
* for DOS MINIX.
|
||||
*/
|
||||
#define NR_MEMS 8
|
||||
|
||||
#define vir2phys(vir) (kinfo.data_base + (vir_bytes) (vir))
|
||||
|
||||
#endif /* _I386_ACONST_H */
|
||||
|
||||
@@ -55,8 +55,18 @@ struct segdesc_s { /* segment descriptor for protected mode */
|
||||
|
||||
typedef struct segframe {
|
||||
reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */
|
||||
reg_t p_cr3; /* page table root */
|
||||
struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS and remote */
|
||||
} segframe_t;
|
||||
|
||||
/* Page fault event. Stored in process table. Only valid if PAGEFAULT
|
||||
* set in p_rts_flags.
|
||||
*/
|
||||
struct pagefault
|
||||
{
|
||||
u32_t pf_virtual; /* Address causing fault (CR2). */
|
||||
u32_t pf_flags; /* Pagefault flags on stack. */
|
||||
};
|
||||
|
||||
#endif /* #ifndef _I386_TYPES_H */
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <ibm/interrupt.h>
|
||||
#include <archconst.h>
|
||||
#include "../../const.h"
|
||||
#include "vm.h"
|
||||
#include "sconst.h"
|
||||
|
||||
! This file contains a number of assembly code utility routines needed by the
|
||||
@@ -15,7 +16,7 @@
|
||||
|
||||
.define _monitor ! exit Minix and return to the monitor
|
||||
.define _int86 ! let the monitor make an 8086 interrupt call
|
||||
.define _cp_mess ! copies messages from source to destination
|
||||
!.define _cp_mess ! copies messages from source to destination
|
||||
.define _exit ! dummy for library routines
|
||||
.define __exit ! dummy for library routines
|
||||
.define ___exit ! dummy for library routines
|
||||
@@ -34,8 +35,11 @@
|
||||
.define _level0 ! call a function at level 0
|
||||
.define _read_cpu_flags ! read the cpu flags
|
||||
.define _read_cr0 ! read cr0
|
||||
.define _write_cr3 ! write cr3
|
||||
.define _last_cr3
|
||||
.define _write_cr0 ! write a value in cr0
|
||||
.define _write_cr3 ! write a value in cr3 (root of the page table)
|
||||
|
||||
.define _kernel_cr3
|
||||
|
||||
! The routines only guarantee to preserve the registers the C compiler
|
||||
! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
|
||||
@@ -162,42 +166,42 @@ csinit: mov eax, DS_SELECTOR
|
||||
! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set
|
||||
! correctly. Changing the definition of message in the type file and not
|
||||
! changing it here will lead to total disaster.
|
||||
|
||||
CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4
|
||||
! es ds edi esi eip proc scl sof dcl dof
|
||||
|
||||
.align 16
|
||||
_cp_mess:
|
||||
cld
|
||||
push esi
|
||||
push edi
|
||||
push ds
|
||||
push es
|
||||
|
||||
mov eax, FLAT_DS_SELECTOR
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
mov esi, CM_ARGS+4(esp) ! src clicks
|
||||
shl esi, CLICK_SHIFT
|
||||
add esi, CM_ARGS+4+4(esp) ! src offset
|
||||
mov edi, CM_ARGS+4+4+4(esp) ! dst clicks
|
||||
shl edi, CLICK_SHIFT
|
||||
add edi, CM_ARGS+4+4+4+4(esp) ! dst offset
|
||||
|
||||
mov eax, CM_ARGS(esp) ! process number of sender
|
||||
stos ! copy number of sender to dest message
|
||||
add esi, 4 ! do not copy first word
|
||||
mov ecx, Msize - 1 ! remember, first word does not count
|
||||
rep
|
||||
movs ! copy the message
|
||||
|
||||
pop es
|
||||
pop ds
|
||||
pop edi
|
||||
pop esi
|
||||
ret ! that is all folks!
|
||||
|
||||
!
|
||||
!CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4
|
||||
!! es ds edi esi eip proc scl sof dcl dof
|
||||
!
|
||||
! .align 16
|
||||
!_cp_mess:
|
||||
! cld
|
||||
! push esi
|
||||
! push edi
|
||||
! push ds
|
||||
! push es
|
||||
!
|
||||
! mov eax, FLAT_DS_SELECTOR
|
||||
! mov ds, ax
|
||||
! mov es, ax
|
||||
!
|
||||
! mov esi, CM_ARGS+4(esp) ! src clicks
|
||||
! shl esi, CLICK_SHIFT
|
||||
! add esi, CM_ARGS+4+4(esp) ! src offset
|
||||
! mov edi, CM_ARGS+4+4+4(esp) ! dst clicks
|
||||
! shl edi, CLICK_SHIFT
|
||||
! add edi, CM_ARGS+4+4+4+4(esp) ! dst offset
|
||||
!
|
||||
! mov eax, CM_ARGS(esp) ! process number of sender
|
||||
! stos ! copy number of sender to dest message
|
||||
! add esi, 4 ! do not copy first word
|
||||
! mov ecx, Msize - 1 ! remember, first word does not count
|
||||
! rep
|
||||
! movs ! copy the message
|
||||
!
|
||||
! pop es
|
||||
! pop ds
|
||||
! pop edi
|
||||
! pop esi
|
||||
! ret ! that is all folks!
|
||||
!
|
||||
|
||||
!*===========================================================================*
|
||||
!* exit *
|
||||
@@ -229,6 +233,9 @@ _phys_insw:
|
||||
cld
|
||||
push edi
|
||||
push es
|
||||
|
||||
LOADKERNELCR3
|
||||
|
||||
mov ecx, FLAT_DS_SELECTOR
|
||||
mov es, cx
|
||||
mov edx, 8(ebp) ! port to read from
|
||||
@@ -254,6 +261,9 @@ _phys_insb:
|
||||
cld
|
||||
push edi
|
||||
push es
|
||||
|
||||
LOADKERNELCR3
|
||||
|
||||
mov ecx, FLAT_DS_SELECTOR
|
||||
mov es, cx
|
||||
mov edx, 8(ebp) ! port to read from
|
||||
@@ -280,6 +290,9 @@ _phys_outsw:
|
||||
cld
|
||||
push esi
|
||||
push ds
|
||||
|
||||
LOADKERNELCR3
|
||||
|
||||
mov ecx, FLAT_DS_SELECTOR
|
||||
mov ds, cx
|
||||
mov edx, 8(ebp) ! port to write to
|
||||
@@ -306,6 +319,9 @@ _phys_outsb:
|
||||
cld
|
||||
push esi
|
||||
push ds
|
||||
|
||||
LOADKERNELCR3
|
||||
|
||||
mov ecx, FLAT_DS_SELECTOR
|
||||
mov ds, cx
|
||||
mov edx, 8(ebp) ! port to write to
|
||||
@@ -412,6 +428,8 @@ _phys_copy:
|
||||
push edi
|
||||
push es
|
||||
|
||||
LOADKERNELCR3
|
||||
|
||||
mov eax, FLAT_DS_SELECTOR
|
||||
mov es, ax
|
||||
|
||||
@@ -456,6 +474,9 @@ _phys_memset:
|
||||
push esi
|
||||
push ebx
|
||||
push ds
|
||||
|
||||
LOADKERNELCR3
|
||||
|
||||
mov esi, 8(ebp)
|
||||
mov eax, 16(ebp)
|
||||
mov ebx, FLAT_DS_SELECTOR
|
||||
@@ -485,6 +506,7 @@ fill_done:
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
!*===========================================================================*
|
||||
!* mem_rdw *
|
||||
@@ -585,14 +607,13 @@ _write_cr0:
|
||||
ret
|
||||
|
||||
!*===========================================================================*
|
||||
!* write_cr3 *
|
||||
!* write_cr3 *
|
||||
!*===========================================================================*
|
||||
! PUBLIC void write_cr3(unsigned long value);
|
||||
_write_cr3:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
mov eax, 8(ebp)
|
||||
mov cr3, eax
|
||||
pop ebp
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
LOADCR3WITHEAX(0x22, 8(ebp))
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../proc.h"
|
||||
#include "../../vm.h"
|
||||
|
||||
#include <minix/type.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/vm.h>
|
||||
#include <sys/vm_i386.h>
|
||||
|
||||
#include <minix/portio.h>
|
||||
|
||||
#include "proto.h"
|
||||
#include "../../proto.h"
|
||||
#include "../../debug.h"
|
||||
|
||||
/* VM functions and data. */
|
||||
|
||||
PRIVATE int vm_needs_init= 1;
|
||||
PRIVATE u32_t vm_cr3;
|
||||
PUBLIC u32_t kernel_cr3;
|
||||
extern u32_t cswitch;
|
||||
u32_t last_cr3 = 0;
|
||||
|
||||
FORWARD _PROTOTYPE( void phys_put32, (phys_bytes addr, u32_t value) );
|
||||
FORWARD _PROTOTYPE( u32_t phys_get32, (phys_bytes addr) );
|
||||
@@ -22,6 +28,13 @@ FORWARD _PROTOTYPE( void vm_set_cr3, (u32_t value) );
|
||||
FORWARD _PROTOTYPE( void set_cr3, (void) );
|
||||
FORWARD _PROTOTYPE( void vm_enable_paging, (void) );
|
||||
|
||||
#if DEBUG_VMASSERT
|
||||
#define vmassert(t) { \
|
||||
if(!(t)) { minix_panic("vm: assert " #t " failed\n", __LINE__); } }
|
||||
#else
|
||||
#define vmassert(t) { }
|
||||
#endif
|
||||
|
||||
/* *** Internal VM Functions *** */
|
||||
|
||||
PUBLIC void vm_init(void)
|
||||
@@ -31,31 +44,35 @@ PUBLIC void vm_init(void)
|
||||
phys_bytes vm_dir_base, vm_pt_base, phys_mem;
|
||||
u32_t entry;
|
||||
unsigned pages;
|
||||
struct proc* rp;
|
||||
|
||||
if (!vm_size)
|
||||
panic("i386_vm_init: no space for page tables", NO_NUM);
|
||||
minix_panic("i386_vm_init: no space for page tables", NO_NUM);
|
||||
|
||||
if(vm_running)
|
||||
return;
|
||||
|
||||
/* Align page directory */
|
||||
o= (vm_base % PAGE_SIZE);
|
||||
o= (vm_base % I386_PAGE_SIZE);
|
||||
if (o != 0)
|
||||
o= PAGE_SIZE-o;
|
||||
o= I386_PAGE_SIZE-o;
|
||||
vm_dir_base= vm_base+o;
|
||||
|
||||
/* Page tables start after the page directory */
|
||||
vm_pt_base= vm_dir_base+PAGE_SIZE;
|
||||
vm_pt_base= vm_dir_base+I386_PAGE_SIZE;
|
||||
|
||||
pt_size= (vm_base+vm_size)-vm_pt_base;
|
||||
pt_size -= (pt_size % PAGE_SIZE);
|
||||
pt_size -= (pt_size % I386_PAGE_SIZE);
|
||||
|
||||
/* Compute the number of pages based on vm_mem_high */
|
||||
pages= (vm_mem_high-1)/PAGE_SIZE + 1;
|
||||
pages= (vm_mem_high-1)/I386_PAGE_SIZE + 1;
|
||||
|
||||
if (pages * I386_VM_PT_ENT_SIZE > pt_size)
|
||||
panic("i386_vm_init: page table too small", NO_NUM);
|
||||
minix_panic("i386_vm_init: page table too small", NO_NUM);
|
||||
|
||||
for (p= 0; p*I386_VM_PT_ENT_SIZE < pt_size; p++)
|
||||
{
|
||||
phys_mem= p*PAGE_SIZE;
|
||||
phys_mem= p*I386_PAGE_SIZE;
|
||||
entry= phys_mem | I386_VM_USER | I386_VM_WRITE |
|
||||
I386_VM_PRESENT;
|
||||
if (phys_mem >= vm_mem_high)
|
||||
@@ -65,15 +82,33 @@ PUBLIC void vm_init(void)
|
||||
|
||||
for (p= 0; p < I386_VM_DIR_ENTRIES; p++)
|
||||
{
|
||||
phys_mem= vm_pt_base + p*PAGE_SIZE;
|
||||
phys_mem= vm_pt_base + p*I386_PAGE_SIZE;
|
||||
entry= phys_mem | I386_VM_USER | I386_VM_WRITE |
|
||||
I386_VM_PRESENT;
|
||||
if (phys_mem >= vm_pt_base + pt_size)
|
||||
entry= 0;
|
||||
phys_put32(vm_dir_base + p*I386_VM_PT_ENT_SIZE, entry);
|
||||
}
|
||||
|
||||
/* Set this cr3 in all currently running processes for
|
||||
* future context switches.
|
||||
*/
|
||||
for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
|
||||
u32_t mycr3;
|
||||
if(isemptyp(rp)) continue;
|
||||
rp->p_seg.p_cr3 = vm_dir_base;
|
||||
}
|
||||
|
||||
kernel_cr3 = vm_dir_base;
|
||||
|
||||
/* Set this cr3 now (not active until paging enabled). */
|
||||
vm_set_cr3(vm_dir_base);
|
||||
|
||||
/* Actually enable paging (activating cr3 load above). */
|
||||
level0(vm_enable_paging);
|
||||
|
||||
/* Don't do this init in the future. */
|
||||
vm_running = 1;
|
||||
}
|
||||
|
||||
PRIVATE void phys_put32(addr, value)
|
||||
@@ -113,50 +148,6 @@ PRIVATE void vm_enable_paging(void)
|
||||
write_cr0(cr0 | I386_CR0_PG);
|
||||
}
|
||||
|
||||
PUBLIC void vm_map_range(base, size, offset)
|
||||
u32_t base;
|
||||
u32_t size;
|
||||
u32_t offset;
|
||||
{
|
||||
u32_t curr_pt, curr_pt_addr, entry;
|
||||
int dir_ent, pt_ent;
|
||||
|
||||
if (base % PAGE_SIZE != 0)
|
||||
panic("map_range: bad base", base);
|
||||
if (size % PAGE_SIZE != 0)
|
||||
panic("map_range: bad size", size);
|
||||
if (offset % PAGE_SIZE != 0)
|
||||
panic("map_range: bad offset", offset);
|
||||
|
||||
curr_pt= -1;
|
||||
curr_pt_addr= 0;
|
||||
while (size != 0)
|
||||
{
|
||||
dir_ent= (base >> I386_VM_DIR_ENT_SHIFT);
|
||||
pt_ent= (base >> I386_VM_PT_ENT_SHIFT) & I386_VM_PT_ENT_MASK;
|
||||
if (dir_ent != curr_pt)
|
||||
{
|
||||
/* Get address of page table */
|
||||
curr_pt= dir_ent;
|
||||
curr_pt_addr= phys_get32(vm_cr3 +
|
||||
dir_ent * I386_VM_PT_ENT_SIZE);
|
||||
curr_pt_addr &= I386_VM_ADDR_MASK;
|
||||
}
|
||||
entry= offset | I386_VM_USER | I386_VM_WRITE |
|
||||
I386_VM_PRESENT;
|
||||
#if 0 /* Do we need this for memory mapped I/O? */
|
||||
entry |= I386_VM_PCD | I386_VM_PWT;
|
||||
#endif
|
||||
phys_put32(curr_pt_addr + pt_ent * I386_VM_PT_ENT_SIZE, entry);
|
||||
offset += PAGE_SIZE;
|
||||
base += PAGE_SIZE;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
/* reload root of page table. */
|
||||
vm_set_cr3(vm_cr3);
|
||||
}
|
||||
|
||||
PUBLIC vir_bytes alloc_remote_segment(u32_t *selector,
|
||||
segframe_t *segments, int index, phys_bytes phys, vir_bytes size,
|
||||
int priv)
|
||||
@@ -188,6 +179,10 @@ PUBLIC phys_bytes umap_remote(struct proc* rp, int seg,
|
||||
/* Calculate the physical memory address for a given virtual address. */
|
||||
struct far_mem *fm;
|
||||
|
||||
#if 0
|
||||
if(rp->p_misc_flags & MF_FULLVM) return 0;
|
||||
#endif
|
||||
|
||||
if (bytes <= 0) return( (phys_bytes) 0);
|
||||
if (seg < 0 || seg >= NR_REMOTE_SEGS) return( (phys_bytes) 0);
|
||||
|
||||
@@ -212,6 +207,9 @@ vir_bytes bytes; /* # of bytes to be copied */
|
||||
phys_bytes pa; /* intermediate variables as phys_bytes */
|
||||
phys_bytes seg_base;
|
||||
|
||||
if(seg != T && seg != D && seg != S)
|
||||
minix_panic("umap_local: wrong seg", seg);
|
||||
|
||||
if (bytes <= 0) return( (phys_bytes) 0);
|
||||
if (vir_addr + bytes <= vir_addr) return 0; /* overflow */
|
||||
vc = (vir_addr + bytes - 1) >> CLICK_SHIFT; /* last click of data */
|
||||
@@ -232,3 +230,569 @@ vir_bytes bytes; /* # of bytes to be copied */
|
||||
return(seg_base + pa);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* umap_virtual *
|
||||
*===========================================================================*/
|
||||
PUBLIC phys_bytes umap_virtual(rp, seg, vir_addr, bytes)
|
||||
register struct proc *rp; /* pointer to proc table entry for process */
|
||||
int seg; /* T, D, or S segment */
|
||||
vir_bytes vir_addr; /* virtual address in bytes within the seg */
|
||||
vir_bytes bytes; /* # of bytes to be copied */
|
||||
{
|
||||
vir_bytes linear;
|
||||
u32_t phys = 0;
|
||||
|
||||
if(seg == MEM_GRANT) {
|
||||
phys = umap_grant(rp, vir_addr, bytes);
|
||||
} else {
|
||||
if(!(linear = umap_local(rp, seg, vir_addr, bytes))) {
|
||||
kprintf("SYSTEM:umap_virtual: umap_local failed\n");
|
||||
phys = 0;
|
||||
} else {
|
||||
if(vm_lookup(rp, linear, &phys, NULL) != OK) {
|
||||
kprintf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%lx: 0x%lx failed\n", rp->p_name, seg, vir_addr);
|
||||
phys = 0;
|
||||
}
|
||||
if(phys == 0)
|
||||
minix_panic("vm_lookup returned phys", phys);
|
||||
}
|
||||
}
|
||||
|
||||
if(phys == 0) {
|
||||
kprintf("SYSTEM:umap_virtual: lookup failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now make sure addresses are contiguous in physical memory
|
||||
* so that the umap makes sense.
|
||||
*/
|
||||
if(bytes > 0 && !vm_contiguous(rp, linear, bytes)) {
|
||||
kprintf("umap_virtual: %s: %d at 0x%lx (vir 0x%lx) not contiguous\n",
|
||||
rp->p_name, bytes, linear, vir_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* phys must be larger than 0 (or the caller will think the call
|
||||
* failed), and address must not cross a page boundary.
|
||||
*/
|
||||
vmassert(phys);
|
||||
|
||||
return phys;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_lookup *
|
||||
*===========================================================================*/
|
||||
PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, u32_t *ptent)
|
||||
{
|
||||
u32_t *root, *pt;
|
||||
int pde, pte;
|
||||
u32_t pde_v, pte_v;
|
||||
|
||||
vmassert(proc);
|
||||
vmassert(physical);
|
||||
vmassert(!(proc->p_rts_flags & SLOT_FREE));
|
||||
|
||||
/* Retrieve page directory entry. */
|
||||
root = (u32_t *) proc->p_seg.p_cr3;
|
||||
vmassert(!((u32_t) root % I386_PAGE_SIZE));
|
||||
pde = I386_VM_PDE(virtual);
|
||||
vmassert(pde >= 0 && pde < I386_VM_DIR_ENTRIES);
|
||||
pde_v = phys_get32((u32_t) (root + pde));
|
||||
if(!(pde_v & I386_VM_PRESENT)) {
|
||||
#if 0
|
||||
kprintf("vm_lookup: %d:%s:0x%lx: cr3 0x%lx: pde %d not present\n",
|
||||
proc->p_endpoint, proc->p_name, virtual, root, pde);
|
||||
kprintf("kernel stack: ");
|
||||
util_stacktrace();
|
||||
#endif
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
/* Retrieve page table entry. */
|
||||
pt = (u32_t *) I386_VM_PFA(pde_v);
|
||||
vmassert(!((u32_t) pt % I386_PAGE_SIZE));
|
||||
pte = I386_VM_PTE(virtual);
|
||||
vmassert(pte >= 0 && pte < I386_VM_PT_ENTRIES);
|
||||
pte_v = phys_get32((u32_t) (pt + pte));
|
||||
if(!(pte_v & I386_VM_PRESENT)) {
|
||||
#if 0
|
||||
kprintf("vm_lookup: %d:%s:0x%lx: cr3 %lx: pde %d: pte %d not present\n",
|
||||
proc->p_endpoint, proc->p_name, virtual, root, pde, pte);
|
||||
kprintf("kernel stack: ");
|
||||
util_stacktrace();
|
||||
#endif
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
if(ptent) *ptent = pte_v;
|
||||
|
||||
/* Actual address now known; retrieve it and add page offset. */
|
||||
*physical = I386_VM_PFA(pte_v);
|
||||
*physical += virtual % I386_PAGE_SIZE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* From virtual address v in process p,
|
||||
* lookup physical address and assign it to d.
|
||||
* If p is NULL, assume it's already a physical address.
|
||||
*/
|
||||
#define LOOKUP(d, p, v, flagsp) { \
|
||||
int r; \
|
||||
if(!(p)) { (d) = (v); } \
|
||||
else { \
|
||||
if((r=vm_lookup((p), (v), &(d), flagsp)) != OK) { \
|
||||
kprintf("vm_copy: lookup failed of 0x%lx in %d (%s)\n"\
|
||||
"kernel stacktrace: ", (v), (p)->p_endpoint, \
|
||||
(p)->p_name); \
|
||||
util_stacktrace(); \
|
||||
return r; \
|
||||
} } }
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_copy *
|
||||
*===========================================================================*/
|
||||
int vm_copy(vir_bytes src, struct proc *srcproc,
|
||||
vir_bytes dst, struct proc *dstproc, phys_bytes bytes)
|
||||
{
|
||||
#define WRAPS(v) (ULONG_MAX - (v) <= bytes)
|
||||
|
||||
if(WRAPS(src) || WRAPS(dst))
|
||||
minix_panic("vm_copy: linear address wraps", NO_NUM);
|
||||
|
||||
while(bytes > 0) {
|
||||
u32_t n, flags;
|
||||
phys_bytes p_src, p_dst;
|
||||
#define PAGEREMAIN(v) (I386_PAGE_SIZE - ((v) % I386_PAGE_SIZE))
|
||||
|
||||
/* We can copy this number of bytes without
|
||||
* crossing a page boundary, but don't copy more
|
||||
* than asked.
|
||||
*/
|
||||
n = MIN(PAGEREMAIN(src), PAGEREMAIN(dst));
|
||||
n = MIN(n, bytes);
|
||||
vmassert(n > 0);
|
||||
vmassert(n <= I386_PAGE_SIZE);
|
||||
|
||||
/* Convert both virtual addresses to physical and do
|
||||
* copy.
|
||||
*/
|
||||
LOOKUP(p_src, srcproc, src, NULL);
|
||||
LOOKUP(p_dst, dstproc, dst, &flags);
|
||||
if(!(flags & I386_VM_WRITE)) {
|
||||
kprintf("vm_copy: copying to nonwritable page\n");
|
||||
kprintf("kernel stack: ");
|
||||
util_stacktrace();
|
||||
return EFAULT;
|
||||
}
|
||||
phys_copy(p_src, p_dst, n);
|
||||
|
||||
/* Book number of bytes copied. */
|
||||
vmassert(bytes >= n);
|
||||
bytes -= n;
|
||||
src += n;
|
||||
dst += n;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_contiguous *
|
||||
*===========================================================================*/
|
||||
PUBLIC int vm_contiguous(struct proc *targetproc, u32_t vir_buf, size_t bytes)
|
||||
{
|
||||
int first = 1, r, boundaries = 0;
|
||||
u32_t prev_phys, po;
|
||||
u32_t prev_vir;
|
||||
|
||||
vmassert(targetproc);
|
||||
vmassert(bytes > 0);
|
||||
vmassert(vm_running);
|
||||
|
||||
/* Start and end at page boundary to make logic simpler. */
|
||||
po = vir_buf % I386_PAGE_SIZE;
|
||||
if(po > 0) {
|
||||
bytes += po;
|
||||
vir_buf -= po;
|
||||
}
|
||||
po = (vir_buf + bytes) % I386_PAGE_SIZE;
|
||||
if(po > 0)
|
||||
bytes += I386_PAGE_SIZE - po;
|
||||
|
||||
/* Keep going as long as we cross a page boundary. */
|
||||
while(bytes > 0) {
|
||||
u32_t phys;
|
||||
|
||||
if((r=vm_lookup(targetproc, vir_buf, &phys, NULL)) != OK) {
|
||||
kprintf("vm_contiguous: vm_lookup failed, %d\n", r);
|
||||
kprintf("kernel stack: ");
|
||||
util_stacktrace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!first) {
|
||||
if(prev_phys+I386_PAGE_SIZE != phys) {
|
||||
kprintf("vm_contiguous: no (0x%lx, 0x%lx)\n",
|
||||
prev_phys, phys);
|
||||
kprintf("kernel stack: ");
|
||||
util_stacktrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
first = 0;
|
||||
|
||||
prev_phys = phys;
|
||||
prev_vir = vir_buf;
|
||||
vir_buf += I386_PAGE_SIZE;
|
||||
bytes -= I386_PAGE_SIZE;
|
||||
boundaries++;
|
||||
}
|
||||
|
||||
if(verbose_vm)
|
||||
kprintf("vm_contiguous: yes (%d boundaries tested)\n",
|
||||
boundaries);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vm_checkrange_verbose = 0;
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_checkrange *
|
||||
*===========================================================================*/
|
||||
PUBLIC int vm_checkrange(struct proc *caller, struct proc *target,
|
||||
vir_bytes vir, vir_bytes bytes, int wrfl, int checkonly)
|
||||
{
|
||||
u32_t flags, po, v;
|
||||
int r;
|
||||
|
||||
vmassert(vm_running);
|
||||
|
||||
/* If caller has had a reply to this request, return it. */
|
||||
if(RTS_ISSET(caller, VMREQUEST)) {
|
||||
if(caller->p_vmrequest.who == target->p_endpoint) {
|
||||
if(caller->p_vmrequest.vmresult == VMSUSPEND)
|
||||
minix_panic("check sees VMSUSPEND?", NO_NUM);
|
||||
RTS_LOCK_UNSET(caller, VMREQUEST);
|
||||
#if 0
|
||||
kprintf("SYSTEM: vm_checkrange: returning vmresult %d\n",
|
||||
caller->p_vmrequest.vmresult);
|
||||
#endif
|
||||
return caller->p_vmrequest.vmresult;
|
||||
} else {
|
||||
#if 0
|
||||
kprintf("SYSTEM: vm_checkrange: caller has a request for %d, "
|
||||
"but our target is %d\n",
|
||||
caller->p_vmrequest.who, target->p_endpoint);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
po = vir % I386_PAGE_SIZE;
|
||||
if(po > 0) {
|
||||
vir -= po;
|
||||
bytes += po;
|
||||
}
|
||||
|
||||
vmassert(target);
|
||||
vmassert(bytes > 0);
|
||||
|
||||
for(v = vir; v < vir + bytes; v+= I386_PAGE_SIZE) {
|
||||
u32_t phys;
|
||||
|
||||
/* If page exists and it's writable if desired, we're OK
|
||||
* for this page.
|
||||
*/
|
||||
if(vm_lookup(target, v, &phys, &flags) == OK &&
|
||||
!(wrfl && !(flags & I386_VM_WRITE))) {
|
||||
if(vm_checkrange_verbose) {
|
||||
#if 0
|
||||
kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, OK\n",
|
||||
target->p_name, target->p_endpoint, v, wrfl, flags, phys);
|
||||
#endif
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(vm_checkrange_verbose) {
|
||||
kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, NOT OK\n",
|
||||
target->p_name, target->p_endpoint, v, wrfl, flags, phys);
|
||||
}
|
||||
|
||||
if(checkonly)
|
||||
return VMSUSPEND;
|
||||
|
||||
/* This range is not OK for this process. Set parameters
|
||||
* of the request and notify VM about the pending request.
|
||||
*/
|
||||
if(RTS_ISSET(caller, VMREQUEST))
|
||||
minix_panic("VMREQUEST already set", caller->p_endpoint);
|
||||
RTS_LOCK_SET(caller, VMREQUEST);
|
||||
|
||||
/* Set parameters in caller. */
|
||||
caller->p_vmrequest.writeflag = wrfl;
|
||||
caller->p_vmrequest.start = vir;
|
||||
caller->p_vmrequest.length = bytes;
|
||||
caller->p_vmrequest.who = target->p_endpoint;
|
||||
|
||||
/* Set caller in target. */
|
||||
target->p_vmrequest.requestor = caller;
|
||||
|
||||
/* Connect caller on vmrequest wait queue. */
|
||||
caller->p_vmrequest.nextrequestor = vmrequest;
|
||||
vmrequest = caller;
|
||||
soft_notify(VM_PROC_NR);
|
||||
|
||||
#if 0
|
||||
kprintf("SYSTEM: vm_checkrange: range bad for "
|
||||
"target %s:0x%lx-0x%lx, caller %s\n",
|
||||
target->p_name, vir, vir+bytes, caller->p_name);
|
||||
|
||||
kprintf("vm_checkrange kernel trace: ");
|
||||
util_stacktrace();
|
||||
kprintf("target trace: ");
|
||||
proc_stacktrace(target);
|
||||
#endif
|
||||
|
||||
if(target->p_endpoint == VM_PROC_NR) {
|
||||
kprintf("caller trace: ");
|
||||
proc_stacktrace(caller);
|
||||
kprintf("target trace: ");
|
||||
proc_stacktrace(target);
|
||||
minix_panic("VM ranges should be OK", NO_NUM);
|
||||
}
|
||||
|
||||
return VMSUSPEND;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
char *flagstr(u32_t e, int dir)
|
||||
{
|
||||
static char str[80];
|
||||
strcpy(str, "");
|
||||
#define FLAG(v) do { if(e & (v)) { strcat(str, #v " "); } } while(0)
|
||||
FLAG(I386_VM_PRESENT);
|
||||
FLAG(I386_VM_WRITE);
|
||||
FLAG(I386_VM_USER);
|
||||
FLAG(I386_VM_PWT);
|
||||
FLAG(I386_VM_PCD);
|
||||
if(dir)
|
||||
FLAG(I386_VM_BIGPAGE); /* Page directory entry only */
|
||||
else
|
||||
FLAG(I386_VM_DIRTY); /* Page table entry only */
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void vm_pt_print(u32_t *pagetable, u32_t v)
|
||||
{
|
||||
int pte, l = 0;
|
||||
int col = 0;
|
||||
|
||||
vmassert(!((u32_t) pagetable % I386_PAGE_SIZE));
|
||||
|
||||
for(pte = 0; pte < I386_VM_PT_ENTRIES; pte++) {
|
||||
u32_t pte_v, pfa;
|
||||
pte_v = phys_get32((u32_t) (pagetable + pte));
|
||||
if(!(pte_v & I386_VM_PRESENT))
|
||||
continue;
|
||||
pfa = I386_VM_PFA(pte_v);
|
||||
kprintf("%4d:%08lx:%08lx ",
|
||||
pte, v + I386_PAGE_SIZE*pte, pfa);
|
||||
col++;
|
||||
if(col == 3) { kprintf("\n"); col = 0; }
|
||||
}
|
||||
if(col > 0) kprintf("\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_print *
|
||||
*===========================================================================*/
|
||||
void vm_print(u32_t *root)
|
||||
{
|
||||
int pde;
|
||||
|
||||
vmassert(!((u32_t) root % I386_PAGE_SIZE));
|
||||
|
||||
for(pde = 0; pde < I386_VM_DIR_ENTRIES; pde++) {
|
||||
u32_t pde_v;
|
||||
u32_t *pte_a;
|
||||
pde_v = phys_get32((u32_t) (root + pde));
|
||||
if(!(pde_v & I386_VM_PRESENT))
|
||||
continue;
|
||||
pte_a = (u32_t *) I386_VM_PFA(pde_v);
|
||||
kprintf("%4d: pt %08lx %s\n",
|
||||
pde, pte_a, flagstr(pde_v, 1));
|
||||
vm_pt_print(pte_a, pde * I386_VM_PT_ENTRIES * I386_PAGE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* virtual_copy_f *
|
||||
*===========================================================================*/
|
||||
PUBLIC int virtual_copy_f(src_addr, dst_addr, bytes, vmcheck)
|
||||
struct vir_addr *src_addr; /* source virtual address */
|
||||
struct vir_addr *dst_addr; /* destination virtual address */
|
||||
vir_bytes bytes; /* # of bytes to copy */
|
||||
int vmcheck; /* if nonzero, can return VMSUSPEND */
|
||||
{
|
||||
/* Copy bytes from virtual address src_addr to virtual address dst_addr.
|
||||
* Virtual addresses can be in ABS, LOCAL_SEG, REMOTE_SEG, or BIOS_SEG.
|
||||
*/
|
||||
struct vir_addr *vir_addr[2]; /* virtual source and destination address */
|
||||
phys_bytes phys_addr[2]; /* absolute source and destination */
|
||||
int seg_index;
|
||||
int i, r;
|
||||
struct proc *procs[2];
|
||||
|
||||
/* Check copy count. */
|
||||
if (bytes <= 0) return(EDOM);
|
||||
|
||||
/* Do some more checks and map virtual addresses to physical addresses. */
|
||||
vir_addr[_SRC_] = src_addr;
|
||||
vir_addr[_DST_] = dst_addr;
|
||||
|
||||
for (i=_SRC_; i<=_DST_; i++) {
|
||||
int proc_nr, type;
|
||||
struct proc *p;
|
||||
|
||||
type = vir_addr[i]->segment & SEGMENT_TYPE;
|
||||
if((type != PHYS_SEG && type != BIOS_SEG) &&
|
||||
isokendpt(vir_addr[i]->proc_nr_e, &proc_nr))
|
||||
p = proc_addr(proc_nr);
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
procs[i] = p;
|
||||
|
||||
/* Get physical address. */
|
||||
switch(type) {
|
||||
case LOCAL_SEG:
|
||||
case LOCAL_VM_SEG:
|
||||
if(!p) return EDEADSRCDST;
|
||||
seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
|
||||
if(type == LOCAL_SEG)
|
||||
phys_addr[i] = umap_local(p, seg_index, vir_addr[i]->offset,
|
||||
bytes);
|
||||
else
|
||||
phys_addr[i] = umap_virtual(p, seg_index, vir_addr[i]->offset,
|
||||
bytes);
|
||||
if(phys_addr[i] == 0) {
|
||||
kprintf("virtual_copy: map 0x%x failed for %s seg %d, "
|
||||
"offset %lx, len %d, i %d\n",
|
||||
type, p->p_name, seg_index, vir_addr[i]->offset,
|
||||
bytes, i);
|
||||
}
|
||||
break;
|
||||
case REMOTE_SEG:
|
||||
if(!p) return EDEADSRCDST;
|
||||
seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
|
||||
phys_addr[i] = umap_remote(p, seg_index, vir_addr[i]->offset, bytes);
|
||||
break;
|
||||
#if _MINIX_CHIP == _CHIP_INTEL
|
||||
case BIOS_SEG:
|
||||
phys_addr[i] = umap_bios(vir_addr[i]->offset, bytes );
|
||||
break;
|
||||
#endif
|
||||
case PHYS_SEG:
|
||||
phys_addr[i] = vir_addr[i]->offset;
|
||||
break;
|
||||
case GRANT_SEG:
|
||||
phys_addr[i] = umap_grant(p, vir_addr[i]->offset, bytes);
|
||||
break;
|
||||
default:
|
||||
kprintf("virtual_copy: strange type 0x%x\n", type);
|
||||
return(EINVAL);
|
||||
}
|
||||
|
||||
/* Check if mapping succeeded. */
|
||||
if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) {
|
||||
kprintf("virtual_copy EFAULT\n");
|
||||
return(EFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
if(vmcheck && procs[_SRC_])
|
||||
CHECKRANGE_OR_SUSPEND(procs[_SRC_], phys_addr[_SRC_], bytes, 0);
|
||||
if(vmcheck && procs[_DST_])
|
||||
CHECKRANGE_OR_SUSPEND(procs[_DST_], phys_addr[_DST_], bytes, 1);
|
||||
|
||||
/* Now copy bytes between physical addresseses. */
|
||||
if(!vm_running || (procs[_SRC_] == NULL && procs[_DST_] == NULL)) {
|
||||
/* Without vm, address ranges actually are physical. */
|
||||
phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes);
|
||||
r = OK;
|
||||
} else {
|
||||
/* With vm, addresses need further interpretation. */
|
||||
r = vm_copy(phys_addr[_SRC_], procs[_SRC_],
|
||||
phys_addr[_DST_], procs[_DST_], (phys_bytes) bytes);
|
||||
if(r != OK) {
|
||||
kprintf("vm_copy: %lx to %lx failed\n",
|
||||
phys_addr[_SRC_],phys_addr[_DST_]);
|
||||
}
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* data_copy *
|
||||
*===========================================================================*/
|
||||
PUBLIC int data_copy(
|
||||
endpoint_t from_proc, vir_bytes from_addr,
|
||||
endpoint_t to_proc, vir_bytes to_addr,
|
||||
size_t bytes)
|
||||
{
|
||||
struct vir_addr src, dst;
|
||||
|
||||
src.segment = dst.segment = D;
|
||||
src.offset = from_addr;
|
||||
dst.offset = to_addr;
|
||||
src.proc_nr_e = from_proc;
|
||||
dst.proc_nr_e = to_proc;
|
||||
|
||||
return virtual_copy(&src, &dst, bytes);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* arch_pre_exec *
|
||||
*===========================================================================*/
|
||||
PUBLIC int arch_pre_exec(struct proc *pr, u32_t ip, u32_t sp)
|
||||
{
|
||||
/* wipe extra LDT entries, set program counter, and stack pointer. */
|
||||
memset(pr->p_seg.p_ldt + EXTRA_LDT_INDEX, 0,
|
||||
sizeof(pr->p_seg.p_ldt[0]) * (LDT_SIZE - EXTRA_LDT_INDEX));
|
||||
pr->p_reg.pc = ip;
|
||||
pr->p_reg.sp = sp;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* arch_umap *
|
||||
*===========================================================================*/
|
||||
PUBLIC int arch_umap(struct proc *pr, vir_bytes offset, vir_bytes count,
|
||||
int seg, phys_bytes *addr)
|
||||
{
|
||||
switch(seg) {
|
||||
case BIOS_SEG:
|
||||
*addr = umap_bios(offset, count);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* This must be EINVAL; the umap fallback function in
|
||||
* lib/syslib/alloc_util.c depends on it to detect an
|
||||
* older kernel (as opposed to mapping error).
|
||||
*/
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#
|
||||
#
|
||||
! This file, mpx386.s, is included by mpx.s when Minix is compiled for
|
||||
! 32-bit Intel CPUs. The alternative mpx88.s is compiled for 16-bit CPUs.
|
||||
|
||||
@@ -58,6 +58,7 @@ begbss:
|
||||
#include <ibm/interrupt.h>
|
||||
#include <archconst.h>
|
||||
#include "../../const.h"
|
||||
#include "vm.h"
|
||||
#include "sconst.h"
|
||||
|
||||
/* Selected 386 tss offsets. */
|
||||
@@ -71,6 +72,13 @@ begbss:
|
||||
|
||||
.define _restart
|
||||
.define save
|
||||
.define _kernel_cr3
|
||||
.define _pagefault_cr2
|
||||
.define _pagefault_count
|
||||
|
||||
.define errexception
|
||||
.define exception1
|
||||
.define exception
|
||||
|
||||
.define _divide_error
|
||||
.define _single_step_exception
|
||||
@@ -88,6 +96,9 @@ begbss:
|
||||
.define _general_protection
|
||||
.define _page_fault
|
||||
.define _copr_error
|
||||
.define _params_size
|
||||
.define _params_offset
|
||||
.define _mon_ds
|
||||
|
||||
.define _hwint00 ! handlers for hardware interrupts
|
||||
.define _hwint01
|
||||
@@ -173,6 +184,11 @@ copygdt:
|
||||
mov ss, ax
|
||||
mov esp, k_stktop ! set sp to point to the top of kernel stack
|
||||
|
||||
! Save boot parameters into these global variables for i386 code
|
||||
mov (_params_size), edx
|
||||
mov (_params_offset), ebx
|
||||
mov (_mon_ds), SS_SELECTOR
|
||||
|
||||
! Call C startup code to set up a proper environment to run main().
|
||||
push edx
|
||||
push ebx
|
||||
@@ -216,6 +232,7 @@ csinit:
|
||||
#define hwint_master(irq) \
|
||||
call save /* save interrupted process state */;\
|
||||
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
|
||||
LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\
|
||||
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
|
||||
pop ecx ;\
|
||||
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
|
||||
@@ -267,6 +284,7 @@ _hwint07: ! Interrupt routine for irq 7 (printer)
|
||||
#define hwint_slave(irq) \
|
||||
call save /* save interrupted process state */;\
|
||||
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
|
||||
LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\
|
||||
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
|
||||
pop ecx ;\
|
||||
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
|
||||
@@ -358,6 +376,7 @@ _p_s_call:
|
||||
o16 push es
|
||||
o16 push fs
|
||||
o16 push gs
|
||||
|
||||
mov si, ss ! ss is kernel data segment
|
||||
mov ds, si ! load rest of kernel segments
|
||||
mov es, si ! kernel does not use fs, gs
|
||||
@@ -371,6 +390,9 @@ _p_s_call:
|
||||
push ebx ! pointer to user message
|
||||
push eax ! source / destination
|
||||
push ecx ! call number (ipc primitive to use)
|
||||
|
||||
! LOADCR3WITHEAX(0x20, (_kernel_cr3))
|
||||
|
||||
call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map)
|
||||
! caller is now explicitly in proc_ptr
|
||||
mov AXREG(esi), eax ! sys_call MUST PRESERVE si
|
||||
@@ -391,6 +413,7 @@ _restart:
|
||||
mov (_next_ptr), 0
|
||||
0: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
|
||||
lldt P_LDT_SEL(esp) ! enable process' segment descriptors
|
||||
LOADCR3WITHEAX(0x21, P_CR3(esp)) ! switch to process page table
|
||||
lea eax, P_STACKTOP(esp) ! arrange for next interrupt
|
||||
mov (_tss+TSS3_S_SP0), eax ! to save state in process table
|
||||
restart1:
|
||||
@@ -464,6 +487,11 @@ _general_protection:
|
||||
|
||||
_page_fault:
|
||||
push PAGE_FAULT_VECTOR
|
||||
push eax
|
||||
mov eax, cr2
|
||||
sseg mov (_pagefault_cr2), eax
|
||||
sseg inc (_pagefault_count)
|
||||
pop eax
|
||||
jmp errexception
|
||||
|
||||
_copr_error:
|
||||
@@ -492,12 +520,16 @@ errexception:
|
||||
sseg pop (trap_errno)
|
||||
exception1: ! Common for all exceptions.
|
||||
push eax ! eax is scratch register
|
||||
|
||||
mov eax, 0+4(esp) ! old eip
|
||||
sseg mov (old_eip), eax
|
||||
movzx eax, 4+4(esp) ! old cs
|
||||
sseg mov (old_cs), eax
|
||||
mov eax, 8+4(esp) ! old eflags
|
||||
sseg mov (old_eflags), eax
|
||||
|
||||
LOADCR3WITHEAX(0x24, (_kernel_cr3))
|
||||
|
||||
pop eax
|
||||
call save
|
||||
push (old_eflags)
|
||||
@@ -517,6 +549,15 @@ _level0_call:
|
||||
call save
|
||||
jmp (_level0_func)
|
||||
|
||||
!*===========================================================================*
|
||||
!* load_kernel_cr3 *
|
||||
!*===========================================================================*
|
||||
.align 16
|
||||
_load_kernel_cr3:
|
||||
mov eax, (_kernel_cr3)
|
||||
mov cr3, eax
|
||||
ret
|
||||
|
||||
!*===========================================================================*
|
||||
!* data *
|
||||
!*===========================================================================*
|
||||
@@ -533,3 +574,4 @@ k_stktop: ! top of kernel stack
|
||||
.comm old_eip, 4
|
||||
.comm old_cs, 4
|
||||
.comm old_eflags, 4
|
||||
|
||||
|
||||
@@ -307,7 +307,10 @@ PUBLIC void alloc_segments(register struct proc *rp)
|
||||
code_bytes = data_bytes; /* common I&D, poor protect */
|
||||
else
|
||||
code_bytes = (phys_bytes) rp->p_memmap[T].mem_len << CLICK_SHIFT;
|
||||
privilege = (iskernelp(rp)) ? TASK_PRIVILEGE : USER_PRIVILEGE;
|
||||
if( (iskernelp(rp)))
|
||||
privilege = TASK_PRIVILEGE;
|
||||
else
|
||||
privilege = USER_PRIVILEGE;
|
||||
init_codeseg(&rp->p_seg.p_ldt[CS_LDT_INDEX],
|
||||
(phys_bytes) rp->p_memmap[T].mem_phys << CLICK_SHIFT,
|
||||
code_bytes, privilege);
|
||||
|
||||
@@ -44,10 +44,16 @@ _PROTOTYPE( void trp, (void) );
|
||||
_PROTOTYPE( void s_call, (void) ), _PROTOTYPE( p_s_call, (void) );
|
||||
_PROTOTYPE( void level0_call, (void) );
|
||||
|
||||
/* memory.c */
|
||||
_PROTOTYPE( void vir_insb, (u16_t port, struct proc *proc, u32_t vir, size_t count));
|
||||
_PROTOTYPE( void vir_outsb, (u16_t port, struct proc *proc, u32_t vir, size_t count));
|
||||
_PROTOTYPE( void vir_insw, (u16_t port, struct proc *proc, u32_t vir, size_t count));
|
||||
_PROTOTYPE( void vir_outsw, (u16_t port, struct proc *proc, u32_t vir, size_t count));
|
||||
|
||||
|
||||
/* exception.c */
|
||||
_PROTOTYPE( void exception, (unsigned vec_nr, u32_t trap_errno,
|
||||
u32_t old_eip, U16_t old_cs, u32_t old_eflags) );
|
||||
_PROTOTYPE( void stacktrace, (struct proc *proc) );
|
||||
|
||||
/* klib386.s */
|
||||
_PROTOTYPE( void level0, (void (*func)(void)) );
|
||||
@@ -62,6 +68,7 @@ _PROTOTYPE( void phys_insb, (U16_t port, phys_bytes buf, size_t count) );
|
||||
_PROTOTYPE( void phys_insw, (U16_t port, phys_bytes buf, size_t count) );
|
||||
_PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count) );
|
||||
_PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count) );
|
||||
_PROTOTYPE( void i386_invlpg, (U32_t addr) );
|
||||
|
||||
/* protect.c */
|
||||
_PROTOTYPE( void prot_init, (void) );
|
||||
|
||||
@@ -23,5 +23,6 @@ SPREG = PSWREG + W
|
||||
SSREG = SPREG + W
|
||||
P_STACKTOP = SSREG + W
|
||||
P_LDT_SEL = P_STACKTOP
|
||||
P_LDT = P_LDT_SEL + W
|
||||
P_CR3 = P_LDT_SEL + W
|
||||
P_LDT = P_CR3 + W
|
||||
Msize = 9 ! size of a message in 32-bit words
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
#include "../../kernel.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <ibm/cmos.h>
|
||||
#include <ibm/bios.h>
|
||||
#include <minix/portio.h>
|
||||
#include <minix/u64.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <a.out.h>
|
||||
|
||||
#include "proto.h"
|
||||
#include "../../proc.h"
|
||||
@@ -31,7 +35,39 @@ PUBLIC void arch_shutdown(int how)
|
||||
* the program if not already done.
|
||||
*/
|
||||
if (how != RBT_MONITOR)
|
||||
phys_copy(vir2phys(""), kinfo.params_base, 1);
|
||||
arch_set_params("", 1);
|
||||
if(minix_panicing) {
|
||||
int source, dest;
|
||||
static char mybuffer[sizeof(params_buffer)];
|
||||
char *lead = "echo \\n*** kernel messages:\\n";
|
||||
int leadlen = strlen(lead);
|
||||
strcpy(mybuffer, lead);
|
||||
|
||||
#define DECSOURCE source = (source - 1 + _KMESS_BUF_SIZE) % _KMESS_BUF_SIZE
|
||||
|
||||
dest = sizeof(mybuffer)-1;
|
||||
mybuffer[dest--] = '\0';
|
||||
|
||||
source = kmess.km_next;
|
||||
DECSOURCE;
|
||||
|
||||
while(dest >= leadlen) {
|
||||
char c = kmess.km_buf[source];
|
||||
if(c == '\n') {
|
||||
mybuffer[dest--] = 'n';
|
||||
mybuffer[dest] = '\\';
|
||||
} else if(isprint(c) &&
|
||||
c != '\'' && c != '"' &&
|
||||
c != '\\' && c != ';') {
|
||||
mybuffer[dest] = c;
|
||||
} else mybuffer[dest] = '|';
|
||||
|
||||
DECSOURCE;
|
||||
dest--;
|
||||
}
|
||||
|
||||
arch_set_params(mybuffer, strlen(mybuffer)+1);
|
||||
}
|
||||
level0(monitor);
|
||||
} else {
|
||||
/* Reset the system by forcing a processor shutdown. First stop
|
||||
@@ -44,6 +80,17 @@ PUBLIC void arch_shutdown(int how)
|
||||
}
|
||||
}
|
||||
|
||||
/* address of a.out headers, set in mpx386.s */
|
||||
phys_bytes aout;
|
||||
|
||||
PUBLIC void arch_get_aout_headers(int i, struct exec *h)
|
||||
{
|
||||
/* The bootstrap loader created an array of the a.out headers at
|
||||
* absolute address 'aout'. Get one element to h.
|
||||
*/
|
||||
phys_copy(aout + i * A_MINHDR, vir2phys(h), (phys_bytes) A_MINHDR);
|
||||
}
|
||||
|
||||
PUBLIC void system_init(void)
|
||||
{
|
||||
prot_init();
|
||||
@@ -122,7 +169,7 @@ PUBLIC void ser_dump_proc()
|
||||
pp->p_priority, pp->p_max_priority,
|
||||
pp->p_user_time, pp->p_sys_time,
|
||||
pp->p_reg.pc);
|
||||
stacktrace(pp);
|
||||
proc_stacktrace(pp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,3 +266,23 @@ PUBLIC void cons_seth(int pos, int n)
|
||||
else
|
||||
cons_setc(pos, 'A'+(n-10));
|
||||
}
|
||||
|
||||
/* Saved by mpx386.s into these variables. */
|
||||
u32_t params_size, params_offset, mon_ds;
|
||||
|
||||
PUBLIC int arch_get_params(char *params, int maxsize)
|
||||
{
|
||||
phys_copy(seg2phys(mon_ds) + params_offset, vir2phys(params),
|
||||
MIN(maxsize, params_size));
|
||||
params[maxsize-1] = '\0';
|
||||
return OK;
|
||||
}
|
||||
|
||||
PUBLIC int arch_set_params(char *params, int size)
|
||||
{
|
||||
if(size > params_size)
|
||||
return E2BIG;
|
||||
phys_copy(vir2phys(params), seg2phys(mon_ds) + params_offset, size);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
27
kernel/arch/i386/vm.h
Normal file
27
kernel/arch/i386/vm.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
.define _load_kernel_cr3
|
||||
.define _last_cr3
|
||||
|
||||
#define LOADKERNELCR3 ;\
|
||||
inc (_cr3switch) ;\
|
||||
mov eax, (_kernel_cr3) ;\
|
||||
cmp (_last_cr3), eax ;\
|
||||
jz 9f ;\
|
||||
push _load_kernel_cr3 ;\
|
||||
call _level0 ;\
|
||||
pop eax ;\
|
||||
mov eax, (_kernel_cr3) ;\
|
||||
mov (_last_cr3), eax ;\
|
||||
inc (_cr3reload) ;\
|
||||
9:
|
||||
|
||||
#define LOADCR3WITHEAX(type, newcr3) ;\
|
||||
sseg inc (_cr3switch) ;\
|
||||
sseg mov eax, newcr3 ;\
|
||||
sseg cmp (_last_cr3), eax ;\
|
||||
jz 8f ;\
|
||||
mov cr3, eax ;\
|
||||
sseg inc (_cr3reload) ;\
|
||||
sseg mov (_last_cr3), eax ;\
|
||||
8:
|
||||
|
||||
Reference in New Issue
Block a user