Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

DearthnVader

Suspended
Original poster
Dec 17, 2015
2,207
6,399
Red Springs, NC
As much as I love kicking around with this old hardware, we really need new Iron to run our favorite PowerPC OS's.

Rapture computing systems is shipping the Blackbird bundles with Power9.


Really it should not be that hard to get OS X to run on one of these things if we can port Openbios or SLOF to run as the systems firmware. We have the source code to OpenBMC and we are free to reverse engineer it and maybe Rapture would even release any hardware documentation we may need to get a basic level of Open Firmware running.

That would be stage 1.

Stage 2 would be porting the needed code to load BootX


Stage 3 would be patching the Kernel to accept the Power9.

Stage 4 would be writing the Platform drivers needed for Tiger and Leopard to get the Kernel to not panic after it is loaded.

Stage 5-x would be getting everything else up and running.



I have a basic level of understanding of Open Firmware, Openbios, and SLOF, but nowhere near the level of understanding it would take to move this project forward in any meaningful way. We all know who is the resident expert in Open Firmware around here, it's just does he want to take on stage 1 of this project.

I can likely foot the entire cost of the 8 Core Power9 bundle, but it would be a stretch, if we can get a well known and trustworthy member to start a gofundme or whatever contribution system is necessary to purchase the hardware and have it shipped to whoever maybe able and willing to take on Stage 1, it would not be a stretch for me to put up 1/3rd and a good QuickSilver Case with a LaserHive ATX conversion kit.


So is anyone interested in making even small donations or just donating their time and expertise to taking on any stage of this project?
 
So who knows JTAG?

does raptor computing backbird mainboard have a JTAG


Yes, the Raptor Computing Blackbird mainboard does have a JTAG (Joint Test Action Group) interface. The JTAG interface is commonly used for debugging, testing, and programming hardware at a low level. For systems like the Blackbird, which is based on the OpenPOWER architecture, JTAG can be an essential tool for developers and engineers working on firmware development, hardware validation, and debugging.

JTAG on the Blackbird Mainboard​

  1. Purpose of JTAG:
    • Debugging: JTAG allows developers to directly interface with the CPU and other components for low-level debugging.
    • Programming: It can be used to program firmware directly onto the hardware.
    • Testing: JTAG is used for boundary-scan testing to verify the integrity of the hardware interconnections.
  2. Accessing JTAG:
    • The JTAG interface on the Blackbird mainboard typically consists of a set of pins or a dedicated header. The exact location and pinout can be found in the Blackbird mainboard documentation or user manual.
  3. Tools and Software:
    • To use the JTAG interface, you'll need a compatible JTAG adapter and software tools. Popular JTAG adapters include those from manufacturers like Segger (J-Link) or Xilinx. Software tools might include OpenOCD (Open On-Chip Debugger) for interfacing with the JTAG hardware.
  4. Use Cases:
    • Firmware Development: Developers working on coreboot, OpenBMC, or other firmware components can use JTAG for in-system debugging.
    • Hardware Debugging: Engineers can use JTAG to diagnose and resolve hardware issues.
    • System Bring-up: When bringing up new hardware or developing new features, JTAG provides a direct interface for testing and validation.

Example of Using JTAG with Blackbird​

  1. Connect JTAG Adapter:
    • Connect the JTAG adapter to the JTAG header on the Blackbird mainboard.
  2. Configure Software:
    • Set up the software tools (e.g., OpenOCD) to recognize the JTAG adapter and configure it for the specific hardware.
  3. Debugging and Programming:
    • Use the software tools to perform debugging sessions, step through code, set breakpoints, and program firmware.

Summary​

The JTAG interface on the Raptor Computing Blackbird mainboard is a valuable resource for low-level hardware and firmware development. It enables direct interaction with the system's hardware, facilitating debugging, testing, and programming tasks. The availability of JTAG on the Blackbird mainboard aligns with the open and developer-friendly philosophy of Raptor Computing systems, making it a powerful tool for developers working on OpenPOWER systems.
The Sager J-Link has host support for about every popular operating system including the macOS and AppleSoC.


Is the J-Link compatible with the blackbird mainboard JTAG interface?


Yes, the J-Link debug probe from Segger is compatible with the JTAG interface on the Raptor Computing Blackbird mainboard. The J-Link is a widely used JTAG/SWD debug probe that supports a variety of processors and architectures, including those used in the OpenPOWER systems like the Blackbird.

Using J-Link with the Blackbird Mainboard​

Here are the general steps to use the J-Link with the Blackbird mainboard:
  1. Connect the J-Link to the JTAG Header:
    • Locate the JTAG header on the Blackbird mainboard. The pinout and location can be found in the Blackbird documentation.
    • Use the appropriate JTAG cable to connect the J-Link to the JTAG header on the mainboard.
  2. Install J-Link Software:
    • Download and install the J-Link software and drivers from the Segger website. This includes the J-Link Software and Documentation Pack, which provides the necessary tools for interfacing with the J-Link.
  3. Configure the J-Link:
    • Configure the J-Link software to recognize the target device. You may need to specify the correct device and interface settings for the POWER9 processor used in the Blackbird mainboard.
  4. Using J-Link with Debugging Tools:
    • Use compatible debugging tools such as OpenOCD (Open On-Chip Debugger), GDB (GNU Debugger), or the Segger J-Link GDB Server to interface with the J-Link and perform debugging tasks.
    • For example, you can use OpenOCD with a configuration file tailored for the Blackbird mainboard and J-Link.

Example Configuration for OpenOCD​

Here is an example of an OpenOCD configuration for using J-Link with a POWER9 processor:
cfg
Copy code
# J-Link adapter configuration
interface jlink
jlink_device <target_device>
transport select jtag

# JTAG scan chain configuration
set CHIPNAME <chip_name>
jtag newtap $CHIPNAME cpu -irlen 10 -expected-id <idcode>

# Target configuration
target create $CHIPNAME.cpu <arch> -chain-position $CHIPNAME.cpu
Replace <target_device>, <chip_name>, and <idcode> with the appropriate values for the POWER9 processor and the specific configuration of your Blackbird mainboard.

Benefits of Using J-Link​

  • High Speed: J-Link offers high-speed communication with the target device, which is beneficial for debugging and programming tasks.
  • Wide Compatibility: J-Link supports a wide range of processors and architectures, making it a versatile tool.
  • Extensive Tool Support: J-Link is compatible with various debugging tools and IDEs, providing flexibility in your development environment.

Summary​

The J-Link debug probe is compatible with the JTAG interface on the Raptor Computing Blackbird mainboard. By connecting the J-Link to the mainboard and configuring the appropriate software tools, developers can leverage the powerful debugging and programming capabilities of the J-Link to work on OpenPOWER systems like the Blackbird.
 
We may not have to get all the way down to the JtAG level, Petitboot is included in the OpenPOWER firmware on the Blackbird mainboard.

We should be able to compile SLOF to our liking as an ELF format payload and just load it from disk with Petitboot.
 
So we should be able to compile a SLOF .elf to our liking( strip it down as much as we can just to build a basic IO system that will provide us with the console ).

The use the J-Link JTAG to debug that after it gets loaded by Petitboot.

I think this would be hardware safe, as OpenPower is really bringing up the IC's and all the motherboard stuff like the New World ROM 1 MB BootROM does on PPC Mac's, then we are just jumping to Open Firmware to start building out our device-tree.

The JTAG would just allow us to debug our ELF as we bring up and Open Firmware interface.

can I use the j-link JTAG to debug SLOF after I load it with Petitboot


Yes, you can use the J-Link JTAG debugger to debug SLOF (Slimline Open Firmware) after loading it with Petitboot on a system like the Raptor Computing Blackbird. Here’s how you can approach debugging SLOF using J-Link after it has been loaded:

Steps to Debug SLOF with J-Link JTAG​

  1. Load SLOF with Petitboot:
    • Follow the steps outlined earlier to configure Petitboot to load SLOF as a payload. Ensure SLOF is compiled into an ELF format and accessible to Petitboot from a local disk or network location.
  2. Connect J-Link to Blackbird Mainboard:
    • Connect your J-Link JTAG debugger to the JTAG header on the Raptor Computing Blackbird mainboard. Ensure the connection is secure and correctly aligned with the pinout.
  3. Setup J-Link Software:
    • Install the J-Link software and drivers on your development machine. Ensure the software is compatible with your operating system and supports the PowerPC architecture used in the Blackbird mainboard.
  4. Start J-Link GDB Server:
    • Launch the J-Link GDB Server, which acts as a bridge between your development machine running GDB (GNU Debugger) and the J-Link hardware connected to the target (Blackbird mainboard).
    • bash
      Copy code
      JLinkGDBServer -if JTAG -device <device_name> -speed <speed>
    • Replace <device_name> with the appropriate device name for the PowerPC architecture used in your Blackbird mainboard (e.g., PPC970MP) and <speed> with the desired JTAG clock speed.
  5. Connect GDB to J-Link GDB Server:
    • In a separate terminal or GDB session, connect GDB to the J-Link GDB Server running on your development machine. This allows you to interactively debug SLOF running on the Blackbird.
    • bash
      Copy code
      powerpc-linux-gnu-gdb slof.elf
    • Replace powerpc-linux-gnu-gdb with the appropriate GDB executable for PowerPC architecture, and slof.elf with the path to your compiled SLOF ELF file.
  6. Debug SLOF with GDB:
    • Use GDB commands to set breakpoints, inspect memory, step through code, and analyze the execution flow of SLOF on the Blackbird mainboard.
    • gdb
      Copy code
      target remote localhost:2331 # Connect to J-Link GDB Server
      load # Load symbols and executable into GDB
      break <function_name> # Set breakpoints as needed
      continue # Resume execution
  7. Monitor Debug Output:
    • Monitor the GDB console for debug output, messages, and breakpoints hit as SLOF executes on the Blackbird mainboard.

Notes​

  • Ensure the J-Link hardware and software versions are compatible with the PowerPC architecture and your specific debugging requirements.
  • Utilize GDB commands and features effectively to troubleshoot issues, analyze code flow, and validate functionality within SLOF.
  • Refer to the documentation provided with J-Link and SLOF for additional configuration options, troubleshooting tips, and advanced debugging techniques.
By following these steps, you can effectively use the J-Link JTAG debugger to debug SLOF after loading it with Petitboot on your Raptor Computing Blackbird mainboard, enhancing your ability to develop and debug firmware on PowerPC-based systems.
 
