PowerMac 7100 and Linux

joevt

Tinkerer
Mar 5, 2023
130
47
28
I searched my Copland disk image for occurrences of a snippet from the nvramrc and found 7 occurrences.
I mounted the disk image and searched only the HFS partition which also has 7 occurrences which means all occurrences are in the HFS partition.
I take the offsets and divide them by 512 to get block numbers, then use fsck_hfs to get inode numbers.
I mount the disk in Leopard which supports HFS so that I can convert inode numbers to file paths.
Leopard doesn't have the -B option for fsck_hfs.

Code:
# Note grep -b doesn't work well in earlier macOS versions - it gets offset of line instead of occurrences in the line.
grep -a -b -o 'boot-device 2dup drop " /AAPL,ROM" comp if try then' Copland.dmg | perl -pe 's/:.*//'
hdiutil attach -nomount Copland.dmg
grep -a -b -o 'boot-device 2dup drop " /AAPL,ROM" comp if try then' /dev/disk15s9 | perl -pe "s/:.*//" > /tmp/offsets.txt
perl -ne '
    printf("%d ", ($_ / 512));
' /tmp/offsets.txt > /tmp/blocks.txt
fsck_hfs -B /tmp/blocks.txt /dev/disk15s9

# Mount the disk in a version of macOS that supports HFS, such as Leopard
# because FuseHFS does not use HFS inode numbers
diskutil mount disk15s9

GetFileInfo="GetFileInfo"
command -v GetFileInfo > /dev/null 2>&1 || {
    GetFileInfo="/Developer/Tools/GetFileInfo"
}

# Use this to get the volume id of the Copland partition:
stat /Volumes/Copland

# Use this to get the path for a file with volume id/inode number:
"$GetFileInfo" -P "/.vol/234881036/721"

# If it doesn't work then use find:
find /Volumes/Copland -inum 721

# Or use ls:
ls -liR /Volumes/Copland

All the important occurrences seem to be in Mac OS Loader. Here's a list of interesting resources in that file:
Code:
'opfw' (0).                         \ DBOF xcoff for NuBus Macs
'ofpt' (1, "OFPatches").            \ patches for OF not DBOF?
'ofpt' (2, "CONTROL Driver").       \ control
'ofpt' (3, "Platinum Driver").      \ platinum
'ofpt' (4, "Name Registry NVRAM").  \ OF code to load nvram properties into OF?
'ofpt' (128, "auto-boot?").         \ auto-boot? default value?
'ofpt' (129, "use-nvramrc?").       \ use-nvramrc? default value?
'ofpt' (130, "boot-command").       \ boot-command default value for OF?
'ofpt' (131, "load-base").          \ load-base default value?
'ofpt' (4177, "nvramrc").           \ nvramrc for OF not DBOF?
'ofpt' (-15, "nvramrc").            \ nvramrc for DBOF
'ofpt' (-14, "boot-command").       \ boot-command default value for DBOF?
'boot' (1).                         \ default boot block
'nkld' (128).                       \ new kernel loader?
'2ldr' (1, "SecondaryLoader").      \ secondary loader
'nvrm' (0).                         \ DBOF nvram source (modified by above overrides?)

I guess you'll want to look at 'ofpt' (131) and 'nvrm' (0).
load-base and real-base are at a specific offsets in the nvrm.
 

speakers

Tinkerer
Nov 5, 2021
135
91
28
San Jose, CA
peak-weber.net
I searched my Copland disk image for occurrences of a snippet from the nvramrc and found 7 occurrences.
I mounted the disk image and searched only the HFS partition which also has 7 occurrences which means all occurrences are in the HFS partition.
I take the offsets and divide them by 512 to get block numbers, then use fsck_hfs to get inode numbers.
I mount the disk in Leopard which supports HFS so that I can convert inode numbers to file paths.
Leopard doesn't have the -B option for fsck_hfs.
Thanks for this effort. It does seem to show that the Loader constructs nvram in memory from using a number of its resources.
All the important occurrences seem to be in Mac OS Loader. Here's a list of interesting resources in that file:
Code:
'opfw' (0).                         \ DBOF xcoff for NuBus Macs
'ofpt' (1, "OFPatches").            \ patches for OF not DBOF?
'ofpt' (2, "CONTROL Driver").       \ control
'ofpt' (3, "Platinum Driver").      \ platinum
'ofpt' (4, "Name Registry NVRAM").  \ OF code to load nvram properties into OF?
'ofpt' (128, "auto-boot?").         \ auto-boot? default value?
'ofpt' (129, "use-nvramrc?").       \ use-nvramrc? default value?
'ofpt' (130, "boot-command").       \ boot-command default value for OF?
'ofpt' (131, "load-base").          \ load-base default value?
'ofpt' (4177, "nvramrc").           \ nvramrc for OF not DBOF?
'ofpt' (-15, "nvramrc").            \ nvramrc for DBOF
'ofpt' (-14, "boot-command").       \ boot-command default value for DBOF?
'boot' (1).                         \ default boot block
'nkld' (128).                       \ new kernel loader?
'2ldr' (1, "SecondaryLoader").      \ secondary loader
'nvrm' (0).                         \ DBOF nvram source (modified by above overrides?)
I guess you'll want to look at 'ofpt' (131) and 'nvrm' (0).

