/* Return non-zero on error. */ int setup_new_process(TID_t thread, const char *executable, const char **argv_src, virtaddr_t *entry_point, virtaddr_t *stack_top) { pagetable_t *pagetable; elf_info_t elf; openfile_t file; uintptr_t phys_page; int i, res; thread_table_t *thread_entry = thread_get_thread_entry(thread); int argc = 1; virtaddr_t argv_begin; virtaddr_t argv_dst; int argv_elem_size; virtaddr_t argv_elem_dst; file = vfs_open((char *)executable); /* Make sure the file existed and was a valid ELF file */ if (file < 0) { return -1; } res = elf_parse_header(&elf, file); if (res < 0) { return -1; } /* Trivial and naive sanity check for entry point: */ if (elf.entry_point < PAGE_SIZE) { return -1; } *entry_point = elf.entry_point; pagetable = vm_create_pagetable(thread); thread_entry->pagetable = pagetable; /* Allocate and map stack */ for(i = 0; i < CONFIG_USERLAND_STACK_SIZE; i++) { phys_page = physmem_allocblock(); KERNEL_ASSERT(phys_page != 0); /* Zero the page */ memoryset((void*)ADDR_PHYS_TO_KERNEL(phys_page), 0, PAGE_SIZE); vm_map(pagetable, phys_page, (USERLAND_STACK_TOP & PAGE_SIZE_MASK) - i*PAGE_SIZE, 1); } /* Allocate and map pages for the segments. We assume that segments begin at page boundary. (The linker script in tests directory creates this kind of segments) */ for(i = 0; i < (int)elf.ro_pages; i++) { int left_to_read = elf.ro_size - i*PAGE_SIZE; phys_page = physmem_allocblock(); KERNEL_ASSERT(phys_page != 0); /* Zero the page */ memoryset((void*)ADDR_PHYS_TO_KERNEL(phys_page), 0, PAGE_SIZE); /* Fill the page from ro segment */ if (left_to_read > 0) { KERNEL_ASSERT(vfs_seek(file, elf.ro_location + i*PAGE_SIZE) == VFS_OK); KERNEL_ASSERT(vfs_read(file, (void*)ADDR_PHYS_TO_KERNEL(phys_page), MIN(PAGE_SIZE, left_to_read)) == (int) MIN(PAGE_SIZE, left_to_read)); } vm_map(pagetable, phys_page, elf.ro_vaddr + i*PAGE_SIZE, 0); } for(i = 0; i < (int)elf.rw_pages; i++) { int left_to_read = elf.rw_size - i*PAGE_SIZE; phys_page = physmem_allocblock(); KERNEL_ASSERT(phys_page != 0); /* Zero the page */ memoryset((void*)ADDR_PHYS_TO_KERNEL(phys_page), 0, PAGE_SIZE); /* Fill the page from rw segment */ if (left_to_read > 0) { KERNEL_ASSERT(vfs_seek(file, elf.rw_location + i*PAGE_SIZE) == VFS_OK); KERNEL_ASSERT(vfs_read(file, (void*)ADDR_PHYS_TO_KERNEL(phys_page), MIN(PAGE_SIZE, left_to_read)) == (int) MIN(PAGE_SIZE, left_to_read)); } vm_map(pagetable, phys_page, elf.rw_vaddr + i*PAGE_SIZE, 1); } /* Set up argc and argv on the stack. */ /* Start by preparing ancillary information for the new process argv. */ if (argv_src != NULL) for (i = 0; argv_src[i] != NULL; i++) { argc++; } argv_begin = USERLAND_STACK_TOP - (argc * sizeof(virtaddr_t)); argv_dst = argv_begin; /* Prepare for copying executable. */ argv_elem_size = strlen(executable) + 1; argv_elem_dst = argv_dst - wordpad(argv_elem_size); /* Copy executable to argv[0] location. */ vm_memwrite(pagetable, argv_elem_size, argv_elem_dst, executable); /* Set argv[i] */ vm_memwrite(pagetable, sizeof(virtaddr_t), argv_dst, &argv_elem_dst); /* Move argv_dst to &argv[1]. */ argv_dst += sizeof(virtaddr_t); if (argv_src != NULL) { for (i = 0; argv_src[i] != NULL; i++) { /* Compute the size of argv[i+1] */ argv_elem_size = strlen(argv_src[i]) + 1; argv_elem_dst -= wordpad(argv_elem_size); /* Write the 'i+1'th element of argv */ vm_memwrite(pagetable, argv_elem_size, argv_elem_dst, argv_src[i]); /* Write argv[i+1] */ vm_memwrite(pagetable, sizeof(virtaddr_t), argv_dst, &argv_elem_dst); /* Move argv_dst to next element of argv. */ argv_dst += sizeof(virtaddr_t); } } /* Write argc to the stack. */ vm_memwrite(pagetable, sizeof(int), argv_elem_dst - sizeof(int), &argc); /* Write argv to the stack. */ vm_memwrite(pagetable, sizeof(virtaddr_t), argv_elem_dst - sizeof(int) - sizeof(virtaddr_t), &argv_begin); /* Stack pointer points at argv. */ *stack_top = argv_elem_dst - sizeof(int) - sizeof(virtaddr_t); return 0; }
/** * Initialize trivial filesystem. Allocates 1 page of memory dynamically for * filesystem data structure, tfs data structure and buffers needed. * Sets fs_t and tfs_t fields. If initialization is succesful, returns * pointer to fs_t data structure. Else NULL pointer is returned. * * @param Pointer to gbd-device performing tfs. * * @return Pointer to the filesystem data structure fs_t, if fails * return NULL. */ fs_t * tfs_init(gbd_t *disk) { uint32_t addr; gbd_request_t req; char name[TFS_VOLUMENAME_MAX]; fs_t *fs; tfs_t *tfs; int r; semaphore_t *sem; if(disk->block_size(disk) != TFS_BLOCK_SIZE) return NULL; /* check semaphore availability before memory allocation */ sem = semaphore_create(1); if (sem == NULL) { kprintf("tfs_init: could not create a new semaphore.\n"); return NULL; } addr = pagepool_get_phys_page(); if(addr == 0) { semaphore_destroy(sem); kprintf("tfs_init: could not allocate memory.\n"); return NULL; } addr = ADDR_PHYS_TO_KERNEL(addr); /* transform to vm address */ /* Assert that one page is enough */ KERNEL_ASSERT(PAGE_SIZE >= (3*TFS_BLOCK_SIZE+sizeof(tfs_t)+sizeof(fs_t))); /* Read header block, and make sure this is tfs drive */ req.block = 0; req.sem = NULL; req.buf = ADDR_KERNEL_TO_PHYS(addr); /* disk needs physical addr */ r = disk->read_block(disk, &req); if(r == 0) { semaphore_destroy(sem); pagepool_free_phys_page(ADDR_KERNEL_TO_PHYS(addr)); kprintf("tfs_init: Error during disk read. Initialization failed.\n"); return NULL; } if(((uint32_t *)addr)[0] != TFS_MAGIC) { semaphore_destroy(sem); pagepool_free_phys_page(ADDR_KERNEL_TO_PHYS(addr)); return NULL; } /* Copy volume name from header block. */ stringcopy(name, (char *)(addr+4), TFS_VOLUMENAME_MAX); /* fs_t, tfs_t and all buffers in tfs_t fit in one page, so obtain addresses for each structure and buffer inside the allocated memory page. */ fs = (fs_t *)addr; tfs = (tfs_t *)(addr + sizeof(fs_t)); tfs->buffer_inode = (tfs_inode_t *)((uint32_t)tfs + sizeof(tfs_t)); tfs->buffer_bat = (bitmap_t *)((uint32_t)tfs->buffer_inode + TFS_BLOCK_SIZE); tfs->buffer_md = (tfs_direntry_t *)((uint32_t)tfs->buffer_bat + TFS_BLOCK_SIZE); tfs->totalblocks = MIN(disk->total_blocks(disk), 8*TFS_BLOCK_SIZE); tfs->disk = disk; /* save the semaphore to the tfs_t */ tfs->lock = sem; fs->internal = (void *)tfs; stringcopy(fs->volume_name, name, VFS_NAME_LENGTH); fs->unmount = tfs_unmount; fs->open = tfs_open; fs->close = tfs_close; fs->create = tfs_create; fs->remove = tfs_remove; fs->read = tfs_read; fs->write = tfs_write; fs->getfree = tfs_getfree; return fs; }