diff options
Diffstat (limited to 'drivers/lguest/segments.c')
-rw-r--r-- | drivers/lguest/segments.c | 42 |
1 files changed, 22 insertions, 20 deletions
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c index 9e189cbec7dd..02138450ecf5 100644 --- a/drivers/lguest/segments.c +++ b/drivers/lguest/segments.c | |||
@@ -58,7 +58,7 @@ static int ignored_gdt(unsigned int num) | |||
58 | * Protection Fault in the Switcher when it restores a Guest segment register | 58 | * Protection Fault in the Switcher when it restores a Guest segment register |
59 | * which tries to use that entry. Then we kill the Guest for causing such a | 59 | * which tries to use that entry. Then we kill the Guest for causing such a |
60 | * mess: the message will be "unhandled trap 256". */ | 60 | * mess: the message will be "unhandled trap 256". */ |
61 | static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) | 61 | static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end) |
62 | { | 62 | { |
63 | unsigned int i; | 63 | unsigned int i; |
64 | 64 | ||
@@ -71,14 +71,14 @@ static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) | |||
71 | /* Segment descriptors contain a privilege level: the Guest is | 71 | /* Segment descriptors contain a privilege level: the Guest is |
72 | * sometimes careless and leaves this as 0, even though it's | 72 | * sometimes careless and leaves this as 0, even though it's |
73 | * running at privilege level 1. If so, we fix it here. */ | 73 | * running at privilege level 1. If so, we fix it here. */ |
74 | if ((lg->arch.gdt[i].b & 0x00006000) == 0) | 74 | if ((cpu->arch.gdt[i].b & 0x00006000) == 0) |
75 | lg->arch.gdt[i].b |= (GUEST_PL << 13); | 75 | cpu->arch.gdt[i].b |= (GUEST_PL << 13); |
76 | 76 | ||
77 | /* Each descriptor has an "accessed" bit. If we don't set it | 77 | /* Each descriptor has an "accessed" bit. If we don't set it |
78 | * now, the CPU will try to set it when the Guest first loads | 78 | * now, the CPU will try to set it when the Guest first loads |
79 | * that entry into a segment register. But the GDT isn't | 79 | * that entry into a segment register. But the GDT isn't |
80 | * writable by the Guest, so bad things can happen. */ | 80 | * writable by the Guest, so bad things can happen. */ |
81 | lg->arch.gdt[i].b |= 0x00000100; | 81 | cpu->arch.gdt[i].b |= 0x00000100; |
82 | } | 82 | } |
83 | } | 83 | } |
84 | 84 | ||
@@ -109,31 +109,31 @@ void setup_default_gdt_entries(struct lguest_ro_state *state) | |||
109 | 109 | ||
110 | /* This routine sets up the initial Guest GDT for booting. All entries start | 110 | /* This routine sets up the initial Guest GDT for booting. All entries start |
111 | * as 0 (unusable). */ | 111 | * as 0 (unusable). */ |
112 | void setup_guest_gdt(struct lguest *lg) | 112 | void setup_guest_gdt(struct lg_cpu *cpu) |
113 | { | 113 | { |
114 | /* Start with full 0-4G segments... */ | 114 | /* Start with full 0-4G segments... */ |
115 | lg->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT; | 115 | cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT; |
116 | lg->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT; | 116 | cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT; |
117 | /* ...except the Guest is allowed to use them, so set the privilege | 117 | /* ...except the Guest is allowed to use them, so set the privilege |
118 | * level appropriately in the flags. */ | 118 | * level appropriately in the flags. */ |
119 | lg->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13); | 119 | cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13); |
120 | lg->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13); | 120 | cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13); |
121 | } | 121 | } |
122 | 122 | ||
123 | /*H:650 An optimization of copy_gdt(), for just the three "thead-local storage" | 123 | /*H:650 An optimization of copy_gdt(), for just the three "thead-local storage" |
124 | * entries. */ | 124 | * entries. */ |
125 | void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt) | 125 | void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt) |
126 | { | 126 | { |
127 | unsigned int i; | 127 | unsigned int i; |
128 | 128 | ||
129 | for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++) | 129 | for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++) |
130 | gdt[i] = lg->arch.gdt[i]; | 130 | gdt[i] = cpu->arch.gdt[i]; |
131 | } | 131 | } |
132 | 132 | ||
133 | /*H:640 When the Guest is run on a different CPU, or the GDT entries have | 133 | /*H:640 When the Guest is run on a different CPU, or the GDT entries have |
134 | * changed, copy_gdt() is called to copy the Guest's GDT entries across to this | 134 | * changed, copy_gdt() is called to copy the Guest's GDT entries across to this |
135 | * CPU's GDT. */ | 135 | * CPU's GDT. */ |
136 | void copy_gdt(const struct lguest *lg, struct desc_struct *gdt) | 136 | void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt) |
137 | { | 137 | { |
138 | unsigned int i; | 138 | unsigned int i; |
139 | 139 | ||
@@ -141,21 +141,22 @@ void copy_gdt(const struct lguest *lg, struct desc_struct *gdt) | |||
141 | * replaced. See ignored_gdt() above. */ | 141 | * replaced. See ignored_gdt() above. */ |
142 | for (i = 0; i < GDT_ENTRIES; i++) | 142 | for (i = 0; i < GDT_ENTRIES; i++) |
143 | if (!ignored_gdt(i)) | 143 | if (!ignored_gdt(i)) |
144 | gdt[i] = lg->arch.gdt[i]; | 144 | gdt[i] = cpu->arch.gdt[i]; |
145 | } | 145 | } |
146 | 146 | ||
147 | /*H:620 This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). | 147 | /*H:620 This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). |
148 | * We copy it from the Guest and tweak the entries. */ | 148 | * We copy it from the Guest and tweak the entries. */ |
149 | void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num) | 149 | void load_guest_gdt(struct lg_cpu *cpu, unsigned long table, u32 num) |
150 | { | 150 | { |
151 | struct lguest *lg = cpu->lg; | ||
151 | /* We assume the Guest has the same number of GDT entries as the | 152 | /* We assume the Guest has the same number of GDT entries as the |
152 | * Host, otherwise we'd have to dynamically allocate the Guest GDT. */ | 153 | * Host, otherwise we'd have to dynamically allocate the Guest GDT. */ |
153 | if (num > ARRAY_SIZE(lg->arch.gdt)) | 154 | if (num > ARRAY_SIZE(cpu->arch.gdt)) |
154 | kill_guest(lg, "too many gdt entries %i", num); | 155 | kill_guest(lg, "too many gdt entries %i", num); |
155 | 156 | ||
156 | /* We read the whole thing in, then fix it up. */ | 157 | /* We read the whole thing in, then fix it up. */ |
157 | __lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0])); | 158 | __lgread(lg, cpu->arch.gdt, table, num * sizeof(cpu->arch.gdt[0])); |
158 | fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt)); | 159 | fixup_gdt_table(cpu, 0, ARRAY_SIZE(cpu->arch.gdt)); |
159 | /* Mark that the GDT changed so the core knows it has to copy it again, | 160 | /* Mark that the GDT changed so the core knows it has to copy it again, |
160 | * even if the Guest is run on the same CPU. */ | 161 | * even if the Guest is run on the same CPU. */ |
161 | lg->changed |= CHANGED_GDT; | 162 | lg->changed |= CHANGED_GDT; |
@@ -165,12 +166,13 @@ void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num) | |||
165 | * Remember that this happens on every context switch, so it's worth | 166 | * Remember that this happens on every context switch, so it's worth |
166 | * optimizing. But wouldn't it be neater to have a single hypercall to cover | 167 | * optimizing. But wouldn't it be neater to have a single hypercall to cover |
167 | * both cases? */ | 168 | * both cases? */ |
168 | void guest_load_tls(struct lguest *lg, unsigned long gtls) | 169 | void guest_load_tls(struct lg_cpu *cpu, unsigned long gtls) |
169 | { | 170 | { |
170 | struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN]; | 171 | struct desc_struct *tls = &cpu->arch.gdt[GDT_ENTRY_TLS_MIN]; |
172 | struct lguest *lg = cpu->lg; | ||
171 | 173 | ||
172 | __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); | 174 | __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); |
173 | fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); | 175 | fixup_gdt_table(cpu, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); |
174 | /* Note that just the TLS entries have changed. */ | 176 | /* Note that just the TLS entries have changed. */ |
175 | lg->changed |= CHANGED_GDT_TLS; | 177 | lg->changed |= CHANGED_GDT_TLS; |
176 | } | 178 | } |