This is consistent with what I see in ResEdit for the Loader:
Screenshot 2025-07-14 at 9.43.56 AM.png

This is taken from the install kit. I can edit 'auto-boot?' to false, re-install and have it take effect. However, changes to 'load-base' have no effect and 'real-base' is absent.

load-base and real-base are at a specific offsets in the nvrm.

Looking at the Copland Installer, I see the resource 'nvd$':
Screenshot 2025-07-14 at 9.56.03 AM.png

This appears to be a dictionary of OFW variables. Perhaps it's their offsets into the in-memory nvram???

The 'nvrm' resource is 8k of mostly zeroes but with a small chunk containing the values of 'boot-command', 'input-device', 'output-device', 'diag-device' and 'boot-device'. Although after installation it also includes a string starting '" kbd" find-device'.

Note that on my real 7100, I can (using the original subject of this thread) boot Debian to poke in the Copland volume. The tools may be more reliable than Leopard's.
 

joevt

Tinkerer
Mar 5, 2023
130
47
28
This appears to be a dictionary of OFW variables. Perhaps it's their offsets into the in-memory nvram???
Appears to be C strings followed by variable type and bit number or offset (01=boolean, with bit number, 02=number with offset to value, 03=string with offset to string)

So `real-base` is at offset 0x10 in the nvrm resource. It seems to have a value of FFFFFFFF = -1 in the Mac OS Loader resource fork.

You can look at the DingusPPC source code to see the format of the Old World NVRAM variables.

I think New World NVRAM variables use strings for the number types. Look at the DingusPPC source code to be sure.

The string starting with '" kbd" find-device' is for the nvramrc string variable.
 
Last edited:

speakers

Tinkerer
Nov 5, 2021
135
91
28
San Jose, CA
peak-weber.net
I've now confirmed that the nvrm resource of Mac OS Loader can be edited to change the initial value of 'real-base' and 'load-base' variables etc. And it is indeed necessary to update the checksum word (16-bit word offset 2) of the resource.

I use DeRez on OSX to decompile the resource fork of Mac OS Loader to produce a text description file of the nvrm resource. This file can be updated with modified values and a python script used to update the checksum. I could't convince Rez to reconstitute the binary, so I use ResEdit to edit word changes into the active MAc OS Loader image in Mac OS Folder.

