[Linux:Kernel] string 처리 개선

String copying

ssize_t strscpy(char *dest, const char *src, size_t count);

ssize_t strscpy_truncate(char *dest, const char *src, size_t count);

strscpy()는 src에서 dest로 최대 count bytes를 copy한다. source string이 count bytes보다 긴 경우를 제외하고는 copy된 bytes 수를 리턴한다. 긴 경우는 -E2BIG을 리턴한다. 다른 차이는 overflow 나는 경우는 src를 truncate하는게 아니라 dest가 empty string이 된다. 에러 체크를 항상 하면 괜찮은데, 안하는 경우, truncate된 string이 문제를 일으키는 일이 많기 때문에 이렇게 동작한다고 한다.

truncate된 string이 필요한 경우는 아래 버전을 사용하면 된다. 리턴 값은 같지만, null-terminate된 truncate된 string이 dest에 들어간다.

Integer parsing

simple_strto*() 함수가 많이 사용되지만, checkpatch가 불평하듯, kstrto*()가 더 낫다. 그런데, simple_strto*()는 “123abc”와 같은 string을 123으로 변환하는데, 이게 편리한 경우도 있다. 그래서 새로운 함수가 제안되었다.

int parse_integer(const char *s, unsigned int base, <type> *val);

사실, parse_integer()는 함수가 아니라 val의 타입에 맞는 여러가지 매크로이다. val이 unsigned short라면, 디코딩은 unsigned를 기초로 하고, 결과값이 short의 범위를 벗어나지 않는지 확인된다.

최종 결과는 val안에 담기고, 디코딩된 char 수가 리턴된다. 전체 string이 decode됐는지는 s[return_value] 가 null byte인지를 체크하면 된다. null-terminate string이면 원래 s[strlen(s)]는 ‘\0’일 테니까. 아니라면, 그 곳에 parsing하는 string이 계속 있을 거다. base가 문서화되지 않은 값 PARSE_INTEGER_NEWLINE과 or되면, 맨 마지막의 newline character는 무시-sysfs file로의 input을 parsing할 때 유용하다-된다. 아무 character도 convert되지 않으면, -EINVAL을 리턴한다. overflow인 경우 -ERANGE를 리턴한다.

