Changeset 454f1da in mainline


Ignore:
Timestamp:
2007-03-26T19:35:28Z (17 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5d7daff
Parents:
4638401
Message:

Reworked handling of illegal virtual aliases caused by frame reuse.
We moved the incomplete handling from backend's frame method to
backend's page_fault method. The page_fault method is the one that
can create an illegal alias if it writes the userspace frame using
kernel address with a different page color than the page to which is
this frame mapped in userspace. When we detect this, we do D-cache
shootdown on all processors (!!!).

If we add code that accesses userspace memory from kernel address
space, we will have to check for illegal virtual aliases at all such
places.

I tested this on a 4-way simulated E6500 and a real-world Ultra 5,
which has unfortunatelly only one processor.

This solves ticket #26.

Location:
kernel
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/sparc64/include/cpu.h

    r4638401 r454f1da  
    4040#include <arch/asm.h>
    4141
     42#ifdef CONFIG_SMP
     43#include <arch/mm/cache.h>
     44#endif
     45
    4246#define MANUF_FUJITSU           0x04
    4347#define MANUF_ULTRASPARC        0x17    /**< UltraSPARC I, UltraSPARC II */
     
    5458
    5559typedef struct {
    56         uint32_t mid;                   /**< Processor ID as read from UPA_CONFIG. */
     60        uint32_t mid;                   /**< Processor ID as read from
     61                                             UPA_CONFIG. */
    5762        ver_reg_t ver;
    5863        uint32_t clock_frequency;       /**< Processor frequency in Hz. */
    5964        uint64_t next_tick_cmpr;        /**< Next clock interrupt should be
    60                                                                          generated when the TICK register
    61                                                                          matches this value. */
     65                                             generated when the TICK register
     66                                             matches this value. */
     67#ifdef CONFIG_SMP
     68        int dcache_active;
     69        dcache_shootdown_msg_t dcache_messages[DCACHE_MSG_QUEUE_LEN];
     70        count_t dcache_message_count;
     71#endif
    6272} cpu_arch_t;
    6373       
  • kernel/arch/sparc64/include/interrupt.h

    r4638401 r454f1da  
    4747
    4848enum {
    49         IPI_TLB_SHOOTDOWN = VECTOR_TLB_SHOOTDOWN_IPI
     49        IPI_TLB_SHOOTDOWN = VECTOR_TLB_SHOOTDOWN_IPI,
     50        IPI_DCACHE_SHOOTDOWN
    5051};             
    5152
  • kernel/arch/sparc64/include/mm/cache.h

    r4638401 r454f1da  
    4444        dcache_flush_tag(PAGE_COLOR((p)), ADDR2PFN((f)));
    4545
     46/**
     47 * Enumerations to differentiate among different scopes of D-Cache
     48 * invalidation.
     49 */
     50typedef enum {
     51        DCACHE_INVL_INVALID,
     52        DCACHE_INVL_ALL,
     53        DCACHE_INVL_COLOR,
     54        DCACHE_INVL_FRAME
     55} dcache_invalidate_type_t;
     56
     57/**
     58 * Number of messages that can be queued in the cpu_arch_t structure at a time.
     59 */
     60#define DCACHE_MSG_QUEUE_LEN    10
     61
     62/** D-cache shootdown message type. */
     63typedef struct {
     64        dcache_invalidate_type_t type;
     65        int color;
     66        uintptr_t frame;
     67} dcache_shootdown_msg_t;
     68
    4669extern void dcache_flush(void);
    4770extern void dcache_flush_color(int c);
    4871extern void dcache_flush_tag(int c, pfn_t tag);
     72
     73#ifdef CONFIG_SMP
     74extern void dcache_shootdown_start(dcache_invalidate_type_t type, int color,
     75    uintptr_t frame);
     76extern void dcache_shootdown_finalize(void);
     77extern void dcache_shootdown_ipi_recv(void);
     78#else
     79#define dcache_shootdown_start(t, c, f)
     80#define dcache_shootdown_finalize()
     81#define dcache_shootdown_ipi_recv()
     82#endif /* CONFIG_SMP */
    4983
    5084#endif
  • kernel/arch/sparc64/src/cpu/cpu.c

    r4638401 r454f1da  
    5252        CPU->arch.mid = upa_config.mid;
    5353       
     54#if (defined(CONFIG_SMP) && defined(CONFIG_VIRT_IDX_DCACHE))
     55        CPU->arch.dcache_active = 1;
     56        CPU->arch.dcache_message_count = 0;
     57#endif
     58
    5459        /*
    5560         * Detect processor frequency.
  • kernel/arch/sparc64/src/mm/cache.c

    r4638401 r454f1da  
    3232/**
    3333 * @file
     34 * @brief       D-cache shootdown algorithm.
    3435 */
    3536
    3637#include <arch/mm/cache.h>
    3738
     39#ifdef CONFIG_SMP
     40#ifdef CONFIG_VIRT_IDX_DCACHE
     41
     42#include <smp/ipi.h>
     43#include <arch/interrupt.h>
     44#include <synch/spinlock.h>
     45#include <arch.h>
     46#include <debug.h>
     47
     48/**
     49 * This spinlock is used by the processors to synchronize during the D-cache
     50 * shootdown.
     51 */
     52SPINLOCK_INITIALIZE(dcachelock);
     53
     54/** Initialize the D-cache shootdown sequence.
     55 *
     56 * Start the shootdown sequence by sending out an IPI and wait until all
     57 * processors spin on the dcachelock spinlock.
     58 *
     59 * @param type  Scope of the D-cache shootdown.
     60 * @param color Color to be invalidated; applicable only for DCACHE_INVL_COLOR
     61 *              and DCACHE_INVL_FRAME invalidation types.
     62 * @param frame Frame to be invalidated; applicable only for DCACHE_INVL_FRAME
     63 *              invalidation types.
     64 */
     65void dcache_shootdown_start(dcache_invalidate_type_t type, int color,
     66    uintptr_t frame)
     67{
     68        int i;
     69
     70        CPU->arch.dcache_active = 0;
     71        spinlock_lock(&dcachelock);
     72
     73        for (i = 0; i < config.cpu_count; i++) {
     74                cpu_t *cpu;
     75
     76                if (i == CPU->id)
     77                        continue;
     78
     79                cpu = &cpus[i];
     80                spinlock_lock(&cpu->lock);
     81                if (cpu->arch.dcache_message_count ==
     82                    DCACHE_MSG_QUEUE_LEN) {
     83                        /*
     84                         * The queue is full, flush the cache entirely.
     85                         */
     86                        cpu->arch.dcache_message_count = 1;
     87                        cpu->arch.dcache_messages[0].type = DCACHE_INVL_ALL;
     88                        cpu->arch.dcache_messages[0].color = 0; /* ignored */
     89                        cpu->arch.dcache_messages[0].frame = 0; /* ignored */
     90                } else {
     91                        index_t idx = cpu->arch.dcache_message_count++;
     92                        cpu->arch.dcache_messages[idx].type = type;
     93                        cpu->arch.dcache_messages[idx].color = color;
     94                        cpu->arch.dcache_messages[idx].frame = frame;
     95                }
     96                spinlock_unlock(&cpu->lock);
     97        }
     98
     99        ipi_broadcast(IPI_DCACHE_SHOOTDOWN);   
     100
     101busy_wait:
     102        for (i = 0; i < config.cpu_count; i++)
     103                if (cpus[i].arch.dcache_active)
     104                        goto busy_wait;
     105}
     106
     107/** Finish the D-cache shootdown sequence. */
     108void dcache_shootdown_finalize(void)
     109{
     110        spinlock_unlock(&dcachelock);
     111        CPU->arch.dcache_active = 1;
     112}
     113
     114/** Process the D-cache shootdown IPI. */
     115void dcache_shootdown_ipi_recv(void)
     116{
     117        int i;
     118
     119        ASSERT(CPU);
     120
     121        CPU->arch.dcache_active = 0;
     122        spinlock_lock(&dcachelock);
     123        spinlock_unlock(&dcachelock);
     124       
     125        spinlock_lock(&CPU->lock);
     126        ASSERT(CPU->arch.dcache_message_count < DCACHE_MSG_QUEUE_LEN);
     127        for (i = 0; i < CPU->arch.dcache_message_count; i++) {
     128                switch (CPU->arch.dcache_messages[i].type) {
     129                case DCACHE_INVL_ALL:
     130                        dcache_flush();
     131                        goto flushed;
     132                        break;
     133                case DCACHE_INVL_COLOR:
     134                        dcache_flush_color(CPU->arch.dcache_messages[i].color);
     135                        break;
     136                case DCACHE_INVL_FRAME:
     137                        dcache_flush_frame(CPU->arch.dcache_messages[i].color,
     138                            CPU->arch.dcache_messages[i].frame);
     139                        break;
     140                default:
     141                        panic("unknown type (%d)\n",
     142                            CPU->arch.dcache_messages[i].type);
     143                }
     144        }
     145flushed:
     146        CPU->arch.dcache_message_count = 0;
     147        spinlock_unlock(&CPU->lock);
     148
     149        CPU->arch.dcache_active = 1;
     150}
     151
     152#endif /* CONFIG_VIRT_IDX_DCACHE */
     153#endif /* CONFIG_SMP */
     154
    38155/** @}
    39156 */
  • kernel/arch/sparc64/src/mm/tlb.c

    r4638401 r454f1da  
    483483       
    484484        for (i = 0; i < cnt; i++) {
    485                 itlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_PRIMARY, page + i *
    486                         PAGE_SIZE);
    487                 dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_PRIMARY, page + i *
    488                         PAGE_SIZE);
     485                itlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_PRIMARY,
     486                    page + i * PAGE_SIZE);
     487                dtlb_demap(TLB_DEMAP_PAGE, TLB_DEMAP_PRIMARY,
     488                    page + i * PAGE_SIZE);
    489489        }
    490490       
  • kernel/arch/sparc64/src/smp/ipi.c

    r4638401 r454f1da  
    4040#include <config.h>
    4141#include <mm/tlb.h>
     42#include <arch/mm/cache.h>
    4243#include <arch/interrupt.h>
    4344#include <arch/trap/interrupt.h>
     
    7980                asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_1, 0);
    8081                asi_u64_write(ASI_UDB_INTR_W, ASI_UDB_INTR_W_DATA_2, 0);
    81                 asi_u64_write(ASI_UDB_INTR_W, (mid <<
    82                         INTR_VEC_DISPATCH_MID_SHIFT) | ASI_UDB_INTR_W_DISPATCH,
    83                         0);
     82                asi_u64_write(ASI_UDB_INTR_W,
     83                    (mid << INTR_VEC_DISPATCH_MID_SHIFT) |
     84                    ASI_UDB_INTR_W_DISPATCH, 0);
    8485       
    8586                membar();
     
    125126                func = tlb_shootdown_ipi_recv;
    126127                break;
     128#if (defined(CONFIG_SMP) && (defined(CONFIG_VIRT_IDX_DCACHE)))
     129        case IPI_DCACHE_SHOOTDOWN:
     130                func = dcache_shootdown_ipi_recv;
     131                break;
     132#endif
    127133        default:
    128134                panic("Unknown IPI (%d).\n", ipi);
  • kernel/arch/sparc64/src/trap/interrupt.c

    r4638401 r454f1da  
    4545#include <arch.h>
    4646#include <mm/tlb.h>
     47#include <arch/mm/cache.h>
    4748#include <config.h>
    4849#include <synch/spinlock.h>
     
    8485                /*
    8586                 * This is a cross-call.
    86                  * data0 contains address of kernel function.
     87                 * data0 contains address of the kernel function.
    8788                 * We call the function only after we verify
    88                  * it is on of the supported ones.
     89                 * it is one of the supported ones.
    8990                 */
    9091#ifdef CONFIG_SMP
    9192                if (data0 == (uintptr_t) tlb_shootdown_ipi_recv) {
    9293                        tlb_shootdown_ipi_recv();
     94#ifdef CONFIG_VIRT_IDX_DCACHE
     95                } else if (data0 == (uintptr_t) dcache_shootdown_ipi_recv) {
     96                        dcache_shootdown_ipi_recv();
     97#endif
    9398                }
    9499#endif
  • kernel/generic/src/mm/backend_anon.c

    r4638401 r454f1da  
    7979{
    8080        uintptr_t frame;
     81        bool dirty = false;
    8182
    8283        if (!as_area_check_access(area, access))
     
    9596                mutex_lock(&area->sh_info->lock);
    9697                frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
    97                         ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
     98                    ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
    9899                if (!frame) {
    99100                        bool allocate = true;
     
    114115                                frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
    115116                                memsetb(PA2KA(frame), FRAME_SIZE, 0);
     117                                dirty = true;
    116118                               
    117119                                /*
     
    144146                frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);
    145147                memsetb(PA2KA(frame), FRAME_SIZE, 0);
     148                dirty = true;
    146149        }
    147150       
     
    155158                panic("Could not insert used space.\n");
    156159               
     160#ifdef CONFIG_VIRT_IDX_DCACHE
     161        if (dirty && PAGE_COLOR(PA2KA(frame)) != PAGE_COLOR(addr)) {
     162                /*
     163                 * By writing to the frame using kernel virtual address,
     164                 * we have created an illegal virtual alias. We now have to
     165                 * invalidate cachelines belonging to addr on all processors
     166                 * so that they will be reloaded with the new content on next
     167                 * read.
     168                 */
     169                dcache_flush_frame(addr, frame);
     170                dcache_shootdown_start(DCACHE_INVL_FRAME, PAGE_COLOR(addr), frame);
     171                dcache_shootdown_finalize();
     172        }
     173#endif
     174
    157175        return AS_PF_OK;
    158176}
     
    169187{
    170188        frame_free(frame);
    171 #ifdef CONFIG_VIRT_IDX_DCACHE
    172         dcache_flush_frame(page, frame);
    173 #endif
    174189}
    175190
     
    218233                                frame_reference_add(pfn);
    219234                        }
    220                                
     235
    221236                }
    222237        }
  • kernel/generic/src/mm/backend_elf.c

    r4638401 r454f1da  
    8282        uintptr_t base, frame;
    8383        index_t i;
     84        bool dirty = false;
    8485
    8586        if (!as_area_check_access(area, access))
     
    148149                        memcpy((void *) PA2KA(frame),
    149150                            (void *) (base + i * FRAME_SIZE), FRAME_SIZE);
    150                        
     151                        dirty = true;
     152
    151153                        if (area->sh_info) {
    152154                                frame_reference_add(ADDR2PFN(frame));
     
    169171                frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
    170172                memsetb(PA2KA(frame), FRAME_SIZE, 0);
     173                dirty = true;
    171174
    172175                if (area->sh_info) {
     
    189192                memcpy((void *) PA2KA(frame), (void *) (base + i * FRAME_SIZE),
    190193                    size);
     194                dirty = true;
    191195
    192196                if (area->sh_info) {
     
    205209        if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
    206210                panic("Could not insert used space.\n");
     211
     212#ifdef CONFIG_VIRT_IDX_DCACHE
     213        if (dirty && PAGE_COLOR(PA2KA(frame)) != PAGE_COLOR(addr)) {
     214                /*
     215                 * By writing to the frame using kernel virtual address,
     216                 * we have created an illegal virtual alias. We now have to
     217                 * invalidate cachelines belonging to addr on all processors
     218                 * so that they will be reloaded with the new content on next
     219                 * read.
     220                 */
     221                dcache_flush_frame(addr, frame);
     222                dcache_shootdown_start(DCACHE_INVL_FRAME, PAGE_COLOR(addr), frame);
     223                dcache_shootdown_finalize();
     224        }
     225#endif
    207226
    208227        return AS_PF_OK;
     
    239258                         */
    240259                        frame_free(frame);
    241 #ifdef CONFIG_VIRT_IDX_DCACHE
    242                         dcache_flush_frame(page, frame);
    243 #endif
    244260                }
    245261        } else {
     
    248264                 * lower part is backed by the ELF image and the upper is
    249265                 * anonymous). In any case, a frame needs to be freed.
    250                  */
    251                 frame_free(frame);
    252 #ifdef CONFIG_VIRT_IDX_DCACHE
    253                 dcache_flush_frame(page, frame);
    254 #endif
     266                 */
     267                frame_free(frame);
    255268        }
    256269}
Note: See TracChangeset for help on using the changeset viewer.