ความแตกต่างระหว่างพื้นที่ผู้ใช้และพื้นที่เคอร์เนลคืออะไร?


72

พื้นที่เคอร์เนลถูกใช้เมื่อเคอร์เนลกำลังทำงานในนามของโปรแกรมผู้ใช้เช่นการเรียกระบบหรือไม่ หรือเป็นพื้นที่ที่อยู่สำหรับเธรดเคอร์เนลทั้งหมด (เช่นตัวกำหนดตารางเวลา)?

หากเป็นโปรแกรมแรกแสดงว่าโปรแกรมผู้ใช้ปกติไม่สามารถมีหน่วยความจำเกิน 3GB ได้ (หากแบ่งเป็น 3GB + 1GB) นอกจากนี้ในกรณีนั้นเคอร์เนลสามารถใช้หน่วยความจำสูงได้อย่างไรเนื่องจากที่อยู่หน่วยความจำเสมือนใดที่หน้าเว็บจากหน่วยความจำสูงจะถูกแมปเนื่องจากพื้นที่เคอร์เนล 1GB จะถูกแมปอย่างมีเหตุผล

คำตอบ:


93

พื้นที่เคอร์เนลถูกใช้เมื่อเคอร์เนลกำลังทำงานในนามของโปรแกรมผู้ใช้เช่นการเรียกระบบหรือไม่ หรือเป็นพื้นที่ที่อยู่สำหรับเธรดเคอร์เนลทั้งหมด (เช่นตัวกำหนดตารางเวลา)?

ใช่และใช่

ก่อนที่เราจะไปไกลกว่านี้เราควรบอกเรื่องนี้ให้ดี

การรับหน่วยความจำแบ่งออกเป็นสองส่วน:

  • พื้นที่ผู้ใช้ซึ่งเป็นชุดของสถานที่ที่ผู้ใช้ทั่วไปดำเนินการ (เช่นทุกอย่างที่ไม่ใช่เคอร์เนล) บทบาทของเคอร์เนลคือการจัดการแอปพลิเคชั่นที่ทำงานในพื้นที่นี้จากการล้อเล่นซึ่งกันและกันและเครื่อง
  • พื้นที่เคอร์เนลซึ่งเป็นตำแหน่งที่เก็บรหัสของเคอร์เนลและดำเนินการภายใต้

กระบวนการที่ทำงานภายใต้พื้นที่ผู้ใช้มีการเข้าถึงหน่วยความจำส่วนที่ จำกัด เท่านั้นในขณะที่เคอร์เนลมีการเข้าถึงหน่วยความจำทั้งหมด กระบวนการที่ทำงานในพื้นที่ของผู้ใช้ยังไม่สามารถเข้าถึงพื้นที่เคอร์เนลได้ กระบวนการพื้นที่ของผู้ใช้สามารถเข้าถึงส่วนเล็ก ๆ ของเคอร์เนลผ่านส่วนต่อประสานที่สัมผัสโดยเคอร์เนลนั่นคือการเรียกระบบ หากกระบวนการดำเนินการเรียกของระบบการขัดจังหวะของซอฟต์แวร์จะถูกส่งไปยังเคอร์เนลซึ่งจะทำการแจกจ่ายตัวจัดการขัดจังหวะที่เหมาะสมและทำงานต่อไปหลังจากที่ตัวจัดการเสร็จสิ้น

