Module Name: src Committed By: maxv Date: Sun Aug 21 10:07:15 UTC 2016
Modified Files: src/sys/arch/amd64/amd64: gdt.c Log Message: Explain a little what we are doing. Also, make sure gdt_init_cpu is called on the currently running CPU. Theoretically, we could put the same KASSERT in gdt_reload_cpu, but the associated IPI is never sent, which is another issue. To generate a diff of this commit: cvs rdiff -u -r1.31 -r1.32 src/sys/arch/amd64/amd64/gdt.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/amd64/amd64/gdt.c diff -u src/sys/arch/amd64/amd64/gdt.c:1.31 src/sys/arch/amd64/amd64/gdt.c:1.32 --- src/sys/arch/amd64/amd64/gdt.c:1.31 Sun Aug 21 08:30:22 2016 +++ src/sys/arch/amd64/amd64/gdt.c Sun Aug 21 10:07:15 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: gdt.c,v 1.31 2016/08/21 08:30:22 christos Exp $ */ +/* $NetBSD: gdt.c,v 1.32 2016/08/21 10:07:15 maxv Exp $ */ /*- * Copyright (c) 1996, 1997, 2009 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.31 2016/08/21 08:30:22 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.32 2016/08/21 10:07:15 maxv Exp $"); #include "opt_multiprocessor.h" #include "opt_xen.h" @@ -105,7 +105,8 @@ set_sys_gdt(int slot, void *base, size_t } /* - * Initialize the GDT. + * Initialize the GDT. We already have a gdtstore, which was temporarily used + * by the bootstrap code. Now, we allocate a new gdtstore, and put it in cpu0. */ void gdt_init(void) @@ -120,11 +121,18 @@ gdt_init(void) gdt_next = 0; gdt_free = GNULL_SEL; gdt_dynavail = - (gdt_size - DYNSEL_START) / sizeof (struct sys_segment_descriptor); + (gdt_size - DYNSEL_START) / sizeof(struct sys_segment_descriptor); old_gdt = gdtstore; + + /* Allocate MAXGDTSIZ bytes of virtual memory. */ gdtstore = (char *)uvm_km_alloc(kernel_map, MAXGDTSIZ, 0, UVM_KMF_VAONLY); + + /* + * Allocate only MINGDTSIZ bytes of physical memory. We will grow this + * area in gdt_grow at run-time if needed. + */ for (va = (vaddr_t)gdtstore; va < (vaddr_t)gdtstore + MINGDTSIZ; va += PAGE_SIZE) { pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO); @@ -135,17 +143,21 @@ gdt_init(void) VM_PROT_READ | VM_PROT_WRITE, 0); } pmap_update(pmap_kernel()); + + /* Copy the initial bootstrap GDT into the new area. */ memcpy(gdtstore, old_gdt, DYNSEL_START); ci->ci_gdt = (void *)gdtstore; #ifndef XEN set_sys_segment(GDT_ADDR_SYS(gdtstore, GLDT_SEL), ldtstore, LDT_SIZE - 1, SDT_SYSLDT, SEL_KPL, 0); #endif + gdt_init_cpu(ci); } /* - * Allocate shadow GDT for a slave CPU. + * Allocate shadow GDT for a secondary CPU. It contains the same values as the + * GDT present in cpu0 (gdtstore). */ void gdt_alloc_cpu(struct cpu_info *ci) @@ -157,6 +169,7 @@ gdt_alloc_cpu(struct cpu_info *ci) ci->ci_gdt = (union descriptor *)uvm_km_alloc(kernel_map, max_len, 0, UVM_KMF_VAONLY); + for (va = (vaddr_t)ci->ci_gdt; va < (vaddr_t)ci->ci_gdt + min_len; va += PAGE_SIZE) { while ((pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO)) @@ -167,20 +180,22 @@ gdt_alloc_cpu(struct cpu_info *ci) VM_PROT_READ | VM_PROT_WRITE, 0); } pmap_update(pmap_kernel()); + memset(ci->ci_gdt, 0, min_len); memcpy(ci->ci_gdt, gdtstore, gdt_size); } - /* - * Load appropriate gdt descriptor; we better be running on *ci - * (for the most part, this is how a CPU knows who it is). + * Load appropriate GDT descriptor into the currently running CPU, which must + * be ci. */ void gdt_init_cpu(struct cpu_info *ci) { struct region_descriptor region; + KASSERT(curcpu() == ci); + #ifndef XEN setregion(®ion, ci->ci_gdt, (uint16_t)(MAXGDTSIZ - 1)); #else @@ -206,7 +221,9 @@ gdt_reload_cpu(struct cpu_info *ci) #if !defined(XEN) || defined(USER_LDT) /* - * Grow the GDT. + * Grow the GDT. The GDT is present on each CPU, so we need to iterate over all + * of them. We already have the virtual memory, we only need to grow the + * physical memory. */ static void gdt_grow(void) @@ -305,10 +322,13 @@ tss_alloc(struct x86_64_tss *tss) int slot; mutex_enter(&cpu_lock); + slot = gdt_get_slot(); - set_sys_gdt(slot, tss, sizeof (struct x86_64_tss) - 1, - SDT_SYS386TSS, SEL_KPL, 0); + set_sys_gdt(slot, tss, sizeof(struct x86_64_tss) - 1, SDT_SYS386TSS, + SEL_KPL, 0); + mutex_exit(&cpu_lock); + return GDYNSEL(slot, SEL_KPL); #else /* XEN */ /* TSS, what for? */