Changes

10,220 bytes added ,  02:45, 11 February 2024
Redesign page and document communication with MCP
Line 1: Line 1:  
Cafe OS is the operating system running on the PowerPC in Wii U mode. It consists of the Cafe OS kernel, the executable loader, and system libraries. Unlike on the Wii, where each game provided its own copy of [https://wiibrew.org/wiki/Revolution_OS Revolution OS] with no isolation between libraries, Wii U applications run under the supervision of a common PowerPC kernel, isolating them from each other. All applications are [[RPL|modified ELFs]], as are the libraries themselves, and applications dynamically link with them to gain access to OS services. Cafe OS also contains a few system processes, like the home menu and error handler.
 
Cafe OS is the operating system running on the PowerPC in Wii U mode. It consists of the Cafe OS kernel, the executable loader, and system libraries. Unlike on the Wii, where each game provided its own copy of [https://wiibrew.org/wiki/Revolution_OS Revolution OS] with no isolation between libraries, Wii U applications run under the supervision of a common PowerPC kernel, isolating them from each other. All applications are [[RPL|modified ELFs]], as are the libraries themselves, and applications dynamically link with them to gain access to OS services. Cafe OS also contains a few system processes, like the home menu and error handler.
   −
== Architecture ==
+
== Kernel ==
=== Kernel ===
+
The kernel runs in supervisor mode on the PowerPC, and performs the basic tasks of a microkernel. It is responsible for process isolation, memory management, and interrupt dispatching, as well as communication with [[IOSU]]. Cafe OS applications run as user mode processes, with separate address spaces and W^X memory protection.
The kernel runs in supervisor mode on the PowerPC, and performs the basic tasks of a microkernel. It is responsible for process isolation, memory management, and interrupt dispatching, as well as communication with [[IOSU]]. Cafe OS applications run as user mode processes, with separate address spaces and W^X memory protection. The kernel provides basic [[Cafe_OS_Syscalls|syscalls]] for running processes.
     −
=== Processes ===
+
=== Syscalls ===
 +
Cafe OS syscalls are issued by doing the following:
 +
li r0, 0x0100 # load syscall value->r0
 +
sc            # syscall instruction
 +
blr          # return control to program
 +
 
 +
When you send a call to the kernel, it goes to 0xFFF00C00, which then jumps to 0xFFF021A0 + (fastcall << 5).
 +
 
 +
Normal syscalls are divisible by 0x100, so all of them will jump to 0xFFF0021A0 itself, which is a jump to the table dispatcher.
 +
 
 +
The dispatcher uses a RAMPID and the syscall dispatch tables at 0xFFEAAA40 (user table in 5.5.1) and 0xFFE84850 (loader table in 5.5.1) to get the secondary table each RAMPID is able to access.
 +
 
 +
RAMPIDs 0 (Kernel), 2, and 3 all use an empty table, while RAMPID 1 (root.rpx) has its own table with a few unique calls. RAMPIDs 4 (background app), 5 (home menu), and 6 (error display) share the same table and RAMPID 7 (foreground app) has it's own.
 +
 
 +
Below is a list of what all of them, as well as the loader which has its own bare-bones table, have access to call. (sp) indicates that the loader uses a separate function for that syscall. Additionally, the loader uses the same function for IPCKDriver_Open/Close.
 +
 
 +
{| class="wikitable sortable"
 +
|-
 +
! scope="col" | #
 +
! scope="col" | Name
 +
! scope="col" style="width: 24px;" | root
 +
! scope="col" style="width: 24px;" | Sys
 +
! scope="col" style="width: 24px;" | App
 +
! scope="col" style="width: 24px;" | Ldr
 +
|-
 +
| 0x0000 || ConsoleWrite || X || X || X || X (sp)
 +
|-
 +
| 0x0100 || AppPanic || X || X || X || X
 +
|-
 +
| 0x0200 || EffectiveToPhysical || X || X || X ||
 +
|-
 +
| 0x0300 || PhysicalToEffectiveCached || X || X || X ||
 +
|-
 +
| 0x0400 || PhysicalToEffectiveUncached || X || X || X ||
 +
|-
 +
| 0x0500 || ValidateAddrRange || X || X || X || X
 +
|-
 +
| 0x0600 || UpdateCoreTime || X || X || X ||
 +
|-
 +
| 0x0800 || SetUserModeExHandler || X || X || X ||
 +
|-
 +
| 0x0B00 || AllocateTimer || X || X || X ||
 +
|-
 +
| 0x0C00 || FreeTimer || X || X || X ||
 +
|-
 +
| 0x0D00 || PrimeTimer || X || X || X ||
 +
|-
 +
| 0x0E00 || StopTimer || X || X || X ||
 +
|-
 +
| 0x0F00 || DumpModuleList || X || X || X ||
 +
|-
 +
| 0x1000 || SetInterruptHandler || X || X || X ||
 +
|-
 +
| 0x1100 || GetInterruptHandler || X || X || X ||
 +
|-
 +
| 0x1200 || DisableInterrupt || X || X || X ||
 +
|-
 +
| 0x1300 || EnableInterrupt || X || X || X ||
 +
|-
 +
| 0x1400 || ClearAndEnableInterrupt || X || X || X ||
 +
|-
 +
| 0x1500 || GetInterruptStatus || X || X || X ||
 +
|-
 +
| 0x1600 || ClearInterruptStatus || X || X || X ||
 +
|-
 +
| 0x1700 || FindClosestSymbol || X || X || X || X (sp)
 +
|-
 +
| 0x1900 || Exit/Halt || X || X || X ||
 +
|-
 +
| 0x1A00 || GetInfo || X || X || X ||
 +
|-
 +
| 0x1B00 || SetInfo || X || X || X ||
 +
|-
 +
| 0x1C00 || ReleaseCore || X || X || X ||
 +
|-
 +
| 0x1D00 || SendICI || X || X || X ||
 +
|-
 +
| 0x1E00 || IPCKDriver_<nowiki>{Loader|User}</nowiki>Open || X || X || X || X (sp)
 +
|-
 +
| 0x1F00 || IPCKDriver_<nowiki>{Loader|User}</nowiki>Close || X || X || X || X (sp)
 +
|-
 +
| 0x2000 || IPCKDriver_SubmitRequest || X || X || X || X (sp)
 +
|-
 +
| 0x2200 || GetEnvironmentVariable || X || X || X ||
 +
|-
 +
| 0x2700 || GetNotifyTarget || X || X || X ||
 +
|-
 +
| 0x2800 || ReleaseForeground || X || X || X ||
 +
|-
 +
| 0x2900 || GetForegroundBucket || X || X || X ||
 +
|-
 +
| 0x2A00 || RequestSwitch || X || X || X ||
 +
|-
 +
| 0x2B00 || LaunchTitleArgvStr || X || X || X ||
 +
|-
 +
| 0x2C00 || ProcYield || X || X || X ||
 +
|-
 +
| 0x2E00 || GetSystemMessage || X || X || X ||
 +
|-
 +
| 0x2F00 || GetCallArgs || X || X || X ||
 +
|-
 +
| 0x3000 || GetAbsoluteSystemTimeInternal || X || X || X ||
 +
|-
 +
| 0x3100 || SetAbsoluteSystemTimeInternal || X || X || X ||
 +
|-
 +
| 0x3200 || Driver_Register || X || X || X ||
 +
|-
 +
| 0x3300 || Driver_Deregister || X || X || X ||
 +
|-
 +
| 0x3800 || AllocVirtAddr || X || X || X ||
 +
|-
 +
| 0x3900 || FreeVirtAddr || X || X || X ||
 +
|-
 +
| 0x3A00 || GetMapVirtAddrRange || X || X || X ||
 +
|-
 +
| 0x3B00 || GetDataPhysAddrRange || X || X || X ||
 +
|-
 +
| 0x3C00 || GetAvailPhysAddrRange || X || X || X ||
 +
|-
 +
| 0x3D00 || MapMemory || X || X || X ||
 +
|-
 +
| 0x3E00 || UnmapMemory || X || X || X ||
 +
|-
 +
| 0x3F00 || LogBuffer || X || X || X || X
 +
|-
 +
| 0x4000 || LogArgs || X || X || X || X
 +
|-
 +
| 0x4100 || LogFunc || X || X || X || X
 +
|-
 +
| 0x4200 || LogReportKernel || X || X || X || X
 +
|-
 +
| 0x4300 || LogRetrieve || X || X || X || X
 +
|-
 +
| 0x4400 || (unknown) || X || X || X ||
 +
|-
 +
| 0x4500 || (unknown) || X || X || X ||
 +
|-
 +
| 0x4600 || save_fpu || X || X || X ||
 +
|-
 +
| 0x4700 || Driver_CopyFromSaveArea || X || X || X ||
 +
|-
 +
| 0x4800 || Driver_CopyToSaveArea || X || X || X ||
 +
|-
 +
| 0x4900 || SavesDone_ReadyToRelease || X || X || X ||
 +
|-
 +
| 0x4A00 || SetAlarm || X || X || X ||
 +
|-
 +
| 0x4B00 || SetDABR || X || X || X ||
 +
|-
 +
| 0x4C00 || SetIABR || X || X || X ||
 +
|-
 +
| 0x4D00 || GetProcessInfo || X || X || X ||
 +
|-
 +
| 0x4E00 || GetCodegenVirtAddrRange || X || X || X ||
 +
|-
 +
| 0x4F00 || LoaderCall || X || X || X ||
 +
|-
 +
| 0x5000 || RPLLoaderResumeContext ||  ||  ||  || X
 +
|-
 +
| 0x5200 || WaitIopComplete ||  ||  ||  || X
 +
|-
 +
| 0x5300 || FlushCode ||  ||  ||  || X
 +
|-
 +
| 0x5400 || FlushData ||  ||  ||  || X
 +
|-
 +
| 0x5500 || UpdateHeartbeat ||  ||  ||  || X
 +
|-
 +
| 0x5600 || LogEntry ||  ||  ||  || X
 +
|-
 +
| 0x5700 || FastClearMemory ||  ||  ||  || X
 +
|-
 +
| 0x5800 || GetBusClockSpeed ||  ||  ||  || X
 +
|-
 +
| 0x5900 || GetSharedArea || X || X || X ||
 +
|-
 +
| 0x5A00 || SendPolicy || X || X || X ||
 +
|-
 +
| 0x5B00 || GetProcessIndex ||  ||  ||  || X
 +
|-
 +
| 0x5C00 || IPCKDriver_PollLoaderCompletion ||  ||  ||  || X
 +
|-
 +
| 0x5D00 || BlockLogSave || X || X || X ||
 +
|-
 +
| 0x5E00 || FinishInitandPreload ||  ||  ||  || X
 +
|-
 +
| 0x5F00 || ContinueStartProcess ||  ||  ||  || X
 +
|-
 +
| 0x6000 || OpenMCP ||  ||  ||  || X
 +
|-
 +
| 0x6100 || QuerySwitchReady || X || X || X ||
 +
|-
 +
| 0x6200 || launch_title || X || X || X ||
 +
|-
 +
| 0x6300 || call_title || X || X || X ||
 +
|-
 +
| 0x6400 || SetTimeInternal ||  || X ||  ||
 +
|-
 +
| 0x6500 || do_nothing (blr) || X || X || X ||
 +
|-
 +
| 0x6600 || ProfileEntry (blr) ||  ||  ||  || X
 +
|-
 +
| 0x6700 || RequestFastExit || X || X || X ||
 +
|-
 +
| 0x6800 || CoreInitDone || X || X || X ||
 +
|-
 +
| 0x6900 || GetSwitchTarget || X || X || X ||
 +
|-
 +
| 0x6A00 || AcquireDone || X || X || X ||
 +
|-
 +
| 0x6B00 || GetBuiltSDKVersion || X || X || X ||
 +
|-
 +
| 0x6C00 || SystemFatal || X || X || X ||
 +
|-
 +
| 0x6E00 || SwitchSecCodeGenMode || X || X || X ||
 +
|-
 +
| 0x6F00 || IopShell_RegisterCallback || X || X || X ||
 +
|-
 +
| 0x7000 || GetTitleVersion || X || X || X ||
 +
|-
 +
| 0x7100 || IsTestKernel || X || X || X ||
 +
|-
 +
| 0x7200 || ForceFullRelaunch || X || X || X ||
 +
|-
 +
| 0x7300 || Recycle || X ||  ||  ||
 +
|-
 +
| 0x7400 || get_mode_flags || X || X || X || X
 +
|-
 +
| 0x7500 || QueryVirtAddr || X || X || X ||
 +
|-
 +
| 0x7600 || GetCodegenCore || X || X || X ||
 +
|-
 +
| 0x7700 || GetSecCodeGenMode || X || X || X ||
 +
|-
 +
| 0x7800 || CodegenCopy || X || X || X ||
 +
|-
 +
| 0x7900 || LoadShared || X ||  ||  ||
 +
|-
 +
| 0x7A00 || SetExceptionCallback || X || X || X ||
 +
|-
 +
| 0x7B00 || IopShell_InjectCommand || X || X || X ||
 +
|-
 +
| 0x7C00 || Kill || X || X || X ||
 +
|-
 +
| 0x7D00 || EnableOverlayArena || X || X || X ||
 +
|-
 +
| 0x7E00 || DisableOverlayArena || X || X || X ||
 +
|-
 +
| 0x7F00 || GetSystemMode || X || X || X ||
 +
|-
 +
| 0x8000 || SystemMode_RegisterCallback || X || X || X ||
 +
|-
 +
| 0x8100 || ZeroProcessMemory || X ||  ||  ||
 +
|-
 +
| 0x8200 || HandleIopPowerEvents ||  ||  ||  || X
 +
|-
 +
| 0x8300 || ConsoleTimestamp || X || X || X || X
 +
|-
 +
| 0x8400 || ValidateOverlayRange ||  ||  ||  || X
 +
|-
 +
| 0x8500 || BadSysCall (jump to null on purpose) || X || X || X || X
 +
|}
 +
 
 +
=== Fastcalls ===
 +
Fastcalls, on the other hand, are system calls that aren't routed through the dispatcher and can be accessed by any RAMPID.
 +
Attempting to access an unimplemented fastcall will redirect the code flow to syscall 0x0100 (AppPanic).
 +
 
 +
Below is a list of all the currently supported fastcalls.
 +
 
 +
{| class="wikitable sortable"
 +
|-
 +
! scope="col" | #
 +
! scope="col" | Name
 +
|-
 +
| 0x0000 || (default branch to syscall dispatcher)
 +
|-
 +
| 0x0001 || SyncEIEIO
 +
|-
 +
| 0x0006 || LoadContext
 +
|-
 +
| 0x0007 || SaveContext
 +
|-
 +
| 0x0008 || SetCurrentContext
 +
|-
 +
| 0x0009 || GetCurrentFPUContext
 +
|-
 +
| 0x000A || SetCurrentFPUContext
 +
|-
 +
| 0x000B || CompareAndSwapCurrentFPUContext
 +
|-
 +
| 0x000C || WriteGatherInit
 +
|-
 +
| 0x000D || SetPerformanceMonitor
 +
|-
 +
| 0x000E || FlushDMAQueue
 +
|-
 +
| 0x000F || do_nothing (rfi)
 +
|-
 +
| 0x0010 || DisableFPU (???)
 +
|-
 +
| 0x0011 || ReadRegister32Ex
 +
|-
 +
| 0x0012 || WriteRegister32Ex
 +
|-
 +
| 0x0013 || Unknown (FPU?)
 +
|-
 +
| 0x0014 || Unknown (FPU?)
 +
|-
 +
| 0x0015 || Unknown (FPU?)
 +
|-
 +
| 0x0016 || Unknown (FPU?)
 +
|-
 +
| 0x0017 || WriteGatherGetPtr
 +
|-
 +
| 0x0018 || EnableFPU (???)
 +
|-
 +
| 0x0019 || GetSecurityLevel (always zero)
 +
|-
 +
| 0x001A || BadFastCall (jump to error on purpose)
 +
|}
 +
 
 +
=== CosParams ===
 +
This is a structure mapped to address 0x1FFF000 in MEM1 for communicating with the [[IOSU|MCP]] process.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x4 || Magic (0x5726)
 +
|-
 +
| 0x4 || 0x4 || Size (0x40C)
 +
|-
 +
| 0x8 || 0x4 || PpcFlags
 +
|-
 +
| 0xC || 0x4 || ConsoleType
 +
|-
 +
| 0x10 || 0x4 || Iop2x
 +
|-
 +
| 0x14 || 0x4 || Bperf
 +
|-
 +
| 0x18 || 0x4 || PpcSystemClockFrequency
 +
|-
 +
| 0x1C || 0x4 || PpcCore0L2Size
 +
|-
 +
| 0x20 || 0x4 || PpcCore0L2LineSize
 +
|-
 +
| 0x24 || 0x4 || PpcCore0L2SectorSize
 +
|-
 +
| 0x28 || 0x4 || PpcCore0L2FetchSize
 +
|-
 +
| 0x2C || 0x4 || PpcCore0L2SetAssociativity
 +
|-
 +
| 0x30 || 0x4 || PpcCore1L2Size
 +
|-
 +
| 0x34 || 0x4 || PpcCore1L2LineSize
 +
|-
 +
| 0x38 || 0x4 || PpcCore1L2SectorSize
 +
|-
 +
| 0x3C || 0x4 || PpcCore1L2FetchSize
 +
|-
 +
| 0x40 || 0x4 || PpcCore1L2SetAssociativity
 +
|-
 +
| 0x44 || 0x4 || PpcCore2L2Size
 +
|-
 +
| 0x48 || 0x4 || PpcCore2L2LineSize
 +
|-
 +
| 0x4C || 0x4 || PpcCore2L2SectorSize
 +
|-
 +
| 0x50 || 0x4 || PpcCore2L2FetchSize
 +
|-
 +
| 0x54 || 0x4 || PpcCore2L2SetAssociativity
 +
|-
 +
| 0x58 || 0x64 || Reserved
 +
|-
 +
| 0xBC || 0x4 || PpcCorePropertiesCount
 +
|-
 +
| 0xC0 || 0x4 || PpcCorePropertiesFlags
 +
|-
 +
| 0xC4 || 0x4 || PpcMem0Id
 +
|-
 +
| 0xC8 || 0x4 || PpcMem0BaseAddress
 +
|-
 +
| 0xCC || 0x4 || PpcMem0Size
 +
|-
 +
| 0xD0 || 0x4 || PpcMem1Id
 +
|-
 +
| 0xD4 || 0x4 || PpcMem1BaseAddress
 +
|-
 +
| 0xD8 || 0x4 || PpcMem1Size
 +
|-
 +
| 0xDC || 0x4 || PpcMem2Id
 +
|-
 +
| 0xE0 || 0x4 || PpcMem2BaseAddress
 +
|-
 +
| 0xE4 || 0x4 || PpcMem2Size
 +
|-
 +
| 0xE8 || 0x3C || Reserved
 +
|-
 +
| 0x124 || 0x4 || PpcMemRegionCount
 +
|-
 +
| 0x128 || 0x4 || PpcMemRegionFlags
 +
|-
 +
| 0x12C || 0x244 || Reserved
 +
|-
 +
| 0x370 || 0x4 || HardwareVersion
 +
|-
 +
| 0x374 || 0x8C || Reserved
 +
|-
 +
| 0x400 || 0x4 || BootSystemMode
 +
|-
 +
| 0x404 || 0x4 || McpSystemMode
 +
|-
 +
| 0x408 || 0x4 || [[Boot1#PowerFlags|PowerFlags]]
 +
|}
 +
 
 +
== Processes ==
 
A process in Cafe OS represents a single running application, with its own code, memory, and permissions. Cafe OS only executes the code of a single process at a time, but it can hold the data of multiple processes in memory simultaneously, and switch between them. Rather than allowing arbitrary process creation, there is RAM reserved for a single foreground app, a single background app, and various other special processes. Each running process is assigned a unique identifier called a RAMPID:
 
A process in Cafe OS represents a single running application, with its own code, memory, and permissions. Cafe OS only executes the code of a single process at a time, but it can hold the data of multiple processes in memory simultaneously, and switch between them. Rather than allowing arbitrary process creation, there is RAM reserved for a single foreground app, a single background app, and various other special processes. Each running process is assigned a unique identifier called a RAMPID:
 
{| class="wikitable"
 
{| class="wikitable"
Line 118: Line 531:  
|}
 
|}
   −
=== Loader ===
+
== Loader ==
 
{{Main|Loader}}
 
{{Main|Loader}}
    
The loader is responsible for loading RPL formatted libraries and executables into memory. It is a standard ELF executable named loader.elf. It includes a statically linked copy of zlib, probably for decompressing sections of RPL files.
 
The loader is responsible for loading RPL formatted libraries and executables into memory. It is a standard ELF executable named loader.elf. It includes a statically linked copy of zlib, probably for decompressing sections of RPL files.
   −
=== Libraries ===
+
== Libraries ==
 
Cafe OS applications dynamically link with system libraries to get access to OS services. These OS services include memory management, graphics, audio, and controller input. All libraries are [[RPL|RPL files]], a modification of the standard ELF format with compressed sections and more Windows-like dynamic linking. The main system libraries are listed below, with some having their own pages of documentation:
 
Cafe OS applications dynamically link with system libraries to get access to OS services. These OS services include memory management, graphics, audio, and controller input. All libraries are [[RPL|RPL files]], a modification of the standard ELF format with compressed sections and more Windows-like dynamic linking. The main system libraries are listed below, with some having their own pages of documentation:
 
*[[avm.rpl]] - Audio/Video Manager
 
*[[avm.rpl]] - Audio/Video Manager