Blame view

arch/mips/kernel/vpe.c 36.5 KB
e01402b11   Ralf Baechle   More AP / SP bits...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
   *
   *  This program is free software; you can distribute it and/or modify it
   *  under the terms of the GNU General Public License (Version 2) as
   *  published by the Free Software Foundation.
   *
   *  This program is distributed in the hope it will be useful, but WITHOUT
   *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   *  for more details.
   *
   *  You should have received a copy of the GNU General Public License along
   *  with this program; if not, write to the Free Software Foundation, Inc.,
   *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
e01402b11   Ralf Baechle   More AP / SP bits...
16
17
18
19
20
21
   */
  
  /*
   * VPE support module
   *
   * Provides support for loading a MIPS SP program on VPE1.
25985edce   Lucas De Marchi   Fix common misspe...
22
   * The SP environment is rather simple, no tlb's.  It needs to be relocatable
e01402b11   Ralf Baechle   More AP / SP bits...
23
24
25
26
27
28
   * (or partially linked). You should initialise your stack in the startup
   * code. This loader looks for the symbol __start and sets up
   * execution to resume from there. The MIPS SDE kit contains suitable examples.
   *
   * To load and run, simply cat a SP 'program file' to /dev/vpe1.
   * i.e cat spapp >/dev/vpe1.
e01402b11   Ralf Baechle   More AP / SP bits...
29
   */
e01402b11   Ralf Baechle   More AP / SP bits...
30
  #include <linux/kernel.h>
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
31
  #include <linux/device.h>
e01402b11   Ralf Baechle   More AP / SP bits...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <asm/uaccess.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/vmalloc.h>
  #include <linux/elf.h>
  #include <linux/seq_file.h>
  #include <linux/syscalls.h>
  #include <linux/moduleloader.h>
  #include <linux/interrupt.h>
  #include <linux/poll.h>
  #include <linux/bootmem.h>
  #include <asm/mipsregs.h>
340ee4b98   Ralf Baechle   Virtual SMP suppo...
46
  #include <asm/mipsmtregs.h>
e01402b11   Ralf Baechle   More AP / SP bits...
47
  #include <asm/cacheflush.h>
60063497a   Arun Sharma   atomic: use <linu...
48
  #include <linux/atomic.h>
e01402b11   Ralf Baechle   More AP / SP bits...
49
  #include <asm/cpu.h>
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
50
  #include <asm/mips_mt.h>
e01402b11   Ralf Baechle   More AP / SP bits...
51
52
  #include <asm/processor.h>
  #include <asm/system.h>
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
53
54
  #include <asm/vpe.h>
  #include <asm/kspd.h>
e01402b11   Ralf Baechle   More AP / SP bits...
55
56
  
  typedef void *vpe_handle;
e01402b11   Ralf Baechle   More AP / SP bits...
57
58
59
60
61
62
  #ifndef ARCH_SHF_SMALL
  #define ARCH_SHF_SMALL 0
  #endif
  
  /* If this is set, the section belongs in the init part of the module */
  #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
63
64
65
66
  /*
   * The number of TCs and VPEs physically available on the core
   */
  static int hw_tcs, hw_vpes;
e01402b11   Ralf Baechle   More AP / SP bits...
67
  static char module_name[] = "vpe";
307bd284c   Ralf Baechle   VPE loader janito...
68
  static int major;
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
69
  static const int minor = 1;	/* fixed for now  */
e01402b11   Ralf Baechle   More AP / SP bits...
70

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
71
  #ifdef CONFIG_MIPS_APSP_KSPD
349c4229e   Ralf Baechle   MIPS: VPE: Fix bo...
72
  static struct kspd_notifications kspd_events;
982f6ffee   Ralf Baechle   MIPS: Remove usel...
73
  static int kspd_events_reqd;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
74
  #endif
e01402b11   Ralf Baechle   More AP / SP bits...
75
76
77
78
79
80
81
  /* grab the likely amount of memory we will need. */
  #ifdef CONFIG_MIPS_VPE_LOADER_TOM
  #define P_SIZE (2 * 1024 * 1024)
  #else
  /* add an overhead to the max kmalloc size for non-striped symbols/etc */
  #define P_SIZE (256 * 1024)
  #endif
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
82
  extern unsigned long physical_memsize;
e01402b11   Ralf Baechle   More AP / SP bits...
83
  #define MAX_VPES 16
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
84
  #define VPE_PATH_MAX 256
e01402b11   Ralf Baechle   More AP / SP bits...
85
86
87
88
89
90
91
92
93
94
95
96
97
  
  enum vpe_state {
  	VPE_STATE_UNUSED = 0,
  	VPE_STATE_INUSE,
  	VPE_STATE_RUNNING
  };
  
  enum tc_state {
  	TC_STATE_UNUSED = 0,
  	TC_STATE_INUSE,
  	TC_STATE_RUNNING,
  	TC_STATE_DYNAMIC
  };
307bd284c   Ralf Baechle   VPE loader janito...
98
  struct vpe {
e01402b11   Ralf Baechle   More AP / SP bits...
99
100
101
102
103
104
105
  	enum vpe_state state;
  
  	/* (device) minor associated with this vpe */
  	int minor;
  
  	/* elfloader stuff */
  	void *load_addr;
571e0bed8   Ralf Baechle   MIPS: MT: Fix 32-...
106
  	unsigned long len;
e01402b11   Ralf Baechle   More AP / SP bits...
107
  	char *pbuffer;
571e0bed8   Ralf Baechle   MIPS: MT: Fix 32-...
108
  	unsigned long plen;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
109
110
  	unsigned int uid, gid;
  	char cwd[VPE_PATH_MAX];
e01402b11   Ralf Baechle   More AP / SP bits...
111
112
113
114
115
116
117
118
119
120
121
  
  	unsigned long __start;
  
  	/* tc's associated with this vpe */
  	struct list_head tc;
  
  	/* The list of vpe's */
  	struct list_head list;
  
  	/* shared symbol address */
  	void *shared_ptr;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
122
123
124
  
  	/* the list of who wants to know when something major happens */
  	struct list_head notify;
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
125
126
  
  	unsigned int ntcs;
307bd284c   Ralf Baechle   VPE loader janito...
127
128
129
130
131
  };
  
  struct tc {
  	enum tc_state state;
  	int index;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
132
133
134
  	struct vpe *pvpe;	/* parent VPE */
  	struct list_head tc;	/* The list of TC's with this VPE */
  	struct list_head list;	/* The global list of tc's */
307bd284c   Ralf Baechle   VPE loader janito...
135
  };
e01402b11   Ralf Baechle   More AP / SP bits...
136

9cfdf6f15   Ralf Baechle   [MIPS] VPE loader...
137
  struct {
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
138
139
140
141
  	spinlock_t vpe_list_lock;
  	struct list_head vpe_list;	/* Virtual processing elements */
  	spinlock_t tc_list_lock;
  	struct list_head tc_list;	/* Thread contexts */
9cfdf6f15   Ralf Baechle   [MIPS] VPE loader...
142
  } vpecontrol = {
52bd080d5   Thomas Gleixner   MIPS: Replace dep...
143
  	.vpe_list_lock	= __SPIN_LOCK_UNLOCKED(vpe_list_lock),
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
144
  	.vpe_list	= LIST_HEAD_INIT(vpecontrol.vpe_list),
52bd080d5   Thomas Gleixner   MIPS: Replace dep...
145
  	.tc_list_lock	= __SPIN_LOCK_UNLOCKED(tc_list_lock),
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
146
  	.tc_list	= LIST_HEAD_INIT(vpecontrol.tc_list)
9cfdf6f15   Ralf Baechle   [MIPS] VPE loader...
147
  };
e01402b11   Ralf Baechle   More AP / SP bits...
148
149
  
  static void release_progmem(void *ptr);
e01402b11   Ralf Baechle   More AP / SP bits...
150
151
  
  /* get the vpe associated with this minor */
f18b51cc1   Ralf Baechle   MIPS: VPE: Make v...
152
  static struct vpe *get_vpe(int minor)
