From f250bfaa13e97c82bb6d118dd8b9aad42576f371 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 18 Mar 2010 13:35:41 +0000 Subject: [PATCH] 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. --- kernel/arch/i386/klib386.S | 1 - kernel/arch/i386/memory.c | 195 ++++++++++++++++++++------------------------- kernel/arch/i386/mpx386.S | 2 - 3 files changed, 85 insertions(+), 113 deletions(-) diff --git a/kernel/arch/i386/klib386.S b/kernel/arch/i386/klib386.S index cbfb932b4..d1bb9c1aa 100644 --- a/kernel/arch/i386/klib386.S +++ b/kernel/arch/i386/klib386.S @@ -839,6 +839,5 @@ switch_address_space: je 0f mov %eax, %cr3 mov %edx, ptproc - movl $0, dirtypde 0: ret diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 2da9f1732..5cfb7e053 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -33,11 +33,8 @@ PRIVATE int psok = 0; PUBLIC u8_t *vm_pagedirs = NULL; -#define NOPDE (-1) -#define PDEMASK(n) (1L << (n)) -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 MAX_FREEPDES 3 +PRIVATE int nfreepdes = 0, freepdes[MAX_FREEPDES]; #define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0) @@ -58,96 +55,84 @@ PUBLIC void vm_init(struct proc *newptproc) } -#define TYPEDIRECT 0 -#define TYPEPROCMAP 1 -#define TYPEPHYS 2 - -/* This macro sets up a mapping from within the kernel's address +/* This function sets up a mapping from within the kernel's address * space to any other area of memory, either straight physical - * memory (PROC == NULL) or a process view of memory, in 4MB chunks. - * It recognizes PROC having kernel address space as a special case. + * memory (pr == NULL) or a process view of memory, in 4MB windows. + * I.e., it maps in 4MB chunks of virtual (or physical) address space + * to 4MB chunks of kernel virtual address space. + * + * It recognizes pr already being in memory as a special case (no + * mapping required). * - * It sets PTR to the pointer within kernel address space at the start - * of the 4MB chunk, and OFFSET to the offset within that chunk - * that corresponds to LINADDR. + * The target (i.e. in-kernel) mapping area is one of the freepdes[] + * VM has earlier already told the kernel about that is available. It is + * 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. * - * It needs FREEPDE (available and addressable PDE within kernel - * address space), SEG (hardware segment), VIRT (in-datasegment - * address if known). + * 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) { \ - u32_t *pdeptr = NULL; \ - int proc_pde_index; \ - proc_pde_index = I386_VM_PDE(LINADDR); \ - PDE = NOPDE; \ - if((PROC) && (((PROC) == ptproc) || !HASPT(PROC))) { \ - PTR = LINADDR; \ - TYPE = TYPEDIRECT; \ - } else { \ - int fp; \ - 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(); \ - } \ - } \ -} +PRIVATE phys_bytes createpde( + struct proc *pr, /* Requested process, NULL for physical. */ + phys_bytes linaddr, /* Address after segment translation. */ + phys_bytes *bytes, /* Size of chunk, function may truncate it. */ + int pde, /* freepde number to use for the mapping. */ + int *changed /* If mapping is made, this is set to 1. */ + ) +{ + u32_t pdeval; + phys_bytes offset; + + assert(pde >= 0 && pde < nfreepdes); + pde = freepdes[pde]; + + if(pr && ((pr == ptproc) || !HASPT(pr))) { + /* Process memory is requested, and + * it's a process that is already in current page table, or + * a process that is in every page table. + * Therefore linaddr is valid directly, with the requested + * size. + */ + return linaddr; + } -#define DONEPDE(PDE) { \ - if(PDE != NOPDE) { \ - assert(PDE > 0); \ - assert(PDE < sizeof(dirtypde)*8); \ - dirtypde |= PDEMASK(PDE); \ - } \ -} + 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; + } -#define WIPEPDE(PDE) { \ - if(PDE != NOPDE) { \ - assert(PDE > 0); \ - assert(PDE < sizeof(dirtypde)*8); \ - *PROCPDEPTR(ptproc, PDE) = 0; \ - } \ -} + /* 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 * *===========================================================================*/ @@ -173,31 +158,24 @@ PRIVATE int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, while(bytes > 0) { phys_bytes srcptr, dstptr; vir_bytes chunk = bytes; - int srcpde, dstpde; - int srctype, dsttype; + int changed = 0; /* Set up 4MB ranges. */ - inusepde = NOPDE; - CREATEPDE(srcproc, srcptr, srclinaddr, chunk, bytes, srcpde, srctype); - CREATEPDE(dstproc, dstptr, dstlinaddr, chunk, bytes, dstpde, dsttype); + srcptr = createpde(srcproc, srclinaddr, &chunk, 0, &changed); + dstptr = createpde(dstproc, dstlinaddr, &chunk, 1, &changed); + if(changed) + reload_cr3(); /* Copy pages. */ PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr); - DONEPDE(srcpde); - DONEPDE(dstpde); - if(addr) { /* If addr is nonzero, a page fault was caught. */ if(addr >= srcptr && addr < (srcptr + chunk)) { - WIPEPDE(srcpde); - WIPEPDE(dstpde); NOREC_RETURN(linlincopy, EFAULT_SRC); } if(addr >= dstptr && addr < (dstptr + chunk)) { - WIPEPDE(srcpde); - WIPEPDE(dstpde); NOREC_RETURN(linlincopy, EFAULT_DST); } @@ -207,9 +185,6 @@ PRIVATE int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, NOREC_RETURN(linlincopy, EFAULT); } - WIPEPDE(srcpde); - WIPEPDE(dstpde); - /* Update counter and addresses for next iteration, if any. */ bytes -= 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. */ while(bytes > 0) { - int pde, t; - vir_bytes chunk = (vir_bytes) bytes; - phys_bytes ptr; - inusepde = NOPDE; - CREATEPDE(((struct proc *) NULL), ptr, ph, chunk, bytes, pde, t); + int changed = 0; + phys_bytes chunk = bytes, ptr; + ptr = createpde(NULL, ph, &chunk, 0, &changed); + if(changed) + reload_cr3(); + /* We can memset as many bytes as we have remaining, * or as many as remain in the 4MB chunk we mapped in. */ phys_memset(ptr, p, chunk); - DONEPDE(pde); bytes -= 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. */ void i386_freepde(int pde) { - if(nfreepdes >= WANT_FREEPDES) + if(nfreepdes >= MAX_FREEPDES) return; freepdes[nfreepdes++] = pde; } diff --git a/kernel/arch/i386/mpx386.S b/kernel/arch/i386/mpx386.S index 1729fa8cc..dd84ef1b9 100644 --- a/kernel/arch/i386/mpx386.S +++ b/kernel/arch/i386/mpx386.S @@ -110,7 +110,6 @@ begbss: .globl params_offset .globl mon_ds .globl schedcheck -.globl dirtypde .globl lazy_fpu .globl hwint00 /* handlers for hardware interrupts */ @@ -736,7 +735,6 @@ no_fpu_available: reload_cr3: push %ebp mov %esp, %ebp - movl $0, dirtypde mov %cr3, %eax mov %eax, %cr3 pop %ebp -- 2.11.4.GIT