İşlemci bir kesintiden sonra çekirdek kodunu nasıl bulur?


13

Bir kesme oluştuğunda, işlemci geçerli işlemi önler ve kesmeyi işlemek için çekirdek kodunu çağırır. İşlemci çekirdeğe nereden girileceğini nasıl biliyor?

Her kesme hattı için kurulabilen kesme işleyicileri olduğunu anlıyorum. Ancak işlemci yalnızca 'kablolu kablolu mantık' yürüttüğünden, bir kesme işleyicisinin kendisini veya işleyiciden önce çalışan bir kodu işaret eden önceden tanımlanmış bir yer olması gerekir (çünkü bir kesme hattı için birden fazla işleyici olabileceğinden, ikinci).

Yanıtlar:


13

Başlangıçta çekirdek, her satır için bir kesme işleyicisine işaret eden bir kesme vektör tablosu ( kesme tanımlayıcı tablosu veya ID86 olarak adlandırılır) başlatır .

80286'dan önce IDT her zaman sabit bir adreste depolanmıştı; 80286 ile başlayarak, IDT LIDTtalimat kullanılarak yüklenir .

Kesme vektör tabloları, kesme çizgisi başına tek bir işleyiciyi gösterir; bir çekirdek, örneğin, diğer birkaç kesme rutinini çalıştıran bir kesme işleyici sağlamayı veya bazı veya tüm kesintileri kapsayan tek bir işleyici sağlamayı seçebilir. Linux bu şeyleri, hangi kesme hattının çağrıldığını belirleyen ve çağrılacak uygun aşağı akış işleyicisini bulan genel bir kesme işleyicisi sağlayarak yapar.


1
böylece işlemci kesme satırını IDT'ye indeks olarak kullanır, girişi PC'ye koyar ve çalıştırmaya başlar. ancak tüm kesme işleyicilerinden önce çalışan genel bir işlev yok mu? linux için do_IRQ () olur. kesme hattı ne olursa olsun, her IDT girişinin işaret ettiği işlev bu mu?
Philipp Murry

@PhilippMurry evet. Çekirdek daha sonra, daha önce yürütülen koda dönmeden önce kesmeyi gerçekten işlemek için kendi kesme kesme işleyicileri setini (her satırda birden fazla olabilir) kullanır.
Adam Maraş

tamam, yani aslında iki tür kesme işleyicisi vardır: işlemcinin çağırdığı (her zaman do_IRQ ()) ve çekirdeğin çağırdığı (istek_irq () aracılığıyla kaydettiğim). bunu cevabınıza ekleyebilir misiniz? sanırım o zaman kabul edeceğim :) çok teşekkürler
Philipp Murry

1
@PhilippMurry Linux'un kesintileri nasıl ele aldığına (ve çekirdek geliştiricilerinin bu sisteme nasıl dokunduğuna) ilişkin bir uzman değilim, ancak çekirdeklerin kendi ISR ​​yönetimine nasıl sahip olabileceğine dair daha geniş bir bilgi ekledim.
Adam Maras

12

Evet, atlanacak kodun adresini içeren önceden tanımlanmış bir yer var: bir kesme vektörü . İşlemciye bağlı olarak, bu fiziksel bellekteki belirli bir konum (8088), sanal bellekteki belirli bir konum, bir işlemci kaydı, bellekteki bir kayıt tarafından belirtilen bir konum (ARM, 386),…

Ayrıntılar farklı işlemcilere göre değişir, ancak işlemcideki bir kesmeyi işlemek için ana ortak öğeler şunlardır:

  • Maske kesintileri (sonraki kesintilerin beklemek zorunda kalması için).
  • İşlemci modunu çekirdek veya kesme moduna ayarlayın (işlemcide bu tür modlar varsa).
  • Program sayacının değerini bilinen bir yere kaydedin (kayıt veya bellek).
  • Muhtemelen diğer kayıtların değerini kaydedin veya kayıt bankaları arasında geçiş yapın).
  • Bir sonraki talimatı yürütün (yeni PC değerinde).

