1 // Code for manipulating stack locations.
3 // Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
7 #include "biosvar.h" // get_ebda_seg
8 #include "util.h" // dprintf
11 /****************************************************************
13 ****************************************************************/
15 // Switch to the extra stack in ebda and call a function.
17 stack_hop(u32 eax, u32 edx, u32 ecx, void *func)
20 u16 ebda_seg = get_ebda_seg(), bkup_ss;
23 // Backup current %ss/%esp values.
26 // Copy ebda seg to %ds/%ss and set %esp
32 // Restore segments and stack
36 : "+a" (eax), "+d" (edx), "+c" (ecx), "=&r" (bkup_ss), "=&r" (bkup_esp)
37 : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg), "m" (*(u8*)func)
43 /****************************************************************
45 ****************************************************************/
47 #define THREADSTACKSIZE 4096
50 struct thread_info *next;
54 struct thread_info MainThread;
59 MainThread.next = &MainThread;
60 MainThread.stackpos = NULL;
67 if (esp <= BUILD_STACK_ADDR)
69 return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE);
72 // Briefly permit irqs to occur.
76 if (MODE16 || !CONFIG_THREADS) {
77 // Just directly check irqs.
81 struct thread_info *cur = getCurThread();
82 if (cur == &MainThread)
83 // Permit irqs to fire
86 // Switch to the next thread
87 struct thread_info *next = cur->next;
89 " pushl $1f\n" // store return pc
90 " pushl %%ebp\n" // backup %ebp
91 " movl %%esp, 4(%%eax)\n" // cur->stackpos = %esp
92 " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos
93 " popl %%ebp\n" // restore %ebp
94 " retl\n" // restore pc
96 : "+a"(cur), "+c"(next)
98 : "ebx", "edx", "esi", "edi", "cc", "memory");
101 // Last thing called from a thread (called on "next" stack).
103 __end_thread(struct thread_info *old)
105 struct thread_info *pos = &MainThread;
106 while (pos->next != old)
108 pos->next = old->next;
110 dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old);
114 run_thread(void (*func)(void*), void *data)
117 if (! CONFIG_THREADS)
119 struct thread_info *thread;
120 thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE);
124 thread->stackpos = (void*)thread + THREADSTACKSIZE;
125 struct thread_info *cur = getCurThread();
126 thread->next = cur->next;
129 dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread);
132 " pushl $1f\n" // store return pc
133 " pushl %%ebp\n" // backup %ebp
134 " movl %%esp, 4(%%edx)\n" // cur->stackpos = %esp
135 " movl 4(%%ebx), %%esp\n" // %esp = thread->stackpos
136 " calll *%%ecx\n" // Call func
139 " movl (%%ebx), %%ecx\n" // %ecx = thread->next
140 " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos
141 " movl %%ebx, %%eax\n"
142 " calll %4\n" // call __end_thread(thread)
143 " popl %%ebp\n" // restore %ebp
144 " retl\n" // restore pc
146 : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur)
147 : "m"(*(u8*)__end_thread)
148 : "esi", "edi", "cc", "memory");
159 if (! CONFIG_THREADS)
161 while (MainThread.next != &MainThread)