import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / mips / baget / balo.c
1 /*
2  * balo.c: BAget LOader
3  *
4  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
5  */
6 #include <linux/kernel.h>
7 #include <asm/system.h>
8 #include <asm/ptrace.h>
9 #include <asm/addrspace.h>
10
11 #include <asm/baget/baget.h>
12
13 #include "balo.h"  /* Includes some kernel symbol values */
14
15 static char *banner = "\nBaget Linux Loader v0.2\n";
16
17 static void mem_move (long *to, long *from, long size)
18 {
19         while (size > 0) {
20                 *to++ = *from++;
21                 size -= sizeof(long);
22         }
23 }
24
25 static volatile int *mem_limit     = (volatile int*)KSEG1;
26 static volatile int *mem_limit_dbe = (volatile int*)KSEG1;
27
28 static int can_write (volatile int* p) {
29         return p <  (int*)(KSEG1+BALO_OFFSET) ||
30                p >= (int*)(KSEG1+BALO_OFFSET+BALO_SIZE);
31 }
32
33 static volatile enum balo_state_enum {
34         BALO_INIT,
35         MEM_INIT,
36         MEM_PROBE,
37         START_KERNEL
38 } balo_state = BALO_INIT;
39
40
41 static __inline__ void reset_and_jump(int start, int mem_upper)
42 {
43         unsigned long tmp;
44
45         __asm__ __volatile__(
46                 ".set\tnoreorder\n\t"
47                 ".set\tnoat\n\t"
48                 "mfc0\t$1, $12\n\t"
49                 "nop\n\t"
50                 "nop\n\t"
51                 "nop\n\t"
52                 "ori\t$1, $1, 0xff00\n\t"
53                 "xori\t$1, $1, 0xff00\n\t"
54                 "mtc0\t$1, $12\n\t"
55                 "nop\n\t"
56                 "nop\n\t"
57                 "nop\n\t"
58                 "move\t%0, %2\n\t"
59                 "jr\t%1\n\t"
60                 "nop\n\t"
61                 ".set\tat\n\t"
62                 ".set\treorder"
63                 : "=&r" (tmp)
64                 : "Ir" (start), "Ir" (mem_upper)
65                 : "memory");
66 }
67
68 static void start_kernel(void)
69 {
70         extern char _vmlinux_start, _vmlinux_end;
71         extern char _ramdisk_start, _ramdisk_end;
72
73         outs( "Relocating Linux... " );
74         mem_move((long*)KSEG0, (long*)&_vmlinux_start,
75                  &_vmlinux_end-&_vmlinux_start);
76         outs("done.\n");
77
78         if (&_ramdisk_start != &_ramdisk_end) {
79                 outs("Setting up RAMDISK... ");
80                 if (*(unsigned long*)RAMDISK_BASE != 0xBA) {
81                         outs("Bad RAMDISK_BASE signature in system image.\n");
82                         balo_hungup();
83                 }
84                 *(unsigned long*)RAMDISK_BASE = (unsigned long)&_ramdisk_start;
85                 *(unsigned long*)RAMDISK_SIZE = &_ramdisk_end -&_ramdisk_start;
86                 outs("done.\n");
87         }
88
89         {
90                 extern void flush_cache_low(int isize, int dsize);
91                 flush_cache_low(256*1024,256*1024);
92         }
93
94         balo_printf( "Kernel entry: %x\n\n", START);
95         balo_state = START_KERNEL;
96         reset_and_jump(START, (int)mem_limit-KSEG1+KSEG0);
97 }
98
99
100 static void mem_probe(void)
101 {
102         balo_state = MEM_PROBE;
103         outs("RAM: <");
104         while(mem_limit < mem_limit_dbe) {
105                 if (can_write(mem_limit) && *mem_limit != 0)
106                         break; /* cycle found */
107                 outc('.');
108                 if (can_write(mem_limit))
109                         *mem_limit = -1; /* mark */
110                 mem_limit += 0x40000;
111         }
112         outs(">\n");
113         start_kernel();
114 }
115
116 volatile unsigned int int_cause;
117 volatile unsigned int epc;
118 volatile unsigned int badvaddr;
119
120 static void print_regs(void)
121 {
122         balo_printf("CAUSE=%x EPC=%x BADVADDR=%x\n",
123                     int_cause, epc, badvaddr);
124 }
125
126 void int_handler(struct pt_regs *regs)
127 {
128         switch (balo_state) {
129         case BALO_INIT:
130                 balo_printf("\nBALO: trap in balo itself.\n");
131                 print_regs();
132                 balo_hungup();
133                 break;
134         case MEM_INIT:
135                 if ((int_cause & CAUSE_MASK) != CAUSE_DBE) {
136                         balo_printf("\nBALO: unexpected trap during memory init.\n");
137                         print_regs();
138                         balo_hungup();
139                 } else {
140                         mem_probe();
141                 }
142                 break;
143         case MEM_PROBE:
144                 balo_printf("\nBALO: unexpected trap during memory probe.\n");
145                 print_regs();
146                 balo_hungup();
147                 break;
148         case START_KERNEL:
149                 balo_printf("\nBALO: unexpected kernel trap.\n");
150                 print_regs();
151                 balo_hungup();
152                 break;
153         }
154         balo_printf("\nBALO: unexpected return from handler.\n");
155         print_regs();
156         balo_hungup();
157 }
158
159 static void mem_init(void)
160 {
161         balo_state = MEM_INIT;
162
163         while(1) {
164                 *mem_limit_dbe;
165                 if (can_write(mem_limit_dbe))
166                         *mem_limit_dbe = 0;
167
168                 mem_limit_dbe += 0x40000; /* +1M */
169         }
170         /*  no return: must go to int_handler */
171 }
172
173 void balo_entry(void)
174 {
175         extern void except_vec3_generic(void);
176
177         cli();
178         outs(banner);
179         memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80);
180         mem_init();
181 }
182
183 /* Needed for linking */
184
185 int vsprintf(char *buf, const char *fmt, va_list arg)
186 {
187         outs("BALO: vsprintf called.\n");
188         balo_hungup();
189         return 0;
190 }