📄 prom.c
字号:
/* - undefined for user space * * * Procedures for interfacing to Open Firmware. * * Paul Mackerras August 1996. * Copyright (C) 1996 Paul Mackerras. * * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. * {engebret|bergner}@us.ibm.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#if 0#define DEBUG_YABOOT#endif#if 0#define DEBUG_PROM#endif#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/blk.h>#ifdef DEBUG_YABOOT#define call_yaboot(FUNC,...) \ do { \ if (FUNC) { \ struct prom_t *_prom = PTRRELOC(&prom); \ unsigned long prom_entry = _prom->entry;\ _prom->entry = (unsigned long)(FUNC); \ enter_prom(__VA_ARGS__); \ _prom->entry = prom_entry; \ } \ } while (0)#else#define call_yaboot(FUNC,...) do { ; } while (0)#endif#include <asm/init.h>#include <linux/types.h>#include <linux/pci.h>#include <asm/prom.h>#include <asm/rtas.h>#include <asm/lmb.h>#include <asm/abs_addr.h>#include <asm/page.h>#include <asm/processor.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/system.h>#include <asm/mmu.h>#include <asm/pgtable.h>#include <asm/bitops.h>#include <asm/naca.h>#include <asm/pci.h>#include "open_pic.h"#include <asm/bootinfo.h>#include <asm/ppcdebug.h>#ifdef CONFIG_FB#include <asm/linux_logo.h>#endifextern char _end[];/* * 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 PROM_BUG() do { \ prom_print(RELOC("kernel BUG at ")); \ prom_print(RELOC(__FILE__)); \ prom_print(RELOC(":")); \ prom_print_hex(__LINE__); \ prom_print(RELOC("!\n")); \ __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \} while (0)struct pci_reg_property { struct pci_address addr; u32 size_hi; u32 size_lo;};struct isa_reg_property { u32 space; u32 address; u32 size;};struct pci_intr_map { struct pci_address addr; u32 dunno; phandle int_ctrler; u32 intr;};typedef unsigned long interpret_func(struct device_node *, unsigned long, int, int);#if 0static interpret_func interpret_pci_props;#endifstatic unsigned long interpret_pci_props(struct device_node *, unsigned long, int, int);static interpret_func interpret_isa_props;static interpret_func interpret_root_props;#ifndef FB_MAX /* avoid pulling in all of the fb stuff */#define FB_MAX 8#endifstruct prom_t prom = { 0, /* entry */ 0, /* chosen */ 0, /* cpu */ 0, /* stdout */ 0, /* disp_node */ {0,0,0,{0},NULL}, /* args */ 0, /* version */ 32, /* encode_phys_size */ 0 /* bi_rec pointer */#ifdef DEBUG_YABOOT ,NULL /* yaboot */#endif};char *prom_display_paths[FB_MAX] __initdata = { 0, };unsigned int prom_num_displays = 0;char *of_stdout_device = 0;extern struct rtas_t rtas;extern unsigned long klimit;extern unsigned long embedded_sysmap_end;extern struct lmb lmb;#ifdef CONFIG_MSCHUNKSextern struct msChunks msChunks;#endif /* CONFIG_MSCHUNKS */#define MAX_PHB 16 * 3 // 16 Towers * 3 PHBs/towerstruct _of_tce_table of_tce_table[MAX_PHB + 1] = {{0, 0, 0}};char *bootpath = 0;char *bootdevice = 0;struct device_node *allnodes = 0;#define UNDEFINED_IRQ 0xffffunsigned short real_irq_to_virt_map[NR_HW_IRQS];unsigned short virt_irq_to_real_map[NR_IRQS];int last_virt_irq = 2; /* index of last virt_irq. Skip through IPI */static unsigned long call_prom(const char *service, int nargs, int nret, ...);static void prom_exit(void);static unsigned long copy_device_tree(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 struct bi_record * prom_bi_rec_verify(struct bi_record *);static unsigned long prom_bi_rec_reserve(unsigned long);static struct device_node *find_phandle(phandle);#ifdef CONFIG_MSCHUNKSstatic unsigned long prom_initialize_mschunks(unsigned long);#ifdef DEBUG_PROMvoid prom_dump_mschunks_mapping(void);#endif /* DEBUG_PROM */#endif /* CONFIG_MSCHUNKS */#ifdef DEBUG_PROMvoid prom_dump_lmb(void);#endifextern unsigned long reloc_offset(void);extern void enter_prom(void *dummy,...);void cacheable_memzero(void *, unsigned int);#ifndef CONFIG_CMDLINE#define CONFIG_CMDLINE ""#endifchar cmd_line[512] = CONFIG_CMDLINE;unsigned long dev_tree_size;#ifdef CONFIG_HMTstruct { unsigned int pir; unsigned int threadid;} hmt_thread_data[NR_CPUS] = {0};#endif /* CONFIG_HMT */char testString[] = "LINUX\n"; /* This is the one and *ONLY* place where we actually call open * firmware from, since we need to make sure we're running in 32b * mode when we do. We switch back to 64b mode upon return. */static unsigned long __initcall_prom(const char *service, int nargs, int nret, ...){ int i; unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); va_list list; _prom->args.service = (u32)LONG_LSW(service); _prom->args.nargs = nargs; _prom->args.nret = nret; _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); va_start(list, nret); for (i=0; i < nargs ;i++) _prom->args.args[i] = (prom_arg_t)LONG_LSW(va_arg(list, unsigned long)); va_end(list); for (i=0; i < nret ;i++) _prom->args.rets[i] = 0; enter_prom(&_prom->args); return (unsigned long)((nret > 0) ? _prom->args.rets[0] : 0);}static void __initprom_exit(){ unsigned long offset = reloc_offset(); call_prom(RELOC("exit"), 0, 0); for (;;) /* should never get here */ ;}void __initprom_enter(void){ unsigned long offset = reloc_offset(); call_prom(RELOC("enter"), 0, 0);}void __initprom_print(const char *msg){ const char *p, *q; unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); if (_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, _prom->stdout, p, q - p); if (*q != 0) { ++q; call_prom(RELOC("write"), 3, 1, _prom->stdout, RELOC("\r\n"), 2); } }}voidprom_print_hex(unsigned long val){ int i, nibbles = sizeof(val)*2; char buf[sizeof(val)*2+1]; for (i = nibbles-1; i >= 0; i--) { buf[i] = (val & 0xf) + '0'; if (buf[i] > '9') buf[i] += ('a'-'0'-10); val >>= 4; } buf[nibbles] = '\0'; prom_print(buf);}voidprom_print_nl(void){ unsigned long offset = reloc_offset(); prom_print(RELOC("\n"));}static unsigned longprom_initialize_naca(unsigned long mem){ phandle node; char type[64]; unsigned long num_cpus = 0; unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); struct naca_struct *_naca = RELOC(naca); /* NOTE: _naca->debug_switch is already initialized. */#ifdef DEBUG_PROM prom_print(RELOC("prom_initialize_naca: start...\n"));#endif _naca->pftSize = 0; /* ilog2 of htab size. computed below. */ 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"))) { num_cpus += 1; /* We're assuming *all* of the CPUs have the same * d-cache and i-cache sizes... -Peter */ if ( num_cpus == 1 ) { u32 size, lsize, sets; call_prom(RELOC("getprop"), 4, 1, node, RELOC("d-cache-size"), &size, sizeof(size)); call_prom(RELOC("getprop"), 4, 1, node, RELOC("d-cache-line-size"), &lsize, sizeof(lsize)); call_prom(RELOC("getprop"), 4, 1, node, RELOC("d-cache-sets"), &sets, sizeof(sets)); _naca->dCacheL1Size = size; _naca->dCacheL1LineSize = lsize; _naca->dCacheL1LogLineSize = __ilog2(lsize); _naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize; _naca->dCacheL1Assoc = size / lsize / sets; call_prom(RELOC("getprop"), 4, 1, node, RELOC("i-cache-line-size"), &size, sizeof(size)); call_prom(RELOC("getprop"), 4, 1, node, RELOC("i-cache-line-size"), &lsize, sizeof(lsize)); call_prom(RELOC("getprop"), 4, 1, node, RELOC("i-cache-sets"), &sets, sizeof(sets)); _naca->iCacheL1Size = size; _naca->iCacheL1LineSize = lsize; _naca->iCacheL1LogLineSize = __ilog2(lsize); _naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize; _naca->iCacheL1Assoc = size / lsize / sets; if (_naca->platform == PLATFORM_PSERIES_LPAR) { u32 pft_size[2]; call_prom(RELOC("getprop"), 4, 1, node, RELOC("ibm,pft-size"), &pft_size, sizeof(pft_size)); /* pft_size[0] is the NUMA CEC cookie */ _naca->pftSize = pft_size[1]; } } } else if (!strcmp(type, RELOC("serial"))) { phandle isa, pci; struct isa_reg_property reg; union pci_range ranges; type[0] = 0; call_prom(RELOC("getprop"), 4, 1, node, RELOC("ibm,aix-loc"), type, sizeof(type)); if (strcmp(type, RELOC("S1"))) continue; call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), ®, sizeof(reg)); isa = call_prom(RELOC("parent"), 1, 1, node); if (!isa) PROM_BUG(); pci = call_prom(RELOC("parent"), 1, 1, isa); if (!pci) PROM_BUG(); call_prom(RELOC("getprop"), 4, 1, pci, RELOC("ranges"), &ranges, sizeof(ranges)); if ( _prom->encode_phys_size == 32 ) _naca->serialPortAddr = ranges.pci32.phys+reg.address; else { _naca->serialPortAddr = ((((unsigned long)ranges.pci64.phys_hi) << 32) | (ranges.pci64.phys_lo)) + reg.address; } } } _naca->interrupt_controller = IC_INVALID; for (node = 0; prom_next_node(&node); ) { type[0] = 0; call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"), type, sizeof(type)); if (strcmp(type, RELOC("interrupt-controller"))) { continue; } call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"), type, sizeof(type)); if (strstr(type, RELOC("open-pic"))) { _naca->interrupt_controller = IC_OPEN_PIC; } else if (strstr(type, RELOC("ppc-xicp"))) { _naca->interrupt_controller = IC_PPC_XIC; } else { prom_print(RELOC("prom: failed to recognize interrupt-controller\n")); } break; } if (_naca->interrupt_controller == IC_INVALID) { prom_print(RELOC("prom: failed to find interrupt-controller\n")); PROM_BUG(); } /* We gotta have at least 1 cpu... */ if ( (_naca->processorCount = num_cpus) < 1 ) PROM_BUG(); _naca->physicalMemorySize = lmb_phys_mem_size();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -