mirror of
				https://gitlab.com/qemu-project/qemu-palcode.git
				synced 2024-02-13 08:32:59 +08:00 
			
		
		
		
	Implement the console callback interface.
At least enough for GETC and PUTS.
This commit is contained in:
		
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							| @ -12,7 +12,7 @@ CPPFLAGS = -DSYSTEM_H='"sys-$(SYSTEM).h"' | ||||
|  | ||||
| CFLAGS += -mcpu=ev67 | ||||
|  | ||||
| OBJS = pal.o sys-$(SYSTEM).o init.o uart.o memset.o printf.o | ||||
| OBJS = pal.o sys-$(SYSTEM).o init.o crb.o uart.o memset.o printf.o | ||||
|  | ||||
| all: palcode-$(SYSTEM) | ||||
|  | ||||
| @ -27,3 +27,4 @@ pal.o: pal.S osf.h sys-$(SYSTEM).h core-$(CORE).h | ||||
| init.o: init.c hwrpb.h osf.h uart.h sys-$(SYSTEM).h core-$(CORE).h | ||||
| printf.o: printf.c uart.h | ||||
| uart.o: uart.c uart.h protos.h | ||||
| crb.o: crb.c hwrpb.h protos.h console.h uart.h | ||||
|  | ||||
							
								
								
									
										61
									
								
								console.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								console.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| /* Console Callback Routines. | ||||
|  | ||||
|    Copyright (C) 2011 Richard Henderson | ||||
|  | ||||
|    This file is part of QEMU PALcode. | ||||
|  | ||||
|    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. | ||||
|  | ||||
|    This program is distributed in the hope that it will be useful, | ||||
|    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the text | ||||
|    of the GNU General Public License for more details. | ||||
|  | ||||
|    You should have received a copy of the GNU General Public License | ||||
|    along with this program; see the file COPYING.  If not see | ||||
|    <http://www.gnu.org/licenses/>.  */ | ||||
|  | ||||
| #ifndef CONSOLE_H | ||||
| #define CONSOLE_H 1 | ||||
|  | ||||
| #define CRB_GETC		0x01 | ||||
| #define CRB_PUTS		0x02 | ||||
| #define CRB_RESET_TERM		0x03 | ||||
| #define CRB_SET_TERM_INT	0x04 | ||||
| #define CRB_SET_TERM_CTL	0x05 | ||||
| #define CRB_PROCESS_KEYCODE	0x06 | ||||
|  | ||||
| #define CRB_OPEN		0x10 | ||||
| #define CRB_CLOSE		0x11 | ||||
| #define CRB_IOCTL		0x12 | ||||
| #define CRB_READ		0x13 | ||||
| #define CRB_WRITE		0x14 | ||||
|  | ||||
| #define CRB_SET_ENV		0x20 | ||||
| #define CRB_RESET_ENV		0x21 | ||||
| #define CRB_GET_ENV		0x22 | ||||
| #define CRB_SAVE_ENV		0x23 | ||||
|  | ||||
| #define CRB_PSWITCH		0x30 | ||||
|  | ||||
| extern unsigned long crb_getc(long unit); | ||||
| extern unsigned long crb_process_keycode(long unit, long keycode, long again); | ||||
| extern unsigned long crb_puts(long unit, const char *buf, unsigned long length); | ||||
| extern unsigned long crb_reset_term(long unit); | ||||
|  | ||||
| extern unsigned long crb_open(const char *devstr,  unsigned long length); | ||||
| extern unsigned long crb_close(long channel); | ||||
| extern unsigned long crb_read(long channel, unsigned long length, | ||||
|                               char *buf, unsigned long block); | ||||
| extern unsigned long crb_write(long channel, unsigned long length, | ||||
|                                const char *buf, unsigned long block); | ||||
|  | ||||
| extern unsigned long crb_get_env(unsigned long id, char *buf, | ||||
|                                  unsigned long length); | ||||
| extern unsigned long crb_set_env(unsigned long id, const char *buf, | ||||
|                                  unsigned long length); | ||||
|  | ||||
| #endif /* CONSOLE_H */ | ||||
							
								
								
									
										259
									
								
								crb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								crb.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,259 @@ | ||||