e01402b11   Ralf Baechle   More AP / SP bits...
153
  {
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
154
  	struct vpe *res, *v;
e01402b11   Ralf Baechle   More AP / SP bits...
155

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
156
157
  	if (!cpu_has_mipsmt)
  		return NULL;
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
158
159
  	res = NULL;
  	spin_lock(&vpecontrol.vpe_list_lock);
e01402b11   Ralf Baechle   More AP / SP bits...
160
  	list_for_each_entry(v, &vpecontrol.vpe_list, list) {
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
161
162
163
164
  		if (v->minor == minor) {
  			res = v;
  			break;
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
165
  	}
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
166
  	spin_unlock(&vpecontrol.vpe_list_lock);
e01402b11   Ralf Baechle   More AP / SP bits...
167

1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
168
  	return res;
e01402b11   Ralf Baechle   More AP / SP bits...
169
170
171
  }
  
  /* get the vpe associated with this minor */
f18b51cc1   Ralf Baechle   MIPS: VPE: Make v...
172
  static struct tc *get_tc(int index)
e01402b11   Ralf Baechle   More AP / SP bits...
173
  {
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
174
  	struct tc *res, *t;
e01402b11   Ralf Baechle   More AP / SP bits...
175

1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
176
177
  	res = NULL;
  	spin_lock(&vpecontrol.tc_list_lock);
e01402b11   Ralf Baechle   More AP / SP bits...
178
  	list_for_each_entry(t, &vpecontrol.tc_list, list) {
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
179
180
181
182
  		if (t->index == index) {
  			res = t;
  			break;
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
183
  	}
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
184
  	spin_unlock(&vpecontrol.tc_list_lock);
e01402b11   Ralf Baechle   More AP / SP bits...
185

9fbcbd7e1   Hillf Danton   MIPS: VPE: Select...
186
  	return res;
e01402b11   Ralf Baechle   More AP / SP bits...
187
  }
e01402b11   Ralf Baechle   More AP / SP bits...
188
  /* allocate a vpe and associate it with this minor (or index) */
f18b51cc1   Ralf Baechle   MIPS: VPE: Make v...
189
  static struct vpe *alloc_vpe(int minor)
e01402b11   Ralf Baechle   More AP / SP bits...
190
191
  {
  	struct vpe *v;
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
192
  	if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL)
e01402b11   Ralf Baechle   More AP / SP bits...
193
  		return NULL;
e01402b11   Ralf Baechle   More AP / SP bits...
194

e01402b11   Ralf Baechle   More AP / SP bits...
195
  	INIT_LIST_HEAD(&v->tc);
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
196
  	spin_lock(&vpecontrol.vpe_list_lock);
e01402b11   Ralf Baechle   More AP / SP bits...
197
  	list_add_tail(&v->list, &vpecontrol.vpe_list);
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
198
  	spin_unlock(&vpecontrol.vpe_list_lock);
e01402b11   Ralf Baechle   More AP / SP bits...
199

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
200
  	INIT_LIST_HEAD(&v->notify);
e01402b11   Ralf Baechle   More AP / SP bits...
201
  	v->minor = minor;
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
202

e01402b11   Ralf Baechle   More AP / SP bits...
203
204
205
206
  	return v;
  }
  
  /* allocate a tc. At startup only tc0 is running, all other can be halted. */
f18b51cc1   Ralf Baechle   MIPS: VPE: Make v...
207
  static struct tc *alloc_tc(int index)
e01402b11   Ralf Baechle   More AP / SP bits...
208
  {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
209
  	struct tc *tc;
e01402b11   Ralf Baechle   More AP / SP bits...
210

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
211
212
  	if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
  		goto out;
e01402b11   Ralf Baechle   More AP / SP bits...
213

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
214
215
  	INIT_LIST_HEAD(&tc->tc);
  	tc->index = index;
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
216
217
  
  	spin_lock(&vpecontrol.tc_list_lock);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
218
  	list_add_tail(&tc->list, &vpecontrol.tc_list);
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
219
  	spin_unlock(&vpecontrol.tc_list_lock);
e01402b11   Ralf Baechle   More AP / SP bits...
220

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
221
222
  out:
  	return tc;
e01402b11   Ralf Baechle   More AP / SP bits...
223
224
225
  }
  
  /* clean up and free everything */
f18b51cc1   Ralf Baechle   MIPS: VPE: Make v...
226
  static void release_vpe(struct vpe *v)
e01402b11   Ralf Baechle   More AP / SP bits...
227
228
229
230
231
232
  {
  	list_del(&v->list);
  	if (v->load_addr)
  		release_progmem(v);
  	kfree(v);
  }
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
233
  static void __maybe_unused dump_mtregs(void)
e01402b11   Ralf Baechle   More AP / SP bits...
234
235
236
237
238
239
240
  {
  	unsigned long val;
  
  	val = read_c0_config3();
  	printk("config3 0x%lx MT %ld
  ", val,
  	       (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
e01402b11   Ralf Baechle   More AP / SP bits...
241
242
243
244
245
246
  	val = read_c0_mvpcontrol();
  	printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld
  ", val,
  	       (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
  	       (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
  	       (val & MVPCONTROL_EVP));
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
247
248
249
250
251
  	val = read_c0_mvpconf0();
  	printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld
  ", val,
  	       (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
  	       val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
e01402b11   Ralf Baechle   More AP / SP bits...
252
253
254
  }
  
  /* Find some VPE program space  */
571e0bed8   Ralf Baechle   MIPS: MT: Fix 32-...
255
  static void *alloc_progmem(unsigned long len)
e01402b11   Ralf Baechle   More AP / SP bits...
256
  {
5408c490a   Ralf Baechle   [MIPS] VPE loader...
257
  	void *addr;
e01402b11   Ralf Baechle   More AP / SP bits...
258
  #ifdef CONFIG_MIPS_VPE_LOADER_TOM
5408c490a   Ralf Baechle   [MIPS] VPE loader...
259
260
261
262
  	/*
  	 * This means you must tell Linux to use less memory than you
  	 * physically have, for example by passing a mem= boot argument.
  	 */
9f2546ade   Ralf Baechle   [MIPS] Don't use ...
263
  	addr = pfn_to_kaddr(max_low_pfn);
5408c490a   Ralf Baechle   [MIPS] VPE loader...
264
  	memset(addr, 0, len);
e01402b11   Ralf Baechle   More AP / SP bits...
265
  #else
5408c490a   Ralf Baechle   [MIPS] VPE loader...
266
267
  	/* simple grab some mem for now */
  	addr = kzalloc(len, GFP_KERNEL);
e01402b11   Ralf Baechle   More AP / SP bits...
268
  #endif
5408c490a   Ralf Baechle   [MIPS] VPE loader...
269
270
  
  	return addr;
e01402b11   Ralf Baechle   More AP / SP bits...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  }
  
  static void release_progmem(void *ptr)
  {
  #ifndef CONFIG_MIPS_VPE_LOADER_TOM
  	kfree(ptr);
  #endif
  }
  
  /* Update size with this section: return offset. */
  static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
  {
  	long ret;
  
  	ret = ALIGN(*size, sechdr->sh_addralign ? : 1);
  	*size = ret + sechdr->sh_size;
  	return ret;
  }
  
  /* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
     might -- code, read-only data, read-write data, small data.  Tally
     sizes, and place the offsets into sh_entsize fields: high bit means it
     belongs in init. */
  static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
  			    Elf_Shdr * sechdrs, const char *secstrings)
  {
  	static unsigned long const masks[][2] = {
  		/* NOTE: all executable code must be the first section
  		 * in this array; otherwise modify the text_size
  		 * finder in the two loops below */
  		{SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL},
  		{SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL},
  		{SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL},
  		{ARCH_SHF_SMALL | SHF_ALLOC, 0}
  	};
  	unsigned int m, i;
  
  	for (i = 0; i < hdr->e_shnum; i++)
  		sechdrs[i].sh_entsize = ~0UL;
  
  	for (m = 0; m < ARRAY_SIZE(masks); ++m) {
  		for (i = 0; i < hdr->e_shnum; ++i) {
  			Elf_Shdr *s = &sechdrs[i];
  
  			//  || strncmp(secstrings + s->sh_name, ".init", 5) == 0)
  			if ((s->sh_flags & masks[m][0]) != masks[m][0]
  			    || (s->sh_flags & masks[m][1])
  			    || s->sh_entsize != ~0UL)
  				continue;
e2a9cf96a   Raghu Gandham   MIPS: VPE: Fix co...
320
321
  			s->sh_entsize =
  				get_offset((unsigned long *)&mod->core_size, s);
e01402b11   Ralf Baechle   More AP / SP bits...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  		}
  
  		if (m == 0)
  			mod->core_text_size = mod->core_size;
  
  	}
  }
  
  
  /* from module-elf32.c, but subverted a little */
  
  struct mips_hi16 {
  	struct mips_hi16 *next;
  	Elf32_Addr *addr;
  	Elf32_Addr value;
  };
  
  static struct mips_hi16 *mips_hi16_list;
  static unsigned int gp_offs, gp_addr;
  
  static int apply_r_mips_none(struct module *me, uint32_t *location,
  			     Elf32_Addr v)
  {
  	return 0;
  }
  
  static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
  				Elf32_Addr v)
  {
  	int rel;
  
  	if( !(*location & 0xffff) ) {
  		rel = (int)v - gp_addr;
  	}
  	else {
  		/* .sbss + gp(relative) + offset */
  		/* kludge! */
  		rel =  (int)(short)((int)v + gp_offs +
  				    (int)(short)(*location & 0xffff) - gp_addr);
  	}
  
  	if( (rel > 32768) || (rel < -32768) ) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
364
365
366
367
  		printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
  		       "relative address 0x%x out of range of gp register
  ",
  		       rel);
e01402b11   Ralf Baechle   More AP / SP bits...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  		return -ENOEXEC;
  	}
  
  	*location = (*location & 0xffff0000) | (rel & 0xffff);
  
  	return 0;
  }
  
  static int apply_r_mips_pc16(struct module *me, uint32_t *location,
  			     Elf32_Addr v)
  {
  	int rel;
  	rel = (((unsigned int)v - (unsigned int)location));
  	rel >>= 2;		// because the offset is in _instructions_ not bytes.
  	rel -= 1;		// and one instruction less due to the branch delay slot.
  
  	if( (rel > 32768) || (rel < -32768) ) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
385
386
387
  		printk(KERN_DEBUG "VPE loader: "
   		       "apply_r_mips_pc16: relative address out of range 0x%x
  ", rel);
e01402b11   Ralf Baechle   More AP / SP bits...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  		return -ENOEXEC;
  	}
  
  	*location = (*location & 0xffff0000) | (rel & 0xffff);
  
  	return 0;
  }
  
  static int apply_r_mips_32(struct module *me, uint32_t *location,
  			   Elf32_Addr v)
  {
  	*location += v;
  
  	return 0;
  }
  
  static int apply_r_mips_26(struct module *me, uint32_t *location,
  			   Elf32_Addr v)
  {
  	if (v % 4) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
408
409
410
  		printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
  		       " unaligned relocation
  ");
e01402b11   Ralf Baechle   More AP / SP bits...
411
412
  		return -ENOEXEC;
  	}
307bd284c   Ralf Baechle   VPE loader janito...
413
414
415
416
417
418
419
420
421
422
423
424
  /*
   * Not desperately convinced this is a good check of an overflow condition
   * anyway. But it gets in the way of handling undefined weak symbols which
   * we want to set to zero.
   * if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
   * printk(KERN_ERR
   * "module %s: relocation overflow
  ",
   * me->name);
   * return -ENOEXEC;
   * }
   */
e01402b11   Ralf Baechle   More AP / SP bits...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  
  	*location = (*location & ~0x03ffffff) |
  		((*location + (v >> 2)) & 0x03ffffff);
  	return 0;
  }
  
  static int apply_r_mips_hi16(struct module *me, uint32_t *location,
  			     Elf32_Addr v)
  {
  	struct mips_hi16 *n;
  
  	/*
  	 * We cannot relocate this one now because we don't know the value of
  	 * the carry we need to add.  Save the information, and let LO16 do the
  	 * actual relocation.
  	 */
  	n = kmalloc(sizeof *n, GFP_KERNEL);
  	if (!n)
  		return -ENOMEM;
  
  	n->addr = location;
  	n->value = v;
  	n->next = mips_hi16_list;
  	mips_hi16_list = n;
  
  	return 0;
  }
  
  static int apply_r_mips_lo16(struct module *me, uint32_t *location,
  			     Elf32_Addr v)
  {
  	unsigned long insnlo = *location;
  	Elf32_Addr val, vallo;
477c4b074   Ralf Baechle   MIPS: VPE: Free r...
458
  	struct mips_hi16 *l, *next;
e01402b11   Ralf Baechle   More AP / SP bits...
459
460
461
462
463
  
  	/* Sign extend the addend we extract from the lo insn.  */
  	vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
  
  	if (mips_hi16_list != NULL) {
e01402b11   Ralf Baechle   More AP / SP bits...
464
465
466
  
  		l = mips_hi16_list;
  		while (l != NULL) {
e01402b11   Ralf Baechle   More AP / SP bits...
467
468
469
470
471
  			unsigned long insn;
  
  			/*
  			 * The value for the HI16 had best be the same.
  			 */
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
472
473
   			if (v != l->value) {
  				printk(KERN_DEBUG "VPE loader: "
b1e3afa00   Joe Perches   [MIPS] vpe: Add m...
474
  				       "apply_r_mips_lo16/hi16: \t"
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
475
476
  				       "inconsistent value information
  ");
477c4b074   Ralf Baechle   MIPS: VPE: Free r...
477
  				goto out_free;
e01402b11   Ralf Baechle   More AP / SP bits...
478
  			}
e01402b11   Ralf Baechle   More AP / SP bits...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  			/*
  			 * Do the HI16 relocation.  Note that we actually don't
  			 * need to know anything about the LO16 itself, except
  			 * where to find the low 16 bits of the addend needed
  			 * by the LO16.
  			 */
  			insn = *l->addr;
  			val = ((insn & 0xffff) << 16) + vallo;
  			val += v;
  
  			/*
  			 * Account for the sign extension that will happen in
  			 * the low bits.
  			 */
  			val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
  
  			insn = (insn & ~0xffff) | val;
  			*l->addr = insn;
  
  			next = l->next;
  			kfree(l);
  			l = next;
  		}
  
  		mips_hi16_list = NULL;
  	}
  
  	/*
  	 * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
  	 */
  	val = v + vallo;
  	insnlo = (insnlo & ~0xffff) | (val & 0xffff);
  	*location = insnlo;
  
  	return 0;
477c4b074   Ralf Baechle   MIPS: VPE: Free r...
514
515
516
517
518
519
520
521
522
523
  
  out_free:
  	while (l != NULL) {
  		next = l->next;
  		kfree(l);
  		l = next;
  	}
  	mips_hi16_list = NULL;
  
  	return -ENOEXEC;
e01402b11   Ralf Baechle   More AP / SP bits...
524
525
526
527
528
529
530
531
532
533
534
535
  }
  
  static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
  				Elf32_Addr v) = {
  	[R_MIPS_NONE]	= apply_r_mips_none,
  	[R_MIPS_32]	= apply_r_mips_32,
  	[R_MIPS_26]	= apply_r_mips_26,
  	[R_MIPS_HI16]	= apply_r_mips_hi16,
  	[R_MIPS_LO16]	= apply_r_mips_lo16,
  	[R_MIPS_GPREL16] = apply_r_mips_gprel16,
  	[R_MIPS_PC16] = apply_r_mips_pc16
  };
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
536
  static char *rstrs[] = {
e0daad449   Ralf Baechle   [MIPS] Whitespace...
537
  	[R_MIPS_NONE]	= "MIPS_NONE",
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
538
539
540
541
542
543
544
  	[R_MIPS_32]	= "MIPS_32",
  	[R_MIPS_26]	= "MIPS_26",
  	[R_MIPS_HI16]	= "MIPS_HI16",
  	[R_MIPS_LO16]	= "MIPS_LO16",
  	[R_MIPS_GPREL16] = "MIPS_GPREL16",
  	[R_MIPS_PC16] = "MIPS_PC16"
  };
