* better
[mascara-docs.git] / i386 / linux-2.3.21 / arch / sparc64 / kernel / head.S
blobad863a71d1a5167bb2334f410425eff3e8513e11
1 /* $Id: head.S,v 1.61 1999/05/25 16:53:10 jj Exp $
2  * head.S: Initial boot code for the Sparc64 port of Linux.
3  *
4  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
5  * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
6  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7  * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
8  */
10 #include <linux/config.h>
11 #include <linux/version.h>
12 #include <linux/errno.h>
13 #include <asm/asm_offsets.h>
14 #include <asm/asi.h>
15 #include <asm/pstate.h>
16 #include <asm/ptrace.h>
17 #include <asm/spitfire.h>
18 #include <asm/page.h>
19 #include <asm/pgtable.h>
20 #include <asm/errno.h>
21 #include <asm/signal.h>
22 #include <asm/processor.h>
23 #include <asm/lsu.h>
24 #include <asm/head.h>
25 #include <asm/ttable.h>
26         
27 /* This section from from _start to sparc64_boot_end should fit into
28  * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
29  * with bootup_user_stack, which is from 0x0000.0000.0040.4000 to
30  * 0x0000.0000.0040.6000 and empty_bad_page, which is from
31  * 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000. 
32  */
34         .text
35         .globl  start, _start, stext, _stext
36 _start:
37 start:
38 _stext:
39 stext:
40 bootup_user_stack:
41 ! 0x0000000000404000
42         b       sparc64_boot
43          flushw                                 /* Flush register file.      */
45 /* This stuff has to be in sync with SILO and other potential boot loaders
46  * Fields should be kept upward compatible and whenever any change is made,
47  * HdrS version should be incremented.
48  */
49         .global root_flags, ram_flags, root_dev
50         .global sparc_ramdisk_image, sparc_ramdisk_size
51         .globl  silo_args
53         .ascii  "HdrS"
54         .word   LINUX_VERSION_CODE
55         .half   0x0202          /* HdrS version */
56 root_flags:
57         .half   1
58 root_dev:
59         .half   0
60 ram_flags:
61         .half   0
62 sparc_ramdisk_image:
63         .word   0
64 sparc_ramdisk_size:
65         .word   0
66         .xword  reboot_command
67         .xword  bootstr_len
69         /* We must be careful, 32-bit OpenBOOT will get confused if it
70          * tries to save away a register window to a 64-bit kernel
71          * stack address.  Flush all windows, disable interrupts,
72          * remap if necessary, jump onto kernel trap table, then kernel
73          * stack, or else we die.
74          *
75          * PROM entry point is on %o4
76          */
77 sparc64_boot:
78         /* Typically PROM has already enabled both MMU's and both on-chip
79          * caches, but we do it here anyway just to be paranoid.
80          */
81         mov     (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1
82         stxa    %g1, [%g0] ASI_LSU_CONTROL
84         /*
85          * Make sure we are in privileged mode, have address masking,
86          * using the ordinary globals and have enabled floating
87          * point.
88          *
89          * Again, typically PROM has left %pil at 13 or similar, and
90          * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate.
91          */
92         wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
93         wr      %g0, 0, %fprs
95 #ifdef __SMP__
96         /* Ugly but necessary... */
97         sethi   %hi(KERNBASE), %g7
98         sethi   %hi(sparc64_cpu_startup), %g5
99         or      %g5, %lo(sparc64_cpu_startup), %g5
100         sub     %g5, %g7, %g5
101         sethi   %hi(sparc64_cpu_startup_end), %g6
102         or      %g6, %lo(sparc64_cpu_startup_end), %g6
103         sub     %g6, %g7, %g6
104         sethi   %hi(smp_trampoline), %g3
105         or      %g3, %lo(smp_trampoline), %g3
106         sub     %g3, %g7, %g3
107 1:      ldx     [%g5], %g1
108         stx     %g1, [%g3]
109         membar  #StoreStore
110         flush   %g3
111         add     %g5, 8, %g5
112         cmp     %g5, %g6
113         blu,pt  %xcc, 1b
114          add    %g3, 8, %g3
115 #endif
117 create_mappings:
118         /* %g5 holds the tlb data */
119         sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
120         sllx    %g5, 32, %g5
121         or      %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
123         /* Base of physical memory cannot reliably be assumed to be
124          * at 0x0!  Figure out where it happens to be. -DaveM
125          */
127         /* Put PADDR tlb data mask into %g3. */
128         sethi   %uhi(_PAGE_PADDR), %g3
129         or      %g3, %ulo(_PAGE_PADDR), %g3
130         sllx    %g3, 32, %g3
131         sethi   %hi(_PAGE_PADDR), %g7
132         or      %g7, %lo(_PAGE_PADDR), %g7
133         or      %g3, %g7, %g3
135         /* Walk through entire ITLB, looking for entry which maps
136          * our %pc currently, stick PADDR from there into %g5 tlb data.
137          */
138         clr     %l0                     /* TLB entry walker. */
139         set     0x1fff, %l2             /* Page mask. */
140         rd      %pc, %l3
141         andn    %l3, %l2, %g2           /* vaddr comparator */
143         /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
144         ldxa    [%l0] ASI_ITLB_TAG_READ, %g1
145         nop
146         nop
147         nop
148         andn    %g1, %l2, %g1           /* Get vaddr */
149         cmp     %g1, %g2
150         be,a,pn %xcc, got_tlbentry
151          ldxa   [%l0] ASI_ITLB_DATA_ACCESS, %g1
152         cmp     %l0, (63 << 3)
153         blu,pt  %xcc, 1b
154          add    %l0, (1 << 3), %l0
156 got_tlbentry:
157         /* Nops here again, perhaps Cheetah/Blackbird are better behaved... */
158         nop
159         nop
160         nop
161         and     %g1, %g3, %g1           /* Mask to just get paddr bits.       */
162         sub     %g1, %g2, %g1           /* Get rid of %pc offset to get base. */
164         /* NOTE: We hold on to %g1 paddr base as we need it below to lock
165          * NOTE: the PROM cif code into the TLB.
166          */
168         or      %g5, %g1, %g5           /* Or it into TAG being built.        */
170         clr     %l0                     /* TLB entry walker. */
171         sethi   %hi(KERNBASE), %g3      /* 4M lower limit */
172         sethi   %hi(KERNBASE<<1), %g7   /* 8M upper limit */
173         mov     TLB_TAG_ACCESS, %l7
175         /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
176         ldxa    [%l0] ASI_ITLB_TAG_READ, %g1
177         nop
178         nop
179         nop
180         andn    %g1, %l2, %g1           /* Get vaddr */
181         cmp     %g1, %g3
182         blu,pn  %xcc, 2f
183          cmp    %g1, %g7
184         bgeu,pn %xcc, 2f
185          nop
186         stxa    %g0, [%l7] ASI_IMMU
187         stxa    %g0, [%l0] ASI_ITLB_DATA_ACCESS
189         cmp     %l0, (63 << 3)
190         blu,pt  %xcc, 1b
191          add    %l0, (1 << 3), %l0
193         nop; nop; nop
195         clr     %l0                     /* TLB entry walker. */
197         /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
198         ldxa    [%l0] ASI_DTLB_TAG_READ, %g1
199         nop
200         nop
201         nop
202         andn    %g1, %l2, %g1           /* Get vaddr */
203         cmp     %g1, %g3
204         blu,pn  %xcc, 2f
205          cmp    %g1, %g7
206         bgeu,pn %xcc, 2f
207          nop
208         stxa    %g0, [%l7] ASI_DMMU
209         stxa    %g0, [%l0] ASI_DTLB_DATA_ACCESS
211         cmp     %l0, (63 << 3)
212         blu,pt  %xcc, 1b
213          add    %l0, (1 << 3), %l0
215         nop; nop; nop
218         /* PROM never puts any TLB entries into the MMU with the lock bit
219          * set.  So we gladly use tlb entry 63 for KERNBASE.
220          */
222         sethi   %hi(KERNBASE), %g3
223         mov     (63 << 3), %g7
224         stxa    %g3, [%l7] ASI_DMMU             /* KERNBASE into TLB TAG        */
225         stxa    %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA            */
226         membar  #Sync
227         stxa    %g3, [%l7] ASI_IMMU             /* KERNBASE into TLB TAG        */
228         stxa    %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA            */
229         membar  #Sync
230         flush   %g3
231         membar  #Sync
232         ba,pt   %xcc, 1f
233          nop
235         set     sun4u_init, %g2
236         jmpl    %g2 + %g0, %g0
237          nop
239 sun4u_init:
240         /* Set ctx 0 */
241         mov     PRIMARY_CONTEXT, %g7
242         stxa    %g0, [%g7] ASI_DMMU
243         membar  #Sync
245         mov     SECONDARY_CONTEXT, %g7
246         stxa    %g0, [%g7] ASI_DMMU
247         membar  #Sync
249         sethi   %uhi(PAGE_OFFSET), %g4
250         sllx    %g4, 32, %g4
252         /* We are now safely (we hope) in Nucleus context (0), rewrite
253          * the KERNBASE TTE's so they no longer have the global bit set.
254          * Don't forget to setup TAG_ACCESS first 8-)
255          */
256         mov     TLB_TAG_ACCESS, %g2
257         stxa    %g3, [%g2] ASI_IMMU
258         stxa    %g3, [%g2] ASI_DMMU
260         mov     (63 << 3), %g7
261         ldxa    [%g7] ASI_ITLB_DATA_ACCESS, %g1
262         andn    %g1, (_PAGE_G), %g1
263         stxa    %g1, [%g7] ASI_ITLB_DATA_ACCESS
264         membar  #Sync
266         ldxa    [%g7] ASI_DTLB_DATA_ACCESS, %g1
267         andn    %g1, (_PAGE_G), %g1
268         stxa    %g1, [%g7] ASI_DTLB_DATA_ACCESS
269         membar  #Sync
271         /* Kill instruction prefetch queues. */
272         flush   %g3
273         membar  #Sync
275         sethi   %hi(init_task_union), %g6
276         or      %g6, %lo(init_task_union), %g6
277         mov     %sp, %l6
278         mov     %o4, %l7
280 #if 0   /* We don't do it like this anymore, but for historical hack value
281          * I leave this snippet here to show how crazy we can be sometimes. 8-)
282          */
284         /* Setup "Linux Current Register", thanks Sun 8-) */
285         wr      %g0, 0x1, %pcr
286         wr      %g6, 0x0, %pic
287 #endif
289         wr      %g0, ASI_P, %asi
290         mov     1, %g5
291         sllx    %g5, (PAGE_SHIFT + 1), %g5
292         sub     %g5, (REGWIN_SZ + STACK_BIAS), %g5
293         add     %g6, %g5, %sp
294         mov     0, %fp
296         wrpr    %g0, 0, %wstate
297         wrpr    %g0, 0x0, %tl
299         /* Clear the bss */
300         sethi   %hi(8191), %l2
301         or      %l2, %lo(8191), %l2
302         sethi   %hi(__bss_start), %l0
303         or      %l0, %lo(__bss_start), %l0
304         sethi   %hi(_end), %l1
305         or      %l1, %lo(_end), %l1
306         add     %l1, %l2, %l1
307         andn    %l1, %l2, %l1
308         add     %l2, 1, %l2
309         add     %l0, %g0, %o0
311         mov     %l2, %o1
312         call    __bzero
313          add    %l0, %l2, %l0
314         cmp     %l0, %l1
315         blu,pt  %xcc, 1b
316          add    %l0, %g0, %o0
318         /* Now clear empty_zero_page */
319         mov     %l2, %o1
320         call    __bzero
321          mov    %g3, %o0
323         mov     %l6, %o1                        ! OpenPROM stack
324         call    prom_init
325          mov    %l7, %o0                        ! OpenPROM cif handler
327         /* Off we go.... */
328         call    start_kernel
329          nop
330         /* Not reached... */
332 /* IMPORTANT NOTE: Whenever making changes here, check
333  * trampoline.S as well. -jj */
334         .globl  setup_tba
335 setup_tba:      /* i0 = is_starfire */
336         save    %sp, -160, %sp
338         rdpr    %tba, %g7
339         sethi   %hi(prom_tba), %o1
340         or      %o1, %lo(prom_tba), %o1
341         stx     %g7, [%o1]
343         /* Setup "Linux" globals 8-) */
344         rdpr    %pstate, %o1
345         mov     %g6, %o2
346         wrpr    %o1, (PSTATE_AG|PSTATE_IE), %pstate
347         sethi   %hi(sparc64_ttable_tl0), %g5
348         wrpr    %g5, %tba
349         mov     %o2, %g6
351         /* Set up MMU globals */
352         wrpr    %o1, (PSTATE_MG|PSTATE_IE), %pstate
354         /* Set fixed globals used by dTLB miss handler. */
355 #define KERN_HIGHBITS           ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
356 #define KERN_LOWBITS            (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
357 #ifdef THIS_IS_CHEETAH
358 #error Dave, make sure you took care of other issues in rest of sparc64 code...
359 #define VPTE_BASE               0xffe0000000000000
360 #else /* Spitfire/Blackbird */
361 #define VPTE_BASE               0xfffffffe00000000
362 #endif
363         mov     TSB_REG, %g1
364         stxa    %g0, [%g1] ASI_DMMU
365         membar  #Sync
366         mov     TLB_SFSR, %g1
367         sethi   %uhi(KERN_HIGHBITS), %g2
368         or      %g2, %ulo(KERN_HIGHBITS), %g2
369         sllx    %g2, 32, %g2
370         or      %g2, KERN_LOWBITS, %g2
371         sethi   %uhi(VPTE_BASE), %g3
372         or      %g3, %ulo(VPTE_BASE), %g3
373         sllx    %g3, 32, %g3
374         clr     %g7
375 #undef KERN_HIGHBITS
376 #undef KERN_LOWBITS
377 #undef VPTE_BASE
379         /* Setup Interrupt globals */
380         wrpr    %o1, (PSTATE_IG|PSTATE_IE), %pstate
381 #ifndef __SMP__
382         sethi   %hi(__up_workvec), %g5
383         or      %g5, %lo(__up_workvec), %g1
384 #else
385         /* By definition of where we are, this is boot_cpu. */
386         sethi   %hi(cpu_data), %g5
387         or      %g5, %lo(cpu_data), %g5
389         brz,pt  %i0, not_starfire
390          sethi  %hi(0x1fff4000), %g1
391         or      %g1, %lo(0x1fff4000), %g1
392         sllx    %g1, 12, %g1
393         or      %g1, 0xd0, %g1
394         lduwa   [%g1] ASI_PHYS_BYPASS_EC_E, %g1
395         b,pt    %xcc, set_worklist
396          nop
398 not_starfire:
399         ldxa    [%g0] ASI_UPA_CONFIG, %g1
400         srlx    %g1, 17, %g1
401         and     %g1, 0x1f, %g1
403         /* In theory this is: &(cpu_data[boot_cpu_id].irq_worklists[0]) */
404 set_worklist:
405         sllx    %g1, 7, %g1
406         add     %g5, %g1, %g5
407         add     %g5, 64, %g1
408 #endif
410         /* Kill PROM timer */
411         wr      %g0, 0, %tick_cmpr
413         /* Ok, we're done setting up all the state our trap mechanims needs,
414          * now get back into normal globals and let the PROM know what is up.
415          */
416         wrpr    %g0, %g0, %wstate
417         wrpr    %o1, PSTATE_IE, %pstate
419         sethi   %hi(sparc64_ttable_tl0), %g5
420         call    prom_set_trap_table
421          mov    %g5, %o0
423         rdpr    %pstate, %o1
424         or      %o1, PSTATE_IE, %o1
425         wrpr    %o1, 0, %pstate
427         ret
428          restore
430 sparc64_boot_end:
431         .skip   0x2000 + _start - sparc64_boot_end
432 bootup_user_stack_end:
434         .globl  empty_bad_page
435 empty_bad_page:
436         .skip   0x2000
438 #ifdef CONFIG_SBUS
439 /* This is just a hack to fool make depend config.h discovering
440    strategy: As the .S files below need config.h, but
441    make depend does not find it for them, we include config.h
442    in head.S */
443 #endif
445 ! 0x0000000000408000
447 #include "ttable.S"
448 #include "systbls.S"
450         .align  1024
451         .globl  swapper_pg_dir
452 swapper_pg_dir:
453         .word   0
455 #include "etrap.S"
456 #include "rtrap.S"
457 #include "winfixup.S"
458 #include "entry.S"
460         /* This is just anal retentiveness on my part... */
461         .align  16384
463         .data
464         .align  8
465         .globl  prom_tba
466 prom_tba:       .xword  0
467         .section        ".fixup",#alloc,#execinstr
468         .globl  __ret_efault
469 __ret_efault:
470         ret
471          restore %g0, -EFAULT, %o0