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

📄 hwc_rw.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  drivers/s390/char/hwc_rw.c *     driver: reading from and writing to system console on S/390 via HWC * *  S390 version *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation *    Author(s): Martin Peschke <peschke@fh-brandenburg.de> * * * * * * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/ctype.h>#include <linux/mm.h>#include <linux/timer.h>#include <linux/bootmem.h>#include <asm/ebcdic.h>#include <asm/uaccess.h>#include <asm/types.h>#include <asm/bitops.h>#include <asm/setup.h>#include <asm/page.h>#ifndef MIN#define MIN(a,b) ((a<b) ? a : b)#endif#define HWC_RW_PRINT_HEADER "hwc low level driver: "#define  USE_VM_DETECTION#define  DEFAULT_CASE_DELIMITER '%'#define DUMP_HWC_INIT_ERROR#define DUMP_HWC_WRITE_ERROR#define DUMP_HWC_WRITE_LIST_ERROR#define DUMP_HWC_READ_ERROR#undef DUMP_HWCB_INPUT#undef BUFFER_STRESS_TESTtypedef struct {	unsigned char *next;	unsigned short int mto_char_sum;	unsigned char mto_number;	unsigned char times_lost;	unsigned short int mto_number_lost;	unsigned long int mto_char_sum_lost;} __attribute__ ((packed)) hwcb_list_t;#define MAX_HWCB_ROOM (PAGE_SIZE - sizeof(hwcb_list_t))#define MAX_MESSAGE_SIZE (MAX_HWCB_ROOM - sizeof(write_hwcb_t))#define BUF_HWCB hwc_data.hwcb_list_tail#define OUT_HWCB hwc_data.hwcb_list_head#define ALL_HWCB_MTO hwc_data.mto_number#define ALL_HWCB_CHAR hwc_data.mto_char_sum#define _LIST(hwcb) ((hwcb_list_t*)(&(hwcb)[PAGE_SIZE-sizeof(hwcb_list_t)]))#define _HWCB_CHAR(hwcb) (_LIST(hwcb)->mto_char_sum)#define _HWCB_MTO(hwcb) (_LIST(hwcb)->mto_number)#define _HWCB_CHAR_LOST(hwcb) (_LIST(hwcb)->mto_char_sum_lost)#define _HWCB_MTO_LOST(hwcb) (_LIST(hwcb)->mto_number_lost)#define _HWCB_TIMES_LOST(hwcb) (_LIST(hwcb)->times_lost)#define _HWCB_NEXT(hwcb) (_LIST(hwcb)->next)#define BUF_HWCB_CHAR _HWCB_CHAR(BUF_HWCB)#define BUF_HWCB_MTO _HWCB_MTO(BUF_HWCB)#define BUF_HWCB_NEXT _HWCB_NEXT(BUF_HWCB)#define OUT_HWCB_CHAR _HWCB_CHAR(OUT_HWCB)#define OUT_HWCB_MTO _HWCB_MTO(OUT_HWCB)#define OUT_HWCB_NEXT _HWCB_NEXT(OUT_HWCB)#define BUF_HWCB_CHAR_LOST _HWCB_CHAR_LOST(BUF_HWCB)#define BUF_HWCB_MTO_LOST _HWCB_MTO_LOST(BUF_HWCB)#define OUT_HWCB_CHAR_LOST _HWCB_CHAR_LOST(OUT_HWCB)#define OUT_HWCB_MTO_LOST _HWCB_MTO_LOST(OUT_HWCB)#define BUF_HWCB_TIMES_LOST _HWCB_TIMES_LOST(BUF_HWCB)#include  "hwc.h"#define __HWC_RW_C__#include "hwc_rw.h"#undef __HWC_RW_C__static unsigned char _obuf[MAX_HWCB_ROOM];static unsigned char _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));typedef u32 kmem_pages_t;#define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)#define HWC_TIMER_RUNS	1#define FLUSH_HWCBS	2static struct {	hwc_ioctls_t ioctls;	hwc_ioctls_t init_ioctls;	unsigned char *hwcb_list_head;	unsigned char *hwcb_list_tail;	unsigned short int mto_number;	unsigned int mto_char_sum;	unsigned char hwcb_count;	unsigned long kmem_start;	unsigned long kmem_end;	kmem_pages_t kmem_pages;	unsigned char *obuf;	unsigned short int obuf_cursor;	unsigned short int obuf_count;	unsigned short int obuf_start;	unsigned char *page;	u32 current_servc;	unsigned char *current_hwcb;	unsigned char write_nonprio:1;	unsigned char write_prio:1;	unsigned char read_nonprio:1;	unsigned char read_prio:1;	unsigned char flags;	spinlock_t lock;	struct timer_list write_timer;} hwc_data ={	{	},	{		8,		    0,		    80,		    CODE_ASCII,		    1,		    50,		    MAX_KMEM_PAGES,		    0,		    0x6c	},	    NULL,	    NULL,	    0,	    0,	    0,	    0,	    0,	    0,	    _obuf,	    0,	    0,	    0,	    _page,	    0,	    NULL,	    0,	    0,	    0,	    0,	    0};#define DELAYED_WRITE 0#define IMMEDIATE_WRITE 1static signed int do_hwc_write (int from_user, unsigned char *,				unsigned int,				unsigned char,				unsigned char);static asmlinkage int internal_print (char write_time, const char *fmt,...){	va_list args;	int i;	unsigned char buf[512];	va_start (args, fmt);	i = vsprintf (buf, fmt, args);	va_end (args);	return do_hwc_write (0, buf, i, CODE_ASCII, write_time);}int hwc_printk (const char *fmt,...){	va_list args;	int i;	unsigned char buf[512];	unsigned long flags;	int retval;	spin_lock_irqsave (&hwc_data.lock, flags);	i = vsprintf (buf, fmt, args);	va_end (args);	retval = do_hwc_write (0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);	spin_unlock_irqrestore (&hwc_data.lock, flags);	return retval;}#ifdef DUMP_HWCB_INPUTstatic void dump_storage_area (unsigned char *area, unsigned short int count){	unsigned short int index;	ioctl_nl_t old_final_nl;	if (!area || !count)		return;	old_final_nl = hwc_data.ioctls.final_nl;	hwc_data.ioctls.final_nl = 1;	internal_print (DELAYED_WRITE, "\n%8x   ", area);	for (index = 0; index < count; index++) {		if (area[index] <= 0xF)			internal_print (DELAYED_WRITE, "0%x", area[index]);		else			internal_print (DELAYED_WRITE, "%x", area[index]);		if ((index & 0xF) == 0xF)			internal_print (DELAYED_WRITE, "\n%8x   ",					&area[index + 1]);		else if ((index & 3) == 3)			internal_print (DELAYED_WRITE, " ");	}	internal_print (IMMEDIATE_WRITE, "\n");	hwc_data.ioctls.final_nl = old_final_nl;}#endifstatic inline u32 service_call (		     u32 hwc_command_word,		     unsigned char hwcb[]){	unsigned int condition_code = 1;	__asm__ __volatile__ ("L 1, 0(0,%0) \n\t"			      "LRA 2, 0(0,%1) \n\t"			      ".long 0xB2200012 \n\t"			      :			      :"a" (&hwc_command_word), "a" (hwcb)			      :"1", "2", "memory");	__asm__ __volatile__ ("IPM %0 \n\t"			      "SRL %0, 28 \n\t"			      :"=r" (condition_code));	return condition_code;}static inline unsigned char *ext_int_param (void){	u32 param;	__asm__ __volatile__ ("L %0,128(0,0)\n\t"			      :"=r" (param));	return ((unsigned char *) param);}static int prepare_write_hwcb (void){	write_hwcb_t *hwcb;	if (!BUF_HWCB)		return -ENOMEM;	BUF_HWCB_MTO = 0;	BUF_HWCB_CHAR = 0;	hwcb = (write_hwcb_t *) BUF_HWCB;	memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));	if (!hwc_data.write_nonprio && hwc_data.write_prio)		hwcb->msgbuf.type = ET_PMsgCmd;	return 0;}static int sane_write_hwcb (void){	unsigned short int lost_msg;	unsigned int lost_char;	unsigned char lost_hwcb;	unsigned char *bad_addr;	unsigned long page;	int page_nr;	if (!OUT_HWCB)		return -ENOMEM;	if ((unsigned long) OUT_HWCB & 0xFFF) {		bad_addr = OUT_HWCB;#ifdef DUMP_HWC_WRITE_LIST_ERROR		__asm__ ("LHI 1,0xe30\n\t"			 "LRA 2,0(0,%0) \n\t"			 "J .+0 \n\t"	      :	      :	 "a" (bad_addr)	      :	 "1", "2");#endif		hwc_data.kmem_pages = 0;		if ((unsigned long) BUF_HWCB & 0xFFF) {			lost_hwcb = hwc_data.hwcb_count;			lost_msg = ALL_HWCB_MTO;			lost_char = ALL_HWCB_CHAR;			OUT_HWCB = NULL;			BUF_HWCB = NULL;			ALL_HWCB_MTO = 0;			ALL_HWCB_CHAR = 0;			hwc_data.hwcb_count = 0;		} else {			lost_hwcb = hwc_data.hwcb_count - 1;			lost_msg = ALL_HWCB_MTO - BUF_HWCB_MTO;			lost_char = ALL_HWCB_CHAR - BUF_HWCB_CHAR;			OUT_HWCB = BUF_HWCB;			ALL_HWCB_MTO = BUF_HWCB_MTO;			ALL_HWCB_CHAR = BUF_HWCB_CHAR;			hwc_data.hwcb_count = 1;			page = (unsigned long) BUF_HWCB;			if (page >= hwc_data.kmem_start &&			    page < hwc_data.kmem_end) {				page_nr = (int)				    ((page - hwc_data.kmem_start) >> 12);				set_bit (page_nr, &hwc_data.kmem_pages);			}		}		internal_print (				       DELAYED_WRITE,				       HWC_RW_PRINT_HEADER			"found invalid HWCB at address 0x%x. List corrupted. "			   "Lost %i HWCBs with %i characters within up to %i "			   "messages. Saved %i HWCB with last %i characters i"				       "within up to %i messages.\n",				       (unsigned int) bad_addr,				       lost_hwcb, lost_char, lost_msg,				       hwc_data.hwcb_count,				       ALL_HWCB_CHAR, ALL_HWCB_MTO);	}	return 0;}static int reuse_write_hwcb (void){	int retval;	if (hwc_data.hwcb_count < 2)#ifdef DUMP_HWC_WRITE_LIST_ERROR		__asm__ ("LHI 1,0xe31\n\t"			 "LRA 2,0(0,%0)\n\t"			 "LRA 3,0(0,%1)\n\t"			 "J .+0 \n\t"	      :	      :	 "a" (BUF_HWCB), "a" (OUT_HWCB)	      :	 "1", "2", "3");#else		return -EPERM;#endif	if (hwc_data.current_hwcb == OUT_HWCB) {		if (hwc_data.hwcb_count > 2) {			BUF_HWCB_NEXT = OUT_HWCB_NEXT;			BUF_HWCB = OUT_HWCB_NEXT;			OUT_HWCB_NEXT = BUF_HWCB_NEXT;			BUF_HWCB_NEXT = NULL;		}	} else {		BUF_HWCB_NEXT = OUT_HWCB;		BUF_HWCB = OUT_HWCB;		OUT_HWCB = OUT_HWCB_NEXT;		BUF_HWCB_NEXT = NULL;	}	BUF_HWCB_TIMES_LOST += 1;	BUF_HWCB_CHAR_LOST += BUF_HWCB_CHAR;	BUF_HWCB_MTO_LOST += BUF_HWCB_MTO;	ALL_HWCB_MTO -= BUF_HWCB_MTO;	ALL_HWCB_CHAR -= BUF_HWCB_CHAR;	retval = prepare_write_hwcb ();	if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)		internal_print (				       DELAYED_WRITE,				       HWC_RW_PRINT_HEADER				       "reached my own limit of "			    "allowed buffer space for output (%i HWCBs = %li "			  "bytes), skipped content of oldest HWCB %i time(s) "				       "(%i lines = %i characters)\n",				       hwc_data.ioctls.max_hwcb,				       hwc_data.ioctls.max_hwcb * PAGE_SIZE,				       BUF_HWCB_TIMES_LOST,				       BUF_HWCB_MTO_LOST,				       BUF_HWCB_CHAR_LOST);	else		internal_print (				       DELAYED_WRITE,				       HWC_RW_PRINT_HEADER				       "page allocation failed, "			   "could not expand buffer for output (currently in "			     "use: %i HWCBs = %li bytes), skipped content of "			"oldest HWCB %i time(s) (%i lines = %i characters)\n",				       hwc_data.hwcb_count,				       hwc_data.hwcb_count * PAGE_SIZE,				       BUF_HWCB_TIMES_LOST,				       BUF_HWCB_MTO_LOST,				       BUF_HWCB_CHAR_LOST);	return retval;}static int allocate_write_hwcb (void){	unsigned char *page;	int page_nr;	if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)		return -ENOMEM;	page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES);	if (page_nr < hwc_data.ioctls.kmem_hwcb) {		page = (unsigned char *)		    (hwc_data.kmem_start + (page_nr << 12));		set_bit (page_nr, &hwc_data.kmem_pages);	} else		page = (unsigned char *) __get_free_page (GFP_ATOMIC);	if (!page)		return -ENOMEM;	if (!OUT_HWCB)		OUT_HWCB = page;	else		BUF_HWCB_NEXT = page;	BUF_HWCB = page;	BUF_HWCB_NEXT = NULL;	hwc_data.hwcb_count++;	prepare_write_hwcb ();	BUF_HWCB_TIMES_LOST = 0;	BUF_HWCB_MTO_LOST = 0;	BUF_HWCB_CHAR_LOST = 0;#ifdef BUFFER_STRESS_TEST	internal_print (			       DELAYED_WRITE,			       "*** " HWC_RW_PRINT_HEADER			    "page #%i at 0x%x for buffering allocated. ***\n",			       hwc_data.hwcb_count, page);#endif	return 0;}static int release_write_hwcb (void){	unsigned long page;	int page_nr;	if (!hwc_data.hwcb_count)		return -ENODATA;	if (hwc_data.hwcb_count == 1) {		prepare_write_hwcb ();		ALL_HWCB_CHAR = 0;		ALL_HWCB_MTO = 0;		BUF_HWCB_TIMES_LOST = 0;		BUF_HWCB_MTO_LOST = 0;		BUF_HWCB_CHAR_LOST = 0;	} else {		page = (unsigned long) OUT_HWCB;		ALL_HWCB_MTO -= OUT_HWCB_MTO;		ALL_HWCB_CHAR -= OUT_HWCB_CHAR;		hwc_data.hwcb_count--;		OUT_HWCB = OUT_HWCB_NEXT;		if (page >= hwc_data.kmem_start &&		    page < hwc_data.kmem_end) {			memset ((void *) page, 0, PAGE_SIZE);			page_nr = (int) ((page - hwc_data.kmem_start) >> 12);			clear_bit (page_nr, &hwc_data.kmem_pages);		} else			free_page (page);#ifdef BUFFER_STRESS_TEST		internal_print (				       DELAYED_WRITE,				       "*** " HWC_RW_PRINT_HEADER			 "page at 0x%x released, %i pages still in use ***\n",				       page, hwc_data.hwcb_count);#endif	}	return 0;}static int add_mto (		unsigned char *message,		unsigned short int count){	unsigned short int mto_size;	write_hwcb_t *hwcb;	mto_t *mto;	void *dest;	if (!BUF_HWCB)		return -ENOMEM;	if (BUF_HWCB == hwc_data.current_hwcb)		return -ENOMEM;	mto_size = sizeof (mto_t) + count;	hwcb = (write_hwcb_t *) BUF_HWCB;	if ((MAX_HWCB_ROOM - hwcb->length) < mto_size)		return -ENOMEM;	mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length);	memcpy (mto, &mto_template, sizeof (mto_t));	dest = (void *) (((unsigned long) mto) + sizeof (mto_t));	memcpy (dest, message, count);	mto->length += count;	hwcb->length += mto_size;	hwcb->msgbuf.length += mto_size;	hwcb->msgbuf.mdb.length += mto_size;	BUF_HWCB_MTO++;	ALL_HWCB_MTO++;	BUF_HWCB_CHAR += count;	ALL_HWCB_CHAR += count;	return count;}static int write_event_data_1 (void){	unsigned short int condition_code;	int retval;	if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio))		return -EPERM;	if (hwc_data.current_servc)		return -EBUSY;	retval = sane_write_hwcb ();	if (retval < 0)		return retval;	if (!OUT_HWCB_MTO)		return -ENODATA;	condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);#ifdef DUMP_HWC_WRITE_ERROR	if (condition_code != HWC_COMMAND_INITIATED)		__asm__ ("LHI 1,0xe20\n\t"			 "L 2,0(0,%0)\n\t"			 "LRA 3,0(0,%1)\n\t"			 "J .+0 \n\t"	      :	      :	 "a" (&condition_code), "a" (OUT_HWCB)	      :	 "1", "2", "3");#endif

⌨️ 快捷键说明

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