]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/lib/amm/amm_modify.c
update
[l4.git] / kernel / fiasco / src / lib / amm / amm_modify.c
1 /*
2  * Copyright (c) 1996, 1998 University of Utah and the Flux Group.
3  * All rights reserved.
4  * 
5  * This file is part of the Flux OSKit.  The OSKit is free software, also known
6  * as "open source;" you can redistribute it and/or modify it under the terms
7  * of the GNU General Public License (GPL), version 2, as published by the Free
8  * Software Foundation (FSF).  To explore alternate licensing terms, contact
9  * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
10  * 
11  * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GPL for more details.  You should have
14  * received a copy of the GPL along with the OSKit; see the file COPYING.  If
15  * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
16  */
17
18 /*
19  * Modify a range of address space
20  */
21 #include <errno.h>
22 #include "amm.h"
23
24 /*
25  * The big cheese.
26  * Modifies an address range to be associated with a new entry and new flags.
27  * Any existing entries wholly within the range are deleted, any that partly
28  * overlap the range are split as necessary.  After adding the new entry,
29  * the amm may attempt to join it with adjacent already-existing entries if
30  * it appears possible (i.e., if the flags words are the same).  The standard
31  * amm_join function is called in this case.
32  *
33  * Function returns zero if successful, non-zero if a split failed (e.g.,
34  * due to lack of memory).
35  * 
36  * Parameters addr and size define the range to be modified.
37  *
38  * nflags is the new flags for the range.
39  *
40  * Nentry is the new entry to use.  nentry may be zero, in which case the amm
41  * allocates a new standard entry itself.  If nentry is non-zero, the caller
42  * must have already allocated any extra attribate data in the entry.  In
43  * either case, the amm will initialize the private part of the new amm_entry,
44  * including setting its address range type flags to the nflags parameter.
45  */
46 int
47 amm_modify(struct amm *amm, vm_offset_t addr, vm_size_t size,
48            int nflags, struct amm_entry *nentry)
49 {
50         struct amm_entry **pentry, *entry, *hentry, *tentry;
51         vm_offset_t eaddr;
52         int rc;
53
54         eaddr = addr + size;
55         if (eaddr < addr)
56                 return EINVAL;
57
58         entry = amm_find_addr(amm, addr);
59         pentry = amm->hint;
60
61         /*
62          * If no explicit entry was specified and the indicated range
63          * already has the desired attributes, there is nothing to do.
64          */
65         if (nentry == 0 && addr >= entry->start && eaddr <= entry->end &&
66             nflags == entry->flags)
67                 return 0;
68
69         /*
70          * Split off anything before the region of interest.
71          */
72         if (entry->start < addr) {
73                 rc = amm_split(amm, pentry, entry, addr, &hentry, &tentry);
74                 if (rc)
75                         return rc;
76                 pentry = &hentry->next;
77                 entry = tentry;
78         }
79         assert(entry->start == addr);
80
81         /*
82          * Now traverse entries that are completely covered by the new
83          * one and delete them.
84          */
85         while (entry->end < eaddr) {
86                 *pentry = entry->next;
87                 amm_free_entry(amm, entry);
88                 entry = *pentry;
89         }
90
91         /*
92          * Split off anything after the region of interest
93          */
94         if (entry->end > eaddr) {
95                 rc = amm_split(amm, pentry, entry, eaddr, &hentry, &tentry);
96                 if (rc)
97                         return rc;
98                 entry = hentry;
99         }
100         assert(entry->end == eaddr);
101
102         /*
103          * Final entry corresponding to end of range.
104          * If no explicit new entry was specified or the current entry
105          * was specified we just modify the existing entry.
106          */
107         if (nentry == entry) {
108                 entry->start = addr;
109                 entry->flags = nflags;
110                 nentry = entry;
111         } else {
112                 if (nentry == 0) {
113                         nentry = amm_alloc_entry(amm, addr, eaddr-addr, nflags);
114                         if (nentry == 0)
115                                 return ENOMEM;
116                 }
117                 *pentry = nentry;
118                 nentry->next = entry->next;
119                 nentry->start = addr;
120                 nentry->end = eaddr;
121                 nentry->flags = nflags;
122                 amm_free_entry(amm, entry);
123         }
124
125         /*
126          * Finally, try to merge with previous entry...
127          */
128         if (pentry != &amm->nodes) {
129                 hentry = (struct amm_entry *)pentry;
130                 tentry = nentry;
131                 assert(hentry->next == tentry);
132                 if (hentry->flags == tentry->flags) {
133                         for (pentry = &amm->nodes; *pentry;
134                              pentry = &(*pentry)->next)
135                                 if (*pentry == hentry)
136                                         break;
137                         assert(*pentry);
138                         rc = amm_join(amm, pentry, hentry, tentry, &nentry);
139                         /* XXX return an error on rc != 0? */
140                         if (rc)
141                                 pentry = &hentry->next;
142                 }
143         }
144         /*
145          * ...and next entry.
146          */
147         if (nentry->next) {
148                 hentry = nentry;
149                 tentry = nentry->next;
150                 if (hentry->flags == tentry->flags) {
151                         rc = amm_join(amm, pentry, hentry, tentry, &nentry);
152                         /* XXX return an error on rc != 0? */
153                 }
154
155         }
156
157         amm->hint = pentry;
158         return 0;
159 }
160