[go: up one dir, main page]

Bước tới nội dung

Microkernel

Bách khoa toàn thư mở Wikipedia
Cấu trúc của hệ điều hành dựa trên nhân monolithic và microkernel tương ứng

Trong khoa học máy tính, một microkernel (thường được viết tắt là μ-kernel) là lượng phần mềm gần như tối thiểu có thể cung cấp các cơ chế cần thiết để triển khai một hệ điều hành. Các cơ chế này bao gồm quản lý không gian địa chỉ cấp thấp, quản lý luồnggiao tiếp liên tiến trình (IPC).

Nếu phần cứng cung cấp nhiều vòng hoặc chế độ CPU, microkernel có thể là phần mềm duy nhất thực thi ở mức đặc quyền nhất, thường được gọi là chế độ giám sát hoặc chế độ hạt nhân. Các chức năng của hệ điều hành truyền thống, chẳng hạn như trình điều khiển, chồng giao thứchệ thống file, bị loại bỏ khỏi microkernel và thay vào đó được chạy trong không gian người dùng.[1]

Về kích thước mã nguồn, microkernel thường nhỏ hơn hạt nhân monolithic. MINIX là một ví dụ với chỉ có khoảng 12,000 dòng lệnh.[2]

Lịch sử

[sửa | sửa mã nguồn]

Microkernel bắt nguồn từ nhà tiên phong máy tính Đan Mạch Per Brinch Hansen và nhiệm kỳ của ông tại công ty máy tính Đan Mạch Regnecentralen, nơi ông đã dẫn đầu các nỗ lực phát triển phần mềm cho máy tính RC 4000.[3] Năm 1967, Regnecentralen đang lắp đặt một mẫu thử nghiệm RC 4000 tại một nhà máy phân bón Ba Lan ở Puławy. Máy tính sử dụng một hệ điều hành thời gian thực nhỏ được thiết kế riêng cho nhu cầu của nhà máy. Brinch Hansen và nhóm của ông trở nên lo lắng về sự thiếu tính tổng quát và khả năng tái sử dụng của hệ thống RC 4000. Họ sợ rằng mỗi lần cài đặt sẽ yêu cầu một hệ điều hành khác nhau nên họ bắt đầu nghiên cứu những cách mới và tổng quát hơn để tạo phần mềm cho RC 4000.[4] Năm 1969, nỗ lực của họ đã dẫn đến việc hoàn thành Hệ thống đa chương trình RC 4000. Hạt nhân của nó cung cấp thông tin liên lạc giữa các quy trình dựa trên việc truyền thông điệp cho tối đa 23 quy trình không đặc quyền, trong đó 8 quy trình tại một thời điểm được bảo vệ khỏi nhau. Nó tiếp tục thực hiện việc lập lịch các lát thời gian của các chương trình được thực hiện song song, khởi tạo và kiểm soát việc thực thi chương trình theo yêu cầu của các chương trình đang chạy khác và bắt đầu truyền dữ liệu đến hoặc từ thiết bị ngoại vi. Bên cạnh những cơ chế cơ bản này, nó không có chiến lược tích hợp để thực hiện chương trình và phân bổ tài nguyên. Chiến lược này được thực hiện bởi một hệ thống phân cấp các chương trình đang chạy trong đó các quy trình mẹ có toàn quyền kiểm soát các quy trình con và hoạt động như hệ điều hành của chúng.[5]

Sau công việc của Brinch Hansen, microkernels đã được phát triển vào những năm 1970[6] Bản thân thuật ngữ microkernel xuất hiện lần đầu tiên không muộn hơn năm 1981. Microkernels được coi là phản ứng với những thay đổi trong thế giới máy tính và đối với một số thách thức trong việc điều chỉnh các "đơn nhân" hiện có với những các hệ thống. Trình điều khiển thiết bị mới, ngăn xếp giao thức, hệ thống file và các hệ thống cấp thấp khác luôn được phát triển. Mã này thường được đặt trong hạt nhân nguyên khối, do đó cần phải làm việc đáng kể và quản lý mã cẩn thận để hoạt động. Microkernels được phát triển với ý tưởng rằng tất cả các dịch vụ này sẽ được triển khai dưới dạng các chương trình không gian người dùng, giống như bất kỳ chương trình nào khác, cho phép chúng hoạt động trên nguyên khối và bắt đầu và dừng như bất kỳ chương trình nào khác. Điều này không chỉ cho phép các dịch vụ này dễ dàng làm việc hơn, mà còn tách mã hạt nhân để cho phép nó được tinh chỉnh mà không phải lo lắng về các tác dụng phụ ngoài ý muốn. Hơn nữa, nó sẽ cho phép các hệ điều hành hoàn toàn mới được "xây dựng" trên một lõi chung, hỗ trợ nghiên cứu hệ điều hành.

