Skip to content

Commit

Permalink
Issue #134: support multiple DTs in BootV2 and VendorBoot
Browse files Browse the repository at this point in the history
  • Loading branch information
cfig committed Jan 7, 2024
1 parent 05b4b4c commit 2076fad
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
java-version: 17

- name: apt
run: sudo apt install device-tree-compiler p7zip-full android-sdk-libsparse-utils
run: sudo apt install device-tree-compiler p7zip-full android-sdk-libsparse-utils erofs-utils

# Runs a single command using the runners shell
- name: Unit Test
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,20 @@ Refer to Issue https://github.com/cfig/Android_boot_image_editor/issues/120

</details>

<details>
<summary>How to work with vendor_dlkm.img</summary>

```bash
cp <your_vendor_dlkm.img> vendor_dlkm.img
cp <your_vbmeta_image> vbmeta.img
./gradlew unpack
# replace your .ko
./gradlew pack
```
Then flash `vbmeta.img.signed` and `vendor_dlkm.img.signed` to the device.

</details>

## boot.img layout
Read [boot layout](doc/layout.md) of Android boot.img and vendor\_boot.img.
Read [misc layout](doc/misc_image_layout.md) of misc\.img
Expand Down
2 changes: 1 addition & 1 deletion bbootimg/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "1.9.20"
kotlin("jvm") version "1.9.22"
application
}

