1Date: Tue, 11 Jan 94 13:23:11 -0800 2From: "pardo@cs.washington.edu" <pardo@meitner.cs.washington.edu> 3 4>[What's needed to get `qt' on an i860-based machine?] 5 6Almost certainly "some assembly required" (pun accepted). 7 8To write a cswap port, you need to understand the context switching 9model. Turn to figure 2 in the QT TR. Here's about what the assembly 10code looks like to implement that: 11 12 qt_cswap: 13 adjust stack pointer 14 save callee-save registers on to old's stack 15 argument register <- old sp 16 sp <- new sp 17 (*helper)(args...) 18 restore callee-save registers from new's stack 19 unadjust stack pointer 20 return 21 22Once more in slow motion: 23 24 - `old' thread calls context switch routine (new, a0, a1, h) 25 - cswap routine saves registers that have useful values 26 - cswap routine switches to new stack 27 - cswap routine calls helper function (*h)(old, a0, a1) 28 - when helper returns, cswap routine restores registers 29 that were saved the last time `new' was suspended 30 - cswap routine returns to whatever `new' routine called the 31 context switch routine 32 33There's a few tricks here. First, how do you start a thread running 34for the very first time? Answer is: fake some stuff on the stack 35so it *looks* like it was called from the middle of some routine. 36When the new thread is restarted, it is treated like any other 37thread. It just so happens that it's never really run before, but 38you can't tell that because the saved state makes it look like like 39it's been run. The return pc is set to point at a little stub of 40assembly code that loads up registers with the right values and 41then calls `only'. 42 43Second, I advise you to forget about varargs routines (at least 44until you get single-arg routines up and running). 45 46Third, on most machines `qt_abort' is the same as `qt_cswap' except 47that it need not save any callee-save registers. 48 49Fourth, `qt_cswap' needs to save and restore any floating-point 50registers that are callee-save (see your processor handbook). On 51some machines, *no* floating-point registers are callee-save, so 52`qt_cswap' is exactly the same as the integer-only cswap routine. 53 54I suggest staring at the MIPS code for a few minutes. It's "mostly" 55generic RISC code, so it gets a lot of the flavor across without 56getting too bogged down in little nitty details. 57 58 59 60Now for a bit more detail: The stack is laid out to hold callee-save 61registers. On many machines, I implemented fp cswap as save fp 62regs, call integer cswap, and when integer cswap returns (when the 63thread wakes up again), restore fp regs. 64 65For thread startup, I figure out some callee-save registers that 66I use to hold parameters to the startup routine (`only'). When 67the thread is being started it doesn't have any saved registers 68that need to be restored, but I go ahead and let the integer context 69switch routine restore some registers then "return" to the stub 70code. The stub code then copies the "callee save" registers to 71argument registers and calls the startup routine. That keeps the 72stub code pretty darn simple. 73 74For each machine I need to know the machine's procedure calling 75convention before I write a port. I figure out how many callee-save 76registers are there and allocate enough stack space for those 77registers. I also figure out how parameters are passed, since I 78will need to call the helper function. On most RISC machines, I 79just need to put the old sp in the 0'th arg register and then call 80indirect through the 3rd arg register; the 1st and 2nd arg registers 81are already set up correctly. Likewise, I don't touch the return 82value register between the helper's return and the context switch 83routine's return. 84 85I have a bunch of macros set up to do the stack initialization. 86The easiest way to debug this stuff is to go ahead and write a C 87routine to do stack initialization. Once you're happy with it you 88can turn it in to a macro. 89 90In general there's a lot of ugly macros, but most of them do simple 91things like return constants, etc. Any time you're looking at it 92and it looks confusing you just need to remember "this is actually 93simple code, the only tricky thing is calling the helper between 94the stack switch and the new thread's register restore." 95 96 97You will almost certainly need to write the assembly code fragment 98that starts a thread. You might be able to do a lot of the context 99switch code with `setjmp' and `longjmp', if they *happen* to have 100the "right" implementation. But getting all the details right (the 101helper can return a value to the new thread's cswap routine caller) 102is probaby trickier than writing code that does the minimum and 103thus doesn't have any extra instructions (or generality) to cause 104problems. 105 106I don't know of any ports besides those included with the source 107code distribution. If you send me a port I will hapily add it to 108the distribution. 109 110Let me know as you have questions and/or comments. 111 112 ;-D on ( Now *that*'s a switch... ) Pardo 113