เคอร์เนลรหัสพื้นที่มีคุณสมบัติที่จะทำงานใน "โหมดเคอร์เนล" ซึ่ง (ในสก์ท็อปของคุณโดยทั่วไป -x86- คอมพิวเตอร์) คือสิ่งที่คุณเรียกรหัสที่ดำเนินการภายใต้แหวน 0 มักจะอยู่ในสถาปัตยกรรม x86 มี 4 วงของการป้องกัน แหวน 0 (โหมดเคอร์เนล), แหวน 1 (อาจใช้โดยเครื่องเสมือนไฮเปอร์ไวเซอร์หรือไดรเวอร์), แหวน 2 (อาจถูกใช้โดยไดรเวอร์ฉันไม่แน่ใจเกี่ยวกับเรื่องนั้น) แหวน 3 เป็นแอปพลิเคชันทั่วไปที่ทำงานภายใต้ เป็นวงแหวนที่มีสิทธิพิเศษน้อยที่สุดและแอปพลิเคชันที่ทำงานอยู่สามารถเข้าถึงชุดย่อยของคำแนะนำของโปรเซสเซอร์ได้ Ring 0 (พื้นที่เคอร์เนล) เป็นวงแหวนที่มีสิทธิพิเศษมากที่สุดและสามารถเข้าถึงคำแนะนำทั้งหมดของเครื่องได้ ตัวอย่างเช่นนี้แอปพลิเคชัน "ธรรมดา" (เช่นเบราว์เซอร์) ไม่สามารถใช้คำแนะนำการประกอบ x86lgdtเพื่อโหลดตาราง descriptor ทั่วโลกหรือhltหยุดโปรเซสเซอร์

หากเป็นโปรแกรมแรกแสดงว่าโปรแกรมผู้ใช้ปกติไม่สามารถมีหน่วยความจำเกิน 3GB ได้ (หากแบ่งเป็น 3GB + 1GB) นอกจากนี้ในกรณีนั้นเคอร์เนลสามารถใช้หน่วยความจำสูงได้อย่างไรเนื่องจากที่อยู่หน่วยความจำเสมือนใดที่หน้าเว็บจากหน่วยความจำสูงจะถูกแมปเนื่องจากพื้นที่เคอร์เนล 1GB จะถูกแมปอย่างมีเหตุผล

สำหรับคำตอบนี้โปรดดูที่คำตอบที่ดีเยี่ยมโดยกระดิก นี่


4
อย่าลังเลที่จะบอกฉันว่าฉันทำผิดพลาดที่ไหนสักแห่ง ฉันยังใหม่กับการเขียนโปรแกรมเคอร์เนลและฉันทิ้งสิ่งที่ฉันได้เรียนรู้จนถึงขณะนี้พร้อมกับข้อมูลอื่น ๆ ที่ฉันพบในเว็บ ซึ่งหมายความว่าอาจมีข้อบกพร่องในการทำความเข้าใจแนวคิดที่อาจแสดงให้เห็นในข้อความ
NlightNFotis

ขอบคุณ! ฉันคิดว่าตอนนี้ฉันเข้าใจแล้วดีขึ้น เพียงเพื่อให้แน่ใจว่าฉันได้รับอย่างถูกต้องฉันมีอีกหนึ่งคำถาม พิจารณาอีกครั้งว่า 3GB แรกใช้สำหรับ userspace และใช้พื้นที่เคอร์เนล 128MB สำหรับหน่วยความจำสูงส่วนที่เหลืออีก 896MB (หน่วยความจำต่ำ) ถูกแมปแบบคงที่ในเวลาบูตหรือไม่
Poojan

1
@NlightNFotis ฉันบอกว่าเกือบ 15 คนเชื่อว่าสิ่งที่คุณพูดนั้นถูกต้อง (หรือทำให้คุณคิดว่า;))
Braiam

ฉันคิดว่าแหวน x86 -1สำหรับไฮเปอร์ไวเซอร์แล้วเหรอ? en.wikipedia.org/wiki/Protection_ring
Dori

1
บันทึกความแตกต่างระหว่างหน่วยความจำเสมือนและหน่วยความจำกายภาพ สิ่งที่คุณถามเกี่ยวกับส่วนใหญ่เกี่ยวกับหน่วยความจำเสมือน สิ่งนี้ถูกแมปไปยังหน่วยความจำกายภาพซึ่งจะซับซ้อนเนื่องจากหน่วยความจำกายภาพใกล้ถึง 3GB และใช้ PAE จากนั้นจะทำให้ง่ายขึ้นอีกครั้งเมื่อมีการใช้เคอร์เนล 64 บิตในกรณีนี้ที่อยู่เชิงลบจะถูกสงวนไว้สำหรับเคอร์เนลและที่อยู่เชิงบวกสำหรับพื้นที่ผู้ใช้ กระบวนการ 32 บิตสามารถใช้พื้นที่เสมือน 4GB ได้ในขณะนี้ กระบวนการ 64 บิตสามารถใช้มากขึ้น - โดยทั่วไปแล้วจะมีค่า 48 บิต (ในขณะนี้ที่ x86-64)
ctrl-alt-delor

