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

📄 prom.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * $Id: prom.c,v 1.79 1999/10/08 01:56:32 paulus Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. * * In particular, we are interested in the device tree * and in using some of its services (exit, write to stdout). * * Paul Mackerras	August 1996. * Copyright (C) 1996 Paul Mackerras. */#include <stdarg.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/init.h>#include <linux/version.h>#include <linux/threads.h>#include <linux/spinlock.h>#include <asm/init.h>#include <asm/prom.h>#include <asm/page.h>#include <asm/processor.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/bootx.h>#include <asm/system.h>#include <asm/gemini.h>#include <asm/mmu.h>#include <asm/pgtable.h>#include <asm/bitops.h>#ifdef CONFIG_FB#include <asm/linux_logo.h>#endif/* * Properties whose value is longer than this get excluded from our * copy of the device tree.  This way we don't waste space storing * things like "driver,AAPL,MacOS,PowerPC" properties. */#define MAX_PROPERTY_LENGTH	1024struct prom_args {	const char *service;	int nargs;	int nret;	void *args[10];};struct pci_address {	unsigned a_hi;	unsigned a_mid;	unsigned a_lo;};struct pci_reg_property {	struct pci_address addr;	unsigned size_hi;	unsigned size_lo;};struct pci_range {	struct pci_address addr;	unsigned phys;	unsigned size_hi;	unsigned size_lo;};struct isa_reg_property {	unsigned space;	unsigned address;	unsigned size;};struct pci_intr_map {	struct pci_address addr;	unsigned dunno;	phandle int_ctrler;	unsigned intr;};typedef unsigned long interpret_func(struct device_node *, unsigned long,				     int, int);static interpret_func interpret_pci_props;static interpret_func interpret_dbdma_props;static interpret_func interpret_isa_props;static interpret_func interpret_macio_props;static interpret_func interpret_root_props;#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */#define FB_MAX	8#endifchar *prom_display_paths[FB_MAX] __initdata = { 0, };unsigned int prom_num_displays = 0;char *of_stdout_device = 0;prom_entry prom = 0;ihandle prom_chosen = 0, prom_stdout = 0, prom_disp_node = 0;extern char *klimit;char *bootpath = 0;char *bootdevice = 0;unsigned int rtas_data = 0;   /* physical pointer */unsigned int rtas_entry = 0;  /* physical pointer */unsigned int rtas_size = 0;unsigned int old_rtas = 0;/* Set for a newworld machine */int use_of_interrupt_tree = 0;int pmac_newworld = 0;static struct device_node *allnodes = 0;#ifdef CONFIG_BOOTX_TEXT#define NO_SCROLLstatic void clearscreen(void);static void flushscreen(void);#ifndef NO_SCROLLstatic void scrollscreen(void);#endifstatic void prepare_disp_BAT(void);static void draw_byte(unsigned char c, long locX, long locY);static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);/* We want those in data, not BSS */static long				g_loc_X = 0;static long				g_loc_Y = 0;static long				g_max_loc_X = 0;static long				g_max_loc_Y = 0;unsigned long disp_BAT[2] = {0, 0};#define cmapsz	(16*256)static unsigned char vga_font[cmapsz];int bootx_text_mapped = 1;#endif /* CONFIG_BOOTX_TEXT */static void *call_prom(const char *service, int nargs, int nret, ...);static void prom_exit(void);static unsigned long copy_device_tree(unsigned long, unsigned long);static unsigned long inspect_node(phandle, struct device_node *, unsigned long,				  unsigned long, struct device_node ***);static unsigned long finish_node(struct device_node *, unsigned long,				 interpret_func *, int, int);static unsigned long finish_node_interrupts(struct device_node *, unsigned long);static unsigned long check_display(unsigned long);static int prom_next_node(phandle *);static void *early_get_property(unsigned long, unsigned long, char *);#ifdef CONFIG_BOOTX_TEXTstatic void setup_disp_fake_bi(ihandle dp);static void prom_welcome(boot_infos_t* bi, unsigned long phys);#endifextern void enter_rtas(void *);extern unsigned long reloc_offset(void);void phys_call_rtas(int, int, int, ...);extern char cmd_line[512];	/* XXX */boot_infos_t *boot_infos = 0;	/* init it so it's in data segment not bss */#ifdef CONFIG_BOOTX_TEXTboot_infos_t *disp_bi = 0;boot_infos_t fake_bi = {0,};#endifunsigned long dev_tree_size;/* * prom_init() is called very early on, before the kernel text * and data have been mapped to KERNELBASE.  At this point the code * is running at whatever address it has been loaded at, so * references to extern and static variables must be relocated * explicitly.  The procedure reloc_offset() returns the address * we're currently running at minus the address we were linked at. * (Note that strings count as static variables.) * * Because OF may have mapped I/O devices into the area starting at * KERNELBASE, particularly on CHRP machines, we can't safely call * OF once the kernel has been mapped to KERNELBASE.  Therefore all * OF calls should be done within prom_init(), and prom_init() * and all routines called within it must be careful to relocate * references as necessary. * * Note that the bss is cleared *after* prom_init runs, so we have * to make sure that any static or extern variables it accesses * are put in the data segment. */#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))#define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) - offset))#define RELOC(x)	(*PTRRELOC(&(x)))#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))/* Is boot-info compatible ? */#define BOOT_INFO_IS_COMPATIBLE(bi)		((bi)->compatible_version <= BOOT_INFO_VERSION)#define BOOT_INFO_IS_V2_COMPATIBLE(bi)	((bi)->version >= 2)#define BOOT_INFO_IS_V4_COMPATIBLE(bi)	((bi)->version >= 4)__initstatic voidprom_exit(){	struct prom_args args;	unsigned long offset = reloc_offset();	args.service = "exit";	args.nargs = 0;	args.nret = 0;	RELOC(prom)(&args);	for (;;)			/* should never get here */		;}__initvoidprom_enter(void){	struct prom_args args;	unsigned long offset = reloc_offset();	args.service = RELOC("enter");	args.nargs = 0;	args.nret = 0;	RELOC(prom)(&args);}__initstatic void *call_prom(const char *service, int nargs, int nret, ...){	va_list list;	int i;	unsigned long offset = reloc_offset();	struct prom_args prom_args;	prom_args.service = service;	prom_args.nargs = nargs;	prom_args.nret = nret;	va_start(list, nret);	for (i = 0; i < nargs; ++i)		prom_args.args[i] = va_arg(list, void *);	va_end(list);	for (i = 0; i < nret; ++i)		prom_args.args[i + nargs] = 0;	RELOC(prom)(&prom_args);	return prom_args.args[nargs];}__initvoidprom_print(const char *msg){	const char *p, *q;	unsigned long offset = reloc_offset();	if (RELOC(prom_stdout) == 0)	{#ifdef CONFIG_BOOTX_TEXT		if (RELOC(disp_bi) != 0)			prom_drawstring(msg);#endif		return;	}	for (p = msg; *p != 0; p = q) {		for (q = p; *q != 0 && *q != '\n'; ++q)			;		if (q > p)			call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout),				  p, q - p);		if (*q != 0) {			++q;			call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout),				  RELOC("\r\n"), 2);		}	}}voidprom_print_hex(unsigned int v){	char buf[16];	int i, c;	for (i = 0; i < 8; ++i) {		c = (v >> ((7-i)*4)) & 0xf;		c += (c >= 10)? ('a' - 10): '0';		buf[i] = c;	}	buf[i] = ' ';	buf[i+1] = 0;	prom_print(buf);}voidprom_print_nl(void){	unsigned long offset = reloc_offset();	prom_print(RELOC("\n"));}unsigned long smp_chrp_cpu_nr __initdata = 0;#ifdef CONFIG_SMP/* * With CHRP SMP we need to use the OF to start the other * processors so we can't wait until smp_boot_cpus (the OF is * trashed by then) so we have to put the processors into * a holding pattern controlled by the kernel (not OF) before * we destroy the OF. * * This uses a chunk of high memory, puts some holding pattern * code there and sends the other processors off to there until * smp_boot_cpus tells them to do something.  We do that by using * physical address 0x0.  The holding pattern checks that address * until its cpu # is there, when it is that cpu jumps to * __secondary_start().  smp_boot_cpus() takes care of setting those * values. * * We also use physical address 0x4 here to tell when a cpu * is in its holding pattern code. * * -- Cort */static voidprom_hold_cpus(unsigned long mem){	extern void __secondary_hold(void);	unsigned long i;	int cpu;	phandle node;	unsigned long offset = reloc_offset();	char type[16], *path;	unsigned int reg;	/*	 * XXX: hack to make sure we're chrp, assume that if we're	 *      chrp we have a device_type property -- Cort	 */	node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));	if ( (int)call_prom(RELOC("getprop"), 4, 1, node,			    RELOC("device_type"),type, sizeof(type)) <= 0)		return;	/* copy the holding pattern code to someplace safe (0) */	/* the holding pattern is now within the first 0x100	   bytes of the kernel image -- paulus */	memcpy((void *)0, (void *)(KERNELBASE + offset), 0x100);	flush_icache_range(0, 0x100);	/* look for cpus */	*(unsigned long *)(0x0) = 0;	asm volatile("dcbf 0,%0": : "r" (0) : "memory");	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("cpu")) != 0)			continue;		path = (char *) mem;		memset(path, 0, 256);		if ((int) call_prom(RELOC("package-to-path"), 3, 1,				    node, path, 255) < 0)			continue;		reg = -1;		call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),			  &reg, sizeof(reg));		cpu = RELOC(smp_chrp_cpu_nr)++;		RELOC(smp_hw_index)[cpu] = reg;		/* XXX: hack - don't start cpu 0, this cpu -- Cort */		if (cpu == 0)			continue;		prom_print(RELOC("starting cpu "));		prom_print(path);		*(ulong *)(0x4) = 0;		call_prom(RELOC("start-cpu"), 3, 0, node,			  __pa(__secondary_hold), cpu);		prom_print(RELOC("..."));		for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )			;		if (*(ulong *)(0x4) == cpu)			prom_print(RELOC("ok\n"));		else {			prom_print(RELOC("failed: "));			prom_print_hex(*(ulong *)0x4);			prom_print_nl();		}	}}#endif /* CONFIG_SMP */voidbootx_init(unsigned long r4, unsigned long phys){	boot_infos_t *bi = (boot_infos_t *) r4;	unsigned long space;	unsigned long ptr, x;	char *model;	unsigned long offset = reloc_offset();	RELOC(boot_infos) = PTRUNRELOC(bi);	if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))		bi->logicalDisplayBase = 0;#ifdef CONFIG_BOOTX_TEXT	RELOC(g_loc_X) = 0;	RELOC(g_loc_Y) = 0;	RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;	RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;	RELOC(disp_bi) = PTRUNRELOC(bi);			clearscreen();	/* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since	   there is nothing much we can do with an incompatible version, except display	   a message and eventually hang the processor...		   	   I'll try to keep enough of boot-info compatible in the future to always allow	   display of this message;	*/	if (!BOOT_INFO_IS_COMPATIBLE(bi))		prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));			prom_welcome(bi, phys);	flushscreen();#endif	/* CONFIG_BOOTX_TEXT */				/* New BootX enters kernel with MMU off, i/os are not allowed	   here. This hack will have been done by the boostrap anyway.	*/	if (bi->version < 4) {		/*		 * XXX If this is an iMac, turn off the USB controller.		 */		model = (char *) early_get_property			(r4 + bi->deviceTreeOffset, 4, RELOC("model"));		if (model		    && (strcmp(model, RELOC("iMac,1")) == 0			|| strcmp(model, RELOC("PowerMac1,1")) == 0)) {			out_le32((unsigned *)0x80880008, 1);	/* XXX */		}	}			/* Move klimit to enclose device tree, args, ramdisk, etc... */	if (bi->version < 5) {		space = bi->deviceTreeOffset + bi->deviceTreeSize;		if (bi->ramDisk)			space = bi->ramDisk + bi->ramDiskSize;	} else		space = bi->totalParamsSize;	RELOC(klimit) = PTRUNRELOC((char *) bi + space);	/* New BootX will have flushed all TLBs and enters kernel with	   MMU switched OFF, so this should not be useful anymore.	*/	if (bi->version < 4) {		/*		 * Touch each page to make sure the PTEs for them		 * are in the hash table - the aim is to try to avoid		 * getting DSI exceptions while copying the kernel image.		 */		for (ptr = (KERNELBASE + offset) & PAGE_MASK;		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)			x = *(volatile unsigned long *)ptr;	}		#ifdef CONFIG_BOOTX_TEXT	prepare_disp_BAT();	prom_drawstring(RELOC("booting...\n"));	flushscreen();	RELOC(bootx_text_mapped) = 1;#endif}#ifdef CONFIG_PPC64BRIDGE/* * Set up a hash table with a set of entries in it to map the * first 64MB of RAM.  This is used on 64-bit machines since * some of them don't have BATs. * We assume the PTE will fit in the primary PTEG. */static inline void make_pte(unsigned long htab, unsigned int hsize,

⌨️ 快捷键说明

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