00001
00013 #include "mmu.h"
00014
00015 #define EMPTY 0
00016 #define DATA_AVAILABLE 1
00017 #define RESULT_AVAILABLE 2
00018
00024 int anticipatory_paging;
00025
00034 struct mmu_shared_data {
00036 int procnum;
00038 uint32_t virtual_address;
00040 uint32_t translated_address;
00042 int rw;
00044 int status;
00046 pthread_mutex_t lock;
00048 pthread_cond_t condition;
00049 } current =
00050 { -1, 0, 0, 0, 0, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER };
00051
00052
00060 static int mmu_should_exit;
00061
00065 static pthread_mutex_t mem_read_lock = PTHREAD_MUTEX_INITIALIZER;
00066
00070 static STAILQ_HEAD(free_frames, frame) free_frames_head;
00071
00075 static STAILQ_HEAD(used_frames, frame) used_frames_head;
00076
00081 static TAILQ_HEAD(active_pages, active_page) active_page_head;
00082
00083 extern proc_t **proc_table;
00084 extern int max_proc;
00085 extern int debug;
00086
00087
00103 static int
00104 second_chance(int procnum, uint16_t page, int update_stats, frame_t **frame)
00105 {
00106 active_page_t *ap;
00107 proc_t *current_proc;
00108 unsigned int frame_id;
00109 int result;
00110 frame_t *f;
00111
00112 current_proc = proc_table[procnum];
00113 f = NULL;
00114
00115
00116
00117
00118
00119 if (IS_PAGE_PRESENT(current_proc->page_table[page])) {
00120
00121
00122
00123
00124
00125
00126 frame_id = FRAME_ID(current_proc->page_table[page]);
00127 if (update_stats)
00128 mmu.page_hits++;
00129 result = 1;
00130
00131 STAILQ_FOREACH(f, &used_frames_head, entries) {
00132 if (frame_id == f->id) {
00133 PAGE_SET_REFERENCED(current_proc->page_table[page]);
00134 break;
00135 }
00136 }
00137 #ifdef VM_DEBUG
00138 assert(frame_id == f->id);
00139 #endif
00140 } else {
00141
00142
00143
00144
00145
00146
00147 result = 0;
00148 if (update_stats) {
00149 mmu.page_faults++;
00150 current_proc->stats.page_faults++;
00151 }
00152
00153 if (STAILQ_EMPTY(&free_frames_head)) {
00154
00155
00156
00157
00158 int proc_found, page_found;
00159
00160 page_found = proc_found = -1;
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 while (page_found == -1) {
00171 TAILQ_FOREACH(ap, &active_page_head, entries) {
00172 if (IS_PAGE_DIRTY(proc_table[ap->procnum]->page_table[ap->page_id])) {
00173 fprintf(proc_table[ap->procnum]->log_file,
00174 "Write-back della pagina %d\n", ap->page_id);
00175 PAGE_CLEAR_DIRTY(proc_table[ap->procnum]->page_table[ap->page_id]);
00176 PAGE_CLEAR_REFERENCED(proc_table[ap->procnum]->page_table[ap->page_id]);
00177 continue;
00178 }
00179 if (!IS_PAGE_REFERENCED(proc_table[ap->procnum]->page_table[ap->page_id])
00180 && !IS_PAGE_DIRTY(proc_table[ap->procnum]->page_table[ap->page_id])) {
00181 proc_found = ap->procnum;
00182 page_found = ap->page_id;
00183 break;
00184 } else {
00185 if (IS_PAGE_REFERENCED
00186 (proc_table[ap->procnum]->page_table
00187 [ap->page_id])) {
00188 PAGE_CLEAR_REFERENCED(proc_table[ap->procnum]->page_table[ap->page_id]);
00189 continue;
00190 }
00191 }
00192 }
00193 }
00194
00195 #ifdef VM_DEBUG
00196 assert(IS_PAGE_REFERENCED(proc_table[proc_found]->page_table[page_found]) == 0);
00197 assert(IS_PAGE_DIRTY(proc_table[proc_found]->page_table[page_found]) == 0);
00198 #endif
00199
00200
00201
00202
00203
00204 frame_id = FRAME_ID(proc_table[proc_found]->page_table[page_found]);
00205
00206
00207
00208
00209
00210
00211 fprintf(current_proc->log_file,
00212 "<-- La pagina %d del processo %d e stata rimossa "
00213 "dalla memoria %s(frame %d)\n", page_found, proc_found,
00214 (IS_PAGE_DIRTY(proc_table[proc_found]->page_table[page_found]) ?
00215 "e paginata su disco " : ""),
00216 FRAME_ID(proc_table[proc_found]->page_table[page_found]));
00217
00218 PAGE_CLEAR_PRESENT(proc_table[proc_found]->page_table[page_found]);
00219 PAGE_CLEAR_REFERENCED(proc_table[proc_found]->page_table[page_found]);
00220 PAGE_CLEAR_DIRTY(proc_table[proc_found]->page_table[page_found]);
00221 PAGE_CLEAR_FRAMEID(proc_table[proc_found]->page_table[page_found]);
00222
00223 TAILQ_REMOVE(&active_page_head, ap, entries);
00224 XFREE(ap);
00225
00226
00227
00228
00229
00230
00231
00232 STAILQ_FOREACH(f, &used_frames_head, entries) {
00233 if (frame_id == f->id) {
00234 PAGE_SET_REFERENCED(current_proc->page_table[page]);
00235 PAGE_SET_PRESENT(current_proc->page_table[page]);
00236 PAGE_SET_FRAMEID(current_proc->page_table[page], frame_id);
00237 ASSIGN_FRAME_TO_PROC(f, current_proc, page);
00238 STAILQ_REMOVE(&used_frames_head, f, frame, entries);
00239 STAILQ_INSERT_TAIL(&used_frames_head, f, entries);
00240
00241 ap = XMALLOC(active_page_t, 1);
00242 ap->procnum = current.procnum;
00243 ap->page_id = page;
00244 TAILQ_INSERT_TAIL(&active_page_head, ap, entries);
00245
00246 fprintf(current_proc->log_file,
00247 "--> La pagina virtuale %d e' stata "
00248 "associata al frame %u\n", page, f->id);
00249 break;
00250 }
00251 }
00252 } else {
00253
00254
00255
00256
00257
00258 f = STAILQ_FIRST(&free_frames_head);
00259 STAILQ_REMOVE_HEAD(&free_frames_head, entries);
00260 assert(f->valid == 0);
00261 f->valid = 1;
00262 ASSIGN_FRAME_TO_PROC(f, current_proc, page);
00263 STAILQ_INSERT_TAIL(&used_frames_head, f, entries);
00264
00265 fprintf(current_proc->log_file,
00266 "--> La pagina virtuale %d e' stata associata al frame %u\n",
00267 page, f->id);
00268
00269 PAGE_SET_PRESENT(current_proc->page_table[page]);
00270 PAGE_SET_REFERENCED(current_proc->page_table[page]);
00271 PAGE_SET_FRAMEID(current_proc->page_table[page], f->id);
00272
00273 ap = XMALLOC(active_page_t, 1);
00274 ap->procnum = current.procnum;
00275 ap->page_id = page;
00276 TAILQ_INSERT_TAIL(&active_page_head, ap, entries);
00277 }
00278 }
00279
00280 if (frame)
00281 *frame = f;
00282 return result;
00283 }
00284
00285
00294 static void *
00295 thread_mmu(void *pArg)
00296 {
00297 active_page_t *ap, *ap_temp;
00298 proc_t *current_proc;
00299 frame_t *f;
00300 uint16_t page;
00301 uint16_t offset;
00302 uint16_t ws[3];
00303 int result;
00304
00305 printf("--> Thread MMU avviato\n [RAM=%d, PAGESIZE=%d, "
00306 "PHYS-FRAMES=%d, TOTAL_READ=%d, PROC=%d]\n",
00307 mmu.ram_size, mmu.page_size, mmu.max_page_count,
00308 mmu.total_access, max_proc);
00309
00310
00311
00312
00313
00314 while (!mmu_should_exit) {
00315 pthread_mutex_lock(¤t.lock);
00316 while (current.status != DATA_AVAILABLE)
00317 pthread_cond_wait(¤t.condition, ¤t.lock);
00318
00319 if (mmu_should_exit) {
00320 pthread_mutex_unlock(¤t.lock);
00321 break;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330 current_proc = proc_table[current.procnum];
00331 ws[0] = page = current.virtual_address >> mmu.offset_bits;
00332 #ifdef VM_DEBUG
00333 if (page > current_proc->page_count) {
00334 fprintf(stderr, "PROC = %d, PAGE_COUNT = %d, PAGE = %d, "
00335 "ADDRESS = %d\n", current.procnum,
00336 current_proc->page_count, page, current.virtual_address);
00337 assert(0);
00338 }
00339 #endif
00340 offset = current.virtual_address & mmu.offset_mask;
00341
00342 fprintf(current_proc->log_file,
00343 "\n%s indirizzo virtuale %u [pagina %d - offset %d]\n",
00344 current.rw ? "Scrittura" : "Lettura",
00345 current.virtual_address, page, offset);
00346
00347
00348 result = second_chance(current.procnum, page, 1, &f);
00349 #ifdef VM_DEBUG
00350 assert(f);
00351 #endif
00352
00353 if (anticipatory_paging) {
00354 ws[1] = (page > 0)?page-1:(uint16_t)-1;
00355 ws[2] = (page < (current_proc->page_count-1))?page+1:(uint16_t)-1;
00356 if (ws[1] != (uint16_t) -1)
00357 second_chance(current.procnum, ws[1], 0, NULL);
00358 if (ws[2] != (uint16_t) -1)
00359 second_chance(current.procnum, ws[2], 0, NULL);
00360 }
00361
00362 current_proc->stats.mem_accesses++;
00363 current.translated_address = f->physical_addr + offset;
00364 current.status = RESULT_AVAILABLE;
00365 fprintf(current_proc->log_file,
00366 "[PAGE %s] L'indirizzo virtuale %u corrisponde al fisico %u\n",
00367 result?"HIT":"FAULT", current.virtual_address,
00368 current.translated_address);
00369 if (current.rw)
00370 PAGE_SET_DIRTY(current_proc->page_table[page]);
00371
00372 pthread_mutex_unlock(¤t.lock);
00373 pthread_cond_signal(¤t.condition);
00374 }
00375
00376
00377
00378 TAILQ_FOREACH_SAFE(ap, &active_page_head, entries, ap_temp) {
00379 TAILQ_REMOVE(&active_page_head, ap, entries);
00380 XFREE(ap);
00381 }
00382 printf("<-- Thread MMU terminato\n");
00383 pthread_exit(NULL);
00384 }
00385
00386
00400 pthread_t *mmu_init(int max_read, int ram_size, int page_size)
00401 {
00402 pthread_t *tid = XMALLOC(pthread_t, 1);
00403 int i, ret;
00404
00405 mmu_should_exit = 0;
00406 mmu.total_access = max_read;
00407 mmu.page_hits = mmu.page_faults = 0;
00408 mmu.page_size = page_size;
00409 mmu.ram_size = ram_size;
00410 mmu.max_page_count = (mmu.ram_size / mmu.page_size);
00411
00412
00413
00414
00415
00416 if (((float)mmu.max_page_count/max_proc) < 3)
00417 anticipatory_paging = 0;
00418
00419
00420
00421
00422
00423 STAILQ_INIT(&free_frames_head);
00424 STAILQ_INIT(&used_frames_head);
00425 TAILQ_INIT(&active_page_head);
00426
00427
00428
00429
00430
00431 for (i = 0; i < mmu.max_page_count; i++) {
00432 frame_t *f = XMALLOC(frame_t, 1);
00433 f->id = i;
00434 f->physical_addr = i * mmu.page_size;
00435 f->valid = 0;
00436 if (STAILQ_EMPTY(&free_frames_head))
00437 STAILQ_INSERT_HEAD(&free_frames_head, f, entries);
00438 else
00439 STAILQ_INSERT_TAIL(&free_frames_head, f, entries);
00440 }
00441 ret = pthread_create(tid, NULL, &thread_mmu, NULL);
00442
00443 return (ret == 0) ? tid : NULL;
00444 }
00445
00446
00460 uint32_t memory_access(int procnum, uint32_t address, int rw)
00461 {
00462 static int signaled = 0;
00463 uint32_t result = (uint32_t) -1;
00464
00465
00466
00467
00468
00469 pthread_mutex_lock(&mem_read_lock);
00470
00471 if (NUM_OF_REQUESTS() < mmu.total_access) {
00472
00473
00474
00475
00476 pthread_mutex_lock(¤t.lock);
00477 current.procnum = procnum;
00478 current.virtual_address = address;
00479 current.translated_address = 0;
00480 current.rw = rw;
00481 current.status = DATA_AVAILABLE;
00482 pthread_mutex_unlock(¤t.lock);
00483
00484
00485
00486
00487 pthread_cond_signal(¤t.condition);
00488
00489
00490
00491
00492
00493
00494 pthread_mutex_lock(¤t.lock);
00495 while (current.status != RESULT_AVAILABLE)
00496 pthread_cond_wait(¤t.condition, ¤t.lock);
00497 result = current.translated_address;
00498 current.status = EMPTY;
00499 pthread_mutex_unlock(¤t.lock);
00500
00501 if (debug)
00502 process_info(procnum);
00503 } else {
00504
00505
00506
00507
00508
00509
00510 if (!signaled) {
00511 tell_io_device_to_exit();
00512 mmu_should_exit = 1;
00513 current.status = DATA_AVAILABLE;
00514 pthread_cond_signal(¤t.condition);
00515 signaled = 1;
00516 }
00517 }
00518
00519 pthread_mutex_unlock(&mem_read_lock);
00520
00521 return result;
00522 }
00523