http://learnbranch.urigit.com/?demo

http://rogerdudler.github.io/git-guide/index.ko.html

http://git-scm.com/book/ko/v1




git


Git은 커밋을 가능한 자유롭게 하고자하여 커밋할 때마다 디렉토리 전체를 복사하지 않음

각 저장소의 이전 버전과 다음 버전의 변경내역("delta")를 저장

대부분의 커밋이 그 커밋위의 부모 커밋을 가리키고 있게 됨


저장소 복제("clone")을 하려면, 모든 delta를 풀어야 함

=> " resolving deltas "



git commit




git branch 

: 하나의 커밋과 그 부모 커밋들을 포함하는 작업 내역

특정 커밋에 대한 reference로 branch를 많이 만들어도 메모리나 디스크 공간에 부담이 되지 않음.

작업내역을 쌓아놓기보다는 잦은 branch 수행으로 작은 단위로 나누는 것이 좋음



 


git branch newImage


git commit

 : 제어가 master에 있는 상태에서 commit을 수행하여 master branch가 수행됨


다시 돌아가서..

 

git checkout newImage; git commit

* checkout (이동)


git merge(합치기)

: 여러 브랜치에서 새로 개발한 내용을 합치는 작업

두 개의 부모를 가리키는 특별한 커밋을 만들어냄

=> 두 개의 부모를 가리킴? 한 부모의 모든 작업내역과 나머지 부모의 모든 작업내역, 

그리고 그 두 부모의 모든 부모들의 작업 내역을 포함한다는 의미



master가 제어를 가진 상태에서 

git merge bugFix master (bugFix에 master를 합쳐라/연결하라)

 : master가 두 부모가 있는 커밋을 가리키고 있음


여기서 master에 bugFix를 연결하라/합쳐라

git merge master bugFix

 

: 모든 커밋의 색이 같아졌으며, 이는 두 브랜치가 모두 저장소의 모든 작업을 포함하고 있음을 의미


bugFix가 이미 master의 부모쪽에 있었기 때문에, 

아주 간단하게 bugFix를 master가 붙어있는 커밋으로 이동시킬 수 있음




git branch bugFix

git checkout bugFix

git commit

git checkout master; git commit

git merge bugFix master



git rebase

: 브랜치끼리의 작업을 접목하는 두번째 방법으로, 기본적으로 커밋들을 모아서 복사한 뒤 다른 곳에 떨궈 놓는 것


커밋들의 흐름을 보기 좋게 한줄로 만들 수 있음. 커밋과 로그이력이 한결 깨끗해 짐



bufFix 브랜치에서의 작업을 master 브랜치 위로 직접 옮기기 (마치 순서대로 개발한 것 처럼)

bugFix가 선택된 상황에서, 

git rebase master

C3는 어딘가 그대로 남아있고 복사본이 생기게 됨

이때 master branch와의 병합을 원하므로, master로 이동 후 

git rebase bugFix

master가 bugFix의 부모로 위치해 있었기 때문에, 더 앞쪽의 커밋을 가리키게만 바꿔주면 손쉽게 위처럼 설정이 가능





git branch bugFix

git checkout bugFix; git commit

git checkout master; git commit

git checkout bugFix

git rebase master



git 작업돌리기

- 개별 파일이나 묶음을 스테이징하기

- 실제 변경을 복구


변경내용 되돌리기

git reset

git revert


git reset은 이전 커밋을 가리키도록 하여 작업을 되돌리는 방법으로 히스토리 변경이라고도 함


git reset HEAD~1


히스토리를 변경하는 git reset은 각자 작업하는 로컬 브랜치에서는 유용하지만,

여러사람이 공유하는 리모트 브랜치에는 적합하지 않음


변경분을 되돌리고, 되돌린 내용을 다른 사람과 공유하는 작업이 필요함

git revert













'System > Etc.' 카테고리의 다른 글

FDT  (0) 2015.11.14
[OS 기초] File System 2 - Disk Scheduling  (0) 2015.11.06
[OS 기초] File System  (0) 2015.11.05
[OS 기초] I/O Device와 Device Driver  (0) 2015.11.05
[OS 기초] Demand paging 3 - Trashing, Working Set  (0) 2015.11.04




clz :  0의 갯수를 셈


일반적으로 clz을 하면 0의 갯수를 세서 시프트 하려고 사용함

그러면 원하는 값을 얻을 수 있도록 리눅스는... 그렇게 사용함


가령.. 

way의 갯수가 4개라 값이 3일때, 


현재 way의 값을 알고싶을때, 