| /* Console Callback Routines. | ||||
|  | ||||
|    Copyright (C) 2011 Richard Henderson | ||||
|  | ||||
|    This file is part of QEMU PALcode. | ||||
|  | ||||
|    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. | ||||
|  | ||||
|    This program is distributed in the hope that it will be useful, | ||||
|    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the text | ||||
|    of the GNU General Public License for more details. | ||||
|  | ||||
|    You should have received a copy of the GNU General Public License | ||||
|    along with this program; see the file COPYING.  If not see | ||||
|    <http://www.gnu.org/licenses/>.  */ | ||||
|  | ||||
| #include "hwrpb.h" | ||||
| #include "protos.h" | ||||
| #include "console.h" | ||||
| #include "uart.h" | ||||
|  | ||||
|  | ||||
| /* All routines use the high bit to signal error.  */ | ||||
| #define ERR	0x8000000000000000ul | ||||
|  | ||||
|  | ||||
| unsigned long | ||||
| crb_getc(long unit) | ||||
| { | ||||
|   /* Multiple consoles not yet supported.  */ | ||||
|   if (unit != 0) | ||||
|     return ERR; | ||||
|  | ||||
|   return uart_getchar(COM1); | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_process_keycode(long unit, long keycode, long again) | ||||
| { | ||||
|   /* This routine might be needed for real keyboards, and mostly for | ||||
|      internationalization stuff.  */ | ||||
|   /* Return Failure: routine not supported.  */ | ||||
|   return 0xc000000000000000ul; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_puts(long unit, const char *buf, unsigned long length) | ||||
| { | ||||
|   unsigned int orig_length = length; | ||||
|  | ||||
|   /* Multiple consoles not yet supported.  */ | ||||
|   if (unit != 0) | ||||
|     return ERR; | ||||
|  | ||||
|   for (; length != 0; --length, ++buf) | ||||
|     uart_putchar_raw(COM1, (unsigned char)*buf); | ||||
|  | ||||
|   /* Bits <31:0> of the return value are the number of bytes written. | ||||
|      To me that implies that the input value must be 32-bit, but v2 | ||||
|      of the ARM doesn't explicitly say.  */ | ||||
|   return orig_length; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_reset_term(long unit) | ||||
| { | ||||
|   /* Multiple consoles not yet supported.  */ | ||||
|   if (unit != 0) | ||||
|     return ERR; | ||||
|  | ||||
|   uart_init_line(COM1, 9600); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static unsigned long | ||||
| crb_set_term_ctl(long unit, long ctb) | ||||
| { | ||||
|   /* ??? The contents of the CTB do not seem to be defined anywhere. | ||||
|      How, therefore, can the user set new contents?  */ | ||||
|   return ERR; | ||||
| } | ||||
|  | ||||
| static unsigned long | ||||
| crb_set_term_int(long unit, long mask) | ||||
| { | ||||
|   /* We do no buffering, therefore we don't need to support interrupts.  */ | ||||
|   if (unit != 0 || (mask & 0x22) != 0) | ||||
|     return ERR; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_open(const char *devstr,  unsigned long length) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return ERR; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_close(long channel) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static unsigned long | ||||
| crb_ioctl(long channel) | ||||
| { | ||||
|   /* We do not, nor will not, support virtual tapes.  */ | ||||
|   return ERR; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_read(long channel, unsigned long length, char *buf, unsigned long block) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return ERR; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_write(long channel, unsigned long length, const char *buf, | ||||
|           unsigned long block) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return ERR; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_get_env(unsigned long id, char *buf, unsigned long length) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return 0xc000000000000000ul; | ||||
| } | ||||
|  | ||||
| unsigned long | ||||
| crb_set_env(unsigned long id, const char *buf, unsigned long length) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return 0xc000000000000000ul; | ||||
| } | ||||
|  | ||||
| static unsigned long | ||||
| crb_reset_env(unsigned long id, char *buf, unsigned long length) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return 0xc000000000000000ul; | ||||
| } | ||||
|  | ||||
| static unsigned long | ||||
| crb_save_env(void) | ||||
| { | ||||
|   /* FIXME */ | ||||
|   return 0xc000000000000000ul; | ||||
| } | ||||
|  | ||||
| static unsigned long | ||||
| crb_pswitch(long action, long cpu_id) | ||||
| { | ||||
|   /* Why would we ever need to support switching primary processor?  */ | ||||
|   return ERR; | ||||
| } | ||||
|  | ||||
| static unsigned long __attribute__((used)) | ||||
| int_crb_dispatch(long select, long a1, long a2, long a3, long a4) | ||||
| { | ||||
|   switch (select) | ||||
|     { | ||||
|     case CRB_GETC: | ||||
|       return crb_getc(a1); | ||||
|     case CRB_PUTS: | ||||
|       return crb_puts(a1, (const char *)a2, a3); | ||||
|     case CRB_RESET_TERM: | ||||
|       return crb_reset_term(a1); | ||||
|     case CRB_SET_TERM_INT: | ||||
|       return crb_set_term_int(a1, a2); | ||||
|     case CRB_SET_TERM_CTL: | ||||
|       return crb_set_term_ctl(a1, a2); | ||||
|     case CRB_PROCESS_KEYCODE: | ||||
|       return crb_process_keycode(a1, a2, a3); | ||||
|  | ||||
|     case CRB_OPEN: | ||||
|       return crb_open((const char*)a1, a2); | ||||
|     case CRB_CLOSE: | ||||
|       return crb_close(a1); | ||||
|     case CRB_IOCTL: | ||||
|       return crb_ioctl(a1); | ||||
|     case CRB_READ: | ||||
|       return crb_read(a1, a2, (char *)a3, a4); | ||||
|     case CRB_WRITE: | ||||
|       return crb_write(a1, a2, (const char *)a3, a4); | ||||
|  | ||||
|     case CRB_SET_ENV: | ||||
|       return crb_set_env(a1, (const char *)a2, a3); | ||||
|     case CRB_RESET_ENV: | ||||
|       return crb_reset_env(a1, (char *)a2, a3); | ||||
|     case CRB_GET_ENV: | ||||
|       return crb_get_env(a1, (char *)a2, a3); | ||||
|     case CRB_SAVE_ENV: | ||||
|       return crb_save_env(); | ||||
|  | ||||
|     case CRB_PSWITCH: | ||||
|       return crb_pswitch(a1, a2); | ||||
|     } | ||||
|   return ERR; | ||||
| } | ||||
|  | ||||
| static unsigned long __attribute__((used)) | ||||
| int_crb_fixup(unsigned long vptptr, unsigned long hwrpb) | ||||
| { | ||||
|   /* Given that this console is written to use the KSEG, and not be | ||||
|      mapped into any page-table address space, it doesn't seem like | ||||
|      we need to do anything at all here.  */ | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* The CRB DISPATCH and FIXUP functions are defined to use the VMS | ||||
|    calling convention.  This has several effects:  | ||||
|      (1) The set of call-saved registers is different. | ||||
|      (2) $27 contains the procdesc_struct, not the called function. | ||||
|    Map between the two calling conventions here.  */ | ||||
|  | ||||
| asm(".macro	VMStoUNIX name\n" | ||||
| "	.globl	\\name\n" | ||||
| "	.ent	\\name\n" | ||||
| "\\name:\n" | ||||
| "	.frame	$sp, 64, $26, 0\n" | ||||
| "	subq	$sp, 64, $sp\n" | ||||
| "	stq	$26, 0($sp)\n" | ||||
| "	stq	$2, 8($sp)\n" | ||||
| "	stq	$3, 16($sp)\n" | ||||
| "	stq	$4, 24($sp)\n" | ||||
| "	stq	$5, 32($sp)\n" | ||||
| "	stq	$6, 40($sp)\n" | ||||
| "	stq	$7, 48($sp)\n" | ||||
| "	stq	$8, 56($sp)\n" | ||||
| "	.mask	0x40001fc, 0\n" | ||||
| "	.prologue 2\n" | ||||
| "	br	$gp, .+4\n" | ||||
| "	ldgp	$gp, 0($gp)\n" | ||||
| "	bsr	$26, int_\\name !samegp\n" | ||||
| "	ldq	$26, 0($sp)\n" | ||||
| "	ldq	$2, 8($sp)\n" | ||||
| "	ldq	$3, 16($sp)\n" | ||||
| "	ldq	$4, 24($sp)\n" | ||||
| "	ldq	$5, 32($sp)\n" | ||||
| "	ldq	$6, 40($sp)\n" | ||||
| "	ldq	$7, 48($sp)\n" | ||||
| "	ldq	$8, 56($sp)\n" | ||||
| "	addq	$sp, 64, $sp\n" | ||||
| "	ret\n" | ||||
| "	.end	\\name\n" | ||||
| ".endm\n" | ||||
| "	VMStoUNIX	crb_dispatch\n" | ||||
| "	VMStoUNIX	crb_fixup\n" | ||||
| ); | ||||
							
								
								
									
										11
									
								
								hwrpb.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								hwrpb.h
									
									
									
									
									
								
							| @ -130,16 +130,16 @@ struct procdesc_struct { | ||||
| }; | ||||
|  | ||||
| struct vf_map_struct { | ||||
| 	unsigned long va; | ||||
| 	void *va; | ||||
| 	unsigned long pa; | ||||
| 	unsigned long count; | ||||
| }; | ||||
|  | ||||
| struct crb_struct { | ||||
| 	struct procdesc_struct * dispatch_va; | ||||
| 	struct procdesc_struct * dispatch_pa; | ||||
| 	unsigned long dispatch_pa; | ||||
| 	struct procdesc_struct * fixup_va; | ||||
| 	struct procdesc_struct * fixup_pa; | ||||
| 	unsigned long fixup_pa; | ||||
| 	/* virtual->physical map */ | ||||
| 	unsigned long map_entries; | ||||
| 	unsigned long map_pages; | ||||
| @ -211,9 +211,6 @@ struct hwrpb_struct { | ||||
| 	unsigned long dsr_offset;	/* "Dynamic System Recognition Data Block Table" */ | ||||
| }; | ||||
|  | ||||
| #ifdef __KERNEL__ | ||||
|  | ||||
| extern struct hwrpb_struct *hwrpb; | ||||
|  | ||||
| static inline void | ||||
| hwrpb_update_checksum(struct hwrpb_struct *h) | ||||
| @ -224,6 +221,4 @@ hwrpb_update_checksum(struct hwrpb_struct *h) | ||||
|         h->chksum = sum; | ||||
| } | ||||
|  | ||||
| #endif /* __KERNEL__ */ | ||||
|  | ||||
| #endif /* __ALPHA_HWRPB_H */ | ||||
|  | ||||
							
								
								
									
										44
									
								
								init.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								init.c
									
									
									
									
									
								
							| @ -23,6 +23,7 @@ | ||||
| #include "hwrpb.h" | ||||
| #include "osf.h" | ||||
| #include "uart.h" | ||||
| #include "protos.h" | ||||
| #include SYSTEM_H | ||||
|  | ||||
| #define PAGE_SHIFT	13 | ||||
| @ -41,6 +42,9 @@ struct hwrpb_combine { | ||||
|   struct percpu_struct processor; | ||||
|   struct memdesc_struct md; | ||||
|   struct memclust_struct mc[2]; | ||||
|   struct crb_struct crb; | ||||
|   struct procdesc_struct proc_dispatch; | ||||
|   struct procdesc_struct proc_fixup; | ||||
| }; | ||||
|  | ||||
| extern char stack[PAGE_SIZE] __attribute__((section(".sbss"))); | ||||
| @ -53,7 +57,7 @@ static unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE))); | ||||
| /* The HWRPB must be aligned because it is exported at INIT_HWRPB.  */ | ||||
| struct hwrpb_combine hwrpb __attribute__((aligned(PAGE_SIZE))); | ||||
|  | ||||
| static void *last_alloc; | ||||
| void *last_alloc; | ||||
|  | ||||
| static void * | ||||
| alloc (unsigned long size, unsigned long align) | ||||
| @ -147,18 +151,10 @@ init_hwrpb (unsigned long memsize) | ||||
|  | ||||
|   hwrpb.hwrpb.size = sizeof(struct hwrpb_struct); | ||||
|  | ||||
|   /* The inclusion of MILO here tells the Linux kernel that we do | ||||
|      not (yet) support any of the extended console support routines | ||||
|      that are in SRM.  */ | ||||
|   ((int *)hwrpb.hwrpb.ssn)[0] = ( 'M' << 0 | ||||
| 				| 'I' << 8 | ||||
| 				| 'L' << 16 | ||||
| 				| 'O' << 24); | ||||
|   ((int *)hwrpb.hwrpb.ssn)[1] = ( ' ' << 0 | ||||
| 				| 'Q' << 8 | ||||
| 				| 'E' << 16 | ||||
| 				| 'M' << 24); | ||||
|   ((int *)hwrpb.hwrpb.ssn)[2] = ( 'U' << 0); | ||||
|   ((int *)hwrpb.hwrpb.ssn)[0] = ( 'Q' << 0 | ||||
| 				| 'E' << 8 | ||||
| 				| 'M' << 16 | ||||
| 				| 'U' << 24); | ||||
|  | ||||
|   amask = ~__builtin_alpha_amask(-1); | ||||
|   switch (__builtin_alpha_implver()) | ||||
| @ -208,12 +204,22 @@ init_hwrpb (unsigned long memsize) | ||||
|   hwrpb.mc[1].start_pfn = pal_pages; | ||||
|   hwrpb.mc[1].numpages = (memsize >> PAGE_SHIFT) - pal_pages; | ||||
|  | ||||
|   { | ||||
|     unsigned long sum = 0, *l; | ||||
|     for (l = (unsigned long *) &hwrpb.hwrpb; l < &hwrpb.hwrpb.chksum; ++l) | ||||
|       sum += *l; | ||||
|     hwrpb.hwrpb.chksum = sum; | ||||
|   } | ||||
|   hwrpb.hwrpb.crb_offset = offsetof(struct hwrpb_combine, crb); | ||||
|   hwrpb.crb.dispatch_va = &hwrpb.proc_dispatch; | ||||
|   hwrpb.crb.dispatch_pa = PA(&hwrpb.proc_dispatch); | ||||
|   hwrpb.crb.fixup_va = &hwrpb.proc_fixup; | ||||
|   hwrpb.crb.fixup_pa = PA(&hwrpb.proc_fixup); | ||||
|   hwrpb.crb.map_entries = 1; | ||||
|   hwrpb.crb.map_pages = 1; | ||||
|   hwrpb.crb.map[0].va = &hwrpb; | ||||
|   hwrpb.crb.map[0].pa = PA(&hwrpb); | ||||
|   hwrpb.crb.map[0].count = 1; | ||||
|  | ||||
|   /* See crb.c for how we match the VMS calling conventions to Unix.  */ | ||||
|   hwrpb.proc_dispatch.address = (unsigned long)crb_dispatch; | ||||
|   hwrpb.proc_fixup.address = (unsigned long)crb_fixup; | ||||
|  | ||||
|   hwrpb_update_checksum(&hwrpb.hwrpb); | ||||
| } | ||||
|  | ||||
| static void | ||||
|  | ||||
							
								
								
									
										8
									
								
								protos.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								protos.h
									
									
									
									
									
								
							| @ -59,4 +59,12 @@ static inline unsigned long stq_p(unsigned long port, unsigned long val) | ||||
