177 lines
5.0 KiB
C
177 lines
5.0 KiB
C
#include "pvec.h"
|
|
#include "vfs.h"
|
|
#include "interrupts.h"
|
|
#include "schedule.h"
|
|
#include "string.h"
|
|
#include "memory.h"
|
|
#include "console.h"
|
|
|
|
extern struct task_t *current_task;
|
|
|
|
typedef struct {
|
|
unsigned char magic[4];
|
|
unsigned char bitness;
|
|
unsigned char endian;
|
|
unsigned char ver_1;
|
|
unsigned char res[9];
|
|
unsigned short file_type;
|
|
unsigned short machine __attribute__((packed));
|
|
unsigned int ver_2 __attribute__((packed));
|
|
unsigned int entry __attribute__((packed));
|
|
unsigned int phtab_offset __attribute__((packed));
|
|
unsigned int shtab_offset __attribute__((packed));
|
|
unsigned int flags __attribute__((packed));
|
|
unsigned short file_hdr_size __attribute__((packed));
|
|
unsigned short phtab_ent_size __attribute__((packed));
|
|
unsigned short num_phs __attribute__((packed));
|
|
unsigned short shtab_ent_size __attribute__((packed));
|
|
unsigned short num_shs __attribute__((packed));
|
|
unsigned short shstrtab_index __attribute__((packed));
|
|
} elf_file_t; /* 52 bytes */
|
|
|
|
typedef struct {
|
|
unsigned int type __attribute__((packed));
|
|
unsigned int offset __attribute__((packed));
|
|
unsigned int virt_adr __attribute__((packed));
|
|
unsigned int phys_adr __attribute__((packed));
|
|
unsigned int disk_size __attribute__((packed));
|
|
unsigned int mem_size __attribute__((packed));
|
|
unsigned int flags __attribute__((packed));
|
|
unsigned int align __attribute__((packed));
|
|
} elf_seg_t; /* 32 bytes */
|
|
|
|
#define PAGE_SIZE 4096
|
|
#define PAGE_MASK (~(0xffffffff << 12))
|
|
|
|
static __inline__ unsigned int round_up_to_page(unsigned int addr) {
|
|
if ((addr & PAGE_MASK) != 0) {
|
|
addr &= ~(PAGE_MASK);
|
|
addr += PAGE_SIZE;
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
int execve(struct regs *r, char *name, char **argv, char **env) {
|
|
char *exeimage;
|
|
|
|
if (!vfs_read_entire_file(name, &exeimage)) {
|
|
kprintf("Unable to read file\n");
|
|
return -1;
|
|
}
|
|
elf_file_t *elf_header = (elf_file_t *)exeimage;
|
|
|
|
// check magic...
|
|
if (elf_header->magic[0] == 0x7f && elf_header->magic[1] == 'E' && elf_header->magic[2] == 'L' && elf_header->magic[3] == 'F') {
|
|
// it's a valid ELF image.
|
|
int arg_sz = 0;
|
|
int env_sz = 0;
|
|
int envp = 0;
|
|
int argp = 0;
|
|
int i;
|
|
int j;
|
|
int k;
|
|
|
|
unsigned int l;
|
|
|
|
while (argv[argp]) {
|
|
arg_sz += strlen(argv[argp++]) + 1;
|
|
}
|
|
while (env[envp]) {
|
|
env_sz += strlen(env[envp++]) + 1;
|
|
}
|
|
|
|
// point of no return...
|
|
|
|
// setup task name
|
|
memset(current_task->name, 0, 32);
|
|
for (i = strlen(name) - 1; i >= 0; i--) {
|
|
if (name[i] == '/' || name[i] == ':') {
|
|
break;
|
|
}
|
|
}
|
|
k = 0;
|
|
for (j = i + 1; j < 32; j++) {
|
|
if (name[j] == '\0') {
|
|
break;
|
|
} else {
|
|
current_task->name[k++] = name[j];
|
|
}
|
|
}
|
|
|
|
// close all file pointers...
|
|
// vfs_close_all();
|
|
|
|
// free old argv pointers
|
|
|
|
// copy argv and argc to a specific location
|
|
|
|
memset((char *)0xf0000000, 0, 64 * 0x1000);
|
|
|
|
unsigned int **virt = (unsigned int **)(0xf0000000);
|
|
virt[0] = (unsigned int *)0xf0000010;
|
|
virt[1] = (unsigned int *)(0xf0000010 + ((argp + 1) * 4));
|
|
virt[2] = (unsigned int *)argp;
|
|
virt[3] = (unsigned int *)envp;
|
|
|
|
unsigned int argv_data_start = (unsigned int)virt[1] + ((envp + 1) * 4);
|
|
|
|
unsigned int *argv_cont = (unsigned int *)virt[0];
|
|
unsigned int *envp_cont = (unsigned int *)virt[1];
|
|
|
|
for (i = 0; i < argp; i++) {
|
|
memcpy((unsigned char *)argv_data_start, argv[i], strlen(argv[i]) + 1);
|
|
argv_cont[i] = argv_data_start;
|
|
argv_data_start += strlen(argv[i]) + 1;
|
|
}
|
|
argv_cont[i] = 0;
|
|
|
|
unsigned int envp_data_start = argv_data_start;
|
|
|
|
for (i = 0; i < envp; i++) {
|
|
memcpy((unsigned char *)envp_data_start, env[i], strlen(env[i]) + 1);
|
|
envp_cont[i] = envp_data_start;
|
|
envp_data_start += strlen(env[i]) + 1;
|
|
}
|
|
envp_cont[i] = 0;
|
|
|
|
int eip = elf_header->entry;
|
|
|
|
mem_clear_user_pages(current_task);
|
|
|
|
ivld_cr3();
|
|
|
|
dbfree(current_task->user_pages, "execve: free user pages");
|
|
|
|
current_task->user_pages_cnt = 0;
|
|
current_task->user_pages_at = 0x40000000;
|
|
current_task->user_pages = (void *)0;
|
|
|
|
for (i = 0; i < elf_header->num_phs; i++) {
|
|
elf_seg_t *seg = (elf_seg_t *)(exeimage + elf_header->phtab_offset + elf_header->phtab_ent_size * i);
|
|
if (seg->type == 2 || seg->type == 5) {
|
|
return -1;
|
|
} else if (seg->type == 1) {
|
|
if (current_task->user_pages_at < seg->virt_adr + seg->mem_size) {
|
|
for (l = current_task->user_pages_at; l < round_up_to_page(seg->virt_adr + seg->mem_size); l += 0x1000) {
|
|
current_task->user_pages_at = l + 0x1000;
|
|
mem_map_user_page(l);
|
|
}
|
|
}
|
|
memcpy((unsigned char *)seg->virt_adr, (unsigned char *)(exeimage + seg->offset), seg->disk_size);
|
|
if (seg->mem_size > seg->disk_size) {
|
|
memset((unsigned char *)(seg->virt_adr + seg->disk_size), 0, seg->mem_size - seg->disk_size);
|
|
}
|
|
}
|
|
}
|
|
|
|
r->eip = eip;
|
|
r->cs = 0x1b;
|
|
r->ss = r->es = r->gs = r->fs = r->ds = 0x23;
|
|
r->eflags = 0x200;
|
|
r->useresp = current_task->ustack;
|
|
} else {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|