1/** 2 * \file 3 * \brief Inter-processor interrupt (IPI) notify mechanism. 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2010, 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#include <kernel.h> 16#include <dispatch.h> 17#include <capabilities.h> 18#include <arch/x86/ipi_notify.h> 19#include <arch/x86/global.h> 20#include <arch/x86/apic.h> 21#include <barrelfish_kpi/syscalls.h> 22#include <barrelfish_kpi/paging_arch.h> 23 24// Max number of notification IDs that fit into message passing buffers 25#define MAX_CHANIDS 65535 26 27/// User-space endpoints awaiting notifications 28static struct cte endpoints[MAX_CHANIDS]; 29 30#define NOTIFY_FIFO_SIZE 64 31#define NOTIFY_FIFO_BYTES (NOTIFY_FIFO_SIZE * sizeof(uint64_t)) 32 33/// Page used for notify FIFOs 34static char my_notify_page[NOTIFY_FIFO_BYTES * MAX_COREID]; 35 36// Private head/tail pointers for notify FIFOs 37static uint64_t notifyhead[MAX_COREID]; 38static uint64_t notifytail[MAX_COREID]; 39 40static uint8_t my_arch_id; 41 42errval_t ipi_register_notification(capaddr_t ep, int chanid) 43{ 44 struct cte *recv; 45 errval_t err; 46 47 err = caps_lookup_slot(&dcb_current->cspace.cap, ep, 48 2, &recv, CAPRIGHTS_WRITE); 49 if (err_is_fail(err)) { 50 return err_push(err, SYS_ERR_IRQ_LOOKUP); 51 } 52 53 assert(recv != NULL); 54 55 // Return w/error if cap is not an endpoint 56 if(recv->cap.type != ObjType_EndPointLMP) { 57 return SYS_ERR_IRQ_NOT_ENDPOINT; 58 } 59 60 // Return w/error if no listener on endpoint 61 if(recv->cap.u.endpointlmp.listener == NULL) { 62 return SYS_ERR_IRQ_NO_LISTENER; 63 } 64 65 if(chanid < MAX_CHANIDS) { 66 // check that we don't overwrite someone else's handler 67 if (endpoints[chanid].cap.type != ObjType_Null) { 68 printf("kernel: installing new handler for IPI notification %d\n", chanid); 69 } 70 return caps_copy_to_cte(&endpoints[chanid], recv, false, 0, 0); 71 } else { 72 return SYS_ERR_IRQ_INVALID; 73 } 74} 75 76void ipi_handle_notify(void) 77{ 78 uint64_t val = 0; 79 80 for(coreid_t srccore = 0; srccore < MAX_COREID; srccore++) { 81 volatile uint64_t *fifo = (void *)&my_notify_page[NOTIFY_FIFO_BYTES * srccore]; 82 83 if (global->notify[my_arch_id] == 0) { 84 panic("NO PCN for core %d!", my_arch_id); 85 } 86 87 // Which slot in the fifo to poll 88 uint64_t slot = notifytail[srccore] % NOTIFY_FIFO_SIZE; 89 90 while (fifo[slot] != 0) { 91 val = fifo[slot]; 92 93 assert(endpoints[val].cap.type != ObjType_Null); 94 lmp_deliver_notification(&endpoints[val].cap); 95 96 fifo[slot] = 0; // ACK 97 notifytail[srccore]++; 98 slot = notifytail[srccore] % NOTIFY_FIFO_SIZE; 99 } 100 } 101 102 // XXX: Dispatch last listener -- should be done by scheduler 103 if(val != 0) { 104 dispatch(endpoints[val].cap.u.endpointlmp.listener); 105 } 106} 107 108struct sysret ipi_raise_notify(coreid_t coreid, uintptr_t chanid) 109{ 110 char *notify_page = (char *)local_phys_to_mem(global->notify[coreid]); 111 112 if (notify_page == NULL || coreid >= MAX_COREID) { 113 printf("UMPNOTIFY ERROR!\n"); 114 return SYSRET(SYS_ERR_ILLEGAL_INVOCATION); 115 } 116 117 // Locate our private notification fifo and head ptr 118 volatile uint64_t *fifo = (void *)¬ify_page[my_arch_id * NOTIFY_FIFO_BYTES]; 119 uint64_t slot = notifyhead[coreid] % NOTIFY_FIFO_SIZE; 120 121 // Make sure the next slot is empty 122 if (fifo[slot] != 0) { 123 panic("FULL"); 124 } 125 126 // Update notify fifo 127 fifo[slot] = (uint64_t)chanid; 128 notifyhead[coreid]++; 129 130 // Send IPI to dest kernel 131 apic_send_std_ipi(coreid, xapic_none, APIC_INTER_CORE_VECTOR); 132 133 return SYSRET(SYS_ERR_OK); 134} 135 136void ipi_notify_init(void) 137{ 138 my_arch_id = apic_get_id(); 139 // Publish the address of the notify page in the global kernel state 140 global->notify[my_arch_id] = local_phys_to_gen_phys(mem_to_local_phys((lvaddr_t)my_notify_page)); 141} 142