diff --git a/tasks/mm0/include/file.h b/tasks/mm0/include/file.h index e6c9315..077da84 100644 --- a/tasks/mm0/include/file.h +++ b/tasks/mm0/include/file.h @@ -19,6 +19,8 @@ int file_open(struct tcb *opener, int fd); struct vm_file *do_open2(struct tcb *task, int fd, unsigned long vnum, unsigned long length); int flush_file_pages(struct vm_file *f); +int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start, + unsigned long pfn_end); struct vfs_file_data { unsigned long vnum; diff --git a/tasks/mm0/include/memory.h b/tasks/mm0/include/memory.h index d10e8f8..33622d8 100644 --- a/tasks/mm0/include/memory.h +++ b/tasks/mm0/include/memory.h @@ -21,4 +21,12 @@ void init_mm_descriptors(struct page_bitmap *page_map, struct bootdesc *bootdesc, struct membank *membank); void init_physmem(struct initdata *initdata, struct membank *membank); +int pager_address_pool_init(void); +void *pager_new_address(int npages); +int pager_delete_address(void *virt_addr, int npages); +void *pager_map_pages(struct vm_file *f, unsigned long page_offset, unsigned long npages); +void pager_unmap_pages(void *addr, unsigned long npages); +void *pager_map_page(struct vm_file *f, unsigned long page_offset); +void pager_unmap_page(void *addr); + #endif /* __MEMORY_H__ */ diff --git a/tasks/mm0/src/file.c b/tasks/mm0/src/file.c index 320da74..1295c35 100644 --- a/tasks/mm0/src/file.c +++ b/tasks/mm0/src/file.c @@ -21,6 +21,7 @@ #include #include + /* Copy from one page's buffer into another page */ int page_copy(struct page *dst, struct page *src, unsigned long dst_offset, unsigned long src_offset, @@ -308,27 +309,6 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start, return 0; } -/* Maps a page from a vm_file to the pager's address space */ -void *pager_map_page(struct vm_file *f, unsigned long page_offset) -{ - int err; - struct page *p; - - if ((err = read_file_pages(f, page_offset, page_offset + 1)) < 0) - return PTR_ERR(err); - - if ((p = find_page(&f->vm_obj, page_offset))) - return (void *)l4_map_helper((void *)page_to_phys(p), 1); - else - return 0; -} - -/* Unmaps a page's virtual address from the pager's address space */ -void pager_unmap_page(void *addr) -{ - l4_unmap_helper(addr, 1); -} - int vfs_write(unsigned long vnum, unsigned long file_offset, unsigned long npages, void *pagebuf) { diff --git a/tasks/mm0/src/init.c b/tasks/mm0/src/init.c index 590a697..7af9a2e 100644 --- a/tasks/mm0/src/init.c +++ b/tasks/mm0/src/init.c @@ -174,6 +174,10 @@ void init_mm(struct initdata *initdata) printf("UTCB initialisation failed.\n"); BUG(); } + + /* For supplying contiguous virtual addresses to pager */ + pager_address_pool_init(); + // printf("%s: Initialised utcb address pool.\n", __TASKNAME__); /* Give the kernel some memory to use for its allocators */ diff --git a/tasks/mm0/src/lib/elf/elf.c b/tasks/mm0/src/lib/elf/elf.c index bc2eb1b..5cc8c1f 100644 --- a/tasks/mm0/src/lib/elf/elf.c +++ b/tasks/mm0/src/lib/elf/elf.c @@ -24,6 +24,13 @@ int elf_probe(struct elf_header *header) return -1; } +static inline void *pager_map_file_offset(struct vm_file *f, unsigned long f_offset) +{ + void *page = pager_map_page(f, __pfn(f_offset)); + + return (void *)((unsigned long)page | (PAGE_MASK & f_offset)); +} + /* * Loading an ELF file: * @@ -59,8 +66,14 @@ int elf_parse_executable(struct tcb *task, struct vm_file *file, } /* Get the section header table */ - sect_header = (struct elf_section_header *) - ((void *)elf_header + elf_header->e_shoff); + if (__pfn(elf_header->e_shoff) > 0) + sect_header = pager_map_file_offset(file, elf_header->e_shoff); + else + sect_header = (struct elf_section_header *) + ((void *)elf_header + elf_header->e_shoff); + + /* Determine if we cross a page boundary during traversal */ + if (elf_header->e_shentsize * elf_header->e_shnum > TILL_PAGE_ENDS(sect_header)) /* * Sift through sections and copy their marks to tcb and efd diff --git a/tasks/mm0/src/memory.c b/tasks/mm0/src/memory.c index dc1b30d..a46a330 100644 --- a/tasks/mm0/src/memory.c +++ b/tasks/mm0/src/memory.c @@ -8,15 +8,19 @@ #include #include #include +#include #include #include #include INC_GLUE(memory.h) #include INC_SUBARCH(mm.h) #include +#include struct membank membank[1]; struct page *page_array; +struct address_pool pager_vaddr_pool; + void *phys_to_virt(void *addr) { return addr + INITTASK_OFFSET; @@ -90,3 +94,82 @@ void init_physmem(struct initdata *initdata, struct membank *membank) page_array = membank[0].page_array; } +/* Maps a page from a vm_file to the pager's address space */ +void *pager_map_page(struct vm_file *f, unsigned long page_offset) +{ + int err; + struct page *p; + + if ((err = read_file_pages(f, page_offset, page_offset + 1)) < 0) + return PTR_ERR(err); + + if ((p = find_page(&f->vm_obj, page_offset))) + return (void *)l4_map_helper((void *)page_to_phys(p), 1); + else + return 0; +} + +/* Unmaps a page's virtual address from the pager's address space */ +void pager_unmap_page(void *addr) +{ + l4_unmap_helper(addr, 1); +} + +int pager_address_pool_init(void) +{ + int err; + + /* Initialise the global shm virtual address pool */ + if ((err = address_pool_init(&pager_vaddr_pool, + (unsigned long)0xD0000000, + (unsigned long)0xE0000000)) < 0) { + printf("Pager virtual address pool initialisation failed.\n"); + return err; + } + return 0; +} + +void *pager_new_address(int npages) +{ + return address_new(&pager_vaddr_pool, npages); +} + +int pager_delete_address(void *virt_addr, int npages) +{ + return address_del(&pager_vaddr_pool, virt_addr, npages); +} + +/* Maps a page from a vm_file to the pager's address space */ +void *pager_map_pages(struct vm_file *f, unsigned long page_offset, unsigned long npages) +{ + int err; + struct page *p; + void *addr_start, *addr; + + /* Get the pages */ + if ((err = read_file_pages(f, page_offset, page_offset + npages)) < 0) + return PTR_ERR(err); + + /* Get the address range */ + if (!(addr_start = pager_new_address(npages))) + return PTR_ERR(-ENOMEM); + addr = addr_start; + + /* Map pages contiguously one by one */ + for (unsigned long pfn = page_offset; pfn < page_offset + npages; pfn++) { + BUG_ON(!(p = find_page(&f->vm_obj, page_offset))) + l4_map((void *)page_to_phys(p), addr, 1, MAP_USR_RW_FLAGS, self_tid()); + addr += PAGE_SIZE; + } + + return addr_start; +} + +/* Unmaps a page's virtual address from the pager's address space */ +void pager_unmap_pages(void *addr, unsigned long npages) +{ + l4_unmap_helper(addr, npages); + pager_delete_address(addr, npages); +} + +