| extern unsigned long inb(unsigned long port); | ||||
| extern unsigned long outb(unsigned char val, unsigned long port); | ||||
|  | ||||
| /* | ||||
|  * CRB functions | ||||
|  */ | ||||
|  | ||||
| extern unsigned long crb_dispatch(long select, long a1, long a2, | ||||
|                                   long a3, long a4); | ||||
| extern unsigned long crb_fixup(unsigned long vptptr, unsigned long hwrpb); | ||||
|  | ||||
| #endif /* PROTOS_H */ | ||||
|  | ||||
							
								
								
									
										4
									
								
								uart.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								uart.c
									
									
									
									
									
								
							| @ -51,7 +51,7 @@ uart_getchar(int offset) | ||||
| 	return inb(com2Rbr + offset); | ||||
| } | ||||
|  | ||||
| static void | ||||
| void | ||||
| uart_putchar_raw(int offset, char c) | ||||
| { | ||||
| 	while ((inb(com2Lsr + offset) & 0x20) == 0) | ||||
| @ -74,7 +74,7 @@ uart_puts(int offset, const char *s) | ||||
| 		uart_putchar(offset, *s++); | ||||
| } | ||||
|  | ||||
| static void | ||||
| void | ||||
| uart_init_line(int offset, int baud) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
							
								
								
									
										2
									
								
								uart.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								uart.h
									
									
									
									
									
								
							| @ -57,8 +57,10 @@ your own risk. | ||||
|  | ||||
| extern int uart_charav(int port); | ||||
| extern int uart_getchar(int port); | ||||
| extern void uart_putchar_raw(int port, char c); | ||||
| extern void uart_putchar(int port, char c); | ||||
| extern void uart_puts(int port, const char *s); | ||||
| extern void uart_init_line(int port, int baud); | ||||
| extern void uart_init(void); | ||||
|  | ||||
| #endif /* __ASSEMBLER__ */ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Richard Henderson
					Richard Henderson