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