1/** 2 * \file 3 * \brief ACPI daemon Flounder handler functions 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2011, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14#include <stdio.h> 15 16#include <barrelfish/barrelfish.h> 17#include <barrelfish/nameservice_client.h> 18#include <if/acpi_defs.h> 19#include <acpi.h> 20#include <mm/mm.h> 21#include "acpi_shared.h" 22#include "acpi_debug.h" 23 24extern bool mm_debug; 25 26// XXX: proper cap handling (del etc.) 27static void mm_alloc_range_proxy_handler(struct acpi_binding* b, uint8_t sizebits, 28 genpaddr_t minbase, genpaddr_t maxlimit) 29{ 30 ACPI_DEBUG("mm_alloc_range_proxy_handler: sizebits: %d, minbase: 0x%lx maxlimit: 0x%lx\n", 31 sizebits, minbase, maxlimit); 32 33 struct capref devframe = NULL_CAP; 34 /* errval_t err = mm_alloc_range(&pci_mm_physaddr, sizebits, minbase, maxlimit, &devframe, NULL); */ 35 errval_t err = mm_realloc_range(&pci_mm_physaddr, sizebits, minbase, &devframe); 36 if (err_is_fail(err)) { 37 DEBUG_ERR(err, "mm realloc range failed...\n"); 38 } 39 40 err = b->tx_vtbl.mm_alloc_range_proxy_response(b, NOP_CONT, devframe, err); 41 assert(err_is_ok(err)); 42} 43 44static void mm_realloc_range_proxy_handler(struct acpi_binding* b, uint8_t sizebits, 45 genpaddr_t minbase) 46{ 47 ACPI_DEBUG("mm_realloc_range_proxy_handler: sizebits: %d, " 48 "minbase: 0x%"PRIxGENPADDR"\n", 49 sizebits, minbase); 50 51 struct capref devframe = NULL_CAP; 52 errval_t err = mm_realloc_range(&pci_mm_physaddr, sizebits, minbase, &devframe); 53 if (err_is_fail(err)) { 54 DEBUG_ERR(err, "mm alloc range failed...\n"); 55 } 56 57 err = b->tx_vtbl.mm_realloc_range_proxy_response(b, NOP_CONT, devframe, err); 58 assert(err_is_ok(err)); 59} 60 61// XXX: proper cap handling 62static void mm_free_proxy_handler(struct acpi_binding* b, struct capref devframe, 63 uint64_t base, uint8_t sizebits) 64{ 65 ACPI_DEBUG("mm_free_proxy_handler: base: 0x%"PRIx64", sizebits: %d\n", base, sizebits); 66 67 errval_t err = mm_free(&pci_mm_physaddr, devframe, base, sizebits); 68 if (err_is_fail(err)) { 69 DEBUG_ERR(err, "mm free failed...\n"); 70 } 71 72 err = b->tx_vtbl.mm_free_proxy_response(b, NOP_CONT, err); 73 assert(err_is_ok(err)); 74} 75 76static void enable_interrupt_handler(struct acpi_binding* b, uint32_t gsi, 77 coreid_t dest, uint32_t vector) 78{ 79 errval_t err = SYS_ERR_OK; 80 err = enable_and_route_interrupt(gsi, dest, vector); 81 82 err = b->tx_vtbl.enable_and_route_interrupt_response(b, NOP_CONT, err); 83 assert(err_is_ok(err)); 84 85} 86 87static inline bool mcfg_correct_length(uint32_t header_len) 88{ 89 return header_len >= 90 sizeof(ACPI_TABLE_MCFG) + sizeof(ACPI_MCFG_ALLOCATION); 91} 92 93static void get_pcie_confspace(struct acpi_binding* b) 94{ 95 ACPI_DEBUG("get_pcie_confspace\n"); 96 97 errval_t err; 98 ACPI_STATUS as; 99 ACPI_TABLE_HEADER *mcfg_header; 100 101 as = AcpiGetTable("MCFG", 1, &mcfg_header); 102 if (ACPI_SUCCESS(as) && mcfg_correct_length(mcfg_header->Length)) { 103 104 ACPI_MCFG_ALLOCATION *mcfg = (void*) mcfg_header 105 + sizeof(ACPI_TABLE_MCFG); 106 ACPI_DEBUG( 107 "PCIe enhanced configuration region at 0x%"PRIx64" " 108 "(segment %u, buses %u-%u)\n", mcfg->Address, 109 mcfg->PciSegment, mcfg->StartBusNumber, mcfg->EndBusNumber); 110 111 err = b->tx_vtbl.get_pcie_confspace_response(b, NOP_CONT, SYS_ERR_OK, 112 mcfg->Address, mcfg->PciSegment, mcfg->StartBusNumber, 113 mcfg->EndBusNumber); 114 115 } else { 116 ACPI_DEBUG("No MCFG table found -> no PCIe enhanced configuration\n"); 117 err = b->tx_vtbl.get_pcie_confspace_response(b, NOP_CONT, 118 ACPI_ERR_NO_MCFG_TABLE, 0, 0, 0, 0); 119 } 120 121 assert(err_is_ok(err)); 122} 123 124static void get_path_name(ACPI_HANDLE handle, char* name, size_t len) 125{ 126 ACPI_BUFFER buf = { .Length = len, .Pointer = name }; 127 ACPI_STATUS s; 128 129 s = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf); 130 assert(ACPI_SUCCESS(s)); 131} 132 133static void read_irq_table(struct acpi_binding* b, const char* pathname, 134 acpi_pci_address_t addr, uint8_t bus) 135{ 136 ACPI_DEBUG("read_irq_table: (parent)%s, (%"PRIu8",%"PRIu8",%"PRIu8"), %"PRIu8"\n", 137 pathname == NULL ? "NULL" : pathname, addr.bus, addr.device, addr.function, bus); 138 139 errval_t err; 140 ACPI_STATUS as; 141 ACPI_HANDLE handle; 142 143 as = AcpiGetHandle(NULL, (CONST_CAST)pathname, &handle); 144 if (ACPI_SUCCESS(as)) { 145 ACPI_HANDLE child; 146 err = acpi_get_irqtable_device(handle, addr, &child, bus); 147 148 if(err_is_fail(err)){ 149 ACPI_DEBUG("get_irq_table failed.\n"); 150 err = b->tx_vtbl.read_irq_table_response(b, NOP_CONT, err, NULL); 151 assert(err_is_ok(err)); 152 } else { 153 char name[128]; 154 get_path_name(child, name, 128); 155 ACPI_DEBUG("Sending back path name: %s\n", name); 156 157 err = b->tx_vtbl.read_irq_table_response(b, NOP_CONT, SYS_ERR_OK, name); 158 assert(err_is_ok(err)); 159 } 160 } 161 else { 162 ACPI_DEBUG("Unknown ACPI Handle for path: %s\n", pathname); 163 err = b->tx_vtbl.read_irq_table_response(b, NOP_CONT, 164 ACPI_ERR_INVALID_PATH_NAME, NULL); 165 assert(err_is_ok(err)); 166 } 167} 168 169 170 171static void set_device_irq_handler(struct acpi_binding *b, const char* device, uint32_t irq) 172{ 173 errval_t err = set_device_irq(device,irq); 174 err = b->tx_vtbl.set_device_irq_response(b, NOP_CONT, err); 175 assert(err_is_ok(err)); 176} 177 178static void reset_handler(struct acpi_binding *b) 179{ 180 if (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) { 181 printf("Resetting machine via ACPI...\n"); 182 ACPI_STATUS as = AcpiReset(); 183 if (ACPI_FAILURE(as)) { 184 printf("ACPI reset failed\n"); 185 } 186 } 187 188 printf("Resetting machine via syscall...\n"); 189 errval_t err = sys_reboot(); 190 if (err_is_fail(err)) { 191 DEBUG_ERR(err, "reboot syscall failed"); 192 } 193} 194 195static void sleep_handler(struct acpi_binding *b, uint32_t state) 196{ 197 printf("Entering S%"PRIu32" sleep state via ACPI...\n", state); 198 ACPI_STATUS as = AcpiEnterSleepStatePrep(state); 199 if (!ACPI_SUCCESS(as)) { 200 printf("AcpiEnterSleepStatePrep failed\n"); 201 return; 202 } 203 204 as = AcpiEnterSleepState(state); 205 if (!ACPI_SUCCESS(as)) { 206 printf("AcpiEnterSleepState failed\n"); 207 } 208} 209 210 211static 212ACPI_STATUS get_handle_handler_callback( 213 ACPI_HANDLE Object, 214 UINT32 NestingLevel, 215 void *Context, 216 void **ReturnValue) { 217 218 ACPI_STATUS as; 219 ACPI_DEVICE_INFO *device_info; 220 as = AcpiGetObjectInfo(Object, &device_info); 221 if (ACPI_FAILURE(as)) { 222 debug_printf("AcpiGetObjectInfo failed: %x\n", as); 223 return AE_OK; 224 } 225 226 if (device_info->HardwareId.Length && 227 !strncmp(device_info->HardwareId.String, Context, device_info->HardwareId.Length)) { 228 debug_printf("device HardwareId=%s UniqueId=%s\n", device_info->HardwareId.String, device_info->UniqueId.String); 229 *ReturnValue = Object; 230 } 231 ACPI_FREE(device_info); 232 return AE_OK; 233} 234 235static void get_handle_handler(struct acpi_binding *b, const char *dev_id) 236{ 237 errval_t err = SYS_ERR_OK;; 238 239 debug_printf("Looking up handle for device '%s'\n", dev_id); 240 241 ACPI_STATUS s; 242 ACPI_HANDLE handle = NULL; 243 244 s = AcpiGetDevices(NULL, get_handle_handler_callback, (CONST_CAST)dev_id, &handle); 245 if (ACPI_FAILURE(s)) { 246 debug_printf("Looking up handle failed: %d\n", s); 247 err = ACPI_ERR_INVALID_HANDLE; 248 } else if (handle == NULL) { 249 err = ACPI_ERR_OBJECT_NOT_FOUND; 250 } 251 252 //out uint64 handle, out errval err 253 err = b->tx_vtbl.get_handle_response(b, NOP_CONT, (uint64_t)handle, err); 254 assert(err_is_ok(err)); 255} 256 257static void eval_integer_handler(struct acpi_binding *b, 258 uint64_t handle, const char *path) 259{ 260 errval_t err = SYS_ERR_OK; 261 262 ACPI_STATUS s; 263 ACPI_INTEGER val = 0; 264 s = acpi_eval_integer((ACPI_HANDLE)handle, path, &val); 265 if (ACPI_FAILURE(s)) { 266 if (s == AE_BAD_PATHNAME) { 267 err = ACPI_ERR_INVALID_PATH_NAME; 268 } else { 269 err = ACPI_ERR_INVALID_HANDLE; 270 } 271 val = 0; 272 } 273 274 debug_printf("eval_integer_handler\n"); 275 err = b->tx_vtbl.eval_integer_response(b, NOP_CONT, val, err); 276} 277 278 279struct acpi_rx_vtbl acpi_rx_vtbl = { 280 .get_pcie_confspace_call = get_pcie_confspace, 281 .read_irq_table_call = read_irq_table, 282 .set_device_irq_call = set_device_irq_handler, 283 .enable_and_route_interrupt_call = enable_interrupt_handler, 284 285 .get_handle_call = get_handle_handler, 286 .eval_integer_call = eval_integer_handler, 287 288 .mm_alloc_range_proxy_call = mm_alloc_range_proxy_handler, 289 .mm_realloc_range_proxy_call = mm_realloc_range_proxy_handler, 290 .mm_free_proxy_call = mm_free_proxy_handler, 291 292 .reset_call = reset_handler, 293 .sleep_call = sleep_handler, 294}; 295 296static void export_callback(void *st, errval_t err, iref_t iref) 297{ 298 assert(err_is_ok(err)); 299 300 err = nameservice_register("acpi", iref); 301 if (err_is_fail(err)) { 302 USER_PANIC_ERR(err, "nameservice_register failed"); 303 } 304 ACPI_DEBUG("acpi service exported\n"); 305} 306 307static errval_t connect_callback(void *cst, struct acpi_binding *b) 308{ 309 ACPI_DEBUG("acpi service get connection\n"); 310 b->rx_vtbl = acpi_rx_vtbl; 311 b->st = NULL; 312 313 return SYS_ERR_OK; 314} 315 316void start_service(void) 317{ 318 ACPI_DEBUG("start_service\n"); 319 320 acpi_service_arch_init(&acpi_rx_vtbl); 321 322 errval_t r = acpi_export(NULL, export_callback, connect_callback, 323 get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT); 324 assert(err_is_ok(r)); 325 326 ACPI_DEBUG("start_service: terminated\n"); 327} 328