e01402b11   Ralf Baechle   More AP / SP bits...
545

f18b51cc1   Ralf Baechle   MIPS: VPE: Make v...
546
  static int apply_relocations(Elf32_Shdr *sechdrs,
e01402b11   Ralf Baechle   More AP / SP bits...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
  		      const char *strtab,
  		      unsigned int symindex,
  		      unsigned int relsec,
  		      struct module *me)
  {
  	Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
  	Elf32_Sym *sym;
  	uint32_t *location;
  	unsigned int i;
  	Elf32_Addr v;
  	int res;
  
  	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
  		Elf32_Word r_info = rel[i].r_info;
  
  		/* This is where to make the change */
  		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
  			+ rel[i].r_offset;
  		/* This is the symbol it is referring to */
  		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
  			+ ELF32_R_SYM(r_info);
  
  		if (!sym->st_value) {
  			printk(KERN_DEBUG "%s: undefined weak symbol %s
  ",
  			       me->name, strtab + sym->st_name);
  			/* just print the warning, dont barf */
  		}
  
  		v = sym->st_value;
  
  		res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
  		if( res ) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
580
581
582
583
584
585
  			char *r = rstrs[ELF32_R_TYPE(r_info)];
  		    	printk(KERN_WARNING "VPE loader: .text+0x%x "
  			       "relocation type %s for symbol \"%s\" failed
  ",
  			       rel[i].r_offset, r ? r : "UNKNOWN",
  			       strtab + sym->st_name);
e01402b11   Ralf Baechle   More AP / SP bits...
586
  			return res;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
587
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
588
589
590
591
  	}
  
  	return 0;
  }
f18b51cc1   Ralf Baechle   MIPS: VPE: Make v...
592
  static inline void save_gp_address(unsigned int secbase, unsigned int rel)
