6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Mon Apr 29, 2024 9:44 am

All times are UTC




Post new topic Reply to topic  [ 544 posts ]  Go to page Previous  1 ... 4, 5, 6, 7, 8, 9, 10 ... 37  Next
Author Message
 Post subject: Re: POC Version 2
PostPosted: Mon Jun 25, 2012 7:48 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
whartung wrote:
I guess all I was thinking is that Bank $00 can be considered the privileged bank, and each time an opcode is fetched you capture the current bank address for that opcode. When that value is $00, you can set a latch or something.

Assuming you are referring to the linear memory model, no code other than the interrupt handlers would run in bank $00. So setting a latch in itself wouldn't accomplish anything.

Quote:
In the decode logic, when it detects a DATA access is taking place, if the latch is set, then the bank address for the data access can just go through from the DB/BA0-7 pins. If the latch is NOT set, then the data bank address is hidden, and the one that was captured during the opcode fetch is used instead (thus limiting non-privileged banks to their own 64K block).

The security about the DBR is simply that it's effectively ignored and matches the PBR all the time, as enforced by the hardware, save for when running in the kernel space.

The CPLD logic is implicitly aware of the bank bits, since it uses them to generate the chip selects to SRAM. So it should be possible for the CPLD code to compare the bank bits during the final cycle of an instruction against the bank in which the process is running. It would be up to the kernel to keep the CPLD informed as to which bank is active. That would be through a bi-directional HMU register that I have yet to define.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Mon Jun 25, 2012 8:50 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
I guess I'm not following along. I thought you were looking for a way to secure the individual banks, and have a kernel in a dedicated bank, let the kernel access all banks while the "user" banks could only address their own. Each process would be pinned to their own bank. During an software interrupt, the kernel will "know" what the current SP is, which would naturally be pointing in to the source process (thus it could be used as a natural indicator of the calling process by looking at the bank byte of the information on the stack).

I don't know how the "protected" decoder logic would work during a software interrupt when the CPU tries to send control to the interrupt vector, since the PC at the time of the INT would not be from within the protected kernel space. That might muck up the works right there unless the interrupt can be detected somehow.


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Mon Jun 25, 2012 11:17 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 387
Location: Minnesota
Quote:
teamtempest wrote:
Quote:
Segmentation is not without its drawbacks. Since any process is not allowed to access another process's segment, the time-honored method of accessing a kernel API as a subroutine is out—the JSR would cause a hardware exception by virtue of accessing "privileged" RAM (the kernel's space, in this case). Allowing such access would mean a special case condition would have to exist in the glue logic to allow a JSR to a kernel API address, but nowhere else outside of user process space. A lot of CPLD capability could be eaten up trying to enforce this very narrow access rule, as the data bus would have to be monitored for one unique instruction.



What if the hardware "mirrored" a bit of the kernel in every 64K block? 1K or 512 bytes or something like that at the top of every 64K block? Perhaps just enough code space to save enough context to "know" which process is calling and then switch to the "real" kernel?

I'm reminded of the C128's memory management registers, which appeared as I/O at $FF00+ in all 256 possible configurations, even ones which in theory had no I/O registers at all (thus avoiding the problem of getting "stuck" in a configuration with no way out because of being unable to write to the memory management registers).

That could be done but it would then be necessary to somehow write-protect the mirrored area, since it would appear to be in part of the user process' space. If kernel APIs are called via software interrupts then mirroring isn't necessary, but then the problem of the kernel accessing the caller's stack gets involved. It's messy, either way.


If the mirrored section looked like ROM to the user process that ought to be sufficient write protection. Would the HMU be able to make that happen?

Regarding software interrupts - doesn't any multi-tasking kernel, pre-emptive or co-operative, have to have some knowledge of what the current running process is? Otherwise it wouldn't be possible to rationally switch to another process. And shouldn't only the current process be capable of triggering a software interrupt? I have a hard time imagining a stopped process doing so, anyway.

