1 /* head.S: The initial boot code for the Sparc port of Linux. 2 * 3 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 4 * 5 * This file has to serve three purposes. 6 * 7 * 1) determine the prom-version and cpu/architecture 8 * 2) print enough useful info before we start to execute 9 * c-code that I can possibly begin to debug things 10 * 3) Hold the vector of trap entry points 11 * 12 * The Sparc offers many challenges to kernel design. Here I will 13 * document those I have come across thus far. Upon bootup the boot 14 * prom loads your a.out image into memory. This memory the prom has 15 * already mapped for you in two places, however as far as I can tell 16 * the virtual address cache is not turned on although the MMU is 17 * translating things. You get loaded at 0x4000 exactly and you are 18 * aliased to 0xf8004000 with the appropriate mmu entries. So, when 19 * you link a boot-loadable object you want to do something like 20 * 21 * ld -e start -Ttext 4000 -o mykernel myobj1.o myobj2.o .... 22 * 23 * to produce a proper image. 24 * 25 * At boot time you are given (as far as I can tell at this time) 26 * one key to figure out what machine you are one and what devices 27 * are available. The prom when it loads you leaves a pointer to 28 * the 'rom vector' in register %o0 right before it jumps to your 29 * starting address. This is a pointer to a struct that is full of 30 * pointer to functions (ie. printf, halt, reboot), pointers to 31 * linked lists (ie. memory mappings), and pointer to empirical 32 * constants (ie. stdin and stdout magic cookies + rom version). 33 * Starting with this piece of information you can figure out 34 * just about anything you want about the machine you are on. 35 * 36 * Although I don't use it now, if you are on a Multiprocessor and 37 * therefore a v3 or above prom, register %o2 at boot contains a 38 * function pointer you must call before you proceed to invoke the 39 * other cpu's on the machine. I have no idea what kind of magic this 40 * is, give me time. 41 */ 42
43 #include <asm/cprefix.h>
44 #include <asm/head.h>
45 #include <linux/version.h>
46 #include <asm/asi.h>
47 #include <asm/contregs.h>
48 #include <asm/psr.h>
49 #include <asm/page.h>
50 #include <asm/kdebug.h>
51
52 .data
53
54 /* First thing to go in the data segment is the interrupt stack. */ 55
56 .globl C_LABEL(intstack)
57 .globl C_LABEL(eintstack)
58 .align 4
59 C_LABEL(intstack):
60 .skip 4 * PAGE_SIZE ! 16k = 128 128-byte stack frames
61 C_LABEL(eintstack):
62
63
64
65 /* 66 * The following are used with the prom_vector node-ops to figure out 67 * the cpu-type 68 */ 69
70 .align 4
71 .globl C_LABEL(cputyp)
72 C_LABEL(cputyp):
73 .word 1
74
75 .align 4
76 .globl C_LABEL(cputypval)
77 C_LABEL(cputypval):
78 .asciz "sun4c"
79 .ascii " "
80
81 C_LABEL(cputypvalend):
82 C_LABEL(cputypvallen) = C_LABEL(cputypvar) - C_LABEL(cputypval)
83
84 .align 4
85 /* 86 * Sun people can't spell worth damn. "compatability" indeed. 87 * At least we *know* we can't spell, and use a spell-checker. 88 */ 89
90 /* Uh, actually Linus it is I who cannot spell. Too much murky 91 * Sparc assembly will do this to ya. 92 */ 93 C_LABEL(cputypvar):
94 .asciz "compatability"
95
96 /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. --P3 */ 97 .align 4
98 C_LABEL(cputypvar_sun4m):
99 .asciz "compatible"
100
101 /* WARNING: evil messages follow */ 102
103 .align 4
104
105 sun4_notsup:
106 .asciz "Sparc-Linux sun4 support not implemented yet\n\n"
107 .align 4
108
109 sun4d_notsup:
110 .asciz "Sparc-Linux sun4d support does not exist\n\n"
111 .align 4
112
113 sun4e_notsup:
114 .asciz "Sparc-Linux sun4e support does not exist\n\n"
115 .align 4
116
117 sun4u_notsup:
118 .asciz "Sparc-Linux sun4u support does not exist\n\n"
119 .align 4
120
121 /* Ok, things start to get interesting. We get linked such that 'start' 122 * is the entry symbol. However, it is real low in kernel address space 123 * and as such a nifty place to place the trap table. We achieve this goal 124 * by just jumping to 'gokernel' for the first trap's entry as the sparc 125 * never receives the zero trap as it is real special (hw reset). 126 * 127 * Each trap entry point is the size of 4 sparc instructions (or 4 bytes 128 * * 4 insns = 16 bytes). There are 128 hardware traps (some undefined 129 * or unimplemented) and 128 software traps (sys-calls, etc.). 130 * 131 * One of the instructions must be a branch. More often than not this 132 * will be to a trap handler entry point because it is completely 133 * impossible to handle any trap in 4 insns. I welcome anyone to 134 * challenge this theory. :-) 135 * 136 * On entry into this table the hardware has loaded the program counter 137 * at which the trap occurred into register %l1 and the next program 138 * counter into %l2, this way we can return from the trap with a simple 139 * 140 * jmp %l1; rett %l2 ! poof... 141 * 142 * after properly servicing the trap. It wouldn't be a bad idea to load 143 * some more information into the local regs since we have technically 144 * 2 or 3 instructions to play with besides the jmp to the 'real' trap 145 * handler (one can even go in the delay slot). For now I am going to put 146 * the %psr (processor status register) and the trap-type value in %l0 147 * and %l3 respectively. Also, for IRQ's I'll put the level in %l4. 148 */ 149
150 .text
151
152 .globl start
153 .globl _start /* warning, solaris hack */ 154 .globl C_LABEL(trapbase)
155 _start: /* danger danger */ 156 start:
157 C_LABEL(trapbase):
158 /* XXX Grrr, this table is basically sun4c specific, sort of... XXX */ 159 /* We get control passed to us here at t_zero. */ 160 t_zero: b gokernel; nop; nop; nop;
161
162 t_tflt: TRAP_ENTRY(0x1, sparc_text_fault) /* Inst. Access Exception */ 163 t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ 164 t_pins: TRAP_ENTRY(0x3, bad_instruction) /* Privileged Instruction */ 165 t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ 166 t_wovf: TRAP_ENTRY(0x5, spill_window_entry) /* Window Overflow */ 167 t_wunf: TRAP_ENTRY(0x6, fill_window_entry) /* Window Underflow */ 168 t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ 169 t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ 170 t_dflt: TRAP_ENTRY(0x9, sparc_data_fault) /* Data Miss Exception */ 171 t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ 172 t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ 173 t_badc: TRAP_ENTRY(0xc, bad_trap_handler) /* Undefined... */ 174 t_badd: TRAP_ENTRY(0xd, bad_trap_handler) /* Undefined... */ 175 t_bade: TRAP_ENTRY(0xe, bad_trap_handler) /* Undefined... */ 176 t_badf: TRAP_ENTRY(0xf, bad_trap_handler) /* Undefined... */ 177 t_bad10:TRAP_ENTRY(0x10, bad_trap_handler) /* Undefined... */ 178 t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ 179 t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ 180 t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ 181 t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ 182 t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ 183 t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ 184 t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ 185 t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ 186 t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ 187 t_irq10:TRAP_ENTRY_TIMER /* IRQ Timer #1 (one we use) */ 188 t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ 189 t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ 190 t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ 191 t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ 192 t_nmi: NMI_TRAP /* Level 15 (NMI) */ 193 t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ 194 t_iacce:TRAP_ENTRY(0x21, do_iacc_error) /* Instruction Access Error */ 195 t_bad22:TRAP_ENTRY(0x22, bad_trap_handler) /* Undefined... */ 196 t_bad23:TRAP_ENTRY(0x23, bad_trap_handler) /* Undefined... */ 197 t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ 198 t_uflsh:TRAP_ENTRY(0x25, do_bad_flush) /* Unimplemented FLUSH inst. */ 199 t_bad26:TRAP_ENTRY(0x26, bad_trap_handler) /* Undefined... */ 200 t_bad27:TRAP_ENTRY(0x27, bad_trap_handler) /* Undefined... */ 201 t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ 202 t_dacce:TRAP_ENTRY(0x29, do_dacc_error) /* Data Access Error */ 203 t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ 204 t_dserr:TRAP_ENTRY(0x2b, do_dstore_err) /* Data Store Error */ 205 t_daccm:TRAP_ENTRY(0x2c, do_dacc_mmu_miss) /* Data Access MMU-Miss */ 206 t_bad2d:TRAP_ENTRY(0x2d, bad_trap_handler) /* Undefined... */ 207 t_bad2e:TRAP_ENTRY(0x2e, bad_trap_handler) /* Undefined... */ 208 t_bad2f:TRAP_ENTRY(0x2f, bad_trap_handler) /* Undefined... */ 209 t_bad30:TRAP_ENTRY(0x30, bad_trap_handler) /* Undefined... */ 210 t_bad31:TRAP_ENTRY(0x31, bad_trap_handler) /* Undefined... */ 211 t_bad32:TRAP_ENTRY(0x32, bad_trap_handler) /* Undefined... */ 212 t_bad33:TRAP_ENTRY(0x33, bad_trap_handler) /* Undefined... */ 213 t_bad34:TRAP_ENTRY(0x34, bad_trap_handler) /* Undefined... */ 214 t_bad35:TRAP_ENTRY(0x35, bad_trap_handler) /* Undefined... */ 215 t_bad36:TRAP_ENTRY(0x36, bad_trap_handler) /* Undefined... */ 216 t_bad37:TRAP_ENTRY(0x37, bad_trap_handler) /* Undefined... */ 217 t_bad38:TRAP_ENTRY(0x38, bad_trap_handler) /* Undefined... */ 218 t_bad39:TRAP_ENTRY(0x39, bad_trap_handler) /* Undefined... */ 219 t_bad3a:TRAP_ENTRY(0x3a, bad_trap_handler) /* Undefined... */ 220 t_bad3b:TRAP_ENTRY(0x3b, bad_trap_handler) /* Undefined... */ 221 t_iaccm:TRAP_ENTRY(0x3c, do_iacc_mmu_miss) /* Instruction Access MMU-Miss */ 222 t_bad3d:TRAP_ENTRY(0x3d, bad_trap_handler) /* Undefined... */ 223 t_bad3e:TRAP_ENTRY(0x3e, bad_trap_handler) /* Undefined... */ 224 t_bad3f:TRAP_ENTRY(0x3f, bad_trap_handler) /* Undefined... */ 225 t_bad40:TRAP_ENTRY(0x40, bad_trap_handler) /* Undefined... */ 226 t_bad41:TRAP_ENTRY(0x41, bad_trap_handler) /* Undefined... */ 227 t_bad42:TRAP_ENTRY(0x42, bad_trap_handler) /* Undefined... */ 228 t_bad43:TRAP_ENTRY(0x43, bad_trap_handler) /* Undefined... */ 229 t_bad44:TRAP_ENTRY(0x44, bad_trap_handler) /* Undefined... */ 230 t_bad45:TRAP_ENTRY(0x45, bad_trap_handler) /* Undefined... */ 231 t_bad46:TRAP_ENTRY(0x46, bad_trap_handler) /* Undefined... */ 232 t_bad47:TRAP_ENTRY(0x47, bad_trap_handler) /* Undefined... */ 233 t_bad48:TRAP_ENTRY(0x48, bad_trap_handler) /* Undefined... */ 234 t_bad49:TRAP_ENTRY(0x49, bad_trap_handler) /* Undefined... */ 235 t_bad4a:TRAP_ENTRY(0x4a, bad_trap_handler) /* Undefined... */ 236 t_bad4b:TRAP_ENTRY(0x4b, bad_trap_handler) /* Undefined... */ 237 t_bad4c:TRAP_ENTRY(0x4c, bad_trap_handler) /* Undefined... */ 238 t_bad4d:TRAP_ENTRY(0x4d, bad_trap_handler) /* Undefined... */ 239 t_bad4e:TRAP_ENTRY(0x4e, bad_trap_handler) /* Undefined... */ 240 t_bad4f:TRAP_ENTRY(0x4f, bad_trap_handler) /* Undefined... */ 241 t_bad50:TRAP_ENTRY(0x50, bad_trap_handler) /* Undefined... */ 242 t_bad51:TRAP_ENTRY(0x51, bad_trap_handler) /* Undefined... */ 243 t_bad52:TRAP_ENTRY(0x52, bad_trap_handler) /* Undefined... */ 244 t_bad53:TRAP_ENTRY(0x53, bad_trap_handler) /* Undefined... */ 245 t_bad54:TRAP_ENTRY(0x54, bad_trap_handler) /* Undefined... */ 246 t_bad55:TRAP_ENTRY(0x55, bad_trap_handler) /* Undefined... */ 247 t_bad56:TRAP_ENTRY(0x56, bad_trap_handler) /* Undefined... */ 248 t_bad57:TRAP_ENTRY(0x57, bad_trap_handler) /* Undefined... */ 249 t_bad58:TRAP_ENTRY(0x58, bad_trap_handler) /* Undefined... */ 250 t_bad59:TRAP_ENTRY(0x59, bad_trap_handler) /* Undefined... */ 251 t_bad5a:TRAP_ENTRY(0x5a, bad_trap_handler) /* Undefined... */ 252 t_bad5b:TRAP_ENTRY(0x5b, bad_trap_handler) /* Undefined... */ 253 t_bad5c:TRAP_ENTRY(0x5c, bad_trap_handler) /* Undefined... */ 254 t_bad5d:TRAP_ENTRY(0x5d, bad_trap_handler) /* Undefined... */ 255 t_bad5e:TRAP_ENTRY(0x5e, bad_trap_handler) /* Undefined... */ 256 t_bad5f:TRAP_ENTRY(0x5f, bad_trap_handler) /* Undefined... */ 257 t_bad60:TRAP_ENTRY(0x60, bad_trap_handler) /* Impl-Dep Exception */ 258 t_bad61:TRAP_ENTRY(0x61, bad_trap_handler) /* Impl-Dep Exception */ 259 t_bad62:TRAP_ENTRY(0x62, bad_trap_handler) /* Impl-Dep Exception */ 260 t_bad63:TRAP_ENTRY(0x63, bad_trap_handler) /* Impl-Dep Exception */ 261 t_bad64:TRAP_ENTRY(0x64, bad_trap_handler) /* Impl-Dep Exception */ 262 t_bad65:TRAP_ENTRY(0x65, bad_trap_handler) /* Impl-Dep Exception */ 263 t_bad66:TRAP_ENTRY(0x66, bad_trap_handler) /* Impl-Dep Exception */ 264 t_bad67:TRAP_ENTRY(0x67, bad_trap_handler) /* Impl-Dep Exception */ 265 t_bad68:TRAP_ENTRY(0x68, bad_trap_handler) /* Impl-Dep Exception */ 266 t_bad69:TRAP_ENTRY(0x69, bad_trap_handler) /* Impl-Dep Exception */ 267 t_bad6a:TRAP_ENTRY(0x6a, bad_trap_handler) /* Impl-Dep Exception */ 268 t_bad6b:TRAP_ENTRY(0x6b, bad_trap_handler) /* Impl-Dep Exception */ 269 t_bad6c:TRAP_ENTRY(0x6c, bad_trap_handler) /* Impl-Dep Exception */ 270 t_bad6d:TRAP_ENTRY(0x6d, bad_trap_handler) /* Impl-Dep Exception */ 271 t_bad6e:TRAP_ENTRY(0x6e, bad_trap_handler) /* Impl-Dep Exception */ 272 t_bad6f:TRAP_ENTRY(0x6f, bad_trap_handler) /* Impl-Dep Exception */ 273 t_bad70:TRAP_ENTRY(0x70, bad_trap_handler) /* Impl-Dep Exception */ 274 t_bad71:TRAP_ENTRY(0x71, bad_trap_handler) /* Impl-Dep Exception */ 275 t_bad72:TRAP_ENTRY(0x72, bad_trap_handler) /* Impl-Dep Exception */ 276 t_bad73:TRAP_ENTRY(0x73, bad_trap_handler) /* Impl-Dep Exception */ 277 t_bad74:TRAP_ENTRY(0x74, bad_trap_handler) /* Impl-Dep Exception */ 278 t_bad75:TRAP_ENTRY(0x75, bad_trap_handler) /* Impl-Dep Exception */ 279 t_bad76:TRAP_ENTRY(0x76, bad_trap_handler) /* Impl-Dep Exception */ 280 t_bad77:TRAP_ENTRY(0x77, bad_trap_handler) /* Impl-Dep Exception */ 281 t_bad78:TRAP_ENTRY(0x78, bad_trap_handler) /* Impl-Dep Exception */ 282 t_bad79:TRAP_ENTRY(0x79, bad_trap_handler) /* Impl-Dep Exception */ 283 t_bad7a:TRAP_ENTRY(0x7a, bad_trap_handler) /* Impl-Dep Exception */ 284 t_bad7b:TRAP_ENTRY(0x7b, bad_trap_handler) /* Impl-Dep Exception */ 285 t_bad7c:TRAP_ENTRY(0x7c, bad_trap_handler) /* Impl-Dep Exception */ 286 t_bad7d:TRAP_ENTRY(0x7d, bad_trap_handler) /* Impl-Dep Exception */ 287 t_bad7e:TRAP_ENTRY(0x7e, bad_trap_handler) /* Impl-Dep Exception */ 288 t_bad7f:TRAP_ENTRY(0x7f, bad_trap_handler) /* Impl-Dep Exception */ 289 t_sunos:SUNOS_SYSCALL_TRAP /* SunOS System Call */ 290 t_sbkpt:TRAP_ENTRY(0x81, bad_trap_handler) /* Software Breakpoint */ 291 t_divz: TRAP_ENTRY(0x82, bad_trap_handler) /* Divide by zero trap */ 292 t_flwin:TRAP_ENTRY(0x83, bad_trap_handler) /* Flush Windows Trap */ 293 t_clwin:TRAP_ENTRY(0x84, bad_trap_handler) /* Clean Windows Trap */ 294 t_rchk: TRAP_ENTRY(0x85, bad_trap_handler) /* Range Check */ 295 t_funal:TRAP_ENTRY(0x86, bad_trap_handler) /* Fix Unaligned Access Trap */ 296 t_iovf: TRAP_ENTRY(0x87, bad_trap_handler) /* Integer Overflow Trap */ 297 t_slowl:SOLARIS_SYSCALL_TRAP /* Slowaris System Call */ 298 t_netbs:NETBSD_SYSCALL_TRAP /* Net-B.S. System Call */ 299 t_bad8a:TRAP_ENTRY(0x8a, bad_trap_handler) /* Software Trap */ 300 t_bad8b:TRAP_ENTRY(0x8b, bad_trap_handler) /* Software Trap */ 301 t_bad8c:TRAP_ENTRY(0x8c, bad_trap_handler) /* Software Trap */ 302 t_bad8d:TRAP_ENTRY(0x8d, bad_trap_handler) /* Software Trap */ 303 t_bad8e:TRAP_ENTRY(0x8e, bad_trap_handler) /* Software Trap */ 304 t_bad8f:TRAP_ENTRY(0x8f, bad_trap_handler) /* Software Trap */ 305 t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ 306 t_bad91:TRAP_ENTRY(0x91, bad_trap_handler) /* Software Trap */ 307 t_bad92:TRAP_ENTRY(0x92, bad_trap_handler) /* Software Trap */ 308 t_bad93:TRAP_ENTRY(0x93, bad_trap_handler) /* Software Trap */ 309 t_bad94:TRAP_ENTRY(0x94, bad_trap_handler) /* Software Trap */ 310 t_bad95:TRAP_ENTRY(0x95, bad_trap_handler) /* Software Trap */ 311 t_bad96:TRAP_ENTRY(0x96, bad_trap_handler) /* Software Trap */ 312 t_bad97:TRAP_ENTRY(0x97, bad_trap_handler) /* Software Trap */ 313 t_bad98:TRAP_ENTRY(0x98, bad_trap_handler) /* Software Trap */ 314 t_bad99:TRAP_ENTRY(0x99, bad_trap_handler) /* Software Trap */ 315 t_bad9a:TRAP_ENTRY(0x9a, bad_trap_handler) /* Software Trap */ 316 t_bad9b:TRAP_ENTRY(0x9b, bad_trap_handler) /* Software Trap */ 317 t_bad9c:TRAP_ENTRY(0x9c, bad_trap_handler) /* Software Trap */ 318 t_bad9d:TRAP_ENTRY(0x9d, bad_trap_handler) /* Software Trap */ 319 t_bad9e:TRAP_ENTRY(0x9e, bad_trap_handler) /* Software Trap */ 320 t_bad9f:TRAP_ENTRY(0x9f, bad_trap_handler) /* Software Trap */ 321 t_getcc:GETCC_TRAP /* Get Condition Codes */ 322 t_setcc:SETCC_TRAP /* Set Condition Codes */ 323 t_bada2:TRAP_ENTRY(0xa2, bad_trap_handler) /* Software Trap */ 324 t_bada3:TRAP_ENTRY(0xa3, bad_trap_handler) /* Software Trap */ 325 t_bada4:TRAP_ENTRY(0xa4, bad_trap_handler) /* Software Trap */ 326 t_bada5:TRAP_ENTRY(0xa5, bad_trap_handler) /* Software Trap */ 327 t_bada6:TRAP_ENTRY(0xa6, bad_trap_handler) /* Software Trap */ 328 t_bada7:TRAP_ENTRY(0xa7, bad_trap_handler) /* Software Trap */ 329 t_bada8:TRAP_ENTRY(0xa8, bad_trap_handler) /* Software Trap */ 330 t_bada9:TRAP_ENTRY(0xa9, bad_trap_handler) /* Software Trap */ 331 t_badaa:TRAP_ENTRY(0xaa, bad_trap_handler) /* Software Trap */ 332 t_badab:TRAP_ENTRY(0xab, bad_trap_handler) /* Software Trap */ 333 t_badac:TRAP_ENTRY(0xac, bad_trap_handler) /* Software Trap */ 334 t_badad:TRAP_ENTRY(0xad, bad_trap_handler) /* Software Trap */ 335 t_badae:TRAP_ENTRY(0xae, bad_trap_handler) /* Software Trap */ 336 t_badaf:TRAP_ENTRY(0xaf, bad_trap_handler) /* Software Trap */ 337 t_badb0:TRAP_ENTRY(0xb0, bad_trap_handler) /* Software Trap */ 338 t_badb1:TRAP_ENTRY(0xb1, bad_trap_handler) /* Software Trap */ 339 t_badb2:TRAP_ENTRY(0xb2, bad_trap_handler) /* Software Trap */ 340 t_badb3:TRAP_ENTRY(0xb3, bad_trap_handler) /* Software Trap */ 341 t_badb4:TRAP_ENTRY(0xb4, bad_trap_handler) /* Software Trap */ 342 t_badb5:TRAP_ENTRY(0xb5, bad_trap_handler) /* Software Trap */ 343 t_badb6:TRAP_ENTRY(0xb6, bad_trap_handler) /* Software Trap */ 344 t_badb7:TRAP_ENTRY(0xb7, bad_trap_handler) /* Software Trap */ 345 t_badb8:TRAP_ENTRY(0xb8, bad_trap_handler) /* Software Trap */ 346 t_badb9:TRAP_ENTRY(0xb9, bad_trap_handler) /* Software Trap */ 347 t_badba:TRAP_ENTRY(0xba, bad_trap_handler) /* Software Trap */ 348 t_badbb:TRAP_ENTRY(0xbb, bad_trap_handler) /* Software Trap */ 349 t_badbc:TRAP_ENTRY(0xbc, bad_trap_handler) /* Software Trap */ 350 t_badbd:TRAP_ENTRY(0xbd, bad_trap_handler) /* Software Trap */ 351 t_badbe:TRAP_ENTRY(0xbe, bad_trap_handler) /* Software Trap */ 352 t_badbf:TRAP_ENTRY(0xbf, bad_trap_handler) /* Software Trap */ 353 t_badc0:TRAP_ENTRY(0xc0, bad_trap_handler) /* Software Trap */ 354 t_badc1:TRAP_ENTRY(0xc1, bad_trap_handler) /* Software Trap */ 355 t_badc2:TRAP_ENTRY(0xc2, bad_trap_handler) /* Software Trap */ 356 t_badc3:TRAP_ENTRY(0xc3, bad_trap_handler) /* Software Trap */ 357 t_badc4:TRAP_ENTRY(0xc4, bad_trap_handler) /* Software Trap */ 358 t_badc5:TRAP_ENTRY(0xc5, bad_trap_handler) /* Software Trap */ 359 t_badc6:TRAP_ENTRY(0xc6, bad_trap_handler) /* Software Trap */ 360 t_badc7:TRAP_ENTRY(0xc7, bad_trap_handler) /* Software Trap */ 361 t_badc8:TRAP_ENTRY(0xc8, bad_trap_handler) /* Software Trap */ 362 t_badc9:TRAP_ENTRY(0xc9, bad_trap_handler) /* Software Trap */ 363 t_badca:TRAP_ENTRY(0xca, bad_trap_handler) /* Software Trap */ 364 t_badcb:TRAP_ENTRY(0xcb, bad_trap_handler) /* Software Trap */ 365 t_badcc:TRAP_ENTRY(0xcc, bad_trap_handler) /* Software Trap */ 366 t_badcd:TRAP_ENTRY(0xcd, bad_trap_handler) /* Software Trap */ 367 t_badce:TRAP_ENTRY(0xce, bad_trap_handler) /* Software Trap */ 368 t_badcf:TRAP_ENTRY(0xcf, bad_trap_handler) /* Software Trap */ 369 t_badd0:TRAP_ENTRY(0xd0, bad_trap_handler) /* Software Trap */ 370 t_badd1:TRAP_ENTRY(0xd1, bad_trap_handler) /* Software Trap */ 371 t_badd2:TRAP_ENTRY(0xd2, bad_trap_handler) /* Software Trap */ 372 t_badd3:TRAP_ENTRY(0xd3, bad_trap_handler) /* Software Trap */ 373 t_badd4:TRAP_ENTRY(0xd4, bad_trap_handler) /* Software Trap */ 374 t_badd5:TRAP_ENTRY(0xd5, bad_trap_handler) /* Software Trap */ 375 t_badd6:TRAP_ENTRY(0xd6, bad_trap_handler) /* Software Trap */ 376 t_badd7:TRAP_ENTRY(0xd7, bad_trap_handler) /* Software Trap */ 377 t_badd8:TRAP_ENTRY(0xd8, bad_trap_handler) /* Software Trap */ 378 t_badd9:TRAP_ENTRY(0xd9, bad_trap_handler) /* Software Trap */ 379 t_badda:TRAP_ENTRY(0xda, bad_trap_handler) /* Software Trap */ 380 t_baddb:TRAP_ENTRY(0xdb, bad_trap_handler) /* Software Trap */ 381 t_baddc:TRAP_ENTRY(0xdc, bad_trap_handler) /* Software Trap */ 382 t_baddd:TRAP_ENTRY(0xdd, bad_trap_handler) /* Software Trap */ 383 t_badde:TRAP_ENTRY(0xde, bad_trap_handler) /* Software Trap */ 384 t_baddf:TRAP_ENTRY(0xdf, bad_trap_handler) /* Software Trap */ 385 t_bade0:TRAP_ENTRY(0xe0, bad_trap_handler) /* Software Trap */ 386 t_bade1:TRAP_ENTRY(0xe1, bad_trap_handler) /* Software Trap */ 387 t_bade2:TRAP_ENTRY(0xe2, bad_trap_handler) /* Software Trap */ 388 t_bade3:TRAP_ENTRY(0xe3, bad_trap_handler) /* Software Trap */ 389 t_bade4:TRAP_ENTRY(0xe4, bad_trap_handler) /* Software Trap */ 390 t_bade5:TRAP_ENTRY(0xe5, bad_trap_handler) /* Software Trap */ 391 t_bade6:TRAP_ENTRY(0xe6, bad_trap_handler) /* Software Trap */ 392 t_bade7:TRAP_ENTRY(0xe7, bad_trap_handler) /* Software Trap */ 393 t_bade8:TRAP_ENTRY(0xe8, bad_trap_handler) /* Software Trap */ 394 t_bade9:TRAP_ENTRY(0xe9, bad_trap_handler) /* Software Trap */ 395 t_badea:TRAP_ENTRY(0xea, bad_trap_handler) /* Software Trap */ 396 t_badeb:TRAP_ENTRY(0xeb, bad_trap_handler) /* Software Trap */ 397 t_badec:TRAP_ENTRY(0xec, bad_trap_handler) /* Software Trap */ 398 t_baded:TRAP_ENTRY(0xed, bad_trap_handler) /* Software Trap */ 399 t_badee:TRAP_ENTRY(0xee, bad_trap_handler) /* Software Trap */ 400 t_badef:TRAP_ENTRY(0xef, bad_trap_handler) /* Software Trap */ 401 t_badf0:TRAP_ENTRY(0xf0, bad_trap_handler) /* Software Trap */ 402 t_badf1:TRAP_ENTRY(0xf1, bad_trap_handler) /* Software Trap */ 403 t_badf2:TRAP_ENTRY(0xf2, bad_trap_handler) /* Software Trap */ 404 t_badf3:TRAP_ENTRY(0xf3, bad_trap_handler) /* Software Trap */ 405 t_badf4:TRAP_ENTRY(0xf4, bad_trap_handler) /* Software Trap */ 406 t_badf5:TRAP_ENTRY(0xf5, bad_trap_handler) /* Software Trap */ 407 t_badf6:TRAP_ENTRY(0xf6, bad_trap_handler) /* Software Trap */ 408 t_badf7:TRAP_ENTRY(0xf7, bad_trap_handler) /* Software Trap */ 409 t_badf8:TRAP_ENTRY(0xf8, bad_trap_handler) /* Software Trap */ 410 t_badf9:TRAP_ENTRY(0xf9, bad_trap_handler) /* Software Trap */ 411 t_badfa:TRAP_ENTRY(0xfa, bad_trap_handler) /* Software Trap */ 412 t_badfb:TRAP_ENTRY(0xfb, bad_trap_handler) /* Software Trap */ 413 t_badfc:TRAP_ENTRY(0xfc, bad_trap_handler) /* Software Trap */ 414 t_badfd:TRAP_ENTRY(0xfd, bad_trap_handler) /* Software Trap */ 415 dbtrap: TRAP_ENTRY(0xfe, bad_trap_handler) /* Debugger/PROM breakpoint #1 */ 416 dbtrap2:TRAP_ENTRY(0xff, bad_trap_handler) /* Debugger/PROM breakpoint #2 */ 417
418 .globl C_LABEL(end_traptable)
419 C_LABEL(end_traptable):
420
421 .skip 4096
422
423 /* This was the only reasonable way I could think of to properly align 424 * these page-table data structures. 425 * 426 * XXX swapper_pg_dir is going to have to be 'per-CPU' for SMP support 427 */ 428
429 .globl C_LABEL(auxio_reg_addr)
430 C_LABEL(auxio_reg_addr): .skip (PAGE_SIZE)
431
432 .globl C_LABEL(clock_reg_addr)
433 C_LABEL(clock_reg_addr): .skip (PAGE_SIZE*5)
434
435 .globl C_LABEL(int_reg_addr)
436 C_LABEL(int_reg_addr): .skip (PAGE_SIZE*5)
437
438 .globl C_LABEL(pg0)
439 .globl C_LABEL(empty_bad_page)
440 .globl C_LABEL(empty_bad_page_table)
441 .globl C_LABEL(empty_zero_page)
442 .globl C_LABEL(swapper_pg_dir)
443 C_LABEL(swapper_pg_dir): .skip 0x1000
444 C_LABEL(pg0): .skip 0x1000
445 C_LABEL(empty_bad_page): .skip 0x1000
446 C_LABEL(empty_bad_page_table): .skip 0x1000
447 C_LABEL(empty_zero_page): .skip 0x1000
448
449
450 /* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in 451 * %g7 and at prom_vector_p. And also quickly check whether we are on 452 * a v0, v2, or v3 prom. We also get a debug structure of some sort from 453 * the boot loader (or is it the prom?) in %o1. Finally a call back vector 454 * is passed in %o2. I think this is how you register yourself with a 455 * debugger. I do know that it wants my %o7 (return PC - 8) as it's 456 * first argument. I will poke around and figure out what the debug 457 * vector is, it could contain useful stuff. 458 */ 459
460 /* Grrr, in order to be Sparc ABI complient, the kernel has to live in 461 * an address space above 0xe0000000 ;( Must remain position independant 462 * until we 'remap' ourselves from low to high addresses. We only map the 463 * first 3MB of addresses into upper ram as that is how much the PROM 464 * promises to set up for us. 465 */ 466 gokernel:
467 /* Ok, it's nice to know, as early as possible, if we 468 * are already mapped where we expect to be in virtual 469 * memory. The Solaris /boot elf format bootloader 470 * will peek into our elf header and load us where 471 * we want to be, otherwise we have to re-map. 472 * 473 * Some boot loaders don't place the jmp'rs address 474 * in %o7, so we do a pc-relative call to a local 475 * label, then see what %o7 has. 476 */ 477
478 /* XXX Sparc V9 detection goes here XXX */ 479
480 or %g0, %o7, %g4 ! Save %o7
481
482 /* Jump to it, and pray... */ 483 current_pc:
484 call 1f
485 nop
486
487 1:
488 or %g0, %o7, %g3
489
490 got_pc:
491 or %g0, %g4, %o7 /* Previous %o7. */ 492
493 or %g0, %o0, %l0 ! stash away romvec
494 or %g0, %o0, %g7 ! put it here too
495 or %g0, %o1, %l1 ! stash away debug_vec too
496 rd %psr, %l2 ! Save psr
497 rd %wim, %l3 ! wim
498 rd %tbr, %l4 ! tbr
499 or %g0, %o2, %l5 ! and the possible magic func
500
501 /* Ok, let's check out our run time program counter. */ 502 set current_pc, %g5
503 cmp %g3, %g5
504 be already_mapped
505
506 /* %l6 will hold the offset we have to subtract 507 * from absolute symbols in order to access areas 508 * in our own image. If already mapped this is 509 * just plain zero, else it is PAGE_OFFSET which is 510 * also KERNBASE. 511 */ 512 set PAGE_OFFSET, %l6
513 b copy_prom_lvl14
514 nop
515
516 already_mapped:
517 or %g0, %g0, %l6
518
519 /* Copy over the Prom's level 14 clock handler. */ 520 copy_prom_lvl14:
521 rd %tbr, %g1
522 andn %g1, 0xfff, %g1 ! proms trap table base
523 or %g0, (0x1e<<4), %g2 ! offset to lvl14 intr
524 or %g1, %g2, %g2
525 set t_irq14, %g3
526 sub %g3, %l6, %g3
527 ldd [%g2], %g4
528 std %g4, [%g3]
529 ldd [%g2 + 0x8], %g4
530 std %g4, [%g3 + 0x8] ! Copy proms handler
531
532 /* Copy over the Prom/debugger's trap entry points. */ 533 copy_prom_bpoint:
534 or %g0, (0xfe<<4), %g2
535 or %g1, %g2, %g2
536 set dbtrap, %g3
537 sub %g3, %l6, %g3
538 ldd [%g2], %g4
539 std %g4, [%g3]
540 ldd [%g2 + 0x8], %g4
541 std %g4, [%g3 + 0x8]
542 ldd [%g2 + 0x10], %g4
543 std %g4, [%g3 + 0x10]
544 ldd [%g2 + 0x18], %g4
545 std %g4, [%g3 + 0x18]
546
547 copy_prom_done:
548 ld [%o0 + 0x4], %g1
549 and %g1, 0x3, %g1
550 subcc %g1, 0x0, %g0
551 be set_sane_psr ! Not on v0 proms
552 nop
553
554 subcc %o2, 0x0, %g0 ! check for boot routine pointer
555 bz set_sane_psr
556 nop
557 jmpl %o2, %o7 ! call boot setup func
558 add %o7, 0x8, %o0
559
560 set_sane_psr:
561 /* Traps are on, kadb can be tracing through here. But 562 * we have no clue what the PIL is. So we set up a sane 563 * %psr, but preserve CWP or our locals could disappear! 564 */ 565 rd %psr, %g2
566 and %g2, 0x1f, %g2 ! %g2 has CWP now
567 set (PSR_S|PSR_PIL), %g1 ! Supervisor + PIL high
568 or %g1, %g2, %g1 ! mix mix mix
569 wr %g1, 0x0, %psr ! let PIL set in
570 wr %g1, PSR_ET, %psr ! now turn on traps
571
572 /* A note about the last two instructions... 573 * If you are going to increase PIL and turn on 574 * traps at the same time you are asking for trouble. 575 * You MUST set a %psr with traps off containing 576 * your new PIL, then turn on the ET bit with the 577 * next write. On certain buggy Sparc chips if you 578 * set both at the same time you can get a Watchdog 579 * Reset under certain conditions. This is no fun. 580 * Basically the PIL bits get there before the 581 * EnableTrap bit does or something like that. 582 */ 583
584 /* Insane asylum... */ 585 WRITE_PAUSE
586
587 /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT 588 * MMU so we can remap ourselves properly. DONT TOUCH %l0 thru %l5 in these 589 * remapping routines, we need their values afterwards! 590 * 591 * XXX UGH, need to write some sun4u SpitFire remapping V9 code RSN... XXX 592 */ 593 /* Now check whether we are already mapped, if we 594 * are we can skip all this garbage coming up. 595 */ 596 subcc %l6, 0x0, %g0
597 bz go_to_highmem ! this will be a nop then
598 nop
599
600 sethi %hi(LOAD_ADDR), %g6
601 subcc %g7, %g6, %g0
602 bne remap_not_a_sun4 ! This is not a Sun4
603 nop
604
605 or %g0, 0x1, %g1
606 lduba [%g1] ASI_CONTROL, %g1 ! Only safe to try on Sun4.
607 subcc %g1, 0x24, %g0 ! Is this a mutant Sun4/400???
608 be sun4_mutant_remap ! Ugh, it is...
609 nop
610
611 remap_not_a_sun4:
612 lda [%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c
613 and %g1, 0x1, %g1 ! Test SRMMU Enable bit ;-)
614 subcc %g1, 0x0, %g0
615 bz sun4c_remap ! A sun4c MMU or normal Sun4
616 nop
617 srmmu_remap:
618 /* First, check for a viking (TI) module. */ 619 set 0x40000000, %g2
620 rd %psr, %g3
621 and %g2, %g3, %g3
622 subcc %g3, 0x0, %g0
623 bz srmmu_nviking
624 nop
625
626 /* Figure out what kind of viking we are on. 627 * We need to know if we have to play with the 628 * AC bit and disable traps or not. 629 */ 630
631 /* I've only seen MicroSparc's on SparcClassics with this 632 * bit set. 633 */ 634 set 0x800, %g2
635 lda [%g0] ASI_M_MMUREGS, %g3 ! peek in the control reg
636 and %g2, %g3, %g3
637 subcc %g3, 0x0, %g0
638 bnz srmmu_nviking ! is in mbus mode
639 nop
640
641 rd %psr, %g3 ! DONT TOUCH %g3
642 andn %g3, PSR_ET, %g2
643 wr %g2, 0x0, %psr
644 WRITE_PAUSE
645
646 /* Get context table pointer, then convert to 647 * a physical address, which is 36 bits. 648 */ 649 set AC_M_CTPR, %g4
650 lda [%g4] ASI_M_MMUREGS, %g4
651 sll %g4, 0x4, %g4 ! We use this below
652 ! DONT TOUCH %g4
653
654 /* Set the AC bit in the Viking's MMU control reg. */ 655 lda [%g0] ASI_M_MMUREGS, %g5 ! DONT TOUCH %g5
656 set 0x8000, %g6 ! AC bit mask
657 or %g5, %g6, %g6 ! Or it in...
658 sta %g6, [%g0] ASI_M_MMUREGS ! Close your eyes...
659
660 /* Grrr, why does it seem like every other load/store 661 * on the sun4m is in some ASI space... 662 * Fine with me, let's get the pointer to the level 1 663 * page table directory and fetch it's entry. 664 */ 665 lda [%g4] ASI_M_BYPASS, %o1 ! This is a level 1 ptr
666 srl %o1, 0x4, %o1 ! Clear low 4 bits
667 sll %o1, 0x8, %o1 ! Make physical
668
669 /* Ok, pull in the PTD. */ 670 lda [%o1] ASI_M_BYPASS, %o2 ! This is the 0x0 16MB pgd
671
672 /* Calculate to KERNBASE entry. 673 * 674 * XXX Should not use imperical constant, but Gas gets an XXX 675 * XXX upset stomach with the bitshift I would have to use XXX 676 */ 677 add %o1, 0x3c0, %o3
678
679 /* Poke the entry into the calculated address. */ 680 sta %o2, [%o3] ASI_M_BYPASS
681
682 /* I don't get it Sun, if you engineered all these 683 * boot loaders and the PROM (thank you for the debugging 684 * features btw) why did you not have them load kernel 685 * images up in high address space, since this is necessary 686 * for ABI compliance anyways? Does this low-mapping provide 687 * enhanced interoperability? 688 * 689 * "The PROM is the computer." 690 */ 691
692 /* Ok, restore the MMU control register we saved in %g5 */ 693 sta %g5, [%g0] ASI_M_MMUREGS ! POW... ouch
694
695 /* Turn traps back on. We saved it in %g3 earlier. */ 696 wr %g3, 0x0, %psr ! tick tock, tick tock
697
698 /* Now we burn precious CPU cycles due to bad engineering. */ 699 WRITE_PAUSE
700
701 /* Wow, all that just to move a 32-bit value from one 702 * place to another... Jump to high memory. 703 */ 704 b go_to_highmem
705 nop
706
707 /* This works on viking's in Mbus mode and all 708 * other MBUS modules. It is virtually the same as 709 * the above madness sans turning traps off and flipping 710 * the AC bit. 711 */ 712 srmmu_nviking:
713 set AC_M_CTPR, %g1
714 lda [%g1] ASI_M_MMUREGS, %g1 ! get ctx table ptr
715 sll %g1, 0x4, %g1 ! make physical addr
716 lda [%g1] ASI_M_BYPASS, %g1 ! ptr to level 1 pg_table
717 srl %g1, 0x4, %g1
718 sll %g1, 0x8, %g1 ! make phys addr for l1 tbl
719
720 lda [%g1] ASI_M_BYPASS, %g2 ! get level1 entry for 0x0
721 add %g1, 0x3c0, %g3 ! XXX AWAY WITH IMPERICALS
722 sta %g2, [%g3] ASI_M_BYPASS ! place at KERNBASE entry
723 b go_to_highmem
724 nop ! wheee....
725
726 /* This remaps the kernel on Sun4/4xx machines 727 * that have the Sun Mutant Three Level MMU. 728 * It's like a platypus, Sun didn't have the 729 * SRMMU in conception so they kludged the three 730 * level logic in the regular Sun4 MMU probably. 731 * 732 * Basically, you take each entry in the top level 733 * directory that maps the low 3MB starting at 734 * address zero and put the mapping in the KERNBASE 735 * slots. These top level pgd's are called regmaps. 736 */ 737 sun4_mutant_remap:
738 or %g0, %g0, %g3 ! source base
739 sethi %hi(KERNBASE), %g4 ! destination base
740 or %g4, %lo(KERNBASE), %g4
741 sethi %hi(0x300000), %g5
742 or %g5, %lo(0x300000), %g5 ! upper bound 3MB
743 or %g0, 0x1, %l6
744 sll %l6, 24, %l6 ! Regmap mapping size
745 add %g3, 0x2, %g3 ! Base magic
746 add %g4, 0x2, %g4 ! Base magic
747
748 /* Main remapping loop on Sun4-Mutant-MMU. 749 * "I am not an animal..." -Famous Mutant Person 750 */ 751 sun4_mutant_loop:
752 lduha [%g3] ASI_REGMAP, %g2 ! Get lower entry
753 stha %g2, [%g4] ASI_REGMAP ! Store in high entry
754 add %g4, %l6, %g4 ! Move up high memory ptr
755 subcc %g3, %g5, %g0 ! Reached our limit?
756 blu sun4_mutant_loop ! Nope, loop again
757 add %g3, %l6, %g3 ! delay, Move up low ptr
758 b go_to_highmem ! Jump to high memory.
759 nop
760
761 /* The following works for normal (ie. non Sun4/400) Sun4 MMU's */ 762 sun4c_remap:
763 or %g0, %g0, %g3 ! source base
764 sethi %hi(KERNBASE), %g4 ! destination base
765 or %g4, %lo(KERNBASE), %g4
766 sethi %hi(0x300000), %g5
767 or %g5, %lo(0x300000), %g5 ! upper bound 3MB
768 or %g0, 0x1, %l6
769 sll %l6, 18, %l6 ! sun4c mmu segmap size
770 sun4c_remap_loop:
771 lda [%g3] ASI_SEGMAP, %g6 ! load phys_seg
772 sta %g6, [%g4] ASI_SEGMAP ! store new virt mapping
773 add %g3, %l6, %g3 ! Increment source ptr
774 subcc %g3, %g5, %g0 ! Reached limit?
775 bl sun4c_remap_loop ! Nope, loop again
776 add %g4, %l6, %g4 ! delay, Increment dest ptr
777
778 /* Now do a non-relative jump so that PC is in high-memory */ 779 go_to_highmem:
780 set execute_in_high_mem, %g1
781 jmp %g1
782 nop
783
784 /* Acquire boot time privileged register values, this will help debugging. 785 * I figure out and store nwindows and nwindowsm1 later on. 786 */ 787 execute_in_high_mem:
788 or %g0, %l0, %o0 ! put back romvec
789 or %g0, %l1, %o1 ! and debug_vec
790
791 sethi %hi( C_LABEL(prom_vector_p) ), %g1
792 st %o0, [%g1 + %lo( C_LABEL(prom_vector_p) )]
793
794 sethi %hi( C_LABEL(linux_dbvec) ), %g1
795 st %o1, [%g1 + %lo( C_LABEL(linux_dbvec) )]
796
797 ld [%o0 + 0x4], %o3
798 and %o3, 0x3, %o5 ! get the version
799
800 subcc %o3, 0x2, %g0 ! a v2 prom?
801 be found_version
802 nop
803
804 /* paul@sfe.com.au */ 805 subcc %o3, 0x3, %g0 ! a v3 prom?
806 be found_version
807 nop
808
809 /* Old sun4's pass our load address into %o0 instead of the prom 810 * pointer. On sun4's you have to hard code the romvec pointer into 811 * your code. Sun probably still does that because they don't even 812 * trust their own "OpenBoot" specifications. 813 */ 814
815 sethi %hi(LOAD_ADDR), %g6
816 subcc %o0, %g6, %g0 ! an old sun4?
817 be no_sun4_here
818 nop
819
820 found_version:
821
822 /* Get the machine type via the mysterious romvec node operations. 823 * Here we can find out whether we are on a sun4, sun4c, sun4m, 824 * sun4d, or a sun4e. The "nodes" are set up as a bunch of n-ary trees 825 * which you can traverse to get information about devices and such. 826 * The information acquisition happens via the node-ops which are 827 * defined in the openprom.h header file. Of particular interest 828 * is the 'nextnode(int node)' function as it does the smart thing when 829 * presented with a value of '0', it gives you the root node in the 830 * tree. These node integers probably offset into some internal prom 831 * pointer table the openboot has. It's completely undocumented, so 832 * I'm not about to go sifting through the prom address space, but may 833 * do so if I get suspicious enough. :-) 834 */ 835
836 or %g0, %g7, %l1
837 add %l1, 0x1c, %l1
838 ld [%l1], %l0
839 ld [%l0], %l0
840 call %l0
841 or %g0, %g0, %o0 ! next_node(0) = first_node
842 or %o0, %g0, %g6
843
844 sethi %hi( C_LABEL(cputypvar) ), %o1 ! First node has cpu-arch
845 or %o1, %lo( C_LABEL(cputypvar) ), %o1
846 sethi %hi( C_LABEL(cputypval) ), %o2 ! information, the string
847 or %o2, %lo( C_LABEL(cputypval) ), %o2
848 ld [%l1], %l0 ! 'compatibility' tells
849 ld [%l0 + 0xc], %l0 ! that we want 'sun4x' where
850 call %l0 ! x is one of '', 'c', 'm',
851 nop ! 'd' or 'e'. %o2 holds pointer
852 ! to a buf where above string
853 ! will get stored by the prom.
854
855 subcc %o0, %g0, %g0
856 bpos got_prop ! Got the property
857 nop
858
859 or %g6, %g0, %o0
860 sethi %hi( C_LABEL(cputypvar_sun4m) ), %o1
861 or %o1, %lo( C_LABEL(cputypvar_sun4m) ), %o1
862 sethi %hi( C_LABEL(cputypval) ), %o2
863 or %o2, %lo( C_LABEL(cputypval) ), %o2
864 ld [%l1], %l0
865 ld [%l0 + 0xc], %l0
866 call %l0
867 nop
868
869 got_prop:
870 sethi %hi( C_LABEL(cputypval) ), %o2
871 or %o2, %lo( C_LABEL(cputypval) ), %o2
872
873 ldub [%o2 + 0x4], %l1
874 subcc %l1, 'c', %g0 ! We already know we are not
875 be 1f ! on a plain sun4 because of
876 nop ! the check for 0x4000 in %o0
877 subcc %l1, 'm', %g0 ! at start
878 be 1f
879 nop
880
881 subcc %l1, 'd', %g0
882 be no_sun4d_here ! God bless the person who
883 nop ! tried to run this on sun4d.
884
885 subcc %l1, 'e', %g0
886 be no_sun4e_here ! Could be a sun4e.
887 nop
888
889 b no_sun4u_here ! AIEEE, a V9 sun4u...
890 nop
891
892
893 1:
894 or %g0, PAGE_SHIFT, %g5
895
896 sethi %hi( C_LABEL(cputypval) ), %l1
897 or %l1, %lo( C_LABEL(cputypval) ), %l1
898 ldub [%l1 + 0x4], %l1
899 subcc %l1, 'm', %g0 ! Test for sun4d, sun4e ?
900 be sun4m_init
901 nop
902
903 sethi %hi(AC_CONTEXT), %g1 ! kernel context, safe now
904 ! the only valid context
905 ! until we call paging_init()
906 stba %g0, [%g1] ASI_CONTROL
907
908 b sun4c_continue_boot
909 nop
910
911 sun4m_init:
912 /* P3: I just do not know what to do here. But I do know that ASI_CONTROL 913 * will not serve on sun4m. Also I do not want to smash the current MMU 914 * setup until we call paging_init(). 915 */ 916
917 /* Ok, the PROM could have done funny things and apple cider could still 918 * be sitting in the fault status/address registers. Read them all to 919 * clear them so we don't get magic faults later on. 920 */ 921 /* This sucks, aparently this makes Vikings call prom panic, will fix later */ 922
923 set (0x40000000), %o1
924 rd %psr, %o0
925 andcc %o0, %o1, %g0
926 bne sun4c_continue_boot ! quick hack
927 nop
928
929 clr_srmmu_fregs:
930 set AC_M_SFSR, %o0
931 lda [%o0] ASI_M_MMUREGS, %g0
932 set AC_M_SFAR, %o0
933 lda [%o0] ASI_M_MMUREGS, %g0
934 set AC_M_AFSR, %o0
935 lda [%o0] ASI_M_MMUREGS, %g0
936 set AC_M_AFAR, %o0
937 lda [%o0] ASI_M_MMUREGS, %g0
938 nop
939
940
941 sun4c_continue_boot:
942
943
944 /* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's 945 * show-time! 946 */ 947
948 sethi %hi( C_LABEL(cputyp) ), %o0
949 st %g4, [%o0 + %lo( C_LABEL(cputyp) )]
950
951 /* Turn on PreviousSupervisor, Supervisor, EnableFloating, 952 * and all the PIL bits. Also puts us in register window 953 * zero. 954 */ 955 sethi %hi(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
956 or %g2, %lo(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
957 wr %g2, 0x0, %psr
958 WRITE_PAUSE
959
960 wr %g0, 0x2, %wim ! Make window 1 invalid.
961 WRITE_PAUSE
962
963 /* Initialize the WIM value for init_task. */ 964 or %g0, 0x1, %g1
965 sethi %hi( C_LABEL(current) + THREAD_WIM), %g2
966 st %g1, [%g2 + %lo( C_LABEL(current) + THREAD_WIM)]
967
968 /* I want a kernel stack NOW! */ 969 /* Grrr, gotta be real careful about alignment here */ 970
971 set ( C_LABEL(init_user_stack) + PAGE_SIZE - 96 - 96 - 80), %g1
972 andn %g1, 0x7, %g1
973 or %g1, 0x0, %fp
974 add %fp, (96+80), %sp
975
976 /* Enable traps. */ 977 rd %psr, %l0
978 wr %l0, PSR_ET, %psr
979 WRITE_PAUSE
980
981 /* 982 * Maybe the prom zeroes out our BSS section, maybe it doesn't. I certainly 983 * don't know, do you? 984 */ 985
986 set C_LABEL(edata) , %o0 ! First address of BSS
987 set C_LABEL(end) , %o1 ! Last address of BSS
988
989 /* Argh, ELF gets me again... */ 990 andn %o0, 0x3, %o0
991 andn %o1, 0x3, %o1
992
993 /* Friggin' bzero() kludge. */ 994
995 1:
996 st %g0, [%o0]
997 add %o0, 0x4, %o0
998 subcc %o0, %o1, %g0
999 bl 1b
1000 nop
1001
1002 /* Compute NWINDOWS and stash it away. Now uses %wim trick explained1003 * in the V8 manual. Ok, this method seems to work, Sparc is cool...1004 * No, it doesn't work, have to play the save/readCWP/restore trick.1005 */1006
1007 rd %wim, %g1
1008 rd %psr, %g2
1009 wr %g0, 0x0, %wim ! so we dont get a trap
1010 andn %g2, 0x1f, %g3
1011 wr %g3, 0x0, %psr
1012 WRITE_PAUSE
1013 save
1014 rd %psr, %g3
1015 restore
1016 and %g3, 0x1f, %g3
1017 add %g3, 0x1, %g3
1018 wr %g2, 0x0, %psr
1019 wr %g1, 0x0, %wim
1020
1021 cmp %g3, 0x7
1022 bne,a 2f
1023 sethi %hi( C_LABEL(nwindows) ), %g4
1024
1025
1026 /* Nop out one save and one restore in the save state code1027 * and system call entry if this is a seven window Sparc.1028 */1029 sethi %hi(nop7), %g5
1030 or %g5, %lo(nop7), %g5
1031 sethi %hi(NOP_INSN), %g6
1032 or %g6, %lo(NOP_INSN), %g6
1033 /* patch 1 */1034 st %g6, [%g5]
1035 st %g6, [%g5 + 0x4]
1036 sethi %hi(rnop7), %g5
1037 or %g5, %lo(rnop7), %g5
1038 /* patch 2 */1039 st %g6, [%g5]
1040 st %g6, [%g5 + 0x4]
1041
1042 sethi %hi( C_LABEL(nwindows) ), %g4
1043
1044 2:
1045 st %g3, [%g4 + %lo( C_LABEL(nwindows) )] ! store final value
1046 sub %g3, 0x1, %g3
1047 sethi %hi( C_LABEL(nwindowsm1) ), %g4
1048 st %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )]
1049
1050 /* Initialize lnx_winmask. */1051 set lnx_winmask, %g4
1052 or %g0, 0x2, %g5
1053 or %g0, 0x0, %g6
1054 msk_loop:
1055 stb %g5, [%g4 + %g6]
1056 add %g6, 0x1, %g6
1057 cmp %g6, %g3
1058 bl,a msk_loop
1059 sll %g5, 0x1, %g5
1060 or %g0, 0x1, %g5
1061 stb %g5, [%g4 + %g3]
1062
1063 /* Here we go */1064 set C_LABEL(trapbase), %g3
1065 wr %g3, 0x0, %tbr
1066 WRITE_PAUSE
1067
1068
1069 /* First we call prom_init() to set up PROMLIB, then off to start_kernel() */1070 /* XXX put this in setup_arch() */1071
1072 sethi %hi( C_LABEL(prom_vector_p) ), %g5
1073 call C_LABEL(prom_init)
1074 ld [%g5 + %lo( C_LABEL(prom_vector_p) )], %o0
1075
1076 subcc %o0, 0x1, %g0
1077 be halt_me ! promlib init failed
1078 nop
1079
1080 call C_LABEL(start_kernel)
1081 nop
1082
1083 /* We should not get here. */1084 call halt_me
1085 nop
1086
1087 /* There, happy now Adrian? */1088
1089 /* XXX Fix this... XXX */1090 no_sun4_here:
1091 sethi %hi(SUN4_PROM_VECTOR+SUN4_PRINTF), %o1
1092 ld [%o1 + %lo(SUN4_PROM_VECTOR+SUN4_PRINTF)], %o1
1093 set sun4_notsup, %o0
1094 call %o1
1095 nop
1096 1:
1097 ba 1b ! Cannot exit into KMON
1098 nop
1099
1100 no_sun4d_here:
1101 ld [%g7 + 0x68], %o1
1102 set sun4d_notsup, %o0
1103 call %o1
1104 nop
1105 b halt_me
1106 nop
1107
1108 no_sun4e_here:
1109 ld [%g7 + 0x68], %o1
1110 set sun4e_notsup, %o0
1111 call %o1
1112 nop
1113 b halt_me
1114 nop
1115
1116 no_sun4u_here:
1117 ld [%g7 + 0x68], %o1
1118 set sun4u_notsup, %o0
1119 call %o1
1120 nop
1121 b halt_me
1122 nop
1123
1124 halt_me:
1125 ld [%g7 + 0x74], %o0
1126 call %o0 ! Get us out of here...
1127 nop ! Apparently Solaris is better.
1128
1129 .data
1130 .align 4
1131
1132 /*1133 * Fill up the prom vector, note in particular the kind first element,1134 * no joke. I don't need all of them in here as the entire prom vector1135 * gets initialized in c-code so all routines can use it.1136 */1137
1138 .globl C_LABEL(prom_vector_p)
1139 C_LABEL(prom_vector_p): .skip 4
1140
1141 .align 4
1142
1143 /* We calculate the following at boot time, window fills/spills and trap entry1144 * code uses these to keep track of the register windows.1145 */1146
1147 .globl C_LABEL(nwindows)
1148 .globl C_LABEL(nwindowsm1)
1149 C_LABEL(nwindows): .skip 4
1150 C_LABEL(nwindowsm1): .skip 4
1151
1152 .align 4
1153
1154 /* Boot time debugger vector value. We need this later on. */1155
1156 .globl C_LABEL(linux_dbvec)
1157 C_LABEL(linux_dbvec): .skip 4
1158
1159 .align 4
1160
1161 /* Just to get the kernel through the compiler for now */1162 .globl C_LABEL(floppy_track_buffer)
1163 C_LABEL(floppy_track_buffer):
1164 .fill 512*2*36,1,0