Microkernels là một chủ đề rất nóng trong những năm 1980 khi các mạng cục bộ có thể sử dụng được đầu tiên được giới thiệu. Kernel AmigaOS Exec là một ví dụ ban đầu, được giới thiệu vào năm 1986 và được sử dụng trong PC với thành công tương đối về mặt thương mại. Việc thiếu bảo vệ bộ nhớ, được coi là một lỗ hổng khác, cho phép hạt nhân này có hiệu suất truyền thông điệp rất cao vì nó không cần sao chép dữ liệu trong khi trao đổi thông điệp giữa các chương trình không gian người dùng.[7]

Các cơ chế tương tự cho phép hạt nhân được phân phối vào không gian người dùng cũng cho phép hệ thống được phân phối trên các liên kết mạng. Những microkernel đầu tiên, đặc biệt là Mach, đã chứng tỏ có hiệu suất đáng thất vọng, nhưng những lợi thế vốn có xuất hiện rất lớn đến mức nó trở thành một dòng nghiên cứu chính vào cuối những năm 1990. Tuy nhiên, trong thời gian này, tốc độ của máy tính đã tăng lên rất nhiều liên quan đến hệ thống mạng, và những bất lợi trong hiệu suất lấn át những lợi thế trong điều kiện phát triển. bất kỳ nỗ lực nào đã được thực hiện để điều chỉnh các hệ thống hiện có để có hiệu suất tốt hơn, nhưng chi phí luôn là đáng kể và hầu hết các nỗ lực này yêu cầu các chương trình không gian người dùng phải được chuyển trở lại vào hạt nhân. Đến năm 2000, hầu hết các nỗ lực quy mô lớn (giống Mach) đã kết thúc, mặc dù macOS của Apple, được phát hành vào năm 2001, dùng một hybrid kernel có tên là XNU, kết hợp một nhân (hybrid) OSFMK 7.3 được sửa đổi nhiều với mã từ BSD UNIX,[8][9] và kernel này cũng được sử dụng trong iOS, tvOS, và watchOS. Tính đến năm 2012, GNU Hurd dựa trên Mach cũng có chức năng và được bao gồm trong các phiên bản thử nghiệm của Arch LinuxDebian.

Mặc dù công việc chính trên các microkernels đã kết thúc phần lớn, các nhà thử nghiệm vẫn tiếp tục phát triển.[cần dẫn nguồn] Từ đó đã chỉ ra rằng nhiều vấn đề về hiệu suất của các thiết kế trước đó không phải là hạn chế cơ bản của khái niệm mà thay vào đó là do nhà thiết kế mong muốn sử dụng các hệ thống đơn mục đích để triển khai càng nhiều dịch vụ này càng tốt.[cần dẫn nguồn] Sử dụng cách tiếp cận thực tế hơn cho vấn đề, bao gồm mã hợp ngữ và dựa vào bộ xử lý để thực thi các khái niệm thường được hỗ trợ trong phần mềm đã dẫn đến một loạt microkernels mới với hiệu suất được cải thiện.

Microkernels có liên quan chặt chẽ với các exokernels.[10] Chúng cũng có nhiều điểm chung với các hypervisors,[11] nhưng sau này không khẳng định tính tối thiểu và chuyên hỗ trợ các máy ảo; thực sự, microkernel L4 thường được sử dụng trong khả năng siêu giám sát

Introduction

[sửa | sửa mã nguồn]

Các nhân của hệ điều hành ban đầu khá nhỏ, một phần là do bộ nhớ máy tính bị hạn chế. Khi khả năng của máy tính phát triển, số lượng thiết bị mà nhân phải kiểm soát cũng tăng lên. Trong suốt lịch sử ban đầu của Unix, hạt nhân nói chung là nhỏ, mặc dù chúng chứa nhiều triển khai trình điều khiển thiết bịhệ thống file khác nhau. Khi không gian địa chỉ tăng từ 16 lên 32 bit, thiết kế nhân không còn bị giới hạn bởi kiến trúc phần cứng, và nhân bắt đầu phát triển lớn hơn.

