1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include <inttypes.h>
18 #include <stdbool.h>
19 
20 // GOLDFISH SYNC DEVICE
21 // The Goldfish sync driver is designed to provide a interface
22 // between the underlying host's sync device and the kernel's
23 // sw_sync.
24 // The purpose of the device/driver is to enable lightweight
25 // creation and signaling of timelines and fences
26 // in order to synchronize the guest with host-side graphics events.
27 
28 // Each time the interrupt trips, the driver
29 // may perform a sw_sync operation.
30 
31 // The operations are:
32 
33 // Ready signal - used to mark when irq should lower
34 #define CMD_SYNC_READY            0
35 
36 // Create a new timeline. writes timeline handle
37 #define CMD_CREATE_SYNC_TIMELINE  1
38 
39 // Create a fence object. reads timeline handle and time argument.
40 // Writes fence fd to the SYNC_REG_HANDLE register.
41 #define CMD_CREATE_SYNC_FENCE     2
42 
43 // Increments timeline. reads timeline handle and time argument
44 #define CMD_SYNC_TIMELINE_INC     3
45 
46 // Destroys a timeline. reads timeline handle
47 #define CMD_DESTROY_SYNC_TIMELINE 4
48 
49 // Starts a wait on the host with
50 // the given glsync object and sync thread handle.
51 #define CMD_TRIGGER_HOST_WAIT     5
52 
53 // The register layout is:
54 
55 #define SYNC_REG_BATCH_COMMAND                0x00 // host->guest batch commands
56 #define SYNC_REG_BATCH_GUESTCOMMAND           0x04 // guest->host batch commands
57 #define SYNC_REG_BATCH_COMMAND_ADDR           0x08 // communicate physical address of host->guest batch commands
58 #define SYNC_REG_BATCH_COMMAND_ADDR_HIGH      0x0c // 64-bit part
59 #define SYNC_REG_BATCH_GUESTCOMMAND_ADDR      0x10 // communicate physical address of guest->host commands
60 #define SYNC_REG_BATCH_GUESTCOMMAND_ADDR_HIGH 0x14 // 64-bit part
61 #define SYNC_REG_INIT                         0x18 // to signal that the device has been detected by the kernel
62 
63 #define GUEST_TRIGGERED(cmd) (cmd == CMD_SYNC_READY || \
64                               cmd == CMD_TRIGGER_HOST_WAIT)
65 
66 typedef void (*trigger_wait_fn_t)(uint64_t, uint64_t, uint64_t);
67 
68 // The commands below operate on Android sync "timelines" and
69 // "fences". The basic concept is as follows.
70 // - Timeline and fences work together as a state to determine
71 //   which events have completed. The timeline abstraction
72 //   is used to represent a monotonic ordering of events,
73 //   while fences represent levels of progress along
74 //   timelines. By having different threads wait on fences
75 //   until their associated timelines make the required progress,
76 //   we can synchronize multiple threads within a process
77 //   and with binder, across processes.
78 // - What follows is an abstract definition of that concept
79 //   that does not match implementation exactly, but is
80 //   sufficient for our purposes:
81 // - A timeline is a represnted by a single uint32_t, known as
82 //   its "value". Over time, the value may increase.
83 //   timeline : value
84 // - Let "timeline-id" be a uint64_t that uniquely identifies each
85 //   timeline.
86 //   A fence is an immutable map from timeline-id's to values:
87 //   fence : map(timeline-id -> value). We will refer to the
88 //   "timeline-id-values" of a fence to be the set of all pairs
89 //   (timeline-id, value) that comprise the mapping.
90 // - Let "fence-id" be an int that uniquely identifies each fence.
91 //   This is also known as a "fence fd".
92 //   The important state is represented by a pair of maps:
93 //   (T = map(timeline-id -> timeline), F = map(fence-id -> fence)).
94 //   This state may change over time, with timelines and fences
95 //   being added or removed.
96 //   For any state, we care primarily about the "signaled" status
97 //   of the fences within.
98 //   - Each fence in the map from fence-id's to fences is
99 //     signaled if:
100 //     - For all timeline-id-values = (timeline-id, value)
101 //       of that fence, T[timeline-id] >= value.
102 //       Or, timeline-id does not exist in T's keys.
103 //     - Otherwise, it is considered "unsignaled."
104 // The functions below operate with the above abstraction in mind.
105 // They all mutate a particular collection of fences and timelines.
106 // We can think of them as implicitly taking a state (T, F)
107 // as input and returning a new one (T', F') that is possibly updated,
108 // according to the changes described. The new collection then
109 // serves as the true abstract state for all further operations.
110 
111 // |goldfish_sync_create_timeline| creates a new timeline
112 // with value 0. The timeline id is returned.
113 uint64_t goldfish_sync_create_timeline();
114 
115 // |goldfish_sync_create_fence| creates a fence
116 // that has a single timeline-id-value pair as its map.
117 // The first two arguments comprise the pair.
118 // Returns a unique identifier for the fence.
119 // Note that this implementation only allows the creation of
120 // fences associated with a single timeline-id-value pair.
121 int goldfish_sync_create_fence(uint64_t timeline, uint32_t pt);
122 
123 // |goldfish_sync_timeline_inc| advances the value component
124 // of a given timeline by |howmuch|; that is, if
125 // (t, v) is the timeline-id and value of a timeline before this call,
126 // (t, v + |howmuch|) is the value after.
127 // Thus, this may end up changing some fence objects to signaled state.
128 void goldfish_sync_timeline_inc(uint64_t timeline, uint32_t howmuch);
129 
130 // |goldfish_sync_destroy_timeline| removes the key |timeline|
131 // from the global timeline map.
132 // Any fence objects whose only timeline-id-value (t, v) is such that
133 // t == |timeline| would be considered signaled.
134 // If there are any other timeline-id-values, the fence may still be
135 // unsignaled. We would need the other timelines referenced by this fence
136 // to have reached the target value of this fence, fence[timeline].
137 void goldfish_sync_destroy_timeline(uint64_t timeline);
138 
139 // Registering callbacks for goldfish sync ops
140 // Currently, only trigger_wait is supported.
141 void goldfish_sync_register_trigger_wait(trigger_wait_fn_t trigger_fn);
142 
143 // If the virtual device doesn't actually exist (e.g., when
144 // using QEMU1), query that using this function:
145 bool goldfish_sync_device_exists();
146 
147 // Function types for sending commands to the virtual device.
148 typedef void (*queue_device_command_t)
149     (uint32_t cmd, uint64_t handle, uint32_t time_arg,
150      uint64_t hostcmd_handle);
151 
152 typedef struct GoldfishSyncDeviceInterface {
153     // Callback for all communications with virtual device
154     queue_device_command_t doHostCommand;
155 
156     // Callbacks to register other callbacks for triggering
157     // OpenGL waits from the guest
158     void (*registerTriggerWait)(trigger_wait_fn_t);
159 } GoldfishSyncDeviceInterface;
160 
161 // The virtual device will call |goldfish_sync_set_hw_funcs|
162 // to connect up to the AndroidEmu part.
163 extern void
164 goldfish_sync_set_hw_funcs(GoldfishSyncDeviceInterface* hw_funcs);
165 
166 // The virtual device calls this |goldfish_sync_receive_hostcmd_result|
167 // when it receives a reply for host->guest commands that support
168 // that protocol.
169 extern void
170 goldfish_sync_receive_hostcmd_result(uint32_t cmd,
171                                      uint64_t handle,
172                                      uint32_t time_arg,
173                                      uint64_t hostcmd_handle);
174