이때 clz를 해서 14만큼 시프트연산을 수행하면 내가 원하는 값인 3이 나오게 됨



a = 0b 0000 0000 0000 0011이다.

b = 14

a << b = 0b 1100 0000 0000 0000



'System > Linux Kernel' 카테고리의 다른 글

wont_overwrite  (0) 2016.01.23
CFS 구현의 핵심  (0) 2016.01.22
system(), fork()  (0) 2015.12.24
[Unix V6] 시스템 부팅  (0) 2015.12.19
Device Tree, 리눅스 커널 4.0  (0) 2015.08.29

리눅스에서 프로세스 시작과 관련된 함수 

: system(), fork()


종료와 관련된 함수

: wait(), waitpid(), exit()





##### system()


#include <dtdlib.h>

int system(const char    *string);

프로그램 수행도중 새로운 명령이나 프로그램 수행 가능

string : 명령 (sleep 3, ls ...)



##### fork()


#include<unistd.h>

pid_t fork(void);


프로세스 생성

부모프로세스로부터 만들어지며, 부모 프로세스와 같은 공간의 코드를 수행하지만 자기자신만의 데이터 공간 및 FDT등의 실행 환경을 구성

고유한 PID를 갖고, 부모프로세스의 PID를  자신의 PPID에 저장

부모 프로세스로부터 시그널 등도 상속받음

부모프로세스의 함수와 자식 프로세스의 함수에서는 서로 다른 값을 반환하여, 각 프로세스에서 수행할 일을 구분하게 됨

(부모 return : 정상 시 자식프로세스 PID, 자식 return : 정상 시 0)


fork() 실패 시 -1 rerutn.

- 메모리 부족 : errno 변수에 ENOMEM 설정

- 자식 프로세스 개수의 제한 : errno변수에 EAGAIN 설정



##### wait() 

: 자식프로세스의 종료까지 책임이 부여되는 함수


#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *stat_loc);


case 1. 자식프로세스가 존재하는 경우

wait() 호출 -> 자식프로세스가 시그널을 보낼 때 까지 부모프로세스의 수행 중지 -> 자식프로세스의 PID반환

case 2. 자식프로세스가 존재하지 않는 경우

wait() 호출 -> -1 반환 -> errno 변수에 ECHILD 설정

case 3. 부모 프로세스에서 자식 프로세스의 종료 원인을 자세히 알고싶은 경우

인수로 상태정보를 읽어 올 수 있는 변수를 넘겨줌 -> 종료 상태 확인(sys/wait.h의 매크로 사용)


<관련 매크로>

'System > Linux Kernel' 카테고리의 다른 글

CFS 구현의 핵심  (0) 2016.01.22
커널에서 원하는 값을 가지고오기 위해 clz를 하는 이유  (0) 2016.01.16
[Unix V6] 시스템 부팅  (0) 2015.12.19
Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18

리눅스에서는 shell(base)를 통해 명령 및 프로그램을 실행

환경변수는 명령이나 프로그램을 수행하는 데 필요한 정보를 가짐


HOME : 현재 로그인 사용자의 홈 디렉토리

PATH  : 명령을 검색할 디렉토리 목록. 리눅스 명령에 대한 실행 파일의 위치가 포함

PS1 : 쉘 프롬프트

MANPATH : 온라인 매뉴얼 검색 디렉토리 목록

USERNAME : 로그인 사용자 명

HOSTNAME : 사용중인 시스템의 호스트 명


c에서 getenv("환경변수명"); 으로 값을 얻어올 수 있음

<-> putenv();



##### 사용자 계정정보

/etc/passwd : 리눅스에서 사용자 계정정보를 보관하는 파일

계정, UID, GID, 홈디렉토리, 로그인 쉘 등을 포함한 상세한 정보를 저장


# include <sys/types.h>


struct passwd *getpwuid(uid_t uid);

struct passwd *getpwnam(const char *name);


struct passwd {

char *pw_name;

uid_t pw_uid;

gid_t pw_gid;

...

}



### UID

: 리눅스 사용자 ID


1. Real UID : 실제 로그인 한 사용자 계정의 UID


getuid(), getgid(), setuid(), setgid()


2. Effective UID : 파일 접근의 효과를 가지고 있는 UID

일반적으로 Real UID와 동일하나 set-UID 퍼미션이 설정된 프로그램을 수행하면 일시적으로 변경이 가능하며,

파일 접근에 대한 권한을 설정할 수 있음


geteuid(), getegid()



### PID

