loader.asm源碼分析

作用:通過int 15h中斷獲取內(nèi)存信息辙芍,調(diào)用的結(jié)果是BIOS會(huì)填充es:di指向的一塊內(nèi)存,此結(jié)構(gòu)成為ARDS(地址范圍描述符結(jié)構(gòu)):

    mov ebx, 0          ; ebx = 后續(xù)值, 開始時(shí)需為 0
    mov di, _MemChkBuf      ; es:di 指向一個(gè)地址范圍描述符結(jié)構(gòu)(Address Range Descriptor Structure)
.MemChkLoop:
    mov eax, 0E820h     ; eax = 0000E820h 查詢系統(tǒng)地址映射
    mov ecx, 20         ; ecx = 地址范圍描述符結(jié)構(gòu)的大小,20字節(jié)
    mov edx, 0534D4150h     ; edx = 'SMAP'
    int 15h         ; int 15h舟奠,通過這個(gè)中斷獲取內(nèi)存信息
    jc  .MemChkFail
    add di, 20             ;因?yàn)槊總€(gè)ARDS占20字節(jié)输枯,所以自增20指向下一個(gè)空白位置
    inc dword [_dwMCRNumber]    ; dwMCRNumber = ARDS 的個(gè)數(shù)
    cmp ebx, 0  ;int 15h將上次調(diào)用的計(jì)數(shù)值填充到ebx中刮萌,如果為0表示探測結(jié)束嚼贡,否則繼續(xù)探測熏纯。
    jne .MemChkLoop
    jmp .MemChkOK
.MemChkFail:
    mov dword [_dwMCRNumber], 0
.MemChkOK:

ReaderSector:

作用:從序號(Directory Entry 中的 Sector 號)為 ax 的的 Sector 開始, 將 cl 個(gè) Sector 讀入 es:bx 中。

顧名思義粤策,ReaderSector函數(shù)的作用就是讀扇區(qū)樟澜。這個(gè)函數(shù)最最重要的一條語句就是int 13h,這是一個(gè)中斷服務(wù)程序,這里僅僅介紹當(dāng)ah=2時(shí)服務(wù)程序的功能叮盘。

功能描述:讀扇區(qū)
入口參數(shù):AH=02H
AL=扇區(qū)數(shù)
CH=柱面
CL=扇區(qū)
DH=磁頭
DL=驅(qū)動(dòng)器秩贰,00H ~ 7FH:軟盤;80H ~ 0FFH:硬盤
ES:BX=緩沖區(qū)的地址
出口參數(shù):CF=0——操作成功柔吼,AH=00H毒费,AL=傳輸?shù)纳葏^(qū)數(shù),否則愈魏,AH=狀態(tài)代碼觅玻,參見功能號01H中的說明

    push    bp
    mov bp, sp
    sub esp, 2          ; 辟出兩個(gè)字節(jié)的堆棧區(qū)域保存要讀的扇區(qū)數(shù): byte [bp-2]

    mov byte [bp-2], cl
    push    bx          ; 保存 bx
    mov bl, [BPB_SecPerTrk] ; bl: 除數(shù)
    div bl          ; y 在 al 中, z 在 ah 中
    inc ah          ; z ++
    mov cl, ah          ; cl <- 起始扇區(qū)號
    mov dh, al          ; dh <- y
    shr al, 1           ; y >> 1 (其實(shí)是 y/BPB_NumHeads, 這里BPB_NumHeads=2)
    mov ch, al          ; ch <- 柱面號
    and dh, 1           ; dh & 1 = 磁頭號
    pop bx          ; 恢復(fù) bx
    ; 至此, "柱面號, 起始扇區(qū), 磁頭號" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
    mov dl, [BS_DrvNum]     ; 驅(qū)動(dòng)器號 (0 表示 A 盤)
.GoOnReading:
    mov ah, 2           ; 讀
    mov al, byte [bp-2]     ; 讀 al 個(gè)扇區(qū)
    int 13h
    jc  .GoOnReading        ; 如果讀取錯(cuò)誤 CF 會(huì)被置為 1, 這時(shí)就不停地讀, 直到正確為止

    add esp, 2
    pop bp

    ret

在根目錄區(qū)尋找KERNEL.BIN

LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
    cmp word [wRootDirSizeForLoop], 0   ; ┓
    jz  LABEL_NO_KERNELBIN      ; ┣ 判斷根目錄區(qū)是不是已經(jīng)讀完, 如果讀完表示沒有找到 KERNEL.BIN
    dec word [wRootDirSizeForLoop]  ; ┛
    mov ax, BaseOfKernelFile
    mov es, ax          ; es <- BaseOfKernelFile
    mov bx, OffsetOfKernelFile  ; bx <- OffsetOfKernelFile  于是, es:bx = BaseOfKernelFile:OffsetOfKernelFile = BaseOfKernelFile * 10h + OffsetOfKernelFile
    mov ax, [wSectorNo]     ; ax <- Root Directory 中的某 Sector 號
    mov cl, 1
    call    ReadSector ;把一個(gè)扇區(qū)讀到了BaseOfKernelFile:OffsetOfKernelFile

    mov si, KernelFileName  ; ds:si -> "KERNEL  BIN"
    mov di, OffsetOfKernelFile  ; es:di -> BaseOfKernelFile:???? = BaseOfKernelFile*10h+????
    cld
    mov dx, 10h  ;dx作為循環(huán)控制,控制一個(gè)扇區(qū)讀的最大次數(shù)培漏,因?yàn)橐粋€(gè)扇區(qū)512字節(jié)溪厘,一個(gè)條目占32字節(jié),所以最多讀16次牌柄!
LABEL_SEARCH_FOR_KERNELBIN:
    cmp dx, 0                   ; ┓
    jz  LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR  ; ┣ 循環(huán)次數(shù)控制, 如果已經(jīng)讀完了一個(gè) Sector, 就跳到下一個(gè) Sector
    dec dx                  ; ┛
    mov cx, 11 ;"KERNEL  BIN"共11個(gè)字節(jié)
LABEL_CMP_FILENAME:
    cmp cx, 0           ; ┓
    jz  LABEL_FILENAME_FOUND    ; ┣ 循環(huán)次數(shù)控制, 如果比較了 11 個(gè)字符都相等, 表示找到
    dec cx          ; ┛
    lodsb               ; ds:si -> al
    cmp al, byte [es:di]    ; if al == es:di
    jz  LABEL_GO_ON
    jmp LABEL_DIFFERENT
LABEL_GO_ON:
    inc di
    jmp LABEL_CMP_FILENAME  ;   繼續(xù)循環(huán)

LABEL_DIFFERENT:
    and di, 0FFE0h      ; else┓ 這時(shí)di的值不知道是什么, di &= e0 為了讓它是 20h 的倍數(shù)
    add di, 20h         ;     ┃
    mov si, KernelFileName  ;     ┣ di += 20h  下一個(gè)目錄條目(一個(gè)目錄條目32字節(jié))
    jmp LABEL_SEARCH_FOR_KERNELBIN;   ┛

LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
    add word [wSectorNo], 1
    jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN

LABEL_NO_KERNELBIN:
    mov dh, 2           ; "No KERNEL."
    call    DispStrRealMode     ; 顯示字符串
    jmp $           ; 沒有找到 KERNEL.BIN, 死循環(huán)在這里

LABEL_FILENAME_FOUND:
FAT12:
  • 引導(dǎo)扇區(qū)里放了一個(gè)短跳轉(zhuǎn)指令(jmp LABEL_START)和一些與FAT設(shè)置有關(guān)的參數(shù)(如每扇區(qū)的字節(jié)數(shù)畸悬、每簇扇區(qū)數(shù)...)
  • 根目錄區(qū):由若干目錄條目(Directory Entry)組成,條目最多有BPB_RootEntCnt(在引導(dǎo)扇區(qū)定義)個(gè)珊佣。一個(gè)條目占32字節(jié)蹋宦,主要定義了文件的屬性、名稱咒锻、大小妆档、日期以及在磁盤中的位置。
條目結(jié)構(gòu)
  • FAT表:存放FAT項(xiàng)(FAT Entry),每個(gè)FAT項(xiàng)12位虫碉,值代表文件的下一個(gè)簇號贾惦,但如果值大于或等于**0xFF8,則表示當(dāng)前簇是本文件的最后一個(gè)簇。FAT1和FAT2完全一樣敦捧,多一個(gè)備份须板。

這里說明一下代碼中幾個(gè)常數(shù)設(shè)置的原因:

  • mov dx, 10h :一個(gè)扇區(qū)512字節(jié),一個(gè)條目占32字節(jié)兢卵,所以一個(gè)扇區(qū)里最多存放16個(gè)條目习瑰。dx中的值用作循環(huán)控制,控制讀一個(gè)扇區(qū)時(shí)讀條目的最大值秽荤。
  • mov cx, 11:條目中存放文件名甜奄,"KERNEL BIN",占11字節(jié)柠横。

