| 1 | /****************************************************************************** | 
|---|
| 2 |  * common/compat/grant_table.c | 
|---|
| 3 |  * | 
|---|
| 4 |  */ | 
|---|
| 5 |  | 
|---|
| 6 | #include <compat/grant_table.h> | 
|---|
| 7 |  | 
|---|
| 8 | #define xen_grant_entry grant_entry | 
|---|
| 9 | CHECK_grant_entry; | 
|---|
| 10 | #undef xen_grant_entry | 
|---|
| 11 |  | 
|---|
| 12 | #define xen_gnttab_map_grant_ref gnttab_map_grant_ref | 
|---|
| 13 | CHECK_gnttab_map_grant_ref; | 
|---|
| 14 | #undef xen_gnttab_map_grant_ref | 
|---|
| 15 |  | 
|---|
| 16 | #define xen_gnttab_unmap_grant_ref gnttab_unmap_grant_ref | 
|---|
| 17 | CHECK_gnttab_unmap_grant_ref; | 
|---|
| 18 | #undef xen_gnttab_unmap_grant_ref | 
|---|
| 19 |  | 
|---|
| 20 | DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_compat_t); | 
|---|
| 21 | DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_compat_t); | 
|---|
| 22 | DEFINE_XEN_GUEST_HANDLE(gnttab_copy_compat_t); | 
|---|
| 23 |  | 
|---|
| 24 | #define xen_gnttab_dump_table gnttab_dump_table | 
|---|
| 25 | CHECK_gnttab_dump_table; | 
|---|
| 26 | #undef xen_gnttab_dump_table | 
|---|
| 27 |  | 
|---|
| 28 | int compat_grant_table_op(unsigned int cmd, | 
|---|
| 29 |                           XEN_GUEST_HANDLE(void) cmp_uop, | 
|---|
| 30 |                           unsigned int count) | 
|---|
| 31 | { | 
|---|
| 32 |     int rc = 0; | 
|---|
| 33 |     unsigned int i; | 
|---|
| 34 |  | 
|---|
| 35 |     switch ( cmd ) | 
|---|
| 36 |     { | 
|---|
| 37 | #define CASE(name) \ | 
|---|
| 38 |     case GNTTABOP_##name: \ | 
|---|
| 39 |         if ( unlikely(!guest_handle_okay(guest_handle_cast(cmp_uop, \ | 
|---|
| 40 |                                                            gnttab_##name##_compat_t), \ | 
|---|
| 41 |                                          count)) ) \ | 
|---|
| 42 |             rc = -EFAULT; \ | 
|---|
| 43 |         break | 
|---|
| 44 |  | 
|---|
| 45 | #ifndef CHECK_gnttab_map_grant_ref | 
|---|
| 46 |     CASE(map_grant_ref); | 
|---|
| 47 | #endif | 
|---|
| 48 |  | 
|---|
| 49 | #ifndef CHECK_gnttab_unmap_grant_ref | 
|---|
| 50 |     CASE(unmap_grant_ref); | 
|---|
| 51 | #endif | 
|---|
| 52 |  | 
|---|
| 53 | #ifndef CHECK_gnttab_setup_table | 
|---|
| 54 |     CASE(setup_table); | 
|---|
| 55 | #endif | 
|---|
| 56 |  | 
|---|
| 57 | #ifndef CHECK_gnttab_transfer | 
|---|
| 58 |     CASE(transfer); | 
|---|
| 59 | #endif | 
|---|
| 60 |  | 
|---|
| 61 | #ifndef CHECK_gnttab_copy | 
|---|
| 62 |     CASE(copy); | 
|---|
| 63 | #endif | 
|---|
| 64 |  | 
|---|
| 65 | #ifndef CHECK_gnttab_dump_table | 
|---|
| 66 |     CASE(dump_table); | 
|---|
| 67 | #endif | 
|---|
| 68 |  | 
|---|
| 69 | #undef CASE | 
|---|
| 70 |     default: | 
|---|
| 71 |         return do_grant_table_op(cmd, cmp_uop, count); | 
|---|
| 72 |     } | 
|---|
| 73 |  | 
|---|
| 74 |     if ( count > 512 ) | 
|---|
| 75 |         rc = -EINVAL; | 
|---|
| 76 |  | 
|---|
| 77 |     for ( i = 0; i < count && rc == 0; ) | 
|---|
| 78 |     { | 
|---|
| 79 |         unsigned int n; | 
|---|
| 80 |         union { | 
|---|
| 81 |             XEN_GUEST_HANDLE(void) uop; | 
|---|
| 82 |             struct gnttab_setup_table *setup; | 
|---|
| 83 |             struct gnttab_transfer *xfer; | 
|---|
| 84 |             struct gnttab_copy *copy; | 
|---|
| 85 |         } nat; | 
|---|
| 86 |         union { | 
|---|
| 87 |             struct compat_gnttab_setup_table setup; | 
|---|
| 88 |             struct compat_gnttab_transfer xfer; | 
|---|
| 89 |             struct compat_gnttab_copy copy; | 
|---|
| 90 |         } cmp; | 
|---|
| 91 |  | 
|---|
| 92 |         set_xen_guest_handle(nat.uop, (void *)COMPAT_ARG_XLAT_VIRT_START(current->vcpu_id)); | 
|---|
| 93 |         switch ( cmd ) | 
|---|
| 94 |         { | 
|---|
| 95 |         case GNTTABOP_setup_table: | 
|---|
| 96 |             if ( unlikely(count > 1) ) | 
|---|
| 97 |                 rc = -EINVAL; | 
|---|
| 98 |             else if ( unlikely(__copy_from_guest(&cmp.setup, cmp_uop, 1)) ) | 
|---|
| 99 |                 rc = -EFAULT; | 
|---|
| 100 |             else if ( unlikely(!compat_handle_okay(cmp.setup.frame_list, cmp.setup.nr_frames)) ) | 
|---|
| 101 |                 rc = -EFAULT; | 
|---|
| 102 |             else | 
|---|
| 103 |             { | 
|---|
| 104 |                 BUG_ON((COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) / sizeof(*nat.setup->frame_list.p) < max_nr_grant_frames); | 
|---|
| 105 | #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \ | 
|---|
| 106 |                 set_xen_guest_handle((_d_)->frame_list, (unsigned long *)(nat.setup + 1)) | 
|---|
| 107 |                 XLAT_gnttab_setup_table(nat.setup, &cmp.setup); | 
|---|
| 108 | #undef XLAT_gnttab_setup_table_HNDL_frame_list | 
|---|
| 109 |                 rc = gnttab_setup_table(guest_handle_cast(nat.uop, gnttab_setup_table_t), 1); | 
|---|
| 110 |             } | 
|---|
| 111 |             if ( rc == 0 ) | 
|---|
| 112 |             { | 
|---|
| 113 | #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \ | 
|---|
| 114 |                 do \ | 
|---|
| 115 |                 { \ | 
|---|
| 116 |                     if ( (_s_)->status == GNTST_okay ) \ | 
|---|
| 117 |                     { \ | 
|---|
| 118 |                         for ( i = 0; i < (_s_)->nr_frames; ++i ) \ | 
|---|
| 119 |                         { \ | 
|---|
| 120 |                             unsigned int frame = (_s_)->frame_list.p[i]; \ | 
|---|
| 121 |                             BUG_ON(frame != (_s_)->frame_list.p[i]); \ | 
|---|
| 122 |                             (void)__copy_to_compat_offset((_d_)->frame_list, i, &frame, 1); \ | 
|---|
| 123 |                         } \ | 
|---|
| 124 |                     } \ | 
|---|
| 125 |                 } while (0) | 
|---|
| 126 |                 XLAT_gnttab_setup_table(&cmp.setup, nat.setup); | 
|---|
| 127 | #undef XLAT_gnttab_setup_table_HNDL_frame_list | 
|---|
| 128 |                 if ( unlikely(__copy_to_guest(cmp_uop, &cmp.setup, 1)) ) | 
|---|
| 129 |                     rc = -EFAULT; | 
|---|
| 130 |                 else | 
|---|
| 131 |                     i = 1; | 
|---|
| 132 |             } | 
|---|
| 133 |             break; | 
|---|
| 134 |  | 
|---|
| 135 |         case GNTTABOP_transfer: | 
|---|
| 136 |             for ( n = 0; n < COMPAT_ARG_XLAT_SIZE / sizeof(*nat.xfer) && i < count && rc == 0; ++i, ++n ) | 
|---|
| 137 |             { | 
|---|
| 138 |                 if ( unlikely(__copy_from_guest_offset(&cmp.xfer, cmp_uop, i, 1)) ) | 
|---|
| 139 |                     rc = -EFAULT; | 
|---|
| 140 |                 else | 
|---|
| 141 |                 { | 
|---|
| 142 |                     XLAT_gnttab_transfer(nat.xfer + n, &cmp.xfer); | 
|---|
| 143 |                 } | 
|---|
| 144 |             } | 
|---|
| 145 |             if ( rc == 0 ) | 
|---|
| 146 |                 rc = gnttab_transfer(guest_handle_cast(nat.uop, gnttab_transfer_t), n); | 
|---|
| 147 |             if ( rc == 0 ) | 
|---|
| 148 |             { | 
|---|
| 149 |                 XEN_GUEST_HANDLE(gnttab_transfer_compat_t) xfer; | 
|---|
| 150 |  | 
|---|
| 151 |                 xfer = guest_handle_cast(cmp_uop, gnttab_transfer_compat_t); | 
|---|
| 152 |                 guest_handle_add_offset(xfer, i); | 
|---|
| 153 |                 while ( n-- ) | 
|---|
| 154 |                 { | 
|---|
| 155 |                     guest_handle_add_offset(xfer, -1); | 
|---|
| 156 |                     if ( __copy_field_to_guest(xfer, nat.xfer, status) ) | 
|---|
| 157 |                         rc = -EFAULT; | 
|---|
| 158 |                 } | 
|---|
| 159 |             } | 
|---|
| 160 |             break; | 
|---|
| 161 |  | 
|---|
| 162 |         case GNTTABOP_copy: | 
|---|
| 163 |             for ( n = 0; n < COMPAT_ARG_XLAT_SIZE / sizeof(*nat.copy) && i < count && rc == 0; ++i, ++n ) | 
|---|
| 164 |             { | 
|---|
| 165 |                 if ( unlikely(__copy_from_guest_offset(&cmp.copy, cmp_uop, i, 1)) ) | 
|---|
| 166 |                     rc = -EFAULT; | 
|---|
| 167 |                 else | 
|---|
| 168 |                 { | 
|---|
| 169 |                     enum XLAT_gnttab_copy_source_u source_u; | 
|---|
| 170 |                     enum XLAT_gnttab_copy_dest_u dest_u; | 
|---|
| 171 |  | 
|---|
| 172 |                     if ( cmp.copy.flags & GNTCOPY_source_gref ) | 
|---|
| 173 |                         source_u = XLAT_gnttab_copy_source_u_ref; | 
|---|
| 174 |                     else | 
|---|
| 175 |                         source_u = XLAT_gnttab_copy_source_u_gmfn; | 
|---|
| 176 |                     if ( cmp.copy.flags & GNTCOPY_dest_gref ) | 
|---|
| 177 |                         dest_u = XLAT_gnttab_copy_dest_u_ref; | 
|---|
| 178 |                     else | 
|---|
| 179 |                         dest_u = XLAT_gnttab_copy_dest_u_gmfn; | 
|---|
| 180 |                     XLAT_gnttab_copy(nat.copy + n, &cmp.copy); | 
|---|
| 181 |                 } | 
|---|
| 182 |             } | 
|---|
| 183 |             if ( rc == 0 ) | 
|---|
| 184 |                 rc = gnttab_copy(guest_handle_cast(nat.uop, gnttab_copy_t), n); | 
|---|
| 185 |             if ( rc == 0 ) | 
|---|
| 186 |             { | 
|---|
| 187 |                 XEN_GUEST_HANDLE(gnttab_copy_compat_t) copy; | 
|---|
| 188 |  | 
|---|
| 189 |                 copy = guest_handle_cast(cmp_uop, gnttab_copy_compat_t); | 
|---|
| 190 |                 guest_handle_add_offset(copy, i); | 
|---|
| 191 |                 while ( n-- ) | 
|---|
| 192 |                 { | 
|---|
| 193 |                     guest_handle_add_offset(copy, -1); | 
|---|
| 194 |                     if ( __copy_field_to_guest(copy, nat.copy, status) ) | 
|---|
| 195 |                         rc = -EFAULT; | 
|---|
| 196 |                 } | 
|---|
| 197 |             } | 
|---|
| 198 |             break; | 
|---|
| 199 |  | 
|---|
| 200 |         default: | 
|---|
| 201 |             domain_crash(current->domain); | 
|---|
| 202 |             break; | 
|---|
| 203 |         } | 
|---|
| 204 |     } | 
|---|
| 205 |  | 
|---|
| 206 |     return rc; | 
|---|
| 207 | } | 
|---|
| 208 |  | 
|---|
| 209 | /* | 
|---|
| 210 |  * Local variables: | 
|---|
| 211 |  * mode: C | 
|---|
| 212 |  * c-set-style: "BSD" | 
|---|
| 213 |  * c-basic-offset: 4 | 
|---|
| 214 |  * tab-width: 4 | 
|---|
| 215 |  * indent-tabs-mode: nil | 
|---|
| 216 |  * End: | 
|---|
| 217 |  */ | 
|---|