BCQ touch-ups (XCC)
[akaros.git] / kern / src / elf.c
index 30eea88..8db3e45 100644 (file)
@@ -8,12 +8,34 @@
 #include <smp.h>
 #include <arch/arch.h>
 
-#ifdef KERN64
+#ifdef CONFIG_64BIT
 # define elf_field(obj, field) (elf64 ? (obj##64)->field : (obj##32)->field)
 #else
 # define elf_field(obj, field) ((obj##32)->field)
 #endif
 
+/* Check if the file is valid elf file (i.e. by checking for ELF_MAGIC in the
+ * header) */
+bool is_valid_elf(struct file *f)
+{
+       elf64_t h;
+       off64_t o = 0;
+       struct proc *c = switch_to(0);
+
+       if (f->f_op->read(f, (char*)&h, sizeof(elf64_t), &o) != sizeof(elf64_t)) {
+               goto fail;
+       }
+       if (h.e_magic != ELF_MAGIC) {
+               goto fail;
+       }
+success:
+       switch_back(0, c);
+       return TRUE;
+fail:
+       switch_back(0, c);
+       return FALSE;
+}
+
 /* We need the writable flag for ld.  Even though the elf header says it wants
  * RX (and not W) for its main program header, it will page fault (eip 56f0,
  * 46f0 after being relocated to 0x1000, va 0x20f4). */
@@ -24,14 +46,13 @@ static int load_one_elf(struct proc *p, struct file *f, uintptr_t pgoffset,
        ei->phdr = -1;
        ei->dynamic = 0;
        ei->highest_addr = 0;
-       off_t f_off = 0;
+       off64_t f_off = 0;
        void* phdrs = 0;
        int mm_perms, mm_flags = MAP_FIXED;
        
        /* When reading on behalf of the kernel, we need to make sure no proc is
         * "current".  This is a bit ghetto (TODO: KFOP) */
-       struct proc *cur_proc = current;
-       current = 0;
+       struct proc *old_proc = switch_to(0);
 
        /* Read in ELF header. */
        elf64_t elfhdr_storage;
@@ -53,12 +74,18 @@ static int load_one_elf(struct proc *p, struct file *f, uintptr_t pgoffset,
                printk("[kernel] load_one_elf: ID as both 32 and 64 bit\n");
                goto fail;
        }
-       #ifndef KERN64
+       #ifndef CONFIG_64BIT
        if (elf64) {
                printk("[kernel] load_one_elf: 64 bit elf on 32 bit kernel\n");
                goto fail;
        }
        #endif
+       #ifdef CONFIG_X86_64
+       if (elf32) {
+               printk("[kernel] load_one_elf: 32 bit elf on 64 bit kernel\n");
+               goto fail;
+       }
+       #endif
 
        size_t phsz = elf64 ? sizeof(proghdr64_t) : sizeof(proghdr32_t);
        uint16_t e_phnum = elf_field(elfhdr, e_phnum);
@@ -173,11 +200,23 @@ static int load_one_elf(struct proc *p, struct file *f, uintptr_t pgoffset,
                                                goto fail;
                                        }
 
-                                       /* Zero the end of it. */
+                                       /* Zero the end of it.  This is a huge pain in the ass.  The
+                                        * filesystems should zero out the last bits of a page if
+                                        * the file doesn't fill the last page.  But we're dealing
+                                        * with windows into otherwise complete files. */
                                        pte_t *pte = pgdir_walk(p->env_pgdir, (void*)last_page, 0);
-                                       assert(pte);
-                                       void* last_page_kva = ppn2kva(PTE2PPN(*pte));
-                                       memset(last_page_kva + partial, 0, PGSIZE - partial);
+                                       /* if we were able to get a PTE, then there is a real page
+                                        * backing the VMR, and we need to zero the excess.  if
+                                        * there isn't, then the page fault code should handle it.
+                                        * since we set populate above, we should have a PTE, except
+                                        * in cases where the offset + len window exceeded the file
+                                        * size.  in this case, we let them mmap it, but didn't
+                                        * populate it.  there will be a PF right away if someone
+                                        * tries to use this.  check out do_mmap for more info. */
+                                       if (pte) {
+                                               void* last_page_kva = ppn2kva(PTE2PPN(*pte));
+                                               memset(last_page_kva + partial, 0, PGSIZE - partial);
+                                       }
 
                                        filesz = ROUNDUP(filesz, PGSIZE);
                                }
@@ -213,7 +252,7 @@ static int load_one_elf(struct proc *p, struct file *f, uintptr_t pgoffset,
 fail:
        if (phdrs)
                kfree(phdrs);
-       current = cur_proc;
+       switch_back(0, old_proc);
        return ret;
 }
 
@@ -227,8 +266,13 @@ int load_elf(struct proc* p, struct file* f)
                struct file *interp = do_file_open(ei.interp, 0, 0);
                if (!interp)
                        return -1;
-               /* Load dynamic linker one page into the address space */
-               int error = load_one_elf(p, interp, 1, &interp_ei, TRUE);
+               /* Load dynamic linker at 1M. Obvious MIB joke avoided.
+                * It used to be loaded at page 1, but the existence of valid addresses
+                * that low masked bad derefs through NULL pointer structs. This in turn
+                * helped us waste a full day debugging a bug in the Go runtime. True!
+                * Note that MMAP_LOWEST_VA also has this value but we want to make this
+                * explicit. */
+               int error = load_one_elf(p, interp, MiB>>12, &interp_ei, TRUE);
                kref_put(&interp->f_kref);
                if (error)
                        return -1;
@@ -239,9 +283,6 @@ int load_elf(struct proc* p, struct file* f)
                            {ELF_AUX_PHENT, sizeof(proghdr32_t)},
                            {ELF_AUX_PHNUM, ei.phnum},
                            {ELF_AUX_ENTRY, ei.entry},
-                           #ifdef __sparc_v8__
-                           {ELF_AUX_HWCAP, ELF_HWCAP_SPARC_FLUSH},
-                           #endif
                            {0, 0}};
 
        // put auxp after argv, envp in procinfo
@@ -256,13 +297,10 @@ int load_elf(struct proc* p, struct file* f)
        memcpy(p->procinfo->argp+auxp_pos,auxp,sizeof(auxp));
 
        uintptr_t core0_entry = ei.dynamic ? interp_ei.entry : ei.entry;
-       proc_init_trapframe(&p->env_tf,0,core0_entry,USTACKTOP);
+       proc_init_ctx(&p->scp_ctx, 0, core0_entry, USTACKTOP, 0);
        p->env_entry = ei.entry;
 
        int flags = MAP_FIXED | MAP_ANONYMOUS;
-       #ifdef __sparc_v8__
-       flags |= MAP_POPULATE; // SPARC stacks must be mapped in
-       #endif
        uintptr_t stacksz = USTACK_NUM_PAGES*PGSIZE;
        if (do_mmap(p, USTACKTOP-stacksz, stacksz, PROT_READ | PROT_WRITE,
                    flags, NULL, 0) == MAP_FAILED)