Mac OS 9 Lives
Mac OS 9 Discussion => Mac OS 9, Hacks & Upgrades => Topic started by: Protools5LEGuy on May 18, 2016, 11:00:06 AM
-
To be more on topic I split some things
http://macos9lives.com/smforum/index.php/topic,3195.0.html (http://macos9lives.com/smforum/index.php/topic,3195.0.html)
Let's keep "Anyone will to help create 9.2.3 for " for 9.2.3 developments
I beg you all to make a proper post on the trampoline as the Dream team post mentions because that was the only "relevant" info on that post.
Also, the new understandings on how you are disecting how OS9 boots deserve a own post.
Thanks for sharing all your valuable time with our community.
Perhaps I should start a new thread for all of our "theoretical" stuff?
Are you asking for an update post on where we are at and how we are doing this in which thread?
We were talking about the trampoline on "Anyone wanna help out 9.2.3?" And also on the "Dream Team" post. To focus our community to be on topic we thought it would be great to split some topics and merge all the post on unsupported machines with the same specs.
So, Elliot, Nanopico, iMic, Mac OS Plus, MacTron, cc333 and anyone willing, this is da place
-
Got it.
-
Here's what we know now (this may be across several other threads too, but here it is in one spot).
This should be pretty accurate based on documentation and experimentation, but this process may be modified as we find out more.
The order of a few items might be just slightly off, but overall it gives a good picture of the general order of things.
Outline of the boot process (this applies to new world machines. Old World are a bit different).
- Press The Power Button, Okay I think we all knew that part, but in case you didn't then now you know.
- The boot firmware embedded on the machine is executed first
- Boot firmware interrogates and probes all devices on the motherboard and attached to any external ports.
- While it finds hardware it builds the device tree. For each device it checks for firmware and properties. And adds this info to the device tree. This includes addresses of the device, interrupt data required to startup and configure the device and any fcode drivers for the device.
The device tree is just a data structure in memory that is used during boot by the OS. Manipulating the in memory version will only have effect until the machine is rebooted. (Thus the reason for the use of nvram scripts that have been used for things like changing cpu version numbers).
- The firmware then looks to the boot environment variable to find the device and file to load and execute.
- If you hold down the key combo for Open Firmware then rather than boot the firmware drops into the Client Interface program.
- In the case of Mac OS 9 the ROM file is a CHRP Script with a payload. Once this is loaded Open Firmware executes the script
- The script sets up memory to hold the trampoline code and the parcels package, and sets variables for Open Firmware to know where to copy the code to and where to start execution
- At the end of the CHRP Script is an instruction for Open Firmware to start executing
- Open Firmware loads the programs to the requested location and jumps to the start point to start executing. (Keep in mind that Open Firmware is still exists at this point)
- The first thing to run is the trampoline code. For the most part this is a dumb program (not that it isn't important, but more that it really doesn't know very little about what it's doing).
- The trampoline code starts up an Open Firmware connection through the Client Interface API's.
- The trampoline code asks Open Firmware for the device tree and iterates through it and copies all node, device and property info into a flat structure that OS 9 will be able to use.
- While the trampoline code is looping through the device tree it compares each nodes type, name property and compatibility property to the data in the parcels. If there is a match it look into the parcel for instruction on what to add to the device (properties, drivers, configuration instruction). This is where drivers that are required to be in place for early boot are loaded.
Some of the things loaded are actually the libraries and routines that are needed very early that are needed to be loaded before the nano kernel can load them as they are used very early on for setting up other things.
- The trampoline code turns off open firmware (thus the reason for copying the device tree)
- The trampoline code does some page setup of memory, moves some things around, setups up the Virtual Memory.
- The trampoline code then jumps to the nanokernel in the loaded toolbox. And it's job is done.
- And now we are to the nanokernel (the actual OS is now starting up.
- Happy Mac Icon displayed
- The nanokernel looks to the boot block of the start up device to find the location of the System folder, name of the first application to launch (The finder), and the name of the debugger if there is one.
- Font Manager and System Error Handler initialized.
- Set up Disk cache and CPU Specific software patches are executed.
- The 68k Emulator is started up. Not surprisingly a lot of the low level OS stuff runs off this.
- Some more required hardware is setup and initialized (remember the trampoline installed some drivers needing to be there for boot? That's because the OS doesn't yet have a way to load them)
- The resource manager is started up
- The Time Manager is started and initialized along with the NVRAMServices. This is required for drivers to be installed and hardware started up.
- Script systems are loaded and initialized and initialization resources are executed from the System File
- Data structures are setup for internal use
- The debugger if specified is loaded. so that early startup function can be debugged.This is loaded at the top of RAM usually. When the memory manager starts, if it finds there is a debugger it leave's it's memory alone and doesn't manage it so it runs completely outside of the control of the OS.
An interrupt and trap is set so that the debugger can be jumped too.
- The nanokernel starts loading system extensions (including control panels).
These load very early so that they can patch other parts of the system before they start up. - Some more managers are started (not really sure at this point exactly what goes on so from here to the process manager may be a bit off)
- Memory Manager Is loaded and started up.
This one really got me at first. I figured this would be started much earlier, but according to Apple documentation it does appear to start fairly late. If this is true then it will be easier to patch the system to get access to the full 2GB of ram installed on some machines.
- Additional services and managers are started
- The memory manager allocats the stack and heap for the process manager.
- The process manager starts. The process managers works pretty close with the memory manager at this point for loading programs allocating memory and executing programs
All programs actually run from with in the memory allocated by the memory manager to the process manager.
Programs are loaded at the top of available memory of the process manager. So programs load from top to bottom in memory.
- Depending on configuration certian parts of AppleTalk related to printing are loaded
- The Finder (Or what ever was specified in the boot block) is loaded and started and you are ready to use the machine
-
I have read almost every classic Mac OS startup sequence and they pale in comparison to yours !
Excellent breakdown, cleared up a few things I had in the totally wrong sequence, thanks so much :)
-
I have read almost every classic Mac OS startup sequence and they pale in comparison to yours !
Excellent breakdown, cleared up a few things I had in the totally wrong sequence, thanks so much :)
What were the things you thought happened in a different order?
Also some of the things may be a little out of sequence so I'm still looking to make this completely accurate.
The only thing I don't understand yet is
A). What order do all the managers actually start in, I know pretty good some groups of them but I need to figure out the exact order (not that it's super important, but my brain needs to know).
B). How it determines the order to load extensions and control panels.
A lot of the stuff I was reading only focused on a parts of it.
The details of the trampoline code is where most of the experimentation comes in.
The rest of it was learned from Inside Macintosh and Tech Notes from Apple.
Sadly it's not all in one place so it was a matter of taking notes as I read and then piecing it together as I went. Also having a very food understanding of general operating system design doesn't hurt.
-
The only thing I don't understand yet is
A). What order do all the managers actually start in, I know pretty good some groups of them but I need to figure out the exact order (not that it's super important, but my brain needs to know).
B). How it determines the order to load extensions and control panels.
From what I remember about extension loading sequence, first there is a preferential file type property that can be set to make an extension load ahead of the default file type, after which everything else loads in alphabetical order. Users would often insert a space at the front of an extension's filename in order to force it to the front of the alphabetical queue. I can't remember the alternate file type off the top of my head, but I have changed it on some of my extensions in the past when inserting a space in the filename wasn't sufficient to give it first priority (usually CPU upgrade extensions where the vendor hadn't changed it themselves already, and also Medianet). I'm fairly certain the control panels load after the extensions, again in alphabetical order.
-
The only thing I don't understand yet is
A). What order do all the managers actually start in, I know pretty good some groups of them but I need to figure out the exact order (not that it's super important, but my brain needs to know).
B). How it determines the order to load extensions and control panels.
From what I remember about extension loading sequence, first there is a preferential file type property that can be set to make an extension load ahead of the default file type, after which everything else loads in alphabetical order. Users would often insert a space at the front of an extension's filename in order to force it to the front of the alphabetical queue. I can't remember the alternate file type off the top of my head, but I have changed it on some of my extensions in the past when inserting a space in the filename wasn't sufficient to give it first priority (usually CPU upgrade extensions where the vendor hadn't changed it themselves already, and also Medianet). I'm fairly certain the control panels load after the extensions, again in alphabetical order.
Thank you. Greatly helpful. I do recall the documents on writing extensions differentiated between two type. I will no go an a treasure hunt for that info.
-
Users would often insert a space at the front of an extension's filename in order to force it to the front of the alphabetical queue. I can't remember the alternate file type off the top of my head
Yes, we would often prioritize when getting conflicts by loading extensions (with a space)... 1) CPU (if applicable), 2) SCSI Cards, 3) Network Cards, Video... then rest although I think the Video extensions were already "tagged" as priority... been 20 years since hunting down extensions manually so it's hard to remember... this was the Mac OS 8.1 days; OS 9.2 is very rarely plagued by such issues. Also, "Color" labeling the initial OS load set (As I mentioned in previous posts), helped track down new extensions that may be problematic.
-
I updated the order of things to what I have found. Still a work in progress so expect it to change more as I find more info.
-
For anyone interested in what the managers are that existing in the Macintosh OS here's a list. If you read all of Inside Macintosh you will be able to understand them all. You literally have to read all of Inside Macintosh to understand it since it's not all documented in one section.
Going through that you start to get an idea of the order that these are initialized and start to understand the boot process.
Typically a manager is a library of function and data structures. When a manager is loaded there is an initialization routine that runs to setup the structures. Any time one of it's functions are called it updates the structure accordingly. There are some exception where some of them respond to an interrupt or trap and then perform it's duties, but other than that, they just sit there doing nothing until an application calls a method. They are a lot like the background services that run in modern OS.
Listed in no particular order. I'm still trying to figure out the exact order these start in and what starts between them.
- Resource Manager
- Scrap Manager
- Help Manager
- List Manager
- Component Manager
- Translation Manager
- Desktop Manager
- Mixed Mode Manager
- Code Fragment Manager
- Exception Manager
- Device Manager
- Slot Manager
- SCSI Manager
- ADB Manager
- Power Manager
- Font Manager
- Script Manager
- Text Services Manager
- Dictionary Manager
- Sound Manager
- Sound Input Manager
- Speech Manager
- Image Compression Manager
- Process Manager
- Time Manager
- Verticle Retrace Manager
- Notification Manager
- Deferred Task Manager
- Segment Manager
- Shutdown Manager
- Gestalt Manager
- Trap Manager
- Start Manager
- Package Manager
- Memory Manager
- Virtual Memory Manager
- Event Manager/Toolbox Event Manager
- Menu Manager
- Window Manager
- Control Manager
- Dialog Manager
- Edition Manager
- Data Access Manager
- Printing Manager
- File Manager
- Alias Manager
- Disk Initialization Manager
- Digital Signature Manager
- Interprogram Messaging Manager
- Catalog Manager
- Authentication Manager
-
Thanks for this really great explanation. :)
-
I've found some more documentation that brings more detail to the boot process.
It looks like the memory manager and process manager start earlier than expected.
Either I interpreted earlier documentation wrong or I interpreted this new stuff wrong.
I will update the process once I figure out what is correct.
Oh the joy's of work in progress.
-
Steps 1 -7 outlined above are still accurate based on current knowledge. But the remainder I believe is different so here is the updated order of steps from 8 on.
This is kind of a high level view and may get more and more detailed as we learn more.
- And now we are to the nanokernel (the actual OS is now starting up.
- Happy Mac Icon displayed
- The interrupt system is initialized
- I/O Drivers initialized. This is not all devices just some required to boot. One of them being memory
- Memory Manager started up.
- The nanokernel looks to the boot block of the start up device to find the location of the System folder, name of the first application to launch (The finder), and the name of the debugger if there is one.
A copy of the boot block is stored as a resource in the System Folder. The resource type is boot and resource id 0 is the boot block.
When an OS 9 system folder is blessed that resource is copied to the boot block on disk.
Most of what follows is considered part of the start manager.
- System file is loaded.
- The data fork of the System file contains the next level of boot code. There is some relation between this and the resource id 1 of type boot in the system file
- The 68k Emulator is started up. Not surprisingly a lot of the low level OS stuff runs off this.
- The resource manager is started up
- Machine specific and CPU specific patches are loaded from resources in the system file.
This may be where the CPU version is checked to determine if the CPU is supported. It is the most logical spot for that code. - Set up Disk cache
- ROM patches are located from resources in the system file. The ROMversion is checked and patched based on it's version.
This is probably more relevant to old world ROM's as the boot process is different for them.
- ROM resource overrides are loaded. These are stored in the ROv# resources in the System file
- The Time Manager is started and initialized along with the NVRAMServices. This is required for drivers to be installed and hardware started up.
- Script systems are loaded and initialized and initialization resources are executed from the System File.
- Data structures are setup for internal use
- The debugger if specified is loaded. so that early startup function can be debugged.This is loaded at the top of RAM usually.
The debugger is loaded and the memory it is loaded to is setup by the memory manager but somehow hidden from the system.
An interrupt and trap is set so that the debugger can be jumped too.
The debugger is not controlled by the process manager so that it can interrupt anything.
The error handling in the kernel probably checks an entry in it's jump table to determine if it should drop into the debugger.
- The nanokernel starts loading system extensions (including control panels).
Extensions are loaded in order by the file name alphabetically.
Extensions can be in the root of the System Folder, or the Extensions folder. I believe it actually loads the ones in the root before the ones in the Extensions folder.
There are three types of resources loaded as extensions. Each extensions can reference further resources, allocate memory in the system stack and patch code.
- PACK - ROM extensions. These are different from system extensions are used to extend specific ROM code.
- INIT - Your normal system extensions and control panels.
- DRVR - these are for hardware devices. But they can also be virtual software drivers that appear to the system as hardware.
- Most other managers are loaded.
- Process manager is started. It is initialized and treated as standard application except that is loaded in a slightly different order due to it's relationship with the System heap.
- Memory manager loads code resources for the process manager
- The heap is loaded first and initialized. (Generally the stack is loaded and intialized first).
Part of the initialization is to grow the heap to the size referenced in a resource. This resource is either in a resource in the System file or embedded in one of the code segments in the code resources for the process manager.
This is the point where the 1.5 GB limit is enforced. At this point it may be that we find the resource for the process manager size and update it and we have all 2 GB of RAM. - The A5 world and stack pointer are loaded. The A5 world contains a bunch of global stuff that the OS uses and the application uses. See the Memory book of Inside Macintosh page 1-12 for a better explanation of A5
- The jump table is loaded. If your not familiar with this, it's the table of function definitions for the application. Since applications may not be loaded at the same location in memory, this table is used to map the function to it's actual memory address. Each application has it's own jump table.
- The stack is loaded and placed just below the A5 sections.
- The the process manager starts running.
- The process managers works pretty close with the memory manager and is almost a sub system of the memory manager
All programs actually run from with in the memory allocated by the memory manager to the process manager.
Programs are loaded at the top of available memory of the process manager. So programs load from top to bottom in memory.
- Depending on configuration certian parts of AppleTalk related to printing are loaded
- The Finder (Or what ever was specified in the boot block) is loaded and started and you are ready to use the machine
Additional digging is going to happen to get an even better picture.
-
Additional info on the boot process. Eln and I have been really ripping things apart. Here is some info for those that like to geek out on this stuff.
This is the boot process I'm 100% sure of.
1. Power on the machine and the built in firmware ROM starts up hardware as much as it needs to to build a device tree in open firmware (OF for now)
2. OF locates and loads the boot file from disk (The Mac OS ROM file).
3. On loading the image to RAM the boot script is executed to further setup the environment for the trampoline.
4. The script allocates memory for the trampoline, parcels and the info pages that the kernel will use.
5. The trampoline contains three segments. A code sgement, data segment and notes segment (which is pretty useless at the moment).
The code segment is loaded to physical/virtual address 0x200000 and the data segment at 0x100000
6. The trampoline starts executing at memory address 0x20F078
Now the exact order and detail is not 100% clear for the next parts.
7. Trampoline initiates a client interface to OF
8. Trampoline obtains handles to the do-translate, do-map, do-unmap, claim-mem, release-mem,claim-virt and release-virt methods of the mmu and mmc devices
It will use these methods to setup the memory mapping for the hardware in the device tree and to set it all up for the kernel.
9. Trampoline get's the address the parcels package is stored at
10. Memory will be claimed for a flattened directory tree structure (or whatever it is the kernel and os want's for hardware access)
11. The OF device tree will be crawled and compared to the parcels
12. Parcels that are to be added as nodes will be loaded into ram and mapped to the flattened structure
13. Parcels that add properties and code to existing nodes will get loaded into ram and mapped to the flattened structure
14. Some devices (primarly ATA controllers and intterupt controllers) have some info about them in the trampoline code and not in a parcel that details how to start them up. This will need to be updated for the ATA controller in the xserve and then a parcel with an OS 9 ndrv may need to be added to provide boot support from the internal ATA controller
15. The various info structures will be created and populated for the kernel. (config info, cpu info...)
16. (this step I know is 100% true) The trampoline disables open firmware
17. The nano kernel starts up and setups up more memory stuff and loads various pieces of code. It then updates the memory map to clober a bunch of the early boot stuff and relocate structures and code to the final address without having to actually move them around.
18. Then from their it's loading libraries and code fragments and the managers and such and then off to the finder and the users does stupid shit and watches porn or something.
So that's the low level boot process. A couple more interesting tidbits for those who care.
The chrp boot script does a bunch of memory setup and mapping for the info pages, trampoline and parcels.
These parts are allocated the following amounts of ram.
Trampoline 24 4k pages (98304 bytes)
Parcels 610 4K pages (2498560 bytes)
Info Pages 638 4k pages (2613248 bytes)
-
Here is a little bit more on the trampoline code.
In case anyone wants to know.
The trampoline consists of at least 4568 lines of assembly code. This is code that is verified as referenced and used.
There is another 11973 lines of code that I have not determined if is data or code.
At this time it appears that there are 118 methods in the code. This has not been verified yet. Some of these methods would be debugging methods.
Now it's time to analyze every line of code by hand.
-
From an initial glance, it looks like an awful lot of the Trampoline code is debugging logs and messages.
-
From an initial glance, it looks like an awful lot of the Trampoline code is debugging logs and messages.
You got it.
And a lot of loops
-
I'd like to offer a decompiled C source code of the OS9 trampoline I've made several years ago. I'm not sure which OS version it belongs to but we could figure it out.
It won't compile because several standard library functions this code depends on are missing. But it could be easily made compilable (we probably need to figure out how to compile PowerPC ELF binaries). The problem is that the original code bundles a custom lightweight version of the stdc library like bootX does. We need either to find a replacement for them or to write our own implementation or to find a way to avoid them.
Anyway, my code is heavily commented to help to understand what's going on. By reading this code, I was able to spot several bugs in the original code. 8)
I could upload the code either in a private repository of mine and gain you an access to it or directly to your Gitlab repository. Just tell me what you prefer.
-
Welcome and thanks! Now the Dream Team is complete!
-
Christmas in August, huh? Great job! How about you post an archive on this site, and we'll see what we can do about getting it to build. Once that's done, I would absolutely love to have it in the repo.
The build system (new as of December) is MPW-based. I have concocted a slightly dodgy set of PPCAsm files that produce the Trampoline as an ELF *within* an XCOFF container. That XCOFF then gets slurped up by one of my gigantic array of postlinking tools. MPW is almost as flexible as a full Unix environment, so we'll be able to figure something out.
Can't wait to have a read!
-
Probably a good time to offer a progress update. I've been pretty busy with my studies, but I've managed to get some things done in between.
I have neatened up my build stack quite a bit over the past couple of months. Pretty soon (say over the next month) I hope to have a few things to share with the community:
- Instructions for setting up a Netatalk 2.1 server on a Debian VM with a case insensitive FS (my MPW-compatible "MacSrc" server)
- A Python FUSE module allowing Git to work correctly with Mac-newline sources
- A fully annotated disassembly of all the low-level ROM-based Mac OS managers
- A reimplementation of the Apple build tool needed to postlink that disassembly (see patent US5546586 on "ROM vectorisation")
-
You are correct that a minimal stdclib would be required. For an early second stage boot loader like the trampoline, it would have no access to the any standard libraries unless they are directly built in.
Exciting stuff.
Just out of curiosity what did you use to decompile it to C?
-
Christmas in August, huh?
Why not? :P
How about you post an archive on this site, and we'll see what we can do about getting it to build.
I'd avoid posting RE'd or decompiled stuff closely matching copyrighted code in a public forum. Moreover, this way we had very limited possibilities for collaboration. I'd better set up a private repository and work from there.
I have concocted a slightly dodgy set of PPCAsm files that produce the Trampoline as an ELF *within* an XCOFF container.
IIRC, Apple's OpenFirmware implementation is capable of loading and executing XCOFF binaries directly. Does MPW compile to XCOFF?
-
Just out of curiosity what did you use to decompile it to C?
Well, I used the following toolchain: disassembler ==> custom Python decompilation script ==> manual postprocessing.
I worked at the function-level by converting the assembly into pseudo code. My Python script has been programmed to process function prologs/epilogs, some simple code idioms, conditional branches and simple expressions in a basic block. Anything beyond that need to be done manually.
I remember it was very tedious work (and a major hackage). I'd love to have a working decompiler for PowerPC but, unfortunately, I didn't see any...
-
Interesting approach! Mind putting your script on the repo so I can have a peek? My GitLab username is "elliotnunn".
For my NanoKernel disasm I wrote a Python disassembler based on Capstone. The NK actually doesn't use a call stack so there weren't many useful motifs to identify functions (and the NK uses the BL instruction "creatively", to boot). The last change I made to the script was to produce MPW-format binaries. Since then I have been tweaking the disasm by hand.
Here's the script:
https://github.com/elliotnunn/toolboxtoolbox (https://github.com/elliotnunn/toolboxtoolbox)
-
MPW does compile to XCOFF. The initial register values are the same for both ELF and XCOFF, so it doesn't really matter which one is used. ELF files are preferred by Open Firmware because apparently some special section can be used to specify configuration variables or something (which isn't that useful because we can do that from the forth boot script). I assume that we would prefer XCOFF if it can work.
-
IIRC, Apple's OpenFirmware implementation is capable of loading and executing XCOFF binaries directly. Does MPW compile to XCOFF?
Bootx is actually an xcoff. If you look at the code for bootx it has a small utility with it to convert from mach-o format to xcoff. The default output of their build is mach-o which open firmware doesn't like.
As far a stdclib you could lift the code from bootx easily.
The assembler in MPW by default outputs to xcoff and the linker is what converts it to PEF. Mac OS can actually load xcoff and PEF for user programs. xcoff is almost never used though as it is much slower to load and link. Of course there would be preferential treatment for their own format (PEF).
Just out of curiosity what did you use to decompile it to C?
Well, I used the following toolchain: disassembler ==> custom Python decompilation script ==> manual postprocessing.
I worked at the function-level by converting the assembly into pseudo code. My Python script has been programmed to process function prologs/epilogs, some simple code idioms, conditional branches and simple expressions in a basic block. Anything beyond that need to be done manually.
I remember it was very tedious work (and a major hackage). I'd love to have a working decompiler for PowerPC but, unfortunately, I didn't see any...
Sounds like the same thing I am doing, but most of the work after the disassembler is manual. I would say tedious is an understatement no mater which way you go. A boot loader like this is more difficult than other programs as there are no external libraries linked to help aid in identifying what is making external calls and there are no debug symbols. Oh god debug symbols would be the best thing in the world for this.
I'm starting to think it would be worth writing a decompiler.
-
Hey Nanopico! I just found a new trick! Type the following into your open firmware prompt:
dev /openprom/client-services
true to cidebug?
mac-boot
Make sure that you do this from telnet because you will end up with a bunch of lines that look like this
CIcall: 1198c8 finddevice deadbeef returned: deadbeef rets: ff83e940
My only complaint is that the system takes a really long time to boot.
-
Hey Nanopico! I just found a new trick! Type the following into your open firmware prompt:
dev /openprom/client-services
true to cidebug?
mac-boot
Make sure that you do this from telnet because you will end up with a bunch of lines that look like this
CIcall: 1198c8 finddevice deadbeef returned: deadbeef rets: ff83e940
My only complaint is that the system takes a really long time to boot.
Slow boot doesn't bother me. I'm kind of used to it now with some of the things I've ended up with lately.
I'll try this when I get back to doing this. A little slow lately.
Where did you find this or is it just in your head?
-
What on earth is "deadbeef"? ???
-
I was looking at /openprom/client-services to see if there was anything useful. I saw that there was a variable called 'cidebug?'. It was present on every New World Mac I had. I tried setting it to true, and here we are.
deadbeaf is a hexadecimal number that is often used as an indicator to programmers. In decimal it is 3735928495. All of the cidebug logs had the constant deadbeaf in them for some reason. That particular one had very little useful information, but some of the other ones have useful addresses in them.
CIcall: 1198c8 getprop deadbeef 100 106e58 1024ea returned: deadbeef rets: 31
CIcall: 1198c8 getprop deadbeef 8 116990 102512 returned: deadbeef rets: 4
CIcall: 1198c8 getprop deadbeef 8 116990 102519 returned: deadbeef rets: 4
CIcall: 1198c8 finddevice deadbeef returned: deadbeef rets: ff83c1c8
CIcall: 1198c8 getprop deadbeef 8 116990 102557 returned: deadbeef rets: ffffffff
This is only an excerpt. If you try this yourself you will get a very very long list of lines like these. I got around 4000 of them.
All the addressses beginning with 1 point somewhere inside the Trampoline code or data structures.
For the uninitiated, this is a debugging feature of open firmware that records useful data every time the Trampoline asks it to do something. I probably should have stuck this at the beginning of this post :)
-
Okay, I looked up what that was all about. I gather that the main point of "deadbeef" and other such things is that it makes for items that are easily caught by eye in a sea of hex code:
https://en.m.wikipedia.org/wiki/Hexspeak (https://en.m.wikipedia.org/wiki/Hexspeak)
It doesn't explain what the original inspiration for that phrase was, but at least I understand the concept. In a mildly ironic twist relevant to our forum, it's also the name of a music player app:
http://deadbeef.sourceforge.net/ (http://deadbeef.sourceforge.net/)
Computer programmers are curious creatures! ;)
-
It (as a lot of others) is funny. If you dig around a lot you will find these things go way back as jokes.
But deadbeef is common and if you think about it. You are trying access/use a dead piece of something. add beef to be funny and there you go.
-
I was looking at /openprom/client-services to see if there was anything useful. I saw that there was a variable called 'cidebug?'. It was present on every New World Mac I had. I tried setting it to true, and here we are.
deadbeaf is a hexadecimal number that is often used as an indicator to programmers. In decimal it is 3735928495. All of the cidebug logs had the constant deadbeaf in them for some reason. That particular one had very little useful information, but some of the other ones have useful addresses in them.
CIcall: 1198c8 getprop deadbeef 100 106e58 1024ea returned: deadbeef rets: 31
CIcall: 1198c8 getprop deadbeef 8 116990 102512 returned: deadbeef rets: 4
CIcall: 1198c8 getprop deadbeef 8 116990 102519 returned: deadbeef rets: 4
CIcall: 1198c8 finddevice deadbeef returned: deadbeef rets: ff83c1c8
CIcall: 1198c8 getprop deadbeef 8 116990 102557 returned: deadbeef rets: ffffffff
This is only an excerpt. If you try this yourself you will get a very very long list of lines like these. I got around 4000 of them.
All the addressses beginning with 1 point somewhere inside the Trampoline code or data structures.
For the uninitiated, this is a debugging feature of open firmware that records useful data every time the Trampoline asks it to do something. I probably should have stuck this at the beginning of this post :)
Are you seeing lines that don't return deadbeef as well?
This will definitely help with working out how the trampoline is loading parcels and how it determines what ones to load.
-
Either all the lines contain deadbeef or I haven't looked closely enough at ~4100 boring lines that all contain roughly the same thing :)
That 1198c8 is almost certainly the address that is returned to after the client interface call is complete. It is probably near the end of the Trampoline function that actually makes the client interface calls. That would be an interesting place to look.
-
Either all the lines contain deadbeef or I haven't looked closely enough at ~4100 boring lines that all contain roughly the same thing :)
That 1198c8 is almost certainly the address that is returned to after the client interface call is complete. It is probably near the end of the Trampoline function that actually makes the client interface calls. That would be an interesting place to look.
That is interesting. Most of all of the trampoline code starts at 0x00200000 and goes up to roughly 0x00210260.
Though who knows how it rearranges it's self.
-
Only one way to know for sure.
0 > 1198b0 30 dump
001198b0:
DEFAULT CATCH!, code=300 at %SRR0: ff80b1c0 %SRR1: 0000b030
Nothing is there before the Trampoline is run. Now to check inside a client interface call...
dev /openprom/client-services
true value cifirst?
: finddevice cifirst? if false to cifirst? 1198b0 30 dump then finddevice ;
mac-boot
CIcall: 1198c8 finddevice deadbeef
001198b0: 00 00 00 00 00 00 00 00 ff 80 a2 90 de ad be ef |................|
001198c0: 00 00 00 00 00 11 98 b8 00 10 07 21 00 00 00 01 |...........!....|
001198d0: 00 00 00 01 00 10 24 e2 00 00 00 00 00 00 00 00 |......$.........|returned: deadbeef rets: ff83e940
So the Trampoline must be inserting something there. Presumably those are valid powerpc instructions, but I have no idea.
-
Here is that location after the Trampoline is loaded, but before it is run.
: go ;
mac-boot
001198b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
001198c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
001198d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
So that location is allocated when the Trampoline is loaded but is initialized by the Trampoline itself. Maybe it is in the .bss segment?
-
It might actually be parcel code that is getting loaded. Further investigation required I guess.
-
It could be. Hard to say.
-
What on earth is "deadbeef"? ???
0xDEADBEEF is often chosen as bogus value for unused variables or structure members. It hexspeaks for yourself - looking at it you know that's bogus. Plus, an access to this address will cause an exception.
-
CIcall: 1198c8 finddevice deadbeef
001198b0: 00 00 00 00 00 00 00 00 ff 80 a2 90 de ad be ef |................|
Two values shown in your snippet builds the content of the OpenFirmware TVector. This internal MacOS structure looks like that:
typedef struct TVector {
ProcPtr fProcPtr;
void *fTOC;
};
0xff80a290 is therefore the address of the client interface procedure inside OpenFirmware and 0xdeadbeef is the TOC pointer. The latter contains a bogus value because TOC isn't used in OpenFirmware.
It raises the question why does Trampoline use TVector - the mandatory structure to make inter-procedural calls in the classic Mac OS - at all? BootX doesn't do that. I assume Apple simple used a standard Mac OS compiler (MPW oder Metrowerks CodeWarrior) to produce Trampolin's binary. Calling any function via pointer will cause these compiler to generate TVecs + ptr_glue code.
-
What on earth is "deadbeef"? ???
0xDEADBEEF is often chosen as bogus value for unused variables or structure members. It hexspeaks for yourself - looking at it you know that's bogus. Plus, an access to this address will cause an exception.
Thanks, that context explains it's usage here quite well.
-
CIcall: 1198c8 finddevice deadbeef
001198b0: 00 00 00 00 00 00 00 00 ff 80 a2 90 de ad be ef |................|
Two values shown in your snippet builds the content of the OpenFirmware TVector. This internal MacOS structure looks like that:
typedef struct TVector {
ProcPtr fProcPtr;
void *fTOC;
};
0xff80a290 is therefore the address of the client interface procedure inside OpenFirmware and 0xdeadbeef is the TOC pointer. The latter contains a bogus value because TOC isn't used in OpenFirmware.
It raises the question why does Trampoline use TVector - the mandatory structure to make inter-procedural calls in the classic Mac OS - at all? BootX doesn't do that. I assume Apple simple used a standard Mac OS compiler (MPW oder Metrowerks CodeWarrior) to produce Trampolin's binary. Calling any function via pointer will cause these compiler to generate TVecs + ptr_glue code.
Ok. This means that some code in the Trampoline (probably written in assembly) makes a TVector out of the client interface address. Then it can be called by normal c code. That explains it.
-
I figured out what the 1198c8 is. It is the argument array that is passed to the client interface in r3. The Trampoline appears to always use the same location for the argument array. This lets us do some pretty neat stuff.
dev /openprom/client-services
: read-cstring 0 begin 2dup + c@ 0= if true else 1+ false then until ;
: finddevice ." finding " 1198d4 @ read-cstring type ." . It's phandle is " finddevice 1198d8 @ 8 u.r cr ;
: open ." opening " 1198d4 @ read-cstring type ." . It's ihandle is " open 1198d8 @ 8 u.r cr ;
: close ." closing " 1198d4 @ 8 u.r cr close ;
mac-boot
finding /chosen . It's phandle is 00000000
finding / . It's phandle is 00102519
finding /options . It's phandle is 00102557
finding /pci@f2000000/mac-io@17/ata-4@1f000/disk . It's phandle is 00106f58
finding /rtas . It's phandle is 001025d9
finding /chosen . It's phandle is 00180000
finding /cpus/@0 . It's phandle is 000000c0
finding /cpus/@0/l2-cache . It's phandle is 0010183c
finding /cpus/@0/l2-cache/l2-cache . It's phandle is 001016d8
finding /aliases . It's phandle is ffffffff
opening /pseudo-hid/keyboard . It's ihandle is 00100740
finding / . It's phandle is 00000000
finding /rom/macos . It's phandle is 00100f88
opening /nvram@fff04000 . It's ihandle is 00116960
opening /nvram@fff04000 . It's ihandle is 00116998
finding /aliases . It's phandle is 000031e9
opening /pci@f0000000/ATY,RageM3pParent@10/ATY,RageM3pB:0 . It's ihandle is 0010ff34
finding /aliases . It's phandle is 000002c4
finding /pci@f0000000/ATY,RageM3pParent@10/ATY,RageM3pA . It's phandle is 001058cc
opening /pci@f2000000/mac-io@17/via-pmu@16000/power-mgt . It's ihandle is 001166f0
This technique can be extended to any client interface service. I am pretty sure I can also make it drop into the open firmware prompt when certain conditions are met. So we can breakpoint the Trampoline at any client interface call, provided we know what values will be in the argument array beforehand.
-
I figured out what the 1198c8 is. It is the argument array that is passed to the client interface in r3. The Trampoline appears to always use the same location for the argument array. This lets us do some pretty neat stuff.
dev /openprom/client-services
: read-cstring 0 begin 2dup + c@ 0= if true else 1+ false then until ;
: finddevice ." finding " 1198d4 @ read-cstring type ." . It's phandle is " finddevice 1198d8 @ 8 u.r cr ;
: open ." opening " 1198d4 @ read-cstring type ." . It's ihandle is " open 1198d8 @ 8 u.r cr ;
: close ." closing " 1198d4 @ 8 u.r cr close ;
mac-boot
finding /chosen . It's phandle is 00000000
finding / . It's phandle is 00102519
finding /options . It's phandle is 00102557
finding /pci@f2000000/mac-io@17/ata-4@1f000/disk . It's phandle is 00106f58
finding /rtas . It's phandle is 001025d9
finding /chosen . It's phandle is 00180000
finding /cpus/@0 . It's phandle is 000000c0
finding /cpus/@0/l2-cache . It's phandle is 0010183c
finding /cpus/@0/l2-cache/l2-cache . It's phandle is 001016d8
finding /aliases . It's phandle is ffffffff
opening /pseudo-hid/keyboard . It's ihandle is 00100740
finding / . It's phandle is 00000000
finding /rom/macos . It's phandle is 00100f88
opening /nvram@fff04000 . It's ihandle is 00116960
opening /nvram@fff04000 . It's ihandle is 00116998
finding /aliases . It's phandle is 000031e9
opening /pci@f0000000/ATY,RageM3pParent@10/ATY,RageM3pB:0 . It's ihandle is 0010ff34
finding /aliases . It's phandle is 000002c4
finding /pci@f0000000/ATY,RageM3pParent@10/ATY,RageM3pA . It's phandle is 001058cc
opening /pci@f2000000/mac-io@17/via-pmu@16000/power-mgt . It's ihandle is 001166f0
This technique can be extended to any client interface service. I am pretty sure I can also make it drop into the open firmware prompt when certain conditions are met. So we can breakpoint the Trampoline at any client interface call, provided we know what values will be in the argument array beforehand.
I have seen 1198c8 in the trampoline sort of often for the parts I've gotten through. (not very much yet)
-
I figured out what the 1198c8 is. It is the argument array that is passed to the client interface in r3. The Trampoline appears to always use the same location for the argument array. This lets us do some pretty neat stuff.
dev /openprom/client-services
: read-cstring 0 begin 2dup + c@ 0= if true else 1+ false then until ;
: finddevice ." finding " 1198d4 @ read-cstring type ." . It's phandle is " finddevice 1198d8 @ 8 u.r cr ;
: open ." opening " 1198d4 @ read-cstring type ." . It's ihandle is " open 1198d8 @ 8 u.r cr ;
: close ." closing " 1198d4 @ 8 u.r cr close ;
mac-boot
finding /chosen . It's phandle is 00000000
finding / . It's phandle is 00102519
finding /options . It's phandle is 00102557
finding /pci@f2000000/mac-io@17/ata-4@1f000/disk . It's phandle is 00106f58
finding /rtas . It's phandle is 001025d9
finding /chosen . It's phandle is 00180000
finding /cpus/@0 . It's phandle is 000000c0
finding /cpus/@0/l2-cache . It's phandle is 0010183c
finding /cpus/@0/l2-cache/l2-cache . It's phandle is 001016d8
finding /aliases . It's phandle is ffffffff
opening /pseudo-hid/keyboard . It's ihandle is 00100740
finding / . It's phandle is 00000000
finding /rom/macos . It's phandle is 00100f88
opening /nvram@fff04000 . It's ihandle is 00116960
opening /nvram@fff04000 . It's ihandle is 00116998
finding /aliases . It's phandle is 000031e9
opening /pci@f0000000/ATY,RageM3pParent@10/ATY,RageM3pB:0 . It's ihandle is 0010ff34
finding /aliases . It's phandle is 000002c4
finding /pci@f0000000/ATY,RageM3pParent@10/ATY,RageM3pA . It's phandle is 001058cc
opening /pci@f2000000/mac-io@17/via-pmu@16000/power-mgt . It's ihandle is 001166f0
This technique can be extended to any client interface service. I am pretty sure I can also make it drop into the open firmware prompt when certain conditions are met. So we can breakpoint the Trampoline at any client interface call, provided we know what values will be in the argument array beforehand.
I have seen 1198c8 in the trampoline sort of often for the parts I've gotten through. (not very much yet)
It is safe to say that any reference to 1198c8 through 1198f4 or so has something to do with the client interface. These values will either be all over the place or will be in functions that are called from very many places. I am not sure which method is used in the Trampoline.
-
There is space near there too that is commonly used for other stack items.
Now that I think of it and if I am remembering right (sorry at work don't have notes or anything here).
That parameter region is the first item setup. Or the second maybe. But extremely early on.
-
Sounds like the same thing I am doing, but most of the work after the disassembler is manual. I would say tedious is an understatement no mater which way you go. A boot loader like this is more difficult than other programs as there are no external libraries linked to help aid in identifying what is making external calls and there are no debug symbols.
Yes and no. That boot loader is actually much easier to analyze than any other program because
- it's pretty small comparing to full-fledged applications
- it's written in C - no classes, no virtual function calls, no callback hell
- low-level assembly is tiny compared to said NK
- there is no floating-point arithmetic inside, no other fancy stuff like hand crafted Altivec asm
Oh god debug symbols would be the best thing in the world for this.
Yeah, we got the booxtX code to compare with and I'm currently preparing a list of functions, their prototypes and descriptions for you to grab.
-
I will not say much as I do not want to "taint" this amazing thread; I just wanted to say that you guys are truly the "Dream Team" and our heroes; I read this one almost everyday and when there are no new responses, I usually re-read it from the top, just to get the old brain flowing again. I have not coded assembler or C or Pascal in over 25 years, but the excitement of tracing out tight, well written code and finding a better way to "skin a cat" without introducing some bugs has always appealed to me.
You guys are great, keep up the good work, feels like the progress is accelerating on all fronts. I doubt that anyone, even at Apple, could imagine that their secret box of treasures would be exposed to light all these years later !
-
Sounds like the same thing I am doing, but most of the work after the disassembler is manual. I would say tedious is an understatement no mater which way you go. A boot loader like this is more difficult than other programs as there are no external libraries linked to help aid in identifying what is making external calls and there are no debug symbols.
Yes and no. That boot loader is actually much easier to analyze than any other program because
Probably doesn't help that I am still not completely versed in ppc asm and I have this sadistic obsession with going through the code just to get a better grasp at ASM. I figured out early on it is all written in C, but again I'm just a bit sadistic in this regard.
- it's pretty small comparing to full-fledged applications
- it's written in C - no classes, to virtual function calls, no callback hell
- low-level assembly is tiny compared to said NK
- there is no floating-point arithmetic inside, no other fancy stuff like hand crafted Altivec asm
Oh god debug symbols would be the best thing in the world for this.
Yeah, we got the booxtX code to compare with and I'm currently preparing a list of functions, their prototypes and descriptions for you to grab.
Agreed on all yes. I guess my point of more difficult is it's interaction with the parcels. Probably is more effort to me as I have very little time to go through it right now. Everything seems difficult at this point right now. A little overloaded at work make me kind of not want to touch any code at the moment at home.
I will not say much as I do not want to "taint" this amazing thread; I just wanted to say that you guys are truly the "Dream Team" and our heroes; I read this one almost everyday and when there are no new responses, I usually re-read it from the top, just to get the old brain flowing again. I have not coded assembler or C or Pascal in over 25 years, but the excitement of tracing out tight, well written code and finding a better way to "skin a cat" without introducing some bugs has always appealed to me.
You guys are great, keep up the good work, feels like the progress is accelerating on all fronts. I doubt that anyone, even at Apple, could imagine that their secret box of treasures would be exposed to light all these years later !
I'm sure all of use appreciate the sentiment.