16

วงแหวน CPU เป็นความแตกต่างที่ชัดเจนที่สุด

ในโหมดที่ได้รับการป้องกัน x86 CPU จะอยู่ในหนึ่งใน 4 วงเสมอ เคอร์เนล Linux ใช้ 0 และ 3 เท่านั้น:

  • 0 สำหรับเคอร์เนล
  • 3 สำหรับผู้ใช้

นี่เป็นนิยามที่ยากและรวดเร็วที่สุดของ kernel vs userland

ทำไม Linux ไม่ใช้ริง 1 และ 2: https://stackoverflow.com/questions/6710040/cpu-privilege-rings-why-rings-1-and-2-arent-used

วงแหวนปัจจุบันถูกกำหนดอย่างไร?

แหวนปัจจุบันถูกเลือกโดยการรวมกันของ:

  • ตารางตัวอธิบายทั่วโลก: ตารางในหน่วยความจำของรายการ GDT และแต่ละรายการมีเขตข้อมูลPrivlที่เข้ารหัสแหวน

    คำสั่ง LGDT ตั้งค่าที่อยู่เป็นตารางตัวอธิบายปัจจุบัน

    ดูเพิ่มเติมที่: http://wiki.osdev.org/Global_Descriptor_Table

  • ส่วนที่ลงทะเบียน CS, DS ฯลฯ ซึ่งชี้ไปที่ดัชนีของรายการใน GDT

    ตัวอย่างเช่นCS = 0หมายความว่ารายการแรกของ GDT ใช้งานได้ในปัจจุบันสำหรับรหัสดำเนินการ

แหวนแต่ละวงทำอะไรได้บ้าง?

ชิปซีพียูถูกสร้างขึ้นทางกายภาพเพื่อที่:

  • แหวน 0 สามารถทำอะไรก็ได้

  • แหวน 3 ไม่สามารถเรียกใช้หลายคำสั่งและเขียนไปยังหลาย ๆ รีจิสเตอร์ได้อย่างยอดเยี่ยมที่สุด:

    • ไม่สามารถเปลี่ยนแหวนของตัวเองได้! มิฉะนั้นมันอาจตั้งค่าตัวเองให้แหวน 0 และแหวนจะไร้ประโยชน์

      กล่าวอีกนัยหนึ่งไม่สามารถแก้ไขตัวอธิบายส่วนปัจจุบันซึ่งกำหนดแหวนปัจจุบัน

    • ไม่สามารถแก้ไขตารางหน้า: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work

      กล่าวอีกนัยหนึ่งไม่สามารถแก้ไขการลงทะเบียน CR3 และเพจตัวเองป้องกันการแก้ไขตารางหน้า

      สิ่งนี้ป้องกันไม่ให้กระบวนการหนึ่งเห็นหน่วยความจำของกระบวนการอื่น ๆ เพื่อความปลอดภัย / ความง่ายในการเขียนโปรแกรมด้วยเหตุผล

    • ไม่สามารถลงทะเบียนตัวจัดการขัดจังหวะ สิ่งเหล่านั้นถูกกำหนดค่าโดยการเขียนไปยังตำแหน่งหน่วยความจำซึ่งถูกป้องกันโดยการเพจ

      ตัวจัดการทำงานในวงแหวน 0 และจะทำลายรูปแบบความปลอดภัย

      กล่าวอีกนัยหนึ่งไม่สามารถใช้คำแนะนำ LGDT และ LIDT

    • ไม่สามารถทำคำแนะนำ IO เหมือนinและoutและทำให้มีการเข้าถึงฮาร์ดแวร์โดยพลการ

      มิฉะนั้นยกตัวอย่างเช่นการอนุญาตของไฟล์จะไร้ประโยชน์หากโปรแกรมใด ๆ สามารถอ่านจากดิสก์โดยตรง

      แม่นยำมากขึ้นต้องขอบคุณไมเคิลเพชร : มันเป็นจริงที่เป็นไปได้สำหรับ OS เพื่อให้คำแนะนำ IO แหวน 3 นี้จะถูกควบคุมจริงโดยส่วนงานรัฐ

      สิ่งที่เป็นไปไม่ได้คือแหวน 3 จะให้สิทธิ์ตัวเองในการทำเช่นนั้นหากไม่มีในตอนแรก

      ลินุกซ์ไม่อนุญาตมันเสมอ ดูเพิ่มเติมที่: https://stackoverflow.com/questions/2711044/why-doesnt-linux-use-the-hardware-context-switch-via-the-tss

