copy of beng's working copy

This commit is contained in:
Ben Gras
2009-05-20 16:54:58 +00:00
parent 00a2463d71
commit 6579bb3656
13 changed files with 363 additions and 66 deletions

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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"