#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/page.h>
#include <asm/io.h>
#define phy 0xFFE00320
int init_module()
{
unsigned long *vir1;
unsigned long vir3;
unsigned long *vir2;
unsigned long *vir4;
vir2 = (unsigned long) phys_to_virt(0xFFE00320);
printk("address 3 %pn", vir2);
printk(" ddd %lx n", *vir2); // 이부분에서 걸리네요 ㅜㅠ
vir1 = (unsigned long *)ioremap(phy,0x40);
printk(" address1 0x%p n",vir1);
printk(" address 2 0x%p n", &vir1);
printk(" value = %lx n", *vir1); 값이 ffffffff
iounmap(vir1);
return 0;
}
void cleanup_module(){
printk("outn");
}
이것은 제가 작성한 모듈 코드입니다
물리적 주소를 이용하여 가상 주소로 변환 뒤 가상주소를 이용하여
물리적주소의 값을 읽고 싶은데 insmod 시 세그먼트 폴트가 일어 납니다 ㅠ
고수님들의 많은 조언 부탁드리겠습니다.
댓글 13
-
박한범
2010.12.24 13:48
-
송창인
2010.12.24 15:37
관심을 가져주셔서 감사합니다.
물리적 주소가 잘못되어서 수정 했습니다.
하지만 제가 접근하려는 타이머 레지스터인데 값은 써지는 것 같은데 확인을 할 방법을 잘모르겠습니다 ㅠ
혹시 방법을 아시면 알려주실수 있나요?
-
김남형
2010.12.27 01:52
highmem 영역에 존재하는 페이지는 커널 페이지 테이블에 매핑되어 있지 않기 때문에 그냥 읽으면 페이지 폴트가 발생합니다.
(phys_to_virt()는 단순한 오프셋 연산 만을 하는 것으로 NORMAL zone 이하의 페이지에서만 정상 동작합니다.
또한 write protection이나 interrupt disable 등과는 관련이 없어 보입니다.. ;;)
따라서 장치에 할당된 물리 주소 영역은 반드시 ioremap 계열의 함수를 통해 매핑한 뒤 읽어야 하는데
장치의 특성에 따라 다르겠지만 매핑 시에 CPU caching을 disable해 두어야 장치의 변경 사항을 올바로 인식할 수 있는
경우도 있습니다. 이런 경우라면 ioremap_nocache()도 한 번 시도해 보시기 바랍니다.
추천:1 댓글
-
송창인
2010.12.27 15:13
소중한 댓글 감사합니다
김남형님 말씀대로 ioremap_nocache()안의 내용을 읽어 들일수 있었습니다 .
정말 많은 도움이 되었습니다 ㅠ
그리고 죄송하지만 그렇게 읽어온 타이머 레지스터의 값이 바뀔수 있는건지가 궁금합니다.
인텔 계열의 IA32에서는 초기값이 0001 0000h 로 알고 있는데 값이 자꾸 바뀌네요 ;;;
그리고 앞에서도 말씀드렸지만 다시 한번 감사드립니다.
-
박한범
2010.12.27 17:23
오잉?
타이머의 세팅값은 자동으로 변경될 수 없습니다.
아마 변화하는 값이 보이신다면 그 값은 세팅된 값이 아니라 PIT내부의 카운터 값일 겁니다.
PIT가 내부 카운터를 감소시켜 0이 될 때 IRQ로 인터럽트 신호를 전송한다는 점은 알고 계실 겁니다. ㅎㅎ;
-
송창인
2010.12.28 12:59
우선 감사드립니다.
ioremap() 을 쓸때 읽어오는 값 설정 즉 페이지 단위로 읽어와야 하는데 그 값이 설정이 잘못 되있엇나 봅니다 ㅠ
고정적인 값을 읽어 오기는하는데 문제는 그 값이 미약하지만 제가 알고 있는 값과 달라서;;;;;(ef 만 찍어서;;)
타이머 세팅 값을 읽어와야하는데 그 값을 읽을 수 잇는 방법이 없을까요?
그리고 한가지 더 궁금한게 있는데 ioremap api를 이용하여 얻어온 주소가 실질적으로 (제가 위에 코딩한거에서 보시면)
0xFEE00320 을 가지고 가상메모리에 매핑을 해주고 그 얻어온 가상메모리를 다시 virt_to_phys()를 이용하여 물리적메모리를
를 찍어보게 되면 0xFEE00320 가 아닌 다른 주소를 찍는걸 확인했습니다. 왜 0xFEE00320가 아닌지 궁금합니다
-
송창인
2011.01.03 15:10
ㅎㅎ 읽어 보앗습니다 분명 타이머 레지스테에 인터럽트 벡터 넘버가 들어가는거 까지는 알았는데
하위 8비트를 제외하고 나머지 부분들 주기비트 (원샷모드인지 주기 모드인지) mask 비트 등에 대한 정보가 필요해서
이렇게 질문을 올렸는데 많은 분들께서 관심을 가져주시고 많이 도와 주셨습니다
생각한것대로 쉽지 않네요 ㅎ 감사합니다
-
박한범
2011.01.03 13:29
음 모호하게 설명드린거 같아서 일단 죄송합니다.
제 설명은 인텔 매뉴얼을 보셨다고 하셨으니까... 그 부분에 보면 괄호치고 APIC 타이머섹션을 참조하라고 나오거든요. 그 부분을 보셨을 걸로 생각했었어요. 모르겠으시면 메뉴얼에 APIC Timer 섹션을 참고하세요. 10.5.4 입니다.
-
송창인
2011.01.02 14:15
박한범 님 감사 드립니다 덕분에 많은 것을 되뇌어 볼 수 었습니다.
사실 작년에 공부한것이라 이것 저것 어수선하고 헷갈려 했던것이 많았습니다.
얻어온값은 말씀 하신대로 IVT 에 해당하는 값이 맞습니다
레지스터의 마지막 8비트는 인터럽트 벡터 테이블의 값을 가지고 잇는데
타이머 레지스터의 값을 찍으면 인터럽트 벡터 값을 포함하여 다른 셋팅 값을 찍어야하는데
KLDP 의 어떤 분 께서 벡터를 제외한 나머지 셋팅 값이 0으로 셋팅 되어 있다는 정보를 주셔서 조금한 마음에
결정을 지은거 같습니다 .ㅋ
그리고 제가 부족한건지 박한범님께서 말씀하신 "옆에 보면 APIC 타이머를 참조하라고 되어 있죠?"
이부분을 이해를 하지못했습니다 . 죄송하지만 설명을 부탁 드려도 될까요?
-
박한범
2011.01.01 22:38
ㅎㅎㅎ. 긴장하실 필요 없으세요. 전 그냥 추측을 해봤을 뿐이지 틀렸다 이런게 아닙니다.
저도 궁금하기도 하고 토론을 하다보면 좋은 지식을 얻을 수 있다는 걸 여기서 경험해서요 ^^ ( 사실 가르침을 받았습니다. )
말씀하신 부분 저도 봤습니다.
하지만 그 전에 0xef 라는 벡터값을 보셨다고 하셨으니, 이 주소가 어딘지 모르겠지만 잘 못 되었다는 생각은 하고 계실 겁니다.
그 생각이 맞는것 같습니다.
LVT TIMER Register 의 설명과 함께 추론해 봤을때, 이 곳의 값은 IVT = 인터럽트 벡터 테이블에 해당하는 값이지 타이머를 Mapped 한 주소는 아닌 것 같아요. 옆에 보면 APIC 타이머를 참조하라고 되어 있죠?
아마 이 곳에 있는 주소가 실제 타이머가 아닐까 싶네요.
건승하세요 ^^
-
송창인
2011.01.01 19:12
인텔계열에서는 타이머 레지스터의 주소가 0xFEE00320 으로 나타나 있었습니다.
intel 32 architectures software developer's manual을 참고 했습니다.
그리고 리눅스에서 arch/x86/include/asm/apicdef.h 파일에서 보았지만
베이스 어드레스 0xFEE00000을 가지고 320번째를 보면 타이머 레지스터에 대한 구조체가 나와있었습니다.
혹시 제가 잘못 알고 잇는건가요 ;;;;;
그럼 안돼는데;;;;
-
박한범
2011.01.01 18:07
1. 타이머 세팅값.
0xFEE00320 라는 주소를 어디서 얻으셨는지 궁금하군요.
LOCAL APIC 가 0xFEE0_0000H 부터 시작하니까, 말씀하신 내용을 토대로 미뤄보면, 0xFEE00320 에 들어있는 APIC 테이블의 값을 얻어오시는것 같습니다. 여기서는 인터럽트 벡터 값을 얻는게 맞을 겁니다. 여기서 제가 의아한 것은, 타이머 인터럽트는( 정확히는 PIT의 경우) IRQ 0입니다. 제 생각에는 0xFEE00320 에는 타이머 인터럽트 벡터 값이 들어있지 않을 것 같습니다.
그래서 왜 0xFEE00320 이란 값을 적으셨나 생각해봤습니다. 0x20은 4바이트 크기를 가지는 벡터테이블로 봤을때, 8번째 값이고 IRQ8 은 RTC 관련 인터럽트 벡터입니다. 혹시 착각하신게 아닐까요? ;;;
2. 주소 값
솔직히 이 부분은 뭘 물어보신건지 모르겠습니다.
-
송창인
2010.12.29 14:21
ef가 찍히는 이유를 보니 타이머레지스터의 벡터 값이엿습니다;;;;;
몇일동안 많은 것을 배웠습니다
감사합니다 ㅎ
.
크로스컴파일러를 컴파일 하는 동안 잠깐 한 마디 적어봅니다^^
os가 세그먼테이션할때 분명 주소는 0x00000000~0xFFFFFFFF 까지 맵핑합니다. 그래서 4기가 대역이 되죠. 하지만 특정 주소에 접근하려고 하면 세그먼트 폴트가 납니다. 왜 그럴까요?
그건 세그먼테이션으로 가르키는 영역과 os가 맵핑하는 메모리 대역과는 관련이 없기 때문입니다.
쉽게 말해서 세그먼테이션으로 4기가 대역을 커버한다고 해도, 커널에서는 일정 대역에 대해서는 페이지를 존재하지 않음으로 설정합니다. 이는 마치 가상메모리가 이론상으로는 4기가의 메모리를 커버하지만 윈도os에서 보이는 메모리는 3.xx기가로 보이는 이유가 됩니다.
결론적으로 이 주소 대역을 참조하려고 하면 존재하지 않는 페이지이므로 page fault가 나고, 아마 보시려는 메모리 대역이 memory mapped i/o 대역이므로, 커널에서 이 주소대를 사용하지 않기로 한 것 같습니다.
글을 다 적었는데도 컴파일이 안끝나네요 ^^;;