📄 ldtmanag.c
字号:
/* FD32 LDT Management Services * by Salvo Isaja & Luca Abeni * * This file contains parts based on CWSDPMI * Copyright (C) 1995,1996 CW Sandmann (sandmann@clio.rice.edu) * 1206 Braelinn, Sugarland, TX 77479 * Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954 */ #include<ll/i386/hw-data.h>#include<ll/i386/hw-instr.h>#include<ll/i386/error.h>#include<ll/i386/cons.h>#include<logger.h>/* Descriptors Management Routines * * Implemented routines: * DPMI 0.9 service 0000h - Allocate LDT Descriptors * DPMI 0.9 service 0001h - Free LDT Descriptor * DPMI 0.9 service 0002h - Segment to Descriptor * DPMI 0.9 service 0003h - Get Selector Increment Value * DPMI 0.9 service 0006h - Get Segment Base Address * DPMI 0.9 service 0007h - Set Segment Base Address * DPMI 0.9 service 0008h - Set Segment Limit * DPMI 0.9 service 0009h - Set Descriptor Access Rights * DPMI 0.9 service 000Ah - Create Alias Descriptor * DPMI 0.9 service 000Bh - Get Descriptor * DPMI 0.9 service 000Ch - Set Descriptor * DPMI 1.0 service 000Eh - Get Multiple Descriptors * DPMI 1.0 service 000Fh - Set Multiple Descriptors * * Not yet implemented routines: * DPMI 0.9 service 000Dh - Allocate Specific LDT Descriptor * * FIX ME: GDT is currently used instead of the LDT * * NOTE: The 000Dh function, "Allocate Specific LDT Descriptor", receive * a specific selector from applications. It is supposed to be a * selector of the first 10h (16) descriptors in the LDT, so this * function should not work with the current GDT use. */#include<ll/i386/hw-func.h>#include "ldtmanag.h"#define RUN_RING 0 /* Not too sure */#define USE_GDT /* We use the GDT instead of the LDT */#ifdef USE_GDT extern union gdt_entry *GDT_base; #define DESCRIPTOR_TABLE(i) GDT_base[i].d #define DESCRIPTOR_TABLE_INF 12 #define DESCRIPTOR_TABLE_SUP 256 #define INDEX_TO_SELECTOR(x) (((x)*8) | RUN_RING)#else /* FIX ME: This is not defined at all! */ #define DESCRIPTOR_TABLE(i) LDT_base[i].d #define DESCRIPTOR_TABLE_INF 16 #define DESCRIPTOR_TABLE_SUP 128 #define INDEX_TO_SELECTOR(x) (((x)*8) | 4 | RUN_RING)#endif/* fd32_allocate_descriptors - Implementation of DPMI 0.9 service 0000h * "Allocate LDT Descriptors" * * FIX ME: Although the service is "Allocate LDT Descriptors", this * routine actually allocates descriptors into the GDT. * * This code is based on CWSDPMI 5.0, file exphdlr.c * by Salvo Isaja */int fd32_allocate_descriptors(WORD NumSelectors){ WORD i, j; WORD selector;#ifdef __DEBUG__ fd32_log_printf("[DPMI] Allocate Descriptors: 0x%x selector(s)\n", NumSelectors);#endif for (i = DESCRIPTOR_TABLE_INF; (i + NumSelectors) < DESCRIPTOR_TABLE_SUP; i++) { for (j = 0; (j < NumSelectors) && (!DESCRIPTOR_TABLE(i + j).access); j++); if (j >= NumSelectors) break; } if ((i + NumSelectors) < DESCRIPTOR_TABLE_SUP) { for(j = 0; j < NumSelectors; j++, i++) { /* * Allocates a descriptor with 0 base and limit * Access: Present, data, r/w * Granularity: 32-bit, byte granularity, used */#ifdef USE_GDT gdt_place(INDEX_TO_SELECTOR(i), 0, 0, 0x92 | (RUN_RING << 5), 0x40);#else /* FIX ME: This is not defined at all! */ LDT_place(INDEX_TO_SELECTOR(i), 0, 0, 0x92 | (RUN_RING << 5), 0x40);#endif } /* Return the first selector allocated */ selector = INDEX_TO_SELECTOR(i - NumSelectors); return selector; } return ERROR_DESCRIPTOR_UNAVAILABLE;}/* Convert a selector into a descriptor table index, * checking if the selector is valid, and returning * ERROR_INVALID_SELECTOR on failure. * * This code is based on CWSDPMI 5.0, file exphdlr.c * by Salvo Isaja */static int sel_to_ldt_index(WORD Selector, WORD *Index){#ifdef USE_GDT if (!(Selector & 0x4))#else if (Selector & 0x4)#endif { Selector /= 8; if ((Selector < DESCRIPTOR_TABLE_SUP ) && (DESCRIPTOR_TABLE(Selector).access)) { *Index = Selector; return NO_ERROR; } } return ERROR_INVALID_SELECTOR;}/* fd32_free_descriptor - Implementation of DPMI 0.9 service 0001h * "Free LDT Descriptor" * * FIX ME: Although the service is "Free LDT Descriptor", this * routine actually frees a descriptor into the GDT. * * FIX ME: The DPMI Specifications say also that: * Under DPMI 1.0 hosts, any segment registers which contain the * selector being freed are zeroed by this function. * * This code is based on CWSDPMI 5.0, file exphdlr.c * by Salvo Isaja */int fd32_free_descriptor(WORD Selector){ WORD i; int ErrorCode;#ifdef __DEBUG__ fd32_log_printf("[DPMI] Free Descriptor: Selector 0x%x\n", Selector);#endif ErrorCode = sel_to_ldt_index(Selector, &i); if (ErrorCode < 0) return ErrorCode; DESCRIPTOR_TABLE(i).access = 0; /* FIX ME: CWSDPMI provides the following code to clear all registers * containing the freed selector. * We need something different to do that. *//* DPMI 1.0 free descriptor clears any sregs containing value. Don't bother with CS, SS since illegal and will be caught in task switch *//* word16 tval = LDT_SEL(i); if(tss_ptr->tss_ds == tval) tss_ptr->tss_ds = 0; if(tss_ptr->tss_es == tval) tss_ptr->tss_es = 0; if(tss_ptr->tss_fs == tval) tss_ptr->tss_fs = 0; if(tss_ptr->tss_gs == tval) tss_ptr->tss_gs = 0;*/ return NO_ERROR;}/* fd32_segment_to_descriptor - Implementation of DPMI 0.9 service 0002h * "Segment to Descriptor" * * NOTE: The DPMI Specifications say that: * "Descriptors created by this function can never be modified or freed. * For this reason, the function should be used sparingly. Clients * which need to examine various real mode addresses using the same * selector should allocate a descriptor with Int 31H Function 0000H * and change the base address in the descriptor as necessary, using * the Set Segment Base Address function (Int 31H Function 0007H" * But I don't see such limitations in our current code. * * This code is based on CWSDPMI 5.0, file exphdlr.c * by Salvo Isaja */int fd32_segment_to_descriptor(WORD RealModeSegment){ WORD i, selector; int ErrorCode; WORD base_lo = RealModeSegment << 4; WORD base_med = RealModeSegment >> 12;#ifdef __DEBUG__ fd32_log_printf("[DPMI] Segment to Descriptor: RealModeSegment 0x%x\n", RealModeSegment);#endif /* The DPMI Specifications says that: * Multiple calls to this function with the same segment address * will return the same selector. So we search for same descriptor. */ for(i = DESCRIPTOR_TABLE_INF; i < DESCRIPTOR_TABLE_SUP; i++) { if ((!DESCRIPTOR_TABLE(i).gran ) && (!DESCRIPTOR_TABLE(i).base_hi ) && ( DESCRIPTOR_TABLE(i).lim_lo == 0xFFFF ) && ( DESCRIPTOR_TABLE(i).access ) && ( DESCRIPTOR_TABLE(i).base_lo == base_lo ) && ( DESCRIPTOR_TABLE(i).base_med == base_med)) { selector = INDEX_TO_SELECTOR(i); return selector; } } /* A selector for that real mode segment is not allocated. * Allocate one now. */ ErrorCode = fd32_allocate_descriptors(1); if (ErrorCode < 0) return ErrorCode; i = ErrorCode; /* Return the selector just allocated */ selector = i; /* Then convert that selector into a descriptor table index to * initialize our descriptor. * We can safely ignore the exit code of the following */ sel_to_ldt_index(i,&i); DESCRIPTOR_TABLE(i).lim_lo = 0xFFFF; DESCRIPTOR_TABLE(i).base_lo = base_lo; DESCRIPTOR_TABLE(i).base_med = base_med; DESCRIPTOR_TABLE(i).gran = 0; /* 16-bit, not 32 */ return selector;}/* fd32_get_selector_increment_value - Implementation of DPMI 0.9 service 0003h * "Get Selector Increment Value" * * NOTE: This function always succeeds * * This code is based on CWSDPMI 5.0, file exphdlr.c * by Salvo Isaja */WORD fd32_get_selector_increment_value(){ /* CWSDPMI implements it simply by returning 8. Is it really so stupid!?!? * The DPMI Specifications say that: * "The increment value is always a power of two" */#ifdef __DEBUG__ fd32_log_printf("[DPMI] Get Selector Increment Value Rights\n");#endif return 8;}/* fd32_get_segment_base_address - Implementation of DPMI 0.9 service 0006h * "Get Segment Base Address" * * This code is based on CWSDPMI 5.0, file exphdlr.c * by Salvo Isaja */int fd32_get_segment_base_address(WORD Selector, DWORD *BaseAddress){ WORD i; int ErrorCode;#ifdef __DEBUG__ fd32_log_printf("[DPMI] Get Segment Base Address: Selector 0x%x\n", Selector);#endif ErrorCode = sel_to_ldt_index(Selector, &i); if (ErrorCode < 0) { return ErrorCode; } *BaseAddress = DESCRIPTOR_TABLE(i).base_lo + (DESCRIPTOR_TABLE(i).base_med << 16) + (DESCRIPTOR_TABLE(i).base_hi << 24); return NO_ERROR;}/* fd32_set_segment_base_address - Implementation of DPMI 0.9 service 0007h * "Set Segment Base Address" * * This code is based on CWSDPMI 5.0, file exphdlr.c * by Salvo Isaja * * FIX ME: DPMI Specifications indicate the following error codes to return * that are currently not considered (by CWSDPMI too, however): * * 8025h invalid linear address (changing the base would cause the * descriptor to reference a linear address range outside * that allowed for DPMI clients) * * FIX ME: The DPMI Specifications say also that: * A DPMI 1.0 host will reload any segment registers which contain * the selector specified in register BX. It is suggested that * DPMI 0.9 hosts also implement this. */int fd32_set_segment_base_address(WORD Selector, DWORD BaseAddress){ WORD i; int ErrorCode;#ifdef __DEBUG__ fd32_log_printf("[DPMI] Set Segment Base Address: Selector 0x%x Base Address 0x%lx\n",Selector,BaseAddress);#endif ErrorCode = sel_to_ldt_index(Selector,&i); if (ErrorCode < 0) { return ErrorCode; } DESCRIPTOR_TABLE(i).base_lo = (WORD) BaseAddress; DESCRIPTOR_TABLE(i).base_med = (BYTE) (BaseAddress>>16); DESCRIPTOR_TABLE(i).base_hi = (BYTE) (BaseAddress>>24); return NO_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -