Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / fm / kernel / sparc / checkpt.fth
CommitLineData
920dae64
AT
1\ ========== Copyright Header Begin ==========================================
2\
3\ Hypervisor Software File: checkpt.fth
4\
5\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6\
7\ - Do no alter or remove copyright notices
8\
9\ - Redistribution and use of this software in source and binary forms, with
10\ or without modification, are permitted provided that the following
11\ conditions are met:
12\
13\ - Redistribution of source code must retain the above copyright notice,
14\ this list of conditions and the following disclaimer.
15\
16\ - Redistribution in binary form must reproduce the above copyright notice,
17\ this list of conditions and the following disclaimer in the
18\ documentation and/or other materials provided with the distribution.
19\
20\ Neither the name of Sun Microsystems, Inc. or the names of contributors
21\ may be used to endorse or promote products derived from this software
22\ without specific prior written permission.
23\
24\ This software is provided "AS IS," without a warranty of any kind.
25\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
26\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
27\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
28\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
29\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
30\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
31\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
32\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
33\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
34\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
35\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
36\
37\ You acknowledge that this software is not designed, licensed or
38\ intended for use in the design, construction, operation or maintenance of
39\ any nuclear facility.
40\
41\ ========== Copyright Header End ============================================
42id: @(#)checkpt.fth 1.4 05/04/08 22:16:13
43purpose:
44copyright: Copyright 2005 Sun Microsystems, Inc. All Rights Reserved
45copyright: Use is subject to license terms.
46
47\ Checkpt
48\
49\ a checkpt is like a setjmp/longjmp in C. (man setjmp)
50\
51\ push-checkpt : Create an exception frame and push it onto the exception
52\ stack
53
54\ pop-checkpt : Dispose the current exception frame.
55\
56\ The catch and throw are special cases of checkpts.
57\
58\ One of the difference between a push-checkpt and a 'catch' is that
59\ the catch calls the thing it is trying to catch, a checkpoint does
60\ not have this restriction. Looking at the tail end of 'catch' in
61\ the normal execution case it pops the handler, which is the exact
62\ equivalent of 'pop-checkpt'.
63\
64\ The primary difference is that you can mark a checkpoint at an arbitrary
65\ point and 'recover' much like a 'catch' does except that you are no
66\ longer on the same descending call frame (e.g., return stack).
67\
68\ So, consider
69\ : xxx cmn-error[ ..-1 throw ... ]cmn-end ;
70\ : yyy ['] xxx catch ;
71\
72\ The throw destroys the error frame by returning control to the 'catch'.
73\
74\ Now if cmn-error[ was implemented:
75\
76\ : (]cmn-end) ... ;
77\ : cmn-error[
78\ push-checkpt ?dup if
79\ " [truncated]" (]cmn-end)
80\ throw
81\ else
82\ <start the message>
83\ then
84\ ;
85\
86\ : ]cmn-end (]cmn-end) pop-checkpt ;
87\
88\ What we have done is ensure that an error inside an error message
89\ frame is constrained in a recoverable manner and the original 'throw'
90\ is propogated to the catch in yyy.
91\
92\ The magic is that 'cmn-error[' returned to its caller normally and the
93\ caller xxx drove on, but on ERROR the code jumped back into the cmn-error[
94\ routine which then had to throw. If it had not then the '-1 throw' would
95\ execute again (assuming no other disasterous stack effects).
96\
97\ To be a good citizen you should only 'recover' from an error and
98\ not propogate a throw if you know that the throw code is yours (as
99\ in the example).
100\
101\ In general it is bad practice to return from the routine that
102\ established the check point (ie the routine that called 'push-checkpt'),
103\ though a maximum unnest of /check-stack stack elements will permit this
104\ to work.
105\
106\ IT IS BEST *NOT* TO RETURN FROM THE CHECKPOINT FRAME;
107\ THOUGH IT WILL WORK IN MANY CASES
108\
109\ This is a similar restriction to setjmp/longjmp in C.
110\
111\ Frame Starts Frame Ends
112\ push-checkpt pop-checkpt, throw
113\ catch throw
114\
115
116headers
117[ifdef] KERNEL
118nuser checkpt \ most recent checkpoint
119nuser checkbase \ frames
120nuser checktrack \ tracker
121nuser checkalloc \ counter
122nuser checkmax \ max frames
123nuser checknested
124also meta also definitions \ setup metacompiler magic
125[else]
126variable checkpt
127variable checkbase
128variable checktrack
129variable checkalloc
130variable checkmax
131variable checknested
132[then]
133
134[ifdef] miniforth?
135h# 18 constant /check-max \ max outstanding catch frames
136[else]
137h# 80 constant /check-max \ frames alloc'd after dynamic heap
138[then]
139h# 10 constant /check-crit \ frames alloc'd from critical heap
140headerless
1418 constant /check-stack \ How many elements to preserve
142 \ sized for known catch stack usage
143struct
144 /n field >check-prev \ previous frame
145 /n field >check-ip \ checkpt IP
146 /n field >check-sp \ checkpt DS pointer
147 /n field >check-rp \ checkpt RS pointer
148 /l field >check-myself \ my-self
149 /l field >check-age
150 /check-stack /n * field >check-ds \ a chunk of the DS
151 /check-stack /n * field >check-rs \ a chunk of the RS
152constant /check-frame
153
154[ifdef] KERNEL
155previous previous definitions \ back to kernel
156
157\ create the kernel side of these routines, using the structure
158\ created in the host metacompiler to form the offsets.
159
160: >check-prev [ 0 >check-prev ] literal + ;
161: >check-myself [ 0 >check-myself ] literal + ;
162: >check-age [ 0 >check-age ] literal + ;
163
164headers
1650 value my-self
166headerless
167[then]
168
169\ initial 16 frames are allocated from the critical heap
170: init-checkpt
171 checkpt off
172 checkalloc off
173 checknested off
174 /check-crit checkmax !
175 /check-crit dup alloc-mem dup checktrack ! ( va )
176 swap erase ( len va )
177 /check-crit /check-frame * /n + ( sz )
178 alloc-mem /n 1- + /n 1- invert and checkbase ! ( )
179;
180
181\ dynamic heap is installed before we call into this so that the frame alloc
182\ requirements can be satisfied by the expanded heap made available.
183\ the alloc-mem calls will cause checkpt frames to be alloc/free'd due to
184\ calls to 'catch', relying on a coherent state in the checkpt variables,
185\ so the expanded allocations must not be swapped in until after they complete.
186\
187: alloc-checkpt
188 \ alloc max checktrack and copy critical heap checktrack
189 checktrack @ >r r@ ( oldt ) ( r: t )
190 /check-max dup alloc-mem ( oldt len newt )
191 dup rot erase swap ( newt oldt )
192 /check-crit bounds do i c@ over c! 1+ loop ( newt' )
193 /check-crit - ( newt )
194
195 \ alloc max checkpt frames and copy critical heap frames
196 checkbase @ >r r@ tuck ( oldb newt oldb ) ( r: t b )
197 /check-max /check-frame * /n + ( oldb newt oldb len )
198 alloc-mem /n 1- + /n 1- invert and ( oldb newt oldb newb )
199 swap /check-crit /check-frame * bounds ( oldb newt newb hi lo )
200 2dup /check-frame + 2>r ( oldb newt newb hi lo )
201 do i @ over ! na1+ /n +loop ( oldb newt newb' )
202 /check-crit /check-frame * - ( oldb newt newb )
203
204 \ having copied the old frames to the new now patch the >check-prev ptrs
205 \ start at second frame of old and new frames as first frame has null ptr
206 2 pick over /check-frame + 2r> do ( oldb newt newb oldb newb' )
207 over i @ swap - 3 pick + over ! ( oldb newt newb oldb newb'' )
208 /check-frame + /check-frame +loop ( oldb newt newb oldb newb'' )
209 2drop ( oldb newt newb )
210
211 \ now swap in expanded frame allocations after fully initialized
212 \ update checkpt to current frame in newly allocate frames
213 checkbase ! checktrack ! ( oldb )
214 checkpt @ ?dup if ( oldb cur )
215 swap - checkbase @ + checkpt ! ( )
216 else ( oldb )
217 drop ( )
218 then ( )
219 /check-max checkmax ! ( ) ( r: t b )
220
221 r> /check-crit /check-frame * free-mem ( ) ( r: t )
222 r> /check-crit free-mem ( )
223;
224
225\
226\ returns false the first time it is called (by push-checkpt)
227\ returns the throw code when the saved state is restored by restore-checkpt
228\ so that push-checkpt can distinguish between the initial save and a throw
229\ the saved IP will be the symbol after save-checkpt in push-checkpt
230\ the top /check-stack elements of both stacks are preserved
231\
232code save-checkpt ( frame -- 0 )
233 ip tos 0 >check-ip nput
234 \ copy the data stack
235 /check-stack /n* scr move
236 sp sc1 move \ saved SP
237 rp sc2 move \ saved RP
238 tos 0 >check-ds sc3 add
239 tos 0 >check-rs sc4 add
240 begin
241 scr /n scr subcc
242 sp sc5 pop
243 sc5 sc3 scr nput
244 rp sc6 pop
245 0= until
246 sc6 sc4 scr nput
247
248 sp tos 0 >check-sp nput
249 rp tos 0 >check-rp nput
250
251 sc1 sp move \ Restore SP
252 sc2 rp move \ Restore RP
253
254 %g0 tos move
255c;
256
257\ This works by restoring the return and data stack pointers and
258\ /check-stack worth of data from the last checkpt frame,
259\ restoring the IP and then setting tos to the throw code.
260\
261\ the effect is to restart the execution at the symbol following the
262\ save-checkpt call in push-checkpt.
263\
264code restore-checkpt ( code frame -- code )
265 sp sc7 pop
266 tos 0 >check-ip ip nget
267 tos 0 >check-sp sp nget
268 tos 0 >check-rp rp nget
269
270 /check-stack /n* scr move
271 tos 0 >check-ds sc1 add
272 tos 0 >check-rs sc2 add
273 %g0 sc3 move
274 begin
275 scr /n scr subcc
276 sc1 sc3 sc5 nget
277 sc5 sp push
278 sc2 sc3 sc6 nget
279 sc6 rp push
280 0= until
281 sc3 /n sc3 add
282
283 sc7 tos move
284c;
285
286\
287\ We free 16 frames - and hope this is enough to go interactive again
288\ may be useful to increase for debugging
289\ we only get here if we ran out of frames
290\
291: free-oldest-frames ( -- )
292 h# 10 0 do
293 checkalloc @ 0 checkmax @ 0 ?do ( age n )
294 over ( age n age )
295 checkbase @ i /check-frame * + ( age n age ptr )
296 >check-age l@ ( age n age age-2 )
297 tuck > ( age n age-2 old? )
298 checktrack @ i + c@ 0<> ( age n age-2 old? used? )
299 and if ( age n age-2 )
300 nip nip i leave ( age' i )
301 else ( age n age-2 )
302 drop ( age n )
303 then ( age' i )
304 loop ( age n )
305 checktrack @ + 0 swap c! drop ( )
306 loop
307;
308
309\ We track individual allocs so that on an error (no more frames)
310\ we can find the 'oldest' and try to reuse them. This will (hopefully)
311\ give some insight into what the latest sequence of failures was.
312\
313: alloc-frame ( -- n )
314 1 checkalloc +! ( )
315 -1 checktrack @ checkmax @ bounds ?do ( -1 )
316 i c@ 0= if ( -1 )
317 i c! ( )
318 i checktrack @ - leave ( n )
319 then ( n )
320 loop ( n )
321 dup 0< if
322 free-oldest-frames ( )
323 ." FATAL: no exception frames available, "
324 checknested @ checknested on if
325 ." NESTED ERRORs, going interactive" cr
326 begin interact again
327 else
328 ." forcing misaligned trap" cr
329 -1 @
330 then
331 then
332 /check-frame * checkbase @ + ( n )
333 checkalloc @ over >check-age l! ( n )
334;
335
336: free-frame ( ptr -- )
337 0 swap checkbase @ - /check-frame / checktrack @ + c!
338;
339
340: (free-checkpt) ( frame -- )
341 dup >check-prev @ checkpt ! ( frame )
342 free-frame ( )
343;
344
345headers
346
347\ free all allocated frames. used to wipe out frames when reentering
348\ obp (l1-a, halt, exception, etc). the allocated frames are stale and
349\ we prefer to begin with a complete set. otherwise, frames will
350\ slowly leak as we exit/reenter forth (go, breakpoint, etc).
351: reset-checkpts ( -- )
352 checktrack @ checkmax @ erase
353 checkpt off
354;
355
356\ Dispose the current exception frame.
357\
358: pop-checkpt ( -- ) checkpt @ ?dup if (free-checkpt) then ;
359
360\ If a non-zero throw is done, then we unwind the current checkpoint
361\
362: throw ( n -- ) ?dup if checkpt @ ?dup if restore-checkpt then then ;
363
364\
365\ Create an exception frame and push it onto the exception stack
366\
367: push-checkpt ( ??? -- ??? code )
368 alloc-frame >r ( ??? )
369 checkpt @ r@ >check-prev ! ( ??? )
370 my-self r@ >check-myself l! ( ??? )
371 r@ save-checkpt dup if ( ??? code )
372 r> ( ??? code frame )
373 dup >check-myself l@ is my-self ( ??? code frame )
374 (free-checkpt) ( ??? code )
375 else ( ??? 0 )
376 r> checkpt ! ( ??? 0 )
377 then ( ??? code )
378;
379
380: catch ( ??? acf -- code )
381 push-checkpt ?dup if
382 nip
383 else
384 execute pop-checkpt 0
385 then
386;
387
388chain: init
389 init-checkpt
390;