리눅스에서 모든 명령은 파일로 정의되며, 명령을 수행한다는 것은 해당 파일을 실행하는 프로세스가 동작한다는 것을 의미


getpid() : 현재 프로세스 ID 출력

getppid() : 현재 프로세스의 부모 프로세스 ID 출력


### time 

리눅스에서는 시스템 시간을 clock tick으로 세며 다음과 같은 함수들을 제공


time() 초단위 시간으로 확인 가능

gettimeofday() 마이크로 초 단위의 시간까지 확인 가능

times() 프로그램의 실행 시간을 확인하는 함수

uname() 시스템 호스트 정보. 시스템의 이름이나 OS 종류 및 버전 등에 대한 정보가 필요할 경우 사용

localtime() time()에서 구한 시간을 연,월,일,시,분,초의 형식으로 계산해주는 함수


### 시스템 자원의 제한치 설정


int getrlimit(int resource, struct rlimit *r_limit);

int setrlimit(int resource, const struct rlimit *r_limit);


struct rlimit {

rlim_t    rlim_cur;        // 현재 설정된 소프트 제한 값 확인

rlim_t    rlim_max;        // 절대적 제한치

};


<설정 가능한 리소스 종류>

RLIMIT_CPU

RLIMIT_FSIZE

RLIMIT_DATA

RLIMIT_STACK

RLIMIT_CORE

RLIMIT_NPROC

RLIMIT_NOFILE

RLIMIT_MEMLOCK



'System > Linux OS ' 카테고리의 다른 글

.exrc  (0) 2016.04.23
lsof  (0) 2015.12.24
strace, ltrace  (0) 2015.12.24
gcc / gdb  (0) 2015.12.24
man  (0) 2015.12.24


##### lsof

현재 동작 중인 모든 프로세스에 대한 오픈된 파일 보기


* 리눅스에서는 모든걸 파일로 관리하므로 유용하고 다양하게 쓰이는 명령어임


ex) 


$ sudo lsof -p 1052

특정한 1052번 프로세스가 오픈한 파일들의 목록


$ sudo lsof -i:22

네트워크가 연결되어있는 호스트나 포트로 확인


$ lsof -s /tmp

특정 파일 또는 디렉토리와 관련한 프로세스 찾기



'System > Linux OS ' 카테고리의 다른 글

.exrc  (0) 2016.04.23
리눅스 환경변수와 UID, PID, 시스템자원의 제한  (0) 2015.12.24
strace, ltrace  (0) 2015.12.24
gcc / gdb  (0) 2015.12.24
man  (0) 2015.12.24



##### strace

프로그램이 실행되는 동안 수행되는 시스템콜을 추적하는 도구

디버깅 초기에 문제를 확인하거나 메모리 문제 같은 운영체제 관련 문제를 추적할 때 사용


$ strace -help

usage: strace [-CdffhiqrtttTvVxxy] [-I n] [-e expr]...

              [-a column] [-o file] [-s strsize] [-P path]...

              -p pid... / [-D] [-E var=val]... [-u username] PROG [ARGS]

   or: strace -c[df] [-I n] [-e expr]... [-O overhead] [-S sortby]

              -p pid... / [-D] [-E var=val]... [-u username] PROG [ARGS]


-f : 자식프로세스도 추적

-tt / -T : 타임 스탬프 표시 / 실지 함수호출 시간 표시

-v : 상세 출력 모드

-p PID : 이미 실행중인 프로세스 추적

-o 파일명 : 추적 결과 파일에 저장

-e trace=### : ###에 해당되는 내용 출력

ex) -e trace=open



$ strace /bin/pwd

시스템콜 이름, 매개변수, 반환값





$ sudo strace -p $(pgrep ssh)        // ssh 포트그룹을 식별하여 ssh 프로세스의 시스템 콜 확인


> select 함수에서 waiting


> 다른 곳에서 ssh를 통해 접속


> accept 함수로 떨어지면서 정상정으로 ssh 접속 수행




$ sudo strace -e trace=process -p $(pgrep ssh)      // ssh 동작 중 프로세스 관련 시스템 콜 부분만 뽑아 보기


> 프로세스가 수행되는 중인 정보만 나옴


> ssh 접속


> clone 시스템 콜이 동작하여 프로세스가 생성됨


> $ exit 명령을 사용하여 ssh 접속 종료


> ssh 접속 종료후의 프로세스 관련 내용 출력





##### ltrace 

프로그램이 실행되는 동안 호출되는 동적(공유) 라이브러리 함수를 추적하는 도구

strace와 유사