โปรแกรมและระบบปฏิบัติการมีการเปลี่ยนแปลงระหว่างวงแหวนอย่างไร

  • เมื่อซีพียูเปิดทำงานมันจะเริ่มรันโปรแกรมเริ่มต้นในริง 0 (แบบดี แต่มันเป็นการประมาณที่ดี) คุณสามารถคิดว่าโปรแกรมเริ่มต้นนี้เป็นเคอร์เนล (แต่โดยปกติจะเป็น bootloader ที่เรียกเคอร์เนลยังคงอยู่ในแหวน 0)

  • เมื่อกระบวนการของผู้ใช้ต้องการให้เคอร์เนลทำอะไรบางอย่างเพื่อให้มันเหมือนกับเขียนไฟล์มันใช้คำสั่งที่สร้างการขัดจังหวะเช่นint 0x80หรือsyscallส่งสัญญาณเคอร์เนล x86-64 Linux syscall ตัวอย่าง Hello world:

    .data
    hello_world:
        .ascii "hello world\n"
        hello_world_len = . - hello_world
    .text
    .global _start
    _start:
        /* write */
        mov $1, %rax
        mov $1, %rdi
        mov $hello_world, %rsi
        mov $hello_world_len, %rdx
        syscall
    
        /* exit */
        mov $60, %rax
        mov $0, %rdi
        syscall
    

    รวบรวมและเรียกใช้:

    as -o hello_world.o hello_world.S
    ld -o hello_world.out hello_world.o
    ./hello_world.out
    

    GitHub ต้นน้ำ

    เมื่อสิ่งนี้เกิดขึ้น CPU จะเรียกตัวจัดการการติดต่อกลับขัดจังหวะซึ่งเคอร์เนลที่ลงทะเบียนในเวลาบูต นี่คือตัวอย่าง BareMetal คอนกรีตที่ลงทะเบียนจัดการและใช้มัน

    ตัวจัดการนี้ทำงานในวงแหวน 0 ซึ่งตัดสินใจว่าเคอร์เนลจะอนุญาตการดำเนินการนี้ดำเนินการและรีสตาร์ทโปรแกรม userland ในริง 3 x86_64

  • เมื่อมีการexecใช้การเรียกระบบ (หรือเมื่อเคอร์เนลจะเริ่มทำงาน/init ) เคอร์เนลจะจัดเตรียมการลงทะเบียนและหน่วยความจำของกระบวนการ userland ใหม่จากนั้นจะข้ามไปที่จุดเริ่มต้นและสลับ CPU ไปยังวงแหวน 3

  • หากโปรแกรมพยายามทำสิ่งที่ซุกซนเช่นเขียนลงทะเบียนต้องห้ามหรือที่อยู่หน่วยความจำ (เพราะเพจจิ้ง) ซีพียูยังเรียกเคอร์เนลจัดการโทรกลับบางส่วนในแหวน 0

    แต่เนื่องจาก userland ซนเคอร์เนลอาจฆ่ากระบวนการในเวลานี้หรือแจ้งเตือนด้วยสัญญาณ

  • เมื่อเคอร์เนลบูทจะทำการติดตั้งนาฬิกาฮาร์ดแวร์ด้วยความถี่คงที่ซึ่งสร้างอินเทอร์รัปต์เป็นระยะ

    นาฬิกาฮาร์ดแวร์นี้สร้างการขัดจังหวะที่เรียกใช้วงแหวน 0 และอนุญาตให้กำหนดเวลาว่ากระบวนการ userland ใดที่จะปลุก

    ด้วยวิธีนี้การกำหนดเวลาสามารถเกิดขึ้นได้แม้ว่ากระบวนการจะไม่ทำการเรียกระบบใด ๆ

