分类目录归档:未分类

xiaomi cdn

小米firmware下载的cdn 限速了。
据说是因为一帮搞 pcdn的人,为了让自己的上行流量占比 小一点, 故意刷下行流量。 其中小米firmware的下载地址是很好获取的,所以被狂刷了很多流量。
其实没什么用,现在运营商不是看占比, 而是上行流量超过多少G,就停宽带。
这帮人做一些损人不利己的缺德事:小米付出了不应该的流量费用,普通用户获得了糟糕的下载体验; 他们的宽带还是被运营商停了。

默认的地址是 bigota.d.miui.com, 改成

cdn-ota.azureedge.net
cdnorg.d.miui.com
bn.d.miui.com
bkt-sgp-miui-ota-update-alisgp.oss-ap-southeast-1.aliyuncs.com

有时候可以提高下载速率

https://bn.d.miui.com/V12.5.15.0.RGGEUXM/begonia_eea_global_images_V12.5.15.0.RGGEUXM_20220826.0000.00_11.0_eea_b8c6b15c15.tgz

https://cdn-ota.azureedge.net/V12.5.15.0.RGGEUXM/begonia_eea_global_images_V12.5.15.0.RGGEUXM_20220826.0000.00_11.0_eea_b8c6b15c15.tgz

https://cdn-ota.azureedge.net/V13.0.8.0.SJHCNXM/atom_images_V13.0.8.0.SJHCNXM_20230630.0000.00_12.0_cn_acca549dfc.tgz

wget -c      --referer="https://miui.com/"    https://hugeota.d.miui.com/V12.5.6.0.RGGCNXM/begonia_images_V12.5.6.0.RGGCNXM_20220602.0000.00_11.0_cn_fbed701a77.tgz

MTK之NVRAM实现数据的备份与恢复

2017年的时候有做过这样的一个定制化需求:写入一个文件数据,恢复出厂设置后该文件数据也要恢复。

第一步:nvram lib id定义
vendor/mediatek/proprietary/custom/project/cgen/inc/Custom_NvRam_LID.h

typedef enum
{
    AP_CFG_RDCL_FILE_AUDIO_LID=AP_CFG_CUSTOM_BEGIN_LID, //AP_CFG_CUSTOM_BEGIN_LID: this lid must not be changed, it is reserved for system.
    AP_CFG_RDCL_FILE_AUDIO_MAGI_CONFERENCE_LID,
    AP_CFG_RDCL_FILE_AUDIO_HAC_PARAM_LID,
    AP_CFG_CUSTOM_TEST_CUSTOM1_LID, //zrx add 定义lib id
    AP_CFG_CUSTOM_FILE_MAX_LID,
} CUSTOM_CFG_FILE_LID;

//zrx add 添加LID版本信息
#define AP_CFG_CUSTOM_TEST_CUSTOM1_LID_VERNO        "000"

第二步:nvram lib id的数据结构和版本号声明
vendor/mediatek/proprietary/custom/project/cgen/inc/Custom_NvRam_data_item.h

//zrx add
LID_BIT VER_LID(AP_CFG_CUSTOM_TEST_CUSTOM1_LID)
Test_Custom1_Struct *CFG_TEST_CUSTOM1_REC_TOTAL
{

};

第三步:nvram lib数据结构定义
vendor/mediatek/proprietary/custom/project/cgen/cfgfileinc/CFG_Custom1_File.h

//zrx add start
typedef struct
{
    unsigned char Array[1024];
}Test_Custom1_Struct;
//zrx add end

//zrx add start
#define CFG_TEST_CUSTOM1_REC_SIZE    sizeof(Test_Custom1_Struct)
#define CFG_TEST_CUSTOM1_REC_TOTAL   1
//zrx add end

第四步:nvram lib 默认值定义
vendor/mediatek/proprietary/custom/project/cgen/cfgdefault/CFG_Custom1_Default.h

Test_Custom1_Struct stCustom2Default =
{

    0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
    
};

第五步:nvram lib内容加入nvram数组中
vendor/mediatek/proprietary/custom/m107/cgen/inc/CFG_file_info_custom.h

#include "../cfgfileinc/CFG_Custom1_File.h"
#include "../cfgdefault/CFG_Custom1_Default.h"

 const TCFG_FILE g_akCFG_File_Custom[]=
    {

    { "/data/nvram/APCFG/APRDCL/Test_Custom1",   VER(AP_CFG_CUSTOM_TEST_CUSTOM1_LID), CFG_TEST_CUSTOM1_REC_SIZE,
            CFG_TEST_CUSTOM1_REC_TOTAL, SIGNLE_DEFUALT_REC  ,    (char *)&stCustom2Default, DataReset , NULL
        },
    };

第六步:nvram lib id需要备份到BinRegion
vendor/mediatek/proprietary/external/nvram/libcustom_nvram/CFG_file_info.c

FileName aBackupToBinRegion[]=
{
  {"CUSTOM_TEST",AP_CFG_CUSTOM_TEST_CUSTOM1_LID},
}

