1 /*        $NetBSD: bootxx.c,v 1.21 2020/01/23 17:23:03 uwe Exp $      */
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *        This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/types.h>
35 #include <powerpc/oea/bat.h>
36 #include <powerpc/oea/spr.h>
37 
38 #include <sys/bootblock.h>
39 
40 int (*openfirmware)(void *);
41 
42                                         /*
43                                          * 32 KB of stack with 32 bytes overpad
44                                          * (see below)
45                                          */
46 int32_t __attribute__((aligned(16))) stack[8192 + 8];
47 
48 struct shared_bbinfo bbinfo = {
49           { MACPPC_BBINFO_MAGIC },
50           0,
51           SHARED_BBINFO_MAXBLOCKS,
52           { 0 }
53 };
54 
55 #ifndef DEFAULT_ENTRY_POINT
56 #define   DEFAULT_ENTRY_POINT 0xE00000
57 #endif
58 
59 void (*entry_point)(int, int, void *) = (void *)DEFAULT_ENTRY_POINT;
60 
61 
62 __asm(
63 "         .text                         \n"
64 "         .align 2            \n"
65 "         .globl    _start              \n"
66 "_start:                      \n"
67 
68 "         lis       %r8,(_start)@ha     \n"
69 "         addi      %r8,8,(_start)@l\n"
70 "         li        %r9,0x40  \n"       /* loop 64 times (for 2048 bytes of bootxx) */
71 "         mtctr     %r9                 \n"
72 "                                       \n"
73 "1:       dcbf      0,%r8               \n"
74 "         icbi      0,%r8               \n"
75 "         addi      %r8,%r8,0x20        \n"
76 "         bdnz      1b                  \n"
77 "         sync                          \n"
78 
79 "         li        %r0,0               \n"
80 "                                       \n"       /* test for 601 cpu */
81 "         mfspr     %r9,287             \n"       /* mfpvbr %r9 PVR = 287 */
82 "         srwi      %r9,%r9,0x10        \n"
83 "         cmplwi    %r9,0x02  \n"       /* 601 cpu == 0x0001 */
84 "         blt       2f                  \n"       /* skip over non-601 BAT setup */
85 "                                       \n"
86 "         mtdbatu 3,%r0                 \n"       /* non-601 BAT */
87 "         mtibatu   3,%r0               \n"
88 "         isync                         \n"
89 "         li        %r8,0x1ffe          \n"       /* map the lowest 256MB */
90 "         li        %r9,0x22  \n"       /* BAT_I */
91 "         mtdbatl   3,%r9               \n"
92 "         mtdbatu   3,%r8               \n"
93 "         mtibatl   3,%r9               \n"
94 "         mtibatu   3,%r8               \n"
95 "         isync                         \n"
96 "         b         3f                  \n"
97 "                                       \n"
98 "2:       mfmsr     %r8                 \n"       /* 601 BAT */
99 "         mtmsr     %r0                 \n"
100 "         isync                         \n"
101 "                                       \n"
102 "         mtibatu 0,%r0                 \n"
103 "         mtibatu 1,%r0                 \n"
104 "         mtibatu 2,%r0                 \n"
105 "         mtibatu 3,%r0                 \n"
106 "                                       \n"
107 "         li        %r9,0x7f  \n"
108 "         mtibatl 0,%r9                 \n"
109 "         li        %r9,0x1a  \n"
110 "         mtibatu 0,%r9                 \n"
111 "                                       \n"
112 "         lis %r9,0x80                  \n"
113 "         addi %r9,%r9,0x7f   \n"
114 "         mtibatl 1,%r9                 \n"
115 "         lis %r9,0x80                  \n"
116 "         addi %r9,%r9,0x1a   \n"
117 "         mtibatu 1,%r9                 \n"
118 "                                       \n"
119 "         lis %r9,0x100                 \n"
120 "         addi %r9,%r9,0x7f   \n"
121 "         mtibatl 2,%r9                 \n"
122 "         lis %r9,0x100                 \n"
123 "         addi %r9,%r9,0x1a   \n"
124 "         mtibatu 2,%r9                 \n"
125 "                                       \n"
126 "         lis %r9,0x180                 \n"
127 "         addi %r9,%r9,0x7f   \n"
128 "         mtibatl 3,%r9                 \n"
129 "         lis %r9,0x180                 \n"
130 "         addi %r9,%r9,0x1a   \n"
131 "         mtibatu 3,%r9                 \n"
132 "                                       \n"
133 "         isync                         \n"
134 "                                       \n"
135 "         mtmsr     %r8                 \n"
136 "         isync                         \n"
137 "                                       \n"
138           /*
139            * setup 32 KB of stack with 32 bytes overpad (see above)
140            */
141 "3:       lis       %r1,(stack+32768)@ha\n"
142 "         addi      %r1,%r1,(stack+32768)@l\n"
143           /*
144            * terminate the frame link chain,
145            * clear by bytes to avoid ppc601 alignment exceptions
146            */
147 "         stb       %r0,0(%r1)          \n"
148 "         stb       %r0,1(%r1)          \n"
149 "         stb       %r0,2(%r1)          \n"
150 "         stb       %r0,3(%r1)          \n"
151 
152 "         b         startup             \n"
153 );
154 
155 
156 static inline int
OF_finddevice(char * name)157 OF_finddevice(char *name)
158 {
159           static struct {
160                     char *name;
161                     int nargs;
162                     int nreturns;
163                     char *device;
164                     int phandle;
165           } args = {
166                     "finddevice",
167                     1,
168                     1,
169           };
170 
171           args.device = name;
172           openfirmware(&args);
173 
174           return args.phandle;
175 }
176 
177 static inline int
OF_getprop(int handle,char * prop,void * buf,int buflen)178 OF_getprop(int handle, char *prop, void *buf, int buflen)
179 {
180           static struct {
181                     char *name;
182                     int nargs;
183                     int nreturns;
184                     int phandle;
185                     char *prop;
186                     void *buf;
187                     int buflen;
188                     int size;
189           } args = {
190                     "getprop",
191                     4,
192                     1,
193           };
194 
195           args.phandle = handle;
196           args.prop = prop;
197           args.buf = buf;
198           args.buflen = buflen;
199           openfirmware(&args);
200 
201           return args.size;
202 }
203 
204 static inline int
OF_open(char * dname)205 OF_open(char *dname)
206 {
207           static struct {
208                     char *name;
209                     int nargs;
210                     int nreturns;
211                     char *dname;
212                     int handle;
213           } args = {
214                     "open",
215                     1,
216                     1,
217           };
218 
219           args.dname = dname;
220           openfirmware(&args);
221 
222           return args.handle;
223 }
224 
225 static inline int
OF_read(int handle,void * addr,int len)226 OF_read(int handle, void *addr, int len)
227 {
228           static struct {
229                     char *name;
230                     int nargs;
231                     int nreturns;
232                     int ihandle;
233                     void *addr;
234                     int len;
235                     int actual;
236           } args = {
237                     "read",
238                     3,
239                     1,
240           };
241 
242           args.ihandle = handle;
243           args.addr = addr;
244           args.len = len;
245           openfirmware(&args);
246 
247           return args.actual;
248 }
249 
250 static inline int
OF_seek(int handle,u_quad_t pos)251 OF_seek(int handle, u_quad_t pos)
252 {
253           static struct {
254                     char *name;
255                     int nargs;
256                     int nreturns;
257                     int handle;
258                     int poshi;
259                     int poslo;
260                     int status;
261           } args = {
262                     "seek",
263                     3,
264                     1,
265           };
266 
267           args.handle = handle;
268           args.poshi = (int)(pos >> 32);
269           args.poslo = (int)pos;
270           openfirmware(&args);
271 
272           return args.status;
273 }
274 
275 static inline int
OF_write(int handle,const void * addr,int len)276 OF_write(int handle, const void *addr, int len)
277 {
278           static struct {
279                     char *name;
280                     int nargs;
281                     int nreturns;
282                     int ihandle;
283                     const void *addr;
284                     int len;
285                     int actual;
286           } args = {
287                     "write",
288                     3,
289                     1,
290           };
291 
292           args.ihandle = handle;
293           args.addr = addr;
294           args.len = len;
295           openfirmware(&args);
296 
297           return args.actual;
298 }
299 
300 int stdout;
301 
302 static void
putstrn(const char * s,size_t n)303 putstrn(const char *s, size_t n)
304 {
305           OF_write(stdout, s, n);
306 }
307 
308 #define putstr(x)   putstrn((x),sizeof(x)-1)
309 #define putc(x)               do { char __x = (x) ; putstrn(&__x, 1); } while (0)
310 
311 
312 void
startup(int arg1,int arg2,void * openfirm)313 startup(int arg1, int arg2, void *openfirm)
314 {
315           int fd, blk, chosen, options, j;
316           uint32_t cpuvers;
317           size_t i;
318           char *addr;
319           char bootpath[128];
320 
321           __asm volatile ("mfpvr %0" : "=r"(cpuvers));
322           cpuvers >>= 16;
323 
324           openfirmware = openfirm;
325 
326           chosen = OF_finddevice("/chosen");
327           if (OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath)) == 1) {
328                     /*
329                      * buggy firmware doesn't set bootpath...
330                      */
331                     options = OF_finddevice("/options");
332                     OF_getprop(options, "boot-device", bootpath, sizeof(bootpath));
333           }
334           if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout))
335               != sizeof(stdout))
336                     stdout = -1;
337 
338           /*
339            * "scsi/sd@0:0" --> "scsi/sd@0"
340            */
341           for (i = 0; i < sizeof(bootpath); i++) {
342                     if (bootpath[i] == ':')
343                               bootpath[i] = 0;
344                     if (bootpath[i] == 0)
345                               break;
346           }
347 
348           putstr("\r\nOF_open bootpath=");
349           putstrn(bootpath, i);
350           fd = OF_open(bootpath);
351 
352           addr = (char *)entry_point;
353           putstr("\r\nread stage 2 blocks: ");
354           for (j = 0; j < bbinfo.bbi_block_count; j++) {
355                     if ((blk = bbinfo.bbi_block_table[j]) == 0)
356                               break;
357                     putc('0' + j % 10);
358                     OF_seek(fd, (u_quad_t)blk * 512);
359                     OF_read(fd, addr, bbinfo.bbi_block_size);
360                     addr += bbinfo.bbi_block_size;
361           }
362           putstr(". done!\r\nstarting stage 2...\r\n");
363 
364           if (cpuvers != MPC601) {
365                     /*
366                      * enable D/I cache
367                      */
368                     __asm(
369                               "mtdbatu  3,%0\n\t"
370                               "mtdbatl  3,%1\n\t"
371                               "mtibatu  3,%0\n\t"
372                               "mtibatl  3,%1\n\t"
373                               "isync"
374                     ::        "r"(BATU(0, BAT_BL_256M, BAT_Vs)),
375                               "r"(BATL(0, 0, BAT_PP_RW)));
376           }
377 
378           entry_point(0, 0, openfirm);
379           for (;;);                     /* just in case */
380 }
381