加載KERNEL:

調(diào)用ReadSector函數(shù)把Kernel加載到BaseOfKernelFile:OffsetOfKernelFile

LABEL_FILENAME_FOUND:           ; 找到 KERNEL.BIN 后便來到這里繼續(xù)
    mov ax, RootDirSectors    ;RootDirSectors:根目錄占用空間
    and di, 0FFF0h      ; di -> 當(dāng)前條目的開始

    push    eax
    mov eax, [es : di + 01Ch]       ; ┓條目[01Ch]處保存著文件大小信息
    mov dword [dwKernelSize], eax   ; ┛保存 KERNEL.BIN 文件大小
    pop eax

    add di, 01Ah        ; 條目[01Ah]處保存此條目對應(yīng)的開始簇號,因?yàn)檫@里設(shè)置一簇一扇區(qū)课兄,故開始扇區(qū)號等于開始簇號牍氛。
    mov cx, word [es:di]
    push    cx          ; 保存此 Sector 在 FAT 中的序號
    add cx, ax
    add cx, DeltaSectorNo   ;文件的開始Sector號 = DirEntry中的開始Sector號 + 根目錄占用Sector數(shù)目 + DeltaSectorNo,這時(shí) cl 里面是 LOADER.BIN 的起始扇區(qū)號 (從 0 開始數(shù)的序號)
    mov ax, BaseOfKernelFile
    mov es, ax          ; es <- BaseOfKernelFile
    mov bx, OffsetOfKernelFile  ; bx <- OffsetOfKernelFile  于是, es:bx = BaseOfKernelFile:OffsetOfKernelFile = BaseOfKernelFile * 10h + OffsetOfKernelFile
    mov ax, cx          ; ax <- Sector 號

LABEL_GOON_LOADING_FILE:
    push    ax          ; ┓
    push    bx          ; ┃
    mov ah, 0Eh         ; ┃ 每讀一個(gè)扇區(qū)就在 "Loading  " 后面打一個(gè)點(diǎn), 形成這樣的效果:
    mov al, '.'         ; ┃
    mov bl, 0Fh         ; ┃ Loading ......
    int 10h         ; ┃
    pop bx          ; ┃
    pop ax          ; ┛

    mov cl, 1
    call    ReadSector    
    pop ax          ; 取出此 Sector 在 FAT 中的序號
    call    GetFATEntry    ;找到序號為 ax 的 Sector 在 FAT 中的條目, 結(jié)果放在 ax 中
    cmp ax, 0FFFh      ;到文件的最后一個(gè)簇
    jz  LABEL_FILE_LOADED
    push    ax          ; 保存 Sector 在 FAT 中的序號
    mov dx, RootDirSectors
    add ax, dx
    add ax, DeltaSectorNo
    add bx, [BPB_BytsPerSec]
    jmp LABEL_GOON_LOADING_FILE

LABEL_FILE_LOADED:
    call    KillMotor       ; 關(guān)閉軟驅(qū)馬達(dá)
    mov dh, 1           ; "Ready."
    call    DispStrRealMode     ; 顯示字符串

跳入保護(hù)模式:

; 加載 GDTR
    lgdt    [GdtPtr]

; 關(guān)中斷,保護(hù)模式下中斷處理的機(jī)制是不同的烟阐,不關(guān)中斷會(huì)出現(xiàn)錯(cuò)誤
    cli

; 打開地址線A20,8086有20根地址線搬俊,開機(jī)時(shí)置A20=0可以保證即使現(xiàn)代計(jì)算機(jī)有很多根地址線,在實(shí)模式下尋址范圍還是和8086的結(jié)果一樣蜒茄。
    in  al, 92h
    or  al, 00000010b
    out 92h, al

; 準(zhǔn)備切換到保護(hù)模式,寄存器cr0第一位是PE位唉擂,置0,CPU運(yùn)行在實(shí)模式下檀葛。置1玩祟,CPU運(yùn)行在保護(hù)模式下。
    mov eax, cr0
    or  eax, 1
    mov cr0, eax

; 真正進(jìn)入保護(hù)模式
    jmp dword SelectorFlatC:(BaseOfLoaderPhyAddr+LABEL_PM_START)

以下代碼運(yùn)行在保護(hù)模式下


由實(shí)模式跳到此處:

初始化段寄存器屿聋,調(diào)用DispMemInfo空扎、SetupPaging、InitKernel

