URL
https://opencores.org/ocsvn/or1k_old/or1k_old/trunk
Subversion Repositories or1k_old
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k_old/trunk/rc203soc/sw/uClinux/arch/or32/kernel
- from Rev 1765 to Rev 1782
- ↔ Reverse comparison
Rev 1765 → Rev 1782
/time.c
0,0 → 1,161
/* |
* linux/arch/or32/kernel/time.c |
* |
* Copied/hacked from: |
* |
* linux/arch/m68knommu/kernel/time.c |
* |
* Copyright (C) 1991, 1992, 1995 Linus Torvalds |
* |
* This file contains the m68k-specific time handling details. |
* Most of the stuff is located in the machine specific files. |
*/ |
|
#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> |
|
|
static inline int set_rtc_mmss(unsigned long nowtime) |
{ |
if (mach_set_clock_mmss) |
return mach_set_clock_mmss (nowtime); |
return -1; |
} |
|
/* |
* timer_interrupt() needs to keep up the real-time clock, |
* as well as call the "do_timer()" routine every clocktick |
*/ |
/* void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) |
*/ |
void timer_interrupt(struct pt_regs * regs) |
{ |
/* last time the cmos clock got updated */ |
static long last_rtc_update=0; |
|
/* may need to kick the hardware timer */ |
if (mach_tick) |
mach_tick(); |
|
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; |
|
if (mach_sched_init) |
mach_sched_init(timer_interrupt); |
} |
|
/* |
* This version of gettimeofday has near microsecond resolution. |
*/ |
void do_gettimeofday(struct timeval *tv) |
{ |
unsigned long flags; |
|
save_flags(flags); |
cli(); |
*tv = xtime; |
if (mach_gettimeoffset) { |
tv->tv_usec += mach_gettimeoffset(); |
if (tv->tv_usec >= 1000000) { |
tv->tv_usec -= 1000000; |
tv->tv_sec++; |
} |
} |
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 (mach_gettimeoffset) |
tv->tv_usec -= mach_gettimeoffset(); |
|
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(); |
} |
|
/setup.c
0,0 → 1,262
/* |
* linux/arch/or32/kernel/setup.c |
* |
* Based on m86k |
*/ |
|
/* |
* 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/irq.h> |
#include <asm/machdep.h> |
|
#ifdef CONFIG_BLK_DEV_INITRD |
#include <linux/blk.h> |
#include <asm/pgtable.h> |
#endif |
|
extern void register_console(void (*proc)(const char *)); |
#ifdef CONFIG_CONSOLE |
extern struct consw *conswitchp; |
#ifdef CONFIG_FRAMEBUFFER |
extern struct consw fb_con; |
#endif |
#endif |
|
#ifdef CONFIG_BLK_DEV_INITRD |
extern unsigned long _initrd_start; |
extern unsigned long _initrd_end; |
#endif |
|
unsigned long rom_length; |
unsigned long memory_start; |
unsigned long memory_end; |
|
#ifdef CONFIG_CONSOLE |
char command_line[512] = "CONSOLE=/dev/tty MOUSE_TYPE=ps2 MOUSE_PORT=/dev/ttyS0"; |
#else |
char command_line[512] = "CONSOLE=/dev/ttyS0"; |
#endif |
char saved_command_line[512]; |
char console_device[16]; |
|
char console_default[] = "CONSOLE=/dev/tty"; |
|
/* setup some dummy routines */ |
static void dummy_waitbut(void) |
{ |
} |
|
void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) = NULL; |
void (*mach_tick)( void ) = NULL; |
/* machine dependent keyboard functions */ |
int (*mach_keyb_init) (void) = NULL; |
int (*mach_kbdrate) (struct kbd_repeat *) = NULL; |
void (*mach_kbd_leds) (unsigned int) = NULL; |
/* machine dependent irq functions */ |
void (*mach_init_IRQ) (void) = NULL; |
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; |
int (*mach_process_int) (int, struct pt_regs *) = NULL; |
void (*mach_trap_init) (void); |
/* machine dependent timer functions */ |
unsigned long (*mach_gettimeoffset) (void) = NULL; |
void (*mach_gettod) (int*, int*, int*, int*, int*, int*) = NULL; |
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 ) = NULL; |
void (*mach_reset)( void ) = NULL; |
void (*waitbut)(void) = dummy_waitbut; |
void (*mach_debug_init)(void) = NULL; |
|
|
#ifdef CONFIG_OR32 |
#define CPU "OR32" |
#endif |
|
/* |
* Setup the console. There may be a console defined in |
* the command line arguments, so we look there first. If the |
* command line arguments don't exist then we default to the |
* first serial port. If we are going to use a console then |
* setup its device name and the UART for it. |
*/ |
void setup_console(void) |
{ |
char *sp, *cp; |
int i; |
extern void rs_console_init(void); |
extern void rs_console_print(const char *b); |
#ifdef CONFIG_SERIAL |
extern int rs_console_setup(char *arg); |
#endif |
/* Quickly check if any command line arguments for CONSOLE. */ |
for (sp = NULL, i = 0; (i < sizeof(command_line)-8); i++) { |
if (command_line[i] == 0) |
break; |
if (command_line[i] == 'C') { |
if (!strncmp(&command_line[i], "CONSOLE=", 8)) { |
sp = &command_line[i + 8]; |
break; |
} |
} |
} |
|
#if 0 |
/* If no CONSOLE defined then default one */ |
if (sp == NULL) { |
strcpy(command_line, console_default); |
sp = command_line + 8; |
} |
#endif |
|
/* If console specified then copy it into name buffer */ |
for (cp = sp, i = 0; (i < (sizeof(console_device) - 1)); i++) { |
if ((*sp == 0) || (*sp == ' ') || (*sp == ',')) |
break; |
console_device[i] = *sp++; |
} |
console_device[i] = 0; |
|
#ifdef CONFIG_SERIAL |
/* If a serial console then init it */ |
if (rs_console_setup(cp)) { |
rs_console_init(); |
register_console(rs_console_print); |
} |
#endif |
} |
|
#if defined( CONFIG_GEN) && defined( CONFIG_OR32 ) |
#define CAT_ROMARRAY |
#endif |
|
void setup_arch(char **cmdline_p, |
unsigned long * memory_start_p, unsigned long * memory_end_p) |
{ |
extern int _stext, _etext; |
extern int _sdata, _edata; |
extern int _sbss, _ebss, _end; |
extern int _ramstart, _ramend; |
|
#ifdef CAT_ROMARRAY |
extern int __data_rom_start; |
extern int __data_start; |
#endif |
|
memory_start = (unsigned long)&_end; |
memory_end = (unsigned long)&_ramend - 4096; /* <- stack area */ |
config_BSP(&command_line[0], sizeof(command_line)); |
setup_console(); |
printk("\nOpenRisc 1000 support (C) www.opencores.org\n"); |
printk("\r\n\nuClinux/" CPU "\n"); |
printk("Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n"); |
|
#ifdef DEBUG |
printk("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x " |
"BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext, |
(int) &_sdata, (int) &_edata, |
(int) &_sbss, (int) &_ebss); |
printk("KERNEL -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x " |
"STACK=0x%06x-0x%06x\n", |
(int) &_ebss, (int) memory_start, |
(int) memory_start, (int) memory_end, |
(int) memory_end, (int) &_ramend); |
#endif |
|
init_task.mm->start_code = (unsigned long) &_stext; |
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(RAMDISK_MAJOR,0); |
|
/* Keep a copy of command line */ |
*cmdline_p = &command_line[0]; |
|
memcpy(saved_command_line, command_line, sizeof(saved_command_line)); |
saved_command_line[sizeof(saved_command_line)-1] = 0; |
|
#ifdef DEBUG |
if (strlen(*cmdline_p)) |
printk("Command line: '%s'\n", *cmdline_p); |
else |
printk("No Command line passed\n"); |
#endif |
*memory_start_p = memory_start; |
*memory_end_p = memory_end; |
/*rom_length = (unsigned long)&_flashend - (unsigned long)&_romvec;*/ |
|
#ifdef CONFIG_BLK_DEV_INITRD |
initrd_start = (unsigned long)&_initrd_start; |
initrd_end = (unsigned long)&_initrd_end; |
#endif |
|
|
#ifdef CONFIG_CONSOLE |
#ifdef CONFIG_FRAMEBUFFER |
conswitchp = &fb_con; |
#else |
conswitchp = 0; |
#endif |
#endif |
|
#ifdef DEBUG |
printk("Done setup_arch\n"); |
#endif |
|
} |
|
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) |
{ |
if (mach_gettod) |
mach_gettod(year, mon, day, hour, min, sec); |
else |
*year = *mon = *day = *hour = *min = *sec = 0; |
} |
|
/bios32.c
0,0 → 1,201
/*****************************************************************************/ |
|
/* |
* bios32.c -- PCI access code for embedded CO-MEM Lite PCI controller. |
* |
* (C) Copyright 1999-2000, Greg Ungerer (gerg@moreton.com.au). |
*/ |
|
/*****************************************************************************/ |
|
#include <linux/config.h> |
#include <linux/kernel.h> |
#include <linux/types.h> |
#include <linux/bios32.h> |
#include <linux/pci.h> |
#include <asm/anchor.h> |
|
/*****************************************************************************/ |
#ifdef CONFIG_PCI |
/*****************************************************************************/ |
|
unsigned long pcibios_init(unsigned long mem_start, unsigned long mem_end) |
{ |
volatile unsigned long *rp; |
int slot; |
|
#if 0 |
printk("%s(%d): pcibios_init()\n", __FILE__, __LINE__); |
#endif |
|
/* |
* Do some sort of basic check to see if the CO-MEM part |
* is present... |
*/ |
rp = (volatile unsigned long *) COMEM_BASE; |
if ((rp[COMEM_LBUSCFG] & 0xffff) != 0x0b50) { |
printk("PCI: no PCI bus present\n"); |
return(mem_start); |
} |
|
/* |
* Do a quick scan of the PCI bus and see what is here. |
*/ |
for (slot = COMEM_MINIDSEL; (slot <= COMEM_MAXIDSEL); slot++) { |
rp[COMEM_DAHBASE] = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << slot); |
rp[COMEM_PCIBUS] = 0; /* Clear bus */ |
printk("PCI: slot %d --> %08x\n", slot, rp[COMEM_PCIBUS]); |
} |
|
return(mem_start); |
} |
|
/*****************************************************************************/ |
|
unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) |
{ |
return(mem_start); |
} |
|
/*****************************************************************************/ |
|
int pcibios_present(void) |
{ |
return(1); |
} |
|
/*****************************************************************************/ |
|
int pcibios_read_config_dword(unsigned char bus, unsigned char dev, |
unsigned char offset, unsigned int *val) |
{ |
#if 0 |
printk("%s(%d): pcibios_read_config_dword(bus=%x,dev=%x,offset=%x," |
"val=%x)\n", __FILE__, __LINE__, bus, dev, offset, val); |
#endif |
*val = 0xffffffff; |
return(PCIBIOS_SUCCESSFUL); |
} |
|
/*****************************************************************************/ |
|
int pcibios_read_config_word(unsigned char bus, unsigned char dev, |
unsigned char offset, unsigned short *val) |
{ |
#if 0 |
printk("%s(%d): pcibios_read_config_word(bus=%x,dev=%x,offset=%x)\n", |
__FILE__, __LINE__, bus, dev, offset); |
#endif |
*val = 0xffff; |
return(PCIBIOS_SUCCESSFUL); |
} |
|
/*****************************************************************************/ |
|
int pcibios_read_config_byte(unsigned char bus, unsigned char dev, |
unsigned char offset, unsigned char *val) |
{ |
#if 0 |
printk("%s(%d): pcibios_read_config_byte(bus=%x,dev=%x,offset=%x)\n", |
__FILE__, __LINE__, bus, dev, offset); |
#endif |
*val = 0xff; |
return(PCIBIOS_SUCCESSFUL); |
} |
|
/*****************************************************************************/ |
|
int pcibios_write_config_dword(unsigned char bus, unsigned char dev, |
unsigned char offset, unsigned int val) |
{ |
#if 0 |
printk("%s(%d): pcibios_write_config_dword(bus=%x,dev=%x,offset=%x)\n", |
__FILE__, __LINE__, bus, dev, offset); |
#endif |
return(PCIBIOS_SUCCESSFUL); |
} |
|
/*****************************************************************************/ |
|
int pcibios_write_config_word(unsigned char bus, unsigned char dev, |
unsigned char offset, unsigned short val) |
{ |
#if 0 |
printk("%s(%d): pcibios_write_config_word(bus=%x,dev=%x,offset=%x)\n", |
__FILE__, __LINE__, bus, dev, offset); |
#endif |
return(PCIBIOS_SUCCESSFUL); |
} |
|
/*****************************************************************************/ |
|
int pcibios_write_config_byte(unsigned char bus, unsigned char dev, |
unsigned char offset, unsigned char val) |
{ |
#if 0 |
printk("%s(%d): pcibios_write_config_byte(bus=%x,dev=%x,offset=%x)\n", |
__FILE__, __LINE__, bus, dev, offset); |
#endif |
return(PCIBIOS_SUCCESSFUL); |
} |
|
/*****************************************************************************/ |
|
int pcibios_find_device(unsigned short vendor, unsigned short devid, |
unsigned short index, unsigned char *bus, unsigned char *dev) |
{ |
unsigned int vendev, val; |
unsigned char devnr; |
|
#if 0 |
printk("%s(%d): pcibios_find_device(vendor=%04x,devid=%04x," |
"index=%d)\n", __FILE__, __LINE__, vendor, devid, index); |
#endif |
|
if (vendor == 0xffff) |
return(PCIBIOS_BAD_VENDOR_ID); |
|
vendev = (devid << 16) | vendor; |
for (devnr = 0; (devnr < 32); devnr++) { |
pcibios_read_config_dword(0, devnr, PCI_VENDOR_ID, &val); |
if (vendev == val) { |
if (index-- == 0) { |
*bus = 0; |
*dev = devnr; |
return(PCIBIOS_SUCCESSFUL); |
} |
} |
} |
|
return(PCIBIOS_DEVICE_NOT_FOUND); |
} |
|
/*****************************************************************************/ |
|
int pcibios_find_class(unsigned int class, unsigned short index, |
unsigned char *bus, unsigned char *dev) |
{ |
unsigned int val; |
unsigned char devnr; |
|
#if 0 |
printk("%s(%d): pcibios_find_class(class=%04x,index=%d)\n", |
__FILE__, __LINE__, class, index); |
#endif |
|
for (devnr = 0; (devnr < 32); devnr++) { |
pcibios_read_config_dword(0, devnr, PCI_CLASS_REVISION, &val); |
if ((val >> 8) == class) { |
if (index-- == 0) { |
*bus = 0; |
*dev = devnr; |
return(PCIBIOS_SUCCESSFUL); |
} |
} |
} |
|
return(PCIBIOS_DEVICE_NOT_FOUND); |
} |
|
/*****************************************************************************/ |
#endif /* CONFIG_PCI */ |
/console.c
0,0 → 1,2658
|
/* |
* arch/or32/kernel/console.c |
* |
* Copyright (C) 2001,2002 Simon Srot <srot@opencores.org>, |
* www.opencores.org |
* |
* Based on: |
* |
* arch/m68knommu/kernel/console.c |
* |
* |
* linux/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> |
* |
* 680x0 LINUX support by Arno Griffioen (arno@usn.nl) |
* |
* 9-Apr-94: Arno Griffioen: fixed scrolling and delete-char bug. |
* Scrolling code moved to amicon.c |
* |
* 18-Apr-94: David Carter [carter@cs.bris.ac.uk]. 680x0 LINUX modified |
* Integrated support for new low level driver `amicon_ocs.c' |
* |
*/ |
|
#define BLANK 0x0020 |
#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ |
|
/* A bitmap for codes <32. A bit of 1 indicates that the code |
* corresponding to that bit number invokes some special action |
* (such as cursor movement) and should not be displayed as a |
* glyph unless the disp_ctrl mode is explicitly enabled. |
*/ |
#define CTRL_ACTION 0x0d00ff81 |
#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ |
|
/* |
* Here is the default bell parameters: 750HZ, 1/8th of a second |
*/ |
#define DEFAULT_BELL_PITCH 750 |
#define DEFAULT_BELL_DURATION (HZ/8) |
|
/* |
* NOTE!!! We sometimes disable and enable interrupts for a short while |
* (to put a word in video IO), but this will work even for keyboard |
* interrupts. We know interrupts aren't enabled when getting a keyboard |
* interrupt, as we use trap-gates. Hopefully all is well. |
*/ |
|
#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) |
{ |
|
#ifdef CONFIG_FRAMEBUFFER |
|
#if 0 /* Disable console unless some buttons are pressed */ |
{ |
int i; |
for(i=0;i<200000;i++) { |
__asm__("nop"); |
if ((*(volatile unsigned char*)0xFFFFF419) & (8|1)) |
break; |
} |
|
if (!((*(volatile unsigned char*)0xFFFFF419) & (8|1))) |
return; |
} |
} |
#endif |
char *display_desc = "????"; |
unsigned int currcons = 0; |
extern int serial_debug; |
|
memset(&console_driver, 0, sizeof(struct tty_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 = MAX_NR_CONSOLES; |
console_driver.type = TTY_DRIVER_TYPE_CONSOLE; |
console_driver.init_termios = tty_std_termios; |
console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; |
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.write_room = con_write_room; |
console_driver.chars_in_buffer = con_chars_in_buffer; |
console_driver.ioctl = vt_ioctl; |
console_driver.stop = con_stop; |
console_driver.start = con_start; |
console_driver.throttle = con_throttle; |
console_driver.unthrottle = con_unthrottle; |
|
if (tty_register_driver(&console_driver)) |
panic("Couldn't register console driver\n"); |
|
kmem_start = conswitchp->con_startup (kmem_start, &display_desc); |
/*conswitchp->con_set_font (&display_desc, 0, 0, "MINI4x6");*/ |
|
timer_table[BLANK_TIMER].fn = blank_screen; |
timer_table[BLANK_TIMER].expires = 0; |
if (blankinterval) { |
timer_table[BLANK_TIMER].expires = jiffies + blankinterval; |
timer_active |= 1<<BLANK_TIMER; |
} |
|
/* Due to kmalloc roundup allocating statically is more efficient - |
so provide MIN_NR_CONSOLES for people with very little memory */ |
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { |
vc_cons[currcons].d = (struct vc_data *) kmem_start; |
kmem_start += sizeof(struct vc_data); |
vt_cons[currcons] = (struct vt_struct *) kmem_start; |
kmem_start += sizeof(struct vt_struct); |
|
/* ++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; |
|
vc_scrbuf[currcons] = (unsigned short *) kmem_start; |
kmem_start += screenbuf_size; |
kmalloced = 0; |
vc_init(currcons, currcons); |
} |
|
currcons = fg_console = 0; |
|
gotoxy(currcons,0, 0); |
printable = 1; |
sw->con_cursor(vc_cons[currcons].d, CM_DRAW); |
printable = 1; |
|
/* If "serdebug" cmd line option was present, don't register for printk */ |
if (!serial_debug) |
register_console(console_print); |
|
printk("Console driver: %s %s %ldx%ld, %d virtual console%s (max %d)\n", |
can_do_color ? "colour":"mono", |
display_desc, |
cols,rows, |
MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES); |
|
init_bh(CONSOLE_BH, console_bh); |
#endif |
return 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; |
} |
/ksyms.c
0,0 → 1,40
#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/pgtable.h> |
#include <asm/irq.h> |
#include <asm/semaphore.h> |
|
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(request_irq), |
X(free_irq), |
X(dump_fpu), |
X(dump_thread), |
X(strnlen), |
|
/* 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(memcpy), |
|
#include <linux/symtab_end.h> |
}; |
|
void arch_syms_export(void) |
{ |
register_symtab(&arch_symbol_table); |
} |
/mk_defs.c
0,0 → 1,136
/* |
* This program is used to generate definitions needed by |
* assembly language modules. |
*/ |
#define MK_DEFS |
#include <stdio.h> |
|
#include <linux/signal.h> |
#include <linux/sched.h> |
#include <linux/head.h> |
#include <linux/kernel.h> |
#include <linux/errno.h> |
#include <linux/string.h> |
#include <linux/types.h> |
#include <linux/ptrace.h> |
#include <linux/mman.h> |
#include <linux/mm.h> |
|
extern int errno; |
|
main(int argc, char *argv[]) |
{ |
FILE *out; |
struct task_struct task; |
struct thread_struct tss; |
struct pt_regs regs; |
if (!(out = fopen(argv[1], "w"))) |
{ |
fprintf(stderr, "Can't create output file: %s\n", strerror(errno)); |
exit(1); |
} |
fprintf(out, "/*\n"); |
fprintf(out, " * WARNING! This file is automatically generated - DO NOT EDIT!\n"); |
fprintf(out, " */\n"); |
put_line(out, "STATE", (int)&task.state-(int)&task); |
put_line(out, "COUNTER", (int)&task.counter-(int)&task); |
put_line(out, "BLOCKED", (int)&task.blocked-(int)&task); |
put_line(out, "SIGNAL", (int)&task.signal-(int)&task); |
put_line(out, "KERNEL_STACK_PAGE", (int)&task.kernel_stack_page-(int)&task); |
put_line(out, "TSS", (int)&task.tss-(int)&task); |
put_line(out, "KSP", (int)&tss.ksp-(int)&tss); |
put_line(out, "LAST_PC", (int)&tss.last_pc-(int)&tss); |
put_line(out, "USER_STACK", (int)&tss.user_stack-(int)&tss); |
put_line(out, "PT_REGS", (int)&tss.regs-(int)&tss); |
put_line(out, "PF_TRACESYS", PF_TRACESYS); |
put_line(out, "TASK_FLAGS", (int)&task.flags-(int)&task); |
put_line(out, "MMU_SEG0", (int)&tss.segs[0]-(int)&tss); |
put_line(out, "MMU_SEG1", (int)&tss.segs[1]-(int)&tss); |
put_line(out, "MMU_SEG2", (int)&tss.segs[2]-(int)&tss); |
put_line(out, "MMU_SEG3", (int)&tss.segs[3]-(int)&tss); |
put_line(out, "MMU_SEG4", (int)&tss.segs[4]-(int)&tss); |
put_line(out, "MMU_SEG5", (int)&tss.segs[5]-(int)&tss); |
put_line(out, "MMU_SEG6", (int)&tss.segs[6]-(int)&tss); |
put_line(out, "MMU_SEG7", (int)&tss.segs[7]-(int)&tss); |
put_line(out, "MMU_SEG8", (int)&tss.segs[8]-(int)&tss); |
put_line(out, "MMU_SEG9", (int)&tss.segs[9]-(int)&tss); |
put_line(out, "MMU_SEG10", (int)&tss.segs[10]-(int)&tss); |
put_line(out, "MMU_SEG11", (int)&tss.segs[11]-(int)&tss); |
put_line(out, "MMU_SEG12", (int)&tss.segs[12]-(int)&tss); |
put_line(out, "MMU_SEG13", (int)&tss.segs[13]-(int)&tss); |
put_line(out, "MMU_SEG14", (int)&tss.segs[14]-(int)&tss); |
put_line(out, "MMU_SEG15", (int)&tss.segs[15]-(int)&tss); |
put_line(out, "TSS_FPR0", (int)&tss.fpr[0]-(int)&tss); |
put_line(out, "TSS_FPR1", (int)&tss.fpr[1]-(int)&tss); |
put_line(out, "TSS_FPR2", (int)&tss.fpr[2]-(int)&tss); |
put_line(out, "TSS_FPR3", (int)&tss.fpr[3]-(int)&tss); |
put_line(out, "TSS_FPR4", (int)&tss.fpr[4]-(int)&tss); |
put_line(out, "TSS_FPR5", (int)&tss.fpr[5]-(int)&tss); |
put_line(out, "TSS_FPR6", (int)&tss.fpr[6]-(int)&tss); |
put_line(out, "TSS_FPR7", (int)&tss.fpr[7]-(int)&tss); |
put_line(out, "TSS_FPR8", (int)&tss.fpr[8]-(int)&tss); |
put_line(out, "TSS_FPR9", (int)&tss.fpr[9]-(int)&tss); |
put_line(out, "TSS_FPR10", (int)&tss.fpr[10]-(int)&tss); |
put_line(out, "TSS_FPR11", (int)&tss.fpr[11]-(int)&tss); |
put_line(out, "TSS_FPR12", (int)&tss.fpr[12]-(int)&tss); |
put_line(out, "TSS_FPR13", (int)&tss.fpr[13]-(int)&tss); |
put_line(out, "TSS_FPR14", (int)&tss.fpr[14]-(int)&tss); |
put_line(out, "TSS_FPR15", (int)&tss.fpr[15]-(int)&tss); |
put_line(out, "TSS_FPR16", (int)&tss.fpr[16]-(int)&tss); |
put_line(out, "TSS_FPR17", (int)&tss.fpr[17]-(int)&tss); |
put_line(out, "TSS_FPR18", (int)&tss.fpr[18]-(int)&tss); |
put_line(out, "TSS_FPR19", (int)&tss.fpr[19]-(int)&tss); |
put_line(out, "TSS_FPR20", (int)&tss.fpr[20]-(int)&tss); |
put_line(out, "TSS_FPR21", (int)&tss.fpr[21]-(int)&tss); |
put_line(out, "TSS_FPR22", (int)&tss.fpr[22]-(int)&tss); |
put_line(out, "TSS_FPR23", (int)&tss.fpr[23]-(int)&tss); |
put_line(out, "TSS_FPR24", (int)&tss.fpr[24]-(int)&tss); |
put_line(out, "TSS_FPR25", (int)&tss.fpr[25]-(int)&tss); |
put_line(out, "TSS_FPR26", (int)&tss.fpr[26]-(int)&tss); |
put_line(out, "TSS_FPR27", (int)&tss.fpr[27]-(int)&tss); |
put_line(out, "TSS_FPR28", (int)&tss.fpr[28]-(int)&tss); |
put_line(out, "TSS_FPR29", (int)&tss.fpr[29]-(int)&tss); |
put_line(out, "TSS_FPR30", (int)&tss.fpr[30]-(int)&tss); |
put_line(out, "TSS_FPR31", (int)&tss.fpr[31]-(int)&tss); |
/* Interrupt register frame */ |
put_line(out, "INT_FRAME_SIZE", sizeof(regs)); |
put_line(out, "SP", (int)®s.sp-(int)®s); |
put_line(out, "PC", (int)®s.pc-(int)®s); |
put_line(out, "GPR2", (int)®s.gprs[0]-(int)®s); |
put_line(out, "GPR3", (int)®s.gprs[1]-(int)®s); |
put_line(out, "GPR4", (int)®s.gprs[2]-(int)®s); |
put_line(out, "GPR5", (int)®s.gprs[3]-(int)®s); |
put_line(out, "GPR6", (int)®s.gprs[4]-(int)®s); |
put_line(out, "GPR7", (int)®s.gprs[5]-(int)®s); |
put_line(out, "GPR8", (int)®s.gprs[6]-(int)®s); |
put_line(out, "GPR9", (int)®s.gprs[7]-(int)®s); |
put_line(out, "GPR10", (int)®s.gprs[8]-(int)®s); |
put_line(out, "GPR11", (int)®s.gprs[9]-(int)®s); |
put_line(out, "GPR12", (int)®s.gprs[10]-(int)®s); |
put_line(out, "GPR13", (int)®s.gprs[11]-(int)®s); |
put_line(out, "GPR14", (int)®s.gprs[12]-(int)®s); |
put_line(out, "GPR15", (int)®s.gprs[13]-(int)®s); |
put_line(out, "GPR16", (int)®s.gprs[14]-(int)®s); |
put_line(out, "GPR17", (int)®s.gprs[15]-(int)®s); |
put_line(out, "GPR18", (int)®s.gprs[16]-(int)®s); |
put_line(out, "GPR19", (int)®s.gprs[17]-(int)®s); |
put_line(out, "GPR20", (int)®s.gprs[18]-(int)®s); |
put_line(out, "GPR21", (int)®s.gprs[19]-(int)®s); |
put_line(out, "GPR22", (int)®s.gprs[20]-(int)®s); |
put_line(out, "GPR23", (int)®s.gprs[21]-(int)®s); |
put_line(out, "GPR24", (int)®s.gprs[22]-(int)®s); |
put_line(out, "GPR25", (int)®s.gprs[23]-(int)®s); |
put_line(out, "GPR26", (int)®s.gprs[24]-(int)®s); |
put_line(out, "GPR27", (int)®s.gprs[25]-(int)®s); |
put_line(out, "GPR28", (int)®s.gprs[26]-(int)®s); |
put_line(out, "GPR29", (int)®s.gprs[27]-(int)®s); |
put_line(out, "GPR30", (int)®s.gprs[28]-(int)®s); |
put_line(out, "GPR31", (int)®s.gprs[29]-(int)®s); |
put_line(out, "SR", (int)®s.sr-(int)®s); |
exit(0); |
} |
|
put_line(FILE *out, char *name, int offset) |
{ |
fprintf(out, "#define %s %d\n", name, offset); |
} |
/misc.S
0,0 → 1,278
#include <asm/spr_defs.h> |
#include <asm/board.h> |
|
.text |
/* |
* Enable interrupts |
* sti() |
*/ |
.global _sti |
_sti: |
l.mfspr r3,r0,SPR_SR |
l.ori r3,r3,(SPR_SR_IEE | SPR_SR_TEE) |
l.mtspr r0,r3,SPR_SR |
l.jr r9 |
l.nop |
|
/* |
* Disable interrupts |
* cli() |
*/ |
.global _cli |
_cli: |
l.addi r4,r0,-1 |
l.xori r4,r4,(SPR_SR_IEE | SPR_SR_TEE) |
l.mfspr r3,r0,SPR_SR |
l.and r3,r3,r4 |
l.mtspr r0,r3,SPR_SR |
l.jr r9 |
l.nop |
|
/* |
* Get 'flags' (aka status register) |
* __save_flags(long *ptr) |
*/ |
.global ___save_flags |
___save_flags: |
l.mfspr r4,r0,SPR_SR |
l.sw 0(r3),r4 |
l.jr r9 |
l.nop |
|
/* |
* Restore 'flags' |
* __restore_flags(long val) |
*/ |
.global ___restore_flags |
___restore_flags: |
l.mtspr r0,r3,SPR_SR |
l.jr r9 |
l.nop |
|
/* |
* SPR write |
* mtspr(long add, long val) |
*/ |
.global _mtspr |
_mtspr: |
l.mtspr r3,r4,0 |
l.jr r9 |
l.nop |
|
/* |
* SPR read |
* mtspr(long add) |
*/ |
.global _mfspr |
_mfspr: |
l.mfspr r11,r3,0 |
l.jr r9 |
l.nop |
|
/* |
* Instruction cache enable |
* ic_enable() |
*/ |
.global _ic_enable |
_ic_enable: |
/* Disable IC */ |
l.mfspr r13,r0,SPR_SR |
l.addi r11,r0,-1 |
l.xori r11,r11,SPR_SR_ICE |
l.and r11,r13,r11 |
l.mtspr r0,r11,SPR_SR |
|
/* Invalidate IC */ |
l.addi r13,r0,0 |
l.addi r11,r0,IC_SIZE |
1: |
l.mtspr r0,r13,SPR_ICBIR |
l.sfne r13,r11 |
l.bf 1b |
l.addi r13,r13,IC_LINE |
|
/* Enable IC */ |
l.mfspr r13,r0,SPR_SR |
l.ori r13,r13,SPR_SR_ICE |
l.mtspr r0,r13,SPR_SR |
l.nop |
l.nop |
l.nop |
l.nop |
l.nop |
|
l.jr r9 |
l.nop |
|
/* |
* Instruction cache disable |
* ic_disable() |
*/ |
.global _ic_disable |
_ic_disable: |
/* Disable IC */ |
l.mfspr r13,r0,SPR_SR |
l.addi r11,r0,-1 |
l.xori r11,r11,SPR_SR_ICE |
l.and r11,r13,r11 |
l.mtspr r0,r11,SPR_SR |
|
l.jr r9 |
l.nop |
|
/* |
* Instruction cache invalidate |
* ic_flush() |
*/ |
.global _ic_invalidate |
_ic_invalidate: |
/* Disable IC */ |
l.mfspr r13,r0,SPR_SR |
l.addi r11,r0,-1 |
l.xori r11,r11,SPR_SR_ICE |
l.and r11,r13,r11 |
l.mtspr r0,r11,SPR_SR |
|
/* Invalidate IC */ |
l.addi r13,r0,0 |
l.addi r11,r0,IC_SIZE |
1: |
l.mtspr r0,r13,SPR_ICBIR |
l.sfne r13,r11 |
l.bf 1b |
l.addi r13,r13,IC_LINE |
|
/* Enable IC */ |
l.mfspr r13,r0,SPR_SR |
l.ori r13,r13,SPR_SR_ICE |
l.mtspr r0,r13,SPR_SR |
l.nop |
l.nop |
l.nop |
l.nop |
l.nop |
|
l.jr r9 |
l.nop |
|
/* |
* Data cache enable |
* dc_enable() |
*/ |
.global _dc_enable |
_dc_enable: |
/* Disable DC */ |
l.mfspr r13,r0,SPR_SR |
l.addi r11,r0,-1 |
l.xori r11,r11,SPR_SR_DCE |
l.and r11,r13,r11 |
l.mtspr r0,r11,SPR_SR |
|
/* Flush DC */ |
l.addi r13,r0,0 |
l.addi r11,r0,DC_SIZE |
1: |
l.mtspr r0,r13,SPR_DCBIR |
l.sfne r13,r11 |
l.bf 1b |
l.addi r13,r13,DC_LINE |
|
/* Enable DC */ |
l.mfspr r13,r0,SPR_SR |
l.ori r13,r13,SPR_SR_DCE |
l.mtspr r0,r13,SPR_SR |
|
l.jr r9 |
l.nop |
|
/* |
* Data cache disable |
* dc_disable() |
*/ |
.global _dc_disable |
_dc_disable: |
/* Disable DC */ |
l.mfspr r13,r0,SPR_SR |
l.addi r11,r0,-1 |
l.xori r11,r11,SPR_SR_DCE |
l.and r11,r13,r11 |
l.mtspr r0,r11,SPR_SR |
|
l.jr r9 |
l.nop |
|
/* |
* Invalidate data cache line |
* dc_line_invalidate(long ph_add) |
*/ |
.global _dc_line_invalidate |
_dc_line_invalidate: |
l.mfspr r4,r0,SPR_SR |
l.addi r5,r0,-1 |
l.xori r5,r5,SPR_SR_DCE |
l.and r5,r4,r5 |
l.mtspr r0,r5,SPR_SR |
l.mtspr r0,r3,SPR_DCBIR |
l.mtspr r0,r4,SPR_SR |
l.jr r9 |
l.nop |
|
/* |
* Data MMU enable |
* dmmu_enable() |
*/ |
.global _dmmu_enable |
_dmmu_enable: |
/* Invalidate all sets */ |
l.addi r11,r0,DMMU_SET_NB |
l.addi r13,r0,0 |
1: |
l.mtspr r13,r0,SPR_DTLBMR_BASE(0) |
l.addi r11,r11,-1 |
l.sfeqi r11,0 |
l.bnf 1b |
l.addi r13,r13,1 |
l.mfspr r11,r0,SPR_SR |
l.ori r11,r11,SPR_SR_DME |
l.mtspr r0,r11,SPR_SR |
l.jr r9 |
l.nop |
|
/* |
* Instruction MMU enable |
* immu_enable() |
*/ |
.global _immu_enable |
_immu_enable: |
/* Invalidate all sets */ |
l.addi r11,r0,IMMU_SET_NB |
l.addi r13,r0,0 |
1: |
l.mtspr r13,r0,SPR_ITLBMR_BASE(0) |
l.addi r11,r11,-1 |
l.sfeqi r11,0 |
l.bnf 1b |
l.addi r13,r13,1 |
l.mfspr r11,r0,SPR_SR |
l.ori r11,r11,SPR_SR_IME |
l.mtspr r0,r11,SPR_SR |
l.nop |
l.nop |
l.nop |
l.nop |
l.jr r9 |
l.nop |
|
/* |
* Print utility |
* __print(const char *fmt, ...) |
*/ |
.global __print |
__print: |
l.lwz r3,0(r1) |
l.addi r4,r1,4 |
# l.sys 202 |
l.nop 3 |
l.jr r9 |
l.nop |
|
/signal.c
0,0 → 1,262
/* |
* linux/arch/ppc/kernel/signal.c |
* |
* Copyright (C) 1991, 1992 Linus Torvalds |
* Adapted for PowerPC by Gary Thomas |
*/ |
|
#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/segment.h> |
#include <asm/pgtable.h> |
#include <asm/traps.h> |
|
/* |
#define DEBUG |
*/ |
|
#define offsetof(type, member) ((size_t)(&((type *)0)->member)) |
|
#define _S(nr) (1<<((nr)-1)) |
|
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) |
|
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); |
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); |
|
/* |
* atomically swap in the new signal mask, and wait for a signal. |
*/ |
asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs) |
{ |
unsigned long mask; |
|
mask = current->blocked; |
current->blocked = set & _BLOCKABLE; |
regs->gprs[1] = -EINTR; |
#if 0 |
printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, |
set); |
#endif |
while (1) { |
current->state = TASK_INTERRUPTIBLE; |
schedule(); |
if (do_signal(mask,regs)) |
return -EINTR; |
} |
} |
|
/* |
* This sets regs->esp even though we don't actually use sigstacks yet.. |
*/ |
asmlinkage int sys_sigreturn(struct pt_regs *regs) |
{ |
struct sigcontext_struct *sc; |
struct pt_regs *int_regs; |
int signo; |
sc = (struct sigcontext_struct *)regs->sp; |
current->blocked = sc->oldmask & _BLOCKABLE; |
int_regs = sc->regs; |
signo = sc->signal; |
sc++; /* Pop signal 'context' */ |
if (sc == (struct sigcontext_struct *)(int_regs)) |
{ /* Last stacked signal */ |
int i; |
#if 1 |
memcpy(regs, int_regs, sizeof(*regs)); |
#else |
/* Don't mess up 'my' stack frame */ |
for(i = 0; i < 30; i++) |
if(i != 7) |
regs->gprs[i] = int_regs->gprs[i]; |
regs->sp = int_regs->sp; |
#endif |
if ((int)regs->orig_gpr3 >= 0 && |
((int)regs->result == -ERESTARTNOHAND || |
(int)regs->result == -ERESTARTSYS || |
(int)regs->result == -ERESTARTNOINTR)) |
{ |
regs->gprs[1] = regs->orig_gpr3; |
regs->pc -= 8; /* Back up & retry system call */ |
regs->result = 0; |
} |
return (regs->result); |
} else |
{ /* More signals to go */ |
regs->sp = (unsigned long)sc; |
regs->gprs[1] = sc->signal; /* r3 */ |
regs->gprs[2] = (unsigned long)sc->regs; /* r4 */ |
regs->gprs[7] = (unsigned long)((sc->regs)+1); /* r9 - link register */ |
regs->pc = sc->handler; |
return (sc->signal); |
} |
} |
|
/* |
* 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. |
*/ |
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) |
{ |
unsigned long mask = ~current->blocked; |
unsigned long handler_signal = 0; |
unsigned long *frame = NULL; |
unsigned long *trampoline; |
unsigned long *regs_ptr; |
unsigned long nip = 0; |
unsigned long signr; |
int bitno; |
struct sigcontext_struct *sc; |
struct sigaction * sa; |
unsigned long flags; |
|
save_flags(flags); |
cli(); |
|
while ((signr = current->signal & mask)) { |
#if 0 |
signr = ffz(~signr); /* Compute bit # */ |
#else |
for (bitno = 0; bitno < 32; bitno++) |
{ |
if (signr & (1<<bitno)) break; |
} |
signr = bitno; |
#endif |
current->signal &= ~(1<<signr); /* Clear bit */ |
sa = current->sig->action + signr; |
signr++; |
if ((current->flags & PF_PTRACED) && signr != SIGKILL) { |
current->exit_code = signr; |
current->state = TASK_STOPPED; |
notify_parent(current, SIGCHLD); |
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; |
/* check for SIGCHLD: it's special */ |
while (sys_waitpid(-1,NULL,WNOHANG) > 0) |
/* nothing */; |
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, SIGCHLD); |
schedule(); |
continue; |
|
case SIGQUIT: case SIGILL: case SIGTRAP: |
case SIGIOT: case SIGFPE: case SIGSEGV: |
if (current->binfmt && current->binfmt->core_dump) { |
if (current->binfmt->core_dump(signr, regs)) |
signr |= 0x80; |
} |
/* fall through */ |
default: |
current->signal |= _S(signr & 0x7f); |
do_exit(signr); |
} |
} |
/* |
* OK, we're invoking a handler |
*/ |
if ((int)regs->orig_gpr3 >= 0) { |
if ((int)regs->result == -ERESTARTNOHAND || |
((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART))) |
(int)regs->result = -EINTR; |
} |
handler_signal |= 1 << (signr-1); |
mask &= ~sa->sa_mask; |
} |
if (!handler_signal) /* no handler will be called - return 0 */ |
{ |
restore_flags(flags); |
return 0; |
} |
nip = regs->pc; |
frame = (unsigned long *) regs->sp; |
/* Build trampoline code on stack */ |
frame -= 3; |
trampoline = frame; |
trampoline[0] = 0x9d607777; /* l.addi r11,r0,0x7777 */ |
trampoline[1] = 0x20000001; /* l.sys 1 */ |
trampoline[2] = 0x15000000; /* l.nop 0 */ |
frame -= sizeof(*regs) / sizeof(long); |
regs_ptr = frame; |
memcpy(regs_ptr, regs, sizeof(*regs)); |
signr = 1; |
sa = current->sig->action; |
for (mask = 1 ; mask ; sa++,signr++,mask += mask) { |
if (mask > handler_signal) |
break; |
if (!(mask & handler_signal)) |
continue; |
frame -= sizeof(struct sigcontext_struct) / sizeof(long); |
sc = (struct sigcontext_struct *)frame; |
nip = (unsigned long) sa->sa_handler; |
#if 0 /* Old compiler */ |
nip = *(unsigned long *)nip; |
#endif |
if (sa->sa_flags & SA_ONESHOT) |
sa->sa_handler = NULL; |
sc->handler = nip; |
sc->oldmask = current->blocked; |
sc->regs = (struct pt_regs *)regs_ptr; |
sc->signal = signr; |
current->blocked |= sa->sa_mask; |
regs->gprs[1] = signr; /* r3 = signr */ |
regs->gprs[2] = (unsigned long)regs_ptr; /* r4 = regs_ptr */ |
} |
regs->gprs[7] = (unsigned long)trampoline; /* r9 = trampoline (r9 is link register) */ |
regs->pc = nip; |
regs->sp = (unsigned long)sc; |
/* The DATA cache must be flushed here to insure coherency */ |
/* between the DATA & INSTRUCTION caches. Since we just */ |
/* created an instruction stream using the DATA [cache] space */ |
/* and since the instruction cache will not look in the DATA */ |
/* cache for new data, we have to force the data to go on to */ |
/* memory and flush the instruction cache to force it to look */ |
/* there. The following function performs this magic */ |
#if ICACHE |
ic_invalidate(); |
#endif |
restore_flags(flags); |
return 1; |
} |
/process.c
0,0 → 1,189
/* |
* This file handles the architecture-dependent parts of process handling.. |
* Based on m86k. |
*/ |
|
#include <linux/config.h> |
#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/board.h> |
|
asmlinkage void ret_from_exception(void); |
|
/* |
* The idle loop on an or32.. |
*/ |
asmlinkage int sys_idle(void) |
{ |
if (current->pid != 0) |
return -EPERM; |
|
|
/* endless idle loop with no priority at all */ |
current->counter = -100; |
for (;;) { |
schedule(); |
} |
} |
|
void hard_reset_now(void) |
{ |
HARD_RESET_NOW(); |
} |
|
void show_regs(struct pt_regs * regs) |
{ |
printk("\n"); |
printk("PC: %08lx Status: %08lx\n", |
regs->pc, regs->sr); |
printk("R0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
0L, regs->sp, regs->gprs[0], regs->gprs[1], |
regs->gprs[2], regs->gprs[3], regs->gprs[4], regs->gprs[5]); |
printk("R8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
regs->gprs[6], regs->gprs[7], regs->gprs[8], regs->gprs[9], |
regs->gprs[10], regs->gprs[11], regs->gprs[12], regs->gprs[13]); |
printk("R16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
regs->gprs[14], regs->gprs[15], regs->gprs[16], regs->gprs[17], |
regs->gprs[18], regs->gprs[19], regs->gprs[20], regs->gprs[21]); |
printk("R24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
regs->gprs[22], regs->gprs[23], regs->gprs[24], regs->gprs[25], |
regs->gprs[26], regs->gprs[27], regs->gprs[28], regs->gprs[29]); |
} |
|
/* |
* Free current thread data structures etc.. |
*/ |
void exit_thread(void) |
{ |
} |
|
void flush_thread(void) |
{ |
set_fs(USER_DS); |
current->tss.fs = USER_DS; |
} |
|
asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, struct pt_regs *regs) |
{ |
return do_fork(SIGCHLD|CLONE_WAIT, regs->sp, regs); |
} |
|
asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, struct pt_regs *regs) |
{ |
unsigned long clone_flags = (unsigned long)p1; |
return do_fork(clone_flags, regs->sp, regs); |
} |
|
void release_thread(struct task_struct *dead_task) |
{ |
} |
|
void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, |
struct task_struct * p, struct pt_regs * regs) |
{ |
struct pt_regs * childregs; |
|
/* Copy registers */ |
childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; |
*childregs = *regs; /* STRUCT COPY */ |
childregs->gprs[9] = 0x0; /* Result from fork() */ |
p->tss.ksp = childregs; |
|
/* If this is kernel thread, than we can use kernel stack also as |
"user" stack, if not, we use user stack from parent which should be a sleep |
till we execute execve or exit (that is why sys_fork has CLONE_WAIT |
flag allway set ) */ |
if(regs->sr & SPR_SR_SM) { |
childregs->sp = (unsigned long)(childregs+1); |
p->tss.usp = (unsigned long)(childregs+1); |
} |
else { |
childregs->sp = usp; |
p->tss.usp = usp; |
} |
} |
|
/* Fill in the fpu structure for a core dump. */ |
|
int dump_fpu (struct pt_regs *regs, struct user_or32fp_struct *fpu) |
{ |
return 0; |
} |
|
void switch_to(struct task_struct *prev, struct task_struct *new) |
{ |
struct pt_regs *regs; |
struct thread_struct *new_tss, *old_tss; |
long flags; |
|
save_flags(flags); |
cli(); |
|
regs = (struct pt_regs *)new->tss.ksp; |
new_tss = &new->tss; |
old_tss = ¤t->tss; |
current_set[0] = new; /* FIX ME! */ |
_switch(old_tss, new_tss); |
restore_flags(flags); |
} |
|
/* |
* fill in the user structure for a core dump.. |
*/ |
void dump_thread(struct pt_regs * regs, struct user * dump) |
{ |
/* changed the size calculations - should hopefully work better. lbt */ |
dump->magic = CMAGIC; |
dump->start_code = 0; |
dump->start_stack = regs->sp & ~(PAGE_SIZE - 1); |
dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; |
dump->u_dsize = ((unsigned long) (current->mm->brk + |
(PAGE_SIZE-1))) >> PAGE_SHIFT; |
dump->u_dsize -= dump->u_tsize; |
dump->u_ssize = 0; |
|
|
dump->u_ar0 = (struct pt_regs *)(((int)(&dump->regs)) -((int)(dump))); |
dump->regs = *regs; |
/* dump floating point stuff */ |
dump->u_fpvalid = dump_fpu (regs, &dump->or32fp); |
} |
|
/* |
* sys_execve() executes a new program. |
*/ |
asmlinkage int sys_execve(char *name, char **argv, char **envp, |
int dummy1, int dummy2, unsigned long sp) |
{ |
int error; |
char * filename; |
struct pt_regs *regs = (struct pt_regs *) sp; |
|
_print("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__); |
error = getname(name, &filename); |
_print("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__); |
if (error) |
return error; |
_print("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__); |
error = do_execve(filename, argv, envp, regs); |
_print("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__); |
putname(filename); |
#if ICACHE |
ic_invalidate(); |
#endif |
_print("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__); |
return error; |
} |
/ptrace.c
0,0 → 1,356
/* |
* linux/arch/m68knommu/kernel/ptrace.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/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. |
*/ |
|
#include <stddef.h> |
#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> |
|
/* |
* does not yet catch signals sent when the child dies. |
* in exit.c or in signal.c. |
*/ |
|
/* determines which bits in the SR the user has access to. */ |
/* 1 = access 0 = no access */ |
#define SR_MASK 0x001f |
|
/* sets the trace bits. */ |
#define TRACE_BITS 0x8000 |
|
/* Mapping from PT_xxx to the stack offset at which the register is |
saved. Notice that usp has no stack-slot and needs to be treated |
specially (see get_reg/put_reg below). */ |
static int regoff[] = {0,0,0,0,0,0}; |
|
/* 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) |
{ |
unsigned long *addr; |
/* SIMON */ |
#if 0 |
if (regno == PT_USP) |
addr = &task->tss.usp; |
else if (regno < sizeof(regoff)/sizeof(regoff[0])) |
addr = (unsigned long *)(task->tss.esp0 + regoff[regno]); |
else |
return 0; |
#endif |
return *addr; |
} |
|
/* |
* Write contents of register REGNO in task TASK. |
*/ |
static inline int put_reg(struct task_struct *task, int regno, |
unsigned long data) |
{ |
/* SIMON */ |
#if 0 |
unsigned long *addr; |
if (regno == PT_USP) |
addr = &task->tss.usp; |
else if (regno < sizeof(regoff)/sizeof(regoff[0])) |
addr = (unsigned long *) (task->tss.esp0 + regoff[regno]); |
else |
return -1; |
*addr = data; |
#endif |
return 0; |
} |
|
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) |
{ |
/* SIMON */ |
#if 0 |
struct task_struct *child; |
struct user * dummy; |
dummy = NULL; |
|
if (request == PTRACE_TRACEME) { |
/* are we already being traced? */ |
if (current->flags & PF_PTRACED) |
return -EPERM; |
/* set the ptrace bit in the process flags. */ |
current->flags |= PF_PTRACED; |
return 0; |
} |
if (pid == 1) /* you may not mess with init */ |
return -EPERM; |
if (!(child = get_task(pid))) |
return -ESRCH; |
if (request == PTRACE_ATTACH) { |
if (child == current) |
return -EPERM; |
if ((!child->dumpable || |
(current->uid != child->euid) || |
(current->uid != child->suid) || |
(current->uid != child->uid) || |
(current->gid != child->egid) || |
(current->gid != child->sgid) || |
(current->gid != child->gid)) && !suser()) |
return -EPERM; |
/* the same process cannot be attached many times */ |
if (child->flags & PF_PTRACED) |
return -EPERM; |
child->flags |= PF_PTRACED; |
if (child->p_pptr != current) { |
REMOVE_LINKS(child); |
child->p_pptr = current; |
SET_LINKS(child); |
} |
send_sig(SIGSTOP, child, 1); |
return 0; |
} |
if (!(child->flags & PF_PTRACED)) |
return -ESRCH; |
if (child->state != TASK_STOPPED) { |
if (request != PTRACE_KILL) |
return -ESRCH; |
} |
if (child->p_pptr != current) |
return -ESRCH; |
|
switch (request) { |
/* when I and D space are separate, these will need to be fixed. */ |
case PTRACE_PEEKTEXT: /* read word at location addr. */ |
case PTRACE_PEEKDATA: { |
unsigned long tmp; |
int res; |
|
res = read_long(child, addr, &tmp); |
if (res < 0) |
return res; |
res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); |
if (!res) |
put_user(tmp, (unsigned long *) data); |
return res; |
} |
|
/* read the word at location addr in the USER area. */ |
case PTRACE_PEEKUSR: { |
unsigned long tmp; |
int res; |
|
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) |
return -EIO; |
|
res = verify_area(VERIFY_WRITE, (void *) data, |
sizeof(long)); |
if (res) |
return res; |
tmp = 0; /* Default return condition */ |
addr = addr >> 2; /* temporary hack. */ |
if (addr < 19) { |
tmp = get_reg(child, addr); |
if (addr == PT_SR) |
tmp >>= 16; |
} |
else if (addr >= 21 && addr < 49) |
tmp = child->tss.fp[addr - 21]; |
else if (addr == 49) |
tmp = child->mm->start_code; |
else if (addr == 50) |
tmp = child->mm->start_data; |
else |
return -EIO; |
put_user(tmp,(unsigned long *) data); |
return 0; |
} |
|
/* when I and D space are separate, this will have to be fixed. */ |
case PTRACE_POKETEXT: /* write the word at location addr. */ |
case PTRACE_POKEDATA: |
return write_long(child,addr,data); |
|
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ |
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) |
return -EIO; |
|
addr = addr >> 2; /* temporary hack. */ |
|
if (addr == PT_ORIG_D0) |
return -EIO; |
if (addr == PT_SR) { |
data &= SR_MASK; |
data <<= 16; |
data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); |
} |
if (addr < 19) { |
if (put_reg(child, addr, data)) |
return -EIO; |
return 0; |
} |
if (addr >= 21 && addr < 48) |
{ |
child->tss.fp[addr - 21] = data; |
return 0; |
} |
return -EIO; |
|
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ |
case PTRACE_CONT: { /* restart after signal. */ |
long tmp; |
|
if ((unsigned long) data >= NSIG) |
return -EIO; |
if (request == PTRACE_SYSCALL) |
child->flags |= PF_TRACESYS; |
else |
child->flags &= ~PF_TRACESYS; |
child->exit_code = data; |
wake_up_process(child); |
/* make sure the single step bit is not set. */ |
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); |
put_reg(child, PT_SR, tmp); |
return 0; |
} |
|
/* |
* make the child exit. Best I can do is send it a sigkill. |
* perhaps it should be put in the status that it wants to |
* exit. |
*/ |
case PTRACE_KILL: { |
long tmp; |
|
if (child->state == TASK_ZOMBIE) /* already dead */ |
return 0; |
wake_up_process(child); |
child->exit_code = SIGKILL; |
/* make sure the single step bit is not set. */ |
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); |
put_reg(child, PT_SR, tmp); |
return 0; |
} |
|
case PTRACE_SINGLESTEP: { /* set the trap flag. */ |
long tmp; |
|
if ((unsigned long) data >= NSIG) |
return -EIO; |
child->flags &= ~PF_TRACESYS; |
tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); |
put_reg(child, PT_SR, tmp); |
|
wake_up_process(child); |
child->exit_code = data; |
/* give it a chance to run. */ |
return 0; |
} |
|
case PTRACE_DETACH: { /* detach a process that was attached. */ |
long tmp; |
|
if ((unsigned long) data >= NSIG) |
return -EIO; |
child->flags &= ~(PF_PTRACED|PF_TRACESYS); |
wake_up_process(child); |
child->exit_code = data; |
REMOVE_LINKS(child); |
child->p_pptr = child->p_opptr; |
SET_LINKS(child); |
/* make sure the single step bit is not set. */ |
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); |
put_reg(child, PT_SR, tmp); |
return 0; |
} |
|
default: |
return -EIO; |
} |
#endif |
return 0; |
} |
|
asmlinkage void syscall_trace(void) |
{ |
if ((current->flags & (PF_PTRACED|PF_TRACESYS)) |
!= (PF_PTRACED|PF_TRACESYS)) |
return; |
current->exit_code = SIGTRAP; |
current->state = TASK_STOPPED; |
notify_parent(current, SIGCHLD); |
schedule(); |
/* |
* this isn't the same as continuing with a signal, but it will do |
* for normal use. strace only continues with a signal if the |
* stopping signal is not SIGTRAP. -brl |
*/ |
if (current->exit_code) |
current->signal |= (1 << (current->exit_code - 1)); |
current->exit_code = 0; |
return; |
} |
/entry.S
0,0 → 1,368
|
#include <linux/sys.h> |
#include <linux/config.h> |
#include <linux/linkage.h> |
#include <asm/segment.h> |
|
LENOSYS = 38 |
|
/* |
* these are offsets into the task-struct |
*/ |
LTASK_STATE = 0 |
LTASK_COUNTER = 4 |
LTASK_PRIORITY = 8 |
LTASK_SIGNAL = 12 |
LTASK_BLOCKED = 16 |
LTASK_FLAGS = 20 |
|
/* the following macro is used when enabling interrupts */ |
#define ALLOWINT 0xf8ff |
#define MAX_NOINT_IPL 0 |
|
LD0 = 0x1C |
LORIG_D0 = 0x20 |
LSR = 0x28 |
LFORMATVEC = 0x2E |
|
/* |
* This defines the normal kernel pt-regs layout. |
* |
* regs are a2-a6 and d6-d7 preserved by C code |
* the kernel doesn't mess with usp unless it needs to |
*/ |
#define SAVE_ALL \ |
clrl %sp@-; /* stk_adj */ \ |
movel %d0,%sp@-; /* orig d0 */ \ |
movel %d0,%sp@-; /* d0 */ \ |
moveml %d1-%d5/%a0-%a1,%sp@- |
|
/* moveml %sp@+,%a0-%a1/%d1-%d5; */ |
|
#define RESTORE_ALL \ |
moveml %sp@+,%d1-%d5/%a0-%a1; \ |
movel %sp@+,%d0; \ |
addql #4,%sp; /* orig d0 */ \ |
addl %sp@+,%sp; /* stk adj */ \ |
rte |
|
#define SWITCH_STACK_SIZE (7*4+4) /* includes return address */ |
|
#define SAVE_SWITCH_STACK \ |
moveml %a2-%a6/%d6-%d7,%sp@- |
|
#define RESTORE_SWITCH_STACK \ |
moveml %sp@+,%a2-%a6/%d6-%d7 |
|
.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap) |
.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception) |
.globl SYMBOL_NAME(ret_from_signal) |
.globl SYMBOL_NAME(trap3) |
.globl SYMBOL_NAME(trap4) |
.globl SYMBOL_NAME(trap5) |
.globl SYMBOL_NAME(inthandler1) |
.globl SYMBOL_NAME(inthandler1) |
.globl SYMBOL_NAME(inthandler1) |
.globl SYMBOL_NAME(inthandler2) |
.globl SYMBOL_NAME(inthandler3) |
.globl SYMBOL_NAME(inthandler4) |
.globl SYMBOL_NAME(inthandler5) |
.globl SYMBOL_NAME(inthandler6) |
.globl SYMBOL_NAME(inthandler7) |
.globl SYMBOL_NAME(inthandler8) |
.globl SYMBOL_NAME(inthandler) |
.globl SYMBOL_NAME(inthandler_wrap) |
.globl SYMBOL_NAME(timerhandler) |
.globl SYMBOL_NAME(serialhandler) |
.globl SYMBOL_NAME(sys_call_table) |
.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone) |
.globl SYMBOL_NAME(ret_from_interrupt), SYMBOL_NAME(bad_interrupt) |
|
|
.text |
ENTRY(buserr) |
|
ENTRY(trap) |
|
ENTRY(trap3) |
|
ENTRY(trap4) |
|
ENTRY(trap5) |
|
ENTRY(trap6) |
|
ENTRY(trap7) |
|
ENTRY(trap8) |
|
ENTRY(trap9) |
|
ENTRY(trap10) |
|
ENTRY(trap11) |
|
ENTRY(trap12) |
|
ENTRY(trap13) |
|
ENTRY(trap14) |
|
ENTRY(trap15) |
|
ENTRY(trap33) |
|
ENTRY(trap34) |
|
ENTRY(trap35) |
|
ENTRY(trap36) |
|
ENTRY(trap37) |
|
ENTRY(trap38) |
|
ENTRY(trap39) |
|
ENTRY(trap40) |
|
ENTRY(trap41) |
|
ENTRY(trap42) |
|
ENTRY(trap43) |
|
ENTRY(trap44) |
|
ENTRY(trap45) |
|
|
SYMBOL_NAME_LABEL(timerhandler) |
|
|
SYMBOL_NAME_LABEL(serialhandler) |
|
|
SYMBOL_NAME_LABEL(inthandler1) |
|
|
SYMBOL_NAME_LABEL(inthandler2) |
|
|
SYMBOL_NAME_LABEL(inthandler3) |
|
|
SYMBOL_NAME_LABEL(inthandler4) |
|
|
SYMBOL_NAME_LABEL(inthandler5) |
|
|
SYMBOL_NAME_LABEL(inthandler6) |
|
|
SYMBOL_NAME_LABEL(inthandler7) |
|
|
SYMBOL_NAME_LABEL(inthandler8) |
|
|
SYMBOL_NAME_LABEL(inthandler_wrap) |
|
|
SYMBOL_NAME_LABEL(inthandler) |
|
|
SYMBOL_NAME_LABEL(ret_from_interrupt) |
|
|
SYMBOL_NAME_LABEL(bad_interrupt) |
|
|
SYMBOL_NAME_LABEL(resume) |
|
|
.text |
ALIGN |
SYMBOL_NAME_LABEL(sys_call_table) |
.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(sys_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(sys_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(old_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(old_readdir) |
.long SYMBOL_NAME(old_mmap) /* 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(sys_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) |
.space (NR_syscalls-163)*4 |
|
ENTRY(trap46) |
|
ENTRY(trap47) |
|
ENTRY(reschedule) |
|
ENTRY(system_call) |
|
SYMBOL_NAME_LABEL(ret_from_signal) |
|
SYMBOL_NAME_LABEL(ret_from_exception) |
|
Lsignal_return: |
|
|
/head.S
0,0 → 1,1080
#include <asm/spr_defs.h> |
#include <asm/ptrace.h> |
#include <asm/board.h> |
#include <asm/mc.h> |
#include <linux/errno.h> |
|
#define RAM 0 |
#define TEMP_R_LOC 0x00000010 |
|
.global __text_start |
.global __main |
.global ___bss_start |
.global __bss_end |
.global __ram_start |
.global __ram_end |
.global __rom_start |
.global __rom_end |
.global ___data_start |
.global __data_end |
.global ___data_rom_start |
|
.global splash_bits |
.global __start |
.global __stext |
|
.global __switch |
.global _putc |
|
#define SAVE_REGS(mark) \ |
l.addi r1,r1,-(INT_FRAME_SIZE); \ |
l.mfspr r3,r0,SPR_EPCR_BASE; \ |
l.sw PC(r1),r3; \ |
l.mfspr r3,r0,SPR_ESR_BASE; \ |
l.sw SR(r1),r3; \ |
l.lwz r3,(TEMP_R_LOC + 4)(r0); /* Read r1 (sp) from tmp location */ \ |
l.sw SP(r1),r3; \ |
l.sw GPR2(r1),r2; \ |
l.sw GPR4(r1),r4; \ |
l.sw GPR5(r1),r5; \ |
l.sw GPR6(r1),r6; \ |
l.sw GPR7(r1),r7; \ |
l.sw GPR8(r1),r8; \ |
l.sw GPR9(r1),r9; \ |
l.sw GPR10(r1),r10; \ |
l.sw GPR11(r1),r11; \ |
l.sw GPR12(r1),r12; \ |
l.sw GPR13(r1),r13; \ |
l.sw GPR14(r1),r14; \ |
l.sw GPR15(r1),r15; \ |
l.sw GPR16(r1),r16; \ |
l.sw GPR17(r1),r17; \ |
l.sw GPR18(r1),r18; \ |
l.sw GPR19(r1),r19; \ |
l.sw GPR20(r1),r20; \ |
l.sw GPR21(r1),r21; \ |
l.sw GPR22(r1),r22; \ |
l.sw GPR23(r1),r23; \ |
l.sw GPR24(r1),r24; \ |
l.sw GPR25(r1),r25; \ |
l.sw GPR26(r1),r26; \ |
l.sw GPR27(r1),r27; \ |
l.sw GPR28(r1),r28; \ |
l.sw GPR29(r1),r29; \ |
l.sw GPR30(r1),r30; \ |
l.sw GPR31(r1),r31; \ |
l.lwz r3,(TEMP_R_LOC + 0)(r0); /* Read r3 from tmp location */ \ |
l.sw GPR3(r1),r3; \ |
l.sw ORIG_GPR3(r1),r3; \ |
l.sw RESULT(r1),r0 |
|
#define SAVE_INT_REGS(mark) \ |
l.sw (TEMP_R_LOC + 4)(r0),r1; /* Temporary store r1 to add 4!!! */ \ |
l.mfspr r3,r0,SPR_SR; \ |
l.addi r1,r0,-1; \ |
l.xori r1,r1,(SPR_SR_IEE | SPR_SR_TEE); \ |
l.and r3,r3,r1; \ |
l.mtspr r0,r3,SPR_SR; \ |
l.lwz r1,(TEMP_R_LOC + 4)(r0); \ |
l.mfspr r3,r0,SPR_ESR_BASE; /* Interrupt from user/system mode */ \ |
l.andi r3,r3,SPR_SR_SM; \ |
l.sfeqi r3,SPR_SR_SM; \ |
l.bf 10f; /* SIMON */ /* Branch if SUPV */ \ |
l.nop; \ |
l.movhi r3,hi(_current_set); \ |
l.ori r3,r3,lo(_current_set); \ |
l.lwz r3,0(r3); \ |
l.sw TSS+TSS_USP(r3),r1; \ |
l.mfspr r1,r0,SPR_EPCR_BASE; \ |
l.sw TSS+TSS_PC(r3),r1; \ |
l.lwz r1,TSS+TSS_KSP(r3); \ |
l.addi r1,r1,-(INT_FRAME_SIZE); \ |
l.sw TSS+TSS_REGS(r3),r1; \ |
l.lwz r1,TSS+TSS_KSP(r3); \ |
10: SAVE_REGS(mark) |
|
#define RETURN_FROM_INT(mark) \ |
90: l.addi r4,r0,-1; /* Disable interrupts */ \ |
l.xori r4,r4,(SPR_SR_IEE | SPR_SR_TEE); \ |
l.mfspr r3,r0,SPR_SR; \ |
l.and r3,r3,r4; \ |
l.mtspr r0,r3,SPR_SR; \ |
l.movhi r2,hi(_intr_count); \ |
l.ori r2,r2,lo(_intr_count); \ |
l.lwz r3,0(r2); \ |
l.sfeqi r3,0; \ |
l.bnf 00f; \ |
l.nop; \ |
l.movhi r4,hi(_bh_mask); \ |
l.ori r4,r4,lo(_bh_mask); \ |
l.lwz r4,0(r4); \ |
l.movhi r5,hi(_bh_active); \ |
l.ori r5,r5,lo(_bh_active); \ |
l.lwz r5,0(r5); \ |
l.and r4,r4,r5; \ |
l.sfeqi r4,0; \ |
l.bf 00f; \ |
l.nop; \ |
l.addi r3,r3,1; \ |
l.sw 0(r2),r3; \ |
l.jal _do_bottom_half; \ |
l.nop; \ |
l.movhi r2,hi(_intr_count); \ |
l.ori r2,r2,lo(_intr_count); \ |
l.lwz r3,0(r2); \ |
l.addi r3,r3,-1; \ |
l.sw 0(r2),r3; \ |
00: l.lwz r2,SR(r1); \ |
l.andi r3,r2,SPR_SR_SM; \ |
l.sfeqi r3,0; \ |
l.bnf 10f; /* SIMON */ /* Branch if SUPV */ \ |
l.nop; \ |
l.andi r3,r2,SPR_SR_ICE; \ |
l.sfeqi r3,0; \ |
l.bf 05f; /* Branch if IC disabled */ \ |
l.nop; \ |
l.jal _ic_invalidate; \ |
l.nop; \ |
05: l.movhi r3,hi(_current_set); /* need to save kernel stack pointer */ \ |
l.ori r3,r3,lo(_current_set); \ |
l.lwz r3,0(r3); \ |
l.addi r4,r1,INT_FRAME_SIZE; \ |
l.sw TSS+TSS_KSP(r3),r4; \ |
l.lwz r4,STATE(r3); /* If state != 0, can't run */ \ |
l.sfeqi r4,0; \ |
l.bf 06f; \ |
l.nop; \ |
l.jal _schedule; \ |
l.nop; \ |
l.j 90b; \ |
l.nop; \ |
06: l.lwz r4,COUNTER(r3); \ |
l.sfeqi r4,0; \ |
l.bnf 07f; \ |
l.nop; \ |
l.jal _schedule; \ |
l.nop; \ |
l.j 90b; \ |
l.nop; \ |
07: l.addi r5,r0,-1; \ |
l.lwz r4,BLOCKED(r3); /* Check for pending unblocked signals */ \ |
l.xor r4,r4,r5; \ |
l.lwz r5,SIGNAL(r3); \ |
l.and r5,r5,r4; \ |
l.sfeqi r5,0; \ |
l.bf 10f; \ |
l.nop; \ |
l.addi r3,r4,0; \ |
l.addi r4,r1,0; \ |
l.jal _do_signal; \ |
l.nop; \ |
10: l.lwz r3,PC(r1); \ |
l.movhi r4,0x2; \ |
l.ori r4,r4,0x6034;\ |
l.sfeq r3,r4;\ |
l.bnf 20f; \ |
l.nop; \ |
l.lwz r10,GPR10(r1); \ |
l.sfeqi r10,0; \ |
l.bnf 20f; \ |
l.nop; \ |
l.lwz r4,SR(r1); \ |
l.andi r4,r4,SPR_SR_F;\ |
l.sfeqi r4,0x00; \ |
l.bf 20f; \ |
l.nop; \ |
l.j _fail; \ |
l.nop; \ |
20: l.mtspr r0,r3,SPR_EPCR_BASE; \ |
l.lwz r3,SR(r1); \ |
l.mtspr r0,r3,SPR_ESR_BASE; \ |
l.lwz r2,GPR2(r1); \ |
l.lwz r3,GPR3(r1); \ |
l.lwz r4,GPR4(r1); \ |
l.lwz r5,GPR5(r1); \ |
l.lwz r6,GPR6(r1); \ |
l.lwz r7,GPR7(r1); \ |
l.lwz r8,GPR8(r1); \ |
l.lwz r9,GPR9(r1); \ |
l.lwz r10,GPR10(r1); \ |
l.lwz r11,GPR11(r1); \ |
l.lwz r12,GPR12(r1); \ |
l.lwz r13,GPR13(r1); \ |
l.lwz r14,GPR14(r1); \ |
l.lwz r15,GPR15(r1); \ |
l.lwz r16,GPR16(r1); \ |
l.lwz r17,GPR17(r1); \ |
l.lwz r18,GPR18(r1); \ |
l.lwz r19,GPR19(r1); \ |
l.lwz r20,GPR20(r1); \ |
l.lwz r21,GPR21(r1); \ |
l.lwz r22,GPR22(r1); \ |
l.lwz r23,GPR23(r1); \ |
l.lwz r24,GPR24(r1); \ |
l.lwz r25,GPR25(r1); \ |
l.lwz r26,GPR26(r1); \ |
l.lwz r27,GPR27(r1); \ |
l.lwz r28,GPR28(r1); \ |
l.lwz r29,GPR29(r1); \ |
l.lwz r30,GPR30(r1); \ |
l.lwz r31,GPR31(r1); \ |
l.addi r1,r1,0; \ |
l.lwz r1,SP(r1); \ |
l.rfe; \ |
l.nop |
|
.section .bss |
sys_stack: |
.space 4*4096 |
sys_stack_top: |
#if CONFIG_ROMKERNEL |
.section .romvec, "ax", |
.org 0x100 |
|
l.movhi r3,hi(MC_BASE_ADD) |
l.ori r3,r3,MC_BA_MASK |
l.addi r5,r0,0x00 |
l.sw 0(r3),r5 |
|
l.movhi r3,hi(__start) |
l.ori r3,r3,lo(__start) |
l.jr r3 |
l.nop |
|
.org 0x200 |
|
l.nop |
l.rfe |
l.nop |
|
.org 0x300 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_dpfault) |
l.ori r3,r3,lo(_dpfault) |
l.jr r3 |
l.nop |
|
.org 0x400 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_ipfault) |
l.ori r3,r3,lo(_ipfault) |
l.jr r3 |
l.nop |
|
.org 0x500 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_tick) |
l.ori r3,r3,lo(_tick) |
l.jr r3 |
l.nop |
|
.org 0x600 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_align) |
l.ori r3,r3,lo(_align) |
l.jr r3 |
l.nop |
|
.org 0x800 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_ext_int) |
l.ori r3,r3,lo(_ext_int) |
l.jr r3 |
l.nop |
|
.org 0x900 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_dtlbmiss) |
l.ori r3,r3,lo(_dtlbmiss) |
l.jr r3 |
l.nop |
|
.org 0xa00 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_itlbmiss) |
l.ori r3,r3,lo(_itlbmiss) |
l.jr r3 |
l.nop |
|
.org 0xb00 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_sys_call) |
l.ori r3,r3,lo(_sys_call) |
l.jr r3 |
l.nop |
|
.org 0xc00 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_sys_call) |
l.ori r3,r3,lo(_sys_call) |
l.jr r3 |
l.nop |
#endif |
.section .ramvec, "ax" |
.org 0x100 |
|
l.movhi r3,hi(__start) |
l.ori r3,r3,lo(__start) |
l.jr r3 |
l.nop |
|
.org 0x200 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_trap_200) |
l.ori r3,r3,lo(_trap_200) |
l.jr r3 |
l.nop |
|
.org 0x300 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_trap_300) |
l.ori r3,r3,lo(_trap_300) |
l.jr r3 |
l.nop |
|
.org 0x400 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_trap_400) |
l.ori r3,r3,lo(_trap_400) |
l.jr r3 |
l.nop |
|
.org 0x500 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_tick) |
l.ori r3,r3,lo(_tick) |
l.jr r3 |
l.nop |
|
.org 0x600 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_align) |
l.ori r3,r3,lo(_align) |
l.jr r3 |
l.nop |
|
.org 0x700 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_trap_700) |
l.ori r3,r3,lo(_trap_700) |
l.jr r3 |
l.nop |
|
.org 0x800 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_ext_int) |
l.ori r3,r3,lo(_ext_int) |
l.jr r3 |
l.nop |
|
.org 0x900 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_trap_900) |
l.ori r3,r3,lo(_trap_900) |
l.jr r3 |
l.nop |
|
.org 0xa00 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_trap_a00) |
l.ori r3,r3,lo(_trap_a00) |
l.jr r3 |
l.nop |
|
.org 0xb00 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_trap_b00) |
l.ori r3,r3,lo(_trap_b00) |
l.jr r3 |
l.nop |
|
.org 0xc00 |
|
l.sw (TEMP_R_LOC + 0)(r0),r3; /* Temporary store r3 to add 0!!! */ \ |
l.movhi r3,hi(_sys_call) |
l.ori r3,r3,lo(_sys_call) |
l.jr r3 |
l.nop |
|
|
.text |
__start: |
__stext: |
l.addi r3,r0,SPR_SR_SM |
l.mtspr r0,r3,SPR_SR |
#if 1 |
|
/* Init uart */ |
l.jal _ua_init |
l.nop |
|
/* Jump to flash original location */ |
l.movhi r3,hi(__flsh_start) |
l.ori r3,r3,lo(__flsh_start) |
l.jr r3 |
l.nop |
|
__flsh_start: |
|
#if CONFIG_ROMKERNEL |
#if MC_INIT |
l.movhi r3,hi(MC_BASE_ADD) |
l.ori r3,r3,lo(MC_BASE_ADD) |
|
l.addi r4,r3,MC_CSC(0) |
l.movhi r5,hi(FLASH_BASE_ADD) |
l.srai r5,r5,6 |
l.ori r5,r5,0x0025 |
l.sw 0(r4),r5 |
|
l.addi r4,r3,MC_TMS(0) |
l.movhi r5,hi(FLASH_TMS_VAL) |
l.ori r5,r5,lo(FLASH_TMS_VAL) |
l.sw 0(r4),r5 |
|
l.addi r4,r3,MC_BA_MASK |
l.addi r5,r0,MC_MASK_VAL |
l.sw 0(r4),r5 |
|
l.addi r4,r3,MC_CSR |
l.movhi r5,hi(MC_CSR_VAL) |
l.ori r5,r5,lo(MC_CSR_VAL) |
l.sw 0(r4),r5 |
|
l.addi r4,r3,MC_TMS(1) |
l.movhi r5,hi(SDRAM_TMS_VAL) |
l.ori r5,r5,lo(SDRAM_TMS_VAL) |
l.sw 0(r4),r5 |
|
l.addi r4,r3,MC_CSC(1) |
l.movhi r5,hi(SDRAM_BASE_ADD) |
l.srai r5,r5,6 |
l.ori r5,r5,0x0411 |
l.sw 0(r4),r5 |
|
#ifdef FBMEM_BASE_ADD |
l.addi r4,r3,MC_CSC(2) |
l.movhi r5,hi(FBMEM_BASE_ADD) |
l.srai r5,r5,6 |
l.ori r5,r5,0x0005 |
l.sw 0(r4),r5 |
|
l.addi r4,r3,MC_TMS(2) |
l.movhi r5,0xffff |
l.ori r5,r5,0xffff |
l.sw 0(r4),r5 |
#endif |
#endif |
#endif |
#endif |
|
#if ICACHE |
l.jal _ic_enable |
l.nop |
#endif |
|
#if DCACHE |
l.jal _dc_enable |
l.nop |
#endif |
|
l.movhi r1, hi(sys_stack_top) /* stack setup */ |
l.ori r1,r1,lo(sys_stack_top) |
|
#if CONFIG_ROMKERNEL |
/* Copy data segment from ROM to RAM */ |
l.movhi r3, hi(___data_rom_start) |
l.ori r3,r3,lo(___data_rom_start) |
|
l.movhi r4, hi(___data_start) |
l.ori r4,r4,lo(___data_start) |
|
l.movhi r5, hi(__data_end) |
l.ori r5,r5,lo(__data_end) |
|
/* Copy %r3 to %r4 until %r4 == %r5 */ |
1: |
l.sfeq r3,r4 |
l.bf 3f |
l.nop |
2: |
l.sfgeu r4,r5 |
l.bf 1f |
l.nop |
l.lwz r8,0(r3) |
l.sw 0(r4),r8 |
l.addi r3,r3,4 |
l.j 2b |
l.addi r4,r4,4 |
|
/* Copy ramvec segment from ROM to RAM */ |
1: |
l.movhi r4, hi(__ramvec_start) |
l.ori r4,r4,lo(__ramvec_start) |
|
l.movhi r5, hi(__ramvec_end) |
l.ori r5,r5,lo(__ramvec_end) |
|
/* Copy %r3 to %r4 until %r4 == %r5 */ |
2: |
l.sfgeu r4,r5 |
l.bf 1f |
l.nop |
l.lwz r8,0(r3) |
l.sw 0(r4),r8 |
l.addi r3,r3,4 |
l.j 2b |
l.addi r4,r4,4 |
#if 0 |
/* Copy initrd segment from ROM to RAM */ |
1: |
l.movhi r4, hi(__initrd_start) |
l.ori r4,r4,lo(__initrd_start) |
|
l.movhi r5, hi(__initrd_end) |
l.ori r5,r5,lo(__initrd_end) |
|
/* Copy %r3 to %r4 until %r4 == %r5 */ |
2: |
l.sfgeu r4,r5 |
l.bf 1f |
l.nop |
l.lwz r8,0(r3) |
l.sw 0(r4),r8 |
l.addi r3,r3,4 |
l.j 2b |
l.addi r4,r4,4 |
#endif |
#endif |
1: |
3: |
l.movhi r3, hi(___bss_start) |
l.ori r3,r3,lo(___bss_start) |
|
l.movhi r4, hi(end) |
l.ori r4,r4,lo(end) |
|
/* Copy 0 to %r3 until %r3 == %r4 */ |
1: |
l.sfgeu r3,r4 |
l.bf 1f |
l.nop |
l.sw 0(r3),r0 |
l.j 1b |
l.addi r3,r3,4 |
1: |
|
#if IMMU |
l.jal _immu_enable |
l.nop |
#endif |
|
#if DMMU |
l.jal _dmmu_enable |
l.nop |
#endif |
|
l.j _start_kernel |
l.nop |
|
_exit: |
l.j _exit |
l.nop |
|
_dpfault: |
|
|
_ipfault: |
|
_tick: |
SAVE_INT_REGS(0x0500) |
l.lwz r3,0(r1) |
l.movhi r4,0x2 |
l.ori r4,r4,0x6034 |
l.sfeq r3,r4 |
l.bnf 1f |
l.nop |
l.sfeqi r10,0x00 |
l.bnf 1f |
l.nop |
l.lwz r3,0xc(r0) |
l.addi r3,r3,1 |
l.sw 0xc(r0),r3 |
l.lwz r3,4(r1) |
l.andi r3,r3,SPR_SR_F |
l.sfeqi r3,0x00 |
l.bnf _fail |
l.nop |
1: |
l.addi r3,r1,0 |
l.jal _timer_interrupt |
l.nop |
|
RETURN_FROM_INT(0x500) |
|
_fail: |
l.j _fail |
l.nop |
|
_align: |
l.addi r1,r1,-128 |
l.sw 0x08(r1),r2 |
l.lwz r3,(TEMP_R_LOC + 0)(r0) |
l.sw 0x0c(r1),r3 |
l.sw 0x10(r1),r4 |
l.sw 0x14(r1),r5 |
l.sw 0x18(r1),r6 |
l.sw 0x1c(r1),r7 |
l.sw 0x20(r1),r8 |
l.sw 0x24(r1),r9 |
l.sw 0x28(r1),r10 |
l.sw 0x2c(r1),r11 |
l.sw 0x30(r1),r12 |
l.sw 0x34(r1),r13 |
l.sw 0x38(r1),r14 |
l.sw 0x3c(r1),r15 |
l.sw 0x40(r1),r16 |
l.sw 0x44(r1),r17 |
l.sw 0x48(r1),r18 |
l.sw 0x4c(r1),r19 |
l.sw 0x50(r1),r20 |
l.sw 0x54(r1),r21 |
l.sw 0x58(r1),r22 |
l.sw 0x5c(r1),r23 |
l.sw 0x60(r1),r24 |
l.sw 0x64(r1),r25 |
l.sw 0x68(r1),r26 |
l.sw 0x6c(r1),r27 |
l.sw 0x70(r1),r28 |
l.sw 0x74(r1),r29 |
l.sw 0x78(r1),r30 |
l.sw 0x7c(r1),r31 |
|
l.mfspr r2,r0,SPR_EEAR_BASE /* Load the efective addres */ |
l.mfspr r5,r0,SPR_EPCR_BASE /* Load the insn address */ |
|
l.lwz r3,0(r5) /* Load insn */ |
l.srli r4,r3,26 /* Shift left to get the insn opcode */ |
|
l.sfeqi r4,0x00 /* Check if the load/store insn is in delay slot */ |
l.bf jmp |
l.sfeqi r4,0x01 |
l.bf jmp |
l.sfeqi r4,0x03 |
l.bf jmp |
l.sfeqi r4,0x04 |
l.bf jmp |
l.sfeqi r4,0x11 |
l.bf jr |
l.sfeqi r4,0x12 |
l.bf jr |
l.nop |
l.j 1f |
l.addi r5,r5,4 /* Increment PC to get return insn address */ |
|
jmp: |
l.slli r4,r3,6 /* Get the signed extended jump length */ |
l.srai r4,r4,4 |
|
l.lwz r3,4(r5) /* Load the real load/store insn */ |
|
l.add r5,r5,r4 /* Calculate jump target address */ |
|
l.j 1f |
l.srli r4,r3,26 /* Shift left to get the insn opcode */ |
|
jr: |
l.slli r4,r3,9 /* Shift to get the reg nb */ |
l.andi r4,r4,0x7c |
|
l.lwz r3,4(r5) /* Load the real load/store insn */ |
|
l.add r4,r4,r1 /* Load the jump register value from the stack */ |
l.lwz r5,0(r4) |
|
l.srli r4,r3,26 /* Shift left to get the insn opcode */ |
|
|
1: l.mtspr r0,r5,SPR_EPCR_BASE |
|
l.sfeqi r4,0x26 |
l.bf lhs |
l.sfeqi r4,0x25 |
l.bf lhz |
l.sfeqi r4,0x22 |
l.bf lws |
l.sfeqi r4,0x21 |
l.bf lwz |
l.sfeqi r4,0x37 |
l.bf sh |
l.sfeqi r4,0x35 |
l.bf sw |
l.nop |
|
1: l.j 1b /* I don't know what to do */ |
l.nop |
|
lhs: l.lbs r5,0(r2) |
l.slli r5,r5,8 |
l.lbz r6,1(r2) |
l.or r5,r5,r6 |
l.srli r4,r3,19 |
l.andi r4,r4,0x7c |
l.add r4,r4,r1 |
l.j align_end |
l.sw 0(r4),r5 |
|
lhz: l.lbz r5,0(r2) |
l.slli r5,r5,8 |
l.lbz r6,1(r2) |
l.or r5,r5,r6 |
l.srli r4,r3,19 |
l.andi r4,r4,0x7c |
l.add r4,r4,r1 |
l.j align_end |
l.sw 0(r4),r5 |
|
lws: l.lbs r5,0(r2) |
l.slli r5,r5,24 |
l.lbz r6,1(r2) |
l.slli r6,r6,16 |
l.or r5,r5,r6 |
l.lbz r6,2(r2) |
l.slli r6,r6,8 |
l.or r5,r5,r6 |
l.lbz r6,3(r2) |
l.or r5,r5,r6 |
l.srli r4,r3,19 |
l.andi r4,r4,0x7c |
l.add r4,r4,r1 |
l.j align_end |
l.sw 0(r4),r5 |
|
lwz: l.lbz r5,0(r2) |
l.slli r5,r5,24 |
l.lbz r6,1(r2) |
l.slli r6,r6,16 |
l.or r5,r5,r6 |
l.lbz r6,2(r2) |
l.slli r6,r6,8 |
l.or r5,r5,r6 |
l.lbz r6,3(r2) |
l.or r5,r5,r6 |
l.srli r4,r3,19 |
l.andi r4,r4,0x7c |
l.add r4,r4,r1 |
l.j align_end |
l.sw 0(r4),r5 |
|
sh: |
l.srli r4,r3,9 |
l.andi r4,r4,0x7c |
l.add r4,r4,r1 |
l.lwz r5,0(r4) |
l.sb 1(r2),r5 |
l.srli r5,r5,8 |
l.j align_end |
l.sb 0(r2),r5 |
|
sw: |
l.srli r4,r3,9 |
l.andi r4,r4,0x7c |
l.add r4,r4,r1 |
l.lwz r5,0(r4) |
l.sb 3(r2),r5 |
l.srli r5,r5,8 |
l.sb 2(r2),r5 |
l.srli r5,r5,8 |
l.sb 1(r2),r5 |
l.srli r5,r5,8 |
l.j align_end |
l.sb 0(r2),r5 |
|
align_end: |
l.lwz r2,0x08(r1) |
l.lwz r3,0x0c(r1) |
l.lwz r4,0x10(r1) |
l.lwz r5,0x14(r1) |
l.lwz r6,0x18(r1) |
l.lwz r7,0x1c(r1) |
l.lwz r8,0x20(r1) |
l.lwz r9,0x24(r1) |
l.lwz r10,0x28(r1) |
l.lwz r11,0x2c(r1) |
l.lwz r12,0x30(r1) |
l.lwz r13,0x34(r1) |
l.lwz r14,0x38(r1) |
l.lwz r15,0x3c(r1) |
l.lwz r16,0x40(r1) |
l.lwz r17,0x44(r1) |
l.lwz r18,0x48(r1) |
l.lwz r19,0x4c(r1) |
l.lwz r20,0x50(r1) |
l.lwz r21,0x54(r1) |
l.lwz r22,0x58(r1) |
l.lwz r23,0x5c(r1) |
l.lwz r24,0x60(r1) |
l.lwz r25,0x64(r1) |
l.lwz r26,0x68(r1) |
l.lwz r27,0x6c(r1) |
l.lwz r28,0x70(r1) |
l.lwz r29,0x74(r1) |
l.lwz r30,0x78(r1) |
l.lwz r31,0x7c(r1) |
l.addi r1,r1,128 |
l.rfe |
|
|
_ext_int: |
SAVE_INT_REGS(0x0800) |
l.lwz r3,0(r1) |
l.movhi r4,0x2 |
l.ori r4,r4,0x6034 |
l.sfeq r3,r4 |
l.bnf 1f |
l.nop |
l.lwz r3,0xc(r0) |
l.addi r3,r3,1 |
l.sw 0xc(r0),r3 |
l.sfeqi r10,0x00 |
l.bf _fail |
l.nop |
1: |
l.addi r3,r1,0 |
l.jal _handle_IRQ |
l.nop |
RETURN_FROM_INT(0x800) |
|
_dtlbmiss: |
l.sw (TEMP_R_LOC + 4)(r0),r4 |
l.sw (TEMP_R_LOC + 8)(r0),r5 |
l.mfspr r3,r0,SPR_EEAR_BASE |
l.srli r4,r3,DMMU_PAGE_ADD_BITS |
l.andi r4,r4,DMMU_SET_ADD_MASK |
l.addi r5,r0,-1 |
l.xori r5,r5,DMMU_PAGE_ADD_MASK |
l.and r5,r3,r5 |
l.ori r5,r5,SPR_DTLBMR_V |
l.mtspr r4,r5,SPR_DTLBMR_BASE(0) |
l.movhi r5,hi(SPR_DTLBTR_PPN) |
l.ori r5,r5,lo(SPR_DTLBTR_PPN) |
l.and r5,r3,r5 |
l.ori r5,r5,DTLBTR_NO_LIMIT |
l.movhi r3,0x8000 |
l.sfgeu r5,r3 |
l.bnf 1f |
l.nop |
l.ori r5,r5,SPR_DTLBTR_CI |
1: l.mtspr r4,r5,SPR_DTLBTR_BASE(0) |
l.lwz r3,(TEMP_R_LOC + 0)(r0) |
l.lwz r4,(TEMP_R_LOC + 4)(r0) |
l.lwz r5,(TEMP_R_LOC + 8)(r0) |
l.rfe |
l.nop |
|
|
_itlbmiss: |
l.sw (TEMP_R_LOC + 4)(r0),r4 |
l.sw (TEMP_R_LOC + 8)(r0),r5 |
l.mfspr r3,r0,SPR_EEAR_BASE |
l.srli r4,r3,IMMU_PAGE_ADD_BITS |
l.andi r4,r4,IMMU_SET_ADD_MASK |
l.addi r5,r0,-1 |
l.xori r5,r5,IMMU_PAGE_ADD_MASK |
l.and r5,r3,r5 |
l.ori r5,r5,SPR_ITLBMR_V |
l.mtspr r4,r5,SPR_ITLBMR_BASE(0) |
l.movhi r5,hi(SPR_ITLBTR_PPN) |
l.ori r5,r5,lo(SPR_ITLBTR_PPN) |
l.and r5,r3,r5 |
l.ori r5,r5,ITLBTR_NO_LIMIT |
l.mtspr r4,r5,SPR_ITLBTR_BASE(0) |
l.lwz r3,(TEMP_R_LOC + 0)(r0) |
l.lwz r4,(TEMP_R_LOC + 4)(r0) |
l.lwz r5,(TEMP_R_LOC + 8)(r0) |
l.rfe |
l.nop |
|
_sys_call: |
SAVE_INT_REGS(0x0c00) |
/* EPCR was pointing to l.sys instruction, we have to incremet it */ |
/* l.lwz r2,PC(r1) |
l.addi r2,r2,4 |
l.sw PC(r1),r2 |
*/ |
l.sfeqi r11,0x7777 /* Special case for 'sys_sigreturn' */ |
l.bnf 10f |
l.nop |
l.jal _sys_sigreturn |
l.addi r3,r1,0 |
l.sfgtsi r11,0 /* Check for restarted system call */ |
l.bf 99f |
l.nop |
l.j 20f |
l.nop |
10: |
l.movhi r2,hi(_sys_call_table) |
l.ori r2,r2,lo(_sys_call_table) |
l.slli r11,r11,2 |
l.add r2,r2,r11 |
l.lwz r2,0(r2) |
l.addi r8,r1,0 /* regs pointer */ |
l.jalr r2 |
l.nop |
l.sw GPR11(r1),r11 /* save return value */ |
20: |
l.sw RESULT(r1),r11 /* save result */ |
l.sfgesi r11,0 |
l.bf 99f |
l.nop |
l.sfeqi r11,-ERESTARTNOHAND |
l.bnf 22f |
l.nop |
l.addi r11,r0,EINTR |
22: |
l.sw RESULT(r1),r11 |
99: |
RETURN_FROM_INT(0xc00) |
|
/* |
* This routine switches between two different tasks. The process |
* state of one is saved on its kernel stack. Then the state |
* of the other is restored from its kernel stack. The memory |
* management hardware is updated to the second process's state. |
* Finally, we can return to the second process, via the 'return'. |
* |
* Note: there are two ways to get to the "going out" portion |
* of this code; either by coming in via the entry (_switch) |
* or via "fork" which must set up an environment equivalent |
* to the "_switch" path. If you change this (or in particular, the |
* SAVE_REGS macro), you'll have to change the fork code also. |
*/ |
__switch: |
l.sw (TEMP_R_LOC + 0)(r0),r3 /* Temporary store r3 to add 0!!! */ |
l.sw (TEMP_R_LOC + 4)(r0),r1 /* Temporary store r1 to add 4!!! */ |
l.mtspr r0,r9,SPR_EPCR_BASE /* Link register to EPCR */ |
l.mfspr r3,r0,SPR_SR /* From SR to ESR */ |
l.mtspr r0,r3,SPR_ESR_BASE |
SAVE_REGS(0x0FF0) |
l.sw TSS_KSP(r3),r1 /* Set old stack pointer */ |
l.lwz r1,TSS_KSP(r4) /* Load new stack pointer */ |
RETURN_FROM_INT(0xFF0) |
|
_ua_init: |
l.movhi r3,hi(UART_BASE_ADD) |
|
l.addi r4,r0,0x7 |
l.sb 0x2(r3),r4 |
|
l.addi r4,r0,0x0 |
l.sb 0x1(r3),r4 |
|
l.addi r4,r0,0x3 |
l.sb 0x3(r3),r4 |
|
l.lbz r5,3(r3) |
l.ori r4,r5,0x80 |
l.sb 0x3(r3),r4 |
l.addi r4,r0,((UART_DEVISOR>>8) & 0x000000ff) |
l.sb UART_DLM(r3),r4 |
l.addi r4,r0,((UART_DEVISOR) & 0x000000ff) |
l.sb UART_DLL(r3),r4 |
l.sb 0x3(r3),r5 |
|
l.jr r9 |
l.nop |
|
_putc: |
l.movhi r4,hi(UART_BASE_ADD) |
|
l.addi r6,r0,0x20 |
1: l.lbz r5,5(r4) |
l.andi r5,r5,0x20 |
l.sfeq r5,r6 |
l.bnf 1b |
l.nop |
|
l.sb 0(r4),r3 |
|
l.addi r6,r0,0x60 |
1: l.lbz r5,5(r4) |
l.andi r5,r5,0x60 |
l.sfeq r5,r6 |
l.bnf 1b |
l.nop |
|
l.jr r9 |
l.nop |
|
|
_trap_200: |
l.nop |
l.nop |
.word 0x21000001 |
1: l.j 1b |
l.nop |
|
_trap_300: |
l.nop |
l.nop |
.word 0x21000001 |
1: l.j 1b |
l.nop |
|
_trap_400: |
l.nop |
l.nop |
.word 0x21000001 |
1: l.j 1b |
l.nop |
|
_trap_700: |
l.nop |
l.nop |
.word 0x21000001 |
1: l.j 1b |
l.nop |
|
_trap_900: |
l.nop |
l.nop |
.word 0x21000001 |
1: l.j 1b |
l.nop |
|
_trap_a00: |
l.nop |
l.nop |
.word 0x21000001 |
1: l.j 1b |
l.nop |
|
_trap_b00: |
l.nop |
l.nop |
.word 0x21000001 |
1: l.j 1b |
l.nop |
|
.data |
env: |
.long 0 |
/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 |
*/ |
|
#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); |
return 0; |
} |
|
|
/* |
* 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); |
} |
|
/traps.c
0,0 → 1,209
/* |
* linux/arch/m68knommu/kernel/traps.c |
* |
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>, |
* Kenneth Albanowski <kjahds@kjahds.com> |
* The Silver Hammer Group, Ltd. |
* |
* (Blame me for the icky bits -- kja) |
* |
* Based on: |
* |
* linux/arch/m68k/kernel/traps.c |
* |
* Copyright (C) 1993, 1994 by Hamish Macdonald |
* |
* 68040 fixes by Michael Rausch |
* 68040 fixes by Martin Apel |
* 68060 fixes by Roman Hodek |
* 68060 fixes by Jesper Skov |
* |
* 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. |
* |
* Feb/1999 - Greg Ungerer (gerg@moreton.com.au) changes to support ColdFire. |
*/ |
|
/* |
* 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/system.h> |
#include <asm/segment.h> |
#include <asm/traps.h> |
#include <asm/pgtable.h> |
#include <asm/machdep.h> |
|
|
void trap_init (void) |
{ |
if (mach_trap_init) |
mach_trap_init(); |
} |
|
static inline void console_verbose(void) |
{ |
extern int console_loglevel; |
console_loglevel = 15; |
if (mach_debug_init) |
mach_debug_init(); |
} |
|
|
extern void die_if_kernel(char *,struct pt_regs *,int); |
asmlinkage void trap_c(int vector, struct frame *fp); |
|
asmlinkage void buserr_c(struct frame *fp) |
{ |
#if 1 |
extern void dump(struct pt_regs *fp); |
printk("%s(%d): BUSS ERROR TRAP\n", __FILE__, __LINE__); |
dump((struct pt_regs *) fp); |
#endif |
|
/* Only set esp0 if coming from user mode */ |
if (user_mode(&fp->ptregs)) { |
current->tss.esp0 = (unsigned long) fp; |
} else { |
die_if_kernel("Kernel mode BUS error",(struct pt_regs *)fp,0); |
} |
|
/* insert handler here */ |
force_sig(SIGSEGV, current); |
} |
|
|
static int bad_super_trap_count = 0; |
|
void bad_super_trap (int vector, struct frame *fp) |
{ |
extern void dump(struct pt_regs *fp); |
|
if (bad_super_trap_count++) { |
while(1); |
} |
|
printk ("KERNEL: Bad trap from supervisor state, vector=%d\n", vector); |
dump((struct pt_regs *) fp); |
panic ("Trap from supervisor state"); |
} |
|
asmlinkage void trap_c(int vector, struct frame *fp) |
{ |
int sig; |
#if 0 |
if ((fp->ptregs.sr & PS_S) |
&& ((fp->ptregs.vector) >> 2) == VEC_TRACE |
&& !(fp->ptregs.sr & PS_T)) { |
/* traced a trapping instruction */ |
unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4; |
current->flags |= PF_DTRACE; |
/* clear the trace bit */ |
(*(unsigned short *)lp) &= ~PS_T; |
return; |
} else if (fp->ptregs.sr & PS_S) { |
bad_super_trap(vector, fp); |
return; |
} |
|
/* send the appropriate signal to the user program */ |
switch (vector) { |
case VEC_ADDRERR: |
sig = SIGBUS; |
break; |
case VEC_BUSERR: |
sig = SIGSEGV; |
break; |
case VEC_ILLEGAL: |
case VEC_PRIV: |
case VEC_LINE10: |
case VEC_LINE11: |
case VEC_COPROC: |
case VEC_TRAP2: |
case VEC_TRAP3: |
case VEC_TRAP4: |
case VEC_TRAP5: |
case VEC_TRAP6: |
case VEC_TRAP7: |
case VEC_TRAP8: |
case VEC_TRAP9: |
case VEC_TRAP10: |
case VEC_TRAP11: |
case VEC_TRAP12: |
case VEC_TRAP13: |
case VEC_TRAP14: |
sig = SIGILL; |
break; |
#ifndef NO_FPU |
case VEC_FPBRUC: |
case VEC_FPIR: |
case VEC_FPDIVZ: |
case VEC_FPUNDER: |
case VEC_FPOE: |
case VEC_FPOVER: |
case VEC_FPNAN: |
{ |
unsigned char fstate[216]; |
|
__asm__ __volatile__ ("fsave %0@" : : "a" (fstate) : "memory"); |
/* Set the exception pending bit in the 68882 idle frame */ |
if (*(unsigned short *) fstate == 0x1f38) |
{ |
fstate[fstate[1]] |= 1 << 3; |
__asm__ __volatile__ ("frestore %0@" : : "a" (fstate)); |
} |
} |
/* fall through */ |
#endif |
case VEC_ZERODIV: |
case VEC_TRAP: |
sig = SIGFPE; |
break; |
case VEC_TRACE: /* ptrace single step */ |
fp->ptregs.sr &= ~PS_T; |
case VEC_TRAP15: /* breakpoint */ |
sig = SIGTRAP; |
break; |
case VEC_TRAP1: /* gdbserver breakpoint */ |
/* kwonsk: is this right? */ |
fp->ptregs.pc -= 2; |
sig = SIGTRAP; |
break; |
default: |
sig = SIGILL; |
break; |
} |
|
send_sig (sig, current, 1); |
#endif |
} |
|
asmlinkage void set_esp0 (unsigned long ssp) |
{ |
current->tss.esp0 = ssp; |
} |
|
void die_if_kernel (char *str, struct pt_regs *fp, int nr) |
{ |
extern void dump(struct pt_regs *fp); |
|
if (!(fp->sr & PS_S)) |
return; |
|
console_verbose(); |
dump(fp); |
|
do_exit(SIGSEGV); |
} |
/irq.c
0,0 → 1,290
#include <linux/types.h> |
#include <linux/sched.h> |
#include <linux/kernel_stat.h> |
#include <linux/errno.h> |
|
#include <asm/system.h> |
#include <asm/irq.h> |
#include <asm/traps.h> |
#include <asm/page.h> |
#include <asm/machdep.h> |
|
/* table for system interrupt handlers */ |
static irq_handler_t irq_list[SYS_IRQS]; |
|
static const char *default_names[SYS_IRQS] = { |
"int0", "int1", "int2", "int3", "int4", "int5", "int6", "int7" |
"int8", "int9", "int10", "int11", "int12", "int13", "int14", "int15" |
"int16", "int17", "int18", "int19", "int20", "int21", "int22", "int23" |
"int24", "int25", "int26", "int27", "int28", "int29", "int30", "int31" |
}; |
|
int pic_enable_irq(unsigned int irq) |
{ |
/* Enable in the IMR */ |
mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (0x00000001L << irq)); |
|
return 0; |
} |
|
int pic_disable_irq(unsigned int irq) |
{ |
/* Disable in the IMR */ |
mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(0x00000001L << irq)); |
|
return 0; |
} |
|
int pic_init(void) |
{ |
/* turn off all interrupts */ |
mtspr(SPR_PICMR, 0); |
return 0; |
} |
|
int pic_do_irq(struct pt_regs *fp) |
{ |
int irq; |
int mask; |
|
unsigned long pend = mfspr(SPR_PICSR) & 0xfffffffc; |
|
if (pend & 0x0000ffff) { |
if (pend & 0x000000ff) { |
if (pend & 0x0000000f) { |
mask = 0x00000001; |
irq = 0; |
} else { |
mask = 0x00000010; |
irq = 4; |
} |
} else { |
if (pend & 0x00000f00) { |
mask = 0x00000100; |
irq = 8; |
} else { |
mask = 0x00001000; |
irq = 12; |
} |
} |
} else if(pend & 0xffff0000) { |
if (pend & 0x00ff0000) { |
if (pend & 0x000f0000) { |
mask = 0x00010000; |
irq = 16; |
} else { |
mask = 0x00100000; |
irq = 20; |
} |
} else { |
if (pend & 0x0f000000) { |
mask = 0x01000000; |
irq = 24; |
} else { |
mask = 0x10000000; |
irq = 28; |
} |
} |
} else { |
return -1; |
} |
|
while (! (mask & pend)) { |
mask <<=1; |
irq++; |
} |
|
mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~mask); |
return irq; |
} |
|
void init_IRQ(void) |
{ |
int i; |
|
for (i = 0; i < SYS_IRQS; i++) { |
irq_list[i].handler = NULL; |
irq_list[i].flags = IRQ_FLG_STD; |
irq_list[i].dev_id = NULL; |
irq_list[i].devname = default_names[i]; |
} |
|
pic_init(); |
} |
|
asmlinkage void handle_IRQ(struct pt_regs *regs) |
{ |
int irq; |
|
while((irq = pic_do_irq(regs)) >= 0) { |
|
if (irq_list[irq].handler) |
irq_list[irq].handler(irq, irq_list[irq].dev_id, regs); |
else |
panic("No interrupt handler for autovector %d\n", irq); |
} |
} |
|
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), |
unsigned long flags, const char *devname, void *dev_id) |
{ |
if (irq >= SYS_IRQS) { |
printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname); |
return -ENXIO; |
} |
|
if (!(irq_list[irq].flags & IRQ_FLG_STD)) { |
if (irq_list[irq].flags & IRQ_FLG_LOCK) { |
printk("%s: IRQ %d from %s is not replaceable\n", |
__FUNCTION__, irq, irq_list[irq].devname); |
return -EBUSY; |
} |
if (flags & IRQ_FLG_REPLACE) { |
printk("%s: %s can't replace IRQ %d from %s\n", |
__FUNCTION__, devname, irq, irq_list[irq].devname); |
return -EBUSY; |
} |
} |
irq_list[irq].handler = handler; |
irq_list[irq].flags = flags; |
irq_list[irq].dev_id = dev_id; |
irq_list[irq].devname = devname; |
|
pic_enable_irq(irq); |
|
return 0; |
} |
|
void free_irq(unsigned int irq, void *dev_id) |
{ |
if (irq >= SYS_IRQS) { |
printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); |
return; |
} |
|
pic_disable_irq(irq); |
|
irq_list[irq].handler = NULL; |
irq_list[irq].flags = IRQ_FLG_STD; |
irq_list[irq].dev_id = NULL; |
irq_list[irq].devname = default_names[irq]; |
} |
|
unsigned long probe_irq_on (void) |
{ |
return 0; |
} |
|
int probe_irq_off (unsigned long irqs) |
{ |
return 0; |
} |
|
void enable_irq(unsigned int irq) |
{ |
if (irq >= SYS_IRQS) { |
printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); |
return; |
} |
pic_enable_irq(irq); |
} |
|
void disable_irq(unsigned int irq) |
{ |
if (irq >= SYS_IRQS) { |
printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); |
return; |
} |
pic_disable_irq(irq); |
} |
|
int get_irq_list(char *buf) |
{ |
int i, len = 0; |
|
/* autovector interrupts */ |
for (i = 0; i < SYS_IRQS; i++) { |
if (irq_list[i].handler) { |
if (irq_list[i].flags & IRQ_FLG_LOCK) |
len += sprintf(buf+len, "L "); |
else |
len += sprintf(buf+len, " "); |
if (irq_list[i].flags & IRQ_FLG_PRI_HI) |
len += sprintf(buf+len, "H "); |
else |
len += sprintf(buf+len, "L "); |
len += sprintf(buf+len, "%s\n", irq_list[i].devname); |
} |
} |
|
return len; |
} |
|
void dump(struct pt_regs *fp) |
{ |
unsigned long *sp; |
unsigned char *tp; |
int i; |
|
printk("\nCURRENT PROCESS:\n\n"); |
printk("COMM=%s PID=%d\n", current->comm, current->pid); |
if (current->mm) { |
printk("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", |
(int) current->mm->start_code, |
(int) current->mm->end_code, |
(int) current->mm->start_data, |
(int) current->mm->end_data, |
(int) current->mm->end_data, |
(int) current->mm->brk); |
printk("USER-STACK=%08x KERNEL-STACK=%08x\n\n", |
(int) current->mm->start_stack, |
(int) current->kernel_stack_page); |
} |
printk("PC: %08lx Status: %08lx\n", |
fp->pc, fp->sr); |
printk("R0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
0L, fp->sp, fp->gprs[0], fp->gprs[1], |
fp->gprs[2], fp->gprs[3], fp->gprs[4], fp->gprs[5]); |
printk("R8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
fp->gprs[6], fp->gprs[7], fp->gprs[8], fp->gprs[9], |
fp->gprs[10], fp->gprs[11], fp->gprs[12], fp->gprs[13]); |
printk("R16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
fp->gprs[14], fp->gprs[15], fp->gprs[16], fp->gprs[17], |
fp->gprs[18], fp->gprs[19], fp->gprs[20], fp->gprs[21]); |
printk("R24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", |
fp->gprs[22], fp->gprs[23], fp->gprs[24], fp->gprs[25], |
fp->gprs[26], fp->gprs[27], fp->gprs[28], fp->gprs[29]); |
|
printk("\nUSP: %08lx TRAPFRAME: %08x\n", |
fp->sp, (unsigned int) fp); |
|
printk("\nCODE:"); |
tp = ((unsigned char *) fp->pc) - 0x20; |
for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { |
if ((i % 0x10) == 0) |
printk("\n%08x: ", (int) (tp + i)); |
printk("%08x ", (int) *sp++); |
} |
printk("\n"); |
|
printk("\nKERNEL STACK:"); |
tp = ((unsigned char *) fp) - 0x40; |
for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { |
if ((i % 0x10) == 0) |
printk("\n%08x: ", (int) (tp + i)); |
printk("%08x ", (int) *sp++); |
} |
printk("\n"); |
if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) |
printk("(Possibly corrupted stack page??)\n"); |
printk("\n"); |
|
printk("\nUSER STACK:"); |
tp = (unsigned char *) (fp->sp - 0x10); |
for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { |
if ((i % 0x10) == 0) |
printk("\n%08x: ", (int) (tp + i)); |
printk("%08x ", (int) *sp++); |
} |
printk("\n\n"); |
} |
/Makefile
0,0 → 1,23
# |
# 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__ $(AFLAGS) -traditional -c $< -o $*.o |
|
all: head.o kernel.o |
|
|
O_TARGET := kernel.o |
O_OBJS := setup.o process.o traps.o ptrace.o syscalls.o time.o ksyms.o irq.o misc.o entry.o signal.o semaphore.o |
|
ifdef CONFIG_CONSOLE |
O_OBJS += console.o |
endif |
|
include $(TOPDIR)/Rules.make |
/.depend
0,0 → 1,180
bios32.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/bios32.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/pci.h |
console.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/timer.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/interrupt.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/tty.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/tty_flip.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/console.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kd.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/malloc.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/major.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/ioport.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/io.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/bitops.h \ |
../../../drivers/char/kbd_kern.h \ |
../../../drivers/char/vt_kern.h \ |
../../../drivers/char/consolemap.h \ |
../../../drivers/char/selection.h |
entry.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sys.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/linkage.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h |
head.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/spr_defs.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/ptrace.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/board.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/mc.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h |
irq.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel_stat.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/irq.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/traps.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/page.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/machdep.h |
ksyms.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/module.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/linkage.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/user.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/elfcore.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/irq.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/semaphore.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/symtab_begin.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/symtab_end.h |
misc.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/spr_defs.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/board.h |
mk_defs.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/signal.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/head.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/ptrace.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mman.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h |
process.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stddef.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/unistd.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/ptrace.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/malloc.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/user.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/a.out.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/traps.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/machdep.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/board.h |
ptrace.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/ptrace.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/user.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/page.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h |
semaphore.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/semaphore.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h |
setup.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/delay.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/interrupt.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fs.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fb.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/console.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/genhd.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/major.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/irq.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/machdep.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/blk.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h |
signal.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/signal.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/wait.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/ptrace.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/unistd.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/traps.h |
syscalls.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sem.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/msg.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/shm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mman.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/traps.h |
time.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/param.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/machdep.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/io.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/timex.h |
traps.o: \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/signal.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/a.out.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/user.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/linkage.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/traps.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h \ |
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/machdep.h |
/syscalls.c
0,0 → 1,196
/* |
* linux/arch/or32/kernel/syscalls.c |
* |
* Based on: |
* |
* linux/arch/m68knommu/kernel/sys_m68k.c |
* |
* This file contains various random system calls that |
* have a non-standard calling sequence on the Linux/or32 |
* platform. |
*/ |
|
#include <linux/errno.h> |
#include <linux/sched.h> |
#include <linux/mm.h> |
#include <linux/sem.h> |
#include <linux/msg.h> |
#include <linux/shm.h> |
#include <linux/stat.h> |
#include <linux/mman.h> |
|
#include <asm/segment.h> |
#include <asm/traps.h> |
|
/* |
* sys_pipe() is the normal C calling standard for creating |
* a pipe. It's not the way unix traditionally does this, though. |
*/ |
asmlinkage int sys_pipe(unsigned long * fildes) |
{ |
int fd[2]; |
int error; |
|
error = verify_area(VERIFY_WRITE,fildes,8); |
if (error) |
return error; |
error = do_pipe(fd); |
if (error) |
return error; |
put_user(fd[0],0+fildes); |
put_user(fd[1],1+fildes); |
return 0; |
} |
|
/* |
* Perform the select(nd, in, out, ex, tv) and mmap() system |
* calls. Linux/m68k cloned Linux/i386, which didn't use to be able to |
* handle more than 4 system call parameters, so these system calls |
* used a memory block for parameter passing.. |
*/ |
|
asmlinkage int old_mmap(unsigned long *buffer) |
{ |
int error; |
unsigned long flags; |
struct file * file = NULL; |
|
error = verify_area(VERIFY_READ, buffer, 6*sizeof(long)); |
if (error) |
return error; |
flags = get_user(buffer+3); |
if (!(flags & MAP_ANONYMOUS)) { |
unsigned long fd = get_user(buffer+4); |
if (fd >= NR_OPEN || !(file = current->files->fd[fd])) |
return -EBADF; |
} |
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); |
return do_mmap(file, get_user(buffer), get_user(buffer+1), |
get_user(buffer+2), flags, get_user(buffer+5)); |
} |
|
|
extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); |
|
asmlinkage int old_select(unsigned long *buffer) |
{ |
int n; |
fd_set *inp; |
fd_set *outp; |
fd_set *exp; |
struct timeval *tvp; |
|
n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long)); |
if (n) |
return n; |
|
n = get_user(buffer); |
inp = (fd_set *) get_user(buffer+1); |
outp = (fd_set *) get_user(buffer+2); |
exp = (fd_set *) get_user(buffer+3); |
tvp = (struct timeval *) get_user(buffer+4); |
return sys_select(n, inp, outp, exp, tvp); |
} |
|
/* |
* sys_ipc() is the de-multiplexer for the SysV IPC calls.. |
* |
* This is really horribly ugly. |
*/ |
asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) |
{ |
int version; |
|
version = call >> 16; /* hack for backward compatibility */ |
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 = get_user((void **)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_user (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_ioperm(unsigned long from, unsigned long num, int on) |
{ |
return -ENOSYS; |
} |
|
/* sys_cacheflush -- flush (part of) the processor cache. */ |
asmlinkage int |
sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) |
{ |
return 0; |
} |