⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 process.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/arch/i386/kernel/process.c * *  Copyright (C) 1995  Linus Torvalds * *  Pentium III FXSR, SSE support *	Gareth Hughes <gareth@valinux.com>, May 2000 *//* * This file handles the architecture-dependent parts of process handling.. */#define __KERNEL_SYSCALLS__#include <stdarg.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/user.h>#include <linux/a.out.h>#include <linux/interrupt.h>#include <linux/config.h>#include <linux/delay.h>#include <linux/reboot.h>#include <linux/init.h>#include <linux/mc146818rtc.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/io.h>#include <asm/ldt.h>#include <asm/processor.h>#include <asm/i387.h>#include <asm/desc.h>#ifdef CONFIG_MATH_EMULATION#include <asm/math_emu.h>#endif#include <linux/irq.h>#include <linux/err.h>asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");int hlt_counter;/* * Return saved PC of a blocked thread. */unsigned long thread_saved_pc(struct task_struct *tsk){	return ((unsigned long *)tsk->thread.esp)[3];}/* * Powermanagement idle function, if any.. */void (*pm_idle)(void);/* * Power off function, if any */void (*pm_power_off)(void);void disable_hlt(void){	hlt_counter++;}void enable_hlt(void){	hlt_counter--;}/* * We use this if we don't have any better * idle routine.. */void default_idle(void){	if (current_cpu_data.hlt_works_ok && !hlt_counter) {		__cli();		if (!need_resched())			safe_halt();		else			__sti();	}}/* * On SMP it's slightly faster (but much more power-consuming!) * to poll the ->work.need_resched flag instead of waiting for the * cross-CPU IPI to arrive. Use this option with caution. */static void poll_idle (void){	int oldval;	__sti();	/*	 * Deal with another CPU just having chosen a thread to	 * run here:	 */	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);	if (!oldval) {		set_thread_flag(TIF_POLLING_NRFLAG);		asm volatile(			"2:"			"testl %0, %1;"			"rep; nop;"			"je 2b;"			: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));		clear_thread_flag(TIF_POLLING_NRFLAG);	} else {		set_need_resched();	}}/* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a * low exit latency (ie sit in a loop waiting for * somebody to say that they'd like to reschedule) */void cpu_idle (void){	/* endless idle loop with no priority at all */	while (1) {		void (*idle)(void) = pm_idle;		if (!idle)			idle = default_idle;		irq_stat[smp_processor_id()].idle_timestamp = jiffies;		while (!need_resched())			idle();		schedule();	}}static int __init idle_setup (char *str){	if (!strncmp(str, "poll", 4)) {		printk("using polling idle threads.\n");		pm_idle = poll_idle;	}	return 1;}__setup("idle=", idle_setup);static long no_idt[2];static int reboot_mode;int reboot_thru_bios;#ifdef CONFIG_SMPint reboot_smp = 0;static int reboot_cpu = -1;/* shamelessly grabbed from lib/vsprintf.c for readability */#define is_digit(c)	((c) >= '0' && (c) <= '9')#endifstatic int __init reboot_setup(char *str){	while(1) {		switch (*str) {		case 'w': /* "warm" reboot (no memory testing etc) */			reboot_mode = 0x1234;			break;		case 'c': /* "cold" reboot (with memory testing etc) */			reboot_mode = 0x0;			break;		case 'b': /* "bios" reboot by jumping through the BIOS */			reboot_thru_bios = 1;			break;		case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */			reboot_thru_bios = 0;			break;#ifdef CONFIG_SMP		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/			reboot_smp = 1;			if (is_digit(*(str+1))) {				reboot_cpu = (int) (*(str+1) - '0');				if (is_digit(*(str+2))) 					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');			}				/* we will leave sorting out the final value 				when we are ready to reboot, since we might not 				have set up boot_cpu_id or smp_num_cpu */			break;#endif		}		if((str = strchr(str,',')) != NULL)			str++;		else			break;	}	return 1;}__setup("reboot=", reboot_setup);/* The following code and data reboots the machine by switching to real   mode and jumping to the BIOS reset entry point, as if the CPU has   really been reset.  The previous version asked the keyboard   controller to pulse the CPU reset line, which is more thorough, but   doesn't work with at least one type of 486 motherboard.  It is easy   to stop this code working; hence the copious comments. */static unsigned long longreal_mode_gdt_entries [3] ={	0x0000000000000000ULL,	/* Null descriptor */	0x00009a000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */	0x000092000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */};static struct{	unsigned short       size __attribute__ ((packed));	unsigned long long * base __attribute__ ((packed));}real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },real_mode_idt = { 0x3ff, 0 };/* This is 16-bit protected mode code to disable paging and the cache,   switch to real mode and jump to the BIOS reset code.   The instruction that switches to real mode by writing to CR0 must be   followed immediately by a far jump instruction, which set CS to a   valid value for real mode, and flushes the prefetch queue to avoid   running instructions that have already been decoded in protected   mode.   Clears all the flags except ET, especially PG (paging), PE   (protected-mode enable) and TS (task switch for coprocessor state   save).  Flushes the TLB after paging has been disabled.  Sets CD and   NW, to disable the cache on a 486, and invalidates the cache.  This   is more like the state of a 486 after reset.  I don't know if   something else should be done for other chips.   More could be done here to set up the registers as if a CPU reset had   occurred; hopefully real BIOSs don't assume much. */static unsigned char real_mode_switch [] ={	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,	/*    orl   $0x60000000,%eax */	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */	0x74, 0x02,				/*    jz    f                */	0x0f, 0x08,				/*    invd                   */	0x24, 0x10,				/* f: andb  $0x10,al         */	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */};static unsigned char jump_to_bios [] ={	0xea, 0x00, 0x00, 0xff, 0xff		/*    ljmp  $0xffff,$0x0000  */};static inline void kb_wait(void){	int i;	for (i=0; i<0x10000; i++)		if ((inb_p(0x64) & 0x02) == 0)			break;}/* * Switch to real mode and then execute the code * specified by the code and length parameters. * We assume that length will aways be less that 100! */void machine_real_restart(unsigned char *code, int length){	unsigned long flags;	cli();	/* Write zero to CMOS register number 0x0f, which the BIOS POST	   routine will recognize as telling it to do a proper reboot.  (Well	   that's what this book in front of me says -- it may only apply to	   the Phoenix BIOS though, it's not clear).  At the same time,	   disable NMIs by setting the top bit in the CMOS address register,	   as we're about to do peculiar things to the CPU.  I'm not sure if	   `outb_p' is needed instead of just `outb'.  Use it to be on the	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)	 */	spin_lock_irqsave(&rtc_lock, flags);	CMOS_WRITE(0x00, 0x8f);	spin_unlock_irqrestore(&rtc_lock, flags);	/* Remap the kernel at virtual address zero, as well as offset zero	   from the kernel segment.  This assumes the kernel segment starts at	   virtual address PAGE_OFFSET. */	memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,		sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);	/* Make sure the first page is mapped to the start of physical memory.	   It is normally not mapped, to trap kernel NULL pointer dereferences. */	pg0[0] = _PAGE_RW | _PAGE_PRESENT;	/*	 * Use `swapper_pg_dir' as our page directory.	 */	asm volatile("movl %0,%%cr3": :"r" (__pa(swapper_pg_dir)));	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads	   this on booting to tell it to "Bypass memory test (also warm	   boot)".  This seems like a fairly standard thing that gets set by	   REBOOT.COM programs, and the previous reset routine did this	   too. */	*((unsigned short *)0x472) = reboot_mode;	/* For the switch to real mode, copy some code to low memory.  It has	   to be in the first 64k because it is running in 16-bit mode, and it	   has to have the same physical and virtual address, because it turns	   off paging.  Copy it near the end of the first page, out of the way	   of BIOS variables. */	memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),		real_mode_switch, sizeof (real_mode_switch));	memcpy ((void *) (0x1000 - 100), code, length);	/* Set up the IDT for real mode. */	__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));	/* Set up a GDT from which we can load segment descriptors for real	   mode.  The GDT is not used in real mode; it is just needed here to	   prepare the descriptors. */	__asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));	/* Load the data segment registers, and thus the descriptors ready for	   real mode.  The base address of each segment is 0x100, 16 times the	   selector value being loaded here.  This is so that the segment	   registers don't have to be reloaded after switching to real mode:	   the values are consistent for real mode operation already. */	__asm__ __volatile__ ("movl $0x0010,%%eax\n"				"\tmovl %%eax,%%ds\n"				"\tmovl %%eax,%%es\n"				"\tmovl %%eax,%%fs\n"				"\tmovl %%eax,%%gs\n"				"\tmovl %%eax,%%ss" : : : "eax");	/* Jump to the 16-bit code that we copied earlier.  It disables paging	   and the cache, switches to real mode, and jumps to the BIOS reset	   entry point. */	__asm__ __volatile__ ("ljmp $0x0008,%0"				:				: "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));}void machine_restart(char * __unused){#if CONFIG_SMP	int cpuid;		cpuid = GET_APIC_ID(apic_read(APIC_ID));	if (reboot_smp) {		/* check to see if reboot_cpu is valid 		   if its not, default to the BSP */		if ((reboot_cpu == -1) ||  		      (reboot_cpu > (NR_CPUS -1))  || 		      !(phys_cpu_present_map & (1<<cpuid))) 			reboot_cpu = boot_cpu_physical_apicid;		reboot_smp = 0;  /* use this as a flag to only go through this once*/		/* re-run this function on the other CPUs		   it will fall though this section since we have 		   cleared reboot_smp, and do the reboot if it is the		   correct CPU, otherwise it halts. */		if (reboot_cpu != cpuid)			smp_call_function((void *)machine_restart , NULL, 1, 0);	}	/* if reboot_cpu is still -1, then we want a tradional reboot, 	   and if we are not running on the reboot_cpu,, halt */	if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {		for (;;)		__asm__ __volatile__ ("hlt");	}	/*	 * Stop all CPUs and turn off local APICs and the IO-APIC, so	 * other OSs see a clean IRQ state.	 */	smp_send_stop();	disable_IO_APIC();#endif	if(!reboot_thru_bios) {		/* rebooting needs to touch the page at absolute addr 0 */		*((unsigned short *)__va(0x472)) = reboot_mode;		for (;;) {			int i;			for (i=0; i<100; i++) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -