MIPS概述

【MIPS CPU 体系结构概述2】连载14:

下面是笔者在为godson CPU的页面可执行保护功能增加内核支持时分析linux-mips mmu实现的一些笔记。也许第5节对整个工作过程的分析会有些用,其它语焉不详的 东西多数只是对笔者本人有点用.
首先的,关键的,要明白MIPS CPU的tlb是软件管理的,cache也不是透明的,具体的 参见它们的用户手册.
(for sgi-cvs kernel 2.4.17)

1. mmu context
cpu用8位asid来区分tlb表项所属的进程,但是进程超过256个怎么办?
linux实现的思想是软件扩展,每256个一组,TLB任何时候只存放同一组的asid 因此不会冲突. 从一组的某个进程切换到另一组时,把tlb刷新
ASID switch
include/asm/mmu_context.h:
asid_cache:
8bit physical asid + software extension, the software extension bits are used as a version; this records the newest asid allocated,while process->mm->context records its own version.

【MIPS CPU 体系结构概述2】连载13:

异常返回时,把控制转移到用户代码和把模式从内核态改为用户态要同时完成 如果前者先完成,用户态指令有机会以内核态运行导致安全漏洞;
反之则会由于用户态下不能修改状态而导致异常
r3000以前使用rfe(restore from exception)指令,这个指令把status寄存器
状态位修改回异常发生前的状态(利用硬件的一个小堆栈),但不做跳转.我们使用一个 技巧来完成要求:在一个跳转指令的delay slot中放rte.因为delay slot的指令
是一定会做的,跳转完成时,status也恢复了.
MIPS III(r4000)以上的指令集则增加了eret指令来完成整个工作: 它清除 status寄存器的EXL位并跳转到epc指定的位置.
*/

.set pop

#else

#define RESTORE_SOME \
.set push; \
.set reorder; \
mfc0 t0, CP0_STATUS; \
.set pop; \
ori t0, 0x1f; \
xori t0, 0x1f; \
mtc0 t0, CP0_STATUS; \
li v1, 0xff00; \
and t0, v1; \

【MIPS CPU 体系结构概述2】连载12:

/*判断当前运行态,设置栈顶sp
保存寄存器--参数a0-a3:4-7,返回值v0-v1:2-3,25,28,31以及一些控制寄存器,
*/

#define SAVE_SOME \
.set push; \
.set reorder; \
mfc0 k0, CP0_STATUS; \
sll k0, 3; /* extract cu0 bit */ \
.set noreorder; \
bltz k0, 8f; \
move k1, sp; \
.set reorder; \
/* Called from user mode, new stack. */ \
GET_SAVED_SP \

【MIPS CPU 体系结构概述2】连载11:

好了,说了一通系统调用,无非是想让大家明白内核中寄存器的保存恢复过程,以及 为了少做些无用功所做的努力.下面看为什么要save_static_function:为了避免 s0寄存器的破坏.

如果我们使用

sys_rt_sigsuspend()
{
save_static;

}

会有什么问题呢,请看,

Nasty degree - 3 days of tracking.

The symptom was pthread cannot be created. In the end the caller will get a BUS error.

【MIPS CPU 体系结构概述2】连载10:

/*以下这一段涉及比较微妙的问题,没有兴趣可以跳过*/