pfConvertFunc aNvRamConvertFuncTable[]=
{
  NULL,//AP_CFG_CUSTOM_TEST_CUSTOM1_LID
}

const TABLE_FOR_SPECIAL_LID g_new_nvram_lid[] =
{
    { AP_CFG_CUSTOM_TEST_CUSTOM1_LID, 1024 * 1024, 1024 * 1024},
};

第七步:上层读写nvram数据接口
NvRAMAgent.java

package com.example.nvram_test;

import android.os.IBinder;

public interface NvRAMAgent extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements NvRAMAgent
    {
        private static final java.lang.String DESCRIPTOR = "NvRAMAgent";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an NvRAMAgent interface,
         * generating a proxy if needed.
         */
        public static NvRAMAgent asInterface(android.os.IBinder obj)
        {
            if ((obj == null)) {
                return null;
            }

            android.os.IInterface iin = (android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);

            if (((iin != null) && (iin instanceof NvRAMAgent))) {
                return ((NvRAMAgent) iin);
            }

            return new NvRAMAgent.Stub.Proxy(obj);
        }
        public android.os.IBinder asBinder()
        {
            return this;
        }
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            switch (code)
            {
            case INTERFACE_TRANSACTION:
            {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_READFILE:
            {
                data.enforceInterface(DESCRIPTOR);
                int _arg0;
                _arg0 = data.readInt();
                byte[] _result = this.readFile(_arg0);
                reply.writeNoException();
                reply.writeByteArray(_result);
                return true;
            }
            case TRANSACTION_WRITEFILE:
            {
                data.enforceInterface(DESCRIPTOR);
                int _arg0;
                _arg0 = data.readInt();
                byte[] _arg1;
                _arg1 = data.createByteArray();
                int _result = this.writeFile(_arg0, _arg1);
                reply.writeNoException();
                reply.writeInt(_result);
                return true;
            }
            default:
            {
                break;
            }
            }

            return super.onTransact(code, data, reply, flags);
        }
        private static class Proxy implements NvRAMAgent
        {
            private android.os.IBinder mRemote;
            Proxy(android.os.IBinder remote)
            {
                mRemote = remote;
            }
            public android.os.IBinder asBinder()
            {
                return mRemote;
            }
            public java.lang.String getInterfaceDescriptor()
            {
                return DESCRIPTOR;
            }
            public byte[] readFile(int file_lid) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte[] _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(file_lid);
                    mRemote.transact(Stub.TRANSACTION_READFILE, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createByteArray();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }
            public int writeFile(int file_lid, byte[] buff) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(file_lid);
                    _data.writeByteArray(buff);
                    mRemote.transact(Stub.TRANSACTION_WRITEFILE, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }

            public byte[] readFileByName(String filename) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte[] _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(filename);
                    mRemote.transact(Stub.TRANSACTION_READFILEBYNAME, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createByteArray();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }

            public int writeFileByName(String filename, byte[] buff) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(filename);
                    _data.writeByteArray(buff);
                    mRemote.transact(Stub.TRANSACTION_WRITEFILEBYNAME, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }

                return _result;
            }
        }
        static final int TRANSACTION_READFILE = (IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_WRITEFILE = (IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_READFILEBYNAME = (IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_WRITEFILEBYNAME = (IBinder.FIRST_CALL_TRANSACTION + 3);
    }
    public byte[] readFile(int file_lid) throws android.os.RemoteException;
    public int writeFile(int file_lid, byte[] buff) throws android.os.RemoteException;
    public byte[] readFileByName(String filepath) throws android.os.RemoteException;
    public int writeFileByName(String filepath, byte[] buff) throws android.os.RemoteException;
}

第八步:读写数据帮助类
Utils.java

ackage com.example.nvram_test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;

import android.content.Context;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;
import android.widget.Toast;

public class Utils {
    final String TAG = "Utis";
    byte[] buff;
    Context mContext;
    public Utils(Context mContext){
        this.mContext=mContext;
    }   

    /**
     * 多个字节数组合并为一个字节数组
     * @param a 字节数组
     * @param b 字节数组
     * @return byte[]
     */
    public byte[] combineBytes(byte[] a, byte[] b) {
        byte[] bytes = new byte[a.length + b.length];
        System.arraycopy(a, 0, bytes, 0, a.length);
        System.arraycopy(b, 0, bytes, a.length, b.length);
        return bytes;
    }   

    /**
     * 写文件到app下
     */
    public void writeOwnFile(String fileName,String message){
        try {
            FileOutputStream fout = mContext.openFileOutput(fileName,
                    mContext.MODE_PRIVATE);
            byte[] bytes = message.getBytes();
            fout.write(bytes);
            fout.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从app下读文件
     * @param fileName
     * @return
     */
    public String readOwnFile(String fileName){
        try {
            FileInputStream fis=mContext.openFileInput(fileName);
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int len=0;
            while((len=fis.read(buffer))!=-1){
                bos.write(buff, 0, len);
            }
            byte[] content_byte = bos.toByteArray();  
            String content = new String(content_byte);  
            return content;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 写文件
     * @param fileName 文件名
     * @param bytes 字节数组
     */
    public void writeFile(String fileName,byte[] bytes){
         try {              
                FileOutputStream fout = new FileOutputStream(fileName);            
                fout.write(bytes);
                fout.close();               
            } catch (Exception e) {
                e.printStackTrace();
            }
    }

    /**
     * 读文件
     * @param fileName 文件名
     * @return byte[]
     */
    public byte[] readFile(String fileName){
        try {
            FileInputStream fin = new FileInputStream(fileName);
            int length = fin.available();
            byte [] buffer = new byte[length];
            fin.read(buffer); 
            fin.close();
            return buffer;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return buff;
    }

    /**
     * 写值到NvRam
     * @param file_name NvRam路径
     * @param bytes 字节数组
     */
    public void writeData(String file_name, byte[] bytes) {
        byte[] buff=new byte[1024];
        if(bytes.length 0) {
                Toast.makeText(mContext, "write Success", Toast.LENGTH_SHORT).show();
            //  Log.d(TAG, "zrx----write Success");
            } else {
                Toast.makeText(mContext, "write Failure", Toast.LENGTH_SHORT).show();
                Log.d(TAG, "zrx---- write Failure");
            }
        }
    }

    /**
     * 从NvRam读值
     * @param file_name NvRam路径
     * @param offset  开始位置
     * @param byteCount 字节数
     * @return
     */
    public byte[] readData(String file_name,int offset,int byteCount) {
        byte[] data=new byte[byteCount];
        IBinder binder = ServiceManager.getService("NvRAMAgent");
        NvRAMAgent agent = NvRAMAgent.Stub.asInterface(binder);
        if (agent != null) {
            try {
                buff = agent.readFileByName(file_name);
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
        if (buff != null) {
            try {
                for(int i=0;i

第九步:验证
MainActivity.java

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.example.nvram_test.R;

public class MainActivity extends Activity{
    String TAG="MainActivity";

    /**
     * 文件名在vendor/mediatek/proprietary/custom/m107/cgen/inc/CFG_file_info_custom.h中有定义
     */
    private static final String TEST_FILENAME = "/data/nvram/APCFG/APRDCL/Test_Custom1";
    Button btn1;
    Button btn2;
    Button btn3;
    Button btn4;
    Utils utils;
    /**
     * 测试备份SecretKey文件的路径
     */
    private static final String secret_filename="/storage/emulated/0/SecretKey";

    /**
     * 测试备份goc_database文件的路径
     */
    private static final String goc_database="/storage/emulated/0/goc_database";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        utils=new Utils(this);
        btn1=(Button)findViewById(R.id.btn1);
        btn2=(Button)findViewById(R.id.btn2);

        btn3=(Button)findViewById(R.id.btn3);
        btn4=(Button)findViewById(R.id.btn4);

        /**
         * 测试把SecretKey文件的字节备份到NvRam下
         */
        btn1.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                byte[] a=utils.readFile(secret_filename); //读SecretKey文件
                utils.writeData(TEST_FILENAME, a); //把SecretKey文件的字节备份到NvRam下

                //byte[] b=utils.readData(TEST_FILENAME, 0, a.length);
            /*    if(!Arrays.equals(a, b)){
                    utils.writeData(TEST_FILENAME, a);
                }else{
                    Toast.makeText(MainActivity.this, "SecretKey Data has existed, no need to backup!", Toast.LENGTH_SHORT).show();
                }*/
            }
        });

        /**
         * 测试从NvRAM读SecretKey文件的字节
         */
        btn2.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                byte[] bytes=utils.readData(TEST_FILENAME,0,27);//测试从NvRAM读SecretKey文件的字节
                Toast.makeText(getApplicationContext(), "data = "+new String(bytes), Toast.LENGTH_LONG).show();
            }
        });

        /**
         * 测试写goc_database文件的字节到NvRAM
         */
        btn3.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                byte[] bytes=utils.readFile(goc_database); //goc_database文件的字节
                byte[] a=utils.readData(TEST_FILENAME,0,27); //读NvRAM下SecretKey文件的字节
                utils.writeData(TEST_FILENAME, utils.combineBytes(a, bytes));           
            }
        });

        /**
         * 测试写到NvRAM下的goc_database文件字节是否与原文件goc_database是否一样。
         */
        btn4.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub              
                byte[] bytes=utils.readFile(goc_database); //读goc_database文件
                byte[] b=utils.readData(TEST_FILENAME, 27, bytes.length); //读NvRAM下的goc_database字节
                utils.writeFile("/storage/emulated/0/goc_database2", b);    //把NvRAM下的goc_database字节写到goc_database2文件,  goc_database2文件与原文件goc_database比对,发现是相同的。                   
            }
        });
    }


}

