summaryrefslogtreecommitdiffstats
path: root/arch/sparc/mm/fault.c
blob: 4c5fd0bc3bfa1a78a3d79598bb6ab140d6864e92 (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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/signal.h>
#include <linux/mm.h>

#include <asm/system.h>
#include <asm/segment.h>
#include <asm/openprom.h>
#include <asm/page.h>
#include <asm/pgtable.h>

extern unsigned long pg0[1024];		/* page table for 0-4MB for everybody */
extern struct sparc_phys_banks sp_banks[14];

extern void die_if_kernel(char *,struct pt_regs *,long);

struct linux_romvec *romvec;

/* foo */

int tbase_needs_unmapping;

/* At boot time we determine these two values necessary for setting
 * up the segment maps and page table entries (pte's).
 */

int num_segmaps, num_contexts;
int invalid_segment;

/* various Virtual Address Cache parameters we find at boot time... */

int vac_size, vac_linesize, vac_do_hw_vac_flushes;
int vac_entries_per_context, vac_entries_per_segment;
int vac_entries_per_page;

/*
 * Define this if things work differently on a i386 and a i486:
 * it will (on a i486) warn about kernel memory accesses that are
 * done without a 'verify_area(VERIFY_WRITE,..)'
 */
#undef CONFIG_TEST_VERIFY_AREA

/* Traverse the memory lists in the prom to see how much physical we
 * have.
 */

unsigned long
probe_memory(void)
{
  register struct linux_romvec *lprom;
  register struct linux_mlist_v0 *mlist;
  register unsigned long bytes, base_paddr, tally;
  register int i;

  bytes = tally = 0;
  base_paddr = 0;
  i=0;
  lprom = romvec;
  switch(lprom->pv_romvers)
    {
    case 0:
      mlist=(*(lprom->pv_v0mem.v0_totphys));
      bytes = tally = mlist->num_bytes;
      base_paddr = (unsigned long) mlist->start_adr;

      sp_banks[0].base_addr = base_paddr;
      sp_banks[0].num_bytes = bytes;

      if(mlist->theres_more != (void *)0) {
	  i++;
	  mlist=mlist->theres_more;
	  bytes=mlist->num_bytes;
	  tally += bytes;
	  sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
	  sp_banks[i].num_bytes = mlist->num_bytes;
	}
      break;
    case 2:
      printk("no v2 memory probe support yet.\n");
      (*(lprom->pv_halt))();
      break;
    }

  i++;
  sp_banks[i].base_addr = 0xdeadbeef;
  sp_banks[i].num_bytes = 0;

  return tally;
}

/* Sparc routine to reserve the mapping of the open boot prom */

/* uncomment this for FAME and FORTUNE! */
/* #define DEBUG_MAP_PROM */

int
map_the_prom(int curr_num_segs)
{
  register unsigned long prom_va_begin;
  register unsigned long prom_va_end;
  register int segmap_entry, i;

  prom_va_begin = LINUX_OPPROM_BEGVM;
  prom_va_end   = LINUX_OPPROM_ENDVM;

#ifdef DEBUG_MAP_PROM
  printk("\ncurr_num_segs = 0x%x\n", curr_num_segs);
#endif

  while( prom_va_begin < prom_va_end)
    {
      segmap_entry=get_segmap(prom_va_begin);

      curr_num_segs = ((segmap_entry<curr_num_segs) 
		       ? segmap_entry : curr_num_segs);

      for(i = num_contexts; --i > 0;)
	  (*romvec->pv_setctxt)(i, (char *) prom_va_begin,
				segmap_entry);

      if(segmap_entry == invalid_segment)
	{

#ifdef DEBUG_MAP_PROM
	  printk("invalid_segments, virt_addr 0x%x\n", prom_va_begin);
#endif

	  prom_va_begin += 0x40000;  /* num bytes per segment entry */
	  continue;
	}

      /* DUH, prom maps itself so that users can access it. This is
       * broken.
       */

#ifdef DEBUG_MAP_PROM
      printk("making segmap for prom privileged, va = 0x%x\n",
	     prom_va_begin);
#endif

      for(i = 0x40; --i >= 0; prom_va_begin+=4096)
	{
	  put_pte(prom_va_begin, get_pte(prom_va_begin) | 0x20000000);
	}

    }

  printk("Mapped the PROM in all contexts...\n");

#ifdef DEBUG_MAP_PROM
  printk("curr_num_segs = 0x%x\n", curr_num_segs);
#endif

  return curr_num_segs;

}

/*
 * This routine handles page faults.  It determines the address,
 * and the problem, and then passes it off to one of the appropriate
 * routines.
 */
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
	die_if_kernel("Oops", regs, error_code);
	do_exit(SIGKILL);
}