1
2
3
4
5
6
7
8#include <linux/errno.h>
9#include <linux/sched.h>
10#include <linux/kernel.h>
11#include <linux/mm.h>
12#include <linux/stddef.h>
13#include <linux/unistd.h>
14#include <linux/ptrace.h>
15#include <linux/slab.h>
16#include <asm/smp.h>
17#include <linux/user.h>
18#include <linux/a.out.h>
19#include <linux/tty.h>
20#include <linux/delay.h>
21#include <linux/config.h>
22#include <linux/fs.h>
23#include <linux/seq_file.h>
24#include <linux/kdev_t.h>
25#include <linux/major.h>
26#include <linux/string.h>
27#include <linux/blk.h>
28#include <linux/init.h>
29#include <linux/inet.h>
30#include <linux/console.h>
31
32#include <asm/segment.h>
33#include <asm/system.h>
34#include <asm/io.h>
35#include <asm/processor.h>
36#include <asm/oplib.h>
37#include <asm/page.h>
38#include <asm/pgtable.h>
39#include <asm/idprom.h>
40#include <asm/head.h>
41#include <asm/starfire.h>
42#include <asm/hardirq.h>
43#include <asm/sections.h>
44
45#ifdef CONFIG_IP_PNP
46#include <net/ipconfig.h>
47#endif
48
49struct screen_info screen_info = {
50 0, 0,
51 0,
52 0,
53 0,
54 128,
55 0, 0, 0,
56 54,
57 0,
58 16
59};
60
61
62
63
64
65
66
67#if CONFIG_SUN_CONSOLE
68void (*prom_palette)(int);
69#endif
70void (*prom_keyboard)(void);
71asmlinkage void sys_sync(void);
72
73static void
74prom_console_write(struct console *con, const char *s, unsigned n)
75{
76 prom_printf("%s", s);
77}
78
79static struct console prom_console = {
80 name: "prom",
81 write: prom_console_write,
82 flags: CON_CONSDEV | CON_ENABLED,
83 index: -1,
84};
85
86#define PROM_TRUE -1
87#define PROM_FALSE 0
88
89
90int prom_callback(long *args)
91{
92 struct console *cons, *saved_console = NULL;
93 unsigned long flags;
94 char *cmd;
95 extern spinlock_t prom_entry_lock;
96
97 if (!args)
98 return -1;
99 if (!(cmd = (char *)args[0]))
100 return -1;
101
102
103
104
105
106
107
108
109 irq_exit(smp_processor_id(), 0);
110 save_and_cli(flags);
111 spin_unlock(&prom_entry_lock);
112 cons = console_drivers;
113 while (cons) {
114 unregister_console(cons);
115 cons->flags &= ~(CON_PRINTBUFFER);
116 cons->next = saved_console;
117 saved_console = cons;
118 cons = console_drivers;
119 }
120 register_console(&prom_console);
121 if (!strcmp(cmd, "sync")) {
122 prom_printf("PROM `%s' command...\n", cmd);
123 show_free_areas();
124 if(current->pid != 0) {
125 sti();
126 sys_sync();
127 cli();
128 }
129 args[2] = 0;
130 args[args[1] + 3] = -1;
131 prom_printf("Returning to PROM\n");
132 } else if (!strcmp(cmd, "va>tte-data")) {
133 unsigned long ctx, va;
134 unsigned long tte = 0;
135 long res = PROM_FALSE;
136
137 ctx = args[3];
138 va = args[4];
139 if (ctx) {
140
141
142
143 struct task_struct *p;
144 struct mm_struct *mm = NULL;
145 pgd_t *pgdp;
146 pmd_t *pmdp;
147 pte_t *ptep;
148
149 for_each_task(p) {
150 mm = p->mm;
151 if (CTX_HWBITS(mm->context) == ctx)
152 break;
153 }
154 if (!mm ||
155 CTX_HWBITS(mm->context) != ctx)
156 goto done;
157
158 pgdp = pgd_offset(mm, va);
159 if (pgd_none(*pgdp))
160 goto done;
161 pmdp = pmd_offset(pgdp, va);
162 if (pmd_none(*pmdp))
163 goto done;
164 ptep = pte_offset(pmdp, va);
165 if (!pte_present(*ptep))
166 goto done;
167 tte = pte_val(*ptep);
168 res = PROM_TRUE;
169 goto done;
170 }
171
172 if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
173
174 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
175 "flush %%g6"
176 :
177 : "r" (0),
178 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
179
180
181
182
183
184 if (tlb_type == spitfire)
185 tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
186 else if (tlb_type == cheetah || tlb_type == cheetah_plus)
187 tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
188
189 res = PROM_TRUE;
190 goto done;
191 }
192
193 if (va < PGDIR_SIZE) {
194
195
196
197 pgd_t *pgdp;
198 pmd_t *pmdp;
199 pte_t *ptep;
200 int error;
201
202 if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) {
203 tte = prom_virt_to_phys(va, &error);
204 if (!error)
205 res = PROM_TRUE;
206 goto done;
207 }
208 pgdp = pgd_offset_k(va);
209 if (pgd_none(*pgdp))
210 goto done;
211 pmdp = pmd_offset(pgdp, va);
212 if (pmd_none(*pmdp))
213 goto done;
214 ptep = pte_offset(pmdp, va);
215 if (!pte_present(*ptep))
216 goto done;
217 tte = pte_val(*ptep);
218 res = PROM_TRUE;
219 goto done;
220 }
221
222 if (va < PAGE_OFFSET) {
223
224
225
226 goto done;
227 }
228
229 if (va & (1UL << 40)) {
230
231
232
233
234 tte = (__pa(va) & _PAGE_PADDR) |
235 _PAGE_VALID | _PAGE_SZ4MB |
236 _PAGE_E | _PAGE_P | _PAGE_W;
237 res = PROM_TRUE;
238 goto done;
239 }
240
241
242
243
244 tte = (__pa(va) & _PAGE_PADDR) |
245 _PAGE_VALID | _PAGE_SZ4MB |
246 _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W;
247 res = PROM_TRUE;
248
249 done:
250 if (res == PROM_TRUE) {
251 args[2] = 3;
252 args[args[1] + 3] = 0;
253 args[args[1] + 4] = res;
254 args[args[1] + 5] = tte;
255 } else {
256 args[2] = 2;
257 args[args[1] + 3] = 0;
258 args[args[1] + 4] = res;
259 }
260 } else if (!strcmp(cmd, ".soft1")) {
261 unsigned long tte;
262
263 tte = args[3];
264 prom_printf("%lx:\"%s%s%s%s%s\" ",
265 (tte & _PAGE_SOFT) >> 7,
266 tte & _PAGE_MODIFIED ? "M" : "-",
267 tte & _PAGE_ACCESSED ? "A" : "-",
268 tte & _PAGE_READ ? "W" : "-",
269 tte & _PAGE_WRITE ? "R" : "-",
270 tte & _PAGE_PRESENT ? "P" : "-");
271
272 args[2] = 2;
273 args[args[1] + 3] = 0;
274 args[args[1] + 4] = PROM_TRUE;
275 } else if (!strcmp(cmd, ".soft2")) {
276 unsigned long tte;
277
278 tte = args[3];
279 prom_printf("%lx ", (tte & 0x07FC000000000000) >> 50);
280
281 args[2] = 2;
282 args[args[1] + 3] = 0;
283 args[args[1] + 4] = PROM_TRUE;
284 } else {
285 prom_printf("unknown PROM `%s' command...\n", cmd);
286 }
287 unregister_console(&prom_console);
288 while (saved_console) {
289 cons = saved_console;
290 saved_console = cons->next;
291 register_console(cons);
292 }
293 spin_lock(&prom_entry_lock);
294 restore_flags(flags);
295
296
297
298 irq_enter(smp_processor_id(), 0);
299 return 0;
300}
301
302extern void rs_kgdb_hook(int tty_num);
303
304unsigned int boot_flags = 0;
305#define BOOTME_DEBUG 0x1
306#define BOOTME_SINGLE 0x2
307#define BOOTME_KGDB 0x4
308
309#ifdef CONFIG_SUN_CONSOLE
310static int console_fb __initdata = 0;
311#endif
312
313
314unsigned long cmdline_memory_size = 0;
315
316static struct console prom_debug_console = {
317 name: "debug",
318 write: prom_console_write,
319 flags: CON_PRINTBUFFER,
320 index: -1,
321};
322
323
324void kernel_enter_debugger(void)
325{
326}
327
328int obp_system_intr(void)
329{
330 if (boot_flags & BOOTME_DEBUG) {
331 printk("OBP: system interrupted\n");
332 prom_halt();
333 return 1;
334 }
335 return 0;
336}
337
338
339
340
341
342static void __init process_switch(char c)
343{
344 switch (c) {
345 case 'd':
346 boot_flags |= BOOTME_DEBUG;
347 break;
348 case 's':
349 boot_flags |= BOOTME_SINGLE;
350 break;
351 case 'h':
352 prom_printf("boot_flags_init: Halt!\n");
353 prom_halt();
354 break;
355 case 'p':
356
357 register_console(&prom_debug_console);
358 break;
359 default:
360 printk("Unknown boot switch (-%c)\n", c);
361 break;
362 }
363}
364
365static void __init boot_flags_init(char *commands)
366{
367 while (*commands) {
368
369 while (*commands && *commands == ' ')
370 commands++;
371
372
373 if (*commands == '\0')
374 break;
375 else if (*commands == '-') {
376 commands++;
377 while (*commands && *commands != ' ')
378 process_switch(*commands++);
379 } else if (strlen(commands) >= 9
380 && !strncmp(commands, "kgdb=tty", 8)) {
381 boot_flags |= BOOTME_KGDB;
382 switch (commands[8]) {
383#ifdef CONFIG_SUN_SERIAL
384 case 'a':
385 rs_kgdb_hook(0);
386 prom_printf("KGDB: Using serial line /dev/ttya.\n");
387 break;
388 case 'b':
389 rs_kgdb_hook(1);
390 prom_printf("KGDB: Using serial line /dev/ttyb.\n");
391 break;
392#endif
393 default:
394 printk("KGDB: Unknown tty line.\n");
395 boot_flags &= ~BOOTME_KGDB;
396 break;
397 }
398 commands += 9;
399 } else {
400#if CONFIG_SUN_CONSOLE
401 if (!strncmp(commands, "console=", 8)) {
402 commands += 8;
403 if (!strncmp (commands, "ttya", 4)) {
404 console_fb = 2;
405 prom_printf ("Using /dev/ttya as console.\n");
406 } else if (!strncmp (commands, "ttyb", 4)) {
407 console_fb = 3;
408 prom_printf ("Using /dev/ttyb as console.\n");
409#if defined(CONFIG_PROM_CONSOLE)
410 } else if (!strncmp (commands, "prom", 4)) {
411 char *p;
412
413 for (p = commands - 8; *p && *p != ' '; p++)
414 *p = ' ';
415 conswitchp = &prom_con;
416 console_fb = 1;
417#endif
418 } else {
419 console_fb = 1;
420 }
421 } else
422#endif
423 if (!strncmp(commands, "mem=", 4)) {
424
425
426
427
428 cmdline_memory_size = simple_strtoul(commands + 4,
429 &commands, 0);
430 if (*commands == 'K' || *commands == 'k') {
431 cmdline_memory_size <<= 10;
432 commands++;
433 } else if (*commands=='M' || *commands=='m') {
434 cmdline_memory_size <<= 20;
435 commands++;
436 }
437 }
438 while (*commands && *commands != ' ')
439 commands++;
440 }
441 }
442}
443
444extern int prom_probe_memory(void);
445extern unsigned long start, end;
446extern void panic_setup(char *, int *);
447
448extern unsigned short root_flags;
449extern unsigned short root_dev;
450extern unsigned short ram_flags;
451#define RAMDISK_IMAGE_START_MASK 0x07FF
452#define RAMDISK_PROMPT_FLAG 0x8000
453#define RAMDISK_LOAD_FLAG 0x4000
454
455extern int root_mountflags;
456
457char saved_command_line[256];
458char reboot_command[256];
459
460extern unsigned long phys_base, kern_base, kern_size;
461
462static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
463
464void register_prom_callbacks(void)
465{
466 prom_setcallback(prom_callback);
467 prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
468 "' linux-va>tte-data to va>tte-data");
469 prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
470 "' linux-.soft1 to .soft1");
471 prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
472 "' linux-.soft2 to .soft2");
473}
474
475extern void paging_init(void);
476
477void __init setup_arch(char **cmdline_p)
478{
479 extern int serial_console;
480 unsigned long highest_paddr;
481 int i;
482
483
484 *cmdline_p = prom_getbootargs();
485 strcpy(saved_command_line, *cmdline_p);
486
487 printk("ARCH: SUN4U\n");
488
489#ifdef CONFIG_DUMMY_CONSOLE
490 conswitchp = &dummy_con;
491#elif defined(CONFIG_PROM_CONSOLE)
492 conswitchp = &prom_con;
493#endif
494
495#ifdef CONFIG_SMP
496 i = (unsigned long)&irq_stat[1] - (unsigned long)&irq_stat[0];
497 if ((i == SMP_CACHE_BYTES) || (i == (2 * SMP_CACHE_BYTES))) {
498 extern unsigned int irqsz_patchme[1];
499 irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
500 SMP_CACHE_BYTES_SHIFT + 1);
501 flushi((long)&irqsz_patchme[0]);
502 } else {
503 prom_printf("Unexpected size of irq_stat[] elements\n");
504 prom_halt();
505 }
506#endif
507
508 check_if_starfire();
509
510 boot_flags_init(*cmdline_p);
511
512 idprom_init();
513 (void) prom_probe_memory();
514
515
516
517
518 phys_base = 0xffffffffffffffffUL;
519 highest_paddr = 0UL;
520 for (i = 0; sp_banks[i].num_bytes != 0; i++) {
521 unsigned long top;
522
523 if (sp_banks[i].base_addr < phys_base)
524 phys_base = sp_banks[i].base_addr;
525 top = sp_banks[i].base_addr +
526 sp_banks[i].num_bytes;
527 if (highest_paddr < top)
528 highest_paddr = top;
529 }
530
531 switch (tlb_type) {
532 default:
533 case spitfire:
534 kern_base = spitfire_get_itlb_data(sparc64_highest_locked_tlbent());
535 kern_base &= _PAGE_PADDR_SF;
536 break;
537
538 case cheetah:
539 case cheetah_plus:
540 kern_base = cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
541 kern_base &= _PAGE_PADDR;
542 break;
543 };
544
545 kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
546
547 if (!root_flags)
548 root_mountflags &= ~MS_RDONLY;
549 ROOT_DEV = to_kdev_t(root_dev);
550#ifdef CONFIG_BLK_DEV_INITRD
551 rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
552 rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
553 rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
554#endif
555
556 init_task.thread.kregs = &fake_swapper_regs;
557
558#ifdef CONFIG_IP_PNP
559 if (!ic_set_manually) {
560 int chosen = prom_finddevice ("/chosen");
561 u32 cl, sv, gw;
562
563 cl = prom_getintdefault (chosen, "client-ip", 0);
564 sv = prom_getintdefault (chosen, "server-ip", 0);
565 gw = prom_getintdefault (chosen, "gateway-ip", 0);
566 if (cl && sv) {
567 ic_myaddr = cl;
568 ic_servaddr = sv;
569 if (gw)
570 ic_gateway = gw;
571#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
572 ic_proto_enabled = 0;
573#endif
574 }
575 }
576#endif
577
578#ifdef CONFIG_SUN_SERIAL
579 switch (console_fb) {
580 case 0:
581 {
582 int idev = prom_query_input_device();
583 int odev = prom_query_output_device();
584 if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
585 serial_console = 0;
586 } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
587 serial_console = 1;
588 } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
589 serial_console = 2;
590 } else {
591 prom_printf("Inconsistent console: "
592 "input %d, output %d\n",
593 idev, odev);
594 prom_halt();
595 }
596 }
597 break;
598 case 1:
599 serial_console = 0;
600 break;
601 case 2:
602 serial_console = 1;
603 break;
604 case 3:
605 serial_console = 2;
606 break;
607 }
608#else
609 serial_console = 0;
610#endif
611 if (serial_console)
612 conswitchp = NULL;
613
614 paging_init();
615}
616
617asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
618{
619 return -EIO;
620}
621
622
623
624extern char *sparc_cpu_type;
625extern char *sparc_fpu_type;
626
627extern void smp_info(struct seq_file *);
628extern void smp_bogo(struct seq_file *);
629extern void mmu_info(struct seq_file *);
630
631#ifndef CONFIG_SMP
632unsigned long up_clock_tick;
633#endif
634
635static int show_cpuinfo(struct seq_file *m, void *__unused)
636{
637 seq_printf(m,
638 "cpu\t\t: %s\n"
639 "fpu\t\t: %s\n"
640 "promlib\t\t: Version 3 Revision %d\n"
641 "prom\t\t: %d.%d.%d\n"
642 "type\t\t: sun4u\n"
643 "ncpus probed\t: %d\n"
644 "ncpus active\t: %d\n"
645#ifndef CONFIG_SMP
646 "Cpu0Bogo\t: %lu.%02lu\n"
647 "Cpu0ClkTck\t: %016lx\n"
648#endif
649 ,
650 sparc_cpu_type,
651 sparc_fpu_type,
652 prom_rev,
653 prom_prev >> 16,
654 (prom_prev >> 8) & 0xff,
655 prom_prev & 0xff,
656 linux_num_cpus,
657 smp_num_cpus
658#ifndef CONFIG_SMP
659 , loops_per_jiffy/(500000/HZ),
660 (loops_per_jiffy/(5000/HZ)) % 100,
661 up_clock_tick
662#endif
663 );
664#ifdef CONFIG_SMP
665 smp_bogo(m);
666#endif
667 mmu_info(m);
668#ifdef CONFIG_SMP
669 smp_info(m);
670#endif
671 return 0;
672}
673
674static void *c_start(struct seq_file *m, loff_t *pos)
675{
676
677
678
679
680 return *pos == 0 ? &c_start : NULL;
681}
682
683static void *c_next(struct seq_file *m, void *v, loff_t *pos)
684{
685 ++*pos;
686 return c_start(m, pos);
687}
688
689static void c_stop(struct seq_file *m, void *v)
690{
691}
692
693struct seq_operations cpuinfo_op = {
694 start: c_start,
695 next: c_next,
696 stop: c_stop,
697 show: show_cpuinfo,
698};
699