Changeset 408 for trunk/kernel/mm
- Timestamp:
- Dec 5, 2017, 4:20:07 PM (7 years ago)
- Location:
- trunk/kernel/mm
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/mm/mapper.c
r407 r408 240 240 rwlock_wr_unlock( &mapper->lock ); 241 241 242 // deschedule towait load completion242 // wait load completion 243 243 while( 1 ) 244 244 { 245 245 // exit waiting loop when loaded 246 if( page_is_flag( page , PG_INLOAD )) break;246 if( page_is_flag( page , PG_INLOAD ) == false ) break; 247 247 248 248 // deschedule 249 sched_yield( );249 sched_yield("waiting page loading"); 250 250 } 251 251 } … … 253 253 else // page available in mapper 254 254 { 255 256 255 rwlock_rd_unlock( &mapper->lock ); 257 256 } -
trunk/kernel/mm/page.c
r407 r408 47 47 page->index = 0; 48 48 page->refcount = 0; 49 page->fork_nr = 0; 49 50 50 51 spinlock_init( &page->lock ); … … 180 181 // deschedule the calling thread 181 182 thread_block( thread , THREAD_BLOCKED_PAGE ); 182 sched_yield( );183 sched_yield("cannot lock a page"); 183 184 } 184 185 else // page is not locked -
trunk/kernel/mm/page.h
r407 r408 67 67 xlist_entry_t wait_root; /*! root of list of waiting threads (16) */ 68 68 uint32_t refcount; /*! reference counter (4) */ 69 uint32_t reserved; /*! UNUSED(4) */69 uint32_t fork_nr; /*! number of pending forks (4) */ 70 70 spinlock_t lock; /*! only used to set the PG_LOCKED flag (16) */ 71 71 } -
trunk/kernel/mm/vmm.c
r407 r408 32 32 #include <rwlock.h> 33 33 #include <list.h> 34 #include <xlist.h> 34 35 #include <bits.h> 35 36 #include <process.h> … … 69 70 // initialize local list of vsegs 70 71 vmm->vsegs_nr = 0; 71 list_root_init( &vmm->vsegs_root);72 r wlock_init( &vmm->vsegs_lock);72 xlist_root_init( XPTR( local_cxy , &vmm->vsegs_root ) ); 73 remote_rwlock_init( XPTR( local_cxy , &vmm->vsegs_lock ) ); 73 74 74 75 assert( ((CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) … … 154 155 // initialize instrumentation counters 155 156 vmm->pgfault_nr = 0; 156 vmm->u_err_nr = 0;157 vmm->m_err_nr = 0;158 157 159 158 hal_fence(); … … 176 175 177 176 // get lock protecting the vseg list 178 r wlock_rd_lock( &vmm->vsegs_lock);177 remote_rwlock_rd_lock( XPTR( local_cxy , &vmm->vsegs_lock ) ); 179 178 180 179 // scan the list of vsegs 181 list_entry_t * iter; 180 xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root ); 181 xptr_t iter_xp; 182 xptr_t vseg_xp; 182 183 vseg_t * vseg; 183 LIST_FOREACH( &vmm->vsegs_root , iter ) 184 { 185 vseg = LIST_ELEMENT( iter , vseg_t , list ); 184 XLIST_FOREACH( root_xp , iter_xp ) 185 { 186 vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist ); 187 vseg = (vseg_t *)GET_PTR( vseg_xp ); 188 186 189 printk(" - %s : base = %X / size = %X / npages = %d\n", 187 190 vseg_type_str( vseg->type ) , vseg->min , vseg->max - vseg->min , vseg->vpn_size ); … … 206 209 207 210 // release the lock 208 rwlock_rd_unlock( &vmm->vsegs_lock ); 209 } 210 211 ////////////////////////////////////////// 212 error_t vmm_copy( process_t * dst_process, 213 process_t * src_process ) 214 { 215 error_t error; 216 217 vmm_t * src_vmm = &src_process->vmm; 218 vmm_t * dst_vmm = &dst_process->vmm; 219 220 // take the src_vmm vsegs_lock 221 rwlock_wr_lock( &src_vmm->vsegs_lock ); 222 223 // initialize dst_vmm vsegs_lock 224 rwlock_init( &dst_vmm->vsegs_lock ); 225 226 // initialize the dst_vmm vsegs list 227 dst_vmm->vsegs_nr = 0; 228 list_root_init( &dst_vmm->vsegs_root ); 229 230 // initialize generic page table 231 error = hal_gpt_create( &dst_vmm->gpt ); 232 211 remote_rwlock_rd_unlock( XPTR( local_cxy , &vmm->vsegs_lock ) ); 212 213 } // vmm_display() 214 215 /////////////////////i//////////////////// 216 void vmm_update_pte( process_t * process, 217 vpn_t vpn, 218 uint32_t attr, 219 ppn_t ppn ) 220 { 221 222 xlist_entry_t * process_root_ptr; 223 xptr_t process_root_xp; 224 xptr_t process_iter_xp; 225 226 xptr_t remote_process_xp; 227 cxy_t remote_process_cxy; 228 process_t * remote_process_ptr; 229 xptr_t remote_gpt_xp; 230 231 pid_t pid; 232 cxy_t owner_cxy; 233 lpid_t owner_lpid; 234 235 // get extended pointer on root of process copies xlist in owner cluster 236 pid = process->pid; 237 owner_cxy = CXY_FROM_PID( pid ); 238 owner_lpid = LPID_FROM_PID( pid ); 239 process_root_ptr = &LOCAL_CLUSTER->pmgr.copies_root[owner_lpid]; 240 process_root_xp = XPTR( owner_cxy , process_root_ptr ); 241 242 // loop on destination process copies 243 XLIST_FOREACH( process_root_xp , process_iter_xp ) 244 { 245 // get cluster and local pointer on remote process 246 remote_process_xp = XLIST_ELEMENT( process_iter_xp , process_t , copies_list ); 247 remote_process_ptr = (process_t *)GET_PTR( remote_process_xp ); 248 remote_process_cxy = GET_CXY( remote_process_xp ); 249 250 // get extended pointer on remote gpt 251 remote_gpt_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.gpt ); 252 253 hal_gpt_update_pte( remote_gpt_xp, 254 vpn, 255 attr, 256 ppn ); 257 } 258 } // end vmm_update_pte() 259 260 /////////////////////////////////////// 261 void vmm_set_cow( process_t * process ) 262 { 263 vmm_t * vmm; 264 265 xlist_entry_t * process_root_ptr; 266 xptr_t process_root_xp; 267 xptr_t process_iter_xp; 268 269 xptr_t remote_process_xp; 270 cxy_t remote_process_cxy; 271 process_t * remote_process_ptr; 272 xptr_t remote_gpt_xp; 273 274 xptr_t vseg_root_xp; 275 xptr_t vseg_iter_xp; 276 277 xptr_t vseg_xp; 278 vseg_t * vseg; 279 280 pid_t pid; 281 cxy_t owner_cxy; 282 lpid_t owner_lpid; 283 284 vmm_dmsg("\n[DBG] %s : core[%x,%d] enters for process %x\n", 285 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid ); 286 287 // check cluster is reference 288 assert( (GET_CXY( process->ref_xp ) == local_cxy) , __FUNCTION__, 289 "local cluster is not process reference cluster\n"); 290 291 // get pointer on reference VMM 292 vmm = &process->vmm; 293 294 // get extended pointer on root of process copies xlist in owner cluster 295 pid = process->pid; 296 owner_cxy = CXY_FROM_PID( pid ); 297 owner_lpid = LPID_FROM_PID( pid ); 298 process_root_ptr = &LOCAL_CLUSTER->pmgr.copies_root[owner_lpid]; 299 process_root_xp = XPTR( owner_cxy , process_root_ptr ); 300 301 // get extended pointer on root of vsegs xlist from reference VMM 302 vseg_root_xp = XPTR( local_cxy , &vmm->vsegs_root ); 303 304 // loop on destination process copies 305 XLIST_FOREACH( process_root_xp , process_iter_xp ) 306 { 307 // get cluster and local pointer on remote process 308 remote_process_xp = XLIST_ELEMENT( process_iter_xp , process_t , copies_list ); 309 remote_process_ptr = (process_t *)GET_PTR( remote_process_xp ); 310 remote_process_cxy = GET_CXY( remote_process_xp ); 311 312 vmm_dmsg("\n[DBG] %s : core[%x,%d] handling process %x in cluster %x\n", 313 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid , remote_process_cxy ); 314 315 // get extended pointer on remote gpt 316 remote_gpt_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.gpt ); 317 318 // loop on vsegs in (local) reference process VSL 319 XLIST_FOREACH( vseg_root_xp , vseg_iter_xp ) 320 { 321 // get pointer on vseg 322 vseg_xp = XLIST_ELEMENT( vseg_iter_xp , vseg_t , xlist ); 323 vseg = (vseg_t *)GET_PTR( vseg_xp ); 324 325 assert( (GET_CXY( vseg_xp ) == local_cxy) , __FUNCTION__, 326 "all vsegs in reference VSL must be local\n" ); 327 328 // get vseg type, base and size 329 uint32_t type = vseg->type; 330 vpn_t vpn_base = vseg->vpn_base; 331 vpn_t vpn_size = vseg->vpn_size; 332 333 vmm_dmsg("\n[DBG] %s : core[%x,%d] handling vseg %s / vpn_base = %x / vpn_size = %x\n", 334 __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vseg_type_str(type), vpn_base, vpn_size ); 335 336 // set COW flag on the remote GPT depending on vseg type 337 if( (type == VSEG_TYPE_DATA) || 338 (type == VSEG_TYPE_ANON) || 339 (type == VSEG_TYPE_REMOTE) ) 340 { 341 hal_gpt_flip_cow( true, // set_cow 342 remote_gpt_xp, 343 vpn_base, 344 vpn_size ); 345 } 346 } // en loop on vsegs 347 } // end loop on process copies 348 349 vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for process %x\n", 350 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid ); 351 352 } // end vmm_set-cow() 353 354 ///////////////////////////////////////////////// 355 error_t vmm_fork_copy( process_t * child_process, 356 xptr_t parent_process_xp ) 357 { 358 error_t error; 359 cxy_t parent_cxy; 360 process_t * parent_process; 361 vmm_t * parent_vmm; 362 xptr_t parent_lock_xp; 363 vmm_t * child_vmm; 364 xptr_t iter_xp; 365 xptr_t parent_vseg_xp; 366 vseg_t * parent_vseg; 367 vseg_t * child_vseg; 368 uint32_t type; 369 bool_t cow; 370 vpn_t vpn; 371 vpn_t vpn_base; 372 vpn_t vpn_size; 373 xptr_t page_xp; 374 page_t * page_ptr; 375 cxy_t page_cxy; 376 xptr_t parent_root_xp; 377 bool_t mapped; 378 ppn_t ppn; 379 380 vmm_dmsg("\n[DBG] %s : core[%x,%d] enter\n", 381 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid ); 382 383 // get parent process cluster and local pointer 384 parent_cxy = GET_CXY( parent_process_xp ); 385 parent_process = (process_t *)GET_PTR( parent_process_xp ); 386 387 // get local pointers on parent and child VMM 388 parent_vmm = &parent_process->vmm; 389 child_vmm = &child_process->vmm; 390 391 // get extended pointer on lock protecting the parent VSL 392 parent_lock_xp = XPTR( parent_cxy , &parent_vmm->vsegs_lock ); 393 394 // take the lock protecting the parent VSL 395 remote_rwlock_rd_lock( parent_lock_xp ); 396 397 // initialize the lock protecting the child VSL 398 remote_rwlock_init( XPTR( local_cxy , &child_vmm->vsegs_lock ) ); 399 400 // initialize the child VSL as empty 401 xlist_root_init( XPTR( local_cxy, &child_vmm->vsegs_root ) ); 402 child_vmm->vsegs_nr = 0; 403 404 // create & initialize the child GPT as empty 405 error = hal_gpt_create( &child_vmm->gpt ); 233 406 if( error ) 234 407 { 235 printk("\n[ERROR] in %s : cannot initialize page table\n", __FUNCTION__ ); 236 return ENOMEM; 237 } 238 239 // loop on SRC VSL to register vsegs copies in DST VSL 240 // and copy valid PTEs from SRC GPT to DST GPT 241 list_entry_t * iter; 242 vseg_t * src_vseg; 243 vseg_t * dst_vseg; 244 LIST_FOREACH( &src_vmm->vsegs_root , iter ) 245 { 246 // get pointer on current src_vseg 247 src_vseg = LIST_ELEMENT( iter , vseg_t , list ); 248 249 // allocate memory for a new dst_vseg 250 dst_vseg = vseg_alloc(); 251 252 if( dst_vseg == NULL ) 408 printk("\n[ERROR] in %s : cannot create GPT\n", __FUNCTION__ ); 409 return -1; 410 } 411 412 // build extended pointer on parent VSL 413 parent_root_xp = XPTR( parent_cxy , &parent_vmm->vsegs_root ); 414 415 // loop on parent VSL xlist 416 XLIST_FOREACH( parent_root_xp , iter_xp ) 417 { 418 // get local and extended pointers on current parent vseg 419 parent_vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist ); 420 parent_vseg = (vseg_t *)GET_PTR( parent_vseg_xp ); 421 422 // get vseg type 423 type = hal_remote_lw( XPTR( parent_cxy , &parent_vseg->type ) ); 424 425 426 vmm_dmsg("\n[DBG] %s : core[%x,%d] found parent vseg %s / vpn_base = %x\n", 427 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vseg_type_str(type), 428 hal_remote_lw( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) ); 429 430 // all parent vsegs - but STACK - must be copied in child VSL 431 if( type != VSEG_TYPE_STACK ) 253 432 { 254 // release all allocated vsegs 255 LIST_FOREACH( &dst_vmm->vsegs_root , iter ) 433 // allocate memory for a new child vseg 434 child_vseg = vseg_alloc(); 435 if( child_vseg == NULL ) // release all allocated vsegs 256 436 { 257 dst_vseg = LIST_ELEMENT( iter , vseg_t , list ); 258 vseg_free( dst_vseg ); 437 vmm_destroy( child_process ); 438 printk("\n[ERROR] in %s : cannot create vseg for child\n", __FUNCTION__ ); 439 return -1; 259 440 } 260 return ENOMEM; 261 } 262 263 // copy src_vseg to dst_vseg 264 vseg_init_from_ref( dst_vseg , XPTR( local_cxy , src_vseg ) ); 265 266 // register dst_vseg in DST VSL 267 vseg_attach( dst_vmm , dst_vseg ); 268 269 // copy SRC GPT to DST GPT / set COW for all writable vsegs, but the FILE type 270 bool_t cow = (src_vseg->type != VSEG_TYPE_FILE) && (src_vseg->flags & VSEG_WRITE); 271 error = hal_gpt_copy( &dst_vmm->gpt, 272 &src_vmm->gpt, 273 src_vseg->vpn_base, 274 src_vseg->vpn_size, 275 cow ); 276 if( error ) 277 { 278 printk("\n[ERROR] in %s : cannot copy page GPT\n", __FUNCTION__ ); 279 hal_gpt_destroy( &dst_vmm->gpt ); 280 return ENOMEM; 281 } 282 } 283 284 // release the src_vmm vsegs_lock 285 rwlock_wr_unlock( &src_vmm->vsegs_lock ); 286 287 // initialize STACK allocator 288 dst_vmm->stack_mgr.bitmap = 0; 289 dst_vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE; 290 291 // initialize MMAP allocator 292 dst_vmm->mmap_mgr.vpn_base = CONFIG_VMM_HEAP_BASE; 293 dst_vmm->mmap_mgr.vpn_size = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE; 294 dst_vmm->mmap_mgr.first_free_vpn = CONFIG_VMM_HEAP_BASE; 441 442 // copy parent vseg to child vseg 443 vseg_init_from_ref( child_vseg , parent_vseg_xp ); 444 445 // register child vseg in child VSL 446 vseg_attach( child_vmm , child_vseg ); 447 448 vmm_dmsg("\n[DBG] %s : core[%x,%d] copied to child VSL : vseg %s / vpn_base = %x\n", 449 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vseg_type_str(type), 450 hal_remote_lw( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) ); 451 452 // copy DATA, MMAP, REMOTE, FILE parent GPT entries to child GPT 453 if( type != VSEG_TYPE_CODE ) 454 { 455 // activate the COW for DATA, MMAP, REMOTE vsegs only 456 cow = ( type != VSEG_TYPE_FILE ); 457 458 vpn_base = child_vseg->vpn_base; 459 vpn_size = child_vseg->vpn_size; 460 461 // scan pages in parent vseg 462 for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ ) 463 { 464 error = hal_gpt_pte_copy( &child_vmm->gpt, 465 XPTR( parent_cxy , &parent_vmm->gpt ), 466 vpn, 467 cow, 468 &ppn, 469 &mapped ); 470 if( error ) 471 { 472 vmm_destroy( child_process ); 473 printk("\n[ERROR] in %s : cannot copy GPT\n", __FUNCTION__ ); 474 return -1; 475 } 476 477 // increment page descriptor fork_nr for the referenced page if mapped 478 if( mapped ) 479 { 480 page_xp = ppm_ppn2page( ppn ); 481 page_cxy = GET_CXY( page_xp ); 482 page_ptr = (page_t *)GET_PTR( page_xp ); 483 hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->fork_nr ) , 1 ); 484 485 vmm_dmsg("\n[DBG] %s : core[%x,%d] copied to child GPT : vpn %x\n", 486 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn ); 487 488 } 489 } 490 } // end if no code & no stack 491 } // end if no stack 492 } // end loop on vsegs 493 494 // release the parent vsegs lock 495 remote_rwlock_rd_unlock( parent_lock_xp ); 496 497 // initialize the child VMM STACK allocator 498 child_vmm->stack_mgr.bitmap = 0; 499 child_vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE; 500 501 // initialize the child VMM MMAP allocator 295 502 uint32_t i; 296 for( i = 0 ; i < 32 ; i++ ) list_root_init( &dst_vmm->mmap_mgr.zombi_list[i] ); 503 child_vmm->mmap_mgr.vpn_base = CONFIG_VMM_HEAP_BASE; 504 child_vmm->mmap_mgr.vpn_size = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE; 505 child_vmm->mmap_mgr.first_free_vpn = CONFIG_VMM_HEAP_BASE; 506 for( i = 0 ; i < 32 ; i++ ) list_root_init( &child_vmm->mmap_mgr.zombi_list[i] ); 297 507 298 508 // initialize instrumentation counters 299 dst_vmm->pgfault_nr = 0; 300 dst_vmm->u_err_nr = 0; 301 dst_vmm->m_err_nr = 0; 302 303 // copy base addresses 304 dst_vmm->kent_vpn_base = src_vmm->kent_vpn_base; 305 dst_vmm->args_vpn_base = src_vmm->args_vpn_base; 306 dst_vmm->envs_vpn_base = src_vmm->envs_vpn_base; 307 dst_vmm->heap_vpn_base = src_vmm->heap_vpn_base; 308 dst_vmm->code_vpn_base = src_vmm->code_vpn_base; 309 dst_vmm->data_vpn_base = src_vmm->data_vpn_base; 310 311 dst_vmm->entry_point = src_vmm->entry_point; 509 child_vmm->pgfault_nr = 0; 510 511 // copy base addresses from parent VMM to child VMM 512 child_vmm->kent_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->kent_vpn_base)); 513 child_vmm->args_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->args_vpn_base)); 514 child_vmm->envs_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->envs_vpn_base)); 515 child_vmm->heap_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->heap_vpn_base)); 516 child_vmm->code_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->code_vpn_base)); 517 child_vmm->data_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->data_vpn_base)); 518 519 child_vmm->entry_point = (intptr_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->entry_point)); 312 520 313 521 hal_fence(); … … 315 523 return 0; 316 524 317 } // vmm_ copy()525 } // vmm_fork_copy() 318 526 319 527 /////////////////////////////////////// 320 528 void vmm_destroy( process_t * process ) 321 529 { 530 xptr_t vseg_xp; 322 531 vseg_t * vseg; 323 532 … … 325 534 vmm_t * vmm = &process->vmm; 326 535 536 // get extended pointer on VSL root and VSL lock 537 xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root ); 538 xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock ); 539 327 540 // get lock protecting vseg list 328 r wlock_wr_lock( &vmm->vsegs_lock);329 330 // remove all vsegs registered in vmm331 while( ! list_is_empty( &vmm->vsegs_root) )541 remote_rwlock_wr_lock( lock_xp ); 542 543 // remove all vsegs registered in VSL 544 while( !xlist_is_empty( root_xp ) ) 332 545 { 333 vseg = LIST_FIRST( &vmm->vsegs_root , vseg_t , list ); 546 vseg_xp = XLIST_FIRST_ELEMENT( root_xp , vseg_t , xlist ); 547 vseg = (vseg_t *)GET_PTR( vseg_xp ); 334 548 vseg_detach( vmm , vseg ); 335 549 vseg_free( vseg ); … … 337 551 338 552 // release lock 339 r wlock_wr_unlock(&vmm->vsegs_lock);553 remote_rwlock_wr_unlock( lock_xp ); 340 554 341 555 // remove all vsegs from zombi_lists in MMAP allocator … … 345 559 while( !list_is_empty( &vmm->mmap_mgr.zombi_list[i] ) ) 346 560 { 347 vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , list );561 vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , zlist ); 348 562 vseg_detach( vmm , vseg ); 349 563 vseg_free( vseg ); … … 362 576 { 363 577 vmm_t * vmm = &process->vmm; 578 579 // scan the VSL 364 580 vseg_t * vseg; 365 list_entry_t * iter; 366 367 // scan the list of registered vsegs 368 LIST_FOREACH( &vmm->vsegs_root , iter ) 581 xptr_t iter_xp; 582 xptr_t vseg_xp; 583 xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root ); 584 585 XLIST_FOREACH( root_xp , iter_xp ) 369 586 { 370 vseg = LIST_ELEMENT( iter , vseg_t , list ); 587 vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist ); 588 vseg = (vseg_t *)GET_PTR( vseg_xp ); 371 589 372 590 if( ((vpn_base + vpn_size) > vseg->vpn_base) && … … 463 681 { 464 682 // get pointer on zombi vseg from zombi_list 465 vseg = LIST_FIRST( &mgr->zombi_list[index] , vseg_t , list );683 vseg = LIST_FIRST( &mgr->zombi_list[index] , vseg_t , zlist ); 466 684 467 685 // remove vseg from free-list 468 list_unlink( &vseg-> list );686 list_unlink( &vseg->zlist ); 469 687 470 688 // compute base … … 579 797 cxy ); 580 798 581 // attach vseg to vmm 582 rwlock_wr_lock( &vmm->vsegs_lock ); 799 // attach vseg to VSL 800 xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock ); 801 remote_rwlock_wr_lock( lock_xp ); 583 802 vseg_attach( vmm , vseg ); 584 r wlock_wr_unlock( &vmm->vsegs_lock);803 remote_rwlock_wr_unlock( lock_xp ); 585 804 586 805 vmm_dmsg("\n[DBG] %s : core[%x,%d] exit / process %x / base %x / size %x / type %s\n", … … 601 820 uint32_t type = vseg->type; 602 821 603 // detach vseg from VMM 604 rwlock_wr_lock( &vmm->vsegs_lock ); 605 vseg_detach( &process->vmm , vseg ); 606 rwlock_wr_unlock( &vmm->vsegs_lock ); 822 // detach vseg from VSL 823 xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock ); 824 remote_rwlock_wr_lock( lock_xp ); 825 vseg_detach( &process->vmm , vseg ); 826 remote_rwlock_wr_unlock( lock_xp ); 607 827 608 828 // release the stack slot to VMM stack allocator if STACK type … … 632 852 // update zombi_list 633 853 spinlock_lock( &mgr->lock ); 634 list_add_first( &mgr->zombi_list[index] , &vseg-> list );854 list_add_first( &mgr->zombi_list[index] , &vseg->zlist ); 635 855 spinlock_unlock( &mgr->lock ); 636 856 } … … 686 906 // set page table entry 687 907 ppn = ppm_page2ppn( XPTR( local_cxy , page ) ); 688 error = hal_gpt_set_pte( gpt , vpn , ppn , attr ); 908 error = hal_gpt_set_pte( gpt, 909 vpn, 910 attr, 911 ppn ); 689 912 if( error ) 690 913 { … … 695 918 696 919 return 0; 697 } 920 921 } // end vmm_map_kernel_vseg() 698 922 699 923 ///////////////////////////////////////// … … 729 953 intptr_t vaddr ) 730 954 { 731 list_entry_t * iter; 732 vseg_t * vseg = NULL; 733 734 // get lock protecting the vseg list 735 rwlock_rd_lock( &vmm->vsegs_lock ); 736 737 // scan the list of vsegs 738 LIST_FOREACH( &vmm->vsegs_root , iter ) 739 { 740 vseg = LIST_ELEMENT( iter , vseg_t , list ); 741 if( (vaddr >= vseg->min) && (vaddr < vseg->max) ) break; 742 } 743 744 // release the lock 745 rwlock_rd_unlock( &vmm->vsegs_lock ); 746 747 return vseg; 748 } 955 xptr_t iter_xp; 956 xptr_t vseg_xp; 957 vseg_t * vseg; 958 959 // get extended pointers on VSL lock and root 960 xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock ); 961 xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root ); 962 963 // get lock protecting the VSL 964 remote_rwlock_rd_lock( lock_xp ); 965 966 // scan the list of vsegs in VSL 967 XLIST_FOREACH( root_xp , iter_xp ) 968 { 969 vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist ); 970 vseg = (vseg_t *)GET_PTR( vseg_xp ); 971 if( (vaddr >= vseg->min) && (vaddr < vseg->max) ) 972 { 973 // return success 974 remote_rwlock_rd_unlock( lock_xp ); 975 return vseg; 976 } 977 } 978 979 // return failure 980 remote_rwlock_rd_unlock( lock_xp ); 981 return NULL; 982 983 } // end vseg_from_vaddr() 749 984 750 985 ///////////////////////////////////////////// … … 769 1004 if( vseg == NULL) return EINVAL; 770 1005 771 // get VMM lock protecting vsegs list 772 rwlock_wr_lock( &vmm->vsegs_lock ); 1006 // get extended pointer on VSL lock 1007 xptr_t lock_xp = XPTR( local_cxy , &vmm->vsegs_lock ); 1008 1009 // get lock protecting VSL 1010 remote_rwlock_wr_lock( lock_xp ); 773 1011 774 1012 if( (vseg->min > addr_min) || (vseg->max < addr_max) ) // region not included in vseg … … 831 1069 832 1070 // release VMM lock 833 r wlock_wr_unlock( &vmm->vsegs_lock);1071 remote_rwlock_wr_unlock( lock_xp ); 834 1072 835 1073 return error; … … 1129 1367 ppn_t new_ppn; // new PTE_PPN 1130 1368 uint32_t new_attr; // new PTE_ATTR 1131 xptr_t page_xp; // extended pointer on allocated page descriptor1132 1369 error_t error; 1133 1370 … … 1137 1374 1138 1375 vmm_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x in process %x / cow = %d\n", 1139 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , process->pid , %d);1376 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , process->pid , cow ); 1140 1377 1141 1378 // get VMM pointer … … 1159 1396 hal_gpt_get_pte( &vmm->gpt , vpn , &old_attr , &old_ppn ); 1160 1397 1161 // for both copy_on_write and page_fault events, we allocate a physical page, 1162 // initialize it, register it in the GPT, and return the new_ppn and new_attr 1398 // for both "copy_on_write" and "page_fault" events, allocate a physical page, 1399 // initialize it, register it in the reference GPT, update GPT copies in all 1400 // clusters containing a copy, and return the new_ppn and new_attr 1163 1401 1164 1402 if( cow ) ////////////// copy_on_write request /////////// 1165 1403 { 1166 assert( ( *attr & GPT_MAPPED) , __FUNCTION__ ,1167 "PTE must be mapped for a copy-on-write \n" );1168 1169 vmm_dmsg("\n[DBG] %s : core[%x,%d] page %x must be copied => do it\n",1404 assert( (old_attr & GPT_MAPPED) , __FUNCTION__ , 1405 "PTE must be mapped for a copy-on-write exception\n" ); 1406 1407 excp_dmsg("\n[DBG] %s : core[%x,%d] handling COW for vpn %x\n", 1170 1408 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn ); 1171 1409 1172 // allocate a physical page depending on vseg type 1173 page_xp = vmm_page_allocate( vseg , vpn ); 1174 1175 if( page_xp == XPTR_NULL ) 1410 // get extended pointer, cluster and local pointer on page descriptor 1411 xptr_t page_xp = ppm_ppn2page( old_ppn ); 1412 cxy_t page_cxy = GET_CXY( page_xp ); 1413 page_t * page_ptr = (page_t *)GET_PTR( page_xp ); 1414 1415 // get number of pending forks in page descriptor 1416 uint32_t count = hal_remote_lw( XPTR( page_cxy , &page_ptr->fork_nr ) ); 1417 1418 if( count ) // pending fork => allocate a new page, copy it, reset COW 1176 1419 { 1177 printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n", 1178 __FUNCTION__ , process->pid , vpn ); 1179 return ENOMEM; 1420 // allocate a new physical page 1421 page_xp = vmm_page_allocate( vseg , vpn ); 1422 if( page_xp == XPTR_NULL ) 1423 { 1424 printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n", 1425 __FUNCTION__ , process->pid , vpn ); 1426 return -1; 1427 } 1428 1429 // compute allocated page PPN 1430 new_ppn = ppm_page2ppn( page_xp ); 1431 1432 // copy old page content to new page 1433 xptr_t old_base_xp = ppm_ppn2base( old_ppn ); 1434 xptr_t new_base_xp = ppm_ppn2base( new_ppn ); 1435 memcpy( GET_PTR( new_base_xp ), 1436 GET_PTR( old_base_xp ), 1437 CONFIG_PPM_PAGE_SIZE ); 1438 } 1439 else // no pending fork => keep the existing page, reset COW 1440 { 1441 new_ppn = old_ppn; 1180 1442 } 1181 1443 1182 // compute allocated page PPN 1183 new_ppn = ppm_page2ppn( page_xp ); 1184 1185 // copy old page content to new page 1186 xptr_t old_base_xp = ppm_ppn2base( old_ppn ); 1187 xptr_t new_base_xp = ppm_ppn2base( new_ppn ); 1188 memcpy( GET_PTR( new_base_xp ), 1189 GET_PTR( old_base_xp ), 1190 CONFIG_PPM_PAGE_SIZE ); 1191 1192 // update attributes: reset COW and set WRITABLE 1193 new_attr = old_attr & ~GPT_COW; 1194 new_attr = new_attr | GPT_WRITABLE; 1195 1196 // register PTE in GPT 1197 error = hal_gpt_set_pte( &vmm->gpt , vpn , new_ppn , new_attr ); 1198 1199 if( error ) 1444 // build new_attr : reset COW and set WRITABLE, 1445 new_attr = (old_attr | GPT_WRITABLE) & (~GPT_COW); 1446 1447 // update GPT[vpn] for all GPT copies 1448 // to maintain coherence of copies 1449 vmm_update_pte( process, 1450 vpn, 1451 new_attr, 1452 new_ppn ); 1453 1454 // decrement fork_nr in page descriptor 1455 hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->fork_nr ) , -1 ); 1456 } 1457 else /////////////// page_fault request /////////// 1458 { 1459 if( (old_attr & GPT_MAPPED) == 0 ) // true page_fault => map it 1200 1460 { 1201 printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n", 1202 __FUNCTION__ , process->pid , vpn ); 1203 return error; 1204 } 1205 } 1206 else //////////////////// page_fault request /////////// 1207 { 1208 if( (old_attr & GPT_MAPPED) == 0 ) // PTE unmapped in ref GPT 1209 { 1210 1211 vmm_dmsg("\n[DBG] %s : core[%x,%d] page %x unmapped => try to map it\n", 1461 1462 excp_dmsg("\n[DBG] %s : core[%x,%d] handling page fault for vpn %x\n", 1212 1463 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn ); 1213 1464 1214 // allocate one physical page, depending on vseg type1465 // allocate new_ppn, depending on vseg type 1215 1466 error = vmm_get_one_ppn( vseg , vpn , &new_ppn ); 1216 1217 1467 if( error ) 1218 1468 { 1219 1469 printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n", 1220 1470 __FUNCTION__ , process->pid , vpn ); 1221 return error;1471 return -1; 1222 1472 } 1223 1473 1224 // define attributesfrom vseg flags1474 // define new_attr from vseg flags 1225 1475 new_attr = GPT_MAPPED | GPT_SMALL; 1226 1476 if( vseg->flags & VSEG_USER ) new_attr |= GPT_USER; … … 1229 1479 if( vseg->flags & VSEG_CACHE ) new_attr |= GPT_CACHABLE; 1230 1480 1231 // register PTE in GPT 1232 error = hal_gpt_set_pte( &vmm->gpt , vpn , new_ppn , new_attr ); 1233 1481 // register new PTE in reference GPT 1482 // on demand policy => no update of GPT copies 1483 error = hal_gpt_set_pte( &vmm->gpt, 1484 vpn, 1485 new_attr, 1486 new_ppn ); 1234 1487 if( error ) 1235 1488 { 1236 1489 printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n", 1237 1490 __FUNCTION__ , process->pid , vpn ); 1238 return error;1491 return -1; 1239 1492 } 1240 1493 } 1241 else 1494 else // mapped in reference GPT => get it 1242 1495 { 1496 new_ppn = old_ppn; 1243 1497 new_attr = old_attr; 1244 new_ppn = old_ppn;1245 1498 } 1246 1499 } 1247 1500 1248 vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn =%x / ppn = %x / attr = %x\n",1501 excp_dmsg("\n[DBG] %s : core[%x,%d] update GPT for vpn %x / ppn = %x / attr = %x\n", 1249 1502 __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , new_ppn , new_attr ); 1250 1503 1504 // retur success 1251 1505 *ppn = new_ppn; 1252 1506 *attr = new_attr; … … 1282 1536 1283 1537 // update local GPT 1284 error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr ); 1538 error |= hal_gpt_set_pte( &vmm->gpt, 1539 vpn, 1540 attr, 1541 ppn ); 1285 1542 } 1286 1543 else // local cluster is the reference cluster … … 1297 1554 } // end vmm_handle_page_fault() 1298 1555 1299 //////////////////////////////////////////// ///1300 error_t vmm_ copy_on_write( process_t * process,1301 1556 //////////////////////////////////////////// 1557 error_t vmm_handle_cow( process_t * process, 1558 vpn_t vpn ) 1302 1559 { 1303 1560 uint32_t attr; // missing page attributes … … 1324 1581 1325 1582 // update local GPT 1326 error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr ); 1583 error |= hal_gpt_set_pte( &vmm->gpt, 1584 vpn, 1585 attr, 1586 ppn ); 1327 1587 } 1328 1588 else // local cluster is the reference cluster … … 1337 1597 return error; 1338 1598 1339 } // end vmm_ copy_on_write()1599 } // end vmm_handle_cow() 1340 1600 1341 1601 /////////////////////////////////////////// -
trunk/kernel/mm/vmm.h
r407 r408 89 89 /********************************************************************************************* 90 90 * This structure defines the Virtual Memory Manager for a given process in a given cluster. 91 * This local VMM provides three main services: 92 * 1) It registers all vsegs statically or dynamically defined in the vseg list. 93 * 2) It allocates virtual memory space for the STACKS and MMAP vsegs (FILE/ANON/REMOTE). 94 * 3) It contains the local copy of the generic page table descriptor. 91 * This local VMM provides four main services: 92 * 1) It registers all vsegs in the local copy of the vseg list (VSL). 93 * 2) It contains the local copy of the generic page table (GPT). 94 * 3) The stack manager dynamically allocates virtual memory space for the STACK vsegs. 95 * 4) The mmap manager dynamically allocates virtual memory for the (FILE/ANON/REMOTE) vsegs. 96 ******************************************************a************************************** 97 * Implementation notes: 98 * 1. The VSL contains only local vsegs, but it is implemented as an xlist, and protected by 99 * a remote_rwlock, because it can be accessed by a thread running in a remote cluster. 100 * An exemple is the vmm_fork_copy() function. 101 * 2. In most custers, the VSL and GPT are only partial copies of the reference VSL and GPT 102 * structures, stored in the reference cluster. 95 103 ********************************************************************************************/ 96 104 97 105 typedef struct vmm_s 98 106 { 99 rwlock_t vsegs_lock; /*! lock protecting the vsegs list */ 100 list_entry_t vsegs_root; /*! all vsegs in same process and same cluster */ 101 uint32_t vsegs_nr; /*! total number of local vsegs */ 102 103 gpt_t gpt; /*! embedded generic page table descriptor */ 104 105 stack_mgr_t stack_mgr; /*! embedded STACK vsegs allocator */ 106 mmap_mgr_t mmap_mgr; /*! embedded MMAP vsegs allocator */ 107 108 uint32_t pgfault_nr; /*! page fault counter (instrumentation) */ 109 uint32_t u_err_nr; /*! TODO ??? [AG] */ 110 uint32_t m_err_nr; /*! TODO ??? [AG] */ 111 112 vpn_t kent_vpn_base; /*! kentry vseg first page */ 113 vpn_t args_vpn_base; /*! args vseg first page */ 114 vpn_t envs_vpn_base; /*! envs zone first page */ 115 vpn_t heap_vpn_base; /*! envs zone first page */ 116 vpn_t code_vpn_base; /*! code zone first page */ 117 vpn_t data_vpn_base; /*! data zone first page */ 118 119 intptr_t entry_point; /*! main thread entry point */ 107 remote_rwlock_t vsegs_lock; /*! lock protecting the vsegs list */ 108 xlist_entry_t vsegs_root; /*! VSL root (VSL only complete in reference) */ 109 uint32_t vsegs_nr; /*! total number of local vsegs */ 110 111 gpt_t gpt; /*! Generic Page Table (complete in reference) */ 112 113 stack_mgr_t stack_mgr; /*! embedded STACK vsegs allocator */ 114 mmap_mgr_t mmap_mgr; /*! embedded MMAP vsegs allocator */ 115 116 uint32_t pgfault_nr; /*! page fault counter (instrumentation) */ 117 118 vpn_t kent_vpn_base; /*! kentry vseg first page */ 119 vpn_t args_vpn_base; /*! args vseg first page */ 120 vpn_t envs_vpn_base; /*! envs zone first page */ 121 vpn_t heap_vpn_base; /*! envs zone first page */ 122 vpn_t code_vpn_base; /*! code zone first page */ 123 vpn_t data_vpn_base; /*! data zone first page */ 124 125 intptr_t entry_point; /*! main thread entry point */ 120 126 } 121 127 vmm_t; … … 147 153 148 154 /********************************************************************************************* 149 * This function is called by the sys_fork() system call. 150 * It copies the content of a parent process descriptor VMM to a child process VMM. 151 * - All vsegs registered in the source VSL are copied in the destination VSL. 152 * - All PTEs registered in the source GPT are copied in destination GPT. For all writable 153 * PTEs - but the FILE vsegs - the WRITABLE flag is reset and the COW flag is set in 154 * the destination GPT. 155 ********************************************************************************************* 156 * @ dst_process : pointer on destination process descriptor. 157 * @ src_process : pointer on source process descriptor. 155 * This function is called by the process_fork_create() function. It partially copies 156 * the content of a remote parent process VMM to the local child process VMM: 157 * - all DATA, MMAP, REMOTE vsegs registered in the parent VSL are registered in the child 158 * VSL, and all valid GPT entries in parent GPT are copied to the child GPT. 159 * The WRITABLE flag is reset and the COW flag is set in child GPT. 160 * - all CODE vsegs registered in the parent VSL are registered in the child VSL, but the 161 * GPT entries are not copied in the chilf GPT, that will be dynamically updated from 162 * the .elf file when a page fault is reported. 163 * - all FILE vsegs registered in the parent VSL are registered in the child VSL, and all 164 * valid GPT entries in parent GPT are copied to the child GPT. The COW flag is not set. 165 * - no STACK vseg is copied from parent VMM to child VMM, because the child STACK vseg 166 * must be copied from the cluster containing the user thread requesting the fork(). 167 ********************************************************************************************* 168 * @ child_process : local pointer on local child process descriptor. 169 * @ parent_process_xp : extended pointer on remote parent process descriptor. 158 170 * @ return 0 if success / return ENOMEM if failure. 159 171 ********************************************************************************************/ 160 error_t vmm_copy( struct process_s * dst_process, 161 struct process_s * src_process ); 162 163 /********************************************************************************************* 164 * This function removes all vsegs registered in in a virtual memory manager, 165 * and releases the memory allocated to the local generic page table. 172 error_t vmm_fork_copy( struct process_s * child_process, 173 xptr_t parent_process_xp ); 174 175 /********************************************************************************************* 176 * This function is called by the process_make_fork() function to handle the fork syscall. 177 * It set the COW flag, and reset the WRITABLE flag of all GPT entries of the DATA, MMAP, 178 * and REMOTE vsegs of a process identified by the <process> argument. 179 * It must be called by a thread running in the reference cluster, that contains the complete 180 * list of vsegs. Use the rpc_vmm_set_cow_client() when the calling thread client is remote. 181 * It updates all copies of the process in all clusters, to maintain coherence in GPT copies, 182 * using the list of copies stored in the owner process, and using remote_write accesses to 183 * update the remote GPTs. It cannot fail, as only mapped entries in GPT copies are updated. 184 ********************************************************************************************* 185 * @ process : local pointer on local reference process descriptor. 186 ********************************************************************************************/ 187 void vmm_set_cow( struct process_s * process ); 188 189 /********************************************************************************************* 190 * This function is called by the vmm_get_pte() function in case of COW exception. 191 * It modifies both the PPN an the attributes for a GPT entry identified by the <process> 192 * and <vpn> arguments. 193 * It updates all copies of the process in all clusters, to maintain coherence in GPT copies, 194 * using the list of copies stored in the owner process, and using remote_write accesses to 195 * update the remote GPTs. It cannot fail, as only mapped entries in GPT copies are updated. 196 ********************************************************************************************* 197 * @ process : local pointer on local process descriptor. 198 * @ vpn : PTE index. 199 * @ attr : PTE / attributes. 200 * @ ppn : PTE / physical page index. 201 ********************************************************************************************/ 202 void vmm_update_pte( struct process_s * process, 203 vpn_t vpn, 204 uint32_t attr, 205 ppn_t ppn ); 206 207 /********************************************************************************************* 208 * This function removes all vsegs registered in in the virtual memory manager of the 209 * process identified by the <process> argument. 210 * It releases the memory allocated to the local generic page table. 166 211 ********************************************************************************************* 167 212 * @ process : pointer on process descriptor. … … 315 360 * @ returns 0 if success / returns ENOMEM if no memory. 316 361 ********************************************************************************************/ 317 error_t vmm_ copy_on_write( struct process_s * process,318 362 error_t vmm_handle_cow( struct process_s * process, 363 vpn_t vpn ); 319 364 320 365 /********************************************************************************************* -
trunk/kernel/mm/vseg.c
r407 r408 194 194 195 195 // add vseg in vmm list 196 list_add_last( &vmm->vsegs_root , &vseg->list ); 196 xlist_add_last( XPTR( local_cxy , &vmm->vsegs_root ), 197 XPTR( local_cxy , &vseg->xlist ) ); 197 198 } 198 199 … … 205 206 206 207 // remove vseg from vmm list 207 list_unlink( &vseg->list);208 } 209 208 xlist_unlink( XPTR( local_cxy , &vseg->xlist ) ); 209 } 210 -
trunk/kernel/mm/vseg.h
r407 r408 68 68 /********************************************************************************************** 69 69 * This structure defines a virtual segment descriptor. 70 * - The VSL contains only local vsegs, but is implemented as an xlist, because it can be 71 * accessed by thread running in a remote cluster. 72 * - The zombi list is used by the local MMAP allocator. It is implemented as a local list. 70 73 *********************************************************************************************/ 71 74 72 75 typedef struct vseg_s 73 76 { 74 list_entry_t list; /*! all vsegs in same process / same free list if mmap */ 77 xlist_entry_t xlist; /*! all vsegs in same VSL (or same zombi list) */ 78 list_entry_t zlist; /*! all vsegs in same zombi list */ 75 79 struct vmm_s * vmm; /*! pointer on associated VM manager */ 76 80 uint32_t type; /*! vseg type */
Note: See TracChangeset
for help on using the changeset viewer.