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

📄 prom.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			    unsigned int va, unsigned int pa, int mode){	unsigned int *pteg;	unsigned int hash, i;	hash = ((va >> 5) ^ (va >> 21)) & 0x7fff80;	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));	for (i = 0; i < 8; ++i, pteg += 4) {		if ((pteg[1] & 1) == 0) {			pteg[1] = ((va >> 16) & 0xff80) | 1;			pteg[3] = pa | mode;			break;		}	}}extern unsigned long _SDR1;extern PTE *Hash;extern unsigned long Hash_size;voidprom_alloc_htab(void){	unsigned int hsize;	unsigned long htab;	unsigned int addr;	unsigned long offset = reloc_offset();	/*	 * Because of OF bugs we can't use the "claim" client	 * interface to allocate memory for the hash table.	 * This code is only used on 64-bit PPCs, and the only	 * 64-bit PPCs at the moment are RS/6000s, and their	 * OF is based at 0xc00000 (the 12M point), so we just	 * arbitrarily use the 0x800000 - 0xc00000 region for the	 * hash table.	 *  -- paulus.	 */#ifdef CONFIG_POWER4	hsize = 4 << 20;	/* POWER4 has no BATs */#else	hsize = 2 << 20;#endif /* CONFIG_POWER4 */	htab = (8 << 20);	RELOC(Hash) = (void *)(htab + KERNELBASE);	RELOC(Hash_size) = hsize;	RELOC(_SDR1) = htab + __ilog2(hsize) - 18;	/*	 * Put in PTEs for the first 64MB of RAM	 */	cacheable_memzero((void *)htab, hsize);	for (addr = 0; addr < 0x4000000; addr += 0x1000)		make_pte(htab, hsize, addr + KERNELBASE, addr,			 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);}#endif /* CONFIG_PPC64BRIDGE */static __init voidprom_instantiate_rtas(void){	ihandle prom_rtas;	unsigned int i;	struct prom_args prom_args;	unsigned long offset = reloc_offset();	prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));	if (prom_rtas == (void *) -1)		return;	RELOC(rtas_size) = 0;	call_prom(RELOC("getprop"), 4, 1, prom_rtas,		  RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size));	prom_print(RELOC("instantiating rtas"));	if (RELOC(rtas_size) == 0) {		RELOC(rtas_data) = 0;	} else {		/*		 * Ask OF for some space for RTAS.		 * Actually OF has bugs so we just arbitrarily		 * use memory at the 6MB point.		 */		RELOC(rtas_data) = 6 << 20;		prom_print(RELOC(" at "));		prom_print_hex(RELOC(rtas_data));	}	prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));	prom_print(RELOC("..."));	prom_args.service = RELOC("call-method");	prom_args.nargs = 3;	prom_args.nret = 2;	prom_args.args[0] = RELOC("instantiate-rtas");	prom_args.args[1] = prom_rtas;	prom_args.args[2] = (void *) RELOC(rtas_data);	RELOC(prom)(&prom_args);	i = 0;	if (prom_args.args[3] == 0)		i = (unsigned int)prom_args.args[4];	RELOC(rtas_entry) = i;	if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0))		prom_print(RELOC(" failed\n"));	else		prom_print(RELOC(" done\n"));}/* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */__initunsigned longprom_init(int r3, int r4, prom_entry pp){	int chrp = 0;	unsigned long mem;	ihandle prom_mmu, prom_op;	unsigned long offset = reloc_offset();	int l;	char *p, *d;	int prom_version = 0; 	unsigned long phys; 	/* Default */ 	phys = offset + KERNELBASE;	/* check if we're apus, return if we are */	if ( r3 == 0x61707573 )		return phys;	/* If we came here from BootX, clear the screen,	 * set up some pointers and return. */	if (r3 == 0x426f6f58 && pp == NULL) {		bootx_init(r4, phys);		return phys;	}	/* check if we're prep, return if we are */	if ( *(unsigned long *)(0) == 0xdeadc0de )		return phys;	/* First get a handle for the stdout device */	RELOC(prom) = pp;	RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1,				       RELOC("/chosen"));	if (RELOC(prom_chosen) == (void *)-1)		prom_exit();	if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),			    RELOC("stdout"), &RELOC(prom_stdout),			    sizeof(prom_stdout)) <= 0)		prom_exit();	/* Get the full OF pathname of the stdout device */	mem = (unsigned long) RELOC(klimit) + offset;	p = (char *) mem;	memset(p, 0, 256);	call_prom(RELOC("instance-to-path"), 3, 1, RELOC(prom_stdout), p, 255);	RELOC(of_stdout_device) = PTRUNRELOC(p);	mem += strlen(p) + 1;	/* Find the OF version */	prom_op = call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom"));	prom_version = 0;	if (prom_op != (void*)-1) {		char model[64];		int sz;		sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op,				    RELOC("model"), model, 64);		if (sz > 0) {			char *c;			/* hack to skip the ibm chrp firmware # */			if ( strncmp(model,RELOC("IBM"),3) ) {				for (c = model; *c; c++)					if (*c >= '0' && *c <= '9') {						prom_version = *c - '0';						break;					}			}			else				chrp = 1;		}	}	if (prom_version >= 3)		prom_print(RELOC("OF Version 3 detected.\n"));	/* Get the boot device and translate it to a full OF pathname. */	p = (char *) mem;	l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),			    RELOC("bootpath"), p, 1<<20);	if (l > 0) {		p[l] = 0;	/* should already be null-terminated */		RELOC(bootpath) = PTRUNRELOC(p);		mem += l + 1;		d = (char *) mem;		*d = 0;		call_prom(RELOC("canon"), 3, 1, p, d, 1<<20);		RELOC(bootdevice) = PTRUNRELOC(d);		mem = ALIGN(mem + strlen(d) + 1);	}	prom_instantiate_rtas();#ifdef CONFIG_PPC64BRIDGE	/*	 * Find out how much memory we have and allocate a	 * suitably-sized hash table.	 */	prom_alloc_htab();#endif#ifdef CONFIG_SMP	prom_hold_cpus(mem);#endif	mem = check_display(mem);	prom_print(RELOC("copying OF device tree..."));	mem = copy_device_tree(mem, mem + (1<<20));	prom_print(RELOC("done\n"));	RELOC(klimit) = (char *) (mem - offset);	/* If we are already running at 0xc0000000, we assume we were loaded by	 * an OF bootloader which did set a BAT for us. This breaks OF translate	 * so we force phys to be 0	 */	if (offset == 0)		phys = 0;	else { 	    if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),			    RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) {			prom_print(RELOC(" no MMU found\n"));	    } else {		int nargs;		struct prom_args prom_args;		nargs = 4;		prom_args.service = RELOC("call-method");		prom_args.nargs = nargs;		prom_args.nret = 4;		prom_args.args[0] = RELOC("translate");		prom_args.args[1] = prom_mmu;		prom_args.args[2] = (void *)(offset + KERNELBASE);		prom_args.args[3] = (void *)1;		RELOC(prom)(&prom_args);		/* We assume the phys. address size is 3 cells */		if (prom_args.args[nargs] != 0)			prom_print(RELOC(" (translate failed)\n"));		else			phys = (unsigned long)prom_args.args[nargs+3];	    }	}#ifdef CONFIG_BOOTX_TEXT	if (RELOC(prom_disp_node) != 0)		setup_disp_fake_bi(RELOC(prom_disp_node));#endif	/* If OpenFirmware version >= 3, then use quiesce call */	if (prom_version >= 3) {		prom_print(RELOC("Calling quiesce ...\n"));		call_prom(RELOC("quiesce"), 0, 0);	}#ifdef CONFIG_BOOTX_TEXT	if (!chrp && RELOC(disp_bi)) {		RELOC(prom_stdout) = 0; /* stop OF output */		clearscreen();		prepare_disp_BAT();		prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);		prom_drawstring(RELOC("booting...\n"));		RELOC(bootx_text_mapped) = 1;	} else {		RELOC(bootx_text_mapped) = 0;	}#endif	prom_print(RELOC("returning "));	prom_print_hex(phys);	prom_print(RELOC(" from prom_init\n"));	RELOC(prom_stdout) = 0;	return phys;}void phys_call_rtas(int service, int nargs, int nret, ...){	va_list list;	union {		unsigned long words[16];		double align;	} u;	unsigned long offset = reloc_offset();	void (*rtas)(void *, unsigned long);	int i;	u.words[0] = service;	u.words[1] = nargs;	u.words[2] = nret;	va_start(list, nret);	for (i = 0; i < nargs; ++i)		u.words[i+3] = va_arg(list, unsigned long);	va_end(list);	rtas = (void (*)(void *, unsigned long)) RELOC(rtas_entry);	rtas(&u, RELOC(rtas_data));}#ifdef CONFIG_BOOTX_TEXT__init static voidprom_welcome(boot_infos_t* bi, unsigned long phys){	unsigned long offset = reloc_offset();	unsigned long flags;	unsigned long pvr;		prom_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));	prom_drawstring(RELOC("\nstarted at       : 0x"));	prom_drawhex(phys);	prom_drawstring(RELOC("\nlinked at        : 0x"));	prom_drawhex(KERNELBASE);	prom_drawstring(RELOC("\nframe buffer at  : 0x"));	prom_drawhex((unsigned long)bi->dispDeviceBase);	prom_drawstring(RELOC(" (phys), 0x"));	prom_drawhex((unsigned long)bi->logicalDisplayBase);	prom_drawstring(RELOC(" (log)"));	prom_drawstring(RELOC("\nklimit           : 0x"));	prom_drawhex((unsigned long)RELOC(klimit));	prom_drawstring(RELOC("\nMSR              : 0x"));	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));	prom_drawhex(flags);	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));	pvr >>= 16;	if (pvr > 1) {	    prom_drawstring(RELOC("\nHID0             : 0x"));	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));	    prom_drawhex(flags);	}	if (pvr == 8 || pvr == 12) {	    prom_drawstring(RELOC("\nICTC             : 0x"));	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));	    prom_drawhex(flags);	}	prom_drawstring(RELOC("\n\n"));}/* Calc BAT values for mapping the display and store them * in disp_BAT.  Those values are then used from head.S to map * the display during identify_machine() and MMU_Init() *  * For now, the display is mapped in place (1:1). This should * be changed if the display physical address overlaps * KERNELBASE, which is fortunately not the case on any machine * I know of. This mapping is temporary and will disappear as * soon as the setup done by MMU_Init() is applied *  * For now, we align the BAT and then map 8Mb on 601 and 16Mb * on other PPCs. This may cause trouble if the framebuffer * is really badly aligned, but I didn't encounter this case * yet. */__initstatic voidprepare_disp_BAT(void){	unsigned long offset = reloc_offset();	boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));	unsigned long addr = (unsigned long)bi->dispDeviceBase;		if ((_get_PVR() >> 16) != 1) {		/* 603, 604, G3, G4, ... */		addr &= 0xFF000000UL;		RELOC(disp_BAT[0]) = addr | (BL_16M<<2) | 2;		RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);			} else {		/* 601 */		addr &= 0xFF800000UL;		RELOC(disp_BAT[0]) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4;		RELOC(disp_BAT[1]) = addr | BL_8M | 0x40;	}	bi->logicalDisplayBase = bi->dispDeviceBase;}#endifstatic int prom_set_color(ihandle ih, int i, int r, int g, int b){	struct prom_args prom_args;	unsigned long offset = reloc_offset();	prom_args.service = RELOC("call-method");	prom_args.nargs = 6;	prom_args.nret = 1;	prom_args.args[0] = RELOC("color!");	prom_args.args[1] = ih;	prom_args.args[2] = (void *) i;	prom_args.args[3] = (void *) b;	prom_args.args[4] = (void *) g;	prom_args.args[5] = (void *) r;	RELOC(prom)(&prom_args);	return (int) prom_args.args[6];}/* * If we have a display that we don't know how to drive, * we will want to try to execute OF's open method for it * later.  However, OF will probably fall over if we do that * we've taken over the MMU. * So we check whether we will need to open the display, * and if so, open it now. */__initstatic unsigned longcheck_display(unsigned long mem){	phandle node;	ihandle ih;	int i;	unsigned long offset = reloc_offset();	char type[16], *path;	static unsigned char default_colors[] = {		0x00, 0x00, 0x00,		0x00, 0x00, 0xaa,		0x00, 0xaa, 0x00,		0x00, 0xaa, 0xaa,		0xaa, 0x00, 0x00,		0xaa, 0x00, 0xaa,		0xaa, 0xaa, 0x00,		0xaa, 0xaa, 0xaa,		0x55, 0x55, 0x55,		0x55, 0x55, 0xff,		0x55, 0xff, 0x55,		0x55, 0xff, 0xff,		0xff, 0x55, 0x55,		0xff, 0x55, 0xff,		0xff, 0xff, 0x55,		0xff, 0xff, 0xff	};	RELOC(prom_disp_node) = 0;	for (node = 0; prom_next_node(&node); ) {		type[0] = 0;		call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),			  type, sizeof(type));		if (strcmp(type, RELOC("display")) != 0)			continue;		/* It seems OF doesn't null-terminate the path :-( */		path = (char *) mem;		memset(path, 0, 256);		if ((int) call_prom(RELOC("package-to-path"), 3, 1,				    node, path, 255) < 0)			continue;		prom_print(RELOC("opening display "));		prom_print(path);		ih = call_prom(RELOC("open"), 1, 1, path);		if (ih == 0 || ih == (ihandle) -1) {			prom_print(RELOC("... failed\n"));			continue;		}		prom_print(RELOC("... ok\n"));		if (RELOC(prom_disp_node) == 0)			RELOC(prom_disp_node) = node;					/* Setup a useable color table when the appropriate		 * method is available. Should update this to set-colors */		for (i = 0; i < 32; i++)			if (prom_set_color(ih, i, RELOC(default_colors)[i*3],					   RELOC(default_colors)[i*3+1],					   RELOC(default_colors)[i*3+2]) != 0)				break;#ifdef CONFIG_FB		for (i = 0; i < LINUX_LOGO_COLORS; i++)			if (prom_set_color(ih, i + 32,					   RELOC(linux_logo_red)[i],					   RELOC(linux_logo_green)[i],					   RELOC(linux_logo_blue)[i]) != 0)				break;#endif /* CONFIG_FB */		/*		 * If this display is the device that OF is using for stdout,		 * move it to the front of the list.		 */		mem += strlen(path) + 1;		i = RELOC(prom_num_displays)++;		if (RELOC(of_stdout_device) != 0 && i > 0		    && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) {			for (; i > 0; --i)				RELOC(prom_display_paths[i])					= RELOC(prom_display_paths[i-1]);		}		RELOC(prom_display_paths[i]) = PTRUNRELOC(path);		if (RELOC(prom_num_displays) >= FB_MAX)			break;	}	return ALIGN(mem);

⌨️ 快捷键说明

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