├── .gitignore
├── bin
└── .gitignore
├── proof.jpg
├── kpartx.sh
├── boot.tbxi
├── bootinfo.txt
├── hfs.map
├── README.md
├── src
├── ofwmagic.s
└── main.c
└── Makefile
/.gitignore:
--------------------------------------------------------------------------------
1 | dmg_mount/*
2 |
--------------------------------------------------------------------------------
/bin/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.dmg
3 | *.iso
4 | *.img
5 | *.elf
6 |
--------------------------------------------------------------------------------
/proof.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rndtrash/ppc-experiments/master/proof.jpg
--------------------------------------------------------------------------------
/kpartx.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo mkfs.hfsplus -v Hellorld bin/hellorld.dmg
3 | LOOP=$(sudo kpartx -s -a -v bin/hellorld.dmg | awk -F'[ ]' '{print $3}' | tail -n1 )
4 | sudo mount -o loop /dev/mapper/$LOOP ./dmg_mount/
5 |
--------------------------------------------------------------------------------
/boot.tbxi:
--------------------------------------------------------------------------------
1 |
2 | Hellorld!
3 | Hellorld
4 | 1
5 |
6 | MacRISC MacRISC3 MacRISC4
7 |
8 |
9 | " screen" output
10 | boot &device;:&partition;,\ppc\boot.elf
11 |
12 |
13 |
--------------------------------------------------------------------------------
/bootinfo.txt:
--------------------------------------------------------------------------------
1 |
2 | Hellorld!
3 | Hellorld
4 | 1
5 |
6 | MacRISC MacRISC3 MacRISC4
7 |
8 |
9 | " screen" output
10 | boot &device;:&partition;,\ppc\boot.elf
11 |
12 |
13 |
--------------------------------------------------------------------------------
/hfs.map:
--------------------------------------------------------------------------------
1 | # ext. xlate creator type comment
2 | .hqx Ascii 'BnHx' 'TEXT' "BinHex file"
3 | .sit Raw 'SIT!' 'SITD' "StuffIT Expander"
4 | .mov Raw 'TVOD' 'MooV' "QuickTime Movie"
5 | .deb Raw 'Debn' 'bina' "Debian package"
6 | .bin Raw 'ddsk' 'DDim' "Floppy or ramdisk image"
7 | .img Raw 'ddsk' 'DDim' "Floppy or ramdisk image"
8 | .b Raw 'UNIX' 'tbxi' "bootstrap"
9 | .elf Raw 'UNIX' 'boot' "bootstrap"
10 | vmlinux Raw 'UNIX' 'boot' "bootstrap"
11 | .conf Raw 'UNIX' 'conf' "bootstrap"
12 | .tbxi Raw 'UNIX' 'conf' "bootstrap"
13 | * Ascii '????' '????' "Text file"
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hellorld Open Firmware
2 |
3 | 
4 |
5 | Inspired by [thamugadi/powerpc-ofw-boot](https://github.com/thamugadi/powerpc-ofw-boot)
6 |
7 | # Building
8 |
9 | 1. Install kpartx, hfsplus tools with mkfs.hfsplus program and GCC with Binutils for PPC
10 | 2. Run `make`
11 |
12 | # To all the rights owners
13 |
14 | At this point, I'm just kit-bashing random snippets from the Internet,
15 | so please forgive me if I stole your code. I promise to replace it
16 | with the original code as soon as I get this thing working.
17 |
18 | Thank you for your understanding.
19 |
20 | # Links
21 |
22 | - [Mac OS X Internals: A Systems Approach, Section 4.10. BootX](https://flylib.com/books/en/3.126.1.47/1/)
23 | - [The BootX source code](https://github.com/apple-oss-distributions/BootX/)
24 | - [OpenBIOS source code](https://github.com/openbios/openbios/)
25 | - [NetBSD ofwboot for MacPPC source code](https://github.com/NetBSD/src/blob/master/sys/arch/macppc/stand/ofwboot/Makefile)
26 |
--------------------------------------------------------------------------------
/src/ofwmagic.s:
--------------------------------------------------------------------------------
1 | .section ".note","",@note
2 |
3 | # note header
4 |
5 | # length of name
6 | .long 8
7 |
8 | # note descriptor size
9 | .long 24
10 |
11 | # note type (IEEE 1275)
12 | .long 0x1275
13 |
14 | # name of owner
15 | .asciz "PowerPC"
16 | .balign 4
17 |
18 |
19 | # note descriptor
20 |
21 | # real mode (-1) or virtual mode (0)
22 | .long 0
23 |
24 | # real-base
25 | .long -1
26 | # real-size
27 | .long -1
28 |
29 | # virt-base
30 | .long -1
31 | # virt-size
32 | .long -1
33 | # load-base
34 | .long 0x4000
35 |
36 | # second note is for IBM LPARs
37 | # length of name
38 | .long 24
39 | # note descriptor size
40 | .long 28
41 | # note type
42 | .long 0x12759999
43 | # name of owner
44 | .asciz "IBM,RPA-Client-Config"
45 | .balign 4
46 |
47 | # lpar affinity
48 | .long 0
49 | # minimum size in megabytes
50 | .long 64
51 | # minimum percentage size
52 | .long 0
53 | # max pft size ( 2^48 bytes )
54 | .long 48
55 | # splpar
56 | .long 1
57 | # min load ?
58 | .long -1
59 | # new mem def ?
60 | .long 0
61 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SOURCES_C := src/main.c
2 | SOURCES_AS := src/ofwmagic.s
3 | OBJECTS := $(SOURCES_C:src/%.c=bin/%.c.o) $(SOURCES_AS:src/%.s=bin/%.s.o)
4 |
5 | RELOC := E00000
6 |
7 | CFLAGS := -target powerpc-none-eabi -static -msoft-float -ffreestanding
8 | ASFLAGS := -filetype=obj --arch=ppc32
9 | LDFLAGS := -N --Bstatic -nostdlib -e _start -Ttext ${RELOC} -v
10 |
11 | .PHONY: clean qemu
12 |
13 | all: bin/hellorld.iso
14 |
15 | bin/hellorld.iso: bin/boot.elf boot.tbxi bootinfo.txt hfs.map
16 | #dd if=/dev/zero of=bin/hellorld.dmg bs=1M count=16 status=progress
17 | ##parted bin/hellorld.dmg --script mklabel mac mkpart primary hfs 2048s 100%
18 | #mkdir -p dmg_mount
19 | ##sudo ./kpartx.sh
20 | #sudo mkfs.hfs -v Hellorld bin/hellorld.dmg
21 | #sudo mount -o loop bin/hellorld.dmg ./dmg_mount/
22 | #sudo mkdir -p ./dmg_mount/ppc
23 | #sudo cp bootinfo.txt ./dmg_mount/ppc
24 | #sudo cp bin/boot.elf ./dmg_mount/ppc
25 | #sudo umount ./dmg_mount/
26 | #sudo kpartx -d bin/hellorld.dmg
27 | mkdir -p ./dmg_mount/ppc
28 | cp bootinfo.txt boot.tbxi bin/boot.elf ./dmg_mount/ppc
29 | genisoimage \
30 | -joliet-long -r \
31 | -V 'Hellorld' \
32 | -o bin/hellorld.iso \
33 | --iso-level 4 \
34 | --netatalk -hfs -probe \
35 | -map hfs.map \
36 | -hfs-parms MAX_XTCSIZE=2656248 \
37 | --chrp-boot \
38 | -part -no-desktop \
39 | -hfs-bless ppc \
40 | -hfs-volid Hellorld_boot \
41 | ./dmg_mount/
42 |
43 |
44 | bin/boot.elf: $(OBJECTS)
45 | ld.lld $(OBJECTS) $(LDFLAGS) -o bin/boot.elf
46 |
47 | bin/%.c.o: src/%.c Makefile
48 | clang $< $(CFLAGS) -c -o $@
49 |
50 | bin/%.s.o: src/%.s Makefile
51 | llvm-mc $< $(ASFLAGS) -o $@
52 |
53 | clean:
54 | rm -f bin/hellorld.dmg
55 | rm -f bin/*.o
56 |
57 | qemu: bin/hellorld.iso
58 | qemu-system-ppc -L openbios-ppc -boot d -M mac99 -m 256 -cdrom bin/hellorld.iso -device VGA,edid=on
59 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | static int stack[8192/4 + 4] __attribute__((__used__));
2 |
3 | typedef long CICell;
4 |
5 | struct CIArgs {
6 | char *service;
7 | CICell nArgs;
8 | CICell nReturns;
9 |
10 | union {
11 | struct { // nArgs=1 + args, nReturns=1 + rets
12 | const char *forth;
13 | CICell cells[6 + 1 + 6];
14 | } interpret;
15 |
16 | struct { // nArgs=2 + args, nReturns=1 + rets
17 | const char *method;
18 | CICell iHandle;
19 | CICell cells[6 + 1 + 6];
20 | } callMethod;
21 |
22 | struct { // nArgs=1, nReturns=1 ( device-specifier -- ihandle )
23 | char *devSpec; // IN parameter
24 | CICell ihandle; // RETURN value
25 | } open;
26 |
27 | struct { // nArgs=1, nReturns=0 ( ihandle -- )
28 | CICell ihandle; // IN parameter
29 | } close;
30 |
31 | struct { // nArgs=3, nReturns=1 ( ihandle addr length -- actual )
32 | CICell ihandle;
33 | CICell addr;
34 | CICell length;
35 | CICell actual;
36 | } read;
37 |
38 | struct { // nArgs=3, nReturns=1 ( ihandle addr length -- actual )
39 | CICell ihandle;
40 | CICell addr;
41 | CICell length;
42 | CICell actual;
43 | } write;
44 |
45 | struct { // nArgs=3, nReturns=1 ( ihandle pos.high pos.low -- result )
46 | CICell ihandle;
47 | CICell pos_high;
48 | CICell pos_low;
49 | CICell result;
50 | } seek;
51 |
52 | struct { // nArgs=3, nReturns=1
53 | CICell virt;
54 | CICell size;
55 | CICell align;
56 | CICell baseaddr;
57 | } claim;
58 |
59 | struct { // nArgs=2, nReturns=0
60 | CICell virt;
61 | CICell size;
62 | } release;
63 |
64 | struct { // nArgs=1, nReturns=1 ( phandle -- peer-phandle )
65 | CICell phandle; // IN parameter
66 | CICell peerPhandle; // RETURN value
67 | } peer;
68 |
69 | struct { // nArgs=1, nReturns=1 ( phandle -- child-phandle )
70 | CICell phandle; // IN parameter
71 | CICell childPhandle; // RETURN value
72 | } child;
73 |
74 | struct { // nArgs=1, nReturns=1 ( phandle -- parent-phandle )
75 | CICell childPhandle; // IN parameter
76 | CICell parentPhandle; // RETURN value
77 | } parent;
78 |
79 | struct { // nArgs=1, nReturns=1 ( devSpec -- phandle )
80 | char *devSpec; // IN parameter
81 | CICell phandle; // RETURN value
82 | } finddevice;
83 |
84 | struct { // nArgs=3, nReturns=1 ( ihandle buf buflen -- length )
85 | CICell ihandle; // IN ihandle
86 | char *buf; // IN buf
87 | CICell buflen; // IN buflen
88 | CICell length; // RETURN length
89 | } instanceToPath;
90 |
91 | struct { // nArgs=1, nReturns=1 ( ihandle -- phandle )
92 | CICell ihandle; // IN ihandle
93 | CICell phandle; // RETURN phandle
94 | } instanceToPackage;
95 |
96 | struct { // nArgs=3, nReturns=1 ( phandle buf buflen -- length )
97 | CICell phandle; // IN phandle
98 | char *buf; // IN buf
99 | CICell buflen; // IN buflen
100 | CICell length; // RETURN length
101 | } packageToPath;
102 |
103 | struct { // nArgs=2, nReturns=1 ( phandle name -- size )
104 | CICell phandle; // IN parameter
105 | char *name; // IN parameter
106 | CICell size; // RETURN value
107 | } getproplen;
108 |
109 | struct { // nArgs=4, nReturns=1 ( phandle name buf buflen -- size )
110 | CICell phandle; // IN parameter
111 | char *name; // IN parameter
112 | char *buf; // IN parameter
113 | CICell buflen; // IN parameter
114 | CICell size; // RETURN value
115 | } getprop;
116 |
117 | struct { // nArgs=3, nReturns=1 ( phandle previous buf -- flag )
118 | CICell phandle; // IN parameter
119 | char *previous; // IN parameter
120 | char *buf; // IN parameter
121 | CICell flag; // RETURN value
122 | } nextprop;
123 |
124 | struct { // nArgs=4, nReturns=1 ( phandle name buf buflen -- size )
125 | CICell phandle; // IN parameter
126 | char *name; // IN parameter
127 | char *buf; // IN parameter
128 | CICell buflen; // IN parameter
129 | CICell size; // RETURN value
130 | } setprop;
131 |
132 | struct { // nArgs=1, nReturns=0
133 | char *bootspec;
134 | } boot;
135 | } args;
136 | };
137 | typedef struct CIArgs CIArgs;
138 |
139 | typedef long (*ClientInterfacePtr)(CIArgs *args);
140 |
141 | ClientInterfacePtr gClientInterface;
142 |
143 | static void main();
144 | void startup(void *vpd, int res, ClientInterfacePtr openfirm, char *arg, int argl);
145 |
146 | __asm(
147 | " .text \n"
148 | " .globl _start \n"
149 | "_start: \n"
150 | " sync \n"
151 | " isync \n"
152 | " lis %r1,stack@ha \n"
153 | " addi %r1,%r1,stack@l \n"
154 | " addi %r1,%r1,8192 \n"
155 | " \n"
156 | " mfmsr %r8 \n"
157 | " li %r0,0 \n"
158 | " mtmsr %r0 \n"
159 | " isync \n"
160 | " \n"
161 | " \n" /* test for 601 */
162 | " mfspr %r0,287 \n" /* mfpvbr %r0 PVR = 287 */
163 | " srwi %r0,%r0,0x10 \n"
164 | " cmplwi %r0,0x02 \n" /* 601 CPU = 0x0001 */
165 | " blt 2f \n" /* skip over non-601 BAT setup */
166 | " cmplwi %r0,0x39 \n" /* PPC970 */
167 | " blt 0f \n"
168 | " cmplwi %r0,0x45 \n" /* PPC970GX */
169 | " ble 1f \n"
170 | /* non PPC 601 BATs */
171 | "0: li %r0,0 \n"
172 | " mtibatu 0,%r0 \n"
173 | " mtibatu 1,%r0 \n"
174 | " mtibatu 2,%r0 \n"
175 | " mtibatu 3,%r0 \n"
176 | " mtdbatu 0,%r0 \n"
177 | " mtdbatu 1,%r0 \n"
178 | " mtdbatu 2,%r0 \n"
179 | " mtdbatu 3,%r0 \n"
180 | " \n"
181 | " li %r9,0x12 \n" /* BATL(0, BAT_M, BAT_PP_RW) */
182 | " mtibatl 0,%r9 \n"
183 | " mtdbatl 0,%r9 \n"
184 | " li %r9,0x1ffe \n" /* BATU(0, BAT_BL_256M, BAT_Vs) */
185 | " mtibatu 0,%r9 \n"
186 | " mtdbatu 0,%r9 \n"
187 | " b 3f \n"
188 | /* 970 initialization stuff */
189 | "1: \n"
190 | /* make sure we're in bridge mode */
191 | " clrldi %r8,%r8,3 \n"
192 | " mtmsrd %r8 \n"
193 | " isync \n"
194 | /* clear HID5 DCBZ bits (56/57), need to do this early */
195 | " mfspr %r9,0x3f6 \n"
196 | " rldimi %r9,0,6,56 \n"
197 | " sync \n"
198 | " mtspr 0x3f6,%r9 \n"
199 | " isync \n"
200 | " sync \n"
201 | /* Setup HID1 features, prefetch + i-cacheability controlled by PTE */
202 | " mfspr %r9,0x3f1 \n"
203 | " li %r11,0x1200 \n"
204 | " sldi %r11,%r11,44 \n"
205 | " or %r9,%r9,%r11 \n"
206 | " mtspr 0x3f1,%r9 \n"
207 | " isync \n"
208 | " sync \n"
209 | " b 3f \n"
210 | /* PPC 601 BATs */
211 | "2: li %r0,0 \n"
212 | " mtibatu 0,%r0 \n"
213 | " mtibatu 1,%r0 \n"
214 | " mtibatu 2,%r0 \n"
215 | " mtibatu 3,%r0 \n"
216 | " \n"
217 | " li %r9,0x7f \n"
218 | " mtibatl 0,%r9 \n"
219 | " li %r9,0x1a \n"
220 | " mtibatu 0,%r9 \n"
221 | " \n"
222 | " lis %r9,0x80 \n"
223 | " addi %r9,%r9,0x7f \n"
224 | " mtibatl 1,%r9 \n"
225 | " lis %r9,0x80 \n"
226 | " addi %r9,%r9,0x1a \n"
227 | " mtibatu 1,%r9 \n"
228 | " \n"
229 | " lis %r9,0x100 \n"
230 | " addi %r9,%r9,0x7f \n"
231 | " mtibatl 2,%r9 \n"
232 | " lis %r9,0x100 \n"
233 | " addi %r9,%r9,0x1a \n"
234 | " mtibatu 2,%r9 \n"
235 | " \n"
236 | " lis %r9,0x180 \n"
237 | " addi %r9,%r9,0x7f \n"
238 | " mtibatl 3,%r9 \n"
239 | " lis %r9,0x180 \n"
240 | " addi %r9,%r9,0x1a \n"
241 | " mtibatu 3,%r9 \n"
242 | " \n"
243 | "3: isync \n"
244 | " \n"
245 | " mtmsr %r8 \n"
246 | " isync \n"
247 | " \n"
248 | /*
249 | * Make sure that .bss is zeroed
250 | */
251 | " \n"
252 | " li %r0,0 \n"
253 | " lis %r8,_edata@ha \n"
254 | " addi %r8,%r8,_edata@l\n"
255 | " lis %r9,_end@ha \n"
256 | " addi %r9,%r9,_end@l \n"
257 | " \n"
258 | "5: cmpw 0,%r8,%r9 \n"
259 | " bge 6f \n"
260 | /*
261 | * clear by bytes to avoid ppc601 alignment exceptions
262 | */
263 | " stb %r0,0(%r8) \n"
264 | " stb %r0,1(%r8) \n"
265 | " stb %r0,2(%r8) \n"
266 | " stb %r0,3(%r8) \n"
267 | " addi %r8,%r8,4 \n"
268 | " b 5b \n"
269 | " \n"
270 | "6: b startup \n"
271 | );
272 |
273 | void startup(void *vpd, int res, ClientInterfacePtr openfirm, char *arg, int argl)
274 | {
275 | (void) vpd;
276 | (void) res;
277 | (void) arg;
278 | (void) argl;
279 | gClientInterface = openfirm;
280 | //setup();
281 | main();
282 | //OF_exit();
283 | }
284 |
285 | static void main() // __section(".text")
286 | {
287 | //gClientInterface = ciPtr;
288 |
289 | CIArgs args;
290 | args.service = "interpret";
291 | args.nArgs = 1;
292 | args.nReturns = 1;
293 | args.args.interpret.forth = ".( Hellorld!)";
294 |
295 | long ret = (*gClientInterface)(&args);
296 | (void) ret;
297 |
298 | do {} while(1);
299 | }
300 |
--------------------------------------------------------------------------------