]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/thread-vcpu.cpp
1ad498cc2ffbb6290cd1761927dc721a7fb8da5d
[l4.git] / kernel / fiasco / src / kern / thread-vcpu.cpp
1 INTERFACE:
2
3 extern "C" void vcpu_resume(Trap_state *, Return_frame *sp)
4    FIASCO_FASTCALL FIASCO_NORETURN;
5
6
7 // --------------------------------------------------------------------------
8 IMPLEMENTATION:
9
10 #include "logdefs.h"
11 #include "vcpu.h"
12
13 PUBLIC inline NEEDS["logdefs.h", "vcpu.h"]
14 bool
15 Thread::vcpu_pagefault(Address pfa, Mword err, Mword ip)
16 {
17   (void)ip;
18   if (vcpu_pagefaults_enabled())
19     {
20       spill_user_state();
21       vcpu_enter_kernel_mode();
22       LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
23           Vcpu_log *l = tbe->payload<Vcpu_log>();
24           l->type = 3;
25           l->state = vcpu_state()->_saved_state;
26           l->ip = ip;
27           l->sp = pfa;
28           l->space = vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
29           );
30       vcpu_state()->_ts.set_pagefault(pfa, err);
31       vcpu_save_state_and_upcall();
32       return true;
33     }
34
35   return false;
36 }
37
38
39 PRIVATE inline NEEDS[Thread::fast_return_to_user]
40 L4_msg_tag
41 Thread::sys_vcpu_resume(L4_msg_tag const &tag, Utcb *utcb)
42 {
43   if (this != current() || !(state() & Thread_vcpu_enabled))
44     return commit_result(-L4_err::EInval);
45
46   Obj_space *s = space()->obj_space();
47
48   L4_obj_ref user_task = vcpu_state()->user_task;
49   if (user_task.valid())
50     {
51       unsigned char task_rights = 0;
52       Task *task = Kobject::dcast<Task*>(s->lookup_local(user_task.cap(),
53                                                          &task_rights));
54
55       if (EXPECT_FALSE(task && !(task_rights & L4_fpage::W)))
56         return commit_result(-L4_err::EPerm);
57
58       if (task != vcpu_user_space())
59         vcpu_set_user_space(task);
60
61       vcpu_state()->user_task = L4_obj_ref();
62     }
63   else if (user_task.flags() == L4_obj_ref::Ipc_reply)
64     vcpu_set_user_space(0);
65
66   L4_snd_item_iter snd_items(utcb, tag.words());
67   int items = tag.items();
68   for (; items && snd_items.more(); --items)
69     {
70       if (EXPECT_FALSE(!snd_items.next()))
71         break;
72
73       cpu_lock.clear();
74
75       L4_snd_item_iter::Item const *const item = snd_items.get();
76       L4_fpage sfp(item->d);
77
78       Reap_list rl;
79       L4_error err = fpage_map(space(), sfp,
80                                vcpu_user_space(), L4_fpage::all_spaces(),
81                                item->b.raw(), &rl);
82       rl.del();
83
84       cpu_lock.lock();
85
86       if (EXPECT_FALSE(!err.ok()))
87         return commit_error(utcb, err);
88     }
89
90   if ((vcpu_state()->_saved_state & Vcpu_state::F_irqs) && vcpu_irqs_pending())
91     {
92       assert_kdb(cpu_lock.test());
93       do_ipc(L4_msg_tag(), 0, 0, true, 0,
94              L4_timeout_pair(L4_timeout::Zero, L4_timeout::Zero),
95              &vcpu_state()->_ipc_regs, 7);
96       if (EXPECT_TRUE(!vcpu_state()->_ipc_regs.tag().has_error()))
97         {
98           vcpu_state()->_ts.set_ipc_upcall();
99
100           Address sp;
101
102           if (vcpu_state()->_saved_state & Vcpu_state::F_user_mode)
103             sp = vcpu_state()->_entry_sp;
104           else
105             sp = vcpu_state()->_ts.sp();
106
107           LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
108               Vcpu_log *l = tbe->payload<Vcpu_log>();
109               l->type = 4;
110               l->state = vcpu_state()->state;
111               l->ip = vcpu_state()->_entry_ip;
112               l->sp = sp;
113               l->space = vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
114               );
115
116           fast_return_to_user(vcpu_state()->_entry_ip, sp, false);
117         }
118     }
119
120   vcpu_state()->state = vcpu_state()->_saved_state;
121   Trap_state ts;
122   memcpy(&ts, &vcpu_state()->_ts, sizeof(Trap_state));
123
124
125   assert_kdb(cpu_lock.test());
126
127   ts.set_ipc_upcall();
128
129   ts.sanitize_user_state();
130
131   if (vcpu_state()->state & Vcpu_state::F_user_mode)
132     {
133       if (!vcpu_user_space())
134         return commit_result(-L4_err::EInval);
135
136       vcpu_state()->state |= Vcpu_state::F_traps | Vcpu_state::F_exceptions
137                              | Vcpu_state::F_debug_exc;
138       state_add_dirty(Thread_vcpu_user_mode | Thread_alien);
139
140       if (!(vcpu_state()->state & Vcpu_state::F_fpu_enabled))
141         {
142           state_add_dirty(Thread_vcpu_fpu_disabled);
143           Fpu::disable();
144         }
145       else
146         state_del_dirty(Thread_vcpu_fpu_disabled);
147
148       vcpu_resume_user_arch();
149
150       vcpu_user_space()->switchin_context(space());
151     }
152
153   LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
154       Vcpu_log *l = tbe->payload<Vcpu_log>();
155       l->type = 0;
156       l->state = vcpu_state()->state;
157       l->ip = ts.ip();
158       l->sp = ts.sp();
159       l->space = vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
160       );
161
162   vcpu_resume(&ts, regs());
163 }