aboutsummaryrefslogtreecommitdiff
path: root/newlib/libc/sys/go32/setstack.S
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/sys/go32/setstack.S')
-rw-r--r--newlib/libc/sys/go32/setstack.S70
1 files changed, 70 insertions, 0 deletions
diff --git a/newlib/libc/sys/go32/setstack.S b/newlib/libc/sys/go32/setstack.S
new file mode 100644
index 0000000..dcd3ac0
--- /dev/null
+++ b/newlib/libc/sys/go32/setstack.S
@@ -0,0 +1,70 @@
+/* This routine potentially increases the stack size at runtime based on
+ the _stklen variable. Only used by DPMI code.
+ Copyright (c) 1993 C. Sandmann
+ Environment: called by crt0.s (and gcrt0.s)
+ EAX, EBX, EBP, EDI, ESI disposable (cleared on return) */
+
+ .text
+ .globl __setstack
+__setstack:
+ movl %esp,%eax
+ andl $0xc0000000,%eax /* clear all except upper bits */
+ jne ok_stack /* obviously not DPMI! */
+ movw %ss,%ax
+ lsll %eax,%ebx /* stack segment limit */
+ movl %esp,%eax /* current location */
+ subl %ebx,%eax /* Free stack */
+ cmpl %eax,__stklen
+ jb ok_stack
+
+/* Not enough stack. Call sbrk() to get a new area. Copy current ESP + 20
+ to end of new area (3 args + our stack). Change ESP to new area. Set new
+ limit to start of new area using DPMI services. */
+
+ pushl __stklen
+ call _sbrk /* eax = got memory base */
+ popl %ebx /* remove _stklen */
+ cmpl $0xffffffff,%eax /* if eax = -1 failure */
+ je badstack
+ addl %eax,%ebx /* ebx now is end of new stack area */
+ andl $0xfffffff0,%ebx /* 16 byte alignment */
+ addl $0xfff,%eax /* make stack base page aligned */
+ andl $0xfffff000,%eax /* 4096 byte alignment */
+
+/* Now copy old stack to new stack. We only need our part + 4 words, 3 for
+ the parameters to pass to main, one for our return EIP (4 extra safety) */
+ movl %esp, %esi /* Source is current stack */
+ subl $0x20, %ebx /* 8 longwords */
+ movl %ebx, %edi /* Destination is new stack */
+ movl $8,%ecx
+ rep
+ movsl
+
+/* New stack in place. Change ESP to point to it. Assumes new stack is
+ higher in memory so we don't get caught by limit. Change limit using
+ DPMI services. */
+
+ movl %ebx,%esp /* Switch to new stack */
+ subl $1,%eax /* Low 12 bits all 1s */
+ pushl %eax /* Easiest way to move long to words */
+ popw %dx
+ popw %cx
+ movl $8,%eax /* DPMI function Set Segment Limit */
+ movw %ss,%bx /* Selector */
+ int $0x31 /* Do service */
+
+ xor %ecx,%ecx /* Clean up */
+ xor %edx,%edx /* Clean up */
+
+ok_stack:
+ ret /* What we have is already bigger */
+
+badstack:
+ movl $0x4c01,%eax
+ int $0x21
+ jmp badstack
+
+ .data
+ .globl __stklen
+ .comm __stklen,4
+