Rev 3596 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3596 | Rev 3624 | ||
---|---|---|---|
Line 110... | Line 110... | ||
110 | 110 | ||
111 | /** Kernel address space. */ |
111 | /** Kernel address space. */ |
112 | as_t *AS_KERNEL = NULL; |
112 | as_t *AS_KERNEL = NULL; |
113 | 113 | ||
114 | static int area_flags_to_page_flags(int); |
114 | static int area_flags_to_page_flags(int); |
115 | static as_area_t *find_area_and_lock(as_t *, uintptr_t); |
- | |
116 | static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *); |
115 | static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *); |
117 | static void sh_info_remove_reference(share_info_t *); |
116 | static void sh_info_remove_reference(share_info_t *); |
118 | 117 | ||
119 | static int as_constructor(void *obj, int flags) |
118 | static int as_constructor(void *obj, int flags) |
120 | { |
119 | { |
Line 1105... | Line 1104... | ||
1105 | spinlock_unlock(&asidlock); |
1104 | spinlock_unlock(&asidlock); |
1106 | 1105 | ||
1107 | AS = new_as; |
1106 | AS = new_as; |
1108 | } |
1107 | } |
1109 | 1108 | ||
1110 | #ifdef CONFIG_UDEBUG |
- | |
1111 | - | ||
1112 | /** Write directly into a page, bypassing area flags. |
- | |
1113 | * |
- | |
1114 | * This allows a debugger to write into a page that is mapped read-only |
- | |
1115 | * (such as the text segment). Naturally, this can only be done if the |
- | |
1116 | * correspoinding area is private (not shared) and anonymous. |
- | |
1117 | * |
- | |
1118 | * If this is not the case, this function calls as_area_make_writeable() |
- | |
1119 | * first. |
- | |
1120 | */ |
- | |
1121 | static int debug_write_inside_page(uintptr_t va, void *data, size_t n) |
- | |
1122 | { |
- | |
1123 | uintptr_t page; |
- | |
1124 | pte_t *pte; |
- | |
1125 | as_area_t *area; |
- | |
1126 | uintptr_t frame; |
- | |
1127 | ipl_t ipl; |
- | |
1128 | int rc; |
- | |
1129 | - | ||
1130 | page = ALIGN_DOWN(va, PAGE_SIZE); |
- | |
1131 | ASSERT(ALIGN_DOWN(va + n - 1, PAGE_SIZE) == page); |
- | |
1132 | - | ||
1133 | restart: |
- | |
1134 | mutex_lock(&AS->lock); |
- | |
1135 | ipl = interrupts_disable(); |
- | |
1136 | area = find_area_and_lock(AS, page); |
- | |
1137 | if (area->backend != &anon_backend || area->sh_info != NULL) { |
- | |
1138 | mutex_unlock(&area->lock); |
- | |
1139 | mutex_unlock(&AS->lock); |
- | |
1140 | interrupts_restore(ipl); |
- | |
1141 | - | ||
1142 | rc = as_area_make_writeable(area->base); |
- | |
1143 | if (rc != 0) return rc; |
- | |
1144 | - | ||
1145 | goto restart; |
- | |
1146 | } |
- | |
1147 | - | ||
1148 | pte = page_mapping_find(AS, page); |
- | |
1149 | if (! (pte && PTE_VALID(pte) && PTE_PRESENT(pte)) ) { |
- | |
1150 | mutex_unlock(&area->lock); |
- | |
1151 | mutex_unlock(&AS->lock); |
- | |
1152 | interrupts_restore(ipl); |
- | |
1153 | - | ||
1154 | rc = as_page_fault(page, PF_ACCESS_WRITE, NULL); |
- | |
1155 | if (rc == AS_PF_FAULT) return EINVAL; |
- | |
1156 | - | ||
1157 | goto restart; |
- | |
1158 | } |
- | |
1159 | - | ||
1160 | frame = PTE_GET_FRAME(pte); |
- | |
1161 | memcpy((void *)(PA2KA(frame) + (va - page)), data, n); |
- | |
1162 | - | ||
1163 | mutex_unlock(&area->lock); |
- | |
1164 | mutex_unlock(&AS->lock); |
- | |
1165 | interrupts_restore(ipl); |
- | |
1166 | - | ||
1167 | return EOK; |
- | |
1168 | } |
- | |
1169 | - | ||
1170 | /** Write data bypassing area flags. |
- | |
1171 | * |
- | |
1172 | * See debug_write_inside_page(). |
- | |
1173 | */ |
- | |
1174 | int as_debug_write(uintptr_t va, void *data, size_t n) |
- | |
1175 | { |
- | |
1176 | size_t now; |
- | |
1177 | int rc; |
- | |
1178 | - | ||
1179 | while (n > 0) { |
- | |
1180 | /* Number of bytes until the end of page */ |
- | |
1181 | now = ALIGN_DOWN(va, PAGE_SIZE) + PAGE_SIZE - va; |
- | |
1182 | if (now > n) now = n; |
- | |
1183 | - | ||
1184 | rc = debug_write_inside_page(va, data, now); |
- | |
1185 | if (rc != EOK) return rc; |
- | |
1186 | - | ||
1187 | va += now; |
- | |
1188 | data += now; |
- | |
1189 | n -= now; |
- | |
1190 | } |
- | |
1191 | - | ||
1192 | return EOK; |
- | |
1193 | } |
- | |
1194 | - | ||
1195 | /** Make sure area is private and anonymous. |
- | |
1196 | * |
- | |
1197 | * Not atomic atm. |
- | |
1198 | * @param address Virtual address in AS. |
- | |
1199 | */ |
- | |
1200 | int as_area_make_writeable(uintptr_t address) |
- | |
1201 | { |
- | |
1202 | ipl_t ipl; |
- | |
1203 | as_area_t *area; |
- | |
1204 | uintptr_t base, page; |
- | |
1205 | uintptr_t old_frame, frame; |
- | |
1206 | size_t size; |
- | |
1207 | int flags; |
- | |
1208 | int page_flags; |
- | |
1209 | pte_t *pte; |
- | |
1210 | int rc; |
- | |
1211 | uintptr_t *pagemap; |
- | |
1212 | - | ||
1213 | ipl = interrupts_disable(); |
- | |
1214 | mutex_lock(&AS->lock); |
- | |
1215 | area = find_area_and_lock(AS, address); |
- | |
1216 | if (!area) { |
- | |
1217 | /* |
- | |
1218 | * Could not find the address space area. |
- | |
1219 | */ |
- | |
1220 | mutex_unlock(&AS->lock); |
- | |
1221 | interrupts_restore(ipl); |
- | |
1222 | return ENOENT; |
- | |
1223 | } |
- | |
1224 | - | ||
1225 | if (area->backend == &anon_backend && !area->sh_info) { |
- | |
1226 | /* Nothing to do */ |
- | |
1227 | mutex_unlock(&area->lock); |
- | |
1228 | mutex_unlock(&AS->lock); |
- | |
1229 | interrupts_restore(ipl); |
- | |
1230 | return EOK; |
- | |
1231 | } |
- | |
1232 | - | ||
1233 | base = area->base; |
- | |
1234 | size = area->pages * PAGE_SIZE; |
- | |
1235 | flags = area->flags; |
- | |
1236 | page_flags = as_area_get_flags(area); |
- | |
1237 | - | ||
1238 | pagemap = malloc(area->pages * sizeof(uintptr_t), 0); |
- | |
1239 | page_table_lock(AS, false); |
- | |
1240 | - | ||
1241 | for (page = base; page < base + size; page += PAGE_SIZE) { |
- | |
1242 | pte = page_mapping_find(AS, page); |
- | |
1243 | if (!pte || !PTE_PRESENT(pte) || !PTE_READABLE(pte)) { |
- | |
1244 | /* Fetch the missing page */ |
- | |
1245 | if (!area->backend || !area->backend->page_fault) { |
- | |
1246 | page_table_unlock(AS, false); |
- | |
1247 | mutex_unlock(&area->lock); |
- | |
1248 | mutex_unlock(&AS->lock); |
- | |
1249 | interrupts_restore(ipl); |
- | |
1250 | return EINVAL; |
- | |
1251 | } |
- | |
1252 | if (area->backend->page_fault(area, page, PF_ACCESS_READ) != AS_PF_OK) { |
- | |
1253 | page_table_unlock(AS, false); |
- | |
1254 | mutex_unlock(&area->lock); |
- | |
1255 | mutex_unlock(&AS->lock); |
- | |
1256 | interrupts_restore(ipl); |
- | |
1257 | return EINVAL; |
- | |
1258 | } |
- | |
1259 | } |
- | |
1260 | ASSERT(PTE_VALID(pte)); |
- | |
1261 | - | ||
1262 | old_frame = PTE_GET_FRAME(pte); |
- | |
1263 | - | ||
1264 | frame = (uintptr_t)frame_alloc(ONE_FRAME, 0); |
- | |
1265 | memcpy((void *) PA2KA(frame), (void *)PA2KA(old_frame), |
- | |
1266 | FRAME_SIZE); |
- | |
1267 | - | ||
1268 | pagemap[(page - base) / PAGE_SIZE] = frame; |
- | |
1269 | } |
- | |
1270 | - | ||
1271 | page_table_unlock(AS, false); |
- | |
1272 | mutex_unlock(&area->lock); |
- | |
1273 | mutex_unlock(&AS->lock); |
- | |
1274 | interrupts_restore(ipl); |
- | |
1275 | - | ||
1276 | rc = as_area_destroy(AS, address); |
- | |
1277 | if (rc < 0) { |
- | |
1278 | free(pagemap); |
- | |
1279 | return rc; |
- | |
1280 | } |
- | |
1281 | - | ||
1282 | area = as_area_create(AS, flags, size, base, AS_AREA_ATTR_PARTIAL, |
- | |
1283 | &anon_backend, NULL); |
- | |
1284 | if (area == NULL) { |
- | |
1285 | free(pagemap); |
- | |
1286 | return rc; |
- | |
1287 | } |
- | |
1288 | - | ||
1289 | mutex_lock(&AS->lock); |
- | |
1290 | mutex_lock(&area->lock); |
- | |
1291 | page_table_lock(AS, false); |
- | |
1292 | for (page = base; page < base + size; page += PAGE_SIZE) { |
- | |
1293 | frame = pagemap[(page - base) / PAGE_SIZE]; |
- | |
1294 | - | ||
1295 | page_mapping_insert(AS, page, frame, page_flags); |
- | |
1296 | if (!used_space_insert(area, page, 1)) |
- | |
1297 | panic("Could not insert used space.\n"); |
- | |
1298 | } |
- | |
1299 | - | ||
1300 | page_table_unlock(AS, false); |
- | |
1301 | - | ||
1302 | area->attributes &= ~AS_AREA_ATTR_PARTIAL; |
- | |
1303 | - | ||
1304 | mutex_unlock(&area->lock); |
- | |
1305 | mutex_unlock(&AS->lock); |
- | |
1306 | - | ||
1307 | free(pagemap); |
- | |
1308 | - | ||
1309 | return EOK; |
- | |
1310 | } |
- | |
1311 | - | ||
1312 | #endif /* defined(CONFIG_UDEBUG) */ |
- | |
1313 | - | ||
1314 | /** Convert address space area flags to page flags. |
1109 | /** Convert address space area flags to page flags. |
1315 | * |
1110 | * |
1316 | * @param aflags Flags of some address space area. |
1111 | * @param aflags Flags of some address space area. |
1317 | * |
1112 | * |
1318 | * @return Flags to be passed to page_mapping_insert(). |
1113 | * @return Flags to be passed to page_mapping_insert(). |