Aros/平台/68k 支持/开发者/Exec
如果我将地址从
- 主 ROM (0xf80000 - 0xffffff)
ROMLOC_rom := 0x0f80000 to 0x4FF80000 - 4FF8ffff
我是否需要告诉 arosbootstrap,还是它会遵循该指针?Arosbootstrap 与任何类型的外部地址重新映射不兼容。该地址用于构建正常的 2x512K ROM 映像,arosbootstrap 使用可重定位的 ELF 映像。
请注意,ROM 会检测到 arosbootstrap 模式,并自动使用 MMU(如果可用)将“ROM”重新映射到快速 RAM,如果 arosbootstrap 最初将其加载到芯片 RAM 中(如果可用快速 RAM 不兼容,例如 Blizzard A1200 加速器的快速 RAM 有这个问题,因为它不是自动配置)。检查日志中的 MMU 消息。
它显然必须是 UBYTE m68060[0x12];我想 mc68060 在为 68060 编译时与其他一些编译器变量冲突。该联合仅用于为最大的 FPU 堆栈帧(68882)保留空间,变量名并不重要。(也许用 fpu_?作为前缀)
注意到 InternalLoadSeg_ELF 的一个奇怪的特性。
它对传入的 BPTR 进行 Seek() 调用。现在,这本身并不奇怪,除了当 funcarray[] 对 Read 有一个覆盖(见 workbench/c/AddDatatypes.c)它对内存中的数据结构而不是文件进行操作时。
因为我也需要内存中的搜索功能来将 GZIP 压缩的 ELF 文件加载到 RAM 中(别问),所以修改了 InternalLoadSeg 及其相关函数,使用第四个 funcarray 成员(覆盖 Seek)来提供此功能。
PPC 维护者:请仔细检查我对您文件的工作,以及它们是否可以合并回 rom/dos/internalloadseg_elf.c
Exec/ShutdownA(SD_ACTION_POWEROFF) 是否为任何 Amiga 机器定义?如果是,我需要做些什么才能让该机器关机?在任何 Amiga 型号中都没有软电源硬件。
对于其他机器,使屏幕完全变黑的最快方法是什么?(这可能是一个铜列表,对吗?)。据我所知,每个图形驱动程序都会安装一个重置处理程序钩子,该钩子会使屏幕变黑。重置处理程序可能不会在 ShutdownA(SD_ACTION_POWEROFF) 上被调用,但也许应该。
打开窗口似乎需要很多内存。AROS 是否为每个窗口分配了一个完整的位图?还是我的打开方式不对?有没有一个神奇的 OpenWindow() 标签说“没有后备存储”?只有智能刷新窗口应该使用额外的窗口位图(至少在 AOS 上是这样)。
事实证明,Deallocate() NULL 是问题所在。我已经提交了一个修复程序,使 NULL 的 Deallocte() 成为一个无操作。今晚我会恢复 UAEGfx 的更改。
task->tc_Launch()、task->tc_Switch() 和 Exec/Exception() 应该在什么特权模式下运行?
我想应该是用户模式,但考虑到 core_Dispatch 可以从 Switch() 中调用,这意味着 tc_Launch() 可以在管理模式下执行吗?
另一个重要的缺失部分似乎是 expansion.library 自动配置板处理(以及棘手的额外功能:如果检测到快速 RAM,则将 exec/管理程序堆栈重新定位到快速 RAM)。这将比 Exec/Dispatch() 和 Exec/Supervisor() 实现更简单!
但是,您可能需要查看 exec/child* 系列调用,因为它们看起来以一种奇怪的方式进行类型转换,例如
child = FindChild((ULONG)tid);
我不知道这对 x86_64 是否安全,我不知道您的 tid 实现。
一个典型的 68k 汇编编码的 PutChProc 函数执行
move.b d0,(A3)+ rts
A3 = PutChData(通常是字符串缓冲区),并且该函数依赖于获得修改后的 A3(指向要插入的下一个字节/字符),下次调用 PutChProc 时。
例如:“Hello”,A3 = 0x100000
call PutChProc("H", 0x100000) call PutChProc("e", 0x100001) call PutChProc("l", 0x100002) call PutChProc("l", 0x100003) call PutChProc("o", 0x100004)
所以 A3 基本上是一个输入+输出参数,而不仅仅是输入参数。
您也可以尝试在真实的自动配置快速 RAM 中(在 ConfigChain() 调用之后)获得 exec(如果您还有太多空闲时间)。您是在谈论移动“启动任务”堆栈,还是将整个 Exec 从 ROM 移动到 RAM?不,我的意思是只有 execbase。官方的 2.0+ ROM 会将 execbase 移动到真实的自动配置快速(而不是 0xc00000 慢速 RAM)RAM,如果它存在。这样做是因为芯片 RAM 和“慢速 RAM”(实际上与芯片 RAM 具有完全相同的速度)在真正的 Amiga 上相对较慢。这很容易做到。我将其添加为一个架构函数到 rom/expansion 或 rom/strap 中。
关于动态重定位
我试图将可重定位的 1M ROM 映像加载到可用快速 RAM 的末尾。从技术上讲,它已经可以工作,但是对于在重置过程中消失的自动配置 RAM 板存在问题。(UAE Z3 板不会,至少在 WinUAE 中不会,A3000/A4000 主板 RAM 也是“安全的”)
1: 让原始 KS(位于 ROM 中)执行自动配置操作,并添加 coolcapture/kicktag hack,将 ConfigDevs 复制到 AROS 扩展列表中。- Aros 自动配置实现未使用。这不会帮助我们发现任何错误。- KS 扩展行为可能具有无法记录的功能,这些功能可能会破坏复制阶段。
2: 将 coldcapture/kicktag 放置到芯片 RAM,它指向 AROS expansion.library(也位于芯片 RAM 中)。它首先运行自动配置(启用“rom”所在的 RAM 板),将数据存储在芯片 RAM 中,跳到 AROS ROM,AROS ROM 会检测到这种情况,并且只收集自动配置数据,而不会再次运行自动配置。- 是否可以拥有一个单独的可重定位文件,其中只包含 expansion.library?(Jason?)- 无法使用任何 exec 例程,需要一些修补。(只使用绝对芯片 RAM 地址,没有人关心,它们是临时的)(是的,我知道芯片 RAM 在执行重置时也会被 ROM 暂时替换,但这一点可以解决,即使在没有崩溃的 68000 上也是如此。甚至有一个游戏将此用作复制保护的一部分)。
3: 只复制当前的自动配置数据,然后跳到 RAM 中的 ROM 映像,而无需重置。只工作一次(任何重置都会破坏它),任何引导 ROM 板对 AROS ROM 都是不可见的。对我来说太愚蠢了 :)
选项 2 并不容易,但它将与所有 Amiga 模型兼容(只要它至少有 1M 的快速 RAM)。只要需要特定的硬件或 EPROM 刻录器,对“普通”用户来说测试就太难了。(不幸的是,您必须对所有板进行自动配置,您无法选择特定的 RAM 板,除非该 RAM 板是自动配置链中的第一个板,但我认为您不能假设这一点。)
WHDLoad 是如何做到的?我们可以生成 WHDLoad 可以使用的 ROM 映像/重定位映射吗?它使用 .RTB 文件,这些文件也是某种重定位文件(据我所知,它们最初由一些 ROM 映像加载器使用)。但就我个人而言,我更喜欢将所有内容放在单个文件中,因为混用不同版本太容易了(也许甚至应该包含加载器,像“伪覆盖”文件一样的 titanic 压缩器很容易创建)。无论如何,在拥有可用的 expansion.library 自动配置 hack(+ Gayle IDE 驱动程序端口)之前,我并不太在意。
在 m68k-amiga Disable() 中删除了 softint 检查(r36842),并将所有处理移至 Cause(),因为 m68k Disable() 和 Enable() 应该尽可能短和快。使用 Paula 中断时,softint 是“自动的”,因此无需在每次 Enable() 调用中检查它们。(m68k-amiga 中断处理可能应该完全使用汇编语言,如果这个东西要在 A500 上有用,它需要真正优化。但现在还为时过早。)
崩溃发生在调用 sprintf() 时。 sprintf() 不在 arosc.library 中吗?当然,你可以始终用调用 RawDoFmt() 来替换它,并移除对 arosc.library 的依赖。我有点想对所有 workbench/c 都这样做(移除对 arosc.library 的依赖)
AOS 3.1 iPrefs 实用程序会修补 RawDoFmt() 以进行本地化,并且不理解 AROS 的“魔术”常量
- RAWFMTFUNC_STRING
- RAWFMTFUNC_SERIAL
- RAWFMTFUNC_COUNT
Would anyone mind if I made those 'magic constants' point to real m68k functions on AROS m68k, for better 3.1 support? It changes the magic constants for m68k to point to functions, but continues to support the 'NULL == RAWFMTFUNC_STRING' assumption of AOS 4.x and Morphos.
加载 locale.library,让它修补 AROS 的 RawDoFmt,然后也修补它,使用一个包装器将特殊代码正确地翻译成真实函数。在退出 SetPatchAROS 之前,请记住在卸载 locale.library 之前取消修补 RawDoFmt。我更喜欢这种方式,而不是弹出窗口。它在 Exec/SetFunction 中会有点 hacky,但可行。
因此 WB locale.library SetFunction() 的 RawDoFmt(),然后需要非 AOS 扩展(RAWFMTFUNC_STRING 及其他)的 AROS 程序停止工作,对吧?扩展 RawDoFmt() 是个坏主意。RawDoFmt() 应该只做原始 Autodocs 中说明的事情,所有 AROS 程序都应该使用 VNewRawDoFmt()。解决方案:替换或添加包装宏,用 VNewRawDoFmt() 包装所有 AROS RawDoFmt() 调用。嗯,虽然这确实修复了 WB 在 AROS 上的问题,但它使得 AOS ROM 上的 AROS 用户空间几乎不可能(在 AOS exec.library 向量空间中没有空间),除非 SetPatchAROS 重新定位并扩展 exec.library。在这种情况下,我最好做一个外部的“exec.library”来替换 AOS 的那个。
事实
- AROS RawDoFmt() 接受“特殊”PutChFunc 向量 0、1 和 2
- AOS RawDoFmt() 假设 PutChFunc 始终指向一个有效函数
- AOS locale.library 使用 SetFunction() 将 Exec/RawDoFmt() 更新为具有 AOS PutChFunc 约定的一个
APTR realRawDoFmt; AROS_UFP4(fixupRawDoFmt, blah, blah) { If PutChProc is a magic vector, make it a real function. Call realRawDoFmt; } ... Exec/SetFunction (AROS) ... if (library_to_patch == SysBase && function_to_patch == LVO_RawDoFmt) { realRawDoFmt = vector_of_patch; vector_of_patch = fixupRawDoFmt; } Set library_to_patch -> function_to_patch = vector_of_patch
这实际上比我想到的要好,因为它不依赖于 locale.library,但任何试图修补 RawDoFmt() 的东西都会得到它的包装器。如果你不认为 hackish 修补 SetFunction() 本身。现在 AROS 的 locale.library 修补 RawDoFmt() 时会发生什么?它也会经过魔法到真实函数转换器的修正,这会在每次调用中添加 16 个 m68k 指令。我们将把 rom/exec/setfunction.c 中的所有与 m68k 相关的代码移动到 arch/m68k-all/exec/setfunction.c 中,这样它实际上将成为其他体系结构的“清理”。这些 AOS 兼容性 hack 应该明确标记还是放在一些 ifdefs 中?(它们应该易于查找,否则有人迟早会忘记它们,这会变得非常混乱。)在 arch/m68k-all/exec/setfunction.c 中添加广泛的注释
我唯一能想到的问题
- 有人试图替换 RawDoFmt 会移除链,并在他的替换中获得未转换的值。
- 碰巧将 RawDoFmt 链接到捕获完全相同的值的人必须实际接收它们
但是从调用来看,我们无法区分链和替换,因此我们如何知道是否必须向该修补程序添加转换器修补程序呢?
这是一个非常小的问题,因此取决于我们想要保证完全兼容性,还是仅仅一个好的近似值。
此外,我认为没有取消修补。我不确定这是否会造成明显的问题。
但如果 VNewRawDoFmt 使用了这些常量,它是否必须与它们进行检查?为了比较,它们实际上是静态函数指针并不重要。并且由于是符号化的,比较是识别它们的唯一允许的操作。
由于 AOS 没有扩展的任务结构,因此此代码将 acpd 设置为 NULL->iet_acpd。修复 arosc 不要使用任务结构中的私有字段。你可以使用 AVL 树进行关联(OS3.5+)。或者在 arosc 中静态地复制这些函数。还请记住,arosc.library 依赖于一些其他 AROS 扩展,例如 NewAddTask() 和 NewStackSwap()。
ACPI。内核/exec 初始化很棘手,可能无法一次完成。Exec 已经被初始化了两次(甚至三次,如果我们计算内核.resource 的获取)。内核.resource 应该在优先级 127 初始化,因为将来即使 AllocMem() 也将无法在没有它的情况下工作(它将在内核的页面分配器之上工作)。
用于在 PrepareExecBase 之前进行调试。为此,你拥有 kernel_debug.h 中的 bug() 宏。在内核.resource 中进行非常早期的调试时,你可以使用内核自己的 bug() 定义,它静态地调用 KrnBug()。它不以任何方式使用 exec。并且 exec 的设施在调用 exec 的 init 代码后启动并运行,这会填充 KernelBase。请注意,除了内核.resource 的启动代码外,没有其他代码可以在 PrepareExecBase() 之前运行。还要记住 KrnPutChar() 和内部 krnPutC()。
我如何早早启用 SAD?我目前有一个(许可证很糟糕的)m68k-gdbstub,我正在使用它为我的 ROM 提供调试,当我提交时必须删除它。在你的内核.resource 中实现 KrnPutChar() 和 KrnMayGetChar(),它就可以工作。请注意,Alert() 不会调用它,因为当前的警报例程非常基本,不会处理任何输入。这是因为 PC 上没有通用的输入硬件。事实上,这需要改进。也许警报需要接管屏幕,在上面打印信息,然后接管输入,并从它那里请求一些命令。RFC,我写了关于调试通道的文章,是实现这种机制的一小步。
供列表审查。此修补程序启用“--with-paranoia”./configure 选项,并在 rom/exec 中提供一个使用示例。
语义
./configure => 没有 paranoia ./configure—with-paranoia => PARANOIA_CFLAGS=-Wall -W -Werror ./configure—with-paranoia=-Wmega => PARANOIA_CFLAGS=-Wmega
这允许(a)构建过程没有变化,(b)开发者*为他们自己*启用 paranoia,以及(c)开发者*仅*在他们认为干净的目标上启用 paranoia。这样,一旦库中所有的 -Wall 问题都被清除,它就会保持这种状态。
人们使用不同的编译器版本(*),这些版本报告不同的警告——例如,现在 4.4 系列在没有调试的情况下编译时会报告大量严格别名问题。我们可能会最终陷入这样一种情况,即某个模块为 10 个人中的 9 个人构建,但不幸的 1 个人无法或不愿意进行修复。
虽然同意 -Wall 中的一些警告。其中一些可能是错误的(例如,“变量 x 可能没有初始化”),或者试图强制执行特定的编码风格(例如,“考虑在用作真值的赋值周围使用括号”)。
我们的目标是避免使用 -fno-strict-aliasing 来提高性能。
我认为 USER_CFLAGS 在 mmakefile 中被过度使用;IMO 它应该只在某些符号需要定义等特殊情况下使用。大多数程序/库应该使用 configure 生成的默认 CFLAGS 进行编译。
BRA := "\(" KET := "\)" TST := "test$(BRA)test$(KET) test" USER_CFLAGS := -DDEFINE=\"$(TST)\"
或者
USER_CFLAGS := -DDEFINE=\"test\(test\)\ test\"
最后一个括号后面的反斜杠真的有必要吗?我认为它只在需要指定后续字符为特殊情况时才需要?是的,它需要转义空格并将整个内容作为一个命令行参数。
此外,你不需要复制调试函数。还有一个关于 GDB 桩的问题。也许你应该考虑将它集成到现有的 SAD 中?能够使用 gdb 远程调试任何机器将非常棒。不幸的是,gdb 桩非常特定于机器。我相信它们需要为每个端口重写。我计划在 SAD 工作后移除 GDB 桩。
不幸的是,gdb 桩非常特定于机器。我相信它们需要为每个端口重写。我计划在 SAD 工作后移除 GDB 桩。好吧,SAD 确实需要改造了。它是一个非常古老的东西。
此消息主要针对 Jason 和 Toni。如果你查看 arch/all-<cpu>/include/aros/<cpu>/cpucontext.h,我已经为除 m68k 之外的所有体系结构编写了 CPU 上下文定义。指向此类结构的指针将在两个地方使用
- 它作为第三个参数传递给内核异常处理程序(使用 KrnAddExceptionHandler() 添加)。
- 它作为第二个参数传递给 exec 陷阱处理程序(tc_TrapCode)。
这主要目的是统一和扩展崩溃处理代码,并为第三方开发者提供编写调试工具的可能性,这些工具可以捕获异常并分析任务状态。PowerPC 上下文与 AmigaOS4 兼容。我希望 m68k 上下文与 m68k AmigaOS 兼容。我知道在 m68k 上
tc_TrapCode gets the whole context frame on the stack, this should be the only difference to other ports. I. e. on m68k we should take context pointer as follows:
void MyTrapHandler(ULONG trapCode) { struct ExceptionContext *regs = (struct ExceptionContext *)(&trapCode + 1); ... process exception here ... }
你还需要编写特定于 m68k 的 cpu_init.c、KrnCreateContext() 和 PrepareContext()。请参考其他体系结构的示例。
简要说明
- kb_ContextSize 需要设置为上下文的总大小。
- kb_ContextFlags 可以用于任何你想要的目的。i386 和 ARM 使用它来指定 FPU 类型。也许你根本不需要它,因为在 m68k 上你拥有 SysBase->AttnFlags。这两个变量由 cpu_init.c 设置,它执行启动时 CPU 探测。
KrnCreateContext() 分配上下文帧并设置一些初始数据(如果需要)。常见用途是创建初始 FPU 帧。CPU 上下文的公共部分应该是 sizeof(struct AROSCPUContext)。这是托管端口所必需的,因为在托管上,你需要将一些特定于主机的私有数据存储为 CPU 上下文的一部分。如果你查看托管 CPU 定义,你将在 struct AROSCPUContext 的开头看到 struct ExceptionContext。在本地,你只需
#define AROSCPUContext ExceptionContext
可选数据(如 FPU 上下文)跟随同一个块中的 struct AROSCPUContext。
PrepareContext() 没有改变,我只是扩展了所有宏。由于上下文是统一的,你不再需要为每个端口定义相同的宏。
kernel_cpu.h 中唯一仍然需要的旧宏是 GET_PC 和 SET_PC。它们由 exec 的崩溃处理程序使用。它们将在一段时间后消失。PRINT_CPU_CONTEXT 事实上打印了无用的内容,所以你可以安全地移除它。Debug() 将在没有它的情况下工作。
应该记住,BPTR 在(所有?)其他端口上并不真正存在。
> struct ExceptionContext
这是 AROS 侧上下文的公共形式。这是 AROS 异常处理程序期望获取的内容。在使用相同 CPU 的所有架构上,它都是相同的。
> regs_t
这是 CPU 生成的原始堆栈帧。在托管 AROS 中,它是主机操作系统上下文结构的别名。在本地,它可能与 ExceptionContext 相同。
> struct AROSCPUContext
ExceptionContext + 私有部分。在托管环境中(您保存主机特定的内容)是有意义的。在本地,它应该与 ExceptionContext 相同。struct AROSCPUContext 在开头包含 struct ExceptionContext。
> ucontext
上下文的 UNIX 名称。regs_t 是它在 UNIX 托管环境中的别名。
> 我试图让 m68k 与所有其他架构相似,但陷阱/异常区域发生了很多变化,并且文档太少了(或者至少我不知道文档在哪里)。
这是一个新设计的东西。我在源代码中提供了一些注释,我希望这足够了。对不起,我现在时间不多,甚至不能积极地阅读邮件列表。所做工作的核心思想是统一每个 CPU 的 CPU 上下文格式。因此,struct ExceptionContext 在同一个 CPU 上是相同的,无论它是托管系统还是本地系统。是的,我研究过 AmigaOS exec 陷阱处理,我知道这个怪癖。我建议使用 asm 存根。我在代码中注释了这一点。
请在您的评论中放置指示器 FIXME 或 TODO,以表示需要稍后注意的事项。这使得稍后更容易找到它并且不会忘记它。例如
/* fetch Task pointer before function call because A6 can change inside initialPC * (FIXME: temporary hack) */
添加 MoveExecBase(),以便 m68k-amiga 端口可以使用它将 exec 从芯片/慢速 RAM 移动到自动配置快速 RAM。出于好奇:这在 WinUAE 上会带来任何改进,还是针对实际硬件?在实际硬件中,execbase 或任何其他通常访问的芯片 RAM(或“慢速”RAM)中的系统结构会导致明显的减速,尤其是在加速的 OCS/ECS Amiga 上。
16 位 OCS/ECS 芯片 RAM 与加速器 32 位快速 RAM 之间的速度差异可能很大,而且芯片 RAM 也不可缓存。
KS 2.0 是第一个正式的 ROM,引入了将 exec 传输到快速 RAM 的功能。
(如果我们想要工作重置证明程序,这将变得非常棘手)
调度程序
[edit | edit source]您需要使用现有的 kernel.resource。它已经具有完整的调度程序,您只需要编写特定于 CPU 的代码,就可以完成。查看 rom/kernel/kernel_schedule.c 中的 core_* 代码。
请注意,将来可能会出现更好的调度程序(请记住 KrnSetScheduler() 函数)。另一个注意:启动代码(start.c)在引导目录中,恕我直言,最好位于内核目录中,因为它实际上是 kernel.resource 的一部分。
查看 Windows 托管和 UNIX 托管端口。它们是最新的,它们是使用最新模型设计的。x86-64 和 PPC 端口只是比较旧,它们没有使用公共代码,但它们是我的实现的基础。我只是没有重写它们,因为我没有这些机器并且无法测试。实际上,引导目录包含一个外部引导程序,它应该将 kickstart 映像加载到机器的 RAM 中并执行它。在 Amiga 上,kickstart 位于 ROM 中,它不需要任何引导加载程序(好吧,如果你不重新刷新 ROM 而是以编程方式重新启动 Amiga,它可能有一个引导加载程序,在这种情况下,kickstart 交换器将是你的引导程序)。
当我完成 kernel.resource 重写时,我写了它。它在某些地方仍然不完整,并且缺少移植 HOWTO。
确保任务切换仅在从监督模式返回用户模式时完成,而不在从监督模式返回监督模式(中断内部中断)时完成。很久以前,x86 本地也有类似的消失任务问题,这是由 exitintr 处理中错误的“我们是否返回用户模式”检查引起的。arch/m68k-amiga/kernel/amiga_irq.c 中的代码仅在返回用户模式时调用 core_ExitInterrupt()。当然,我可能是错的。我很乐意让第二个人看看我的 arch exec 和内核代码,现在我已经更接近标准约定。系统调用在 amiga_irq.c 中处理(通过 F-Line 陷阱),并且仅针对用户模式,所有其他中断要么陷阱到调试器,要么(对于 Paula 中断)通过 amiga_irq.c 中的 Paula 处理程序。
在慢速处理器下,它更明显,任务切换必须尽可能快。它与调度程序无关,问题是处理程序进程优先级太低。太低的优先级 dos 数据包处理程序和某个人使用所有 CPU 时间 = 控制台和文件系统 io 爬行。您可以在 AOS 上轻松确认它,方法是将所有处理程序进程的优先级更改为零或更低 : )
Sysbase
[edit | edit source]在 expansion.library 和 scsi.device 中,似乎存在专门制作的 16 位非法指令,'原始' Exec 会查找这些指令并为捕获它们后适当地设置 D0。是否有任何地方有这些'非法指令'陷阱的文档?您必须使用 Amiga Forever 3.x ROM(s),它们至少有一条特殊的非法指令,使其与真实的 Amiga 不兼容(UAE 有一个 rom 检查黑客修复了这个问题)。据我所知,它是许可证的一部分,rom 镜像不能在真实的 Amiga 上使用。确保您拥有真正的原始 kickstart rom 镜像。
解决方案是确保当您拥有'SysBase'时,它是全局的,而不是本地副本。
SysBase = PrepareExecBase(...)
一个小问题:你为什么认为 PrepareExecBase() 不应该设置全局 SysBase?我记得有一次我也想出了这样的想法,只是因为我认为它看起来不好。改变之后,我意识到自己错了多少。许多意想不到的地方可能依赖于全局 SysBase。我记得我在某个地方有早期的调试输出,这破坏了它。也许那个输出甚至都不存在了,但这证明了这个想法很糟糕。全局 SysBase 应该尽早设置。这意味着 - 在 PrepareAROSS 之前。被 PrepareExecBase() 如何返回 SysBase 所误导,以及它所有的调用者都将它用作'SysBase = PrepareExecBase()'。它看起来就像 PrepareExecBase() 缺少一个本地'struct ExecBase *SysBase'的错别字。也许 PrepareExecBase() 应该返回 void,以便它的调用者必须 *显式* 获取全局 SysBase?
此外,goUser() 是否应该始终降级到用户特权,或者恢复 goSuper() 之前存在的特权?它切换到用户模式。还有 goBack() 定义,它跳转到 goSuper() 记住的先前模式。
最后一点 - 任务->tc_Launch()、任务->tc_Switch()、Launch 和 Switch 回调是在监督程序内部直接调用的,我相信这是可以的,我认为原始的 Amiga 也这样做。无论如何,您不会在这些回调中执行长时间运行的操作。
以及 Exec/Exception() 应该在什么特权模式下运行?Exception()(与 AmigaOS 不同)是在完成所有特定于架构的准备工作后调用的,您处于任务上下文中的用户模式。此代码只检查信号并调用相应的例程,它不包含任何特定于架构的代码。
为了正确处理异常,您需要将任务的上下文(cpu_Dispatch() 将要跳转到的上下文)保存到某个地方,然后调整上下文,以便您的任务跳转到异常处理程序。处理程序应该调用 exec 的 Exception(),然后它应该获取原始任务的上下文(您在 cpu_Dispatch() 中保存的上下文),并跳转到它。
结果看起来就像您的任务只是调用了它的异常处理程序。您可以查看 Windows 托管实现,这是一个工作示例。UNIX 托管实现不起作用(至少在 PPC 上不起作用)。在本地端口上,异常也不起作用。请注意,在 m68k-native 上,您 100% 知道您的堆栈上发生了什么,因此您不需要使用将上下文传递给异常处理程序的技巧。您可以将其直接保存到任务的堆栈上(这是 UNIX 托管版本所做的,也是它不起作用的原因)。
中断
[edit | edit source]在我的最后一次更改中(我记得在进入 cpu_Dispatch() 中的 CPU 空闲状态之前重新启用硬件中断),我似乎能够进入 KickStart 1.3 Intuition 空闲循环。
但是,我似乎遗漏了一些东西,因为(除了一个漂亮的白色屏幕)我什么也没得到。
我认为我需要调用 KS 的“strap”或“romboot.library”,或者 AROS 的“dosboot.library”,但我不知道应该从哪里调用它们。FWIW,AROS 的 strap 是由于它位于驻留列表(优先级 -50)中而调用的。请参阅 rom/boot/strap.c。
strap 模块在 dos 初始化之前在真实的 rom 中执行磁盘块读取,它似乎没有很好的文档记录。
信号量
[edit | edit source]我遇到了一些结构布局问题,因为当我尝试从 AROS exec 初始化 KickStart 3.0 库时,我得到了 MH 免费列表的损坏。(奇怪的是,它们似乎初始化了很多。内存损坏发生在 expansion.library 中,在调用 Exec/InitSemaphore 之后,以及另一个似乎在 Intuition 调用 Graphics/Screen OpenScreen 时发生的损坏 - 可能都是相同的结构)> Amiga os 3.1 的一个很好的来源是 .i 包含文件,它们是 AmigaOS 结构的字节级布局的良好参考?(即 SignalSemaphore 等)。
您的编译器是否使用 WORD(2 字节)对齐来处理 LONG 等,正如 AOS 所期望的那样?如果不是,您可能需要像 AOS4/MOS 中那样在头文件中包含以下内容
#pragma pack(2) [...] #pragma pack()
NewAddTask 想要将堆栈对齐到 16 字节。我已经在 AROS_FLAVOUR_BINCOMPAT 中关闭了它。例如,PPC 端口需要这种对齐方式。当然,其他端口可能不需要它。
我在 KS 3.1 上注意到,Exec/InitStructure 的一些调用者将大小字段的第 16 位设置为 1。不知道为什么。现在,我必须将其屏蔽掉(这将 InitStructure 限制为只能处理大小不超过 64k 的结构)。
这可能是函数的一个情况,其中原始函数只查看低 16 位,即使库原型对参数说的是 LONG 或 ULONG。因此,高 16 位可能包含垃圾,而其他一些代码可能依赖于此(== 在调用函数时实际上在高 16 位中包含垃圾)。
您也可以在其他地方看到这一点,例如 graphics.library。在某些函数中,我们使用
x = (WORD)x
(FIX_GFXCOORD 宏)来清除高 16 位中的垃圾。
例如,如果原型是 LONG,预期值宽度是 WORD,传递的垃圾 < 0,那么为什么类型转换应该足够呢?
x = (WORD) (x & 0x0000FFFF)
确保您只获得低 16 位?我在 x86(gcc 4)和 68k(gcc 2.95)上尝试过,它在那里起作用。
#include <stdio.h> void func(int param) { int fixed = (short)(param); printf("%d (%x) %d (%x)\n", param, param, fixed, fixed); } int main(void) { func(0xF234fffe); }
-231407618 (f234fffe) -2 (fffffffe)
你说得对——当从(无符号或有符号)长整型转换为(无符号或有符号)短整型时,C 语言的规则似乎是保留低位字。我个人更喜欢“&”符号,因为它直观地展示了操作过程,而不是需要记住编译器根据某种隐含的约定所进行的操作。
在修复 i386-pc exec 初始化的过程中,我再次遇到了 SysBase->MaxLocMem。AmigaOS 3.x NDK 将其描述为“最大芯片内存量”。如果是这样,为什么不能通过检查 MemList 并将所有 MEMF_CHIP 内存大小相加来设置它?为什么需要对地址进行一些神奇的处理?它的确切值是什么?关于 MaxExtMem 也有同样的问题。我想为所有平台正确地实现它。
MaxLocMem 是芯片 RAM 的大小(等于 AOS 上芯片 RAM 的最后一个地址 + 1)
MaxExtMem 是“慢速”/“Ranger” RAM 的最后一个地址 + 1(不是大小!)(0x00C00000)。没有慢速 RAM = NULL。它永远不会包含任何其他本地 RAM 区域。
我认为这些设计并非为了支持多个内存区域。
文档(和原型文件)说明返回值类型为 BYTE,但许多程序(包括 WB1.3 system/setmap)都假定返回值类型为 LONG。KS1.3 和 3.1 OpenDevice() 都会获取 io_Error,然后将其扩展(EXT.W D0 + EXT.L D0)为 LONG,然后再返回。哪个是错误的,文档还是实现?(或者两者都不是? :))
(m68k-amiga 端口已经有扩展 OpenDevice() 返回码的黑客程序,但会被 dos lddemon 钩子覆盖)
在 rom/dos/endnotify.c 中
/* get the device pointer and dir lock. The lock is only needed for * packet.handler, and has been stored by it during FSA_ADD_NOTIFY */ iofs.IOFS.io_Device = (struct Device *) notify->nr_Handler; iofs.IOFS.io_Unit = (APTR)notify->nr_Reserved[0];
“iofs.IOFS.io_Unit”是一个指针,而 notify->nr_Reserved[0] 是 ULONG。
这个代码位置和 FSA_ADD_NOTIFY 需要处理 64 位指针。
目前没有解决方法。
在 rom/dos/deviceproc.c 中
/* all good. get the lock and device */ SetIoErr(dvp->dvp_Lock); res = dvp->dvp_Port;
问题是 dvp->dvp_Lock 是一个 BPTR,它不能(安全地)在 x86_64 下转换为 LONG。由于他的函数被标记为已弃用,我认为它应该在 x86_64 下抛出 ERROR_DEVICE_NOT_MOUNTED。我不确定这样做是否可行,可能我们在整个代码库中做了很多假设,才让它变得简单,但一种想法是将 BPTR 视为一个不透明的句柄:在 x86 上,它只是一个指针,出于速度考虑,而在其他不允许这种“优化”的架构上,它可能是一个指向某种字典的键(使用哈希表、二叉树或类似的东西实现)。
将 pr_Result2 更改为 SIPTR 会有什么危害吗?
这是我们位于 trunk/contrib/necessary/USB:classes/HID 类/MassStorage 栈/存根中的“旧”USB 栈(未使用)。当前栈位于 rom/poseidon 中。旧的栈用于 ppc-efika,虽然该端口目前无法使用。另一方面,我希望能在 sam 端口取得进展。
有没有人知道 AmigaOS 上 input.device 的 IECLASS_TIMER 滴答率是多少?(Google 和 Autodocs 帮不上忙——它们只说 IECLASS_TIMER 是一个“定时器事件”,但没有说明事件发生的频率)。在 AROS 中,它被设置为每 100 毫秒一次。正确吗?还是应该使用 VBlank 频率?或者更慢?
需要 MFM 解码和一些简单的硬件操作(Paula 和 CIA)。
对于 cia,骨架应该保留在 rom/cia 中,据我所知,你只需要将特定于 Amiga 的文件添加到 arch/m68k-amiga/cia 中,并使用 %build_archspecific 宏来覆盖初始文件,使其特定于架构。
disk.resource GetUnit() 永远不会启用磁盘 DMA 完成中断。它之所以“能用”,是因为串行传输和磁盘中断使用相同的中断级别。Trackdisk.device 负责启用中断。
如果我添加 arch/m68k-amiga/cia 目录并将特定于 Amiga 的文件放在那里(例如 seticr.c 和 ableicr.c),就会出现错误。
目标是 amiga-m68k。
arch/m68k-amiga/cia/mmakefile.src 很简单
include $(TOP)/config/make.cfg
FILES := seticr ableicr USER_CFLAGS := -I$(SRCDIR)/rom/cia
%build_archspecific \
mainmmake=kernel-cia maindir=rom/cia arch=amiga-m68k \ files=$(FILES) modulename=cia
trackdisk.device 应该位于... m68k-amiga/devs/
而 HIDD 应该位于... m68k-amiga/hidd/
另一方面,资源应该直接放在 m68k-amiga 中——我认为这映射了 AROS/rom 目录的布局。
“Retro”相关问题:我们应该如何配置 ROM 以实现“兼容”模式/特定于型号的配置,例如未扩展的 A500?ROM 必须不要使用太多 RAM 进行高级操作(例如,trackdisk.device 必须不要为 HD 磁盘分配 DMA 缓冲区,15k 与 30k 在芯片 RAM 使用方面存在巨大差异。目前我动态地执行此操作,只有在插入 HD 磁盘时才会重新分配 HD 大小缓冲区,请注意,除非插入 HD 磁盘,否则 HD 磁盘会报告为 DD)。
今天并不太重要,但我希望能够制作一个能够启动大多数 A500 游戏和演示的免费 ROM :)(当然不可能完全兼容,一些非常旧的游戏会直接跳转到 ROM...)
我还注意到(以前我不知道它有那么糟糕)生成的 M68k 代码非常糟糕,效率低下,而且很长...(希望只是因为使用的选项?)
读取驱动器 ID 的代码(来自我的 disk.resource 实现)
void readunitid_internal (struct DiscResource *DiskBase, LONG unitNum) { volatile struct CIA *ciaa = (struct CIA*)0xbfe001; volatile struct CIA *ciab = (struct CIA*)0xbfd000; UBYTE unitmask = 8 << unitNum; ULONG id = 0; int i; ciab->ciaprb &= ~0x80; // MTR ciab->ciaprb &= ~unitmask; // SELx ciab->ciaprb |= unitmask; // SELX ciab->ciaprb |= 0x80; // MTR ciab->ciaprb &= ~unitmask; // SELx ciab->ciaprb |= unitmask; // SELX for (i = 0; i < 32; i++) { ciab->ciaprb &= ~unitmask; // SELx id <<= 1; if (!(ciaa->ciapra & 0x20)) // RDY id |= 1; ciab->ciaprb |= unitmask; // SELX } if (unitNum == 0 && HAVE_NO_DF0_DISK_ID && id == 0) id = 0xffffffff; DiskBase->dr_UnitID[unitNum] = id; }
结果是:(开头和结尾已删除)
00FE8AB6 206f 0010 MOVEA.L (A7, $0010) == $0000ee78,A0 00FE8ABA 7208 MOVE.L #$00000008,D1 00FE8ABC 2008 MOVE.L A0,D0 00FE8ABE e1a9 LSL.L D0,D1 00FE8AC0 1039 00bf d100 MOVE.B $00bfd100,D0 00FE8AC6 0200 007f AND.B #$7f,D0 00FE8ACA 13c0 00bf d100 MOVE.B D0,$00bfd100 00FE8AD0 1039 00bf d100 MOVE.B $00bfd100,D0 00FE8AD6 1401 MOVE.B D1,D2 00FE8AD8 4602 NOT.B D2 00FE8ADA c002 AND.B D2,D0 00FE8ADC 13c0 00bf d100 MOVE.B D0,$00bfd100 00FE8AE2 1039 00bf d100 MOVE.B $00bfd100,D0 00FE8AE8 8001 OR.B D1,D0 00FE8AEA 13c0 00bf d100 MOVE.B D0,$00bfd100 00FE8AF0 1039 00bf d100 MOVE.B $00bfd100,D0 00FE8AF6 0000 ff80 OR.B #$80,D0 00FE8AFA 13c0 00bf d100 MOVE.B D0,$00bfd100 00FE8B00 1039 00bf d100 MOVE.B $00bfd100,D0 00FE8B06 c002 AND.B D2,D0 00FE8B08 13c0 00bf d100 MOVE.B D0,$00bfd100 00FE8B0E 1039 00bf d100 MOVE.B $00bfd100,D0 00FE8B14 8001 OR.B D1,D0 00FE8B16 13c0 00bf d100 MOVE.B D0,$00bfd100 00FE8B1C 327c 0020 MOVEA.W #$0020,A1 00FE8B20 7000 MOVE.L #$00000000,D0 00FE8B22 1639 00bf d100 MOVE.B $00bfd100,D3 00FE8B28 c602 AND.B D2,D3 00FE8B2A 13c3 00bf d100 MOVE.B D3,$00bfd100 00FE8B30 d080 ADD.L D0,D0 00FE8B32 1639 00bf e001 MOVE.B $00bfe001,D3 00FE8B38 0803 0005 BTST.L #$0005,D3 00FE8B3C 6604 BNE.B #$00000004 == $00FE8B42 00FE8B3E 7601 MOVE.L #$00000001,D3 00FE8B40 8083 OR.L D3,D0 00FE8B42 1639 00bf d100 MOVE.B $00bfd100,D3 00FE8B48 8601 OR.B D1,D3 00FE8B4A 13c3 00bf d100 MOVE.B D3,$00bfd100 00FE8B50 5389 SUBA.L #$00000001,A1 00FE8B52 b2fc 0000 CMPA.W #$0000,A1 00FE8B56 66ca BNE.B #$ffffffca == $00FE8B22
没有相对地址的 CIA 寻址,移动到寄存器,执行操作,然后写回... 无法更糟糕了。为什么它会将地址寄存器用作计数器(subaq.l #1,a1; cmpa.w #0,a1?你使用了 volatile 关键字,因此对 ciaprb 的每次操作都会执行!)
考虑
ciab->ciaprb &= ~0x80; // MTR ciab->ciaprb &= ~unitmask; // SELx
将替换为
ciab->ciaprb &= ~(0x80 | unitmask); // MTR, SELx
生成的代码会更短... ;)
将“int i”更改为“UBYTE i”,因为你只从 0 计数到 31。否则,你会迫使 gcc 为你分配一个 32 位寄存器。
我的意思是,为什么它没有创建简单而短的
and.b #$7f,$bfd100 and.b d0,$bfd100
(或者更好的是,将 bfd100 放在某个地址寄存器中,并执行 and.b #$7f,(a0))
许多数据寄存器完全没有使用。volatile 关键字会强制生成完全无优化的代码吗?:) 当然!它禁止任何过度优化,因为变量的状态始终可能以无法预测的方式发生变化。使用 volatile 关键字描述的寄存器将被访问的次数与你的代码建议的一样多 :P
con-handler 将 Shell 的 I/O 指向 console.device,后者在窗口中绘制输出,并从键盘读取输入。con-handler 用于打开窗口并将窗口传递给 console.device,但现在 console.device 会执行此操作。con-handler 仍然处理名称完成、命令历史记录等,但已发生了很大的改变。
console.device 打开显示器,读取键盘,处理显示历史记录,在一个窗口中处理多个控制台(选项卡)、菜单等。它已被重构,并在很大程度上被重写。
我昨天成功地让 dos 数据包正常工作(主要是启动时需要的函数,如 open/lock、examine、getdeviceproc、assignlock)。Lock 和 Open 使用 FileLock 和 FileHandle 结构。
UAE FS 会启动,直到第一个可执行文件运行,CON 也需要尽快转换。
但我发布此帖子的原因是:NIL 句柄。
无法创建 NIL 句柄,因为 CreateProcess() 需要 NIL:而 NIL 需要 CreateProcess(),以此类推... 原始的 NIL“句柄”只不过是 Open() 检查“NIL:”并返回 fh_Type 为 NULL(数据包端口)的 FileHandle。
问题是:这会导致其他端口出现问题吗?如果是,如何解决?(是否需要某种特殊版本的 CreateProcess()?)Aminet 上有一个 NULL 句柄文件系统,但我已经好几年没有看过它了。 http://aminet.net/package/util/batch/NULL-Handler 可能是一种选择,因为它附带源代码。NULL: 和 NIL: 之间的区别在于 NIL: 是一个虚拟文件系统,而 NULL: 文件系统不是。
我们能不能直接删除 NIL 句柄?这会造成兼容性问题吗?如果存在期望(可能是意外地)使用“完整”NIL 句柄(或 DosList 中列出的 NIL,作为 DLT_DEVICE)的特定于 AROS 的程序。实际上,这不是问题,如果需要,可以从 Dosboot 手动启动真正的 NIL: 句柄(覆盖伪 NIL)。
DOS 数据包转换正在顺利进行,UAE FS 现在可以启动(并且速度更快,原因不明)。直到调用 Open(CON:) 时。下一个问题:控制台句柄,在没有看到屏幕上的任何内容的情况下,很难测试基于磁盘的命令。它看起来不像 NIL 句柄那样简单转换(我之前转换过,后来发现它不能使用)。我们是否在某个地方隐藏了更旧的、真正基于 dos 数据包的版本?没有,console.handler 的第一个签入(在 1998 年)使用了 FSA_* API。
diff --git a/arch/m68k-amiga/devs/filesys/console_handler/con_handler.c b/arch/m index 2f0bc85..38c3bb9 100644 --- a/arch/m68k-amiga/devs/filesys/console_handler/con_handler.c +++ b/arch/m68k-amiga/devs/filesys/console_handler/con_handler.c @@ -297,10 +297,10 @@ static void startread(struct filehandle *fh) } #if (AROS_FLAVOUR & AROS_FLAVOUR_BINCOMPAT) - - /* SegList points here, must be long aligned */ - __attribute__((aligned(4))) - + /* We use the GCC trick of .balign, which + * will pad us with NOPs + */ +asm (" .text\n.balign 4\n"); #endif LONG CONMain(void)
为什么 Amiga 编译器不会出现这个问题?仅仅是运气,还是它们会自动将函数对齐到 4 字节?如果是后者,也许我们应该在 68k 交叉编译器中执行相同的操作。
这是一种非常糟糕的代码,它只是偶然起作用了... 文档中没有说明输入句柄有额外的暂存寄存器。我们是否只需要保存 D2 和 D3,或者其他程序也会(非法地)修改其他非暂存寄存器?同样糟糕的是 Titanics Cruncher 解压缩器,它使用 A5 作为基址寄存器来调用 dos 函数,而 A6 指向 dosbase 之外的其他内容,它之所以能用(再次是偶然),是因为 dos 数据包可以在没有 dosbase 的情况下发送... 我认为所有寄存器都需要保存,但也许可以添加一个 GCC 编译器命令,这样在调用事件处理程序后,所有寄存器都将失效,因此后面的代码将不使用任何寄存器。
但当你查看软件中断时,这里的文档写着“不要修改 a6”,而在中断中写着
“(D0/D1/A0/A1/A5/A6) 可以被中断处理程序用作暂存寄存器”
当 Inputhandler 中没有可用的寄存器时,我认为 AOS 中的代码是为所有寄存器都可以在 Inputhandler 中使用而编写的。不要假设这种行为是允许的。请提供文档证明你的假设。由于 InputHandlers 在 input.device 中以 Interrupt 结构的形式进行链式连接,我认为与软件中断相同的规则也适用。
IMO 规则是,临时寄存器是 D0-D1/A0-A1,除非文档另有说明,否则不要触碰其他寄存器。不要只是想,修改你的测试程序来确认它(查看哪些寄存器可以更改而不会导致 AOS 输入处理程序崩溃,我相信至少有一个地址寄存器不能修改,否则会导致崩溃)。
或者,你可以看看为什么屏幕切换器 awin 在 AROS 上无法工作。也许我错了,但为了找出原因,一个保存所有寄存器的 AROS 版本很有用。所有这些程序都会导致 AROS 崩溃。
http://aminet.net/package/util/wb/ScreenSwitch http://aminet.net/package/util/wb/awin
awin 是由 kas1e 编写的,也许他知道可能出现的问题,也许商品处理程序也存在类似问题,它们不接受修改寄存器。
CON
[edit | edit source]CON 的原始原因是:编译器/autoinit/stdiowin.c,它总是将输入和输出流设置为 "CON://///AUTO/CLOSE"。这将强制打开控制台窗口,如果程序从 Input()/Output() 中读取或写入任何内容。
这是正确的。此行为是从 libnix 中复制的。我建议首先在 AmigaOS 上测试从该文件读取是否真的会打开控制台窗口。也许只有输出会打开它,而输入不会。窗口不会立即打开,而是在第一次访问时打开。
在编写这篇文章时,我理解了它的起源。CreateNewProc() 会处理这个问题,但在从 Workbench 启动时,进程的输入/输出都是 NIL:。启动代码接管了这两个,最终导致 Input() 不包含任何预注入的数据。
我建议在 AmigaOS 上测试以下顺序
1. 使用这些参数打开 CON:。 2. 尝试读取一些内容。 3. 尝试写入一些内容。 4. 尝试再次读取。
如果我的猜测正确,步骤 (2) 不会导致窗口打开,只会返回 EOF。如果是这样,我们的控制台处理程序需要修复。这种情况最初没有发生(=错误的行为),直到(我认为)一些与 dos 数据包相关的修复被移到主线上。它不是与数据包相关的,而是与 AmigaOS 如何处理进程的参数相关的。它将它们注入 Input() 中。
KS3.1
handle = Open("CON://///AUTO/CLOSE", MODE_OLDFILE) 控制台窗口尚未打开 Read(handle,buf,1) = 窗口打开,等待输入或 Write(handle,buf,1) = 窗口打开
资源
[edit | edit source]存在一个微小的先有鸡还是先有蛋的问题。AOS 在使用第三方自动引导 ROM(UAE 硬盘文件驱动程序是第三方自动引导 ROM)进行自动挂载时会执行此操作:FileSystem.resource 被添加。
某些东西将 FFS dostype 节点添加到 FileSystem.resource 中。这发生在 dos 初始化之前。(也许是在 FileSystem.resource 初始化时,或者是在 FFS 初始化时,根据 Guru Book,它在 dos 之前初始化)。
自动引导 ROM 执行其工作,检查分区,从 RDB 加载文件系统(如果已安装),并将版本与 FileSystem.resource 中的文件系统进行比较。如果不存在 RDB FFS,则检查 FileSystem.resource,添加 dos 节点等。Dos 初始化,依此类推…
问题:AROS 非 dos 数据包 AFS.handler 在初始化期间需要 dos。这意味着它不能在 dos 之前初始化,因此 FileSystem.resource 节点不能由 AFS 处理程序过早添加。(我很乐意将其破坏,因为它不正确,但我认为我是少数派:D)。
但 AFS 处理程序的版本和修订信息需要正确填充 FileSystem.resource AFS 条目。(不需要 seglist,因为 NULL seglist 意味着使用 rn_FileHandlerSegment,它可以在 dos 之后设置)。
此外,驻留列表条目需要由除 AFS.handler 之外的其他东西添加(我不知道)(同样,需要 dos 来执行此操作)。
我认为真正的问题是 AROS 文件系统检测根本没有使用 FileSystem.resource。M68k-amiga 需要它,因为第三方引导 ROM 预计它会存在,并预计它在 KS2.0+ 中包含 AFS Dostypes。
此剩余问题阻止从第三方引导 ROM 驱动程序 RDB 硬盘驱动器启动,而没有安装 RDB LSEG FFS(使用例如任何 SCSI 适配器或正常 UAE 硬盘文件驱动程序的真实 Amiga)或正常分区硬盘文件(仅限 UAE)。
AROS ata.driver 工作是因为它知道如何处理它,UAE 目录硬盘驱动器也是如此,因为它是一个文件系统,而不是一个设备驱动程序。
是的,但请注意,AOS 甚至没有 FFS 节点中的 seglist 字段("patchflags" 中的 seglist 位未设置,seglist 指针位于分配的内存之外,它们每个节点节省了 4 字节的 RAM!),处理程序启动代码在 RootNode 中的 seglist 为 null 时使用 rn_FileHandlerSegment。
这似乎暗示
- FileSystem.resource 初始化
- afs.handler 通过向 FileSystem.resource 注册自身进行初始化
- dos.library 初始化,在 FileSystem 中查找 'afs.handler' 条目,并将 rn_FileHandlerSegment 设置为条目的 fse_SegList
如果 AROS 的 AFS 处理程序在初始化期间不需要 DOS,我们将没问题。是的,只要它以比 dos 更高的驻留优先级工作即可。如果是这样,这可能是最好的方法。AFS 处理程序在初始化期间所做的只是将自身(版本和处理程序 LSEG)注册到 FileSystem.resource?是的,但请注意,AOS 甚至没有 FFS 节点中的 seglist 字段("patchflags" 中的 seglist 位未设置,seglist 指针位于分配的内存之外,它们每个节点节省了 4 字节的 RAM!),处理程序启动代码在 RootNode 中的 seglist 为 null 时使用 rn_FileHandlerSegment。
我们可以摆脱 AROS_STACK_GROWS_DOWNWARDS 吗?这似乎不必要地使一些事情复杂化,而且它似乎在整个 AROS 中并没有被一致地使用。我们是否真的支持“堆栈向上增长”的架构?是否有人能想到一个不是来自 1980 年代之前的架构?
我认为是为 PA RISC(我可能错了),这在 90 年代中期,这段代码编写时仍然很常见。(我记得当时它几乎是最快的 CPU)。
也就是说,我认为出于实际原因,摆脱它是有意义的。我预计 AROS 会在使用寄存器窗口的 CPU 上运行,然后才会在堆栈以另一种方式增长的 CPU 上运行。