Berkeley Software Distribution (BSD) của Unix bắt đầu kỷ nguyên của các hạt nhân lớn hơn. Ngoài việc vận hành một hệ thống cơ bản bao gồm CPU, đĩa và máy in, BSD đã bổ sung một hệ thống mạng TCP/IP hoàn chỉnh và một số thiết bị "ảo" cho phép các chương trình hiện có hoạt động 'vô hình' qua mạng. Sự tăng trưởng này tiếp tục trong nhiều năm, tạo ra các hạt nhân với hàng triệu dòng mã nguồn. Kết quả của sự phát triển này, hạt nhân dễ bị lỗi và ngày càng khó bảo trì.

Microkernel được thiết kế để giải quyết sự phát triển này của các hạt nhân và những khó khăn dẫn đến. Về lý thuyết, thiết kế microkernelcho phép quản lý mã dễ dàng hơn do nó được phân chia thành các dịch vụ không gian người dùng. Điều này cũng cho phép tăng cường bảo mật và ổn định do giảm lượng mã chạy trong kernel mode. Ví dụ: nếu một dịch vụ mạng gặp sự cố do tràn bộ đệm, chỉ bộ nhớ của dịch vụ mạng sẽ bị hỏng, phần còn lại của hệ thống vẫn hoạt động.

Hiệu năng

[sửa | sửa mã nguồn]

Trên hầu hết các bộ xử lý chính thống, việc nhận được một dịch vụ vốn đã đắt hơn trong một hệ thống dựa trên microkernel hơn là một hệ thống monolithic.[10] Trong hệ thống monolithic, dịch vụ có được bằng một lệnh gọi hệ thống, yêu cầu hai mode switches (thay đổi vòng của bộ xử lý hoặc chế độ CPU). Trong hệ thống dựa trên microkernel, dịch vụ nhận được bằng cách gửi một thông điệp IPC đến một server, và nhận được kết quả trong một thông điệp IPC khác từ server. Điều này yêu cầu chuyển đổi ngữ cảnh nếu các trình điều khiển được triển khai dưới dạng các quy trình hoặc một lệnh gọi hàm nếu chúng được thực hiện dưới dạng các thủ tục. Ngoài ra, việc chuyển dữ liệu thực tế đến máy chủ và quay lại có thể phát sinh thêm chi phí sao chép, trong khi trong một hệ thống monolithic, hạt nhân có thể truy cập trực tiếp vào dữ liệu trong bộ đệm của máy khách.

Do đó, hiệu suất là một vấn đề tiềm ẩn trong các hệ thống microkernel. Thật vậy, kinh nghiệm của các microkernels thế hệ đầu tiên như Mach hayChorusOS cho thấy rằng các hệ thống dựa trên chúng hoạt động rất kém. Tuy nhiên, Jochen Liedtke đã chỉ ra rằng các vấn đề về hiệu suất của Mach là kết quả của việc thiết kế và triển khai kém, cụ thể là bộ nhớ đệm quá nhiều của Mach. Liedtke đã chứng minh với L4 microkernel của riêng mình rằng thông qua thiết kế và triển khai cẩn thận, và đặc biệt là bằng cách tuân theo nguyên tắc tối thiểu, chi phí IPC có thể giảm nhiều hơn một bậc so với Mach.Hiệu suất IPC của L4 vẫn bất bại trên nhiều loại kiến trúc.

Mặc dù những kết quả này chứng minh rằng hiệu suất kém của các hệ thống dựa trên các microkernels thế hệ thứ nhất không phải là đại diện cho các hạt nhân thế hệ thứ hai như L4, nhưng điều này không tạo ra bằng chứng rằng các hệ thống dựa trên microkernel có thể được xây dựng với hiệu suất tốt. Nó đã được chỉ ra rằng một máy chủ Linux nguyên khối được chuyển sang L4 chỉ thể hiện một vài phần trăm chi phí so với Linux gốc.[12] Tuy nhiên, hệ thống một máy chủ như vậy thể hiện rất ít lợi thế, nếu có, các microkernel được cho là cung cấp bằng cách cấu trúc chức năng của hệ điều hành thành các máy chủ riêng biệt.

