กองเคอร์เนลและสแตกพื้นที่ผู้ใช้


111

อะไรคือความแตกต่างระหว่าง kernel stack และ user stack? เหตุใดจึงใช้เคอร์เนลสแต็ก หากมีการประกาศตัวแปรภายในใน ISR จะเก็บไว้ที่ใด แต่ละกระบวนการมี kernel stack ของตัวเองหรือไม่? แล้วกระบวนการประสานงานระหว่างทั้งสองกองนี้อย่างไร?

คำตอบ:


188
  1. อะไรคือความแตกต่างระหว่าง kernel stack และ user stack?

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

  1. เหตุใดจึงใช้สแต็กเคอร์เนล [แยก]

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

  1. หากมีการประกาศตัวแปรภายในใน ISR จะเก็บไว้ที่ใด

บนกองเคอร์เนล เคอร์เนล (เคอร์เนลลินุกซ์นั่นคือ) ไม่เชื่อมโยง ISR โดยตรงกับประตูขัดจังหวะของสถาปัตยกรรม x86 แต่จะมอบหมายการส่งการขัดจังหวะไปยังกลไกการเข้า / ออกจากการขัดจังหวะเคอร์เนลทั่วไปซึ่งจะบันทึกสถานะการลงทะเบียนล่วงหน้าก่อนที่จะเรียกตัวจัดการที่ลงทะเบียน . ตัว CPU เองเมื่อส่งการขัดจังหวะอาจเรียกใช้สิทธิ์และ / หรือสวิตช์สแต็กและสิ่งนี้ถูกใช้ / ตั้งค่าโดยเคอร์เนลเพื่อให้โค้ดรายการอินเตอร์รัปต์ทั่วไปสามารถพึ่งพาสแต็กเคอร์เนลที่มีอยู่แล้ว
ที่กล่าวว่าการขัดจังหวะที่เกิดขึ้นในขณะเรียกใช้รหัสเคอร์เนลจะเพียงแค่ (ดำเนินการต่อไป) โดยใช้เคอร์เนลสแต็กที่จุดนั้น สิ่งนี้สามารถหากตัวจัดการการขัดจังหวะมีเส้นทางการโทรที่ซ้อนกันอย่างลึกล้ำนำไปสู่การล้นสแต็ก (หากเส้นทางการเรียกเคอร์เนลแบบลึกถูกขัดจังหวะและตัวจัดการทำให้เกิดเส้นทางลึกอื่นใน Linux รหัส RAID ของระบบไฟล์ / ซอฟต์แวร์ที่ถูกขัดจังหวะโดยรหัสเครือข่ายที่มี iptables ที่ใช้งานอยู่คือ เป็นที่ทราบกันดีว่าจะทริกเกอร์เช่นนี้ในเมล็ดพันธุ์เก่าที่ไม่ได้ปรับแต่ง ... วิธีแก้ปัญหาคือการเพิ่มขนาดเคอร์เนลสแต็กสำหรับปริมาณงานดังกล่าว)

  1. แต่ละกระบวนการมี kernel stack ของตัวเองหรือไม่?

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

  1. กระบวนการประสานงานระหว่างสแต็กทั้งสองนี้อย่างไร?

ไม่เลย - ไม่จำเป็นต้องทำ การจัดกำหนดการ (วิธีการ / เมื่อเธรดที่แตกต่างกันกำลังถูกเรียกใช้สถานะของพวกเขาถูกบันทึกและเรียกคืนอย่างไร) เป็นงานและกระบวนการของระบบปฏิบัติการไม่จำเป็นต้องกังวลกับสิ่งนี้ เมื่อเธรดถูกสร้างขึ้น (และแต่ละกระบวนการต้องมีเธรดอย่างน้อยหนึ่งเธรด) เคอร์เนลจะสร้างสแต็กเคอร์เนลสำหรับพวกเขาในขณะที่สแต็ก userspace ถูกสร้างขึ้นอย่างชัดเจน / จัดเตรียมโดยกลไกใดก็ตามที่ใช้ในการสร้างเธรด (ฟังก์ชันเช่นmakecontext()หรือpthread_create()อนุญาตให้ผู้เรียกใช้ ระบุขอบเขตหน่วยความจำที่จะใช้สำหรับสแต็กของเธรด "ชายด์") หรือรับช่วง (โดยการโคลนหน่วยความจำที่เข้าถึงโดยปกติเรียกว่า "copy on write" / COW เมื่อสร้างกระบวนการใหม่)
ที่กล่าวว่า(สถานะในนั้นคือสแต็กพอยน์เตอร์ของเธรด) มีหลายวิธีสำหรับสิ่งนี้: สัญญาณ UNIX setcontext(),, pthread_yield()/ pthread_cancel(), ... - แต่นี่เป็นการขัดข้องเล็กน้อยจากคำถามเดิม


คำตอบที่ยอดเยี่ยม FrankH. ขอบคุณ.
kumar

1
@ FrankH คำตอบที่ยอดเยี่ยม .. แต่ฉันมีคำถามเล็ก ๆ เกี่ยวกับเรื่องนี้ แต่ในสถาปัตยกรรม ARM .. เคอร์เนลสแต็กนี้เกี่ยวข้องกับโหมดโปรเซสเซอร์ที่แตกต่างกันอย่างไร
ราหุล

