Skip to content

Commit 2199924

Browse files
joshuaseatongnoliyil
authored andcommitted
[zither] Introduce rust syscall backend
This change introduces a backend dedicated to generating thin Rust FFI syscall wrappers, generated by kazoo today. Bug: 110294 Change-Id: If37708ccc06e3dbf46765156e567ae3d3c9da341 Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/773344 Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com> Reviewed-by: Roland McGrath <mcgrathr@google.com> Fuchsia-Auto-Submit: Joshua Seaton <joshuaseaton@google.com>
1 parent 3012ff4 commit 2199924

File tree

10 files changed

+297
-31
lines changed

10 files changed

+297
-31
lines changed

zircon/tools/zither/BUILD.gn

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ if (is_host) {
5656
"kernel",
5757
"legacy_syscall_cdecl",
5858
"rust",
59+
"rust_syscall",
5960
"zircon_ifs",
6061
"//tools/fidl/lib/fidlgen",
6162
"//tools/lib/color",
@@ -316,13 +317,14 @@ template("zither_golden_test") {
316317
"output_subdir",
317318
])
318319
} else if (case.backend == "rust" || case.backend == "kernel" ||
319-
case.backend == "legacy_syscall_cdecl") {
320-
# The generated rust library target should already enforce compilation.
320+
case.backend == "legacy_syscall_cdecl" ||
321+
case.backend == "rust_syscall") {
322+
# The generated rust library targets should already enforce compilation.
321323
#
322-
# The kernel and legacy_syscall_cdecl backends generate sources that rely
323-
# on a number of other kernel and vDSO-specific definitions. Given that
324-
# and the fact the singular use-case for these sources will be exercised
325-
# in any default build invocation, it is neither worthwhile nor all that
324+
# The kernel and syscall-related backends generate sources that rely on a
325+
# number of other kernel and vDSO-specific definitions. Given that and
326+
# the fact the singular use-case for these sources will be exercised in
327+
# any default build invocation, it is neither worthwhile nor all that
326328
# practical to do a compilation check here.
327329
group(compilation_check_target) {
328330
visibility = [ ":*" ]
@@ -572,6 +574,10 @@ zither_golden_test("zx.test") {
572574
"cdecls-next.inc",
573575
]
574576
},
577+
{
578+
backend = "rust_syscall"
579+
files = [ "definitions.rs" ]
580+
},
575581
]
576582
}
577583

zircon/tools/zither/cmd/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"go.fuchsia.dev/fuchsia/zircon/tools/zither/kernel"
2323
"go.fuchsia.dev/fuchsia/zircon/tools/zither/legacy_syscall_cdecl"
2424
"go.fuchsia.dev/fuchsia/zircon/tools/zither/rust"
25+
"go.fuchsia.dev/fuchsia/zircon/tools/zither/rust_syscall"
2526
"go.fuchsia.dev/fuchsia/zircon/tools/zither/zircon_ifs"
2627
)
2728

@@ -33,6 +34,7 @@ const (
3334
zirconIFSBackend string = "zircon_ifs"
3435
kernelBackend string = "kernel"
3536
legacySyscallCDeclBackend string = "legacy_syscall_cdecl"
37+
rustSyscallBackend string = "rust_syscall"
3638
)
3739

3840
var supportedBackends = []string{
@@ -43,6 +45,7 @@ var supportedBackends = []string{
4345
zirconIFSBackend,
4446
kernelBackend,
4547
legacySyscallCDeclBackend,
48+
rustSyscallBackend,
4649
}
4750

4851
// Flag values, grouped into a struct to be kept out of the global namespace.
@@ -94,6 +97,8 @@ func main() {
9497
gen = kernel.NewGenerator(f)
9598
case legacySyscallCDeclBackend:
9699
gen = legacy_syscall_cdecl.NewGenerator(f)
100+
case rustSyscallBackend:
101+
gen = rust_syscall.NewGenerator(f)
97102
default:
98103
logger.Errorf(ctx, "unrecognized `-backend` value: %q", flags.backend)
99104
os.Exit(1)

zircon/tools/zither/rust/rust.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ func NewGenerator(formatter fidlgen.Formatter) *Generator {
3636
"ConstValue": ConstValue,
3737
"EnumAttributes": EnumAttributes,
3838
"StructAttributes": StructAttributes,
39-
"DescribeType": DescribeType,
39+
"DescribeType": func(desc zither.TypeDescriptor) string {
40+
return DescribeType(desc, CaseStyleRust)
41+
},
4042
})
4143
return &Generator{*gen}
4244
}
@@ -182,24 +184,56 @@ func StructAttributes() []string {
182184
return []string{"#[repr(C)]"}
183185
}
184186

