/kernel/branches/kolibri-process/blkdev/disk.inc |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 4273 $ |
$Revision: 4437 $ |
; ============================================================================= |
; ================================= Constants ================================= |
/kernel/branches/kolibri-process/blkdev/disk_cache.inc |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 4133 $ |
$Revision: 4465 $ |
; Read/write functions try to do large operations, |
; it is significantly faster than several small operations. |
/kernel/branches/kolibri-process/blkdev/flp_drv.inc |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 4273 $ |
$Revision: 4695 $ |
;********************************************************** |
/kernel/branches/kolibri-process/blkdev/hd_drv.inc |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 4420 $ |
$Revision: 4839 $ |
; Low-level driver for HDD access |
/kernel/branches/kolibri-process/blkdev/ide_cache.inc |
---|
21,7 → 21,7 |
; |
;************************************************************************** |
$Revision: 3742 $ |
$Revision: 4700 $ |
align 4 |
find_empty_slot_CD_cache: |
/kernel/branches/kolibri-process/core/exports.inc |
---|
94,6 → 94,7 |
load_cursor, 'LoadCursor', \ ;stdcall |
\ |
get_curr_task, 'GetCurrentTask', \ |
change_task, 'ChangeTask', \ |
load_file, 'LoadFile', \ ;retval eax, ebx |
delay_ms, 'Sleep', \ |
\ |
/kernel/branches/kolibri-process/core/mtrr.inc |
---|
0,0 → 1,881 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 4619 $ |
; Initializes MTRRs. |
proc init_mtrr |
cmp [BOOT_VARS+BOOT_MTRR], byte 2 |
je .exit |
bt [cpu_caps], CAPS_MTRR |
jnc .exit |
call mtrr_reconfigure |
stdcall set_mtrr, [LFBAddress], 0x1000000, MEM_WC |
.exit: |
ret |
endp |
; Helper procedure for mtrr_reconfigure and set_mtrr, |
; called before changes in MTRRs. |
proc mtrr_begin_change |
mov eax, cr0 |
or eax, 0x60000000 ;disable caching |
mov cr0, eax |
wbinvd ;invalidate cache |
ret |
endp |
; Helper procedure for mtrr_reconfigure and set_mtrr, |
; called after changes in MTRRs. |
proc mtrr_end_change |
wbinvd ;again invalidate |
mov eax, cr0 |
and eax, not 0x60000000 |
mov cr0, eax ; enable caching |
ret |
endp |
; Some limits to number of structures located in the stack. |
MAX_USEFUL_MTRRS = 16 |
MAX_RANGES = 16 |
; mtrr_reconfigure keeps a list of MEM_WB ranges. |
; This structure describes one item in the list. |
struct mtrr_range |
next dd ? ; next item |
start dq ? ; first byte |
length dq ? ; length in bytes |
ends |
uglobal |
align 4 |
num_variable_mtrrs dd 0 ; number of variable-range MTRRs |
endg |
; Helper procedure for MTRR initialization. |
; Takes MTRR configured by BIOS and tries to recongifure them |
; in order to allow non-UC data at top of 4G memory. |
; Example: if low part of physical memory is 3.5G = 0xE0000000 bytes wide, |
; BIOS can configure two MTRRs so that the first MTRR describes [0, 4G) as WB |
; and the second MTRR describes [3.5G, 4G) as UC; |
; WB+UC=UC, so the resulting memory map would be as needed, |
; but in this configuration our attempts to map LFB at (say) 0xE8000000 as WC |
; would be ignored, WB+UC+WC is still UC. |
; So we must keep top of 4G memory not covered by MTRRs, |
; using three WB MTRRs [0,2G) + [2G,3G) + [3G,3.5G), |
; this gives the same memory map, but allows to add further entries. |
; See mtrrtest.asm for detailed input/output from real hardware+BIOS. |
proc mtrr_reconfigure |
push ebp ; we're called from init_LFB, and it feels hurt when ebp is destroyed |
; 1. Prepare local variables. |
; 1a. Create list of MAX_RANGES free (aka not yet allocated) ranges. |
xor eax, eax |
lea ecx, [eax+MAX_RANGES] |
.init_ranges: |
sub esp, sizeof.mtrr_range - 4 |
push eax |
mov eax, esp |
dec ecx |
jnz .init_ranges |
mov eax, esp |
; 1b. Fill individual local variables. |
xor edx, edx |
sub esp, MAX_USEFUL_MTRRS * 16 ; .mtrrs |
push edx ; .mtrrs_end |
push edx ; .num_used_mtrrs |
push eax ; .first_free_range |
push edx ; .first_range: no ranges yet |
mov cl, [cpu_phys_addr_width] |
or eax, -1 |
shl eax, cl ; note: this uses cl&31 = cl-32, not the entire cl |
push eax ; .phys_reserved_mask |
virtual at esp |
.phys_reserved_mask dd ? |
.first_range dd ? |
.first_free_range dd ? |
.num_used_mtrrs dd ? |
.mtrrs_end dd ? |
.mtrrs rq MAX_USEFUL_MTRRS * 2 |
.local_vars_size = $ - esp |
end virtual |
; 2. Get the number of variable-range MTRRs from MTRRCAP register. |
; Abort if zero. |
mov ecx, 0xFE |
rdmsr |
test al, al |
jz .abort |
mov byte [num_variable_mtrrs], al |
; 3. Validate MTRR_DEF_TYPE register. |
mov ecx, 0x2FF |
rdmsr |
; If BIOS has not initialized variable-range MTRRs, fallback to step 7. |
test ah, 8 |
jz .fill_ranges_from_memory_map |
; If the default memory type (not covered by MTRRs) is not UC, |
; then probably BIOS did something strange, so it is better to exit immediately |
; hoping for the best. |
cmp al, MEM_UC |
jnz .abort |
; 4. Validate all variable-range MTRRs |
; and copy configured MTRRs to the local array [.mtrrs]. |
; 4a. Prepare for the loop over existing variable-range MTRRs. |
mov ecx, 0x200 |
lea edi, [.mtrrs] |
.get_used_mtrrs_loop: |
; 4b. For every MTRR, read PHYSBASEn and PHYSMASKn. |
; In PHYSBASEn, clear upper bits and copy to ebp:ebx. |
rdmsr |
or edx, [.phys_reserved_mask] |
xor edx, [.phys_reserved_mask] |
mov ebp, edx |
mov ebx, eax |
inc ecx |
; If PHYSMASKn is not active, ignore this MTRR. |
rdmsr |
inc ecx |
test ah, 8 |
jz .get_used_mtrrs_next |
; 4c. For every active MTRR, check that number of local entries is not too large. |
inc [.num_used_mtrrs] |
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS |
ja .abort |
; 4d. For every active MTRR, store PHYSBASEn with upper bits cleared. |
; This contains the MTRR base and the memory type in low byte. |
mov [edi], ebx |
mov [edi+4], ebp |
; 4e. For every active MTRR, check that the range is continuous: |
; PHYSMASKn with upper bits set must be negated power of two, and |
; low bits of PHYSBASEn must be zeroes: |
; PHYSMASKn = 1...10...0, |
; PHYSBASEn = x...x0...0, |
; this defines a continuous range from x...x0...0 to x...x1...1, |
; length = 10...0 = negated PHYSMASKn. |
; Store length in the local array. |
and eax, not 0xFFF |
or edx, [.phys_reserved_mask] |
mov dword [edi+8], 0 |
mov dword [edi+12], 0 |
sub [edi+8], eax |
sbb [edi+12], edx |
; (x and -x) is the maximum power of two that divides x. |
; Condition for powers of two: (x and -x) equals x. |
and eax, [edi+8] |
and edx, [edi+12] |
cmp eax, [edi+8] |
jnz .abort |
cmp edx, [edi+12] |
jnz .abort |
sub eax, 1 |
sbb edx, 0 |
and eax, not 0xFFF |
and eax, ebx |
jnz .abort |
and edx, ebp |
jnz .abort |
; 4f. For every active MTRR, validate memory type: it must be either WB or UC. |
add edi, 16 |
cmp bl, MEM_UC |
jz .get_used_mtrrs_next |
cmp bl, MEM_WB |
jnz .abort |
.get_used_mtrrs_next: |
; 4g. Repeat the loop at 4b-4f for all [num_variable_mtrrs] entries. |
mov eax, [num_variable_mtrrs] |
lea eax, [0x200+eax*2] |
cmp ecx, eax |
jb .get_used_mtrrs_loop |
; 4h. If no active MTRRs were detected, fallback to step 7. |
cmp [.num_used_mtrrs], 0 |
jz .fill_ranges_from_memory_map |
mov [.mtrrs_end], edi |
; 5. Generate sorted list of ranges marked as WB. |
; 5a. Prepare for the loop over configured MTRRs filled at step 4. |
lea ecx, [.mtrrs] |
.fill_wb_ranges: |
; 5b. Ignore non-WB MTRRs. |
mov ebx, [ecx] |
cmp bl, MEM_WB |
jnz .next_wb_range |
mov ebp, [ecx+4] |
and ebx, not 0xFFF ; clear memory type and reserved bits |
; ebp:ebx = start of the range described by the current MTRR. |
; 5c. Find the first existing range containing a point greater than ebp:ebx. |
lea esi, [.first_range] |
.find_range_wb: |
; If there is no next range or start of the next range is greater than ebp:ebx, |
; exit the loop to 5d. |
mov edi, [esi] |
test edi, edi |
jz .found_place_wb |
mov eax, ebx |
mov edx, ebp |
sub eax, dword [edi+mtrr_range.start] |
sbb edx, dword [edi+mtrr_range.start+4] |
jb .found_place_wb |
; Otherwise, if end of the next range is greater than or equal to ebp:ebx, |
; exit the loop to 5e. |
mov esi, edi |
sub eax, dword [edi+mtrr_range.length] |
sbb edx, dword [edi+mtrr_range.length+4] |
jb .expand_wb |
or eax, edx |
jnz .find_range_wb |
jmp .expand_wb |
.found_place_wb: |
; 5d. ebp:ebx is not within any existing range. |
; Insert a new range between esi and edi. |
; (Later, during 5e, it can be merged with the following ranges.) |
mov eax, [.first_free_range] |
test eax, eax |
jz .abort |
mov [esi], eax |
mov edx, [eax+mtrr_range.next] |
mov [.first_free_range], edx |
mov dword [eax+mtrr_range.start], ebx |
mov dword [eax+mtrr_range.start+4], ebp |
; Don't fill [eax+mtrr_range.next] and [eax+mtrr_range.length] yet, |
; they will be calculated including merges at step 5e. |
mov esi, edi |
mov edi, eax |
.expand_wb: |
; 5e. The range at edi contains ebp:ebx, and esi points to the first range |
; to be checked for merge: esi=edi if ebp:ebx was found in an existing range, |
; esi is next after edi if a new range with ebp:ebx was created. |
; Merge it with following ranges while start of the next range is not greater |
; than the end of the new range. |
add ebx, [ecx+8] |
adc ebp, [ecx+12] |
; ebp:ebx = end of the range described by the current MTRR. |
.expand_wb_loop: |
; If there is no next range or start of the next range is greater than ebp:ebx, |
; exit the loop to 5g. |
test esi, esi |
jz .expand_wb_done |
mov eax, ebx |
mov edx, ebp |
sub eax, dword [esi+mtrr_range.start] |
sbb edx, dword [esi+mtrr_range.start+4] |
jb .expand_wb_done |
; Otherwise, if end of the next range is greater than or equal to ebp:ebx, |
; exit the loop to 5f. |
sub eax, dword [esi+mtrr_range.length] |
sbb edx, dword [esi+mtrr_range.length+4] |
jb .expand_wb_last |
; Otherwise, the current range is completely within the new range. |
; Free it and continue the loop. |
mov edx, [esi+mtrr_range.next] |
cmp esi, edi |
jz @f |
mov eax, [.first_free_range] |
mov [esi+mtrr_range.next], eax |
mov [.first_free_range], esi |
@@: |
mov esi, edx |
jmp .expand_wb_loop |
.expand_wb_last: |
; 5f. Start of the new range is inside range described by esi, |
; end of the new range is inside range described by edi. |
; If esi is equal to edi, the new range is completely within |
; an existing range, so proceed to the next range. |
cmp esi, edi |
jz .next_wb_range |
; Otherwise, set end of interval at esi to end of interval at edi |
; and free range described by edi. |
mov ebx, dword [esi+mtrr_range.start] |
mov ebp, dword [esi+mtrr_range.start+4] |
add ebx, dword [esi+mtrr_range.length] |
adc ebp, dword [esi+mtrr_range.length+4] |
mov edx, [esi+mtrr_range.next] |
mov eax, [.first_free_range] |
mov [esi+mtrr_range.next], eax |
mov [.first_free_range], esi |
mov esi, edx |
.expand_wb_done: |
; 5g. We have found the next range (maybe 0) after merging and |
; the new end of range (maybe ebp:ebx from the new range |
; or end of another existing interval calculated at step 5f). |
; Write them to range at edi. |
mov [edi+mtrr_range.next], esi |
sub ebx, dword [edi+mtrr_range.start] |
sbb ebp, dword [edi+mtrr_range.start+4] |
mov dword [edi+mtrr_range.length], ebx |
mov dword [edi+mtrr_range.length+4], ebp |
.next_wb_range: |
; 5h. Continue the loop 5b-5g over all configured MTRRs. |
add ecx, 16 |
cmp ecx, [.mtrrs_end] |
jb .fill_wb_ranges |
; 6. Exclude all ranges marked as UC. |
; 6a. Prepare for the loop over configured MTRRs filled at step 4. |
lea ecx, [.mtrrs] |
.fill_uc_ranges: |
; 6b. Ignore non-UC MTRRs. |
mov ebx, [ecx] |
cmp bl, MEM_UC |
jnz .next_uc_range |
mov ebp, [ecx+4] |
and ebx, not 0xFFF ; clear memory type and reserved bits |
; ebp:ebx = start of the range described by the current MTRR. |
lea esi, [.first_range] |
; 6c. Find the first existing range containing a point greater than ebp:ebx. |
.find_range_uc: |
; If there is no next range, ignore this MTRR, |
; exit the loop and continue to next MTRR. |
mov edi, [esi] |
test edi, edi |
jz .next_uc_range |
; If start of the next range is greater than or equal to ebp:ebx, |
; exit the loop to 6e. |
mov eax, dword [edi+mtrr_range.start] |
mov edx, dword [edi+mtrr_range.start+4] |
sub eax, ebx |
sbb edx, ebp |
jnb .truncate_uc |
; Otherwise, continue the loop if end of the next range is less than ebp:ebx, |
; exit the loop to 6d otherwise. |
mov esi, edi |
add eax, dword [edi+mtrr_range.length] |
adc edx, dword [edi+mtrr_range.length+4] |
jnb .find_range_uc |
; 6d. ebp:ebx is inside (or at end of) an existing range. |
; Split the range. (The second range, maybe containing completely within UC-range, |
; maybe of zero length, can be removed at step 6e, if needed.) |
mov edi, [.first_free_range] |
test edi, edi |
jz .abort |
mov dword [edi+mtrr_range.start], ebx |
mov dword [edi+mtrr_range.start+4], ebp |
mov dword [edi+mtrr_range.length], eax |
mov dword [edi+mtrr_range.length+4], edx |
mov eax, [edi+mtrr_range.next] |
mov [.first_free_range], eax |
mov eax, [esi+mtrr_range.next] |
mov [edi+mtrr_range.next], eax |
; don't change [esi+mtrr_range.next] yet, it will be filled at step 6e |
mov eax, ebx |
mov edx, ebp |
sub eax, dword [esi+mtrr_range.start] |
sbb edx, dword [esi+mtrr_range.start+4] |
mov dword [esi+mtrr_range.length], eax |
mov dword [esi+mtrr_range.length+4], edx |
.truncate_uc: |
; 6e. edi is the first range after ebp:ebx, check it and next ranges |
; for intersection with the new range, truncate heads. |
add ebx, [ecx+8] |
adc ebp, [ecx+12] |
; ebp:ebx = end of the range described by the current MTRR. |
.truncate_uc_loop: |
; If start of the next range is greater than ebp:ebx, |
; exit the loop to 6g. |
mov eax, ebx |
mov edx, ebp |
sub eax, dword [edi+mtrr_range.start] |
sbb edx, dword [edi+mtrr_range.start+4] |
jb .truncate_uc_done |
; Otherwise, if end of the next range is greater than ebp:ebx, |
; exit the loop to 6f. |
sub eax, dword [edi+mtrr_range.length] |
sbb edx, dword [edi+mtrr_range.length+4] |
jb .truncate_uc_last |
; Otherwise, the current range is completely within the new range. |
; Free it and continue the loop if there is a next range. |
; If that was a last range, exit the loop to 6g. |
mov edx, [edi+mtrr_range.next] |
mov eax, [.first_free_range] |
mov [.first_free_range], edi |
mov [edi+mtrr_range.next], eax |
mov edi, edx |
test edi, edi |
jnz .truncate_uc_loop |
jmp .truncate_uc_done |
.truncate_uc_last: |
; 6f. The range at edi partially intersects with the UC-range described by MTRR. |
; Truncate it from the head. |
mov dword [edi+mtrr_range.start], ebx |
mov dword [edi+mtrr_range.start+4], ebp |
neg eax |
adc edx, 0 |
neg edx |
mov dword [edi+mtrr_range.length], eax |
mov dword [edi+mtrr_range.length+4], edx |
.truncate_uc_done: |
; 6g. We have found the next range (maybe 0) after intersection. |
; Write it to [esi+mtrr_range.next]. |
mov [esi+mtrr_range.next], edi |
.next_uc_range: |
; 6h. Continue the loop 6b-6g over all configured MTRRs. |
add ecx, 16 |
cmp ecx, [.mtrrs_end] |
jb .fill_uc_ranges |
; Sanity check: if there are no ranges after steps 5-6, |
; fallback to step 7. Otherwise, go to 8. |
cmp [.first_range], 0 |
jnz .ranges_ok |
.fill_ranges_from_memory_map: |
; 7. BIOS has not configured variable-range MTRRs. |
; Create one range from 0 to [MEM_AMOUNT]. |
mov eax, [.first_free_range] |
mov edx, [eax+mtrr_range.next] |
mov [.first_free_range], edx |
mov [.first_range], eax |
xor edx, edx |
mov [eax+mtrr_range.next], edx |
mov dword [eax+mtrr_range.start], edx |
mov dword [eax+mtrr_range.start+4], edx |
mov ecx, [MEM_AMOUNT] |
mov dword [eax+mtrr_range.length], ecx |
mov dword [eax+mtrr_range.length+4], edx |
.ranges_ok: |
; 8. We have calculated list of WB-ranges. |
; Now we should calculate a list of MTRRs so that |
; * every MTRR describes a range with length = power of 2 and start that is aligned, |
; * every MTRR can be WB or UC |
; * (sum of all WB ranges) minus (sum of all UC ranges) equals the calculated list |
; * top of 4G memory must not be covered by any ranges |
; Example: range [0,0xBC000000) can be converted to |
; [0,0x80000000)+[0x80000000,0xC0000000)-[0xBC000000,0xC0000000) |
; WB +WB -UC |
; but not to [0,0x100000000)-[0xC0000000,0x100000000)-[0xBC000000,0xC0000000). |
; 8a. Check that list of ranges is [0,something) plus, optionally, [4G,something). |
; This holds in practice (see mtrrtest.asm for real-life examples) |
; and significantly simplifies the code: ranges are independent, start of range |
; is almost always aligned (the only exception >4G upper memory can be easily covered), |
; there is no need to consider adding holes before start of range, only |
; append them to end of range. |
xor eax, eax |
mov edi, [.first_range] |
cmp dword [edi+mtrr_range.start], eax |
jnz .abort |
cmp dword [edi+mtrr_range.start+4], eax |
jnz .abort |
cmp dword [edi+mtrr_range.length+4], eax |
jnz .abort |
mov edx, [edi+mtrr_range.next] |
test edx, edx |
jz @f |
cmp dword [edx+mtrr_range.start], eax |
jnz .abort |
cmp dword [edx+mtrr_range.start+4], 1 |
jnz .abort |
cmp [edx+mtrr_range.next], eax |
jnz .abort |
@@: |
; 8b. Initialize: no MTRRs filled. |
mov [.num_used_mtrrs], eax |
lea esi, [.mtrrs] |
.range2mtrr_loop: |
; 8c. If we are dealing with upper-memory range (after 4G) |
; with length > start, create one WB MTRR with [start,2*start), |
; reset start to 2*start and return to this step. |
; Example: [4G,24G) -> [4G,8G) {returning} + [8G,16G) {returning} |
; + [16G,24G) {advancing to ?}. |
mov eax, dword [edi+mtrr_range.length+4] |
test eax, eax |
jz .less4G |
mov edx, dword [edi+mtrr_range.start+4] |
cmp eax, edx |
jb .start_aligned |
inc [.num_used_mtrrs] |
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS |
ja .abort |
mov dword [esi], MEM_WB |
mov dword [esi+4], edx |
mov dword [esi+8], 0 |
mov dword [esi+12], edx |
add esi, 16 |
add dword [edi+mtrr_range.start+4], edx |
sub dword [edi+mtrr_range.length+4], edx |
jnz .range2mtrr_loop |
cmp dword [edi+mtrr_range.length], 0 |
jz .range2mtrr_next |
.less4G: |
; 8d. If we are dealing with low-memory range (before 4G) |
; and appending a maximal-size hole would create a range covering top of 4G, |
; create a maximal-size WB range and return to this step. |
; Example: for [0,0xBC000000) the following steps would consider |
; variants [0,0x80000000)+(another range to be splitted) and |
; [0,0x100000000)-(another range to be splitted); we forbid the last variant, |
; so the first variant must be used. |
bsr ecx, dword [edi+mtrr_range.length] |
xor edx, edx |
inc edx |
shl edx, cl |
lea eax, [edx*2] |
add eax, dword [edi+mtrr_range.start] |
jnz .start_aligned |
inc [.num_used_mtrrs] |
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS |
ja .abort |
mov eax, dword [edi+mtrr_range.start] |
mov dword [esi], eax |
or dword [esi], MEM_WB |
mov dword [esi+4], 0 |
mov dword [esi+8], edx |
mov dword [esi+12], 0 |
add esi, 16 |
add dword [edi+mtrr_range.start], edx |
sub dword [edi+mtrr_range.length], edx |
jnz .less4G |
jmp .range2mtrr_next |
.start_aligned: |
; Start is aligned for any allowed length, maximum-size hole is allowed. |
; Select the best MTRR configuration for one range. |
; length=...101101 |
; Without hole at the end, we need one WB MTRR for every 1-bit in length: |
; length=...100000 + ...001000 + ...000100 + ...000001 |
; We can also append one hole at the end so that one 0-bit (selected by us) |
; becomes 1 and all lower bits become 0 for WB-range: |
; length=...110000 - (...00010 + ...00001) |
; In this way, we need one WB MTRR for every 1-bit higher than the selected bit, |
; one WB MTRR for the selected bit, one UC MTRR for every 0-bit between |
; the selected bit and lowest 1-bit (they become 1-bits after negation) |
; and one UC MTRR for lowest 1-bit. |
; So we need to select 0-bit with the maximal difference |
; (number of 0-bits) - (number of 1-bits) between selected and lowest 1-bit, |
; this equals the gain from using a hole. If the difference is negative for |
; all 0-bits, don't append hole. |
; Note that lowest 1-bit is not included when counting, but selected 0-bit is. |
; 8e. Find the optimal bit position for hole. |
; eax = current difference, ebx = best difference, |
; ecx = hole bit position, edx = current bit position. |
xor eax, eax |
xor ebx, ebx |
xor ecx, ecx |
bsf edx, dword [edi+mtrr_range.length] |
jnz @f |
bsf edx, dword [edi+mtrr_range.length+4] |
add edx, 32 |
@@: |
push edx ; save position of lowest 1-bit for step 8f |
.calc_stat: |
inc edx |
cmp edx, 64 |
jae .stat_done |
inc eax ; increment difference in hope for 1-bit |
; Note: bt conveniently works with both .length and .length+4, |
; depending on whether edx>=32. |
bt dword [edi+mtrr_range.length], edx |
jc .calc_stat |
dec eax ; hope was wrong, decrement difference to correct 'inc' |
dec eax ; and again, now getting the real difference |
cmp eax, ebx |
jle .calc_stat |
mov ebx, eax |
mov ecx, edx |
jmp .calc_stat |
.stat_done: |
; 8f. If we decided to create a hole, flip all bits between lowest and selected. |
pop edx ; restore position of lowest 1-bit saved at step 8e |
test ecx, ecx |
jz .fill_hi_init |
@@: |
inc edx |
cmp edx, ecx |
ja .fill_hi_init |
btc dword [edi+mtrr_range.length], edx |
jmp @b |
.fill_hi_init: |
; 8g. Create MTRR ranges corresponding to upper 32 bits. |
sub ecx, 32 |
.fill_hi_loop: |
bsr edx, dword [edi+mtrr_range.length+4] |
jz .fill_hi_done |
inc [.num_used_mtrrs] |
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS |
ja .abort |
mov eax, dword [edi+mtrr_range.start] |
mov [esi], eax |
mov eax, dword [edi+mtrr_range.start+4] |
mov [esi+4], eax |
xor eax, eax |
mov [esi+8], eax |
bts eax, edx |
mov [esi+12], eax |
cmp edx, ecx |
jl .fill_hi_uc |
or dword [esi], MEM_WB |
add dword [edi+mtrr_range.start+4], eax |
jmp @f |
.fill_hi_uc: |
sub dword [esi+4], eax |
sub dword [edi+mtrr_range.start+4], eax |
@@: |
add esi, 16 |
sub dword [edi+mtrr_range.length], eax |
jmp .fill_hi_loop |
.fill_hi_done: |
; 8h. Create MTRR ranges corresponding to lower 32 bits. |
add ecx, 32 |
.fill_lo_loop: |
bsr edx, dword [edi+mtrr_range.length] |
jz .range2mtrr_next |
inc [.num_used_mtrrs] |
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS |
ja .abort |
mov eax, dword [edi+mtrr_range.start] |
mov [esi], eax |
mov eax, dword [edi+mtrr_range.start+4] |
mov [esi+4], eax |
xor eax, eax |
mov [esi+12], eax |
bts eax, edx |
mov [esi+8], eax |
cmp edx, ecx |
jl .fill_lo_uc |
or dword [esi], MEM_WB |
add dword [edi+mtrr_range.start], eax |
jmp @f |
.fill_lo_uc: |
sub dword [esi], eax |
sub dword [edi+mtrr_range.start], eax |
@@: |
add esi, 16 |
sub dword [edi+mtrr_range.length], eax |
jmp .fill_lo_loop |
.range2mtrr_next: |
; 8i. Repeat the loop at 8c-8h for all ranges. |
mov edi, [edi+mtrr_range.next] |
test edi, edi |
jnz .range2mtrr_loop |
; 9. We have calculated needed MTRRs, now setup them in the CPU. |
; 9a. Abort if number of MTRRs is too large. |
mov eax, [num_variable_mtrrs] |
cmp [.num_used_mtrrs], eax |
ja .abort |
; 9b. Prepare for changes. |
call mtrr_begin_change |
; 9c. Prepare for loop over MTRRs. |
lea esi, [.mtrrs] |
mov ecx, 0x200 |
@@: |
; 9d. For every MTRR, copy PHYSBASEn as is: step 8 has configured |
; start value and type bits as needed. |
mov eax, [esi] |
mov edx, [esi+4] |
wrmsr |
inc ecx |
; 9e. For every MTRR, calculate PHYSMASKn = -(length) or 0x800 |
; with upper bits cleared, 0x800 = MTRR is valid. |
xor eax, eax |
xor edx, edx |
sub eax, [esi+8] |
sbb edx, [esi+12] |
or eax, 0x800 |
or edx, [.phys_reserved_mask] |
xor edx, [.phys_reserved_mask] |
wrmsr |
inc ecx |
; 9f. Continue steps 9d and 9e for all MTRRs calculated at step 8. |
add esi, 16 |
dec [.num_used_mtrrs] |
jnz @b |
; 9g. Zero other MTRRs. |
xor eax, eax |
xor edx, edx |
mov ebx, [num_variable_mtrrs] |
lea ebx, [0x200+ebx*2] |
@@: |
cmp ecx, ebx |
jae @f |
wrmsr |
inc ecx |
wrmsr |
inc ecx |
jmp @b |
@@: |
; 9i. Configure MTRR_DEF_TYPE. |
mov ecx, 0x2FF |
rdmsr |
or ah, 8 ; enable variable-ranges MTRR |
and al, 0xF0; default memtype = UC |
wrmsr |
; 9j. Changes are done. |
call mtrr_end_change |
.abort: |
add esp, .local_vars_size + MAX_RANGES * sizeof.mtrr_range |
pop ebp |
ret |
endp |
; Allocate&set one MTRR for given range. |
; size must be power of 2 that divides base. |
proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword |
; find unused register |
mov ecx, 0x201 |
.scan: |
rdmsr |
dec ecx |
test ah, 8 |
jz .found |
rdmsr |
test edx, edx |
jnz @f |
and eax, not 0xFFF ; clear reserved bits |
cmp eax, [base] |
jz .ret |
@@: |
add ecx, 3 |
mov eax, [num_variable_mtrrs] |
lea eax, [0x200+eax*2] |
cmp ecx, eax |
jb .scan |
; no free registers, ignore the call |
.ret: |
ret |
.found: |
; found, write values |
call mtrr_begin_change |
xor edx, edx |
mov eax, [base] |
or eax, [mem_type] |
wrmsr |
mov al, [cpu_phys_addr_width] |
xor edx, edx |
bts edx, eax |
xor eax, eax |
sub eax, [size] |
sbb edx, 0 |
or eax, 0x800 |
inc ecx |
wrmsr |
call mtrr_end_change |
ret |
endp |
; Helper procedure for mtrr_validate. |
; Calculates memory type for given address according to variable-range MTRRs. |
; Assumes that MTRRs are enabled. |
; in: ebx = 32-bit physical address |
; out: eax = memory type for ebx |
proc mtrr_get_real_type |
; 1. Initialize: we have not yet found any MTRRs covering ebx. |
push 0 |
mov ecx, 0x201 |
.mtrr_loop: |
; 2. For every MTRR, check whether it is valid; if not, continue to the next MTRR. |
rdmsr |
dec ecx |
test ah, 8 |
jz .next |
; 3. For every valid MTRR, check whether (ebx and PHYSMASKn) == PHYSBASEn, |
; excluding low 12 bits. |
and eax, ebx |
push eax |
rdmsr |
test edx, edx |
pop edx |
jnz .next |
xor edx, eax |
and edx, not 0xFFF |
jnz .next |
; 4. If so, set the bit corresponding to memory type defined by this MTRR. |
and eax, 7 |
bts [esp], eax |
.next: |
; 5. Continue loop at 2-4 for all variable-range MTRRs. |
add ecx, 3 |
mov eax, [num_variable_mtrrs] |
lea eax, [0x200+eax*2] |
cmp ecx, eax |
jb .mtrr_loop |
; 6. If no MTRRs cover address in ebx, use default MTRR type from MTRR_DEF_CAP. |
pop edx |
test edx, edx |
jz .default |
; 7. Find&clear 1-bit in edx. |
bsf eax, edx |
btr edx, eax |
; 8. If there was only one 1-bit, then all MTRRs are consistent, return that bit. |
test edx, edx |
jz .nothing |
; Otherwise, return MEM_UC (e.g. WB+UC is UC). |
xor eax, eax |
.nothing: |
ret |
.default: |
mov ecx, 0x2FF |
rdmsr |
movzx eax, al |
ret |
endp |
; If MTRRs are configured improperly, this is not obvious to the user; |
; everything works, but the performance can be horrible. |
; Try to detect this and let the user know that the low performance |
; is caused by some problem and is not a global property of the system. |
; Let's hope he would report it to developers... |
proc mtrr_validate |
; 1. If MTRRs are not supported, they cannot be configured improperly. |
; Note: VirtualBox claims MTRR support in cpuid, but emulates MTRRCAP=0, |
; which is efficiently equivalent to absent MTRRs. |
; So check [num_variable_mtrrs] instead of CAPS_MTRR in [cpu_caps]. |
cmp [num_variable_mtrrs], 0 |
jz .exit |
; 2. If variable-range MTRRs are not configured, this is a problem. |
mov ecx, 0x2FF |
rdmsr |
test ah, 8 |
jz .fail |
; 3. Get the memory type for address somewhere inside working memory. |
; It must be write-back. |
mov ebx, 0x27FFFF |
call mtrr_get_real_type |
cmp al, MEM_WB |
jnz .fail |
; 4. If we're using a mode with LFB, |
; get the memory type for last pixel of the framebuffer. |
; It must be write-combined. |
test word [SCR_MODE], 0x4000 |
jz .exit |
mov eax, [_display.pitch] |
mul [_display.height] |
dec eax |
; LFB is mapped to virtual address LFB_BASE, |
; it uses global pages if supported by CPU. |
mov ebx, [sys_proc+PROC.pdt_0+(LFB_BASE shr 20)] |
test ebx, PG_LARGE |
jnz @f |
mov ebx, [page_tabs+(LFB_BASE shr 10)] |
@@: |
and ebx, not 0xFFF |
add ebx, eax |
call mtrr_get_real_type |
cmp al, MEM_WC |
jz .exit |
; 5. The check at step 4 fails on Bochs: |
; Bochs BIOS configures MTRRs in a strange way not respecting [cpu_phys_addr_width], |
; so mtrr_reconfigure avoids to touch anything. |
; However, Bochs core ignores MTRRs (keeping them only for rdmsr/wrmsr), |
; so we don't care about proper setting for Bochs. |
; Use northbridge PCI id to detect Bochs: it emulates either i440fx or i430fx |
; depending on configuration file. |
mov eax, [pcidev_list.fd] |
cmp eax, pcidev_list ; sanity check: fail if no PCI devices |
jz .fail |
cmp [eax+PCIDEV.vendor_device_id], 0x12378086 |
jz .exit |
cmp [eax+PCIDEV.vendor_device_id], 0x01228086 |
jnz .fail |
.exit: |
ret |
.fail: |
mov ebx, mtrr_user_message |
mov ebp, notifyapp |
call fs_execute_from_sysdir_param |
ret |
endp |
/kernel/branches/kolibri-process/core/v86.inc |
---|
14,9 → 14,7 |
struct V86_machine |
; page directory |
pagedir dd ? |
; translation table: V86 address -> flat linear address |
pages dd ? |
process dd ? |
; mutex to protect all data from writing by multiple threads at one time |
mutex dd ? |
; i/o permission map |
38,91 → 36,87 |
and dword [eax+V86_machine.mutex], 0 |
; allocate tables |
mov ebx, eax |
; We allocate 4 pages. |
; First is main page directory for V86 mode. |
; Second page: |
; first half (0x800 bytes) is page table for addresses 0 - 0x100000, |
; second half is for V86-to-linear translation. |
; Third and fourth are for I/O permission map. |
push 8000h ; blocks less than 8 pages are discontinuous |
stdcall create_process, 4096, OS_BASE, 4096 |
test eax, eax |
jz .fail2 |
mov [eax+PROC.mem_used], 4096 |
mov [ebx+V86_machine.process], eax |
push 2000h |
call kernel_alloc |
test eax, eax |
jz .fail2 |
mov [ebx+V86_machine.pagedir], eax |
push edi eax |
mov [ebx+V86_machine.iopm], eax |
; initialize tables |
push edi |
mov edi, eax |
add eax, 1800h |
mov [ebx+V86_machine.pages], eax |
; initialize tables |
mov eax, -1 |
mov ecx, 2000h/4 |
xor eax, eax |
rep stosd |
mov [ebx+V86_machine.iopm], edi |
dec eax |
mov ecx, 2000h/4 |
rep stosd |
pop eax |
; page directory: first entry is page table... |
mov edi, eax |
add eax, 1000h |
push eax |
call get_pg_addr |
or al, PG_UW |
stosd |
; ...and also copy system page tables |
; thx to Serge, system is located at high addresses |
add edi, (OS_BASE shr 20) - 4 |
push esi |
mov esi, sys_proc+PROC.pdt_0+(OS_BASE shr 20) |
mov ecx, 0x80000000 shr 22 |
rep movsd |
mov eax, [ebx+V86_machine.pagedir] ;root dir also is |
call get_pg_addr ;used as page table |
or al, PG_SW |
mov [edi-4096+(page_tabs shr 20)], eax |
mov eax, [ebx+V86_machine.process] |
mov eax, [eax+PROC.pdt_0_phys] |
pop esi |
pushfd |
cli |
mov cr3, eax |
; now V86 specific: initialize known addresses in first Mb |
pop eax |
; first page - BIOS data (shared between all machines!) |
; physical address = 0 |
; linear address = OS_BASE |
mov dword [eax], 111b |
mov dword [eax+800h], OS_BASE |
; page before 0xA0000 - Extended BIOS Data Area (shared between all machines!) |
; physical address = 0x9C000 |
; linear address = 0x8009C000 |
; (I have seen one computer with EBDA segment = 0x9D80, |
; all other computers use less memory) |
mov ecx, 4 |
mov edx, 0x9C000 |
push eax |
lea edi, [eax+0x9C*4] |
mov eax, PG_UW |
mov [page_tabs], eax |
invlpg [eax] |
mov byte [0x500], 0xCD |
mov byte [0x501], 0x13 |
mov byte [0x502], 0xF4 |
mov byte [0x503], 0xCD |
mov byte [0x504], 0x10 |
mov byte [0x505], 0xF4 |
mov eax, 0x99000+PG_UW |
mov edi, page_tabs+0x99*4 |
mov edx, 0x1000 |
mov ecx, 7 |
@@: |
lea eax, [edx + OS_BASE] |
mov [edi+800h], eax |
lea eax, [edx + 111b] |
stosd |
add edx, 0x1000 |
add eax, edx |
loop @b |
pop eax |
pop edi |
; addresses 0xC0000 - 0xFFFFF - BIOS code (shared between all machines!) |
; physical address = 0xC0000 |
; linear address = 0x800C0000 |
mov ecx, 0xC0 |
mov eax, 0xC0000+PG_UW |
mov edi, page_tabs+0xC0*4 |
mov edx, 0x1000 |
mov ecx, 64 |
@@: |
mov edx, ecx |
shl edx, 12 |
push edx |
or edx, 111b |
mov [eax+ecx*4], edx |
pop edx |
add edx, OS_BASE |
mov [eax+ecx*4+0x800], edx |
inc cl |
jnz @b |
stosd |
add eax, edx |
loop @b |
mov eax, sys_proc-OS_BASE+PROC.pdt_0 |
mov cr3, eax |
popfd |
pop edi |
mov eax, ebx |
ret |
.fail2: |
132,15 → 126,16 |
xor eax, eax |
ret |
;not used |
; Destroy V86 machine |
; in: eax = handle |
; out: nothing |
; destroys: eax, ebx, ecx, edx (due to free) |
v86_destroy: |
push eax |
stdcall kernel_free, [eax+V86_machine.pagedir] |
pop eax |
jmp free |
;v86_destroy: |
; push eax |
; stdcall kernel_free, [eax+V86_machine.pagedir] |
; pop eax |
; jmp free |
; Translate V86-address to linear address |
; in: eax=V86 address |
150,7 → 145,7 |
v86_get_lin_addr: |
push ecx edx |
mov ecx, eax |
mov edx, [esi+V86_machine.pages] |
mov edx, page_tabs |
shr ecx, 12 |
and eax, 0xFFF |
add eax, [edx+ecx*4] ; atomic operation, no mutex needed |
157,6 → 152,7 |
pop edx ecx |
ret |
;not used |
; Sets linear address for V86-page |
; in: eax=linear address (must be page-aligned) |
; ecx=V86 page (NOT address!) |
163,15 → 159,15 |
; esi=handle |
; out: nothing |
; destroys: nothing |
v86_set_page: |
push eax ebx |
mov ebx, [esi+V86_machine.pagedir] |
mov [ebx+ecx*4+0x1800], eax |
call get_pg_addr |
or al, 111b |
mov [ebx+ecx*4+0x1000], eax |
pop ebx eax |
ret |
;v86_set_page: |
; push eax ebx |
; mov ebx, [esi+V86_machine.pagedir] |
; mov [ebx+ecx*4+0x1800], eax |
; call get_pg_addr |
; or al, 111b |
; mov [ebx+ecx*4+0x1000], eax |
; pop ebx eax |
; ret |
; Allocate memory in V86 machine |
; in: eax=size (in bytes) |
214,21 → 210,7 |
mov [sys_v86_machine], eax |
test eax, eax |
jz .ret |
mov byte [OS_BASE + 0x500], 0xCD |
mov byte [OS_BASE + 0x501], 0x13 |
mov byte [OS_BASE + 0x502], 0xF4 |
mov byte [OS_BASE + 0x503], 0xCD |
mov byte [OS_BASE + 0x504], 0x10 |
mov byte [OS_BASE + 0x505], 0xF4 |
mov esi, eax |
mov ebx, [eax+V86_machine.pagedir] |
; one page for stack, two pages for results (0x2000 bytes = 16 sectors) |
mov dword [ebx+0x99*4+0x1000], 0x99000 or 111b |
mov dword [ebx+0x99*4+0x1800], OS_BASE + 0x99000 |
mov dword [ebx+0x9A*4+0x1000], 0x9A000 or 111b |
mov dword [ebx+0x9A*4+0x1800], OS_BASE + 0x9A000 |
mov dword [ebx+0x9B*4+0x1000], 0x9B000 or 111b |
mov dword [ebx+0x9B*4+0x1800], OS_BASE + 0x9B000 |
if ~DEBUG_SHOW_IO |
; allow access to all ports |
mov ecx, [esi+V86_machine.iopm] |
272,6 → 254,9 |
; eax = 3 - IRQ is already hooked by another VM |
; destroys: nothing |
v86_start: |
xchg bx, bx |
pushad |
cli |
296,13 → 281,11 |
mov [ecx+APPDATA.saved_esp0], esp |
mov [tss._esp0], esp |
mov eax, [esi+V86_machine.pagedir] |
call get_pg_addr |
mov eax, [esi+V86_machine.process] |
mov [ecx+APPDATA.process], eax |
; mov cr3, eax |
mov eax, [eax+PROC.pdt_0_phys] |
mov cr3, eax |
; mov [irq_tab+5*4], my05 |
; We do not enable interrupts, because V86 IRQ redirector assumes that |
; machine is running |
; They will be enabled by IRET. |
795,6 → 778,7 |
pop ebx |
mov dword [SLOT_BASE+ecx+APPDATA.io_map], ebx |
mov dword [page_tabs + (tss._io_map_0 shr 10)], ebx |
mov eax, [eax+PROC.pdt_0_phys] |
mov cr3, eax |
sti |
843,8 → 827,7 |
pop eax |
v86_irq2: |
mov esi, [v86_irqhooks+edi*8] ; get VM handle |
mov eax, [esi+V86_machine.pagedir] |
call get_pg_addr |
mov eax, [esi+V86_machine.process] |
mov ecx, [CURRENT_TASK] |
shl ecx, 8 |
cmp [SLOT_BASE+ecx+APPDATA.process], eax |
895,6 → 878,7 |
popad |
iretd |
.found: |
mov eax, [eax+PROC.pdt_0_phys] |
mov cr3, eax |
mov esi, [ebx+APPDATA.saved_esp0] |
sub word [esi-sizeof.v86_regs+v86_regs.esp], 6 |
/kernel/branches/kolibri-process/detect/init_ata.inc |
---|
0,0 → 1,459 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2014. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 4850 $ |
;----------------------------------------------------------------------------- |
; find the IDE controller in the device list |
;----------------------------------------------------------------------------- |
mov ecx, IDE_controller_1 |
mov esi, pcidev_list |
;-------------------------------------- |
align 4 |
.loop: |
mov esi, [esi+PCIDEV.fd] |
cmp esi, pcidev_list |
jz find_IDE_controller_done |
mov eax, [esi+PCIDEV.class] |
shr eax, 4 |
cmp eax, 0x01018 |
jnz .loop |
;-------------------------------------- |
.found: |
mov eax, [esi+PCIDEV.class] |
DEBUGF 1, 'K : IDE controller programming interface %x\n', eax |
mov [ecx+IDE_DATA.ProgrammingInterface], eax |
mov ah, [esi+PCIDEV.bus] |
mov al, 2 |
mov bh, [esi+PCIDEV.devfn] |
;-------------------------------------- |
mov dx, 0x1F0 |
test byte [esi+PCIDEV.class], 1 |
jz @f |
mov bl, 0x10 |
push eax |
call pci_read_reg |
and eax, 0xFFFC |
mov edx, eax |
pop eax |
@@: |
DEBUGF 1, 'K : BAR0 IDE base addr %x\n', dx |
mov [StandardATABases], dx |
mov [ecx+IDE_DATA.BAR0_val], dx |
;-------------------------------------- |
mov dx, 0x3F4 |
test byte [esi+PCIDEV.class], 1 |
jz @f |
mov bl, 0x14 |
push eax |
call pci_read_reg |
and eax, 0xFFFC |
mov edx, eax |
pop eax |
@@: |
DEBUGF 1, 'K : BAR1 IDE base addr %x\n', dx |
mov [ecx+IDE_DATA.BAR1_val], dx |
;-------------------------------------- |
mov dx, 0x170 |
test byte [esi+PCIDEV.class], 4 |
jz @f |
mov bl, 0x18 |
push eax |
call pci_read_reg |
and eax, 0xFFFC |
mov edx, eax |
pop eax |
@@: |
DEBUGF 1, 'K : BAR2 IDE base addr %x\n', dx |
mov [StandardATABases+2], dx |
mov [ecx+IDE_DATA.BAR2_val], dx |
;-------------------------------------- |
mov dx, 0x374 |
test byte [esi+PCIDEV.class], 4 |
jz @f |
mov bl, 0x1C |
push eax |
call pci_read_reg |
and eax, 0xFFFC |
mov edx, eax |
pop eax |
@@: |
DEBUGF 1, 'K : BAR3 IDE base addr %x\n', dx |
mov [ecx+IDE_DATA.BAR3_val], dx |
;-------------------------------------- |
mov bl, 0x20 |
push eax |
call pci_read_reg |
and eax, 0xFFFC |
DEBUGF 1, 'K : BAR4 IDE controller register base addr %x\n', ax |
mov [ecx+IDE_DATA.RegsBaseAddres], ax |
pop eax |
;-------------------------------------- |
mov bl, 0x3C |
push eax |
call pci_read_reg |
and eax, 0xFF |
DEBUGF 1, 'K : IDE Interrupt %x\n', al |
mov [ecx+IDE_DATA.Interrupt], ax |
pop eax |
add ecx, sizeof.IDE_DATA |
;-------------------------------------- |
jmp .loop |
;----------------------------------------------------------------------------- |
uglobal |
align 4 |
;-------------------------------------- |
IDE_controller_pointer dd ? |
;-------------------------------------- |
IDE_controller_1 IDE_DATA |
IDE_controller_2 IDE_DATA |
IDE_controller_3 IDE_DATA |
;-------------------------------------- |
cache_ide0 IDE_CACHE |
cache_ide1 IDE_CACHE |
cache_ide2 IDE_CACHE |
cache_ide3 IDE_CACHE |
cache_ide4 IDE_CACHE |
cache_ide5 IDE_CACHE |
cache_ide6 IDE_CACHE |
cache_ide7 IDE_CACHE |
cache_ide8 IDE_CACHE |
cache_ide9 IDE_CACHE |
cache_ide10 IDE_CACHE |
cache_ide11 IDE_CACHE |
;-------------------------------------- |
IDE_device_1 rd 2 |
IDE_device_2 rd 2 |
IDE_device_3 rd 2 |
;-------------------------------------- |
endg |
;----------------------------------------------------------------------------- |
; START of initialisation IDE ATA code |
;----------------------------------------------------------------------------- |
Init_IDE_ATA_controller: |
cmp [ecx+IDE_DATA.ProgrammingInterface], 0 |
jne @f |
ret |
;-------------------------------------- |
@@: |
mov esi, boot_disabling_ide |
call boot_log |
;-------------------------------------- |
; Disable IDE interrupts, because the search |
; for IDE partitions is in the PIO mode. |
;-------------------------------------- |
.disable_IDE_interrupt: |
; Disable interrupts in IDE controller for PIO |
mov al, 2 |
mov dx, [ecx+IDE_DATA.BAR1_val] ;0x3F4 |
add dx, 2 ;0x3F6 |
out dx, al |
mov dx, [ecx+IDE_DATA.BAR3_val] ;0x374 |
add dx, 2 ;0x376 |
out dx, al |
;----------------------------------------------------------------------------- |
; set current ata bases |
@@: |
mov ax, [ecx+IDE_DATA.BAR0_val] |
mov [StandardATABases], ax |
mov ax, [ecx+IDE_DATA.BAR2_val] |
mov [StandardATABases+2], ax |
mov esi, boot_detecthdcd |
call boot_log |
;-------------------------------------- |
include 'dev_hdcd.inc' |
;-------------------------------------- |
ret |
;----------------------------------------------------------------------------- |
Init_IDE_ATA_controller_2: |
cmp [ecx+IDE_DATA.ProgrammingInterface], 0 |
jne @f |
ret |
;-------------------------------------- |
@@: |
mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
; test whether it is our interrupt? |
add dx, 2 |
in al, dx |
test al, 100b |
jz @f |
; clear Bus Master IDE Status register |
; clear Interrupt bit |
out dx, al |
;-------------------------------------- |
@@: |
add dx, 8 |
; test whether it is our interrupt? |
in al, dx |
test al, 100b |
jz @f |
; clear Bus Master IDE Status register |
; clear Interrupt bit |
out dx, al |
;-------------------------------------- |
@@: |
; read status register and remove the interrupt request |
mov dx, [ecx+IDE_DATA.BAR0_val] ;0x1F0 |
add dx, 0x7 ;0x1F7 |
in al, dx |
mov dx, [ecx+IDE_DATA.BAR2_val] ;0x170 |
add dx, 0x7 ;0x177 |
in al, dx |
;----------------------------------------------------------------------------- |
; push eax edx |
; mov dx, [ecx+IDE_DATA.RegsBaseAddres] |
; xor eax, eax |
; add dx, 2 |
; in al, dx |
; DEBUGF 1, "K : Primary Bus Master IDE Status Register %x\n", eax |
; add dx, 8 |
; in al, dx |
; DEBUGF 1, "K : Secondary Bus Master IDE Status Register %x\n", eax |
; pop edx eax |
; cmp [ecx+IDE_DATA.RegsBaseAddres], 0 |
; setnz [ecx+IDE_DATA.dma_hdd] |
;----------------------------------------------------------------------------- |
; set interrupts for IDE Controller |
;----------------------------------------------------------------------------- |
pushfd |
cli |
.enable_IDE_interrupt: |
mov esi, boot_enabling_ide |
call boot_log |
; Enable interrupts in IDE controller for DMA |
xor ebx, ebx |
cmp ecx, IDE_controller_2 |
jne @f |
add ebx, 5 |
jmp .check_DRIVE_DATA |
;-------------------------------------- |
@@: |
cmp ecx, IDE_controller_3 |
jne .check_DRIVE_DATA |
add ebx, 10 |
;-------------------------------------- |
.check_DRIVE_DATA: |
mov al, 0 |
mov ah, [ebx+DRIVE_DATA+1] |
test ah, 10100000b ; check for ATAPI devices |
jz @f |
;-------------------------------------- |
.ch1_pio_set_ATAPI: |
DEBUGF 1, "K : IDE CH1 PIO, because ATAPI drive present\n" |
jmp .ch1_pio_set_for_all |
;-------------------------------------- |
.ch1_pio_set_no_devices: |
DEBUGF 1, "K : IDE CH1 PIO because no devices\n" |
jmp .ch1_pio_set_for_all |
;------------------------------------- |
.ch1_pio_set: |
DEBUGF 1, "K : IDE CH1 PIO because device not support UDMA\n" |
;------------------------------------- |
.ch1_pio_set_for_all: |
mov [ecx+IDE_DATA.dma_hdd_channel_1], al |
jmp .ch2_check |
;-------------------------------------- |
@@: |
xor ebx, ebx |
call calculate_IDE_device_values_storage |
test ah, 1010000b |
jz .ch1_pio_set_no_devices |
test ah, 1000000b |
jz @f |
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al |
je .ch1_pio_set |
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al |
je .ch1_pio_set |
;-------------------------------------- |
@@: |
test ah, 10000b |
jz @f |
add ebx, 2 |
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al |
je .ch1_pio_set |
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al |
je .ch1_pio_set |
;-------------------------------------- |
@@: |
mov dx, [ecx+IDE_DATA.BAR1_val] ;0x3F4 |
add dx, 2 ;0x3F6 |
out dx, al |
DEBUGF 1, "K : IDE CH1 DMA enabled\n" |
mov [ecx+IDE_DATA.dma_hdd_channel_1], byte 1 |
;-------------------------------------- |
.ch2_check: |
test ah, 1010b ; check for ATAPI devices |
jz @f |
;-------------------------------------- |
.ch2_pio_set_ATAPI: |
DEBUGF 1, "K : IDE CH2 PIO, because ATAPI drive present\n" |
jmp .ch2_pio_set_for_all |
;-------------------------------------- |
.ch2_pio_set_no_devices: |
DEBUGF 1, "K : IDE CH2 PIO because no devices\n" |
jmp .ch2_pio_set_for_all |
;-------------------------------------- |
.ch2_pio_set: |
DEBUGF 1, "K : IDE CH2 PIO because device not support UDMA\n" |
;-------------------------------------- |
.ch2_pio_set_for_all: |
mov [ecx+IDE_DATA.dma_hdd_channel_2], al |
jmp .set_interrupts_for_IDE_controllers |
;-------------------------------------- |
@@: |
mov ebx, 4 |
call calculate_IDE_device_values_storage |
test ah, 101b |
jz .ch2_pio_set_no_devices |
test ah, 100b |
jz @f |
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al |
je .ch2_pio_set |
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al |
je .ch2_pio_set |
;-------------------------------------- |
@@: |
test ah, 1b |
jz @f |
add ebx, 2 |
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al |
je .ch2_pio_set |
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al |
je .ch2_pio_set |
;-------------------------------------- |
@@: |
mov dx, [ecx+IDE_DATA.BAR3_val] ;0x374 |
add dx, 2 ;0x376 |
out dx, al |
DEBUGF 1, "K : IDE CH2 DMA enabled\n" |
mov [ecx+IDE_DATA.dma_hdd_channel_2], byte 1 |
;-------------------------------------- |
.set_interrupts_for_IDE_controllers: |
mov esi, boot_set_int_IDE |
call boot_log |
;-------------------------------------- |
mov eax, [ecx+IDE_DATA.ProgrammingInterface] |
cmp ax, 0x0180 |
je .pata_ide |
cmp ax, 0x018a |
jne .sata_ide |
;-------------------------------------- |
.pata_ide: |
cmp [ecx+IDE_DATA.RegsBaseAddres], 0 |
je .end_set_interrupts |
push ecx |
stdcall attach_int_handler, 14, IDE_irq_14_handler, 0 |
DEBUGF 1, "K : Set IDE IRQ14 return code %x\n", eax |
stdcall attach_int_handler, 15, IDE_irq_15_handler, 0 |
DEBUGF 1, "K : Set IDE IRQ15 return code %x\n", eax |
pop ecx |
jmp .end_set_interrupts |
;-------------------------------------- |
.sata_ide: |
cmp ax, 0x0185 |
je .sata_ide_1 |
cmp ax, 0x018f |
jne .end_set_interrupts |
;-------------------------------------- |
.sata_ide_1: |
; Some weird controllers generate an interrupt even if IDE interrupts |
; are disabled and no IDE devices. For example, notebook ASUS K72F - |
; IDE controller 010185 generates false interrupt when we work with |
; the IDE controller 01018f. For this reason, the interrupt handler |
; does not need to be installed if both channel IDE controller |
; running in PIO mode. |
cmp [ecx+IDE_DATA.RegsBaseAddres], 0 |
je .end_set_interrupts |
cmp [ecx+IDE_DATA.dma_hdd_channel_1], 0 |
jne @f |
cmp [ecx+IDE_DATA.dma_hdd_channel_2], 0 |
je .end_set_interrupts |
;-------------------------------------- |
@@: |
mov ax, [ecx+IDE_DATA.Interrupt] |
movzx eax, al |
push ecx |
stdcall attach_int_handler, eax, IDE_common_irq_handler, 0 |
pop ecx |
DEBUGF 1, "K : Set IDE IRQ%d return code %x\n", [ecx+IDE_DATA.Interrupt]:1, eax |
;-------------------------------------- |
.end_set_interrupts: |
popfd |
ret |
;----------------------------------------------------------------------------- |
; END of initialisation IDE ATA code |
;----------------------------------------------------------------------------- |
find_IDE_controller_done: |
mov ecx, IDE_controller_1 |
mov [IDE_controller_pointer], ecx |
call Init_IDE_ATA_controller |
mov ecx, IDE_controller_2 |
mov [IDE_controller_pointer], ecx |
call Init_IDE_ATA_controller |
mov ecx, IDE_controller_3 |
mov [IDE_controller_pointer], ecx |
call Init_IDE_ATA_controller |
;----------------------------------------------------------------------------- |
mov esi, boot_getcache |
call boot_log |
include 'getcache.inc' |
;----------------------------------------------------------------------------- |
mov esi, boot_detectpart |
call boot_log |
include 'sear_par.inc' |
;----------------------------------------------------------------------------- |
mov esi, boot_init_sys |
call boot_log |
call Parser_params |
if ~ defined extended_primary_loader |
; ramdisk image should be loaded by extended primary loader if it exists |
; READ RAMDISK IMAGE FROM HD |
include '../boot/rdload.inc' |
end if |
;----------------------------------------------------------------------------- |
mov ecx, IDE_controller_1 |
mov [IDE_controller_pointer], ecx |
call Init_IDE_ATA_controller_2 |
mov ecx, IDE_controller_2 |
mov [IDE_controller_pointer], ecx |
call Init_IDE_ATA_controller_2 |
mov ecx, IDE_controller_3 |
mov [IDE_controller_pointer], ecx |
call Init_IDE_ATA_controller_2 |
;----------------------------------------------------------------------------- |
/kernel/branches/kolibri-process/gui/button.inc |
---|
39,6 → 39,7 |
;> 7 (31) = 0 |
;> 6 (30) = don't draw button |
;> 5 (29) = don't draw button frame when pressed |
;> 4 (28) = don't draw button 3d frame |
;> esi = button color |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Undefine button: |
86,9 → 87,11 |
mov ax, dx |
stosw ; button id number: bits 0-15 |
mov eax, ebx |
dec eax |
rol eax, 16 |
stosd ; x start | x size |
mov eax, ecx |
dec eax |
rol eax, 16 |
stosd ; y start | y size |
mov eax, edx |
100,113 → 103,115 |
test edx, 0x40000000 |
jnz .exit |
; draw button body |
; DRAW BODY ----------------------------- |
pushad |
; calculate window-relative coordinates |
movzx edi, cx |
shr ebx, 16 |
shr ecx, 16 |
mov eax, [TASK_BASE] |
add ebx, [eax - twdw + WDATA.box.left] |
add ecx, [eax - twdw + WDATA.box.top] |
mov eax, ebx |
shl eax, 16 |
mov ax, bx |
add ax, word[esp + 16] |
mov ebx, ecx |
shl ebx, 16 |
mov bx, cx |
; calculate initial color |
call button._.button_calc_relativ |
xor edi, edi ; for __sys_draw_line |
; set color |
mov ecx, esi |
; set coordinate |
inc edx |
; if gradient |
cmp [buttontype], 0 |
je @f |
call button._.incecx2 |
; set button height counter |
@@: |
mov edx, edi |
je .next_line |
call button._.incecx |
align 4 |
.next_line: |
call button._.button_dececx |
push edi |
xor edi, edi |
; call [draw_line] |
call __sys_draw_line |
pop edi |
add ebx, 0x00010001 |
dec edx |
jnz .next_line |
popad |
; DRAW FRAME ---------------------------- |
pushad |
call button._.button_calc_relativ |
mov esi, common_colours |
mov edi, dword [esi+104] |
call .top_border |
mov edi, dword [esi+104] |
call .bottom_border |
mov edi, dword [esi+104] |
call .right_border |
mov edi, dword [esi+104] |
call .left_border |
popad |
; draw button frame |
; DRAW 3D SHADOW ------------------------ |
test edx, 0x10000000 |
jnz .exit |
push ebx ecx |
pushad |
mov edi, edx |
call button._.button_calc_relativ |
; get color address |
mov esi, common_colours |
test edi, 0x10000000 |
jnz @f |
add eax, 0x10000 |
dec eax |
inc ecx |
dec edx |
dec edx |
align 4 |
@@: |
mov edi, dword [esi+12] |
call .top_border |
mov edi, dword [esi+8] |
call .bottom_border |
mov edi, dword [esi+8] |
call .right_border |
mov edi, dword [esi+12] |
call .left_border |
popad |
ret |
; calculate window-relative coordinates |
shr ebx, 16 |
shr ecx, 16 |
mov eax, [TASK_BASE] |
add ebx, [eax - twdw + WDATA.box.left] |
add ecx, [eax - twdw + WDATA.box.top] |
; top border |
mov eax, ebx |
shl eax, 16 |
mov ax, bx |
add ax, [esp + 4] |
align 4 |
.top_border: |
mov ebx, ecx |
shl ebx, 16 |
mov bx, cx |
push ebx |
mov ecx, edi |
xor edi, edi |
mov ecx, esi |
call button._.incecx |
; call [draw_line] |
call __sys_draw_line |
ret |
; bottom border |
movzx edx, word[esp + 4 + 0] |
add ebx, edx |
shl edx, 16 |
add ebx, edx |
mov ecx, esi |
call button._.dececx |
; call [draw_line] |
align 4 |
.bottom_border: |
add bx , dx |
rol ebx, 16 |
add bx , dx |
mov ecx, edi |
xor edi, edi |
call __sys_draw_line |
ret |
; left border |
pop ebx |
push edx |
mov edx, eax |
shr edx, 16 |
mov ax, dx |
mov edx, ebx |
shr edx, 16 |
mov bx, dx |
add bx, [esp + 4 + 0] |
pop edx |
mov ecx, esi |
call button._.incecx |
; call [draw_line] |
align 4 |
.right_border: |
push eax |
sub bx, dx |
mov cx, ax |
shl eax, 16 |
mov ax, cx |
mov ecx, edi |
xor edi, edi |
call __sys_draw_line |
pop eax |
ret |
; right border |
mov dx, [esp + 4] |
add ax, dx |
shl edx, 16 |
add eax, edx |
add ebx, 0x00010000 |
mov ecx, esi |
call button._.dececx |
; call [draw_line] |
align 4 |
.left_border: |
shr eax, 16 |
mov cx, ax |
shl eax, 16 |
mov ax, cx |
mov ecx, edi |
xor edi, edi |
call __sys_draw_line |
pop ecx ebx |
ret |
align 4 |
.exit: |
ret |
269,8 → 274,10 |
jz .exit |
mov ebx, dword[eax + SYS_BUTTON.id_hi - 2] |
push edi ; spam |
xor edi, edi |
call button._.negative_button |
pop edi |
.exit: |
ret |
289,8 → 296,11 |
jz .exit |
mov ebx, dword[eax + SYS_BUTTON.id_hi - 2] |
push edi ; spam |
xor edi, edi |
inc edi |
call button._.negative_button |
pop edi |
.exit: |
ret |
374,49 → 384,41 |
ret |
;------------------------------------------------------------------------------ |
button._.dececx: ;///////////////////////////////////////////////////////////// |
button._.button_dececx: ;////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
sub cl, 0x20 |
cmp [buttontype], 1 |
jne .finish |
push eax |
mov al, 1 |
;cmp edi, 20 |
;jg @f |
;mov al, 2 |
@@: |
sub cl, al |
jnc @f |
xor cl, cl |
@@: |
sub ch, 0x20 |
sub ch, al |
jnc @f |
xor ch, ch |
@@: |
rol ecx, 16 |
sub cl, 0x20 |
sub cl, al |
jnc @f |
xor cl, cl |
@@: |
rol ecx, 16 |
ret |
;------------------------------------------------------------------------------ |
button._.incecx: ;///////////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
add cl, 0x20 |
jnc @f |
or cl, -1 |
@@: |
add ch, 0x20 |
jnc @f |
or ch, -1 |
@@: |
rol ecx, 16 |
add cl, 0x20 |
jnc @f |
or cl, -1 |
@@: |
rol ecx, 16 |
pop eax |
.finish: |
ret |
;------------------------------------------------------------------------------ |
button._.incecx2: ;//////////////////////////////////////////////////////////// |
button._.incecx: ;//////////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
435,40 → 437,26 |
@@: |
rol ecx, 16 |
ret |
;------------------------------------------------------------------------------ |
button._.button_dececx: ;////////////////////////////////////////////////////// |
button._.button_calc_relativ: ; |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
cmp [buttontype], 1 |
jne .finish |
push eax |
mov al, 1 |
cmp edi, 20 |
jg @f |
mov al, 2 |
@@: |
sub cl, al |
jnc @f |
xor cl, cl |
@@: |
sub ch, al |
jnc @f |
xor ch, ch |
@@: |
rol ecx, 16 |
sub cl, al |
jnc @f |
xor cl, cl |
@@: |
rol ecx, 16 |
pop eax |
.finish: |
movzx edx, cx |
dec edx ; get height |
shr ebx, 16 |
shr ecx, 16 |
mov eax, [TASK_BASE] |
add ebx, [eax - twdw + WDATA.box.left] |
add ecx, [eax - twdw + WDATA.box.top] |
mov eax, ebx |
shl eax, 16 |
mov ax, bx |
add ax, word[esp + 20] |
dec eax |
mov bx, cx |
shl ebx, 16 |
mov bx, cx |
ret |
;------------------------------------------------------------------------------ |
475,6 → 463,7 |
button._.negative_button: ;//////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Invert system button border |
; edi - 0 activate, 1 - deactivate |
;------------------------------------------------------------------------------ |
; if requested, do not display button border on press. |
test ebx, 0x20000000 |
481,7 → 470,7 |
jnz .exit |
pushad |
push ebx |
xchg esi, eax |
movzx ecx, [esi + SYS_BUTTON.pslot] |
499,10 → 488,58 |
add ax, cx |
add bx, dx |
xor edx, edx |
mov dx, [esi + SYS_BUTTON.id_lo] |
cmp dx, 1 |
jne .no_close |
sub eax, 0x00010001 |
dec ebx |
mov esi, 0x01000000 |
call draw_rectangle.forced |
jmp .fade |
align 4 |
.no_close: |
cmp dx, 65535 |
jne .no_mini |
sub eax, 0x00010001 |
dec ebx |
mov esi, 0x01000000 |
call draw_rectangle.forced |
jmp .fade |
align 4 |
.no_mini: |
add eax, 0x00010000 |
add ebx, 0x00010000 |
pop edx |
test edx, 0x10000000 |
jnz .only_frame |
mov edx, common_colours |
mov esi, dword [edx+12] |
cmp edi, 0 |
jne .shadow |
mov esi, dword [edx+8] |
align 4 |
.shadow: |
call draw_rectangle.forced |
align 4 |
.only_frame: |
mov edx, common_colours |
sub eax, 0x00010000 |
sub ebx, 0x00010000 |
mov esi, dword [edx+104] |
cmp edi, 0 |
jne .draw |
mov esi, dword [edx+112] |
align 4 |
.draw: |
call draw_rectangle.forced |
popad |
ret |
align 4 |
.fade: |
pop ebx |
popad |
align 4 |
.exit: |
ret |
/kernel/branches/kolibri-process/hid/keyboard.inc |
---|
1,6 → 1,6 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
457,19 → 457,40 |
test bl, bl |
jz .exit.irq1 |
test [kb_state], VKEY_NUMLOCK |
jz .dowrite |
cmp cl, 0xE0 ; extended keycode |
jne @f |
cmp cl, 0xE0 |
jz .dowrite |
cmp ch, 53 |
jne .dowrite |
mov bl, '/' |
jmp .dowrite |
@@: |
cmp ch, 55 |
jnz @f |
jne @f |
mov bl, 0x2A ;* |
mov bl, '*' |
jmp .dowrite |
;-------------------------------------- |
@@: |
cmp ch, 74 |
jne @f |
mov bl, '-' |
jmp .dowrite |
@@: |
cmp ch, 78 |
jne @f |
mov bl, '+' |
jmp .dowrite |
@@: |
test [kb_state], VKEY_NUMLOCK |
jz .dowrite |
cmp ch, 71 |
jb .dowrite |
/kernel/branches/kolibri-process/kernel.asm |
---|
685,7 → 685,8 |
xchg bx, bx |
call v86_init |
; call v86_init |
call init_sys_v86 |
mov esi, boot_inittimer |
call boot_log |
1008,7 → 1009,6 |
; Load PS/2 mouse driver |
stdcall load_driver, szPS2MDriver |
; stdcall load_driver, szCOM_MDriver |
mov esi, boot_setmouse |
call boot_log |
/kernel/branches/kolibri-process/network/IPv4.inc |
---|
267,10 → 267,9 |
cmp eax, 224 |
je .ip_ok |
; or a loopback address (127.0.0.0/8) |
; maybe we just dont have an IP yet and should accept everything on the IP level |
and eax, 0x00ffffff |
cmp eax, 127 |
cmp [IP_LIST + edi], 0 |
je .ip_ok |
; or it's just not meant for us.. :( |
/kernel/branches/kolibri-process/network/stack.inc |
---|
110,7 → 110,7 |
SS_BLOCKED = 0x8000 |
SOCKET_MAXDATA = 4096*8 ; must be 4096*(power of 2) where 'power of 2' is at least 8 |
SOCKET_MAXDATA = 4096*64 ; must be 4096*(power of 2) where 'power of 2' is at least 8 |
MAX_backlog = 20 ; maximum backlog for stream sockets |
; Error Codes |