| 928 | } |
| 929 | |
| 930 | int |
| 931 | fpusetxstate(struct thread *td, char *xfpustate, size_t xfpustate_size) |
| 932 | { |
| 933 | struct xstate_hdr *hdr, *ehdr; |
| 934 | size_t len, max_len; |
| 935 | uint64_t bv; |
| 936 | |
| 937 | /* XXXKIB should we clear all extended state in xstate_bv instead ? */ |
| 938 | if (xfpustate == NULL) |
| 939 | return (0); |
| 940 | if (!use_xsave) |
| 941 | return (EOPNOTSUPP); |
| 942 | |
| 943 | len = xfpustate_size; |
| 944 | if (len < sizeof(struct xstate_hdr)) |
| 945 | return (EINVAL); |
| 946 | max_len = cpu_max_ext_state_size - sizeof(struct savefpu); |
| 947 | if (len > max_len) |
| 948 | return (EINVAL); |
| 949 | |
| 950 | ehdr = (struct xstate_hdr *)xfpustate; |
| 951 | bv = ehdr->xstate_bv; |
| 952 | |
| 953 | /* |
| 954 | * Avoid #gp. |
| 955 | */ |
| 956 | if (bv & ~xsave_mask) |
| 957 | return (EINVAL); |
| 958 | |
| 959 | hdr = (struct xstate_hdr *)(get_pcb_user_save_td(td) + 1); |
| 960 | |
| 961 | hdr->xstate_bv = bv; |
| 962 | bcopy(xfpustate + sizeof(struct xstate_hdr), |
| 963 | (char *)(hdr + 1), len - sizeof(struct xstate_hdr)); |
| 964 | |
| 965 | return (0); |
| 966 | } |
| 967 | |
| 968 | /* |
| 969 | * Set the state of the FPU. |
no test coverage detected