Một số hệ thống đa máy chủ thương mại tồn tại, đặc biệt là hệ thống thời gian thực QNX và Integrity. Không có so sánh toàn diện về hiệu suất so với các hệ thống nguyên khối đã được công bố cho các hệ thống nhiều máy chủ đó. Hơn nữa, hiệu suất dường như không phải là mối quan tâm lớn đối với các hệ thống thương mại đó, thay vào đó nhấn mạnh thời gian phản hồi xử lý ngắt nhanh đáng tin cậy (QNX) và tính đơn giản vì lợi ích của sự mạnh mẽ. Một nỗ lực để xây dựng một hệ điều hành đa máy chủ hiệu suất cao là dự án IBM Sawmill Linux. Tuy nhiên, dự án này đã không bao giờ được hoàn thành.

Trong khi đó, người ta đã chứng minh rằng trình điều khiển thiết bị cấp người dùng có thể đạt được hiệu suất của trình điều khiển trong nhân ngay cả đối với các thiết bị có thông lượng cao, ngắt quãng cao như Gigabit Ethernet.[13] Điều này dường như ngụ ý rằng các hệ thống đa máy chủ hiệu suất cao là có thể.

Bảo mật

[sửa | sửa mã nguồn]

Lợi ích bảo mật của các microkernels đã được thảo luận thường xuyên.[14] Trong bối cảnh bảo mật, nguyên tắc tối thiểu của microkernels, một số người đã lập luận, là hệ quả trực tiếp của nguyên tắc đặc quyền ít nhất, theo đó tất cả mã chỉ nên có những đặc quyền cần thiết để cung cấp chức năng cần thiết. Tính tối thiểu đòi hỏi cơ sở tính toán đáng tin cậy (TCB) của hệ thống phải được giữ ở mức tối thiểu. Vì hạt nhân (mã thực thi ở chế độ đặc quyền của phần cứng) đã tiết lộ quyền truy cập vào bất kỳ dữ liệu nào và do đó có thể vi phạm tính toàn vẹn hoặc tính bảo mật của nó, hạt nhân luôn là một phần của TCB. Giảm thiểu nó là điều đương nhiên trong một thiết kế theo hướng bảo mật.

Do đó, các thiết kế microkernel đã được sử dụng cho các hệ thống được thiết kế cho các ứng dụng bảo mật cao, bao gồm KeyKOS, EROS và các hệ thống quân sự. Trên thực tế, các tiêu chí chung common criteria (CC) at ở mức đảm bảo cao nhất (Evaluation Assurance Level (EAL) 7)có một yêu cầu rõ ràng rằng mục tiêu đánh giá phải "đơn giản", một sự thừa nhận về khả năng thiết lập độ tin cậy thực sự đối với một hệ thống phức tạp Thật không may, một lần nữa, thuật ngữ "đơn giản" gây hiểu lầm và không được xác định rõ ràng. Ít nhất thì Department of Defense Trusted Computer System Evaluation Criteria đã đưa ra một cách chính xác hơn phần nào các lớp B3/A1:

 

"The TCB shall [implement] complete, conceptually simple protection mechanisms with precisely defined semantics. Significant system engineering shall be directed toward minimizing the complexity of the TCB, as well as excluding from the TCB those modules that are not protection-critical."

— Department of Defense Trusted Computer System Evaluation Criteria

Vào năm 2018, một bài báo được trình bày tại Hội nghị Hệ thống Châu Á - Thái Bình Dương tuyên bố rằng các microkernel an toàn hơn đáng kể so với các hạt nhân monolithic bằng cách điều tra tất cả các CVE quan trọng được công bố cho nhân Linux vào thời điểm đó. Nghiên cứu kết luận rằng 40% các vấn đề hoàn toàn không thể xảy ra trong một microkernel, đã được xác minh chính thức và chỉ 4% các vấn đề sẽ hoàn toàn không có vấn đề trong một hệ thống như vậy.[15]

Thế hệ thứ ba

[sửa | sửa mã nguồn]