e01402b11   Ralf Baechle   More AP / SP bits...
593
594
595
596
597
598
599
600
601
  {
  	gp_addr = secbase + rel;
  	gp_offs = gp_addr - (secbase & 0xffff0000);
  }
  /* end module-elf32.c */
  
  
  
  /* Change all symbols so that sh_value encodes the pointer directly. */
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
602
  static void simplify_symbols(Elf_Shdr * sechdrs,
e01402b11   Ralf Baechle   More AP / SP bits...
603
604
605
606
607
608
609
610
  			    unsigned int symindex,
  			    const char *strtab,
  			    const char *secstrings,
  			    unsigned int nsecs, struct module *mod)
  {
  	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
  	unsigned long secbase, bssbase = 0;
  	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
611
  	int size;
e01402b11   Ralf Baechle   More AP / SP bits...
612
613
614
  
  	/* find the .bss section for COMMON symbols */
  	for (i = 0; i < nsecs; i++) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
615
  		if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
e01402b11   Ralf Baechle   More AP / SP bits...
616
  			bssbase = sechdrs[i].sh_addr;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
617
618
  			break;
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
619
620
621
622
623
  	}
  
  	for (i = 1; i < n; i++) {
  		switch (sym[i].st_shndx) {
  		case SHN_COMMON:
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
624
625
  			/* Allocate space for the symbol in the .bss section.
  			   st_value is currently size.
e01402b11   Ralf Baechle   More AP / SP bits...
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  			   We want it to have the address of the symbol. */
  
  			size = sym[i].st_value;
  			sym[i].st_value = bssbase;
  
  			bssbase += size;
  			break;
  
  		case SHN_ABS:
  			/* Don't need to do anything */
  			break;
  
  		case SHN_UNDEF:
  			/* ret = -ENOENT; */
  			break;
  
  		case SHN_MIPS_SCOMMON:
b1e3afa00   Joe Perches   [MIPS] vpe: Add m...
643
  			printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON "
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
644
645
646
  			       "symbol <%s> st_shndx %d
  ", strtab + sym[i].st_name,
  			       sym[i].st_shndx);
e01402b11   Ralf Baechle   More AP / SP bits...
647
648
649
650
651
652
653
654
655
656
657
658
659
  			// .sbss section
  			break;
  
  		default:
  			secbase = sechdrs[sym[i].st_shndx].sh_addr;
  
  			if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) {
  				save_gp_address(secbase, sym[i].st_value);
  			}
  
  			sym[i].st_value += secbase;
  			break;
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
660
  	}
e01402b11   Ralf Baechle   More AP / SP bits...
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
  }
  
  #ifdef DEBUG_ELFLOADER
  static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
  			    const char *strtab, struct module *mod)
  {
  	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
  	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
  
  	printk(KERN_DEBUG "dump_elfsymbols: n %d
  ", n);
  	for (i = 1; i < n; i++) {
  		printk(KERN_DEBUG " i %d name <%s> 0x%x
  ", i,
  		       strtab + sym[i].st_name, sym[i].st_value);
  	}
  }
  #endif
e01402b11   Ralf Baechle   More AP / SP bits...
679
  /* We are prepared so configure and start the VPE... */
be6e14374   Ralf Baechle   [MIPS] vpe_elfloa...
680
  static int vpe_run(struct vpe * v)
e01402b11   Ralf Baechle   More AP / SP bits...
681
  {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
682
  	unsigned long flags, val, dmt_flag;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
683
  	struct vpe_notifications *n;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
684
  	unsigned int vpeflags;
e01402b11   Ralf Baechle   More AP / SP bits...
685
686
687
  	struct tc *t;
  
  	/* check we are the Master VPE */
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
688
  	local_irq_save(flags);
e01402b11   Ralf Baechle   More AP / SP bits...
689
690
691
  	val = read_c0_vpeconf0();
  	if (!(val & VPECONF0_MVP)) {
  		printk(KERN_WARNING
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
692
693
  		       "VPE loader: only Master VPE's are allowed to configure MT
  ");
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
694
  		local_irq_restore(flags);
e01402b11   Ralf Baechle   More AP / SP bits...
695
696
  		return -1;
  	}
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
697
698
  	dmt_flag = dmt();
  	vpeflags = dvpe();
e01402b11   Ralf Baechle   More AP / SP bits...
699

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
700
  	if (!list_empty(&v->tc)) {
e0daad449   Ralf Baechle   [MIPS] Whitespace...
701
  		if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
702
703
704
705
706
707
708
709
  			evpe(vpeflags);
  			emt(dmt_flag);
  			local_irq_restore(flags);
  
  			printk(KERN_WARNING
  			       "VPE loader: TC %d is already in use.
  ",
                                 t->index);
e0daad449   Ralf Baechle   [MIPS] Whitespace...
710
711
712
  			return -ENOEXEC;
  		}
  	} else {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
713
714
715
716
717
718
719
  		evpe(vpeflags);
  		emt(dmt_flag);
  		local_irq_restore(flags);
  
  		printk(KERN_WARNING
  		       "VPE loader: No TC's associated with VPE %d
  ",
e0daad449   Ralf Baechle   [MIPS] Whitespace...
720
  		       v->minor);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
721

e0daad449   Ralf Baechle   [MIPS] Whitespace...
722
723
  		return -ENOEXEC;
  	}
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
724

e01402b11   Ralf Baechle   More AP / SP bits...
725
  	/* Put MVPE's into 'configuration state' */
340ee4b98   Ralf Baechle   Virtual SMP suppo...
726
  	set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b11   Ralf Baechle   More AP / SP bits...
727

e01402b11   Ralf Baechle   More AP / SP bits...
728
  	settc(t->index);
e01402b11   Ralf Baechle   More AP / SP bits...
729
730
  	/* should check it is halted, and not activated */
  	if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
731
732
733
734
735
736
  		evpe(vpeflags);
  		emt(dmt_flag);
  		local_irq_restore(flags);
  
  		printk(KERN_WARNING "VPE loader: TC %d is already active!
  ",
e01402b11   Ralf Baechle   More AP / SP bits...
737
  		       t->index);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
738

e01402b11   Ralf Baechle   More AP / SP bits...
739
740
741
742
743
  		return -ENOEXEC;
  	}
  
  	/* Write the address we want it to start running from in the TCPC register. */
  	write_tc_c0_tcrestart((unsigned long)v->__start);
e01402b11   Ralf Baechle   More AP / SP bits...
744
  	write_tc_c0_tccontext((unsigned long)0);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
745

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
746
747
748
749
  	/*
  	 * Mark the TC as activated, not interrupt exempt and not dynamically
  	 * allocatable
  	 */
e01402b11   Ralf Baechle   More AP / SP bits...
750
751
752
753
754
  	val = read_tc_c0_tcstatus();
  	val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
  	write_tc_c0_tcstatus(val);
  
  	write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
e01402b11   Ralf Baechle   More AP / SP bits...
755
756
  	/*
  	 * The sde-kit passes 'memsize' to __start in $a3, so set something
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
757
  	 * here...  Or set $a3 to zero and define DFLT_STACK_SIZE and
e01402b11   Ralf Baechle   More AP / SP bits...
758
759
  	 * DFLT_HEAP_SIZE when you compile your program
  	 */
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
760
  	mttgpr(6, v->ntcs);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
761
  	mttgpr(7, physical_memsize);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
762
763
764
765
766
767
  
  	/* set up VPE1 */
  	/*
  	 * bind the TC to VPE 1 as late as possible so we only have the final
  	 * VPE registers to set up, and so an EJTAG probe can trigger on it
  	 */
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
768
  	write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
e01402b11   Ralf Baechle   More AP / SP bits...
769

a94d70204   Elizabeth Oldham   [MIPS] MT: Fix se...
770
771
772
  	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
  
  	back_to_back_c0_hazard();
e0daad449   Ralf Baechle   [MIPS] Whitespace...
773
774
775
  	/* Set up the XTC bit in vpeconf0 to point at our tc */
  	write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
  	                      | (t->index << VPECONF0_XTC_SHIFT));
e01402b11   Ralf Baechle   More AP / SP bits...
776

a94d70204   Elizabeth Oldham   [MIPS] MT: Fix se...
777
  	back_to_back_c0_hazard();
e0daad449   Ralf Baechle   [MIPS] Whitespace...
778
779
  	/* enable this VPE */
  	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
e01402b11   Ralf Baechle   More AP / SP bits...
780
781
  
  	/* clear out any left overs from a previous program */
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
782
  	write_vpe_c0_status(0);
e01402b11   Ralf Baechle   More AP / SP bits...
783
784
785
  	write_vpe_c0_cause(0);
  
  	/* take system out of configuration state */
340ee4b98   Ralf Baechle   Virtual SMP suppo...
786
  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b11   Ralf Baechle   More AP / SP bits...
787

b618336aa   Kevin D. Kissell   [MIPS] Fixes nece...
788
789
790
791
792
  	/*
  	 * SMTC/SMVP kernels manage VPE enable independently,
  	 * but uniprocessor kernels need to turn it on, even
  	 * if that wasn't the pre-dvpe() state.
  	 */
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
793
  #ifdef CONFIG_SMP
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
794
  	evpe(vpeflags);