However, the Copland DBOF seems intolerant to changes to real-base: only -1 or 0x400000 appear viable :(

And I still can't find a load-base setting to avoid claim failure when loading client code (ofwboot in particulat). I'd like to get a memory map of allocated spaces managed by OFW so I could resolve this.
 

joevt

Tinkerer
Mar 5, 2023
130
47
28
And I still can't find a load-base setting to avoid claim failure when loading client code (ofwboot in particulat). I'd like to get a memory map of allocated spaces managed by OFW so I could resolve this.
You have the Open Firmware code (assembly and Forth) from my dump. You can look at the code to see what's happening. I don't know when real-base and load-base are setup/used - is it before Open Firmware has started (in System 7), or in the Open Firmware init code (Part1.txt) or in Open Firmware (Part2.of)?

The available property in /memory (memory ihandle in /chosen) shows physical RAM addresses that are available.
The available property in the cpu node (mmu ihandle in /chosen) shows virtual addresses that are available.
The translations property in the cpu node has a list of current translations.

The lists of ranges are kept in queues (mem-avail and vert-avail). Here's some code I created for later Open Firmware versions that can dump them.
Code:
: dump-vt { ; q entry }
    cr
    translations dup -> q
    >q.next@ -> entry
    begin
        entry q <>
    while
        entry >vt.virt @ ."  virt:" 8 u.r
        entry >vt.size @ ."  size:" 8 u.r
        entry >vt.phys @ ."  phys:" 8 u.r
        entry >vt.mode @ ."  mode:" 8 u.r
        cr
        entry >q.next@ -> entry
    repeat
    ;

: dump-avail ( q -- ) { q ; entry }
    cr
    q >q.next@ -> entry
    begin
        entry q <>
    while
        entry >fa.addr @ ."  addr:" 8 u.r
        entry >fa.size @ ."  size:" 8 u.r
        cr
        entry >q.next@ -> entry
    repeat
    ;

\ available physical address for RAM \ ra-prop|mem-avail|claim-mem|release-mem
\ words: claim-mem release-mem
\ device: memory ; words: claim = claim-mem, release = release-mem ; properties: available
\ - on initialization, the amount of RAM detected at startup is released.
\ - claims first 16K of RAM for interrupt vectors
\ - used during probing of PCI (with mapping)
mem-avail dump-avail

\ available physical addresses for I/O \ real-avail|claim-real|release-real
\ words: claim-real (for claiming physical addresses for I/O and PCI devices) release-real
\ - on initialization, releases the range 0x80000000..0xFFFFFFFF.
real-avail dump-avail

\ available virtual addresses \ va-prop|virt-avail|claim-virt|release-virt
\ words: claim-virt release-virt
\ device: cpus ; words: claim release ; properties: available
\ device: macparts ; words: map-space (claims mem and virt and maps them)
\ - on initialization, releases ranges 0x0000000..virt_base-1 and virt_base+1MiB..rombase=0ffc00000-1
virt-avail dump-avail

\ translations
\ device: cpu ; properties: translations
dump-vt

mem-avail dump-avail
real-avail dump-avail
virt-avail dump-avail
dump-vt

@startvec contains a list of fields. Many of them point to structures in memory. The following code lists the fields of @startvec and the values for each field:
Code:
\ For Open Firmware 2.4 and earlier, >h.count needs to be changed to 4+ because xt>hdr points to >h.flags instead of >h.link

: dump-fields { addr fcodestart fcodeend ; token ptr }
    cr
    fcodeend 1+ fcodestart do
        i ." 0x" 4 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
        @ -> ptr
        ptr 8 u.r space
        \ check if the field might point to a xt token and if so, output its name
        ptr @startvec u> ptr 7 and 0= and if
            ptr xt>hdr 4+ ( >h.count ) dup c@ + 8 + -8 and ptr = if ptr name. then
        then
        cr
    loop
;

: dump-startvec
    \ Dump all fields of @startvec
    @startvec 48a 4d1 dump-fields ;

dump-startvec

I believe copland @startvec fields have fcode numbers 48a ... 4d1. This will be different in different versions of Open Firmware.

Once you dump the fields and their values, you can sort by values to get a memory map (but some fields are not pointers so you should remove those from the memory map).

Here's an example from a Beige G3 with OF 2.4:
Code:
\=========================================================================================
\ Open Firmware memory map for OF 2.4
\
\ fields marked "\ real" store a real address (change FF8 to 004)

FF800000  >real_base     \ real
FF800000  >virt_base     
FF800400  >dp            
FF800800  >rp            
FF800C00  >lp            
FF801000  >fp            
FF801800  >ep            
FF801C00  >tib           
FF802000  >noname        
FF804000  >ttp           
FF808000  >regsvalid?    
FF808940  >endiango      
FF809D10  >'<sc-int>     \ real
FF809E18  >'cientry      cientry 
FF80A350  >'(poplocals)  (poplocals) 
FF80D0B0  >'ferror       ferror 
FF80D8D0  >'my-self      
FF80F738  >'cold-load    cold-load 
FF811FA0  >'abort        abort 
FF8179A8  >'quit         quit 
FF818350  >'cold-init    _cold-init 
FF819338  >'excp         _exception 
FF819638  >'syscatch     _syscatch 
FF829498  >'cicall       cicall 
FF82A3D0  >ciwords       
FF85D4E8  >word-list     
FF85D524  >here          
FF8D0000  >free-bot      
FF8D6000  >ttp800        
FF8DF600  >intvectv      
FF8DF600  >intvectr      \ real
FF8DF800  >ciregsv       
FF8DF800  >ciregsr       \ real
FF8DFA00  >ofregsv       ^-720600  
FF8DFA00  >ofregsr       \ real
FF8DFC00  >real-vt-hd    \ real
FF8E0000  >free-top      
FF8E0000  >htab          \ real
FF8F0800  >dl-buf
All of these are in the Open Firmware range (1MB virtual address range FF800000 .. FF8FFFFF). Later versions of Open Firmware have larger ranges (up to 3 MB in the latest).

You can convert physical addresses to/from virtual addresses using virt->real[icode] and [icode]real->virt but only for addresses related to virt_base and real_base? Otherwise, you can use the translate method of the mmu ihandle (or use do-translate anywhere) to convert a virtual address to a physical address which will use the translations list.

Since we can dump most of the Open Firmware DBOF, we can also modify it using a reverse process (may need to update some fields in @startvec which has default values in the beginning of DBOF). The Forth fcode tokenizer needs to be updated to handle some Apple Open Firmware features.