1/** 2 * \file acpi_generic.c 3 * \brief 4 */ 5 6 7/* 8 * Copyright (c) 2017 ETH Zurich. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16// Memory allocator instance for physical address regions and platform memory 17 18#include <barrelfish/barrelfish.h> 19#include <barrelfish/capabilities.h> 20#include <if/monitor_blocking_defs.h> 21 22#include <mm/mm.h> 23 24#include <skb/skb.h> 25 26#include "acpi_debug.h" 27#include "acpi_shared.h" 28#include "acpi_allocators.h" 29 30 31struct mm pci_mm_physaddr; 32 33struct capref physical_caps; 34struct capref my_devframes_cnode; 35 36// XXX should be from offests 37#define PADDR_SPACE_SIZE_BITS 48 38#define MAXCHILDBITS 4 ///< Max branching of BTree nodes 39 40errval_t acpi_allocators_init(void) 41{ 42 errval_t err, msgerr; 43 44 ACPI_DEBUG("acpi: initializing allocators\n"); 45 46 struct monitor_blocking_binding *cl = get_monitor_blocking_binding(); 47 assert(cl != NULL); 48 49 ACPI_DEBUG("acpi: obtaining boot info...\n"); 50 51 // Get the bootinfo and map it in. 52 struct capref bootinfo_frame; 53 size_t bootinfo_size; 54 struct bootinfo *bootinfo; 55 56 err = slot_alloc(&bootinfo_frame); 57 if (err_is_fail(err)) { 58 USER_PANIC_ERR(err, "slot_alloc for monitor->get_bootinfo"); 59 } 60 61 msgerr = cl->rpc_tx_vtbl.get_bootinfo(cl, &err, &bootinfo_frame, &bootinfo_size); 62 if (err_is_fail(msgerr) || err_is_fail(err)) { 63 USER_PANIC_ERR(err_is_fail(msgerr) ? msgerr : err, "failed in get_bootinfo"); 64 } 65 66 err = vspace_map_one_frame((void**)&bootinfo, bootinfo_size, bootinfo_frame, 67 NULL, NULL); 68 if (err_is_fail(err)) { 69 DEBUG_ERR(err, "mapping of bootinfo frame failed\n"); 70 return err; 71 } 72 73 ACPI_DEBUG("acpi: boot info mapped [%p..%p]\n", bootinfo, 74 bootinfo + bootinfo_size); 75 76 77 ACPI_DEBUG("acpi: setup slot allocator with %" PRIu64 " slots\n", L2_CNODE_SLOTS); 78 79 /* Initialize the memory allocator to handle PhysAddr caps */ 80 static struct range_slot_allocator devframes_allocator; 81 err = range_slot_alloc_init(&devframes_allocator, L2_CNODE_SLOTS, NULL); 82 if (err_is_fail(err)) { 83 return err_push(err, LIB_ERR_SLOT_ALLOC_INIT); 84 } 85 86 err = range_slot_alloc_refill(&devframes_allocator, L2_CNODE_SLOTS); 87 if (err_is_fail(err)) { 88 return err_push(err, LIB_ERR_SLOT_ALLOC_INIT); 89 } 90 ACPI_DEBUG("acpi: setup memory manager for physaddr region\n"); 91 92 err = mm_init(&pci_mm_physaddr, ObjType_DevFrame, 0, 48, 93 /* This next parameter is important. It specifies the maximum 94 * amount that a cap may be "chunked" (i.e. broken up) at each 95 * level in the allocator. Setting it higher than 1 reduces the 96 * memory overhead of keeping all the intermediate caps around, 97 * but leads to problems if you chunk up a cap too small to be 98 * able to allocate a large subregion. This caused problems 99 * for me with a large framebuffer... -AB 20110810 */ 100 1, /*was DEFAULT_CNODE_BITS,*/ 101 slab_default_refill, slot_alloc_dynamic, 102 slot_refill_dynamic, &devframes_allocator, false); 103 if (err_is_fail(err)) { 104 return err_push(err, MM_ERR_MM_INIT); 105 } 106 107 108 ACPI_DEBUG("acpi: REFILL=%p %p\n", slot_refill_dynamic, pci_mm_physaddr.slot_refill); 109 110 struct capref requested_caps; 111 112 113 // XXX: The code below is confused about gen/l/paddrs. 114 // Caps should be managed in genpaddr, while the bus mgmt must be in lpaddr. 115 116 ACPI_DEBUG("acpi: obtaining CNODE containing physaddr caps\n"); 117 118 // Here we get a cnode cap, so we need to put it somewhere in the root cnode 119 // As we already have a reserved slot for a phyaddr caps cnode, we put it there 120 err = slot_alloc(&requested_caps); 121 if (err_is_fail(err)) { 122 USER_PANIC_ERR(err, "slot_alloc for monitor->get_phyaddr_cap"); 123 } 124 err = cl->rpc_tx_vtbl.get_phyaddr_cap(cl, &requested_caps, &msgerr); 125 assert(err_is_ok(err) && err_is_ok(msgerr)); 126 physical_caps = requested_caps; 127 128 struct capref pacn = { 129 .cnode = cnode_root, 130 .slot = ROOTCN_SLOT_PACN 131 }; 132 // Move phyaddr cap to ROOTCN_SLOT_PACN to conform to 2 level cspace 133 err = cap_copy(pacn, requested_caps); 134 assert(err_is_ok(err)); 135 136 // Build the capref for the first physical address capability 137 struct capref phys_cap; 138 phys_cap.cnode = build_cnoderef(pacn, CNODE_TYPE_OTHER); 139 phys_cap.slot = 0; 140 141 ACPI_DEBUG("acpi: creating L2 cnode for device caps\n"); 142 143 struct cnoderef devcnode; 144 err = cnode_create_l2(&my_devframes_cnode, &devcnode); 145 if (err_is_fail(err)) { USER_PANIC_ERR(err, "cnode create"); } 146 struct capref devframe; 147 devframe.cnode = devcnode; 148 devframe.slot = 0; 149 150 if (bootinfo->regions_length > L2_CNODE_SLOTS) { 151 USER_PANIC("boot info has more regions (%d) than fit into L2 CNode (%d)", 152 bootinfo->regions_length, L2_CNODE_SLOTS); 153 } 154 155 ACPI_DEBUG("acpi: walking boot info to obtain the device regions\n"); 156 157 for (int i = 0; i < bootinfo->regions_length; i++) { 158 struct mem_region *mrp = &bootinfo->regions[i]; 159 160 if (mrp->mr_type == RegionType_Module) { 161// ACPI_DEBUG("acpi: region[%u] base=0x%" PRIxGENPADDR ", size=%zu, type=%u\n", 162// i, mrp->mr_base, mrp->mrmod_size, mrp->mr_type); 163 164 skb_add_fact("memory_region(16'%" PRIxGENPADDR ",%u,%zu,%u,%tu).", 165 mrp->mr_base, 0, mrp->mrmod_size, mrp->mr_type, 166 mrp->mrmod_data); 167 } 168 else { 169 // ACPI_DEBUG("acpi: region[%u] base=0x%" PRIxGENPADDR ", size=%zu, type=%u\n", 170 // i, mrp->mr_base, mrp->mr_bytes, mrp->mr_type); 171 172 skb_add_fact("memory_region(16'%" PRIxGENPADDR ",%u,%zu,%u,%tu).", 173 mrp->mr_base, 0, mrp->mr_bytes, mrp->mr_type, 174 mrp->mrmod_data); 175 } 176 177 if (mrp->mr_type == RegionType_PhyAddr || 178 mrp->mr_type == RegionType_PlatformData) { 179 ACPI_DEBUG("Region %d: %"PRIxGENPADDR" - %"PRIxGENPADDR" (%lu) bytes %s\n", 180 i, mrp->mr_base, mrp->mr_base + mrp->mr_bytes, mrp->mr_bytes, 181 mrp->mr_type == RegionType_PhyAddr ? 182 "physical address" : "platform data"); 183 184 err = cap_retype(devframe, phys_cap, 0, ObjType_DevFrame, mrp->mr_bytes, 1); 185 if (err_is_ok(err)) { 186 err = mm_add_multi(&pci_mm_physaddr, devframe, mrp->mr_bytes, 187 mrp->mr_base); 188 if (err_is_fail(err)) { 189 USER_PANIC_ERR(err, "adding region %d FAILED\n", i); 190 } 191 } else { 192 if (err_no(err) == SYS_ERR_REVOKE_FIRST) { 193 printf("cannot retype region %d: need to revoke first; ignoring it\n", i); 194 } else { 195 USER_PANIC_ERR(err, "error in retype\n"); 196 } 197 } 198 devframe.slot++; 199 phys_cap.slot++; 200 } 201 } 202 203 return acpi_allocators_init_arch(bootinfo); 204} 205