So...shouldn't the kernel be able to easily figure out which process issued a software interrupt? And therefore which context holds any parameters passed on that process' stack? Or isn't that the problem?


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Tue Jun 26, 2012 5:34 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
teamtempest wrote:
Regarding software interrupts - doesn't any multi-tasking kernel, pre-emptive or co-operative, have to have some knowledge of what the current running process is? Otherwise it wouldn't be possible to rationally switch to another process.

I've never done multitasking with a full multitasking OS-- only pseudomultitasking with interrupts, including alarms that come due to carry out a task when it is time, and interrupts can continue while that task is executing, too. I can see however that coöperative multitasking would be quite easy to do in Forth on a 6502 with very little overhead; and I can imagine a situation where the OS is mostly only involved in setting up new tasks or taking tasks down. It could, for example, even tell task #4 when it sets it up, or when it sets up or changes #5, "Every time you're done, just jump to task 5's entry point, which is ___. You don't need to bother me." If a task is sleeping at the moment, it could just pass the baton, so to speak, without taking time to do anything else. The task at the end of the line would pass the baton to the OS. Any task could call routines in the OS though. Sure, if one task crashes, they all crash; but we're not talking about purchased black-box software. If it's bad, you're going to go into it and fix it, because you wrote it.

[Edit, 5/15/14: I posted an article on simple methods of doing multitasking without a multitasking OS, at http://wilsonminesco.com/multitask/index.html.]

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Tue Jun 26, 2012 6:37 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
whartung wrote:
I guess I'm not following along. I thought you were looking for a way to secure the individual banks, and have a kernel in a dedicated bank, let the kernel access all banks while the "user" banks could only address their own. Each process would be pinned to their own bank. During an software interrupt, the kernel will "know" what the current SP is, which would naturally be pointing in to the source process (thus it could be used as a natural indicator of the calling process by looking at the bank byte of the information on the stack).

I don't know how the "protected" decoder logic would work during a software interrupt when the CPU tries to send control to the interrupt vector, since the PC at the time of the INT would not be from within the protected kernel space. That might muck up the works right there unless the interrupt can be detected somehow.

I'm not sure you understand the nature of the problem. Sandboxing per se would not all that difficult to achieve, if it weren't for a design "feature" of the 65C816. First off, let's review how the '816 generates valid addresses and how that information would be used to set up memory protection.

A0-A15 are generated from the MPU program counter, the same as the 65(c)02, and A16-A23 are generated on D0-D7 when Ø2 is low and the address bus is declared to be valid, the latter being determined by the VDA and VPA signals. The origin of the A16-A23 component varies as an instruction is executed. The VDA/VPA and address generation relationships are as follows:

Code:
                                A16-A23
Ref   VDA   VPA   Address Bus   Source    MPU Activity
—————————————————————————————————————————————————————————————
 1     0     0      Invalid       --      Internal operation
 2     0     1       Valid        PB      Operand fetch
 3     1     0       Valid        DB      Data fetch or store
 4     1     1       Valid        PB      Opcode fetch
—————————————————————————————————————————————————————————————

In the above, "address bus" includes the A16-A23 component that is multiplexed on D0-D7 during valid memory cycles when Ø2 low. If a memory cycle is not valid the state of D0-D7 is undefined. The entries in the A16-A23 Source Column refer to the program bank (PB) and data bank (DB) registers. The conditions in reference #1 occur during the intermediate execution stages of some instructions, especially those that involve indexed addressing. Chip selects must never be valid during the condition defined in reference #1, as the effective address is undefined. Incidentally, the conditions in reference #4 correspond to when the 65C02 asserts the SYNC signal.

At any given time, the CPLD logic will "know" from watching VDA and VPA when the effective address is valid and, indirectly, what is on the data bus during any given clock cycle. Hence such information could be used to police memory accesses. However, this is a stateless situation—there is no way to know what transpired in the past, unless the CPLD institutes stateful inspection of each instruction cycle and records the condition of VDA, VPA, A0-A23 and D0-D7 for posterity. That's not practical, nor is it necessary in order to sandbox processes. All that has to be known is what is on D0-D7 when the expression !Ø2 & (VDA | VPA) is true, where & is logical AND, | is logical OR and ! is logical NOT. At that time, if the bit pattern on D0-D7 is not the same as the bank number of the currently executing process, and if the current process is not the kernel, a memory access violation has occurred. So the basic means of memory protection is implicitly defined in the CPLD logic.

The real, and so far intractable, problem is two-fold in nature and is due to a design choice made when the '816 was conceived:

  • All zero page and stack accesses are forced to bank $00 without regard to the setting of DB, which makes that bank a "community" sandbox. Therefore, the bank comparison rule has to be ignored for ZP and stack activity if the system is to be able to function—it's kind of tough to do much without ZP and a stack.

  • When any interrupt occurs the '816 automatically forces PB to $00 immediately after pushing the 24 bit program counter (PB followed by PC) and the status register (SR). Pushes occur to the currently-executing process' stack, since that is where SP will be pointing when the interrupt hits. Naturally, the relevant interrupt vector must be located in bank $00, since the MPU effectively does a JMP (<addr>) to get to the interrupt service routine (ISR), where <addr> is always $00xxxx. This characteristic implies that the ISR, or at least part of it, must be in bank $00 (it can, however, jump to another bank). Once again, the sandbox rule cannot be applied to bank $00 if the interrupt system is to be functional.

Given the requirement that bank $00 be accessible to all processes under all conditions, the approach to be taken at first blush would be to prohibit any user-space process from "manually" changing the direct page (DP) register and/or stack pointer (SP). Such a rule would prevent a user-space process from, say, making the I/O block its new stack (Ouch!) or selecting another process' stack as its new ZP. However, blocking DP and SP changes will hobble programming to some extent (being able to change DP on the fly is real useful) and obviously won't prevent a rogue process from overwriting much of bank $00 due to failure to maintain a clean stack.

Given all this, I need more than bank comparisons to prevent ZP and stack space corruption. Bank comparisons will protect all non-zero banks from improper accesses and thus provide sandboxing. Keeping bank $00 in shape is a different matter. My tiny dinosaur brain is having trouble visualizing what needs to be done.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Tue Jun 26, 2012 5:10 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Tue Jun 26, 2012 7:24 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
teamtempest wrote:
What if the hardware "mirrored" a bit of the kernel in every 64K block?...
BigDumbDinosaur wrote:
That could be done but it would then be necessary to somehow write-protect the mirrored area

If the mirrored section looked like ROM to the user process that ought to be sufficient write protection. Would the HMU be able to make that happen?

In theory, yes. Practically speaking, the logic might be too complicated to implement in a reasonably sized CPLD. What would have to be done is to somehow prevent /WD (write data) from being asserted when a very specific address range appears on A0-A15, except when it is the kernel that is addressing that very specific range. In any case, it would only be required if kernel APIs were treated as subroutines, which most modern operating systems don't do. I'm looking at using software interrupts (INT N) to call kernel APIs, as doing so eliminates the need for every application to have knowledge of a jump table. Applications would only need to know the API numbers, and that sort of information can be buried in macros (e.g., READ CH,BUF,NBYTES instead of LDA #CH, LDX #BUF, LDY #NBYTES, INT 4).

Quote:
Regarding software interrupts - doesn't any multi-tasking kernel, pre-emptive or co-operative, have to have some knowledge of what the current running process is? Otherwise it wouldn't be possible to rationally switch to another process. And shouldn't only the current process be capable of triggering a software interrupt? I have a hard time imagining a stopped process doing so, anyway.

You're correct. Only a running process would be able to cause a software interrupt and hence the kernel would have to know which process is in context at any given instant.

Using UNIX as the example, each running process has a process ID (PID) assigned by the kernel, usually a signed 16 bit number. All processes are listed in a table, and each table entry has information to tell the kernel where the process is in memory so the kernel can keep processes away from each other. In the '816 environment, the bank (A16-A23) is really all that is needed for this purpose, since assigning RAM in 64 KB chunks is convenient. Along with the process table entries, information about each process' state, whether running or waiting, must be maintained, along with MPU state information, such as the stack pointer (SP). The MPU registers can be pushed on the process' stack when interrupted for any reason. If SP is restored when the process is selected to run after being idle, an RTI-like sequence can reload the registers and the process will resume where it left off.

When any interrupt is serviced by the '816, the current program bank (PB) is pushed to the top of the stack, followed by the PC and SR. PB is then changed to $00 and the MPU jumps through the relevant vector to service the interrupt (the ISR must be in bank $00). The key to this is it is the process' stack on which the pushes are occurring, so the kernel implicitly knows where to find the stack (just look at SP). If the interrupt is an IRQ, the stack frame provides the data needed to restart the process after the IRQ has been serviced. If the interrupt is an API call (INT N), the stack frame can be interpreted as parameters need by the API and the stack be manipulated by the kernel as required, using the '816's handy stack addressing functions.

Part and parcel to all this is the necessity of telling the CPLD logic when the system is in user or kernel mode, the latter occurring when any interrupt occurs. Switching between modes would change some of the memory protection rules on the fly, allowing, for example, a kernel function to touch RAM in a user-process space. This system behavior would be somewhat analogous to the use of the "privilege ring" capabilities of other microprocessors, but more difficult to implement, due to the use of bank $00 for ZP and stack accesses.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Tue Jun 26, 2012 9:21 am 
Offline

Joined: Sun Apr 10, 2011 8:29 am
Posts: 597
Location: Norway/Japan
Would it be tricky to implement some kind of 'shadow memory' for bank $00? So that kernel mode would see the shadow memory, and non-kernel mode would see the 'normal' memory. Would presumably need a 'kernel mode' bit or some such in the logic, which would be switched on when an interrupt occurs, and could be manually manipulated by kernel functions (well, that would need two bits then.. an interrupt would set the 'kernel' and 'shadow' bits, and sw could only change the 'shadow' bit if the 'kernel' (or 'privileged') bit is on.)

(All solutions based on external logic will start to sound like a description of typical memory management hardware I suppose..)

-Tor


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Tue Jun 26, 2012 8:17 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
Tor wrote:
Would it be tricky to implement some kind of 'shadow memory' for bank $00?

Probably not and it appears you are mirroring thoughts that are slowly taking shape in my dinosaurish brain.

Quote:
So that kernel mode would see the shadow memory, and non-kernel mode would see the 'normal' memory. Would presumably need a 'kernel mode' bit or some such in the logic, which would be switched on when an interrupt occurs, and could be manually manipulated by kernel functions (well, that would need two bits then.. an interrupt would set the 'kernel' and 'shadow' bits, and sw could only change the 'shadow' bit if the 'kernel' (or 'privileged') bit is on.)

That line of thought is similar to what I am now starting to envision. The ATF1508AS CPLD should/will have sufficient room to set up some flops to act as various flags. There are also enough address bus inputs to the CPLD to decode multiple virtual registers, some of which could be machine state registers, such as whether in user-mode or kernel-mode, is an interrupt being handled, etc.

Quote:
(All solutions based on external logic will start to sound like a description of typical memory management hardware I suppose..)

Funny how that works. I'd have to accomplish with the CPLD what most 32/64 bit MPUs (PA-RISC, x86, etc.) are able to accomplish on their own.

My thoughts on this bank $00 dilemma are slowly gelling and I will expound on them in another post once I get to where I can put them "to paper," so to speak.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: POC V2 Bank $00 Dilemma
PostPosted: Wed Jun 27, 2012 6:07 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
I have been contemplating the "bank $00 dilemma" for quite a while, even before POC V2 was more than some passing thoughts. To briefly recapitulate, the "bank $00 dilemma" exists due to a characteristic of the 65C816 that causes it to "hard wire" all zero page (ZP) and stack accesses, as well as indirect absolute addressing, to the first 64 KB of RAM, resulting in a $00xxxx effective address. Also, response to an interrupt of any kind causes the program bank to be forced to $00, thus requiring that the MPU's hardware vectors and interrupt service routines be located in bank $00. This convergence on bank $00 is inconvenient in any system that is expected to support preemptive multitasking, as it complicates the implementation of hardware memory protection.

Ideally, the natural memory segmentation produce by the '816's bank-oriented architecture should allow the system designer to confine each running process to an arbitrarily assigned bank, and prevent inter-bank access without the permission and cooperation of a supervisory program (e.g., an operating system kernel). This is the architecture I envision with POC V2. As ZP and stack access is necessary in most programs, a dilemma is created about what to do with the fact that ZP and stack accesses are directed to bank $00, thus violating the rule that no process be allowed to access any bank other than its own. If an exception to this rule is created so ZP and stack accesses will work, what would prevent any process from overwriting parts of bank $00 that it shouldn't touch?

In current RISC and x86 hardware, the MPU has a feature called "privilege rings," which can be utilized to prevent user-mode programs from executing instructions that should only be executed by the kernel. In such hardware, the kernel operates with maximum privileges and user applications operate with much lower privileges. Hence an attempt by a user-space process to execute potentially destructive instructions can be blocked. Unfortunately, the '816 doesn't have this feature, which if present, would solve the bank $00 dilemma. Therefore, the system glue logic has to somehow take over and create a "privilege rings" analog. I've started to develop some ideas on how to go about doing this. So the rest of this post will be a sort of sounding board for a possible solution to the bank $00 dilemma. I won't go into any hardware or software specifics, since the solution can't be designed until the problem has been defined.

Architectures that support memory protection typically use virtual addressing rather than physical, both for segregation of running processes and for economizing on RAM consumption. In virtual addressing architectures, the smallest amount of contiguous RAM that can be protected is often referred to as a page (not to be confused with the 65xx notion of a page) and, in many cases, is 4 KB in size. Multiple pages can be ganged to produce a larger protected execution space when needed.

In POC V2, I'm not particularly concerned about RAM consumption at this time. Therefore, I've decided to use fixed sized protected space equal in size to a bank, or 64 KB. As the '816's architecture is bank-oriented, I'll use that term instead of page when talking about protected space. V2 will have 1024 KB of RAM, which is equal to 16 banks, enough to prove that my virtual addressing concept will work—or not. :? The CPLD will be tasked with generating the A16-A23 bank bits, which means it will always determine into which bank an access will occur. If my logic is correctly implemented, accesses that would normally be forced into bank $00 by the MPU could instead be directed to a different bank without the running process being aware of the change. The result would be a solution to the bank $00 dilemma.

In order to remap bank $00 accesses, the CPLD logic has to know where to remap the accesses and when such a translation is appropriate. The former would be determine by consulting some virtual registers in the CPLD that the operating system kernel would maintain. The latter would be determined by whether the hardware is running in "real" or "protected" mode. Also, when in protected mode, a distinction will be made between user or kernel mode. Additional rules will apply when an interrupt is serviced:

  • User mode. Full protection is enabled. The effective address is always in the bank set in the CPLD's user bank virtual register. Bank $00 accesses are always remapped to the bank in which the user mode process is executing. Attempted accesses to another bank will cause an memory fault and trigger a hardware abort.

  • Kernel mode. Reduced memory protection is enabled. The effective address is normally in the bank set in the CPLD's kernel bank virtual register but can be changed to access another process' bank. Bank $00 accesses are normally remapped to the kernel bank but can be remapped to any other bank, such as for accessing another process' stack.

  • Interrupt mode. This mode occurs when the MPU starts to service an interrupt. The following generalized steps would occur:

    1. The current mode and bank $00 remapping is maintained until the MPU has pushed the program bank (PB), program counter (PC) and status register (SR). As bank $00 remapping has not been changed during this step, PB, PC and SR will be pushed onto the interrupted process' stack.

    2. As soon as the MPU has pushed SR (cycle 6 of the interrupt sequence), it will assert (negate) its VPB (vector pull) output, which will cause the CPLD to enable interrupt mode. Protection will be changed to kernel mode and bank $00 remapping will be disabled, causing the MPU hardware vectors to appear in the range $00FE00-$00FFFF.

    3. During cycles 7 and 8 of the interrupt sequence, the MPU will load PC from the relevant interrupt service routine (ISR) jump vector and execute the ISR.

    4. With bank $00 remapping disabled, any stack activity performed by the ISR will be directed to physical bank $00. The ISR is permitted to access any bank and may also enable bank $00 remapping as long as when doing so subsequent ISR code is not in the real bank $00. Special handling of the stack pointer would be required if an ISR itself was interrupted. Proper coding, however, can prevent this from occurring.

    As kernel APIs are called via software interrupts, the system always goes into interrupt mode before the API code is executed. Once the kernel has saved context it can (probably should) clear interrupt mode and re-enable IRQs before continuing.

  • Real mode. All protection is disabled. The effective address is always that generated by the MPU—the CPLD will use the DB (data bank) or PB register contents to assert the appropriate address bus and chip select lines. Real mode is the default following reset.

Also essential to effective protection is preventing execution of certain MPU instructions that could take down the system. Some instructions will automatically cause a memory fault because the associated operand uses a 24 bit address. However, there are instructions that should never be executed and some that should not be executable by user-mode processes. In the first group are COP, STP, WDM and XCE. In the second group are JML, JSL, RTI, RTL and SEI. SEP is potentially dangerous in one case: SEP #%00000100, which is effectively an SEI instruction. The sequence:

Code:
         LDA #%00000100
         PHA
         PLP

which would likewise disable IRQs, causing a total system halt (which a watchdog timer could fix by triggering an NMI whose handler would re-enable IRQs).

It is possible for CPLD code to look at D0-D7 while the MPU is fetching an opcode and compare it to the above list for further action. Checking SEP would mean also looking at the operand. Unfortunately, I can't think of any way to prevent a program from pulling a stack value into SR that would shut down IRQs.

Anyhow, now that I've got some of this down on paper the next step is to create some logic tables that describe what I'm trying to achieve.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Wed Jun 27, 2012 10:43 am 
Offline

Joined: Sun Apr 10, 2011 8:29 am
Posts: 597
Location: Norway/Japan
Just wondering - because I have never programmed the 65C816 (only the 6502): Will the user process running in bank NN be aware of the physical bank it's running in? Should it be made to "think" that it's always running in bank $00? Or maybe it doesn't matter? (as you can see, I'm not familiar with the 65816 :))
I guess I'm asking if your POC V2 will look like a (better/improved) 65C02 to each of the user level programs?

