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