JDRead1

硬件

CPU:  Onyx i.MX 6SoloLite
[ro.hardware]: [freescale]
ro.product.manufacturer]: [Onyx]
[ro.build.fingerprint]: [Onyx/JDRead/JDRead:4.4.2/2018-06-29_16-28_r3_a9ff2db/371:user/dev-keys]

开启USB调试
(0)联网
开启JDRead1,连接WiFi

(1)设置密码为0423
设置-设备名称-密码设置:密码输入0423,手机号输入自己的手机号。
为什么设置密码为 0423, 请看 https://www.senventise.com/posts/jdread1-exploit/

(2)开启开发者权限
设置-设备名称-设备信息:连续点击系统版本,直到显示“已开启开发者权限”。

https://www.cnblogs.com/arbo/p/14619813.html

用kingroot进行root
jdread1小白教程及软件v2.2.zip

提醒: 不要替换 services.jar

Kindle Paperwhite 3

型号: DP75SDI
属于 Kindel的 第七代 产品

2015 年 6 月 17 日,亚马逊上架了全新 Kindle Paperwhite(KPW3)电子书阅读器。像素 300 ppi, RAM增大了一倍,也就是说运行速度也会有较大提升,但Storage依然是 4GB。 这款新机在亚马逊中国上的预订价格为 958 元,2015 年 6 月 30 日正式发货。

