]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/task-ia32-amd64.cpp
f8f9ed6939ef283d640a60e55618f8bdaefc437c
[l4.git] / kernel / fiasco / src / kern / ia32 / task-ia32-amd64.cpp
1 IMPLEMENTATION [ia32 || amd64]:
2
3 #include "gdt.h"
4 #include "std_macros.h"
5 #include "x86desc.h"
6
7 IMPLEMENT inline
8 Task::~Task()
9 {
10   free_utcbs();
11 }
12
13 PRIVATE inline NEEDS["gdt.h"]
14 bool
15 Task::invoke_arch(L4_msg_tag &tag, Utcb *utcb)
16 {
17   switch (utcb->values[0])
18     {
19     case Ldt_set_x86:
20         {
21           enum
22           {
23             Utcb_values_per_ldt_entry
24               = Cpu::Ldt_entry_size / sizeof(utcb->values[0]),
25           };
26           if (EXPECT_FALSE(tag.words() < 3
27                            || tag.words() % Utcb_values_per_ldt_entry))
28             {
29               tag = commit_result(-L4_err::EInval);
30               return true;
31             }
32
33           unsigned entry_number  = utcb->values[1];
34           unsigned size          = (tag.words() - 2) * sizeof(utcb->values[0]);
35
36           // Allocate the memory if not yet done
37           if (!_ldt.addr())
38             _ldt.alloc();
39
40           if (entry_number * Cpu::Ldt_entry_size + size > Config::PAGE_SIZE)
41             {
42               WARN("set_ldt: LDT size exceeds one page, not supported.");
43               tag = commit_result(-L4_err::EInval);
44               return true;
45             }
46
47           _ldt.size(size + Cpu::Ldt_entry_size * entry_number);
48
49           Address desc_addr = reinterpret_cast<Address>(&utcb->values[2]);
50           Gdt_entry desc;
51           Gdt_entry *ldtp
52             = reinterpret_cast<Gdt_entry *>(_ldt.addr()) + entry_number;
53
54           while (size >= Cpu::Ldt_entry_size)
55             {
56               desc = *reinterpret_cast<Gdt_entry const *>(desc_addr);
57               if (desc.unsafe())
58                 {
59                   WARN("set_ldt: Bad descriptor.");
60                   tag = commit_result(-L4_err::EInval);
61                   return true;
62                 }
63
64               *ldtp      = desc;
65               size      -= Cpu::Ldt_entry_size;
66               desc_addr += Cpu::Ldt_entry_size;
67               ldtp++;
68             }
69
70           if (this == current()->space())
71             Cpu::cpus.cpu(current_cpu()).enable_ldt(_ldt.addr(), _ldt.size());
72
73           tag = commit_result(0);
74         }
75       return true;
76     }
77
78
79
80
81   return false;
82 }