/* * Allocate more memory to the indicated bucket. */ static void morecore(int bucket) { char *buf; union overhead *op; size_t sz; /* size of desired block */ int amt; /* amount to allocate */ int nblks; /* how many blocks we get */ /* * sbrk_size <= 0 only for big, FLUFFY, requests (about * 2^30 bytes on a VAX, I think) or for a negative arg. */ sz = 1 << (bucket + 3); #ifdef MALLOC_DEBUG ASSERT(sz > 0); #else if (sz <= 0) return; #endif if (sz < pagesz) { amt = pagesz; nblks = amt / sz; } else { amt = sz + pagesz; nblks = 1; } if (amt > pagepool_end - pagepool_start) if (__morepages(amt/pagesz) == 0) return; /* * XXXRW: For now, depend on a global $c0 -- but shouldn't need to as * we could be deriving from heap. */ buf = cheri_setoffset(cheri_getdefault(), pagepool_start); buf = cheri_setbounds(buf, amt); pagepool_start += amt; /* * Add new memory allocated to that on * free list for this hash bucket. */ nextf[bucket] = op = cheri_setbounds(buf, sz); while (--nblks > 0) { op->ov_next = (union overhead *)cheri_setbounds(buf + sz, sz); buf += sz; op = op->ov_next; } }
context_t act_init(context_t own_context, init_info_t* info, size_t init_base, size_t init_entry) { KERNEL_TRACE("init", "activation init"); internel_if.message_send = kernel_seal(act_send_message_get_trampoline(), act_ref_type); internel_if.message_reply = kernel_seal(act_send_return_get_trampoline(), act_sync_ref_type); setup_syscall_interface(&internel_if); kernel_next_act = 0; // This is a dummy. Our first context has already been created reg_frame_t frame; bzero(&frame, sizeof(struct reg_frame)); // Register the kernel (exception) activation act_t * kernel_act = &kernel_acts[0]; act_register(&frame, &kernel_queue.queue, "kernel", status_terminated, NULL, cheri_getbase(cheri_getpcc())); /* The kernel context already exists and we set it here */ kernel_act->context = own_context; // Create and register the init activation KERNEL_TRACE("act", "Retroactively creating init activation"); /* Not a dummy here. We will subset our own c0/pcc for init. init is loaded directly after the kernel */ bzero(&frame, sizeof(struct reg_frame)); size_t length = cheri_getlen(cheri_getdefault()) - init_base; frame.cf_c0 = cheri_setbounds(cheri_setoffset(cheri_getdefault(), init_base), length); capability pcc = cheri_setbounds(cheri_setoffset(cheri_getpcc(), init_base), length); KERNEL_TRACE("act", "assuming init has virtual entry point %lx", init_entry); frame.cf_c12 = frame.cf_pcc = cheri_setoffset(pcc, init_entry); /* provide config info to init. c3 is the conventional register */ frame.cf_c3 = info; act_t * init_act = &kernel_acts[namespace_num_boot]; act_register_create(&frame, &init_queue.queue, "init", status_alive, NULL); /* The boot activation should be the current activation */ sched_schedule(init_act); return init_act->context; }
void * kernel_malloc(size_t nbytes) { union overhead *op; int bucket; size_t amt; /* * First time malloc is called, setup page size and * align break pointer so all data will be page aligned. */ if (pagesz == 0) { pagesz = CHERIOS_PAGESIZE; init_pagebucket(); __init_heap(pagesz); } kernel_assert(pagesz != 0); /* * Convert amount of memory requested into closest block size * stored in hash buckets which satisfies request. * Account for space used per block for accounting. */ if (nbytes <= pagesz - sizeof (*op)) { amt = 32; /* size of first bucket */ bucket = 2; } else { amt = pagesz; bucket = pagebucket; } while (nbytes > (size_t)amt - sizeof(*op)) { amt <<= 1; if (amt == 0) return (NULL); bucket++; } /* * If nothing in hash bucket right now, * request more memory from the system. */ if ((op = nextf[bucket]) == NULL) { morecore(bucket); if ((op = nextf[bucket]) == NULL) return (NULL); } /* remove from linked list */ nextf[bucket] = op->ov_next; op->ov_magic = MAGIC; op->ov_index = bucket; return (cheri_setbounds(op + 1, nbytes)); }
char *localmalloc(int size) { char *blah; if (size>remaining) { temp = mmap(NULL, 256<<20, PROT_RW, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if(temp == MAP_FAILED) printf("Error! malloc returns null\n"); remaining = 256<<20; } blah = temp; temp += size; remaining -= size; return cheri_setbounds(blah, size); }
void * kernel_realloc(void *cp, size_t nbytes) { size_t cur_space; /* Space in the current bucket */ size_t smaller_space; /* Space in the next smaller bucket */ union overhead *op; char *res; if (cp == NULL) return (kernel_malloc(nbytes)); op = find_overhead(cp); if (op == NULL) return (NULL); cur_space = (1 << (op->ov_index + 3)) - sizeof(*op); /* avoid the copy if same size block */ /* * XXX-BD: Arguably we should be tracking the actual allocation * not just the bucket size so that we can do a full malloc+memcpy * when the caller has restricted the length of the pointer passed * realloc() but is growing the buffer within the current bucket. * * As it is, this code contains a leak where realloc recovers access * to the contents in foo: * char *foo = malloc(10); * strcpy(foo, "abcdefghi"); * cheri_setbouds(foo, 5); * foo = realloc(foo, 10); */ smaller_space = (1 << (op->ov_index + 2)) - sizeof(*op); if (nbytes <= cur_space && nbytes > smaller_space) return (cheri_andperm(cheri_setbounds(op + 1, nbytes), cheri_getperm(cp))); if ((res = kernel_malloc(nbytes)) == NULL) return (NULL); /* * Only copy data the caller had access to even if this is less * than the size of the original allocation. This risks surprise * for some programmers, but to do otherwise risks information leaks. */ memcpy(res, cp, (nbytes <= cheri_getlen(cp)) ? nbytes : cheri_getlen(cp)); res = cheri_andperm(res, cheri_getperm(cp)); kernel_free(cp); return (res); }
void bootloader_main(void) { /* Init hardware */ hw_init(); /* Initialize elf-loader environment */ init_elf_loader(); /* Load the nano kernel. Doing this will install exception vectors */ boot_printf("Boot: loading nano kernel ...\n"); nano_init_t * nano_init = (nano_init_t *)load_nano(); //We have to rederive this as an executable cap nano_init = (nano_init_t*)cheri_setoffset(cheri_getpcc(),cheri_getoffset(nano_init)); /* TODO: we could have some boot exception vectors if we want exception handling in boot. */ /* These should be in ROM as a part of the boot image (i.e. make a couple more dedicated sections */ cp0_status_bev_set(0); boot_printf("Boot: loading kernel ...\n"); size_t entry = load_kernel(); boot_printf("Boot: loading init ...\n"); boot_info_t *bi = load_init(); size_t invalid_length = bi->init_end; capability phy_start = cheri_setbounds(cheri_setoffset(cheri_getdefault(), MIPS_KSEG0), invalid_length); /* Do we actually need this? */ //boot_printf("Invalidating %p length %lx:\n", phy_start, invalid_length); //caches_invalidate(phy_start, invalid_length); register_t mem_size = bi->init_end - bi->nano_end; /* Jumps to the nano kernel init. This will completely destroy boot and so we can never return here. * All registers will be cleared apart from a specified few. mem_size of memory will be left unmanaged and the * rest will be returned as a reservation. The third argument is an extra argument to the kernel */ boot_printf("Jumping to nano kernel...\n"); BOOT_PRINT_CAP(nano_init); nano_init(mem_size, entry, bi->init_begin - bi->kernel_begin, bi->init_entry); }