อะไรคือจุดที่มีหลาย ๆ วง?

มีข้อดีสองประการที่สำคัญของการแยกเคอร์เนลและ userland:

  • มันง่ายกว่าที่จะสร้างโปรแกรมเมื่อคุณมั่นใจว่าจะไม่เข้าไปยุ่งกับโปรแกรมอื่น เช่นกระบวนการ userland หนึ่งกระบวนการไม่ต้องกังวลเกี่ยวกับการเขียนทับหน่วยความจำของโปรแกรมอื่นเนื่องจากการเพจหรือการวางฮาร์ดแวร์ในสถานะที่ไม่ถูกต้องสำหรับกระบวนการอื่น
  • ปลอดภัยยิ่งขึ้น เช่นการอนุญาตไฟล์และการแยกหน่วยความจำสามารถป้องกันไม่ให้แอปแฮ็คอ่านข้อมูลธนาคารของคุณ แน่นอนว่าสิ่งนี้ถือว่าคุณเชื่อถือเคอร์เนล

จะเล่นกับมันอย่างไร?

ฉันได้สร้างการตั้งค่าโลหะเปลือยที่ควรจะเป็นวิธีที่ดีในการจัดการแหวนโดยตรง: https://github.com/cirosantilli/x86-bare-metal-examples

ฉันไม่ได้มีความอดทนในการสร้างตัวอย่าง userland อย่างน่าเสียดาย แต่ฉันไปไกลถึงการตั้งค่าการเพจดังนั้น userland ควรเป็นไปได้ ฉันชอบที่จะเห็นคำขอดึง

อีกวิธีหนึ่งคือโมดูลเคอร์เนล Linux ทำงานในวงแหวน 0 ดังนั้นคุณสามารถใช้พวกเขาเพื่อลองการดำเนินการพิเศษเช่นอ่านการลงทะเบียนควบคุม: https://stackoverflow.com/questions/7415515/how-to-access-the-control-registers -cr0-CR2-CR3 จาก-a-โปรแกรมรับ-กลุ่ม A / 7419306 # 7419306

นี่คือการตั้งค่า QEMU + Buildroot ที่สะดวกเพื่อลองใช้งานโดยไม่ต้องฆ่าโฮสต์ของคุณ

ข้อเสียของโมดูลเคอร์เนลคือ kthreads อื่นกำลังทำงานและอาจรบกวนการทดลองของคุณ แต่ในทางทฤษฎีคุณสามารถจัดการตัวจัดการขัดจังหวะทั้งหมดด้วยโมดูลเคอร์เนลของคุณและเป็นเจ้าของระบบซึ่งจะเป็นโครงการที่น่าสนใจจริง ๆ

แหวนเชิงลบ

ในขณะที่วงแหวนด้านลบนั้นไม่ได้อ้างอิงในคู่มือ Intel จริง ๆ แล้วมีโหมด CPU ที่มีความสามารถเพิ่มเติมนอกเหนือจากวงแหวน 0 นั้นจึงเหมาะสำหรับชื่อ "วงแหวนลบ"

ตัวอย่างหนึ่งคือโหมดไฮเปอร์ไวเซอร์ที่ใช้ในการจำลองเสมือน

สำหรับรายละเอียดเพิ่มเติมดูที่: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1

แขน

ใน ARM วงแหวนจะถูกเรียกว่า Exception Levels แทน แต่ความคิดหลักยังคงเหมือนเดิม

