aboutsummaryrefslogtreecommitdiffstats
path: root/xen-2.4.16/arch/i386/mm.c
blob: 2260882efca7b1f9a0f12a3ada7de6b70020117d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <xeno/config.h>
#include <xeno/lib.h>
#include <xeno/init.h>
#include <xeno/mm.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/fixmap.h>

static inline void set_pte_phys (unsigned long vaddr,
                                 l1_pgentry_t entry)
{
    l2_pgentry_t *l2ent;
    l1_pgentry_t *l1ent;

    l2ent = idle0_pg_table + l2_table_offset(vaddr);
    l1ent = l2_pgentry_to_l1(*l2ent) + l1_table_offset(vaddr);
    *l1ent = entry;

    /* It's enough to flush this one mapping. */
    __flush_tlb_one(vaddr);
}

void __set_fixmap (enum fixed_addresses idx, 
                   l1_pgentry_t entry)
{
    unsigned long address = __fix_to_virt(idx);

    if (idx >= __end_of_fixed_addresses) {
        printk("Invalid __set_fixmap\n");
        return;
    }
    set_pte_phys(address, entry);
}

static void __init fixrange_init (unsigned long start, 
                                  unsigned long end, l2_pgentry_t *pg_base)
{
    l2_pgentry_t *l2e;
    int i;
    unsigned long vaddr, page;

    vaddr = start;
    i = l2_table_offset(vaddr);
    l2e = pg_base + i;

    for ( ; (i < ENTRIES_PER_L2_PAGETABLE) && (vaddr != end); l2e++, i++ ) 
    {
        if ( !l2_pgentry_empty(*l2e) ) continue;
        page = (unsigned long)get_free_page(GFP_KERNEL);
        clear_page(page);
        *l2e = mk_l2_pgentry(__pa(page) | PAGE_HYPERVISOR);
        vaddr += 1 << L2_PAGETABLE_SHIFT;
    }
}

void __init paging_init(void)
{
    unsigned long addr;
    void *ioremap_pt;

    /* XXX initialised in boot.S */
    /*if ( cpu_has_pge ) set_in_cr4(X86_CR4_PGE);*/
    /*if ( cpu_has_pse ) set_in_cr4(X86_CR4_PSE);*/
    /*if ( cpu_has_pae ) set_in_cr4(X86_CR4_PAE);*/

    /*
     * Fixed mappings, only the page table structure has to be
     * created - mappings will be set by set_fixmap():
     */
    addr = FIXADDR_START & ~((1<<L2_PAGETABLE_SHIFT)-1);
    fixrange_init(addr, 0, idle0_pg_table);

    /* Create page table for ioremap(). */
    ioremap_pt = (void *)get_free_page(GFP_KERNEL);
    clear_page(ioremap_pt);
    idle0_pg_table[MAPCACHE_VIRT_START >> L2_PAGETABLE_SHIFT] = 
        mk_l2_pgentry(__pa(ioremap_pt) | PAGE_HYPERVISOR);
}

void __init zap_low_mappings (void)
{
    int i, j;
    for ( i = 0; i < smp_num_cpus; i++ )
    {
        for ( j = 0; j < DOMAIN_ENTRIES_PER_L2_PAGETABLE; j++ )
        {
            idle_pg_table[i][j] = mk_l2_pgentry(0);
        }
    }
    flush_tlb_all();
}


long do_stack_and_ldt_switch(
    unsigned long ss, unsigned long esp, unsigned long ldts)
{
    int nr = smp_processor_id();
    struct tss_struct *t = &init_tss[nr];

    if ( (ss == __HYPERVISOR_CS) || (ss == __HYPERVISOR_DS) )
        return -1;

    if ( ldts != current->mm.ldt_sel )
    {
        unsigned long *ptabent = GET_GDT_ADDRESS(current);
        /* Out of range for GDT table? */
        if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1;
        ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */
        /* Not an LDT entry? (S=0b, type =0010b) */
        if ( (*ptabent & 0x00001f00) != 0x00000200 ) return -1;
        current->mm.ldt_sel = ldts;
        __load_LDT(ldts);
    }

    current->thread.ss1  = ss;
    current->thread.esp1 = esp;
    t->ss1  = ss;
    t->esp1 = esp;

    return 0;
}


long do_set_gdt(unsigned long *frame_list, int entries)
{
    return -ENOSYS;
}


long do_update_descriptor(
    unsigned long pa, unsigned long word1, unsigned long word2)
{
    return -ENOSYS;
}