185-
func DescribeType(desc zither.TypeDescriptor) string {
187+
// CaseStyle represents a style of casing Rust type names.
188+
type CaseStyle int
189+
190+
const (
191+
// CaseStyleRust represents official rust style.
192+
CaseStyleRust CaseStyle = iota
193+
194+
// CaseStyleSyscall gives a C-style spelling for certain types, for
195+
// suggestive use in the Rust FFI syscall wrapper definitions.
196+
CaseStyleSyscall
197+
)
198+
199+
func DescribeType(desc zither.TypeDescriptor, style CaseStyle) string {
200+
var casify func(string) string
201+
switch style {
202+
case CaseStyleRust:
203+
casify = fidlgen.ToUpperCamelCase
204+
case CaseStyleSyscall:
205+
casify = func(name string) string {
206+
typ := fidlgen.ToSnakeCase(name)
207+
switch desc.Kind {
208+
case zither.TypeKindAlias, zither.TypeKindStruct, zither.TypeKindEnum,
209+
zither.TypeKindBits, zither.TypeKindHandle:
210+
return "zx_" + typ + "_t"
211+
default:
212+
return typ
213+
}
214+
}
215+
}
216+
186217
switch desc.Kind {
187218
case zither.TypeKindBool, zither.TypeKindInteger, zither.TypeKindSize:
188219
return ScalarTypeName(fidlgen.PrimitiveSubtype(desc.Type))
189220
case zither.TypeKindEnum, zither.TypeKindBits, zither.TypeKindStruct:
190221
layout, _ := fidlgen.MustReadName(desc.Type).SplitMember()
191-
return fidlgen.ToUpperCamelCase(layout.DeclarationName())
222+
return casify(layout.DeclarationName())
192223
case zither.TypeKindAlias, zither.TypeKindHandle:
193224
// TODO(fxbug.dev/105758): This assumes that the alias/handle was defined
194225
// within the same package. That's true now, but this would need to be
195226
// re-evaluated if/when zither supports library dependencies and the IR
196227
// preserves imported alias names.
197-
return fidlgen.ToUpperCamelCase(fidlgen.MustReadName(desc.Type).DeclarationName())
228+
return casify(fidlgen.MustReadName(desc.Type).DeclarationName())
198229
case zither.TypeKindArray:
199-
return fmt.Sprintf("[%s; %d]", DescribeType(*desc.ElementType), *desc.ElementCount)
230+
return fmt.Sprintf("[%s; %d]", DescribeType(*desc.ElementType, style), *desc.ElementCount)
200231
case zither.TypeKindPointer, zither.TypeKindVoidPointer:
201-
// TODO(fxbug.dev/110294): Handle mutability.
202-
return "*const " + DescribeType(*desc.ElementType)
232+
mutability := "const"
233+
if desc.ElementType.Mutable {
234+
mutability = "mut"
235+
}
236+
return fmt.Sprintf("*%s %s", mutability, DescribeType(*desc.ElementType, style))
203237
default:
204238
panic(fmt.Sprintf("unsupported type kind: %v", desc.Kind))
205239
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright 2022 The Fuchsia Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
import("//build/go/go_library.gni")
6+
7+
go_library("rust_syscall") {
8+
visibility = [ "../*" ]
9+
sources = [
10+
"rust_syscall.go",
11+
"templates/definitions.rs.tmpl",
12+
]
13+
deps = [
14+
"..:common",
15+
"../rust",
16+
"//tools/fidl/lib/fidlgen",
17+
]
18+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2022 The Fuchsia Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package rust_syscall
6+
7+
import (
8+
"embed"
9+
"fmt"
10+
"path/filepath"
11+
"sort"
12+
"strings"
13+
"text/template"
14+
15+
"go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen"
16+
"go.fuchsia.dev/fuchsia/zircon/tools/zither"
17+
"go.fuchsia.dev/fuchsia/zircon/tools/zither/rust"
18+
)
19+
20+
//go:embed templates/*
21+
var templates embed.FS
22+
23+
type Generator struct {
24+
fidlgen.Generator
25+
}
26+
27+
func NewGenerator(formatter fidlgen.Formatter) *Generator {
28+
gen := fidlgen.NewGenerator("RustSyscallTemplates", templates, formatter, template.FuncMap{
29+
"LowerCaseWithUnderscores": rust.LowerCaseWithUnderscores,
30+
"ParameterType": parameterType,
31+
"ReturnType": returnType,
32+
"LastParameterIndex": func(syscall zither.Syscall) int { return len(syscall.Parameters) - 1 },
33+
})
34+
return &Generator{*gen}
35+
}
36+
37+
func (gen Generator) DeclOrder() zither.DeclOrder { return zither.SourceDeclOrder }
38+
39+
func (gen *Generator) Generate(summaries []zither.FileSummary, outputDir string) ([]string, error) {
40+
var syscalls []zither.Syscall
41+
for _, summary := range summaries {
42+
for _, decl := range summary.Decls {
43+
if !decl.IsSyscallFamily() {
44+
continue
45+
}
46+
for _, syscall := range decl.AsSyscallFamily().Syscalls {
47+
if syscall.IsInternal() {
48+
continue
49+
}
50+
syscalls = append(syscalls, syscall)
51+
}
52+
}
53+
}
54+
sort.Slice(syscalls, func(i, j int) bool {
55+
return strings.Compare(syscalls[i].Name, syscalls[j].Name) < 0
56+
})
57+
58+
outputDir = filepath.Join(outputDir, strings.Join(summaries[0].Library.Parts(), "-"), "src")
59+
definitions := filepath.Join(outputDir, "definitions.rs")
60+
if err := gen.GenerateFile(definitions, "GenerateDefinitions", syscalls); err != nil {
61+
return nil, err
62+
}
63+
return []string{definitions}, nil
64+
}
65+
66+
func typeName(desc zither.TypeDescriptor) string {
67+
return rust.DescribeType(desc, rust.CaseStyleSyscall)
68+
}
69+
70+
//
71+
// Template functions.
72+
//
73+
74+
func parameterType(param zither.SyscallParameter) string {
75+
// Structs and non-inputs should be passed as pointers.
76+
kind := param.Type.Kind
77+
if !kind.IsPointerLike() && (!param.IsStrictInput() || kind == zither.TypeKindStruct) {
78+
elementType := param.Type
79+
elementType.Mutable = !param.IsStrictInput()
80+
return typeName(zither.TypeDescriptor{
81+
Kind: zither.TypeKindPointer,
82+
ElementType: &elementType,
83+
})
84+
}
85+
return typeName(param.Type)
86+
}
87+
88+
func returnType(syscall zither.Syscall) string {
89+
if syscall.ReturnType == nil {
90+
panic(fmt.Sprintf("%s does not have a return type", syscall.Name))
91+
}
92+
return typeName(*syscall.ReturnType)
93+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{{/*
2+
// Copyright 2022 The Fuchsia Authors. All rights reserved.
3+
// Use of this source code is governed by a BSD-style license that can be
4+
// found in the LICENSE file.
5+
*/}}
6+
{{- define "GenerateDefinitions" -}}
7+
// Copyright 2022 The Fuchsia Authors. All rights reserved.
8+
// Use of this source code is governed by a BSD-style license that can be
9+
// found in the LICENSE file.
10+
11+
// Re-export the types defined in the fuchsia-zircon-types crate
12+
pub use fuchsia_zircon_types::*;
13+
14+
// Only link against zircon when targeting Fuchsia
15+
#[cfg(target_os = "fuchsia")]
16+
#[link(name = "zircon")]
17+
extern {
18+
{{ range . }}
19+
{{ $lastParamIndex := LastParameterIndex .}}
20+
pub fn zx_{{ LowerCaseWithUnderscores . }}(
21+
{{- range $i, $param := .Parameters }}
22+
{{ LowerCaseWithUnderscores $param }}: {{ ParameterType $param }} {{ if ne $i $lastParamIndex }},{{ end }}
23+
{{- end }}
24+
){{ if .ReturnType }} -> {{ ReturnType . }} {{ end }};
25+
{{ end }}
26+
}
27+
28+
{{ end }}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2022 The Fuchsia Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Re-export the types defined in the fuchsia-zircon-types crate
6+
pub use fuchsia_zircon_types::*;
7+
8+
// Only link against zircon when targeting Fuchsia
9+
#[cfg(target_os = "fuchsia")]
10+
#[link(name = "zircon")]
11+
extern "C" {
12+
13+
pub fn zx_channel_read(
14+
handle: zx_handle_t,
15+
options: u32,
16+
bytes: *mut u8,
17+
handles: *mut zx_handle_t,
18+
num_bytes: u32,
19+
num_handles: u32,
20+
actual_bytes: *mut u32,
21+
actual_handles: *mut u32,
22+
) -> zx_status_t;
23+
24+
pub fn zx_channel_write(
25+
handle: zx_handle_t,
26+
options: u32,
27+
bytes: *const u8,
28+
num_bytes: u32,
29+
handles: *const zx_handle_t,
30+
num_handles: u32,
31+
) -> zx_status_t;
32+
33+
pub fn zx_clock_get_monotonic() -> zx_time_t;
34+
35+
pub fn zx_handle_close_many(handles: *const zx_handle_t, num_handles: usize) -> zx_status_t;
36+
37+
pub fn zx_ktrace_control(
38+
handle: zx_handle_t,
39+
action: u32,
40+
options: u32,
41+
ptr: *mut u8,
42+
) -> zx_status_t;
43+
44+
pub fn zx_nanosleep(deadline: zx_time_t) -> zx_status_t;
45+
46+
pub fn zx_process_exit(retcode: i64);
47+
48+
pub fn zx_syscall_next();
49+
50+
pub fn zx_syscall_test0();
51+
52+
pub fn zx_syscall_test1();
53+
54+
pub fn zx_syscall_test2();
55+
56+
pub fn zx_system_get_page_size() -> u32;
57+
58+
}

zircon/tools/zither/zither_ir.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,9 @@ type TypeDescriptor struct {
673673

674674
// ElementCount gives the size of the associated array.
675675
ElementCount *int
676+
677+
// Mutable gives whether this type is mutable.
678+
Mutable bool
676679
}
677680

678681
// Represents an recursively-defined type, effectively abstracting
@@ -1323,10 +1326,14 @@ func newSyscallFamily(protocol fidlgen.Protocol, decls declMap) (*SyscallFamily,
13231326
} else if m.inout {
13241327
param.Orientation = ParameterOrientationInOut
13251328
}
1329+
kind := param.Type.Kind
1330+
if !param.IsStrictInput() && (kind.IsVectorLike() || kind.IsPointerLike()) {
1331+
param.Type.ElementType.Mutable = true
1332+
}
13261333

1327-
switch param.Type.Kind {
1334+
switch kind {
13281335
case TypeKindHandle, TypeKindPointer, TypeKindVector, TypeKindVector32:
1329-
if param.Type.Kind != TypeKindHandle && param.Type.ElementType.Kind != TypeKindHandle {
1336+
if kind != TypeKindHandle && param.Type.ElementType.Kind != TypeKindHandle {
13301337
break
13311338
}
13321339
if method.GetAttributes().HasAttribute("handle_unchecked") {
@@ -1338,10 +1345,10 @@ func newSyscallFamily(protocol fidlgen.Protocol, decls declMap) (*SyscallFamily,
13381345

13391346
// Vector parameters decay into separate pointer and length
13401347
// parameters.
1341-
if param.Type.Kind.IsVectorLike() {
1348+
if kind.IsVectorLike() {
13421349
pointer := param
13431350
pointer.SetTag(ParameterTagDecayedFromVector)
1344-
if param.Type.Kind.IsVoidVectorLike() {
1351+
if kind.IsVoidVectorLike() {
13451352
pointer.Type.Kind = TypeKindVoidPointer
13461353
} else {
13471354
pointer.Type.Kind = TypeKindPointer
@@ -1364,7 +1371,7 @@ func newSyscallFamily(protocol fidlgen.Protocol, decls declMap) (*SyscallFamily,
13641371
length.Name += "_size"
13651372
}
13661373

1367-
if param.Type.Kind.IsVector32Like() {
1374+
if kind.IsVector32Like() {
13681375
length.Type = TypeDescriptor{
13691376
Kind: TypeKindInteger,
13701377
Type: string(fidlgen.Uint32),

0 commit comments

Comments
 (0)