blob: 93fe88df3e77e5b921e1320418f586d68d2fb0c0 [file] [log] [blame]
Andrew Walbran66839252019-11-07 16:01:48 +00001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "hf/spci.h"
18
19#include "hf/types.h"
20
21/*
22 * Copied from hf/arch/std.h because we can't include Hafnium internal headers
23 * here.
24 */
25#ifndef align_up
26#define align_up(v, a) (((uintptr_t)(v) + ((a)-1)) & ~((a)-1))
27#endif
28
29/**
30 * Helper method to fill in the information about the architected message.
31 */
32void spci_architected_message_init(void *message, enum spci_memory_share type)
33{
34 /* Fill the architected header. */
35 struct spci_architected_message_header *architected_header =
36 (struct spci_architected_message_header *)message;
37 architected_header->type = type;
38 architected_header->reserved[0] = 0;
39 architected_header->reserved[1] = 0;
40 architected_header->reserved[2] = 0;
41}
42
43/**
44 * Initialises the given `spci_memory_region` and copies the constituent
45 * information to it. Returns the length in bytes occupied by the data copied to
46 * `memory_region` (attributes, constituents and memory region header size).
47 */
48uint32_t spci_memory_region_init(
49 struct spci_memory_region *memory_region, spci_vm_id_t receiver,
50 const struct spci_memory_region_constituent constituents[],
51 uint32_t constituent_count, uint32_t tag,
52 enum spci_memory_access access, enum spci_memory_type type,
53 enum spci_memory_cacheability cacheability,
54 enum spci_memory_shareability shareability)
55{
56 uint32_t constituents_length =
57 constituent_count *
58 sizeof(struct spci_memory_region_constituent);
59 uint32_t index;
60 struct spci_memory_region_constituent *region_constituents;
61 uint16_t attributes = 0;
62
63 /* Set memory region's page attributes. */
64 spci_set_memory_access_attr(&attributes, access);
65 spci_set_memory_type_attr(&attributes, type);
66 spci_set_memory_cacheability_attr(&attributes, cacheability);
67 spci_set_memory_shareability_attr(&attributes, shareability);
68
69 memory_region->tag = tag;
70 memory_region->flags = 0;
71 memory_region->page_count = 0;
72 memory_region->constituent_count = constituent_count;
73 memory_region->attribute_count = 1;
74 memory_region->attributes[0].receiver = receiver;
75 memory_region->attributes[0].memory_attributes = attributes;
76
77 /*
78 * Constituent offset must be aligned to a 64-bit boundary so that
79 * 64-bit addresses can be copied without alignment faults.
80 */
81 memory_region->constituent_offset = align_up(
82 sizeof(struct spci_memory_region) +
83 memory_region->attribute_count *
84 sizeof(struct spci_memory_region_attributes),
85 8);
86 region_constituents =
87 spci_memory_region_get_constituents(memory_region);
88
89 for (index = 0; index < constituent_count; index++) {
90 region_constituents[index] = constituents[index];
91 region_constituents[index].reserved = 0;
92 memory_region->page_count += constituents[index].page_count;
93 }
94
95 /*
96 * TODO: Add assert ensuring that the specified message
97 * length is not greater than SPCI_MSG_PAYLOAD_MAX.
98 */
99
100 return memory_region->constituent_offset + constituents_length;
101}
102
103/**
104 * Constructs an 'architected message' for SPCI memory sharing of the given
105 * type.
106 */
107uint32_t spci_memory_init(
108 void *message, enum spci_memory_share share_type, spci_vm_id_t receiver,
109 struct spci_memory_region_constituent *region_constituents,
110 uint32_t constituent_count, uint32_t tag,
111 enum spci_memory_access access, enum spci_memory_type type,
112 enum spci_memory_cacheability cacheability,
113 enum spci_memory_shareability shareability)
114{
115 uint32_t message_length =
116 sizeof(struct spci_architected_message_header);
117 struct spci_memory_region *memory_region =
118 spci_get_memory_region(message);
119
120 /* Fill in the details on the common message header. */
121 spci_architected_message_init(message, share_type);
122
123 /* Fill in memory region. */
124 message_length += spci_memory_region_init(
125 memory_region, receiver, region_constituents, constituent_count,
126 tag, access, type, cacheability, shareability);
127 return message_length;
128}