Subversion Repositories HelenOS

Rev

Rev 3596 | Rev 4377 | 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().