module_create.c 8.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
/*
 * module_load.c
 *
 * For creating an empty LCD and loading a kernel
 * module in it.
 *
 * Copyright: University of Utah
 */

10
11
12
static int do_grant_and_map_for_mem(cptr_t lcd, struct lcd_create_ctx *ctx,
				void *mem, gpa_t map_base,
				cptr_t *dest)
13
14
{
	int ret;
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
	cptr_t mo;
	unsigned int order;
	/*
	 * Look up the cptr for the *creator*
	 */
	ret = lcd_virt_to_cptr(__gva((unsigned long)mem), &mo, &order);
	if (ret) {
		LIBLCD_ERR("lookup failed");
		goto fail1;
	}
	/*
	 * Alloc a cptr in the new LCD cptr cache
	 */
	ret = cptr_alloc(lcd_to_boot_cptr_cache(ctx), dest);
	if (ret) {
		LIBLCD_ERR("cptr alloc failed");
		goto fail2;
	}
	/*
	 * Grant and map the memory
	 */
	ret = lcd_memory_grant_and_map(lcd, mo, *dest, map_base);
	if (ret) {
		LIBLCD_ERR("grant and map failed");
		goto fail3;
	}

	return 0;
43

44
45
46
47
48
49
fail3:
	cptr_free(lcd_to_boot_cptr_cache(ctx), *dest);
fail2:
fail1:
	return ret;
}
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
static int do_kernel_module_grant_map(cptr_t lcd, struct lcd_create_ctx *ctx,
				gva_t m_init_link_addr, gva_t m_core_link_addr)
{
	unsigned long offset;
	cptr_t *c;
	/*
	 * Map module init and core at correct offsets
	 */
	offset = gva_val(m_init_link_addr) - 
		gva_val(LCD_KERNEL_MODULE_REGION_GV_ADDR);
	c = &(lcd_to_boot_info(ctx)->lcd_boot_cptrs.module_init);
	ret = do_grant_and_map_for_mem(lcd, ctx, ctx->m_init_bits,
				gpa_add(LCD_KERNEL_MODULE_REGION_GP_ADDR,
					offset),
				c);
	if (ret)
		goto fail1;
68

69
70
71
72
73
74
75
76
77
	offset = gva_val(m_core_link_addr) - 
		gva_val(LCD_KERNEL_MODULE_REGION_GV_ADDR);
	c = &(lcd_to_boot_info(ctx)->lcd_boot_cptrs.module_core);
	ret = do_grant_and_map_for_mem(lcd, ctx, ctx->m_core_bits,
				gpa_add(LCD_KERNEL_MODULE_REGION_GP_ADDR,
					offset),
				c);
	if (ret)
		goto fail2;
78

79
80
81
82
fail2:
fail1:
	return ret;
}
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
static int setup_phys_addr_space(cptr_t lcd, struct lcd_create_ctx *ctx,
				gva_t m_init_link_addr, gva_t m_core_link_addr)
{
	int ret;
	cptr_t *c;
	/*
	 * Map and grant bootstrap pages, page tables, and stack
	 */
	c = &(lcd_to_boot_info(ctx)->lcd_boot_cptrs.boot_pages);
	ret = do_grant_and_map_for_mem(lcd, ctx, ctx->lcd_boot_info,
				LCD_BOOTSTRAP_PAGES_GP_ADDR, c);
	if (ret)
		goto fail1;
	c = &(lcd_to_boot_info(ctx)->lcd_boot_cptrs.gv);
	ret = do_grant_and_map_for_mem(lcd, ctx, ctx->pgd,
				LCD_BOOTSTRAP_PAGE_TABLES_GP_ADDR, c);
	if (ret)
		goto fail2;
	c = &(lcd_to_boot_info(ctx)->lcd_boot_cptrs.stack);
	ret = do_grant_and_map_for_mem(lcd, ctx, ctx->stack,
				LCD_STACK_GP_ADDR, c);
	if (ret)
		goto fail3;
	/*
	 * Map and grant kernel module
	 */
	ret = do_kernel_module_grant_map(lcd, ctx,
					m_init_link_addr, m_core_link_addr);
	if (ret)
		goto fail4;
	
	return 0;
116

117
118
119
120
121
fail4:  /* Just return; caller should kill new LCD and free up resources. */
fail3:
fail2:
fail1:
	return ret;
122
123
}

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
static void setup_lcd_pud(struct lcd_create_ctx *ctx)
{
	/*
	 * This assumes the PAT has Writeback in PAT0, Uncacheable in PAT1.
	 *
	 * See Intel SDM V3 11.12.3 for how PAT indexing is done.
	 */
	unsigned int i;
	unsigned int ioremap_offset = LCD_IOREMAP_REGION_OFFSET >> 30;
	unsigned int after_ioremap_offset = ioremap_offset +
		LCD_IOREMAP_REGION_SIZE >> 30;
	pteval_t wb_flags = _PAGE_PRESENT | _PAGE_RW | _PAGE_PSE;
	pteval_t uc_flags = _PAGE_PRESENT | _PAGE_RW | _PAGE_PSE | _PAGE_PWT;
	pud_t *pud_entry;
	/*
	 * Map first GBs as write back
	 */
	for (i = 0; i < ioremap_offset; i++) {
		pud_entry = &ctx->pud[i];
		set_pud(pud_entry,
			(LCD_PHYS_BASE + i * (1UL << 30)) | wb_flags)
	}
	/*
	 * Map ioremap GBs as uncacheable
	 */
	for (i = ioremap_offset; i < after_ioremap_offset; i++) {
		pud_entry = &ctx->pud[i];
		set_pud(pud_entry,
			(LCD_PHYS_BASE + i * (1UL << 30)) | uc_flags)
	}
	/*
	 * Map remaining GBs as write back
	 */
	for (i = after_ioremap_offset; i < 512; i++) {
		pud_entry = &ctx->pud[i];
		set_pud(pud_entry,
			(LCD_PHYS_BASE + i * (1UL << 30)) | wb_flags)
	}
}

