Skip to content

Commit 104d401

Browse files
markdryangopherbot
authored andcommitted
unix: add riscv_hwprobe for riscv64
The riscv_hwprobe system call was introduced in Linux 6.4 and allows the caller to determine a number of interesting pieces of information about the underlying RISC-V CPUs, e.g., which extensions they support and whether they allow fast unaligned memory accesses. For more information please see: https://docs.kernel.org/riscv/hwprobe.html We also update linux/mksysnum.go to ensure that the generated syscall constants written to the zsysnum_linux_*.go files are always sorted by their syscall numbers in ascending order. Updates golang/go#61416 Change-Id: Iedb0a86adb65faac9061b9a5969ffa09eb5b303a Reviewed-on: https://go-review.googlesource.com/c/sys/+/510795 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]>
1 parent 70f4e40 commit 104d401

7 files changed

+173
-10
lines changed

unix/linux/mksysnum.go

+61-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"os"
1414
"os/exec"
1515
"regexp"
16+
"sort"
1617
"strconv"
1718
"strings"
1819
)
@@ -36,15 +37,15 @@ func plusBuildTags() string {
3637
return fmt.Sprintf("%s,%s", goarch, goos)
3738
}
3839

39-
func format(name string, num int, offset int) string {
40+
func format(name string, num int, offset int) (int, string) {
4041
if num > 999 {
4142
// ignore deprecated syscalls that are no longer implemented
4243
// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
43-
return ""
44+
return 0, ""
4445
}
4546
name = strings.ToUpper(name)
4647
num = num + offset
47-
return fmt.Sprintf(" SYS_%s = %d;\n", name, num)
48+
return num, fmt.Sprintf(" SYS_%s = %d;\n", name, num)
4849
}
4950

5051
func checkErr(err error) {
@@ -69,6 +70,36 @@ func (r *re) Match(exp string) bool {
6970
return false
7071
}
7172

73+
// syscallNum holds the syscall number and the string
74+
// we will write to the generated file.
75+
type syscallNum struct {
76+
num int
77+
declaration string
78+
}
79+
80+
// syscallNums is a slice of syscallNum sorted by the syscall number in ascending order.
81+
type syscallNums []syscallNum
82+
83+
// addSyscallNum adds the syscall declaration to syscallNums.
84+
func (nums *syscallNums) addSyscallNum(num int, declaration string) {
85+
if declaration == "" {
86+
return
87+
}
88+
if len(*nums) == 0 || (*nums)[len(*nums)-1].num <= num {
89+
// This is the most common case as the syscall declarations output by the preprocessor
90+
// are almost always sorted.
91+
*nums = append(*nums, syscallNum{num, declaration})
92+
return
93+
}
94+
i := sort.Search(len(*nums), func(i int) bool { return (*nums)[i].num >= num })
95+
96+
// Maintain the ordering in the preprocessor output when we have multiple definitions with
97+
// the same value. i cannot be > len(nums) - 1 as nums[len(nums)-1].num > num.
98+
for ; (*nums)[i].num == num; i++ {
99+
}
100+
*nums = append((*nums)[:i], append([]syscallNum{{num, declaration}}, (*nums)[i:]...)...)
101+
}
102+
72103
func main() {
73104
// Get the OS and architecture (using GOARCH_TARGET if it exists)
74105
goos = os.Getenv("GOOS")
@@ -100,11 +131,23 @@ func main() {
100131
fmt.Fprintf(os.Stderr, "can't run %s", cc)
101132
os.Exit(1)
102133
}
103-
text := ""
104134
s := bufio.NewScanner(strings.NewReader(string(cmd)))
105-
var offset, prev int
135+
var offset, prev, asOffset int
136+
var nums syscallNums
106137
for s.Scan() {
107138
t := re{str: s.Text()}
139+
140+
// The generated zsysnum_linux_*.go files for some platforms (arm64, loong64, riscv64)
141+
// treat SYS_ARCH_SPECIFIC_SYSCALL as if it's a syscall which it isn't. It's an offset.
142+
// However, as this constant is already part of the public API we leave it in place.
143+
// Lines of type SYS_ARCH_SPECIFIC_SYSCALL = 244 are thus processed twice, once to extract
144+
// the offset and once to add the constant.
145+
146+
if t.Match(`^#define __NR_arch_specific_syscall\s+([0-9]+)`) {
147+
// riscv: extract arch specific offset
148+
asOffset, _ = strconv.Atoi(t.sub[1]) // Make asOffset=0 if empty or non-numeric
149+
}
150+
108151
if t.Match(`^#define __NR_Linux\s+([0-9]+)`) {
109152
// mips/mips64: extract offset
110153
offset, _ = strconv.Atoi(t.sub[1]) // Make offset=0 if empty or non-numeric
@@ -118,24 +161,32 @@ func main() {
118161
} else if t.Match(`^#define __NR_(\w+)\s+([0-9]+)`) {
119162
prev, err = strconv.Atoi(t.sub[2])
120163
checkErr(err)
121-
text += format(t.sub[1], prev, offset)
164+
nums.addSyscallNum(format(t.sub[1], prev, offset))
122165
} else if t.Match(`^#define __NR3264_(\w+)\s+([0-9]+)`) {
123166
prev, err = strconv.Atoi(t.sub[2])
124167
checkErr(err)
125-
text += format(t.sub[1], prev, offset)
168+
nums.addSyscallNum(format(t.sub[1], prev, offset))
126169
} else if t.Match(`^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)`) {
127170
r2, err := strconv.Atoi(t.sub[2])
128171
checkErr(err)
129-
text += format(t.sub[1], prev+r2, offset)
172+
nums.addSyscallNum(format(t.sub[1], prev+r2, offset))
130173
} else if t.Match(`^#define __NR_(\w+)\s+\(__NR_(?:SYSCALL_BASE|Linux) \+ ([0-9]+)`) {
131174
r2, err := strconv.Atoi(t.sub[2])
132175
checkErr(err)
133-
text += format(t.sub[1], r2, offset)
176+
nums.addSyscallNum(format(t.sub[1], r2, offset))
177+
} else if asOffset != 0 && t.Match(`^#define __NR_(\w+)\s+\(__NR_arch_specific_syscall \+ ([0-9]+)`) {
178+
r2, err := strconv.Atoi(t.sub[2])
179+
checkErr(err)
180+
nums.addSyscallNum(format(t.sub[1], r2, asOffset))
134181
}
135182
}
136183
err = s.Err()
137184
checkErr(err)
138-
fmt.Printf(template, cmdLine(), goBuildTags(), plusBuildTags(), text)
185+
var text strings.Builder
186+
for _, num := range nums {
187+
text.WriteString(num.declaration)
188+
}
189+
fmt.Printf(template, cmdLine(), goBuildTags(), plusBuildTags(), text.String())
139190
}
140191

141192
const template = `// %s

unix/linux/types.go

+49
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,32 @@ struct my_can_bittiming_const {
426426
__u32 brp_max;
427427
__u32 brp_inc;
428428
};
429+
430+
#if defined(__riscv)
431+
#include <asm/hwprobe.h>
432+
#else
433+
434+
// copied from /usr/include/asm/hwprobe.h
435+
// values are not used but they need to be defined.
436+
437+
#define RISCV_HWPROBE_KEY_MVENDORID 0
438+
#define RISCV_HWPROBE_KEY_MARCHID 1
439+
#define RISCV_HWPROBE_KEY_MIMPID 2
440+
#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
441+
#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0)
442+
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
443+
#define RISCV_HWPROBE_IMA_FD (1 << 0)
444+
#define RISCV_HWPROBE_IMA_C (1 << 1)
445+
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
446+
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
447+
#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
448+
#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0)
449+
#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0)
450+
#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
451+
#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
452+
453+
struct riscv_hwprobe {};
454+
#endif
429455
*/
430456
import "C"
431457

@@ -5747,3 +5773,26 @@ const (
57475773
VIRTIO_NET_HDR_GSO_UDP_L4 = C.VIRTIO_NET_HDR_GSO_UDP_L4
57485774
VIRTIO_NET_HDR_GSO_ECN = C.VIRTIO_NET_HDR_GSO_ECN
57495775
)
5776+
5777+
type RISCVHWProbePairs C.struct_riscv_hwprobe
5778+
5779+
// Filtered out for non RISC-V architectures in mkpost.go
5780+
// generated by:
5781+
// perl -nlE '/^#define\s+(RISCV_HWPROBE_\w+)/ && say "$1 = C.$1"' /tmp/riscv64/include/asm/hwprobe.h
5782+
const (
5783+
RISCV_HWPROBE_KEY_MVENDORID = C.RISCV_HWPROBE_KEY_MVENDORID
5784+
RISCV_HWPROBE_KEY_MARCHID = C.RISCV_HWPROBE_KEY_MARCHID
5785+
RISCV_HWPROBE_KEY_MIMPID = C.RISCV_HWPROBE_KEY_MIMPID
5786+
RISCV_HWPROBE_KEY_BASE_BEHAVIOR = C.RISCV_HWPROBE_KEY_BASE_BEHAVIOR
5787+
RISCV_HWPROBE_BASE_BEHAVIOR_IMA = C.RISCV_HWPROBE_BASE_BEHAVIOR_IMA
5788+
RISCV_HWPROBE_KEY_IMA_EXT_0 = C.RISCV_HWPROBE_KEY_IMA_EXT_0
5789+
RISCV_HWPROBE_IMA_FD = C.RISCV_HWPROBE_IMA_FD
5790+
RISCV_HWPROBE_IMA_C = C.RISCV_HWPROBE_IMA_C
5791+
RISCV_HWPROBE_KEY_CPUPERF_0 = C.RISCV_HWPROBE_KEY_CPUPERF_0
5792+
RISCV_HWPROBE_MISALIGNED_UNKNOWN = C.RISCV_HWPROBE_MISALIGNED_UNKNOWN
5793+
RISCV_HWPROBE_MISALIGNED_EMULATED = C.RISCV_HWPROBE_MISALIGNED_EMULATED
5794+
RISCV_HWPROBE_MISALIGNED_SLOW = C.RISCV_HWPROBE_MISALIGNED_SLOW
5795+
RISCV_HWPROBE_MISALIGNED_FAST = C.RISCV_HWPROBE_MISALIGNED_FAST
5796+
RISCV_HWPROBE_MISALIGNED_UNSUPPORTED = C.RISCV_HWPROBE_MISALIGNED_UNSUPPORTED
5797+
RISCV_HWPROBE_MISALIGNED_MASK = C.RISCV_HWPROBE_MISALIGNED_MASK
5798+
)

unix/mkpost.go

+11
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ func main() {
112112
}
113113
}
114114

115+
if goos == "linux" && goarch != "riscv64" {
116+
// The RISCV_HWPROBE_ constants are only defined on Linux for riscv64
117+
hwprobeConstRexexp := regexp.MustCompile(`const\s+\(\s+RISCV_HWPROBE_[^\)]+\)`)
118+
b = hwprobeConstRexexp.ReplaceAll(b, nil)
119+
}
120+
115121
// Intentionally export __val fields in Fsid and Sigset_t
116122
valRegex := regexp.MustCompile(`type (Fsid|Sigset_t) struct {(\s+)X__(bits|val)(\s+\S+\s+)}`)
117123
b = valRegex.ReplaceAll(b, []byte("type $1 struct {${2}Val$4}"))
@@ -138,6 +144,11 @@ func main() {
138144
ptraceRexexp := regexp.MustCompile(`type Ptrace((Psw|Fpregs|Per) struct {\s*})`)
139145
b = ptraceRexexp.ReplaceAll(b, nil)
140146

147+
// If we have an empty RISCVHWProbePairs struct, we should delete it. Only riscv64 emits
148+
// nonempty RISCVHWProbePairs structs.
149+
hwprobeRexexp := regexp.MustCompile(`type RISCVHWProbePairs struct {\s*}`)
150+
b = hwprobeRexexp.ReplaceAll(b, nil)
151+
141152
// Replace the control_regs union with a blank identifier for now.
142153
controlRegsRegex := regexp.MustCompile(`(Control_regs)\s+\[0\]uint64`)
143154
b = controlRegsRegex.ReplaceAll(b, []byte("_ [0]uint64"))

unix/syscall_linux_riscv64.go

+11
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,14 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error
177177
}
178178
return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
179179
}
180+
181+
//sys riscvHWProbe(pairs []RISCVHWProbePairs, cpuCount uintptr, cpus *CPUSet, flags uint) (err error)
182+
183+
func RISCVHWProbe(pairs []RISCVHWProbePairs, set *CPUSet, flags uint) (err error) {
184+
var setSize uintptr
185+
186+
if set != nil {
187+
setSize = uintptr(unsafe.Sizeof(*set))
188+
}
189+
return riscvHWProbe(pairs, setSize, set, flags)
190+
}

unix/zsyscall_linux_riscv64.go

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

unix/zsysnum_linux_riscv64.go

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

unix/ztypes_linux_riscv64.go

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)