From ee671d4ef86346e8d10cd0474aad998c16aa0383 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 2 May 2011 10:46:14 -0700 Subject: Implement the console callback interface. At least enough for GETC and PUTS. --- Makefile | 3 +- console.h | 61 +++++++++++++++ crb.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hwrpb.h | 11 +-- init.c | 44 ++++++----- protos.h | 8 ++ uart.c | 4 +- uart.h | 2 + 8 files changed, 362 insertions(+), 30 deletions(-) create mode 100644 console.h create mode 100644 crb.c diff --git a/Makefile b/Makefile index f62888f..71ce4ae 100644 --- a/Makefile +++ b/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 diff --git a/console.h b/console.h new file mode 100644 index 0000000..98ac015 --- /dev/null +++ b/console.h @@ -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 + . */ + +#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 */ diff --git a/crb.c b/crb.c new file mode 100644 index 0000000..c79d4b2 --- /dev/null +++ b/crb.c @@ -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 + . */ + +#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" +); diff --git a/hwrpb.h b/hwrpb.h index 134bbb0..2166bad 100644 --- a/hwrpb.h +++ b/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 */ diff --git a/init.c b/init.c index 9827bee..59da517 100644 --- a/init.c +++ b/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 diff --git a/protos.h b/protos.h index 653696d..901fe3a 100644 --- a/protos.h +++ b/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 */ diff --git a/uart.c b/uart.c index 2e93482..56e1cc7 100644 --- a/uart.c +++ b/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; diff --git a/uart.h b/uart.h index 48cceef..bb47b0c 100644 --- a/uart.h +++ b/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__ */ -- cgit v1.1