+static VkResult
+radv_secure_compile(struct radv_pipeline *pipeline,
+ struct radv_device *device,
+ const struct radv_pipeline_key *key,
+ const VkPipelineShaderStageCreateInfo **pStages,
+ const VkPipelineCreateFlags flags,
+ unsigned num_stages)
+{
+ uint8_t allowed_pipeline_hashes[2][20];
+ radv_hash_shaders(allowed_pipeline_hashes[0], pStages,
+ pipeline->layout, key, get_hash_flags(device));
+
+ /* Generate the GC copy hash */
+ memcpy(allowed_pipeline_hashes[1], allowed_pipeline_hashes[0], 20);
+ allowed_pipeline_hashes[1][0] ^= 1;
+
+ uint8_t allowed_hashes[2][20];
+ for (unsigned i = 0; i < 2; ++i) {
+ disk_cache_compute_key(device->physical_device->disk_cache,
+ allowed_pipeline_hashes[i], 20,
+ allowed_hashes[i]);
+ }
+
+ /* Do an early exit if all cache entries are already there. */
+ bool may_need_copy_shader = pStages[MESA_SHADER_GEOMETRY];
+ void *main_entry = disk_cache_get(device->physical_device->disk_cache, allowed_hashes[0], NULL);
+ void *copy_entry = NULL;
+ if (may_need_copy_shader)
+ copy_entry = disk_cache_get(device->physical_device->disk_cache, allowed_hashes[1], NULL);
+
+ bool has_all_cache_entries = main_entry && (!may_need_copy_shader || copy_entry);
+ free(main_entry);
+ free(copy_entry);
+
+ if(has_all_cache_entries)
+ return VK_SUCCESS;
+
+ unsigned process = 0;
+ uint8_t sc_threads = device->instance->num_sc_threads;
+ while (true) {
+ mtx_lock(&device->sc_state->secure_compile_mutex);
+ if (device->sc_state->secure_compile_thread_counter < sc_threads) {
+ device->sc_state->secure_compile_thread_counter++;
+ for (unsigned i = 0; i < sc_threads; i++) {
+ if (!device->sc_state->secure_compile_processes[i].in_use) {
+ device->sc_state->secure_compile_processes[i].in_use = true;
+ process = i;
+ break;
+ }
+ }
+ mtx_unlock(&device->sc_state->secure_compile_mutex);
+ break;
+ }
+ mtx_unlock(&device->sc_state->secure_compile_mutex);
+ }
+
+ int fd_secure_input = device->sc_state->secure_compile_processes[process].fd_secure_input;
+ int fd_secure_output = device->sc_state->secure_compile_processes[process].fd_secure_output;
+
+ /* Fork a copy of the slim untainted secure compile process */
+ enum radv_secure_compile_type sc_type = RADV_SC_TYPE_FORK_DEVICE;
+ write(fd_secure_input, &sc_type, sizeof(sc_type));
+
+ if (!radv_sc_read(fd_secure_output, &sc_type, sizeof(sc_type), true) ||
+ sc_type != RADV_SC_TYPE_INIT_SUCCESS)
+ return VK_ERROR_DEVICE_LOST;
+
+ fd_secure_input = device->sc_state->secure_compile_processes[process].fd_server;
+ fd_secure_output = device->sc_state->secure_compile_processes[process].fd_client;
+
+ /* Write pipeline / shader module out to secure process via pipe */
+ sc_type = RADV_SC_TYPE_COMPILE_PIPELINE;
+ write(fd_secure_input, &sc_type, sizeof(sc_type));
+
+ /* Write pipeline layout out to secure process */
+ struct radv_pipeline_layout *layout = pipeline->layout;
+ write(fd_secure_input, layout, sizeof(struct radv_pipeline_layout));
+ write(fd_secure_input, &layout->num_sets, sizeof(uint32_t));
+ for (uint32_t set = 0; set < layout->num_sets; set++) {
+ write(fd_secure_input, &layout->set[set].layout->layout_size, sizeof(uint32_t));
+ write(fd_secure_input, layout->set[set].layout, layout->set[set].layout->layout_size);
+ }
+
+ /* Write pipeline key out to secure process */
+ write(fd_secure_input, key, sizeof(struct radv_pipeline_key));
+
+ /* Write pipeline create flags out to secure process */
+ write(fd_secure_input, &flags, sizeof(VkPipelineCreateFlags));
+
+ /* Write stage and shader information out to secure process */
+ write(fd_secure_input, &num_stages, sizeof(uint32_t));
+ for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (!pStages[i])
+ continue;
+
+ /* Write stage out to secure process */
+ gl_shader_stage stage = ffs(pStages[i]->stage) - 1;
+ write(fd_secure_input, &stage, sizeof(gl_shader_stage));
+
+ /* Write entry point name out to secure process */
+ size_t name_size = strlen(pStages[i]->pName) + 1;
+ write(fd_secure_input, &name_size, sizeof(size_t));
+ write(fd_secure_input, pStages[i]->pName, name_size);
+
+ /* Write shader module out to secure process */
+ struct radv_shader_module *module = radv_shader_module_from_handle(pStages[i]->module);
+ assert(!module->nir);
+ size_t module_size = sizeof(struct radv_shader_module) + module->size;
+ write(fd_secure_input, &module_size, sizeof(size_t));
+ write(fd_secure_input, module, module_size);
+
+ /* Write specialization info out to secure process */
+ const VkSpecializationInfo *specInfo = pStages[i]->pSpecializationInfo;
+ bool has_spec_info = specInfo ? true : false;
+ write(fd_secure_input, &has_spec_info, sizeof(bool));
+ if (specInfo) {
+ write(fd_secure_input, &specInfo->dataSize, sizeof(size_t));
+ write(fd_secure_input, specInfo->pData, specInfo->dataSize);
+
+ write(fd_secure_input, &specInfo->mapEntryCount, sizeof(uint32_t));
+ for (uint32_t j = 0; j < specInfo->mapEntryCount; j++)
+ write(fd_secure_input, &specInfo->pMapEntries[j], sizeof(VkSpecializationMapEntry));
+ }
+ }
+
+ /* Read the data returned from the secure process */
+ while (sc_type != RADV_SC_TYPE_COMPILE_PIPELINE_FINISHED) {
+ if (!radv_sc_read(fd_secure_output, &sc_type, sizeof(sc_type), true))
+ return VK_ERROR_DEVICE_LOST;
+
+ if (sc_type == RADV_SC_TYPE_WRITE_DISK_CACHE) {
+ assert(device->physical_device->disk_cache);
+
+ uint8_t disk_sha1[20];
+ if (!radv_sc_read(fd_secure_output, disk_sha1, sizeof(uint8_t) * 20, true))
+ return VK_ERROR_DEVICE_LOST;
+
+ if (memcmp(disk_sha1, allowed_hashes[0], 20) &&
+ memcmp(disk_sha1, allowed_hashes[1], 20))
+ return VK_ERROR_DEVICE_LOST;
+
+ uint32_t entry_size;
+ if (!radv_sc_read(fd_secure_output, &entry_size, sizeof(uint32_t), true))
+ return VK_ERROR_DEVICE_LOST;
+
+ struct cache_entry *entry = malloc(entry_size);
+ if (!radv_sc_read(fd_secure_output, entry, entry_size, true))
+ return VK_ERROR_DEVICE_LOST;
+
+ disk_cache_put(device->physical_device->disk_cache,
+ disk_sha1, entry, entry_size,
+ NULL);
+
+ free(entry);
+ } else if (sc_type == RADV_SC_TYPE_READ_DISK_CACHE) {
+ uint8_t disk_sha1[20];
+ if (!radv_sc_read(fd_secure_output, disk_sha1, sizeof(uint8_t) * 20, true))
+ return VK_ERROR_DEVICE_LOST;
+
+ if (memcmp(disk_sha1, allowed_hashes[0], 20) &&
+ memcmp(disk_sha1, allowed_hashes[1], 20))
+ return VK_ERROR_DEVICE_LOST;
+
+ size_t size;
+ struct cache_entry *entry = (struct cache_entry *)
+ disk_cache_get(device->physical_device->disk_cache,
+ disk_sha1, &size);
+
+ uint8_t found = entry ? 1 : 0;
+ write(fd_secure_input, &found, sizeof(uint8_t));
+
+ if (found) {
+ write(fd_secure_input, &size, sizeof(size_t));
+ write(fd_secure_input, entry, size);
+ }
+
+ free(entry);
+ }
+ }
+
+ sc_type = RADV_SC_TYPE_DESTROY_DEVICE;
+ write(fd_secure_input, &sc_type, sizeof(sc_type));
+
+ mtx_lock(&device->sc_state->secure_compile_mutex);
+ device->sc_state->secure_compile_thread_counter--;
+ device->sc_state->secure_compile_processes[process].in_use = false;
+ mtx_unlock(&device->sc_state->secure_compile_mutex);
+
+ return VK_SUCCESS;
+}
+