vm86.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:17k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/kernel/vm86.c
  3.  *
  4.  *  Copyright (C) 1994  Linus Torvalds
  5.  */
  6. #include <linux/errno.h>
  7. #include <linux/sched.h>
  8. #include <linux/kernel.h>
  9. #include <linux/signal.h>
  10. #include <linux/string.h>
  11. #include <linux/ptrace.h>
  12. #include <linux/mm.h>
  13. #include <linux/smp.h>
  14. #include <linux/smp_lock.h>
  15. #include <asm/uaccess.h>
  16. #include <asm/pgalloc.h>
  17. #include <asm/io.h>
  18. #include <asm/irq.h>
  19. /*
  20.  * Known problems:
  21.  *
  22.  * Interrupt handling is not guaranteed:
  23.  * - a real x86 will disable all interrupts for one instruction
  24.  *   after a "mov ss,xx" to make stack handling atomic even without
  25.  *   the 'lss' instruction. We can't guarantee this in v86 mode,
  26.  *   as the next instruction might result in a page fault or similar.
  27.  * - a real x86 will have interrupts disabled for one instruction
  28.  *   past the 'sti' that enables them. We don't bother with all the
  29.  *   details yet.
  30.  *
  31.  * Let's hope these problems do not actually matter for anything.
  32.  */
  33. #define KVM86 ((struct kernel_vm86_struct *)regs)
  34. #define VMPI  KVM86->vm86plus
  35. /*
  36.  * 8- and 16-bit register defines..
  37.  */
  38. #define AL(regs) (((unsigned char *)&((regs)->eax))[0])
  39. #define AH(regs) (((unsigned char *)&((regs)->eax))[1])
  40. #define IP(regs) (*(unsigned short *)&((regs)->eip))
  41. #define SP(regs) (*(unsigned short *)&((regs)->esp))
  42. /*
  43.  * virtual flags (16 and 32-bit versions)
  44.  */
  45. #define VFLAGS (*(unsigned short *)&(current->thread.v86flags))
  46. #define VEFLAGS (current->thread.v86flags)
  47. #define set_flags(X,new,mask) 
  48. ((X) = ((X) & ~(mask)) | ((new) & (mask)))
  49. #define SAFE_MASK (0xDD5)
  50. #define RETURN_MASK (0xDFF)
  51. #define VM86_REGS_PART2 orig_eax
  52. #define VM86_REGS_SIZE1 
  53.         ( (unsigned)( & (((struct kernel_vm86_regs *)0)->VM86_REGS_PART2) ) )
  54. #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1)
  55. struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
  56. struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
  57. {
  58. struct tss_struct *tss;
  59. struct pt_regs *ret;
  60. unsigned long tmp;
  61. if (!current->thread.vm86_info) {
  62. printk("no vm86_info: BADn");
  63. do_exit(SIGSEGV);
  64. }
  65. set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->thread.v86mask);
  66. tmp = copy_to_user(&current->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
  67. tmp += copy_to_user(&current->thread.vm86_info->regs.VM86_REGS_PART2,
  68. &regs->VM86_REGS_PART2, VM86_REGS_SIZE2);
  69. tmp += put_user(current->thread.screen_bitmap,&current->thread.vm86_info->screen_bitmap);
  70. if (tmp) {
  71. printk("vm86: could not access userspace vm86_infon");
  72. do_exit(SIGSEGV);
  73. }
  74. tss = init_tss + smp_processor_id();
  75. tss->esp0 = current->thread.esp0 = current->thread.saved_esp0;
  76. current->thread.saved_esp0 = 0;
  77. ret = KVM86->regs32;
  78. return ret;
  79. }
  80. static void mark_screen_rdonly(struct task_struct * tsk)
  81. {
  82. pgd_t *pgd;
  83. pmd_t *pmd;
  84. pte_t *pte;
  85. int i;
  86. pgd = pgd_offset(tsk->mm, 0xA0000);
  87. if (pgd_none(*pgd))
  88. return;
  89. if (pgd_bad(*pgd)) {
  90. pgd_ERROR(*pgd);
  91. pgd_clear(pgd);
  92. return;
  93. }
  94. pmd = pmd_offset(pgd, 0xA0000);
  95. if (pmd_none(*pmd))
  96. return;
  97. if (pmd_bad(*pmd)) {
  98. pmd_ERROR(*pmd);
  99. pmd_clear(pmd);
  100. return;
  101. }
  102. pte = pte_offset(pmd, 0xA0000);
  103. for (i = 0; i < 32; i++) {
  104. if (pte_present(*pte))
  105. set_pte(pte, pte_wrprotect(*pte));
  106. pte++;
  107. }
  108. flush_tlb();
  109. }
  110. static int do_vm86_irq_handling(int subfunction, int irqnumber);
  111. static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
  112. asmlinkage int sys_vm86old(struct vm86_struct * v86)
  113. {
  114. struct kernel_vm86_struct info; /* declare this _on top_,
  115.  * this avoids wasting of stack space.
  116.  * This remains on the stack until we
  117.  * return to 32 bit user space.
  118.  */
  119. struct task_struct *tsk;
  120. int tmp, ret = -EPERM;
  121. tsk = current;
  122. if (tsk->thread.saved_esp0)
  123. goto out;
  124. tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
  125. tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
  126. (long)&info.vm86plus - (long)&info.regs.VM86_REGS_PART2);
  127. ret = -EFAULT;
  128. if (tmp)
  129. goto out;
  130. memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
  131. info.regs32 = (struct pt_regs *) &v86;
  132. tsk->thread.vm86_info = v86;
  133. do_sys_vm86(&info, tsk);
  134. ret = 0; /* we never return here */
  135. out:
  136. return ret;
  137. }
  138. asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct * v86)
  139. {
  140. struct kernel_vm86_struct info; /* declare this _on top_,
  141.  * this avoids wasting of stack space.
  142.  * This remains on the stack until we
  143.  * return to 32 bit user space.
  144.  */
  145. struct task_struct *tsk;
  146. int tmp, ret;
  147. tsk = current;
  148. switch (subfunction) {
  149. case VM86_REQUEST_IRQ:
  150. case VM86_FREE_IRQ:
  151. case VM86_GET_IRQ_BITS:
  152. case VM86_GET_AND_RESET_IRQ:
  153. ret = do_vm86_irq_handling(subfunction,(int)v86);
  154. goto out;
  155. case VM86_PLUS_INSTALL_CHECK:
  156. /* NOTE: on old vm86 stuff this will return the error
  157.    from verify_area(), because the subfunction is
  158.    interpreted as (invalid) address to vm86_struct.
  159.    So the installation check works.
  160.  */
  161. ret = 0;
  162. goto out;
  163. }
  164. /* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
  165. ret = -EPERM;
  166. if (tsk->thread.saved_esp0)
  167. goto out;
  168. tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
  169. tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
  170. (long)&info.regs32 - (long)&info.regs.VM86_REGS_PART2);
  171. ret = -EFAULT;
  172. if (tmp)
  173. goto out;
  174. info.regs32 = (struct pt_regs *) &subfunction;
  175. info.vm86plus.is_vm86pus = 1;
  176. tsk->thread.vm86_info = (struct vm86_struct *)v86;
  177. do_sys_vm86(&info, tsk);
  178. ret = 0; /* we never return here */
  179. out:
  180. return ret;
  181. }
  182. static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
  183. {
  184. struct tss_struct *tss;
  185. /*
  186.  * make sure the vm86() system call doesn't try to do anything silly
  187.  */
  188. info->regs.__null_ds = 0;
  189. info->regs.__null_es = 0;
  190. /* we are clearing fs,gs later just before "jmp ret_from_sys_call",
  191.  * because starting with Linux 2.1.x they aren't no longer saved/restored
  192.  */
  193. /*
  194.  * The eflags register is also special: we cannot trust that the user
  195.  * has set it up safely, so this makes sure interrupt etc flags are
  196.  * inherited from protected mode.
  197.  */
  198.   VEFLAGS = info->regs.eflags;
  199. info->regs.eflags &= SAFE_MASK;
  200. info->regs.eflags |= info->regs32->eflags & ~SAFE_MASK;
  201. info->regs.eflags |= VM_MASK;
  202. switch (info->cpu_type) {
  203. case CPU_286:
  204. tsk->thread.v86mask = 0;
  205. break;
  206. case CPU_386:
  207. tsk->thread.v86mask = NT_MASK | IOPL_MASK;
  208. break;
  209. case CPU_486:
  210. tsk->thread.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
  211. break;
  212. default:
  213. tsk->thread.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
  214. break;
  215. }
  216. /*
  217.  * Save old state, set default return value (%eax) to 0
  218.  */
  219. info->regs32->eax = 0;
  220. tsk->thread.saved_esp0 = tsk->thread.esp0;
  221. tss = init_tss + smp_processor_id();
  222. tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
  223. tsk->thread.screen_bitmap = info->screen_bitmap;
  224. if (info->flags & VM86_SCREEN_BITMAP)
  225. mark_screen_rdonly(tsk);
  226. __asm__ __volatile__(
  227. "xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gsnt"
  228. "movl %0,%%espnt"
  229. "jmp ret_from_sys_call"
  230. : /* no outputs */
  231. :"r" (&info->regs), "b" (tsk) : "ax");
  232. /* we never return here */
  233. }
  234. static inline void return_to_32bit(struct kernel_vm86_regs * regs16, int retval)
  235. {
  236. struct pt_regs * regs32;
  237. regs32 = save_v86_state(regs16);
  238. regs32->eax = retval;
  239. __asm__ __volatile__("movl %0,%%espnt"
  240. "jmp ret_from_sys_call"
  241. : : "r" (regs32), "b" (current));
  242. }
  243. static inline void set_IF(struct kernel_vm86_regs * regs)
  244. {
  245. VEFLAGS |= VIF_MASK;
  246. if (VEFLAGS & VIP_MASK)
  247. return_to_32bit(regs, VM86_STI);
  248. }
  249. static inline void clear_IF(struct kernel_vm86_regs * regs)
  250. {
  251. VEFLAGS &= ~VIF_MASK;
  252. }
  253. static inline void clear_TF(struct kernel_vm86_regs * regs)
  254. {
  255. regs->eflags &= ~TF_MASK;
  256. }
  257. static inline void set_vflags_long(unsigned long eflags, struct kernel_vm86_regs * regs)
  258. {
  259. set_flags(VEFLAGS, eflags, current->thread.v86mask);
  260. set_flags(regs->eflags, eflags, SAFE_MASK);
  261. if (eflags & IF_MASK)
  262. set_IF(regs);
  263. }
  264. static inline void set_vflags_short(unsigned short flags, struct kernel_vm86_regs * regs)
  265. {
  266. set_flags(VFLAGS, flags, current->thread.v86mask);
  267. set_flags(regs->eflags, flags, SAFE_MASK);
  268. if (flags & IF_MASK)
  269. set_IF(regs);
  270. }
  271. static inline unsigned long get_vflags(struct kernel_vm86_regs * regs)
  272. {
  273. unsigned long flags = regs->eflags & RETURN_MASK;
  274. if (VEFLAGS & VIF_MASK)
  275. flags |= IF_MASK;
  276. return flags | (VEFLAGS & current->thread.v86mask);
  277. }
  278. static inline int is_revectored(int nr, struct revectored_struct * bitmap)
  279. {
  280. __asm__ __volatile__("btl %2,%1ntsbbl %0,%0"
  281. :"=r" (nr)
  282. :"m" (*bitmap),"r" (nr));
  283. return nr;
  284. }
  285. /*
  286.  * Boy are these ugly, but we need to do the correct 16-bit arithmetic.
  287.  * Gcc makes a mess of it, so we do it inline and use non-obvious calling
  288.  * conventions..
  289.  */
  290. #define pushb(base, ptr, val) 
  291. __asm__ __volatile__( 
  292. "decw %w0nt" 
  293. "movb %2,0(%1,%0)" 
  294. : "=r" (ptr) 
  295. : "r" (base), "q" (val), "0" (ptr))
  296. #define pushw(base, ptr, val) 
  297. __asm__ __volatile__( 
  298. "decw %w0nt" 
  299. "movb %h2,0(%1,%0)nt" 
  300. "decw %w0nt" 
  301. "movb %b2,0(%1,%0)" 
  302. : "=r" (ptr) 
  303. : "r" (base), "q" (val), "0" (ptr))
  304. #define pushl(base, ptr, val) 
  305. __asm__ __volatile__( 
  306. "decw %w0nt" 
  307. "rorl $16,%2nt" 
  308. "movb %h2,0(%1,%0)nt" 
  309. "decw %w0nt" 
  310. "movb %b2,0(%1,%0)nt" 
  311. "decw %w0nt" 
  312. "rorl $16,%2nt" 
  313. "movb %h2,0(%1,%0)nt" 
  314. "decw %w0nt" 
  315. "movb %b2,0(%1,%0)" 
  316. : "=r" (ptr) 
  317. : "r" (base), "q" (val), "0" (ptr))
  318. #define popb(base, ptr) 
  319. ({ unsigned long __res; 
  320. __asm__ __volatile__( 
  321. "movb 0(%1,%0),%b2nt" 
  322. "incw %w0" 
  323. : "=r" (ptr), "=r" (base), "=q" (__res) 
  324. : "0" (ptr), "1" (base), "2" (0)); 
  325. __res; })
  326. #define popw(base, ptr) 
  327. ({ unsigned long __res; 
  328. __asm__ __volatile__( 
  329. "movb 0(%1,%0),%b2nt" 
  330. "incw %w0nt" 
  331. "movb 0(%1,%0),%h2nt" 
  332. "incw %w0" 
  333. : "=r" (ptr), "=r" (base), "=q" (__res) 
  334. : "0" (ptr), "1" (base), "2" (0)); 
  335. __res; })
  336. #define popl(base, ptr) 
  337. ({ unsigned long __res; 
  338. __asm__ __volatile__( 
  339. "movb 0(%1,%0),%b2nt" 
  340. "incw %w0nt" 
  341. "movb 0(%1,%0),%h2nt" 
  342. "incw %w0nt" 
  343. "rorl $16,%2nt" 
  344. "movb 0(%1,%0),%b2nt" 
  345. "incw %w0nt" 
  346. "movb 0(%1,%0),%h2nt" 
  347. "incw %w0nt" 
  348. "rorl $16,%2" 
  349. : "=r" (ptr), "=r" (base), "=q" (__res) 
  350. : "0" (ptr), "1" (base)); 
  351. __res; })
  352. static void do_int(struct kernel_vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp)
  353. {
  354. unsigned long *intr_ptr, segoffs;
  355. if (regs->cs == BIOSSEG)
  356. goto cannot_handle;
  357. if (is_revectored(i, &KVM86->int_revectored))
  358. goto cannot_handle;
  359. if (i==0x21 && is_revectored(AH(regs),&KVM86->int21_revectored))
  360. goto cannot_handle;
  361. intr_ptr = (unsigned long *) (i << 2);
  362. if (get_user(segoffs, intr_ptr))
  363. goto cannot_handle;
  364. if ((segoffs >> 16) == BIOSSEG)
  365. goto cannot_handle;
  366. pushw(ssp, sp, get_vflags(regs));
  367. pushw(ssp, sp, regs->cs);
  368. pushw(ssp, sp, IP(regs));
  369. regs->cs = segoffs >> 16;
  370. SP(regs) -= 6;
  371. IP(regs) = segoffs & 0xffff;
  372. clear_TF(regs);
  373. clear_IF(regs);
  374. return;
  375. cannot_handle:
  376. return_to_32bit(regs, VM86_INTx + (i << 8));
  377. }
  378. int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno)
  379. {
  380. if (VMPI.is_vm86pus) {
  381. if ( (trapno==3) || (trapno==1) )
  382. return_to_32bit(regs, VM86_TRAP + (trapno << 8));
  383. do_int(regs, trapno, (unsigned char *) (regs->ss << 4), SP(regs));
  384. return 0;
  385. }
  386. if (trapno !=1)
  387. return 1; /* we let this handle by the calling routine */
  388. if (current->ptrace & PT_PTRACED) {
  389. unsigned long flags;
  390. spin_lock_irqsave(&current->sigmask_lock, flags);
  391. sigdelset(&current->blocked, SIGTRAP);
  392. recalc_sigpending(current);
  393. spin_unlock_irqrestore(&current->sigmask_lock, flags);
  394. }
  395. send_sig(SIGTRAP, current, 1);
  396. current->thread.trap_no = trapno;
  397. current->thread.error_code = error_code;
  398. return 0;
  399. }
  400. void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
  401. {
  402. unsigned char *csp, *ssp;
  403. unsigned long ip, sp;
  404. #define CHECK_IF_IN_TRAP 
  405. if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) 
  406. pushw(ssp,sp,popw(ssp,sp) | TF_MASK);
  407. #define VM86_FAULT_RETURN 
  408. if (VMPI.force_return_for_pic  && (VEFLAGS & (IF_MASK | VIF_MASK))) 
  409. return_to_32bit(regs, VM86_PICRETURN); 
  410. return;
  411.                                    
  412. csp = (unsigned char *) (regs->cs << 4);
  413. ssp = (unsigned char *) (regs->ss << 4);
  414. sp = SP(regs);
  415. ip = IP(regs);
  416. switch (popb(csp, ip)) {
  417. /* operand size override */
  418. case 0x66:
  419. switch (popb(csp, ip)) {
  420. /* pushfd */
  421. case 0x9c:
  422. SP(regs) -= 4;
  423. IP(regs) += 2;
  424. pushl(ssp, sp, get_vflags(regs));
  425. VM86_FAULT_RETURN;
  426. /* popfd */
  427. case 0x9d:
  428. SP(regs) += 4;
  429. IP(regs) += 2;
  430. CHECK_IF_IN_TRAP
  431. set_vflags_long(popl(ssp, sp), regs);
  432. VM86_FAULT_RETURN;
  433. /* iretd */
  434. case 0xcf:
  435. SP(regs) += 12;
  436. IP(regs) = (unsigned short)popl(ssp, sp);
  437. regs->cs = (unsigned short)popl(ssp, sp);
  438. CHECK_IF_IN_TRAP
  439. set_vflags_long(popl(ssp, sp), regs);
  440. VM86_FAULT_RETURN;
  441. /* need this to avoid a fallthrough */
  442. default:
  443. return_to_32bit(regs, VM86_UNKNOWN);
  444. }
  445. /* pushf */
  446. case 0x9c:
  447. SP(regs) -= 2;
  448. IP(regs)++;
  449. pushw(ssp, sp, get_vflags(regs));
  450. VM86_FAULT_RETURN;
  451. /* popf */
  452. case 0x9d:
  453. SP(regs) += 2;
  454. IP(regs)++;
  455. CHECK_IF_IN_TRAP
  456. set_vflags_short(popw(ssp, sp), regs);
  457. VM86_FAULT_RETURN;
  458. /* int xx */
  459. case 0xcd: {
  460.         int intno=popb(csp, ip);
  461. IP(regs) += 2;
  462. if (VMPI.vm86dbg_active) {
  463. if ( (1 << (intno &7)) & VMPI.vm86dbg_intxxtab[intno >> 3] )
  464. return_to_32bit(regs, VM86_INTx + (intno << 8));
  465. }
  466. do_int(regs, intno, ssp, sp);
  467. return;
  468. }
  469. /* iret */
  470. case 0xcf:
  471. SP(regs) += 6;
  472. IP(regs) = popw(ssp, sp);
  473. regs->cs = popw(ssp, sp);
  474. CHECK_IF_IN_TRAP
  475. set_vflags_short(popw(ssp, sp), regs);
  476. VM86_FAULT_RETURN;
  477. /* cli */
  478. case 0xfa:
  479. IP(regs)++;
  480. clear_IF(regs);
  481. VM86_FAULT_RETURN;
  482. /* sti */
  483. /*
  484.  * Damn. This is incorrect: the 'sti' instruction should actually
  485.  * enable interrupts after the /next/ instruction. Not good.
  486.  *
  487.  * Probably needs some horsing around with the TF flag. Aiee..
  488.  */
  489. case 0xfb:
  490. IP(regs)++;
  491. set_IF(regs);
  492. VM86_FAULT_RETURN;
  493. default:
  494. return_to_32bit(regs, VM86_UNKNOWN);
  495. }
  496. }
  497. /* ---------------- vm86 special IRQ passing stuff ----------------- */
  498. #define VM86_IRQNAME "vm86irq"
  499. static struct vm86_irqs {
  500. struct task_struct *tsk;
  501. int sig;
  502. } vm86_irqs[16];
  503. static int irqbits;
  504. #define ALLOWED_SIGS ( 1 /* 0 = don't send a signal */ 
  505. | (1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGIO)  | (1 << SIGURG) 
  506. | (1 << SIGUNUSED) )
  507. static void irq_handler(int intno, void *dev_id, struct pt_regs * regs) {
  508. int irq_bit;
  509. unsigned long flags;
  510. save_flags(flags);
  511. cli();
  512. irq_bit = 1 << intno;
  513. if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk)
  514. goto out;
  515. irqbits |= irq_bit;
  516. if (vm86_irqs[intno].sig)
  517. send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1);
  518. /* else user will poll for IRQs */
  519. out:
  520. restore_flags(flags);
  521. }
  522. static inline void free_vm86_irq(int irqnumber)
  523. {
  524. free_irq(irqnumber,0);
  525. vm86_irqs[irqnumber].tsk = 0;
  526. irqbits &= ~(1 << irqnumber);
  527. }
  528. static inline int task_valid(struct task_struct *tsk)
  529. {
  530. struct task_struct *p;
  531. int ret = 0;
  532. read_lock(&tasklist_lock);
  533. for_each_task(p) {
  534. if ((p == tsk) && (p->sig)) {
  535. ret = 1;
  536. break;
  537. }
  538. }
  539. read_unlock(&tasklist_lock);
  540. return ret;
  541. }
  542. void release_x86_irqs(struct task_struct *task)
  543. {
  544. int i;
  545. for (i=3; i<16; i++)
  546.     if (vm86_irqs[i].tsk == task)
  547. free_vm86_irq(i);
  548. }
  549. static inline void handle_irq_zombies(void)
  550. {
  551. int i;
  552. for (i=3; i<16; i++) {
  553. if (vm86_irqs[i].tsk) {
  554. if (task_valid(vm86_irqs[i].tsk)) continue;
  555. free_vm86_irq(i);
  556. }
  557. }
  558. }
  559. static inline int get_and_reset_irq(int irqnumber)
  560. {
  561. int bit;
  562. unsigned long flags;
  563. if ( (irqnumber<3) || (irqnumber>15) ) return 0;
  564. if (vm86_irqs[irqnumber].tsk != current) return 0;
  565. save_flags(flags);
  566. cli();
  567. bit = irqbits & (1 << irqnumber);
  568. irqbits &= ~bit;
  569. restore_flags(flags);
  570. return bit;
  571. }
  572. static int do_vm86_irq_handling(int subfunction, int irqnumber)
  573. {
  574. int ret;
  575. switch (subfunction) {
  576. case VM86_GET_AND_RESET_IRQ: {
  577. return get_and_reset_irq(irqnumber);
  578. }
  579. case VM86_GET_IRQ_BITS: {
  580. return irqbits;
  581. }
  582. case VM86_REQUEST_IRQ: {
  583. int sig = irqnumber >> 8;
  584. int irq = irqnumber & 255;
  585. handle_irq_zombies();
  586. if (!capable(CAP_SYS_ADMIN)) return -EPERM;
  587. if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM;
  588. if ( (irq<3) || (irq>15) ) return -EPERM;
  589. if (vm86_irqs[irq].tsk) return -EPERM;
  590. ret = request_irq(irq, &irq_handler, 0, VM86_IRQNAME, 0);
  591. if (ret) return ret;
  592. vm86_irqs[irq].sig = sig;
  593. vm86_irqs[irq].tsk = current;
  594. return irq;
  595. }
  596. case  VM86_FREE_IRQ: {
  597. handle_irq_zombies();
  598. if ( (irqnumber<3) || (irqnumber>15) ) return -EPERM;
  599. if (!vm86_irqs[irqnumber].tsk) return 0;
  600. if (vm86_irqs[irqnumber].tsk != current) return -EPERM;
  601. free_vm86_irq(irqnumber);
  602. return 0;
  603. }
  604. }
  605. return -EINVAL;
  606. }