summaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel/relocate_kernel.S
blob: 3e09a89067add5a5a5bde1d42d58b390a5ea2baa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <linux/linkage.h>

#include <asm/asm-offsets.h>
#include <asm/page.h>
#include <asm/setup.h>


#define MMU_BASE	8		/* MMU flags base in cpu_mmu_flags */

.text

ENTRY(relocate_new_kernel)
	movel %sp@(4),%a0		/* a0 = ptr */
	movel %sp@(8),%a1		/* a1 = start */
	movel %sp@(12),%d1		/* d1 = cpu_mmu_flags */
	movew #PAGE_MASK,%d2		/* d2 = PAGE_MASK */

	/* Disable MMU */

	btst #MMU_BASE + MMUB_68851,%d1
	jeq 3f

1:	/* 68851 or 68030 */

	lea %pc@(.Lcopy),%a4
2:	addl #0x00000000,%a4		/* virt_to_phys() */

	.section ".m68k_fixup","aw"
	.long M68K_FIXUP_MEMOFFSET, 2b+2
	.previous

	.chip 68030
	pmove %tc,%d0			/* Disable MMU */
	bclr #7,%d0
	pmove %d0,%tc
	jmp %a4@			/* Jump to physical .Lcopy */
	.chip 68k

3:
	btst #MMU_BASE + MMUB_68030,%d1
	jne 1b

	btst #MMU_BASE + MMUB_68040,%d1
	jeq 6f

4:	/* 68040 or 68060 */

	lea %pc@(.Lcont040),%a4
5:	addl #0x00000000,%a4		/* virt_to_phys() */

	.section ".m68k_fixup","aw"
	.long M68K_FIXUP_MEMOFFSET, 5b+2
	.previous

	movel %a4,%d0
	andl #0xff000000,%d0
	orw #0xe020,%d0			/* Map 16 MiB, enable, cacheable */
	.chip 68040
	movec %d0,%itt0
	movec %d0,%dtt0
	.chip 68k
	jmp %a4@			/* Jump to physical .Lcont040 */

.Lcont040:
	moveq #0,%d0
	.chip 68040
	movec %d0,%tc			/* Disable MMU */
	movec %d0,%itt0
	movec %d0,%itt1
	movec %d0,%dtt0
	movec %d0,%dtt1
	.chip 68k
	jra .Lcopy

6:
	btst #MMU_BASE + MMUB_68060,%d1
	jne 4b

.Lcopy:
	movel %a0@+,%d0			/* d0 = entry = *ptr */
	jeq .Lflush

	btst #2,%d0			/* entry & IND_DONE? */
	jne .Lflush

	btst #1,%d0			/* entry & IND_INDIRECTION? */
	jeq 1f
	andw %d2,%d0
	movel %d0,%a0			/* ptr = entry & PAGE_MASK */
	jra .Lcopy

1:
	btst #0,%d0			/* entry & IND_DESTINATION? */
	jeq 2f
	andw %d2,%d0
	movel %d0,%a2			/* a2 = dst = entry & PAGE_MASK */
	jra .Lcopy

2:
	btst #3,%d0			/* entry & IND_SOURCE? */
	jeq .Lcopy

	andw %d2,%d0
	movel %d0,%a3			/* a3 = src = entry & PAGE_MASK */
	movew #PAGE_SIZE/32 - 1,%d0	/* d0 = PAGE_SIZE/32 - 1 */
3:
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	movel %a3@+,%a2@+		/* *dst++ = *src++ */
	dbf %d0, 3b
	jra .Lcopy

.Lflush:
	/* Flush all caches */

	btst #CPUB_68020,%d1
	jeq 2f

1:	/* 68020 or 68030 */
	.chip 68030
	movec %cacr,%d0
	orw #0x808,%d0
	movec %d0,%cacr
	.chip 68k
	jra .Lreincarnate

2:
	btst #CPUB_68030,%d1
	jne 1b

	btst #CPUB_68040,%d1
	jeq 4f

3:	/* 68040 or 68060 */
	.chip 68040
	nop
	cpusha %bc
	nop
	cinva %bc
	nop
	.chip 68k
	jra .Lreincarnate

4:
	btst #CPUB_68060,%d1
	jne 3b

.Lreincarnate:
	jmp %a1@

relocate_new_kernel_end:

ENTRY(relocate_new_kernel_size)
	.long relocate_new_kernel_end - relocate_new_kernel