This doc is a short guide to adding a new Zircon syscall. The intended audience is kernel developers or anyone who is adding a new syscall.
Keep in mind that this guide only covers the mechanics of adding syscall/objects. It's not a style guide, rubric, and does not provide any advice on how to know when an API is stable enough or mature enough to become part of the system interface.
Because our system continues to change, you should expect that this guide is out of date. Sorry. If you are following this guide and you notice errors or omissions, please make an attempt to update it. Thank you!
Overview
There are a number of ways you can structure the changes to add a new Zircon syscall (or object). This guide will describe an approach consisting of four CLs: stub, implementation, extras, and annotations.
We're going to follow the "rewrite history" method. Zircon syscalls do not (currently) follow Platform Versioning so instead we're going to make it look as if the new syscall had been there all along. To do this, we'll need to update some SDK history files for frozen API levels.
Stub CL: Start with a stub at HEAD
In this CL, you'll define the syscall and provide a stub implementation that
simply returns ZX_ERR_NOT_SUPPORTED
. Be sure to include a core-test in this
stub CL that verifies the caller doesn't crash and that the new call returns the
error as expected.
The build system and FIDL compiler will automatically generate some of the
boilerplate for you. To take advantage, you'll want to get in the habit of
performing a default build, fx build
, and running fx check-goldens
after you
make changes to FIDL files.
To illustrate, let's look at a stub CL that adds both a new Zircon
object (counter
) and a new syscall (zx_counter_create
).
The stub CL has four parts.
1. Define the syscall using FIDL
Next, define the new syscall in an existing .fidl
file or add
a new file if appropriate. Be sure to add a commented out
@available(added=HEAD)
annotation that indicates the new syscall (or object if
adding a new Zircon object) is added at HEAD.
In the rarer event of adding a new Zircon object, you'll need to take a few extra steps.
a. Teach the FIDL compiler about the new object type. The FIDL toolchain bakes in knowledge of object types. This isn't elegant, but it avoids some circular dependencies. You'll have to update parts of the FIDL toolchain to understand your new object type. In particular, update:
HandleSubtype
in//tools/fidl/fidlc/src/properties.h
NameHandleSubtype
in//tools/fidl/fidlc/src/names.cc
HandleType
in//tools/fidl/abi-compat/src/compare/handle.rs
handle-subtype
in//tools/fidl/fidlc/schema.json
GoodHandleSubtype
in//tools/fidl/fidlc/tests/types_tests.cc
HandleSubtype
andObjectType
consts in//tools/fidl/lib/fidlgen/types.go
handleSubtypes
,handleSubtypesFdomain
andobjectTypeConsts
in//tools/fidl/fidlgen_rust/codegen/ir.go
b. Update the fidlc
goldens by following the instructions provided in the build
error you get when you build without updating them.
c. Add the new object type to zircon/types.h.
d. Update the //sdk/history/*/zx.api_summary.json
files. These
are for the public zx
FIDL library, which shares zx_common.fidl
with the
syscall library.
e. Extend docsgen as necessary.
2. Implement the syscall in the kernel
Implement the syscall somewhere in
zircon/kernel/lib/syscalls/, with a prefix of sys_
instead of zx_
. For now, the implementation should simply return
ZX_ERR_NOT_SUPPORTED
.
3. Add a lib/zx C++ wrapper
Add a new or extend an existing lib/zx wrapper in order to
provide a C++ API for the new syscall. Be sure to apply a
ZX_AVAILABLE_SINCE(HEAD)
annotation to your new C++ method (or class if it's a
new Zircon object). While the syscall itself will appear to have been present
from the very beginning, the C++ wrapper is added at HEAD.
4. Add a core-test
Add a core-test that verifies the stub returns the right
error value (and does not crash the system). By using the new lib/zx
wrapper
in this test, you can be sure it also works as expected.
Once you've gotten the stub to build and pass CQ, land it. Next, move on to the implementation CL.
Implementation CL: Filling in the stub
Now it's time to replace the stub implementation with a real one, add real tests and real documentation. Built it, pass CQ, land it, and move on.
Extras CL: Add the rest
Once you've got a working implementation with C/C++ bindings, you're now ready
to add Rust bindings, and update (fidl_codec
(used by fidlcat
):
- ShortObjTypeName
in display_handle.cc
- PrettyPrinter::DisplayObjType
in printer.cc
The above list of "extras" may be incomplete so this is a good time look around ad other syscalls to see if there are more things you need to update (tools? bindings for other languages?). Land the extras CLs and move on to the final step.
Annotations CL: Change HEAD to NEXT
Now that the implementation and extras have landed, go back and change the value
you added in the @available
and ZX_AVAILABLE_SINCE
annotation(s) from HEAD
to NEXT
to make the syscall available in the next stable API level.