add lab answers
This commit is contained in:
99
labcodes_answer/lab1_result/kern/mm/pmm.c
Normal file
99
labcodes_answer/lab1_result/kern/mm/pmm.c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <defs.h>
|
||||
#include <x86.h>
|
||||
#include <mmu.h>
|
||||
#include <memlayout.h>
|
||||
#include <pmm.h>
|
||||
|
||||
/* *
|
||||
* Task State Segment:
|
||||
*
|
||||
* The TSS may reside anywhere in memory. A special segment register called
|
||||
* the Task Register (TR) holds a segment selector that points a valid TSS
|
||||
* segment descriptor which resides in the GDT. Therefore, to use a TSS
|
||||
* the following must be done in function gdt_init:
|
||||
* - create a TSS descriptor entry in GDT
|
||||
* - add enough information to the TSS in memory as needed
|
||||
* - load the TR register with a segment selector for that segment
|
||||
*
|
||||
* There are several fileds in TSS for specifying the new stack pointer when a
|
||||
* privilege level change happens. But only the fields SS0 and ESP0 are useful
|
||||
* in our os kernel.
|
||||
*
|
||||
* The field SS0 contains the stack segment selector for CPL = 0, and the ESP0
|
||||
* contains the new ESP value for CPL = 0. When an interrupt happens in protected
|
||||
* mode, the x86 CPU will look in the TSS for SS0 and ESP0 and load their value
|
||||
* into SS and ESP respectively.
|
||||
* */
|
||||
static struct taskstate ts = {0};
|
||||
|
||||
/* *
|
||||
* Global Descriptor Table:
|
||||
*
|
||||
* The kernel and user segments are identical (except for the DPL). To load
|
||||
* the %ss register, the CPL must equal the DPL. Thus, we must duplicate the
|
||||
* segments for the user and the kernel. Defined as follows:
|
||||
* - 0x0 : unused (always faults -- for trapping NULL far pointers)
|
||||
* - 0x8 : kernel code segment
|
||||
* - 0x10: kernel data segment
|
||||
* - 0x18: user code segment
|
||||
* - 0x20: user data segment
|
||||
* - 0x28: defined for tss, initialized in gdt_init
|
||||
* */
|
||||
static struct segdesc gdt[] = {
|
||||
SEG_NULL,
|
||||
[SEG_KTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_KERNEL),
|
||||
[SEG_KDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_KERNEL),
|
||||
[SEG_UTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_USER),
|
||||
[SEG_UDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_USER),
|
||||
[SEG_TSS] = SEG_NULL,
|
||||
};
|
||||
|
||||
static struct pseudodesc gdt_pd = {
|
||||
sizeof(gdt) - 1, (uint32_t)gdt
|
||||
};
|
||||
|
||||
/* *
|
||||
* lgdt - load the global descriptor table register and reset the
|
||||
* data/code segement registers for kernel.
|
||||
* */
|
||||
static inline void
|
||||
lgdt(struct pseudodesc *pd) {
|
||||
asm volatile ("lgdt (%0)" :: "r" (pd));
|
||||
asm volatile ("movw %%ax, %%gs" :: "a" (USER_DS));
|
||||
asm volatile ("movw %%ax, %%fs" :: "a" (USER_DS));
|
||||
asm volatile ("movw %%ax, %%es" :: "a" (KERNEL_DS));
|
||||
asm volatile ("movw %%ax, %%ds" :: "a" (KERNEL_DS));
|
||||
asm volatile ("movw %%ax, %%ss" :: "a" (KERNEL_DS));
|
||||
// reload cs
|
||||
asm volatile ("ljmp %0, $1f\n 1:\n" :: "i" (KERNEL_CS));
|
||||
}
|
||||
|
||||
/* temporary kernel stack */
|
||||
uint8_t stack0[1024];
|
||||
|
||||
/* gdt_init - initialize the default GDT and TSS */
|
||||
static void
|
||||
gdt_init(void) {
|
||||
// Setup a TSS so that we can get the right stack when we trap from
|
||||
// user to the kernel. But not safe here, it's only a temporary value,
|
||||
// it will be set to KSTACKTOP in lab2.
|
||||
ts.ts_esp0 = (uint32_t)&stack0 + sizeof(stack0);
|
||||
ts.ts_ss0 = KERNEL_DS;
|
||||
|
||||
// initialize the TSS filed of the gdt
|
||||
gdt[SEG_TSS] = SEG16(STS_T32A, (uint32_t)&ts, sizeof(ts), DPL_KERNEL);
|
||||
gdt[SEG_TSS].sd_s = 0;
|
||||
|
||||
// reload all segment registers
|
||||
lgdt(&gdt_pd);
|
||||
|
||||
// load the TSS
|
||||
ltr(GD_TSS);
|
||||
}
|
||||
|
||||
/* pmm_init - initialize the physical memory management */
|
||||
void
|
||||
pmm_init(void) {
|
||||
gdt_init();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user