2022-08-22 06:49:18 +00:00
# Open Firmware in Power Macintosh
2020-03-07 22:40:46 +00:00
2021-08-07 14:00:56 +00:00
*compiled from various sources by Max Poliakovski.*
2020-03-01 17:58:09 +00:00
2021-08-07 14:00:56 +00:00
[Open Firmware ](https://en.wikipedia.org/wiki/Open_Firmware ) is a platform-independent
boot firmware architecture covered by an IEEE standard.
2020-03-01 17:58:09 +00:00
2023-12-03 09:12:37 +00:00
All Power Macintosh computers run Open Firmware except the very first generation
2021-08-07 14:00:56 +00:00
that uses [Nubus ](https://en.wikipedia.org/wiki/NuBus ) instead of
[PCI ](https://en.wikipedia.org/wiki/Peripheral_Component_Interconnect ).
2020-03-07 22:40:46 +00:00
2022-08-22 06:49:18 +00:00
Open Firmware is used to perform hardware identification and initialization during
2021-08-07 14:00:56 +00:00
the booting process after power-on. It also provides a platform-independent
description of the attached devices available for operating systems.
2022-08-22 06:49:18 +00:00
In this respect, Open Firmware can be compared with [BIOS ](https://en.wikipedia.org/wiki/BIOS ),
2021-08-07 14:00:56 +00:00
widely used in the PC world.
Being based upon the [Forth programming language ](https://en.wikipedia.org/wiki/Forth_(programming_language )),
2022-08-22 06:49:18 +00:00
Open Firmware offers an operating system, an interactive environment as well as a
2021-08-07 14:00:56 +00:00
programming language in one package. Its shell can be used as well by users for
controlling the boot enviroment as by developers for developing and debugging device
drivers.
2022-08-22 06:49:18 +00:00
This document focuses on various aspects of Apple's Open Firmware implementation
2023-12-03 09:12:37 +00:00
as found in various Power Macintosh models.
2021-08-07 14:00:56 +00:00
2022-08-22 06:49:18 +00:00
## Open Firmware Versions
2021-08-07 14:00:56 +00:00
### Old World Macs
2021-11-29 21:35:12 +00:00
| ROM dump/Machine | BootROM codename | OF version | OF image offset |
2021-08-07 20:19:25 +00:00
|:------------------------------------:|:----------------:|:-------------:|:---------------:|
2021-08-07 14:00:56 +00:00
| Power Macintosh 7300/7600/8600/9600 | TNT | 1.0.5 | 0x330000 |
| Bandai Pippin | Pip | 1.0.5 | 0x330000 |
2021-08-07 20:19:25 +00:00
| Power Macintosh,Performa 6400 | Alchemy | 2.0 | 0x330000 |
2021-08-07 14:00:56 +00:00
| Power Macintosh G3 desktop | Gossamer | 2.0f1 | 0x320000 |
| PowerBook G3 Wallstreet v2 | GRX | 2.0.1 | 0x330000 |
| Power Macintosh 4400/7220 | Zanzibar | 2.0.2 | 0x330000 |
| Power Macintosh 6500 | Gazelle | 2.0.3 | 0x330000 |
| Power Macintosh G3 v3 | Gossamer | 2.4 | 0x320000 |
### NewWorld Macs
*TBD*
2022-08-22 06:49:18 +00:00
## Open Firmware image
2021-08-07 14:00:56 +00:00
### Old World Macs
2022-08-22 06:49:18 +00:00
Open Firmware in OldWorld Macs is stored in the monolithic 4MB ROM. Its hibernated
2021-08-07 14:00:56 +00:00
image is located at offset `0x320000` or `0x330000` from beginning of the ROM.
That corresponds to the physical address `0xFFF20000` or `0xFFF30000` , respectively.
2022-08-22 06:49:18 +00:00
The size of the Open Firmware image varies from 98KB (v1.0.5) to 172KB (v2.4).
2021-08-07 14:00:56 +00:00
2022-08-22 06:49:18 +00:00
Apple's Open Firmware image has the following structure:
2021-08-07 14:00:56 +00:00
| Section type | Architecture | Relative Size (v1.0.5) | Relative Size (v2.4) |
|:------------------:|:------------:|:----------------------:|:--------------------:|
| OF kernel | PowerPC | 26% | 18% |
| OF main code | FCode | 62% | 51% |
| OF device packages | FCode | 12% | 31% |
OF image is wrapped in the COFF container. At the start of the image, a COFF file
header and a section header are located. The following example parses the COFF
headers of the OF image from the Gossamer ROM v3:
```
org 0xFFF20000
; OF COFF file header
dc.w 0x1DF ; COFF magic
dc.w 1 ; number of sections
dc.l 'Gary' ; Gary Davidian's signature replaces time and date
dc.l 0 ; ptr to the symbol table
dc.l 0 ; number of entries in the symbol table
dc.w 0 ; size of the optional header
dc.w 0 ; flags
; OF COFF section header
dc.b '.text', 0, 0, 0 ; section name
dc.l 0 ; physical address
dc.l 0 ; virtual address
dc.l 0x2ADB0 ; section size in bytes (= 171KB)
dc.l 0x3C ; file offset to section data
dc.l 0 ; file offset to section relocations
dc.l 0 ; file offset to line number entries
dc.w 0 ; number of relocation entries
dc.w 0 ; number of line number entries
dc.l 0x20 ; section flags (this section contains executable code)
```
Right after the COFF section header, a vital OF kernel data structure called `StartVec`
is located. It contains among others several important offsets into the OF image
for finding all required OF parts. That's also the location HWInit passes control
to when invoking OF:
```
org 0xFFF2003C
; OF execution starts here
mflr r11 ; save return address to HWInit in R11
bl OF_kernel_start ; pass control to OF kernel
; LR will contain physical address of StartVec
; Begin of StartVec structure
; All offsets are from the beginning of the .text section (0xFFF2003C)
FFF20044 dc.l 0x7918 ; offset to the FCode stream of the OF main package
...
FFF2007C dc.l 0x28C48 ; offset to the last driver in the device packages
...
FFF20084 dc.l 0x7720 ; offset to the last Forth word descriptor of the kernel
```
2022-08-22 07:39:08 +00:00
This StartVec structure in ROM is not to be confused with the `@startvec` structure in RAM.
Open Firmware 2.4 lists the fields of `@startvec` :
```
0x48D 0008 FF808008 >imagesize 00000000
0x48E 000C FF80800C >'cold2 00000000
0x48F 0010 FF808010 >'map-page 00000000
0x490 0014 FF808014 >'map-io 00000000
0x491 0018 FF808018 >endiango FF808940
0x492 001C FF80801C >little? 00000000
0x493 0020 FF808020 >swizzle? 00000000
0x494 0024 FF808024 >real? 00000000
0x495 0028 FF808028 >rom-base FFF2003C
0x496 002C FF80802C >real_base 00400000
0x497 0030 FF808030 >virt_base FF800000
0x498 0034 FF808034 >real-vt-hd 004DFC00
0x499 0038 FF808038 >restart FFF201DC
0x49A 003C FF80803C >fcimage FFF27954
0x49B 0040 FF808040 >fcfiles FFF48C84
0x49C 0044 FF808044 >lasttoken 00000EB5
0x49D 0048 FF808048 >word-list FF85D4E8
0x49E 004C FF80804C >'ferror FF80D0B0 ferror
0x49F 0050 FF808050 >'(poplocals) FF80A350 (poplocals)
0x4A0 0054 FF808054 >'cold-load FF80F738 cold-load
0x4A1 0058 FF808058 >'cold-init FF818350 _cold-init
0x4A2 005C FF80805C >'quit FF8179A8 quit
0x4A3 0060 FF808060 >'abort FF811FA0 abort
0x4A4 0064 FF808064 >'syscatch FF819638 _syscatch
0x4A5 0068 FF808068 >'excp FF819338 _exception
0x4A6 006C FF80806C >'bp-done 00000000
0x4A7 0070 FF808070 >'step-done 00000000
0x4A8 0074 FF808074 >'mini-nub 00000000
0x4A9 0078 FF808078 >hwinitlr FFF04D50
0x4AA 007C FF80807C >hwinitiv 00000000
0x4AB 0080 FF808080 >hwinit3 00009000
0x4AC 0084 FF808084 >hwinit4 00009120
0x4AD 0088 FF808088 >hwinit8 FFF03058
0x4AE 008C FF80808C >hwinit9 F3060000
0x4AF 0090 FF808090 >sccac F3013020
0x4B0 0094 FF808094 >sccad F3013030
0x4B1 0098 FF808098 >ramsize 30000000
0x4B2 009C FF80809C >cpuclock 0DF092B0
0x4B3 00A0 FF8080A0 >busclock 03FB97A0
0x4B4 00A4 FF8080A4 >tbclock 00FEE5E8
0x4B5 00A8 FF8080A8 >here FF85D524
0x4B6 00AC FF8080AC >free-top FF8E0000
0x4B7 00B0 FF8080B0 >free-bot FF8D0000
0x4B8 00B4 FF8080B4 >#dsi-ints 00000000
0x4B9 00B8 FF8080B8 >#isi-ints 00000000
0x4BA 00BC FF8080BC >dl-buf FF8F0800
0x4BB 00C0 FF8080C0 >ttp800 FF8D6000
0x4BC 00C4 FF8080C4 >'cientry FF809E18 cientry
0x4BD 00C8 FF8080C8 >'cicall FF829498 cicall
0x4BE 00CC FF8080CC >'my-self FF80D8D0
0x4BF 00D0 FF8080D0 >'< sc-int > 00409D10
0x4C0 00D4 FF8080D4 >ofregsv FF8DFA00 ^-720600
0x4C1 00D8 FF8080D8 >ciregsv FF8DF800
0x4C2 00DC FF8080DC >ofregsr 004DFA00
0x4C3 00E0 FF8080E0 >ciregsr 004DF800
0x4C4 00E4 FF8080E4 >intvectv FF8DF600
0x4C5 00E8 FF8080E8 >intvectr 004DF600
0x4C6 00EC FF8080EC >regsvalid? FF808000
0x4C7 00F0 FF8080F0 >ciwords FF82A3D0
0x4C8 00F4 FF8080F4 >htab 004E0000
0x4C9 00F8 FF8080F8 >keepbat2? 00000000
0x4CA 00FC FF8080FC >keepbat3? 00000000
0x4CB 0100 FF808100 >rp FF800800
0x4CC 0104 FF808104 >dp FF800400
0x4CD 0108 FF808108 >fp FF801000
0x4CE 010C FF80810C >lp FF800C00
0x4CF 0110 FF808110 >ep FF801800
0x4D0 0114 FF808114 >ttp FF804000
0x4D1 0118 FF808118 >tib FF801C00
0x4D2 011C FF80811C >noname FF802000
0x4D3 0120 FF808120 >dec-ints 00000000
0x4D4 0124 FF808124 >dec-msec 00004141
0x4D5 0128 FF808128 >r13-31 FFF03078
```
The above is produced by this:
```
: dump_fields { addr fcodestart fcodeend ; token }
cr fcodeend 1+ fcodestart do
i ." 0x" 3 u.r space
i get-token drop -> token
0 token execute 4 u.r space
addr token execute dup 8 u.r space
token name.
#out @ d# 42 < if d # 42 #out @ - spaces then
@ dup 8 u.r space
\ check if the field might point to a xt token and if so, output its name
dup @startvec u> if
dup dup xt>hdr 4+ dup c@ + 8 + -8 and = if name. else drop then
else drop then
cr
loop
;
: dumpstartvec
2023-10-30 23:46:21 +00:00
@startvec 48d 4d5 dump_fields ;
2022-08-22 07:39:08 +00:00
dumpstartvec
```
2021-08-07 14:00:56 +00:00
2022-08-22 06:49:18 +00:00
### Open Firmware internals
Apple's Open Firmware contains a small kernel implemented in the native PowerPC code. This kernel performs the following actions:
2021-08-07 14:00:56 +00:00
* set up memory translation for OF execution
* relocate itself from ROM to RAM
* initialize Forth runtime environment
* recompile OF main image from FCode to native PPC code
* pass control to recompiled OF that starts building the device tree
* process low-level exceptions
2022-08-22 06:49:18 +00:00
## Open Firmware and the Macintosh boot process
2021-08-07 14:00:56 +00:00
### Old World Macs
1. In response to power coming on, HWInit code in the Power Macintosh ROM performs initialization of the memory controller and the basic I/O facilities as well as some self-testing. After that, the startup chime is played.
2022-08-22 06:49:18 +00:00
2. HWInit passes control to Open Firmware kernel that prepares OF execution from RAM. OF builds the **device tree** - a platform-independent description of the attached HW.
2021-08-07 14:00:56 +00:00
3. OF returns control to HWInit that initializes several low-level data structures required by the Nanokernel.
2021-11-29 21:35:12 +00:00
4. HWInit passes control to the Nanokernel that initializes the native execution enviroment and the 68k emulator.
2021-08-07 14:00:56 +00:00
5. 68k emulator executes the start-up code in the Macintosh ROM that initializes various managers.
2022-08-22 06:49:18 +00:00
6. The device tree generated by the Open Firmware in step 2 is imported by the Expansion Bus Manager initialization code and stored in the **NameRegistry** .
2021-08-07 14:00:56 +00:00
7. An operating system is located and loaded.
### New World Macs
*TBD*
2022-08-22 06:49:18 +00:00
## Open Firmware bugs
2021-08-07 14:00:56 +00:00
Apple OF is known to contain numerous bugs. The following table lists some recently discrovered bugs, not mentioned elsewhere.
| OF version affected | Bug description |
|:-------------------:|-----------------|
2021-08-07 20:26:27 +00:00
| 2.0f1, 2.4 | A numerical overflow in `um/mod` used by `get-usecs-60x` causes the OF console to become unresponsive after approx. 71 minutes. You have to restart your computer once the bug is triggered. |
2022-08-22 07:44:12 +00:00
| 1.0.5 | /chaos/control `fill-rectangle` is ( ? color y x w h -- ) instead of ( color x y w h -- ) |
2023-10-30 23:47:15 +00:00
| | `$find` is ( name-str name-len -- xt true | pstr name-str name-len false ) instead of ( name-str name-len -- xt true | name-str name-len false ) |
2022-08-22 07:44:12 +00:00
| 2.4 | string literal buffers `"` on the command line are 256 bytes but will overflow if you enter more than 256 bytes. |
2022-08-22 07:45:28 +00:00
`get-inherited-property notes.txt` discusses known bugs regarding get-inherited-property and map-in in Open Firmware 1.0.5.