2
@ Rahul: "ขอบของความคิดเห็น SO น้อยเกินไปที่จะมีคำตอบเช่นนี้" การลงทะเบียนสแต็ก / สแต็กพอยน์เตอร์ทำงานอย่างไรในโหมด ARM CPU แบบต่างๆ (ซึ่งใช้ SP แบบแถ) เป็นคำถามที่ดี แต่ต้องใช้พื้นที่ในการตอบมากกว่าที่ความคิดเห็นจะสามารถให้ได้ เช่นเดียวกับสิ่งต่าง ๆ เช่นประตูงาน x86 หรือ IST - ไม่มีสิ่งที่เรียกว่าตัวชี้สแต็กเคอร์เนล "เดี่ยว" (เช่นเดียวกับที่ไม่มีตัวชี้สแต็กผู้ใช้ "เดี่ยว") และสิ่งที่สนับสนุน / คำสั่งฮาร์ดแวร์มีไว้สำหรับ ตัวชี้สแต็กแยกต่างหากในโหมดการทำงานที่แตกต่างกัน ... ขึ้นอยู่กับฮาร์ดแวร์มาก
แฟรงค์

@ แฟรงค์. ฉันสร้างคำถามใหม่สำหรับคำถามเดียวกัน ... stackoverflow.com/q/22601165/769260ฉันหวังว่าตอนนี้คุณสามารถช่วยฉันได้โดยไม่ต้องดูแลพื้นที่ :)
ราหุล

1
@ แฟรงค์. คุณสามารถจัดเตรียมแผนภาพที่แสดงตำแหน่งของเคอร์เนลสแตกในโครงร่างหน่วยความจำของกระบวนการได้หรือไม่?
Jithin Pavithran

19

คำตอบของฉันรวบรวมจากคำถาม SO อื่น ๆ ที่มีเนื้อหาของฉัน

What's the difference between kernel stack and user stack?

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

มี "เคอร์เนลสแต็ก" หนึ่งรายการต่อ CPU เช่น ISR Stack และหนึ่ง "kernel stack" ต่อหนึ่งกระบวนการ มี "สแต็กผู้ใช้" หนึ่งรายการสำหรับแต่ละกระบวนการแม้ว่าแต่ละเธรดจะมีสแต็กของตัวเองรวมทั้งเธรดผู้ใช้และเคอร์เนล

http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html

Why kernel stack is used?

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

http://www.kernel.org/doc/Documentation/x86/kernel-stacks

If a local variable is declared in an ISR, where it will be stored?

จะถูกเก็บไว้ใน ISR stack (IRQSTACKSIZE) ISR จะทำงานบนอินเตอร์รัปต์สแต็กที่แยกจากกันเฉพาะในกรณีที่ฮาร์ดแวร์รองรับเท่านั้น มิฉะนั้นเฟรมสแต็ก ISR จะถูกดันไปที่สแต็กของเธรดที่ถูกขัดจังหวะ

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

 Does each process has its own kernel stack ?

ใช่. แต่ละกระบวนการมีกองเคอร์เนลของตัวเอง

 Then how the process coordinates between both these stacks?

คำตอบของ @ FrankH ดูดีสำหรับฉัน


4
  1. อะไรคือความแตกต่างระหว่าง kernel stack และ user stack

อ้างอิงจากการพัฒนาเคอร์เนลลินุกซ์ของ Robert Love ความแตกต่างที่สำคัญคือขนาด:

พื้นที่ผู้ใช้สามารถหลีกเลี่ยงได้ด้วยการจัดสรรตัวแปรจำนวนมากบนสแต็กแบบคงที่รวมถึงโครงสร้างขนาดใหญ่และอาร์เรย์หลายพันองค์ประกอบ
พฤติกรรมนี้ถูกกฎหมายเนื่องจากพื้นที่ผู้ใช้มีสแต็กขนาดใหญ่ที่สามารถเติบโตแบบไดนามิก
สแต็กเคอร์เนลไม่มีขนาดใหญ่หรือไดนามิก มีขนาดเล็กและมีขนาดคงที่
ขนาดที่แน่นอนของสแต็กของเคอร์เนลจะแตกต่างกันไปตามสถาปัตยกรรม
บน x86 ขนาดสแต็กสามารถกำหนดค่าได้ในเวลาคอมไพล์และสามารถเป็น 4KB หรือ 8KB
ในอดีตสแต็กเคอร์เนลมีสองหน้าซึ่งโดยทั่วไปหมายความว่าเป็น 8KB บนสถาปัตยกรรม 32 บิตและ 16KB สำหรับสถาปัตยกรรม 64 บิตขนาดนี้ได้รับการแก้ไขและสัมบูรณ์
แต่ละกระบวนการได้รับสแตกของตัวเอง

นอกจากนี้สแต็กเคอร์เนลยังมีตัวชี้ไปยังข้อมูลที่เก็บโครงสร้าง thread_info เกี่ยวกับเธรด

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