동적 라이브러리만 추적하므로 파악하기는 쉽지만, 문제의 원인을 찾기가 어려움


-u username : username의 권한으로 명령 실행하면서 라이브러리 추적 (관리자 권한 필요)

-tt / -T : 타임 스탬프 표시 / 실지 함수호출 시간 표시

-v : 상세 출력 모드

-p PID : 이미 실행중인 프로세스 추적

-o 파일명 : 추적 결과 파일에 저장

-e {[+|-][라이브러리 함수명][라이브러리 파일명]} : 해당 내용만 출력



$ ltrace cat /etc/passwd


> 함수들과 인수들의 값을 동적으로 확인



$ sudo ltrace -e malloc+free+select -p $(pgrep ssh)        // ssh 동작 중 -e 옵션으로 malloc+free+select 부분만 출력



> ssh 접속이 되면 해당 부분만 출력


> ssh 접속 종료에도 해당 정보만 출력



 

'System > Linux OS ' 카테고리의 다른 글

리눅스 환경변수와 UID, PID, 시스템자원의 제한  (0) 2015.12.24
lsof  (0) 2015.12.24
gcc / gdb  (0) 2015.12.24
man  (0) 2015.12.24
리눅스 커널 커밋(commit)하기 - ing  (0) 2015.12.23


##### gcc 

: GNU Compiler CollectionGNU의 C 컴파일러

(이름이 바뀜, 이전엔 C Compiler 였나..?)


ANSI + POSIX



### 과정 및 옵션

.c -> 컴파일(전처리①, 문법검사/코드최적화 -> .o -> 링크 -> .exe


① 컴파일과정 - 전처리 옵션

-I : 헤더파일 위치지정 옵션, 표준 디렉토리(/usr/include) 외의 헤더파일의 위치 지정에 사용

-D : Dname, name에 지정된 심볼을 1로 정의, 조건부 컴파일에서 유용하게 사용 됨


② 컴파일과정 - 문법검사/코드최적화

-O : "ON", 컴파일러 최적화 옵션으로 최적화 단계(0~3)를 N으로 지정


③ 링크과정

-L : 라이브러리 파일이 위치하는 경로를 지정

-l + string : 컴파일 시 string으로 입력한 경로의 라이브러리 파일을 추가

* 라이브러리 파일은 ".so" or ".a"

* 라이브러리 파일의 이름은 "lib"로 시작

* 표준 라이브러리는 "/usr/lib"에 존재

ex) 수학 표준 라이브러리 libm.a or libm.so 사용시 "-lm"을 사용해야 함

gcc -o exam_mlib ex exam_mlib.c -lm


④ 기타

g : 실행파일에 표준 디버깅 정보 포함, gdb, DDD 등 디버거 이용 시 사용

wall : gcc가 제공하는 모든 경고를 사용,

시스템과 네트워크 프로그램 및 커널기반의 프로그램 작성 시 해당 옵션을 사용하는 게 좋음



### 라이브러리


1. 정적 라이브러리

소스파일 생성(.c) -> 오브젝트파일 생성(.o) -> 라이브러리파일생성(.a)

  vi static.c                gcc -c static.c                ar rb lib##.a  static.o


2. 동적 라이브러리

소스파일 생성(.c) -> 재배치 가능한 오브젝트파일 생성(.o) -> 라이브러리파일생성(.a)

  vi shared.c              gcc -c -fPIC shared.c                        ld -shared -o lib##.so shared.o


* 공유 라이브러리 파일 이용 시 메모리에 미리 올라가져 있어야 사용할 수 있으며, 환경변수 설정 후 사용할 수 있게 됨됨

사용자 home의 .bashrc파일에 저장하여 매번 실행해야하는 불편함을 줄일 수 있음




### sysinfo를 활용하여 간단한 프로그램 작성


$ man 2 sysinfo


$ vi test_sysinfo.c


$ gcc -o sysinfo sysinfo.c


$ ./sysinfo



##### gdb 


* gdb를 이용하여 파일을 디버깅하려면 실행파일이 디버그모드로 컴파일 되어 있어야 함 (-g 옵션 사용)


명령어 참고. 

https://sourceware.org/gdb/current/onlinedocs/gdb/index.html#Top

http://egloos.zum.com/psyoblade/v/2653919




'System > Linux OS ' 카테고리의 다른 글

lsof  (0) 2015.12.24
strace, ltrace  (0) 2015.12.24
man  (0) 2015.12.24
리눅스 커널 커밋(commit)하기 - ing  (0) 2015.12.23
Btrfs/트리  (0) 2015.08.13


### man 

