change messy CREATEPDE macro to clean little function.
forget about the dirtypde bitmap and WIPEPDE/DONEPDE macros too. check if mapping happens to already be in place, and if so, don't reload cr3 (on the account of that mapping, that is). don't reload cr3 unconditionally.
This commit is contained in:
parent
c3e73f0793
commit
f250bfaa13
3 changed files with 85 additions and 113 deletions
|
@ -839,6 +839,5 @@ switch_address_space:
|
||||||
je 0f
|
je 0f
|
||||||
mov %eax, %cr3
|
mov %eax, %cr3
|
||||||
mov %edx, ptproc
|
mov %edx, ptproc
|
||||||
movl $0, dirtypde
|
|
||||||
0:
|
0:
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -33,11 +33,8 @@ PRIVATE int psok = 0;
|
||||||
|
|
||||||
PUBLIC u8_t *vm_pagedirs = NULL;
|
PUBLIC u8_t *vm_pagedirs = NULL;
|
||||||
|
|
||||||
#define NOPDE (-1)
|
#define MAX_FREEPDES 3
|
||||||
#define PDEMASK(n) (1L << (n))
|
PRIVATE int nfreepdes = 0, freepdes[MAX_FREEPDES];
|
||||||
PUBLIC u32_t dirtypde; /* Accessed from assembly code. */
|
|
||||||
#define WANT_FREEPDES (sizeof(dirtypde)*8-5)
|
|
||||||
PRIVATE int nfreepdes = 0, freepdes[WANT_FREEPDES], inusepde = NOPDE;
|
|
||||||
|
|
||||||
#define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0)
|
#define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0)
|
||||||
|
|
||||||
|
@ -58,96 +55,84 @@ PUBLIC void vm_init(struct proc *newptproc)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TYPEDIRECT 0
|
/* This function sets up a mapping from within the kernel's address
|
||||||
#define TYPEPROCMAP 1
|
|
||||||
#define TYPEPHYS 2
|
|
||||||
|
|
||||||
/* This macro sets up a mapping from within the kernel's address
|
|
||||||
* space to any other area of memory, either straight physical
|
* space to any other area of memory, either straight physical
|
||||||
* memory (PROC == NULL) or a process view of memory, in 4MB chunks.
|
* memory (pr == NULL) or a process view of memory, in 4MB windows.
|
||||||
* It recognizes PROC having kernel address space as a special case.
|
* I.e., it maps in 4MB chunks of virtual (or physical) address space
|
||||||
|
* to 4MB chunks of kernel virtual address space.
|
||||||
*
|
*
|
||||||
* It sets PTR to the pointer within kernel address space at the start
|
* It recognizes pr already being in memory as a special case (no
|
||||||
* of the 4MB chunk, and OFFSET to the offset within that chunk
|
* mapping required).
|
||||||
* that corresponds to LINADDR.
|
|
||||||
*
|
*
|
||||||
* It needs FREEPDE (available and addressable PDE within kernel
|
* The target (i.e. in-kernel) mapping area is one of the freepdes[]
|
||||||
* address space), SEG (hardware segment), VIRT (in-datasegment
|
* VM has earlier already told the kernel about that is available. It is
|
||||||
* address if known).
|
* identified as the 'pde' parameter. This value can be chosen freely
|
||||||
|
* by the caller, as long as it is in range (i.e. 0 or higher and corresonds
|
||||||
|
* to a known freepde slot). It is up to the caller to keep track of which
|
||||||
|
* freepde's are in use, and to determine which ones are free to use.
|
||||||
|
*
|
||||||
|
* The logical number supplied by the caller is translated into an actual
|
||||||
|
* pde number to be used, and a pointer to it (linear address) is returned
|
||||||
|
* for actual use by phys_copy or phys_memset.
|
||||||
*/
|
*/
|
||||||
#define CREATEPDE(PROC, PTR, LINADDR, REMAIN, BYTES, PDE, TYPE) { \
|
PRIVATE phys_bytes createpde(
|
||||||
u32_t *pdeptr = NULL; \
|
struct proc *pr, /* Requested process, NULL for physical. */
|
||||||
int proc_pde_index; \
|
phys_bytes linaddr, /* Address after segment translation. */
|
||||||
proc_pde_index = I386_VM_PDE(LINADDR); \
|
phys_bytes *bytes, /* Size of chunk, function may truncate it. */
|
||||||
PDE = NOPDE; \
|
int pde, /* freepde number to use for the mapping. */
|
||||||
if((PROC) && (((PROC) == ptproc) || !HASPT(PROC))) { \
|
int *changed /* If mapping is made, this is set to 1. */
|
||||||
PTR = LINADDR; \
|
)
|
||||||
TYPE = TYPEDIRECT; \
|
{
|
||||||
} else { \
|
u32_t pdeval;
|
||||||
int fp; \
|
phys_bytes offset;
|
||||||
int mustinvl; \
|
|
||||||
u32_t pdeval, mask; \
|
|
||||||
phys_bytes offset; \
|
|
||||||
assert(psok); \
|
|
||||||
if(PROC) { \
|
|
||||||
TYPE = TYPEPROCMAP; \
|
|
||||||
assert(!iskernelp(PROC)); \
|
|
||||||
assert(HASPT(PROC)); \
|
|
||||||
pdeptr = PROCPDEPTR(PROC, proc_pde_index); \
|
|
||||||
pdeval = *pdeptr; \
|
|
||||||
} else { \
|
|
||||||
TYPE = TYPEPHYS; \
|
|
||||||
pdeval = (LINADDR & I386_VM_ADDR_MASK_4MB) | \
|
|
||||||
I386_VM_BIGPAGE | I386_VM_PRESENT | \
|
|
||||||
I386_VM_WRITE | I386_VM_USER; \
|
|
||||||
} \
|
|
||||||
for(fp = 0; fp < nfreepdes; fp++) { \
|
|
||||||
int k = freepdes[fp]; \
|
|
||||||
if(inusepde == k) \
|
|
||||||
continue; \
|
|
||||||
*PROCPDEPTR(ptproc, k) = 0; \
|
|
||||||
PDE = k; \
|
|
||||||
assert(k >= 0); \
|
|
||||||
assert(k < sizeof(dirtypde)*8); \
|
|
||||||
mask = PDEMASK(PDE); \
|
|
||||||
if(dirtypde & mask) \
|
|
||||||
continue; \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
assert(PDE != NOPDE); \
|
|
||||||
assert(mask); \
|
|
||||||
if(dirtypde & mask) { \
|
|
||||||
mustinvl = TRUE; \
|
|
||||||
} else { \
|
|
||||||
mustinvl = FALSE; \
|
|
||||||
} \
|
|
||||||
inusepde = PDE; \
|
|
||||||
*PROCPDEPTR(ptproc, PDE) = pdeval; \
|
|
||||||
offset = LINADDR & I386_VM_OFFSET_MASK_4MB; \
|
|
||||||
PTR = I386_BIG_PAGE_SIZE*PDE + offset; \
|
|
||||||
REMAIN = MIN(REMAIN, I386_BIG_PAGE_SIZE - offset); \
|
|
||||||
if(1 || mustinvl) { \
|
|
||||||
reload_cr3(); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DONEPDE(PDE) { \
|
assert(pde >= 0 && pde < nfreepdes);
|
||||||
if(PDE != NOPDE) { \
|
pde = freepdes[pde];
|
||||||
assert(PDE > 0); \
|
|
||||||
assert(PDE < sizeof(dirtypde)*8); \
|
|
||||||
dirtypde |= PDEMASK(PDE); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define WIPEPDE(PDE) { \
|
if(pr && ((pr == ptproc) || !HASPT(pr))) {
|
||||||
if(PDE != NOPDE) { \
|
/* Process memory is requested, and
|
||||||
assert(PDE > 0); \
|
* it's a process that is already in current page table, or
|
||||||
assert(PDE < sizeof(dirtypde)*8); \
|
* a process that is in every page table.
|
||||||
*PROCPDEPTR(ptproc, PDE) = 0; \
|
* Therefore linaddr is valid directly, with the requested
|
||||||
} \
|
* size.
|
||||||
}
|
*/
|
||||||
|
return linaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pr) {
|
||||||
|
/* Requested address is in a process that is not currently
|
||||||
|
* accessible directly. Grab the PDE entry of that process'
|
||||||
|
* page table that corresponds to the requested address.
|
||||||
|
*/
|
||||||
|
pdeval = *PROCPDEPTR(pr, I386_VM_PDE(linaddr));
|
||||||
|
} else {
|
||||||
|
/* Requested address is physical. Make up the PDE entry. */
|
||||||
|
pdeval = (linaddr & I386_VM_ADDR_MASK_4MB) |
|
||||||
|
I386_VM_BIGPAGE | I386_VM_PRESENT |
|
||||||
|
I386_VM_WRITE | I386_VM_USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the pde value that we need into a pde that the kernel
|
||||||
|
* can access, into the currently loaded page table so it becomes
|
||||||
|
* visible.
|
||||||
|
*/
|
||||||
|
if(*PROCPDEPTR(ptproc, pde) != pdeval) {
|
||||||
|
*PROCPDEPTR(ptproc, pde) = pdeval;
|
||||||
|
*changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Memory is now available, but only the 4MB window of virtual
|
||||||
|
* address space that we have mapped; calculate how much of
|
||||||
|
* the requested range is visible and return that in *bytes,
|
||||||
|
* if that is less than the requested range.
|
||||||
|
*/
|
||||||
|
offset = linaddr & I386_VM_OFFSET_MASK_4MB; /* Offset in 4MB window. */
|
||||||
|
*bytes = MIN(*bytes, I386_BIG_PAGE_SIZE - offset);
|
||||||
|
|
||||||
|
/* Return the linear address of the start of the new mapping. */
|
||||||
|
return I386_BIG_PAGE_SIZE*pde + offset;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* lin_lin_copy *
|
* lin_lin_copy *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -173,31 +158,24 @@ PRIVATE int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
|
||||||
while(bytes > 0) {
|
while(bytes > 0) {
|
||||||
phys_bytes srcptr, dstptr;
|
phys_bytes srcptr, dstptr;
|
||||||
vir_bytes chunk = bytes;
|
vir_bytes chunk = bytes;
|
||||||
int srcpde, dstpde;
|
int changed = 0;
|
||||||
int srctype, dsttype;
|
|
||||||
|
|
||||||
/* Set up 4MB ranges. */
|
/* Set up 4MB ranges. */
|
||||||
inusepde = NOPDE;
|
srcptr = createpde(srcproc, srclinaddr, &chunk, 0, &changed);
|
||||||
CREATEPDE(srcproc, srcptr, srclinaddr, chunk, bytes, srcpde, srctype);
|
dstptr = createpde(dstproc, dstlinaddr, &chunk, 1, &changed);
|
||||||
CREATEPDE(dstproc, dstptr, dstlinaddr, chunk, bytes, dstpde, dsttype);
|
if(changed)
|
||||||
|
reload_cr3();
|
||||||
|
|
||||||
/* Copy pages. */
|
/* Copy pages. */
|
||||||
PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr);
|
PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr);
|
||||||
|
|
||||||
DONEPDE(srcpde);
|
|
||||||
DONEPDE(dstpde);
|
|
||||||
|
|
||||||
if(addr) {
|
if(addr) {
|
||||||
/* If addr is nonzero, a page fault was caught. */
|
/* If addr is nonzero, a page fault was caught. */
|
||||||
|
|
||||||
if(addr >= srcptr && addr < (srcptr + chunk)) {
|
if(addr >= srcptr && addr < (srcptr + chunk)) {
|
||||||
WIPEPDE(srcpde);
|
|
||||||
WIPEPDE(dstpde);
|
|
||||||
NOREC_RETURN(linlincopy, EFAULT_SRC);
|
NOREC_RETURN(linlincopy, EFAULT_SRC);
|
||||||
}
|
}
|
||||||
if(addr >= dstptr && addr < (dstptr + chunk)) {
|
if(addr >= dstptr && addr < (dstptr + chunk)) {
|
||||||
WIPEPDE(srcpde);
|
|
||||||
WIPEPDE(dstpde);
|
|
||||||
NOREC_RETURN(linlincopy, EFAULT_DST);
|
NOREC_RETURN(linlincopy, EFAULT_DST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +185,6 @@ PRIVATE int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
|
||||||
NOREC_RETURN(linlincopy, EFAULT);
|
NOREC_RETURN(linlincopy, EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
WIPEPDE(srcpde);
|
|
||||||
WIPEPDE(dstpde);
|
|
||||||
|
|
||||||
/* Update counter and addresses for next iteration, if any. */
|
/* Update counter and addresses for next iteration, if any. */
|
||||||
bytes -= chunk;
|
bytes -= chunk;
|
||||||
srclinaddr += chunk;
|
srclinaddr += chunk;
|
||||||
|
@ -708,16 +683,16 @@ int vm_phys_memset(phys_bytes ph, u8_t c, phys_bytes bytes)
|
||||||
* We can do this 4MB at a time.
|
* We can do this 4MB at a time.
|
||||||
*/
|
*/
|
||||||
while(bytes > 0) {
|
while(bytes > 0) {
|
||||||
int pde, t;
|
int changed = 0;
|
||||||
vir_bytes chunk = (vir_bytes) bytes;
|
phys_bytes chunk = bytes, ptr;
|
||||||
phys_bytes ptr;
|
ptr = createpde(NULL, ph, &chunk, 0, &changed);
|
||||||
inusepde = NOPDE;
|
if(changed)
|
||||||
CREATEPDE(((struct proc *) NULL), ptr, ph, chunk, bytes, pde, t);
|
reload_cr3();
|
||||||
|
|
||||||
/* We can memset as many bytes as we have remaining,
|
/* We can memset as many bytes as we have remaining,
|
||||||
* or as many as remain in the 4MB chunk we mapped in.
|
* or as many as remain in the 4MB chunk we mapped in.
|
||||||
*/
|
*/
|
||||||
phys_memset(ptr, p, chunk);
|
phys_memset(ptr, p, chunk);
|
||||||
DONEPDE(pde);
|
|
||||||
bytes -= chunk;
|
bytes -= chunk;
|
||||||
ph += chunk;
|
ph += chunk;
|
||||||
}
|
}
|
||||||
|
@ -948,7 +923,7 @@ PUBLIC int arch_umap(struct proc *pr, vir_bytes offset, vir_bytes count,
|
||||||
/* VM reports page directory slot we're allowed to use freely. */
|
/* VM reports page directory slot we're allowed to use freely. */
|
||||||
void i386_freepde(int pde)
|
void i386_freepde(int pde)
|
||||||
{
|
{
|
||||||
if(nfreepdes >= WANT_FREEPDES)
|
if(nfreepdes >= MAX_FREEPDES)
|
||||||
return;
|
return;
|
||||||
freepdes[nfreepdes++] = pde;
|
freepdes[nfreepdes++] = pde;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,6 @@ begbss:
|
||||||
.globl params_offset
|
.globl params_offset
|
||||||
.globl mon_ds
|
.globl mon_ds
|
||||||
.globl schedcheck
|
.globl schedcheck
|
||||||
.globl dirtypde
|
|
||||||
.globl lazy_fpu
|
.globl lazy_fpu
|
||||||
|
|
||||||
.globl hwint00 /* handlers for hardware interrupts */
|
.globl hwint00 /* handlers for hardware interrupts */
|
||||||
|
@ -736,7 +735,6 @@ no_fpu_available:
|
||||||
reload_cr3:
|
reload_cr3:
|
||||||
push %ebp
|
push %ebp
|
||||||
mov %esp, %ebp
|
mov %esp, %ebp
|
||||||
movl $0, dirtypde
|
|
||||||
mov %cr3, %eax
|
mov %cr3, %eax
|
||||||
mov %eax, %cr3
|
mov %eax, %cr3
|
||||||
pop %ebp
|
pop %ebp
|
||||||
|
|
Loading…
Reference in a new issue