diff --git a/kernel/.gitignore b/kernel/.gitignore index a6c57f5..2c41d45 100644 --- a/kernel/.gitignore +++ b/kernel/.gitignore @@ -1 +1,2 @@ *.json +.cache diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c index 092104f..0eaeedc 100644 --- a/kernel/proc/proc.c +++ b/kernel/proc/proc.c @@ -38,9 +38,13 @@ static bool proc_check_elf (uint8_t* elf) { return true; } -void proc_map (struct proc* proc, uintptr_t start_paddr, uintptr_t start_vaddr, size_t pages, +bool proc_map (struct proc* proc, uintptr_t start_paddr, uintptr_t start_vaddr, size_t pages, uint32_t flags) { struct proc_mapping* mapping = malloc (sizeof (*mapping)); + + if (mapping == NULL) + return false; + mapping->paddr = start_paddr; mapping->vaddr = start_vaddr; mapping->size = pages * PAGE_SIZE; @@ -57,6 +61,68 @@ void proc_map (struct proc* proc, uintptr_t start_paddr, uintptr_t start_vaddr, } spin_unlock (&proc->pd.lock); + + return true; +} + +bool proc_unmap (struct proc* proc, uintptr_t start_vaddr, size_t pages) { + size_t unmap_size = pages * PAGE_SIZE; + uintptr_t end_vaddr = start_vaddr + unmap_size; + struct list_node_link *mapping_link, *mapping_link_tmp; + bool used_tail_mapping = false; + + struct proc_mapping* tail_mapping = malloc (sizeof (*tail_mapping)); + if (tail_mapping == NULL) + return false; + + spin_lock (&proc->pd.lock); + + list_foreach (proc->mappings, mapping_link, mapping_link_tmp) { + struct proc_mapping* mapping = + list_entry (mapping_link, struct proc_mapping, proc_mappings_link); + + uintptr_t m_end = mapping->vaddr + mapping->size; + + /* check overlap */ + if ((start_vaddr < m_end) && (end_vaddr > mapping->vaddr)) { + /* split in the middle */ + if ((start_vaddr > mapping->vaddr) && (end_vaddr < m_end)) { + tail_mapping->vaddr = end_vaddr; + tail_mapping->paddr = mapping->paddr + (end_vaddr - mapping->vaddr); + tail_mapping->size = m_end - end_vaddr; + + mapping->size = start_vaddr - mapping->vaddr; + + list_insert_after (proc->mappings, &mapping->proc_mappings_link, + &tail_mapping->proc_mappings_link); + + used_tail_mapping = true; + + break; + } else if ((start_vaddr <= mapping->vaddr) && (end_vaddr < m_end)) { /* shrink left */ + size_t diff = end_vaddr - mapping->vaddr; + mapping->vaddr += diff; + mapping->paddr += diff; + mapping->size -= diff; + } else if ((start_vaddr > mapping->vaddr) && (end_vaddr >= m_end)) { /* shrink right */ + mapping->size = start_vaddr - mapping->vaddr; + } else { /* full overlap */ + list_remove (proc->mappings, &mapping->proc_mappings_link); + free (mapping); + } + } + } + + if (!used_tail_mapping) + free (tail_mapping); + + for (uintptr_t vpage = start_vaddr; vpage < end_vaddr; vpage += PAGE_SIZE) { + mm_unmap_page (&proc->pd, vpage, 0); + } + + spin_unlock (&proc->pd.lock); + + return true; } struct elf_aux proc_load_segments (struct proc* proc, uint8_t* elf) { diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index c45ab8f..9f7e990 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -44,7 +44,7 @@ struct proc { void proc_sched (void); void proc_kill (struct proc* proc); -void proc_map (struct proc* proc, uintptr_t start_paddr, uintptr_t start_vaddr, size_t pages, +bool proc_map (struct proc* proc, uintptr_t start_paddr, uintptr_t start_vaddr, size_t pages, uint32_t flags); struct elf_aux proc_load_segments (struct proc* proc, uint8_t* elf); void proc_init (void);