URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/uclinux/uClinux-2.0.x/arch/i960
- from Rev 199 to Rev 1765
- ↔ Reverse comparison
Rev 199 → Rev 1765
/empty.c
0,0 → 1,4
|
/* This file is necessary to produce an "empty" .o file */ |
|
extern int foo; |
/kernel/time.c
0,0 → 1,169
/* |
* linux/arch/i960/kernel/time.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Based on: |
* |
* linux/arch/m68knommu/kernel/time.c |
* |
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, |
* Kenneth Albanowski <kjahds@kjahds.com>, |
* The Silver Hammer Group, Ltd. |
* |
* Copied/hacked from: |
* |
* linux/arch/m68k/kernel/time.c |
* |
* Copyright (C) 1991, 1992, 1995 Linus Torvalds |
* |
* This file contains the i960-specific time handling details. |
*/ |
|
#include <linux/config.h> |
#include <linux/errno.h> |
#include <linux/sched.h> |
#include <linux/kernel.h> |
#include <linux/param.h> |
#include <linux/string.h> |
#include <linux/mm.h> |
|
#include <asm/machdep.h> |
#include <asm/segment.h> |
#include <asm/io.h> |
|
#include <linux/timex.h> |
|
|
/* |
* XXX: bloody hell. We need to have figured out our machine's MHZ, and |
* programmed its clock accordingly. |
*/ |
static inline int set_rtc_mmss(unsigned long nowtime) |
{ |
return -1; |
} |
|
int do_reboot = 0; |
|
/* |
* timer_interrupt() needs to keep up the real-time clock, |
* as well as call the "do_timer()" routine every clocktick |
*/ |
void timer_interrupt(struct pt_regs * regs) |
{ |
/* last time the cmos clock got updated */ |
static long last_rtc_update=0; |
|
do_timer(regs); |
|
/* |
* If we have an externally synchronized Linux clock, then update |
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be |
* called as close as possible to 500 ms before the new second starts. |
*/ |
if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && |
xtime.tv_usec > 500000 - (tick >> 1) && |
xtime.tv_usec < 500000 + (tick >> 1)) |
if (set_rtc_mmss(xtime.tv_sec) == 0) |
last_rtc_update = xtime.tv_sec; |
else |
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ |
|
} |
|
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. |
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59 |
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59. |
* |
* [For the Julian calendar (which was used in Russia before 1917, |
* Britain & colonies before 1752, anywhere else before 1582, |
* and is still in use by some communities) leave out the |
* -year/100+year/400 terms, and add 10.] |
* |
* This algorithm was first published by Gauss (I think). |
* |
* WARNING: this function will overflow on 2106-02-07 06:28:16 on |
* machines were long is 32-bit! (However, as time_t is signed, we |
* will already get problems at other places on 2038-01-19 03:14:08) |
*/ |
static inline unsigned long mktime(unsigned int year, unsigned int mon, |
unsigned int day, unsigned int hour, |
unsigned int min, unsigned int sec) |
{ |
if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ |
mon += 12; /* Puts Feb last since it has leap day */ |
year -= 1; |
} |
return ((( |
(unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + |
year*365 - 719499 |
)*24 + hour /* now have hours */ |
)*60 + min /* now have minutes */ |
)*60 + sec; /* finally seconds */ |
} |
|
void time_init(void) |
{ |
unsigned int year, mon, day, hour, min, sec; |
|
extern void arch_gettod(int *year, int *mon, int *day, int *hour, |
int *min, int *sec); |
|
arch_gettod (&year, &mon, &day, &hour, &min, &sec); |
|
if ((year += 1900) < 1970) |
year += 100; |
xtime.tv_sec = mktime(year, mon, day, hour, min, sec); |
xtime.tv_usec = 0; |
|
#ifdef CONFIG_M68328 |
(*((volatile unsigned short*)0xFFFFF610)) = /*0x1000;*/ 0xd7e4; |
(*((volatile unsigned short*)0xFFFFF60c)) = 0x33; /* Reset */ |
(*((volatile unsigned short*)0xFFFFF60e)) = 0x2; /* divider */ |
(*((volatile unsigned long*)0xFFFFF304)) &= ~2; /* Enable interrupt */ |
#endif |
#ifdef CONFIG_M68332 |
*(volatile unsigned short *)0xfffa22 = 0x0140; /* ipl 6, vec 0x40 */ |
*(volatile unsigned short *)0xfffa24 = 0x00a3; /* 50 Hz */ |
#endif |
} |
|
/* |
* This version of gettimeofday has near microsecond resolution. |
*/ |
void do_gettimeofday(struct timeval *tv) |
{ |
unsigned long flags; |
|
save_flags(flags); |
cli(); |
*tv = xtime; |
restore_flags(flags); |
} |
|
void do_settimeofday(struct timeval *tv) |
{ |
cli(); |
/* This is revolting. We need to set the xtime.tv_usec |
* correctly. However, the value in this location is |
* is value at the last tick. |
* Discover what correction gettimeofday |
* would have done, and then undo it! |
*/ |
#if 0 |
tv->tv_usec -= mach_gettimeoffset(); |
#endif |
|
if (tv->tv_usec < 0) { |
tv->tv_usec += 1000000; |
tv->tv_sec--; |
} |
|
xtime = *tv; |
time_state = TIME_BAD; |
time_maxerror = MAXPHASE; |
time_esterror = MAXPHASE; |
sti(); |
} |
/kernel/setup.c
0,0 → 1,185
/* |
* linux/arch/i960/kernel/setup.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu>, |
* Erik Walthinsen <omega@cse.ogi.edu> |
* |
* Copied/hacked from code by: |
* |
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, |
* Kenneth Albanowski <kjahds@kjahds.com> |
* The Silver Hammer Group, Ltd. |
* |
* linux/arch/m68k/kernel/setup.c |
* |
* Copyright (C) 1995 Hamish Macdonald |
*/ |
|
/* |
* This file handles the architecture-dependent parts of system setup |
*/ |
|
#include <linux/config.h> |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/delay.h> |
#include <linux/interrupt.h> |
#include <linux/fs.h> |
#include <linux/fb.h> |
#include <linux/console.h> |
#include <linux/genhd.h> |
#include <linux/errno.h> |
#include <linux/string.h> |
#include <linux/major.h> |
|
#include <asm/setup.h> |
#include <asm/irq.h> |
#include <asm/machdep.h> |
|
#ifdef CONFIG_BLK_DEV_INITRD |
#include <linux/blk.h> |
#include <asm/pgtable.h> |
#endif |
|
|
extern int end; |
/* FIXME this needs to be looked into */ |
unsigned long availmem = 1024*1024; |
|
unsigned long rom_length; |
unsigned long memory_start; |
unsigned long memory_end; |
char command_line[512]; |
char saved_command_line[512]; |
|
/* setup some dummy routines */ |
static void dummy_waitbut(void) |
{ |
} |
|
/* machine dependent keyboard functions */ |
int (*mach_keyb_init) (void); |
int (*mach_kbdrate) (struct kbd_repeat *) = NULL; |
void (*mach_kbd_leds) (unsigned int) = NULL; |
/* machine dependent irq functions */ |
void (*mach_init_IRQ) (void); |
void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; |
int (*mach_request_irq) (unsigned int, void (*)(int, void *, struct pt_regs *), |
unsigned long, const char *, void *); |
int (*mach_free_irq) (unsigned int, void *); |
void (*mach_enable_irq) (unsigned int) = NULL; |
void (*mach_disable_irq) (unsigned int) = NULL; |
int (*mach_get_irq_list) (char *) = NULL; |
void (*mach_process_int) (int, struct pt_regs *) = NULL; |
/* machine dependent timer functions */ |
unsigned long (*mach_gettimeoffset) (void); |
void (*mach_gettod) (int*, int*, int*, int*, int*, int*); |
int (*mach_hwclk) (int, struct hwclk_time*) = NULL; |
int (*mach_set_clock_mmss) (unsigned long) = NULL; |
void (*mach_mksound)( unsigned int count, unsigned int ticks ); |
void (*mach_reset)( void ); |
void (*waitbut)(void) = dummy_waitbut; |
void (*mach_debug_init)(void); |
|
extern void register_console(void (*proc)(const char *)); |
|
#define MASK_256K 0xfffc0000 |
|
#ifdef CONFIG_I960VH |
# define CPU "i960Vh" |
#endif |
#ifdef CONFIG_I960RX |
# define CPU "i960Rx" |
#endif |
#ifdef CONFIG_I960HX |
# define CPU "i960Hx" |
#endif |
#ifdef CONFIG_I960CX |
# define CPU "i960Cx" |
#endif |
#ifdef CONFIG_I960JX |
# define CPU "i960Jx" |
#endif |
|
|
|
/* set up for i960 */ |
void setup_arch(char **cmdline_p, |
unsigned long * memory_start_p, unsigned long * memory_end_p) |
{ |
extern int stackbase, _etext, _edata, _end; |
extern void mon960_console_init(void); |
|
#ifdef CONFIG_MON960_CONSOLE |
extern void console_print_mon960(const char* msg); |
|
register_console(console_print_mon960); |
mon960_console_init(); |
#endif |
|
printk("\r\n\nuClinux " CPU "\n"); |
printk("i960 port (C) 1999 Keith Adams, Erik Walthinsen, Oregon Graduate Institute\n"); |
printk("Flat model support (C) 1998 Kenneth Albanowski, D. Jeff Dionne, TSHG Ltd.\n"); |
|
memory_start = PAGE_ALIGN(((unsigned long)&_end)); |
|
init_task.mm->start_code = 0; |
init_task.mm->end_code = (unsigned long) &_etext; |
init_task.mm->end_data = (unsigned long) &_edata; |
init_task.mm->brk = (unsigned long) &_end; |
|
ROOT_DEV = MKDEV(BLKMEM_MAJOR,0); |
|
command_line[512-1] = '\0'; |
|
if (memcmp(command_line, "Arg!", 4)) |
command_line[4] = '\0'; |
|
memset(command_line, 0, 4); |
|
strcpy(saved_command_line, command_line+4); |
*cmdline_p = command_line+4; |
|
|
#ifdef DEBUG |
if (strlen(*cmdline_p)) |
printk("Command line: '%s'\n", *cmdline_p); |
#endif |
|
*memory_start_p = memory_start; |
#ifdef CONFIG_CYVH |
*memory_end_p = (unsigned long)&stackbase; |
#endif |
} |
|
/* set up for i960 */ |
int get_cpuinfo(char * buffer) |
{ |
char *cpu, *mmu, *fpu; |
u_long clockfreq, clockfactor; |
|
cpu = CPU; |
mmu = "none"; |
fpu = "none"; |
clockfactor = 16; |
|
clockfreq = loops_per_sec*clockfactor; |
|
return(sprintf(buffer, "CPU:\t\t%s\n" |
"MMU:\t\t%s\n" |
"FPU:\t\t%s\n" |
"Clocking:\t%lu.%1luMHz\n" |
"BogoMips:\t%lu.%02lu\n" |
"Calibration:\t%lu loops\n", |
cpu, mmu, fpu, |
clockfreq/1000000,(clockfreq/100000)%10, |
loops_per_sec/500000,(loops_per_sec/5000)%100, |
loops_per_sec)); |
|
} |
|
void arch_gettod(int *year, int *mon, int *day, int *hour, |
int *min, int *sec) |
{ |
*year = *mon = *day = *hour = *min = *sec = 0; |
} |
/kernel/head.c
0,0 → 1,46
/* |
* FILE: head.c |
* AUTHOR: kma |
* DESCR: Initialization code for the i960. |
*/ |
|
#ident "$Id: head.c,v 1.1.1.1 2001-09-10 07:43:56 simons Exp $" |
|
#include <linux/autoconf.h> |
#include <linux/kernel.h> |
|
/* |
* So here we are! Running at ipl 31, in supervisor mode, on mon960's user |
* stack. Do we need to do much here? Let's just get right into start_kernel. |
*/ |
|
int main(void) |
{ |
long oldac; |
|
extern void start_kernel(void); |
|
/* 64-bit math routines need the overflow mask bit set */ |
__asm__ __volatile__ |
("modac %1, %1, %1" : "=r"(oldac) : "0"(1 << 12)); |
|
/* Make the i960 think it's in an interrupt handler. This has the effect |
* of not switching to the interrupt stack for every interrupt. Of |
* course, we wouldn't need this if there were a sensible way of |
* specifying an interrupt stack short of reinitializing the CPU, but |
* such is life. |
* |
* XXX: this has the effect of using user stacks for interrupts too. |
* The world's a scary place. |
*/ |
__asm__ __volatile__ ("modpc %1, %1, %1" : "=r"(oldac) : "0"(1<<13)); |
|
#ifdef CONFIG_CMDLINE_PROMPT |
/* do crazy command-line obtainments... */ |
#endif |
|
start_kernel(); |
|
printk("XXX: start_kernel returned!!!\n"); |
for(;;) ; |
} |
/kernel/bios32.c
0,0 → 1,149
/* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Bios and PCI stuff. |
*/ |
|
#include <linux/pci.h> |
#include <linux/bios32.h> |
#include <linux/config.h> |
#include <linux/kernel.h> |
#include <asm/system.h> |
|
unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) |
{ |
return memory_start; |
} |
|
unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) |
{ |
return memory_start; |
} |
|
unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end) |
{ |
return memory_start; |
} |
|
#ifdef CONFIG_MON960 |
|
#include <asm/mon960.h> |
|
/* |
* mon960 system calls for pci management |
*/ |
extern int mon960_pcibios_present(void* info); |
extern int mon960_pcibios_find_device(int vendor, int dev, int idx, void* loc); |
extern int mon960_pcibios_find_class(int class, int idx, void* dev); |
|
int pcibios_present(void) |
{ |
return 1; |
} |
|
int pcibios_find_device(unsigned short vendor, unsigned short dev, |
unsigned short index, unsigned char* bus, |
unsigned char* dev_fn) |
{ |
pci_dev_info loc; |
int status; |
|
if ((status=mon960_pcibios_find_device(vendor, dev, index, &loc))) |
return -1; |
|
printk("PCI device found: %x, %x, %x\n", loc.bus, loc.dev, loc.fn); |
*bus = loc.bus; |
*dev_fn = loc.dev; |
return 0; |
} |
|
int pcibios_find_class(unsigned int class, unsigned short idx, |
unsigned char* bus, unsigned char* dev_fn) |
{ |
pci_dev_info loc; |
int status; |
|
if ((status=mon960_pcibios_find_class(class, idx, &loc))) |
return -1; |
|
*bus = loc.bus; |
*dev_fn = loc.dev; |
return 0; |
} |
|
#define CONFIG_RDWR(op,sz,type) \ |
int pcibios_ ## op ## _config_ ## sz(unsigned char bus, unsigned char fn, \ |
unsigned char offset, type val) \ |
{ \ |
return mon960_pcibios_ ## op ## _config_ ## sz(bus, fn, 0, offset, val); \ |
} |
|
CONFIG_RDWR(read,byte,unsigned char*); |
CONFIG_RDWR(read,word,unsigned short*); |
CONFIG_RDWR(read,dword,unsigned int*); |
CONFIG_RDWR(write,byte,unsigned char); |
CONFIG_RDWR(write,word,unsigned short); |
CONFIG_RDWR(write,dword,unsigned int); |
|
#endif /* CONFIG_MON960 */ |
|
/* |
* Dealing with the ATU. We just do all accesses translated; checking |
* whether we can directly use the address might not be any faster. |
*/ |
|
/* external address = (local address & 0x03ffffff) | ATU_OMWVR */ |
#define OIOW_BASE 0x90000000UL /* outbound I/O space window */ |
#define ATU_OIOWVR ((unsigned long*) 0x125c) /* I/O window val */ |
|
/* Set up ATU, return local address to use */ |
static unsigned long program_atu(unsigned long pciaddr) |
{ |
unsigned long retval; |
unsigned long pci_hibits = pciaddr & 0xfc000000; |
*ATU_OIOWVR = pci_hibits; |
retval = (pciaddr & 0x03ffffff) | OIOW_BASE; |
return retval; |
} |
|
/* Note that we synchronize ATU access with the ipl. |
* |
* XXX: diddling the ipl every time seems to be a performance problem. Is |
* there any way to use the i960 hardware in just one memory op, instead of |
* two? |
*/ |
|
#define READ_OP(type,name) \ |
type name(char* addr) \ |
{ \ |
volatile type *local_addr; \ |
type retval; \ |
unsigned long oldatu = *ATU_OIOWVR; \ |
local_addr = (volatile type*) \ |
program_atu((unsigned long)addr); \ |
retval = *local_addr; \ |
*ATU_OIOWVR = oldatu; \ |
return retval; \ |
} |
READ_OP(unsigned char,readb) |
READ_OP(unsigned short,readw) |
READ_OP(unsigned int,readl) |
#undef READ_OP |
|
#define WRITE_OP(type,name) \ |
type name(type val, char* addr) \ |
{ \ |
volatile type *local_addr; \ |
type retval; \ |
unsigned long oldatu = *ATU_OIOWVR; \ |
local_addr = (volatile type*) \ |
program_atu((unsigned long)addr); \ |
retval = *local_addr = val; \ |
*ATU_OIOWVR = oldatu; \ |
return retval; \ |
} |
WRITE_OP(unsigned char,writeb) |
WRITE_OP(unsigned short,writew) |
WRITE_OP(unsigned int,writel) |
#undef WRITE_OP |
/kernel/console.c
0,0 → 1,2523
|
/* |
* arch/i960/kernel/console.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* based on |
* drivers/char/console.c |
* Copyright (C) 1991, 1992 Linus Torvalds |
*/ |
/* |
* console.c |
* |
* This module exports the console io functions: |
* |
* 'void do_keyboard_interrupt(void)' |
* |
* 'int vc_allocate(unsigned int console)' |
* 'int vc_cons_allocated(unsigned int console)' |
* 'int vc_resize(unsigned long lines, unsigned long cols)' |
* 'int vc_resize_con(unsigned long lines, unsigned long cols, |
* unsigned int currcons)' |
* 'void vc_disallocate(unsigned int currcons)' |
* |
* 'unsigned long con_init(unsigned long)' |
* 'int con_open(struct tty_struct *tty, struct file * filp)' |
* 'void con_write(struct tty_struct * tty)' |
* 'void console_print(const char * b)' |
* 'void update_screen(int new_console)' |
* |
* 'void do_blank_screen(int)' |
* 'void do_unblank_screen(void)' |
* 'void poke_blanked_console(void)' |
* |
* 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)' |
* 'void complement_pos(int currcons, int offset)' |
* 'void invert_screen(int currcons, int offset, int count, int shift)' |
* |
* 'void scrollback(int lines)' |
* 'void scrollfront(int lines)' |
* |
* 'int con_get_font(char *)' |
* 'int con_set_font(char *)' |
* |
* 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)' |
* 'int mouse_reporting(void)' |
* |
* 'unsigned long get_video_num_lines(unsigned int console)' |
* 'unsigned long get_video_num_columns(unsigned int console)' |
* 'unsigned long get_video_size_row(unsigned int console)' |
* |
* Hopefully this will be a rather complete VT102 implementation. |
* |
* Beeping thanks to John T Kohl. |
* |
* Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics |
* Chars, and VT100 enhancements by Peter MacDonald. |
* |
* Copy and paste function by Andrew Haylett, |
* some enhancements by Alessandro Rubini. |
* |
* User definable mapping table and font loading by Eugene G. Crosser, |
* <crosser@pccross.msk.su> |
* |
* Code to check for different video-cards mostly by Galen Hunt, |
* <g-hunt@ee.utah.edu> |
* |
* Rudimentary ISO 10646/Unicode/UTF-8 character set support by |
* Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>. |
* |
* Dynamic allocation of consoles, aeb@cwi.nl, May 1994 |
* Resizing of consoles, aeb, 940926 |
* |
* Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 |
* <poe@daimi.aau.dk> |
* |
*/ |
|
#include <linux/config.h> |
#include <linux/sched.h> |
#include <linux/timer.h> |
#include <linux/interrupt.h> |
#include <linux/tty.h> |
#include <linux/tty_flip.h> |
#include <linux/kernel.h> |
#include <linux/string.h> |
#include <linux/errno.h> |
#include <linux/console.h> |
#include <linux/kd.h> |
#include <linux/malloc.h> |
#include <linux/major.h> |
#include <linux/mm.h> |
#include <linux/ioport.h> |
|
#include <asm/io.h> |
#include <asm/segment.h> |
#include <asm/system.h> |
#include <asm/bitops.h> |
|
#include "../../../drivers/char/kbd_kern.h" |
#include "../../../drivers/char/vt_kern.h" |
#include "../../../drivers/char/consolemap.h" |
#include "../../../drivers/char/selection.h" |
|
|
|
#ifndef MIN |
#define MIN(a,b) ((a) < (b) ? (a) : (b)) |
#endif |
|
struct tty_driver console_driver; |
static int console_refcount; |
static struct tty_struct *console_table[MAX_NR_CONSOLES]; |
static struct termios *console_termios[MAX_NR_CONSOLES]; |
static struct termios *console_termios_locked[MAX_NR_CONSOLES]; |
|
static void vc_init(unsigned int console, int do_clear); |
|
static void update_attr(int currcons); |
static void gotoxy(int currcons, int new_x, int new_y); |
static void save_cur(int currcons); |
static void blank_screen(void); |
static void unblank_screen(void); |
extern void change_console(unsigned int); |
static inline void set_cursor(int currcons); |
static void reset_terminal(int currcons, int do_clear); |
extern void reset_vc(unsigned int new_console); |
extern void vt_init(void); |
extern void register_console(void (*proc)(const char *)); |
extern void vesa_blank(void); |
extern void vesa_unblank(void); |
extern void compute_shiftstate(void); |
void poke_blanked_console(void); |
void do_blank_screen(int); |
|
unsigned long video_num_lines; |
unsigned long video_num_columns; |
unsigned long video_size_row; |
|
static int printable = 0; /* Is console ready for printing? */ |
unsigned long video_font_height; /* Height of current screen font */ |
unsigned long video_scan_lines; /* Number of scan lines on screen */ |
unsigned long default_font_height; /* Height of default screen font */ |
int video_mode_512ch = 0; /* 512-character mode */ |
static unsigned short console_charmask = 0x0ff; |
|
static unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; |
|
/* used by kbd_bh - set by keyboard_interrupt */ |
int do_poke_blanked_console = 0; |
int console_blanked = 0; |
static int blankinterval = 10*60*HZ; |
static int vesa_off_interval = 0; |
static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ |
|
static struct vc { |
struct vc_data *d; |
|
/* might add scrmem, vt_struct, kbd at some time, |
to have everything in one place - the disadvantage |
would be that vc_cons etc can no longer be static */ |
} vc_cons [MAX_NR_CONSOLES]; |
struct consw *conswitchp; |
|
#define cols (vc_cons[currcons].d->vc_cols) |
#define rows (vc_cons[currcons].d->vc_rows) |
#define size_row (vc_cons[currcons].d->vc_size_row) |
#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) |
#define cons_num (vc_cons[currcons].d->vc_num) |
#define origin (vc_cons[currcons].d->vc_origin) |
#define scr_end (vc_cons[currcons].d->vc_scr_end) |
#define pos (vc_cons[currcons].d->vc_pos) |
#define top (vc_cons[currcons].d->vc_top) |
#define bottom (vc_cons[currcons].d->vc_bottom) |
#define x (vc_cons[currcons].d->vc_x) |
#define y (vc_cons[currcons].d->vc_y) |
#define vc_state (vc_cons[currcons].d->vc_state) |
#define npar (vc_cons[currcons].d->vc_npar) |
#define par (vc_cons[currcons].d->vc_par) |
#define ques (vc_cons[currcons].d->vc_ques) |
#define attr (vc_cons[currcons].d->vc_attr) |
#define saved_x (vc_cons[currcons].d->vc_saved_x) |
#define saved_y (vc_cons[currcons].d->vc_saved_y) |
#define translate (vc_cons[currcons].d->vc_translate) |
#define G0_charset (vc_cons[currcons].d->vc_G0_charset) |
#define G1_charset (vc_cons[currcons].d->vc_G1_charset) |
#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) |
#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) |
#define utf (vc_cons[currcons].d->vc_utf) |
#define utf_count (vc_cons[currcons].d->vc_utf_count) |
#define utf_char (vc_cons[currcons].d->vc_utf_char) |
#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start) |
#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end) |
#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) |
#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) |
#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) |
#define decscnm (vc_cons[currcons].d->vc_decscnm) |
#define decom (vc_cons[currcons].d->vc_decom) |
#define decawm (vc_cons[currcons].d->vc_decawm) |
#define deccm (vc_cons[currcons].d->vc_deccm) |
#define decim (vc_cons[currcons].d->vc_decim) |
#define deccolm (vc_cons[currcons].d->vc_deccolm) |
#define need_wrap (vc_cons[currcons].d->vc_need_wrap) |
#define has_scrolled (vc_cons[currcons].d->vc_has_scrolled) |
#define kmalloced (vc_cons[currcons].d->vc_kmalloced) |
#define report_mouse (vc_cons[currcons].d->vc_report_mouse) |
#define can_do_color (vc_cons[currcons].d->vc_can_do_color) |
#define color (vc_cons[currcons].d->vc_color) |
#define s_color (vc_cons[currcons].d->vc_s_color) |
#define def_color (vc_cons[currcons].d->vc_def_color) |
#define foreground (color & 0x0f) |
#define background (color & 0xf0) |
#define charset (vc_cons[currcons].d->vc_charset) |
#define s_charset (vc_cons[currcons].d->vc_s_charset) |
#define intensity (vc_cons[currcons].d->vc_intensity) |
#define underline (vc_cons[currcons].d->vc_underline) |
#define blink (vc_cons[currcons].d->vc_blink) |
#define reverse (vc_cons[currcons].d->vc_reverse) |
#define s_intensity (vc_cons[currcons].d->vc_s_intensity) |
#define s_underline (vc_cons[currcons].d->vc_s_underline) |
#define s_blink (vc_cons[currcons].d->vc_s_blink) |
#define s_reverse (vc_cons[currcons].d->vc_s_reverse) |
#define ulcolor (vc_cons[currcons].d->vc_ulcolor) |
#define halfcolor (vc_cons[currcons].d->vc_halfcolor) |
#define tab_stop (vc_cons[currcons].d->vc_tab_stop) |
#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) |
#define bell_duration (vc_cons[currcons].d->vc_bell_duration) |
#define sw (vc_cons[currcons].d->vc_sw) |
|
#define vcmode (vt_cons[currcons]->vc_mode) |
#if 0 /* XXX */ |
#define vtmode (vt_cons[currcons]->vt_mode) |
#define vtpid (vt_cons[currcons]->vt_pid) |
#define vtnewvt (vt_cons[currcons]->vt_newvt) |
#endif |
|
#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) |
|
int vc_cons_allocated(unsigned int i) |
{ |
return (i < MAX_NR_CONSOLES && vc_cons[i].d); |
} |
|
int vc_allocate(unsigned int currcons) /* return 0 on success */ |
{ |
if (currcons >= MAX_NR_CONSOLES) |
return -ENODEV; |
if (!vc_cons[currcons].d) { |
long p, q; |
|
/* prevent users from taking too much memory */ |
if (currcons >= MAX_NR_USER_CONSOLES && !suser()) |
return -EPERM; |
|
/* due to the granularity of kmalloc, we waste some memory here */ |
/* the alloc is done in two steps, to optimize the common situation |
of a 25x80 console (structsize=216, screenbuf_size=4000) */ |
p = (long) kmalloc(structsize, GFP_KERNEL); |
if (!p) |
return -ENOMEM; |
vc_cons[currcons].d = (struct vc_data *) p; |
vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); |
|
/* ++Geert: sw->con_init determines console size */ |
sw = conswitchp; |
cons_num = currcons; |
sw->con_init (vc_cons[currcons].d); |
size_row = cols<<1; |
screenbuf_size = rows*size_row; |
|
q = (long) kmalloc(screenbuf_size, GFP_KERNEL); |
if (!q) { |
kfree_s((char *) p, structsize); |
vc_cons[currcons].d = NULL; |
return -ENOMEM; |
} |
vc_scrbuf[currcons] = (unsigned short *) q; |
kmalloced = 1; |
vc_init (currcons, 1); |
} |
return 0; |
} |
|
/* |
* Change # of rows and columns (0 means the size of fg_console) |
* [this is to be used together with some user program |
* like resize that changes the hardware videomode] |
*/ |
int vc_resize(unsigned long lines, unsigned long columns) |
{ |
unsigned long cc, ll, ss, sr; |
unsigned long occ, oll, oss, osr; |
unsigned short *p; |
unsigned int currcons = fg_console, i; |
unsigned short *newscreens[MAX_NR_CONSOLES]; |
long ol, nl, rlth, rrem; |
|
cc = (columns ? columns : cols); |
ll = (lines ? lines : rows); |
sr = cc << 1; |
ss = sr * ll; |
|
/* |
* Some earlier version had all consoles of potentially |
* different sizes, but that was really messy. |
* So now we only change if there is room for all consoles |
* of the same size. |
*/ |
for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { |
if (!vc_cons_allocated(currcons)) |
newscreens[currcons] = 0; |
else { |
p = (unsigned short *) kmalloc(ss, GFP_USER); |
if (!p) { |
for (i = 0; i< currcons; i++) |
if (newscreens[i]) |
kfree_s(newscreens[i], ss); |
return -ENOMEM; |
} |
newscreens[currcons] = p; |
} |
} |
|
#if 0 /* XXX */ |
get_scrmem(fg_console); |
#endif |
|
for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { |
if (!vc_cons_allocated(currcons)) |
continue; |
|
oll = rows; |
occ = cols; |
osr = size_row; |
oss = screenbuf_size; |
|
rows = ll; |
cols = cc; |
size_row = sr; |
screenbuf_size = ss; |
|
rlth = MIN(osr, sr); |
rrem = sr - rlth; |
ol = origin; |
nl = (long) newscreens[currcons]; |
if (ll < oll) |
ol += (oll - ll) * osr; |
|
update_attr(currcons); |
while (ol < scr_end) { |
/* ++Geert: TODO: Because the attributes have different meanings |
on monochrome and color, they should really be converted if |
can_do_color changes... */ |
memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); |
if (rrem) |
memsetw((void *)(nl + rlth), video_erase_char, rrem); |
ol += osr; |
nl += sr; |
} |
|
if (kmalloced) |
kfree_s(vc_scrbuf[currcons], oss); |
vc_scrbuf[currcons] = newscreens[currcons]; |
kmalloced = 1; |
screenbuf_size = ss; |
|
origin = (long) video_mem_start = vc_scrbuf[currcons]; |
scr_end = video_mem_end = ((long) video_mem_start) + ss; |
|
if (scr_end > nl) |
memsetw((void *) nl, video_erase_char, scr_end - nl); |
|
/* do part of a reset_terminal() */ |
top = 0; |
bottom = rows; |
gotoxy(currcons, x, y); |
save_cur(currcons); |
} |
|
#if 0 /* XXX */ |
set_scrmem(fg_console, 0); |
set_origin(fg_console); |
#endif /* XXX */ |
update_screen(fg_console); |
set_cursor(fg_console); |
|
return 0; |
} |
|
/* |
* ++Geert: Change # of rows and columns for one specific console. |
* Of course it's not messy to have all consoles of potentially different sizes, |
* except on PCish hardware :-) |
* |
* This is called by the low level console driver (arch/m68k/console/fbcon.c or |
* arch/m68k/console/txtcon.c) |
*/ |
void vc_resize_con(unsigned long lines, unsigned long columns, |
unsigned int currcons) |
{ |
unsigned long cc, ll, ss, sr; |
unsigned long occ, oll, oss, osr; |
unsigned short *newscreen; |
long ol, nl, rlth, rrem; |
struct winsize ws; |
|
if (!columns || !lines || currcons >= MAX_NR_CONSOLES) |
return; |
|
cc = columns; |
ll = lines; |
sr = cc << 1; |
ss = sr * ll; |
|
if (!vc_cons_allocated(currcons)) |
newscreen = 0; |
else if (!(newscreen = (unsigned short *) kmalloc(ss, GFP_USER))) |
return; |
|
if (vc_cons_allocated(currcons)) { |
oll = rows; |
occ = cols; |
osr = size_row; |
oss = screenbuf_size; |
|
rows = ll; |
cols = cc; |
size_row = sr; |
screenbuf_size = ss; |
|
rlth = MIN(osr, sr); |
rrem = sr - rlth; |
ol = origin; |
nl = (long) newscreen; |
if (ll < oll) |
ol += (oll - ll) * osr; |
|
update_attr(currcons); |
while (ol < scr_end) { |
/* ++Geert: TODO: Because the attributes have different meanings |
on monochrome and color, they should really be converted if |
can_do_color changes... */ |
memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); |
if (rrem) |
memsetw((void *)(nl + rlth), video_erase_char, rrem); |
ol += osr; |
nl += sr; |
} |
|
if (kmalloced) |
kfree_s(vc_scrbuf[currcons], oss); |
vc_scrbuf[currcons] = newscreen; |
kmalloced = 1; |
screenbuf_size = ss; |
|
origin = (long) video_mem_start = vc_scrbuf[currcons]; |
scr_end = video_mem_end = ((long)video_mem_start) + ss; |
|
if (scr_end > nl) |
memsetw((void *) nl, video_erase_char, scr_end - nl); |
|
/* do part of a reset_terminal() */ |
top = 0; |
bottom = rows; |
gotoxy(currcons, x, y); |
save_cur(currcons); |
|
ws.ws_row = rows; |
ws.ws_col = cols; |
if (memcmp(&ws, &console_table[currcons]->winsize, sizeof (struct winsize)) && |
console_table[currcons]->pgrp > 0) |
kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); |
console_table[currcons]->winsize = ws; |
} |
|
if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT) |
update_screen(fg_console); |
} |
|
void vc_disallocate(unsigned int currcons) |
{ |
if (vc_cons_allocated(currcons)) { |
if (kmalloced) |
kfree_s(vc_scrbuf[currcons], screenbuf_size); |
if (currcons >= MIN_NR_CONSOLES) |
kfree_s(vc_cons[currcons].d, structsize); |
vc_cons[currcons].d = 0; |
} |
} |
|
|
#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) |
#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) |
#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) |
|
#define decarm VC_REPEAT |
#define decckm VC_CKMODE |
#define kbdapplic VC_APPLIC |
#define lnm VC_CRLF |
|
/* |
* this is what the terminal answers to a ESC-Z or csi0c query. |
*/ |
#define VT100ID "\033[?1;2c" |
#define VT102ID "\033[?6c" |
|
static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, |
8,12,10,14, 9,13,11,15 }; |
|
/* |
* gotoxy() must verify all boundaries, because the arguments |
* might also be negative. If the given position is out of |
* bounds, the cursor is placed at the nearest margin. |
*/ |
static void gotoxy(int currcons, int new_x, int new_y) |
{ |
int min_y, max_y; |
|
if (new_x < 0) |
x = 0; |
else |
if (new_x >= cols) |
x = cols - 1; |
else |
x = new_x; |
if (decom) { |
min_y = top; |
max_y = bottom; |
} else { |
min_y = 0; |
max_y = rows; |
} |
if (new_y < min_y) |
y = min_y; |
else if (new_y >= max_y) |
y = max_y - 1; |
else |
y = new_y; |
pos = video_mem_start + y * cols + x; |
need_wrap = 0; |
} |
|
/* for absolute user moves, when decom is set */ |
static void gotoxay(int currcons, int new_x, int new_y) |
{ |
gotoxy(currcons, new_x, decom ? (top+new_y) : new_y); |
} |
|
static void hide_cursor(int currcons) |
{ |
sw->con_cursor(vc_cons[currcons].d,CM_ERASE); |
return; |
} |
|
static void set_cursor(int currcons) |
{ |
if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) |
return; |
if (deccm) |
sw->con_cursor(vc_cons[currcons].d,CM_DRAW); |
else |
hide_cursor(currcons); |
return; |
} |
|
void no_scroll(char *str, int *ints) |
{ |
/* |
* no_scroll currently does nothing on the m68k. |
*/ |
} |
|
/* |
* Arno: |
* Why do we need these? The keyboard code doesn't seem to do anything |
* with them either... |
*/ |
void scrollfront(int l) |
{ |
return; |
} |
|
void scrollback(int l) |
{ |
return; |
} |
|
static void scrup(int currcons, unsigned int t, unsigned int b, |
int nr) |
{ |
unsigned short *p; |
int i; |
|
if (b > rows || t >= b) |
return; |
|
memmove (video_mem_start + t * cols, |
video_mem_start + (t + nr) * cols, |
(b - t - nr) * cols * 2); |
|
p = video_mem_start + (b - nr) * cols; |
for (i = nr * cols; i > 0; i--) |
*p++ = video_erase_char; |
|
if (currcons != fg_console) |
return; |
/* |
* Arno: |
* Scrolling has now been moved to amicon.c where it should have |
* been all along. |
*/ |
sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr); |
|
return; |
|
} |
|
static void scrdown(int currcons, unsigned int t, unsigned int b, |
int nr) |
{ |
unsigned short *p; |
int i; |
|
if (b > rows || t >= b) |
return; |
|
memmove (video_mem_start + (t + nr) * cols, |
video_mem_start + t * cols, |
(b - t - nr) * cols * 2); |
|
p = video_mem_start + t * cols; |
for (i = nr * cols; i > 0; i--) |
*p++ = video_erase_char; |
|
if (currcons != fg_console) |
return; |
/* |
* Arno: |
* Scrolling has now been moved to amicon.c where it should have |
* been all along. |
*/ |
sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr); |
|
return; |
} |
|
static void lf(int currcons) |
{ |
/* don't scroll if above bottom of scrolling region, or |
* if below scrolling region |
*/ |
if (y+1 == bottom) |
scrup(currcons,top,bottom, 1); |
else if (y < rows-1) { |
y++; |
pos += cols; |
} |
need_wrap = 0; |
} |
|
static void ri(int currcons) |
{ |
/* don't scroll if below top of scrolling region, or |
* if above scrolling region |
*/ |
if (y == top) |
scrdown(currcons,top,bottom, 1); |
else if (y > 0) { |
y--; |
pos -= cols; |
} |
need_wrap = 0; |
} |
|
static inline void cr(int currcons) |
{ |
pos -= x; |
need_wrap = x = 0; |
} |
|
static inline void bs(int currcons) |
{ |
if (x) { |
pos--; |
x--; |
need_wrap = 0; |
} |
} |
|
static inline void del(int currcons) |
{ |
/* ignored */ |
} |
|
static void csi_J(int currcons, int vpar) |
{ |
unsigned long count; |
unsigned short *start; |
|
switch (vpar) { |
case 0: /* erase from cursor to end of display */ |
count = (video_mem_start |
+ cols * rows |
- pos); |
start = pos; |
if (currcons != fg_console) |
break; |
/* 680x0 do in two stages */ |
sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); |
sw->con_clear(vc_cons[currcons].d,y+1,0,rows-y-1, cols); |
break; |
case 1: /* erase from start to cursor */ |
count = pos - video_mem_start + 1; |
start = video_mem_start; |
if (currcons != fg_console) |
break; |
/* 680x0 do in two stages */ |
sw->con_clear(vc_cons[currcons].d,0,0,y, cols); |
sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); |
break; |
case 2: /* erase whole display */ |
count = cols * rows; |
start = video_mem_start; |
if (currcons != fg_console) |
break; |
sw->con_clear(vc_cons[currcons].d,0,0,rows, cols); |
break; |
default: |
return; |
} |
while (count-- > 0) |
*start++ = video_erase_char; |
need_wrap = 0; |
} |
|
static void csi_K(int currcons, int vpar) |
{ |
unsigned long count; |
unsigned short *start; |
|
switch (vpar) { |
case 0: /* erase from cursor to end of line */ |
count = cols - x; |
start = pos; |
if (currcons != fg_console) |
break; |
sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); |
break; |
case 1: /* erase from start of line to cursor */ |
start = pos - x; |
count = x + 1; |
if (currcons != fg_console) |
break; |
sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); |
break; |
case 2: /* erase whole line */ |
start = pos - x; |
count = cols; |
if (currcons != fg_console) |
break; |
sw->con_clear(vc_cons[currcons].d,y,0,1,cols); |
break; |
default: |
return; |
} |
while (count-- > 0) |
*start++ = video_erase_char; |
need_wrap = 0; |
} |
|
static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ |
{ /* not vt100? */ |
unsigned long count; |
unsigned short * start; |
|
if (!vpar) |
vpar++; |
|
start=pos; |
count=(vpar > cols-x) ? (cols-x) : vpar; |
|
if (currcons == fg_console) |
sw->con_clear(vc_cons[currcons].d,y,x,1,count); |
|
while (count-- > 0) |
*start++ = video_erase_char; |
need_wrap = 0; |
} |
|
/* |
* Arno: |
* On 680x0 attributes are currently not used. This piece of code |
* seems hardware independent, but uses the EGA/VGA way of representing |
* attributes. |
* TODO: modify for 680x0 and add attribute processing to putc code. |
* |
* ++roman: I completely changed the attribute format for monochrome |
* mode (!can_do_color). The formerly used MDA (monochrome display |
* adapter) format didn't allow the combination of certain effects. |
* Now the attribute is just a bit vector: |
* Bit 0..1: intensity (0..2) |
* Bit 2 : underline |
* Bit 3 : reverse |
* Bit 7 : blink |
*/ |
static void update_attr(int currcons) |
{ |
if (!can_do_color) { |
/* Special treatment for monochrome */ |
attr = intensity | |
(underline ? 4 : 0) | |
((reverse ^ decscnm) ? 8 : 0) | |
(blink ? 0x80 : 0); |
video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0); |
return; |
} |
|
attr = color; |
if (underline) |
attr = (attr & 0xf0) | ulcolor; |
else if (intensity == 0) |
attr = (attr & 0xf0) | halfcolor; |
if (reverse ^ decscnm) |
attr = reverse_video_char(attr); |
if (blink) |
attr ^= 0x80; |
if (intensity == 2) |
attr ^= 0x08; |
if (decscnm) |
video_erase_char = (reverse_video_char(color) << 8) | ' '; |
else |
video_erase_char = (color << 8) | ' '; |
} |
|
static void default_attr(int currcons) |
{ |
intensity = 1; |
underline = 0; |
reverse = 0; |
blink = 0; |
color = def_color; |
} |
|
static void csi_m(int currcons) |
{ |
int i; |
|
for (i=0;i<=npar;i++) |
switch (par[i]) { |
case 0: /* all attributes off */ |
default_attr(currcons); |
break; |
case 1: |
intensity = 2; |
break; |
case 2: |
intensity = 0; |
break; |
case 4: |
underline = 1; |
break; |
case 5: |
blink = 1; |
break; |
case 7: |
reverse = 1; |
break; |
case 10: /* ANSI X3.64-1979 (SCO-ish?) |
* Select primary font, don't display |
* control chars if defined, don't set |
* bit 8 on output. |
*/ |
translate = set_translate(charset == 0 |
? G0_charset |
: G1_charset); |
disp_ctrl = 0; |
toggle_meta = 0; |
break; |
case 11: /* ANSI X3.64-1979 (SCO-ish?) |
* Select first alternate font, let's |
* chars < 32 be displayed as ROM chars. |
*/ |
translate = set_translate(IBMPC_MAP); |
disp_ctrl = 1; |
toggle_meta = 0; |
break; |
case 12: /* ANSI X3.64-1979 (SCO-ish?) |
* Select second alternate font, toggle |
* high bit before displaying as ROM char. |
*/ |
translate = set_translate(IBMPC_MAP); |
disp_ctrl = 1; |
toggle_meta = 1; |
break; |
case 21: |
case 22: |
intensity = 1; |
break; |
case 24: |
underline = 0; |
break; |
case 25: |
blink = 0; |
break; |
case 27: |
reverse = 0; |
break; |
case 38: /* ANSI X3.64-1979 (SCO-ish?) |
* Enables underscore, white foreground |
* with white underscore (Linux - use |
* default foreground). |
*/ |
color = (def_color & 0x0f) | background; |
underline = 1; |
break; |
case 39: /* ANSI X3.64-1979 (SCO-ish?) |
* Disable underline option. |
* Reset colour to default? It did this |
* before... |
*/ |
color = (def_color & 0x0f) | background; |
underline = 0; |
break; |
case 49: |
color = (def_color & 0xf0) | foreground; |
break; |
default: |
if (par[i] >= 30 && par[i] <= 37) |
color = color_table[par[i]-30] |
| background; |
else if (par[i] >= 40 && par[i] <= 47) |
color = (color_table[par[i]-40]<<4) |
| foreground; |
break; |
} |
update_attr(currcons); |
} |
|
static void respond_string(const char * p, struct tty_struct * tty) |
{ |
while (*p) { |
tty_insert_flip_char(tty, *p, 0); |
p++; |
} |
tty_schedule_flip(tty); |
} |
|
static void cursor_report(int currcons, struct tty_struct * tty) |
{ |
char buf[40]; |
|
sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1); |
respond_string(buf, tty); |
} |
|
static inline void status_report(struct tty_struct * tty) |
{ |
respond_string("\033[0n", tty); /* Terminal ok */ |
} |
|
static inline void respond_ID(struct tty_struct * tty) |
{ |
respond_string(VT102ID, tty); |
} |
|
void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) |
{ |
char buf[8]; |
|
sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), |
(char)('!' + mry)); |
respond_string(buf, tty); |
} |
|
/* invoked via ioctl(TIOCLINUX) */ |
int mouse_reporting(void) |
{ |
int currcons = fg_console; |
|
return report_mouse; |
} |
|
static inline unsigned short *screenpos(int currcons, int offset, int viewed) |
{ |
unsigned short *p = (unsigned short *)(origin + offset); |
#if 0 |
if (viewed && currcons == fg_console) |
p -= (__real_origin - __origin); |
#endif |
return p; |
} |
|
/* Note: inverting the screen twice should revert to the original state */ |
void invert_screen(int currcons, int offset, int count, int viewed) |
{ |
unsigned short *p; |
unsigned short xx, yy, oldattr; |
|
count /= 2; |
p = screenpos(currcons, offset, viewed); |
xx = (offset >> 1) % cols; |
yy = (offset >> 1) / cols; |
oldattr = attr; |
if (can_do_color) |
while (count--) { |
unsigned short old = scr_readw(p); |
unsigned short new = reverse_video_short(old); |
scr_writew(new, p); |
p++; |
if (currcons != fg_console) |
continue; |
attr = new >> 8; |
sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); |
if (++xx == cols) |
xx = 0, ++yy; |
} |
else |
while (count--) { |
unsigned short old = scr_readw(p); |
unsigned short new = old ^ 0x800; |
scr_writew(new, p); |
p++; |
if (currcons != fg_console) |
continue; |
attr = new >> 8; |
sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); |
if (++xx == cols) |
xx = 0, ++yy; |
} |
attr = oldattr; |
} |
|
/* used by selection: complement pointer position */ |
void complement_pos(int currcons, int offset) |
{ |
static unsigned short *p = NULL; |
static unsigned short old = 0; |
static unsigned short oldx = 0, oldy = 0; |
unsigned short new, oldattr; |
|
oldattr = attr; |
if (p) { |
scr_writew(old, p); |
if (currcons == fg_console) { |
attr = old >> 8; |
sw->con_putc(vc_cons[currcons].d, old & 0xff, oldy, oldx); |
attr = oldattr; |
} |
} |
if (offset == -1) |
p = NULL; |
else { |
p = screenpos(currcons, offset, 1); |
old = scr_readw(p); |
oldx = (offset >> 1) % cols; |
oldy = (offset >> 1) / cols; |
if (can_do_color) |
new = old ^ 0x7700; |
else |
new = old ^ 0x800; |
scr_writew(new, p); |
if (currcons == fg_console) { |
attr = new >> 8; |
sw->con_putc(vc_cons[currcons].d, new & 0xff, oldy, oldx); |
attr = oldattr; |
} |
} |
} |
|
/* used by selection */ |
unsigned short screen_word(int currcons, int offset, int viewed) |
{ |
return scr_readw(screenpos(currcons, offset, viewed)); |
} |
|
/* used by selection - convert a screen word to a glyph number */ |
int scrw2glyph(unsigned short scr_word) |
{ |
return ( video_mode_512ch ) |
? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff) |
: scr_word & 0x00ff; |
} |
|
/* used by vcs - note the word offset */ |
unsigned short *screen_pos(int currcons, int w_offset, int viewed) |
{ |
return screenpos(currcons, 2 * w_offset, viewed); |
} |
|
void getconsxy(int currcons, char *p) |
{ |
p[0] = x; |
p[1] = y; |
} |
|
void putconsxy(int currcons, char *p) |
{ |
gotoxy(currcons, p[0], p[1]); |
set_cursor(currcons); |
} |
|
static void set_mode(int currcons, int on_off) |
{ |
int i; |
|
for (i=0; i<=npar; i++) |
if (ques) switch(par[i]) { /* DEC private modes set/reset */ |
case 1: /* Cursor keys send ^[Ox/^[[x */ |
if (on_off) |
set_kbd(decckm); |
else |
clr_kbd(decckm); |
break; |
case 3: /* 80/132 mode switch unimplemented */ |
deccolm = on_off; |
#if 0 |
(void) vc_resize(rows, deccolm ? 132 : 80); |
/* this alone does not suffice; some user mode |
utility has to change the hardware regs */ |
#endif |
break; |
case 5: /* Inverted screen on/off */ |
if (decscnm != on_off) { |
decscnm = on_off; |
invert_screen(currcons, 0, screenbuf_size, 0); |
update_attr(currcons); |
} |
break; |
case 6: /* Origin relative/absolute */ |
decom = on_off; |
gotoxay(currcons,0,0); |
break; |
case 7: /* Autowrap on/off */ |
decawm = on_off; |
break; |
case 8: /* Autorepeat on/off */ |
if (on_off) |
set_kbd(decarm); |
else |
clr_kbd(decarm); |
break; |
case 9: |
report_mouse = on_off ? 1 : 0; |
break; |
case 25: /* Cursor on/off */ |
deccm = on_off; |
set_cursor(currcons); |
break; |
case 1000: |
report_mouse = on_off ? 2 : 0; |
break; |
} else switch(par[i]) { /* ANSI modes set/reset */ |
case 3: /* Monitor (display ctrls) */ |
disp_ctrl = on_off; |
break; |
case 4: /* Insert Mode on/off */ |
decim = on_off; |
break; |
case 20: /* Lf, Enter == CrLf/Lf */ |
if (on_off) |
set_kbd(lnm); |
else |
clr_kbd(lnm); |
break; |
} |
} |
|
static void setterm_command(int currcons) |
{ |
switch(par[0]) { |
case 1: /* set color for underline mode */ |
if (can_do_color && par[1] < 16) { |
ulcolor = color_table[par[1]]; |
if (underline) |
update_attr(currcons); |
} |
break; |
case 2: /* set color for half intensity mode */ |
if (can_do_color && par[1] < 16) { |
halfcolor = color_table[par[1]]; |
if (intensity == 0) |
update_attr(currcons); |
} |
break; |
case 8: /* store colors as defaults */ |
def_color = attr; |
default_attr(currcons); |
update_attr(currcons); |
break; |
case 9: /* set blanking interval */ |
blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; |
poke_blanked_console(); |
break; |
case 10: /* set bell frequency in Hz */ |
if (npar >= 1) |
bell_pitch = par[1]; |
else |
bell_pitch = DEFAULT_BELL_PITCH; |
break; |
case 11: /* set bell duration in msec */ |
if (npar >= 1) |
bell_duration = (par[1] < 2000) ? |
par[1]*HZ/1000 : 0; |
else |
bell_duration = DEFAULT_BELL_DURATION; |
break; |
case 12: /* bring specified console to the front */ |
if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) |
update_screen(par[1]-1); |
break; |
case 13: /* unblank the screen */ |
unblank_screen(); |
break; |
case 14: /* set vesa powerdown interval */ |
vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; |
break; |
} |
} |
|
static void insert_char(int currcons) |
{ |
int i; |
unsigned short *p = pos; |
|
for (i = cols - x - 2; i >= 0; i--) |
p[i + 1] = p[i]; |
*pos = video_erase_char; |
need_wrap = 0; |
|
if (currcons != fg_console) |
return; |
|
/* Arno: |
* Move the remainder of the line (-1 character) one spot to the right |
*/ |
sw->con_bmove(vc_cons[currcons].d,y,x,y,x+1,1,(cols-x-1)); |
/* |
* Print the erase char on the current position |
*/ |
sw->con_putc(vc_cons[currcons].d,(video_erase_char & 0x00ff),y,x); |
} |
|
static void csi_at(int currcons, unsigned int nr) |
{ |
int i; |
unsigned short *p; |
|
if (nr > cols - x) |
nr = cols - x; |
else if (!nr) |
nr = 1; |
|
p = pos + cols - x - nr; |
while (--p >= pos) |
p[nr] = *p; |
for (i = 0; i < nr; i++) |
*++p = video_erase_char; |
need_wrap = 0; |
|
if (currcons != fg_console) |
return; |
|
sw->con_bmove (vc_cons[currcons].d, y, x, y, x + nr, |
1, cols - x - nr); |
while (nr--) |
sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff, |
y, x + nr); |
} |
|
static void csi_L(int currcons, unsigned int nr) |
{ |
if (nr > rows) |
nr = rows; |
else if (!nr) |
nr = 1; |
scrdown (currcons, y, bottom, nr); |
need_wrap = 0; |
} |
|
static void csi_P(int currcons, unsigned int nr) |
{ |
int i; |
unsigned short *p, *end; |
|
if (nr > cols - x) |
nr = cols - x; |
else if (!nr) |
nr = 1; |
|
p = pos; |
end = pos + cols - x - nr; |
while (p < end) |
*p = p[nr], p++; |
for (i = 0; i < nr; i++) |
*p++ = video_erase_char; |
need_wrap = 0; |
|
if (currcons != fg_console) |
return; |
|
sw->con_bmove (vc_cons[currcons].d, y, x + nr, y, x, |
1, cols - x - nr); |
|
while (nr--) |
sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff, |
y, cols - 1 - nr); |
} |
|
static void csi_M(int currcons, unsigned int nr) |
{ |
if (nr > rows) |
nr = rows; |
else if (!nr) |
nr=1; |
scrup (currcons, y, bottom, nr); |
need_wrap = 0; |
} |
|
static void save_cur(int currcons) |
{ |
saved_x = x; |
saved_y = y; |
s_intensity = intensity; |
s_underline = underline; |
s_blink = blink; |
s_reverse = reverse; |
s_charset = charset; |
s_color = color; |
saved_G0 = G0_charset; |
saved_G1 = G1_charset; |
} |
|
static void restore_cur(int currcons) |
{ |
gotoxy(currcons,saved_x,saved_y); |
intensity = s_intensity; |
underline = s_underline; |
blink = s_blink; |
reverse = s_reverse; |
charset = s_charset; |
color = s_color; |
G0_charset = saved_G0; |
G1_charset = saved_G1; |
translate = set_translate(charset ? G1_charset : G0_charset); |
update_attr(currcons); |
need_wrap = 0; |
} |
|
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, |
EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, |
ESpalette }; |
|
static void reset_terminal(int currcons, int do_clear) |
{ |
top = 0; |
bottom = rows; |
vc_state = ESnormal; |
ques = 0; |
translate = set_translate(LAT1_MAP); |
G0_charset = LAT1_MAP; |
G1_charset = GRAF_MAP; |
charset = 0; |
need_wrap = 0; |
report_mouse = 0; |
utf = 0; |
utf_count = 0; |
|
disp_ctrl = 0; |
toggle_meta = 0; |
|
decscnm = 0; |
decom = 0; |
decawm = 1; |
deccm = 1; |
decim = 0; |
|
set_kbd(decarm); |
clr_kbd(decckm); |
clr_kbd(kbdapplic); |
clr_kbd(lnm); |
kbd_table[currcons].lockstate = 0; |
kbd_table[currcons].slockstate = 0; |
kbd_table[currcons].ledmode = LED_SHOW_FLAGS; |
kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; |
set_leds(); |
|
default_attr(currcons); |
update_attr(currcons); |
|
tab_stop[0] = 0x01010100; |
tab_stop[1] = |
tab_stop[2] = |
tab_stop[3] = |
tab_stop[4] = 0x01010101; |
|
bell_pitch = DEFAULT_BELL_PITCH; |
bell_duration = DEFAULT_BELL_DURATION; |
|
gotoxy(currcons,0,0); |
save_cur(currcons); |
if (do_clear) |
csi_J(currcons,2); |
} |
|
/* |
* Turn the Scroll-Lock LED on when the tty is stopped |
*/ |
static void con_stop(struct tty_struct *tty) |
{ |
int console_num; |
if (!tty) |
return; |
console_num = MINOR(tty->device) - (tty->driver.minor_start); |
if (!vc_cons_allocated(console_num)) |
return; |
set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); |
set_leds(); |
} |
|
/* |
* Turn the Scroll-Lock LED off when the console is started |
*/ |
static void con_start(struct tty_struct *tty) |
{ |
int console_num; |
if (!tty) |
return; |
console_num = MINOR(tty->device) - (tty->driver.minor_start); |
if (!vc_cons_allocated(console_num)) |
return; |
clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); |
set_leds(); |
} |
|
static int con_write(struct tty_struct * tty, int from_user, |
const unsigned char *buf, int count) |
{ |
int c, tc, ok, n = 0; |
unsigned int currcons; |
struct vt_struct *vt = (struct vt_struct *)tty->driver_data; |
|
currcons = vt->vc_num; |
if (!vc_cons_allocated(currcons)) { |
/* could this happen? */ |
static int error = 0; |
if (!error) { |
error = 1; |
printk("con_write: tty %d not allocated\n", currcons+1); |
} |
return 0; |
} |
|
/* undraw cursor first */ |
if (currcons == fg_console) |
hide_cursor(currcons); |
|
/* clear the selection */ |
if (currcons == sel_cons) |
clear_selection(); |
|
disable_bh(CONSOLE_BH); |
while (count) { |
enable_bh(CONSOLE_BH); |
c = from_user ? get_user(buf) : *buf; |
buf++; n++; count--; |
disable_bh(CONSOLE_BH); |
|
if (utf) { |
/* Combine UTF-8 into Unicode */ |
/* Incomplete characters silently ignored */ |
if(c > 0x7f) { |
if (utf_count > 0 && (c & 0xc0) == 0x80) { |
utf_char = (utf_char << 6) | (c & 0x3f); |
utf_count--; |
if (utf_count == 0) |
tc = c = utf_char; |
else continue; |
} else { |
if ((c & 0xe0) == 0xc0) { |
utf_count = 1; |
utf_char = (c & 0x1f); |
} else if ((c & 0xf0) == 0xe0) { |
utf_count = 2; |
utf_char = (c & 0x0f); |
} else if ((c & 0xf8) == 0xf0) { |
utf_count = 3; |
utf_char = (c & 0x07); |
} else if ((c & 0xfc) == 0xf8) { |
utf_count = 4; |
utf_char = (c & 0x03); |
} else if ((c & 0xfe) == 0xfc) { |
utf_count = 5; |
utf_char = (c & 0x01); |
} else |
utf_count = 0; |
continue; |
} |
} else { |
tc = c; |
utf_count = 0; |
} |
} else { /* no utf */ |
tc = translate[toggle_meta ? (c|0x80) : c]; |
} |
|
/* If the original code was a control character we |
* only allow a glyph to be displayed if the code is |
* not normally used (such as for cursor movement) or |
* if the disp_ctrl mode has been explicitly enabled. |
* Certain characters (as given by the CTRL_ALWAYS |
* bitmap) are always displayed as control characters, |
* as the console would be pretty useless without |
* them; to display an arbitrary font position use the |
* direct-to-font zone in UTF-8 mode. |
*/ |
ok = tc && (c >= 32 || |
(!utf && !(((disp_ctrl ? CTRL_ALWAYS |
: CTRL_ACTION) >> c) & 1))) |
&& (c != 127 || disp_ctrl); |
|
if (vc_state == ESnormal && ok) { |
/* Now try to find out how to display it */ |
tc = conv_uni_to_pc(tc); |
if ( tc == -4 ) { |
/* If we got -4 (not found) then see if we have |
defined a replacement character (U+FFFD) */ |
tc = conv_uni_to_pc(0xfffd); |
} else if ( tc == -3 ) { |
/* Bad hash table -- hope for the best */ |
tc = c; |
} |
if (tc & ~console_charmask) |
continue; /* Conversion failed */ |
|
if (need_wrap) { |
cr(currcons); |
lf(currcons); |
} |
|
#if 1 /* XXX */ |
/* DPC: 1994-04-12 |
* Speed up overstrike mode, using new putcs. |
* |
* P.S. I hate 8 spaces per tab! Use Emacs! |
*/ |
|
/* Only use this for the foreground console, |
where we really draw the chars */ |
|
if (count > 2 && |
!decim && !utf && currcons == fg_console) { |
static char putcs_buf[256]; |
char *p = putcs_buf; |
int putcs_count = 1; |
ushort nextx = x + 1; |
|
*p++ = tc; |
*pos++ = tc | (attr << 8); |
|
if (nextx == cols) { |
sw->con_putc(vc_cons[currcons].d, |
*putcs_buf, y, x); |
pos--; |
need_wrap = decawm; |
continue; |
} |
|
/* TAB TAB TAB - Arghh!!!! */ |
|
while (count) |
{ |
enable_bh(CONSOLE_BH); |
c = from_user ? get_user(buf) : *buf; |
disable_bh(CONSOLE_BH); |
tc = translate[toggle_meta ? (c|0x80) : c]; |
if (!tc || |
!(c >= 32 |
|| !(((disp_ctrl ? CTRL_ALWAYS |
: CTRL_ACTION) >> c) & 1))) |
break; |
tc = conv_uni_to_pc(tc); |
if (tc == -4) |
tc = conv_uni_to_pc(0xfffd); |
else if (tc == -3) |
tc = c; |
|
buf++; n++; count--; |
if (tc & ~console_charmask) |
continue; /* Conversion failed */ |
|
*p++ = tc; |
*pos++ = tc | (attr << 8); |
++putcs_count; |
++nextx; |
if (nextx == cols || |
putcs_count == sizeof (putcs_buf)) |
break; |
} |
|
sw->con_putcs(vc_cons[currcons].d, |
putcs_buf, putcs_count, y, x); |
if (nextx == cols) { |
pos--; |
x = cols-1; |
need_wrap = decawm; |
} else |
x += putcs_count; |
continue; |
} |
|
/* DPC: End of putcs support */ |
#endif |
|
if (decim) |
insert_char(currcons); |
*pos = (attr << 8) + tc; |
if (currcons == fg_console) |
sw->con_putc(vc_cons[currcons].d,tc,y,x); |
if (x == cols - 1) |
need_wrap = decawm; |
else { |
pos++; |
x++; |
} |
continue; |
} |
|
/* |
* Control characters can be used in the _middle_ |
* of an escape sequence. |
*/ |
switch (c) { |
case 7: |
if (bell_duration) |
kd_mksound(bell_pitch, bell_duration); |
continue; |
case 8: |
bs(currcons); |
continue; |
case 9: |
pos -= x; |
while (x < cols - 1) { |
x++; |
if (tab_stop[x >> 5] & (1 << (x & 31))) |
break; |
} |
pos += x; |
continue; |
case 10: case 11: case 12: |
lf(currcons); |
if (!is_kbd(lnm)) |
continue; |
case 13: |
cr(currcons); |
continue; |
case 14: |
charset = 1; |
translate = set_translate(G1_charset); |
disp_ctrl = 1; |
continue; |
case 15: |
charset = 0; |
translate = set_translate(G0_charset); |
disp_ctrl = 0; |
continue; |
case 24: case 26: |
vc_state = ESnormal; |
continue; |
case 27: |
vc_state = ESesc; |
continue; |
case 127: |
del(currcons); |
continue; |
case 128+27: |
vc_state = ESsquare; |
continue; |
} |
switch(vc_state) { |
case ESesc: |
vc_state = ESnormal; |
switch (c) { |
case '[': |
vc_state = ESsquare; |
continue; |
case ']': |
vc_state = ESnonstd; |
continue; |
case '%': |
vc_state = ESpercent; |
continue; |
case 'E': |
cr(currcons); |
lf(currcons); |
continue; |
case 'M': |
ri(currcons); |
continue; |
case 'D': |
lf(currcons); |
continue; |
case 'H': |
tab_stop[x >> 5] |= (1 << (x & 31)); |
continue; |
case 'Z': |
respond_ID(tty); |
continue; |
case '7': |
save_cur(currcons); |
continue; |
case '8': |
restore_cur(currcons); |
continue; |
case '(': |
vc_state = ESsetG0; |
continue; |
case ')': |
vc_state = ESsetG1; |
continue; |
case '#': |
vc_state = EShash; |
continue; |
case 'c': |
reset_terminal(currcons,1); |
continue; |
case '>': /* Numeric keypad */ |
clr_kbd(kbdapplic); |
continue; |
case '=': /* Appl. keypad */ |
set_kbd(kbdapplic); |
continue; |
} |
continue; |
case ESnonstd: |
if (c=='P') { /* palette escape sequence */ |
for (npar=0; npar<NPAR; npar++) |
par[npar] = 0 ; |
npar = 0 ; |
vc_state = ESpalette; |
continue; |
} else if (c=='R') { /* reset palette */ |
#if 0 |
reset_palette (currcons); |
#endif |
vc_state = ESnormal; |
} else |
vc_state = ESnormal; |
continue; |
case ESpalette: |
if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { |
par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; |
if (npar==7) { |
#if 0 |
int i = par[0]*3, j = 1; |
palette[i] = 16*par[j++]; |
palette[i++] += par[j++]; |
palette[i] = 16*par[j++]; |
palette[i++] += par[j++]; |
palette[i] = 16*par[j++]; |
palette[i] += par[j]; |
set_palette() ; |
#endif |
vc_state = ESnormal; |
} |
} else |
vc_state = ESnormal; |
continue; |
case ESsquare: |
for(npar = 0 ; npar < NPAR ; npar++) |
par[npar] = 0; |
npar = 0; |
vc_state = ESgetpars; |
if (c == '[') { /* Function key */ |
vc_state=ESfunckey; |
continue; |
} |
ques = (c=='?'); |
if (ques) |
continue; |
case ESgetpars: |
if (c==';' && npar<NPAR-1) { |
npar++; |
continue; |
} else if (c>='0' && c<='9') { |
par[npar] *= 10; |
par[npar] += c-'0'; |
continue; |
} else vc_state=ESgotpars; |
case ESgotpars: |
vc_state = ESnormal; |
switch(c) { |
case 'h': |
set_mode(currcons,1); |
continue; |
case 'l': |
set_mode(currcons,0); |
continue; |
case 'n': |
if (!ques) |
if (par[0] == 5) |
status_report(tty); |
else if (par[0] == 6) |
cursor_report(currcons,tty); |
continue; |
} |
if (ques) { |
ques = 0; |
continue; |
} |
switch(c) { |
case 'G': case '`': |
if (par[0]) par[0]--; |
gotoxy(currcons,par[0],y); |
continue; |
case 'A': |
if (!par[0]) par[0]++; |
gotoxy(currcons,x,y-par[0]); |
continue; |
case 'B': case 'e': |
if (!par[0]) par[0]++; |
gotoxy(currcons,x,y+par[0]); |
continue; |
case 'C': case 'a': |
if (!par[0]) par[0]++; |
gotoxy(currcons,x+par[0],y); |
continue; |
case 'D': |
if (!par[0]) par[0]++; |
gotoxy(currcons,x-par[0],y); |
continue; |
case 'E': |
if (!par[0]) par[0]++; |
gotoxy(currcons,0,y+par[0]); |
continue; |
case 'F': |
if (!par[0]) par[0]++; |
gotoxy(currcons,0,y-par[0]); |
continue; |
case 'd': |
if (par[0]) par[0]--; |
gotoxay(currcons,x,par[0]); |
continue; |
case 'H': case 'f': |
if (par[0]) par[0]--; |
if (par[1]) par[1]--; |
gotoxay(currcons,par[1],par[0]); |
continue; |
case 'J': |
csi_J(currcons,par[0]); |
continue; |
case 'K': |
csi_K(currcons,par[0]); |
continue; |
case 'L': |
csi_L(currcons,par[0]); |
continue; |
case 'M': |
csi_M(currcons,par[0]); |
continue; |
case 'P': |
csi_P(currcons,par[0]); |
continue; |
case 'c': |
if (!par[0]) |
respond_ID(tty); |
continue; |
case 'g': |
if (!par[0]) |
tab_stop[x >> 5] &= ~(1 << (x & 31)); |
else if (par[0] == 3) { |
tab_stop[0] = |
tab_stop[1] = |
tab_stop[2] = |
tab_stop[3] = |
tab_stop[4] = 0; |
} |
continue; |
case 'm': |
csi_m(currcons); |
continue; |
case 'q': /* DECLL - but only 3 leds */ |
/* map 0,1,2,3 to 0,1,2,4 */ |
if (par[0] < 4) |
setledstate(kbd_table + currcons, |
(par[0] < 3) ? par[0] : 4); |
continue; |
case 'r': |
if (!par[0]) |
par[0]++; |
if (!par[1]) |
par[1] = rows; |
/* Minimum allowed region is 2 lines */ |
if (par[0] < par[1] && |
par[1] <= rows) { |
top=par[0]-1; |
bottom=par[1]; |
gotoxay(currcons,0,0); |
} |
continue; |
case 's': |
save_cur(currcons); |
continue; |
case 'u': |
restore_cur(currcons); |
continue; |
case 'X': |
csi_X(currcons, par[0]); |
continue; |
case '@': |
csi_at(currcons,par[0]); |
continue; |
case ']': /* setterm functions */ |
setterm_command(currcons); |
continue; |
} |
continue; |
case ESpercent: |
vc_state = ESnormal; |
switch (c) { |
case '@': /* defined in ISO 2022 */ |
utf = 0; |
continue; |
case 'G': /* prelim official escape code */ |
case '8': /* retained for compatibility */ |
utf = 1; |
continue; |
} |
continue; |
case ESfunckey: |
vc_state = ESnormal; |
continue; |
case EShash: |
vc_state = ESnormal; |
if (c == '8') { |
/* DEC screen alignment test. kludge :-) */ |
video_erase_char = |
(video_erase_char & 0xff00) | 'E'; |
/* Arno: |
* Doesn't work, because csi_J(c,2) |
* calls con_clear and doesn't print |
* the erase char.. |
*/ |
csi_J(currcons, 2); |
video_erase_char = |
(video_erase_char & 0xff00) | ' '; |
} |
continue; |
case ESsetG0: |
if (c == '0') |
G0_charset = GRAF_MAP; |
else if (c == 'B') |
G0_charset = LAT1_MAP; |
else if (c == 'U') |
G0_charset = IBMPC_MAP; |
else if (c == 'K') |
G0_charset = USER_MAP; |
if (charset == 0) |
translate = set_translate(G0_charset); |
vc_state = ESnormal; |
continue; |
case ESsetG1: |
if (c == '0') |
G1_charset = GRAF_MAP; |
else if (c == 'B') |
G1_charset = LAT1_MAP; |
else if (c == 'U') |
G1_charset = IBMPC_MAP; |
else if (c == 'K') |
G1_charset = USER_MAP; |
if (charset == 1) |
translate = set_translate(G1_charset); |
vc_state = ESnormal; |
continue; |
default: |
vc_state = ESnormal; |
} |
} |
if (vcmode != KD_GRAPHICS) |
set_cursor(currcons); |
enable_bh(CONSOLE_BH); |
return n; |
} |
|
static int con_write_room(struct tty_struct *tty) |
{ |
if (tty->stopped) |
return 0; |
return 4096; /* No limit, really; we're not buffering */ |
} |
|
static int con_chars_in_buffer(struct tty_struct *tty) |
{ |
return 0; /* we're not buffering */ |
} |
|
void poke_blanked_console(void) |
{ |
timer_active &= ~(1<<BLANK_TIMER); |
if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) |
return; |
if (console_blanked) { |
timer_table[BLANK_TIMER].fn = unblank_screen; |
timer_table[BLANK_TIMER].expires = 0; |
timer_active |= 1<<BLANK_TIMER; |
} else if (blankinterval) { |
timer_table[BLANK_TIMER].expires = jiffies + blankinterval; |
timer_active |= 1<<BLANK_TIMER; |
} |
} |
|
|
/* DPC: New version of console_print using putcs */ |
|
void console_print(const char * b) |
{ |
int currcons = fg_console; |
unsigned char c; |
const char *start = b; |
ushort count = 0; |
ushort myx = x; |
static int printing = 0; |
|
if (!printable || printing) |
return; /* console not yet initialized */ |
printing = 1; |
|
if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) |
currcons = kmsg_redirect - 1; |
|
if (!vc_cons_allocated(currcons)) { |
/* impossible */ |
printk("console_print: tty %d not allocated ??\n", currcons+1); |
printing = 0; |
return; |
} |
|
/* undraw cursor first */ |
hide_cursor(currcons); |
|
/* Contrived structure to try to emulate original need_wrap behaviour |
* Problems caused when we have need_wrap set on '\n' character */ |
|
while ((c = *(b++)) != 0) { |
if (c == 10 || c == 13 || c == 8 || need_wrap) { |
if ((count = b - start - 1) > 0) { |
sw->con_putcs(vc_cons[currcons].d, start, count , |
y, x); |
x += count; |
if (need_wrap) |
x--; |
} |
|
if (c == 8) { /* backspace */ |
bs(currcons); |
start = b; |
myx = x; |
continue; |
} |
if (c != 13) |
lf(currcons); |
cr(currcons); |
|
if (c == 10 || c == 13) { |
start = b; myx = x; continue; |
} |
|
start = b-1; myx = x; |
} |
|
*pos = c | (attr << 8); |
if (myx == cols - 1) { |
need_wrap = 1; |
continue; |
} |
pos++; |
myx++; |
} |
|
if ((count = b - start -1) > 0) { |
sw->con_putcs(vc_cons[currcons].d, start, count , |
y, x); |
x += count; |
if (x == cols) |
{ |
x--; |
need_wrap = 1; |
} |
} |
|
set_cursor(currcons); |
poke_blanked_console(); |
printing = 0; |
} |
|
/* You didn't see this... */ |
void console_printn(const char * b, int n) |
{ |
int i; |
char buf[2]; |
|
|
buf[1] = '\0'; |
for(i=0;i<n;i++) { |
buf[0] = *b++; |
console_print(buf); |
} |
} |
|
/* |
* con_throttle and con_unthrottle are only used for |
* paste_selection(), which has to stuff in a large number of |
* characters... |
*/ |
static void con_throttle(struct tty_struct *tty) |
{ |
} |
|
static void con_unthrottle(struct tty_struct *tty) |
{ |
struct vt_struct *vt = (struct vt_struct *) tty->driver_data; |
|
wake_up_interruptible(&vt->paste_wait); |
} |
|
static void vc_init(unsigned int currcons, int do_clear) |
{ |
long base = (long) vc_scrbuf[currcons]; |
|
pos = (unsigned short *)(origin = (ulong)video_mem_start = base); |
scr_end = base + screenbuf_size; |
video_mem_end = base + screenbuf_size; |
reset_vc(currcons); |
def_color = 0x07; /* white */ |
ulcolor = 0x0f; /* bold white */ |
halfcolor = 0x08; /* grey */ |
vt_cons[currcons]->paste_wait = 0; |
reset_terminal(currcons, do_clear); |
} |
|
/* |
* This is the console switching bottom half handler. |
* |
* Doing console switching in a bottom half handler allows |
* us to do the switches asynchronously (needed when we want |
* to switch due to a keyboard interrupt), while still giving |
* us the option to easily disable it to avoid races when we |
* need to write to the console. |
*/ |
static void console_bh(void) |
{ |
if (want_console >= 0) { |
if (want_console != fg_console) { |
change_console(want_console); |
/* we only changed when the console had already |
been allocated - a new console is not created |
in an interrupt routine */ |
} |
want_console = -1; |
} |
if (do_poke_blanked_console) { /* do not unblank for a LED change */ |
do_poke_blanked_console = 0; |
poke_blanked_console(); |
} |
} |
|
/* |
* unsigned long con_init(unsigned long); |
* |
* This routine initializes console interrupts, and does nothing |
* else. If you want the screen to clear, call tty_write with |
* the appropriate escape-sequence. |
* |
* Reads the information preserved by setup.s to determine the current display |
* type and sets everything accordingly. |
*/ |
unsigned long con_init(unsigned long kmem_start) |
{ |
} |
|
void vesa_powerdown_screen(void) |
{ |
int currcons = fg_console; |
|
timer_active &= ~(1<<BLANK_TIMER); |
timer_table[BLANK_TIMER].fn = unblank_screen; |
|
/* Power down if currently suspended (1 or 2), |
* suspend if currently blanked (0), |
* else do nothing (i.e. already powered down (3)). |
* Called only if powerdown features are allowed. |
*/ |
switch (vesa_blank_mode) { |
case 0: |
sw->con_blank(2); |
break; |
case 1: |
case 2: |
sw->con_blank(4); |
break; |
} |
} |
|
void do_blank_screen(int nopowersave) |
{ |
#if 0 |
int currcons; |
|
if (console_blanked) |
return; |
|
if (!vc_cons_allocated(fg_console)) { |
/* impossible */ |
printk("blank_screen: tty %d not allocated ??\n", fg_console+1); |
return; |
} |
|
/* don't blank graphics */ |
if (vt_cons[fg_console]->vc_mode == KD_TEXT) { |
if (vesa_off_interval && !nopowersave) { |
timer_table[BLANK_TIMER].fn = vesa_powerdown_screen; |
timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval; |
timer_active |= (1<<BLANK_TIMER); |
} else { |
timer_active &= ~(1<<BLANK_TIMER); |
timer_table[BLANK_TIMER].fn = unblank_screen; |
} |
|
/* try not to lose information by blanking, |
and not to waste memory */ |
currcons = fg_console; |
has_scrolled = 0; |
sw->con_blank(1); |
if (!nopowersave) |
sw->con_blank(vesa_blank_mode + 1); |
} |
else |
hide_cursor(fg_console); |
console_blanked = fg_console + 1; |
#endif |
} |
|
void do_unblank_screen(void) |
{ |
#if 0 |
int currcons; |
|
if (!console_blanked) |
return; |
if (!vc_cons_allocated(fg_console)) { |
/* impossible */ |
printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); |
return; |
} |
timer_table[BLANK_TIMER].fn = blank_screen; |
if (blankinterval) { |
timer_table[BLANK_TIMER].expires = jiffies + blankinterval; |
timer_active |= 1<<BLANK_TIMER; |
} |
|
currcons = fg_console; |
console_blanked = 0; |
if (sw->con_blank (0)) |
/* Low-level driver cannot restore -> do it ourselves */ |
update_screen( fg_console ); |
set_cursor (fg_console); |
#endif |
} |
|
void update_screen(int new_console) |
{ |
int currcons = fg_console; |
int xx, yy, startx, attr_save; |
char buf[256], *bufp; |
unsigned short *p; |
static int lock = 0; |
|
if (/* new_console == fg_console || */ lock) |
return; |
if (!vc_cons_allocated(new_console)) { |
/* strange ... */ |
printk("update_screen: tty %d not allocated ??\n", new_console+1); |
return; |
} |
lock = 1; |
|
clear_selection(); |
|
currcons = fg_console = new_console; |
sw->con_cursor (vc_cons[currcons].d, CM_ERASE); |
sw->con_switch (vc_cons[new_console].d); |
/* Update the screen contents */ |
p = video_mem_start; |
attr_save = attr; |
for (yy = 0; yy < rows; yy++) |
{ |
bufp = buf; |
for (startx = xx = 0; xx < cols; xx++) |
{ |
if (attr != ((*p >> 8) & 0xff)) |
{ |
if (bufp > buf) |
sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, |
yy, startx); |
startx = xx; |
bufp = buf; |
attr = (*p >> 8) & 0xff; |
} |
*bufp++ = *p++; |
if (bufp == buf + sizeof (buf)) |
{ |
sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, |
yy, startx); |
startx = xx + 1; |
bufp = buf; |
} |
} |
if (bufp > buf) |
sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, |
yy, startx); |
} |
set_cursor (currcons); |
attr = attr_save; |
set_leds(); |
compute_shiftstate(); |
lock = 0; |
} |
|
/* |
* If a blank_screen is due to a timer, then a power save is allowed. |
* If it is related to console_switching, then avoid vesa_blank(). |
*/ |
static void blank_screen(void) |
{ |
do_blank_screen(0); |
} |
|
static void unblank_screen(void) |
{ |
do_unblank_screen(); |
} |
|
/* |
* Allocate the console screen memory. |
*/ |
int con_open(struct tty_struct *tty, struct file * filp) |
{ |
unsigned int currcons; |
int i; |
|
currcons = MINOR(tty->device) - tty->driver.minor_start; |
|
i = vc_allocate(currcons); |
if (i) |
return i; |
|
vt_cons[currcons]->vc_num = currcons; |
tty->driver_data = vt_cons[currcons]; |
|
if (!tty->winsize.ws_row && !tty->winsize.ws_col) { |
tty->winsize.ws_row = rows; |
tty->winsize.ws_col = cols; |
} |
|
return 0; |
} |
|
/* |
* PIO_FONT support. |
* |
* Currently we only support 8 pixels wide fonts, at a maximum height |
* of 32 pixels. Userspace fontdata is stored with 32 bytes reserved |
* for each character which is kinda wasty, but this is done in order |
* to maintain compatibility with the EGA/VGA fonts. It is upto the |
* actual low-level console-driver convert data into its favorite |
* format (maybe we should add a `fontoffset' field to the `display' |
* structure so we wont have to convert the fontdata all the time. |
* /Jes |
*/ |
|
#define cmapsz 8192 |
|
static int set_get_font(char * arg, int set, int ch512) |
{ |
#ifdef CAN_LOAD_EGA_FONTS |
int i, unit, size; |
char *charmap; |
|
if (arg){ |
i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, |
(void *)arg, ch512 ? 2*cmapsz : cmapsz); |
if (i) |
return i; |
}else |
return -EINVAL; |
|
|
size = ch512 ? 2*cmapsz : cmapsz; |
|
charmap = (char *)kmalloc(size, GFP_USER); |
|
if (set){ |
memcpy_fromfs(charmap, arg, size); |
|
for (unit = 32; unit > 0; unit--) |
for (i = 0; i < (ch512 ? 512 : 256); i++) |
if (charmap[32*i+unit-1]) |
goto nonzero; |
nonzero: |
i = conswitchp->con_set_font(vc_cons[fg_console].d, 8, |
unit, charmap); |
}else{ |
memset(charmap, 0, size); |
i = conswitchp->con_get_font(vc_cons[fg_console].d, |
&unit, &unit, charmap); |
memcpy_tofs(arg, charmap, size); |
} |
kfree(charmap); |
|
return i; |
#else |
return -EINVAL; |
#endif |
} |
|
/* |
* Load palette into the EGA/VGA DAC registers. arg points to a colour |
* map, 3 bytes per colour, 16 colours, range from 0 to 255. |
*/ |
|
int con_set_cmap (unsigned char *arg) |
{ |
return -EINVAL; |
} |
|
int con_get_cmap (unsigned char *arg) |
{ |
return -EINVAL; |
} |
|
void reset_palette(int currcons) |
{ |
} |
|
void set_palette(void) |
{ |
} |
|
/* |
* Load font into the EGA/VGA character generator. arg points to a 8192 |
* byte map, 32 bytes per character. Only first H of them are used for |
* 8xH fonts (0 < H <= 32). |
*/ |
|
int con_set_font (char *arg, int ch512) |
{ |
int i; |
|
i = set_get_font (arg,1,ch512); |
if ( !i ) { |
hashtable_contents_valid = 0; |
video_mode_512ch = ch512; |
console_charmask = ch512 ? 0x1ff : 0x0ff; |
} |
return i; |
} |
|
int con_get_font (char *arg) |
{ |
return set_get_font (arg,0,video_mode_512ch); |
} |
|
/* |
* Adjust the screen to fit a font of a certain height |
* |
* Returns < 0 for error, 0 if nothing changed, and the number |
* of lines on the adjusted console if changed. |
*/ |
int con_adjust_height(unsigned long fontheight) |
{ |
return -EINVAL; |
} |
|
void set_vesa_blanking(int arg) |
{ |
char *argp = (char *)arg + 1; |
unsigned int mode = get_fs_byte(argp); |
vesa_blank_mode = (mode < 4) ? mode : 0; |
} |
|
unsigned long get_video_num_lines(unsigned int currcons) |
{ |
return(rows); |
} |
|
unsigned long get_video_num_columns(unsigned int currcons) |
{ |
return(cols); |
} |
|
unsigned long get_video_size_row(unsigned int currcons) |
{ |
return(size_row); |
} |
|
/* |
* Report the current status of the vc. This is exported to modules (ARub) |
*/ |
|
int con_get_info(int *mode, int *shift, int *col, int *row, |
struct tty_struct **tty) |
{ |
extern int shift_state; |
extern struct tty_driver console_driver; |
struct tty_struct **console_table=console_driver.table; |
|
if (mode) *mode = vt_cons[fg_console]->vc_mode; |
if (shift) *shift = shift_state; |
if (col) *col = video_num_columns; |
if (row) *row = video_num_lines; |
if (tty) *tty = console_table[fg_console]; |
return fg_console; |
} |
/kernel/prcb.S
0,0 → 1,103
#include <linux/linkage.h> |
/* initial PRCB */ |
|
.globl _prcb |
.align 4 /* or .align 2 */ |
|
_prcb: |
.word boot_flt_table # 0 - Fault Table |
.word _boot_control_table # 4 - Control Table |
.word 0x00001000 # 8 - AC reg mask overflow fault |
.word 0x40000001 # 12 - Flt CFG- Allow Unaligned |
.word boot_intr_table # 16 - Interrupt Table |
.word sys_proc_table # 20 - System Procedure Table |
.word 0 # 24 - Reserved |
.word _intr_stack # 28 - Interrupt Stack Pointer |
.word 0x00000000 # 32 - Inst. Cache - enable cache |
.word 0x5 # 36 - Register Cache Config.- 5 sets cached |
|
/* ROM system procedure table */ |
|
.equ supervisor_proc, 2 |
.text |
.align 6 /* or .align 2 or .align 4 */ |
|
sys_proc_table: |
.space 12 # Reserved |
.word _supervisor_stack # Supervisor stack pointer |
.space 32 # Preserved |
.word SYMBOL_NAME(system_call) # sysproc 0 |
.space 258*4 # sysproc 1-258 |
|
/* Fault Table */ |
|
.equ syscall, 2 |
.equ fault_proc, 7 |
.text |
.align 4 |
|
boot_flt_table: |
|
.word (fault_proc<<2) + syscall # 0-Parallel Fault |
.word 0x27f |
.word (fault_proc<<2) + syscall # 1-Trace Fault |
.word 0x27f |
.word (fault_proc<<2) + syscall # 2-Operation Fault |
.word 0x27f |
.word (fault_proc<<2) + syscall # 3-Arithmetic Fault |
.word 0x27f |
.word (fault_proc<<2) + syscall # 4-Reserved |
.word 0x27f |
.word (fault_proc<<2) + syscall # 5-Constraint Fault |
.word 0x27f |
.word (fault_proc<<2) + syscall # 6-Reserved |
.word 0x27f |
.word (fault_proc<<2) + syscall # 7-Protection Fault |
.word 0x27f |
.word (fault_proc<<2) + syscall # 8-Reserved |
.word 0x27f |
.word (fault_proc<<2) + syscall # 9-Reserved |
.word 0x27f |
.word (fault_proc<<2) + syscall # 0xa-Type Fault |
.word 0x27f |
.space 21*8 # reserved |
|
/* Boot Interrupt Table */ |
|
.text |
|
boot_intr_table: |
|
.word 0 |
.word 0, 0, 0, 0, 0, 0, 0, 0 |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
.word _intr, _intr, _intr, _intr, _intr, _intr, _intr, _intr |
/kernel/mon960_calls.c
0,0 → 1,56
/* |
* FILE: mon960_calls.c |
* AUTHOR: kma |
* DESCR: system calls to mon960 |
*/ |
|
#ident "$Id: mon960_calls.c,v 1.1.1.1 2001-09-10 07:43:56 simons Exp $" |
|
#include <linux/config.h> |
#include <asm/mon960.h> |
|
#define SYSCALL(number) \ |
asm("calls %0; ret" \ |
: : "lI"(number): "g0"); |
|
unsigned long mon_entry(void) |
{ |
SYSCALL(254); |
} |
|
unsigned long get_prcbptr(void) |
{ |
SYSCALL(245); |
} |
|
void mon960_exit(int val) |
{ |
SYSCALL(257); |
} |
|
#ifdef CONFIG_PCI |
|
int mon960_pcibios_present(void* info) |
{ SYSCALL(100); } |
int mon960_pcibios_find_device(int vnd, int dev, int idx, void* loc) |
{ SYSCALL(101); } |
int mon960_pcibios_find_class(int class, int idx, void* dev) |
{ SYSCALL(102); } |
|
#define BIOS_OP(op,sz,type,nr) \ |
int \ |
mon960_pcibios_ ## op ## _config_ ##sz(unsigned short vec, \ |
unsigned short dev, \ |
unsigned short func, \ |
unsigned char off, \ |
type val) \ |
{ SYSCALL(nr); } |
|
BIOS_OP(read,byte,unsigned char*,104) |
BIOS_OP(read,word,unsigned short*,105) |
BIOS_OP(read,dword,unsigned int*,106) |
BIOS_OP(write,byte,unsigned char,107) |
BIOS_OP(write,word,unsigned short,108) |
BIOS_OP(write,dword,unsigned int,109) |
|
#endif |
/kernel/ksyms.c
0,0 → 1,69
#include <linux/config.h> |
#include <linux/module.h> |
#include <linux/linkage.h> |
#include <linux/sched.h> |
#include <linux/string.h> |
#include <linux/mm.h> |
#include <linux/user.h> |
#include <linux/elfcore.h> |
|
#include <asm/setup.h> |
#include <asm/pgtable.h> |
#include <asm/irq.h> |
#include <asm/semaphore.h> |
|
asmlinkage long long __ashrdi3 (long long, int); |
extern char m68k_debug_device[]; |
|
#ifdef CONFIG_ATARI |
extern void mach_atari_syms_export (void); |
#endif |
#ifdef CONFIG_AMIGA |
extern void mach_amiga_syms_export (void); |
#endif |
#ifdef CONFIG_MAC |
extern void mach_mac_syms_export (void); |
#endif |
|
extern void dump_thread(struct pt_regs *, struct user *); |
extern int dump_fpu(elf_fpregset_t *); |
|
static struct symbol_table arch_symbol_table = { |
#include <linux/symtab_begin.h> |
/* platform dependent support */ |
|
X(memcmp), |
/*X(boot_info), |
X(m68k_is040or060), |
X(cache_push), |
X(cache_push_v), |
X(cache_clear), |
X(mm_vtop), |
X(mm_ptov), |
X(mm_end_of_chunk), |
X(kernel_map),*/ |
/*X(m68k_debug_device),*/ |
X(request_irq), |
X(free_irq), |
X(dump_fpu), |
X(dump_thread), |
X(strnlen), |
X(strstr), |
|
/* The following are special because they're not called |
explicitly (the C compiler generates them). Fortunately, |
their interface isn't gonna change any time soon now, so |
it's OK to leave it out of version control. */ |
XNOVERS(__ashrdi3), |
XNOVERS(memcpy), |
XNOVERS(memset), |
|
#include <linux/symtab_end.h> |
}; |
|
void arch_syms_export(void) |
{ |
register_symtab(&arch_symbol_table); |
|
/*our_syms_export()*/ |
} |
/kernel/mon960-head.S
0,0 → 1,35
/* mon960 head.S code: should be extremely simple, since mon960 takes care |
of almost all our requirements for us. We're at ipl 31 (highest), |
interrupts are off, we have a C stack frame set up for us, etc. |
This is modelled after the alpha head.S (excerpt below), which |
actually does some other cruft before calling start_kernel, but without |
knowning the alpha instruction set I can't tell for sure what's |
happening. |
|
For now I'll stick with just a call, as it seems to work in other |
places. |
|
alpha head.S: |
__start: |
br $27,1f |
1: ldgp $29,0($27) |
lda $27,start_kernel |
jsr $26,($27),start_kernel |
halt |
.end __start |
*/ |
|
|
#define __ASSEMBLY__ |
#include <asm/system.h> |
|
.align 4 |
.globl _stext |
.globl __start |
.ent __start |
|
_stext: |
__start: |
call start_kernel |
halt |
.end __start |
/kernel/mon960_console.c
0,0 → 1,181
/* |
* FILE: mon960_console.c |
* AUTHOR: kma |
* DESCR: serial console for TI's 16552 serial controller |
*/ |
|
#ident "$Id: mon960_console.c,v 1.1.1.1 2001-09-10 07:43:56 simons Exp $" |
|
#include <linux/tty.h> |
#include <linux/tty_driver.h> |
#include <linux/major.h> |
#include <linux/interrupt.h> |
#include <asm/system.h> |
#include <asm/delay.h> |
|
#define SER16552_LSR ((volatile unsigned char*)0xe0000014) /* line status */ |
#define SER16552_THR ((volatile unsigned char*)0xe0000000) /* send fifo */ |
#define SER16552_RBR ((volatile unsigned char*)0xe0000000) /* rcv fifo */ |
#define SER16552_IER ((volatile unsigned char*)0xe0000004) /* int enable */ |
|
#define LSR_READY 1 |
#define LSR_SEND_READY 0x20 |
#define LSR_RECEIVE_READY 0x1 |
#define LSR_BREAK (1 << 4) |
|
#define IER_RCV_ENABLE 1 |
#define IER_SEND_ENABLE 2 |
|
static int console_refcount; |
static struct tty_struct *console_table[1]; |
static struct termios *console_termios[1]; |
static struct termios *console_termios_locked[1]; |
static struct tty_driver console_driver; |
|
/* |
* The interrupt for the 16552; should only happen for reads |
*/ |
void do_16552_intr(void) |
{ |
unsigned char buf[16]; |
int ii; |
struct tty_struct *tty = console_table[0]; |
unsigned long lsr; |
|
/* Drain the fifo into the tty */ |
for (ii=0; (lsr = *SER16552_LSR) & LSR_RECEIVE_READY; ii++) { |
/* If there was a break, enter the debugger */ |
#ifdef CONFIG_MON960 |
char garbage; |
if (lsr & LSR_BREAK) { |
extern void system_break(void); |
system_break(); |
garbage = *SER16552_RBR; |
ii--; |
} |
else |
#endif |
buf[ii] = *SER16552_RBR; |
} |
|
|
if (ii) |
tty->ldisc.receive_buf(tty, buf, 0, ii); |
} |
|
#if 0 |
static void do_16552_bh(void) |
{ |
printk("in 16552 bottom half!\n"); |
printk("umm... yeah.\n"); |
} |
#endif |
|
static inline void putc_16552(char c, int blocking) |
{ |
unsigned long flags; |
|
save_flags(flags); |
cli(); |
top: |
while (!(*SER16552_LSR & LSR_SEND_READY)) { |
udelay(1000); |
} |
|
*SER16552_THR = c; |
|
if (c == '\n') { |
c = '\r'; |
goto top; |
} |
restore_flags(flags); |
} |
|
void console_print_mon960(const char* msg) |
{ |
long flags; |
char c; |
|
save_flags(flags); |
cli(); |
while (c = *msg++) |
putc_16552(c, 0); |
|
restore_flags(flags); |
} |
|
/* |
* XXX: make this interrupt driven if it's coming from the user |
*/ |
static int con_write(struct tty_struct* tty, int from_user, |
const unsigned char* buf, int count) |
{ |
int ii = count; |
|
while (ii--) |
putc_16552(*buf++, from_user); |
return count; |
} |
|
static int con_chars_in_buffer(struct tty_struct *tty) |
{ |
return 0; /* we're not buffering */ |
} |
|
static int con_writeroom(struct tty_struct *tty) |
{ |
return 8192; /* could return anything */ |
} |
|
static void con_putchar(struct tty_struct* tty, unsigned char c) |
{ |
putc_16552(c, 0); |
} |
|
static int con_open(struct tty_struct* tty, struct file* filp) |
{ |
return 0; |
} |
|
/* |
* register our tty driver |
*/ |
|
void mon960_console_init(void) |
{ |
memset(&console_driver, 0, sizeof(console_driver)); |
console_driver.magic = TTY_DRIVER_MAGIC; |
console_driver.name = "tty"; |
console_driver.name_base = 1; |
console_driver.major = TTY_MAJOR; |
console_driver.minor_start = 1; |
console_driver.num = 1; |
console_driver.type = TTY_DRIVER_TYPE_SERIAL; |
console_driver.init_termios = tty_std_termios; |
console_driver.init_termios.c_lflag |= ISIG | ICANON | ECHO |
| ECHOE | ECHOK ; |
console_driver.init_termios.c_iflag |= ICRNL; |
console_driver.init_termios.c_cflag = CS8 | CREAD | CLOCAL; |
console_driver.flags = TTY_DRIVER_REAL_RAW; |
console_driver.refcount = &console_refcount; |
|
console_driver.table = console_table; |
console_driver.termios = console_termios; |
console_driver.termios_locked = console_termios_locked; |
|
console_driver.open = con_open; |
console_driver.write = con_write; |
console_driver.put_char = con_putchar; |
console_driver.write_room = con_writeroom; |
console_driver.chars_in_buffer = con_chars_in_buffer; |
|
if (tty_register_driver(&console_driver)) { |
printk("Couldn't register console driver\n"); |
} |
|
/* |
* Enable receive interrupts |
*/ |
*SER16552_IER = IER_RCV_ENABLE; |
|
} |
/kernel/syscall.c
0,0 → 1,260
/* |
* FILE: syscall.c |
* AUTHOR: kma |
* DESCR: High-level system call path. |
*/ |
|
#ident "$Id: syscall.c,v 1.1.1.1 2001-09-10 07:43:56 simons Exp $" |
#include <linux/sched.h> |
#include <linux/mm.h> |
#include <linux/sem.h> |
#include <linux/msg.h> |
#include <linux/shm.h> |
|
#include <asm/unistd.h> |
#include <asm/cachectl.h> |
#include <asm/dprintk.h> |
#include <asm/mman.h> |
|
#ifdef DEBUG |
#define CHECK_STACK() \ |
do { \ |
unsigned long sp; \ |
\ |
__asm__ __volatile__("mov sp, %0" : "=r"(sp)); \ |
if (current->pid \ |
&& (!(sp > current->kernel_stack_page \ |
&& sp < (current->kernel_stack_page + PAGE_SIZE)))) \ |
panic("bad ksp: 0x%8x\ncurrent ksp: 0x%8x", sp, \ |
current->kernel_stack_page); \ |
} while(0) |
#else |
#define CHECK_STACK() \ |
do { } while (0) |
#endif |
|
extern void system_break(void); |
extern int (*syscall_tab[])(int, int, int, int, int); |
static int sys_mmap(struct pt_regs* regs); |
|
asmlinkage void |
csyscall(struct pt_regs* regs) |
{ |
unsigned long num = regs->gregs[13]; |
extern void stack_trace(void); |
extern void leave_kernel(struct pt_regs* regs); |
|
CHECK_STACK(); |
#if 0 |
if (user_mode(regs)) { |
printk("syscall %d; pc == 0x%8x\n", num, get_pc()); |
stack_trace(); |
} |
#endif |
if (num >= 0 && num < __NR_nocall) { |
switch(num) { |
/* |
* system calls that need the regs |
*/ |
case __NR_fork: |
case __NR_clone: |
case __NR_execve: |
case __NR_sigsuspend: |
regs->gregs[0] = ((int (*)(int))(syscall_tab[num]))((int)regs); |
break; |
|
#ifdef DEBUG /* help debug user applications */ |
case __NR_dbg_break: |
printk("break: %s\n", regs->gregs[0]); |
system_break(); |
break; |
|
case __NR_dbg_hexprint: |
printk("value: %x\n", regs->gregs[0]); |
break; |
#endif |
case __NR_mmap: |
regs->gregs[0] = sys_mmap(regs); |
#if 0 |
dprintk("mmap: returning 0x%8x\n", |
regs->gregs[0]); |
#endif |
break; |
|
default: |
regs->gregs[0] = |
syscall_tab[num](regs->gregs[0], |
regs->gregs[1], |
regs->gregs[2], |
regs->gregs[3], |
regs->gregs[4]); |
break; |
} |
} else { |
regs->gregs[0] = -ENOSYS; |
} |
#if 0 |
printk("csyscall: returning %p\n", regs->gregs[0]); |
stack_trace(); |
#endif |
|
leave_kernel(regs); |
} |
|
static int |
sys_mmap(struct pt_regs* regs) |
{ |
struct file* file = 0; |
unsigned long flags = regs->gregs[3]; |
|
if (!(flags & MAP_ANON)) { |
unsigned long fd = regs->gregs[4]; |
if (fd >= NR_OPEN || !(file = current->files->fd[fd])) |
return -EBADF; |
} |
|
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); |
return do_mmap(file, regs->gregs[0], regs->gregs[1], regs->gregs[2], |
flags, regs->gregs[5]); |
} |
|
asmlinkage int |
sys_fork(struct pt_regs* regs) |
{ |
return do_fork(SIGCHLD|CLONE_WAIT, regs->lregs[PT_SP], regs); |
} |
|
asmlinkage int |
sys_clone(struct pt_regs* regs) |
{ |
dprintk("in sys_clone\n"); |
return do_fork(regs->gregs[0], regs->gregs[1], regs); |
} |
|
asmlinkage int |
sys_execve(struct pt_regs* regs) |
{ |
dprintk("sys_execve: %s, %p, %p\n", |
regs->gregs[0], regs->gregs[1], regs->gregs[2]); |
return do_execve((void*)regs->gregs[0], (void*)regs->gregs[1], |
(void*)regs->gregs[2], regs); |
} |
|
asmlinkage int |
sys_ioperm(unsigned long from, unsigned long num, int turn_on) |
{ |
return -EINVAL; |
} |
|
asmlinkage int |
sys_ipc (uint call, int first, int second, int third, void* ptr, long fifth) |
{ |
int version; |
|
version = call >> 16; |
call &= 0xffff; |
|
if (call <= SEMCTL) |
switch (call) { |
case SEMOP: |
return sys_semop (first, (struct sembuf *)ptr, second); |
case SEMGET: |
return sys_semget (first, second, third); |
case SEMCTL: { |
union semun fourth; |
int err; |
if (!ptr) |
return -EINVAL; |
if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) |
return err; |
fourth.__pad = (void *) get_fs_long(ptr); |
return sys_semctl (first, second, third, fourth); |
} |
default: |
return -EINVAL; |
} |
if (call <= MSGCTL) |
switch (call) { |
case MSGSND: |
return sys_msgsnd (first, (struct msgbuf *) ptr, |
second, third); |
case MSGRCV: |
switch (version) { |
case 0: { |
struct ipc_kludge tmp; |
int err; |
if (!ptr) |
return -EINVAL; |
if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) |
return err; |
memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, |
sizeof (tmp)); |
return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); |
} |
case 1: default: |
return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); |
} |
case MSGGET: |
return sys_msgget ((key_t) first, second); |
case MSGCTL: |
return sys_msgctl (first, second, (struct msqid_ds *) ptr); |
default: |
return -EINVAL; |
} |
if (call <= SHMCTL) |
switch (call) { |
case SHMAT: |
switch (version) { |
case 0: default: { |
ulong raddr; |
int err; |
if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) |
return err; |
err = sys_shmat (first, (char *) ptr, second, &raddr); |
if (err) |
return err; |
put_fs_long (raddr, (ulong *) third); |
return 0; |
} |
case 1: /* iBCS2 emulator entry point */ |
if (get_fs() != get_ds()) |
return -EINVAL; |
return sys_shmat (first, (char *) ptr, second, (ulong *) third); |
} |
case SHMDT: |
return sys_shmdt ((char *)ptr); |
case SHMGET: |
return sys_shmget (first, second, third); |
case SHMCTL: |
return sys_shmctl (first, second, (struct shmid_ds *) ptr); |
default: |
return -EINVAL; |
} |
return -EINVAL; |
|
} |
|
asmlinkage int |
sys_cacheflush(char* addr, int nbytes, int cache) |
{ |
if (cache & ICACHE) |
__asm__ __volatile__ ("icctl 2, g0, g0"); |
|
if (cache & DCACHE) |
__asm__ __volatile__ ("dcctl 2, g0, g0"); |
|
return 0; |
} |
|
void |
kthread_start(void (*func)(void*), void* arg) |
{ |
extern long _etext, _stext; |
|
CHECK_STACK(); |
if ( ((unsigned long)func > (unsigned long)&_etext) |
|| ((unsigned long)func < (unsigned long)&_stext) ) { |
panic("XXX: bad kthread addr: %p\n", func); |
} |
func(arg); |
} |
/kernel/signal.c
0,0 → 1,251
/* |
* linux/arch/i960/kernel/signal.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Based on: |
* |
* linux/arch/m68k/kernel/signal.c |
* |
* Copyright (C) 1991, 1992 Linus Torvalds |
* |
* This file is subject to the terms and conditions of the GNU General Public |
* License. See the file COPYING in the main directory of this archive |
* for more details. |
*/ |
|
#include <linux/config.h> |
|
#include <linux/sched.h> |
#include <linux/mm.h> |
#include <linux/kernel.h> |
#include <linux/signal.h> |
#include <linux/errno.h> |
#include <linux/wait.h> |
#include <linux/ptrace.h> |
#include <linux/unistd.h> |
|
#include <asm/setup.h> |
#include <asm/segment.h> |
#include <asm/pgtable.h> |
#include <asm/traps.h> |
|
|
#define _S(nr) (1<<((nr)-1)) |
|
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) |
|
int do_signal(struct pt_regs *regs); |
|
/* |
* atomically swap in the new signal mask, and wait for a signal. |
*/ |
asmlinkage int do_sigsuspend(struct pt_regs* regs) |
{ |
int err; |
sigset_t* set = (sigset_t*) regs->gregs[0]; |
unsigned long mask; |
|
if ((err=verify_area(VERIFY_READ, set, 4))) |
return -EINTR; |
|
mask = current->blocked; |
current->blocked = *set & _BLOCKABLE; |
regs->gregs[0] = -EINTR; |
for (;;) { |
current->state = TASK_INTERRUPTIBLE; |
schedule(); |
if (do_signal(regs)) |
return -EINTR; |
} |
} |
|
/* |
* We don't ever need this on i960; the function return path lets setup_frame |
* return straight to the faulting instruction. |
*/ |
asmlinkage int do_sigreturn(unsigned long __unused) |
{ |
printk("killing %d for trying to sigreturn\n"); |
do_exit(SIGSEGV); |
return -1; |
} |
|
#define STACK_ALIGN 16 |
static inline unsigned long stack_align(unsigned long sp) |
{ |
int lobits = sp & (STACK_ALIGN -1); |
|
if (sp & lobits) |
sp += STACK_ALIGN - lobits; |
return sp; |
} |
|
/* |
* Note that 'init' is a special process: it doesn't get signals it doesn't |
* want to handle. Thus you cannot kill init even with a SIGKILL even by |
* mistake. |
* |
* Note that we go through the signals twice: once to check the signals |
* that the kernel can handle, and then we build all the user-level signal |
* handling stack-frames in one go after that. |
* |
* XXX: todo: sigcontext stuff. |
*/ |
|
asmlinkage int do_signal(struct pt_regs *regs) |
{ |
unsigned long mask = ~current->blocked; |
unsigned long handler_signal = 0; |
unsigned long signr; |
struct sigaction * sa; |
|
while ((signr = current->signal & mask)) { |
signr = ffz(~signr); |
clear_bit(signr, ¤t->signal); |
sa = current->sig->action + signr; |
signr++; |
|
if ((current->flags & PF_PTRACED) && signr != SIGKILL) { |
current->exit_code = signr; |
current->state = TASK_STOPPED; |
notify_parent(current, signr); |
schedule(); |
|
if (!(signr = current->exit_code)) |
continue; |
current->exit_code = 0; |
if (signr == SIGSTOP) |
continue; |
if (_S(signr) & current->blocked) { |
current->signal |= _S(signr); |
continue; |
} |
sa = current->sig->action + signr - 1; |
} |
|
if (sa->sa_handler == SIG_IGN) { |
if (signr != SIGCHLD) |
continue; |
/* SIGCHLD is special */ |
while (sys_waitpid(-1,0,WNOHANG) > 0) |
; |
continue; |
} |
if (sa->sa_handler == SIG_DFL) { |
if (current->pid == 1) |
continue; |
switch(signr) { |
case SIGCONT: case SIGCHLD: case SIGWINCH: |
continue; |
case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: |
if (current->flags & PF_PTRACED) |
continue; |
current->state = TASK_STOPPED; |
current->exit_code = signr; |
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & |
SA_NOCLDSTOP)) |
notify_parent(current, signr); |
schedule(); |
continue; |
|
case SIGQUIT: case SIGILL: case SIGTRAP: |
case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: |
if (current->binfmt && current->binfmt->core_dump) { |
if (current->binfmt->core_dump(signr, regs)) |
signr |= 0x80; |
} |
/* fall through */ |
default: |
current->signal |= _S(signr & 0x7f); |
current->flags |= PF_SIGNALED; |
do_exit(signr); |
} |
} |
|
/* |
* OK, we're invoking a handler |
*/ |
#ifdef DEBUG |
printk("user-specified handler for signal: %d\n", signr); |
#endif |
handler_signal |= 1 << (signr-1); |
mask &= ~sa->sa_mask; |
} |
|
if (! handler_signal) |
return 0; |
|
/* |
* We chain user frames for the various handlers together. Since we use |
* local regs to pass parameters, all RIPs go to the asm routine |
* signal_head found in entry.S; if we were an MMU-full system, we would |
* have to copy signal_head out to the user process's stack. |
*/ |
{ |
extern void signal_head(void); |
struct frame { |
unsigned long pfp; |
unsigned long sp; |
unsigned long rip; |
unsigned long* args[13]; |
} *userframe, *newframe; |
unsigned long type; |
|
#ifdef DEBUG |
stack_trace(); |
#endif |
asm("flushreg"); |
type = regs->lregs[PT_PFP] & 0x7; |
#ifdef DEBUG |
printk("pfp, type: 0x%8x, 0x%8x\n", regs->lregs[PT_PFP], type); |
#endif |
userframe = (struct frame*) |
(((unsigned long) regs->lregs[PT_PFP]) & ~0x7); |
#ifdef DEBUG |
printk("userframe: 0x%8x\n", userframe); |
stack_trace_from((unsigned long) userframe); |
#endif |
|
for (sa=current->sig->action, signr=1, mask=1; |
mask; |
sa++, signr++, mask<<=1) { |
if (mask > handler_signal) |
break; |
if ((!(mask & handler_signal)) || (!sa->sa_handler)) |
continue; |
#ifdef DEBUG |
printk("userframe->rip: 0x%8x\n", userframe->rip); |
#endif |
newframe = stack_align(userframe->sp); |
newframe->rip = (unsigned long) signal_head; |
newframe->args[0] = (unsigned long) sa->sa_handler; |
newframe->args[1] = signr; |
#ifdef DEBUG |
printk("r3,r4: 0x%8x, %d\n", sa->sa_handler, signr); |
#endif |
newframe->pfp = (unsigned long) userframe; |
newframe->sp = (unsigned long)(newframe) + 64; |
userframe = newframe; |
} |
|
#ifdef DEBUG |
printk("done; look:\n"); |
stack_trace(); |
#endif |
regs->lregs[PT_PFP] = (unsigned long)userframe | type; |
asm("flushreg"); |
|
/* |
* appropriate syscalls should return EINTR |
*/ |
if ((type & 6) == 2 && |
(regs->gregs[0] == -ERESTARTNOHAND || |
regs->gregs[0] == -ERESTARTSYS || |
regs->gregs[0] == -ERESTARTNOINTR)) |
regs->gregs[0] = -EINTR; |
} |
|
return 1; |
} |
/kernel/ints.c
0,0 → 1,455
/* |
* linux/arch/i960/kernel/ints.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Based on: |
* |
* linux/arch/i386/kernel/irq.c |
* |
* Copyright (C) 1992 Linux Torvalds |
* |
* This file is subject to the terms and conditions of the GNU General Public |
* License. See the file COPYING in the main directory of this archive |
* for more details. |
* |
* N.B. that we treat "irq" as meaning, the high order four bits of the vector |
* number. Since there seems to be no way to set the low bits to something other |
* than 0010, this is good enough for us. |
*/ |
|
#include <linux/types.h> |
#include <linux/sched.h> |
#include <linux/kernel_stat.h> |
#include <linux/errno.h> |
#include <linux/interrupt.h> |
#include <linux/config.h> |
#include <linux/ip.h> |
#include <linux/tcp.h> |
|
#include <asm/atomic.h> |
#include <asm/system.h> |
#include <asm/irq.h> |
#include <asm/traps.h> |
#include <asm/page.h> |
#include <asm/ptrace.h> |
#include <asm/machdep.h> |
#include <asm/i960.h> |
#include <asm/unistd.h> |
|
#if defined(CONFIG_I960JX) || defined(CONFIG_I960VH) |
#include <asm/i960jx.h> |
#endif |
|
/* |
* device vectors; the *_HO macros are the corresponding indices into the |
* low-mem isr table |
*/ |
#define NMI_VEC 248 |
|
#define LED ((unsigned char*)0xe0040000) |
#define LED_THRESHOLD (HZ/2) |
|
#define TMR0_VEC_HO 0xd |
#define TMR1_VEC_HO 0xe |
#define XINT0_VEC_HO 1 |
#define XINT1_VEC_HO 2 |
#define XINT2_VEC_HO 3 |
#define XINT3_VEC_HO 4 |
#define XINT4_VEC_HO 5 |
#define XINT5_VEC_HO 6 |
#define XINT6_VEC_HO 7 |
#define XINT7_VEC_HO 8 |
|
static char* irq_names[] = { |
0, /* 0 */ |
"xint0", |
"xint1", |
"xint2", |
"xint3", |
"serial", |
"xint5", |
"xint6", |
"xint7", |
0, 0, 0, 0, |
"timer0", |
"timer1", |
0, |
}; |
|
#ifdef CONFIG_PROF_IRQ |
static struct irqstat { |
unsigned long min; |
unsigned long avg; |
unsigned long max; |
} irqstat[16]; |
#endif |
|
static void* pci_dev; |
static const char* pci_name; |
static void (*pci_isr)(int, void *, struct pt_regs *); |
|
#define __VEC(ho) (((ho) << 4) | 2) |
#define TMR0_VEC __VEC(TMR0_VEC_HO) |
#define TMR1_VEC __VEC(TMR1_VEC_HO) |
#define XINT0_VEC __VEC(XINT0_VEC_HO) |
#define XINT1_VEC __VEC(XINT1_VEC_HO) |
#define XINT2_VEC __VEC(XINT2_VEC_HO) |
#define XINT3_VEC __VEC(XINT3_VEC_HO) |
#define XINT4_VEC __VEC(XINT4_VEC_HO) |
#define SERIAL_VEC XINT4_VEC |
#define PCI_VEC XINT1_VEC |
#define XINT5_VEC __VEC(XINT5_VEC_HO) |
#define XINT6_VEC __VEC(XINT6_VEC_HO) |
#define XINT7_VEC __VEC(XINT7_VEC_HO) |
|
|
void leave_kernel(struct pt_regs* regs); |
static void nmi_intr(void); |
static void bad_intr(unsigned char vec, struct pt_regs* regs); |
static void xint(unsigned char ho, struct pt_regs* regs); |
void stack_trace(void); |
|
extern void intr(void); |
static void program_clock(void); |
|
#ifdef CONFIG_MON960 |
#include <asm/i960jx.h> |
#include <asm/mon960.h> |
|
static unsigned long get_mon960_serial_isr(void) |
{ |
prcb_t* prcb = (prcb_t*)get_prcbptr(); |
unsigned long vec = (*(unsigned long*)IMAP1 & 0x0f00) >> 8; |
|
/* on cyclone, serial isr is XINT5 */ |
return (unsigned long) prcb->pr_intr_tab->i_vectors[vec]; |
} |
|
#endif |
|
static void init_syscalls(void) |
{ |
unsigned long** prcb = (unsigned long**)get_prcbptr(); |
unsigned long* syscall_tab = prcb[5]; |
extern void syscall(void); |
/* we only use syscall 0, which is 12 words from the start of |
* the syscall table. The entry type field of 0x2 indicates a call |
* to supervisor mode. */ |
syscall_tab[12] = ((unsigned long) syscall) | 0x2; |
return; |
} |
|
/* |
* At entry here, we have a high ipl. We need to establish |
* our isr's, and enable the clock. |
*/ |
void init_IRQ(void) |
{ |
unsigned long *dram = 0; |
int ii; |
|
/* set up the following layout in low RAM for our 15 vectors: |
* 0: NMI (we have no choice about this) |
* 1-8: XINT0-7 |
* 9-12: Invalid |
* 13: Timer0. Note that Timer1 is disabled. |
* 14-15: Invalid. |
* |
* This works out nicely, since the vector number-1 is the |
* corresponding bit in IMSK; see disable_irq below. |
*/ |
atmod((void*)IMAP0, 0xffff, 0x4321); /* xint 0-3 */ |
atmod((void*)IMAP1, 0xffff, 0x8756); /* xint 4-7 */ |
atmod((void*)IMAP2, 0xff<<16, 0xed << 16); /* Timer 0, Timer 1 */ |
|
/* we vector all interrupts through intr */ |
for (ii=0; ii < 16; ii++) |
dram[ii] = (unsigned long)intr; |
|
#ifdef CONFIG_MON960 |
/* reset the XINT5 interrupt handler from software */ |
dram[XINT5_VEC_HO] = get_mon960_serial_isr(); |
#endif |
|
program_clock(); |
/* set 13th bit of ICON; enable vector caching */ |
atmod((void*)ICON, 1<<13, 1<<13); |
/* |
* XXX: what to mask is somewhat board dependent; we leave XINT4 |
* masked because Cyclone needs it to always be masked. |
*/ |
atmod((void*)IPND, ~0, 0); |
atmod((void*)IMSK, 0x30ef, 0x30ef); |
|
/* Now set up syscalls */ |
init_syscalls(); |
} |
|
#define TRR0 (volatile unsigned long*)0xff000300 |
#define TCR0 (volatile unsigned long*)0xff000304 |
#define TMR0 (volatile unsigned long*)0xff000308 |
|
#define TRR1 (volatile unsigned long*)0xff000310 |
#define TCR1 (volatile unsigned long*)0xff000314 |
#define TMR1 (volatile unsigned long*)0xff000318 |
/* some helper macros for programming the mode register, TMR0 */ |
|
/* the clock may decrement once per cpu cycle, once every two cycles, ... |
* up to eight; set the appropriate bits in TMR0 |
*/ |
#define CLOCKSHIFT 4 |
#define CLOCKDIV(x) (x << CLOCKSHIFT) |
#define CLOCKDIV1 CLOCKDIV(0) |
#define CLOCKDIV2 CLOCKDIV(1) |
#define CLOCKDIV4 CLOCKDIV(2) |
#define CLOCKDIV8 CLOCKDIV(3) |
|
#define CLOCK_ENABLE 2 /* set for clock to work */ |
#define CLOCK_AUTO_RELOAD 4 /* reload from TRR0 when we reach 0 */ |
#define CLOCK_SUPER_ONLY 8 /* don't let users reprogram clocks */ |
|
/* |
* Set up timer 0 to interrupt us every so many clocks. Assumes |
* interrupts are disabled. |
*/ |
static void |
program_clock(void) |
{ |
/* 33Mhz PCI Bus assumed */ |
#define CYCLES_PER_HZ (33 * 1000* 1000) / HZ |
*TRR0 = *TCR0 = CYCLES_PER_HZ; |
*TMR0 = CLOCKDIV1 | CLOCK_ENABLE | CLOCK_AUTO_RELOAD | CLOCK_SUPER_ONLY; |
|
#ifdef CONFIG_PROF_IRQ |
disable_irq(TMR1_VEC_HO); |
#endif |
} |
|
irq_node_t *new_irq_node(void) |
{ |
/* XXX: write me */ |
return NULL; |
} |
|
int request_irq(unsigned int irq, |
void (*handler)(int, void *, struct pt_regs *), |
unsigned long flags, const char *devname, void *dev_id) |
{ |
/* XXX: this is a stopgap; we only can handle one pci device */ |
if (pci_dev) |
return -1; |
|
pci_dev = dev_id; |
pci_name = devname; |
pci_isr = handler; |
return 0; |
} |
|
void free_irq(unsigned int irq, void *dev_id) |
{ |
pci_dev = 0; |
} |
|
/* |
* Do we need these probe functions on the i960? |
*/ |
unsigned long probe_irq_on (void) |
{ |
return 0; |
} |
|
int probe_irq_off (unsigned long irqs) |
{ |
return 0; |
} |
|
void disable_irq(unsigned int irq) |
{ |
if (irq && irq < SYS_IRQS) |
atmod((void*)IMSK, 1<<(irq-1), 0); |
} |
|
void enable_irq(unsigned int irq) |
{ |
if (irq && irq < SYS_IRQS) |
atmod((void*)IMSK, 1<<(irq-1), 1<<(irq-1)); |
} |
|
#ifdef CONFIG_PROF_IRQ |
#define SAMPLE_BITS 7 |
static inline void |
update_prof_timers(int vec, unsigned long ticks) |
{ |
struct irqstat* irq; |
vec = vec >> 4; |
irq = irqstat + vec; |
|
if (!irq->avg) { |
irq->max = ticks; |
irq->min = ticks; |
irq->avg = ticks; |
return; |
} |
|
if (ticks < irq->min) |
irq->min = ticks; |
if (ticks > irq->max) |
irq->max = ticks; |
irq->avg -= irq->avg >> SAMPLE_BITS; |
irq->avg += ticks >> SAMPLE_BITS; |
} |
#endif |
|
/* |
* Interrupt service routine. N.B. that XINT0, which is really a system call, |
* is never routed to cintr; it ends up in syscall instead. |
*/ |
extern void do_signal(void); |
asmlinkage void cintr(unsigned char vec, struct pt_regs* regs) |
{ |
extern void timer_interrupt(struct pt_regs* regs); |
static int ticks; |
#ifdef CONFIG_PROF_IRQ |
unsigned long clocks; |
*TCR1 = CYCLES_PER_HZ * HZ; |
*TMR1 = CLOCKDIV1 | CLOCK_ENABLE; |
#endif |
atomic_inc(&intr_count); |
|
kstat.interrupts[vec >> 4]++; |
switch(vec) { |
case NMI_VEC: |
nmi_intr(); |
break; |
|
case XINT1_VEC: |
case XINT0_VEC: |
case XINT2_VEC: |
case XINT3_VEC: |
case XINT4_VEC: |
case XINT5_VEC: |
case XINT6_VEC: |
case XINT7_VEC: |
xint(vec, regs); |
break; |
|
case TMR0_VEC: |
if ((++ticks) >= LED_THRESHOLD) { |
static char nm = 0; |
*LED = ~ (1 << (nm++ % 8)); |
ticks = 0; |
} |
timer_interrupt(regs); |
break; |
|
default: |
bad_intr(vec, regs); |
break; |
} |
atomic_dec(&intr_count); |
|
if (!intr_count) |
leave_kernel(regs); |
|
#ifdef CONFIG_PROF_IRQ |
clocks = CYCLES_PER_HZ*HZ - *TCR1; |
update_prof_timers(vec, clocks); |
#endif |
return; |
} |
|
/* |
* Common code to interrupt and syscall paths. When leaving the kernel, and not |
* returning to an interrupt context, do a whole bunch of processing. |
* |
* Note that if we're called from cintr, we're running at high ipl. |
* |
* Run the bottom half, check if scheduling is needed, and deliver signals to |
* the current process, just as in every other architecture. |
*/ |
void leave_kernel(struct pt_regs* regs) |
{ |
bh: |
if (bh_mask & bh_active) { |
atomic_inc(&intr_count); |
do_bottom_half(); |
atomic_dec(&intr_count); |
} |
sti(); |
|
if (user_mode(regs)) { |
if (need_resched) { |
schedule(); |
goto bh; |
} |
|
|
if (current->signal & ~current->blocked) { |
do_signal(); |
} |
} |
} |
|
static void nmi_intr(void) |
{ |
/* XXX: write me */ |
} |
|
static void bad_intr(unsigned char vec, struct pt_regs* regs) |
{ |
/* XXX: write me */ |
printk("whoah! bad intr: %x\n", vec); |
} |
|
static void xint(unsigned char vec, struct pt_regs* regs) |
{ |
/* |
* This basically shouldn't happen |
*/ |
#ifdef CONFIG_MON960_CONSOLE |
if (vec == SERIAL_VEC) { |
extern void do_16552_intr(void); |
do_16552_intr(); |
return; |
} |
#endif |
|
#ifdef CONFIG_PCI |
if (vec == PCI_VEC && pci_dev) { |
pci_isr(0, pci_dev, regs); |
return; |
} |
#endif |
printk("EEP: xint %x\n", vec); |
stack_trace(); |
} |
|
int get_irq_list(char *buf) |
{ |
int len = 0; |
int ii; |
|
for (ii=0; ii < 16; ii++) { |
if (irq_names[ii]) { |
#ifdef CONFIG_PROF_IRQ |
len += sprintf(buf+len, "%d\t%s\t(%08x, %08x, %08x)\n", |
kstat.interrupts[ii], |
(ii==2 && pci_dev) |
? pci_name |
: irq_names[ii], |
irqstat[ii].min, irqstat[ii].avg, |
irqstat[ii].max); |
#else |
len += sprintf(buf+len, "%d\t%s\n", |
kstat.interrupts[ii], |
(ii==2 && pci_dev) |
? pci_name |
: irq_names[ii]); |
#endif |
} |
} |
return len; |
} |
|
/kernel/ptrace.c
0,0 → 1,104
/* |
* linux/arch/i960/kernel/ptrace.c |
* |
* Copyright (C) 1998 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Based on: |
* |
* linux/arch/m68k/kernel/ptrace |
* |
* Copyright (C) 1994 by Hamish Macdonald |
* Taken from linux/kernel/ptrace.c and modified for M680x0. |
* linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds |
* |
* This file is subject to the terms and conditions of the GNU General |
* Public License. See the file COPYING in the main directory of |
* this archive for more details. |
*/ |
|
/* |
* XXX: unimplemented |
*/ |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/string.h> |
|
#include <linux/mm.h> |
#include <linux/errno.h> |
#include <linux/ptrace.h> |
#include <linux/user.h> |
|
#include <asm/segment.h> |
#include <asm/page.h> |
#include <asm/pgtable.h> |
#include <asm/system.h> |
|
/* change a pid into a task struct. */ |
static inline struct task_struct * get_task(int pid) |
{ |
int i; |
|
for (i = 1; i < NR_TASKS; i++) { |
if (task[i] != NULL && (task[i]->pid == pid)) |
return task[i]; |
} |
return NULL; |
} |
|
/* |
* Get contents of register REGNO in task TASK. |
*/ |
static inline long get_reg(struct task_struct *task, int regno) |
{ |
return -1; |
} |
|
/* |
* Write contents of register REGNO in task TASK. |
*/ |
static inline int put_reg(struct task_struct *task, int regno, |
unsigned long data) |
{ |
return -1; |
} |
|
inline |
static unsigned long get_long(struct task_struct * tsk, |
struct vm_area_struct * vma, unsigned long addr) |
{ |
return *(unsigned long*)addr; |
} |
|
inline |
static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, |
unsigned long data) |
{ |
*(unsigned long*)addr = data; |
} |
|
|
inline |
static int read_long(struct task_struct * tsk, unsigned long addr, |
unsigned long * result) |
{ |
*result = *(unsigned long *)addr; |
return 0; |
} |
|
inline |
static int write_long(struct task_struct * tsk, unsigned long addr, |
unsigned long data) |
{ |
*(unsigned long *)addr = data; |
return 0; |
} |
|
asmlinkage int sys_ptrace(long request, long pid, long addr, long data) |
{ |
return -1; |
} |
|
asmlinkage void syscall_trace(void) |
{ |
} |
/kernel/process.c
0,0 → 1,302
/* |
* linux/arch/i960/kernel/process.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Based on: |
* |
* linux/arch/m68k/kernel/process.c |
* |
* Copyright (C) 1995 Hamish Macdonald |
* |
*/ |
|
/* |
* This file handles the architecture-dependent parts of process handling.. |
*/ |
|
#include <linux/errno.h> |
#include <linux/sched.h> |
#include <linux/kernel.h> |
#include <linux/mm.h> |
#include <linux/stddef.h> |
#include <linux/unistd.h> |
#include <linux/ptrace.h> |
#include <linux/malloc.h> |
#include <linux/user.h> |
#include <linux/a.out.h> |
|
#include <asm/segment.h> |
#include <asm/system.h> |
#include <asm/traps.h> |
#include <asm/machdep.h> |
#include <asm/setup.h> |
#include <asm/dprintk.h> |
|
extern void stack_trace(void); |
extern void stack_trace_from(unsigned long sp); |
|
asmlinkage void ret_from_exception(void); |
|
/* |
* The idle loop on an i960 |
*/ |
asmlinkage int sys_idle(void) |
{ |
if (current->pid != 0) |
return -EPERM; |
|
sti(); |
/* endless idle loop with no priority at all */ |
current->counter = -100; |
for (;;) { |
__asm__ ("halt 2"); |
schedule(); |
} |
} |
|
static unsigned long |
stack_align(unsigned long sp) |
{ |
#define STACK_ALIGN 16 /* must be power of 2 */ |
if ((unsigned long) sp & (STACK_ALIGN-1)) { |
(unsigned long) sp += STACK_ALIGN; |
(unsigned long) sp &= ~(STACK_ALIGN-1); |
} |
#undef STACK_ALIGN |
return sp; |
} |
|
#ifdef CONFIG_MON960 |
#include <asm/mon960.h> |
#endif |
|
void hard_reset_now(void) |
{ |
#ifdef CONFIG_MON960 |
cli(); |
mon960_exit(0); |
#else |
printk("ermm, I don't know how to reset. Sorry.\n"); |
#endif |
} |
|
void show_regs(struct pt_regs * regs) |
{ |
int ii; |
printk("\n"); |
printk("PC:\t%08lx\tAC:\t%08lx\n", |
regs->pc, regs->ac); |
printk("pfp:\t%08lx\tg0:\t%08lx\n", |
regs->lregs[0], regs->gregs[0]); |
printk("sp:\t%08lx\tg1:\t%08lx\n", |
regs->lregs[1], regs->gregs[1]); |
printk("rip:\t%08lx\tg2:\t%08lx\n", |
regs->lregs[2], regs->gregs[2]); |
for (ii=3; ii < 16; ii++) |
printk("r%d:\t%08lx\tg%d\t%08lx\n", ii, |
regs->lregs[ii], ii, regs->gregs[ii]); |
} |
|
void hex_dump(unsigned long start, int len) |
{ |
char* c = (char*) start; |
int ii; |
|
#define CHARS_IN_LINE 16 |
for (ii=0; ii < len; ii++) { |
if (! (ii & (CHARS_IN_LINE-1))) { |
printk("\n%8x: ", start + ii); |
} |
printk("%2x ", c[ii]); |
} |
printk("\n"); |
} |
|
/* |
* Free current thread data structures etc.. |
*/ |
void exit_thread(void) |
{ |
} |
|
void flush_thread(void) |
{ |
} |
|
void release_thread(struct task_struct *dead_task) |
{ |
} |
|
void switch_to(struct task_struct* prev, struct task_struct* next) |
{ |
if (next == prev) |
return; |
|
#if 0 |
dprintk("*** switch_to: new pfp: 0x%8x\n", next->tss.pfp); |
dprintk("*** switch_to: old stack:\n"); |
stack_trace(); |
dprintk("*** switch_to: new stack:\n"); |
stack_trace_from(next->tss.pfp); |
#endif |
current_set[smp_processor_id()] = next; |
__asm__ __volatile__ |
("st pfp, (%1)\n\t" /* save current pfp */ |
"flushreg\n\t" |
"mov %2, pfp\n\t" |
"flushreg\n\t" |
: "=m" (prev->tss.pfp) |
:"r" (&prev->tss.pfp), "r" (next->tss.pfp)); |
} |
|
/* |
* Called from the vfork path. We need to copy enough of the caller's kernel and |
* user stacks to get the child out of the kernel, and back to the level where |
* vfork was called. This is, I admit, somewhat heinous, and probably a longer |
* code path than one would like. |
*/ |
void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, |
struct task_struct * p, struct pt_regs * regs) |
{ |
struct pt_regs *childregs; |
extern void syscall_return(void); |
unsigned long new_ustack; |
|
if (!regs) |
return; /* kernel_thread hack */ |
|
asm("flushreg"); |
/* |
* Setting up child's ustack: allocate it just below caller's ustack, |
* copy in caller's ustack, and relocate sp's. When returning to the |
* child, we skip the syscall_frame and go straight back to the caller |
* frame. |
* |
* low addresses |
* _______________ |
* | caller_frame | |
* |_______________| |
* | syscall_frame | |
* |_______________| |
* | child_caller_frame |
* |_______________| |
* ... |
* _______________ |
* | regs | (top o' kernel stack) |
* ... |
* |
* high addresses |
*/ |
{ |
struct i960_frame *syscall_frame, *caller_frame; |
struct i960_frame *child_caller_frame; |
unsigned long frame_len, offset; |
|
syscall_frame = (struct i960_frame*) |
(regs->lregs[PT_PFP] & ~0xf); |
caller_frame = (struct i960_frame*)syscall_frame->pfp; |
dprintk("new_ustack: 0x%8x\n", syscall_frame->sp); |
new_ustack = stack_align(syscall_frame->sp); |
dprintk("new_ustack: 0x%8x\n", new_ustack); |
child_caller_frame = (struct i960_frame*) new_ustack; |
frame_len = caller_frame->sp - (unsigned long)(caller_frame); |
dprintk("frame len: 0x%8x\n", frame_len); |
memcpy((void*)new_ustack, caller_frame, frame_len); |
|
offset = new_ustack - (unsigned long)caller_frame; |
child_caller_frame->sp += offset; |
/* |
* XXX: you should never return from the function that called |
* vfork; right now, you'll just walk off with a bad stack, |
* but eventually we might want to catch this case and force |
* an exit. |
*/ |
child_caller_frame->pfp = 0; |
} |
|
/* |
* We build a near-copy of the top frame of the caller's syscall stack |
* in the child's kstack; the child's sp points to the child stack. Its |
* pfp heads to the frame in the child's ustack that we created above. |
*/ |
|
childregs = (struct pt_regs*)p->kernel_stack_page; |
*childregs = *regs; /* bitwise copy */ |
|
childregs->lregs[PT_PFP] = new_ustack | 2; /* return to user */ |
childregs->lregs[PT_SP] = (unsigned long)(childregs + 1); |
childregs->gregs[0] = 0; /* Child gets a retval of zero */ |
childregs->gregs[15] = (unsigned long) &childregs->lregs[0]; |
|
/* we reload the pfp from the thread struct in switch_to */ |
p->tss.pfp = (unsigned long)&childregs->lregs; |
#ifdef DEBUG |
dprintk("child stack:\n"); |
stack_trace_from(p->tss.pfp); |
#endif |
} |
|
/* Fill in the fpu structure for a core dump. */ |
|
int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) |
{ |
return 0; |
} |
|
/* |
* fill in the user structure for a core dump.. |
*/ |
void dump_thread(struct pt_regs * regs, struct user * dump) |
{ |
/* XXX: write this */ |
} |
|
/* |
* start a thread |
*/ |
void start_thread(struct pt_regs * regs, unsigned long ip, unsigned long sp) |
{ |
struct i960_frame* frame; |
|
/* align the stack */ |
sp = stack_align(sp); |
|
/* |
* build a little stack frame at sp; start running |
*/ |
frame = (struct i960_frame*) sp; |
frame->sp = ((unsigned long)sp) + 16*4; |
frame->rip = ip; |
frame->pfp = 0; |
#ifdef DEBUG |
dprintk("before:\n"); |
stack_trace(); |
#endif |
regs->lregs[PT_PFP] = (sp | 0x7); /* returning from interrupt */ |
regs->pc = (1<<13); /* bit 13: interrupted mode */ |
regs->ac = (1<<15) | (1<<12); /* bits 15 and 12: precise faults, no overflow interrupts */ |
|
/* |
* g12 contains the "data" bias. the code expects text and data to |
* be allocated contiguously, and g12 points to code. Since data/bss |
* might be allocated separately from text, we point g12 at |
* data_start - text_len |
*/ |
regs->gregs[12] = current->mm->start_data - |
(current->mm->end_code - current->mm->start_code); |
regs->gregs[13] = current->mm->env_start - 12; |
regs->gregs[14] = 0; |
dprintk("set first arg: 0x%8x\n", regs->gregs[0]); |
/* make memory coherent; the stack cache flush might be gratuitous */ |
asm("flushreg |
dcctl 3, g0, g0 |
icctl 2, g0, g0"); |
#ifdef DEBUG |
dprintk("set data seg to: 0x%8x\n", regs->gregs[12]); |
dprintk("set start to %p\n", ip); |
stack_trace(); |
#endif |
} |
|
/kernel/entry.S
0,0 → 1,358
/* |
* |
* linux/arch/m68knommu/kernel/entry.S |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu>, |
* Oregon Graduate Institute |
* |
*/ |
|
/* |
* syscall, interrupt, and fault entry points |
*/ |
|
#include <asm/i960.h> |
#include <asm/unistd.h> |
#define ALL_ONES 0xffffffff |
|
#include <linux/sys.h> |
#include <linux/config.h> |
#include <linux/linkage.h> |
#include <asm/setup.h> |
#include <asm/segment.h> |
#ifdef CONFIG_I960VH |
#include <asm/i960jx.h> |
#endif |
|
|
.globl SYMBOL_NAME(atmod) |
SYMBOL_NAME_LABEL(atmod) |
atmod g0, g1, g2 |
mov g2, g0 |
ret |
|
/* |
* The birthplace of kernel threads. Once here, we find the function to call |
* in register r3, and its argument in r4. See kernel_thread in asm/unistd.h |
* for why this exists. |
*/ |
.globl SYMBOL_NAME(kthread_trampoline) |
SYMBOL_NAME_LABEL(kthread_trampoline) |
mov r3, g0 |
mov r4, g1 |
call SYMBOL_NAME(kthread_start) |
ldconst 0, g0 |
b SYMBOL_NAME(do_exit) |
/* no ret */ |
|
/* |
* signal handlers start here in signal_head. |
*/ |
.globl SYMBOL_NAME(signal_head) |
SYMBOL_NAME_LABEL(signal_head) |
mov g0, r5 |
mov r4, g0 |
callx (r3) |
mov r5, g0 |
ret |
|
#define USER_AC 0x3b001000 |
#define USER_PC 0x00002000 /* bit 13 set: interrupted mode */ |
#define KSP_OFFSET 0x58 |
|
#if 0 |
#define CKPT(x,y) \ |
ldconst x, g0; \ |
mov y, g1; \ |
call SYMBOL_NAME(ckpt); |
#endif |
|
/* XXX: todo: emulate an interrupt: put PC and AC on stack */ |
/* |
* This is branched to by intr and syscall; it switches to the kernel stack, |
* and returns to the ip in r6. The choice of registers lets us economize |
* on store operations. |
* |
* Be sure to branch here, rather than call; we can't use a single frame of |
* the shared intr/syscall stacks. |
* |
* Observe weird register conventions (because we can't alter g* regs): |
* ip after switch: r6 |
* r3 in new stack: r7 (for intr/fault) |
* PC to be seen in new stack: r8 |
*/ |
.align 4 |
switch_to_kstack: |
ld SYMBOL_NAME(current_set), r3 |
ld KSP_OFFSET(r3), r3 |
ldconst 64, r5 |
addo r3, r5, r3 # get some space on stack (for PC/AC) |
/* |
* r3 now points to the address of the new stack frame. We build an image of |
* the new stack frame in regs r4-r7. The intr needs to |
* remember its intr vector, so we also put r7 on the stack, in the r3 |
* position. |
*/ |
|
mov pfp, r4 # newframe->pfp = current pfp |
addo r5, r3, r5 # newframe->sp = newframe + 64 |
# newframe->rip = rip (passed in r6) |
# newframe->r3 = r7 |
stq r4, (r3) |
|
/* Store AC, PC as if in interrupt context */ |
modac 0, 0, r9 |
stl r8, -16(r3) # current ac, pc passed in r8 |
flushreg |
mov r3, pfp |
flushreg |
ret # returns to ip from r6 |
|
/* |
* System calls all end up here. |
*/ |
.globl SYMBOL_NAME(syscall) |
.align 4 |
SYMBOL_NAME_LABEL(syscall) |
/* |
* first, examine pfp; if its 1st and 2nd bits are 1 and 0 respectively, |
* we're coming from user mode, so we need to switch stacks. |
*/ |
|
bbs 2, pfp, 1f # if bit 2 is set, we're cool |
bbc 1, pfp, 1f # same if bit 1 is clear |
/* uh-oh, we're coming from user mode: switch stacks */ |
lda 1f, r6 |
ldconst USER_PC, r8 |
b switch_to_kstack |
|
1: |
SAVE_ALL(r3) |
subo 16, fp, g0 |
call SYMBOL_NAME(csyscall) |
RESTORE_ALL(r3) |
ret |
|
/* |
* This is the main interrupt handler; it is also the entry point for |
* system calls. |
*/ |
.globl SYMBOL_NAME(intr) |
.align 4 |
SYMBOL_NAME_LABEL(intr) |
ld -16(fp), r3 |
ldob -8(fp), r7 |
bbs 1, r3, 1f # if we're supervisor, forget it |
/* uh-oh, switch stacks */ |
lda 2f, r6 |
mov r3, r8 |
b switch_to_kstack |
|
1: |
mov r7, r3 |
2: |
/* |
* by now we're on a valid stack, and the interrupt vector number is in |
* r3. |
*/ |
SAVE_ALL(r4) |
mov r3, g0 # 1st arg is intr vector |
flushreg # get regs on stack |
subo 16, fp, g1 # 2nd arg is pointer to pt_regs |
call SYMBOL_NAME(cintr) |
RESTORE_ALL(r3) |
ret # back to user-level |
|
/* |
* Again, if we're coming from user mode, switch to kstack. We get this info |
* from the fault record, 16 bytes below the current fp. We play games similar |
* to intr to hold onto the fault record... |
*/ |
.globl SYMBOL_NAME(fault) |
SYMBOL_NAME_LABEL(fault) |
subo 16, fp, r7 |
ld (r7), r3 # r3 gets pc of faulting instr |
bbs 1, r3, 1f # if it was a supervisor fault, don't switch |
|
lda 2f, r6 |
ldconst USER_PC, r8 |
b switch_to_kstack |
1: |
mov r7, r3 |
2: |
SAVE_ALL(r4) |
mov r3, g0 |
subo 16, fp, g1 |
call SYMBOL_NAME(cfault) |
RESTORE_ALL(r4) |
ret |
|
/* |
* The table of system calls. |
*/ |
.globl SYMBOL_NAME(syscall_tab) |
SYMBOL_NAME_LABEL(syscall_tab) |
.long SYMBOL_NAME(sys_setup) /* 0 */ |
.long SYMBOL_NAME(sys_exit) |
.long SYMBOL_NAME(sys_fork) |
.long SYMBOL_NAME(sys_read) |
.long SYMBOL_NAME(sys_write) |
.long SYMBOL_NAME(sys_open) /* 5 */ |
.long SYMBOL_NAME(sys_close) |
.long SYMBOL_NAME(sys_waitpid) |
.long SYMBOL_NAME(sys_creat) |
.long SYMBOL_NAME(sys_link) |
.long SYMBOL_NAME(sys_unlink) /* 10 */ |
.long SYMBOL_NAME(sys_execve) |
.long SYMBOL_NAME(sys_chdir) |
.long SYMBOL_NAME(sys_time) |
.long SYMBOL_NAME(sys_mknod) |
.long SYMBOL_NAME(sys_chmod) /* 15 */ |
.long SYMBOL_NAME(sys_chown) |
.long SYMBOL_NAME(sys_break) |
.long SYMBOL_NAME(sys_stat) |
.long SYMBOL_NAME(sys_lseek) |
.long SYMBOL_NAME(sys_getpid) /* 20 */ |
.long SYMBOL_NAME(sys_mount) |
.long SYMBOL_NAME(sys_umount) |
.long SYMBOL_NAME(sys_setuid) |
.long SYMBOL_NAME(sys_getuid) |
.long SYMBOL_NAME(sys_stime) /* 25 */ |
.long SYMBOL_NAME(sys_ptrace) |
.long SYMBOL_NAME(sys_alarm) |
.long SYMBOL_NAME(sys_fstat) |
.long SYMBOL_NAME(sys_pause) |
.long SYMBOL_NAME(sys_utime) /* 30 */ |
.long SYMBOL_NAME(sys_stty) |
.long SYMBOL_NAME(sys_gtty) |
.long SYMBOL_NAME(sys_access) |
.long SYMBOL_NAME(sys_nice) |
.long SYMBOL_NAME(sys_ftime) /* 35 */ |
.long SYMBOL_NAME(sys_sync) |
.long SYMBOL_NAME(sys_kill) |
.long SYMBOL_NAME(sys_rename) |
.long SYMBOL_NAME(sys_mkdir) |
.long SYMBOL_NAME(sys_rmdir) /* 40 */ |
.long SYMBOL_NAME(sys_dup) |
.long SYMBOL_NAME(do_pipe) |
.long SYMBOL_NAME(sys_times) |
.long SYMBOL_NAME(sys_prof) |
.long SYMBOL_NAME(sys_brk) /* 45 */ |
.long SYMBOL_NAME(sys_setgid) |
.long SYMBOL_NAME(sys_getgid) |
.long SYMBOL_NAME(sys_signal) |
.long SYMBOL_NAME(sys_geteuid) |
.long SYMBOL_NAME(sys_getegid) /* 50 */ |
.long SYMBOL_NAME(sys_acct) |
.long SYMBOL_NAME(sys_phys) |
.long SYMBOL_NAME(sys_lock) |
.long SYMBOL_NAME(sys_ioctl) |
.long SYMBOL_NAME(sys_fcntl) /* 55 */ |
.long SYMBOL_NAME(sys_mpx) |
.long SYMBOL_NAME(sys_setpgid) |
.long SYMBOL_NAME(sys_ulimit) |
.long SYMBOL_NAME(sys_olduname) |
.long SYMBOL_NAME(sys_umask) /* 60 */ |
.long SYMBOL_NAME(sys_chroot) |
.long SYMBOL_NAME(sys_ustat) |
.long SYMBOL_NAME(sys_dup2) |
.long SYMBOL_NAME(sys_getppid) |
.long SYMBOL_NAME(sys_getpgrp) /* 65 */ |
.long SYMBOL_NAME(sys_setsid) |
.long SYMBOL_NAME(sys_sigaction) |
.long SYMBOL_NAME(sys_sgetmask) |
.long SYMBOL_NAME(sys_ssetmask) |
.long SYMBOL_NAME(sys_setreuid) /* 70 */ |
.long SYMBOL_NAME(sys_setregid) |
.long SYMBOL_NAME(do_sigsuspend) |
.long SYMBOL_NAME(sys_sigpending) |
.long SYMBOL_NAME(sys_sethostname) |
.long SYMBOL_NAME(sys_setrlimit) /* 75 */ |
.long SYMBOL_NAME(sys_getrlimit) |
.long SYMBOL_NAME(sys_getrusage) |
.long SYMBOL_NAME(sys_gettimeofday) |
.long SYMBOL_NAME(sys_settimeofday) |
.long SYMBOL_NAME(sys_getgroups) /* 80 */ |
.long SYMBOL_NAME(sys_setgroups) |
.long SYMBOL_NAME(sys_select) |
.long SYMBOL_NAME(sys_symlink) |
.long SYMBOL_NAME(sys_lstat) |
.long SYMBOL_NAME(sys_readlink) /* 85 */ |
.long SYMBOL_NAME(sys_uselib) |
.long SYMBOL_NAME(sys_swapon) |
.long SYMBOL_NAME(sys_reboot) |
.long SYMBOL_NAME(sys_ni_syscall) |
.long SYMBOL_NAME(sys_ni_syscall) /* 90 */ |
.long SYMBOL_NAME(sys_munmap) |
.long SYMBOL_NAME(sys_truncate) |
.long SYMBOL_NAME(sys_ftruncate) |
.long SYMBOL_NAME(sys_fchmod) |
.long SYMBOL_NAME(sys_fchown) /* 95 */ |
.long SYMBOL_NAME(sys_getpriority) |
.long SYMBOL_NAME(sys_setpriority) |
.long SYMBOL_NAME(sys_profil) |
.long SYMBOL_NAME(sys_statfs) |
.long SYMBOL_NAME(sys_fstatfs) /* 100 */ |
.long SYMBOL_NAME(sys_ioperm) |
.long SYMBOL_NAME(sys_socketcall) |
.long SYMBOL_NAME(sys_syslog) |
.long SYMBOL_NAME(sys_setitimer) |
.long SYMBOL_NAME(sys_getitimer) /* 105 */ |
.long SYMBOL_NAME(sys_newstat) |
.long SYMBOL_NAME(sys_newlstat) |
.long SYMBOL_NAME(sys_newfstat) |
.long SYMBOL_NAME(sys_uname) |
.long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */ |
.long SYMBOL_NAME(sys_vhangup) |
.long SYMBOL_NAME(sys_idle) |
.long SYMBOL_NAME(sys_ni_syscall) /* vm86 for i386 */ |
.long SYMBOL_NAME(sys_wait4) |
.long SYMBOL_NAME(sys_swapoff) /* 115 */ |
.long SYMBOL_NAME(sys_sysinfo) |
.long SYMBOL_NAME(sys_ipc) |
.long SYMBOL_NAME(sys_fsync) |
.long SYMBOL_NAME(do_sigreturn) |
.long SYMBOL_NAME(sys_clone) /* 120 */ |
.long SYMBOL_NAME(sys_setdomainname) |
.long SYMBOL_NAME(sys_newuname) |
.long SYMBOL_NAME(sys_cacheflush) /* modify_ldt for i386 */ |
.long SYMBOL_NAME(sys_adjtimex) |
.long SYMBOL_NAME(sys_mprotect) /* 125 */ |
.long SYMBOL_NAME(sys_sigprocmask) |
.long SYMBOL_NAME(sys_create_module) |
.long SYMBOL_NAME(sys_init_module) |
.long SYMBOL_NAME(sys_delete_module) |
.long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */ |
.long SYMBOL_NAME(sys_quotactl) |
.long SYMBOL_NAME(sys_getpgid) |
.long SYMBOL_NAME(sys_fchdir) |
.long SYMBOL_NAME(sys_bdflush) |
.long SYMBOL_NAME(sys_sysfs) /* 135 */ |
.long SYMBOL_NAME(sys_personality) |
.long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */ |
.long SYMBOL_NAME(sys_setfsuid) |
.long SYMBOL_NAME(sys_setfsgid) |
.long SYMBOL_NAME(sys_llseek) /* 140 */ |
.long SYMBOL_NAME(sys_getdents) |
.long SYMBOL_NAME(sys_select) |
.long SYMBOL_NAME(sys_flock) |
.long SYMBOL_NAME(sys_msync) |
.long SYMBOL_NAME(sys_readv) /* 145 */ |
.long SYMBOL_NAME(sys_writev) |
.long SYMBOL_NAME(sys_getsid) |
.long SYMBOL_NAME(sys_fdatasync) |
.long SYMBOL_NAME(sys_sysctl) |
.long SYMBOL_NAME(sys_mlock) /* 150 */ |
.long SYMBOL_NAME(sys_munlock) |
.long SYMBOL_NAME(sys_mlockall) |
.long SYMBOL_NAME(sys_munlockall) |
.long SYMBOL_NAME(sys_sched_setparam) |
.long SYMBOL_NAME(sys_sched_getparam) /* 155 */ |
.long SYMBOL_NAME(sys_sched_setscheduler) |
.long SYMBOL_NAME(sys_sched_getscheduler) |
.long SYMBOL_NAME(sys_sched_yield) |
.long SYMBOL_NAME(sys_sched_get_priority_max) |
.long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */ |
.long SYMBOL_NAME(sys_sched_rr_get_interval) |
.long SYMBOL_NAME(sys_nanosleep) |
.long SYMBOL_NAME(sys_mremap) |
/kernel/semaphore.c
0,0 → 1,83
/* |
* FILE: semaphore.c |
* AUTHOR: kma@cse.ogi.edu |
* DESCR: interrupt-safe i960 semaphore implementation; isn't ready for SMP |
*/ |
|
#ident "$Id: semaphore.c,v 1.1.1.1 2001-09-10 07:43:56 simons Exp $" |
#include <asm/semaphore.h> |
#include <linux/sched.h> |
|
extern int __down_common(struct semaphore* sem, int intrflag) |
{ |
long flags; |
int retval=0; |
|
save_flags(flags); |
cli(); |
|
if (--sem->count < 0) { |
if (intrflag) { |
interruptible_sleep_on(&sem->wait); |
if (current->signal & ~current->blocked) { |
retval = -1; |
} |
} |
else |
sleep_on(&sem->wait); |
} |
restore_flags(flags); |
return retval; |
} |
|
void down(struct semaphore * sem) |
{ |
__down_common(sem, 0); |
} |
|
|
/* |
* This version waits in interruptible state so that the waiting |
* process can be killed. The down_failed_interruptible routine |
* returns negative for signalled and zero for semaphore acquired. |
*/ |
extern int down_interruptible(struct semaphore * sem) |
{ |
return __down_common(sem, 1); |
} |
|
|
/* |
* Primitives to spin on a lock. Needed only for SMP. |
*/ |
extern void get_buzz_lock(int *lock_ptr) |
{ |
#ifdef __SMP__ |
while (xchg(lock_ptr,1) != 0) ; |
#endif |
} |
|
extern void give_buzz_lock(int *lock_ptr) |
{ |
#ifdef __SMP__ |
*lock_ptr = 0 ; |
#endif |
} |
|
|
/* |
* We wake people up only if the semaphore was negative (== somebody was |
* waiting on it). |
*/ |
extern void up(struct semaphore * sem) |
{ |
long flags; |
save_flags(flags); |
cli(); |
|
if (sem->count++ < 0) |
wake_up(&sem->wait); |
|
restore_flags(flags); |
} |
|
/kernel/traps.c
0,0 → 1,251
/* |
* linux/arch/i960/kernel/traps.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Based on: |
* |
* linux/arch/m68k/kernel/traps.c |
* |
* Copyright (C) 1993, 1994 by Hamish Macdonald |
* |
* This file is subject to the terms and conditions of the GNU General Public |
* License. See the file COPYING in the main directory of this archive |
* for more details. |
*/ |
|
/* |
* Sets up all exception vectors |
*/ |
|
#include <linux/config.h> |
#include <linux/sched.h> |
#include <linux/signal.h> |
#include <linux/kernel.h> |
#include <linux/mm.h> |
#include <linux/types.h> |
#include <linux/a.out.h> |
#include <linux/user.h> |
#include <linux/string.h> |
#include <linux/linkage.h> |
|
#include <asm/setup.h> |
#include <asm/system.h> |
#include <asm/segment.h> |
#include <asm/traps.h> |
#include <asm/pgtable.h> |
#include <asm/machdep.h> |
#include <asm/i960jx.h> |
#include <asm/mon960.h> |
|
/* set fault handlers in fault table, syscall table */ |
void trap_init (void) |
{ |
int ii; |
unsigned long** prcb = (unsigned long**) get_prcbptr(); |
unsigned long* syscall_tab = prcb[5]; |
unsigned long* fault_tab = prcb[0]; |
extern void fault(void); |
|
/* faults use syscall table entry 1 (0 is for syscalls) */ |
syscall_tab[13] = ((unsigned long) fault) | 0x2; |
for (ii=0; ii < 20; ii += 2) { |
/* leave trace trap to mon960; don't mess with reserved |
* fields. */ |
if (ii == 2 || ii == 8 || ii == 12 || ii == 16 || ii == 18) |
continue; |
|
fault_tab[ii] = (1 << 2) | 2; /* use syscall #1 */ |
fault_tab[ii+1] = 0x27f; /* magic number */ |
} |
} |
|
void cfault(unsigned long* fault_rec, struct pt_regs* regs) |
{ |
int ii; |
unsigned long wd = fault_rec[2]; |
unsigned char type = (wd >> 16); |
unsigned char subtype = (unsigned char)(wd); |
char* nm = "<no fault>"; |
int sig = 0; |
|
switch(type) { |
case 3: |
/* arithmetic fault */ |
nm = "arithmetic error"; |
sig = SIGFPE; |
break; |
case 5: |
/* constraint error? */ |
nm = "constraint error"; |
break; |
case 2: |
switch(subtype) { |
case 1: |
nm = "illegal instruction"; |
sig = SIGILL; |
break; |
case 2: |
nm = "accessed bad address"; |
sig = SIGSEGV; |
break; |
case 3: |
nm = "unaligned"; |
sig = SIGBUS; |
break; |
case 4: |
nm = "invalid operand"; |
sig = SIGILL; |
break; |
} |
break; |
case 7: |
nm = "protection fault"; |
sig = SIGILL; |
break; |
case 1: |
nm = "trace fault"; |
/* bugger: we need to do better tracing */ |
break; |
|
case 0xa: |
nm = "type.mismatch"; |
sig = SIGILL; |
break; |
} |
|
if (user_mode(regs)) { |
extern void leave_kernel(struct pt_regs* regs); |
if (sig) { |
current-> signal |= (1 << (sig -1)); |
} |
leave_kernel(regs); |
return; |
} |
|
cli(); |
/* Amuse the user. */ |
printk("\n" |
" \\|/ ____ \\|/\n" |
" \"@'/ ,. \\`@\"\n" |
" /_| \\__/ |_\\\n" |
" \\__U_/\n"); |
|
printk("kernel fault: %s\n", nm); |
for (ii=0; ii < 4; ii++) |
printk("fault_rec: 0x%8x\n", fault_rec[ii]); |
|
show_regs(regs); |
stack_trace(); |
|
#ifdef CONFIG_MON960 |
system_break(); |
#else |
for (;;) ; |
#endif |
} |
|
void die_if_kernel(char* msg, struct pt_regs* regs, long err) |
{ |
if (user_mode(regs)) |
return; |
|
/* Amuse the user. */ |
printk( |
" \\|/ ____ \\|/\n" |
" \"@'/ ,. \\`@\"\n" |
" /_| \\__/ |_\\\n" |
" \\__U_/\n"); |
|
printk("%s: %04lx\n", msg, err & 0xffff); |
show_regs(regs); |
stack_trace(); |
|
cli(); |
for (;;) ; |
} |
|
/* |
* Print a quick n' dirty stack trace |
*/ |
struct frameo { |
struct frameo* pfp; |
unsigned long sp; |
void* rip; |
}; |
|
void stack_trace(void) |
{ |
unsigned long fp; |
|
__asm__ __volatile__ ("flushreg; mov pfp, %0" : "=r"(fp)); |
stack_trace_from(fp); |
} |
|
void stack_trace_from(unsigned long ulfp) |
{ |
int ii; |
long flags; |
struct frameo* fp = (struct frameo*) ulfp; |
|
save_flags(flags); |
cli(); |
printk("trace: fp == %p\n", fp); |
for (ii=1; fp && (ii < 50); ii++, fp=fp->pfp) { |
unsigned long type = ((unsigned long)fp) & 0xf; |
fp = ((unsigned long)fp) & ~0xf; |
|
switch(type) { |
case 1: |
printk("<f>"); |
break; |
|
case 2: |
case 3: |
printk("<s>"); |
break; |
case 7: |
printk("<i>"); |
} |
printk("\t%8x", fp->rip); |
if (! (ii & 0x3)) |
printk("\n"); |
} |
|
if (!fp) { |
printk("<bottom of stack>\n"); |
} |
|
printk("\n"); |
restore_flags(flags); |
} |
|
void ckpt(int num, unsigned long val) |
{ |
|
printk("--------reached ckpt: %d\tval:0x%8x\n", num, val); |
#if 0 |
struct pt_regs* regs; |
asm("flushreg; subo 16, fp, %0" : "=r"(regs)); |
|
show_regs(regs); |
#endif |
printk("current stack trace:\n"); |
stack_trace(); |
printk("new stack strace:\n"); |
stack_trace_from(val); |
printk("offset of ksp: 0x%8x\n", |
&(((struct task_struct*)0)->kernel_stack_page)); |
printk("current ksp: 0x%8x\n", current->kernel_stack_page); |
} |
|
void system_break(void) |
{ |
long flags; |
|
save_flags(flags); |
cli(); |
mon_entry(); |
restore_flags(flags); |
} |
/kernel/Makefile
0,0 → 1,25
# |
# Makefile for the linux kernel. |
# |
# Note! Dependencies are done automagically by 'make dep', which also |
# removes any old dependencies. DON'T put your own dependencies here |
# unless it's something special (ie not a .c file). |
# |
# Note 2! The CFLAGS definitions are now in the main makefile... |
|
.S.o: |
$(CC) -D__ASSEMBLY__ -traditional $(EXTRA_CFLAGS) -c $< -o $*.o |
|
all: head.o entry.o kernel.o |
O_TARGET := kernel.o |
O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \ |
setup.o bios32.o time.o ksyms.o semaphore.o syscall.o |
|
ifdef CONFIG_MON960 |
O_OBJS += mon960_calls.o |
ifdef CONFIG_MON960_CONSOLE |
O_OBJS += mon960_console.o |
endif |
endif |
|
include $(TOPDIR)/Rules.make |
/boot/Makefile
0,0 → 1,5
clean: |
rm -f *.[oa] |
|
dep depend: |
echo Nope |
/defconfig
0,0 → 1,182
# |
# Automatically generated by make menuconfig: don't edit |
# |
CONFIG_UCLINUX=y |
|
# |
# Code maturity level options |
# |
CONFIG_EXPERIMENTAL=y |
|
# |
# Loadable module support |
# |
# CONFIG_MODULES is not set |
|
# |
# Platform dependant setup |
# |
# CONFIG_I960JX is not set |
# CONFIG_I960KX is not set |
# CONFIG_I960MC is not set |
# CONFIG_I960CX is not set |
# CONFIG_I960JX is not set |
# CONFIG_I960HX is not set |
CONFIG_I960VH=y |
CONFIG_CYVH=y |
CONFIG_CYVH_4MB=y |
# CONFIG_CYVH_8MB is not set |
# CONFIG_CYVH_16MB is not set |
# CONFIG_CYVH_32MB is not set |
CONFIG_MON960=y |
|
# |
# General setup |
# |
# CONFIG_MATH_EMULATION is not set |
CONFIG_NET=y |
# CONFIG_MAX_16M is not set |
CONFIG_PCI=y |
# CONFIG_PCI_OPTIMIZE is not set |
CONFIG_SYSVIPC=y |
CONFIG_REDUCED_MEMORY=y |
CONFIG_BINFMT_FLAT=y |
|
# |
# Floppy, IDE, and other block devices |
# |
# CONFIG_BLK_DEV_FD is not set |
# CONFIG_BLK_DEV_IDE is not set |
# CONFIG_BLK_DEV_HD_ONLY is not set |
# CONFIG_BLK_DEV_LOOP is not set |
# CONFIG_BLK_DEV_MD is not set |
CONFIG_BLK_DEV_RAM=y |
CONFIG_RD_RELEASE_BLOCKS=y |
# CONFIG_BLK_DEV_INITRD is not set |
CONFIG_BLK_DEV_KROM=y |
CONFIG_BLK_DEV_BLKMEM=y |
# CONFIG_BLK_DEV_XD is not set |
# CONFIG_PARIDE is not set |
# CONFIG_BLK_DEV_HD is not set |
|
# |
# Networking options |
# |
# CONFIG_FIREWALL is not set |
# CONFIG_NET_ALIAS is not set |
CONFIG_INET=y |
# CONFIG_IP_FORWARD is not set |
# CONFIG_IP_MULTICAST is not set |
# CONFIG_SYN_COOKIES is not set |
# CONFIG_IP_ACCT is not set |
# CONFIG_IP_ROUTER is not set |
# CONFIG_NET_IPIP is not set |
# CONFIG_INET_PCTCP is not set |
# CONFIG_INET_RARP is not set |
# CONFIG_NO_PATH_MTU_DISCOVERY is not set |
CONFIG_IP_NOSR=y |
# CONFIG_SKB_LARGE is not set |
# CONFIG_IPX is not set |
# CONFIG_ATALK is not set |
# CONFIG_AX25 is not set |
# CONFIG_BRIDGE is not set |
# CONFIG_NETLINK is not set |
|
# |
# SCSI support |
# |
# CONFIG_SCSI is not set |
|
# |
# Network device support |
# |
CONFIG_NETDEVICES=y |
CONFIG_DUMMY=y |
# CONFIG_EQUALIZER is not set |
# CONFIG_DLCI is not set |
# CONFIG_PLIP is not set |
CONFIG_PPP=y |
CONFIG_SLIP=y |
CONFIG_SLIP_COMPRESSED=y |
# CONFIG_SLIP_SMART is not set |
# CONFIG_SLIP_MODE_SLIP6 is not set |
# CONFIG_NET_RADIO is not set |
CONFIG_NET_ETHERNET=y |
# CONFIG_NET_VENDOR_3COM is not set |
# CONFIG_NET_VENDOR_SMC is not set |
CONFIG_NET_PCI=y |
# CONFIG_PCNET32 is not set |
CONFIG_EEXPRESS_PRO100B=y |
# CONFIG_DE4X5 is not set |
# CONFIG_DEC_ELCP is not set |
# CONFIG_DGRS is not set |
# CONFIG_NE2K_PCI is not set |
# CONFIG_YELLOWFIN is not set |
# CONFIG_RTL8139 is not set |
# CONFIG_EPIC is not set |
# CONFIG_TLAN is not set |
# CONFIG_NET_ISA is not set |
# CONFIG_NET_EISA is not set |
# CONFIG_NET_POCKET is not set |
# CONFIG_TR is not set |
# CONFIG_FDDI is not set |
# CONFIG_ARCNET is not set |
|
# |
# ISDN subsystem |
# |
# CONFIG_ISDN is not set |
|
# |
# Filesystems |
# |
# CONFIG_IMMUNIX_MMFS is not set |
# CONFIG_QUOTA is not set |
# CONFIG_MINIX_FS is not set |
# CONFIG_EXT_FS is not set |
CONFIG_EXT2_FS=y |
# CONFIG_EXT2_CASELESS_ASCII7 is not set |
# CONFIG_XIA_FS is not set |
# CONFIG_NLS is not set |
CONFIG_PROC_FS=y |
# CONFIG_NFS_FS is not set |
# CONFIG_SMB_FS is not set |
# CONFIG_HPFS_FS is not set |
# CONFIG_SYSV_FS is not set |
# CONFIG_AUTOFS_FS is not set |
# CONFIG_AFFS_FS is not set |
CONFIG_ROMFS_FS=y |
# CONFIG_ROMFS_CASELESS_ASCII7 is not set |
# CONFIG_UFS_FS is not set |
|
# |
# Character devices |
# |
CONFIG_SERIAL=y |
# CONFIG_SERIAL_CONSOLE is not set |
# CONFIG_DIGI is not set |
# CONFIG_CYCLADES is not set |
# CONFIG_STALDRV is not set |
# CONFIG_RISCOM8 is not set |
# CONFIG_PRINTER is not set |
# CONFIG_SPECIALIX is not set |
# CONFIG_MOUSE is not set |
# CONFIG_UMISC is not set |
# CONFIG_QIC02_TAPE is not set |
# CONFIG_FTAPE is not set |
# CONFIG_APM is not set |
# CONFIG_WATCHDOG is not set |
# CONFIG_RTC is not set |
# CONFIG_CONSOLE is not set |
# CONFIG_KEYBOARD is not set |
|
# |
# Sound |
# |
# CONFIG_SOUND is not set |
|
# |
# Kernel hacking |
# |
# CONFIG_DEBUG_MALLOC is not set |
# CONFIG_PROFILE is not set |
/eval960.ld
0,0 → 1,26
/*----------------------------------------------------------*/ |
/* Linker Directive File (init_jx.ld) */ |
/*----------------------------------------------------------*/ |
MEMORY |
{ |
data: o=0xA3C00000,l=0x40000 /* for 4 MB dram on eval board */ |
/* data: o=0xA3800000,l=0x80000 for 8 MB dram on eval board */ |
/* data: o=0xA3000000,l=0x100000 for 16 MB dram on eval board */ |
/* data: o=0xA2C00000,l=0x200000 for 32 MB dram on eval board */ |
} |
|
SECTIONS |
{ |
.text : |
{ |
*(.text) |
.=ALIGN(0x10); |
} > data |
.data : |
{ |
} > data |
.bss : |
{ |
} > data |
} |
|
/lib/bzero.c
0,0 → 1,78
|
#include <linux/types.h> |
#include <linux/string.h> |
|
/* Optimization used unaligned access, so it had to go. */ |
|
void bzero(void * s, size_t count) { |
memset(s, '\0', count); |
} |
|
#if 0 |
void * memset(void * s, int c, size_t count) |
{ |
void *xs = s; |
size_t temp, temp1; |
|
if (!count) |
return xs; |
c &= 0xff; |
c |= c << 8; |
c |= c << 16; |
if ((long) s & 1) |
{ |
char *cs = s; |
*cs++ = c; |
s = cs; |
count--; |
} |
if (count > 2 && (long) s & 2) |
{ |
short *ss = s; |
*ss++ = c; |
s = ss; |
count -= 2; |
} |
temp = count >> 2; |
if (temp) |
{ |
long *ls = s; |
|
__asm__ __volatile__("movel %1,%2\n\t" |
"andw #7,%2\n\t" |
"lsrl #3,%1\n\t" |
"negw %2\n\t" |
"jmp %%pc@(2f,%2:w:2)\n\t" |
"1:\t" |
"movel %3,%0@+\n\t" |
"movel %3,%0@+\n\t" |
"movel %3,%0@+\n\t" |
"movel %3,%0@+\n\t" |
"movel %3,%0@+\n\t" |
"movel %3,%0@+\n\t" |
"movel %3,%0@+\n\t" |
"movel %3,%0@+\n\t" |
"2:\t" |
"dbra %1,1b\n\t" |
"clrw %1\n\t" |
"subql #1,%1\n\t" |
"jpl 1b\n\t" |
: "=a" (ls), "=d" (temp), "=&d" (temp1) |
: "d" (c), "0" (ls), "1" (temp) |
); |
s = ls; |
} |
if (count & 2) |
{ |
short *ss = s; |
*ss++ = c; |
s = ss; |
} |
if (count & 1) |
{ |
char *cs = s; |
*cs = c; |
} |
return xs; |
} |
#endif |
/lib/checksum.c
0,0 → 1,172
/* |
* INET An implementation of the TCP/IP protocol suite for the LINUX |
* operating system. |
* |
* IP/TCP/UDP checksumming routines |
* |
* Authors: Keith Adams, <kma@cse.ogi.edu> |
* Jorge Cwik, <jorge@laser.satlink.net> |
* Arnt Gulbrandsen, <agulbra@nvg.unit.no> |
* Tom May, <ftom@netcom.com> |
* Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de> |
* Lots of code moved from tcp.c and ip.c; see those files |
* for more names. |
* |
*/ |
|
#include <net/checksum.h> |
|
#if 1 |
static unsigned long do_csum(const unsigned char * buff, int len) |
{ |
int odd, count; |
unsigned long result = 0; |
|
if (len <= 0) |
goto out; |
odd = 1 & (unsigned long) buff; |
if (odd) { |
result = *buff; |
len--; |
buff++; |
} |
count = len >> 1; /* nr of 16-bit words.. */ |
if (count) { |
if (2 & (unsigned long) buff) { |
result += *(unsigned short *) buff; |
count--; |
len -= 2; |
buff += 2; |
} |
count >>= 1; /* nr of 32-bit words.. */ |
if (count) { |
#if 1 |
unsigned long carry = 0; |
do { |
unsigned long w = *(unsigned long *) buff; |
count--; |
buff += 4; |
result += carry; |
result += w; |
carry = (w > result); |
} while (count); |
result += carry; |
#else |
asm("cmpo 0, 1"); /* clear carry */ |
do { |
unsigned long w = *(unsigned long*) buff; |
count--; |
buff += 4; |
asm("addc 0, %0, %0\n\t" /* r += carry */ |
"cmpo 0, 1\n\t" /* reset c */ |
"addc %1, %0, %0" /* r += w */ |
: "=&r"(result) |
: "r"(w), "0"(result)); |
} while (count); |
asm("addc 0, %0, %0" /* result += carry */ |
: "=r"(result) : "0"(result)); |
#endif |
result = (result & 0xffff) + (result >> 16); |
} |
if (len & 2) { |
result += *(unsigned short *) buff; |
buff += 2; |
} |
} |
if (len & 1) |
result += *buff; |
|
result = from32to16(result); |
if (odd) |
return ntohs(result); |
out: |
return result; |
} |
#else |
|
/* |
* Naive implementation stolen from Stevens |
*/ |
static unsigned long do_csum(const unsigned char * buff, int len) |
{ |
long sum=0; |
|
while (len > 1) { |
sum += *((unsigned short*)buff)++; |
if (sum & (1<<31)) |
sum = (sum & 0xffff); |
len -= 2; |
} |
|
if (len) |
sum += (unsigned short) *buff; |
|
while (sum >> 16) |
sum = (sum & 0xffff) + (sum >> 16); |
|
return sum; |
} |
#endif |
|
/* |
* This is a version of ip_compute_csum() optimized for IP headers, |
* which always checksum on 4 octet boundaries. |
*/ |
unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) |
{ |
return ~do_csum(iph,ihl*4); |
} |
|
/* |
* computes the checksum of a memory block at buff, length len, |
* and adds in "sum" (32-bit) |
* |
* returns a 32-bit number suitable for feeding into itself |
* or csum_tcpudp_magic |
* |
* this function must be called with even lengths, except |
* for the last fragment, which may be odd |
* |
* it's best to have buff aligned on a 32-bit boundary |
*/ |
unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) |
{ |
unsigned int result = do_csum(buff, len); |
|
/* add in old sum, and carry.. */ |
result += sum; |
/* 16+c bits -> 16 bits */ |
result = (result & 0xffff) + (result >> 16); |
return result; |
} |
|
/* |
* this routine is used for miscellaneous IP-like checksums, mainly |
* in icmp.c |
*/ |
unsigned short ip_compute_csum(const unsigned char * buff, int len) |
{ |
return ~do_csum(buff,len); |
} |
|
|
/* |
* copy from fs while checksumming, otherwise like csum_partial |
*/ |
|
unsigned int |
csum_partial_copy_fromuser(const char *src, char *dst, int len, int sum) |
{ |
memcpy(dst, src, len); |
return csum_partial(dst, len, sum); |
} |
/* |
* copy from ds while checksumming, otherwise like csum_partial |
*/ |
|
unsigned int |
csum_partial_copy(const char *src, char *dst, int len, int sum) |
{ |
memcpy(dst, src, len); |
return csum_partial(dst, len, sum); |
} |
/lib/abs.c
0,0 → 1,12
/* |
* FILE: abs.c |
* AUTHOR: kma |
* DESCR: absolute value; we need this |
*/ |
|
#ident "$Id: abs.c,v 1.1.1.1 2001-09-10 07:43:56 simons Exp $" |
|
int abs(int j) |
{ |
return (j<0)? -j : j; |
} |
/lib/__adddi3.S
0,0 → 1,41
/* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
*/ |
|
#include <linux/linkage.h> |
|
/* |
* 64-bit math routines that gcc needs but doesn't have. |
*/ |
|
/* |
* 64-bit addition. |
* |
* registers: |
* g0 = low word of arg 1, g1 = hi word of arg 1 |
* g2 = low word of arg 2, g3 = hi word of arg 2 |
* it wants result in g0-g1 |
*/ |
#define AC_OVERFLOW_BIT 8 |
.globl SYMBOL_NAME(__adddi3) |
SYMBOL_NAME_LABEL(__adddi3) |
cmpo 1, 0 |
addc g0, g2, g0 |
addc g1, g3, g1 |
ret |
|
/* |
* 64-bit subtraction: a-b = c |
* |
* registers in: |
* g0-g1 = a; g2-g3 = b |
* registers out: |
* g0-g1 = c |
*/ |
.globl SYMBOL_NAME(__subdi3) |
SYMBOL_NAME_LABEL(__subdi3) |
cmpo 1, 0 |
subc g2, g0, g0 |
subc g3, g1, g1 |
ret |
/lib/Makefile
0,0 → 1,11
# |
# Makefile for m68k-specific library files.. |
# |
|
.S.o: |
$(CC) $(AFLAGS) -D__ASSEMBLY__ -traditional -c $< -o $@ |
|
L_TARGET = lib.a |
L_OBJS = abs.o ashrdi3.o checksum.o __adddi3.o |
|
include $(TOPDIR)/Rules.make |
/lib/ashrdi3.c
0,0 → 1,65
/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ |
/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
|
This file is part of GNU CC. |
|
GNU CC 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, or (at your option) |
any later version. |
|
GNU CC 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 |
GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#include <linux/stddef.h> |
|
#define BITS_PER_UNIT 8 |
|
typedef int SItype __attribute__ ((mode (SI))); |
typedef unsigned int USItype __attribute__ ((mode (SI))); |
typedef int DItype __attribute__ ((mode (DI))); |
typedef int word_type __attribute__ ((mode (__word__))); |
|
struct DIstruct {SItype high, low;}; |
|
typedef union |
{ |
struct DIstruct s; |
DItype ll; |
} DIunion; |
|
DItype |
__ashrdi3 (DItype u, word_type b) |
{ |
DIunion w; |
word_type bm; |
DIunion uu; |
|
if (b == 0) |
return u; |
|
uu.ll = u; |
|
bm = (sizeof (SItype) * BITS_PER_UNIT) - b; |
if (bm <= 0) |
{ |
/* w.s.high = 1..1 or 0..0 */ |
w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); |
w.s.low = uu.s.high >> -bm; |
} |
else |
{ |
USItype carries = (USItype)uu.s.high << bm; |
w.s.high = uu.s.high >> b; |
w.s.low = ((USItype)uu.s.low >> b) | carries; |
} |
|
return w.ll; |
} |
/mm/init.c
0,0 → 1,226
/* |
* linux/arch/i960/mm/init.c |
* |
* Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu> |
* Oregon Graduate Institute |
* |
* Based on: |
* |
* linux/arch/m68knommu/mm/init.c |
* |
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, |
* Kenneth Albanowski <kjahds@kjahds.com>, |
* The Silver Hammer Group, Ltd. |
* |
* Based on: |
* |
* linux/arch/m68k/mm/init.c |
* |
* Copyright (C) 1995 Hamish Macdonald |
*/ |
|
#include <linux/config.h> |
#include <linux/signal.h> |
#include <linux/sched.h> |
#include <linux/mm.h> |
#include <linux/swap.h> |
#include <linux/kernel.h> |
#include <linux/string.h> |
#include <linux/types.h> |
#ifdef CONFIG_BLK_DEV_RAM |
#include <linux/blk.h> |
#endif |
|
#include <asm/setup.h> |
#include <asm/segment.h> |
#include <asm/page.h> |
#include <asm/pgtable.h> |
#include <asm/system.h> |
#include <asm/machdep.h> |
|
#ifndef PAGE_OFFSET |
#define PAGE_OFFSET 0 |
#endif |
|
extern void die_if_kernel(char *,struct pt_regs *,long); |
extern void show_net_buffers(void); |
|
/* |
* BAD_PAGE is the page that is used for page faults when linux |
* is out-of-memory. Older versions of linux just did a |
* do_exit(), but using this instead means there is less risk |
* for a process dying in kernel mode, possibly leaving a inode |
* unused etc.. |
* |
* BAD_PAGETABLE is the accompanying page-table: it is initialized |
* to point to BAD_PAGE entries. |
* |
* ZERO_PAGE is a special page that is used for zero-initialized |
* data and COW. |
*/ |
static unsigned long empty_bad_page_table; |
|
static unsigned long empty_bad_page; |
|
unsigned long empty_zero_page; |
|
extern unsigned long rom_length; |
|
void show_mem(void) |
{ |
unsigned long i; |
int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0; |
|
printk("\nMem-info:\n"); |
show_free_areas(); |
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); |
i = high_memory >> PAGE_SHIFT; |
while (i-- > 0) { |
total++; |
if (PageReserved(mem_map+i)) |
reserved++; |
else if (!mem_map[i].count) |
free++; |
else if (mem_map[i].count == 1) |
nonshared++; |
else |
shared += mem_map[i].count-1; |
} |
printk("%d pages of RAM\n",total); |
printk("%d free pages\n",free); |
printk("%d reserved pages\n",reserved); |
printk("%d pages nonshared\n",nonshared); |
printk("%d pages shared\n",shared); |
show_buffers(); |
#ifdef CONFIG_NET |
show_net_buffers(); |
#endif |
} |
|
extern unsigned long free_area_init(unsigned long, unsigned long); |
|
/* |
* paging_init() sets up the 'virtual' memory environment. |
* The parameters are pointers to where to stick the starting and ending |
* addresses of available kernel virtual memory. |
*/ |
unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) |
{ |
|
#ifdef DEBUG |
printk ("memory available is %ldKB\n", (end_mem - start_mem) >> 10); |
#endif |
|
/* |
* virtual address after end of kernel |
* "availmem" is setup by the code in head.S. |
*/ |
/*start_mem = availmem;*/ |
|
#ifdef DEBUG |
printk ("start_mem is %#lx\nvirtual_end is %#lx\n", |
start_mem, end_mem); |
#endif |
|
/* |
* initialize the bad page table and bad page to point |
* to a couple of allocated pages |
*/ |
empty_bad_page_table = start_mem; |
start_mem += PAGE_SIZE; |
empty_bad_page = start_mem; |
start_mem += PAGE_SIZE; |
empty_zero_page = start_mem; |
start_mem += PAGE_SIZE; |
memset((void *)empty_zero_page, 0, PAGE_SIZE); |
|
/* |
* Set up SFC/DFC registers (user data space) |
*/ |
/* on NO_MM systems this is rather a nop */ |
set_fs (USER_DS); |
|
#ifdef DEBUG |
printk ("before free_area_init\n"); |
|
printk ("free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n", |
start_mem, end_mem); |
#endif |
|
return PAGE_ALIGN(free_area_init (start_mem, end_mem)); |
} |
|
void mem_init(unsigned long start_mem, unsigned long end_mem) |
{ |
int codek = 0; |
int datapages = 0; |
unsigned long tmp; |
extern char _etext, _stext, _sdata; |
unsigned long len = end_mem-(unsigned long)&_sdata; |
|
#ifdef DEBUG |
printk("Mem_init: start=%lx, end=%lx\n", start_mem, end_mem); |
#endif |
|
end_mem &= PAGE_MASK; |
high_memory = end_mem; |
|
start_mem = PAGE_ALIGN(start_mem); |
while (start_mem < high_memory) { |
clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); |
start_mem += PAGE_SIZE; |
} |
|
for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) { |
|
#ifdef MAX_DMA_ADDRESS |
if (VTOP (tmp) >= MAX_DMA_ADDRESS) |
clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); |
#endif |
|
if (PageReserved(mem_map+MAP_NR(tmp))) { |
datapages++; |
continue; |
} |
mem_map[MAP_NR(tmp)].count = 1; |
#ifdef CONFIG_BLK_DEV_INITRD |
if (!initrd_start || |
(tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end)) |
#endif |
free_page(tmp); |
} |
|
codek = (&_etext - &_stext) >> 10; |
tmp = nr_free_pages << PAGE_SHIFT; |
printk("Memory available: %luk/%luk RAM, %luk/%luk ROM (%dk kernel data, %dk code)\n", |
tmp >> 10, |
len >> 10, |
(rom_length >> 10) - codek, |
rom_length >> 10, |
datapages << (PAGE_SHIFT-10), |
codek |
); |
} |
|
void si_meminfo(struct sysinfo *val) |
{ |
unsigned long i; |
|
i = (high_memory - PAGE_OFFSET) >> PAGE_SHIFT; |
val->totalram = 0; |
val->sharedram = 0; |
val->freeram = nr_free_pages << PAGE_SHIFT; |
val->bufferram = buffermem; |
while (i-- > 0) { |
if (PageReserved(mem_map+i)) |
continue; |
val->totalram++; |
if (!mem_map[i].count) |
continue; |
val->sharedram += mem_map[i].count-1; |
} |
val->totalram <<= PAGE_SHIFT; |
val->sharedram <<= PAGE_SHIFT; |
return; |
} |
|
/mm/memory.c
0,0 → 1,1067
/* |
* linux/arch/m68knommu/mm/memory.c |
* |
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>, |
* The Silver Hammer Group, Ltd. |
* |
* Based on: |
* |
* linux/arch/m68k/mm/memory.c |
* |
* Copyright (C) 1995 Hamish Macdonald |
*/ |
|
#include <linux/config.h> |
#include <linux/mm.h> |
#include <linux/kernel.h> |
#include <linux/string.h> |
#include <linux/types.h> |
#include <linux/malloc.h> |
|
#include <asm/setup.h> |
#include <asm/segment.h> |
#include <asm/page.h> |
#include <asm/pgtable.h> |
#include <asm/system.h> |
#include <asm/traps.h> |
|
#ifndef NO_MM |
|
extern pte_t *kernel_page_table (unsigned long *memavailp); |
|
/* Strings for `extern inline' functions in <asm/pgtable.h>. If put |
directly into these functions, they are output for every file that |
includes pgtable.h */ |
|
const char PgtabStr_bad_pmd[] = "Bad pmd in pte_alloc: %08lx\n"; |
const char PgtabStr_bad_pgd[] = "Bad pgd in pmd_alloc: %08lx\n"; |
const char PgtabStr_bad_pmdk[] = "Bad pmd in pte_alloc_kernel: %08lx\n"; |
const char PgtabStr_bad_pgdk[] = "Bad pgd in pmd_alloc_kernel: %08lx\n"; |
|
static struct ptable_desc { |
struct ptable_desc *prev; |
struct ptable_desc *next; |
unsigned long page; |
unsigned char alloced; |
} ptable_list = { &ptable_list, &ptable_list, 0, 0xff }; |
|
#define PD_NONEFREE(dp) ((dp)->alloced == 0xff) |
#define PD_ALLFREE(dp) ((dp)->alloced == 0) |
#define PD_TABLEFREE(dp,i) (!((dp)->alloced & (1<<(i)))) |
#define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i))) |
#define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i))) |
|
#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t)) |
|
pmd_t *get_pointer_table (void) |
{ |
pmd_t *pmdp = NULL; |
unsigned long flags; |
struct ptable_desc *dp = ptable_list.next; |
int i; |
|
/* |
* For a pointer table for a user process address space, a |
* table is taken from a page allocated for the purpose. Each |
* page can hold 8 pointer tables. The page is remapped in |
* virtual address space to be noncacheable. |
*/ |
if (PD_NONEFREE (dp)) { |
|
if (!(dp = kmalloc (sizeof(struct ptable_desc),GFP_KERNEL))) { |
return 0; |
} |
|
if (!(dp->page = __get_free_page (GFP_KERNEL))) { |
kfree (dp); |
return 0; |
} |
|
nocache_page (dp->page); |
|
dp->alloced = 0; |
/* put at head of list */ |
save_flags(flags); |
cli(); |
dp->next = ptable_list.next; |
dp->prev = ptable_list.next->prev; |
ptable_list.next->prev = dp; |
ptable_list.next = dp; |
restore_flags(flags); |
} |
|
for (i = 0; i < 8; i++) |
if (PD_TABLEFREE (dp, i)) { |
PD_MARKUSED (dp, i); |
pmdp = (pmd_t *)(dp->page + PTABLE_SIZE*i); |
break; |
} |
|
if (PD_NONEFREE (dp)) { |
/* move to end of list */ |
save_flags(flags); |
cli(); |
dp->prev->next = dp->next; |
dp->next->prev = dp->prev; |
|
dp->next = ptable_list.next->prev; |
dp->prev = ptable_list.prev; |
ptable_list.prev->next = dp; |
ptable_list.prev = dp; |
restore_flags(flags); |
} |
|
memset (pmdp, 0, PTABLE_SIZE); |
|
return pmdp; |
} |
|
void free_pointer_table (pmd_t *ptable) |
{ |
struct ptable_desc *dp; |
unsigned long page = (unsigned long)ptable & PAGE_MASK; |
int index = ((unsigned long)ptable - page)/PTABLE_SIZE; |
unsigned long flags; |
|
for (dp = ptable_list.next; dp->page && dp->page != page; dp = dp->next) |
; |
|
if (!dp->page) |
panic ("unable to find desc for ptable %p on list!", ptable); |
|
if (PD_TABLEFREE (dp, index)) |
panic ("table already free!"); |
|
PD_MARKFREE (dp, index); |
|
if (PD_ALLFREE (dp)) { |
/* all tables in page are free, free page */ |
save_flags(flags); |
cli(); |
dp->prev->next = dp->next; |
dp->next->prev = dp->prev; |
restore_flags(flags); |
cache_page (dp->page); |
free_page (dp->page); |
kfree (dp); |
return; |
} else { |
/* |
* move this descriptor the the front of the list, since |
* it has one or more free tables. |
*/ |
save_flags(flags); |
cli(); |
dp->prev->next = dp->next; |
dp->next->prev = dp->prev; |
|
dp->next = ptable_list.next; |
dp->prev = ptable_list.next->prev; |
ptable_list.next->prev = dp; |
ptable_list.next = dp; |
restore_flags(flags); |
} |
} |
|
/* maximum pages used for kpointer tables */ |
#define KPTR_PAGES 4 |
/* # of reserved slots */ |
#define RESERVED_KPTR 4 |
extern pmd_tablepage kernel_pmd_table; /* reserved in head.S */ |
|
static struct kpointer_pages { |
pmd_tablepage *page[KPTR_PAGES]; |
u_char alloced[KPTR_PAGES]; |
} kptr_pages; |
|
void init_kpointer_table(void) { |
short i = KPTR_PAGES-1; |
|
/* first page is reserved in head.S */ |
kptr_pages.page[i] = &kernel_pmd_table; |
kptr_pages.alloced[i] = ~(0xff>>RESERVED_KPTR); |
for (i--; i>=0; i--) { |
kptr_pages.page[i] = NULL; |
kptr_pages.alloced[i] = 0; |
} |
} |
|
pmd_t *get_kpointer_table (void) |
{ |
/* For pointer tables for the kernel virtual address space, |
* use the page that is reserved in head.S that can hold up to |
* 8 pointer tables. 3 of these tables are always reserved |
* (kernel_pg_dir, swapper_pg_dir and kernel pointer table for |
* the first 16 MB of RAM). In addition, the 4th pointer table |
* in this page is reserved. On Amiga and Atari, it is used to |
* map in the hardware registers. It may be used for other |
* purposes on other 68k machines. This leaves 4 pointer tables |
* available for use by the kernel. 1 of them are usually used |
* for the vmalloc tables. This allows mapping of 3 * 32 = 96 MB |
* of physical memory. But these pointer tables are also used |
* for other purposes, like kernel_map(), so further pages can |
* now be allocated. |
*/ |
pmd_tablepage *page; |
pmd_table *table; |
long nr, offset = -8; |
short i; |
|
for (i=KPTR_PAGES-1; i>=0; i--) { |
asm volatile("bfffo %1{%2,#8},%0" |
: "=d" (nr) |
: "d" ((u_char)~kptr_pages.alloced[i]), "d" (offset)); |
if (nr) |
break; |
} |
if (i < 0) { |
printk("No space for kernel pointer table!\n"); |
return NULL; |
} |
if (!(page = kptr_pages.page[i])) { |
if (!(page = (pmd_tablepage *)__get_free_page(GFP_KERNEL))) { |
printk("No space for kernel pointer table!\n"); |
return NULL; |
} |
nocache_page((u_long)(kptr_pages.page[i] = page)); |
} |
asm volatile("bfset %0@{%1,#1}" |
: /* no output */ |
: "a" (&kptr_pages.alloced[i]), "d" (nr-offset)); |
table = &(*page)[nr-offset]; |
memset(table, 0, sizeof(pmd_table)); |
return ((pmd_t *)table); |
} |
|
void free_kpointer_table (pmd_t *pmdp) |
{ |
pmd_table *table = (pmd_table *)pmdp; |
pmd_tablepage *page = (pmd_tablepage *)((u_long)table & PAGE_MASK); |
long nr; |
short i; |
|
for (i=KPTR_PAGES-1; i>=0; i--) { |
if (kptr_pages.page[i] == page) |
break; |
} |
nr = ((u_long)table - (u_long)page) / sizeof(pmd_table); |
if (!table || i < 0 || (i == KPTR_PAGES-1 && nr < RESERVED_KPTR)) { |
printk("Attempt to free invalid kernel pointer table: %p\n", table); |
return; |
} |
asm volatile("bfclr %0@{%1,#1}" |
: /* no output */ |
: "a" (&kptr_pages.alloced[i]), "d" (nr)); |
if (!kptr_pages.alloced[i]) { |
kptr_pages.page[i] = 0; |
cache_page ((u_long)page); |
free_page ((u_long)page); |
} |
} |
|
static unsigned long transp_transl_matches( unsigned long regval, |
unsigned long vaddr ) |
{ |
unsigned long base, mask; |
|
/* enabled? */ |
if (!(regval & 0x8000)) |
return( 0 ); |
|
if (CPU_IS_030) { |
/* function code match? */ |
base = (regval >> 4) & 7; |
mask = ~(regval & 7); |
if ((SUPER_DATA & mask) != (base & mask)) |
return( 0 ); |
} |
else { |
/* must not be user-only */ |
if ((regval & 0x6000) == 0) |
return( 0 ); |
} |
|
/* address match? */ |
base = regval & 0xff000000; |
mask = ~((regval << 8) & 0xff000000); |
return( (vaddr & mask) == (base & mask) ); |
} |
|
/* |
* The following two routines map from a physical address to a kernel |
* virtual address and vice versa. |
*/ |
unsigned long mm_vtop (unsigned long vaddr) |
{ |
int i; |
unsigned long voff = vaddr; |
unsigned long offset = 0; |
|
for (i = 0; i < boot_info.num_memory; i++) |
{ |
if (voff < offset + boot_info.memory[i].size) { |
#ifdef DEBUGPV |
printk ("VTOP(%lx)=%lx\n", vaddr, |
boot_info.memory[i].addr + voff - offset); |
#endif |
return boot_info.memory[i].addr + voff - offset; |
} else |
offset += boot_info.memory[i].size; |
} |
|
/* not in one of the memory chunks; test for applying transparent |
* translation */ |
|
if (CPU_IS_030) { |
unsigned long ttreg; |
register unsigned long *ttregptr __asm__( "a2" ) = &ttreg; |
|
asm volatile( ".long 0xf0120a00;" /* pmove %/tt0,%a0@ */ |
: "=g" (ttreg) : "a" (ttregptr) ); |
if (transp_transl_matches( ttreg, vaddr )) |
return vaddr; |
|
asm volatile( ".long 0xf0120a00" /* pmove %/tt1,%a0@ */ |
: "=g" (ttreg) : "a" (ttregptr) ); |
if (transp_transl_matches( ttreg, vaddr )) |
return vaddr; |
} |
else if (CPU_IS_040_OR_060) { |
register unsigned long ttreg __asm__( "d0" ); |
|
asm volatile( ".long 0x4e7a0006" /* movec %dtt0,%d0 */ |
: "=d" (ttreg) ); |
if (transp_transl_matches( ttreg, vaddr )) |
return vaddr; |
asm volatile( ".long 0x4e7a0007" /* movec %dtt1,%d0 */ |
: "=d" (ttreg) ); |
if (transp_transl_matches( ttreg, vaddr )) |
return vaddr; |
} |
|
/* no match, too, so get the actual physical address from the MMU. */ |
|
if (CPU_IS_060) { |
unsigned long fs = get_fs(); |
unsigned long paddr; |
|
set_fs (SUPER_DATA); |
|
/* The PLPAR instruction causes an access error if the translation |
* is not possible. We don't catch that here, so a bad kernel trap |
* will be reported in this case. */ |
asm volatile ("movel %1,%/a0\n\t" |
".word 0xf5c8\n\t" /* plpar (a0) */ |
"movel %/a0,%0" |
: "=g" (paddr) |
: "g" (vaddr) |
: "a0" ); |
set_fs (fs); |
|
return paddr; |
|
} else if (CPU_IS_040) { |
unsigned long mmusr; |
unsigned long fs = get_fs(); |
|
set_fs (SUPER_DATA); |
|
asm volatile ("movel %1,%/a0\n\t" |
".word 0xf568\n\t" /* ptestr (a0) */ |
".long 0x4e7a8805\n\t" /* movec mmusr, a0 */ |
"movel %/a0,%0" |
: "=g" (mmusr) |
: "g" (vaddr) |
: "a0", "d0"); |
set_fs (fs); |
|
if (mmusr & MMU_R_040) |
return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1)); |
|
panic ("VTOP040: bad virtual address %08lx (%lx)", vaddr, mmusr); |
} else { |
volatile unsigned short temp; |
unsigned short mmusr; |
unsigned long *descaddr; |
|
asm volatile ("ptestr #5,%2@,#7,%0\n\t" |
"pmove %/psr,%1@" |
: "=a&" (descaddr) |
: "a" (&temp), "a" (vaddr)); |
mmusr = temp; |
|
if (mmusr & (MMU_I|MMU_B|MMU_L)) |
panic ("VTOP030: bad virtual address %08lx (%x)", vaddr, mmusr); |
|
descaddr = (unsigned long *)PTOV(descaddr); |
|
switch (mmusr & MMU_NUM) { |
case 1: |
return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff); |
case 2: |
return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff); |
case 3: |
return (*descaddr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1)); |
default: |
panic ("VTOP: bad levels (%u) for virtual address %08lx", |
mmusr & MMU_NUM, vaddr); |
} |
} |
|
panic ("VTOP: bad virtual address %08lx", vaddr); |
} |
|
unsigned long mm_ptov (unsigned long paddr) |
{ |
int i; |
unsigned long offset = 0; |
|
for (i = 0; i < boot_info.num_memory; i++) |
{ |
if (paddr >= boot_info.memory[i].addr && |
paddr < (boot_info.memory[i].addr |
+ boot_info.memory[i].size)) { |
#ifdef DEBUGPV |
printk ("PTOV(%lx)=%lx\n", paddr, |
(paddr - boot_info.memory[i].addr) + offset); |
#endif |
return (paddr - boot_info.memory[i].addr) + offset; |
} else |
offset += boot_info.memory[i].size; |
} |
|
/* |
* assume that the kernel virtual address is the same as the |
* physical address. |
* |
* This should be reasonable in most situations: |
* 1) They shouldn't be dereferencing the virtual address |
* unless they are sure that it is valid from kernel space. |
* 2) The only usage I see so far is converting a page table |
* reference to some non-FASTMEM address space when freeing |
* mmaped "/dev/mem" pages. These addresses are just passed |
* to "free_page", which ignores addresses that aren't in |
* the memory list anyway. |
* |
*/ |
|
/* |
* if on an amiga and address is in first 16M, move it |
* to the ZTWO_ADDR range |
*/ |
if (MACH_IS_AMIGA && paddr < 16*1024*1024) |
return ZTWO_VADDR(paddr); |
return paddr; |
} |
|
/* invalidate page in both caches */ |
#define clear040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ |
"nop\n\t"\ |
".word 0xf4d0"\ |
/* CINVP I/D (a0) */\ |
: : "g" ((paddr))\ |
: "a0") |
|
/* invalidate page in i-cache */ |
#define cleari040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ |
/* CINVP I (a0) */\ |
"nop\n\t"\ |
".word 0xf490"\ |
: : "g" ((paddr))\ |
: "a0") |
|
/* push page in both caches */ |
#define push040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ |
"nop\n\t"\ |
".word 0xf4f0"\ |
/* CPUSHP I/D (a0) */\ |
: : "g" ((paddr))\ |
: "a0") |
|
/* push and invalidate page in both caches */ |
#define pushcl040(paddr) do { push040((paddr));\ |
if (CPU_IS_060) clear040((paddr));\ |
} while(0) |
|
/* push page in both caches, invalidate in i-cache */ |
#define pushcli040(paddr) do { push040((paddr));\ |
if (CPU_IS_060) cleari040((paddr));\ |
} while(0) |
|
/* push page defined by virtual address in both caches */ |
#define pushv040(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ |
/* ptestr (a0) */\ |
"nop\n\t"\ |
".word 0xf568\n\t"\ |
/* movec mmusr,d0 */\ |
".long 0x4e7a0805\n\t"\ |
"andw #0xf000,%/d0\n\t"\ |
"movel %/d0,%/a0\n\t"\ |
/* CPUSHP I/D (a0) */\ |
"nop\n\t"\ |
".word 0xf4f0"\ |
: : "g" ((vaddr))\ |
: "a0", "d0") |
|
/* push page defined by virtual address in both caches */ |
#define pushv060(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\ |
/* plpar (a0) */\ |
".word 0xf5c8\n\t"\ |
/* CPUSHP I/D (a0) */\ |
".word 0xf4f0"\ |
: : "g" ((vaddr))\ |
: "a0") |
|
|
/* |
* 040: Hit every page containing an address in the range paddr..paddr+len-1. |
* (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s). |
* Hit every page until there is a page or less to go. Hit the next page, |
* and the one after that if the range hits it. |
*/ |
/* ++roman: A little bit more care is required here: The CINVP instruction |
* invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning |
* and the end of the region must be treated differently if they are not |
* exactly at the beginning or end of a page boundary. Else, maybe too much |
* data becomes invalidated and thus lost forever. CPUSHP does what we need: |
* it invalidates the page after pushing dirty data to memory. (Thanks to Jes |
* for discovering the problem!) |
*/ |
/* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set |
* the DPI bit in the CACR; would it cause problems with temporarily changing |
* this?). So we have to push first and then additionally to invalidate. |
*/ |
|
/* |
* cache_clear() semantics: Clear any cache entries for the area in question, |
* without writing back dirty entries first. This is useful if the data will |
* be overwritten anyway, e.g. by DMA to memory. The range is defined by a |
* _physical_ address. |
*/ |
|
void cache_clear (unsigned long paddr, int len) |
{ |
if (CPU_IS_040_OR_060) { |
/* |
* cwe need special treatment for the first page, in case it |
* is not page-aligned. |
*/ |
if (paddr & (PAGE_SIZE - 1)){ |
pushcl040(paddr); |
if (len <= PAGE_SIZE){ |
if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { |
pushcl040(paddr + len - 1); |
} |
return; |
}else{ |
len -=PAGE_SIZE; |
paddr += PAGE_SIZE; |
} |
} |
|
while (len > PAGE_SIZE) { |
#if 0 |
pushcl040(paddr); |
#else |
clear040(paddr); |
#endif |
len -= PAGE_SIZE; |
paddr += PAGE_SIZE; |
} |
if (len > 0) { |
pushcl040(paddr); |
if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { |
/* a page boundary gets crossed at the end */ |
pushcl040(paddr + len - 1); |
} |
} |
} |
else /* 68030 or 68020 */ |
asm volatile ("movec %/cacr,%/d0\n\t" |
"oriw %0,%/d0\n\t" |
"movec %/d0,%/cacr" |
: : "i" (FLUSH_I_AND_D) |
: "d0"); |
} |
|
|
/* |
* cache_push() semantics: Write back any dirty cache data in the given area, |
* and invalidate the range in the instruction cache. It needs not (but may) |
* invalidate those entries also in the data cache. The range is defined by a |
* _physical_ address. |
*/ |
|
void cache_push (unsigned long paddr, int len) |
{ |
if (CPU_IS_040_OR_060) { |
/* |
* on 68040 or 68060, push cache lines for pages in the range; |
* on the '040 this also invalidates the pushed lines, but not on |
* the '060! |
*/ |
while (len > PAGE_SIZE) { |
pushcli040(paddr); |
len -= PAGE_SIZE; |
paddr += PAGE_SIZE; |
} |
if (len > 0) { |
pushcli040(paddr); |
if (((paddr + len - 1) ^ paddr) & PAGE_MASK) { |
/* a page boundary gets crossed at the end */ |
pushcli040(paddr + len - 1); |
} |
} |
} |
|
|
/* |
* 68030/68020 have no writeback cache. On the other hand, |
* cache_push is actually a superset of cache_clear (the lines |
* get written back and invalidated), so we should make sure |
* to perform the corresponding actions. After all, this is getting |
* called in places where we've just loaded code, or whatever, so |
* flushing the icache is appropriate; flushing the dcache shouldn't |
* be required. |
*/ |
else /* 68030 or 68020 */ |
asm volatile ("movec %/cacr,%/d0\n\t" |
"oriw %0,%/d0\n\t" |
"movec %/d0,%/cacr" |
: : "i" (FLUSH_I) |
: "d0"); |
} |
|
|
/* |
* cache_push_v() semantics: Write back any dirty cache data in the given |
* area, and invalidate those entries at least in the instruction cache. This |
* is intended to be used after data has been written that can be executed as |
* code later. The range is defined by a _user_mode_ _virtual_ address (or, |
* more exactly, the space is defined by the %sfc/%dfc register.) |
*/ |
|
void cache_push_v (unsigned long vaddr, int len) |
{ |
if (CPU_IS_040) { |
/* on 68040, push cache lines for pages in the range */ |
while (len > PAGE_SIZE) { |
pushv040(vaddr); |
len -= PAGE_SIZE; |
vaddr += PAGE_SIZE; |
} |
if (len > 0) { |
pushv040(vaddr); |
if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) { |
/* a page boundary gets crossed at the end */ |
pushv040(vaddr + len - 1); |
} |
} |
} |
else if (CPU_IS_060) { |
/* on 68040, push cache lines for pages in the range */ |
while (len > PAGE_SIZE) { |
pushv060(vaddr); |
len -= PAGE_SIZE; |
vaddr += PAGE_SIZE; |
} |
if (len > 0) { |
pushv060(vaddr); |
if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) { |
/* a page boundary gets crossed at the end */ |
pushv060(vaddr + len - 1); |
} |
} |
} |
/* 68030/68020 have no writeback cache; still need to clear icache. */ |
else /* 68030 or 68020 */ |
asm volatile ("movec %/cacr,%/d0\n\t" |
"oriw %0,%/d0\n\t" |
"movec %/d0,%/cacr" |
: : "i" (FLUSH_I) |
: "d0"); |
} |
|
#undef clear040 |
#undef cleari040 |
#undef push040 |
#undef pushcl040 |
#undef pushcli040 |
#undef pushv040 |
#undef pushv060 |
|
unsigned long mm_phys_to_virt (unsigned long addr) |
{ |
return PTOV (addr); |
} |
|
int mm_end_of_chunk (unsigned long addr, int len) |
{ |
int i; |
|
for (i = 0; i < boot_info.num_memory; i++) |
if (boot_info.memory[i].addr + boot_info.memory[i].size |
== addr + len) |
return 1; |
return 0; |
} |
|
/* Map some physical address range into the kernel address space. The |
* code is copied and adapted from map_chunk(). |
*/ |
|
unsigned long kernel_map(unsigned long paddr, unsigned long size, |
int nocacheflag, unsigned long *memavailp ) |
{ |
#define STEP_SIZE (256*1024) |
|
static unsigned long vaddr = 0xe0000000; /* safe place */ |
unsigned long physaddr, retaddr; |
pte_t *ktablep = NULL; |
pmd_t *kpointerp; |
pgd_t *page_dir; |
int pindex; /* index into pointer table */ |
int prot; |
|
/* Round down 'paddr' to 256 KB and adjust size */ |
physaddr = paddr & ~(STEP_SIZE-1); |
size += paddr - physaddr; |
retaddr = vaddr + (paddr - physaddr); |
paddr = physaddr; |
/* Round up the size to 256 KB. It doesn't hurt if too much is |
* mapped... */ |
size = (size + STEP_SIZE - 1) & ~(STEP_SIZE-1); |
|
if (CPU_IS_040_OR_060) { |
prot = _PAGE_PRESENT | _PAGE_GLOBAL040; |
switch( nocacheflag ) { |
case KERNELMAP_FULL_CACHING: |
prot |= _PAGE_CACHE040; |
break; |
case KERNELMAP_NOCACHE_SER: |
default: |
prot |= _PAGE_NOCACHE_S; |
break; |
case KERNELMAP_NOCACHE_NONSER: |
prot |= _PAGE_NOCACHE; |
break; |
case KERNELMAP_NO_COPYBACK: |
prot |= _PAGE_CACHE040W; |
/* prot |= 0; */ |
break; |
} |
} else |
prot = _PAGE_PRESENT | |
((nocacheflag == KERNELMAP_FULL_CACHING || |
nocacheflag == KERNELMAP_NO_COPYBACK) ? 0 : _PAGE_NOCACHE030); |
|
page_dir = pgd_offset_k(vaddr); |
if (pgd_present(*page_dir)) { |
kpointerp = (pmd_t *)pgd_page(*page_dir); |
pindex = (vaddr >> 18) & 0x7f; |
if (pindex != 0 && CPU_IS_040_OR_060) { |
if (pmd_present(*kpointerp)) |
ktablep = (pte_t *)pmd_page(*kpointerp); |
else { |
ktablep = kernel_page_table (memavailp); |
/* Make entries invalid */ |
memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); |
pmd_set(kpointerp,ktablep); |
} |
ktablep += (pindex & 15)*64; |
} |
} |
else { |
/* we need a new pointer table */ |
kpointerp = get_kpointer_table (); |
pgd_set(page_dir, (pmd_t *)kpointerp); |
memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); |
pindex = 0; |
} |
|
for (physaddr = paddr; physaddr < paddr + size; vaddr += STEP_SIZE) { |
|
if (pindex > 127) { |
/* we need a new pointer table */ |
kpointerp = get_kpointer_table (); |
pgd_set(pgd_offset_k(vaddr), (pmd_t *)kpointerp); |
memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); |
pindex = 0; |
} |
|
if (CPU_IS_040_OR_060) { |
int i; |
unsigned long ktable; |
|
/* |
* 68040, use page tables pointed to by the |
* kernel pointer table. |
*/ |
|
if ((pindex & 15) == 0) { |
/* Need new page table every 4M on the '040 */ |
ktablep = kernel_page_table (memavailp); |
/* Make entries invalid */ |
memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); |
} |
|
ktable = VTOP(ktablep); |
|
/* |
* initialize section of the page table mapping |
* this 1M portion. |
*/ |
for (i = 0; i < 64; i++) { |
pte_val(*ktablep++) = physaddr | prot; |
physaddr += PAGE_SIZE; |
} |
|
/* |
* make the kernel pointer table point to the |
* kernel page table. |
*/ |
|
((unsigned long *)kpointerp)[pindex++] = ktable | _PAGE_TABLE; |
|
} else { |
/* |
* 68030, use early termination page descriptors. |
* Each one points to 64 pages (256K). |
*/ |
((unsigned long *)kpointerp)[pindex++] = physaddr | prot; |
physaddr += 64 * PAGE_SIZE; |
} |
} |
|
return( retaddr ); |
} |
|
|
static inline void set_cmode_pte( pmd_t *pmd, unsigned long address, |
unsigned long size, unsigned cmode ) |
{ pte_t *pte; |
unsigned long end; |
|
if (pmd_none(*pmd)) |
return; |
|
pte = pte_offset( pmd, address ); |
address &= ~PMD_MASK; |
end = address + size; |
if (end >= PMD_SIZE) |
end = PMD_SIZE; |
|
for( ; address < end; pte++ ) { |
pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode; |
address += PAGE_SIZE; |
} |
} |
|
|
static inline void set_cmode_pmd( pgd_t *dir, unsigned long address, |
unsigned long size, unsigned cmode ) |
{ |
pmd_t *pmd; |
unsigned long end; |
|
if (pgd_none(*dir)) |
return; |
|
pmd = pmd_offset( dir, address ); |
address &= ~PGDIR_MASK; |
end = address + size; |
if (end > PGDIR_SIZE) |
end = PGDIR_SIZE; |
|
if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) { |
/* 68030 early termination descriptor */ |
pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode; |
return; |
} |
else { |
/* "normal" tables */ |
for( ; address < end; pmd++ ) { |
set_cmode_pte( pmd, address, end - address, cmode ); |
address = (address + PMD_SIZE) & PMD_MASK; |
} |
} |
} |
|
|
/* |
* Set new cache mode for some kernel address space. |
* The caller must push data for that range itself, if such data may already |
* be in the cache. |
*/ |
|
void kernel_set_cachemode( unsigned long address, unsigned long size, |
unsigned cmode ) |
{ |
pgd_t *dir = pgd_offset_k( address ); |
unsigned long end = address + size; |
|
if (CPU_IS_040_OR_060) { |
switch( cmode ) { |
case KERNELMAP_FULL_CACHING: |
cmode = _PAGE_CACHE040; |
break; |
case KERNELMAP_NOCACHE_SER: |
default: |
cmode = _PAGE_NOCACHE_S; |
break; |
case KERNELMAP_NOCACHE_NONSER: |
cmode = _PAGE_NOCACHE; |
break; |
case KERNELMAP_NO_COPYBACK: |
cmode = _PAGE_CACHE040W; |
break; |
} |
} else |
cmode = ((cmode == KERNELMAP_FULL_CACHING || |
cmode == KERNELMAP_NO_COPYBACK) ? |
0 : _PAGE_NOCACHE030); |
|
for( ; address < end; dir++ ) { |
set_cmode_pmd( dir, address, end - address, cmode ); |
address = (address + PGDIR_SIZE) & PGDIR_MASK; |
} |
flush_tlb_all(); |
} |
|
#else /* !NO_MM */ |
|
/* |
* The following two routines map from a physical address to a kernel |
* virtual address and vice versa. |
*/ |
unsigned long mm_vtop (unsigned long vaddr) |
{ |
return vaddr; |
} |
|
unsigned long mm_ptov (unsigned long paddr) |
{ |
return paddr; |
} |
|
|
/* |
* 040: Hit every page containing an address in the range paddr..paddr+len-1. |
* (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s). |
* Hit every page until there is a page or less to go. Hit the next page, |
* and the one after that if the range hits it. |
*/ |
/* ++roman: A little bit more care is required here: The CINVP instruction |
* invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning |
* and the end of the region must be treated differently if they are not |
* exactly at the beginning or end of a page boundary. Else, maybe too much |
* data becomes invalidated and thus lost forever. CPUSHP does what we need: |
* it invalidates the page after pushing dirty data to memory. (Thanks to Jes |
* for discovering the problem!) |
*/ |
/* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set |
* the DPI bit in the CACR; would it cause problems with temporarily changing |
* this?). So we have to push first and then additionally to invalidate. |
*/ |
|
/* |
* cache_clear() semantics: Clear any cache entries for the area in question, |
* without writing back dirty entries first. This is useful if the data will |
* be overwritten anyway, e.g. by DMA to memory. The range is defined by a |
* _physical_ address. |
*/ |
|
void cache_clear (unsigned long paddr, int len) |
{ |
} |
|
|
/* |
* cache_push() semantics: Write back any dirty cache data in the given area, |
* and invalidate the range in the instruction cache. It needs not (but may) |
* invalidate those entries also in the data cache. The range is defined by a |
* _physical_ address. |
*/ |
|
void cache_push (unsigned long paddr, int len) |
{ |
} |
|
|
/* |
* cache_push_v() semantics: Write back any dirty cache data in the given |
* area, and invalidate those entries at least in the instruction cache. This |
* is intended to be used after data has been written that can be executed as |
* code later. The range is defined by a _user_mode_ _virtual_ address (or, |
* more exactly, the space is defined by the %sfc/%dfc register.) |
*/ |
|
void cache_push_v (unsigned long vaddr, int len) |
{ |
} |
|
unsigned long mm_phys_to_virt (unsigned long addr) |
{ |
return PTOV (addr); |
} |
|
/* Map some physical address range into the kernel address space. The |
* code is copied and adapted from map_chunk(). |
*/ |
|
unsigned long kernel_map(unsigned long paddr, unsigned long size, |
int nocacheflag, unsigned long *memavailp ) |
{ |
return paddr; |
} |
|
|
void kernel_set_cachemode( unsigned long address, unsigned long size, |
unsigned cmode ) |
{ |
} |
|
unsigned long alloc_kernel_stack() |
{ |
unsigned long rval = __get_free_page(GFP_KERNEL); |
#ifdef DEBUG |
printk("+++ alloc_kernel_stack: 0x%8x\n", rval); |
stack_trace(); |
show_free_areas(); |
#endif |
return rval; |
} |
|
void free_kernel_stack(unsigned long ksp) |
{ |
#ifdef DEBUG |
printk("--- free_kernel_stack: 0x%8x\n", ksp); |
show_free_areas(); |
#endif |
free_page(ksp); |
#ifdef DEBUG |
printk(" page freed\n"); |
show_free_areas(); |
#endif |
} |
|
#ifdef CONFIG_CYVH |
#define ROMA_START 0xfec00000 |
#define ROMB_START 0xfee00000 |
#define ROMA_END ROMB_START |
#define ROMB_END 0xff000000 |
#endif |
|
int is_in_rom(unsigned long addr) |
{ |
#if 0 |
return ((addr >= ROMA_START) && (addr < ROMA_END)) |
|| ((addr >= ROMB_START) && (addr < ROMB_END)); |
#else |
extern int __data_rom_start, __data_rom_end; |
return (addr >= (unsigned long)&__data_rom_start) |
&& (addr < (unsigned long)&__data_rom_end); |
#endif |
} |
|
#endif |
/mm/fault.c
0,0 → 1,57
/* |
* linux/arch/m68knommu/mm/fault.c |
* |
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, |
* The Silver Hammer Group, Ltd. |
* |
* Based on: |
* |
* linux/arch/m68k/mm/fault.c |
* |
* Copyright (C) 1995 Hamish Macdonald |
*/ |
|
#include <linux/mman.h> |
#include <linux/mm.h> |
#include <linux/kernel.h> |
#include <linux/ptrace.h> |
|
#include <asm/system.h> |
#include <asm/pgtable.h> |
|
extern void die_if_kernel(char *, struct pt_regs *, long); |
|
/* |
* This routine handles page faults. It determines the problem, and |
* then passes it off to one of the appropriate routines. |
* |
* error_code: |
* bit 0 == 0 means no page found, 1 means protection fault |
* bit 1 == 0 means read, 1 means write |
* |
* If this routine detects a bad access, it returns 1, otherwise it |
* returns 0. |
*/ |
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, |
unsigned long error_code) |
{ |
#ifdef DEBUG |
printk("page fault!\n"); |
show_regs(regs); |
#endif |
|
/* |
* Oops. The kernel tried to access some bad page. We'll have to |
* terminate things with extreme prejudice. |
*/ |
if ((unsigned long) address < PAGE_SIZE) { |
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); |
} else |
printk(KERN_ALERT "Unable to handle kernel access"); |
printk(" at virtual address %08lx\n",address); |
die_if_kernel("Oops", regs, error_code); |
do_exit(SIGKILL); |
|
return 1; |
} |
|
/mm/Makefile
0,0 → 1,13
# |
# Makefile for the linux m68k-specific parts of the memory manager. |
# |
# Note! Dependencies are done automagically by 'make dep', which also |
# removes any old dependencies. DON'T put your own dependencies here |
# unless it's something special (ie not a .c file). |
# |
# Note 2! The CFLAGS definition is now in the main makefile... |
|
O_TARGET := mm.o |
O_OBJS := init.o fault.o memory.o |
|
include $(TOPDIR)/Rules.make |
/config.in
0,0 → 1,134
# |
# For a description of the syntax of this configuration file, |
# see the Configure script. |
# |
mainmenu_name "uClinux/i960 (w/o MMU) Kernel Configuration" |
|
define_bool CONFIG_UCLINUX y |
define_bool CONFIG_64BIT_MATH n |
|
mainmenu_option next_comment |
comment 'Code maturity level options' |
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL |
endmenu |
|
mainmenu_option next_comment |
comment 'Loadable module support' |
bool 'Enable loadable module support' CONFIG_MODULES |
if [ "$CONFIG_MODULES" = "y" ]; then |
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS |
bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD |
fi |
endmenu |
|
bool 'Prompt for command-line options at boot-time' CONFIG_CMDLINE_PROMPT |
|
mainmenu_option next_comment |
comment 'Platform dependant setup' |
|
choice 'CPU' \ |
"i960Sx CONFIG_I960JX |
i960Kx CONFIG_I960KX |
i960MC CONFIG_I960MC |
i960Cx CONFIG_I960CX |
i960Jx CONFIG_I960JX |
i960Hx CONFIG_I960HX |
i960VH CONFIG_I960VH" i960VH |
|
comment 'Platform' |
|
if [ "$CONFIG_I960VH" = "y" ]; then |
bool ' Cyclone evaluation board with VH processor' CONFIG_CYVH |
if [ "$CONFIG_CYVH" = "y" ];then |
choice ' Installed RAM' \ |
"4MB CONFIG_CYVH_4MB \ |
8MB CONFIG_CYVH_8MB \ |
16MB CONFIG_CYVH_16MB \ |
32MB CONFIG_CYVH_32MB" 4MB |
bool ' Use Mon960 to bootstrap kernel' CONFIG_MON960 |
if [ "$CONFIG_MON960" = "y" ]; then |
bool ' Use Mon960 for a console' CONFIG_MON960_CONSOLE |
fi |
fi |
fi |
|
endmenu |
|
mainmenu_option next_comment |
comment 'General setup' |
|
bool 'Kernel math emulation' CONFIG_MATH_EMULATION |
bool 'Networking support' CONFIG_NET |
bool 'Limit memory to low 16MB' CONFIG_MAX_16M |
if [ "$CONFIG_CYVH" = "y" ];then |
bool 'PCI bios support' CONFIG_PCI |
if [ "$CONFIG_PCI" = "y" ]; then |
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then |
bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE |
fi |
fi |
fi |
bool 'System V IPC' CONFIG_SYSVIPC |
bool 'Reduced memory footprint' CONFIG_REDUCED_MEMORY |
tristate 'Kernel support for flat binaries' CONFIG_BINFMT_FLAT |
|
endmenu |
|
source drivers/block/Config.in |
|
if [ "$CONFIG_NET" = "y" ]; then |
source net/Config.in |
fi |
|
mainmenu_option next_comment |
comment 'SCSI support' |
|
tristate 'SCSI support' CONFIG_SCSI |
|
if [ "$CONFIG_SCSI" != "n" ]; then |
source drivers/scsi/Config.in |
fi |
endmenu |
|
if [ "$CONFIG_NET" = "y" ]; then |
mainmenu_option next_comment |
comment 'Network device support' |
|
bool 'Network device support' CONFIG_NETDEVICES |
if [ "$CONFIG_NETDEVICES" = "y" ]; then |
source drivers/net/Config.in |
fi |
endmenu |
fi |
|
mainmenu_option next_comment |
comment 'ISDN subsystem' |
|
tristate 'ISDN support' CONFIG_ISDN |
if [ "$CONFIG_ISDN" != "n" ]; then |
source drivers/isdn/Config.in |
fi |
endmenu |
|
source fs/Config.in |
|
source drivers/char/Config.in |
|
mainmenu_option next_comment |
comment 'Sound' |
|
tristate 'Sound card support' CONFIG_SOUND |
if [ "$CONFIG_SOUND" != "n" ]; then |
source drivers/sound/Config.in |
fi |
endmenu |
|
mainmenu_option next_comment |
comment 'Kernel hacking' |
|
bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC |
bool 'Kernel IRQ profiling' CONFIG_PROF_IRQ |
if [ "$CONFIG_PROF_IRQ" = "y" ]; then |
int ' Profile shift count CONFIG_PROF_SHIFT 2 |
fi |
endmenu |
/init_cyvh.ld
0,0 → 1,46
#include <linux/config.h> |
/* |
* This is the linker directive file to link an application to run |
* under mon960 on the CY board with a Cx, Jx, or Hx processor. |
* Programs linked with this file are downloaded to DRAM after the |
* data area used by mon960. |
* malloc() uses the symbols _heap_base and _heap_end to manage the heap. |
* _heap_base is located at the end of program memory (.text + .data +.bss). |
* _heap_size is defined as 0x20000. |
* The C runtime stack starts at _heap_end and grows up. |
* There must be enough room after the program memory in the dram for |
* the program's heap and stack. |
*/ |
|
|
MEMORY |
{ |
#ifdef CONFIG_CYVH_4MB |
data: o=0xA3C08000,l=0x7f8000 /* for 4 MB dram on eval board */ |
#endif |
#ifdef CONFIG_CYVH_8MB |
data: o=0xA3808000,l=0xff8000 /* for 8 MB dram on eval board */ |
#endif |
#ifdef CONFIG_CYVH_16MB |
data: o=0xA3008000,l=0x1ff8000 /* for 16 MB dram on eval board */ |
#endif |
#ifdef CONFIG_CYVH_32MB |
data: o=0xA2008000,l=0x3ff8000 /* for 32 MB dram on eval board */ |
#endif |
} |
|
SECTIONS |
{ |
.text : |
{ |
*(.text) |
.=ALIGN(0x10); |
} > data |
.data : |
{ |
} > data |
.bss : |
{ |
} > data |
} |
|
/Makefile
0,0 → 1,76
# |
# i960/Makefile |
# |
# This file is included by the global makefile so that you can add your own |
# architecture-specific flags and dependencies. Remember to do have actions |
# for "archclean" and "archdep" for cleaning up and making dependencies for |
# this architecture |
# |
# This file is subject to the terms and conditions of the GNU General Public |
# License. See the file "COPYING" in the main directory of this archive |
# for more details. |
# |
# Copyright (C) 1999 Keith Adams <kma@cse.ogi.edu>, |
# Erik Walthinsen <omega@cse.ogi.edu>, |
# Oregon Graduate Institute |
# |
# based on uClinux for the m68knommu (pilot/shglcore) by: |
# Copyright (C) 1998,1999 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, |
# Kenneth Albanowski <kjahds@kjahds.com>, |
# The Silver Hammer Group, Ltd. |
# |
# Based on arch/m68k/Makefile: |
# Copyright (C) 1994 by Hamish Macdonald |
# |
|
# test for cross compiling |
COMPILE_ARCH = $(shell uname -m) |
CROSS_COMPILE=y |
XAS =gas960 |
XLD =gld960 |
XCC =gcc960 |
XAR =gar960 |
XNM =gnm960 |
XSTRIP =gstrip960 |
|
# even though i960 is COFF, don't define __COFF__; gcc960 still uses the |
# _ prefixes, so __COFF__ makes linkage.h do the wrong thing |
CFLAGS += -pipe $(DBG_FLAGS) -DNO_MM -DNO_FPU -DNO_FORGET -DUTS_SYSNAME='"uClinux-i960"' -DMAGIC_ROM_PTR -mabi |
AFLAGS += -pipe -DNO_MM -DNO_FPU -DUTS_SYSNAME='"uClinux-i960"' |
|
ifeq ($(CONFIG_CYVH),y) |
LINKFLAGS = -T arch/$(ARCH)/init_cyjx.ld |
endif |
|
ifeq ($(CONFIG_I960VH),y) |
GCC960ARCH=-AJF |
CFLAGS += $(GCC960ARCH) |
AFLAGS += $(GCC960ARCH) |
endif |
|
HEAD := arch/$(ARCH)/kernel/head.o |
|
SUBDIRS=arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/lib |
ARCHIVES=arch/$(ARCH)/kernel/kernel.o arch/$(ARCH)/mm/mm.o |
LIBS=arch/$(ARCH)/lib/lib.a $(LIBGCC) |
|
ifeq ($(CONFIG_ROMFS_FS),y) |
ARCHIVES+=arch/$(ARCH)/romfs/romfs.o |
endif |
|
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot |
|
debug: |
$(MAKE) coff DBG_FLAGS="-DDEBUG" |
|
coff: vmlinux |
cof960 -Fcoff -JS vmlinux |
|
bootstrap: |
@$(MAKEBOOT) bootstrap |
|
archclean: |
@$(MAKEBOOT) clean |
|
archdep: |
$(MAKEBOOT) dep |
/init_cyjx.ld
0,0 → 1,66
/* |
* This is the linker directive file to link an application to run |
* under mon960 on the CY board with a Cx, Jx, or Hx processor. |
* Programs linked with this file are downloaded to DRAM after the |
* data area used by mon960. |
* malloc() uses the symbols _heap_base and _heap_end to manage the heap. |
* _heap_base is located at the end of program memory (.text + .data +.bss). |
* _heap_size is defined as 0x20000. |
* The C runtime stack starts at _heap_end and grows up. |
* There must be enough room after the program memory in the dram for |
* the program's heap and stack. |
*/ |
|
MEMORY |
{ |
dram : org = 0xA3C08000, len = 0x1ff8000 /* 4M less monitor */ |
isram : org = 0x00000100, len = 0x300 |
} |
|
|
SECTIONS |
{ |
.text : |
{ |
} >dram |
|
.data : |
{ |
} >dram |
|
.bss : |
{ |
} >dram |
|
|
/* For R4.0 of the compiler & libraries, the following lines */ |
/* should not be enclosed in comments. */ |
/* |
SFP_AC : |
{ |
fpem_CA_AC = .; |
} >isram |
*/ |
} |
|
/* Bounds of heap: */ |
/* The heap may be placed in a separate memory region, if desired. */ |
|
/* _stackbase marks the base of the kernel's initial stack. We put it way at |
* the top of memory. */ |
__stext = __Btext; |
__etext = __Etext; |
__sdata = __Bdata; |
__edata = __Edata; |
__end = _end; |
_stackbase = 0xa3ff0000; |
|
ENTRY(_main) |
/* Don't use low-level libs anymore */ |
/* |
STARTUP ("crt960*") |
HLL () |
SYSLIB ("libmn*") |
SYSLIB ("libll*") |
*/ |
FLOAT |