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