-Tor


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Wed Jun 27, 2012 2:39 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
Tor wrote:
Just wondering - because I have never programmed the 65C816 (only the 6502): Will the user process running in bank NN be aware of the physical bank it's running in? Should it be made to "think" that it's always running in bank $00? Or maybe it doesn't matter? (as you can see, I'm not familiar with the 65816 :))
I guess I'm asking if your POC V2 will look like a (better/improved) 65C02 to each of the user level programs?

That's the way it sounds to me. Everything should just be believe they're running in $00, and effectively act like a 6502+extra '816 instructions.

My only question regarding the interrupt handling is it seems that the kernel will not be able to access the context information that was pushed on to the restricted banks stacks, is that correct? By the time kernel mode is invoked, all of that context switching is done, but there's no record of it, so the kernel won't be able to even get access to the stack of the caller?

How does that work?


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Wed Jun 27, 2012 6:12 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
Tor wrote:
Just wondering - because I have never programmed the 65C816 (only the 6502): Will the user process running in bank NN be aware of the physical bank it's running in? Should it be made to "think" that it's always running in bank $00? Or maybe it doesn't matter? (as you can see, I'm not familiar with the 65816 :))
I guess I'm asking if your POC V2 will look like a (better/improved) 65C02 to each of the user level programs?