Jailbreak
参考资料:
https://www.mobileread.com/forums/showthread.php?t=225030
https://bookfere.com/post/892.html
https://bookfere.com/post/311.html
https://bookfere.com/post/59.html

设备信息
序列号 G090 G1
固件版本 5.8.11
硬件 Hardware : Freescale i.MX 6SoloLite based Wario Board

步骤:
1. 通过序列号 确定型号
(G090G1 Kindle PaperWhite 3 (2015) WiFi PW3 型号)
可以root / jailbreak

2. 充满电

3. 关掉密码 , 关掉家长控制

4. 开启 飞行模式,关闭3G/WiFi


更新到 5.12.3 固件 https://s3.amazonaws.com/firmwaredownloads/update_kindle_all_new_paperwhite_5.12.3.bin

固件文件名:update_kindle_all_new_paperwhite_5.12.3.bin
MD5 校验码:e4d7ff60132c58448b0c1b31d5961b12
SHA1 校验码:ff8cf3a93ce37f6adf7c12b5166f73dc0ba929fe

6. 下载 kindle-jb-kindlebreak-1.0-r18327.tar.xz

下载 jb-kindlebreak.zip 并解压,得到下列四个文件,把它们全部拷贝到 Kindle 根目录(所谓根目录,就是那个目录下有一个叫documents的子目录)

kindlebreak.jxr
kindlebreak.html
jb.sh
jb

接着点击 Kindle 右上角的菜单按钮,进入“体验版网页浏览器(Experimental Browser)”。

请务必确保“浏览器设置”中的图片设置处于启用状态,也就是显示“禁用图片(Disable Images)”字样。如显示的是“启用图片(Enable Images)”字样,你需要点击启用,以确保浏览器能够正常解析图片。

