1 /*
2 * Copyright (C) 2006-2007 XenSource Ltd.
3 * Copyright (C) 2008 Citrix Ltd.
4 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; version 2.1 only. with the special
9 * exception on linking described in file LICENSE.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 */
16
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <sys/mman.h>
20 #include <string.h>
21 #include <errno.h>
22 #include "mmap_stubs.h"
23
24 #include <caml/mlvalues.h>
25 #include <caml/memory.h>
26 #include <caml/alloc.h>
27 #include <caml/custom.h>
28 #include <caml/fail.h>
29 #include <caml/callback.h>
30
31 #define Intf_val(a) ((struct mmap_interface *) a)
32
mmap_interface_init(struct mmap_interface * intf,int fd,int pflag,int mflag,int len,int offset)33 static int mmap_interface_init(struct mmap_interface *intf,
34 int fd, int pflag, int mflag,
35 int len, int offset)
36 {
37 intf->len = len;
38 intf->addr = mmap(NULL, len, pflag, mflag, fd, offset);
39 return (intf->addr == MAP_FAILED) ? errno : 0;
40 }
41
stub_mmap_init(value fd,value pflag,value mflag,value len,value offset)42 CAMLprim value stub_mmap_init(value fd, value pflag, value mflag,
43 value len, value offset)
44 {
45 CAMLparam5(fd, pflag, mflag, len, offset);
46 CAMLlocal1(result);
47 int c_pflag, c_mflag;
48
49 switch (Int_val(pflag)) {
50 case 0: c_pflag = PROT_READ; break;
51 case 1: c_pflag = PROT_WRITE; break;
52 case 2: c_pflag = PROT_READ|PROT_WRITE; break;
53 default: caml_invalid_argument("protectiontype");
54 }
55
56 switch (Int_val(mflag)) {
57 case 0: c_mflag = MAP_SHARED; break;
58 case 1: c_mflag = MAP_PRIVATE; break;
59 default: caml_invalid_argument("maptype");
60 }
61
62 result = caml_alloc(sizeof(struct mmap_interface), Abstract_tag);
63
64 if (mmap_interface_init(Intf_val(result), Int_val(fd),
65 c_pflag, c_mflag,
66 Int_val(len), Int_val(offset)))
67 caml_failwith("mmap");
68 CAMLreturn(result);
69 }
70
stub_mmap_final(value intf)71 CAMLprim value stub_mmap_final(value intf)
72 {
73 CAMLparam1(intf);
74
75 if (Intf_val(intf)->addr != MAP_FAILED)
76 munmap(Intf_val(intf)->addr, Intf_val(intf)->len);
77 Intf_val(intf)->addr = MAP_FAILED;
78
79 CAMLreturn(Val_unit);
80 }
81
stub_mmap_read(value intf,value start,value len)82 CAMLprim value stub_mmap_read(value intf, value start, value len)
83 {
84 CAMLparam3(intf, start, len);
85 CAMLlocal1(data);
86 int c_start;
87 int c_len;
88
89 c_start = Int_val(start);
90 c_len = Int_val(len);
91
92 if (c_start > Intf_val(intf)->len)
93 caml_invalid_argument("start invalid");
94 if (c_start + c_len > Intf_val(intf)->len)
95 caml_invalid_argument("len invalid");
96
97 data = caml_alloc_string(c_len);
98 memcpy((char *) data, Intf_val(intf)->addr + c_start, c_len);
99
100 CAMLreturn(data);
101 }
102
stub_mmap_write(value intf,value data,value start,value len)103 CAMLprim value stub_mmap_write(value intf, value data,
104 value start, value len)
105 {
106 CAMLparam4(intf, data, start, len);
107 int c_start;
108 int c_len;
109
110 c_start = Int_val(start);
111 c_len = Int_val(len);
112
113 if (c_start > Intf_val(intf)->len)
114 caml_invalid_argument("start invalid");
115 if (c_start + c_len > Intf_val(intf)->len)
116 caml_invalid_argument("len invalid");
117
118 memcpy(Intf_val(intf)->addr + c_start, (char *) data, c_len);
119
120 CAMLreturn(Val_unit);
121 }
122
stub_mmap_getpagesize(value unit)123 CAMLprim value stub_mmap_getpagesize(value unit)
124 {
125 CAMLparam1(unit);
126 CAMLlocal1(data);
127
128 data = Val_int(getpagesize());
129 CAMLreturn(data);
130 }
131