1
2
3
4
5
6
7
8
9
10
11
12
13
14#define __KERNEL_SYSCALLS__
15#include <stdarg.h>
16
17#include <linux/errno.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/smp.h>
22#include <linux/smp_lock.h>
23#include <linux/stddef.h>
24#include <linux/unistd.h>
25#include <linux/ptrace.h>
26#include <linux/slab.h>
27#include <linux/vmalloc.h>
28#include <linux/user.h>
29#include <linux/a.out.h>
30#include <linux/interrupt.h>
31#include <linux/config.h>
32#include <linux/delay.h>
33#include <linux/reboot.h>
34#include <linux/init.h>
35#include <linux/mc146818rtc.h>
36
37#include <asm/uaccess.h>
38#include <asm/pgtable.h>
39#include <asm/system.h>
40#include <asm/io.h>
41#include <asm/ldt.h>
42#include <asm/processor.h>
43#include <asm/i387.h>
44#include <asm/irq.h>
45#include <asm/desc.h>
46#include <asm/mmu_context.h>
47#ifdef CONFIG_MATH_EMULATION
48#include <asm/math_emu.h>
49#endif
50
51#include <linux/irq.h>
52
53asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
54
55int hlt_counter;
56
57
58
59
60void (*pm_idle)(void);
61
62
63
64
65void (*pm_power_off)(void);
66
67void disable_hlt(void)
68{
69 hlt_counter++;
70}
71
72void enable_hlt(void)
73{
74 hlt_counter--;
75}
76
77
78
79
80
81void default_idle(void)
82{
83 if (current_cpu_data.hlt_works_ok && !hlt_counter) {
84 __cli();
85 if (!current->need_resched)
86 safe_halt();
87 else
88 __sti();
89 }
90}
91
92
93
94
95
96
97static void poll_idle (void)
98{
99 int oldval;
100
101 __sti();
102
103
104
105
106
107 oldval = xchg(¤t->need_resched, -1);
108
109 if (!oldval)
110 asm volatile(
111 "2:"
112 "cmpl $-1, %0;"
113 "rep; nop;"
114 "je 2b;"
115 : :"m" (current->need_resched));
116}
117
118
119
120
121
122
123
124void cpu_idle (void)
125{
126
127 init_idle();
128 current->nice = 20;
129 current->counter = -100;
130
131 while (1) {
132 void (*idle)(void) = pm_idle;
133 if (!idle)
134 idle = default_idle;
135 while (!current->need_resched)
136 idle();
137 schedule();
138 check_pgt_cache();
139 }
140}
141
142static int __init idle_setup (char *str)
143{
144 if (!strncmp(str, "poll", 4)) {
145 printk("using polling idle threads.\n");
146 pm_idle = poll_idle;
147 }
148
149 return 1;
150}
151
152__setup("idle=", idle_setup);
153
154static long no_idt[2];
155static int reboot_mode;
156int reboot_thru_bios;
157
158#ifdef CONFIG_SMP
159int reboot_smp = 0;
160static int reboot_cpu = -1;
161
162#define is_digit(c) ((c) >= '0' && (c) <= '9')
163#endif
164static int __init reboot_setup(char *str)
165{
166 while(1) {
167 switch (*str) {
168 case 'w':
169 reboot_mode = 0x1234;
170 break;
171 case 'c':
172 reboot_mode = 0x0;
173 break;
174 case 'b':
175 reboot_thru_bios = 1;
176 break;
177 case 'h':
178 reboot_thru_bios = 0;
179 break;
180#ifdef CONFIG_SMP
181 case 's':
182 reboot_smp = 1;
183 if (is_digit(*(str+1))) {
184 reboot_cpu = (int) (*(str+1) - '0');
185 if (is_digit(*(str+2)))
186 reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
187 }
188
189
190
191 break;
192#endif
193 }
194 if((str = strchr(str,',')) != NULL)
195 str++;
196 else
197 break;
198 }
199 return 1;
200}
201
202__setup("reboot=", reboot_setup);
203
204
205
206
207
208
209
210
211static unsigned long long
212real_mode_gdt_entries [3] =
213{
214 0x0000000000000000ULL,
215 0x00009a000000ffffULL,
216 0x000092000100ffffULL
217};
218
219static struct
220{
221 unsigned short size __attribute__ ((packed));
222 unsigned long long * base __attribute__ ((packed));
223}
224real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
225real_mode_idt = { 0x3ff, 0 };
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246static unsigned char real_mode_switch [] =
247{
248 0x66, 0x0f, 0x20, 0xc0,
249 0x66, 0x83, 0xe0, 0x11,
250 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,
251 0x66, 0x0f, 0x22, 0xc0,
252 0x66, 0x0f, 0x22, 0xd8,
253 0x66, 0x0f, 0x20, 0xc3,
254 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,
255 0x74, 0x02,
256 0x0f, 0x08,
257 0x24, 0x10,
258 0x66, 0x0f, 0x22, 0xc0
259};
260static unsigned char jump_to_bios [] =
261{
262 0xea, 0x00, 0x00, 0xff, 0xff
263};
264
265static inline void kb_wait(void)
266{
267 int i;
268
269 for (i=0; i<0x10000; i++)
270 if ((inb_p(0x64) & 0x02) == 0)
271 break;
272}
273
274
275
276
277
278
279void machine_real_restart(unsigned char *code, int length)
280{
281 unsigned long flags;
282
283 cli();
284
285
286
287
288
289
290
291
292
293
294
295 spin_lock_irqsave(&rtc_lock, flags);
296 CMOS_WRITE(0x00, 0x8f);
297 spin_unlock_irqrestore(&rtc_lock, flags);
298
299
300
301
302
303 memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
304 sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
305
306
307
308
309 pg0[0] = _PAGE_RW | _PAGE_PRESENT;
310
311
312
313
314 load_cr3(swapper_pg_dir);
315
316
317
318
319
320
321
322 *((unsigned short *)0x472) = reboot_mode;
323
324
325
326
327
328
329
330 memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
331 real_mode_switch, sizeof (real_mode_switch));
332 memcpy ((void *) (0x1000 - 100), code, length);
333
334
335
336 __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
337
338
339
340
341
342 __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
343
344
345
346
347
348
349
350 __asm__ __volatile__ ("movl $0x0010,%%eax\n"
351 "\tmovl %%eax,%%ds\n"
352 "\tmovl %%eax,%%es\n"
353 "\tmovl %%eax,%%fs\n"
354 "\tmovl %%eax,%%gs\n"
355 "\tmovl %%eax,%%ss" : : : "eax");
356
357
358
359
360
361 __asm__ __volatile__ ("ljmp $0x0008,%0"
362 :
363 : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
364}
365
366void machine_restart(char * __unused)
367{
368#if CONFIG_SMP
369 int cpuid;
370
371 cpuid = GET_APIC_ID(apic_read(APIC_ID));
372
373 if (reboot_smp) {
374
375
376
377 if ((reboot_cpu == -1) ||
378 (reboot_cpu > (NR_CPUS -1)) ||
379 !(phys_cpu_present_map & (1<<cpuid)))
380 reboot_cpu = boot_cpu_physical_apicid;
381
382 reboot_smp = 0;
383
384
385
386
387 if (reboot_cpu != cpuid)
388 smp_call_function((void *)machine_restart , NULL, 1, 0);
389 }
390
391
392
393 if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
394 for (;;)
395 __asm__ __volatile__ ("hlt");
396 }
397
398
399
400
401 smp_send_stop();
402 disable_IO_APIC();
403#endif
404
405 if(!reboot_thru_bios) {
406
407 *((unsigned short *)__va(0x472)) = reboot_mode;
408 for (;;) {
409 int i;
410 for (i=0; i<100; i++) {
411 kb_wait();
412 udelay(50);
413 outb(0xfe,0x64);
414 udelay(50);
415 }
416
417 __asm__ __volatile__("lidt %0": :"m" (no_idt));
418 __asm__ __volatile__("int3");
419 }
420 }
421
422 machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
423}
424
425void machine_halt(void)
426{
427}
428
429void machine_power_off(void)
430{
431 if (pm_power_off)
432 pm_power_off();
433}
434
435extern void show_trace(unsigned long* esp);
436
437void show_regs(struct pt_regs * regs)
438{
439 unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
440
441 printk("\n");
442 printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
443 printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
444 if (regs->xcs & 3)
445 printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
446 printk(" EFLAGS: %08lx %s\n",regs->eflags, print_tainted());
447 printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
448 regs->eax,regs->ebx,regs->ecx,regs->edx);
449 printk("ESI: %08lx EDI: %08lx EBP: %08lx",
450 regs->esi, regs->edi, regs->ebp);
451 printk(" DS: %04x ES: %04x\n",
452 0xffff & regs->xds,0xffff & regs->xes);
453
454 __asm__("movl %%cr0, %0": "=r" (cr0));
455 __asm__("movl %%cr2, %0": "=r" (cr2));
456 __asm__("movl %%cr3, %0": "=r" (cr3));
457
458 __asm__("1: movl %%cr4, %0 \n"
459 "2: \n"
460 ".section __ex_table,\"a\" \n"
461 ".long 1b,2b \n"
462 ".previous \n"
463 : "=r" (cr4): "0" (0));
464 printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
465 show_trace(®s->esp);
466}
467
468
469
470
471void release_segments(struct mm_struct *mm)
472{
473 void * ldt = mm->context.segments;
474
475
476
477
478 if (ldt) {
479 mm->context.segments = NULL;
480 clear_LDT();
481 vfree(ldt);
482 }
483}
484
485
486
487
488int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
489{
490 long retval, d0;
491
492 __asm__ __volatile__(
493 "movl %%esp,%%esi\n\t"
494 "int $0x80\n\t"
495 "cmpl %%esp,%%esi\n\t"
496 "je 1f\n\t"
497
498
499
500 "movl %4,%%eax\n\t"
501 "pushl %%eax\n\t"
502 "call *%5\n\t"
503 "movl %3,%0\n\t"
504 "int $0x80\n"
505 "1:\t"
506 :"=&a" (retval), "=&S" (d0)
507 :"0" (__NR_clone), "i" (__NR_exit),
508 "r" (arg), "r" (fn),
509 "b" (flags | CLONE_VM)
510 : "memory");
511
512 return retval;
513}
514
515
516
517
518void exit_thread(void)
519{
520
521}
522
523void flush_thread(void)
524{
525 struct task_struct *tsk = current;
526
527 memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
528
529
530
531 clear_fpu(tsk);
532 tsk->used_math = 0;
533}
534
535void release_thread(struct task_struct *dead_task)
536{
537 if (dead_task->mm) {
538 void * ldt = dead_task->mm->context.segments;
539
540
541 if (ldt) {
542 printk("WARNING: dead process %8s still has LDT? <%p>\n",
543 dead_task->comm, ldt);
544 BUG();
545 }
546 }
547
548 release_x86_irqs(dead_task);
549}
550
551
552
553
554
555void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
556{
557 struct mm_struct * old_mm;
558 void *old_ldt, *ldt;
559
560 ldt = NULL;
561 old_mm = current->mm;
562 if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
563
564
565
566 ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
567 if (!ldt)
568 printk(KERN_WARNING "ldt allocation failed\n");
569 else
570 memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
571 }
572 new_mm->context.segments = ldt;
573 new_mm->context.cpuvalid = ~0UL;
574}
575
576
577
578
579#define savesegment(seg,value) \
580 asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
581
582int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
583 unsigned long unused,
584 struct task_struct * p, struct pt_regs * regs)
585{
586 struct pt_regs * childregs;
587
588 childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
589 struct_cpy(childregs, regs);
590 childregs->eax = 0;
591 childregs->esp = esp;
592
593 p->thread.esp = (unsigned long) childregs;
594 p->thread.esp0 = (unsigned long) (childregs+1);
595
596 p->thread.eip = (unsigned long) ret_from_fork;
597
598 savesegment(fs,p->thread.fs);
599 savesegment(gs,p->thread.gs);
600
601 unlazy_fpu(current);
602 struct_cpy(&p->thread.i387, ¤t->thread.i387);
603
604 return 0;
605}
606
607
608
609
610void dump_thread(struct pt_regs * regs, struct user * dump)
611{
612 int i;
613
614
615 dump->magic = CMAGIC;
616 dump->start_code = 0;
617 dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
618 dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
619 dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
620 dump->u_dsize -= dump->u_tsize;
621 dump->u_ssize = 0;
622 for (i = 0; i < 8; i++)
623 dump->u_debugreg[i] = current->thread.debugreg[i];
624
625 if (dump->start_stack < TASK_SIZE)
626 dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
627
628 dump->regs.ebx = regs->ebx;
629 dump->regs.ecx = regs->ecx;
630 dump->regs.edx = regs->edx;
631 dump->regs.esi = regs->esi;
632 dump->regs.edi = regs->edi;
633 dump->regs.ebp = regs->ebp;
634 dump->regs.eax = regs->eax;
635 dump->regs.ds = regs->xds;
636 dump->regs.es = regs->xes;
637 savesegment(fs,dump->regs.fs);
638 savesegment(gs,dump->regs.gs);
639 dump->regs.orig_eax = regs->orig_eax;
640 dump->regs.eip = regs->eip;
641 dump->regs.cs = regs->xcs;
642 dump->regs.eflags = regs->eflags;
643 dump->regs.esp = regs->esp;
644 dump->regs.ss = regs->xss;
645
646 dump->u_fpvalid = dump_fpu (regs, &dump->i387);
647}
648
649
650
651
652#define loaddebug(thread,register) \
653 __asm__("movl %0,%%db" #register \
654 : \
655 :"r" (thread->debugreg[register]))
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
681{
682 struct thread_struct *prev = &prev_p->thread,
683 *next = &next_p->thread;
684 struct tss_struct *tss = init_tss + smp_processor_id();
685
686 unlazy_fpu(prev_p);
687
688
689
690
691 tss->esp0 = next->esp0;
692
693
694
695
696
697 asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
698 asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
699
700
701
702
703 loadsegment(fs, next->fs);
704 loadsegment(gs, next->gs);
705
706
707
708
709 if (next->debugreg[7]){
710 loaddebug(next, 0);
711 loaddebug(next, 1);
712 loaddebug(next, 2);
713 loaddebug(next, 3);
714
715 loaddebug(next, 6);
716 loaddebug(next, 7);
717 }
718
719 if (prev->ioperm || next->ioperm) {
720 if (next->ioperm) {
721
722
723
724
725
726
727
728
729 memcpy(tss->io_bitmap, next->io_bitmap,
730 IO_BITMAP_BYTES);
731 tss->bitmap = IO_BITMAP_OFFSET;
732 } else
733
734
735
736
737
738
739 tss->bitmap = INVALID_IO_BITMAP_OFFSET;
740 }
741}
742
743asmlinkage int sys_fork(struct pt_regs regs)
744{
745 return do_fork(SIGCHLD, regs.esp, ®s, 0);
746}
747
748asmlinkage int sys_clone(struct pt_regs regs)
749{
750 unsigned long clone_flags;
751 unsigned long newsp;
752
753 clone_flags = regs.ebx;
754 newsp = regs.ecx;
755 if (!newsp)
756 newsp = regs.esp;
757 return do_fork(clone_flags, newsp, ®s, 0);
758}
759
760
761
762
763
764
765
766
767
768
769
770asmlinkage int sys_vfork(struct pt_regs regs)
771{
772 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0);
773}
774
775
776
777
778asmlinkage int sys_execve(struct pt_regs regs)
779{
780 int error;
781 char * filename;
782
783 filename = getname((char *) regs.ebx);
784 error = PTR_ERR(filename);
785 if (IS_ERR(filename))
786 goto out;
787 error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s);
788 if (error == 0)
789 current->ptrace &= ~PT_DTRACE;
790 putname(filename);
791out:
792 return error;
793}
794
795
796
797
798extern void scheduling_functions_start_here(void);
799extern void scheduling_functions_end_here(void);
800#define first_sched ((unsigned long) scheduling_functions_start_here)
801#define last_sched ((unsigned long) scheduling_functions_end_here)
802
803unsigned long get_wchan(struct task_struct *p)
804{
805 unsigned long ebp, esp, eip;
806 unsigned long stack_page;
807 int count = 0;
808 if (!p || p == current || p->state == TASK_RUNNING)
809 return 0;
810 stack_page = (unsigned long)p;
811 esp = p->thread.esp;
812 if (!stack_page || esp < stack_page || esp > 8188+stack_page)
813 return 0;
814
815 ebp = *(unsigned long *) esp;
816 do {
817 if (ebp < stack_page || ebp > 8184+stack_page)
818 return 0;
819 eip = *(unsigned long *) (ebp+4);
820 if (eip < first_sched || eip >= last_sched)
821 return eip;
822 ebp = *(unsigned long *) ebp;
823 } while (count++ < 16);
824 return 0;
825}
826#undef last_sched
827#undef first_sched
828