이전에 이어서
시스템콜 구현이다
하다 죽을 뻔했다
CRLF 시ㅂ
오늘 아마 이거 2개하고 끝일 거 같다
오늘 컨디션도 안좋기에 더 하기는 어려울듯?
꒰ ᐢ ◞‸◟ᐢ꒱
(외적, 내적 전부)
사나이로 태어나 글이라면 자기 이름 석자 읽고 쓸줄 알면 충분하다지만
컴퓨터는 예외다
주는 거 다 읽어야지 ㅇㅇ
static int
system_read(int fd, void *buffer, unsigned size) {
if (size == 0) return 0;
if (fd == 0) { // 키보드
for (unsigned i = 0; i < size; i++) {
uint8_t key = (uint8_t)input_getc();
copy_out((uint8_t*)buffer + i, &key, 1);
}
return (int)size;
}
if (fd == 1) return -1;
struct file *f = fd_get(fd);
if (!f) return -1;
void *read_page = palloc_get_page(PAL_ZERO);
if (read_page == NULL) return -1;
int total = 0;
lock_acquire(&filesys_lock);
while (total < (int)size) {
size_t chunk = size - total;
if (chunk > PGSIZE) chunk = PGSIZE;
off_t n = file_read(f, read_page, (off_t)chunk);
if (n <= 0) break;
copy_out((uint8_t*)buffer + total, read_page, (size_t)n);
total += (int)n;
}
lock_release(&filesys_lock);
palloc_free_page(read_page);
return total;
}
상딩히 길다
초기 fd 값이 0이면 키보드 입력을 받는 걸로 바꾸고
아닐 경우 데이터 읽어 유저 버퍼에 넣어준다
데이터 읽는 곳은 파일이나 콘솔이다
참고로 덩어리 단위로 읽어서 페이지 바뀌었을때도 고려한다
copy_out
은 중간의 매개체 역할이다
직접 데이터 참조하거나 하지 않게 말이다
유저 프로그램 메모리 데이터를 꺼내는 역할이다
콘솔/파일에서 꺼내주는게 아닌 유저 프로그램에서 꺼내줬다는 것은
넣어줄 곳은 콘솔/파일 이라는 거다
중간에 매개체로 쓸 버퍼 만드는데에 copy_in
사용한다
static long
system_write (int fd, const void *buf, unsigned size) {
if (size == 0) return 0;
if (buf == NULL) system_exit(-1);
void *kpage = palloc_get_page(0);
if (!kpage) return -1;
long total = 0;
if (fd == 1) { // STDOUT
while ((unsigned)total < size) {
size_t chunk = size - (unsigned)total;
if (chunk > PGSIZE) chunk = PGSIZE;
copy_in(kpage, (const uint8_t *)buf + total, chunk);
putbuf((const char *)kpage, chunk);
total += (long)chunk;
}
palloc_free_page(kpage);
return total;
}
if (fd == 0) { palloc_free_page(kpage); return -1; }
struct file *f = fd_get(fd);
if (!f) { palloc_free_page(kpage); return -1; }
lock_acquire(&filesys_lock);
while ((unsigned)total < size) {
size_t chunk = size - (unsigned)total;
if (chunk > PGSIZE) chunk = PGSIZE;
copy_in(kpage, (const uint8_t *)buf + total, chunk);
off_t n = file_write(f, kpage, chunk);
if (n <= 0) break;
total += (long)n;
if ((size_t)n < chunk) break;
}
lock_release(&filesys_lock);
palloc_free_page(kpage);
return total;
}
헬퍼도 쓰인다
코어타임하고 안 사실인데
테스트 케이스 개헐렁해서
그냥 이런거 안해도 통과된다고 한다
유저 주소를 커널에서 직접 믿고 쓰면 안되기에
둘을 구분하고 나눠 쓰기 위한 함수들인데…
pintos는 시부레 다 커널 스레드라 이런 거 없이 걍 써도 통과다
내 시간…
=ε/̵͇̿̿/’̿’̿ ̿ (︶︹︺)
유저 프로그램 메모리의 데이터를 바깥으로 꺼내는 용도다
반환값은 실제 사용 바이트 수, 실패시는 -1
이다
유저가 buf
를 주는데 이는 유저 가상주소라 그냥 쓰면 안된다
그래서 커널 접근 가능 주소 얻어
이를 임시 버퍼로 써서 데이터 옮기는 역할이다
이렇게 데이터 담긴 버퍼를 다른데서 쓰는 거고 말이다
그리고 pintos에서는 쓸모 없다
static void
copy_in(void *kdst, const void *usrc, size_t n) {
uint8_t *kd = (uint8_t *)kdst; // 커널 공간 목적지 포인터 (진행 포인터)
const uint8_t *u = (const uint8_t *)usrc; // 유저 공간 소스 포인터 (진행 포인터)
while (n > 0) {
// 1) 현재 유저 주소 u가 "유저 영역"인지 확인
if (!is_user_vaddr(u)) system_exit(-1);
// 2) u가 속한 유저 페이지의 커널 매핑 주소(페이지 시작)를 얻는다
const void *kp = pml4_get_page(thread_current()->pml4, pg_round_down(u));
if (kp == NULL) system_exit(-1);
// 3) 페이지 내 오프셋을 더해 정확한 소스 주소(커널이 접근 가능한)를 만든다
const uint8_t *ksrc = (const uint8_t *)kp + pg_ofs(u);
// 4) 이 페이지에서 읽을 수 있는 최대 바이트 수 계산
size_t chunk = PGSIZE - pg_ofs(u);
if (chunk > n) chunk = n;
// 5) 실제 복사: 유저(의 커널 매핑) → 커널
memcpy(kd, ksrc, chunk);
// 6) 진행 포인터/잔량 갱신
kd += chunk;
u += chunk;
n -= chunk;
}
}
얜 반대다
유저가 아닌 커널 버퍼의 데이터를 유저주소로 옮겨준다는 말이다
그거 말고는 비슷하다
static void
copy_out(void *udst, const void *ksrc, size_t n) {
uint8_t *u = (uint8_t *)udst; // 유저 공간 목적지 포인터 (진행 포인터)
const uint8_t *k = (const uint8_t *)ksrc; // 커널 공간 소스 포인터 (진행 포인터)
while (n > 0) {
// 1) 현재 유저 주소 u가 "유저 영역"인지 확인 (커널/NULL/커널 예약영역이면 out)
if (!is_user_vaddr(u)) system_exit(-1);
// 2) u가 속한 "유저 페이지"를 현재 스레드의 pml4에서 커널이 접근 가능한 VA로 얻음
// - pg_round_down(u): u가 속한 페이지의 시작 주소로 내림
// - pml4_get_page(...): 그 페이지 프레임을 가리키는 '커널 매핑'을 리턴(없으면 NULL)
void *kp = pml4_get_page(thread_current()->pml4, pg_round_down(u));
if (kp == NULL) system_exit(-1);
// 3) 그 페이지의 '페이지 내 오프셋' 위치로 목적지를 맞춘다
// - kdst: "커널이 접근 가능한" 해당 유저 페이지의 정확한 목표 주소
uint8_t *kdst = (uint8_t *)kp + pg_ofs(u);
// 4) 이번에 이 페이지에서 쓸 수 있는 최대 바이트 수를 계산
// - 현재 u가 페이지 끝에 가까우면 남은 공간만큼만
size_t chunk = PGSIZE - pg_ofs(u);
if (chunk > n) chunk = n;
// 5) 실제 복사: 커널→유저(의 커널 매핑)
memcpy(kdst, k, chunk);
// 6) 진행 포인터/잔량 갱신
u += chunk;
k += chunk;
n -= chunk;
}
}