You might hit up Cameron Kaiser (creator of TenFourFox).




 
Interesting idea. I'll keep tabs on this thread to see if any progress comes of it.

Unfortunately, I won't be able to contribute much-- modern POWER architecture is so much more expensive than x86-64 contemporaries of similar performance. I've been keeping an eye for a long time, but even the costs of decom POWER7 and even POWER6 systems are asinine.

It's no wonder that still the best way to get into POWER architecture is to just buy an old Mac.
 
Stage 4 would be writing the Platform drivers needed for Tiger and Leopard to get the Kernel to not panic after it is loaded.

on this front one place to potentially look to is the Mac On linux project since back when I messed with that, almost 10 years ago now(!)


one very curious thing I noticed about MoL was that it did not actually emulate any one mac platform, but was its own special hypervisor that at boot time injected its own Platform Expert driver/kext, which I thought was very interesting! and I am wondering if it might just give us clues how to write a platform driver for MacOS X in general (I am surprised no ones picked up on that, if nothing else to make a fully VirtIO PowerPC compatible MacOS X virtual machine or something along those lines)
 
Last edited:
on this front one place to potentially look to is the Mac On linux project since back when I messed with that, almost 10 years ago now(!)


one very curious thing I noticed about MoL was that it did not actually emulate any one mac platform, but was its own special hypervisor that at boot time injected its own Platform Expert driver/kext, which I thought was very interesting! and I am wondering if it might just give us clues how to write a platform driver for MacOS X in general (I am surprised no ones picked up on that, if nothing else to make a fully VirtIO PowerPC compatible MacOS X virtual machine or something along those lines)
I would definitely be looking at that code for the Platform Expert to get OX X up on the Blackbird.

I used MOL all the time on my PM8600 as I ran YellowDog for over a year as my main OS before Jaguar made OS X a truly production ready OS.
 
Does anyone know if BootX contains a file system driver for HFS?
BootX does HFS and HFS+. Basically, it just needs enough code to read directory lists and files.
XPostFacto/BootX/bootx.tproj/fs.subproj/hfs.c
BootX also does TFTP (network), UFS, and Ext2FS.
 
BootX does HFS and HFS+. Basically, it just needs enough code to read directory lists and files.
XPostFacto/BootX/bootx.tproj/fs.subproj/hfs.c
BootX also does TFTP (network), UFS, and Ext2FS.
Thanks Joe, I think I loaded BootX from the EFI partition of a GUID disk on one of the 2005 Mac's that supports GUID. If I am remembering correct it happily booted the first HFS+ partition it found.

Tho I'm sure I could just point it there, I think if the HFS+ partition on the same GUID disk is the first one it finds, it will just boot that, assuming it finds the mach_kernel there.

In the scope of what I an hopping to do here that should make things a little easier. As SLOF already supports GUID disks and has a FAT file systems /package.

So we kind of chain load OpenPOWER>SLOF.elf>BootX.

This is where I'm stuck and need some help and guidance, BootX is an XCOFF executable correct?

SLOF lacks an XCOFF-LOADER /package.

So I'm going to need to patch SLOF to include an xcoff-loader, correct?
 
Oops, spawned way too many Power9's:)

Code:
Ready!
0 > include evaluator.fs   ok
0 > dev / ls 
7e643530 :  /
7e643b40 :  |-- ibm,persistent-memory
7e643da0 :  |-- chosen
7e6441b0 :  |-- rtas
7e6454d8 :  |-- event-sources
7e645690 :  |   |-- hot-plug-events
7e6457e8 :  |   +-- epow-events
7e645988 :  |-- cpus
7e6460c0 :  |   |-- PowerPC,POWER9@0
7e646ad8 :  |   |-- PowerPC,POWER9@1
7e6474f0 :  |   |-- PowerPC,POWER9@2
7e647f08 :  |   |-- PowerPC,POWER9@3
7e648920 :  |   |-- PowerPC,POWER9@4
7e649338 :  |   |-- PowerPC,POWER9@5
7e649d50 :  |   |-- PowerPC,POWER9@6
7e64a768 :  |   |-- PowerPC,POWER9@7
7e64b180 :  |   |-- PowerPC,POWER9@8
7e64bb98 :  |   |-- PowerPC,POWER9@9
7e64c5b0 :  |   |-- PowerPC,POWER9@a
7e64cfc8 :  |   |-- PowerPC,POWER9@b
7e64d9e0 :  |   |-- PowerPC,POWER9@c
7e64e3f8 :  |   |-- PowerPC,POWER9@d
7e64ee10 :  |   |-- PowerPC,POWER9@e
7e64f828 :  |   |-- PowerPC,POWER9@f
7e650240 :  |   |-- PowerPC,POWER9@10
7e650c58 :  |   |-- PowerPC,POWER9@11
7e651670 :  |   |-- PowerPC,POWER9@12
7e652088 :  |   |-- PowerPC,POWER9@13
7e652aa0 :  |   |-- PowerPC,POWER9@14
7e6534b8 :  |   |-- PowerPC,POWER9@15
7e653ed0 :  |   |-- PowerPC,POWER9@16
7e6548e8 :  |   |-- PowerPC,POWER9@17
7e655300 :  |   |-- PowerPC,POWER9@18
7e655d18 :  |   |-- PowerPC,POWER9@19
7e656730 :  |   |-- PowerPC,POWER9@1a
7e657148 :  |   |-- PowerPC,POWER9@1b
7e657b60 :  |   |-- PowerPC,POWER9@1c
7e658578 :  |   |-- PowerPC,POWER9@1d
7e658f90 :  |   |-- PowerPC,POWER9@1e
7e6599a8 :  |   |-- PowerPC,POWER9@1f
7e65a3c0 :  |   |-- PowerPC,POWER9@20
7e65add8 :  |   |-- PowerPC,POWER9@21
7e65b7f0 :  |   |-- PowerPC,POWER9@22
7e65c208 :  |   |-- PowerPC,POWER9@23
7e65cc20 :  |   |-- PowerPC,POWER9@24
7e65d638 :  |   |-- PowerPC,POWER9@25
7e65e050 :  |   |-- PowerPC,POWER9@26
7e65ea68 :  |   |-- PowerPC,POWER9@27
7e65f480 :  |   |-- PowerPC,POWER9@28
7e65fe98 :  |   |-- PowerPC,POWER9@29
7e6608b0 :  |   |-- PowerPC,POWER9@2a
7e6612c8 :  |   |-- PowerPC,POWER9@2b
7e661ce0 :  |   |-- PowerPC,POWER9@2c
7e6626f8 :  |   |-- PowerPC,POWER9@2d
7e663110 :  |   |-- PowerPC,POWER9@2e
7e663b28 :  |   |-- PowerPC,POWER9@2f
7e664540 :  |   |-- PowerPC,POWER9@30
7e664f58 :  |   |-- PowerPC,POWER9@31
7e665970 :  |   |-- PowerPC,POWER9@32
7e666388 :  |   |-- PowerPC,POWER9@33
7e666da0 :  |   |-- PowerPC,POWER9@34
7e6677b8 :  |   |-- PowerPC,POWER9@35
7e6681d0 :  |   |-- PowerPC,POWER9@36
7e668be8 :  |   |-- PowerPC,POWER9@37
7e669600 :  |   |-- PowerPC,POWER9@38
7e66a018 :  |   |-- PowerPC,POWER9@39
7e66aa30 :  |   |-- PowerPC,POWER9@3a
7e66b448 :  |   |-- PowerPC,POWER9@3b
7e66be60 :  |   |-- PowerPC,POWER9@3c
7e66c878 :  |   |-- PowerPC,POWER9@3d
7e66d290 :  |   |-- PowerPC,POWER9@3e
7e66dca8 :  |   +-- PowerPC,POWER9@3f
7e66e768 :  |-- pci@800000020000000
7e670d48 :  |   |-- vga@0
7e671260 :  |   |-- usb-xhci@1
7e6b7320 :  |   |   |-- usb-keyboard@1
7e6b7de0 :  |   |   +-- usb-mouse@2
7e671890 :  |   |-- ethernet@2
7e671e68 :  |   +-- usb-ehci@3
7e672458 :  |-- vdevice
7e6726d8 :  |   |-- vty@71000000
7e6728f8 :  |   |-- nvram@71000001
7e672b68 :  |   +-- v-scsi@71000002
7e698f28 :  |       +-- disk
7e673028 :  |-- memory@100000000
7e673220 :  |-- memory@0
7e673418 :  |-- interrupt-controller
7e676558 :  |-- aliases
7e676660 :  |-- options
7e676720 :  |-- openprom
7e676828 :  |-- packages
7e6768f0 :  |   |-- deblocker
7e677390 :  |   |-- disk-label
7e67ba30 :  |   |-- fat-files
7e67e1a8 :  |   |-- rom-files
7e67ebc8 :  |   |-- ext2-files
7e681640 :  |   |-- obp-tftp
7e681a10 :  |   +-- iso-9660
7e686458 :  +-- mmu ok
0 >
 
  • Haha
Reactions: Doq
Hmmm....Looks better!