The '816 itself does allow any program to look at the (program and data) bank registers.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: POC Version 2
PostPosted: Wed Jun 27, 2012 7:10 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
Tor wrote:
Just wondering - because I have never programmed the 65C816 (only the 6502): Will the user process running in bank NN be aware of the physical bank it's running in? Should it be made to "think" that it's always running in bank $00? Or maybe it doesn't matter? (as you can see, I'm not familiar with the 65816 :))
I guess I'm asking if your POC V2 will look like a (better/improved) 65C02 to each of the user level programs?

As Garth pointed out, almost any 65C816 register can be retrieved for inspection. So a user-mode process can determine in which bank it is running with the following sequence:

Code:
         shorta                ;8 bit .A (a macro that performs SEP #%00100000)
         phk                   ;push program bank (PB) &...
         pla                   ;retrieve it

Note that the '816 doesn't have an instruction that can pull PB from the stack. Hence it would be difficult (but not impossible) for a user-mode process to change its execution bank. If it were to do so, however, a memory protection fault would immediately occur because the A16-A23 part of the effective address at which the next instruction would be located wouldn't match the active bank set in the CPLD logic.

whartung wrote:
That's the way it sounds to me. Everything should just be believe they're running in $00, and effectively act like a 6502+extra '816 instructions.

Correct.

Quote:
My only question regarding the interrupt handling is it seems that the kernel will not be able to access the context information that was pushed on to the restricted banks stacks, is that correct? By the time kernel mode is invoked, all of that context switching is done, but there's no record of it, so the kernel won't be able to even get access to the stack of the caller?

How does that work?

The CPLD maintains context state information in several virtual registers:

  • HMU_IBNK. The bank in context when a hardware interrupt occurs. This register is changed by the CPLD logic when it detects an IRQ or NMI, and is consulted by the hardware interrupt handlers so they know to which bank to return when interrupt processing is completed.

  • HMU_KBNK. The bank in which the kernel is running, which is established at boot time (it would not change thereafter).

  • HMU_UBNK. The bank in which the current user-mode process is running. This register is changed by the kernel when any software context switch is made. When a kernel API has completed processing it returns to the bank in this register.

  • HMU_BNK0. If bit 7 is set in this register, bank $00 remapping rules are in effect, causing effective addresses that are "hard wired" to bank $00 to be redirected to the bank currently in context. The effective address seen by the MPU will be in the range $BB0000-$BBFFFF, where BB is the bank currently in context. If bit 7 is clear, effective addresses that are "hard wired" to bank $00 are directed to physical bank $00. The effective address seen by the MPU will be in the range $000000-$00FFFF.

HMU refers to the "hardware management unit," which is a virtual device inside the CPLD. All HMU virtual registers are accessible only to the kernel when operating in protected mode.

The kernel also has the ability to perform cross-bank loads and stores by loading the MPU's DB (data bank) register with any bank and then executing an absolute addressing instruction, such as LDA STACK_U,X. As long A8-A15 of the generated effective address is non-zero the load or store will go to the bank defined by DB. A user-mode process could likewise change DB and do the same thing, but would cause a memory protection fault on the next absolute memory referencing instruction.

The following code examples illustrates a preliminary version of the kernel's API entry code. Kernel APIs are called with the INT API_NUM macro, in which API_NUM is a non-zero API number. The macro assembles as:

Code:
         brk
         .byte API_NUM

In order to know which API has been requested, the kernel has to be able to get API_NUM from the caller's bank, which it would do with several cross-bank reads:

Code:
;KERNEL API CALL FRONT END
;
;   ————————————————————————————————————————————————————————————————————————————————
;   Kernel APIs are called with the INT API_NUM macro, where API_NUM is a (non-zero)
;   API number.  Prior to making the API call, the caller must load the MPU reg-
;   isters with whatever parameters are required by the API.  Upon entry, the MPU
;   will have pushed PB, PC & SR to the caller's stack & disabled IRQs.  The
;   caller's stack frame will be as follows:
;
;   SP + 4   PB
;   SP + 3   PC MSB
;   SP + 2   PC LSB
;   SP + 1   SR w/the I bit set
;
;   PC points to the location immediately following API_NUM.
;
;   For programming convenience, the stack frame is defined as follows:
;
stkptr   =0                     ;current stack location
sr_call  =stkptr+s_byte         ;SR stack offset
pc_call  =sr_call+s_byte        ;PC LSB offset
pb_call  =pc_call+s_word        ;PB offset
;
;   The values S_BYTE & S_WORD are 1 & 2 respectively.
;
;   At the point when the MPU jumps through the BRK vector the kernel's bank
;   bank is in context & stack references go to the kernel's stack, not the
;   caller's.  The 1st step is to preserve the entry register values, as well as
;   the caller's stack pointer.  Preserved values are written to zero page loc-
;   ations that, due to bank $00 remapping, always appear in the kernel's bank,
;   even though the MPU DB register is pointing to the caller's bank.
;   ————————————————————————————————————————————————————————————————————————————————
;
         longr                 ;16 bit writes
         sta ca_ent            ;protect entry values
         stx cx_ent
         sty cy_ent
         tsx                   ;get caller's stack pointer &...
         stx sp_ent            ;protect
         lda sp_kern
         tcs                   ;set kernal's stack pointer
         shorta                ;select 8 bit .A & memory
         cli                   ;re-enable IRQs
;
;   ——————————————————————————————————————————————————————————————————————
;   At this point, the switch to kernel mode has been completed.  The next
;   step is to determine which API has been requested.
;   ——————————————————————————————————————————————————————————————————————
;
         longa                 ;16 bit .A & memory
         lda pc_call,x         ;read caller's stack to get PC
         dec a                 ;move PC back to API number
         tax                   ;now an index
         shorta                ;8 bit .A
         lda $0000,x           ;get API number...
;
;   —————————————————————————————————————————————————————————————————
;   Due to the way the MPU generates the effective address, the above
;   instruction will not be affected by bank $00 remapping, as the
;   A8-A15 bit pattern will be non-zero & therefore not a ZP address.
;   —————————————————————————————————————————————————————————————————
;
         shortx                ;8 bit .X & .Y
         ldx hmu_kbnk          ;kernel bank number (in CPLD)
         phx                   ;direct loads/stores to...
         plb                   ;kernel's bank
         asl a                 ;API number becomes...
         tax                   ;an index
         jsr (kapitab,x)       ;run requested API
;
;   API common exit point would be here...omitted for clarity.
;
   ...program continues...

Obviously, all of this is subject to change, as POC V2 is only a paper computer at this time.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Wed Jun 27, 2012 7:25 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: POC V2 Logic
PostPosted: Wed Jun 27, 2012 7:23 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
BTW, there are some differences in what transpires during a kernel API call as described in my previous post, than as described in the post where I originally laid out my thoughts. Further rumination suggested that bank $00 remapping not be disabled when in kernel mode, except in some very narrow circumstances that have yet to be defined. It's all subject to change as my thoughts gradually come into clearer focus.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: POC Version 2
PostPosted: Thu Jul 19, 2012 4:18 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8155
Location: Midwestern USA
I've slept on the design for a while and made a few modifications, mostly to simplify it. Also, I've fleshed out the HMU (hardware management unit) definitions. The PCB layout is also a little tighter. See updated schematics and PCB layout. I've spread the illustrations over two posts to get around the five attachment limit per post. Schematic pages one through five are below. Pages six and seven, as well as the PCB layout are in the next post.

Attachment:
File comment: POC V2 Schematic Page 1 — Architecture
poc_v2_p1.gif
poc_v2_p1.gif [ 24.71 KiB | Viewed 1524 times ]
Attachment:
File comment: POC V2 Schematic Page 2 — Memory Map
poc_v2_p2.gif
poc_v2_p2.gif [ 58.29 KiB | Viewed 1524 times ]
Attachment:
File comment: POC V2 Schematic Page 3 — HMU Map
poc_v2_p3.gif
poc_v2_p3.gif [ 51.05 KiB | Viewed 1524 times ]
Attachment:
File comment: POC V2 Schematic Page 4 — I/O Map
poc_v2_p4.gif
poc_v2_p4.gif [ 25.86 KiB | Viewed 1524 times ]
Attachment:
File comment: POC V2 Schematic Page 5 — MPU Interface
poc_v2_p5.gif
poc_v2_p5.gif [ 65.74 KiB | Viewed 1524 times ]

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Thu Jul 19, 2012 4:25 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 544 posts ]  Go to page Previous  1 ... 4, 5, 6, 7, 8, 9, 10 ... 37  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 36 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: