mNo edit summary |
No edit summary |
||
(2 intermediate revisions by the same user not shown) | |||
Line 14: | Line 14: | ||
| 5 || getNANDDescriptor || - || - | | 5 || getNANDDescriptor || - || - | ||
|- | |- | ||
| 6 || setNVMeState || | | 6 || setNVMeState || uint64_t state || - | ||
|- | |- | ||
| 7 || setPCIPortState || | | 7 || setPCIPortState || uint64_t state || - | ||
|- | |- | ||
| 8 || setBFHGPIO || uint64_t value || uint64_t unknown | | 8 || setBFHGPIO || uint64_t value || uint64_t unknown | ||
Line 24: | Line 24: | ||
'''NOTE:''' this table currently is only showing the selectors, the input / output will be documented later. | '''NOTE:''' this table currently is only showing the selectors, the input / output will be documented later. | ||
By reverse engineering a userland daemon ('''nvmefwupdater''') that can be found on the update ramdisk in /usr/local/bin the following structures could be derrived: | By reverse engineering a userland daemon <span class="newwin">([https://www.theiphonewiki.com/wiki/Nvmefwupdater '''nvmefwupdater'''])</span> that can be found on the update ramdisk in /usr/local/bin the following structures could be derrived: | ||
<source lang="c"> | <source lang="c"> |
Latest revision as of 11:55, 30 January 2020
AppleEmbeddedNVMeController is a kernel extension for managing the NAND disk via Peripheral Component Interconnect Express (PCIe) bus.
Methods
Selector | Action | Input | Output |
---|---|---|---|
2 | sendNVMECommand | struct NVMeCommand* | __n128 unknown |
3 | isBFHMode | - | bool bfhMode |
4 | performBFH | - | - |
5 | getNANDDescriptor | - | - |
6 | setNVMeState | uint64_t state | - |
7 | setPCIPortState | uint64_t state | - |
8 | setBFHGPIO | uint64_t value | uint64_t unknown |
NOTE: this table currently is only showing the selectors, the input / output will be documented later.
By reverse engineering a userland daemon (nvmefwupdater) that can be found on the update ramdisk in /usr/local/bin the following structures could be derrived:
typedef union __attribute__((aligned(8))) __n128
{
uint64_t n128_u64[2];
uint32_t n128_u32[4];
uint16_t n128_u16[8];
uint8_t n128_u8[16];
int64_t n128_i64[2];
int32_t n128_i32[4];
int16_t n128_i16[8];
int8_t n128_i8[16];
float n128_f32[4];
double n128_f64[2];
} __n128;
enum AppleEmbeddedNVMeControllerAction {
kNVMECTL_sendNVMECommandAction = 2,
kNVMECTL_isBFHModeAction = 3,
kNVMECTL_performBFHAction = 4,
kNVMECTL_getNandDescriptorAction = 5,
kNVMECTL_setNVMeStateAction = 6,
kNVMECTL_setPCIPortStateAction = 7,
kNVMECTL_setBFHGPIOAction = 8,
};
typedef struct NVMeIdentifyControllerStruct {
char unknown[0x1000];
} NVMeIdentifyControllerStruct;
typedef struct NVMeCommand {
} *NVMeCommand;
typedef struct FTLVersion {
uint8_t clogMajor;
uint8_t clogMinor;
uint8_t dm;
} FTLVersion;
To connect to an IOKit service in general by its name the following snippet can be used.
io_service_t io_get_service(const char *name) {
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(name));
io_name_t className = {};
if(MACH_PORT_VALID(service)) {
IOObjectGetClass(service, className);
printf("We got a userclient: %s::%s\n", name, className);
}
return service;
}
io_connect_t io_connect_service(io_service_t service) {
kern_return_t err = KERN_SUCCESS;
io_connect_t conn = IO_OBJECT_NULL;
io_name_t className = {};
err = IOObjectGetClass(service,className); // Retrieve the classname of the userclient
printf("Got UserClient: %s\n", className);
err = IOServiceOpen(service, mach_task_self(), 0, &conn); // Try to connect to the service
if(err != KERN_SUCCESS){
printf("Can not connect to %s\n", className);
return IO_OBJECT_NULL;
}
return conn; // Return the connection to the service
}
And finally, this is how logic implementation around the userclient looks:
#define IOSVC_NVMECTL "AppleEmbeddedNVMeController"
kern_return_t nvmecontroller_setBFHGPIO(uint64_t value) {
kern_return_t err = KERN_SUCCESS;
io_service_t nvmesvc = io_get_service(IOSVC_NVMECTL); // Try-get nvme-controller service
io_connect_t conn = IO_OBJECT_NULL;
// First make sure that we found the iombf service
if( !MACH_PORT_VALID(nvmesvc) ) {
printf("Couldn't find AppleEmbeddedNVMeController service.\n");
return KERN_FAILURE;
}
conn = io_connect_service(nvmesvc); // Open a connection to AppleEmbeddedNVMeController
// Now make sure that the connection succeeded (sandbox might change in the future)
if( !MACH_PORT_VALID(conn) ) {
printf("Could not connect to AppleEmbeddedNVMeController service.\n");
return KERN_FAILURE;
}
uint64_t output = 0;
uint32_t outputCnt = 1;
err = IOConnectCallMethod(conn, kNVMECTL_setBFHGPIOAction, &value, 1, NULL, 0, &output, &outputCnt, NULL, NULL);
if(err != KERN_SUCCESS) {
return err;
}
return err;
}
kern_return_t nvmecontroller_isBFHMode(bool *bfhMode) {
kern_return_t err = KERN_SUCCESS;
io_service_t nvmesvc = io_get_service(IOSVC_NVMECTL); // Try-get nvme-controller service
io_connect_t conn = IO_OBJECT_NULL;
if( !bfhMode )
return KERN_INVALID_ARGUMENT;
// First make sure that we found the iombf service
if( !MACH_PORT_VALID(nvmesvc) ) {
printf("Couldn't find AppleEmbeddedNVMeController service.\n");
return KERN_FAILURE;
}
conn = io_connect_service(nvmesvc); // Open a connection to AppleEmbeddedNVMeController
// Now make sure that the connection succeeded (sandbox might change in the future)
if( !MACH_PORT_VALID(conn) ) {
printf("Could not connect to AppleEmbeddedNVMeController service.\n");
return KERN_FAILURE;
}
uint64_t output = 0;
uint32_t outputCnt = 1;
err = IOConnectCallMethod(conn, kNVMECTL_isBFHModeAction, NULL, 0, NULL, 0, &output, &outputCnt, NULL, NULL);
if(err != KERN_SUCCESS) {
return err;
}
*bfhMode = output != 0;
return err;
}