diff --git a/.gitignore b/.gitignore index 4ad4a98b..64ab614c 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,6 @@ all.config # Kdevelop4 *.kdev4 + +# emacs e-tag +TAGS diff --git a/Documentation/SubmittingPatches.md b/Documentation/SubmittingPatches.md new file mode 100644 index 00000000..f9c45ea7 --- /dev/null +++ b/Documentation/SubmittingPatches.md @@ -0,0 +1,827 @@ +#How to Get Your Change Into the Linux Kernel +###or +#Care And Operation Of Your Linus Torvalds + + + +For a person or company who wishes to submit a change to the Linux +kernel, the process can sometimes be daunting if you're not familiar +with "the system." This text is a collection of suggestions which +can greatly increase the chances of your change being accepted. + +> 리눅스 커널 패치를 하고자 하는 개인이나 기업이 시스템에 익숙치 않다면 커널 패치 과정은 때때로 벅찰 수 있습니다. 이 문서는 당신의 패치가 더욱 더 잘 반영될 수 있도록 하는 방법을 모은 것입니다. + +This document contains a large number of suggestions in a relatively terse +format. For detailed information on how the kernel development process +works, see Documentation/development-process. Also, read +Documentation/SubmitChecklist for a list of items to check before +submitting code. If you are submitting a driver, also read +Documentation/SubmittingDrivers; for device tree binding patches, read +Documentation/devicetree/bindings/submitting-patches.txt. + +> 이 문서는 상대적으로 간결한 형식의 많은 제안을 포함하고 있습니다. 더 자세한 커널 개발 프로세스에 대해 알고 싶으면 Documentation/development-process 문서를 보세요. 또한 코드를 제출하기 전에 점검해 볼 것들을 위해 Documentation/SubmitChecklist을 읽어보세요. 만약 드라이버를 제출하려고 한다면 Documentation/SubmittingDrivers을 읽어 보세요. 패치에 결속된 device tree를 위해 Documentation/devicetree/bindings/submitting-patches.txt를 읽어 보세요. + +Many of these steps describe the default behavior of the git version +control system; if you use git to prepare your patches, you'll find much +of the mechanical work done for you, though you'll still need to prepare +and document a sensible set of patches. In general, use of git will make +your life as a kernel developer easier. + +> 많은 이 과정들은 git 버전 관리 시스템의 기본적인 동작을 설명합니다. 만약 git을 사용하여 당신의 패치를 준비한다면 아직 많은 기계적인 작업이 이미 모두 완료되었고 . 일반적으로 git의 사용은 커널 개발자로써의 당신의 삶을 좀 더 쉽게 만들어 줄 것입니다. + + +SECTION 1 - CREATING AND SENDING YOUR CHANGE +-------------------------------------------- + + +###0) Obtain a current source tree + +If you do not have a repository with the current kernel source handy, use +git to obtain one. You'll want to start with the mainline repository, +which can be grabbed with: +> 만약 현재 커널 소스의 저장소를 가지고 있지 않다면 git을 사용하여 다운로드 받으세요 . mainline 저장소로 시작하고 싶다면 다음 명령어로 소스를 얻을 수 있습니다. + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + +Note, however, that you may not want to develop against the mainline tree +directly. Most subsystem maintainers run their own trees and want to see +patches prepared against those trees. See the "T:" entry for the subsystem +in the MAINTAINERS file to find that tree, or simply ask the maintainer if +the tree is not listed there. +> 그러나 + +It is still possible to download kernel releases via tarballs (as described +in the next section), but that is the hard way to do kernel development. +> tarballs (다음 섹션에 설명되는)를 통해 여전히 커널을 다운받을 수 있지만 그것은 커널 개발을 하기에 어려운 방법입니다. + +###1) "diff -up" + +If you must generate your patches by hand, use "diff -up" or "diff -uprN" +to create patches. Git generates patches in this form by default; if +you're using git, you can skip this section entirely. +> 만약 당신의 패치를 반드시 수동으로 생성해야 한다면 패치를 생성하기 위해 "diff -up"과 "diff -uprN"을 사용하세요. Git은 기본적인 형식으로 패치를 생성합니다. 만약 git을 사용하고 있다면 이 섹션 전체를 스킵하셔도 됩니다. + +All changes to the Linux kernel occur in the form of patches, as +generated by diff(1). When creating your patch, make sure to create it +in "unified diff" format, as supplied by the '-u' argument to diff(1). +Also, please use the '-p' argument which shows which C function each +change is in - that makes the resultant diff a lot easier to read. +Patches should be based in the root kernel source directory, +not in any lower subdirectory. +> Linux 커널에 대한 모든 변경은 diff(1) 명령을 사용하여 패치 형식으로 생성하십시오. 패치를 만들 때 "unified diff" 형식의 패치를 만들기 위해 diff(1) 명령에 "-u"인수를 사용하십시오. 또한 변경이 어느 C 함수에서 이루어 졌는지를 표시하는 "-p"인수를 사용하십시오. 이 인수는 resultant diff를 꽤 읽기 쉽게 해줍니다. 패치는 Linux 커널 소스에서 서브 디렉토리가 아니라 Linux 커널 소스의 루트 디렉토리를 기준으로 해야 합니다. + +To create a patch for a single file, it is often sufficient to do: +> 하나의 파일에 대한 패치를 생성하기 위해서는 다음의 작업으로 대부분 충분합니다: + + SRCTREE= linux + MYFILE= drivers/net/mydriver.c + + cd $SRCTREE + cp $MYFILE $MYFILE.orig + vi $MYFILE # make your change + cd .. + diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch + +To create a patch for multiple files, you should unpack a "vanilla", +or unmodified kernel source tree, and generate a diff against your +own source tree. For example: +> 여러 파일에 대한 패치를 작성하기 위해서는 "vanilla"를 언팩하거나 커널 소스 트리를 수정해야 하고 당신의 소스 트리에 대한 차이인 diff를 생성해야 합니다. 예를 들어, + + MYSRC= /devel/linux + + tar xvfz linux-3.19.tar.gz + mv linux-3.19 linux-3.19-vanilla + diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \ + linux-3.19-vanilla $MYSRC > /tmp/patch + +"dontdiff" is a list of files which are generated by the kernel during +the build process, and should be ignored in any diff(1)-generated +patch. +> "dontdiff"은 Linux 커널 빌드 프로세스 과정에서 생성 된 파일 목록으로 패치를 생성하는 diff(1) 명령에 무시되어져야 합니다. + +Make sure your patch does not include any extra files which do not +belong in a patch submission. Make sure to review your patch -after- +generating it with diff(1), to ensure accuracy. +> 패치에 관계없는 불필요한 파일이 포함되어 있지 않은지 확인하십시오. diff (1) 명령으로 생성 된 패치가 당신의 의도대로 만들어졌는지 확인하십시오. + +If your changes produce a lot of deltas, you need to split them into +individual patches which modify things in logical stages; see section +3. This will facilitate review by other kernel developers, +very important if you want your patch accepted. +> 만약 여러분의 패치가 많은 수정을 요한다면, 당신은 패치를 논리적인 단계로 수정된 개별적인 패치로 나눌 필요가 있습니다. 섹션 3을 보십시요. 이것은 다른 커널 개발자들이 검토하기 쉬워지므로, 당신의 패치가 받아들여 지기를 원한다면 이 작업은 매우 중요합니다. + +If you're using git, "git rebase -i" can help you with this process. If +you're not using git, quilt +is another popular alternative. +> 만약 git을 사용한다면 "git rebase -i"는 이 과정을 도울 수 있습니다. 만약 git을 사용하지 않는다면 quilt는 잘알려진 다른 대안입니다. + + +###2) Describe your changes. + +Describe your problem. Whether your patch is a one-line bug fix or +5000 lines of a new feature, there must be an underlying problem that +motivated you to do this work. Convince the reviewer that there is a +problem worth fixing and that it makes sense for them to read past the +first paragraph. +> 당신의 문제를 서술하세요. 당신의 패치가 한줄의 버그를 수정하는 것이든 5000줄의 새로운 기능이든 당신이 이 작업을 하게된 이유에 대한 근본적인 문제가 있어야 합니다. 이것은 고칠 필요가 있는 문제가 있다는 것과 첫 번째 단락을 읽음으로써 + +Describe user-visible impact. Straight up crashes and lockups are +pretty convincing, but not all bugs are that blatant. Even if the +problem was spotted during code review, describe the impact you think +it can have on users. Keep in mind that the majority of Linux +installations run kernels from secondary stable trees or +vendor/product-specific trees that cherry-pick only specific patches +from upstream, so include anything that could help route your change +downstream: provoking circumstances, excerpts from dmesg, crash +descriptions, performance regressions, latency spikes, lockups, etc. +> 볼수있는 사실을 서술하세요. 충돌을 고치는것은 꽤나 좋은 일이지만, 모든 버그들이 그렇게 뻔뻔한건 아닙니다. 만약에 그 문제가 code review(코드 리뷰)에서 발견 되었을지라도, 사용자들에게 보일수 있는 문제라고 생각되는것을 서술하세요. 그리고 대규모의 리눅스 설치들은 2번째로 안정적인 커널이나 upstream에서 몇가지 패치들을 cherry-pick(체리픽)해온 vendor나 기기전용 트리에서 진행된다는것을 알아두세요 그래서 downstream시에 도움을 줄만한것들을 모두 추가헤세요 : provoking circumstances, dmesg에서 발, 충돌 정보, performance regressions, latency spikes, lockups, 등.. + +Quantify optimizations and trade-offs. If you claim improvements in +performance, memory consumption, stack footprint, or binary size, +include numbers that back them up. But also describe non-obvious +costs. Optimizations usually aren't free but trade-offs between CPU, +memory, and readability; or, when it comes to heuristics, between +different workloads. Describe the expected downsides of your +optimization so that the reviewer can weigh costs against benefits. + +Once the problem is established, describe what you are actually doing +about it in technical detail. It's important to describe the change +in plain English for the reviewer to verify that the code is behaving +as you intend it to. + +The maintainer will thank you if you write your patch description in a +form which can be easily pulled into Linux's source code management +system, git, as a "commit log". See #15, below. + +Solve only one problem per patch. If your description starts to get +long, that's a sign that you probably need to split up your patch. +See #3, next. + +When you submit or resubmit a patch or patch series, include the +complete patch description and justification for it. Don't just +say that this is version N of the patch (series). Don't expect the +subsystem maintainer to refer back to earlier patch versions or referenced +URLs to find the patch description and put that into the patch. +I.e., the patch (series) and its description should be self-contained. +This benefits both the maintainers and reviewers. Some reviewers +probably didn't even receive earlier versions of the patch. + +Describe your changes in imperative mood, e.g. "make xyzzy do frotz" +instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy +to do frotz", as if you are giving orders to the codebase to change +its behaviour. + +If the patch fixes a logged bug entry, refer to that bug entry by +number and URL. If the patch follows from a mailing list discussion, +give a URL to the mailing list archive; use the https://lkml.kernel.org/ +redirector with a Message-Id, to ensure that the links cannot become +stale. + +However, try to make your explanation understandable without external +resources. In addition to giving a URL to a mailing list archive or +bug, summarize the relevant points of the discussion that led to the +patch as submitted. + +If you want to refer to a specific commit, don't just refer to the +SHA-1 ID of the commit. Please also include the oneline summary of +the commit, to make it easier for reviewers to know what it is about. +Example: + + Commit e21d2170f36602ae2708 ("video: remove unnecessary + platform_set_drvdata()") removed the unnecessary + platform_set_drvdata(), but left the variable "dev" unused, + delete it. + +You should also be sure to use at least the first twelve characters of the +SHA-1 ID. The kernel repository holds a *lot* of objects, making +collisions with shorter IDs a real possibility. Bear in mind that, even if +there is no collision with your six-character ID now, that condition may +change five years from now. + +If your patch fixes a bug in a specific commit, e.g. you found an issue using +git-bisect, please use the 'Fixes:' tag with the first 12 characters of the +SHA-1 ID, and the one line summary. For example: + + Fixes: e21d2170f366 ("video: remove unnecessary platform_set_drvdata()") + +The following git-config settings can be used to add a pretty format for +outputting the above style in the git log or git show commands + + [core] + abbrev = 12 + [pretty] + fixes = Fixes: %h (\"%s\") + +###3) Separate your changes. + +Separate each _logical change_ into a separate patch. +> 의미있는 변경을 개별의 패치로 나누세요. + +For example, if your changes include both bug fixes and performance +enhancements for a single driver, separate those changes into two +or more patches. If your changes include an API update, and a new +driver which uses that new API, separate those into two patches. +> 예를 들어, 만약 하나의 드라이버에 대한 버그 수정 및 성능 강화를 포함하는 것이라면 그 변경을 2 개 이상의 패치로 나누세요. 만약 당신의 수정사항이 API의 업데이트와 새로운 API를 사용하는 새로운 드라이버가 포함되어 있다면, 2개의 패치로 나누어주십시오. + +On the other hand, if you make a single change to numerous files, +group those changes into a single patch. Thus a single logical change +is contained within a single patch. +> 반면에 만약 하나의 수정사항이 여러 파일을 변경한다면 그 변경 사항들을 하나의 패치 정리하십시오. 그래서 하나의 의미있는 수정사항은 하나의 패치에 포함됩니다. + +The point to remember is that each patch should make an easily understood +change that can be verified by reviewers. Each patch should be justifiable +on its own merits. +> 기억해야 할 점은 각 패치는 + +If one patch depends on another patch in order for a change to be +complete, that is OK. Simply note "this patch depends on patch X" +in your patch description. +> + +When dividing your change into a series of patches, take special care to +ensure that the kernel builds and runs properly after each patch in the +series. Developers using "git bisect" to track down a problem can end up +splitting your patch series at any point; they will not thank you if you +introduce bugs in the middle. + +If you cannot condense your patch set into a smaller set of patches, +then only post say 15 or so at a time and wait for review and integration. + + + +###4) Style-check your changes. + +Check your patch for basic style violations, details of which can be +found in Documentation/CodingStyle. Failure to do so simply wastes +the reviewers time and will get your patch rejected, probably +without even being read. + +One significant exception is when moving code from one file to +another -- in this case you should not modify the moved code at all in +the same patch which moves it. This clearly delineates the act of +moving the code and your changes. This greatly aids review of the +actual differences and allows tools to better track the history of +the code itself. + +Check your patches with the patch style checker prior to submission +(scripts/checkpatch.pl). Note, though, that the style checker should be +viewed as a guide, not as a replacement for human judgment. If your code +looks better with a violation then its probably best left alone. + +The checker reports at three levels: + - ERROR: things that are very likely to be wrong + - WARNING: things requiring careful review + - CHECK: things requiring thought + +You should be able to justify all violations that remain in your +patch. + + +###5) Select the recipients for your patch. + +You should always copy the appropriate subsystem maintainer(s) on any patch +to code that they maintain; look through the MAINTAINERS file and the +source code revision history to see who those maintainers are. The +script scripts/get_maintainer.pl can be very useful at this step. If you +cannot find a maintainer for the subsystem you are working on, Andrew +Morton (akpm@linux-foundation.org) serves as a maintainer of last resort. + +You should also normally choose at least one mailing list to receive a copy +of your patch set. linux-kernel@vger.kernel.org functions as a list of +last resort, but the volume on that list has caused a number of developers +to tune it out. Look in the MAINTAINERS file for a subsystem-specific +list; your patch will probably get more attention there. Please do not +spam unrelated lists, though. + +Many kernel-related lists are hosted on vger.kernel.org; you can find a +list of them at http://vger.kernel.org/vger-lists.html. There are +kernel-related lists hosted elsewhere as well, though. + +Do not send more than 15 patches at once to the vger mailing lists!!! + +Linus Torvalds is the final arbiter of all changes accepted into the +Linux kernel. His e-mail address is . +He gets a lot of e-mail, and, at this point, very few patches go through +Linus directly, so typically you should do your best to -avoid- +sending him e-mail. + +If you have a patch that fixes an exploitable security bug, send that patch +to security@kernel.org. For severe bugs, a short embargo may be considered +to allow distributors to get the patch out to users; in such cases, +obviously, the patch should not be sent to any public lists. + +Patches that fix a severe bug in a released kernel should be directed +toward the stable maintainers by putting a line like this: + + Cc: stable@vger.kernel.org + +into the sign-off area of your patch (note, NOT an email recipient). You +should also read Documentation/stable_kernel_rules.txt in addition to this +file. + +Note, however, that some subsystem maintainers want to come to their own +conclusions on which patches should go to the stable trees. The networking +maintainer, in particular, would rather not see individual developers +adding lines like the above to their patches. + +If changes affect userland-kernel interfaces, please send the MAN-PAGES +maintainer (as listed in the MAINTAINERS file) a man-pages patch, or at +least a notification of the change, so that some information makes its way +into the manual pages. User-space API changes should also be copied to +linux-api@vger.kernel.org. + +For small patches you may want to CC the Trivial Patch Monkey +trivial@kernel.org which collects "trivial" patches. Have a look +into the MAINTAINERS file for its current manager. +Trivial patches must qualify for one of the following rules: + Spelling fixes in documentation + Spelling fixes for errors which could break grep(1) + Warning fixes (cluttering with useless warnings is bad) + Compilation fixes (only if they are actually correct) + Runtime fixes (only if they actually fix things) + Removing use of deprecated functions/macros + Contact detail and documentation fixes + Non-portable code replaced by portable code (even in arch-specific, + since people copy, as long as it's trivial) + Any fix by the author/maintainer of the file (ie. patch monkey + in re-transmission mode) + + + +###6) No MIME, no links, no compression, no attachments. Just plain text. + +Linus and other kernel developers need to be able to read and comment +on the changes you are submitting. It is important for a kernel +developer to be able to "quote" your changes, using standard e-mail +tools, so that they may comment on specific portions of your code. + +For this reason, all patches should be submitted by e-mail "inline". +WARNING: Be wary of your editor's word-wrap corrupting your patch, +if you choose to cut-n-paste your patch. + +Do not attach the patch as a MIME attachment, compressed or not. +Many popular e-mail applications will not always transmit a MIME +attachment as plain text, making it impossible to comment on your +code. A MIME attachment also takes Linus a bit more time to process, +decreasing the likelihood of your MIME-attached change being accepted. + +Exception: If your mailer is mangling patches then someone may ask +you to re-send them using MIME. + +See Documentation/email-clients.txt for hints about configuring +your e-mail client so that it sends your patches untouched. + +###7) E-mail size. + +Large changes are not appropriate for mailing lists, and some +maintainers. If your patch, uncompressed, exceeds 300 kB in size, +it is preferred that you store your patch on an Internet-accessible +server, and provide instead a URL (link) pointing to your patch. But note +that if your patch exceeds 300 kB, it almost certainly needs to be broken up +anyway. + +###8) Respond to review comments. + +Your patch will almost certainly get comments from reviewers on ways in +which the patch can be improved. You must respond to those comments; +ignoring reviewers is a good way to get ignored in return. Review comments +or questions that do not lead to a code change should almost certainly +bring about a comment or changelog entry so that the next reviewer better +understands what is going on. + +Be sure to tell the reviewers what changes you are making and to thank them +for their time. Code review is a tiring and time-consuming process, and +reviewers sometimes get grumpy. Even in that case, though, respond +politely and address the problems they have pointed out. + + +###9) Don't get discouraged - or impatient. + +After you have submitted your change, be patient and wait. Reviewers are +busy people and may not get to your patch right away. + +Once upon a time, patches used to disappear into the void without comment, +but the development process works more smoothly than that now. You should +receive comments within a week or so; if that does not happen, make sure +that you have sent your patches to the right place. Wait for a minimum of +one week before resubmitting or pinging reviewers - possibly longer during +busy times like merge windows. + + +###10) Include PATCH in the subject + +Due to high e-mail traffic to Linus, and to linux-kernel, it is common +convention to prefix your subject line with [PATCH]. This lets Linus +and other kernel developers more easily distinguish patches from other +e-mail discussions. + + + +###11) Sign your work + +To improve tracking of who did what, especially with patches that can +percolate to their final resting place in the kernel through several +layers of maintainers, we've introduced a "sign-off" procedure on +patches that are being emailed around. + +The sign-off is a simple line at the end of the explanation for the +patch, which certifies that you wrote it or otherwise have the right to +pass it on as an open-source patch. The rules are pretty simple: if you +can certify the below: + + Developer's Certificate of Origin 1.1 + + By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +then you just add a line saying + + Signed-off-by: Random J Developer + +using your real name (sorry, no pseudonyms or anonymous contributions.) + +Some people also put extra tags at the end. They'll just be ignored for +now, but you can do this to mark internal company procedures or just +point out some special detail about the sign-off. + +If you are a subsystem or branch maintainer, sometimes you need to slightly +modify patches you receive in order to merge them, because the code is not +exactly the same in your tree and the submitters'. If you stick strictly to +rule (c), you should ask the submitter to rediff, but this is a totally +counter-productive waste of time and energy. Rule (b) allows you to adjust +the code, but then it is very impolite to change one submitter's code and +make him endorse your bugs. To solve this problem, it is recommended that +you add a line between the last Signed-off-by header and yours, indicating +the nature of your changes. While there is nothing mandatory about this, it +seems like prepending the description with your mail and/or name, all +enclosed in square brackets, is noticeable enough to make it obvious that +you are responsible for last-minute changes. Example : + + Signed-off-by: Random J Developer + [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h] + Signed-off-by: Lucky K Maintainer + +This practice is particularly helpful if you maintain a stable branch and +want at the same time to credit the author, track changes, merge the fix, +and protect the submitter from complaints. Note that under no circumstances +can you change the author's identity (the From header), as it is the one +which appears in the changelog. + +Special note to back-porters: It seems to be a common and useful practice +to insert an indication of the origin of a patch at the top of the commit +message (just after the subject line) to facilitate tracking. For instance, +here's what we see in a 3.x-stable release: + +Date: Tue Oct 7 07:26:38 2014 -0400 + + libata: Un-break ATA blacklist + + commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream. + +And here's what might appear in an older kernel once a patch is backported: + + Date: Tue May 13 22:12:27 2008 +0200 + + wireless, airo: waitbusy() won't delay + + [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a] + +Whatever the format, this information provides a valuable help to people +tracking your trees, and to people trying to troubleshoot bugs in your +tree. + + +###12) When to use Acked-by: and Cc: + +The Signed-off-by: tag indicates that the signer was involved in the +development of the patch, or that he/she was in the patch's delivery path. + +If a person was not directly involved in the preparation or handling of a +patch but wishes to signify and record their approval of it then they can +ask to have an Acked-by: line added to the patch's changelog. + +Acked-by: is often used by the maintainer of the affected code when that +maintainer neither contributed to nor forwarded the patch. + +Acked-by: is not as formal as Signed-off-by:. It is a record that the acker +has at least reviewed the patch and has indicated acceptance. Hence patch +mergers will sometimes manually convert an acker's "yep, looks good to me" +into an Acked-by: (but note that it is usually better to ask for an +explicit ack). + +Acked-by: does not necessarily indicate acknowledgement of the entire patch. +For example, if a patch affects multiple subsystems and has an Acked-by: from +one subsystem maintainer then this usually indicates acknowledgement of just +the part which affects that maintainer's code. Judgement should be used here. +When in doubt people should refer to the original discussion in the mailing +list archives. + +If a person has had the opportunity to comment on a patch, but has not +provided such comments, you may optionally add a "Cc:" tag to the patch. +This is the only tag which might be added without an explicit action by the +person it names - but it should indicate that this person was copied on the +patch. This tag documents that potentially interested parties +have been included in the discussion. + + +###13) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes: + +The Reported-by tag gives credit to people who find bugs and report them and it +hopefully inspires them to help us again in the future. Please note that if +the bug was reported in private, then ask for permission first before using the +Reported-by tag. + +A Tested-by: tag indicates that the patch has been successfully tested (in +some environment) by the person named. This tag informs maintainers that +some testing has been performed, provides a means to locate testers for +future patches, and ensures credit for the testers. + +Reviewed-by:, instead, indicates that the patch has been reviewed and found +acceptable according to the Reviewer's Statement: + + Reviewer's statement of oversight + + By offering my Reviewed-by: tag, I state that: + + (a) I have carried out a technical review of this patch to + evaluate its appropriateness and readiness for inclusion into + the mainline kernel. + + (b) Any problems, concerns, or questions relating to the patch + have been communicated back to the submitter. I am satisfied + with the submitter's response to my comments. + + (c) While there may be things that could be improved with this + submission, I believe that it is, at this time, (1) a + worthwhile modification to the kernel, and (2) free of known + issues which would argue against its inclusion. + + (d) While I have reviewed the patch and believe it to be sound, I + do not (unless explicitly stated elsewhere) make any + warranties or guarantees that it will achieve its stated + purpose or function properly in any given situation. + +A Reviewed-by tag is a statement of opinion that the patch is an +appropriate modification of the kernel without any remaining serious +technical issues. Any interested reviewer (who has done the work) can +offer a Reviewed-by tag for a patch. This tag serves to give credit to +reviewers and to inform maintainers of the degree of review which has been +done on the patch. Reviewed-by: tags, when supplied by reviewers known to +understand the subject area and to perform thorough reviews, will normally +increase the likelihood of your patch getting into the kernel. + +A Suggested-by: tag indicates that the patch idea is suggested by the person +named and ensures credit to the person for the idea. Please note that this +tag should not be added without the reporter's permission, especially if the +idea was not posted in a public forum. That said, if we diligently credit our +idea reporters, they will, hopefully, be inspired to help us again in the +future. + +A Fixes: tag indicates that the patch fixes an issue in a previous commit. It +is used to make it easy to determine where a bug originated, which can help +review a bug fix. This tag also assists the stable kernel team in determining +which stable kernel versions should receive your fix. This is the preferred +method for indicating a bug fixed by the patch. See #2 above for more details. + + +###14) The canonical patch format + +This section describes how the patch itself should be formatted. Note +that, if you have your patches stored in a git repository, proper patch +formatting can be had with "git format-patch". The tools cannot create +the necessary text, though, so read the instructions below anyway. + +The canonical patch subject line is: + + Subject: [PATCH 001/123] subsystem: summary phrase + +The canonical patch message body contains the following: + + - A "from" line specifying the patch author (only needed if the person + sending the patch is not the author). + + - An empty line. + + - The body of the explanation, line wrapped at 75 columns, which will + be copied to the permanent changelog to describe this patch. + + - The "Signed-off-by:" lines, described above, which will + also go in the changelog. + + - A marker line containing simply "---". + + - Any additional comments not suitable for the changelog. + + - The actual patch (diff output). + +The Subject line format makes it very easy to sort the emails +alphabetically by subject line - pretty much any email reader will +support that - since because the sequence number is zero-padded, +the numerical and alphabetic sort is the same. + +The "subsystem" in the email's Subject should identify which +area or subsystem of the kernel is being patched. + +The "summary phrase" in the email's Subject should concisely +describe the patch which that email contains. The "summary +phrase" should not be a filename. Do not use the same "summary +phrase" for every patch in a whole patch series (where a "patch +series" is an ordered sequence of multiple, related patches). + +Bear in mind that the "summary phrase" of your email becomes a +globally-unique identifier for that patch. It propagates all the way +into the git changelog. The "summary phrase" may later be used in +developer discussions which refer to the patch. People will want to +google for the "summary phrase" to read discussion regarding that +patch. It will also be the only thing that people may quickly see +when, two or three months later, they are going through perhaps +thousands of patches using tools such as "gitk" or "git log +--oneline". + +For these reasons, the "summary" must be no more than 70-75 +characters, and it must describe both what the patch changes, as well +as why the patch might be necessary. It is challenging to be both +succinct and descriptive, but that is what a well-written summary +should do. + +The "summary phrase" may be prefixed by tags enclosed in square +brackets: "Subject: [PATCH ...] ". The tags are +not considered part of the summary phrase, but describe how the patch +should be treated. Common tags might include a version descriptor if +the multiple versions of the patch have been sent out in response to +comments (i.e., "v1, v2, v3"), or "RFC" to indicate a request for +comments. If there are four patches in a patch series the individual +patches may be numbered like this: 1/4, 2/4, 3/4, 4/4. This assures +that developers understand the order in which the patches should be +applied and that they have reviewed or applied all of the patches in +the patch series. + +A couple of example Subjects: + + Subject: [PATCH 2/5] ext2: improve scalability of bitmap searching + Subject: [PATCH v2 01/27] x86: fix eflags tracking + +The "from" line must be the very first line in the message body, +and has the form: + + From: Original Author + +The "from" line specifies who will be credited as the author of the +patch in the permanent changelog. If the "from" line is missing, +then the "From:" line from the email header will be used to determine +the patch author in the changelog. + +The explanation body will be committed to the permanent source +changelog, so should make sense to a competent reader who has long +since forgotten the immediate details of the discussion that might +have led to this patch. Including symptoms of the failure which the +patch addresses (kernel log messages, oops messages, etc.) is +especially useful for people who might be searching the commit logs +looking for the applicable patch. If a patch fixes a compile failure, +it may not be necessary to include _all_ of the compile failures; just +enough that it is likely that someone searching for the patch can find +it. As in the "summary phrase", it is important to be both succinct as +well as descriptive. + +The "---" marker line serves the essential purpose of marking for patch +handling tools where the changelog message ends. + +One good use for the additional comments after the "---" marker is for +a diffstat, to show what files have changed, and the number of +inserted and deleted lines per file. A diffstat is especially useful +on bigger patches. Other comments relevant only to the moment or the +maintainer, not suitable for the permanent changelog, should also go +here. A good example of such comments might be "patch changelogs" +which describe what has changed between the v1 and v2 version of the +patch. + +If you are going to include a diffstat after the "---" marker, please +use diffstat options "-p 1 -w 70" so that filenames are listed from +the top of the kernel source tree and don't use too much horizontal +space (easily fit in 80 columns, maybe with some indentation). (git +generates appropriate diffstats by default.) + +See more details on the proper patch format in the following +references. + +###15) Explicit In-Reply-To headers + +It can be helpful to manually add In-Reply-To: headers to a patch +(e.g., when using "git send-email") to associate the patch with +previous relevant discussion, e.g. to link a bug fix to the email with +the bug report. However, for a multi-patch series, it is generally +best to avoid using In-Reply-To: to link to older versions of the +series. This way multiple versions of the patch don't become an +unmanageable forest of references in email clients. If a link is +helpful, you can use the https://lkml.kernel.org/ redirector (e.g., in +the cover email text) to link to an earlier version of the patch series. + + +###16) Sending "git pull" requests + +If you have a series of patches, it may be most convenient to have the +maintainer pull them directly into the subsystem repository with a +"git pull" operation. Note, however, that pulling patches from a developer +requires a higher degree of trust than taking patches from a mailing list. +As a result, many subsystem maintainers are reluctant to take pull +requests, especially from new, unknown developers. If in doubt you can use +the pull request as the cover letter for a normal posting of the patch +series, giving the maintainer the option of using either. + +A pull request should have [GIT] or [PULL] in the subject line. The +request itself should include the repository name and the branch of +interest on a single line; it should look something like: + + Please pull from + + git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus + + to get these changes: + +A pull request should also include an overall message saying what will be +included in the request, a "git shortlog" listing of the patches +themselves, and a diffstat showing the overall effect of the patch series. +The easiest way to get all this information together is, of course, to let +git do it for you with the "git request-pull" command. + +Some maintainers (including Linus) want to see pull requests from signed +commits; that increases their confidence that the request actually came +from you. Linus, in particular, will not pull from public hosting sites +like GitHub in the absence of a signed tag. + +The first step toward creating such tags is to make a GNUPG key and get it +signed by one or more core kernel developers. This step can be hard for +new developers, but there is no way around it. Attending conferences can +be a good way to find developers who can sign your key. + +Once you have prepared a patch series in git that you wish to have somebody +pull, create a signed tag with "git tag -s". This will create a new tag +identifying the last commit in the series and containing a signature +created with your private key. You will also have the opportunity to add a +changelog-style message to the tag; this is an ideal place to describe the +effects of the pull request as a whole. + +If the tree the maintainer will be pulling from is not the repository you +are working from, don't forget to push the signed tag explicitly to the +public tree. + +When generating your pull request, use the signed tag as the target. A +command like this will do the trick: + + git request-pull master git://my.public.tree/linux.git my-signed-tag + + + + +SECTION 2 - REFERENCES +---------------------- + +Andrew Morton, "The perfect patch" (tpp). + + +Jeff Garzik, "Linux kernel patch submission format". + + +Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer". + + + + + + + +NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people! + + +Kernel Documentation/CodingStyle: + + +Linus Torvalds's mail on the canonical patch format: + + +Andi Kleen, "On submitting kernel patches" + Some strategies to get difficult or controversial changes in. + http://halobates.de/on-submitting-patches.pdf + +-- diff --git a/IAMROOT_12CD.md b/IAMROOT_12CD.md new file mode 100644 index 00000000..ec594d43 --- /dev/null +++ b/IAMROOT_12CD.md @@ -0,0 +1,154 @@ +# Iamroot ARM Kernel 분석 12차 CD조 (http://www.iamroot.org) + +## 제 75주차 스터디 +#### 날짜: 2016-09-24 +#### 장소: Koss 공개SW개발자 Lab +#### 내용: + - setup_arch() -> paging_init() -> map_lowmem() 분석중.. + - 다들 수고 하셨습니다. 다음부터는 AB에 합쳐집니다. +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김미르 (skykmr8405@naver.com)* + - 김민호 (8891m@naver.com) + +## 제 74주차 스터디 +#### 날짜: 2016-09-17 +#### 장소: Koss 공개SW개발자 Lab +#### 내용: 추석 휴가 + +## 제 73주차 스터디 +#### 날짜: 2016-09-10 +#### 장소: Koss 공개SW개발자 Lab +#### 내용: + - setup_arch() -> paging_init() -> build_mem_type_table() 분석 완료. + - setup_arch() -> paging_init() -> prepare_page_table() 분석 +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김미르 (skykmr8405@naver.com)* + + +## 제 72주차 스터디 +#### 날짜: 2016-09-03 +#### 장소: Koss 공개SW개발자 Lab +#### 내용: setup_arch() -> paging_init() 분석 +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *조훈근 (hoonycho12@gmail.com)* + - 김민호 (8891m@naver.com) + - 김미르 (skykmr8405@naver.com) + +## 제 71주차 스터디 +#### 날짜: 2016-08-27 +#### 장소: Koss 공개SW개발자 Lab +#### 내용: setup_arch() -> arm_memblock_init() 분석완료, paging_init() 분석시작. +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김민호 (8891m@naver.com)* + - 김미르 (skykmr8405@naver.com) + - 김영준 (iam.yeongjunkim@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + +## 제 70주차 스터디 +#### 날짜: 2016-08-20 +#### 장소: 강남 윙스터디 2호점 +#### 내용: setup_arch() -> arm_memblock_init() 분석중 +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - 조훈근 (hoonycho12@gmail.com) + - 김미르 (skykmr8405@naver.com) + +## 제 69주차 스터디 +#### 날짜: 2016-08-13 +#### 내용: 하계휴가 + +## 제 68주차 스터디 +#### 날짜: 2016-08-06 +#### 장소: 강남 토즈타워 +#### 내용: setup_arch -> sanity_check_meminfo() 분석 +#### 참석자 + - **조훈근 (hoonycho12@gmail.com)** + - *김영준 (iam.yeongjunkim@gmail.com)* + - 임채훈 (im.fehead@gmail.com) + - 김민호 (8891m@naver.com) + +## 제 67주차 스터디 +#### 날짜: 2016-07-30 +#### 장소: 강남 토즈타워 +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김민호 (8891m@naver.com)* + - 조훈근 (hoonycho12@gmail.com) + + +## 제 66주차 스터디 + +#### 날짜: 2016-07-23 +#### 장소: 강남 토즈타워 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김민호 (8891m@naver.com)* + - 김영준 (iam.yeongjunkim@gmail.com) + - 김미르 (skykmr8405@naver.com) + +## 제 65주차 스터디 + +#### 날짜: 2016-07-16 +#### 장소: 강남 토즈타워 + +#### 참석자 + - **김민호 (8891m@naver.com)** + - *조훈근 (hoonycho12@gmail.com)* + - 임채훈 (im.fehead@gmail.com) + - 김영준 (iam.yeongjunkim@gmail.com) + + +## 제 64주차 스터디 + +#### 날짜: 2016-07-09 +#### 장소: 강남 토즈타워 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김영준 (iam.yeongjunkim@gmail.com)* + - 김미르 (skykmr8405@naver.com) + + +## 제 63주차 스터디 + +#### 날짜: 2016-07-02 +#### 장소: 강남 토즈타워 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김미르 (skykmr8405@naver.com)* + - 김영준 (iam.yeongjunkim@gmail.com) + - 김민호 (8891m@naver.com) + - 김동호 (dong3097@naver.com) + - 신은환 (comsky@msn.com) + + +## 제 62주차 스터디 + +#### 날짜: 2016-06-25 +#### 장소: 강남 토즈타워 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *권세홍 (sehongkwon2.24@gmail.com)* + - 김영준 (iam.yeongjunkim@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + - 김민호 (8891m@naver.com) + - 김동호 (dong3097@naver.com) + - 심만섭 (tlqaksqhr@naver.com) + +## 제 61주차 스터디 + +#### 날짜: 2016-06-18 +#### 장소: 토즈 강남 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김영준 (iam.yeongjunkim@gmail.com)* + - 김미르 (skykmr8405@naver.com) + - 신은환 diff --git a/IAMROOT_12D.md b/IAMROOT_12D.md new file mode 100644 index 00000000..0be49a02 --- /dev/null +++ b/IAMROOT_12D.md @@ -0,0 +1,690 @@ +# Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + +## 제 60주차 스터디 + +#### 날짜: 2016-06-11 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김영준 (iam.yeongjunkim@gmail.com)* + - 조훈근 (hoonycho12@gmail.com) + - 김민호 (8891m@naver.com) + - 권세홍 (sehongkwon2.24@gmail.com) + +## 제 59주차 스터디 +#### 날짜: 2016-06-04 +#### 장소: 휴가 + + +## 제 58주차 스터디 + +#### 날짜: 2016-05-28 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김민호 (8891m@naver.com)* + - 안종찬 (ahnchan2@gmail.com) + - 김영준 (iam.yeongjunkim@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + + +## 제 57주차 스터디 + +#### 날짜: 2016-05-21 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **김민호 (8891m@naver.com)** + - *임채훈 (im.fehead@gmail.com)* + - 안종찬 (ahnchan2@gmail.com) + +## 제 56주차 스터디 + +#### 날짜: 2016-05-14 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **안종찬 (ahnchan2@gmail.com)** + - *김민호 (8891m@naver.com)* + - 임채훈 (im.fehead@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + - 김영준 (iam.yeongjunkim@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 곽희범 (andrew@norux.me) + +## 제 55주차 스터디 + +#### 날짜: 2016-05-07 +#### 휴가 + +## 제 54주차 스터디 + +#### 날짜: 2016-04-30 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **김민호 (8891m@naver.com)** + - *안종찬 (ahnchan2@gmail.com)* + - 임채훈 (im.fehead@gmail.com) + +## 제 53주차 스터디 + +#### 날짜: 2016-04-23 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *김민호 (8891m@naver.com)* + - 안종찬 (ahnchan2@gmail.com) + +## 제 52주차 스터디 + +#### 날짜: 2016-04-16 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *조훈근 (hoonycho12@gmail.com)* + - 김영준 (iam.yeongjunkim@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 박병배 (i.billpark@gmail.com) + +## 제 51주차 스터디 + +#### 날짜: 2016-04-09 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **권세홍 (sehongkwon2.24@gmail.com)** + - *조훈근 (hoonycho12@gmail.com)* + - 임채훈 (im.fehead@gmail.com) + - 김민호 (8891m@naver.com) + - 김지은 (yeswldms@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 박종성 (jongsong.park@gmail.com) + +## 제 50주차 스터디 + +#### 날짜: 2016-04-02 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *안종찬 (ahnchan2@gmail.com)* + - 조훈근 (hoonycho12@gmail.com) + - 김민호 (8891m@naver.com) + - 곽희범 (andrew@norux.me) + - 김영준 (iam.yeongjunkim@gmail.com) + - 김지은 (yeswldms@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 박병배 (i.billpark@gmail.com) + +## 제 49주차 스터디 + +#### 날짜: 2016-03-26 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **안종찬 (ahnchan2@gmail.com)** + - *임채훈 (im.fehead@gmail.com)* + - 김민호 (8891m@naver.com) + - 곽희범 (andrew@norux.me) + - 김영준 (iam.yeongjunkim@gmail.com) + - 김건용 (gykim0914@gmail.com) + +## 제 48주차 스터디 + +#### 날짜: 2016-03-19 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - *안종찬 (ahnchan2@gmail.com)* + - 김민호 (8891m@naver.com) + - 박종성 (jongsong.park@gmail.com) + - 박병배 (i.billpark@gmail.com) + +## 제 47주차 스터디 + +#### 날짜: 2016-03-12 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **김민호 (8891m@naver.com)** + - *임채훈 (im.fehead@gmail.com)* + - *안종찬 (ahnchan2@gmail.com)* + - 곽승준 (rialtoksj@yahoo.com) + - 김건용 (gykim0914@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + - 박종성 (jongsong.park@gmail.com) + + +## 제 46주차 스터디 + +#### 날짜: 2016-03-05 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **곽희범 (andrew@norux.me)** + - 안종찬 (ahnchan2@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 김민호 (8891m@naver.com) + - 임채훈 (im.fehead@gmail.com) + - 김지은 (yeswldms@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 김건용 (gykim0914@gmail.com) + + +## 제 45주차 스터디 + +#### 날짜: 2016-02-27 +#### 장소: 강남토즈타워점 + +#### 참석자 + - **안종찬 (ahnchan2@gmail.com)** + - 곽승준 (rialtoksj@yahoo.com) + - 김민호 (8891m@naver.com) + - 임채훈 (im.fehead@gmail.com) + - 곽희범 (andrew@norux.me) + - 김지은 (yeswldms@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 박종성 (jongsong.park@gmail.com) + +## 제 44주차 스터디 + +#### 날짜: 2016-02-19 +#### 장소: 힐 스터디 강남점 + +#### 참석자 + - **곽승준 (rialtoksj@yahoo.com)** + - 김민호 (8891m@naver.com) + - 안종찬 (ahnchan2@gmail.com) + - 임채훈 (im.fehead@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + +## 제 43주차 스터디 + +#### 날짜: 2016-02-13 +#### 장소: 윙 스터디 강남점 + +#### 참석자 + - **김민호 (8891m@naver.com)** + - 곽희범 (andrew@norux.me) + - 안종찬 (ahnchan2@gmail.com) + - 임채훈 (im.fehead@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 권세홍 (sehongkwon2.24@gmail.com) + +## 제 42주차 스터디 + +#### 날짜: 2016-02-06 +#### 설 휴가 + +## 제 41주차 스터디 + +#### 날짜: 2016-01-30 +#### 장소: 토즈 강남타워점 + +#### 참석자 + - **곽희범 (andrew@norux.me)** + - 안종찬 (ahnchan2@gmail.com) + - 임채훈 (im.fehead@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 김민호 (8891m@naver.com) + - 김건용 (gykim0914@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 권세홍 (sehongkwon2.24@gmail.com) + +## 제 40주차 스터디 + +#### 날짜: 2016-01-23 +#### 장소: 토즈 강남타워점 + +#### 참석자 + - **안종찬 (ahnchan2@gmail.com)** + - 임채훈 (im.fehead@gmail.com) + - 김지은 (yeswldms@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 김민호 (8891m@naver.com) + - 곽희범 (andrew@norux.me) + - 김건용 (gykim0914@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + +**참석인원: 9 명** + +## 제 39주차 스터디 + +#### 날짜: 2016-01-16 +#### 장소: 토즈 강남타워점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - 박종성 (jongsong.park@gmail.com) + - 안종찬 (ahnchan2@gmail.com) + - 김지은 (yeswldms@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 김민호 (8891m@naver.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 최일선 (isc0304@naver.com) + - 곽희범 (andrew@norux.me) + +**참석인원: 9 명** + + +## 제 38주차 스터디 + +#### 날짜: 2016-01-09 +#### 장소: 토즈 강남1호점 + +#### 참석자 + - **임채훈 (im.fehead@gmail.com)** + - 박종성 (jongsong.park@gmail.com) + - 안종찬 (ahnchan2@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 김지은 (yeswldms@gmail.com) + - 김건용 (gykim0914@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 김민호 (8891m@naver.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 최일선 (isc0304@naver.com) + - 조훈근 (hoonycho12@gmail.com) + +**참석인원: 11 명** + + +## 제 37주차 스터디 + +#### 날짜: 2016-01-02 +#### 동계휴가 + + +## 제 36주차 스터디 + +#### 날짜: 2016-12-26 +#### 동계휴가 + + +## 제 35주차 스터디 + +#### 날짜: 2015-12-19 +#### 장소: 커널연구회 + +#### 참석자 + - 소스 드라이빙 : 박종성 (jongsong.park@gmail.com) + - 안종찬 (ahnchan2@gmail.com) + - 임채훈 (im.fehead@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 곽희범 (andrew@norux.me) + - 김지은 (yeswldms@gmail.com) + - 김건용 (gykim0914@gmail.com) + +**참석인원: 7 명** + + +## 제 34주차 스터디 + +#### 날짜: 2015-12-12 +#### 장소: 커널연구회 + +#### 참석자 + - 소스 드라이빙 : 안종찬 (ahnchan2@gmail.com) + - 임채훈 (im.fehead@gmail.com) + - 박종성 (jongsong.park@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 김민호 (8891m@naver.com) + +**참석인원: 7 명** + +## 제 33주차 스터디 + +#### 날짜: 2015-12-05 +#### 장소: 커널연구회 + +#### 참석자 + - 곽희범 (andrew@norux.me) + - 임채훈 (im.fehead@gmail.com) + - 박종성 (jongsong.park@gmail.com) + - 안종찬 (ahnchan2@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 구자협 (1212combat@naver.com) + - 김지은 (yeswldms@gmail.com) + - 김민호 (8891m@naver.com) + +**참석인원: 8 명** + +## 제 32주차 스터디 + +#### 날짜: 2015-11-28 +#### 장소: 커널연구회 + +#### 참석자 + - 곽희범 (andrew@norux.me) + - 임채훈 (im.fehead@gmail.com) + - 박종성 (jongsong.park@gmail.com) + - 안종찬 (ahnchan2@gmail.com) + - 김건용 (gykim0914@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 박병배 (i.billpark@gmail.com) + - 구자협 (1212combat@naver.com) + +**참석인원: 10 명** + +## 제 31주차 스터디 + +#### 날짜: 2015-11-21 +#### 장소: 커널연구회 + +#### 참석자 + - 곽희범 (andrew@norux.me) + - 임채훈 (im.fehead@gmail.com) + - 김영준 (iam.yeongjunkim@gmail.com) + - 박종성 (jongsong.park@gmail.com) + - 안종찬 (ahnchan2@gmail.com) + - 김건용 (gykim0914@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 김지은 (yeswldms@gmail.com) + - 조훈근 (hoonycho12@gmail.com) + - 곽승준 (rialtoksj@yahoo.com) + - 김문영 (m03y29@gmail.com) + - 구자협 (1212combat@naver.com) + +**참석인원: 12 명** + + +## 제 30주차 스터디 + +#### 날짜: 2015-11-14 +#### 장소: 커널연구회 + +#### 참석자 + - 곽희범 (andrew@norux.me) + - 임채훈 (im.fehead@gmail.com) + - 민혜미 (mhyem2@naver.com) + - 박종성 (jongsong.park@gmail.com) + - 김영준 (iam.yeongjunkim@gmail.com) + - 박병배 (i.billpark@gmail.com) + - 안종찬 (ahnchan2@gmail.com) + - 김건용 (gykim0914@gmail.com) + - 권세홍 (sehongkwon2.24@gmail.com) + - 김지은 (yeswldms@gmail.com) + - 김민호 (8891m@naver.com) + +**참석인원: 11 명** + +## 29 주차 스터디 + +#### 날짜: 2015.11.07 +#### 장소: 커널연구회 + +#### 스터디내용: arch/arm/boot/compressed/head.S FDT, DTB 분석 +#### 참석자 + - 10명 + + +## 28 주차 스터디 + +#### 날짜: 2015.10.31 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S MMU 설정 +#### 참석자 + - 8명 + + +## 27 주차 스터디 + +#### 날짜: 2015.10.24 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S MMU 설정 +#### 참석자 + - 11명 + + +## 26 주차 스터디 + +#### 날짜: 2015.10.17 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S MMU 설정 +#### 참석자 + - 8명 + + +## 25 주차 스터디 + +#### 날짜: 2015.10.10 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S MMU 설정 +#### 참석자 + - 11명 + + +## 24 주차 스터디 + +#### 날짜: 2015.10.03 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S MMU 설정 +#### 참석자 + - 15명 + + +## 23주차 스터디 + +#### 날짜: 2015.09.26 +#### 추석연휴 + + +## 22 주차 스터디 + +#### 날짜: 2015.09.19 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S start section 전 매크로 분석 +#### 참석자 + - 15명 + + +## 21 주차 스터디 + +#### 날짜: 2015.09.12 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S start section 전 매크로 분석 +#### 참석자 + - 18명 + + +## 20 주차 스터디 + +#### 날짜: 2015.09.05 +#### 장소: 커널연구회 + +#### 스터디내용: linux/arch/arm/boot/compressed/head.S Line 82 .macro kphex 매크로까지 분석 +#### 참석자 + - 20명 + + +## 19 주차 스터디 + +#### 날짜: 2015.08.29 +#### 장소: 커널연구회 + +#### 스터디내용: git 사용방법, vim 설정및 사용방법 +#### 참석자 + - 21명 + + +## 18 주차 스터디 + +#### 날짜: 2015.08.22 +#### 장소: 커널연구회 + +#### 스터디내용: (1p ~ 70p) - 미완료 +#### 참석자 + - 19명 + + +## 17 주차 스터디 + +#### 날짜: 2015.08.15 +#### 장소: 경기대학교 제2공학관 + +#### 스터디내용: ~ 9. 네트워킹(189p~247p) +#### 참석자 + - 15명 + + +## 16 주차 스터디 + +#### 날짜: 2015.08.08 +#### 장소: 경기대학교 제2공학관 + +#### 스터디내용: ~ 6. 인터럽트와 트랩 그리고 시스템 호출(111p~187p) +#### 참석자 + - 15명 + + +## 15주차 스터디 + +#### 날짜: 2015.08.01 +#### 하계 휴가 + + +## 14 주차 스터디 + +#### 날짜: 2015.07.25 +#### 장소: 경기대학교 제2공학관 + +#### 스터디내용: ~3.3 슬랩할당자(75p ~ 109p) +#### 참석자 + - 18명 + + +## 13 주차 스터디 + +#### 날짜: 2015.07.18 +#### 장소: 경기대학교 제2공학관 + +#### 스터디내용: 0 ~ 3.6 (9p~75p) +#### 참석자 + - 12명 + + +## 12 주차 스터디 + +#### 날짜: 2015.07.11 +#### 장소: 어쩌면 사무소 + +#### 스터디내용: ~ 14. 시스템 부팅 (396p~469p 완료) +#### 참석자 + - 18명 + + +## 11 주차 스터디 + +#### 날짜: 2015.07.04 +#### 장소: 성균관대 자연과학캠퍼스 제2공학관 26310호 + +#### 스터디내용: ~ 11. 파이프 (326p~394p) +#### 참석자 + - 19명 + + +## 10 주차 스터디 + +#### 날짜: 2015.06.27 +#### 장소: 서울대학교 자연과학대학(25동) 104호 + +#### 스터디내용: ~ 9.6 블록 디바이스의 블록할당 (262p~325p) +#### 참석자 + - 20명 + + +## 09 주차 스터디 + +#### 날짜: 2015.06.20 +#### 장소: 광운대학교 비마관 427호 + +#### 스터디내용: ~ 7.블록 디바이스 서브시스템 (196~261p) +#### 참석자 + - 18명 + + +## 08주차 스터디 + +#### 날짜: 2015.06.13 +#### 장소: 당산동3가 22 + +#### 스터디내용: ~ 3. 프로세스제어 (34~140p) +#### 참석자 + - 8명 + + +## 07주차 스터디 + +#### 날짜: 2015.06.06 +#### 메르스 바이러스로 인한 휴식 결정 + + +## 06 주차 스터디 + +#### 날짜: 2015.05.30 +#### 장소: 경기대학교 덕문관 5101 + +#### 스터디내용: ~ 5.5.2 grow()(~195p) +#### 참석자 + - 35명 + + +## 05 주차 스터디 + +#### 날짜: 2015.05.23 +#### 장소: 안양대학교 수리관 404호 + +#### 스터디내용: ~ 4.3 요약(~157p) 004 +#### 참석자 + - 39명 + + +## 03 주차 스터디 + +#### 날짜: 2015.05.09 +#### 장소: 구로디지털단지 이앤씨 벤터드림타워2차 B1 다목적세미나룸 + +#### 스터디내용: ~ 3.3.8 switch()에서 돌아갈 위치 (~95page) +#### 참석자 + - 49명 + + +## 02 주차 스터디 + +#### 날짜: 2015.05.04 +#### 장소: 성균관대 (명륜캠퍼스) + +#### 스터디내용: ~ 3.2.2 부모 프로세서(~71page) +#### 참석자 + - 48명 + + +## 01 주차 스터디 + +#### 날짜: 2015.04.23 +#### 장소: NIPA 본원 5층 대강당 + +#### 스터디내용: +#### 참석자 + - ?명 diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c index 9448aa0c..b77dea41 100644 --- a/arch/arm/boot/compressed/atags_to_fdt.c +++ b/arch/arm/boot/compressed/atags_to_fdt.c @@ -9,10 +9,22 @@ #define NR_BANKS 16 +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-12-05 + * ------------------------------------------------------------------ + * + * 만약, node_path가 존재하지 않으면, add_subnode를 통해 새로 노드를 만든다. + * + * ================================================================== + */ static int node_offset(void *fdt, const char *node_path) { + /* node를 찾지못하면 FDT_ERR_NOTFOUND가 나옴 */ int offset = fdt_path_offset(fdt, node_path); if (offset == -FDT_ERR_NOTFOUND) + /* parent offset이 0인이유는, 루트하위의 노드로 넣겠다는 + 의미이다.*/ offset = fdt_add_subnode(fdt, 0, node_path); return offset; } @@ -26,6 +38,13 @@ static int setprop(void *fdt, const char *node_path, const char *property, return fdt_setprop(fdt, offset, property, val_array, size); } +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * + * fdt 에서 지정된 offset 위치의 property를 string 값으로 세팅 + */ static int setprop_string(void *fdt, const char *node_path, const char *property, const char *string) { @@ -35,32 +54,65 @@ static int setprop_string(void *fdt, const char *node_path, return fdt_setprop_string(fdt, offset, property, string); } +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-12-05 + * ------------------------------------------------------------------ + * node_path - property 에 val을 세팅한다. + * ================================================================== + */ static int setprop_cell(void *fdt, const char *node_path, const char *property, uint32_t val) { + /* + node_path를 구해온다. + 만약, node_path가 없다면 추가 이후 오프셋을 구해온다. + */ int offset = node_offset(fdt, node_path); if (offset < 0) return offset; return fdt_setprop_cell(fdt, offset, property, val); } +/* + * chosen { + * bootargs="console=ttyS0,115200 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs"; + * }; + + * 호출: fdt_bootargs = getprop(fdt, "/chosen", "bootargs", &len); + */ static const void *getprop(const void *fdt, const char *node_path, const char *property, int *len) { + // node "/chosen"의 offset을 가져옴 int offset = fdt_path_offset(fdt, node_path); if (offset == -FDT_ERR_NOTFOUND) return NULL; + // 이젠 node "/chosen" 안에 있는 property "bootargs"를 가져옴 return fdt_getprop(fdt, offset, property, len); } +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-12-05 + * ------------------------------------------------------------------ + * fdt에서 cell size를 읽어옴 + * + * 32/64bit를 셀사이즈로 판단한다. + * + * 1: 32bit(*default) + * 2: 64bit + * ================================================================== + */ static uint32_t get_cell_size(const void *fdt) { int len; uint32_t cell_size = 1; const uint32_t *size_len = getprop(fdt, "/", "#size-cells", &len); + /* 64bit면 size_len이 2로 올것이다. */ if (size_len) cell_size = fdt32_to_cpu(*size_len); return cell_size; @@ -73,8 +125,30 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) char *ptr = cmdline; int len = 0; + /* + * fdt_node 예 + * /{ + * ... + * chosen { + * bootargs="root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; + * }; + * ... + * }; + + * 위 예제에서 + * 노드명: "/chosen" + * property: "bootargs" + * 더 많은 참고: http://xillybus.com/tutorials/device-tree-zynq-2 + + * fdt_bootargs에 받아오는 내용은 아래와 같음 + * "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; + * len에 길이가 저장됨 + */ + + // node "/chosen"의 property "bootargs"의 value과 길이를 받아옴 /* copy the fdt command line into the buffer */ fdt_bootargs = getprop(fdt, "/chosen", "bootargs", &len); + // [2015.11.28 여기서부터 시작] if (fdt_bootargs) if (len < COMMAND_LINE_SIZE) { memcpy(ptr, fdt_bootargs, len); @@ -84,6 +158,10 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) } /* and append the ATAG_CMDLINE */ + /* fdt_bootargs 로 리턴된 문자열과 + * 인자로 넘어온 fdt_cmdline 문자열을 합치는 구문 + * ex) cmdline = fdt_bootargs + ' ' + fdt_cmdline + '\0' + */ if (fdt_cmdline) { len = strlen(fdt_cmdline); if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) { @@ -97,6 +175,28 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) setprop_string(fdt, "/chosen", "bootargs", cmdline); } +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-07 + * ------------------------------------------------------------------ + * + * 참석자: 곽희범 (andrew@norux.me) + * 임채훈 (im.fehead@gmail.com) + * 박종성 (@minidump) + * 안종찬 (ahnchan2@gmail.com) + * 김건용 (gykim0914@gmail.com) + * 권세홍 (sehongkwon2.24@gmail.com) + * 조훈근 (hoonycho12@gmail.com) + * 김민호 (8891m@naver.com) + * 정종채 (fynia@naver.com) + * 김문영 (m03y29@gmail.com) + * + * 참석인원: 10 명 + * + * http://www.iamroot.org/xe/Kernel_10_ARM/178300 + * + * ================================================================== + */ /* * Convert and fold provided ATAGs into the provided FDT. * @@ -104,20 +204,48 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt + * + * atags의 내용을 fdt에 변환하여 넣는다. + * + * head.S 소스 restart 라벨 근처에서 호출됨 + * in atags_list atags 주소 0x00000100 + * out fdt dtb의 주소 .bss 주소 + * in total_space 32KB <= (dtb_totalsize * 1.5) <= 1MB */ + /* fdt의 첫 4byte 값은 MAGIC_NUMBER이고 두번째 4byte 값은 fdt의 size */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ + /* TODO Bank? NR_BANKS:16 */ + /* + +-------------------------------------------+ + | | | | | | ... | | + +-------------------------------------------+ + + 64비트 머신에서는 uint64_t로 형변환해서 2칸씩 뛰게된다. + + Bank의 수는 16개, 16개까지 채울수 있다. + + Address start 과, 사이즈 값을 담을 배열이 필요하여 곱하기 2를 함 + + 64비트 머신에서는 Address값이 2칸이 필요함으로 곱하기 2를 함 + (reserve) + */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ + // 하위 두비트 값 확인 http://www.iamroot.org/xe/Kernel_10_ARM/178300 + // atag_list = 0x00000100 if ((u32)atag_list & 0x3) return 1; + /* IAMROOT-12D (2016-01-30): + * -------------------------- + * 만약, 이미 우리가 DTB를 가지고 있다면 리턴한다. + * 이는 에러가 아니라, 두 번째 restart를 돌고 있다는 의미이다. + */ /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; @@ -141,29 +269,68 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space) * the device tree and in the tags, the one from the * tags will be chosen. */ + /* + * do_extend_cmdline는 아래 config 가 들어가 있을때 1 + * ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND + * "Extend with bootloader kernel arguments" + * help + * The command-line arguments provided by the boot + * loader will be appended to the the device tree + * bootargs property. + * + * /arch/arm/boot/dts/ *.dts 파일 중 아래 옵션 + * chosen { + * bootargs = "console=ttyS0,115200 ubi.mtd=4 \ + */ + // 2015-11-21 시작할 위치 if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); + + /* if (atag->hdr.tag == ATAG_CMDLINE) */ } else if (atag->hdr.tag == ATAG_MEM) { + /* + uint32_t[64]배열 + sizeof(mem_reg_property) : 64 * 4 = 256 + 배열의 Entry 개수만 구한듯 + 4 -> sizeof(uint32_t) + 4는 버그같..? + 64비트일때의 고려가 되어있지 않음 + + continue: for_each_tag(atag, atag_list) + */ if (memcount >= sizeof(mem_reg_property)/4) + /* continue: 다음 태그를 읽음 */ continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); + /* 2cell이라면 64비트 */ + /* + mem_reg_property 에다가 Address start, Address Size를 + 차곡차곡 저장한다. + */ if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; + + /* 실제로는 아무 문제 없겠지만, + memcount는 코드상으로 63까지 가능하다. + memcount가 32이상이되면 아래의 메모리참조에서 + 에러가 날 가능성이 있다. + */ mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); + /* 32비트 */ } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); @@ -175,14 +342,41 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space) uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; + + /* + [example] + + chosen { + bootargs = "console=ttyS0 ip=on root=/dev/ram"; + linux,stdout-path = "/plb@0/serial@83e00000"; + + 현재는 아래 두 값이 없지만, 아래 함수에 의해 + 설정될 것이다. + linux,initrd-start = ; + linux,initrd-end = ; + } ; + */ setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } - } + } /* for_each_tag 종료 */ + + /* + memsize: 1(32bit) / 2(64bit) + mem_reg_property 실제 사이즈: (4 * memcount * memsize) + i.e. reg = <0x0 0x8000000 0x8000000 0x1000000>; + */ if (memcount) { + /* IAMROOT-12CD (2016-07-23): + * -------------------------- + * ATAGS [ATAG_MEM] size: 8000000, start: 0 + * memory { + * reg = <0x0 0x80000000>; + * }; + */ setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c index bd245d34..4acdde61 100644 --- a/arch/arm/boot/compressed/decompress.c +++ b/arch/arm/boot/compressed/decompress.c @@ -57,5 +57,10 @@ extern char * strstr(const char * s1, const char *s2); int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) { + /* IAMROOT-12D (2016-01-23): + * -------------------------- + * /lib/decompress_inflate.c 파일의 gunzip 함수로 이동됨. + * (#define decompress gunzip 로 선언되어 있기 때문) + */ return decompress(input, len, NULL, NULL, output, NULL, error); } diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 6bc4e0d3..e0f118fd 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -9,30 +9,23 @@ * ================================================================== */ /* ================================================================== - * 제 20주차 스터디 - * 날짜: 2015-09-05 + * 제 27주차 스터디 + * 날짜: 2015-11-07 * 장소: 커널 연구회 * * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) - * 참석자: 곽희범 (kh-1143@hanmail.net) - * 임채훈 (im.fehead@gmail.com) - * 한대현 (rhrnak0501@gmail.com) - * 민혜미 (mhyem2@naver.com) - * 김동현 (dhkim1027@gmail.com) - * 정종채 (fynia@naver.com) - * 김문영 (m03y29@gmail.com) - * 정성욱 (huber7908@gmail.com) - * 김일호 (lkimilhol@naver.com) - * 박창수 (darkpcs@gmail.com) - * 곽승준 (rialtoksj@yahoo.com) - * 배병휴 (isswindx@gmail.com) - * 김영준 (iam.yeongjunkim@gmail.com) - * 박종성 (@minidump) - * 박병배 (i.billpark@gmail.com) - * 안종찬 (ahnchan2@gmail.com) - * 이상선 (razr1121@gmail.com) - * - * 참석인원: 17 명 + * 참석자: 곽희범 (andrew@norux.me) + * 임채훈 (im.fehead@gmail.com) + * 박종성 (@minidump) + * 안종찬 (ahnchan2@gmail.com) + * 김건용 (gykim0914@gmail.com) + * 권세홍 (sehongkwon2.24@gmail.com) + * 조훈근 (hoonycho12@gmail.com) + * 김민호 (8891m@naver.com) + * 정종채 (fynia@naver.com) + * 김문영 (m03y29@gmail.com) + * + * 참석인원: 10 명 * ================================================================== */ /* @@ -53,14 +46,17 @@ * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-05 * ------------------------------------------------------------------ + * * a: application-cpu * m: micro controller * r: realtime * * AR_CLASS : CONFIG_CPU_V7M 일때 사용하지 않음 * M_CLASS : CONFIG_CPU_V7M 일때 사용 + * * ================================================================== */ + AR_CLASS( .arch armv7-a ) M_CLASS( .arch armv7-m ) @@ -79,6 +75,7 @@ * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-05 * ------------------------------------------------------------------ + * * CONFIG_CPU_V6, CONFIG_CPU_V6K, CONFIG_CPU_V7 이면 * * Coprocessor - CPU를 돕는 연산 장치 @@ -103,6 +100,7 @@ * * * writeb, r2, r3 ; r2에 문자가 들어있음, r3에 출력할 주소가 있음 + * * ================================================================== */ #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7) @@ -134,9 +132,11 @@ * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-05 * ------------------------------------------------------------------ + * * senduart: uart로 보낸다. (출력) rs-232c (시리얼포트) * * c-style: #define writeb(ch, rb) senduart \ch, \rb + * * ================================================================== */ .macro writeb, ch, rb @@ -147,6 +147,7 @@ * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-05 * ------------------------------------------------------------------ + * * 시리얼 포트의 메모리 주소 * SA1100: Strong Arm 1100 * - SA1100기준에서 시리얼포트0: 0x80000000 @@ -159,6 +160,7 @@ * * * loadsp, r3, r1 + * * ================================================================== */ #if defined(CONFIG_ARCH_SA1100) @@ -215,59 +217,74 @@ * 날짜: 2015-09-12 * ------------------------------------------------------------------ * debug_reloc_start 매크로 정의 + * 이하는 디버그 모드일경우, 관련 정보를 출력함 * - * ; 이하는 디버그 모드일경우, 관련 정보를 출력함 - * kputc #'\n' ; new line하나 찍기 + * kputc #'\n' + * ; new line하나 찍기 * - * kphex r6, 8 ; r6에는 프로세서 id가 들어있는 레지스터 - * ; 그 값을 16진수로 찍기 - * ; 8은 32비트.(r6의 크기) + * kphex r6, 8 + * ; r6에는 프로세서 id가 들어있는 레지스터 + * ; 그 값을 16진수로 찍기 + * ; 8은 32비트.(r6의 크기) * * #ifdef CONFIG_CPU_CP15 - * kputc #':' ; ':' 찍기 - * kphex r7, 8 ; 아키텍처 id 찍기 + * kputc #':' + * ; ':' 찍기 + * + * kphex r7, 8 + * ; 아키텍처 id 찍기 * * #ifdef CONFIG_CPU_CP15 - * kputc #':' ; ':' 찍기 - * mrc p15, 0, r0, c1, c0 ; mrc(REG값을 코프로세서에서 읽어온다) - * ; p15 : 코프로세서 15(mmu나 캐시를 설정하는 역할) - * ; 0 : 코프로세서의 명령어 - * ; : 이게 0일경우, 프로세서id를 가져오는 의미 - * ; r0 : 저장할 레지스터(dest) - * ; c1 : 주-레지스터 lhs (코프로세서 레지스터 넘버?) - * ; 시스템 제어에 사용되는 레지스터 - * ; (mpu 또는 캐시를 활성/비활성화 하는 역할) - * ; c0 : 부-레지스터 rhs (코프로세서 레지스터 넘버?) - * ; - * ; 가정) - * ; c1과 c0를 0오퍼레이션으로 수행한 후, r0에 그 결과를 저장?? - * ; 가정2) - * ; c1과 c0 코프로세서의 상태를 r0로 저장하는 것 - * - * ; 참고) endian configuration and control - * ; MRCp15, 0, r0, c1, c0 ; r0 := CP15 register 1 - * - * ; 참고) - * ; BAND의 "Summary of CP15 instructions"를 참고해주세요 - * ; 샘플의 주석: read control register cofiguration data - * - * ; 참고) - * ; mcr p14: 프로세스의 데이터를 코프로세서로 보냄 - * ; - jtag에서 사용하기 위해 - * ; - 그럼 jtag가 coprocessor의 레지스터에서 데이터를 읽어옴 - - * ; 결국, 코프로세서의 값을 읽어와서 찍는다 - * - * kphex r0, 8 ; 컨트롤 레지스터 값이 r0에 들어와서 16진수로 찍는다 - * kputc #'\n' ; 커널의 시작주소, 끝주소, 실행주소르 찍는다 - * kphex r5, 8 - * kputc #'-' - * kphex r9, 8 - * kputc #'>' - * kphex r4, 8 - * kputc #'\n' - * - * ; 질문) 주레지스터와 부레지스터가 어떤 의미/구분이 있냐? + * kputc #':' + * ; ':' 찍기 + * + * mrc p15, 0, r0, c1, c0 + * ; mrc(REG값을 코프로세서에서 읽어온다) + * ; p15: 코프로세서 15(mmu나 캐시를 설정하는 역할) + * ; 0: 코프로세서의 명령어 + * 이게 0일경우, 프로세서id를 가져오는 의미 + * ; r0: 저장할 레지스터(dest) + * ; c1: 주-레지스터 lhs(코프로세서 레지스터 넘버?) + * 시스템 제어에 사용되는 레지스터 + * (mpu 또는 캐시를 활성/비활성화 하는 역할) + * ; c0: 부-레지스터 rhs(코프로세서 레지스터 넘버?) + * + * ; 가정) + * ; c1과 c0를 0오퍼레이션으로 수행한 후, + * r0에 그 결과를 저장?? + * ; 가정2) + * ; c1과 c0 코프로세서의 상태를 r0로 저장하는 것 + * + * ; 참고) endian configuration and control + * ; MRCp15, 0, r0, c1, c0 ; r0 := CP15 register 1 + * + * ; 참고) + * ; BAND의 "Summary of CP15 instructions"를 참고 + * ; 샘플의 주석: read control register cofiguration data + * + * ; 참고) + * ; mcr p14: 프로세스의 데이터를 코프로세서로 보냄 + * - jtag에서 사용하기 위해 + * - 그럼 jtag가 coprocessor의 레지스터에서 + * 데이터를 읽어옴 + * + * ; 결국, 코프로세서의 값을 읽어와서 찍는다 + * + * kphex r0, 8 + * ; 컨트롤 레지스터 값이 r0에 들어와서 16진수로 찍는다. + * + * kputc #'\n' + * ; 커널의 시작주소, 끝주소, 실행주소르 찍는다 + * + * kphex r5, 8 + * kputc #'-' + * kphex r9, 8 + * kputc #'>' + * kphex r4, 8 + * kputc #'\n' + * + * ; 질문) 주레지스터와 부레지스터가 어떤 의미/구분이 있냐? + * * ================================================================== */ .macro debug_reloc_start @@ -296,14 +313,19 @@ * 날짜: 2015-09-12 * ------------------------------------------------------------------ * - * kphex r5, 8 ; 커널의 끝(?)을 16진수로찍기(end of kernel) + * kphex r5, 8 + * ; 커널의 끝(?)을 16진수로찍기(end of kernel) * - * mov r0, r4 ; r4: zImage(compressed kernel) 압축이 풀릴 시작 위치를 r0로 복사 + * mov r0, r4 + * ; r4: zImage(compressed kernel) 압축이 풀릴 시작 위치를 + * r0로 복사 * - * bl memdump ; dump 256 bytes at start of kernel + * bl memdump + * ; dump 256 bytes at start of kernel * * ================================================================== */ + .macro debug_reloc_end #ifdef DEBUG kphex r5, 8 /* end of kernel */ @@ -312,89 +334,169 @@ bl memdump /* dump 256 bytes at start of kernel */ #endif .endm + /* ================================================================== * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-19 * ------------------------------------------------------------------ * - * .section ".start", #alloc, #execinstr ; start section을 정의(start 분기 시작은 안함). - * ; 섹션 명칭 다음에 ,(콤마)로 구분하여 추가로 섹션의 특성? (할당, 실행)을 정의가 가능. - * .align ; 기본 4byte 기준으로 정렬. - * AR_CLASS( .arm ) ; Application/Realtime CPU일 때 .arm mode를 적용. - * ; This performs the same action as .code 32. - * ; .code[16/32] The value 16 selects Thumb, with the value 32 selecting ARM. - * - * ; [질문] .section 에 ".start"를 지정하는 것과 start: label의 차이? - * ; .start section을 실행가능하고 메모리 할당가능한 섹션에 위치시켜라. - * ; start: 는 일반적인 브랜치 label. - * - * start: ; start label 시작. - * .type start,#function ; start를 function으로 지정. - * .rept 7 ; 7번 반복매크로. - * mov r0, r0 ; r0 = r0 - * ; 즉, r0 = r0를 7번 반복. - * ; 7번 반복한 이유 : 처음에는 사람들이 pipeline을 비워두기 위한 것이라고 추측. - * ; 일반적인 start 주소는 0xnnnn8000에서 시작하는데 특정 부트로더에서는 - * ; 0xnnnn8020에서 시작하므로 0xnnnn8000으로 맞춰주기 위해서. - * ; iamroot 10차팀 9주차 정리 link에 내용 나와 있음 - * ; (http://neuromancer.kr/t/009-2013-06-22-arm-system-developers-guide-ch14/35) + * .section ".start", #alloc, #execinstr + * ; start section을 정의(start 분기 시작은 안함). + * ; 섹션 명칭 다음에 ,(콤마)로 구분하여 추가로 섹션의 + * 특성? (할당, 실행)을 정의가 가능. + * + * .align + * ; 기본 4byte 기준으로 정렬. + * + * AR_CLASS( .arm ) + * ; Application/Realtime CPU일 때 .arm mode를 적용. + * + * ; This performs the same action as .code 32. + * ; .code[16/32] The value 16 selects Thumb, with the + * value 32 selecting ARM. + * + * ; [질문] .section 에 ".start"를 지정하는 것과 + * start: label의 차이? + * ; .start section을 실행가능하고 메모리 할당가능한 섹션에 + * 위치시켜라. + * ; start: 는 일반적인 브랜치 label. + * + * start: + * ; start label 시작. + * + * .type start,#function + * ; start를 function으로 지정. + * + * .rept 7 + * ; 7번 반복매크로. + * + * mov r0, r0 + * ; r0 = r0 + * + * ; 즉, r0 = r0를 7번 반복. + * ; 7번 반복한 이유: 처음에는 사람들이 pipeline을 + * 비워두기 위한 것이라고 추측. + * ; 일반적인 start 주소는 0xnnnn8000에서 시작하는데 + * 특정 부트로더에서는 0xnnnn8020에서 시작하므로 + * 0xnnnn8000으로 맞춰주기 위해서. + * ; iamroot 10차팀 9주차 정리 link에 내용 나와 있음 + * ; (http://neuromancer.kr/t/009-2013-06-22-arm-system-developers-guide-ch14/35) * * .endr - * ARM( mov r0, r0 ) ; ARM mode에서 1번더 r0 = r0 - * ARM( b 1f ) ; 브랜치 1f - * THUMB( adr r12, BSYM(1f) ) ; THUMB mode에서 r12 = 1f + 1의 주소 - * ; #define BSYM(sym) sym + 1 => (/arch/arm/include/asm/unified.h) - * ; 왜 1을 더하는지에 대한 대답 아래 2개 주소사이트 참조 - * ; http://stackoverflow.com/questions/9368360/arm-thumb-using-bx-in-thumb-code-to-call-a-thumb-function-or-to-jump-to-a-thu - * ; http://recipes.egloos.com/5032032 - * ; +1을 더하는 이유는 THUMB 모드와 ARM 모드를 구분. - * ; (CPSR의 T bit가 1 이면 THUMB, 0이면 ARM) 이므로 최하위비트를 1로 만들어 THUMB 모드로 사용. - * ; T bit를 1과 0으로 자동 setting해 주는 명령어 bx(branch with exchange) - * ; bx라는 명령어에 jump할 주소를 주게 되는데, 그 주소가 홀수이면 T bit를 1로, 즉 Thumb mode로, 그 주소가 짝이면 T bit를 0 - * - * THUMB( bx r12 ) ; 위 BSYM을 통해 주소+1을 하여 홀수주소를 만들기 때문에 bx명령을 통해 CPSR의 T bit를 자동으로 1로 셋팅하여 THUMB 모드로 동작. - * .word _magic_sig @ Magic numbers to help the loader ; word단위로 _magic_sig를 주소저장 :: 0x016f2818 - * .word _magic_start @ absolute load/run zImage address ; word단위로 _maigc_start를 주소저장 :: zImage는 compressed kernel의 start 주소. - * .word _magic_end @ zImage end address ; word단위로 _maigc_end를 주소저장 :: zImage는 compressed kernel의 end 주소. - * .word 0x04030201 @ endianness flag ; word단위로 endiannesflag를 저장 :: 이 단계에서 big/little endian을 알수 없고 flag가 메모리에 올라갔을 때 첫 바이트가 0x01이면 little endian, 0x04이면 big endian로 검사해야 알 수 있다. - * - * THUMB( .thumb ) ; THUMB mode를 사용. - * - * 1: - * ARM_BE8( setend be ) @ go BE8 if compiled for BE8 ; CONFIG_CPU_ENDIAN_BE8 일 때 setend be 명령이 실행되어 big endian으로 사용하도록 설정. - ; 기본적으로 ARM CPU는 little endian을 사용. - * AR_CLASS( mrs r9, cpsr ) ; cpsr의 내용을 Arm register(r9)에 저장. - * #ifdef CONFIG_ARM_VIRT_EXT - * bl __hyp_stub_install @ get into SVC mode, reversibly ; to do 가상화 - * #endif - * mov r7, r1 @ save architecture ID ; r7 = r1 - * mov r8, r2 @ save atags pointer ; r8 = r2 - * ; [질문] atags pointer는 무엇인가요? - * ; => bootloader에서 linux kernel로 설정을 전달하는 pointer. - * ; [질문] r1, r2는 어디서 나온 것인가요? - * ; => bootloader에서 linux kernel로 전달된다. - * - * #ifndef CONFIG_CPU_V7M - * mrs r2, cpsr @ get current mode ; cpsr의 내용을 r2에 저장. - * tst r2, #3 @ not user? ; cpsr의 하위 2bit(mode bit)를 비교하여 user mode인지 체크. (tst :: test) - * bne not_angel ; cpsr의 하위 2bit가 11이 아니면(user mode가 아니면_인터럽트 제외) not_angel로 브랜치. - * ; [질문] angel이 무엇인가? - * ; => 부트로더 종류 중 하나로 angel 부트로더를 말함. - * mov r0, #0x17 @ angel_SWIreason_EnterSVC ; r0 = 0x17 - * ; [질문] # 또는 operand 2는 barrel shifter를 통해 전달되는데 barrel shifter는 어떤 동작을 하나? - ; [질문] 왜 0x17값을 넣는가? - * ARM( swi 0x123456 ) @ angel_SWI_ARM - * THUMB( svc 0xab ) @ angel_SWI_THUMB - * ; 링크 참조 :: - * ; 1. http://trace32.com/wiki/index.php/SemiHosting_%EA%B3%BC_%EA%B7%B8_%ED%99%9C%EC%9A%A9 - * ; 2. http://egloos.zum.com/recipes/v/5037342 - * ; 3. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0282b/BGBJHIEA.html - * not_angel: - * safe_svcmode_maskall r0 ; Helper macro to enter SVC mode cleanly and mask interrupts. + * ARM( mov r0, r0 ) + * ; ARM mode에서 1번더 r0 = r0 + * + * ARM( b 1f ) + * ; 브랜치 1f + * + * THUMB( adr r12, BSYM(1f) ) + * ; THUMB mode에서 r12 = 1f + 1의 주소 + * ; #define BSYM(sym) sym + 1 + * 참조 => (/arch/arm/include/asm/unified.h) + * + * ; 왜 1을 더하는지에 대한 대답 아래 2개 주소사이트 참조 + * ; http://stackoverflow.com/questions/9368360/arm-thumb-using-bx-in-thumb-code-to-call-a-thumb-function-or-to-jump-to-a-thu + * ; http://recipes.egloos.com/5032032 + * + * ; +1을 더하는 이유는 THUMB 모드와 ARM 모드를 구분. + * ; (CPSR의 T bit가 1 이면 THUMB, 0이면 ARM) 이므로 + * 최하위비트를 1로 만들어 THUMB 모드로 사용. + * ; T bit를 1과 0으로 자동 setting해 주는 명령어 + * bx(branch with exchange) + * ; bx라는 명령어에 jump할 주소를 주게 되는데, + * 그 주소가 홀수이면 T bit를 1로, 즉 Thumb mode로, + * 그 주소가 짝이면 T bit를 0 + * + * THUMB( bx r12 ) + * ; 위 BSYM을 통해 주소+1을 하여 홀수주소를 만들기 때문에 + * bx명령을 통해 CPSR의 T bit를 자동으로 1로 셋팅하여 + * THUMB 모드로 동작. + * + * .word _magic_sig @ Magic numbers to help the loader + * ; word단위로 _magic_sig를 주소저장: 0x016f2818 + * + * .word _magic_start @ absolute load/run zImage address + * ; word단위로 _maigc_start를 주소저장: zImage는 + * compressed kernel의 start 주소. + * + * .word _magic_end @ zImage end address + * ; word단위로 _maigc_end를 주소저장: zImage는 compressed + * kernel의 end 주소. + * + * .word 0x04030201 @ endianness flag + * ; word단위로 endiannesflag를 저장: 이 단계에서 + * big/little endian을 알수 없고 flag가 메모리에 올라갔을 + * 때 첫 바이트가 0x01이면 little endian, 0x04이면 big + * endian로 검사해야 알 수 있다. + * + * THUMB( .thumb ) + * ; THUMB mode를 사용. + * + * 1: + * ARM_BE8( setend be ) @ go BE8 if compiled for BE8 + * ; CONFIG_CPU_ENDIAN_BE8 일 때 setend be 명령이 실행되어 + * big endian으로 사용하도록 설정. + * ; 기본적으로 ARM CPU는 little endian을 사용. + * + * AR_CLASS( mrs r9, cpsr ) + * ; cpsr의 내용을 Arm register(r9)에 저장. + * + * #ifdef CONFIG_ARM_VIRT_EXT + * bl __hyp_stub_install @ get into SVC mode, reversibly + * ; to do 가상화 + * + * #endif + * mov r7, r1 @ save architecture ID + * ; r7 = r1 + * + * mov r8, r2 @ save atags pointer + * ; bootloader로부터 atag 위치를 전달받음. + * ; r8 = r2 + * + * ; [질문] atags pointer는 무엇인가요? + * ; => bootloader에서 linux kernel로 설정을 전달하는 + * pointer. + * ; [질문] r1, r2는 어디서 나온 것인가요? + * ; => bootloader에서 linux kernel로 전달된다. + * + * #ifndef CONFIG_CPU_V7M + * mrs r2, cpsr @ get current mode + * ; cpsr의 내용을 r2에 저장. + * + * tst r2, #3 @ not user? + * ; cpsr의 하위 2bit(mode bit)를 비교하여 user mode인지 + * 체크. (tst :: test) + * + * bne not_angel + * ; cpsr의 하위 2bit가 11이 아니면(user mode가 아니면 + * 인터럽트 제외) not_angel로 브랜치. + * + * ; [질문] angel이 무엇인가? + * ; => 부트로더 종류 중 하나로 angel 부트로더를 말함. + * + * mov r0, #0x17 @ angel_SWIreason_EnterSVC + * ; r0 = 0x17 + * + * ; [질문] # 또는 operand 2는 barrel shifter를 통해 + * 전달되는데 barrel shifter는 어떤 동작을 하나? + * + * ; [질문] 왜 0x17값을 넣는가? + * + * ARM( swi 0x123456 ) @ angel_SWI_ARM + * THUMB( svc 0xab ) @ angel_SWI_THUMB + * ; 링크 참조: + * 1. http://trace32.com/wiki/index.php/SemiHosting_%EA%B3%BC_%EA%B7%B8_%ED%99%9C%EC%9A%A9 + * 2. http://egloos.zum.com/recipes/v/5037342 + * 3. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0282b/BGBJHIEA.html + * + * not_angel: + * safe_svcmode_maskall r0 + * ; Helper macro to enter SVC mode cleanly and mask + * interrupts. * msr spsr_cxsf, r9 @ Save the CPU boot mode in * @ SPSR - * ; - * #endif + * #endif + * * ================================================================== */ @@ -469,79 +571,104 @@ not_angel: * ------------------------------------------------------------------ * * 참고 URL : http://iamroot.org/wiki/doku.php?id=kernel_original_12_a:%EB%B6%80%ED%8A%B8_%EA%B4%80%EB%A0%A8#zimage%EC%9D%98_%EC%8B%9C%EC%9E%91_%EC%9C%84%EC%B9%98_offset - *#ifdef CONFIG_AUTO_ZRELADDR ; Auto calculation of the decompressed kernel image address - * ; 자동 재배치 소스 - * ; http://stackcanary.com/?p=246 + * #ifdef CONFIG_AUTO_ZRELADDR + * ; Auto calculation of the decompressed kernel image + * address + * + * ; 자동 재배치 소스 + * ; http://stackcanary.com/?p=246 + * + * / * + * * <원문 주석> + * * Set up a page table only if it won't overwrite ourself. + * * That means r4 < pc || r4 - 16k page directory > &_end. + * * Given that r4 > &_end is most unfrequent, we add a rough + * * additional 1MB of room for a possible appended DTB. + * * / + * + * <번역> + * 중복된 영역이 아니라면 page table를 설정한다. + * r4가 pc 보다 작거나 r4 - 16k page directory 가 + * &_end보다 크다는 뜻이다. r4가 &_end보다 큰일은 거의 + * 없으며, DTB 추가가 가능하도록 1MB 정도의 빈공간(room)을 + * 추가한다. + * + * mov r4, pc + * and r4, r4, #0xf8000000 + * ; r4 = pc & 0xf8000000 + * + * add r4, r4, #TEXT_OFFSET + * ; r4 += TEXT_OFFSET + * ; TEXT_OFFSET : 0x00008000 + * ; arch/arm/Makefile + * ; TEXT_OFFSET := $(textofs-y) * - * / * - * * Set up a page table only if it won't overwrite ourself. - * * That means r4 < pc || r4 - 16k page directory > &_end. - * * Given that r4 > &_end is most unfrequent, we add a rough - * * additional 1MB of room for a possible appended DTB. - * - * 중복된 영역이 아니라면 page table를 설정한다. - * r4가 pc 보다 작거나 r4 - 16k page directory 가 &_end보다 크다는 뜻이다. - * r4가 &_end보다 큰일은 거의 없으며, DTB 추가가 가능하도록 1MB 정도의 빈공간(room)을 - * 추가한다. - * * / - * mov r4, pc ; - * and r4, r4, #0xf8000000 ; r4 = pc & 0xf8000000 - * add r4, r4, #TEXT_OFFSET ; r4 += TEXT_OFFSET - * ; TEXT_OFFSET : 0x00008000 - * ; arch/arm/Makefile - * ; TEXT_OFFSET := $(textofs-y) - * - *#else - * ldr r4, =zreladdr ; arch/arm/boot/compressed/Makefile - * ; LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR) - * ; arch/arm/boot/Makefile - * ; ZRELADDR := $(zreladdr-y) - * ; arch/arm/mach-bcm2709/Makefile.boot - * ; zreladdr-y := 0x00008000 - * - *#endif // CONFIG_AUTO_ZRELADDR - * - * mov r0, pc ; r0 = pc - * cmp r0, r4 ; cmp : r0 - r4 의 결과값을 cspr에 저장 - * - * ; Carry flag, Zero flag - * ; X | Y | X-Y | C | Z - * ; -----+-----+-----+-----+----- - * ; 0 | 0 | 0 | 1 | 1 - * ; 0 | 1 | -1 | 0 | 0 - * ; 1 | 0 | 1 | 1 | 0 - * ; 1 | 1 | 0 | 1 | 1 + * #else + * ldr r4, =zreladdr + * ; arch/arm/boot/compressed/Makefile + * ; LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR) + * ; arch/arm/boot/Makefile + * ; ZRELADDR := $(zreladdr-y) + * ; arch/arm/mach-bcm2709/Makefile.boot + * ; zreladdr-y := 0x00008000 + * + * #endif // CONFIG_AUTO_ZRELADDR + * + * mov r0, pc + * ; r0 = pc + * + * cmp r0, r4 + * ; cmp : r0 - r4 의 결과값을 cspr에 저장 + * + * ; Carry flag, Zero flag + * ; X | Y | X-Y | C | Z + * ; -----+-----+-----+-----+----- + * ; 0 | 0 | 0 | 1 | 1 + * ; 0 | 1 | -1 | 0 | 0 + * ; 1 | 0 | 1 | 1 | 0 + * ; 1 | 1 | 0 | 1 | 1 * - * ; ldr : load address - * ; cc : 조건문 carry clear - * ; ex1) r0 = 0000 r4 = 0001 - * ; r0 - r4 = -1(1111) 빌림 발생(Carray Clear) - * ; 0000 + 1111 - * ; ex2) r0 = 0001 r4 = 0000 - * ; r0 - r4 = 1(0001)빌림 발생 하지 않음(Carray Set) + * ; ldr : load address + * ; cc : 조건문 carry clear + * ; ex1) r0 = 0000 r4 = 0001 + * ; r0 - r4 = -1(1111) 빌림 발생(Carray Clear) + * ; 0000 + 1111 + * ; ex2) r0 = 0001 r4 = 0000 + * ; r0 - r4 = 1(0001)빌림 발생 하지 않음(Carray Set) * 0001 + 0000 - * ; furyheimdall.tistory.com/30 - * - * ldrcc r0, LC0+32 ; if(r0 < r4) { - * ; r0 = (LC0+32) - * addcc r0, r0, pc ; r0 += pc - * cmpcc r4, r0 ; if(r4 < r0) - * orrcc r4, r4, #1 ; r4 |= 1; // remember we skipped cache_on - * ; else - * ; cache_on(); - * ; } else { - * blcs cache_on ; cache_on(); - * ; } - * + * ; furyheimdall.tistory.com/30 + * + * ldrcc r0, LC0+32 + * addcc r0, r0, pc + * cmpcc r4, r0 + * orrcc r4, r4, #1 + * blcs cache_on + * ; + * ; if(r0 < r4) { + * ; r0 = (LC0+32) + * ; r0 += pc + * ; if(r4 < r0) + * ; r4 |= 1; // remember we skipped cache_on + * ; else + * ; cache_on(); + * ; } else { + * ; cache_on(); + * ; } + * + * ================================================================== */ + #ifdef CONFIG_AUTO_ZRELADDR + /* + * <원문> * ZRELADDR is the physical address where the decompressed kernel * image will be placed. If AUTO_ZRELADDR is selected, the address * will be determined at run-time by masking the current IP with * 0xf8000000. This assumes the zImage being placed in the first 128MB * from start of memory. * + * <번역> * ZRELADDR는 압축풀린 커널이 놓여질 물리 주소이다. AUTO_ZRELADDR 가 * 설정되어 있으면, 주소는 실시간에 현재 IP(pc ?)에 0xf8000000과 마스킹 * 해서 결정된다. zImage가 0MB ~ 128MB 안에 놓여진다고 가정한다. @@ -549,6 +676,7 @@ not_angel: * */ /* + * <원문 주석> * Find the start of physical memory. As we are executing * without the MMU on, we are in the physical address space. * We just need to get rid of any offset by aligning the @@ -566,6 +694,7 @@ not_angel: * of this range. */ /* + * <번역> * 물리메모리의 시작 주소를 찾는다. MMU를 사용중이지 않기 때문에 * 현재 물리 주소를 다루고 있다. * 주소정렬에 사용한 offset들을 제거할 필요가 있다. @@ -598,6 +727,17 @@ not_angel: * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-10-03 * ------------------------------------------------------------------ + * 날짜: 2015-10-31 + * 참석자: 곽희범 (andrew@norux.me) + * 임채훈 (im.fehead@gmail.com) + * 김영준 (iam.yeongjunkim@gmail.com) + * 박병배 (i.billpark@gmail.com) + * 안종찬 (ahnchan2@gmail.com) + * 권세홍 (sehongkwon2.24@gmail.com) + * 김민호 (8891m@naver.com) + * 곽승준 (rialtoksj@yahoo.com) + * + * 참석인원: 8 명 * * IAMROOT-12A: * ------------ @@ -615,35 +755,366 @@ not_angel: * _input_data_end-4 = 압축된 커널(piggy)의 마지막 어드레스를 의미함. * 데이터 내용은 압축된 커널의 길이. * - *restart: adr r0, LC0 ; r0 = &LC0 + * (참고URL) r0와 r1값의 차이 - 메모리 주소와 offset 값 + * http://www.iamroot.org/xe/Kernel_10_ARM/176234 + * + *restart: adr r0, LC0 + * ; r0 = &LC0 + * ; [2nd] r0에는 재정렬된(복사된) LC0(delta + 0x240)주소값 + * ; 이 들어간다. + * * ldmia r0, {r1, r2, r3, r6, r10, r11, r12} - * ; ldmia r0 주소에 있는 값을 차례로 다음 레지스터들에 - * ; 값을 저장하고 r0값을 증가 시킨다. ia : Increase After - * ; r1 = LC0 - * ; r2 = __bss_start - * ; r3 = _end - * ; r6 = _edata; - * ; r10 = input_data_end - 4 - * ; r11 = _got_start - * ; r12(ip) = _got_end - * ldr sp, [r0, #28] ; sp = .L_user_stack_end + * ; ldmia r0 주소에 있는 값을 차례로 다음 레지스터들에 + * ; 값을 저장한다. 만약, r0 뒤에 ! 기호가 있는경우는 + * ; r0값을 증가시켜 저장한다. ia : Increase After + * ; ldmia (load multiple increament after) + * + * ; (컴파일하여 확인해본 각 레지스터 값) + * ; r1 = LC0 (0x00000240 메모리주소) + * ; r2 = __bss_start (0x003d8a60 파일 offset값) + * ; r3 = _end (0x003d8a76 파일 offset값) + * ; r6 = _edata; (0x003d8a60 파일 offset값) + * ; r10 = input_data_end - 4 (0x003d8a22 파일 offset값) + * ; r11 = _got_start (0x003d8a34 파일 offset값) + * ; r12(ip) = _got_end (0x003d8a5c 파일 offset값) + * + * ldr sp, [r0, #28] + * ; sp = .L_user_stack_end (0x003d9a80 파일 offset값) + * + * <원문 주석> + * / * + * * We might be running at a different address. We need + * * to fix up various pointers. + * * / + * <번역> + * 다른 주소에서 실행되고 있으므로 다양한 포인터등을 고칠 + * 필요가 있다. * - * / * - * * We might be running at a different address. We need - * * to fix up various pointers. - * * - * * 다른 주소에서 실행되고 있으므로 다양한 포인터등을 고칠 필요가있다. - * * / * sub r0, r0, r1 @ calculate the delta offset - * ; r0 = r0 - r1 : &LC0 - &LC0 - * ; Q) delta 란 무엇인가? A) 0번지부터 이미지 최초위치 - * ; 12 A팀 부팅관련 문서 참고 + * ; r0 = r0 - r1 : &LC0(메모리 주소) - &LC0(파일 offset값) + * ; Q) delta 란 무엇인가? A) 0번지부터 램에 로드된 이미지 + * ; 최초위치 12 A팀 부팅관련 문서 참고 + * * add r6, r6, r0 @ _edata - * ; r6 = _edata + delta + * ; r6 = _edata + delta + * * add r10, r10, r0 @ inflated kernel size location - * ; r10 = input_data_end - 4 + delta + * ; r10 = input_data_end - 4 + delta + * + * (참조: 커널 ELF 헤더 정보) + * Section Headers: + * [Nr] Name Type Addr Off Size ES Flg Lk Inf Al + * [ 0] NULL 00000000 000000 000000 00 0 0 0 + * [ 1] .text PROGBITS 00000000 008000 003a94 00 AX 0 0 32 + * [ 2] .rodata PROGBITS 00003a94 00ba94 000cc4 00 A 0 0 4 + * [ 3] .piggydata PROGBITS 00004758 00c758 3d42ce 00 A 0 0 1 + * [ 4] .got.plt PROGBITS 003d8a28 3e0a28 00000c 04 WA 0 0 4 + * [ 5] .got PROGBITS 003d8a34 3e0a34 000028 00 WA 0 0 4 + * [ 6] .pad PROGBITS 003d8a5c 3e0a5c 000004 00 WA 0 0 1 + * [ 7] .bss NOBITS 003d8a60 3e0a60 00001c 00 WA 0 0 4 + * [ 8] .stack NOBITS 003d8a80 3e0a60 001000 00 WA 0 0 1 + * + * / * + * * The kernel build system appends the size of the + * * decompressed kernel at the end of the compressed data + * * in little-endian form. + * * / + * + * ; r10 이 가리키고 있는 메모리의 값을 big-endian 에서 + * little-endian 포맷으로 변경하는 작업 + * (참고URL) + * http://www.iamroot.org/xe/Kernel_10_ARM/176234 + * + * ldrb r9, [r10, #0] + * ldrb lr, [r10, #1] + * orr r9, r9, lr, lsl #8 + * ldrb lr, [r10, #2] + * ldrb r10, [r10, #3] + * orr r9, r9, lr, lsl #16 + * orr r9, r9, r10, lsl #24 + * + * #ifndef CONFIG_ZBOOT_ROM + * ; zImage(uImage, bzImage 포함)는 보통 SDRAM에 로딩하고 + * ; 그 후 실행되지만 그렇지 않고 바로 ROM/Flash에서 + * ; 동작시킬 수 있는데 이 때 커널 빌드 시 + * ; CONFIG_ZBOOT_ROM 옵션을 사용한다. + * ; #ifndef 이므로 설정되어있지 않으면 이하 2라인이 + * 수행된다. + * + * / * malloc space is above the relocated stack (64k max) * / + * + * ; 압축 커널 이미지의 이동을 위해, Stack Pointer 위에 + * ; 64k 크기의 버퍼를 할당하여 여유공간을 두기 위함. + * + * add sp, sp, r0 + * add r10, sp, #0x10000 + * #else + * + * / * + * * With ZBOOT_ROM the bss/stack is non relocatable, + * * but someone could still run this code from RAM, + * * in which case our reference is _edata. + * * / + * mov r10, r6 + * #endif + * + * mov r5, #0 @ init dtb size to 0 + * + * #ifdef CONFIG_ARM_APPENDED_DTB + * ldr lr, [r6, #0] + * ; lr = *(r6 + 0) + * ; lr에는 DTB의 매직넘버가 저장된다. * + * #ifndef __ARMEB__ + * ldr r1, =0xedfe0dd0 @ sig is 0xd00dfeed big endian + * ; little endian 사용시 + * + * #else + * ldr r1, =0xd00dfeed + * ; big endian 사용시 + * + * #endif + * cmp lr, r1 + * ; if(lr != r1) goto dtb_check_done; + * + * bne dtb_check_done @ not found + * ; dtb_check_done은 dtb가 없는 경우이고, 아무작업도 하지 + * 않음. + * + * + * #ifdef CONFIG_ARM_ATAG_DTB_COMPAT + * / * + * * OK... Let's do some funky business here. + * * If we do have a DTB appended to zImage, and we do have + * * an ATAG list around, we want the later to be translated + * * and folded into the former here. No GOT fixup has occurred + * * yet, but none of the code we're about to call uses any + * * global variable. + * * / + * + * / * Get the initial DTB size * / + * + * ; (참고URL) 현재까지의 메모리 맵 - 대박자료 + * ; http://www.iamroot.org/xe/Kernel_10_ARM/178300 + * + * < 2015-11-07 시작예정 > + * + * ldr r5, [r6, #4] + * ;r5에 dtb의 첫번째 data값을 넣는다. + * ;r6의 +4값은 dtb의 사이즈를 의미하는것으로 생각됨. + * #ifndef __ARMEB__ + * ;big endian이 아닐때 우리는 __ARMEB__가 정의되어 있지 + * ;않으므로 여기를 타게 됨 + * * convert to little endian * + * eor r1, r5, r5, ror #16 + * ;r1=(r5)^(r5>>16) ;rotate는 + * bic r1, r1, #0x00ff0000 + * ;r1 = r1 & !(0x00ff0000) + * mov r5, r5, ror #8 + * ;r5 = r5 >> 8 + * eor r5, r5, r1, lsr #8 + * ;r5 = r5 ^ (r1 >> 8) + * ;여기까지 r5의 빅엔디안 -> 리틀엔디안 수정작업 + * ;ex) r5 = 0x12345678 -> r5 = 0x78563412 + * #endif + * * 50% DTB growth should be good enough * + * add r5, r5, r5, lsr #1 + * ;r5 = r5 + (r5 >> 1) + * * preserve 64-bit alignment * + * add r5, r5, #7 + * ;r5 = r5 + 7 + * bic r5, r5, #7 + * ;r5 = r5 & !(0b...111) + * ;8올림 연산을 수행하여 값이 8의 배수가 되게함 + * * clamp to 32KB min and 1MB max * + * cmp r5, #(1 << 15) + * ;r5와 32k를 비교 + * movlo r5, #(1 << 15) + * ;r5 = 32k lo=미만 + * cmp r5, #(1 << 20) + * ; r5와 1MB를 비교 + * movhi r5, #(1 << 20) + * ;r5 = 1Mb 초과 hi=초과 + * * temporarily relocate the stack past the DTB work space * + * add sp, sp, r5 + * ;sp = sp+r5 DTB사이즈만큼 그위에 스택위치도 수정되야함 + * stmfd sp!, {r0-r3, ip, lr} + * + * ;http://recipes.egloos.com/5059742 //stack명령 참고 + * + * ;stmfd + * ;ex) sp = 0x5400, r0=1, r1= 2, r2=3, r3=4, ip=7, lr=8 + * stm명령 수행후 sp값은 아래와 같이 됩니다. + * 바뀐 sp=> | r0 + * | r1 + * | r2 + * | r3 + * | ip + * | lr + * 기존 sp = 0x5400 | + * + * mov r0, r8 + * ;r8은 기존에 atag pointer가 저장되어 있음. + * mov r1, r6 + * ;r6은 DTB를 가리키는 edata값 + * mov r2, r5 + * ;r5는 32KB <= (dtb_totalsize * 1.5) <= 1MB + * bl atags_to_fdt + * ;c함수로 점프 + * ; 2015-12-05 분석 완료. + * ; atgs의 내용을 fdt 로 변환하여 내용을 채운다. + * ;int atags_to_fdt(void *atag_list, void *fdt, int total_space) + * + * + * * If returned value is 1, there is no ATAG at the location + * * pointed by r8. Try the typical 0x100 offset from start + * * of RAM and hope for the best. + * * + * cmp r0, #1 + * ; atgs_to_fdt의 리턴값(r0)이 1인지 비교한다. + * ; 1이 리턴되는 경우는, atag를 찾지 못했을 경우이다. + * + * sub r0, r4, #TEXT_OFFSET + * ; r4에는 0x8000 정도가 들어있을 것이다. + * ; r0 = r4 - TEXT_OFFSET => 0또는 1(캐시온 보류시) + * + * bic r0, r0, #1 + * ; CacheOn 보류시 설정되는 1을 제거 + * + * add r0, r0, #0x100 + * ; 0x100: atag의 위치 + * + * mov r1, r6 + * ; r6은 DTB를 가리키는 edata값 + * + * mov r2, r5 + * ; r5는 DTB의 total space + * + * bleq atags_to_fdt + * ; r8에 atag 포인터가 담겨있지 않았다면, 직접 0x100을 + * ; 세팅하여 재시도한다. 일반적으로 atag는 0x100에 있기 + * ; 때문이다. + * ; + * ; [Like C Style] + * ; r0 = r8; r1 = r6; r2 = r5; + * ; r0 = atags_to_fdt( r0, r1, r2 ); + * ; if( r0 == 1 ) + * ; { + * ; r0 = 0x100; r1 = r6; r2 = r5; + * ; r0 = atags_to_fdt( r0, r1, r2 ); + * ; } + * + * ldmfd sp!, {r0-r3, ip, lr} + * ; 위에서 저장한 ( stmfd sp!, {r0-r3, ip, lr} ) + * ; Register들을 복원한다. (push-pop) + * + * sub sp, sp, r5 + * ; sp = sp - DTB Total Size + * ; 위에서 더했던 ( add sp, sp, r5 ) + * ; sp를 복원한다. + *#endif + * + * mov r8, r6 @ use the appended device tree + * ; r6은 DTB를 가리키는 edata값 + * + * [원문 주석] + * Make sure that the DTB doesn't end up in the final + * kernel's .bss area. To do so, we adjust the decompressed + * kernel size to compensate if that .bss size is larger + * than the relocated code. + * + * [번역] + * DTB가 최종적인 커널의 .bss 영역에 포함되지 않는 것을 보장해야 + * 한다. + * .bss사이즈가 재배치될 코드보다 크다면, 이를 맞춰주기 위해 + * decompressed 커널의 사이즈를 조정한다. + * + * ldr r5, =_kernel_bss_size + * ; kernel_bss_size(압축풀린 커널 bss size)를 r5에 담는다. + * + * adr r1, wont_overwrite + * ; wont_overwrite(wont_overwrite 이하의 영역에는 + * ; 덮어쓰기 해도 상관 없음)의 주소를 r1에 로드한다. + * + * sub r1, r6, r1 + * subs r1, r5, r1 + * ; r6: 압축된 커널 bss_start + * ; r5: 압축 풀린 커널 bss size + * ; r1 = _kernel_bss_size - (bss_start - wont_overwrite) + * addhi r9, r9, r1 + * ; if(r1 > 0) + * ; r9 = r9 + r1; + * ; r9: decompressed kernel size + * ; 압축풀린 커널 bss사이즈가 재배치될 zImage 사이즈보다 + * ; 크다면, r9을 조정한다. + * + * / * Get the current DTB size * / + * ldr r5, [r6, #4] + * ; r6의 첫 4바이트는 매직값, + * ; 그 다음 4바이트가 dtb_total_size + * + *#ifndef __ARMEB__ + * / * convert r5 (dtb size) to little endian * / + * eor r1, r5, r5, ror #16 + * bic r1, r1, #0x00ff0000 + * mov r5, r5, ror #8 + * eor r5, r5, r1, lsr #8 + *#endif + * + * / * preserve 64-bit alignment * / + * add r5, r5, #7 + * bic r5, r5, #7 + * + * / * relocate some pointers past the appended dtb * / + * add r6, r6, r5 + * ; dtb 끝(dtb_start + dtb_size) + * ; 기존 r6 는 bss 시작점인 동시에 DTB 시작점 이었으나, + * ; 이 코드에서부터 bss 시작점만을 가리키게 된다. + * + * add r10, r10, r5 + * ; r10 = end of this image, including bss/stack/malloc + * space if non XIP + * ; r5(dtb사이즈를 기존에는 알 수 없었기 때문에, r10에도 + * 반영이 되어있는 상황은 아닐 것이다. 이제 dtb size를 + * 구해와서 알게됐으므로, r10에 반영한다.) + * add sp, sp, r5 + * ; sp도 마찬가지로, r5를 더해서 늘려준다. + * + * + * + * +-----------------------+ <- r10 + * | buffer(64K),heap 영역 | (848라인) add r10, sp, #0x10000 + * +-----------------------+ <- sp + * | stack | + * +-----------------------+ + * | bss | + * +-----------------------+ <- r6 + * | | + * | D T B | r5 = 갱신된 DTB size + * | | + * |Magic|TotalSize|.. |.. | + * +-----------------------+ <- DTB 시작 + * | | + * | | + * | | - 해결되지 않은 의문점 + * | K e r n e l | _kernal_bss_size 가 zImage 보다 작을 경우, + * | | DTB 가 복사될 위치가 _kernel_bss 마지막 영역과 + * | (compressed) | 일치하지 않게 되는데, 이 때의 처리가 아직없다. + * | | + * | | + * +-----------------------+ + * | Page Table | + * +-----+-----------------+ + * | | Atag | + * | +-----------------+ + * | | + * +-----------------------+ + * + *dtb_check_done: + *#endif + * ================================================================== */ + restart: adr r0, LC0 ldmia r0, {r1, r2, r3, r6, r10, r11, r12} ldr sp, [r0, #28] @@ -767,6 +1238,13 @@ restart: adr r0, LC0 sub sp, sp, r5 #endif + /* IAMROOT-12D (2016-01-30): + * -------------------------- + * 처음에 돌때 atag이 담겨있는 r8레지스터에 DTB를 담는다. + * 따라서 restart때, 두 번째 atags_to_fdt()를 수행하는 것이 + * 아니다. r8에는 DTB가 담겨있기때문에 함수를 수행하지않고 + * 진행되게 된다. + */ mov r8, r6 @ use the appended device tree /* @@ -802,6 +1280,26 @@ restart: adr r0, LC0 dtb_check_done: #endif + +/* IAMROOT-12D (2015-12-19): + * ------------------------- + * 오늘부터 위와 같이 주석 탭플릿을 변경해서 사용하고자 합니다. + * - 기존: 코드 블록을 복사해서 주석을 그 안에 추가 + * - 변경: 원본 소스 블록 사이에 주석을 추가 + * + * ------------------------- + * 현재 상태는 다음과 같고 + * r4 = 최종 커널의 주소(커널이 풀려질 주소, 0x8000) + * r9 = 압축이 풀릴 이미지의 크기 + * r10= 압축된 커널 이미지의 끝 주소 + * 지금 하려고 하는건 + * (r4 - 16k) >= r10 + * (r4 + image length) <= &wont_overwrite + * + * @TODO: 그런데 Note에서 적혀진 내용에서 + * r4의 LSB(최하위 비트)가 있다면(?) 좋지 않다는건지 의미가 궁금함 + */ + /* * Check to see if we will overwrite ourselves. * r4 = final kernel address (possibly with LSB set) @@ -812,6 +1310,18 @@ dtb_check_done: * r4 + image length <= address of wont_overwrite -> OK * Note: the possible LSB in r4 is harmless here. */ + + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * r10 += 16k; + * if(r4 >= r10) + * goto wont_overwrite; + * + * r10 = r4 + r9 + * r9 = &wont_overwrite; + * if( r10 <= r9) + * goto wont_overwrite; + */ add r10, r10, #16384 cmp r4, r10 bhs wont_overwrite @@ -820,6 +1330,16 @@ dtb_check_done: cmp r10, r9 bls wont_overwrite +/* IAMROOT-12D (2015-12-19): + * ------------------------- + * http://iamroot.org/wiki/doku.php?id=kernel_original_12_a:%EB%B6%80%ED%8A%B8_%EA%B4%80%EB%A0%A8 + * @TODO: 그림 "4) 1st start ~ relocation 수행 과정"에서 "Target커널의 끝에 약간의 + * 공간 확보"라는 내용이 있는데, 이게 오해한거 아니냐?는 의견이 나옴 + * (r10에 16k를 더한걸 약간의 공간이라고?) -> 검토 필요 + * + * r6 = _edata, 재배치전의 zImage의 끝 주소와 동일 + * r10 = 압축이 풀릴 커널의 끝 주소 + */ /* * Relocate ourselves past the end of the decompressed kernel. * r6 = _edata @@ -827,6 +1347,12 @@ dtb_check_done: * Because we always copy ahead, we need to do it from the end and go * backward in case the source and destination overlap. */ + + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * 재배치시킬 zImage와 압축이 풀릴 커널이 서로 겹치지 않도록 약 + * 간의 공간을 확보 (256바이트 영역을 인접시킴(bump)) + */ /* * Bump to the next 256-byte boundary with the size of * the relocation code added. This avoids overwriting @@ -835,10 +1361,18 @@ dtb_check_done: add r10, r10, #((reloc_code_end - restart + 256) & ~255) bic r10, r10, #255 + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * restart 주소를 가져와서 4byte얼라인 시킴 + */ /* Get start of code we want to copy and align it down. */ adr r5, restart bic r5, r5, #31 +/* IAMROOT-12D (2015-12-19): + * ------------------------- + * 아래 코드(가상화)는 생략함 + */ /* Relocate the hyp vector base if necessary */ #ifdef CONFIG_ARM_VIRT_EXT mrs r0, spsr @@ -853,17 +1387,62 @@ dtb_check_done: 1: #endif + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * r6 = _edata; + * r5 = &restart;(4바이트 정렬) + * r9 = r6 - r5; (zImage + DTB = 복사할 zImage의 크기) + * r9 += 31; (32바이트 정렬을 위해 round up계산) + * (8개의 레지스터 단위로 블록 복사하기 아래쪽에 나옴) + * r9 ~= 31; + * r6 = r9 + r5; (초기 _edata에서 얼라인 적용만큼 살짝 변경된 값) + * r9 += r10; (압축풀릴 커널 끝 주소 + 재배치될 zImage + DTB를 + * 더한 끝 위치) + */ sub r9, r6, r5 @ size to copy add r9, r9, #31 @ rounded up to a multiple bic r9, r9, #31 @ ... of 32 bytes add r6, r9, r5 add r9, r9, r10 -1: ldmdb r6!, {r0 - r3, r10 - r12, lr} + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * ldmdb(load register muliple decrement before) + * r6가 가리키고 있는 주소에 r0~r3, r10~r12, lr를 읽어와서 r9이 + * 가리키고 있는 주소로럭 블록 복사하는 루프 (그래서 32바이트 정 + * 렬이 필요했음) 아래 루프가 끝나면 zImage는 재배치 영역으로 복 + * 사 완료됨 + * + * do { + * r0 = *(--r6); + * r1 = *(--r6); + * r2 = *(--r6); + * r3 = *(--r6); + * r10 = *(--r6); + * r11 = *(--r6); + * r12 = *(--r6); + * lr = *(--r6); + * + * *(--r9) = *r0; + * *(--r9) = *r1; + * *(--r9) = *r2; + * *(--r9) = *r3; + * *(--r9) = *r10; + * *(--r9) = *r11; + * *(--r9) = *r12; + * *(--r9) = *lr; + * } while( r6 > r5); + */ + 1: ldmdb r6!, {r0 - r3, r10 - r12, lr} cmp r6, r5 stmdb r9!, {r0 - r3, r10 - r12, lr} bhi 1b + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * r6 = r9 - r6; 재배치전 restart에서 재배치후 restart까지의 오 + * 프셋 + */ /* Preserve offset to relocated code. */ sub r6, r9, r6 @@ -872,12 +1451,55 @@ dtb_check_done: add sp, sp, r6 #endif + /* IAMROOT-12D (2016-01-09): + * ------------------------- + * 여기부터 시작 + */ bl cache_clean_flush + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * r0 = &restart; (재배치전 restart) + * r0 += r6; (결국 r0는 재배치된 restart의 주소가 됨) + * goto r0; (이로써 재배치된 restart에서 재시작) + */ adr r0, BSYM(restart) add r0, r0, r6 mov pc, r0 +/* IAMROOT-12D (2015-12-19): + * ------------------------- + * wont_overwirte 분석 시작 + * + * @TODO: + * 1.delta가 (다시) 뭐였죠? + * A조의 주석에서 발췌: + * r0에 현재 실행되는 상태의 LC0의 주소 값이 담기고, + * r1은 처음 이미지가 만들어질 때 당시의 주소 값(0을 기준으로)이 담겨 있고 + * 이 둘의 차이 값이 r0(delta) 값이 된다.이 델타 값으로 Image의 위치를 + * 가리키는 레지스터들을 보정하는데 사용한다. + * + * 2.GOT(global offset table)가 뭐죠? + * http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries + * elf의 데이터 섹션 헤더(section header)에 있는 멤버중 하나로, 모든 외부 함수의 주소 + * 를 저장하고 있는 테이블 + * + * 3.linked란 어떤걸 의미? + * (만약 delta가 0이라면, 링크된 주소에서 실행중이란 뜻) + * + * 4.LC0가 (역시) 뭐였죠? + * https://e4deen.wordpress.com/2014/06/21/39/ + * LC0 는 컴파일러가 임의로 만들어주는 지역레이블로서, 컴파일과 링크 등의 + * 과정을 거치면서 link script 를 통해 각 section 의 위치를 기록해두는 + * 레이블로 사용된다. 그리고, LC0 레이블이 위치해야할 주소값을 LC0 레이블의 + * 첫번째 word 에 기록해둔다. + */ + +/* IAMROOT-12D (2016-01-23): + * -------------------------- + * 여기서 부터 + */ + wont_overwrite: /* * If delta is zero, we are running at the address we were linked at. @@ -892,6 +1514,13 @@ wont_overwrite: * r12 = GOT end * sp = stack pointer */ + + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * r1 = r0 | r5 (delta | 덧붙여진 dtb의 크기) + * if(r1 == 0) + * goto not_relocated; + */ orrs r1, r0, r5 beq not_relocated @@ -911,6 +1540,14 @@ wont_overwrite: * Relocate all entries in the GOT table. * Bump bss entries to _edata + dtb size */ + /* IAMROOT-12D (2016-01-23): + * -------------------------- + * got의 각 엔트리가 가리키는 영역이 bss 영역 이라면, + * DTB 사이즈만큼을 더하여 최종적으로 + * bss 영역이 되도록 조정한다. + * (바로 아래에서 bss 영역이 조정된다.) + * (got 엔트리를 하나씩 돌면서 영역 조정) + */ 1: ldr r1, [r11, #0] @ relocate entries in the GOT add r1, r1, r0 @ This fixes up C references cmp r1, r2 @ if entry >= bss_start && @@ -920,6 +1557,11 @@ wont_overwrite: cmp r11, r12 blo 1b + /* IAMROOT-12D (2016-01-23): + * -------------------------- + * bss 영역에 DTB size를 더하여 bss 영역 조정 + * bss 영역을 DTB 영역 위에 놓는다. + */ /* bump our bss pointers too */ add r2, r2, r5 add r3, r3, r5 @@ -939,6 +1581,16 @@ wont_overwrite: blo 1b #endif + + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * r2 = BSS start + * r3 = BSS end + * + * r0 = 0; + * while( r2 < r3) + * ++r2 = r0; + */ not_relocated: mov r0, #0 1: str r0, [r2], #4 @ clear bss str r0, [r2], #4 @@ -947,6 +1599,25 @@ not_relocated: mov r0, #0 cmp r2, r3 blo 1b + /* IAMROOT-12D (2015-12-19): + * ------------------------- + * r4 = kernel execution address (possibly with LSB set) + * tst: AND 논리 연산을 이용한 비교명령어 + * teq: OR 논리 연산을 이용한 비교명령어 + * blne: branch link register if not equal(z플래그 확인. 즉, 0이 + * 아니면) + * + * if((r4 & 1) != 0) { + * r4 &= ~1; + * goto cache_on; + * } + * + * 질문:그런데 왜 LSB(최하위 비트)가 1일때하고 비교를 하나요? + * 예전에 start레이블 내에서 cache_on을 검사한 루틴이 있는데, + * 당시에 중복 영역이 있다면 cache_on을 보류(skipped)하기위해서 + * LSB를 1로 설정했었다. 해서 bic로 LSB값을 다시 초기화 한다. + * (이해가 안되면 아래 주석을 반드시 참고하세요) + */ /* * Did we skip the cache setup earlier? * That is indicated by the LSB in r4. @@ -1019,8 +1690,7 @@ params: ldr r0, =0x10000100 @ params_phys for RPC * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-10-03 * ------------------------------------------------------------------ - */ -/* + * * Turn on the cache. We need to setup some page tables so that we * can have both the I and D caches on. * @@ -1040,12 +1710,18 @@ params: ldr r0, =0x10000100 @ params_phys for RPC * cache 를 ON시킴. I(Instruction Cache), D(Data Cache) * 커널 실행 주소로부터 아래로 16k에 page table을위치시킨다. * - * .align 5 ; 32Byte 정렬 - * ; TODO: align이 뭔지 애매하다?? + * .align 5 + * ; 32Byte 정렬 + * ; TODO: align이 뭔지 애매하다?? + * *cache_on: mov r3, #8 @ cache_on function - * ; ? #8 : cache on + * ; ? #8 : cache on + * * b call_cache_fn + * + * ================================================================== */ + .align 5 cache_on: mov r3, #8 @ cache_on function b call_cache_fn @@ -1120,125 +1796,279 @@ __armv3_mpu_cache_on: /* ================================================================== * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) - * 날짜: 2015-10-10 + * 날짜: 2015-10-10 * 날짜: 2015-10-17 * ------------------------------------------------------------------ * + * Cache Cash : http://recipes.egloos.com/5170809 * MMU 에 대한 설명 : http://recipes.egloos.com/5232056 - * 페이징 소스를 C 코드로 구현: http://kth3321.blogspot.kr/2013/04/arm-cortex-1.html + * 페이징 소스를 C 코드로 구현 : http://kth3321.blogspot.kr/2013/04/arm-cortex-1.html * 소스 관련 참고 : http://www.iamroot.org/xe/Kernel_10_ARM/174738 * - * ================================================================== * __setup_mmu: sub r3, r4, #16384 @ Page directory size - * ; r3 = r4 - 16384(16k) - * ; r4 = cache_on 에서 설정된 kernel execution address - * ; arm의 경우 1M 단위로 페이지 세팅하기 때문에 - * ; 2^32 = 4G는 총4096개의 - * ; 엔트리가 필요하고 한 엔트리는 32비트 워드이기 때문 - * ; 4096 * 4byte = 16k - * ; 0x8000 - 16k = 0x4000 모기향책 그림5-4 참고(66p) + * ; r3 = r4 - 16384(16k) + * ; r4 = cache_on 에서 설정된 kernel execution address + * ; arm의 경우 1M 단위로 페이지 세팅하기 때문에 + * ; 2^32 = 4G는 총4096개의 + * ; 엔트리가 필요하고 한 엔트리는 32비트 워드이기 때문 + * ; 4096 * 4byte = 16k + * ; 0x8000 - 16k = 0x4000 모기향책 그림5-4 참고(66p) + * * bic r3, r3, #0xff @ Align the pointer - * ; bit clear r3 = r3 & ~0xff + * ; bit clear r3 = r3 & ~0xff + * * bic r3, r3, #0x3f00 - * ; bit clear r3 = r3 & ~0x3f00 - * ; 왜 r3 & ~0x3fff 로 하지 않는가? - * ; 답) 명령어 operand로 8bit만 받을 수있어 - * ; 부득이 하게 2번 처리하는 것 - * ; 결국 하위 14bit를 지움, 16kB align을 위해 - * ; if r4 = 0x0000 8000, 최종적으로 r3 = 0x0000 4000 - * ; 참조)https://github.com/iamroot12b/kernel/issues/4 + * ; bit clear r3 = r3 & ~0x3f00 + * ; 왜 r3 & ~0x3fff 로 하지 않는가? + * ; 답) 명령어 operand로 8bit만 받을 수있어 + * ; 부득이 하게 2번 처리하는 것 + * ; 결국 하위 14bit를 지움, 16kB align을 위해 + * ; if r4 = 0x0000 8000, 최종적으로 r3 = 0x0000 4000 + * ; 참조)https://github.com/iamroot12b/kernel/issues/4 + * * Initialise the page tables, turning on the cacheable and bufferable * bits for the RAM area only. - * 오직 메모리 영역만에만 cacheable bufferable로 설정 - * 이것은 커널의 압축해제시 캐시와 쓰기버퍼사용을 통해서 압축해제 성능을 높이기 위함 + * 오직 메모리 영역만에만 cacheable bufferable로 설정 이것은 커널의 압축해제시, + * 캐시와 쓰기버퍼사용을 통해서 압축해제 성능을 높이기 위함 * 모기향 책 65p * * mov r0, r3 - * ; r0 = r3 - * ; r3 페이지 디렉토리 시작주소 0x0000 4000 - * ; 0100 0000 0000 0000 + * ; r0 = r3 + * ; r3 페이지 디렉토리 시작주소 0x0000 4000 + * ; 0100 0000 0000 0000 + * + * mov r9, r0, lsr #18 + * ; 000 0000 0000 0000 + * ; 2^18 = 256k + * ; r9 = r0 >> 18 + * ; r9 = 0 + * + * mov r9, r9, lsl #18 @ start of RAM + * ; r9 = r9 << 18 + * ; r9 = 0 + * + * add r10, r9, #0x10000000 @ a reasonable RAM size + * ; why? 265MB가 리눅스 구동하기 위한 최소한 메모리?? + * ; r10 = r9 + 256M + * ; r10 = End Of Ram + * + * mov r1, #0x12 @ XN|U + section mapping + * ; XN : http://www.iamroot.org/xe/Kernel_10_ARM/174738 + * ; #define XN (XN_MASK << XN_SHIFT) + * ; XN_MASK = 0x01, XN_SHIFT = 4 + * ; XN : MMU 접근권한 설정 + * ; r1 = 0x12 (10010)로 section entry table를 나타냄 + * ; When the XN bit is 1, a Permission fault is + * ; generated if the processor attempts to execute an + * ; instruction fetched from the corresponding memory + * ; region. + * ; Lv.1 Page Table Entry에서 U는 entry의 종류를 나타냄 + * ; 0b10은 section entry table을 나타냄 + * ; 0b11은 fine entry table을 나타냄 + * ; 0b01은 coarse entry table을 나타냄 + * ; 0b00은 page fault를 나타냄 + * + * orr r1, r1, #3 << 10 @ AP=11 + * ; AP (Access Permition)를 설정 + * ; AP는 11,10번 비트, Read & Write된다는 뜻 + * ; r1 = 0b10010 | 0b110000000000 + * ; r1 = 0xc12 (0b1100 0001 0010) + * + * add r2, r3, #16384 + * ; r2 = r3 + 16k + * ; r2 = Lv.1 PageTable의 끝, 밑 1:루프의 끝을 설정 + * + * 1: cmp r1, r9 @ if virt > start of RAM + * ; r9은 시작주소 + * ; 0xc12(AP = 11, XN|U = 10010) > r9 + * + * cmphs r10, r1 @ && end of RAM > virt + * ; r10 = 256MB + * ; hs (higher or same) + * ; if (r9 <= r1)면 수행됨 + * + * bic r1, r1, #0x1c @ clear XN|U + C + B + * ; r1 = 0xc12 (0b1100 0001 0010) + * ; 0x01c (0b0000 0001 1100) + * ; r1 = 0xc02 (0b1100 0000 0010) + * + * orrlo r1, r1, #0x10 @ Set XN|U for non-RAM + * ; if(r10 < r1)면 수행됨, r10 = end of Ram + * ; post fix lo는 Unsigned lower (identical to CC) + * + * orrhs r1, r1, r6 @ set RAM section settings + * ; if (r9 <= r1 < r10)면 orrhs가 수행됨 + * ; arch/arm/mm/Kconfig파일에 CPU_DCACHE_WRITETHROUGH + * ; 셋되어 있으면 CB_BITS = 0x08, 아니면 0x0c + * ; r6 = #CB_BITS | 0x02로 0x1E아니면 0x1A값을 가짐 + * + * str r1, [r0], #4 @ 1:1 mapping + * ; r0는 페이지 디렉토리 시작주소 0x0000 4000 + * ; *(r0 + 4) = r1 + * + * add r1, r1, #1048576 + * ; 1048576 = 0x100000 + * ; section table entry의 base address는 1M단위 + * + * teq r0, r2 + * ; r2 = Lv.1 PageTable의 끝, 끝까지 루프를 돌았나? + * + * bne 1b + * ; 아니면 1로 점프 + * ; r0 = r3 + * ; r3 페이지 디렉토리 시작주소 0x0000 4000 + * ; 0100 0000 0000 0000 + * * mov r9, r0, lsr #18 - * ; 000 0000 0000 0000 - * ; 2^18 = 256k - * ; r9 = r0 >> 18 - * ; r9 = 0 + * ; 000 0000 0000 0000 + * ; 2^18 = 256k + * ; r9 = r0 >> 18 + * ; r9 = 0 + * * mov r9, r9, lsl #18 @ start of RAM - * ; r9 = r9 << 18 - * ; r9 = 0 + * ; r9 = r9 << 18 + * ; r9 = 0 + * * add r10, r9, #0x10000000 @ a reasonable RAM size - * ; why? 265MB가 리눅스 구동하기 위한 최소한 메모리?? - * ; r10 = r9 + 256M - * ; r10 = End Of Ram + * ; why? 265MB가 리눅스 구동하기 위한 최소한 메모리?? + * ; r10 = r9 + 256M + * ; r10 = End Of Ram + * * mov r1, #0x12 @ XN|U + section mapping - * ; XN : http://www.iamroot.org/xe/Kernel_10_ARM/174738 - * ; #define XN (XN_MASK << XN_SHIFT) - * ; XN_MASK = 0x01, XN_SHIFT = 4 - * ; XN : MMU 접근권한 설정 - * ; r1 = 0x12 (10010)로 section entry table를 나타냄 - * ; When the XN bit is 1, a Permission fault is - * ; generated if the processor attempts to execute an - * ; instruction fetched from the corresponding memory - * ; region. - * ; Lv.1 Page Table Entry에서 U는 entry의 종류를 나타냄 - * ; 0b10은 section entry table을 나타냄 - * ; 0b11은 fine entry table을 나타냄 - * ; 0b01은 coarse entry table을 나타냄 - * ; 0b00은 page fault를 나타냄 + * ; XN : http://www.iamroot.org/xe/Kernel_10_ARM/174738 + * ; #define XN (XN_MASK << XN_SHIFT) + * ; XN_MASK = 0x01, XN_SHIFT = 4 + * ; XN : MMU 접근권한 설정 + * ; r1 = 0x12 (10010)로 section entry table를 나타냄 + * ; When the XN bit is 1, a Permission fault is + * ; generated if the processor attempts to execute an + * ; instruction fetched from the corresponding memory + * ; region. + * ; Lv.1 Page Table Entry에서 U는 entry의 종류를 나타냄 + * ; 0b10은 section entry table을 나타냄 + * ; 0b11은 fine entry table을 나타냄 + * ; 0b01은 coarse entry table을 나타냄 + * ; 0b00은 page fault를 나타냄 + * * orr r1, r1, #3 << 10 @ AP=11 - * ; AP (Access Permition)를 설정 - * ; AP는 11,10번 비트, Read & Write된다는 뜻 - * ; r1 = 0b10010 | 0b110000000000 - * ; r1 = 0xc12 (0b1100 0001 0010) + * ; AP (Access Permition)를 설정 + * ; AP는 11,10번 비트, Read & Write된다는 뜻 + * ; r1 = 0b10010 | 0b110000000000 + * ; r1 = 0xc12 (0b1100 0001 0010) + * * add r2, r3, #16384 - * ; r2 = r3 + 16k - * ; r2 = Lv.1 PageTable의 끝, 밑 1:루프의 끝을 설정 + * ; r2 = r3 + 16k + * ; r2 = Lv.1 PageTable의 끝, 밑 1:루프의 끝을 설정 + * * 1: cmp r1, r9 @ if virt > start of RAM - * ; r9은 시작주소 - * ; 0xc12(AP = 11, XN|U = 10010) > r9 + * ; r9은 시작주소 + * ; 0xc12(AP = 11, XN|U = 10010) > r9 + * * cmphs r10, r1 @ && end of RAM > virt - * ; r10 = 256MB - * ; hs (higher or same) - * ; if (r9 <= r1)면 수행됨 + * ; r10 = 256MB + * ; hs (higher or same) + * ; if (r9 <= r1)면 수행됨 + * * bic r1, r1, #0x1c @ clear XN|U + C + B - * ; r1 = 0xc12 (0b1100 0001 0010) - * ; 0x01c (0b0000 0001 1100) - * ; r1 = 0xc02 (0b1100 0000 0010) + * ; r1 = 0xc12 (0b1100 0001 0010) + * ; 0x01c (0b0000 0001 1100) + * ; r1 = 0xc02 (0b1100 0000 0010) + * * orrlo r1, r1, #0x10 @ Set XN|U for non-RAM - * ; if(r10 < r1)면 수행됨, r10 = end of Ram - * ; post fix lo는 Unsigned lower (identical to CC) + * ; if(r10 < r1)면 수행됨, r10 = end of Ram + * ; post fix lo는 Unsigned lower (identical to CC) + * * orrhs r1, r1, r6 @ set RAM section settings - * ; if (r9 <= r1 < r10)면 orrhs가 수행됨 - * ; arch/arm/mm/Kconfig파일에 CPU_DCACHE_WRITETHROUGH - * ; 셋되어 있으면 CB_BITS = 0x08, 아니면 0x0c - * ; r6 = #CB_BITS | 0x02로 0x1E아니면 0x1A값을 가짐 + * ; if (r9 <= r1 < r10)면 orrhs가 수행됨 + * ; arch/arm/mm/Kconfig파일에 CPU_DCACHE_WRITETHROUGH + * ; 셋되어 있으면 CB_BITS = 0x08, 아니면 0x0c + * ; r6 = #CB_BITS | 0x02로 0xE아니면 0xA값을 가짐 + * * str r1, [r0], #4 @ 1:1 mapping - * ; r0는 페이지 디렉토리 시작주소 0x0000 4000 - * ; *(r0 + 4) = r1 + * ; r0는 페이지 디렉토리 시작주소 0x0000 4000 + * ; *(r0 + 4) = r1 + * * add r1, r1, #1048576 - * ; 1048576 = 0x100000 - * ; section table entry의 base address는 1M단위 - * teq r0, r2 ; r2 = Lv.1 PageTable의 끝, 끝까지 루프를 돌았나? - * bne 1b ; 아니면 1로 점프 + * ; 1048576 = 0x100000 + * ; section table entry의 base address는 1M단위 + * + * teq r0, r2 + * ; r2 = Lv.1 PageTable의 끝, 끝까지 루프를 돌았나? + * + * bne 1b + * ; 아니면 1로 점프 + * * * If ever we are running from Flash, then we surely want the cache * to be enabled also for our execution instance... We map 2MB of it * so there is no map overlap problem for up to 1 MB compressed kernel. * If the execution is in RAM then we would only be duplicating the above. - * 2015-10-24 시작부분 + * * orr r1, r6, #0x04 @ ensure B is set for this + * ; B(Write Buffer)를 on + * ; r1 = 0x0E + * ; CPU_DCACHE_WRITETHROUGH에 독립적으로 B를 활성화 + * * orr r1, r1, #3 << 10 + * ; AP를 rw활성화 + * * mov r2, pc + * ; promgram counter를 r2에 대입 + * * mov r2, r2, lsr #20 + * ; r2 = r2 >> 20 + * ; base 주소를 얻기 위한 과정 + * * orr r1, r1, r2, lsl #20 + * ; r1 |= (r2 << 20) + * ; r1(0xC0E) + * ; 설정값과 base 주소를 조합하는 과정 + * * add r0, r3, r2, lsl #2 + * ; r3 = 0x4000 (page directory 시작 주소) + * ; r2 = base address + * ; r0 += (r2 << 2) + * ; result : r0 = 0x4000 + pc의 page entry의 주소 + * * str r1, [r0], #4 + * ; *r0 = r1 ; r0 += 4 + * * add r1, r1, #1048576 + * ; 다음 page entry 값 세팅 + * ; 1MB = #1048576 + * * str r1, [r0] + * ; *r0 = r1 + * * mov pc, lr + * ; C언어의 return + * ; pc = link register + * * ENDPROC(__setup_mmu) + * * ============================================================================= */ +/* ========================================================================== + * 제 27주차 스터디 + * 날짜: 2015-10-24 + * 장소: 커널 연구회 + * + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 참석자: 곽희범 (andrew@norux.me) + * 임채훈 (im.fehead@gmail.com) + * 민혜미 (mhyem2@naver.com) + * 김영준 (iam.yeongjunkim@gmail.com) + * 박종성 (@minidump) + * 박병배 (i.billpark@gmail.com) + * 안종찬 (ahnchan2@gmail.com) + * 김건용 (gykim0914@gmail.com) + * 권세홍 (sehongkwon2.24@gmail.com) + * 조훈근 (hoonycho12@gmail.com) + * + * 참석인원: 10 명 + * ==========================================================================*/ + __setup_mmu: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer bic r3, r3, #0x3f00 @@ -1319,47 +2149,169 @@ __armv4_mmu_cache_on: * ------------------------------------------------------------------ * __armv7_mmu_cache_on: * mov r12, lr - * ; r12 = lr + * ; r12 = lr + * * #ifdef CONFIG_MMU - * ; arch/arm/Kconfig - * ; config MMU - * ; bool "MMU-based Paged Memory Management Support" - * ; default y - * ; help - * ; Select if you want MMU-based virtualised - * ; addressing space - * ; support by paged memory management. - * ; If unsure, say 'Y'. + * ; arch/arm/Kconfig + * ; config MMU + * ; bool "MMU-based Paged Memory Management Support" + * ; default y + * ; help + * ; Select if you want MMU-based virtualised + * ; addressing space + * ; support by paged memory management. + * ; If unsure, say 'Y'. + * * mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0 - * ; ID_MMFR0 : 메모리 모델 정보, 메모리관리 서포트 정보 - * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0438e/BABEHBEB.html + * ; ID_MMFR0 : 메모리 모델 정보, 메모리관리 서포트 정보 + * ; http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0438e/BABEHBEB.html * * tst r11, #0xf @ VMSA - * ; 하위 4비트 VMSA 지원여부 체크 - * ; 버추얼 메모리 시스템 아키텍쳐 = MMU? + * ; 하위 4비트 VMSA 지원여부 체크 + * ; 버추얼 메모리 시스템 아키텍쳐 = MMU? + * * movne r6, #CB_BITS | 0x02 @ !XN - * ; z 플래그가 0아닐 때(지원하면) 실행 - * ; arch/arm/mm/Kconfig파일에 CPU_DCACHE_WRITETHROUGH - * ; 셋되어 있으면 CB_BITS = 0x08, 아니면 0x0c - * ; r6 = #CB_BITS | 0x02 + * ; z 플래그가 0아닐 때(지원하면) 실행 + * ; arch/arm/mm/Kconfig파일에 CPU_DCACHE_WRITETHROUGH + * ; 셋되어 있으면 CB_BITS = 0x08, 아니면 0x0c + * ; r6 = #CB_BITS | 0x02 + * * blne __setup_mmu - * ; + * + * ================================================================== + */ + +/* ========================================================================== + * Team: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * Date: 24.10.2015 + * + * clean과 flush 차이 : http://linuxphil.blogspot.kr/2011/01/arm-clean-flush-invalidate.html ; + * This code is... * mov r0, #0 + * ; r0 = 0 + * * mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + * ; cache의 clean == WriteBuffer의 drain (메모리 반영x) + * ; mcr (move to co-processor from resgister) + * * tst r11, #0xf @ VMSA + * ; VMSA 지원가능 여부 check + * * mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs + * ; 메모리 반영시키고 MMU의 페이지 테이블의 cache 비움 + * * #endif * mrc p15, 0, r0, c1, c0, 0 @ read control reg + * ; r0로 control register를 가져옴. + * ; http://infocenter.arm.com/help/topic/com.arm.doc.ddi0464f/DDI0464F_cortex_a7_mpcore_r0p5_trm.pdf p.108 + * * bic r0, r0, #1 << 28 @ clear SCTLR.TRE + * ; TRE : tex remap enable / disable + * ; text remap disable + * * orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement + * ; r0 |= 0x5000 + * ; round + * * orr r0, r0, #0x003c @ write buffer + * ; r0 |= 0x003c + * * bic r0, r0, #2 @ A (no unaligned access fault) + * ; r0 &= ~2 + * ; SCTLR의 2번째 비트를 clear하면, alignment fault check + * disable + * ; ex) ldrh : align checking을 half word 단위로 하는데, + * ; SCTLR의 2번째 비트가 0으로 되어 있으면, 사용가능하고 + * ; 1로 되어 있으면, alignment fault가 발생한다. + * ; link : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0338g/Cdffhdje.html + * * orr r0, r0, #1 << 22 @ U (v6 unaligned access model) + * ; arm v7의 경우 항상 1 + * * @ (needed for ARM1176) * * ================================================================== */ +/* ========================================================================== + * Team: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * Date: 24.10.2015 + * + * This code is... + * + * #ifdef CONFIG_MMU + * ARM_BE8(orr r0, r0, #1 << 25 ) @ big-endian page tables + * ; ARM_BE8일 경우에 내부 명령어 실행 + * ; SCTLR의 25번째 비트가 EE + * ; 용도: exception이 발생시, SCTLR.EE를 통해 CPSR.E를 + * 설정 + * + * mrcne p15, 0, r6, c2, c0, 2 @ read ttb control reg + * ; if (VMSA) + * ; r6 <- ttb(translation table base register) + * ; ttbr0 = user용 + * ; ttbr1 = kernel용 + * ; link : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/Bihgfcgf.html + * + * orrne r0, r0, #1 @ MMU enabled + * ; if (VMSA) + * ; r0 |= 1 + * + * movne r1, #0xfffffffd @ domain 0 = client + * ; DACR의 값을 설정 + * ; 00 : No access 01: Client + * ; 10 : Reserved 11: Master + * + * bic r6, r6, #1 << 31 @ 32-bit translation system + * ; r6의 2^32자리를 clear + * ; 31번 bit -> EAE (extended address enable) + * ; EAE가 0일 경우, 32bit를 이용한다. + * ; EAE가 1일 경우, 40bit를 이용한다. + * ; ref : PAE + * + * bic r6, r6, #3 << 0 @ use only ttbr0 + * ; 하위 2비트를 clear + * ; TTBCR의 N[2:0]으로 TTBR0의 base address field + * ; 길이를 설정한다. + * ; base address field 길이 : 31 ~ 14-N + * ; N : 0 ~ 7 + * ; link : http://liris.cnrs.fr/~mmrissa/lib/exe/fetch.php?media=armv7-a-r-manual.pdf + * ; N이 0일경우 ARM v5와 ARM v6가 호환이 되고 + * ; 그외의 값의 경우 base address field의 길이를 설정한다 + * + * mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer + * ; r3 <- page table pointer (0x4000) + * + * mcrne p15, 0, r1, c3, c0, 0 @ load domain access control + * ; r1 <- domain access control + * + * mcrne p15, 0, r6, c2, c0, 2 @ load ttb control + * #endif + * mcr p15, 0, r0, c7, c5, 4 @ ISB + * ; Instruction Synchronization Barrier + * ; ISB 수행 전의 내용을 파이프라인에서 모두 반영하여 + * 비운다. + * ; 파이프라인을 비워서, 모든 명령들이 cache 나 memory 로 + * 부터 fetch 되도록 한다. + * ; 따라서, ISB 이전 수행이 완료되었음을 보장한다. + * + * ; (참고URL) + * ; http://forum.falinux.com/zbxe/index.php?document_srl=534002&mid=Kernel_API + * ; http://www.iamroot.org/xe/Kernel_8_ARM/58427 + * ; (참고) 이전 버전의 커널에서는 ISB를 사용하지 않고, + * ; 다음과 같이 처리함. + * ; mcr p15, 0, r0, c1, c0, 0 @ load control register + * ; mrc p15, 0, r0, c1, c0, 0 @ and read it back to + * ; sub pc, lr, r0, lsr #32 @ properly flush pipeline + * + * mcr p15, 0, r0, c1, c0, 0 @ load control register + * mrc p15, 0, r0, c1, c0, 0 @ and read it back + * mov r0, #0 + * mcr p15, 0, r0, c7, c5, 4 @ ISB + * mov pc, r12 + * + * ==========================================================================*/ + __armv7_mmu_cache_on: mov r12, lr #ifdef CONFIG_MMU @@ -1430,6 +2382,10 @@ __common_mmu_cache_on: #define PROC_ENTRY_SIZE (4*5) /* + * ==================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * -------------------------------------------------------------------- + * * Here follow the relocatable cache support functions for the * various processors. This is a generic hook for locating an * entry and jumping to an instruction at the specified offset @@ -1450,10 +2406,12 @@ __common_mmu_cache_on: * * * call_cache_fn: adr r12, proc_types - * ; r12 = &proc_types; + * ; r12 = &proc_types; + * * #ifdef CONFIG_CPU_CP15 * mrc p15, 0, r9, c0, c0 @ get processor ID - * ; r9 = processor ID + * ; r9 = processor ID + * * #elif defined(CONFIG_CPU_V7M) ; cp15 코프로쎄서가 없으며 V7M cpu일때 * / * * * On v7-M the processor id is located in the V7M_SCB_CPUID @@ -1466,30 +2424,40 @@ __common_mmu_cache_on: * bx lr * #else * ldr r9, =CONFIG_PROCESSOR_ID - * ; r9 = CONFIG_PROCESSOR_ID + * ; r9 = CONFIG_PROCESSOR_ID + * * #endif // CONFIG_CPU_CP15 * * 1: ldr r1, [r12, #0] @ get value - * ; r1 = cpu ID : 0x41000000 + * ; r1 = cpu ID : 0x410fc075 (라즈베리파이 2 CPU ID) + * * ldr r2, [r12, #4] @ get mask - * ; r2 = cpu ID mask : 0xff00f000 + * ; r2 = cpu ID mask : 0x000f0000 + * * eor r1, r1, r9 @ (real ^ match) - * ; r1 = r1 ^ r9 + * ; r1 = r1 ^ r9 + * * tst r1, r2 @ & mask - * ; cpsr = r1 & 0xff00f000 - * ; 정리 --> cpsr = (r9 ^ cpuID) & cpuMask - * ; 0 이면 : 같음, 1이외값 : 틀림 - * ARM( addeq pc, r12, r3 ) @ call cache function - * ; r3=(cache온, cache오프, cache 클리어) - * ; tst r1, r2 값이 0으로 세팅되어있으면 pc = r12+r3 - * THUMB( addeq r12, r3 ) - * THUMB( moveq pc, r12 ) @ call cache function + * ; cpsr = r1 & 0xff00f000 + * ; 정리 --> cpsr = (r9 ^ cpuID) & cpuMask + * ; 0 이면 : 같음, 1이외값 : 틀림 + * + * ARM( addeq pc, r12, r3 ) @ call cache function + * ; r3=(cache온, cache오프, cache 클리어) + * ; tst r1, r2 값이 0으로 세팅되어있으면 pc = r12+r3 + * + * THUMB( addeq r12, r3 ) + * THUMB( moveq pc, r12 ) @ call cache function * add r12, r12, #PROC_ENTRY_SIZE - * ; * b 1b * + * ==================================================================== + */ +/* IAMROOT-12D (2016-01-09): + * -------------------------- + * 두번째 restart에서 들어옴 + * cache clean & flush : r3 = 16 */ - call_cache_fn: adr r12, proc_types #ifdef CONFIG_CPU_CP15 mrc p15, 0, r9, c0, c0 @ get processor ID @@ -1658,6 +2626,14 @@ proc_types: W(b) __armv4_mmu_cache_off W(b) __armv6_mmu_cache_flush + +/* IAMROOT-12D (2016-01-09): + * -------------------------- + * 라즈베리 파이 proc_types + * 라즈베리파이 2 cpu ID : 0x410fc075 + * ( real_cpu_id ^ proc_types_cpu_id ) & mask = 0 + * ( 0x410fc075 ^ 0x000f0000 ) & 0x000f0000 = 0 + */ .word 0x000f0000 @ new CPU Id .word 0x000f0000 W(b) __armv7_mmu_cache_on @@ -1739,6 +2715,12 @@ __armv7_mmu_cache_off: bl __armv7_mmu_cache_flush mov r0, #0 #ifdef CONFIG_MMU + /* IAMROOT-12D (2016-01-23): + * -------------------------- + * TLB : 가상메모리주소를 물리메모리주소로 변환하는 속도를 + * 높이기 위해 사용되는 캐시. + * BTC : Branch Target Cache + */ mcr p15, 0, r0, c8, c7, 0 @ invalidate whole TLB #endif mcr p15, 0, r0, c7, c5, 6 @ invalidate BTC @@ -1797,21 +2779,128 @@ __armv6_mmu_cache_flush: mov pc, lr __armv7_mmu_cache_flush: + + /* IAMROOT-12D (2016-01-09): + * -------------------------- + * r4는 최종 커널의 시작주소 0x8000 + * r4의 LSB가 1이면 cache_on 연기가 셋팅 되어 있는 상태. + * if(r4 & 1 != 0) // cache_on 연기 상태이면 + * iflush(); + * + * 우리가 분석하는 소스에서는 cache_on 연기 상태가 아니므로 + * iflush는 호출하지 않는다. + */ tst r4, #1 bne iflush + + /* IAMROOT-12D (2016-01-09): + * -------------------------- + * ID_MMFR1: 프로세서의 메모리 관리, 메모리 모델정보를 제공한다. + * https://github.com/iamroot12D/linux/issues/24 + * https://cloud.githubusercontent.com/assets/6335376/12215156/da670158-b6f3-11e5-850e-f6d0ffec1170.jpg + * 하버드 구조는 명령어와 데이터가 각각의 버스로 이동하는 구조 + * 폰노이드만 구조는 명령어와 데이터가 같은 버스로 이동하는 구조 + * + * 만약 계층 캐시 구조라면(멀티 레벨 캐시) + * hierarchical(계층적인, 트리구조 같은..)를 호출한다. + * #0xf << 16 = 0x000f0000 + * r10 = id_mmfr1; + * if(r10 & 0x000f0000 == 0) + * goto hierarchical; + */ mrc p15, 0, r10, c0, c1, 5 @ read ID_MMFR1 tst r10, #0xf << 16 @ hierarchical cache (ARMv7) mov r10, #0 beq hierarchical + + /* IAMROOT-12D (2016-01-09): + * -------------------------- + * 데이터 캐시를 clean & flush하고 + * 명령어 캐시를 flush한다.(iflush) + */ mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D b iflush + + /* IAMROOT-12D (2016-01-09): + * -------------------------- + * DMB : data memory barrier + * 다른 데이터 영역 메모리의 접근을 막는다. + */ hierarchical: mcr p15, 0, r10, c7, c10, 5 @ DMB + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * 스택에 r0 ~ r7, r9 ~ r11 저장 + * + * clidr : cache level id register + * Figure 4.19. CLIDR bit assignments + * 29 27 24 21 18 15 12 9 6 3 0 + *+-----------------------------------------------------------------+ + *| |LoUU|Loc|LoUIS|Ctype7|Ctype6|Ctype5|Ctype4|Ctype3|Ctype2|Ctype1| + *+-----------------------------------------------------------------+ + * Ctype1 : Level 1 cache의 구현 type + * Ctype2 : Level 2 Cache의 구현 type + */ stmfd sp!, {r0-r7, r9-r11} mrc p15, 1, r0, c0, c0, 1 @ read clidr + + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * L2 캐시 지원 여부를 알아아보는 소스 + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0464d/BABHCIHB.html + * clidr[26:24] LoC + * Indicates the Level of Coherency for the cache hierarchy: + * - 0b000 L2 cache not implemented on the processor. + * - 0b010 L2 cache coherency. + * r3 = clidr & 0x07000000; + * r3 = r3 >> 23; + * if(r3 == 0) // L2 캐시 지원하지않음. + * goto finished; + */ ands r3, r0, #0x7000000 @ extract loc from clidr mov r3, r3, lsr #23 @ left align loc bit field beq finished @ if loc is 0, then no need to clean + + /* IAMROOT-12D (2016-01-09): + * -------------------------- + * r0 = clidr; + * r3 = 0b0010 ~ 0b1110; // clidr[26:24] << 1 + * r10 = 0; + * do { + * r2 = r10 + (r10 / 2); // r2 = r10 * 1.5; + * r1 = r0 >> r2; // 처음 r1 = clidr; + * r1 = r1 & 0b0111; // r1 = Indicates the type of + * // cache implemented at level 1 + * // +------+-----------+ + * // |00 |no cache | + * // +------+-----------+ + * // |01 |icache | + * // +------+-----------+ + * // |10 |data cache | + * // +------+-----------+ + * // |11 |I/D Cache | + * // +------+-----------+ + * if(r1 < 2) // instruction cache skip + * goto skip; + * cssr = r10; + * // ISB : Instruction Synchronization Barrier. + * cssr, csidr = r10; @ isb to sych the new cssr&csidr + * r1 = csidr; + * r2 = r1 & 0b0111; // 하위 3비트를 가져온다. + * r2 = r2 + 4; + * r4 = 0x3ff; + * r4 = r4 & (r1 >> 3); + * ands r4, r4, r1, lsr #3 @ find maximum number on the way size + * r5 = clz r4 // 최초 0이 아닌 인 비트까지의 개수. + * r7 = 0x7fff & (r1 >> 13); + * loop2: + * + * 2016-01-16 부터 + * .... + * r10 += 2; + * } while (r3 <= r10); + * + */ mov r10, #0 @ start clean at cache level 0 loop1: add r2, r10, r10, lsr #1 @ work out 3x current cache level @@ -1819,14 +2908,92 @@ loop1: and r1, r1, #7 @ mask of the bits for current cache only cmp r1, #2 @ see what cache we have at this level blt skip @ skip if no cache, or just i-cache + + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * Cache Size Selection Register + * Figure 4.26. CSSELR bit assignments + * 31 4 1 0 + * +-----------------+-----+-+ + * | Reserved(SBZ) |Level| | + * +-----------------+-----+-+ + * ^ + * InD ---+ + * Level : cache level : 0-level1, 1-level2 ... + * InD : 명령어 혹은 데이터 캐쉬를 사용하는지 + * 0 : data, 1:instruction + * + * clean and flush할 L1, L2, L3 캐시를 선택한다. + */ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr + + /* IAMROOT-12D (2016-01-09): + * -------------------------- + * Instruction Synchronization Barrier + * ISB 수행 전의 내용을 파이프라인에서 모두 반영하여 비운다. + * 파이프라인을 비워서, 모든 명령들이 cache 나 memory 로 + * 부터 fetch 되도록 한다. + * 따라서, ISB 이전 수행이 완료되었음을 보장한다. + */ mcr p15, 0, r10, c7, c5, 4 @ isb to sych the new cssr&csidr + + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * ccsidr : Cache Size ID Register + * 캐시 아키텍쳐 정보를 제공. + * + * Figure 4.18. CCSIDR bit assignments + * 31302928 13 3 0 + * +-+-+-+-+----------+---------------+--+ + * | | | | | NumSets | Associativity |LS| + * +-+-+-+-+----------+---------------+--+ + * + * [27:13] NumSets Indicates number of sets + * 0x7F = 16KB cache size + * 0xFF = 32KB cache size + * 0x1FF = 64KB cache size. + * 라즈베리 파이2 B는 L1 32K, L2 512K이다. + * + * [12:3] Associativity Indicates number of ways. + * b0000000011. Four ways. + * + * [2:0] LineSize Indicates the (log 2 (number of words in + * cache line)) - 2: + * b001 = 8 words per line. + * b010 = 16 words per line. + */ mrc p15, 1, r1, c0, c0, 0 @ read the new csidr + + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * r2 = CCSIDR[2:0] LineSize + 4 + */ and r2, r1, #7 @ extract the length of the cache lines add r2, r2, #4 @ add 4 (line length offset) + + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * r4 = CCSIDR[12:3] Associativity + */ ldr r4, =0x3ff ands r4, r4, r1, lsr #3 @ find maximum number on the way size + + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * clz count leading zeros + * 최초 0이 아닌 비트까지의 0 개수 + * + * 여기서는 0이 아닌 비트를 최상단으로 옮기기 위해 사용했다. + * 예) a = 0b 0000 0000 0000 0011 + * b = clz a = 14 + * a << b = 0b 1100 0000 0000 0000 + */ clz r5, r4 @ find bit position of way size increment + + /* IAMROOT-12D (2016-01-16): + * -------------------------- + * r7 = CCSIDR[27:13] NumSets + */ ldr r7, =0x7fff ands r7, r7, r1, lsr #13 @ extract max number of the index size loop2: @@ -1838,6 +3005,17 @@ loop3: THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 THUMB( lsl r6, r7, r2 ) THUMB( orr r11, r11, r6 ) @ factor index number into r11 + + /* IAMROOT-12D (2016-01-12): + * -------------------------- + * r11 register + * 30 13 5 0 + * +---+--------+-----------+-----+ + * |Way| SBZ | Set | SBZ | + * +---+--------+-----------+-----+ + * + * Set 위치는 cache line size(word) 사이즈에 따라 바뀐다 + */ mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way subs r9, r9, #1 @ decrement the way bge loop3 @@ -1852,6 +3030,23 @@ finished: mov r10, #0 @ swith back to cache level 0 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr iflush: + /* IAMROOT-12D (2016-01-09): + * -------------------------- + * BTB branch target buffer + * instruction cache를 flush한다. + * + * DSB : 배리어의 특별한 형태로써 이 명령이 수행되기 전에 명령어 + * 의 수행이 모두 완료된 다는 것이다. 추가로 캐쉬, 분기예측 + * , TLB(가상/물리 어드레스 변환테이블의 캐쉬) 수행 명령도 + * 모두 완료되는 것을 보장한다. + * + * ISB : 명령어 동기화로서 프로세서의 파이프라인을 모두 비운다. + * 따라서 ISB 뒤에서 실행되는 명령어는 이 명령어의 수행이 끝난 + * 후 캐쉬나 메모리로부터 다시 읽혀지게 된다. 뒤에 무엇에 의한 + * 영향을 피하기 위해서라고 설명하는데 어쨋건 중요한 것은 이 + * 명령어 수행하고 나면 파이프라인이 비워진다는 것이 다. + * 참고 URL : http://forum.falinux.com/zbxe/index.php?document_srl=534002&mid=Kernel_API + */ mcr p15, 0, r10, c7, c10, 4 @ DSB mcr p15, 0, r10, c7, c5, 0 @ invalidate I+BTB mcr p15, 0, r10, c7, c10, 4 @ DSB @@ -1917,6 +3112,7 @@ __armv3_mpu_cache_flush: * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-05 * ------------------------------------------------------------------ + * * TODO * .align : 디폴트는 4byte이다. * .type: phexbuf 는 #object이다. @@ -1926,6 +3122,7 @@ __armv3_mpu_cache_flush: * * c-style: char phexbuf[12]; * int size = &phexbuf[12] - &phexbuf[0] + * * ================================================================== */ #ifdef DEBUG @@ -1938,50 +3135,73 @@ phexbuf: .space 12 * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-12 * ------------------------------------------------------------------ + * * 함수명: phex(put hexa?) * 설명: 10진수를 받아들여서 16진수로 변환함 * 인자 * r0: value, * r1: length (offset) - * - * adr r3, phexbuf ; r3 = &phexbuf - * mov r2, #0 ; r2 = 0 - * strb r2, [r3, r1] ; *(r3+r1) = r2; - * <----------------------------- 2015/9/12 여기부터 시작 - * subs r1, r1, #1 ; r1 = r1 - 1 - * ; subs의 s가 왠지 플래그값을 바꾸는것 같아서 - * ; 그 결과값을 가지고 이하의 명령어들을 참고합니다. - * ; (r1값이 음수면 N플래그가 1로 설정된다고 가정) - * - * movmi r0, r3 ; r0 = ( r1 < 0 ) ? r3 : ; - * ; movmi : r1안의 값이 마이너스면(음수면?) mov해라(r0에 넣어라) - * - * bmi puts ; bmi(branch if minus?) r1값이 음수면 puts 호출한다 - * - * and r2, r0, #15 ; r2 = r0 & 0xF - * ; and(AND연산?) : 0xF 마스크 연산을 하는거. 하위 비트 잘라내기 - * - * mov r0, r0, lsr #4 ; r0 = r0 >> 4 - * ; lsr(logical shift right) : 논리연산인데 unsigned 연산 - * ; : 참고로 asr는 signed 연산 - * ; 결국 4비트씩 자르는 과정 - * - * cmp r2, #10 ; cmp(compare?) : r2와 10을 비교 - * - * addge r2, r2, #7 ; r2 = ( r2 >= 10 ) ? r2+7 : ; - * ; addge(add if greater and equal to) - * ; 질문)r2 + 7 : 왜 7을 더해주나? - * - * add r2, r2, #'0' ; '0'은 ascii code로 48, 아까 위에서 연산한 r2에 48을 더해서 - * ; 결국 'A'로 변환해 줌 - * - * strb r2, [r3, r1] ; *(r3+r1) = r2 - * ; strb(store byte?) 8비트값을 메모리에 저장 - * - * b 1b ; branch 1b (1b는 가장 가까운 레이블1로 back해라) - * ; (참고로 1f라면 가장 가까운 레이블1로 forward해라) + * phdex(unsigned int value, int len); + * phdexbuf 에 정수값을 string hexa값으로 바꾸어 넣는다. + * 예) 0x1234ABCD --> char * phdexbuf = "1234ABCD", '\0'; + * + * adr r3, phexbuf + * ; r3 = &phexbuf + * + * mov r2, #0 + * ; r2 = 0 + * + * strb r2, [r3, r1] + * ; *(r3+r1) = r2; + * + * subs r1, r1, #1 + * ; r1 = r1 - 1 + * ; subs의 s가 왠지 플래그값을 바꾸는것 같아서 + * ; 그 결과값을 가지고 이하의 명령어들을 참고합니다. + * ; (r1값이 음수면 N플래그가 1로 설정된다고 가정) + * + * movmi r0, r3 + * ; r0 = ( r1 < 0 ) ? r3 : ; + * ; movmi : r1안의 값이 마이너스면(음수면?) mov해라 + * (r0에 넣어라) + * + * bmi puts + * ; bmi(branch if minus?) r1값이 음수면 puts 호출한다 + * + * and r2, r0, #15 + * ; r2 = r0 & 0xF + * ; and(AND연산?) : 0xF 마스크 연산을 하는거. 하위 비트 + * 잘라내기 + * + * mov r0, r0, lsr #4 + * ; r0 = r0 >> 4 + * ; lsr(logical shift right): 논리연산인데 unsigned 연산 + * ; : 참고로 asr는 signed 연산 + * ; 결국 4비트씩 자르는 과정 + * + * cmp r2, #10 + * ; cmp(compare?) : r2와 10을 비교 + * + * addge r2, r2, #7 + * ; r2 = ( r2 >= 10 ) ? r2+7 : ; + * ; addge(add if greater and equal to) + * ; 질문)r2 + 7 : 왜 7을 더해주나? + * + * add r2, r2, #'0' + * ; '0'은 ascii code로 48, 아까 위에서 연산한 r2에 48을 + * 더해서 결국 'A'로 변환해 줌 + * + * strb r2, [r3, r1] + * ; *(r3+r1) = r2 + * ; strb(store byte?) 8비트값을 메모리에 저장 + * + * b 1b + * ; branch 1b (1b는 가장 가까운 레이블1로 back해라) + * ; (참고로 1f라면 가장 가까운 레이블1로 forward해라) + * * ================================================================== */ + @ phex corrupts {r0, r1, r2, r3} phex: adr r3, phexbuf mov r2, #0 @@ -2002,33 +3222,53 @@ phex: adr r3, phexbuf * 날짜: 2015-09-05 * ------------------------------------------------------------------ * 1: - * ldrb r2, [r0], #1 ; load register byte. r2 = r0 + 1 - * ; 참고: r0 = char *str. 즉, str + 1 + * ldrb r2, [r0], #1 + * ;load register byte. r2 = r0 + 1 + * ; 참고: r0 = char *str. 즉, str + 1 + * * 2: - * writeb r2, r3 ; r2(문자)를 r3(출력될 주소)로 보낸다. - * mov r1, #0x00020000 ; r1 = 0x00020000 - * subs r1, r1, #1 ; r1 = r1 - 1 - * bne 3b ; for( r1 = 20000 ; r1 != 0; r-- ) - * puts, 문자 하나를 전송하고 약간의 딜레이 시간이 - * 필요할 수도 있다. - * TODO 20000 값이 baud rate 값과 같은지 - * teq r2, \n ; teq : XOR 연산을 이용한 비교 연산 - * 결과에 따라 n, z flag를 업데이트한다. - * - n flag: 계산한 결과가 음수면 세팅됨 - * - z flag: 계산한 결과가 0일때, set됨 - * r2 == \n 이면, z flag가 세팅됨. - * ; puts!! null문자를 만날 때까지 반복 - * moveq r2, \r ; if(r2 == '\n') r2 = '\r'; - * z flag가 세팅되어 있으면 mov 수행 - * beq 2b ; z flag가 세팅되어 있으면 branch 수행 - * ... - * mov pc, lr ; pc = lr, 돌아갈 장소를 pc에 담는다. - * - * 정리: \n은 \r 로 변경하고, NULL을 만날때까지, writeb를 수행한다. - * writeb 이후에, 약간의 딜레이를 주어 받는쪽에서 처리를 - * 완료할 수 있게 한다. + * writeb r2, r3 + * ; r2(문자)를 r3(출력될 주소)로 보낸다. + * + * mov r1, #0x00020000 + * ; r1 = 0x00020000 + * + * 3: + * subs r1, r1, #1 + * ; r1 = r1 - 1 + * + * bne 3b + * ; for( r1 = 20000 ; r1 != 0; r-- ) + * puts, 문자 하나를 전송하고 약간의 딜레이 시간이 + * 필요할 수도 있다. + * TODO 20000 값이 baud rate 값과 같은지 + * + * teq r2, \n + * ; teq : XOR 연산을 이용한 비교 연산 + * 결과에 따라 n, z flag를 업데이트한다. + * - n flag: 계산한 결과가 음수면 세팅됨 + * - z flag: 계산한 결과가 0일때, set됨 + * r2 == \n 이면, z flag가 세팅됨. + * + * ; puts!! null문자를 만날 때까지 반복 + * + * moveq r2, \r + * ; if(r2 == '\n') r2 = '\r'; + * z flag가 세팅되어 있으면 mov 수행 + * beq 2b + * ; z flag가 세팅되어 있으면 branch 수행 + * ... + * + * mov pc, lr + * ; pc = lr, 돌아갈 장소를 pc에 담는다. + * + * ; 정리: \n은 \r 로 변경하고, NULL을 만날때까지, + * writeb를 수행한다. writeb 이후에, 약간의 딜레이를 + * 주어 받는쪽에서 처리를 완료할 수 있게 한다. + * * ================================================================== */ + @ puts corrupts {r0, r1, r2, r3} puts: loadsp r3, r1 1: ldrb r2, [r0], #1 @@ -2049,14 +3289,23 @@ puts: loadsp r3, r1 * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-05 * ------------------------------------------------------------------ - * mov r2, r0 ; c-style: r2 = r0; - * mov r0, #0 ; c-style: r0 = 0; - * loadsp r3, r1 ; 문자 하나를 시리얼 포트로 보낸다. (디버그 모드일 때) - * r3에 물리메모리 주소가 매핑된다. - * r1은 tmp용으로 사용 - * b 2b ; puts의 2: 라벨로 브렌치, 여기서 문자가 쓰여진다. + * + * mov r2, r0 + * ; c-style: r2 = r0; + * + * mov r0, #0 + * ; c-style: r0 = 0; + * + * loadsp r3, r1 + * ; 문자 하나를 시리얼 포트로 보낸다. (디버그 모드일 때) + * r3에 물리메모리 주소가 매핑된다. + * r1은 tmp용으로 사용 + * b 2b + * ; puts의 2: 라벨로 브렌치, 여기서 문자가 쓰여진다. + * * ================================================================== */ + @ putc corrupts {r0, r1, r2, r3} putc: mov r2, r0 @@ -2068,63 +3317,103 @@ putc: * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) * 날짜: 2015-09-12 * ------------------------------------------------------------------ - * bl(branch after saving lr?) : 호출하기 전에 lr레지스터값에 다음 실행할 pc값을 저장하고 브랜치함 * + * bl(branch after saving lr?) : 호출하기 전에 lr레지스터값에 다음 실행할 + * pc값을 저장하고 브랜치함 + * + * + * memdump: mov r12, r0 + * ; r0는 아까 zImage의 압축이 풀릴 시작주소를 r12로 복사 + * + * mov r10, lr + * ; lr(link register)를 r10에 복사 + * ; 아래에서 bl로 분기가 생기니까 lr을 임시 저장 + * + * mov r11, #0 + * ; #0은 10진수 0. 이걸 r11에 복사 + * + * 2: mov r0, r11, lsl #2 + * ; 레이블2 시작. (헤더주소 찍기) + * ; 00000000: deadbeef deadbeef deadbeef ... 뭐 이런 느낌? + * ; 참고) $xxd -l 256 sh 쉘을 256바이트 덤프하는 예 + * ; r0 = r11 << 2 + * ; lsl(logical shift left) lsl #2는 곱하기 4 + * + * add r0, r0, r12 + * ; r0 = r0 + r12 + * + * mov r1, #8 + * ; r1 = 8 + * + * bl phex + * ; lr에 돌아올위치를 저장하고 phex로 브랜치(점프) + * ; 인자로는 r0(val), r1(len) + * ; 결국, r0부터 8 글자를 16진수로 찍기 + * + * mov r0, #':' + * ; ": " 찍기 + * + * bl putc + * + * 1: mov r0, #' + * ; 레이블1 시작. (바디 64바이트 덤프) + * + * bl putc + * + * ldr r0, [r12, r11, lsl #2] + * ; ldr(load register. 32비트 값을 레지스터로 일어들이기) + * ; r0 = *(r12 + (r11 << 2)) + * ; []이게 나오면 주소의 의미 + * + * mov r1, #8 + * ; r1은 lenght * - * memdump: mov r12, r0 ; r0는 아까 zImage의 압축이 풀릴 시작주소를 r12로 복사 + * bl phex + * ; 8개 찍기 * - * mov r10, lr ; lr(link register)를 r10에 복사 - * ; 아래에서 bl로 분기가 생기니까 lr을 임시 저장 + * and r0, r11, #7 + * ; r0 = r11 & 0x07 (00000111b) * - * mov r11, #0 ; #0은 10진수 0. 이걸 r11에 복사 + * teq r0, #3 + * ; teq(test if equal). (r0 == 3)면 z플래그가 세운다 + * ; 여기서 3과 비교하는 이유는 4덩어리씩 끊어주기 위해서 * - * 2: mov r0, r11, lsl #2 ; 레이블2 시작. (헤더주소 찍기) - * ; 00000000: deadbeef deadbeef deadbeef .... 뭐 이런 느낌? - * ; 참고) $xxd -l 256 sh 쉘을 256바이트 덤프하는 예 - * ; r0 = r11 << 2 - * ; lsl(logical shift left) lsl #2는 곱하기 4 + * ; 질문) + * ; 근데 지금 몇 글자씩 찍고있나? * - * add r0, r0, r12 ; r0 = r0 + r12 + * moveq r0, #' ' + * ; z플래그가 서있으면 r0에 ' '를 복사한다 * - * mov r1, #8 ; r1 = 8 + * bleq putc + * ; bleq: z플래그가 1이면 브랜치 * - * bl phex ; lr에 돌아올위치를 저장하고 phex로 브랜치(점프) - * ; 인자로는 r0(val), r1(len) - * ; 결국, r0부터 8 글자를 16진수로 찍기 + * and r0, r11, #7 + * ; r0 = r11 & 0x07 다시 마스킹하고 * - * mov r0, #':' ; ": " 찍기 - * bl putc - * 1: mov r0, #' ; 레이블1 시작. (바디 64바이트 덤프) - * bl putc + * add r11, r11, #1 + * ; r11 = r11 + 1 * - * ldr r0, [r12, r11, lsl #2] ; ldr(load register. 32비트 값을 레지스터로 일어들이기) - * ; r0 = *(r12 + (r11 << 2)) - * ; []이게 나오면 주소의 의미 - * mov r1, #8 ; r1은 lenght - * bl phex ; 8개 찍기 + * teq r0, #7 + * ; r0와 7이 같은지 테스트. 같으면 z플래그가 서짐 + * (1로 세팅됨) * - * and r0, r11, #7 ; r0 = r11 & 0x07 (00000111b) - * teq r0, #3 ; teq(test if equal). (r0 == 3)면 z플래그가 세운다 - * ; 여기서 3과 비교하는 이유는 4덩어리씩 끊어주기 위해서 - * ; - * ; 질문) - * ; 근데 지금 몇 글자씩 찍고있나? + * bne 1b + * ; 8(덩어리)이 아니라면 레이블1로 브랜치 * - * moveq r0, #' ' ; z플래그가 서있으면 r0에 ' '를 복사한다 + * mov r0, #'\n' + * ; 8덩어리니까 new line을 찍는다 * - * bleq putc ; bleq: z플래그가 1이면 브랜치 + * bl putc * - * and r0, r11, #7 ; r0 = r11 & 0x07 다시 마스킹하고 - * add r11, r11, #1 ; r11 = r11 + 1 - * teq r0, #7 ; r0와 7이 같은지 테스트. 같으면 z플래그가 서짐(1로 세팅됨) - * bne 1b ; 8(덩어리)이 아니라면 레이블1로 브랜치 - * mov r0, #'\n' ; 8덩어리니까 new line을 찍는다 - * bl putc + * cmp r11, #64 + * ; r11이 64와 비교(비교 방법은 그 다음 명령어를 참고) * - * cmp r11, #64 ; r11이 64와 비교(비교 방법은 그 다음 명령어를 참고) - * blt 2b ; blt(branch if less than): r11이 그 대상(64)보다 작으면 브랜치 + * blt 2b + * ; blt(branch if less than): r11이 그 대상(64)보다 + * 작으면 브랜치 * - * mov pc, r10 ; 임시 저장했던 lr을 pc에 복사(결국 리턴) + * mov pc, r10 + * ; 임시 저장했던 lr을 pc에 복사(결국 리턴) * * ================================================================== */ diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index d4f891f5..618a5e24 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -16,6 +16,10 @@ * This allows for a much quicker boot time. */ +/* IAMROOT-12CD (2016-07-02): + * -------------------------- + * __machine_arch_type = MACH_TYPE_BCM_2709 + */ unsigned int __machine_arch_type; #include /* for inline */ @@ -141,7 +145,22 @@ void __stack_chk_fail(void) extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)); - +/* IAMROOT-12D (2016-01-23): + * -------------------------- + * 입력 파라미터 + * output_start = kernal 시작 주소 (0x8000) + * free_mem_ptr_p = 스택 시작 주소 (스택은 거꾸로 쌓이므로 낮은 어드레스) + * free_mem_ptr_end_p = 스택의 시작 + 64KB (=힙영역으로 추정) + * arch_id = 아키텍쳐 ID + * + * +-----------------------+ <- free_mem_ptr_end_p + * | buffer(64K),heap 영역 | + * +-----------------------+ <- free_mem_ptr_p + * | stack | + * +-----------------------+ + * | bss | + * +-----------------------+ + */ void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, unsigned long free_mem_ptr_end_p, @@ -159,6 +178,19 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, arch_decomp_setup(); putstr("Uncompressing Linux..."); + /* IAMROOT-12D (2016-01-23): + * -------------------------- + * arch/arm/boot/compressed/piggy.gzip.S 파일에 다음과 같은 내용 + * + * .section .piggydata,#alloc + * .globl input_data + * input_data: + * .incbin "arch/arm/boot/compressed/piggy.gzip" + * .globl input_data_end + * input_data_end: + * + * input_data = 압축된 커널 시작 위치 + */ ret = do_decompress(input_data, input_data_end - input_data, output_data, error); if (ret) diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c index 36e53ef9..bf949e0e 100644 --- a/arch/arm/boot/compressed/string.c +++ b/arch/arm/boot/compressed/string.c @@ -4,8 +4,19 @@ * Small subset of simple string routines */ +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-14 + * ------------------------------------------------------------------ + * + * ================================================================== + */ #include +/* + * 최적화를 위해 loop unrolling처리 + * dest가 src보다 작은 경우 복사시 안전 + */ void *memcpy(void *__dest, __const void *__src, size_t __n) { int i = 0; @@ -40,6 +51,9 @@ void *memcpy(void *__dest, __const void *__src, size_t __n) return __dest; } +/* + * 버퍼 끝에서 부터 복사를 하여 항상 안전한 복사가 가능하다. + */ void *memmove(void *__dest, __const void *__src, size_t count) { unsigned char *d = __dest; diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index 56380995..d9c2bb0c 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -179,6 +179,12 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset); #define ATOMIC_BITOP(name,nr,p) \ (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p)) #else +/* IAMROOT-12D (2016-05-14): + * -------------------------- + * _##name(nr,p) 는 다음과 같이 변경된다. + * _set_bit(nr,p) + * _clear_bit(nr,p) + */ #define ATOMIC_BITOP(name,nr,p) _##name(nr,p) #endif diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h index 7ea78144..67cae437 100644 --- a/arch/arm/include/asm/cachetype.h +++ b/arch/arm/include/asm/cachetype.h @@ -1,6 +1,11 @@ #ifndef __ASM_ARM_CACHETYPE_H #define __ASM_ARM_CACHETYPE_H +/* IAMROOT-12D : Virtually Indexed Physically Tagged + * VIPT는 TLB, cache를 가상주소로 동시에 접근한다.(병렬접근) + * aliasing은 하나의 physical address를 여러개의 가상주소로 사용 가능하게 하고 + * non aliasing은 하나의 physical address를 하나의 가상주소로만 사용 가능하다. + */ #define CACHEID_VIVT (1 << 0) #define CACHEID_VIPT_NONALIASING (1 << 1) #define CACHEID_VIPT_ALIASING (1 << 2) @@ -26,6 +31,10 @@ extern unsigned int cacheid; * - v7+ VIPT never aliases on D-side */ #if __LINUX_ARM_ARCH__ >= 7 +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * 0b0111010 --> 0x0000003a + */ #define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING |\ CACHEID_ASID_TAGGED |\ CACHEID_VIPT_I_ALIASING |\ @@ -43,7 +52,7 @@ extern unsigned int cacheid; #define __CACHEID_ALWAYS (CACHEID_VIVT) #define __CACHEID_NEVER (~CACHEID_VIVT) #elif !defined(CONFIG_CPU_CACHE_VIVT) && defined(CONFIG_CPU_CACHE_VIPT) -#define __CACHEID_ALWAYS (0) +#define __CACHEID_ALWAYS (0) /* IAMROOT-12D : 라즈베리파이2*/ #define __CACHEID_NEVER (CACHEID_VIVT) #else #define __CACHEID_ALWAYS (0) diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h index abb2c376..953571de 100644 --- a/arch/arm/include/asm/cmpxchg.h +++ b/arch/arm/include/asm/cmpxchg.h @@ -50,6 +50,16 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size : "r" (x), "r" (ptr) : "memory", "cc"); break; + /* IAMROOT-12D (2016-04-16): + * -------------------------- + * LDREX 및 STREX + * 단독 레지스터 로드 및 저장 + * + * 1: ldrex &ret, [ptr] @ ret = *ptr; + * strex &tmp, x, [&ptr] @ *tmp = *(x + *ptr) + * teq tmp, 0 @ if(tmp != 0) goto 1 + * bne 1b + */ case 4: asm volatile("@ __xchg4\n" "1: ldrex %0, [%3]\n" diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h index c3f11524..ac8fefe6 100644 --- a/arch/arm/include/asm/cp15.h +++ b/arch/arm/include/asm/cp15.h @@ -35,13 +35,17 @@ #define CR_XP (1 << 23) /* Extended page tables */ #define CR_VE (1 << 24) /* Vectored interrupts */ #define CR_EE (1 << 25) /* Exception (Big) Endian */ -#define CR_TRE (1 << 28) /* TEX remap enable */ +#define CR_TRE (1 << 28) /* TEX(Type EXtension field) remap enable */ #define CR_AFE (1 << 29) /* Access flag enable */ #define CR_TE (1 << 30) /* Thumb exception enable */ #ifndef __ASSEMBLY__ #if __LINUX_ARM_ARCH__ >= 4 +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * cr(0x10c5387d & (1 << 13)) = 0x2000 + */ #define vectors_high() (get_cr() & CR_V) #else #define vectors_high() (0) @@ -51,6 +55,63 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */ +/* IAMROOT-12D (2016-06-09): + * -------------------------- + * 라즈베리파이2 기본값 : 0x10c5387d + * + * System control register (SCTLR) + * The SCTLR is another of a number of registers that are accessed using CP15, + * and controls standard memory, system facilities and provides status + * information for functions implemented in the core. + * SCTLR는 CP15를 사용하여 액세스되는 레지스터의 중 하나 이며, 표준 메모리 시스 + * 템의 기능을 제어하고, 상기 코어에서 구현되는 기능에 대한 상태 정보를 제공한다 + * + * 30 20 10 0 + * 1 0 9 8 7 6 5 4 2 1 0 4 3 2 1 0 3 2 1 0 + * +-+-+-+-+-+-+-+--+-+-+-------+-+-+-+--------+-+-+-+ + * | |T|A|T|N| |E| |U|F| |V|I|Z| |C|A|M| + * | |E|F|R|M| |E| | |I| | | | | | | | | + * +-+-+-+-+-+-+-+--+-+-+-------+-+-+-+--------+-+-+-+ + * + * [30] TE – Thumb exception enable. This controls whether exceptions are taken + * in ARM or Thumb state. + * [29] AFE Access flag enable bit. This bit enables use of the AP[0] bit in the + translation table descriptors as the Access flag. + * 0 In the translation table descriptors, AP[0] is an access permissions bit. + * The full range of access permissions is supported. No Access flag is + * implemented. This is the reset value. + * 1 In the translation table descrip + * + * [28] TRE TEX remap enable bit. This bit enables remapping of the TEX[2:1] + * bits for use as two translation table bits that can be managed by the + * operating system. Enabling this remapping also changes the scheme used + * to describe the memory region attributes in the VMSA: + * 0 TEX remap disabled. TEX[2:0] are used, with the C and B bits, to describe + * the memory region attributes. This is the reset value. + * 1 TEX remap enabled. TEX[2:1] are reassigned for use as bits managed by the + * operating system. The TEX[0], C and B bits are used to describe the + * memory region attributes, with the MMU remap registers. + * + * [27] NMFI(NM) – Non-maskable FIQ (NMFI) support. + * + * [25] EE Exception Endianness bit. The value of this bit defines the value of + * the CPSR.E bit on entry to an exception vector, including reset. This + * value also indicates the endianness of the translation table data for + * translation table + * lookups: + * 0 Little endian. + * 1 Big endian. + * The primary input CFGEND defines the reset value of the EE bit. + * + * [22] U – Indicates use of the alignment model. + * [21] FI – FIQ configuration enable. + * - V – This bit selects the base address of the exception vector table. + * - I – Instruction cache enable bit. + * - Z – Branch prediction enable bit. + * - C – Cache enable bit. + * - A – Alignment check enable bit. + * - M – Enable the MMU. + */ static inline unsigned long get_cr(void) { unsigned long val; diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index 85e374f8..c549492e 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -54,8 +54,16 @@ #define MPIDR_INVALID (~MPIDR_HWID_BITMASK) #define MPIDR_LEVEL_BITS 8 +/* IAMROOT-12D (2016-03-26): + * -------------------------- + * ((1 << 8) - 1) = (0x100 - 1) = 0xFF + */ #define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1) +/* IAMROOT-12D (2016-03-26): + * -------------------------- + * ((0xF00 >> 0) & 0xFF) = 0x0 + */ #define MPIDR_AFFINITY_LEVEL(mpidr, level) \ ((mpidr >> (MPIDR_LEVEL_BITS * level)) & MPIDR_LEVEL_MASK) @@ -83,6 +91,12 @@ extern unsigned int processor_id; +/* IAMROOT-12D (2016-03-26): + * -------------------------- + * 라즈베리파이2 의 경우 + * MRC p15, 0, r0, c0, c0, 0 ---> 0x410FC075 + * MRC p15, 0, r0, c0, c0, 5 ---> 0x80000F00 + */ #ifdef CONFIG_CPU_CP15 #define read_cpuid(reg) \ ({ \ @@ -99,6 +113,11 @@ extern unsigned int processor_id; * any is_smp() tests, which can cause undefined instruction aborts on * ARM1136 r0 due to the missing extended CP15 registers. */ +/* IAMROOT-12CD (2016-08-23): + * -------------------------- + * CPUID_EXT_MMFR0 "c1, 4" -> 0x10201105 + * mrc p15, 0, %0, c0, c1, 4 + */ #define read_cpuid_ext(ext_reg) \ ({ \ unsigned int __val; \ @@ -147,6 +166,26 @@ static inline unsigned int __attribute_const__ read_cpuid_ext(unsigned offset) * compiler that it's constant. Use this function to read the CPU ID * rather than directly reading processor_id or read_cpuid() directly. */ +/* IAMROOT-12D (2016-05-23): + * -------------------------- + * 프로세서에 대한 정보를 포함하는 디바이스 ID 코드를 반환한다. + * + * Main ID Register format + * + * 31 24 23 20 19 16 15 4 3 0 + * +------------+---------+--------------+-------------+---------+ + * |Implementer | Variant | Architecture | Part number | revison | + * +------------+---------+--------------+-------------+---------+ + * + * 라즈베리파이2 의 경우 + * MRC p15, 0, r0, c0, c0, 0 ---> 0x410FC075 + * + * Implementer : 0x41 (ARM) + * Variant : 0x0 + * Architecture : 0xF (ARMv7) + * Part number : 0xc07(Cortex-A7 MPcore) + * revision : 0x5 + */ static inline unsigned int __attribute_const__ read_cpuid_id(void) { return read_cpuid(CPUID_ID); @@ -193,6 +232,44 @@ static inline unsigned int __attribute_const__ xscale_cpu_arch_version(void) return read_cpuid_id() & ARM_CPU_XSCALE_ARCH_MASK; } +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * Read Cache Type Register + * 아키택처의 캐쉬 정보를 제공 + * MRC p15, 0, r0, c0, c0, 1 --> 0x84448003 + * + * 31 29 27 23 19 15 13 3 0 + * +---+-+----+----+----+--+----------+----+ + * |100|0|CWG |ERG |DL |L |0000000000|IL | + * +---+-+----+----+----+--+----------+----+ + * + * [31:29] Format : Indicates the CTR format: + * 0x4 ARMv7 format. + * + * [27:24] CWG : Cache Write-Back granule. Log 2 of the number of words of the + * maximum size of memory that can be overwritten as a result of + * the eviction of a cache entry that has had a memory location in + * it modified: + * 0x4 Cache Write-Back granule size is 16 words. + * + * [23:20] ERG : Exclusives Reservation Granule. Log 2 of the number of words of + * the maximum size of the reservation granule that has been + * implemented for the Load-Exclusive and Store-Exclusive + * instructions: + * 0x4 Exclusive reservation granule size is 16 words. + * + * [19:16] DminLine : Log 2 of the number of words in the smallest cache line of + * all the data and unified caches that the processor controls: + * 0x4 Smallest data cache line size is 16 words. + * + * [15:14] L1Ip : L1 instruction cache policy. Indicates the indexing and + * tagging policy for the L1 instruction cache: + * 0b10 Virtually Indexed Physically Tagged (VIPT). + * + * [3:0] IminLine : Log 2 of the number of words in the smallest cache line of + * all the instruction caches that the processor controls. + * 0x03 Smallest instruction cache line size is 8 words. + */ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void) { return read_cpuid(CPUID_CACHETYPE); @@ -203,6 +280,14 @@ static inline unsigned int __attribute_const__ read_cpuid_tcmstatus(void) return read_cpuid(CPUID_TCM); } +/* IAMROOT-12D (2016-03-26): + * -------------------------- + * MPIDR 사용 목적 ? + * 멀티 프로세서 시스템에서 스케줄링을 위해 추가 프로세서 식별 메커니즘을 + * 제공한다. + * CPUID_MPIDR = 5 + * read_cpuid(CPUID_MPIDR) 결과값 = 0x80000F00 + */ static inline unsigned int __attribute_const__ read_cpuid_mpidr(void) { return read_cpuid(CPUID_MPIDR); diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index db58deb0..ec783ac7 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -127,9 +127,28 @@ static inline u32 __raw_readl(const volatile void __iomem *addr) /* * Architecture ioremap implementation. */ +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * ARM의 공유 디바이스. + */ #define MT_DEVICE 0 + +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * ARM의 비공유 디바이스 + */ #define MT_DEVICE_NONSHARED 1 + +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 캐쉬 쓰기 버퍼 및 캐시 사용 디바이스 + */ #define MT_DEVICE_CACHED 2 + +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 쓰기 버퍼 및 캐시 미사용 디바이스(Without Cache) + */ #define MT_DEVICE_WC 3 /* * types 4 onwards can be found in asm/mach/map.h and are undefined diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h index 57704085..4e8762c5 100644 --- a/arch/arm/include/asm/irqflags.h +++ b/arch/arm/include/asm/irqflags.h @@ -20,10 +20,39 @@ #if __LINUX_ARM_ARCH__ >= 6 +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * 현재 상태 레지스터를 flags에 저장하고 irq를 disable 시킨다. + * @return 현재 상태 레지스터. + */ static inline unsigned long arch_local_irq_save(void) { unsigned long flags; + /* IAMROOT-12D (2016-04-16): + * -------------------------- + * mrs flags, cpsr + * cpsid i @ irq 인터럽트를 금지한다. + * + * CPS (프로세서 상태 변경) 는 CPSR에서 하나 이상의 모드와 A, I 및 F + * 비트를 변경 하고 다른 CPSR 비트는 변경하지 않습니다. + * + * CPSeffect iflags{, #mode} + * 인수 설명 + * effect 다음 중 하나입니다. + * IE 인터럽트 또는 어보트 사용 + * ID 인터럽트 또는 어보트 사용 안 함 + * + * iflags 다음 중 하나 이상의 시퀀스입니다. + * a 부정확한 어보트를 사용하거나 사용하지 않습니다. + * i IRQ 인터럽트를 사용하거나 사용하지 않습니다. + * f FIQ 인터럽트를 사용하거나 사용하지 않습니다. + * + * CPSID i 는 CPS + ID + i + * ID : 다음에 나오는 iflags를 사용 하지 않음 + * i : 인터럽트이므로 + * 인터럽트를 사용하지 않게 셋팅 + */ asm volatile( " mrs %0, " IRQMASK_REG_NAME_R " @ arch_local_irq_save\n" " cpsid i" @@ -135,6 +164,11 @@ static inline void arch_local_irq_disable(void) /* * Save the current interrupt enable state. */ +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * mrs flags, cpsr + * 현재의 상태 플레그 값을 가져온다. + */ static inline unsigned long arch_local_save_flags(void) { unsigned long flags; @@ -166,6 +200,11 @@ static inline void arch_local_irq_restore(unsigned long flags) : "memory", "cc"); } +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * IRQ 가 disable인지 알아냄. + * IRQMASK_I_BIT 0x00000080 + */ static inline int arch_irqs_disabled_flags(unsigned long flags) { return flags & IRQMASK_I_BIT; diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 0406cb3f..3e3f5653 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -33,6 +33,10 @@ struct machine_desc { unsigned int nr_irqs; /* number of IRQs */ + /* IAMROOT-12D (2016-06-11): + * -------------------------- + * 라즈베리파이2 에는 CONFIG_ZONE_DMA 가 없음. + */ #ifdef CONFIG_ZONE_DMA phys_addr_t dma_zone_size; /* size of DMA-able area */ #endif @@ -59,6 +63,10 @@ struct machine_desc { void (*init_time)(void); void (*init_machine)(void); void (*init_late)(void); + /* IAMROOT-12D (2016-06-11): + * -------------------------- + * 라즈베리파이2 에는 CONFIG_MULTI_IRQ_HANDLER 가 없음. + */ #ifdef CONFIG_MULTI_IRQ_HANDLER void (*handle_irq)(struct pt_regs *); #endif diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 184def0e..a22ae88b 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -31,6 +31,10 @@ #define UL(x) _AC(x, UL) /* PAGE_OFFSET - the virtual address of the start of the kernel image */ +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * CONFIG_PAGE_OFFSET=0x80000000 + */ #define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET) #ifdef CONFIG_MMU @@ -39,6 +43,10 @@ * TASK_SIZE - the maximum size of a user space task. * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area */ +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * 0x80000000 - 0x01000000(16M) = 0x7f000000 + */ #define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M)) #define TASK_UNMAPPED_BASE ALIGN(TASK_SIZE / 3, SZ_16M) @@ -51,6 +59,12 @@ * The module space lives between the addresses given by TASK_SIZE * and PAGE_OFFSET - it must be within 32MB of the kernel text. */ +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 모듈 공간은 TASK_SIZE와 PAGE_OFFSET 사이에 있다. - 이것은 커널 text 32MB이내 + * 에 있어야한다. + * MODULES_VADDR = 2G-16M = 0x7f000000(2030M) + */ #ifndef CONFIG_THUMB2_KERNEL #define MODULES_VADDR (PAGE_OFFSET - SZ_16M) #else @@ -152,6 +166,10 @@ * have CONFIG_ARM_PATCH_PHYS_VIRT. Assembly code must always use * PLAT_PHYS_OFFSET and not PHYS_OFFSET. */ +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * CONFIG_PHYS_OFFSET=0 + */ #define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) #ifndef __ASSEMBLY__ @@ -165,12 +183,24 @@ * PFN 0 == physical address 0. */ #if defined(__virt_to_phys) +/* IAMROOT-12A: + * ------------ + * 메모리 Case 1. + * ------------ + * 별도 제작한 __virt_to_phys 매크로 사용 시 + * + * 이 헤더 화일(asm/memory.h)에서 기본 제공하는 __virt_to_phys() 인라인함수를 + * 사용하지 않을 때 __virt_to_phys 매크로를 정의하여 사용하는 경우에 아래 3줄의 + * 설정을 사용한다. + * + * 아직 ARM 기본 빌드에서는 별도로 정의하여 사용하는 시스템이 없음. + */ #define PHYS_OFFSET PLAT_PHYS_OFFSET #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT)) #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#elif defined(CONFIG_ARM_PATCH_PHYS_VIRT) +#elif defined(CONFIG_ARM_PATCH_PHYS_VIRT) /* IAMROOT-12D: NOT SET */ /* * Constants used to force the right instruction encodings and shifts @@ -191,6 +221,13 @@ extern const void *__pv_table_begin, *__pv_table_end; ((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \ PHYS_PFN_OFFSET) +/* IAMROOT-12CD (2016-06-25): + * -------------------------- + * __pv_stub((unsigned long) x, t, "sub", __PV_BITS_31_24); + * 1: sub t, from, __PV_BITS_31_24 + * t = from - __PV_BITS_31_24 + * t = from - 0x81000000 + */ #define __pv_stub(from,to,instr,type) \ __asm__("@ __pv_stub\n" \ "1: " instr " %0, %1, %2\n" \ @@ -243,25 +280,53 @@ static inline unsigned long __phys_to_virt(phys_addr_t x) * assembler expression receives 32 bit argument * in place where 'r' 32 bit operand is expected. */ + /* IAMROOT-12CD (2016-06-25): + * -------------------------- + * t = from - __PV_BITS_31_24 + */ __pv_stub((unsigned long) x, t, "sub", __PV_BITS_31_24); return t; } -#else +#else /* IAMROOT-12D: 라즈베리파이2 사용 */ +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * PHYS_OFFSET = 0 + */ #define PHYS_OFFSET PLAT_PHYS_OFFSET + +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * PHYS_PFN_OFFSET = 0 + */ #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT)) +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * reutrn x - 0x80000000 + 0 + */ static inline phys_addr_t __virt_to_phys(unsigned long x) { return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET; } +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * return x - 0x0 + 0x80000000 + * ex) x = 0x100 + * 0x100 - 0 + 0x80000000 = 0x80000100 + */ static inline unsigned long __phys_to_virt(phys_addr_t x) { return x - PHYS_OFFSET + PAGE_OFFSET; } +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * (kaddr - 0x80000000) >> 12 + 0 + * 페이지 단위(4k)로 나눈 몫 + */ #define virt_to_pfn(kaddr) \ ((((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) + \ PHYS_PFN_OFFSET) @@ -281,6 +346,10 @@ static inline phys_addr_t virt_to_phys(const volatile void *x) } #define phys_to_virt phys_to_virt +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * 물리주소를 가상 주소로 변환 : 0x100 --> 0x80000100 + */ static inline void *phys_to_virt(phys_addr_t x) { return (void *)__phys_to_virt(x); diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 4355f0ec..f267c215 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -13,6 +13,10 @@ /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * PAGE_MASK = 0xfffff000 + */ #define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) #ifndef __ASSEMBLY__ diff --git a/arch/arm/include/asm/percpu.h b/arch/arm/include/asm/percpu.h index a89b4076..af751393 100644 --- a/arch/arm/include/asm/percpu.h +++ b/arch/arm/include/asm/percpu.h @@ -21,6 +21,18 @@ * in the TPIDRPRW. TPIDRPRW only exists on V6K and V7 */ #if defined(CONFIG_SMP) && !defined(CONFIG_CPU_V6) +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * TPIDRPRW can be read write only at PL1 or higher. + * http://www.iamroot.org/xe/index.php?mid=Kernel_10_ARM&document_srl=184082&sort_index=readed_count&order_type=desc + * + * https://lwn.net/Articles/527927/ + * Use the previously unused TPIDRPRW register to store percpu offsets. + * TPIDRPRW is only accessible in PL1, so it can only be used in the kernel. + * 이전에 사용되지 않는 TPIDRPRW 레지스터를 percpu 오프셋을 저장하기 위해 사용함 + * TPIDRPRW는 PL1에만 접근이 가능하므로 커널에서만 사용할 수있다. + * (속도 향상을 위해) + */ static inline void set_my_cpu_offset(unsigned long off) { /* Set TPIDRPRW */ diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h index 19cfab52..99db8e30 100644 --- a/arch/arm/include/asm/pgalloc.h +++ b/arch/arm/include/asm/pgalloc.h @@ -22,7 +22,15 @@ #ifdef CONFIG_MMU +/* IAMROOT-12CD (2016-08-23): + * -------------------------- + * _PAGE_USER_TABLE = 0x1 | 0x10 | 0x20 = 0x31 + */ #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER)) +/* IAMROOT-12CD (2016-08-23): + * -------------------------- + * _PAGE_KERNEL_TABLE = 0x01 | 0x10 | 0x0 = 0x11 + */ #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL)) #ifdef CONFIG_ARM_LPAE diff --git a/arch/arm/include/asm/pgtable-2level-hwdef.h b/arch/arm/include/asm/pgtable-2level-hwdef.h index 5e68278e..24997f8b 100644 --- a/arch/arm/include/asm/pgtable-2level-hwdef.h +++ b/arch/arm/include/asm/pgtable-2level-hwdef.h @@ -30,10 +30,20 @@ #define PMD_SECT_PXN (_AT(pmdval_t, 1) << 0) /* v7 */ #define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2) #define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3) +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * Execute never bits int the TLB entry : 1로 설정하면 실행을 못한다. + * http://forum.falinux.com/zbxe/?mid=lecture_tip&page=9&document_srl=555371 + */ #define PMD_SECT_XN (_AT(pmdval_t, 1) << 4) /* v6 */ #define PMD_SECT_AP_WRITE (_AT(pmdval_t, 1) << 10) #define PMD_SECT_AP_READ (_AT(pmdval_t, 1) << 11) #define PMD_SECT_TEX(x) (_AT(pmdval_t, (x)) << 12) /* v5 */ +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * APX(AP eXtension) + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/CHDDEFEE.html + */ #define PMD_SECT_APX (_AT(pmdval_t, 1) << 15) /* v6 */ #define PMD_SECT_S (_AT(pmdval_t, 1) << 16) /* v6 */ #define PMD_SECT_nG (_AT(pmdval_t, 1) << 17) /* v6 */ @@ -44,6 +54,10 @@ #define PMD_SECT_BUFFERED (PMD_SECT_BUFFERABLE) #define PMD_SECT_WT (PMD_SECT_CACHEABLE) #define PMD_SECT_WB (PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE) +/* IAMROOT-12CD (2016-08-23): + * -------------------------- + * PMD_SECT_MINICACHE = 0x100 | 0x8 = 0x1008 + */ #define PMD_SECT_MINICACHE (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE) #define PMD_SECT_WBWA (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE) #define PMD_SECT_NONSHARED_DEV (PMD_SECT_TEX(2)) diff --git a/arch/arm/include/asm/pgtable-2level-types.h b/arch/arm/include/asm/pgtable-2level-types.h index 66cb5b0e..a0a1da22 100644 --- a/arch/arm/include/asm/pgtable-2level-types.h +++ b/arch/arm/include/asm/pgtable-2level-types.h @@ -16,6 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * 라즈베리파이2는 아마도.. 2단계 pagetable을 쓸것이다. + */ #ifndef _ASM_PGTABLE_2LEVEL_TYPES_H #define _ASM_PGTABLE_2LEVEL_TYPES_H diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index bfd662e4..5f7341b8 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h @@ -82,9 +82,21 @@ * PMD_SHIFT determines the size of the area a second-level page table can map * PGDIR_SHIFT determines what a third-level page table entry can map */ +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 2단계 페이지 테이블 구조 + * 31 21 20 12 11 0 + * +------------+---------+-----------+ + * | PGD = PMD | PTE | offset | + * +------------+---------+-----------+ + */ #define PMD_SHIFT 21 #define PGDIR_SHIFT 21 +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * PMD_SIZE = 2M + */ #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) @@ -117,20 +129,60 @@ * The PTE table pointer refers to the hardware entries; the "Linux" * entries are stored 1024 bytes below. */ +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * 페이지가 메모리에 상주해 있고 스왑 아웃되지 않은 상태 + */ #define L_PTE_VALID (_AT(pteval_t, 1) << 0) /* Valid */ +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * 페이지가 메모리에 상주해 있고 스왑 아웃되지 않은 상태 + */ #define L_PTE_PRESENT (_AT(pteval_t, 1) << 0) +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * 페이지에 접근이 된 경우 + */ #define L_PTE_YOUNG (_AT(pteval_t, 1) << 1) +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * 페이지가 변경된 경우 + */ #define L_PTE_DIRTY (_AT(pteval_t, 1) << 6) #define L_PTE_RDONLY (_AT(pteval_t, 1) << 7) +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * user process가 접근 가능한 경우 1, 커널만 접근 가능하게 할 경우 0 + */ #define L_PTE_USER (_AT(pteval_t, 1) << 8) +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * Excute Never로 실행 금지 + */ #define L_PTE_XN (_AT(pteval_t, 1) << 9) +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * 공유된 페이지 + */ #define L_PTE_SHARED (_AT(pteval_t, 1) << 10) /* shared(v6), coherent(xsc3) */ +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * 페이지가 있으나 access 할 수 없는 페이지 + */ #define L_PTE_NONE (_AT(pteval_t, 1) << 11) /* * These are the memory types, defined to be compatible with * pre-ARMv6 CPUs cacheable and bufferable bits: XXCB */ +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * XXCB --> XX(TEX), C(cacheable), B(bufferable) + * TEX C B + * 0 1 0 Write Through(no Write Allocate) + * 0 1 1 Write Back(no Write Allocate) + * 1 1 1 Write Back, Write Allocate + */ #define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << 2) /* 0000 */ #define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << 2) /* 0001 */ #define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 0x02) << 2) /* 0010 */ diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index a745a2a5..9572802d 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -47,6 +47,9 @@ */ #define PMD_SHIFT 21 +/* + * PMD_SIZE: 2MB + */ #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~((1 << PMD_SHIFT) - 1)) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index f4035419..03eaad92 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -42,7 +42,17 @@ * area for the same reason. ;) */ #define VMALLOC_OFFSET (8*1024*1024) +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * high_memory = 0xBC000000, VMALLOC_OFFSET=8M + * VMALLOC_START = 0xBC000000 + 8M --> 968M의 virtual addr + * VMALLOC_START = 0xbc800000 + */ #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * VMALLOC_END = 4080M (4G - 16M) + */ #define VMALLOC_END 0xff000000UL #define LIBRARY_TEXT_START 0x0c000000 @@ -144,6 +154,13 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, * 2) If we could do execute protection, then read is implied * 3) write implies read permissions */ +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 대부분의 ARM 하드웨어 상에서는... + * 1) 실행 보호를 할수 없다. + * 2) 만약 실행보호를 할수 있다면, 읽기는 묵시적로 가능하다. + * 3) 쓰기가 가능하면 읽기는 묵시적으로 가능하다. + */ #define __P000 __PAGE_NONE #define __P001 __PAGE_READONLY #define __P010 __PAGE_COPY diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 8a1e8e99..ef58bc3d 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -115,6 +115,15 @@ static inline void prefetch(const void *ptr) } #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP) +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * PLD, PLDW + * 데이터 및 명령어 사전 로드. 프로세서는 주소에서 데이터나 명령어를 곧 로 + * 드할 것이라는 신호를 메모리 시스템에 보낼 수 있습니다. + * + * DW 쓰기를 위한 데이터 주소 + * D 데이터 주소 + */ #define ARCH_HAS_PREFETCHW static inline void prefetchw(const void *ptr) { diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h index cd94ef2e..14cffa5e 100644 --- a/arch/arm/include/asm/prom.h +++ b/arch/arm/include/asm/prom.h @@ -11,7 +11,7 @@ #ifndef __ASMARM_PROM_H #define __ASMARM_PROM_H -#ifdef CONFIG_OF +#ifdef CONFIG_OF /* IAMROOT-12D: 라즈베리파이2 SET */ extern const struct machine_desc *setup_machine_fdt(unsigned int dt_phys); extern void __init arm_dt_init_cpu_maps(void); diff --git a/arch/arm/include/asm/smp_plat.h b/arch/arm/include/asm/smp_plat.h index 993e5224..3fcf3b4f 100644 --- a/arch/arm/include/asm/smp_plat.h +++ b/arch/arm/include/asm/smp_plat.h @@ -14,6 +14,10 @@ /* * Return true if we are running on a SMP platform */ +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * Symmetric Multiprocessing (대칭형 멀티 프로세싱 : SMP) + */ static inline bool is_smp(void) { #ifndef CONFIG_SMP diff --git a/arch/arm/include/asm/stackprotector.h b/arch/arm/include/asm/stackprotector.h index de003327..3f09a95e 100644 --- a/arch/arm/include/asm/stackprotector.h +++ b/arch/arm/include/asm/stackprotector.h @@ -23,6 +23,17 @@ extern unsigned long __stack_chk_guard; * NOTE: this must only be called from functions that never return, * and it must always be inlined. */ + +/* IAMROOT-12D (2016-04-30): + * -------------------------- + * 기본적인 sequence : + * - 랜덤한 canary 값 생성 + * - 생성한 값을 현재 스텍의 canary 영역에 넣는다. + * - 앞서 구한 canary 값을 global 변수인 __stack_chk_guard에 넣는다. + * 이 global 변수로 stack overflow를 체크한다. + * 다만, __stack_chk_guard는 처음에 지정한 값으로 고정되기에 + * SMP상에서 프로세스 별로 서로 다른 canary값을 사용할 수 없다. + */ static __always_inline void boot_init_stack_canary(void) { unsigned long canary; diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index bd32eded..31ef3070 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -17,6 +17,10 @@ #include #define THREAD_SIZE_ORDER 1 +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * THREAD_SIZE = 8k + */ #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) #define THREAD_START_SP (THREAD_SIZE - 8) @@ -92,6 +96,11 @@ register unsigned long current_stack_pointer asm ("sp"); */ static inline struct thread_info *current_thread_info(void) __attribute_const__; +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * THREAD_SIZE 는 8k이고 sp포인터에 스택과 thread_info 구조체가 있다. + * 8k하위 비트는 날려버린다. + */ static inline struct thread_info *current_thread_info(void) { return (struct thread_info *) diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index def9e570..9767e1dc 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -126,6 +126,10 @@ # define _TLB v4wbi # endif #else +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * 라즈베리파이2 + */ # define fr_possible_flags 0 # define fr_always_flags (-1UL) #endif @@ -229,6 +233,13 @@ extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long); extern struct cpu_tlb_fns cpu_tlb; +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * cpu_tlb.tlb_flags = v7wbi_tlb_flags_smp(TLB_WB | TLB_BARRIER | \ + * TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | \ + * TLB_V7_UIS_ASID | TLB_V7_UIS_BP) + * = 0x90f00000 + */ #define __cpu_tlb_flags cpu_tlb.tlb_flags /* @@ -304,6 +315,23 @@ extern struct cpu_tlb_fns cpu_tlb; #define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f))) +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * f 조건이 always_tlb_flags에 있으면 mcr 명령어를 실행하고 + * f 조건이 possible_tlb_flags 에 있으면 + * f 조건이 __tlb_flag에 있으면 mrc 실행. + * + * __tlb_op(TLB_DCLEAN, "p15, 0, %0, c7, c10, 1 @ flush_pmd", pmd) + * always_tlb_flags & (f) == false + * possible_tlb_flags & (f) = true + * tst __tlb_flag, f @ and 계산 결과 + * mcrne p15, 0, pmd, c7, c10, 1 @ flush_pmd + * @ Clean DCache single entry (MVA) MCR p15, 0, , c7, c10, 1 + * + * __tlb_op(TLB_L2CLEAN_FR, "p15, 1, %0, c15, c9, 1 @ L2 flush_pmd", pmd) + * always_tlb_flags & (f) = false + * possible_tlb_flags & (f) = false + */ #define __tlb_op(f, insnarg, arg) \ do { \ if (always_tlb_flags & (f)) \ @@ -316,7 +344,18 @@ extern struct cpu_tlb_fns cpu_tlb; : "cc"); \ } while (0) +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * f(인자)를 지원하면 regs(인자)를 실행해라. + * tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd); + */ #define tlb_op(f, regs, arg) __tlb_op(f, "p15, 0, %0, " regs, arg) + +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd); + * __tlb_op(TLB_L2CLEAN_FR, "p15, 1, %0, c15, c9, 1 @ L2 flush_pmd", pmd) + */ #define tlb_l2_op(f, regs, arg) __tlb_op(f, "p15, 1, %0, " regs, arg) static inline void __local_flush_tlb_all(void) @@ -584,11 +623,31 @@ static inline void flush_pmd_entry(void *pmd) dsb(ishst); } +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * pmd + * 0x80004000 + * 0x80004008 + * 0x80004016 + * 0x80004024 + */ static inline void clean_pmd_entry(void *pmd) { + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * __tlb_flag = 0x90f00000 + */ const unsigned int __tlb_flag = __cpu_tlb_flags; + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * Clean DCache single entry (MVA) MCR p15, 0, , c7, c10, 1 + */ tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd); + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * 아래는 TLB_L2CLEAN_FR에 해당 되는 flag가 없어서 실행 안함. + */ tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd); } diff --git a/arch/arm/include/uapi/asm/hwcap.h b/arch/arm/include/uapi/asm/hwcap.h index 20d12f23..e25f090d 100644 --- a/arch/arm/include/uapi/asm/hwcap.h +++ b/arch/arm/include/uapi/asm/hwcap.h @@ -4,14 +4,14 @@ /* * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP */ -#define HWCAP_SWP (1 << 0) -#define HWCAP_HALF (1 << 1) -#define HWCAP_THUMB (1 << 2) +#define HWCAP_SWP (1 << 0) /* IAMROOT-12D : SWP 명령어 지원 여부 */ +#define HWCAP_HALF (1 << 1) /* IAMROOT-12D : 16bit 데이형 지원 */ +#define HWCAP_THUMB (1 << 2) /* IAMROOT-12D : THUMB 명령어 지원 */ #define HWCAP_26BIT (1 << 3) /* Play it safe */ -#define HWCAP_FAST_MULT (1 << 4) +#define HWCAP_FAST_MULT (1 << 4) /* IAMROOT-12D : 빠른 곱셈 지원 */ #define HWCAP_FPA (1 << 5) #define HWCAP_VFP (1 << 6) -#define HWCAP_EDSP (1 << 7) +#define HWCAP_EDSP (1 << 7) /* IAMROOT-12D : DSP extensions */ #define HWCAP_JAVA (1 << 8) #define HWCAP_IWMMXT (1 << 9) #define HWCAP_CRUNCH (1 << 10) @@ -19,9 +19,13 @@ #define HWCAP_NEON (1 << 12) #define HWCAP_VFPv3 (1 << 13) #define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */ +/* IAMROOT-12D (2016-05-28): + * -------------------------- + * Thread Local Storage : Thread별로 다른 값을 가질수 있는 전역 변수 + */ #define HWCAP_TLS (1 << 15) #define HWCAP_VFPv4 (1 << 16) -#define HWCAP_IDIVA (1 << 17) +#define HWCAP_IDIVA (1 << 17) /* IAMROOT-12D : SDIV,UDIV 명령어지원 */ #define HWCAP_IDIVT (1 << 18) #define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ #define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index 11c54de9..de6735c3 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -183,6 +183,11 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id) static const void * __init arch_get_next_mach(const char *const **match) { + /* IAMROOT-12D (2016-05-26): + * -------------------------- + * __arch_info_begin = section ".init.arch.info" + * arch/arm/mach-bcm2709/bcm2709.c 참고 + */ static const struct machine_desc *mdesc = __arch_info_begin; const struct machine_desc *m = mdesc; @@ -201,10 +206,32 @@ static const void * __init arch_get_next_mach(const char *const **match) * If a dtb was passed to the kernel in r2, then use it to choose the * correct machine_desc and to setup the system. */ +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * static const struct machine_desc __mach_desc_BCM_2709 + * _used + * __attribute__((__section__(".arch.info.init"))) = { + * .nr = MACH_TYPE_BCM_2709 + * .name = "BCM_2709", + * .smp = smp_ops(bcm2709_smp_ops), + * .map_io = bcm2709_map_io, + * .init_irq = bcm2709_init_irq, + * .init_time = bcm2709_timer_init, + * .init_machine = bcm2709_init, + * .init_early = bcm2709_init_early, + * .reserve = board_reserve, + * .restart = bcm2709_restart, + * .dt_compat = bcm2709_compat, + * }; + */ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) { const struct machine_desc *mdesc, *mdesc_best = NULL; +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * 라즈베리파이2에는 CONFIG_ARCH_MULTIPLATFORM 가 셋팅 되어 있지 않다. + */ #ifdef CONFIG_ARCH_MULTIPLATFORM DT_MACHINE_START(GENERIC_DT, "Generic DT based system") MACHINE_END @@ -212,9 +239,17 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) mdesc_best = &__mach_desc_GENERIC_DT; #endif + /* IAMROOT-12D (2016-06-11): + * -------------------------- + * 간단한 fdt헤더 검사와 crc32을 만든다. + */ if (!dt_phys || !early_init_dt_verify(phys_to_virt(dt_phys))) return NULL; + /* IAMROOT-12CD: + * ------------ + * 현재 시스템에 맞는 머신 디스크립터를 찾아온다. + */ mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); if (!mdesc) { @@ -237,6 +272,10 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) dump_machine_table(); /* does not return */ } + /* IAMROOT-12D (2016-06-11): + * -------------------------- + * 라즈베리파이2는 dt_fixup 함수가 없음. + */ /* We really don't want to do this, but sometimes firmware provides buggy data */ if (mdesc->dt_fixup) mdesc->dt_fixup(); diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index 8733012d..af9aeda6 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S @@ -44,6 +44,38 @@ * r2 either valid atags pointer, valid dtb pointer, or zero * r5, r6 corrupted */ +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * r2에는 DTB 가 있다. + * + * 검사하는 목록 + * 1. align 검사 + * 2. DTB인지 검사 (magic값으로 체크) DTB라면 리턴 + * 3. (DTB가 아닌 경우) + * atag는 첫번째에 매직값이 담겨있는게 아니라, 아래 구조체의 size가 있다. + * + * struct tag_header { + * __u32 size; + * __u32 tag; + * }; + * union{ + * struct tag_core { + * __u32 flags; / * bit 0 = read-only * / + * __u32 pagesize; + * __u32 rootdev; + * }; + * ... + * }; + * 이때의 size는 word기준으로 담겨있다. + * + * #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) + * 2*4 의 2는 struct tag_header의 엔트리, 4는 byte이다. + * 3*4 의 3은 tag_core의 엔트리이다. 4는 바이트를 의미한다. + * 마지막에 >> 2 를 하는 이유는, 워드단위로 맞춰주기 위함이다. + * + * 이후, r5에 담은 정보는 tag_header.tag 이다. TAG_CORE와 비교한다. + * #define ATAG_CORE 0x54410001 + */ __vet_atags: tst r2, #0x3 @ aligned? bne 1f @@ -77,6 +109,10 @@ ENDPROC(__vet_atags) * r2 = atags/dtb pointer * r9 = processor ID */ +/* IAMROOT-12D (2016-03-19): +* -------------------------- +* 여기서 부터는 0x80000000 으로 시작되는 절대 주소번지를 사용한다. +*/ __INIT __mmap_switched: adr r3, __mmap_switched_data @@ -88,6 +124,26 @@ __mmap_switched: strne fp, [r5], #4 bne 1b + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * fp(r11) frame pointer + * ip(r12) scratch register + * sp(r13) stack pointer + * lr(r14) link register + * pc(r15) program counter + * + * cc : carry clear : 보다 작음 + * cs : carry set : 크거나 같음. + * + * memset(r6, 0, r7 - r6); + * memset(__bss_start, 0, _end - __bss_start); + * + * fp = 0; r6 = __bss_start ; r7 = _end; + * while(r6 < r7) { + * *r6 = 0; + * r6 += 4; + * } + */ mov fp, #0 @ Clear BSS (and zero fp) 1: cmp r6, r7 strcc fp, [r6],#4 @@ -104,6 +160,13 @@ __mmap_switched: b start_kernel ENDPROC(__mmap_switched) + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * __data_loc : .data section 시작위치 + * _sdata : .data section 시작위치 + * __bss_start : .bss section 시작위치 + * _end : .bss section 끝위치 + */ .align 2 .type __mmap_switched_data, %object __mmap_switched_data: @@ -125,6 +188,12 @@ __mmap_switched_data: /* * This provides a C-API version of __lookup_processor_type */ +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * linux/arch/arm/kernel/setup.c 에 함수가 선언되어있다. + * extern struct proc_info_list *lookup_processor_type(unsigned int); + * C에서 이용할 수 있는 API로 정의되어 있다. + */ ENTRY(lookup_processor_type) stmfd sp!, {r4 - r6, r9, lr} mov r9, r0 @@ -149,6 +218,21 @@ ENDPROC(lookup_processor_type) * r5 = proc_info pointer in physical address space * r9 = cpuid (preserved) */ +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * r4: . + * r5: __proc_info_begin + * r6: __proc_info_end + * + * r3 - r4 => 물리 메모리에서의 Offset을 구한다. + * r3는 __lookup_processor_type_data의 물리주소이고, + * r4는 파일에서의 offset을 가지고 있다. + * 두 값의 차이를 구하면 물리메모리에서의 위치를 계산할 수 있는 offset을 + * 구할 수 있다. + * + * proc_info_list에서 v7의 cpu 정보를 읽어와 구조체에 담는다. + * 이 채워진 구조체 정보의 주소를 r5에 저장한다. + */ __lookup_processor_type: adr r3, __lookup_processor_type_data ldmia r3, {r4 - r6} @@ -168,6 +252,34 @@ ENDPROC(__lookup_processor_type) /* * Look in for information about the __proc_info structure. + */ +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * /__proc_info_begin은 linux/arch/arm/kernel/vmlinux.lds.S에 아래와 같이 + * 디파인되어있다. + * #define PROC_INFO \ + * . = ALIGN(4); \ + * VMLINUX_SYMBOL(__proc_info_begin) = .; \ + * *(.proc.info.init) \ + * VMLINUX_SYMBOL(__proc_info_end) = .; + * + * .proc.info.init은 /linux/arch/arm/mm/proc-v7.S 을 참고하라. + * .proc.info.init의 섹션이 정의되어 있고 프로세서 정보를 담은 레이블들이 존재 + * 한다. + * + * 우리는 라즈베리파이니까, 아래의 정보를 가져올 것이다. + * + * .type __v7_proc_info, #object + * __v7_proc_info: + * .long 0x000f0000 @ Required ID value + * .long 0x000f0000 @ Mask for ID + * __v7_proc __v7_proc_info, __v7_setup + * .size __v7_proc_info, . - __v7_proc_info + * + * 참고] 라즈베리 파이 proc_types + * 라즈베리파이 2 cpu ID : 0x410fc075 + * ( real_cpu_id ^ proc_types_cpu_id ) & mask = 0 + * ( 0x410fc075 ^ 0x000f0000 ) & 0x000f0000 = 0 */ .align 2 .type __lookup_processor_type_data, %object @@ -218,6 +330,10 @@ __error: str r3, [r0], #4 str r3, [r0], #4 #endif +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * Error나면 무한루프.. nop + */ 1: mov r0, r0 b 1b ENDPROC(__error) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 380430a6..2ee56cf0 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -34,23 +34,63 @@ * the least significant 16 bits to be 0x8000, but we could probably * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. */ +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * KERNEL_RAM_VADDR : 커널의 가상 메모리 주소 + * 예를들어, 32bit에서 3/1GB 로 영역을 split했을 때, 1GB의 시작주소이다. + * + * 커널 스플릿 설정에 따라서 PAGE_OFFSET의 주소가 다른데, + * + * default PHYS_OFFSET if !MMU + * default 0x40000000 if VMSPLIT_1G + * default 0x80000000 if VMSPLIT_2G + * default 0xC0000000 + * + * 라즈베리파이는 2/2GB 로 스플릿을 하기 때문에 0x80000000 로 설정된다. + * + * KERNEL_RAM_VADDR: 0x80000000 + 0x8000 = 0x80008000 가 실제 커널의 가상메모리 + * 시작주소가 된다 + * + * 참고] 위의 설정을 보고 싶으면 /boot/config-리눅스버전 파일 안에 모두 기록되어 + * 있다. + */ #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 #error KERNEL_RAM_VADDR must start at 0xXXXX8000 #endif +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * LPAE: 32bit에서 4GB이상 메모리를 지원하기 위해 사용했던 설정 + */ #ifdef CONFIG_ARM_LPAE /* LPAE requires an additional page for the PGD */ #define PG_DIR_SIZE 0x5000 #define PMD_ORDER 3 #else +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * PG_DIR_SIZE: 32K (페이지테이블 사이즈) + * 0x4000 = 2^15 = 2^5 * 2^10 = 32 * 1K + */ #define PG_DIR_SIZE 0x4000 #define PMD_ORDER 2 #endif +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * swapper_pg_dir: 0x80004000 이다. + */ .globl swapper_pg_dir .equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * page table 물리주소를 구하기 위한 매크로 + * rd = phys + TEXT_OFFSET - PG_DIR_SIZE; + * rd = phys + 0x8000 - 0x4000; + * rd = phys + 0x4000 + */ .macro pgtbl, rd, phys add \rd, \phys, #TEXT_OFFSET sub \rd, \rd, #PG_DIR_SIZE @@ -73,10 +113,42 @@ * We're trying to keep crap to a minimum; DO NOT add any machine specific * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. + */ +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * 우리가 사용하는 라즈베리파이의 정보이다. + * (linux/arch/arm/tools/mach-types) + * + * machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number + * bcm2709 MACH_BCM2709 BCM2709 3139 + * + * .arm 모드로 시작 + * + * #define __HEAD .section ".head.text","ax" + * __HEAD: 섹션을 정의 */ .arm __HEAD + +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * 여기부터 시작 + * #include + * + * #ifndef ENTRY + * #define ENTRY(name) \ + * .globl name ASM_NL \ + * ALIGN ASM_NL \ + * name: + * #endif + * + * .globl stext ; + * ALIGN ; + * stext: + * + * stext를 글로벌로 선언하고, 레이블을 생성한다. + */ ENTRY(stext) ARM_BE8(setend be ) @ ensure we are in BE8 mode @@ -88,6 +160,19 @@ ENTRY(stext) #ifdef CONFIG_ARM_VIRT_EXT bl __hyp_stub_install #endif + +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * r9은 스크래치 레지스터이다. + * 참고] 스크래치 레지스터: 고양이가 할퀴듯 아무렇게나 사용하는 레지스터 + * + * safe_svcmode_maskall : 모든 인터럽트를 중단하고, 안전하게 svc모드로 변경된다. + * + * __lookup_processor_type: cpuid를 r9으로 넘겨주고, r5에 프로세스정보를 얻는다. + * + * __error_p: 프로세서 타입 찾다가 에러 + * __error_lpae: LPAE 에러 + */ @ ensure svc mode and all interrupts masked safe_svcmode_maskall r9 @@ -105,6 +190,21 @@ ENTRY(stext) blo __error_lpae @ only classic page table format #endif + +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * 참고: XIP - 커널을 압축하지않고 ROM FLASH에서 바로 실행되는 커널 + * + * MMU가 Off상태이기 때문에 물리주소를 직접 이용한다. + * + * r3: 2번 레이블의 물리주소가 담긴다. (예: 0x8080) + * r4: 2번 레이블의 가상주소 (0x80008080) + * (r4 = r3 - r4 = 0x8080 - 0x80008080 = 0x80000000) + * r8: 가상 메모리 시작 Offset (0x80000000) + * 오버플로우 발생으로 인해 더한값이 0 이 된다. + * add 연산 후, 물리 메모리 Offset 이 된다. + * (r8 = r8 + r4 = 0x80000000 + 0x80000000 = 0x0) + */ #ifndef CONFIG_XIP_KERNEL adr r3, 2f ldmia r3, {r4, r8} @@ -118,13 +218,40 @@ ENTRY(stext) * r1 = machine no, r2 = atags or dtb, * r8 = phys_offset, r9 = cpuid, r10 = procinfo */ + + /* IAMROOT-12D (2016-01-30): + * -------------------------- + * atags 포인터의 유효성 검사 + */ bl __vet_atags + + /* IAMROOT-12D (2016-01-30): + * -------------------------- + * SMP: Symmetric Multi Processing + * + * __fixup_smp를 call 하는 목적 + * : UP환경에서 SMP명령어를 교체하기 위해 + */ #ifdef CONFIG_SMP_ON_UP bl __fixup_smp #endif + + /* IAMROOT-12D (2016-02-13): + * -------------------------- + * PV : Physical Virtual + * + * __fixup_pv_table를 call하는 목적 + * : TODO + */ #ifdef CONFIG_ARM_PATCH_PHYS_VIRT bl __fixup_pv_table #endif + + /* IAMROOT-12D (2016-02-13): + * -------------------------- + * __create_page_talbes 를 call하는 목적 + * : page table들을 만들기 위해 + */ bl __create_page_tables /* @@ -134,6 +261,58 @@ ENTRY(stext) * above. On return, the CPU will be ready for the MMU to be * turned on, and r0 will hold the CPU control register value. */ +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * r10에 담겨있는 구조체 형태 + * + * struct proc_info_list { + * unsigned int cpu_val; + * unsigned int cpu_mask; + * unsigned long __cpu_mm_mmu_flags; / * used by head.S * / + * unsigned long __cpu_io_mmu_flags; / * used by head.S * / + * unsigned long __cpu_flush; / * used by head.S * / + * const char *arch_name; + * const char *elf_name; + * unsigned int elf_hwcap; + * const char *cpu_name; + * struct processor *proc; + * struct cpu_tlb_fns *tlb; + * struct cpu_user_fns *user; + * struct cpu_cache_fns *cache; + * }; + * + * TTBR1: 페이지테이블의 위치(주소)를 저장하는 CPU 레지스터 + * (Translation Table Base Register 1) + * + */ + /* IAMROOT-12D (2016-03-05): + * -------------------------- + * r13: __mmap_switched 레이블의 주소를 가져온다. + * mmu가 켜진 이후 이곳으로 점프한다. + * + * lr 레지스터에 b __enable_mmu 의 레이블의 주소를 담는다. + * r12 = *(r10 + 16) // proc_info_list->cpu_flush + * r10 + 16 = initfn __v7_setup, __v7_proc_info + * + * ldr로 r12에 읽어온 값은 __v7_proc_info - __v7_setup의 값이 담긴다. + * 이때의 값은 음수값이다. (__v7_proc_info 주소 < __v7_setup) + * 이렇게 구해진 r12값에 r10을 더하게 되면 __v7_setup의 주소가 된다. + * + * [결론] r12 = __v7_setup + * + * TODO : + * - TTBR0와 TTBR1이란 무엇인가? + * : http://www.iamroot.org/xe/Kernel_10_ARM/176798 + * - BSYM이란?? + * : http://www.iamroot.org/xe/Kernel_10_ARM/171562 + * : http://www.iamroot.org/xe/Kernel_10_ARM/173070 + * - ret은 ARM 명령어?? + * : 무조건 분기하는 명령어 + * + * adr 은 현재 pc값에 대한 상대 주소를 가져오고 + * ldr 은 상수값 그대로를 가져온다. + * r13에는 0x80008???? 의 값이 들어 있다. + */ ldr r13, =__mmap_switched @ address to jump to after @ mmu has been enabled adr lr, BSYM(1f) @ return (PIC) address @@ -141,10 +320,19 @@ ENTRY(stext) ldr r12, [r10, #PROCINFO_INITFUNC] add r12, r12, r10 ret r12 +/* IAMROOT-12D (2016-03-12): + * -------------------------- + * 다음주 부터는 여기서 시작한다. + */ 1: b __enable_mmu ENDPROC(stext) .ltorg #ifndef CONFIG_XIP_KERNEL +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * . 은 현재의 주소 + * PAGE_OFFSET은 0x80000000 + */ 2: .long . .long PAGE_OFFSET #endif @@ -160,12 +348,47 @@ ENDPROC(stext) * r0, r3, r5-r7 corrupted * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) */ + + /* IAMROOT-12D (2016-02-13): + * -------------------------- + * __create_page_table : + * memset(&page_table, 0, sizeof(&page_table)) + * + * &page_tabe = 0x4000 + * sizeof(&page_table) = 0x4000 + * + * r8 = 0x0 + * + * pgtbl r4, r8 분석 + * + * add r4, r8, #TEXT_OFFSET + * sub r4, r4, #PG_DIR_SIZE + * + * rd = phys + TEXT_OFFSET - PG_DIR_SIZE; + * rd = phys + 0x8000 - 0x4000; + * + * 계산 과정 + * r4 = r8 + 0x8000 - 0x4000 + * r4 = 0x0 + 0x8000 - 0x4000 + * r4 = 0x4000 + */ + __create_page_tables: pgtbl r4, r8 @ page table address /* * Clear the swapper page table */ + /* IAMROOT-12D (2016-02-20): + * -------------------------- + * r0 = r4; ( 0x4000 페이지테이블 시작점 ) + * r3 = 0; + * r6 = 0x8000 ( 페이지테이블 끝지점 ) + * for(r0 = r4; r0mm_mmuflags; + * + * #PROCINFO_MM_MMUFLAGS 를 따라가면, 아래와 같이 선언되어 있고, + * + * DEFINE(PROCINFO_MM_MMUFLAGS, + * offsetof(struct proc_info_list, __cpu_mm_mmu_flags)); + * + * #define DEFINE(sym, val) \ + * asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + * + * 결과적으로 다음 형태와 같은 뜻이 된다. + * #define PROCINFO_MM_MMUFLAGS 8 + * + * r7 = 0x11c0e + * /arch/arm/mm/proc-v7.S 의 __v7_proc 매크로 주석 참고 + * + */ ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags /* * Create identity mapping to cater for __enable_mmu. * This identity mapping will be removed by paging_init(). */ + /* IAMROOT-12D (2016-02-27): + * -------------------------- + * r0 = __turn_mmu_on_loc 의 물리 주소값 (0x8134) + * r3 = __turn_mmu_on_loc 의 가상 주소값 (0x80008134) + * r5 = __turn_mmu_on 의 주소값 (0x80008240) + * r6 = __turn_mmu_on_end 의 주소값 (0x80008260) + * + * r0 = r0 - r3 = 0x8134 - 0x80008134 = 0x80000000 + * r5 = r5 + r0 = 0x80008240 + 0x80000000 = 0x8240 + * r6 = r6 + r0 = 0x80008260 + 0x80000000 = 0x8260 + * r5 = r5 >> 20 = 0x0 + * r6 = r6 >> 20 = 0x0 + */ adr r0, __turn_mmu_on_loc ldmia r0, {r3, r5, r6} sub r0, r0, r3 @ virt->phys offset @@ -218,12 +480,64 @@ __create_page_tables: mov r5, r5, lsr #SECTION_SHIFT mov r6, r6, lsr #SECTION_SHIFT + /* IAMROOT-12D (2016-02-27): + * -------------------------- + * __turn_mmu_on 과 __turn_mmu_on_end 영역만 page table 매핑. + * + * r3 = r7 | (r5 << 20) = 0x11c0e | 0x0 = 0x11c0e + * *(r4 + (r5 << 2) ) = r3 + * *(0x4000 + (0x0 << 2) ) = 0x11c0e + * *(0x4000) = 0x11c0e + * + * if( 0x0 < 0x0 ){ 분기문 진입하지 않음 + * r5 = r5 + 1 = 0x1 + * goto 1b + * } + * + */ 1: orr r3, r7, r5, lsl #SECTION_SHIFT @ flags + kernel base str r3, [r4, r5, lsl #PMD_ORDER] @ identity mapping cmp r5, r6 addlo r5, r5, #1 @ next section blo 1b + + /* IAMROOT-12D (2016-03-05): + * -------------------------- + * 커널코드 시작부터 .bss 섹션의 끝까지 메모리를 매핑한다. + * r4: page table 시작위치 (0x4000) + * r4 + ( 0x80000000 >> (20 - 2) ) + * 2^31 / ( 2^20 * 2^-2) + * 즉, + * r4 + ( (2G / 1M) * 4 ) 로 이해하면 편하다. + * 2048 => 1M단위로 계산된 페이지 테이블의 Index이다. + * 2048 * 4 를 하게되면, 이 페이지 테이블 Index의 주소가 나온다. + * 그 주소는 0x2000이다. + * + * r0 = r4 + 0x2000 = 0x6000 >> 페이지테이블의 주소로 매핑한다. + * + * _end(.bss section의 끝) 0x8092378C - 1 상수값을 r6에 넣는다. + * ldr을 이용해서 담는 이유는, ARM 아키텍쳐에서 해당 상수를 담을수 있는 + * 방법이 없기때문이다. (mov로 담을 수 없는 상수) + * + * r6: 0x8092378B => 약 9.2 MB + * r7: 0x11c0e (mmu_flags값) + * r8: 0x0 (현재 커널의 Base주소) + * + * r6 = r4 + ( r6 >> (20 - 2) ) + * .bss 섹션의 마지막이 매핑되는 페이지 테이블의 주소를 구한다. + * + * r6 = 0x809 (위를 계산하면) => 0x2024 + * 즉, 0x6000 ~ 0x6024 까지 커널의 .bss 섹션까지의 영역과 매핑한다. + * + * 이 시점에서, r0: 0x6000, r6: 0x6024 + * while( r0 < r6 ) + * { + * *r0 = r3; + * r0++; // 0x6000, 0x6004, 0x6008... 물리 주소가 증가한다. + * r3++; // 실제로는 r3의 Base Address만 증가한다. + * } + */ /* * Map our RAM from the start to the end of the kernel .bss section. */ @@ -255,6 +569,36 @@ __create_page_tables: bls 1b #endif + /* IAMROOT-12D (2016-03-05): + * -------------------------- + * 만약 ATAGs/DTB가 정의되어있다면 매핑한다. + * + * r2는 .bss 위에 올려놓은 DTB의 시작주소를 가지고 있다. + * r2 >> 20 => 약 10이 나온다고 가정한다. (정확한 시작주소를 모른다.) + * + * r2에 만약 atag(0x100)이 있었다면, movs에서 zero flag가 세팅될것이고, + * 아래의 코드는 전부 패스하게 된다. + * + * r8: Kernel의 물리 Base Address (현재 0x00) + * + * r0 = 0x00a00000 + * r3 = 0x00a00000 + PAGE_OFFSET(0x80000000) + * r3 = 0x80a00000 (DTB의 주소) + * r7 = 0x11c0e (mmu_flag) + * + * r3 >> ( 20 -2 ) + * 1) r3 >> 20 => 0x80a + * 2) r3 << 2 => 0x2028 + * r4: 0x4000 (PAGE_TABLE 시작주소) + * + * r3 = 0x6028 (이곳에다 DTB의 영역을 매핑할 예정이다.) + * + * r6 = 0x00a11c0e + * DTB의 사이즈는 최대 1MB이다. 1MB의 영역이 겹쳐있을 수 있으므로 + * 2MB영역을 페이지 테이블에 매핑한다. + * + * 참조: int atags_to_fdt(void *atag_list, void *fdt, int total_space) + */ /* * Then map boot params address in r2 if specified. * We map 2 sections in case the ATAGs/DTB crosses a section boundary. @@ -276,6 +620,16 @@ __create_page_tables: #ifdef CONFIG_DEBUG_LL #if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING) + /* IAMROOT-12D (2016-03-05): + * -------------------------- + * r7: 물리주소 0x20201000 + * r3: 가상주소 0xf0201000 + * + * r0 = 0x7c08 (페이지 테이블의 주소) + * r7 = 0xc02 (io의 mmuflag 값) + * + * r3 = 0x20200000 | 0xc02 = 0x20200c02 + */ /* * Map in IO space for serial debugging. * This allows debug messages to be output @@ -300,6 +654,14 @@ __create_page_tables: str r7, [r0], #4 #endif #else + /* IAMROOT-12D (2016-03-05): + * -------------------------- + * XN : Excutable Not + * 시리얼포트영역이라, 실행되어서는 안되기때문에 XN을 세팅한다. + * + * r0: 0x7c08 (페이지 테이블의 주소) + * r3: 0x20200c12 + */ orr r3, r3, #PMD_SECT_XN str r3, [r0], #4 #endif @@ -434,6 +796,10 @@ __enable_mmu: #ifdef CONFIG_CPU_DCACHE_DISABLE bic r0, r0, #CR_C #endif + /* IAMROOT-12D (2016-03-17): + * -------------------------- + * 분기 예측 disable + */ #ifdef CONFIG_CPU_BPREDICT_DISABLE bic r0, r0, #CR_Z #endif @@ -441,11 +807,36 @@ __enable_mmu: bic r0, r0, #CR_I #endif #ifndef CONFIG_ARM_LPAE + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * #define domain_val(dom,type) ((type) << (2*(dom))) + * #define DOMAIN_KERNEL 0 + * #define DOMAIN_TABLE 0 + * #define DOMAIN_USER 1 + * #define DOMAIN_IO 2 + * + * #define DOMAIN_NOACCESS 0 + * #define DOMAIN_CLIENT 1 + * #define DOMAIN_MANAGER 1 + * + * domain_val(1, 1) --> (1 << 2*1) --> 4 + * domain_val(0, 1) --> (1 << 2*0) --> 1 + * domain_val(0, 1) --> 1 + * domain_val(2, 1) --> (1 << 2*2) --> 0x10 + * 4 | 1 | 1 | 0x10 --> 0x15 + * + * mov r5, 0x15 + */ mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT)) mcr p15, 0, r5, c3, c0, 0 @ load domain access register + /* IAMROOT-12D (2016-03-17): + * -------------------------- + * TTBR0 설정 + * TTBR0 = r4(0x4000 - page table pointer) + */ mcr p15, 0, r4, c2, c0, 0 @ load page table pointer #endif b __turn_mmu_on @@ -465,15 +856,27 @@ ENDPROC(__enable_mmu) * * other registers depend on the function called upon completion */ +/* IAMROOT-12D (2016-03-19): +* -------------------------- +* MMU를 enable함. +*/ .align 5 .pushsection .idmap.text, "ax" ENTRY(__turn_mmu_on) mov r0, r0 instr_sync mcr p15, 0, r0, c1, c0, 0 @ write control reg + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * TODO: main id code register를 읽어왔는데 왜 사용하지 않는가? + */ mrc p15, 0, r3, c0, c0, 0 @ read id reg instr_sync mov r3, r3 + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * r13 =__mmap_switched + */ mov r3, r13 ret r3 __turn_mmu_on_end: @@ -481,6 +884,10 @@ ENDPROC(__turn_mmu_on) .popsection +/* IAMROOT-12D (2016-01-30): + * -------------------------- + * #define ARM_CPU_PART_ARM11MPCORE 0x4100b020 + */ #ifdef CONFIG_SMP_ON_UP __HEAD __fixup_smp: @@ -496,11 +903,31 @@ __fixup_smp: teq r3, r4 @ ARM 11MPCore? reteq lr @ yes, assume SMP + /* IAMROOT-12D (2016-01-30): + * -------------------------- + * http://www.iamroot.org/xe/index.php?mid=Kernel_10_ARM&page=2&document_srl=181691 + * 위 주소를 가면, 중간쯤에 MPIDR 관련 그림이 있다. + * + * MPDIR 구조 + * +----------------------------------------------------------------+ + * | 1 | U | ... | + * +----------------------------------------------------------------+ + * 31 30 ... 0 + * + * 30번째의 U가 uniprocessor를 판단할 수 있는 비트이다. + * 0: Multiprocessor + * 1: Uniprocessor + */ mrc p15, 0, r0, c0, c0, 5 @ read MPIDR and r0, r0, #0xc0000000 @ multiprocessing extensions and teq r0, #0x80000000 @ not part of a uniprocessor system? bne __fixup_smp_on_up @ no, assume UP + /* IAMROOT-12D (2016-01-30): + * -------------------------- + * rasberrypi2는 ARM Cortex-A7이다. Architecture는 ARMv7-A이다. + * 우리는 여기서 리턴될 것이다. + */ @ Core indicates it is SMP. Check for Aegis SOC where a single @ Cortex-A9 CPU is present but SMP operations fault. mov r4, #0x41000000 @@ -509,6 +936,17 @@ __fixup_smp: teq r3, r4 @ Check for ARM Cortex-A9 retne lr @ Not ARM Cortex-A9, + /* IAMROOT-12D (2016-02-13): + * -------------------------- + * 2016-02-13부터 행복하게 시작 + * SCU (Snoop Control Unit) 이란? + * L1과 L2와의 일관성을 중재하기 위한 제어장치이다. + * + * 다만, raspberrypi는 ARM Cortex-A7이므로 아래 코드를 타지 않는다. + * + * TODO: what is ACP? + * manage ACP accesses. + */ @ If a future SoC *does* use 0x0 as the PERIPH_BASE, then the @ below address check will need to be #ifdef'd or equivalent @ for the Aegis platform. @@ -521,6 +959,13 @@ ARM_BE8(rev r0, r0) @ byteswap if big endian teq r0, #0x0 @ is 1? retne lr + /* IAMROOT-12D (2016-02-13): + * -------------------------- + * __fixup_smp_on_up은 UP(uni processor - core 1개) 로 설정되어 있을 때 + * 반드시 실행되는 코드이다. + * + * 역할 : SMP용 코드를 UP용 코드로 모두 교체한다. + */ __fixup_smp_on_up: adr r0, 1f ldmia r0, {r3 - r5} diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 6c777e90..c6bc41e6 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -85,9 +85,24 @@ unsigned int processor_id; EXPORT_SYMBOL(processor_id); unsigned int __machine_arch_type __read_mostly; EXPORT_SYMBOL(__machine_arch_type); +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * cacheid = CACHEID_VIPT_NONALIASING | CACHEID_VIPT_I_ALIASING = 0x12 + * + * L1 i-cache의 타입은 CACHEID_VIPT_I_ALIASING + * cacheid에 d-cache + i-cache 플래그들의 특성을 담는다. + * CACHEID_VIPT_NONALIASING(b1) | CACHEID_VIPT_I_ALIASING(b4) + * cacheid = 0x12 + */ unsigned int cacheid __read_mostly; + EXPORT_SYMBOL(cacheid); +/* IAMROOT-12D (2016-06-11): + * -------------------------- + * __atags_pointer 에는 atags 주소가 들어 가지만 dtb가 있을경우 + * dtb 주소가 들어간다. 이값은 0x8000????로 시작된다. + */ unsigned int __atags_pointer __initdata; unsigned int system_rev; @@ -99,6 +114,13 @@ EXPORT_SYMBOL(system_serial_low); unsigned int system_serial_high; EXPORT_SYMBOL(system_serial_high); +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * elf_hwcap = HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | + * HWCAP_EDSP | HWCAP_TLS | HWCAP_IDIVA | HWCAP_LPAE; + * HWCAP_SWP 는 elf_hwcap_fixup() 함수에서 제거됨. + * h/w capability + */ unsigned int elf_hwcap __read_mostly; EXPORT_SYMBOL(elf_hwcap); @@ -107,15 +129,46 @@ EXPORT_SYMBOL(elf_hwcap2); #ifdef MULTI_CPU +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * - proc : process 초기화 관련 함수 목록(arch/arm/mm/proc-macros.S 참고 + * v7_early_abort, v7_pabort, cpu_v7_proc_init, cpu_v7_proc_fin + * , cpu_v7_reset, cpu_v7_do_idle, cpu_v7_dcache_clean_area + * , cpu_v7_switch_mm, cpu_v7_set_pte_ext, cpu_v7_suspend_size등의 함수 + * + */ struct processor processor __read_mostly; #endif #ifdef MULTI_TLB +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * - tlb : tlb table flush 관련 함수 목록 arch/arm/mm/tlb-v7.S 참고 + * v7wbi_flush_kern_tlb_range, v7wbi_tlb_flags_smp, v7wbi_tlb_flags_up + */ struct cpu_tlb_fns cpu_tlb __read_mostly; #endif #ifdef MULTI_USER +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * clear page, or copy page(??) + * struct cpu_user_fns *user = v6_user_fns; + * + * struct cpu_user_fns v6_user_fns __initdata = { + * .cpu_clear_user_highpage = v6_clear_user_highpage_nonaliasing, + * .cpu_copy_user_highpage = v6_copy_user_highpage_nonaliasing, +}; + */ struct cpu_user_fns cpu_user __read_mostly; #endif #ifdef MULTI_CACHE +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * arch/arm/mm/cache-v7.S 참고 + * v7_flush_icache_all, v7_flush_kern_cache_all, v7_flush_kern_cache_louis, + * v7_flush_user_cache_all, v7_flush_user_cache_range, v7_coherent_kern_range, + * v7_coherent_user_range, v7_flush_kern_dcache_area, v7_dma_map_area, + * v7_dma_unmap_area, v7_dma_flush_range + */ struct cpu_cache_fns cpu_cache __read_mostly; #endif #ifdef CONFIG_OUTER_CACHE @@ -128,6 +181,11 @@ EXPORT_SYMBOL(outer_cache); * C code should use the cpu_architecture() function instead of accessing this * variable directly. */ +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * 라즈베리파이2 는 + * __cpu_architecture = CPU_ARCH_ARMv7; // 9 + */ int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN; struct stack { @@ -141,12 +199,40 @@ struct stack { static struct stack stacks[NR_CPUS]; #endif -char elf_platform[ELF_PLATFORM_SIZE]; +char elf_platform[ELF_PLATFORM_SIZE]; /* IAMROOT-12D : "v7l" */ EXPORT_SYMBOL(elf_platform); +/* IAMROOT-12CD (2016-06-18): + * -------------------------- + * cpu_name = "ARMv7 Processor"; + */ static const char *cpu_name; +/* IAMROOT-12D (2016-06-09): + * -------------------------- + * machine_name = "BCM_2709" + */ static const char *machine_name; static char __initdata cmd_line[COMMAND_LINE_SIZE]; +/* IAMROOT-12D (2016-06-09): + * -------------------------- + * arch/arm/mach-bcm2709/bcm2709.c + * + * static const struct machine_desc __mach_desc_BCM_2709 + * _used + * __attribute__((__section__(".arch.info.init"))) = { + * .nr = MACH_TYPE_BCM_2709 + * .name = "BCM_2709", + * .smp = smp_ops(bcm2709_smp_ops), + * .map_io = bcm2709_map_io, + * .init_irq = bcm2709_init_irq, + * .init_time = bcm2709_timer_init, + * .init_machine = bcm2709_init, + * .init_early = bcm2709_init_early, + * .reserve = board_reserve, + * .restart = bcm2709_restart, + * .dt_compat = bcm2709_compat, + * }; + */ const struct machine_desc *machine_desc __initdata; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; @@ -233,10 +319,20 @@ static int __get_cpu_architecture(void) return CPU_ARCH_ARMv7M; } #else +/* IAMROOT-12D (2016-05-24): + * -------------------------- + * 라즈베리파이는 CPU_ARCH_ARMv7를 반환 + * #define CPU_ARCH_ARMv7 9 + */ static int __get_cpu_architecture(void) { int cpu_arch; + /* IAMROOT-12D (2016-05-24): + * -------------------------- + * 라즈베리파이2 + * read_cpuid_id() = MRC p15, 0, r0, c0, c0, 0 ---> 0x410FC075 + */ if ((read_cpuid_id() & 0x0008f000) == 0) { cpu_arch = CPU_ARCH_UNKNOWN; } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { @@ -244,19 +340,34 @@ static int __get_cpu_architecture(void) } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { cpu_arch = (read_cpuid_id() >> 16) & 7; if (cpu_arch) - cpu_arch += CPU_ARCH_ARMv3; + cpu_arch += CPU_ARCH_ARMv3; } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { - /* Revised CPUID format. Read the Memory Model Feature - * Register 0 and check for VMSAv7 or PMSAv7 */ - unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0); - if ((mmfr0 & 0x0000000f) >= 0x00000003 || + /* Revised CPUID format. Read the Memory Model Feature + * Register 0 and check for VMSAv7 or PMSAv7 */ + /* IAMROOT-12D (2016-05-21): + * -------------------------- + * 우리 라즈베리파이에 해당하는 cpu_architecture이다. + * : CPU_ARCH_ARMv7 + * + * #define CPUID_EXT_MMFR0 "c1, 4" + * MMFR0 : Memory Model Feature Register 0 + * MRC p15, 0, r0, c0, c1, 4 --> 0x10101105 + */ + unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0); + /* IAMROOT-12D (2016-05-24): + * -------------------------- + * (mmfr0 & 0x0000000f) >= 0x00000003 : VMSA support 지원 여부 체크 + * (mmfr0 & 0x000000f0) >= 0x00000030 : Outermost shareability 지원범위 + * Outermost (L2캐쉬 공유 여부) + */ + if ((mmfr0 & 0x0000000f) >= 0x00000003 || (mmfr0 & 0x000000f0) >= 0x00000030) - cpu_arch = CPU_ARCH_ARMv7; - else if ((mmfr0 & 0x0000000f) == 0x00000002 || - (mmfr0 & 0x000000f0) == 0x00000020) - cpu_arch = CPU_ARCH_ARMv6; - else - cpu_arch = CPU_ARCH_UNKNOWN; + cpu_arch = CPU_ARCH_ARMv7; + else if ((mmfr0 & 0x0000000f) == 0x00000002 || + (mmfr0 & 0x000000f0) == 0x00000020) + cpu_arch = CPU_ARCH_ARMv6; + else + cpu_arch = CPU_ARCH_UNKNOWN; } else cpu_arch = CPU_ARCH_UNKNOWN; @@ -271,6 +382,15 @@ int __pure cpu_architecture(void) return __cpu_architecture; } +/* IAMROOT-12D (2016-05-28): + * -------------------------- + * 라즈베리 파이2는 true를 반환함. + */ +/* IAMROOT-12A: + * ------------ + * aliasing이 필요한 경우는 캐시 단면의 사이즈가 + * 한 개의 페이지 사이즈(4K)를 초과하는 경우 aliasing이 필요 + */ static int cpu_has_aliasing_icache(unsigned int arch) { int aliasing_icache; @@ -283,14 +403,38 @@ static int cpu_has_aliasing_icache(unsigned int arch) /* arch specifies the register format */ switch (arch) { case CPU_ARCH_ARMv7: + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * CSSELR : Write Cache Size Selection Register + * MCR p15, 2, r0, c0, c0, 0; + * + * r0 = 1 : Select Instruction cache. + */ asm("mcr p15, 2, %0, c0, c0, 0 @ set CSSELR" : /* No output operands */ : "r" (1)); isb(); + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * CCSIDR : Cache Size ID Register + * Provides information about the architecture of the caches. + * 라즈베리파이2 + * CCSIDR = LineSize = 0b001 + * L1 Cache : I-32K(TCM, VIPT) 2way, 32B cache line + * D-32K(PIPT, 4way, 64B cache line + * line_size = 32 + * num_sets = 0x200 + * aliasing_icache = (32 * 512) > 4096 (true) + */ asm("mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" : "=r" (id_reg)); line_size = 4 << ((id_reg & 0x7) + 2); num_sets = ((id_reg >> 13) & 0x7fff) + 1; + /* IAMROOT-12A: + * ------------ + * aliasing이 필요한 경우는 캐시 단면의 사이즈가 + * 한 개의 페이지 사이즈(4K)를 초과하는 경우 aliasing이 필요 + */ aliasing_icache = (line_size * num_sets) > PAGE_SIZE; break; case CPU_ARCH_ARMv6: @@ -304,13 +448,41 @@ static int cpu_has_aliasing_icache(unsigned int arch) return aliasing_icache; } +/* IAMROOT-12A: + * ------------ + * 전역 변수 cacheid에 L1 cache 타입 설정 + */ static void __init cacheid_init(void) { + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * CPU_ARCH_ARMv7; // 9 + */ unsigned int arch = cpu_architecture(); if (arch == CPU_ARCH_ARMv7M) { cacheid = 0; } else if (arch >= CPU_ARCH_ARMv6) { + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * cachetype = 0x84448003 + * [31:29] Format : Indicates the CTR format: + * 0x4 ARMv7 format. + * + * [15:14] L1Ip : L1 instruction cache policy. Indicates the + * indexing and tagging policy for the L1 + * instruction cache: + * 0b10 Virtually Indexed Physically Tagged (VIPT). + */ + /* IAMROOT-12A: + * ------------ + * cachetype = CTR(Cache Type Register) + * CTR.Format을 읽어 0x4 인경우 ARMv7이다. + * - L1 d-cache를 CACHEID_VIPT_NONALIASING로 설정한다. + * (참고로 ARMv7의 실제 L1 d-cache 타입은 PIPT) + * CTR.L1IP(L1 instruction cache policy) + * 값이 2인 경우는 i-cache 관련하여 VIPT + */ unsigned int cachetype = read_cpuid_cachetype(); if ((cachetype & (7 << 29)) == 4 << 29) { /* ARMv7 register format */ @@ -337,6 +509,10 @@ static void __init cacheid_init(void) cacheid = CACHEID_VIVT; } + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache + */ pr_info("CPU: %s data cache, %s instruction cache\n", cache_is_vivt() ? "VIVT" : cache_is_vipt_aliasing() ? "VIPT aliasing" : @@ -369,7 +545,13 @@ void __init early_print(const char *str, ...) #endif printk("%s", buf); } - +/* IAMROOT-12D (2016-05-21): + * -------------------------- + * TODO : isar5는 무엇인가? + * v8 Crypto 명령어 셋 정보이며 라즈베리파이는 지원하지 않음. + * + * 반환 : elf_hwcap |= (HWCAP_IDIVA | HWCAP_LPAE) + */ static void __init cpuid_init_hwcaps(void) { int block; @@ -378,18 +560,37 @@ static void __init cpuid_init_hwcaps(void) if (cpu_architecture() < CPU_ARCH_ARMv7) return; + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * Read Instruction Set Attribute Register 0 + * MRC p15, 0, r0, c0, c2, 0 --> 0x02101110 + * 24~27번 비트는 나누기 명령어 셋 지원 여부를 가르키며 라즈베리파이2는 + * 0x2 이며 SDIV and UDIV Thumb, ARM 명령어 셋을 지원한다. + */ block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24); if (block >= 2) - elf_hwcap |= HWCAP_IDIVA; + elf_hwcap |= HWCAP_IDIVA; /* IAMROOT-12D : 라즈베리 파이2 */ if (block >= 1) elf_hwcap |= HWCAP_IDIVT; /* LPAE implies atomic ldrd/strd instructions */ + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * Read Memory Model Feature Register 0 + * MRC p15, 0, r0, c0, c1, 4 --> 0x10101105 + * 0~3비트는 VMSA(Virtual Memory System Architecture)지원 여부를 나타낸 + * 다. + */ block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0); if (block >= 5) - elf_hwcap |= HWCAP_LPAE; + elf_hwcap |= HWCAP_LPAE; /* IAMROOT-12D : 라즈베리 파이2 */ /* check for supported v8 Crypto instructions */ + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * ISAR5 Instruction Set Attribute Register 5 + * MRC p15, 0, r0, c0, c2, 5 --> 0x00000000 + */ isar5 = read_cpuid_ext(CPUID_EXT_ISAR5); block = cpuid_feature_extract_field(isar5, 4); @@ -411,14 +612,30 @@ static void __init cpuid_init_hwcaps(void) elf_hwcap2 |= HWCAP2_CRC32; } +/* IAMROOT-12D (2016-05-28): + * -------------------------- + * 라즈베리파이2는 HWCAP_SWP 명령어를 제외한다. + * (ldrex, strex 명령어-atomic 메모리 접근 ARM 명령어-가 있기때문에) + */ static void __init elf_hwcap_fixup(void) { - unsigned id = read_cpuid_id(); + unsigned id = read_cpuid_id(); /* IAMROOT-12D : 0x410FC075 */ /* * HWCAP_TLS is available only on 1136 r1p0 and later, * see also kuser_get_tls_init. */ + /* IAMROOT-12A: + * ------------ + * CPU 아키텍처가 ARM1136 r1p0 이상에서는 TLS 기능이 있다. + * 아래의 루틴같이 ARM1136 r1p0에서 MIDR.variant = 0인 경우 + * TLS 기능이 없다고 판단하면 뒤 루틴을 생략하고 빠져나간다. + */ + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * read_cpuid_part() = 0x410FC075 & 0xff00fff0 + * #define ARM_CPU_PART_ARM1136 0x4100b360 + */ if (read_cpuid_part() == ARM_CPU_PART_ARM1136 && ((id >> 20) & 3) == 0) { elf_hwcap &= ~HWCAP_TLS; @@ -426,6 +643,10 @@ static void __init elf_hwcap_fixup(void) } /* Verify if CPUID scheme is implemented */ + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * 0x410FC075 & 0x000f0000 + */ if ((id & 0x000f0000) != 0x000f0000) return; @@ -434,6 +655,17 @@ static void __init elf_hwcap_fixup(void) * avoid advertising SWP; it may not be atomic with * multiprocessing cores. */ + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * ISAR3 : Instruction Set Attribute Register 3 + * 프로세서가 기본적으로 제공하는 명령어 셋 정보를 제공한다. + * + * MRC p15, 0, r0, c0, c2, 3 --> 0x11112131 + * [15:12] SynchPrim_instrs 동기화 명령어 셋 지원 여부(라즈베리파이2는 + * 0x02로 ldrex, strex, clrex, ldrexb, ldrexh, strexb, strexh, + * ldrexd, strexd 명령어를 지원 함) + * [23:20] ThumbCopy_instrs thumb move 명령어 지원 여부. + */ if (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) > 1 || (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) == 1 && cpuid_feature_extract(CPUID_EXT_ISAR3, 20) >= 3)) @@ -462,6 +694,20 @@ void notrace cpu_init(void) */ set_my_cpu_offset(per_cpu_offset(cpu)); + /* IAMROOT-12A: + * ------------ + * 특정 CPU 아키텍처에서 필요한 코드를 실행한다. + * v7 아케텍처에서는 아무것도 하지 않고 그냥 return 한다. + * + * 라즈베리파이2: + * MULTI_CPU가 동작 중이어서 processor._proc_init()를 호출하는데 + * 이 변수에는 cpu_v7_proc_init의 주소가 담김 (../mm/proc-v7.S) + */ + /* IAMROOT-12D (2016-05-26): + * -------------------------- + * cpu_proc_init 함수는 cpu_v7_proc_init를 호출하며 + * cpu_v7_proc_init 함수는 그냥 아무것도 하지 않고 리턴함 + */ cpu_proc_init(); /* @@ -471,12 +717,21 @@ void notrace cpu_init(void) #ifdef CONFIG_THUMB2_KERNEL #define PLC "r" #else -#define PLC "I" +#define PLC "I" /* IAMROOT-12D : 라즈베리파2 */ #endif /* * setup stacks for re-entrant exception handlers */ + /* IAMROOT-12D (2016-05-26): + * -------------------------- + * 1. IRQ_MODE 스택설정 + * 인터럽트 disable + IRQ_MODE 진입후 sp를 stack[0].irq[0]주소로 설정 + * 2. ABT_MODE 스택설정 + * 인터럽트 disable + ABT_MODE 진입후 sp를 stack.abt[0]주소로 설정 + * 3. UND_MODE, FIQ_MODE 각각 sp 설정 + * 4. SVC_MODE로 복귀. + */ __asm__ ( "msr cpsr_c, %1\n\t" "add r14, %0, %2\n\t" @@ -508,6 +763,15 @@ void notrace cpu_init(void) u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID }; +/* IAMROOT-12D (2016-03-26): + * -------------------------- + * is_smp() = 1 + * read_cpuid_mpidr() = 0x80000F00 + * MPIDR_HWID_BITMASK = 0x00FFFFFF + * read_cpuid_mpidr() & MPIDR_HWID_BITMASK = 0x00000F00 + * + * cpu = 0x0 + */ void __init smp_setup_processor_id(void) { int i; @@ -525,6 +789,11 @@ void __init smp_setup_processor_id(void) */ set_my_cpu_offset(0); + /* IAMROOT-12D (2016-04-12): + * -------------------------- + * 라즈베리파이 실제 로그(dmesg) + * [ 0.000000] Booting Linux on physical CPU 0xf00 + */ pr_info("Booting Linux on physical CPU 0x%x\n", mpidr); } @@ -594,6 +863,31 @@ static void __init smp_build_mpidr_hash(void) } #endif +/* IAMROOT-12D (2016-05-21): + * -------------------------- + * Start_kernel 이전 시점에 우리는 proc_info_list정보를 모두 담아왔다. + * 이미 담겨져 있는 정보를 우리는 lookup_processor_type()을 통해 가져온다. + * -------------------------- + * 참고 사항 : arch/arm/mm/proc-v7.S + * struct proc_info_list { + * unsigned int cpu_val = 0x000f0000; + * unsigned int cpu_mask = 0x000f0000; + * unsigned long __cpu_mm_mmu_flags = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | + * PMD_SECT_AP_READ | PMD_SECT_AF | PMD_FLAGS_SMP; + * unsigned long __cpu_io_mmu_flags = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | + * PMD_SECT_AP_READ | PMD_SECT_AF; + * unsigned long __cpu_flush = __v7_setup; // arch/arm/mm/proc-v7.S + * const char *arch_name = "armv7"; + * const char *elf_name = "v7"; + * unsigned int elf_hwcap = HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | + * HWCAP_FAST_MULT | HWCAP_EDSP | HWCAP_TLS; + * const char *cpu_name = "ARMv7 Processor"; + * struct processor *proc = v7_processor_functions; + * struct cpu_tlb_fns *tlb = v7wbi_tlb_fns; + * struct cpu_user_fns *user = v6_user_fns; + * struct cpu_cache_fns *cache = v7_cache_fns; + * }; + */ static void __init setup_processor(void) { struct proc_info_list *list; @@ -610,30 +904,77 @@ static void __init setup_processor(void) while (1); } + /* IAMROOT-12D (2016-05-24): + * -------------------------- + * cpu_name = "ARMv7 Processor"; + * __cpu_architecture = CPU_ARCH_ARMv7 + */ cpu_name = list->cpu_name; __cpu_architecture = __get_cpu_architecture(); + /* IAMROOT-12D (2016-05-21): + * -------------------------- + * - proc: process 초기화 관련 함수 목록(arch/arm/mm/proc-macros.S 참고) + * v7_early_abort, v7_pabort, cpu_v7_proc_init, cpu_v7_proc_fin + * , cpu_v7_reset, cpu_v7_do_idle, cpu_v7_dcache_clean_area + * , cpu_v7_switch_mm, cpu_v7_set_pte_ext, cpu_v7_suspend_size등의 함수 + * - tlb: tlb table flush 관련 함수 목록 arch/arm/mm/tlb-v7.S 참고 + * v7wbi_flush_kern_tlb_range, v7wbi_tlb_flags_smp, v7wbi_tlb_flags_up + * - user: 사용자 메모리 할당과 해제(?) + * - cache: cache 정책 함수들. + * - hwcap: + */ #ifdef MULTI_CPU + /* IAMROOT-12D (2016-05-24): + * -------------------------- + * struct processor *proc = v7_processor_functions; + */ processor = *list->proc; #endif #ifdef MULTI_TLB + /* IAMROOT-12D (2016-05-24): + * -------------------------- + * struct cpu_tlb_fns *tlb = v7wbi_tlb_fns; + */ cpu_tlb = *list->tlb; #endif #ifdef MULTI_USER + /* IAMROOT-12D (2016-05-24): + * -------------------------- + * struct cpu_user_fns *user = v6_user_fns; + */ cpu_user = *list->user; #endif #ifdef MULTI_CACHE + /* IAMROOT-12D (2016-05-24): + * -------------------------- + * struct cpu_cache_fns *cache = v7_cache_fns; + */ cpu_cache = *list->cache; #endif - + /* IAMROOT-12D (2016-05-21): + * -------------------------- + * CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c5387d + */ pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", cpu_name, read_cpuid_id(), read_cpuid_id() & 15, proc_arch[cpu_architecture()], get_cr()); + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * machine = "armv7l" + * elf_platform = "v7l" + */ snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c", - list->arch_name, ENDIANNESS); + list->arch_name, ENDIANNESS); snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c", - list->elf_name, ENDIANNESS); + list->elf_name, ENDIANNESS); + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * list->elf_hwcap = HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | + * HWCAP_FAST_MULT | HWCAP_EDSP | HWCAP_TLS; + * h/w capability + */ elf_hwcap = list->elf_hwcap; cpuid_init_hwcaps(); @@ -910,18 +1251,42 @@ void __init hyp_mode_check(void) #endif } +/* IAMROOT-12D (2016-05-21): + * -------------------------- + * setup_processor()까지 함. + */ void __init setup_arch(char **cmdline_p) { const struct machine_desc *mdesc; setup_processor(); + /* IAMROOT-12A: + * ------------ + * 처음에 DT_START_MACHINE에서 등록한 머신 디스크립터 테이블에서 이름으로 + * 검색해보고 없으면 START_MACHINE에서 등록한 머신 디스크립터 테이블에서 + * 머신 번호로 검색한다. + * + * setup_machine_fdt() + * - dtb로부터 boot_cmd_line과 memblock에 메모리 노드의 reg 영역을 추가. + */ mdesc = setup_machine_fdt(__atags_pointer); if (!mdesc) mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type); machine_desc = mdesc; + + /* IAMROOT-12D (2016-06-09): + * -------------------------- + * machine_name = "BCM_2709" + */ machine_name = mdesc->name; dump_stack_set_arch_desc("%s", mdesc->name); + /* IAMROOT-12D (2016-06-09): + * -------------------------- + * default : REBOOT_COLD = 0, + * reboot_mode 초기값은 REBOOT_HARD reboot.c 참고 + * reboot_mode = REBOOT_COLD; + */ if (mdesc->reboot_mode != REBOOT_HARD) reboot_mode = mdesc->reboot_mode; @@ -934,6 +1299,19 @@ void __init setup_arch(char **cmdline_p) strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = cmd_line; + /* IAMROOT-12AB: + * ------------- + * cmdline에서 입력된 모든 파라메터에 대응하는 early 함수를 찾아 호출한다. + * 일반 파라메터 함수 등록 매크로: __setup() -> __setup_param(,,0) + * early 파라메터 함수 등록 매크로: early_param() -> __setup_param(,,1) + * earlycon 파라메터 함수 등록 매크로: EARLYCON_DECLARE() -> __early_param() -> .. + */ + /* IAMROOT-12CD (2016-07-23): + * -------------------------- + * rpi2: + * - setup_of_earlycon() : 여기까지 호출되나 결국 아무것도 하지 않고 + * 넘어간다. + */ parse_early_param(); early_paging_init(mdesc, lookup_processor_type(read_cpuid_id())); diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h index 7d807cfd..01dbcd6f 100644 --- a/arch/arm/lib/bitops.h +++ b/arch/arm/lib/bitops.h @@ -3,6 +3,15 @@ #if __LINUX_ARM_ARCH__ >= 6 .macro bitop, name, instr +/* IAMROOT-12D (2016-05-14): + * -------------------------- + * r0 : 몇번째 비트를 세팅 할 것인지 + * r1 : 비트맵 시작 주소 + * 예) _set_bit(0,bits[1]) 인 경우 + * bits[0] 의 0번째 비트를 세팅한다. (bit offset = 0, word offset = 0) + * _set_bit(33,bits[2]) 인 경우 + * bits[1] 의 2번째 비트를 세팅한다. (bit offset = 2, word offset = 1) + */ ENTRY( \name ) UNWIND( .fnstart ) ands ip, r1, #3 diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c index e1934dc7..e7a302bf 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -1170,6 +1170,10 @@ void __init bcm2709_init_early(void) static void __init board_reserve(void) { +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * CMA: Contiguous Memory Allocation 연속 메모리 할당 + */ #if defined(CONFIG_BCM_VC_CMA) vc_cma_reserve(); #endif @@ -1287,6 +1291,24 @@ static const char * const bcm2709_compat[] = { NULL }; +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * static const struct machine_desc __mach_desc_BCM_2709 + * _used + * __attribute__((__section__(".arch.info.init"))) = { + * .nr = MACH_TYPE_BCM_2709 + * .name = "BCM_2709", + * .smp = smp_ops(bcm2709_smp_ops), + * .map_io = bcm2709_map_io, + * .init_irq = bcm2709_init_irq, + * .init_time = bcm2709_timer_init, + * .init_machine = bcm2709_init, + * .init_early = bcm2709_init_early, + * .reserve = board_reserve, + * .restart = bcm2709_restart, + * .dt_compat = bcm2709_compat, + * }; + */ MACHINE_START(BCM2709, "BCM2709") /* Maintainer: Broadcom Europe Ltd. */ #ifdef CONFIG_SMP diff --git a/arch/arm/mach-bcm2709/include/mach/uncompress.h b/arch/arm/mach-bcm2709/include/mach/uncompress.h index d6348138..9eb65bca 100644 --- a/arch/arm/mach-bcm2709/include/mach/uncompress.h +++ b/arch/arm/mach-bcm2709/include/mach/uncompress.h @@ -53,6 +53,10 @@ static inline void flush(void) } while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE); } +/* IAMROOT-12D (2016-01-23): + * -------------------------- + * 시리얼 통신을 위한 초기화 + */ static inline void arch_decomp_setup(void) { int temp, div, rem, frac; diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h index 23e7a313..e168e3db 100644 --- a/arch/arm/mach-realview/include/mach/memory.h +++ b/arch/arm/mach-realview/include/mach/memory.h @@ -20,7 +20,7 @@ #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H -#ifdef CONFIG_SPARSEMEM +#ifdef CONFIG_SPARSEMEM /* IAMROOT-12D: 라즈베리파이2는 NOT SET */ /* * Sparsemem definitions for RealView PBX. diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index a134d8a1..186c8527 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -86,6 +86,13 @@ ENDPROC(v7_flush_icache_all) * * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) */ +/* IAMROOT-12D (2016-03-12): + * -------------------------- + * Cache hierarchy에 존재하는 모든 Cache들 차례대로(L1,L2...) + * Clean & Flush 를 하는 함수이다. + * + * louis : Level of Unification Inner Shareable + */ ENTRY(v7_flush_dcache_louis) dmb @ ensure ordering with previous memory accesses @@ -444,5 +451,21 @@ ENDPROC(v7_dma_unmap_area) __INITDATA + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * .type v7_cache_fns, #object + * ENTRY(v7_cache_fns) + * .long v7_flush_icache_all + * .long v7_flush_kern_cache_all + * .long v7_flush_kern_cache_louis + * .long v7_flush_user_cache_all + * .long v7_flush_user_cache_range + * .long v7_coherent_kern_range + * .long v7_coherent_user_range + * .long v7_flush_kern_dcache_area + * .long v7_dma_map_area + * .long v7_dma_unmap_area + * .long v7_dma_flush_range + */ @ define struct cpu_cache_fns (see and proc-macros.S) define_cache_functions v7 diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 6e4b9ff2..b6e63142 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -396,10 +396,29 @@ struct dma_contig_early_reserve { unsigned long size; }; +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * dma_mmu_remap = { + * [0] = {base = 0x3b800000(952M), size = 0x800000(8M)}, cma 영역. + * cma 영역 0~8M(원래 5M지만 4M alignment 처리하여 8M가 됨) + * [1] = {base = 0, size = 0}, + * ... + * } + */ static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS] __initdata; +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * dma_mmu_remap_num = 1 + */ static int dma_mmu_remap_num __initdata; +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * dma_contiguous_reserve_area() 가 호출 + * base= 0x3b8000000 (952M) + * size= 0x8000000 (8M) + */ void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { dma_mmu_remap[dma_mmu_remap_num].base = base; diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index be92fa0f..0245851c 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -121,6 +121,10 @@ static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, } #endif +/* IAMROOT-12CD (2016-07-23): + * -------------------------- + * pi2에서는 CONFIG_ZONE_DMA 가 없으므로 넘어감. + */ void __init setup_dma_zone(const struct machine_desc *mdesc) { #ifdef CONFIG_ZONE_DMA @@ -211,6 +215,10 @@ static void __init arm_memory_present(void) } #endif +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * arm_memblock_steal_permitted = false (arm_memblock_init() 함수에서 설정) + */ static bool arm_memblock_steal_permitted = true; phys_addr_t __init arm_memblock_steal(phys_addr_t size, phys_addr_t align) @@ -232,10 +240,23 @@ void __init arm_memblock_init(const struct machine_desc *mdesc) #ifdef CONFIG_XIP_KERNEL memblock_reserve(__pa(_sdata), _end - _sdata); #else + /* IAMROOT-12CD (2016-08-16): + * -------------------------- + * memblock_reserve(0x8240, 9737564) + */ memblock_reserve(__pa(_stext), _end - _stext); #endif #ifdef CONFIG_BLK_DEV_INITRD + /* IAMROOT-12CD (2016-08-16): + * -------------------------- + * initrd_start = 0 + * phys_initrd_size = 0 + */ /* FDT scan will populate initrd_start */ + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * initrd_start: 0, phys_initrd_size:0 + */ if (initrd_start && !phys_initrd_size) { phys_initrd_start = __virt_to_phys(initrd_start); phys_initrd_size = initrd_end - initrd_start; @@ -266,6 +287,11 @@ void __init arm_memblock_init(const struct machine_desc *mdesc) /* reserve any platform specific memblock areas */ if (mdesc->reserve) + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * arch/arm/mach-bcm2709/bcm2709.c + * board_reserve() 호출 + */ mdesc->reserve(); early_init_fdt_scan_reserved_mem(); diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index d1e5ad7a..ac06a4b2 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -40,6 +40,14 @@ #include "mm.h" +/* IAMROOT-12CD (2016-07-09): + * -------------------------- + * struct list_head static_vmlist = LIST_HEAD_INIT(static_vmlist); + * struct static_vm { + * struct vm_struct vm; + * struct list_head list; + * }; + */ LIST_HEAD(static_vmlist); static struct static_vm *find_static_vm_paddr(phys_addr_t paddr, @@ -284,6 +292,10 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, /* * Try to reuse one of the static mapping whenever possible. */ + /* IAMROOT-12CD (2016-07-09): + * -------------------------- + * size 는 0이상, 그리고 32bit이면서 32bit이하 주소영역일때 + */ if (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) { struct static_vm *svm; diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index ce727d47..b74d2017 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -33,6 +33,24 @@ static inline pte_t get_top_pte(unsigned long va) return *ptep; } +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 아래 2단계 페이지 테이블 구조에서 PMD + 페이지 테이블 시작주소(0x80004000) + * 값을 반환한다. + * + * 2단계 페이지 테이블 구조 + * 31 21 20 12 11 0 + * +------------+---------+-----------+ + * | PGD = PMD | PTE | offset | + * +------------+---------+-----------+ + * + * + * virt pgd_offset_k pud_offset pmd_offset + * 0 0x80004000 + 0 0x80004000 + 0 0x80004000 + 0 + * 0x200000 0x80004000 + 8 0x80004000 + 8 0x80004000 + 8 + * 0x400000 0x80004000 + 16 0x80004000 + 16 0x80004000 + 16 + * 0x600000 0x80004000 + 24 0x80004000 + 24 0x80004000 + 24(8*3) + */ static inline pmd_t *pmd_off_k(unsigned long virt) { return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt); @@ -86,6 +104,10 @@ extern __init void add_static_vm_early(struct static_vm *svm); extern phys_addr_t arm_dma_limit; extern unsigned long arm_dma_pfn_limit; #else +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * 라즈베리파이2는 DMA zone이 없으므로 아래가 맞다. + */ #define arm_dma_limit ((phys_addr_t)~0) #define arm_dma_pfn_limit (~0ul >> PAGE_SHIFT) #endif diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 71863826..593030f9 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -61,6 +61,10 @@ pmdval_t user_pmd_table = _PAGE_USER_TABLE; #define CPOLICY_WRITEBACK 3 #define CPOLICY_WRITEALLOC 4 +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * 라즈베리 파이2는 cachepolicy = 4; // CPOLICY_WRITEALLOC + */ static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK; static unsigned int ecc_mask __initdata = 0; pgprot_t pgprot_user; @@ -121,6 +125,11 @@ static struct cachepolicy cache_policies[] __initdata = { }; #ifdef CONFIG_CPU_CP15 +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * initial_pmd_value = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | + * PMD_SECT_AF | PMD_SECT_WBWA|PMD_SECT_S; + */ static unsigned long initial_pmd_value __initdata = 0; /* @@ -130,6 +139,11 @@ static unsigned long initial_pmd_value __initdata = 0; * assembly code, which avoids an illegal state where the TLBs can get * confused. See comments in early_cachepolicy() for more information. */ +/* IAMROOT-12D (2016-05-25): + * -------------------------- + * cmd = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_SECT_AF | + * | PMD_SECT_WBWA|PMD_SECT_S; + */ void __init init_default_cache_policy(unsigned long pmd) { int i; @@ -140,7 +154,7 @@ void __init init_default_cache_policy(unsigned long pmd) for (i = 0; i < ARRAY_SIZE(cache_policies); i++) if (cache_policies[i].pmd == pmd) { - cachepolicy = i; + cachepolicy = i; /* IAMROOT-12D : 4 */ break; } @@ -153,6 +167,11 @@ void __init init_default_cache_policy(unsigned long pmd) * the cache or the cache and writebuffer to be turned off. (Note: the * write buffer should not be on and the cache off). */ +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 다음은 해제 될 캐시 또는 캐시와 writebuffer을 허용하여 캐시 일관성 문제를 + * 식별하는 데 유용합니다(쓰기 버퍼는 켜지않거나 cache off를 하지 않는것이 좋다) + */ static int __init early_cachepolicy(char *p) { int i, selected = -1; @@ -238,51 +257,176 @@ __setup("noalign", noalign_setup); #endif /* ifdef CONFIG_CPU_CP15 / else */ +/* IAMROOT-12CD (2016-09-03): + * -------------------------- + * IO 디바이스 메모리 매핑 영역은 실행불가, 쓰기 가능(DIRTY - DEVICE에서 + * writable 로사용), 항상 메모리상주(L_PTE_PRESENT) 되어 있어야함. + * TODO: L_PTE_YOUNG + */ #define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN #define PROT_PTE_S2_DEVICE PROT_PTE_DEVICE #define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_AP_WRITE +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * mem_types[MT_DEVICE].prot_sect |= PMD_SECT_XN; + * mem_types[MT_DEVICE_NONSHARED].prot_sect |= PMD_SECT_XN; + * mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_XN; + * mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_XN; + * mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_XN; + * + * mem_types[MT_DEVICE].prot_sect |= PMD_SECT_TEX(1); + * mem_types[MT_DEVICE_NONSHARED].prot_sect |= PMD_SECT_TEX(1); + * mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_BUFFERABLE; + * + * Privileged 모드에서 읽기만 허용, User 모드에서는 접근 불가. + * ARM Architecture Reference Manual B4-9 참고. + * mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; + * mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; + * mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; + * + * 공유 설정 + * mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S; + * mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED; + * mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S; + * mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED; + * mem_types[MT_MEMORY_RWX].prot_sect |= PMD_SECT_S; + * mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_SHARED; + * mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_S; + * mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_SHARED; + * mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED; + * mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_S; + * mem_types[MT_MEMORY_RWX_NONCACHED].prot_pte |= L_PTE_SHARED; + * + * Non-cacheable Normal is XCB = 001 + * mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_BUFFERED; + * + * mem_types[MT_LOW_VECTORS].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * mem_types[MT_HIGH_VECTORS].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * + * mem_types[MT_MEMORY_RWX].prot_sect |= PMD_SECT_WBWA + * mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_WBWA + * mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * mem_types[MT_ROM].prot_sect |= PMD_SECT_WBWA + * + * mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB; + */ static struct mem_type mem_types[] = { [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED, + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_pte_s2 = L_PTE_SHARED = 0x400 + */ .prot_pte_s2 = s2_policy(PROT_PTE_S2_DEVICE) | s2_policy(L_PTE_S2_MT_DEV_SHARED) | L_PTE_SHARED, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * .prot_sect |= PMD_SECT_XN + * .prot_sect |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_S, .domain = DOMAIN_IO, }, [MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_NONSHARED, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect |= (PMD_SECT_XN | PMD_SECT_TEX(1)) + * .prot_sect |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_sect = PROT_SECT_DEVICE, .domain = DOMAIN_IO, }, [MT_DEVICE_CACHED] = { /* ioremap_cached */ + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED | + * L_PTE_SHARED(0x400) = 0x66f + */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect |= (PMD_SECT_XN | PMD_SECT_S(0x10000)) = 0x1041e + * .prot_sect |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB, .domain = DOMAIN_IO, }, [MT_DEVICE_WC] = { /* ioremap_wc */ + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC | + * L_PTE_SHARED(0x400) = 0x667 + * + */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect = PROT_SECT_DEVICE | PMD_SECT_XN | + * PMD_SECT_BUFFERABLE | PMD_SECT_S = 0x10416 + * .prot_sect |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_sect = PROT_SECT_DEVICE, .domain = DOMAIN_IO, }, [MT_UNCACHED] = { .prot_pte = PROT_PTE_DEVICE, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_sect |= PMD_DOMAIN(DOMAIN_IO) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_IO, }, [MT_CACHECLEAN] = { + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_APX| + * PMD_SECT_AP_WRITE = 0x2 | 0x10 | 0x8000 | 0x400 = 0x8412 + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_KERNEL, }, #ifndef CONFIG_ARM_LPAE [MT_MINICLEAN] = { + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect = PMD_TYPE_SECT | PMD_TYPE_SECT | PMD_SECT_XN | + * PMD_SECT_MINICACHE | PMD_SECT_APX|PMD_SECT_AP_WRITE + * = 0x02 | 0x10 | 0x1008 | 0x8000 | 0x400 = 0x941a + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE, .domain = DOMAIN_KERNEL, }, @@ -290,62 +434,145 @@ static struct mem_type mem_types[] = { [MT_LOW_VECTORS] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_RDONLY, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_USER) + */ .prot_l1 = PMD_TYPE_TABLE, .domain = DOMAIN_USER, }, [MT_HIGH_VECTORS] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_USER | L_PTE_RDONLY, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_USER) + */ .prot_l1 = PMD_TYPE_TABLE, .domain = DOMAIN_USER, }, [MT_MEMORY_RWX] = { + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + * L_PTE_SHARED + */ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_S + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, }, [MT_MEMORY_RW] = { + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + * L_PTE_XN | L_PTE_SHARED + */ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect |= (PMD_SECT_XN | PMD_SECT_S) + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, }, [MT_ROM] = { + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect = PMD_TYPE_SECT | PMD_SECT_APX|PMD_SECT_AP_WRITE + * = 0x02 | 0x8000 | 0x400 = 0x8402 + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT, .domain = DOMAIN_KERNEL, }, [MT_MEMORY_RWX_NONCACHED] = { + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_pte |= L_PTE_SHARED + */ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_MT_BUFFERABLE, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_sect |= (PMD_SECT_S | PMD_SECT_BUFFERED) + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, }, [MT_MEMORY_RW_DTCM] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_KERNEL, }, [MT_MEMORY_RWX_ITCM] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_l1 = PMD_TYPE_TABLE, .domain = DOMAIN_KERNEL, }, [MT_MEMORY_RW_SO] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_MT_UNCACHED | L_PTE_XN, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_l1 = PMD_TYPE_TABLE, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_sect |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_S | PMD_SECT_UNCACHED | PMD_SECT_XN, .domain = DOMAIN_KERNEL, }, [MT_MEMORY_DMA_READY] = { + /* IAMROOT-12CD (2016-08-23): + * -------------------------- + * .prot_pte |= L_PTE_SHARED + */ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN, + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * .prot_l1 |= PMD_DOMAIN(DOMAIN_KERNEL) + */ .prot_l1 = PMD_TYPE_TABLE, .domain = DOMAIN_KERNEL, }, @@ -386,9 +613,17 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot) static void __init build_mem_type_table(void) { struct cachepolicy *cp; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * 라즈베리파이2 기본값 : 0x10c5387d + */ unsigned int cr = get_cr(); pteval_t user_pgprot, kern_pgprot, vecs_pgprot; pteval_t hyp_device_pgprot, s2_pgprot, s2_device_pgprot; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * cpu_arch = CPU_ARCH_ARMv7; // 9 + */ int cpu_arch = cpu_architecture(); int i; @@ -458,6 +693,11 @@ static void __init build_mem_type_table(void) * Mark device regions on ARMv6+ as execute-never * to prevent speculative instruction fetches. */ + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * 위험한 명령어 fetches를 방지하기 위해 실행 방지로 + * ARMv6+에 표시 디바이스 영역 표시한다. + */ mem_types[MT_DEVICE].prot_sect |= PMD_SECT_XN; mem_types[MT_DEVICE_NONSHARED].prot_sect |= PMD_SECT_XN; mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_XN; @@ -474,6 +714,10 @@ static void __init build_mem_type_table(void) * - write combine device mem is SXCB=0001 * (Uncached Normal memory) */ + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/Babifihd.html + */ mem_types[MT_DEVICE].prot_sect |= PMD_SECT_TEX(1); mem_types[MT_DEVICE_NONSHARED].prot_sect |= PMD_SECT_TEX(1); mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_BUFFERABLE; @@ -510,9 +754,29 @@ static void __init build_mem_type_table(void) /* * Now deal with the memory-type mappings */ + /* IAMROOT-12CD (2016-09-03): + * -------------------------- + * cp = { + * .policy = "writealloc", + * .cr_mask = 0, + * .pmd = PMD_SECT_WBWA, + * .pte = L_PTE_MT_WRITEALLOC, + * .pte_s2 = 0, 라즈베리파이는 쓰이지 않는다. + * } + */ cp = &cache_policies[cachepolicy]; + /* IAMROOT-12CD (2016-09-03): + * -------------------------- + * vecs_pgprot = kern_pgprot = user_pgprot = L_PTE_MT_WRITEALLOC + */ vecs_pgprot = kern_pgprot = user_pgprot = cp->pte; s2_pgprot = cp->pte_s2; + /* IAMROOT-12CD (2016-09-03): + * -------------------------- + * hyp_device_pgprot = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | + * L_PTE_SHARED, + * s2_device_pgprot = L_PTE_SHARED + */ hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte; s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2; @@ -529,6 +793,11 @@ static void __init build_mem_type_table(void) * Check is it with support for the PXN bit * in the Short-descriptor translation table format descriptors. */ + /* IAMROOT-12CD (2016-09-03): + * -------------------------- + * CPUID_EXT_MMFR0 "c1, 4" -> 0x10201105 + * mrc p15, 0, %0, c0, c1, 4 + */ if (cpu_arch == CPU_ARCH_ARMv7 && (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) == 4) { user_pmd_table |= PMD_PXNTABLE; @@ -544,6 +813,11 @@ static void __init build_mem_type_table(void) * Mark cache clean areas and XIP ROM read only * from SVC mode and no access from userspace. */ + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * APX AP[1:0](RW) Privileged 권한 user 권한 + * 1 0b01 Read only No access + */ mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; @@ -554,7 +828,22 @@ static void __init build_mem_type_table(void) * set, then we need to do the same here for the same * reasons given in early_cachepolicy(). */ +/* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 초기 페이지 테이블이 S 비트 세트를 만든 경우, 우리는 early_cachepolicy()에 + * 주어진 같은 이유로 여기에 동일한 작업을 수행해야합니다. + * initial_pmd_value = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | + * PMD_SECT_AF | PMD_SECT_WBWA|PMD_SECT_S; + * PMD_SEC_S : shared 가 아닐까? + */ if (initial_pmd_value & PMD_SECT_S) { + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * user_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * kern_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * vecs_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * s2_pgprot = L_PTE_SHARED + */ user_pgprot |= L_PTE_SHARED; kern_pgprot |= L_PTE_SHARED; vecs_pgprot |= L_PTE_SHARED; @@ -611,12 +900,31 @@ static void __init build_mem_type_table(void) for (i = 0; i < 16; i++) { pteval_t v = pgprot_val(protection_map[i]); + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * user_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + */ protection_map[i] = __pgprot(v | user_pgprot); } + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * user_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * kern_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * vecs_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * s2_pgprot = L_PTE_SHARED + */ mem_types[MT_LOW_VECTORS].prot_pte |= vecs_pgprot; mem_types[MT_HIGH_VECTORS].prot_pte |= vecs_pgprot; + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * pgprot_user = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * pgprot_kernel = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * pgprot_s2 = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_SHARED + * pgprot_s2_device = L_PTE_SHARED + * pgprot_hyp_device = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED + */ pgprot_user = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot); pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | kern_pgprot); @@ -626,6 +934,18 @@ static void __init build_mem_type_table(void) mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask; mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask; + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * cp->pmd = PMD_SECT_WBWA, + * kern_pgprot = L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * + * mem_types[MT_MEMORY_RWX].prot_sect |= PMD_SECT_WBWA + * mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_WBWA + * mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_MT_WRITEALLOC | L_PTE_SHARED + * mem_types[MT_ROM].prot_sect |= PMD_SECT_WBWA + */ mem_types[MT_MEMORY_RWX].prot_sect |= ecc_mask | cp->pmd; mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot; mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd; @@ -643,6 +963,11 @@ static void __init build_mem_type_table(void) mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB; break; } + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * ecc_mask = 0 + * cp->policy = "writealloc", + */ pr_info("Memory policy: %sData cache %s\n", ecc_mask ? "ECC enabled, " : "", cp->policy); @@ -841,6 +1166,14 @@ static void __init create_36bit_mapping(struct map_desc *md, * offsets, and we take full advantage of sections and * supersections. */ +/* IAMROOT-12CD (2016-09-24): + * -------------------------- + * kernel 실행 영역. + * md.pfn = 0 + * md.virtual = 0x80000000 + * md.length = 0x900000 + * md.type = MT_MEMORY_RWX + */ static void __init create_mapping(struct map_desc *md) { unsigned long addr, length, end; @@ -848,12 +1181,20 @@ static void __init create_mapping(struct map_desc *md) const struct mem_type *type; pgd_t *pgd; + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * 사용자 영역에 맵핑을 만드는 경우 에러. + */ if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n", (long long)__pfn_to_phys((u64)md->pfn), md->virtual); return; } + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * MT_DEVICE이거나 MT_ROM이면서 vmalloc 공간을 벗어날 영역이면 에러. + */ if ((md->type == MT_DEVICE || md->type == MT_ROM) && md->virtual >= PAGE_OFFSET && (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) { @@ -861,6 +1202,12 @@ static void __init create_mapping(struct map_desc *md) (long long)__pfn_to_phys((u64)md->pfn), md->virtual); } + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * md.type = MT_MEMORY_RWX + * 여기까지 12CD 끝입니다. + * AB팀으로 합칩니다. + */ type = &mem_types[md->type]; #ifndef CONFIG_ARM_LPAE @@ -873,6 +1220,11 @@ static void __init create_mapping(struct map_desc *md) } #endif + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * md->virtual = 0x80000000 + * addr = 0x80000000 + */ addr = md->virtual & PAGE_MASK; phys = __pfn_to_phys(md->pfn); length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); @@ -1035,6 +1387,12 @@ void __init debug_ll_io_init(void) } #endif +/* IAMROOT-12CD (2016-07-23): + * -------------------------- + * vmalloc_min = 0xEF800000 + * 3.83G 정도 되고 이 영역은 커널 하이메모리 시작 주소 바로 아래 부분이다. + * 하이메모리 영역은 3.893G~4G영역이다. 그래서 하이메모리 바로 아래에 위치한다. + */ static void * __initdata vmalloc_min = (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET); @@ -1064,15 +1422,36 @@ static int __init early_vmalloc(char *arg) } early_param("vmalloc", early_vmalloc); +/* IAMROOT-12CD (2016-08-06): + * arm_lowmem_limit: 0x3c000000(960mb) + */ phys_addr_t arm_lowmem_limit __initdata = 0; +/* IAMROOT-12CD (2016-07-23): + * -------------------------- + * meminfo 에 근본적인 문제가 있는지 체크. + */ void __init sanity_check_meminfo(void) { phys_addr_t memblock_limit = 0; int highmem = 0; + + /* IAMROOT-12CD (2016-07-23): + * -------------------------- + * vmalloc_limit = 0x6F800000 3.835G + */ phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1; struct memblock_region *reg; + /* IAMROOT-12CD (2016-07-23): + * -------------------------- + * for (reg = memblock.memory.regions; + * reg < (memblock.memory.regions + memblock.memory.cnt); + * reg++) + * reg.base: 0x0 + * reg.size: 0x3c000000 (960mb) + * reg.flags: 0 + */ for_each_memblock(memory, reg) { phys_addr_t block_start = reg->base; phys_addr_t block_end = reg->base + reg->size; @@ -1081,6 +1460,9 @@ void __init sanity_check_meminfo(void) if (reg->base >= vmalloc_limit) highmem = 1; else + /* IAMROOT-12CD (2016-08-06): + * size_limit = 0x6F800000(3.835G) - 0; + */ size_limit = vmalloc_limit - reg->base; @@ -1093,6 +1475,9 @@ void __init sanity_check_meminfo(void) continue; } + /* IAMROOT-12CD (2016-08-06): + * reg->size: 960mb, size_limit: 3.835G + */ if (reg->size > size_limit) { phys_addr_t overlap_size = reg->size - size_limit; @@ -1102,12 +1487,19 @@ void __init sanity_check_meminfo(void) block_end = vmalloc_limit; } } + /* IAMROOT-12CD (2016-08-06): + * block_end: 960mb, arm_lowmem_limit: 0 + */ if (!highmem) { if (block_end > arm_lowmem_limit) { if (reg->size > size_limit) arm_lowmem_limit = vmalloc_limit; else + /* IAMROOT-12CD (2016-08-14): + * -------------------------- + * arm_lowmem_limit: 0x3c000000(960mb) + */ arm_lowmem_limit = block_end; } @@ -1134,6 +1526,10 @@ void __init sanity_check_meminfo(void) } } + /* IAMROOT-12CD (2016-08-06): + * high_memory = (0x3c000000 - 1) + 0x80000000 + 1 + * = 0xBC000000 + */ high_memory = __va(arm_lowmem_limit - 1) + 1; /* @@ -1141,6 +1537,9 @@ void __init sanity_check_meminfo(void) * helps to ensure that we will allocate memory from the * last full pmd, which should be mapped. */ + /* IAMROOT-12CD (2016-08-06): + * memblock_limit = 960mb + */ if (memblock_limit) memblock_limit = round_down(memblock_limit, PMD_SIZE); if (!memblock_limit) @@ -1157,6 +1556,20 @@ static inline void prepare_page_table(void) /* * Clear out all the mappings below the kernel image. */ + /* IAMROOT-12CD (2016-09-10): + * -------------------------- + * 커널이미지 아래 모든 매핑을 청소(data clean)합니다. + * MODULES_VADDR = 2G-16M = 0x7f000000 + * PMD_SIZE = (1 << 21) = 2M + * + * addr pmd_off_k + * 0 0x80004000 + * 0x200000 0x80004008 + * 0x400000 0x80004010 + * 0x600000 0x80004018 + * ... + * 0x7ee00000 0x80005fb8 + */ for (addr = 0; addr < MODULES_VADDR; addr += PMD_SIZE) pmd_clear(pmd_off_k(addr)); @@ -1164,12 +1577,31 @@ static inline void prepare_page_table(void) /* The XIP kernel is mapped in the module area -- skip over it */ addr = ((unsigned long)_etext + PMD_SIZE - 1) & PMD_MASK; #endif + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * addr pmd_off_k + * 0x7f000000 0x80005fc0 + * 0x7f200000 0x80005fc8 + * 0x7f400000 0x80005fd0 + * ... + * 0x7fe00000 0x80005ff8 + */ for ( ; addr < PAGE_OFFSET; addr += PMD_SIZE) pmd_clear(pmd_off_k(addr)); /* * Find the end of the first block of lowmem. */ + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * .memory + * {cnt = 0x1, max = 0x80, total_size = 0x3c000000, regions = { + * [0] = {base = 0x0, size = 0x3c000000, flags = 0x0}, 0 ~ 960M 영역. + * [1] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * + * end = 960M + */ end = memblock.memory.regions[0].base + memblock.memory.regions[0].size; if (end >= arm_lowmem_limit) end = arm_lowmem_limit; @@ -1178,6 +1610,14 @@ static inline void prepare_page_table(void) * Clear out all the kernel space mappings, except for the first * memory bank, up to the vmalloc region. */ + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * end = 960M, addr = 0x80000000 + 960M = 2.96G + * VMALLOC_START = 0xbc800000(968M의 가상주소) = 3.968G + * PMD_SIZE = 2M + * + * 2.96G ~ 3.968G 커널 영역의 Cache clear + */ for (addr = __phys_to_virt(end); addr < VMALLOC_START; addr += PMD_SIZE) pmd_clear(pmd_off_k(addr)); @@ -1200,6 +1640,11 @@ void __init arm_mm_memblock_reserve(void) * Reserve the page tables. These are already in use, * and can only be in node 0. */ + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * swapper_pg_dir = 0x80004000 , + * memblock_reserve(0x4000, 0x4000); + */ memblock_reserve(__pa(swapper_pg_dir), SWAPPER_PG_DIR_SIZE); #ifdef CONFIG_SA1111 @@ -1329,11 +1774,25 @@ static void __init kmap_init(void) static void __init map_lowmem(void) { struct memblock_region *reg; + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * _stext = 0x80008240, kernel_x_start = 0x0 + * __init_end = 0x8080c000, kernel_x_end = 0x900000 + */ phys_addr_t kernel_x_start = round_down(__pa(_stext), SECTION_SIZE); phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE); /* Map all the lowmem memory banks. */ for_each_memblock(memory, reg) { + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * .memory + * {cnt = 0x1, max = 0x80, total_size = 0x3c000000, regions = { + * [0] = {base = 0x0, size = 0x3c000000, flags = 0x0}, 0 ~ 960M 영역. + * [1] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * }} + */ phys_addr_t start = reg->base; phys_addr_t end = start + reg->size; struct map_desc map; @@ -1359,6 +1818,14 @@ static void __init map_lowmem(void) create_mapping(&map); } else { /* This better cover the entire kernel */ + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * 커널 전체를 커버 해야한다. + * + * start = 0, end = 960M + * _stext = 0x80008240, kernel_x_start = 0x0 + * __init_end = 0x8080c000, kernel_x_end = 0x900000 + */ if (start < kernel_x_start) { map.pfn = __phys_to_pfn(start); map.virtual = __phys_to_virt(start); @@ -1368,6 +1835,13 @@ static void __init map_lowmem(void) create_mapping(&map); } + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * map.pfn = 0 + * map.virtual = 0x80000000 + * map.length = 0x900000 + * map.type = MT_MEMORY_RWX + */ map.pfn = __phys_to_pfn(kernel_x_start); map.virtual = __phys_to_virt(kernel_x_start); map.length = kernel_x_end - kernel_x_start; @@ -1499,6 +1973,10 @@ void __init early_paging_init(const struct machine_desc *mdesc, #else +/* IAMROOT-12CD (2016-07-23): + * -------------------------- + * pi2에서는 mdesc->init_meminfo 값이 NULL 이다. + */ void __init early_paging_init(const struct machine_desc *mdesc, struct proc_info_list *procinfo) { diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index c671f345..16bce139 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -258,6 +258,27 @@ mcr p15, 0, ip, c7, c10, 4 @ data write barrier .endm +/* IAMROOT-12D (2016-05-24): + * -------------------------- + * define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 + * + * .type v7_processor_functions, #object + * .align 2 + * ENTRY(v7_processor_functions) + * .word v7_early_abort + * .word v7_pabort + * .word cpu_v7_proc_init + * .word cpu_v7_proc_fin + * .word cpu_v7_reset + * .word cpu_v7_do_idle + * .word cpu_v7_dcache_clean_area + * .word cpu_v7_switch_mm + * .word cpu_v7_set_pte_ext + * .word cpu_v7_suspend_size + * .word 0 + * .word 0 + * .size v7_processor_functions, . - v7_processor_functions + */ .macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0 .type \name\()_processor_functions, #object .align 2 diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S index 10405b8d..2469a993 100644 --- a/arch/arm/mm/proc-v7-2level.S +++ b/arch/arm/mm/proc-v7-2level.S @@ -23,6 +23,11 @@ #define TTB_FLAGS_UP TTB_IRGN_WB|TTB_RGN_OC_WB #define PMD_FLAGS_UP PMD_SECT_WB +/* IAMROOT-12D (2016-03-12): + * -------------------------- + * PTW : Page Table Walks + * WBWA : Write Back Write Allocate + */ /* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */ #define TTB_FLAGS_SMP TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA #define PMD_FLAGS_SMP PMD_SECT_WBWA|PMD_SECT_S @@ -148,6 +153,58 @@ ENDPROC(cpu_v7_set_pte_ext) * Macro for setting up the TTBRx and TTBCR registers. * - \ttb0 and \ttb1 updated with the corresponding flags. */ + /* IAMROOT-12D (2016-03-12): + * -------------------------- + * TTBCR을 0으로 세팅하여 page table boundary 사이즈를 16KB 설정한다. + * 왜냐하면 N(TTBCR[2:0])가 0이기 때문이다. (N이 0이면 이전 아키텍처 버 + * 전과 호환됩니다.) + * + * 31 TTBCR 3 2 0 + * +-------------------+---+ + * | UNPREDICTABLE/SBZ | N | + * +-------------------+---+ + * + * TTBR0, TTBR1 + * 31 14-n 13-n 5 43 2 1 0 + * +-------------+------+--+-----+ S : Shareable + * | Base | SBZ | |0|S|C| C : inner cacheable + * +-------------+------+-++-----+ + * | RGN : L1 cache이외의 cacheable상태 + * RGN <--------------+ 00: outer or memory - nonecacheable + * 01: x , 10: outer write-throuth, 11: outer write-back + * + * TTBR0와 TTBR1의 TTB_FLAG들을 설정한다. + * (ex : TTB_FLAGS_SMP TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA) + * TTB : Translation Table Base + * + * WBWA : Write Back Write Allocate + * IRGN/RGN_OC : Inner/Outer Cache Region + * S : Shared + * NOS : Not Outer shareable + * + * 일반적으로 L1 캐시를 Inner, L2 캐시를 Outer. + * + * http://iamroot.org/wiki/doku.php?id=%EC%8A%A4%ED%84%B0%EB%94%94:2013.07.13_10%EC%B0%A8_arm_b + * Write back cache에서 Write buffer가 있을 때, write allocate 방식과 + * no write allocate 방식. + * write allocate 방식 : + * write miss가 발생했을 때, 우선 메인 메모리로부터 해당 block을 + * fetch하여 cache 내의 block에 allocate한다. 그러면 write hit + * 가 가능해지게 되는데 write hit에 의하여 cache 내 해당 block에 + * write를 수행하면 그 해당 block은 Modified된다. 향후, 다른 + * miss에 의하여 Modified 된 block을 replace하게 되는 경우, miss + * 로 인하여 main memory로부터 요청된 block을 cache로 읽어오는 + * 동안, modified된 block은 write buffer에 write된다. 그리고 + * main memory write가 가능해질 때, write buffer는 그 modified된 + * block을 main memory에 write를 한다. + * no write allocate 방식 : + * write miss가 발생했을 때, 우선 write buffer에 write한다. 그 + * 후, write buffer에 write된 데이터는 메인 메모리에 write를 수 + * 행한다. (메인 메모리로부터 해당 block을 fetch하여 cache 내의 + * block에 allocate를 수행하지 않는다.) + * + * TTBR1을 page table address + TTB_FLAG로 설정한다. + */ .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp mcr p15, 0, \zero, c2, c0, 2 @ TTB control register ALT_SMP(orr \ttbr0, \ttbr0, #TTB_FLAGS_SMP) @@ -165,5 +222,14 @@ ENDPROC(cpu_v7_set_pte_ext) */ .align 2 .type v7_crval, #object + +/* IAMROOT-12D (2016-03-12): + * -------------------------- + * .macro crval, clear, mmuset, ucset + * .word \clear + * .word \mmuset + * .endm + */ + v7_crval: crval clear=0x2120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 7615bbf3..aa328d9d 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -332,6 +332,24 @@ __v7_pj4b_setup: mcr p15, 1, r0, c15, c1, 0 #endif /* CONFIG_CPU_PJ4B */ + /* IAMROOT-12D (2016-03-12): + * -------------------------- + * Commit 참조 : + * - 860ae153d8efa897371453b2d7ba224909b643bc + * - 메세지 : 38주차 (Cache Clean & Flush) + * - v7_flush_decache_louis의 목적은 존재하는 모든 Dcache를 + * Clean & Flush 하는 것이다. + * + * main ID register : CPU ID (machine ID) + * - Raspberry의 main ID = 0x410fc075 + * + * ubfx 란? : + * - unsigned bit field extract + * - ubfx dst, src, lsb, width + * - src에서 lsb 만큼의 비트부터 width만 추출하여 dst에 넣는 명령어 + * - ubfx r0, r0, #4, #12 == (r0 = r0[16:4]) + * + */ __v7_setup: adr r12, __v7_setup_stack @ the local stack @@ -420,7 +438,23 @@ __v7_setup: orrle r10, r10, #1 << 1 @ disable loop buffer mcrle p15, 0, r10, c1, c0, 1 @ write aux control register #endif - + /* IAMROOT-12D (2016-03-12): + * -------------------------- + * 앞서 4로 오기까지 ARM version을 체크했으며 모두 불 일치시 + * 기본적으로 ARM에서 공통적으로 해줘야 할 세팅을 한다. + * r4 = 0x4000(page table entry address) + * r8 = 0x4000(page table entry address) + * + * BTB(Branch Target Buffer:분기예측) + * TLB(page table entry들을 위한 특별한 고속의 cache) + * 1. Cache를 Flush하고, I+D TLB를 Flush 한다. + * 2. TTBCR과 TTBR1을 세팅한다. + * 3. PRRR과 NMRR을 세팅한다. + * - PRRR : Primary Region Remap Register의 약자로서, 메모리 타입 결정 + * - NMRR : Normal Memory Region Register의 약자로서, inner & outer + * cacheability 결정 + * - 참조 문서 : http://www.iamroot.org/xe/Kernel_10_ARM/185229 + */ 4: mov r10, #0 mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate #ifdef CONFIG_MMU @@ -433,6 +467,15 @@ __v7_setup: #endif dsb @ Complete invalidations #ifndef CONFIG_ARM_THUMBEE + /* IAMROOT-12D (2016-03-15): + * -------------------------- + * ID_PFR0 = 라즈베리파이2 0x00001131 + * ThumbEE Base Handler register (TEEHBR). + * ThumbEE Ctrl register (TEECR) + * + * UserSpace에서 TEEHR(ThumbEE Base Handler register) 를 사용하지 못하 + * 게 한다. + */ mrc p15, 0, r0, c0, c1, 0 @ read ID_PFR0 for ThumbEE and r0, r0, #(0xf << 12) @ ThumbEE enabled field teq r0, #(1 << 12) @ check if ThumbEE is present @@ -444,6 +487,26 @@ __v7_setup: mcr p14, 6, r0, c0, c0, 0 @ stop userspace TEEHBR access 1: #endif +/* IAMROOT-12D (2016-03-12): + * -------------------------- + * v7_crval: + * crval clear=0x2120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c + * + * r5 = clear + * r6 = mmuset + * + * v7_crval : v7's control register value + * + * cp15의 control register를 세팅한다. 이 때 cp15는 mmu 및 cache 관련 모든 설정 + * 을 관장하고 현재 그 control register에 mmu 관련 설정 bit를 세팅한다. + * + * TODO : SWP_EMULATE는 무엇이며 clear & mmuset에 세팅하는 비트가 + * 어떤 의미를 가지는가? + * SWP_EMULATE : http://cateee.net/lkddb/web-lkddb/SWP_EMULATE.html + * + * 여기서 2016-03-12 study 진행 종료 + */ + adr r5, v7_crval ldmia r5, {r5, r6} ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables @@ -451,6 +514,17 @@ __v7_setup: orr r5, r5, #(1 << 10) @ set SW bit in "clear" bic r6, r6, #(1 << 10) @ clear it in "mmuset" #endif + /* IAMROOT-12D (2016-03-15): + * -------------------------- + * r0 = 0x00C50878 (SCTLR) + * r5 = 0x2120c302 + * r6 = 0x10c03c7d + * bic r0, r0, r5 = 0x00C50878 + * orr r0, r0, r6 = 0x10c53c7d + * System Control Register에 설정할 값들을 r0에 설정한다. + * 예) cache , MMU, 사용여부, endian 설정, TEX remap 설정, + * vector 테이블 위치등등 + */ mrc p15, 0, r0, c1, c0, 0 @ read control register bic r0, r0, r5 @ clear bits them orr r0, r0, r6 @ set them @@ -486,11 +560,64 @@ __v7_setup_stack: /* * Standard v7 proc info content */ + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * v7_processor_functions : proc-macros.S 참고 + * define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 + * + * .type v7_processor_functions, #object + * .align 2 + * ENTRY(v7_processor_functions) + * .word v7_early_abort + * .word v7_pabort + * .word cpu_v7_proc_init + * .word cpu_v7_proc_fin + * .word cpu_v7_reset + * .word cpu_v7_do_idle + * .word cpu_v7_dcache_clean_area + * .word cpu_v7_switch_mm + * .word cpu_v7_set_pte_ext + * .word cpu_v7_suspend_size + * .word 0 + * .word 0 + * .size v7_processor_functions, . - v7_processor_functions + */ .macro __v7_proc name, initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions + /* IAMROOT-12D (2016-02-20): + * -------------------------- + * PMD_TYPE_SECT (_AT(pmdval_t, 2) << 0) 0x2 + * PMD_SECT_AP_WRITE (_AT(pmdval_t, 1) << 10) 0x400 + * PMD_SECT_AP_READ (_AT(pmdval_t, 1) << 11) 0x800 + * PMD_SECT_AF (_AT(pmdval_t, 0)) 0x0 + * PMD_FLAGS_SMP = PMD_SECT_WBWA|PMD_SECT_S = (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE + * | PMD_SECT_BUFFERABLE) = 0x1100c + * + * .long 0x11c0e + * + * http://kth3321.blogspot.kr/2013/04/arm-cortex-1.html + * http://kth3321.blogspot.kr/2013/06/arm-cortex-2.html + */ ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \ PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags) + + /* IAMROOT-12D (2016-02-20): + * -------------------------- + * PMD_FLAGS_UP = PMD_SECT_WB = + * (PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE) 0x8|0x4 = 0xc + * + * .long 0xc0e + */ ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \ PMD_SECT_AF | PMD_FLAGS_UP | \mm_mmuflags) + /* IAMROOT-12D (2016-02-20): + * -------------------------- + * PMD_TYPE_SECT (_AT(pmdval_t, 2) << 0) 0x2 + * PMD_SECT_AP_WRITE (_AT(pmdval_t, 1) << 10) 0x400 + * PMD_SECT_AP_READ (_AT(pmdval_t, 1) << 11) 0x800 + * PMD_SECT_AF (_AT(pmdval_t, 0)) 0x0 + * + * .long 0xc02 + */ .long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ | PMD_SECT_AF | \io_mmuflags initfn \initfunc, \name @@ -500,6 +627,16 @@ __v7_setup_stack: HWCAP_EDSP | HWCAP_TLS | \hwcaps .long cpu_v7_name .long \proc_fns + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * tlb-v7.S 와 proc-macros.S 참고. + */ + /* IAMROOT-12CD (2016-09-24): + * -------------------------- + * v7vbi_tlb_fns.tlb = v7wbi_tlb_flags_smp(TLB_WB | TLB_BARRIER | \ + * TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | \ + * TLB_V7_UIS_ASID | TLB_V7_UIS_BP) + */ .long v7wbi_tlb_fns .long v6_user_fns .long v7_cache_fns @@ -631,7 +768,28 @@ __krait_proc_info: */ .type __v7_proc_info, #object __v7_proc_info: +/* IAMROOT-12D (2016-02-20): + * -------------------------- + *매크로 변환후 + * + *__v7_proc_info: + * .long 0x000f0000 @ Required ID value + * .long 0x000f0000 @ Mask for ID + * .long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_SECT_AF | PMD_FLAGS_SMP + * .long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_SECT_AF + * initfn __v7_setup, __v7_proc + * .long cpu_arch_name + * .long cpu_elf_name + * .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | HWCAP_EDSP | HWCAP_TLS + * .long cpu_v7_name + * .long v7_processor_functions + * .long v7wbi_tlb_fns + * .long v6_user_fns + * .long v7_cache_fns + * .size __v7_proc_info, . - __v7_proc_info + */ .long 0x000f0000 @ Required ID value .long 0x000f0000 @ Mask for ID __v7_proc __v7_proc_info, __v7_setup .size __v7_proc_info, . - __v7_proc_info + diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S index e5101a3b..a63a79e2 100644 --- a/arch/arm/mm/tlb-v7.S +++ b/arch/arm/mm/tlb-v7.S @@ -92,4 +92,14 @@ ENDPROC(v7wbi_flush_kern_tlb_range) __INIT /* define struct cpu_tlb_fns (see and proc-macros.S) */ + /* IAMROOT-12D (2016-05-25): + * -------------------------- + * .type v7wbi_tlb_fns, #object + * ENTRY(v7wbi_tlb_fns) + * .long v7wbi_flush_user_tlb_range + * .long v7wbi_flush_kern_tlb_range + * ALT_SMP(.long v7wbi_tlb_flags_smp ) + * ALT_UP(.long v7wbi_tlb_flags_up ) + * .size v7wbi_tlb_fns, . - v7wbi_tlb_fns + */ define_tlb_functions v7wbi, v7wbi_tlb_flags_up, flags_smp=v7wbi_tlb_flags_smp diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 950fff9c..e16e453a 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -28,12 +28,20 @@ #include #include +/* IAMROOT-12CD (2016-08-17): + * -------------------------- + * CONFIG_CMA_SIZE_MBYTES=5 + */ #ifdef CONFIG_CMA_SIZE_MBYTES #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES #else #define CMA_SIZE_MBYTES 0 #endif +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * dma_contiguous_default_area = &cma_areas[0] + */ struct cma *dma_contiguous_default_area; /* @@ -46,6 +54,10 @@ struct cma *dma_contiguous_default_area; * Users, who want to set the size of global CMA area for their system * should use cma= kernel parameter. */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * size_byptes = 5M(0x500000) + */ static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M; static phys_addr_t size_cmdline = -1; static phys_addr_t base_cmdline; @@ -113,6 +125,10 @@ void __init dma_contiguous_reserve(phys_addr_t limit) pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit); + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * size_cmdline 초기값은 -1 + */ if (size_cmdline != -1) { selected_size = size_cmdline; selected_base = base_cmdline; @@ -121,6 +137,10 @@ void __init dma_contiguous_reserve(phys_addr_t limit) fixed = true; } else { #ifdef CONFIG_CMA_SIZE_SEL_MBYTES + /* IAMROOT-12CD (2016-08-17): + * -------------------------- + * selected_size = 5M(0x500000) + */ selected_size = size_bytes; #elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE) selected_size = cma_early_percent_memory(); @@ -131,10 +151,20 @@ void __init dma_contiguous_reserve(phys_addr_t limit) #endif } + /* IAMROOT-12CD (2016-08-17): + * -------------------------- + * selected_size = 5M(0x500000) + * dma_contiguous_default_area = 0 + */ if (selected_size && !dma_contiguous_default_area) { pr_debug("%s: reserving %ld MiB for global area\n", __func__, (unsigned long)selected_size / SZ_1M); + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * selected_size= 5M(0x500000), selected_base= 0, + * selected_limit= 0xffffffff, fixed= false + */ dma_contiguous_reserve_area(selected_size, selected_base, selected_limit, &dma_contiguous_default_area, @@ -159,17 +189,36 @@ void __init dma_contiguous_reserve(phys_addr_t limit) * If @fixed is true, reserve contiguous area at exactly @base. If false, * reserve in range from @base to @limit. */ +/* IAMROOT-12CD (2016-08-17): + * -------------------------- + * size: 5M(0x500000), base: 0, limit: 0xffffffff, fixed: false + */ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, phys_addr_t limit, struct cma **res_cma, bool fixed) { int ret; + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * base= 0, size= 5M(0x500000), limit= 0xffffffff, fixed= false, + * res_cms= &dma_contiguous_default_area + */ ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, res_cma); if (ret) return ret; + /* IAMROOT-12CD (2016-08-22): + * -------------------------- + * *res_cms = &cma_areas[0] + * cma_get_base(&cma_areas[0]) = 0x3b8000000 (960M - 8M) + * cma_get_size(&cma_areas[0]) = 0x8000000 (8M) + */ /* Architecture specific contiguous memory fixup. */ + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * dma_contiguous_early_fixup(952M, 8M) + */ dma_contiguous_early_fixup(cma_get_base(*res_cma), cma_get_size(*res_cma)); diff --git a/drivers/char/broadcom/vc_cma/vc_cma.c b/drivers/char/broadcom/vc_cma/vc_cma.c index 07b31a7b..0e9b2ee3 100644 --- a/drivers/char/broadcom/vc_cma/vc_cma.c +++ b/drivers/char/broadcom/vc_cma/vc_cma.c @@ -115,9 +115,17 @@ static struct proc_dir_entry *vc_cma_proc_entry; phys_addr_t vc_cma_base; struct page *vc_cma_base_page; +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * vc_cma_size = 0 + */ unsigned int vc_cma_size; EXPORT_SYMBOL(vc_cma_size); unsigned int vc_cma_initial; +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * vc_cma_chunks = 0 + */ unsigned int vc_cma_chunks; unsigned int vc_cma_chunks_used; unsigned int vc_cma_chunks_reserved; @@ -203,6 +211,10 @@ void vc_cma_reserve(void) /* if vc_cma_size is set, then declare vc CMA area of the same * size from the end of memory */ + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * vc_cma_size = 0 + */ if (vc_cma_size) { if (dma_declare_contiguous(&vc_cma_device.dev, vc_cma_size, vc_cma_base, 0) == 0) { diff --git a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h index ef338509..b0456dd3 100644 --- a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h @@ -36,6 +36,12 @@ #define ARRAY_SIZE(_A) (sizeof(_A) / sizeof((_A)[0])) #endif /* ARRAY_SIZE */ +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * DIV_ROUND_UP(4, 32) = 1 + * DIV_ROUND_UP(32, 32) = 1 + * DIV_ROUND_UP(35, 32) = 2 + */ #define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) #define max_t(type, x, y) ((x) > (y) ? (x) : (y)) #define min_t(type, x, y) ((x) < (y) ? (x) : (y)) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index dd7fbfe8..dab5949c 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -449,13 +449,36 @@ void of_fdt_unflatten_tree(unsigned long *blob, EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); /* Everything below here references initial_boot_params directly. */ +/* IAMROOT-12CD (2016-06-17): + * -------------------------- + * dt_root_size_cells = \ { #address-cells } = 1 + * dt_root_addr_cells = \ { #size-cells } = 1 + * + * arch/arm/boot/dts/skeleton.dtsi + * / { + * #address-cells = <1>; + * #size-cells = <1>; + * ... + * }; + */ int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * Setup flat device-tree pointer + * fdt 주소로 설정 되어 있다.(가상주소 0x8xxxxxxx 대역) + */ void *initial_boot_params; #ifdef CONFIG_OF_EARLY_FLATTREE +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * fdt 테이블 데이터 crc32값 + * CRC(Cyclic Redundancy Check)는 시리얼 전송에서 데이타의 신뢰성을 검증하기 + * 위한 에러 검출 방법의 일종이다. + */ static u32 of_fdt_crc32; /** @@ -581,6 +604,10 @@ void __init early_init_fdt_scan_reserved_mem(void) return; /* Reserve the dtb region */ + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * dtb 영역을 예약영역(memblock.reserved)에 설정한다.(추가한다) + */ early_init_dt_reserve_memory_arch(__pa(initial_boot_params), fdt_totalsize(initial_boot_params), 0); @@ -593,7 +620,16 @@ void __init early_init_fdt_scan_reserved_mem(void) early_init_dt_reserve_memory_arch(base, size, 0); } + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * __fdt_scan_reserved_mem에서 아무것도 하지 않는다. + */ of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); + + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * 아무것도 하지않음. + */ fdt_init_reserved_mem(); } @@ -606,6 +642,10 @@ void __init early_init_fdt_scan_reserved_mem(void) * used to extract the memory information at boot before we can * unflatten the tree */ +/* IAMROOT-12D (2016-06-11): + * -------------------------- + * of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); + */ int __init of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, int depth, void *data), @@ -649,6 +689,11 @@ int __init of_get_flat_dt_size(void) * This function can be used within scan_flattened_dt callback to get * access to properties */ +/* IAMROOT-12CD (2016-07-02): + * -------------------------- + * const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + * node = root node 어디쯤 offset.. + */ const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, int *size) { @@ -682,6 +727,13 @@ struct fdt_scan_status { void *data; }; +/* IAMROOT-12D (2016-06-09): + * -------------------------- + * arch/arm/boot/dts/bcm2709-rpi-2-b.dts 참고 + * { compatible = "brcm,bcm2709"; + * model = "Raspberry Pi 2 Model B"; + * } + */ const char * __init of_flat_dt_get_machine_name(void) { const char *name; @@ -702,6 +754,11 @@ const char * __init of_flat_dt_get_machine_name(void) * Iterate through machine match tables to find the best match for the machine * compatible string in the FDT. */ +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * setup_machine_fdt에서 호출 됨 + * of_flat_dt_match_machine(mdesc_best=NULL, arch_get_next_mach); + */ const void * __init of_flat_dt_match_machine(const void *default_match, const void * (*get_next_compat)(const char * const**)) { @@ -711,6 +768,11 @@ const void * __init of_flat_dt_match_machine(const void *default_match, unsigned long dt_root; unsigned int best_score = ~1, score = 0; + /* IAMROOT-12D (2016-05-26): + * -------------------------- + * 초기값 dt_root = 0 + * get_next_compat --> arch_get_next_mach + */ dt_root = of_get_flat_dt_root(); while ((data = get_next_compat(&compat))) { score = of_flat_dt_match(dt_root, compat); @@ -737,11 +799,24 @@ const void * __init of_flat_dt_match_machine(const void *default_match, return NULL; } + /* IAMROOT-12D (2016-06-09): + * -------------------------- + * Machine model: Raspberry Pi 2 Model B Rev 1.1 + */ pr_info("Machine model: %s\n", of_flat_dt_get_machine_name()); return best_data; } +/* IAMROOT-12CD (2016-06-25): + * -------------------------- + * 라즈베리파이는 CONFIG_BLK_DEV_INITRD 를 지원하며 + * CONFIG_BLK_DEV_INITRD + * Initial RAM filesystem and RAM disk (initramfs/initrd) support + * initramfs, initrd(Initial RAM disk)를 지원 + * initrd : 부팅하는 동안 임시적으로 루트 파일시스템으로 쓰이는 RAM disk. + * initramfs : initrd의 계승자(successor). + */ #ifdef CONFIG_BLK_DEV_INITRD /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree @@ -755,6 +830,19 @@ static void __init early_init_dt_check_for_initrd(unsigned long node) pr_debug("Looking for initrd properties... "); + /* IAMROOT-12CD (2016-06-25): + * -------------------------- + * 라즈베리파이2는 해당사항 없음. + * + * tegra114 soc의 경우.. + * chosen { + * / * SHIELD's bootloader's arguments need to be overridden * / + * bootargs = "console=ttyS0,115200n8 console=tty1 gpt fbcon=rotate:1"; + * / * SHIELD's bootloader will place initrd at this address * / + * linux,initrd-start = <0x82000000>; + * linux,initrd-end = <0x82800000>; + * }; + */ prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); if (!prop) return; @@ -781,6 +869,11 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) #ifdef CONFIG_SERIAL_EARLYCON extern struct of_device_id __earlycon_of_table[]; +/* IAMROOT-12CD (2016-07-09): + * -------------------------- + * 라즈베리 파이2에서는 /chosen/stdout-path, /chosen/linux,stdout-path 값이 없으 + * 므로 아무것도 하지 않고 리턴(-ENOENT)한다. + */ static int __init early_init_dt_scan_chosen_serial(void) { int offset; @@ -861,10 +954,18 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname, return 1; } +/* IAMROOT-12CD (2016-07-02): + * -------------------------- + * s = 1, cellp = "reg : <0 0>;" 시작지점" + */ u64 __init dt_mem_next_cell(int s, const __be32 **cellp) { const __be32 *p = *cellp; + /* IAMROOT-12CD (2016-07-02): + * -------------------------- + * *cellp 는 "reg : <0 0>;" 값중 두번째 0을 가르키게 한다. + */ *cellp = p + s; return of_read_number(p, s); } @@ -872,6 +973,19 @@ u64 __init dt_mem_next_cell(int s, const __be32 **cellp) /** * early_init_dt_scan_memory - Look for an parse memory nodes */ +/* IAMROOT-12CD (2016-06-17): + * -------------------------- + * arch/arm/boot/dts/skeleton.dtsi + * / { + * #address-cells = <1>; + * #size-cells = <1>; + * chosen { }; + * aliases { }; + * memory { device_type = "memory"; reg = <0 0>; }; + * }; + * + * 결론 : 라즈베리파이2에서는 reg = <0 0> 이므로 아무것도 하지 않고 끝낸다. + */ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data) { @@ -890,12 +1004,28 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, } else if (strcmp(type, "memory") != 0) return 0; + /* IAMROOT-12CD (2016-06-25): + * -------------------------- + * reg 는 아래의 "reg = <0 0>" 값으로 설정 된다. + * / { + * #address-cells = <1>; + * #size-cells = <1>; + * chosen { }; + * aliases { }; + * memory { device_type = "memory"; reg = <0 0>; }; + * }; + */ reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); if (reg == NULL) reg = of_get_flat_dt_prop(node, "reg", &l); if (reg == NULL) return 0; + /* IAMROOT-12CD (2016-07-02): + * -------------------------- + * 라즈베리파이 2의 경우 reg = <0 0> 이기 때문에 (l / sizeof(__be32)) 값 + * 은 2이기 때문에 l = 8 + */ endp = reg + (l / sizeof(__be32)); pr_debug("memory scan node %s, reg size %d,\n", uname, l); @@ -931,6 +1061,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, early_init_dt_check_for_initrd(node); + /* IAMROOT-12CD (2016-06-25): + * -------------------------- + * bootargs 는 atags 에 있는 cmdline 값이다. + * arch/arm/boot/compressed/atags_to_fdt.c 에서 atags에 있는 값을 fdt에 + * 복사 했다. + */ /* Retrieve command line */ p = of_get_flat_dt_prop(node, "bootargs", &l); @@ -944,6 +1080,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, */ ((char *)data)[0] = '\0'; +/* IAMROOT-12CD (2016-06-17): + * -------------------------- + * 라즈베리파이2 + * CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" + * CONFIG_CMDLINE_EXTEND is not set + * CONFIG_CMDLINE_FORCE is not set + */ #ifdef CONFIG_CMDLINE strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); @@ -958,6 +1101,10 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, #elif defined(CONFIG_CMDLINE_FORCE) pr_warning("Ignoring bootargs property (using the default kernel command line)\n"); #else + /* IAMROOT-12CD (2016-06-25): + * -------------------------- + * 위의 CONFIG_CMDLINE 값을 무시하고 atags에 있는 정보가 복사됨 + */ /* Neither extend nor force - just override */ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); #endif @@ -980,6 +1127,10 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) { const u64 phys_offset = __pa(PAGE_OFFSET); + /* IAMROOT-12CD (2016-07-02): + * -------------------------- + * PAGE_SIZE 단위로 align을 맞쳐준다. + */ if (!PAGE_ALIGNED(base)) { if (size < PAGE_SIZE - (base & ~PAGE_MASK)) { pr_warn("Ignoring memory block 0x%llx - 0x%llx\n", @@ -1043,6 +1194,10 @@ int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, } #endif +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * 간단한 fdt헤더 검사와 crc32을 만든다. + */ bool __init early_init_dt_verify(void *params) { if (!params) @@ -1062,6 +1217,10 @@ bool __init early_init_dt_verify(void *params) void __init early_init_dt_scan_nodes(void) { + /* IAMROOT-12CD (2016-06-25): + * -------------------------- + * atags에 있던 cmdline를 boot_command_line에 복사. + */ /* Retrieve various information from the /chosen node */ of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index ad458012..e60e1066 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2152,7 +2152,38 @@ static int __init pl011_early_console_setup(struct earlycon_device *device, device->con->write = pl011_early_write; return 0; } +/* +#define EARLYCON_DECLARE(_name, func) \ + static const struct earlycon_id __earlycon_##_name \ + __used __section(__earlycon_table) \ + = { .name = __stringify(_name), \ + .setup = func } + +#define OF_EARLYCON_DECLARE(name, compat, fn) \ + _OF_DECLARE(earlycon, name, compat, fn, void *) +*/ +/* IAMROOT-12CD (2016-07-09): + * -------------------------- + * EARLYCON_DECLARE(pl011, pl011_early_console_setup); + * static const struct earlycon_id __earlycon_pl011 + * __used __section(__earlycon_table) + * = { .name = "pl011", + * .setup = pl011_early_console_setup } + * + */ +/* IAMROOT-12D (2016-07-16): + * -------------------------- + * 어찌하면 console의 val값인 "ttyAMA"가 들어올수 있을까? + */ EARLYCON_DECLARE(pl011, pl011_early_console_setup); +/* IAMROOT-12CD (2016-07-09): + * -------------------------- + * OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); + * static const struct of_device_id __of_table_pl011 + * __used __section(__earlycon_of_table) + * = { .compatible = "arm,pl011", + * .data = pl011_early_console_setup }; + */ OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); #else diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 6dc471e3..e50dc952 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -145,6 +145,12 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) * Returns 0 if an attempt to register the earlycon was made, * otherwise negative error code */ +/* IAMROOT-12D (2016-07-16): + * -------------------------- + * buf = "ttyAMA0,115200" + * buf = "tty1" + * 설명 : 총 처리할 파라미터는 두개 + */ int __init setup_earlycon(char *buf) { const struct earlycon_id *match; @@ -175,6 +181,13 @@ int __init setup_earlycon(char *buf) } /* early_param wrapper for setup_earlycon() */ +/* IAMROOT-12D (2016-07-16): + * -------------------------- + * console=ttyAMA0,115200 console=tty1 + * = = + * buf = "ttyAMA0,115200" + * buf = "tty1" + */ static int __init param_setup_earlycon(char *buf) { int err; diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index ecdf9405..69294743 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -389,11 +389,25 @@ typedef char *va_list; /* Storage alignment properties */ +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * _AUPBND = 3 + * _ADNBND = 3 + */ #define _AUPBND (sizeof (acpi_native_int) - 1) #define _ADNBND (sizeof (acpi_native_int) - 1) /* Variable argument list macro definitions */ +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * (void) ((args) = (((char *) &fmt + (_bnd(fmt, _AUPBND)))) + * _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) + * _bnd(fmt, 3) = (((sizeof(fmt)) + 3) &(~3)) + * = (4 + 3) & ~3 = 4 + * + * _bnd : 4바이트 올림정렬(alignment) + */ #define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) #define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) #define va_end(ap) (ap = (va_list) NULL) diff --git a/include/asm-generic/bitsperlong.h b/include/asm-generic/bitsperlong.h index d1d70aa1..e4af8540 100644 --- a/include/asm-generic/bitsperlong.h +++ b/include/asm-generic/bitsperlong.h @@ -4,6 +4,11 @@ #include +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * 32 bit cpu는 long 이 32비트 + * 64 bit cpu에서는 long이 64비트 + */ #ifdef CONFIG_64BIT #define BITS_PER_LONG 64 #else diff --git a/include/asm-generic/cmpxchg.h b/include/asm-generic/cmpxchg.h index 811fb1e9..ead19bf8 100644 --- a/include/asm-generic/cmpxchg.h +++ b/include/asm-generic/cmpxchg.h @@ -21,6 +21,10 @@ */ extern void __xchg_called_with_bad_pointer(void); +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * irq를 disable 시키고(값을 바꾼후 원래대로) 값을 바꾼다. + */ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index 4d9f233c..67dcbdb9 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -14,6 +14,11 @@ * Most arches use the __per_cpu_offset array for those offsets but * some arches have their own ways of determining the offset (x86_64, s390). */ +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * per_cpu_offset()은 특정 프로세서에 대한 인스턴스를 얻기 위해 percpu 변수에 + * 더해져야 하는 오프셋이다. + */ #ifndef __per_cpu_offset extern unsigned long __per_cpu_offset[NR_CPUS]; @@ -52,10 +57,10 @@ extern void setup_per_cpu_areas(void); #ifndef PER_CPU_BASE_SECTION #ifdef CONFIG_SMP #define PER_CPU_BASE_SECTION ".data..percpu" -#else +#else /* !CONFIG_SMP */ #define PER_CPU_BASE_SECTION ".data" -#endif -#endif +#endif /* CONFIG_SMP */ +#endif /* PER_CPU_BASE_SECTION */ #ifndef PER_CPU_ATTRIBUTES #define PER_CPU_ATTRIBUTES diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index ea17cca9..cc05318e 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -172,6 +172,12 @@ extern unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int extern int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, int nmaskbits); +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * BITS_PER_LONG = 32 bit + * BITMAP_FIRST_WORD_MASK(4) = 0xfffffff0 + * BITMAP_LAST_WORD_MASK(4) = 0x0000000f + */ #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 297f5bda..6b5f4a5b 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -10,6 +10,13 @@ #define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) #define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) #define BITS_PER_BYTE 8 +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * 몇개의 long으로 nr(bit)로 커버 가능한가. + * BITS_TO_LONGS( 4) = 1 + * BITS_TO_LONGS(32) = 1 + * BITS_TO_LONGS(35) = 2 + */ #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #endif diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index b9cb94c3..e18dfcb1 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -44,6 +44,17 @@ extern int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, #define SUBSYS(_x) _x ## _cgrp_id, enum cgroup_subsys_id { #include + /* IAMROOT-12D (2016-05-04): + * -------------------------- + * cpuset_cgrp_id, + * cpu_cgrp_id, + * cpuacct_cgrp_id, + * blkio_cgrp_id, + * memory_cgrp_id, + * devices_cgrp_id, + * freezer_cgrp_id, + * net_cls_cgrp_id, + */ CGROUP_SUBSYS_COUNT, }; #undef SUBSYS @@ -253,6 +264,13 @@ struct cgroup { * following lists all css_sets which point to this cgroup's css * for the given subsystem. */ + /* IAMROOT-12D (2016-04-30): + * -------------------------- + * cset이 cgroup subsystem들인지는 알겠다. 왜 e_ 라는 prefix는 + * 무엇을 의미하는가? + * : enabled cset을 의미한다. 즉 기존에 cset은 모든 cset을 가지고 + * 있다면 e_csets는 enable된 cset을 의미한다. + */ struct list_head e_csets[CGROUP_SUBSYS_COUNT]; /* diff --git a/include/linux/cma.h b/include/linux/cma.h index f7ef093e..fb9b586f 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -5,7 +5,15 @@ * There is always at least global CMA area and a few optional * areas configured in kernel .config. */ +/* IAMROOT-12CD (2016-08-17): + * -------------------------- + * CONFIG_CMA_AREAS=7 + */ #ifdef CONFIG_CMA_AREAS +/* IAMROOT-12CD (2016-08-17): + * -------------------------- + * MAX_CMA_AREAS=8 + */ #define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS) #else diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 86772259..7574eb03 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -7,6 +7,10 @@ # define __user __attribute__((noderef, address_space(1))) # define __kernel __attribute__((address_space(0))) # define __safe __attribute__((safe)) +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * __force를 가지고 있으면 sparse 가 warning을 띄우지 않는다. + */ # define __force __attribute__((force)) # define __nocast __attribute__((nocast)) # define __iomem __attribute__((noderef, address_space(2))) @@ -131,6 +135,17 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); # ifndef likely # define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1)) # endif + +/* IAMROOT-12D (2016-04-09): + * -------------------------- + * !!는 이중 부정을 의미하므로 숫자 0이면 false, 그외 숫자일때 true를 리턴 + * boolean이 아닌 값을 boolean을 만듬 + * + * __builtin_constant_p = 이 기본 제공 함수는 컴파일 시 값이 상수로 알려져 있는 + * 지 판단합니다.이 기본 제공 함수는 ARM 컴파일러에서 지원하는 GNU 컴파일러 확 + * 장입니다. + * + */ # ifndef unlikely # define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0)) # endif @@ -160,6 +175,13 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); #endif /* CONFIG_PROFILE_ALL_BRANCHES */ #else +/* IAMROOT-12D (2016-04-09): + * -------------------------- + * __builtin_expect : + * 이 내장 함수는 컴파일러에 분기 예상 정보를 제공합니다. + * __builtin_expect(expr, , c)를 호출하면 expr == c가 예상됨을 + * 컴파일러에 알립니다. + */ # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) #endif diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 59915ea5..244bea03 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -12,6 +12,10 @@ #include /* Don't assign or return these: may not be this big! */ +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * typedef struct cpumask { unsigned long bits[1]; } cpumask_t; + */ typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t; /** @@ -794,7 +798,21 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) nr_cpu_ids); } +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * NR_CPUS : 4 (라즈베리파이2 cpu 개수) + * BITS_PER_LONG : 32 (라즈베리파이2 32bit cpu) + */ #if NR_CPUS <= BITS_PER_LONG +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * BITS_TO_LONGS( 3) --> 1 3비트를 몇개의 long으로 표현할수 있는가? + * BITS_TO_LONGS(32) --> 1 32비트는 1개의 long으로 표현할수 있다. + * BITS_TO_LONGS(35) --> 2 35비트는 2개의 long으로 표현할수 있다. + * BITMAP_LAST_WORD_MASK(4) --> 0x0000000f + * BITMAP_LAST_WORD_MASK(5) --> 0x0000001f + * BITMAP_LAST_WORD_MASK(6) --> 0x0000003f + */ #define CPU_MASK_ALL \ (cpumask_t) { { \ [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 822c1354..7d052aed 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h @@ -11,6 +11,10 @@ extern int debug_locks; extern int debug_locks_silent; +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * debug_locks에 0을 설정하고 기존 debug_locks 값을 반환한다. + */ static inline int __debug_locks_off(void) { return xchg(&debug_locks, 0); @@ -21,6 +25,10 @@ static inline int __debug_locks_off(void) */ extern int debug_locks_off(void); +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * c 값이 true이면 WARN을 출력 + */ #define DEBUG_LOCKS_WARN_ON(c) \ ({ \ int __ret = 0; \ diff --git a/include/linux/debugobjects.h b/include/linux/debugobjects.h index 98ffcbd4..ca04d403 100644 --- a/include/linux/debugobjects.h +++ b/include/linux/debugobjects.h @@ -25,11 +25,11 @@ struct debug_obj_descr; * @descr: pointer to an object type specific debug description structure */ struct debug_obj { - struct hlist_node node; - enum debug_obj_state state; - unsigned int astate; - void *object; - struct debug_obj_descr *descr; + struct hlist_node node; /* 트랙커 리스트에 있는 오브젝트 링크 */ + enum debug_obj_state state; /* 추적된 오브젝트의 상태 */ + unsigned int astate; /* 현재 active 상태 */ + void *object;/* 실제 오브젝트에 대한 포인터 */ + struct debug_obj_descr *descr; /* 디버깅용 디스크립터 구조체 포인터 */ }; /** diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 6cd8c0ee..15e2ac58 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -666,6 +666,15 @@ static inline void __ftrace_enabled_restore(int enabled) #endif /* Archs may use other ways for ADDR1 and beyond */ +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * http://forum.falinux.com/zbxe/index.php?document_srl=550242&mid=lecture_tip + * void *__builtin_return_address(unsigned int LEVEL) + * 이 함수는 리턴수소, 즉 자신을 호출한 함수의 반환 위치 주소를 돌려 줍니다 + * arm 으로 하면 현재 상태에서의 lr 을 반환해 주는 것입니다. + * 매개 변수 LEVEL 은 호출 지점을 몇번 거슬러 올라갈지를 지정합니다. + * + */ #ifndef ftrace_return_address # ifdef CONFIG_FRAME_POINTER # define ftrace_return_address(n) __builtin_return_address(n) diff --git a/include/linux/init.h b/include/linux/init.h index 21b6d768..8e96bd98 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -267,6 +267,34 @@ struct obs_kernel_param { * NOTE: fn is as per module_param, not __setup! * Emits warning if fn returns non-zero. */ +/* IAMROOT-12D (2016-07-16): + * -------------------------- + *static int __init param_setup_earlycon(char *buf) + *{ + * int err; + * + * if (!buf || !buf[0]) + * return 0; + * + * err = setup_earlycon(buf); + * if (err == -ENOENT || err == -EALREADY) + * return 0; + * return err; + *} + * + * 변환 형태 : + * early_param("earlycon", param_setup_earlycon); + * -> __setup_param(str, fn, fn, 1) + * -> __setup_param(str, unique_id, fn, early) + * static const char __setup_str_param_setup_earlycon[] __init const + * __aligned(1) = "earlycon"; + * static struct obs_kernel_param __setup_param_setup_earlycon + * __used __section(.init.setup) + * __attribute__((aligned((sizeof(long))))) + * = { __setup_str_param_setup_earlycon, param_setup_earlycon, 1 } + * + * 설명 : 컴파일 타임에 .init.setup section에 차곡차곡 obs_kernel_param 형태로 쌓는다. + */ #define early_param(str, fn) \ __setup_param(str, fn, fn, 1) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 696d2231..d9bf6256 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -186,6 +186,10 @@ extern struct task_group root_task_group; * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * 여기까지. + */ #define INIT_TASK(tsk) \ { \ .state = 0, \ diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index 5dd1272d..78490854 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -130,12 +130,16 @@ #define local_save_flags(flags) raw_local_save_flags(flags) +#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT /* * Some architectures don't define arch_irqs_disabled(), so even if either * definition would be fine we need to use different ones for the time being * to avoid build issues. */ -#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT + /* IAMROOT-12D (2016-04-16): + * -------------------------- + * 현재의 상태 레지스터 값을 가져와서 irq 상태값이 disable인지 아닌지 알아냄. + */ #define irqs_disabled() \ ({ \ unsigned long _flags; \ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3a5b48e5..9adef2db 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -61,6 +61,10 @@ */ #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * round_down(x, y) = x & ~(y-1) + */ #define round_down(x, y) ((x) & ~__round_mask(x, y)) #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) @@ -751,6 +755,10 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } * This macro does strict typechecking of lo/hi to make sure they are of the * same type as val. See the unnecessary pointer comparisons. */ +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * 엄격한 유형 검사와 함께 주어진 범위에 고정 값을 반환 + */ #define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) /* diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h index d0a1f99e..d54a7f84 100644 --- a/include/linux/kmemleak.h +++ b/include/linux/kmemleak.h @@ -60,6 +60,10 @@ static inline void kmemleak_erase(void **ptr) #else +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * 라즈베리파이2는 아래의 함수를 사용함. + */ static inline void kmemleak_init(void) { } diff --git a/include/linux/list.h b/include/linux/list.h index feb773c7..83dd0021 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -634,7 +634,13 @@ static inline void hlist_del_init(struct hlist_node *n) INIT_HLIST_NODE(n); } } - +/* IAMROOT-12D (2016-04-30): + * -------------------------- + * pprev가 double pointer로 구현된 이유는? + * - 기본적으로 속도에 이유가 있다. + * - 동작 자체는 list_head와 별 다를 바 없다. + * - double 포인터는 NULL 포인터를 받는 경우가 전혀 없어 분기분을 없앨 수 있다. + */ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 9497ec7c..6f05521f 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -123,6 +123,10 @@ void __next_mem_range_rev(u64 *idx, int nid, struct memblock_type *type_a, * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL * @p_nid: ptr to int for nid of the range, can be %NULL */ +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * type_a에서 type_b영역을 제외한 memblock 영역을 뒤에서 부터 하나씩 가져온다. + */ #define for_each_mem_range_rev(i, type_a, type_b, nid, \ p_start, p_end, p_nid) \ for (i = (u64)ULLONG_MAX, \ @@ -143,6 +147,10 @@ static inline bool movable_node_is_enabled(void) return movable_node_enabled; } #else +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * 라즈베리파이2는 아래것이 맞다. + */ static inline bool memblock_is_hotpluggable(struct memblock_region *m) { return false; @@ -230,6 +238,10 @@ static inline int memblock_get_region_node(const struct memblock_region *r) return r->nid; } #else +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * 라즈베리파이2 + */ static inline void memblock_set_region_node(struct memblock_region *r, int nid) { } @@ -264,6 +276,10 @@ static inline bool memblock_bottom_up(void) return memblock.bottom_up; } #else +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * 라즈베리 파이2는 아래것이 맞다. + */ static inline void __init memblock_set_bottom_up(bool enable) {} static inline bool memblock_bottom_up(void) { return false; } #endif diff --git a/include/linux/mm.h b/include/linux/mm.h index 0755b9fd..fb8dfc90 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -947,6 +947,18 @@ void set_page_address(struct page *page, void *virtual); void page_address_init(void); #endif +/* IAMROOT-12D (2016-05-21): + * -------------------------- + * Raspberry PI는 메모리가 적은 관계로 Highmem이 설정이 안되어 있기에 + * 아래 sequence를 탄다. + * 결과적으로 page_address_init()은 어떠한 기능도 하지 않는다. + * + * HASHED_PAGE_VIRTUAL + * : HIGHMEM의 운용방식을 결정하는 definition으로 일반적인 Virtual Page로 + * 이를 접근할 것이냐 아니면 따로 Hash table을 만들어 접근할 것인가를 결정한다. + * Hash table로 접근하기 위해서 page_address_init()로 초기화 하고, 아래와 같은 + * 함수들(page_address(), set_page_address())를 사용한다. + */ #if !defined(HASHED_PAGE_VIRTUAL) && !defined(WANT_PAGE_VIRTUAL) #define page_address(page) lowmem_page_address(page) #define set_page_address(page, address) do { } while(0) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 54d74f6e..15c7a675 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -23,6 +23,10 @@ #ifndef CONFIG_FORCE_MAX_ZONEORDER #define MAX_ORDER 11 #else +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * CONFIG_FORCE_MAX_ZONEORDER= 11 + */ #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER #endif #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) diff --git a/include/linux/numa.h b/include/linux/numa.h index 3aaa3160..e5ad9e2f 100644 --- a/include/linux/numa.h +++ b/include/linux/numa.h @@ -5,9 +5,13 @@ #ifdef CONFIG_NODES_SHIFT #define NODES_SHIFT CONFIG_NODES_SHIFT #else -#define NODES_SHIFT 0 +#define NODES_SHIFT 0 /* IAMROOT-12CD: 라즈베리파이 2 */ #endif +/* IAMROOT-12CD (2016-07-02): + * -------------------------- + * MAX_NUMNODES = 1; + */ #define MAX_NUMNODES (1 << NODES_SHIFT) #define NUMA_NO_NODE (-1) diff --git a/include/linux/of.h b/include/linux/of.h index 8135d507..d401af79 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -923,7 +923,7 @@ static inline int of_get_available_child_count(const struct device_node *np) return num; } -#ifdef CONFIG_OF +#ifdef CONFIG_OF /* IAMROOT-12CD: 라즈베리파이2 */ #define _OF_DECLARE(table, name, compat, fn, fn_type) \ static const struct of_device_id __of_table_##name \ __used __section(__##table##_of_table) \ diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h index 2baeee12..13230959 100644 --- a/include/linux/pageblock-flags.h +++ b/include/linux/pageblock-flags.h @@ -56,6 +56,10 @@ extern int pageblock_order; #else /* CONFIG_HUGETLB_PAGE */ /* If huge pages are not used, group by MAX_ORDER_NR_PAGES */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * pageblock_order = 10 + */ #define pageblock_order (MAX_ORDER-1) #endif /* CONFIG_HUGETLB_PAGE */ diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index 57f3a1c5..aaae810b 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -214,6 +214,14 @@ do { \ * to prevent the compiler from making incorrect assumptions about the * pointer value. The weird cast keeps both GCC and sparse happy. */ +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * http://egloos.zum.com/studyfoss/v/5374731 + * + * 주어진 ptr을 통해 off 만큼 떨어진 데이터에 접근하는 경우인데 + * 사실 이 ptr 값이 실제로 메모리 상에 존재하는 데이터 (객체)에 대한 타입이 + * 아니라 (구현 상의 어떤 제약에 따른) 다른 타입의 포인터인 경우이다. + */ #define SHIFT_PERCPU_PTR(__p, __offset) \ RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)) @@ -300,6 +308,24 @@ extern void __this_cpu_preempt_check(const char *op); static inline void __this_cpu_preempt_check(const char *op) { } #endif +/* IAMROOT-12D (2016-04-02): + * -------------------------- + * __pcpu_size_call_return(this_cpu_read_, vprintk_default) + * { + * typeof(vprintk_default) pscr_ret__; + * __verify_pcpu_ptr(&vprintk_default); + * switch(sizeof(vprintk_default)) { + * case 1: pscr_ret__ = this_cpu_read_1(vprintk_default); break; \ + * case 2: pscr_ret__ = this_cpu_read_2(vprintk_default); break; \ + * case 4: pscr_ret__ = this_cpu_read_4(vprintk_default); break; \ + * case 8: pscr_ret__ = this_cpu_read_8(vprintk_default); break; \ + * default: + * __bad_size_call_parameter(); break; + * } + * pscr_ret__; + * } + * + */ #define __pcpu_size_call_return(stem, variable) \ ({ \ typeof(variable) pscr_ret__; \ diff --git a/include/linux/pfn.h b/include/linux/pfn.h index 76466372..fbe6e589 100644 --- a/include/linux/pfn.h +++ b/include/linux/pfn.h @@ -5,8 +5,16 @@ #include #endif +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * Page Frame Number (PFN) + */ #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +/* IAMROOT-12CD (2016-08-22): + * -------------------------- + * 메모리 주소 를 page 단위로 변경 (하위 12비트 제거) + */ #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) #define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT) diff --git a/include/linux/printk.h b/include/linux/printk.h index 9b30871c..623618eb 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -53,6 +53,10 @@ static inline void console_silent(void) console_loglevel = CONSOLE_LOGLEVEL_SILENT; } +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * console_loglevel을 verbose로 설정. + */ static inline void console_verbose(void) { if (console_loglevel) diff --git a/include/linux/sched/prio.h b/include/linux/sched/prio.h index d9cf5a57..07dd0e1c 100644 --- a/include/linux/sched/prio.h +++ b/include/linux/sched/prio.h @@ -3,6 +3,10 @@ #define MAX_NICE 19 #define MIN_NICE -20 +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * NICE 의 폭(40) + */ #define NICE_WIDTH (MAX_NICE - MIN_NICE + 1) /* @@ -21,6 +25,11 @@ #define MAX_USER_RT_PRIO 100 #define MAX_RT_PRIO MAX_USER_RT_PRIO +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * MAX_PRIO = 140 + * DEFAULT_PRIO = 120 + */ #define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH) #define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2) diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index dc368b8c..d6fd6576 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h @@ -29,6 +29,10 @@ struct semaphore { #define DEFINE_SEMAPHORE(name) \ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * 세마포어 count를 val로 설정하고 초기화. + */ static inline void sema_init(struct semaphore *sem, int val) { static struct lock_class_key __key; diff --git a/include/linux/threads.h b/include/linux/threads.h index 383ab959..83f660ba 100644 --- a/include/linux/threads.h +++ b/include/linux/threads.h @@ -11,6 +11,10 @@ * Maximum supported processors. Setting this smaller saves quite a * bit of memory. Use nr_cpu_ids instead of this except for static bitmaps. */ +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * 라즈베리파는 quad core CONFIG_NR_CPUS 가 4이다. + */ #ifndef CONFIG_NR_CPUS /* FIXME: This should be fixed in the arch's Kconfig */ #define CONFIG_NR_CPUS 1 diff --git a/include/linux/types.h b/include/linux/types.h index 8715287c..85319038 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -161,7 +161,7 @@ typedef unsigned __bitwise__ oom_flags_t; #ifdef CONFIG_PHYS_ADDR_T_64BIT typedef u64 phys_addr_t; #else -typedef u32 phys_addr_t; +typedef u32 phys_addr_t; /* IAMROOT-12D: 라즈베리파이2에서 사용 */ #endif typedef phys_addr_t resource_size_t; diff --git a/include/uapi/linux/kernel.h b/include/uapi/linux/kernel.h index 321e3994..866088ce 100644 --- a/include/uapi/linux/kernel.h +++ b/include/uapi/linux/kernel.h @@ -6,6 +6,12 @@ /* * 'kernel.h' contains some often-used function prototypes etc */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * x = 5M, a = 4M + * (5M + (4M-1)) & ~(4M-1)) + * (9M-1) & ~(0x3f ffff) = (9M-1) & 0xffc00000 = 8M + */ #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) diff --git a/init/init_task.c b/init/init_task.c index ba0a7f36..579560a9 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -15,6 +15,10 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); /* Initial task structure */ +/* IAMROOT-12D (2016-03-19): + * -------------------------- + * struct task_struct --> include/linux/sched.h + */ struct task_struct init_task = INIT_TASK(init_task); EXPORT_SYMBOL(init_task); diff --git a/init/main.c b/init/main.c index 2a89545e..ffce7ae0 100644 --- a/init/main.c +++ b/init/main.c @@ -104,6 +104,12 @@ static inline void mark_rodata_ro(void) { } * operations which are not allowed with IRQ disabled are allowed while the * flag is set. */ +/* IAMROOT-12D (2016-05-14): + * -------------------------- + * 주석 해석 + * : 이 플래그를 통해서 IRQ가 disabled 된 상태에서 boot processor 가 실행중이며, + * 'early bootup code' 안에 있음을 알 수 있다 + */ bool early_boot_irqs_disabled __read_mostly; enum system_states system_state __read_mostly; @@ -120,6 +126,26 @@ extern void time_init(void); void (*__initdata late_time_init)(void); /* Untouched command line saved by arch-specific code. */ +/* IAMROOT-12CD (2016-06-16): + * -------------------------- + * boot_command_line = + * dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 bcm2708_fb.fbheight=416 bcm2709. + * boardrev=0xa01041 bcm2709.serial=0xe467606e smsc95xx.macaddr=B8:27:EB:67:60:6E + * bcm2708_fb.fbswap=1 bcm2709.uart_clock=3000000 bcm2709.disk_led_gpio=47 + * bcm2709.disk_led_active_low=0 sdhci-bcm2708.emmc_clock_freq=250000000 + * vc_mem.mem_base=0x3dc00000 vc_mem.mem_size=0x3f000000 dwc_otg.pm_enable=0 + * console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 + * elevator=deadline fsck.repair=yes rootwait + * + * arch/arm/boot/dts/bcm2709.dtsi + * chosen { + * bootargs = ""; + * }; + * + * /boot/cmdline.txt + * dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 + * rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait + */ char __initdata boot_command_line[COMMAND_LINE_SIZE]; /* Untouched saved command line (eg. for /proc) */ char *saved_command_line; @@ -409,11 +435,57 @@ static noinline void __init_refok rest_init(void) cpu_startup_entry(CPUHP_ONLINE); } +/* IAMROOT-12CD (2016-07-16): + * -------------------------- + * 로그 출력 : + * Kernel command line: dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 + * bcm2708_fb.fbheight=416 bcm2709.boardrev=0xa01041 bcm2709.serial= + * 0xe467606e smsc95xx.macaddr=B8:27:EB:67:60:6E bcm2708_fb.fbswap=1 + * bcm2709.uart_clock=3000000 bcm2709.disk_led_gpio=47 bcm2709. + * disk_led_active_low=0 sdhci-bcm2708.emmc_clock_freq=250000000 + * vc_mem.mem_base=0x3dc00000 vc_mem.mem_size=0x3f000000 dwc_otg. + * pm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 + * rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait + * + * struct obs_kernel_param { + * const char *str; + * int (*setup_func)(char *); + * int early; + * }; + * + * 예제 : + * str = "earlycon" + * setup_func = param_setup_earlycon + * early = 1 + */ /* Check for early params. */ +/* IAMROOT-12D (2016-06-11): + * -------------------------- + * do_early_param(param, val, "early options"); + */ static int __init do_early_param(char *param, char *val, const char *unused) { const struct obs_kernel_param *p; + /* IAMROOT-12CD (2016-07-01): + * -------------------------- + * include/linux/init.h + * + * #define __setup_param(str, unique_id, fn, early) \ + * static const char __setup_str_##unique_id[] __initconst \ + * __aligned(1) = str; \ + * static struct obs_kernel_param __setup_##unique_id \ + * __used __section(.init.setup) \ + * __attribute__((aligned((sizeof(long))))) \ + * = { __setup_str_##unique_id, fn, early } + * + * #define __setup(str, fn) \ + * __setup_param(str, fn, fn, 0) + * + * #define early_param(str, fn) \ + * __setup_param(str, fn, fn, 1) + + */ for (p = __setup_start; p < __setup_end; p++) { if ((p->early && parameq(param, p->str)) || (strcmp(param, "console") == 0 && @@ -451,6 +523,10 @@ void __init parse_early_param(void) * Activate the first processor. */ +/* IAMROOT-12D (2016-05-14): + * -------------------------- + * CPU의 상태를 관리하는 전역변수에 현재 CPU상태를 설정한다. + */ static void __init boot_cpu_init(void) { int cpu = smp_processor_id(); @@ -498,7 +574,15 @@ asmlinkage __visible void __init start_kernel(void) * Need to run as early as possible, to initialize the * lockdep hash: */ + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * classhash_table, chainhash_table double linked list를 초기화 한다. + */ lockdep_init(); + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * include/linux/sched.h + */ set_task_stack_end_magic(&init_task); smp_setup_processor_id(); debug_objects_early_init(); @@ -519,6 +603,12 @@ asmlinkage __visible void __init start_kernel(void) */ boot_cpu_init(); page_address_init(); + /* IAMROOT-12D (2016-06-11): + * -------------------------- + * Linux version 4.1.17-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 + * 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - + * Linaro GCC 2014.03) ) #838 SMP Tue Feb 9 13:15:09 GMT 2016 + */ pr_notice("%s", linux_banner); setup_arch(&command_line); mm_init_cpumask(&init_mm); @@ -530,6 +620,18 @@ asmlinkage __visible void __init start_kernel(void) build_all_zonelists(NULL, NULL); page_alloc_init(); + /* IAMROOT-12CD (2016-06-16): + * -------------------------- + * 로그 출력 : + * Kernel command line: dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 + * bcm2708_fb.fbheight=416 bcm2709.boardrev=0xa01041 bcm2709.serial= + * 0xe467606e smsc95xx.macaddr=B8:27:EB:67:60:6E bcm2708_fb.fbswap=1 + * bcm2709.uart_clock=3000000 bcm2709.disk_led_gpio=47 bcm2709. + * disk_led_active_low=0 sdhci-bcm2708.emmc_clock_freq=250000000 + * vc_mem.mem_base=0x3dc00000 vc_mem.mem_size=0x3f000000 dwc_otg. + * pm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 + * rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait + */ pr_notice("Kernel command line: %s\n", boot_command_line); parse_early_param(); after_dashes = parse_args("Booting kernel", diff --git a/init/version.c b/init/version.c index fe41a63e..8f3050a7 100644 --- a/init/version.c +++ b/init/version.c @@ -31,7 +31,7 @@ struct uts_namespace init_uts_ns = { .nodename = UTS_NODENAME, .release = UTS_RELEASE, .version = UTS_VERSION, - .machine = UTS_MACHINE, + .machine = UTS_MACHINE, /* IAMROOT-12D : "armv7l" */ .domainname = UTS_DOMAINNAME, }, .user_ns = &init_user_ns, diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 24283557..316c993b 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -126,6 +126,17 @@ static struct workqueue_struct *cgroup_pidlist_destroy_wq; #define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, static struct cgroup_subsys *cgroup_subsys[] = { #include + /* IAMROOT-12D (2016-05-04): + * -------------------------- + * [cpuset_cgrp_id] = &cpuset_cgrp_subsys, + * [cpu_cgrp_id] = &cpu_cgrp_subsys, + * [cpuacct_cgrp_id] = &cpuacct_cgrp_subsys, + * [blkio_cgrp_id] = &blkio_cgrp_subsys, + * [memory_cgrp_id] = &memory_cgrp_subsys, + * [devices_cgrp_id] = &devices_cgrp_subsys, + * [freezer_cgrp_id] = &freezer_cgrp_subsys, + * [net_cls_cgrp_id] = &net_cls_cgrp_subsys, + */ }; #undef SUBSYS @@ -133,6 +144,17 @@ static struct cgroup_subsys *cgroup_subsys[] = { #define SUBSYS(_x) [_x ## _cgrp_id] = #_x, static const char *cgroup_subsys_name[] = { #include + /* IAMROOT-12D (2016-05-04): + * -------------------------- + * [cpuset_cgrp_id] = "cpuset", + * [cpu_cgrp_id] = "cpu", + * [cpuacct_cgrp_id] = "cpuacct", + * [blkio_cgrp_id] = "blkio", + * [memory_cgrp_id] = "memory", + * [devices_cgrp_id] = "devices", + * [freezer_cgrp_id] = "freezer", + * [net_cls_cgrp_id] = "net_cls", + */ }; #undef SUBSYS @@ -4891,6 +4913,20 @@ static struct kernfs_syscall_ops cgroup_kf_syscall_ops = { .rename = cgroup_rename, }; +/* IAMROOT-12D (2016-05-04): + * -------------------------- + * ss 는 아래의 목록중 한개 + * static struct cgroup_subsys *cgroup_subsys[] = { + * [cpuset_cgrp_id] = &cpuset_cgrp_subsys, + * [cpu_cgrp_id] = &cpu_cgrp_subsys, + * [cpuacct_cgrp_id] = &cpuacct_cgrp_subsys, + * [blkio_cgrp_id] = &blkio_cgrp_subsys, + * [memory_cgrp_id] = &memory_cgrp_subsys, + * [devices_cgrp_id] = &devices_cgrp_subsys, + * [freezer_cgrp_id] = &freezer_cgrp_subsys, + * [net_cls_cgrp_id] = &net_cls_cgrp_subsys, + * }; + */ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) { struct cgroup_subsys_state *css; @@ -4947,6 +4983,14 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) * Initialize cgroups at system boot, and initialize any * subsystems that request early init. */ +/* IAMROOT-12D (2016-04-30): + * -------------------------- + * cgroup 이란? + * - 프로세스들을 그룹화하여 그룹에 자원을 분배하거나 제어하는 + * 기능을 제공해준다. + * - 실질적인 자원 분배를 위해서는 subsystem이 필요하며 인터페이스로서 특정 + * 파일시스템을 마운트해야하는 것으로 보인다. + */ int __init cgroup_init_early(void) { static struct cgroup_sb_opts __initdata opts; @@ -4954,6 +4998,11 @@ int __init cgroup_init_early(void) int i; init_cgroup_root(&cgrp_dfl_root, &opts); + /* IAMROOT-12D (2016-04-30): + * -------------------------- + * cgroup root의 경우 어떠한 subsystem의 영향을 받지 않기에 + * CSS NO REF 로 설정한다. + */ cgrp_dfl_root.cgrp.self.flags |= CSS_NO_REF; RCU_INIT_POINTER(init_task.cgroups, &init_css_set); diff --git a/kernel/fork.c b/kernel/fork.c index 03c1eaaa..45b43d40 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -317,6 +317,14 @@ int __weak arch_dup_task_struct(struct task_struct *dst, return 0; } +/* IAMROOT-12D (2016-03-26): + * -------------------------- + * start_kernel()이 커널 초기화 과정을 수행하는 동안 사용할 최초 커널 스택의 + * 마지막에 magic value를 기록한다. 이후에 만들어지는 커널 스택은 메모리를 + * 할당 받아 생성되어 사용되며 태스크가 종료되는 경우 메모리를 회수한다. + * 기록된 magic value(STACK_END_MAGIC: 0x57AC6E9D)를 통해 + * kernel stack overflow를 감지하는데 사용된다. + */ void set_task_stack_end_magic(struct task_struct *tsk) { unsigned long *stackend; diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index aaeae885..f9b808f8 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -738,6 +738,13 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass) * yet. Otherwise we look it up. We cache the result in the lock object * itself, so actual lookup of the hash should be once per lock object. */ +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * class가 아직 보이지 않았으면 hash-table에 lock class를 등록한다. + * 그렇지 않으면 찾아낸다. lock object 자체의 결과를 cache한다. + * + * TODO: 읽는것을 보류함. + */ static inline struct lock_class * register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) { @@ -3065,6 +3072,10 @@ static int __lock_is_held(struct lockdep_map *lock); * This gets called for every mutex_lock*()/spin_lock*() operation. * We maintain the dependency maps and validate the locking attempt: */ +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * mutex_lock*(), spin_lock*() 등의 모든 함수들이 호출 하는 함수다. + */ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, int trylock, int read, int check, int hardirqs_off, struct lockdep_map *nest_lock, unsigned long ip, @@ -3086,6 +3097,10 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, * get an interrupt which would want to take locks, which would * end up in lockdep and have you got a head-ache already? */ + /* IAMROOT-12D (2016-04-16): + * -------------------------- + * irq가 enable 되어있으면 WARNING을 출력하고 return 0 + */ if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) return 0; @@ -4016,6 +4031,11 @@ void lockdep_reset_lock(struct lockdep_map *lock) raw_local_irq_restore(flags); } +/* IAMROOT-12D (2016-03-26): + * -------------------------- + * lock dependency의 약자로 커널이 lock을 모니터링하고 디버깅하기 위한 것으로 + * dead-lock 검출도 한다. + */ void lockdep_init(void) { int i; @@ -4029,6 +4049,10 @@ void lockdep_init(void) if (lockdep_initialized) return; + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * #define CLASSHASH_SIZE (1UL << 12) = 4k + */ for (i = 0; i < CLASSHASH_SIZE; i++) INIT_LIST_HEAD(classhash_table + i); diff --git a/kernel/params.c b/kernel/params.c index a22d6a75..f4167003 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -93,15 +93,21 @@ static void param_check_unsafe(const struct kernel_param *kp) } } +/* IAMROOT-12D (2016-06-11): + * -------------------------- + * ret = parse_one(param, val, "early options", NULL, 0, 0, 0, + * do_early_param) + */ static int parse_one(char *param, char *val, - const char *doing, - const struct kernel_param *params, - unsigned num_params, - s16 min_level, - s16 max_level, + const char *doing, /* IAMROOT-12CD: "early options" */ + const struct kernel_param *params, /* IAMROOT-12CD: NULL */ + unsigned num_params, /* IAMROOT-12CD: 0 */ + s16 min_level, /* IAMROOT-12CD: 0 */ + s16 max_level, /* IAMROOT-12CD: 0 */ int (*handle_unknown)(char *param, char *val, const char *doing)) + /* IAMROOT-12CD: do_early_param */ { unsigned int i; int err; @@ -128,6 +134,11 @@ static int parse_one(char *param, if (handle_unknown) { pr_debug("doing %s: %s='%s'\n", doing, param, val); + /* IAMROOT-12CD (2016-07-09): + * -------------------------- + * handle_unknown = do_early_param + * doing = "early options" + */ return handle_unknown(param, val, doing); } @@ -137,6 +148,14 @@ static int parse_one(char *param, /* You can use " around spaces, but can't escape ". */ /* Hyphens and underscores equivalent in parameter names. */ +/* IAMROOT-12D (2016-06-11): + * -------------------------- + * args 값이 "foo=bar,bar2 baz=fuz wiz" 라면 + * 결과는 + * args = "baz=fuz wiz" + * *param = "foo" + * *val = "bar,bar2" 가 된다. + */ static char *next_arg(char *args, char **param, char **val) { unsigned int i, equals = 0; @@ -149,6 +168,13 @@ static char *next_arg(char *args, char **param, char **val) quoted = 1; } + /* IAMROOT-12CD (2016-07-09): + * -------------------------- + * args = "dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656" + * ^ <-- args + * ^ ^ <-- equals + * ^ <-- i + */ for (i = 0; args[i]; i++) { if (isspace(args[i]) && !in_quote) break; @@ -160,6 +186,22 @@ static char *next_arg(char *args, char **param, char **val) in_quote = !in_quote; } + /* IAMROOT-12CD (2016-07-09): + * -------------------------- + * 아래 args에서 '_' 가 null이다고 가정 + * args = "dma.dmachans_0x7f35_bcm2708_fb.fbwidth=656" + * ^ <-- args = param + * ^ ^ <-- equals + * ^ <-- i + * ^ <-- val + * ^ <-- NULL + * ^ <-- next + * + * args = "dma.dmachans_0x7f35_bcm2708_fb.fbwidth=656" + * param= "dma.dmachans" + * val = "0x7f35" + * next = "bcm2708_fb.fbwidth=656" + */ *param = args; if (!equals) *val = NULL; @@ -187,14 +229,29 @@ static char *next_arg(char *args, char **param, char **val) return skip_spaces(next); } +/* IAMROOT-12D (2016-06-11): + * -------------------------- + * parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param); + * cmdline = boot_command_line + * + * boot_command_line = + * dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 bcm2708_fb.fbheight=416 bcm2709. + * boardrev=0xa01041 bcm2709.serial=0xe467606e smsc95xx.macaddr=B8:27:EB:67:60:6E + * bcm2708_fb.fbswap=1 bcm2709.uart_clock=3000000 bcm2709.disk_led_gpio=47 + * bcm2709.disk_led_active_low=0 sdhci-bcm2708.emmc_clock_freq=250000000 + * vc_mem.mem_base=0x3dc00000 vc_mem.mem_size=0x3f000000 dwc_otg.pm_enable=0 + * console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 + * elevator=deadline fsck.repair=yes rootwait + */ /* Args looks like "foo=bar,bar2 baz=fuz wiz". */ char *parse_args(const char *doing, - char *args, - const struct kernel_param *params, - unsigned num, - s16 min_level, - s16 max_level, + char *args, /* IAMROOT-12CD: cmdline */ + const struct kernel_param *params, /* IAMROOT-12CD: NULL */ + unsigned num, /* IAMROOT-12CD: 0 */ + s16 min_level, /* IAMROOT-12CD: 0 */ + s16 max_level, /* IAMROOT-12CD: 0 */ int (*unknown)(char *param, char *val, const char *doing)) + /* IAMROOT-12CD: do_early_param */ { char *param, *val; @@ -208,6 +265,13 @@ char *parse_args(const char *doing, int ret; int irq_was_disabled; + /* IAMROOT-12CD (2016-07-09): + * -------------------------- + * dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 + * param = dma.dmachans + * val = 0x7f35 + * return = "bcm2708_fb.fbwidth=656" + */ args = next_arg(args, ¶m, &val); /* Stop at -- */ if (!val && strcmp(param, "--") == 0) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index bff0169e..3c3b9810 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -227,6 +227,10 @@ struct printk_log { * within the scheduler's rq lock. It must be released before calling * console_unlock() or anything else that might wake up a process. */ +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * raw_spinlock_t logbuf_lock = __RAW_SPIN_LOCK_UNLOCKED(x); + */ static DEFINE_RAW_SPINLOCK(logbuf_lock); #ifdef CONFIG_PRINTK @@ -962,6 +966,11 @@ static int __init boot_delay_setup(char *str) } early_param("boot_delay", boot_delay_setup); +/* IAMROOT-12D (2016-04-09): + * -------------------------- + * boot_delay 밀리초만큼 while을 돌며 delay. + * touch_nmi_watchdog은 raspberry pi 에서는 함수가 비어있음. + */ static void boot_delay_msec(int level) { unsigned long long k; @@ -1420,10 +1429,21 @@ static void call_console_drivers(int level, const char *text, size_t len) * To leave time for slow consoles to print a full oops, * only zap at most once every 30 seconds. */ +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * 30초 동안 계속 crash 되어 재귀호출이 일어나면 log, debug락을 풀어버린다. + * 왜냐하면 crash메세지를 계속 출력하고 데드락을 발생시키지 않게 하기위해서다. + * + * debug_locks을 off하고 logbuf_lock초기화, console semaphore를 초기화 한다. + */ static void zap_locks(void) { static unsigned long oops_timestamp; + /* IAMROOT-12D (2016-04-16): + * -------------------------- + * 30초 이전에 재 호출되었으면 리턴 + */ if (time_after_eq(jiffies, oops_timestamp) && !time_after(jiffies, oops_timestamp + 30 * HZ)) return; @@ -1491,6 +1511,12 @@ static int console_trylock_for_printk(void) int printk_delay_msec __read_mostly; +/* IAMROOT-12D (2016-04-09): + * -------------------------- + * boot_delay_msec와 많은 부분 유사하며 차이는 mdelay입니다. + * 하는 일은 printk_delay_msec만큼 딜레이를 합니다. + * 이는 udelay관련 루틴을 호출하며, asm으로 loop를 돌게 됩니다. + */ static inline void printk_delay(void) { if (unlikely(printk_delay_msec)) { @@ -1607,6 +1633,11 @@ static size_t cont_print_text(char *text, size_t size) return textlen; } +/* IAMROOT-12D (2016-04-09): + * -------------------------- + * level = -1 + * fmt = 첫번째 인자, args = 두번째 인자 + */ asmlinkage int vprintk_emit(int facility, int level, const char *dict, size_t dictlen, const char *fmt, va_list args) @@ -1638,6 +1669,11 @@ asmlinkage int vprintk_emit(int facility, int level, /* * Ouch, printk recursed into itself! */ + /* IAMROOT-12D (2016-04-16): + * -------------------------- + * printk 함수가 실행중 crash가 발생하면 printk 함수 crash 메세지를 출력 + * 시도 하는데 이는 재귀 호출이 될수 있다. 이를 방지하기위한 코드이다. + */ if (unlikely(logbuf_cpu == this_cpu)) { /* * If a crash is occurring during printk() on this CPU, @@ -1646,6 +1682,15 @@ asmlinkage int vprintk_emit(int facility, int level, * recursion and return - but flag the recursion so that * it can be printed at the next appropriate moment: */ + /* IAMROOT-12D (2016-04-16): + * -------------------------- + * 데드락이 발생하지않게 하기위해서 return 하고 대신 + * recursion_bug를 셋팅하여 나중에 해당내용을 적절하게 출력하게 + * 할수 있게한다. + * + * 재귀 호출이지만 프로세스가 정상이고 락이 풀려있으면 + * recursion_bug 를 1로 설정하여 나중에 처리하도록 한다. + */ if (!oops_in_progress && !lockdep_recursing(current)) { recursion_bug = 1; local_irq_restore(flags); @@ -1802,6 +1847,12 @@ asmlinkage int printk_emit(int facility, int level, } EXPORT_SYMBOL(printk_emit); +/* IAMROOT-12D (2016-04-09): + * -------------------------- + * 기본적으로 호출되는 printk 함수 + * CONFIG_KGDB_KDB는 정의 되어 있음 + */ + int vprintk_default(const char *fmt, va_list args) { int r; @@ -1853,6 +1904,10 @@ asmlinkage __visible int printk(const char *fmt, ...) va_list args; int r; + /* IAMROOT-12D (2016-04-02): + * -------------------------- + * args에 fmt 다음 인자의 시작 주소(stack)를 구한다. + */ va_start(args, fmt); /* diff --git a/kernel/reboot.c b/kernel/reboot.c index d20c85d9..fac7ce23 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -30,6 +30,10 @@ EXPORT_SYMBOL(cad_pid); #else #define DEFAULT_REBOOT_MODE #endif +/* IAMROOT-12CD (2016-07-02): + * -------------------------- + * 라즈베리파이2에서는 rebootmode 에 REBOOT_COLD 값이들어간다. + */ enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE; /* diff --git a/kernel/time/time.c b/kernel/time/time.c index 2c85b772..14638ba2 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -505,6 +505,13 @@ unsigned long msecs_to_jiffies(const unsigned int m) if ((int)m < 0) return MAX_JIFFY_OFFSET; +/* IAMROOT-12D (2016-04-09): + * -------------------------- + * raspberry pi의 HZ는 100으로 정의됨 + * 즉 아래의 if는 true + * return( m + (1000 / 100) - 1) / (1000 / 100) = 일의자리 올림 / 10 + * ex) 10 = 1, 11~20 = 2, 21~30 = 3 + */ #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) /* * HZ is equal to or smaller than 1000, and 1000 is a nice diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 8523ea34..ff937835 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -359,6 +359,10 @@ check_critical_timing(struct trace_array *tr, __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc); } +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * ip : instruction pointer(아마도..) + */ static inline void start_critical_timing(unsigned long ip, unsigned long parent_ip) { diff --git a/lib/crc32.c b/lib/crc32.c index 9a907d48..7b0a1e42 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -332,6 +332,10 @@ u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) { return crc32_be_generic(crc, p, len, NULL, CRCPOLY_BE); } +/* IAMROOT-12D (2016-05-26): + * -------------------------- + * 라즈베리파이2는 CRC_LE_BITS = 64 + */ #else u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) { diff --git a/lib/crc32defs.h b/lib/crc32defs.h index 64cba2c3..858521b3 100644 --- a/lib/crc32defs.h +++ b/lib/crc32defs.h @@ -14,7 +14,7 @@ #define CRC32C_POLY_LE 0x82F63B78 /* Try to choose an implementation variant via Kconfig */ -#ifdef CONFIG_CRC32_SLICEBY8 +#ifdef CONFIG_CRC32_SLICEBY8 /* IAMROOT-12D: 라즈베리파이 2 */ # define CRC_LE_BITS 64 # define CRC_BE_BITS 64 #endif diff --git a/lib/debug_locks.c b/lib/debug_locks.c index 96c4c633..4b64a205 100644 --- a/lib/debug_locks.c +++ b/lib/debug_locks.c @@ -21,6 +21,15 @@ * that would just muddy the log. So we report the first one and * shut up after that. */ +/* IAMROOT-12D (2016-04-23): + * -------------------------- + * 한번에 모든 debug관련한 lock를 off/on 시키는 전역 변수. + * 1 : 로그 출력(debug_locks 가 걸려있지 않다.) + * 0 : 로그 미출력(debug_locks가 걸려 있다.) + * + * 이 변수를 사용하므로써 첫번째 버그의 로그를 출력시키고 나머지 버그(첫번째 버 + * 그로 유발 될수 있는 버그 포함)는 닥치게 만들 목적이다. + */ int debug_locks = 1; EXPORT_SYMBOL_GPL(debug_locks); @@ -35,6 +44,12 @@ EXPORT_SYMBOL_GPL(debug_locks_silent); /* * Generic 'turn off all lock debugging' function: */ +/* IAMROOT-12D (2016-04-16): + * -------------------------- + * debug_lock을 off(0으로 셋팅)시키고 + * 기존 debug_lock이 설정되어 있고 debug_locks_silent 가 설정 되어 있지 않으면 + * console_loglevel를 verbose로 설정. + */ int debug_locks_off(void) { if (__debug_locks_off()) { diff --git a/lib/debugobjects.c b/lib/debugobjects.c index 547f7f92..707321db 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c @@ -1004,6 +1004,17 @@ static inline void debug_objects_selftest(void) { } * the static object pool objects into the poll list. After this call * the object tracker is fully operational. */ +/* IAMROOT-12D (2016-04-30): + * -------------------------- + * CONFIG_DEBUG_OBJECTS + * description : + * If you say Y here, additional code will be inserted into the + * kernel to track the life time of various objects and validate + * the operations on those objects. + * 번역 : + * 위 feature가 enable 되어 있다면 추가적인 코드가 커널에 삽입되어 + * 다양한 객체들의 life time은 tracking 및 유효성을 체크할 수 있다. + */ void __init debug_objects_early_init(void) { int i; diff --git a/lib/idr.c b/lib/idr.c index 5335c43a..136b83d6 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -835,6 +835,13 @@ void __init idr_init_cache(void) * This function is use to set up the handle (@idp) that you will pass * to the rest of the functions. */ +/* IAMROOT-12D (2016-04-30): + * -------------------------- + * idr이란 radix tree의 일종으로 정수 id와 포인터 주소를 연결해주는 구조체이다. + * + * Radix Tree 란? + * https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Patricia_trie.svg/400px-Patricia_trie.svg.png + */ void idr_init(struct idr *idp) { memset(idp, 0, sizeof(struct idr)); diff --git a/make_tags.sh b/make_tags.sh new file mode 100755 index 00000000..2a1a5b79 --- /dev/null +++ b/make_tags.sh @@ -0,0 +1,11 @@ +#!/bin/bash +if [ "$1" != "emacs" ];then + echo "make tags ARCH=arm" + make tags ARCH=arm +else + echo "make TAGS ARCH=arm" + make TAGS ARCH=arm +fi + +echo "make cscope ARCH=arm" +make cscope ARCH=arm diff --git a/mm/cma.c b/mm/cma.c index 3a7a67b9..4fc1996d 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -39,15 +39,34 @@ #include "cma.h" +/* IAMROOT-12CD (2016-08-17): + * -------------------------- + * MAX_CMA_AREAS=8 + * [0] = {base_pfn = 0x3b800, count = 0x800, order_per_bit = 0x0, ...}, + * cma 영역 0~8M(원래 할당은 5M지만 4M alignment 되어서 8M가 됨) + * + */ struct cma cma_areas[MAX_CMA_AREAS]; +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * cma_area_count = 1 : 0 번째는 cma 영역 (0~8M) + */ unsigned cma_area_count; static DEFINE_MUTEX(cma_mutex); +/* IAMROOT-12CD (2016-08-22): + * -------------------------- + * 페이지 단위로 된 cma base 주소를 메모리 주소로 변환 + */ phys_addr_t cma_get_base(const struct cma *cma) { return PFN_PHYS(cma->base_pfn); } +/* IAMROOT-12CD (2016-08-22): + * -------------------------- + * 페이지 단위로 된 cma size를 메모리 사이즈로 변환 + */ unsigned long cma_get_size(const struct cma *cma) { return cma->count << PAGE_SHIFT; @@ -166,6 +185,10 @@ core_initcall(cma_init_reserved_areas); * * This function creates custom contiguous area from already reserved memory. */ +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * base= 952M, size=8M, order_per_bit= 0, res_cma= &dma_contiguous_default_area + */ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, unsigned int order_per_bit, struct cma **res_cma) @@ -182,6 +205,10 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, if (!size || !memblock_is_region_reserved(base, size)) return -EINVAL; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * alignment = PAGE_SIZE << 10 = 4M + */ /* ensure minimal alignment requied by mm core */ alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); @@ -197,9 +224,23 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, * subsystems (like slab allocator) are available. */ cma = &cma_areas[cma_area_count]; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * base = 952M + * cma->base_pfn = 952M >> 12 = 0x3b800 + * cma->size = 8M >> 12 = 2k(0x800) + * cma->order_per_bit = 0 + * totalcma_pages = 2k(0x800) + */ cma->base_pfn = PFN_DOWN(base); cma->count = size >> PAGE_SHIFT; cma->order_per_bit = order_per_bit; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * res_cma= &dma_contiguous_default_area + * *res_cma = &cma_areas[0]; + * dma_contiguous_default_area = &cma_areas[0] + */ *res_cma = cma; cma_area_count++; totalcma_pages += (size / PAGE_SIZE); @@ -225,11 +266,21 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, * If @fixed is true, reserve contiguous area at exactly @base. If false, * reserve in range from @base to @limit. */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * CMA (Contiguous Memory Allocation) + * base= 0, size= 5M(0x500000), limit= 0xffffffff, alignment= 0, order_per_bit=0 + * fixed= false, res_cms= &dma_contiguous_default_area + */ int __init cma_declare_contiguous(phys_addr_t base, phys_addr_t size, phys_addr_t limit, phys_addr_t alignment, unsigned int order_per_bit, bool fixed, struct cma **res_cma) { + /* IAMROOT-12CD (2016-08-17): + * -------------------------- + * memblock_end = 960M(0x3c000000) + */ phys_addr_t memblock_end = memblock_end_of_DRAM(); phys_addr_t highmem_start; int ret = 0; @@ -244,6 +295,10 @@ int __init cma_declare_contiguous(phys_addr_t base, */ highmem_start = __pa_nodebug(high_memory); #else + /* IAMROOT-12CD (2016-08-17): + * -------------------------- + * highmem_start = __pa(0xbc000000) = 960M(0x3c000000) + */ highmem_start = __pa(high_memory); #endif pr_debug("%s(size %pa, base %pa, limit %pa alignment %pa)\n", @@ -266,9 +321,28 @@ int __init cma_declare_contiguous(phys_addr_t base, * migratetype page by page allocator's buddy algorithm. In the case, * you couldn't get a contiguous memory, which is not what we want. */ + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * alignment = 4M(0x400000) + * base = 0, size=5M + */ alignment = max(alignment, (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order)); + /* IAMROOT-12CD (2016-08-17): + * -------------------------- + * ALIGN(x, a) (x+a-1)&~(a-1) + * ALIGN(0, 4M) = (0+4M-1) & ~(4M-1) = 0x3fffff & 0xffc00000 = 0 + * ALIGN(5M, 4M) = (5M+4M-1) & ~(4M-1) = 0x8fffff & 0xffc00000 = 8M + * + * base = 0 + * size = 0x800000(8M) + * limit = 0xffc00000 + */ base = ALIGN(base, alignment); + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * size = 8M + */ size = ALIGN(size, alignment); limit &= ~(alignment - 1); @@ -283,6 +357,10 @@ int __init cma_declare_contiguous(phys_addr_t base, * If allocating at a fixed base the request region must not cross the * low/high memory boundary. */ + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * fixed 이면서 highmem에 걸쳐 있으면 안된다. + */ if (fixed && base < highmem_start && base + size > highmem_start) { ret = -EINVAL; pr_err("Region at %pa defined on low/high memory boundary (%pa)\n", @@ -296,6 +374,10 @@ int __init cma_declare_contiguous(phys_addr_t base, * checks. */ if (limit == 0 || limit > memblock_end) + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * limit = 0x3c000000(960M) + */ limit = memblock_end; /* Reserve memory */ @@ -314,6 +396,10 @@ int __init cma_declare_contiguous(phys_addr_t base, * try allocating from high memory first and fall back to low * memory in case of failure. */ + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * base = 0, highmem_start = 960M, limit = 960M + */ if (base < highmem_start && limit > highmem_start) { addr = memblock_alloc_range(size, alignment, highmem_start, limit); @@ -321,6 +407,11 @@ int __init cma_declare_contiguous(phys_addr_t base, } if (!addr) { + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * size= 8M, alignment= 4M, base= 0, + * limit: 0x3c000000(960M) + */ addr = memblock_alloc_range(size, alignment, base, limit); if (!addr) { @@ -334,9 +425,18 @@ int __init cma_declare_contiguous(phys_addr_t base, * objects but this address isn't mapped and accessible */ kmemleak_ignore(phys_to_virt(addr)); + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * base = 952M(cma, dma 시작주소) + */ base = addr; } + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * base= 952M, size=8M, order_per_bit= 0, + * res_cma= &dma_contiguous_default_area + */ ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma); if (ret) goto err; diff --git a/mm/init-mm.c b/mm/init-mm.c index a56a8519..5164261d 100644 --- a/mm/init-mm.c +++ b/mm/init-mm.c @@ -15,6 +15,10 @@ struct mm_struct init_mm = { .mm_rb = RB_ROOT, + /* IAMROOT-12D (2016-03-19): + * -------------------------- + * arch/arm/kernel/head.S swapper_pg_dir 참고 : 0x80004000 + */ .pgd = swapper_pg_dir, .mm_users = ATOMIC_INIT(2), .mm_count = ATOMIC_INIT(1), diff --git a/mm/memblock.c b/mm/memblock.c index 9318b567..fc4cc1c3 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -31,11 +31,46 @@ static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIO static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS] __initdata_memblock; #endif +/* IAMROOT-12CD (2016-07-23): + * -------------------------- + * .momory.total_size = 0x3c00 0000 초기값. 약 960M + */ +/* IAMROOT-12CD (2016-08-16): + * -------------------------- + * memblock.reserved { + * cnt = 3, max = 128, total_size = 9795242, + * regions[0] = {base = 0x4000(page table), size = 0x4000, flags = 0x0}, + * regions[1] = {base = 0x8240(_stext), size = 9737564, flags = 0}, + * regions[2] = {base = 0x8000000(fdt), size = 41294, flags = 0}, + * regions[3] = {base = 0, size = 0, flags = 0}, + * ... + */ struct memblock memblock __initdata_memblock = { +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * .memory + * {cnt = 0x1, max = 0x80, total_size = 0x3c000000, regions = { + * [0] = {base = 0x0, size = 0x3c000000, flags = 0x0}, 0 ~ 960M 영역. + * [1] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * }} + */ .memory.regions = memblock_memory_init_regions, .memory.cnt = 1, /* empty dummy entry */ .memory.max = INIT_MEMBLOCK_REGIONS, +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * .reserved + * {cnt = 0x4, max = 0x80, total_size = 18183850, regions = { + * [0] = {base = 0x4000, size = 0x4000, flags = 0x0}, page table + * [1] = {base = 0x8240, size = 9737564, flags = 0x0}, 커널 영역 + * [2] = {base = 0x8000000, size = 41294, flags = 0x0}, fdt 영역 + * [3] = {base = 0x3b800000, size = 0x800000, flags = 0x0}, cma(dma) 952M~960M + * [4] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * } } + */ .reserved.regions = memblock_reserved_init_regions, .reserved.cnt = 1, /* empty dummy entry */ .reserved.max = INIT_MEMBLOCK_REGIONS, @@ -47,6 +82,9 @@ struct memblock memblock __initdata_memblock = { #endif .bottom_up = false, + /* IAMROOT-12CD (2016-08-06): + * current_limit = 0x3c000000(960mb) + */ .current_limit = MEMBLOCK_ALLOC_ANYWHERE, }; @@ -145,6 +183,14 @@ __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, * RETURNS: * Found address on success, 0 on failure. */ +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * start= 4096, end= 960M, size= 8M, align= 4M, nid= -1 + * 예약된 메모리 영역을 제외한 메모리 공간에서 위에서 부터(top_down) 필요한 메 + * 모리 사이즈(size)에 해당 되는 영역의 시작 번지를 가져온다. + * + * 여기서는 8M 사이즈를 원하므로 960M 영역에서 8M사이즈를 뺀 952M를 반한한다. + */ static phys_addr_t __init_memblock __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid) @@ -152,13 +198,49 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, phys_addr_t this_start, this_end, cand; u64 i; +/* IAMROOT-12CD (2016-08-18): + * -------------------------- + * for (i = (u64)ULLONG_MAX, + * __next_mem_range_rev(&i, nid, &memblock.memory, &memblock.reserved, + * &this_start, &this_end, NULL); + * i != (u64)ULLONG_MAX; + * __next_mem_range_rev(&i, nid, &memblock.memory, &memblock.reserved, + * &this_start, &this_end, NULL)) + * + * index:0 + * *this_start = 0x800a14e + * *this_end = 0x3c000000 + * i = 0x20000 0000(idx_b:2, idx_a:0) + */ for_each_free_mem_range_reverse(i, nid, &this_start, &this_end, NULL) { + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * this_start = 0x800a14e + * this_end = 960M(0x3c000000) + * idx = 0x0 | (0x2 << 32) (idx_a = 0, idx_b = 2) + * start= 4096, end= 960M, size= 8M, align= 4M, nid= -1 + * + * clamp(val, lo, hi) --> min(max(val, lo), hi) + * clamp(0x800a14e, 4096, 960M)->min(max(0x800a14e, 4096), 960M) + * min(0x800a14e, 960M) -> 0x800a14e + * this_start= 0x800a14e + * this_end = 960M + */ this_start = clamp(this_start, start, end); this_end = clamp(this_end, start, end); if (this_end < size) continue; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * this_end = 960M, size = 8M, align = 4M + * round_down(952M, 4M) + * cand = round_down(x, y) = x & ~(y-1) + * cand = 952M & ~(4M -1 ) = 952M + * cand = 952M + * this_start= 0x800a14e + */ cand = round_down(this_end - size, align); if (cand >= this_start) return cand; @@ -188,6 +270,11 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, * RETURNS: * Found address on success, 0 on failure. */ +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * size= 8M, align= 4M, start=0, end= 960M, nid= -1 + * return 952M + */ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, int nid) @@ -198,7 +285,16 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, if (end == MEMBLOCK_ALLOC_ACCESSIBLE) end = memblock.current_limit; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * 첫번째 페이지 할당을 피한다. + */ /* avoid allocating the first page */ + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * start = 4096 + * end = 960M + */ start = max_t(phys_addr_t, start, PAGE_SIZE); end = max(start, end); kernel_end = __pa_symbol(_end); @@ -233,6 +329,10 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, "memory hotunplug may be affected\n"); } + /* IAMROOT-12CD (2016-08-18): + * -------------------------- + * start: 4096, end: 0x3c000000, size: 0x800000, align: 0x400000, nid:-1 + */ return __memblock_find_range_top_down(start, end, size, align, nid); } @@ -425,6 +525,19 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, * * Scan @type and merge neighboring compatible regions. */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * (gdb) p/x memblock.reserved + * = {cnt = 0x2, max = 0x80, total_size = 9753948, regions = { + * [0] = {base = 0x4000, size = 0x4000, flags = 0x0}, page table + * [1] = {base = 0x8240, size = 9737564, flags = 0x0}, 커널 영역. + * [2] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * } + * + * 인접한 메모리(this->base + this->size == next->base)영역의 flags값이 동일하면 + * 병합(merge) 한다. + */ static void __init_memblock memblock_merge_regions(struct memblock_type *type) { int i = 0; @@ -462,6 +575,11 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type) * Insert new memblock region [@base,@base+@size) into @type at @idx. * @type must already have extra room to accomodate the new region. */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * type: &memblock.reserved, idx:0, base=0x4000, size=0x4000, nid:1, flags:0 + * page table 영역. + */ static void __init_memblock memblock_insert_region(struct memblock_type *type, int idx, phys_addr_t base, phys_addr_t size, @@ -495,6 +613,29 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type, * RETURNS: * 0 on success, -errno on failure. */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * type: &memblock.reserved, base=0x8240, size=9737564, nid:1, flags:0 + * _stext ~ _end 커널영역. + * type: &memblock.reserved, base=0x4000, size=0x4000, nid:1, flags:0 + * page table 영역. + * type: &memblock.reserved, base=0x8000000, size=41294, nid:1, flags:0 + * fdt 영역. + * + * type: &memblock.reserved, base=0x3b800000(952M), size=8M nid:1, flags:0 + * dma(cma) 영역. + * + * (gdb) p/x memblock.reserved + * = {cnt = 0x4, max = 0x80, total_size = 18183850, regions = { + * [0] = {base = 0x4000, size = 0x4000, flags = 0x0}, page table + * [1] = {base = 0x8240, size = 9737564, flags = 0x0}, 커널 영역 + * [2] = {base = 0x8000000, size = 41294, flags = 0x0}, fdt 영역 + * [3] = {base = 0x3b800000, size = 0x800000, flags = 0x0}, cma(dma) + * [4] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * } + * } + */ int __init_memblock memblock_add_range(struct memblock_type *type, phys_addr_t base, phys_addr_t size, int nid, unsigned long flags) @@ -527,6 +668,14 @@ int __init_memblock memblock_add_range(struct memblock_type *type, nr_new = 0; for (i = 0; i < type->cnt; i++) { + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * [0] = {base = 0x8240, size = 9737564, flags = 0x0},커널 영역 + * rbase = 0x8240 + * rend = 9770908 + * end = 0x8000 + * base = 0x4000 + */ struct memblock_region *rgn = &type->regions[i]; phys_addr_t rbase = rgn->base; phys_addr_t rend = rbase + rgn->size; @@ -550,6 +699,11 @@ int __init_memblock memblock_add_range(struct memblock_type *type, base = min(rend, end); } + /* IAMROOT-12CD (2016-08-20): + * -------------------------- + * end = 0x8000 + * base = 0x4000 + */ /* insert the remaining portion */ if (base < end) { nr_new++; @@ -592,6 +746,10 @@ static int __init_memblock memblock_add_region(phys_addr_t base, (unsigned long long)base + size - 1, flags, (void *)_RET_IP_); + /* IAMROOT-12CD (2016-07-02): + * -------------------------- + * memblock_add_range(_rgn, base, size, 1, 0); + */ return memblock_add_range(_rgn, base, size, nid, flags); } @@ -708,6 +866,13 @@ int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size) return memblock_remove_range(&memblock.reserved, base, size); } +/* IAMROOT-12CD (2016-08-16): + * -------------------------- + * base=0x8240, size=9737564, nid:1, flags:0 커널 _stext ~ _end영역.. + * base=0x4000, size=0x4000, nid:1, flags:0 page table 영역. + * base=0x8000000, size=41294, nid:1, flags:0 fdt 영역. + * base=0x3b800000(952M), size=8M nid:1, flags:0 dma(cma) 영역. + */ static int __init_memblock memblock_reserve_region(phys_addr_t base, phys_addr_t size, int nid, @@ -723,6 +888,13 @@ static int __init_memblock memblock_reserve_region(phys_addr_t base, return memblock_add_range(type, base, size, nid, flags); } +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * base=0x8240, size=9737564 커널 _stext ~ _end영역.. + * base=0x4000, size=0x4000 page table 영역. + * base=0x8000000, size=41294 fdt 영역. + * base=0x3b800000(952M), size=8M dma(cma) 영역. + */ int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) { return memblock_reserve_region(base, size, MAX_NUMNODES, 0); @@ -903,31 +1075,84 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, * * Reverse of __next_mem_range(). */ +/* IAMROOT-12CD (2016-08-18): + * -------------------------- + * type_b에서 부적합으로 표시되지않은 범위를 type_a에서 찾습니다. + * + * idx: ULLONG_MAX, nid: 0, type_a: &memblock.memory, type_b: &memblock.reserved + * out_start: OUT, out_end: OUT, out_nid: OUT + * + * (gdb) p/x memblock.reserved + * = {cnt = 0x3, max = 0x80, total_size = 0x9576aa, regions = { + * [0] = {base = 0x4000, size = 0x4000, flags = 0x0}, + * [1] = {base = 0x8240, size = 0x94955c, flags = 0x0}, + * [2] = {base = 0x8000000, size = 0xa14e, flags = 0x0}, + * } + * (gdb) p/x memblock.memory + * = {cnt = 0x1, max = 0x80, total_size = 0x3c000000, regions = { + * [0] = {base = 0x0, size = 0x3c000000, flags = 0x0} + * } + * + * OUT: + * (gdb) p/x *out_start = 0x800a14e + * (gdb) p/x *out_end = 0x3c000000 + * (gdb) p/x *idx = 0x20000 0000(idx_b:2, idx_a:0) + */ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid) { + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * idx_a = idx_b = 0xffffffff + */ int idx_a = *idx & 0xffffffff; int idx_b = *idx >> 32; if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) nid = NUMA_NO_NODE; + /* IAMROOT-12CD (2016-08-18): + * -------------------------- + * *idx: ULLONG_MAX + */ if (*idx == (u64)ULLONG_MAX) { + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * idx_a = 0, idx_b = 3 + */ idx_a = type_a->cnt - 1; idx_b = type_b->cnt; } for (; idx_a >= 0; idx_a--) { + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * idx_a = 0 + * m = memblock.memory.regions[0] + * {cnt = 0x1, max = 0x80, total_size = 0x3c000000, regions = { + * [0] = {base = 0x0, size = 0x3c000000, flags = 0x0}, 0 ~ 960M 영역. + * [1] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * }} + */ struct memblock_region *m = &type_a->regions[idx_a]; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * m_start = 0, m_end = 960M, m_nid = 0 + */ phys_addr_t m_start = m->base; phys_addr_t m_end = m->base + m->size; int m_nid = memblock_get_region_node(m); /* only memory regions are associated with nodes, check it */ + /* IAMROOT-12CD (2016-08-18): + * -------------------------- + * nid == 0, m_nid = 0 + */ if (nid != NUMA_NO_NODE && nid != m_nid) continue; @@ -947,13 +1172,44 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, return; } + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * idx_b = 3 + */ /* scan areas before each reservation */ + /* IAMROOT-12CD (2016-08-18): + * -------------------------- + * idx_b: 3 + */ for (; idx_b >= 0; idx_b--) { struct memblock_region *r; phys_addr_t r_start; phys_addr_t r_end; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * type_b = memblock.reserved = + * {cnt = 0x3, max = 0x80, total_size = 9795242, regions = { + * [0] = {base = 0x4000, size = 0x4000, flags = 0x0}, page table + * [1] = {base = 0x8240, size = 9737564, flags = 0x0}, 커널 영역 + * [2] = {base = 0x8000000, size = 41294, flags = 0x0}, fdt 영역 + * [3] = {base = 0x0, size = 0x0, flags = 0x0}, + * ... + * } } + * + * idx_b = 3 + * r_start = 0x800a14e, r_end = ULLONG_MAX + */ r = &type_b->regions[idx_b]; + /* IAMROOT-12CD (2016-08-18): + * -------------------------- + * ibx_b = 3 + * (gdb) p/x memblock.reserved.regions[2] + * = {base = 0x8000000, size = 0xa14e, flags = 0x0} + * (gdb) p/x 0x8000000 + 0xa14e = 0x800a14e + * r_start = 0x800a14e + * r_end = ULLONG_MAX + */ r_start = idx_b ? r[-1].base + r[-1].size : 0; r_end = idx_b < type_b->cnt ? r->base : ULLONG_MAX; @@ -962,9 +1218,19 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, * break out to advance idx_a */ + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * m_start = 0, m_end = 960M(0x3c000000), m_nid = 0 + * r_start = 0x800a14e, r_end = ULLONG_MAX + */ if (r_end <= m_start) break; /* if the two regions intersect, we're done */ + /* IAMROOT-12CD (2016-08-18): + * -------------------------- + * m_end: 0x3c000000, r_start: 0x800a14e + * m_start: 0x0, r_end = ULLONG_MAX + */ if (m_end > r_start) { if (out_start) *out_start = max(m_start, r_start); @@ -977,6 +1243,14 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, else idx_b--; *idx = (u32)idx_a | (u64)idx_b << 32; + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * *out_start = r_start = 0x800a14e + * *out_end = m_end = 960M(0x3c000000) + * out_nid = NULL + * idx_a = 0, idx_b = 2 + * *idx = 0x0 | (0x2 << 32) + */ return; } } @@ -1048,6 +1322,10 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, } #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ +/* IAMROOT-12CD (2016-08-27): + * -------------------------- + * size= 8M, align= 4M, start=0, end= 960M, nid= -1 + */ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, int nid) @@ -1059,6 +1337,11 @@ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, found = memblock_find_in_range_node(size, align, start, end, nid); if (found && !memblock_reserve(found, size)) { + /* IAMROOT-12CD (2016-08-18): + * -------------------------- + * found: 0x3b800000, size: 0x800000 + * __va(0x3b00000) -> 0xbb800000 + */ /* * The min_count is set to 0 so that memblock allocations are * never reported as leaks. @@ -1072,6 +1355,10 @@ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end) { + /* IAMROOT-12CD (2016-08-27): + * -------------------------- + * size= 8M, align= 4M, start=0, end= 960M, NUM_NO_NODE= -1 + */ return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE); } @@ -1348,11 +1635,19 @@ phys_addr_t __init memblock_mem_size(unsigned long limit_pfn) } /* lowest address */ +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * 라즈베리파이2의 경우 0 반환 + */ phys_addr_t __init_memblock memblock_start_of_DRAM(void) { return memblock.memory.regions[0].base; } +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * 라즈베리파이2의 경우 0x3c000000(960M) 반환 + */ phys_addr_t __init_memblock memblock_end_of_DRAM(void) { int idx = memblock.memory.cnt - 1; diff --git a/mm/memory.c b/mm/memory.c index 2a9e0987..2e00f37a 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -91,6 +91,10 @@ EXPORT_SYMBOL(mem_map); * highstart_pfn must be the same; there must be no gap between ZONE_NORMAL * and ZONE_HIGHMEM. */ +/* IAMROOT-12CD (2016-08-06): + * -------------------------- + * high_memory = 0xBC000000 (0x3c000000 960mb의 virtual address) + */ void * high_memory; EXPORT_SYMBOL(high_memory); diff --git a/mm/mmap.c b/mm/mmap.c index bb50cacc..827fd52a 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -76,6 +76,34 @@ static void unmap_region(struct mm_struct *mm, * x: (no) no x: (no) yes x: (no) yes x: (yes) yes * */ +/* IAMROOT-12CD (2016-08-23): + * -------------------------- + * 현재 구현에 매핑 유형과 보호의 효과에 대한 설명입니다. 이것은 제한된 86 + * 페이지 보호 하드웨어에 기인한다. 예상되는 동작은 괄호에있다 : + * { 0xa83, 0x383, 0x383, 0x383, 0x183, 0x183, 0x183, 0x183, + * 0xa83, 0x383, 0x303, 0x303, 0x183, 0x183, 0x103, 0x103} + * + * #define __P000 __PAGE_NONE + * #define __P001 __PAGE_READONLY + * #define __P010 __PAGE_COPY + * #define __P011 __PAGE_COPY + * #define __P100 __PAGE_READONLY_EXEC + * #define __P101 __PAGE_READONLY_EXEC + * #define __P110 __PAGE_COPY_EXEC + * #define __P111 __PAGE_COPY_EXEC + * + * #define __S000 __PAGE_NONE + * #define __S001 __PAGE_READONLY + * #define __S010 __PAGE_SHARED + * #define __S011 __PAGE_SHARED + * #define __S100 __PAGE_READONLY_EXEC + * #define __S101 __PAGE_READONLY_EXEC + * #define __S110 __PAGE_SHARED_EXEC + * #define __S111 __PAGE_SHARED_EXEC + * + * for (i = 0; i < 16; i++) + * protection_map[i] |= (L_PTE_MT_WRITEALLOC | L_PTE_SHARED) + */ pgprot_t protection_map[16] = { __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ebffa0e4..fcc5e5a8 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -112,6 +112,10 @@ static DEFINE_SPINLOCK(managed_page_count_lock); unsigned long totalram_pages __read_mostly; unsigned long totalreserve_pages __read_mostly; +/* IAMROOT-12CD (2016-08-22): + * -------------------------- + * totalcma_pages 0 -> 0x800(page단위 8M)로 변경. + */ unsigned long totalcma_pages __read_mostly; /* * When calculating the number of globally allowed dirty pages, there diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index e56833ae..fc3832f6 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -55,8 +55,14 @@ #include "libfdt_internal.h" +//MAGIC값과 VERSION을 체크해서 문제가 있을 시 음수값을 리턴함. int fdt_check_header(const void *fdt) { + /* FDT_MAGIC 0xd00dfeed + fdt_magic(fdt) 설명: + struct fdt_header * pf = fdt; + return pf->magic; + */ if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) @@ -78,11 +84,32 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { const char *p; + /* 0x11 = 17, Default version */ if (fdt_version(fdt) >= 0x11) + /* 1. offset의 overflow체크? len은 unsigned int임. + * 2. offset+len은 size_dt_struct보다 작거나 같아야만 한다. + * + * ex) dt_struct + * +-------------+ + + * | | | + * | something | | dt_struct_size + * | | | + * +-------------+ <-- dt_struct_offset + + * + * _fdt_offset_ptr 내부에서 dt_struct_offset + offset을 한다. + * 따라서, offset + len 이 dt_struct_size 보다 크면 안된다. + * + * 아래 if를 거꾸로 쓰면, + * offset < offset + len < fdt_size_dt_struct(fdt) + * + * len이 unsigned!!! 절대 음수가 들어올 수 없음. + * 따라서 오버플로우 방어코드라고 추정.. + */ if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; + /* offset은 Valid 검증된 이후 */ p = _fdt_offset_ptr(fdt, offset); if (p + len < p) @@ -90,6 +117,16 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) return p; } +/* + * 다음 tag의 Offset를 찾는다.(nextoffset갱신) + * in startoffset 현재 시작 offset + * out nextoffset 다음 시작 offset + * return FDT_END 에러 혹은 현재의 tag값 + * tag 구분값 + * define FDT_BEGIN_NODE 0x1 + * #define FDT_END_NODE 0x2 + * #define FDT_PROP 0x3 + */ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const uint32_t *tagp, *lenp; @@ -98,6 +135,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) const char *p; *nextoffset = -FDT_ERR_TRUNCATED; + /* FDT_TAGSIZE: sizeof(uint32_t) word사이즈 */ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); if (!tagp) return FDT_END; /* premature end */ @@ -106,8 +144,21 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) *nextoffset = -FDT_ERR_BADSTRUCTURE; switch (tag) { + /* + #define FDT_BEGIN_NODE 0x1 + #define FDT_END_NODE 0x2 + #define FDT_PROP 0x3 + + [2015-11-07 여기까지 함] + */ case FDT_BEGIN_NODE: /* skip name */ + /* + struct fdt_node_header { + uint32_t tag; + char name[0]; + }; + */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); @@ -116,10 +167,21 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) break; case FDT_PROP: + /* + struct fdt_property { + uint32_t tag; + uint32_t len; + uint32_t nameoff; + char data[0]; + }; + */ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (!lenp) return FDT_END; /* premature end */ /* skip-name offset, length and value */ + /* offset += 12 - 4 + (*lenp) + sizeof(struct fdt_property) 는 12이다. + */ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + fdt32_to_cpu(*lenp); break; @@ -133,13 +195,28 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) return FDT_END; } + // offset값 범위체크 if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) return FDT_END; /* premature end */ - + /* + 4 byte align을 맞추기위해 + #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + + ex) FDT_TAGALIGN(10) + FDT_ALIGN(10, 4) + ((10 + 4 - 1) & ~(4 - 1)) = 12 + (13 & ~3) = 0b1101 & ~0b0011 = 0b1100 = 12 + */ *nextoffset = FDT_TAGALIGN(offset); return tag; } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * 1. offset 이 valid 한 range에 있는지 check + */ int _fdt_check_node_offset(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) @@ -158,15 +235,34 @@ int _fdt_check_prop_offset(const void *fdt, int offset) return offset; } +/* + * offset을 기준으로 다음 노드를 가져옴 + * 현재 탐색중인 node의 depth를 저장 +*/ int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; uint32_t tag; + // "chosen" 맨 처음에는 offset는 0 if (offset >= 0) + /* + * offset의 유효성 체크 + * 참고:http://iamroot.org/wiki/lib/exe/fetch.php?media=%EC%8A%A4%ED%84%B0%EB%94%94:dtb_structure.png + */ if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) return nextoffset; + /* + * FDT_BEGIN_NODE + * - 현재 노드의 tag값을 찾는데 만약에 새로운 노드가 시작되면 depth++ + * FDT_END_NODE + * - 탐색중인 노드가 끝난 경우 depth를 -- + * depth를 감소했을때 음수가 아닌경우 + * - childNode가 더이상 없는 경우 nextoffset(0) 리턴 + + * childNode안에 또 childNode가 있을수 있으니 depth로 판별? + */ do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); @@ -197,7 +293,12 @@ int fdt_next_node(const void *fdt, int offset, int *depth) return offset; } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * strtab ~ tabsize 구간에서 s 문자열의 위치를 찾아서 return + */ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) { int len = strlen(s) + 1; @@ -210,6 +311,13 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) return NULL; } +/* + * buf에 fdt를 복사. + * in fdt fdt + * out buf fdt + * return 0 : 성공 + * -FDT_ERR_NOSPACE : 실패 + */ int fdt_move(const void *fdt, void *buf, int bufsize) { FDT_CHECK_HEADER(fdt); diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h index 48ccfd91..891cbff5 100644 --- a/scripts/dtc/libfdt/fdt.h +++ b/scripts/dtc/libfdt/fdt.h @@ -3,6 +3,7 @@ #ifndef __ASSEMBLY__ +// sizeof(fdt_header)는 40byte struct fdt_header { uint32_t magic; /* magic word FDT_MAGIC */ uint32_t totalsize; /* total size of DT block */ diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 02b6d687..cb456fa6 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -58,6 +58,15 @@ static int _fdt_nodename_eq(const void *fdt, int offset, const char *s, int len) { + /* + * struct fdt_node_header { + * uint32_t tag; + * char name[0]; + * }; + + * fdt_node_header의 name을 가져옴 + * (len+1)만큼 가져오는 것은 밑에서 '@'을 체크하기 위해? + */ const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); if (! p) @@ -80,6 +89,11 @@ const char *fdt_string(const void *fdt, int stroffset) return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; } +/* + * stroffset: property name offset + * s: 찾고자하는 propert의 이름 + * 찾고자 하는 property가 맞는지 propert명 체크 +*/ static int _fdt_string_eq(const void *fdt, int stroffset, const char *s, int len) { @@ -88,6 +102,10 @@ static int _fdt_string_eq(const void *fdt, int stroffset, return (strlen(p) == len) && (memcmp(p, s, len) == 0); } +/* IAMROOT-12CD (2016-08-20): + * -------------------------- + * 라즈베리파이2에서는 _fdt_mem_rsv 영역에 아무런 값이 없다. + */ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); @@ -96,39 +114,74 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) return 0; } +/* memory reserve map의 개수를 구한다.*/ int fdt_num_mem_rsv(const void *fdt) { int i = 0; + /* size가 0이 아니면 reserve map이 있다고 판단한다. */ while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) i++; return i; } +/* + * 다음 property를 찾아서 해당 offset을 리턴 +*/ static int _nextprop(const void *fdt, int offset) { uint32_t tag; int nextoffset; do { + /* + * offset: property의 offset + * nextoffset: property offset의 다음 offset + */ tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: + /* + * 이미 FDT_END인데 nextoffset이 있다면 에러 + * (FDT_END인데 다음 offset이 있다가 말이 안됨) + * nextoffset<0 라면 에러값이 들어가 있음 + */ if (nextoffset >= 0) return -FDT_ERR_BADSTRUCTURE; else return nextoffset; + // property라면 해당 offset 리턴 case FDT_PROP: return offset; } + // property를 찾을때까지 다음 offset으로 이동 offset = nextoffset; } while (tag == FDT_NOP); return -FDT_ERR_NOTFOUND; } +/* + * fdt에서 offset를 기준으로 하위 노드를 탐색 + * (참고로 꼭 root가 아닐수 있음 즉, offset는 상대적인 위치임) + + * 참고: http://iamroot.org/wiki/lib/exe/fetch.php?media=%EC%8A%A4%ED%84%B0%EB%94%94:dtb_structure.png + * +------+-------------------------+ + * | Node | FDT_BEGIN_NODE | + * | +-------------------------+ + * | | Node Name | + * | +----------+--------------+ + * | | Property | FDT_PROP | + * | | +--------------+ + * | | | Value Length | + * | | +--------------+ + * | | | Name Offset | + * | | +--------------+ + * | | | Value | + * +------+----------+--------------+ +*/ int fdt_subnode_offset_namelen(const void *fdt, int offset, const char *name, int namelen) { @@ -136,13 +189,22 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, FDT_CHECK_HEADER(fdt); + /* + * root부터 시작해서(depth=0) node를 탐색 + * 현재 탐색중인 node의 depth를 받아와서 + */ for (depth = 0; (offset >= 0) && (depth >= 0); offset = fdt_next_node(fdt, offset, &depth)) + /* + * root 입장으로 봤을때 depth가 1인 node들 중에서 + * 찾고자 하는 node가 맞다면 node offset을 리턴 + */ if ((depth == 1) && _fdt_nodename_eq(fdt, offset, name, namelen)) return offset; + // 탐색했더니 찾고자 하는 node가 없는 상황 if (depth < 0) return -FDT_ERR_NOTFOUND; return offset; /* error */ @@ -154,8 +216,19 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); } +/* + * chosen { + * bootargs = "console=ttyS0,115200 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs"; + * }; + + * 호출: int offset = fdt_path_offset(fdt, "/chosen"); +*/ int fdt_path_offset(const void *fdt, const char *path) { + /* + * p : "chosen"의 시작 주소 + * end : "chosen"의 끝 주소 + */ const char *end = path + strlen(path); const char *p = path; int offset = 0; @@ -164,12 +237,20 @@ int fdt_path_offset(const void *fdt, const char *path) /* see if we have an alias */ if (*path != '/') { + // path가 '/'로 시작하지 않으면 path내에서 '/' 위치 찾음 const char *q = strchr(path, '/'); + // path내에 '/'가 없으면 끝 주소로 지정 if (!q) q = end; + /* + * '/'로 시작하지 않았다면 alias라고 가정하고 원래 node명 탐색 + * p: alias명 + * q-p: alias 길이 + */ p = fdt_get_alias_namelen(fdt, p, q - p); + // alias도 아닌경우 에러 리턴 if (!p) return -FDT_ERR_BADPATH; offset = fdt_path_offset(fdt, p); @@ -177,17 +258,27 @@ int fdt_path_offset(const void *fdt, const char *path) p = q; } + /* + * "chosen"의 alias가 없으면 여기서 탐색 + * 여기서는 node의 이름이 "chosen"인지 아닌지 탐색 + */ while (*p) { const char *q; + // path내에서 '/'가 아닌곳까지 이동 while (*p == '/') p++; + // path 끝까지 이동한 경우 if (! *p) return offset; + // p를 기준으로 다음 '/' 위치까지 찾아서 q = strchr(p, '/'); + // 다음 '/'가 없다면 path의 끝으로 지정 if (! q) q = end; - + + // path에서 '/'로 split 해보면서 + // 하위 node들중 해당 이름의 node가 있는지 탐색 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); if (offset < 0) return offset; @@ -218,16 +309,23 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) return NULL; } +/* + * 첫번째 property의 offset을 가져온다. +*/ int fdt_first_property_offset(const void *fdt, int nodeoffset) { int offset; + // node 유효성 체크 if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) return offset; return _nextprop(fdt, offset); } +/* + * 그 다음 property의 offset을 가져온다. +*/ int fdt_next_property_offset(const void *fdt, int offset) { if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) @@ -236,6 +334,11 @@ int fdt_next_property_offset(const void *fdt, int offset) return _nextprop(fdt, offset); } +/* + * offset: propert의 offset + * lenp: propert내의 value 길이 저장 + * offset을 이용하여 property에 접근 및 property 구조체와, value 길이를 받아옴 +*/ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp) @@ -243,41 +346,73 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int err; const struct fdt_property *prop; + // property의 유효성을 체크 if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { if (lenp) *lenp = err; return NULL; } + // property 구조체를 가져옴 prop = _fdt_offset_ptr(fdt, offset); + // property의 value의 길이 저장 if (lenp) *lenp = fdt32_to_cpu(prop->len); return prop; } +/* + * chosen { + * bootargs="console=ttyS0,115200 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs"; + * }; + + * offset: node "/chosen"의 offset + * name: property "bootargs" + * namelen: property "bootargs" 길이 + * lenp: property 내용의 길이 +*/ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int offset, const char *name, int namelen, int *lenp) { + /* + * node안의 property들을 순회하면서 찾고자 하는 name의 property 리턴 + * 참고로 아래 for문에서 offset을 계속 받아오면서 값을 체크하고 있음 + * 즉, 순회하면서 찾는 property가 없거나 탐색시 에러가 나면 탐색 중단 + */ for (offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; + /* + * offset만큼 위치한 property에 접근해서 + * lenp에 property의 value의 길이를 저장 + * 하지만 에러가 나는 경우엔 for문을 빠져나감 + */ if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { offset = -FDT_ERR_INTERNAL; break; } + /* + * 찾고자 하는 property가 맞는지 확인하고 + * 맞다면 가져온 property 구조체를 리턴 + */ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) return prop; } + /* + * 찾는 property가 없는경우 or property 접근하다 에러가 난 경우 + * lenp에 에러값 저장 + */ if (lenp) *lenp = offset; + return NULL; } @@ -289,15 +424,24 @@ const struct fdt_property *fdt_get_property(const void *fdt, strlen(name), lenp); } +/* + * nodeoffset: 탐색 대상이되는 node의 offset + * name: 찾을 property 이름 + * namelen: 찾을 property 이름 길이 + * lenp: property value 길이 +*/ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp) { const struct fdt_property *prop; + // 찾고자 하는 property가 있는지 확인하고 property의 구조체를 가져옴 prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); + // 가져온 property 구조체가 없다면 NULL 리턴 if (! prop) return NULL; + // 가져온 property 구조체가 있다면 value을 리턴 return prop->data; } @@ -314,6 +458,11 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, return prop->data; } +/* + * nodeoffset: 탐색 대상이 되는 node의 offset + * name: 찾고자 하는 property 이름 + * lenp: 찾고자 하는 property의 value 길이 +*/ const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp) { @@ -337,15 +486,25 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return fdt32_to_cpu(*php); } +/* + * name: alias + * namelen: alias 길이 +*/ const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen) { int aliasoffset; + // aliases에 정의된 alias가 있는지 찾아보고 alias offset을 가져옴 aliasoffset = fdt_path_offset(fdt, "/aliases"); + // alias offset이 에러값이라면 NULL 리턴 if (aliasoffset < 0) return NULL; + /* + * alias offset이 유효하다면 + * alias에 해당하는 property의 value를 가져옴 + */ return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); } diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 24437dfc..1bf85541 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -55,9 +55,36 @@ #include "libfdt_internal.h" +/* + * fdt 블럭의 순서들이 올바른지 체크한다. + * + * return 0 : 올바르다 + * 0이 아님 : 옳지 않다 + */ static int _fdt_blocks_misordered(const void *fdt, int mem_rsv_size, int struct_size) { + /** + * FDT 순서는 아래와 같다. + * 아래의 영역들은 인접한 영역이다. + * +--------------------+ <-- fdt + * | fdt_header(40byte) | + * +--------------------+ + * | mem_rsvmap | + * | ... | + * +--------------------+ + * | dt_struct | + * | ... | + * +--------------------+ + * | dt_strings | + * | ... | + * +--------------------+ <-- total_size + * + * 1. off_mem_rsvmap 은 fdt_header size보다 커야 된다. + * 2. dt_struct 는 mem_rsvmap 뒤에 있어야 한다. + * 3. dt_strings 는 dt_struct 보다 뒤에 있어야 한다. + * 4. totalsize는 dt_strings 보다 뒤에 있어야한다. + */ return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) || (fdt_off_dt_struct(fdt) < (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) @@ -66,16 +93,29 @@ static int _fdt_blocks_misordered(const void *fdt, || (fdt_totalsize(fdt) < (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * + * Description :1.fdt 의 version, magic 값 검사 + * 2.fdt->version 이 17보다작으면 에러, 17보다 크면 17로 세팅 + * 3.fdt struct 구조체에 맞는지 체크 + */ static int _fdt_rw_check_header(void *fdt) { + // fdt 의 magic 과 version 을 check FDT_CHECK_HEADER(fdt); + // fdt->version return. default fdt 버전은 17 if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; + // fdt 가 fdt 구조체 순서에 맞게 되어 있는지 check if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), fdt_size_dt_struct(fdt))) return -FDT_ERR_BADLAYOUT; + + // fdt->version 이 17보다 큰 값이면 17로 세팅 if (fdt_version(fdt) > 17) fdt_set_version(fdt, 17); @@ -91,18 +131,47 @@ static int _fdt_rw_check_header(void *fdt) static inline int _fdt_data_size(void *fdt) { + /* + * fdt_off_dt_strings : fdt 구조체의 off_dt_strings 필드 주소 리턴함 + * fdt_size_dt_strings : fdt 구조체의 size_dt_strings 필드 주소 리턴함 + * dtstring 필드의 끝 위치를 리턴 + */ return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * 1. splicepoint 유효성 check + * 2. splicepoint 의 길이가 변경되므로, + * splicepoint 뒤의 필드들의 위치를 재조정 + */ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) { char *p = splicepoint; char *end = (char *)fdt + _fdt_data_size(fdt); + /* property *p 의 유효성 check */ if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; + /* 새로 갱신되는 길이가 전체 fdt size보다 크면 에러 */ if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; + /* + * before memmove => + * slicepoint next tag + * +------------+---------------------+ + * | abc | cpus{cpu0, 1...} | + * +------------+---------------------+ + * p+oldlen end + * after memmove => + * +----------------+---------------------+ + * | abc def | cpus{cpu0, 1...} | + * +----------------+-----------------^---+ + * p+newlen end(end 위치는 동일) + * delta 만큼 shift + */ + // memmove(p + newlen, p + oldlen, end - (p + oldlen) ); memmove(p + newlen, p + oldlen, end - p - oldlen); return 0; } @@ -119,7 +188,13 @@ static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * 1. _fdt_splice : p 뒤의 필드 재조정 + * 2. fdt의 size_dt_struct 와 off_dt_strings 값 갱신 + */ static int _fdt_splice_struct(void *fdt, void *p, int oldlen, int newlen) { @@ -129,11 +204,30 @@ static int _fdt_splice_struct(void *fdt, void *p, if ((err = _fdt_splice(fdt, p, oldlen, newlen))) return err; + /* + * fdt_set_size_dt_struct : fdt의 size_dt_struct 값 갱신 + * fdt_set_off_dt_strings : fdt의 off_dt_strings 값 갱신 + */ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * fdt 현재 구조 => + * +--------------------------------------------------------+ + * | FDT header | reserved | dt struct | dtstrings | buffer | + * +--------------------------------------------------------+ + * + * fdt_splice_string 수행 후 => + * +--------------------------------------------------------+ + * | FDT header | reserved | dt struct | dtstrings | buffer | + * +------------------------------------------------^-------+ + * | + * 새로운 dt string 필드 추가 됨 + */ static int _fdt_splice_string(void *fdt, int newlen) { void *p = (char *)fdt @@ -146,7 +240,16 @@ static int _fdt_splice_string(void *fdt, int newlen) fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); return 0; } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * 1. fdt에서 dtsting 에서 S 문자열의 시작위치 offset을 리턴함 + * 2. fdt에서 s 문자열이 존재하지 않을 경우 + * a. dtstrings 맨 뒤에 s 문자열 추가를 위해 공간 확보 + * b. s 문자열을 추가된 공간에 복사한다 + * c. dtsrings 에서 s 문자열의 시작위치 offset을 리턴함 + */ static int _fdt_find_add_string(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); @@ -155,6 +258,9 @@ static int _fdt_find_add_string(void *fdt, const char *s) int len = strlen(s) + 1; int err; + /* strtab ~ fdt_sisze_dt_strings(fdt) 범위 안에서 + * s 문자열을 찾아서 문자열의 시작 주소를 리턴함 + */ p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); if (p) /* found it */ @@ -202,16 +308,40 @@ int fdt_del_mem_rsv(void *fdt, int n) return 0; } +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * setprop_string(fdt, "/chosen", "bootargs", cmdline); 함수에서 + * 호출했다는 전제로 분석 + * fdt : device tree pointer, + * nodeoffset : "/chosen" node offset, + * name : "bootargs" property, + * len : 새로 갱신될 bootargs 속성의 길이, + * prop : fdt_property pointer 변수 + * 1. *prop = bootargs 속성 값을 얻어 온다. + * oldlen = bootargs 속성 값의 길이 + * 2. prop->data 길이가 변경 되므로, prop 뒤의 필드들이 + * 변경된 prop->data 뒤에 오도록 재조정 + */ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { int oldlen; int err; + /* + * prop = bootargs, oldlen = bootargs의 value 길이 + */ *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (! (*prop)) + // bootargs를 못 찾으면 error를 return return oldlen; + // + // (*prop)->data : property의 value + // FDT_TAGALIGN(oldlen) : 현재 property의 길이 + // FDT_TAGALIGN(len) : update 할 property의 길이 if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), FDT_TAGALIGN(len)))) return err; @@ -219,7 +349,13 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, (*prop)->len = cpu_to_fdt32(len); return 0; } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * 1. offset 유효성 check 하고 nextoffset에 다음 tag의 offset값 할당 + * 2. name 필드의 offset값을 찾아서 namestroff값 할당 + */ static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { @@ -231,17 +367,30 @@ static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) return nextoffset; + /* + * name 문자열을 dtstrings 에서 찾고 없으면 추가한다. + * 반환값은 dtstrings 시작 위치에서 문자열이 시작되는 위치의 offset + */ namestroff = _fdt_find_add_string(fdt, name); if (namestroff < 0) return namestroff; + /* + * dt_struct 에서 해당 property 주소를 찾는다. + */ *prop = _fdt_offset_ptr_w(fdt, nextoffset); proplen = sizeof(**prop) + FDT_TAGALIGN(len); + /* + * dt_struct 에서 prop를 추가할 공간을 확보한다. + */ err = _fdt_splice_struct(fdt, *prop, 0, proplen); if (err) return err; + /* + * prop member 갱신함 + */ (*prop)->tag = cpu_to_fdt32(FDT_PROP); (*prop)->nameoff = cpu_to_fdt32(namestroff); (*prop)->len = cpu_to_fdt32(len); @@ -270,7 +419,19 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) memcpy(namep, name, newlen+1); return 0; } - +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * nodeoffset : "/chosen" node 의 offset + * name : "bootargs" property name + * val : bootargs property 값과 인자로 넘어온 atags cmdline이 합쳐진 string + * len : strlen(val) + * 1. FDT_RW_CHECK_HEADER : fdt 의 유효성 check + * 2. _fdt_resize_property : prop 를 갱신해야 되기에 dt_strings size 재조정 및 + * 갱신하려는 prop 뒤의 property를 shift + * 3. memcpy : val를 지정된 prop->data에 저장 + */ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len) { @@ -285,6 +446,9 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, if (err) return err; + /* + * property 에 새로운 val 값으로 memcpy + */ memcpy(prop->data, val, len); return 0; } @@ -343,12 +507,36 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, FDT_RW_CHECK_HEADER(fdt); + /* 여기서는 추가하는 중이기때문에 서브노드에 추가할 같은 이름이 있어서는 + 안된다. 따라서 아래 함수의 결과는 에러값(NOT_FOUND)가 나올것이다. */ offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) return -FDT_ERR_EXISTS; else if (offset != -FDT_ERR_NOTFOUND) return offset; + /* + * +------+-------------------------+ + * | Node | FDT_BEGIN_NODE | + * | +-------------------------+ + * | | Node Name | + * | +----------+--------------+ + * | | Property | FDT_PROP | + * | | +--------------+ + * | | | Value Length | + * | | +--------------+ + * | | | Name Offset | + * | | +--------------+ + * | | | Value | + * +------+----------+--------------+ + * | Sub | FDT_BEGIN_NODE | << 이렇게 추가(서브노드) + * | Node | | + * | +-------------------------+ + * | | ... | + * + * 다음 노드를 가르키게 한다. + * 즉, 첫번째 서브노드로 add 하겠다는 의미가 된다. + */ /* Try to place the new node after the parent's properties */ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ do { @@ -356,6 +544,9 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, tag = fdt_next_tag(fdt, offset, &nextoffset); } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + /* fdt_node_header *nh + nodelen을 계산한다. + */ nh = _fdt_offset_ptr_w(fdt, offset); nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; @@ -391,15 +582,35 @@ int fdt_del_node(void *fdt, int nodeoffset) endoffset - nodeoffset, 0); } +/* + * in old 순서가 맞지 않은 fdt + * out new 순서를 맞춘 fdt + */ static void _fdt_packblocks(const char *old, char *new, int mem_rsv_size, int struct_size) { + /** + * FDT 순서는 아래와 같다. + * +--------------------+ <-- fdt + * | fdt_header(40byte) | + * +--------------------+ <-- mem_rsv_off + * | mem_rsvmap | + * | ... | + * +--------------------+ <-- struct_off + * | dt_struct | + * | ... | + * +--------------------+ <-- strings_off + * | dt_strings | + * | ... | + * +--------------------+ <-- total_size + */ int mem_rsv_off, struct_off, strings_off; mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); struct_off = mem_rsv_off + mem_rsv_size; strings_off = struct_off + struct_size; + // 순서에 맞게 fdt의 각각의 블럭들의 정보를 설정 및 복사한다. memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); fdt_set_off_mem_rsvmap(new, mem_rsv_off); @@ -413,41 +624,82 @@ static void _fdt_packblocks(const char *old, char *new, fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } +/* + * fdt struct의 공간 확보를 하는것이 아닐까? + * + * in fdt fdt + * out buf fdt + * in bufsize fdt의 총 크기 + * return 0 성공, + * 0미만 실패 + * + * val = 0x 30, *val=10 + * const int * ptr1=&val; 10을 못바꿈 (data를 못바꿈) + * int * const ptr2 = &val2 ; 30을 못바꿈 (주소 번지를 못바꿈) + * + * fdt = DTB의 시작 주소 +*/ int fdt_open_into(const void *fdt, void *buf, int bufsize) { int err; int mem_rsv_size, struct_size; int newsize; const char *fdtstart = fdt; + /*bufsize는 32K 1MB제한을 건것이어서 아래 macro에서 struct에서 가져 온 + 것과 다를 수 있다. + + fdt_totalsize(fdt) 설명: + struct fdt_header * pf = fdt; + return pf->totalsize + */ const char *fdtend = fdtstart + fdt_totalsize(fdt); char *tmp; + // 아래 함수에서 fdt의 MAGIC, VERSION 을 체크해서 문제시 에러로 리턴함. FDT_CHECK_HEADER(fdt); + /* memory reserve map의 총 size를 계산한다. */ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); + /* DEFAULT_FDT_VERSION이 17이다. */ if (fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); } else { + /* 버전 17이전에는 dt_struct struct_size 멤버가 없었다 + * struct_size 를 모두 구할때까지 다음 tag를 계속 구한다. + */ struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; + + // 만약 size가 음수가 된다면, 에러이다. if (struct_size < 0) return struct_size; } if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { + // 순서가 올바른 경우 /* no further work necessary */ err = fdt_move(fdt, buf, bufsize); if (err) return err; + + /* scripts/dtc/libfdt/libfdt.h 파일에 __fdt_set_hdr(version); 가 + * 선언 되어 있으며 이것은 아래와 같은 inline 함수로 대처 된다. + * static inline void fdt_set_version(void *fdt, uint32_t val) + * { + * struct fdt_header *fdth = (struct fdt_header*)fdt; + * fdth->version = cpu_to_fdt32(val); + * } + */ fdt_set_version(buf, 17); fdt_set_size_dt_struct(buf, struct_size); fdt_set_totalsize(buf, bufsize); return 0; } + // 순서가 올바르지 않는 경우 /* Need to reorder */ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + struct_size + fdt_size_dt_strings(fdt); @@ -458,13 +710,27 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) /* First attempt to build converted tree at beginning of buffer */ tmp = buf; /* But if that overlaps with the old tree... */ + /* + * fdtend --> +-------------+ + * | | + * | | + * | +-------+-----+ <-- tmp + newsize + * | | | | + * fdtstart -->+-----+-------+ | + * | | + * | | + * +-------------+ <-- tmp + */ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { /* Try right after the old tree instead */ + /* 겹쳤을 경우 tmp를 fdtend로 */ tmp = (char *)(uintptr_t)fdtend; + // bufsize 보다 크면 에러 if ((tmp + newsize) > ((char *)buf + bufsize)) return -FDT_ERR_NOSPACE; } + // tmp에 fdt 정렬에 맞쳐 패키징한다. _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); memmove(buf, tmp, newsize); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 73f49759..f397f69b 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -456,10 +456,20 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, */ const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp); +/* ================================================================== + * 팀: Iamroot ARM Kernel 분석 12차 D조 (http://www.iamroot.org) + * 날짜: 2015-11-28 + * ------------------------------------------------------------------ + * bootagrs property 를 찾아서 return + */ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, const char *name, int *lenp) { + /* + * intptr : 32 bit와 64bit 에서 + * 모두 호환 동작될 수 있도록 하기 위해 사용 + */ return (struct fdt_property *)(uintptr_t) fdt_get_property(fdt, nodeoffset, name, lenp); } diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 381133ba..c4ac5f68 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -53,6 +53,12 @@ #include #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +/* FDT_TAGALIGN(4byte) 단위로 올림 연산 2015-11-28 + ex) FDT_TAGALIGN(10) + FDT_ALIGN(10, 4) + ((10 + 4 - 1) & ~(4 - 1)) = 12 + (13 & ~3) = 0b1101 & ~0b0011 = 0b1100 = 12 +*/ #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #define FDT_CHECK_HEADER(fdt) \ @@ -69,6 +75,7 @@ int _fdt_node_end_offset(void *fdt, int nodeoffset); static inline const void *_fdt_offset_ptr(const void *fdt, int offset) { + /* dt_struct의 시작 지점(offset) + 계산되고 있는 offset */ return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; }