home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / m68k / ptrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  5.6 KB  |  230 lines

  1. /*
  2.  *  linux/m68k/ptrace.c
  3.  *
  4.  *  Copyright (C) 1994 by Hamish Macdonald
  5.  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
  6.  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
  7.  *
  8.  * This file is subject to the terms and conditions of the GNU General
  9.  * Public License.  See the file README.legal in the main directory of
  10.  * this archive for more details.
  11.  */
  12.  
  13. #include <asm/segment.h>
  14.  
  15. #include <linux/sched.h>
  16. #include <linux/mm.h>
  17. #include <linux/ptrace.h>
  18. #include <linux/errno.h>
  19. #include <linux/bootinfo.h>
  20.  
  21. /*
  22.  * This routine gets a long from any process space by following the page
  23.  * tables. NOTE! You should check that the long isn't on a page boundary,
  24.  * and that it is in the task area before calling this: this routine does
  25.  * no checking.
  26.  *
  27.  */
  28. static unsigned long get_long(struct task_struct * tsk,
  29.     unsigned long addr)
  30. {
  31.     unsigned long page, *ptrp;
  32.  
  33. repeat:
  34.     page = tsk->tss.pagedir_v[L1_INDEX(addr)];
  35.     if (!(page & PAGE_TABLE)) {
  36.         do_no_page(0,addr,tsk,0);
  37.         goto repeat;
  38.     }
  39.     ptrp = (unsigned long *)PTOV(page & TABLE_MASK);
  40.     page = ptrp[L2_INDEX(addr)];
  41.     if (!(page & PAGE_TABLE)) {
  42.         do_no_page(0,addr,tsk,0);
  43.         goto repeat;
  44.     }
  45.     page = PTOV(page & PAGE_MASK);
  46.     page += PAGE_PTR(addr);
  47.     page = *(unsigned long *)page;
  48.     if (!(page & PAGE_PRESENT)) {
  49.         do_no_page(0,addr,tsk,0);
  50.         goto repeat;
  51.     }
  52.     page = PTOV(page & PAGE_MASK);
  53.     page += addr & ~PAGE_MASK;
  54.     return *(unsigned long *) page;
  55. }
  56.  
  57. /*
  58.  * This routine puts a long into any process space by following the page
  59.  * tables. NOTE! You should check that the long isn't on a page boundary,
  60.  * and that it is in the task area before calling this: this routine does
  61.  * no checking.
  62.  *
  63.  * Now keeps R/W state of page so that a text page stays readonly
  64.  * even if a debugger scribbles breakpoints into it.  -M.U-
  65.  */
  66. static void put_long(struct task_struct * tsk, unsigned long addr,
  67.     unsigned long data)
  68. {
  69.     unsigned long page, pte = 0, *ptrp;
  70.     int readonly = 0;
  71.  
  72. repeat:
  73.     page = tsk->tss.pagedir_v[L1_INDEX(addr)];
  74.     if (!(page & PAGE_TABLE)) {
  75.         do_no_page(0,addr,tsk,0);
  76.         goto repeat;
  77.     }
  78.     ptrp = (unsigned long *)PTOV(page & TABLE_MASK);
  79.     page = ptrp[L2_INDEX(addr)];
  80.     if (!(page & PAGE_TABLE)) {
  81.         do_no_page(0,addr,tsk,0);
  82.         goto repeat;
  83.     }
  84.     page = PTOV(page & PAGE_MASK);
  85.     page += PAGE_PTR(addr);
  86.     pte = page;
  87.     page = *(unsigned long *)page;
  88.     if (!(page & PAGE_PRESENT)) {
  89.         do_no_page(0 /* PAGE_RW */ ,addr,tsk,0);
  90.         goto repeat;
  91.     }
  92.     if (!PAGE_IS_RW(page)) {
  93.         if(!(page & PAGE_COW))
  94.             readonly = 1;
  95.         do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0);
  96.         goto repeat;
  97.     }
  98. /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
  99.     *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
  100.     page = PTOV(page & PAGE_MASK);
  101.     page += addr & ~PAGE_MASK;
  102.     *(unsigned long *) page = data;
  103.     if(readonly) {
  104.         *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
  105.         invalidate();
  106.     }
  107. }
  108.  
  109. /*
  110.  * This routine checks the page boundaries, and that the offset is
  111.  * within the task area. It then calls get_long() to read a long.
  112.  */
  113. int ptrace_read_long(struct task_struct * tsk, long addr,
  114.              unsigned long * result)
  115. {
  116.     unsigned long low,high;
  117.  
  118.     if (addr > TASK_SIZE-sizeof(long))
  119.         return -EIO;
  120.     if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
  121.         low = get_long(tsk,addr & ~(sizeof(long)-1));
  122.         high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
  123.         switch (addr & (sizeof(long)-1)) {
  124.             case 1:
  125.                 low >>= 8;
  126.                 low |= high << 24;
  127.                 break;
  128.             case 2:
  129.                 low >>= 16;
  130.                 low |= high << 16;
  131.                 break;
  132.             case 3:
  133.                 low >>= 24;
  134.                 low |= high << 8;
  135.                 break;
  136.         }
  137.         *result = low;
  138.     } else
  139.         *result = get_long(tsk,addr);
  140.     return 0;
  141. }
  142.  
  143. /*
  144.  * This routine checks the page boundaries, and that the offset is
  145.  * within the task area. It then calls put_long() to write a long.
  146.  */
  147. int ptrace_write_long(struct task_struct * tsk, long addr, long data)
  148. {
  149.     unsigned long low,high;
  150.  
  151.     if (addr > TASK_SIZE-sizeof(long))
  152.         return -EIO;
  153.     if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
  154.         low = get_long(tsk,addr & ~(sizeof(long)-1));
  155.         high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
  156.         switch (addr & (sizeof(long)-1)) {
  157.             case 0: /* shouldn't happen, but safety first */
  158.                 low = data;
  159.                 break;
  160.             case 1:
  161.                 low &= 0x000000ff;
  162.                 low |= data << 8;
  163.                 high &= ~0xff;
  164.                 high |= data >> 24;
  165.                 break;
  166.             case 2:
  167.                 low &= 0x0000ffff;
  168.                 low |= data << 16;
  169.                 high &= ~0xffff;
  170.                 high |= data >> 16;
  171.                 break;
  172.             case 3:
  173.                 low &= 0x00ffffff;
  174.                 low |= data << 24;
  175.                 high &= ~0xffffff;
  176.                 high |= data >> 8;
  177.                 break;
  178.         }
  179.         put_long(tsk,addr & ~(sizeof(long)-1),low);
  180.         put_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1),high);
  181.     } else
  182.         put_long(tsk,addr,data);
  183.     return 0;
  184. }
  185.  
  186. int ptrace_peekusr (struct task_struct *tsk, long addr, long data)
  187. {
  188.     unsigned long tmp;
  189.     int res;
  190.  
  191.     if ((addr & 3) || addr < 0 || addr > 18*sizeof(long))
  192.         return -EIO;
  193.  
  194.     res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
  195.     if (res)
  196.         return res;
  197.     tmp = 0;  /* Default return condition */
  198.     if(addr < 19*sizeof(long)) {
  199.         addr = addr >> 2; /* temporary hack. */
  200.         tmp = ptrace_get_stack_long(tsk, sizeof(long)*addr);
  201.         if (addr == PT_SR)
  202.             tmp &= 0xffff;
  203.     }
  204.     put_fs_long(tmp,(unsigned long *) data);
  205.     return 0;
  206. }
  207.  
  208. int ptrace_pokeusr(struct task_struct *tsk, long addr, long data)
  209. {
  210.     if ((addr & 3) || addr < 0 || addr > 18*sizeof(long))
  211.         return -EIO;
  212.  
  213.     addr = addr >> 2; /* temporary hack. */
  214.  
  215.     if (addr == PT_ORIG_D0)
  216.         return -EIO;
  217.     if (addr == PT_SR) {
  218.         data &= SR_MASK;
  219.         data |= ptrace_get_stack_long(tsk, PT_SR*sizeof(long)) & ~SR_MASK;
  220.     }
  221.     /* Do not allow the user to set the debug register for kernel
  222.        address space */
  223.     if(addr < 19){
  224.         if (ptrace_put_stack_long(tsk, sizeof(long)*addr, data))
  225.             return -EIO;
  226.         return 0;
  227.     };
  228.     return -EIO;
  229. }
  230.