Back to home page

Quest Cross Reference

 
 

    


0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "arch/i386.h"
0019 #include "kernel.h"
0020 #include "smp/spinlock.h"
0021 #include "util/printf.h"
0022 #include "util/screen.h"
0023 #include "util/debug.h"
0024 #include "mem/virtual.h"
0025 #include "mem/physical.h"
0026 #include "sched/sched.h"
0027 
0028 static spinlock kernel_lock ALIGNED(LOCK_ALIGNMENT) = SPINLOCK_INIT;
0029 
0030 /* Declare space for a stack */
0031 uint32 ul_stack[NR_MODS][1024] ALIGNED (0x1000);
0032 
0033 /* Declare space for a task state segment */
0034 uint32 ul_tss[NR_MODS][1024] ALIGNED (0x1000);
0035 
0036 /* Declare space for a page directory */
0037 uint32 pg_dir[NR_MODS][1024] ALIGNED (0x1000);
0038 
0039 /* Declare space for a page table */
0040 uint32 pg_table[NR_MODS][1024] ALIGNED (0x1000);
0041 
0042 /* Declare space for per process kernel stack */
0043 uint32 kl_stack[NR_MODS][1024] ALIGNED (0x1000);
0044 
0045 /* Declare space for a page table mappings for kernel stacks */
0046 uint32 kls_pg_table[NR_MODS][1024] ALIGNED (0x1000);
0047 
0048 /* Each CPU gets an IDLE task -- something to do when nothing else */
0049 quest_tss idleTSS[MAX_CPUS];
0050 uint16 idleTSS_selector[MAX_CPUS];
0051 
0052 /* Each CPU gets a CPU TSS for sw task switching */
0053 tss cpuTSS[MAX_CPUS];
0054 uint16 cpuTSS_selector[MAX_CPUS];
0055 
0056 char *pchVideo = (char *) KERN_SCR;
0057 
0058 /* PANIC!!!!! */
0059 void panic (char *sz)
0060 {
0061   print ("kernel panic: ");
0062   print (sz);
0063 
0064   cli ();
0065   hlt ();
0066 }
0067 
0068 /* Global kernel lock */
0069 void
0070 lock_kernel (void)
0071 {
0072   spinlock_lock (&kernel_lock);
0073 }
0074 
0075 void
0076 unlock_kernel (void)
0077 {
0078   spinlock_unlock (&kernel_lock);
0079 }
0080 
0081 /* Retrieve the pointer to the TSS structure for the task by
0082  * reconstructing it from the GDT descriptor entry. */
0083 extern quest_tss *
0084 lookup_TSS (uint16 selector)
0085 {
0086 
0087   descriptor *ad = (descriptor *) KERN_GDT;
0088 
0089   return (quest_tss *) (ad[selector >> 3].pBase0 |
0090                         (ad[selector >> 3].pBase1 << 16) |
0091                         (ad[selector >> 3].pBase2 << 24));
0092 }
0093 
0094 extern void *
0095 lookup_GDT_selector (uint16 selector)
0096 {
0097 
0098   descriptor *ad = (descriptor *) KERN_GDT;
0099 
0100   return (void *) (ad[selector >> 3].pBase0 |
0101                    (ad[selector >> 3].pBase1 << 16) |
0102                    (ad[selector >> 3].pBase2 << 24));
0103 }
0104 
0105 extern void
0106 get_GDT_descriptor (uint16 selector, descriptor *ad)
0107 {
0108   *ad = ((descriptor *) KERN_GDT)[selector >> 3];
0109 }
0110 
0111 /* Idle loop for CPU IDLE task */
0112 void
0113 idle_task (void)
0114 {
0115   unlock_kernel ();
0116   sti ();                       /* when we initially jump here, IF=0 */
0117   for (;;) {
0118     asm volatile ("pause");
0119   }
0120 }
0121 
0122 /* Mask out every IDT entry. */
0123 void
0124 disable_idt (void)
0125 {
0126   uint16 len = KERN_IDT_LEN;
0127   idt_descriptor *ptr = (idt_descriptor *) KERN_IDT;
0128   uint16 i;
0129 
0130   for (i = 0; i < (len >> 3); i++) {
0131     if (ptr[i].pBase0)
0132       ptr[i].fPresent = 0;
0133   }
0134 }
0135 
0136 /* Unmask every valid IDT entry. */
0137 void
0138 enable_idt (void)
0139 {
0140   uint16 len = KERN_IDT_LEN;
0141   idt_descriptor *ptr = (idt_descriptor *) KERN_IDT;
0142   uint16 i;
0143 
0144   for (i = 0; i < (len >> 3); i++) {
0145     if (ptr[i].pBase0)
0146       ptr[i].fPresent = 1;
0147   }
0148 }
0149 
0150 /* Unmask an IDT entry. */
0151 void
0152 enable_idt_entry (uint16 i)
0153 {
0154   idt_descriptor *ptr = (idt_descriptor *) KERN_IDT;
0155   if (ptr[i].pBase0)
0156     ptr[i].fPresent = 1;
0157 }
0158 
0159 /* Setup an IDT entry given the address of a function and an
0160  * appropriate descriptor privilege level. */
0161 void
0162 set_idt_descriptor_by_addr (uint8 n, void *addr, uint8 dpl)
0163 {
0164   idt_descriptor *ptr = (idt_descriptor *) KERN_IDT;
0165 
0166   ptr[n].fPresent = 0;          /* disable */
0167   ptr[n].pBase1 = ((uint32) addr & 0xFFFF0000) >> 16;
0168   ptr[n].pBase0 = ((uint32) addr & 0x0000FFFF);
0169   ptr[n].pSeg = 0x08;
0170   ptr[n].fZero0 = 0;
0171   ptr[n].fZero1 = 0;
0172   ptr[n].fReserved = 0;
0173   ptr[n].fType = 0x6;
0174   ptr[n].f32bit = 1;
0175   ptr[n].uDPL = dpl;
0176   ptr[n].fPresent = 1;          /* re-enable */
0177 }
0178 
0179 /* Read an IDT entry into the pointer. */
0180 void
0181 get_idt_descriptor (uint8 n, idt_descriptor * d)
0182 {
0183   idt_descriptor *ptr = (idt_descriptor *) KERN_IDT;
0184 
0185   *d = ptr[n];
0186 }
0187 
0188 /* Write an IDT entry from a given entry. */
0189 void
0190 set_idt_descriptor (uint8 n, idt_descriptor * d)
0191 {
0192   idt_descriptor *ptr = (idt_descriptor *) KERN_IDT;
0193 
0194   ptr[n] = *d;
0195 }
0196 
0197 static bool kernel_threads_running = FALSE;
0198 static task_id kernel_thread_waitq = 0;
0199 
0200 task_id
0201 create_kernel_thread_args (uint eip, uint esp, bool run, uint n, ...)
0202 {
0203   task_id pid;
0204   uint32 eflags;
0205   extern u32 *pgd;              /* original page-global dir */
0206   void *page_dir = &pgd;
0207   uint *stack, i;
0208   va_list args;
0209 
0210   asm volatile ("pushfl\n" "pop %0\n":"=r" (eflags):);
0211 
0212   esp -= sizeof (void *) * (n + 1);
0213   stack = (uint *) esp;
0214 
0215   /* place arguments on the stack (i386-specific) */
0216   va_start (args, n);
0217   for (i=0; i<n; i++)
0218     stack[i+1] = va_arg (args, uint);
0219   va_end (args);
0220 
0221   stack[0] = (uint) exit_kernel_thread; /* set return address */
0222 
0223   /* start kernel thread */
0224   pid = duplicate_TSS (0, NULL,
0225                        eip, 0, esp,
0226                        eflags, (uint32) page_dir);
0227 
0228   lookup_TSS (pid)->priority = 0x1f;
0229 
0230   if (run) {
0231     if (kernel_threads_running)
0232       wakeup (pid);
0233     else
0234       queue_append (&kernel_thread_waitq, pid);
0235   }
0236 
0237   return pid;
0238 }
0239 
0240 task_id
0241 start_kernel_thread (uint eip, uint esp)
0242 {
0243   return create_kernel_thread_args (eip, esp, TRUE, 0);
0244 }
0245 
0246 void
0247 begin_kernel_threads (void)
0248 {
0249   if (kernel_threads_running == FALSE) {
0250     wakeup_queue (&kernel_thread_waitq);
0251     kernel_threads_running = TRUE;
0252   }
0253 }
0254 
0255 void
0256 exit_kernel_thread (void)
0257 {
0258   uint8 LAPIC_get_physical_ID (void);
0259   quest_tss *tss;
0260   uint tss_frame;
0261   task_id waiter;
0262 
0263   for (;;)
0264     sched_usleep (1000000);
0265 
0266   tss = lookup_TSS (str ());
0267   tss_frame = (uint) get_phys_addr (tss);
0268 
0269   /* All tasks waiting for us now belong on the runqueue. */
0270   while ((waiter = queue_remove_head (&tss->waitqueue)))
0271     wakeup (waiter);
0272 
0273   /* clean up TSS memory */
0274   memset (tss, 0, sizeof (quest_tss));
0275   unmap_virtual_page (tss);
0276   free_phys_frame (tss_frame);
0277 
0278   /* clear current task */
0279   ltr (0);
0280 
0281   schedule ();
0282 
0283   panic ("exit_kernel_thread: unreachable");
0284 }
0285 
0286 /*
0287  * Local Variables:
0288  * indent-tabs-mode: nil
0289  * mode: C
0290  * c-file-style: "gnu"
0291  * c-basic-offset: 2
0292  * End:
0293  */
0294 
0295 /* vi: set et sw=2 sts=2: */