/* save_static_function宏是一个令人迷惑的东西,它定义了一个汇编函数,保存s0-s8 可是这个函数没有返回!实际上,它只是一个函数的一部分:

在arch/mips/kernel/signal.c中有:
save_static_function(sys_rt_sigsuspend);
static_unused int
_sys_rt_sigsuspend(struct pt_regs regs)
{
sigset_t *unewset, saveset, newset;
size_t sigsetsize;

这里用save_static_function定义了sys_rt_sigsuspend,而实际上如果
你调用sys_rt_sigsuspend的话,它保存完s0-s8后,接着就调用_sys_rt_sigsuspend! 看它链接后的反汇编片段:

80108cc8 :

80108cc8: afb00058 sw
80108ccc: afb1005c sw
80108cd0: afb20060 sw
80108cd4: afb30064 sw

【MIPS CPU 体系结构概述2】连载10:

2.cause寄存器

31 30 29 28 27 16 15 8 7 6 2 1 0

|BD|0 | CE | 0 | IP7 - IP0 |0|Exc code | 0 |

异常发生时cause被自动设置
其中:
BD指示最近发生的异常指令是否在delay slot中
CE发生coprocessor unusable异常时的coprocessor编号(mips有4个cp) IP: interrupt pending, 1->pending,0->no interrupt,CPU有6个中断
引脚,加上两个软件中断(最高两个)
Exc code:异常类型,所有的外设中断为0,系统调用为8,...

3.EPC
对一般的异常,EPC包含:
. 导致异常的指令地址(virtual)
or. if 异常在delay slot指令发生,该指令前面那个跳转指令的地址 当EXL=1时,处理器不写EPC

4.和存储相关的:
context,BadVaddr,Xcontext,ECC,CacheErr,ErrorEPC
以后再说

【MIPS CPU 体系结构概述2】连载9:

到底是哪个中断呢?从主板寄存器读*/

int_status = BONITO_INTISR & BONITO_INTEN & ~(1 << (P6032INT_ISAIRQ-16))
;
/* Scan all pending interrupt bits and execute appropriate actions */ for (i=0; i<32 && int_status; i++) {
if (int_status & 1< irq = i + 16; /* 0-15 assigned to 8259int,16-48 bonito*/
/* Clear bit to optimise loop exit */
int_status &= ~(1< do_IRQ(irq,regs);

}
}

return;
}

8259控制器的代码类似,不再列出.

更高层一点的通用irq代码在arch/mips/kernel/irq.c arch/mips/kernel/i8259.c

总之,p6032上一个中断的过程是:

【MIPS CPU 体系结构概述2】连载8:

/* 中断初始化,核心的数据结构就是irq_desc[]数组
它的每个元素对应一个中断,记录该中断的控制器类型,处理函数,状态等 关于这些可以参见对x86中断的分析*/

void __init init_IRQ(void)
{
Bonito;

/*
* Mask out all interrupt by writing "1" to all bit position in * the interrupt reset reg.

*/

BONITO_INTEDGE = BONITO_ICU_SYSTEMERR | BONITO_ICU_MASTERERR | BONITO_ICU_RETRYERR | BONITO_ICU_MBOXES;
BONITO_INTPOL = (1 << (P6032INT_UART1-16)) | (1 << (P6032INT_ISANMI-16))
| (1 << (P6032INT_ISAIRQ-16))
| (1 << (P6032INT_UART0-16));

BONITO_INTSTEER = 0;
BONITO_INTENCLR = ~0;
/* init all controllers */

【MIPS CPU 体系结构概述2】连载6:

irq.c部分代码如下:

p6032中断共有四类:

begin{enumerate}
item timer中断,单独处理
item debug中断,单独处理
item 8259中断,由8259控制器代码处理
item bonito中断由bonito控制器代码处理 end{enumerate}

/* now mips kernel is using the same abstraction as x86 kernel,
that is, all irq in the system are described in an struct
array: irq_desc[]. Each item of a specific item records
all the information about this irq,including status,action,
and the controller that handle it etc. Below is the controller
structure for bonito irqs,we can easily guess its functionality
from its names.*/

【MIPS CPU 体系结构概述2】连载5:

下面列出这两个文件以便解说:

p6032IRQ.s
algor p6032(笔者用的开发板)中断安排如下: MIPS IRQ Source
*
* 0 Software (ignored)
* 1 Software (ignored)
* 2 bonito interrupt (hw0)
* 3 i8259A interrupt (hw1)
* 4 Hardware (ignored)
* 5 Debug Switch
* 6 Hardware (ignored)
* 7 R4k timer (what we use)

.text
.set noreorder
.set noat
.align 5
NESTED(p6032IRQ, PT_SIZE, sp)

SAVE_ALL /* 保存现场,切换堆栈(if usermode -> kernel mode)*/

CLI /* 关中断,mips有多种方法禁止响应中断,CLI用清status相应位 的方法,如下: Move to kernel mode and disable interrupts. Set cp0 enable bit as sign

同步内容
--电子创新网--
粤ICP备12070055号