1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
// IBM_PROLOG_BEGIN_TAG
// This is an automatically generated prolog.
//
// $Source: src/kernel/intmsghandler.C $
//
// IBM CONFIDENTIAL
//
// COPYRIGHT International Business Machines Corp. 2011
//
// p1
//
// Object Code Only (OCO) source materials
// Licensed Internal Code Source Materials
// IBM HostBoot Licensed Internal Code
//
// The source code for this program is not published or other-
// wise divested of its trade secrets, irrespective of what has
// been deposited with the U.S. Copyright Office.
//
// Origin: 30
//
// IBM_PROLOG_END
#include <kernel/intmsghandler.H>
#include <sys/msg.h>
#include <util/singleton.H>
#include <kernel/console.H>
#include <sys/interrupt.h>
#include <util/lockfree/atomic_construct.H>
const char* INTR_MSGQ = "/msg/interrupt";
InterruptMsgHdlr * InterruptMsgHdlr::cv_instance = NULL;
void InterruptMsgHdlr::create(MessageQueue * i_msgQ)
{
if(cv_instance)
{
// TODO should this be considered an unrecoverable error?
// i_msgQ has already been changed by the syscall, so we either have to
// make a new InterrupMsgHdlr object to match the new queue or we halt
// the system.
printk("WARNING replacing existing Interrupt handler!\n");
InterruptMsgHdlr* instance = cv_instance;
while(instance != NULL)
{
if(__sync_bool_compare_and_swap(&cv_instance, instance, NULL))
{
delete instance;
}
instance = cv_instance;
}
}
// Atomically construct.
if (__sync_bool_compare_and_swap(&cv_instance, NULL, NULL))
{
InterruptMsgHdlr* instance = new InterruptMsgHdlr(i_msgQ);
if (!__sync_bool_compare_and_swap(&cv_instance, NULL, instance))
{
delete instance;
}
}
}
void InterruptMsgHdlr::handleInterrupt()
{
// TODO will this always be processor 0 core 0 thread 0?
// Need a way to pass this addr down from user code?
uint64_t xirrAddress = (static_cast<uint64_t>(ICPBAR_VAL) << 20) + 4;
// Ignore HRMOR setting
xirrAddress |= 0x8000000000000000ul;
uint32_t xirr = 0;
printkd ("XirrAddr %lx\n",xirrAddress);
// Reading this register acknowledges the interrupt and deactivates the
// external interrupt signal to the processor. The XIRR is now locked
// and can't be pre-empted by a "more favored" interrupt.
// This is a cache-inhibited load from hypervisor state.
// lwzcix BOP1,Ref_G0,BOP2
asm volatile("lwzcix %0, 0, %1"
: "=r" (xirr) // output, %0
: "r" (xirrAddress) // input, %1
: ); // no impacts
if(cv_instance)
{
cv_instance->sendMessage(MSG_INTR_EXTERN,
(void *)xirr,
NULL,
NULL);
}
// else we got an external interrupt before we got things set up.
// TODO Is there anything that can be done other than
// leave the interrupt presenter locked.
// Does the code that sets up the IP registers need to check to see if
// there is an interrupt sitting there and send an EOI?
}
void InterruptMsgHdlr::addCpuCore(uint64_t i_pir)
{
if(cv_instance)
{
cv_instance->sendMessage(MSG_INTR_ADD_CPU,(void *)i_pir,NULL,NULL);
}
}
MessageHandler::HandleResult InterruptMsgHdlr::handleResponse
(
msg_sys_types_t i_type,
void* i_key,
task_t* i_task,
int i_rc
)
{
return UNHANDLED_RC;
}
|