void dma_load(uint8_t channel, void *start, int count) { KASSERT(PAGE_ALIGNED(start)); prd_t* table = DMA_PRDS[channel]; memset(table, 0, sizeof(prd_t)); /* set up the PRD for this operation */ table->prd_addr = pt_virt_to_phys((uintptr_t) start); table->prd_count = count; table->prd_last = 0x8000; return; }
void dma_start(uint8_t channel, uint16_t busmaster_addr, int write) { uint8_t cmd = 0; /* first we need to set the read/write bit */ if (write == 0) { cmd = (1 << 3); } /* then set the address of the prd */ outl(busmaster_addr + DMA_PRD, pt_virt_to_phys((uintptr_t)DMA_PRDS[channel])); /* then allow all channels of DMA on this busmaster by setting that status register */ outb(busmaster_addr + DMA_STATUS, inb(busmaster_addr + DMA_STATUS) | 0x60); /* then we need to set the start/stop bit */ cmd |= 0x01; outb(busmaster_addr + DMA_COMMAND, cmd); }
/* * This gets called by _pt_fault_handler in mm/pagetable.c The * calling function has already done a lot of error checking for * us. In particular it has checked that we are not page faulting * while in kernel mode. Make sure you understand why an * unexpected page fault in kernel mode is bad in Weenix. You * should probably read the _pt_fault_handler function to get a * sense of what it is doing. * * Before you can do anything you need to find the vmarea that * contains the address that was faulted on. Make sure to check * the permissions on the area to see if the process has * permission to do [cause]. If either of these checks does not * pass kill the offending process, setting its exit status to * EFAULT (normally we would send the SIGSEGV signal, however * Weenix does not support signals). * * Now it is time to find the correct page (don't forget * about shadow objects, especially copy-on-write magic!). Make * sure that if the user writes to the page it will be handled * correctly. * * Finally call pt_map to have the new mapping placed into the * appropriate page table. * * @param vaddr the address that was accessed to cause the fault * * @param cause this is the type of operation on the memory * address which caused the fault, possible values * can be found in pagefault.h */ void handle_pagefault(uintptr_t vaddr, uint32_t cause) { /*NOT_YET_IMPLEMENTED("VM: handle_pagefault");*/ vmmap_t *map = curproc->p_vmmap; dbginfo(DBG_ERROR, proc_info, curproc); dbginfo(DBG_ERROR, proc_list_info, NULL); if(vaddr == NULL){ } vmarea_t *vma = vmmap_lookup(map, ADDR_TO_PN(vaddr)); /*uintptr_t pagenum = PAGE_OFFSET(vaddr);*/ if(vma == NULL || !(cause & FAULT_USER)){ /*XXX permission checks*/ curproc->p_status = EFAULT; proc_kill(curproc, EFAULT); } pframe_t *pf; uintptr_t pagenum = ADDR_TO_PN(vaddr) - vma->vma_start+vma->vma_off; /*XXX handle shadow objects*/ /* int forWrite = 0; if(cause & FAULT_WRITE){ forWrite = 1; } */ /* if(vma->vma_obj->mmo_shadowed != NULL){ shadow_lookuppage(vma->vma_obj->mmo_shadowed, pagenum, forWrite,&pf); }else{ */ pframe_get(vma->vma_obj, pagenum, &pf); /*}*/ uintptr_t paddr = pt_virt_to_phys((uintptr_t)pf->pf_addr); uintptr_t pdflags = PD_PRESENT | PD_WRITE | PD_USER; uintptr_t ptflags = PT_PRESENT | PT_WRITE | PT_USER; /*XXX tlb flush?*/ pt_map(curproc->p_pagedir,(uintptr_t)PAGE_ALIGN_DOWN(vaddr), paddr, pdflags, ptflags); }
/* * This gets called by _pt_fault_handler in mm/pagetable.c The * calling function has already done a lot of error checking for * us. In particular it has checked that we are not page faulting * while in kernel mode. Make sure you understand why an * unexpected page fault in kernel mode is bad in Weenix. You * should probably read the _pt_fault_handler function to get a * sense of what it is doing. * * Before you can do anything you need to find the vmarea that * contains the address that was faulted on. Make sure to check * the permissions on the area to see if the process has * permission to do [cause]. If either of these checks does not * pass kill the offending process, setting its exit status to * EFAULT (normally we would send the SIGSEGV signal, however * Weenix does not support signals). * * Now it is time to find the correct page (don't forget * about shadow objects, especially copy-on-write magic!). Make * sure that if the user writes to the page it will be handled * correctly. * * Finally call pt_map to have the new mapping placed into the * appropriate page table. * * @param vaddr the address that was accessed to cause the fault * * @param cause this is the type of operation on the memory * address which caused the fault, possible values * can be found in pagefault.h */ void handle_pagefault(uintptr_t vaddr, uint32_t cause) { int forwrite = 0; if( vaddr<(USER_MEM_LOW) ||vaddr >= (USER_MEM_HIGH)){ dbg(DBG_PRINT, "(GRADING3D) ADDRESS NOT VALID \n"); do_exit(EFAULT); return; } vmarea_t *container = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(vaddr)); if(container == NULL){ dbg(DBG_PRINT, "(GRADING3D) VMAREA NOT VALID \n"); do_exit(EFAULT); return; } if(container->vma_prot == PROT_NONE){ dbg(DBG_PRINT, "(GRADING3D) PROT NOT VALID \n"); do_exit(EFAULT); return; } if((cause & FAULT_WRITE) && !(container->vma_prot & PROT_WRITE)){ dbg(DBG_PRINT, "(GRADING3D) CONTAINER PROT NOT VALID \n"); do_exit(EFAULT); return; } if(!(container->vma_prot & PROT_READ)){ dbg(DBG_PRINT, "(GRADING3D) PROT IS NOT PROT READ \n"); do_exit(EFAULT); return; } int pagenum = ADDR_TO_PN(vaddr)-container->vma_start+container->vma_off; pframe_t *pf; if((container->vma_prot & PROT_WRITE) && (cause & FAULT_WRITE)){ dbg(DBG_PRINT, "(GRADING3D) prot write fault write \n"); int pf_res = pframe_lookup(container->vma_obj, pagenum, 1, &pf); if(pf_res<0){ dbg(DBG_PRINT, "(GRADING3D) pframe lookup failed\n"); do_exit(EFAULT); } pframe_dirty(pf); }else{ dbg(DBG_PRINT, "(GRADING3D) prot write fault write else \n"); int pf_res = pframe_lookup(container->vma_obj, pagenum, forwrite, &pf); if(pf_res<0){ dbg(DBG_PRINT, "(GRADING3D) pframe lookup failed \n"); do_exit(EFAULT); } } KASSERT(pf); dbg(DBG_PRINT, "(GRADING3A 5.a) pf is not NULL\n"); KASSERT(pf->pf_addr); dbg(DBG_PRINT, "(GRADING3A 5.a) pf->addr is not NULL\n"); uint32_t pdflags = PD_PRESENT | PD_USER; uint32_t ptflags = PT_PRESENT | PT_USER; if(cause & FAULT_WRITE){ dbg(DBG_PRINT, "(GRADING3D) cause is fault write \n"); pdflags = pdflags | PD_WRITE; ptflags = ptflags | PT_WRITE; } int ptmap_res = pt_map(curproc->p_pagedir, (uintptr_t)PAGE_ALIGN_DOWN(vaddr), pt_virt_to_phys((uintptr_t)pf->pf_addr), pdflags, ptflags); }
/* * This gets called by _pt_fault_handler in mm/pagetable.c The * calling function has already done a lot of error checking for * us. In particular it has checked that we are not page faulting * while in kernel mode. Make sure you understand why an * unexpected page fault in kernel mode is bad in Weenix. You * should probably read the _pt_fault_handler function to get a * sense of what it is doing. * * Before you can do anything you need to find the vmarea that * contains the address that was faulted on. Make sure to check * the permissions on the area to see if the process has * permission to do [cause]. If either of these checks does not * pass kill the offending process, setting its exit status to * EFAULT (normally we would send the SIGSEGV signal, however * Weenix does not support signals). * * Now it is time to find the correct page (don't forget * about shadow objects, especially copy-on-write magic!). Make * sure that if the user writes to the page it will be handled * correctly. * * Finally call pt_map to have the new mapping placed into the * appropriate page table. * * @param vaddr the address that was accessed to cause the fault * * @param cause this is the type of operation on the memory * address which caused the fault, possible values * can be found in pagefault.h */ void handle_pagefault(uintptr_t vaddr, uint32_t cause) { /*NOT_YET_IMPLEMENTED("VM: handle_pagefault");*/ vmarea_t *vma; pframe_t *pf; int pflags = PD_PRESENT | PD_USER; int writeflag = 0; dbg(DBG_PRINT, "(GRADING3F)\n"); if ((vma = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(vaddr))) == NULL) { dbg(DBG_PRINT, "(GRADING3C 1)\n"); proc_kill(curproc, EFAULT); return; } /* if (vma->vma_prot & PROT_NONE) { dbg(DBG_ERROR, "(GRADING3 3)\n"); proc_kill(curproc, EFAULT); return; }*/ if (!((cause & FAULT_WRITE) || (cause & FAULT_EXEC)) && !(vma->vma_prot & PROT_READ)) { dbg(DBG_PRINT, "(GRADING3D 3)\n"); proc_kill(curproc, EFAULT); return; } if ((cause & FAULT_WRITE) && !(vma->vma_prot & PROT_WRITE)) { dbg(DBG_PRINT, "(GRADING3D 3)\n"); proc_kill(curproc, EFAULT); return; }/* if ((cause & FAULT_EXEC) && !(vma->vma_prot & PROT_EXEC)) { dbg(DBG_ERROR, "(GRADING3 6)\n"); proc_kill(curproc, EFAULT); return;; }*/ if (cause & FAULT_WRITE) { dbg(DBG_PRINT, "(GRADING3F)\n"); writeflag = 1; } if (pframe_lookup(vma->vma_obj, ADDR_TO_PN(vaddr) - vma->vma_start + vma->vma_off, writeflag, &pf) < 0) { dbg(DBG_PRINT, "(GRADING3D 4)\n"); proc_kill(curproc, EFAULT); return; } if (cause & FAULT_WRITE) { pframe_pin(pf); dbg(DBG_PRINT, "(GRADING3F)\n"); pframe_dirty(pf); /* if ( < 0) { dbg(DBG_ERROR, "(GRADING3 10)\n"); pframe_unpin(pf); proc_kill(curproc, EFAULT); return; }*/ pframe_unpin(pf); pflags |= PD_WRITE; } pt_map(curproc->p_pagedir, (uintptr_t) PAGE_ALIGN_DOWN(vaddr), pt_virt_to_phys((uintptr_t) pf->pf_addr), pflags, pflags); }
void handle_pagefault(uintptr_t vaddr, uint32_t cause) { pframe_t *pf; int ret_val; vmarea_t *vma = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(vaddr)); if(vma == NULL) { dbg(DBG_PRINT,"(GRADING3D 1): No vmarea found\n"); proc_kill(curproc,EFAULT); return; } if(cause & FAULT_WRITE) { dbg(DBG_VM,"grade14\n"); dbg(DBG_PRINT,"(GRADING3D 1),checking permission for writing\n"); if(vma->vma_prot & PROT_WRITE) { dbg(DBG_VM,"grade15\n"); dbg(DBG_PRINT,"(GRADING3D 1),Vmarea has write permission\n"); ret_val = pframe_lookup(vma->vma_obj, ADDR_TO_PN(vaddr) - vma->vma_start + vma->vma_off, (cause & FAULT_WRITE),&pf); if(ret_val<0) { dbg(DBG_VM,"grade16\n"); dbg(DBG_PRINT,"(GRADING3D 1),pframe could not be found\n"); proc_kill(curproc,EFAULT); return; } pframe_dirty(pf); KASSERT(pf); dbg(DBG_PRINT,"(GRADING3A 5.a),pframe is not NULL\n"); KASSERT(pf->pf_addr); dbg(DBG_PRINT,"(GRADING3A 5.a),pf->pf_addr is not NULL\n"); } else { dbg(DBG_VM,"grade17\n"); dbg(DBG_PRINT,"(GRADING3D 1),Vmarea does not have write permission\n"); proc_kill(curproc,EFAULT); return; } dbg(DBG_VM,"grade18\n"); dbg(DBG_PRINT,"(GRADING3D 1),Calling pt_map after write\n"); pt_map(curproc->p_pagedir,(uintptr_t)PAGE_ALIGN_DOWN(vaddr),pt_virt_to_phys((uintptr_t)pf->pf_addr), (PD_WRITE|PD_PRESENT|PD_USER), (PT_WRITE|PT_PRESENT|PT_USER)); } else { dbg(DBG_VM,"grade19\n"); dbg(DBG_PRINT,"(GRADING3D 1),checking permission for reading\n"); if(vma->vma_prot & PROT_READ) { dbg(DBG_VM,"grade20\n"); dbg(DBG_PRINT,"(GRADING3D 1),Vmarea has read permission\n"); ret_val = pframe_lookup(vma->vma_obj, ADDR_TO_PN(vaddr) - vma->vma_start + vma->vma_off, (cause & FAULT_WRITE),&pf); if(ret_val<0) { dbg(DBG_VM,"grade21\n"); dbg(DBG_PRINT,"(GRADING3D 1),pframe could not be found\n"); proc_kill(curproc,EFAULT); return; } dbg(DBG_VM,"grade22\n"); KASSERT(pf); dbg(DBG_PRINT,"(GRADING3A 5.a),pframe is not NULL\n"); KASSERT(pf->pf_addr); dbg(DBG_PRINT,"(GRADING3A 5.a),pf->pf_addr is not NULL\n"); } else { dbg(DBG_VM,"grade23\n"); dbg(DBG_PRINT,"(GRADING3D 1),Vmarea does not have read permission\n"); proc_kill(curproc,EFAULT); return; } dbg(DBG_VM,"grade24\n"); dbg(DBG_PRINT,"(GRADING3D 1),Calling pt_map after read\n"); pt_map(curproc->p_pagedir,(uintptr_t)PAGE_ALIGN_DOWN(vaddr),pt_virt_to_phys((uintptr_t)pf->pf_addr), (PD_PRESENT|PD_USER), (PT_PRESENT|PT_USER)); } }
/* * This gets called by _pt_fault_handler in mm/pagetable.c The * calling function has already done a lot of error checking for * us. In particular it has checked that we are not page faulting * while in kernel mode. Make sure you understand why an * unexpected page fault in kernel mode is bad in Weenix. You * should probably read the _pt_fault_handler function to get a * sense of what it is doing. * * Before you can do anything you need to find the vmarea that * contains the address that was faulted on. Make sure to check * the permissions on the area to see if the process has * permission to do [cause]. If either of these checks does not * pass kill the offending process, setting its exit status to * EFAULT (normally we would send the SIGSEGV signal, however * Weenix does not support signals). * * Now it is time to find the correct page (don't forget * about shadow objects, especially copy-on-write magic!). Make * sure that if the user writes to the page it will be handled * correctly. * * Finally call pt_map to have the new mapping placed into the * appropriate page table. * * @param vaddr the address that was accessed to cause the fault * * @param cause this is the type of operation on the memory * address which caused the fault, possible values * can be found in pagefault.h */ void handle_pagefault(uintptr_t vaddr, uint32_t cause) { /*NOT_YET_IMPLEMENTED("VM: handle_pagefault");*/ uint32_t res_vfn=ADDR_TO_PN(vaddr); vmarea_t *temp_vmarea=vmmap_lookup(curproc->p_vmmap,res_vfn); if(temp_vmarea==NULL) { proc_kill(curproc,EFAULT); return; } if((cause&FAULT_PRESENT)&&(!(temp_vmarea->vma_prot&PROT_READ))) { proc_kill(curproc,EFAULT); return; } if(cause&FAULT_RESERVED&&(!(temp_vmarea->vma_prot&PROT_NONE))) { proc_kill(curproc,EFAULT); return; } if(cause&FAULT_EXEC&&(!(temp_vmarea->vma_prot&PROT_EXEC))) { proc_kill(curproc,EFAULT); return; } if ((cause & FAULT_WRITE)&&!(temp_vmarea->vma_prot & PROT_WRITE)) { do_exit(EFAULT); return; } if((cause&FAULT_WRITE)==0) { if((temp_vmarea->vma_prot & PROT_READ)==0) { do_exit(EFAULT); } } pframe_t *temp_pf_res=NULL; uint32_t pagenum=temp_vmarea->vma_off+res_vfn-temp_vmarea->vma_start; if(cause & FAULT_WRITE)/*******according to google group:1. pframe_get 2.pt_map(permission!!!)*************/ { int tempres=pframe_lookup(temp_vmarea->vma_obj,pagenum,1, &temp_pf_res); if(tempres<0) { proc_kill(curproc,EFAULT); return; } uintptr_t paddr=pt_virt_to_phys((uintptr_t)temp_pf_res->pf_addr); pt_map(curproc->p_pagedir,(uintptr_t)(PN_TO_ADDR(res_vfn)),paddr,PD_PRESENT|PD_WRITE|PD_USER,PT_PRESENT|PT_WRITE|PT_USER); } else{ int tempres=pframe_lookup(temp_vmarea->vma_obj,pagenum,0, &temp_pf_res); if(tempres<0) { proc_kill(curproc,EFAULT); return; } uintptr_t paddr=pt_virt_to_phys((uintptr_t)temp_pf_res->pf_addr); pt_map(curproc->p_pagedir,(uintptr_t)(PN_TO_ADDR(res_vfn)),paddr,PD_PRESENT|PD_USER,PT_PRESENT|PT_USER); } }