diff -u --new-file --recursive v1.1.8/linux/CREDITS linux/CREDITS --- v1.1.8/linux/CREDITS Tue Apr 19 10:52:42 1994 +++ linux/CREDITS Mon Apr 25 10:09:56 1994 @@ -614,9 +614,10 @@ S: USA N: Eric Youngdale +E: ericy@cais.com E: eric@tantalus.nrl.navy.mil D: General kernel hacker -D: SCSI iso9660 and ELF +D: SCSI, iso9660, ELF, ibcs2, clustering in buffer cache, generalized mmap. S: 17 Canterbury Square #101 S: Alexandria, Virginia 22304 S: USA diff -u --new-file --recursive v1.1.8/linux/Makefile linux/Makefile --- v1.1.8/linux/Makefile Mon Apr 25 10:04:31 1994 +++ linux/Makefile Mon Apr 25 10:10:18 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 8 +SUBLEVEL = 9 all: Version zImage diff -u --new-file --recursive v1.1.8/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c --- v1.1.8/linux/drivers/block/sbpcd.c Tue Apr 19 10:52:14 1994 +++ linux/drivers/block/sbpcd.c Mon Apr 25 10:20:02 1994 @@ -5,7 +5,7 @@ * and for "no-sound" interfaces like Lasermate and the * Panasonic CI-101P. * - * NOTE: This is release 1.4. + * NOTE: This is release 1.5. * It works with my SbPro & drive CR-521 V2.11 from 2/92 * and with the new CR-562-B V0.75 on a "naked" Panasonic * CI-101P interface. And vice versa. @@ -72,6 +72,10 @@ * Added some debugging printout for the UPC/EAN code - but my drives * return only zeroes. Is there no UPC/EAN code written? * + * 1.5 Laborate with UPC/EAN code (not better yet). + * Adapt to kernel 1.1.8 change (have to explicitely include + * now). + * * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine * elaborated speed-up experiments (and the fabulous results!), for * the "push" towards load-free wait loops, and for the extensive mail @@ -113,6 +117,7 @@ #include #include #include +#include #if SBPCD_USE_IRQ #include @@ -129,7 +134,7 @@ #define MAJOR_NR MATSUSHITA_CDROM_MAJOR #include "blk.h" -#define VERSION "1.4 Eberhard Moenkeberg " +#define VERSION "1.5 Eberhard Moenkeberg " #define SBPCD_DEBUG @@ -149,6 +154,8 @@ #undef XA_TEST1 #define XA_TEST2 +#define TEST_UPC 0 + /*==========================================================================*/ /*==========================================================================*/ @@ -238,6 +245,7 @@ * (1<0;j--) { + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x87; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + response_count=11; + } + else + { + drvcmd[0]=0x89; + drvcmd[1]=0x02; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + response_count=13; + } i=cmd_out(); if (i<0) return (i); + DPRINTF((DBG_SQ,"SBPCD: xx_ReadSubQ:")); + for (i=0;i<(new_drive?11:13);i++) + { + DPRINTF((DBG_SQ," %02X", infobuf[i])); + } + DPRINTF((DBG_SQ,"\n")); if (infobuf[0]!=0) break; - if (!st_spinning) + if ((!st_spinning) || (j==1)) { DS[d].SubQ_ctl_adr=DS[d].SubQ_trk=DS[d].SubQ_pnt_idx=DS[d].SubQ_whatisthis=0; DS[d].SubQ_run_tot=DS[d].SubQ_run_trk=0; return (0); } } - DS[d].SubQ_audio=infobuf[0]; DS[d].SubQ_ctl_adr=swap_nibbles(infobuf[1]); DS[d].SubQ_trk=byt2bcd(infobuf[2]); DS[d].SubQ_pnt_idx=byt2bcd(infobuf[3]); @@ -1479,37 +1493,62 @@ static int xx_ReadUPC(void) { int i; +#if TEST_UPC + int block, checksum; +#endif TEST_UPC DS[d].diskstate_flags &= ~upc_bit; - clr_cmdbuf(); - if (new_drive) - { - drvcmd[0]=0x88; - response_count=8; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else - { - drvcmd[0]=0x08; - response_count=0; - flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; - } - i=cmd_out(); - if (i<0) return (i); - if (!new_drive) +#if TEST_UPC + for (block=CD_BLOCK_OFFSET+1;block>16)&0xFF; + drvcmd[2]=(block>>8)&0xFF; + drvcmd[3]=block&0xFF; +#endif TEST_UPC + response_count=8; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + } + else + { + drvcmd[0]=0x08; +#if TEST_UPC + drvcmd[2]=(block>>16)&0xFF; + drvcmd[3]=(block>>8)&0xFF; + drvcmd[4]=block&0xFF; +#endif TEST_UPC + response_count=0; + flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; + } + i=cmd_out(); if (i<0) return (i); - } - - DPRINTF((DBG_UPC,"SBPCD: UPC info: ")); - for (i=0;i<(new_drive?8:16);i++) - { - DPRINTF((DBG_UPC,"%02X ", infobuf[i])); + if (!new_drive) + { + response_count=16; + i=xx_ReadPacket(); + if (i<0) return (i); + } +#if TEST_UPC + checksum=0; +#endif TEST_UPC + DPRINTF((DBG_UPC,"SBPCD: UPC info: ")); + for (i=0;i<(new_drive?8:16);i++) + { +#if TEST_UPC + checksum |= infobuf[i]; +#endif TEST_UPC + DPRINTF((DBG_UPC,"%02X ", infobuf[i])); + } + DPRINTF((DBG_UPC,"\n")); +#if TEST_UPC + if ((checksum&0x7F)!=0) break; } - DPRINTF((DBG_UPC,"\n")); - +#endif TEST_UPC DS[d].UPC_ctl_adr=0; if (new_drive) i=0; else i=2; @@ -1559,6 +1598,31 @@ return (0); } /*==========================================================================*/ +#if FUTURE +static int yy_SubChanInfo(int frame, int count, u_char *buffer) +/* "frame" is a RED BOOK address */ +{ + int i; + + if (!new_drive) return (-3); +#if 0 + if (DS[d].audio_state!=audio_playing) return (-2); +#endif + clr_cmdbuf(); + drvcmd[0]=0x11; + drvcmd[1]=(frame>>16)&0xFF; + drvcmd[2]=(frame>>8)&0xFF; + drvcmd[3]=frame&0xFF; + drvcmd[5]=(count>>8)&0xFF; + drvcmd[6]=count&0xFF; + flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; + cmd_type=READ_SC; + DS[d].frame_size=CD_FRAMESIZE_SUB; + i=cmd_out(); /* read directly into user's buffer */ + return (i); +} +#endif FUTURE +/*==========================================================================*/ static void check_datarate(void) { #ifdef CDMKE @@ -2290,9 +2354,6 @@ st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl)); if (st) return (st); memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); -#if 0 - if (DS[d].SubQ_audio==0x80) DS[d].SubQ_audio=CDROM_AUDIO_NO_STATUS; -#endif switch (DS[d].audio_state) { case audio_playing: @@ -2634,7 +2695,7 @@ u_int data_waits = 0; u_int data_retrying = 0; int error_flag; - + int xa_count; error_flag=0; for (frame=DS[d].sbp_current;frame= 1000) diff -u --new-file --recursive v1.1.8/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.1.8/linux/drivers/net/slhc.c Tue Apr 19 10:53:45 1994 +++ linux/drivers/net/slhc.c Mon Apr 25 11:00:35 1994 @@ -73,7 +73,7 @@ int last_retran; -static unsigned char *encode(unsigned char *cp,int n); +static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); static unsigned short pull16(unsigned char **cpp); @@ -160,7 +160,7 @@ /* Put a short in host order into a char array in network order */ -static unsigned char * +static inline unsigned char * put16(unsigned char *cp, unsigned short x) { *cp++ = x >> 8; @@ -172,7 +172,7 @@ /* Encode a number */ unsigned char * -encode(unsigned char *cp, int n) +encode(unsigned char *cp, unsigned short n) { if(n >= 256 || n == 0){ *cp++ = 0; diff -u --new-file --recursive v1.1.8/linux/fs/buffer.c linux/fs/buffer.c --- v1.1.8/linux/fs/buffer.c Mon Apr 25 10:04:33 1994 +++ linux/fs/buffer.c Mon Apr 25 21:27:48 1994 @@ -15,11 +15,8 @@ * disk change. This is where it fits best, I think, as it should * invalidate changed floppy-disk-caches. */ - -#include #include -#include #include #include #include @@ -195,7 +192,7 @@ if (wait && bh->b_req && !bh->b_lock && !bh->b_dirt && !bh->b_uptodate) { err = 1; - printk("Weird - unlocked, clean and not uptodate buffer on list %d\n", nlist); + printk("Weird - unlocked, clean and not uptodate buffer on list %d %x %lu\n", nlist, bh->b_dev, bh->b_blocknr); continue; } /* Don't write clean buffers. Don't write ANY buffers @@ -1867,7 +1864,7 @@ repeat: bh = lru_list[nlist]; if(bh) - for (i = nr_buffers_type[nlist]; --i > 0 && ndirty < bdf_prm.b_un.ndirty; + for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; bh = next) { /* We may have stalled while waiting for I/O to complete. */ if(bh->b_list != nlist) goto repeat; @@ -1909,8 +1906,10 @@ if(nr_buffers_type[BUF_DIRTY] < (nr_buffers - nr_buffers_type[BUF_SHARED]) * bdf_prm.b_un.nfract/100) { - if (current->signal & (1 << (SIGKILL-1))) + if (current->signal & (1 << (SIGKILL-1))) { + bdflush_running--; return 0; + } current->signal = 0; interruptible_sleep_on(&bdflush_wait); } diff -u --new-file --recursive v1.1.8/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v1.1.8/linux/fs/isofs/inode.c Tue Apr 19 10:52:57 1994 +++ linux/fs/isofs/inode.c Mon Apr 25 10:09:55 1994 @@ -477,6 +477,15 @@ brelse(bh); inode->i_op = NULL; + + /* A volume number of 0 is nonsense. Disable checking if we see + this */ + if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && + isonum_723 (raw_inode->volume_sequence_number) == 0) { + printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n"); + inode->i_sb->u.isofs_sb.s_cruft = 'y'; + } + if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && isonum_723 (raw_inode->volume_sequence_number) != 1) { printk("Multi volume CD somehow got mounted.\n"); diff -u --new-file --recursive v1.1.8/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h --- v1.1.8/linux/include/linux/sbpcd.h Tue Apr 19 10:52:15 1994 +++ linux/include/linux/sbpcd.h Mon Apr 25 10:19:26 1994 @@ -74,7 +74,8 @@ #define DBG_UPC 21 /* show UPC information */ #define DBG_XA 22 /* XA mode debugging */ #define DBG_LCK 23 /* door (un)lock info */ -#define DBG_000 24 /* unnecessary information */ +#define DBG_SQ 24 /* dump SubQ frame */ +#define DBG_000 25 /* unnecessary information */ /*==========================================================================*/ /*==========================================================================*/ @@ -215,6 +216,7 @@ #define CD_FRAMESIZE 2048 /* bytes per frame, data mode */ #define CD_FRAMESIZE_XA 2340 /* bytes per frame, "xa" mode */ #define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */ +#define CD_FRAMESIZE_SUB 96 /* subchannel data size */ #define CD_BLOCK_OFFSET 150 /* offset of first logical frame */ #define CD_XA_HEAD 12 /* header size of XA frame */ #define CD_XA_TAIL 280 /* tail size of XA frame */ diff -u --new-file --recursive v1.1.8/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.1.8/linux/include/linux/sched.h Mon Apr 25 10:04:35 1994 +++ linux/include/linux/sched.h Mon Apr 25 11:26:58 1994 @@ -219,8 +219,10 @@ unsigned short used_math; unsigned short rss; /* number of resident pages */ char comm[16]; +/* virtual 86 mode stuff */ struct vm86_struct * vm86_info; unsigned long screen_bitmap; + unsigned long v86flags, v86mask, v86mode; /* file system info */ int link_count; int tty; /* -1 if no tty, so it must be signed */ @@ -286,7 +288,7 @@ /* math */ 0, \ /* rss */ 2, \ /* comm */ "swapper", \ -/* vm86_info */ NULL, 0, \ +/* vm86_info */ NULL, 0, 0, 0, 0, \ /* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL, \ /* ipc */ NULL, NULL, \ /* filp */ {NULL,}, \ diff -u --new-file --recursive v1.1.8/linux/include/linux/vm86.h linux/include/linux/vm86.h --- v1.1.8/linux/include/linux/vm86.h Mon Apr 25 10:04:35 1994 +++ linux/include/linux/vm86.h Mon Apr 25 21:27:48 1994 @@ -1,18 +1,46 @@ #ifndef _LINUX_VM86_H #define _LINUX_VM86_H +/* + * I'm guessing at the VIF/VIP flag usage, but hope that this is how + * the Pentium uses them. Linux will return from vm86 mode when both + * VIF and VIP is set. + * + * On a Pentium, we could probably optimize the virtual flags directly + * in the eflags register instead of doing it "by hand" in vflags... + * + * Linus + */ + #define TF_MASK 0x00000100 #define IF_MASK 0x00000200 #define IOPL_MASK 0x00003000 #define NT_MASK 0x00004000 #define VM_MASK 0x00020000 #define AC_MASK 0x00040000 +#define VIF_MASK 0x00080000 /* virtual interrupt flag */ +#define VIP_MASK 0x00100000 /* virtual interrupt pending */ +#define ID_MASK 0x00200000 #define BIOSSEG 0x0f000 +#define CPU_086 0 +#define CPU_186 1 #define CPU_286 2 #define CPU_386 3 #define CPU_486 4 +#define CPU_586 5 + +/* + * Return values for the 'vm86()' system call + */ +#define VM86_TYPE(retval) ((retval) & 0xff) +#define VM86_ARG(retval) ((retval) >> 8) + +#define VM86_SIGNAL 0 /* return due to signal */ +#define VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ +#define VM86_INTx 2 /* int3/int x instruction (ARG = x) */ +#define VM86_STI 3 /* sti/popfl instruction enabled virtual interrupts */ /* * This is the stack-layout when we have done a "SAVE_ALL" from vm86 @@ -53,25 +81,35 @@ unsigned short gs, __gsh; }; +struct revectored_struct { + unsigned long __map[8]; /* 256 bits */ +}; + struct vm86_struct { struct vm86_regs regs; unsigned long flags; unsigned long screen_bitmap; - unsigned long v_eflags; unsigned long cpu_type; - unsigned long return_if_iflag; - unsigned char int_revectored[0x100]; - unsigned char int21_revectored[0x100]; + struct revectored_struct int_revectored; + struct revectored_struct int21_revectored; }; /* * flags masks */ -#define VM86_SCREEN_BITMAP 1 +#define VM86_SCREEN_BITMAP 0x0001 #ifdef __KERNEL__ void handle_vm86_fault(struct vm86_regs *, long); + +extern inline int is_revectored(int nr, struct revectored_struct * bitmap) +{ + __asm__ __volatile__("btl %2,%%fs:%1\n\tsbbl %0,%0" + :"=r" (nr) + :"m" (*bitmap),"r" (nr)); + return nr; +} #endif diff -u --new-file --recursive v1.1.8/linux/kernel/vm86.c linux/kernel/vm86.c --- v1.1.8/linux/kernel/vm86.c Mon Apr 25 10:04:37 1994 +++ linux/kernel/vm86.c Mon Apr 25 21:27:48 1994 @@ -13,20 +13,37 @@ #include #include +/* + * 16-bit register defines.. + */ +#define IP(regs) (*(unsigned short *)&((regs)->eip)) +#define SP(regs) (*(unsigned short *)&((regs)->esp)) + +/* + * virtual flags (16 and 32-bit versions) + */ +#define VFLAGS(regs) (*(unsigned short *)&(current->v86flags)) +#define VEFLAGS(regs) (current->v86flags) + +#define set_flags(X,new,mask) \ +((X) = ((X) & ~(mask)) | ((new) & (mask))) + +#define SAFE_MASK (0xDD5) + asmlinkage struct pt_regs * save_v86_state(struct vm86_regs * regs) { - unsigned long stack; + unsigned long tmp; if (!current->vm86_info) { printk("no vm86_info: BAD\n"); do_exit(SIGSEGV); } - memcpy_tofs(&(current->vm86_info->regs),regs,sizeof(*regs)); - put_fs_long(current->screen_bitmap,&(current->vm86_info->screen_bitmap)); - stack = current->tss.esp0; + memcpy_tofs(¤t->vm86_info->regs,regs,sizeof(*regs)); + put_fs_long(current->screen_bitmap,¤t->vm86_info->screen_bitmap); + tmp = current->tss.esp0; current->tss.esp0 = current->saved_kernel_stack; current->saved_kernel_stack = 0; - return (struct pt_regs *) stack; + return (struct pt_regs *) tmp; } static void mark_screen_rdonly(struct task_struct * tsk) @@ -74,20 +91,41 @@ * has set it up safely, so this makes sure interrupt etc flags are * inherited from protected mode. */ - info.regs.eflags &= 0x00000dd5; - info.regs.eflags |= ~0x00000dd5 & pt_regs->eflags; + current->v86flags = info.regs.eflags; + info.regs.eflags &= SAFE_MASK; + info.regs.eflags |= ~SAFE_MASK & pt_regs->eflags; info.regs.eflags |= VM_MASK; + + switch (info.cpu_type) { + case CPU_286: + current->v86mask = 0; + break; + case CPU_386: + current->v86mask = NT_MASK | IOPL_MASK; + break; + case CPU_486: + current->v86mask = AC_MASK | NT_MASK | IOPL_MASK; + break; + default: + current->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; + break; + } + +/* + * Save old state, set default return value (%eax) to 0 + */ + pt_regs->eax = 0; current->saved_kernel_stack = current->tss.esp0; current->tss.esp0 = (unsigned long) pt_regs; current->vm86_info = v86; + current->screen_bitmap = info.screen_bitmap; if (info.flags & VM86_SCREEN_BITMAP) mark_screen_rdonly(current); __asm__ __volatile__("movl %0,%%esp\n\t" - "pushl $ret_from_sys_call\n\t" - "ret" + "jmp ret_from_sys_call" : /* no outputs */ - :"g" ((long) &(info.regs)),"a" (info.regs.eax)); + :"r" (&info.regs)); return 0; } @@ -97,131 +135,226 @@ regs32 = save_v86_state(regs16); regs32->eax = retval; - __asm__("movl %0,%%esp\n\t" + __asm__ __volatile__("movl %0,%%esp\n\t" "jmp ret_from_sys_call" : : "r" (regs32)); } +static inline void set_IF(struct vm86_regs * regs) +{ + current->v86flags |= VIF_MASK; + if (current->v86flags & VIP_MASK) + return_to_32bit(regs, VM86_STI); +} + +static inline void clear_IF(struct vm86_regs * regs) +{ + current->v86flags &= ~VIF_MASK; +} + +static inline void clear_TF(struct vm86_regs * regs) +{ + regs->eflags &= ~TF_MASK; +} + +static inline void set_vflags_long(unsigned long eflags, struct vm86_regs * regs) +{ + set_flags(VEFLAGS(regs), eflags, current->v86mask); + set_flags(regs->eflags, eflags, SAFE_MASK); + if (eflags & IF_MASK) + set_IF(regs); +} + +static inline void set_vflags_short(unsigned short flags, struct vm86_regs * regs) +{ + set_flags(VFLAGS(regs), flags, current->v86mask); + set_flags(regs->eflags, flags, SAFE_MASK); + if (flags & IF_MASK) + set_IF(regs); +} + +static inline unsigned long get_vflags(struct vm86_regs * regs) +{ + unsigned long flags = regs->eflags & SAFE_MASK; + + if (current->v86flags & VIF_MASK) + flags |= IF_MASK; + return flags | (VEFLAGS(regs) & current->v86mask); +} + +/* + * Boy are these ugly, but we need to do the correct 16-bit arithmetic. + * Gcc makes a mess of it, so we do it inline and use non-obvious calling + * conventions.. + */ +#define pushb(base, ptr, val) \ +__asm__ __volatile__( \ + "decw %w0\n\t" \ + "movb %2,%%fs:0(%1,%0)" \ + : "=r" (ptr) \ + : "r" (base), "q" (val), "0" (ptr)) + +#define pushw(base, ptr, val) \ +__asm__ __volatile__( \ + "decw %w0\n\t" \ + "movb %h2,%%fs:0(%1,%0)\n\t" \ + "decw %w0\n\t" \ + "movb %b2,%%fs:0(%1,%0)" \ + : "=r" (ptr) \ + : "r" (base), "q" (val), "0" (ptr)) + +#define pushl(base, ptr, val) \ +__asm__ __volatile__( \ + "decw %w0\n\t" \ + "rorl $16,%2\n\t" \ + "movb %h2,%%fs:0(%1,%0)\n\t" \ + "decw %w0\n\t" \ + "movb %b2,%%fs:0(%1,%0)\n\t" \ + "decw %w0\n\t" \ + "rorl $16,%2\n\t" \ + "movb %h2,%%fs:0(%1,%0)\n\t" \ + "decw %w0\n\t" \ + "movb %b2,%%fs:0(%1,%0)" \ + : "=r" (ptr) \ + : "r" (base), "q" (val), "0" (ptr)) + +#define popb(base, ptr) \ +({ unsigned long __res; \ +__asm__ __volatile__( \ + "movb %%fs:0(%1,%0),%b2\n\t" \ + "incw %w0" \ + : "=r" (ptr), "=r" (base), "=r" (__res) \ + : "0" (ptr), "1" (base), "2" (0)); \ +__res; }) + +#define popw(base, ptr) \ +({ unsigned long __res; \ +__asm__ __volatile__( \ + "movb %%fs:0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "movb %%fs:0(%1,%0),%h2\n\t" \ + "incw %w0" \ + : "=r" (ptr), "=r" (base), "=r" (__res) \ + : "0" (ptr), "1" (base), "2" (0)); \ +__res; }) + +#define popl(base, ptr) \ +({ unsigned long __res; \ +__asm__ __volatile__( \ + "movb %%fs:0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "movb %%fs:0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "rorl $16,%2\n\t" \ + "movb %%fs:0(%1,%0),%b2\n\t" \ + "incw %w0\n\t" \ + "movb %%fs:0(%1,%0),%h2\n\t" \ + "incw %w0\n\t" \ + "rorl $16,%2" \ + : "=r" (ptr), "=r" (base), "=r" (__res) \ + : "0" (ptr), "1" (base)); \ +__res; }) + +static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp) +{ + unsigned short seg = get_fs_word((void *) ((i<<2)+2)); + + if (seg == BIOSSEG || regs->cs == BIOSSEG || + is_revectored(i, ¤t->vm86_info->int_revectored)) + return_to_32bit(regs, VM86_INTx + (i << 8)); + if (i==0x21 && is_revectored((regs->eax >> 4) & 0xff,¤t->vm86_info->int21_revectored)) { + return_to_32bit(regs, VM86_INTx + (i << 8)); + } + pushw(ssp, sp, get_vflags(regs)); + pushw(ssp, sp, regs->cs); + pushw(ssp, sp, IP(regs)); + regs->cs = seg; + SP(regs) -= 6; + IP(regs) = get_fs_word((void *) (i<<2)); + clear_TF(regs); + clear_IF(regs); + return; +} + + void handle_vm86_fault(struct vm86_regs * regs, long error_code) { - unsigned char *csp; - unsigned short *ssp; - unsigned short flags; - unsigned char i; + unsigned char *csp, *ssp; + unsigned long ip, sp; - csp = (unsigned char *) ((regs->cs << 4) + (regs->eip & 0xffff)); - ssp = (unsigned short *) ((regs->ss << 4) + (regs->esp & 0xffff)); + csp = (unsigned char *) (regs->cs << 4); + ssp = (unsigned char *) (regs->ss << 4); + sp = SP(regs); + ip = IP(regs); - switch (get_fs_byte(csp)) { + switch (popb(csp, ip)) { /* operand size override */ case 0x66: - switch (get_fs_byte(++csp)) { + switch (popb(csp, ip)) { /* pushfd */ case 0x9c: - regs->esp -= 4; - regs->eip += 2; - if (get_fs_long(&(current->vm86_info->cpu_type)) == CPU_386) - put_fs_long(((regs->eflags) & ~(AC_MASK|NT_MASK|IOPL_MASK|IF_MASK)) | - (get_fs_long(&(current->vm86_info->v_eflags)) & (NT_MASK|IOPL_MASK|IF_MASK)), ssp-2); - else - put_fs_long(((regs->eflags) & ~(AC_MASK|NT_MASK|IOPL_MASK|IF_MASK)) | - (get_fs_long(&(current->vm86_info->v_eflags)) & (AC_MASK|NT_MASK|IOPL_MASK|IF_MASK)), ssp-2); + SP(regs) -= 4; + IP(regs) += 2; + pushl(ssp, sp, get_vflags(regs)); return; /* popfd */ case 0x9d: - regs->esp += 4; - regs->eip += 2; - flags = get_fs_word(ssp+1); - put_fs_word(flags, (unsigned short *) &(current->vm86_info->v_eflags) +1); - goto return_from_popf; + SP(regs) += 4; + IP(regs) += 2; + set_vflags_long(popl(ssp, sp), regs); + return; } /* pushf */ case 0x9c: - regs->esp -= 2; - regs->eip++; - if (get_fs_long(&(current->vm86_info->cpu_type)) == CPU_286) - put_fs_word(((regs->eflags) & 0x0dd5) | - (get_fs_word(&(current->vm86_info->v_eflags)) & ~0xfdd5), --ssp); - else - put_fs_word(((regs->eflags) & ~(NT_MASK|IOPL_MASK|IF_MASK)) | - (get_fs_word(&(current->vm86_info->v_eflags)) & (NT_MASK|IOPL_MASK|IF_MASK)), --ssp); + SP(regs) -= 2; + IP(regs)++; + pushw(ssp, sp, get_vflags(regs)); return; /* popf */ case 0x9d: - regs->esp += 2; - regs->eip++; - return_from_popf: - flags = get_fs_word(ssp); - regs->eflags &= ~0x00000dd5; - regs->eflags |= flags & 0x00000dd5; - put_fs_word(flags, &(current->vm86_info->v_eflags)); - goto do_dosemu_timer; + SP(regs) += 2; + IP(regs)++; + set_vflags_short(popw(ssp, sp), regs); + return; /* int 3 */ case 0xcc: - if (get_fs_word((void *)14) == BIOSSEG || regs->cs == BIOSSEG - || get_fs_byte(&(current->vm86_info->int_revectored[3]))) - return_to_32bit(regs, SIGSEGV); - i = 3; - regs->eip++; - goto return_from_int_xx; + IP(regs)++; + do_int(regs, 3, ssp, sp); + return; /* int xx */ case 0xcd: - i = get_fs_byte(++csp); - if (get_fs_word((void *)((i<<2)+2)) == BIOSSEG - || regs->cs == BIOSSEG - || get_fs_byte(&(current->vm86_info->int_revectored[i]))) - return_to_32bit(regs, SIGSEGV); - if ((i==0x21) && get_fs_byte(&(current->vm86_info->int21_revectored[((regs->eax >> 4) & 0xff)]))) - return_to_32bit(regs, SIGSEGV); - regs->eip+=2; - return_from_int_xx: - regs->esp -= 6; - if (get_fs_long(&(current->vm86_info->cpu_type)) == CPU_286) - put_fs_word(((regs->eflags) & 0x0dd5) | - (get_fs_word(&(current->vm86_info->v_eflags)) & ~0xfdd5), --ssp); - else - put_fs_word(((regs->eflags) & ~IF_MASK) | - (get_fs_word(&(current->vm86_info->v_eflags)) & IF_MASK), --ssp); - put_fs_word(regs->cs, --ssp); - put_fs_word((unsigned short)(regs->eip), --ssp); - regs->cs = get_fs_word((void *)((i<<2)+2)); - regs->eip = (unsigned long) get_fs_word((void *)(i<<2)); - regs->eflags &= ~TF_MASK; - and_fs_long(~IF_MASK, &(current->vm86_info->v_eflags)); + IP(regs) += 2; + do_int(regs, popb(csp, ip), ssp, sp); return; /* iret */ case 0xcf: - regs->esp += 6; - regs->eip = get_fs_word(ssp++); - regs->cs = get_fs_word(ssp++); - goto return_from_popf; + SP(regs) += 6; + IP(regs) = popw(ssp, sp); + regs->cs = popw(ssp, sp); + set_vflags_short(popw(ssp, sp), regs); + return; /* cli */ case 0xfa: - regs->eip++; - and_fs_long(~IF_MASK, &(current->vm86_info->v_eflags)); + IP(regs)++; + clear_IF(regs); return; /* sti */ case 0xfb: - regs->eip++; - or_fs_long(IF_MASK, &(current->vm86_info->v_eflags)); - do_dosemu_timer: - if ((get_fs_long(&(current->vm86_info->v_eflags)) & IF_MASK) && - get_fs_long(&(current->vm86_info->return_if_iflag))) - break; + IP(regs)++; + set_IF(regs); return; default: - return_to_32bit(regs, SIGSEGV); + return_to_32bit(regs, VM86_UNKNOWN); } - return_to_32bit(regs, SIGALRM); }