2010年02月09日 情報科学類 オペレーティングシステム II 筑波大学 システム情報工学研究科 コンピュータサイエンス専攻, 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/literacy-2009/2010-02-09
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
arch/x86/mm/fault.c: do_page_fault(struct pt_regs *regs, unsigned long error_code)do_page_fault() は、CPUアーキテクチャによって違う。 x86 の ハードウェアの割り込み 14 により呼ばれる。次の条件で生じる。
Bit 2 | Bit 1 | Bit 0 | |
---|---|---|---|
0 | カーネル | 読み込み | ページがない |
1 | ユーザ | 書き込み | 保護違反 |
arch/x86/mm/fault.c 944: do_page_fault(struct pt_regs *regs, unsigned long error_code) 945: { 946: struct vm_area_struct *vma; 947: struct task_struct *tsk; 948: unsigned long address; 949: struct mm_struct *mm; 950: int write; 951: int fault; 952: 953: tsk = current; 954: mm = tsk->mm; ... 957: address = read_cr2(); ... 1072: vma = find_vma(mm, address); 1073: if (unlikely(!vma)) { 1074: bad_area(regs, error_code, address); 1075: return; 1076: } 1077: if (likely(vma->vm_start <= address)) 1078: goto good_area; 1079: if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) { 1080: bad_area(regs, error_code, address); 1081: return; 1082: } ... 1095: if (unlikely(expand_stack(vma, address))) { 1096: bad_area(regs, error_code, address); 1097: return; 1098: } ... 1104: good_area: 1105: write = error_code & PF_WRITE; 1106: 1107: if (unlikely(access_error(error_code, write, vma))) { 1108: bad_area_access_error(regs, error_code, address); 1109: return; 1110: } .. 1117: fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); ... 1137: }
mm/memory.c 2963: int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, 2964: unsqigned long address, unsigned int flags) 2965: { 2966: pgd_t *pgd; 2967: pud_t *pud; 2968: pmd_t *pmd; 2969: pte_t *pte; ... 2978: pgd = pgd_offset(mm, address); 2979: pud = pud_alloc(mm, pgd, address); 2980: if (!pud) 2981: return VM_FAULT_OOM; 2982: pmd = pmd_alloc(mm, pud, address); 2983: if (!pmd) 2984: return VM_FAULT_OOM; 2985: pte = pte_alloc_map(mm, pmd, address); 2986: if (!pte) 2987: return VM_FAULT_OOM; 2988: 2989: return handle_pte_fault(mm, vma, address, pte, pmd, flags); 2990: }
2907: static inline int handle_pte_fault(struct mm_struct *mm, 2908: struct vm_area_struct *vma, unsigned long address, 2909: pte_t *pte, pmd_t *pmd, unsigned int flags) 2910: { 2911: pte_t entry; 2912: spinlock_t *ptl; 2913: 2914: entry = *pte; ... 2916: if (pte_none(entry)) { 2917: if (vma->vm_ops) { 2918: if (likely(vma->vm_ops->fault)) 2919: return do_linear_fault(mm, vma, address, 2920: pte, pmd, flags, entry); 2921: } 2922: return do_anonymous_page(mm, vma, address, 2923: pte, pmd, flags); 2924: } ... 2928: return do_swap_page(mm, vma, address, 2929: pte, pmd, flags, entry); ... 2958: }
vma->vm_ops->fault
という関数があれば、
do_linear_fault() で処理する。
% date
Mon Feb 8 23:33:36 JST 2010
% hwclock --show
Mon Feb 8 23:33:40 2010 -0.748647 seconds
%
wdrivers/char/rtc.c 1299: static void rtc_get_rtc_time(struct rtc_time *rtc_tm) 1300: { 1301: unsigned long uip_watchdog = jiffies, flags; 1302: unsigned char ctrl; ... 1327: spin_lock_irqsave(&rtc_lock, flags); 1328: rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); 1329: rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); 1330: rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); 1331: rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); 1332: rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); 1333: rtc_tm->tm_year = CMOS_READ(RTC_YEAR); 1334: /* Only set from 2.6.16 onwards */ 1335: rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); ... 1340: ctrl = CMOS_READ(RTC_CONTROL); 1341: spin_unlock_irqrestore(&rtc_lock, flags); 1342: 1343: if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 1344: rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); 1345: rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); 1346: rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); 1347: rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); 1348: rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); 1349: rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); 1350: rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday); 1351: } 1361: rtc_tm->tm_year += epoch - 1900; 1362: if (rtc_tm->tm_year <= 69) 1363: rtc_tm->tm_year += 100; 1364: 1365: rtc_tm->tm_mon--; 1366: }
arch/x86/include/asm/mc146818rtc.h 94: #define CMOS_READ(addr) rtc_cmos_read(addr) 95: #define CMOS_WRITE(val, addr) rtc_cmos_write(val, addr) arch/x86/kernel/rtc.c 146: unsigned char rtc_cmos_read(unsigned char addr) 147: { 148: unsigned char val; 149: 150: lock_cmos_prefix(addr); 151: outb(addr, RTC_PORT(0)); 152: val = inb(RTC_PORT(1)); 153: lock_cmos_suffix(addr); 154: 155: return val; 156: } include/linux/mc146818rtc.h 43: #define RTC_SECONDS 0 45: #define RTC_MINUTES 2 47: #define RTC_HOURS 4 ... 52: #define RTC_DAY_OF_WEEK 6 53: #define RTC_DAY_OF_MONTH 7 54: #define RTC_MONTH 8 55: #define RTC_YEAR 9 86: #define RTC_CONTROL RTC_REG_B 92: # define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ arch/x86/include/asm/mc146818rtc.h 13: #define RTC_PORT(x) (0x70 + (x)) 14: #define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */
outb(unsigned char value, int port) ポート番号 port に 1 バイトの value を出力する unsigned char inb(int port) ポート番号 port から 1 バイトの value を入力してその値を返す
asm ( アセンブラの命令列 : 出力オペランド(省略可) : 入力オペランド(省略可) : 破壊するレジスタ(省略可) )
"制約"(Cの値)
=
があると、書き込み専用
arch/x86/include/asm/io_32.h 126: #define __BUILDIO(bwl, bw, type) \ 127: static inline void out##bwl(unsigned type value, int port) \ 128: { \ 129: out##bwl##_local(value, port); \ 130: } \ 131: \ 132: static inline unsigned type in##bwl(int port) \ 133: { \ 134: return in##bwl##_local(port); \ 135: } 136: 137: #define BUILDIO(bwl, bw, type) \ 138: static inline void out##bwl##_local(unsigned type value, int port) \ 139: { \ 140: asm volatile("out" #bwl " %" #bw "0, %w1" \ 141: : : "a"(value), "Nd"(port)); \ 142: } \ 143: \ 144: static inline unsigned type in##bwl##_local(int port) \ 145: { \ 146: unsigned type value; \ 147: asm volatile("in" #bwl " %w1, %" #bw "0" \ 148: : "=a"(value) : "Nd"(port)); \ 149: return value; \ 150: } \ 151: \ ... 192: BUILDIO(b, b, char) 193: BUILDIO(w, w, short) 194: BUILDIO(l, , int)
unsigned char hh; outb( /*(a)*/, 0x70 ); hh = inb( /*(b)*/ );