1 /* $Id: setup.c,v 1.110 1999/08/31 06:54:23 davem Exp $
2 * linux/arch/sparc/kernel/setup.c
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
7 #include <linux/errno.h>
8 #include <linux/sched.h>
9 #include <linux/kernel.h>
11 #include <linux/stddef.h>
12 #include <linux/unistd.h>
13 #include <linux/ptrace.h>
14 #include <linux/malloc.h>
16 #include <linux/user.h>
17 #include <linux/a.out.h>
18 #include <linux/tty.h>
19 #include <linux/delay.h>
20 #include <linux/config.h>
22 #include <linux/kdev_t.h>
23 #include <linux/major.h>
24 #include <linux/string.h>
25 #include <linux/blk.h>
26 #include <linux/init.h>
27 #include <linux/interrupt.h>
28 #include <linux/console.h>
29 #include <linux/spinlock.h>
31 #include <asm/segment.h>
32 #include <asm/system.h>
35 #include <asm/processor.h>
36 #include <asm/oplib.h>
38 #include <asm/pgtable.h>
39 #include <asm/traps.h>
40 #include <asm/vaddrs.h>
41 #include <asm/kdebug.h>
43 #include <asm/idprom.h>
44 #include <asm/softirq.h>
45 #include <asm/hardirq.h>
46 #include <asm/machines.h>
48 struct screen_info screen_info
= {
49 0, 0, /* orig-x, orig-y */
51 0, /* orig-video-page */
52 0, /* orig-video-mode */
53 128, /* orig-video-cols */
54 0,0,0, /* ega_ax, ega_bx, ega_cx */
55 54, /* orig-video-lines */
56 0, /* orig-video-isVGA */
57 16 /* orig-video-points */
60 unsigned int phys_bytes_of_ram
, end_of_phys_memory
;
62 /* Typing sync at the prom prompt calls the function pointed to by
63 * romvec->pv_synchook which I set to the following function.
64 * This should sync all filesystems and return, for now it just
65 * prints out pretty messages and returns.
68 extern unsigned long trapbase
;
69 extern int serial_console
;
70 extern void breakpoint(void);
71 #if CONFIG_SUN_CONSOLE
72 void (*prom_palette
)(int);
74 asmlinkage
void sys_sync(void); /* it's really int */
77 void prom_sync_me(void)
79 unsigned long prom_tbr
, flags
;
82 global_irq_holder
= NO_PROC_ID
;
83 *((unsigned char *)&global_irq_lock
) = 0;
84 *((unsigned char *)&global_bh_lock
) = 0;
86 __save_and_cli(flags
);
87 __asm__
__volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr
));
88 __asm__
__volatile__("wr %0, 0x0, %%tbr\n\t"
91 "nop\n\t" : : "r" (&trapbase
));
93 #ifdef CONFIG_SUN_CONSOLE
97 prom_printf("PROM SYNC COMMAND...\n");
99 if(current
->pid
!= 0) {
104 prom_printf("Returning to prom\n");
106 __asm__
__volatile__("wr %0, 0x0, %%tbr\n\t"
109 "nop\n\t" : : "r" (prom_tbr
));
110 __restore_flags(flags
);
115 extern void rs_kgdb_hook(int tty_num
); /* sparc/serial.c */
117 unsigned int boot_flags
;
118 #define BOOTME_DEBUG 0x1
119 #define BOOTME_SINGLE 0x2
120 #define BOOTME_KGDBA 0x4
121 #define BOOTME_KGDBB 0x8
122 #define BOOTME_KGDB 0xc
124 #ifdef CONFIG_SUN_CONSOLE
125 static int console_fb
= 0;
127 static unsigned long memory_size __initdata
= 0;
129 void kernel_enter_debugger(void)
131 if (boot_flags
& BOOTME_KGDB
) {
132 printk("KGDB: Entered\n");
137 int obp_system_intr(void)
139 if (boot_flags
& BOOTME_KGDB
) {
140 printk("KGDB: system interrupted\n");
144 if (boot_flags
& BOOTME_DEBUG
) {
145 printk("OBP: system interrupted\n");
153 * Process kernel command line switches that are specific to the
154 * SPARC or that require special low-level processing.
156 static void __init
process_switch(char c
)
160 boot_flags
|= BOOTME_DEBUG
;
163 boot_flags
|= BOOTME_SINGLE
;
166 prom_printf("boot_flags_init: Halt!\n");
170 printk("Unknown boot switch (-%c)\n", c
);
175 static void __init
boot_flags_init(char *commands
)
178 /* Move to the start of the next "argument". */
179 while (*commands
&& *commands
== ' ')
182 /* Process any command switches, otherwise skip it. */
183 if (*commands
== '\0')
185 else if (*commands
== '-') {
187 while (*commands
&& *commands
!= ' ')
188 process_switch(*commands
++);
189 } else if (strlen(commands
) >= 9
190 && !strncmp(commands
, "kgdb=tty", 8)) {
191 switch (commands
[8]) {
192 #ifdef CONFIG_SUN_SERIAL
194 boot_flags
|= BOOTME_KGDBA
;
195 prom_printf("KGDB: Using serial line /dev/ttya.\n");
198 boot_flags
|= BOOTME_KGDBB
;
199 prom_printf("KGDB: Using serial line /dev/ttyb.\n");
204 printk("KGDB: AP1000+ debugging\n");
208 printk("KGDB: Unknown tty line.\n");
213 #if CONFIG_SUN_CONSOLE
214 if (!strncmp(commands
, "console=", 8)) {
216 if (!strncmp (commands
, "ttya", 4)) {
218 prom_printf ("Using /dev/ttya as console.\n");
219 } else if (!strncmp (commands
, "ttyb", 4)) {
221 prom_printf ("Using /dev/ttyb as console.\n");
222 #if defined(CONFIG_PROM_CONSOLE)
223 } else if (!strncmp (commands
, "prom", 4)) {
226 for (p
= commands
- 8; *p
&& *p
!= ' '; p
++)
228 conswitchp
= &prom_con
;
236 if (!strncmp(commands
, "mem=", 4)) {
238 * "mem=XXX[kKmM] overrides the PROM-reported
241 memory_size
= simple_strtoul(commands
+ 4,
243 if (*commands
== 'K' || *commands
== 'k') {
246 } else if (*commands
=='M' || *commands
=='m') {
251 while (*commands
&& *commands
!= ' ')
257 /* This routine will in the future do all the nasty prom stuff
258 * to probe for the mmu type and its parameters, etc. This will
259 * also be where SMP things happen plus the Sparc specific memory
260 * physical memory probe as on the alpha.
263 extern int prom_probe_memory(void);
264 extern void sun4c_probe_vac(void);
265 extern char cputypval
;
266 extern unsigned long start
, end
;
267 extern void panic_setup(char *, int *);
268 extern void srmmu_end_memory(unsigned long, unsigned long *);
269 extern unsigned long sun_serial_setup(unsigned long);
271 extern unsigned short root_flags
;
272 extern unsigned short root_dev
;
273 extern unsigned short ram_flags
;
274 extern unsigned sparc_ramdisk_image
;
275 extern unsigned sparc_ramdisk_size
;
276 #define RAMDISK_IMAGE_START_MASK 0x07FF
277 #define RAMDISK_PROMPT_FLAG 0x8000
278 #define RAMDISK_LOAD_FLAG 0x4000
280 extern int root_mountflags
;
282 char saved_command_line
[256];
283 char reboot_command
[256];
284 enum sparc_cpu sparc_cpu_model
;
286 struct tt_entry
*sparc_ttable
;
288 struct pt_regs fake_swapper_regs
= { 0, 0, 0, 0, { 0, } };
290 static void prom_cons_write(struct console
*con
, const char *str
, unsigned count
)
293 prom_printf("%c", *str
++);
296 static struct console prom_console
= {
297 "PROM", prom_cons_write
, 0, 0, 0, 0, 0, CON_PRINTBUFFER
, 0, 0, 0
300 void __init
setup_arch(char **cmdline_p
,
301 unsigned long * memory_start_p
, unsigned long * memory_end_p
)
303 int total
, i
, packed
;
305 sparc_ttable
= (struct tt_entry
*) &start
;
307 /* Initialize PROM console and command line. */
308 *cmdline_p
= prom_getbootargs();
309 strcpy(saved_command_line
, *cmdline_p
);
311 /* Set sparc_cpu_model */
312 sparc_cpu_model
= sun_unknown
;
313 if(!strcmp(&cputypval
,"sun4 ")) { sparc_cpu_model
=sun4
; }
314 if(!strcmp(&cputypval
,"sun4c")) { sparc_cpu_model
=sun4c
; }
315 if(!strcmp(&cputypval
,"sun4m")) { sparc_cpu_model
=sun4m
; }
316 if(!strcmp(&cputypval
,"sun4s")) { sparc_cpu_model
=sun4m
; } /* CP-1200 with PROM 2.30 -E */
317 if(!strcmp(&cputypval
,"sun4d")) { sparc_cpu_model
=sun4d
; }
318 if(!strcmp(&cputypval
,"sun4e")) { sparc_cpu_model
=sun4e
; }
319 if(!strcmp(&cputypval
,"sun4u")) { sparc_cpu_model
=sun4u
; }
322 if (sparc_cpu_model
!= sun4
) {
323 prom_printf("This kernel is for Sun4 architecture only.\n");
328 sparc_cpu_model
=ap1000
;
329 strcpy(&cputypval
, "ap+");
333 switch(sparc_cpu_model
) {
358 register_console(&prom_console
);
363 printk("UNKNOWN!\n");
367 #ifdef CONFIG_DUMMY_CONSOLE
368 conswitchp
= &dummy_con
;
369 #elif defined(CONFIG_PROM_CONSOLE)
370 conswitchp
= &prom_con
;
372 boot_flags_init(*cmdline_p
);
378 total
= prom_probe_memory();
379 *memory_start_p
= PAGE_ALIGN(((unsigned long) &end
));
382 for(i
=0; sp_banks
[i
].num_bytes
!= 0; i
++) {
383 end_of_phys_memory
= sp_banks
[i
].base_addr
+
384 sp_banks
[i
].num_bytes
;
386 if (end_of_phys_memory
> memory_size
) {
387 sp_banks
[i
].num_bytes
-=
388 (end_of_phys_memory
- memory_size
);
389 end_of_phys_memory
= memory_size
;
390 sp_banks
[++i
].base_addr
= 0xdeadbeef;
391 sp_banks
[i
].num_bytes
= 0;
395 *memory_end_p
= (end_of_phys_memory
+ KERNBASE
);
397 srmmu_end_memory(memory_size
, memory_end_p
);
400 root_mountflags
&= ~MS_RDONLY
;
401 ROOT_DEV
= to_kdev_t(root_dev
);
402 #ifdef CONFIG_BLK_DEV_RAM
403 rd_image_start
= ram_flags
& RAMDISK_IMAGE_START_MASK
;
404 rd_prompt
= ((ram_flags
& RAMDISK_PROMPT_FLAG
) != 0);
405 rd_doload
= ((ram_flags
& RAMDISK_LOAD_FLAG
) != 0);
407 #ifdef CONFIG_BLK_DEV_INITRD
408 if (sparc_ramdisk_image
) {
409 initrd_start
= sparc_ramdisk_image
;
410 if (initrd_start
< KERNBASE
) initrd_start
+= KERNBASE
;
411 initrd_end
= initrd_start
+ sparc_ramdisk_size
;
412 if (initrd_end
> *memory_end_p
) {
413 printk(KERN_CRIT
"initrd extends beyond end of memory "
414 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
415 initrd_end
,*memory_end_p
);
418 if (initrd_start
>= *memory_start_p
&& initrd_start
< *memory_start_p
+ 2 * PAGE_SIZE
) {
419 initrd_below_start_ok
= 1;
420 *memory_start_p
= PAGE_ALIGN (initrd_end
);
421 } else if (initrd_start
&& sparc_ramdisk_image
< KERNBASE
) {
422 switch (sparc_cpu_model
) {
425 initrd_start
-= KERNBASE
;
426 initrd_end
-= KERNBASE
;
434 prom_setsync(prom_sync_me
);
436 #ifdef CONFIG_SUN_SERIAL
437 *memory_start_p
= sun_serial_setup(*memory_start_p
); /* set this up ASAP */
440 #if !CONFIG_SUN_SERIAL
443 switch (console_fb
) {
444 case 0: /* Let get our io devices from prom */
446 int idev
= prom_query_input_device();
447 int odev
= prom_query_output_device();
448 if (idev
== PROMDEV_IKBD
&& odev
== PROMDEV_OSCREEN
) {
450 } else if (idev
== PROMDEV_ITTYA
&& odev
== PROMDEV_OTTYA
) {
452 } else if (idev
== PROMDEV_ITTYB
&& odev
== PROMDEV_OTTYB
) {
454 } else if (idev
== PROMDEV_I_UNK
&& odev
== PROMDEV_OTTYA
) {
455 prom_printf("MrCoffee ttya\n");
457 } else if (idev
== PROMDEV_I_UNK
&& odev
== PROMDEV_OSCREEN
) {
459 prom_printf("MrCoffee keyboard\n");
461 prom_printf("Inconsistent or unknown console\n");
462 prom_printf("You cannot mix serial and non serial input/output devices\n");
467 case 1: serial_console
= 0; break; /* Force one of the framebuffers as console */
468 case 2: serial_console
= 1; break; /* Force ttya as console */
469 case 3: serial_console
= 2; break; /* Force ttyb as console */
474 if ((boot_flags
& BOOTME_KGDBA
)) {
477 if ((boot_flags
& BOOTME_KGDBB
)) {
481 if((boot_flags
&BOOTME_DEBUG
) && (linux_dbvec
!=0) &&
482 ((*(short *)linux_dbvec
) != -1)) {
483 printk("Booted under KADB. Syncing trap table.\n");
484 (*(linux_dbvec
->teach_debugger
))();
486 if((boot_flags
& BOOTME_KGDB
)) {
488 prom_printf ("Breakpoint!\n");
493 /* Due to stack alignment restrictions and assumptions... */
494 init_mm
.mmap
->vm_page_prot
= PAGE_SHARED
;
495 init_mm
.mmap
->vm_start
= KERNBASE
;
496 init_mm
.mmap
->vm_end
= *memory_end_p
;
497 init_mm
.context
= (unsigned long) NO_CONTEXT
;
498 init_task
.thread
.kregs
= &fake_swapper_regs
;
504 asmlinkage
int sys_ioperm(unsigned long from
, unsigned long num
, int on
)
509 /* BUFFER is PAGE_SIZE bytes long. */
511 extern char *sparc_cpu_type
[];
512 extern char *sparc_fpu_type
[];
514 int get_cpuinfo(char *buffer
)
516 int cpuid
=hard_smp_processor_id();
519 len
= sprintf(buffer
, "cpu\t\t: %s\n"
521 "promlib\t\t: Version %d Revision %d\n"
524 "ncpus probed\t: %d\n"
525 "ncpus active\t: %d\n"
527 "BogoMips\t: %lu.%02lu\n"
530 sparc_cpu_type
[cpuid
] ? : "undetermined",
531 sparc_fpu_type
[cpuid
] ? : "undetermined",
532 romvec
->pv_romvers
, prom_rev
, romvec
->pv_printrev
>> 16, (short)romvec
->pv_printrev
,
534 linux_num_cpus
, smp_num_cpus
536 , loops_per_sec
/500000, (loops_per_sec
/5000) % 100
540 len
+= smp_bogo_info(buffer
+ len
);
542 len
+= mmu_info(buffer
+ len
);
544 len
+= smp_info(buffer
+ len
);