copy of beng's working copy
This commit is contained in:
@@ -10,7 +10,10 @@
|
||||
#include "../../system.h"
|
||||
#include <minix/type.h>
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
extern u32_t kernel_cr3;
|
||||
extern u32_t *vm_pagedirs;
|
||||
|
||||
/*===========================================================================*
|
||||
* arch_do_vmctl *
|
||||
@@ -19,6 +22,10 @@ PUBLIC int arch_do_vmctl(m_ptr, p)
|
||||
register message *m_ptr; /* pointer to request message */
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
static int vmpde = -1;
|
||||
static u32_t pdeval = -1;
|
||||
|
||||
switch(m_ptr->SVMCTL_PARAM) {
|
||||
case VMCTL_I386_GETCR3:
|
||||
/* Get process CR3. */
|
||||
@@ -53,6 +60,41 @@ struct proc *p;
|
||||
m_ptr->SVMCTL_PF_I386_ERR = rp->p_pagefault.pf_flags;
|
||||
return OK;
|
||||
}
|
||||
case VMCTL_I386_KERNELLIMIT:
|
||||
{
|
||||
/* VM wants kernel to increase its segment. */
|
||||
kprintf("kernel: increase limit to 0x%x\n",
|
||||
m_ptr->SVMCTL_VALUE);
|
||||
return prot_set_kern_seg_limit(m_ptr->SVMCTL_VALUE);
|
||||
}
|
||||
case VMCTL_I386_PAGEDIRS:
|
||||
{
|
||||
int pde;
|
||||
vm_pagedirs = (u32_t *) m_ptr->SVMCTL_VALUE;
|
||||
kprintf("kernel: pagedirs now 0x%lx\n", vm_pagedirs);
|
||||
return OK;
|
||||
}
|
||||
case VMCTL_I386_PDE:
|
||||
{
|
||||
vmpde = m_ptr->SVMCTL_VALUE;
|
||||
kprintf("kernel: HACK: vmpde %d\n", vmpde);
|
||||
return OK;
|
||||
}
|
||||
case VMCTL_I386_PDEVAL:
|
||||
{
|
||||
pdeval = m_ptr->SVMCTL_VALUE;
|
||||
kprintf("kernel: HACK: vmpde %d, set val 0x%x\n",
|
||||
vmpde, pdeval);
|
||||
i386_updatepde(vmpde, pdeval);
|
||||
kprintf("kernel: HACK: vmpde %d, set val 0x%x done\n",
|
||||
vmpde, pdeval);
|
||||
return OK;
|
||||
}
|
||||
case VMCTL_I386_FREEPDE:
|
||||
{
|
||||
i386_freepde(m_ptr->SVMCTL_VALUE);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
kprintf("arch_do_vmctl: strange param %d\n", m_ptr->SVMCTL_PARAM);
|
||||
|
||||
@@ -136,5 +136,6 @@
|
||||
#define IOPL_MASK 0x003000
|
||||
|
||||
#define vir2phys(vir) (kinfo.data_base + (vir_bytes) (vir))
|
||||
#define phys2vir(ph) ((vir_bytes) (ph) - kinfo.data_base)
|
||||
|
||||
#endif /* _I386_ACONST_H */
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
.define _write_cr0 ! write a value in cr0
|
||||
.define _read_cr4
|
||||
.define _write_cr4
|
||||
.define _i386_invlpg_addr
|
||||
.define _i386_invlpg_level0
|
||||
|
||||
.define _kernel_cr3
|
||||
|
||||
@@ -644,3 +646,15 @@ _write_cr3:
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
!*===========================================================================*
|
||||
!* i386_invlpg *
|
||||
!*===========================================================================*
|
||||
! PUBLIC void i386_invlpg(void);
|
||||
_i386_invlpg_level0:
|
||||
push ebp
|
||||
invlpg (_i386_invlpg_addr)
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,13 @@ PUBLIC u32_t kernel_cr3;
|
||||
extern u32_t cswitch;
|
||||
u32_t last_cr3 = 0;
|
||||
|
||||
u32_t *vm_pagedirs = NULL;
|
||||
|
||||
u32_t i386_invlpg_addr = 0;
|
||||
|
||||
#define WANT_FREEPDES 4
|
||||
PRIVATE int nfreepdes = 0, freepdes[WANT_FREEPDES];
|
||||
|
||||
#define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0)
|
||||
|
||||
FORWARD _PROTOTYPE( void phys_put32, (phys_bytes addr, u32_t value) );
|
||||
@@ -693,6 +700,92 @@ void vm_print(u32_t *root)
|
||||
return;
|
||||
}
|
||||
|
||||
void invlpg_range(u32_t lin, u32_t bytes)
|
||||
{
|
||||
u32_t o;
|
||||
o = lin % I386_PAGE_SIZE;
|
||||
lin -= o;
|
||||
bytes += o;
|
||||
while(bytes >= I386_PAGE_SIZE) {
|
||||
i386_invlpg_addr = lin;
|
||||
level0(i386_invlpg_level0);
|
||||
lin += I386_PAGE_SIZE;
|
||||
bytes -= I386_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* lin_lin_copy *
|
||||
*===========================================================================*/
|
||||
int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, u8_t *vsrc,
|
||||
struct proc *dstproc, vir_bytes dstlinaddr, u8_t *vdst,
|
||||
vir_bytes bytes)
|
||||
{
|
||||
|
||||
if(nfreepdes < 2)
|
||||
minix_panic("vm: not enough free PDE's", NO_NUM);
|
||||
|
||||
util_stacktrace();
|
||||
|
||||
#define CREATEPDE(PROC, PTR, LINADDR, OFFSET, FREEPDE, VIRT) { \
|
||||
if(iskernelp(PROC)) { \
|
||||
PTR = VIRT; \
|
||||
OFFSET = 0; \
|
||||
} else { \
|
||||
u32_t *pdevalptr; \
|
||||
u32_t myphysaddr; \
|
||||
int pde_index; \
|
||||
pde_index = I386_VM_PDE(LINADDR); \
|
||||
pdevalptr = (u32_t *) ((u8_t *) vm_pagedirs + \
|
||||
I386_PAGE_SIZE * PROC->p_nr + \
|
||||
I386_VM_PT_ENT_SIZE * pde_index); \
|
||||
kprintf("pagedirs: 0x%x p_nr: %d linaddr: 0x%x pde: %d\n", \
|
||||
vm_pagedirs, PROC->p_nr, LINADDR, pde_index); \
|
||||
kprintf("pde ptr: 0x%x\n", pdevalptr); \
|
||||
kprintf("value: 0x%x\n", *pdevalptr); \
|
||||
myphysaddr = kernel_cr3 + FREEPDE*I386_VM_PT_ENT_SIZE; \
|
||||
phys_put32(myphysaddr, *pdevalptr); \
|
||||
PTR = (u8_t *) phys2vir(I386_BIG_PAGE_SIZE*FREEPDE); \
|
||||
kprintf("ptr: 0x%x\n", PTR); \
|
||||
OFFSET = LINADDR & I386_VM_OFFSET_MASK_4MB; \
|
||||
kprintf("offset: 0x%lx & 0x%lx -> 0x%lx\n", LINADDR, \
|
||||
I386_VM_OFFSET_MASK_4MB, OFFSET); \
|
||||
invlpg_range(LINADDR, bytes + I386_PAGE_SIZE); \
|
||||
} \
|
||||
}
|
||||
|
||||
while(bytes > 0) {
|
||||
u8_t *srcptr, *dstptr;
|
||||
vir_bytes srcoffset, dstoffset, chunk, remain;
|
||||
|
||||
/* Set up 4MB ranges. */
|
||||
CREATEPDE(srcproc, srcptr, srclinaddr, srcoffset, freepdes[0], vsrc);
|
||||
CREATEPDE(dstproc, dstptr, dstlinaddr, dstoffset, freepdes[1], vdst);
|
||||
|
||||
remain = I386_BIG_PAGE_SIZE - MAX(srcoffset, dstoffset);
|
||||
chunk = MIN(bytes, remain);
|
||||
|
||||
/* Copy pages. */
|
||||
while(chunk > 0) {
|
||||
kprintf("copy %d -> %d %d/%d using 0x%lx+0x%lx -> 0x%lx+0x%lx\n",
|
||||
srcproc->p_endpoint, dstproc->p_endpoint,
|
||||
chunk, bytes, srcptr, srcoffset,
|
||||
dstptr, dstoffset);
|
||||
memcpy(dstptr + dstoffset, srcptr + srcoffset, chunk);
|
||||
kprintf("done\n");
|
||||
}
|
||||
|
||||
/* Update counter and addresses for next iteration, if any. */
|
||||
bytes -= chunk;
|
||||
srclinaddr += chunk;
|
||||
dstlinaddr += chunk;
|
||||
vsrc += chunk;
|
||||
vdst += chunk;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* virtual_copy_f *
|
||||
*===========================================================================*/
|
||||
@@ -778,6 +871,17 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Special case: vir to vir copy */
|
||||
if(vm_pagedirs && procs[_SRC_] && procs[_DST_] &&
|
||||
HASPT(procs[_SRC_]) && HASPT(procs[_DST_]) &&
|
||||
src_addr->segment == D && src_addr->segment == D) {
|
||||
lin_lin_copy(procs[_SRC_], phys_addr[_SRC_], (u8_t *) src_addr->offset,
|
||||
procs[_DST_], phys_addr[_DST_], (u8_t *) dst_addr->offset,
|
||||
bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(vmcheck && procs[_SRC_])
|
||||
CHECKRANGE_OR_SUSPEND(procs[_SRC_], phys_addr[_SRC_], bytes, 0);
|
||||
if(vmcheck && procs[_DST_])
|
||||
@@ -852,4 +956,21 @@ PUBLIC int arch_umap(struct proc *pr, vir_bytes offset, vir_bytes count,
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
void i386_updatepde(int pde, u32_t val)
|
||||
{
|
||||
u32_t physaddr;
|
||||
physaddr = kernel_cr3 + pde*I386_VM_PT_ENT_SIZE;
|
||||
kprintf("kernel: i386_updatepde: cr3 0x%lx; phys addr 0x%lx; pde %d, val 0x%lx\n",
|
||||
kernel_cr3, physaddr, pde, val);
|
||||
kprintf("previous entry was: 0x%lx\n", phys_get32(physaddr));
|
||||
phys_put32(physaddr, val);
|
||||
kprintf("entry is now: 0x%lx\n", phys_get32(physaddr));
|
||||
}
|
||||
|
||||
void i386_freepde(int pde)
|
||||
{
|
||||
if(nfreepdes >= WANT_FREEPDES)
|
||||
return;
|
||||
freepdes[nfreepdes++] = pde;
|
||||
printf("kernel: free pde: %d\n", pde);
|
||||
}
|
||||
|
||||
@@ -189,6 +189,11 @@ PUBLIC void prot_init(void)
|
||||
{ level0_call, LEVEL0_VECTOR, TASK_PRIVILEGE },
|
||||
};
|
||||
|
||||
/* Click-round kernel. */
|
||||
if(kinfo.data_base % CLICK_SIZE)
|
||||
minix_panic("kinfo.data_base not aligned", NO_NUM);
|
||||
kinfo.data_size = ((kinfo.data_size+CLICK_SIZE-1)/CLICK_SIZE) * CLICK_SIZE;
|
||||
|
||||
/* Build gdt and idt pointers in GDT where the BIOS expects them. */
|
||||
dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
|
||||
* (u16_t *) dtp->limit = (sizeof gdt) - 1;
|
||||
@@ -325,3 +330,51 @@ PUBLIC void alloc_segments(register struct proc *rp)
|
||||
rp->p_reg.ds = (DS_LDT_INDEX*DESC_SIZE) | TI | privilege;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* prot_set_kern_seg_limit *
|
||||
*===========================================================================*/
|
||||
PUBLIC int prot_set_kern_seg_limit(vir_bytes limit)
|
||||
{
|
||||
struct proc *rp;
|
||||
vir_bytes prev;
|
||||
int orig_click;
|
||||
int incr_clicks;
|
||||
|
||||
kprintf("prot_set_kern_seg_limit: limit 0x%lx\n", limit);
|
||||
|
||||
if(limit <= kinfo.data_base) {
|
||||
kprintf("prot_set_kern_seg_limit: limit bogus\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
kprintf("size: 0x%lx -> ", kinfo.data_size);
|
||||
|
||||
/* Do actual increase. */
|
||||
orig_click = kinfo.data_size / CLICK_SIZE;
|
||||
kinfo.data_size = limit - kinfo.data_base;
|
||||
incr_clicks = kinfo.data_size / CLICK_SIZE - orig_click;
|
||||
|
||||
kprintf("0x%lx\n", kinfo.data_size);
|
||||
|
||||
kprintf("prot_set_kern_seg_limit: prot_init\n");
|
||||
|
||||
prot_init();
|
||||
|
||||
kprintf("prot_set_kern_seg_limit: prot_init done\n");
|
||||
|
||||
/* Increase kernel processes too. */
|
||||
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; ++rp) {
|
||||
if (RTS_ISSET(rp, SLOT_FREE) || !iskernelp(rp))
|
||||
continue;
|
||||
kprintf("prot_set_kern_seg_limit: increase %d 0x%x ->\n",
|
||||
rp->p_endpoint, rp->p_memmap[S].mem_len);
|
||||
rp->p_memmap[S].mem_len += incr_clicks;
|
||||
alloc_segments(rp);
|
||||
kprintf("prot_set_kern_seg_limit: increase %d done -> 0x%x\n",
|
||||
rp->p_endpoint, rp->p_memmap[S].mem_len);
|
||||
}
|
||||
kprintf("prot_set_kern_seg_limit: done\n");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ _PROTOTYPE( void vir_insb, (u16_t port, struct proc *proc, u32_t vir, size_t cou
|
||||
_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));
|
||||
_PROTOTYPE( void i386_updatepde, (int pde, u32_t val));
|
||||
_PROTOTYPE( void i386_freepde, (int pde));
|
||||
|
||||
|
||||
/* exception.c */
|
||||
@@ -70,7 +72,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) );
|
||||
_PROTOTYPE( void i386_invlpg_level0, (void) );
|
||||
|
||||
/* protect.c */
|
||||
_PROTOTYPE( void prot_init, (void) );
|
||||
@@ -79,6 +81,7 @@ _PROTOTYPE( void init_codeseg, (struct segdesc_s *segdp, phys_bytes base,
|
||||
_PROTOTYPE( void init_dataseg, (struct segdesc_s *segdp, phys_bytes base,
|
||||
vir_bytes size, int privilege) );
|
||||
_PROTOTYPE( void enable_iop, (struct proc *pp) );
|
||||
_PROTOTYPE( int prot_set_kern_seg_limit, (vir_bytes limit) );
|
||||
|
||||
/* functions defined in architecture-independent kernel source. */
|
||||
#include "../../proto.h"
|
||||
|
||||
Reference in New Issue
Block a user