: 개발자를 위한 리눅스 매뉴얼



man [section #no] 라이브러리 함수명 or 시스템 콜이름


section #no. 1 : 시스템 콜 매뉴얼

     2 : 라이브러리 함수 매뉴얼





$ man --help

Usage: man [OPTION...] [SECTION] PAGE...




### time system call 매뉴얼


$ man 2 time





SYNOPSIS : 문법

DESCRIPTION : 설명

RETURN VALUE




### memset() 함수 매뉴얼


$ man 3 memset





'System > Linux OS ' 카테고리의 다른 글

strace, ltrace  (0) 2015.12.24
gcc / gdb  (0) 2015.12.24
리눅스 커널 커밋(commit)하기 - ing  (0) 2015.12.23
Btrfs/트리  (0) 2015.08.13
Linux LVM  (0) 2015.08.12


1. ubuntu 설치


virtualbox

ubuntu-desktop-14.04.iso


Memory 2GB, HDD 20GB

Network Interfaces

eth0(bridge mode) 192.168.168.106/24

eth1(NAT) - 10.0.3.15/24



 > ssh로 작업할 예정




2. GRUB 부트로더 설정 (CLI 모드로 실행되게)


$ sudo vi /etc/default/grub 


GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

GRUB_CMDLINE_LINUX=""

#GRUB_TERMINAL=console

를 아래와 같이 수정


#GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

GRUB_CMDLINE_LINUX="text"

GRUB_TERMINAL=console




'System > Linux OS ' 카테고리의 다른 글

gcc / gdb  (0) 2015.12.24
man  (0) 2015.12.24
Btrfs/트리  (0) 2015.08.13
Linux LVM  (0) 2015.08.12
[tip] tmpdump ipv4 ipv6 모드변경  (0) 2015.05.01


UNIX v6로 배우는 커널의 원리와 구조 (한빛미디어)

http://v6.cuzuco.com/v6.pdf






##### 14. 시스템 부팅




<개요>


- 커널 프로그램을 메모리로 읽어야 함(약 40KByte)

- 당시에는 메모리 용량이 작아서 ROM에 저장해 놓을 수 없었음

=> 단계를 나누어 작은 크기부터 읽은 후 큰 크기의 프로그램을 읽는 점진적 형태로 부팅을 수행

1. 부트로더를 읽는 프로그램을 먼저 메모리로 올리고,

2. 부트로더를 읽고,

3. 실제 커널 프로그램을 읽음




<Unix V6의 부팅과정>


1. ROM에 저장되어있는 Boot Strap Loader Program에서, Root Disk의 블록번호 0에 저장된 Boot Strap Program을 읽어서 메모리의 0x0으로 읽어옴

* Boot Strap Program은 시스템 관리자가 /etc/mkfs을 실행하여 파일 시스템을 구축할 때 블록 디바이스의 0번째 블록에 위치하도록 설정


2. Boot Strap Program은 Root Disk의 fs에서 /Unix나 /rkunix에 있는 Kernel Program의 본체를 메모리의 0x0으로 계속하여 읽어서 실행


3. kernel은 시스템을 초기화 함



<부팅, low.s>

--------------------------------------------------------------------------

/*

 *    커널 본체(?)의 하위 어드레스 부분

*/


1.    . = 0^.                            // 프로그램이 메모리로 로드될 때 주소가 0x0 임

2.        br    1f                       // 최초 실행 명령어, label 1로 brach

3.        4                               

4.        

5.        /* 중간 생략 */

6.

7.    . = 40^.

8.    .global    start,    dump   

9.    1:    jmp    start               // start로 jump

10.         jmp    dump

--------------------------------------------------------------------------





### 14.1.1 start


<start, m40.s> 

--------------------------------------------------------------------------

/*

 *    <처리내용>

 *

 *    1. 커널 APR 초기화

 *        - 최초의 커널공간을 설정

 *        - 커널 APR(Active Page Register, PAR과 PDR) 설정 (참고. p460, 표 14.1 커널 APR 초기 설정)

 *            a. APR0~5 : 물리메모리의 0~0137777를 할당. 물리어드레스 = 가상어드레스영역. 앞부분에 커널프로그램의 본체가 로드 됨

 *            b. APR6 : 커널 프로그램 뒤의 1KByte 영역 할당. proc[0]의 PRDA(user 구조체와 커널스택)이 할당

 *                            현재 실행 중인 프로세스의 PRDA이며, 프로세스 전환히 함께 전환 됨

 *            c. APR7 : 물리메모리의 최상위 영역 할당(0760000~07777777)

 *                            PDP-11/40이나 주변 디바이스 레지스터를 할당하여 PDP-11/40과 주변장치를 제어

 *            d. SP는 APR6 영역의 맨 끝을 가리키도록 함

  *        - 커널 APR은 PAR6을 제외하고 시스템 동작 중에는 값이 바뀌지 않음

 *            => 실행 프로세스의 PAR6은, user 구조체로 접근할 수 있는 전역변수 u(0140000)를 사용하여         

 *                해당 data segment의 physical memory address로 설정 (참조. p65, 그림 2.13 물리 어드레스 계산)

 *            (PAR, Page Address Register, 11~0 bit, physical memory block address의 base address register, 64bit 단위)

 * 

 *    2. MMU 초기화

 *        - SR0을 설정하여 MMU를 활성화 하면 "physical address <-> logical address"가 시작 됨 (가상메모리 사용을 시작 함)

 *            MMU는 SR0과 SR2라는 Status Register를 가짐 (참고. p41)

 *            SR0 : 메모리 관리 유효화 플래그와 에러 정보에 사용

 *            SR2 : 실행할 명령어의 16bit logical address

 *        - 커널 프로그램의 bss와 proc[0]의 PPDA를 0으로 초기화 (참고. p59)

 *                PPDA : 프로세스의 메모리 영역 중 Data Segment의 "user구조체 + 커널 스택 영역" 

 *                bss : 프로세스의 메모리 영역 중 Data Segment의 Data 영역에 있는 정적 변수가 위치하는 영역

 *        - 이전 모드를 user mode로 설정한 후 main() 실행 

 * 

 *    3. miain() 수행

 * 

*/


0610 /* ------------------------- */ 


0611 .globl start, _end, _edata, _main 

0612 start: 


/* MMU가 이미 활성화 되어있으면 비활성화가 될 때까지 진행하지 않음 */

0613 bit $1,SSR0 / SSR0 : SR0의 어드레스, SR0[0] bit가 서 있으면, MMU에서 메모리 관리 활성화 (SSRO = 177572)

0614 bne start / loop if restart 

0615 reset 

0616 


0617 / initialize systems segments, 커널 APR0-5의 초기화

0618 

0619 mov $KISA0,r0 / KISA0 = 172340, 커널 APR의 PAR

0620 mov $KISD0,r1 / KISD0 = 172300, 커널 APR의 PDR

0621 mov $200,r4 

0622 clr r2 / r2 클리어 

0623 mov $6,r3 


0624 1: 

0625 mov r2,(r0)+ 

0626 mov $77406,(r1)+ / 4k rw

0627 add r4,r2 

0628 sob r3,1b 

0629 

/*

* APR은 0~7까지 8쌍이 존재하며, 한 쌍의 APR은 한 페이지에 대응

* _edata : 데이터영역, _etext : 텍스트영역, _end : bss영역의 하한 어드레스를 가리킴 

* => 프로그램 컴파일 시 링커에 의해서 심볼 테이블로 저장

*/

0630 / initialize user segment, 커널 APR6 초기화

0631 

0632 mov $_end+63.,r2 

0633 ash $-6,r2 

0634 bic $!1777,r2 / PAR6 설정값 계산

0635 mov r2,(r0)+ / ksr = sysu / APR이 64byte 단위로 물리 어드레스를 관리하므로 반올림 할 때

0636 mov $USIZE-1\<8|6,(r1)+ / 6비트 오른쪽으로 시프트하여 하위 10bit를 남기고 0으로 초기호 

0637 

0638 / initialize io segment, 커널 APR7 초기화

0639 / set up counts on supervisor segments 

0640 

0641 mov $IO,(r0)+ 

0642 mov $77406,(r1)+ / rw 4k 

0643 

0644 / get a sp and start segmentation 

0645 / SP 초기화 및 MMU 활성

0646 mov $_u+[USIZE*64.],sp 

0647 inc SSR0 

0648 

0649 / clear bss

0650 / bss 활성화

0651 mov $_edata,r0  

0652 1:

0653 clr (r0)+

0654 cmp r0,$_end

0655 blo 1b

0656

0657 / clear user block

0658 / proc[0] user 커널 스택 영역을 0으로 초기화 

0659 mov $_u,r0

0660 1:

0661 clr (r0)+

0662 cmp r0,$_u+[USIZE*64.]

0663 blo 1b

0664

0665 / set up previous mode and call main

0666 / on return, enter user mode at 0R

0667 / main() 호출

0668 mov $30000,PS

0669 jsr pc,_main

0670 mov $170000,-(sp)

0671 clr -(sp)

0672 rtt


--------------------------------------------------------------------------



### 14.1.2 main() 



<처리내용>


1. 메모리 초기화


- proc[0]의 PPDA이하를 0으로 초기화 한 후 빈 영역의 관리를 위해서 coremap[]에 추가.

map 구조체 : 물리 메모리와 스와프 영역의 빈 영역을 관리 (빈 영역의 어드레스 크기를 나타냄) (참고. p134)

(coremap[] : 물리 메모리 관리영역(APR의 최소단위인 64bytes 단위) , swapmap[] : swap 메모리 관리영역(512bytes, 블록단위)


- MAXMEM 설정

: 실제 빈 영역의 크기를 나타내는 maxmem에는 실제 빈 영역의 크기와 MAXMEM 중 더 작은 값을 설정


int maxmem;    (system.h, maxmem)

#define MAXMEM    (64*32)    (param.h, MAXMEM)


2. swap 영역 초기화


- swapmap[]

- mfree() 확보

- swplo 블록에서 mswap 블록까지의 영역을 swapswap에 swap 영역으로 등록


(conf.c)

int swplo    4000;

int nswap    872;


3. clock 장치 초기화


4. proc[0] 생성

- proc[0] : 시스템 프로세스 스케줄러


5. I/O자원 초기화


6. proc[1] 생성 

- proc[1] : /etc/init을 실행하는 사용자 프로세스로 inode[]에 넣어둔 명령어들을 실행


* inode : 파일크기, 접근권한, 데이터가 저장된 블록 디바이스의 블록 번호정보 등을 포함하는 파일의 속성 데이터

블록 디바이스에 저장되어 있으며, 커널은 파일을 사용하기 위해 해당 파일의 inode를 읽음




<inode[], ken/main.c>


1511 /* 1561 UISD->r[0] = 077406; 

1512 * Icode is the octal bootstrap 

1513 * program executed in user mode

1514 * to bring up the system. 

1515 */ 

1516 int icode[] 

1517 {

1518     0104413, /* sys exec; init; initp */ 

1519     0000014, 

1520     0000010, 

1521     0000777, 

1522     0000014, /* initp: init; 0 */ 

1523     0000000, 

1524     0062457, /* init: */ 

1525     0061564, 

1526     0064457, 

1527     0064556, 

1528     0000164, 

1529 };



=> C언어 판

1    char *init = "/etc/init";

2    execl(init, init, 0);

3    while(1);



< main(), ken/main.c >


1550 main() 

1551 { 

1552     extern schar; 

1553     register i, *p; 

1554 

1555     /* 

1556     *     zero and free all of core  메모리와 스택영역 초기화

1557     */ 

1558 

1559     updlock = 0; 

1560     i = *ka6 + USIZE;                 // i에 proc[0]의 PRDA 영역의 뒤에 어드레스를 설정

ka6은 커널의 APR6의 어드레스(KISA6)이 설정되어 있으므로 "*ka6"으로 커널 APR6 값 가져오기

1561     UISD->r[0] = 077406;         // UISD, UISA : 사용자 APR0의 PAR, PDR의 어드레스 (seg.h에 define되어있음)

1562     for(;;) {     

1563         UISA->r[0] = i; 

1564         if(fuibyte(0) < 0)             // fuibyte() : 이전 모드의 가상 어드레스 공간의 데이터를 한 바이트만큼 복사하는 함수

 전 모드가 user mode이므로 fuibyte(0)은 사용자 APR0에 할당된 페이지의 처음부터 데이터를 복사하기 시작

1565             break; 

1566         clearseg(i);                       // 성공 시 수행루틴

1567         maxmem++;                     // coremap을 증가시키기 

1568         mfree(coremap, 1, i);        //  coremap 초기화

1569         i++; 

1570     } 

1571     if(cputype == 70) 

1572    for(i=0; i<62; i=+2) { 

1573         UBMAP->r[i] = i<<12; 

1574         UBMAP->r[i+1] = 0; 

1575     } 

1576     printf("mem = %l\n", maxmem*5/16); 

1577     printf("RESTRICTED RIGHTS\n\n"); 

1578     printf("Use, duplication or disclosure is subject to\n"); 

1579     printf("restrictions stated in Contract with Western\n"); 

1580     printf("Electric Company, Inc.\n"); 

1581 

1582     maxmem = min(maxmem, MAXMEM);

1583     mfree(swapmap, nswap, swplo); 

1584 

1585     /* 

1586     * set up system process, 프로세스 0 생성

1587     */ 

1588 

1589     proc[0].p_addr = *ka6;     

1590     proc[0].p_size = USIZE; 

1591      proc[0].p_stat = SRUN;

1592     proc[0].p_flag =| SLOAD|SSYS;     // SSYS : 시스템 프로세스, 스와프아웃의 대상이 되지 않음

1593     u.u_procp = &proc[0]; 

1594 

1595     /*

1596     * determine clock, 클록장치 초기화

1597     */ 

1598 

1599     UISA->r[7] = ka6[1]; /* io segment */        // 사용자 APR7에 커널 APR7 값을 설정 => fuiword()가 I/O 영역에 접근할 수 있도록 설정

1600    UISD->r[7] = 077406; 


// CLOCK1 : 전원주파수 클록 레지스터의 어드레스

// CLOCK2 :  프로그래머블 클록 자아치의 레지스터의 어드레스


< CLOCK, ken/main.c >

#define CLOCK1    0177546

#define CLOCK2    0172540


1601     lks = CLOCK1;                         

1602     if(fuiword(lks) == -1) {     // CLOCK1에 대해 fuiworkd()를 수행

1603         lks = CLOCK2;             // 실패하면 CLOCK2에 재수행

1604         if(fuiword(lks) == -1) 

1605             panic("no clock");     // CLOCK1, CLOCK2 둘 다 실패하면 pannic()으로 실행 중지

1606     } 

1607     *lks = 0115;     // 초기값이 왜 뒤에있을까.. 미리 설정되어있어야 하는게 아닐까? 전역변수 같은데 딴데서 먼저 했나보네~~

1608 

1609    /* 

1610     * set up ’known’ i-nodes, 자원 초기화

1611     */ 

1612 

1613     cinit(); 

1614     binit(); 

1615     iinit(); 

1616     rootdir = iget(rootdev, ROOTINO); 

1617     rootdir->i_flag =& ~ILOCK; 

1667     while(nt >= 128) { 

1618         u.u_cdir = iget(rootdev, ROOTINO); 

1619         u.u_cdir->i_flag =& ~ILOCK; 

1621         /* 

1622         * make init process             , 프로세스 1 생성

1623         * enter scheduling loop 

1624         * with system process 

1625         */ 

1626 

1627         if(newproc()) {         // proc[1]을 생성


//  proc[1]의 데이터영역의 어드레스 0에 inode[]를 복사하고 리턴

//

1628             expand(USIZE+1);             

1629             estabur(0, 1, 0, 0); 

1630             copyout(icode, 0, sizeof icode);   

1632             * Return goes to loc. 0 of user init 

1633             * code just copied out. 

1634             */ 

1635             return;     // return 되면 main()을 실행했던 위치로 돌아가서 값을 스택에 쌓고, rtt 명령을 실행

// rtt명령 : 스택의 처음부터 pc에 0, PSW에 0170000을 읽음

// 현모드, 이전모드가 사용자 모드 상태이며, 사용자 공간의 어드레스 0부터 명령이 실행

// 어드레스 0에 icode[]가 복사되어 있기 때문에 /etc/init을 실행하여 처리

1636         } 

1637         sched();         // proc[0]이 실행하여, 스와핑 대상이 없으므로 proc[0]은 sleep하고 제어권은 proc[1]로 이동

1638     } 

1639 /* ------------------------- */





### 14.1.3 /etc/init


* 사용자 프로그램, 자세한 내용은 UPM(8) 참조


1. 등록된 터미널에 대한 프로세스를 생성

2. 각 프로세스는 터미널의 다이얼 업 접속, 사용자의 로그인을 기다림. 

사용자가 로그인하면 쉘 프로그램을 실행

3. /etc/init는 이후 무한 루프로 들어가서 프로세스 처리를 계속


> 스케줄러는 sched(), switch() 실행을 계속 수행

> /etc/init : 등록된 터미널에 대응하는 프로세스를 생성하고 고아 프로세스의 처리 루프를 계속 수행

> 각 터미널에 대응하는 프로세스 터미널의 다이얼 업 접속과 사용자의 로그인을 기다림







'System > Linux Kernel' 카테고리의 다른 글

커널에서 원하는 값을 가지고오기 위해 clz를 하는 이유  (0) 2016.01.16
system(), fork()  (0) 2015.12.24
Device Tree, 리눅스 커널 4.0  (0) 2015.08.29
메모리관리  (0) 2015.08.18
인터럽트 / 트랩  (0) 2015.08.16

+ Recent posts