Main Page | Modules | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

space.h

Go to the documentation of this file.
00001 // AUTOMATICALLY GENERATED -- DO NOT EDIT!         -*- c++ -*-
00002 
00003 #ifndef space_h
00004 #define space_h
00005 
00006 #include "space_index.h"
00007 
00008 #include "paging.h"             // for page attributes
00009 
00010 //
00011 // INTERFACE definition follows 
00012 //
00013 
00014 
00020 class Space
00021 {
00022 public:
00024   enum Status {
00025     Insert_ok = 0,              
00026     Insert_warn_exists,         
00027     Insert_warn_attrib_upgrade, 
00028     Insert_err_nomem,           
00029     Insert_err_exists           
00030   };
00031 
00033   enum Page_attrib 
00034     {
00035       Page_no_attribs = 0,
00037       Page_writable = Pt_entry::Writable, 
00039       Page_noncacheable = Pt_entry::Noncacheable | Pt_entry::Write_through, 
00041       Page_user_accessible = Pt_entry::User,
00043       Page_all_attribs = Page_writable | Page_noncacheable |
00044                          Page_user_accessible,
00045     };
00046 
00048   bool is_privileged (void);
00049 
00050   static Space *id_lookup(Task_num id);
00051 
00052 public:
00053   static Space *current();
00054   void          make_current();
00055   void          switchin_context();
00056 
00057 protected:
00058   void switchin_lipc_kip_pointer();
00059 
00060   // DATA (be careful here!):  just a page directory
00061   Pdir                    _dir;
00062 private:
00063 
00064 private:
00065   Space();                      // default constructors are undefined
00066   Space(const Space&);
00067 private:
00068 
00069 public:
00076   template < typename T >
00077   T peek (T const *addr, bool user_space);
00078 
00084   template < typename T >
00085   T peek_user (T const *addr);
00086 
00092   template < typename T >
00093   void poke_user (T *addr, T value);
00094 
00101   template < typename T >
00102   void copy_from_user (T *kdst, T const *usrc, size_t n);
00103 
00110   template < typename T >
00111   void copy_to_user (T *udst, T const *ksrc, size_t n);
00112 private:
00113 
00114 public:
00115 
00116   void  page_map        (Address phys, Address virt,
00117                          Address size, unsigned page_attribs);
00118 
00119   void  page_unmap      (Address virt, Address size);
00120 
00121   void  page_protect    (Address virt, Address size,
00122                          unsigned page_attribs);
00123 
00128   Address kip_address() const;
00129 
00138   void kmem_update (void *addr);
00139 
00150   void remote_update (const Address, const Space *,
00151                       const Address, size_t);
00152 
00157   void update_small (Address virt, bool flush);
00158 
00164   bool is_mappable (Address addr, size_t size);
00165 
00166 private:
00168   void remove_from_space_index();
00169 private:
00170 
00171 private:
00172   void switch_ldt();
00173 
00174 public:  
00175   // state requests/manipulation
00176   inline int mapped(Address addr, int need_writable) const;
00177   
00184   inline Address virt_to_phys(Address virt) const;
00185   
00186   inline const Pdir* dir() const;
00187   
00192   inline Space_index id() const;
00193   
00198   inline Space_index chief() const;
00199   
00200   // allocator and deallocator
00201   void * operator new (size_t size);
00202   
00203   void operator delete (void *block);
00204   
00205   // routines
00206   
00220   inline Address virt_to_phys_s0(void *a) const; // pgtble lookup
00221   
00226   inline bool is_sigma0(void) const;
00227   
00228   inline unsigned get_io_counter(void);
00229   
00230   inline bool io_lookup(Address);
00231   
00236   ~Space();
00237   
00256   Space::Status v_insert(Address phys, Address virt, size_t size, unsigned page_attribs);
00257   
00273   bool v_lookup(Address virt, Address *phys = 0, Address *size = 0, unsigned *page_attribs = 0);
00274   
00284   bool v_delete(Address virt, Address size, unsigned page_attribs = 0);
00285   
00286   inline void ldt_addr(void *addr);
00287   
00288   inline Address ldt_addr() const;
00289   
00290   inline void ldt_size(Mword size);
00291   
00292   inline Mword ldt_size() const;
00293 
00294 protected:  
00305   Space(unsigned number);
00306 
00307 private:  
00308   inline void free_ldt_memory();
00309 };
00310 
00316 inline Space * current_space();
00317 
00318 //
00319 // IMPLEMENTATION includes follow (for use by inline functions)
00320 //
00321 
00322 #include "globals.h"
00323 
00324 #include <cassert>
00325 #include "l4_types.h"
00326 #include "mem_unit.h"
00327 #include "paging.h"
00328 #include "config.h"
00329 
00330 #include "cpu.h"
00331 #include "kmem.h"
00332 #include "logdefs.h"
00333 
00334 //
00335 // IMPLEMENTATION of inline functions (and needed classes)
00336 //
00337 
00338 
00339 
00340 // state requests/manipulation
00341 
00342 inline int
00343 Space::mapped(Address addr, int need_writable) const
00344 {
00345   Pd_entry p = _dir.entry(addr);
00346 
00347   if (!p.valid())
00348     return 0;
00349 
00350   if (p.superpage())
00351     return !need_writable || p.writable();
00352 
00353   Pt_entry e = *(p.ptab()->lookup(addr));
00354 
00355   return e.valid() && (!need_writable || e.writable());
00356 }
00357 
00358 
00366 inline Address
00367 Space::virt_to_phys(Address virt) const
00368 {
00369   return dir()->virt_to_phys(virt);
00370 }
00371 
00372 
00373 
00374 inline const Pdir*
00375 Space::dir() const
00376 {
00377   return &_dir;
00378 }
00379 
00380 
00386 inline Space_index
00387 Space::id() const
00388 {
00389   return Space_index (_dir.entry(Mem_layout::Space_index).raw() >> 8);
00390 }
00391 
00392 
00398 inline Space_index 
00399 Space::chief() const
00400 {
00401   return Space_index (_dir.entry(Mem_layout::Chief_index).raw() >> 8);
00402 }
00403 
00404 
00405 // routines
00406 
00421 inline Address
00422 Space::virt_to_phys_s0(void *a) const // pgtble lookup
00423 {
00424   if (is_sigma0())              // sigma0 doesn't have mapped everything
00425     return (Address)a;
00426 
00427   return dir()->virt_to_phys((Address)a);
00428 }
00429 
00430 
00436 inline bool Space::is_sigma0(void) const
00437 {
00438   return this == sigma0_space;
00439 }
00440 
00441 
00442 
00443 inline unsigned
00444 Space::get_io_counter(void)
00445 { return 0; }
00446 
00447 
00448 
00449 inline bool
00450 Space::io_lookup(Address)
00451 { return false; }
00452 
00453 
00454 
00455 inline void
00456 Space::ldt_addr(void *addr)
00457 {
00458   Pd_entry *p = _dir.lookup(Mem_layout::Ldt_addr);
00459   assert(!p->valid());
00460   assert(!((Address)addr & 1));
00461 
00462   *p = (Address)addr & ~1;
00463 }
00464 
00465 
00466 
00467 inline Address
00468 Space::ldt_addr() const
00469 {
00470   Pd_entry p = _dir.entry(Mem_layout::Ldt_addr);
00471   assert(!p.valid());
00472 
00473   return p.raw();
00474 }
00475 
00476 
00477 
00478 inline void
00479 Space::ldt_size(Mword size)
00480 {
00481   Pd_entry *p = _dir.lookup(Mem_layout::Ldt_size);
00482   assert(!p->valid());
00483   assert(!(size & 1));
00484 
00485   *p = size & ~1;
00486 }
00487 
00488 
00489 
00490 inline Mword
00491 Space::ldt_size() const
00492 {
00493   Pd_entry p = _dir.entry(Mem_layout::Ldt_size);
00494   assert(!p.valid());
00495 
00496   return p.raw();
00497 }
00498 
00499 
00500 
00501 inline void
00502 Space::switchin_lipc_kip_pointer()
00503 {}
00504 
00505 
00507 
00508 inline Space *
00509 Space::id_lookup(Task_num id)
00510 {
00511   return Space_index (id).lookup();
00512 }
00513 
00514 
00515 
00516 inline bool Space::is_privileged(void) 
00517 {
00518   // A task is privileged if it has all the IO ports mapped.
00519   return (!Config::enable_io_protection 
00520           || (get_io_counter() == L4_fpage::Io_port_max));
00521 }
00522 
00523 
00524 
00525 template < typename T > inline T
00526 Space::peek(T const *addr, bool user_space)
00527 {
00528   // this == current_space() does not apply for SMAS
00529   return user_space ? peek_user (addr) : *addr;
00530 }
00531 
00532 
00533 
00534 template < typename T > inline T
00535 Space::peek_user(T const *addr)
00536 {
00537   assert (this == current_space());
00538   return *addr;
00539 }
00540 
00541 
00542 
00543 template < typename T > inline void
00544 Space::poke_user(T *addr, T value)
00545 {
00546   assert (this == current_space());
00547   *addr = value;
00548 }
00549 
00550 
00551 
00552 template < typename T > inline void
00553 Space::copy_from_user(T *kdst, T const *usrc, size_t n)
00554 {
00555   assert (this == current_space());
00556   Cpu::memcpy_bytes (kdst, usrc, n * sizeof (T));
00557 }
00558 
00559 
00560 
00561 template <> inline void
00562 Space::copy_from_user <Mword>(Mword *kdst, Mword const *usrc, size_t n)
00563 {
00564   assert (this == current_space());
00565   Cpu::memcpy_mwords (kdst, usrc, n);
00566 }
00567 
00568 
00569 
00570 template < typename T > inline void
00571 Space::copy_to_user(T *udst, T const *ksrc, size_t n)
00572 {
00573   assert (this == current_space());
00574   Cpu::memcpy_bytes (udst, ksrc, n * sizeof (T));
00575 }
00576 
00577 
00578 
00579 template <> inline void
00580 Space::copy_to_user <Mword>(Mword *udst, Mword const *ksrc, size_t n)
00581 {
00582   assert (this == current_space());
00583   Cpu::memcpy_mwords (udst, ksrc, n);
00584 }
00585 
00586 
00587 
00588 inline Address
00589 Space::kip_address() const
00590 {
00591   return (is_sigma0()
00592           ? Kmem::virt_to_phys (Kip::k())
00593           : (Address)Mem_layout::Kip_auto_map);
00594 }
00595 
00596 
00597 
00598 inline void
00599 Space::remove_from_space_index()
00600 {
00601   Space_index::del (id(), chief());
00602 }
00603 
00604 
00605 
00606 inline bool
00607 Space::is_mappable(Address, size_t)
00608 {
00609   return true;
00610 }
00611 
00612 
00613 
00614 inline Space *
00615 Space::current()
00616 {
00617   return reinterpret_cast<Space*>(Kmem::phys_to_virt(Cpu::get_pdbr()));
00618 }
00619 
00620 
00621 
00622 inline void
00623 Space::make_current()
00624 {
00625   Cpu::set_pdbr((Mem_layout::pmem_to_phys(this)));
00626 }
00627 
00628 
00629 
00630 inline void
00631 Space::switchin_context()
00632 {
00633   // never switch to kernel space (context of the idle thread)
00634   if (this == (Space*)Kmem::dir())
00635     return;
00636 
00637   bool need_flush_tlb = false;
00638   unsigned index      = Pdir::virt_to_idx(Kmem::ipc_window(0));
00639 
00640   if (_dir[index] || _dir[index + 1])
00641     {
00642       _dir[index]     = 0;
00643       _dir[index + 1] = 0;
00644       need_flush_tlb  = true;
00645     }
00646 
00647   index = Pdir::virt_to_idx(Kmem::ipc_window(1));
00648 
00649   if (_dir[index] || _dir[index + 1])
00650     {
00651       _dir[index]     = 0;
00652       _dir[index + 1] = 0;
00653       need_flush_tlb  = true;
00654     }
00655 
00656   if (need_flush_tlb || this != Space::current())
00657     {
00658       switchin_lipc_kip_pointer();
00659       CNT_ADDR_SPACE_SWITCH;
00660       make_current();
00661       switch_ldt();
00662     }
00663 }
00664 
00665 
00666 
00667 inline void
00668 Space::switch_ldt()
00669 {
00670 }
00671 
00672 
00673 /*
00674  * The following functions are all no-ops on native ia32.
00675  * Pages appear in an address space when the corresponding PTE is made
00676  * ... unlike Fiasco-UX which needs these special tricks
00677  */
00678 
00679 inline void
00680 Space::page_map(Address, Address, Address, unsigned)
00681 {}
00682 
00683 
00684 
00685 inline void
00686 Space::page_protect(Address, Address, unsigned)
00687 {}
00688 
00689 
00690 
00691 inline void
00692 Space::page_unmap(Address, Address)
00693 {}
00694 
00695 
00696 
00697 inline void Space::kmem_update(void *addr)
00698 {
00699   unsigned i = Pdir::virt_to_idx((Address)addr);
00700 
00701   _dir[i] = (*Kmem::dir())[i];
00702 }
00703 
00704 
00712 inline void
00713 Space::remote_update(const Address loc_addr, const Space *rem,
00714                       const Address rem_addr, size_t n)
00715 {
00716   bool tlb_flush    = false;
00717   unsigned loc_slot = Pdir::virt_to_idx(loc_addr),
00718            rem_slot = Pdir::virt_to_idx(rem_addr);
00719 
00720   // PDE boundary check
00721   assert (loc_slot + n <= 1024);
00722   assert (rem_slot + n <= 1024);
00723 
00724   while (n--)
00725     {
00726       if (_dir[loc_slot])
00727         tlb_flush = true;
00728 
00729       // XXX: If we copy a PDE and it maps either a superpage with PDE_GLOBAL
00730       // or a pagetable with one or multiple PTE_GLOBAL entries, these won't
00731       // be flushed on a TLB flush. Suggested solution: When mapping a page
00732       // with global bit, a PDE_NO_LONGIPC bit should be set in the
00733       // corresponding PDE and this bit should be checked here before copying.
00734 
00735       // This loop seems unnecessary, but remote_update is also used for
00736       // updating the long IPC window.
00737       // Now consider following scenario with super pages:
00738       // Sender A makes long IPC to receiver B.
00739       // A setups the IPC window by reading the pagedir slot from B in an 
00740       // temporary register. Now the sender is preempted by C. Then C unmaps 
00741       // the corresponding super page from B. C switch to A back, using 
00742       // switch_to, which clears the IPC window pde slots from A. BUT then A 
00743       // write the  content of the temporary register, which contain the now 
00744       // invalid pde slot, in his own page directory and starts the long IPC.
00745       // Because no pagefault will happen, A will write to now invalid memory.
00746       // So we compare after storing the pde slot, if the copy is still
00747       // valid. And this solution is much faster than grabbing the cpu lock,
00748       // when updating the ipc window.
00749       for(;;) {
00750 
00751         const volatile Pd_entry *val = rem->dir()->index(rem_slot);
00752         _dir[loc_slot] =  val->raw();
00753 
00754         if(EXPECT_TRUE(_dir[loc_slot] == val->raw()))
00755           break;
00756       }
00757 
00758       loc_slot++;
00759       rem_slot++;
00760 
00761     }
00762 
00763   if (tlb_flush)
00764     Mem_unit::tlb_flush();
00765 }
00766 
00767 
00768 
00769 inline void
00770 Space::update_small(Address, bool)
00771 {}
00772 
00773 
00774 
00775 inline Space *
00776 current_space()
00777 {  
00778   return Space::current();
00779 }
00780 
00781 #endif // space_h

Generated on Mon Sep 26 14:20:12 2005 for Fiasco by  doxygen 1.4.2