aboutsummaryrefslogtreecommitdiff
path: root/core/sys/linux/helpers.odin
blob: aefc1179e6aac5982251ab698b45067da277081c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#+build linux
#+no-instrumentation
package linux

import "base:intrinsics"

// Note(flysand): In the case of syscall let's get rid of extra
// casting. First of all, let these syscalls return int, because
// we'll need to check for Errno anyway. Second of all
// most parameters are going to be trivially-castable to
// uintptr, so we'll have that.

@(private)
syscall0 :: #force_inline proc "contextless" (nr: uintptr) -> int {
	return int(intrinsics.syscall(nr))
}

@(private)
syscall1 :: #force_inline proc "contextless" (nr: uintptr, p1: $T) -> int
where
	size_of(p1) <= size_of(uintptr)
{
	return int(intrinsics.syscall(nr, uintptr(p1)))
}

@(private)
syscall2 :: #force_inline proc "contextless" (nr: uintptr,p1: $T1, p2: $T2) -> int
where
	size_of(p1) <= size_of(uintptr),
	size_of(p2) <= size_of(uintptr) 
{
	return int(intrinsics.syscall(nr, uintptr(p1), uintptr(p2)))
}

@(private)
syscall3 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3) -> int
where
	size_of(p1) <= size_of(uintptr),
	size_of(p2) <= size_of(uintptr),
	size_of(p3) <= size_of(uintptr)
{
	return int(intrinsics.syscall(nr,
		uintptr(p1),
		uintptr(p2),
		uintptr(p3),
	))
}

@(private)
syscall4 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4) -> int
where
	size_of(p1) <= size_of(uintptr),
	size_of(p2) <= size_of(uintptr),
	size_of(p3) <= size_of(uintptr),
	size_of(p4) <= size_of(uintptr)
{
	return int(intrinsics.syscall(nr,
		uintptr(p1),
		uintptr(p2),
		uintptr(p3),
		uintptr(p4),
	))
}

@(private)
syscall5 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4, p5: $T5) -> int
where
	size_of(p1) <= size_of(uintptr),
	size_of(p2) <= size_of(uintptr),
	size_of(p3) <= size_of(uintptr),
	size_of(p4) <= size_of(uintptr),
	size_of(p5) <= size_of(uintptr)
{
	return int(intrinsics.syscall(nr,
		uintptr(p1),
		uintptr(p2),
		uintptr(p3),
		uintptr(p4),
		uintptr(p5),
	))
}

@(private)
syscall6 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4, p5: $T5, p6: $T6) -> int
where
	size_of(p1) <= size_of(uintptr),
	size_of(p2) <= size_of(uintptr),
	size_of(p3) <= size_of(uintptr),
	size_of(p4) <= size_of(uintptr),
	size_of(p5) <= size_of(uintptr),
	size_of(p6) <= size_of(uintptr)
{
	return int(intrinsics.syscall(nr,
		uintptr(p1),
		uintptr(p2),
		uintptr(p3),
		uintptr(p4),
		uintptr(p5),
		uintptr(p6),
	))
}

syscall :: proc {syscall0, syscall1, syscall2, syscall3, syscall4, syscall5, syscall6}

// Note(bumbread): This should shrug off a few lines from every syscall.
// Since not any type can be trivially casted to another type, we take two arguments:
// the final type to cast to, and the type to transmute to before casting.
// One transmute + one cast should allow us to get to any type we might want
// to return from a syscall wrapper.
@(private)
errno_unwrap3 :: #force_inline proc "contextless" (ret: $P, $T: typeid, $U: typeid) -> (T, Errno)
where
	intrinsics.type_is_ordered_numeric(P)
{
	if ret < 0 {
		default_value: T
		return default_value, Errno(-ret)
	} else {
		return T(transmute(U)ret), Errno(.NONE)
	}
}

@(private)
errno_unwrap2 :: #force_inline proc "contextless" (ret: $P, $T: typeid) -> (T, Errno) {
	if ret < 0 {
		default_value: T
		return default_value, Errno(-ret)
	} else {
		return T(ret), Errno(.NONE)
	}
}

@(private)
errno_unwrap :: proc {errno_unwrap2, errno_unwrap3}

// Note(flysand): 32-bit architectures sometimes take in a 64-bit argument in a
// register pair. This function should help me avoid typing the same code a few times..
when size_of(int) == 4 {
	// xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer
	@(private)
	compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) {
		no_sign := uint(a)
		hi = uint(no_sign >> 32)
		lo = uint(no_sign & 0xffff_ffff)
		return
	}
} else {
	// ... and on 64-bit architectures it's just a long
	@(private)
	compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (uint) {
		return uint(a)
	}
}