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

📄 misc.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
字号:
/* *  head.S -- Bootloader Entry point * *  Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es * *  Modified to compile in RTEMS development environment *  by Eric Valette * *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr * *  The license and distribution terms for this file may be *  found in found in the file LICENSE in this distribution or at *  http://www.rtems.com/license/LICENSE. * * $Id: misc.c,v 1.4.4.2 2004/11/10 22:15:00 joel Exp $ */#include <rtems/system.h>#include <sys/types.h>#include <string.h>#include "bootldr.h"#include <libcpu/spr.h>#include "zlib.h"#include <libcpu/page.h>#include <libcpu/byteorder.h>#include <rtems/bspIo.h>#include <bsp.h>SPR_RW(DEC)SPR_RO(PVR)struct inode;struct wait_queue;struct buffer_head;typedef struct { int counter; } atomic_t;typedef struct page {	/* these must be first (free area handling) */	struct page *next;	struct page *prev;	struct inode *inode;	unsigned long offset;	struct page *next_hash;	atomic_t count;	unsigned long flags;	/* atomic flags, some possibly updated asynchronously */	struct wait_queue *wait;	struct page **pprev_hash;	struct buffer_head * buffers;} mem_map_t;extern opaque mm_private, pci_private, v86_private, console_private;#define CONSOLE_ON_SERIAL	"console=ttyS0"extern struct console_io vacuum_console_functions;extern opaque log_console_setup, serial_console_setup, vga_console_setup;boot_data __bd = {0, 0, 0, 0, 0, 0, 0, 0,		  32, 0, 0, 0, 0, 0, 0, 		  &mm_private,		  NULL,		  &pci_private,		  NULL,		  &v86_private,		  "root=/dev/hdc1"			 };static void exit(void) __attribute__((noreturn));static void exit(void) {	printk("\nOnly way out is to press the reset button!\n");	asm volatile("": : :"memory");	while(1);}void hang(const char *s, u_long x, ctxt *p) {	u_long *r1;#ifdef DEBUG	print_all_maps("\nMemory mappings at exception time:\n");#endif	printk("%s %lx NIP: %p LR: %p\n" 	       "Callback trace (stack:return address)\n",	       s, x, (void *) p->nip, (void *) p->lr);	asm volatile("lwz %0,0(1); lwz %0,0(%0); lwz %0,0(%0)": "=b" (r1));	while(r1) {		printk("  %p:%p\n", r1, (void *) r1[1]);		r1 = (u_long *) *r1;	}	exit();};void *zalloc(void *x, unsigned items, unsigned size){	void *p = salloc(items*size);	if (!p) {		printk("oops... not enough memory for gunzip\n");	}	return p;}void zfree(void *x, void *addr, unsigned nb){	sfree(addr);}#define HEAD_CRC	2#define EXTRA_FIELD	4#define ORIG_NAME	8#define COMMENT		0x10#define RESERVED	0xe0#define DEFLATED	8void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp){	z_stream s;	int r, i, flags;	/* skip header */	i = 10;	flags = src[3];	if (src[2] != DEFLATED || (flags & RESERVED) != 0) {		printk("bad gzipped data\n");		exit();	}	if ((flags & EXTRA_FIELD) != 0)		i = 12 + src[10] + (src[11] << 8);	if ((flags & ORIG_NAME) != 0)		while (src[i++] != 0)			;	if ((flags & COMMENT) != 0)		while (src[i++] != 0)			;	if ((flags & HEAD_CRC) != 0)		i += 2;	if (i >= *lenp) {		printk("gunzip: ran out of data in header\n");		exit();	}		s.zalloc = zalloc;	s.zfree = zfree;	r = inflateInit2(&s, -MAX_WBITS);	if (r != Z_OK) {		printk("inflateInit2 returned %d\n", r);		exit();	}	s.next_in = src + i;	s.avail_in = *lenp - i;	s.next_out = dst;	s.avail_out = dstlen;	r = inflate(&s, Z_FINISH);	if (r != Z_OK && r != Z_STREAM_END) {		printk("inflate returned %d\n", r);		exit();	}	*lenp = s.next_out - (unsigned char *) dst;	inflateEnd(&s);}void decompress_kernel(int kernel_size, void * zimage_start, int len, 		       void * initrd_start, int initrd_len ) {	u_char *parea; 	RESIDUAL* rescopy;	int zimage_size= len;	/* That's a mess, we have to copy the residual data twice just in	 * case it happens to be in the low memory area where the kernel	 * is going to be unpacked. Later we have to copy it back to	 * lower addresses because only the lowest part of memory is mapped	 * during boot.	 */	parea=__palloc(kernel_size, PA_LOW);	if(!parea) {		printk("Not enough memory to uncompress the kernel.");		exit();	}	/* Note that this clears the bss as a side effect, so some code	 * with ugly special case for SMP could be removed from the kernel! 	 */	memset(parea, 0, kernel_size);	printk("\nUncompressing the kernel...\n");	rescopy=salloc(sizeof(RESIDUAL));	/* Let us hope that residual data is aligned on word boundary */ 	*rescopy =  *bd->residual;	bd->residual = (void *)PAGE_ALIGN(kernel_size);	gunzip(parea, kernel_size, zimage_start, &zimage_size);	bd->of_entry = 0;	bd->load_address = 0;	bd->r6 = (char *)bd->residual+PAGE_ALIGN(sizeof(RESIDUAL));	bd->r7 = bd->r6+strlen(bd->cmd_line); 	if ( initrd_len ) {	  	/* We have to leave some room for the hash table and for the		 * whole array of struct page. The hash table would be better		 * located at the end of memory if possible. With some bridges		 * DMA from the last pages of memory is slower because		 * prefetching from PCI has to be disabled to avoid accessing		 * non existing memory. So it is the ideal place to put the		 * hash table. 		 */	        unsigned tmp = rescopy->TotalMemory;		/* It's equivalent to tmp & (-tmp), but using the negation		 * operator on unsigned variables looks so ugly.		 */		if ((tmp & (~tmp+1)) != tmp) tmp <<= 1; /* Next power of 2 */		tmp /= 256; /* Size of hash table */		if (tmp> (2<<20)) tmp=2<<20;		tmp = tmp*2 + 0x40000; /* Alignment can double size + 256 kB */		tmp += (rescopy->TotalMemory / PAGE_SIZE)		  	       * sizeof(struct page); 		bd->load_address = (void *)PAGE_ALIGN((int)bd->r7 + tmp); 		bd->of_entry = (char *)bd->load_address+initrd_len; 	}#ifdef DEBUG	printk("Kernel at 0x%p, size=0x%x\n", NULL, kernel_size); 	printk("Initrd at 0x%p, size=0x%x\n",bd->load_address, initrd_len);	printk("Residual data at 0x%p\n", bd->residual);	printk("Command line at 0x%p\n",bd->r6);#endif	printk("done\nNow booting...\n");	MMUoff();	/* We need to access address 0 ! */	codemove(0, parea, kernel_size, bd->cache_lsize);	codemove(bd->residual, rescopy, sizeof(RESIDUAL), bd->cache_lsize); 	codemove(bd->r6, bd->cmd_line, sizeof(bd->cmd_line), bd->cache_lsize);	/* codemove checks for 0 length */	codemove(bd->load_address, initrd_start, initrd_len, bd->cache_lsize);}static int ticks_per_ms=0;/* this is from rtems_bsp_delay from libcpu */voidboot_udelay(unsigned32 _microseconds){   unsigned32 start, ticks, now;   ticks = _microseconds * ticks_per_ms / 1000;   CPU_Get_timebase_low( start );   do {     CPU_Get_timebase_low( now );   } while (now - start < ticks);}void setup_hw(void){	char *cp, ch;	register RESIDUAL * res;	/* PPC_DEVICE * nvram; */	struct pci_dev *default_vga;	int timer, err;	u_short default_vga_cmd;	static unsigned int indic;		indic = 0;		res=bd->residual;	default_vga=NULL;	default_vga_cmd = 0;#define vpd res->VitalProductData	if (_read_PVR()>>16 != 1) {		if ( res && vpd.ProcessorBusHz ) {			ticks_per_ms = vpd.ProcessorBusHz/			    (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000);		} else {			ticks_per_ms = 16500; /* assume 66 MHz on bus */		}	}		select_console(CONSOLE_LOG);	/* We check that the keyboard is present and immediately 	 * select the serial console if not.	 */#if defined(BSP_KBD_IOBASE)	err = kbdreset();        if (err) select_console(CONSOLE_SERIAL);#else	err = 1;	select_console(CONSOLE_SERIAL);#endif	printk("\nModel: %s\nSerial: %s\n"	       "Processor/Bus frequencies (Hz): %ld/%ld\n"	       "Time Base Divisor: %ld\n"	       "Memory Size: %lx\n", 	       vpd.PrintableModel,	       vpd.Serial,	       vpd.ProcessorHz,               vpd.ProcessorBusHz,	       (vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000),	       res->TotalMemory);	/* This reconfigures all the PCI subsystem */        pci_init();		/* The Motorola NT firmware does not set the correct mem size */	if ( vpd.FirmwareSupplier == 0x10000 ) {		int memsize;		memsize = find_max_mem(bd->pci_devices);		if ( memsize != res->TotalMemory ) {			printk("Changed Memory size from %lx to %x\n",				res->TotalMemory, memsize);			res->TotalMemory = memsize;			res->GoodMemory = memsize;		}	}#define	ENABLE_VGA_USAGE#undef ENABLE_VGA_USAGE #ifdef ENABLE_VGA_USAGE	/* Find the primary VGA device, chosing the first one found	 * if none is enabled. The basic loop structure has been copied	 * from linux/drivers/char/bttv.c by Alan Cox.	 */	for (p = bd->pci_devices; p; p = p->next) {		u_short cmd;		if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&		    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))		  	continue;		if (p->bus->number != 0) {			printk("VGA device not on bus 0 not initialized!\n");			continue;		}		/* Only one can be active in text mode, which for now will		 * be assumed as equivalent to having I/O response enabled.		 */		pci_read_config_word(p, PCI_COMMAND, &cmd);		if(cmd & PCI_COMMAND_IO || !default_vga) {		  	default_vga=p;			default_vga_cmd=cmd;		}	}	/* Disable the enabled VGA device, if any. */	if (default_vga)		pci_write_config_word(default_vga, PCI_COMMAND, 				      default_vga_cmd&				      ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));	init_v86();	/* Same loop copied from bttv.c, this time doing the serious work */	for (p = bd->pci_devices; p; p = p->next) {		u_short cmd;		if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&		    ((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))		  	continue;		if (p->bus->number != 0) continue;		pci_read_config_word(p, PCI_COMMAND, &cmd); 		pci_write_config_word(p, PCI_COMMAND, 				      cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);		printk("Calling the emulator.\n");		em86_main(p);		pci_write_config_word(p, PCI_COMMAND, cmd);	}		cleanup_v86_mess();#endif		/* Reenable the primary VGA device */	if (default_vga) {		pci_write_config_word(default_vga, PCI_COMMAND, 				      default_vga_cmd|				      (PCI_COMMAND_IO|PCI_COMMAND_MEMORY));		if (err) { 			printk("Keyboard error %d, using serial console!\n", 			       err);		} else {			select_console(CONSOLE_VGA);		}	} else if (!err) {		select_console(CONSOLE_SERIAL);		if (bd->cmd_line[0] == '\0') {		  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);		}		else {		  int s = strlen (bd->cmd_line);		  bd->cmd_line[s + 1] = ' ';		  bd->cmd_line[s + 2] = '\0';		  strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);		}	}#if 0	/* In the future we may use the NVRAM to store default	 * kernel parameters.	 */	nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM, 				   ~0UL, 0);	if (nvram) {		PnP_TAG_PACKET * pkt;		switch (nvram->DevId.Interface) {			case IndirectNVRAM:			  pkt=PnP_find_packet(res->DevicePnpHeap				      +nvram->AllocatedOffset, 					      )		}	}#endif	printk("\nRTEMS 4.x/PPC load: ");	timer = 0;	cp = bd->cmd_line+strlen(bd->cmd_line);	while (timer++ < 5*1000) {		if (debug_tstc()) {			while ((ch = debug_getc()) != '\n' && ch != '\r') {				if (ch == '\b' || ch == 0177) {					if (cp != bd->cmd_line) {						cp--;						printk("\b \b");					}				} else {					*cp++ = ch;					debug_putc(ch);				}			}			break;  /* Exit 'timer' loop */		}		boot_udelay(1000);  /* 1 msec */	}	*cp = 0;}/* Functions to deal with the residual data */static int same_DevID(unsigned short vendor,	       unsigned short Number,	       char * str) {	static unsigned const char hexdigit[]="0123456789ABCDEF";	if (strlen(str)!=7) return 0;	if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&	     ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&	     ( (vendor&0x1f)+'A'-1 == str[2])        &&	     (hexdigit[(Number>>12)&0x0f] == str[3]) &&	     (hexdigit[(Number>>8)&0x0f] == str[4])  &&	     (hexdigit[(Number>>4)&0x0f] == str[5])  &&	     (hexdigit[Number&0x0f] == str[6]) ) return 1;	return 0;}PPC_DEVICE *residual_find_device(unsigned long BusMask,			 unsigned char * DevID,			 int BaseType,			 int SubType,			 int Interface,			 int n){	int i;	RESIDUAL *res = bd->residual;	if ( !res || !res->ResidualLength ) return NULL;	for (i=0; i<res->ActualNumDevices; i++) {#define Dev res->Devices[i].DeviceId		if ( (Dev.BusId&BusMask)                                  &&		     (BaseType==-1 || Dev.BaseType==BaseType)             &&		     (SubType==-1 || Dev.SubType==SubType)                &&		     (Interface==-1 || Dev.Interface==Interface)          &&		     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,						Dev.DevId&0xffff, DevID)) &&		     !(n--) ) return res->Devices+i;#undef Dev	}	return 0;}PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,				unsigned packet_tag,				int n){	unsigned mask, masked_tag, size;	if(!p) return 0;	if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;	masked_tag = packet_tag&mask;	for(; *p != END_TAG; p+=size) {		if ((*p & mask) == masked_tag && !(n--)) 			return (PnP_TAG_PACKET *) p;		if (tag_type(*p))			size=ld_le16((unsigned short *)(p+1))+3;		else 			size=tag_small_count(*p)+1;	}	return 0; /* not found */}PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,					     unsigned packet_type,					     int n){	int next=0;	while (p) {		p = (unsigned char *) PnP_find_packet(p, 0x70, next);		if (p && p[1]==packet_type && !(n--)) 			return (PnP_TAG_PACKET *) p;		next = 1;	};	return 0; /* not found */}PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,					   unsigned packet_type,					   int n){	int next=0;	while (p) {		p = (unsigned char *) PnP_find_packet(p, 0x84, next);		if (p && p[3]==packet_type && !(n--)) 			return (PnP_TAG_PACKET *) p;		next = 1;	};	return 0; /* not found */}/* Find out the amount of installed memory. For MPC105 and IBM 660 this * can be done by finding the bank with the highest memory ending address */intfind_max_mem( struct pci_dev *dev ){	u_char banks,tmp;	int i, top, max;	max = 0;	for ( ; dev; dev = dev->next) {		if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&		      (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||		     ((dev->vendor == PCI_VENDOR_ID_IBM) &&		      (dev->device == 0x0037/*IBM 660 Bridge*/)) ) {			pci_read_config_byte(dev, 0xa0, &banks); 			for (i = 0; i < 8; i++) {				if ( banks & (1<<i) ) {					pci_read_config_byte(dev, 0x90+i, &tmp); 					top = tmp;					pci_read_config_byte(dev, 0x98+i, &tmp); 					top |= (tmp&3)<<8;					if ( top > max ) max = top;				}			}			if ( max ) return ((max+1)<<20);			else return(0);		}	}	return(0);}

⌨️ 快捷键说明

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