b618336aa   Kevin D. Kissell   [MIPS] Fixes nece...
795
796
  #else
  	evpe(EVPE_ENABLE);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
797
798
799
  #endif
  	emt(dmt_flag);
  	local_irq_restore(flags);
e01402b11   Ralf Baechle   More AP / SP bits...
800

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
801
802
  	list_for_each_entry(n, &v->notify, list)
  		n->start(minor);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
803

e01402b11   Ralf Baechle   More AP / SP bits...
804
805
  	return 0;
  }
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
806
  static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
e01402b11   Ralf Baechle   More AP / SP bits...
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
  				      unsigned int symindex, const char *strtab,
  				      struct module *mod)
  {
  	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
  	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
  
  	for (i = 1; i < n; i++) {
  		if (strcmp(strtab + sym[i].st_name, "__start") == 0) {
  			v->__start = sym[i].st_value;
  		}
  
  		if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) {
  			v->shared_ptr = (void *)sym[i].st_value;
  		}
  	}
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
822
823
  	if ( (v->__start == 0) || (v->shared_ptr == NULL))
  		return -1;
e01402b11   Ralf Baechle   More AP / SP bits...
824
825
  	return 0;
  }
307bd284c   Ralf Baechle   VPE loader janito...
826
  /*
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
827
828
829
830
   * Allocates a VPE with some program code space(the load address), copies the
   * contents of the program (p)buffer performing relocatations/etc, free's it
   * when finished.
   */
be6e14374   Ralf Baechle   [MIPS] vpe_elfloa...
831
  static int vpe_elfload(struct vpe * v)
e01402b11   Ralf Baechle   More AP / SP bits...
832
833
834
835
836
  {
  	Elf_Ehdr *hdr;
  	Elf_Shdr *sechdrs;
  	long err = 0;
  	char *secstrings, *strtab = NULL;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
837
  	unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
e01402b11   Ralf Baechle   More AP / SP bits...
838
839
840
  	struct module mod;	// so we can re-use the relocations code
  
  	memset(&mod, 0, sizeof(struct module));
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
841
  	strcpy(mod.name, "VPE loader");
e01402b11   Ralf Baechle   More AP / SP bits...
842
843
844
845
846
847
  
  	hdr = (Elf_Ehdr *) v->pbuffer;
  	len = v->plen;
  
  	/* Sanity checks against insmoding binaries or wrong arch,
  	   weird elf version */
d303f4a1a   Cyrill Gorcunov   [MIPS] ELF handli...
848
  	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
849
850
  	    || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
  	    || !elf_check_arch(hdr)
e01402b11   Ralf Baechle   More AP / SP bits...
851
852
  	    || hdr->e_shentsize != sizeof(*sechdrs)) {
  		printk(KERN_WARNING
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
853
854
  		       "VPE loader: program wrong arch or weird elf version
  ");
e01402b11   Ralf Baechle   More AP / SP bits...
855
856
857
  
  		return -ENOEXEC;
  	}
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
858
859
  	if (hdr->e_type == ET_REL)
  		relocate = 1;
e01402b11   Ralf Baechle   More AP / SP bits...
860
  	if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
861
862
863
  		printk(KERN_ERR "VPE loader: program length %u truncated
  ",
  		       len);
e01402b11   Ralf Baechle   More AP / SP bits...
864
865
866
867
868
869
870
871
872
873
  		return -ENOEXEC;
  	}
  
  	/* Convenience variables */
  	sechdrs = (void *)hdr + hdr->e_shoff;
  	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
  	sechdrs[0].sh_addr = 0;
  
  	/* And these should exist, but gcc whinges if we don't init them */
  	symindex = strindex = 0;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
874
875
876
877
878
879
880
881
882
  	if (relocate) {
  		for (i = 1; i < hdr->e_shnum; i++) {
  			if (sechdrs[i].sh_type != SHT_NOBITS
  			    && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
  				printk(KERN_ERR "VPE program length %u truncated
  ",
  				       len);
  				return -ENOEXEC;
  			}
e01402b11   Ralf Baechle   More AP / SP bits...
883

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
884
885
886
  			/* Mark all sections sh_addr with their address in the
  			   temporary image. */
  			sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
e01402b11   Ralf Baechle   More AP / SP bits...
887

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
888
889
890
891
892
893
  			/* Internal symbols and strings. */
  			if (sechdrs[i].sh_type == SHT_SYMTAB) {
  				symindex = i;
  				strindex = sechdrs[i].sh_link;
  				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
  			}
e01402b11   Ralf Baechle   More AP / SP bits...
894
  		}
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
895
  		layout_sections(&mod, hdr, sechdrs, secstrings);
e01402b11   Ralf Baechle   More AP / SP bits...
896
  	}
e01402b11   Ralf Baechle   More AP / SP bits...
897
  	v->load_addr = alloc_progmem(mod.core_size);
5408c490a   Ralf Baechle   [MIPS] VPE loader...
898
899
  	if (!v->load_addr)
  		return -ENOMEM;
e01402b11   Ralf Baechle   More AP / SP bits...
900

5408c490a   Ralf Baechle   [MIPS] VPE loader...
901
902
  	pr_info("VPE loader: loading to %p
  ", v->load_addr);
e01402b11   Ralf Baechle   More AP / SP bits...
903

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
904
905
906
  	if (relocate) {
  		for (i = 0; i < hdr->e_shnum; i++) {
  			void *dest;
e01402b11   Ralf Baechle   More AP / SP bits...
907

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
908
909
  			if (!(sechdrs[i].sh_flags & SHF_ALLOC))
  				continue;
e01402b11   Ralf Baechle   More AP / SP bits...
910

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
911
  			dest = v->load_addr + sechdrs[i].sh_entsize;
e01402b11   Ralf Baechle   More AP / SP bits...
912

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
913
914
915
916
917
  			if (sechdrs[i].sh_type != SHT_NOBITS)
  				memcpy(dest, (void *)sechdrs[i].sh_addr,
  				       sechdrs[i].sh_size);
  			/* Update sh_addr to point to copy in image. */
  			sechdrs[i].sh_addr = (unsigned long)dest;
e01402b11   Ralf Baechle   More AP / SP bits...
918

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
919
920
921
922
  			printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x
  ",
  			       secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
923

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
   		/* Fix up syms, so that st_value is a pointer to location. */
   		simplify_symbols(sechdrs, symindex, strtab, secstrings,
   				 hdr->e_shnum, &mod);
  
   		/* Now do relocations. */
   		for (i = 1; i < hdr->e_shnum; i++) {
   			const char *strtab = (char *)sechdrs[strindex].sh_addr;
   			unsigned int info = sechdrs[i].sh_info;
  
   			/* Not a valid relocation section? */
   			if (info >= hdr->e_shnum)
   				continue;
  
   			/* Don't bother with non-allocated sections */
   			if (!(sechdrs[info].sh_flags & SHF_ALLOC))
   				continue;
  
   			if (sechdrs[i].sh_type == SHT_REL)
   				err = apply_relocations(sechdrs, strtab, symindex, i,
   							&mod);
   			else if (sechdrs[i].sh_type == SHT_RELA)
   				err = apply_relocate_add(sechdrs, strtab, symindex, i,
   							 &mod);
   			if (err < 0)
   				return err;
  
    		}
    	} else {
bdf5d42c6   Ralf Baechle   [MIPS] VPE: reimp...
952
  		struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
953

bdf5d42c6   Ralf Baechle   [MIPS] VPE: reimp...
954
  		for (i = 0; i < hdr->e_phnum; i++) {
b618336aa   Kevin D. Kissell   [MIPS] Fixes nece...
955
956
957
958
959
960
961
962
  			if (phdr->p_type == PT_LOAD) {
  				memcpy((void *)phdr->p_paddr,
  				       (char *)hdr + phdr->p_offset,
  				       phdr->p_filesz);
  				memset((void *)phdr->p_paddr + phdr->p_filesz,
  				       0, phdr->p_memsz - phdr->p_filesz);
  		    }
  		    phdr++;
bdf5d42c6   Ralf Baechle   [MIPS] VPE: reimp...
963
964
965
  		}
  
  		for (i = 0; i < hdr->e_shnum; i++) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
966
967
968
969
970
971
972
973
974
975
   			/* Internal symbols and strings. */
   			if (sechdrs[i].sh_type == SHT_SYMTAB) {
   				symindex = i;
   				strindex = sechdrs[i].sh_link;
   				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
  
   				/* mark the symtab's address for when we try to find the
   				   magic symbols */
   				sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
   			}
e01402b11   Ralf Baechle   More AP / SP bits...
976
977
978
979
980
981
982
983
  		}
  	}
  
  	/* make sure it's physically written out */
  	flush_icache_range((unsigned long)v->load_addr,
  			   (unsigned long)v->load_addr + v->len);
  
  	if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
984
985
986
987
988
989
  		if (v->__start == 0) {
  			printk(KERN_WARNING "VPE loader: program does not contain "
  			       "a __start symbol
  ");
  			return -ENOEXEC;
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
990

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
991
992
993
994
995
996
  		if (v->shared_ptr == NULL)
  			printk(KERN_WARNING "VPE loader: "
  			       "program does not contain vpe_shared symbol.
  "
  			       " Unable to use AMVP (AP/SP) facilities.
  ");
e01402b11   Ralf Baechle   More AP / SP bits...
997
998
999
1000
  	}
  
  	printk(" elf loaded
  ");
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1001
  	return 0;
e01402b11   Ralf Baechle   More AP / SP bits...
1002
  }
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1003
1004
  static void cleanup_tc(struct tc *tc)
  {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1005
1006
  	unsigned long flags;
  	unsigned int mtflags, vpflags;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1007
  	int tmp;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1008
1009
1010
  	local_irq_save(flags);
  	mtflags = dmt();
  	vpflags = dvpe();
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
  	/* Put MVPE's into 'configuration state' */
  	set_c0_mvpcontrol(MVPCONTROL_VPC);
  
  	settc(tc->index);
  	tmp = read_tc_c0_tcstatus();
  
  	/* mark not allocated and not dynamically allocatable */
  	tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
  	tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
  	write_tc_c0_tcstatus(tmp);
  
  	write_tc_c0_tchalt(TCHALT_H);
7c3a622d9   Nigel Stephens   [MIPS] vpe: handl...
1023
  	mips_ihb();
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1024
1025
  
  	/* bind it to anything other than VPE1 */
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1026
  //	write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1027
1028
  
  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1029
1030
1031
  	evpe(vpflags);
  	emt(mtflags);
  	local_irq_restore(flags);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1032
1033
1034
1035
1036
1037
1038
1039
1040
  }
  
  static int getcwd(char *buff, int size)
  {
  	mm_segment_t old_fs;
  	int ret;
  
  	old_fs = get_fs();
  	set_fs(KERNEL_DS);
21a151d8c   Ralf Baechle   [MIPS] checkfiles...
1041
  	ret = sys_getcwd(buff, size);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1042
1043
1044
1045
1046
1047
1048
  
  	set_fs(old_fs);
  
  	return ret;
  }
  
  /* checks VPE is unused and gets ready to load program  */
e01402b11   Ralf Baechle   More AP / SP bits...
1049
1050
  static int vpe_open(struct inode *inode, struct file *filp)
  {
c4c4018b0   Ralf Baechle   [MIPS] RTLX, VPE:...
1051
  	enum vpe_state state;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1052
  	struct vpe_notifications *not;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1053
  	struct vpe *v;
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
1054
  	int ret;
e01402b11   Ralf Baechle   More AP / SP bits...
1055

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1056
1057
  	if (minor != iminor(inode)) {
  		/* assume only 1 device at the moment. */
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
1058
1059
1060
1061
  		pr_warning("VPE loader: only vpe1 is supported
  ");
  
  		return -ENODEV;
e01402b11   Ralf Baechle   More AP / SP bits...
1062
  	}
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1063
  	if ((v = get_vpe(tclimit)) == NULL) {
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
1064
1065
1066
1067
  		pr_warning("VPE loader: unable to get vpe
  ");
  
  		return -ENODEV;
e01402b11   Ralf Baechle   More AP / SP bits...
1068
  	}
c4c4018b0   Ralf Baechle   [MIPS] RTLX, VPE:...
1069
1070
  	state = xchg(&v->state, VPE_STATE_INUSE);
  	if (state != VPE_STATE_UNUSED) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1071
1072
  		printk(KERN_DEBUG "VPE loader: tc in use dumping regs
  ");
e01402b11   Ralf Baechle   More AP / SP bits...
1073

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1074
  		list_for_each_entry(not, &v->notify, list) {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1075
  			not->stop(tclimit);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1076
  		}
e01402b11   Ralf Baechle   More AP / SP bits...
1077

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1078
  		release_progmem(v->load_addr);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1079
  		cleanup_tc(get_tc(tclimit));
e01402b11   Ralf Baechle   More AP / SP bits...
1080
  	}
e01402b11   Ralf Baechle   More AP / SP bits...
1081
1082
  	/* this of-course trashes what was there before... */
  	v->pbuffer = vmalloc(P_SIZE);
863abad4f   Jesper Juhl   MIPS: VPE loader:...
1083
1084
1085
1086
1087
  	if (!v->pbuffer) {
  		pr_warning("VPE loader: unable to allocate memory
  ");
  		return -ENOMEM;
  	}
e01402b11   Ralf Baechle   More AP / SP bits...
1088
1089
1090
  	v->plen = P_SIZE;
  	v->load_addr = NULL;
  	v->len = 0;
d76b0d9b2   David Howells   CRED: Use creds i...
1091
1092
  	v->uid = filp->f_cred->fsuid;
  	v->gid = filp->f_cred->fsgid;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
  
  #ifdef CONFIG_MIPS_APSP_KSPD
  	/* get kspd to tell us when a syscall_exit happens */
  	if (!kspd_events_reqd) {
  		kspd_notify(&kspd_events);
  		kspd_events_reqd++;
  	}
  #endif
  
  	v->cwd[0] = 0;
  	ret = getcwd(v->cwd, VPE_PATH_MAX);
  	if (ret < 0)
  		printk(KERN_WARNING "VPE loader: open, getcwd returned %d
  ", ret);
  
  	v->shared_ptr = NULL;
  	v->__start = 0;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1110

e01402b11   Ralf Baechle   More AP / SP bits...
1111
1112
1113
1114
1115
  	return 0;
  }
  
  static int vpe_release(struct inode *inode, struct file *filp)
  {
307bd284c   Ralf Baechle   VPE loader janito...
1116
  	struct vpe *v;
e01402b11   Ralf Baechle   More AP / SP bits...
1117
  	Elf_Ehdr *hdr;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1118
  	int ret = 0;
e01402b11   Ralf Baechle   More AP / SP bits...
1119

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1120
1121
  	v = get_vpe(tclimit);
  	if (v == NULL)
e01402b11   Ralf Baechle   More AP / SP bits...
1122
  		return -ENODEV;
e01402b11   Ralf Baechle   More AP / SP bits...
1123
  	hdr = (Elf_Ehdr *) v->pbuffer;
d303f4a1a   Cyrill Gorcunov   [MIPS] ELF handli...
1124
  	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1125
  		if (vpe_elfload(v) >= 0) {
e01402b11   Ralf Baechle   More AP / SP bits...
1126
  			vpe_run(v);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1127
  		} else {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1128
1129
   			printk(KERN_WARNING "VPE loader: ELF load failed.
  ");
e01402b11   Ralf Baechle   More AP / SP bits...
1130
1131
1132
  			ret = -ENOEXEC;
  		}
  	} else {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1133
1134
   		printk(KERN_WARNING "VPE loader: only elf files are supported
  ");
e01402b11   Ralf Baechle   More AP / SP bits...
1135
1136
  		ret = -ENOEXEC;
  	}
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1137
1138
  	/* It's good to be able to run the SP and if it chokes have a look at
  	   the /dev/rt?. But if we reset the pointer to the shared struct we
8ebcfc8bc   Nick Andrew   MIPS: Fix incorre...
1139
  	   lose what has happened. So perhaps if garbage is sent to the vpe
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1140
1141
1142
1143
  	   device, use it as a trigger for the reset. Hopefully a nice
  	   executable will be along shortly. */
  	if (ret < 0)
  		v->shared_ptr = NULL;
863abad4f   Jesper Juhl   MIPS: VPE loader:...
1144
  	vfree(v->pbuffer);
e01402b11   Ralf Baechle   More AP / SP bits...
1145
  	v->plen = 0;
863abad4f   Jesper Juhl   MIPS: VPE loader:...
1146

e01402b11   Ralf Baechle   More AP / SP bits...
1147
1148
1149
1150
1151
1152
  	return ret;
  }
  
  static ssize_t vpe_write(struct file *file, const char __user * buffer,
  			 size_t count, loff_t * ppos)
  {
e01402b11   Ralf Baechle   More AP / SP bits...
1153
  	size_t ret = count;
307bd284c   Ralf Baechle   VPE loader janito...
1154
  	struct vpe *v;
e01402b11   Ralf Baechle   More AP / SP bits...
1155

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1156
1157
1158
1159
1160
  	if (iminor(file->f_path.dentry->d_inode) != minor)
  		return -ENODEV;
  
  	v = get_vpe(tclimit);
  	if (v == NULL)
e01402b11   Ralf Baechle   More AP / SP bits...
1161
  		return -ENODEV;
e01402b11   Ralf Baechle   More AP / SP bits...
1162
1163
  	if ((count + v->len) > v->plen) {
  		printk(KERN_WARNING
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1164
1165
  		       "VPE loader: elf size too big. Perhaps strip uneeded symbols
  ");
e01402b11   Ralf Baechle   More AP / SP bits...
1166
1167
1168
1169
  		return -ENOMEM;
  	}
  
  	count -= copy_from_user(v->pbuffer + v->len, buffer, count);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1170
  	if (!count)
e01402b11   Ralf Baechle   More AP / SP bits...
1171
  		return -EFAULT;
e01402b11   Ralf Baechle   More AP / SP bits...
1172
1173
1174
1175
  
  	v->len += count;
  	return ret;
  }
5dfe4c964   Arjan van de Ven   [PATCH] mark stru...
1176
  static const struct file_operations vpe_fops = {
e01402b11   Ralf Baechle   More AP / SP bits...
1177
1178
1179
  	.owner = THIS_MODULE,
  	.open = vpe_open,
  	.release = vpe_release,
6038f373a   Arnd Bergmann   llseek: automatic...
1180
1181
  	.write = vpe_write,
  	.llseek = noop_llseek,
e01402b11   Ralf Baechle   More AP / SP bits...
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
  };
  
  /* module wrapper entry points */
  /* give me a vpe */
  vpe_handle vpe_alloc(void)
  {
  	int i;
  	struct vpe *v;
  
  	/* find a vpe */
  	for (i = 1; i < MAX_VPES; i++) {
  		if ((v = get_vpe(i)) != NULL) {
  			v->state = VPE_STATE_INUSE;
  			return v;
  		}
  	}
  	return NULL;
  }
  
  EXPORT_SYMBOL(vpe_alloc);
  
  /* start running from here */
  int vpe_start(vpe_handle vpe, unsigned long start)
  {
  	struct vpe *v = vpe;
  
  	v->__start = start;
  	return vpe_run(v);
  }
  
  EXPORT_SYMBOL(vpe_start);
  
  /* halt it for now */
  int vpe_stop(vpe_handle vpe)
  {
  	struct vpe *v = vpe;
  	struct tc *t;
  	unsigned int evpe_flags;
  
  	evpe_flags = dvpe();
  
  	if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {
  
  		settc(t->index);
  		write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
  	}
  
  	evpe(evpe_flags);
  
  	return 0;
  }
  
  EXPORT_SYMBOL(vpe_stop);
  
  /* I've done with it thank you */
  int vpe_free(vpe_handle vpe)
  {
  	struct vpe *v = vpe;
  	struct tc *t;
  	unsigned int evpe_flags;
  
  	if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
  		return -ENOEXEC;
  	}
  
  	evpe_flags = dvpe();
  
  	/* Put MVPE's into 'configuration state' */
340ee4b98   Ralf Baechle   Virtual SMP suppo...
1250
  	set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b11   Ralf Baechle   More AP / SP bits...
1251
1252
1253
  
  	settc(t->index);
  	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
7c3a622d9   Nigel Stephens   [MIPS] vpe: handl...
1254
  	/* halt the TC */
e01402b11   Ralf Baechle   More AP / SP bits...
1255
  	write_tc_c0_tchalt(TCHALT_H);
7c3a622d9   Nigel Stephens   [MIPS] vpe: handl...
1256
1257
1258
1259
  	mips_ihb();
  
  	/* mark the TC unallocated */
  	write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
e01402b11   Ralf Baechle   More AP / SP bits...
1260
1261
  
  	v->state = VPE_STATE_UNUSED;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
1262
  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b11   Ralf Baechle   More AP / SP bits...
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
  	evpe(evpe_flags);
  
  	return 0;
  }
  
  EXPORT_SYMBOL(vpe_free);
  
  void *vpe_get_shared(int index)
  {
  	struct vpe *v;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1273
  	if ((v = get_vpe(index)) == NULL)
e01402b11   Ralf Baechle   More AP / SP bits...
1274
  		return NULL;
e01402b11   Ralf Baechle   More AP / SP bits...
1275
1276
1277
1278
1279
  
  	return v->shared_ptr;
  }
  
  EXPORT_SYMBOL(vpe_get_shared);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
  int vpe_getuid(int index)
  {
  	struct vpe *v;
  
  	if ((v = get_vpe(index)) == NULL)
  		return -1;
  
  	return v->uid;
  }
  
  EXPORT_SYMBOL(vpe_getuid);
  
  int vpe_getgid(int index)
  {
  	struct vpe *v;
  
  	if ((v = get_vpe(index)) == NULL)
  		return -1;
  
  	return v->gid;
  }
  
  EXPORT_SYMBOL(vpe_getgid);
  
  int vpe_notify(int index, struct vpe_notifications *notify)
  {
  	struct vpe *v;
  
  	if ((v = get_vpe(index)) == NULL)
  		return -1;
  
  	list_add(&notify->list, &v->notify);
  	return 0;
  }
  
  EXPORT_SYMBOL(vpe_notify);
  
  char *vpe_getcwd(int index)
  {
  	struct vpe *v;
  
  	if ((v = get_vpe(index)) == NULL)
  		return NULL;
  
  	return v->cwd;
  }
  
  EXPORT_SYMBOL(vpe_getcwd);
  
  #ifdef CONFIG_MIPS_APSP_KSPD
  static void kspd_sp_exit( int sp_id)
  {
  	cleanup_tc(get_tc(sp_id));
  }
  #endif
736fad17b   Kay Sievers   [MIPS] VPE loader...
1335
1336
  static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
  			  const char *buf, size_t len)
0f5d0df35   Ralf Baechle   [MIPS] RP: Sysfs ...
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
  {
  	struct vpe *vpe = get_vpe(tclimit);
  	struct vpe_notifications *not;
  
  	list_for_each_entry(not, &vpe->notify, list) {
  		not->stop(tclimit);
  	}
  
  	release_progmem(vpe->load_addr);
  	cleanup_tc(get_tc(tclimit));
  	vpe_stop(vpe);
  	vpe_free(vpe);
  
  	return len;
  }
736fad17b   Kay Sievers   [MIPS] VPE loader...
1352
1353
  static ssize_t show_ntcs(struct device *cd, struct device_attribute *attr,
  			 char *buf)
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1354
1355
1356
1357
1358
1359
  {
  	struct vpe *vpe = get_vpe(tclimit);
  
  	return sprintf(buf, "%d
  ", vpe->ntcs);
  }
736fad17b   Kay Sievers   [MIPS] VPE loader...
1360
1361
  static ssize_t store_ntcs(struct device *dev, struct device_attribute *attr,
  			  const char *buf, size_t len)
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
  {
  	struct vpe *vpe = get_vpe(tclimit);
  	unsigned long new;
  	char *endp;
  
  	new = simple_strtoul(buf, &endp, 0);
  	if (endp == buf)
  		goto out_einval;
  
  	if (new == 0 || new > (hw_tcs - tclimit))
  		goto out_einval;
  
  	vpe->ntcs = new;
  
  	return len;
  
  out_einval:
52a7a27cd   Joe Perches   MIPS: MT: Remove ...
1379
  	return -EINVAL;
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1380
  }
736fad17b   Kay Sievers   [MIPS] VPE loader...
1381
  static struct device_attribute vpe_class_attributes[] = {
0f5d0df35   Ralf Baechle   [MIPS] RP: Sysfs ...
1382
  	__ATTR(kill, S_IWUSR, NULL, store_kill),
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1383
1384
1385
  	__ATTR(ntcs, S_IRUGO | S_IWUSR, show_ntcs, store_ntcs),
  	{}
  };
736fad17b   Kay Sievers   [MIPS] VPE loader...
1386
  static void vpe_device_release(struct device *cd)
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1387
1388
1389
1390
1391
1392
1393
  {
  	kfree(cd);
  }
  
  struct class vpe_class = {
  	.name = "vpe",
  	.owner = THIS_MODULE,
736fad17b   Kay Sievers   [MIPS] VPE loader...
1394
1395
  	.dev_release = vpe_device_release,
  	.dev_attrs = vpe_class_attributes,
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1396
  };
736fad17b   Kay Sievers   [MIPS] VPE loader...
1397
  struct device vpe_device;
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
1398

e01402b11   Ralf Baechle   More AP / SP bits...
1399
1400
  static int __init vpe_module_init(void)
  {
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1401
  	unsigned int mtflags, vpflags;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1402
  	unsigned long flags, val;
e01402b11   Ralf Baechle   More AP / SP bits...
1403
1404
  	struct vpe *v = NULL;
  	struct tc *t;
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1405
  	int tc, err;
e01402b11   Ralf Baechle   More AP / SP bits...
1406
1407
1408
1409
1410
1411
  
  	if (!cpu_has_mipsmt) {
  		printk("VPE loader: not a MIPS MT capable processor
  ");
  		return -ENODEV;
  	}
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
  	if (vpelimit == 0) {
  		printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
  		       "initializing VPE loader.
  Pass maxvpes=<n> argument as "
  		       "kernel argument
  ");
  
  		return -ENODEV;
  	}
  
  	if (tclimit == 0) {
  		printk(KERN_WARNING "No TCs reserved for AP/SP, not "
  		       "initializing VPE loader.
  Pass maxtcs=<n> argument as "
  		       "kernel argument
  ");
  
  		return -ENODEV;
  	}
682e852e2   Alexey Dobriyan   [PATCH] Fix more ...
1431
1432
  	major = register_chrdev(0, module_name, &vpe_fops);
  	if (major < 0) {
e01402b11   Ralf Baechle   More AP / SP bits...
1433
1434
  		printk("VPE loader: unable to register character device
  ");
307bd284c   Ralf Baechle   VPE loader janito...
1435
  		return major;
e01402b11   Ralf Baechle   More AP / SP bits...
1436
  	}
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1437
1438
1439
1440
  	err = class_register(&vpe_class);
  	if (err) {
  		printk(KERN_ERR "vpe_class registration failed
  ");
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
1441
1442
  		goto out_chrdev;
  	}
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1443

736fad17b   Kay Sievers   [MIPS] VPE loader...
1444
  	device_initialize(&vpe_device);
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1445
1446
  	vpe_device.class	= &vpe_class,
  	vpe_device.parent	= NULL,
1bb5beb49   Kay Sievers   mips: struct devi...
1447
  	dev_set_name(&vpe_device, "vpe1");
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1448
  	vpe_device.devt = MKDEV(major, minor);
736fad17b   Kay Sievers   [MIPS] VPE loader...
1449
  	err = device_add(&vpe_device);
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1450
1451
1452
1453
1454
  	if (err) {
  		printk(KERN_ERR "Adding vpe_device failed
  ");
  		goto out_class;
  	}
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
1455

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1456
1457
1458
  	local_irq_save(flags);
  	mtflags = dmt();
  	vpflags = dvpe();
e01402b11   Ralf Baechle   More AP / SP bits...
1459
1460
  
  	/* Put MVPE's into 'configuration state' */
340ee4b98   Ralf Baechle   Virtual SMP suppo...
1461
  	set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b11   Ralf Baechle   More AP / SP bits...
1462
1463
  
  	/* dump_mtregs(); */
e01402b11   Ralf Baechle   More AP / SP bits...
1464
  	val = read_c0_mvpconf0();
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
  	hw_tcs = (val & MVPCONF0_PTC) + 1;
  	hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
  
  	for (tc = tclimit; tc < hw_tcs; tc++) {
  		/*
  		 * Must re-enable multithreading temporarily or in case we
  		 * reschedule send IPIs or similar we might hang.
  		 */
  		clear_c0_mvpcontrol(MVPCONTROL_VPC);
  		evpe(vpflags);
  		emt(mtflags);
  		local_irq_restore(flags);
  		t = alloc_tc(tc);
  		if (!t) {
  			err = -ENOMEM;
  			goto out;
  		}
  
  		local_irq_save(flags);
  		mtflags = dmt();
  		vpflags = dvpe();
  		set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b11   Ralf Baechle   More AP / SP bits...
1487
1488
  
  		/* VPE's */
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1489
1490
  		if (tc < hw_tcs) {
  			settc(tc);
e01402b11   Ralf Baechle   More AP / SP bits...
1491

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1492
  			if ((v = alloc_vpe(tc)) == NULL) {
e01402b11   Ralf Baechle   More AP / SP bits...
1493
1494
  				printk(KERN_WARNING "VPE: unable to allocate VPE
  ");
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1495
1496
  
  				goto out_reenable;
e01402b11   Ralf Baechle   More AP / SP bits...
1497
  			}
41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1498
  			v->ntcs = hw_tcs - tclimit;
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1499
1500
  			/* add the tc to the list of this vpe's tc's. */
  			list_add(&t->tc, &v->tc);
e01402b11   Ralf Baechle   More AP / SP bits...
1501
1502
  
  			/* deactivate all but vpe0 */
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1503
  			if (tc >= tclimit) {
e01402b11   Ralf Baechle   More AP / SP bits...
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  				unsigned long tmp = read_vpe_c0_vpeconf0();
  
  				tmp &= ~VPECONF0_VPA;
  
  				/* master VPE */
  				tmp |= VPECONF0_MVP;
  				write_vpe_c0_vpeconf0(tmp);
  			}
  
  			/* disable multi-threading with TC's */
  			write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1515
  			if (tc >= vpelimit) {
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1516
1517
1518
1519
  				/*
  				 * Set config to be the same as vpe0,
  				 * particularly kseg0 coherency alg
  				 */
e01402b11   Ralf Baechle   More AP / SP bits...
1520
1521
  				write_vpe_c0_config(read_c0_config());
  			}
e01402b11   Ralf Baechle   More AP / SP bits...
1522
1523
1524
1525
  		}
  
  		/* TC's */
  		t->pvpe = v;	/* set the parent vpe */
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1526
  		if (tc >= tclimit) {
e01402b11   Ralf Baechle   More AP / SP bits...
1527
  			unsigned long tmp;
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1528
  			settc(tc);
e01402b11   Ralf Baechle   More AP / SP bits...
1529

2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
  			/* Any TC that is bound to VPE0 gets left as is - in case
  			   we are running SMTC on VPE0. A TC that is bound to any
  			   other VPE gets bound to VPE0, ideally I'd like to make
  			   it homeless but it doesn't appear to let me bind a TC
  			   to a non-existent VPE. Which is perfectly reasonable.
  
  			   The (un)bound state is visible to an EJTAG probe so may
  			   notify GDB...
  			*/
  
  			if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
  				/* tc is bound >vpe0 */
  				write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
  
  				t->pvpe = get_vpe(0);	/* set the parent vpe */
  			}
e01402b11   Ralf Baechle   More AP / SP bits...
1546

7c3a622d9   Nigel Stephens   [MIPS] vpe: handl...
1547
1548
1549
  			/* halt the TC */
  			write_tc_c0_tchalt(TCHALT_H);
  			mips_ihb();
e01402b11   Ralf Baechle   More AP / SP bits...
1550
  			tmp = read_tc_c0_tcstatus();
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1551
  			/* mark not activated and not dynamically allocatable */
e01402b11   Ralf Baechle   More AP / SP bits...
1552
1553
1554
  			tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
  			tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
  			write_tc_c0_tcstatus(tmp);
e01402b11   Ralf Baechle   More AP / SP bits...
1555
1556
  		}
  	}
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1557
  out_reenable:
e01402b11   Ralf Baechle   More AP / SP bits...
1558
  	/* release config state */
340ee4b98   Ralf Baechle   Virtual SMP suppo...
1559
  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b11   Ralf Baechle   More AP / SP bits...
1560

07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1561
1562
1563
  	evpe(vpflags);
  	emt(mtflags);
  	local_irq_restore(flags);
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1564
1565
1566
  #ifdef CONFIG_MIPS_APSP_KSPD
  	kspd_events.kspd_sp_exit = kspd_sp_exit;
  #endif
e01402b11   Ralf Baechle   More AP / SP bits...
1567
  	return 0;
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
1568

41790e04e   Ralf Baechle   [MIPS] RP: Pass n...
1569
1570
  out_class:
  	class_unregister(&vpe_class);
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
1571
1572
  out_chrdev:
  	unregister_chrdev(major, module_name);
07cc0c9e6   Ralf Baechle   [MIPS] MT: Enable...
1573
  out:
27a3bbaf4   Ralf Baechle   [MIPS] VPE: Sprin...
1574
  	return err;
e01402b11   Ralf Baechle   More AP / SP bits...
1575
1576
1577
1578
1579
  }
  
  static void __exit vpe_module_exit(void)
  {
  	struct vpe *v, *n;
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
1580
1581
1582
1583
  	device_del(&vpe_device);
  	unregister_chrdev(major, module_name);
  
  	/* No locking needed here */
e01402b11   Ralf Baechle   More AP / SP bits...
1584
  	list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
1bbfc20d0   Ralf Baechle   MIPS: VPE: Get ri...
1585
  		if (v->state != VPE_STATE_UNUSED)
e01402b11   Ralf Baechle   More AP / SP bits...
1586
  			release_vpe(v);
e01402b11   Ralf Baechle   More AP / SP bits...
1587
  	}
e01402b11   Ralf Baechle   More AP / SP bits...
1588
1589
1590
1591
1592
  }
  
  module_init(vpe_module_init);
  module_exit(vpe_module_exit);
  MODULE_DESCRIPTION("MIPS VPE Loader");
2600990e6   Ralf Baechle   [MIPS] kpsd and o...
1593
  MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
e01402b11   Ralf Baechle   More AP / SP bits...
1594
  MODULE_LICENSE("GPL");