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

📄 prom.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * BK Id: SCCS/s.prom.c 1.48 12/19/01 10:50:58 paulus *//* * 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 <linux/ioport.h>#include <linux/pci.h>#include <linux/slab.h>#include <asm/sections.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/mmu.h>#include <asm/pgtable.h>#include <asm/bitops.h>#include <asm/bootinfo.h>#include <asm/btext.h>#include <asm/pci-bridge.h>#include "open_pic.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.  But this value * does need to be big enough to ensure that we don't lose things * like the interrupt-map property on a PCI-PCI bridge. */#define MAX_PROPERTY_LENGTH	4096struct 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, };phandle prom_display_nodes[FB_MAX] __initdata;unsigned int prom_num_displays __initdata = 0;char *of_stdout_device __initdata = 0;ihandle prom_disp_node __initdata = 0;prom_entry prom __initdata = 0;ihandle prom_chosen __initdata = 0;ihandle prom_stdout __initdata = 0;extern char *klimit;char *bootpath;char *bootdevice;unsigned int rtas_data;   /* physical pointer */unsigned int rtas_entry;  /* physical pointer */unsigned int rtas_size;unsigned int old_rtas;/* Set for a newworld or CHRP machine */int use_of_interrupt_tree;struct device_node *dflt_interrupt_controller;int num_interrupt_controllers;int pmac_newworld;static struct device_node *allnodes;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 *);static struct device_node *find_phandle(phandle);#ifdef CONFIG_BOOTX_TEXTstatic void setup_disp_fake_bi(ihandle dp);#endifextern void enter_rtas(void *);void phys_call_rtas(int, int, int, ...);extern char cmd_line[512];	/* XXX */boot_infos_t *boot_infos;unsigned long dev_tree_size;#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)/* * Note that prom_init() and anything called from prom_init() must * use the RELOC/PTRRELOC macros to access any static data in * memory, since the kernel may be running at an address that is * different from the address that it was linked at. * (Note that strings count as static variables.) */static void __initprom_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 */		;}void __initprom_enter(void){	struct prom_args args;	unsigned long offset = reloc_offset();	args.service = RELOC("enter");	args.nargs = 0;	args.nret = 0;	RELOC(prom)(&args);}static void * __initcall_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];}void __initprom_print(const char *msg){	const char *p, *q;	unsigned long offset = reloc_offset();	if (RELOC(prom_stdout) == 0)		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);		}	}}static void __initprom_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);}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 void __initprom_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(RELOC("\n"));		}	}}#endif /* CONFIG_SMP */void __initbootx_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	btext_init(bi);	/*	 * 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)) {		btext_drawstring(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));		btext_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	/*	 * Note that after we call prepare_disp_BAT, we can't do	 * prom_draw*, flushscreen or clearscreen until we turn the MMU	 * on, since prepare_disp_BAT sets disp_bi->logicalDisplayBase	 * to a virtual address.	 */	btext_prepare_BAT();#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,			    unsigned int va, unsigned int pa, int mode){	unsigned int *pteg;	unsigned int hash, i, vsid;	vsid = ((va >> 28) * 0x111) << 12;	hash = ((va ^ vsid) >> 5) & 0x7fff80;	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));	for (i = 0; i < 8; ++i, pteg += 4) {		if ((pteg[1] & 1) == 0) {			pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;			pteg[3] = pa | mode;			break;		}	}}extern unsigned long _SDR1;extern PTE *Hash;extern unsigned long Hash_size;static void __initprom_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 void __initprom_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"));}

⌨️ 快捷键说明

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