Blame view

kernel/linux-rt-4.4.41/arch/sparc/mm/extable.c 2.2 KB
5113f6f70   김현기   kernel add
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
  /*
   * linux/arch/sparc/mm/extable.c
   */
  
  #include <linux/module.h>
  #include <asm/uaccess.h>
  
  void sort_extable(struct exception_table_entry *start,
  		  struct exception_table_entry *finish)
  {
  }
  
  /* Caller knows they are in a range if ret->fixup == 0 */
  const struct exception_table_entry *
  search_extable(const struct exception_table_entry *start,
  	       const struct exception_table_entry *last,
  	       unsigned long value)
  {
  	const struct exception_table_entry *walk;
  
  	/* Single insn entries are encoded as:
  	 *	word 1:	insn address
  	 *	word 2:	fixup code address
  	 *
  	 * Range entries are encoded as:
  	 *	word 1: first insn address
  	 *	word 2: 0
  	 *	word 3: last insn address + 4 bytes
  	 *	word 4: fixup code address
  	 *
  	 * Deleted entries are encoded as:
  	 *	word 1: unused
  	 *	word 2: -1
  	 *
  	 * See asm/uaccess.h for more details.
  	 */
  
  	/* 1. Try to find an exact match. */
  	for (walk = start; walk <= last; walk++) {
  		if (walk->fixup == 0) {
  			/* A range entry, skip both parts. */
  			walk++;
  			continue;
  		}
  
  		/* A deleted entry; see trim_init_extable */
  		if (walk->fixup == -1)
  			continue;
  
  		if (walk->insn == value)
  			return walk;
  	}
  
  	/* 2. Try to find a range match. */
  	for (walk = start; walk <= (last - 1); walk++) {
  		if (walk->fixup)
  			continue;
  
  		if (walk[0].insn <= value && walk[1].insn > value)
  			return walk;
  
  		walk++;
  	}
  
          return NULL;
  }
  
  #ifdef CONFIG_MODULES
  /* We could memmove them around; easier to mark the trimmed ones. */
  void trim_init_extable(struct module *m)
  {
  	unsigned int i;
  	bool range;
  
  	for (i = 0; i < m->num_exentries; i += range ? 2 : 1) {
  		range = m->extable[i].fixup == 0;
  
  		if (within_module_init(m->extable[i].insn, m)) {
  			m->extable[i].fixup = -1;
  			if (range)
  				m->extable[i+1].fixup = -1;
  		}
  		if (range)
  			i++;
  	}
  }
  #endif /* CONFIG_MODULES */
  
  /* Special extable search, which handles ranges.  Returns fixup */
  unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
  {
  	const struct exception_table_entry *entry;
  
  	entry = search_exception_tables(addr);
  	if (!entry)
  		return 0;
  
  	/* Inside range?  Fix g2 and return correct fixup */
  	if (!entry->fixup) {
  		*g2 = (addr - entry->insn) / 4;
  		return (entry + 1)->fixup;
  	}
  
  	return entry->fixup;
  }