Các nghiên cứu gần đây hơn về các microkernels đang tập trung vào các thông số kỹ thuật chính thức của API hạt nhân và các bằng chứng chính thức về các thuộc tính bảo mật của API và tính đúng đắn của việc triển khai. Ví dụ đầu tiên về điều này là một bằng chứng toán học về các cơ chế giam giữ trong EROS, dựa trên mô hình đơn giản hóa của API EROS. Gần đây hơn (vào năm 2007) một tập hợp toàn diện các bằng chứng được kiểm tra bằng máy đã được thực hiện về các thuộc tính của mô hình bảo vệ của seL4, một phiên bản của L4.[16]

Điều này đã dẫn đến những gì được gọi là microkernels thế hệ thứ 3, được đặc trưng bởi một API định hướng bảo mật với quyền truy cập tài nguyên được kiểm soát bởi các khả năng, ảo hóa là mối quan tâm hàng đầu, các phương pháp mới để quản lý tài nguyên hạt nhân và mục tiêu thiết kế về tính phù hợp cho phân tích chính thức, bên cạnh mục tiêu thông thường là hiệu suất cao. Ví dụ như, Coyotos, seL4, Nova,[17] Redox và Fiasco.OC.

Trong trường hợp của seL4, đã đạt được xác minh chính thức hoàn chỉnh về việc triển khai, tức là một bằng chứng toán học cho thấy việc triển khai của hạt nhân nhất quán với đặc điểm kỹ thuật chính thức của nó. Điều này cung cấp một đảm bảo rằng các thuộc tính được chứng minh về API thực sự giữ cho hạt nhân thực, một mức độ đảm bảo vượt xa ngay cả CC EAL7. Tiếp theo là bằng chứng về các thuộc tính thực thi bảo mật của API và bằng chứng chứng minh rằng mã nhị phân thực thi là bản dịch chính xác của việc triển khai C, đưa trình biên dịch ra khỏi TCB. Kết hợp lại với nhau, các bằng chứng này thiết lập một bằng chứng đầu cuối về các thuộc tính bảo mật của hạt nhân.[18]

Nanokernel

[sửa | sửa mã nguồn]

Thuật ngữ nanokernel hoặc picokernel trước đây được gọi là:

  • Một nhân mà tổng lượng mã nhân, tức là mã thực thi trong chế độ đặc quyền của phần cứng, là rất nhỏ. Thuật ngữ picokernel đôi khi được sử dụng để nhấn mạnh thêm về kích thước nhỏ. Thuật ngữ nanokernel được đặt ra bởi Jonathan S. Shapiro trong bài báo Kiến trúc Nanokernel KeyKOS. Đó là một phản ứng mỉa mai đối với Mach, vốn được cho là một microkernel trong khi Shapiro coi nó là monolithic, về cơ bản là không có cấu trúc và chậm hơn so với các hệ thống mà nó tìm cách thay thế. Việc sử dụng lại và phản hồi sau đó đối với thuật ngữ, bao gồm cả picokernel coinage, cho thấy rằng điểm này phần lớn đã bị bỏ sót. Cả nanokernelpicokernel sau đó đều có cùng một ý nghĩa được biểu thị bằng thuật ngữ microkernel.
  • Một lớp ảo hóa bên dưới hệ điều hành, được gọi một cách chính xác hơn là một Hypervisor.
  • Một lớp trừu tượng phần cứng tạo thành phần cấp thấp nhất của nhân, đôi khi được sử dụng để cung cấp chức năng thời gian thực cho các hệ điều hành bình thường, như Adeos.

Cũng có ít nhất một trường hợp mà thuật ngữ nanokernel được sử dụng không phải để chỉ một hạt nhân nhỏ, mà là một hạt hỗ trợ độ phân giải xung nhịp nano giây.[19]

Chú thích