LABEL_PM_START:
    mov ax, SelectorVideo
    mov gs, ax              ;gs指向顯存 
    mov ax, SelectorFlatRW
    mov ds, ax              
    mov es, ax
    mov fs, ax
    mov ss, ax              ;ds,es,fs,ss指向SelectorFlatRW
    mov esp, TopOfStack     ;esp指向棧頂

    push    szMemChkTitle    ;szMemChkTitle:"BaseAddrL BaseAddrH LengthLow LengthHigh   Type"
    call    DispStr
    add esp, 4

    call    DispMemInfo
    call    SetupPaging

    mov ah, 0Fh             ; 0000: 黑底    1111: 白字
    mov al, 'P'
    mov [gs:((80 * 0 + 39) * 2)], ax    ; 屏幕第 0 行, 第 39 列胜臊。

    call    InitKernel

顯示內(nèi)存信息:

DispMemInfo:
    push    esi
    push    edi
    push    ecx

    mov esi, MemChkBuf
    mov ecx, [dwMCRNumber]  ;for(int i=0;i<[MCRNumber];i++) // 每次得到一個(gè)ARDS(Address Range Descriptor Structure)結(jié)構(gòu)
.loop:                  ;{
    mov edx, 5          ;   for(int j=0;j<5;j++)    // 每次得到一個(gè)ARDS中的成員勺卢,共5個(gè)成員
    mov edi, ARDStruct      ;   {           // 依次顯示:BaseAddrLow伙判,BaseAddrHigh象对,LengthLow,LengthHigh宴抚,Type
.1:                 ;
    push    dword [esi]     ;
    call    DispInt         ;       DispInt(MemChkBuf[j*4]); // 顯示一個(gè)成員
    pop eax         ;
    stosd               ;       ARDStruct[j*4] = MemChkBuf[j*4];
    add esi, 4          ;
    dec edx         ;
    cmp edx, 0          ;
    jnz .1          ;   }
    call    DispReturn      ;   printf("\n");
    cmp dword [dwType], 1   ;   if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2
    jne .2          ;   {
    mov eax, [dwBaseAddrLow]    ;
    add eax, [dwLengthLow]  ;
    cmp eax, [dwMemSize]    ;       if(BaseAddrLow + LengthLow > MemSize)
    jb  .2          ;
    mov [dwMemSize], eax    ;           MemSize = BaseAddrLow + LengthLow;
.2:                 ;   }
    loop    .loop           ;}
                    ;
    call    DispReturn      ;printf("\n");
    push    szRAMSize       ;
    call    DispStr         ;printf("RAM size:");
    add esp, 4          ;
                    ;
    push    dword [dwMemSize]   ;
    call    DispInt         ;DispInt(MemSize);
    add esp, 4          ;

    pop ecx
    pop edi
    pop esi
    ret

啟動(dòng)分頁機(jī)制:

SetupPaging:
    ; 根據(jù)內(nèi)存大小計(jì)算應(yīng)初始化多少PDE以及多少頁表
    xor edx, edx
    mov eax, [dwMemSize]
    mov ebx, 400000h    ; 400000h = 4M = 4096 * 1024, 一個(gè)頁表對應(yīng)的內(nèi)存大小
    div ebx
    mov ecx, eax    ; 此時(shí) ecx 為頁表的個(gè)數(shù)勒魔,也即 PDE 應(yīng)該的個(gè)數(shù)
    test    edx, edx
    jz  .no_remainder
    inc ecx     ; 如果余數(shù)不為 0 就需增加一個(gè)頁表
.no_remainder:
    push    ecx     ; 暫存頁表個(gè)數(shù)

    ; 為簡化處理, 所有線性地址對應(yīng)相等的物理地址. 并且不考慮內(nèi)存空洞.

    ; 首先初始化頁目錄
    mov ax, SelectorFlatRW
    mov es, ax
    mov edi, PageDirBase    ; 此段首地址為 PageDirBase:equ    200000h ,頁目錄開始地址
    xor eax, eax
    mov eax, PageTblBase | PG_P  | PG_USU | PG_RWW
.1:
    stosd                   菇曲;將 EAX 存儲(chǔ)到地址 ES:EDI
    add eax, 4096       ; 為了簡化, 所有頁表在內(nèi)存中是連續(xù)的.一個(gè)頁表大小4KB冠绢,4096字節(jié)
    loop    .1

    ; 再初始化所有頁表
    pop eax         ; 頁表個(gè)數(shù)
    mov ebx, 1024       ; 每個(gè)頁表 1024 個(gè) PTE
    mul ebx              ;PTE個(gè)數(shù) = 頁表個(gè)數(shù) * 1024
    mov ecx, eax        
    mov edi, PageTblBase    ; 此段首地址為 PageTblBase:equ    201000h 常潮,頁表開始地址:
    xor eax, eax
    mov eax, PG_P  | PG_USU | PG_RWW
