From 9bfc57c3684f7aebba0f6865a1ea248f576b947f Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Sun, 8 Nov 2026 07:46:07 +0800 Subject: [mubios] Add switching and return paths between real-mode interrupts and protected-mode C services. Signed-off-by: Richard Qin --- mubios/arch/interrupt.S | 346 +++++++++------------------------------------- mubios/arch/mode_switch.S | 103 ++++++++++++++ 2 files changed, 166 insertions(+), 283 deletions(-) (limited to 'mubios/arch') diff --git a/mubios/arch/interrupt.S b/mubios/arch/interrupt.S index 88ccfbf..0822b1a 100644 --- a/mubios/arch/interrupt.S +++ b/mubios/arch/interrupt.S @@ -6,31 +6,21 @@ # # RCC-Project is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. # -# RCC-Project is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# RCC-Project; see the file COPYING. If not see -# . +# RCC-Project is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. .intel_syntax noprefix .code16 - .equ ATA_DATA, 0x1F0 - .equ ATA_SECTOR_COUNT, 0x1F2 - .equ ATA_LBA_LOW, 0x1F3 - .equ ATA_LBA_MID, 0x1F4 - .equ ATA_LBA_HIGH, 0x1F5 - .equ ATA_DRIVE, 0x1F6 - .equ ATA_STATUS, 0x1F7 - .equ ATA_COMMAND, 0x1F7 - .section .text16.irq, "ax" + .extern enter_protected_service + .global int1a_entry .type int1a_entry, @function @@ -58,268 +48,58 @@ int1a_entry: int1a_return: iret - .global int10_entry - .type int10_entry, @function - -int10_entry: - cmp ah, 0x0E - jne int10_return - - push bp - mov bp, sp - - push ax - push bx - push dx - push si - push di - push ds - push es - - xor ax, ax - mov ds, ax - - mov ax, 0xB800 - mov es, ax - - mov si, 0x0050 - mov dx, word ptr [si] - - mov al, byte ptr [bp - 2] - mov bl, byte ptr [bp - 4] - - cmp al, 0x0D - je int10_carriage_return - - cmp al, 0x0A - je int10_line_feed - - cmp al, 0x08 - je int10_backspace - - mov di, dx - shl di, 1 - mov ah, bl - mov word ptr es:[di], ax - inc dx - jmp int10_store_cursor - - -int10_carriage_return: - mov ax, dx - mov si, 80 - xor dx, dx - div si - mul si - mov dx, ax - jmp int10_store_cursor - -int10_line_feed: - add dx, 80 - jmp int10_store_cursor - -int10_backspace: - cmp dx, 0 - je int10_store_cursor - - dec dx - mov di, dx - shl di, 1 - mov al, 0x20 - mov ah, bl - mov word ptr es:[di], ax - -int10_store_cursor: - cmp dx, 2000 - jb int10_save_cursor - - xor dx, dx - -int10_save_cursor: - mov word ptr [0x0050], dx - - pop es - pop ds - pop di - pop si - pop dx - pop bx - pop ax - pop bp - -int10_return: - iret - - .global int13_entry - .type int13_entry, @function - -int13_entry: - cmp ah, 0x42 - je int13_extended_read - - cmp ah, 0x41 - jne int13_return - - push bp - mov bp, sp - - cmp bx, 0x55AA - jne int13_fail - - mov bx, 0xAA55 - mov cx, 0x0001 - mov ax, 0x3000 - - # Clear CF in the FLAGS saved by INT. - and word ptr [bp + 6], 0xFFFE - - pop bp - iret - -int13_fail: - mov ah, 0x01 - - # Set CF in the FLAGS saved by INT. - or word ptr [bp + 6], 0x0001 - - pop bp - iret - -int13_return: - push bp - mov bp, sp - - mov ah, 0x01 - - # Set CF in the FLAGS saved by INT. - or word ptr [bp + 6], 0x0001 - - pop bp - iret -int13_extended_read: - push bp - mov bp, sp - - push bx - push cx - push dx - push si - push di - push ds - push es - - # DAP size must be 0x10. - cmp byte ptr [si], 0x10 - jne int13_extended_fail - - # This step supports exactly one sector. - cmp word ptr [si + 2], 1 - jne int13_extended_fail - - # Reject LBA values above 28 bits. - mov ax, word ptr [si + 12] - or ax, word ptr [si + 14] - jnz int13_extended_fail - - mov ax, word ptr [si + 10] - test ax, 0xF000 - jnz int13_extended_fail - - # Load DAP buffer ES:DI. - mov di, word ptr [si + 4] - mov ax, word ptr [si + 6] - mov es, ax - - cld - - # Select ATA drive from DL. - mov al, 0xE0 - test dl, 1 - jz int13_drive_selected - - or al, 0x10 - -int13_drive_selected: - mov dx, ATA_DRIVE - out dx, al - - # 400 ns delay. - mov dx, ATA_STATUS - in al, dx - in al, dx - in al, dx - in al, dx - - # Sector count = 1. - mov dx, ATA_SECTOR_COUNT - mov al, 1 - out dx, al - - # LBA byte 0. - mov ax, word ptr [si + 8] - mov dx, ATA_LBA_LOW - out dx, al - - # LBA byte 1. - mov al, ah - mov dx, ATA_LBA_MID - out dx, al - - # LBA byte 2. - mov ax, word ptr [si + 10] - mov dx, ATA_LBA_HIGH - out dx, al - - # READ SECTORS command. - mov dx, ATA_COMMAND - mov al, 0x20 - out dx, al - -int13_wait_data: - mov dx, ATA_STATUS - in al, dx - - test al, 0x80 - jnz int13_wait_data - - test al, 0x01 - jnz int13_extended_fail - - test al, 0x08 - jz int13_wait_data - - # Read one 512-byte sector. - mov dx, ATA_DATA - mov cx, 256 - rep insw - - # Clear CF in the saved FLAGS. - and word ptr [bp + 6], 0xFFFE - - pop es - pop ds - pop di - pop si - pop dx - pop cx - pop bx - pop bp - - xor ax, ax - iret - -int13_extended_fail: - # Set CF in the saved FLAGS. - or word ptr [bp + 6], 0x0001 - - pop es - pop ds - pop di - pop si - pop dx - pop cx - pop bx - pop bp - - mov ax, 0x0100 - iret + .macro BIOS_SERVICE_ENTRY name, vector + .global \name + .type \name, @function + +\name: + # Build struct bios_regs on the interrupted real-mode stack. + push 0 + push es + push ds + push bp + push di + push si + push dx + push cx + push bx + push ax + + mov bp, sp + mov ax, word ptr [bp + 24] + mov word ptr [bp + 18], ax + + # ESI = linear address of struct bios_regs. + movzx esi, sp + xor eax, eax + mov ax, ss + shl eax, 4 + add esi, eax + + # EBP = original SS:SP return point, packed as SS:SP. + movzx ebp, sp + sub ebp, 2 + xor eax, eax + mov ax, ss + shl eax, 16 + or ebp, eax + + mov edi, \vector + call enter_protected_service + + # Restore the context modified by the C service. + pop ax + pop bx + pop cx + pop dx + pop si + pop di + pop bp + pop ds + pop es + add sp, 2 + iret + .endm + + BIOS_SERVICE_ENTRY int10_entry, 0x10 + BIOS_SERVICE_ENTRY int13_entry, 0x13 diff --git a/mubios/arch/mode_switch.S b/mubios/arch/mode_switch.S index 9b2643a..9dc0ab5 100644 --- a/mubios/arch/mode_switch.S +++ b/mubios/arch/mode_switch.S @@ -23,6 +23,7 @@ .section .text16.mode, "ax" .extern post_main + .extern bios_service_dispatch .global enter_protected_mode .type enter_protected_mode, @function @@ -59,6 +60,35 @@ enter_protected_mode: .long protected_mode_entry .word 0x0008 + .global enter_protected_service + .type enter_protected_service, @function + +enter_protected_service: + cli + + in al, 0x92 + or al, 0x02 + and al, 0xFE + out 0x92, al + + push cs + pop ds + + call 2f +2: + pop bx + add bx, gdt_descriptor - 2b + lgdt [bx] + + mov eax, cr0 + or eax, 0x00000001 + mov cr0, eax + + .byte 0x66 + .byte 0xEA + .long protected_service_entry + .word 0x0008 + .align 8 gdt_start: @@ -119,6 +149,30 @@ protected_mode_halt: hlt jmp protected_mode_halt + .global protected_service_entry + .type protected_service_entry, @function + +protected_service_entry: + mov ax, 0x0010 + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + mov esp, 0x00007000 + + push esi + push edi + call bios_service_dispatch + add esp, 8 + + call leave_service_protected + +protected_service_halt: + hlt + jmp protected_service_halt + .global leave_protected_mode .type leave_protected_mode, @function @@ -152,6 +206,30 @@ leave_protected_mode: .byte 0x66 .byte 0xFF, 0x2C, 0x24 + .global leave_service_protected + .type leave_service_protected, @function + +leave_service_protected: + sub esp, 16 + + mov eax, OFFSET FLAT:protected16_service_return + mov ebx, OFFSET FLAT:__rom_start + sub eax, ebx + mov word ptr [esp], ax + mov word ptr [esp + 2], 0x0018 + + mov eax, OFFSET FLAT:real_mode_service_return + mov ebx, OFFSET FLAT:__rom_start + sub eax, ebx + mov word ptr [esp + 4], ax + + shr ebx, 4 + mov word ptr [esp + 6], bx + mov dword ptr [esp + 8], ebp + + .byte 0x66 + .byte 0xFF, 0x2C, 0x24 + .code16 .section .text16.mode, "ax" @@ -171,6 +249,19 @@ protected16_return: # Jump to the prepared real-mode CS:IP pointer. .byte 0xFF, 0x2F + .global protected16_service_return + .type protected16_service_return, @function + +protected16_service_return: + mov bx, sp + add bx, 4 + + mov eax, cr0 + and eax, 0xFFFFFFFE + mov cr0, eax + + .byte 0xFF, 0x2F + .global real_mode_return .type real_mode_return, @function @@ -184,5 +275,17 @@ real_mode_return: mov sp, 0x7FFE ret + + .global real_mode_service_return + .type real_mode_service_return, @function + +real_mode_service_return: + mov bx, sp + mov si, word ptr [bx + 8] + mov di, word ptr [bx + 10] + + mov ss, di + mov sp, si + ret -- cgit v1.2.3