[sửa | sửa mã nguồn]
  1. ^ Herder, Jorrit N. (ngày 23 tháng 2 năm 2005). “Toward a True Microkernel Operating System” (PDF). minix3.org. Truy cập ngày 22 tháng 6 năm 2015.
  2. ^ “What is MINIX 3?”. https://wiki.minix3.org/. Bản gốc lưu trữ ngày 20 tháng 8 năm 2020. Truy cập ngày 19 tháng 10 năm 2020. Liên kết ngoài trong |website= (trợ giúp)
  3. ^ “2002 Computer Pioneer Award Recipient”. IEEE Computer Society. Truy cập ngày 13 tháng 9 năm 2016.
  4. ^ Brinch Hansen, Per (2004). A Programmer's Story: The Life of a Computer Pioneer. Truy cập ngày 13 tháng 9 năm 2016.
  5. ^ Brinch Hansen, Per (1970). “The Nucleus of a Multiprogramming Operating System” (PDF). Communications of the ACM. 13 (4): 238–250. CiteSeerX 10.1.1.105.4204. doi:10.1145/362258.362278.
  6. ^ .Wulf, William; Cohen, Ellis; Corwin, William; Jones, Anita; Levin, Roy; Pierson, C.; Pollack, Fred (tháng 6 năm 1974). “HYDRA: The Kernel of a Multiprocessor Operating System”. Communications of the ACM. 17 (6): 337–345. doi:10.1145/355616.364017.
  7. ^ Sassenrath, Carl (1986). Amiga ROM Kernel Reference Manual. Exec.
  8. ^ Jim Magee. WWDC 2000 Session 106 - Mac OS X: Kernel. 14 phút.
  9. ^ “Porting UNIX/Linux Applications to Mac OS X”. Apple. Truy cập ngày 26 tháng 4 năm 2011.
  10. ^ a b Liedtke, Jochen (tháng 9 năm 1996). “Towards Real Microkernels”. Communications of the ACM. 39 (9): 70–77. doi:10.1145/234215.234473.
  11. ^ Heiser, Gernot; Uhlig, Volkmar; LeVasseur, Joshua (tháng 1 năm 2006). “Are Virtual-Machine Monitors Microkernels Done Right?”. ACM SIGOPS Operating Systems Review. ACM. 40 (1): 95–99. doi:10.1145/1113361.1113363. Bản gốc (PDF) lưu trữ ngày 13 tháng 1 năm 2014. Truy cập ngày 11 tháng 10 năm 2020.
  12. ^ Härtig, Hermann; Hohmuth, Michael; Liedtke, Jochen; Schönberg, Sebastian (tháng 10 năm 1997). “The performance of µ-kernel-based systems”. Proceedings of the Sixteenth ACM Symposium on Operating Systems Principles: 66–77. doi:10.1145/268998.266660. ISBN 0-89791-916-5.
  13. ^ Leslie, Ben; Chubb, Peter; FitzRoy-Dale, Nicholas; Götz, Stefan; Gray, Charles; Macpherson, Luke; Potts, Daniel; Shen, Yueting; Elphinstone, Kevin (tháng 9 năm 2005). “User-level device drivers: achieved performance”. Journal of Computer Science and Technology. 20 (5): 654–664. doi:10.1007/s11390-005-0654-4.
  14. ^ Tanenbaum, Andrew S. “Tanenbaum-Torvalds debate, part II”.
  15. ^ Biggs, Simon; Lee, Damon; Heiser, Gernot (2018). “The Jury Is In: Monolithic OS Design Is Flawed: Microkernel-based Designs Improve Security”. Proceedings of the 9th Asia-Pacific Workshop on Systems. Jeju Island, Republic of Korea: Association for Computing Machinery. tr. 1–7. doi:10.1145/3265723.3265733.
  16. ^ Elkaduwe, Dhammika; Klein, Gerwin; Elphinstone, Kevin (2007). Verified Protection Model of the seL4 Microkernel. submitted for publication. Bản gốc lưu trữ ngày 29 tháng 11 năm 2011. Truy cập ngày 11 tháng 10 năm 2020.
  17. ^ “TUD Home: Operating Systems: Research: Microkernel & Hypervisor”. Faculty of Computer Science. Technische Universität Dresden. ngày 12 tháng 8 năm 2010. Bản gốc lưu trữ ngày 26 tháng 9 năm 2020. Truy cập ngày 5 tháng 11 năm 2011.
  18. ^ Klein, Gerwin; Andronick, June; Elphinstone, Kevin; Murray, Toby; Sewell, Thomas; Kolanski, Rafal; Heiser, Gernot (tháng 2 năm 2014). “Comprehensive Formal Verification of an OS Microkernel”. ACM Transactions on Computer Systems. 32 (1): 2:1–2:70. doi:10.1145/2560537.
  19. ^ David L. Mills and Poul-Henning Kamp (ngày 28 tháng 11 năm 2000). “The Nanokernel” (PDF). Truy cập ngày 28 tháng 8 năm 2017.

Đọc thêm

[sửa | sửa mã nguồn]