Buradaki kod blokları gerçek çalışma alanından derleme sırasında alınır. Sol sütun uygulanan kaynak, sağ sütun assertion veya test hazırlığıdır. Her kayıtta çalıştırma komutu, beklenen çıktı ve kanıtlanmayan alan ayrıca yazılır.
TEK KOMUT / TAM ZİNCİR
Önce ortamı kur ve tamamını sınayalım.
verify.sh VM ve çekirdek birim testlerini çalıştırır, beş imajı üretir, 9 standart ve bir özel DTB konuk açılışını sınar; her biri için geçici JSON raporu üretip 10 raporun içeriğini denetler. Ardından siteyi derleyip bağlantıları kontrol eder. Aşağıdaki tekil QEMU komutları, bu imajlar ve target/debug/rustos-vm üretildikten sonra çalıştırılır.
sh scripts/verify.sh
ÇEKİRDEK / TEST KAYDI
01 / Image başlığı ve giriş sözleşmesi
QEMU, ARM64 Image başlığındaki metin ofsetinden girişe ulaşır. Bu test yalnızca başlık biçimini ve sanal makinede BOOT0 çıkışını kanıtlar; UEFI yükleyiciyi kanıtlamaz.
text offset 0x80000; magic 0x644d5241; TURKOS/BOOT0: ARM64 kernel entered
Kapsam sınırı: Başlık denetimi gerçek Apple donanımında veya UEFI üzerinden açılış testi değildir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
02 / Seri port ve DTB keşfi
İlk BOOT0 mesajı sabit bootstrap PL011 adresinden çıkar. Sonra x0 ile gelen DTB okunur ve UART tabanı bulunan reg değerine geçirilir; test seri portu ve 256/512/1024 MiB RAM boyutunu denetler.
GERÇEK KAYNAK · kernel/src/main.rs
let hardware = &boot.hardware;
UART_BASE.store(hardware.uart_base as usize, Ordering::Relaxed);
write_str("TURKOS/UART: 0x");
write_hex(hardware.uart_base as usize);
write_str("\r\nTURKOS/RAM: 0x");
write_hex(hardware.ram_base as usize);
write_str("+0x");
write_hex(hardware.ram_size as usize);
write_str("\r\n");
write_str("TURKOS/GICD: 0x");
write_hex(boot.interrupts.gic_distributor as usize);
Kapsam sınırı: Kök UART/RAM düğümleri için dar QEMU virt profili; genel aygıt ağacı veya bus çevirisi yok. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
03 / Korunan RAM serbest haritaya girmez
Çekirdek imajı, DTB blobu, FDT rezervasyon bloğu ve statik /reserved-memory aralıkları FreeMap içinden kesilir. Birim testi kısmi sayfaları da tam 4 KiB sayfa olarak korur.
GERÇEK KAYNAK · kernel/src/main.rs
fn plan_free_memory(boot: &BootData, dtb_address: usize) -> Result<memory::FreeMap, memory::Error> {
let mut free = memory::FreeMap::from_ram(boot.hardware.ram_base, boot.hardware.ram_size)?;
let kernel_start = core::ptr::addr_of!(_image_start) as u64;
let kernel_end = core::ptr::addr_of!(_image_end) as u64;
let kernel_size = kernel_end
.checked_sub(kernel_start)
.ok_or(memory::Error::Invalid)?;
free.reserve(kernel_start, kernel_size)?;
free.reserve(dtb_address as u64, boot.dtb_size as u64)?;
for region in boot.reservations.as_slice() {
free.reserve(region.start, region.size)?;
}
for region in boot.static_reserved.as_slice() {
free.reserve(region.start, region.size)?;
}
Ok(free)
}
fn frame_smoke_test(free: memory::FreeMap) -> bool {
YENİDEN ÇALIŞTIRcargo test --manifest-path kernel/Cargo.toml --lib --locked
BEKLENEN GÖZLEM
excludes_kernel_and_dtb_pages … ok; korunmuş aralıklar hiçbir tahsiste dönmez
Kapsam sınırı: Dinamik DTB rezervasyonu ve çevrilen ranges bilinçli olarak reddedilir; firmware haritası henüz yok. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
04 / Özel DTB ile uçtan uca rezervasyon
Test, QEMU cihaz ağacına ilk dört RAM sayfasını kapsayan statik no-map havuzu ekler. Gerçek çekirdek açılışında ilk verilen çerçevenin 0x40004000 olduğu seri günlükte aranır.
Kapsam sınırı: no-map şu anda yalnızca ayırıcıdan dışlanır; MMU eşleme kuralı henüz kurulmadı. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
05 / Tahsis, tükenme ve çift iade
FrameAllocator yalnızca izinli serbest haritadan 4 KiB çerçeve dağıtır. Birim testi korunmuş bölge iadesini, hizasız adresi, çift iadeyi ve tekrar tahsis sırasını denetler.
GERÇEK KAYNAK · kernel/src/memory.rs
pub fn release(&mut self, address: u64) -> Result<(), Error> {
if address & (PAGE_SIZE - 1) != 0 {
return Err(Error::Invalid);
}
let end = address.checked_add(PAGE_SIZE).ok_or(Error::Invalid)?;
if !self
.allowed
.regions()
.iter()
.any(|region| region.start <= address && end <= region.end)
{
return Err(Error::Invalid);
}
let index = self
.free
.regions()
.iter()
.position(|region| region.start >= address)
GERÇEK TEST · kernel/src/memory.rs
fn release_coalesces_regions_and_rejects_protected_or_double_free() {
let mut map = FreeMap::from_ram(0x4000_0000, 0x5000).unwrap();
map.reserve(0x4000_4000, 0x1000).unwrap();
let mut allocator = FrameAllocator::new(map);
for _ in 0..4 {
assert!(allocator.allocate().is_some());
}
assert_eq!(allocator.release(0x4000_4000), Err(Error::Invalid));
assert_eq!(allocator.release(0x4000_0001), Err(Error::Invalid));
allocator.release(0x4000_0000).unwrap();
allocator.release(0x4000_2000).unwrap();
allocator.release(0x4000_1000).unwrap();
allocator.release(0x4000_3000).unwrap();
assert_eq!(allocator.release(0x4000_2000), Err(Error::Invalid));
assert_eq!(allocator.remaining_pages(), 4);
for offset in 0..4 {
assert_eq!(allocator.allocate(), Some(0x4000_0000 + offset * PAGE_SIZE));
}
}
#[test]
YENİDEN ÇALIŞTIRcargo test --manifest-path kernel/Cargo.toml --lib --locked memory::tests
BEKLENEN GÖZLEM
release_coalesces_regions_and_rejects_protected_or_double_free … ok
Kapsam sınırı: Ayırıcı tek CPU ve sabit bölge metaverisi ile sınırlı; eşzamanlı erişim ve MMU yok. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
06 / 16 sayfalık gerçek konuk yaz/oku/iade
Normal Image 16 çerçeveyi aynı anda ayırır; her ilk sözcüğü kaydedip işaret yazar, okur ve eski değeri geri koyar. Ardından sayfaları iade ederek başlangıç serbest sayfa sayısına dönüldüğünü kontrol eder.
GERÇEK KAYNAK · kernel/src/main.rs
fn frame_smoke_test(free: memory::FreeMap) -> bool {
#[cfg(feature = "frame-stress-test")]
const TEST_PAGES: usize = 128;
#[cfg(not(feature = "frame-stress-test"))]
const TEST_PAGES: usize = 16;
let initial_pages = free.total_pages();
let mut allocator = memory::FrameAllocator::new(free);
let mut frames = [0; TEST_PAGES];
for index in 0..TEST_PAGES {
let Some(address) = allocator.allocate() else {
return false;
};
if frames[..index].contains(&address) {
return false;
}
frames[index] = address;
// SAFETY: finalized free RAM excludes image, DTB and both reservation
// sources. Direct QEMU Image boot uses an identity-mapped RAM view.
unsafe {
let first = address as *mut u64;
let last =
(address + memory::PAGE_SIZE - core::mem::size_of::<u64>() as u64) as *mut u64;
let before_first = read_volatile(first);
let before_last = read_volatile(last);
let first_canary = 0x5455_524b_4f53_4652 ^ address;
let last_canary = !first_canary;
write_volatile(first, first_canary);
write_volatile(last, last_canary);
let passed = read_volatile(first) == first_canary && read_volatile(last) == last_canary;
write_volatile(first, before_first);
write_volatile(last, before_last);
if !passed {
write_str("TURKOS/FRAME-ERROR-ADDRESS: 0x");
write_hex(address as usize);
write_str("\r\n");
return false;
}
}
}
let address = frames[0];
write_str("TURKOS/FRAME-ADDRESS: 0x");
write_hex(address as usize);
write_str("\r\nTURKOS/FRAME-COUNT: 0x");
write_hex(TEST_PAGES);
write_str("\r\nTURKOS/FRAME-EDGE: PASS\r\n");
for frame in frames.into_iter().rev() {
if allocator.release(frame).is_err() {
FRAME-COUNT: 0x0000000000000010; FRAME-TEST: PASS; FRAME-ERROR yok
Kapsam sınırı: Bu 16 sayfalık erken boot yüküdür; büyük bellek baskısı veya çok CPU kanıtı değildir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
07 / BRK ve UDF ayrı hata sınıfları
İki ayrı test imajı x3 içine farklı işaret koyarak BRK ve UDF üretir. Vektör girişinde özgün x3 yığına alınır; test SLOT=0x04, EC ve x3 değerlerini tam eşleşmeyle arar.
GERÇEK KAYNAK · kernel/src/vectors.S
sub sp, sp, #EXCEPTION_FRAME_SIZE
str x3, [sp, #EXCEPTION_X3_OFFSET]
mov x3, #vector_slot
b __exception_entry
Kapsam sınırı: Fatal senkron yol sınandı; IRQ, EL2 konuk yolu, SIMD bağlam geri yükleme ve istisnadan dönüş yok. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
08 / Çift DTB reg alanını güvenli reddet
Aynı reserved-memory çocuk düğümündeki ikinci reg özelliği ilk korunan aralığı sessizce örtebiliyordu. Geçerli FDT biçimli karşı-örnek eklendi; ayrıştırıcı artık ikinci reg alanını Invalid ile reddediyor.
GERÇEK KAYNAK · kernel/src/dtb.rs
// A second property must not replace an earlier protected range.
if child_reg.is_some() {
return Err(Error::Invalid);
}
child_reg = Some(value);
}
GERÇEK TEST · kernel/src/dtb.rs
fn rejects_duplicate_reserved_reg_property() {
let first = [0x4001_0000u64.to_be_bytes(), 0x1000u64.to_be_bytes()].concat();
let second = [0x4002_0000u64.to_be_bytes(), 0x1000u64.to_be_bytes()].concat();
let mut blob = reserved_fixture(Some(&first), false, Some(&[]), false);
let mut extra = Vec::new();
prop(&mut extra, 27, &second);
let insertion = blob
.windows(first.len())
.position(|window| window == first)
.unwrap()
+ first.len();
let added = extra.len() as u32;
blob.splice(insertion..insertion, extra);
let total = blob.len() as u32;
blob[4..8].copy_from_slice(&total.to_be_bytes());
let strings = be32(&blob, 12).unwrap() + added;
blob[12..16].copy_from_slice(&strings.to_be_bytes());
let structure_len = be32(&blob, 36).unwrap() + added;
blob[36..40].copy_from_slice(&structure_len.to_be_bytes());
assert_eq!(be32(&blob, insertion), Ok(3));
assert_eq!(be32(&blob, insertion + 4), Ok(16));
assert!(
discover(&blob).is_ok(),
YENİDEN ÇALIŞTIRcargo test --manifest-path kernel/Cargo.toml --lib --locked dtb::tests
BEKLENEN GÖZLEM
rejects_duplicate_reserved_reg_property … ok; sıfır uzunluk ve kesik ikinci aralık testleri de geçer
Kapsam sınırı: Genel FDT uyumluluğu değil; desteklenmeyen dinamik/çevrilen rezervasyonlar hâlâ kapalı reddedilir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
09 / 4.096 adımlık çerçeve sahipliği
Deterministik ayır–iade dizisi, korunan sayfalardan tahsis yapılmamasını ve serbest+eldeki sayfa toplamının her adımda sabit kalmasını doğrular. Bölge kapasitesi aşılırsa FreeMap değişmeden kalır.
GERÇEK KAYNAK · kernel/src/memory.rs
pub fn release(&mut self, address: u64) -> Result<(), Error> {
if address & (PAGE_SIZE - 1) != 0 {
return Err(Error::Invalid);
}
let end = address.checked_add(PAGE_SIZE).ok_or(Error::Invalid)?;
if !self
.allowed
.regions()
.iter()
.any(|region| region.start <= address && end <= region.end)
{
return Err(Error::Invalid);
}
let index = self
.free
.regions()
.iter()
.position(|region| region.start >= address)
GERÇEK TEST · kernel/src/memory.rs
fn deterministic_fragmentation_preserves_page_ownership() {
const PAGES: usize = 96;
const BASE: u64 = 0x4000_0000;
let mut map = FreeMap::from_ram(BASE, PAGES as u64 * PAGE_SIZE).unwrap();
map.reserve(BASE + 5 * PAGE_SIZE, 2 * PAGE_SIZE).unwrap();
map.reserve(BASE + 20 * PAGE_SIZE, 4 * PAGE_SIZE).unwrap();
map.reserve(BASE + 50 * PAGE_SIZE, PAGE_SIZE).unwrap();
let allowed = map.total_pages();
assert_eq!(allowed, 89);
let mut allocator = FrameAllocator::new(map);
let mut held = [false; PAGES];
let mut held_count = 0u64;
let mut seed = 0x5455_524b_4f53u64;
for _ in 0..4096 {
seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
if (seed & 3 == 0 && held_count > 0) || allocator.remaining_pages() == 0 {
let mut index = seed as usize % PAGES;
while !held[index] {
index = (index + 1) % PAGES;
}
allocator.release(BASE + index as u64 * PAGE_SIZE).unwrap();
held[index] = false;
held_count -= 1;
} else {
let address = allocator.allocate().unwrap();
let index = ((address - BASE) / PAGE_SIZE) as usize;
assert!(index < PAGES && !held[index]);
assert!(!((5..7).contains(&index) || (20..24).contains(&index) || index == 50));
held[index] = true;
held_count += 1;
}
assert_eq!(allocator.remaining_pages() + held_count, allowed);
}
for (index, occupied) in held.iter().enumerate() {
if *occupied {
YENİDEN ÇALIŞTIRcargo test --manifest-path kernel/Cargo.toml --lib --locked memory::tests
BEKLENEN GÖZLEM
deterministic_fragmentation_preserves_page_ownership … ok; reserve_capacity_error_leaves_the_free_map_unchanged … ok
Kapsam sınırı: Tek CPU ve 96 sayfalık sentetik model; gerçek çok-CPU yarış koşulu veya MMU sınaması değildir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
10 / Tarihsel 64 çerçeveden 128 çerçeveye
H04 aşamasında StressImage 64 ilk-sözcük sınamasını geçti. E04 ile aynı ayrı imaj 128 çerçevenin ilk ve son sözcüğünü sınar; normal Image 16 sayfada kalır.
GERÇEK KAYNAK · kernel/src/main.rs
#[cfg(feature = "frame-stress-test")]
const TEST_PAGES: usize = 128;
#[cfg(not(feature = "frame-stress-test"))]
const TEST_PAGES: usize = 16;
let initial_pages = free.total_pages();
let mut allocator = memory::FrameAllocator::new(free);
let mut frames = [0; TEST_PAGES];
for index in 0..TEST_PAGES {
let Some(address) = allocator.allocate() else {
return false;
};
if frames[..index].contains(&address) {
Kapsam sınırı: 64 sayfalık eski ölçüm tarihsel; güncel iki uç kanaryası bile tüm sayfa/RAM veya MMU testi değildir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
11 / Rust–assembly fatal çerçeve sözleşmesi
Rust ExceptionFrame boyutu ve kesilen SP ofseti derleme zamanında doğrulanır; assembly boyut, x3 ve SP ofsetlerini Rust yerleşiminden alır. BRK/UDF imajları kesilen x0, x3 ve x30 için ayrı işaretler üretir.
Kapsam sınırı: Yalnız fatal EL1 senkron yolları ölçüldü; IRQ, EL2, SIMD bağlamı ve istisnadan dönüş yok. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
12 / Her açılışın makinece okunur kanıtı
Dokuz standart ve bir özel DTB açılışı, imaj SHA-256, virt-11.1 profili, RAM, beklenen/görülen seri işaretleri ve PASS/FAIL durumuyla ayrı JSON raporuna yazılır. Hata durumunda seri günlüğü test VM’i silinmeden önce kopyalanır.
assert.equal(files.length, expectedCount, 'one JSON report is required per QEMU boot');
const scenarios = new Set();
for (const name of files) {
const report = JSON.parse(readFileSync(join(directory, name), 'utf8'));
assert.equal(report.schemaVersion, 1);
assert.equal(name, `${report.scenario}.json`);
assert.ok(!scenarios.has(report.scenario), `duplicate scenario ${report.scenario}`);
scenarios.add(report.scenario);
assert.equal(report.status, 'pass', `${name}: boot failed: ${report.error}`);
assert.equal(report.machine, 'virt-11.1');
assert.ok(Number.isInteger(report.memoryMiB) && report.memoryMiB >= 256);
assert.match(report.imageSha256, /^[0-9a-f]{64}$/);
const currentHash = createHash('sha256').update(readFileSync(report.image)).digest('hex');
assert.equal(report.imageSha256, currentHash, `${name}: image changed after the test`);
assert.match(report.serialSha256, /^[0-9a-f]{64}$/);
assert.ok(report.expectedMarkers.includes('TURKOS/FRAME-TEST: PASS'));
YENİDEN ÇALIŞTIRsh scripts/verify.sh
BEKLENEN GÖZLEM
10 JSON raporu; her beklenen işaret görüldü; başarısızlık fikstüründe *.serial.log korundu
Kapsam sınırı: Raporlar yerel/geçici test artefaktıdır; imzalı sürüm kanıtı veya genel kullanım imajı değildir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
13 / İkinci RAM bankasını sessizce kaybetme
Hardware tek RAM aralığı taşıdığı için ikinci kök reg bankası güvenli biçimde Unsupported olur; kesik ikinci bankaysa Invalid. Bu, birden çok bankayı destekleme iddiası değil, veri kaybını önleme kapısıdır.
GERÇEK KAYNAK · kernel/src/dtb.rs
if ram.is_some() {
return Err(Error::Unsupported);
}
let pair_len = (address_cells + size_cells) * 4;
if bytes.len() > pair_len && bytes.len() % pair_len == 0 {
return Err(Error::Unsupported);
}
let (base, size) = reg(bytes, address_cells, size_cells)?;
if size == 0 || base.checked_add(size).is_none() {
return Err(Error::Invalid);
}
ram = Some((base, size));
GERÇEK TEST · kernel/src/dtb.rs
fn rejects_second_ram_range_in_one_reg() {
let mut blob = fixture();
let name = b"memory@40000000\0";
let reg_token = blob.windows(name.len()).position(|w| w == name).unwrap() + name.len();
let reg_offset = reg_token + 12;
let second = [0x5000_0000u64.to_be_bytes(), 0x1000_0000u64.to_be_bytes()].concat();
blob.splice(reg_offset + 16..reg_offset + 16, second);
// A second bank is not supported by the single-range Hardware contract.
let total = blob.len() as u32;
blob[4..8].copy_from_slice(&total.to_be_bytes());
let strings = be32(&blob, 12).unwrap() + 16;
blob[12..16].copy_from_slice(&strings.to_be_bytes());
let structure = be32(&blob, 36).unwrap() + 16;
blob[36..40].copy_from_slice(&structure.to_be_bytes());
let len_offset = reg_token + 4;
blob[len_offset..len_offset + 4].copy_from_slice(&32u32.to_be_bytes());
assert_eq!(discover(&blob), Err(Error::Unsupported));
// A malformed trailing bank must be rejected as invalid, not ignored.
let mut truncated = fixture();
let reg_token = truncated
.windows(name.len())
.position(|w| w == name)
.unwrap()
+ name.len();
let reg_offset = reg_token + 12;
YENİDEN ÇALIŞTIRcargo test --manifest-path kernel/Cargo.toml --lib --locked dtb::tests
BEKLENEN GÖZLEM
rejects_second_ram_range_in_one_reg … ok; ikinci bankanın ilk bankaya indirgenmesi yok
Kapsam sınırı: Çoklu RAM tahsisi hâlâ yok; tanınmayan topoloji açılışı kapalı reddedilir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
14 / 128 çerçeve ve iki uç kanaryası
Ayrı StressImage 128 benzersiz çerçeveyi eşzamanlı ayırır; her sayfanın ilk ve son 64-bit sözcüğünü yaz/oku/geri koy yapar, tüm çerçeveleri iade eder ve serbest sayfa toplamına döner.
GERÇEK KAYNAK · kernel/src/main.rs
const TEST_PAGES: usize = 128;
#[cfg(not(feature = "frame-stress-test"))]
const TEST_PAGES: usize = 16;
let initial_pages = free.total_pages();
let mut allocator = memory::FrameAllocator::new(free);
let mut frames = [0; TEST_PAGES];
for index in 0..TEST_PAGES {
let Some(address) = allocator.allocate() else {
return false;
};
if frames[..index].contains(&address) {
return false;
}
frames[index] = address;
// SAFETY: finalized free RAM excludes image, DTB and both reservation
// sources. Direct QEMU Image boot uses an identity-mapped RAM view.
unsafe {
let first = address as *mut u64;
let last =
(address + memory::PAGE_SIZE - core::mem::size_of::<u64>() as u64) as *mut u64;
let before_first = read_volatile(first);
let before_last = read_volatile(last);
let first_canary = 0x5455_524b_4f53_4652 ^ address;
let last_canary = !first_canary;
write_volatile(first, first_canary);
write_volatile(last, last_canary);
let passed = read_volatile(first) == first_canary && read_volatile(last) == last_canary;
write_volatile(first, before_first);
write_volatile(last, before_last);
Kapsam sınırı: Sayfanın tamamı değil iki sınır sözcüğü sınanır; tek CPU ve kimlik eşlemeli erken açılıştır. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
15 / Açık onaylı Image reseti
Reset komutu önce veri kaybı onayı ister. QMP system_reset aynı çalışan Image konuğuna iki kez gönderilir; üç BOOT0 görülür ve ikinci QEMU sahibi kilitte reddedilir. GUI de uyarı ve ayrı onay gösterir.
GERÇEK KAYNAK · src/lib.rs
fn reset_kernel(root: &Path, name: &str) -> Result<()> {
let dir = vm_path(root, name)?;
if !matches!(read_config(&dir)?.boot, Boot::Kernel { .. }) {
bail!(
"Yeniden başlatma yalnız Image VM'lerinde destekleniyor; UEFI konuğunu sıfırlamıyoruz"
);
}
qmp_command(&dir.join("qmp.sock"), "system_reset")
.with_context(|| format!("VM çalışmıyor veya QMP kopuk: {name}"))?;
Ok(())
}
YENİDEN ÇALIŞTIRcargo test --locked && node scripts/test-kernel-boot.mjs && node scripts/test-gui-macos.mjs
BEKLENEN GÖZLEM
İki yeni BOOT0; tek QEMU; GUI uyarı/onay ve CLI running eşleşmesi
Kapsam sınırı: UEFI/Alpine reseti kapalı; reset temiz kapanma veya kalıcı disk bütünlüğü garantisi değildir. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
16 / MMU açılmadan eşleme sahipliği
Saf planlayıcı RAM ile MMIO için ayrı nitelik ve izinler tutar. Hizasız, taşan, çakışan, korunan RAM veya tablo/veri çerçevesi çakışması ve çalıştırılabilir MMIO reddedilir; tablo çerçeveleri plan bırakılınca iade edilir.
fn out_of_frames_does_not_add_partial_mapping() {
let (mut frames, allowed) = allocator(2);
let mut plan = Plan::new(&mut frames, &allowed).unwrap();
assert_eq!(
plan.map(Mapping {
kind: Kind::Mmio,
physical_start: 0x0900_0000,
..ram(0x4000_0000, 513)
}),
Err(Error::OutOfFrames)
);
assert_eq!(plan.table_count(), 0);
YENİDEN ÇALIŞTIRcargo test --manifest-path kernel/Cargo.toml --lib --locked paging::tests
BEKLENEN GÖZLEM
7 paging testi; hata sonrası eşleme yok ve sayfa sayısı değişmez
Kapsam sınırı: İzinli FreeMap dışı RAM reddedilir; çekirdek imajını eşleyecek ayrı yetki kuralı, donanım descriptor, TTBR/SCTLR ve MMU etkinleştirme yok. İşlem gerekçesi ↗
ÇEKİRDEK / TEST KAYDI
17 / GICv3 ve timer keşfi, IRQ kapalı
QEMU virt DTB kökünden GIC distributor/redistributor ve non-secure fiziksel timer PPI okunur. Bilinmeyen GIC ve aralık dışı PPI reddedilir; seri günlüğü IRQ-MASK: ON gösterir.
GERÇEK KAYNAK · kernel/src/dtb.rs
pub fn discover_interrupts(blob: &[u8]) -> Result<InterruptHardware, Error> {
let size = total_size(blob)?;
if blob.len() < size || be32(blob, 20)? < 17 || be32(blob, 24)? > 17 {
return Err(Error::Invalid);
}
let blob = &blob[..size];
let structure = section(blob, be32(blob, 8)? as usize, be32(blob, 36)? as usize)?;
let strings = section(blob, be32(blob, 12)? as usize, be32(blob, 32)? as usize)?;
let mut cursor = 0;
let mut depth = 0;
let mut address_cells = 2;
let mut size_cells = 1;
let mut gic_node = false;
let mut timer_node = false;
let mut compatible: Option<&[u8]> = None;
let mut node_reg: Option<&[u8]> = None;
let mut interrupts: Option<&[u8]> = None;
let mut interrupt_cells = None;
let mut controller = false;
let mut disabled = false;
let mut gic = None;
let mut timer = None;
YENİDEN ÇALIŞTIRcargo test --manifest-path kernel/Cargo.toml --lib --locked && node scripts/test-kernel-boot.mjs
BEKLENEN GÖZLEM
GICD=0x08000000; GICR=0x080a0000; timer PPI=30; IRQ-MASK: ON
Kapsam sınırı: irq.rs yalnız ABI taslağıdır; IRQ vektöründen geri dönüş, ayrı yığın kullanımı ve timer kesmesi henüz yok. İşlem gerekçesi ↗
40 / 40 ÇEKİRDEK BİRİM TESTİ
Test adlarının tamamı
Bu liste kaynak dosyalarındaki #[test] işaretlerinden derleme sırasında okunur. Birim testleri QEMU açılışının yerine geçmez; DTB, bellek, eşleme planı ve IRQ ABI davranışını izole eder.
cargo test --manifest-path kernel/Cargo.toml --lib --locked
10 / 10 SANAL AÇILIŞ
Hangi imaj, hangi gözlem?
Image · 256 / 512 / 1024 MiB
BOOT0, DTB UART/RAM/GIC/timer, 16 çerçeve ve FRAME-TEST: PASS.
StressImage · 256 / 512 / 1024 MiB
128 benzersiz çerçeve; FRAME-COUNT=0x80, FRAME-EDGE: PASS ve FRAME-TEST: PASS.
PanicImage · 512 MiB
Normal bellek testinden sonra TURKOS/PANIC.
ExceptionImage · 512 MiB
BRK, SLOT=0x04, EC=0x3c ve korunan X0/X3/X30.
FaultImage · 512 MiB
UDF, SLOT=0x04, EC=0x00 ve farklı X0/X3/X30.
Image + özel DTB · 512 MiB
İlk dört sayfa atlanır; FRAME-ADDRESS=0x40004000.
Image 512 MiB senaryosu iki açık onaylı QMP resetiyle üç BOOT0 üretir. 9 standart senaryo scripts/test-kernel-boot.mjs, özel DTB senaryosu scripts/test-reserved-boot.mjs içindedir. Her açılışın imaj kimliği ve seri gözlemi ayrı JSON raporunda tutulur; VM'ler test sonunda kapatılır. GUI kabulü ayrı macOS testiyle ölçülür; gerçek Mac üzerinde doğrudan çekirdek açılışı bu matrise dahil değildir.
SONRAKİ KANIT KAPISI
Geçmeyen katmanı geçmiş gibi göstermiyoruz.
UEFI çekirdek yükleyicisi, MMU, IRQ, GIC/zamanlayıcı, EL0 görevleri, virtio blok sürücüsü ve gerçek Apple donanımı açılışı bu kayıtta PASS değildir. Yeni bir özellik eklendiğinde aynı kalıp kullanılacak: kaynak satırı → test kodu → komut → beklenen çıktı → açık sınır.