1

Diğer iki cevap (yazma sırasında) kesintiler ve IDT hakkında konuşur. Bu doğrudur, ancak modern bir Intel-esque CPU'da, çekirdeğe çağrı yapmanın üçten az yolu yoktur.

Yöntem # 1: Kesmeler.

Bu yukarıda açıklanmıştır. Kesme tanımlayıcı tablosu / kesinti vektörüne bir giriş ayarladınız ve sonra çekirdeğe girmek için bir yazılım kesintisi gerçekleştirdiniz.

Bu yöntemin ana avantajı, tipik bir çekirdeğin kesmeleri yine de ele alabilmesi ve arkaik donanım üzerinde çalışmasıdır.

Yöntem # 2: Çağrı kapıları.

Bir çağrı kapısı, özel bir tür segment seçicidir. Çağrının hedefinin genel veya yerel segment tanımlayıcı tablosuna yüklenmesi gerekir (sırasıyla GDT ve LDT). Daha sonra, segment olarak çağrı kapısını kullanarak bir uzak çağrı talimatı gerçekleştirirseniz (çağrının ofseti yoksayılır), bu daha ayrıcalıklı kod çağırmanıza izin verir. Çağrı kapıları son derece esnektir; IA-32 mimarisinin dört ayrıcalık seviyesi vardır ve çağrı kapıları herhangi bir seviyeyi aramanızı sağlar.

Linux'un şimdiye kadar çağrı kapıları kullandığına inanmıyorum, ancak Windows 95 kullandı. Win95 çekirdek hizmetleri ( krnl386.exeve kernel.dll) aslında kullanıcı modunda (halka 3) koştu. En yüksek ayrıcalık düzeyi (halka 0) yalnızca sürücüler ve yalnızca işlem anahtarlaması gerçekleştiren bir mikro çekirdek için kullanıldı. Şoförlere çağrı, çağrı kapıları kullanılarak yapıldı. Bu, her zamanki gibi, standart bir uzak çağrı kullanarak Win95 sürücülerini kullanmak için eski 16 bit koduna (çok fazla şey vardı!) İzin verdi.

Genel tanımlayıcı tablosunun yetersiz korunması, kendi arama kapılarını bellek üzerine yazarak yüklemeyi başaran birkaç Windows 95 istismarının nedeniydi.

Yöntem # 3: SYSCALL / SYSRET ve SYSENTER / SYSEXIT

Bunlar, AMD ve Intel tarafından bağımsız olarak icat edilen iki talimat setidir, ancak aslında aynı şeyi yaparlar. SYSCALL / SYSRET önce geldi ve sadece AMD'ydi, SYSENTER / SYSEXIT Intel'di, ancak AMD şimdi uyguladı. Bu yüzden SYSENTER / SYSEXIT'i anlatacağım.

Çağrı kapılarının aksine, SYSENTER yalnızca 0 halkasına aktarmak için kullanılabilir ve yalnızca bir konuma aktarılabilir. Bununla birlikte, son derece düşük gecikme olma avantajına sahiptir, çünkü bir çağrı veya kesmenin aksine yığına değmez.

Aktarma konumu, modele özgü üç kayıt kullanılarak ayarlanır: biri segment bilgisi için ve her biri çekirdek kodunun yönerge işaretçisi ve yığın işaretçisi için. Yığına "hiçbir şey" itilmediğinden, kullanıcı modu kodu, kayıtlara iade talimatı işaretçisini ve yığın işaretçisini ileterek çekirdeğe nereye dönüleceğini bildirmekten sorumludur. Çekirdek, yığın işaretçisini geri yüklemekten sorumludur ve SYSEXIT komutu, talimat işaretçisini geri yükler.

SYSENTER ve SYSEXIT talimatları hakkında daha fazla bilgi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.