Code:
7e643530 :  /
7e643b40 :  |-- ibm,persistent-memory
7e643da0 :  |-- chosen
7e6441b0 :  |-- rtas
7e6454d8 :  |-- event-sources
7e645690 :  |   |-- hot-plug-events
7e6457e8 :  |   +-- epow-events
7e645988 :  |-- cpus
7e645ca0 :  |   |-- PowerPC,POWER9@0
7e6466d8 :  |   |-- PowerPC,POWER9@4
7e647110 :  |   |-- PowerPC,POWER9@8
7e647b48 :  |   |-- PowerPC,POWER9@c
7e648580 :  |   |-- PowerPC,POWER9@10
7e648fb8 :  |   |-- PowerPC,POWER9@14
7e6499f0 :  |   |-- PowerPC,POWER9@18
7e64a428 :  |   +-- PowerPC,POWER9@1c
7e64af08 :  |-- pci@800000020000000
7e64d4e8 :  |   |-- vga@0
7e64da00 :  |   |-- usb-xhci@1
7e6946e8 :  |   |   |-- usb-keyboard@1
7e6951a8 :  |   |   +-- usb-mouse@2
7e64e030 :  |   |-- ethernet@2
7e64e608 :  |   +-- usb-ehci@3
7e64ebf8 :  |-- vdevice
7e64ee78 :  |   |-- vty@71000000
7e64f098 :  |   |-- nvram@71000001
7e64f308 :  |   +-- v-scsi@71000002
7e6756c8 :  |       +-- disk
7e64f7c8 :  |-- memory@100000000
7e64f9c0 :  |-- memory@0
7e64fbb8 :  |-- interrupt-controller
7e652cf8 :  |-- aliases
7e652e00 :  |-- options
7e652ec0 :  |-- openprom
7e652fc8 :  |-- packages
7e653090 :  |   |-- deblocker
7e653b30 :  |   |-- disk-label
7e6581d0 :  |   |-- fat-files
7e65a948 :  |   |-- rom-files
7e65b368 :  |   |-- ext2-files
7e65dde0 :  |   |-- obp-tftp
7e65e1b0 :  |   +-- iso-9660
7e662bf8 :  +-- mmu ok
0 > dev /cpus   ok
0 > ls 
7e645988 :  /cpus
7e645ca0 :  |-- PowerPC,POWER9@0
7e6466d8 :  |-- PowerPC,POWER9@4
7e647110 :  |-- PowerPC,POWER9@8
7e647b48 :  |-- PowerPC,POWER9@c
7e648580 :  |-- PowerPC,POWER9@10
7e648fb8 :  |-- PowerPC,POWER9@14
7e6499f0 :  |-- PowerPC,POWER9@18
7e64a428 :  +-- PowerPC,POWER9@1c ok
0 > dev @0   ok
0 > .properties 
slof,from-fdt                    00000000 
ibm,my-drc-index                 10000000 
reg                              00000000 
device_type                      cpu
                                 63707500 
cpu-version                      004e1202 
d-cache-block-size               00000080 
d-cache-line-size                00000080 
i-cache-block-size               00000080 
i-cache-line-size                00000080 
d-cache-size                     00008000 
i-cache-size                     00008000 
timebase-frequency               1e848000 
clock-frequency                  3b9aca00 
slb-size                         00000020 
ibm,slb-size                     00000020 
status                           okay
                                 6f6b6179  00
64-bit                         
ibm,purr                         00000001 
ibm,spurr                        00000001 
ibm,processor-segment-sizes      0000001c  00000028  ffffffff  ffffffff
                                
ibm,vmx                          00000002 
ibm,dfp                          00000001 
ibm,segment-page-sizes           0000000c  00000000  00000001  0000000c
                                 00000000  00000010  00000110  00000001
                                 00000010  00000001 
ibm,pa-features                  4200f63f  c7c000f0  80000000  00000000
                                 00008000  80008000  00008000  80008000
                                 00008000  c0000000  00008000  80008000
                                 80008000  80008000  80008000  80008000
                                 80000000 
ibm,chip-id                      00000000 
ibm,pft-size                     00000000  0000001a 
ibm,ppc-interrupt-server#s       00000000  00000001  00000002  00000003
                                
ibm,ppc-interrupt-gserver#s      00000000  00000000  00000001  00000000
                                 00000002  00000000  00000003  00000000
                                
ibm,processor-radix-AP-encodings 0000000c  a0000010  20000015  4000001e
                                
ibm,dec-bits                     00000038 
name                             PowerPC,POWER9
                                 506f7765  7250432c  504f5745  523900 ok
0 >
 
Thanks Joe, I think I loaded BootX from the EFI partition of a GUID disk on one of the 2005 Mac's that supports GUID. If I am remembering correct it happily booted the first HFS+ partition it found.

Tho I'm sure I could just point it there, I think if the HFS+ partition on the same GUID disk is the first one it finds, it will just boot that, assuming it finds the mach_kernel there.

In the scope of what I an hopping to do here that should make things a little easier. As SLOF already supports GUID disks and has a FAT file systems /package.

So we kind of chain load OpenPOWER>SLOF.elf>BootX.

This is where I'm stuck and need some help and guidance, BootX is an XCOFF executable correct?

SLOF lacks an XCOFF-LOADER /package.

So I'm going to need to patch SLOF to include an xcoff-loader, correct?
I'm assuming I need to do sometime like this:

Code:
: read-file ( c-addr u -- c-addr' u' ) r/o bin open-file throw >r r@ file-size throw dup allocate throw r@ read-file throw drop r> close-file throw ;

variable xcoff-buffer
variable xcoff-size

: load-xcoff ( c-addr u -- )
  read-file
  xcoff-buffer !
  xcoff-size ! ;

"example.xcoff" s" load-xcoff


\ Define constants for XCOFF header offsets and sizes
256 constant FILE-HEADER-SIZE

: parse-file-header ( c-addr -- )
  \ Extract and print header information
  \ Adjust the offsets and sizes as per the XCOFF format
  dup 0 FILE-HEADER-SIZE move-to-header
  header magic-number @ . \ Display the magic number
  header number-of-sections @ . \ Display the number of sections
  header optional-header-size @ . \ Display the optional header size
  ;

: parse-xcoff ( -- )
  xcoff-buffer @
  parse-file-header
  \ Continue parsing optional headers, section headers, etc.
  ;

: load-section ( c-addr size -- )
  \ Logic to load section data into memory
  \ This might involve relocating to a different address
  ;

: load-sections ( -- )
  \ Iterate through sections and load them
  \ Use header information to find section offsets and sizes
  ;

: relocate-symbols ( -- )
  \ Process relocation entries and adjust addresses
  ;

: process-symbol-table ( -- )
  \ Parse and handle symbol table entries
  ;

: load-xcoff-file ( c-addr u -- )
  load-xcoff
  parse-xcoff
  load-sections
  relocate-symbols
  process-symbol-table
  ;
 
I think I have some workable code to build SLOF with XCOFF loading, likely I need to debug it after I actually try and load BootX this way, but first I have to setup a working PPC64 cross compiler for macOS Sonoma on AppleSoc and that is proving to be non-trivial.....
 
Maybe you can do it like the Quad G5 does it. Its xcoff-loader package is not very large.

The attached is taken from Quad G5 but is missing stuff that you need to fill in. Does SLOF support Open Firmware local variables?

Whatever gets executed needs access to Open Firmware through the CI (client interface).
 

Attachments

  • xcoff-loader from Quad G5 Open Firmware.zip
    13.4 KB · Views: 44
I don't know, I tried this, but it seems to be shooting me off the dark side of the moon.

