prom_init.c
字号:
/* * * * 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. */#undef DEBUG_PROM#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/types.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <linux/stringify.h>#include <linux/delay.h>#include <linux/initrd.h>#include <asm/prom.h>#include <asm/rtas.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 <asm/iommu.h>#include <asm/bootinfo.h>#include <asm/ppcdebug.h>#include <asm/btext.h>#include <asm/sections.h>#include <asm/machdep.h>#include "open_pic.h"#ifdef CONFIG_LOGO_LINUX_CLUT224#include <linux/linux_logo.h>extern const struct linux_logo logo_linux_clut224;#endif/* * Properties whose value is longer than this get excluded from our * copy of the device tree. 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 (1UL * 1024 * 1024)/* * Eventually bump that one up */#define DEVTREE_CHUNK_SIZE 0x100000/* * This is the size of the local memory reserve map that gets copied * into the boot params passed to the kernel. That size is totally * flexible as the kernel just reads the list until it encounters an * entry with size 0, so it can be changed without breaking binary * compatibility */#define MEM_RESERVE_MAP_SIZE 8/* * 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_printf("kernel BUG at %s line 0x%x!\n", \ RELOC(__FILE__), __LINE__); \ __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \} while (0)#ifdef DEBUG_PROM#define prom_debug(x...) prom_printf(x)#else#define prom_debug(x...)#endiftypedef u32 prom_arg_t;struct prom_args { u32 service; u32 nargs; u32 nret; prom_arg_t args[10]; prom_arg_t *rets; /* Pointer to return values in args[16]. */};struct prom_t { unsigned long entry; ihandle root; ihandle chosen; int cpu; ihandle stdout; ihandle disp_node; struct prom_args args; unsigned long version; unsigned long root_size_cells; unsigned long root_addr_cells;};struct pci_reg_property { struct pci_address addr; u32 size_hi; u32 size_lo;};struct mem_map_entry { u64 base; u64 size;};typedef u32 cell_t;extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);extern unsigned long reloc_offset(void);extern void enter_prom(struct prom_args *args, unsigned long entry);extern void copy_and_flush(unsigned long dest, unsigned long src, unsigned long size, unsigned long offset);extern unsigned long klimit;//int global_width = 640, global_height = 480, global_depth = 8, global_pitch;//unsigned global_address;/* prom structure */static struct prom_t __initdata prom;#define PROM_SCRATCH_SIZE 256static char __initdata of_stdout_device[256];static char __initdata prom_scratch[PROM_SCRATCH_SIZE];static unsigned long __initdata dt_header_start;static unsigned long __initdata dt_struct_start, dt_struct_end;static unsigned long __initdata dt_string_start, dt_string_end;static unsigned long __initdata prom_initrd_start, prom_initrd_end;static int __initdata iommu_force_on;static int __initdata ppc64_iommu_off;static int __initdata of_platform;static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];static unsigned long __initdata alloc_top;static unsigned long __initdata alloc_top_high;static unsigned long __initdata alloc_bottom;static unsigned long __initdata rmo_top;static unsigned long __initdata ram_top;static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];static int __initdata mem_reserve_cnt;static cell_t __initdata regbuf[1024];#define MAX_CPU_THREADS 2/* TO GO */#ifdef CONFIG_HMTstruct { unsigned int pir; unsigned int threadid;} hmt_thread_data[NR_CPUS];#endif /* CONFIG_HMT *//* * This are used in calls to call_prom. The 4th and following * arguments to call_prom should be 32-bit values. 64 bit values * are truncated to 32 bits (and fortunately don't get interpreted * as two arguments). */#define ADDR(x) (u32) ((unsigned long)(x) - offset)/* 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. */#define PROM_ERROR (-1)static int __init call_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 = ADDR(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] = va_arg(list, prom_arg_t); va_end(list); for (i=0; i < nret ;i++) _prom->args.rets[i] = 0; enter_prom(&_prom->args, _prom->entry); return (nret > 0) ? _prom->args.rets[0] : 0;}static unsigned int __init prom_claim(unsigned long virt, unsigned long size, unsigned long align){ return (unsigned int)call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, (prom_arg_t)align);}static void __init prom_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("write", 3, 1, _prom->stdout, p, q - p); if (*q == 0) break; ++q; call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); }}static void __init prom_print_hex(unsigned long val){ unsigned long offset = reloc_offset(); int i, nibbles = sizeof(val)*2; char buf[sizeof(val)*2+1]; struct prom_t *_prom = PTRRELOC(&prom); 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'; call_prom("write", 3, 1, _prom->stdout, buf, nibbles);}static void __init prom_printf(const char *format, ...){ unsigned long offset = reloc_offset(); const char *p, *q, *s; va_list args; unsigned long v; struct prom_t *_prom = PTRRELOC(&prom); va_start(args, format); for (p = PTRRELOC(format); *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) ; if (q > p) call_prom("write", 3, 1, _prom->stdout, p, q - p); if (*q == 0) break; if (*q == '\n') { ++q; call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); continue; } ++q; if (*q == 0) break; switch (*q) { case 's': ++q; s = va_arg(args, const char *); prom_print(s); break; case 'x': ++q; v = va_arg(args, unsigned long); prom_print_hex(v); break; } }}static void __init __attribute__((noreturn)) prom_panic(const char *reason){ unsigned long offset = reloc_offset(); prom_print(PTRRELOC(reason)); /* ToDo: should put up an SRC here */ call_prom("exit", 0, 0); for (;;) /* should never get here */ ;}static int __init prom_next_node(phandle *nodep){ phandle node; if ((node = *nodep) != 0 && (*nodep = call_prom("child", 1, 1, node)) != 0) return 1; if ((*nodep = call_prom("peer", 1, 1, node)) != 0) return 1; for (;;) { if ((node = call_prom("parent", 1, 1, node)) == 0) return 0; if ((*nodep = call_prom("peer", 1, 1, node)) != 0) return 1; }}static int __init prom_getprop(phandle node, const char *pname, void *value, size_t valuelen){ unsigned long offset = reloc_offset(); return call_prom("getprop", 4, 1, node, ADDR(pname), (u32)(unsigned long) value, (u32) valuelen);}static int __init prom_getproplen(phandle node, const char *pname){ unsigned long offset = reloc_offset(); return call_prom("getproplen", 2, 1, node, ADDR(pname));}static int __init prom_setprop(phandle node, const char *pname, void *value, size_t valuelen){ unsigned long offset = reloc_offset(); return call_prom("setprop", 4, 1, node, ADDR(pname), (u32)(unsigned long) value, (u32) valuelen);}/* * Early parsing of the command line passed to the kernel, used for * the options that affect the iommu */static void __init early_cmdline_parse(void){ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); char *opt, *p; int l = 0; RELOC(prom_cmd_line[0]) = 0; p = RELOC(prom_cmd_line); if ((long)_prom->chosen > 0) l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);#ifdef CONFIG_CMDLINE if (l == 0) /* dbl check */ strlcpy(RELOC(prom_cmd_line), RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));#endif /* CONFIG_CMDLINE */ prom_printf("command line: %s\n", RELOC(prom_cmd_line)); opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); if (opt) { prom_printf("iommu opt is: %s\n", opt); opt += 6; while (*opt && *opt == ' ') opt++; if (!strncmp(opt, RELOC("off"), 3)) RELOC(ppc64_iommu_off) = 1; else if (!strncmp(opt, RELOC("force"), 5)) RELOC(iommu_force_on) = 1; }}/* * Memory allocation strategy... our layout is normally:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -