]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/32/cpu-32.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / 32 / cpu-32.cpp
1 IMPLEMENTATION [ia32,ux]:
2
3 #include "mem_layout.h"
4 #include "tss.h"
5
6 PUBLIC static inline
7 Mword
8 Cpu::stack_align(Mword stack)
9 { return stack & ~0x3; }
10
11
12 PUBLIC inline
13 Unsigned64
14 Cpu::ns_to_tsc(Unsigned64 ns) const
15 {
16   Unsigned32 dummy;
17   Unsigned64 tsc;
18   asm volatile
19         ("movl  %%edx, %%ecx            \n\t"
20          "mull  %3                      \n\t"
21          "movl  %%ecx, %%eax            \n\t"
22          "movl  %%edx, %%ecx            \n\t"
23          "mull  %3                      \n\t"
24          "addl  %%ecx, %%eax            \n\t"
25          "adcl  $0, %%edx               \n\t"
26          "shld  $5, %%eax, %%edx        \n\t"
27          "shll  $5, %%eax               \n\t"
28         :"=A" (tsc), "=&c" (dummy)
29         : "0" (ns),  "b" (scaler_ns_to_tsc)
30         );
31   return tsc;
32 }
33
34 PUBLIC inline
35 Unsigned64
36 Cpu::tsc_to_ns(Unsigned64 tsc) const
37 {
38   Unsigned32 dummy;
39   Unsigned64 ns;
40   asm volatile
41         ("movl  %%edx, %%ecx            \n\t"
42          "mull  %3                      \n\t"
43          "movl  %%ecx, %%eax            \n\t"
44          "movl  %%edx, %%ecx            \n\t"
45          "mull  %3                      \n\t"
46          "addl  %%ecx, %%eax            \n\t"
47          "adcl  $0, %%edx               \n\t"
48          "shld  $5, %%eax, %%edx        \n\t"
49          "shll  $5, %%eax               \n\t"
50         :"=A" (ns), "=&c" (dummy)
51         : "0" (tsc), "b" (scaler_tsc_to_ns)
52         );
53   return ns;
54 }
55
56 PUBLIC inline
57 Unsigned64
58 Cpu::tsc_to_us(Unsigned64 tsc) const
59 {
60   Unsigned32 dummy;
61   Unsigned64 us;
62   asm volatile
63         ("movl  %%edx, %%ecx            \n\t"
64          "mull  %3                      \n\t"
65          "movl  %%ecx, %%eax            \n\t"
66          "movl  %%edx, %%ecx            \n\t"
67          "mull  %3                      \n\t"
68          "addl  %%ecx, %%eax            \n\t"
69          "adcl  $0, %%edx               \n\t"
70         :"=A" (us), "=&c" (dummy)
71         : "0" (tsc), "S" (scaler_tsc_to_us)
72         );
73   return us;
74 }
75
76
77 PUBLIC inline
78 void
79 Cpu::tsc_to_s_and_ns(Unsigned64 tsc, Unsigned32 *s, Unsigned32 *ns) const
80 {
81     Unsigned32 dummy;
82     __asm__
83         ("                              \n\t"
84          "movl  %%edx, %%ecx            \n\t"
85          "mull  %4                      \n\t"
86          "movl  %%ecx, %%eax            \n\t"
87          "movl  %%edx, %%ecx            \n\t"
88          "mull  %4                      \n\t"
89          "addl  %%ecx, %%eax            \n\t"
90          "adcl  $0, %%edx               \n\t"
91          "movl  $1000000000, %%ecx      \n\t"
92          "shld  $5, %%eax, %%edx        \n\t"
93          "shll  $5, %%eax               \n\t"
94          "divl  %%ecx                   \n\t"
95         :"=a" (*s), "=d" (*ns), "=&c" (dummy)
96         : "A" (tsc), "g" (scaler_tsc_to_ns)
97         );
98 }
99
100
101 PUBLIC static inline
102 Unsigned64
103 Cpu::rdtsc()
104 {
105   Unsigned64 tsc;
106   asm volatile ("rdtsc" : "=A" (tsc));
107   return tsc;
108 }
109
110 PUBLIC static inline
111 Unsigned32
112 Cpu::get_flags()
113 { Unsigned32 efl; asm volatile ("pushfl ; popl %0" : "=r"(efl)); return efl; }
114
115 PUBLIC static inline
116 void
117 Cpu::set_flags(Unsigned32 efl)
118 { asm volatile ("pushl %0 ; popfl" : : "rm" (efl) : "memory"); }
119
120 IMPLEMENT inline NEEDS["tss.h"]
121 Address volatile &
122 Cpu::kernel_sp() const
123 { return *reinterpret_cast<Address volatile *>(&get_tss()->_esp0); }
124
125 //----------------------------------------------------------------------------
126 IMPLEMENTATION[ia32]:
127
128 PUBLIC static inline
129 void
130 Cpu:: set_cs()
131 {
132   asm volatile("ljmp %0, $1f ; 1:"
133                : : "i"(Gdt::gdt_code_kernel | Gdt::Selector_kernel));
134 }
135
136 extern "C" void entry_vec08_dbf();
137 extern "C" Address dbf_stack_top;
138
139 PUBLIC FIASCO_INIT_CPU
140 void
141 Cpu::init_tss_dbf(Address tss_dbf_mem, Address kdir)
142 {
143   tss_dbf = reinterpret_cast<Tss*>(tss_dbf_mem);
144
145   gdt->set_entry_byte(Gdt::gdt_tss_dbf / 8, tss_dbf_mem, sizeof(Tss) - 1,
146                       Gdt_entry::Access_kernel | Gdt_entry::Access_tss |
147                       Gdt_entry::Accessed, 0);
148
149   tss_dbf->_cs     = Gdt::gdt_code_kernel;
150   tss_dbf->_ss     = Gdt::gdt_data_kernel;
151   tss_dbf->_ds     = Gdt::gdt_data_kernel;
152   tss_dbf->_es     = Gdt::gdt_data_kernel;
153   tss_dbf->_fs     = Gdt::gdt_data_kernel;
154   tss_dbf->_gs     = Gdt::gdt_data_kernel;
155   tss_dbf->_eip    = (Address)entry_vec08_dbf;
156   tss_dbf->_esp    = (Address)&dbf_stack_top;
157   tss_dbf->_ldt    = 0;
158   tss_dbf->_eflags = 0x00000082;
159   tss_dbf->_cr3    = kdir;
160   tss_dbf->_io_bit_map_offset = 0x8000;
161 }
162
163
164 PUBLIC FIASCO_INIT_CPU
165 void
166 Cpu::init_tss(Address tss_mem, size_t tss_size)
167 {
168   tss = reinterpret_cast<Tss*>(tss_mem);
169
170   gdt->set_entry_byte(Gdt::gdt_tss / 8, tss_mem, tss_size,
171                       Gdt_entry::Access_kernel | Gdt_entry::Access_tss, 0);
172
173   tss->set_ss0(Gdt::gdt_data_kernel);
174   tss->_io_bit_map_offset = Mem_layout::Io_bitmap - tss_mem;
175 }
176
177
178 PUBLIC FIASCO_INIT_CPU
179 void
180 Cpu::init_gdt(Address gdt_mem, Address user_max)
181 {
182   gdt = reinterpret_cast<Gdt*>(gdt_mem);
183
184   // make sure kernel cs/ds and user cs/ds are placed in the same
185   // cache line, respectively; pre-set all "accessed" flags so that
186   // the CPU doesn't need to do this later
187
188   gdt->set_entry_4k(Gdt::gdt_code_kernel / 8, 0, 0xffffffff,
189                     Gdt_entry::Access_kernel |
190                     Gdt_entry::Access_code_read |
191                     Gdt_entry::Accessed, Gdt_entry::Size_32);
192   gdt->set_entry_4k(Gdt::gdt_data_kernel / 8, 0, 0xffffffff,
193                     Gdt_entry::Access_kernel |
194                     Gdt_entry::Access_data_write |
195                     Gdt_entry::Accessed, Gdt_entry::Size_32);
196   gdt->set_entry_4k(Gdt::gdt_code_user / 8, 0, user_max,
197                     Gdt_entry::Access_user |
198                     Gdt_entry::Access_code_read |
199                     Gdt_entry::Accessed, Gdt_entry::Size_32);
200   gdt->set_entry_4k(Gdt::gdt_data_user / 8, 0, user_max,
201                     Gdt_entry::Access_user |
202                     Gdt_entry::Access_data_write |
203                     Gdt_entry::Accessed, Gdt_entry::Size_32);
204 }