Files
UniXNU/drivers/NativeRamBlock/SparseDisk.h
T
2026-10-19 18:49:31 +08:00

61 lines
2.5 KiB
C++

// SPDX-License-Identifier: BSD-2-Clause-Patent
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <string.h>
struct RamSparseDisk {
uint8_t **pages;
uint64_t bytes, resident;
};
static uint32_t ramU32(const uint8_t *p){uint32_t v;memcpy(&v,p,4);return v;}
static uint64_t ramU64(const uint8_t *p){uint64_t v;memcpy(&v,p,8);return v;}
static bool ramPackedLayout(const uint8_t *p,uint64_t n,uint64_t *logical) {
if(!p || n<32 || n>0x10000000 || memcmp(p,"DBRDISK1",8) || ramU32(p+8)!=1 || ramU32(p+12)!=4096)return false;
uint64_t size=ramU64(p+16),count=ramU64(p+24),end=0;
if(!size || size>0x80000000 || (size&4095) || count>65536 || count>(n-32)/16)return false;
uint64_t cursor=32+count*16;
for(uint64_t i=0;i<count;++i){
uint64_t at=ramU64(p+32+i*16),len=ramU64(p+40+i*16);
if(!len || ((at|len)&4095) || at<end || at>size || len>size-at || len>n-cursor)return false;
end=at+len;cursor+=len;
}
if(cursor!=n)return false;
*logical=size;return true;
}
template<class Ops> static bool ramSparseImport(RamSparseDisk &d,const uint8_t *p,uint64_t n,Ops &ops) {
uint64_t size=0;if(!d.pages || !ramPackedLayout(p,n,&size) || d.bytes!=size || d.resident)return false;
uint64_t count=ramU64(p+24),cursor=32+count*16;
for(uint64_t i=0;i<count;++i){
uint64_t at=ramU64(p+32+i*16),len=ramU64(p+40+i*16);
for(uint64_t j=0;j<len;j+=4096){
const uint8_t *src=p+cursor+j;uint8_t any=0;
for(unsigned k=0;k<4096;++k)any|=src[k];
if(!any)continue;
uint8_t *page=ops.allocate();if(!page)return false;
memcpy(page,src,4096);d.pages[(at+j)/4096]=page;d.resident+=4096;
}
cursor+=len;
}
return true;
}
// Caller serializes I/O. Ops performs genuine descriptor reads/writes and
// zero-initialized allocation. Short copies preserve truthful byte counts.
template<class Ops> static uint64_t ramSparseIO(RamSparseDisk &d,bool write,uint64_t offset,uint64_t length,Ops &ops,bool &noMemory) {
static const uint8_t zero[4096]={};noMemory=false;
if(!d.pages || !length || offset>d.bytes || length>d.bytes-offset)return 0;
uint64_t done=0;
while(done<length){
uint64_t at=offset+done,index=at/4096,skip=at&4095,n=4096-skip;
if(n>length-done)n=length-done;
uint8_t *page=d.pages[index];
if(write && !page){
page=ops.allocate();if(!page){noMemory=true;break;}
d.pages[index]=page;d.resident+=4096;
}
uint64_t actual=write?ops.read(done,page+skip,n):ops.copy(done,(page?page:zero)+skip,n);
if(actual>n)break;
done+=actual;if(actual!=n)break;
}
return done;
}