scratch an itch I've had for a while: clean up the x86 context switch routine to not
[newos.git] / kernel / arch / i386 / arch_i386.S
blob44ceac67120088f8225e9c637ab820cab8cffb75
1 /*
2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Copyright 2002, Michael Noisternig. All rights reserved.
4 ** Distributed under the terms of the NewOS License.
5 */
7 #define FUNCTION(x) .global x; .type x,@function; x
9 .text
11 /* int atomic_add(int *val, int incr) */
12 FUNCTION(atomic_add):
13         movl    4(%esp),%edx
14         movl    8(%esp),%eax
15         lock
16         xaddl   %eax,(%edx)
17         ret
19 /* int atomic_and(int *val, int incr) */
20 FUNCTION(atomic_and):
21         movl    4(%esp),%edx
23 _atomic_and1:
24         movl    8(%esp),%ecx
25         movl    (%edx),%eax
26         andl    %eax,%ecx
28         lock
29         cmpxchgl        %ecx,(%edx)
31         jnz             _atomic_and1
33         ret
35 /* int atomic_or(int *val, int incr) */
36 FUNCTION(atomic_or):
37         movl    4(%esp),%edx
39 _atomic_or1:
40         movl    8(%esp),%ecx
41         movl    (%edx),%eax
42         orl             %eax,%ecx
44         lock
45         cmpxchgl        %ecx,(%edx)
47         jnz             _atomic_or1
49         ret
51 /* int atomic_set(int *val, int set_to) */
52 FUNCTION(atomic_set):
53         movl    4(%esp),%edx
54         movl    8(%esp),%eax
55         xchg    %eax,(%edx)
56         ret
58 /* int test_and_set(int *val, int set_to, int test_val) */
59 FUNCTION(test_and_set):
60         movl    4(%esp),%edx
61         movl    8(%esp),%ecx
62         movl    12(%esp),%eax
64         lock
65         cmpxchgl        %ecx,(%edx)
67         ret
69 /* uint64 i386_rdtsc() */
70 .global i386_rdtsc
71 i386_rdtsc:
72         rdtsc
73         ret
75 /* saves the conversion factor needed for system_time */
76 .global cv_factor
77 cv_factor:
78         .word 0
80 FUNCTION(setup_system_time):
81         movl    4(%esp),%eax
82         movl    %eax,cv_factor
83         ret
85 /* bigtime_t i386_cycles_to_time(uint64 cycles); */
86 FUNCTION(i386_cycles_to_time):
87         movl    4(%esp),%eax
88         movl    8(%esp),%edx
90         pushl   %ebx
91         pushl   %ecx
92         movl    cv_factor, %ebx
93         movl    %edx, %ecx      /* save high half */
94         mull    %ebx            /* truncate %eax, but keep %edx */
95         movl    %ecx, %eax
96         movl    %edx, %ecx      /* save high half of low */
97         mull    %ebx /*, %eax*/
98         /* now compute  [%edx, %eax] + [%ecx], propagating carry */
99         subl    %ebx, %ebx      /* need zero to propagate carry */
100         addl    %ecx, %eax
101         adc             %ebx, %edx
102         popl    %ecx
103         popl    %ebx
104         ret
106 /* void arch_cpu_global_TLB_invalidate(); */
107 FUNCTION(arch_cpu_global_TLB_invalidate):
108         movl    %cr3,%eax
109         movl    %eax,%cr3
110         ret
112 /* void i386_fsave(void *fpu_state); */
113 FUNCTION(i386_fsave):
114         movl    4(%esp), %eax
115         fsave   (%eax)
116         ret
118 /* void i386_fxsave(void *fpu_state); */
119 FUNCTION(i386_fxsave):
120         movl    4(%esp), %eax
121         fxsave  (%eax)
122         ret
124 /* void i386_frstor(void *fpu_state); */
125 FUNCTION(i386_frstor):
126         movl    4(%esp), %eax
127         frstor  (%eax)
128         ret
130 /* void i386_fxrstor(void *fpu_state); */
131 FUNCTION(i386_fxrstor):
132         movl    4(%esp), %eax
133         fxrstor (%eax)
134         ret
136 /* void i386_fsave_swap(void *old_fpu_state, void *new_fpu_state); */
137 FUNCTION(i386_fsave_swap):
138         movl    4(%esp),%eax
139         fsave   (%eax)
140         movl    8(%esp),%eax
141         frstor  (%eax)
142         ret
144 /* void i386_fxsave_swap(void *old_fpu_state, void *new_fpu_state); */
145 FUNCTION(i386_fxsave_swap):
146         movl    4(%esp),%eax
147         fxsave  (%eax)
148         movl    8(%esp),%eax
149         fxrstor (%eax)
150         ret
152 /* void i386_context_switch(struct arch_thread *old, struct arch_thread *new); */
153 FUNCTION(i386_context_switch):
154         pusha                                   /* pushes 8 words onto the stack */
156         movl    36(%esp),%eax   /* save current_stack */
157         movl    %esp,(%eax)
159         pushl   %ss                             /* push the old ss */
160         popl    %edx                    /* pop it back off the stack */
161         movl    %edx,4(%eax)    /* save it into the arch_thread structure */
163         movl    40(%esp),%eax   /* get new current_stack */
164         lss             (%eax),%esp
166         popa
167         ret
169 /* void i386_swap_pgdir(addr_t new_pgdir); */
170 FUNCTION(i386_swap_pgdir):
171         movl    4(%esp),%eax
172         movl    %eax,%cr3
173         ret
175 /* thread exit stub */
176         .align 4
177 i386_uspace_exit_stub:
178         pushl   %eax
179         movl    $1, %ecx
180         lea     (%esp), %edx
181         movl    $25, %eax;
182         int     $99
183         .align 4
184 i386_uspace_exit_stub_end:
187 /* void i386_enter_uspace(addr_t entry, void *args, addr_t ustack_top); */
188 FUNCTION(i386_enter_uspace):
189         movl    4(%esp),%eax    // get entry point
190         movl    8(%esp),%edx    // get arguments
191         movl    12(%esp),%ebx   // get user stack
192         movw    $0x23,%cx
193         movw    %cx,%ds
194         movw    %cx,%es
195         movw    %cx,%fs
196         movw    %cx,%gs
198         // copy exit stub to stack
199         movl    $i386_uspace_exit_stub_end, %esi
200 _copy_more:
201         lea     -4(%esi), %esi
202         lea     -4(%ebx), %ebx
203         mov     (%esi), %ecx
204         mov     %ecx, (%ebx)
205         cmp     $i386_uspace_exit_stub, %esi
206         jg      _copy_more
209         // push the args onto the user stack
210         movl    %edx,-4(%ebx)   // args
211         movl    %ebx,-8(%ebx)   // fake return address to copied exit stub
212         sub             $8,%ebx
214         pushl   $0x23                   // user data segment
215         pushl   %ebx                    // user stack
216         pushl   $(1 << 9) | 2   // user flags
217         pushl   $0x1b                   // user code segment
218         pushl   %eax                    // user IP
219         iret
221 /* void i386_switch_stack_and_call(addr_t stack, void (*func)(void *), void *arg); */
222 FUNCTION(i386_switch_stack_and_call):
223         movl    4(%esp),%eax    // new stack
224         movl    8(%esp),%ecx    // func
225         movl    12(%esp),%edx   // args
227         movl    %eax,%esp               // switch the stack
228         pushl   %edx                    // push the argument
229         call    *%ecx                   // call the target function
230 _loop:
231         jmp             _loop
233 null_idt_descr:
234         .word   0
235         .word   0,0
237 FUNCTION(reboot):
238         lidt    null_idt_descr
239         int             $0
240 done:
241         jmp             done
244 FUNCTION(dbg_save_registers):
245         pushl   %esi
246         pushl   %eax
247         movl    12(%esp), %esi
249         movl    %eax, 0(%esi)
250         movl    %ebx, 4(%esi)
251         movl    %ecx, 8(%esi)
252         movl    %edx, 12(%esi)
254         lea     16(%esp), %eax
255         movl    %eax, 16(%esi)  // caller's %esp
256         movl    %ebp, 20(%esi)
258         movl    4(%esp), %eax
259         movl    %eax, 24(%esi)  // caller's %esi
260         movl    %edi, 28(%esi)
262         movl    8(%esp), %eax
263         movl    %eax, 32(%esi)  // caller's %ebp
266         pushfl
267         popl    %eax
268         mov     %eax, 36(%esi)
270         movl    %cs, 40(%esi)
271         movl    %ss, 44(%esi)
272         movl    %ds, 48(%esi)
273         movl    %es, 52(%esi)
275         popl    %eax
276         popl    %esi
277         ret