.2:
    stosd
    add eax, 4096       ; 每一頁指向 4K 的空間
    loop    .2

    mov eax, PageDirBase
    mov cr3, eax
    mov eax, cr0
    or  eax, 80000000h
    mov cr0, eax
    jmp short .3
.3:
    nop

    ret
; 分頁機(jī)制啟動(dòng)完畢 ----------------------------------------------------------

分頁機(jī)制:

邏輯地址-->分段機(jī)制-->線性地址-->分頁機(jī)制-->物理地址

  • 頁:就是一塊內(nèi)存弟胀,大小可以是4K、1M等等
  • 開關(guān)位于寄存器cr0的PG位喊式,PG=1分頁機(jī)制開啟

尋址方式:


  • 頁目錄表:大小為4KB孵户,儲(chǔ)存在一個(gè)物理頁中,每個(gè)表項(xiàng)4字節(jié)長岔留,共1024個(gè)表項(xiàng)夏哭,每個(gè)表項(xiàng)對應(yīng)第二級的一個(gè)頁表。
  • 頁表:1024項(xiàng)献联,每項(xiàng)對應(yīng)一個(gè)物理頁竖配。

InitKernel:

InitKernel:
        xor   esi, esi
        mov   cx, word [BaseOfKernelFilePhyAddr+2Ch];`. ecx <- pELFHdr->e_phnum
        movzx ecx, cx                               ;/
        mov   esi, [BaseOfKernelFilePhyAddr + 1Ch]  ; esi <- pELFHdr->e_phoff
        add   esi, BaseOfKernelFilePhyAddr;esi<-OffsetOfKernel+pELFHdr->e_phoff
.Begin:
        mov   eax, [esi + 0]
        cmp   eax, 0                      ; PT_NULL
        jz    .NoAction
        push  dword [esi + 010h]    ;size ;`.
        mov   eax, [esi + 04h]            ; |
        add   eax, BaseOfKernelFilePhyAddr; | memcpy((void*)(pPHdr->p_vaddr),
        push  eax           ;src  ; |      uchCode + pPHdr->p_offset,
        push  dword [esi + 08h]     ;dst  ; |      pPHdr->p_filesz;
        call  MemCpy                      ; |
        add   esp, 12                     ;/
.NoAction:
        add   esi, 020h                   ; esi += pELFHdr->e_phentsize
        dec   ecx
        jnz   .Begin

        ret

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末何址,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子进胯,更是在濱河造成了極大的恐慌用爪,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件龄减,死亡現(xiàn)場離奇詭異项钮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)希停,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門烁巫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宠能,你說我怎么就攤上這事亚隙。” “怎么了违崇?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵阿弃,是天一觀的道長。 經(jīng)常有香客問我羞延,道長渣淳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任伴箩,我火速辦了婚禮入愧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嗤谚。我一直安慰自己棺蛛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布巩步。 她就那樣靜靜地躺著旁赊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪椅野。 梳的紋絲不亂的頭發(fā)上终畅,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機(jī)與錄音竟闪,去河邊找鬼离福。 笑死,一個(gè)胖子當(dāng)著我的面吹牛瘫怜,可吹牛的內(nèi)容都是我干的术徊。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼鲸湃,長吁一口氣:“原來是場噩夢啊……” “哼赠涮!你這毒婦竟也來了子寓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤笋除,失蹤者是張志新(化名)和其女友劉穎斜友,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體垃它,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鲜屏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了国拇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洛史。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酱吝,靈堂內(nèi)的尸體忽然破棺而出也殖,到底是詐尸還是另有隱情,我是刑警寧澤务热,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布忆嗜,位于F島的核電站,受9級特大地震影響崎岂,放射性物質(zhì)發(fā)生泄漏捆毫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一冲甘、第九天 我趴在偏房一處隱蔽的房頂上張望绩卤。 院中可真熱鬧,春花似錦损合、人聲如沸省艳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赖晶,卻和暖如春律适,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背遏插。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工捂贿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胳嘲。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓厂僧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親了牛。 傳聞我的和親對象是個(gè)殘疾皇子颜屠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容