]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/task.cpp
update
[l4.git] / kernel / fiasco / src / kern / task.cpp
1 INTERFACE:
2
3 #include "context.h"
4 #include "kobject.h"
5 #include "l4_types.h"
6 #include "rcupdate.h"
7 #include "space.h"
8 #include "spin_lock.h"
9
10 class slab_cache_anon;
11
12 /**
13  * \brief A task is a protection domain.
14  *
15  * A is derived from Space, which aggregates a set of address spaces.
16  * Additionally to a space, a task provides initialization and
17  * destruction functionality for a protection domain.
18  * Task is also derived from Rcu_item to provide RCU shutdown of tasks.
19  */
20 class Task :
21   public Space,
22   public Kobject_iface,
23   public Kobject,
24   private Rcu_item
25 {
26   FIASCO_DECLARE_KOBJ();
27
28   friend class Jdb_space;
29
30 private:
31
32   /// \brief Do host (platform) specific initialization.
33   void host_init();
34
35   /// \brief Map the trace buffer to the user address space.
36   void map_tbuf();
37
38 public:
39
40   enum Operation
41   {
42     Map         = 0,
43     Unmap       = 1,
44     Cap_info    = 2,
45     Ldt_set_x86 = 0x11,
46     Vm_ops      = 0x20,
47   };
48
49
50   /// \brief Destroy it.
51   ~Task();
52
53   /**
54    * \brief Allocate memory for UTCBs for that task.
55    * \return true on success, or false on memory shortage.
56    */
57   bool alloc_utcbs();
58
59   /**
60    * \brief Free the UTCBs allocated with alloc_utcbs()-.
61    */
62   void free_utcbs();
63
64 private:
65
66   enum
67   {
68     /// Number of Utcbs fitting on a single page
69     Utcbs_per_page = Config::PAGE_SIZE / sizeof(Utcb),
70   };
71
72 private:
73   /// map the global utcb pointer page into this task
74   void map_utcb_ptr_page();
75
76
77
78 };
79
80
81 //---------------------------------------------------------------------------
82 IMPLEMENTATION:
83
84 #include "atomic.h"
85 #include "auto_ptr.h"
86 #include "config.h"
87 #include "entry_frame.h"
88 #include "globals.h"
89 #include "kdb_ke.h"
90 #include "kmem.h"
91 #include "kmem_slab_simple.h"
92 #include "l4_types.h"
93 #include "l4_buf_iter.h"
94 #include "logdefs.h"
95 #include "map_util.h"
96 #include "mem_layout.h"
97 #include "ram_quota.h"
98 #include "paging.h"
99 #include "vmem_alloc.h"
100
101 FIASCO_DEFINE_KOBJ(Task);
102
103
104 PUBLIC virtual
105 bool
106 Task::put()
107 {
108   return dec_ref() == 0;
109 }
110
111
112 IMPLEMENT
113 bool
114 Task::alloc_utcbs()
115 {
116   if (!utcb_area_size())
117     {
118       set_kern_utcb_area(0);
119       return true;
120     }
121
122   Mapped_allocator *const alloc = Mapped_allocator::allocator();
123   void *utcbs = alloc->q_unaligned_alloc(ram_quota(), utcb_area_size());
124
125   if (EXPECT_FALSE(!utcbs))
126     return false;
127
128   // clean up utcbs
129   memset(utcbs, 0, utcb_area_size());
130   set_kern_utcb_area(Address(utcbs));
131
132   unsigned long page_size = Config::PAGE_SIZE;
133
134   // the following works because the size is a power of two
135   // and once we have size larger than a super page we have
136   // always multiples of superpages
137   if (utcb_area_size() >= Config::SUPERPAGE_SIZE)
138     page_size = Config::SUPERPAGE_SIZE;
139
140   for (unsigned long i = 0; i < utcb_area_size(); i += page_size)
141     {
142       Address kern_va = kern_utcb_area() + i;
143       Address user_va = user_utcb_area() + i;
144       Address pa = mem_space()->pmem_to_phys(kern_va);
145
146       // must be valid physical address
147       assert(pa != ~0UL);
148
149       Mem_space::Status res =
150         mem_space()->v_insert(Mem_space::Phys_addr(pa),
151             Mem_space::Addr(user_va), Mem_space::Size(page_size),
152             Mem_space::Page_writable | Mem_space::Page_user_accessible
153             | Mem_space::Page_cacheable);
154
155       switch (res)
156         {
157         case Mem_space::Insert_ok: break;
158         case Mem_space::Insert_err_nomem:
159           free_utcbs();
160           return false;
161         default:
162           printf("UTCB mapping failed: va=%p, ph=%p, res=%d\n",
163               (void*)user_va, (void*)kern_va, res);
164           kdb_ke("BUG in utcb allocation");
165           free_utcbs();
166           return false;
167         }
168     }
169
170   return true;
171 }
172
173 IMPLEMENT
174 void
175 Task::free_utcbs()
176 {
177   if (EXPECT_FALSE(!kern_utcb_area() || !mem_space() || !mem_space()->dir()))
178     return;
179
180   Mapped_allocator * const alloc = Mapped_allocator::allocator();
181   unsigned long page_size = Config::PAGE_SIZE;
182
183   // the following works because the size is a poer of two
184   // and once we have size larger than a super page we have
185   // always multiples of superpages
186   if (utcb_area_size() >= Config::SUPERPAGE_SIZE)
187     page_size = Config::SUPERPAGE_SIZE;
188
189   for (unsigned long i = 0; i < utcb_area_size(); i += page_size)
190     {
191       Address user_va = user_utcb_area() + i;
192       mem_space()->v_delete(Mem_space::Addr(user_va),
193                             Mem_space::Size(page_size));
194     }
195
196   alloc->q_unaligned_free(ram_quota(), utcb_area_size(), (void*)kern_utcb_area());
197
198   set_kern_utcb_area(0);
199 }
200
201
202
203 /** Allocate space for the UTCBs of all threads in this task.
204  *  @ return true on success, false if not enough memory for the UTCBs
205  */
206 PUBLIC
207 bool
208 Task::initialize()
209 {
210   // For UX, map the UTCB pointer page. For ia32, do nothing
211   map_utcb_ptr_page();
212
213   return true;
214 }
215
216 /**
217  * \brief Create a normal Task.
218  * \pre \a parent must be valid and exist.
219  */
220 PUBLIC
221 template< typename SPACE_FACTORY >
222 Task::Task(SPACE_FACTORY const &sf, Ram_quota *q, L4_fpage const &utcb_area)
223   : Space(sf, q, utcb_area)
224 {
225   host_init();
226
227   inc_ref();
228
229   if (mem_space()->is_sigma0())
230     map_tbuf();
231
232   if (alloc_utcbs())
233     {
234       Lock_guard<Spin_lock> guard(state_lock());
235       set_state(Ready);
236     }
237 }
238
239
240 PROTECTED static
241 slab_cache_anon*
242 Task::allocator()
243 {
244   static slab_cache_anon* slabs = new Kmem_slab_simple (sizeof (Task), 
245                                                         sizeof (Mword),
246                                                         "Task");
247   return slabs;
248
249   // If Fiasco would kill all tasks even when exiting through the
250   // kernel debugger, we could use a deallocating version of the above:
251   //
252   // static auto_ptr<slab_cache_anon> slabs
253   //   (new Kmem_slab_simple (sizeof (Task), sizeof (Mword)))
254   // return slabs.get();
255 }
256
257
258
259 PROTECTED inline NEEDS["kmem_slab_simple.h"]
260 void *
261 Task::operator new (size_t size, void *p)
262 {
263   (void)size;
264   assert (size == sizeof (Task));
265   return p;
266 }
267
268
269 PUBLIC //inline NEEDS["kmem_slab_simple.h"]
270 void
271 Task::operator delete (void *ptr)
272 {
273   Task *t = reinterpret_cast<Task*>(ptr);
274   LOG_TRACE("Kobject delete", "del", current(), __fmt_kobj_destroy,
275             Log_destroy *l = tbe->payload<Log_destroy>();
276             l->id = t->dbg_id();
277             l->obj = t;
278             l->type = "Task";
279             l->ram = t->ram_quota()->current());
280
281   allocator()->q_free(t->ram_quota(), ptr);
282 }
283
284 PUBLIC template< typename SPACE_FACTORY > inline NEEDS[Task::operator new]
285 static
286 Task *
287 Task::create(SPACE_FACTORY const &sf, Ram_quota *quota,
288              L4_fpage const &utcb_area)
289 {
290   if (void *t = allocator()->q_alloc(quota))
291     {
292       Task *a = new (t) Task(sf, quota, utcb_area);
293       if (a->valid())
294         return a;
295
296       delete a;
297     }
298
299   return 0;
300 }
301
302 PUBLIC inline
303 bool
304 Task::valid() const
305 { return mem_space()->valid() && state() == Ready; }
306
307
308 PUBLIC
309 void
310 Task::initiate_deletion(Kobject ***reap_list)
311 {
312   Kobject::initiate_deletion(reap_list);
313
314   Lock_guard<Spin_lock> guard(state_lock());
315   set_state(In_deletion);
316 }
317
318 /**
319  * \brief Shutdown the task.
320  *
321  * Currently:
322  * -# Unbind and delete all contexts bound to this task.
323  * -# Unmap everything from all spaces.
324  * -# Delete child tasks.
325  */
326 PUBLIC
327 void
328 Task::destroy(Kobject ***reap_list)
329 {
330   Kobject::destroy(reap_list);
331
332   fpage_unmap(this, L4_fpage::all_spaces(L4_fpage::RWX), L4_map_mask::full(), reap_list);
333 }
334
335 PRIVATE inline NOEXPORT
336 L4_msg_tag
337 Task::sys_map(unsigned char rights, Syscall_frame *f, Utcb *utcb)
338 {
339   LOG_TRACE("Task map", "map", ::current(), __task_unmap_fmt,
340       Log_unmap *lu = tbe->payload<Log_unmap>();
341       lu->id = dbg_id();
342       lu->mask  = utcb->values[1];
343       lu->fpage = utcb->values[2]);
344
345   if (EXPECT_FALSE(!(rights & L4_fpage::W)))
346     return commit_result(-L4_err::EPerm);
347
348   L4_msg_tag const tag = f->tag();
349
350   Obj_space *s = current()->space()->obj_space();
351   L4_snd_item_iter snd_items(utcb, tag.words());
352
353   if (EXPECT_FALSE(!tag.items() || !snd_items.next()))
354     return commit_result(-L4_err::EInval);
355
356   L4_fpage src_task(snd_items.get()->d);
357   if (EXPECT_FALSE(!src_task.is_objpage()))
358     return commit_result(-L4_err::EInval);
359
360   Task *from = Kobject::dcast<Task*>(s->lookup_local(src_task.obj_index()));
361   if (!from)
362     return commit_result(-L4_err::EInval);
363
364   // enforce lock order to prevent deadlocks.
365   // always take lock from task with the lower memory address first
366   Lock_guard_2<Lock> guard;
367
368   if (!guard.lock(&existence_lock, &from->existence_lock))
369     return commit_result(-L4_err::EInval);
370
371   cpu_lock.clear();
372
373   Reap_list rl;
374
375   L4_error ret = fpage_map(from, L4_fpage(utcb->values[2]), this, L4_fpage::all_spaces(), utcb->values[1], &rl);
376
377   rl.del();
378
379   cpu_lock.lock();
380   // FIXME: treat reaped stuff
381   if (ret.ok())
382     return commit_result(0);
383   else
384     return commit_error(utcb, ret);
385 }
386
387
388 PRIVATE inline NOEXPORT
389 L4_msg_tag
390 Task::sys_unmap(Syscall_frame *f, Utcb *utcb)
391 {
392   Lock_guard<Lock> guard;
393
394   if (!guard.lock(&existence_lock))
395     return commit_error(utcb, L4_error::Not_existent);
396
397   LOG_TRACE("Task unmap", "unm", ::current(), __task_unmap_fmt,
398             Log_unmap *lu = tbe->payload<Log_unmap>();
399             lu->id = dbg_id();
400             lu->mask  = utcb->values[1];
401             lu->fpage = utcb->values[2]);
402
403   cpu_lock.clear();
404
405   Reap_list rl;
406   L4_map_mask m(utcb->values[1]);
407   unsigned words = f->tag().words();
408
409   for (unsigned i = 2; i < words; ++i)
410     {
411       unsigned const flushed = fpage_unmap(this, L4_fpage(utcb->values[i]), m, rl.list());
412       utcb->values[i] = (utcb->values[i] & ~0xfUL) | flushed;
413     }
414
415   rl.del();
416
417   cpu_lock.lock();
418   return commit_result(0, words);
419 }
420
421 PRIVATE inline NOEXPORT
422 L4_msg_tag
423 Task::sys_cap_valid(Syscall_frame *, Utcb *utcb)
424 {
425   L4_obj_ref obj(utcb->values[1]);
426
427   if (obj.invalid())
428     return commit_result(0);
429
430   Obj_space::Capability cap = obj_space()->lookup(obj.cap());
431   if (EXPECT_TRUE(cap.valid()))
432     {
433       if (!(utcb->values[1] & 1))
434         return commit_result(1);
435       else
436         return commit_result(cap.obj()->map_root()->cap_ref_cnt());
437     }
438   else
439     return commit_result(0);
440 }
441
442 PRIVATE inline NOEXPORT
443 L4_msg_tag
444 Task::sys_caps_equal(Syscall_frame *, Utcb *utcb)
445 {
446   L4_obj_ref obj_a(utcb->values[1]);
447   L4_obj_ref obj_b(utcb->values[2]);
448
449   if (obj_a == obj_b)
450     return commit_result(1);
451
452   if (obj_a.invalid() || obj_b.invalid())
453     return commit_result(obj_a.invalid() && obj_b.invalid());
454   
455   Obj_space::Capability c_a = obj_space()->lookup(obj_a.cap());
456   Obj_space::Capability c_b = obj_space()->lookup(obj_b.cap());
457
458   return commit_result(c_a == c_b);
459 }
460
461 PRIVATE inline NOEXPORT
462 L4_msg_tag
463 Task::sys_cap_info(Syscall_frame *f, Utcb *utcb)
464 {
465   L4_msg_tag const &tag = f->tag();
466
467   switch (tag.words())
468     {
469     default: return commit_result(-L4_err::EInval);
470     case 2:  return sys_cap_valid(f, utcb);
471     case 3:  return sys_caps_equal(f, utcb);
472     }
473 }
474
475
476
477
478 PUBLIC
479 void
480 Task::invoke(L4_obj_ref, Mword rights, Syscall_frame *f, Utcb *utcb)
481 {
482   if (EXPECT_FALSE(f->tag().proto() != L4_msg_tag::Label_task))
483     {
484       f->tag(commit_result(-L4_err::EBadproto));
485       return;
486     }
487
488   switch (utcb->values[0])
489     {
490     case Map:
491       f->tag(sys_map(rights, f, utcb));
492       return;
493     case Unmap:
494       f->tag(sys_unmap(f, utcb));
495       return;
496     case Cap_info:
497       f->tag(sys_cap_info(f, utcb));
498       return;
499     default:
500       L4_msg_tag tag = f->tag();
501       if (invoke_arch(tag, utcb))
502         f->tag(tag);
503       else
504         f->tag(commit_result(-L4_err::ENosys));
505       return;
506     }
507 }
508
509 //---------------------------------------------------------------------------
510 IMPLEMENTATION [!ux]:
511
512 IMPLEMENT inline
513 void
514 Task::map_utcb_ptr_page()
515 {}
516
517 IMPLEMENT inline
518 void
519 Task::host_init()
520 {}
521
522 IMPLEMENT inline
523 void
524 Task::map_tbuf()
525 {}
526
527
528 //---------------------------------------------------------------------------
529 IMPLEMENTATION [!(ia32|ux|amd64)]:
530
531 IMPLEMENT inline
532 Task::~Task()
533 { free_utcbs(); }
534
535
536
537 // ---------------------------------------------------------------------------
538 INTERFACE [debug]:
539
540 EXTENSION class Task
541 {
542 private:
543   struct Log_unmap
544   {
545     Mword id;
546     Mword mask;
547     Mword fpage;
548   } __attribute__((packed));
549
550   static unsigned unmap_fmt(Tb_entry *, int max, char *buf) asm ("__task_unmap_fmt");
551 };
552
553 // ---------------------------------------------------------------------------
554 IMPLEMENTATION [debug]:
555
556 IMPLEMENT
557 unsigned
558 Task::unmap_fmt(Tb_entry *e, int max, char *buf)
559 {
560   Log_unmap *l = e->payload<Log_unmap>();
561   L4_fpage fp(l->fpage);
562   return snprintf(buf, max, "task=[U:%lx] mask=%lx fpage=[%u/%u]%lx",
563                   l->id, l->mask, (unsigned)fp.order(), fp.type(), l->fpage);
564 }
565
566 // ---------------------------------------------------------------------------
567 IMPLEMENTATION[!ia32 || !svm]:
568
569 PRIVATE inline NOEXPORT
570 L4_msg_tag
571 Task::sys_vm_run(Syscall_frame *, Utcb *)
572 {
573   return commit_result(-L4_err::ENosys);
574 }
575