1/// @file
2///  Low level IPF routines used by the debug support driver
3///
4/// Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
5/// This program and the accompanying materials
6/// are licensed and made available under the terms and conditions of the BSD License
7/// which accompanies this distribution.  The full text of the license may be found at
8/// http://opensource.org/licenses/bsd-license.php
9///
10/// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11/// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12///
13///
14
15
16#include "Common.i"
17#include "Ds64Macros.i"
18
19ASM_GLOBAL PatchSaveBuffer
20ASM_GLOBAL IpfContextBuf
21ASM_GLOBAL CommonHandler
22ASM_GLOBAL ExternalInterruptCount
23
24
25/////////////////////////////////////////////
26//
27//  Name:
28//      InstructionCacheFlush
29//
30//  Description:
31//      Flushes instruction cache for specified number of bytes
32//
33        ASM_GLOBAL InstructionCacheFlush
34        .proc   InstructionCacheFlush
35        .align 32
36InstructionCacheFlush::
37 {      .mii
38        alloc   r3=2, 0, 0, 0
39        cmp4.leu p0,p6=32, r33;;
40        (p6)    mov r33=32;;
41 }
42 {      .mii
43        nop.m    0
44        zxt4    r29=r33;;
45        dep.z   r30=r29, 0, 5;;
46 }
47 {      .mii
48        cmp4.eq p0,p7=r0, r30
49        shr.u   r28=r29, 5;;
50        (p7)    adds    r28=1, r28;;
51 }
52 {      .mii
53        nop.m    0
54        shl r27=r28, 5;;
55        zxt4    r26=r27;;
56 }
57 {      .mfb
58        add r31=r26, r32
59        nop.f    0
60        nop.b    0
61 }
62LoopBack:   // $L143:
63 {      .mii
64        fc   r32
65        adds    r32=32, r32;;
66        cmp.ltu p14,p15=r32, r31
67 }
68 {      .mfb
69        nop.m    0
70        nop.f    0
71        //(p14) br.cond.dptk.few $L143#;;
72        (p14)   br.cond.dptk.few LoopBack;;
73 }
74 {      .mmi
75        sync.i;;
76        srlz.i
77        nop.i   0;;
78 }
79 {      .mfb
80        nop.m    0
81        nop.f    0
82        br.ret.sptk.few b0;;
83 }
84        .endp   InstructionCacheFlush
85
86
87/////////////////////////////////////////////
88//
89//  Name:
90//      ChainHandler
91//
92//  Description:
93//      Chains an interrupt handler
94//
95//      The purpose of this function is to enable chaining of the external interrupt.
96//      Since there's no clean SAL abstraction for doing this, we must do it
97//      surreptitiously.
98//
99//      The reserved IVT entry at offset 0x3400 is coopted for use by this handler.
100//      According to Itanium architecture, it is reserved.  Strictly speaking, this is
101//      not safe, as we're cheating and violating the Itanium architecture.  However,
102//      as long as we're the only ones cheating, we should be OK.  Without hooks in
103//      the SAL to enable IVT management, there aren't many good options.
104//
105//      The strategy is to replace the first bundle of the external interrupt handler
106//      with our own that will branch into a piece of code we've supplied and located
107//      in the reserved IVT entry.  Only the first bundle of the external interrupt
108//      IVT entry is modified.
109//
110//      The original bundle is moved and relocated to space
111//      allocated within the reserved IVT entry.  The next bundle following is
112//      is generated to go a hard coded branch back to the second bundle of the
113//      external interrupt IVT entry just in case the first bundle had no branch.
114//
115//      Our new code will execute our handler, and then fall through to the
116//      original bundle after restoring all context appropriately.
117//
118//      The following is a representation of what the IVT memory map looks like with
119//      our chained handler installed:
120//
121//
122//
123//
124//
125//      This IVT entry is      Failsafe bundle
126//      reserved by the
127//      Itanium architecture   Original bundle 0
128//      and is used for
129//      for locating our
130//      handler and the
131//      original bundle        Patch code...
132//      zero of the ext
133//      interrupt handler
134//
135//      RSVD    (3400)         Unused
136//
137//
138//
139//
140//
141//
142//
143//
144//
145//
146//
147//
148//      EXT_INT (3000)         Bundle 0               Bundle zero - This one is
149//                                modified, all other bundles
150//                                                       in the EXT_INT entry are
151//                                                       untouched.
152//
153//
154//       Arguments:
155//
156//       Returns:
157//
158//       Notes:
159//
160//
161        ASM_GLOBAL ChainHandler
162        .proc ChainHandler
163ChainHandler:
164
165        NESTED_SETUP( 0,2+3,3,0 )
166
167        mov         r8=1                           // r8 = success
168        mov         r2=cr.iva;;
169//
170// NOTE: There's a potential hazard here in that we're simply stealing a bunch of
171// bundles (memory) from the IVT and assuming there's no catastrophic side effect.
172//
173// First, save IVT area we're taking over with the patch so we can restore it later
174//
175        addl        out0=PATCH_ENTRY_OFFSET, r2    // out0 = source buffer
176        movl        out1=PatchSaveBuffer           // out1 = destination buffer
177        mov         out2=0x40;;                    // out2 = number of bundles to copy... save entire IDT entry
178        br.call.sptk.few    b0 = CopyBundles
179
180// Next, copy the patch code into the IVT
181        movl        out0=PatchCode                 // out0 = source buffer of patch code
182        addl        out1=PATCH_OFFSET, r2          // out1 = destination buffer - in IVT
183        mov         out2=PATCH_CODE_SIZE;;
184        shr         out2=out2, 4;;                 // out2 = number of bundles to copy
185        br.call.sptk.few    b0 = CopyBundles
186
187
188// copy original bundle 0 from the external interrupt handler to the
189// appropriate place in the reserved IVT interrupt slot
190        addl        out0=EXT_INT_ENTRY_OFFSET, r2  // out0 = source buffer
191        addl        out1=RELOCATED_EXT_INT, r2     // out1 = destination buffer - in reserved IVT
192        mov         out2=1;;                       // out2 = copy 1 bundle
193        br.call.sptk.few    b0 = CopyBundles
194
195// Now relocate it there because it very likely had a branch instruction that
196// that must now be fixed up.
197        addl        out0=RELOCATED_EXT_INT, r2     // out0 = new runtime address of bundle - in reserved IVT
198        addl        out1=EXT_INT_ENTRY_OFFSET, r2;;// out1 = IP address of previous location
199        mov         out2=out0;;                    // out2 = IP address of new location
200        br.call.sptk.few    b0 = RelocateBundle
201
202// Now copy into the failsafe branch into the next bundle just in case
203// the original ext int bundle 0 bundle did not contain a branch instruction
204        movl        out0=FailsafeBranch            // out0 = source buffer
205        addl        out1=FAILSAFE_BRANCH_OFFSET, r2  // out1 = destination buffer - in reserved IVT
206        mov         out2=1;;                       // out2 = copy 1 bundle
207        br.call.sptk.few    b0 = CopyBundles
208
209// Last, copy in our replacement for the external interrupt IVT entry bundle 0
210        movl        out0=PatchCodeNewBun0          // out0 = source buffer - our replacement bundle 0
211        addl        out1=EXT_INT_ENTRY_OFFSET, r2  // out1 = destination buffer - bundle 0 of External interrupt entry
212        mov         out2=1;;                       // out2 = copy 1 bundle
213        br.call.sptk.few    b0 = CopyBundles
214
215ChainHandlerDone:
216        NESTED_RETURN
217
218        .endp ChainHandler
219
220
221/////////////////////////////////////////////
222//
223//  Name:
224//      UnchainHandler
225//
226//  Description:
227//      Unchains an interrupt handler
228//
229//  Arguments:
230//
231//  Returns:
232//
233//  Notes:
234//
235//
236        ASM_GLOBAL UnchainHandler
237        .proc UnchainHandler
238
239UnchainHandler:
240
241        NESTED_SETUP( 0,2+3,3,0 )
242
243        mov         r8=1                        // r8 = success
244        mov         r2=cr.iva;;                 // r2 = interrupt vector address
245
246// First copy original Ext Int bundle 0 back to it's proper home...
247        addl        out0=RELOCATED_EXT_INT, r2     // out0 = source - in reserved IVT
248        addl        out1=EXT_INT_ENTRY_OFFSET, r2  // out1 = destination buffer - first bundle of Ext Int entry
249        mov         out2=1;;                       // out2 = copy 1 bundle
250        br.call.sptk.few    b0 = CopyBundles
251
252// Now, relocate it again...
253        addl        out0=EXT_INT_ENTRY_OFFSET, r2  // out1 = New runtime address
254        addl        out1=RELOCATED_EXT_INT, r2;;   // out0 = IP address of previous location
255        mov         out2=out0;;                    // out2 = IP address of new location
256        br.call.sptk.few    b0 = RelocateBundle
257
258// Last, restore the patch area
259        movl        out0=PatchSaveBuffer           // out0 = source buffer
260        addl        out1=PATCH_ENTRY_OFFSET, r2    // out1 = destination buffer
261        mov         out2=0x40;;                    // out2 = number of bundles to copy... save entire IDT entry
262        br.call.sptk.few    b0 = CopyBundles
263
264UnchainHandlerDone:
265        NESTED_RETURN
266
267        .endp UnchainHandler
268
269
270/////////////////////////////////////////////
271//
272//  Name:
273//      CopyBundles
274//
275//  Description:
276//      Copies instruction bundles - flushes icache as necessary
277//
278//  Arguments:
279//      in0 - Bundle source
280//      in1 - Bundle destination
281//      in2 - Bundle count
282//
283//  Returns:
284//
285//  Notes:
286//      This procedure is a leaf routine
287//
288        .proc   CopyBundles
289
290CopyBundles:
291
292        NESTED_SETUP(3,2+1,0,0)
293
294        shl         in2=in2, 1;;                // in2 = count of 8 byte blocks to copy
295
296CopyBundlesLoop:
297
298        cmp.eq      p14, p15 = 0, in2;;         // Check if done
299(p14)   br.sptk.few CopyBundlesDone;;
300
301        ld8         loc2=[in0], 0x8;;           // loc2 = source bytes
302        st8         [in1]=loc2;;                // [in1] = destination bytes
303        fc          in1;;                       // Flush instruction cache
304        sync.i;;                                // Ensure local and remote data/inst caches in sync
305        srlz.i;;                                // Ensure sync has been observed
306        add         in1=0x8, in1;;              // in1 = next destination
307        add         in2=-1, in2;;               // in2 = decrement 8 bytes blocks to copy
308        br.sptk.few CopyBundlesLoop;;
309
310CopyBundlesDone:
311        NESTED_RETURN
312
313        .endp   CopyBundles
314
315
316/////////////////////////////////////////////
317//
318//  Name:
319//      RelocateBundle
320//
321//  Description:
322//      Relocates an instruction bundle by updating any ip-relative branch instructions.
323//
324//  Arguments:
325//      in0 - Runtime address of bundle
326//      in1 - IP address of previous location of bundle
327//      in2 - IP address of new location of bundle
328//
329//  Returns:
330//      in0 - 1 if successful or 0 if unsuccessful
331//
332//  Notes:
333//      This routine examines all slots in the given bundle that are destined for the
334//      branch execution unit.  If any of these slots contain an IP-relative branch
335//      namely instructions B1, B2, B3, or B6, the slot is fixed-up with a new relative
336//      address.  Errors can occur if a branch cannot be reached.
337//
338        .proc   RelocateBundle
339
340RelocateBundle:
341
342        NESTED_SETUP(3,2+4,3,0)
343
344        mov         loc2=SLOT0                  // loc2 = slot index
345        mov         loc5=in0;;                  // loc5 = runtime address of bundle
346        mov         in0=1;;                     // in0 = success
347
348RelocateBundleNextSlot:
349
350        cmp.ge      p14, p15 = SLOT2, loc2;;    // Check if maximum slot
351(p15)   br.sptk.few RelocateBundleDone
352
353        mov         out0=loc5;;                 // out0 = runtime address of bundle
354        br.call.sptk.few    b0 = GetTemplate
355        mov         loc3=out0;;                 // loc3 = instruction template
356        mov         out0=loc5                   // out0 = runtime address of bundle
357        mov         out1=loc2;;                 // out1 = instruction slot number
358        br.call.sptk.few    b0 = GetSlot
359        mov         loc4=out0;;                 // loc4 = instruction encoding
360        mov         out0=loc4                   // out0 = instuction encoding
361        mov         out1=loc2                   // out1 = instruction slot number
362        mov         out2=loc3;;                 // out2 = instruction template
363        br.call.sptk.few    b0 = IsSlotBranch
364        cmp.eq      p14, p15 = 1, out0;;        // Check if branch slot
365(p15)   add         loc2=1,loc2                 // Increment slot
366(p15)   br.sptk.few RelocateBundleNextSlot
367        mov         out0=loc4                   // out0 = instuction encoding
368        mov         out1=in1                    // out1 = IP address of previous location
369        mov         out2=in2;;                  // out2 = IP address of new location
370        br.call.sptk.few    b0 = RelocateSlot
371        cmp.eq      p14, p15 = 1, out1;;        // Check if relocated slot
372(p15)   mov         in0=0                       // in0 = failure
373(p15)   br.sptk.few RelocateBundleDone
374        mov         out2=out0;;                 // out2 = instruction encoding
375        mov         out0=loc5                   // out0 = runtime address of bundle
376        mov         out1=loc2;;                 // out1 = instruction slot number
377        br.call.sptk.few    b0 = SetSlot
378        add         loc2=1,loc2;;               // Increment slot
379        br.sptk.few RelocateBundleNextSlot
380
381RelocateBundleDone:
382        NESTED_RETURN
383
384        .endp   RelocateBundle
385
386
387/////////////////////////////////////////////
388//
389//  Name:
390//      RelocateSlot
391//
392//  Description:
393//      Relocates an instruction bundle by updating any ip-relative branch instructions.
394//
395//  Arguments:
396//      in0 - Instruction encoding (41-bits, right justified)
397//      in1 - IP address of previous location of bundle
398//      in2 - IP address of new location of bundle
399//
400//  Returns:
401//      in0 - Instruction encoding (41-bits, right justified)
402//      in1 - 1 if successful otherwise 0
403//
404//  Notes:
405//      This procedure is a leaf routine
406//
407        .proc   RelocateSlot
408
409RelocateSlot:
410        NESTED_SETUP(3,2+5,0,0)
411        extr.u      loc2=in0, 37, 4;;           // loc2 = instruction opcode
412        cmp.eq      p14, p15 = 4, loc2;;        // IP-relative branch (B1) or
413                                                // IP-relative counted branch (B2)
414(p15)   cmp.eq      p14, p15 = 5, loc2;;        // IP-relative call (B3)
415(p15)   cmp.eq      p14, p15 = 7, loc2;;        // IP-relative predict (B6)
416(p15)   mov         in1=1                       // Instruction did not need to be reencoded
417(p15)   br.sptk.few RelocateSlotDone
418        tbit.nz     p14, p15 = in0, 36;;        // put relative offset sign bit in p14
419        extr.u      loc2=in0, 13, 20;;          // loc2 = relative offset in instruction
420(p14)   movl        loc3=0xfffffffffff00000;;   // extend sign
421(p14)   or          loc2=loc2, loc3;;
422        shl         loc2=loc2,4;;               // convert to byte offset instead of bundle offset
423        add         loc3=loc2, in1;;            // loc3 = physical address of branch target
424(p14)   sub         loc2=r0,loc2;;              // flip sign in loc2 if offset is negative
425        sub         loc4=loc3,in2;;             // loc4 = relative offset from new ip to branch target
426        cmp.lt      p15, p14 = 0, loc4;;        // get new sign bit
427(p14)   sub         loc5=r0,loc4                // get absolute value of offset
428(p15)   mov         loc5=loc4;;
429        movl        loc6=0x0FFFFFF;;            // maximum offset in bytes for ip-rel branch
430        cmp.gt      p14, p15 = loc5, loc6;;     // check to see we're not out of range for an ip-relative branch
431(p14)   br.sptk.few RelocateSlotError
432        cmp.lt      p15, p14 = 0, loc4;;        // store sign in p14 again
433(p14)   dep         in0=-1,in0,36,1              // store sign bit in instruction
434(p15)   dep         in0=0,in0,36,1
435        shr         loc4=loc4, 4;;              // convert back to bundle offset
436        dep         in0=loc4,in0,13,16;;        // put first 16 bits of new offset into instruction
437        shr         loc4=loc4,16;;
438        dep         in0=loc4,in0,13+16,4        // put last 4 bits of new offset into instruction
439        mov         in1=1;;                     // in1 = success
440        br.sptk.few RelocateSlotDone;;
441
442RelocateSlotError:
443        mov         in1=0;;                     // in1 = failure
444
445RelocateSlotDone:
446        NESTED_RETURN
447
448        .endp   RelocateSlot
449
450
451/////////////////////////////////////////////
452//
453//  Name:
454//      IsSlotBranch
455//
456//  Description:
457//      Determines if the given instruction is a branch instruction.
458//
459//  Arguments:
460//      in0 - Instruction encoding (41-bits, right justified)
461//      in1 - Instruction slot number
462//      in2 - Bundle template
463//
464//  Returns:
465//      in0 - 1 if branch or 0 if not branch
466//
467//  Notes:
468//      This procedure is a leaf routine
469//
470//      IsSlotBranch recognizes all branch instructions by looking at the provided template.
471//      The instruction encoding is only passed to this routine for future expansion.
472//
473        .proc   IsSlotBranch
474
475IsSlotBranch:
476
477        NESTED_SETUP (3,2+0,0,0)
478
479        mov         in0=1;;                     // in0 = 1 which destroys the instruction
480        andcm       in2=in2,in0;;               // in2 = even template to reduce compares
481        mov         in0=0;;                     // in0 = not a branch
482        cmp.eq      p14, p15 = 0x16, in2;;      // Template 0x16 is BBB
483(p14)   br.sptk.few IsSlotBranchTrue
484        cmp.eq      p14, p15 = SLOT0, in1;;     // Slot 0 has no other possiblities
485(p14)   br.sptk.few IsSlotBranchDone
486        cmp.eq      p14, p15 = 0x12, in2;;      // Template 0x12 is MBB
487(p14)   br.sptk.few IsSlotBranchTrue
488        cmp.eq      p14, p15 = SLOT1, in1;;     // Slot 1 has no other possiblities
489(p14)   br.sptk.few IsSlotBranchDone
490        cmp.eq      p14, p15 = 0x10, in2;;      // Template 0x10 is MIB
491(p14)   br.sptk.few IsSlotBranchTrue
492        cmp.eq      p14, p15 = 0x18, in2;;      // Template 0x18 is MMB
493(p14)   br.sptk.few IsSlotBranchTrue
494        cmp.eq      p14, p15 = 0x1C, in2;;      // Template 0x1C is MFB
495(p14)   br.sptk.few IsSlotBranchTrue
496        br.sptk.few IsSlotBranchDone
497
498IsSlotBranchTrue:
499        mov         in0=1;;                     // in0 = branch
500
501IsSlotBranchDone:
502        NESTED_RETURN
503
504        .endp   IsSlotBranch
505
506
507/////////////////////////////////////////////
508//
509//  Name:
510//      GetTemplate
511//
512//  Description:
513//      Retrieves the instruction template for an instruction bundle
514//
515//  Arguments:
516//      in0 - Runtime address of bundle
517//
518//  Returns:
519//      in0 - Instruction template (5-bits, right-justified)
520//
521//  Notes:
522//      This procedure is a leaf routine
523//
524        .proc   GetTemplate
525
526GetTemplate:
527
528        NESTED_SETUP (1,2+2,0,0)
529
530        ld8     loc2=[in0], 0x8             // loc2 = first 8 bytes of branch bundle
531        movl    loc3=MASK_0_4;;             // loc3 = template mask
532        and     loc2=loc2,loc3;;            // loc2 = template, right justified
533        mov     in0=loc2;;                  // in0 = template, right justified
534
535        NESTED_RETURN
536
537        .endp   GetTemplate
538
539
540/////////////////////////////////////////////
541//
542//  Name:
543//      GetSlot
544//
545//  Description:
546//      Gets the instruction encoding for an instruction slot and bundle
547//
548//  Arguments:
549//      in0 - Runtime address of bundle
550//      in1 - Instruction slot (either 0, 1, or 2)
551//
552//  Returns:
553//      in0 - Instruction encoding (41-bits, right justified)
554//
555//  Notes:
556//      This procedure is a leaf routine
557//
558//      Slot0 - [in0 + 0x8] Bits 45-5
559//      Slot1 - [in0 + 0x8] Bits 63-46 and [in0] Bits 22-0
560//      Slot2 - [in0] Bits 63-23
561//
562        .proc   GetSlot
563
564GetSlot:
565        NESTED_SETUP (2,2+3,0,0)
566
567        ld8     loc2=[in0], 0x8;;           // loc2 = first 8 bytes of branch bundle
568        ld8     loc3=[in0];;                // loc3 = second 8 bytes of branch bundle
569        cmp.eq  p14, p15 = 2, in1;;         // check if slot 2 specified
570 (p14)  br.cond.sptk.few    GetSlot2;;      // get slot 2
571        cmp.eq  p14, p15 = 1, in1;;         // check if slot 1 specified
572 (p14)  br.cond.sptk.few    GetSlot1;;      // get slot 1
573
574GetSlot0:
575        extr.u  in0=loc2, 5, 45             // in0 = extracted slot 0
576        br.sptk.few GetSlotDone;;
577
578GetSlot1:
579        extr.u  in0=loc2, 46, 18            // in0 = bits 63-46 of loc2 right-justified
580        extr.u  loc4=loc3, 0, 23;;          // loc4 = bits 22-0 of loc3 right-justified
581        dep     in0=loc4, in0, 18, 15;;
582        shr.u   loc4=loc4,15;;
583        dep     in0=loc4, in0, 33, 8;;      // in0 = extracted slot 1
584        br.sptk.few GetSlotDone;;
585
586GetSlot2:
587        extr.u  in0=loc3, 23, 41;;          // in0 = extracted slot 2
588
589GetSlotDone:
590        NESTED_RETURN
591
592        .endp   GetSlot
593
594
595/////////////////////////////////////////////
596//
597//  Name:
598//      SetSlot
599//
600//  Description:
601//      Sets the instruction encoding for an instruction slot and bundle
602//
603//  Arguments:
604//      in0 - Runtime address of bundle
605//      in1 - Instruction slot (either 0, 1, or 2)
606//      in2 - Instruction encoding (41-bits, right justified)
607//
608//  Returns:
609//
610//  Notes:
611//      This procedure is a leaf routine
612//
613        .proc       SetSlot
614
615SetSlot:
616        NESTED_SETUP (3,2+3,0,0)
617
618        ld8     loc2=[in0], 0x8;;           // loc2 = first 8 bytes of bundle
619        ld8     loc3=[in0];;                // loc3 = second 8 bytes of bundle
620        cmp.eq  p14, p15 = 2, in1;;         // check if slot 2 specified
621 (p14)  br.cond.sptk.few    SetSlot2;;      // set slot 2
622        cmp.eq  p14, p15 = 1, in1;;         // check if slot 1 specified
623 (p14)  br.cond.sptk.few    SetSlot1;;      // set slot 1
624
625SetSlot0:
626        dep     loc2=0, loc2, 5, 41;;       // remove old instruction from slot 0
627        shl     loc4=in2, 5;;               // loc4 = new instruction ready to be inserted
628        or      loc2=loc2, loc4;;           // loc2 = updated first 8 bytes of bundle
629        add     loc4=0x8,in0;;              // loc4 = address to store first 8 bytes of bundle
630        st8     [loc4]=loc2                 // [loc4] = updated bundle
631        br.sptk.few SetSlotDone;;
632        ;;
633
634SetSlot1:
635        dep     loc2=0, loc2, 46, 18        // remove old instruction from slot 1
636        dep     loc3=0, loc3, 0, 23;;
637        shl     loc4=in2, 46;;              // loc4 = partial instruction ready to be inserted
638        or      loc2=loc2, loc4;;           // loc2 = updated first 8 bytes of bundle
639        add     loc4=0x8,in0;;              // loc4 = address to store first 8 bytes of bundle
640        st8     [loc4]=loc2;;               // [loc4] = updated bundle
641        shr.u   loc4=in2, 18;;              // loc4 = partial instruction ready to be inserted
642        or      loc3=loc3, loc4;;           // loc3 = updated second 8 bytes of bundle
643        st8     [in0]=loc3;;                // [in0] = updated bundle
644        br.sptk.few SetSlotDone;;
645
646SetSlot2:
647        dep     loc3=0, loc3, 23, 41;;      // remove old instruction from slot 2
648        shl     loc4=in2, 23;;              // loc4 = instruction ready to be inserted
649        or      loc3=loc3, loc4;;           // loc3 = updated second 8 bytes of bundle
650        st8     [in0]=loc3;;                // [in0] = updated bundle
651
652SetSlotDone:
653
654        NESTED_RETURN
655        .endp       SetSlot
656
657
658/////////////////////////////////////////////
659//
660//  Name:
661//      GetIva
662//
663//  Description:
664//      C callable function to obtain the current value of IVA
665//
666//  Returns:
667//      Current value if IVA
668
669        ASM_GLOBAL     GetIva
670        .proc       GetIva
671GetIva:
672        mov         r8=cr2;;
673        br.ret.sptk.many    b0
674
675        .endp       GetIva
676
677
678/////////////////////////////////////////////
679//
680//  Name:
681//      ProgramInterruptFlags
682//
683//  Description:
684//      C callable function to enable/disable interrupts
685//
686//  Returns:
687//      Previous state of psr.ic
688//
689        ASM_GLOBAL     ProgramInterruptFlags
690        .proc       ProgramInterruptFlags
691ProgramInterruptFlags:
692        alloc       loc0=1,2,0,0;;
693        mov         loc0=psr
694        mov         loc1=0x6000;;
695        and         r8=loc0, loc1           // obtain current psr.ic and psr.i state
696        and         in0=in0, loc1           // insure no extra bits set in input
697        andcm       loc0=loc0,loc1;;        // clear original psr.i and psr.ic
698        or          loc0=loc0,in0;;         // OR in new psr.ic value
699        mov         psr.l=loc0;;            // write new psr
700        srlz.d
701        br.ret.sptk.many    b0              // return
702
703        .endp       ProgramInterruptFlags
704
705
706/////////////////////////////////////////////
707//
708//  Name:
709//      SpillContext
710//
711//  Description:
712//      Saves system context to context record.
713//
714//  Arguments:
715//          in0 = 512 byte aligned context record address
716//          in1 = original B0
717//          in2 = original ar.bsp
718//          in3 = original ar.bspstore
719//          in4 = original ar.rnat
720//          in5 = original ar.pfs
721//
722//  Notes:
723//      loc0 - scratch
724//      loc1 - scratch
725//      loc2 - temporary application unat storage
726//      loc3 - temporary exception handler unat storage
727
728        .proc       SpillContext
729
730SpillContext:
731        alloc       loc0=6,4,0,0;;          // alloc 6 input, 4 locals, 0 outs
732        mov         loc2=ar.unat;;          // save application context unat (spilled later)
733        mov         ar.unat=r0;;            // set UNAT=0
734        st8.spill   [in0]=r0,8;;
735        st8.spill   [in0]=r1,8;;            // save R1 - R31
736        st8.spill   [in0]=r2,8;;
737        st8.spill   [in0]=r3,8;;
738        st8.spill   [in0]=r4,8;;
739        st8.spill   [in0]=r5,8;;
740        st8.spill   [in0]=r6,8;;
741        st8.spill   [in0]=r7,8;;
742        st8.spill   [in0]=r8,8;;
743        st8.spill   [in0]=r9,8;;
744        st8.spill   [in0]=r10,8;;
745        st8.spill   [in0]=r11,8;;
746        st8.spill   [in0]=r12,8;;
747        st8.spill   [in0]=r13,8;;
748        st8.spill   [in0]=r14,8;;
749        st8.spill   [in0]=r15,8;;
750        st8.spill   [in0]=r16,8;;
751        st8.spill   [in0]=r17,8;;
752        st8.spill   [in0]=r18,8;;
753        st8.spill   [in0]=r19,8;;
754        st8.spill   [in0]=r20,8;;
755        st8.spill   [in0]=r21,8;;
756        st8.spill   [in0]=r22,8;;
757        st8.spill   [in0]=r23,8;;
758        st8.spill   [in0]=r24,8;;
759        st8.spill   [in0]=r25,8;;
760        st8.spill   [in0]=r26,8;;
761        st8.spill   [in0]=r27,8;;
762        st8.spill   [in0]=r28,8;;
763        st8.spill   [in0]=r29,8;;
764        st8.spill   [in0]=r30,8;;
765        st8.spill   [in0]=r31,8;;
766        mov         loc3=ar.unat;;          // save debugger context unat (spilled later)
767        stf.spill   [in0]=f2,16;;           // save f2 - f31
768        stf.spill   [in0]=f3,16;;
769        stf.spill   [in0]=f4,16;;
770        stf.spill   [in0]=f5,16;;
771        stf.spill   [in0]=f6,16;;
772        stf.spill   [in0]=f7,16;;
773        stf.spill   [in0]=f8,16;;
774        stf.spill   [in0]=f9,16;;
775        stf.spill   [in0]=f10,16;;
776        stf.spill   [in0]=f11,16;;
777        stf.spill   [in0]=f12,16;;
778        stf.spill   [in0]=f13,16;;
779        stf.spill   [in0]=f14,16;;
780        stf.spill   [in0]=f15,16;;
781        stf.spill   [in0]=f16,16;;
782        stf.spill   [in0]=f17,16;;
783        stf.spill   [in0]=f18,16;;
784        stf.spill   [in0]=f19,16;;
785        stf.spill   [in0]=f20,16;;
786        stf.spill   [in0]=f21,16;;
787        stf.spill   [in0]=f22,16;;
788        stf.spill   [in0]=f23,16;;
789        stf.spill   [in0]=f24,16;;
790        stf.spill   [in0]=f25,16;;
791        stf.spill   [in0]=f26,16;;
792        stf.spill   [in0]=f27,16;;
793        stf.spill   [in0]=f28,16;;
794        stf.spill   [in0]=f29,16;;
795        stf.spill   [in0]=f30,16;;
796        stf.spill   [in0]=f31,16;;
797        mov         loc0=pr;;               // save predicates
798        st8.spill   [in0]=loc0,8;;
799        st8.spill   [in0]=in1,8;;           // save b0 - b7... in1 already equals saved b0
800        mov         loc0=b1;;
801        st8.spill   [in0]=loc0,8;;
802        mov         loc0=b2;;
803        st8.spill   [in0]=loc0,8;;
804        mov         loc0=b3;;
805        st8.spill   [in0]=loc0,8;;
806        mov         loc0=b4;;
807        st8.spill   [in0]=loc0,8;;
808        mov         loc0=b5;;
809        st8.spill   [in0]=loc0,8;;
810        mov         loc0=b6;;
811        st8.spill   [in0]=loc0,8;;
812        mov         loc0=b7;;
813        st8.spill   [in0]=loc0,8;;
814        mov         loc0=ar.rsc;;           // save ar.rsc
815        st8.spill   [in0]=loc0,8;;
816        st8.spill   [in0]=in2,8;;           // save ar.bsp (in2)
817        st8.spill   [in0]=in3,8;;           // save ar.bspstore (in3)
818        st8.spill   [in0]=in4,8;;           // save ar.rnat (in4)
819        mov         loc0=ar.fcr;;           // save ar.fcr (ar21 - IA32 floating-point control register)
820        st8.spill   [in0]=loc0,8;;
821        mov         loc0=ar.eflag;;         // save ar.eflag (ar24)
822        st8.spill   [in0]=loc0,8;;
823        mov         loc0=ar.csd;;           // save ar.csd (ar25 - ia32 CS descriptor)
824        st8.spill   [in0]=loc0,8;;
825        mov         loc0=ar.ssd;;           // save ar.ssd (ar26 - ia32 ss descriptor)
826        st8.spill   [in0]=loc0,8;;
827        mov         loc0=ar.cflg;;          // save ar.cflg (ar27 - ia32 cr0 and cr4)
828        st8.spill   [in0]=loc0,8;;
829        mov         loc0=ar.fsr;;           // save ar.fsr (ar28 - ia32 floating-point status register)
830        st8.spill   [in0]=loc0,8;;
831        mov         loc0=ar.fir;;           // save ar.fir (ar29 - ia32 floating-point instruction register)
832        st8.spill   [in0]=loc0,8;;
833        mov         loc0=ar.fdr;;           // save ar.fdr (ar30 - ia32 floating-point data register)
834        st8.spill   [in0]=loc0,8;;
835        mov         loc0=ar.ccv;;           // save ar.ccv
836        st8.spill   [in0]=loc0,8;;
837        st8.spill   [in0]=loc2,8;;          // save ar.unat (saved to loc2 earlier)
838        mov         loc0=ar.fpsr;;          // save floating point status register
839        st8.spill   [in0]=loc0,8;;
840        st8.spill   [in0]=in5,8;;           // save ar.pfs
841        mov         loc0=ar.lc;;            // save ar.lc
842        st8.spill   [in0]=loc0,8;;
843        mov         loc0=ar.ec;;            // save ar.ec
844        st8.spill   [in0]=loc0,8;;
845
846        // save control registers
847        mov         loc0=cr.dcr;;           // save dcr
848        st8.spill   [in0]=loc0,8;;
849        mov         loc0=cr.itm;;           // save itm
850        st8.spill   [in0]=loc0,8;;
851        mov         loc0=cr.iva;;           // save iva
852        st8.spill   [in0]=loc0,8;;
853        mov         loc0=cr.pta;;           // save pta
854        st8.spill   [in0]=loc0,8;;
855        mov         loc0=cr.ipsr;;          // save ipsr
856        st8.spill   [in0]=loc0,8;;
857        mov         loc0=cr.isr;;           // save isr
858        st8.spill   [in0]=loc0,8;;
859        mov         loc0=cr.iip;;           // save iip
860        st8.spill   [in0]=loc0,8;;
861        mov         loc0=cr.ifa;;           // save ifa
862        st8.spill   [in0]=loc0,8;;
863        mov         loc0=cr.itir;;          // save itir
864        st8.spill   [in0]=loc0,8;;
865        mov         loc0=cr.iipa;;          // save iipa
866        st8.spill   [in0]=loc0,8;;
867        mov         loc0=cr.ifs;;           // save ifs
868        st8.spill   [in0]=loc0,8;;
869        mov         loc0=cr.iim;;           // save iim
870        st8.spill   [in0]=loc0,8;;
871        mov         loc0=cr.iha;;           // save iha
872        st8.spill   [in0]=loc0,8;;
873
874        // save debug registers
875        mov         loc0=dbr[r0];;          // save dbr0 - dbr7
876        st8.spill   [in0]=loc0,8;;
877        movl        loc1=1;;
878        mov         loc0=dbr[loc1];;
879        st8.spill   [in0]=loc0,8;;
880        movl        loc1=2;;
881        mov         loc0=dbr[loc1];;
882        st8.spill   [in0]=loc0,8;;
883        movl        loc1=3;;
884        mov         loc0=dbr[loc1];;
885        st8.spill   [in0]=loc0,8;;
886        movl        loc1=4;;
887        mov         loc0=dbr[loc1];;
888        st8.spill   [in0]=loc0,8;;
889        movl        loc1=5;;
890        mov         loc0=dbr[loc1];;
891        st8.spill   [in0]=loc0,8;;
892        movl        loc1=6;;
893        mov         loc0=dbr[loc1];;
894        st8.spill   [in0]=loc0,8;;
895        movl        loc1=7;;
896        mov         loc0=dbr[loc1];;
897        st8.spill   [in0]=loc0,8;;
898        mov         loc0=ibr[r0];;          // save ibr0 - ibr7
899        st8.spill   [in0]=loc0,8;;
900        movl        loc1=1;;
901        mov         loc0=ibr[loc1];;
902        st8.spill   [in0]=loc0,8;;
903        movl        loc1=2;;
904        mov         loc0=ibr[loc1];;
905        st8.spill   [in0]=loc0,8;;
906        movl        loc1=3;;
907        mov         loc0=ibr[loc1];;
908        st8.spill   [in0]=loc0,8;;
909        movl        loc1=4;;
910        mov         loc0=ibr[loc1];;
911        st8.spill   [in0]=loc0,8;;
912        movl        loc1=5;;
913        mov         loc0=ibr[loc1];;
914        st8.spill   [in0]=loc0,8;;
915        movl        loc1=6;;
916        mov         loc0=ibr[loc1];;
917        st8.spill   [in0]=loc0,8;;
918        movl        loc1=7;;
919        mov         loc0=ibr[loc1];;
920        st8.spill   [in0]=loc0,8;;
921        st8.spill   [in0]=loc3;;
922
923        br.ret.sptk.few     b0
924
925        .endp       SpillContext
926
927
928/////////////////////////////////////////////
929//
930//  Name:
931//      FillContext
932//
933//  Description:
934//      Restores register context from context record.
935//
936//  Arguments:
937//          in0 = address of last element 512 byte aligned context record address
938//          in1 = modified B0
939//          in2 = modified ar.bsp
940//          in3 = modified ar.bspstore
941//          in4 = modified ar.rnat
942//          in5 = modified ar.pfs
943//
944//  Notes:
945//      loc0 - scratch
946//      loc1 - scratch
947//      loc2 - temporary application unat storage
948//      loc3 - temporary exception handler unat storage
949
950        .proc       FillContext
951FillContext:
952        alloc       loc0=6,4,0,0;;          // alloc 6 inputs, 4 locals, 0 outs
953        ld8.fill    loc3=[in0],-8;;         // int_nat (nat bits for R1-31)
954        movl        loc1=7;;                // ibr7
955        ld8.fill    loc0=[in0],-8;;
956        mov         ibr[loc1]=loc0;;
957        movl        loc1=6;;                // ibr6
958        ld8.fill    loc0=[in0],-8;;
959        mov         ibr[loc1]=loc0;;
960        movl        loc1=5;;                // ibr5
961        ld8.fill    loc0=[in0],-8;;
962        mov         ibr[loc1]=loc0;;
963        movl        loc1=4;;                // ibr4
964        ld8.fill    loc0=[in0],-8;;
965        mov         ibr[loc1]=loc0;;
966        movl        loc1=3;;                // ibr3
967        ld8.fill    loc0=[in0],-8;;
968        mov         ibr[loc1]=loc0;;
969        movl        loc1=2;;                // ibr2
970        ld8.fill    loc0=[in0],-8;;
971        mov         ibr[loc1]=loc0;;
972        movl        loc1=1;;                // ibr1
973        ld8.fill    loc0=[in0],-8;;
974        mov         ibr[loc1]=loc0;;
975        ld8.fill    loc0=[in0],-8;;         // ibr0
976        mov         ibr[r0]=loc0;;
977        movl        loc1=7;;                // dbr7
978        ld8.fill    loc0=[in0],-8;;
979        mov         dbr[loc1]=loc0;;
980        movl        loc1=6;;                // dbr6
981        ld8.fill    loc0=[in0],-8;;
982        mov         dbr[loc1]=loc0;;
983        movl        loc1=5;;                // dbr5
984        ld8.fill    loc0=[in0],-8;;
985        mov         dbr[loc1]=loc0;;
986        movl        loc1=4;;                // dbr4
987        ld8.fill    loc0=[in0],-8;;
988        mov         dbr[loc1]=loc0;;
989        movl        loc1=3;;                // dbr3
990        ld8.fill    loc0=[in0],-8;;
991        mov         dbr[loc1]=loc0;;
992        movl        loc1=2;;                // dbr2
993        ld8.fill    loc0=[in0],-8;;
994        mov         dbr[loc1]=loc0;;
995        movl        loc1=1;;                // dbr1
996        ld8.fill    loc0=[in0],-8;;
997        mov         dbr[loc1]=loc0;;
998        ld8.fill    loc0=[in0],-8;;         // dbr0
999        mov         dbr[r0]=loc0;;
1000        ld8.fill    loc0=[in0],-8;;         // iha
1001        mov         cr.iha=loc0;;
1002        ld8.fill    loc0=[in0],-8;;         // iim
1003        mov         cr.iim=loc0;;
1004        ld8.fill    loc0=[in0],-8;;         // ifs
1005        mov         cr.ifs=loc0;;
1006        ld8.fill    loc0=[in0],-8;;         // iipa
1007        mov         cr.iipa=loc0;;
1008        ld8.fill    loc0=[in0],-8;;         // itir
1009        mov         cr.itir=loc0;;
1010        ld8.fill    loc0=[in0],-8;;         // ifa
1011        mov         cr.ifa=loc0;;
1012        ld8.fill    loc0=[in0],-8;;         // iip
1013        mov         cr.iip=loc0;;
1014        ld8.fill    loc0=[in0],-8;;         // isr
1015        mov         cr.isr=loc0;;
1016        ld8.fill    loc0=[in0],-8;;         // ipsr
1017        mov         cr.ipsr=loc0;;
1018        ld8.fill    loc0=[in0],-8;;         // pta
1019        mov         cr.pta=loc0;;
1020        ld8.fill    loc0=[in0],-8;;         // iva
1021        mov         cr.iva=loc0;;
1022        ld8.fill    loc0=[in0],-8;;         // itm
1023        mov         cr.itm=loc0;;
1024        ld8.fill    loc0=[in0],-8;;         // dcr
1025        mov         cr.dcr=loc0;;
1026        ld8.fill    loc0=[in0],-8;;         // ec
1027        mov         ar.ec=loc0;;
1028        ld8.fill    loc0=[in0],-8;;         // lc
1029        mov         ar.lc=loc0;;
1030        ld8.fill    in5=[in0],-8;;          // ar.pfs
1031        ld8.fill    loc0=[in0],-8;;         // ar.fpsr
1032        mov         ar.fpsr=loc0;;
1033        ld8.fill    loc2=[in0],-8;;         // ar.unat - restored later...
1034        ld8.fill    loc0=[in0],-8;;         // ar.ccv
1035        mov         ar.ccv=loc0;;
1036        ld8.fill    loc0=[in0],-8;;         // ar.fdr
1037        mov         ar.fdr=loc0;;
1038        ld8.fill    loc0=[in0],-8;;         // ar.fir
1039        mov         ar.fir=loc0;;
1040        ld8.fill    loc0=[in0],-8;;         // ar.fsr
1041        mov         ar.fsr=loc0;;
1042        ld8.fill    loc0=[in0],-8;;         // ar.cflg
1043        mov         ar.cflg=loc0;;
1044        ld8.fill    loc0=[in0],-8;;         // ar.ssd
1045        mov         ar.ssd=loc0;;
1046        ld8.fill    loc0=[in0],-8;;         // ar.csd
1047        mov         ar.csd=loc0;;
1048        ld8.fill    loc0=[in0],-8;;         // ar.eflag
1049        mov         ar.eflag=loc0;;
1050        ld8.fill    loc0=[in0],-8;;         // ar.fcr
1051        mov         ar.fcr=loc0;;
1052        ld8.fill    in4=[in0],-8;;          // ar.rnat
1053        ld8.fill    in3=[in0],-8;;          // bspstore
1054        ld8.fill    in2=[in0],-8;;          // bsp
1055        ld8.fill    loc0=[in0],-8;;         // ar.rsc
1056        mov         ar.rsc=loc0;;
1057        ld8.fill    loc0=[in0],-8;;         // B7 - B0
1058        mov         b7=loc0;;
1059        ld8.fill    loc0=[in0],-8;;
1060        mov         b6=loc0;;
1061        ld8.fill    loc0=[in0],-8;;
1062        mov         b5=loc0;;
1063        ld8.fill    loc0=[in0],-8;;
1064        mov         b4=loc0;;
1065        ld8.fill    loc0=[in0],-8;;
1066        mov         b3=loc0;;
1067        ld8.fill    loc0=[in0],-8;;
1068        mov         b2=loc0;;
1069        ld8.fill    loc0=[in0],-8;;
1070        mov         b1=loc0;;
1071        ld8.fill    in1=[in0],-8;;          // b0 is temporarily stored in in1
1072        ld8.fill    loc0=[in0],-16;;        // predicates
1073        mov         pr=loc0;;
1074        ldf.fill    f31=[in0],-16;;
1075        ldf.fill    f30=[in0],-16;;
1076        ldf.fill    f29=[in0],-16;;
1077        ldf.fill    f28=[in0],-16;;
1078        ldf.fill    f27=[in0],-16;;
1079        ldf.fill    f26=[in0],-16;;
1080        ldf.fill    f25=[in0],-16;;
1081        ldf.fill    f24=[in0],-16;;
1082        ldf.fill    f23=[in0],-16;;
1083        ldf.fill    f22=[in0],-16;;
1084        ldf.fill    f21=[in0],-16;;
1085        ldf.fill    f20=[in0],-16;;
1086        ldf.fill    f19=[in0],-16;;
1087        ldf.fill    f18=[in0],-16;;
1088        ldf.fill    f17=[in0],-16;;
1089        ldf.fill    f16=[in0],-16;;
1090        ldf.fill    f15=[in0],-16;;
1091        ldf.fill    f14=[in0],-16;;
1092        ldf.fill    f13=[in0],-16;;
1093        ldf.fill    f12=[in0],-16;;
1094        ldf.fill    f11=[in0],-16;;
1095        ldf.fill    f10=[in0],-16;;
1096        ldf.fill    f9=[in0],-16;;
1097        ldf.fill    f8=[in0],-16;;
1098        ldf.fill    f7=[in0],-16;;
1099        ldf.fill    f6=[in0],-16;;
1100        ldf.fill    f5=[in0],-16;;
1101        ldf.fill    f4=[in0],-16;;
1102        ldf.fill    f3=[in0],-16;;
1103        ldf.fill    f2=[in0],-8;;
1104        mov         ar.unat=loc3;;          // restore unat (int_nat) before fill of general registers
1105        ld8.fill    r31=[in0],-8;;
1106        ld8.fill    r30=[in0],-8;;
1107        ld8.fill    r29=[in0],-8;;
1108        ld8.fill    r28=[in0],-8;;
1109        ld8.fill    r27=[in0],-8;;
1110        ld8.fill    r26=[in0],-8;;
1111        ld8.fill    r25=[in0],-8;;
1112        ld8.fill    r24=[in0],-8;;
1113        ld8.fill    r23=[in0],-8;;
1114        ld8.fill    r22=[in0],-8;;
1115        ld8.fill    r21=[in0],-8;;
1116        ld8.fill    r20=[in0],-8;;
1117        ld8.fill    r19=[in0],-8;;
1118        ld8.fill    r18=[in0],-8;;
1119        ld8.fill    r17=[in0],-8;;
1120        ld8.fill    r16=[in0],-8;;
1121        ld8.fill    r15=[in0],-8;;
1122        ld8.fill    r14=[in0],-8;;
1123        ld8.fill    r13=[in0],-8;;
1124        ld8.fill    r12=[in0],-8;;
1125        ld8.fill    r11=[in0],-8;;
1126        ld8.fill    r10=[in0],-8;;
1127        ld8.fill    r9=[in0],-8;;
1128        ld8.fill    r8=[in0],-8;;
1129        ld8.fill    r7=[in0],-8;;
1130        ld8.fill    r6=[in0],-8;;
1131        ld8.fill    r5=[in0],-8;;
1132        ld8.fill    r4=[in0],-8;;
1133        ld8.fill    r3=[in0],-8;;
1134        ld8.fill    r2=[in0],-8;;
1135        ld8.fill    r1=[in0],-8;;
1136        mov         ar.unat=loc2;;          // restore application context unat
1137
1138        br.ret.sptk.many    b0
1139
1140        .endp       FillContext
1141
1142
1143/////////////////////////////////////////////
1144//
1145//  Name:
1146//      HookHandler
1147//
1148//  Description:
1149//      Common branch target from hooked IVT entries.  Runs in interrupt context.
1150//      Responsible for saving and restoring context and calling common C
1151//      handler.  Banked registers running on bank 0 at entry.
1152//
1153//  Arguments:
1154//      All arguments are passed in banked registers:
1155//          B0_REG = Original B0
1156//          SCRATCH_REG1 = IVT entry index
1157//
1158//  Returns:
1159//      Returns via rfi
1160//
1161//  Notes:
1162//      loc0 - scratch
1163//      loc1 - scratch
1164//      loc2 - vector number / mask
1165//      loc3 - 16 byte aligned context record address
1166//      loc4 - temporary storage of last address in context record
1167
1168HookHandler:
1169        flushrs;;                               // Synch RSE with backing store
1170        mov         SCRATCH_REG2=ar.bsp         // save interrupted context bsp
1171        mov         SCRATCH_REG3=ar.bspstore    // save interrupted context bspstore
1172        mov         SCRATCH_REG4=ar.rnat        // save interrupted context rnat
1173        mov         SCRATCH_REG6=cr.ifs;;       // save IFS in case we need to chain...
1174        cover;;                                 // creates new frame, moves old
1175                                                //   CFM to IFS.
1176        alloc       SCRATCH_REG5=0,5,6,0        // alloc 5 locals, 6 outs
1177        ;;
1178        // save banked registers to locals
1179        mov         out1=B0_REG                 // out1 = Original B0
1180        mov         out2=SCRATCH_REG2           // out2 = original ar.bsp
1181        mov         out3=SCRATCH_REG3           // out3 = original ar.bspstore
1182        mov         out4=SCRATCH_REG4           // out4 = original ar.rnat
1183        mov         out5=SCRATCH_REG5           // out5 = original ar.pfs
1184        mov         loc2=SCRATCH_REG1;;         // loc2 = vector number + chain flag
1185        bsw.1;;                                 // switch banked registers to bank 1
1186        srlz.d                                  // explicit serialize required
1187                                                // now fill in context record structure
1188        movl        loc3=IpfContextBuf          // Insure context record is aligned
1189        add         loc0=-0x200,r0;;            // mask the lower 9 bits (align on 512 byte boundary)
1190        and         loc3=loc3,loc0;;
1191        add         loc3=0x200,loc3;;           // move to next 512 byte boundary
1192                                                // loc3 now contains the 512 byte aligned context record
1193                                                // spill register context into context record
1194        mov         out0=loc3;;                 // Context record base in out0
1195                                                // original B0 in out1 already
1196                                                // original ar.bsp in out2 already
1197                                                // original ar.bspstore in out3 already
1198        br.call.sptk.few b0=SpillContext;;      // spill context
1199        mov         loc4=out0                   // save modified address
1200
1201    // At this point, the context has been saved to the context record and we're
1202    // ready to call the C part of the handler...
1203
1204        movl        loc0=CommonHandler;;        // obtain address of plabel
1205        ld8         loc1=[loc0];;               // get entry point of CommonHandler
1206        mov         b6=loc1;;                   // put it in a branch register
1207        adds        loc1= 8, loc0;;             // index to GP in plabel
1208        ld8         r1=[loc1];;                 // set up gp for C call
1209        mov         loc1=0xfffff;;              // mask off so only vector bits are present
1210        and         out0=loc2,loc1;;            // pass vector number (exception type)
1211        mov         out1=loc3;;                 // pass context record address
1212        br.call.sptk.few b0=b6;;                // call C handler
1213
1214    // We've returned from the C call, so restore the context and either rfi
1215    // back to interrupted thread, or chain into the SAL if this was an external interrupt
1216        mov         out0=loc4;;                 // pass address of last element in context record
1217        br.call.sptk.few b0=FillContext;;       // Fill context
1218        mov         b0=out1                     // fill in b0
1219        mov         ar.rnat=out4
1220        mov         ar.pfs=out5
1221
1222  // Loadrs is necessary because the debugger may have changed some values in
1223  // the backing store.  The processor, however may not be aware that the
1224  // stacked registers need to be reloaded from the backing store.  Therefore,
1225  // we explicitly cause the RSE to refresh the stacked register's contents
1226  // from the backing store.
1227        mov         loc0=ar.rsc                 // get RSC value
1228        mov         loc1=ar.rsc                 // save it so we can restore it
1229        movl        loc3=0xffffffffc000ffff;;   // create mask for clearing RSC.loadrs
1230        and         loc0=loc0,loc3;;            // create value for RSC with RSC.loadrs==0
1231        mov         ar.rsc=loc0;;               // modify RSC
1232        loadrs;;                                // invalidate register stack
1233        mov         ar.rsc=loc1;;               // restore original RSC
1234
1235        bsw.0;;                                 // switch banked registers back to bank 0
1236        srlz.d;;                                // explicit serialize required
1237        mov         PR_REG=pr                   // save predicates - to be restored after chaining decision
1238        mov         B0_REG=b0                   // save b0 - required by chain code
1239        mov         loc2=EXCPT_EXTERNAL_INTERRUPT;;
1240        cmp.eq      p7,p0=SCRATCH_REG1,loc2;;   // check to see if this is the timer tick
1241  (p7)  br.cond.dpnt.few    DO_CHAIN;;
1242
1243NO_CHAIN:
1244        mov         pr=PR_REG;;
1245        rfi;;                                   // we're outa here.
1246
1247DO_CHAIN:
1248        mov         pr=PR_REG
1249        mov         SCRATCH_REG1=cr.iva
1250        mov         SCRATCH_REG2=PATCH_RETURN_OFFSET;;
1251        add         SCRATCH_REG1=SCRATCH_REG1, SCRATCH_REG2;;
1252        mov         b0=SCRATCH_REG1;;
1253        br.cond.sptk.few  b0;;
1254
1255EndHookHandler:
1256
1257
1258/////////////////////////////////////////////
1259//
1260//  Name:
1261//      HookStub
1262//
1263//  Description:
1264//      HookStub will be copied from it's loaded location into the IVT when
1265//      an IVT entry is hooked.  The IVT entry does an indirect jump via B0 to
1266//      HookHandler, which in turn calls into the default C handler, which calls
1267//      the user-installed C handler.  The calls return and HookHandler executes
1268//      an rfi.
1269//
1270//  Notes:
1271//      Saves B0 to B0_REG
1272//      Saves IVT index to SCRATCH_REG1 (immediate value is fixed up when code is copied
1273//          to the IVT entry.
1274
1275        ASM_GLOBAL HookStub
1276        .proc   HookStub
1277HookStub:
1278
1279        mov         B0_REG=b0
1280        movl        SCRATCH_REG1=HookHandler;;
1281        mov         b0=SCRATCH_REG1;;
1282        mov         SCRATCH_REG1=0;;// immediate value is fixed up during install of handler to be the vector number
1283        br.cond.sptk.few b0
1284
1285        .endp       HookStub
1286
1287
1288/////////////////////////////////////////////
1289// The following code is moved into IVT entry 14 (offset 3400) which is reserved
1290// in the Itanium architecture.  The patch code is located at the end of the
1291// IVT entry.
1292
1293PatchCode:
1294        mov       SCRATCH_REG0=psr
1295        mov       SCRATCH_REG6=cr.ipsr
1296        mov       PR_REG=pr
1297        mov       B0_REG=b0;;
1298
1299        // turn off any virtual translations
1300        movl      SCRATCH_REG1 = ~( MASK(PSR_DT,1) | MASK(PSR_RT,1));;
1301        and       SCRATCH_REG1 = SCRATCH_REG0, SCRATCH_REG1;;
1302        mov       psr.l = SCRATCH_REG1;;
1303        srlz.d
1304        tbit.z    p14, p15 = SCRATCH_REG6, PSR_IS;;   // Check to see if we were
1305                                                      // interrupted from IA32
1306                                                      // context.  If so, bail out
1307                                                      // and chain to SAL immediately
1308 (p15)  br.cond.sptk.few Stub_IVT_Passthru;;
1309        // we only want to take 1 out of 32 external interrupts to minimize the
1310        // impact to system performance.  Check our interrupt count and bail
1311        // out if we're not up to 32
1312        movl      SCRATCH_REG1=ExternalInterruptCount;;
1313        ld8       SCRATCH_REG2=[SCRATCH_REG1];;       // ExternalInterruptCount
1314        tbit.z    p14, p15 = SCRATCH_REG2, 5;;        // bit 5 set?
1315 (p14)  add       SCRATCH_REG2=1, SCRATCH_REG2;;      // No?  Then increment
1316                                                      // ExternalInterruptCount
1317                                                      // and Chain to SAL
1318                                                      // immediately
1319 (p14)  st8       [SCRATCH_REG1]=SCRATCH_REG2;;
1320 (p14)  br.cond.sptk.few Stub_IVT_Passthru;;
1321 (p15)  mov       SCRATCH_REG2=0;;                    // Yes?  Then reset
1322                                                        // ExternalInterruptCount
1323                                                        // and branch to
1324                                                        // HookHandler
1325 (p15)  st8       [SCRATCH_REG1]=SCRATCH_REG2;;
1326        mov       pr=PR_REG
1327        movl      SCRATCH_REG1=HookHandler;;          // SCRATCH_REG1 = entrypoint of HookHandler
1328        mov       b0=SCRATCH_REG1;;                   // b0 = entrypoint of HookHandler
1329        mov       SCRATCH_REG1=EXCPT_EXTERNAL_INTERRUPT;;
1330        br.sptk.few b0;;                                // branch to HookHandler
1331
1332PatchCodeRet:
1333        // fake-up an rfi to get RSE back to being coherent and insure psr has
1334        // original contents when interrupt occured, then exit to SAL
1335        // at this point:
1336        //      cr.ifs has been modified by previous "cover"
1337        //      SCRATCH_REG6 has original cr.ifs
1338
1339        mov       SCRATCH_REG5=cr.ipsr
1340        mov       SCRATCH_REG4=cr.iip;;
1341        mov       cr.ipsr=SCRATCH_REG0
1342        mov       SCRATCH_REG1=ip;;
1343        add       SCRATCH_REG1=0x30, SCRATCH_REG1;;
1344        mov       cr.iip=SCRATCH_REG1;;
1345        rfi;;                       // rfi to next instruction
1346
1347Stub_RfiTarget:
1348        mov       cr.ifs=SCRATCH_REG6
1349        mov       cr.ipsr=SCRATCH_REG5
1350        mov       cr.iip=SCRATCH_REG4;;
1351
1352Stub_IVT_Passthru:
1353        mov       pr=PR_REG                         // pr = saved predicate registers
1354        mov       b0=B0_REG;;                       // b0 = saved b0
1355EndPatchCode:
1356
1357
1358/////////////////////////////////////////////
1359// The following bundle is moved into IVT entry 14 (offset 0x3400) which is reserved
1360// in the Itanium architecture.  This bundle will be the last bundle and will
1361// be located at offset 0x37F0 in the IVT.
1362
1363FailsafeBranch:
1364{
1365        .mib
1366        nop.m     0
1367        nop.i     0
1368        br.sptk.few -(FAILSAFE_BRANCH_OFFSET - EXT_INT_ENTRY_OFFSET - 0x10)
1369}
1370
1371
1372/////////////////////////////////////////////
1373// The following bundle is moved into IVT entry 13 (offset 0x3000) which is the
1374// external interrupt.  It branches to the patch code.
1375
1376PatchCodeNewBun0:
1377{
1378        .mib
1379        nop.m     0
1380        nop.i     0
1381        br.cond.sptk.few PATCH_BRANCH
1382}
1383