CMU CL PowerPC Port Notes ------------------------- Here are some notes (from memory) that might help anyone who wants to work on reviving the LinuxPPC port. It's been more than 3 years since I worked on this & I'm sure that I'm forgetting some things. Anyone who winds up working on it is welcome to ask me technical questions, but they shouldn't be too surprized if I have no idea of what I was thinking about three years ago ... In no particular order -- *** addresses I don't know whether the area addresses defined in "ppc-validate.h" are still valid in more modern versions of LinuxPPC. It might be necessary to write a small program that tries to mmap() those areas and to redefine them if that program fails. *** lisp kernel & signal handling: In LinuxPPC, signal handlers receive a second argument of type 'struct sigcontext *'. Some early versions of MkLinux (a Mach-based port of Linux to the PPC) passed a 'struct pt_regs *' as the second argument. Some of the ppc-cmucl signal handling code may try to guess at runtime which type of structure a signal handler receives as its second arg; if that code still exists, it's unnecessary (and probably a little confusing.) In older versions of Linux (I guess that the distinction really involves older versions of GNU libc), signal handlers installed via 'signal()' were not disestablished when they were called. (I may be misremembering this: for whatever reason, signal handler installed via 'signal()' aren't able to reentrantly handle signals, and it's necessary to use 'sigaction()' with appropriate flags to install signal handlers that behave as expected.) I assume that other CMUCL Linux ports faced the same issue. The LinuxPPC (OS) kernel maps the hardware exceptions generated by conditional trap instructions (TW/TWI, and all of the simplified mnemonics derived from them) to the SIGTRAP signal. This is unfortunate, because GDB blindly assumes that all SIGTRAPs are related to debugging events, and it's therefore difficult to debug programs that use conditional traps. Conditional traps are a convenient and efficient means of checking for exceptional conditions; I didn't want to give up on using them because of PPC Linux misdesign, so I wound up patching the Linux kernel so that programs that used conditional traps could be debugged. This patch is to an old version of $(LINUX)/arch/ppc/kernel/traps.c; I'd guess that it'd still be pretty easy to apply to modern versions of the Linux kernel: ------ cut here ---- --- traps.c Thu Aug 13 23:08:55 1998 +++ traps.c~ Thu Feb 5 20:22:14 1998 @@ -95,24 +95,7 @@ if (xmon_bpt(regs)) return; #endif -#if 1 - /* This is a trap instruction. If it's a breakpoint - and the current process is traced, signal a SIGTRAP. - Otherwise, signal a SIGILL. - */ - if (current->flags & PF_PTRACED) { - long instr, *pc = (long *) (regs->nip); - __get_user(instr, pc); - - if (instr == 0x7d821008) { /* a breakpoint */ - _exception(SIGTRAP, regs); - return; - } - } - _exception(SIGILL, regs); -#else _exception(SIGTRAP, regs); -#endif } else { _exception(SIGILL, regs); } ------ cut here ---- (I should have reported this to the LinuxPPC kernel maintainers, of course. There might be better ways of fixing the problem.) With a patched Linux kernel in place, it's possible to debug CMUCL: conditional trap instructions (other than a breakpoint - which, as something like "twge r2,r2", is a lot less "condtional" than other conditional traps - will generate SIGILL and SIGTRAP will stay the debugger's business. In order to avoid requiring users to use a patched Linux kernel, the CMUCL kernel should handle both SIGILL and SIGTRAP. I don't remember, but it may be necessary to invent a command-line argument to suppress the handling of SIGTRAP when debugging. I hope that that all makes sense to whoever's reading it. *** Unix interface This was all written for a pre-glibc2 version of Linux. I assume that you'd need to modernize the OS-interface stuff quite a bit. I don't know how to do that other than by staring at .h files and trying to convince yourself that the lisp structure definitions match the C ones ... At one point in time, the PPC CMUCL kernel was statically linked and referenced every function in libc that it thought the Lisp might possibly be interested in. Building the kernel caused a map file to be produced (by running "nm"); lisp code used this map file to determine the addresses of foreign symbols. Looking up foreign symbols via dlopen()/dlsym() is certainly more flexible, but it may not be possible when cross-compiling. You might want to take a careful look at "nm"'s output, and may need to massage it some to get it into the format that the lisp code expects to see. *** ppc-backend issues When I defined the PPC instruction set, I gave branch instructions the :branch attribute. When I started to get things working, I discovered that the CMUCL instruction scheduler assumed that the :branch attribute implied that the architecture used delayed branches (ala the SPARC and MIPS) and started trying to fill their delay slots. I believe that I worked around this by disabling the instruction scheduler, which was obviously the wrong approach. It would undoubtedly make more sense to define the PPC instructions with a minimal set of attributes, get that working, then gradually add attributes that helped the instruction scheduler improve the code. That must have made too much sense ... There may have been other cases where I made changes to the architecture- neutral parts of the compiler in order to get something to work. In some cases, those changes may have been justified; in other cases, they probably weren't (and the real bug was in the PPC backend.) I don't remember all of the details, but it might be worth looking at any changes I made to the architecture-neutral parts of the compiler carefully (and skeptically.) I did this port on a PPC 601, which was a sort of hybrid between a PowerPC and the IBM Power architecture. The 601 had a Special Purpose Register (called the MQ register) that could be used in some Power instructions that implemented 64/32 division and multiplication; later versions of the PPC dropped the MQ register and the instructions that used it. At one point, I was using a Power instruction to implement a VOP in the CMUCL PPC backend. I'm sure that I changed this at some point, but I don't know for sure whether that change was contained in the archive at cons.org. Any references to the MQ register that remain in the PPC backend should be removed (if they haven't been already.) *** Random nonsense At the time I was working on this, CMUCL didn't have much support for stack-groups/lisp thread/lightweight processes; the code wasn't thread-safe, and I was a little leery of doing context switches in the middle of atomic operations that weren't marked as such ( halfway through the binding of a special variable, for instance.) I'd worked out a scheme that would allow the lisp to do this, but needed a dedicated register to implement that scheme efficiently. I was in the process of making some changes in register usage to support that scheme when I stopped working on the PPC port. In the archive I had, I believe that bin/lisp.old and lib/lisp.core.OLD were the lisp kernel and core image from before I made that change and bin/lisp and lib/lisp.core are from after. I don't remember whether or not I broke anything in the process (though it looks like I also did some work on this in June of 1998, which is about 6 months after the lisp.core file was generated. Hmm.) Moral: treat anything related to "polling", the r2 register, and threads with a great deal of skepticism. If any source files were modified after the end of 1997, it might be a good idea to see if there's an Emacs backup file ... Hope this all makes sense; if anyone has any technical questions, feel free to ask. Gary Byers gb@clozure.com