Exemplo n.º 1
0
/// Setup the module cnode, which contains frame caps to all multiboot modules
void create_module_caps(struct spawn_state *st)
{
    errval_t err;

    /* Create caps for multiboot modules */
    struct multiboot_modinfo *module =
        (struct multiboot_modinfo *)local_phys_to_mem(glbl_core_data->mods_addr);

    // Allocate strings area
    lpaddr_t mmstrings_phys = bsp_alloc_phys(BASE_PAGE_SIZE);
    lvaddr_t mmstrings_base = local_phys_to_mem(mmstrings_phys);
    lvaddr_t mmstrings = mmstrings_base;

    // create cap for strings area in first slot of modulecn
    assert(st->modulecn_slot == 0);
    err = caps_create_new(ObjType_Frame, mmstrings_phys, BASE_PAGE_BITS,
                          BASE_PAGE_BITS,
                          caps_locate_slot(CNODE(st->modulecn),
                                           st->modulecn_slot++));
    assert(err_is_ok(err));

    /* Walk over multiboot modules, creating frame caps */
    for (int i = 0; i < glbl_core_data->mods_count; i++) {
        struct multiboot_modinfo *m = &module[i];

        // Set memory regions within bootinfo
        struct mem_region *region =
            &bootinfo->regions[bootinfo->regions_length++];

        genpaddr_t remain = MULTIBOOT_MODULE_SIZE(*m);
        genpaddr_t base_addr = local_phys_to_gen_phys(m->mod_start);

        region->mr_type = RegionType_Module;
        region->mr_base = base_addr;
        region->mrmod_slot = st->modulecn_slot;  // first slot containing caps
        region->mrmod_size = remain;  // size of image _in bytes_
        region->mrmod_data = mmstrings - mmstrings_base; // offset of string in area

        // round up to page size for caps
        remain = ROUND_UP(remain, BASE_PAGE_SIZE);

        // Create max-sized caps to multiboot module in module cnode
        while (remain > 0) {
            assert((base_addr & BASE_PAGE_MASK) == 0);
            assert((remain & BASE_PAGE_MASK) == 0);

            // determine size of next chunk
            uint8_t block_size = bitaddralign(remain, base_addr);

            assert(st->modulecn_slot < (1UL << st->modulecn->cap.u.cnode.bits));
            // create as DevFrame cap to avoid zeroing memory contents
            err = caps_create_new(ObjType_DevFrame, base_addr, block_size,
                                  block_size,
                                  caps_locate_slot(CNODE(st->modulecn),
                                                   st->modulecn_slot++));
            assert(err_is_ok(err));

            // Advance by that chunk
            base_addr += ((genpaddr_t)1 << block_size);
            remain -= ((genpaddr_t)1 << block_size);
        }

        // Copy multiboot module string to mmstrings area
        strcpy((char *)mmstrings, MBADDR_ASSTRING(m->string));
        mmstrings += strlen(MBADDR_ASSTRING(m->string)) + 1;
        assert(mmstrings < mmstrings_base + BASE_PAGE_SIZE);
    }
}
Exemplo n.º 2
0
/// Create physical address range or RAM caps to unused physical memory
static void create_phys_caps(lpaddr_t init_alloc_addr)
{
	errval_t err;

	/* Walk multiboot MMAP structure, and create appropriate caps for memory */
	char *mmap_addr = MBADDR_ASSTRING(glbl_core_data->mmap_addr);
	genpaddr_t last_end_addr = 0;

	for(char *m = mmap_addr; m < mmap_addr + glbl_core_data->mmap_length;)
	{
		struct multiboot_mmap *mmap = (struct multiboot_mmap * SAFE)TC(m);

		debug(SUBSYS_STARTUP, "MMAP %llx--%llx Type %"PRIu32"\n",
				mmap->base_addr, mmap->base_addr + mmap->length,
				mmap->type);

		if (last_end_addr >= init_alloc_addr
				&& mmap->base_addr > last_end_addr)
		{
			/* we have a gap between regions. add this as a physaddr range */
			debug(SUBSYS_STARTUP, "physical address range %llx--%llx\n",
					last_end_addr, mmap->base_addr);

			err = create_caps_to_cnode(last_end_addr,
					mmap->base_addr - last_end_addr,
					RegionType_PhyAddr, &spawn_state, bootinfo);
			assert(err_is_ok(err));
		}

		if (mmap->type == MULTIBOOT_MEM_TYPE_RAM)
		{
			genpaddr_t base_addr = mmap->base_addr;
			genpaddr_t end_addr  = base_addr + mmap->length;

			// only map RAM which is greater than init_alloc_addr
			if (end_addr > local_phys_to_gen_phys(init_alloc_addr))
			{
				if (base_addr < local_phys_to_gen_phys(init_alloc_addr)) {
					base_addr = local_phys_to_gen_phys(init_alloc_addr);
				}
				debug(SUBSYS_STARTUP, "RAM %llx--%llx\n", base_addr, end_addr);

				assert(end_addr >= base_addr);
				err = create_caps_to_cnode(base_addr, end_addr - base_addr,
						RegionType_Empty, &spawn_state, bootinfo);
				assert(err_is_ok(err));
			}
		}
		else if (mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr))
		{
			/* XXX: The multiboot spec just says that mapping types other than
			 * RAM are "reserved", but GRUB always maps the ACPI tables as type
			 * 3, and things like the IOAPIC tend to show up as type 2 or 4,
			 * so we map all these regions as platform data
			 */
			debug(SUBSYS_STARTUP, "platform %llx--%llx\n", mmap->base_addr,
					mmap->base_addr + mmap->length);
			assert(mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr));
			err = create_caps_to_cnode(mmap->base_addr, mmap->length,
					RegionType_PlatformData, &spawn_state, bootinfo);
			assert(err_is_ok(err));
		}
        last_end_addr = mmap->base_addr + mmap->length;
        m += mmap->size + 4;
	}

    // Assert that we have some physical address space
    assert(last_end_addr != 0);

    if (last_end_addr < PADDR_SPACE_SIZE)
    {
    	/*
    	 * FIXME: adding the full range results in too many caps to add
    	 * to the cnode (and we can't handle such big caps in user-space
    	 * yet anyway) so instead we limit it to something much smaller
    	 */
    	genpaddr_t size = PADDR_SPACE_SIZE - last_end_addr;
    	const genpaddr_t phys_region_limit = 1ULL << 32; // PCI implementation limit
    	if (last_end_addr > phys_region_limit) {
    		size = 0; // end of RAM is already too high!
    	} else if (last_end_addr + size > phys_region_limit) {
    		size = phys_region_limit - last_end_addr;
    	}
    	debug(SUBSYS_STARTUP, "end physical address range %llx--%llx\n",
    			last_end_addr, last_end_addr + size);
    	err = create_caps_to_cnode(last_end_addr, size,
    			RegionType_PhyAddr, &spawn_state, bootinfo);
    	assert(err_is_ok(err));
    }
}
Exemplo n.º 3
0
/// Create physical address range or RAM caps to unused physical memory
static void create_phys_caps(lpaddr_t init_alloc_addr)
{
    errval_t err;

#ifndef __scc__
    // map first meg of RAM, which contains lots of crazy BIOS tables
    err = create_caps_to_cnode(0, X86_32_START_KERNEL_PHYS,
                               RegionType_PlatformData, &spawn_state, bootinfo);
    assert(err_is_ok(err));
#endif

    /* Walk multiboot MMAP structure, and create appropriate caps for memory */
    char *mmap_addr = MBADDR_ASSTRING(glbl_core_data->mmap_addr);
    genpaddr_t last_end_addr = 0;

    char *clean_mmap_addr;
    uint32_t clean_mmap_length;
    cleanup_bios_regions(mmap_addr, &clean_mmap_addr, &clean_mmap_length);


    for(char *m = mmap_addr; m < mmap_addr + glbl_core_data->mmap_length;) {
        struct multiboot_mmap *mmap = (struct multiboot_mmap * SAFE)TC(m);

        debug(SUBSYS_STARTUP, "MMAP %llx--%llx Type %"PRIu32"\n",
              mmap->base_addr, mmap->base_addr + mmap->length,
              mmap->type);

#if 0
        // XXX: Remove intersecting regions
        bool skip = false;
        for(int i = 0; i < bootinfo->regions_length; i++) {
            struct mem_region *r = &bootinfo->regions[i];

            // Remove intersecting regions (earlier additions take precedence)
            if((r->base + (1 << r->bits) >= mmap->base_addr
                && r->base + (1 << r->bits) <= mmap->base_addr + mmap->length)
               || (r->base >= mmap->base_addr
                   && r->base <= mmap->base_addr + mmap->length)) {
                skip = true;
                break;
            }
        }

        if(skip) {
            continue;
        }
#endif

        if (last_end_addr >= init_alloc_addr
            && mmap->base_addr > last_end_addr) {
            /* we have a gap between regions. add this as a physaddr range */
            debug(SUBSYS_STARTUP, "physical address range %llx--%llx\n",
                  last_end_addr, mmap->base_addr);

            err = create_caps_to_cnode(last_end_addr,
                                       mmap->base_addr - last_end_addr,
                                       RegionType_PhyAddr, &spawn_state, bootinfo);
            assert(err_is_ok(err));
        }

        if (mmap->type == MULTIBOOT_MEM_TYPE_RAM) {
            genpaddr_t base_addr = mmap->base_addr;
            genpaddr_t end_addr  = base_addr + mmap->length;

            // only map RAM which is greater than init_alloc_addr
            if (end_addr > local_phys_to_gen_phys(init_alloc_addr)) {
                if (base_addr < local_phys_to_gen_phys(init_alloc_addr)) {
                    base_addr = local_phys_to_gen_phys(init_alloc_addr);
                }

#ifndef CONFIG_PAE
                if(base_addr >= X86_32_PADDR_SPACE_SIZE) {
                    printk(LOG_NOTE, "skipping RAM [%llx--%llx] out of "
                           "mappable space\n", base_addr, end_addr);
                    last_end_addr = mmap->base_addr + mmap->length;
                    m += mmap->size + 4;
                    continue;
                }
                if(end_addr > X86_32_PADDR_SPACE_SIZE) {
                    printk(LOG_NOTE, "shortening RAM [%llx--%llx] to mappable "
                           "space [0--%llx]\n", base_addr, end_addr,
                           X86_32_PADDR_SPACE_LIMIT);
                    end_addr = X86_32_PADDR_SPACE_SIZE;
                }
#endif

#ifndef __scc__
                // XXX: Do not create ram caps for memory the kernel cannot
                // address to prevent kernel objects from being created there
                if(base_addr >= PADDR_SPACE_LIMIT) {
                    last_end_addr = mmap->base_addr + mmap->length;
                    m += mmap->size + 4;
                    continue;
                }
                if (end_addr > PADDR_SPACE_LIMIT) {
                    end_addr = PADDR_SPACE_LIMIT;
                }
#endif

                debug(SUBSYS_STARTUP, "RAM %llx--%llx\n", base_addr, end_addr);

                assert(end_addr >= base_addr);
                err = create_caps_to_cnode(base_addr, end_addr - base_addr,
                                           RegionType_Empty, &spawn_state, bootinfo);
                assert(err_is_ok(err));
            }
        } else if (mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr)) {
            /* XXX: The multiboot spec just says that mapping types other than
             * RAM are "reserved", but GRUB always maps the ACPI tables as type
             * 3, and things like the IOAPIC tend to show up as type 2 or 4,
             * so we map all these regions as platform data
             */
            debug(SUBSYS_STARTUP, "platform %llx--%llx\n", mmap->base_addr,
                  mmap->base_addr + mmap->length);
            assert(mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr));
            err = create_caps_to_cnode(mmap->base_addr, mmap->length,
                                       RegionType_PlatformData, &spawn_state, bootinfo);
            assert(err_is_ok(err));
        }

        last_end_addr = mmap->base_addr + mmap->length;
        m += mmap->size + 4;
    }

    // Assert that we have some physical address space
    assert(last_end_addr != 0);

    if (last_end_addr < X86_32_PADDR_SPACE_SIZE) {
        /*
         * FIXME: adding the full range results in too many caps to add
         * to the cnode (and we can't handle such big caps in user-space
         * yet anyway) so instead we limit it to something much smaller
         */
        genpaddr_t size = X86_32_PADDR_SPACE_SIZE - last_end_addr;
        const genpaddr_t phys_region_limit = 1ULL << 32; // PCI implementation limit
        if (last_end_addr > phys_region_limit) {
            size = 0; // end of RAM is already too high!
        } else if (last_end_addr + size > phys_region_limit) {
            size = phys_region_limit - last_end_addr;
        }
        debug(SUBSYS_STARTUP, "end physical address range %llx--%llx\n",
              last_end_addr, last_end_addr + size);
        err = create_caps_to_cnode(last_end_addr, size,
                                   RegionType_PhyAddr, &spawn_state, bootinfo);
        assert(err_is_ok(err));
    }
}