출처: Improving kernel string handling(http://lwn.net/Articles/643376/)

구글의 Python Tutorial

[번역] 구글의 파이썬 튜토리얼 요약.
원문은 Google’s Python Class(https://developers.google.com/edu/python/)

* Python 환경 설정

나올 때 윈도우에서는 Ctrl-Z, 다른 OS에서는 Ctrl-D

* Introduction

if __name__ == ‘__main__’:
    main()

sys.argv[0]는 프로그램 이름, sys.argv[1]은 첫번째 인자, sys.argv[2]는 두번째 인자…

TAB 문자 대신 Space들을 입력.

help(len) : len 함수에 대한 문서를 출력
dir(sys): sys 모듈에 대한 전반적인 문서
help(sys.exit): sys 내의 exit() 함수에 대한 문서

* Strings

파이썬 스트링은 “immutable”하다. 즉, 생성 후에 값을 변경할 수 없다. 따라서 다른 값이 되면 새로운 스트링이 생성된다.

“”” 로 여러줄 string 가능

[ ]로 문자 접근 가능
Slice로 substring 얻기
len(string) 은 string의 길이. sequence 타입에는 다 사용 가능
‘+’ 로 concatenate.

Value를 string 으로 변경하고 싶을 때는 str() 함수를 사용

pi = 3.14
text = ‘The value of pi is ‘ + str(pi)

정수로 나눗셈을 할 때는 // 를 사용. 6 // 5 == 1

print 뒤에 줄바꿈을 하고 싶지 않으면 마지막에 , 를 붙인다.
r 을 앞에 붙이면 ‘raw’ string. \ 를 특별히 취급하지 않는다. r’x\nx’ 는 ‘x\nx’ 가 됨. u 를 앞에 붙이면 unicode.

s.lower(), s.upper(): 소문자, 대문자로
s.strip(): 앞 뒤의 whitespace 제거
s.isalpha() / s.isdigit() / s.isspace(): 알파벳인지, 숫자인지, space인지
s.startswith(‘other’), s.endswith(‘other’): s 스트링이 다른 특정 스트링으로 시작하거나 끝나는지.
s.find(‘other’): s 스트링 안의 다른 스트링을 찾는다. 찾으면 인덱스 리턴, 못찾으면 -1
s.replace(‘old’, ‘new’): 모든 ‘old’를 ‘new’로 변경한 string 리턴
s.split(‘delim’): 주어진 delimiter로 자른 substring 리스트를 리턴,
s.join(list): split()의 반대, s를 delimiter로 리스트를 합친다.

길이가 1인 string 에 ==, <= 등의 작업을 할 수 있다. char 타입이 따로 없다.

H  e  l  l  o
0  1  2  3  4
-5 -4 -3 -2 -1

s[1:4]는 ‘ell’, s[1:]는 ‘ello’, s[:]는 ‘Hello’의 복사본, s[1:100]은 ‘ello’ – 더 큰 index를 사용하면 string의 length나 마찬가지가 된다.
s[-1]은 ‘o’, s[-4]은 ‘e’, s[:-3]은 ‘He’, s[-3:]은 ‘llo’
s[:n] + s[n:] == s 는 항상 참. n이 음수거나, index영역을 벗어났을 때도 성립.

% 연산자를 사용해 printf 같은 format string. %d는 int, %s는 string, %f/%g는 float, 오른쪽에 튜플.

text = “%d little pigs come out or I’ll %s and %s and %s” % (3, ‘huff’, ‘puff’, ‘blow down’)

너무 길면 전체 expression을 괄호로 싸면 된다.

text = (“%d little pigs come out or I’ll %s and %s and %s” %
    (3, ‘huff’, ‘puff’, ‘blow down’))

unistring.encode()와 unicode로 encoding 변환.

s = unistring.encode(‘utf-8’)
t = unicode(s, ‘utf-8’)
t == unistring

if / elif/ else. “zero” 값들(None, 0, “”, ”, [], {}, False)은 false, True/False로 boolean 값, and, or, not 사용. ()로 expression 을 감싸지 않는다.

* Lists

= 을 사용하면 그냥 reference.
‘+’ 를 사용해 list를 합칠 수 있다.

for와 in 으로 iteration

squares = [1, 4, 9, 16]
sum = 0
for num in squares:
    sum += num
print sum ## 30

in 은 독립적으로 어떤 원소가 list(또는 다른 collection)에 있는지 테스트 할 수 있다.

list = [‘larry’, ‘curly’, ‘moe’]
if ‘curly’ in list:
    print ‘yay’

range(n)은 0, 1, 2, …, n-1 까지의 숫자를 리턴. range(a, b) 는 a, a+1, a+2, …, b-1 까지를 리턴.

for i in range(100):
    print i

xrange()는 전체 리스트를 만드는 과정을 없애 성능 상 좋다.

while

i = 0
while i < len(a):
    print a[i]
    i = i + 3

list.append(elem): 리스트를 수정하여 가장 뒤에 elem 추가. 리턴하지 않는다.
list.insert(index, elem): index에 elem을 추가. 리턴하지 않는다.
list.extend(list2): list2의 원소들을 list에 추가. 리턴하지 않는다.
list.index(elem): elem이 있으면 index 리턴, 없으면 ValueError를 발생. ValueError 없이 확인하려면 in 을 사용.
list.remove(elem): 첫번째 elem을 제거, 없으면 ValueError. 리턴하지 않는다.
list.sort(): list를 sort. 리턴하지 않는다. sorted()를 더 자주 사용.
list.reverse(): list를 역순으로 변경. 리턴하지 않는다.
list.pop(index): index의 원소를 제거하고 리턴. index를 생략하면 가장 끝의 원소를 리턴(append()와 반대)

* Sorting

sorted()를 사용. reverse=True를 전달하면 역순. Case sensitive하다.

strs = [‘aa’, ‘BB’, ‘zz’, ‘CC’]
print sorted(strs) ## [‘BB’, ‘CC’, ‘aa’, ‘zz’] 
print sorted(strs, reverse=True) ## [‘zz’, ‘aa’, ‘CC’, ‘BB’]

key로 함수를 전달하면 해당 함수를 key로 정렬. key=len, key=str.lower 하면 대소문자 동일하게 취급하여 정렬.

print sorted(strs, key=str.lower) ## [‘aa’, ‘BB’, ‘CC’, ‘zz’]

key로 custom 함수 전달 가능

def MyFn(s):
    return s[-1]
print sorted(strs, key=MyFn)

cmp=cmpFn 선택 인자를 전달할 수도 있음. 내장 함수는 cmp(a, b)로 -/0/+ 로 순서를 리턴

Tuple은 struct와 비슷한 역할. 변경 불가능, 크기가 변하지 않음. () 를 통해 만듦. 크기가 1인 튜플은 ( 1, ) 처럼 , 을 넣어 만듦.

변수 할당에 사용 가능. 반환값이 여러 값을 가진 경우도 사용 가능
(x, y, z) = (42, 13, “Hike”)
(err_string, err_code) = foo()

[ _expr_ for var in list ] 형태로 원하는 형태의 리스트 생성 가능.

fruits = [‘apple’, ‘cherry’, ‘banana’, ‘lemon’]
afruits = [ s.upper() for s in fruits if ‘a’ in s ] ## [‘APPLE’, ‘BANANA’]

* Dictionaries and Files

dict = {}
dict[‘a’] = ‘alpha’
dict[‘g’] = ‘gamma’
dict[‘o’] = ‘omega’

print dict[‘a’] ## ‘alpha’
dict[‘a’] = 6
‘a’ in dict ## True
## print dict[‘z’] ## Throws KeyError
if ‘z’ in dict: print dict[‘z’] ## KeyError를 피한다.
print dict.get(‘z’) ## None

dict.get(key, not-found) 형태로 키가 없을 경우 not-found 로 설정한 값을 리턴하도록 할 수도 있다.

dict.keys(): key 리스트
dict.values(): value 리스트
dict.items(): (key, value) 튜플의 리스트

for k, v in dict.items(): print k, ‘>’, v

iterkeys(), itervalues(), iteritems()는 전체 리스트를 만들지 않아 성능 상 좋다.

hash = {}
hash[‘word’] = ‘garfield’
hash[‘count’] = 42
s = ‘I want %(count)d copies of %(word)s’ % hash # ‘I want 42 copies of garfield’

del 로 변수, list 원소, dict key/value를 지울 수 있다.

Files open(), close(). open 시 ‘rU’를 사용하면 줄바꿈을 ‘\n’으로 변형하여 준다.

f = open(‘foo.txt’,’rU’)
for line in f: ## 파일을 한 줄씩 방문
    print line, ## line 끝에 이미 줄바꿈이 포함되어 있으므로 print가 줄바꿈하지 않도록 한다.
f.close()

f.readlines()는 전체를 메모리에 올리고 줄들의 list를 리턴, read()는 전체 파일을 하나의 string으로.

파일에 쓰려면, f.write(string). print를 사용하려면, print >> f, string. python 3에서는 print(string, file=f)

codes는 unicode를 읽을 때 사용 가능

import codecs
f = codecs.open(‘foo.txt’, ‘rU’, ‘utf-8’)
for line in f: # line은 unicode string이 됨.

* Regular expression

import re
str = ‘an example word:cat!!’
match = re.search(r’word:\w\w\w’, str)
if match:
    print ‘검색 성공’, match.group() ## 발견 word:cat
else
    print ‘검색 실패’

패턴 스트링은 항상 r로 시작.

a, X, 9: 있는 그대로의 문자를 매치
.: 아무 문자 하나를 매치. \n 은 제외
\w: 하나의 word에 쓰이는 문자 하나를 매치(단어가 아님). a-z, A-Z, 0-9, _ [a-zA-Z0-9_]를 매치.
\W: non-word에 쓰이는 문자 하나를 매치
\b: word와 non-word의 경계
\s: 하나의 whitespace 문자[ \n\r\t\f]를 매치
\S: whitespace 이외의 문자를 매치
\d: 숫자 [0-9]
^: 시작
$: 끝
\를 붙여 위의 것들을 그저 문자로 사용 가능

+: 왼쪽 패턴 1개 이상.
*: 왼쪽 패턴 0개 이상.
?: 왼쪽 패턴 0개 혹은 1개
+와 *는 가장 왼쪽의 것을 찾고, greedy 하다. 

r'[\w.-]+@[\w.-]+’ 로 @ 주위에 ‘.’와 ‘-‘도 매치하도록 할 수 있다. -가 구간을 매치하지 않도록 하려면 가장 마지막에 넣는다.
[] 안의 내용을 ^로 시작하면 집합을 뒤집는다. [^ab]는 ‘a’와 ‘b’를 제외한 모든 문자를 뜻한다.

패턴 안에 ( )를 넣으면 그룹으로 구분할 수 있게 해준다.

str = ‘purple alice-b@google.com monkey dishwasher’
match = re.search(r'([\w.-]+)@([\w.-]+)’, str)
if match
    print match.group() ## ‘alice-b@google.com’
    print match.group(1) ## ‘alice-b’
    print match.group(2) ## ‘google.com’

findall(): 모든 패턴에 해당하는 string 리스트를 리턴

f = open(‘text.txt’, ‘r’)
strings = re.findall(r’some pattern’, f.read())

findall 에 ( )를 넣으면 그룹에 해당하는 튜플 리스트를 만든다.

str = ‘purple alice@google.com, blah monkey bob@abc.com blah dishwasher’
tuples = re.findall(r'(\w\.-]+)@([\w\.-]+)’, str)
print tuples ## [(‘alice’, ‘google.com’), (‘bob’, ‘abc.com’)]
for tuple in tuples:
    print tuple[0] ## username
    print tuple[1] ## host

re.search(pat, str, re.IGNORECASE) 처럼 추가 옵션 가능
IGNORECASE: 대소문자 구별하지 않음
DOTALL: 마침표 . 이 newline을 매치하도록 한다. 보통은 newline을 제외한 모든것들을 매치.
MULTILINE: 여러줄로 이루어진 string에서 ^와 $가 줄의 시작과 끝을 매치하도록 한다. 보통은 ^ $는 전체 스트링의 시작과 끝을 매치한다.

정규 표현식의 확장으로 .*? 나 .+?처럼 ?를 끝에 더해서 greedy 하지 않게 변경할 수 있다.

str = ‘<b>foo</b> and <i>so on</i>’
match = re.search(r'(<.*>)’, str)
if match:
    print match.group() ##'<b>foo</b> and <i>so on</i>’
match = re.search(r'(<.*?>)’, str)
if match:
    print match.group() ## ‘<b>’

re.sub(pat, replacement, str) 은 str에서 pat과 매치되는 모든 스트링들을 찾아 replacement로 치환한다. replacement 스트링은 \1, \2 를 이용하여 group(1), group(2)를 표현할 수 있다.

str = ‘purple alice@google.com, blah monkey bob@abc.com blah dishwasher’
print re.sub(r'([\w\.-]+)@([\w\.-]+)’, r’\1@yo-yo-dyne.com’, str)
# purple alice@yo-yo-dyne.com, blah monkey bob@yo-yo-dyne.com blah dishwasher

* Utilities

os 모듈
filenames = os.listdir(dir): dir에 있는 .과 ..을 제외한 파일이름들의 리스트, 절대경로가 아님.
os.path.join(dir, filename): filename과 dir을 합쳐서 path를 만든다.
os.path.abspath(path): path를 받아서 절대 경로를 리턴
os.path.dirname(path), os.path.basename(path): dir/foo/bar.html을 받아서 dirname ‘dir/foo’와 basename’bar.html’을 리턴
os.path.exists(path): path 가 존재하면 True를 리턴
os.mkdir(dir_path): dir 하나를 만든다.
os.makedirs(dir_path): dir_path를 만들기 위한 모든 디렉토리들을 만든다.
shutil.copy(source-path, dest-path): 파일을 복사한다. 복사될 디렉토리가 존재해야 한다.

commands 모듈: 외부 명령을 실행하고 결과물을 얻어옴.
(status, output) = commands.getstatusoutput(cmd): cmd를 실행하고 exit할 때까지 기다려서,
status int값과 output text를 tuple로 리턴한다. stdout과 stderr이 하나의 출력물로 합쳐져서 나타난다.
output = commands.getoutput(cmd): 위와 동일, status값을 받지 않는다는 것만 다름.
commands.getstatus() 라는 함수는 사용하지 말아라.
sub-process에 대한 더 많은 제어권을 원하면 “popen2” 모듈을 보라.
os.system(cmd): cmd의 결과물을 여러분 코드의 output으로 출력하고, error 코드를 리턴.

try/except. ‘except IOError, e:’ 의 형태로 exception 객체에 대한 포인터를 얻을 수 있다.

try:
  f = open(filename, ‘rU’)
  text = f.read()
  f.close()
except IOError:
  sys.stderr.write(‘problem reading:’ + filename)

urllib 모듈: url을 마치 file처럼 읽을 수 있게 한다. urlparse 모듈은 url을 분해하거나 합치는 기능을 제공
ufile = urllib.urlopen(url): url에 대한 file 같은 객체를 리턴
text = ufile.read(): 파일처럼 읽음. readlines()도 사용 가능
info = ufile.info(): 요청에 대한 meta 정보를 리턴. info.gettype() 으로 ‘text/html’ 같은 mime 타입을 얻어 옴.
baseurl = ufile.geturl(): 요청에 대한 “base” url을 얻어옴. redirect로 인해 open할 때 사용한 url과 다를 수 있다.
urllib.urlretrieve(url, filename): url의 데이터를 다운받아 filename의 file로 저장한다.
urlparse.urljoin(baseurl, url): full url을 만든다.

def wget2(url):
  try:
    ufile.urllib.urlopen(url)
    if ufile.info().gettype() == ‘text/html’:
      print ufile.read()
  except IOError:
    prit ‘problem reading url:’, url

[Linux:Kernel] Documentation/io-mapping.txt

이 문서의 저작권은 GPL 라이센스를 따릅니다(This document is released under GPL license).
Documentation/io-mapping.txt
번역: 양정석 <dasomoli@gmailREMOVETHIS.com>
linux/io-mapping.h 안의 io_mapping 함수들은 CPU에 I/O 디바이스들의 작은 영역을
효율적으로 맵핑하는 추상화를 제공합니다. 애초의 용도는 ioremap_wc가 커널 주소
영역을 너무 많이 소비할 때 처럼 CPU에 전체 영역을 정적으로 맵핑할 수 없을 때,
32비트 프로세서들에서 큰 그래픽 영역을 제공하기 위함입니다.
맵핑 객체는 드라이버 초기화 중에 다음을 사용하여 생성합니다
        struct io_mapping *io_mapping_create_wc(unsigned long base,
                                                unsigned long size)
                ‘base’는 맵핑 가능하게 만들어 질 영역의 버스 주소인 반면,
                ‘size’는 얼마나 크게 영역을 맵핑할 것인지를 나타냅니다.
                둘다 바이트 수 입니다.
                이 _wc 변형은 io_mapping_map_atomic_wc나 io_mapping_map_wc로만
                사용할 수 있는 맵핑을 제공합니다.
이 맵핑 객체로, 개별 페이지들이 자동적으로, 혹은 아니게 필요한 스케줄링 환경에
따라 맵핑될 수 있습니다. 물론, 어토믹 맵핑은 더 효율적입니다:
        void *io_mapping_map_atomic_wc(struct io_mapping *mapping,
                                       unsigned long offset)
                ‘offset’은 정의된 맵핑 영역 안에서의 오프셋입니다. 생성 함수
                에서 지정된 영역을 넘어서서 주소를 접근하는 것은 정의되지
                않은 결과를 불러옵니다. 페이지 정렬되지 않은 오프셋을
                사용하는 것도 정의되지 않은 결과를 불러옵니다. 반환 값은
                CPU 주소 공간 안의 한 페이지를 가리킵니다.
                이 _wc 변형은 페이지로의 write-combining 맵핑을 반환하고,
                io_mapping_create_wc에 의해 생성된 맵핑에만 사용가능합니다.
                태스크가 이 맵핑된 페이지를 잡고 있는 동안 슬립하지 않음을
                알아두세요.
        void io_mapping_unmap_atomic(void *vaddr)
                ‘vaddr’은 반드시 마지막 io_mapping_map_atomic_wc 호출에
                의해 반환된 값이어야 합니다. 이것은 지정된 페이지를 맵핑
                해제하고 그 태스크가 다시 한번 잠들 수 있게 합니다.
여러분이 그 락을 잡은 동안 슬립해야할 필요가 있다면, 극히 더 느리긴 하지만,
어토믹이 아닌 변형을 사용할 수 있습니다.
        void *io_mapping_map_wc(struct io_mapping *mapping,
                                unsigned long offset)
                이것은 태스크가 맵핑된 페이지를 잡고 있는 동안 슬립할 수 있다는
                것을 제외하면 io_mapping_map_atomic_wc와 같이 동작합니다.
        void io_mapping_unmap(void *vaddr)
                이것은 io_mapping_map_wc로 매핑된 페이지들이 사용되는 것을
                제외하면 io_mapping_unmap_atomic과 같이 동작합니다.
드라이버에 가까운 시간에, io_mapping 객체는 반드시 해제되어야만 합니다:
        void io_mapping_free(struct io_mapping *mapping)
현재 구현:
이들 함수의 초기 구현은 이미 구현된 맵핑 메카니즘을 사용해서 오직 추상 계층만
제공하고 새로운 기능은 없습니다.
64비트 프로세서에서 io_mapping_create_wc는 자원으로의 영구적으로 커널이 볼 수
있는 맵핑을 생성하는 전체 영역을 위해서 ioremap_wc를 호출합니다. 그 map_atomic과
map 함수들은 ioremap_wc에 의해 반환되는 가상 주소의 기준점으로부터의 요청된
오프셋을 더합니다.
HIGHMEM이 정의된 32비트 프로세서에서는 io_mappinc_map_atomic_wc가
kmap_atomic_pfn을 지정된 페이지를 어토믹하게 맵핑하는데 사용됩니다;
kmap_atimic_pfn은 디바이스 페이지와 사용될 것이라고 정말 여겨지지 않았습니다만,
이 용도를 위한 효율적인 맵핑을 제공합니다.
HIGHMEM 정의가 없는 32비트 프로세서에서는 io_mapping_map_atomic_wc와
io_mapping_map_wc 모두 새로운 맵핑을 모든 프로세서에 알리기 위해서 IPI를 수행하는
극악하게 비효율적인 함수인 ioremap_wc를 사용합니다. 이것은 극적인 성능 저하를
가져옵니다.

[Linux:Kernel] Documentation/printk-formats.txt

이 문서의 저작권은 GPL 라이센스를 따릅니다(This document is released under GPL license).

변수가 아래 타입이라면,           printk형식 지시자를 사용하세요:
———————————————————
                int                     %d 나 %x
                unsigned int            %u 나 %x
                long                    %ld 나 %lx
                unsigned long           %lu 나 %lx
                long long               %lld 나 %llx
                unsigned long long      %llu 나 %llx
                size_t                  %zu 나 %zx
                ssize_t                 %zd 나 %zx

가공되지 않은 포인터 값은 %p로 출력되는 것이 ‘좋습니다’. 커널은 포인터
형식을 위해 다음의 확장된 형식 지시자를 지원합니다:

심볼/함수 포인터:

        %pF     versatile_init+0x0/0x110
        %pf     versatile_init
        %pS     versatile_init+0x0/0x110
        %pSR    versatile_init+0x9/0x110
                (__builtin_extract_return_addr() 변환으로)
        %ps     versatile_init
        %pB     prev_fn_of_versatile_init+0x88/0x88

        심볼과 함수 포인터를 출력하기 위해서, (‘S’)로 오프셋과 함께, 혹은 (‘s’)로
        오프셋 없이, ‘S’와 ‘s’ 지시자들로 심볼 이름을 나타냅니다. KALLSYMS 없는
        커널 상에서 사용되면, 심볼 주소가 대신 출력됩니다.

        ‘B’ 지시자는 오프셋과 함께 심볼 이름을 나타내고, 스택 트레이스를 출력할
        때 사용되어야 합니다. 이 지시자는 Tail-Call이 사용되고, noreturn GCC 속성으로
        표시되었을 때 일어날 컴파일러 최적화의 효과를 고려하게 합니다.

        ia64, ppc64, 그리고 parisc64 아키텍처에서 함수 포인터들은 실제로는
        가장 먼저 풀어야 할 함수 기술자들입니다. ‘F’와 ‘f’ 지시자는 이 해결을
        수행하여 ‘S’와 ‘s’ 지시자와 같은 기능을 제공합니다.

커널 포인터:

        %pK     0x01234567 나 0x0123456789abcdef

        권한이 없는 사용자에게 가려져야 할 커널 포인터를 출력하기 위해서 사용.
        %pK의 동작은 kptr_restrict sysctl에 의존적입니다.
        – 더 자세한 사항은 Documentation/sysctl/kernel.txt를 보세요.

구조체 자원:

        %pr     [mem 0x60000000-0x6fffffff flags 0x2200] or
                [mem 0x0000000060000000-0x000000006fffffff flags 0x2200]
        %pR     [mem 0x60000000-0x6fffffff pref] or
                [mem 0x0000000060000000-0x000000006fffffff pref]

        구조체 자원을 출력하기 위해 사용. ‘R’과 ‘r’ 지시자는 디코딩된 플래그
        멤버들이 있게(‘R’) 혹은 없게(‘r’) 자원을 출력합니다.

phys_addr_t 타입의 물리 주소:

        %pa[p]  0x01234567 나 0x0123456789abcdef

        CPU 데이터 경로의 너비와 상관없이, 빌드 옵션에 의해서 다양하게 될 수 있는
        phys_addr_t 타입(그리고 resource_size_t 같은 그 변형)의 출력을 위해서 사용.
        참조로 넘김.
        

dma_addr_t 타입의 DMA 주소:

        %pad    0x01234567 나 0x0123456789abcdef

        CPU 데이터 경로의 너비와 상관없이, 빌드 옵션에 의해서 다양하게 될 수 있는
        dma_addr_t 타입의 출력을 위해서 사용. 참조로 넘김.

16진수 문자열의 비가공 버퍼:
        %*ph    00 01 02  …  3f
        %*phC   00:01:02: … :3f
        %*phD   00-01-02- … -3f
        %*phN   000102 … 3f

        명확한 구분자로 된 16진수 문자열로 작은 버퍼(64 바이트 길이까지의)를
        출력할 때 사용. 더 큰 버퍼는 print_hex_dump()의 사용을 고려하세요.

MAC/FDDI 주소:

        %pM     00:01:02:03:04:05
        %pMR    05:04:03:02:01:00
        %pMF    00-01-02-03-04-05
        %pm     000102030405
        %pmR    050403020100

        16진수 표기로 된 6바이트 MAC/FDDI 주소를 출력할 때 사용. ‘M’과
        ‘m’ 지시자는 바이트 구분자가 있게(‘M’) 혹은 없게(‘m’) 주소를 출력합니다.
        기본 바이트 구분자는 콜론(‘:’)입니다.

        FDDI 주소들이 쓰이는 곳에서 ‘F’ 지시자는 기본 구분자 대신에 대시(‘-‘)
        구분자를 사용하기 위해서 ‘M’ 지시자 이후에 사용될 수 있습니다.

        블루투스 주소를 위해서 리틀 엔디언으로 된 블루투스 주소의 보이는 형태의
        거꾸로 된 바이트 순서 맞춤을 사용하기 위해서 ‘R’ 지시자가 쓰이면 좋습니다.

IPv4 주소:

        %pI4    1.2.3.4
        %pi4    001.002.003.004
        %p[Ii]4[hnbl]

        IPv4의 점으로 구분된 10진수 주소를 출력할 때 사용. ‘I4’와 ‘i4’ 지시자는
        앞 쪽 0들이 있게(‘i4’) 혹은 없게(‘I4’) 주소를 출력합니다.

        덧붙는 ‘h’, ‘n’, ‘b’, 그리고 ‘l’ 지사자들은 각각 호스트, 네트워크,
        빅 또는    리틀 엔디언 주소를 나타내는데 사용됩니다. 아무 지시자가 없다면,
        기본 네트워크/빅 엔디언 오더가 사용됩니다.

IPv6 주소:

        %pI6    0001:0002:0003:0004:0005:0006:0007:0008
        %pi6    00010002000300040005000600070008
        %pI6c   1:2:3:4:5:6:7:8

        IPv6 네트워크-오더 16비트 16진수 주소를 출력할 때 사용. ‘I6’와 ‘i6’
        지시자는 콜론 구분자가 있게(‘I6’) 혹은 없게(‘i6’) 주소를 출력합니다.
        앞 쪽의 0들은 항상 사용됩니다.
        
        덧붙는 ‘c’ 지시자는 ‘I’ 지시자와 함께 http://tools.ietf.org/html/rfc5952에
        쓰여 있는 압축된 IPv6 주소를 출력하는데 사용할 수 있습니다.

IPv4/IPv6 주소 (일반적인, 포트와 함께, flowinfo, 범위):

        %pIS    1.2.3.4         나 0001:0002:0003:0004:0005:0006:0007:0008
        %piS    001.002.003.004 나 00010002000300040005000600070008
        %pISc   1.2.3.4         나 1:2:3:4:5:6:7:8
        %pISpc  1.2.3.4:12345   나 [1:2:3:4:5:6:7:8]:12345
        %p[Ii]S[pfschnbl]

        그 타입이 AF_INET인지 AF_INET6인지 구분할 필요 없이 IP 주소를 줄력할 때
        사용. ‘IS’ 또는 ‘iS’를 통해 지정된 유효한 ‘struct socketaddr’로의
        포인터는 이 형식 지시자에게 넘겨질 수 있습니다.

        덧붙는 ‘p’, ‘f’, 그리고 ‘s’ 지시자는 포트(IPv4, IPv6), flowinfo(IPv6),
        범위(IPv6)를 지정하는데 사용됩니다. 포트는 “:” 접두어를 갖고, flowinfo는
        ‘/’, 그리고 스코프는 ‘%’를 갖고, 각각 실제 값이 뒤 따릅니다.

        IPv6 주소의 경우에 http://tools.ietf.org/html/rfc5952에서 기술된
        압축된 IPv6 주소는 지시자 ‘c’를 사용하면 사용됩니다. IPv6 주소는
        추가적인 지시자        ‘p’, ‘f’, ‘s’의 경우에
        https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07 에
        제안된 것처럼 ‘[‘, ‘]’로 둘러싸입니다.

        IPv4 주소의 경우, 덧붙는 ‘h’, ‘n’, ‘b’, 그리고 ‘l’ 지시자가 잘 사용될 수
        있고, IPv6 주소의 경우에는 무시됩니다.

        더 많은 예제:

        %pISfc          1.2.3.4         나 [1:2:3:4:5:6:7:8]/123456789
        %pISsc          1.2.3.4         나 [1:2:3:4:5:6:7:8]%1234567890
        %pISpfc         1.2.3.4:12345   나 [1:2:3:4:5:6:7:8]:12345/123456789

UUID/GUID 주소:

        %pUb    00010203-0405-0607-0809-0a0b0c0d0e0f
        %pUB    00010203-0405-0607-0809-0A0B0C0D0E0F
        %pUl    03020100-0504-0706-0809-0a0b0c0e0e0f
        %pUL    03020100-0504-0706-0809-0A0B0C0E0E0F

        16바이트 UUID/GUID 주소를 출력하기 위해 사용. 덧붙는 ‘l’, ‘L’, ‘b’,
        그리고, ‘B’ 지시자는 리틀 엔디언 오더를 소문자(‘l’) 또는 대문자(‘L’)
        16진수 문자로 – 그리고 빅 엔디언 오더를 소문자(‘b’) 또는 대문자(‘B’)
        16진수 문자로 표시하는데 사용됩니다.

        아무 추가 지시자도 붙지 않으면 기본으로 리틀 엔디언 오더에 소문자로
        출력될 것입니다.

dentry 이름:
        %pd{,2,3,4}
        %pD{,2,3,4}

        dentry 이름을 출력하는데 사용; 만약 우리가 d_move()로 경쟁 상태를 만들면,
        그 이름은 오래된 것과 새 것이 섞일 것입니다. 웁스를 일으키지 않습니다.
        %pd dentry는 우리가 사용하곤 했던 %s dentry->d_name.name와 같지만 더
        안전합니다. %pd<n>은 마지막 n 컴포넌트를 출력합니다. %pD는 struct file에
        같은 동작을 합니다.

struct va_format:

        %pV

        struct va_fotmat 구조체를 출력하는데 사용. 이들은 다음과 같은 va_list와
        형식 문자열을 포함합니다:

        struct va_format {
                const char *fmt;
                va_list *va;
        };

        형식 문자열이나 va_list 인자들의 정확성을 확인하기 위한 어떤 메카니즘 없이
        이 기능을 사용하지 마세요.

u64는 %llu/&llx로 ‘출력해야’ 합니다:

        printk(“%llu”, u64_var);

s64는 %lld/%llx로 ‘출력해야’ 합니다:

        printk(“%lld”, s64_var);

Example:
<type>이 그 크기의 설정 옵션(예를 들면, sector_t, blkcnt_t)이나 그 크기의 아키텍처
(예를 들면, tcflag_t)에 의존적이라면, 가능한 가장 큰 타입의 형식 지시자를 쓰고
명시적으로 형을 변환하세요.
예제:

        printk(“test: sector number/total blocks: %llu/%llu\n”,
                (unsigned long long)sector, (unsigned long long)blockcount);

다시 알림: sizeof() 결과는 size_t 타입입니다.

여러분의 협력과 주의에 감사합니다.
By Randy Dunlap <rdunlap@infradead.org> and
Andrew Murray <amurray@mpc-data.co.uk>
그리고 우리말 번역에 양정석 <dasomoli@gmail.com>

[ARM] Cortex-A 페이징

ARM Cortex-A 페이징에 대해서 잘 적혀있는 글 발견!
설명하면서 쓴 단어의 정의들도 정확하다. 설명도 간략하면서 쉽게 되어 있다.

http://kth3321.blogspot.kr/search?q=ARM+Cortex-A+%ED%8E%98%EC%9D%B4%EC%A7%95 

아참, 본문의 내용 중 예제에 Offset에 따른 물리 주소를 그저 Offset을 더하는 것으로 설명되어져 있는데, 이 부분은 잘못된 것으로 보인다. 실제로는 32비트 주소 값 혹은 pgd/pte 의 주소+a를 갖고 있으므로 Base + Offset * 4(=32 bits) 의 물리 주소를 참조한다.

[Linux:Kernel] AArch64 리눅스의 메모리 배치

이 문서의 저작권은 GPL 라이센스를 따릅니다(This document is released under the GPL license).

Documentation/arm64/memory.txt

     AArch64 리눅스의 메모리 배치
     ============================

Author: Catalin Marinas <catalin.marinas@arm.com>
번역  : 양정석 <dasomoli@gmailREMOVETHIS.com>
Date  : 20 February 2012

이 문서는 AArch64 리눅스 커널이 사용하는 가상 메모리 배치를 설명합니다.
이 아키텍처는 4KB 페이지 크기의 4단계 변환 테이블과 64KB 페이지 크기의
3단계 변환 테이블을 허용합니다.

AArch64 리눅스는 유저와 커널 양 쪽 모두 39비트 (512GB) 가상 주소를 허용하는
4KB 페이지 설정의 3단계 변환 테이블을 사용합니다. 64KB 페이지는 오직
2단계 변환 테이블이 사용되지만 메모리 배치는 같습니다.

유저 주소는 63:39 비트가 0으로 셋팅되는 반면, 커널 주소는 같은 곳의 비트에
1로 셋팅됩니다. TTBRx 선택은 가상 주소의 비트 63에 의해 결정됩니다.
swapper_pg_dir은 오직 커널 (전역) 맵핑만 포합하는 반면,
유저 pgd는 오직 유저 (비전역) 맵핑만 포함합니다. swapper_pgd_dir 주소는
TTBR1으로 쓰여지고, TTBR0로 절대 쓰여지지 않습니다.


4KB 페이지의 AArch64 리눅스 메모리 배치:

시작 크기 용도
———————————————————————–
0000000000000000 0000007fffffffff 512GB 유저

ffffff8000000000 ffffffbbfffeffff ~240GB vmalloc

ffffffbbffff0000 ffffffbbffffffff  64KB [guard page]

ffffffbc00000000 ffffffbdffffffff   8GB vmemmap

ffffffbe00000000 ffffffbffbbfffff  ~8GB [guard, 추후 vmmemap]

ffffffbffa000000 ffffffbffaffffff  16MB PCI I/O 공간

ffffffbffb000000 ffffffbffbbfffff  12MB [guard]

ffffffbffbc00000 ffffffbffbdfffff   2MB 고정 맵핑

ffffffbffbe00000 ffffffbffbffffff   2MB [guard]

ffffffbffc000000 ffffffbfffffffff  64MB 모듈들

ffffffc000000000 ffffffffffffffff 256GB 커널 논리 메모리 맵


64KB 페이지의 AArch64 리눅스 메모리 배치:

시작 크기 용도
———————————————————————–
0000000000000000 000003ffffffffff   4TB 유저

fffffc0000000000 fffffdfbfffeffff  ~2TB vmalloc

fffffdfbffff0000 fffffdfbffffffff  64KB [guard page]

fffffdfc00000000 fffffdfdffffffff   8GB vmemmap

fffffdfe00000000 fffffdfffbbfffff  ~8GB [guard, 추후 vmmemap]

fffffdfffa000000 fffffdfffaffffff  16MB PCI I/O 공간

fffffdfffb000000 fffffdfffbbfffff  12MB [guard]

fffffdfffbc00000 fffffdfffbdfffff   2MB 고정 맵핑

fffffdfffbe00000 fffffdfffbffffff   2MB [guard]

fffffdfffc000000 fffffdffffffffff  64MB 모듈들

fffffe0000000000 ffffffffffffffff   2TB 커널 논리 메모리 맵


4KB 페이지의 변환 테이블 탐색:

+——–+——–+——–+——–+——–+——–+——–+——–+
|63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
+——–+——–+——–+——–+——–+——–+——–+——–+
 |                 |         |         |         |         |
 |                 |         |         |         |         v
 |                 |         |         |         |   [11:0]  페이지 내의 오프셋
 |                 |         |         |         +-> [20:12] L3 인덱스
 |                 |         |         +———–> [29:21] L2 인덱스
 |                 |         +———————> [38:30] L1 인덱스
 |                 +——————————-> [47:39] L0 인덱스 (미사용)
 +————————————————-> [63] TTBR0/1


64KB 페이지의 변환 테이블 탐색:

+——–+——–+——–+——–+——–+——–+——–+——–+
|63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
+——–+——–+——–+——–+——–+——–+——–+——–+
 |                 |    |               |              |
 |                 |    |               |              v
 |                 |    |               |            [15:0]  페이지 내의 오프셋
 |                 |    |               +———-> [28:16] L3 인덱스
 |                 |    +————————–> [41:29] L2 인덱스 (38:29 만 사용)
 |                 +——————————-> [47:42] L1 인덱스 (미사용)
 +————————————————-> [63] TTBR0/1

KVM을 사용할 때, 하이퍼바이저는 커널 페이지를 EL2에서 커널 VA로부터 고정된
오프셋(커널 VA의 상위 24비트를 0으로 셋팅한)에 맵핑합니다:

시작 크기 용도
———————————————————————–
0000004000000000 0000007fffffffff 256GB HYP 내에서 맵핑된 커널 객체

[Linux:Kernel] AArch64 리눅스 부팅(AArch64 Linux Booting)

이 문서의 저작권은 GPL 라이센스를 따릅니다(This document is released under the GPL license).

Documentation/arm64/booting.txt

AArch64 리눅스 부팅

===================

Author: Will Deacon <will.deacon@arm.com>
번역  : 양정석 <dasomoli@gmailREMOVETHIS.com>
Date  : 07 September 2012

이 문서는 Russell King의 ARM 부팅 문서에 기초하고 AArch64 리눅스 커널의
모든 공개 릴리즈와 연관됩니다.

AArch64 예외 모델은 몇 개의 예외 단계(EL0 – EL3)으로, 그 중 EL0와 EL1은
시큐어와 논-시큐어 구성을 가지는 것으로 구성되어 있습니다. EL2는
하이퍼바이저 단계이고 논-시큐어 모드에서만 존재합니다. EL3는 가장 높은
단계이고, 시큐어 모드에서만 존재합니다.

이 문서의 목적에 따라, 우리는 ‘부트 로더’ 용어를 간단히 리눅스 커널로
제어를 넘기기 전에 CPU(들) 상에서 실행되는 모든 소프트웨어로 정의하여
사용할 것입니다. 이것은 시큐어 모니터와 하이퍼바이저 코드를 포함할 것이고,
또는 최소 부팅 환경을 준비하기 위한 한 줌의 명령들이 될 수도 있습니다.

기본적으로, 부트 로더는 다음을 (최소한) 제공해야 합니다:

1. RAM을 셋업하고 초기화
2. 디바이스 트리를 셋업
3. 커널 이미지를 압축 해제
4. 커널 이미지를 호출
1. RAM을 셋업하고 초기화
————————

요구 사항: 필수

부트 로더는 커널이 시스템 상의 임시 데이터 저장 공간으로 사용할 모든
RAM을 찾아서 초기화할 것으로 여겨집니다. 이는 머신 의존적인 방법으로
수행됩니다. (자동으로 모든 RAM의 크기를 재고 위치시키는데 내부
알고리즘을 사용하거나, 머신 안의 RAM에 대한 지식을 사용하거나, 또는
부트 로더 설계자가 맞춰 보는 다른 방법을 사용할 수도 있습니다.)
2. 디바이스 트리를 셋업
———————–

요구 사항: 필수

디바이스 트리 조각 (dtb)는 8 바이트 경계로 커널 이미지의 시작으로부터
512 메가 바이트 내에, 그리고 2 바이트 경계에 걸치지 않도록 위치해야만
합니다. 이것은 커널이 초기 페이지 내이블 내의 하나의 섹션 맵핑을 사용해서
조각을 맵핑할 수 있도록 해줍니다.
3. 커널 이미지를 압축 해제
————————–

요구 사항: 선택

AArch64 커널은 현재 압축 해제기를 제공하지 않고, 그래서 압축된 Image 타겟
(예를 들면, Image.gz)이 사용된다면 부트 로더에 의한 압축 해제
(gzip, 기타 등)를 요구합니다. 이 요구 사항을 구현하지 않은 부트로더들을
위해서 압축되지 않은 Image 타겟이 현재 대신 이용 가능합니다.
4. 커널 이미지를 호출
———————

요구 사항: 필수

압축 해제된 커널 이미지는 다음과 같은 64바이트 헤더를 포함합니다:

  u32 code0;
/* 실행 가능 코드 */
  u32 code1; /* 실행 가능 코드 */
  u64 text_offset; /* 이미지 로딩 오프셋 */
  u64 res0 = 0; /* 여분으로 예약 */
  u64 res1 = 0; /* 여분으로 예약 */
  u64 res2 = 0; /* 여분으로 예약 */
  u64 res3 = 0; /* 여분으로 예약 */
  u64 res4 = 0; /* 여분으로 예약 */
  u32 magic = 0x644d5241; /* 매직 넘버, 리틀 엔디언, “ARM\x64” */
  u32 res5 = 0;       /* 여분으로 예약 */
헤더 설명:

– code0/code1 은 stext로의 뜀을 책임집니다.
– EFI를 통해 부팅할 때, code0/code1은 초기에 건너 뜁니다. res5는
  PE 헤더로의 offset이고, PE 헤더는 EFI 진입 포인트(efi_stub_entry)를
  가집니다. 그 코드 조각이 작업을 끝내면, 보통의 부팅 프로세스를 재개하기
  위해서 code0 로 점프합니다.
  
이미지는 시스템 RAM의 시작으로부터 지정된 오프셋(현재는 0x80000)에
위치하고, 거기서 호출되어야만 합니다. 시스템 RAM의 시작은 2MB로 정렬되어져
있어야 합니다.

커널로 점프하기 전에, 다음 조건을 만족해야만 합니다:

– 모든 DMA 가능 장치들을 중지시켜 메모리가 가짜 네트워크 패킷이나
  디스크 데이터로 인해 깨지지 않도록 하세요. 이것은 많은 디버깅 시간을
  절약시켜 줄 것입니다.
  
– 주요 CPU 일반-목적(general-purpose) 레지스터 셋팅
  x0 = 시스템 RAM 내의 디바이스 트리 조각(dtb)의 물리 주소
  x1 = 0 (차후 용도를 위해 예약)
  x2 = 0 (차후 용도를 위해 예약)
  x3 = 0 (차후 용도를 위해 예약)  
  
– CPU 모드
  모든 형태의 인터럽트는 PSTATE.DAIF(Debug, Serror, IRQ 그리고 FIQ)로
  마스킹되어져야 합니다.
  CPU는 EL2(가상화 확장에 접근하기 위해서 추천함) 또는 논-시큐어 EL1 에
  있어야 합니다.

– 캐시, MMU
  MMU는 반드시 꺼져야 합니다.
  명령 캐시는 켜지거나 꺼져 있을 수 있습니다.
  로딩된 커널 이미지에 해당하는 주소 범위는 PoC로 깨끗해야 합니다.
  시스템 캐시나 켜진 캐시와 연관된 다른 마스터들의 존재 안에서,
  이것은 보통, 셋/웨이 연산보다는 VA에 의한 캐시 관리를 필요로 합니다.
  VA 연산에 의한 구조화된 캐시 관리를 준수하는 시스템 캐시는 설정되어져야
  하고, 켜지게 될 것 입니다.
  VA 연산에 의한 구조화된 캐시 관리를 따르지 않는(권장하지 않음) 시스템
  캐시는 설정되고 꺼져야만 합니다.

– 구조화된 타이머
  CNTFRQ는 반드시 타이머 주기로 프로그램되어야 하고, CNTVOFF는 모든
  CPU들의 일관된 값으로 프로그램되어야 합니다. 만약 EL1에서 커널로
  진입한다면, CNTHCTL_EL2는 반드시 셋팅된 EL1PCTEN(비트 0)을 가져야 합니다.

– 연관성
  커널에 의해 부팅될 모든 CPU들은 커널로의 진입 상의 같은 연관 도메인의
  일부가 되어야 합니다. 이것은 각 CPU 상의 관리 연산의 수신을 켜는
  ‘구현에 따라 정의된’ 초기화를 요구할 것입니다.
  
– 시스템 레지스터
  커널이미지가 진입하는 그 예외 레벨에서 모든 쓰기 가능한 구조화된 시스템
  레지스터들은 ‘알려지지 않은’ 상태 내의 실행을 막기 위해서 더 높은 예외
  레벨에서 소프트웨어에 의해 초기화되어야만 합니다.

위에 쓰여진 CPU 모드, 캐시, MMU, 구조화된 타이머, 연관성과 시스템 레지스터들에
대한 요구사항은 모든 CPU에 적용됩니다. 모든 CPU는 같은 예외 레벨 안에서
커널로 진입해야 합니다.

부트로더는 각 CPU가 다음과 같은 관례로 커널로 진입할 것으로 생각합니다:

– 주 CPU는 커널 이미지의 첫 명령으로 직접 점프해야만 합니다. 이 CPU에 의해
  넘겨진 디바이스 트리 조각은 각 CPU 노드의 ‘enable-method’ 프로퍼티를
  포함해야만 합니다. 지원되는 enable-method 들은 아래에서 설명합니다.

  부트로더는 이들 디바이스 트리 프로퍼티를 생생하고 커널 진입보다 먼저
  조각 안에 그들을 끼워 넣을 것입니다.

– “spin-table” enable-method 의 CPU들은 그들의 cpu 노드 내에
  하나의 ‘cpu-release-addr’ 프로퍼티를 가져야 합니다. 이 프로퍼티는
  자연스럽게 정렬된 64비트의 0으로 초기화된 메모리 위치를 나타냅니다.

  이 CPU들은 예약된 영역 안에 포함되어야만 하는, 그들의 cpu-release-addr
  위치를 폴링하는 (디바이스 트리 안의 /memreserve/ 영역에 의해 커널로
  전달되는) 메모리의 예약된 영역 안의 커널 밖에서 돌아야 합니다.
  wfe 명령은 비지-루프(busy-loop)의 부하를 줄이기 위해서 추가될 것이고,
  sev는 주 CPU에 의해 일어날 것입니다. cpu-release-addr에 의해
  가리켜지는 위치를 읽는 것이 0이 아닌 값을 반환할 때, 그 CPU는 이 값으로
  점프해야 합니다. 그 값은 하나의 64비트 리틀 엔디언 값으로 쓰여질
  것이므로 CPU들은 읽은 값을 그리로 점프하기 전에 그들 원래의 엔디언으로
  변환해야 합니다.

– “psci” enable method의 CPU들은 커널의 밖(즉, memory 노드 안에 커널로
  기술된 메모리의 그 영역 밖, 또는 디바이스 트리 안의 /memreserve/ 영역에
  의해 커널로 기술된 메모리의 예약된 영역 안)에 남아 있어야 합니다.
  커널은 커널 내로 CPU들을 가져오기 위해서 ARM DEN 0022A
  (“Power State Coordination Interface System Software on ARM processors”)
  문서 안에 설명된 것처럼 CPU_ON 호출들을 일으킬 것입니다.
  
  디바이스 트리는 하나의 ‘psci’ 노드를
  Documentation/devicetree/bindings/arm/psci.txt 안에 설명된대로
  포함해야만 합니다.

– 두번째 CPU 일반-목적 레지스터 셋팅
  x0 = 0 (차후 용도를 위해 예약)
  x1 = 0 (차후 용도를 위해 예약)
  x2 = 0 (차후 용도를 위해 예약)
  x3 = 0 (차후 용도를 위해 예약)

[Android] “Running Android with low RAM” 의 Kernel Configuration

Except as noted, this content is licensed under Creative Commons Attribution 2.5. For details and restrictions, see the Content License.
 

원문: http://source.android.com/devices/low-ram.html
번역: 양정석<dasomoli@gmailREMOVETHIS.com>(근데 원래 혼자 보려던 거라 이상한 거 많음;;)

커널 설정


직접 회수(Direct reclaim)를 줄이기 위한 커널/ActivityManager 튜닝

직접 회수는 하나의 프로세스 또는 커널이 메모리의 한 페이지를 (직접 혹은 새로운 페이지 안의 폴트로 인해서) 할당하고자 하며, 커널이 모든 사용 가능한 자유 메모리를 사용하고 있을 때 일어납니다. 이것은 커널에게 하나의 페이지를 해제하는 동안 할당을 막도록 요구합니다. 결국 이것은 더티한 File-backed 페이지를 플러싱하기 위한 디스크 I/O나 lowmemorykiller가 프로세스 하나를 죽이기를 기다리는 것을 종종 요구합니다. 이것은 UI 스레드를 포함하는 어떤 스레드에 추가 I/O를 일으킬 수 있습니다.
직접 회수를 피하기 위해서 커널은 kswapd나 백그라운드 회수를 촉발시키는 워터마크를 가집니다. 이것은 페이지들을 해제하도록 시도해서 다음에 그를 할당하는 리얼 타임 스레드가 빨리 수행할 수 있도록 하는 하나의 스레드입니다.
백그라운드 회수를 촉발시키는 디폴트 임계값은 2GB 디바이스에서 2MB, 512MB 디바이스에서 636KB로, 상당히 낮습니다. 그리고 커널은 그저 수 MB의 메모리를 백그라운드 회수 시에 회수할 뿐입니다. 이것은 수 MB 이상을 빨리 할당하는 어떤 프로세스는 빨리 직접 회수를 치게 될 것이라는 것을 의미합니다.
새로운 커널에 튜닝 가능한 지원이 android-3.4 커널 브랜치에 패치 92189d47f66c67e5fd92eafaa287e153197a454f(“add extra free kbytes tunable”)로 추가됩니다. 이 패치를 디바이스의 커널로 체리픽하는 것은 ActivityManager가 커널에게 3개의 풀스크린 32 bpp 버퍼의 메모리를 자유롭게 유지하도록 할 것임을 이야기하는 것을 허용할 것입니다.
이들 임계값은 프레임워크 config.xml을 통해 설정될 수 있습니다.
<!– 커널 내에 (존재한다면) 튜닝 가능한 /proc/sys/vm/extra_free_kbytes를 셋팅하는 디바이스 설정. 높은 값은 커널이 free를 유지하는 메모리의 양을 증가시키고, 할당 시간을 줄이고, lowmemerykiller가 더 빨리 죽이도록 할 것입니다. 낮은 값은 프로세스들에 의해 더 많은 메모리를 사용하도록 하지만 디스크 I/O나 lowmemorykiller 상에서의 대기를 막는 더 많은 할당이 일어날 것입니다. 화면 크기에 기초한 ActivityManager에 의해 선택된 기본 값은 덮어씌움. 0은 커널의 기본 값을 넘는 추가 메모리를 유지하는 것을 막습니다. -1은 기본값을 유지합니다 –>
<integer name=”config_extraFreeKbytesAbsolute”>-1</integer>
<!– 커널 내에 (존재한다면) 튜닝 가능한 /proc/sys/vm/extra_free_kbytes를 조정하는 디바이스 설정. 0은 ActivityManager가 고르는 기본 값을 사용합니다. 양수 값은 커널이 해제를 유지하는 메모리의 양을 증가시키고, 할당 시간을 줄이고, lowmemorykiller 가 더 빨리 죽이도록 할 것입니다. 음수 값은 프로세스들에 의해 사용되는 메모리를 더 많이 허용하지만, 디스크 I/O나 lowmemorykiller 상의 대기를 막는 더 많은 할당이 일어날 것입니다. 화면 크기에 기초한 ActivityManager에 의해 선택된 기본 값은 직접 더해짐. –>
<integer name=”config_extraFreeKbytesAdjust”>0</integer>
LowMemoryKiller 튜닝
ActivityManager는 각 우선 순위 단계 버킷 안에서 프로세스를 실행하는데 필요한 file-backed 페이지(캐시된(cached) 페이지)의 워킹 셋의 그 예상치를 맞추기 위해서 LowMemoryKiller의 임계값을 설정합니다. 디바이스가 워킹 셋을 위한 높은 요구 사항을 갖는다면, 예를 들면, 벤더 UI가 더 많은 메모리를 요구하거나 더 많은 서비스가 추가되었다면, 임계값은 증가될 수 있습니다.
작아지고 있는 캐시 때문에 디스크 스레싱(thrashing)이 일어나기 전에 백그라운드 프로세스들이 죽여지고 있어서, 너무 많은 메모리가 file backed 페이지를 위해 예약되어 지고 있다면 임계값을 줄일 수 있습니다. 
<!– 커널 내의 lowmemorykiller 내의 튜닝 가능한 minfree를 셋팅하는 디바이스 설정. 높은 값은 lowmemorykiller가 더 일찍 켜지고, 파일 캐시 안에 더 많은 메모리를 유지하고, I/O 스레싱을 막도록 할 것이지만, 메모리 내에 더 적은 프로세스가 머물도록 할 것입니다. 낮은 값은 더 많은 프로세스가 메모리 상에 유지되지만, 너무 낮으면 스레싱을 일으킬 것입니다. 화면 크기와 가장 큰 lowmemorykiller 버킷을 위한 전체 메모리에 기초해서 ActivityManager에 의해 선택된 기본값을 덮어쓰고, 더 작은 버킷에 비례해서 크기가 조정됨. -1은 기본값을 유지 —>
<integer name=”config_lowMemoryKillerMinFreeKbytesAbsolute”>-1</integer>
<!– 커널 내의 lowmemorykiller 내의 튜닝 가능한 minfree를 조정하는 디바이스 설정. 높은 값은 lowmemorykiller가 더 일찍 켜지고, 파일 캐시 안에 더 많은 메모리를 유지하고, I/O 스레싱을 막도록 할 것이지만, 메모리 내에 더 적은 프로세스가 머물도록 할 것입니다. 낮은 값은 더 많은 프로세스가 메모리 상에 유지되지만, 너무 낮으면 스레싱을 일으킬 것입니다. 화면 크기와 가장 큰 lowmemorykiller 버킷을 위한 전체 메모리에 기초해서 ActivityManager에 의해 선택된 기본값에 직접 더해지고, 더 작은 버킷에 비례해서 크기가 조정됨. 0은 기본값을 유지 —>
<integer name=”config_lowMemoryKillerMinFreeKbytesAdjust”>0</integer>

Framework의 설정 참고 소스 코드: frameworks/base/services/java/com/android/server/am/ProcessList.java