0

首先,感谢无艺术噪音的好建议。
我选择与 usr task (vaddr : 0 - 4G) 共享 3G - 4G-1 内核空间地址来切换任务。
我认为任务切换是这样的:

  1. 当 usr 任务在其自己的地址空间中运行时,会出现时钟中断

  2. 跳转到 usr 地址空间的 3G(也是内核 3G 空间)。

  3. 上下文保存

  4. schedule ()
    {
    ....
    switch_ttb_base (ttb_base);
    // 我认为是关键,(taskA --> TaskB)
    // 当ttb_base 切换时,地址空间发生变化,
    // 看起来TaskB 被中断&& 到达这里。
    // 所以,上下文恢复后,它会返回到TaskB
    // 看起来TaskB 刚刚被中断了!
    ....
    }

  5. 上下文恢复

  6. 分支到新的 usr 任务

因此,要共享内核 3G 地址,我应该将 page_tbls 从内核 3G 地址复制到 usr page_tbls。
这是我的代码,(ARM920T,S3C2440)

#define INIT_L1_BASE        (0x30100000)            /* 16K */
#define INIT_L2_BASE        (0x30104000)            /* 64k */

#define KERNEL_IMG_SIZE     (0x20000)           /* 128 K */  
#define KERNEL_CODE_START   (0xC0000000)        /* 3G start */

#define TTB_BASE            (0x30000000)          
#define PAGE_DIR            (TTB_BASE)          
#define TTB_FULL_SIZE       (0x4000)            /* 16K */   
#define PAGE_TABLE          (TTB_BASE+TTB_FULL_SIZE)                 

#define PAGE_DIR_SIZE       (0x4000)            /* 16k */
#define PAGE_TBL_SIZE       (0x10000)           /* 64K */

void copy_kernel_page_tbls (unsigned dest_ttb,unsigned vaddr,unsigned size)
{
    if ((size & 0xFFFFF) || (vaddr & 0xFFFFF))                            /* 1M alignment */
        panic ( "trying to copy page tables with non-1M alignment !\n" );
    volatile unsigned *_from_page_dir,*_to_page_dir;

    _from_page_dir = (volatile unsigned *)(TTB_BASE);
    _to_page_dir = (volatile unsigned *)dest_ttb;

    unsigned l1_idx;
    unsigned i = 0,j = 0,k = 0,page;
    volatile unsigned *_to_page_tbl,*_from_page_tbl;

    for (k = 0 ,size >>= 20 ; k < size ; k ++,vaddr += 0x100000 ) 
    {
        l1_idx = vaddr>>20;
        if ( !(_from_page_dir[l1_idx] & ~0x3FF)) 
            continue;
        if ( !(_to_page_dir[l1_idx] & ~0x3FF) ) {                       /* if dest page dir unit is empty */
            i = l1_idx & ~3;
            if ((_to_page_dir[i+0] & ~0x3FF) || (_to_page_dir[i+1] & ~0x3FF)
            ||  (_to_page_dir[i+2] & ~0x3FF) || (_to_page_dir[i+3] & ~0x3FF) )
            {
                panic ( "page dir corrupts with l1_idx %d !\n",l1_idx );
            }
            if (!(page = find_free_page ())) 
                panic ( "no more free page !\n" );                      /* alloc a page page dir*/
            wordset ((void*)page,AP_FAULT_ALL|CB|TTB1_SPG,0x1000);      /* set all be fault  */

            _to_page_dir[i+0] = (page + 0x000)|DOMAIN_SYS|TTB0_COARSE;  /* small page 1st 1KB */
            _to_page_dir[i+1] = (page + 0x400)|DOMAIN_SYS|TTB0_COARSE;  /* small page 2nd 1KB */
            _to_page_dir[i+2] = (page + 0x800)|DOMAIN_SYS|TTB0_COARSE;  /* small page 3rd 1KB */
            _to_page_dir[i+3] = (page + 0xC00)|DOMAIN_SYS|TTB0_COARSE;  /* small page 4th 1KB */
        }
        _from_page_tbl = (volatile unsigned*)(_from_page_dir[l1_idx] & ~(0x3FF));
        _to_page_tbl = (volatile unsigned*)(_to_page_dir[l1_idx] & ~(0x3FF));

        /* continue copying .... */
        for (j = 0 ; j < 256 ; j++ ) {                                  /* 256 * 4K */
            if (_from_page_tbl[j] & ~0xFFF) 
                _to_page_tbl[j] = _from_page_tbl[j];            /* FIXME : change attribute */
        }
    }
}

我这样称呼它

copy_kernel_page_tbls (INIT_L1_BASE,KERNEL_CODE_START,1<<30);   /* 1G size */

时钟处理程序是

extern unsigned long __ticks;

    #define __DEBUG__

    static   
    void schedlue ( void )
    {
        // ..............

        sync_dcaches ();
        invalidate_icaches ();
        invalidate_dcaches ();

        invalidate_tlbs();                                  
        set_ttb_base(current_p->ttb_base);                         
    }

    void __do_timer0 (void)
    {
            static unsigned i = 0;
            ++ i;
        current_p = task_st[i & 1];         /* just 2 tasks */
        __ticks ++;

        .....
        .....
        schedule ();
    }

ARM只是停止。我不知道为什么?任何帮助表示赞赏!

4

1 回答 1

0

我做了一个 mmu 测试来测试 mmu 缓存操作

我用以下方式切换 ttb 基地:

void change_ttb_base (unsigned ttb)
{
    sync_dcaches ();
    invalidate_icache ();
    invalidate_dcaches ();
    set_ttb_base (ttb);
    invalidate_tlbs ();
}

在我的s3c2440板上,0x30000000 - 0x34000000是sdram地址,我在sdram地址空间做测试,ttb_base切换成功!

但是当代码运行在高3G地址,调用change_ttb_base()后,ARM就停止了所以ARM核心不知道下一步是什么,所以就停下来......

那正确吗 ???

于 2013-05-12T07:49:05.247 回答