最后输入如下所示的文件地址(注意 file:/// 是一个冒号三个斜杠):

file:///mnt/us/kindlebreak.html

如果一切正常,Kindle 会在数秒至数分钟后自动重启(时长取决于不同设备)。重启完毕越狱便告成功。之前放进去的文件会被自动清理,你会在 Kindle 根目录看到一个日志文件 kindlebreak_log.txt。

7. 安装热修复补丁 JailBreak-1.16.N-FW-5.x-hotfix.zip

Jailbreak Hotfix 的具体安装步骤如下:

(1)用 USB 数据线把 Kindle 连接到电脑,直到出现 Kindle 盘符;
(2)解压缩下载到的 ZIP 压缩包 JailBreak-x.xx.N-FW-5.x-hotfix.zip,得到一个名为 Update_jailbreak_hotfix_x.xx.N_install.bin 的文件;
(3)将此 bin 文件拷贝到 Kindle 磁盘根目录,然后从电脑弹出 Kindle;
(4) 依次在 Kindle 中点击【菜单 → 设置 → 菜单 → 更新您的 Kindle】,等待重启;

8. 安装 MobileRead Package Installer (MRPI)

(1)用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
(2) 解压缩下载到的 kual-mrinstaller-1.7.N-xxx.tar.xz 得到一个文件夹;
(3)把文件夹内的 extensions 和 mrpackages 拷贝到 Kindle 的根目录。
(4)从电脑上断开 Kindle磁盘,重启Kindel

注意,如果根目录已有 extensions 这个文件夹,可以只把解压得到的 extensions 文件夹中的内容拷贝到 Kindle 根目录原有的 extensions 文件夹内,以避免原文件夹内的其它文件被删除。

9. 安装 KUAL ( Kindle Unified Application Launcher)
(1) 用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
(2) 如果没有安装MRPI, 先按照第8步的方法安装 MobileRead Package Installer (MRPI);
(3) 然后解压缩下载到的 KUAL-v2.x.xx-xxxxxxxx-20xxxxxx.tar.xz 得到一个文件夹;
在文件夹中找到 Update_KUALBooklet_v2.x.xx_install.bin 文件,拷贝到 Kindle 根目录下的 mrpackages 文件夹,然后在 Kindle 搜索框中输入 ;log mrpi 点击回车;
这时会调用 mrpi 安装 KUAL,安装完成并等待 Kindle 重启完毕后即可使用 KUAL。

10. 安装 Koreader

首先确保安装了 MRPI 和 KUAL;
用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
解压缩下载到的 Koreader 压缩包,可得到 extensions 和 koreader 两个文件夹;
先把文件夹 extensions 中的内容拷贝到 Kindle 根目录下的 extensions 文件夹中;
然后把文件夹内的 koreader 文件夹拷贝到 kindle 根目录下;
通过 KUAL 菜单中启动 Koreader 并用它的文件浏览器打开并阅读电子书。

11. 安装 USBNetwork

(1)首先确保安装了 MRPI 和 KUAL;
(2)用 USB 数据线将 Kindle 连接到电脑上,直到出现 Kindle 磁盘;
(3) 解压缩下载到的 kindle-usbnet-0.xx.N-rxxxxx.tar.xz 压缩包,得到一个文件夹;
(4) 把文件夹内的 Update_usbnet_0.xx.N_install_pw2_and_up.bin 拷贝到 Kindle 里 mrpackages 文件夹中;
(5)弹出 Kindle 磁盘,进入 Kindle 界面,打开 KUAL,依次点击菜单【Helper → Install MR Packages】(或在搜索栏输入 ;log mrpi 并回车);
耐心等待 USBNetwork 安装,直到安装完成后 Kindle 重启完毕;

配置 USBNetwork
修改配置文件

重启完成后,可以在 Kindle 根目录可以看到 usbnet 文件夹。首先将此文件夹中的文件 DISABLED_auto 重命名为 auto。然后在此文件夹里的 etc 文件夹中找到配置文件 config,并用代码编辑器(如 Sublime Text)将其打开。找到 USE_WIFI 和 USE_WIFI_SSHD_ONLY 两个配置项,将两者的值从默认的 false 修改为 true(注意,两者都要改成 true),保存并关闭。

USE_WIFI="true"
USE_WIFI_SSHD_ONLY="true"

如果不将USE_WIFI_SSHD_ONLY 改为true, 会导致 将kindel通过usb插入电脑时, 不识别 Kindle 磁盘

创建密钥

ssh-keygen -t rsa -f ~/Desktop/KindleKey

会在你的桌面上会出现 KindleKey 和 KindleKey.pub 两个文件,把其中的 KindleKey.pub 重命名为 authorized_keys,并拷贝到 usbnet 插件目录中的 etc 文件夹中。

ssh登陆到kindle

ssh -i KindleKey root@192.168.xxx.xxx

在 Kindle 搜索框中输入 ;711 可以看到 Kindel分配到IP地址

红米Note 10 Pro启动modem分析

Redmi Note 10 Pro
天玑1100
CPU型号为 MT6891Z/CZA
( MT6885,天玑1000L, 联发科的首款5G芯片)

sysfs

/sys/kernel/ccci
/sys/class/ccci_node/ccci_ccb_meta
/sys/class/ccci_node/ccci_ccb_md_monitor
/sys/class/ccci_node/ccci_raw_mdm
/sys/class/ccci_node/ccci_mdl_monitor

/sys/class/ccci_md_sta/ccci_md1_sta
/sys/firmware/devicetree/base/mddriver/ccci,modem_info_v2

代码

drivers/misc/mediatek/ccci_util/ccci_util_lib_load_img.c

drivers/misc/mediatek/ccci_util/ccci_util_lib_sys.c


drivers/misc/mediatek/eccci/ccci_core.c
    ccci_init(void)



drivers/misc/mediatek/eccci/mt6885/ccci_platform.c
     ccci_plat_common_init


配置地址

drivers/misc/mediatek/eccci/ccci_modem.c
void ccci_md_config(struct ccci_modem *md)
{
	phys_addr_t md_resv_mem_addr = 0,
		md_resv_smem_addr = 0, md1_md3_smem_phy = 0;
	unsigned int md_resv_mem_size = 0,
		md_resv_smem_size = 0, md1_md3_smem_size = 0;
	int amms_pos_size = 0;
	phys_addr_t bank4_phy_addr;
......
......
	/* Get memory info */
	get_md_resv_mem_info(md->index, &md_resv_mem_addr,
		&md_resv_mem_size, &md_resv_smem_addr, &md_resv_smem_size);
	get_md1_md3_resv_smem_info(md->index, &md1_md3_smem_phy,
		&md1_md3_smem_size);
	/* setup memory layout */
	/* MD image */
	md->mem_layout.md_bank0.base_ap_view_phy = md_resv_mem_addr;
	md->mem_layout.md_bank0.size = md_resv_mem_size;
	/* do not remap whole region, consume too much vmalloc space */
	md->mem_layout.md_bank0.base_ap_view_vir =
		ccci_map_phy_addr(
			md->mem_layout.md_bank0.base_ap_view_phy,
			MD_IMG_DUMP_SIZE);
	/* Share memory */
	/*
	 * MD bank4 is remap to nearest 32M aligned address
	 * assume share memoy layout is:
	 * |---AP/MD1--| <--MD1 bank4 0x0 (non-cacheable)
	 * |--MD1/MD3--| <--MD3 bank4 0x0 (non-cacheable)
	 * |---AP/MD3--|
	 * |--non-used_-|
	 * |--cacheable--| <-- MD1 bank4 0x8000000 (for 6292)
	 * this should align with LK's remap setting
	 */



eccci/modem_sys1.c
    ccci_set_mem_access_protection_1st_stage(md);


eccci/fsm/ccci_fsm.c

    ccci_set_mem_access_protection_second_stage








modem firmware的结构
代码位于 drivers/misc/mediatek/ccci_util/ccci_util_lib_load_img.c



#define IMG_MAGIC		0x58881688
#define EXT_MAGIC		0x58891689

#define IMG_NAME_SIZE		32
#define IMG_HDR_SIZE		512
union prt_img_hdr {
	struct {
		/* always IMG_MAGIC */
		unsigned int magic;
		/* image size, image header and padding are not included */
		unsigned int dsize;
		char name[IMG_NAME_SIZE];
		/* image load address in RAM */
		unsigned int maddr;
		/* maddr is counted from the beginning or end of RAM */
		unsigned int mode;
		/* extension */
		/* always EXT_MAGIC */
		unsigned int ext_magic;
		/* header size is 512 bytes currently,
		 * but may extend in the future
		 */
		unsigned int hdr_size;
		/* see HDR_VERSION */
		unsigned int hdr_version;
		/* please refer to #define beginning with SEC_IMG_TYPE_ */
		unsigned int img_type;
		/* end of image list?
		 * 0: this image is followed by another image
		 * 1: end
		 */
		unsigned int img_list_end;
		/* image size alignment setting in bytes,
		 * 16 by default for AES encryption
		 */
		unsigned int align_size;
		/* high word of image size for 64 bit address support */
		unsigned int dsize_extend;
		/* high word of image load address in RAM
		 * for 64 bit address support
		 */
		unsigned int maddr_extend;
	} info;
	unsigned char data[IMG_HDR_SIZE];
};

USRP B210

SMA天线接口 有3个输入信号:
1. 外部 PPS 参考
2. 10 MHz 时钟 参考
3. GPS信号
都是所谓 Timing Reference Input (定时基准输入)

1 PPS
秒脉冲 (Pulse Per Second)

PPS 时间参考 和 10MHz 时钟参考,主要用于多个 B210之间进行同步。
B210接受外部PPS信号进行时间校准,以及10 MHz参考频率校准—这允许外部时间和频率源用于更精确的同步
GPS则可实现 在物理位置上相距非常大的 多个B210之间 的时间同步。

GPS时钟主要分为两类,
一类是GPS授时仪,主要输出时标信息,包括1 PPS及TOD信息;
另外一类是GPS同步时钟,后者输出利用卫星信号驯服OCXO或者铷钟得到的高稳定频率信息,以及本地恢复的更平稳的时标信号。

高精度1 PPS信号,精度优于50ns,占空比为50%,1 PPS信号 上升沿为时间同步点,上升沿时间小于5ns。


两个接收前端共享RX LO(本振),而两个发射前端共享TX LO。每个本振可在50mhz和6ghz之间独立调谐,可用于1或2个信道;所有使用相同本振的信道必须使用相同的采样参数,包括采样率和射频中心频率。


附带的USB 3.0电缆为USRP总线系列提供电源和数据连接。
我的板子带了GPSDO,必须连接外部直流电源(12V 3A)

所有GPSDO都有一些共同的特性。每个GPSDO包括一个10 MHz振荡器,可以是TCXO或OCXO。10MHz振荡器可以独立工作,也就是说,
即使GPSDO没有锁定到卫星星座,它也可以提供时钟。

根据GPSDO型号,解锁振荡器将提供20~75 ppb之间的系统频率精度。
GPSDO模块还将产生1-pps信号,用于定时同步。如果连接了GPS天线,GPSDO将锁定到GPS卫星星座,并且10 MHz振荡器可以按照全球GPS标准进行调节。在这种情况下,1-pps信号也将在50ns内与全球标准对齐。

共享一个时钟总是比尝试通过GPS同步要好。gpsdo将代替共享时钟,提供下一个最佳的同步级别,这对于大多数应用程序来说已经足够了。

但前面也说了,GPS也更加灵活,因为设备可以在地理上相隔十万八千里,但依然保持同步。

板载OCXO和板载TCXO的结构和工作原理是相同的。然而,TCXO消耗较少的功率,在其整个温度范围内提供较少的精度,并且具有不同的相位噪声特性。

我的是 OCXO, 需要外接电源。


输入/输出阻抗
所有射频端口通常匹配50欧姆,回波损耗为-10dB或更好


LED600 电源指示
灭 = 无供电 或者 外部供电,但初始化 未完成
蓝 = USB供电
红 = 外部供电成功(初始化完成)

LED800 通道2 接收2
灭 = 无供电
绿色 = 正在接收

LED801 通道2 发送/接收
灭 = 无供电
绿色 = 正在接收
红色 = 正在发送
橙色 = 正在切换(发送或接收)

LED802 通道1 发送/接收
灭 = 无供电
绿色 = 正在接收
红色 = 正在发送
橙色 = 正在切换(发送或接

LED803 通道1 接收2
灭 = 无供电
绿色 = 正在接收

LED100 GPS锁定指示
灭 = 没有锁定
绿色 = 已经锁定


J601 外部供电接口 6V 3A
J701 USB3 接口
J104 外部PPS 输入 (1.8 V – 5 V )
J101 GPS天线 (GPSDO will supply nominal voltage to antenna)
J100 外部10 MHz输入 (最大 +15 dBm )
J800 射频天线B TX/RX (发射功率 最大+20 dBm, 接收 -15 dBm)
J802 射频天线B 接收2 ( 接收 -15 dBm)
J803 射频天线A 接收2 ( 接收最大 -15 dBm)


当使用 GPSDO 时, 不能使用 外部10MHz 输入, 除非将 GPSDO从板子上拿走

MIPS16

MIPS16
MIPS16是从MIPS I到V的特定应用扩展,由LSI Logic和MIPS科技设计,于1996年10月21日与其第一个实现LSI Logic TinyRISC处理器一起发布

MIPS16使用16位指令而不是32位指令,减少应用程序的大小多达40%,并且还提高了电源效率、指令缓存命中率,并且在性能方面与其基础架构相当。它由MIPS科技和其他供应商的硬件和软件开发工具提供支持。

MIPS16e是MIPS16的改进版本,首先由MIPS32和MIPS64 Release 1支持。MIPS16e2是MIPS16的改进版本,由MIPS32和MIPS64(直到Release 5)支持。Release 6将其替换为microMIPS。

microMIPS32/64架构(分别)是MIPS32和MIPS64架构的超集,旨在取代MIPS16e ASE。MIPS16e的一个缺点是在处理任何16位指令之前需要切换模式。microMIPS将最常用的32位指令编码为16位指令版本。允许程序混合16位和32位指令而无需切换模式。microMIPS与MIPS32/64 Release 3一起推出,MIPS32/64的每个后续版本都有相应的microMIPS32/64版本。处理器可以单独实现microMIPS32/64,或同时实现microMIPS32/64及其相应的MIPS32/64子集。从MIPS32/64 Release 6开始,对MIPS16e的支持结束,microMIPS是MIPS中唯一的代码压缩形式。

nanoMIPS32


MIPS有几个调用约定,尤其是在32位平台上。

O32 ABI是最常用的ABI,因为它是MIPS的原始System V ABI。它严格基于堆栈,只有四个寄存器$a0-$a3可用于传递参数。堆栈上的空间是保留的,以防被调用者需要保存其参数,但调用者不会将寄存器存储在那里。返回值存储在寄存器$v0中;第二个返回值可以存储在$v1中。ABI形成于1990年,最后一次更新是在1994年。这种肉眼可见的缓慢,以及只有16个寄存器的老式浮点模型,促进了许多其他调用约定的扩散。它仅针对32位MIPS定义,但GCC创建了一个名为O64的64位变体

对于O32及N32/N64,返回地址存储在$ra寄存器中。这是使用JAL(跳转和链接)或JALR(跳转和链接寄存器)指令自动设置的。(非叶子)MIPS子例程的函数序言将返回地址(在$ra中)推入堆栈


MediaTek has adopted multi-threaded MIPS I-class CPUs for smartphone LTE modems. The first device from MediaTek featuring MIPS technology is the new flagship MT6799 Helio™ X30 processor which uses MIPS in its Cat-10 LTE modem.

自从 2014 年发布 MIPS R6 版本之后, MIPS 公司的 IP Core 产品全面转向 MIPS R6 版本,形成覆盖高中低不同性能和应用需求的 Warrior 产品系列, 而把 R6 之前的产品全部归为 Classic 系列。 Warrior 产品系列又分为 M-Class, I-Class 和 P-Class 三个级别,覆盖了从 32 位微控制器到 64 位服务器与基础设施之间的所有领域。

P-class 采用 MIPS R6 MIPS 指令集,当前的产品是 P6600 (MIPS64 R6) 和 P5600 (32-bit MIPS32 R5)。
I-class 采用 MIPS R6 nanoMIPS 指令集,用于嵌入式设备,当前的产品是 I7200 (2.1 GHz, 32-bit nanoMIPS),I6500-F (MIPS64 R6),I6500 (MIPS64 R6) 和 I6400 (MIPS64 R6)。
M-class 采用 MIPS R6 microMIPS 指令集,用于微控制器,当前的产品是 M6250 (64 bit,4GB Virtual Memory,750 MHz),M6200,M51xx。

联发科用于modem的就是I系列, nanomips指令集

nanoMIPS designed for embedded devices, it can deliver up to 40% smaller code than MIPS32. With smaller memory accesses and efficient use of the instruction cache, nanoMIPS also helps to reduce system power consumption.


联发科的4G处理器 Helio 系列的是 MIPS16e2
5G处理器 Dimensity的是 nanoMIPS

MT6763 modem 编译

modem部分,MTK给 大的手机公司(小米、OPPO、vivo) 比如大的设计公司 (华勤通讯、龙旗科技、闻泰科技) 和 模块厂商 (移远,广和通,美格,日海) 才是全部源代码。

小厂家拿到 都是 二进制的lib 和 部分定制参数的 源代码

magnet:?xt=urn:btih:f677fe1da33fd349130cdb2404a13c8ecdf7da4f&dn=t-alps-q0.mp1-V9.122.1
里面的
TK_MD_BASIC_MOLY.LR12A.R2.MP.V143.7.tar.zst

推荐的编译环境

 Recommended Build Environment
*******************************************
* [OS]         : Linux
* [PERL]       : v5.14.2 or v5.18.4  / v5.26.1
* [MAKE]       : GNU Make v3.81   / v4.1
* [SHELL]      : GNU bash v4.2.25 or v4.3.11
* [COMPILER]   : v4.9.2 or above
* [Host GCC]   : gcc version 4.8.4
* [Perl Module]: Switch.pm, File/Copy/Recursive.pm, XML/Simple.pm

实际的编译环境
Debian Buster
[PERL] : v5.28.1
[MAKE] : GUN Make v4.2.1
[COMPILER] : v4.9.2(2016.05-08) [OK]
[HOST GCC] : v8.3.0

apt install build-essential
apt install libswitch-perl    libfile-copy-recursive-perl  libxml-simple-perl

https://codescape.mips.com/components/toolchain/2016.05-08/Codescape.GNU.Tools.Package.2016.05-08.for.MIPS.MTI.Bare.Metal.CentOS-5.x86_64.tar.gz
(MTI Bare Metal Toolchain MIPS32R2-MIPS32R5, MIPS64R2-MIPS64R5 and microMIPS)

编译 硬件配置 16G RAM, 100G Storage

mkdir ~/modem
cd  ~/modem
tar xvaf ~/Downloads/TK_MD_BASIC_MOLY.LR12A.R2.MP.V143.7.tar.zst
cd mcu/common/tools
mkdir -p GCC/MIPS/4.9.2
cd GCC/MIPS/4.9.2
tar xvaf ~/Downloads/Codescape.GNU.Tools.Package.2016.05-08.for.MIPS.MTI.Bare.Metal.CentOS-5.x86_64.tar.gz
cd mips-mti-elf
mv 2016.05-08/ ../linux
cd  ~/modem/
cd mcu
common/tools/GCC/MIPS/4.9.2/linux/bin/mips-mti-elf-gcc -v

MIPS gcc 的版本应该是 2016.05-08

cd ~/modem
cd mcu
ls -a make/projects

可以看到
'TK_MD_BASIC(LWCTG_R2_6763).mak'  'TK_MD_BASIC(LWTG_R2_6763).mak'

开始编译

./m  "TK_MD_BASIC(LWTG_R2_6763).mak"  new

在编译前,可以对定制目录 mcu/pcore/custom 的内容进行修改

编译生成的 结果在 mcu/build/TK_MD_BASIC/LWTG_R2_6763/bin 目录下

TK_MD_BASIC_MDBIN_PCB01_MT6763_S00.MOLY_LR12A_R2_MP_V143_7.bin
就是
md1bin.img (也就是 md1rom)

DbgInfo_LR12A.R2.MP_TK_MD_BASIC_MOLY_LR12A_R2_MP_V143_7_2024_02_15_09_49

md_all_in_one/single_bin_modem.bin


perl device/mediatek/build/build/tools/modemRenameCopy.pl ./ “TK_MD_BASIC(LWTG_R2_6763).mak”

执行modemRenameCopy.pl脚本,这个步骤一定不能漏掉。

它的作用是把所有需要拷贝到AP端的文件收集到temp_modem文件夹中(modem codebase根目录下),并且还会生成一个Android.mk文件。
————
在Android源码目录device/mediatek/build/build/tools 下执行命令来重命令打包modem镜像
在Linux环境下进入如上Android目录,执行命令
./modemRenameCopy.pl ~//mtk/modem/mcu “TK_MD_BASIC(LWCTG_R2_6763).mak”

然后在modem代码目录modem/mcu/temp_modem下会生成新的modem镜像文件

将md1bin.img修改成md1img.img和md1dsp.img一起放入到版本目录中,就可以用于刷机