Code:
: read  ( ihandle str len -- len' )      rot s" read"  rot
    ['] $call-method CATCH IF 2drop 3drop -1 THEN ;

\ Define XCOFF header structure
create xcoff-header
2 , \ magic
2 , \ nscns
4 , \ timdat
4 , \ symptr
4 , \ nsyms
2 , \ opthdr
2 , \ flags

\ Define XCOFF section structure
create xcoff-section
4 , \ p_vaddr
4 , \ p_filesz
4 , \ p_memsz
4 , \ p_offset

: parse-xcoff ( addr -- )
    xcoff-header 0 do
        dup i + @
        \ Store the header values as needed
    loop
    xcoff-section 0 do
        dup i + @
        \ Store the section values as needed
    loop
;

: load-xcoff ( addr filename -- )
    \ Implementation to load an XCOFF file from filename into memory at addr
    \ This is a placeholder and needs to be implemented according to your requirements
    \ For example, you might need to read the file and parse the XCOFF format
    \ and then load it into the specified memory address.
    \ This is just a skeleton and needs to be filled with actual logic.
;

0 VALUE xcoff-mem

: load-xcoff-file ( filename -- )
    \ Allocate memory for the XCOFF file
    1000000 alloc-mem throw to xcoff-mem
    \ Load the XCOFF file into memory
    s" BootX.xcoff" xcoff-mem load-xcoff throw
    \ Set the entry point and other necessary state
    xcoff-mem 1000000 + to go-entry
    true state-valid !
;

Code:
" disk:,\bootx.xcoff" load-xcoff   ok
4 > go-entry @ 100 dump  \ This will dump 256 bytes (100 in hex) starting from the address in go-entry                                                           
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88  ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28  ...............(
00000020: 68 65 61 64 65 72 00 00 6d 61 67 69 63 31 32 33  header..magic123
00000030: 00 00 00 00 00 0f 2e b8 67 69 74 2d 33 61 32 35  ........git-3a25
00000040: 39 64 66 32 34 34 39 66 71 65 6d 75 30 00 00 00  9df2449fqemu0...
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000060: 00 00 00 00 00 00 00 00 00 00 20 23 09 18 18 57  .......... #...W
00000070: 00 00 00 00 00 00 00 00 31 00 00 00 00 00 00 00  ........1.......
00000080: 00 00 00 00 97 be e5 b9 ff ff ff ff ff ff ff ff  ................
00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 01 03 40  ...............@
000000e0: 00 00 00 00 00 01 03 10 00 00 00 00 00 00 00 01  ................
000000f0: 00 00 00 00 00 00 00 28 73 74 61 67 65 31 00 00  .......(stage1.. ok
4 > go-entry @ 100 dump  \ This will dump 256 bytes (100 in hex) starting from the a\ Define XCOFF header structure   ok
4 > go-entry @ 400 dump 
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88  ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28  ...............(
00000020: 68 65 61 64 65 72 00 00 6d 61 67 69 63 31 32 33  header..magic123
00000030: 00 00 00 00 00 0f 2e b8 67 69 74 2d 33 61 32 35  ........git-3a25
00000040: 39 64 66 32 34 34 39 66 71 65 6d 75 30 00 00 00  9df2449fqemu0...
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000060: 00 00 00 00 00 00 00 00 00 00 20 23 09 18 18 57  .......... #...W
00000070: 00 00 00 00 00 00 00 00 31 00 00 00 00 00 00 00  ........1.......
00000080: 00 00 00 00 97 be e5 b9 ff ff ff ff ff ff ff ff  ................
00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 01 03 40  ...............@
000000e0: 00 00 00 00 00 01 03 10 00 00 00 00 00 00 00 01  ................
000000f0: 00 00 00 00 00 00 00 28 73 74 61 67 65 31 00 00  .......(stage1..
00000100: e8 60 2f f0 7c 69 03 a6 38 00 01 00 4e 80 04 20  .`/.|i..8...N..
00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000001a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000200: 7c 10 43 a6 7c 09 02 a6 7c 12 43 a6 7c 08 02 a6  |.C.|...|.C.|...
00000210: 7c 13 43 a6 e8 00 2f f0 7c 09 03 a6 38 00 02 00  |.C.../.|...8...
00000220: 4e 80 04 20 00 00 00 00 00 00 00 00 00 00 00 00  N.. ............
00000230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000280: 7c 10 43 a6 7c 09 02 a6 7c 12 43 a6 7c 08 02 a6  |.C.|...|.C.|...
00000290: 7c 13 43 a6 e8 00 2f f0 7c 09 03 a6 38 00 02 80  |.C.../.|...8...
000002a0: 4e 80 04 20 00 00 00 00 00 00 00 00 00 00 00 00  N.. ............
000002b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000300: 7c 10 43 a6 7c 09 02 a6 7c 12 43 a6 7c 08 02 a6  |.C.|...|.C.|...
00000310: 7c 13 43 a6 e8 00 2f f0 7c 09 03 a6 38 00 03 00  |.C.../.|...8...
00000320: 4e 80 04 20 00 00 00 00 00 00 00 00 00 00 00 00  N.. ............
00000330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000380: 7c 10 43 a6 7c 09 02 a6 7c 12 43 a6 7c 08 02 a6  |.C.|...|.C.|...
00000390: 7c 13 43 a6 e8 00 2f f0 7c 09 03 a6 38 00 03 80  |.C.../.|...8...
000003a0: 4e 80 04 20 00 00 00 00 00 00 00 00 00 00 00 00  N.. ............
000003b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000003c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000003d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000003e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000003f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ ok
4 > go-entry @ .   0  ok
 
Seem SLOF already has a load-xcoff-file support.

Code:
: load-xcoff-file ( addr len -- )
   2dup open-dev dup IF
      dup to my-self
      dup ihandle>phandle set-node
      -rot                              ( ihandle devstr len )
      encode-string s" bootpath" set-chosen
      $bootargs encode-string s" bootargs" set-chosen
      get-load-base s" load" 3 pick ['] $call-method CATCH IF
         -67 boot-exception-handler 3drop drop false
      ELSE
         dup 0> IF
            init-program
         ELSE
            false state-valid !
            drop 0                                     \ Could not load
         THEN
      THEN
      swap close-dev device-end dup to load-size
   ELSE -68 boot-exception-handler 3drop false THEN
   r> set-node r> to my-self                           \ Restore my-self
;

Apple's bootx.xcoff header seems a little off?

Code:
Let's analyze the provided XCOFF header in hex format:

Copy code
101DF0003 00000000 00000000 00000000 00480000 010B0000 00028000 00002000 0003A000 05616ECC
Here's a breakdown of the header fields based on the XCOFF format:

Magic Number (2 bytes): 01DF
Number of Sections (2 bytes): 0003
Timestamp (4 bytes): 00000000
Symbol Table Offset (4 bytes): 00000000
Number of Symbols (4 bytes): 00000000
Optional Header Size (2 bytes): 0048
Flags (2 bytes): 0000
Optional Header:
Magic Number (2 bytes): 010B
Version Stamp (2 bytes): 0000
Text Size (4 bytes): 00028000
Data Size (4 bytes): 00002000
BSS Size (4 bytes): 0003A000
Entry Point (4 bytes): 05616ECC
Potential Issues

Magic Number: The magic number 01DF seems unusual. Typically, XCOFF files use 01DF for 32-bit and 01F7 for 64-bit. Ensure this is correct for your environment.
Symbol Table Offset and Number of Symbols: Both are 00000000, indicating no symbol table. This might be fine, but ensure it's expected.
Optional Header Size: 0048 (72 bytes) seems correct, but verify if this matches the expected size for your XCOFF variant.
Entry Point: 05616ECC seems unusually high. Ensure this is within the valid range of your memory map.
Next Steps

Verify Magic Number: Ensure 01DF is correct for your XCOFF variant.
Check Entry Point: Ensure 05616ECC is a valid entry point.
Validate Header Fields: Cross-check all fields with the XCOFF specification for your environment.
If the header fields are correct, the issue might be elsewhere, such as in the file system or device initialization. If you need further assistance, please provide more context or specific details about the environment and setup.
 
Let's see if we can steal the code we need from OpenBios and maybe this will work a little better.

Step 1: Define XCOFF Structures​

First, we need to define the XCOFF structures in SLOF. Create a new file xcoff.fs in the SLOF source directory and add the following definitions:

Code:
\ xcoff.fs - XCOFF file format definitions

\ XCOFF Header structure
STRUCT
    /h FIELD xcoff-magic
    /h FIELD xcoff-num-sections
    /l FIELD xcoff-timestamp
    /l FIELD xcoff-symtab-offset
    /l FIELD xcoff-num-syms
    /h FIELD xcoff-opt-header-size
    /h FIELD xcoff-flags
CONSTANT xcoff-header

\ XCOFF Section structure
STRUCT
    8 FIELD xcoff-sec-name
    /l FIELD xcoff-sec-physaddr
    /l FIELD xcoff-sec-virtaddr
    /l FIELD xcoff-sec-size
    /l FIELD xcoff-sec-rawdata-offset
    /l FIELD xcoff-sec-reloc-offset
    /l FIELD xcoff-sec-linenum-offset
    /h FIELD xcoff-sec-num-reloc
    /h FIELD xcoff-sec-num-linenum
    /l FIELD xcoff-sec-flags
CONSTANT xcoff-section

Step 2: Implement XCOFF Loading Function​

Next, implement the function to load an XCOFF file. Add the following code to xcoff.fs:

Code:
\ Load an XCOFF file
: load-xcoff ( addr len -- success )
    \ Open the file
    2dup open-dev ?dup 0= IF
        2drop false EXIT
    THEN
    dup to my-self

    \ Read the XCOFF header
    xcoff-header alloc-mem ?dup 0= ABORT" Unable to allocate memory for XCOFF header!"
    dup xcoff-header erase
    xcoff-header read-dev ?dup 0= ABORT" Unable to read XCOFF header!"
    xcoff-header xcoff-magic @ 0x01DF <> IF
        xcoff-header free-mem
        close-dev
        false EXIT
    THEN

    \ Load sections
    xcoff-header xcoff-num-sections @ 0 ?DO
        xcoff-section alloc-mem ?dup 0= ABORT" Unable to allocate memory for XCOFF section!"
        dup xcoff-section erase
        xcoff-section read-dev ?dup 0= ABORT" Unable to read XCOFF section!"
        xcoff-section xcoff-sec-rawdata-offset @ seek-dev
        xcoff-section xcoff-sec-size @ alloc-mem ?dup 0= ABORT" Unable to allocate memory for section data!"
        dup xcoff-section xcoff-sec-size @ read-dev ?dup 0= ABORT" Unable to read section data!"
        \ Load section into memory (implementation-specific)
        \ ...
        xcoff-section free-mem
    LOOP

    \ Clean up
    xcoff-header free-mem
    close-dev
    true
;

Step 3: Integrate XCOFF Loading into SLOF Boot Process​

Modify boot.fs to call the load-xcoff function when attempting to load a boot file. Add the following code to boot.fs:

Code:
\ Attempt to load an XCOFF file
: load-xcoff-init ( arg len file-addr -- success )
    false state-valid !                            \ Not valid anymore ...
    claim-list IF                                    \ Release claimed mem
        claim-list elf-release 0 to claim-list        \ from last load
    THEN

    true swap -1                       ( arg len true file-addr -1 )
    load-xcoff                         ( arg len true claim-list entry elftype )

    ( arg len true claim-list entry elftype )
    CASE
        1  OF ['] go-32-be   ENDOF           ( arg len true claim-list entry go )
        2  OF ['] go-64-be   ENDOF           ( arg len true claim-list entry go )
        3  OF ['] go-64-lev1 ENDOF           ( arg len true claim-list entry go )
        4  OF ['] go-64-lev2 ENDOF           ( arg len true claim-list entry go )
        5  OF ['] go-32-lev1 ENDOF           ( arg len true claim-list entry go )
        dup OF ['] no-go to go
            2drop 3drop false EXIT   ENDOF                   ( false )
    ENDCASE

    to go to go-entry to claim-list
    dup state-valid ! -rot

    2 pick IF
        go-args 2!
    ELSE
        2drop
    THEN
;

\ Modify init-program to call load-xcoff-init
: init-program ( -- )
    $bootargs get-load-base ['] load-xcoff-init CATCH ?dup IF
        boot-exception-handler
        2drop 2drop false          \ Could not claim
    ELSE IF
            0 ciregs 2dup >r3 ! >r4 !  \ Valid (XCOFF) Image
        THEN
    THEN
;
 
I don't know, I tried this, but it seems to be shooting me off the dark side of the moon.

Code:
: read  ( ihandle str len -- len' )      rot s" read"  rot
    ['] $call-method CATCH IF 2drop 3drop -1 THEN ;
Usually we use " instead of s" because it's shorter but " adds hex parsing which might not be good for some strings. They both compile or tokenize to the same result.

Code:
\ Define XCOFF header structure
create xcoff-header
2 , \ magic
2 , \ nscns
4 , \ timdat
4 , \ symptr
4 , \ nsyms
2 , \ opthdr
2 , \ flags
xcoff-header will be an address in the dictionary. The size depends on what else you put in the dictionary following create.
, appends a 4 byte value to the dictionary. For xcoff-header, you are appending 28 bytes but I think you want it to be 20 bytes.
Code:
xcoff-header 20 dump 
FF8653BC: 00 00 00 02 00 00 00 02 00 00 00 04 00 00 00 04 :................:
FF8653CC: 00 00 00 04 00 00 00 02 00 00 00 02 00 00 00 00 :................: ok

If you want to create space for some data, then buffer: is probably the way to go.
d# 20 buffer: xcoff-header
The buffer is allocated in Open Firmware heap space which is different than dictionary space (but this might be different in other implementations of Open Firmware). In Apple Open firmware, the heap seems to grow down toward the dictionary top (here) which grows upward. There's no way to unallocate the space used by the buffer so you might want to allocate the buffer manually.
d# 20 alloc-mem value xcoff-header
Then you can free it when you don't need it anymore.
xcoff-header d# 20 free-mem

Code:
: parse-xcoff ( addr -- )
    xcoff-header 0 do
        dup i + @
        \ Store the header values as needed
    loop
;
This assumes xcoff-header is the size of the header, rather than the address of the header. Replace xcoff-header to xcoff-header-size or change the value of xcoff-header to represent the size instead of the address.

@ loads 4 bytes onto the stack but i is only incrementing by 1. Change @ to c@ or change loop to 4 +loop

You need to do something with the loaded value, otherwise the next iteration will use that value as the address. Add some code after @, such as . which will show the value that was loaded.

You need to drop the addr before ; if you don't want to keep it on the stack as you've indicated by the usage comment ( addr -- )

Code:
: load-xcoff-file ( filename -- )
    \ Allocate memory for the XCOFF file
    1000000 alloc-mem throw to xcoff-mem
    \ Load the XCOFF file into memory
    s" BootX.xcoff" xcoff-mem load-xcoff throw
    \ Set the entry point and other necessary state
    xcoff-mem 1000000 + to go-entry
    true state-valid !
;
alloc-mem returns an address, not an error code, so throw is not appropriate there.
alloc-mem probably shouldn't be used for large allocations. 1000000 alloc-mem fails in Apple Open Firmware which can accept only up to 10000 (64K).

Code:
" disk:,\bootx.xcoff" load-xcoff   ok
4 > go-entry @ 400 dump  \ This will dump 256 bytes (100 in hex) starting from the address in go-entry                                                           
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88  ................
to go-entry implies that go-entry is a value but go-entry @ implies it is a variable.

I think it's supposed to be a value so you want to do go-entry 400 dump

A variable is useful when you want to pass an argument to a method by reference rather than by value. When using a variable, you have to dereference it using @ or ! to access the value.

Code:
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28  ...............(
00000020: 68 65 61 64 65 72 00 00 6d 61 67 69 63 31 32 33  header..magic123
00000030: 00 00 00 00 00 0f 2e b8 67 69 74 2d 33 61 32 35  ........git-3a25
00000040: 39 64 66 32 34 34 39 66 71 65 6d 75 30 00 00 00  9df2449fqemu0...
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000060: 00 00 00 00 00 00 00 00 00 00 20 23 09 18 18 57  .......... #...W
00000070: 00 00 00 00 00 00 00 00 31 00 00 00 00 00 00 00  ........1.......
00000080: 00 00 00 00 97 be e5 b9 ff ff ff ff ff ff ff ff  ................
00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 01 03 40  ...............@
000000e0: 00 00 00 00 00 01 03 10 00 00 00 00 00 00 00 01  ................
000000f0: 00 00 00 00 00 00 00 28 73 74 61 67 65 31 00 00  .......(stage1.. ok
Not sure what this stuff is. I suppose SLOF loads a binary at address zero. The binary includes code for PowerPC exception handlers, etc. I think xnu is similar?

Code:
00000100: e8 60 2f f0 7c 69 03 a6 38 00 01 00 4e 80 04 20  .`/.|i..8...N..
...
00000200: 7c 10 43 a6 7c 09 02 a6 7c 12 43 a6 7c 08 02 a6  |.C.|...|.C.|...
...
00000300: 7c 10 43 a6 7c 09 02 a6 7c 12 43 a6 7c 08 02 a6  |.C.|...|.C.|...
These are the first 3 PowerPC exception handlers which contain instructions for handling exception 100, 200, 300.
In Apple Open Firmware, the exception handlers are at the optional address at FFF00n00. An exception would appear like this:
Code:
DEFAULT CATCH!, code=FFF00300 at   %SRR0: FF80C750   %SRR1: 00009070
where FFF00300 is the address of the PowerPC exception handler for the third exception type.

Apple's bootx.xcoff header seems a little off?

Code:
Let's analyze the provided XCOFF header in hex format:

Copy code
101DF0003 00000000 00000000 00000000 00480000 010B0000 00028000 00002000 0003A000 05616ECC
Here's a breakdown of the header fields based on the XCOFF format:

Magic Number (2 bytes): 01DF
Number of Sections (2 bytes): 0003
Timestamp (4 bytes): 00000000
Symbol Table Offset (4 bytes): 00000000
Number of Symbols (4 bytes): 00000000
Optional Header Size (2 bytes): 0048
Flags (2 bytes): 0000
Optional Header:
Magic Number (2 bytes): 010B
Version Stamp (2 bytes): 0000
Text Size (4 bytes): 00028000
Data Size (4 bytes): 00002000
BSS Size (4 bytes): 0003A000
Entry Point (4 bytes): 05616ECC
Potential Issues

Magic Number: The magic number 01DF seems unusual. Typically, XCOFF files use 01DF for 32-bit and 01F7 for 64-bit. Ensure this is correct for your environment.
Symbol Table Offset and Number of Symbols: Both are 00000000, indicating no symbol table. This might be fine, but ensure it's expected.
Optional Header Size: 0048 (72 bytes) seems correct, but verify if this matches the expected size for your XCOFF variant.
Entry Point: 05616ECC seems unusually high. Ensure this is within the valid range of your memory map.
Next Steps

Verify Magic Number: Ensure 01DF is correct for your XCOFF variant.
Check Entry Point: Ensure 05616ECC is a valid entry point.
Validate Header Fields: Cross-check all fields with the XCOFF specification for your environment.
If the header fields are correct, the issue might be elsewhere, such as in the file system or device initialization. If you need further assistance, please provide more context or specific details about the environment and setup.
Seems valid. The Mac OS X PowerPC kernel is always 32-bit so BootX is also 32-bit.
BootX doesn't need symbols because it doesn't import or export symbols. It just needs the entry point.
The entry point is at 05616ECC because the text section loads at 05600000
I used MPW's DumpXCOFF command to look at it. You can run MPW commands in modern macOS. https://github.com/ksherlock/mpw
sl.h in BootX source code has memory maps. The XPostFacto project has a -seg1addr 05600000 linker flag for the BootX target.
 
xcoff-header will be an address in the dictionary. The size depends on what else you put in the dictionary following create.
, appends a 4 byte value to the dictionary. For xcoff-header, you are appending 28 bytes but I think you want it to be 20 bytes.
It looks like you want to define an XCOFF header structure in Forth. Based on your description, you want to ensure that the structure is 20 bytes in size. Here is how you can define the XCOFF header structure correctly:

Code:
\ Define XCOFF header structure
create xcoff-header
2 , \ magic
2 , \ nscns
4 , \ timdat
4 , \ symptr
4 , \ nsyms
2 , \ opthdr
2 , \ flags

\ Verify the size of xcoff-header
xcoff-header 20 dump

This will create a 20-byte structure for the XCOFF header. Each , appends a 4-byte value to the dictionary. The structure is defined as follows:

  • 2 , for magic (2 bytes)
  • 2 , for nscns (2 bytes)
  • 4 , for timdat (4 bytes)
  • 4 , for symptr (4 bytes)
  • 4 , for nsyms (4 bytes)
  • 2 , for opthdr (2 bytes)
  • 2 , for flags (2 bytes)
This totals to 20 bytes. The dump command at the end is used to verify the size and contents of the xcoff-header.

If you need to create space for some data, you can use buffer: or alloc-mem as follows:

Code:
\ Using buffer:
d# 20 buffer: xcoff-header

\ Using alloc-mem
d# 20 alloc-mem value xcoff-header

And remember to free the allocated memory when it's no longer needed:

Code:
xcoff-header d# 20 free-mem

This ensures that the memory management is handled correctly?
If you want to create space for some data, then buffer: is probably the way to go.
d# 20 buffer: xcoff-header
The buffer is allocated in Open Firmware heap space which is different than dictionary space (but this might be different in other implementations of Open Firmware). In Apple Open firmware, the heap seems to grow down toward the dictionary top (here) which grows upward. There's no way to unallocate the space used by the buffer so you might want to allocate the buffer manually.
d# 20 alloc-mem value xcoff-header
Then you can free it when you don't need it anymore.
xcoff-header d# 20 free-mem
To create space for some data in Open Firmware, you can use either buffer: or alloc-mem. Here are the details on how to use both methods:

Using buffer:​

The buffer: word allocates space in the Open Firmware heap space. This space cannot be deallocated, so use it when you need a persistent buffer.

Code:
\ Allocate a 20-byte buffer for the XCOFF header
d# 20 buffer: xcoff-header

Using alloc-mem​

The alloc-mem word allocates memory that can be freed later. This is useful when you need temporary space.

Code:
\ Allocate a 20-byte buffer for the XCOFF header
d# 20 alloc-mem value xcoff-header

\ Free the allocated memory when it's no longer needed
xcoff-header d# 20 free-mem

Example Usage in Context​

Here is an example of how you might use these methods in a Forth program:

Code:
\ Using buffer:
d# 20 buffer: xcoff-header
\ Now xcoff-header points to a 20-byte buffer in the heap space

\ Using alloc-mem:
d# 20 alloc-mem value xcoff-header
\ Now xcoff-header points to a 20-byte buffer in the allocated memory

\ ... use the buffer ...

\ Free the allocated memory when done
xcoff-header d# 20 free-mem

Summary​

  • Use buffer: for persistent buffers that do not need to be deallocated.
  • Use alloc-mem for temporary buffers that you can free when done.
Choose the method that best fits your use case.


This assumes xcoff-header is the size of the header, rather than the address of the header. Replace xcoff-header to xcoff-header-size or change the value of xcoff-header to represent the size instead of the address.

@ loads 4 bytes onto the stack but i is only incrementing by 1. Change @ to c@ or change loop to 4 +loop

You need to do something with the loaded value, otherwise the next iteration will use that value as the address. Add some code after @, such as . which will show the value that was loaded.

You need to drop the addr before ; if you don't want to keep it on the stack as you've indicated by the usage comment ( addr -- )

To address the issues you mentioned, here are the necessary changes and explanations:

  1. Change xcoff-header to xcoff-header-size or change the value of xcoff-header to represent the size instead of the address:
    If xcoff-header is meant to represent the size, rename it to xcoff-header-size for clarity. If it should represent the address, ensure it is used correctly.
  2. Change @ to c@ or change loop to 4 +loop:
    Since @ loads 4 bytes and i is incrementing by 1, either use c@ to load 1 byte or change the loop to increment by 4.
  3. Add code to handle the loaded value:
    Add code to process the loaded value, such as printing it with ..
  4. Drop the address before ;:
    Ensure the address is dropped before the end of the word definition if it is not needed on the stack.
Here is the revised Forth code:

Code:
\ Define the size of the XCOFF header
d# 20 constant xcoff-header-size

\ Allocate a 20-byte buffer for the XCOFF header
d# 20 buffer: xcoff-header

\ Example loop to process each byte in the buffer
: process-xcoff-header ( addr -- )
    xcoff-header-size 0 do
        xcoff-header i + c@ . \ Load and print each byte
    loop
    drop \ Drop the address before ending the word
;

\ Example usage
xcoff-header process-xcoff-header

alloc-mem returns an address, not an error code, so throw is not appropriate there.
alloc-mem probably shouldn't be used for large allocations. 1000000 alloc-mem fails in Apple Open Firmware which can accept only up to 10000 (64K).
  1. Change xcoff-header to xcoff-header-size or change the value of xcoff-header to represent the size instead of the address:
    If xcoff-header is meant to represent the size, rename it to xcoff-header-size for clarity. If it should represent the address, ensure it is used correctly.
  2. Change @ to c@ or change loop to 4 +loop:
    Since @ loads 4 bytes and i is incrementing by 1, either use c@ to load 1 byte or change the loop to increment by 4.
  3. Add code to handle the loaded value:
    Add code to process the loaded value, such as printing it with ..
  4. Drop the address before ;:
    Ensure the address is dropped before the end of the word definition if it is not needed on the stack.
Here is the revised Forth code:

Code:
\ Define the size of the XCOFF header
d# 20 constant xcoff-header-size

\ Allocate a 20-byte buffer for the XCOFF header
d# 20 buffer: xcoff-header

\ Example loop to process each byte in the buffer
: process-xcoff-header ( addr -- )
    xcoff-header-size 0 do
        xcoff-header i + c@ . \ Load and print each byte
    loop
    drop \ Drop the address before ending the word
;

\ Example usage
xcoff-header process-xcoff-header

Revised load-xcoff-file Function​

To address the issues with alloc-mem and the use of throw, here is the revised load-xcoff-file function:

Code:
: load-xcoff-file ( filename -- )
    \ Allocate memory for the XCOFF file
    10000 alloc-mem to xcoff-mem \ Use a smaller allocation size
    \ Load the XCOFF file into memory
    s" BootX.xcoff" xcoff-mem load-xcoff \ Assuming load-xcoff does not throw
    \ Set the entry point and other necessary state
    xcoff-mem 10000 + to go-entry
    true state-valid !
;
to go-entry implies that go-entry is a value but go-entry @ implies it is a variable.

I think it's supposed to be a value so you want to do go-entry 400 dump

A variable is useful when you want to pass an argument to a method by reference rather than by value. When using a variable, you have to dereference it using @ or ! to access the value.


To clarify the usage of go-entry and ensure it is treated as a value rather than a variable, you should define go-entry as a constant. This way, you can directly use it without needing to dereference it.

Here is the revised code:

Code:
\ Define go-entry as a value
variable go-entry

: load-xcoff-file ( filename -- )
    \ Allocate memory for the XCOFF file
    10000 alloc-mem to xcoff-mem \ Use a smaller allocation size
    \ Load the XCOFF file into memory
    s" BootX.xcoff" xcoff-mem load-xcoff \ Assuming load-xcoff does not throw
    \ Set the entry point and other necessary state
    xcoff-mem 10000 + go-entry !
    true state-valid !
;

\ Example usage
" disk:,\bootx.xcoff" load-xcoff
go-entry @ 400 dump \ Dump 256 bytes starting from the address in go-entry

Not sure what this stuff is. I suppose SLOF loads a binary at address zero. The binary includes code for PowerPC exception handlers, etc. I think xnu is similar?

Explanation of the Memory Dump​

The memory dump shows a sequence of bytes, which can be interpreted as follows:

  • Header Information: The initial bytes are likely part of the XCOFF header, which includes metadata about the file.
  • Magic String: The string "magic123" at address 0x20 indicates a magic number used to identify the file format.
  • Git Information: The string "git-3a259df2449fqemu0" at address 0x30 suggests versioning information, possibly a commit hash.
  • Zeroed Data: The sequence of zeros indicates uninitialized or cleared memory regions.
  • Other Data: Various other bytes represent different sections of the loaded file, including code and data segments.

SLOF Loading Process​

The SLOF (Slimline Open Firmware) loads a binary at a specific address, which includes code for PowerPC exception handlers and other initialization routines. The load-xcoff-file function is responsible for loading the XCOFF file into memory and setting the entry point.

Relevant Code Snippets​


Code:
: load-xcoff-file ( filename -- )
    \ Allocate memory for the XCOFF file
    10000 alloc-mem to xcoff-mem \ Use a smaller allocation size
    \ Load the XCOFF file into memory
    s" BootX.xcoff" xcoff-mem load-xcoff \ Assuming load-xcoff does not throw
    \ Set the entry point and other necessary state
    xcoff-mem 10000 + go-entry !
    true state-valid !
;

SLOF Initialization Code​

The SLOF initialization code in ofw.S sets up various registers and memory locations before jumping to the entry point:

Code:
.section ".slof.loader","ax"

lis r31, fdt_start@h    /* save address of */
ori r31, r31, fdt_start@l    /* flattened device */
std r3, 0(r31)        /* tree */

lis r31, romfs_base@h    /* save address of */
ori r31, r31, romfs_base@l    /* the romfs */
std r4, 0(r31)

lis r31, epapr_magic@h    /* if it is an epapr compliant */
ori r31, r31, epapr_magic@l    /* low level firmware; then r6 */
std r6, 0(r31)        /* contains the epapr magic */

lis r31, epapr_ima_size@h
ori r31, r31, epapr_ima_size@l
std r7, 0(r31)        /* r7 contains the IMA size */

mfmsr r0
mtsrr1 r0
lis r3, _slof_text@h
ori r3, r3, _slof_text@l
ld r3, 0(r3)
std r3, XVECT_M_HANDLER(0)

ba 0x100

Conclusion​

The memory dump and the SLOF loading process indicate that the binary loaded at address zero includes various sections such as headers, code, and data. The load-xcoff-file function is responsible for loading the XCOFF file and setting the entry point, which is then used to start execution. The SLOF initialization code sets up the necessary state before jumping to the entry point.



These are the first 3 PowerPC exception handlers which contain instructions for handling exception 100, 200, 300.
In Apple Open Firmware, the exception handlers are at the optional address at FFF00n00. An exception would appear like this:

Exception Handling in SLOF​

The file /slof/fs/exception.fs contains definitions and handlers for various exceptions. Here are some key parts of the code:

  • Exception Register Structure:

Code:
STRUCT
   cell FIELD >r0   cell FIELD >r1   cell FIELD >r2   cell FIELD >r3
   cell FIELD >r4   cell FIELD >r5   cell FIELD >r6   cell FIELD >r7
   cell FIELD >r8   cell FIELD >r9   cell FIELD >r10  cell FIELD >r11
   cell FIELD >r12  cell FIELD >r13  cell FIELD >r14  cell FIELD >r15
   cell FIELD >r16  cell FIELD >r17  cell FIELD >r18  cell FIELD >r19
   cell FIELD >r20  cell FIELD >r21  cell FIELD >r22  cell FIELD >r23
   cell FIELD >r24  cell FIELD >r25  cell FIELD >r26  cell FIELD >r27
   cell FIELD >r28  cell FIELD >r29  cell FIELD >r30  cell FIELD >r31
   cell FIELD >cr   cell FIELD >xer  cell FIELD >lr   cell FIELD >ctr
   cell FIELD >srr0 cell FIELD >srr1 cell FIELD >dar  cell FIELD >dsisr
CONSTANT ciregs-size

Exception Display Functions:

Code:
: .16  10 0.r 3 spaces ;
: .8   8 spaces 8 0.r 3 spaces ;
: .4regs  cr 4 0 DO dup @ .16 8 cells+ LOOP drop ;
: .fixed-regs
   cr ."     R0 .. R7           R8 .. R15         R16 .. R23         R24 .. R31"
   dup 8 0 DO dup .4regs cell+ LOOP drop
;

: .special-regs
   cr ."     CR / XER           LR / CTR          SRR0 / SRR1        DAR / DSISR"
   cr dup >cr  @ .8   dup >lr  @ .16  dup >srr0 @ .16  dup >dar @ .16
   cr dup >xer @ .16  dup >ctr @ .16  dup >srr1 @ .16    >dsisr @ .8
;

: .regs
   cr .fixed-regs
   cr .special-regs
   cr cr
;

Hardware Exception Handler:

Code:
: .hw-exception ( reason-code exception-nr -- )
   ." ( " dup . ." ) "
   CASE
      200 OF ." Machine Check" ENDOF
      300 OF ." Data Storage" ENDOF
      380 OF ." Data Segment" ENDOF
      400 OF ." Instruction Storage" ENDOF
      480 OF ." Instruction Segment" ENDOF
      500 OF ." External" ENDOF
      600 OF ." Alignment" ENDOF
      700 OF ." Program" ENDOF
      800 OF ." Floating-point unavailable" ENDOF
      900 OF ." Decrementer" ENDOF
      980 OF ." Hypervisor Decrementer" ENDOF
      C00 OF ." System Call" ENDOF
      D00 OF ." Trace" ENDOF
      F00 OF ." Performance Monitor" ENDOF
      F20 OF ." VMX Unavailable" ENDOF
      1200 OF ." System Error" ENDOF
      1600 OF ." Maintenance" ENDOF
      1800 OF ." Thermal" ENDOF
      dup OF ." Unknown" ENDOF
   ENDCASE
   ."  Exception [ " . ." ]"
;


where FFF00300 is the address of the PowerPC exception handler for the third exception type.



Seems valid. The Mac OS X PowerPC kernel is always 32-bit so BootX is also 32-bit.
BootX doesn't need symbols because it doesn't import or export symbols. It just needs the entry point.
The entry point is at 05616ECC because the text section loads at 05600000
I used MPW's DumpXCOFF command to look at it. You can run MPW commands in modern macOS. https://github.com/ksherlock/mpw
sl.h in BootX source code has memory maps. The XPostFacto project has a -seg1addr 05600000 linker flag for the BootX target.

Conclusion​

The XCOFF header you provided seems valid for a 32-bit PowerPC environment. The entry point 05616ECC is within the expected range given that the text section loads at 05600000. Ensure that all header fields match the XCOFF specification for your environment. If the header fields are correct, the issue might be elsewhere, such as in the file system or device initialization.
 
Last edited:
Taking what we have just learned for Joe Van Tunen and the OpenBios source code, please help me write an xcoff loader for SLOF to boot Apple's bootx.xcoff for loading the Mac OS X on the pseries qemu machine. I'd like it to show up in the /packages section of SLOF's dev tree. It can be both forth and/or C, but we need all the debug strings so we can see what it is doing and what stage it may fail.

To create an XCOFF loader for SLOF to boot Apple's bootx.xcoff for loading Mac OS X on the pseries QEMU machine, we need to extend SLOF with a new package that can handle XCOFF files. This involves writing both Forth and C code to parse the XCOFF header, load the sections into memory, and jump to the entry point.

Step 1: Create the XCOFF Loader Package​

First, let's create a new Forth file for the XCOFF loader package. We'll call it xcoff-loader.fs and place it in the slof/fs/packagesdirectory.

xcoff-loader.fs​


Code:
\ *****************************************************************************
\ * XCOFF Loader for SLOF
\ * This package loads and executes XCOFF binaries.
\ *****************************************************************************

s" xcoff-loader" device-name
get-node to xcoff-loader

\ Constants for XCOFF header fields
2 CONSTANT XCOFF_MAGIC_OFFSET
2 CONSTANT XCOFF_NUM_SECTIONS_OFFSET
4 CONSTANT XCOFF_TIMESTAMP_OFFSET
4 CONSTANT XCOFF_SYMTAB_OFFSET
4 CONSTANT XCOFF_NUM_SYMS_OFFSET
2 CONSTANT XCOFF_OPTHDR_SIZE_OFFSET
2 CONSTANT XCOFF_FLAGS_OFFSET

\ Constants for XCOFF optional header fields
2 CONSTANT XCOFF_OPT_MAGIC_OFFSET
2 CONSTANT XCOFF_OPT_VERSION_OFFSET
4 CONSTANT XCOFF_OPT_TEXT_SIZE_OFFSET
4 CONSTANT XCOFF_OPT_DATA_SIZE_OFFSET
4 CONSTANT XCOFF_OPT_BSS_SIZE_OFFSET
4 CONSTANT XCOFF_OPT_ENTRY_POINT_OFFSET

\ Function to read XCOFF header
: read-xcoff-header ( addr -- )
    ." Reading XCOFF header..." cr
    dup XCOFF_MAGIC_OFFSET + @ . ." Magic Number" cr
    dup XCOFF_NUM_SECTIONS_OFFSET + @ . ." Number of Sections" cr
    dup XCOFF_TIMESTAMP_OFFSET + @ . ." Timestamp" cr
    dup XCOFF_SYMTAB_OFFSET + @ . ." Symbol Table Offset" cr
    dup XCOFF_NUM_SYMS_OFFSET + @ . ." Number of Symbols" cr
    dup XCOFF_OPTHDR_SIZE_OFFSET + @ . ." Optional Header Size" cr
    dup XCOFF_FLAGS_OFFSET + @ . ." Flags" cr
;

\ Function to read XCOFF optional header
: read-xcoff-opt-header ( addr -- )
    ." Reading XCOFF optional header..." cr
    dup XCOFF_OPT_MAGIC_OFFSET + @ . ." Optional Magic Number" cr
    dup XCOFF_OPT_VERSION_OFFSET + @ . ." Version Stamp" cr
    dup XCOFF_OPT_TEXT_SIZE_OFFSET + @ . ." Text Size" cr
    dup XCOFF_OPT_DATA_SIZE_OFFSET + @ . ." Data Size" cr
    dup XCOFF_OPT_BSS_SIZE_OFFSET + @ . ." BSS Size" cr
    dup XCOFF_OPT_ENTRY_POINT_OFFSET + @ . ." Entry Point" cr
;

\ Function to load XCOFF sections
: load-xcoff-sections ( addr -- )
    ." Loading XCOFF sections..." cr
    \ Implement section loading logic here
;

\ Function to execute XCOFF binary
: exec-xcoff ( entry-point -- )
    ." Executing XCOFF binary at entry point: " . cr
    \ Implement execution logic here
;

\ Main function to load and execute XCOFF binary
: load-xcoff ( addr -- )
    read-xcoff-header
    read-xcoff-opt-header
    load-xcoff-sections
    XCOFF_OPT_ENTRY_POINT_OFFSET + @ exec-xcoff
;

finish-device

Step 2: Integrate the XCOFF Loader Package​

Next, we need to integrate the new xcoff-loader package into SLOF's package system. We'll modify the packages.fs file to include our new package.

packages.fs​


Code:
\ *****************************************************************************
\ * Support Packages
\ *****************************************************************************

s" packages" device-name
get-node to packages

new-device
#include "packages/deblocker.fs"
finish-device

new-device
#include "packages/disk-label.fs"
finish-device

new-device
#include "packages/fat-files.fs"
finish-device

new-device
#include "packages/rom-files.fs"
finish-device

new-device
#include "packages/ext2-files.fs"
finish-device

new-device
#include "packages/obp-tftp.fs"
finish-device

new-device
#include "packages/iso-9660.fs"
finish-device

new-device
#include "packages/xcoff-loader.fs"
finish-device

Step 3: Implement the C Functions​

We need to implement the C functions that will be called from the Forth code to handle the actual loading and execution of the XCOFF binary. We'll create a new C file called xcoff-loader.c and place it in the lib directory.

xcoff-loader.c​


Code:
/******************************************************************************
 * XCOFF Loader for SLOF
 * This file contains the C functions for loading and executing XCOFF binaries.
 *****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "OF.h"

#define XCOFF_MAGIC 0x01DF

typedef struct {
    uint16_t magic;
    uint16_t num_sections;
    uint32_t timestamp;
    uint32_t symtab_offset;
    uint32_t num_syms;
    uint16_t opthdr_size;
    uint16_t flags;
} xcoff_header_t;

typedef struct {
    uint16_t magic;
    uint16_t version;
    uint32_t text_size;
    uint32_t data_size;
    uint32_t bss_size;
    uint32_t entry_point;
} xcoff_opt_header_t;

void read_xcoff_header(void *addr) {
    xcoff_header_t *header = (xcoff_header_t *)addr;
    printf("Magic Number: 0x%04X\n", header->magic);
    printf("Number of Sections: %d\n", header->num_sections);
    printf("Timestamp: 0x%08X\n", header->timestamp);
    printf("Symbol Table Offset: 0x%08X\n", header->symtab_offset);
    printf("Number of Symbols: %d\n", header->num_syms);
    printf("Optional Header Size: %d\n", header->opthdr_size);
    printf("Flags: 0x%04X\n", header->flags);
}

void read_xcoff_opt_header(void *addr) {
    xcoff_opt_header_t *opt_header = (xcoff_opt_header_t *)addr;
    printf("Optional Magic Number: 0x%04X\n", opt_header->magic);
    printf("Version Stamp: %d\n", opt_header->version);
    printf("Text Size: 0x%08X\n", opt_header->text_size);
    printf("Data Size: 0x%08X\n", opt_header->data_size);
    printf("BSS Size: 0x%08X\n", opt_header->bss_size);
    printf("Entry Point: 0x%08X\n", opt_header->entry_point);
}

void load_xcoff_sections(void *addr) {
    printf("Loading XCOFF sections...\n");
    // Implement section loading logic here
}

void exec_xcoff(uint32_t entry_point) {
    printf("Executing XCOFF binary at entry point: 0x%08X\n", entry_point);
    // Implement execution logic here
}

Step 4: Update the Makefile​

Finally, we need to update the Makefile to compile the new xcoff-loader.c file and link it with the rest of the SLOF firmware.

Makefile​


Code:
# Add xcoff-loader.c to the list of source files
SOURCES += lib/xcoff-loader.c

# Add the necessary include directories
INCLUDES += -Ilib

# Compile the xcoff-loader.c file
lib/xcoff-loader.o: lib/xcoff-loader.c
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

@joevt we're training an AI, or at least you are, if you have time to look at this code and see if it learned anything. The first two iterations of the code it gave me just broke things a little when I compiled them into SLOF firmware for qemu pseries, but the last one just caused the exception handler to break.

The forth code it gives me I try and test from within the command prompt in SLOF, and some of it works ok after we debug it, but none of it have had the expected results of even loading bootx.xcoff into ram to an address where it can be executed.

It may not be very productive, but I'm actually learning some too, so thanks for your input.
 
Last edited:
To add debug strings to the xcoff-loader.fs file, we can use the ." ..." syntax to print messages at various stages of the loading and execution process. This will help us understand at what stage the process is and where it might fail.

Here is the updated xcoff-loader.fs file with debug strings added:

slof/fs/packages/xcoff-loader.fs​


Code:
\ *****************************************************************************
\ * XCOFF Loader for SLOF
\ * This package loads and executes XCOFF binaries.
\ *****************************************************************************

s" xcoff-loader" device-name
get-node to xcoff-loader

\ Constants for XCOFF header fields
2 CONSTANT XCOFF_MAGIC_OFFSET
2 CONSTANT XCOFF_NUM_SECTIONS_OFFSET
4 CONSTANT XCOFF_TIMESTAMP_OFFSET
4 CONSTANT XCOFF_SYMTAB_OFFSET
4 CONSTANT XCOFF_NUM_SYMS_OFFSET
2 CONSTANT XCOFF_OPTHDR_SIZE_OFFSET
2 CONSTANT XCOFF_FLAGS_OFFSET

\ Constants for XCOFF optional header fields
2 CONSTANT XCOFF_OPT_MAGIC_OFFSET
2 CONSTANT XCOFF_OPT_VERSION_OFFSET
4 CONSTANT XCOFF_OPT_TEXT_SIZE_OFFSET
4 CONSTANT XCOFF_OPT_DATA_SIZE_OFFSET
4 CONSTANT XCOFF_OPT_BSS_SIZE_OFFSET
4 CONSTANT XCOFF_OPT_ENTRY_POINT_OFFSET

\ Constants for XCOFF section header fields
4 CONSTANT XCOFF_SEC_NAME_OFFSET
4 CONSTANT XCOFF_SEC_PADDR_OFFSET
4 CONSTANT XCOFF_SEC_VADDR_OFFSET
4 CONSTANT XCOFF_SEC_SIZE_OFFSET
4 CONSTANT XCOFF_SEC_SCNOFF_OFFSET
4 CONSTANT XCOFF_SEC_RELOFF_OFFSET
4 CONSTANT XCOFF_SEC_LNNOFF_OFFSET
2 CONSTANT XCOFF_SEC_NUMRELOFF_OFFSET
2 CONSTANT XCOFF_SEC_NUMLNNOFF_OFFSET
4 CONSTANT XCOFF_SEC_FLAGS_OFFSET

\ Function to read XCOFF header
: read-xcoff-header ( addr -- )
    ." Reading XCOFF header..." cr
    dup XCOFF_MAGIC_OFFSET + @ . ." Magic Number" cr
    dup XCOFF_NUM_SECTIONS_OFFSET + @ . ." Number of Sections" cr
    dup XCOFF_TIMESTAMP_OFFSET + @ . ." Timestamp" cr
    dup XCOFF_SYMTAB_OFFSET + @ . ." Symbol Table Offset" cr
    dup XCOFF_NUM_SYMS_OFFSET + @ . ." Number of Symbols" cr
    dup XCOFF_OPTHDR_SIZE_OFFSET + @ . ." Optional Header Size" cr
    dup XCOFF_FLAGS_OFFSET + @ . ." Flags" cr
;

\ Function to read XCOFF optional header
: read-xcoff-opt-header ( addr -- )
    ." Reading XCOFF optional header..." cr
    dup XCOFF_OPT_MAGIC_OFFSET + @ . ." Optional Magic Number" cr
    dup XCOFF_OPT_VERSION_OFFSET + @ . ." Version Stamp" cr
    dup XCOFF_OPT_TEXT_SIZE_OFFSET + @ . ." Text Size" cr
    dup XCOFF_OPT_DATA_SIZE_OFFSET + @ . ." Data Size" cr
    dup XCOFF_OPT_BSS_SIZE_OFFSET + @ . ." BSS Size" cr
    dup XCOFF_OPT_ENTRY_POINT_OFFSET + @ . ." Entry Point" cr
;

\ Function to load XCOFF sections
: load-xcoff-sections ( addr -- )
    ." Loading XCOFF sections..." cr
    \ Get the number of sections
    addr XCOFF_NUM_SECTIONS_OFFSET + @
    \ Calculate the address of the first section header
    addr XCOFF_OPTHDR_SIZE_OFFSET + @ addr + 20 + \ 20 is the size of the fixed header
    \ Loop through each section
    0 do
        \ Read section header fields
        ." Reading section header..." cr
        dup XCOFF_SEC_NAME_OFFSET + @ . ." Section Name" cr
        dup XCOFF_SEC_PADDR_OFFSET + @ . ." Physical Address" cr
        dup XCOFF_SEC_VADDR_OFFSET + @ . ." Virtual Address" cr
        dup XCOFF_SEC_SIZE_OFFSET + @ . ." Section Size" cr
        dup XCOFF_SEC_SCNOFF_OFFSET + @ . ." Section Offset" cr
        dup XCOFF_SEC_RELOFF_OFFSET + @ . ." Relocation Offset" cr
        dup XCOFF_SEC_LNNOFF_OFFSET + @ . ." Line Number Offset" cr
        dup XCOFF_SEC_NUMRELOFF_OFFSET + @ . ." Number of Relocation Entries" cr
        dup XCOFF_SEC_NUMLNNOFF_OFFSET + @ . ." Number of Line Number Entries" cr
        dup XCOFF_SEC_FLAGS_OFFSET + @ . ." Flags" cr
        \ Load the section into memory
        ." Loading section into memory..." cr
        dup XCOFF_SEC_SCNOFF_OFFSET + @ swap XCOFF_SEC_PADDR_OFFSET + @ swap XCOFF_SEC_SIZE_OFFSET + @ move
        \ Move to the next section header
        40 + \ 40 is the size of the section header
    loop
;

\ Function to execute XCOFF binary
: exec-xcoff ( entry-point -- )
    ." Executing XCOFF binary at entry point: " . cr
    \ Call the entry point
    execute
;

\ Main function to load and execute XCOFF binary
: load-xcoff ( addr -- )
    ." Starting XCOFF load process..." cr
    read-xcoff-header
    ." XCOFF header read successfully." cr
    read-xcoff-opt-header
    ." XCOFF optional header read successfully." cr
    load-xcoff-sections
    ." XCOFF sections loaded successfully." cr
    XCOFF_OPT_ENTRY_POINT_OFFSET + @ exec-xcoff
    ." XCOFF binary executed successfully." cr
;

finish-device

Explanation​

  1. Debug Strings: Added ." ..." statements to print messages at various stages:
    • Start of the load process.
    • After reading the XCOFF header.
    • After reading the XCOFF optional header.
    • During section loading.
    • After loading all sections.
    • Before executing the binary.
    • After executing the binary.
These debug strings will help you trace the execution flow and identify where any issues might occur.
 
Just a side note for those that maybe reading along, right now I'm just testing SLOF builds in the Qemu pSeries machine with Power9 because it's the closest thing to the Blackbird system and I want to make sure I can load the Mac OS X on that before I put out $3500 on equipment.

I may start adding a Blackbird system board to Qemu at some point, because I'd rather not fry the logic board on the first day.

I think the low level stuff is going to be handled by OpenPower before it hands of control to SLOF, so I don't think there is a great danger of creating a very expensive brick?????

I should be able to debug builds of SLOF on the Blackbird with a J-Link over JTAG.

However if I can't get OS X at least running on one core of the Power9 in Qemu there isn't much point to the project to me, I do run Linux often, but PC hardware is so much cheaper and faster, I could build a hell of a ThreadRipper system for running Linux for less than $3500 and it would likely be at least equal to or better than the 8 core 32 thread power9 for running linux.

I just love PowerPC because I like my Endian BIG or Mixed, but really all the years of video card hacking just makes me want system that run Open Firmware and the macOS is my main productivity tool.

We have all the code and tools needed to extend the functionality of Tiger and Leopard anyway we want, we just need faster hardware, because even the Quad G5 is a 20 year old computer.

My MacBook Pro 13" with the M2 and 16G of RAM is night and day faster at running Qemu than the Dual G5 2.0Ghz. I can't even really test my firmwares on that machine even with --nographic, it's just too slow, but I do the firmware builds on it because I could not find a way to get a working PPC64 cross compiling toolchain on AppleSoC.
 
Don't use ChatGPT. It's not smart. It can't do research or reasoning or logic or math with consistency. What it says in one statement will be contradicted in the next...

If you're posting output from ChatGPT then say so, so we can ignore it or at least not blame you for the incoherent ramblings of a chat bot.

It looks like you want to define an XCOFF header structure in Forth. Based on your description, you want to ensure that the structure is 20 bytes in size. Here is how you can define the XCOFF header structure correctly:
No.

To clarify the usage of go-entry and ensure it is treated as a value rather than a variable, you should define go-entry as a constant. This way, you can directly use it without needing to dereference it.
It proceeds to declare go-entry as a variable, not a constant or a value but at least it dereferences it correctly (even though the intent was to use a value or constant so it doesn't need to be dereferenced).
Is 64K large enough to load BootX? The binary is usually between 100 and 200K.
Why does go-entry point to after the 64K allocation?

Code:
\ Constants for XCOFF header fields
2 CONSTANT XCOFF_MAGIC_OFFSET
2 CONSTANT XCOFF_NUM_SECTIONS_OFFSET
4 CONSTANT XCOFF_TIMESTAMP_OFFSET
4 CONSTANT XCOFF_SYMTAB_OFFSET
4 CONSTANT XCOFF_NUM_SYMS_OFFSET
2 CONSTANT XCOFF_OPTHDR_SIZE_OFFSET
2 CONSTANT XCOFF_FLAGS_OFFSET
Those are defining field sizes, not offsets.
In Open Firmware, field is used to define a field. Fields are preceded by the struct word.
When an Open Firmware field is used, the offset to field is added to the address on the top of the stack.
A struct ends with a constant which represents the size of the struct.
Fields in Apple Open Firmware usually have a name that begins with >

Code:
\ XCOFF header fields
struct
/w field >XCOFF_MAGIC
/w field >XCOFF_NUM_SECTIONS
/l field >XCOFF_TIMESTAMP
/l field >XCOFF_SYMTAB
/l field >XCOFF_NUM_SYMS
/w field >XCOFF_OPTHDR_SIZE
/w field >XCOFF_FLAGS

Check with your Open Firmware implementation that /w = 2 and /l = 4.

Code:
\ Function to read XCOFF header
: read-xcoff-header ( addr -- )
    ." Reading XCOFF header..." cr
    dup XCOFF_MAGIC_OFFSET + @ . ." Magic Number" cr
    dup XCOFF_NUM_SECTIONS_OFFSET + @ . ." Number of Sections" cr
    dup XCOFF_TIMESTAMP_OFFSET + @ . ." Timestamp" cr
    dup XCOFF_SYMTAB_OFFSET + @ . ." Symbol Table Offset" cr
    dup XCOFF_NUM_SYMS_OFFSET + @ . ." Number of Symbols" cr
    dup XCOFF_OPTHDR_SIZE_OFFSET + @ . ." Optional Header Size" cr
    dup XCOFF_FLAGS_OFFSET + @ . ." Flags" cr
;

@ always reads 4 bytes (or whatever the default cell size is) but some of the fields are not 4 bytes. Should use l@ for 4 byte values anyway.
Open Firmware fields include the +
Code:
\ Function to dump XCOFF header
: dump-xcoff-header ( addr -- )
    cr
    ." XCOFF header" cr
    dup >XCOFF_MAGIC w@ . ." Magic Number" cr
    dup >XCOFF_NUM_SECTIONS w@ . ." Number of Sections" cr
    dup >XCOFF_TIMESTAMP l@ . ." Timestamp" cr
    dup >XCOFF_SYMTAB l@ . ." Symbol Table Offset" cr
    dup >XCOFF_NUM_SYMS l@ . ." Number of Symbols" cr
    dup >XCOFF_OPTHDR_SIZE w@ . ." Optional Header Size" cr
    dup >XCOFF_FLAGS w@ . ." Flags" cr
;

We need to implement the C functions that will be called from the Forth code to handle the actual loading and execution of the XCOFF binary. We'll create a new C file called xcoff-loader.c and place it in the lib directory.
Why is C code needed? Can't Open Firmware do the loading like in Apple Open Firmware?

Just a side note for those that maybe reading along, right now I'm just testing SLOF builds in the Qemu pSeries machine with Power9 because it's the closest thing to the Blackbird system and I want to make sure I can load the Mac OS X on that before I put out $3500 on equipment.
Probably need to recompile the Mac OS X kernel after making changes to handle the Power9 CPU. How does Power9 compare to Apple's PowerPC G5 (PowerPC 970, PowerPC 970FX, or PowerPC 970MP)?
 
Last edited:
  • Like
Reactions: Needleroozer
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.