static void setup_lcd_pgd(struct lcd_create_ctx *ctx)
{
	pgd_t *pgd_entry;
	gpa_t pud_gpa;
	pteval_t flags = 0;

	pgd_entry = &ctx->pgd[511]; /* only map last pud for high 512 GBs */

	/* pud comes after pgd */
	pud_gpa = gpa_add(LCD_BOOTSTRAP_PAGE_TABLES_GP_ADDR, PAGE_SIZE);

	flags |= _PAGE_PRESENT;
	flags |= _PAGE_RW;

	set_pgd(pgd_entry,
		__pgd(gpa_val(pud_gpa) | flags))
}

static void setup_virt_addr_space(struct lcd_create_ctx *ctx)
{
	/*
	 * pgd and pud (PML4 and PDPT) should already be zero'd out
	 *
	 * Set up root pgd
	 */
	setup_lcd_pgd(ctx);
	/*
	 * Set up pud (only one for high 512 GBs)
	 */
	setup_lcd_pud(ctx);
}

196
197
198
199
200
static int setup_addr_spaces(cptr_t lcd, struct lcd_create_ctx *ctx,
			gva_t m_init_link_addr, gva_t m_core_link_addr)
{
	int ret;
	/*
201
202
	 * Set up physical address space (except UTCB - that's done
	 * via lcd_config)
203
204
205
206
207
208
209
210
211
212
	 */
	ret = setup_phys_addr_space(lcd, cxt, m_init_link_addr, 
				m_core_link_addr);
	if (ret) {
		LIBLCD_ERR("error setting up phys addr space");
		goto fail1;
	}
	/*
	 * Set up virtual address space
	 */
213
	setup_virt_addr_space(cxt);
214
215
216

	return 0;

217
fail1: /* just return non-zero ret; caller will free mem */
218
219
220
	return ret;
}

221
222
223
224
225
226
227
228
229
230
231
232
static int init_create_ctx(struct lcd_create_ctx **ctx_out)
{
	struct lcd_create_ctx *ctx;
	/*
	 * Alloc ctx
	 */
	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
	if (!ctx) {
		LIBLCD_ERR("kzalloc failed");
		ret = -ENOMEM;
		goto fail1;
	}
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

	*ctx_out = ctx;

	return 0;

fail1:
	return ret;
}

static void destroy_create_ctx(struct lcd_create_ctx *ctx)
{
	/*
	 * Remove pages from our address space and delete our
	 * capabilities to them. If these are the last caps,
	 * pages will be freed by microkernel.
	 */
	if (ctx->m_init_bits)
		lcd_module_release(ctx->m_init_bits, ctx->m_core_bits);
	if (ctx->stack)
		lcd_free_pages(lcd_virt_to_page(ctx->stack),
			LCD_STACK_ORDER);
	if (ctx->gv_pgd)
		lcd_free_pages(lcd_virt_to_page(ctx->gv_pgd),
			LCD_BOOTSTRAP_PAGE_TABLES_ORDER);
	if (ctx->lcd_boot_info)
		lcd_free_pages(lcd_virt_to_page(ctx->lcd_boot_info),
			LCD_BOOTSTRAP_PAGES_ORDER);
	/*
	 * Free the ctx
	 */
	kfree(ctx);
}

