[Ntdebugging]실력이 시험되는 장, 하드웨어 조사하기
"이 문서는 https://blogs.msdn.com/ntdebugging blog 의 번역이며 원래의 자료가 통보 없이 변경될 수 있습니다. 이 자료는 법률적 보증이 없으며 의견을 주시기 위해 원래의 blog 를 방문하실 수 있습니다. (https://blogs.msdn.com/ntdebugging/archive/2007/06/22/where-the-rubber-meets-the-road-or-in-this-case-the-hardware-meets-the-probe.aspx )
실력이 시험되는 장, 하드웨어 조사하기
안녕하세요 Bob 입니다.Microsoft critical problem resolution 팀에서 근무하는 Escalation engineer 입니다. 독자 중 한 분이 저희가 얼마나 자주 하드웨어 문제를 다루는지 문의해 주셨는데 최근 아주 흥미로운 문제를 처리 하였는데 이 내용을 공유해 드리고자 합니다. 이 문제는 아주 흥미로운데 일부 멀티 프로세서에서 발생하고 드라이버를 개발한 사람에게는 문제가 되지 않는 것으로 보입니다.
무엇이 문제일까요?
시스템의 시간이 업데이트 되지 않는다는 것 이외에는 모든 것이 정상 입니다. RTC 가 정지된 것 입니다. RTC가 어떻게 동작하는지 확인해 보았고 마더보드의 RTC에 오실로스코프로 연결하여 특정 값을 디버거로 써서 RTC를 끌 수 있는지도 확인해 보았습니다. 오실로스코프를 사용하여 어떤 값을 포트에 써야 클럭을 끌 수 있는지도 검증해 보았습니다. 이를 통해 드라이버가 문제를 일으킬 수 있는 방법에 대해서 완벽히 이해할 수 있었습니다. 클럭은 매 10ms 마다 발생하며 매우 빠른 오실로스코프가 필요하지는 않습니다.
특별한 키보드 드라이버 작성
문제가 발생한 상태에서 덤프를 수집하기 위해 키보드 드라이버 수정하여 Bugcheck E2가 발생하지 않고 Int 3이 호출되도록 수정하였습니다. RTC는 퀀텀을 소모하지 않는 Idle 쓰레드에서는 동작하지 않고 일반적인 덤프에서는 원하는 결과를 얻을 수 없습니다. 하지만 시스템은 ISR 에 응답 합니다.
발견한 것.
모든 RTC 인터럽트가 멈추었다. – 클럭이 동작하지 않는다. RTC가 사용되지 않게 되었는지 모든 방면에서 확인해 보았습니다.
I/O APIC의 ICR을 확인해 보았습니다. 이것은 인터럽트 컨피그레이션 레지스터로 APIC의 모든 인터럽트 핀에 있는 레지스터 입니다. 이 레지스터들은 APIC에 어떤 벡터 값이 프로세서로 전달되었는지 알려주고 프로세서가 인터럽트 서비스를 실행할 수 있게 해 줍니다. 또한 레벨에 대한 설정 정보를 가지고 있으며 트리거 되었는지 마스크 되었는지 알려 줍니다. 마스크 비트는 설정되어 있지 않았습니다..
아래는 사용 규칙 입니다.
0: kd> ed ffd01000
ffd01000 00000034 20 <- 핀 8번에 해당하는 20번 레지스터 선택.
0: kd> ed ffd01010
ffd01010 000008d1 <- 내용 <- 벡터 D1 비트 16, 인터럽트 마스크는 설정하지 않았습니다.
I/O 포트 70번과 71번의 RTC 상태 레지지스터를 확인 합니다. 70번 포트는 어드레스 포트이고 71번 포트는 데이터 포트 입니다. 이 정보는 BIOS 관련 책에서 확인할 수 있습니다.
0: kd> ob 70 b <- ‘B’ 는 컨트롤 레지스터 입니다.
0: kd> ib 71
00000071: 42 <- 42는 RTC 사용을 의미 합니다. 6번째 비트가 활성화 입니다.
무엇일까요?
RTC는 특정 간격으로 인터럽트를 발생시킬 것이고 인터럽트가 서비스 될 때 상태 레지스터가 읽힐 것 입니다.
덤프에서 다른 드라이버들을 디스어셈블하여 특정 드라이버가 포트 70과 71에 대한 연산을 통하여 클럭을 읽는 것을 확인 하였습니다. 낮은 어드레스가 포트 70으로 설정되어 읽을 때의 시간을 산출하고 있었습니다. 이것이 드라이버가 문제를 일으킨 동작 입니다.
시간을 읽는 작업은 간단한 것으로 다른 곳에 영향을 미치지 않을 것이라고 생각 할 수 있습니다. 하지만 멀티 프로세서 시스템에서는 포트에 대한 접근은 직렬화 됩니다.
하나의 클럭, 주소, 데이터에 대해서 두 개의 프로세스로 인해서 두 개의 접근이 발생하여 결과에 오류가 발생하였습니다.
아래는 접근에 대한 시간 흐름도 입니다.
프로세서 0 : OS RTC 핸들러 프로세서 1 : XYZ 드라이버
T1 상태 레지트러를 선택하도록 레지스터 설정
T2 시간을 읽도록 레지스터 선택
T3 클럭을 재 시작 하기 위해 상태 레지스터 읽기
T3 에서 OS RTC 핸들러는 잘못된 레지스터를 읽어 클럭이 시작되지 않습니다.
결론
이 문제는 직렬화를 잘 이야기 해 줄 수 있는 좋은 예제라고 생각 됩니다. 그리고 멀티 프로세서 환경을 잘 보여주는 것이라고 생각 됩니다. 항상 다른 프로세서에서 무엇을 하는지 생각해 보는 것이 좋다고 생각 됩니다.
아래 정보를 통해 보다 많은 BIOS에 대한 정보를 얻을 수 있습니다.
https://www.geocities.com/SiliconValley/Campus/1671/docs/rtc.htm