summaryrefslogtreecommitdiff
path: root/libdiskfs/=exc.c
blob: 76cb1bcc490bfe91c7b85c98b30841492cab1752 (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
/* 
   Copyright (C) 1994 Free Software Foundation

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that 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., 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "priv.h"

#define EXC_TABLE_SIZE 1024	/* Ack!XXX -- should be dynamically sized!  */
/* This is the table of addresses for which we should report faults
   back to the faulting thread. */
static struct 
{
  struct pager *p;
  vm_offset_t pager_offset;
  void *offset;
  long length;
} memory_fault_table[EXC_TABLE_SIZE];

static spin_lock_t memory_fault_lock;

/* Mark the memory at ADDR continuing for LEN bytes as mapped from pager P
   at offset OFF.  Call when vm_map-ing part of the disk. 
   CAVEAT: addr must not be zero. */
void
diskfs_register_memory_fault_area (struct pager *p,
				   vm_address_t off,
				   void *addr, 
				   long len)
{
  int i;

  assert (addr);

  spin_lock (&memory_fault_lock);
  
  for (i = 0; i < EXC_TABLE_SIZE; i++)
    if (!memory_fault_table[i].offset)
      {
	memory_fault_table[i].p = p;
	memory_fault_table[i].pager_offset = off;
	memory_fault_table[i].offset = addr;
	memory_fault_table[i].length = len;
	spin_unlock (&memory_fault_lock);
	return;
      }

  assert (0);
}

/* Mark the memory at ADDR continuing for LEN bytes as no longer
   mapped from the disk.  Call when vm_unmap-ing part of the disk.  */
void
diskfs_unregister_memory_fault_area (void *addr,
				     long len)
{
  int i;

  assert (addr);

  spin_lock (&memory_fault_lock);
  for (i = 0; i < EXC_TABLE_SIZE; i++)
    if (memory_fault_table[i].offset == addr
	&& memory_fault_table[i].length == len)
      {
	memory_fault_table[i].offset = 0;
	spin_unlock (&memory_fault_lock);
	return;
      }
  assert (0);
}

/* Set up the exception handling system.  */
void
init_exceptions ()
{
  int i;

  for (i = 0; i < EXC_TABLE_SIZE; i++)
    memory_fault_table[i].offset = 0;
  spin_lock_init (&memory_fault_lock);

#if notdebugging
  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &excport);
  mach_port_insert_right (mach_task_self (), excport, excport, 
			  MACH_MSG_TYPE_MAKE_SEND);
  task_get_special_port (mach_task_self (), TASK_EXCEPTION_PORT, &oldexcport);
  task_set_special_port (mach_task_self (), TASK_EXCEPTION_PORT, excport);
  mach_port_deallocate (mach_task_self (), excport);
#endif
}