static int get_pages_for_lcd(struct lcd_create_ctx *ctx)
{
	struct page *p1, *p2, *p3;
269
	/*
270
271
272
	 * We explicity zero things out. If this code is used inside
	 * an LCD, it may not zero out the alloc'd pages.
	 *
273
274
	 * Alloc boot pages
	 */
275
276
277
278
279
280
	p1 = lcd_alloc_pages(0, LCD_BOOTSTRAP_PAGES_ORDER);
	if (!p1) {
		LIBLCD_ERR("alloc boot pages failed");
		ret = -ENOMEM;
		goto fail1;
	}
281
	memset(lcd_page_address(p1), 0, LCD_BOOTSTRAP_PAGES_SIZE);
282
283
284
285
286
	ctx->lcd_boot_info = lcd_page_address(p1);
	/*
	 * Alloc boot page tables
	 */
	p2 = lcd_alloc_pages(0, LCD_BOOTSTRAP_PAGE_TABLES_ORDER);
287
	if (!p) {
288
		LIBLCD_ERR("alloc boot page tables failed");
289
290
291
		ret = -ENOMEM;
		goto fail2;
	}
292
	memset(lcd_page_address(p2), 0, LCD_BOOTSTRAP_PAGE_TABLES_SIZE);
293
294
	ctx->gv_pgd = lcd_page_address(p2);
	ctx->gv_pud = lcd_page_address(p2 + 1);
295
	/*
296
	 * Alloc stack
297
	 */
298
299
300
301
	p3 = lcd_alloc_pages(0, LCD_STACK_ORDER);
	if (!p3) {
		LIBLCD_ERR("alloc stack pages failed");
		ret = -ENOMEM;
302
303
		goto fail3;
	}
304
	memset(lcd_page_address(p3), 0, LCD_STACK_SIZE);
305
	ctx->stack = lcd_page_address(p3);
306
307
308
309

	return 0;

fail3:
310
	lcd_free_pages(p2, LCD_BOOTSTRAP_PAGE_TABLES_ORDER);
311
fail2:
312
	lcd_free_pages(p1, LCD_BOOTSTRAP_PAGES_ORDER);
313
314
315
316
317
318
319
320
fail1:
	return ret;
}

int lcd_create_module_lcd(char *mdir, char *mname, cptr_t *lcd_out,
			struct lcd_create_ctx **ctx_out)
{
	int ret;
321
	cptr_t m_init_cptr, m_core_cptr;
322
323
324
325
326
327
328
329
330
331
332
	gva_t m_init_link_addr, m_core_link_addr;
	struct lcd_create_ctx *ctx;
	cptr_t lcd;
	/*
	 * Initialize create ctx
	 */
	ret = init_create_ctx(&ctx);
	if (ret) {
		LIBLCD_ERR("error creating ctx");
		goto fail1;
	}
333
334
335
336
337
338
339
340
	/*
	 * Alloc boot pages, stack pages, etc. for LCD
	 */
	ret = get_pages_for_lcd(ctx);
	if (ret) {
		LIBLCD_ERR("error alloc'ing boot, stack pages for LCD");
		goto fail2;
	}
341
342
343
344
	/*
	 * Load kernel module into caller's address space
	 */
	ret = lcd_module_load(mdir, mname,
345
346
			&ctx->m_init_bits, &ctx->m_core_bits,
			&m_init_cptr, &m_core_cptr,
347
348
349
			&m_init_link_addr, &m_core_link_addr);
	if (ret) {
		LIBLCD_ERR("error loading kernel module");
350
		goto fail3;
351
352
	}
	/*
353
354
355
	 * At this point, we have all of the data that will go in the LCD
	 * (the microkernel has the UTCB page)
	 *
356
357
358
359
360
	 * Initialize empty LCD
	 */
	ret = lcd_create(&lcd);
	if (ret) {
		LIBLCD_ERR("error creating empty LCD");
361
		goto fail4;
362
363
364
365
366
367
368
369
	}
	/*
	 * Set up address spaces
	 */
	ret = setup_addr_spaces(lcd, cxt, m_init_link_addr, 
				m_core_link_addr);
	if (ret) {
		LIBLCD_ERR("error setting up address spaces");
370
		goto fail5;
371
372
373
374
375
376
	}
	/*
	 * Configure initial control registers, etc. for LCD
	 */

	/*
377
	 * Return context and lcd
378
379
380
381
382
383
384
385
	 */
	*cxt_out = cxt;
	*lcd_out = lcd;

	return 0;

fail5:
	lcd_cap_delete(lcd);
386
fail4:
387
388
389
390
391
392
fail3:
fail2:
	destroy_create_ctx(ctx);
fail1:
	return ret;
}