Expand Down
26 changes: 21 additions & 5 deletions bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ data class BootV2(
var ramdisk: RamdiskArgs = RamdiskArgs(),
var secondBootloader: CommArgs? = null,
var recoveryDtbo: CommArgsLong? = null,
var dtb: CommArgsLong? = null,
var dtb: DtbArgsLong? = null,
) {
data class MiscInfo(
var output: String = "",
Expand Down Expand Up @@ -85,6 +85,14 @@ data class BootV2(
var loadOffset: Long = 0,
)

data class DtbArgsLong(
var file: String? = null,
var position: Long = 0,
var size: Int = 0,
var loadOffset: Long = 0,
var dtbList: MutableList<DTC.DtbEntry> = mutableListOf(),
)

companion object {
private val log = LoggerFactory.getLogger(BootV2::class.java)
private val workDir = Helper.prop("workDir")
Expand Down Expand Up @@ -148,7 +156,7 @@ data class BootV2(
ret.recoveryDtbo!!.position = ret.getRecoveryDtboPosition()
}
if (bh2.dtbLength > 0) {
ret.dtb = CommArgsLong()
ret.dtb = DtbArgsLong()
ret.dtb!!.size = bh2.dtbLength
ret.dtb!!.loadOffset = bh2.dtbOffset //Q
ret.dtb!!.file = "${workDir}dtb"
Expand Down Expand Up @@ -243,6 +251,13 @@ data class BootV2(
//dtb
this.dtb?.let { _ ->
Common.dumpDtb(Helper.Slice(info.output, dtb!!.position.toInt(), dtb!!.size, dtb!!.file!!))
this.dtb!!.dtbList = DTC.parseMultiple(dtb!!.file!!)
log.info("dtb sz = " + this.dtb!!.dtbList.size)
//dump info again
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + info.json), this)

//dump dtb items
DTC.extractMultiple(dtb!!.file!!, this.dtb!!.dtbList)
}

return this
Expand Down Expand Up @@ -340,12 +355,13 @@ data class BootV2(
//dtb
this.dtb?.let { theDtb ->
if (theDtb.size > 0) {
val dtbCount = this.dtb!!.dtbList.size
it.addRule()
it.addRow("dtb", theDtb.file)
prints.add(Pair("dtb", theDtb.file.toString()))
if (File(theDtb.file + ".${dtsSuffix}").exists()) {
it.addRow("\\-- decompiled dts", theDtb.file + ".${dtsSuffix}")
prints.add(Pair("\\-- decompiled dts", theDtb.file + ".${dtsSuffix}"))
it.addRow("\\-- decompiled dts [$dtbCount]", theDtb.file + ".*.${dtsSuffix}")
prints.add(Pair("\\-- decompiled dts [$dtbCount]", theDtb.file + ".*.${dtsSuffix}"))
}
}
}
Expand Down Expand Up @@ -441,7 +457,7 @@ data class BootV2(
//refresh dtb size
dtb?.let { theDtb ->
if (File(theDtb.file!! + ".${dtsSuffix}").exists()) {
check(DTC().compile(theDtb.file!! + ".${dtsSuffix}", theDtb.file!!)) { "fail to compile dts" }
DTC.packMultiple(theDtb.file!!, theDtb.dtbList)
}
theDtb.size = File(theDtb.file!!).length().toInt()
}
Expand Down
24 changes: 19 additions & 5 deletions bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import cfig.bootimg.Common as C
data class VendorBoot(
var info: MiscInfo = MiscInfo(),
var ramdisk: RamdiskArgs = RamdiskArgs(),
var dtb: CommArgs = CommArgs(),
var dtb: DtbArgs = DtbArgs(),
var ramdisk_table: Vrt = Vrt(),
var bootconfig: CommArgs = CommArgs(),
) {
Expand All @@ -50,6 +50,14 @@ data class VendorBoot(
var loadAddr: Long = 0,
)

data class DtbArgs(
var file: String = "",
var position: Long = 0,
var size: Int = 0,
var loadAddr: Long = 0,
var dtbList: MutableList<DTC.DtbEntry> = mutableListOf(),
)

data class RamdiskArgs(
var file: String = "",
var position: Long = 0,
Expand Down Expand Up @@ -251,7 +259,7 @@ data class VendorBoot(
}
//update dtb
if (File(this.dtb.file + ".${dtsSuffix}").exists()) {
check(DTC().compile(this.dtb.file + ".${dtsSuffix}", this.dtb.file)) { "fail to compile dts" }
DTC.packMultiple(this.dtb.file, this.dtb.dtbList)
}
this.dtb.size = File(this.dtb.file).length().toInt()
//header
Expand Down Expand Up @@ -359,7 +367,13 @@ data class VendorBoot(
this.ramdisk.xzFlags = checkType
}
//dtb
C.dumpDtb(Helper.Slice(info.output, dtb.position.toInt(), dtb.size, dtb.file))
run {
C.dumpDtb(Helper.Slice(info.output, dtb.position.toInt(), dtb.size, dtb.file))
if (dtb.size > 0) {
dtb.dtbList = DTC.parseMultiple(dtb.file)
DTC.extractMultiple(dtb.file, dtb.dtbList)
}
}
//vrt
this.ramdisk_table.ramdidks.forEachIndexed { index, it ->
log.info("dumping vendor ramdisk ${index + 1}/${this.ramdisk_table.ramdidks.size} ...")
Expand Down Expand Up @@ -425,8 +439,8 @@ data class VendorBoot(
it.addRow("dtb", this.dtb.file)
prints.add(Pair("dtb", this.dtb.file))
if (File(this.dtb.file + ".${dtsSuffix}").exists()) {
it.addRow("\\-- decompiled dts", dtb.file + ".${dtsSuffix}")
prints.add(Pair("\\-- decompiled dts", dtb.file + ".${dtsSuffix}"))
it.addRow("\\-- decompiled dts [${dtb.dtbList.size}]", dtb.file + "*.${dtsSuffix}")
prints.add(Pair("\\-- decompiled dts [${dtb.dtbList.size}]", dtb.file + "*.${dtsSuffix}"))
}
} else {
it.addRow("dtb", "-")
Expand Down
113 changes: 113 additions & 0 deletions bbootimg/src/main/kotlin/utils/DTC.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,67 @@

package cfig.utils

import cc.cfig.io.Struct
import cfig.helper.Dumpling
import cfig.helper.Helper
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream

class DTC {
private val log = LoggerFactory.getLogger(DTC::class.java)

data class DtbEntry(
var seqNo: Int = 0,
var offset: Long = 0,
var header: FdtHeader = FdtHeader(),
)

data class FdtHeader(
var magic: Int = 0,
val totalsize: Int = 0,
val offDtStruct: Int = 0,
val offDtStrings: Int = 0,
val offMemRsvmap: Int = 0,
val version: Int = 0,
val lastCompVersion: Int = 0,
val bootCpuidPhys: Int = 0,
val sizeDtStrings: Int = 0,
val sizeDtStruct: Int = 0
) {
companion object {
private const val MAGIC = 0xd00dfeedu
const val FORMAT_STRING = ">10i"
const val SIZE = 40

init {
check(Struct(FORMAT_STRING).calcSize() == SIZE)
}

@Throws(IllegalStateException::class)
fun parse(iS: InputStream): FdtHeader {
val info = Struct(FORMAT_STRING).unpack(iS)
val ret = FdtHeader(
info[0] as Int,
info[1] as Int,
info[2] as Int,
info[3] as Int,
info[4] as Int,
info[5] as Int,
info[6] as Int,
info[7] as Int,
info[8] as Int,
info[9] as Int
)
check(ret.magic.toUInt() == MAGIC) { "bad magic: ${ret.magic}" }
return ret
}
}
}

fun decompile(dtbFile: String, outFile: String): Boolean {
log.info("parsing DTB: $dtbFile")
//CommandLine.parse("fdtdump").let {
Expand Down Expand Up @@ -75,4 +129,63 @@ class DTC {
}
return true
}

companion object {
private val log = LoggerFactory.getLogger(DTC::class.java)
fun parseMultiple(fileName: String): MutableList<DtbEntry> {
val ret = mutableListOf<DtbEntry>()
var seqNo = 0
while (true) {
try {
val index = ret.sumOf { it.header.totalsize.toLong() }
val data = Dumpling(fileName).readFully(Pair(index, FdtHeader.SIZE))
val header = FdtHeader.parse(data.inputStream())
log.info("Found FDT header: #${seqNo} $header")
ret.add(DtbEntry(seqNo, index, header))
seqNo++
} catch (e: IllegalStateException) {
log.info("no more FDT header")
break
}
}
val remainder = File(fileName).length() - ret.sumOf { it.header.totalsize }.toLong()
if (remainder == 0L) {
log.info("Successfully parsed ${ret.size} FDT headers")
} else {
log.warn("Successfully parsed ${ret.size} FDT headers, remainder: $remainder bytes")
}
return ret
}

fun extractMultiple(fileStem: String, entries: List<DtbEntry>) {
entries.forEach {
val slice = Helper.Slice(
fileStem,
it.offset.toInt(), it.header.totalsize, "${fileStem}.${it.seqNo}"
)
Helper.extractFile(slice.srcFile, slice.dumpFile, slice.offset.toLong(), slice.length)
if (EnvironmentVerifier().hasDtc) {
DTC().decompile(slice.dumpFile, slice.dumpFile + "." + Helper.prop("config.dts_suffix"))
}
}
}

fun packMultiple(fileStem: String, entries: List<DtbEntry>) {
if (EnvironmentVerifier().hasDtc) {
entries.forEach {
DTC().compile(
fileStem + ".${it.seqNo}." + Helper.prop("config.dts_suffix"),
fileStem + "." + it.seqNo
)
}
FileOutputStream(fileStem).use { outFile ->
entries.indices.forEach {
log.info("Appending ${fileStem}.${it} ...")
outFile.write(File("$fileStem.$it").readBytes())
}
log.info("Appended ${entries.size} DTBs to ${fileStem}")
}
}
}
}
}
2 changes: 1 addition & 1 deletion helper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "1.9.20"
kotlin("jvm") version "1.9.22"
`java-library`
application
}
Expand Down
2 changes: 1 addition & 1 deletion lazybox/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "1.9.20"
kotlin("jvm") version "1.9.22"
application
}

Expand Down
2 changes: 1 addition & 1 deletion src/integrationTest/resources_2
Submodule resources_2 updated from 517ca7 to b5906e

0 comments on commit 2076fad

Please sign in to comment.