มีข้อยกเว้น 4 ระดับใน ARMv8 ที่ใช้โดยทั่วไปดังนี้:

  • EL0: userland

  • EL1: เคอร์เนล ("ผู้ควบคุม" ในคำศัพท์ ARM)

    ป้อนด้วยsvcคำสั่ง (SuperVisor Call) ซึ่งก่อนหน้านี้รู้จักกันก่อนหน้านี้ว่าเป็นswi แอสเซมบลีรวมซึ่งเป็นคำสั่งที่ใช้ในการโทรระบบ Linux สวัสดีชาวโลกตัวอย่าง ARMv8:

    .text
    .global _start
    _start:
        /* write */
        mov x0, 1
        ldr x1, =msg
        ldr x2, =len
        mov x8, 64
        svc 0
    
        /* exit */
        mov x0, 0
        mov x8, 93
        svc 0
    msg:
        .ascii "hello syscall v8\n"
    len = . - msg
    

    GitHub ต้นน้ำ

    ทดสอบกับ QEMU บน Ubuntu 16.04:

    sudo apt-get install qemu-user gcc-arm-linux-gnueabihf
    arm-linux-gnueabihf-as -o hello.o hello.S
    arm-linux-gnueabihf-ld -o hello hello.o
    qemu-arm hello
    

    นี่เป็นตัวอย่าง BareMetal เป็นรูปธรรมที่ลงทะเบียนการจัดการ SVC และไม่รับสายเรียก

  • EL2: hypervisorsเช่นXen

    เข้าไปพร้อมกับhvcคำแนะนำ (HyperVisor Call)

    ไฮเปอร์ไวเซอร์คือระบบปฏิบัติการระบบปฏิบัติการคืออะไรสำหรับผู้ใช้

    ตัวอย่างเช่น Xen อนุญาตให้คุณเรียกใช้หลาย ๆ OS เช่น Linux หรือ Windows บนระบบเดียวกันในเวลาเดียวกันและมันแยก OS ต่างๆออกจากกันเพื่อความปลอดภัยและความสะดวกในการดีบักเช่นเดียวกับ Linux สำหรับโปรแกรมผู้ใช้

    Hypervisors เป็นส่วนสำคัญของโครงสร้างพื้นฐานคลาวด์ในปัจจุบัน: อนุญาตให้เซิร์ฟเวอร์หลาย ๆ เครื่องทำงานบนฮาร์ดแวร์เดียวทำให้การใช้งานฮาร์ดแวร์ใกล้เคียงกับ 100% และประหยัดเงินเป็นจำนวนมาก

    AWS เช่นใช้ Xen จนกระทั่ง 2017 เมื่อย้ายไป KVM ทำข่าว

  • EL3: อีกระดับหนึ่ง ตัวอย่างสิ่งที่ต้องทำ

    เข้าสู่smcคำสั่ง (การเรียกใช้โหมดปลอดภัย)

ARMv8 สถาปัตยกรรมแบบอ้างอิง DDI 0487C.a - บท D1 - ระดับ AArch64 ระบบโปรแกรมเมอร์รุ่น - รูปที่แสดงให้เห็นถึง D1-1 นี้สวยงาม:

ป้อนคำอธิบายรูปภาพที่นี่

สังเกตว่า ARM อาจจะเป็นเพราะประโยชน์ของการเข้าใจถึงปัญหาหลังเหตุการณ์มีการตั้งชื่อที่ดีกว่าสำหรับระดับสิทธิ์มากกว่า x86 โดยไม่จำเป็นต้องมีระดับลบ: 0 เป็นต่ำและ 3 สูงที่สุด ระดับที่สูงขึ้นมีแนวโน้มที่จะถูกสร้างขึ้นบ่อยกว่าระดับที่ต่ำกว่า

สามารถสอบถาม EL ปัจจุบันด้วยMRSคำสั่ง: https://stackoverflow.com/questions/31787617/what-is-the-current-execution-mode-exception-level-etc

ARM ไม่จำเป็นต้องมีระดับการยกเว้นทั้งหมดเพื่อให้มีการใช้งานที่ไม่ต้องการคุณสมบัติในการบันทึกพื้นที่ชิป ARMv8 "ระดับการยกเว้น" พูดว่า:

