int ahci_write_prdt(struct hba_memory *abar, struct hba_port *port, struct ahci_device *dev, int slot, int offset, int length, addr_t virt_buffer) { int num_entries = ((length-1) / PRDT_MAX_COUNT) + 1; struct hba_command_table *tbl = (struct hba_command_table *)(dev->ch[slot]); int i; struct hba_prdt_entry *prd; for(i=0;i<num_entries-1;i++) { /* TODO: do we need to do this? */ addr_t phys_buffer; mm_virtual_getmap(virt_buffer, &phys_buffer, 0); prd = &tbl->prdt_entries[i+offset]; prd->byte_count = PRDT_MAX_COUNT-1; prd->data_base_l = LOWER32(phys_buffer); prd->data_base_h = UPPER32(phys_buffer); prd->interrupt_on_complete=0; length -= PRDT_MAX_COUNT; virt_buffer += PRDT_MAX_COUNT; } addr_t phys_buffer; mm_virtual_getmap(virt_buffer, &phys_buffer, 0); prd = &tbl->prdt_entries[i+offset]; prd->byte_count = length-1; prd->data_base_l = LOWER32(phys_buffer); prd->data_base_h = UPPER32(phys_buffer); prd->interrupt_on_complete=0; return num_entries; }
/* Decrease the count of each requested page by 1, and unmap it from the virtual address. * If the count reaches zero, sync the page, free it, and delete the entry to the hash table. */ void fs_inode_unmap_region(struct inode *node, addr_t virt, size_t offset, size_t length) { mutex_acquire(&node->mappings_lock); ASSERT(node->flags & INODE_PCACHE); ASSERT(!(offset & ~PAGE_MASK)); ASSERT(!(virt & ~PAGE_MASK)); int page_number = offset / PAGE_SIZE; int npages = ((length-1) / PAGE_SIZE) + 1; for(int i = page_number; i < (page_number + npages); i++) { struct physical_page *entry; if((entry = hash_lookup(&node->physicals, &i, sizeof(i))) != NULL) { mutex_acquire(&entry->lock); atomic_fetch_sub(&entry->count, 1); mutex_release(&entry->lock); } // We'll actually do the unmapping too. int attr; addr_t page; if(mm_virtual_getmap(virt + (i - page_number)*PAGE_SIZE, &page, &attr)) { mm_virtual_unmap(virt + (i - page_number)*PAGE_SIZE); mm_physical_decrement_count(entry->page); } } mutex_release(&node->mappings_lock); }
void fs_inode_sync_physical_page(struct inode *node, addr_t virt, size_t offset, size_t req_len) { ASSERT(!(offset & ~PAGE_MASK)); ASSERT(!(virt & ~PAGE_MASK)); if(!mm_virtual_getmap(virt, NULL, NULL)) return; // Again, no real good way to notify userspace of a failure. size_t len = req_len; if(len + offset > (size_t)node->length) len = node->length - offset; if(offset >= (size_t)node->length) return; if(node->filesystem && fs_inode_write(node, offset, len, (void *)virt) < 0) printk(0, "[MMINODE]: WARNING: Failed to write back data.\n"); }