1/** 2 * \file 3 * \brief Code responsible for starting hpet 4 */ 5 6/* 7 * Copyright (c) 2018 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 15 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19 20#include <barrelfish/barrelfish.h> 21#include <skb/skb.h> 22#include <if/octopus_defs.h> 23#include <octopus/trigger.h> 24#include <acpi_client/acpi_client.h> 25#include <hw_records.h> 26#include <if/acpi_defs.h> 27 28#include "kaluga.h" 29 30#define DRIVER_CORE 0 31#define HPET_INT_CAP 1 // should change it to refer to the one in hpet.h 32 33errval_t start_hpet_driver(coreid_t where, struct module_info *driver, 34 char *record ) { 35 errval_t err; 36 static struct domain_instance *inst = NULL; 37 struct driver_instance *drv = NULL; 38 int64_t address = 0, uid = 0; 39 40 KALUGA_DEBUG("start_hpet_driver: record=%s\n", record); 41 err = oct_read(record, "_ { " HW_HPET_RECORD_FIELDS_READ " }", 42 &address, &uid); 43 if (err_is_fail(err)) { 44 DEBUG_ERR(err, "oct_read"); 45 goto out; 46 } 47 48 // Fail early 49 assert(address != 0); 50 51 errval_t msgerr; 52 53 struct capref arg_caps; 54 struct cnoderef argnode_ref; 55 err = cnode_create_l2(&arg_caps, &argnode_ref); 56 struct capref devcap = { 57 .cnode = argnode_ref, 58 .slot = 0 59 }; 60 61 struct capref devcap_tmp; 62 err = slot_alloc(&devcap_tmp); 63 assert(err_is_ok(err)); 64 65 // store mem caps 66 err = connect_to_acpi(); 67 if (err_is_fail(err)) { 68 DEBUG_ERR(err, "connect_to_acpi"); 69 goto out; 70 } 71 struct acpi_binding *acpi = get_acpi_binding(); 72 err = acpi->rpc_tx_vtbl.mm_alloc_range_proxy(acpi, BASE_PAGE_BITS, address, 73 address + BASE_PAGE_SIZE, 74 &devcap_tmp, &msgerr); 75 if (err_is_fail(err)) { 76 DEBUG_ERR(err, "mm_alloc_range_proxy\n"); 77 goto out; 78 } 79 if (err_is_fail(msgerr)) { 80 DEBUG_ERR(msgerr, "mm_alloc_range_proxy msgerr\n"); 81 err = msgerr; 82 goto out; 83 } 84 KALUGA_DEBUG("start_hpet_driver: got mem cap for hpet \n"); 85 86 err = cap_copy(devcap, devcap_tmp); 87 assert(err_is_ok(err)); 88 89 drv = ddomain_create_driver_instance("hpet_module", "key"); 90 if (drv == NULL) { 91 err = DRIVERKIT_ERR_DRIVER_INIT; 92 goto out; 93 } 94 95 KALUGA_DEBUG("start_hpet_driver: created int cap for hpet \n"); 96 97 // add mem cap to driver 98 drv->caps[0] = arg_caps; 99 //err = ddomain_driver_add_cap(drv, devcap); 100 if (err_is_fail(err)) { 101 USER_PANIC_ERR(err, "add_cap"); 102 goto out; 103 } 104 105 drv->args[0] = malloc(50); 106 snprintf(drv->args[0], 50, "%ld", uid); 107 108 KALUGA_DEBUG("start_hpet_driver: Instantiating driver\n"); 109 110 // create driver instance 111 if (driver->driverinstance == NULL) { 112 KALUGA_DEBUG("Driver instance not running, starting...\n"); 113 114 // create driver domain 115 inst = instantiate_driver_domain(driver->binary, where); 116 driver->driverinstance = inst; 117 118 while (inst->b == NULL) { 119 event_dispatch(get_default_waitset()); 120 } 121 } 122 123 ddomain_instantiate_driver(inst, drv); 124 125out: 126 free(drv->args[0]); 127 drv->args[0] = NULL; 128 return err; 129} 130 131/* 132 * For a hpet comp, instantiate the correct irq controller in the skb and return 133 * the input singleton range. 134 */ 135static errval_t hpet_comp_get_irq_index(const char *record, char *ctrl_label, 136 uint64_t *irq_idx) { 137 int64_t hpet_uid, index; 138 errval_t err; 139 err = oct_read(record, "_ { " HW_HPET_COMP_RECORD_FIELDS_READ " }", &hpet_uid, 140 &index); 141 if (err_is_fail(err)) 142 return err; 143 144 err = skb_execute_query("Uid=%"PRIi64",Index=%"PRIi64",add_hpet_comp_controller(Lbl, Uid, " 145 "Index),write('\n'),print_int_controller(Lbl)", 146 hpet_uid, index); 147 if (err_is_fail(err)) { 148 DEBUG_SKB_ERR(err, ""); 149 return err; 150 } 151 152 uint64_t end = 0; 153 err = skb_read_output("%*[^\n]\n%64[^,],%*[^,],%" SCNu64 ",%" SCNu64, 154 ctrl_label, irq_idx, &end); 155 156 if (err_is_fail(err)) 157 return err; 158 159 // we expect a range of only one element 160 assert(*irq_idx == end); 161 162 return SYS_ERR_OK; 163} 164 165 166static errval_t hpet_comp_store_irq_info(const char *device_record, 167 struct driver_instance *drv) { 168 errval_t err; 169 struct capref *all_irq_cap = get_irq_cap(); 170 struct capref intcap; 171 172 err = slot_alloc(&intcap); 173 if (err_is_fail(err)) { 174 DEBUG_ERR(err, "Could not retype int_src cap"); 175 return err; 176 } 177 uint64_t irq_idx; 178 drv->args[0] = malloc(128); 179 assert(drv->args[0]); 180 err = hpet_comp_get_irq_index(device_record, drv->args[0], &irq_idx); 181 if (err_is_fail(err)) { 182 return err; 183 } 184 struct capref arg_caps; 185 struct cnoderef argnode_ref; 186 err = cnode_create_l2(&arg_caps, &argnode_ref); 187 struct capref irq_cap = { 188 .cnode = argnode_ref, 189 .slot = 0 190 }; 191 err = cap_retype(irq_cap, *all_irq_cap, irq_idx, ObjType_IRQSrc, irq_idx, 1); 192 if (err_is_fail(err)) { 193 DEBUG_ERR(err, "Could not retype int_src cap"); 194 return err; 195 } 196 197 return ddomain_driver_add_cap(drv, arg_caps); 198} 199 200static errval_t hpet_comp_store_index_arg(const char *record, 201 struct driver_instance *drv) { 202 int64_t hpet_uid, index; 203 errval_t err; 204 err = oct_read(record, "_ { " HW_HPET_COMP_RECORD_FIELDS_READ " }", &hpet_uid, 205 &index); 206 if (err_is_fail(err)) 207 return err; 208 209 drv->args[1] = malloc(128); 210 assert(drv->args[1] != NULL); 211 snprintf(drv->args[1], 128, "%"PRIi64, index); 212 return err; 213} 214 215static errval_t start_hpet_comp_driver(const char *device_record){ 216 errval_t err; 217 218 struct module_info *mi = find_module("hpet"); 219 assert(mi != NULL); 220 assert(mi->driverinstance != NULL); 221 222 struct driver_instance *drv = NULL; 223 drv = ddomain_create_driver_instance("hpet_comp_module", "key"); 224 225 err = hpet_comp_store_irq_info(device_record, drv); 226 if(err_is_fail(err)) return err; 227 228 err = hpet_comp_store_index_arg(device_record, drv); 229 if(err_is_fail(err)) return err; 230 231 KALUGA_DEBUG("start_hpet_comp_driver: Instantiating driver \n"); 232 ddomain_instantiate_driver(mi->driverinstance, drv); 233 234 return SYS_ERR_OK; 235} 236 237static void hpet_comp_change_event(oct_mode_t mode, const char *device_record, void *st) { 238 if ((mode & OCT_ON_SET) > 0) { 239 KALUGA_DEBUG("HPET_comp change event: start\n"); 240 errval_t err = start_hpet_comp_driver(device_record); 241 if(err_is_fail(err)){ 242 DEBUG_ERR(err,""); 243 } 244 } 245} 246 247void hpet_change_event(oct_mode_t mode, const char *device_record, void *st) { 248 if ((mode & OCT_ON_SET) > 0) { 249 KALUGA_DEBUG("HPET change event: start \n"); 250 errval_t err; 251 252 struct module_info *mi = find_module("hpet"); 253 if (mi == NULL) { 254 printf("HPET driver not found or not declared as auto."); 255 return; 256 } 257 258 // Todo : change 0 is for core_0 259 err = start_hpet_driver(0, mi, (CONST_CAST)device_record); 260 261 switch (err_no(err)) { 262 case SYS_ERR_OK: 263 KALUGA_DEBUG("Spawned HPET driver: %s\n", mi->binary); 264 break; 265 266 case KALUGA_ERR_DRIVER_NOT_AUTO: 267 KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary); 268 break; 269 270 default: 271 DEBUG_ERR(err, "Unhandled error while starting hpet\n"); 272 break; 273 } 274 } 275} 276 277/* 278 * Kaluga is notified (from acpi) of a new hpet. Kaluga obtains the page for reading 279 * the base registers of hpet starts hpet domain with hpet_module. 280 * 281 * The hpet_module will read the number of timers (we call this comparators) 282 * and insert for each comparator an skb hpet_comp and and octopus hpet_comp entry. 283 * 284 * Kaluga will react on this event, instantiate the hpet_comp interrupt controller driver. 285 * and start the hpet_comp_module with: the input interrupt cap and the label of 286 * the interrupt controller. 287 */ 288 289static void irq_ready_event(oct_mode_t mode, const char *device_record, 290 void *st) { 291 KALUGA_DEBUG("irq_ready_event: watching for HPET now\n"); 292 293 errval_t err; 294 const char *hpet_device = HW_HPET_RECORD_REGEX; 295 err = oct_trigger_existing_and_watch(hpet_device, hpet_change_event, NULL, 296 NULL); 297 298 if (err_is_fail(err)) { 299 DEBUG_ERR(err, "oct_trigger... hpet_device"); 300 } 301} 302 303errval_t watch_for_hpet(void) { 304 // We only start watching for HPETs once we get the base_irq_controller 305 // ready. Only then it's safe to call the add_hpet_controller method. 306 307 errval_t err; 308 const char *irq_ready = "base_irq_controller_ready {}"; 309 err = oct_trigger_existing_and_watch(irq_ready, irq_ready_event, NULL, NULL); 310 311 if (err_is_fail(err)) { 312 DEBUG_ERR(err, "oct_trigger... base_irq_controller_ready"); 313 } 314 315 err = oct_trigger_existing_and_watch(HW_HPET_COMP_RECORD_REGEX, 316 hpet_comp_change_event, NULL, NULL); 317 318 if (err_is_fail(err)) { 319 DEBUG_ERR(err, "oct_trigger... base_irq_controller_ready"); 320 } 321 return err; 322} 323