การใช้งานอาจไม่รวมถึงระดับข้อยกเว้นทั้งหมด การใช้งานทั้งหมดจะต้องมี EL0 และ EL1 EL2 และ EL3 เป็นตัวเลือก

QEMU เช่นค่าเริ่มต้นเป็น EL1 แต่สามารถเปิดใช้งาน EL2 และ EL3 ด้วยตัวเลือกบรรทัดคำสั่ง: https://stackoverflow.com/questions/42824706/qemu-system-aarch64-entering-el1-when-emulating-a53-power-up

ตัวอย่างโค้ดทดสอบบน Ubuntu 18.10


3

หากเป็นโปรแกรมแรกแสดงว่าโปรแกรมผู้ใช้ปกติไม่สามารถมีหน่วยความจำเกิน 3GB ได้ (หากแบ่งเป็น 3GB + 1GB)

ใช่เป็นกรณีนี้ในระบบ linux ปกติ มีชุดของแพทช์ "4G / 4G" ที่ลอยอยู่รอบ ๆ จุดหนึ่งที่ทำให้ผู้ใช้และที่อยู่เคอร์เนลพื้นที่อิสระอย่างสมบูรณ์ (ที่ค่าใช้จ่ายประสิทธิภาพเพราะมันทำให้มันยากสำหรับเคอร์เนลในการเข้าถึงหน่วยความจำผู้ใช้) แต่ฉันไม่คิดว่า พวกเขารวมกันตั้งแต่ต้นน้ำและดอกเบี้ยลดลงด้วยการเพิ่มขึ้นของ x86-64

นอกจากนี้ในกรณีนั้นเคอร์เนลสามารถใช้หน่วยความจำสูงได้อย่างไรเนื่องจากที่อยู่หน่วยความจำเสมือนใดที่หน้าเว็บจากหน่วยความจำสูงจะถูกแมปเนื่องจากพื้นที่เคอร์เนล 1GB จะถูกแมปอย่างมีเหตุผล

วิธีที่ linux ใช้ในการทำงาน (และยังคงอยู่ในระบบที่หน่วยความจำมีขนาดเล็กเมื่อเทียบกับพื้นที่ที่อยู่) คือหน่วยความจำกายภาพทั้งหมดถูกแมปอย่างถาวรในส่วนเคอร์เนลของพื้นที่ที่อยู่ สิ่งนี้ทำให้เคอร์เนลเข้าถึงหน่วยความจำกายภาพทั้งหมดโดยไม่มีการแมปใหม่ แต่ชัดเจนว่ามันไม่ได้ปรับขนาดเป็นเครื่อง 32 บิตที่มีหน่วยความจำกายภาพจำนวนมาก

ดังนั้นแนวคิดของหน่วยความจำต่ำและสูงจึงเกิดขึ้น หน่วยความจำ "ต่ำ" ถูกแมปเข้ากับพื้นที่ที่อยู่ของเมล็ดอย่างถาวร หน่วยความจำ "สูง" ไม่ใช่

เมื่อตัวประมวลผลกำลังเรียกใช้ระบบมันกำลังทำงานในโหมดเคอร์เนล แต่ยังอยู่ในบริบทของกระบวนการปัจจุบัน ดังนั้นจึงสามารถเข้าถึงพื้นที่ที่อยู่เคอร์เนลและพื้นที่ที่อยู่ผู้ใช้ของกระบวนการปัจจุบันโดยตรง (สมมติว่าคุณไม่ได้ใช้แพตช์ 4G / 4G ดังกล่าวข้างต้น) ซึ่งหมายความว่าจะไม่มีปัญหาสำหรับหน่วยความจำ "สูง" ที่จะจัดสรรให้กับกระบวนการ userland

การใช้หน่วยความจำ "สูง" เพื่อจุดประสงค์เคอร์เนลเป็นปัญหามากกว่า ในการเข้าถึงหน่วยความจำสูงที่ไม่ได้แมปกับกระบวนการปัจจุบันนั้นจะต้องมีการแมปชั่วคราวในพื้นที่ที่อยู่ของเคอร์เนล นั่นหมายถึงรหัสพิเศษและการลงโทษประสิทธิภาพ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.